diff options
author | jl139090 <none@none> | 2006-04-08 10:25:15 -0700 |
---|---|---|
committer | jl139090 <none@none> | 2006-04-08 10:25:15 -0700 |
commit | 25cf1a301a396c38e8adf52c15f537b80d2483f7 (patch) | |
tree | a76776c2cfbbe43c1ae252223c7ccfa5df15c21c | |
parent | 918fadfadf0c235e6c65ca652caab042b6f05976 (diff) | |
download | illumos-joyent-25cf1a301a396c38e8adf52c15f537b80d2483f7.tar.gz |
PSARC 2004/750 Solaris for OPL
6379529 Solaris for OPL Project
--HG--
rename : usr/src/cmd/sckmd/sparc/sun4u/sckm.sh => deleted_files/usr/src/cmd/sckmd/sparc/sun4u/sckm.sh
328 files changed, 84181 insertions, 2699 deletions
diff --git a/usr/src/cmd/sckmd/sparc/sun4u/sckm.sh b/deleted_files/usr/src/cmd/sckmd/sparc/sun4u/sckm.sh index f9fe17758c..f9fe17758c 100644 --- a/usr/src/cmd/sckmd/sparc/sun4u/sckm.sh +++ b/deleted_files/usr/src/cmd/sckmd/sparc/sun4u/sckm.sh diff --git a/usr/src/Makefile b/usr/src/Makefile index 9bb3ce8da2..1feef8e6ce 100644 --- a/usr/src/Makefile +++ b/usr/src/Makefile @@ -275,6 +275,7 @@ EXPORT_SRC: @cd $(CLOSED)/uts/sun4u/lw2plus; pwd; $(MAKE) EXPORT_SRC @cd uts/sun4u/lw8; pwd; $(MAKE) EXPORT_SRC @cd uts/sun4u/mpxu; pwd; $(MAKE) EXPORT_SRC + @cd uts/sun4u/opl; pwd; $(MAKE) EXPORT_SRC @cd uts/sun4u/serengeti; pwd; $(MAKE) EXPORT_SRC @cd uts/sun4u/starcat; pwd; $(MAKE) EXPORT_SRC @cd uts/sun4u/taco; pwd; $(MAKE) EXPORT_SRC diff --git a/usr/src/Makefile.lint b/usr/src/Makefile.lint index db6904d8a2..a3c57b9c20 100644 --- a/usr/src/Makefile.lint +++ b/usr/src/Makefile.lint @@ -407,10 +407,12 @@ sparc_SUBDIRS= \ cmd/datadm \ cmd/dcs \ cmd/fruadm \ + cmd/prtdscp \ cmd/prtfru \ cmd/sckmd \ cmd/wrsmconf \ cmd/wrsmstat \ + lib/libdscp \ lib/libwrsmconf \ lib/wrsm \ lib/libpcp \ diff --git a/usr/src/cmd/Makefile b/usr/src/cmd/Makefile index 580a2f51ff..6c39c9b938 100644 --- a/usr/src/cmd/Makefile +++ b/usr/src/cmd/Makefile @@ -450,6 +450,7 @@ sparc_SUBDIRS= \ cvcd \ dcs \ fruadm \ + prtdscp \ prtfru \ scadm \ sckmd \ @@ -687,6 +688,7 @@ $(CLOSED_BUILD)MSGSUBDIRS += \ sparc_MSGSUBDIRS= \ fruadm \ + prtdscp \ prtfru \ stmsboot \ wrsmconf \ diff --git a/usr/src/cmd/dcs/sparc/sun4u/dcs.c b/usr/src/cmd/dcs/sparc/sun4u/dcs.c index c926ad5f82..2748217737 100644 --- a/usr/src/cmd/dcs/sparc/sun4u/dcs.c +++ b/usr/src/cmd/dcs/sparc/sun4u/dcs.c @@ -145,6 +145,7 @@ int (*dcs_cmd[])(rdr_msg_hdr_t *, cfga_params_t *) = { * strictly decreasing. */ dcs_ver_t ver_supp[] = { + { 1, 1 }, { 1, 0 } }; @@ -160,6 +161,8 @@ int standalone = 0; /* control standalone mode */ boolean_t inetd = B_FALSE; /* control daemon mode */ ulong_t max_sessions = DCS_MAX_SESSIONS; /* control maximum active sessions */ int dcsfd = STDIN_FILENO; /* fd for the DCS reserved port */ +int use_libdscp = 0; /* control use of libdscp */ +sa_family_t use_family = AF_INET6; /* control use of AF_INET/AF_INET6 */ /* * Array of acceptable -a, -e and -u arguments. @@ -287,6 +290,11 @@ main(int argc, char **argv) break; + case 'l': + use_libdscp = 1; + use_family = AF_INET; + break; + default: if (optopt == 'a' || optopt == 'e' || optopt == 'u') dcs_log_bad_alg(optopt, optarg); @@ -476,7 +484,7 @@ init_server(struct pollfd *pfd, uint8_t ah_auth_alg, uint8_t esp_encr_alg, if (inetd == B_FALSE || standalone) { /* in standalone mode, init fd for reserved port */ - if ((dcsfd = rdr_open(AF_INET6)) == -1) { + if ((dcsfd = rdr_open(use_family)) == -1) { DCS_DBG(DBG_ALL, "rdr_open failed"); return (-1); } @@ -531,16 +539,24 @@ init_server(struct pollfd *pfd, uint8_t ah_auth_alg, uint8_t esp_encr_alg, req_port = se->s_port; } - /* initialize our local address */ - sin6 = (struct sockaddr_in6 *)&ss; - (void) memset(sin6, 0, sizeof (*sin6)); - sin6->sin6_family = AF_INET6; - sin6->sin6_port = htons(req_port); - sin6->sin6_addr = in6addr_any; + (void) memset(&ss, 0, sizeof (ss)); + if (use_family == AF_INET) { + /* initialize our local address */ + sin = (struct sockaddr_in *)&ss; + sin->sin_family = AF_INET; + sin->sin_port = htons(req_port); + sin->sin_addr.s_addr = htonl(INADDR_ANY); + } else { + /* initialize our local address */ + sin6 = (struct sockaddr_in6 *)&ss; + sin6->sin6_family = AF_INET6; + sin6->sin6_port = htons(req_port); + sin6->sin6_addr = in6addr_any; + } num_sock_opts = sizeof (sock_opts) / sizeof (*sock_opts); - init_status = rdr_init(pfd->fd, (struct sockaddr *)sin6, + init_status = rdr_init(pfd->fd, (struct sockaddr *)&ss, sock_opts, num_sock_opts, DCS_BACKLOG); if (init_status != RDR_OK) { diff --git a/usr/src/cmd/dcs/sparc/sun4u/dcs.h b/usr/src/cmd/dcs/sparc/sun4u/dcs.h index b8a328c68b..aa5d8dcb27 100644 --- a/usr/src/cmd/dcs/sparc/sun4u/dcs.h +++ b/usr/src/cmd/dcs/sparc/sun4u/dcs.h @@ -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,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -121,8 +120,9 @@ typedef struct dcs_alg { * -a control the IPsec AH algorithm ("none", "md5", or "sha1") * -e control the IPsec ESP encr algorithm ("none", "des", or "3des") * -u control the IPsec ESP auth algorithm ("none", "md5", or "sha1") + * -l control the use of libdscp for endpoint authentication. */ -#define OPT_STR "d:Ss:a:e:u:" +#define OPT_STR "d:Ss:a:e:u:l" #else /* DCS_DEBUG */ @@ -133,8 +133,9 @@ typedef struct dcs_alg { * -a control the IPsec AH algorithm ("none", "md5", or "sha1") * -e control the IPsec ESP encr algorithm ("none", "des", or "3des") * -u control the IPsec ESP auth algorithm ("none", "md5", or "sha1") + * -l control the use of libdscp for endpoint authentication. */ -#define OPT_STR "s:a:e:u:" +#define OPT_STR "s:a:e:u:l" #endif /* DCS_DEBUG */ @@ -273,6 +274,7 @@ typedef enum { extern ulong_t dcs_debug; extern int standalone; extern ulong_t max_sessions; +extern int use_libdscp; /* diff --git a/usr/src/cmd/dcs/sparc/sun4u/rdr_messages.c b/usr/src/cmd/dcs/sparc/sun4u/rdr_messages.c index f672887a17..51b836a57b 100644 --- a/usr/src/cmd/dcs/sparc/sun4u/rdr_messages.c +++ b/usr/src/cmd/dcs/sparc/sun4u/rdr_messages.c @@ -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,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -56,10 +55,14 @@ #include <string.h> #include <fcntl.h> #include <errno.h> +#include <dlfcn.h> #include <netdb.h> +#include <libdscp.h> #include <sys/socket.h> +#include <sys/systeminfo.h> #include <netinet/tcp.h> +#include "dcs.h" #include "remote_cfg.h" #include "rdr_param_types.h" #include "rdr_messages.h" @@ -85,7 +88,6 @@ typedef struct { int function_pad_sz; } rdr_variable_message_info_t; - /* * A table of maximum sizes for each message type. Message size is * validated when the message header is first received. This prevents @@ -131,6 +133,30 @@ struct { static const int RDR_ALIGN_64_BIT = 8; /* 8 bytes */ +/* + * Interfaces for dynamic use of libdscp. + */ + +#define LIBDSCP_PATH "/usr/platform/%s/lib/libdscp.so.1" + +#define LIBDSCP_BIND "dscpBind" +#define LIBDSCP_SECURE "dscpSecure" +#define LIBDSCP_AUTH "dscpAuth" + +typedef enum { + LIBDSCP_UNKNOWN = 0, + LIBDSCP_AVAILABLE, + LIBDSCP_UNAVAILABLE +} dscp_status_t; + +typedef struct { + dscp_status_t status; + int (*bind)(int, int, int); + int (*secure)(int, int); + int (*auth)(int, struct sockaddr *, int); +} libdscp_t; + +static libdscp_t libdscp; /* * Static Function Declarations @@ -143,6 +169,10 @@ static int rdr_setopt(int fd, int name, int level); static int rdr_bind(int fd, struct sockaddr *addr); +static int rdr_secure(int fd, struct sockaddr *addr); + +static int rdr_auth(struct sockaddr *addr, int len); + static int rdr_snd(int fd, rdr_msg_hdr_t *hdr, char *data, int data_sz, int timeout); static int rdr_snd_raw(int fd, char *msg, int data_sz, int timeout); @@ -151,7 +181,6 @@ static int rdr_rcv(int fd, rdr_msg_hdr_t *hdr, char **data, int timeout); static int rdr_rcv_raw(int fd, char *msg, int data_size, int timeout); - /* * Data Validation Routines */ @@ -270,7 +299,7 @@ static int pack_rsrc_info_request(rsrc_info_params_t *params, char **buf, static int unpack_rsrc_info_request(rsrc_info_params_t *params, const char *buf); static int pack_rsrc_info_reply(rsrc_info_params_t *params, char **buf, - int *buf_size); + int *buf_size, int encoding); static int unpack_rsrc_info_reply(rsrc_info_params_t *params, const char *buf); /* @@ -313,6 +342,11 @@ static void cleanup_variable_ap_id_info( rdr_variable_message_info_t *var_msg_info); /* + * Functions for loading libdscp. + */ +static int load_libdscp(libdscp_t *libdscp); + +/* * Public Functions */ @@ -360,6 +394,11 @@ rdr_init(int fd, struct sockaddr *addr, int *opts, int num_opts, int blog) num_opts = 0; } + /* turn on security features */ + if (rdr_secure(fd, addr) != RDR_OK) { + return (RDR_NET_ERR); + } + /* bind the address, if is not already bound */ if (rdr_bind(fd, addr) != RDR_OK) { return (RDR_NET_ERR); @@ -457,11 +496,18 @@ rdr_connect_srv(int fd) struct sockaddr_storage faddr; + /* accept the connection */ faddr_len = sizeof (faddr); if ((newfd = accept(fd, (struct sockaddr *)&faddr, &faddr_len)) == -1) { return (RDR_BAD_FD); } + /* if the peer doesn't authenticate properly, reject */ + if (rdr_auth((struct sockaddr *)&faddr, faddr_len) != RDR_OK) { + (void) close(newfd); + return (RDR_BAD_FD); + } + return (newfd); } @@ -486,7 +532,7 @@ rdr_reject(int fd) } /* then close it */ - close(fd); + (void) close(fd); return (RDR_OK); } @@ -500,7 +546,7 @@ rdr_reject(int fd) int rdr_close(int fd) { - close(fd); + (void) close(fd); return (RDR_OK); } @@ -718,8 +764,16 @@ rdr_snd_msg(int fd, rdr_msg_hdr_t *hdr, cfga_params_t *param, int timeout) err = pack_rsrc_info_request(rparam, &pack_buf, &pack_buf_sz); } else { - err = pack_rsrc_info_reply(rparam, &pack_buf, - &pack_buf_sz); + if ((hdr->major_version == 1) && + (hdr->minor_version == 0)) { + err = pack_rsrc_info_reply(rparam, + &pack_buf, &pack_buf_sz, + NV_ENCODE_NATIVE); + } else { + err = pack_rsrc_info_reply(rparam, + &pack_buf, &pack_buf_sz, + NV_ENCODE_XDR); + } } break; } @@ -1291,6 +1345,69 @@ rdr_bind(int fd, struct sockaddr *addr) /* + * rdr_secure: + * + * Activate security features for a socket. + * + * Some platforms have libdscp, which provides additional + * security features. An attempt is made to load libdscp + * and use these features. + * + * Nothing is done if libdscp is not available. + */ +static int +rdr_secure(int fd, struct sockaddr *addr) +{ + struct sockaddr_in *sin; + int port; + int error; + + if (use_libdscp == 0) { + return (RDR_OK); + } + + if (load_libdscp(&libdscp) != 1) { + return (RDR_ERROR); + } + + /* LINTED E_BAD_PTR_CAST_ALIGN */ + sin = (struct sockaddr_in *)addr; + port = ntohs(sin->sin_port); + error = libdscp.bind(0, fd, port); + + if ((error != DSCP_OK) && (error != DSCP_ERROR_ALREADY)) { + return (RDR_ERROR); + } + + if (libdscp.secure(0, fd) != DSCP_OK) { + return (RDR_ERROR); + } + return (RDR_OK); +} + +/* + * rdr_auth: + * + * Authenticate if a connection is really from the service + * processor. This is dependent upon functionality from + * libdscp, so an attempt to load and use libdscp is made. + * + * Without libdscp, this function does nothing. + */ +static int +rdr_auth(struct sockaddr *addr, int len) +{ + if (use_libdscp != 0) { + if ((load_libdscp(&libdscp) == 0) || + (libdscp.auth(0, addr, len) != DSCP_OK)) { + return (RDR_ERROR); + } + } + + return (RDR_OK); +} + +/* * rdr_snd: * * Send a message in two stages. First the header is sent, @@ -3916,7 +4033,8 @@ unpack_rsrc_info_request(rsrc_info_params_t *params, const char *buf) * Handle packing a resource info reply message. */ static int -pack_rsrc_info_reply(rsrc_info_params_t *params, char **buf, int *buf_size) +pack_rsrc_info_reply(rsrc_info_params_t *params, char **buf, int *buf_size, + int encoding) { char *bufptr; rdr_rsrc_info_reply_t rsrc_info_data; @@ -3932,7 +4050,8 @@ pack_rsrc_info_reply(rsrc_info_params_t *params, char **buf, int *buf_size) /* * Pack snapshot handle data. */ - pack_status = ri_pack(params->hdl, &rsrc_info_bufp, &rsrc_info_size); + pack_status = ri_pack(params->hdl, &rsrc_info_bufp, &rsrc_info_size, + encoding); if (pack_status != 0) { return (RDR_ERROR); } @@ -4363,3 +4482,76 @@ cleanup_variable_ap_id_info(rdr_variable_message_info_t *var_msg_info) } } } + +/* + * load_libdscp: + * + * Try to dynamically link with libdscp. + * + * Returns: 0 if libdscp not available, + * 1 if libdscp is available. + */ +static int +load_libdscp(libdscp_t *libdscp) +{ + int len; + void *lib; + static char platform[100]; + static char pathname[MAXPATHLEN]; + + /* + * Only try to load libdscp once. Use the saved + * status in the libdscp interface to know the + * results of previous attempts. + */ + if (libdscp->status == LIBDSCP_AVAILABLE) { + return (1); + } + if (libdscp->status == LIBDSCP_UNAVAILABLE) { + return (0); + } + + /* + * Construct a platform specific pathname for libdscp. + */ + len = sysinfo(SI_PLATFORM, platform, sizeof (platform)); + if ((len < 0) || (len > sizeof (platform))) { + return (0); + } + len = snprintf(pathname, MAXPATHLEN, LIBDSCP_PATH, platform); + if (len >= MAXPATHLEN) { + libdscp->status = LIBDSCP_UNAVAILABLE; + return (0); + } + + /* + * Try dynamically loading libdscp. + */ + if ((lib = dlopen(pathname, RTLD_LAZY)) == NULL) { + libdscp->status = LIBDSCP_UNAVAILABLE; + return (0); + } + + /* + * Try to resolve all the symbols. + */ + libdscp->bind = (int (*)(int, int, int))dlsym(lib, LIBDSCP_BIND); + libdscp->secure = (int (*)(int, int))dlsym(lib, LIBDSCP_SECURE); + libdscp->auth = (int (*)(int, struct sockaddr *, int))dlsym(lib, + LIBDSCP_AUTH); + + if ((libdscp->bind == NULL) || + (libdscp->secure == NULL) || + (libdscp->auth == NULL)) { + (void) dlclose(lib); + libdscp->status = LIBDSCP_UNAVAILABLE; + return (0); + } + + /* + * Success. + * Update the status to indicate libdscp is available. + */ + libdscp->status = LIBDSCP_AVAILABLE; + return (1); +} diff --git a/usr/src/cmd/dcs/sparc/sun4u/rsrc_info.c b/usr/src/cmd/dcs/sparc/sun4u/rsrc_info.c index 3f5239f26d..2587613f89 100644 --- a/usr/src/cmd/dcs/sparc/sun4u/rsrc_info.c +++ b/usr/src/cmd/dcs/sparc/sun4u/rsrc_info.c @@ -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) 2000-2001 by Sun Microsystems, Inc. - * All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" @@ -36,19 +35,19 @@ #include "rsrc_info.h" #include "rsrc_info_impl.h" -static int ap_list_pack(ri_ap_t *, char **, size_t *); +static int ap_list_pack(ri_ap_t *, char **, size_t *, int); static int ap_list_unpack(char *, size_t, ri_ap_t **); -static int ap_pack(ri_ap_t *, char **, size_t *); +static int ap_pack(ri_ap_t *, char **, size_t *, int); static int ap_unpack(char *, size_t, ri_ap_t *); -static int dev_list_pack(ri_dev_t *, char **, size_t *); +static int dev_list_pack(ri_dev_t *, char **, size_t *, int); static int dev_list_unpack(char *, size_t, ri_dev_t **); -static int dev_pack(ri_dev_t *, char **, size_t *); +static int dev_pack(ri_dev_t *, char **, size_t *, int); static int dev_unpack(char *, size_t, ri_dev_t *); -static int client_list_pack(ri_client_t *, char **, size_t *); +static int client_list_pack(ri_client_t *, char **, size_t *, int); static int client_list_unpack(char *, size_t, ri_client_t **); -static int client_pack(ri_client_t *, char **, size_t *); +static int client_pack(ri_client_t *, char **, size_t *, int); static int client_unpack(char *, size_t, ri_client_t *); -static int pack_add_byte_array(nvlist_t *, char *, nvlist_t *); +static int pack_add_byte_array(nvlist_t *, char *, nvlist_t *, int); static int lookup_unpack_byte_array(nvlist_t *, char *, nvlist_t **); static void ri_ap_free(ri_ap_t *); @@ -132,7 +131,7 @@ ri_client_free(ri_client_t *client) * Pack everything contained in the handle up inside out. */ int -ri_pack(ri_hdl_t *hdl, caddr_t *bufp, size_t *sizep) +ri_pack(ri_hdl_t *hdl, caddr_t *bufp, size_t *sizep, int encoding) { nvlist_t *nvl = NULL; char *buf = NULL; @@ -162,27 +161,29 @@ ri_pack(ri_hdl_t *hdl, caddr_t *bufp, size_t *sizep) goto fail; } - if (ap_list_pack(hdl->aps, &buf, &size) != 0 || + if (ap_list_pack(hdl->aps, &buf, &size, encoding) != 0 || nvlist_add_byte_array(nvl, RI_HDL_APS, (uchar_t *)buf, size) != 0) { goto fail; } s_free(buf); - if (client_list_pack(hdl->cpu_cap_clients, &buf, &size) != 0 || + if (client_list_pack(hdl->cpu_cap_clients, &buf, &size, + encoding) != 0 || nvlist_add_byte_array(nvl, RI_HDL_CPU_CAPS, (uchar_t *)buf, size) != 0) { goto fail; } s_free(buf); - if (client_list_pack(hdl->mem_cap_clients, &buf, &size) != 0 || + if (client_list_pack(hdl->mem_cap_clients, &buf, &size, + encoding) != 0 || nvlist_add_byte_array(nvl, RI_HDL_MEM_CAPS, (uchar_t *)buf, size) != 0) { goto fail; } s_free(buf); - if (nvlist_pack(nvl, &buf, &size, NV_ENCODE_NATIVE, 0) != 0) { + if (nvlist_pack(nvl, &buf, &size, encoding, 0) != 0) { dprintf((stderr, "nvlist_pack fail\n")); goto fail; } @@ -205,7 +206,7 @@ fail: * Pack a list of attachment point handles. */ static int -ap_list_pack(ri_ap_t *aplist, char **bufp, size_t *sizep) +ap_list_pack(ri_ap_t *aplist, char **bufp, size_t *sizep, int encoding) { nvlist_t *nvl = NULL; char *buf = NULL; @@ -223,7 +224,7 @@ ap_list_pack(ri_ap_t *aplist, char **bufp, size_t *sizep) while (aplist != NULL) { s_free(buf); - if (ap_pack(aplist, &buf, &size) != 0) + if (ap_pack(aplist, &buf, &size, encoding) != 0) goto fail; if (nvlist_add_byte_array(nvl, RI_AP_T, (uchar_t *)buf, @@ -236,7 +237,7 @@ ap_list_pack(ri_ap_t *aplist, char **bufp, size_t *sizep) } s_free(buf); - if (nvlist_pack(nvl, &buf, &size, NV_ENCODE_NATIVE, 0) != 0) { + if (nvlist_pack(nvl, &buf, &size, encoding, 0) != 0) { dprintf((stderr, "nvlist_pack fail\n")); goto fail; } @@ -259,7 +260,7 @@ fail: * Pack a list of ri_dev_t's. */ static int -dev_list_pack(ri_dev_t *devlist, char **bufp, size_t *sizep) +dev_list_pack(ri_dev_t *devlist, char **bufp, size_t *sizep, int encoding) { nvlist_t *nvl = NULL; char *buf = NULL; @@ -277,7 +278,7 @@ dev_list_pack(ri_dev_t *devlist, char **bufp, size_t *sizep) while (devlist != NULL) { s_free(buf); - if (dev_pack(devlist, &buf, &size) != 0) + if (dev_pack(devlist, &buf, &size, encoding) != 0) goto fail; if (nvlist_add_byte_array(nvl, RI_DEV_T, (uchar_t *)buf, @@ -290,7 +291,7 @@ dev_list_pack(ri_dev_t *devlist, char **bufp, size_t *sizep) } s_free(buf); - if (nvlist_pack(nvl, &buf, &size, NV_ENCODE_NATIVE, 0) != 0) { + if (nvlist_pack(nvl, &buf, &size, encoding, 0) != 0) { dprintf((stderr, "nvlist_pack fail\n")); goto fail; } @@ -313,7 +314,8 @@ fail: * Pack a list of ri_client_t's. */ static int -client_list_pack(ri_client_t *client_list, char **bufp, size_t *sizep) +client_list_pack(ri_client_t *client_list, char **bufp, size_t *sizep, + int encoding) { nvlist_t *nvl = NULL; char *buf = NULL; @@ -331,7 +333,7 @@ client_list_pack(ri_client_t *client_list, char **bufp, size_t *sizep) while (client_list != NULL) { s_free(buf); - if (client_pack(client_list, &buf, &size) != 0) + if (client_pack(client_list, &buf, &size, encoding) != 0) goto fail; if (nvlist_add_byte_array(nvl, RI_CLIENT_T, (uchar_t *)buf, @@ -344,7 +346,7 @@ client_list_pack(ri_client_t *client_list, char **bufp, size_t *sizep) } s_free(buf); - if (nvlist_pack(nvl, &buf, &size, NV_ENCODE_NATIVE, 0) != 0) { + if (nvlist_pack(nvl, &buf, &size, encoding, 0) != 0) { dprintf((stderr, "nvlist_pack fail\n")); goto fail; } @@ -364,7 +366,7 @@ fail: } static int -ap_pack(ri_ap_t *ap, char **bufp, size_t *sizep) +ap_pack(ri_ap_t *ap, char **bufp, size_t *sizep, int encoding) { nvlist_t *nvl = NULL; char *buf = NULL; @@ -375,10 +377,11 @@ ap_pack(ri_ap_t *ap, char **bufp, size_t *sizep) return (-1); } - if (pack_add_byte_array(ap->conf_props, RI_AP_PROPS, nvl) != 0) + if (pack_add_byte_array(ap->conf_props, RI_AP_PROPS, nvl, + encoding) != 0) goto fail; - if (dev_list_pack(ap->cpus, &buf, &size) != 0) + if (dev_list_pack(ap->cpus, &buf, &size, encoding) != 0) goto fail; if (nvlist_add_byte_array(nvl, RI_AP_CPUS, (uchar_t *)buf, @@ -388,7 +391,7 @@ ap_pack(ri_ap_t *ap, char **bufp, size_t *sizep) } s_free(buf); - if (dev_list_pack(ap->mems, &buf, &size) != 0) + if (dev_list_pack(ap->mems, &buf, &size, encoding) != 0) goto fail; if (nvlist_add_byte_array(nvl, RI_AP_MEMS, (uchar_t *)buf, @@ -398,7 +401,7 @@ ap_pack(ri_ap_t *ap, char **bufp, size_t *sizep) } s_free(buf); - if (dev_list_pack(ap->ios, &buf, &size) != 0) + if (dev_list_pack(ap->ios, &buf, &size, encoding) != 0) goto fail; if (nvlist_add_byte_array(nvl, RI_AP_IOS, (uchar_t *)buf, @@ -408,7 +411,7 @@ ap_pack(ri_ap_t *ap, char **bufp, size_t *sizep) } s_free(buf); - if (nvlist_pack(nvl, &buf, &size, NV_ENCODE_NATIVE, 0) != 0) { + if (nvlist_pack(nvl, &buf, &size, encoding, 0) != 0) { dprintf((stderr, "nvlist_pack fail\n")); goto fail; } @@ -428,7 +431,7 @@ fail: } static int -dev_pack(ri_dev_t *dev, char **bufp, size_t *sizep) +dev_pack(ri_dev_t *dev, char **bufp, size_t *sizep, int encoding) { nvlist_t *nvl = NULL; char *buf = NULL; @@ -439,10 +442,11 @@ dev_pack(ri_dev_t *dev, char **bufp, size_t *sizep) return (-1); } - if (pack_add_byte_array(dev->conf_props, RI_DEV_PROPS, nvl) != 0) + if (pack_add_byte_array(dev->conf_props, RI_DEV_PROPS, nvl, + encoding) != 0) goto fail; - if (client_list_pack(dev->rcm_clients, &buf, &size) != 0) + if (client_list_pack(dev->rcm_clients, &buf, &size, encoding) != 0) goto fail; if (nvlist_add_byte_array(nvl, RI_DEV_CLIENTS, (uchar_t *)buf, @@ -453,7 +457,7 @@ dev_pack(ri_dev_t *dev, char **bufp, size_t *sizep) } s_free(buf); - if (nvlist_pack(nvl, &buf, &size, NV_ENCODE_NATIVE, 0) != 0) { + if (nvlist_pack(nvl, &buf, &size, encoding, 0) != 0) { dprintf((stderr, "nvlist_pack fail\n")); goto fail; } @@ -473,7 +477,7 @@ fail: } static int -client_pack(ri_client_t *client, char **bufp, size_t *sizep) +client_pack(ri_client_t *client, char **bufp, size_t *sizep, int encoding) { nvlist_t *nvl = NULL; char *buf = NULL; @@ -485,7 +489,7 @@ client_pack(ri_client_t *client, char **bufp, size_t *sizep) } if (pack_add_byte_array(client->usg_props, RI_CLIENT_USAGE_PROPS, - nvl) != 0) { + nvl, encoding) != 0) { goto fail; } @@ -494,11 +498,11 @@ client_pack(ri_client_t *client, char **bufp, size_t *sizep) * in the call to ri_init. */ if (client->v_props != NULL && pack_add_byte_array(client->v_props, - RI_CLIENT_VERB_PROPS, nvl) != 0) { + RI_CLIENT_VERB_PROPS, nvl, encoding) != 0) { goto fail; } - if (nvlist_pack(nvl, &buf, &size, NV_ENCODE_NATIVE, 0) != 0) { + if (nvlist_pack(nvl, &buf, &size, encoding, 0) != 0) { dprintf((stderr, "nvlist_pack fail\n")); goto fail; } @@ -521,12 +525,13 @@ fail: * Pack nvlist_t and add as byte array to another nvlist_t. */ static int -pack_add_byte_array(nvlist_t *nvl_packme, char *name, nvlist_t *nvl) +pack_add_byte_array(nvlist_t *nvl_packme, char *name, nvlist_t *nvl, + int encoding) { char *buf = NULL; size_t size = 0; - if (nvlist_pack(nvl_packme, &buf, &size, NV_ENCODE_NATIVE, 0) != 0) { + if (nvlist_pack(nvl_packme, &buf, &size, encoding, 0) != 0) { dprintf((stderr, "nvlist_pack fail (%s)\n", name)); s_free(buf); return (-1); diff --git a/usr/src/cmd/dcs/sparc/sun4u/rsrc_info.h b/usr/src/cmd/dcs/sparc/sun4u/rsrc_info.h index dfedebfe62..d663e9dcbf 100644 --- a/usr/src/cmd/dcs/sparc/sun4u/rsrc_info.h +++ b/usr/src/cmd/dcs/sparc/sun4u/rsrc_info.h @@ -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) 2000 by Sun Microsystems, Inc. - * All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. */ #ifndef _RSRC_INFO_H @@ -147,7 +146,7 @@ int ri_init(uint_t, int, char **, int, ri_hdl_t **); #else int ri_init(int, char **, int, ri_hdl_t **); #endif /* SMSLIB_TARGET */ -int ri_pack(ri_hdl_t *, caddr_t *, size_t *); +int ri_pack(ri_hdl_t *, caddr_t *, size_t *, int encoding); int ri_unpack(caddr_t, size_t, ri_hdl_t **); void ri_fini(ri_hdl_t *); ri_ap_t *ri_ap_next(ri_hdl_t *, ri_ap_t *); diff --git a/usr/src/cmd/dcs/sparc/sun4u/svc-dcs b/usr/src/cmd/dcs/sparc/sun4u/svc-dcs index 5245357f96..52e0897ef7 100644 --- a/usr/src/cmd/dcs/sparc/sun4u/svc-dcs +++ b/usr/src/cmd/dcs/sparc/sun4u/svc-dcs @@ -1,14 +1,13 @@ #!/sbin/sh # -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # CDDL HEADER START # # The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. +# 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. @@ -48,17 +47,27 @@ getproparg() { DCS=/usr/lib/dcs platform=`/sbin/uname -i` -starfire="SUNW,Ultra-Enterprise-10000" -starcat="SUNW,Sun-Fire-15000" +e10k="SUNW,Ultra-Enterprise-10000" +sf15k="SUNW,Sun-Fire-15000" +opl="SUNW,SPARC-Enterprise" +fjopl="FJSV,SPARC-Enterprise" +tmpopl="SUNW,OPL-Enterprise" args="" -if [ $platform = "$starcat" ]; then +if [ $platform = "$sf15k" ]; then args="$args `getproparg -a dcs/ah_auth`" args="$args `getproparg -e dcs/esp_encr`" args="$args `getproparg -u dcs/esp_auth`" +elif [ $platform = "$opl" -o \ + $platform = "$fjopl" -o \ + $platform = "$tmpopl" ]; then + args="-l" fi -if [ $platform = "$starfire" -o $platform = "$starcat" ]; then +if [ $platform = "$e10k" -o $platform = "$sf15k" -o \ + $platform = "$opl" -o \ + $platform = "$fjopl" -o \ + $platform = "$tmpopl" ]; then $DCS $args # Fail if can't execute exit # Use dcs's exit status else diff --git a/usr/src/cmd/devfsadm/misc_link.c b/usr/src/cmd/devfsadm/misc_link.c index d446392618..a8f0ef5d71 100644 --- a/usr/src/cmd/devfsadm/misc_link.c +++ b/usr/src/cmd/devfsadm/misc_link.c @@ -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,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -58,6 +57,7 @@ static int zcons_create(di_minor_t minor, di_node_t node); static int cpuid(di_minor_t minor, di_node_t node); static int glvc(di_minor_t minor, di_node_t node); static int ses_callback(di_minor_t minor, di_node_t node); +static int kmdrv_create(di_minor_t minor, di_node_t node); static devfsadm_create_t misc_cbt[] = { { "pseudo", "ddi_pseudo", "(^pts$)|(^sad$)", @@ -146,7 +146,10 @@ static devfsadm_create_t misc_cbt[] = { TYPE_EXACT | DRV_EXACT, ILEVEL_0, gpio }, { "pseudo", "ddi_pseudo", "sckmdrv", - TYPE_EXACT | DRV_RE, ILEVEL_0, minor_name, + TYPE_EXACT | DRV_RE, ILEVEL_0, kmdrv_create, + }, + { "pseudo", "ddi_pseudo", "oplkmdrv", + TYPE_EXACT | DRV_RE, ILEVEL_0, kmdrv_create, }, { "av", "^ddi_av:(isoch|async)$", NULL, TYPE_RE, ILEVEL_0, av_create, @@ -169,6 +172,9 @@ static devfsadm_create_t misc_cbt[] = { { "pseudo", "ddi_pseudo", "glvc", TYPE_EXACT | DRV_EXACT, ILEVEL_0, glvc, }, + { "pseudo", "ddi_pseudo", "dm2s", + TYPE_EXACT | DRV_EXACT, ILEVEL_0, minor_name, + }, }; DEVFSADM_CREATE_INIT_V0(misc_cbt); @@ -658,3 +664,16 @@ glvc(di_minor_t minor, di_node_t node) } return (DEVFSADM_CONTINUE); } + +/* + * Handles links of the form: + * type=ddi_pseudo;name=sckmdrv kmdrv\M0 + * type=ddi_pseudo;name=oplkmdrv kmdrv\M0 + */ +static int +kmdrv_create(di_minor_t minor, di_node_t node) +{ + + (void) devfsadm_mklink("kmdrv", node, minor, 0); + return (DEVFSADM_CONTINUE); +} diff --git a/usr/src/cmd/fm/dicts/SUN4U.dict b/usr/src/cmd/fm/dicts/SUN4U.dict index 236373e354..91b46e4b29 100644 --- a/usr/src/cmd/fm/dicts/SUN4U.dict +++ b/usr/src/cmd/fm/dicts/SUN4U.dict @@ -1,13 +1,12 @@ # -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # CDDL HEADER START # # The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. +# 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. @@ -23,8 +22,11 @@ # CDDL HEADER END # #ident "%Z%%M% %I% %E% SMI" +# +# DO NOT EDIT -- this file is generated by the Event Registry. +# -FMDICT: name=SUN4U version=1 maxkey=7 +FMDICT: name=SUN4U version=1 maxkey=7 dictid=0x3455 fault.memory.page=1 fault.memory.dimm=2 @@ -255,3 +257,7 @@ fault.asic.dx.dp=226 fault.asic.sdi.dp=227 fault.asic.cp.dp=228 fault.asic.rp.dp=229 +fault.io.oberon=230 +fault.cpu.SPARC64-VI.chip=231 +fault.cpu.SPARC64-VI.core=232 +fault.cpu.SPARC64-VI.strand=233 diff --git a/usr/src/cmd/fm/dicts/SUN4U.po b/usr/src/cmd/fm/dicts/SUN4U.po index b5f62c1f1e..95ec5cd8a9 100644 --- a/usr/src/cmd/fm/dicts/SUN4U.po +++ b/usr/src/cmd/fm/dicts/SUN4U.po @@ -1,13 +1,12 @@ # -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # CDDL HEADER START # # The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. +# 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. @@ -23,7 +22,9 @@ # CDDL HEADER END # #ident "%Z%%M% %I% %E% SMI" - +# +# DO NOT EDIT -- this file is generated by the Event Registry. +# # # code: SUN4U-8000-1A # keys: fault.memory.page @@ -47,7 +48,7 @@ msgstr "No repair action is recommended at this time." msgid "SUN4U-8000-2S.type" msgstr "Fault" msgid "SUN4U-8000-2S.severity" -msgstr "Minor" +msgstr "Major" msgid "SUN4U-8000-2S.description" msgstr "The number of errors associated with this memory module has exceeded acceptable levels. Refer to %s for more information." msgid "SUN4U-8000-2S.response" @@ -55,7 +56,7 @@ msgstr "Pages of memory associated with this memory module are being removed fro msgid "SUN4U-8000-2S.impact" msgstr "Total system memory capacity will be reduced as pages are retired." msgid "SUN4U-8000-2S.action" -msgstr "Schedule a repair procedure to replace the affected memory module. Use fmdump -v -u <EVENT_ID> to identify the module." +msgstr "Schedule a repair procedure to replace the affected memory module. Use fmdump -v -u <EVENT_ID> to identify the module." # # code: SUN4U-8000-35 # keys: fault.memory.bank @@ -63,7 +64,7 @@ msgstr "Schedule a repair procedure to replace the affected memory module. Use msgid "SUN4U-8000-35.type" msgstr "Fault" msgid "SUN4U-8000-35.severity" -msgstr "Minor" +msgstr "Critical" msgid "SUN4U-8000-35.description" msgstr "The number of errors associated with this memory module has exceeded acceptable levels. Refer to %s for more information." msgid "SUN4U-8000-35.response" @@ -71,7 +72,7 @@ msgstr "Pages of memory associated with this memory module are being removed fro msgid "SUN4U-8000-35.impact" msgstr "Total system memory capacity will be reduced as pages are retired." msgid "SUN4U-8000-35.action" -msgstr "Schedule a repair procedure to replace the affected memory module. Use fmdump -v -u <EVENT_ID> to identify the module." +msgstr "Schedule a repair procedure to replace the affected memory module. Use fmdump -v -u <EVENT_ID> to identify the module." # # code: SUN4U-8000-4Y # keys: fault.cpu.ultraSPARC-III.dcache @@ -81,13 +82,13 @@ msgstr "Fault" msgid "SUN4U-8000-4Y.severity" msgstr "Major" msgid "SUN4U-8000-4Y.description" -msgstr "The number of errors associated with this CPU has exceeded acceptable levels. Refer to %s for more information." +msgstr "The number of errors associated with a CPU has exceeded acceptable levels. Refer to %s for more information." msgid "SUN4U-8000-4Y.response" -msgstr "An attempt will be made to remove the affected CPU from service." +msgstr "The fault manager will attempt to remove the affected CPU from service." msgid "SUN4U-8000-4Y.impact" -msgstr "Performance of this system may be affected." +msgstr "System performance may be affected." msgid "SUN4U-8000-4Y.action" -msgstr "Schedule a repair procedure to replace the affected CPU. Use fmdump -v -u <EVENT_ID> to identify the CPU." +msgstr "Schedule a repair procedure to replace the affected CPU, the identity of which can be determined using fmdump -v -u <EVENT_ID>." # # code: SUN4U-8000-53 # keys: fault.cpu.ultraSPARC-III.icache @@ -97,13 +98,13 @@ msgstr "Fault" msgid "SUN4U-8000-53.severity" msgstr "Major" msgid "SUN4U-8000-53.description" -msgstr "The number of errors associated with this CPU has exceeded acceptable levels. Refer to %s for more information." +msgstr "The number of errors associated with a CPU has exceeded acceptable levels. Refer to %s for more information." msgid "SUN4U-8000-53.response" -msgstr "An attempt will be made to remove the affected CPU from service." +msgstr "The fault manager will attempt to remove the affected CPU from service." msgid "SUN4U-8000-53.impact" -msgstr "Performance of this system may be affected." +msgstr "System performance may be affected." msgid "SUN4U-8000-53.action" -msgstr "Schedule a repair procedure to replace the affected CPU. Use fmdump -v -u <EVENT_ID> to identify the CPU." +msgstr "Schedule a repair procedure to replace the affected CPU, the identity of which can be determined using fmdump -v -u <EVENT_ID>." # # code: SUN4U-8000-6H # keys: fault.cpu.ultraSPARC-III.l2cachedata @@ -115,11 +116,11 @@ msgstr "Major" msgid "SUN4U-8000-6H.description" msgstr "The number of errors associated with this CPU has exceeded acceptable levels. Refer to %s for more information." msgid "SUN4U-8000-6H.response" -msgstr "An attempt will be made to remove the affected CPU from service." +msgstr "The fault manager will attempt to remove the affected CPU from service." msgid "SUN4U-8000-6H.impact" -msgstr "Performance of this system may be affected." +msgstr "System performance may be affected." msgid "SUN4U-8000-6H.action" -msgstr "Schedule a repair procedure to replace the affected CPU. Use fmdump -v -u <EVENT_ID> to identify the CPU." +msgstr "Schedule a repair procedure to replace the affected CPU, the identity of which can be determined using fmdump -v -u <EVENT_ID>." # # code: SUN4U-8000-7D # keys: fault.cpu.ultraSPARC-III.l2cachetag @@ -131,11 +132,11 @@ msgstr "Major" msgid "SUN4U-8000-7D.description" msgstr "The number of errors associated with this CPU has exceeded acceptable levels. Refer to %s for more information." msgid "SUN4U-8000-7D.response" -msgstr "An attempt will be made to remove the affected CPU from service." +msgstr "The fault manager will attempt to remove the affected CPU from service." msgid "SUN4U-8000-7D.impact" -msgstr "Performance of this system may be affected." +msgstr "System performance may be affected." msgid "SUN4U-8000-7D.action" -msgstr "Schedule a repair procedure to replace the affected CPU. Use fmdump -v -u <EVENT_ID> to identify the CPU." +msgstr "Schedule a repair procedure to replace the affected CPU, the identity of which can be determined using fmdump -v -u <EVENT_ID>." # # code: SUN4U-8000-84 # keys: fault.cpu.ultraSPARC-IIIi.dcache @@ -147,11 +148,11 @@ msgstr "Major" msgid "SUN4U-8000-84.description" msgstr "The number of errors associated with this CPU has exceeded acceptable levels. Refer to %s for more information." msgid "SUN4U-8000-84.response" -msgstr "An attempt will be made to remove the affected CPU from service." +msgstr "The fault manager will attempt to remove the affected CPU from service." msgid "SUN4U-8000-84.impact" -msgstr "Performance of this system may be affected." +msgstr "System performance system may be affected." msgid "SUN4U-8000-84.action" -msgstr "Schedule a repair procedure to replace the affected CPU. Use fmdump -v -u <EVENT_ID> to identify the CPU." +msgstr "Schedule a repair procedure to replace the affected CPU, the identity of which can be determined using fmdump -v -u <EVENT_ID>." # # code: SUN4U-8000-9R # keys: fault.cpu.ultraSPARC-IIIi.icache @@ -163,11 +164,11 @@ msgstr "Major" msgid "SUN4U-8000-9R.description" msgstr "The number of errors associated with this CPU has exceeded acceptable levels. Refer to %s for more information." msgid "SUN4U-8000-9R.response" -msgstr "An attempt will be made to remove the affected CPU from service." +msgstr "The fault manager will attempt to remove the affected CPU from service." msgid "SUN4U-8000-9R.impact" -msgstr "Performance of this system may be affected." +msgstr "System performance may be affected." msgid "SUN4U-8000-9R.action" -msgstr "Schedule a repair procedure to replace the affected CPU. Use fmdump -v -u <EVENT_ID> to identify the CPU." +msgstr "Schedule a repair procedure to replace the affected CPU, the identity of which can be determined using fmdump -v -u <EVENT_ID>." # # code: SUN4U-8000-AC # keys: fault.cpu.ultraSPARC-IIIi.l2cachedata @@ -179,11 +180,11 @@ msgstr "Major" msgid "SUN4U-8000-AC.description" msgstr "The number of errors associated with this CPU has exceeded acceptable levels. Refer to %s for more information." msgid "SUN4U-8000-AC.response" -msgstr "An attempt will be made to remove the affected CPU from service." +msgstr "The fault manager will attempt to remove the affected CPU from service." msgid "SUN4U-8000-AC.impact" -msgstr "Performance of this system may be affected." +msgstr "System performance may be affected." msgid "SUN4U-8000-AC.action" -msgstr "Schedule a repair procedure to replace the affected CPU. Use fmdump -v -u <EVENT_ID> to identify the CPU." +msgstr "Schedule a repair procedure to replace the affected CPU, the identity of which can be determined using fmdump -v -u <EVENT_ID>." # # code: SUN4U-8000-CQ # keys: fault.cpu.ultraSPARC-IIIi.l2cachetag @@ -195,11 +196,11 @@ msgstr "Major" msgid "SUN4U-8000-CQ.description" msgstr "The number of errors associated with this CPU has exceeded acceptable levels. Refer to %s for more information." msgid "SUN4U-8000-CQ.response" -msgstr "An attempt will be made to remove the affected CPU from service." +msgstr "The fault manager will attempt to remove the affected CPU from service." msgid "SUN4U-8000-CQ.impact" -msgstr "Performance of this system may be affected." +msgstr "System performance may be affected." msgid "SUN4U-8000-CQ.action" -msgstr "Schedule a repair procedure to replace the affected CPU. Use fmdump -v -u <EVENT_ID> to identify the CPU." +msgstr "Schedule a repair procedure to replace the affected CPU, the identity of which can be determined using fmdump -v -u <EVENT_ID>." # # code: SUN4U-8000-DE # keys: fault.cpu.ultraSPARC-IIIplus.dcache @@ -211,11 +212,11 @@ msgstr "Major" msgid "SUN4U-8000-DE.description" msgstr "The number of errors associated with this CPU has exceeded acceptable levels. Refer to %s for more information." msgid "SUN4U-8000-DE.response" -msgstr "An attempt will be made to remove the affected CPU from service." +msgstr "The fault manager will attempt to remove the affected CPU from service." msgid "SUN4U-8000-DE.impact" -msgstr "Performance of this system may be affected." +msgstr "System performance may be affected." msgid "SUN4U-8000-DE.action" -msgstr "Schedule a repair procedure to replace the affected CPU. Use fmdump -v -u <EVENT_ID> to identify the CPU." +msgstr "Schedule a repair procedure to replace the affected CPU, the identity of which can be determined using fmdump -v -u <EVENT_ID>." # # code: SUN4U-8000-EJ # keys: fault.cpu.ultraSPARC-IIIplus.icache @@ -227,11 +228,11 @@ msgstr "Major" msgid "SUN4U-8000-EJ.description" msgstr "The number of errors associated with this CPU has exceeded acceptable levels. Refer to %s for more information." msgid "SUN4U-8000-EJ.response" -msgstr "An attempt will be made to remove the affected CPU from service." +msgstr "The fault manager will attempt to remove the affected CPU from service." msgid "SUN4U-8000-EJ.impact" -msgstr "Performance of this system may be affected." +msgstr "System performance may be affected." msgid "SUN4U-8000-EJ.action" -msgstr "Schedule a repair procedure to replace the affected CPU. Use fmdump -v -u <EVENT_ID> to identify the CPU." +msgstr "Schedule a repair procedure to replace the affected CPU, the identity of which can be determined using fmdump -v -u <EVENT_ID>." # # code: SUN4U-8000-F2 # keys: fault.cpu.ultraSPARC-IIIplus.l2cachedata @@ -243,11 +244,11 @@ msgstr "Major" msgid "SUN4U-8000-F2.description" msgstr "The number of errors associated with this CPU has exceeded acceptable levels. Refer to %s for more information." msgid "SUN4U-8000-F2.response" -msgstr "An attempt will be made to remove the affected CPU from service." +msgstr "The fault manager will attempt to remove the affected CPU from service." msgid "SUN4U-8000-F2.impact" -msgstr "Performance of this system may be affected." +msgstr "System performance may be affected." msgid "SUN4U-8000-F2.action" -msgstr "Schedule a repair procedure to replace the affected CPU. Use fmdump -v -u <EVENT_ID> to identify the CPU." +msgstr "Schedule a repair procedure to replace the affected CPU, the identity of which can be determined using fmdump -v -u <EVENT_ID>." # # code: SUN4U-8000-GX # keys: fault.cpu.ultraSPARC-IIIplus.l2cachetag @@ -261,9 +262,9 @@ msgstr "The number of errors associated with this CPU has exceeded acceptable le msgid "SUN4U-8000-GX.response" msgstr "An attempt will be made to remove the affected CPU from service." msgid "SUN4U-8000-GX.impact" -msgstr "Performance of this system may be affected." +msgstr "System performance may be affected." msgid "SUN4U-8000-GX.action" -msgstr "Schedule a repair procedure to replace the affected CPU. Use fmdump -v -u <EVENT_ID> to identify the CPU." +msgstr "Schedule a repair procedure to replace the affected CPU. Use fmdump -v -u <EVENT_ID> to identify the CPU." # # code: SUN4U-8000-H5 # keys: fault.cpu.ultraSPARC-IV.dcache @@ -275,11 +276,11 @@ msgstr "Major" msgid "SUN4U-8000-H5.description" msgstr "The number of errors associated with this CPU has exceeded acceptable levels. Refer to %s for more information." msgid "SUN4U-8000-H5.response" -msgstr "An attempt will be made to remove the affected CPU from service." +msgstr "The fault manager will attempt to remove the affected CPU from service." msgid "SUN4U-8000-H5.impact" -msgstr "Performance of this system may be affected." +msgstr "System performance may be affected." msgid "SUN4U-8000-H5.action" -msgstr "Schedule a repair procedure to replace the affected CPU. Use fmdump -v -u <EVENT_ID> to identify the CPU." +msgstr "Schedule a repair procedure to replace the affected CPU, the identity of which can be determined using fmdump -v -u <EVENT_ID>." # # code: SUN4U-8000-JS # keys: fault.cpu.ultraSPARC-IV.icache @@ -291,11 +292,11 @@ msgstr "Major" msgid "SUN4U-8000-JS.description" msgstr "The number of errors associated with this CPU has exceeded acceptable levels. Refer to %s for more information." msgid "SUN4U-8000-JS.response" -msgstr "An attempt will be made to remove the affected CPU from service." +msgstr "The fault manager will attempt to remove the affected CPU from service." msgid "SUN4U-8000-JS.impact" -msgstr "Performance of this system may be affected." +msgstr "System performance may be affected." msgid "SUN4U-8000-JS.action" -msgstr "Schedule a repair procedure to replace the affected CPU. Use fmdump -v -u <EVENT_ID> to identify the CPU." +msgstr "Schedule a repair procedure to replace the affected CPU, the identity of which can be determined using fmdump -v -u <EVENT_ID>." # # code: SUN4U-8000-KA # keys: fault.cpu.ultraSPARC-IV.l2cachedata @@ -307,11 +308,11 @@ msgstr "Major" msgid "SUN4U-8000-KA.description" msgstr "The number of errors associated with this CPU has exceeded acceptable levels. Refer to %s for more information." msgid "SUN4U-8000-KA.response" -msgstr "An attempt will be made to remove the affected CPU from service." +msgstr "The fault manager will attempt to remove the affected CPU from service." msgid "SUN4U-8000-KA.impact" -msgstr "Performance of this system may be affected." +msgstr "System performance may be affected." msgid "SUN4U-8000-KA.action" -msgstr "Schedule a repair procedure to replace the affected CPU. Use fmdump -v -u <EVENT_ID> to identify the CPU." +msgstr "Schedule a repair procedure to replace the affected CPU, the identity of which can be determined using fmdump -v -u <EVENT_ID>." # # code: SUN4U-8000-LP # keys: fault.cpu.ultraSPARC-IV.l2cachetag @@ -323,11 +324,11 @@ msgstr "Major" msgid "SUN4U-8000-LP.description" msgstr "The number of errors associated with this CPU has exceeded acceptable levels. Refer to %s for more information." msgid "SUN4U-8000-LP.response" -msgstr "An attempt will be made to remove the affected CPU from service." +msgstr "The fault manager will attempt to remove the affected CPU from service." msgid "SUN4U-8000-LP.impact" -msgstr "Performance of this system may be affected." +msgstr "System performance may be affected." msgid "SUN4U-8000-LP.action" -msgstr "Schedule a repair procedure to replace the affected CPU. Use fmdump -v -u <EVENT_ID> to identify the CPU." +msgstr "Schedule a repair procedure to replace the affected CPU, the identity of which can be determined using fmdump -v -u <EVENT_ID>." # # code: SUN4U-8000-MD # keys: fault.cpu.ultraSPARC-III.fpu @@ -339,11 +340,11 @@ msgstr "Major" msgid "SUN4U-8000-MD.description" msgstr "A fault has been detected in the FPU of this CPU. Refer to %s for more information." msgid "SUN4U-8000-MD.response" -msgstr "An attempt will be made to remove the affected CPU from service." +msgstr "The fault manager will attempt to remove the affected CPU from service." msgid "SUN4U-8000-MD.impact" -msgstr "Performance of this system may be affected." +msgstr "System performance may be affected." msgid "SUN4U-8000-MD.action" -msgstr "Schedule a repair procedure to replace the affected CPU. Use fmdump -v -u <EVENT_ID> to identify the CPU." +msgstr "Schedule a repair procedure to replace the affected CPU, the identity of which can be determined using fmdump -v -u <EVENT_ID>." # # code: SUN4U-8000-NH # keys: fault.cpu.ultraSPARC-IIIi.fpu @@ -355,11 +356,11 @@ msgstr "Major" msgid "SUN4U-8000-NH.description" msgstr "A fault has been detected in the FPU of this CPU. Refer to %s for more information." msgid "SUN4U-8000-NH.response" -msgstr "An attempt will be made to remove the affected CPU from service." +msgstr "The fault manager will attempt to remove the affected CPU from service." msgid "SUN4U-8000-NH.impact" -msgstr "Performance of this system may be affected." +msgstr "System performance may be affected." msgid "SUN4U-8000-NH.action" -msgstr "Schedule a repair procedure to replace the affected CPU. Use fmdump -v -u <EVENT_ID> to identify the CPU." +msgstr "Schedule a repair procedure to replace the affected CPU, the identity of which can be determined using fmdump -v -u <EVENT_ID>." # # code: SUN4U-8000-P3 # keys: fault.cpu.ultraSPARC-IIIplus.fpu @@ -371,11 +372,11 @@ msgstr "Major" msgid "SUN4U-8000-P3.description" msgstr "A fault has been detected in the FPU of this CPU. Refer to %s for more information." msgid "SUN4U-8000-P3.response" -msgstr "An attempt will be made to remove the affected CPU from service." +msgstr "The fault manager will attempt to remove the affected CPU from service." msgid "SUN4U-8000-P3.impact" -msgstr "Performance of this system may be affected." +msgstr "System performance may be affected." msgid "SUN4U-8000-P3.action" -msgstr "Schedule a repair procedure to replace the affected CPU. Use fmdump -v -u <EVENT_ID> to identify the CPU." +msgstr "Schedule a repair procedure to replace the affected CPU, the identity of which can be determined using fmdump -v -u <EVENT_ID>." # # code: SUN4U-8000-QY # keys: fault.cpu.ultraSPARC-IV.fpu @@ -387,11 +388,11 @@ msgstr "Major" msgid "SUN4U-8000-QY.description" msgstr "A fault has been detected in the FPU of this CPU. Refer to %s for more information." msgid "SUN4U-8000-QY.response" -msgstr "An attempt will be made to remove the affected CPU from service." +msgstr "The fault manager will attempt to remove the affected CPU from service." msgid "SUN4U-8000-QY.impact" -msgstr "Performance of this system may be affected." +msgstr "System performance may be affected." msgid "SUN4U-8000-QY.action" -msgstr "Schedule a repair procedure to replace the affected CPU. Use fmdump -v -u <EVENT_ID> to identify the CPU." +msgstr "Schedule a repair procedure to replace the affected CPU, the identity of which can be determined using fmdump -v -u <EVENT_ID>." # # code: SUN4U-8000-RQ # keys: fault.cpu.ultraSPARC-IVplus.fpu @@ -403,11 +404,11 @@ msgstr "Major" msgid "SUN4U-8000-RQ.description" msgstr "A fault has been detected in the FPU of this CPU. Refer to %s for more information." msgid "SUN4U-8000-RQ.response" -msgstr "An attempt will be made to remove the affected CPU from service." +msgstr "The fault manager will attempt to remove the affected CPU from service." msgid "SUN4U-8000-RQ.impact" -msgstr "Performance of this system may be affected." +msgstr "System performance may be affected." msgid "SUN4U-8000-RQ.action" -msgstr "Schedule a repair procedure to replace the affected CPU. Use fmdump -v -u <EVENT_ID> to identify the CPU." +msgstr "Schedule a repair procedure to replace the affected CPU, the identity of which can be determined using fmdump -v -u <EVENT_ID>." # # code: SUN4U-8000-SC # keys: fault.cpu.ultraSPARC-IVplus.dcache @@ -419,11 +420,11 @@ msgstr "Major" msgid "SUN4U-8000-SC.description" msgstr "The number of errors associated with this CPU has exceeded acceptable levels. Refer to %s for more information." msgid "SUN4U-8000-SC.response" -msgstr "An attempt will be made to remove the affected CPU from service." +msgstr "The fault manager will attempt to remove the affected CPU from service." msgid "SUN4U-8000-SC.impact" -msgstr "Performance of this system may be affected." +msgstr "System performance may be affected." msgid "SUN4U-8000-SC.action" -msgstr "Schedule a repair procedure to replace the affected CPU. Use fmdump -v -u <EVENT_ID> to identify the CPU." +msgstr "Schedule a repair procedure to replace the affected CPU, the identity of which can be determined using fmdump -v -u <EVENT_ID>." # # code: SUN4U-8000-TR # keys: fault.cpu.ultraSPARC-IVplus.icache @@ -435,11 +436,11 @@ msgstr "Major" msgid "SUN4U-8000-TR.description" msgstr "The number of errors associated with this CPU has exceeded acceptable levels. Refer to %s for more information." msgid "SUN4U-8000-TR.response" -msgstr "An attempt will be made to remove the affected CPU from service." +msgstr "The fault manager will attempt to remove the affected CPU from service." msgid "SUN4U-8000-TR.impact" -msgstr "Performance of this system may be affected." +msgstr "System performance may be affected." msgid "SUN4U-8000-TR.action" -msgstr "Schedule a repair procedure to replace the affected CPU. Use fmdump -v -u <EVENT_ID> to identify the CPU." +msgstr "Schedule a repair procedure to replace the affected CPU, the identity of which can be determined using fmdump -v -u <EVENT_ID>." # # code: SUN4U-8000-U4 # keys: fault.cpu.ultraSPARC-IVplus.pcache @@ -451,11 +452,11 @@ msgstr "Major" msgid "SUN4U-8000-U4.description" msgstr "The number of errors associated with this CPU has exceeded acceptable levels. Refer to %s for more information." msgid "SUN4U-8000-U4.response" -msgstr "An attempt will be made to remove the affected CPU from service." +msgstr "The fault manager will attempt to remove the affected CPU from service." msgid "SUN4U-8000-U4.impact" -msgstr "Performance of this system may be affected." +msgstr "System performance may be affected." msgid "SUN4U-8000-U4.action" -msgstr "Schedule a repair procedure to replace the affected CPU. Use fmdump -v -u <EVENT_ID> to identify the CPU." +msgstr "Schedule a repair procedure to replace the affected CPU, the identity of which can be determined using fmdump -v -u <EVENT_ID>." # # code: SUN4U-8000-VX # keys: fault.cpu.ultraSPARC-IVplus.dtlb @@ -467,11 +468,11 @@ msgstr "Major" msgid "SUN4U-8000-VX.description" msgstr "The number of errors associated with this CPU has exceeded acceptable levels. Refer to %s for more information." msgid "SUN4U-8000-VX.response" -msgstr "An attempt will be made to remove the affected CPU from service." +msgstr "The fault manager will attempt to remove the affected CPU from service." msgid "SUN4U-8000-VX.impact" -msgstr "Performance of this system may be affected." +msgstr "System performance may be affected." msgid "SUN4U-8000-VX.action" -msgstr "Schedule a repair procedure to replace the affected CPU. Use fmdump -v -u <EVENT_ID> to identify the CPU." +msgstr "Schedule a repair procedure to replace the affected CPU, the identity of which can be determined using fmdump -v -u <EVENT_ID>." # # code: SUN4U-8000-W2 # keys: fault.cpu.ultraSPARC-IVplus.itlb @@ -483,11 +484,11 @@ msgstr "Major" msgid "SUN4U-8000-W2.description" msgstr "The number of errors associated with this CPU has exceeded acceptable levels. Refer to %s for more information." msgid "SUN4U-8000-W2.response" -msgstr "An attempt will be made to remove the affected CPU from service." +msgstr "The fault manager will attempt to remove the affected CPU from service." msgid "SUN4U-8000-W2.impact" -msgstr "Performance of this system may be affected." +msgstr "System performance may be affected." msgid "SUN4U-8000-W2.action" -msgstr "Schedule a repair procedure to replace the affected CPU. Use fmdump -v -u <EVENT_ID> to identify the CPU." +msgstr "Schedule a repair procedure to replace the affected CPU, the identity of which can be determined using fmdump -v -u <EVENT_ID>." # # code: SUN4U-8000-XJ # keys: fault.cpu.ultraSPARC-IVplus.l2cachedata @@ -499,11 +500,11 @@ msgstr "Major" msgid "SUN4U-8000-XJ.description" msgstr "The number of errors associated with this CPU has exceeded acceptable levels. Refer to %s for more information." msgid "SUN4U-8000-XJ.response" -msgstr "An attempt will be made to remove the affected CPU from service." +msgstr "The fault manager will attempt to remove the affected CPU from service." msgid "SUN4U-8000-XJ.impact" -msgstr "Performance of this system may be affected." +msgstr "System performance may be affected." msgid "SUN4U-8000-XJ.action" -msgstr "Schedule a repair procedure to replace the affected CPU. Use fmdump -v -u <EVENT_ID> to identify the CPU." +msgstr "Schedule a repair procedure to replace the affected CPU, the identity of which can be determined using fmdump -v -u <EVENT_ID>." # # code: SUN4U-8000-YE # keys: fault.cpu.ultraSPARC-IVplus.l2cachetag @@ -515,11 +516,11 @@ msgstr "Major" msgid "SUN4U-8000-YE.description" msgstr "The number of errors associated with this CPU has exceeded acceptable levels. Refer to %s for more information." msgid "SUN4U-8000-YE.response" -msgstr "An attempt will be made to remove the affected CPU from service." +msgstr "The fault manager will attempt to remove the affected CPU from service." msgid "SUN4U-8000-YE.impact" -msgstr "Performance of this system may be affected." +msgstr "System performance may be affected." msgid "SUN4U-8000-YE.action" -msgstr "Schedule a repair procedure to replace the affected CPU. Use fmdump -v -u <EVENT_ID> to identify the CPU." +msgstr "Schedule a repair procedure to replace the affected CPU, the identity of which can be determined using fmdump -v -u <EVENT_ID>." # # code: SUN4U-8001-0J # keys: fault.cpu.ultraSPARC-IVplus.l3cachedata @@ -531,11 +532,11 @@ msgstr "Major" msgid "SUN4U-8001-0J.description" msgstr "The number of errors associated with this CPU has exceeded acceptable levels. Refer to %s for more information." msgid "SUN4U-8001-0J.response" -msgstr "An attempt will be made to remove the affected CPU from service." +msgstr "The fault manager will attempt to remove the affected CPU from service." msgid "SUN4U-8001-0J.impact" -msgstr "Performance of this system may be affected." +msgstr "System performance may be affected." msgid "SUN4U-8001-0J.action" -msgstr "Schedule a repair procedure to replace the affected CPU. Use fmdump -v -u <EVENT_ID> to identify the CPU." +msgstr "Schedule a repair procedure to replace the affected CPU, the identity of which can be determined using fmdump -v -u <EVENT_ID>." # # code: SUN4U-8001-1E # keys: fault.cpu.ultraSPARC-IVplus.l3cachetag @@ -547,11 +548,11 @@ msgstr "Major" msgid "SUN4U-8001-1E.description" msgstr "The number of errors associated with this CPU has exceeded acceptable levels. Refer to %s for more information." msgid "SUN4U-8001-1E.response" -msgstr "An attempt will be made to remove the affected CPU from service." +msgstr "The fault manager will attempt to remove the affected CPU from service." msgid "SUN4U-8001-1E.impact" -msgstr "Performance of this system may be affected." +msgstr "System performance may be affected." msgid "SUN4U-8001-1E.action" -msgstr "Schedule a repair procedure to replace the affected CPU. Use fmdump -v -u <EVENT_ID> to identify the CPU." +msgstr "Schedule a repair procedure to replace the affected CPU, the identity of which can be determined using fmdump -v -u <EVENT_ID>." # # code: SUN4U-8001-2X # keys: defect.ultraSPARC-II.memory.nodiag @@ -561,7 +562,7 @@ msgstr "Defect" msgid "SUN4U-8001-2X.severity" msgstr "Minor" msgid "SUN4U-8001-2X.description" -msgstr "The Solaris Fault Manager received an event from the IO subsystem for which automated diagnosis software is currently unavailable. Refer to %s for more information" +msgstr "The Solaris Fault Manager received an event from the IO subsystem for which automated diagnosis software is currently unavailable. Refer to %s for more information." msgid "SUN4U-8001-2X.response" msgstr "The error information has been saved for examination by Sun." msgid "SUN4U-8001-2X.impact" @@ -593,13 +594,13 @@ msgstr "Fault" msgid "SUN4U-8001-4R.severity" msgstr "Critical" msgid "SUN4U-8001-4R.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8001-4R.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8001-4R.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8001-4R.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8001-54 # keys: defect.io.pci.driver fault.io.datapath @@ -609,13 +610,13 @@ msgstr "Fault" msgid "SUN4U-8001-54.severity" msgstr "Critical" msgid "SUN4U-8001-54.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8001-54.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8001-54.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8001-54.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8001-6Q # keys: fault.io.datapath fault.io.pci.bus @@ -625,13 +626,13 @@ msgstr "Fault" msgid "SUN4U-8001-6Q.severity" msgstr "Critical" msgid "SUN4U-8001-6Q.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8001-6Q.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8001-6Q.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8001-6Q.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8001-7C # keys: defect.io.pci.driver fault.io.datapath fault.io.pci.bus @@ -641,13 +642,13 @@ msgstr "Fault" msgid "SUN4U-8001-7C.severity" msgstr "Critical" msgid "SUN4U-8001-7C.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8001-7C.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8001-7C.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8001-7C.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8001-83 # keys: fault.io.datapath fault.io.pci.device @@ -657,13 +658,13 @@ msgstr "Fault" msgid "SUN4U-8001-83.severity" msgstr "Critical" msgid "SUN4U-8001-83.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8001-83.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8001-83.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8001-83.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8001-9Y # keys: defect.io.pci.driver fault.io.datapath fault.io.pci.device @@ -673,13 +674,13 @@ msgstr "Fault" msgid "SUN4U-8001-9Y.severity" msgstr "Critical" msgid "SUN4U-8001-9Y.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8001-9Y.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8001-9Y.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8001-9Y.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8001-AD # keys: fault.io.datapath fault.io.pci.bus fault.io.pci.device @@ -689,13 +690,13 @@ msgstr "Fault" msgid "SUN4U-8001-AD.severity" msgstr "Critical" msgid "SUN4U-8001-AD.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8001-AD.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8001-AD.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8001-AD.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8001-CH # keys: defect.io.pci.driver fault.io.datapath fault.io.pci.bus fault.io.pci.device @@ -705,13 +706,13 @@ msgstr "Fault" msgid "SUN4U-8001-CH.severity" msgstr "Critical" msgid "SUN4U-8001-CH.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8001-CH.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8001-CH.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8001-CH.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8001-DA # keys: fault.io.hbus @@ -721,13 +722,13 @@ msgstr "Fault" msgid "SUN4U-8001-DA.severity" msgstr "Critical" msgid "SUN4U-8001-DA.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8001-DA.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8001-DA.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8001-DA.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8001-EP # keys: defect.io.pci.driver fault.io.hbus @@ -737,13 +738,13 @@ msgstr "Fault" msgid "SUN4U-8001-EP.severity" msgstr "Critical" msgid "SUN4U-8001-EP.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8001-EP.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8001-EP.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8001-EP.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8001-F5 # keys: fault.io.hbus fault.io.pci.bus @@ -753,13 +754,13 @@ msgstr "Fault" msgid "SUN4U-8001-F5.severity" msgstr "Critical" msgid "SUN4U-8001-F5.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8001-F5.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8001-F5.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8001-F5.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8001-GS # keys: defect.io.pci.driver fault.io.hbus fault.io.pci.bus @@ -769,13 +770,13 @@ msgstr "Fault" msgid "SUN4U-8001-GS.severity" msgstr "Critical" msgid "SUN4U-8001-GS.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8001-GS.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8001-GS.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8001-GS.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8001-H2 # keys: fault.io.hbus fault.io.pci.device @@ -785,13 +786,13 @@ msgstr "Fault" msgid "SUN4U-8001-H2.severity" msgstr "Critical" msgid "SUN4U-8001-H2.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8001-H2.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8001-H2.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8001-H2.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8001-JX # keys: defect.io.pci.driver fault.io.hbus fault.io.pci.device @@ -801,13 +802,13 @@ msgstr "Fault" msgid "SUN4U-8001-JX.severity" msgstr "Critical" msgid "SUN4U-8001-JX.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8001-JX.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8001-JX.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8001-JX.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8001-KE # keys: fault.io.hbus fault.io.pci.bus fault.io.pci.device @@ -817,13 +818,13 @@ msgstr "Fault" msgid "SUN4U-8001-KE.severity" msgstr "Critical" msgid "SUN4U-8001-KE.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8001-KE.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8001-KE.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8001-KE.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8001-LJ # keys: defect.io.pci.driver fault.io.hbus fault.io.pci.bus fault.io.pci.device @@ -833,13 +834,13 @@ msgstr "Fault" msgid "SUN4U-8001-LJ.severity" msgstr "Critical" msgid "SUN4U-8001-LJ.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8001-LJ.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8001-LJ.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8001-LJ.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8001-MC # keys: fault.io.datapath fault.io.hbus @@ -849,13 +850,13 @@ msgstr "Fault" msgid "SUN4U-8001-MC.severity" msgstr "Critical" msgid "SUN4U-8001-MC.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8001-MC.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8001-MC.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8001-MC.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8001-NQ # keys: defect.io.pci.driver fault.io.datapath fault.io.hbus @@ -865,13 +866,13 @@ msgstr "Fault" msgid "SUN4U-8001-NQ.severity" msgstr "Critical" msgid "SUN4U-8001-NQ.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8001-NQ.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8001-NQ.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8001-NQ.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8001-P4 # keys: fault.io.datapath fault.io.hbus fault.io.pci.bus @@ -881,13 +882,13 @@ msgstr "Fault" msgid "SUN4U-8001-P4.severity" msgstr "Critical" msgid "SUN4U-8001-P4.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8001-P4.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8001-P4.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8001-P4.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8001-QR # keys: defect.io.pci.driver fault.io.datapath fault.io.hbus fault.io.pci.bus @@ -897,13 +898,13 @@ msgstr "Fault" msgid "SUN4U-8001-QR.severity" msgstr "Critical" msgid "SUN4U-8001-QR.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8001-QR.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8001-QR.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8001-QR.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8001-RH # keys: fault.io.datapath fault.io.hbus fault.io.pci.device @@ -913,13 +914,13 @@ msgstr "Fault" msgid "SUN4U-8001-RH.severity" msgstr "Critical" msgid "SUN4U-8001-RH.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8001-RH.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8001-RH.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8001-RH.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8001-SD # keys: defect.io.pci.driver fault.io.datapath fault.io.hbus fault.io.pci.device @@ -929,13 +930,13 @@ msgstr "Fault" msgid "SUN4U-8001-SD.severity" msgstr "Critical" msgid "SUN4U-8001-SD.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8001-SD.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8001-SD.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8001-SD.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8001-TY # keys: fault.io.datapath fault.io.hbus fault.io.pci.bus fault.io.pci.device @@ -945,13 +946,13 @@ msgstr "Fault" msgid "SUN4U-8001-TY.severity" msgstr "Critical" msgid "SUN4U-8001-TY.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8001-TY.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8001-TY.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8001-TY.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8001-U3 # keys: defect.io.pci.driver fault.io.datapath fault.io.hbus fault.io.pci.bus fault.io.pci.device @@ -961,13 +962,13 @@ msgstr "Fault" msgid "SUN4U-8001-U3.severity" msgstr "Critical" msgid "SUN4U-8001-U3.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8001-U3.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8001-U3.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8001-U3.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8001-VS # keys: fault.io.schizo @@ -977,13 +978,13 @@ msgstr "Fault" msgid "SUN4U-8001-VS.severity" msgstr "Critical" msgid "SUN4U-8001-VS.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8001-VS.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8001-VS.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8001-VS.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8001-W5 # keys: defect.io.pci.driver fault.io.schizo @@ -993,13 +994,13 @@ msgstr "Fault" msgid "SUN4U-8001-W5.severity" msgstr "Critical" msgid "SUN4U-8001-W5.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8001-W5.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8001-W5.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8001-W5.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8001-XP # keys: fault.io.pci.bus fault.io.schizo @@ -1009,13 +1010,13 @@ msgstr "Fault" msgid "SUN4U-8001-XP.severity" msgstr "Critical" msgid "SUN4U-8001-XP.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8001-XP.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8001-XP.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8001-XP.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8001-YA # keys: defect.io.pci.driver fault.io.pci.bus fault.io.schizo @@ -1025,13 +1026,13 @@ msgstr "Fault" msgid "SUN4U-8001-YA.severity" msgstr "Critical" msgid "SUN4U-8001-YA.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8001-YA.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8001-YA.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8001-YA.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8002-0R # keys: fault.io.pci.device fault.io.schizo @@ -1041,13 +1042,13 @@ msgstr "Fault" msgid "SUN4U-8002-0R.severity" msgstr "Critical" msgid "SUN4U-8002-0R.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8002-0R.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8002-0R.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8002-0R.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8002-14 # keys: defect.io.pci.driver fault.io.pci.device fault.io.schizo @@ -1057,13 +1058,13 @@ msgstr "Fault" msgid "SUN4U-8002-14.severity" msgstr "Critical" msgid "SUN4U-8002-14.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8002-14.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8002-14.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8002-14.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8002-2Q # keys: fault.io.pci.bus fault.io.pci.device fault.io.schizo @@ -1073,13 +1074,13 @@ msgstr "Fault" msgid "SUN4U-8002-2Q.severity" msgstr "Critical" msgid "SUN4U-8002-2Q.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8002-2Q.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8002-2Q.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8002-2Q.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8002-3C # keys: defect.io.pci.driver fault.io.pci.bus fault.io.pci.device fault.io.schizo @@ -1089,13 +1090,13 @@ msgstr "Fault" msgid "SUN4U-8002-3C.severity" msgstr "Critical" msgid "SUN4U-8002-3C.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8002-3C.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8002-3C.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8002-3C.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8002-4J # keys: fault.io.datapath fault.io.schizo @@ -1105,13 +1106,13 @@ msgstr "Fault" msgid "SUN4U-8002-4J.severity" msgstr "Critical" msgid "SUN4U-8002-4J.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8002-4J.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8002-4J.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8002-4J.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8002-5E # keys: defect.io.pci.driver fault.io.datapath fault.io.schizo @@ -1121,13 +1122,13 @@ msgstr "Fault" msgid "SUN4U-8002-5E.severity" msgstr "Critical" msgid "SUN4U-8002-5E.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8002-5E.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8002-5E.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8002-5E.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8002-6X # keys: fault.io.datapath fault.io.pci.bus fault.io.schizo @@ -1137,13 +1138,13 @@ msgstr "Fault" msgid "SUN4U-8002-6X.severity" msgstr "Critical" msgid "SUN4U-8002-6X.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8002-6X.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8002-6X.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8002-6X.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8002-72 # keys: defect.io.pci.driver fault.io.datapath fault.io.pci.bus fault.io.schizo @@ -1153,13 +1154,13 @@ msgstr "Fault" msgid "SUN4U-8002-72.severity" msgstr "Critical" msgid "SUN4U-8002-72.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8002-72.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8002-72.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8002-72.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8002-8A # keys: fault.io.datapath fault.io.pci.device fault.io.schizo @@ -1169,13 +1170,13 @@ msgstr "Fault" msgid "SUN4U-8002-8A.severity" msgstr "Critical" msgid "SUN4U-8002-8A.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8002-8A.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8002-8A.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8002-8A.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8002-9P # keys: defect.io.pci.driver fault.io.datapath fault.io.pci.device fault.io.schizo @@ -1185,13 +1186,13 @@ msgstr "Fault" msgid "SUN4U-8002-9P.severity" msgstr "Critical" msgid "SUN4U-8002-9P.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8002-9P.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8002-9P.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8002-9P.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8002-A5 # keys: fault.io.datapath fault.io.pci.bus fault.io.pci.device fault.io.schizo @@ -1201,13 +1202,13 @@ msgstr "Fault" msgid "SUN4U-8002-A5.severity" msgstr "Critical" msgid "SUN4U-8002-A5.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8002-A5.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8002-A5.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8002-A5.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8002-CS # keys: defect.io.pci.driver fault.io.datapath fault.io.pci.bus fault.io.pci.device fault.io.schizo @@ -1217,13 +1218,13 @@ msgstr "Fault" msgid "SUN4U-8002-CS.severity" msgstr "Critical" msgid "SUN4U-8002-CS.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8002-CS.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8002-CS.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8002-CS.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8002-D3 # keys: fault.io.hbus fault.io.schizo @@ -1233,13 +1234,13 @@ msgstr "Fault" msgid "SUN4U-8002-D3.severity" msgstr "Critical" msgid "SUN4U-8002-D3.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8002-D3.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8002-D3.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8002-D3.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8002-EY # keys: defect.io.pci.driver fault.io.hbus fault.io.schizo @@ -1249,13 +1250,13 @@ msgstr "Fault" msgid "SUN4U-8002-EY.severity" msgstr "Critical" msgid "SUN4U-8002-EY.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8002-EY.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8002-EY.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8002-EY.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8002-FD # keys: fault.io.hbus fault.io.pci.bus fault.io.schizo @@ -1265,13 +1266,13 @@ msgstr "Fault" msgid "SUN4U-8002-FD.severity" msgstr "Critical" msgid "SUN4U-8002-FD.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8002-FD.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8002-FD.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8002-FD.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8002-GH # keys: defect.io.pci.driver fault.io.hbus fault.io.pci.bus fault.io.schizo @@ -1281,13 +1282,13 @@ msgstr "Fault" msgid "SUN4U-8002-GH.severity" msgstr "Critical" msgid "SUN4U-8002-GH.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8002-GH.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8002-GH.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8002-GH.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8002-HC # keys: fault.io.hbus fault.io.pci.device fault.io.schizo @@ -1297,13 +1298,13 @@ msgstr "Fault" msgid "SUN4U-8002-HC.severity" msgstr "Critical" msgid "SUN4U-8002-HC.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8002-HC.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8002-HC.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8002-HC.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8002-JQ # keys: defect.io.pci.driver fault.io.hbus fault.io.pci.device fault.io.schizo @@ -1313,13 +1314,13 @@ msgstr "Fault" msgid "SUN4U-8002-JQ.severity" msgstr "Critical" msgid "SUN4U-8002-JQ.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8002-JQ.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8002-JQ.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8002-JQ.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8002-K4 # keys: fault.io.hbus fault.io.pci.bus fault.io.pci.device fault.io.schizo @@ -1329,13 +1330,13 @@ msgstr "Fault" msgid "SUN4U-8002-K4.severity" msgstr "Critical" msgid "SUN4U-8002-K4.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8002-K4.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8002-K4.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8002-K4.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8002-LR # keys: defect.io.pci.driver fault.io.hbus fault.io.pci.bus fault.io.pci.device fault.io.schizo @@ -1345,13 +1346,13 @@ msgstr "Fault" msgid "SUN4U-8002-LR.severity" msgstr "Critical" msgid "SUN4U-8002-LR.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8002-LR.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8002-LR.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8002-LR.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8002-M2 # keys: fault.io.datapath fault.io.hbus fault.io.schizo @@ -1361,13 +1362,13 @@ msgstr "Fault" msgid "SUN4U-8002-M2.severity" msgstr "Critical" msgid "SUN4U-8002-M2.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8002-M2.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8002-M2.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8002-M2.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8002-NX # keys: defect.io.pci.driver fault.io.datapath fault.io.hbus fault.io.schizo @@ -1377,13 +1378,13 @@ msgstr "Fault" msgid "SUN4U-8002-NX.severity" msgstr "Critical" msgid "SUN4U-8002-NX.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8002-NX.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8002-NX.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8002-NX.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8002-PE # keys: fault.io.datapath fault.io.hbus fault.io.pci.bus fault.io.schizo @@ -1393,13 +1394,13 @@ msgstr "Fault" msgid "SUN4U-8002-PE.severity" msgstr "Critical" msgid "SUN4U-8002-PE.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8002-PE.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8002-PE.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8002-PE.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8002-QJ # keys: defect.io.pci.driver fault.io.datapath fault.io.hbus fault.io.pci.bus fault.io.schizo @@ -1409,13 +1410,13 @@ msgstr "Fault" msgid "SUN4U-8002-QJ.severity" msgstr "Critical" msgid "SUN4U-8002-QJ.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8002-QJ.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8002-QJ.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8002-QJ.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8002-RS # keys: fault.io.datapath fault.io.hbus fault.io.pci.device fault.io.schizo @@ -1425,13 +1426,13 @@ msgstr "Fault" msgid "SUN4U-8002-RS.severity" msgstr "Critical" msgid "SUN4U-8002-RS.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8002-RS.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8002-RS.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8002-RS.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8002-S5 # keys: defect.io.pci.driver fault.io.datapath fault.io.hbus fault.io.pci.device fault.io.schizo @@ -1441,13 +1442,13 @@ msgstr "Fault" msgid "SUN4U-8002-S5.severity" msgstr "Critical" msgid "SUN4U-8002-S5.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8002-S5.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8002-S5.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8002-S5.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8002-TP # keys: fault.io.datapath fault.io.hbus fault.io.pci.bus fault.io.pci.device fault.io.schizo @@ -1457,13 +1458,13 @@ msgstr "Fault" msgid "SUN4U-8002-TP.severity" msgstr "Critical" msgid "SUN4U-8002-TP.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8002-TP.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8002-TP.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8002-TP.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8002-UA # keys: defect.io.pci.driver fault.io.datapath fault.io.hbus fault.io.pci.bus fault.io.pci.device fault.io.schizo @@ -1473,13 +1474,13 @@ msgstr "Fault" msgid "SUN4U-8002-UA.severity" msgstr "Critical" msgid "SUN4U-8002-UA.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8002-UA.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8002-UA.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8002-UA.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8002-VH # keys: fault.io.xmits @@ -1489,13 +1490,13 @@ msgstr "Fault" msgid "SUN4U-8002-VH.severity" msgstr "Critical" msgid "SUN4U-8002-VH.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8002-VH.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8002-VH.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8002-VH.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8002-WD # keys: defect.io.pci.driver fault.io.xmits @@ -1505,13 +1506,13 @@ msgstr "Fault" msgid "SUN4U-8002-WD.severity" msgstr "Critical" msgid "SUN4U-8002-WD.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8002-WD.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8002-WD.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8002-WD.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8002-XY # keys: fault.io.pci.bus fault.io.xmits @@ -1521,13 +1522,13 @@ msgstr "Fault" msgid "SUN4U-8002-XY.severity" msgstr "Critical" msgid "SUN4U-8002-XY.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8002-XY.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8002-XY.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8002-XY.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8002-Y3 # keys: defect.io.pci.driver fault.io.pci.bus fault.io.xmits @@ -1537,13 +1538,13 @@ msgstr "Fault" msgid "SUN4U-8002-Y3.severity" msgstr "Critical" msgid "SUN4U-8002-Y3.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8002-Y3.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8002-Y3.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8002-Y3.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8003-0Y # keys: fault.io.pci.device fault.io.xmits @@ -1553,13 +1554,13 @@ msgstr "Fault" msgid "SUN4U-8003-0Y.severity" msgstr "Critical" msgid "SUN4U-8003-0Y.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8003-0Y.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8003-0Y.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8003-0Y.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8003-13 # keys: defect.io.pci.driver fault.io.pci.device fault.io.xmits @@ -1569,13 +1570,13 @@ msgstr "Fault" msgid "SUN4U-8003-13.severity" msgstr "Critical" msgid "SUN4U-8003-13.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8003-13.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8003-13.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8003-13.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8003-2H # keys: fault.io.pci.bus fault.io.pci.device fault.io.xmits @@ -1585,13 +1586,13 @@ msgstr "Fault" msgid "SUN4U-8003-2H.severity" msgstr "Critical" msgid "SUN4U-8003-2H.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8003-2H.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8003-2H.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8003-2H.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8003-3D # keys: defect.io.pci.driver fault.io.pci.bus fault.io.pci.device fault.io.xmits @@ -1601,13 +1602,13 @@ msgstr "Fault" msgid "SUN4U-8003-3D.severity" msgstr "Critical" msgid "SUN4U-8003-3D.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8003-3D.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8003-3D.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8003-3D.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8003-4P # keys: fault.io.datapath fault.io.xmits @@ -1617,13 +1618,13 @@ msgstr "Fault" msgid "SUN4U-8003-4P.severity" msgstr "Critical" msgid "SUN4U-8003-4P.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8003-4P.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8003-4P.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8003-4P.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8003-5A # keys: defect.io.pci.driver fault.io.datapath fault.io.xmits @@ -1633,13 +1634,13 @@ msgstr "Fault" msgid "SUN4U-8003-5A.severity" msgstr "Critical" msgid "SUN4U-8003-5A.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8003-5A.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8003-5A.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8003-5A.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8003-6S # keys: fault.io.datapath fault.io.pci.bus fault.io.xmits @@ -1649,13 +1650,13 @@ msgstr "Fault" msgid "SUN4U-8003-6S.severity" msgstr "Critical" msgid "SUN4U-8003-6S.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8003-6S.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8003-6S.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8003-6S.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8003-75 # keys: defect.io.pci.driver fault.io.datapath fault.io.pci.bus fault.io.xmits @@ -1665,13 +1666,13 @@ msgstr "Fault" msgid "SUN4U-8003-75.severity" msgstr "Critical" msgid "SUN4U-8003-75.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8003-75.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8003-75.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8003-75.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8003-8E # keys: fault.io.datapath fault.io.pci.device fault.io.xmits @@ -1681,13 +1682,13 @@ msgstr "Fault" msgid "SUN4U-8003-8E.severity" msgstr "Critical" msgid "SUN4U-8003-8E.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8003-8E.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8003-8E.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8003-8E.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8003-9J # keys: defect.io.pci.driver fault.io.datapath fault.io.pci.device fault.io.xmits @@ -1697,13 +1698,13 @@ msgstr "Fault" msgid "SUN4U-8003-9J.severity" msgstr "Critical" msgid "SUN4U-8003-9J.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8003-9J.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8003-9J.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8003-9J.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8003-A2 # keys: fault.io.datapath fault.io.pci.bus fault.io.pci.device fault.io.xmits @@ -1713,13 +1714,13 @@ msgstr "Fault" msgid "SUN4U-8003-A2.severity" msgstr "Critical" msgid "SUN4U-8003-A2.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8003-A2.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8003-A2.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8003-A2.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8003-CX # keys: defect.io.pci.driver fault.io.datapath fault.io.pci.bus fault.io.pci.device fault.io.xmits @@ -1729,13 +1730,13 @@ msgstr "Fault" msgid "SUN4U-8003-CX.severity" msgstr "Critical" msgid "SUN4U-8003-CX.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8003-CX.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8003-CX.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8003-CX.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8003-D4 # keys: fault.io.hbus fault.io.xmits @@ -1745,13 +1746,13 @@ msgstr "Fault" msgid "SUN4U-8003-D4.severity" msgstr "Critical" msgid "SUN4U-8003-D4.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8003-D4.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8003-D4.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8003-D4.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8003-ER # keys: defect.io.pci.driver fault.io.hbus fault.io.xmits @@ -1761,13 +1762,13 @@ msgstr "Fault" msgid "SUN4U-8003-ER.severity" msgstr "Critical" msgid "SUN4U-8003-ER.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8003-ER.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8003-ER.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8003-ER.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8003-FC # keys: fault.io.hbus fault.io.pci.bus fault.io.xmits @@ -1777,13 +1778,13 @@ msgstr "Fault" msgid "SUN4U-8003-FC.severity" msgstr "Critical" msgid "SUN4U-8003-FC.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8003-FC.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8003-FC.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8003-FC.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8003-GQ # keys: defect.io.pci.driver fault.io.hbus fault.io.pci.bus fault.io.xmits @@ -1793,13 +1794,13 @@ msgstr "Fault" msgid "SUN4U-8003-GQ.severity" msgstr "Critical" msgid "SUN4U-8003-GQ.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8003-GQ.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8003-GQ.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8003-GQ.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8003-HD # keys: fault.io.hbus fault.io.pci.device fault.io.xmits @@ -1809,13 +1810,13 @@ msgstr "Fault" msgid "SUN4U-8003-HD.severity" msgstr "Critical" msgid "SUN4U-8003-HD.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8003-HD.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8003-HD.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8003-HD.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8003-JH # keys: defect.io.pci.driver fault.io.hbus fault.io.pci.device fault.io.xmits @@ -1825,13 +1826,13 @@ msgstr "Fault" msgid "SUN4U-8003-JH.severity" msgstr "Critical" msgid "SUN4U-8003-JH.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8003-JH.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8003-JH.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8003-JH.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8003-K3 # keys: fault.io.hbus fault.io.pci.bus fault.io.pci.device fault.io.xmits @@ -1841,13 +1842,13 @@ msgstr "Fault" msgid "SUN4U-8003-K3.severity" msgstr "Critical" msgid "SUN4U-8003-K3.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8003-K3.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8003-K3.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8003-K3.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8003-LY # keys: defect.io.pci.driver fault.io.hbus fault.io.pci.bus fault.io.pci.device fault.io.xmits @@ -1857,13 +1858,13 @@ msgstr "Fault" msgid "SUN4U-8003-LY.severity" msgstr "Critical" msgid "SUN4U-8003-LY.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8003-LY.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8003-LY.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8003-LY.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8003-M5 # keys: fault.io.datapath fault.io.hbus fault.io.xmits @@ -1873,13 +1874,13 @@ msgstr "Fault" msgid "SUN4U-8003-M5.severity" msgstr "Critical" msgid "SUN4U-8003-M5.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8003-M5.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8003-M5.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8003-M5.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8003-NS # keys: defect.io.pci.driver fault.io.datapath fault.io.hbus fault.io.xmits @@ -1889,13 +1890,13 @@ msgstr "Fault" msgid "SUN4U-8003-NS.severity" msgstr "Critical" msgid "SUN4U-8003-NS.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8003-NS.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8003-NS.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8003-NS.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8003-PA # keys: fault.io.datapath fault.io.hbus fault.io.pci.bus fault.io.xmits @@ -1905,13 +1906,13 @@ msgstr "Fault" msgid "SUN4U-8003-PA.severity" msgstr "Critical" msgid "SUN4U-8003-PA.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8003-PA.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8003-PA.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8003-PA.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8003-QP # keys: defect.io.pci.driver fault.io.datapath fault.io.hbus fault.io.pci.bus fault.io.xmits @@ -1921,13 +1922,13 @@ msgstr "Fault" msgid "SUN4U-8003-QP.severity" msgstr "Critical" msgid "SUN4U-8003-QP.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8003-QP.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8003-QP.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8003-QP.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8003-RX # keys: fault.io.datapath fault.io.hbus fault.io.pci.device fault.io.xmits @@ -1937,13 +1938,13 @@ msgstr "Fault" msgid "SUN4U-8003-RX.severity" msgstr "Critical" msgid "SUN4U-8003-RX.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8003-RX.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8003-RX.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8003-RX.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8003-S2 # keys: defect.io.pci.driver fault.io.datapath fault.io.hbus fault.io.pci.device fault.io.xmits @@ -1953,13 +1954,13 @@ msgstr "Fault" msgid "SUN4U-8003-S2.severity" msgstr "Critical" msgid "SUN4U-8003-S2.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8003-S2.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8003-S2.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8003-S2.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8003-TJ # keys: fault.io.datapath fault.io.hbus fault.io.pci.bus fault.io.pci.device fault.io.xmits @@ -1969,13 +1970,13 @@ msgstr "Fault" msgid "SUN4U-8003-TJ.severity" msgstr "Critical" msgid "SUN4U-8003-TJ.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8003-TJ.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8003-TJ.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8003-TJ.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8003-UE # keys: defect.io.pci.driver fault.io.datapath fault.io.hbus fault.io.pci.bus fault.io.pci.device fault.io.xmits @@ -1985,13 +1986,13 @@ msgstr "Fault" msgid "SUN4U-8003-UE.severity" msgstr "Critical" msgid "SUN4U-8003-UE.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8003-UE.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8003-UE.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8003-UE.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8003-VQ # keys: fault.io.schizo fault.io.xmits @@ -2001,13 +2002,13 @@ msgstr "Fault" msgid "SUN4U-8003-VQ.severity" msgstr "Critical" msgid "SUN4U-8003-VQ.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8003-VQ.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8003-VQ.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8003-VQ.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8003-WC # keys: defect.io.pci.driver fault.io.schizo fault.io.xmits @@ -2017,13 +2018,13 @@ msgstr "Fault" msgid "SUN4U-8003-WC.severity" msgstr "Critical" msgid "SUN4U-8003-WC.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8003-WC.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8003-WC.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8003-WC.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8003-XR # keys: fault.io.pci.bus fault.io.schizo fault.io.xmits @@ -2033,13 +2034,13 @@ msgstr "Fault" msgid "SUN4U-8003-XR.severity" msgstr "Critical" msgid "SUN4U-8003-XR.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8003-XR.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8003-XR.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8003-XR.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8003-Y4 # keys: defect.io.pci.driver fault.io.pci.bus fault.io.schizo fault.io.xmits @@ -2049,13 +2050,13 @@ msgstr "Fault" msgid "SUN4U-8003-Y4.severity" msgstr "Critical" msgid "SUN4U-8003-Y4.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8003-Y4.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8003-Y4.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8003-Y4.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8004-0A # keys: fault.io.pci.device fault.io.schizo fault.io.xmits @@ -2065,13 +2066,13 @@ msgstr "Fault" msgid "SUN4U-8004-0A.severity" msgstr "Critical" msgid "SUN4U-8004-0A.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8004-0A.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8004-0A.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8004-0A.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8004-1P # keys: defect.io.pci.driver fault.io.pci.device fault.io.schizo fault.io.xmits @@ -2081,13 +2082,13 @@ msgstr "Fault" msgid "SUN4U-8004-1P.severity" msgstr "Critical" msgid "SUN4U-8004-1P.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8004-1P.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8004-1P.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8004-1P.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8004-25 # keys: fault.io.pci.bus fault.io.pci.device fault.io.schizo fault.io.xmits @@ -2097,13 +2098,13 @@ msgstr "Fault" msgid "SUN4U-8004-25.severity" msgstr "Critical" msgid "SUN4U-8004-25.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8004-25.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8004-25.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8004-25.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8004-3S # keys: defect.io.pci.driver fault.io.pci.bus fault.io.pci.device fault.io.schizo fault.io.xmits @@ -2113,13 +2114,13 @@ msgstr "Fault" msgid "SUN4U-8004-3S.severity" msgstr "Critical" msgid "SUN4U-8004-3S.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8004-3S.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8004-3S.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8004-3S.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8004-43 # keys: fault.io.datapath fault.io.schizo fault.io.xmits @@ -2129,13 +2130,13 @@ msgstr "Fault" msgid "SUN4U-8004-43.severity" msgstr "Critical" msgid "SUN4U-8004-43.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8004-43.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8004-43.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8004-43.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8004-5Y # keys: defect.io.pci.driver fault.io.datapath fault.io.schizo fault.io.xmits @@ -2145,13 +2146,13 @@ msgstr "Fault" msgid "SUN4U-8004-5Y.severity" msgstr "Critical" msgid "SUN4U-8004-5Y.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8004-5Y.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8004-5Y.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8004-5Y.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8004-6D # keys: fault.io.datapath fault.io.pci.bus fault.io.schizo fault.io.xmits @@ -2161,13 +2162,13 @@ msgstr "Fault" msgid "SUN4U-8004-6D.severity" msgstr "Critical" msgid "SUN4U-8004-6D.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8004-6D.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8004-6D.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8004-6D.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8004-7H # keys: defect.io.pci.driver fault.io.datapath fault.io.pci.bus fault.io.schizo fault.io.xmits @@ -2177,13 +2178,13 @@ msgstr "Fault" msgid "SUN4U-8004-7H.severity" msgstr "Critical" msgid "SUN4U-8004-7H.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8004-7H.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8004-7H.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8004-7H.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8004-8R # keys: fault.io.datapath fault.io.pci.device fault.io.schizo fault.io.xmits @@ -2193,13 +2194,13 @@ msgstr "Fault" msgid "SUN4U-8004-8R.severity" msgstr "Critical" msgid "SUN4U-8004-8R.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8004-8R.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8004-8R.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8004-8R.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8004-94 # keys: defect.io.pci.driver fault.io.datapath fault.io.pci.device fault.io.schizo fault.io.xmits @@ -2209,13 +2210,13 @@ msgstr "Fault" msgid "SUN4U-8004-94.severity" msgstr "Critical" msgid "SUN4U-8004-94.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8004-94.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8004-94.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8004-94.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8004-AQ # keys: fault.io.datapath fault.io.pci.bus fault.io.pci.device fault.io.schizo fault.io.xmits @@ -2225,13 +2226,13 @@ msgstr "Fault" msgid "SUN4U-8004-AQ.severity" msgstr "Critical" msgid "SUN4U-8004-AQ.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8004-AQ.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8004-AQ.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8004-AQ.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8004-CC # keys: defect.io.pci.driver fault.io.datapath fault.io.pci.bus fault.io.pci.device fault.io.schizo fault.io.xmits @@ -2241,13 +2242,13 @@ msgstr "Fault" msgid "SUN4U-8004-CC.severity" msgstr "Critical" msgid "SUN4U-8004-CC.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8004-CC.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8004-CC.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8004-CC.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8004-DJ # keys: fault.io.hbus fault.io.schizo fault.io.xmits @@ -2257,13 +2258,13 @@ msgstr "Fault" msgid "SUN4U-8004-DJ.severity" msgstr "Critical" msgid "SUN4U-8004-DJ.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8004-DJ.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8004-DJ.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8004-DJ.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8004-EE # keys: defect.io.pci.driver fault.io.hbus fault.io.schizo fault.io.xmits @@ -2273,13 +2274,13 @@ msgstr "Fault" msgid "SUN4U-8004-EE.severity" msgstr "Critical" msgid "SUN4U-8004-EE.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8004-EE.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8004-EE.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8004-EE.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8004-FX # keys: fault.io.hbus fault.io.pci.bus fault.io.schizo fault.io.xmits @@ -2289,13 +2290,13 @@ msgstr "Fault" msgid "SUN4U-8004-FX.severity" msgstr "Critical" msgid "SUN4U-8004-FX.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8004-FX.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8004-FX.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8004-FX.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8004-G2 # keys: defect.io.pci.driver fault.io.hbus fault.io.pci.bus fault.io.schizo fault.io.xmits @@ -2305,13 +2306,13 @@ msgstr "Fault" msgid "SUN4U-8004-G2.severity" msgstr "Critical" msgid "SUN4U-8004-G2.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8004-G2.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8004-G2.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8004-G2.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8004-HS # keys: fault.io.hbus fault.io.pci.device fault.io.schizo fault.io.xmits @@ -2321,13 +2322,13 @@ msgstr "Fault" msgid "SUN4U-8004-HS.severity" msgstr "Critical" msgid "SUN4U-8004-HS.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8004-HS.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8004-HS.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8004-HS.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8004-J5 # keys: defect.io.pci.driver fault.io.hbus fault.io.pci.device fault.io.schizo fault.io.xmits @@ -2337,13 +2338,13 @@ msgstr "Fault" msgid "SUN4U-8004-J5.severity" msgstr "Critical" msgid "SUN4U-8004-J5.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8004-J5.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8004-J5.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8004-J5.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8004-KP # keys: fault.io.hbus fault.io.pci.bus fault.io.pci.device fault.io.schizo fault.io.xmits @@ -2353,13 +2354,13 @@ msgstr "Fault" msgid "SUN4U-8004-KP.severity" msgstr "Critical" msgid "SUN4U-8004-KP.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8004-KP.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8004-KP.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8004-KP.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8004-LA # keys: defect.io.pci.driver fault.io.hbus fault.io.pci.bus fault.io.pci.device fault.io.schizo fault.io.xmits @@ -2369,13 +2370,13 @@ msgstr "Fault" msgid "SUN4U-8004-LA.severity" msgstr "Critical" msgid "SUN4U-8004-LA.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8004-LA.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8004-LA.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8004-LA.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8004-MH # keys: fault.io.datapath fault.io.hbus fault.io.schizo fault.io.xmits @@ -2385,13 +2386,13 @@ msgstr "Fault" msgid "SUN4U-8004-MH.severity" msgstr "Critical" msgid "SUN4U-8004-MH.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8004-MH.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8004-MH.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8004-MH.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8004-ND # keys: defect.io.pci.driver fault.io.datapath fault.io.hbus fault.io.schizo fault.io.xmits @@ -2401,13 +2402,13 @@ msgstr "Fault" msgid "SUN4U-8004-ND.severity" msgstr "Critical" msgid "SUN4U-8004-ND.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8004-ND.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8004-ND.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8004-ND.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8004-PY # keys: fault.io.datapath fault.io.hbus fault.io.pci.bus fault.io.schizo fault.io.xmits @@ -2417,13 +2418,13 @@ msgstr "Fault" msgid "SUN4U-8004-PY.severity" msgstr "Critical" msgid "SUN4U-8004-PY.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8004-PY.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8004-PY.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8004-PY.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8004-Q3 # keys: defect.io.pci.driver fault.io.datapath fault.io.hbus fault.io.pci.bus fault.io.schizo fault.io.xmits @@ -2433,13 +2434,13 @@ msgstr "Fault" msgid "SUN4U-8004-Q3.severity" msgstr "Critical" msgid "SUN4U-8004-Q3.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8004-Q3.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8004-Q3.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8004-Q3.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8004-RC # keys: fault.io.datapath fault.io.hbus fault.io.pci.device fault.io.schizo fault.io.xmits @@ -2449,13 +2450,13 @@ msgstr "Fault" msgid "SUN4U-8004-RC.severity" msgstr "Critical" msgid "SUN4U-8004-RC.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8004-RC.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8004-RC.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8004-RC.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8004-SQ # keys: defect.io.pci.driver fault.io.datapath fault.io.hbus fault.io.pci.device fault.io.schizo fault.io.xmits @@ -2465,13 +2466,13 @@ msgstr "Fault" msgid "SUN4U-8004-SQ.severity" msgstr "Critical" msgid "SUN4U-8004-SQ.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8004-SQ.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8004-SQ.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8004-SQ.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8004-T4 # keys: fault.io.datapath fault.io.hbus fault.io.pci.bus fault.io.pci.device fault.io.schizo fault.io.xmits @@ -2481,13 +2482,13 @@ msgstr "Fault" msgid "SUN4U-8004-T4.severity" msgstr "Critical" msgid "SUN4U-8004-T4.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8004-T4.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8004-T4.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8004-T4.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8004-UR # keys: defect.io.pci.driver fault.io.datapath fault.io.hbus fault.io.pci.bus fault.io.pci.device fault.io.schizo fault.io.xmits @@ -2497,13 +2498,13 @@ msgstr "Fault" msgid "SUN4U-8004-UR.severity" msgstr "Critical" msgid "SUN4U-8004-UR.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8004-UR.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8004-UR.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8004-UR.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8004-V2 # keys: fault.io.psycho @@ -2513,13 +2514,13 @@ msgstr "Fault" msgid "SUN4U-8004-V2.severity" msgstr "Critical" msgid "SUN4U-8004-V2.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8004-V2.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8004-V2.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8004-V2.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8004-WX # keys: defect.io.pci.driver fault.io.psycho @@ -2529,13 +2530,13 @@ msgstr "Fault" msgid "SUN4U-8004-WX.severity" msgstr "Critical" msgid "SUN4U-8004-WX.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8004-WX.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8004-WX.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8004-WX.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8004-XE # keys: fault.io.datapath fault.io.psycho @@ -2545,13 +2546,13 @@ msgstr "Fault" msgid "SUN4U-8004-XE.severity" msgstr "Critical" msgid "SUN4U-8004-XE.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8004-XE.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8004-XE.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8004-XE.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8004-YJ # keys: defect.io.pci.driver fault.io.datapath fault.io.psycho @@ -2561,13 +2562,13 @@ msgstr "Fault" msgid "SUN4U-8004-YJ.severity" msgstr "Critical" msgid "SUN4U-8004-YJ.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8004-YJ.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8004-YJ.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8004-YJ.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8005-0E # keys: fault.io.hbus fault.io.psycho @@ -2577,13 +2578,13 @@ msgstr "Fault" msgid "SUN4U-8005-0E.severity" msgstr "Critical" msgid "SUN4U-8005-0E.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8005-0E.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8005-0E.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8005-0E.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8005-1J # keys: defect.io.pci.driver fault.io.hbus fault.io.psycho @@ -2593,13 +2594,13 @@ msgstr "Fault" msgid "SUN4U-8005-1J.severity" msgstr "Critical" msgid "SUN4U-8005-1J.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8005-1J.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8005-1J.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8005-1J.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8005-22 # keys: fault.io.datapath fault.io.hbus fault.io.psycho @@ -2609,13 +2610,13 @@ msgstr "Fault" msgid "SUN4U-8005-22.severity" msgstr "Critical" msgid "SUN4U-8005-22.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8005-22.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8005-22.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8005-22.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8005-3X # keys: defect.io.pci.driver fault.io.datapath fault.io.hbus fault.io.psycho @@ -2625,13 +2626,13 @@ msgstr "Fault" msgid "SUN4U-8005-3X.severity" msgstr "Critical" msgid "SUN4U-8005-3X.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8005-3X.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8005-3X.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8005-3X.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8005-44 # keys: fault.io.pci.bus fault.io.psycho @@ -2641,13 +2642,13 @@ msgstr "Fault" msgid "SUN4U-8005-44.severity" msgstr "Critical" msgid "SUN4U-8005-44.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8005-44.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8005-44.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8005-44.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8005-5R # keys: defect.io.pci.driver fault.io.pci.bus fault.io.psycho @@ -2657,13 +2658,13 @@ msgstr "Fault" msgid "SUN4U-8005-5R.severity" msgstr "Critical" msgid "SUN4U-8005-5R.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8005-5R.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8005-5R.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8005-5R.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8005-6C # keys: fault.io.datapath fault.io.pci.bus fault.io.psycho @@ -2673,13 +2674,13 @@ msgstr "Fault" msgid "SUN4U-8005-6C.severity" msgstr "Critical" msgid "SUN4U-8005-6C.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8005-6C.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8005-6C.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8005-6C.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8005-7Q # keys: defect.io.pci.driver fault.io.datapath fault.io.pci.bus fault.io.psycho @@ -2689,13 +2690,13 @@ msgstr "Fault" msgid "SUN4U-8005-7Q.severity" msgstr "Critical" msgid "SUN4U-8005-7Q.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8005-7Q.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8005-7Q.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8005-7Q.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8005-8Y # keys: fault.io.hbus fault.io.pci.bus fault.io.psycho @@ -2705,13 +2706,13 @@ msgstr "Fault" msgid "SUN4U-8005-8Y.severity" msgstr "Critical" msgid "SUN4U-8005-8Y.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8005-8Y.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8005-8Y.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8005-8Y.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8005-93 # keys: defect.io.pci.driver fault.io.hbus fault.io.pci.bus fault.io.psycho @@ -2721,13 +2722,13 @@ msgstr "Fault" msgid "SUN4U-8005-93.severity" msgstr "Critical" msgid "SUN4U-8005-93.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8005-93.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8005-93.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8005-93.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8005-AH # keys: fault.io.datapath fault.io.hbus fault.io.pci.bus fault.io.psycho @@ -2737,13 +2738,13 @@ msgstr "Fault" msgid "SUN4U-8005-AH.severity" msgstr "Critical" msgid "SUN4U-8005-AH.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8005-AH.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8005-AH.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8005-AH.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8005-CD # keys: defect.io.pci.driver fault.io.datapath fault.io.hbus fault.io.pci.bus fault.io.psycho @@ -2753,13 +2754,13 @@ msgstr "Fault" msgid "SUN4U-8005-CD.severity" msgstr "Critical" msgid "SUN4U-8005-CD.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8005-CD.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8005-CD.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8005-CD.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8005-DP # keys: fault.io.pci.device fault.io.psycho @@ -2769,13 +2770,13 @@ msgstr "Fault" msgid "SUN4U-8005-DP.severity" msgstr "Critical" msgid "SUN4U-8005-DP.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8005-DP.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8005-DP.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8005-DP.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8005-EA # keys: defect.io.pci.driver fault.io.pci.device fault.io.psycho @@ -2785,13 +2786,13 @@ msgstr "Fault" msgid "SUN4U-8005-EA.severity" msgstr "Critical" msgid "SUN4U-8005-EA.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8005-EA.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8005-EA.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8005-EA.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8005-FS # keys: fault.io.datapath fault.io.pci.device fault.io.psycho @@ -2801,13 +2802,13 @@ msgstr "Fault" msgid "SUN4U-8005-FS.severity" msgstr "Critical" msgid "SUN4U-8005-FS.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8005-FS.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8005-FS.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8005-FS.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8005-G5 # keys: defect.io.pci.driver fault.io.datapath fault.io.pci.device fault.io.psycho @@ -2817,13 +2818,13 @@ msgstr "Fault" msgid "SUN4U-8005-G5.severity" msgstr "Critical" msgid "SUN4U-8005-G5.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8005-G5.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8005-G5.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8005-G5.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8005-HX # keys: fault.io.hbus fault.io.pci.device fault.io.psycho @@ -2833,13 +2834,13 @@ msgstr "Fault" msgid "SUN4U-8005-HX.severity" msgstr "Critical" msgid "SUN4U-8005-HX.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8005-HX.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8005-HX.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8005-HX.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8005-J2 # keys: defect.io.pci.driver fault.io.hbus fault.io.pci.device fault.io.psycho @@ -2849,13 +2850,13 @@ msgstr "Fault" msgid "SUN4U-8005-J2.severity" msgstr "Critical" msgid "SUN4U-8005-J2.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8005-J2.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8005-J2.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8005-J2.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8005-KJ # keys: fault.io.datapath fault.io.hbus fault.io.pci.device fault.io.psycho @@ -2865,13 +2866,13 @@ msgstr "Fault" msgid "SUN4U-8005-KJ.severity" msgstr "Critical" msgid "SUN4U-8005-KJ.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8005-KJ.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8005-KJ.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8005-KJ.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8005-LE # keys: defect.io.pci.driver fault.io.datapath fault.io.hbus fault.io.pci.device fault.io.psycho @@ -2881,13 +2882,13 @@ msgstr "Fault" msgid "SUN4U-8005-LE.severity" msgstr "Critical" msgid "SUN4U-8005-LE.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8005-LE.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8005-LE.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8005-LE.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8005-MQ # keys: fault.io.pci.bus fault.io.pci.device fault.io.psycho @@ -2897,13 +2898,13 @@ msgstr "Fault" msgid "SUN4U-8005-MQ.severity" msgstr "Critical" msgid "SUN4U-8005-MQ.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8005-MQ.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8005-MQ.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8005-MQ.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8005-NC # keys: defect.io.pci.driver fault.io.pci.bus fault.io.pci.device fault.io.psycho @@ -2913,13 +2914,13 @@ msgstr "Fault" msgid "SUN4U-8005-NC.severity" msgstr "Critical" msgid "SUN4U-8005-NC.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8005-NC.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8005-NC.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8005-NC.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8005-PR # keys: fault.io.datapath fault.io.pci.bus fault.io.pci.device fault.io.psycho @@ -2929,13 +2930,13 @@ msgstr "Fault" msgid "SUN4U-8005-PR.severity" msgstr "Critical" msgid "SUN4U-8005-PR.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8005-PR.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8005-PR.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8005-PR.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8005-Q4 # keys: defect.io.pci.driver fault.io.datapath fault.io.pci.bus fault.io.pci.device fault.io.psycho @@ -2945,13 +2946,13 @@ msgstr "Fault" msgid "SUN4U-8005-Q4.severity" msgstr "Critical" msgid "SUN4U-8005-Q4.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8005-Q4.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8005-Q4.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8005-Q4.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8005-RD # keys: fault.io.hbus fault.io.pci.bus fault.io.pci.device fault.io.psycho @@ -2961,13 +2962,13 @@ msgstr "Fault" msgid "SUN4U-8005-RD.severity" msgstr "Critical" msgid "SUN4U-8005-RD.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8005-RD.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8005-RD.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8005-RD.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8005-SH # keys: defect.io.pci.driver fault.io.hbus fault.io.pci.bus fault.io.pci.device fault.io.psycho @@ -2977,13 +2978,13 @@ msgstr "Fault" msgid "SUN4U-8005-SH.severity" msgstr "Critical" msgid "SUN4U-8005-SH.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8005-SH.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8005-SH.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8005-SH.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8005-T3 # keys: fault.io.datapath fault.io.hbus fault.io.pci.bus fault.io.pci.device fault.io.psycho @@ -2993,13 +2994,13 @@ msgstr "Fault" msgid "SUN4U-8005-T3.severity" msgstr "Critical" msgid "SUN4U-8005-T3.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8005-T3.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8005-T3.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8005-T3.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8005-UY # keys: defect.io.pci.driver fault.io.datapath fault.io.hbus fault.io.pci.bus fault.io.pci.device fault.io.psycho @@ -3009,13 +3010,13 @@ msgstr "Fault" msgid "SUN4U-8005-UY.severity" msgstr "Critical" msgid "SUN4U-8005-UY.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8005-UY.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8005-UY.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8005-UY.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8005-V5 # keys: fault.io.tomatillo @@ -3025,13 +3026,13 @@ msgstr "Fault" msgid "SUN4U-8005-V5.severity" msgstr "Critical" msgid "SUN4U-8005-V5.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8005-V5.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8005-V5.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8005-V5.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8005-WS # keys: defect.io.pci.driver fault.io.tomatillo @@ -3041,13 +3042,13 @@ msgstr "Fault" msgid "SUN4U-8005-WS.severity" msgstr "Critical" msgid "SUN4U-8005-WS.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8005-WS.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8005-WS.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8005-WS.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8005-XA # keys: fault.io.datapath fault.io.tomatillo @@ -3057,13 +3058,13 @@ msgstr "Fault" msgid "SUN4U-8005-XA.severity" msgstr "Critical" msgid "SUN4U-8005-XA.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8005-XA.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8005-XA.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8005-XA.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8005-YP # keys: defect.io.pci.driver fault.io.datapath fault.io.tomatillo @@ -3073,13 +3074,13 @@ msgstr "Fault" msgid "SUN4U-8005-YP.severity" msgstr "Critical" msgid "SUN4U-8005-YP.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8005-YP.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8005-YP.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8005-YP.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8006-04 # keys: fault.io.hbus fault.io.tomatillo @@ -3089,13 +3090,13 @@ msgstr "Fault" msgid "SUN4U-8006-04.severity" msgstr "Critical" msgid "SUN4U-8006-04.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8006-04.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8006-04.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8006-04.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8006-1R # keys: defect.io.pci.driver fault.io.hbus fault.io.tomatillo @@ -3105,13 +3106,13 @@ msgstr "Fault" msgid "SUN4U-8006-1R.severity" msgstr "Critical" msgid "SUN4U-8006-1R.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8006-1R.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8006-1R.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8006-1R.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8006-2C # keys: fault.io.datapath fault.io.hbus fault.io.tomatillo @@ -3121,13 +3122,13 @@ msgstr "Fault" msgid "SUN4U-8006-2C.severity" msgstr "Critical" msgid "SUN4U-8006-2C.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8006-2C.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8006-2C.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8006-2C.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8006-3Q # keys: defect.io.pci.driver fault.io.datapath fault.io.hbus fault.io.tomatillo @@ -3137,13 +3138,13 @@ msgstr "Fault" msgid "SUN4U-8006-3Q.severity" msgstr "Critical" msgid "SUN4U-8006-3Q.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8006-3Q.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8006-3Q.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8006-3Q.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8006-4E # keys: fault.io.pci.bus fault.io.tomatillo @@ -3153,13 +3154,13 @@ msgstr "Fault" msgid "SUN4U-8006-4E.severity" msgstr "Critical" msgid "SUN4U-8006-4E.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8006-4E.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8006-4E.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8006-4E.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8006-5J # keys: defect.io.pci.driver fault.io.pci.bus fault.io.tomatillo @@ -3169,13 +3170,13 @@ msgstr "Fault" msgid "SUN4U-8006-5J.severity" msgstr "Critical" msgid "SUN4U-8006-5J.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8006-5J.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8006-5J.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8006-5J.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8006-62 # keys: fault.io.datapath fault.io.pci.bus fault.io.tomatillo @@ -3185,13 +3186,13 @@ msgstr "Fault" msgid "SUN4U-8006-62.severity" msgstr "Critical" msgid "SUN4U-8006-62.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8006-62.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8006-62.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8006-62.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8006-7X # keys: defect.io.pci.driver fault.io.datapath fault.io.pci.bus fault.io.tomatillo @@ -3201,13 +3202,13 @@ msgstr "Fault" msgid "SUN4U-8006-7X.severity" msgstr "Critical" msgid "SUN4U-8006-7X.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8006-7X.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8006-7X.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8006-7X.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8006-8P # keys: fault.io.hbus fault.io.pci.bus fault.io.tomatillo @@ -3217,13 +3218,13 @@ msgstr "Fault" msgid "SUN4U-8006-8P.severity" msgstr "Critical" msgid "SUN4U-8006-8P.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8006-8P.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8006-8P.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8006-8P.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8006-9A # keys: defect.io.pci.driver fault.io.hbus fault.io.pci.bus fault.io.tomatillo @@ -3233,13 +3234,13 @@ msgstr "Fault" msgid "SUN4U-8006-9A.severity" msgstr "Critical" msgid "SUN4U-8006-9A.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8006-9A.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8006-9A.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8006-9A.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8006-AS # keys: fault.io.datapath fault.io.hbus fault.io.pci.bus fault.io.tomatillo @@ -3249,13 +3250,13 @@ msgstr "Fault" msgid "SUN4U-8006-AS.severity" msgstr "Critical" msgid "SUN4U-8006-AS.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8006-AS.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8006-AS.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8006-AS.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8006-C5 # keys: defect.io.pci.driver fault.io.datapath fault.io.hbus fault.io.pci.bus fault.io.tomatillo @@ -3265,13 +3266,13 @@ msgstr "Fault" msgid "SUN4U-8006-C5.severity" msgstr "Critical" msgid "SUN4U-8006-C5.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8006-C5.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8006-C5.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8006-C5.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8006-DY # keys: fault.io.pci.device fault.io.tomatillo @@ -3281,13 +3282,13 @@ msgstr "Fault" msgid "SUN4U-8006-DY.severity" msgstr "Critical" msgid "SUN4U-8006-DY.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8006-DY.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8006-DY.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8006-DY.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8006-E3 # keys: defect.io.pci.driver fault.io.pci.device fault.io.tomatillo @@ -3297,13 +3298,13 @@ msgstr "Fault" msgid "SUN4U-8006-E3.severity" msgstr "Critical" msgid "SUN4U-8006-E3.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8006-E3.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8006-E3.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8006-E3.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8006-FH # keys: fault.io.datapath fault.io.pci.device fault.io.tomatillo @@ -3313,13 +3314,13 @@ msgstr "Fault" msgid "SUN4U-8006-FH.severity" msgstr "Critical" msgid "SUN4U-8006-FH.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8006-FH.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8006-FH.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8006-FH.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8006-GD # keys: defect.io.pci.driver fault.io.datapath fault.io.pci.device fault.io.tomatillo @@ -3329,13 +3330,13 @@ msgstr "Fault" msgid "SUN4U-8006-GD.severity" msgstr "Critical" msgid "SUN4U-8006-GD.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8006-GD.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8006-GD.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8006-GD.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8006-HQ # keys: fault.io.hbus fault.io.pci.device fault.io.tomatillo @@ -3345,13 +3346,13 @@ msgstr "Fault" msgid "SUN4U-8006-HQ.severity" msgstr "Critical" msgid "SUN4U-8006-HQ.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8006-HQ.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8006-HQ.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8006-HQ.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8006-JC # keys: defect.io.pci.driver fault.io.hbus fault.io.pci.device fault.io.tomatillo @@ -3361,13 +3362,13 @@ msgstr "Fault" msgid "SUN4U-8006-JC.severity" msgstr "Critical" msgid "SUN4U-8006-JC.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8006-JC.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8006-JC.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8006-JC.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8006-KR # keys: fault.io.datapath fault.io.hbus fault.io.pci.device fault.io.tomatillo @@ -3377,13 +3378,13 @@ msgstr "Fault" msgid "SUN4U-8006-KR.severity" msgstr "Critical" msgid "SUN4U-8006-KR.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8006-KR.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8006-KR.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8006-KR.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8006-L4 # keys: defect.io.pci.driver fault.io.datapath fault.io.hbus fault.io.pci.device fault.io.tomatillo @@ -3393,13 +3394,13 @@ msgstr "Fault" msgid "SUN4U-8006-L4.severity" msgstr "Critical" msgid "SUN4U-8006-L4.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8006-L4.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8006-L4.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8006-L4.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8006-MX # keys: fault.io.pci.bus fault.io.pci.device fault.io.tomatillo @@ -3409,13 +3410,13 @@ msgstr "Fault" msgid "SUN4U-8006-MX.severity" msgstr "Critical" msgid "SUN4U-8006-MX.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8006-MX.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8006-MX.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8006-MX.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8006-N2 # keys: defect.io.pci.driver fault.io.pci.bus fault.io.pci.device fault.io.tomatillo @@ -3425,13 +3426,13 @@ msgstr "Fault" msgid "SUN4U-8006-N2.severity" msgstr "Critical" msgid "SUN4U-8006-N2.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8006-N2.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8006-N2.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8006-N2.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8006-PJ # keys: fault.io.datapath fault.io.pci.bus fault.io.pci.device fault.io.tomatillo @@ -3441,13 +3442,13 @@ msgstr "Fault" msgid "SUN4U-8006-PJ.severity" msgstr "Critical" msgid "SUN4U-8006-PJ.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8006-PJ.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8006-PJ.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8006-PJ.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8006-QE # keys: defect.io.pci.driver fault.io.datapath fault.io.pci.bus fault.io.pci.device fault.io.tomatillo @@ -3457,13 +3458,13 @@ msgstr "Fault" msgid "SUN4U-8006-QE.severity" msgstr "Critical" msgid "SUN4U-8006-QE.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8006-QE.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8006-QE.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8006-QE.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8006-R5 # keys: fault.io.hbus fault.io.pci.bus fault.io.pci.device fault.io.tomatillo @@ -3473,13 +3474,13 @@ msgstr "Fault" msgid "SUN4U-8006-R5.severity" msgstr "Critical" msgid "SUN4U-8006-R5.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8006-R5.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8006-R5.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8006-R5.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8006-SS # keys: defect.io.pci.driver fault.io.hbus fault.io.pci.bus fault.io.pci.device fault.io.tomatillo @@ -3489,13 +3490,13 @@ msgstr "Fault" msgid "SUN4U-8006-SS.severity" msgstr "Critical" msgid "SUN4U-8006-SS.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8006-SS.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8006-SS.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8006-SS.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8006-TA # keys: fault.io.datapath fault.io.hbus fault.io.pci.bus fault.io.pci.device fault.io.tomatillo @@ -3505,13 +3506,13 @@ msgstr "Fault" msgid "SUN4U-8006-TA.severity" msgstr "Critical" msgid "SUN4U-8006-TA.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nA problem was detected in a system core bus.\n Refer to %s for more information." msgid "SUN4U-8006-TA.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8006-TA.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8006-TA.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nSchedule a repair procedure to replace the affected device. Use\nfmdump -v -u EVENT_ID to identify the device or contact\nSun for support.\n" # # code: SUN4U-8006-UP # keys: defect.io.pci.driver fault.io.datapath fault.io.hbus fault.io.pci.bus fault.io.pci.device fault.io.tomatillo @@ -3521,13 +3522,13 @@ msgstr "Fault" msgid "SUN4U-8006-UP.severity" msgstr "Critical" msgid "SUN4U-8006-UP.description" -msgstr "A problem has been detected in the PCI subsystem. Refer to %s for more information." +msgstr "\n\nThe system has diagnosed a problem, the suspects include one or more \nPCI buses, devices and one or more PCI controller drivers, based on the \nerror telemetry detected by the PCI subsystem.\n Refer to %s for more information." msgid "SUN4U-8006-UP.response" -msgstr "One or more device instances may be disabled" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." msgid "SUN4U-8006-UP.impact" -msgstr "Loss of services provided by the device instances associated with this fault" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." msgid "SUN4U-8006-UP.action" -msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +msgstr "\n\nUse fmdump -v -u <EVENT_ID> to identify the \nsuspected device(s). Schedule a repair of the most likely suspect \nlisted in the output. If the most likely suspect is a package then run \npkgchk on the package(s).\n" # # code: SUN4U-8006-VD # keys: fault.cpu.ultraSPARC-IIIiplus.dcache @@ -3537,13 +3538,13 @@ msgstr "Fault" msgid "SUN4U-8006-VD.severity" msgstr "Major" msgid "SUN4U-8006-VD.description" -msgstr "The number of errors associated with this CPU has exceeded acceptable levels. Refer to %s for more information." +msgstr "The number of errors associated with a CPU has exceeded acceptable levels. Refer to %s for more information." msgid "SUN4U-8006-VD.response" -msgstr "An attempt will be made to remove the affected CPU from service." +msgstr "The fault manager will attempt to remove the affected CPU from service." msgid "SUN4U-8006-VD.impact" -msgstr "Performance of this system may be affected." +msgstr "System performance may be affected." msgid "SUN4U-8006-VD.action" -msgstr "Schedule a repair procedure to replace the affected CPU. Use fmdump -v -u <EVENT_ID> to identify the CPU." +msgstr "Schedule a repair procedure to replace the affected CPU, the identity of which can be determined using fmdump -v -u <EVENT_ID>." # # code: SUN4U-8006-WH # keys: fault.cpu.ultraSPARC-IIIiplus.icache @@ -3553,13 +3554,13 @@ msgstr "Fault" msgid "SUN4U-8006-WH.severity" msgstr "Major" msgid "SUN4U-8006-WH.description" -msgstr "The number of errors associated with this CPU has exceeded acceptable levels. Refer to %s for more information." +msgstr "The number of errors associated with a CPU has exceeded acceptable levels. Refer to %s for more information." msgid "SUN4U-8006-WH.response" -msgstr "An attempt will be made to remove the affected CPU from service." +msgstr "The fault manager will attempt to remove the affected CPU from service." msgid "SUN4U-8006-WH.impact" -msgstr "Performance of this system may be affected." +msgstr "System performance may be affected." msgid "SUN4U-8006-WH.action" -msgstr "Schedule a repair procedure to replace the affected CPU. Use fmdump -v -u <EVENT_ID> to identify the CPU." +msgstr "Schedule a repair procedure to replace the affected CPU, the identity of which can be determined using fmdump -v -u <EVENT_ID>." # # code: SUN4U-8006-X3 # keys: fault.cpu.ultraSPARC-IIIiplus.l2cachedata @@ -3569,13 +3570,13 @@ msgstr "Fault" msgid "SUN4U-8006-X3.severity" msgstr "Major" msgid "SUN4U-8006-X3.description" -msgstr "The number of errors associated with this CPU has exceeded acceptable levels. Refer to %s for more information." +msgstr "The number of errors associated with a CPU has exceeded acceptable levels. Refer to %s for more information." msgid "SUN4U-8006-X3.response" -msgstr "An attempt will be made to remove the affected CPU from service." +msgstr "The fault manager will attempt to remove the affected CPU from service." msgid "SUN4U-8006-X3.impact" -msgstr "Performance of this system may be affected." +msgstr "System performance may be affected." msgid "SUN4U-8006-X3.action" -msgstr "Schedule a repair procedure to replace the affected CPU. Use fmdump -v -u <EVENT_ID> to identify the CPU." +msgstr "Schedule a repair procedure to replace the affected CPU, the identity of which can be determined using fmdump -v -u <EVENT_ID>." # # code: SUN4U-8006-YY # keys: fault.cpu.ultraSPARC-IIIiplus.l2cachetag @@ -3585,13 +3586,13 @@ msgstr "Fault" msgid "SUN4U-8006-YY.severity" msgstr "Major" msgid "SUN4U-8006-YY.description" -msgstr "The number of errors associated with this CPU has exceeded acceptable levels. Refer to %s for more information." +msgstr "The number of errors associated with a CPU has exceeded acceptable levels. Refer to %s for more information." msgid "SUN4U-8006-YY.response" -msgstr "An attempt will be made to remove the affected CPU from service." +msgstr "The fault manager will attempt to remove the affected CPU from service." msgid "SUN4U-8006-YY.impact" -msgstr "Performance of this system may be affected." +msgstr "System performance may be affected." msgid "SUN4U-8006-YY.action" -msgstr "Schedule a repair procedure to replace the affected CPU. Use fmdump -v -u <EVENT_ID> to identify the CPU." +msgstr "Schedule a repair procedure to replace the affected CPU, the identity of which can be determined using fmdump -v -u <EVENT_ID>." # # code: SUN4U-8007-03 # keys: fault.cpu.ultraSPARC-IIIiplus.fpu @@ -3601,13 +3602,13 @@ msgstr "Fault" msgid "SUN4U-8007-03.severity" msgstr "Major" msgid "SUN4U-8007-03.description" -msgstr "A fault has been detected in the FPU of this CPU. Refer to %s for more information." +msgstr "The number of errors associated with a CPU has exceeded acceptable levels. Refer to %s for more information." msgid "SUN4U-8007-03.response" -msgstr "An attempt will be made to remove the affected CPU from service." +msgstr "The fault manager will attempt to remove the affected CPU from service." msgid "SUN4U-8007-03.impact" -msgstr "Performance of this system may be affected." +msgstr "System performance may be affected." msgid "SUN4U-8007-03.action" -msgstr "Schedule a repair procedure to replace the affected CPU. Use fmdump -v -u <EVENT_ID> to identify the CPU." +msgstr "Schedule a repair procedure to replace the affected CPU, the identity of which can be determined using fmdump -v -u <EVENT_ID>." # # code: SUN4U-8007-1Y # keys: fault.asic.cds.dp @@ -3617,13 +3618,13 @@ msgstr "Fault" msgid "SUN4U-8007-1Y.severity" msgstr "Critical" msgid "SUN4U-8007-1Y.description" -msgstr "A hardware problem was detected on the datapath interconnect. Refer to %s for more information." +msgstr "A hardware problem was detected on the datapath interconnect.\n Refer to %s for more information." msgid "SUN4U-8007-1Y.response" -msgstr "One or more CPUs may be offlined. Additionally, page retires for memory in the impacted region may be disabled." +msgstr "One or more CPUs may be offlined. Additionally, page retires for memory in the impacted region may be disabled.\n" msgid "SUN4U-8007-1Y.impact" -msgstr "System performace may be affected." +msgstr "System performace may be affected.\n" msgid "SUN4U-8007-1Y.action" -msgstr "Schedule a repair procedure to replace the affected component(s). The System Controller (SC) diagnostic messages have the authoritative information on the affected component(s). fmdump -v -u <EVENT_ID> can also be used, but the SC is authoritative." +msgstr "Schedule a repair procedure to replace the affected component(s). The System Controller (SC) diagnostic messages have the authoritative information on the affected component(s). fmdump -v -u <EVENT-ID> can also be used, but the SC is authoritative.\n" # # code: SUN4U-8007-2D # keys: fault.asic.dx.dp @@ -3633,13 +3634,13 @@ msgstr "Fault" msgid "SUN4U-8007-2D.severity" msgstr "Critical" msgid "SUN4U-8007-2D.description" -msgstr "A hardware problem was detected on the datapath interconnect. Refer to %s for more information." +msgstr "A hardware problem was detected on the datapath interconnect.\n Refer to %s for more information." msgid "SUN4U-8007-2D.response" -msgstr "One or more CPUs may be offlined. Additionally, page retires for memory in the impacted region may be disabled." +msgstr "One or more CPUs may be offlined. Additionally, page retires for memory in the impacted region may be disabled.\n" msgid "SUN4U-8007-2D.impact" -msgstr "System performace may be affected." +msgstr "System performace may be affected.\n" msgid "SUN4U-8007-2D.action" -msgstr "Schedule a repair procedure to replace the affected component(s). The System Controller (SC) diagnostic messages have the authoritative information on the affected component(s). fmdump -v -u <EVENT_ID> can also be used, but the SC is authoritative." +msgstr "Schedule a repair procedure to replace the affected component(s). The System Controller (SC) diagnostic messages have the authoritative information on the affected component(s). fmdump -v -u <EVENT-ID> can also be used, but the SC is authoritative.\n" # # code: SUN4U-8007-3H # keys: fault.asic.sdi.dp @@ -3649,13 +3650,13 @@ msgstr "Fault" msgid "SUN4U-8007-3H.severity" msgstr "Critical" msgid "SUN4U-8007-3H.description" -msgstr "A hardware problem was detected on the datapath interconnect. Refer to %s for more information." +msgstr "A hardware problem was detected on the datapath interconnect.\n Refer to %s for more information." msgid "SUN4U-8007-3H.response" -msgstr "One or more CPUs may be offlined. Additionally, page retires for memory in the impacted region may be disabled." +msgstr "One or more CPUs may be offlined. Additionally, page retires for memory in the impacted region may be disabled.\n" msgid "SUN4U-8007-3H.impact" -msgstr "System performace may be affected." +msgstr "System performace may be affected.\n" msgid "SUN4U-8007-3H.action" -msgstr "Schedule a repair procedure to replace the affected component(s). The System Controller (SC) diagnostic messages have the authoritative information on the affected component(s). fmdump -v -u <EVENT_ID> can also be used, but the SC is authoritative." +msgstr "Schedule a repair procedure to replace the affected component(s). The System Controller (SC) diagnostic messages have the authoritative information on the affected component(s). fmdump -v -u <EVENT-ID> can also be used, but the SC is authoritative.\n" # # code: SUN4U-8007-4A # keys: fault.asic.cp.dp @@ -3665,13 +3666,13 @@ msgstr "Fault" msgid "SUN4U-8007-4A.severity" msgstr "Critical" msgid "SUN4U-8007-4A.description" -msgstr "A hardware problem was detected on the datapath interconnect. Refer to %s for more information." +msgstr "A hardware problem was detected on the datapath interconnect.\n Refer to %s for more information." msgid "SUN4U-8007-4A.response" -msgstr "One or more CPUs may be offlined. Additionally, page retires for memory in the impacted region may be disabled." +msgstr "One or more CPUs may be offlined. Additionally, page retires for memory in the impacted region may be disabled.\n" msgid "SUN4U-8007-4A.impact" -msgstr "System performace may be affected." +msgstr "System performace may be affected.\n" msgid "SUN4U-8007-4A.action" -msgstr "Schedule a repair procedure to replace the affected component(s). The System Controller (SC) diagnostic messages have the authoritative information on the affected component(s). fmdump -v -u <EVENT_ID> can also be used, but the SC is authoritative." +msgstr "Schedule a repair procedure to replace the affected component(s). The System Controller (SC) diagnostic messages have the authoritative information on the affected component(s). fmdump -v -u <EVENT-ID> can also be used, but the SC is authoritative.\n" # # code: SUN4U-8007-5P # keys: fault.asic.rp.dp @@ -3681,10 +3682,74 @@ msgstr "Fault" msgid "SUN4U-8007-5P.severity" msgstr "Critical" msgid "SUN4U-8007-5P.description" -msgstr "A hardware problem was detected on the datapath interconnect. Refer to %s for more information." +msgstr "A hardware problem was detected on the datapath interconnect.\n Refer to %s for more information." msgid "SUN4U-8007-5P.response" -msgstr "One or more CPUs may be offlined. Additionally, page retires for memory in the impacted region may be disabled." +msgstr "One or more CPUs may be offlined. Additionally, page retires for memory in the impacted region may be disabled.\n" msgid "SUN4U-8007-5P.impact" -msgstr "System performace may be affected." +msgstr "System performace may be affected.\n" msgid "SUN4U-8007-5P.action" -msgstr "Schedule a repair procedure to replace the affected component(s). The System Controller (SC) diagnostic messages have the authoritative information on the affected component(s). fmdump -v -u <EVENT_ID> can also be used, but the SC is authoritative." +msgstr "Schedule a repair procedure to replace the affected component(s). The System Controller (SC) diagnostic messages have the authoritative information on the affected component(s). fmdump -v -u <EVENT-ID> can also be used, but the SC is authoritative.\n" +# +# code: SUN4U-8007-65 +# keys: fault.io.oberon +# +msgid "SUN4U-8007-65.type" +msgstr "Fault" +msgid "SUN4U-8007-65.severity" +msgstr "Critical" +msgid "SUN4U-8007-65.description" +msgstr "Oberon PCI-Express hostbridge fault\n Refer to %s for more information." +msgid "SUN4U-8007-65.response" +msgstr "This fault requires user and/or service interaction and currently does not have an automated response agent." +msgid "SUN4U-8007-65.impact" +msgstr "Possible loss of devices that may be attached to the system via this device/bus and/or system downtime." +msgid "SUN4U-8007-65.action" +msgstr "Ensure that the latest drivers and patches are installed, schedule a repair procedure to replace the affected device if necessary, or contact Sun for support." +# +# code: SUN4U-8007-7S +# keys: fault.cpu.SPARC64-VI.chip +# +msgid "SUN4U-8007-7S.type" +msgstr "Fault" +msgid "SUN4U-8007-7S.severity" +msgstr "Critical" +msgid "SUN4U-8007-7S.description" +msgstr "The number of errors associated with this CHIP has exceeded acceptable levels.\nRefer to %s for more information.\n Refer to %s for more information." +msgid "SUN4U-8007-7S.response" +msgstr "An attempt will be made to remove the affected CHIP from service.\n" +msgid "SUN4U-8007-7S.impact" +msgstr "The system will not be functioning at the same performance level with the CHIP removal.\n" +msgid "SUN4U-8007-7S.action" +msgstr "Schedule a repair procedure to replace the affected CHIP. Use fmdump -v -u\n to identify the smallest CPU/Strand ID of the affected CORE on this\nCHIP.\n" +# +# code: SUN4U-8007-8J +# keys: fault.cpu.SPARC64-VI.core +# +msgid "SUN4U-8007-8J.type" +msgstr "Fault" +msgid "SUN4U-8007-8J.severity" +msgstr "Critical" +msgid "SUN4U-8007-8J.description" +msgstr "The number of errors associated with this CHIP has exceeded acceptable levels.\nRefer to %s for more information.\n Refer to %s for more information." +msgid "SUN4U-8007-8J.response" +msgstr "An attempt will be made to remove the affected CORE from service.\n" +msgid "SUN4U-8007-8J.impact" +msgstr "The system will not be functioning at the same performance level with the CORE removal.\n" +msgid "SUN4U-8007-8J.action" +msgstr "Schedule a repair procedure to replace the affected CORE. Use fmdump -v -u\n to identify the smallest CPU/Strand ID of the affected CORE on this\nCORE.\n" +# +# code: SUN4U-8007-9E +# keys: fault.cpu.SPARC64-VI.strand +# +msgid "SUN4U-8007-9E.type" +msgstr "Fault" +msgid "SUN4U-8007-9E.severity" +msgstr "Critical" +msgid "SUN4U-8007-9E.description" +msgstr "The number of errors associated with this STRAND has exceeded acceptable levels.\nRefer to %s for more information.\n Refer to %s for more information." +msgid "SUN4U-8007-9E.response" +msgstr "An attempt will be made to remove the affected STRAND from service.\n" +msgid "SUN4U-8007-9E.impact" +msgstr "The system will not be functioning at the same performance level with the STRAND removal.\n" +msgid "SUN4U-8007-9E.action" +msgstr "Schedule a repair procedure to replace the affected STRAND. Use fmdump -v -u\n to identify the smallest CPU/Strand ID of the affected CORE on this\nSTRAND.\n" diff --git a/usr/src/cmd/fm/eversholt/files/sparc/sun4u/Makefile b/usr/src/cmd/fm/eversholt/files/sparc/sun4u/Makefile index 51cc35a7c4..630ed0348e 100644 --- a/usr/src/cmd/fm/eversholt/files/sparc/sun4u/Makefile +++ b/usr/src/cmd/fm/eversholt/files/sparc/sun4u/Makefile @@ -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,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" @@ -28,7 +27,7 @@ include ../sun4/Makefile.sun4 EFT_PLAT= sun4u -SUN4UEFTFILES= schizo.eft psycho.eft tomatillo.eft xmits.eft +SUN4UEFTFILES= schizo.eft psycho.eft tomatillo.eft xmits.eft oberon.eft EFT_PLAT_FILES= $(SUN4UEFTFILES) $(SUN4EFTFILES) include ../../Makefile.com diff --git a/usr/src/cmd/fm/eversholt/files/sparc/sun4u/oberon.esc b/usr/src/cmd/fm/eversholt/files/sparc/sun4u/oberon.esc new file mode 100644 index 0000000000..6bf20dc659 --- /dev/null +++ b/usr/src/cmd/fm/eversholt/files/sparc/sun4u/oberon.esc @@ -0,0 +1,155 @@ +/* + * 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" + +/* + * Eversholt rules for Oberon ASICs + */ + +#pragma dictionary "SUN4U" + +#define HB_FIT 1000 + +/* + * Test for primary or secondary ereports + */ +#define IS_PRIMARY (payloadprop("primary")) +#define IS_SECONDARY (! payloadprop("primary")) + +event error.io.oberon.pec.secondary@hostbridge/pciexrc; +event error.io.oberon.pec.fabric_error@hostbridge/pciexrc; + +/* + * Ereports derived from the + * UBC Status Clear Register + * + * dmarduea-channel DMA read uncorrectable error (UE) in leaf A + * dmawtuea DMA write UE in leaf A + * memrdaxa Memory read invalid address error in leaf A + * memwtaxa Memory write invalid address error in leaf A + * dmardueb-channel DMA read uncorrectable error (UE) in leaf B + * dmawtueb DMA write UE in leaf B + * memrdaxb Memory read invalid address error in leaf B + * memwtaxb Memory write invalid address error in leaf B + * piowtue-channel PIO write UE + * piowbeue-channel PIO write byte enable UE + * piorbeue-channel PIO read byte enable UE + */ +event ereport.io.oberon.ubc.dmarduea-channel@hostbridge/pciexrc{within(5s)}; +event ereport.io.oberon.ubc.dmawtuea@hostbridge/pciexrc{within(5s)}; +event ereport.io.oberon.ubc.memrdaxa@hostbridge/pciexrc{within(5s)}; +event ereport.io.oberon.ubc.memwtaxa@hostbridge/pciexrc{within(5s)}; +event ereport.io.oberon.ubc.dmardueb-channel@hostbridge/pciexrc{within(5s)}; +event ereport.io.oberon.ubc.dmawtueb@hostbridge/pciexrc{within(5s)}; +event ereport.io.oberon.ubc.memrdaxb@hostbridge/pciexrc{within(5s)}; +event ereport.io.oberon.ubc.memwtaxb@hostbridge/pciexrc{within(5s)}; +event ereport.io.oberon.ubc.piowtue-channel@hostbridge/pciexrc{within(5s)}; +event ereport.io.oberon.ubc.piowbeue-channel@hostbridge/pciexrc{within(5s)}; +event ereport.io.oberon.ubc.piorbeue-channel@hostbridge/pciexrc{within(5s)}; + +/* + * tlueitmo TLU Egress Issue Timeout + */ +event ereport.io.oberon.pec.tlueitmo@hostbridge/pciexrc{within(5s)}; + +/* + * TLU Uncorrectable and Correctable ereports + * + * ecrc End-to-end CRC error + */ +event ereport.io.oberon.pec.ecrc@hostbridge/pciexrc{within(5s)}; + +/* + * A faulty Oberon may cause; + * + * - DMA write internal RAM UE: dmawtuea, dmawtueb + * - TLU ECRC + * + * Errors marked with * may cause PCI-E abort + */ + +fru hostbridge/pciexrc; +asru hostbridge/pciexrc; +event fault.io.oberon@hostbridge/pciexrc, + FITrate=HB_FIT, FRU=hostbridge/pciexrc, ASRU=hostbridge/pciexrc; +prop fault.io.oberon@hostbridge/pciexrc (0)-> + ereport.io.oberon.ubc.dmawtuea@hostbridge/pciexrc, + ereport.io.oberon.ubc.dmawtueb@hostbridge/pciexrc, + ereport.io.oberon.pec.ecrc@hostbridge/pciexrc { IS_PRIMARY }; + +/* + * A faulty PX nexus driver can cause + * - Jbus unmapped error + * - mmu invalid, out of range, protection etc. all except data parity + * - invalid pio r/w + * - unsolicited read or interrupt return + * - msg received to unenabled queue + */ + +event defect.io.fire.pciex.driver@hostbridge/pciexrc; + +prop defect.io.fire.pciex.driver@hostbridge/pciexrc (0)-> + ereport.io.oberon.ubc.memrdaxa@hostbridge/pciexrc, + ereport.io.oberon.ubc.memrdaxb@hostbridge/pciexrc, + ereport.io.oberon.ubc.memwtaxa@hostbridge/pciexrc, + ereport.io.oberon.ubc.memwtaxb@hostbridge/pciexrc; + +/* + * Secondary errors of the ereport that the device is at fault. + * Undiagnosed the secondary errors since the payload is invalid. + */ +prop error.io.oberon.pec.secondary@hostbridge/pciexrc (0) -> + ereport.io.oberon.pec.ecrc@hostbridge/pciexrc{ IS_SECONDARY }; + +/* + * For logging purpose only. + * The px nexus driver generates equivalent pciex ereports for the + * common pciex rules to diagnose. + */ +prop error.io.oberon.pec.fabric_error@hostbridge/pciexrc(0) -> + ereport.io.oberon.pec.ecrc@hostbridge/pciexrc; + +event ereport.io.oberon.nodiag@hostbridge; + +/* + * Upset used to hide ereports that are not currently diagnosed. + */ +engine serd.io.oberon.nodiag@hostbridge, + N=1000, T=1s, method=persistent, + trip=ereport.io.oberon.nodiag@hostbridge; + +event upset.io.oberon.nodiag@hostbridge, + engine=serd.io.oberon.nodiag@hostbridge; + +prop upset.io.oberon.nodiag@hostbridge (0)-> + ereport.io.oberon.ubc.dmarduea-channel@hostbridge/pciexrc, + ereport.io.oberon.ubc.dmardueb-channel@hostbridge/pciexrc, + ereport.io.oberon.ubc.piowtue-channel@hostbridge/pciexrc, + ereport.io.oberon.ubc.piowbeue-channel@hostbridge/pciexrc, + ereport.io.oberon.ubc.piorbeue-channel@hostbridge/pciexrc, + ereport.io.oberon.pec.tlueitmo@hostbridge/pciexrc, + error.io.oberon.pec.fabric_error@hostbridge/pciexrc, + ereport.io.oberon.nodiag@hostbridge; diff --git a/usr/src/cmd/fm/modules/Makefile b/usr/src/cmd/fm/modules/Makefile index ab5810ea52..ae81c5585a 100644 --- a/usr/src/cmd/fm/modules/Makefile +++ b/usr/src/cmd/fm/modules/Makefile @@ -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,12 @@ # CDDL HEADER END # # -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" -sparc_SUBDIRS = sun4u sun4v +sparc_SUBDIRS = sun4u sun4v SUNW,SPARC-Enterprise i386_SUBDIRS = SUBDIRS = common $($(MACH)_SUBDIRS) diff --git a/usr/src/cmd/fm/modules/SUNW,SPARC-Enterprise/Makefile b/usr/src/cmd/fm/modules/SUNW,SPARC-Enterprise/Makefile new file mode 100644 index 0000000000..5772a37f9f --- /dev/null +++ b/usr/src/cmd/fm/modules/SUNW,SPARC-Enterprise/Makefile @@ -0,0 +1,29 @@ +# +# 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. +# +#ident "%Z%%M% %I% %E% SMI" + +SUBDIRS = event-transport + +include ../../Makefile.subdirs diff --git a/usr/src/cmd/fm/modules/SUNW,SPARC-Enterprise/event-transport/Makefile b/usr/src/cmd/fm/modules/SUNW,SPARC-Enterprise/event-transport/Makefile new file mode 100644 index 0000000000..c45119ca68 --- /dev/null +++ b/usr/src/cmd/fm/modules/SUNW,SPARC-Enterprise/event-transport/Makefile @@ -0,0 +1,36 @@ +# +# 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. +# +#ident "%Z%%M% %I% %E% SMI" + +PLATFORMS = SUNW,SPARC-Enterprise + +$(PLATFORMS)_SRCS = ex_dscp.c + +LIBDIRS = $(ROOT)/usr/platform/$(PLATFORMS)/lib +LIBFLAGS = \$$ORIGIN/../../../../lib +XPORTLIBS = -lsocket -lnsl -ldscp + +include ../../common/event-transport/Makefile.etm + diff --git a/usr/src/cmd/fm/modules/SUNW,SPARC-Enterprise/event-transport/event-transport.conf b/usr/src/cmd/fm/modules/SUNW,SPARC-Enterprise/event-transport/event-transport.conf new file mode 100644 index 0000000000..f7875fc840 --- /dev/null +++ b/usr/src/cmd/fm/modules/SUNW,SPARC-Enterprise/event-transport/event-transport.conf @@ -0,0 +1,80 @@ +# +# 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. +# +#ident "%Z%%M% %I% %E% SMI" +# +# fmd configuration file for the event-transport.so plugin module. +# +# The following configuration options are valid: +# +# setprop reconnect_timeout <time> +# +# Sets the total time spent attempting to connect with a peer +# after a connection has been lost. Time is in nanoseconds. +# +# setprop reconnect_interval <time> +# +# Sets the timeout value in between individual reconnection +# attempts. Time is in nanoseconds. +# +# setprop rw_timeout <time> +# +# Sets the timeout value for a read or write I/O operation. +# Time is in nanoseconds. +# +# setprop client_list <FMRI string> +# +# Specifies a list of peers this module will accept a +# connection from. +# +# This list may take the following forms: +# +# (1) A space-separated list. +# +# setprop client_list "dev:///dom0 dev:///dom1 dev:///dom2" +# +# (2) An array syntax for a range of endpoints. The following +# example is equivalent to the previous example. +# +# setprop client_list "dev:///dom[0:2]" +# +# (3) A combination of both. The following example is +# equivalent to the previous examples. +# +# setprop client_list "dev:///dom0 dev:///dom[1:2]" +# +# setprop server_list <FMRI string> +# +# Specifies a list of peers this module will initiate a +# connection to. +# +# The syntax of this property is the same as the "client_list" +# property above. +# +# If a peer is found in both client_list and server_list, +# a connection will not be initiated to the peer, but a +# connection will be accepted from the peer. +# + +setprop server_list "dev:///sp0" diff --git a/usr/src/cmd/fm/modules/SUNW,SPARC-Enterprise/event-transport/ex_dscp.c b/usr/src/cmd/fm/modules/SUNW,SPARC-Enterprise/event-transport/ex_dscp.c new file mode 100644 index 0000000000..55c404a416 --- /dev/null +++ b/usr/src/cmd/fm/modules/SUNW,SPARC-Enterprise/event-transport/ex_dscp.c @@ -0,0 +1,839 @@ +/* + * 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" + +/* + * FMA Event Transport Module Transport Layer API implementation. + * + * Library for establishing connections and transporting FMA events between + * ETMs (event-transport modules) in separate fault domains. + * + * The transport for this library is internet socket based and uses the DSCP + * client services library (libdscp). + */ + +#include <unistd.h> +#include <strings.h> +#include <sys/socket.h> +#include <fcntl.h> +#include <netdb.h> +#include <pthread.h> +#include <errno.h> +#include <time.h> +#include <libdscp.h> +#include "etm_xport_api.h" + +/* + * Transport Layer handle implementations + */ +/* Connection handle */ +typedef struct etm_xport_sock_conn { + int c_len; /* Length of saddr */ + int c_sd; /* Socket descriptor */ + struct sockaddr_in c_saddr; /* Sockaddr for DSCP connection */ +} exs_conn_t; + +typedef enum etm_xport_sock_status { + S_WAITING, /* Server thread is waiting to start */ + S_RUNNING, /* Server thread is running */ + S_DOEXIT /* Server thread needs to exit */ +} exs_status_t; + +/* Transport instance handle */ +typedef struct etm_xport_sock_hdl { + exs_conn_t h_client; /* Sending connection handle */ + exs_conn_t h_server; /* Receiving connection handle */ + char *h_endpt_id; /* Endpoint id from ETM common */ + int h_domain_id; /* Domain ID from platform (libdscp) */ + pthread_mutex_t h_lock; /* Lock for instance handle */ + fmd_hdl_t *h_hdl; /* fmd handle */ + int (*h_cb_func)(fmd_hdl_t *, etm_xport_conn_t, etm_cb_flag_t, void *); + /* Callback function for ETM common */ + void *h_cb_func_arg; /* Arg to pass when calling h_cb_func */ + struct etm_xport_sock_hdl *h_next; +} exs_hdl_t; + +/* For the socket */ +#define EXS_SERVER_PORT 24 /* Port number for server */ +#define EXS_SERVER_ADDR in6addr_any /* Address for server */ +#define EXS_CLIENT_PORT 0 /* Port number for client */ +#define EXS_NUM_SOCKS 5 /* Length of socket queue */ +#define EXS_SD_FREE -1 /* Socket descr value when unset */ + +#define EXS_DOMAIN_PREFIX "dom" /* Domain auth prefix in FMRI string */ +#define EXS_DOMAIN_PREFIX_LEN 3 /* Length of domain prefix */ +#define EXS_SP_PREFIX "sp" /* SP auth prefix in FMRI string */ +#define EXS_IO_SLEEP_DIV 100 /* Divisor for I/O sleeptime */ + +/* + * Global variables + */ +static exs_status_t Server_status = S_WAITING; + /* Status of Server */ +static pthread_t Server_tid = 0; /* Thread ID of Server */ +static exs_conn_t Acceptor_conn; /* Connection handle for Acceptor */ +static fd_set Conn_set; /* Set of accepted connections */ +static pthread_mutex_t Mod_lock = PTHREAD_MUTEX_INITIALIZER; + /* Protects globals (above) */ +static exs_hdl_t *Exh_head = NULL; /* Head of ex_hdl_t list */ +static pthread_mutex_t List_lock = PTHREAD_MUTEX_INITIALIZER; + /* Protects linked list of ex_hdl_t */ +/* + * Mutex lock order + * (1) List_lock + * (2) hp->h_lock + * (3) Mod_lock + */ + +/* + * Module specific routines. + */ + +/* + * Allocate and initialize a transport instance handle. + * Return hdl pointer for success, NULL for failure. + */ +static exs_hdl_t * +exs_hdl_alloc(fmd_hdl_t *hdl, char *endpoint_id, + int (*cb_func)(fmd_hdl_t *hdl, etm_xport_conn_t conn, etm_cb_flag_t flag, + void *arg), void *cb_func_arg, int domain_id) +{ + exs_hdl_t *hp; + + hp = fmd_hdl_zalloc(hdl, sizeof (exs_hdl_t), FMD_SLEEP); + + (void) pthread_mutex_init(&hp->h_lock, NULL); + + hp->h_endpt_id = fmd_hdl_strdup(hdl, endpoint_id, FMD_SLEEP); + hp->h_domain_id = domain_id; + hp->h_client.c_sd = EXS_SD_FREE; + hp->h_server.c_sd = EXS_SD_FREE; + hp->h_hdl = hdl; + hp->h_cb_func = cb_func; + hp->h_cb_func_arg = cb_func_arg; + + return (hp); +} + +/* + * Prepare the client connection. + * Return 0 for success, nonzero for failure. + */ +static int +exs_prep_client(fmd_hdl_t *hdl, exs_hdl_t *hp) +{ + int rv; + + /* Find the DSCP address for the remote endpoint */ + if ((rv = dscpAddr(hp->h_domain_id, DSCP_ADDR_REMOTE, + (struct sockaddr *)&hp->h_client.c_saddr, + &hp->h_client.c_len)) != DSCP_OK) { + fmd_hdl_debug(hdl, "xport - dscpAddr for %s failed: %d", + hp->h_endpt_id, rv); + return (1); + } + + if ((hp->h_client.c_sd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { + fmd_hdl_debug(hdl, "xport - client socket failed for %s", + hp->h_endpt_id); + return (1); + } + + /* Bind the socket to the local IP address of the DSCP link */ + if ((rv = dscpBind(hp->h_domain_id, hp->h_client.c_sd, + EXS_CLIENT_PORT)) != DSCP_OK) { + fmd_hdl_debug(hdl, "xport - client bind for %s failed: %d", + hp->h_endpt_id, rv); + (void) close(hp->h_client.c_sd); + hp->h_client.c_sd = EXS_SD_FREE; + return (1); + } + + hp->h_client.c_saddr.sin_port = htons(EXS_SERVER_PORT); + + /* Set IPsec security policy for this socket */ + if ((rv = dscpSecure(hp->h_domain_id, hp->h_client.c_sd)) != DSCP_OK) { + fmd_hdl_debug(hdl, "xport - dscpSecure for %s failed: %d", + hp->h_endpt_id, rv); + (void) close(hp->h_client.c_sd); + hp->h_client.c_sd = EXS_SD_FREE; + return (1); + } + + return (0); +} + +/* + * Prepare to accept a connection. + * Assume Mod_lock is held by caller. + * Return 0 for success, nonzero for failure. + */ +static int +exs_prep_accept(fmd_hdl_t *hdl) +{ + + int flags, domain = 0, optval = 1; + int rv; + + if ((Acceptor_conn.c_sd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { + fmd_hdl_debug(hdl, "xport - acceptor socket failed"); + return (1); + } + + if (setsockopt(Acceptor_conn.c_sd, SOL_SOCKET, SO_REUSEADDR, + &optval, sizeof (optval))) { + fmd_hdl_debug(hdl, "xport - set REUSEADDR failed"); + (void) close(Acceptor_conn.c_sd); + Acceptor_conn.c_sd = EXS_SD_FREE; + return (1); + } + + /* Bind the socket to the local IP address of the DSCP link */ + if ((rv = dscpBind(domain, Acceptor_conn.c_sd, + EXS_SERVER_PORT)) != DSCP_OK) { + fmd_hdl_debug(hdl, "xport - acceptor bind failed: %d", rv); + (void) close(Acceptor_conn.c_sd); + Acceptor_conn.c_sd = EXS_SD_FREE; + return (1); + } + + /* Activate IPsec security policy for this socket */ + if ((rv = dscpSecure(domain, Acceptor_conn.c_sd)) != DSCP_OK) { + fmd_hdl_debug(hdl, "xport - dscpSecure for acceptor failed: %d", + rv); + (void) close(Acceptor_conn.c_sd); + Acceptor_conn.c_sd = EXS_SD_FREE; + return (1); + } + + if ((listen(Acceptor_conn.c_sd, EXS_NUM_SOCKS)) == -1) { + fmd_hdl_debug(hdl, "xport - acceptor listen failed"); + (void) close(Acceptor_conn.c_sd); + Acceptor_conn.c_sd = EXS_SD_FREE; + return (1); + } + + flags = fcntl(Acceptor_conn.c_sd, F_GETFL, 0); + (void) fcntl(Acceptor_conn.c_sd, F_SETFL, flags | O_NONBLOCK); + + return (0); +} + +/* + * Translate endpoint_id str to int. + * Return the domain ID via "dom_id". + * Return 0 for success, nonzero for failure + */ +static int +exs_get_id(fmd_hdl_t *hdl, char *endpoint_id, int *dom_id) +{ + char *ptr; + + if (strstr(endpoint_id, EXS_SP_PREFIX) != NULL) { + /* Remote endpoint is the SP */ + *dom_id = DSCP_IDENT_SP; + return (0); + } else { + if ((ptr = strstr(endpoint_id, EXS_DOMAIN_PREFIX)) == NULL) { + fmd_hdl_debug(hdl, "xport - %s not found in %s\n", + EXS_DOMAIN_PREFIX, endpoint_id); + return (1); + } + + ptr += EXS_DOMAIN_PREFIX_LEN; + + if ((sscanf(ptr, "%d", dom_id)) != 1) { + fmd_hdl_debug(hdl, "xport - no integer found in %s\n", + endpoint_id); + return (1); + } + } + + return (0); +} + +/* + * Build set of socket descriptors based on the current list of exs_hdl_t. + * Return the largest descriptor. + */ +static int +exs_build_set(fmd_hdl_t *hdl) +{ + exs_hdl_t *curr; + struct sockaddr sa; + socklen_t slen = sizeof (struct sockaddr); + fd_set rset; + int max_sd = 0; + + fmd_hdl_debug(hdl, "xport - building set of socket descr"); + + FD_ZERO(&rset); + FD_SET(Acceptor_conn.c_sd, &rset); + + (void) pthread_mutex_lock(&List_lock); + + for (curr = Exh_head; curr; curr = curr->h_next) { + (void) pthread_mutex_lock(&curr->h_lock); + if (curr->h_server.c_sd != EXS_SD_FREE) { + /* Use getsockname to test for valid socket descr */ + if (getsockname(curr->h_server.c_sd, &sa, &slen) == 0) + FD_SET(curr->h_server.c_sd, &rset); + else if ((errno == EBADF) || (errno == ENOTSOCK)) + curr->h_server.c_sd = EXS_SD_FREE; + else + fmd_hdl_error(hdl, "xport - getsockname fail"); + + if (curr->h_server.c_sd > max_sd) + max_sd = curr->h_server.c_sd; + } + (void) pthread_mutex_unlock(&curr->h_lock); + } + + (void) pthread_mutex_unlock(&List_lock); + + (void) pthread_mutex_lock(&Mod_lock); + Conn_set = rset; + (void) pthread_mutex_unlock(&Mod_lock); + + if (max_sd > FD_SETSIZE) + fmd_hdl_abort(hdl, "xport - max_sd too big"); + + return (max_sd); +} + +/* + * Find the exs_hdl_t associated with the given sockaddr_in. + * Assume caller holds lock on List_lock. + * Return the exs_hdl_t for success, NULL for failure. + */ +static exs_hdl_t * +exs_find_hdl(fmd_hdl_t *hdl, struct sockaddr_in *saddr, socklen_t salen) +{ + exs_hdl_t *curr; + int domain_id, rv; + + /* Translate saddr to a domain id string */ + if ((rv = dscpIdent((struct sockaddr *)saddr, (int)salen, + &domain_id)) != DSCP_OK) { + fmd_hdl_debug(hdl, "xport - dscpIdent failed for 0x%x : %d", + saddr->sin_addr.s_addr, rv); + return (NULL); + } + + if ((rv = dscpAuth(domain_id, (struct sockaddr *)saddr, + (int)salen)) != DSCP_OK) { + fmd_hdl_debug(hdl, "xport - dscpAuth failed for 0x%x : %d", + saddr->sin_addr.s_addr, rv); + return (NULL); + } + + /* Lookup this domain id */ + for (curr = Exh_head; curr; curr = curr->h_next) { + if (curr->h_domain_id == domain_id) + break; + } + + return (curr); +} + +/* + * Main server function, runs on thread started at init. + * Accepts incoming connections and notifies ETM of incoming data. + * Thread/function runs until Server_status changes to S_DOEXIT. + */ +static void +exs_server(void *arg) +{ + int new_sd; /* Socket desc of new conn */ + int nready; /* Num readable sockets from select */ + int max_sd; /* Max socket desc : for select */ + fd_set rset; /* Read socket desc set for select */ + struct sockaddr_in new_saddr; /* Sockaddr of remote endpt */ + exs_hdl_t *hp; + fmd_hdl_t *hdl = (fmd_hdl_t *)arg; + socklen_t new_len = sizeof (struct sockaddr); + int flags, old_sd = 0; + + (void) pthread_mutex_lock(&Mod_lock); + Server_status = S_RUNNING; + FD_ZERO(&Conn_set); + FD_SET(Acceptor_conn.c_sd, &Conn_set); + max_sd = Acceptor_conn.c_sd; + + while (Server_status != S_DOEXIT) { + rset = Conn_set; + (void) pthread_mutex_unlock(&Mod_lock); + + if ((nready = select(max_sd + 1, &rset, NULL, NULL, + NULL)) == -1) { + if (errno == EINTR) + fmd_hdl_debug(hdl, "xport - select EINTR"); + else + max_sd = exs_build_set(hdl); + + (void) pthread_mutex_lock(&Mod_lock); + continue; + } + + /* First check if a new connection has arrived */ + if (FD_ISSET(Acceptor_conn.c_sd, &rset)) { + if ((new_sd = accept(Acceptor_conn.c_sd, + (struct sockaddr *)&new_saddr, &new_len)) != -1) { + (void) pthread_mutex_lock(&List_lock); + + if ((hp = exs_find_hdl(hdl, &new_saddr, + new_len)) != NULL) { + fmd_hdl_debug(hdl, "xport - new server " + "connection for %s", + hp->h_endpt_id); + + (void) pthread_mutex_lock(&hp->h_lock); + + if (hp->h_server.c_sd != EXS_SD_FREE) { + (void) close(hp->h_server.c_sd); + old_sd = hp->h_server.c_sd; + } + + hp->h_server.c_sd = new_sd; + + /* Set the socket to be non-blocking */ + flags = fcntl(hp->h_server.c_sd, + F_GETFL, 0); + (void) fcntl(hp->h_server.c_sd, + F_SETFL, flags | O_NONBLOCK); + + (void) pthread_mutex_unlock( + &hp->h_lock); + (void) pthread_mutex_unlock(&List_lock); + + /* + * Add this socket descriptor to the + * fd_set and remove the old one. + */ + (void) pthread_mutex_lock(&Mod_lock); + FD_SET(new_sd, &Conn_set); + if (old_sd) { + FD_CLR(old_sd, &Conn_set); + old_sd = 0; + } + (void) pthread_mutex_unlock(&Mod_lock); + + if (new_sd > max_sd) + max_sd = new_sd; + } else { + (void) pthread_mutex_unlock(&List_lock); + fmd_hdl_debug(hdl, + "xport - no tlhdl for endpt 0x%x", + new_saddr.sin_addr.s_addr); + (void) close(new_sd); + } + } else { + fmd_hdl_debug(hdl, + "xport - accept failed"); + } + + if (--nready <= 0) { + /* No more sockets to check */ + (void) pthread_mutex_lock(&Mod_lock); + continue; + } + } + + /* Check if any of the other sockets have data to recv */ + (void) pthread_mutex_lock(&List_lock); + for (hp = Exh_head; hp; hp = hp->h_next) { + (void) pthread_mutex_lock(&hp->h_lock); + + if (hp->h_server.c_sd == EXS_SD_FREE) { + (void) pthread_mutex_unlock(&hp->h_lock); + continue; + } + + if (FD_ISSET(hp->h_server.c_sd, &rset)) { + /* + * Data is available on this socket + * or the remote side has closed. + */ + if ((hp->h_cb_func(hp->h_hdl, + &hp->h_server, ETM_CBFLAG_RECV, + hp->h_cb_func_arg)) != 0) { + /* + * Remove the socket descriptor from + * the fd_set + */ + (void) pthread_mutex_lock(&Mod_lock); + FD_CLR(hp->h_server.c_sd, &Conn_set); + (void) pthread_mutex_unlock(&Mod_lock); + + /* Close the server socket */ + (void) close(hp->h_server.c_sd); + hp->h_server.c_sd = EXS_SD_FREE; + } + + if (--nready <= 0) { + /* No more sockets to check */ + (void) pthread_mutex_unlock( + &hp->h_lock); + break; + } + } + + (void) pthread_mutex_unlock(&hp->h_lock); + } + + (void) pthread_mutex_unlock(&List_lock); + (void) pthread_mutex_lock(&Mod_lock); + } + + fmd_hdl_debug(hdl, "xport - exiting server thread %d", Server_tid); + (void) close(Acceptor_conn.c_sd); + Acceptor_conn.c_sd = EXS_SD_FREE; + Server_tid = 0; + Server_status = S_WAITING; + (void) pthread_mutex_unlock(&Mod_lock); + /* Thread dies */ +} + +/* + * ETM-to-Transport API Connection Management routines + */ + +/* + * Initialize and setup any transport infrastructure before any connections + * are opened. + * Return etm_xport_hdl_t for success, NULL for failure. + */ +etm_xport_hdl_t +etm_xport_init(fmd_hdl_t *hdl, char *endpoint_id, + int (*cb_func)(fmd_hdl_t *hdl, etm_xport_conn_t conn, etm_cb_flag_t flag, + void *arg), void *cb_func_arg) +{ + exs_hdl_t *hp, *curr; + int domain_id; + + if ((exs_get_id(hdl, endpoint_id, &domain_id)) == -1) + return (NULL); + + (void) pthread_mutex_lock(&List_lock); + if (Exh_head == NULL) { + /* This is the first init */ + (void) pthread_mutex_lock(&Mod_lock); + if (exs_prep_accept(hdl)) { + (void) pthread_mutex_unlock(&Mod_lock); + (void) pthread_mutex_unlock(&List_lock); + return (NULL); + } + (void) pthread_mutex_unlock(&Mod_lock); + } else { + /* Check for a duplicate endpoint_id on the list */ + for (curr = Exh_head; curr; curr = curr->h_next) { + if (domain_id == curr->h_domain_id) { + fmd_hdl_debug(hdl, "xport - init failed, " + "duplicate domain_id : %d\n", domain_id); + (void) pthread_mutex_unlock(&List_lock); + return (NULL); + } + } + } + + /* Alloc and init a transport instance handle */ + hp = exs_hdl_alloc(hdl, endpoint_id, cb_func, cb_func_arg, + domain_id); + + /* Prep the client-side connection */ + if (exs_prep_client(hdl, hp)) { + if (Exh_head == NULL) { + (void) pthread_mutex_lock(&Mod_lock); + if (Acceptor_conn.c_sd != EXS_SD_FREE) { + (void) close(Acceptor_conn.c_sd); + Acceptor_conn.c_sd = EXS_SD_FREE; + } + (void) pthread_mutex_unlock(&Mod_lock); + } + + fmd_hdl_strfree(hdl, hp->h_endpt_id); + (void) pthread_mutex_unlock(&hp->h_lock); + (void) pthread_mutex_destroy(&hp->h_lock); + fmd_hdl_free(hdl, hp, sizeof (exs_hdl_t)); + (void) pthread_mutex_unlock(&List_lock); + return (NULL); + } + + /* Add this transport instance handle to the list */ + hp->h_next = Exh_head; + Exh_head = hp; + (void) pthread_mutex_unlock(&List_lock); + + /* Create the Server thread, if necessary */ + (void) pthread_mutex_lock(&Mod_lock); + if (Server_tid == 0) + Server_tid = fmd_thr_create(hdl, exs_server, hdl); + + (void) pthread_mutex_unlock(&Mod_lock); + + return ((etm_xport_hdl_t)hp); +} + +/* + * Teardown any transport infrastructure after all connections are closed. + * Return 0 for success, or nonzero for failure. + */ +int +etm_xport_fini(fmd_hdl_t *hdl, etm_xport_hdl_t tlhdl) +{ + exs_hdl_t *hp = (exs_hdl_t *)tlhdl; + exs_hdl_t *prev, *curr; + + /* Remove this handle from the list */ + prev = NULL; + + (void) pthread_mutex_lock(&List_lock); + + for (curr = Exh_head; curr; curr = curr->h_next) { + if (curr == hp) + break; + + prev = curr; + } + + if (curr == NULL) { + (void) pthread_mutex_unlock(&List_lock); + fmd_hdl_debug(hdl, "xport - fini failed, tlhdl %p not on list", + curr); + return (1); + } + + if (prev == NULL) + Exh_head = Exh_head->h_next; + else + prev->h_next = hp->h_next; + + /* If this is the last handle, cleanup and exit the Server thread */ + if (Exh_head == NULL) { + (void) pthread_mutex_lock(&Mod_lock); + Server_status = S_DOEXIT; + (void) pthread_mutex_unlock(&Mod_lock); + fmd_thr_signal(hdl, Server_tid); + fmd_thr_destroy(hdl, Server_tid); + } + + (void) pthread_mutex_unlock(&List_lock); + + /* Close the handle's client connection */ + (void) pthread_mutex_lock(&hp->h_lock); + if (hp->h_client.c_sd != EXS_SD_FREE) + (void) close(hp->h_client.c_sd); + + /* + * Close the handle's server connection and remove it from the fd_set + * used in the Server thread. + */ + if (hp->h_server.c_sd != EXS_SD_FREE) { + (void) close(hp->h_server.c_sd); + (void) pthread_mutex_lock(&Mod_lock); + FD_CLR(hp->h_server.c_sd, &Conn_set); + (void) pthread_mutex_unlock(&Mod_lock); + } + + fmd_hdl_strfree(hdl, hp->h_endpt_id); + (void) pthread_mutex_unlock(&hp->h_lock); + (void) pthread_mutex_destroy(&hp->h_lock); + fmd_hdl_free(hdl, hp, sizeof (exs_hdl_t)); + + return (0); +} + +/* + * Open a connection with the given endpoint, + * Return etm_xport_conn_t for success, NULL and set errno for failure. + */ +etm_xport_conn_t +etm_xport_open(fmd_hdl_t *hdl, etm_xport_hdl_t tlhdl) +{ + int flags; + exs_hdl_t *hp = (exs_hdl_t *)tlhdl; + + if (hp->h_client.c_sd == EXS_SD_FREE) { + if (exs_prep_client(hdl, hp) != 0) + return (NULL); + } + + if ((connect(hp->h_client.c_sd, + (struct sockaddr *)&hp->h_client.c_saddr, + hp->h_client.c_len)) == -1) { + fmd_hdl_error(hdl, "xport - failed connect to server for %s", + hp->h_endpt_id); + (void) close(hp->h_client.c_sd); + hp->h_client.c_sd = EXS_SD_FREE; + return (NULL); + } + + /* Set the socket to be non-blocking */ + flags = fcntl(hp->h_client.c_sd, F_GETFL, 0); + (void) fcntl(hp->h_client.c_sd, F_SETFL, flags | O_NONBLOCK); + + fmd_hdl_debug(hdl, "xport - connected client socket for %s", + hp->h_endpt_id); + + return (&hp->h_client); +} + +/* + * Close a connection from either endpoint. + * Return zero for success, nonzero for failure. + */ +/*ARGSUSED*/ +int +etm_xport_close(fmd_hdl_t *hdl, etm_xport_conn_t conn) +{ + exs_conn_t *cp = (exs_conn_t *)conn; + + if (cp->c_sd == EXS_SD_FREE) + return (0); /* Connection already closed */ + + (void) close(cp->c_sd); + cp->c_sd = EXS_SD_FREE; + + return (0); +} + +/* + * ETM-to-Transport API I/O routines + */ + +/* + * Try to read byte_cnt bytes from the connection into the given buffer. + * Return how many bytes actually read for success, negative value for failure. + */ +ssize_t +etm_xport_read(fmd_hdl_t *hdl, etm_xport_conn_t conn, hrtime_t timeout, + void *buf, size_t byte_cnt) +{ + ssize_t len, nbytes = 0; + hrtime_t endtime, sleeptime; + struct timespec tms; + char *ptr = (char *)buf; + exs_conn_t *cp = (exs_conn_t *)conn; + + if (cp->c_sd == EXS_SD_FREE) { + fmd_hdl_debug(hdl, "xport - read socket %d is closed\n", + cp->c_sd); + return (-EBADF); + } + + endtime = gethrtime() + timeout; + sleeptime = timeout / EXS_IO_SLEEP_DIV; + + tms.tv_sec = 0; + tms.tv_nsec = sleeptime; + + while (nbytes < byte_cnt) { + if (gethrtime() < endtime) { + if ((len = recv(cp->c_sd, ptr, byte_cnt - nbytes, + 0)) < 0) { + if (errno != EINTR && errno != EWOULDBLOCK) { + fmd_hdl_debug(hdl, "xport - recv " + "failed for socket %d", cp->c_sd); + } + + (void) nanosleep(&tms, 0); + continue; + } else if (len == 0) { + fmd_hdl_debug(hdl, "xport - remote endpt " + "closed for socket %d", cp->c_sd); + return (0); + } + + ptr += len; + nbytes += len; + } else { + fmd_hdl_debug(hdl, "xport - read timed out for socket " + "%d", cp->c_sd); + break; + } + } + + if (nbytes) + return (nbytes); + else + return (-1); +} + +/* + * Try to write byte_cnt bytes to the connection from the given buffer. + * Return how many bytes actually written for success, negative value + * for failure. + */ +ssize_t +etm_xport_write(fmd_hdl_t *hdl, etm_xport_conn_t conn, hrtime_t timeout, + void *buf, size_t byte_cnt) +{ + ssize_t len, nbytes = 0; + hrtime_t endtime, sleeptime; + struct timespec tms; + char *ptr = (char *)buf; + exs_conn_t *cp = (exs_conn_t *)conn; + + if (cp->c_sd == EXS_SD_FREE) { + fmd_hdl_debug(hdl, "xport - write socket %d is closed\n", + cp->c_sd); + return (-EBADF); + } + + endtime = gethrtime() + timeout; + sleeptime = timeout / EXS_IO_SLEEP_DIV; + + tms.tv_sec = 0; + tms.tv_nsec = sleeptime; + + while (nbytes < byte_cnt) { + if (gethrtime() < endtime) { + if ((len = send(cp->c_sd, ptr, byte_cnt - nbytes, + 0)) < 0) { + if (errno != EINTR && errno != EWOULDBLOCK) { + fmd_hdl_debug(hdl, "xport - send " + "failed for socket %d", cp->c_sd); + } + + (void) nanosleep(&tms, 0); + continue; + } + + ptr += len; + nbytes += len; + } else { + fmd_hdl_debug(hdl, "xport - write timed out for socket " + "%d", cp->c_sd); + break; + } + } + + if (nbytes) + return (nbytes); + else + return (-1); +} diff --git a/usr/src/cmd/fm/modules/common/cpumem-retire/cma.h b/usr/src/cmd/fm/modules/common/cpumem-retire/cma.h index 0b3477937b..bf872e2eb4 100644 --- a/usr/src/cmd/fm/modules/common/cpumem-retire/cma.h +++ b/usr/src/cmd/fm/modules/common/cpumem-retire/cma.h @@ -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. @@ -37,6 +36,9 @@ extern "C" { #endif +#define CMA_RA_SUCCESS 0 +#define CMA_RA_FAILURE 1 + typedef struct cma_page { struct cma_page *pg_next; /* List of page retirements for retry */ nvlist_t *pg_fmri; /* FMRI for this page */ @@ -79,9 +81,9 @@ typedef struct cma_stats { extern cma_stats_t cma_stats; extern cma_t cma; -extern void cma_cpu_retire(fmd_hdl_t *, nvlist_t *, nvlist_t *, const char *); +extern int cma_cpu_retire(fmd_hdl_t *, nvlist_t *, nvlist_t *, const char *); -extern void cma_page_retire(fmd_hdl_t *, nvlist_t *, nvlist_t *, const char *); +extern int cma_page_retire(fmd_hdl_t *, nvlist_t *, nvlist_t *, const char *); extern void cma_page_retry(fmd_hdl_t *); extern void cma_page_fini(fmd_hdl_t *); diff --git a/usr/src/cmd/fm/modules/common/cpumem-retire/cma_cpu.c b/usr/src/cmd/fm/modules/common/cpumem-retire/cma_cpu.c index e89f4e674d..7868272060 100644 --- a/usr/src/cmd/fm/modules/common/cpumem-retire/cma_cpu.c +++ b/usr/src/cmd/fm/modules/common/cpumem-retire/cma_cpu.c @@ -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,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -98,8 +97,8 @@ cpu_blacklist(fmd_hdl_t *hdl, nvlist_t *nvl, nvlist_t *asru) return (0); } -static void -cpu_offline(fmd_hdl_t *hdl, const char *uuid, uint_t cpuid, int cpustate) +static int +cpu_offline(fmd_hdl_t *hdl, uint_t cpuid, int cpustate) { int i; @@ -108,21 +107,22 @@ cpu_offline(fmd_hdl_t *hdl, const char *uuid, uint_t cpuid, int cpustate) if (p_online(cpuid, cpustate) != -1) { fmd_hdl_debug(hdl, "offlined cpu %u\n", cpuid); cma_stats.cpu_flts.fmds_value.ui64++; - if (uuid != NULL) - fmd_case_uuclose(hdl, uuid); - return; + return (CMA_RA_SUCCESS); } } fmd_hdl_debug(hdl, "failed to offline %u: %s\n", cpuid, strerror(errno)); cma_stats.cpu_fails.fmds_value.ui64++; + return (CMA_RA_FAILURE); } -void +int +/* ARGSUSED 3 */ cma_cpu_retire(fmd_hdl_t *hdl, nvlist_t *nvl, nvlist_t *asru, const char *uuid) { uint_t cpuid, cpuvid; + int err = 0; /* * This added expansion is needed to cover the situation where a @@ -133,13 +133,13 @@ cma_cpu_retire(fmd_hdl_t *hdl, nvlist_t *nvl, nvlist_t *asru, const char *uuid) if (fmd_nvl_fmri_expand(hdl, asru) < 0) { fmd_hdl_debug(hdl, "failed to expand cpu asru\n"); cma_stats.bad_flts.fmds_value.ui64++; - return; + return (CMA_RA_FAILURE); } if (nvlist_lookup_uint32(asru, FM_FMRI_CPU_ID, &cpuid) != 0) { fmd_hdl_debug(hdl, "cpu fault missing '%s'\n", FM_FMRI_CPU_ID); cma_stats.bad_flts.fmds_value.ui64++; - return; + return (CMA_RA_FAILURE); } /* @@ -156,7 +156,7 @@ cma_cpu_retire(fmd_hdl_t *hdl, nvlist_t *nvl, nvlist_t *asru, const char *uuid) if (cma.cma_cpu_forcedoffline) cpustate |= P_FORCED; - cpu_offline(hdl, uuid, cpuid, cpustate); + err = cpu_offline(hdl, cpuid, cpustate); } else { fmd_hdl_debug(hdl, "suppressed offline of CPU %u\n", cpuid); cma_stats.cpu_supp.fmds_value.ui64++; @@ -169,4 +169,6 @@ cma_cpu_retire(fmd_hdl_t *hdl, nvlist_t *nvl, nvlist_t *asru, const char *uuid) fmd_hdl_debug(hdl, "suppressed blacklist of CPU %u\n", cpuid); cma_stats.cpu_blsupp.fmds_value.ui64++; } + + return (err); } diff --git a/usr/src/cmd/fm/modules/common/cpumem-retire/cma_main.c b/usr/src/cmd/fm/modules/common/cpumem-retire/cma_main.c index e74bc51c4d..78c9cfb344 100644 --- a/usr/src/cmd/fm/modules/common/cpumem-retire/cma_main.c +++ b/usr/src/cmd/fm/modules/common/cpumem-retire/cma_main.c @@ -56,7 +56,7 @@ typedef struct cma_subscriber { const char *subr_class; const char *subr_sname; uint_t subr_svers; - void (*subr_func)(fmd_hdl_t *, nvlist_t *, nvlist_t *, const char *); + int (*subr_func)(fmd_hdl_t *, nvlist_t *, nvlist_t *, const char *); } cma_subscriber_t; static const cma_subscriber_t cma_subrs[] = { @@ -129,6 +129,7 @@ cma_recv_list(fmd_hdl_t *hdl, nvlist_t *nvl) char *uuid = NULL; nvlist_t **nva; uint_t nvc = 0; + uint_t keepopen; int err = 0; err |= nvlist_lookup_string(nvl, FM_SUSPECT_UUID, &uuid); @@ -139,6 +140,7 @@ cma_recv_list(fmd_hdl_t *hdl, nvlist_t *nvl) return; } + keepopen = nvc; while (nvc-- != 0 && !fmd_case_uuclosed(hdl, uuid)) { nvlist_t *nvl = *nva++; const cma_subscriber_t *subr; @@ -147,9 +149,22 @@ cma_recv_list(fmd_hdl_t *hdl, nvlist_t *nvl) if ((subr = nvl2subr(hdl, nvl, &asru)) == NULL) continue; - if (subr->subr_func != NULL) - subr->subr_func(hdl, nvl, asru, uuid); + /* + * A handler returns CMA_RA_SUCCESS to indicate that + * from this suspects point-of-view the case may be + * closed, CMA_RA_FAILURE otherwise. + * A handler must not close the case itself. + */ + if (subr->subr_func != NULL) { + err = subr->subr_func(hdl, nvl, asru, uuid); + + if (err == CMA_RA_SUCCESS) + keepopen--; + } } + + if (!keepopen) + fmd_case_uuclose(hdl, uuid); } static void @@ -157,12 +172,18 @@ cma_recv_one(fmd_hdl_t *hdl, nvlist_t *nvl) { const cma_subscriber_t *subr; nvlist_t *asru; + int err; if ((subr = nvl2subr(hdl, nvl, &asru)) == NULL) return; - if (subr->subr_func != NULL) - subr->subr_func(hdl, nvl, asru, NULL); + if (subr->subr_func != NULL) { + err = subr->subr_func(hdl, nvl, asru, NULL); + + if (err != CMA_RA_SUCCESS) + fmd_hdl_debug(hdl, "failed to offline cpu\n"); + } + } /*ARGSUSED*/ diff --git a/usr/src/cmd/fm/modules/common/cpumem-retire/cma_page.c b/usr/src/cmd/fm/modules/common/cpumem-retire/cma_page.c index e2ea6298eb..efc65aa6af 100644 --- a/usr/src/cmd/fm/modules/common/cpumem-retire/cma_page.c +++ b/usr/src/cmd/fm/modules/common/cpumem-retire/cma_page.c @@ -127,7 +127,7 @@ cma_page_free(fmd_hdl_t *hdl, cma_page_t *page) * in userland (i.e. with a libtopo method to compute and update the PA). */ /*ARGSUSED*/ -void +int cma_page_retire(fmd_hdl_t *hdl, nvlist_t *nvl, nvlist_t *asru, const char *uuid) { cma_page_t *page; @@ -139,29 +139,27 @@ cma_page_retire(fmd_hdl_t *hdl, nvlist_t *nvl, nvlist_t *asru, const char *uuid) if (fmd_nvl_fmri_expand(hdl, asru) < 0) { fmd_hdl_debug(hdl, "failed to expand page asru\n"); cma_stats.bad_flts.fmds_value.ui64++; - return; + return (CMA_RA_FAILURE); } if (nvlist_lookup_uint64(asru, FM_FMRI_MEM_PHYSADDR, &pageaddr) != 0) { fmd_hdl_debug(hdl, "mem fault missing '%s'\n", FM_FMRI_MEM_PHYSADDR); cma_stats.bad_flts.fmds_value.ui64++; - return; + return (CMA_RA_FAILURE); } if (!cma.cma_page_doretire) { fmd_hdl_debug(hdl, "suppressed retire of page %llx\n", (u_longlong_t)pageaddr); cma_stats.page_supp.fmds_value.ui64++; - return; + return (CMA_RA_FAILURE); } if (!fmd_nvl_fmri_present(hdl, asru)) { fmd_hdl_debug(hdl, "page retire overtaken by events\n"); cma_stats.page_nonent.fmds_value.ui64++; - if (uuid != NULL) - fmd_case_uuclose(hdl, uuid); - return; + return (CMA_RA_SUCCESS); } /* @@ -177,13 +175,13 @@ cma_page_retire(fmd_hdl_t *hdl, nvlist_t *nvl, nvlist_t *asru, const char *uuid) if (topo_fmri_str2nvl(thp, unumstr, &unumfmri, &err) != 0) { fmd_hdl_debug(hdl, "page retire str2nvl failed: %s\n", topo_strerror(err)); - return; + return (CMA_RA_FAILURE); } if (nvlist_dup(asru, &asrucp, 0) != 0) { fmd_hdl_debug(hdl, "page retire nvlist dup failed\n"); nvlist_free(unumfmri); - return; + return (CMA_RA_FAILURE); } if (nvlist_add_nvlist(asrucp, FM_FMRI_MEM_UNUM "-fmri", @@ -192,7 +190,7 @@ cma_page_retire(fmd_hdl_t *hdl, nvlist_t *nvl, nvlist_t *asru, const char *uuid) "unumfmri to modified asru"); nvlist_free(unumfmri); nvlist_free(asrucp); - return; + return (CMA_RA_FAILURE); } nvlist_free(unumfmri); } @@ -202,19 +200,17 @@ cma_page_retire(fmd_hdl_t *hdl, nvlist_t *nvl, nvlist_t *asru, const char *uuid) fmd_hdl_debug(hdl, "retired page 0x%llx\n", (u_longlong_t)pageaddr); cma_stats.page_flts.fmds_value.ui64++; - if (uuid != NULL) - fmd_case_uuclose(hdl, uuid); if (asrucp) nvlist_free(asrucp); - return; + return (CMA_RA_SUCCESS); } else if (errno != EAGAIN) { fmd_hdl_debug(hdl, "retire of page 0x%llx failed, will not " "retry: %s\n", (u_longlong_t)pageaddr, strerror(errno)); - if (uuid != NULL && cma.cma_page_maxretries != 0) - fmd_case_uuclose(hdl, uuid); if (asrucp) nvlist_free(asrucp); - return; + if (uuid != NULL && cma.cma_page_maxretries != 0) + return (CMA_RA_SUCCESS); + return (CMA_RA_FAILURE); } /* @@ -243,6 +239,8 @@ cma_page_retire(fmd_hdl_t *hdl, nvlist_t *nvl, nvlist_t *asru, const char *uuid) cma.cma_page_timerid = fmd_timer_install(hdl, NULL, NULL, cma.cma_page_curdelay); + + return (CMA_RA_FAILURE); } static int diff --git a/usr/src/cmd/fm/modules/common/event-transport/Makefile.etm b/usr/src/cmd/fm/modules/common/event-transport/Makefile.etm new file mode 100644 index 0000000000..b0d9f6d1e1 --- /dev/null +++ b/usr/src/cmd/fm/modules/common/event-transport/Makefile.etm @@ -0,0 +1,49 @@ +# +# 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. +# +#ident "%Z%%M% %I% %E% SMI" + +MODULE = event-transport +CLASS = plat +ETMDIR = ../../common/$(MODULE) +SRCS = \ + etm.c \ + $($(PLATFORMS)_SRCS) + +include ../../Makefile.plugin + +INCDIRS += \ + . \ + $(ETMDIR) + +CPPFLAGS += $(INCDIRS:%=-I%) +LDFLAGS += $(LIBFLAGS:%=-R%) +LDLIBS += $(LIBDIRS:%=-L%) $(XPORTLIBS) + +%.o: $(ETMDIR)/%.c + $(COMPILE.c) -o $@ $< + $(CTFCONVERT_O) + +%.ln: $(ETMDIR)/%.c + $(LINT.c) -c $< diff --git a/usr/src/cmd/fm/modules/common/event-transport/etm.c b/usr/src/cmd/fm/modules/common/event-transport/etm.c new file mode 100644 index 0000000000..285c33caa8 --- /dev/null +++ b/usr/src/cmd/fm/modules/common/event-transport/etm.c @@ -0,0 +1,1379 @@ +/* + * 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" + +/* + * FMA Event Transport Module + * + * Plugin for sending/receiving FMA events to/from a remote endoint. + */ + +#include <netinet/in.h> +#include <sys/fm/protocol.h> +#include <sys/sysmacros.h> +#include <pthread.h> +#include <strings.h> +#include <ctype.h> +#include <link.h> +#include <libnvpair.h> +#include "etm_xport_api.h" +#include "etm_proto.h" + +/* + * ETM declarations + */ + +typedef enum etm_connection_status { + C_UNINITIALIZED = 0, + C_OPEN, /* Connection is open */ + C_CLOSED, /* Connection is closed */ + C_LIMBO, /* Bad value in header from peer */ + C_TIMED_OUT /* Reconnection to peer timed out */ +} etm_connstat_t; + +typedef enum etm_fmd_queue_status { + Q_UNINITIALIZED = 100, + Q_INIT_PENDING, /* Queue initialization in progress */ + Q_OPEN, /* Queue is open */ + Q_SUSPENDED /* Queue is suspended */ +} etm_qstat_t; + +/* Per endpoint data */ +typedef struct etm_endpoint_map { + uint8_t epm_ver; /* Protocol version being used */ + char *epm_ep_str; /* Endpoint ID string */ + int epm_xprtflags; /* FMD transport open flags */ + etm_xport_hdl_t epm_tlhdl; /* Transport Layer instance handle */ + pthread_mutex_t epm_lock; /* Protects remainder of struct */ + pthread_cond_t epm_tx_cv; /* Cond var for send/transmit */ + int epm_txbusy; /* Busy doing send/transmit */ + fmd_xprt_t *epm_xprthdl; /* FMD transport handle */ + etm_qstat_t epm_qstat; /* Status of fmd xprt queue */ + nvlist_t *epm_ep_nvl; /* Endpoint ID nv_list */ + etm_xport_conn_t epm_oconn; /* Connection for outgoing events */ + etm_connstat_t epm_cstat; /* Status of connection */ + id_t epm_timer_id; /* Timer id */ + int epm_timer_in_use; /* Indicates if timer is in use */ + hrtime_t epm_reconn_end; /* Reconnection end time */ + struct etm_endpoint_map *epm_next; +} etm_epmap_t; + +#define ETM_HDR_INVALID (ETM_HDR_TYPE_TOO_HIGH + 1) +#define ETM_HDR_BADVERSION (ETM_HDR_TYPE_TOO_HIGH + 2) +#define ETM_HDR_BADTYPE (ETM_HDR_TYPE_TOO_HIGH + 3) +#define ETM_EP_INST_MAX 4 /* Max chars in endpt instance */ +#define ETM_CLIENT_XPRT_FLAGS FMD_XPRT_RDWR +#define ETM_SERVER_XPRT_FLAGS (FMD_XPRT_RDWR | FMD_XPRT_ACCEPT) + +#define ALLOC_BUF(hdl, buf, size) \ + buf = fmd_hdl_zalloc((hdl), (size), FMD_SLEEP); + +#define FREE_BUF(hdl, buf, size) fmd_hdl_free((hdl), (buf), (size)); + +#define IS_CLIENT(mp) (((mp)->epm_xprtflags & FMD_XPRT_ACCEPT) ? 0 : 1) + +#define INCRSTAT(x) { (void) pthread_mutex_lock(&Etm_mod_lock); \ + (x)++; \ + (void) pthread_mutex_unlock(&Etm_mod_lock); \ + } + +#define DECRSTAT(x) { (void) pthread_mutex_lock(&Etm_mod_lock); \ + (x)--; \ + (void) pthread_mutex_unlock(&Etm_mod_lock); \ + } + +#define ADDSTAT(x, y) { (void) pthread_mutex_lock(&Etm_mod_lock); \ + (x) += (y); \ + (void) pthread_mutex_unlock(&Etm_mod_lock); \ + } + +/* + * Global variables + */ +static pthread_mutex_t Etm_mod_lock = PTHREAD_MUTEX_INITIALIZER; + /* Protects globals */ +static hrtime_t Reconn_interval; /* Time between reconnection attempts */ +static hrtime_t Reconn_timeout; /* Time allowed for reconnection */ +static hrtime_t Rw_timeout; /* Time allowed for I/O operation */ +static int Etm_dump = 0; /* Enables hex dump for debug */ +static int Etm_exit = 0; /* Flag for exit */ +static etm_epmap_t *Epmap_head = NULL; /* Head of list of epmap structs */ + +/* Module statistics */ +static struct etm_stats { + /* read counters */ + fmd_stat_t read_ack; + fmd_stat_t read_bytes; + fmd_stat_t read_msg; + /* write counters */ + fmd_stat_t write_ack; + fmd_stat_t write_bytes; + fmd_stat_t write_msg; + /* error counters */ + fmd_stat_t error_protocol; + fmd_stat_t error_drop_read; + fmd_stat_t error_read; + fmd_stat_t error_read_badhdr; + fmd_stat_t error_write; + /* misc */ + fmd_stat_t peer_count; + +} Etm_stats = { + /* read counters */ + { "read_ack", FMD_TYPE_UINT64, "ACKs read" }, + { "read_bytes", FMD_TYPE_UINT64, "Bytes read" }, + { "read_msg", FMD_TYPE_UINT64, "Messages read" }, + /* write counters */ + { "write_ack", FMD_TYPE_UINT64, "ACKs sent" }, + { "write_bytes", FMD_TYPE_UINT64, "Bytes sent" }, + { "write_msg", FMD_TYPE_UINT64, "Messages sent" }, + /* ETM error counters */ + { "error_protocol", FMD_TYPE_UINT64, "ETM protocol errors" }, + { "error_drop_read", FMD_TYPE_UINT64, "Dropped read messages" }, + { "error_read", FMD_TYPE_UINT64, "Read I/O errors" }, + { "error_read_badhdr", FMD_TYPE_UINT64, "Bad headers read" }, + { "error_write", FMD_TYPE_UINT64, "Write I/O errors" }, + /* ETM Misc */ + { "peer_count", FMD_TYPE_UINT64, "Number of peers initialized" }, +}; + +/* + * ETM Private functions + */ + +/* + * Hex dump for debug. + */ +static void +etm_hex_dump(fmd_hdl_t *hdl, void *buf, size_t buflen, int direction) +{ + int i, j, k; + int16_t *c; + + if (Etm_dump == 0) + return; + + j = buflen / 16; /* Number of complete 8-column rows */ + k = buflen % 16; /* Is there a last (non-8-column) row? */ + + if (direction) + fmd_hdl_debug(hdl, "--- WRITE Message Dump ---"); + else + fmd_hdl_debug(hdl, "--- READ Message Dump ---"); + + fmd_hdl_debug(hdl, " Displaying %d bytes", buflen); + + /* Dump the complete 8-column rows */ + for (i = 0; i < j; i++) { + c = (int16_t *)buf + (i * 8); + fmd_hdl_debug(hdl, "%3d: %4x %4x %4x %4x %4x %4x %4x %4x", i, + *(c+0), *(c+1), *(c+2), *(c+3), + *(c+4), *(c+5), *(c+6), *(c+7)); + } + + /* Dump the last (incomplete) row */ + c = (int16_t *)buf + (i * 8); + switch (k) { + case 4: + fmd_hdl_debug(hdl, "%3d: %4x %4x", i, *(c+0), *(c+1)); + break; + case 8: + fmd_hdl_debug(hdl, "%3d: %4x %4x %4x %4x", i, *(c+0), *(c+1), + *(c+2), *(c+3)); + break; + case 12: + fmd_hdl_debug(hdl, "%3d: %4x %4x %4x %4x %4x %4x", i, *(c+0), + *(c+1), *(c+2), *(c+3), *(c+4), *(c+5)); + break; + } + + fmd_hdl_debug(hdl, "--- End Dump ---"); +} + +/* + * Provide the length of a message based on the data in the given ETM header. + */ +static size_t +etm_get_msglen(void *buf) +{ + etm_proto_hdr_t *hp = (etm_proto_hdr_t *)buf; + + return (ntohl(hp->hdr_msglen)); +} + +/* + * Check the contents of the ETM header for errors. + * Return the header type (hdr_type). + */ +static int +etm_check_hdr(fmd_hdl_t *hdl, etm_epmap_t *mp, void *buf) +{ + etm_proto_hdr_t *hp = (etm_proto_hdr_t *)buf; + + if (bcmp(hp->hdr_delim, ETM_DELIM, ETM_DELIMLEN) != 0) { + fmd_hdl_error(hdl, "Bad delimiter in ETM header from %s " + ": 0x%x\n", mp->epm_ep_str, hp->hdr_delim); + return (ETM_HDR_INVALID); + } + + if ((hp->hdr_type == ETM_HDR_C_HELLO) || + (hp->hdr_type == ETM_HDR_S_HELLO)) { + /* Until version is negotiated, other fields may be wrong */ + return (hp->hdr_type); + } + + if (hp->hdr_ver != mp->epm_ver) { + fmd_hdl_error(hdl, "Bad version in ETM header from %s : 0x%x\n", + mp->epm_ep_str, hp->hdr_ver); + return (ETM_HDR_BADVERSION); + } + + if ((hp->hdr_type == ETM_HDR_TYPE_TOO_LOW) || + (hp->hdr_type >= ETM_HDR_TYPE_TOO_HIGH)) { + fmd_hdl_error(hdl, "Bad type in ETM header from %s : 0x%x\n", + mp->epm_ep_str, hp->hdr_type); + return (ETM_HDR_BADTYPE); + } + + return (hp->hdr_type); +} + +/* + * Create an ETM header of a given type in the given buffer. + * Return length of header. + */ +static size_t +etm_create_hdr(void *buf, uint8_t ver, uint8_t type, uint32_t msglen) +{ + etm_proto_hdr_t *hp = (etm_proto_hdr_t *)buf; + + bcopy(ETM_DELIM, hp->hdr_delim, ETM_DELIMLEN); + hp->hdr_ver = ver; + hp->hdr_type = type; + hp->hdr_msglen = htonl(msglen); + + return (ETM_HDRLEN); +} + +/* + * Convert message bytes to nvlist and post to fmd. + * Return zero for success, non-zero for failure. + * + * Note : nvl is free'd by fmd. + */ +static int +etm_post_msg(fmd_hdl_t *hdl, etm_epmap_t *mp, void *buf, size_t buflen) +{ + nvlist_t *nvl; + int rv; + + if (nvlist_unpack((char *)buf, buflen, &nvl, 0)) { + fmd_hdl_debug(hdl, "failed to unpack message"); + return (1); + } + + (void) pthread_mutex_lock(&mp->epm_lock); + (void) pthread_mutex_lock(&Etm_mod_lock); + if (!Etm_exit) { + (void) pthread_mutex_unlock(&Etm_mod_lock); + if (mp->epm_qstat == Q_OPEN) { + fmd_xprt_post(hdl, mp->epm_xprthdl, nvl, 0); + rv = 0; + } else if (mp->epm_qstat == Q_SUSPENDED) { + fmd_xprt_resume(hdl, mp->epm_xprthdl); + if (mp->epm_timer_in_use) { + fmd_timer_remove(hdl, mp->epm_timer_id); + mp->epm_timer_in_use = 0; + } + mp->epm_qstat = Q_OPEN; + fmd_hdl_debug(hdl, "queue resumed for %s", + mp->epm_ep_str); + fmd_xprt_post(hdl, mp->epm_xprthdl, nvl, 0); + rv = 0; + } else { + fmd_hdl_debug(hdl, "unable to post message, qstat = %d", + mp->epm_qstat); + rv = 2; + } + } else { + (void) pthread_mutex_unlock(&Etm_mod_lock); + fmd_hdl_debug(hdl, "unable to post message, module exiting"); + rv = 3; + } + + (void) pthread_mutex_unlock(&mp->epm_lock); + + return (rv); +} + +/* + * Handle the startup handshake to the server. The client always initiates + * the startup handshake. In the following sequence, we are the client and + * the remote endpoint is the server. + * + * Client sends C_HELLO and transitions to Q_INIT_PENDING state. + * Server sends S_HELLO and transitions to Q_INIT_PENDING state. + * Client sends ACK and transitions to Q_OPEN state. + * Server receives ACK and transitions to Q_OPEN state. + * + * Return 0 for success, nonzero for failure. + */ +static int +etm_handle_startup(fmd_hdl_t *hdl, etm_epmap_t *mp) +{ + etm_proto_hdr_t *hp; + size_t hdrlen = ETM_HDRLEN; + int hdrstat; + char hbuf[ETM_HDRLEN]; + + if ((mp->epm_oconn = etm_xport_open(hdl, mp->epm_tlhdl)) == NULL) + return (1); + + mp->epm_cstat = C_OPEN; + + hdrlen = etm_create_hdr(hbuf, mp->epm_ver, ETM_HDR_C_HELLO, 0); + + if ((etm_xport_write(hdl, mp->epm_oconn, Rw_timeout, hbuf, + hdrlen)) != hdrlen) { + fmd_hdl_error(hdl, "Failed to write C_HELLO to %s", + mp->epm_ep_str); + return (2); + } + + mp->epm_qstat = Q_INIT_PENDING; + + if ((etm_xport_read(hdl, mp->epm_oconn, Rw_timeout, hbuf, + hdrlen)) != hdrlen) { + fmd_hdl_error(hdl, "Failed to read S_HELLO from %s", + mp->epm_ep_str); + return (3); + } + + hdrstat = etm_check_hdr(hdl, mp, hbuf); + + if (hdrstat != ETM_HDR_S_HELLO) { + fmd_hdl_error(hdl, "Protocol error, did not receive S_HELLO " + "from %s", mp->epm_ep_str); + return (4); + } + + /* + * Get version from the server. + * Currently, only one version is supported. + */ + hp = (etm_proto_hdr_t *)(void *)hbuf; + if (hp->hdr_ver != ETM_PROTO_V1) { + fmd_hdl_error(hdl, "Unable to use same version as %s : %d", + mp->epm_ep_str, hp->hdr_ver); + return (5); + } + mp->epm_ver = hp->hdr_ver; + + hdrlen = etm_create_hdr(hbuf, mp->epm_ver, ETM_HDR_ACK, 0); + + if ((etm_xport_write(hdl, mp->epm_oconn, Rw_timeout, hbuf, + hdrlen)) != hdrlen) { + fmd_hdl_error(hdl, "Failed to write ACK for S_HELLO to %s", + mp->epm_ep_str); + return (6); + } + + /* + * Call fmd_xprt_open and fmd_xprt_setspecific with + * Etm_mod_lock held to avoid race with etm_send thread. + */ + (void) pthread_mutex_lock(&Etm_mod_lock); + if ((mp->epm_xprthdl = fmd_xprt_open(hdl, mp->epm_xprtflags, + mp->epm_ep_nvl, NULL)) == NULL) { + fmd_hdl_abort(hdl, "Failed to init xprthdl for %s", + mp->epm_ep_str); + } + fmd_xprt_setspecific(hdl, mp->epm_xprthdl, mp); + (void) pthread_mutex_unlock(&Etm_mod_lock); + + mp->epm_qstat = Q_OPEN; + fmd_hdl_debug(hdl, "queue open for %s", mp->epm_ep_str); + + return (0); +} + +/* + * Alloc a nvlist and add a string for the endpoint. + * Return zero for success, non-zero for failure. + */ +static int +etm_get_ep_nvl(fmd_hdl_t *hdl, etm_epmap_t *mp) +{ + /* + * Cannot use nvlist_xalloc(3NVPAIR) due to a recursive mutex situation + * in fmd when this nvlist_t is free'd. + */ + (void) nvlist_alloc(&mp->epm_ep_nvl, NV_UNIQUE_NAME, 0); + + if (nvlist_add_string(mp->epm_ep_nvl, "domain-id", mp->epm_ep_str)) { + fmd_hdl_debug(hdl, "failed to add domain-id string to nvlist " + "for %s", mp->epm_ep_str); + nvlist_free(mp->epm_ep_nvl); + return (1); + } + + return (0); +} + +/* + * Free the nvlist for the endpoint_id string. + */ +/*ARGSUSED*/ +static void +etm_free_ep_nvl(fmd_hdl_t *hdl, etm_epmap_t *mp) +{ + nvlist_free(mp->epm_ep_nvl); +} + +/* + * Check for a duplicate endpoint/peer string. + */ +/*ARGSUSED*/ +static int +etm_check_dup_ep_str(fmd_hdl_t *hdl, char *epname) +{ + etm_epmap_t *mp; + + for (mp = Epmap_head; mp != NULL; mp = mp->epm_next) + if (strcmp(epname, mp->epm_ep_str) == 0) + return (1); + + return (0); +} + +/* + * Attempt to re-open a connection with the remote endpoint. + */ +static void +etm_reconnect(fmd_hdl_t *hdl, etm_epmap_t *mp) +{ + if ((mp->epm_reconn_end > 0) && (mp->epm_cstat == C_UNINITIALIZED)) { + if (gethrtime() < mp->epm_reconn_end) { + if ((mp->epm_oconn = etm_xport_open(hdl, + mp->epm_tlhdl)) == NULL) { + fmd_hdl_debug(hdl, "reconnect failed for %s", + mp->epm_ep_str); + mp->epm_timer_id = fmd_timer_install(hdl, mp, + NULL, Reconn_interval); + mp->epm_timer_in_use = 1; + } else { + fmd_hdl_debug(hdl, "reconnect success for %s", + mp->epm_ep_str); + mp->epm_reconn_end = 0; + mp->epm_cstat = C_OPEN; + } + } else { + fmd_hdl_error(hdl, "Reconnect timed out for %s\n", + mp->epm_ep_str); + mp->epm_reconn_end = 0; + mp->epm_cstat = C_TIMED_OUT; + } + } + + if (mp->epm_cstat == C_OPEN) { + fmd_xprt_resume(hdl, mp->epm_xprthdl); + mp->epm_qstat = Q_OPEN; + fmd_hdl_debug(hdl, "queue resumed for %s", mp->epm_ep_str); + } +} + +/* + * Suspend a given connection and setup for reconnection retries. + */ +static void +etm_suspend_reconnect(fmd_hdl_t *hdl, etm_epmap_t *mp) +{ + (void) pthread_mutex_lock(&Etm_mod_lock); + if (Etm_exit) { + (void) pthread_mutex_unlock(&Etm_mod_lock); + return; + } + (void) pthread_mutex_unlock(&Etm_mod_lock); + + (void) pthread_mutex_lock(&mp->epm_lock); + + if (mp->epm_oconn != NULL) { + (void) etm_xport_close(hdl, mp->epm_oconn); + mp->epm_oconn = NULL; + } + + mp->epm_reconn_end = gethrtime() + Reconn_timeout; + mp->epm_cstat = C_UNINITIALIZED; + + if (mp->epm_xprthdl != NULL) { + fmd_xprt_suspend(hdl, mp->epm_xprthdl); + mp->epm_qstat = Q_SUSPENDED; + fmd_hdl_debug(hdl, "queue suspended for %s", mp->epm_ep_str); + + if (mp->epm_timer_in_use == 0) { + mp->epm_timer_id = fmd_timer_install(hdl, mp, NULL, + Reconn_interval); + mp->epm_timer_in_use = 1; + } + } + + (void) pthread_mutex_unlock(&mp->epm_lock); +} + +/* + * Reinitialize the connection. The old fmd_xprt_t handle must be + * removed/closed first. + * Assume caller holds lock on epm_lock. + */ +static void +etm_reinit(fmd_hdl_t *hdl, etm_epmap_t *mp) +{ + /* + * To avoid a deadlock, wait for etm_send to finish before + * calling fmd_xprt_close() + */ + while (mp->epm_txbusy) + (void) pthread_cond_wait(&mp->epm_tx_cv, &mp->epm_lock); + + if (mp->epm_xprthdl != NULL) { + fmd_xprt_close(hdl, mp->epm_xprthdl); + fmd_hdl_debug(hdl, "queue closed for %s", mp->epm_ep_str); + mp->epm_xprthdl = NULL; + /* mp->epm_ep_nvl is free'd in fmd_xprt_close */ + mp->epm_ep_nvl = NULL; + } + + if (mp->epm_timer_in_use) { + fmd_timer_remove(hdl, mp->epm_timer_id); + mp->epm_timer_in_use = 0; + } + + if (mp->epm_oconn != NULL) { + (void) etm_xport_close(hdl, mp->epm_oconn); + mp->epm_oconn = NULL; + } + + mp->epm_cstat = C_UNINITIALIZED; + mp->epm_qstat = Q_UNINITIALIZED; +} + +/* + * Receive data from ETM transport layer. + * Note : This is not the fmdo_recv entry point. + * + */ +static int +etm_recv(fmd_hdl_t *hdl, etm_xport_conn_t conn, etm_epmap_t *mp) +{ + size_t buflen, hdrlen; + void *buf; + char hbuf[ETM_HDRLEN]; + int hdrstat, rv; + + hdrlen = ETM_HDRLEN; + + if ((etm_xport_read(hdl, conn, Rw_timeout, hbuf, hdrlen)) != hdrlen) { + fmd_hdl_debug(hdl, "failed to read header from %s", + mp->epm_ep_str); + INCRSTAT(Etm_stats.error_read.fmds_value.ui64); + return (EIO); + } + + hdrstat = etm_check_hdr(hdl, mp, hbuf); + + switch (hdrstat) { + case ETM_HDR_INVALID: + (void) pthread_mutex_lock(&mp->epm_lock); + if (mp->epm_cstat == C_OPEN) + mp->epm_cstat = C_CLOSED; + (void) pthread_mutex_unlock(&mp->epm_lock); + + INCRSTAT(Etm_stats.error_read_badhdr.fmds_value.ui64); + rv = ECANCELED; + break; + + case ETM_HDR_BADTYPE: + case ETM_HDR_BADVERSION: + hdrlen = etm_create_hdr(hbuf, mp->epm_ver, ETM_HDR_NAK, 0); + + if ((etm_xport_write(hdl, conn, Rw_timeout, hbuf, + hdrlen)) != hdrlen) { + fmd_hdl_debug(hdl, "failed to write NAK to %s", + mp->epm_ep_str); + INCRSTAT(Etm_stats.error_write.fmds_value.ui64); + return (EIO); + } + + (void) pthread_mutex_lock(&mp->epm_lock); + mp->epm_cstat = C_LIMBO; + (void) pthread_mutex_unlock(&mp->epm_lock); + + INCRSTAT(Etm_stats.error_read_badhdr.fmds_value.ui64); + rv = ENOTSUP; + break; + + case ETM_HDR_C_HELLO: + /* Client is initiating a startup handshake */ + (void) pthread_mutex_lock(&mp->epm_lock); + etm_reinit(hdl, mp); + mp->epm_qstat = Q_INIT_PENDING; + (void) pthread_mutex_unlock(&mp->epm_lock); + + hdrlen = etm_create_hdr(hbuf, mp->epm_ver, ETM_HDR_S_HELLO, 0); + + if ((etm_xport_write(hdl, conn, Rw_timeout, hbuf, + hdrlen)) != hdrlen) { + fmd_hdl_debug(hdl, "failed to write S_HELLO to %s", + mp->epm_ep_str); + INCRSTAT(Etm_stats.error_write.fmds_value.ui64); + return (EIO); + } + + rv = 0; + break; + + case ETM_HDR_ACK: + (void) pthread_mutex_lock(&mp->epm_lock); + if (mp->epm_qstat == Q_INIT_PENDING) { + /* This is client's ACK from startup handshake */ + /* mp->epm_ep_nvl is free'd in fmd_xprt_close */ + if (mp->epm_ep_nvl == NULL) + (void) etm_get_ep_nvl(hdl, mp); + + /* + * Call fmd_xprt_open and fmd_xprt_setspecific with + * Etm_mod_lock held to avoid race with etm_send thread. + */ + (void) pthread_mutex_lock(&Etm_mod_lock); + if ((mp->epm_xprthdl = fmd_xprt_open(hdl, + mp->epm_xprtflags, mp->epm_ep_nvl, NULL)) == NULL) { + fmd_hdl_abort(hdl, "Failed to init xprthdl " + "for %s", mp->epm_ep_str); + } + fmd_xprt_setspecific(hdl, mp->epm_xprthdl, mp); + (void) pthread_mutex_unlock(&Etm_mod_lock); + + mp->epm_qstat = Q_OPEN; + (void) pthread_mutex_unlock(&mp->epm_lock); + fmd_hdl_debug(hdl, "queue open for %s", + mp->epm_ep_str); + } else { + (void) pthread_mutex_unlock(&mp->epm_lock); + fmd_hdl_debug(hdl, "protocol error, not expecting ACK " + "from %s\n", mp->epm_ep_str); + INCRSTAT(Etm_stats.error_protocol.fmds_value.ui64); + } + + rv = 0; + break; + + case ETM_HDR_SHUTDOWN: + fmd_hdl_debug(hdl, "received shutdown from %s", + mp->epm_ep_str); + + (void) pthread_mutex_lock(&mp->epm_lock); + + etm_reinit(hdl, mp); + + if (IS_CLIENT(mp)) { + /* + * A server shutdown is considered to be temporary. + * Prepare for reconnection. + */ + mp->epm_timer_id = fmd_timer_install(hdl, mp, NULL, + Reconn_interval); + + mp->epm_timer_in_use = 1; + } + + (void) pthread_mutex_unlock(&mp->epm_lock); + + rv = ECANCELED; + break; + + case ETM_HDR_MSG: + (void) pthread_mutex_lock(&mp->epm_lock); + if (mp->epm_qstat == Q_UNINITIALIZED) { + /* Peer (client) is unaware that we've restarted */ + (void) pthread_mutex_unlock(&mp->epm_lock); + hdrlen = etm_create_hdr(hbuf, mp->epm_ver, + ETM_HDR_S_RESTART, 0); + + if ((etm_xport_write(hdl, conn, Rw_timeout, hbuf, + hdrlen)) != hdrlen) { + fmd_hdl_debug(hdl, "failed to write S_RESTART " + "to %s", mp->epm_ep_str); + INCRSTAT(Etm_stats.error_write.fmds_value.ui64); + return (EIO); + } + + return (ECANCELED); + } + (void) pthread_mutex_unlock(&mp->epm_lock); + + buflen = etm_get_msglen(hbuf); + ALLOC_BUF(hdl, buf, buflen); + + if (etm_xport_read(hdl, conn, Rw_timeout, buf, + buflen) != buflen) { + fmd_hdl_debug(hdl, "failed to read message from %s", + mp->epm_ep_str); + FREE_BUF(hdl, buf, buflen); + INCRSTAT(Etm_stats.error_read.fmds_value.ui64); + return (EIO); + } + + INCRSTAT(Etm_stats.read_msg.fmds_value.ui64); + ADDSTAT(Etm_stats.read_bytes.fmds_value.ui64, buflen); + + etm_hex_dump(hdl, buf, buflen, 0); + + if (etm_post_msg(hdl, mp, buf, buflen)) { + INCRSTAT(Etm_stats.error_drop_read.fmds_value.ui64); + FREE_BUF(hdl, buf, buflen); + return (EIO); + } + + FREE_BUF(hdl, buf, buflen); + + hdrlen = etm_create_hdr(hbuf, mp->epm_ver, ETM_HDR_ACK, 0); + + if ((etm_xport_write(hdl, conn, Rw_timeout, hbuf, + hdrlen)) != hdrlen) { + fmd_hdl_debug(hdl, "failed to write ACK to %s", + mp->epm_ep_str); + INCRSTAT(Etm_stats.error_write.fmds_value.ui64); + return (EIO); + } + + INCRSTAT(Etm_stats.write_ack.fmds_value.ui64); + + /* + * If we got this far and the current state of the + * outbound/sending connection is TIMED_OUT or + * LIMBO, then we should reinitialize it. + */ + (void) pthread_mutex_lock(&mp->epm_lock); + if (mp->epm_cstat == C_TIMED_OUT || + mp->epm_cstat == C_LIMBO) { + if (mp->epm_oconn != NULL) { + (void) etm_xport_close(hdl, mp->epm_oconn); + mp->epm_oconn = NULL; + } + mp->epm_cstat = C_UNINITIALIZED; + fmd_xprt_resume(hdl, mp->epm_xprthdl); + if (mp->epm_timer_in_use) { + fmd_timer_remove(hdl, mp->epm_timer_id); + mp->epm_timer_in_use = 0; + } + mp->epm_qstat = Q_OPEN; + fmd_hdl_debug(hdl, "queue resumed for %s", + mp->epm_ep_str); + } + (void) pthread_mutex_unlock(&mp->epm_lock); + + rv = 0; + break; + + default: + fmd_hdl_debug(hdl, "protocol error, unexpected header " + "from %s : %d", mp->epm_ep_str, hdrstat); + INCRSTAT(Etm_stats.error_protocol.fmds_value.ui64); + rv = 0; + } + + return (rv); +} + +/* + * ETM transport layer callback function. + * The transport layer calls this function to : + * (a) pass an incoming message (flag == ETM_CBFLAG_RECV) + * (b) tell us to reinitialize the connection (flag == ETM_CBFLAG_REINIT) + */ +static int +etm_cb_func(fmd_hdl_t *hdl, etm_xport_conn_t conn, etm_cb_flag_t flag, + void *arg) +{ + etm_epmap_t *mp = (etm_epmap_t *)arg; + int rv = 0; + + (void) pthread_mutex_lock(&Etm_mod_lock); + if (Etm_exit) { + (void) pthread_mutex_unlock(&Etm_mod_lock); + return (ECANCELED); + } + (void) pthread_mutex_unlock(&Etm_mod_lock); + + switch (flag) { + case ETM_CBFLAG_RECV: + rv = etm_recv(hdl, conn, mp); + break; + case ETM_CBFLAG_REINIT: + (void) pthread_mutex_lock(&mp->epm_lock); + etm_reinit(hdl, mp); + (void) pthread_mutex_unlock(&mp->epm_lock); + /* + * Return ECANCELED so the transport layer will close the + * server connection. The transport layer is responsible for + * reestablishing this connection (should a connection request + * arrive from the peer). + */ + rv = ECANCELED; + break; + default: + fmd_hdl_debug(hdl, "Unknown callback flag : 0x%x", flag); + rv = ENOTSUP; + } + + return (rv); +} + +/* + * Allocate and initialize an etm_epmap_t struct for the given endpoint + * name string. + */ +static void +etm_init_epmap(fmd_hdl_t *hdl, char *epname, int flags) +{ + etm_epmap_t *newmap; + + if (etm_check_dup_ep_str(hdl, epname)) { + fmd_hdl_debug(hdl, "skipping duplicate peer : %s", epname); + return; + } + + newmap = fmd_hdl_zalloc(hdl, sizeof (etm_epmap_t), FMD_SLEEP); + newmap->epm_ep_str = fmd_hdl_strdup(hdl, epname, FMD_SLEEP); + newmap->epm_xprtflags = flags; + newmap->epm_cstat = C_UNINITIALIZED; + newmap->epm_qstat = Q_UNINITIALIZED; + newmap->epm_ver = ETM_PROTO_V1; /* Currently support one proto ver */ + newmap->epm_txbusy = 0; + + (void) pthread_mutex_init(&newmap->epm_lock, NULL); + (void) pthread_cond_init(&newmap->epm_tx_cv, NULL); + + if (etm_get_ep_nvl(hdl, newmap)) { + fmd_hdl_strfree(hdl, newmap->epm_ep_str); + fmd_hdl_free(hdl, newmap, sizeof (etm_epmap_t)); + return; + } + + if ((newmap->epm_tlhdl = etm_xport_init(hdl, newmap->epm_ep_str, + etm_cb_func, newmap)) == NULL) { + fmd_hdl_debug(hdl, "failed to init tlhdl for %s\n", + newmap->epm_ep_str); + etm_free_ep_nvl(hdl, newmap); + fmd_hdl_strfree(hdl, newmap->epm_ep_str); + fmd_hdl_free(hdl, newmap, sizeof (etm_epmap_t)); + return; + } + + if (IS_CLIENT(newmap)) { + if (etm_handle_startup(hdl, newmap)) { + etm_free_ep_nvl(hdl, newmap); + (void) etm_xport_fini(hdl, newmap->epm_tlhdl); + fmd_hdl_strfree(hdl, newmap->epm_ep_str); + fmd_hdl_free(hdl, newmap, sizeof (etm_epmap_t)); + return; + } + } + + /* Add this transport instance handle to the list */ + newmap->epm_next = Epmap_head; + Epmap_head = newmap; + + INCRSTAT(Etm_stats.peer_count.fmds_value.ui64); +} + +/* + * Parse the given property list string and call etm_init_epmap + * for each endpoint. + */ +static void +etm_create_epmaps(fmd_hdl_t *hdl, char *eplist, int flags) +{ + char *epstr, *ep, *prefix, *lasts, *numstr; + char epname[MAXPATHLEN]; + size_t slen, nlen; + int beg, end, i; + + if (eplist == NULL) + return; + /* + * Create a copy of eplist for parsing. + * strtok/strtok_r(3C) will insert null chars to the string. + * Therefore, fmd_hdl_strdup/fmd_hdl_strfree cannot be used. + */ + slen = strlen(eplist); + epstr = fmd_hdl_zalloc(hdl, slen + 1, FMD_SLEEP); + (void) strcpy(epstr, eplist); + + /* + * The following are supported for the "client_list" and + * "server_list" properties : + * + * A space-separated list of endpoints. + * "dev:///dom0 dev:///dom1 dev:///dom2" + * + * An array syntax for a range of instances. + * "dev:///dom[0:2]" + * + * A combination of both. + * "dev:///dom0 dev:///dom[1:2]" + */ + ep = strtok_r(epstr, " ", &lasts); + while (ep != NULL) { + if (strchr(ep, '[') != NULL) { + /* + * This string is using array syntax. + * Check the string for correct syntax. + */ + if ((strchr(ep, ':') == NULL) || + (strchr(ep, ']') == NULL)) { + fmd_hdl_error(hdl, "Syntax error in property " + "that includes : %s\n", ep); + ep = strtok_r(NULL, " ", &lasts); + continue; + } + + /* expand the array syntax */ + prefix = strtok(ep, "["); + + numstr = strtok(NULL, ":"); + if ((numstr == NULL) || (!isdigit(*numstr))) { + fmd_hdl_error(hdl, "Syntax error in property " + "that includes : %s[\n", prefix); + ep = strtok_r(NULL, " ", &lasts); + continue; + } + beg = atoi(numstr); + + numstr = strtok(NULL, "]"); + if ((numstr == NULL) || (!isdigit(*numstr))) { + fmd_hdl_error(hdl, "Syntax error in property " + "that includes : %s[\n", prefix); + ep = strtok_r(NULL, " ", &lasts); + continue; + } + end = atoi(numstr); + + nlen = strlen(prefix) + ETM_EP_INST_MAX; + + if (nlen > MAXPATHLEN) { + fmd_hdl_error(hdl, "Endpoint prop string " + "exceeds MAXPATHLEN\n"); + ep = strtok_r(NULL, " ", &lasts); + continue; + } + + for (i = beg; i <= end; i++) { + bzero(epname, MAXPATHLEN); + (void) snprintf(epname, nlen, "%s%d", + prefix, i); + etm_init_epmap(hdl, epname, flags); + } + } else { + etm_init_epmap(hdl, ep, flags); + } + + ep = strtok_r(NULL, " ", &lasts); + } + + fmd_hdl_free(hdl, epstr, slen + 1); +} + +/* + * Free the transport infrastructure for an endpoint. + */ +static void +etm_free_epmap(fmd_hdl_t *hdl, etm_epmap_t *mp) +{ + size_t hdrlen; + char hbuf[ETM_HDRLEN]; + + (void) pthread_mutex_lock(&mp->epm_lock); + + /* + * If an etm_send thread is in progress, wait for it to finish. + * The etm_recv thread is managed by the transport layer and will + * be destroyed with etm_xport_fini(). + */ + while (mp->epm_txbusy) + (void) pthread_cond_wait(&mp->epm_tx_cv, &mp->epm_lock); + + if (mp->epm_timer_in_use) + fmd_timer_remove(hdl, mp->epm_timer_id); + + if (mp->epm_oconn != NULL) { + hdrlen = etm_create_hdr(hbuf, mp->epm_ver, + ETM_HDR_SHUTDOWN, 0); + (void) etm_xport_write(hdl, mp->epm_oconn, Rw_timeout, hbuf, + hdrlen); + (void) etm_xport_close(hdl, mp->epm_oconn); + mp->epm_oconn = NULL; + } + + if (mp->epm_xprthdl != NULL) { + fmd_xprt_close(hdl, mp->epm_xprthdl); + /* mp->epm_ep_nvl is free'd in fmd_xprt_close */ + mp->epm_ep_nvl = NULL; + } + + if (mp->epm_ep_nvl != NULL) + etm_free_ep_nvl(hdl, mp); + + if (mp->epm_tlhdl != NULL) + (void) etm_xport_fini(hdl, mp->epm_tlhdl); + + (void) pthread_mutex_unlock(&mp->epm_lock); + (void) pthread_mutex_destroy(&mp->epm_lock); + fmd_hdl_strfree(hdl, mp->epm_ep_str); + fmd_hdl_free(hdl, mp, sizeof (etm_epmap_t)); + DECRSTAT(Etm_stats.peer_count.fmds_value.ui64); +} + +/* + * FMD entry points + */ + +/* + * FMD fmdo_send entry point. + * Send an event to the remote endpoint and receive an ACK. + */ +static int +etm_send(fmd_hdl_t *hdl, fmd_xprt_t *xprthdl, fmd_event_t *ep, nvlist_t *nvl) +{ + etm_epmap_t *mp; + nvlist_t *msgnvl; + int hdrstat, rv; + char *buf, *nvbuf, *class; + size_t nvsize, buflen, hdrlen; + + (void) pthread_mutex_lock(&Etm_mod_lock); + if (Etm_exit) { + (void) pthread_mutex_unlock(&Etm_mod_lock); + return (FMD_SEND_RETRY); + } + (void) pthread_mutex_unlock(&Etm_mod_lock); + + mp = fmd_xprt_getspecific(hdl, xprthdl); + + (void) pthread_mutex_lock(&mp->epm_lock); + + mp->epm_txbusy++; + + if (mp->epm_cstat == C_CLOSED) { + mp->epm_txbusy--; + (void) pthread_mutex_unlock(&mp->epm_lock); + (void) pthread_cond_broadcast(&mp->epm_tx_cv); + etm_suspend_reconnect(hdl, mp); + return (FMD_SEND_RETRY); + } + + if (mp->epm_cstat == C_LIMBO) { + if (mp->epm_oconn != NULL) { + (void) etm_xport_close(hdl, mp->epm_oconn); + mp->epm_oconn = NULL; + } + + fmd_xprt_suspend(hdl, xprthdl); + mp->epm_qstat = Q_SUSPENDED; + mp->epm_txbusy--; + (void) pthread_mutex_unlock(&mp->epm_lock); + (void) pthread_cond_broadcast(&mp->epm_tx_cv); + fmd_hdl_debug(hdl, "queue suspended for %s", mp->epm_ep_str); + return (FMD_SEND_RETRY); + } + + if (mp->epm_oconn == NULL) { + if ((mp->epm_oconn = etm_xport_open(hdl, mp->epm_tlhdl)) + == NULL) { + mp->epm_txbusy--; + (void) pthread_mutex_unlock(&mp->epm_lock); + (void) pthread_cond_broadcast(&mp->epm_tx_cv); + etm_suspend_reconnect(hdl, mp); + return (FMD_SEND_RETRY); + } else { + mp->epm_cstat = C_OPEN; + } + } + + if (nvlist_lookup_string(nvl, FM_CLASS, &class) != 0) + fmd_hdl_abort(hdl, "No class string in nvlist"); + + msgnvl = fmd_xprt_translate(hdl, xprthdl, ep); + if (msgnvl == NULL) { + mp->epm_qstat = Q_UNINITIALIZED; + (void) pthread_mutex_unlock(&mp->epm_lock); + fmd_hdl_error(hdl, "Failed to translate event %p\n", + (void *) ep); + return (FMD_SEND_FAILED); + } + + (void) pthread_mutex_unlock(&mp->epm_lock); + + (void) nvlist_size(msgnvl, &nvsize, NV_ENCODE_XDR); + + hdrlen = ETM_HDRLEN; + buflen = nvsize + hdrlen; + + ALLOC_BUF(hdl, buf, buflen); + + nvbuf = buf + hdrlen; + + (void) etm_create_hdr(buf, mp->epm_ver, ETM_HDR_MSG, nvsize); + + if (rv = nvlist_pack(msgnvl, &nvbuf, &nvsize, NV_ENCODE_XDR, 0)) { + fmd_hdl_error(hdl, "Failed to pack event : %s\n", strerror(rv)); + FREE_BUF(hdl, buf, buflen); + return (FMD_SEND_FAILED); + } + + nvlist_free(msgnvl); + + if (etm_xport_write(hdl, mp->epm_oconn, Rw_timeout, buf, + buflen) != buflen) { + (void) pthread_mutex_lock(&mp->epm_lock); + mp->epm_txbusy--; + (void) pthread_mutex_unlock(&mp->epm_lock); + (void) pthread_cond_broadcast(&mp->epm_tx_cv); + fmd_hdl_debug(hdl, "failed to send message to %s", + mp->epm_ep_str); + FREE_BUF(hdl, buf, buflen); + INCRSTAT(Etm_stats.error_write.fmds_value.ui64); + etm_suspend_reconnect(hdl, mp); + return (FMD_SEND_RETRY); + } + + INCRSTAT(Etm_stats.write_msg.fmds_value.ui64); + ADDSTAT(Etm_stats.write_bytes.fmds_value.ui64, nvsize); + + etm_hex_dump(hdl, nvbuf, nvsize, 1); + + if (etm_xport_read(hdl, mp->epm_oconn, Rw_timeout, buf, + hdrlen) != hdrlen) { + (void) pthread_mutex_lock(&mp->epm_lock); + mp->epm_txbusy--; + (void) pthread_mutex_unlock(&mp->epm_lock); + (void) pthread_cond_broadcast(&mp->epm_tx_cv); + fmd_hdl_debug(hdl, "failed to read ACK from %s", + mp->epm_ep_str); + FREE_BUF(hdl, buf, buflen); + INCRSTAT(Etm_stats.error_read.fmds_value.ui64); + etm_suspend_reconnect(hdl, mp); + return (FMD_SEND_RETRY); + } + + hdrstat = etm_check_hdr(hdl, mp, buf); + FREE_BUF(hdl, buf, buflen); + + if (hdrstat == ETM_HDR_ACK) { + INCRSTAT(Etm_stats.read_ack.fmds_value.ui64); + } else { + (void) pthread_mutex_lock(&mp->epm_lock); + + (void) etm_xport_close(hdl, mp->epm_oconn); + mp->epm_oconn = NULL; + + if (hdrstat == ETM_HDR_NAK) { + /* Peer received a bad value in the header */ + if (mp->epm_xprthdl != NULL) { + mp->epm_cstat = C_LIMBO; + fmd_xprt_suspend(hdl, xprthdl); + mp->epm_qstat = Q_SUSPENDED; + fmd_hdl_debug(hdl, "received NAK, queue " + "suspended for %s", mp->epm_ep_str); + } + + rv = FMD_SEND_RETRY; + + } else if (hdrstat == ETM_HDR_S_RESTART) { + /* Server has restarted */ + if (mp->epm_xprthdl != NULL) { + mp->epm_cstat = C_CLOSED; + fmd_xprt_close(hdl, xprthdl); + /* mp->epm_ep_nvl is free'd in fmd_xprt_close */ + mp->epm_ep_nvl = NULL; + mp->epm_qstat = Q_UNINITIALIZED; + fmd_hdl_debug(hdl, "server restarted, queue " + "closed for %s", mp->epm_ep_str); + if (mp->epm_timer_in_use == 0) { + mp->epm_timer_id = fmd_timer_install( + hdl, mp, NULL, Reconn_interval); + mp->epm_timer_in_use = 1; + } + } + + /* + * fault.* or list.* events will be replayed if a + * transport is opened with the same auth. + * Other events will be discarded. + */ + rv = FMD_SEND_FAILED; + + } else { + mp->epm_cstat = C_CLOSED; + fmd_hdl_debug(hdl, "bad ACK from %s", mp->epm_ep_str); + + rv = FMD_SEND_RETRY; + } + + mp->epm_txbusy--; + (void) pthread_mutex_unlock(&mp->epm_lock); + + (void) pthread_cond_broadcast(&mp->epm_tx_cv); + + INCRSTAT(Etm_stats.error_read_badhdr.fmds_value.ui64); + + return (rv); + } + + (void) pthread_mutex_lock(&mp->epm_lock); + mp->epm_txbusy--; + (void) pthread_mutex_unlock(&mp->epm_lock); + + (void) pthread_cond_broadcast(&mp->epm_tx_cv); + + return (FMD_SEND_SUCCESS); +} + +/* + * FMD fmdo_timeout entry point.. + */ +/*ARGSUSED*/ +static void +etm_timeout(fmd_hdl_t *hdl, id_t id, void *data) +{ + etm_epmap_t *mp = (etm_epmap_t *)data; + + (void) pthread_mutex_lock(&mp->epm_lock); + + mp->epm_timer_in_use = 0; + + if (mp->epm_qstat == Q_UNINITIALIZED) { + /* Server has shutdown and we (client) need to reconnect */ + if (mp->epm_ep_nvl == NULL) + (void) etm_get_ep_nvl(hdl, mp); + + if (etm_handle_startup(hdl, mp)) { + mp->epm_qstat = Q_UNINITIALIZED; + mp->epm_timer_id = fmd_timer_install(hdl, mp, NULL, + Reconn_interval); + mp->epm_timer_in_use = 1; + } + } else { + etm_reconnect(hdl, mp); + } + + (void) pthread_mutex_unlock(&mp->epm_lock); +} + +/* + * FMD Module declarations + */ +static const fmd_hdl_ops_t etm_ops = { + NULL, /* fmdo_recv */ + etm_timeout, /* fmdo_timeout */ + NULL, /* fmdo_close */ + NULL, /* fmdo_stats */ + NULL, /* fmdo_gc */ + etm_send, /* fmdo_send */ +}; + +static const fmd_prop_t etm_props[] = { + { "client_list", FMD_TYPE_STRING, NULL }, + { "server_list", FMD_TYPE_STRING, NULL }, + { "reconnect_interval", FMD_TYPE_UINT64, "10000000000" }, + { "reconnect_timeout", FMD_TYPE_UINT64, "300000000000"}, + { "rw_timeout", FMD_TYPE_UINT64, "2000000000"}, + { NULL, 0, NULL } +}; + +static const fmd_hdl_info_t etm_info = { + "Event Transport Module", "2.0", &etm_ops, etm_props +}; + +/* + * Initialize the transport for use by ETM. + */ +void +_fmd_init(fmd_hdl_t *hdl) +{ + char *propstr; + + if (fmd_hdl_register(hdl, FMD_API_VERSION, &etm_info) != 0) { + return; /* invalid data in configuration file */ + } + + /* Create global stats */ + (void) fmd_stat_create(hdl, FMD_STAT_NOALLOC, + sizeof (Etm_stats) / sizeof (fmd_stat_t), (fmd_stat_t *)&Etm_stats); + + /* Get module properties */ + Reconn_timeout = fmd_prop_get_int64(hdl, "reconnect_timeout"); + Reconn_interval = fmd_prop_get_int64(hdl, "reconnect_interval"); + Rw_timeout = fmd_prop_get_int64(hdl, "rw_timeout"); + + propstr = fmd_prop_get_string(hdl, "client_list"); + etm_create_epmaps(hdl, propstr, ETM_SERVER_XPRT_FLAGS); + fmd_prop_free_string(hdl, propstr); + + propstr = fmd_prop_get_string(hdl, "server_list"); + etm_create_epmaps(hdl, propstr, ETM_CLIENT_XPRT_FLAGS); + fmd_prop_free_string(hdl, propstr); + + if (Etm_stats.peer_count.fmds_value.ui64 == 0) { + fmd_hdl_debug(hdl, "Failed to init any endpoint\n"); + fmd_hdl_unregister(hdl); + return; + } +} + +/* + * Teardown the transport + */ +void +_fmd_fini(fmd_hdl_t *hdl) +{ + etm_epmap_t *mp, *next; + + (void) pthread_mutex_lock(&Etm_mod_lock); + Etm_exit = 1; + (void) pthread_mutex_unlock(&Etm_mod_lock); + + mp = Epmap_head; + + while (mp) { + next = mp->epm_next; + etm_free_epmap(hdl, mp); + mp = next; + } + + fmd_hdl_unregister(hdl); +} diff --git a/usr/src/cmd/fm/modules/common/event-transport/etm_proto.h b/usr/src/cmd/fm/modules/common/event-transport/etm_proto.h new file mode 100644 index 0000000000..128aa16cce --- /dev/null +++ b/usr/src/cmd/fm/modules/common/event-transport/etm_proto.h @@ -0,0 +1,76 @@ +/* + * 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. + */ + +/* + * FMA ETM-to-ETM Protocol header + * + * const/type defns for protocol used between two event transport + * modules (ETMs) + */ + +#ifndef _ETM_PROTO_H +#define _ETM_PROTO_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +#include <sys/types.h> + +#define ETM_DELIM "\177ETM" /* Start of header delimiter */ +#define ETM_DELIMLEN 4 /* Length of header deimiter */ + +typedef struct etm_proto_header { + char hdr_delim[ETM_DELIMLEN]; /* Start of header delimiter */ + uint8_t hdr_ver; /* ETM protocol version */ + uint8_t hdr_type; /* Header type */ + uint8_t hdr_pad1; /* reserved/padding/alignment */ + uint8_t hdr_pad2; /* reserved/padding/alignment */ + uint32_t hdr_msglen; /* Length of following message */ +} etm_proto_hdr_t; + +typedef enum etm_proto_header_type { + ETM_HDR_TYPE_TOO_LOW = 0, /* Range check place holder */ + ETM_HDR_MSG, /* FMA event to follow */ + ETM_HDR_S_RESTART, /* Server re-start indication */ + ETM_HDR_C_HELLO, /* Client startup indication */ + ETM_HDR_S_HELLO, /* Server response to C_HELLO */ + ETM_HDR_ACK, /* Acknowledgement */ + ETM_HDR_NAK, /* Negative acknowledgement */ + ETM_HDR_SHUTDOWN, /* Notify remote ETM of shutdown */ + ETM_HDR_TYPE_TOO_HIGH /* Range check place holder */ +} etm_proto_hdr_type_t; + +#define ETM_HDRLEN sizeof (etm_proto_hdr_t) +#define ETM_PROTO_V1 1 + +#ifdef __cplusplus +} +#endif + +#endif /* _ETM_PROTO_H */ diff --git a/usr/src/cmd/fm/modules/common/event-transport/etm_xport_api.h b/usr/src/cmd/fm/modules/common/event-transport/etm_xport_api.h new file mode 100644 index 0000000000..c4d5c233c6 --- /dev/null +++ b/usr/src/cmd/fm/modules/common/event-transport/etm_xport_api.h @@ -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 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* + * FMA ETM-to-Transport API header + * + * const/type defns for transporting data between an Event Transport + * Module (ETM) and its associated Transport Layer within a fault domain. + */ + +#ifndef _ETM_XPORT_API_H +#define _ETM_XPORT_API_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +#include <fm/fmd_api.h> + +typedef void* etm_xport_hdl_t; /* transport instance handle */ +typedef void* etm_xport_conn_t; /* transport connection handle */ + +typedef enum etm_callback_flag { + ETM_CBFLAG_REINIT, /* reinitialize connection */ + ETM_CBFLAG_RECV /* receive message */ +} etm_cb_flag_t; + +/* + * Connection Management + */ + +/* + * Initialize/setup transport instance before any connections are opened. + * Return transport instance handle if successful, or NULL for failure. + */ +etm_xport_hdl_t +etm_xport_init(fmd_hdl_t *hdl, char *endpoint_id, + int (*cb_func)(fmd_hdl_t *hdl, etm_xport_conn_t conn, etm_cb_flag_t flag, + void *arg), void *cb_func_arg); + +/* + * Callback function provided to etm_xport_init(). + * This function is called by the transport layer to notify the common layer + * that action is required (receive a message, reinitialize a connection, etc.). + * Return zero for success. + * For any non-zero return value, the connection should be closed. + */ +int +etm_xport_cb_func(fmd_hdl_t *hdl, etm_xport_conn_t conn, etm_cb_flag_t flag, + void *arg); + +/* + * Finish/teardown any transport infrastructure. + * Return zero if successful, or nonzero for failure. + */ +int +etm_xport_fini(fmd_hdl_t *hdl, etm_xport_hdl_t tlhdl); + +/* + * Open a connection with the given endpoint. + * Return the transport connection handle if successful, or NULL for failure. + */ +etm_xport_conn_t +etm_xport_open(fmd_hdl_t *hdl, etm_xport_hdl_t tlhdl); + +/* + * Close a connection. + * Return zero if successful, or nonzero for failure. + */ +int +etm_xport_close(fmd_hdl_t *hdl, etm_xport_conn_t conn); + +/* + * Input/Output + */ + +/* + * Try to read byte_cnt bytes from the connection into the given buffer. + * Return number of bytes successfully read, or a value < 0 for failure. + */ +ssize_t +etm_xport_read(fmd_hdl_t *hdl, etm_xport_conn_t conn, hrtime_t timeout, + void *buf, size_t byte_cnt); + +/* + * Try to write byte_cnt bytes to the connection from the given buffer. + * Return number of bytes successfully written, or a value < 0 for failure. + */ +ssize_t +etm_xport_write(fmd_hdl_t *hdl, etm_xport_conn_t conn, hrtime_t timeout, + void *buf, size_t byte_cnt); + +#ifdef __cplusplus +} +#endif + +#endif /* _ETM_XPORT_API_H */ diff --git a/usr/src/cmd/fm/modules/sun4/cpumem-diagnosis/cmd_cpu.c b/usr/src/cmd/fm/modules/sun4/cpumem-diagnosis/cmd_cpu.c index 159825e531..2574a0debb 100644 --- a/usr/src/cmd/fm/modules/sun4/cpumem-diagnosis/cmd_cpu.c +++ b/usr/src/cmd/fm/modules/sun4/cpumem-diagnosis/cmd_cpu.c @@ -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. @@ -48,6 +47,15 @@ #include <sys/async.h> #include <sys/fm/protocol.h> +#ifdef sun4u +#include <sys/cheetahregs.h> +#include <sys/fm/cpu/UltraSPARC-III.h> +#include <cmd_opl.h> +#else /* sun4u */ +#include <sys/niagararegs.h> +#include <sys/fm/cpu/UltraSPARC-T1.h> +#endif /* sun4u */ + #define CMD_CPU_UEC_INCR 10 #define CPU_FRU_FMRI FM_FMRI_SCHEME_HC":///" \ FM_FMRI_LEGACY_HC"=" @@ -61,7 +69,18 @@ static const char *const cpu_names[] = { "ultraSPARC-IV", "ultraSPARC-IVplus", "ultraSPARC-IIIiplus", - "ultraSPARC-T1" + "ultraSPARC-T1", + "SPARC64-VI" +}; + +/* + * This needs to be in sync with cpu_family_t. + */ +static const faminfo_t fam_info_tbl[] = { + { CMD_CPU_FAM_UNSUPPORTED, B_FALSE }, + { CMD_CPU_FAM_CHEETAH, B_TRUE }, + { CMD_CPU_FAM_NIAGARA, B_FALSE }, + { CMD_CPU_FAM_SPARC64, B_FALSE } }; static cmd_cpu_t *cpu_lookup_by_cpuid(uint32_t); @@ -686,7 +705,7 @@ cpu_lookup_by_cpuid(uint32_t cpuid) return (NULL); } -static char * +char * cpu_getfrustr(fmd_hdl_t *hdl, uint32_t cpuid) { kstat_named_t *kn; @@ -904,7 +923,7 @@ cpu_create(fmd_hdl_t *hdl, nvlist_t *asru, uint32_t cpuid, cmd_cpu_type_t type) * residing at the indicated cpuid are the same. We do this by comparing the * serial IDs from the three entities. */ -static cmd_cpu_t * +cmd_cpu_t * cmd_cpu_lookup(fmd_hdl_t *hdl, nvlist_t *asru, const char *class) { cmd_cpu_t *cpu; @@ -1331,7 +1350,8 @@ typedef struct { static famdata_t famdata_tbl[] = { {"UltraSPARC-III", CMD_CPU_FAM_CHEETAH}, {"UltraSPARC-IV", CMD_CPU_FAM_CHEETAH}, - {"UltraSPARC-T", CMD_CPU_FAM_NIAGARA} + {"UltraSPARC-T", CMD_CPU_FAM_NIAGARA}, + {"SPARC64-VI", CMD_CPU_FAM_SPARC64} }; cpu_family_t @@ -1385,3 +1405,66 @@ cmd_cpu_check_support(void) (void) kstat_close(kc); return (CMD_CPU_FAM_UNSUPPORTED); } + +boolean_t +cmd_cpu_ecache_support(void) +{ + cpu_family_t value; + + value = cmd_cpu_check_support(); + return (fam_info_tbl[value].ecache_flush_needed); +} + +/* + * This is derived from "cmd_cpu_lookup()". + * The difference here is that it does not do + * "fmd_nvl_fmri_expand" since these are for the sibling CPUs. + * They are not part of the original fmri page. + */ +cmd_cpu_t * +cmd_sibcpu_lookup(fmd_hdl_t *hdl, nvlist_t *asru, const char *class) +{ + cmd_cpu_t *cpu; + uint8_t vers; + const char *scheme; + uint32_t cpuid; + + if (nvlist_lookup_pairs(asru, 0, + FM_VERSION, DATA_TYPE_UINT8, &vers, + FM_FMRI_SCHEME, DATA_TYPE_STRING, &scheme, + FM_FMRI_CPU_ID, DATA_TYPE_UINT32, &cpuid, + NULL) != 0 || (vers != CPU_SCHEME_VERSION0 && + vers != CPU_SCHEME_VERSION1) || + strcmp(scheme, FM_FMRI_SCHEME_CPU) != 0) { + CMD_STAT_BUMP(bad_cpu_asru); + return (NULL); + } + + cpu = cpu_lookup_by_cpuid(cpuid); + + if (cpu != NULL && (!fmd_nvl_fmri_present(hdl, cpu->cpu_asru_nvl) || + fmd_nvl_fmri_unusable(hdl, cpu->cpu_asru_nvl))) { + fmd_hdl_debug(hdl, "sibcpu_lookup: discarding old state\n"); + cmd_cpu_destroy(hdl, cpu); + cpu = NULL; + } + + /* + * Check to see if the CPU described by the ereport has been removed + * from the system. If it has, return to the caller without a CPU. + */ + if (!fmd_nvl_fmri_present(hdl, asru) || + fmd_nvl_fmri_unusable(hdl, asru)) { + fmd_hdl_debug(hdl, "sibcpu_lookup: discarding old ereport\n"); + return (NULL); + } + + if (cpu == NULL) { + const char *cpuname = class + sizeof ("ereport.cpu"); + + cpu = cpu_create(hdl, asru, cpuid, cpu_nname2type(hdl, cpuname, + (size_t)(strchr(cpuname, '.') - cpuname))); + } + + return (cpu); +} diff --git a/usr/src/cmd/fm/modules/sun4/cpumem-diagnosis/cmd_cpu.h b/usr/src/cmd/fm/modules/sun4/cpumem-diagnosis/cmd_cpu.h index cf12bc81c2..e37dfb0c7f 100644 --- a/usr/src/cmd/fm/modules/sun4/cpumem-diagnosis/cmd_cpu.h +++ b/usr/src/cmd/fm/modules/sun4/cpumem-diagnosis/cmd_cpu.h @@ -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,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -83,14 +82,6 @@ #include <cmd_state.h> #include <cmd_fmri.h> -#ifdef sun4u -#include <sys/cheetahregs.h> -#include <sys/fm/cpu/UltraSPARC-III.h> -#else /* sun4u */ -#include <sys/niagararegs.h> -#include <sys/fm/cpu/UltraSPARC-T1.h> -#endif /* sun4u */ - #ifdef __cplusplus extern "C" { #endif @@ -104,7 +95,8 @@ typedef enum cmd_cpu_type { CPU_ULTRASPARC_IV, CPU_ULTRASPARC_IVplus, CPU_ULTRASPARC_IIIiplus, - CPU_ULTRASPARC_T1 + CPU_ULTRASPARC_T1, + CPU_SPARC64_VI } cmd_cpu_type_t; typedef struct cmd_cpu_cases { @@ -122,6 +114,27 @@ typedef struct cmd_cpu_cases { cmd_case_t cpuc_freg; /* Floatpnt reg errors (frc, fru) */ cmd_case_t cpuc_mau; /* Modular arith errors (MAU) */ cmd_case_t cpuc_l2ctl; /* L2$ directory, VUAD parity */ + cmd_case_t cpuc_opl_inv_sfsr; /* Olympus-C cpu inv-sfsr errors */ + cmd_case_t cpuc_opl_ue_det_cpu; /* Olympus-C cpu det. ue (eid=CPU) */ + cmd_case_t cpuc_opl_ue_det_io; /* Olympus-C io det. ue (eid=CPU) */ + cmd_case_t cpuc_opl_mtlb; /* Olympus-C mtlb errors */ + cmd_case_t cpuc_opl_tlbp; /* Olympus-C tlbp errors */ + cmd_case_t cpuc_opl_inv_urg; /* Olympus-C inv-urg invalid urgent */ + cmd_case_t cpuc_opl_cre; /* Olympus-C cre urgent errors */ + cmd_case_t cpuc_opl_tsb_ctx; /* Olympus-C tsb_ctx urgent errors */ + cmd_case_t cpuc_opl_tsbp; /* Olympus-C tsbp urgent errors */ + cmd_case_t cpuc_opl_pstate; /* Olympus-C pstate urgent errors */ + cmd_case_t cpuc_opl_tstate; /* Olympus-C tstate urgent errors */ + cmd_case_t cpuc_opl_iug_f; /* Olympus-C iug_f urgent errors */ + cmd_case_t cpuc_opl_iug_r; /* Olympus-C iug_r urgent errors */ + cmd_case_t cpuc_opl_sdc; /* Olympus-C sdc urgent errors */ + cmd_case_t cpuc_opl_wdt; /* Olympus-C wdt urgent errors */ + cmd_case_t cpuc_opl_dtlb; /* Olympus-C dtlb urgent errors */ + cmd_case_t cpuc_opl_itlb; /* Olympus-C itlb urgent errors */ + cmd_case_t cpuc_opl_core_err; /* Olympus-C core-err urgent errors */ + cmd_case_t cpuc_opl_dae; /* Olympus-C dae urgent errors */ + cmd_case_t cpuc_opl_iae; /* Olympus-C iae urgent errors */ + cmd_case_t cpuc_opl_uge; /* Olympus-C uge urgent errors */ } cmd_cpu_cases_t; /* @@ -384,6 +397,27 @@ struct cmd_cpu { #define cpu_freg cpu_cases.cpuc_freg #define cpu_mau cpu_cases.cpuc_mau #define cpu_l2ctl cpu_cases.cpuc_l2ctl +#define cpu_opl_inv_sfsr cpu_cases.cpuc_opl_inv_sfsr +#define cpu_opl_ue_det_cpu cpu_cases.cpuc_opl_ue_det_cpu +#define cpu_opl_ue_det_io cpu_cases.cpuc_opl_ue_det_io +#define cpu_opl_mtlb cpu_cases.cpuc_opl_mtlb +#define cpu_opl_tlbp cpu_cases.cpuc_opl_tlbp +#define cpu_opl_inv_urg cpu_cases.cpuc_opl_inv_urg +#define cpu_opl_cre cpu_cases.cpuc_opl_cre +#define cpu_opl_tsb_ctx cpu_cases.cpuc_opl_tsb_ctx +#define cpu_opl_tsbp cpu_cases.cpuc_opl_tsbp +#define cpu_opl_pstate cpu_cases.cpuc_opl_pstate +#define cpu_opl_tstate cpu_cases.cpuc_opl_tstate +#define cpu_opl_iug_f cpu_cases.cpuc_opl_iug_f +#define cpu_opl_iug_r cpu_cases.cpuc_opl_iug_r +#define cpu_opl_sdc cpu_cases.cpuc_opl_sdc +#define cpu_opl_wdt cpu_cases.cpuc_opl_wdt +#define cpu_opl_dtlb cpu_cases.cpuc_opl_dtlb +#define cpu_opl_itlb cpu_cases.cpuc_opl_itlb +#define cpu_opl_core_err cpu_cases.cpuc_opl_core_err +#define cpu_opl_dae cpu_cases.cpuc_opl_dae +#define cpu_opl_iae cpu_cases.cpuc_opl_iae +#define cpu_opl_uge cpu_cases.cpuc_opl_uge #define cpu_asru_nvl cpu_asru.fmri_nvl #define cpu_fru_nvl cpu_fru.fmri_nvl @@ -564,6 +598,10 @@ extern cmd_evdisp_t cmd_l2ctl(fmd_hdl_t *, fmd_event_t *, nvlist_t *, extern cmd_cpu_t *cmd_cpu_lookup_from_detector(fmd_hdl_t *, nvlist_t *, const char *); +extern char *cpu_getfrustr(fmd_hdl_t *, uint32_t); +extern cmd_cpu_t *cmd_cpu_lookup(fmd_hdl_t *, nvlist_t *, const char *); +extern cmd_cpu_t *cmd_sibcpu_lookup(fmd_hdl_t *, nvlist_t *, const char *); + extern nvlist_t *cmd_cpu_create_fault(fmd_hdl_t *, cmd_cpu_t *, const char *, nvlist_t *, uint_t); @@ -578,10 +616,17 @@ extern char *cmd_cpu_serdnm_create(fmd_hdl_t *, cmd_cpu_t *, const char *); typedef enum { CMD_CPU_FAM_UNSUPPORTED, CMD_CPU_FAM_CHEETAH, - CMD_CPU_FAM_NIAGARA + CMD_CPU_FAM_NIAGARA, + CMD_CPU_FAM_SPARC64 } cpu_family_t; +typedef struct faminfo { + cpu_family_t fam_value; + boolean_t ecache_flush_needed; +} faminfo_t; + extern cpu_family_t cmd_cpu_check_support(void); +extern boolean_t cmd_cpu_ecache_support(void); extern int cmd_xr_fill(fmd_hdl_t *, nvlist_t *, cmd_xr_t *, cmd_errcl_t); @@ -591,6 +636,12 @@ extern int cmd_cpu_synd_check(uint16_t); extern int cmd_cpu_synd_check(uint32_t); #endif /* sun4u */ +typedef struct opl_cpu_list { + uint32_t cpuid; + struct opl_cpu_list *next_cpu; + cmd_cpu_t *opl_cmd_cpu; +} opl_cpu_list_t; + #ifdef __cplusplus } #endif diff --git a/usr/src/cmd/fm/modules/sun4/cpumem-diagnosis/cmd_cpuerr.c b/usr/src/cmd/fm/modules/sun4/cpumem-diagnosis/cmd_cpuerr.c index d8b428527b..bbfbdfc8da 100644 --- a/usr/src/cmd/fm/modules/sun4/cpumem-diagnosis/cmd_cpuerr.c +++ b/usr/src/cmd/fm/modules/sun4/cpumem-diagnosis/cmd_cpuerr.c @@ -38,6 +38,10 @@ #include <fm/fmd_api.h> #include <sys/fm/protocol.h> #include <sys/async.h> +#ifdef sun4u +#include <sys/fm/cpu/UltraSPARC-III.h> +#include <cmd_opl.h> +#endif /* * We follow the same algorithm for handling all L1$, TLB, and L2/L3 cache @@ -160,6 +164,121 @@ CMD_CPU_UEHANDLER(l2ctl, l2ctl, CMD_PTR_CPU_L2CTL, "l2ctl") CMD_CPU_UEHANDLER(iru, ireg, CMD_PTR_CPU_IREG, "ireg") CMD_CPU_UEHANDLER(fru, freg, CMD_PTR_CPU_FREG, "freg") +#ifdef sun4u +/* + * The following macro handles UE errors for CPUs. + * It handles the error cases in which there is no "resource", + * only detector info. is available. + * + * If the "fltname" "core" is to be generated, the sibling CPUs + * within the core will be added to the suspect list. + * If the "fltname" "chip" is to be generated, the sibling CPUs + * within the chip will be added to the suspect list. + * If the "fltname" "strand" is to be generated, the strand + * itself will be in the suspect list. + */ +#define CMD_OPL_UEHANDLER(name, casenm, ptr, fltname) \ +cmd_evdisp_t \ +cmd_##name(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl, \ + const char *class, cmd_errcl_t clcode) \ +{ \ + cmd_cpu_t *cpu; \ + nvlist_t *det; \ + cmd_case_t *cc; \ + uint8_t cpumask, version = 1; \ + cmd_evdisp_t rc; \ + \ + fmd_hdl_debug(hdl, \ + "Enter CMD_OPL_UEHANDLER for class %x\n", clcode); \ + \ + if ((cpu = cmd_cpu_lookup_from_detector(hdl, nvl, class)) == \ + NULL || cpu->cpu_faulting) \ + return (CMD_EVD_UNUSED); \ + \ + (void) nvlist_lookup_nvlist(nvl, FM_EREPORT_DETECTOR, &det); \ + if (nvlist_lookup_uint8(det, FM_VERSION, &version) != 0 || \ + version > FM_CPU_SCHEME_VERSION || \ + nvlist_lookup_uint8(det, FM_FMRI_CPU_MASK, &cpumask) != 0) \ + return (CMD_EVD_BAD); \ + \ + cc = &cpu->cpu_##casenm; \ + rc = opl_cpuue_handler(hdl, ep, class, fltname, \ + ptr, cpu, cc, cpumask); \ + return (rc); \ +} + +CMD_OPL_UEHANDLER(oplinv_urg, opl_inv_urg, CMD_PTR_CPU_UGESR_INV_URG, "core") +CMD_OPL_UEHANDLER(oplcre, opl_cre, CMD_PTR_CPU_UGESR_CRE, "core") +CMD_OPL_UEHANDLER(opltsb_ctx, opl_tsb_ctx, CMD_PTR_CPU_UGESR_TSB_CTX, "core") +CMD_OPL_UEHANDLER(opltsbp, opl_tsbp, CMD_PTR_CPU_UGESR_TSBP, "core") +CMD_OPL_UEHANDLER(oplpstate, opl_pstate, CMD_PTR_CPU_UGESR_PSTATE, "core") +CMD_OPL_UEHANDLER(opltstate, opl_tstate, CMD_PTR_CPU_UGESR_TSTATE, "core") +CMD_OPL_UEHANDLER(opliug_f, opl_iug_f, CMD_PTR_CPU_UGESR_IUG_F, "core") +CMD_OPL_UEHANDLER(opliug_r, opl_iug_r, CMD_PTR_CPU_UGESR_IUG_R, "core") +CMD_OPL_UEHANDLER(oplsdc, opl_sdc, CMD_PTR_CPU_UGESR_SDC, "chip") +CMD_OPL_UEHANDLER(oplwdt, opl_wdt, CMD_PTR_CPU_UGESR_WDT, "core") +CMD_OPL_UEHANDLER(opldtlb, opl_dtlb, CMD_PTR_CPU_UGESR_DTLB, "core") +CMD_OPL_UEHANDLER(oplitlb, opl_itlb, CMD_PTR_CPU_UGESR_ITLB, "core") +CMD_OPL_UEHANDLER(oplcore_err, opl_core_err, CMD_PTR_CPU_UGESR_CORE_ERR, "core") +CMD_OPL_UEHANDLER(opldae, opl_dae, CMD_PTR_CPU_UGESR_DAE, "core") +CMD_OPL_UEHANDLER(opliae, opl_iae, CMD_PTR_CPU_UGESR_IAE, "core") +CMD_OPL_UEHANDLER(opluge, opl_uge, CMD_PTR_CPU_UGESR_UGE, "core") +#endif + +/* + * The following macro handles UE errors for CPUs. + * The difference in this one compared to the "CMD_CPU_UEHANDLER" + * is that the "asru" here is getting pulled from the resource + * of this ereport instead of from detector. + * + * If the "fltname" "core" is to be generated, the sibling CPUs + * within the core will be added to the suspect list. + * If the "fltname" "chip" is to be generated, the sibling CPUs + * within the chip will be added to the suspect list. + * If the "fltname" "strand" is to be generated, the strand + * itself will be in the suspect list. + */ +#define CMD_GENCPU_UEHANDLER(name, casenm, ptr, fltname) \ +cmd_evdisp_t \ +opl_cmd_##name(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl, \ + const char *class, cmd_errcl_t clcode) \ +{ \ + cmd_cpu_t *cpu; \ + nvlist_t *rsrc = NULL; \ + cmd_case_t *cc; \ + uint8_t cpumask, version = 1; \ + cmd_evdisp_t rc; \ + \ + fmd_hdl_debug(hdl, \ + "Enter CMD_GENCPU_UEHANDLER for class %x\n", clcode); \ + \ + if (nvlist_lookup_nvlist(nvl, \ + FM_EREPORT_PAYLOAD_NAME_RESOURCE, &rsrc) != 0) \ + return (CMD_EVD_BAD); \ + \ + if ((cpu = cmd_cpu_lookup(hdl, rsrc, CPU_EREPORT_STRING)) \ + == NULL || cpu->cpu_faulting) \ + return (CMD_EVD_UNUSED); \ + \ + if (nvlist_lookup_uint8(rsrc, FM_VERSION, &version) != 0 || \ + version > FM_CPU_SCHEME_VERSION || \ + nvlist_lookup_uint8(rsrc, FM_FMRI_CPU_MASK, &cpumask) != 0) \ + return (CMD_EVD_BAD); \ + \ + cc = &cpu->cpu_opl_##casenm; \ + rc = opl_cpuue_handler(hdl, ep, class, fltname, \ + ptr, cpu, cc, cpumask); \ + return (rc); \ +} + +#ifdef sun4u +CMD_GENCPU_UEHANDLER(oplinv_sfsr, inv_sfsr, CMD_PTR_CPU_INV_SFSR, "strand") +CMD_GENCPU_UEHANDLER(ue_cpu_det_cpu, ue_det_cpu, CMD_PTR_CPU_UE_DET_CPU, "chip") +CMD_GENCPU_UEHANDLER(ue_cpu_det_io, ue_det_io, CMD_PTR_CPU_UE_DET_IO, "chip") +CMD_GENCPU_UEHANDLER(oplmtlb, mtlb, CMD_PTR_CPU_MTLB, "core") +CMD_GENCPU_UEHANDLER(opltlbp, tlbp, CMD_PTR_CPU_TLBP, "core") +#endif + typedef struct errdata { cmd_serd_t *ed_serd; const char *ed_fltnm; diff --git a/usr/src/cmd/fm/modules/sun4/cpumem-diagnosis/cmd_main.c b/usr/src/cmd/fm/modules/sun4/cpumem-diagnosis/cmd_main.c index f017c96668..2aeeaae772 100644 --- a/usr/src/cmd/fm/modules/sun4/cpumem-diagnosis/cmd_main.c +++ b/usr/src/cmd/fm/modules/sun4/cpumem-diagnosis/cmd_main.c @@ -27,8 +27,8 @@ #pragma ident "%Z%%M% %I% %E% SMI" /* - * CPU/Memory error diagnosis engine for the UltraSPARC III, IV and T1 - * families of processors. + * CPU/Memory error diagnosis engine for the UltraSPARC III, IV, T1 + * and SPARC64 VI families of processors. */ #include <cmd_state.h> @@ -43,6 +43,7 @@ #include <cmd_dimm.h> #ifdef sun4u #include <cmd_dp.h> +#include <cmd_opl.h> #endif #include <cmd_bank.h> #include <cmd.h> @@ -130,6 +131,61 @@ static cmd_subscriber_t cmd_subscribers[] = { { "ereport.asic.*.sdi.sdi-dp", cmd_dp_ex }, { "ereport.asic.*.cp.cp-dp", cmd_dp_cp }, { "ereport.asic.*.rp.rp-dp", cmd_dp_cp }, + { "ereport.asic.mac.mi-ue", opl_cmd_mac_common }, + { "ereport.asic.mac.ptrl-ue", opl_cmd_mac_common }, + { "ereport.asic.mac.mi-ce", opl_cmd_mac_common }, + { "ereport.asic.mac.ptrl-ce", opl_cmd_mac_common }, + { "ereport.asic.mac.mi-cmpe", opl_cmd_mac_common }, + { "ereport.asic.mac.ptrl-cmpe", opl_cmd_mac_common }, + { "ereport.asic.mac.mi-sue", opl_cmd_mac_common }, + { "ereport.asic.mac.ptrl-sue", opl_cmd_mac_common }, + { "ereport.asic.mac.mi-mue", opl_cmd_mac_common }, + { "ereport.asic.mac.ptrl-mue", opl_cmd_mac_common }, + { "ereport.cpu.*.ue-mem", opl_cmd_cpu_hdlr_mem }, + { "ereport.cpu.*.ue-channel", cmd_nop }, + { "ereport.cpu.*.ue-cpu", opl_cmd_ue_cpu_det_cpu }, + { "ereport.cpu.*.ue-path", cmd_nop }, + { "ereport.cpu.*.inv-sfsr", opl_cmd_oplinv_sfsr }, + { "ereport.cpu.*.berr", cmd_nop }, + { "ereport.cpu.*.bto", cmd_nop }, + { "ereport.cpu.*.mtlb", opl_cmd_oplmtlb }, + { "ereport.cpu.*.tlbp", opl_cmd_opltlbp }, + { "ereport.cpu.*.inv-urg", cmd_oplinv_urg }, + { "ereport.cpu.*.cre", cmd_oplcre }, + { "ereport.cpu.*.tsb-ctx", cmd_opltsb_ctx }, + { "ereport.cpu.*.tsbp", cmd_opltsbp }, + { "ereport.cpu.*.pstate", cmd_oplpstate }, + { "ereport.cpu.*.tstate", cmd_opltstate }, + { "ereport.cpu.*.iug-f", cmd_opliug_f }, + { "ereport.cpu.*.iug-r", cmd_opliug_r }, + { "ereport.cpu.*.sdc", cmd_oplsdc }, + { "ereport.cpu.*.wdt", cmd_oplwdt }, + { "ereport.cpu.*.dtlb", cmd_opldtlb }, + { "ereport.cpu.*.itlb", cmd_oplitlb }, + { "ereport.cpu.*.core-err", cmd_oplcore_err }, + { "ereport.cpu.*.dae", cmd_opldae }, + { "ereport.cpu.*.iae", cmd_opliae }, + { "ereport.cpu.*.uge", cmd_opluge }, + { "ereport.io.oberon.ubc.dmarduea-mem", opl_cmd_io_hdlr_mem }, + { "ereport.io.oberon.ubc.dmarduea-channel", cmd_nop }, + { "ereport.io.oberon.ubc.dmarduea-cpu", opl_cmd_ue_cpu_det_io }, + { "ereport.io.oberon.ubc.dmarduea-path", cmd_nop }, + { "ereport.io.oberon.ubc.dmardueb-mem", opl_cmd_io_hdlr_mem }, + { "ereport.io.oberon.ubc.dmardueb-channel", cmd_nop }, + { "ereport.io.oberon.ubc.dmardueb-cpu", opl_cmd_ue_cpu_det_io }, + { "ereport.io.oberon.ubc.dmardueb-path", cmd_nop }, + { "ereport.io.oberon.ubc.piowtue-mem", opl_cmd_io_hdlr_mem }, + { "ereport.io.oberon.ubc.piowtue-channel", cmd_nop }, + { "ereport.io.oberon.ubc.piowtue-cpu", opl_cmd_ue_cpu_det_io }, + { "ereport.io.oberon.ubc.piowtue-path", cmd_nop }, + { "ereport.io.oberon.ubc.piowbeue-mem", opl_cmd_io_hdlr_mem }, + { "ereport.io.oberon.ubc.piowbeue-channel", cmd_nop }, + { "ereport.io.oberon.ubc.piowbeue-cpu", opl_cmd_ue_cpu_det_io }, + { "ereport.io.oberon.ubc.piowbeue-path", cmd_nop }, + { "ereport.io.oberon.ubc.piorbeue-mem", opl_cmd_io_hdlr_mem }, + { "ereport.io.oberon.ubc.piorbeue-channel", cmd_nop }, + { "ereport.io.oberon.ubc.piorbeue-cpu", opl_cmd_ue_cpu_det_io }, + { "ereport.io.oberon.ubc.piorbeue-path", cmd_nop }, #else /* i.e. sun4v */ { "ereport.cpu.*.irc", cmd_irc }, { "ereport.cpu.*.iru", cmd_iru }, @@ -322,12 +378,7 @@ static const fmd_hdl_ops_t fmd_ops = { }; static const fmd_hdl_info_t fmd_info = { -#ifdef sun4u - "UltraSPARC-III/IV CPU/Memory Diagnosis", -#else - "UltraSPARC-T1 CPU/Memory Diagnosis", -#endif - CMD_VERSION, &fmd_ops, fmd_props + "CPU/Memory Diagnosis", CMD_VERSION, &fmd_ops, fmd_props }; static const struct cmd_evdisp_name { @@ -419,6 +470,32 @@ _fmd_init(fmd_hdl_t *hdl) fmd_hdl_subscribe(hdl, "ereport.asic.*.sdi.sdi-dp"); fmd_hdl_subscribe(hdl, "ereport.asic.*.cp.cp-dp"); fmd_hdl_subscribe(hdl, "ereport.asic.*.rp.rp-dp"); + + /* + * OPL platform specific subscriptions. + */ + fmd_hdl_subscribe(hdl, "ereport.cpu.SPARC64-VI.*"); + fmd_hdl_subscribe(hdl, "ereport.asic.mac.*"); + fmd_hdl_subscribe(hdl, "ereport.io.oberon.ubc.dmarduea-mem"); + fmd_hdl_subscribe(hdl, "ereport.io.oberon.ubc.dmarduea-channel"); + fmd_hdl_subscribe(hdl, "ereport.io.oberon.ubc.dmarduea-cpu"); + fmd_hdl_subscribe(hdl, "ereport.io.oberon.ubc.dmarduea-path"); + fmd_hdl_subscribe(hdl, "ereport.io.oberon.ubc.dmardueb-mem"); + fmd_hdl_subscribe(hdl, "ereport.io.oberon.ubc.dmardueb-channel"); + fmd_hdl_subscribe(hdl, "ereport.io.oberon.ubc.dmardueb-cpu"); + fmd_hdl_subscribe(hdl, "ereport.io.oberon.ubc.dmardueb-path"); + fmd_hdl_subscribe(hdl, "ereport.io.oberon.ubc.piowtue-mem"); + fmd_hdl_subscribe(hdl, "ereport.io.oberon.ubc.piowtue-channel"); + fmd_hdl_subscribe(hdl, "ereport.io.oberon.ubc.piowtue-cpu"); + fmd_hdl_subscribe(hdl, "ereport.io.oberon.ubc.piowtue-path"); + fmd_hdl_subscribe(hdl, "ereport.io.oberon.ubc.piowbeue-mem"); + fmd_hdl_subscribe(hdl, "ereport.io.oberon.ubc.piowbeue-channel"); + fmd_hdl_subscribe(hdl, "ereport.io.oberon.ubc.piowbeue-cpu"); + fmd_hdl_subscribe(hdl, "ereport.io.oberon.ubc.piowbeue-path"); + fmd_hdl_subscribe(hdl, "ereport.io.oberon.ubc.piorbeue-mem"); + fmd_hdl_subscribe(hdl, "ereport.io.oberon.ubc.piorbeue-channel"); + fmd_hdl_subscribe(hdl, "ereport.io.oberon.ubc.piorbeue-cpu"); + fmd_hdl_subscribe(hdl, "ereport.io.oberon.ubc.piorbeue-path"); #endif bzero(&cmd, sizeof (cmd_t)); @@ -454,11 +531,14 @@ _fmd_init(fmd_hdl_t *hdl) cmd.cmd_iorxefrx_window = fmd_prop_get_int64(hdl, "iorxefrx_window"); #ifdef sun4u - if (cmd_ecache_init() < 0) { - _fmd_fini(hdl); - fmd_hdl_abort(hdl, "failed to find device for E-cache flush"); + if (cmd_cpu_ecache_support()) { + if (cmd_ecache_init() < 0) { + _fmd_fini(hdl); + fmd_hdl_abort(hdl, + "failed to find device for E-cache flush"); + } } -#endif /* sun4u */ +#endif if ((cmd.cmd_thresh_tpct_sysmem = fmd_prop_get_int64(hdl, "thresh_tpct_sysmem")) > 100000) { diff --git a/usr/src/cmd/fm/modules/sun4/cpumem-diagnosis/cmd_state.c b/usr/src/cmd/fm/modules/sun4/cpumem-diagnosis/cmd_state.c index ae0e83a2bc..8ee4c7365c 100644 --- a/usr/src/cmd/fm/modules/sun4/cpumem-diagnosis/cmd_state.c +++ b/usr/src/cmd/fm/modules/sun4/cpumem-diagnosis/cmd_state.c @@ -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,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -45,6 +44,10 @@ #include <string.h> #include <fm/fmd_api.h> +#ifdef sun4u +#include <cmd_opl.h> +#endif + /* Must be in sync with cmd_ptrsubtype_t */ static cmd_case_closer_f *const cmd_case_closers[] = { NULL, @@ -73,7 +76,28 @@ static cmd_case_closer_f *const cmd_case_closers[] = { #else NULL, /* CMD_PTR_DP_CASE */ #endif - NULL /* CMD_PTR_DP_PAGE_DEFER */ + NULL, /* CMD_PTR_DP_PAGE_DEFER */ + cmd_cpuerr_close, /* CMD_PTR_CPU_INV_SFSR */ + cmd_cpuerr_close, /* CMD_PTR_CPU_UE_DET_CPU */ + cmd_cpuerr_close, /* CMD_PTR_CPU_UE_DET_IO */ + cmd_cpuerr_close, /* CMD_PTR_CPU_MTLB */ + cmd_cpuerr_close, /* CMD_PTR_CPU_TLBP */ + cmd_cpuerr_close, /* CMD_PTR_CPU_UGESR_INV_URG */ + cmd_cpuerr_close, /* CMD_PTR_CPU_UGESR_CRE */ + cmd_cpuerr_close, /* CMD_PTR_CPU_UGESR_TSB_CTX */ + cmd_cpuerr_close, /* CMD_PTR_CPU_UGESR_TSBP */ + cmd_cpuerr_close, /* CMD_PTR_CPU_UGESR_PSTATE */ + cmd_cpuerr_close, /* CMD_PTR_CPU_UGESR_TSTATE */ + cmd_cpuerr_close, /* CMD_PTR_CPU_UGESR_IUG_F */ + cmd_cpuerr_close, /* CMD_PTR_CPU_UGESR_IUG_R */ + cmd_cpuerr_close, /* CMD_PTR_CPU_UGESR_SDC */ + cmd_cpuerr_close, /* CMD_PTR_CPU_UGESR_WDT */ + cmd_cpuerr_close, /* CMD_PTR_CPU_UGESR_DTLB */ + cmd_cpuerr_close, /* CMD_PTR_CPU_UGESR_ITLB */ + cmd_cpuerr_close, /* CMD_PTR_CPU_UGESR_CORE_ERR */ + cmd_cpuerr_close, /* CMD_PTR_CPU_UGESR_DAE */ + cmd_cpuerr_close, /* CMD_PTR_CPU_UGESR_IAE */ + cmd_cpuerr_close /* CMD_PTR_CPU_UGESR_UGE */ }; fmd_case_t * diff --git a/usr/src/cmd/fm/modules/sun4/cpumem-diagnosis/cmd_state.h b/usr/src/cmd/fm/modules/sun4/cpumem-diagnosis/cmd_state.h index b0b9b7fea2..1dd7d4ab24 100644 --- a/usr/src/cmd/fm/modules/sun4/cpumem-diagnosis/cmd_state.h +++ b/usr/src/cmd/fm/modules/sun4/cpumem-diagnosis/cmd_state.h @@ -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,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -102,7 +101,28 @@ typedef enum cmd_ptrsubtype { CMD_PTR_CPU_MAU, CMD_PTR_CPU_L2CTL, CMD_PTR_DP_CASE, - CMD_PTR_DP_PAGE_DEFER + CMD_PTR_DP_PAGE_DEFER, + CMD_PTR_CPU_INV_SFSR, + CMD_PTR_CPU_UE_DET_CPU, + CMD_PTR_CPU_UE_DET_IO, + CMD_PTR_CPU_MTLB, + CMD_PTR_CPU_TLBP, + CMD_PTR_CPU_UGESR_INV_URG, + CMD_PTR_CPU_UGESR_CRE, + CMD_PTR_CPU_UGESR_TSB_CTX, + CMD_PTR_CPU_UGESR_TSBP, + CMD_PTR_CPU_UGESR_PSTATE, + CMD_PTR_CPU_UGESR_TSTATE, + CMD_PTR_CPU_UGESR_IUG_F, + CMD_PTR_CPU_UGESR_IUG_R, + CMD_PTR_CPU_UGESR_SDC, + CMD_PTR_CPU_UGESR_WDT, + CMD_PTR_CPU_UGESR_DTLB, + CMD_PTR_CPU_UGESR_ITLB, + CMD_PTR_CPU_UGESR_CORE_ERR, + CMD_PTR_CPU_UGESR_DAE, + CMD_PTR_CPU_UGESR_IAE, + CMD_PTR_CPU_UGESR_UGE } cmd_ptrsubtype_t; /* diff --git a/usr/src/cmd/fm/modules/sun4u/cpumem-diagnosis/Makefile b/usr/src/cmd/fm/modules/sun4u/cpumem-diagnosis/Makefile index 4ac58e65a4..bae63b765d 100644 --- a/usr/src/cmd/fm/modules/sun4u/cpumem-diagnosis/Makefile +++ b/usr/src/cmd/fm/modules/sun4u/cpumem-diagnosis/Makefile @@ -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,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" @@ -30,7 +29,8 @@ ARCH = sun4u sun4u_SRCS = cmd_ecache.c \ cmd_dp.c \ cmd_dperr.c \ - cmd_dp_page.c + cmd_dp_page.c \ + cmd_opl.c INCDIRS = $(SRC)/uts/sun4u diff --git a/usr/src/cmd/fm/modules/sun4u/cpumem-diagnosis/cmd_opl.c b/usr/src/cmd/fm/modules/sun4u/cpumem-diagnosis/cmd_opl.c new file mode 100644 index 0000000000..61629976e7 --- /dev/null +++ b/usr/src/cmd/fm/modules/sun4u/cpumem-diagnosis/cmd_opl.c @@ -0,0 +1,565 @@ +/* + * 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" + +/* + * OPL platform specific functions for + * CPU/Memory error diagnosis engine. + */ +#include <cmd.h> +#include <cmd_page.h> +#include <cmd_opl.h> +#include <string.h> +#include <errno.h> +#include <kstat.h> + +#include <sys/fm/protocol.h> +#include <sys/fm/io/opl_mc_fm.h> +#include <sys/async.h> +#include <sys/opl_olympus_regs.h> +#include <sys/fm/cpu/SPARC64-VI.h> +#include <sys/int_const.h> + +/* + * derived from cpu scheme function "cpu_get_serialid_kstat". + */ +static int +opl_cpu_get_serialid_kstat(uint32_t cpuid, uint64_t *serialidp) +{ + kstat_named_t *kn; + kstat_ctl_t *kc; + kstat_t *ksp; + int i; + + if ((kc = kstat_open()) == NULL) /* XXX commonify */ + return (-1); /* errno is set for us */ + + if ((ksp = kstat_lookup(kc, "cpu_info", cpuid, NULL)) == NULL) { + (void) kstat_close(kc); + return (cmd_set_errno(ENOENT)); + } + + if (kstat_read(kc, ksp, NULL) == -1) { + int oserr = errno; + (void) kstat_close(kc); + return (cmd_set_errno(oserr)); + } + + for (kn = ksp->ks_data, i = 0; i < ksp->ks_ndata; i++, kn++) { + if (strcmp(kn->name, "device_ID") == 0) { + *serialidp = kn->value.ui64; + (void) kstat_close(kc); + return (0); + } + } + + (void) kstat_close(kc); + + return (cmd_set_errno(ENOENT)); +} + +/* + * This function builds the ASRU page + * of the given cpuid based on the CPU scheme. + */ +nvlist_t * +opl_cmd_cpu_asru_create(uint32_t cpuid, uint8_t cpumask) +{ + uint64_t serialid; + nvlist_t *fmri; + char sbuf[21]; /* sizeof (UINT64_MAX) + '\0' */ + + if ((errno = nvlist_alloc(&fmri, NV_UNIQUE_NAME, 0)) != 0) + return (NULL); + + if (opl_cpu_get_serialid_kstat(cpuid, &serialid) != 0) { + nvlist_free(fmri); + return (NULL); + } + + /* + * Version 1 calls for a string-based serial number + */ + (void) snprintf(sbuf, sizeof (sbuf), "%llX", (u_longlong_t)serialid); + + if (nvlist_add_uint8(fmri, FM_VERSION, + FM_CPU_SCHEME_VERSION) != 0 || nvlist_add_string(fmri, + FM_FMRI_SCHEME, FM_FMRI_SCHEME_CPU) != 0 || + nvlist_add_uint32(fmri, FM_FMRI_CPU_ID, cpuid) != 0 || + nvlist_add_string(fmri, FM_FMRI_CPU_SERIAL_ID, sbuf) != 0 || + nvlist_add_uint8(fmri, FM_FMRI_CPU_MASK, cpumask) != 0) { + nvlist_free(fmri); + return (NULL); + } + + return (fmri); +} + +opl_cpu_list_t * +opl_alloc_struct(fmd_hdl_t *hdl, uint32_t cpuid, int flt_type) +{ + opl_cpu_list_t *p = NULL, *pp = NULL, *first_p = NULL; + uint32_t c, s, sib_cpuid, cur_cpuid; + + switch (flt_type) { + case IS_STRAND: + p = fmd_hdl_alloc(hdl, sizeof (opl_cpu_list_t), FMD_SLEEP); + if (p != NULL) { + p->cpuid = cpuid; + p->next_cpu = NULL; + first_p = p; + } else + first_p = NULL; + break; + + case IS_CORE: + /* + * Based on the Olympus-C CPUID definition in multi-strands + * mode to flip the bits to get the sibling strands + */ + sib_cpuid = cpuid ^ 1; + for (s = 0; s <= STRAND_UPPER_BOUND; s++) { + p = fmd_hdl_alloc(hdl, sizeof (opl_cpu_list_t), + FMD_SLEEP); + if (p == NULL) { + if (s > 0) + fmd_hdl_free(hdl, pp, + sizeof (opl_cpu_list_t)); + return (p); + } + if (s == 0) { + p->cpuid = cpuid; + p->next_cpu = NULL; + pp = p; + first_p = p; + } else { + p->cpuid = sib_cpuid; + p->next_cpu = NULL; + pp->next_cpu = p; + } + } + break; + + case IS_CHIP: + /* + * Based on the Olympus-C CPUID definition in multi-strand + * mode to flip the bits in CPUID for getting the sibling + * strand IDs + */ + cur_cpuid = cpuid; + for (c = 0; c <= CORE_UPPER_BOUND; c++) { + sib_cpuid = cur_cpuid; + for (s = 0; s <= 1; s++) { + p = fmd_hdl_alloc(hdl, + sizeof (opl_cpu_list_t), FMD_SLEEP); + if (p == NULL) { + if (c > 0) + opl_free_struct(hdl, first_p); + return (p); + } else { + if (c == 0 && s == 0) { + p->cpuid = cpuid; + p->next_cpu = NULL; + first_p = p; + } else { + p->cpuid = sib_cpuid; + p->next_cpu = NULL; + pp->next_cpu = p; + } + } + pp = p; + sib_cpuid = cur_cpuid ^ 1; + } + cur_cpuid = cur_cpuid ^ 2; + } + break; + + default: + first_p = NULL; + break; + } + + return (first_p); +} + +void +opl_free_struct(fmd_hdl_t *hdl, opl_cpu_list_t *cpu_list) +{ + opl_cpu_list_t *p, *pp; + + for (p = cpu_list; p != NULL; ) { + pp = p; + if (p != NULL) + p = p->next_cpu; + fmd_hdl_free(hdl, pp, sizeof (opl_cpu_list_t)); + } +} + +/* + * Based on "avg" function of eversholt + */ +uint8_t +opl_avg(uint_t sum, uint_t cnt) +{ + unsigned long long s = sum * 10; + + return ((s / cnt / 10) + (((s / cnt % 10) >= 5) ? 1 : 0)); +} + +void +opl_free_nvpairs(nvlist_t *nvpairs[], uint_t npairs) +{ + uint_t idx; + + if (!npairs) { + for (idx = 0; idx < npairs; idx++) + nvlist_free(nvpairs[idx]); + } +} + +/* + * This function builds the resource fmri page based on + * the kstat "cpu_fru" of the faulted cpu and cpuid + * using the "hc" scheme. + */ +nvlist_t * +opl_cmd_cpu_rsrc_create(fmd_hdl_t *hdl, uint32_t cpuid) +{ + nvlist_t *fmri, *pairs[LIST_SIZE]; + uint_t npairs; + char *frustr, *comp; + char chip_str[STR_BUFLEN]; + char core_str[STR_BUFLEN]; + char strand_str[STR_BUFLEN]; + + for (npairs = 0; npairs < LIST_SIZE; npairs++) { + if ((errno = nvlist_alloc(&pairs[npairs], + NV_UNIQUE_NAME, 0)) != 0) { + opl_free_nvpairs(pairs, npairs); + return (NULL); + } + } + + if ((errno = nvlist_alloc(&fmri, NV_UNIQUE_NAME, 0)) != 0) { + opl_free_nvpairs(pairs, npairs); + return (NULL); + } + + if ((frustr = cpu_getfrustr(hdl, cpuid)) == NULL) { + opl_free_nvpairs(pairs, npairs); + nvlist_free(fmri); + return (NULL); + } + + /* + * get the CMU # from cpu_fru + */ + if (strncmp(frustr, OPL_CPU_FRU_FMRI, + sizeof (OPL_CPU_FRU_FMRI) - 1) == 0) { + comp = frustr + sizeof (OPL_CPU_FRU_FMRI) - 1; + /* + * incorrect format; default to zero + */ + } else + comp = "0"; + + (void) snprintf(chip_str, STR_BUFLEN, "%u", + (cpuid >> CHIPID_SHIFT) & CHIP_OR_CORE_MASK); + + (void) snprintf(core_str, STR_BUFLEN, "%u", + (cpuid >> COREID_SHIFT) & CHIP_OR_CORE_MASK); + + (void) snprintf(strand_str, STR_BUFLEN, "%u", + (cpuid & STRAND_MASK)); + + if (nvlist_add_string(pairs[0], FM_FMRI_HC_NAME, "chassis") != 0 || + nvlist_add_string(pairs[0], FM_FMRI_HC_ID, "0") != 0 || + nvlist_add_string(pairs[1], FM_FMRI_HC_NAME, "cmu") != 0 || + nvlist_add_string(pairs[1], FM_FMRI_HC_ID, comp) != 0 || + nvlist_add_string(pairs[2], FM_FMRI_HC_NAME, "chip") != 0 || + nvlist_add_string(pairs[2], FM_FMRI_HC_ID, chip_str) != 0 || + nvlist_add_string(pairs[3], FM_FMRI_HC_NAME, "core") != 0 || + nvlist_add_string(pairs[3], FM_FMRI_HC_ID, core_str) != 0 || + nvlist_add_string(pairs[4], FM_FMRI_HC_NAME, "strand") != 0 || + nvlist_add_string(pairs[4], FM_FMRI_HC_ID, strand_str) != 0) { + fmd_hdl_strfree(hdl, frustr); + opl_free_nvpairs(pairs, npairs); + nvlist_free(fmri); + return (NULL); + } + + if (nvlist_add_uint8(fmri, FM_VERSION, FM_HC_SCHEME_VERSION) != 0 || + nvlist_add_string(fmri, FM_FMRI_SCHEME, FM_FMRI_SCHEME_HC) != 0 || + nvlist_add_string(fmri, FM_FMRI_HC_ROOT, "") != 0 || + nvlist_add_uint32(fmri, FM_FMRI_HC_LIST_SZ, LIST_SIZE) != 0 || + nvlist_add_nvlist_array(fmri, FM_FMRI_HC_LIST, + pairs, npairs) != 0) { + fmd_hdl_strfree(hdl, frustr); + opl_free_nvpairs(pairs, npairs); + nvlist_free(fmri); + return (NULL); + } + + if (fmd_nvl_fmri_expand(hdl, fmri) < 0) { + fmd_hdl_strfree(hdl, frustr); + opl_free_nvpairs(pairs, npairs); + nvlist_free(fmri); + return (NULL); + } + + fmd_hdl_strfree(hdl, frustr); + opl_free_nvpairs(pairs, npairs); + return (fmri); +} + +/* + * The following is the main function to handle generating + * the sibling cpu suspect list for the CPU detected UE + * error cases. This is to handle the + * multiple strand/core architecture on the OPL platform. + */ +cmd_evdisp_t +opl_cpuue_handler(fmd_hdl_t *hdl, fmd_event_t *ep, + const char *class, const char *fltname, + cmd_ptrsubtype_t ptr, cmd_cpu_t *cpu, + cmd_case_t *cc, uint8_t cpumask) +{ + const char *uuid; + cmd_cpu_t *main_cpu, *sib_cpu; + nvlist_t *flt, *fmri; + opl_cpu_list_t *cpu_list, *cpu_lp; + uint32_t main_cpuid, nsusp = 1; + uint8_t cert; + + fmd_hdl_debug(hdl, + "Enter OPL_CPUUE_HANDLER for class %x\n", class); + + main_cpuid = cpu->cpu_cpuid; + main_cpu = cpu; + + if (strcmp(fltname, "core") == 0) + cpu_list = opl_alloc_struct(hdl, cpu->cpu_cpuid, + IS_CORE); + else if (strcmp(fltname, "chip") == 0) + cpu_list = opl_alloc_struct(hdl, cpu->cpu_cpuid, + IS_CHIP); + else + cpu_list = opl_alloc_struct(hdl, cpu->cpu_cpuid, + IS_STRAND); + + for (cpu_lp = cpu_list; cpu_lp != NULL; cpu_lp = cpu_lp->next_cpu) { + if (cpu_lp->cpuid == main_cpuid) { + sib_cpu = main_cpu; + cpu_lp->opl_cmd_cpu = main_cpu; + } else { + fmri = opl_cmd_cpu_asru_create(cpu_lp->cpuid, cpumask); + if (fmri == NULL) { + cpu_lp->opl_cmd_cpu = NULL; + fmd_hdl_debug(hdl, + "missing asru, cpuid %u excluded\n", + cpu_lp->cpuid); + continue; + } + + sib_cpu = cmd_sibcpu_lookup(hdl, fmri, + CPU_EREPORT_STRING); + if (sib_cpu == NULL || sib_cpu->cpu_faulting) { + if (fmri != NULL) + nvlist_free(fmri); + cpu_lp->opl_cmd_cpu = NULL; + fmd_hdl_debug(hdl, + "cpu not present, cpuid %u excluded\n", + cpu_lp->cpuid); + continue; + } + cpu_lp->opl_cmd_cpu = sib_cpu; + if (fmri != NULL) + nvlist_free(fmri); + nsusp++; + } + if (cpu->cpu_cpuid == main_cpuid) { + if (cc->cc_cp != NULL && + fmd_case_solved(hdl, cc->cc_cp)) { + if (cpu_list != NULL) + opl_free_struct(hdl, cpu_list); + return (CMD_EVD_REDUND); + } + + if (cc->cc_cp == NULL) + cc->cc_cp = cmd_case_create(hdl, + &cpu->cpu_header, ptr, &uuid); + + if (cc->cc_serdnm != NULL) { + fmd_hdl_debug(hdl, + "destroying existing %s state for class %x\n", + cc->cc_serdnm, class); + fmd_serd_destroy(hdl, cc->cc_serdnm); + fmd_hdl_strfree(hdl, cc->cc_serdnm); + cc->cc_serdnm = NULL; + fmd_case_reset(hdl, cc->cc_cp); + } + fmd_case_add_ereport(hdl, cc->cc_cp, ep); + } + } + cert = opl_avg(100, nsusp); + for (cpu_lp = cpu_list; cpu_lp != NULL; cpu_lp = cpu_lp->next_cpu) { + if (cpu_lp->opl_cmd_cpu != NULL) { + nvlist_t *cpu_rsrc; + + cpu_rsrc = opl_cmd_cpu_rsrc_create(hdl, cpu_lp->cpuid); + if (cpu_rsrc == NULL) { + fmd_hdl_debug(hdl, + "missing rsrc, cpuid %u excluded\n", + cpu_lp->cpuid); + continue; + } + flt = cmd_cpu_create_fault(hdl, + cpu_lp->opl_cmd_cpu, fltname, cpu_rsrc, cert); + nvlist_free(cpu_rsrc); + fmd_case_add_suspect(hdl, cc->cc_cp, flt); + } + } + fmd_case_solve(hdl, cc->cc_cp); + if (cpu_list != NULL) + opl_free_struct(hdl, cpu_list); + return (CMD_EVD_OK); +} + +/* + * The following is the common function for handling + * memory UE with EID=MEM. + * The error could be detected by either CPU/IO. + */ +cmd_evdisp_t +opl_cmd_ue_mem(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl, + int hdlr_type) +{ + nvlist_t *rsrc = NULL, *asru = NULL; + uint64_t ubc_ue_log_reg, pa; + + if (nvlist_lookup_nvlist(nvl, + FM_EREPORT_PAYLOAD_NAME_RESOURCE, &rsrc) != 0) + return (CMD_EVD_BAD); + + switch (hdlr_type) { + case CMD_OPL_HDLR_CPU: + + if (nvlist_lookup_uint64(nvl, + FM_EREPORT_PAYLOAD_NAME_SFAR, &pa) != 0) + return (CMD_EVD_BAD); + + fmd_hdl_debug(hdl, "cmd_ue_mem: pa=%llx\n", + (u_longlong_t)pa); + break; + + case CMD_OPL_HDLR_IO: + + if (nvlist_lookup_uint64(nvl, OBERON_UBC_MUE, + &ubc_ue_log_reg) != 0) + return (CMD_EVD_BAD); + + pa = (ubc_ue_log_reg & UBC_UE_ADR_MASK); + + fmd_hdl_debug(hdl, "cmd_ue_mem: ue_log_reg=%llx\n", + (u_longlong_t)ubc_ue_log_reg); + fmd_hdl_debug(hdl, "cmd_ue_mem: pa=%llx\n", + (u_longlong_t)pa); + break; + + default: + + return (CMD_EVD_BAD); + } + + if ((errno = nvlist_dup(rsrc, &asru, 0)) != 0 || + (errno = nvlist_add_uint64(asru, + FM_FMRI_MEM_PHYSADDR, pa)) != 0) + fmd_hdl_abort(hdl, "failed to build page fmri"); + + cmd_page_fault(hdl, asru, rsrc, ep, pa); + return (CMD_EVD_OK); +} + +/* + * This is the common entry for processing MAC detected errors. + * It is responsible for generating the memory page fault event. + * The permanent CE in normal mode is handled here also in the + * same way as in the UE case. + */ +/*ARGSUSED*/ +cmd_evdisp_t +opl_cmd_mac_common(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl, + const char *class, cmd_errcl_t clcode) +{ + uint64_t pa; + nvlist_t *rsrc = NULL, *asru = NULL; + + fmd_hdl_debug(hdl, "cmd_mac_common: clcode=%ll\n", clcode); + + if (nvlist_lookup_nvlist(nvl, MC_OPL_RESOURCE, &rsrc) != 0) + return (CMD_EVD_BAD); + + if (nvlist_lookup_uint64(nvl, MC_OPL_PA, &pa) + != 0) + return (CMD_EVD_BAD); + + /* + * Check for invalid pa. + * The most sig. bit should not be on. + * It would be out of the range of possible pa + * in MAC's view. + */ + if (((uint64_t)1 << 63) & pa) + return (CMD_EVD_BAD); + + if ((errno = nvlist_dup(rsrc, &asru, 0)) != 0 || + (errno = nvlist_add_uint64(asru, FM_FMRI_MEM_PHYSADDR, pa)) != 0) + fmd_hdl_abort(hdl, "failed to build page fmri"); + + cmd_page_fault(hdl, asru, rsrc, ep, pa); + return (CMD_EVD_OK); +} + +/* + * Common entry points for handling CPU/IO detected UE with + * respect to EID=MEM. + */ +/*ARGSUSED*/ +cmd_evdisp_t +opl_cmd_cpu_hdlr_mem(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl, + const char *class, cmd_errcl_t clcode) +{ + return (opl_cmd_ue_mem(hdl, ep, nvl, CMD_OPL_HDLR_CPU)); +} + +/*ARGSUSED*/ +cmd_evdisp_t +opl_cmd_io_hdlr_mem(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl, + const char *class, cmd_errcl_t clcode) +{ + return (opl_cmd_ue_mem(hdl, ep, nvl, CMD_OPL_HDLR_IO)); +} diff --git a/usr/src/cmd/fm/modules/sun4u/cpumem-diagnosis/cmd_opl.h b/usr/src/cmd/fm/modules/sun4u/cpumem-diagnosis/cmd_opl.h new file mode 100644 index 0000000000..c7a2dfa1df --- /dev/null +++ b/usr/src/cmd/fm/modules/sun4u/cpumem-diagnosis/cmd_opl.h @@ -0,0 +1,145 @@ +/* + * 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 _CMD_OPL_H +#define _CMD_OPL_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <cmd.h> +#include <cmd_cpu.h> + +#ifdef __cplusplus +extern "C" { +#endif + +extern cmd_evdisp_t cmd_oplinv_urg(fmd_hdl_t *, fmd_event_t *, nvlist_t *, + const char *, cmd_errcl_t); +extern cmd_evdisp_t cmd_oplcre(fmd_hdl_t *, fmd_event_t *, nvlist_t *, + const char *, cmd_errcl_t); +extern cmd_evdisp_t cmd_opltsb_ctx(fmd_hdl_t *, fmd_event_t *, nvlist_t *, + const char *, cmd_errcl_t); +extern cmd_evdisp_t cmd_opltsbp(fmd_hdl_t *, fmd_event_t *, nvlist_t *, + const char *, cmd_errcl_t); +extern cmd_evdisp_t cmd_oplpstate(fmd_hdl_t *, fmd_event_t *, nvlist_t *, + const char *, cmd_errcl_t); +extern cmd_evdisp_t cmd_opltstate(fmd_hdl_t *, fmd_event_t *, nvlist_t *, + const char *, cmd_errcl_t); +extern cmd_evdisp_t cmd_opliug_f(fmd_hdl_t *, fmd_event_t *, nvlist_t *, + const char *, cmd_errcl_t); +extern cmd_evdisp_t cmd_opliug_r(fmd_hdl_t *, fmd_event_t *, nvlist_t *, + const char *, cmd_errcl_t); +extern cmd_evdisp_t cmd_oplsdc(fmd_hdl_t *, fmd_event_t *, nvlist_t *, + const char *, cmd_errcl_t); +extern cmd_evdisp_t cmd_oplwdt(fmd_hdl_t *, fmd_event_t *, nvlist_t *, + const char *, cmd_errcl_t); +extern cmd_evdisp_t cmd_opldtlb(fmd_hdl_t *, fmd_event_t *, nvlist_t *, + const char *, cmd_errcl_t); +extern cmd_evdisp_t cmd_oplitlb(fmd_hdl_t *, fmd_event_t *, nvlist_t *, + const char *, cmd_errcl_t); +extern cmd_evdisp_t cmd_oplcore_err(fmd_hdl_t *, fmd_event_t *, nvlist_t *, + const char *, cmd_errcl_t); +extern cmd_evdisp_t cmd_opldae(fmd_hdl_t *, fmd_event_t *, nvlist_t *, + const char *, cmd_errcl_t); +extern cmd_evdisp_t cmd_opliae(fmd_hdl_t *, fmd_event_t *, nvlist_t *, + const char *, cmd_errcl_t); +extern cmd_evdisp_t cmd_opluge(fmd_hdl_t *, fmd_event_t *, nvlist_t *, + const char *, cmd_errcl_t); +extern cmd_evdisp_t opl_cmd_oplmtlb(fmd_hdl_t *, fmd_event_t *, nvlist_t *, + const char *, cmd_errcl_t); +extern cmd_evdisp_t opl_cmd_opltlbp(fmd_hdl_t *, fmd_event_t *, nvlist_t *, + const char *, cmd_errcl_t); +extern cmd_evdisp_t opl_cmd_oplinv_sfsr(fmd_hdl_t *, fmd_event_t *, nvlist_t *, + const char *, cmd_errcl_t); +extern cmd_evdisp_t opl_cmd_ue_cpu_det_cpu(fmd_hdl_t *, fmd_event_t *, + nvlist_t *, const char *, cmd_errcl_t); +extern cmd_evdisp_t opl_cmd_ue_cpu_det_io(fmd_hdl_t *, fmd_event_t *, + nvlist_t *, const char *, cmd_errcl_t); + +extern cmd_evdisp_t opl_cmd_mac_common(fmd_hdl_t *, fmd_event_t *, nvlist_t *, + const char *, cmd_errcl_t); +extern cmd_evdisp_t opl_cmd_cpu_hdlr_mem(fmd_hdl_t *, fmd_event_t *, nvlist_t *, + const char *, cmd_errcl_t); +extern cmd_evdisp_t opl_cmd_io_hdlr_mem(fmd_hdl_t *, fmd_event_t *, nvlist_t *, + const char *, cmd_errcl_t); + +extern nvlist_t *opl_cmd_cpu_asru_create(uint32_t, uint8_t); +extern nvlist_t *opl_cmd_cpu_rsrc_create(fmd_hdl_t *, uint32_t); +extern opl_cpu_list_t *opl_alloc_struct(fmd_hdl_t *, uint32_t, int); +extern void opl_free_struct(fmd_hdl_t *, opl_cpu_list_t *); +extern uint8_t opl_avg(uint_t, uint_t); + +extern cmd_evdisp_t opl_cpuue_handler(fmd_hdl_t *, fmd_event_t *, + const char *, const char *, cmd_ptrsubtype_t, cmd_cpu_t *, cmd_case_t *, + uint8_t); + +#define CPU_EREPORT_STRING "ereport.cpu.SPARC64-VI." +#define OPL_CMU_SIGN "CMU" +#define OPL_CHASSIS_DEFAULT "0" +#define OPL_CPU_FRU_FMRI FM_FMRI_SCHEME_HC":///" \ + FM_FMRI_LEGACY_HC"="OPL_CMU_SIGN +#define STR_BUFLEN 32 +#define LIST_SIZE 5 + +/* + * Mask for getting the fault address + * from MARKEDID in UBC Memory UE + * Log Register (Oberon) + */ +#define UBC_UE_ADR_MASK 0x00007FFFFFFFFFFFULL + +/* + * To indicate if the CPU/IO handler is to be used. + */ +#define CMD_OPL_HDLR_CPU 1 +#define CMD_OPL_HDLR_IO 2 + +/* + * Macors for dealing with "core", "chip" + * or "strand" related operations. + */ +#define IS_STRAND 0 +#define IS_CORE 1 +#define IS_CHIP 2 +#define STRAND_UPPER_BOUND 1 +#define CORE_UPPER_BOUND 1 + +#define COREID_SHIFT 1 +#define CHIPID_SHIFT 3 +#define STRAND_MASK 1 +#define CHIP_OR_CORE_MASK 3 + +/* + * This is to reference the Oberon + * UBC memory UE log register payload. + */ +#define OBERON_UBC_MUE "ubc-mue" + +#ifdef __cplusplus +} +#endif + +#endif /* _CMD_OPL_H */ diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,SPARC-Enterprise/Makefile b/usr/src/cmd/fm/topo/files/sparc/SUNW,SPARC-Enterprise/Makefile new file mode 100644 index 0000000000..9765254200 --- /dev/null +++ b/usr/src/cmd/fm/topo/files/sparc/SUNW,SPARC-Enterprise/Makefile @@ -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 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "%Z%%M% %I% %E% SMI" + +TOPOSUBDIR = SUNW,SPARC-Enterprise +TOPOFILES = platform.topo + +include ../../Makefile.com diff --git a/usr/src/cmd/fm/topo/files/sparc/SUNW,SPARC-Enterprise/platform.topo b/usr/src/cmd/fm/topo/files/sparc/SUNW,SPARC-Enterprise/platform.topo new file mode 100644 index 0000000000..4f282b8d6d --- /dev/null +++ b/usr/src/cmd/fm/topo/files/sparc/SUNW,SPARC-Enterprise/platform.topo @@ -0,0 +1,585 @@ +# +# 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. +# +#ident "%Z%%M% %I% %E% SMI" + +/lsb0 + PLAT-ASRU=hc:///component=LSB0 + PLAT-FRU=hc:///component=LSB0 +/lsb0/ioc0 + PLAT-ASRU=hc:///component=LSB0/IOC0 + PLAT-FRU=hc:///component=LSB0 +/lsb0/ioc0/hostbridge0/pciexrc[0] + DEV=/pci@0,600000 + DRIVER = px +/lsb0/ioc0/hostbridge0/pciexrc[1] + DEV=/pci@1,700000 + DRIVER = px +/lsb0/ioc0/hostbridge1/pciexrc[0] + DEV=/pci@2,600000 + DRIVER = px +/lsb0/ioc0/hostbridge1/pciexrc[1] + DEV=/pci@3,700000 + DRIVER = px + +/lsb0/ioc1 + PLAT-ASRU=hc:///component=LSB0/IOC1 + PLAT-FRU=hc:///component=LSB1 +/lsb0/ioc1/hostbridge0/pciexrc[0] + DEV=/pci@4,600000 + DRIVER = px +/lsb0/ioc1/hostbridge0/pciexrc[1] + DEV=/pci@5,700000 + DRIVER = px +/lsb0/ioc1/hostbridge1/pciexrc[0] + DEV=/pci@6,600000 + DRIVER = px +/lsb0/ioc1/hostbridge1/pciexrc[1] + DEV=/pci@7,700000 + DRIVER = px + +/lsb1 + PLAT-ASRU=hc:///component=LSB1 + PLAT-FRU=hc:///component=LSB1 +/lsb1/ioc0 + PLAT-ASRU=hc:///component=LSB1/IOC0 + PLAT-FRU=hc:///component=LSB0 +/lsb1/ioc0/hostbridge0/pciexrc[0] + DEV=/pci@16,600000 + DRIVER = px +/lsb1/ioc0/hostbridge0/pciexrc[1] + DEV=/pci@17,700000 + DRIVER = px +/lsb1/ioc0/hostbridge1/pciexrc[0] + DEV=/pci@18,600000 + DRIVER = px +/lsb1/ioc0/hostbridge1/pciexrc[1] + DEV=/pci@19,700000 + DRIVER = px + +/lsb1/ioc1 + PLAT-ASRU=hc:///component=LSB1/IOC1 + PLAT-FRU=hc:///component=LSB1 +/lsb1/ioc1/hostbridge0/pciexrc[0] + DEV=/pci@20,600000 + DRIVER = px +/lsb1/ioc1/hostbridge0/pciexrc[1] + DEV=/pci@21,700000 + DRIVER = px +/lsb1/ioc1/hostbridge1/pciexrc[0] + DEV=/pci@22,600000 + DRIVER = px +/lsb1/ioc1/hostbridge1/pciexrc[1] + DEV=/pci@23,700000 + DRIVER = px + +/lsb2 + PLAT-ASRU=hc:///component=LSB2 + PLAT-FRU=hc:///component=LSB2 +/lsb2/ioc0 + PLAT-ASRU=hc:///component=LSB2/IOC0 + PLAT-FRU=hc:///component=LSB0 +/lsb2/ioc0/hostbridge0/pciexrc[0] + DEV=/pci@32,600000 + DRIVER = px +/lsb2/ioc0/hostbridge0/pciexrc[1] + DEV=/pci@33,700000 + DRIVER = px +/lsb2/ioc0/hostbridge1/pciexrc[0] + DEV=/pci@34,600000 + DRIVER = px +/lsb2/ioc0/hostbridge1/pciexrc[1] + DEV=/pci@35,700000 + DRIVER = px + +/lsb2/ioc1 + PLAT-ASRU=hc:///component=LSB2/IOC1 + PLAT-FRU=hc:///component=LSB1 +/lsb2/ioc1/hostbridge0/pciexrc[0] + DEV=/pci@36,600000 + DRIVER = px +/lsb2/ioc1/hostbridge0/pciexrc[1] + DEV=/pci@37,700000 + DRIVER = px +/lsb2/ioc1/hostbridge1/pciexrc[0] + DEV=/pci@38,600000 + DRIVER = px +/lsb2/ioc1/hostbridge1/pciexrc[1] + DEV=/pci@39,700000 + DRIVER = px + +/lsb3 + PLAT-ASRU=hc:///component=LSB3 + PLAT-FRU=hc:///component=LSB3 +/lsb3/ioc0 + PLAT-ASRU=hc:///component=LSB3/IOC0 + PLAT-FRU=hc:///component=LSB0 +/lsb3/ioc0/hostbridge0/pciexrc[0] + DEV=/pci@48,600000 + DRIVER = px +/lsb3/ioc0/hostbridge0/pciexrc[1] + DEV=/pci@49,700000 + DRIVER = px +/lsb3/ioc0/hostbridge1/pciexrc[0] + DEV=/pci@50,600000 + DRIVER = px +/lsb3/ioc0/hostbridge1/pciexrc[1] + DEV=/pci@51,700000 + DRIVER = px + +/lsb3/ioc1 + PLAT-ASRU=hc:///component=LSB3/IOC1 + PLAT-FRU=hc:///component=LSB1 +/lsb3/ioc1/hostbridge0/pciexrc[0] + DEV=/pci@52,600000 + DRIVER = px +/lsb3/ioc1/hostbridge0/pciexrc[1] + DEV=/pci@53,700000 + DRIVER = px +/lsb3/ioc1/hostbridge1/pciexrc[0] + DEV=/pci@54,600000 + DRIVER = px +/lsb3/ioc1/hostbridge1/pciexrc[1] + DEV=/pci@55,700000 + DRIVER = px + +/lsb4 + PLAT-ASRU=hc:///component=LSB4 + PLAT-FRU=hc:///component=LSB4 +/lsb4/ioc0 + PLAT-ASRU=hc:///component=LSB4/IOC0 + PLAT-FRU=hc:///component=LSB0 +/lsb4/ioc0/hostbridge0/pciexrc[0] + DEV=/pci@64,600000 + DRIVER = px +/lsb4/ioc0/hostbridge0/pciexrc[1] + DEV=/pci@65,700000 + DRIVER = px +/lsb4/ioc0/hostbridge1/pciexrc[0] + DEV=/pci@66,600000 + DRIVER = px +/lsb4/ioc0/hostbridge1/pciexrc[1] + DEV=/pci@67,700000 + DRIVER = px + +/lsb4/ioc1 + PLAT-ASRU=hc:///component=LSB4/IOC1 + PLAT-FRU=hc:///component=LSB1 +/lsb4/ioc1/hostbridge0/pciexrc[0] + DEV=/pci@68,600000 + DRIVER = px +/lsb4/ioc1/hostbridge0/pciexrc[1] + DEV=/pci@69,700000 + DRIVER = px +/lsb4/ioc1/hostbridge1/pciexrc[0] + DEV=/pci@70,600000 + DRIVER = px +/lsb4/ioc1/hostbridge1/pciexrc[1] + DEV=/pci@71,700000 + DRIVER = px + +/lsb5 + PLAT-ASRU=hc:///component=LSB5 + PLAT-FRU=hc:///component=LSB5 +/lsb5/ioc0 + PLAT-ASRU=hc:///component=LSB5/IOC0 + PLAT-FRU=hc:///component=LSB0 +/lsb5/ioc0/hostbridge0/pciexrc[0] + DEV=/pci@80,600000 + DRIVER = px +/lsb5/ioc0/hostbridge0/pciexrc[1] + DEV=/pci@81,700000 + DRIVER = px +/lsb5/ioc0/hostbridge1/pciexrc[0] + DEV=/pci@82,600000 + DRIVER = px +/lsb5/ioc0/hostbridge1/pciexrc[1] + DEV=/pci@83,700000 + DRIVER = px + +/lsb5/ioc1 + PLAT-ASRU=hc:///component=LSB5/IOC1 + PLAT-FRU=hc:///component=LSB1 +/lsb5/ioc1/hostbridge0/pciexrc[0] + DEV=/pci@84,600000 + DRIVER = px +/lsb5/ioc1/hostbridge0/pciexrc[1] + DEV=/pci@85,700000 + DRIVER = px +/lsb5/ioc1/hostbridge1/pciexrc[0] + DEV=/pci@86,600000 + DRIVER = px +/lsb5/ioc1/hostbridge1/pciexrc[1] + DEV=/pci@87,700000 + DRIVER = px + +/lsb6 + PLAT-ASRU=hc:///component=LSB6 + PLAT-FRU=hc:///component=LSB6 +/lsb6/ioc0 + PLAT-ASRU=hc:///component=LSB6/IOC0 + PLAT-FRU=hc:///component=LSB0 +/lsb6/ioc0/hostbridge0/pciexrc[0] + DEV=/pci@96,600000 + DRIVER = px +/lsb6/ioc0/hostbridge0/pciexrc[1] + DEV=/pci@97,700000 + DRIVER = px +/lsb6/ioc0/hostbridge1/pciexrc[0] + DEV=/pci@98,600000 + DRIVER = px +/lsb6/ioc0/hostbridge1/pciexrc[1] + DEV=/pci@99,700000 + DRIVER = px + +/lsb6/ioc1 + PLAT-ASRU=hc:///component=LSB6/IOC1 + PLAT-FRU=hc:///component=LSB1 +/lsb6/ioc1/hostbridge0/pciexrc[0] + DEV=/pci@100,600000 + DRIVER = px +/lsb6/ioc1/hostbridge0/pciexrc[1] + DEV=/pci@101,700000 + DRIVER = px +/lsb6/ioc1/hostbridge1/pciexrc[0] + DEV=/pci@102,600000 + DRIVER = px +/lsb6/ioc1/hostbridge1/pciexrc[1] + DEV=/pci@103,700000 + DRIVER = px + +/lsb7 + PLAT-ASRU=hc:///component=LSB7 + PLAT-FRU=hc:///component=LSB7 +/lsb7/ioc0 + PLAT-ASRU=hc:///component=LSB7/IOC0 + PLAT-FRU=hc:///component=LSB0 +/lsb7/ioc0/hostbridge0/pciexrc[0] + DEV=/pci@112,600000 + DRIVER = px +/lsb7/ioc0/hostbridge0/pciexrc[1] + DEV=/pci@113,700000 + DRIVER = px +/lsb7/ioc0/hostbridge1/pciexrc[0] + DEV=/pci@114,600000 + DRIVER = px +/lsb7/ioc0/hostbridge1/pciexrc[1] + DEV=/pci@115,700000 + DRIVER = px + +/lsb7/ioc1 + PLAT-ASRU=hc:///component=LSB7/IOC1 + PLAT-FRU=hc:///component=LSB1 +/lsb7/ioc1/hostbridge0/pciexrc[0] + DEV=/pci@116,600000 + DRIVER = px +/lsb7/ioc1/hostbridge0/pciexrc[1] + DEV=/pci@117,700000 + DRIVER = px +/lsb7/ioc1/hostbridge1/pciexrc[0] + DEV=/pci@118,600000 + DRIVER = px +/lsb7/ioc1/hostbridge1/pciexrc[1] + DEV=/pci@119,700000 + DRIVER = px + +/lsb8 + PLAT-ASRU=hc:///component=LSB8 + PLAT-FRU=hc:///component=LSB8 +/lsb8/ioc0 + PLAT-ASRU=hc:///component=LSB8/IOC0 + PLAT-FRU=hc:///component=LSB0 +/lsb8/ioc0/hostbridge0/pciexrc[0] + DEV=/pci@128,600000 + DRIVER = px +/lsb8/ioc0/hostbridge0/pciexrc[1] + DEV=/pci@129,700000 + DRIVER = px +/lsb8/ioc0/hostbridge1/pciexrc[0] + DEV=/pci@130,600000 + DRIVER = px +/lsb8/ioc0/hostbridge1/pciexrc[1] + DEV=/pci@131,700000 + DRIVER = px + +/lsb8/ioc1 + PLAT-ASRU=hc:///component=LSB8/IOC1 + PLAT-FRU=hc:///component=LSB1 +/lsb8/ioc1/hostbridge0/pciexrc[0] + DEV=/pci@132,600000 + DRIVER = px +/lsb8/ioc1/hostbridge0/pciexrc[1] + DEV=/pci@133,700000 + DRIVER = px +/lsb8/ioc1/hostbridge1/pciexrc[0] + DEV=/pci@134,600000 + DRIVER = px +/lsb8/ioc1/hostbridge1/pciexrc[1] + DEV=/pci@135,700000 + DRIVER = px + +/lsb9 + PLAT-ASRU=hc:///component=LSB9 + PLAT-FRU=hc:///component=LSB9 +/lsb9/ioc0 + PLAT-ASRU=hc:///component=LSB9/IOC0 + PLAT-FRU=hc:///component=LSB0 +/lsb9/ioc0/hostbridge0/pciexrc[0] + DEV=/pci@144,600000 + DRIVER = px +/lsb9/ioc0/hostbridge0/pciexrc[1] + DEV=/pci@145,700000 + DRIVER = px +/lsb9/ioc0/hostbridge1/pciexrc[0] + DEV=/pci@146,600000 + DRIVER = px +/lsb9/ioc0/hostbridge1/pciexrc[1] + DEV=/pci@147,700000 + DRIVER = px + +/lsb9/ioc1 + PLAT-ASRU=hc:///component=LSB9/IOC1 + PLAT-FRU=hc:///component=LSB1 +/lsb9/ioc1/hostbridge0/pciexrc[0] + DEV=/pci@148,600000 + DRIVER = px +/lsb9/ioc1/hostbridge0/pciexrc[1] + DEV=/pci@149,700000 + DRIVER = px +/lsb9/ioc1/hostbridge1/pciexrc[0] + DEV=/pci@150,600000 + DRIVER = px +/lsb9/ioc1/hostbridge1/pciexrc[1] + DEV=/pci@151,700000 + DRIVER = px + +/lsb10 + PLAT-ASRU=hc:///component=LSB10 + PLAT-FRU=hc:///component=LSB10 +/lsb10/ioc0 + PLAT-ASRU=hc:///component=LSB10/IOC0 + PLAT-FRU=hc:///component=LSB0 +/lsb10/ioc0/hostbridge0/pciexrc[0] + DEV=/pci@160,600000 + DRIVER = px +/lsb10/ioc0/hostbridge0/pciexrc[1] + DEV=/pci@161,700000 + DRIVER = px +/lsb10/ioc0/hostbridge1/pciexrc[0] + DEV=/pci@162,600000 + DRIVER = px +/lsb10/ioc0/hostbridge1/pciexrc[1] + DEV=/pci@163,700000 + DRIVER = px + +/lsb10/ioc1 + PLAT-ASRU=hc:///component=LSB10/IOC1 + PLAT-FRU=hc:///component=LSB1 +/lsb10/ioc1/hostbridge0/pciexrc[0] + DEV=/pci@164,600000 + DRIVER = px +/lsb10/ioc1/hostbridge0/pciexrc[1] + DEV=/pci@165,700000 + DRIVER = px +/lsb10/ioc1/hostbridge1/pciexrc[0] + DEV=/pci@166,600000 + DRIVER = px +/lsb10/ioc1/hostbridge1/pciexrc[1] + DEV=/pci@167,700000 + DRIVER = px + +/lsb11 + PLAT-ASRU=hc:///component=LSB11 + PLAT-FRU=hc:///component=LSB11 +/lsb11/ioc0 + PLAT-ASRU=hc:///component=LSB11/IOC0 + PLAT-FRU=hc:///component=LSB0 +/lsb11/ioc0/hostbridge0/pciexrc[0] + DEV=/pci@176,600000 + DRIVER = px +/lsb11/ioc0/hostbridge0/pciexrc[1] + DEV=/pci@177,700000 + DRIVER = px +/lsb11/ioc0/hostbridge1/pciexrc[0] + DEV=/pci@178,600000 + DRIVER = px +/lsb11/ioc0/hostbridge1/pciexrc[1] + DEV=/pci@179,700000 + DRIVER = px + +/lsb11/ioc1 + PLAT-ASRU=hc:///component=LSB11/IOC1 + PLAT-FRU=hc:///component=LSB1 +/lsb11/ioc1/hostbridge0/pciexrc[0] + DEV=/pci@180,600000 + DRIVER = px +/lsb11/ioc1/hostbridge0/pciexrc[1] + DEV=/pci@181,700000 + DRIVER = px +/lsb11/ioc1/hostbridge1/pciexrc[0] + DEV=/pci@182,600000 + DRIVER = px +/lsb11/ioc1/hostbridge1/pciexrc[1] + DEV=/pci@183,700000 + DRIVER = px + +/lsb12 + PLAT-ASRU=hc:///component=LSB12 + PLAT-FRU=hc:///component=LSB12 +/lsb12/ioc0 + PLAT-ASRU=hc:///component=LSB12/IOC0 + PLAT-FRU=hc:///component=LSB0 +/lsb12/ioc0/hostbridge0/pciexrc[0] + DEV=/pci@192,600000 + DRIVER = px +/lsb12/ioc0/hostbridge0/pciexrc[1] + DEV=/pci@193,700000 + DRIVER = px +/lsb12/ioc0/hostbridge1/pciexrc[0] + DEV=/pci@194,600000 + DRIVER = px +/lsb12/ioc0/hostbridge1/pciexrc[1] + DEV=/pci@195,700000 + DRIVER = px + +/lsb12/ioc1 + PLAT-ASRU=hc:///component=LSB12/IOC1 + PLAT-FRU=hc:///component=LSB1 +/lsb12/ioc1/hostbridge0/pciexrc[0] + DEV=/pci@196,600000 + DRIVER = px +/lsb12/ioc1/hostbridge0/pciexrc[1] + DEV=/pci@197,700000 + DRIVER = px +/lsb12/ioc1/hostbridge1/pciexrc[0] + DEV=/pci@198,600000 + DRIVER = px +/lsb12/ioc1/hostbridge1/pciexrc[1] + DEV=/pci@199,700000 + DRIVER = px + +/lsb13 + PLAT-ASRU=hc:///component=LSB13 + PLAT-FRU=hc:///component=LSB13 +/lsb13/ioc0 + PLAT-ASRU=hc:///component=LSB13/IOC0 + PLAT-FRU=hc:///component=LSB0 +/lsb13/ioc0/hostbridge0/pciexrc[0] + DEV=/pci@208,600000 + DRIVER = px +/lsb13/ioc0/hostbridge0/pciexrc[1] + DEV=/pci@209,700000 + DRIVER = px +/lsb13/ioc0/hostbridge1/pciexrc[0] + DEV=/pci@210,600000 + DRIVER = px +/lsb13/ioc0/hostbridge1/pciexrc[1] + DEV=/pci@211,700000 + DRIVER = px + +/lsb13/ioc1 + PLAT-ASRU=hc:///component=LSB13/IOC1 + PLAT-FRU=hc:///component=LSB1 +/lsb13/ioc1/hostbridge0/pciexrc[0] + DEV=/pci@212,600000 + DRIVER = px +/lsb13/ioc1/hostbridge0/pciexrc[1] + DEV=/pci@213,700000 + DRIVER = px +/lsb13/ioc1/hostbridge1/pciexrc[0] + DEV=/pci@214,600000 + DRIVER = px +/lsb13/ioc1/hostbridge1/pciexrc[1] + DEV=/pci@215,700000 + DRIVER = px + +/lsb14 + PLAT-ASRU=hc:///component=LSB14 + PLAT-FRU=hc:///component=LSB14 +/lsb14/ioc0 + PLAT-ASRU=hc:///component=LSB14/IOC0 + PLAT-FRU=hc:///component=LSB0 +/lsb14/ioc0/hostbridge0/pciexrc[0] + DEV=/pci@224,600000 + DRIVER = px +/lsb14/ioc0/hostbridge0/pciexrc[1] + DEV=/pci@225,700000 + DRIVER = px +/lsb14/ioc0/hostbridge1/pciexrc[0] + DEV=/pci@226,600000 + DRIVER = px +/lsb14/ioc0/hostbridge1/pciexrc[1] + DEV=/pci@227,700000 + DRIVER = px + +/lsb14/ioc1 + PLAT-ASRU=hc:///component=LSB14/IOC1 + PLAT-FRU=hc:///component=LSB1 +/lsb14/ioc1/hostbridge0/pciexrc[0] + DEV=/pci@228,600000 + DRIVER = px +/lsb14/ioc1/hostbridge0/pciexrc[1] + DEV=/pci@229,700000 + DRIVER = px +/lsb14/ioc1/hostbridge1/pciexrc[0] + DEV=/pci@230,600000 + DRIVER = px +/lsb14/ioc1/hostbridge1/pciexrc[1] + DEV=/pci@231,700000 + DRIVER = px + +/lsb15 + PLAT-ASRU=hc:///component=LSB15 + PLAT-FRU=hc:///component=LSB15 +/lsb15/ioc0 + PLAT-ASRU=hc:///component=LSB15/IOC0 + PLAT-FRU=hc:///component=LSB0 +/lsb15/ioc0/hostbridge0/pciexrc[0] + DEV=/pci@240,600000 + DRIVER = px +/lsb15/ioc0/hostbridge0/pciexrc[1] + DEV=/pci@241,700000 + DRIVER = px +/lsb15/ioc0/hostbridge1/pciexrc[0] + DEV=/pci@242,600000 + DRIVER = px +/lsb15/ioc0/hostbridge1/pciexrc[1] + DEV=/pci@243,700000 + DRIVER = px + +/lsb15/ioc1 + PLAT-ASRU=hc:///component=LSB15/IOC1 + PLAT-FRU=hc:///component=LSB1 +/lsb15/ioc1/hostbridge0/pciexrc[0] + DEV=/pci@244,600000 + DRIVER = px +/lsb15/ioc1/hostbridge0/pciexrc[1] + DEV=/pci@245,700000 + DRIVER = px +/lsb15/ioc1/hostbridge1/pciexrc[0] + DEV=/pci@246,600000 + DRIVER = px +/lsb15/ioc1/hostbridge1/pciexrc[1] + DEV=/pci@247,700000 + DRIVER = px + diff --git a/usr/src/cmd/mdb/sparc/kmdb/kmdb_kdi_isadep.c b/usr/src/cmd/mdb/sparc/kmdb/kmdb_kdi_isadep.c index 1d46481cfc..c82095ada5 100644 --- a/usr/src/cmd/mdb/sparc/kmdb/kmdb_kdi_isadep.c +++ b/usr/src/cmd/mdb/sparc/kmdb/kmdb_kdi_isadep.c @@ -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,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -82,6 +81,9 @@ kdi_init_cpus_cb(pnode_t node, void *arg, void *result) int cpu_freq; #ifndef sun4v + /* Get the real cpu property node if needed */ + node = kmdb_prom_getcpu_propnode(node); + /* * data cache */ diff --git a/usr/src/cmd/mdb/sparc/kmdb/kmdb_promif_isadep.c b/usr/src/cmd/mdb/sparc/kmdb/kmdb_promif_isadep.c index 58f6cf72ba..6928665e6f 100644 --- a/usr/src/cmd/mdb/sparc/kmdb/kmdb_promif_isadep.c +++ b/usr/src/cmd/mdb/sparc/kmdb/kmdb_promif_isadep.c @@ -113,7 +113,7 @@ walk_cpus_cb(pnode_t node, void *arg, void *result) walk_cpu_data_t *wcd = arg; /* - * Sun4v dosen't support port_id on guest. + * Sun4v doesn't support port_id on guest. */ #ifndef sun4v int port_id; @@ -155,6 +155,31 @@ kmdb_prom_enter_mon(void) prom_enter_mon(); } +#ifndef sun4v +pnode_t +kmdb_prom_getcpu_propnode(pnode_t node) +{ + int val; + pnode_t pnode; + char name[OBP_MAXPROPNAME]; + + + /* + * Check for the CMT case where cpu nodes are "strand" nodes + * In this case, the "cpu node" properties are contained in + * its parent "core" node. + */ + if (prom_getprop(node, "portid", (caddr_t)&val) == -1 && + prom_getprop(node, "upa-portid", (caddr_t)&val) == -1 && + prom_getprop((pnode = prom_parentnode(node)), + "name", name) != -1 && + strcmp(name, "core") == 0) + return (pnode); + + return (node); +} +#endif /* sun4v */ + void kmdb_prom_exit_to_mon(void) { diff --git a/usr/src/cmd/mdb/sparc/kmdb/kmdb_promif_isadep.h b/usr/src/cmd/mdb/sparc/kmdb/kmdb_promif_isadep.h index f2d160aefe..1af9ef083a 100644 --- a/usr/src/cmd/mdb/sparc/kmdb/kmdb_promif_isadep.h +++ b/usr/src/cmd/mdb/sparc/kmdb/kmdb_promif_isadep.h @@ -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,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -46,6 +45,10 @@ extern void kmdb_prom_exit_to_mon(void); extern void kmdb_prom_interpret(const char *); extern int kmdb_prom_getprop(pnode_t, char *, caddr_t); +#ifndef sun4v +extern pnode_t kmdb_prom_getcpu_propnode(pnode_t); +#endif /* sun4v */ + /* private to promif */ extern int kmdb_prom_translate_virt(uintptr_t, physaddr_t *); diff --git a/usr/src/cmd/netadm/iu.ap.sh b/usr/src/cmd/netadm/iu.ap.sh index 093616fd32..8f4c1b8d50 100644 --- a/usr/src/cmd/netadm/iu.ap.sh +++ b/usr/src/cmd/netadm/iu.ap.sh @@ -3,9 +3,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. @@ -21,14 +20,14 @@ # CDDL HEADER END # # -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T # All Rights Reserved -#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.3 */ +#ident "%Z%%M% %I% %E% SMI" case "$MACH" in "i386" ) @@ -70,6 +69,7 @@ case "$MACH" in ttymux -1 0 ldterm ttcompat ipsecesp -1 0 ipsecesp ipsecah -1 0 ipsecah + oplmsu 0 0 ldterm ttcompat " >iu.ap ;; * ) diff --git a/usr/src/cmd/prtdscp/Makefile b/usr/src/cmd/prtdscp/Makefile new file mode 100644 index 0000000000..8aa5fac510 --- /dev/null +++ b/usr/src/cmd/prtdscp/Makefile @@ -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 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# +# usr/src/cmd/prtdscp/Makefile +# + +SUBDIRS = sparc + +all := TARGET= all +install := TARGET= install +clean := TARGET= clean +clobber := TARGET= clobber +lint := TARGET= lint +_msg := TARGET= _msg + +.KEEP_STATE: + +all install lint clean clobber _msg: $(SUBDIRS) + +$(SUBDIRS): FRC + @cd $@; pwd; $(MAKE) $(TARGET) + +FRC: diff --git a/usr/src/cmd/prtdscp/req.flg b/usr/src/cmd/prtdscp/req.flg new file mode 100644 index 0000000000..aa7df21bd4 --- /dev/null +++ b/usr/src/cmd/prtdscp/req.flg @@ -0,0 +1,28 @@ +#!/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 +# +# +# ident "%Z%%M% %I% %E% SMI" +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. + +echo_file usr/src/lib/libdscp/libdscp.h diff --git a/usr/src/cmd/prtdscp/sparc/Makefile b/usr/src/cmd/prtdscp/sparc/Makefile new file mode 100644 index 0000000000..84733b8f09 --- /dev/null +++ b/usr/src/cmd/prtdscp/sparc/Makefile @@ -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 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# +# usr/src/cmd/prtdscp/sparc/Makefile +# + +SUBDIRS = sun4u + +all := TARGET= all +install := TARGET= install +clean := TARGET= clean +clobber := TARGET= clobber +lint := TARGET= lint +_msg := TARGET= _msg + +.KEEP_STATE: + +all install lint clean clobber _msg: $(SUBDIRS) + +$(SUBDIRS): FRC + @cd $@; pwd; $(MAKE) $(TARGET) + +FRC: diff --git a/usr/src/cmd/prtdscp/sparc/sun4u/Makefile b/usr/src/cmd/prtdscp/sparc/sun4u/Makefile new file mode 100644 index 0000000000..76a57c3a1f --- /dev/null +++ b/usr/src/cmd/prtdscp/sparc/sun4u/Makefile @@ -0,0 +1,69 @@ +# +# 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. +# +# ident "%Z%%M% %I% %E% SMI" +# +# usr/src/cmd/prtdscp/sparc/sun4u/Makefile +# + +PROG= prtdscp +ROOTFS_PROG= $(PROG) +PLATFORM= SUNW,SPARC-Enterprise + +CLASS= 32 +SRCS= $(PROG:%=%.c) +OBJS= $(PROG:%=%.o) + +include ../../../Makefile.cmd +include ../../../../Makefile.psm + +LDLIBS += -ldscp -lnsl + +CFLAGS += $(CCVERBOSE) + +LDFLAGS += -L$(USR_PSM_LIB_DIR) +LDFLAGS += -R\$$ORIGIN/../lib + +LINT_FLAGS= -c -Nlevel=4 -Ncheck $($(CONCURR_MODE)_FLAGS) + +.KEEP_STATE: + +# Definitions for installation of the program +FILEMODE= 0755 +OWNER= root +GROUP= sys +ROOTPSMPROG = $(USR_PSM_SBIN_DIR)/$(PROG) + +all: $(ROOTFS_PROG) + +install: all .WAIT $(ROOTPSMPROG) + +clean: + $(RM) $(PROG) $(OBJS) + +lint: + $(LINT) $(LINT_FLAGS) $(CPPFLAGS) $(SRCS) + +include ../../../Makefile.targ +include ../../../../Makefile.psm.targ diff --git a/usr/src/cmd/prtdscp/sparc/sun4u/prtdscp.c b/usr/src/cmd/prtdscp/sparc/sun4u/prtdscp.c new file mode 100644 index 0000000000..11d31afa50 --- /dev/null +++ b/usr/src/cmd/prtdscp/sparc/sun4u/prtdscp.c @@ -0,0 +1,280 @@ +/* + * 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 <stdlib.h> +#include <stdarg.h> +#include <strings.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <libintl.h> +#include <locale.h> +#include <libdscp.h> + +#if !defined(TEXT_DOMAIN) +#define TEXT_DOMAIN "SYS_TEST" +#endif + +#define OPT_SP 1 +#define OPT_DOMAIN 2 + +static void usage(void); +static void parse_options(int, char **, int *); +static int get_address(int, char *); +static void trace(char *, ...); +static void err(char *, ...); +static char *dscp_strerror(int); + +static int verbose = 0; + +int +main(int argc, char **argv) +{ + int options; + char saddr[INET_ADDRSTRLEN]; + char daddr[INET_ADDRSTRLEN]; + + (void) setlocale(LC_ALL, ""); + (void) textdomain(TEXT_DOMAIN); + + parse_options(argc, argv, &options); + + /* + * Get the desired IP addresses. + */ + if ((options & OPT_SP) != 0) { + trace(gettext("Looking up SP address...\n")); + if (get_address(DSCP_ADDR_REMOTE, saddr) < 0) { + trace(gettext("Lookup failed. Aborting.\n")); + exit(-1); + } + } + if ((options & OPT_DOMAIN) != 0) { + trace(gettext("Looking up domain address...\n")); + if (get_address(DSCP_ADDR_LOCAL, daddr) < 0) { + trace(gettext("Lookup failed. Aborting.\n")); + exit(-1); + } + } + + /* + * Print the IP addresses. + */ + if (options == OPT_SP) { + (void) printf("%s\n", saddr); + } else if (options == OPT_DOMAIN) { + (void) printf("%s\n", daddr); + } else { + (void) printf(gettext("Domain Address: %s\n"), daddr); + (void) printf(gettext("SP Address: %s\n"), saddr); + } + + return (0); +} + +/* + * parse_options() + * + * Parse the commandline options. + */ +static void +parse_options(int argc, char **argv, int *options) +{ + int i; + int c; + extern int opterr; + extern int optopt; + + /* + * Unless told otherwise, print everything. + */ + *options = (OPT_SP | OPT_DOMAIN); + + /* + * Skip this routine if no options exist. + */ + if (argc == 1) { + return; + } + + /* + * Scan for the -h option separately, so that + * other commandline options are ignored. + */ + for (i = 1; i < argc; i++) { + if (strcmp(argv[i], "-h") == 0) { + usage(); + exit(0); + } + } + + /* + * Disable the built-in error reporting, so that + * error messages can be properly internationalized. + */ + opterr = 0; + + /* + * The main loop for parsing options. + */ + while ((c = getopt(argc, argv, "vsd")) != -1) { + switch (c) { + case 'v': + verbose = 1; + break; + case 's': + if (*options == OPT_DOMAIN) { + err(gettext("cannot use -s and -d together")); + usage(); + exit(-1); + } + *options = OPT_SP; + break; + case 'd': + if (*options == OPT_SP) { + err(gettext("cannot use -s and -d together")); + usage(); + exit(-1); + } + *options = OPT_DOMAIN; + break; + default: + err(gettext("invalid option -%c"), optopt); + usage(); + exit(-1); + } + } +} + +/* + * usage() + * + * Print a brief synopsis of the program's usage. + */ +static void +usage(void) +{ + (void) printf(gettext("Usage: prtdscp -h \n")); + (void) printf(gettext(" prtdscp [-v] [-s|-d]\n")); +} + +/* + * get_address() + * + * Retrieve a DSCP IP address using libdscp. + */ +static int +get_address(int which, char *addr) +{ + int len; + int error; + struct sockaddr_in *sin; + struct sockaddr saddr; + + error = dscpAddr(0, which, &saddr, &len); + if (error != DSCP_OK) { + err(gettext("dscpAddr() failed: %s"), dscp_strerror(error)); + return (-1); + } + + /* LINTED pointer cast may result in improper alignment */ + sin = (struct sockaddr_in *)&saddr; + if (inet_ntop(AF_INET, &(sin->sin_addr), addr, sizeof (*sin)) == NULL) { + err(gettext("address string conversion failed.")); + return (-1); + } + + return (0); +} + +/* + * trace() + * + * Print tracing statements to stderr when in verbose mode. + */ +/*PRINTFLIKE1*/ +static void +trace(char *fmt, ...) +{ + va_list args; + + if (verbose != 0) { + va_start(args, fmt); + (void) vfprintf(stderr, fmt, args); + va_end(args); + } +} + +/* + * err() + * + * Print error messages to stderr. + */ +/*PRINTFLIKE1*/ +static void +err(char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + + (void) fprintf(stderr, gettext("ERROR: ")); + (void) vfprintf(stderr, fmt, args); + (void) fprintf(stderr, "\n"); + + va_end(args); +} + +/* + * dscp_strerror() + * + * Convert a DSCP error value into a localized string. + */ +static char * +dscp_strerror(int error) +{ + switch (error) { + case DSCP_OK: + return (gettext("Success.")); + case DSCP_ERROR: + return (gettext("General error.")); + case DSCP_ERROR_ALREADY: + return (gettext("Socket already bound.")); + case DSCP_ERROR_INVALID: + return (gettext("Invalid arguments.")); + case DSCP_ERROR_NOENT: + return (gettext("No entry found.")); + case DSCP_ERROR_DB: + return (gettext("Error reading database.")); + case DSCP_ERROR_REJECT: + return (gettext("Connection rejected.")); + default: + return (gettext("Unknown failure.")); + } +} diff --git a/usr/src/cmd/sckmd/Makefile b/usr/src/cmd/sckmd/Makefile index 3ba00c0d94..83c86d6a93 100644 --- a/usr/src/cmd/sckmd/Makefile +++ b/usr/src/cmd/sckmd/Makefile @@ -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. @@ -22,23 +21,37 @@ # #pragma ident "%Z%%M% %I% %E% SMI" # -# Copyright (c) 2000 by Sun Microsystems, Inc. -# All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. # # cmd/sckmd/Makefile # -SUBDIRS = sparc +PROG = sckmd +MANIFEST = $(PROG).xml +SVCMETHOD = svc-$(PROG) -all := TARGET= all -install := TARGET= install -clean := TARGET= clean -clobber := TARGET= clobber -lint := TARGET= lint +include ../Makefile.cmd + +SUBDIRS = sparc + +ROOTMANIFESTDIR = $(ROOTSVCPLATFORMSUN4U) + +all := TARGET= all +install := TARGET= install +clean := TARGET= clean +clobber := TARGET= clobber +lint := TARGET= lint + +$(ROOTMANIFEST) := FILEMODE = 444 .KEEP_STATE: -all install lint clean clobber: $(SUBDIRS) +all lint clean clobber: $(SUBDIRS) + +install: $(SUBDIRS) $(ROOTMANIFEST) $(ROOTSVCMETHOD) + +check: $(CHKMANIFEST) $(SUBDIRS): FRC @cd $@; pwd; $(MAKE) $(TARGET) diff --git a/usr/src/cmd/sckmd/sckmd.xml b/usr/src/cmd/sckmd/sckmd.xml new file mode 100644 index 0000000000..0d85468e40 --- /dev/null +++ b/usr/src/cmd/sckmd/sckmd.xml @@ -0,0 +1,89 @@ +<?xml version="1.0"?> +<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1"> +<!-- + Copyright 2006 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 + + ident "%Z%%M% %I% %E% SMI" + + NOTE: This service manifest is not editable; its contents will + be overwritten by package or patch operations, including + operating system upgrade. Make customizations in a different + file. +--> + +<service_bundle type='manifest' name='SUNWsckmu.u:sckmd'> + +<service name='platform/sun4u/sckmd' type='service' version='1'> + + <create_default_instance enabled='false' /> + + <single_instance /> + + <dependency + name='network' + grouping='require_any' + restart_on='error' + type='service'> + <service_fmri value='svc:/milestone/network' /> + </dependency> + + <dependency + name='local-filesystems' + type='service' + grouping='require_all' + restart_on='none'> + <service_fmri value='svc:/system/filesystem/local' /> + </dependency> + + <exec_method + type='method' + name='start' + exec='/lib/svc/method/svc-sckmd' + timeout_seconds='60' /> + + <exec_method + type='method' + name='stop' + exec=':kill -9' + timeout_seconds='60' /> + + <property_group name='application' type='framework'> + <propval name='auto_enable' type='boolean' value='true' /> + </property_group> + + <stability value='Evolving' /> + + <template> + <common_name> + <loctext xml:lang='C'> + key management daemon + </loctext> + </common_name> + <documentation> + <manpage title='sckmd' section='1M' + manpath='/usr/share/man' /> + </documentation> + </template> +</service> + +</service_bundle> diff --git a/usr/src/cmd/sckmd/sparc/sun4u/Makefile b/usr/src/cmd/sckmd/sparc/sun4u/Makefile index 12e769c865..b73b2e3992 100644 --- a/usr/src/cmd/sckmd/sparc/sun4u/Makefile +++ b/usr/src/cmd/sckmd/sparc/sun4u/Makefile @@ -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,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" @@ -30,7 +29,7 @@ PROG= sckmd -PLATFORM= SUNW,Sun-Fire-15000 +PLATFORM= sun4u CLASS= 32 @@ -66,58 +65,25 @@ LINT_FLAGS= -c -Nlevel=4 -Ncheck # LDLIBS += -lsocket -lipsecutil - -# -# Definitions for building init scripts -# -SHPROG = sckm -SHPROG_STARTPRIO = 70 -SHPROG_KILLPRIO = 42 - -ROOTINIT_D = $(ROOTETC)/init.d -ROOTRC0_D = $(ROOTETC)/rc0.d -ROOTRCS_D = $(ROOTETC)/rcS.d -ROOTRC1_D = $(ROOTETC)/rc1.d -ROOTRC2_D = $(ROOTETC)/rc2.d - -ROOTINIT_D_SHPROG = $(ROOTINIT_D)/$(SHPROG) -ROOTRCLINKS = $(ROOTRC0_D)/K$(SHPROG_KILLPRIO)$(SHPROG) \ - $(ROOTRCS_D)/K$(SHPROG_KILLPRIO)$(SHPROG) \ - $(ROOTRC1_D)/K$(SHPROG_KILLPRIO)$(SHPROG) \ - $(ROOTRC2_D)/S$(SHPROG_STARTPRIO)$(SHPROG) - -$(ROOTINIT_D_SHPROG) $(ROOTRCLINKS) := FILEMODE = 744 - - # # Build rules # .KEEP_STATE: -all: $(PROG) $(SHPROG) +all: $(PROG) $(PROG): $(OBJS) $(LINK.c) $(OBJS) -o $@ $(LDLIBS) $(POST_PROCESS) -install: all .WAIT $(USRPSMPROG) $(ROOTINIT_D_SHPROG) $(ROOTRCLINKS) +install: all .WAIT $(USRPSMPROG) lint: $(LINT) $(LINT_FLAGS) $(CPPFLAGS) $(LINT_SRCS) clean: - $(RM) $(PROG) $(SHPROG) $(OBJS) *.po $(LINT_FILES) core - - -# -# Build rules for init scripts -# -$(ROOTINIT_D)/%: % - $(INS.file) - -$(ROOTRCLINKS): $(ROOTINIT_D_SHPROG) - $(RM) $@; $(LN) $(ROOTINIT_D_SHPROG) $@ + $(RM) $(PROG) $(OBJS) *.po $(LINT_FILES) core include ../../../Makefile.targ diff --git a/usr/src/cmd/sckmd/sparc/sun4u/sckmd.c b/usr/src/cmd/sckmd/sparc/sun4u/sckmd.c index c8df4a766b..f528322f39 100644 --- a/usr/src/cmd/sckmd/sparc/sun4u/sckmd.c +++ b/usr/src/cmd/sckmd/sparc/sun4u/sckmd.c @@ -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,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -63,7 +62,7 @@ #define OPT_STR "" #endif /* SCKMD_DEBUG */ -#define SCKM_DEV "/dev/sckmdrv" +#define KM_DEV "/dev/kmdrv" #define SCKMD_MAX_MSG_SIZE 1024 #define SCKMD_ERR_MSG_SIZE 512 @@ -163,8 +162,8 @@ main(int argc, char **argv) } /* open driver */ - if ((fd = open(SCKM_DEV, O_RDONLY)) == -1) { - sckmd_log(LOG_ERR, "error initializing sckm driver: %s\n", + if ((fd = open(KM_DEV, O_RDONLY)) == -1) { + sckmd_log(LOG_ERR, "error initializing km driver: %s\n", strerror(errno)); exit(1); } diff --git a/usr/src/cmd/sckmd/svc-sckmd b/usr/src/cmd/sckmd/svc-sckmd new file mode 100644 index 0000000000..99f81a0b3e --- /dev/null +++ b/usr/src/cmd/sckmd/svc-sckmd @@ -0,0 +1,51 @@ +#!/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 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +# +# Startup script for the Key Management Daemon +# + +. /lib/svc/share/smf_include.sh + +platform=${_INIT_UTS_PLATFORM:-`/sbin/uname -i`} +starcat="SUNW,Sun-Fire-15000" +opl="SUNW,SPARC-Enterprise" +fjopl="FJSV,SPARC-Enterprise" +tmpopl="SUNW,OPL-Enterprise" +sckmd="/usr/platform/sun4u/lib/sckmd" + +if [ ${platform} = "${starcat}" -o \ + ${platform} = "${opl}" -o \ + ${platform} = "${fjopl}" -o \ + ${platform} = "${tmpopl}" ]; then + if [ -x ${sckmd} ]; then + ${sckmd} + exit $SMF_EXIT_OK + fi +fi +exit $SMF_EXIT_MON_OFFLINE diff --git a/usr/src/cmd/svc/profile/Makefile b/usr/src/cmd/svc/profile/Makefile index ad7e537edc..1c86ca7681 100644 --- a/usr/src/cmd/svc/profile/Makefile +++ b/usr/src/cmd/svc/profile/Makefile @@ -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,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" @@ -44,6 +43,7 @@ PROFILESRCS = \ ns_nis.xml \ ns_nisplus.xml \ ns_none.xml \ + platform_SUNW,SPARC-Enterprise.xml \ platform_SUNW,Sun-Fire-15000.xml \ platform_SUNW,Sun-Fire-880.xml \ platform_SUNW,Sun-Fire.xml \ diff --git a/usr/src/cmd/svc/profile/platform_SUNW,SPARC-Enterprise.xml b/usr/src/cmd/svc/profile/platform_SUNW,SPARC-Enterprise.xml new file mode 100644 index 0000000000..14bc2b1e70 --- /dev/null +++ b/usr/src/cmd/svc/profile/platform_SUNW,SPARC-Enterprise.xml @@ -0,0 +1,47 @@ +<?xml version='1.0'?> +<!DOCTYPE service_bundle SYSTEM '/usr/share/lib/xml/dtd/service_bundle.dtd.1'> +<!-- + Copyright 2006 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 + + ident "%Z%%M% %I% %E% SMI" + + NOTE: This service profile is not editable; its contents will be + overwritten by package or patch operations, including operating + system upgrade. + + SPARC-Enterprise platform service profile. +--> +<service_bundle type='profile' name='default'> + <service name='platform/sun4u/dcs' version='1' type='service'> + <instance name='default' enabled='true'/> + </service> + <service name='platform/sun4u/efdaemon' version='1' type='service'> + <instance name='default' enabled='true'/> + </service> + <service name='platform/sun4u/sckmd' version='1' type='service'> + <instance name='default' enabled='true'/> + </service> + <service name='platform/sun4u/dscp' version='1' type='service'> + <instance name='default' enabled='true'/> + </service> +</service_bundle> diff --git a/usr/src/cmd/svc/profile/platform_SUNW,Sun-Fire-15000.xml b/usr/src/cmd/svc/profile/platform_SUNW,Sun-Fire-15000.xml index 31a5e66a52..1f8b61f2e8 100644 --- a/usr/src/cmd/svc/profile/platform_SUNW,Sun-Fire-15000.xml +++ b/usr/src/cmd/svc/profile/platform_SUNW,Sun-Fire-15000.xml @@ -1,15 +1,14 @@ <?xml version='1.0'?> <!DOCTYPE service_bundle SYSTEM '/usr/share/lib/xml/dtd/service_bundle.dtd.1'> <!-- - Copyright 2005 Sun Microsystems, Inc. All rights reserved. + Copyright 2006 Sun Microsystems, Inc. All rights reserved. Use is subject to license terms. CDDL HEADER START The contents of this file are subject to the terms of the - Common Development and Distribution License, Version 1.0 only - (the "License"). You may not use this file except in compliance - with the License. + 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. @@ -39,8 +38,10 @@ <service name='platform/sun4u/dcs' version='1' type='service'> <instance name='default' enabled='true'/> </service> - <service name='platform/sun4u/efdaemon' version='1' - type='service'> + <service name='platform/sun4u/efdaemon' version='1' type='service'> + <instance name='default' enabled='true'/> + </service> + <service name='platform/sun4u/sckmd' version='1' type='service'> <instance name='default' enabled='true'/> </service> </service_bundle> diff --git a/usr/src/lib/Makefile b/usr/src/lib/Makefile index a46006f5d5..b6caadbd20 100644 --- a/usr/src/lib/Makefile +++ b/usr/src/lib/Makefile @@ -221,6 +221,7 @@ SUBDIRS += \ sparc_SUBDIRS= .WAIT \ efcode \ libc_psr .WAIT \ + libdscp \ libprtdiag .WAIT \ libprtdiag_psr \ librsc \ @@ -379,6 +380,7 @@ $(CLOSED_BUILD)HDRSUBDIRS += \ $(CLOSED)/lib/smartcard sparc_HDRSUBDIRS= \ + libdscp \ libwrsmconf all := TARGET= all diff --git a/usr/src/lib/efcode/Makefile b/usr/src/lib/efcode/Makefile index 4806e7a9bc..660a81d0e2 100644 --- a/usr/src/lib/efcode/Makefile +++ b/usr/src/lib/efcode/Makefile @@ -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,16 +19,16 @@ # CDDL HEADER END # # -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -# -# ident "%Z%%M% %I% %E% SMI" +#ident "%Z%%M% %I% %E% SMI" # include ../Makefile.lib -SUBDIRS = engine fcdriver extend packages pci gp2 upa interpreter efdaemon +SUBDIRS = engine fcdriver extend packages pci gp2 upa interpreter efdaemon \ + jupiter TESTDIRS = fcode_test EFCODEDIRS= $(ROOTLIBDIR)/efcode $(ROOTLIBDIR)/efcode/$(MACH64) @@ -62,10 +61,10 @@ FRC: # Interdependencies between shared objects follow. # -extend fcdriver packages pci gp2 upa interpreter efdaemon: engine +extend fcdriver packages pci gp2 upa interpreter efdaemon jupiter: engine fcdriver: packages -gp2 pci interpreter: fcdriver +gp2 pci interpreter jupiter: fcdriver interpreter: packages extend diff --git a/usr/src/lib/efcode/engine/package.c b/usr/src/lib/efcode/engine/package.c index b32773f45d..be241d01ac 100644 --- a/usr/src/lib/efcode/engine/package.c +++ b/usr/src/lib/efcode/engine/package.c @@ -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) 2000 by Sun Microsystems, Inc. - * All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" @@ -461,6 +460,8 @@ dollar_open_package(fcode_env_t *env) if (ok) { open_package(env); } else { + (void) POP(DS); + (void) POP(DS); PUSH(DS, 0); } } diff --git a/usr/src/lib/efcode/jupiter/Makefile b/usr/src/lib/efcode/jupiter/Makefile new file mode 100644 index 0000000000..2cb77e4732 --- /dev/null +++ b/usr/src/lib/efcode/jupiter/Makefile @@ -0,0 +1,28 @@ +# +# 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. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.subdirs diff --git a/usr/src/lib/efcode/jupiter/Makefile.com b/usr/src/lib/efcode/jupiter/Makefile.com new file mode 100644 index 0000000000..4e005dd494 --- /dev/null +++ b/usr/src/lib/efcode/jupiter/Makefile.com @@ -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 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +OBJECTS = jupiter.o +LIBRARY = lfc_jupiter.a +SYMLINKS = lfc_jupiter_jupiter.so + +include ../../Makefile.efcode + +CPPFLAGS += -I$(SRC)/uts/sun4 -I$(SRC)/uts/sun4u diff --git a/usr/src/lib/efcode/jupiter/jupiter.c b/usr/src/lib/efcode/jupiter/jupiter.c new file mode 100644 index 0000000000..2fc159bc20 --- /dev/null +++ b/usr/src/lib/efcode/jupiter/jupiter.c @@ -0,0 +1,437 @@ +/* + * 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 <stdlib.h> +#include <strings.h> + +#include <fcode/private.h> +#include <fcode/log.h> + +#include <fcdriver/fcdriver.h> + +#include <sys/opl_cfg.h> + +/* VA for HardWare Descriptor */ +static hwd_cmu_chan_t hwd_va_cmu; +static hwd_leaf_t hwd_va_pci; + +/* Macro to get I/O portid */ +#define DO_GET_IO_PORTID(env, lo, hi, portid) \ + PUSH(DS, lo); \ + PUSH(DS, hi); \ + do_get_io_portid(env); \ + portid = (uint32_t)POP(DS) + +fstack_t +mem_map_in(fcode_env_t *env, fstack_t hi, fstack_t lo, fstack_t len) +{ + private_data_t *pdp = DEVICE_PRIVATE(env); + fc_cell_t virt; + fstack_t mcookie = NULL; + char *service = "map-in"; + int error; + int offset = 0; + + /* + * The calculation of the offset, lo and len are left here + * due to historical precedence. + */ + + offset = lo & PAGEOFFSET; + lo &= PAGEMASK; + len = (len + offset + PAGEOFFSET) & PAGEMASK; + + error = fc_run_priv(pdp->common, service, 3, 1, fc_size2cell(len), + fc_uint32_t2cell(hi), fc_uint32_t2cell(lo), &virt); + + if (error) + throw_from_fclib(env, 1, "jupiter:%s: failed\n", service); + + mcookie = mapping_to_mcookie(virt, len, NULL, NULL); + + if (mcookie == NULL) + throw_from_fclib(env, 1, + "jupiter:%s: mapping_to_mcookie failed\n", service); + + mcookie += offset; + + debug_msg(DEBUG_REG_ACCESS, "jupiter:%s: %llx -> %x\n", service, + (long long)virt, (uint32_t)mcookie); + + return (mcookie); +} + +static void +mem_map_out(fcode_env_t *env, fstack_t mcookie, fstack_t len) +{ + private_data_t *pdp = DEVICE_PRIVATE(env); + fc_cell_t virt; + char *service = "map-out"; + int error; + int offset; + + /* + * The calculation of the offset, lo and len are left here + * due to historical precedence. + */ + + offset = mcookie & PAGEOFFSET; + mcookie &= PAGEMASK; + len = (len + offset + PAGEOFFSET) & PAGEMASK; + + if (!is_mcookie(mcookie)) { + log_message(MSG_ERROR, "jupiter:%s: %x not an mcookie!\n", + service, (int)mcookie); + virt = mcookie; + } else { + virt = mcookie_to_addr(mcookie); + debug_msg(DEBUG_REG_ACCESS, "jupiter:%s: %x -> %llx\n", + service, (int)mcookie, (long long)virt); + delete_mapping(mcookie); + } + + error = fc_run_priv(pdp->common, service, 2, 0, + fc_size2cell(len), virt); + if (error) + log_message(MSG_ERROR, "jupiter:%s: failed\n", service); +} + +static void +do_map_in(fcode_env_t *env) +{ + fstack_t phi, plo, len, addr; + + CHECK_DEPTH(env, 3, "jupiter:map-in"); + len = POP(DS); + phi = POP(DS); + plo = POP(DS); + addr = mem_map_in(env, phi, plo, len); + PUSH(DS, addr); +} + +static void +do_map_out(fcode_env_t *env) +{ + fstack_t addr, len; + + CHECK_DEPTH(env, 2, "jupiter:map-out"); + len = POP(DS); + addr = POP(DS); + mem_map_out(env, addr, len); +} + +static void +do_get_io_portid(fcode_env_t *env) +{ + fstack_t phi, plo; + unsigned int portid, lsb, ch, leaf; + + CHECK_DEPTH(env, 2, "jupiter:get-portid"); + + phi = POP(DS); + plo = POP(DS); + + lsb = OPL_ADDR_TO_LSB(phi); + ch = OPL_ADDR_TO_CHANNEL(phi); + leaf = OPL_ADDR_TO_LEAF(phi, plo); + + portid = OPL_IO_PORTID(lsb, ch, leaf); + + debug_msg(DEBUG_REG_ACCESS, "jupiter:get-portid ( %x %x ) -> %x\n", + (int)phi, (int)plo, (int)portid); + PUSH(DS, portid); +} + +static void +do_encode_unit(fcode_env_t *env) +{ + char enc_buf[64]; + fstack_t hi, lo; + uint32_t id; + long long off; + + CHECK_DEPTH(env, 2, "jupiter:encode-unit"); + + hi = POP(DS); + lo = POP(DS); + off = (long long)(((hi & 0x1F) << 32) | lo); + + /* Convert physical address to portid */ + DO_GET_IO_PORTID(env, lo, hi, id); + + if (off) { + (void) sprintf(enc_buf, "%x,%llx", id, off); + } else { + (void) sprintf(enc_buf, "%x", id); + } + + debug_msg(DEBUG_REG_ACCESS, "jupiter:encode_unit ( %x %x ) -> '%s'\n", + (uint32_t)hi, (uint32_t)lo, enc_buf); + + push_a_string(env, STRDUP(enc_buf)); +} + +static void +do_decode_unit(fcode_env_t *env) +{ + uint32_t hi; + long long lo; + unsigned int portid, lsb, ch; + char *buf; + + CHECK_DEPTH(env, 2, "jupiter:decode-unit"); + + buf = pop_a_string(env, NULL); + if (sscanf(buf, "%x,%llx", &portid, &lo) != 2) { + if (sscanf(buf, "%x", &portid) != 1) { + throw_from_fclib(env, 1, "jupiter:decode_unit:%s", + buf); + } + lo = 0; + } + + lsb = OPL_IO_PORTID_TO_LSB(portid); + ch = OPL_PORTID_TO_CHANNEL(portid); + hi = OPL_ADDR_HI(lsb, ch); + + debug_msg(DEBUG_REG_ACCESS, + "jupiter:decode_unit ( '%s' ) -> %x %llx\n", buf, hi, lo); + + PUSH(DS, (fstack_t)lo); + PUSH(DS, (fstack_t)hi); +} + +static void +do_device_id(fcode_env_t *env) +{ + common_data_t *cdp = COMMON_PRIVATE(env); + char *buf = NULL; + uint32_t hi; + long long lo; + uint32_t portid, ch, leaf; + + CHECK_DEPTH(env, 2, "jupiter:device-id"); + + hi = POP(DS); + lo = POP(DS); + + portid = 0; + if (cdp && cdp->fc.unit_address && + ((buf = strdup(cdp->fc.unit_address)) != NULL)) { + /* + * Get portid number from unit_address + * Because of no leaf information in physical address + */ + if (sscanf(buf, "%x,%llx", &portid, &lo) != 2) { + if (sscanf(buf, "%x", &portid) != 1) { + throw_from_fclib(env, 1, + "jupiter:do_device_id: invalid %s", buf); + } + } + } else { + /* + * Non existence unit_address case. + * Convert physical address to portid. + */ + throw_from_fclib(env, 1, + "jupiter:do_device_id: failed unit address"); + DO_GET_IO_PORTID(env, lo, hi, portid); + } + + debug_msg(DEBUG_FIND_FCODE, + "jupiter:do_device_id:(%x,%llx)\n", portid, lo); + + /* Pick up each ID from portid */ + ch = OPL_PORTID_TO_CHANNEL(portid); + leaf = OPL_PORTID_TO_LEAF(portid); + + if (ch == OPL_CMU_CHANNEL) { + /* + * CMU-CH: PCICMU CHANNEL + */ + debug_msg(DEBUG_FIND_FCODE, + "jupiter:do_device_id:cmu-ch\n"); + push_a_string(env, "cmu-ch"); + } else if (OPL_OBERON_CHANNEL(ch) && OPL_VALID_LEAF(leaf)) { + /* + * PCI-CH: Oberon Leaves CHANNEL + */ + if (leaf) { + /* Leaf B */ + debug_msg(DEBUG_FIND_FCODE, + "jupiter:do_device_id:jup-oberon-pci1\n"); + push_a_string(env, "jup-oberon-pci1"); + } else { + /* Leaf A */ + debug_msg(DEBUG_FIND_FCODE, + "jupiter:do_device_id:jup-oberon-pci0\n"); + push_a_string(env, "jup-oberon-pci0"); + } + } else { + /* Not matched to any channels */ + throw_from_fclib(env, 1, + "jupiter:do_device_id: invalid portid %x", portid); + push_a_string(env, ""); + } + + /* Free the duplicated buf */ + if (buf != NULL) + free(buf); +} + +static void +do_get_hwd_va(fcode_env_t *env) +{ + private_data_t *pdp = DEVICE_PRIVATE(env); + char *service = "get-hwd-va"; + char *buf; + uint32_t portid = 0; + int ch; + int error; + fc_cell_t status; + void *hwd_va; + + CHECK_DEPTH(env, 2, "jupiter:get-hwd-va"); + + /* Get a portid with string format */ + buf = pop_a_string(env, NULL); + + /* Convert to the integer from the string */ + if (sscanf(buf, "%x", &portid) != 1) { + throw_from_fclib(env, 1, "jupiter:%s: invalid portid", + service); + } + + ch = OPL_PORTID_TO_CHANNEL(portid); + if (!OPL_VALID_CHANNEL(ch)) { + throw_from_fclib(env, 1, "jupiter:%s: invalid poritd", + service); + hwd_va = 0; + goto out; + } + + if (ch == OPL_CMU_CHANNEL) { + hwd_va = (void *)&hwd_va_cmu; + } else { + hwd_va = (void *)&hwd_va_pci; + } + + /* + * Get the virtual address of hwd specified with portid. + */ + error = fc_run_priv(pdp->common, service, 2, 1, + fc_uint32_t2cell(portid), fc_ptr2cell(hwd_va), &status); + + if (error || !status) + throw_from_fclib(env, 1, "jupiter:%s: failed\n", service); + +out: + PUSH(DS, (fstack_t)hwd_va); +} + +static void +do_get_intrp_name(fcode_env_t *env) +{ + /* + * Just pass the "eFCode" string. + */ + + debug_msg(DEBUG_FIND_FCODE, + "jupiter: do_get_intrp_name: eFCode\n"); + + push_a_string(env, "eFCode"); +} + +static void +do_master_interrupt(fcode_env_t *env) +{ + int portid; + token_t xt; + + CHECK_DEPTH(env, 2, "jupiter:master-interrput"); + portid = POP(DS); + xt = POP(DS); + + PUSH(DS, FALSE); + debug_msg(DEBUG_REG_ACCESS, + "jupiter:master-interrupt ( %x %x ) -> %x\n", + portid, xt, (int)FALSE); +} + +static void +do_register_vector_entry(fcode_env_t *env) +{ + int ign, ino, level; + + CHECK_DEPTH(env, 3, "jupiter:register-vector-entry"); + ign = POP(DS); + ino = POP(DS); + level = POP(DS); + + PUSH(DS, FALSE); + debug_msg(DEBUG_REG_ACCESS, + "jupiter:register-vector-entry ( %x %x %x ) -> %x\n", + ign, ino, level, (int)FALSE); +} + +static void +do_get_interrupt_target(fcode_env_t *env) +{ + int mid = -1; + + PUSH(DS, mid); + debug_msg(DEBUG_REG_ACCESS, + "jupiter:get-interrupt-target ( ) -> %x\n", mid); +} + + +#pragma init(_init) + +static void +_init(void) +{ + fcode_env_t *env = initial_env; + + ASSERT(env); + ASSERT(env->current_device); + NOTICE; + + create_int_prop(env, "#address-cells", 2); + + FORTH(0, "map-in", do_map_in); + FORTH(0, "map-out", do_map_out); + FORTH(0, "get-portid", do_get_io_portid); + FORTH(0, "decode-unit", do_decode_unit); + FORTH(0, "encode-unit", do_encode_unit); + FORTH(0, "device-id", do_device_id); + FORTH(0, "get-hwd-va", do_get_hwd_va); + FORTH(0, "get-fcinterp-name", do_get_intrp_name); + FORTH(0, "master-interrupt", do_master_interrupt); + FORTH(0, "register-vector-entry", do_register_vector_entry); + FORTH(0, "get-interrupt-target", do_get_interrupt_target); +} diff --git a/usr/src/lib/efcode/jupiter/sparcv9/Makefile b/usr/src/lib/efcode/jupiter/sparcv9/Makefile new file mode 100644 index 0000000000..99913538b5 --- /dev/null +++ b/usr/src/lib/efcode/jupiter/sparcv9/Makefile @@ -0,0 +1,33 @@ +# +# 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. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.com +include $(SRC)/lib/Makefile.lib.64 + +DYNFLAGS += $(FCODE64) $(FCDRIVER64) + +install: all $(ROOTLIBS64) $(ROOTSYMLINKS64) diff --git a/usr/src/lib/efcode/packages/memalloc.c b/usr/src/lib/efcode/packages/memalloc.c index 3bb4a928ff..5e8d365d17 100644 --- a/usr/src/lib/efcode/packages/memalloc.c +++ b/usr/src/lib/efcode/packages/memalloc.c @@ -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,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 1999-2003 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -35,11 +34,9 @@ #include <fcdriver/fcdriver.h> -static void schizo_vtop(fcode_env_t *, fc_cell_t, fstack_t *, fstack_t *); - /* - * claim under /openprom/client-services is only used by schizo Fcode, we - * call "schizo,claim-memory" service. + * claim under /openprom/client-services is used by schizo and oberon Fcode, we + * call "claim-memory" service. */ void claim(fcode_env_t *env) @@ -50,11 +47,11 @@ claim(fcode_env_t *env) fc_cell_t vaddr; int error; - CHECK_DEPTH(env, 3, "schizo,claim-memory"); + CHECK_DEPTH(env, 3, "claim-memory"); hint = (void *)POP(DS); size = POP(DS); align = POP(DS); - error = fc_run_priv(env->private, "schizo,claim-memory", 3, 1, + error = fc_run_priv(env->private, "claim-memory", 3, 1, fc_int2cell(align), fc_size2cell(size), fc_ptr2cell(hint), &vaddr); if (error) throw_from_fclib(env, 1, "client-services/claim failed\n"); @@ -69,10 +66,10 @@ release(fcode_env_t *env) void *addr; int error; - CHECK_DEPTH(env, 2, "schizo,release-memory"); + CHECK_DEPTH(env, 2, "release-memory"); addr = (void *)POP(DS); size = POP(DS); - error = fc_run_priv(env->private, "schizo,release-memory", 2, 0, + error = fc_run_priv(env->private, "release-memory", 2, 0, fc_size2cell(size), fc_ptr2cell(addr)); if (error) throw_from_fclib(env, 1, "client-services/release failed\n"); @@ -86,9 +83,9 @@ fc_vtop(fcode_env_t *env) fc_cell_t physlo, physhi; int error; - CHECK_DEPTH(env, 1, "schizo,vtop"); + CHECK_DEPTH(env, 1, "vtop"); vaddr = (void *)POP(DS); - error = fc_run_priv(env->private, "schizo,vtop", 1, 2, + error = fc_run_priv(env->private, "vtop", 1, 2, fc_ptr2cell(vaddr), &physlo, &physhi); if (error) throw_from_fclib(env, 1, "fc_vtop: '>physical' failed\n"); diff --git a/usr/src/lib/libc_psr/Makefile b/usr/src/lib/libc_psr/Makefile index df8c308012..2521a042c0 100644 --- a/usr/src/lib/libc_psr/Makefile +++ b/usr/src/lib/libc_psr/Makefile @@ -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. @@ -22,7 +21,7 @@ # #ident "%Z%%M% %I% %E% SMI" # -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # lib/libc_psr/Makefile @@ -30,7 +29,7 @@ include ../Makefile.lib -SUBDIRS= sun4u sun4u-us3 sun4u_hwcap1 sun4u_hwcap2 sun4v sun4v_hwcap1 etc +SUBDIRS= sun4u sun4u-opl sun4u-us3 sun4u_hwcap1 sun4u_hwcap2 sun4v sun4v_hwcap1 etc all := TARGET= all install := TARGET= install diff --git a/usr/src/lib/libc_psr/spec/Makefile b/usr/src/lib/libc_psr/spec/Makefile index 175550e312..7742b756e6 100644 --- a/usr/src/lib/libc_psr/spec/Makefile +++ b/usr/src/lib/libc_psr/spec/Makefile @@ -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. @@ -22,12 +21,12 @@ # #pragma ident "%Z%%M% %I% %E% SMI" # -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # usr/src/lib/libc_psr/spec/Makefile -SUBDIRS= sun4u sun4u_hwcap1 sun4u_hwcap2 sun4v_hwcap1 +SUBDIRS= sun4u sun4u-opl sun4u_hwcap1 sun4u_hwcap2 sun4v_hwcap1 all := TARGET= all install := TARGET= install diff --git a/usr/src/lib/libc_psr/spec/sun4u-opl/Makefile b/usr/src/lib/libc_psr/spec/sun4u-opl/Makefile new file mode 100644 index 0000000000..e41b66e7f1 --- /dev/null +++ b/usr/src/lib/libc_psr/spec/sun4u-opl/Makefile @@ -0,0 +1,29 @@ +# +# 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 +# +# +#pragma ident "%Z%%M% %I% %E% SMI" +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# lib/libc_psr/spec/sun4u-opl/Makefile + +include $(SRC)/lib/Makefile.spec.arch diff --git a/usr/src/lib/libc_psr/spec/sun4u-opl/Makefile.links b/usr/src/lib/libc_psr/spec/sun4u-opl/Makefile.links new file mode 100644 index 0000000000..53c0bd026e --- /dev/null +++ b/usr/src/lib/libc_psr/spec/sun4u-opl/Makefile.links @@ -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 +# +#pragma ident "%Z%%M% %I% %E% SMI" +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# lib/libc_psr/spec/sun4u-opl/Makefile.links + +include $(SRC)/Makefile.psm + +MODULE = abi + +# +# links in /usr/platform +# +LINKED_PLATFORMS = SUNW,SPARC-Enterprise + +include $(SRC)/lib/libc_psr/spec/Makefile.com diff --git a/usr/src/lib/libc_psr/spec/sun4u-opl/c_psr-sparc.spec b/usr/src/lib/libc_psr/spec/sun4u-opl/c_psr-sparc.spec new file mode 100644 index 0000000000..ade9554bdc --- /dev/null +++ b/usr/src/lib/libc_psr/spec/sun4u-opl/c_psr-sparc.spec @@ -0,0 +1,66 @@ +# +# 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" +# +# lib/libc_psr/spec/sun4u-opl/c_psr-sparc.spec + +function memcmp extends libc/spec/gen.spec +arch sparc +version SUNWprivate_1.1 +end + +function _memcmp extends libc/spec/private.spec +arch sparc +version SUNWprivate_1.1 +end + +function memcpy extends libc/spec/gen.spec +arch sparc +version SUNWprivate_1.1 +end + +function _memcpy extends libc/spec/private.spec +arch sparc +version SUNWprivate_1.1 +end + +function memmove extends libc/spec/gen.spec +arch sparc +version SUNWprivate_1.1 +end + +function _memmove extends libc/spec/private.spec +arch sparc +version SUNWprivate_1.1 +end + +function memset extends libc/spec/gen.spec +arch sparc +version SUNWprivate_1.1 +end + +function _memset extends libc/spec/private.spec +arch sparc +version SUNWprivate_1.1 +end diff --git a/usr/src/lib/libc_psr/spec/sun4u-opl/c_psr-sparcv9.spec b/usr/src/lib/libc_psr/spec/sun4u-opl/c_psr-sparcv9.spec new file mode 100644 index 0000000000..07acdd7e66 --- /dev/null +++ b/usr/src/lib/libc_psr/spec/sun4u-opl/c_psr-sparcv9.spec @@ -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 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#pragma ident "%Z%%M% %I% %E% SMI" +# +# lib/libc_psr/spec/sun4u-opl/c_psr-sparcv9.spec + +function memcmp extends libc/spec/gen.spec +arch sparcv9 +version SUNWprivate_1.1 +end + +function _memcmp extends libc/spec/private.spec +arch sparcv9 +version SUNWprivate_1.1 +end + +function memcpy extends libc/spec/gen.spec +arch sparcv9 +version SUNWprivate_1.1 +end + +function _memcpy extends libc/spec/private.spec +arch sparcv9 +version SUNWprivate_1.1 +end + +function memmove extends libc/spec/gen.spec +arch sparcv9 +version SUNWprivate_1.1 +end + +function _memmove extends libc/spec/private.spec +arch sparcv9 +version SUNWprivate_1.1 +end + +function memset extends libc/spec/gen.spec +arch sparcv9 +version SUNWprivate_1.1 +end + +function _memset extends libc/spec/private.spec +arch sparcv9 +version SUNWprivate_1.1 +end diff --git a/usr/src/lib/libc_psr/spec/sun4u-opl/sparc/Makefile b/usr/src/lib/libc_psr/spec/sun4u-opl/sparc/Makefile new file mode 100644 index 0000000000..edd059ba21 --- /dev/null +++ b/usr/src/lib/libc_psr/spec/sun4u-opl/sparc/Makefile @@ -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 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#pragma ident "%Z%%M% %I% %E% SMI" +# +# lib/libc_psr/spec/sun4u-opl/sparc/Makefile + +.KEEP_STATE: + +LIBRARY = libc_psr.a +VERS = .1 + +PLATFORM= SUNW,SPARC-Enterprise +ALT_PLAT= sun4u-opl +CLASS = 32 + +OBJECTS = c_psr-$(MACH).o + +SPECVERS = -$(MACH) + +include $(SRC)/lib/Makefile.lib +include $(SRC)/lib/libc_psr/spec/$(ALT_PLAT)/Makefile.links + +# Uncomment the following if the linker complains +#sparc_C_PICFLAGS = -K PIC + +include $(SRC)/lib/Makefile.spec +include $(SRC)/lib/Makefile.spec.psm + +$(DISABLE_APPTRACE)install: $(ROOTABILIB) diff --git a/usr/src/lib/libc_psr/spec/sun4u-opl/sparcv9/Makefile b/usr/src/lib/libc_psr/spec/sun4u-opl/sparcv9/Makefile new file mode 100644 index 0000000000..557004d67e --- /dev/null +++ b/usr/src/lib/libc_psr/spec/sun4u-opl/sparcv9/Makefile @@ -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 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#pragma ident "%Z%%M% %I% %E% SMI" +# +# lib/libc_psr/spec/sun4u-opl/sparcv9/Makefile + +.KEEP_STATE: + +LIBRARY = libc_psr.a +VERS = .1 + +PLATFORM= SUNW,SPARC-Enterprise +ALT_PLAT= sun4u-opl +CLASS = 64 + +OBJECTS = c_psr-$(MACH64).o + +SPECVERS= -$(MACH64) + +include $(SRC)/lib/Makefile.lib +include $(SRC)/lib/Makefile.lib.64 +include $(SRC)/lib/libc_psr/spec/$(ALT_PLAT)/Makefile.links + +# Uncomment the following if the linker complains +#sparcv9_C_PICFLAGS = -K PIC + +include $(SRC)/lib/Makefile.spec +include $(SRC)/lib/Makefile.spec.psm + +$(DISABLE_APPTRACE)install: $(ROOTABILIB) diff --git a/usr/src/lib/libc_psr/spec/sun4u-opl/versions-sparc b/usr/src/lib/libc_psr/spec/sun4u-opl/versions-sparc new file mode 100644 index 0000000000..048669407d --- /dev/null +++ b/usr/src/lib/libc_psr/spec/sun4u-opl/versions-sparc @@ -0,0 +1,31 @@ +# +# 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" +# +# vers file for libc_psr/sun4u-opl/sparc +# +sparc { + SUNWprivate_1.1; +} diff --git a/usr/src/lib/libc_psr/spec/sun4u-opl/versions-sparcv9 b/usr/src/lib/libc_psr/spec/sun4u-opl/versions-sparcv9 new file mode 100644 index 0000000000..2c57d5f9db --- /dev/null +++ b/usr/src/lib/libc_psr/spec/sun4u-opl/versions-sparcv9 @@ -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 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#pragma ident "%Z%%M% %I% %E% SMI" +# +# vers file for libc_psr/sun4u-opl/sparcv9 +# +sparcv9 { + SUNWprivate_1.1; +} diff --git a/usr/src/lib/libc_psr/sun4u-opl/Makefile b/usr/src/lib/libc_psr/sun4u-opl/Makefile new file mode 100644 index 0000000000..65799c0b96 --- /dev/null +++ b/usr/src/lib/libc_psr/sun4u-opl/Makefile @@ -0,0 +1,61 @@ +# +# 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. +# +# ident "%Z%%M% %I% %E% SMI" +# +# lib/libc_psr/sun4u-opl/Makefile +# + +include ../../Makefile.lib + +PLATFORM= SUNW,SPARC-Enterprise +ALT_PLAT= sun4u-opl + +SUBDIRS= $(MACH) +SUBDIRS64= $(MACH64) + +all := TARGET= all +install := TARGET= install +clean := TARGET= clean +clobber := TARGET= clobber + +.KEEP_STATE: + +all install clean clobber : lib32 \ + $(BUILD64) lib64 + +lint: + @ $(ECHO) "Nothing to lint here: skipping" + +lib32: spec .WAIT $(SUBDIRS) + +lib64: $(SUBDIRS64) + +$(SUBDIRS) $(SUBDIRS64): FRC + @cd $@; pwd; $(MAKE) $(TARGET) + +spec: FRC + @cd ../spec/$(ALT_PLAT); pwd; $(MAKE) $(TARGET) + +FRC: diff --git a/usr/src/lib/libc_psr/sun4u-opl/Makefile.com b/usr/src/lib/libc_psr/sun4u-opl/Makefile.com new file mode 100644 index 0000000000..c2cb4edd2d --- /dev/null +++ b/usr/src/lib/libc_psr/sun4u-opl/Makefile.com @@ -0,0 +1,72 @@ +# +# 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. +# +# ident "%Z%%M% %I% %E% SMI" +# + +# +# Create default so empty rules don't +# confuse make +# + +LIBRARY = libc_psr.a +VERS = .1 + +include $(SRC)/lib/Makefile.lib +include $(SRC)/Makefile.psm + +# +# Since libc_psr is strictly assembly, deactivate the CTF build logic. +# +CTFCONVERT_POST = : +CTFMERGE_LIB = : + +LIBS = $(DYNLIB) +IFLAGS = -I$(SRC)/lib/libc/inc -I$(SRC)/uts/sun4u \ + -I$(ROOT)/usr/platform/sun4u/include +CPPFLAGS = -D_REENTRANT -D$(MACH) $(IFLAGS) $(CPPFLAGS.master) +ASDEFS = -D__STDC__ -D_ASM $(CPPFLAGS) +ASFLAGS = -P $(ASDEFS) + +# +# Used when building links in /platform/$(PLATFORM)/lib +# +LINKED_PLATFORMS = SUNW,SPARC-Enterprise + +# +# install rule +# +$(ROOT_PSM_LIB_DIR)/%: % $(ROOT_PSM_LIB_DIR) + $(INS.file) + +# +# build rules +# +pics/%.o: ../../$(PLATFORM)/common/%.s + $(AS) $(ASFLAGS) $< -o $@ + $(POST_PROCESS_O) + +pics/%.o: ../../$(COMPAT_PLAT)/common/%.s + $(AS) $(ASFLAGS) $< -o $@ + $(POST_PROCESS_O) diff --git a/usr/src/lib/libc_psr/sun4u-opl/common/memcpy.s b/usr/src/lib/libc_psr/sun4u-opl/common/memcpy.s new file mode 100644 index 0000000000..cf41195e78 --- /dev/null +++ b/usr/src/lib/libc_psr/sun4u-opl/common/memcpy.s @@ -0,0 +1,716 @@ +/* + * 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. + */ + +.ident "%Z%%M% %I% %E% SMI" + + .file "memcpy.s" +/* + * memcpy(s1, s2, len) + * + * Copy s2 to s1, always copy n bytes. + * Note: this C code does not work for overlapped copies. + * Memmove() and bcopy() do. + * + * Fast assembler language version of the following C-program for memcpy + * which represents the `standard' for the C-library. + * + * void * + * memcpy(void *s, const void *s0, size_t n) + * { + * if (n != 0) { + * char *s1 = s; + * const char *s2 = s0; + * do { + * *s1++ = *s2++; + * } while (--n != 0); + * } + * return (s); + * } + */ + +#include <sys/asm_linkage.h> +#include <sys/sun4asi.h> +#include <sys/trap.h> + +#define ICACHE_LINE_SIZE 32 +#define BLOCK_SIZE 64 +#define FPRS_FEF 0x4 + +#define SHORTCOPY 3 +#define SMALL_MAX 39 +#define MEDIUM_MAX 255 +#define MED_WMAX 256 /* max copy for medium word-aligned case */ +#define MED_MAX 65536 /* max copy for medium longword-aligned case */ + + ANSI_PRAGMA_WEAK(memmove,function) + ANSI_PRAGMA_WEAK(memcpy,function) + +#include "synonyms.h" + + ENTRY(memmove) + cmp %o1, %o0 ! if from address is >= to use forward copy + bgeu %ncc, .forcpy ! else use backward if ... + sub %o0, %o1, %o4 ! get difference of two addresses + cmp %o2, %o4 ! compare size and difference of addresses + bleu %ncc, .forcpy ! if size is bigger, do overlapped copy + nop + + ! + ! an overlapped copy that must be done "backwards" + ! +.ovbc: + mov %o0, %g1 ! save dest address for return val + add %o1, %o2, %o1 ! get to end of source space + add %o0, %o2, %o0 ! get to end of destination space + +.chksize: + cmp %o2, 8 + bgeu,pn %ncc, .dbalign + andcc %o0, 7, %g0 ! Is DST 8 byte aligned? + +.byte: +1: deccc %o2 ! decrement count + blu,pn %ncc, .exit ! loop until done + dec %o0 ! decrement to address + dec %o1 ! decrement from address + ldub [%o1], %o3 ! read a byte + ba 1b ! loop until done + stb %o3, [%o0] ! write byte + +.dbalign: + bz %ncc, .dbbck + nop + dec %o1 + dec %o0 + dec %o2 + ldub [%o1], %o3 + ba .chksize + stb %o3, [%o0] + +.dbbck: + rd %fprs, %o3 ! o3 = fprs + + ! if fprs.fef == 0, set it. Checking it, requires 2 instructions. + ! So set it anyway, without checking. + wr %g0, 0x4, %fprs ! fprs.fef = 1 + + alignaddr %o1, %g0, %o5 ! align src + ldd [%o5], %d0 ! get first 8 byte block + sub %o5, 8, %o5 + andn %o2, 7, %o4 + sub %o1, %o4, %o1 + +2: + sub %o0, 8, %o0 ! since we are at the end + ! when we first enter the loop + ldd [%o5], %d2 + sub %o2, 8, %o2 ! 8 less bytes to copy + sub %o5, 8, %o5 + cmp %o2, 8 ! do we have < 8 bytes remaining + faligndata %d2, %d0, %d8 ! extract 8 bytes out + std %d8, [%o0] ! store the current 8 bytes + bgeu,pt %ncc, 2b + fmovd %d2, %d0 + + and %o3, 0x4, %o3 ! fprs.du = fprs.dl = 0 + ba .byte + wr %o3, %g0, %fprs ! fprs = o3 restore fprs + +.exit: + retl + mov %g1, %o0 + SET_SIZE(memmove) + + + .align ICACHE_LINE_SIZE + ENTRY(memcpy) + ! adjust instruction alignment + nop ! Do not remove, these nops affect + nop ! icache alignment and performance +.forcpy: + prefetch [%o1], #n_reads + prefetch [%o0], #n_reads + cmp %o2, SMALL_MAX ! check for not small case + bgu,pn %ncc, .medium ! go to larger cases + mov %o0, %g1 ! save %o0 + cmp %o2, SHORTCOPY ! check for really short case + ble,pt %ncc, .smallleft ! + or %o0, %o1, %o3 ! prepare alignment check + andcc %o3, 0x3, %g0 ! test for alignment + bz,pt %ncc, .smallword ! branch to word aligned case + sub %o2, 3, %o2 ! adjust count to allow cc zero test +.smallnotalign4: + ldub [%o1], %o3 ! read byte + subcc %o2, 4, %o2 ! reduce count by 4 + stb %o3, [%o0] ! write byte + ldub [%o1+1], %o3 ! repeat for a total of 4 bytes + add %o1, 4, %o1 ! advance SRC by 4 + stb %o3, [%o0+1] + ldub [%o1-2], %o3 + add %o0, 4, %o0 ! advance DST by 4 + stb %o3, [%o0-2] + ldub [%o1-1], %o3 + bgu,pt %ncc, .smallnotalign4 ! loop til 3 or fewer bytes remain + stb %o3, [%o0-1] + add %o2, 3, %o2 ! restore count +.smallleft: + tst %o2 + bz,pt %ncc, .smallexit + nop +.smallleft3: ! 1, 2, or 3 bytes remain + ldub [%o1], %o3 ! load one byte + deccc %o2 ! reduce count for cc test + bz,pt %ncc, .smallexit + stb %o3, [%o0] ! store one byte + ldub [%o1+1], %o3 ! load second byte + deccc %o2 + bz,pt %ncc, .smallexit + stb %o3, [%o0+1] ! store second byte + ldub [%o1+2], %o3 ! load third byte + stb %o3, [%o0+2] ! store third byte + retl + mov %g1, %o0 ! restore %o0 + + .align 8 + nop ! affects loop icache alignment +.smallwords: + lduw [%o1], %o3 ! read word +.smallwordx: + subcc %o2, 8, %o2 ! update count + stw %o3, [%o0] ! write word + add %o1, 8, %o1 ! update SRC + lduw [%o1-4], %o3 ! read word + add %o0, 8, %o0 ! update DST + bgu,pt %ncc, .smallwords ! loop until done + stw %o3, [%o0-4] ! write word + addcc %o2, 7, %o2 ! restore count + bz,pt %ncc, .smallexit ! check for completion + nop + cmp %o2, 4 ! check for 4 or more bytes left + blt .smallleft3 ! if not, go to finish up + nop + lduw [%o1], %o3 + add %o1, 4, %o1 + subcc %o2, 4, %o2 + stw %o3, [%o0] + add %o0, 4, %o0 + bnz,pt %ncc, .smallleft3 + nop + retl + mov %g1, %o0 ! restore %o0 + +.smallword: + subcc %o2, 4, %o2 ! update count + bgu,pt %ncc, .smallwordx + lduw [%o1], %o3 ! read word + addcc %o2, 3, %o2 ! restore count + bz,pt %ncc, .smallexit + stw %o3, [%o0] ! write word + deccc %o2 ! reduce count for cc test + ldub [%o1+4], %o3 ! load one byte + bz,pt %ncc, .smallexit + stb %o3, [%o0+4] ! store one byte + ldub [%o1+5], %o3 ! load second byte + deccc %o2 + bz,pt %ncc, .smallexit + stb %o3, [%o0+5] ! store second byte + ldub [%o1+6], %o3 ! load third byte + stb %o3, [%o0+6] ! store third byte +.smallexit: + retl + mov %g1, %o0 ! restore %o0 + .align 16 +.medium: + neg %o0, %o5 + neg %o1, %o3 + andcc %o5, 7, %o5 ! bytes till DST 8 byte aligned + and %o3, 7, %o3 ! bytes till SRC 8 byte aligned + + bz %ncc, 2f + sub %o5, %o3, %o3 ! -(bytes till SRC aligned after DST aligned) + ! o3={-7, -6, ... 7} o3>0 => SRC overaligned + + sub %o2, %o5, %o2 ! update count + +1: + ldub [%o1], %o4 + deccc %o5 + inc %o1 + stb %o4, [%o0] + bgu,pt %ncc, 1b + inc %o0 + + ! Now DST is 8-byte aligned. o0, o1, o2 are current. + +2: + andcc %o1, 0x3, %g0 ! test alignment + prefetch [%o1 + (1 * BLOCK_SIZE)], #n_reads + bnz,pt %ncc, .mediumsetup ! branch to skip aligned cases + ! if src, dst not aligned + prefetch [%o0 + (1 * BLOCK_SIZE)], #n_reads + +/* + * Handle all cases where src and dest are aligned on word + * or long word boundaries. Use unrolled loops for better + * performance. This option wins over standard large data + * move when source and destination is in cache for medium + * to short data moves. + */ + andcc %o1, 0x7, %g0 ! test word alignment + prefetch [%o1 + (2 * BLOCK_SIZE)], #n_reads + bz,pt %ncc, .medlword ! branch to long word aligned case + prefetch [%o0 + (2 * BLOCK_SIZE)], #n_reads + + cmp %o2, MED_WMAX ! limit to store buffer size + bgu,pt %ncc, .mediumrejoin ! otherwise rejoin main loop + prefetch [%o1 + (3 * BLOCK_SIZE)], #n_reads + subcc %o2, 15, %o2 ! adjust length to allow cc test + prefetch [%o0 + (3 * BLOCK_SIZE)], #n_reads + ! for end of loop + ble,pt %ncc, .medw15 ! skip big loop if less than 16 + .empty +.medw16: + prefetch [%o1 + (4 * BLOCK_SIZE)], #n_reads + ld [%o1], %o4 ! load + subcc %o2, 16, %o2 ! decrement length count + prefetch [%o0 + (4 * BLOCK_SIZE)], #n_reads + stw %o4, [%o0] ! and store + ld [%o1+4], %o3 ! a block of 16 bytes + add %o1, 16, %o1 ! increase src ptr by 16 + stw %o3, [%o0+4] + ld [%o1-8], %o4 + add %o0, 16, %o0 ! increase dst ptr by 16 + stw %o4, [%o0-8] + ld [%o1-4], %o3 + bgu,pt %ncc, .medw16 ! repeat if at least 16 bytes left + stw %o3, [%o0-4] +.medw15: + addcc %o2, 15, %o2 ! restore count + bz,pt %ncc, .medwexit ! exit if finished + nop + cmp %o2, 8 + blt,pt %ncc, .medw7 ! skip if 7 or fewer bytes left + nop ! + ld [%o1], %o4 ! load 4 bytes + subcc %o2, 8, %o2 ! decrease count by 8 + stw %o4, [%o0] ! and store 4 bytes + add %o1, 8, %o1 ! increase src ptr by 8 + ld [%o1-4], %o3 ! load 4 bytes + add %o0, 8, %o0 ! increase dst ptr by 8 + stw %o3, [%o0-4] ! and store 4 bytes + bz %ncc, .medwexit ! exit if finished + nop +.medw7: ! count is ge 1, less than 8 + cmp %o2, 3 ! check for 4 bytes left + ble,pt %ncc, .medw3 ! skip if 3 or fewer bytes left + nop ! + ld [%o1], %o4 ! load 4 bytes + sub %o2, 4, %o2 ! decrease count by 4 + add %o1, 4, %o1 ! increase src ptr by 4 + stw %o4, [%o0] ! and store 4 bytes + add %o0, 4, %o0 ! increase dst ptr by 4 + tst %o2 ! check for zero bytes left + bz %ncc, .medwexit ! exit if finished + nop +.medw3: ! count is known to be 1, 2, or 3 + deccc %o2 ! reduce count by one + ldub [%o1], %o3 ! load one byte + bz,pt %ncc, .medwexit ! exit if last byte + stb %o3, [%o0] ! store one byte + ldub [%o1+1], %o3 ! load second byte + deccc %o2 ! reduce count by one + bz,pt %ncc, .medwexit ! exit if last byte + stb %o3, [%o0+1] ! store second byte + ldub [%o1+2], %o3 ! load third byte + stb %o3, [%o0+2] ! store third byte +.medwexit: + retl + mov %g1, %o0 ! restore %o0 + +/* + * Special case for handling when src and dest are both long word aligned + * and total data to move is between SMALL_MAX and MED_MAX bytes + */ + + .align 16 + nop +.medlword: ! long word aligned + ! length > SMALL_MAX + set MED_MAX, %o4 + cmp %o2, %o4 + bgu,pt %ncc, .mediumrejoin ! otherwise rejoin main loop + prefetch [%o1 + (3 * BLOCK_SIZE)], #n_reads + prefetch [%o0 + (3 * BLOCK_SIZE)], #n_reads + subcc %o2, 31, %o2 ! adjust length to allow cc test + ! for end of loop + ble,pt %ncc, .medl31 ! skip big loop if less than 32 + .empty +.medl32: + prefetch [%o1 + (4 * BLOCK_SIZE)], #n_reads + ldx [%o1], %o4 ! load + subcc %o2, 32, %o2 ! decrement length count + prefetch [%o0 + (4 * BLOCK_SIZE)], #n_reads + stx %o4, [%o0] ! and store + ldx [%o1+8], %o3 ! a block of 32 bytes + add %o1, 32, %o1 ! increase src ptr by 32 + stx %o3, [%o0+8] + ldx [%o1-16], %o4 + add %o0, 32, %o0 ! increase dst ptr by 32 + stx %o4, [%o0-16] + ldx [%o1-8], %o3 + bgu,pt %ncc, .medl32 ! repeat if at least 32 bytes left + stx %o3, [%o0-8] +.medl31: + addcc %o2, 16, %o2 ! adjust remaining count + ble,pt %ncc, .medl15 ! skip if 15 or fewer bytes left + nop ! + ldx [%o1], %o4 ! load and store 16 bytes + add %o1, 16, %o1 ! increase src ptr by 16 + stx %o4, [%o0] ! + sub %o2, 16, %o2 ! decrease count by 16 + ldx [%o1-8], %o3 ! + add %o0, 16, %o0 ! increase dst ptr by 16 + stx %o3, [%o0-8] +.medl15: + addcc %o2, 15, %o2 ! restore count + bz,pt %ncc, .medwexit ! exit if finished + nop + cmp %o2, 8 + blt,pt %ncc, .medw7 ! skip if 7 or fewer bytes left + nop + ldx [%o1], %o4 ! load 8 bytes + add %o1, 8, %o1 ! increase src ptr by 8 + stx %o4, [%o0] ! and store 8 bytes + subcc %o2, 8, %o2 ! decrease count by 8 + bz %ncc, .medwexit ! exit if finished + add %o0, 8, %o0 ! increase dst ptr by 8 + ba .medw7 + nop + + .align 8 +.mediumsetup: + prefetch [%o1 + (2 * BLOCK_SIZE)], #one_read + prefetch [%o1 + (3 * BLOCK_SIZE)], #one_read +.mediumrejoin: + rd %fprs, %o4 ! check for unused FPU + + add %o1, 8, %o1 ! prepare to round SRC upward + + sethi %hi(0x1234567f), %o5 ! For GSR.MASK + or %o5, 0x67f, %o5 + + andcc %o4, FPRS_FEF, %o4 ! test FEF, fprs.du = fprs.dl = 0 + prefetch [%o1 + (4 * BLOCK_SIZE)], #one_read + bz,a %ncc, 3f + wr %g0, FPRS_FEF, %fprs ! fprs.fef = 1 +3: + cmp %o2, MEDIUM_MAX + prefetch [%o1 + (5 * BLOCK_SIZE)], #one_read + bmask %o5, %g0, %g0 + + ! Compute o5 (number of bytes that need copying using the main loop). + ! First, compute for the medium case. + ! Then, if large case, o5 is replaced by count for block alignment. + ! Be careful not to read past end of SRC + ! Currently, o2 is the actual count remaining + ! o3 is how much sooner we'll cross the alignment boundary + ! in SRC compared to in DST + ! + ! Examples: Let # denote bytes that should not be accessed + ! Let x denote a byte already copied to align DST + ! Let . and - denote bytes not yet copied + ! Let | denote double alignment boundaries + ! + ! DST: ######xx|........|--------|..###### o2 = 18 + ! o0 + ! + ! o3 = -3: SRC: ###xx...|.....---|-----..#|######## o5 = 8 + ! o1 + ! + ! o3 = 0: SRC: ######xx|........|--------|..###### o5 = 16-8 = 8 + ! o1 + ! + ! o3 = +1: SRC: #######x|x.......|.-------|-..##### o5 = 16-8 = 8 + ! o1 + + or %g0, -8, %o5 + alignaddr %o1, %g0, %o1 ! set GSR.ALIGN and align o1 + + movrlz %o3, %g0, %o5 ! subtract 8 from o2+o3 only if o3>=0 + add %o5, %o2, %o5 + add %o5, %o3, %o5 + + bleu %ncc, 4f + andn %o5, 7, %o5 ! 8 byte aligned count + neg %o0, %o5 ! 'large' case + and %o5, BLOCK_SIZE-1, %o5 ! bytes till DST block aligned +4: + prefetch [%o1 + (6 * BLOCK_SIZE)], #one_read + brgez,a %o3, .beginmedloop + ldd [%o1-8], %d0 + + add %o1, %o3, %o1 ! back up o1 +5: + ldda [%o1]ASI_FL8_P, %d2 + inc %o1 + andcc %o1, 7, %g0 + bnz %ncc, 5b + bshuffle %d0, %d2, %d0 ! shifts d0 left 1 byte and or's in d2 + +.beginmedloop: + prefetch [%o1 + (7 * BLOCK_SIZE)], #one_read + tst %o5 + bz %ncc, .endmedloop + sub %o2, %o5, %o2 ! update count for later + + ! Main loop to write out doubles. Note: o5 & 7 == 0 + + ldx [%o1], %d2 + subcc %o5, 8, %o5 ! update local count + bz,pn %ncc, 1f + add %o1, 8, %o1 ! update SRC + +.medloop: + faligndata %d0, %d2, %d4 + ldd [%o1], %d0 + subcc %o5, 8, %o5 ! update local count + add %o1, 16, %o1 ! update SRC + std %d4, [%o0] + bz,pn %ncc, 2f + faligndata %d2, %d0, %d6 + ldd [%o1 - 8], %d2 + subcc %o5, 8, %o5 ! update local count + std %d6, [%o0 + 8] + bnz,pt %ncc, .medloop + add %o0, 16, %o0 ! update DST + +1: + faligndata %d0, %d2, %d4 + fmovd %d2, %d0 + std %d4, [%o0] + ba .endmedloop + add %o0, 8, %o0 + +2: + std %d6, [%o0 + 8] + sub %o1, 8, %o1 + add %o0, 16, %o0 + + +.endmedloop: + ! Currently, o1 is pointing to the next double-aligned byte in SRC + ! The 8 bytes starting at [o1-8] are available in d0 + ! At least one, and possibly all, of these need to be written. + + prefetch [%o1 + (8 * BLOCK_SIZE)], #one_read + cmp %o2, BLOCK_SIZE + bgu %ncc, .large ! otherwise, less than 16 bytes left + +#if 0 + + /* This code will use partial stores. */ + + mov %g0, %o5 + and %o3, 7, %o3 ! Number of bytes needed to completely + ! fill %d0 with good (unwritten) data. + + subcc %o2, 8, %o2 ! update count (maybe too much) + movl %ncc, %o2, %o5 + addcc %o3, %o5, %o5 ! extra bytes we can stuff into %d0 + sub %o3, %o5, %o3 ! update o3 (# bad bytes in %d0) + + bz %ncc, 2f + alignaddr %o3, %g0, %g0 ! set GSR.ALIGN + +1: + deccc %o5 + ldda [%o1]ASI_FL8_P, %d2 + inc %o1 + bgu %ncc, 1b + bshuffle %d0, %d2, %d0 ! shifts d0 left 1 byte and or's in d2 + +2: + not %o3 + faligndata %d0, %d0, %d0 ! shift bytes to the left + and %o3, 7, %o3 ! last byte to be stored in [%o0+%o3] + edge8n %g0, %o3, %o5 + stda %d0, [%o0]%o5, ASI_PST8_P + brlez %o2, .mediumexit + add %o0, %o3, %o0 ! update DST to last stored byte +3: + inc %o0 + deccc %o2 + ldub [%o1], %o3 + stb %o3, [%o0] + bgu %ncc, 3b + inc %o1 + +#else + + andcc %o3, 7, %o5 ! Number of bytes needed to completely + ! fill %d0 with good (unwritten) data. + bz %ncc, 2f + sub %o5, 8, %o3 ! -(number of good bytes in %d0) + cmp %o2, 8 + bl,a %ncc, 3f ! Not enough bytes to fill %d0 + add %o1, %o3, %o1 ! Back up %o1 + +1: + deccc %o5 + ldda [%o1]ASI_FL8_P, %d2 + inc %o1 + bgu %ncc, 1b + bshuffle %d0, %d2, %d0 ! shifts d0 left 1 byte and or's in d2 + +2: + subcc %o2, 8, %o2 + std %d0, [%o0] + bz %ncc, .mediumexit + add %o0, 8, %o0 +3: + ldub [%o1], %o3 + deccc %o2 + inc %o1 + stb %o3, [%o0] + bgu %ncc, 3b + inc %o0 +#endif + +.mediumexit: + wr %o4, %g0, %fprs ! fprs = o4 restore fprs + retl + mov %g1, %o0 + + + .align 8 +.large: + + ! %o0 I/O DST is 64-byte aligned + ! %o1 I/O 8-byte aligned (and we've set GSR.ALIGN) + ! %d0 I/O already loaded with SRC data from [%o1-8] + ! %o2 I/O count (number of bytes that need to be written) + ! %o3 I Not written. If zero, then SRC is double aligned. + ! %o4 I Not written. Holds fprs. + ! %o5 O The number of doubles that remain to be written. + + ! Load the rest of the current block + ! Recall that %o1 is further into SRC than %o0 is into DST + + prefetch [%o1 + (9 * BLOCK_SIZE)], #one_read + ldd [%o1], %f2 + ldd [%o1 + 0x8], %f4 + faligndata %f0, %f2, %f32 + ldd [%o1 + 0x10], %f6 + faligndata %f2, %f4, %f34 + ldd [%o1 + 0x18], %f8 + faligndata %f4, %f6, %f36 + ldd [%o1 + 0x20], %f10 + or %g0, -8, %o5 ! if %o3 >= 0, %o5 = -8 + faligndata %f6, %f8, %f38 + ldd [%o1 + 0x28], %f12 + movrlz %o3, %g0, %o5 ! if %o3 < 0, %o5 = 0 (needed later) + faligndata %f8, %f10, %f40 + ldd [%o1 + 0x30], %f14 + faligndata %f10, %f12, %f42 + ldd [%o1 + 0x38], %f0 + sub %o2, BLOCK_SIZE, %o2 ! update count + add %o1, BLOCK_SIZE, %o1 ! update SRC + + ! This point is 32-byte aligned since 24 instructions appear since + ! the previous alignment directive. + + + ! Main loop. Write previous block. Load rest of current block. + ! Some bytes will be loaded that won't yet be written. +1: + ldd [%o1], %f2 + faligndata %f12, %f14, %f44 + ldd [%o1 + 0x8], %f4 + faligndata %f14, %f0, %f46 + stda %f32, [%o0]ASI_BLK_P + sub %o2, BLOCK_SIZE, %o2 ! update count + ldd [%o1 + 0x10], %f6 + faligndata %f0, %f2, %f32 + ldd [%o1 + 0x18], %f8 + faligndata %f2, %f4, %f34 + ldd [%o1 + 0x20], %f10 + faligndata %f4, %f6, %f36 + ldd [%o1 + 0x28], %f12 + faligndata %f6, %f8, %f38 + ldd [%o1 + 0x30], %f14 + prefetch [%o1 + (2 * BLOCK_SIZE)], #n_reads + faligndata %f8, %f10, %f40 + ldd [%o1 + 0x38], %f0 + faligndata %f10, %f12, %f42 + prefetch [%o1 + (10 * BLOCK_SIZE)], #one_read + add %o0, BLOCK_SIZE, %o0 ! update DST + cmp %o2, BLOCK_SIZE + 8 + ! second prefetch important to correct for occasional dropped + prefetch [%o1 + (6 * BLOCK_SIZE) + 8], #one_read + bgu,pt %ncc, 1b + add %o1, BLOCK_SIZE, %o1 ! update SRC + + faligndata %f12, %f14, %f44 + faligndata %f14, %f0, %f46 + stda %f32, [%o0]ASI_BLK_P ! store 64 bytes, bypass cache + cmp %o2, BLOCK_SIZE + bne %ncc, 2f ! exactly 1 block remaining? + add %o0, BLOCK_SIZE, %o0 ! update DST + brz,a %o3, 3f ! is SRC double aligned? + ldd [%o1], %f2 + +2: + add %o5, %o2, %o5 ! %o5 was already set to 0 or -8 + add %o5, %o3, %o5 + + membar #StoreLoad|#StoreStore + + ba .beginmedloop + andn %o5, 7, %o5 ! 8 byte aligned count + + + ! This is when there is exactly 1 block remaining and SRC is aligned +3: + ldd [%o1 + 0x8], %f4 + ldd [%o1 + 0x10], %f6 + fsrc1 %f0, %f32 + ldd [%o1 + 0x18], %f8 + fsrc1 %f2, %f34 + ldd [%o1 + 0x20], %f10 + fsrc1 %f4, %f36 + ldd [%o1 + 0x28], %f12 + fsrc1 %f6, %f38 + ldd [%o1 + 0x30], %f14 + fsrc1 %f8, %f40 + fsrc1 %f10, %f42 + fsrc1 %f12, %f44 + fsrc1 %f14, %f46 + stda %f32, [%o0]ASI_BLK_P + membar #StoreLoad|#StoreStore + wr %o4, 0, %fprs + retl + mov %g1, %o0 + + SET_SIZE(memcpy) diff --git a/usr/src/lib/libc_psr/sun4u-opl/sparc/Makefile b/usr/src/lib/libc_psr/sun4u-opl/sparc/Makefile new file mode 100644 index 0000000000..2eb91a6117 --- /dev/null +++ b/usr/src/lib/libc_psr/sun4u-opl/sparc/Makefile @@ -0,0 +1,70 @@ +# +# 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. +# +# ident "%Z%%M% %I% %E% SMI" +# +# Platform specific Makefile for libc_psr. +# +PLATFORM = SUNW,SPARC-Enterprise +ALT_PLAT = sun4u-opl + +COMPAT_PLAT = sun4u-us3 +CLASS = 32 + +OBJECTS = memcpy.o memset.o memcmp.o + +include ../Makefile.com + +MAPDIR= ../../spec/$(ALT_PLAT)/$(MACH) +MAPFILE= $(MAPDIR)/mapfile-$(MACH) +MAPFILES= $(MAPFILE) $(MAPFILE-FLTR) +MAPOPTS= $(MAPFILES:%=-M %) +DYNFLAGS += $(MAPOPTS) +CLOBBERFILES += $(MAPFILE) +ASFLAGS += -xarch=v8plusb + +# Redefine shared object build rule to use $(LD) directly (this avoids .init +# and .fini sections being added). + +BUILD.SO= $(LD) -o $@ -G $(DYNFLAGS) $(PICS) $(LDLIBS) + +$(DYNLIB): $(MAPFILES) + +$(MAPFILE): + @cd $(MAPDIR); $(MAKE) `basename $@` + +.KEEP_STATE: + +MODULE = libc_psr.so.1 +LIBC_PSR_DIR = $(ROOT_PSM_LIB_DIR) +LIBC_PSR_LIB = $(LIBC_PSR_DIR)/$(MODULE) + +$(LIBC_PSR_DIRS): + -$(INS.dir.root.bin) + +all: $(LIBS) + +install: all $(LIBC_PSR_DIR) $(ROOT_PSM_LIBS) + +include ../../Makefile.targ diff --git a/usr/src/lib/libc_psr/sun4u-opl/sparcv9/Makefile b/usr/src/lib/libc_psr/sun4u-opl/sparcv9/Makefile new file mode 100644 index 0000000000..7c6de5d904 --- /dev/null +++ b/usr/src/lib/libc_psr/sun4u-opl/sparcv9/Makefile @@ -0,0 +1,73 @@ +# +# 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. +# +# ident "%Z%%M% %I% %E% SMI" +# +# Platform specific Makefile for libc_psr. +# +PLATFORM = SUNW,SPARC-Enterprise +ALT_PLAT = sun4u-opl +COMPAT_PLAT = sun4u-us3 +CLASS = 64 + +OBJECTS = memcpy.o memset.o memcmp.o + +include ../Makefile.com + +MAPDIR= ../../spec/$(ALT_PLAT)/$(MACH64) +MAPFILE= $(MAPDIR)/mapfile-$(MACH64) +MAPFILES= $(MAPFILE) $(MAPFILE-FLTR) +MAPOPTS= $(MAPFILES:%=-M %) +DYNFLAGS += $(MAPOPTS) +CLOBBERFILES += $(MAPFILE) + +ASDEFS += -D__sparcv9 +ASFLAGS += -xarch=v9b + +include $(SRC)/Makefile.master.64 + +# Redefine shared object build rule to use $(LD) directly (this avoids .init +# and .fini sections being added). + +BUILD.SO= $(LD) -o $@ -G $(DYNFLAGS) $(PICS) $(LDLIBS) + +$(DYNLIB): $(MAPFILES) + +$(MAPFILE): + @cd $(MAPDIR); $(MAKE) `basename $@` + +.KEEP_STATE: + +MODULE = libc_psr.so.1 +LIBC_PSR64_DIR = $(ROOT_PSM_LIB_DIR)/$(MACH64) +LIBC_PSR64_LIB = $(LIBC_PSR64_DIR)/$(MODULE) + +$(LIBC_PSR64_DIRS): + -$(INS.dir.root.bin) + +all: $(LIBS) + +install: all $(LIBC_PSR64_DIR) $(ROOT_PSM_LIB64_DIR)/$(LIBS) + +include ../../Makefile.targ diff --git a/usr/src/lib/libdscp/Makefile b/usr/src/lib/libdscp/Makefile new file mode 100644 index 0000000000..8eff9de752 --- /dev/null +++ b/usr/src/lib/libdscp/Makefile @@ -0,0 +1,62 @@ +# +# 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. +# +# lib/libdscp/Makefile +# +#ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.lib + +SUBDIRS= spec .WAIT sparc svc + +all := TARGET= all +install := TARGET= install +clean := TARGET= clean +clobber := TARGET= clobber +lint := TARGET= lint + +# definitions for install_h target +HDRS= libdscp.h +ROOTHDRDIR= $(ROOT)/usr/include +ROOTHDRS= $(HDRS:%=$(ROOTHDRDIR)/%) +CHECKHDRS= $(HDRS:%.h=%.check) + +.KEEP_STATE: + +all install clean clobber lint: $(SUBDIRS) + +# install rule for install_h target + +$(ROOTHDRDIR)/%: % + $(INS.file) + +install_h: $(ROOTHDRS) + +check: $(CHECKHDRS) + +spec sparc svc: FRC + @cd $@; pwd; $(MAKE) $(TARGET) + +FRC: diff --git a/usr/src/lib/libdscp/Makefile.com b/usr/src/lib/libdscp/Makefile.com new file mode 100644 index 0000000000..5c9e76421c --- /dev/null +++ b/usr/src/lib/libdscp/Makefile.com @@ -0,0 +1,68 @@ +# +# 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. +# +# lib/libdscp/Makefile.com +# +#ident "%Z%%M% %I% %E% SMI" +# + +LIBRARY= libdscp.a +VERS= .1 +MANIFEST= dscp.xml +OBJECTS= libdscp.o + +include ../../Makefile.lib +include ../../Makefile.rootfs + +LIBS = $(DYNLIB) $(LINTLIB) +LDLIBS += -lc -lsocket -lnsl +$(LINTLIB) := SRCS = $(SRCDIR)/$(LINTSRC) + +SRCDIR = .. +MAPDIR = ../spec/$(TRANSMACH) +SPECMAPFILE = $(MAPDIR)/mapfile + +CPPFLAGS += -I.. +CFLAGS += $(CCVERBOSE) + +.KEEP_STATE: + +# Defintions for installation of the library +USR_PLAT_DIR = $(ROOT)/usr/platform +USR_PSM_DIR = $(USR_PLAT_DIR)/SUNW,SPARC-Enterprise +USR_PSM_LIB_DIR = $(USR_PSM_DIR)/lib +ROOTLIBDIR= $(USR_PSM_LIB_DIR) + +$(ROOTLIBDIR): + $(INS.dir) + +.KEEP_STATE: + +all: $(LIBS) + +install: all .WAIT $(ROOTLIBDIR) $(ROOTLIB) + +lint: lintcheck + +include ../../Makefile.targ diff --git a/usr/src/lib/libdscp/libdscp.c b/usr/src/lib/libdscp/libdscp.c new file mode 100644 index 0000000000..63c49383d0 --- /dev/null +++ b/usr/src/lib/libdscp/libdscp.c @@ -0,0 +1,542 @@ +/* + * 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 <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <ctype.h> +#include <errno.h> +#include <fcntl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <sys/sockio.h> +#include <net/if.h> +#include <net/pfkeyv2.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <libdscp.h> + +/* + * Define the file containing the configured DSCP interface name + */ +#define DSCP_CONFIGFILE "/var/run/dscp.ifname" + +/* + * Forward declarations + */ +static int get_ifname(char *); +static int convert_ipv6(struct sockaddr_in6 *, uint32_t *); +static int convert_ipv4(struct sockaddr_in *, + struct sockaddr_in6 *, int *); + +/* + * dscpBind() + * + * Properly bind a socket to the local DSCP address. + * Optionally bind it to a specific port. + */ +int +dscpBind(int domain_id, int sockfd, int port) +{ + int len; + int len6; + int error; + struct sockaddr_in addr; + struct sockaddr_in6 addr6; + + /* Check arguments */ + if ((sockfd < 0) || (port >= IPPORT_RESERVED)) { + return (DSCP_ERROR_INVALID); + } + + /* Get the local DSCP address used to communicate with the SP */ + error = dscpAddr(domain_id, DSCP_ADDR_LOCAL, + (struct sockaddr *)&addr, &len); + + if (error != DSCP_OK) { + return (error); + } + + /* + * If the caller specified a port, then update the socket address + * to also specify the same port. + */ + if (port != 0) { + addr.sin_port = htons(port); + } + + /* + * Bind the socket. + * + * EINVAL means it is already bound. + * EAFNOSUPPORT means try again using IPv6. + */ + if (bind(sockfd, (struct sockaddr *)&addr, len) < 0) { + + if (errno == EINVAL) { + return (DSCP_ERROR_ALREADY); + } + + if (errno != EAFNOSUPPORT) { + return (DSCP_ERROR); + } + + if (convert_ipv4(&addr, &addr6, &len6) < 0) { + return (DSCP_ERROR); + } + + if (bind(sockfd, (struct sockaddr *)&addr6, len6) < 0) { + if (errno == EINVAL) { + return (DSCP_ERROR_ALREADY); + } + return (DSCP_ERROR); + } + } + + return (DSCP_OK); +} + +/* + * dscpSecure() + * + * Enable DSCP security mechanisms on a socket. + * + * DSCP uses the IPSec AH (Authentication Headers) protocol with + * the SHA-1 algorithm. + */ +/*ARGSUSED*/ +int +dscpSecure(int domain_id, int sockfd) +{ + ipsec_req_t opt; + + /* Check arguments */ + if (sockfd < 0) { + return (DSCP_ERROR_INVALID); + } + + /* + * Construct a socket option argument that specifies the protocols + * and algorithms required for DSCP's use of IPSec. + */ + (void) memset(&opt, 0, sizeof (opt)); + opt.ipsr_ah_req = IPSEC_PREF_REQUIRED; + opt.ipsr_esp_req = IPSEC_PREF_NEVER; + opt.ipsr_self_encap_req = IPSEC_PREF_NEVER; + opt.ipsr_auth_alg = SADB_AALG_MD5HMAC; + + /* + * Set the socket option that enables IPSec usage upon the socket, + * using the socket option argument constructed above. + */ + if (setsockopt(sockfd, IPPROTO_IP, IP_SEC_OPT, (const char *)&opt, + sizeof (opt)) < 0) { + return (DSCP_ERROR); + } + + return (DSCP_OK); +} + +/* + * dscpAuth() + * + * Test whether a connection should be accepted or refused. + * The address of the connection request is compared against + * the remote address of the specified DSCP link. + */ +/*ARGSUSED*/ +int +dscpAuth(int domain_id, struct sockaddr *saddr, int len) +{ + int dlen; + struct sockaddr daddr; + struct sockaddr_in *sin; + struct sockaddr_in6 *sin6; + uint32_t spaddr; + uint32_t reqaddr; + + /* Check arguments */ + if (saddr == NULL) { + return (DSCP_ERROR_INVALID); + } + + /* + * Get the remote IP address associated with the SP. + */ + if (dscpAddr(0, DSCP_ADDR_REMOTE, &daddr, &dlen) != DSCP_OK) { + return (DSCP_ERROR_DB); + } + + /* + * Convert the request's address to a 32-bit integer. + * + * This may require a conversion if the caller is + * using an IPv6 socket. + */ + switch (saddr->sa_family) { + case AF_INET: + /* LINTED E_BAD_PTR_CAST_ALIGN */ + sin = (struct sockaddr_in *)saddr; + reqaddr = ntohl(*((uint32_t *)&(sin->sin_addr))); + break; + case AF_INET6: + /* LINTED E_BAD_PTR_CAST_ALIGN */ + sin6 = (struct sockaddr_in6 *)saddr; + if (convert_ipv6(sin6, &reqaddr) < 0) { + return (DSCP_ERROR); + } + break; + default: + return (DSCP_ERROR); + } + + /* + * Convert the SP's address to a 32-bit integer. + */ + /* LINTED E_BAD_PTR_CAST_ALIGN */ + sin = (struct sockaddr_in *)&daddr; + spaddr = ntohl(*((uint32_t *)&(sin->sin_addr))); + + /* + * Compare the addresses. Reject if they don't match. + */ + if (reqaddr != spaddr) { + return (DSCP_ERROR_REJECT); + } + + return (DSCP_OK); +} + +/* + * dscpAddr() + * + * Get the addresses associated with a specific DSCP link. + */ +/*ARGSUSED*/ +int +dscpAddr(int domain_id, int which, struct sockaddr *saddr, int *lenp) +{ + int error; + int sockfd; + uint64_t flags; + char ifname[LIFNAMSIZ]; + struct lifreq lifr; + + /* Check arguments */ + if (((saddr == NULL) || (lenp == NULL)) || + ((which != DSCP_ADDR_LOCAL) && (which != DSCP_ADDR_REMOTE))) { + return (DSCP_ERROR_INVALID); + } + + /* + * Get the DSCP interface name. + */ + if (get_ifname(ifname) != 0) { + return (DSCP_ERROR_DB); + } + + /* + * Open a socket. + */ + if ((sockfd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { + return (DSCP_ERROR_DB); + } + + /* + * Get the interface flags. + */ + (void) memset(&lifr, 0, sizeof (lifr)); + (void) strncpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name)); + if (ioctl(sockfd, SIOCGLIFFLAGS, (char *)&lifr) < 0) { + (void) close(sockfd); + return (DSCP_ERROR_DB); + } + flags = lifr.lifr_flags; + + /* + * The interface must be a PPP link using IPv4. + */ + if (((flags & IFF_IPV4) == 0) || + ((flags & IFF_POINTOPOINT) == 0)) { + (void) close(sockfd); + return (DSCP_ERROR_DB); + } + + /* + * Get the local or remote address, depending upon 'which'. + */ + (void) strncpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name)); + if (which == DSCP_ADDR_LOCAL) { + error = ioctl(sockfd, SIOCGLIFADDR, (char *)&lifr); + } else { + error = ioctl(sockfd, SIOCGLIFDSTADDR, (char *)&lifr); + } + if (error < 0) { + (void) close(sockfd); + return (DSCP_ERROR_DB); + } + + /* + * Copy the sockaddr value back to the caller. + */ + (void) memset(saddr, 0, sizeof (struct sockaddr)); + (void) memcpy(saddr, &lifr.lifr_addr, sizeof (struct sockaddr_in)); + *lenp = sizeof (struct sockaddr_in); + + (void) close(sockfd); + return (DSCP_OK); +} + +/* + * dscpIdent() + * + * Determine the domain of origin associated with a sockaddr. + * (Map a sockaddr to a domain ID.) + * + * In the Solaris version, the remote socket address should always + * be the SP. A call to dscpAuth() is used to confirm this, and + * then DSCP_IDENT_SP is returned as a special domain ID. + */ +int +dscpIdent(struct sockaddr *saddr, int len, int *domainp) +{ + int error; + + /* Check arguments */ + if ((saddr == NULL) || (domainp == NULL)) { + return (DSCP_ERROR_INVALID); + } + + /* Confirm that the address is the SP */ + error = dscpAuth(0, saddr, len); + if (error != DSCP_OK) { + if (error == DSCP_ERROR_REJECT) { + return (DSCP_ERROR); + } + return (error); + } + + *domainp = DSCP_IDENT_SP; + return (DSCP_OK); +} + +/* + * get_ifname() + * + * Retrieve the interface name used by DSCP. + * It should be available from a file in /var/run. + * + * Returns: 0 upon success, -1 upon failure. + */ +static int +get_ifname(char *ifname) +{ + int i; + int fd; + int len; + int size; + int count; + int end; + int begin; + struct stat stbuf; + + /* + * Initialize the interface name. + */ + (void) memset(ifname, 0, LIFNAMSIZ); + + /* + * Test for a a valid configuration file. + */ + if ((stat(DSCP_CONFIGFILE, &stbuf) < 0) || + (S_ISREG(stbuf.st_mode) == 0) || + (stbuf.st_size > LIFNAMSIZ)) { + return (-1); + } + + /* + * Open the configuration file and read its contents + */ + + if ((fd = open(DSCP_CONFIGFILE, O_RDONLY)) < 0) { + return (-1); + } + + count = 0; + size = stbuf.st_size; + do { + i = read(fd, &ifname[count], size - count); + if (i <= 0) { + (void) close(fd); + return (-1); + } + count += i; + } while (count < size); + + (void) close(fd); + + /* + * Analyze the interface name that was just read, + * and clean it up as necessary. The result should + * be a simple NULL terminated string such as "sppp0" + * with no extra whitespace or other characters. + */ + + /* Detect the beginning of the interface name */ + for (begin = -1, i = 0; i < size; i++) { + if (isalnum(ifname[i]) != 0) { + begin = i; + break; + } + } + + /* Fail if no such beginning was found */ + if (begin < 0) { + return (-1); + } + + /* Detect the end of the interface name */ + for (end = size - 1, i = begin; i < size; i++) { + if (isalnum(ifname[i]) == 0) { + end = i; + break; + } + } + + /* Compute the length of the name */ + len = end - begin; + + /* Remove leading whitespace */ + if (begin > 0) { + (void) memmove(ifname, &ifname[begin], len); + } + + /* Clear out any remaining garbage */ + if (len < size) { + (void) memset(&ifname[len], 0, size - len); + } + + return (0); +} + +/* + * convert_ipv6() + * + * Converts an IPv6 socket address into an equivalent IPv4 + * address. The conversion is to a 32-bit integer because + * that is sufficient for how libdscp uses IPv4 addresses. + * + * The IPv4 address is additionally converted from network + * byte order to host byte order. + * + * Returns: 0 upon success, with 'addrp' updated. + * -1 upon failure, with 'addrp' undefined. + */ +static int +convert_ipv6(struct sockaddr_in6 *addr6, uint32_t *addrp) +{ + uint32_t addr; + char *ipv4str; + char ipv6str[INET6_ADDRSTRLEN]; + + /* + * Convert the IPv6 address into a string. + */ + if (inet_ntop(AF_INET6, &addr6->sin6_addr, ipv6str, + sizeof (ipv6str)) == NULL) { + return (-1); + } + + /* + * Use the IPv6 string to construct an IPv4 string. + */ + if ((ipv4str = strrchr(ipv6str, ':')) != NULL) { + ipv4str++; + } else { + return (-1); + } + + /* + * Convert the IPv4 string into a 32-bit integer. + */ + if (inet_pton(AF_INET, ipv4str, &addr) <= 0) { + return (-1); + } + + *addrp = ntohl(addr); + return (0); +} + +/* + * convert_ipv4() + * + * Convert an IPv4 socket address into an equivalent IPv6 address. + * + * Returns: 0 upon success, with 'addr6' and 'lenp' updated. + * -1 upon failure, with 'addr6' and 'lenp' undefined. + */ +static int +convert_ipv4(struct sockaddr_in *addr, struct sockaddr_in6 *addr6, int *lenp) +{ + int len; + uint32_t ipv4addr; + char ipv4str[INET_ADDRSTRLEN]; + char ipv6str[INET6_ADDRSTRLEN]; + + /* + * Convert the IPv4 socket address into a string. + */ + ipv4addr = *((uint32_t *)&(addr->sin_addr)); + if (inet_ntop(AF_INET, &ipv4addr, ipv4str, sizeof (ipv4str)) == NULL) { + return (-1); + } + + /* + * Use the IPv4 string to construct an IPv6 string. + */ + len = snprintf(ipv6str, INET6_ADDRSTRLEN, "::ffff:%s", ipv4str); + if (len >= INET6_ADDRSTRLEN) { + return (-1); + } + + /* + * Convert the IPv6 string to an IPv6 socket address. + */ + (void) memset(addr6, 0, sizeof (*addr6)); + addr6->sin6_family = AF_INET6; + addr6->sin6_port = addr->sin_port; + if (inet_pton(AF_INET6, ipv6str, &addr6->sin6_addr) <= 0) { + return (-1); + } + + *lenp = sizeof (struct sockaddr_in6); + + return (0); +} diff --git a/usr/src/lib/libdscp/libdscp.h b/usr/src/lib/libdscp/libdscp.h new file mode 100644 index 0000000000..aa3b76cdde --- /dev/null +++ b/usr/src/lib/libdscp/libdscp.h @@ -0,0 +1,72 @@ +/* + * 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 _LIBDSCP_H +#define _LIBDSCP_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/socket.h> +#include <netinet/in.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * DSCP Error Codes + */ +typedef enum { + DSCP_OK = 0, /* Success */ + DSCP_ERROR, /* General Error */ + DSCP_ERROR_ALREADY, /* Socket Already Bound */ + DSCP_ERROR_INVALID, /* Invalid Arguments */ + DSCP_ERROR_NOENT, /* Lookup Failure From dscpIdent() */ + DSCP_ERROR_DB, /* Error Reading Database */ + DSCP_ERROR_REJECT /* Rejection From dscpAuth() */ +} dscp_err_t; + +/* + * Possible values for the 'which' parameter to dscpAddr(). + */ +#define DSCP_ADDR_LOCAL (1) /* Get the domain's local IP address */ +#define DSCP_ADDR_REMOTE (2) /* Get the SP's remote IP address */ + +/* + * Define a special value used to represent the SP as a domain ID. + */ +#define DSCP_IDENT_SP (-1) + +int dscpBind(int domain, int sockfd, int port); +int dscpSecure(int domain, int sockfd); +int dscpAuth(int domain, struct sockaddr *saddr, int len); +int dscpAddr(int domain, int which, struct sockaddr *saddr, int *lenp); +int dscpIdent(struct sockaddr *saddr, int len, int *domainp); + +#ifdef __cplusplus +} +#endif + +#endif /* _LIBDSCP_H */ diff --git a/usr/src/lib/libdscp/llib-ldscp b/usr/src/lib/libdscp/llib-ldscp new file mode 100644 index 0000000000..b4ce6b9926 --- /dev/null +++ b/usr/src/lib/libdscp/llib-ldscp @@ -0,0 +1,32 @@ +/* + * 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 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + * + * usr/src/lib/libdscp/llib-ldscp + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <libdscp.h> diff --git a/usr/src/lib/libdscp/sparc/Makefile b/usr/src/lib/libdscp/sparc/Makefile new file mode 100644 index 0000000000..22bf606d7a --- /dev/null +++ b/usr/src/lib/libdscp/sparc/Makefile @@ -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 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# lib/libdscp/sparc/Makefile +# +#ident "%Z%%M% %I% %E% SMI" +# + +MAPDIR= ../spec/sparc +include ../Makefile.com + +all: $(LIBS) + +install: all $(ROOTLIBS) $(ROOTLINKS) diff --git a/usr/src/lib/libdscp/spec/Makefile b/usr/src/lib/libdscp/spec/Makefile new file mode 100644 index 0000000000..048c9a5306 --- /dev/null +++ b/usr/src/lib/libdscp/spec/Makefile @@ -0,0 +1,61 @@ +# +# 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. +# +# lib/libdscp/spec/Makefile +# +#ident "%Z%%M% %I% %E% SMI" +# + +SUBDIRS= sparc + +all := TARGET= all +install := TARGET= install +clean := TARGET= clean +clobber := TARGET= clobber +lint := TARGET= lint + +.KEEP_STATE: + +all install clean clobber: ${SUBDIRS} + +${SUBDIRS}: FRC + @cd $@; pwd; ${MAKE} ${TARGET} + +# +# This will make sure that any target not +# explicitly defined will not break the build. +# +# XXX pmake on intel does not like the following rules +# %: ignore_and_exit_quietly +# ignore_and_exit_quietly: +# +# So here it is manually +# +IGNORE= _msg catalog install_h delete \ + package tcov debug private_t \ + check analyze test dynamic lint + +${IGNORE}: + +FRC: diff --git a/usr/src/lib/libdscp/spec/Makefile.targ b/usr/src/lib/libdscp/spec/Makefile.targ new file mode 100644 index 0000000000..c9f02d8818 --- /dev/null +++ b/usr/src/lib/libdscp/spec/Makefile.targ @@ -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 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# lib/libdscp/spec/Makefile.targ +# +#ident "%Z%%M% %I% %E% SMI" +# + +LIBRARY = libdscp.a +VERS = .1 + +OBJECTS = libdscp.o + +SPECCPP = -I../.. diff --git a/usr/src/lib/libdscp/spec/libdscp.spec b/usr/src/lib/libdscp/spec/libdscp.spec new file mode 100644 index 0000000000..91cdd7c540 --- /dev/null +++ b/usr/src/lib/libdscp/spec/libdscp.spec @@ -0,0 +1,56 @@ +# +# Copyright 2006 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 +# +# lib/libdscp/spec/libdscp.spec +# +#ident "%Z%%M% %I% %E% SMI" + +function dscpBind +include <libdscp.h> +declaration int dscpBind(int, int, int) +version SUNWprivate_1.1 +end + +function dscpSecure +include <libdscp.h> +declaration int dscpSecure(int, int) +version SUNWprivate_1.1 +end + +function dscpAuth +include <libdscp.h> +declaration int dscpAuth(int, struct sockaddr *, int) +version SUNWprivate_1.1 +end + +function dscpAddr +include <libdscp.h> +declaration int dscpAddr(int, int, struct sockaddr *, int *) +version SUNWprivate_1.1 +end + +function dscpIdent +include <libdscp.h> +declaration int dscpIdent(struct sockaddr *, int, int *) +version SUNWprivate_1.1 +end diff --git a/usr/src/lib/libdscp/spec/sparc/Makefile b/usr/src/lib/libdscp/spec/sparc/Makefile new file mode 100644 index 0000000000..79205aad21 --- /dev/null +++ b/usr/src/lib/libdscp/spec/sparc/Makefile @@ -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 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# lib/libdscp/spec/sparc/Makefile +# +#ident "%Z%%M% %I% %E% SMI" +# + +.KEEP_STATE: + +include ../Makefile.targ + +include $(SRC)/lib/Makefile.lib + +include $(SRC)/lib/Makefile.spec + +install: $(ROOTABILIB) diff --git a/usr/src/lib/libdscp/spec/versions b/usr/src/lib/libdscp/spec/versions new file mode 100644 index 0000000000..bbebe2a784 --- /dev/null +++ b/usr/src/lib/libdscp/spec/versions @@ -0,0 +1,31 @@ +# +# Copyright 2006 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 +# +# usr/src/lib/libdscp/spec/versions +# +#ident "%Z%%M% %I% %E% SMI" +# + +sparc { + SUNWprivate_1.1; +} diff --git a/usr/src/lib/libdscp/svc/Makefile b/usr/src/lib/libdscp/svc/Makefile new file mode 100644 index 0000000000..8a34b10cca --- /dev/null +++ b/usr/src/lib/libdscp/svc/Makefile @@ -0,0 +1,56 @@ +# +# 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. +# +# lib/libdscp/svc/Makefile.com +# +#ident "%Z%%M% %I% %E% SMI" +# + +MANIFEST= dscp.xml +SVCMETHOD= svc-dscp + +include ../../../cmd/Makefile.cmd + +.KEEP_STATE: + +# definitions for installing the manifest +ROOTMANIFESTDIR = $(ROOTSVCPLATFORMSUN4U) +$(ROOTMANIFEST) := FILEMODE = 0444 + +# definitions for installing the PPP options +OPTIONS = dscp.ppp.options +ROOTOPTIONSDIR = $(ROOT)/usr/platform/SUNW,SPARC-Enterprise/lib +ROOTOPTIONS = $(OPTIONS:%=$(ROOTOPTIONSDIR)/%) + +$(ROOTOPTIONSDIR): + $(INS.dir) + +$(ROOTOPTIONSDIR)/%: % + $(INS.file) + +all clean clobber lint: + +install: $(ROOTMANIFEST) $(ROOTSVCMETHOD) $(ROOTOPTIONS) + +check: $(CHKMANIFEST) diff --git a/usr/src/lib/libdscp/svc/dscp.ppp.options b/usr/src/lib/libdscp/svc/dscp.ppp.options new file mode 100644 index 0000000000..d46df31de3 --- /dev/null +++ b/usr/src/lib/libdscp/svc/dscp.ppp.options @@ -0,0 +1,112 @@ +# +# Copyright 2006 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 +# +# dscp.ppp.options +# +#ident "%Z%%M% %I% %E% SMI" +# + +# +# These are options for running pppd(1M) to provide a DSCP +# link between a service processor and a domain in OPL. All +# options are explicitly set here so that site customizations +# of the global options files will not affect DSCP. +# + +# +# Generic pppd options. +# +persist +noplink +lock +nolog +maxfail 0 +holdoff 5 +noproxyarp +linkname dscp + +# +# Physical link properties. +# +sync +local +nocrtscts +nocdtrcts +default-fcs +mtu 1500 +mru 1500 + +# +# Configure LCP. +# +passive +noendpoint +lcp-echo-failure 6 +lcp-echo-interval 5 +lcp-max-configure 10 +lcp-max-failure 10 +lcp-max-terminate 3 +lcp-restart 3 + +# +# Configure the IPv4 NCP. +# IP addresses are given by the peer. +# +0:0 +noipv6 +noipdefault +nodefaultroute +ipcp-accept-local +ipcp-accept-remote +ipcp-max-configure 10 +ipcp-max-failure 10 +ipcp-max-terminate 3 +ipcp-restart 3 + +# +# Disable all authentication. +# +noauth +noident +nopam +refuse-pap +refuse-chap +refuse-mschap +refuse-mschapv2 + +# +# Disable all compression. +# +novj +noccp +nopcomp +noaccomp +nobsdcomp + +# +# Disable all scripts. +# +init /bin/true +welcome /bin/true +connect /bin/true +disconnect /bin/true diff --git a/usr/src/lib/libdscp/svc/dscp.xml b/usr/src/lib/libdscp/svc/dscp.xml new file mode 100644 index 0000000000..f3f6565098 --- /dev/null +++ b/usr/src/lib/libdscp/svc/dscp.xml @@ -0,0 +1,121 @@ +<?xml version="1.0"?> +<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1"> +<!-- + Copyright 2006 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 + + ident "%Z%%M% %I% %E% SMI" + + NOTE: This service manifest is not editable; its contents will + be overwritten by package or patch operations, including + operating system upgrade. Make customizations in a different + file. +--> + +<service_bundle type='manifest' name='SUNW:dscp'> + +<service + name='platform/sun4u/dscp' + type='service' + version='1'> + + <create_default_instance enabled='false' /> + + <single_instance /> + + <dependency + name='network' + grouping='require_any' + restart_on='error' + type='service'> + <service_fmri value='svc:/milestone/network' /> + </dependency> + + <dependency + name='local-filesystems' + type='service' + grouping='require_all' + restart_on='none'> + <service_fmri value='svc:/system/filesystem/local' /> + </dependency> + + <dependency + name='sckmd' + type='service' + grouping='optional_all' + restart_on='none'> + <service_fmri value='svc:/platform/sun4u/sckmd:default' /> + </dependency> + + <dependent + name='dcs' + grouping='optional_all' + restart_on='none'> + <service_fmri value='svc:/platform/sun4u/dcs:default' /> + </dependent> + + <dependent + name='fmd' + grouping='optional_all' + restart_on='none'> + <service_fmri value='svc:/system/fmd:default' /> + </dependent> + + <exec_method + type='method' + name='start' + exec='/lib/svc/method/svc-dscp %m' + timeout_seconds='60' /> + + <exec_method + type='method' + name='refresh' + exec='/lib/svc/method/svc-dscp %m' + timeout_seconds='60' /> + + <exec_method + type='method' + name='stop' + exec='/lib/svc/method/svc-dscp %m' + timeout_seconds='60' /> + + <property_group name='application' type='framework'> + <stability value='Evolving' /> + <propval name='auto_enable' type='boolean' value='true' /> + </property_group> + + <stability value='Evolving' /> + + <template> + <common_name> + <loctext xml:lang='C'> + DSCP Service + </loctext> + </common_name> + <documentation> + <manpage title='??' section='1M' + manpath='/usr/share/man' /> + </documentation> + </template> +</service> + +</service_bundle> diff --git a/usr/src/lib/libdscp/svc/svc-dscp b/usr/src/lib/libdscp/svc/svc-dscp new file mode 100644 index 0000000000..f8f79e81a2 --- /dev/null +++ b/usr/src/lib/libdscp/svc/svc-dscp @@ -0,0 +1,111 @@ +#!/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 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +# +# Start script for the SPARC-Enterprise DSCP service. +# + +. /lib/svc/share/smf_include.sh + +OPL=SUNW,SPARC-Enterprise +FJOPL=FJSV,SPARC-Enterprise +TMPOPL=SUNW,OPL-Enterprise +OPL_LIB=/usr/platform/${OPL}/lib +DM2S_DEVICE=/dev/dm2s0 +PPP_OPTIONS=${OPL_LIB}/dscp.ppp.options +DSCP_IFNAME=/var/run/dscp.ifname +PRTDSCP=/usr/platform/${OPL}/sbin/prtdscp +PLATFORM=`/sbin/uname -i` +SLEEP=/bin/sleep +PKILL=/bin/pkill + +LD_LIBRARY_PATH=/lib:${OPL_LIB}; export LD_LIBRARY_PATH + +# This service can only run on OPL. +if [ "${PLATFORM}" != "${OPL}" -a \ + "${PLATFORM}" != "${FJOPL}" -a \ + "${PLATFORM}" != "${TMPOPL}" ]; then + + exit $SMF_EXIT_ERR_CONFIG +fi + +case "$1" in +'start') + + if [ ! -x /usr/bin/pppd ]; then + exit $SMF_EXIT_ERR_CONFIG + fi + + if [ ! -c $DM2S_DEVICE ]; then + exit $SMF_EXIT_ERR_CONFIG + fi + + if [ ! -f $PPP_OPTIONS ]; then + exit $SMF_EXIT_ERR_CONFIG + fi + + SUCCESS=0 + for UNIT in 0 1 2 3 4 5 6 7 8 9; do + /usr/bin/pppd $DM2S_DEVICE unit $UNIT file $PPP_OPTIONS + if [ ! "$?" = "1" ]; then + echo "sppp$UNIT" > $DSCP_IFNAME + SUCCESS=1 + break + fi + done + + if [ $SUCCESS -ne 1 ]; then + exit $SMF_EXIT_ERR_FATAL + fi + + # Wait for the DSCP link to come up, but only for 30 seconds + for RETRY in 0 1 2 3 4 5; do + ${PRTDSCP} >/dev/null 2>&1 + if [ $? -eq 0 ]; then + exit $SMF_EXIT_OK + fi + ${SLEEP} 5 + done + + # Stop pppd before we return failure + ${PKILL} -TERM -f "pppd ${DM2S_DEVICE}" + ${SLEEP} 1 + ${PKILL} -KILL -f "pppd ${DM2S_DEVICE}" + rm -f $DSCP_IFNAME + exit $SMF_EXIT_ERR_FATAL + ;; + +'stop') + # First try SIGTERM and then SIGKILL + ${PKILL} -TERM -f "pppd ${DM2S_DEVICE}" + ${SLEEP} 1 + ${PKILL} -KILL -f "pppd ${DM2S_DEVICE}" + rm -f $DSCP_IFNAME + exit $SMF_EXIT_OK + ;; +esac diff --git a/usr/src/lib/libprtdiag/common/cpu.c b/usr/src/lib/libprtdiag/common/cpu.c index 4248f3415c..b39479f254 100644 --- a/usr/src/lib/libprtdiag/common/cpu.c +++ b/usr/src/lib/libprtdiag/common/cpu.c @@ -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,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" @@ -59,18 +58,18 @@ * is passed in or the clock-frequency property does not exist, the * function returns 0. */ -int +uint_t get_cpu_freq(Prom_node *pnode) { Prop *prop; - int *value; + uint_t *value; /* find the property */ if ((prop = find_prop(pnode, "clock-frequency")) == NULL) { return (0); } - if ((value = (int *)get_prop_val(prop)) == NULL) { + if ((value = (uint_t *)get_prop_val(prop)) == NULL) { return (0); } diff --git a/usr/src/lib/libprtdiag/inc/libprtdiag.h b/usr/src/lib/libprtdiag/inc/libprtdiag.h index 0354aea6a3..e9361b8e9c 100644 --- a/usr/src/lib/libprtdiag/inc/libprtdiag.h +++ b/usr/src/lib/libprtdiag/inc/libprtdiag.h @@ -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,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 1999-2003 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -91,7 +90,7 @@ void display_platform_specific_header(void); void display_cpu_devices(Sys_tree *); void display_cpus(Board_node *); void display_mid(int mid); -int get_cpu_freq(Prom_node *); +uint_t get_cpu_freq(Prom_node *); int get_ecache_size(Prom_node *); /* diff --git a/usr/src/lib/libprtdiag_psr/sparc/Makefile b/usr/src/lib/libprtdiag_psr/sparc/Makefile index e9d36c0d44..1a5121e2bc 100644 --- a/usr/src/lib/libprtdiag_psr/sparc/Makefile +++ b/usr/src/lib/libprtdiag_psr/sparc/Makefile @@ -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,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" @@ -29,7 +28,7 @@ PRTDIAG_PLATFORMS= desktop tazmo javelin sunfire starfire serengeti \ montecarlo littleneck starcat daktari cherrystone \ - lw8 snowbird ontario schumacher + lw8 snowbird ontario schumacher opl all := TARGET= all lint := TARGET= lint diff --git a/usr/src/lib/libprtdiag_psr/sparc/opl/Makefile b/usr/src/lib/libprtdiag_psr/sparc/opl/Makefile new file mode 100644 index 0000000000..16eb8eb1e5 --- /dev/null +++ b/usr/src/lib/libprtdiag_psr/sparc/opl/Makefile @@ -0,0 +1,74 @@ +# +# 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. +# +#ident "%Z%%M% %I% %E% SMI" +# +# lib/libprtdiag_psr/sparc/opl/Makefile + +UTSBASE = ../../../../../src/uts + +PLATFORM_OBJECTS= opl.o + +include ../Makefile.com + +IFLAGS += -I$(USR_PLAT_DIR)/sun4u/include -I ../../../libprtdiag/inc +LINTFLAGS += $(IFLAGS) + +LDLIBS += -ldevinfo -lkstat + +#IMPLEMENTED_PLATFORM = SUNW,OPL-Enterprise +#PLATFORM=$(IMPLEMENTED_PLATFORM) +PLATFORM = SUNW,SPARC-Enterprise + +.KEEP_STATE: + +PLATLIBS= $(USR_PLAT_DIR)/$(PLATFORM)/lib/ + +install: all $(USR_PSM_LIBS) + +$(USR_PSM_LIB_DIR): + cd $(UTSBASE)/sun4u/opl; $(MAKE) $(USR_PSM_LIB_DIR) + +# +# install rule +# +$(USR_PSM_LIB_DIR)/%: % $(USR_PSM_LIB_DIR) + $(INS.file) + +POFILE= libprtdiag_psr_opl.po +POFILES= opl.po + +_msg: $(MSGDOMAIN) $(POFILE) + $(RM) $(MSGDOMAIN)/$(POFILE) + $(CP) $(POFILE) $(MSGDOMAIN) + +$(POFILE): $(POFILES) + $(RM) $@ + $(CAT) $(POFILES) > $@ + +$(POFILES): + $(RM) messages.po + $(XGETTEXT) $(XGETFLAGS) `$(GREP) -l gettext common/opl.c` + $(SED) -e '/^# msg/d' -e '/^domain/d' messages.po > $@ + $(RM) messages.po diff --git a/usr/src/lib/libprtdiag_psr/sparc/opl/common/opl.c b/usr/src/lib/libprtdiag_psr/sparc/opl/common/opl.c new file mode 100644 index 0000000000..9bce08b95a --- /dev/null +++ b/usr/src/lib/libprtdiag_psr/sparc/opl/common/opl.c @@ -0,0 +1,850 @@ +/* + * 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. + * + * Opl Platform specific functions. + * + * called when : + * machine_type == MTYPE_OPL + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <ctype.h> +#include <string.h> +#include <varargs.h> +#include <fcntl.h> +#include <assert.h> +#include <sys/param.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/utsname.h> +#include <sys/systeminfo.h> +#include <sys/openpromio.h> +#include <libintl.h> +#include <syslog.h> +#include <sys/dkio.h> +#include <pdevinfo.h> +#include <libprtdiag.h> +#include <libdevinfo.h> +#include <kstat.h> + +/* + * Globals and externs + */ +#define KBYTE 1024 +#define MBYTE (KBYTE * KBYTE) +#define HZ_TO_MHZ(x) ((((uint64_t)(x)) + 500000) / 1000000) +#define SCF_SECURE_MODE_KSTAT_NAMED "secure_mode" +#define SCF_STAT_MODE_UNLOCK 0 +#define SCF_STAT_MODE_LOCK 1 +#define SCF_SYSTEM_KSTAT_NAME "scf" +#ifndef TEXT_DOMAIN +#define TEXT_DOMAIN "SYS_TEST" +#endif /* TEXT_DOMAIN */ +#define IS_PCI_BRIDGE(name, type) \ + (((name) != NULL) && ((type) != NULL) && \ + (strncmp((name), "pci", 3) == 0) && \ + (strncmp((type), "pci", 3) == 0)) + +/* + * Global functions and variables + * these functions will overlay the symbol table of libprtdiag + * at runtime (Opl systems only) + */ +struct cs_status { + int cs_number; + int status; + int avail_hi; + int avail_lo; + int dimm_hi; + int dimm_lo; + int dimms; +}; + +int do_prominfo(int syserrlog, char *pgname, int log_flag, int prt_flag); +void *get_prop_val(Prop *prop); +void display_pci(Board_node *); +void display_ffb(Board_node *, int); +void display_sbus(Board_node *board); +void display_cpu_devices(Sys_tree *tree); +void display_cpus(Board_node *board); +void display_memoryconf(Sys_tree *tree, struct grp_info *grps); +void display_io_cards(struct io_card *list); +void display_diaginfo(int flag, Prom_node *root, Sys_tree *tree, + struct system_kstat_data *kstats); +Prop *find_prop(Prom_node *pnode, char *name); + +/* Local functions */ +static void opl_disp_environ(void); +static void opl_disp_hw_revisions(Sys_tree *tree, Prom_node *root); +static uint64_t print_opl_memory_line(int lsb, struct cs_status *cs_stat, + int ngrps); +static uint64_t get_opl_mem_regs(Board_node *bnode); +void add_node(Sys_tree *root, Prom_node *pnode); +static int get_prop_size(Prop *prop); + +/* + * Display all the leaf PCI nodes on this board that have "reg" property. + * If the "reg" property is NULL for a leaf node, skip parsing its sibling + * nodes and display the parent node properties. + */ +void +display_pci(Board_node *board) +{ + struct io_card *card_list = NULL; + struct io_card card; + Prom_node *pci, *card_node; + char *name, *type; + int *int_val; + + if (board == NULL) + return; + + /* Initialize common information */ + card.board = board->board_num; + + pci = board->nodes; + while (pci != NULL) { + name = get_node_name(pci); + + /* Skip non-PCI board nodes */ + if ((name == NULL) || (strcmp(name, "pci") != 0)) { + pci = pci->sibling; + continue; + } + + type = (char *)get_prop_val(find_prop(pci, "device_type")); + + /* + * Skip PCI/ebus devices + * They have name == "pci" and type == "pci" + */ + if (strcmp(type, "pci") == 0) { + pci = pci->sibling; + continue; + } + + card_node = pci; + while (card_node != NULL) { + int pci_parent_bridge = 0; + + /* If it does have a child, skip to leaf child */ + if (card_node->child != NULL) { + card_node = card_node->child; + continue; + } + + /* Get name of the card */ + name = (char *)get_prop_val(find_prop + (card_node, "name")); + + /* Get type of card */ + type = (char *)get_prop_val(find_prop + (card_node, "device_type")); + + /* Leaf pci-bridges are to be ignored */ + if (!IS_PCI_BRIDGE(name, type)) { + + /* Get reg property of the node */ + int_val = (int *)get_prop_val(find_prop + (card_node, "reg")); + + /* + * If no "reg" property check to see + * whether parent node has reg property. + * and check if parent is a bridge + */ + if (int_val == NULL) { + Prom_node *cparent = card_node->parent; + if (cparent == NULL) + break; + + name = (char *)get_prop_val(find_prop + (cparent, "name")); + + type = (char *)get_prop_val(find_prop + (cparent, "device_type")); + + /* check if parent is a bridge */ + if (IS_PCI_BRIDGE(name, type)) + pci_parent_bridge = 1; + + int_val = (int *)get_prop_val( + find_prop(cparent, "reg")); + + if (int_val != NULL) + /* Switch to parent */ + card_node = cparent; + else + /* parent node has no reg */ + break; + } + + if (!pci_parent_bridge) { + + name = (char *)get_prop_val(find_prop + (card_node, "name")); + + if (name == NULL) + card.name[0] = '\0'; + else { + (void) snprintf(card.name, + MAXSTRLEN, "%s", name); + } + + /* Get the model of this card */ + name = (char *)get_prop_val(find_prop + (card_node, "model")); + + if (name == NULL) { + (void) snprintf(card.model, + MAXSTRLEN, "%s", "N/A"); + } else { + (void) snprintf(card.model, + MAXSTRLEN, "%s", name); + } + + /* insert card to the list */ + card_list = insert_io_card + (card_list, &card); + + } + + } + + /* + * Parse sibling nodes. + * Then move up the parent's sibling upto the top + * intermediate node + * Stop if pci board node is reached. + */ + if (card_node->sibling != NULL) + card_node = card_node->sibling; + else { + Prom_node *cparent; + cparent = card_node->parent; + card_node = NULL; + while (cparent != NULL) { + if (cparent == pci) + break; + if (cparent->sibling != NULL) { + card_node = cparent->sibling; + break; + } + cparent = cparent->parent; + } + } + + } + + /* On to the next board node */ + pci = pci->sibling; + + } + + display_io_cards(card_list); + free_io_cards(card_list); +} + +/* + * There are no FFB's on OPL. + */ +/*ARGSUSED*/ +void +display_ffb(Board_node *board, int table) +{ +} + +/* + * There are no Sbus's on OPL. + */ +/*ARGSUSED*/ +void +display_sbus(Board_node *board) +{ +} + +/* + * Details of I/O information. Print out all the io cards. + */ +void +display_io_cards(struct io_card *list) +{ + char *hdrfmt = "%-6.6s %-14.14s %-12.12s\n"; + + struct io_card *p; + + if (list == NULL) + return; + + (void) textdomain(TEXT_DOMAIN); + + log_printf(hdrfmt, gettext("LSB"), gettext("Name"), gettext("Model"), + 0); + + log_printf(hdrfmt, "---", "-----------------", "------------", 0); + + for (p = list; p != NULL; p = p->next) { + + /* Board number */ + log_printf(" %02d ", p->board, 0); + + /* Card name */ + log_printf("%-15.15s", p->name, 0); + + /* Card model */ + log_printf("%-12.12s", p->model, 0); + + log_printf("\n", 0); + } + log_printf("\n", 0); +} + +/* + * Details of CPU information. + */ +void +display_cpu_devices(Sys_tree *tree) +{ + Board_node *bnode; + char *hdrfmt = + "%-5.5s %-8.8s %-20.20s %-8.8s %-8.8s %-8.8s %-8.8s\n"; + + (void) textdomain(TEXT_DOMAIN); + + /* + * Display the table header for CPUs . Then display the CPU + * frequency, cache size, and processor revision of all cpus. + */ + log_printf("\n", 0); + log_printf("====================================", 0); + log_printf(gettext(" CPUs "), 0); + log_printf("====================================", 0); + log_printf("\n\n", 0); + + log_printf(hdrfmt, + "", + gettext("CPU"), + gettext(" CPU "), + gettext("Run"), + gettext("L2$"), + gettext("CPU"), + gettext("CPU"), 0); + + log_printf(hdrfmt, + gettext("LSB"), + gettext("Chip"), + gettext(" ID "), + gettext("MHz"), + gettext(" MB"), + gettext("Impl."), + gettext("Mask"), 0); + + log_printf(hdrfmt, + "---", "----", "--------------------", "----", + "---", "-----", "----", 0); + + /* Now display all of the cpus on each board */ + for (bnode = tree->bd_list; bnode != NULL; bnode = bnode->next) { + display_cpus(bnode); + } + + log_printf("\n", 0); +} + +/* + * Display the CPUs present on this board. + */ +void +display_cpus(Board_node *board) +{ + int *impl, *mask, *cpuid, *portid, *l2cache_size; + uint_t freq; /* CPU clock frequency */ + Prom_node *pnode, *cpu; + char *name; + + (void) textdomain(TEXT_DOMAIN); + + /* + * Get the Cpus' properties for display + */ + for (pnode = board->nodes; pnode != NULL; pnode = pnode->sibling) { + char cpu_str[MAXSTRLEN], fcpu_str[MAXSTRLEN] = {0}; + + name = get_node_name(pnode); + if ((name == NULL) || (strncmp(name, "cmp", 3) != 0)) { + continue; + } + + portid = (int *)get_prop_val(find_prop(pnode, "portid")); + freq = (HZ_TO_MHZ(get_cpu_freq(pnode->child))); + l2cache_size = + (int *)get_prop_val + (find_prop(pnode->child, "l2-cache-size")); + impl = + (int *)get_prop_val + (find_prop(pnode->child, "implementation#")); + mask = (int *)get_prop_val(find_prop(pnode->child, "mask#")); + + /* Lsb id */ + log_printf(" %02d ", board->board_num, 0); + + if (portid != NULL) + log_printf("%3d ", (((*portid)>>3)&0x3), 0); + + /* + * Specific parsing of the CMP/CORE/CPU chain. + * The internal cpu tree built by walk_di_tree() + * in common code can be illustrated by the diagram + * below: + * + * cmp->cpu->cpu->cpu->cpu->(next board nodes) + * / \ + * core core + * where "/" or "\" are children + * and "->" are siblings + */ + for (cpu = pnode->sibling; cpu != NULL; ) { + Prom_node *cpu_next = NULL; + + name = get_node_name(cpu); + if ((name == NULL) || (strncmp(name, "cpu", 3) != 0)) { + break; + } + + /* Id assigned to Virtual processor core */ + cpuid = (int *)get_prop_val(find_prop(cpu, "cpuid")); + cpu_next = cpu->sibling; + + if (cpu_next != NULL) { + name = get_node_name(cpu_next); + + if ((name == NULL) || + (strncmp(name, "cpu", 3) != 0)) { + cpu_next = NULL; + } + } + + if (cpuid != NULL) { + /* Used for printing in comma format */ + (void) sprintf(cpu_str, "%4d", *cpuid); + (void) strlcat(fcpu_str, cpu_str, MAXSTRLEN); + + if (cpu_next != NULL) + (void) strlcat(fcpu_str, ",", MAXSTRLEN); + } else { + (void) sprintf(cpu_str, "%4s", "N/A"); + (void) strlcat(fcpu_str, cpu_str, MAXSTRLEN); + + if (cpu_next != NULL) + (void) strlcat(fcpu_str, ",", MAXSTRLEN); + } + cpu = cpu_next; + } + + log_printf("%-20.20s", fcpu_str, 0); + + /* Running frequency */ + if (freq != 0) + log_printf(" %4ld ", freq, 0); + else + log_printf(" %4s ", "N/A", 0); + + /* L2 cache size */ + if (l2cache_size == NULL) + log_printf(" %3s ", "N/A", 0); + else { + log_printf("%4.1f ", + (float)(*l2cache_size) / (float)(1<<20), 0); + } + + + /* Implementation number of processor */ + if (impl != NULL) + log_printf("%4d ", *impl, 0); + else + log_printf("%4s ", "N/A", 0); + + /* Mask Set version */ + /* Bits 31:24 of VER register is mask. */ + /* Mask value : Non MTP mode - 00-7f, MTP mode - 80-ff */ + if (mask == NULL) + log_printf("%4s", "N/A", 0); + else + log_printf("%4d", (*mask)&0xff, 0); + + log_printf("\n", 0); + + } +} + +/* + * Gather memory information: Details of memory information. + */ +static uint64_t +get_opl_mem_regs(Board_node *bnode) +{ + Prom_node *pnode; + struct cs_status *cs_stat; + uint64_t total_mem = 0; + int cs_size, ngrps; + + pnode = dev_find_node(bnode->nodes, "pseudo-mc"); + while (pnode != NULL) { + + cs_size = get_prop_size(find_prop(pnode, "cs-status")); + + if (cs_size > 0) { + + /* OBP returns lists of 7 ints */ + cs_stat = (struct cs_status *)get_prop_val + (find_prop(pnode, "cs-status")); + + /* cs_size must be at least 28 */ + ngrps = cs_size/sizeof (struct cs_status); + + if (cs_stat != NULL) { + total_mem += + print_opl_memory_line(bnode->board_num, + cs_stat, ngrps); + } + } + + pnode = dev_next_node(pnode, "pseudo-mc"); + } + return (total_mem); +} + +/* + * Display memory information. + */ +/*ARGSUSED*/ +void +display_memoryconf(Sys_tree *tree, struct grp_info *grps) +{ + Board_node *bnode = tree->bd_list; + uint64_t total_mem = 0, total_sys_mem = 0; + char *hdrfmt = "\n%-5.5s %-6.6s %-12.12s %-10.10s" + " %-8.8s %-10.10s"; + + (void) textdomain(TEXT_DOMAIN); + + log_printf("======================", 0); + log_printf(gettext(" Memory Configuration "), 0); + log_printf("======================", 0); + log_printf("\n", 0); + + log_printf(hdrfmt, + "", + gettext("Memory"), + gettext("Available"), + gettext("Memory"), + gettext("DIMM"), + gettext("Number of"), + 0); + + log_printf(hdrfmt, + gettext("LSB"), + gettext("Group"), + gettext("Size"), + gettext("Status"), + gettext("Size"), + gettext("DIMMs"), 0); + + log_printf(hdrfmt, + "---", "-------", "------------", "-------", "-----", + "---------", 0); + + log_printf("\n", 0); + + for (bnode = tree->bd_list; bnode != NULL; bnode = bnode->next) { + total_mem += get_opl_mem_regs(bnode); + } + + /* + * Sanity check to ensure that the total amount of system + * memory matches the total number of memory that + * we find here. Display error message if there is a mis-match. + */ + total_sys_mem = (((uint64_t)sysconf(_SC_PAGESIZE) * (uint64_t)sysconf + (_SC_PHYS_PAGES)) / MBYTE); + + if (total_mem != total_sys_mem) { + log_printf(dgettext(TEXT_DOMAIN, + "\nError:total available size [%lldMB] does not match" + " total system memory [%lldMB]\n"), + total_mem, total_sys_mem, 0); + } + +} + +/* + * This function provides Opl's formatting of the memory config + * information that get_opl_mem_regs() has gathered. + */ +static uint64_t +print_opl_memory_line(int lsb, struct cs_status *cs_stat, int ngrps) +{ + int i; + uint64_t total_board_mem = 0; + + (void) textdomain(TEXT_DOMAIN); + + + for (i = 0; i < ngrps; i++) { + int64_t mem_size = 0; + + mem_size = ((((int64_t)cs_stat[i].avail_hi)<<32) + + cs_stat[i].avail_lo); + + if (mem_size == 0) continue; + + /* Lsb Id */ + log_printf(" %02d ", lsb, 0); + + /* Memory Group Number */ + if ((cs_stat[i].cs_number) == 0) + log_printf("%-6.6s", "A", 0); + else + log_printf("%-6.6s", "B", 0); + + /* Memory Group Size */ + log_printf(" %4lldMB ", mem_size/MBYTE, 0); + + total_board_mem += (mem_size/MBYTE); + + /* Memory Group Status */ + log_printf("%-11.11s", + cs_stat[i].status ? "partial": "okay", 0); + + /* DIMM Size */ + log_printf("%4lldMB ", + ((((int64_t)cs_stat[i].dimm_hi)<<32) + + cs_stat[i].dimm_lo)/MBYTE, 0); + + /* Number of DIMMs */ + log_printf("%9d\n", cs_stat[i].dimms); + } + return (total_board_mem); +} + +/* + * Details of hardware revision and environmental status. + */ +/*ARGSUSED*/ +void +display_diaginfo(int flag, Prom_node *root, Sys_tree *tree, + struct system_kstat_data *kstats) +{ + /* Print the PROM revisions */ + if (flag) + opl_disp_hw_revisions(tree, root); +} + +/* + * Gather and display hardware revision and environmental status + */ +/*ARGSUSED*/ +static void +opl_disp_hw_revisions(Sys_tree *tree, Prom_node *root) +{ + char *version; + Prom_node *pnode; + + (void) textdomain(TEXT_DOMAIN); + + /* Print the header */ + log_printf("\n", 0); + log_printf("====================", 0); + log_printf(gettext(" Hardware Revisions "), 0); + log_printf("====================", 0); + log_printf("\n\n", 0); + + /* Display Prom revision header */ + log_printf(gettext("System PROM revisions:"), 0); + log_printf("\n----------------------\n", 0); + log_printf("\n", 0); + + /* Display OBP version info */ + pnode = dev_find_node(root, "openprom"); + if (pnode != NULL) { + version = (char *)get_prop_val(find_prop(pnode, "version")); + if (version != NULL) + log_printf("%s\n\n", version, 0); + else + log_printf("%s\n\n", "N/A", 0); + } + + /* Print the header */ + log_printf("\n", 0); + log_printf("===================", 0); + log_printf(gettext(" Environmental Status "), 0); + log_printf("===================", 0); + log_printf("\n\n", 0); + + opl_disp_environ(); +} + +/* + * Gather environmental information + */ +static void +opl_disp_environ(void) +{ + kstat_ctl_t *kc; + kstat_t *ksp; + kstat_named_t *k; + + if ((kc = kstat_open()) == NULL) + return; + + if ((ksp = kstat_lookup + (kc, "scfd", 0, SCF_SYSTEM_KSTAT_NAME)) == NULL) { + (void) kstat_close(kc); + return; + } + + if (kstat_read(kc, ksp, NULL) == -1) { + (void) kstat_close(kc); + return; + } + + if ((k = (kstat_named_t *)kstat_data_lookup + (ksp, SCF_SECURE_MODE_KSTAT_NAMED)) == NULL) { + (void) kstat_close(kc); + return; + } + + if (k->value.c[0] == SCF_STAT_MODE_LOCK) + log_printf("Mode switch is in LOCK mode ", 0); + else if (k->value.c[0] == SCF_STAT_MODE_UNLOCK) + log_printf("Mode switch is in UNLOCK mode", 0); + else + log_printf("Mode switch is in UNKNOWN mode", 0); + + log_printf("\n", 0); + + (void) kstat_close(kc); +} + + +/* + * Calls do_devinfo() in order to use the libdevinfo device tree + * instead of OBP's device tree. + */ +int +do_prominfo(int syserrlog, char *pgname, int log_flag, int prt_flag) +{ + return (do_devinfo(syserrlog, pgname, log_flag, prt_flag)); +} + +/* + * Return the property value for the Prop + * passed in. (When using libdevinfo) + */ +void * +get_prop_val(Prop *prop) +{ + if (prop == NULL) + return (NULL); + + return ((void *)(prop->value.val_ptr)); +} + +/* + * Return the property size for the Prop + * passed in. (When using libdevinfo) + */ +static int +get_prop_size(Prop *prop) +{ + + if ((prop != NULL) && (prop->size > 0)) + return (prop->size); + else + return (0); +} + + +/* + * Search a Prom node and retrieve the property with the correct + * name. (When using libdevinfo) + */ +Prop * +find_prop(Prom_node *pnode, char *name) +{ + Prop *prop; + + if (pnode == NULL) + return (NULL); + + for (prop = pnode->props; prop != NULL; prop = prop->next) { + if (prop->name.val_ptr != NULL && + strcmp((char *)(prop->name.val_ptr), name) == 0) + break; + } + + return (prop); +} + +/* + * This function adds a board node to the board structure where that + * that node's physical component lives. + */ +void +add_node(Sys_tree *root, Prom_node *pnode) +{ + int board; + Board_node *bnode; + Prom_node *p; + char *type; + + if ((board = get_board_num(pnode)) == -1) { + type = get_node_type(pnode); + if ((type != NULL) && (strcmp(type, "cpu") == 0)) + board = get_board_num((pnode->parent)->parent); + } + + /* find the node with the same board number */ + if ((bnode = find_board(root, board)) == NULL) { + bnode = insert_board(root, board); + bnode->board_type = UNKNOWN_BOARD; + } + + /* now attach this prom node to the board list */ + /* Insert this node at the end of the list */ + pnode->sibling = NULL; + if (bnode->nodes == NULL) + bnode->nodes = pnode; + else { + p = bnode->nodes; + while (p->sibling != NULL) + p = p->sibling; + p->sibling = pnode; + } + +} diff --git a/usr/src/pkgdefs/Makefile b/usr/src/pkgdefs/Makefile index 9e0ad9b9b0..a8d94762ad 100644 --- a/usr/src/pkgdefs/Makefile +++ b/usr/src/pkgdefs/Makefile @@ -47,6 +47,8 @@ sparc_SUBDIRS= \ SUNWdcsu \ SUNWdrcr.u \ SUNWdrr.u \ + SUNWdscpr.u \ + SUNWdscpu.u \ SUNWefcl \ SUNWefcr \ SUNWefcu \ diff --git a/usr/src/pkgdefs/SUNWcakr.u/prototype_com b/usr/src/pkgdefs/SUNWcakr.u/prototype_com index 89ac9a9d5c..ad30c281c6 100644 --- a/usr/src/pkgdefs/SUNWcakr.u/prototype_com +++ b/usr/src/pkgdefs/SUNWcakr.u/prototype_com @@ -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,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" @@ -98,6 +97,33 @@ f none platform/SUNW,Netra-T4/kernel/drv/sparcv9/lombus 755 root sys d none platform/SUNW,Netra-T4/kernel/misc 755 root sys d none platform/SUNW,Netra-T4/kernel/misc/sparcv9 755 root sys s none platform/SUNW,Netra-T4/kernel/misc/sparcv9/platmod=../../../../SUNW,Sun-Fire-280R/kernel/misc/sparcv9/platmod +d none platform/SUNW,SPARC-Enterprise 755 root sys +d none platform/SUNW,SPARC-Enterprise/kernel 755 root sys +d none platform/SUNW,SPARC-Enterprise/kernel/cpu 755 root sys +d none platform/SUNW,SPARC-Enterprise/kernel/cpu/sparcv9 755 root sys +f none platform/SUNW,SPARC-Enterprise/kernel/cpu/sparcv9/FJSV,SPARC64-VI 755 root sys +d none platform/SUNW,SPARC-Enterprise/kernel/crypto 755 root sys +d none platform/SUNW,SPARC-Enterprise/kernel/crypto/sparcv9 755 root sys +s none platform/SUNW,SPARC-Enterprise/kernel/crypto/sparcv9/aes=../../../../sun4u-us3/kernel/crypto/sparcv9/aes +d none platform/SUNW,SPARC-Enterprise/kernel/drv 755 root sys +f none platform/SUNW,SPARC-Enterprise/kernel/drv/dr.conf 644 root sys +f none platform/SUNW,SPARC-Enterprise/kernel/drv/mc-opl.conf 644 root sys +f none platform/SUNW,SPARC-Enterprise/kernel/drv/oplpanel.conf 644 root sys +f none platform/SUNW,SPARC-Enterprise/kernel/drv/options.conf 644 root sys +f none platform/SUNW,SPARC-Enterprise/kernel/drv/scfd.conf 644 root sys +d none platform/SUNW,SPARC-Enterprise/kernel/drv/sparcv9 755 root sys +f none platform/SUNW,SPARC-Enterprise/kernel/drv/sparcv9/dr 755 root sys +f none platform/SUNW,SPARC-Enterprise/kernel/drv/sparcv9/mc-opl 755 root sys +f none platform/SUNW,SPARC-Enterprise/kernel/drv/sparcv9/oplmsu 755 root sys +f none platform/SUNW,SPARC-Enterprise/kernel/drv/sparcv9/oplpanel 755 root sys +f none platform/SUNW,SPARC-Enterprise/kernel/drv/sparcv9/pcicmu 755 root sys +f none platform/SUNW,SPARC-Enterprise/kernel/drv/sparcv9/scfd 755 root sys +d none platform/SUNW,SPARC-Enterprise/kernel/sparcv9 755 root sys +f none platform/SUNW,SPARC-Enterprise/kernel/sparcv9/unix 755 root sys +d none platform/SUNW,SPARC-Enterprise/kernel/misc 755 root sys +d none platform/SUNW,SPARC-Enterprise/kernel/misc/sparcv9 755 root sys +f none platform/SUNW,SPARC-Enterprise/kernel/misc/sparcv9/drmach 755 root sys +f none platform/SUNW,SPARC-Enterprise/kernel/misc/sparcv9/platmod 755 root sys d none platform/SUNW,Serverblade1 755 root sys d none platform/SUNW,Serverblade1/kernel 755 root sys d none platform/SUNW,Serverblade1/kernel/drv 755 root sys @@ -463,6 +489,7 @@ f none platform/sun4u/kernel/misc/sparcv9/forthdebug 755 root sys f none platform/sun4u/kernel/misc/sparcv9/i2c_svc 755 root sys l none platform/sun4u/kernel/misc/sparcv9/md5=../../../kernel/crypto/sparcv9/md5 f none platform/sun4u/kernel/misc/sparcv9/obpsym 755 root sys +f none platform/sun4u/kernel/misc/sparcv9/opl_cfg 755 root sys f none platform/sun4u/kernel/misc/sparcv9/platmod 755 root sys f none platform/sun4u/kernel/misc/sparcv9/sbd 755 root sys l none platform/sun4u/kernel/misc/sparcv9/sha1=../../../kernel/crypto/sparcv9/sha1 @@ -484,6 +511,7 @@ f none platform/sun4u/kernel/tod/sparcv9/todm5819 755 root sys f none platform/sun4u/kernel/tod/sparcv9/todm5819p_rmc 755 root sys f none platform/sun4u/kernel/tod/sparcv9/todm5823 755 root sys f none platform/sun4u/kernel/tod/sparcv9/todmostek 755 root sys +f none platform/sun4u/kernel/tod/sparcv9/todopl 755 root sys f none platform/sun4u/kernel/tod/sparcv9/todsg 755 root sys f none platform/sun4u/kernel/tod/sparcv9/todstarcat 755 root sys f none platform/sun4u/kernel/tod/sparcv9/todstarfire 755 root sys diff --git a/usr/src/pkgdefs/SUNWcar.u/prototype_com b/usr/src/pkgdefs/SUNWcar.u/prototype_com index 6c585372b4..601322484f 100644 --- a/usr/src/pkgdefs/SUNWcar.u/prototype_com +++ b/usr/src/pkgdefs/SUNWcar.u/prototype_com @@ -58,6 +58,9 @@ d none platform/SUNW,Netra-T12 755 root sys d none platform/SUNW,Netra-T4 755 root sys d none platform/SUNW,Netra-CP2300 755 root sys d none platform/SUNW,Netra-CP3010 755 root sys +d none platform/SUNW,SPARC-Enterprise 755 root sys +s none platform/FJSV,SPARC-Enterprise=SUNW,SPARC-Enterprise +s none platform/SUNW,OPL-Enterprise=SUNW,SPARC-Enterprise d none platform/SUNW,Serverblade1 755 root sys d none platform/SUNW,Sun-Blade-100 755 root sys d none platform/SUNW,Sun-Blade-1000 755 root sys @@ -129,6 +132,8 @@ d none platform/SUNW,UltraSPARC-IIe-NetraCT-60/lib/sparcv9 755 root bin d none platform/SUNW,UltraSPARC-IIi-Netract/lib/sparcv9 755 root bin d none platform/SUNW,Netra-CP2300/lib/sparcv9 755 root bin d none platform/SUNW,Netra-CP3010/lib/sparcv9 755 root bin +d none platform/SUNW,SPARC-Enterprise/lib/sparcv9 755 root bin +f none platform/SUNW,SPARC-Enterprise/lib/sparcv9/libc_psr.so.1 755 root bin d none platform/sun4u-us3/lib/sparcv9 755 root bin d none platform/sun4u-us3/lib/sparcv9/libc_psr 755 root bin f none platform/sun4u/lib/sparcv9/libc_psr.so.1 755 root bin @@ -239,6 +244,8 @@ d none platform/SUNW,UltraSPARC-IIe-NetraCT-60/lib 755 root bin d none platform/SUNW,UltraSPARC-IIi-Netract/lib 755 root bin d none platform/SUNW,Netra-CP2300/lib 755 root bin d none platform/SUNW,Netra-CP3010/lib 755 root bin +d none platform/SUNW,SPARC-Enterprise/lib 755 root bin +f none platform/SUNW,SPARC-Enterprise/lib/libc_psr.so.1 755 root bin f none platform/sun4u/lib/libc_psr.so.1 755 root bin d none platform/sun4u-us3/lib 755 root sys v none platform/sun4u-us3/lib/libc_psr.so.1 755 root bin diff --git a/usr/src/pkgdefs/SUNWcpcu/prototype_sparc b/usr/src/pkgdefs/SUNWcpcu/prototype_sparc index 1c316216ee..999f3bd5a8 100644 --- a/usr/src/pkgdefs/SUNWcpcu/prototype_sparc +++ b/usr/src/pkgdefs/SUNWcpcu/prototype_sparc @@ -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,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" @@ -44,7 +43,9 @@ # d none usr/bin/sparcv9 755 root bin f none usr/bin/sparcv9/cputrack 555 root bin +f none usr/include/libdscp.h 644 root bin d none usr/kernel/pcbe/sparcv9 755 root sys +f none usr/kernel/pcbe/sparcv9/pcbe.4.6 755 root sys f none usr/kernel/pcbe/sparcv9/pcbe.62 755 root sys l none usr/kernel/pcbe/sparcv9/pcbe.23=pcbe.62 755 root sys d none usr/lib/sparcv9 755 root bin diff --git a/usr/src/pkgdefs/SUNWcryr/prototype_sparc b/usr/src/pkgdefs/SUNWcryr/prototype_sparc index 5c5e836a0d..263defca16 100644 --- a/usr/src/pkgdefs/SUNWcryr/prototype_sparc +++ b/usr/src/pkgdefs/SUNWcryr/prototype_sparc @@ -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,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" @@ -71,6 +70,11 @@ d none platform/sun4v/kernel/crypto/sparcv9 755 root sys f none platform/sun4v/kernel/crypto/sparcv9/arcfour2048 755 root sys d none platform/SUNW,Netra-T12 755 root sys d none platform/SUNW,Netra-T4 755 root sys +d none platform/SUNW,SPARC-Enterprise 755 root sys +d none platform/SUNW,SPARC-Enterprise/kernel 755 root sys +d none platform/SUNW,SPARC-Enterprise/kernel/crypto 755 root sys +d none platform/SUNW,SPARC-Enterprise/kernel/crypto/sparcv9 755 root sys +s none platform/SUNW,SPARC-Enterprise/kernel/crypto/sparcv9/aes256=../../../../sun4u-us3/kernel/crypto/sparcv9/aes256 d none platform/SUNW,Sun-Blade-1000 755 root sys d none platform/SUNW,Sun-Blade-1500 755 root sys d none platform/SUNW,Sun-Blade-2500 755 root sys diff --git a/usr/src/pkgdefs/SUNWcsr/Makefile b/usr/src/pkgdefs/SUNWcsr/Makefile index 3f0c540da7..9ce4595bd8 100644 --- a/usr/src/pkgdefs/SUNWcsr/Makefile +++ b/usr/src/pkgdefs/SUNWcsr/Makefile @@ -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,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" @@ -66,6 +65,7 @@ DATAFILES += \ i.shadow \ i.syslogconf \ i.tiservices \ + i.ttydefs \ i.ttysrch \ i.vfstab \ i.voldconf diff --git a/usr/src/pkgdefs/SUNWcsr/pkginfo.tmpl b/usr/src/pkgdefs/SUNWcsr/pkginfo.tmpl index ec4b2fa59e..f88e459768 100644 --- a/usr/src/pkgdefs/SUNWcsr/pkginfo.tmpl +++ b/usr/src/pkgdefs/SUNWcsr/pkginfo.tmpl @@ -44,7 +44,7 @@ DESC="core software for a specific instruction-set architecture" VENDOR="Sun Microsystems, Inc." HOTLINE="Please contact your local service provider" EMAIL="" -CLASSES="none initd renamenew preserve cronroot passwd tiservices inetdconf definit etcremote nsswitch netconfig deflogin defsu syslogconf ttysrch group inittab etcrpc etcprofile mailxrc shadow voldconf rmmconf locallogin localprofile logadmconf nscd fstypes pamconf services rbac renameold dhcpinittab policyconf pkcs11confbase defpasswd vfstab manifest" +CLASSES="none ttydefs initd renamenew preserve cronroot passwd tiservices inetdconf definit etcremote nsswitch netconfig deflogin defsu syslogconf ttysrch group inittab etcrpc etcprofile mailxrc shadow voldconf rmmconf locallogin localprofile logadmconf nscd fstypes pamconf services rbac renameold dhcpinittab policyconf pkcs11confbase defpasswd vfstab manifest" BASEDIR=/ SUNW_PKGVERS="1.0" SUNW_PKG_ALLZONES="true" diff --git a/usr/src/pkgdefs/SUNWcsr/prototype_com b/usr/src/pkgdefs/SUNWcsr/prototype_com index d70ea97e23..abe3f75780 100644 --- a/usr/src/pkgdefs/SUNWcsr/prototype_com +++ b/usr/src/pkgdefs/SUNWcsr/prototype_com @@ -81,6 +81,7 @@ i i.defpasswd i i.vfstab i i.manifest i r.manifest +i i.ttydefs # # source locations relative to the prototype file # @@ -305,7 +306,7 @@ e syslogconf etc/syslog.conf 644 root sys s none etc/tar=../usr/sbin/tar s none etc/telinit=../sbin/init d none etc/tm 755 root sys -f none etc/ttydefs 644 root sys +e ttydefs etc/ttydefs 644 root sys e ttysrch etc/ttysrch 644 root sys s none etc/uadmin=../sbin/uadmin s none etc/umount=../sbin/umount diff --git a/usr/src/pkgdefs/SUNWcsr/prototype_sparc b/usr/src/pkgdefs/SUNWcsr/prototype_sparc index 0af3d40291..52a172cbae 100644 --- a/usr/src/pkgdefs/SUNWcsr/prototype_sparc +++ b/usr/src/pkgdefs/SUNWcsr/prototype_sparc @@ -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,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" @@ -52,6 +51,7 @@ d none var/ld/sparcv9 755 root bin s none var/ld/64=sparcv9 d none var/svc/manifest/platform/sun4u 755 root sys f manifest var/svc/manifest/platform/sun4u/mpxio-upgrade.xml 444 root sys +f none var/svc/profile/platform_SUNW,SPARC-Enterprise.xml 444 root sys f none var/svc/profile/platform_SUNW,Sun-Fire.xml 444 root sys f none var/svc/profile/platform_SUNW,Sun-Fire-880.xml 444 root sys l none var/svc/profile/platform_SUNW,Sun-Fire-V890.xml=./platform_SUNW,Sun-Fire-880.xml diff --git a/usr/src/pkgdefs/SUNWdscpr.u/Makefile b/usr/src/pkgdefs/SUNWdscpr.u/Makefile new file mode 100644 index 0000000000..252dd87619 --- /dev/null +++ b/usr/src/pkgdefs/SUNWdscpr.u/Makefile @@ -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 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.com + +DATAFILES += i.manifest r.manifest + +.KEEP_STATE: + +all: $(FILES) depend +install: all pkg + +include ../Makefile.targ +include ../Makefile.prtarg diff --git a/usr/src/pkgdefs/SUNWdscpr.u/depend b/usr/src/pkgdefs/SUNWdscpr.u/depend new file mode 100644 index 0000000000..befdb8b1aa --- /dev/null +++ b/usr/src/pkgdefs/SUNWdscpr.u/depend @@ -0,0 +1,53 @@ +# +# Copyright 2006 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 +# +# ident "%Z%%M% %I% %E% SMI" +# +# 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 +R SUNWdcsr Domain Configuration Server, (Root) +R SUNWdcsu Domain Configuration Server diff --git a/usr/src/pkgdefs/SUNWdscpr.u/pkginfo.tmpl b/usr/src/pkgdefs/SUNWdscpr.u/pkginfo.tmpl new file mode 100644 index 0000000000..2bb312bb71 --- /dev/null +++ b/usr/src/pkgdefs/SUNWdscpr.u/pkginfo.tmpl @@ -0,0 +1,56 @@ +# +# 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. +# +# ident "%Z%%M% %I% %E% SMI" +# +# This required package information file describes characteristics of the +# package, such as package abbreviation, full package name, package version, +# and package architecture. +# +PKG="SUNWdscpr" +NAME="Domain to Service Processor Communications Protocol (Root)" +ARCH="sparc.sun4u" +VERSION="ONVERS,REV=0.0.0" +SUNW_PRODNAME="SunOS" +SUNW_PRODVERS="RELEASE/VERSION" +SUNW_PKGTYPE="root" +MAXINST="1000" +CATEGORY="system" +DESC="Domain to Service Processor Communications Protocol (Root)" +VENDOR="Sun Microsystems, Inc." +HOTLINE="Please contact your local service provider" +EMAIL="" +CLASSES="none manifest" +BASEDIR=/ +SUNW_PKGVERS="1.0" +SUNW_PKG_ALLZONES="true" +SUNW_PKG_HOLLOW="true" +SUNW_PKG_THISZONE="false" +#VSTOCK="<reserved by Release Engineering for package part #>" +#ISTATES="<developer defined>" +#RSTATES='<developer defined>' +#ULIMIT="<developer defined>" +#ORDER="<developer defined>" +#PSTAMP="<developer defined>" +#INTONLY="<developer defined>" diff --git a/usr/src/pkgdefs/SUNWdscpr.u/prototype_com b/usr/src/pkgdefs/SUNWdscpr.u/prototype_com new file mode 100644 index 0000000000..d2d6c549c8 --- /dev/null +++ b/usr/src/pkgdefs/SUNWdscpr.u/prototype_com @@ -0,0 +1,66 @@ +# +# 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 +# +# +#ident "%Z%%M% %I% %E% SMI" +# +# Copyright 2006 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 + +# packaging files +i pkginfo +i copyright +i depend +i i.manifest +i r.manifest +# +# source locations relative to the prototype file +# +# SUNWdscpr.u +# +d none lib 0755 root bin +d none lib/svc 0755 root bin +d none lib/svc/method 0755 root bin +f none lib/svc/method/svc-dscp 0555 root bin +d none platform 755 root sys +d none platform/SUNW,SPARC-Enterprise 755 root sys +d none platform/SUNW,SPARC-Enterprise/kernel 755 root sys +d none platform/SUNW,SPARC-Enterprise/kernel/drv 755 root sys +f none platform/SUNW,SPARC-Enterprise/kernel/drv/dm2s.conf 644 root sys +f none platform/SUNW,SPARC-Enterprise/kernel/drv/oplkmdrv.conf 644 root sys +d none platform/SUNW,SPARC-Enterprise/kernel/drv/sparcv9 755 root sys +f none platform/SUNW,SPARC-Enterprise/kernel/drv/sparcv9/dm2s 755 root sys +f none platform/SUNW,SPARC-Enterprise/kernel/drv/sparcv9/oplkmdrv 755 root sys +d none var 0755 root sys +d none var/svc 0755 root sys +d none var/svc/manifest 0755 root sys +d none var/svc/manifest/platform 0755 root sys +d none var/svc/manifest/platform/sun4u 0755 root sys +f manifest var/svc/manifest/platform/sun4u/dscp.xml 0444 root sys diff --git a/usr/src/pkgdefs/SUNWdscpr.u/prototype_sparc b/usr/src/pkgdefs/SUNWdscpr.u/prototype_sparc new file mode 100644 index 0000000000..af05ed1d6d --- /dev/null +++ b/usr/src/pkgdefs/SUNWdscpr.u/prototype_sparc @@ -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 +# +# +#ident "%Z%%M% %I% %E% SMI" +# +# Copyright 2006 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 + +# +# Include ISA independent files (prototype_com) +# +!include prototype_com +# +# +# +# List files which are SPARC specific here +# +# source locations relative to the prototype file +# +# +# SUNWdscpr.u +# diff --git a/usr/src/pkgdefs/SUNWdscpu.u/Makefile b/usr/src/pkgdefs/SUNWdscpu.u/Makefile new file mode 100644 index 0000000000..9942a1fdeb --- /dev/null +++ b/usr/src/pkgdefs/SUNWdscpu.u/Makefile @@ -0,0 +1,36 @@ +# +# 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. +# +#ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.com + +.KEEP_STATE: + +all: $(FILES) depend +install: all pkg + +include ../Makefile.targ +include ../Makefile.prtarg diff --git a/usr/src/pkgdefs/SUNWdscpu.u/depend b/usr/src/pkgdefs/SUNWdscpu.u/depend new file mode 100644 index 0000000000..8c22c9d617 --- /dev/null +++ b/usr/src/pkgdefs/SUNWdscpu.u/depend @@ -0,0 +1,54 @@ +# +# Copyright 2006 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 +# +# ident "%Z%%M% %I% %E% SMI" +# +# 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 SUNWpppdu Solaris PPP daemon and utilities +R SUNWdcsr Domain Configuration Server, (Root) +R SUNWdcsu Domain Configuration Server diff --git a/usr/src/pkgdefs/SUNWdscpu.u/pkginfo.tmpl b/usr/src/pkgdefs/SUNWdscpu.u/pkginfo.tmpl new file mode 100644 index 0000000000..b0810e949a --- /dev/null +++ b/usr/src/pkgdefs/SUNWdscpu.u/pkginfo.tmpl @@ -0,0 +1,55 @@ +# +# Copyright 2006 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 +# +# ident "%Z%%M% %I% %E% SMI" +# +# This required package information file describes characteristics of the +# package, such as package abbreviation, full package name, package version, +# and package architecture. +# +PKG="SUNWdscpu" +NAME="Domain to Service Processor Communications Protocol (Usr)" +ARCH="sparc.sun4u" +VERSION="ONVERS,REV=0.0.0" +SUNW_PRODNAME="SunOS" +SUNW_PRODVERS="RELEASE/VERSION" +SUNW_PKGTYPE="root" +MAXINST="1000" +CATEGORY="system" +DESC="Domain to Service Processor Communications Protocol (Usr)" +VENDOR="Sun Microsystems, Inc." +HOTLINE="Please contact your local service provider" +EMAIL="" +CLASSES="none" +BASEDIR=/ +SUNW_PKGVERS="1.0" +SUNW_PKG_ALLZONES="true" +SUNW_PKG_HOLLOW="true" +SUNW_PKG_THISZONE="false" +#VSTOCK="<reserved by Release Engineering for package part #>" +#ISTATES="<developer defined>" +#RSTATES='<developer defined>' +#ULIMIT="<developer defined>" +#ORDER="<developer defined>" +#PSTAMP="<developer defined>" +#INTONLY="<developer defined>" diff --git a/usr/src/pkgdefs/SUNWdscpu.u/prototype_com b/usr/src/pkgdefs/SUNWdscpu.u/prototype_com new file mode 100644 index 0000000000..b3557383c5 --- /dev/null +++ b/usr/src/pkgdefs/SUNWdscpu.u/prototype_com @@ -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 +# +# +#ident "%Z%%M% %I% %E% SMI" +# +# Copyright 2006 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 + +# packaging files +i pkginfo +i copyright +i depend +# +# source locations relative to the prototype file +# +# SUNWdscpu.u +# +d none usr 755 root sys +d none usr/platform 755 root sys +d none usr/platform/SUNW,SPARC-Enterprise 755 root sys +d none usr/platform/SUNW,SPARC-Enterprise/lib 755 root bin +f none usr/platform/SUNW,SPARC-Enterprise/lib/dscp.ppp.options 555 root sys +s none usr/platform/SUNW,SPARC-Enterprise/lib/libdscp.so=./libdscp.so.1 +f none usr/platform/SUNW,SPARC-Enterprise/lib/libdscp.so.1 755 root bin +f none usr/platform/SUNW,SPARC-Enterprise/lib/llib-ldscp.ln 644 root sys +d none usr/platform/SUNW,SPARC-Enterprise/sbin 755 root bin +f none usr/platform/SUNW,SPARC-Enterprise/sbin/prtdscp 755 root bin diff --git a/usr/src/pkgdefs/SUNWdscpu.u/prototype_sparc b/usr/src/pkgdefs/SUNWdscpu.u/prototype_sparc new file mode 100644 index 0000000000..1286626a37 --- /dev/null +++ b/usr/src/pkgdefs/SUNWdscpu.u/prototype_sparc @@ -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 +# +# +#ident "%Z%%M% %I% %E% SMI" +# +# Copyright 2006 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 + +# +# Include ISA independent files (prototype_com) +# +!include prototype_com +# +# +# +# List files which are SPARC specific here +# +# source locations relative to the prototype file +# +# +# SUNWdscpu.u +# diff --git a/usr/src/pkgdefs/SUNWefcl/prototype_sparc b/usr/src/pkgdefs/SUNWefcl/prototype_sparc index 7c8c6748d5..4205fd3154 100644 --- a/usr/src/pkgdefs/SUNWefcl/prototype_sparc +++ b/usr/src/pkgdefs/SUNWefcl/prototype_sparc @@ -63,6 +63,8 @@ f none usr/lib/efcode/sparcv9/lfc_upa_pci.so 755 root bin f none usr/lib/efcode/sparcv9/lfc_gptwo.so 755 root bin s none usr/lib/efcode/sparcv9/lfc_gptwo_gptwo.so=lfc_gptwo.so s none usr/lib/efcode/sparcv9/lfc_gptwo_pci.so=lfc_upa_pci.so +f none usr/lib/efcode/sparcv9/lfc_jupiter.so 755 root bin +s none usr/lib/efcode/sparcv9/lfc_jupiter_jupiter.so=lfc_jupiter.so s none usr/lib/efcode/sparcv9/lfc_pciex_pciex.so=lfc_upa_pci.so s none usr/lib/efcode/sparcv9/lfc_pciex_pci.so=lfc_upa_pci.so s none usr/lib/efcode/sparcv9/lfc_pci_pciex.so=lfc_upa_pci.so diff --git a/usr/src/pkgdefs/SUNWfmd/prototype_sparc b/usr/src/pkgdefs/SUNWfmd/prototype_sparc index b63ef0d4a3..96dbb9de5d 100644 --- a/usr/src/pkgdefs/SUNWfmd/prototype_sparc +++ b/usr/src/pkgdefs/SUNWfmd/prototype_sparc @@ -74,6 +74,7 @@ d none usr/platform/sun4u/lib/fm 755 root bin d none usr/platform/sun4u/lib/fm/eft 755 root bin f none usr/platform/sun4u/lib/fm/eft/fire.eft 444 root bin f none usr/platform/sun4u/lib/fm/eft/psycho.eft 444 root bin +f none usr/platform/sun4u/lib/fm/eft/oberon.eft 444 root bin f none usr/platform/sun4u/lib/fm/eft/schizo.eft 444 root bin f none usr/platform/sun4u/lib/fm/eft/tomatillo.eft 444 root bin f none usr/platform/sun4u/lib/fm/eft/xmits.eft 444 root bin @@ -109,6 +110,13 @@ f none usr/platform/sun4v/lib/fm/topo/plugins/chip.so 555 root bin f none usr/platform/sun4v/lib/fm/topo/plugins/hostbridge.so 555 root bin f none usr/platform/sun4v/lib/fm/topo/plugins/pcibus.so 555 root bin f none usr/platform/sun4v/lib/fm/topo/plugins/ioboard.so 555 root bin +d none usr/platform/SUNW,SPARC-Enterprise 755 root sys +d none usr/platform/SUNW,SPARC-Enterprise/lib 755 root bin +d none usr/platform/SUNW,SPARC-Enterprise/lib/fm 755 root bin +d none usr/platform/SUNW,SPARC-Enterprise/lib/fm/fmd 755 root bin +d none usr/platform/SUNW,SPARC-Enterprise/lib/fm/fmd/plugins 755 root bin +f none usr/platform/SUNW,SPARC-Enterprise/lib/fm/fmd/plugins/event-transport.so 555 root bin +f none usr/platform/SUNW,SPARC-Enterprise/lib/fm/fmd/plugins/event-transport.conf 644 root bin d none usr/platform/SUNW,Sun-Fire 755 root sys d none usr/platform/SUNW,Sun-Fire/lib 755 root bin d none usr/platform/SUNW,Sun-Fire/lib/fm 755 root bin diff --git a/usr/src/pkgdefs/SUNWhea/prototype_com b/usr/src/pkgdefs/SUNWhea/prototype_com index 6121faaaae..f265268418 100644 --- a/usr/src/pkgdefs/SUNWhea/prototype_com +++ b/usr/src/pkgdefs/SUNWhea/prototype_com @@ -666,6 +666,7 @@ d none usr/include/sys/fm/fs 755 root bin f none usr/include/sys/fm/fs/zfs.h 644 root bin d none usr/include/sys/fm/io 755 root bin f none usr/include/sys/fm/io/ddi.h 644 root bin +f none usr/include/sys/fm/io/opl_mc_fm.h 644 root bin f none usr/include/sys/fm/io/pci.h 644 root bin f none usr/include/sys/fm/io/sun4upci.h 644 root bin f none usr/include/sys/frame.h 644 root bin diff --git a/usr/src/pkgdefs/SUNWhea/prototype_sparc b/usr/src/pkgdefs/SUNWhea/prototype_sparc index 46e43ff0aa..524ffd4913 100644 --- a/usr/src/pkgdefs/SUNWhea/prototype_sparc +++ b/usr/src/pkgdefs/SUNWhea/prototype_sparc @@ -82,6 +82,7 @@ f none usr/include/sys/fdvar.h 644 root bin f none usr/include/sys/fm/cpu/UltraSPARC-II.h 644 root bin f none usr/include/sys/fm/cpu/UltraSPARC-III.h 644 root bin f none usr/include/sys/fm/cpu/UltraSPARC-T1.h 644 root bin +f none usr/include/sys/fm/cpu/SPARC64-VI.h 644 root bin d none usr/include/sys/fpu 755 root bin f none usr/include/sys/fpu/fpu_simulator.h 644 root bin f none usr/include/sys/fpu/fpusystm.h 644 root bin @@ -113,6 +114,8 @@ f none usr/include/sys/zsdev.h 644 root bin d none usr/platform 755 root sys d none usr/platform/sun4u 755 root sys d none usr/platform/sun4u/include 755 root bin +d none usr/platform/SUNW,SPARC-Enterprise 755 root sys +s none usr/platform/SUNW,SPARC-Enterprise/include=../sun4u/include d none usr/platform/SUNW,Ultra-2 755 root sys s none usr/platform/SUNW,Ultra-2/include=../sun4u/include d none usr/platform/SUNW,Ultra-250 755 root sys @@ -182,6 +185,7 @@ f none usr/platform/sun4u/include/sys/clock.h 644 root bin f none usr/platform/sun4u/include/sys/cmp.h 644 root bin f none usr/platform/sun4u/include/sys/cpc_ultra.h 644 root bin f none usr/platform/sun4u/include/sys/cpr_impl.h 644 root bin +f none usr/platform/sun4u/include/sys/cpu_impl.h 644 root bin f none usr/platform/sun4u/include/sys/cpu_sgnblk_defs.h 644 root bin f none usr/platform/sun4u/include/sys/daktari.h 644 root bin f none usr/platform/sun4u/include/sys/ddi_subrdefs.h 644 root bin @@ -225,6 +229,8 @@ f none usr/platform/sun4u/include/sys/memlist_plat.h 644 root bin f none usr/platform/sun4u/include/sys/memnode.h 644 root bin f none usr/platform/sun4u/include/sys/mmu.h 644 root bin f none usr/platform/sun4u/include/sys/nexusdebug.h 644 root bin +f none usr/platform/sun4u/include/sys/opl_hwdesc.h 644 root bin +f none usr/platform/sun4u/include/sys/opl_module.h 644 root bin f none usr/platform/sun4u/include/sys/prom_debug.h 644 root bin f none usr/platform/sun4u/include/sys/sbd_ioctl.h 644 root bin f none usr/platform/sun4u/include/sys/prom_plat.h 644 root bin diff --git a/usr/src/pkgdefs/SUNWkvm.u/prototype_com b/usr/src/pkgdefs/SUNWkvm.u/prototype_com index f02ea4daa2..234ac77595 100644 --- a/usr/src/pkgdefs/SUNWkvm.u/prototype_com +++ b/usr/src/pkgdefs/SUNWkvm.u/prototype_com @@ -1,10 +1,9 @@ -# + # 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,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #pragma ident "%Z%%M% %I% %E% SMI" @@ -50,6 +49,9 @@ d none usr/platform/sun4u-us3 755 root sys # # other platform directories # +d none usr/platform/SUNW,SPARC-Enterprise 755 root sys +s none usr/platform/FJSV,SPARC-Enterprise=SUNW,SPARC-Enterprise +s none usr/platform/SUNW,OPL-Enterprise=SUNW,SPARC-Enterprise d none usr/platform/SUNW,Ultra-2 755 root sys d none usr/platform/SUNW,Ultra-250 755 root sys d none usr/platform/SUNW,Ultra-4 755 root sys @@ -95,6 +97,11 @@ s none usr/platform/SUNW,Sun-Blade-1000/sbin=../sun4u/sbin s none usr/platform/SUNW,Sun-Blade-1500/sbin=../sun4u/sbin s none usr/platform/SUNW,Sun-Blade-2500/sbin=../sun4u/sbin s none usr/platform/SUNW,A70/sbin=../sun4u/sbin +d none usr/platform/SUNW,SPARC-Enterprise/sbin 755 root bin +s none usr/platform/SUNW,SPARC-Enterprise/sbin/eeprom=../../sun4u/sbin/eeprom +s none usr/platform/SUNW,SPARC-Enterprise/sbin/fruadm=../../sun4u/sbin/fruadm +s none usr/platform/SUNW,SPARC-Enterprise/sbin/prtdiag=../../sun4u/sbin/prtdiag +s none usr/platform/SUNW,SPARC-Enterprise/sbin/trapstat=../../sun4u/sbin/trapstat d none usr/platform/SUNW,Sun-Fire-V445/sbin 755 root bin s none usr/platform/SUNW,Sun-Fire-V445/sbin/eeprom=../../sun4u/sbin/eeprom s none usr/platform/SUNW,Sun-Fire-V445/sbin/prtdiag=../../sun4u/sbin/prtdiag @@ -145,6 +152,7 @@ f none usr/platform/sun4u/lib/libprtdiag.so.1 755 root bin s none usr/platform/sun4u/lib/libprtdiag.so=./libprtdiag.so.1 f none usr/platform/SUNW,Netra-CP3010/lib/libprtdiag_psr.so.1 644 root bin f none usr/platform/SUNW,Ultra-2/lib/libprtdiag_psr.so.1 644 root bin +f none usr/platform/SUNW,SPARC-Enterprise/lib/libprtdiag_psr.so.1 644 root bin s none usr/platform/sun4u/lib/libprtdiag_psr.so.1=../../SUNW,Ultra-2/lib/libprtdiag_psr.so.1 f none usr/platform/SUNW,Ultra-250/lib/libprtdiag_psr.so.1 644 root bin f none usr/platform/SUNW,Ultra-4/lib/libprtdiag_psr.so.1 644 root bin @@ -164,6 +172,7 @@ s none usr/platform/SUNW,UltraSPARC-IIe-NetraCT-40/lib/libprtdiag_psr.so.1=../.. # d none usr/platform/sun4u/lib 755 root bin d none usr/platform/sun4u-us3/lib 755 root bin +d none usr/platform/SUNW,SPARC-Enterprise/lib 755 root bin d none usr/platform/SUNW,Ultra-2/lib 755 root bin d none usr/platform/SUNW,Ultra-250/lib 755 root bin d none usr/platform/SUNW,Ultra-4/lib 755 root bin diff --git a/usr/src/pkgdefs/SUNWonmtst.u/prototype_sparc b/usr/src/pkgdefs/SUNWonmtst.u/prototype_sparc index d9b7bd61c6..e838c1845c 100644 --- a/usr/src/pkgdefs/SUNWonmtst.u/prototype_sparc +++ b/usr/src/pkgdefs/SUNWonmtst.u/prototype_sparc @@ -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,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #pragma ident "%Z%%M% %I% %E% SMI" @@ -64,6 +63,7 @@ f none usr/platform/sun4u/include/sys/memtestio_ch.h 644 root bin f none usr/platform/sun4u/include/sys/memtestio_chp.h 644 root bin f none usr/platform/sun4u/include/sys/memtestio_ja.h 644 root bin f none usr/platform/sun4u/include/sys/memtestio_jg.h 644 root bin +f none usr/platform/sun4u/include/sys/memtestio_oc.h 644 root bin f none usr/platform/sun4u/include/sys/memtestio_pn.h 644 root bin f none usr/platform/sun4u/include/sys/memtestio_sf.h 644 root bin f none usr/platform/sun4u/include/sys/memtestio_sr.h 644 root bin diff --git a/usr/src/pkgdefs/SUNWsckmr/Makefile b/usr/src/pkgdefs/SUNWsckmr/Makefile index 760a57c075..0b69891c63 100644 --- a/usr/src/pkgdefs/SUNWsckmr/Makefile +++ b/usr/src/pkgdefs/SUNWsckmr/Makefile @@ -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,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2000, 2002 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" @@ -28,8 +27,7 @@ include ../Makefile.com -DATAFILES += i.initd depend -CHKINSTALLSRC=checkinstall.initd +DATAFILES += i.manifest r.manifest .KEEP_STATE: diff --git a/usr/src/pkgdefs/SUNWsckmr/depend b/usr/src/pkgdefs/SUNWsckmr/depend new file mode 100644 index 0000000000..fe746984a6 --- /dev/null +++ b/usr/src/pkgdefs/SUNWsckmr/depend @@ -0,0 +1,52 @@ +# +# Copyright 2006 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 +# +# ident "%Z%%M% %I% %E% SMI" +# +# 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 SUNWsckmu Key Management daemon diff --git a/usr/src/pkgdefs/SUNWsckmr/pkginfo.tmpl b/usr/src/pkgdefs/SUNWsckmr/pkginfo.tmpl index 2dc705e3a0..ce00839a06 100644 --- a/usr/src/pkgdefs/SUNWsckmr/pkginfo.tmpl +++ b/usr/src/pkgdefs/SUNWsckmr/pkginfo.tmpl @@ -32,7 +32,7 @@ # and package architecture. # PKG="SUNWsckmr" -NAME="Init script & links for Sun Fire 15000 Key Management daemon" +NAME="SMF service for the Key Management daemon" ARCH="sparc" VERSION="ONVERS,REV=0.0.0" SUNW_PRODNAME="SunOS" @@ -40,13 +40,13 @@ SUNW_PRODVERS="RELEASE/VERSION" SUNW_PKGTYPE="root" MAXINST="1000" CATEGORY="system" -DESC="Init script & links for Sun Fire 15000 Key Management daemon" +DESC="SMF service for the Key Management daemon" VENDOR="Sun Microsystems, Inc." HOTLINE="Please contact your local service provider" EMAIL="" -CLASSES="none initd" +CLASSES="none manifest" BASEDIR=/ -SUNW_PKGVERS="1.0" +SUNW_PKGVERS="2.0" SUNW_PKG_ALLZONES="true" SUNW_PKG_HOLLOW="true" SUNW_PKG_THISZONE="false" diff --git a/usr/src/pkgdefs/SUNWsckmr/preremove b/usr/src/pkgdefs/SUNWsckmr/preremove index 9cf8e1bd47..832c16ba0e 100644 --- a/usr/src/pkgdefs/SUNWsckmr/preremove +++ b/usr/src/pkgdefs/SUNWsckmr/preremove @@ -3,9 +3,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. @@ -23,8 +22,8 @@ # #pragma ident "%Z%%M% %I% %E% SMI" # -# Copyright (c) 2001 by Sun Microsystems, Inc. -# All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. # PATH="/usr/bin:/usr/sbin:${PATH}" @@ -32,6 +31,16 @@ export PATH IPSECINIT="$BASEDIR/etc/inet/ipsecinit.conf" +# +# Update IPsec policy configuration file only if installed +# on a Sun Fire 15000. +# +platform=`uname -i` +starcat="SUNW,Sun-Fire-15000" +if [ ${platform} != "${starcat}" ]; then + exit 0 +fi + issue_warning=0 # diff --git a/usr/src/pkgdefs/SUNWsckmr/prototype_com b/usr/src/pkgdefs/SUNWsckmr/prototype_com index 09f0fece1f..086c6f3d76 100644 --- a/usr/src/pkgdefs/SUNWsckmr/prototype_com +++ b/usr/src/pkgdefs/SUNWsckmr/prototype_com @@ -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,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2000, 2002 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" @@ -39,23 +38,24 @@ i pkginfo i copyright i depend -i checkinstall +i i.manifest +i r.manifest i postinstall i preremove -i i.initd + # # source locations relative to the prototype file # # SUNWsckmr # -d none etc 0755 root sys -d none etc/init.d 0755 root sys -d none etc/rcS.d 755 root sys -d none etc/rc0.d 755 root sys -d none etc/rc1.d 755 root sys -d none etc/rc2.d 0755 root sys -e initd etc/init.d/sckm 0744 root sys -l initd etc/rcS.d/K42sckm=../../etc/init.d/sckm -l initd etc/rc0.d/K42sckm=../../etc/init.d/sckm -l initd etc/rc1.d/K42sckm=../../etc/init.d/sckm -l initd etc/rc2.d/S70sckm=../../etc/init.d/sckm +d none lib 0755 root bin +d none lib/svc 0755 root bin +d none lib/svc/method 0755 root bin +f none lib/svc/method/svc-sckmd 0555 root bin +d none var 0755 root sys +d none var/svc 0755 root sys +d none var/svc/manifest 0755 root sys +d none var/svc/manifest/platform 0755 root sys +d none var/svc/manifest/platform/sun4u 0755 root sys +f manifest var/svc/manifest/platform/sun4u/sckmd.xml 0444 root sys + diff --git a/usr/src/pkgdefs/SUNWsckmu.u/depend b/usr/src/pkgdefs/SUNWsckmu.u/depend index 5a30ca402e..10cc905d0d 100644 --- a/usr/src/pkgdefs/SUNWsckmu.u/depend +++ b/usr/src/pkgdefs/SUNWsckmu.u/depend @@ -1,13 +1,12 @@ # -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # CDDL HEADER START # # The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. +# 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. @@ -50,4 +49,3 @@ P SUNWcnetr Core Solaris Network Infrastructure (Root) P SUNWcsu Core Solaris, (Usr) P SUNWcsd Core Solaris Devices P SUNWcsl Core Solaris Libraries -P SUNWsckmr Init script and rc links for Sun Fire 15000 Key Management daemon diff --git a/usr/src/pkgdefs/SUNWsckmu.u/pkginfo.tmpl b/usr/src/pkgdefs/SUNWsckmu.u/pkginfo.tmpl index d9a1bda7e6..370ec43ee6 100644 --- a/usr/src/pkgdefs/SUNWsckmu.u/pkginfo.tmpl +++ b/usr/src/pkgdefs/SUNWsckmu.u/pkginfo.tmpl @@ -32,7 +32,7 @@ # and package architecture. # PKG="SUNWsckmu" -NAME="Key Management daemon for Sun Fire 15000" +NAME="Key Management daemon" ARCH="sparc.sun4u" VERSION="ONVERS,REV=0.0.0" SUNW_PRODNAME="SunOS" @@ -40,7 +40,7 @@ SUNW_PRODVERS="RELEASE/VERSION" SUNW_PKGTYPE="kvm" MAXINST="1000" CATEGORY="system" -DESC="Key Management daemon for Sun Fire 15000" +DESC="Key Management daemon for exchanging security keys from the Service Processor" VENDOR="Sun Microsystems, Inc." HOTLINE="Please contact your local service provider" EMAIL="" diff --git a/usr/src/pkgdefs/SUNWsckmu.u/prototype_com b/usr/src/pkgdefs/SUNWsckmu.u/prototype_com index 5e9e043f99..94444cfd42 100644 --- a/usr/src/pkgdefs/SUNWsckmu.u/prototype_com +++ b/usr/src/pkgdefs/SUNWsckmu.u/prototype_com @@ -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. @@ -22,8 +21,8 @@ # #pragma ident "%Z%%M% %I% %E% SMI" # -# Copyright (c) 2000 by Sun Microsystems, Inc. -# All rights reserved. +# Copyright 2006 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 @@ -46,6 +45,6 @@ i depend # d none usr 755 root sys d none usr/platform 755 root sys -d none usr/platform/SUNW,Sun-Fire-15000 0755 root sys -d none usr/platform/SUNW,Sun-Fire-15000/lib 0755 root bin -f none usr/platform/SUNW,Sun-Fire-15000/lib/sckmd 0755 root sys +d none usr/platform/sun4u 0755 root sys +d none usr/platform/sun4u/lib 0755 root bin +f none usr/platform/sun4u/lib/sckmd 0755 root sys diff --git a/usr/src/pkgdefs/common_files/i.ttydefs b/usr/src/pkgdefs/common_files/i.ttydefs new file mode 100644 index 0000000000..6c3d316527 --- /dev/null +++ b/usr/src/pkgdefs/common_files/i.ttydefs @@ -0,0 +1,61 @@ +#!/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 +# +# +# ident "%Z%%M% %I% %E% SMI" +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. + +# +# SUNWcsr i.ttydefs script +# + +while read src dest +do + if [ "`basename $src`" = "ttydefs" ] + then + TMP=/tmp/SUNWcsr.ttydefs.$$ + + # Make sure that there is a copy of the original $dest file. + if [ ! -f $dest ]; then + cp $src $dest + fi + + # Confirm that this is an appropriate system. + PLATFORM_TOKEN=`uname -i` + case "$PLATFORM_TOKEN" + in + SUNW,OPL-Enterprise | \ + SUNW,SPARC-Enterprise | \ + FJSV,SPARC-Enterprise) + + # Add the crtscts flag for the console settings + sed -e "/^console:.*onlcr:/ { + s/onlcr:/onlcr crtscts:/ + }" $dest > ${TMP} + # Update the $dest file + cp ${TMP} $dest + ;; + esac + fi +done +exit 0 diff --git a/usr/src/pkgdefs/etc/exception_list_i386 b/usr/src/pkgdefs/etc/exception_list_i386 index 154ae5457a..532972b732 100644 --- a/usr/src/pkgdefs/etc/exception_list_i386 +++ b/usr/src/pkgdefs/etc/exception_list_i386 @@ -642,6 +642,7 @@ usr/include/librestart.h i386 usr/include/librestart_priv.h i386 usr/include/libcontract_priv.h i386 var/svc/manifest/platform/sun4u i386 +var/svc/profile/platform_SUNW,SPARC-Enterprise.xml i386 var/svc/profile/platform_SUNW,Sun-Fire.xml i386 var/svc/profile/platform_SUNW,Sun-Fire-880.xml i386 var/svc/profile/platform_SUNW,Sun-Fire-V890.xml i386 diff --git a/usr/src/psm/promif/ieee1275/sun4u/Makefile.files b/usr/src/psm/promif/ieee1275/sun4u/Makefile.files index 61182791d6..6808bc6499 100644 --- a/usr/src/psm/promif/ieee1275/sun4u/Makefile.files +++ b/usr/src/psm/promif/ieee1275/sun4u/Makefile.files @@ -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) 1992-2001 by Sun Microsystems, Inc. -# All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. # #pragma ident "%Z%%M% %I% %E% SMI" # @@ -57,4 +56,5 @@ CORE_OBJS += \ prom_starfire.o \ prom_sunfire.o \ prom_vercheck.o \ - prom_vername.o + prom_vername.o \ + prom_opl.o diff --git a/usr/src/psm/promif/ieee1275/sun4u/prom_opl.c b/usr/src/psm/promif/ieee1275/sun4u/prom_opl.c new file mode 100644 index 0000000000..62f067fcb8 --- /dev/null +++ b/usr/src/psm/promif/ieee1275/sun4u/prom_opl.c @@ -0,0 +1,137 @@ +/* + * 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 <sys/promif.h> +#include <sys/promimpl.h> + +/* + * This file implements promif routines for OPL-specific OBP client + * interfaces defined in FWARC/2005/268. + */ + +/* + * prom_opl_get_tod - this function gets time-of-day and stick value from OBP. + * Please, see "The OPL OBP functional specification" for details. + */ + +void +prom_opl_get_tod(time_t *time, int64_t *stickval) +{ + cell_t ci[5]; + + ci[0] = p1275_ptr2cell("FJSV,get-tod"); /* Service name */ + ci[1] = (cell_t)0; /* #argument cells */ + ci[2] = (cell_t)2; /* #result cells */ + ci[3] = (cell_t)0; /* The result: STICK */ + ci[4] = (cell_t)0; /* The result: time */ + + promif_preprom(); + (void) p1275_cif_handler(&ci); + promif_postprom(); + + *stickval = ci[3]; + *time = ci[4]; +} + +/* + * prom_opl_set_diff - this function updates time difference + * w.r.t. SP/OBP reference time. + * Please, see "The OPL OBP functional specification" for details. + */ + +void +prom_opl_set_diff(int64_t diff) +{ + cell_t ci[4]; + + ci[0] = p1275_ptr2cell("FJSV,set-domain-time"); /* Service name */ + ci[1] = (cell_t)1; /* #argument cells */ + ci[2] = (cell_t)0; /* #result cells */ + ci[3] = (cell_t)diff; /* Arg1: time diff */ + + promif_preprom(); + (void) p1275_cif_handler(&ci); + promif_postprom(); +} + +int +prom_attach_notice(int boardnum) +{ + int rv; + cell_t ci[5]; + + ci[0] = p1275_ptr2cell("FJSV,attach-notice"); + ci[1] = (cell_t)1; + ci[2] = (cell_t)1; + ci[3] = (cell_t)boardnum; + + promif_preprom(); + rv = p1275_cif_handler(&ci); + promif_postprom(); + + return ((rv) ? -1 : p1275_cell2int(ci[4])); +} + +int +prom_detach_notice(int boardnum) +{ + int rv; + cell_t ci[5]; + + ci[0] = p1275_ptr2cell("FJSV,detach-notice"); + ci[1] = (cell_t)1; + ci[2] = (cell_t)1; + ci[3] = (cell_t)boardnum; + + promif_preprom(); + rv = p1275_cif_handler(&ci); + promif_postprom(); + + return ((rv) ? -1 : p1275_cell2int(ci[4])); +} + +int +prom_opl_switch_console(int lsb_id) +{ + cell_t ci[5]; + int rv; + + ci[0] = p1275_ptr2cell("FJSV,switch-console"); /* name */ + ci[1] = (cell_t)1; /* #argument cells */ + ci[2] = (cell_t)1; /* #result cells */ + /* target tty-port# */ + ci[3] = p1275_int2cell(lsb_id); + + promif_preprom(); + rv = p1275_cif_handler(&ci); + promif_postprom(); + + if (rv != 0) { + return (rv); + } + return (p1275_cell2int(ci[4])); /* Res1: Catch result */ +} diff --git a/usr/src/psm/stand/boot/sparc/common/sun4dep.c b/usr/src/psm/stand/boot/sparc/common/sun4dep.c index 7a6cb4937c..e4dbcc2d7b 100644 --- a/usr/src/psm/stand/boot/sparc/common/sun4dep.c +++ b/usr/src/psm/stand/boot/sparc/common/sun4dep.c @@ -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,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -49,6 +48,7 @@ setup_aux(void) pnode_t node; /* big enough for OBP_NAME and for a reasonably sized OBP_COMPATIBLE. */ static char cpubuf[5 * OBP_MAXDRVNAME]; + char dname[OBP_MAXDRVNAME]; extern uint_t icache_flush; extern char *cpulist; @@ -61,8 +61,19 @@ setup_aux(void) nlen > sizeof (cpubuf) || prom_getprop(node, OBP_NAME, cpubuf) <= 0) prom_panic("no name in cpu node"); + /* nlen includes the terminating null character */ - if ((clen = prom_getproplen(node, OBP_COMPATIBLE)) > 0) { + + /* + * For the CMT case, need check the parent "core" + * node for the compatible property. + */ + if ((clen = prom_getproplen(node, OBP_COMPATIBLE)) > 0 || + ((node = prom_parentnode(node)) != OBP_NONODE && + node != OBP_BADNODE && + (clen = prom_getproplen(node, OBP_COMPATIBLE)) > 0 && + prom_getprop(node, OBP_DEVICETYPE, dname) > 0 && + strcmp(dname, "core") == 0)) { if ((clen + nlen) > sizeof (cpubuf)) prom_panic("cpu node \"compatible\" too long"); /* read in compatible, leaving space for ':' */ diff --git a/usr/src/uts/common/io/hotplug/pciehpc/pciehpc.c b/usr/src/uts/common/io/hotplug/pciehpc/pciehpc.c index 41435779fa..737a83ea7c 100644 --- a/usr/src/uts/common/io/hotplug/pciehpc/pciehpc.c +++ b/usr/src/uts/common/io/hotplug/pciehpc/pciehpc.c @@ -746,9 +746,14 @@ pciehpc_enable_intr(pciehpc_t *ctrl_p) reg = pciehpc_reg_get16(ctrl_p, ctrl_p->pcie_caps_reg_offset + PCIE_SLOTCTL); - /* enable all interrupts */ - pciehpc_reg_put16(ctrl_p, ctrl_p->pcie_caps_reg_offset + - PCIE_SLOTCTL, reg | SLOTCTL_SUPPORTED_INTRS_MASK); + /* enable interrupts */ + if (ctrl_p->slot.slot_state == HPC_SLOT_CONNECTED) + pciehpc_reg_put16(ctrl_p, ctrl_p->pcie_caps_reg_offset + + PCIE_SLOTCTL, reg | SLOTCTL_SUPPORTED_INTRS_MASK); + else + pciehpc_reg_put16(ctrl_p, ctrl_p->pcie_caps_reg_offset + + PCIE_SLOTCTL, reg | (SLOTCTL_SUPPORTED_INTRS_MASK & + ~PCIE_SLOTCTL_PWR_FAULT_EN)); return (DDI_SUCCESS); } @@ -1075,9 +1080,45 @@ pciehpc_slot_connect(caddr_t ops_arg, hpc_slot_t slot_hdl, control &= ~PCIE_SLOTCTL_PWR_CONTROL; pciehpc_issue_hpc_command(ctrl_p, control); - /* NOTE - any check to make sure power is really turned ON? */ + /* check power is really turned ON? */ + control = pciehpc_reg_get16(ctrl_p, + ctrl_p->pcie_caps_reg_offset + PCIE_SLOTCTL); + if (control & PCIE_SLOTCTL_PWR_CONTROL) { + PCIEHPC_DEBUG((CE_NOTE, + "slot %d fails to turn on power on connect\n", + ctrl_p->slot.slotNum)); + + goto cleanup1; + } + + /* check power-fault on the slot? */ + status = pciehpc_reg_get16(ctrl_p, + ctrl_p->pcie_caps_reg_offset + PCIE_SLOTSTS); + if (status & PCIE_SLOTSTS_PWR_FAULT_DETECTED) { + PCIEHPC_DEBUG((CE_NOTE, + "slot %d detects power fault on connect\n", + ctrl_p->slot.slotNum)); - /* NOTE - what about power-fault on the slot? */ + /* set power control to OFF */ + control = pciehpc_reg_get16(ctrl_p, + ctrl_p->pcie_caps_reg_offset + PCIE_SLOTCTL); + control |= PCIE_SLOTCTL_PWR_CONTROL; + pciehpc_issue_hpc_command(ctrl_p, control); + + /* clear the status */ + pciehpc_reg_put16(ctrl_p, + ctrl_p->pcie_caps_reg_offset + PCIE_SLOTSTS, status); + goto cleanup1; + } + + /* enable all interrupts */ + pciehpc_reg_put16(ctrl_p, + ctrl_p->pcie_caps_reg_offset + PCIE_SLOTSTS, status); + + control = pciehpc_reg_get16(ctrl_p, + ctrl_p->pcie_caps_reg_offset + PCIE_SLOTCTL); + pciehpc_reg_put16(ctrl_p, ctrl_p->pcie_caps_reg_offset + + PCIE_SLOTCTL, control | SLOTCTL_SUPPORTED_INTRS_MASK); /* 3. Set power LED to be ON */ pciehpc_set_led_state(ctrl_p, HPC_POWER_LED, HPC_LED_ON); @@ -1093,6 +1134,10 @@ pciehpc_slot_connect(caddr_t ops_arg, hpc_slot_t slot_hdl, mutex_exit(&ctrl_p->pciehpc_mutex); return (HPC_SUCCESS); +cleanup1: + /* set power led to OFF */ + pciehpc_set_led_state(ctrl_p, HPC_POWER_LED, HPC_LED_OFF); + cleanup: mutex_exit(&ctrl_p->pciehpc_mutex); return (HPC_ERR_FAILED); @@ -1177,6 +1222,13 @@ pciehpc_slot_disconnect(caddr_t ops_arg, hpc_slot_t slot_hdl, pciehpc_set_led_state(ctrl_p, HPC_POWER_LED, HPC_LED_OFF); pciehpc_set_led_state(ctrl_p, HPC_ATTN_LED, HPC_LED_OFF); + /* disable interrupt of power fault detection */ + control = pciehpc_reg_get16(ctrl_p, + ctrl_p->pcie_caps_reg_offset + PCIE_SLOTCTL); + pciehpc_reg_put16(ctrl_p, ctrl_p->pcie_caps_reg_offset + + PCIE_SLOTCTL, control | (SLOTCTL_SUPPORTED_INTRS_MASK & + ~PCIE_SLOTCTL_PWR_FAULT_EN)); + ctrl_p->slot.slot_state = HPC_SLOT_DISCONNECTED; mutex_exit(&ctrl_p->pciehpc_mutex); return (HPC_SUCCESS); diff --git a/usr/src/uts/common/os/chip.c b/usr/src/uts/common/os/chip.c index 8b0bfd765d..6a74cf4a91 100644 --- a/usr/src/uts/common/os/chip.c +++ b/usr/src/uts/common/os/chip.c @@ -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. @@ -230,11 +229,11 @@ chip_cpu_init(cpu_t *cp) * On sun4v platforms, the chip infrastructure is currently being * leveraged to implement core level load balancing. */ -#ifdef sun4v +#ifdef DO_CORELEVEL_LOADBAL cid = chip_plat_get_coreid(cp); #else cid = chip_plat_get_chipid(cp); -#endif /* sun4v */ +#endif /* DO_CORELEVEL_LOADBAL */ chp = chip_find(cid); if (chp == NULL) { diff --git a/usr/src/uts/common/os/cpu.c b/usr/src/uts/common/os/cpu.c index ea0f219b9e..cfb190b1c5 100644 --- a/usr/src/uts/common/os/cpu.c +++ b/usr/src/uts/common/os/cpu.c @@ -2593,8 +2593,13 @@ cpuset_find(cpuset_t *s) /* * Find a cpu in the cpuset */ - for (i = 0; (i < CPUSET_WORDS && cpu == (uint_t)-1); i++) + for (i = 0; i < CPUSET_WORDS; i++) { cpu = (uint_t)(lowbit(s->cpub[i]) - 1); + if (cpu != (uint_t)-1) { + cpu += i * BT_NBIPUL; + break; + } + } return (cpu); } diff --git a/usr/src/uts/common/sys/Makefile b/usr/src/uts/common/sys/Makefile index 94069abd27..5c6c23acab 100644 --- a/usr/src/uts/common/sys/Makefile +++ b/usr/src/uts/common/sys/Makefile @@ -663,7 +663,8 @@ FMFSHDRS= \ FMIOHDRS= \ ddi.h \ pci.h \ - sun4upci.h + sun4upci.h \ + opl_mc_fm.h FSHDRS= \ autofs.h \ diff --git a/usr/src/uts/common/sys/ddidmareq.h b/usr/src/uts/common/sys/ddidmareq.h index af6d7d69f1..f770413ac4 100644 --- a/usr/src/uts/common/sys/ddidmareq.h +++ b/usr/src/uts/common/sys/ddidmareq.h @@ -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,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -388,6 +387,11 @@ typedef struct ddi_dma_lim { */ #define DDI_DMA_FLAGERR 0x200 +/* + * Enable relaxed ordering + */ +#define DDI_DMA_RELAXED_ORDERING 0x400 + #define DMA_ATTR_V0 0 #define DMA_ATTR_VERSION DMA_ATTR_V0 diff --git a/usr/src/uts/common/sys/fm/io/opl_mc_fm.h b/usr/src/uts/common/sys/fm/io/opl_mc_fm.h new file mode 100644 index 0000000000..f9f8436d7d --- /dev/null +++ b/usr/src/uts/common/sys/fm/io/opl_mc_fm.h @@ -0,0 +1,69 @@ +/* + * 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_FM_IO_OPL_MC_FM_H +#define _SYS_FM_IO_OPL_MC_FM_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +/* mc-opl ereport components */ +#define MC_OPL_ERROR_CLASS "asic.mac" +#define MC_OPL_PTRL_SUBCLASS "ptrl" +#define MC_OPL_MI_SUBCLASS "mi" + +/* + * ereport definition + */ +#define MC_OPL_UE "ue" +#define MC_OPL_CE "ce" +#define MC_OPL_CMPE "cmpe" +#define MC_OPL_MUE "mue" +#define MC_OPL_SUE "sue" + +/* mc-opl payload name fields */ +#define MC_OPL_BOARD "board" +#define MC_OPL_BANK "bank" +#define MC_OPL_STATUS "status" +#define MC_OPL_ERR_ADD "err-add" +#define MC_OPL_ERR_LOG "err-log" +#define MC_OPL_ERR_SYND "syndrome" +#define MC_OPL_ERR_DIMMSLOT "dimm-slot" +#define MC_OPL_ERR_DRAM "dram-place" +#define MC_OPL_PA "pa" +#define MC_OPL_FLT_TYPE "flt-type" + +#define MC_OPL_RESOURCE "resource" + +#define MC_OPL_NO_UNUM "" + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_FM_IO_OPL_MC_FM_H */ diff --git a/usr/src/uts/common/sys/fm/io/sun4_fire.h b/usr/src/uts/common/sys/fm/io/sun4_fire.h index 708d5ba825..4a7a8fa7eb 100644 --- a/usr/src/uts/common/sys/fm/io/sun4_fire.h +++ b/usr/src/uts/common/sys/fm/io/sun4_fire.h @@ -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,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -39,6 +38,7 @@ extern "C" { */ #define PCIEX_FIRE "fire" +#define PCIEX_OBERON "oberon" /* FIRE's JBUS ereport classes */ #define FIRE_JBC_MB_PEA "jbc.mb_pea" @@ -71,6 +71,18 @@ extern "C" { #define FIRE_JBC_UNSOL_INTR "jbc.unsol_intr" #define FIRE_JBC_EBUS_TO "jbc.ebus_to" +/* OBERON's UBC ereport classes */ +#define FIRE_UBC_DMARDUEA "ubc.dmarduea" +#define FIRE_UBC_DMAWTUEA "ubc.dmawtuea" +#define FIRE_UBC_MEMRDAXA "ubc.memrdaxa" +#define FIRE_UBC_MEMWTAXA "ubc.memwtaxa" +#define FIRE_UBC_DMARDUEB "ubc.dmardueb" +#define FIRE_UBC_DMAWTUEB "ubc.dmawtueb" +#define FIRE_UBC_MEMRDAXB "ubc.memrdaxb" +#define FIRE_UBC_MEMWTAXB "ubc.memwtaxb" +#define FIRE_UBC_PIOWTUE "ubc.piowtue" +#define FIRE_UBC_PIOWBEUE "ubc.piowbeue" +#define FIRE_UBC_PIORBEUE "ubc.piorbeue" /* FIRE's DMC ereport classes */ #define FIRE_DMC_MSI_NOT_EN "dmc.msi_not_en" @@ -95,6 +107,7 @@ extern "C" { #define FIRE_DMC_TBW_ERR "dmc.tbw_err" #define FIRE_DMC_TBW_DPE "dmc.tbw_dpe" #define FIRE_DMC_TTC_CAE "dmc.ttc_cae" +#define FIRE_DMC_TTC_DUE "dmc.ttc_due" /* FIRE's PEC ereport classes */ @@ -121,7 +134,7 @@ extern "C" { #define FIRE_PEC_UC "pec.uc" #define FIRE_PEC_CTO "pec.cto" #define FIRE_PEC_MFP "pec.mfp" -#define FIRE_PEC_PP "pec.pp" +#define FIRE_PEC_PP "pec.pois" #define FIRE_PEC_FCP "pec.fcp" #define FIRE_PEC_DLP "pec.dlp" #define FIRE_PEC_TE "pec.te" @@ -131,6 +144,13 @@ extern "C" { #define FIRE_PEC_BDP "pec.bdp" #define FIRE_PEC_BTP "pec.btp" #define FIRE_PEC_RE "pec.re" +#define FIRE_PEC_IHB_UE "pec.ihb_ue" +#define FIRE_PEC_ECRC "pec.ecrc" +#define FIRE_PEC_EIUE "pec.eiue" +#define FIRE_PEC_ERBUE "pec.erbue" +#define FIRE_PEC_EHBUE "pec.ehbue" +#define FIRE_PEC_EDBUE "pec.edbue" +#define FIRE_PEC_TLUEITMO "pec.tlueitmo" /* Primary error */ #define FIRE_PRIMARY "primary" @@ -190,6 +210,17 @@ extern "C" { #define FIRE_JBC_JOTEL2 "jbc-jotel2" #define FIRE_JBC_MTEL "jbc-mtel" +/* UBC ereport payload */ +#define OBERON_UBC_ELE "ubc-ele" +#define OBERON_UBC_IE "ubc-ie" +#define OBERON_UBC_IS "ubc-is" +#define OBERON_UBC_ESS "ubc-ess" +#define OBERON_UBC_MUE "ubc-mue" +#define OBERON_UBC_UNUM "ubc-unum" +#define OBERON_UBC_DID "ubc-did" +#define OBERON_UBC_CPUV "ubc-cpuv" +#define OBERON_UBC_RESOURCE "resource" + #ifdef __cplusplus } #endif diff --git a/usr/src/uts/sfmmu/ml/sfmmu_asm.s b/usr/src/uts/sfmmu/ml/sfmmu_asm.s index 13992d870a..4ed8cd2e29 100644 --- a/usr/src/uts/sfmmu/ml/sfmmu_asm.s +++ b/usr/src/uts/sfmmu/ml/sfmmu_asm.s @@ -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,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -279,6 +278,8 @@ label: TSB_INSERT_UNLOCK_ENTRY(tsbep, tte, tagtarget, tmp1) ;\ label: +#endif /* UTSB_PHYS */ + /* * Load a 32M/256M Panther TSB entry into the TSB at TL > 0, * for ITLB synthesis. @@ -356,8 +357,6 @@ label: ;\ sllx tmp, TTE_SZ_SHFT, tmp ;\ or tte, tmp, tte -#endif /* UTSB_PHYS */ - /* * Load an entry into the TSB at TL=0. * @@ -972,10 +971,10 @@ sfmmu_kpm_unload_tsb(caddr_t addr, int vpshift) SET_SIZE(sfmmu_kpm_patch_tsbm) ENTRY_NP(sfmmu_patch_utsb) -#ifdef sun4v +#ifdef UTSB_PHYS retl nop -#else /* sun4v */ +#else /* UTSB_PHYS */ /* * We need to hot patch utsb_vabase and utsb4m_vabase */ @@ -1044,7 +1043,7 @@ sfmmu_kpm_unload_tsb(caddr_t addr, int vpshift) ret restore -#endif /* sun4v */ +#endif /* UTSB_PHYS */ SET_SIZE(sfmmu_patch_utsb) @@ -1420,9 +1419,12 @@ hblk_add_panic2: mov %o2, %g3 #ifndef sun4v GET_CPU_IMPL(%g2) - cmp %g2, CHEETAH_IMPL - bge %icc, hblk_hash_rm_1 - and %o4, %g4, %g2 + cmp %g2, CHEETAH_IMPL + bge,a,pt %icc, hblk_hash_rm_1 + and %o4, %g4, %g2 + cmp %g2, SPITFIRE_IMPL + blt %icc, hblk_hash_rm_2 /* no flushing needed for OPL */ + and %o4, %g4, %g2 stxa %g0, [%g2]ASI_DC_TAG /* flush prev pa from dcache */ add %o4, HMEBLK_NEXT, %o4 and %o4, %g4, %g2 @@ -2111,7 +2113,7 @@ label/**/4: ;\ TTE_SUSPEND_INT_SHIFT(hmentoff) ;\ btst tte, hmentoff ;\ bz,pt %xcc, foundlabel ;\ - nop ;\ + nop ;\ ;\ /* ;\ * Mapping is suspended, so goto suspend label. ;\ @@ -2176,7 +2178,15 @@ sfmmu_kprot_patch_ktsb4m_szcode: /* %g3 = second TSB entry ptr now, %g2 preserved */ #else /* sun4v */ +#ifdef UTSB_PHYS + /* g1 = first TSB entry ptr */ + GET_2ND_TSBREG(%g3) + brlz,a,pt %g3, 9f /* check for 2nd TSB */ + mov %g0, %g3 /* clear second tsbe ptr */ + GET_2ND_TSBE_PTR(%g2, %g3, %g4, %g5) + /* %g3 = second TSB entry ptr now, %g2 preserved */ +#else /* UTSB_PHYS */ brgez,pt %g1, 9f /* check for 2nd TSB */ mov %g0, %g3 /* clear second tsbe ptr */ @@ -2185,8 +2195,8 @@ sfmmu_kprot_patch_ktsb4m_szcode: /* %g3 = second TSB entry ptr now, %g7 clobbered */ mov %g1, %g7 GET_1ST_TSBE_PTR(%g7, %g1, %g5, sfmmu_uprot) - -#endif /* sun4v */ +#endif /* UTSB_PHYS */ +#endif /* sun4v */ 9: CPU_TSBMISS_AREA(%g6, %g7) HAT_PERCPU_STAT16(%g6, TSBMISS_UPROTS, %g7) @@ -2375,7 +2385,6 @@ dktsb4m_kpmcheck: .align 64 ALTENTRY(sfmmu_uitlb_fastpath) - SETUP_UTSB_ATOMIC_ASI(%g4, %g5) PROBE_1ST_ITSB(%g1, %g7, uitlb_fast_8k_probefail) /* g4 - g5 = clobbered by PROBE_1ST_ITSB */ ba,pn %xcc, sfmmu_tsb_miss_tt @@ -2395,16 +2404,13 @@ dktsb4m_kpmcheck: .align 64 ALTENTRY(sfmmu_udtlb_fastpath) - SETUP_UTSB_ATOMIC_ASI(%g4, %g6) PROBE_1ST_DTSB(%g1, %g7, udtlb_fast_8k_probefail) /* g4 - g5 = clobbered by PROBE_1ST_DTSB */ ba,pn %xcc, sfmmu_tsb_miss_tt mov %g0, %g3 -#endif /* sun4v */ - /* - * User instruction miss w/ multiple TSBs. + * User instruction miss w/ multiple TSBs (sun4v). * The first probe covers 8K, 64K, and 512K page sizes, * because 64K and 512K mappings are replicated off 8K * pointer. Second probe covers 4M page size only. @@ -2422,10 +2428,7 @@ dktsb4m_kpmcheck: .align 64 ALTENTRY(sfmmu_uitlb_slowpath) -#ifdef sun4v - SETUP_UTSB_ATOMIC_ASI(%g4, %g5) GET_1ST_TSBE_PTR(%g2, %g1, %g4, %g5) - PROBE_1ST_ITSB(%g1, %g7, uitlb_8k_probefail) /* g4 - g5 = clobbered here */ @@ -2434,17 +2437,47 @@ dktsb4m_kpmcheck: srlx %g2, TAG_VALO_SHIFT, %g7 PROBE_2ND_ITSB(%g3, %g7) /* NOT REACHED */ + #else /* sun4v */ + + /* + * User instruction miss w/ multiple TSBs (sun4u). + * The first probe covers 8K, 64K, and 512K page sizes, + * because 64K and 512K mappings are replicated off 8K + * pointer. Second probe covers 4M page size only. + * + * Just like sfmmu_udtlb_slowpath, except: + * o Uses ASI_ITLB_IN + * o checks for execute permission + * o No ISM prediction. + * + * g1 = tsb8k pointer register + * g2 = tag access register + * g3 = 2nd tsbreg if defined UTSB_PHYS, else scratch + * g4 - g6 = scratch registers + * g7 = TSB tag to match + */ + .align 64 + ALTENTRY(sfmmu_uitlb_slowpath) + +#ifdef UTSB_PHYS + /* + * g1 = 1st TSB entry pointer + * g3 = 2nd TSB base register + * Need 2nd TSB entry pointer for 2nd probe. + */ + PROBE_1ST_ITSB(%g1, %g7, uitlb_8k_probefail) + + GET_2ND_TSBE_PTR(%g2, %g3, %g4, %g5) +#else /* UTSB_PHYS */ mov %g1, %g3 /* save tsb8k reg in %g3 */ - SETUP_UTSB_ATOMIC_ASI(%g4, %g5) GET_1ST_TSBE_PTR(%g3, %g1, %g5, sfmmu_uitlb) - PROBE_1ST_ITSB(%g1, %g7, uitlb_8k_probefail) - /* g4 - g5 = clobbered here */ mov %g2, %g6 /* GET_2ND_TSBE_PTR clobbers tagacc */ mov %g3, %g7 /* copy tsb8k reg in %g7 */ GET_2ND_TSBE_PTR(%g6, %g7, %g3, %g4, %g5, sfmmu_uitlb) +#endif /* UTSB_PHYS */ /* g1 = first TSB pointer, g3 = second TSB pointer */ srlx %g2, TAG_VALO_SHIFT, %g7 PROBE_2ND_ITSB(%g3, %g7, isynth) @@ -2462,14 +2495,13 @@ dktsb4m_kpmcheck: * * g1 = tsb8k pointer register * g2 = tag access register - * g3 - g6 = scratch registers + * g3 = 2nd tsbreg if defined UTSB_PHYS, else scratch + * g4 - g6 = scratch registers * g7 = TSB tag to match */ .align 64 ALTENTRY(sfmmu_udtlb_slowpath) - SETUP_UTSB_ATOMIC_ASI(%g4, %g6) - /* * Check for ISM. If it exists, look for 4M mappings in the second TSB * first, then probe for other mappings in the first TSB if that fails. @@ -2499,8 +2531,10 @@ udtlb_miss_probefirst: brgz,pn %g6, sfmmu_tsb_miss_tt nop #else /* sun4v */ +#ifndef UTSB_PHYS mov %g1, %g4 GET_1ST_TSBE_PTR(%g4, %g1, %g5, sfmmu_udtlb) +#endif UTSB_PHYS PROBE_1ST_DTSB(%g1, %g7, udtlb_first_probefail) /* @@ -2511,7 +2545,9 @@ udtlb_miss_probefirst: */ brgz,pn %g6, sfmmu_tsb_miss_tt nop +#ifndef UTSB_PHYS ldxa [%g0]ASI_DMMU_TSB_8K, %g3 +#endif UTSB_PHYS /* fall through in 8K->4M probe order */ #endif /* sun4v */ @@ -2526,16 +2562,21 @@ udtlb_miss_probesecond: */ #ifdef sun4v /* GET_2ND_TSBE_PTR(tagacc, tsbe_ptr, tmp1, tmp2) */ - /* tagacc (%g2) not destroyed */ GET_2ND_TSBE_PTR(%g2, %g3, %g4, %g5) /* %g2 is okay, no need to reload, %g3 = second tsbe ptr */ -#else +#else /* sun4v */ +#ifdef UTSB_PHYS + GET_2ND_TSBREG(%g3) + GET_2ND_TSBE_PTR(%g2, %g3, %g4, %g5) + /* tagacc (%g2) is okay, no need to reload, %g3 = second tsbe ptr */ +#else /* UTSB_PHYS */ mov %g3, %g7 GET_2ND_TSBE_PTR(%g2, %g7, %g3, %g4, %g5, sfmmu_udtlb) /* %g2 clobbered, %g3 =second tsbe ptr */ mov MMU_TAG_ACCESS, %g2 ldxa [%g2]ASI_DMMU, %g2 -#endif +#endif /* UTSB_PHYS */ +#endif /* sun4v */ srlx %g2, TAG_VALO_SHIFT, %g7 PROBE_2ND_DTSB(%g3, %g7, udtlb_4m_probefail) @@ -2670,18 +2711,22 @@ tsb_4M: tsb_32M: #ifndef sun4v GET_CPU_IMPL(%g5) + cmp %g5, OLYMPUS_C_IMPL + be,pn %xcc, 0f + nop cmp %g5, PANTHER_IMPL bne,pt %xcc, tsb_pagefault nop #endif +0: ldn [%g6 + (TSBMISS_SCRATCH + TSB_TAGACC)], %g3 sllx %g3, TAGACC_CTX_LSHIFT, %g5 #ifdef sun4v - brz,pn %g5, 6f -#else + brz,pn %g5, 6f +#else brz,pn %g5, tsb_pagefault -#endif +#endif lduh [%g6 + TSBMISS_HATFLAGS], %g4 and %g4, HAT_32M_FLAG, %g5 brz,pn %g5, tsb_256M @@ -2813,10 +2858,10 @@ tsb_user: tsb_user8k: ldn [%g6 + TSBMISS_TSBPTR], %g1 ! g1 = first TSB ptr -#ifndef sun4v - mov ASI_N, %g7 ! user TSBs always accessed by VA +#ifndef UTSB_PHYS + mov ASI_N, %g7 ! user TSBs accessed by VA mov %g7, %asi -#endif /* sun4v */ +#endif /* UTSB_PHYS */ TSB_UPDATE_TL(%g1, %g3, %g2, %g4, %g7, %g6, 5) @@ -2843,10 +2888,10 @@ tsb_user4m: brz,pn %g1, 5f /* Check to see if we have 2nd TSB programmed */ nop -#ifndef sun4v - mov ASI_N, %g7 ! user TSBs always accessed by VA - mov %g7, %asi -#endif +#ifndef UTSB_PHYS + mov ASI_N, %g7 ! user TSBs accessed by VA + mov %g7, %asi +#endif /* UTSB_PHYS */ TSB_UPDATE_TL(%g1, %g3, %g2, %g4, %g7, %g6, 6) diff --git a/usr/src/uts/sfmmu/vm/hat_sfmmu.c b/usr/src/uts/sfmmu/vm/hat_sfmmu.c index 93bf6f4a6b..4e507ef2a3 100644 --- a/usr/src/uts/sfmmu/vm/hat_sfmmu.c +++ b/usr/src/uts/sfmmu/vm/hat_sfmmu.c @@ -1191,7 +1191,7 @@ hat_init(void) ((struct hme_blk *)hblk_reserve)->hblk_nextpa = va_to_pa((caddr_t)hblk_reserve); -#ifndef sun4v +#ifndef UTSB_PHYS /* * Reserve some kernel virtual address space for the locked TTEs * that allow us to probe the TSB from TL>0. @@ -2065,7 +2065,7 @@ sfmmu_memload_batchsmall(struct hat *hat, caddr_t vaddr, page_t **pps, * Construct a tte for a page: * * tte_valid = 1 - * tte_size2 = size & TTE_SZ2_BITS (Panther-only) + * tte_size2 = size & TTE_SZ2_BITS (Panther and Olympus-C only) * tte_size = size * tte_nfo = attr & HAT_NOFAULT * tte_ie = attr & HAT_STRUCTURE_LE @@ -12190,7 +12190,7 @@ tte_t *gorig[NCPU], *gcur[NCPU], *gnew[NCPU]; void chk_tte(tte_t *orig_old, tte_t *cur, tte_t *new, struct hme_blk *hmeblkp) { - uint_t i, j, k; + pfn_t i, j, k; int cpuid = CPU->cpu_id; gorig[cpuid] = orig_old; @@ -12208,14 +12208,12 @@ chk_tte(tte_t *orig_old, tte_t *cur, tte_t *new, struct hme_blk *hmeblkp) k = TTE_TO_TTEPFN(new); if (i != j) { /* remap error? */ - panic("chk_tte: bad pfn, 0x%x, 0x%x", - i, j); + panic("chk_tte: bad pfn, 0x%lx, 0x%lx", i, j); } if (i != k) { /* remap error? */ - panic("chk_tte: bad pfn2, 0x%x, 0x%x", - i, k); + panic("chk_tte: bad pfn2, 0x%lx, 0x%lx", i, k); } } else { if (TTE_IS_VALID(new)) { @@ -12225,8 +12223,7 @@ chk_tte(tte_t *orig_old, tte_t *cur, tte_t *new, struct hme_blk *hmeblkp) i = TTE_TO_TTEPFN(orig_old); k = TTE_TO_TTEPFN(new); if (i != k) { - panic("chk_tte: bad pfn3, 0x%x, 0x%x", - i, k); + panic("chk_tte: bad pfn3, 0x%lx, 0x%lx", i, k); } } } else { @@ -12235,8 +12232,8 @@ chk_tte(tte_t *orig_old, tte_t *cur, tte_t *new, struct hme_blk *hmeblkp) if (TTE_IS_VALID(new)) { k = TTE_TO_TTEPFN(new); if (j != k) { - panic("chk_tte: bad pfn4, 0x%x, 0x%x", - j, k); + panic("chk_tte: bad pfn4, 0x%lx, 0x%lx", + j, k); } } else { panic("chk_tte: why here?"); diff --git a/usr/src/uts/sfmmu/vm/hat_sfmmu.h b/usr/src/uts/sfmmu/vm/hat_sfmmu.h index 5a81b63090..c90663408a 100644 --- a/usr/src/uts/sfmmu/vm/hat_sfmmu.h +++ b/usr/src/uts/sfmmu/vm/hat_sfmmu.h @@ -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,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -1280,6 +1279,13 @@ extern uint_t tsb_slab_pamask; * may be up to 4M in size. For now, only hardware supported TSB sizes * are supported, though the slabs are usually 4M in size. * + * sun4u platforms that define UTSB_PHYS use physical addressing to access + * the user TSBs at TL>0. The first user TSB base is in the MMU I/D TSB Base + * registers. The second TSB base uses a dedicated scratchpad register which + * requires a definition of SCRATCHPAD_UTSBREG in mach_sfmmu.h. The layout for + * both registers is equivalent to sun4v below, except the TSB PA range is + * [46..13] for sun4u. + * * sun4v platforms * --------------- * On sun4v platforms, we use two dedicated scratchpad registers as pseudo @@ -1516,9 +1522,9 @@ extern void sfmmu_hblk_hash_add(struct hmehash_bucket *, struct hme_blk *, * functions exported to machine dependent VM code */ extern void sfmmu_patch_ktsb(void); -#ifndef sun4v +#ifndef UTSB_PHYS extern void sfmmu_patch_utsb(void); -#endif /* sun4v */ +#endif /* UTSB_PHYS */ extern pfn_t sfmmu_vatopfn(caddr_t, sfmmu_t *, tte_t *); extern void sfmmu_vatopfn_suspended(caddr_t, sfmmu_t *, tte_t *); #ifdef DEBUG diff --git a/usr/src/uts/sparc/fpu/fpu_simulator.c b/usr/src/uts/sparc/fpu/fpu_simulator.c index a29c45f0da..0705a1023b 100644 --- a/usr/src/uts/sparc/fpu/fpu_simulator.c +++ b/usr/src/uts/sparc/fpu/fpu_simulator.c @@ -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,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -107,6 +106,15 @@ struct fpuinfo_kstat fpuinfo = { { "fpu_sim_fqtoi", KSTAT_DATA_UINT64}, { "fpu_sim_fmovcc", KSTAT_DATA_UINT64}, { "fpu_sim_fmovr", KSTAT_DATA_UINT64}, + { "fpu_sim_fmadds", KSTAT_DATA_UINT64}, + { "fpu_sim_fmaddd", KSTAT_DATA_UINT64}, + { "fpu_sim_fmsubs", KSTAT_DATA_UINT64}, + { "fpu_sim_fmsubd", KSTAT_DATA_UINT64}, + { "fpu_sim_fnmadds", KSTAT_DATA_UINT64}, + { "fpu_sim_fnmaddd", KSTAT_DATA_UINT64}, + { "fpu_sim_fnmsubs", KSTAT_DATA_UINT64}, + { "fpu_sim_fnmsubd", KSTAT_DATA_UINT64}, + { "fpu_sim_invalid", KSTAT_DATA_UINT64}, }; struct visinfo_kstat visinfo = { @@ -182,241 +190,315 @@ _fp_fpu_simulator( */ pfpsd->fp_direction = GSR_IM(gsr) ? GSR_IRND(gsr) : fsr.rnd; pfpsd->fp_precision = fsr.rnp; - nfcc = nrd & 0x3; - if (inst.op3 == 0x35) { /* fpop2 */ - fsr.cexc = 0; - *pfsr = fsr; - if ((inst.opcode & 0xf) == 0) { - if ((fp_notp) && (inst.prec == 0)) - return (ftt_unimplemented); - FPUINFO_KSTAT(fpu_sim_fmovcc); - return (fmovcc(pfpsd, inst, pfsr)); /* fmovcc */ - } else if ((inst.opcode & 0x7) == 1) { - if ((fp_notp) && (inst.prec == 0)) - return (ftt_unimplemented); - FPUINFO_KSTAT(fpu_sim_fmovr); - return (fmovr(pfpsd, inst)); /* fmovr */ - } - } - /* ibit not valid for fpop1 instructions */ - if ((fp_notp) && (inst.ibit != 0)) - return (ftt_unimplemented); - if ((fp_notp) && (inst.prec == 0)) { /* fxto[sdq], fito[sdq] */ - if ((inst.opcode != flltos) && - (inst.opcode != flltod) && - (inst.opcode != flltox) && - (inst.opcode != fitos) && - (inst.opcode != fitod) && - (inst.opcode != fitox)) { - return (ftt_unimplemented); - } - } - switch (inst.opcode) { - case fmovs: /* also covers fmovd, fmovq */ - if (inst.prec < 2) { /* fmovs */ - _fp_unpack_word(pfpsd, &usr, nrs2); - _fp_pack_word(pfpsd, &usr, nrd); - FPUINFO_KSTAT(fpu_sim_fmovs); - } else { /* fmovd */ - _fp_unpack_extword(pfpsd, &lusr, nrs2); - _fp_pack_extword(pfpsd, &lusr, nrd); - if (inst.prec > 2) { /* fmovq */ - _fp_unpack_extword(pfpsd, &lusr, nrs2+2); - _fp_pack_extword(pfpsd, &lusr, nrd+2); - FPUINFO_KSTAT(fpu_sim_fmovq); - } else { - FPUINFO_KSTAT(fpu_sim_fmovd); + + if (inst.op3 == 0x37) { /* IMPDEP2B FMA-fused opcode */ + fp_fma_inst_type *fma_inst; + uint32_t nrs3; + unpacked us3; + unpacked ust; + fma_inst = (fp_fma_inst_type *) &inst; + nrs2 = fma_inst->rs2; + nrs3 = fma_inst->rs3; + switch (fma_inst->var) { + case fmadd: + _fp_unpack(pfpsd, &us1, nrs1, fma_inst->sz); + _fp_unpack(pfpsd, &us2, nrs2, fma_inst->sz); + _fp_mul(pfpsd, &us1, &us2, &ust); + if ((pfpsd->fp_current_exceptions & fsr.tem) == 0) { + _fp_unpack(pfpsd, &us3, nrs3, fma_inst->sz); + _fp_add(pfpsd, &ust, &us3, &ud); + _fp_pack(pfpsd, &ud, nrd, fma_inst->sz); } - } - break; - case fabss: /* also covers fabsd, fabsq */ - if (inst.prec < 2) { /* fabss */ - _fp_unpack_word(pfpsd, &usr, nrs2); - usr &= 0x7fffffff; - _fp_pack_word(pfpsd, &usr, nrd); - FPUINFO_KSTAT(fpu_sim_fabss); - } else { /* fabsd */ - _fp_unpack_extword(pfpsd, &lusr, nrs2); - lusr &= 0x7fffffffffffffff; - _fp_pack_extword(pfpsd, &lusr, nrd); - if (inst.prec > 2) { /* fabsq */ - _fp_unpack_extword(pfpsd, &lusr, nrs2+2); - _fp_pack_extword(pfpsd, &lusr, nrd+2); - FPUINFO_KSTAT(fpu_sim_fabsq); - } else { - FPUINFO_KSTAT(fpu_sim_fabsd); + FPUINFO_KSTAT_PREC(fma_inst->sz, fpu_sim_fmadds, + fpu_sim_fmaddd, fpu_sim_invalid); + break; + case fmsub: + _fp_unpack(pfpsd, &us1, nrs1, fma_inst->sz); + _fp_unpack(pfpsd, &us2, nrs2, fma_inst->sz); + _fp_mul(pfpsd, &us1, &us2, &ust); + if ((pfpsd->fp_current_exceptions & fsr.tem) == 0) { + _fp_unpack(pfpsd, &us3, nrs3, fma_inst->sz); + _fp_sub(pfpsd, &ust, &us3, &ud); + _fp_pack(pfpsd, &ud, nrd, fma_inst->sz); + } + FPUINFO_KSTAT_PREC(fma_inst->sz, fpu_sim_fmsubs, + fpu_sim_fmsubd, fpu_sim_invalid); + break; + case fnmadd: + _fp_unpack(pfpsd, &us1, nrs1, fma_inst->sz); + _fp_unpack(pfpsd, &us2, nrs2, fma_inst->sz); + _fp_mul(pfpsd, &us1, &us2, &ust); + if ((pfpsd->fp_current_exceptions & fsr.tem) == 0) { + if (ust.fpclass == fp_quiet || + ust.fpclass == fp_signaling) { + _fp_pack(pfpsd, &ust, nrd, fma_inst->sz); + } else { + _fp_unpack(pfpsd, &us3, nrs3, fma_inst->sz); + _fp_add(pfpsd, &ust, &us3, &ud); + ud.sign ^= 1; + _fp_pack(pfpsd, &ud, nrd, fma_inst->sz); + } + } + FPUINFO_KSTAT_PREC(fma_inst->sz, fpu_sim_fnmadds, + fpu_sim_fnmaddd, fpu_sim_invalid); + break; + case fnmsub: + _fp_unpack(pfpsd, &us1, nrs1, fma_inst->sz); + _fp_unpack(pfpsd, &us2, nrs2, fma_inst->sz); + _fp_mul(pfpsd, &us1, &us2, &ust); + if ((pfpsd->fp_current_exceptions & fsr.tem) == 0) { + if (ust.fpclass == fp_quiet || + ust.fpclass == fp_signaling) { + _fp_pack(pfpsd, &ust, nrd, fma_inst->sz); + } else { + _fp_unpack(pfpsd, &us3, nrs3, fma_inst->sz); + _fp_sub(pfpsd, &ust, &us3, &ud); + ud.sign ^= 1; + _fp_pack(pfpsd, &ud, nrd, fma_inst->sz); + } } + FPUINFO_KSTAT_PREC(fma_inst->sz, fpu_sim_fnmsubs, + fpu_sim_fnmsubd, fpu_sim_invalid); } - break; - case fnegs: /* also covers fnegd, fnegq */ - if (inst.prec < 2) { /* fnegs */ - _fp_unpack_word(pfpsd, &usr, nrs2); - usr ^= 0x80000000; - _fp_pack_word(pfpsd, &usr, nrd); - FPUINFO_KSTAT(fpu_sim_fnegs); - } else { /* fnegd */ - _fp_unpack_extword(pfpsd, &lusr, nrs2); - lusr ^= 0x8000000000000000; - _fp_pack_extword(pfpsd, &lusr, nrd); - if (inst.prec > 2) { /* fnegq */ - _fp_unpack_extword(pfpsd, &lusr, nrs2+2); - lusr ^= 0x0000000000000000; - _fp_pack_extword(pfpsd, &lusr, nrd+2); - FPUINFO_KSTAT(fpu_sim_fnegq); - } else { - FPUINFO_KSTAT(fpu_sim_fnegd); + } else { + nfcc = nrd & 0x3; + if (inst.op3 == 0x35) { /* fpop2 */ + fsr.cexc = 0; + *pfsr = fsr; + if ((inst.opcode & 0xf) == 0) { + if ((fp_notp) && (inst.prec == 0)) + return (ftt_unimplemented); + FPUINFO_KSTAT(fpu_sim_fmovcc); + return (fmovcc(pfpsd, inst, pfsr)); /* fmovcc */ + } else if ((inst.opcode & 0x7) == 1) { + if ((fp_notp) && (inst.prec == 0)) + return (ftt_unimplemented); + FPUINFO_KSTAT(fpu_sim_fmovr); + return (fmovr(pfpsd, inst)); /* fmovr */ } } - break; - case fadd: - _fp_unpack(pfpsd, &us1, nrs1, inst.prec); - _fp_unpack(pfpsd, &us2, nrs2, inst.prec); - _fp_add(pfpsd, &us1, &us2, &ud); - _fp_pack(pfpsd, &ud, nrd, inst.prec); - FPUINFO_KSTAT_PREC(inst.prec, fpu_sim_fadds, - fpu_sim_faddd, fpu_sim_faddq); - break; - case fsub: - _fp_unpack(pfpsd, &us1, nrs1, inst.prec); - _fp_unpack(pfpsd, &us2, nrs2, inst.prec); - _fp_sub(pfpsd, &us1, &us2, &ud); - _fp_pack(pfpsd, &ud, nrd, inst.prec); - FPUINFO_KSTAT_PREC(inst.prec, fpu_sim_fsubs, - fpu_sim_fsubd, fpu_sim_fsubq); - break; - case fmul: - _fp_unpack(pfpsd, &us1, nrs1, inst.prec); - _fp_unpack(pfpsd, &us2, nrs2, inst.prec); - _fp_mul(pfpsd, &us1, &us2, &ud); - _fp_pack(pfpsd, &ud, nrd, inst.prec); - FPUINFO_KSTAT_PREC(inst.prec, fpu_sim_fmuls, - fpu_sim_fmuld, fpu_sim_fmulq); - break; - case fsmuld: - if ((fp_notp) && (inst.prec != 1)) - return (ftt_unimplemented); - _fp_unpack(pfpsd, &us1, nrs1, inst.prec); - _fp_unpack(pfpsd, &us2, nrs2, inst.prec); - _fp_mul(pfpsd, &us1, &us2, &ud); - _fp_pack(pfpsd, &ud, nrd, (enum fp_op_type) ((int)inst.prec+1)); - FPUINFO_KSTAT(fpu_sim_fsmuld); - break; - case fdmulx: - if ((fp_notp) && (inst.prec != 2)) + /* ibit not valid for fpop1 instructions */ + if ((fp_notp) && (inst.ibit != 0)) return (ftt_unimplemented); - _fp_unpack(pfpsd, &us1, nrs1, inst.prec); - _fp_unpack(pfpsd, &us2, nrs2, inst.prec); - _fp_mul(pfpsd, &us1, &us2, &ud); - _fp_pack(pfpsd, &ud, nrd, (enum fp_op_type) ((int)inst.prec+1)); - FPUINFO_KSTAT(fpu_sim_fdmulx); - break; - case fdiv: - _fp_unpack(pfpsd, &us1, nrs1, inst.prec); - _fp_unpack(pfpsd, &us2, nrs2, inst.prec); - _fp_div(pfpsd, &us1, &us2, &ud); - _fp_pack(pfpsd, &ud, nrd, inst.prec); - FPUINFO_KSTAT_PREC(inst.prec, fpu_sim_fdivs, - fpu_sim_fdivd, fpu_sim_fdivq); - break; - case fcmp: - _fp_unpack(pfpsd, &us1, nrs1, inst.prec); - _fp_unpack(pfpsd, &us2, nrs2, inst.prec); - cc = _fp_compare(pfpsd, &us1, &us2, 0); - if (!(pfpsd->fp_current_exceptions & pfpsd->fp_fsrtem)) - switch (nfcc) { - case fcc_0: - fsr.fcc0 = cc; - break; - case fcc_1: - fsr.fcc1 = cc; - break; - case fcc_2: - fsr.fcc2 = cc; - break; - case fcc_3: - fsr.fcc3 = cc; - break; + if ((fp_notp) && (inst.prec == 0)) { /* fxto[sdq], fito[sdq] */ + if ((inst.opcode != flltos) && + (inst.opcode != flltod) && + (inst.opcode != flltox) && + (inst.opcode != fitos) && + (inst.opcode != fitod) && + (inst.opcode != fitox)) { + return (ftt_unimplemented); + } + } + switch (inst.opcode) { + case fmovs: /* also covers fmovd, fmovq */ + if (inst.prec < 2) { /* fmovs */ + _fp_unpack_word(pfpsd, &usr, nrs2); + _fp_pack_word(pfpsd, &usr, nrd); + FPUINFO_KSTAT(fpu_sim_fmovs); + } else { /* fmovd */ + _fp_unpack_extword(pfpsd, &lusr, nrs2); + _fp_pack_extword(pfpsd, &lusr, nrd); + if (inst.prec > 2) { /* fmovq */ + _fp_unpack_extword(pfpsd, &lusr, nrs2+2); + _fp_pack_extword(pfpsd, &lusr, nrd+2); + FPUINFO_KSTAT(fpu_sim_fmovq); + } else { + FPUINFO_KSTAT(fpu_sim_fmovd); + } } - FPUINFO_KSTAT_PREC(inst.prec, fpu_sim_fcmps, - fpu_sim_fcmpd, fpu_sim_fcmpq); - break; - case fcmpe: - _fp_unpack(pfpsd, &us1, nrs1, inst.prec); - _fp_unpack(pfpsd, &us2, nrs2, inst.prec); - cc = _fp_compare(pfpsd, &us1, &us2, 1); - if (!(pfpsd->fp_current_exceptions & pfpsd->fp_fsrtem)) - switch (nfcc) { - case fcc_0: - fsr.fcc0 = cc; - break; - case fcc_1: - fsr.fcc1 = cc; - break; - case fcc_2: - fsr.fcc2 = cc; - break; - case fcc_3: - fsr.fcc3 = cc; - break; + break; + case fabss: /* also covers fabsd, fabsq */ + if (inst.prec < 2) { /* fabss */ + _fp_unpack_word(pfpsd, &usr, nrs2); + usr &= 0x7fffffff; + _fp_pack_word(pfpsd, &usr, nrd); + FPUINFO_KSTAT(fpu_sim_fabss); + } else { /* fabsd */ + _fp_unpack_extword(pfpsd, &lusr, nrs2); + lusr &= 0x7fffffffffffffff; + _fp_pack_extword(pfpsd, &lusr, nrd); + if (inst.prec > 2) { /* fabsq */ + _fp_unpack_extword(pfpsd, &lusr, nrs2+2); + _fp_pack_extword(pfpsd, &lusr, nrd+2); + FPUINFO_KSTAT(fpu_sim_fabsq); + } else { + FPUINFO_KSTAT(fpu_sim_fabsd); + } } - FPUINFO_KSTAT_PREC(inst.prec, fpu_sim_fcmpes, - fpu_sim_fcmped, fpu_sim_fcmpeq); - break; - case fsqrt: - _fp_unpack(pfpsd, &us1, nrs2, inst.prec); - _fp_sqrt(pfpsd, &us1, &ud); - _fp_pack(pfpsd, &ud, nrd, inst.prec); - FPUINFO_KSTAT_PREC(inst.prec, fpu_sim_fsqrts, - fpu_sim_fsqrtd, fpu_sim_fsqrtq); - break; - case ftoi: - _fp_unpack(pfpsd, &us1, nrs2, inst.prec); - pfpsd->fp_direction = fp_tozero; - /* Force rounding toward zero. */ - _fp_pack(pfpsd, &us1, nrd, fp_op_int32); - FPUINFO_KSTAT_PREC(inst.prec, fpu_sim_fstoi, - fpu_sim_fdtoi, fpu_sim_fqtoi); - break; - case ftoll: - _fp_unpack(pfpsd, &us1, nrs2, inst.prec); - pfpsd->fp_direction = fp_tozero; - /* Force rounding toward zero. */ - _fp_pack(pfpsd, &us1, nrd, fp_op_int64); - FPUINFO_KSTAT_PREC(inst.prec, fpu_sim_fstox, - fpu_sim_fdtox, fpu_sim_fqtox); - break; - case flltos: - _fp_unpack(pfpsd, &us1, nrs2, fp_op_int64); - _fp_pack(pfpsd, &us1, nrd, fp_op_single); - FPUINFO_KSTAT(fpu_sim_fxtos); - break; - case flltod: - _fp_unpack(pfpsd, &us1, nrs2, fp_op_int64); - _fp_pack(pfpsd, &us1, nrd, fp_op_double); - FPUINFO_KSTAT(fpu_sim_fxtod); - break; - case flltox: - _fp_unpack(pfpsd, &us1, nrs2, fp_op_int64); - _fp_pack(pfpsd, &us1, nrd, fp_op_extended); - FPUINFO_KSTAT(fpu_sim_fxtoq); - break; - case fitos: - _fp_unpack(pfpsd, &us1, nrs2, inst.prec); - _fp_pack(pfpsd, &us1, nrd, fp_op_single); - FPUINFO_KSTAT(fpu_sim_fitos); - break; - case fitod: - _fp_unpack(pfpsd, &us1, nrs2, inst.prec); - _fp_pack(pfpsd, &us1, nrd, fp_op_double); - FPUINFO_KSTAT(fpu_sim_fitod); - break; - case fitox: - _fp_unpack(pfpsd, &us1, nrs2, inst.prec); - _fp_pack(pfpsd, &us1, nrd, fp_op_extended); - FPUINFO_KSTAT(fpu_sim_fitoq); - break; - default: - return (ftt_unimplemented); + break; + case fnegs: /* also covers fnegd, fnegq */ + if (inst.prec < 2) { /* fnegs */ + _fp_unpack_word(pfpsd, &usr, nrs2); + usr ^= 0x80000000; + _fp_pack_word(pfpsd, &usr, nrd); + FPUINFO_KSTAT(fpu_sim_fnegs); + } else { /* fnegd */ + _fp_unpack_extword(pfpsd, &lusr, nrs2); + lusr ^= 0x8000000000000000; + _fp_pack_extword(pfpsd, &lusr, nrd); + if (inst.prec > 2) { /* fnegq */ + _fp_unpack_extword(pfpsd, &lusr, nrs2+2); + lusr ^= 0x0000000000000000; + _fp_pack_extword(pfpsd, &lusr, nrd+2); + FPUINFO_KSTAT(fpu_sim_fnegq); + } else { + FPUINFO_KSTAT(fpu_sim_fnegd); + } + } + break; + case fadd: + _fp_unpack(pfpsd, &us1, nrs1, inst.prec); + _fp_unpack(pfpsd, &us2, nrs2, inst.prec); + _fp_add(pfpsd, &us1, &us2, &ud); + _fp_pack(pfpsd, &ud, nrd, inst.prec); + FPUINFO_KSTAT_PREC(inst.prec, fpu_sim_fadds, + fpu_sim_faddd, fpu_sim_faddq); + break; + case fsub: + _fp_unpack(pfpsd, &us1, nrs1, inst.prec); + _fp_unpack(pfpsd, &us2, nrs2, inst.prec); + _fp_sub(pfpsd, &us1, &us2, &ud); + _fp_pack(pfpsd, &ud, nrd, inst.prec); + FPUINFO_KSTAT_PREC(inst.prec, fpu_sim_fsubs, + fpu_sim_fsubd, fpu_sim_fsubq); + break; + case fmul: + _fp_unpack(pfpsd, &us1, nrs1, inst.prec); + _fp_unpack(pfpsd, &us2, nrs2, inst.prec); + _fp_mul(pfpsd, &us1, &us2, &ud); + _fp_pack(pfpsd, &ud, nrd, inst.prec); + FPUINFO_KSTAT_PREC(inst.prec, fpu_sim_fmuls, + fpu_sim_fmuld, fpu_sim_fmulq); + break; + case fsmuld: + if ((fp_notp) && (inst.prec != 1)) + return (ftt_unimplemented); + _fp_unpack(pfpsd, &us1, nrs1, inst.prec); + _fp_unpack(pfpsd, &us2, nrs2, inst.prec); + _fp_mul(pfpsd, &us1, &us2, &ud); + _fp_pack(pfpsd, &ud, nrd, + (enum fp_op_type) ((int)inst.prec+1)); + FPUINFO_KSTAT(fpu_sim_fsmuld); + break; + case fdmulx: + if ((fp_notp) && (inst.prec != 2)) + return (ftt_unimplemented); + _fp_unpack(pfpsd, &us1, nrs1, inst.prec); + _fp_unpack(pfpsd, &us2, nrs2, inst.prec); + _fp_mul(pfpsd, &us1, &us2, &ud); + _fp_pack(pfpsd, &ud, nrd, + (enum fp_op_type) ((int)inst.prec+1)); + FPUINFO_KSTAT(fpu_sim_fdmulx); + break; + case fdiv: + _fp_unpack(pfpsd, &us1, nrs1, inst.prec); + _fp_unpack(pfpsd, &us2, nrs2, inst.prec); + _fp_div(pfpsd, &us1, &us2, &ud); + _fp_pack(pfpsd, &ud, nrd, inst.prec); + FPUINFO_KSTAT_PREC(inst.prec, fpu_sim_fdivs, + fpu_sim_fdivd, fpu_sim_fdivq); + break; + case fcmp: + _fp_unpack(pfpsd, &us1, nrs1, inst.prec); + _fp_unpack(pfpsd, &us2, nrs2, inst.prec); + cc = _fp_compare(pfpsd, &us1, &us2, 0); + if (!(pfpsd->fp_current_exceptions & pfpsd->fp_fsrtem)) + switch (nfcc) { + case fcc_0: + fsr.fcc0 = cc; + break; + case fcc_1: + fsr.fcc1 = cc; + break; + case fcc_2: + fsr.fcc2 = cc; + break; + case fcc_3: + fsr.fcc3 = cc; + break; + } + FPUINFO_KSTAT_PREC(inst.prec, fpu_sim_fcmps, + fpu_sim_fcmpd, fpu_sim_fcmpq); + break; + case fcmpe: + _fp_unpack(pfpsd, &us1, nrs1, inst.prec); + _fp_unpack(pfpsd, &us2, nrs2, inst.prec); + cc = _fp_compare(pfpsd, &us1, &us2, 1); + if (!(pfpsd->fp_current_exceptions & pfpsd->fp_fsrtem)) + switch (nfcc) { + case fcc_0: + fsr.fcc0 = cc; + break; + case fcc_1: + fsr.fcc1 = cc; + break; + case fcc_2: + fsr.fcc2 = cc; + break; + case fcc_3: + fsr.fcc3 = cc; + break; + } + FPUINFO_KSTAT_PREC(inst.prec, fpu_sim_fcmpes, + fpu_sim_fcmped, fpu_sim_fcmpeq); + break; + case fsqrt: + _fp_unpack(pfpsd, &us1, nrs2, inst.prec); + _fp_sqrt(pfpsd, &us1, &ud); + _fp_pack(pfpsd, &ud, nrd, inst.prec); + FPUINFO_KSTAT_PREC(inst.prec, fpu_sim_fsqrts, + fpu_sim_fsqrtd, fpu_sim_fsqrtq); + break; + case ftoi: + _fp_unpack(pfpsd, &us1, nrs2, inst.prec); + pfpsd->fp_direction = fp_tozero; + /* Force rounding toward zero. */ + _fp_pack(pfpsd, &us1, nrd, fp_op_int32); + FPUINFO_KSTAT_PREC(inst.prec, fpu_sim_fstoi, + fpu_sim_fdtoi, fpu_sim_fqtoi); + break; + case ftoll: + _fp_unpack(pfpsd, &us1, nrs2, inst.prec); + pfpsd->fp_direction = fp_tozero; + /* Force rounding toward zero. */ + _fp_pack(pfpsd, &us1, nrd, fp_op_int64); + FPUINFO_KSTAT_PREC(inst.prec, fpu_sim_fstox, + fpu_sim_fdtox, fpu_sim_fqtox); + break; + case flltos: + _fp_unpack(pfpsd, &us1, nrs2, fp_op_int64); + _fp_pack(pfpsd, &us1, nrd, fp_op_single); + FPUINFO_KSTAT(fpu_sim_fxtos); + break; + case flltod: + _fp_unpack(pfpsd, &us1, nrs2, fp_op_int64); + _fp_pack(pfpsd, &us1, nrd, fp_op_double); + FPUINFO_KSTAT(fpu_sim_fxtod); + break; + case flltox: + _fp_unpack(pfpsd, &us1, nrs2, fp_op_int64); + _fp_pack(pfpsd, &us1, nrd, fp_op_extended); + FPUINFO_KSTAT(fpu_sim_fxtoq); + break; + case fitos: + _fp_unpack(pfpsd, &us1, nrs2, inst.prec); + _fp_pack(pfpsd, &us1, nrd, fp_op_single); + FPUINFO_KSTAT(fpu_sim_fitos); + break; + case fitod: + _fp_unpack(pfpsd, &us1, nrs2, inst.prec); + _fp_pack(pfpsd, &us1, nrd, fp_op_double); + FPUINFO_KSTAT(fpu_sim_fitod); + break; + case fitox: + _fp_unpack(pfpsd, &us1, nrs2, inst.prec); + _fp_pack(pfpsd, &us1, nrd, fp_op_extended); + FPUINFO_KSTAT(fpu_sim_fitoq); + break; + default: + return (ftt_unimplemented); + } } fsr.cexc = pfpsd->fp_current_exceptions; if (pfpsd->fp_current_exceptions) { /* Exception(s) occurred. */ @@ -450,6 +532,7 @@ _fp_fpu_simulator( return (ftt_none); } + /* * fpu_vis_sim simulates fpu and vis instructions; * It can work with both real and pcb image registers. @@ -495,7 +578,8 @@ fpu_vis_sim( pregs, (ulong_t *)pregs->r_sp, pfp); return (ftt); } else if ((fp.inst.hibits == 2) && - ((fp.inst.op3 == 0x34) || (fp.inst.op3 == 0x35))) { + ((fp.inst.op3 == 0x34) || (fp.inst.op3 == 0x35) || + (fp.inst.op3 == 0x37))) { ftt = _fp_fpu_simulator(pfpsd, fp.inst, pfsr, gsr); if (ftt == ftt_none || ftt == ftt_ieee) { pregs->r_pc = pregs->r_npc; @@ -573,7 +657,8 @@ fp_emulator( return (ftt); if ((fp.inst.hibits == 2) && - ((fp.inst.op3 == 0x34) || (fp.inst.op3 == 0x35))) { + ((fp.inst.op3 == 0x34) || (fp.inst.op3 == 0x35) || + (fp.inst.op3 == 0x37))) { ftt = _fp_fpu_simulator(pfpsd, fp.inst, (fsr_type *)&tfsr, gsr); /* Do not retry emulated instruction. */ pregs->r_pc = pregs->r_npc; @@ -612,7 +697,8 @@ again: if (ftt != ftt_none) return (ftt); if ((fp.inst.hibits == 2) && /* fpops */ - ((fp.inst.op3 == 0x34) || (fp.inst.op3 == 0x35))) { + ((fp.inst.op3 == 0x34) || (fp.inst.op3 == 0x35) || + (fp.inst.op3 == 0x37))) { ftt = _fp_fpu_simulator(pfpsd, fp.inst, (fsr_type *)&tfsr, gsr); /* Do not retry emulated instruction. */ pfpu->fpu_fsr = tfsr; diff --git a/usr/src/uts/sparc/os/driver_aliases b/usr/src/uts/sparc/os/driver_aliases index db3ba0352c..787f3d32f0 100644 --- a/usr/src/uts/sparc/os/driver_aliases +++ b/usr/src/uts/sparc/os/driver_aliases @@ -144,6 +144,7 @@ ibd "ib.ipib" px "SUNW,sun4v-pci" px "pci108e,80f0" px "pciex108e,80f0" +px "pciex108e,80f8" px_pci "pci1033,124" px_pci "pci1033,125" px_pci "pci8086,340" @@ -161,3 +162,9 @@ epic "SUNW,ebus-pic18lf65j10-env" i8042 "8042" mouse8042 "pnpPNP,f03" kb8042 "pnpPNP,303" +pcicmu "pci10cf,138f" +pcicmu "pci10cf,1390" +oplpanel "FJSV,panel" +oplmsu "FJSV,oplmsu" +mc-opl "FJSV,oplmc" +scfd "FJSV,scfc" diff --git a/usr/src/uts/sparc/os/name_to_major b/usr/src/uts/sparc/os/name_to_major index d38eb494a4..81708db46f 100644 --- a/usr/src/uts/sparc/os/name_to_major +++ b/usr/src/uts/sparc/os/name_to_major @@ -207,3 +207,10 @@ mouse8042 256 kssl 257 epic 258 adm1026 259 +pcicmu 260 +oplpanel 261 +oplmsu 262 +scfd 263 +mc-opl 264 +dm2s 265 +oplkmdrv 266 diff --git a/usr/src/uts/sparc/sys/Makefile b/usr/src/uts/sparc/sys/Makefile index 72c122f969..b75af1c382 100644 --- a/usr/src/uts/sparc/sys/Makefile +++ b/usr/src/uts/sparc/sys/Makefile @@ -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. @@ -68,7 +67,8 @@ FPUHDRS= \ FMCPUHDRS= \ UltraSPARC-II.h \ UltraSPARC-III.h \ - UltraSPARC-T1.h + UltraSPARC-T1.h \ + SPARC64-VI.h ROOTDIR= $(ROOT)/usr/include/sys ROOTDIRS= \ diff --git a/usr/src/uts/sparc/sys/cpu.h b/usr/src/uts/sparc/sys/cpu.h index be90896939..6f0fbc919d 100644 --- a/usr/src/uts/sparc/sys/cpu.h +++ b/usr/src/uts/sparc/sys/cpu.h @@ -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,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -69,7 +68,9 @@ extern int vac; /* * Use to insert cpu-dependent instructions into spin loops */ -#define SMT_PAUSE() /* none */ +#pragma weak cpu_smt_pause +extern void cpu_smt_pause(); +#define SMT_PAUSE() { if (&cpu_smt_pause) cpu_smt_pause(); } #endif /* defined(_KERNEL) && !defined(_ASM) */ diff --git a/usr/src/uts/sparc/sys/fm/cpu/SPARC64-VI.h b/usr/src/uts/sparc/sys/fm/cpu/SPARC64-VI.h new file mode 100644 index 0000000000..c1de31063d --- /dev/null +++ b/usr/src/uts/sparc/sys/fm/cpu/SPARC64-VI.h @@ -0,0 +1,118 @@ +/* + * 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_FM_SPARC64_VI_H +#define _SYS_FM_SPARC64_VI_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +/* ereport class subcategories for SPARC64-VI */ +#define FM_EREPORT_CPU_SPARC64_VI "SPARC64-VI" +#define FM_EREPORT_CPU_UNSUPPORTED "unsupported" + +/* + * Ereport payload definitions. + */ +#define FM_EREPORT_PAYLOAD_NAME_SFSR "sfsr" +#define FM_EREPORT_PAYLOAD_NAME_SFAR "sfar" +#define FM_EREPORT_PAYLOAD_NAME_UGESR "ugesr" +#define FM_EREPORT_PAYLOAD_NAME_PC "pc" +#define FM_EREPORT_PAYLOAD_NAME_TL "tl" +#define FM_EREPORT_PAYLOAD_NAME_TT "tt" +#define FM_EREPORT_PAYLOAD_NAME_PRIV "privileged" +#define FM_EREPORT_PAYLOAD_NAME_RESOURCE "resource" +#define FM_EREPORT_PAYLOAD_NAME_FLT_STATUS "flt-status" + +#define FM_EREPORT_PAYLOAD_FLAG_SFSR 0x00000001 +#define FM_EREPORT_PAYLOAD_FLAG_SFAR 0x00000002 +#define FM_EREPORT_PAYLOAD_FLAG_UGESR 0x00000004 +#define FM_EREPORT_PAYLOAD_FLAG_PC 0x00000008 +#define FM_EREPORT_PAYLOAD_FLAG_TL 0x00000010 +#define FM_EREPORT_PAYLOAD_FLAG_TT 0x00000020 +#define FM_EREPORT_PAYLOAD_FLAG_PRIV 0x00000040 +#define FM_EREPORT_PAYLOAD_FLAG_RESOURCE 0x00000080 +#define FM_EREPORT_PAYLOAD_FLAG_FLT_STATUS 0x00000100 + +#define FM_EREPORT_PAYLOAD_FLAGS_TRAP \ + (FM_EREPORT_PAYLOAD_FLAG_TL | \ + FM_EREPORT_PAYLOAD_FLAG_TT) + +#define FM_EREPORT_PAYLOAD_SYNC (FM_EREPORT_PAYLOAD_FLAG_SFSR | \ + FM_EREPORT_PAYLOAD_FLAG_SFAR | \ + FM_EREPORT_PAYLOAD_FLAG_PC | \ + FM_EREPORT_PAYLOAD_FLAGS_TRAP | \ + FM_EREPORT_PAYLOAD_FLAG_PRIV | \ + FM_EREPORT_PAYLOAD_FLAG_FLT_STATUS | \ + FM_EREPORT_PAYLOAD_FLAG_RESOURCE) + +#define FM_EREPORT_PAYLOAD_URGENT (FM_EREPORT_PAYLOAD_FLAG_UGESR | \ + FM_EREPORT_PAYLOAD_FLAG_PC | \ + FM_EREPORT_PAYLOAD_FLAGS_TRAP | \ + FM_EREPORT_PAYLOAD_FLAG_PRIV) + +/* + * FM_EREPORT_PAYLOAD_SYNC + */ + +#define FM_EREPORT_CPU_UE_MEM "ue-mem" +#define FM_EREPORT_CPU_UE_CHANNEL "ue-channel" +#define FM_EREPORT_CPU_UE_CPU "ue-cpu" +#define FM_EREPORT_CPU_UE_PATH "ue-path" +#define FM_EREPORT_CPU_BERR "berr" +#define FM_EREPORT_CPU_BTO "bto" +#define FM_EREPORT_CPU_MTLB "mtlb" +#define FM_EREPORT_CPU_TLBP "tlbp" +#define FM_EREPORT_CPU_INV_SFSR "inv-sfsr" + +/* + * FM_EREPORT_PAYLOAD_URGENT + */ + +#define FM_EREPORT_CPU_CRE "cre" +#define FM_EREPORT_CPU_TSBCTX "tsb-ctx" +#define FM_EREPORT_CPU_TSBP "tsbp" +#define FM_EREPORT_CPU_PSTATE "pstate" +#define FM_EREPORT_CPU_TSTATE "tstate" +#define FM_EREPORT_CPU_IUG_F "iug-f" +#define FM_EREPORT_CPU_IUG_R "iug-r" +#define FM_EREPORT_CPU_SDC "sdc" +#define FM_EREPORT_CPU_WDT "wdt" +#define FM_EREPORT_CPU_DTLB "dtlb" +#define FM_EREPORT_CPU_ITLB "itlb" +#define FM_EREPORT_CPU_CORE "core-err" +#define FM_EREPORT_CPU_DAE "dae" +#define FM_EREPORT_CPU_IAE "iae" +#define FM_EREPORT_CPU_UGE "uge" +#define FM_EREPORT_CPU_INV_URG "inv-urg" + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_FM_SPARC64_VI_H */ diff --git a/usr/src/uts/sparc/sys/fpu/fpu_simulator.h b/usr/src/uts/sparc/sys/fpu/fpu_simulator.h index 70b1bb54b7..3b46025fcf 100644 --- a/usr/src/uts/sparc/sys/fpu/fpu_simulator.h +++ b/usr/src/uts/sparc/sys/fpu/fpu_simulator.h @@ -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,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -221,6 +220,25 @@ typedef /* FPU instruction. */ uint32_t rs2 : 5; /* Second operand. */ } fp_inst_type; +enum fp_op_fma_var { /* IMPDEP2B FMA-fused instr. variations */ + fmadd = 0, + fmsub = 1, + fnmsub = 2, + fnmadd = 3 +}; + +typedef /* IMPDEP2B FPU FMA-fused instruction. */ + struct { + uint32_t hibits : 2; /* Top two bits. */ + uint32_t rd : 5; /* Destination. */ + uint32_t op3 : 6; /* Main op code. */ + uint32_t rs1 : 5; /* First operand. */ + uint32_t rs3 : 5; /* Third operand */ + uint32_t /* enum fp_op_fma_var */ var : 2; /* Instr. variation */ + uint32_t sz : 2; /* Size */ + uint32_t rs2 : 5; /* Second operand. */ +} fp_fma_inst_type; + typedef /* Integer condition code. */ struct { uint32_t : 28; /* the unused part */ @@ -305,6 +323,15 @@ struct fpuinfo_kstat { struct kstat_named fpu_sim_fqtoi; struct kstat_named fpu_sim_fmovcc; struct kstat_named fpu_sim_fmovr; + struct kstat_named fpu_sim_fmadds; + struct kstat_named fpu_sim_fmaddd; + struct kstat_named fpu_sim_fmsubs; + struct kstat_named fpu_sim_fmsubd; + struct kstat_named fpu_sim_fnmadds; + struct kstat_named fpu_sim_fnmaddd; + struct kstat_named fpu_sim_fnmsubs; + struct kstat_named fpu_sim_fnmsubd; + struct kstat_named fpu_sim_invalid; }; struct visinfo_kstat { diff --git a/usr/src/uts/sun4/io/px/px_debug.c b/usr/src/uts/sun4/io/px/px_debug.c index af16f7b301..10eefafb16 100644 --- a/usr/src/uts/sun4/io/px/px_debug.c +++ b/usr/src/uts/sun4/io/px/px_debug.c @@ -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,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -89,7 +88,7 @@ static char *px_debug_sym [] = { /* same sequence as px_debug_bit */ /* 36 */ "ilu", /* 37 */ "tlu", /* 38 */ "lpu", - /* 39 */ NULL, + /* 39 */ "mmu", /* 40 */ "open", /* 41 */ "close", diff --git a/usr/src/uts/sun4/io/px/px_dma.c b/usr/src/uts/sun4/io/px/px_dma.c index 6451a9b32c..3a1b8569b7 100644 --- a/usr/src/uts/sun4/io/px/px_dma.c +++ b/usr/src/uts/sun4/io/px/px_dma.c @@ -286,7 +286,8 @@ px_dma_attr2hdl(px_t *px_p, ddi_dma_impl_t *mp) align = 1; /* align on 1 page boundary */ /* do a range check and get the limits */ - ret = px_lib_dma_bypass_rngchk(attrp, &syslo, &syshi); + ret = px_lib_dma_bypass_rngchk(px_p->px_dip, attrp, + &syslo, &syshi); if (ret != DDI_SUCCESS) return (ret); } else { /* MMU_XLATE or PEER_TO_PEER */ @@ -674,7 +675,8 @@ px_dvma_map_fast(px_mmu_t *mmu_p, ddi_dma_impl_t *mp) { uint_t clustsz = px_dvma_page_cache_clustsz; uint_t entries = px_dvma_page_cache_entries; - io_attributes_t attr = PX_GET_TTE_ATTR(mp->dmai_rflags); + io_attributes_t attr = PX_GET_TTE_ATTR(mp->dmai_rflags, + mp->dmai_attr.dma_attr_flags); int i = mmu_p->mmu_dvma_addr_scan_start; uint8_t *lock_addr = mmu_p->mmu_dvma_cache_locks + i; px_dvma_addr_t dvma_pg; @@ -750,7 +752,8 @@ px_dvma_map(ddi_dma_impl_t *mp, ddi_dma_req_t *dmareq, px_mmu_t *mmu_p) uint_t npages = PX_DMA_WINNPGS(mp); px_dvma_addr_t dvma_pg, dvma_pg_index; void *dvma_addr; - uint64_t tte = PX_GET_TTE_ATTR(mp->dmai_rflags); + uint64_t tte = PX_GET_TTE_ATTR(mp->dmai_rflags, + mp->dmai_attr.dma_attr_flags); int sleep = dmareq->dmar_fp == DDI_DMA_SLEEP ? VM_SLEEP : VM_NOSLEEP; dev_info_t *dip = mp->dmai_rdip; int ret = DDI_SUCCESS; @@ -1031,7 +1034,8 @@ px_dma_newwin(dev_info_t *dip, ddi_dma_req_t *dmareq, ddi_dma_impl_t *mp, size_t sz = cookie_no * sizeof (ddi_dma_cookie_t); px_dma_win_t *win_p = kmem_zalloc(sizeof (px_dma_win_t) + sz, waitfp == DDI_DMA_SLEEP ? KM_SLEEP : KM_NOSLEEP); - io_attributes_t attr = PX_GET_TTE_ATTR(mp->dmai_rflags); + io_attributes_t attr = PX_GET_TTE_ATTR(mp->dmai_rflags, + mp->dmai_attr.dma_attr_flags); if (!win_p) goto noresource; @@ -1193,7 +1197,8 @@ px_dma_physwin(px_t *px_p, ddi_dma_req_t *dmareq, ddi_dma_impl_t *mp) uint64_t count_max, bypass_addr = 0; px_dma_win_t **win_pp = (px_dma_win_t **)&mp->dmai_winlst; ddi_dma_cookie_t *cookie0_p; - io_attributes_t attr = PX_GET_TTE_ATTR(mp->dmai_rflags); + io_attributes_t attr = PX_GET_TTE_ATTR(mp->dmai_rflags, + mp->dmai_attr.dma_attr_flags); dev_info_t *dip = px_p->px_dip; ASSERT(PX_DMA_ISPTP(mp) || PX_DMA_ISBYPASS(mp)); diff --git a/usr/src/uts/sun4/io/px/px_dma.h b/usr/src/uts/sun4/io/px/px_dma.h index ae4ed5b6ab..0bd23f9eb2 100644 --- a/usr/src/uts/sun4/io/px/px_dma.h +++ b/usr/src/uts/sun4/io/px/px_dma.h @@ -233,9 +233,9 @@ extern int px_dma_ctl(dev_info_t *dip, dev_info_t *rdip, #define PX_GET_MP_TTE(tte) \ (((uint64_t)(uintptr_t)(tte) >> 5) << (32 + 5) | \ - ((uint32_t)(uintptr_t)(tte)) & 0x12) + ((uint32_t)(uintptr_t)(tte)) & 0x16) #define PX_SAVE_MP_TTE(mp, tte) \ - (mp)->dmai_tte = (caddr_t)((uintptr_t)HI32(tte) | ((tte) & 0x12)) + (mp)->dmai_tte = (caddr_t)((uintptr_t)HI32(tte) | ((tte) & 0x16)) #define PX_GET_MP_PFN1(mp, page_no) \ (((px_iopfn_t *)(mp)->dmai_pfnlst)[page_no]) diff --git a/usr/src/uts/sun4/io/px/px_fdvma.c b/usr/src/uts/sun4/io/px/px_fdvma.c index be377cb638..24b2a57067 100644 --- a/usr/src/uts/sun4/io/px/px_fdvma.c +++ b/usr/src/uts/sun4/io/px/px_fdvma.c @@ -87,7 +87,7 @@ px_fdvma_load(ddi_dma_handle_t h, caddr_t a, uint_t len, uint_t index, DBG(DBG_FAST_DVMA | DBG_CONT, dip, "cookie: %x+%x\n", cp->dmac_address, cp->dmac_size); - attr = PX_GET_TTE_ATTR(mp->dmai_rflags); + attr = PX_GET_TTE_ATTR(mp->dmai_rflags, mp->dmai_attr.dma_attr_flags); if (px_lib_iommu_map(dip, PCI_TSBID(0, pg_index), npages, attr, (void *)a, 0, MMU_MAP_BUF) != DDI_SUCCESS) { diff --git a/usr/src/uts/sun4/io/px/px_ib.c b/usr/src/uts/sun4/io/px/px_ib.c index ee3a78712e..782129718e 100644 --- a/usr/src/uts/sun4/io/px/px_ib.c +++ b/usr/src/uts/sun4/io/px/px_ib.c @@ -38,6 +38,7 @@ #include <sys/machsystm.h> /* intr_dist_add */ #include <sys/ddi_impldefs.h> #include <sys/cpuvar.h> +#include <sys/time.h> #include "px_obj.h" /*LINTLIBRARY*/ @@ -49,6 +50,8 @@ static uint_t px_ib_intr_reset(void *arg); static void px_fill_in_intr_devs(pcitool_intr_dev_t *dev, char *driver_name, char *path_name, int instance); +extern uint64_t xc_tick_jump_limit; + int px_ib_attach(px_t *px_p) { @@ -172,7 +175,8 @@ px_ib_intr_dist_en(dev_info_t *dip, cpuid_t cpu_id, devino_t ino, uint32_t old_cpu_id; sysino_t sysino; intr_valid_state_t enabled = 0; - hrtime_t start_time; + hrtime_t start_time, prev, curr, interval, jump; + hrtime_t intr_timeout; intr_state_t intr_state; int e = DDI_SUCCESS; @@ -208,11 +212,27 @@ px_ib_intr_dist_en(dev_info_t *dip, cpuid_t cpu_id, devino_t ino, /* Busy wait on pending interrupts */ PX_INTR_DISABLE(dip, sysino); - for (start_time = gethrtime(); !panicstr && + intr_timeout = px_intrpend_timeout; + jump = TICK_TO_NSEC(xc_tick_jump_limit); + + for (curr = start_time = gethrtime(); !panicstr && ((e = px_lib_intr_getstate(dip, sysino, &intr_state)) == DDI_SUCCESS) && (intr_state == INTR_DELIVERED_STATE); /* */) { - if (gethrtime() - start_time > px_intrpend_timeout) { + /* + * If we have a really large jump in hrtime, it is most + * probably because we entered the debugger (or OBP, + * in general). So, we adjust the timeout accordingly + * to prevent declaring an interrupt timeout. The + * master-interrupt mechanism in OBP should deliver + * the interrupts properly. + */ + prev = curr; + curr = gethrtime(); + interval = curr - prev; + if (interval > jump) + intr_timeout += interval; + if (curr - start_time > intr_timeout) { cmn_err(CE_WARN, "%s%d: px_ib_intr_dist_en: sysino 0x%lx(ino 0x%x) " "from cpu id 0x%x to 0x%x timeout", diff --git a/usr/src/uts/sun4/io/px/px_ioapi.h b/usr/src/uts/sun4/io/px/px_ioapi.h index 79b7cffe94..e8ad722fa8 100644 --- a/usr/src/uts/sun4/io/px/px_ioapi.h +++ b/usr/src/uts/sun4/io/px/px_ioapi.h @@ -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,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -103,13 +102,14 @@ typedef enum intr_valid_state { * * PCI_MAP_ATTR_READ 0x01 - xfr direction is from memory * PCI_MAP_ATTR_WRITE 0x02 - xfr direction is to memory + * PCI_MAP_ATTR_RO 0x04 - enable relaxed ordering * - * Bits 63:2 are unused and must be set to zero for this + * Bits 63:3 are unused and must be set to zero for this * version of the specification. * * Note: For compatibility with future versions of this - * specification, the caller must set 63:2 to zero. - * The implementation shall ignore bits 63:2 + * specification, the caller must set 63:3 to zero. + * The implementation shall ignore bits 63:3 * * r_addr - 64-bit Real Address. * @@ -196,7 +196,8 @@ typedef uint64_t pci_device_t; typedef enum io_attributes { PCI_MAP_ATTR_READ = (uint32_t)0x01, - PCI_MAP_ATTR_WRITE = (uint32_t)0x02 + PCI_MAP_ATTR_WRITE = (uint32_t)0x02, + PCI_MAP_ATTR_RO = (uint32_t)0x04 } io_attributes_t; typedef enum io_sync_direction { diff --git a/usr/src/uts/sun4/io/px/px_lib.h b/usr/src/uts/sun4/io/px/px_lib.h index 02553a3b37..07bd06e2a3 100644 --- a/usr/src/uts/sun4/io/px/px_lib.h +++ b/usr/src/uts/sun4/io/px/px_lib.h @@ -89,8 +89,8 @@ extern int px_lib_iommu_map(dev_info_t *dip, tsbid_t tsbid, pages_t pages, extern int px_lib_iommu_demap(dev_info_t *dip, tsbid_t tsbid, pages_t pages); extern int px_lib_iommu_getmap(dev_info_t *dip, tsbid_t tsbid, io_attributes_t *attr_p, r_addr_t *r_addr_p); -extern int px_lib_dma_bypass_rngchk(ddi_dma_attr_t *attr_p, uint64_t *lo_p, - uint64_t *hi_p); +extern int px_lib_dma_bypass_rngchk(dev_info_t *dip, ddi_dma_attr_t *attr_p, + uint64_t *lo_p, uint64_t *hi_p); extern int px_lib_iommu_getbypass(dev_info_t *dip, r_addr_t ra, io_attributes_t attr, io_addr_t *io_addr_p); extern int px_lib_dma_sync(dev_info_t *dip, dev_info_t *rdip, diff --git a/usr/src/uts/sun4/io/px/px_mmu.h b/usr/src/uts/sun4/io/px/px_mmu.h index c861d3ba67..660985a737 100644 --- a/usr/src/uts/sun4/io/px/px_mmu.h +++ b/usr/src/uts/sun4/io/px/px_mmu.h @@ -43,9 +43,10 @@ typedef uint64_t px_window_t; /* * boiler plate for tte (everything except the pfn) */ -#define PX_GET_TTE_ATTR(flags)\ +#define PX_GET_TTE_ATTR(flags, attr)\ (((flags & DDI_DMA_READ) ? PCI_MAP_ATTR_WRITE : 0) | \ - ((flags & DDI_DMA_WRITE) ? PCI_MAP_ATTR_READ : 0)) + ((flags & DDI_DMA_WRITE) ? PCI_MAP_ATTR_READ : 0) | \ + ((attr & DDI_DMA_RELAXED_ORDERING) ? PCI_MAP_ATTR_RO : 0)) /* * mmu block soft state structure: diff --git a/usr/src/uts/sun4/io/px/px_space.c b/usr/src/uts/sun4/io/px/px_space.c index 85fb3f120e..ec5b819edf 100644 --- a/usr/src/uts/sun4/io/px/px_space.c +++ b/usr/src/uts/sun4/io/px/px_space.c @@ -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,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -146,72 +145,6 @@ uint_t px_preserve_mmu_tsb = 1; */ uintptr_t px_kmem_clid = 0; -uint64_t px_tlu_ue_intr_mask = PX_ERR_EN_ALL; -uint64_t px_tlu_ue_log_mask = PX_ERR_EN_ALL; -uint64_t px_tlu_ue_count_mask = PX_ERR_EN_ALL; - -uint64_t px_tlu_ce_intr_mask = PX_ERR_MASK_NONE; -uint64_t px_tlu_ce_log_mask = PX_ERR_MASK_NONE; -uint64_t px_tlu_ce_count_mask = PX_ERR_MASK_NONE; - -/* - * Do not enable Link Interrupts - */ -uint64_t px_tlu_oe_intr_mask = PX_ERR_EN_ALL & ~0x80000000800; -uint64_t px_tlu_oe_log_mask = PX_ERR_EN_ALL & ~0x80000000800; -uint64_t px_tlu_oe_count_mask = PX_ERR_EN_ALL; - -uint64_t px_mmu_intr_mask = PX_ERR_EN_ALL; -uint64_t px_mmu_log_mask = PX_ERR_EN_ALL; -uint64_t px_mmu_count_mask = PX_ERR_EN_ALL; - -uint64_t px_imu_intr_mask = PX_ERR_EN_ALL; -uint64_t px_imu_log_mask = PX_ERR_EN_ALL; -uint64_t px_imu_count_mask = PX_ERR_EN_ALL; - -/* - * (1ull << ILU_INTERRUPT_ENABLE_IHB_PE_S) | - * (1ull << ILU_INTERRUPT_ENABLE_IHB_PE_P); - */ -uint64_t px_ilu_intr_mask = (((uint64_t)0x10 << 32) | 0x10); -uint64_t px_ilu_log_mask = (((uint64_t)0x10 << 32) | 0x10); -uint64_t px_ilu_count_mask = PX_ERR_EN_ALL; - -uint64_t px_cb_intr_mask = PX_ERR_EN_ALL; -uint64_t px_cb_log_mask = PX_ERR_EN_ALL; -uint64_t px_cb_count_mask = PX_ERR_EN_ALL; - -/* - * LPU Intr Registers are reverse encoding from the registers above. - * 1 = disable - * 0 = enable - * - * Log and Count are however still the same. - */ -uint64_t px_lpul_intr_mask = LPU_INTR_DISABLE; -uint64_t px_lpul_log_mask = PX_ERR_EN_ALL; -uint64_t px_lpul_count_mask = PX_ERR_EN_ALL; - -uint64_t px_lpup_intr_mask = LPU_INTR_DISABLE; -uint64_t px_lpup_log_mask = PX_ERR_EN_ALL; -uint64_t px_lpup_count_mask = PX_ERR_EN_ALL; - -uint64_t px_lpur_intr_mask = LPU_INTR_DISABLE; -uint64_t px_lpur_log_mask = PX_ERR_EN_ALL; -uint64_t px_lpur_count_mask = PX_ERR_EN_ALL; - -uint64_t px_lpux_intr_mask = LPU_INTR_DISABLE; -uint64_t px_lpux_log_mask = PX_ERR_EN_ALL; -uint64_t px_lpux_count_mask = PX_ERR_EN_ALL; - -uint64_t px_lpus_intr_mask = LPU_INTR_DISABLE; -uint64_t px_lpus_log_mask = PX_ERR_EN_ALL; -uint64_t px_lpus_count_mask = PX_ERR_EN_ALL; - -uint64_t px_lpug_intr_mask = LPU_INTR_DISABLE; -uint64_t px_lpug_log_mask = PX_ERR_EN_ALL; -uint64_t px_lpug_count_mask = PX_ERR_EN_ALL; - /* timeout in micro seconds for receiving PME_To_ACK */ uint64_t px_pme_to_ack_timeout = PX_PME_TO_ACK_TIMEOUT; @@ -232,7 +165,8 @@ uint32_t px_fabric_die_rc_ue = PCIE_AER_UCE_UR | PCIE_AER_UCE_TO | PCIE_AER_UCE_RO | PCIE_AER_UCE_FCP | - PCIE_AER_UCE_DLP; + PCIE_AER_UCE_DLP | + PCIE_AER_UCE_ECRC; /* Fire PCIe Error that should cause panics even under protected access */ uint32_t px_fabric_die_rc_ce_gos = 0; diff --git a/usr/src/uts/sun4/io/px/px_space.h b/usr/src/uts/sun4/io/px/px_space.h index dc75020673..7ca21d0641 100644 --- a/usr/src/uts/sun4/io/px/px_space.h +++ b/usr/src/uts/sun4/io/px/px_space.h @@ -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,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -91,64 +90,6 @@ extern uint_t px_iommu_ctx_lock_failure; extern uint_t px_preserve_iommu_tsb; extern uintptr_t px_kmem_clid; -#define PX_ERR_EN_ALL -1ull -#define PX_ERR_MASK_NONE 0ull - -extern uint64_t px_tlu_ue_intr_mask; -extern uint64_t px_tlu_ue_log_mask; -extern uint64_t px_tlu_ue_count_mask; - -extern uint64_t px_tlu_ce_intr_mask; -extern uint64_t px_tlu_ce_log_mask; -extern uint64_t px_tlu_ce_count_mask; - -extern uint64_t px_tlu_oe_intr_mask; -extern uint64_t px_tlu_oe_log_mask; -extern uint64_t px_tlu_oe_count_mask; - -extern uint64_t px_mmu_intr_mask; -extern uint64_t px_mmu_log_mask; -extern uint64_t px_mmu_count_mask; - -extern uint64_t px_imu_intr_mask; -extern uint64_t px_imu_log_mask; -extern uint64_t px_imu_count_mask; - -#define LPU_INTR_ENABLE 0ull -#define LPU_INTR_DISABLE -1ull - -extern uint64_t px_ilu_intr_mask; -extern uint64_t px_ilu_log_mask; -extern uint64_t px_ilu_count_mask; - -extern uint64_t px_cb_intr_mask; -extern uint64_t px_cb_log_mask; -extern uint64_t px_cb_count_mask; - -extern uint64_t px_lpul_intr_mask; -extern uint64_t px_lpul_log_mask; -extern uint64_t px_lpul_count_mask; - -extern uint64_t px_lpup_intr_mask; -extern uint64_t px_lpup_log_mask; -extern uint64_t px_lpup_count_mask; - -extern uint64_t px_lpur_intr_mask; -extern uint64_t px_lpur_log_mask; -extern uint64_t px_lpur_count_mask; - -extern uint64_t px_lpux_intr_mask; -extern uint64_t px_lpux_log_mask; -extern uint64_t px_lpux_count_mask; - -extern uint64_t px_lpus_intr_mask; -extern uint64_t px_lpus_log_mask; -extern uint64_t px_lpus_count_mask; - -extern uint64_t px_lpug_intr_mask; -extern uint64_t px_lpug_log_mask; -extern uint64_t px_lpug_count_mask; - /* timeout length in micro seconds */ #define PX_MSEC_TO_USEC 1000 #define PX_PME_TO_ACK_TIMEOUT (1000 * PX_MSEC_TO_USEC) diff --git a/usr/src/uts/sun4/io/px/px_tools.c b/usr/src/uts/sun4/io/px/px_tools.c index 5033485058..a10978506f 100644 --- a/usr/src/uts/sun4/io/px/px_tools.c +++ b/usr/src/uts/sun4/io/px/px_tools.c @@ -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,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -361,6 +360,7 @@ pxtool_get_phys_addr(px_t *px_p, int space, uint64_t offset) int rval; dev_info_t *dip = px_p->px_dip; uint32_t base_offset = 0; + extern uint64_t px_get_range_prop(px_t *, px_ranges_t *, int); /* * Assume that requested entity is small enough to be on the same page. @@ -385,9 +385,7 @@ pxtool_get_phys_addr(px_t *px_p, int space, uint64_t offset) if (rval != DDI_SUCCESS) return (NULL); else { - range_base = - (((uint64_t)(rp->parent_high & 0x7ff)) << 32) + - rp->parent_low; + range_base = px_get_range_prop(px_p, rp, 0); DBG(DBG_TOOLS, dip, "range base:0x%" PRIx64 "\n", range_base); return (base_offset + range_base); } diff --git a/usr/src/uts/sun4/io/px/px_var.h b/usr/src/uts/sun4/io/px/px_var.h index 4418b71d3a..ffd593a444 100644 --- a/usr/src/uts/sun4/io/px/px_var.h +++ b/usr/src/uts/sun4/io/px/px_var.h @@ -83,7 +83,7 @@ typedef enum { PX_SUSPENDED } px_state_t; -enum { PX_INTR_XBC, PX_INTR_PEC }; +enum { PX_INTR_XBC, PX_INTR_PEC, PX_INTR_HOTPLUG }; #define PX_ATTACH_RETCODE(obj, op, err) \ ((err) ? (obj) << 8 | (op) << 4 | (err) & 0xf : DDI_SUCCESS) diff --git a/usr/src/uts/sun4/io/trapstat.c b/usr/src/uts/sun4/io/trapstat.c index 65a97fbb91..bdaac735fe 100644 --- a/usr/src/uts/sun4/io/trapstat.c +++ b/usr/src/uts/sun4/io/trapstat.c @@ -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,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -46,6 +45,9 @@ #ifdef sun4v #include <sys/hypervisor_api.h> #endif +#ifndef sun4v +#include <sys/chip.h> +#endif /* BEGIN CSTYLED */ /* @@ -1399,6 +1401,14 @@ trapstat_make_traptab(tstat_percpu_t *tcpu) #undef TSTAT_ENABLED_BA #undef TSTAT_DISABLED_BA +#ifndef sun4v +/* + * See Section A.6 in SPARC v9 Manual. + * max branch = 4*((2^21)-1) = 8388604 + */ +#define MAX_BICC_BRANCH_DISPLACEMENT (4 * ((1 << 21) - 1)) +#endif + static void trapstat_setup(processorid_t cpu) { @@ -1407,6 +1417,9 @@ trapstat_setup(processorid_t cpu) int i; caddr_t va; pfn_t *pfn; + cpu_t *cp; + uint_t strand_idx; + size_t tstat_offset; #endif ASSERT(tcpu->tcpu_pfn == NULL); @@ -1422,7 +1435,29 @@ trapstat_setup(processorid_t cpu) * align our instruction base address appropriately. */ #ifndef sun4v - tcpu->tcpu_ibase = (caddr_t)((KERNELBASE - tstat_total_size) + tstat_offset = tstat_total_size; + + cp = cpu_get(cpu); + ASSERT(cp != NULL); + if ((strand_idx = cpu ^ chip_plat_get_coreid(cp)) != 0) { + /* + * On sun4u platforms with multiple CPUs sharing the MMU + * (Olympus-C has 2 strands per core), each CPU uses a + * disjoint trap table. The indexing is based on the + * strand id, which is obtained by XOR'ing the cpuid with + * the coreid. + */ + tstat_offset += tstat_total_size * strand_idx; + + /* + * Offset must be less than the maximum PC-relative branch + * displacement for Bicc variants. See the Implementation + * Details comment. + */ + ASSERT(tstat_offset <= MAX_BICC_BRANCH_DISPLACEMENT); + } + + tcpu->tcpu_ibase = (caddr_t)((KERNELBASE - tstat_offset) & TSTAT_TBA_MASK); tcpu->tcpu_dbase = tcpu->tcpu_ibase + TSTAT_INSTR_SIZE; tcpu->tcpu_vabase = tcpu->tcpu_ibase; diff --git a/usr/src/uts/sun4/ml/interrupt.s b/usr/src/uts/sun4/ml/interrupt.s index 3a316eb8cc..e9f4863836 100644 --- a/usr/src/uts/sun4/ml/interrupt.s +++ b/usr/src/uts/sun4/ml/interrupt.s @@ -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,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -822,6 +821,7 @@ intr_thread(struct regs *regs, uint_t inumber, uint_t pil) ! Switch back to the interrupted thread and return ! stn %o4, [%o2 + CPU_THREAD] + membar #StoreLoad ! sync with mutex_exit() mov %o4, THREAD_REG ! If we pinned an interrupt thread, store its starting timestamp. diff --git a/usr/src/uts/sun4/os/startup.c b/usr/src/uts/sun4/os/startup.c index 2051840ae2..dd8b58faee 100644 --- a/usr/src/uts/sun4/os/startup.c +++ b/usr/src/uts/sun4/os/startup.c @@ -532,7 +532,7 @@ extern caddr_t ecache_init_scrub_flush_area(caddr_t alloc_base); extern uint64_t ecache_flush_address(void); #pragma weak load_platform_modules -#pragma weak starcat_startup_memlist +#pragma weak plat_startup_memlist #pragma weak ecache_init_scrub_flush_area #pragma weak ecache_flush_address @@ -963,12 +963,12 @@ startup_memlist(void) PRM_DEBUG(alloc_base); /* - * Starcat needs its special structures assigned in 32-bit virtual - * address space because its probing routines execute FCode, and FCode - * can't handle 64-bit virtual addresses... + * Platforms like Starcat and OPL need special structures assigned in + * 32-bit virtual address space because their probing routines execute + * FCode, and FCode can't handle 64-bit virtual addresses... */ - if (&starcat_startup_memlist) { - alloc_base = starcat_startup_memlist(alloc_base); + if (&plat_startup_memlist) { + alloc_base = plat_startup_memlist(alloc_base); alloc_base = (caddr_t)roundup((uintptr_t)alloc_base, ecache_alignsize); PRM_DEBUG(alloc_base); diff --git a/usr/src/uts/sun4/sys/platform_module.h b/usr/src/uts/sun4/sys/platform_module.h index f0802dc623..8f96b014c7 100644 --- a/usr/src/uts/sun4/sys/platform_module.h +++ b/usr/src/uts/sun4/sys/platform_module.h @@ -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,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -108,7 +107,7 @@ extern int plat_ecc_capability_sc_get(int type); extern int plat_blacklist(int cmd, const char *scheme, nvlist_t *fmri, const char *class); -extern caddr_t starcat_startup_memlist(caddr_t alloc_base); +extern caddr_t plat_startup_memlist(caddr_t alloc_base); extern int starcat_dr_name(char *name); #pragma weak plat_setprop_enter diff --git a/usr/src/uts/sun4u/Makefile.files b/usr/src/uts/sun4u/Makefile.files index c6a8ddc3d1..cc6825033b 100644 --- a/usr/src/uts/sun4u/Makefile.files +++ b/usr/src/uts/sun4u/Makefile.files @@ -102,6 +102,7 @@ GRBEEP_OBJS += grbeep.o ADM1031_OBJS += adm1031.o ICS951601_OBJS += ics951601.o PPM_OBJS += ppm_subr.o ppm.o +OPLCFG_OBJS += opl_cfg.o PCF8584_OBJS += pcf8584.o PCA9556_OBJS += pca9556.o ADM1026_OBJS += adm1026.o @@ -182,6 +183,7 @@ TODBLADE_OBJS += todblade.o TODM5819_OBJS += todm5819.o TODBQ4802_OBJS += todbq4802.o TODSG_OBJS += todsg.o +TODOPL_OBJS = todopl.o # # Misc modules @@ -198,6 +200,7 @@ SBD_OBJS += sbd.o sbd_cpu.o sbd_mem.o sbd_io.o # Performance Counter BackEnd (PCBE) Modules # US_PCBE_OBJS = us234_pcbe.o +OPL_PCBE_OBJS = opl_pcbe.o # # cpu modules @@ -209,6 +212,8 @@ US3_CMN_OBJS = us3_common.o us3_common_mmu.o us3_common_asm.o us3_kdi.o cheetah_ CHEETAH_OBJS = $(US3_CMN_OBJS) us3_cheetah.o us3_cheetah_asm.o CHEETAHPLUS_OBJS= $(US3_CMN_OBJS) us3_cheetahplus.o us3_cheetahplus_asm.o JALAPENO_OBJS = $(US3_CMN_OBJS) us3_jalapeno.o us3_jalapeno_asm.o +OLYMPUS_OBJS = opl_olympus.o opl_olympus_asm.o opl_olympus_copy.o \ + opl_kdi.o common_asm.o # # platform module diff --git a/usr/src/uts/sun4u/Makefile.sun4u.shared b/usr/src/uts/sun4u/Makefile.sun4u.shared index 61855f6096..3f91e661e5 100644 --- a/usr/src/uts/sun4u/Makefile.sun4u.shared +++ b/usr/src/uts/sun4u/Makefile.sun4u.shared @@ -179,6 +179,7 @@ IMPLEMENTATIONS += chicago .WAIT IMPLEMENTATIONS += sunfire .WAIT IMPLEMENTATIONS += lw8 .WAIT IMPLEMENTATIONS += makaha .WAIT +IMPLEMENTATIONS += opl .WAIT $(CLOSED_BUILD)CLOSED_IMPLEMENTATIONS = chalupa .WAIT $(CLOSED_BUILD)CLOSED_IMPLEMENTATIONS += ents .WAIT @@ -299,6 +300,7 @@ $(IF_TRAPTRACE_OBJ)us3_common_asm.o := DEBUG_DEFS += -DTRAPTRACE $(IF_TRAPTRACE_OBJ)us3_cheetah_asm.o := DEBUG_DEFS += -DTRAPTRACE $(IF_TRAPTRACE_OBJ)us3_cheetahplus_asm.o := DEBUG_DEFS += -DTRAPTRACE $(IF_TRAPTRACE_OBJ)us3_jalapeno_asm.o := DEBUG_DEFS += -DTRAPTRACE +$(IF_TRAPTRACE_OBJ)opl_olympus_asm.o := DEBUG_DEFS += -DTRAPTRACE # Comment these out if you don't want dispatcher lock statistics. @@ -433,6 +435,7 @@ SYS_KMODS += MISC_KMODS += obpsym bootdev vis cpr platmod md5 sha1 i2c_svc MISC_KMODS += sbd +MISC_KMODS += opl_cfg MISC_KMODS += kmech_krb5 MISC_KMODS += zuluvm @@ -472,7 +475,7 @@ CPU_KMODS += cheetah cheetahplus jalapeno serrano spitfire hummingbird # sun4u 'TOD' Modules (/platform/.../kernel/tod): # TOD_KMODS += todds1287 todds1337 todmostek todstarfire -TOD_KMODS += todm5819 todblade todbq4802 todsg +TOD_KMODS += todm5819 todblade todbq4802 todsg todopl $(CLOSED_BUILD)CLOSED_TOD_KMODS += todm5819p_rmc todstarcat todm5823 @@ -480,3 +483,4 @@ $(CLOSED_BUILD)CLOSED_TOD_KMODS += todm5819p_rmc todstarcat todm5823 # Performance Counter BackEnd Modules (/usr/kernel/pcbe): # PCBE_KMODS += us234_pcbe +PCBE_KMODS += opl_pcbe diff --git a/usr/src/uts/sun4u/Makefile.workarounds b/usr/src/uts/sun4u/Makefile.workarounds index 444d2b974d..236b726d67 100644 --- a/usr/src/uts/sun4u/Makefile.workarounds +++ b/usr/src/uts/sun4u/Makefile.workarounds @@ -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. @@ -22,10 +21,10 @@ # # uts/sun4u/Makefile.workarounds # -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -#ident "%Z%%M% %I% %E% SMI" +#pragma ident "%Z%%M% %I% %E% SMI" # # # This makefile contains workaround defines to be shared @@ -89,3 +88,8 @@ WORKAROUND_DEFS += -DJALAPENO_ERRATA_85 # Relocate ITLB t16 index 0 locked TTEs to avoid eviction. # Will not be fixed. WORKAROUND_DEFS += -DCHEETAHPLUS_ERRATUM_34 + +# OLYMPUS C cross-call errata. The first revision of the CPU can +# deliver only one cross call at time. +# Will be fixed in the succeeded revision of the cpu. +WORKAROUND_DEFS += -DOLYMPUS_ERRATA_XCALL diff --git a/usr/src/uts/sun4u/cpu/common_asm.s b/usr/src/uts/sun4u/cpu/common_asm.s index e434e4cca6..49a2080e3a 100644 --- a/usr/src/uts/sun4u/cpu/common_asm.s +++ b/usr/src/uts/sun4u/cpu/common_asm.s @@ -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,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -53,7 +52,7 @@ * Do not use any instruction that modifies condition codes as the * caller may depend on these to remain unchanged across the macro. */ -#if defined(CHEETAH) +#if defined(CHEETAH) || defined(OLYMPUS_C) #define GET_NATIVE_TIME(out, scr1, scr2) \ rd STICK, out @@ -907,6 +906,13 @@ adj_shift: * With UltraSPARC-III the combination of supporting mixed-speed CPUs * and variable clock rate for power management requires that we * use %stick to implement this routine. + * + * For OPL platforms that support the "sleep" instruction, we + * conditionally (ifdef'ed) insert a "sleep" instruction in + * the loop. Note that theoritically we should have move (duplicated) + * the code down to spitfire/us3/opl specific asm files - but this + * is alot of code duplication just to add one "sleep" instruction. + * We chose less code duplication for this. */ #if defined(lint) @@ -935,7 +941,11 @@ usec_delay(int n) GET_NATIVE_TIME(%o2, %o3, %o4) add %o1, %o2, %o1 -1: cmp %o1, %o2 +1: +#ifdef _OPL + .word 0x81b01060 ! insert "sleep" instruction +#endif /* _OPL */ ! use byte code for now + cmp %o1, %o2 GET_NATIVE_TIME(%o2, %o3, %o4) bgeu,pt %xcc, 1b nop @@ -1251,11 +1261,31 @@ prefetch_page_r(void *pp) retl prefetch [%o0+STRIDE2], #n_reads SET_SIZE(prefetch_page_r) -#else /* SPITFIRE || HUMMINGBIRD */ + +#elif defined(OLYMPUS_C) + ! + ! Prefetch strides for Olympus-C + ! + +#define STRIDE1 512 +#define STRIDE2 640 + + ENTRY(prefetch_page_w) + prefetch [%o0+STRIDE1], #n_writes + retl + prefetch [%o0+STRIDE2], #n_writes + SET_SIZE(prefetch_page_w) + + ENTRY(prefetch_page_r) + prefetch [%o0+STRIDE1], #n_writes + retl + prefetch [%o0+STRIDE2], #n_writes + SET_SIZE(prefetch_page_r) +#else /* OLYMPUS_C */ #error "You need to fix this for your new cpu type." -#endif /* SPITFIRE || HUMMINGBIRD */ +#endif /* OLYMPUS_C */ #endif /* lint */ @@ -1278,11 +1308,16 @@ prefetch_smap_w(void *smp) #define PREFETCH_Q_LEN 3 -#else /* SPITFIRE || HUMMINGBIRD */ +#elif defined(OLYMPUS_C) + ! + ! (TBD) Use length of one for now. +#define PREFETCH_Q_LEN 1 + +#else /* OLYMPUS_C */ #error You need to fix this for your new cpu type. -#endif /* SPITFIRE || HUMMINGBIRD */ +#endif /* OLYMPUS_C */ #include <vm/kpm.h> diff --git a/usr/src/uts/sun4u/cpu/opl_kdi.c b/usr/src/uts/sun4u/cpu/opl_kdi.c new file mode 100644 index 0000000000..c6795bb4e8 --- /dev/null +++ b/usr/src/uts/sun4u/cpu/opl_kdi.c @@ -0,0 +1,156 @@ +/* + * 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" + +/* + * CPU-specific functions needed by the Kernel-Debugger Interface (KDI). These + * functions are invoked directly by the kernel debugger (kmdb) while the system + * has been stopped, and as such must not use any kernel facilities that block + * or otherwise rely on forward progress by other parts of the kernel. + * + * These functions may also be called before unix`_start, and as such cannot + * use any kernel facilities that must be initialized as part of system start. + * An example of such a facility is drv_usecwait(), which relies on a parameter + * that is initialized by the unix module. As a result, drv_usecwait() may not + * be used by KDI functions. + */ + +#include <sys/types.h> +#include <sys/systm.h> +#include <sys/archsystm.h> +#include <sys/machsystm.h> +#include <sys/cpu_module.h> +#include <sys/xc_impl.h> +#include <sys/intreg.h> +#include <sys/kdi_impl.h> + +/* + * We keep our own copies, used for cache flushing, because we can be called + * before cpu_fiximpl(). + */ +static int kdi_dcache_size; +static int kdi_dcache_linesize; +static int kdi_icache_size; +static int kdi_icache_linesize; + +/* + * Assembly support for SPARC64-VI modules in opl_olympus_asm.s + */ +extern int idsr_busy(void); +extern void init_mondo_nocheck(xcfunc_t *func, uint64_t arg1, uint64_t arg2); +extern void shipit(int, int); +extern void kdi_flush_idcache(int, int, int, int); +extern int kdi_get_stick(uint64_t *); + +static int +kdi_cpu_ready_iter(int (*cb)(int, void *), void *arg) +{ + int rc, i; + + for (rc = 0, i = 0; i < NCPU; i++) { + if (CPU_IN_SET(cpu_ready_set, i)) + rc += cb(i, arg); + } + + return (rc); +} + +/* + * Sends a cross-call to a specified processor. The caller assumes + * responsibility for repetition of cross-calls, as appropriate (MARSA for + * debugging). + */ +static int +kdi_xc_one(int cpuid, void (*func)(uintptr_t, uintptr_t), uintptr_t arg1, + uintptr_t arg2) +{ + uint64_t idsr; + static void kdi_tickwait(clock_t); + uint64_t endtick, tick; + + init_mondo_nocheck((xcfunc_t *)func, arg1, arg2); + + shipit(cpuid, 0); + + /* Spin for at most 1 second for checking */ + endtick = gettick() + (uint64_t)sys_tick_freq; + + idsr = getidsr(); + + if (idsr & IDSR_BUSY) { + do { + idsr = getidsr(); + tick = gettick(); + if (tick > endtick) { + return (KDI_XC_RES_BUSY); + } + } while (idsr & IDSR_BUSY); + } + + kdi_tickwait(20000); + + if (idsr & IDSR_NACK) + return (KDI_XC_RES_NACK); + else + return (KDI_XC_RES_OK); +} + +static void +kdi_tickwait(clock_t nticks) +{ + clock_t endtick = gettick() + nticks; + + while (gettick() < endtick); +} + +static void +kdi_cpu_init(int dcache_size, int dcache_linesize, int icache_size, + int icache_linesize) +{ + kdi_dcache_size = dcache_size; + kdi_dcache_linesize = dcache_linesize; + kdi_icache_size = icache_size; + kdi_icache_linesize = icache_linesize; +} + +/* used directly by kdi_read/write_phys */ +void +kdi_flush_caches(void) +{ + kdi_flush_idcache(kdi_dcache_size, kdi_dcache_linesize, + kdi_icache_size, kdi_icache_linesize); +} + +void +cpu_kdi_init(kdi_t *kdi) +{ + kdi->kdi_flush_caches = kdi_flush_caches; + kdi->mkdi_cpu_init = kdi_cpu_init; + kdi->mkdi_cpu_ready_iter = kdi_cpu_ready_iter; + kdi->mkdi_xc_one = kdi_xc_one; + kdi->mkdi_tickwait = kdi_tickwait; + kdi->mkdi_get_stick = kdi_get_stick; +} diff --git a/usr/src/uts/sun4u/cpu/opl_olympus.c b/usr/src/uts/sun4u/cpu/opl_olympus.c new file mode 100644 index 0000000000..35d54c0a0a --- /dev/null +++ b/usr/src/uts/sun4u/cpu/opl_olympus.c @@ -0,0 +1,2237 @@ +/* + * 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 <sys/types.h> +#include <sys/systm.h> +#include <sys/ddi.h> +#include <sys/sysmacros.h> +#include <sys/archsystm.h> +#include <sys/vmsystm.h> +#include <sys/machparam.h> +#include <sys/machsystm.h> +#include <sys/machthread.h> +#include <sys/cpu.h> +#include <sys/cmp.h> +#include <sys/elf_SPARC.h> +#include <vm/vm_dep.h> +#include <vm/hat_sfmmu.h> +#include <vm/seg_kpm.h> +#include <sys/cpuvar.h> +#include <sys/opl_olympus_regs.h> +#include <sys/opl_module.h> +#include <sys/async.h> +#include <sys/cmn_err.h> +#include <sys/debug.h> +#include <sys/dditypes.h> +#include <sys/cpu_module.h> +#include <sys/sysmacros.h> +#include <sys/intreg.h> +#include <sys/clock.h> +#include <sys/platform_module.h> +#include <sys/ontrap.h> +#include <sys/panic.h> +#include <sys/memlist.h> +#include <sys/ndifm.h> +#include <sys/ddifm.h> +#include <sys/fm/protocol.h> +#include <sys/fm/util.h> +#include <sys/fm/cpu/SPARC64-VI.h> +#include <sys/dtrace.h> +#include <sys/watchpoint.h> +#include <sys/promif.h> + +/* + * Internal functions. + */ +static int cpu_sync_log_err(void *flt); +static void cpu_payload_add_aflt(struct async_flt *, nvlist_t *, nvlist_t *); +static void opl_cpu_sync_error(struct regs *, ulong_t, ulong_t, uint_t, uint_t); +static int cpu_flt_in_memory(opl_async_flt_t *, uint64_t); + +/* + * Error counters resetting interval. + */ +static int opl_async_check_interval = 60; /* 1 min */ + +/* + * Maximum number of contexts for Olympus-C. + */ +#define MAX_NCTXS (1 << 13) + +/* Will be set !NULL for SPARC64-VI and derivatives. */ +static uchar_t ctx_pgsz_arr[MAX_NCTXS]; +uchar_t *ctx_pgsz_array = ctx_pgsz_arr; + +/* + * PA[22:0] represent Displacement in Jupiter + * configuration space. + */ +uint_t root_phys_addr_lo_mask = 0x7fffffu; + +/* + * set in /etc/system to control logging of user BERR/TO's + */ +int cpu_berr_to_verbose = 0; + +static int min_ecache_size; +static uint_t priv_hcl_1; +static uint_t priv_hcl_2; +static uint_t priv_hcl_4; +static uint_t priv_hcl_8; + +/* + * Olympus error log + */ +static opl_errlog_t *opl_err_log; + +/* + * UE is classified into four classes (MEM, CHANNEL, CPU, PATH). + * No any other ecc_type_info insertion is allowed in between the following + * four UE classess. + */ +ecc_type_to_info_t ecc_type_to_info[] = { + SFSR_UE, "UE ", (OPL_ECC_SYNC_TRAP), OPL_CPU_SYNC_UE, + "Uncorrectable ECC", FM_EREPORT_PAYLOAD_SYNC, + FM_EREPORT_CPU_UE_MEM, + SFSR_UE, "UE ", (OPL_ECC_SYNC_TRAP), OPL_CPU_SYNC_UE, + "Uncorrectable ECC", FM_EREPORT_PAYLOAD_SYNC, + FM_EREPORT_CPU_UE_CHANNEL, + SFSR_UE, "UE ", (OPL_ECC_SYNC_TRAP), OPL_CPU_SYNC_UE, + "Uncorrectable ECC", FM_EREPORT_PAYLOAD_SYNC, + FM_EREPORT_CPU_UE_CPU, + SFSR_UE, "UE ", (OPL_ECC_SYNC_TRAP), OPL_CPU_SYNC_UE, + "Uncorrectable ECC", FM_EREPORT_PAYLOAD_SYNC, + FM_EREPORT_CPU_UE_PATH, + SFSR_BERR, "BERR ", (OPL_ECC_SYNC_TRAP), OPL_CPU_SYNC_OTHERS, + "Bus Error", FM_EREPORT_PAYLOAD_SYNC, + FM_EREPORT_CPU_BERR, + SFSR_TO, "TO ", (OPL_ECC_SYNC_TRAP), OPL_CPU_SYNC_OTHERS, + "Bus Timeout", FM_EREPORT_PAYLOAD_SYNC, + FM_EREPORT_CPU_BTO, + SFSR_TLB_MUL, "TLB_MUL ", (OPL_ECC_SYNC_TRAP), OPL_CPU_SYNC_OTHERS, + "TLB MultiHit", FM_EREPORT_PAYLOAD_SYNC, + FM_EREPORT_CPU_MTLB, + SFSR_TLB_PRT, "TLB_PRT ", (OPL_ECC_SYNC_TRAP), OPL_CPU_SYNC_OTHERS, + "TLB Parity", FM_EREPORT_PAYLOAD_SYNC, + FM_EREPORT_CPU_TLBP, + + UGESR_IAUG_CRE, "IAUG_CRE", OPL_ECC_URGENT_TRAP, OPL_CPU_URGENT, + "IAUG CRE", FM_EREPORT_PAYLOAD_URGENT, + FM_EREPORT_CPU_CRE, + UGESR_IAUG_TSBCTXT, "IAUG_TSBCTXT", + OPL_ECC_URGENT_TRAP, OPL_CPU_URGENT, + "IAUG TSBCTXT", FM_EREPORT_PAYLOAD_URGENT, + FM_EREPORT_CPU_TSBCTX, + UGESR_IUG_TSBP, "IUG_TSBP", OPL_ECC_URGENT_TRAP, OPL_CPU_URGENT, + "IUG TSBP", FM_EREPORT_PAYLOAD_URGENT, + FM_EREPORT_CPU_TSBP, + UGESR_IUG_PSTATE, "IUG_PSTATE", OPL_ECC_URGENT_TRAP, OPL_CPU_URGENT, + "IUG PSTATE", FM_EREPORT_PAYLOAD_URGENT, + FM_EREPORT_CPU_PSTATE, + UGESR_IUG_TSTATE, "IUG_TSTATE", OPL_ECC_URGENT_TRAP, OPL_CPU_URGENT, + "IUG TSTATE", FM_EREPORT_PAYLOAD_URGENT, + FM_EREPORT_CPU_TSTATE, + UGESR_IUG_F, "IUG_F", OPL_ECC_URGENT_TRAP, OPL_CPU_URGENT, + "IUG FREG", FM_EREPORT_PAYLOAD_URGENT, + FM_EREPORT_CPU_IUG_F, + UGESR_IUG_R, "IUG_R", OPL_ECC_URGENT_TRAP, OPL_CPU_URGENT, + "IUG RREG", FM_EREPORT_PAYLOAD_URGENT, + FM_EREPORT_CPU_IUG_R, + UGESR_AUG_SDC, "AUG_SDC", OPL_ECC_URGENT_TRAP, OPL_CPU_URGENT, + "AUG SDC", FM_EREPORT_PAYLOAD_URGENT, + FM_EREPORT_CPU_SDC, + UGESR_IUG_WDT, "IUG_WDT", OPL_ECC_URGENT_TRAP, OPL_CPU_URGENT, + "IUG WDT", FM_EREPORT_PAYLOAD_URGENT, + FM_EREPORT_CPU_WDT, + UGESR_IUG_DTLB, "IUG_DTLB", OPL_ECC_URGENT_TRAP, OPL_CPU_URGENT, + "IUG DTLB", FM_EREPORT_PAYLOAD_URGENT, + FM_EREPORT_CPU_DTLB, + UGESR_IUG_ITLB, "IUG_ITLB", OPL_ECC_URGENT_TRAP, OPL_CPU_URGENT, + "IUG ITLB", FM_EREPORT_PAYLOAD_URGENT, + FM_EREPORT_CPU_ITLB, + UGESR_IUG_COREERR, "IUG_COREERR", + OPL_ECC_URGENT_TRAP, OPL_CPU_URGENT, + "IUG COREERR", FM_EREPORT_PAYLOAD_URGENT, + FM_EREPORT_CPU_CORE, + UGESR_MULTI_DAE, "MULTI_DAE", OPL_ECC_URGENT_TRAP, OPL_CPU_URGENT, + "MULTI DAE", FM_EREPORT_PAYLOAD_URGENT, + FM_EREPORT_CPU_DAE, + UGESR_MULTI_IAE, "MULTI_IAE", OPL_ECC_URGENT_TRAP, OPL_CPU_URGENT, + "MULTI IAE", FM_EREPORT_PAYLOAD_URGENT, + FM_EREPORT_CPU_IAE, + UGESR_MULTI_UGE, "MULTI_UGE", OPL_ECC_URGENT_TRAP, OPL_CPU_URGENT, + "MULTI UGE", FM_EREPORT_PAYLOAD_URGENT, + FM_EREPORT_CPU_UGE, + 0, NULL, 0, 0, + NULL, 0, 0, +}; + +int (*p2get_mem_info)(int synd_code, uint64_t paddr, + uint64_t *mem_sizep, uint64_t *seg_sizep, uint64_t *bank_sizep, + int *segsp, int *banksp, int *mcidp); + + +/* + * Setup trap handlers for 0xA, 0x32, 0x40 trap types. + */ +void +cpu_init_trap(void) +{ + OPL_SET_TRAP(tt0_iae, opl_serr_instr); + OPL_SET_TRAP(tt1_iae, opl_serr_instr); + OPL_SET_TRAP(tt0_dae, opl_serr_instr); + OPL_SET_TRAP(tt1_dae, opl_serr_instr); + OPL_SET_TRAP(tt0_asdat, opl_ugerr_instr); + OPL_SET_TRAP(tt1_asdat, opl_ugerr_instr); +} + +static int +getintprop(pnode_t node, char *name, int deflt) +{ + int value; + + switch (prom_getproplen(node, name)) { + case sizeof (int): + (void) prom_getprop(node, name, (caddr_t)&value); + break; + + default: + value = deflt; + break; + } + + return (value); +} + +/* + * Set the magic constants of the implementation. + */ +/*ARGSUSED*/ +void +cpu_fiximp(pnode_t dnode) +{ + int i, a; + extern int vac_size, vac_shift; + extern uint_t vac_mask; + + static struct { + char *name; + int *var; + int defval; + } prop[] = { + "l1-dcache-size", &dcache_size, OPL_DCACHE_SIZE, + "l1-dcache-line-size", &dcache_linesize, OPL_DCACHE_LSIZE, + "l1-icache-size", &icache_size, OPL_ICACHE_SIZE, + "l1-icache-line-size", &icache_linesize, OPL_ICACHE_LSIZE, + "l2-cache-size", &ecache_size, OPL_ECACHE_SIZE, + "l2-cache-line-size", &ecache_alignsize, OPL_ECACHE_LSIZE, + "l2-cache-associativity", &ecache_associativity, OPL_ECACHE_NWAY + }; + + for (i = 0; i < sizeof (prop) / sizeof (prop[0]); i++) + *prop[i].var = getintprop(dnode, prop[i].name, prop[i].defval); + + ecache_setsize = ecache_size / ecache_associativity; + + vac_size = OPL_VAC_SIZE; + vac_mask = MMU_PAGEMASK & (vac_size - 1); + i = 0; a = vac_size; + while (a >>= 1) + ++i; + vac_shift = i; + shm_alignment = vac_size; + vac = 1; +} + +void +send_mondo_set(cpuset_t set) +{ + int lo, busy, nack, shipped = 0; + uint16_t i, cpuids[IDSR_BN_SETS]; + uint64_t idsr, nackmask = 0, busymask, curnack, curbusy; + uint64_t starttick, endtick, tick, lasttick; +#if (NCPU > IDSR_BN_SETS) + int index = 0; + int ncpuids = 0; +#endif +#ifdef OLYMPUS_ERRATA_XCALL + int bn_sets = IDSR_BN_SETS; + uint64_t ver; + + ASSERT(NCPU > bn_sets); +#endif + + ASSERT(!CPUSET_ISNULL(set)); + starttick = lasttick = gettick(); + +#ifdef OLYMPUS_ERRATA_XCALL + ver = ultra_getver(); + if (((ULTRA_VER_IMPL(ver)) == OLYMPUS_C_IMPL) && + ((OLYMPUS_REV_MASK(ver)) == OLYMPUS_C_A)) + bn_sets = 1; +#endif + +#if (NCPU <= IDSR_BN_SETS) + for (i = 0; i < NCPU; i++) + if (CPU_IN_SET(set, i)) { + shipit(i, shipped); + nackmask |= IDSR_NACK_BIT(shipped); + cpuids[shipped++] = i; + CPUSET_DEL(set, i); + if (CPUSET_ISNULL(set)) + break; + } + CPU_STATS_ADDQ(CPU, sys, xcalls, shipped); +#else + for (i = 0; i < NCPU; i++) + if (CPU_IN_SET(set, i)) { + ncpuids++; + + /* + * Ship only to the first (IDSR_BN_SETS) CPUs. If we + * find we have shipped to more than (IDSR_BN_SETS) + * CPUs, set "index" to the highest numbered CPU in + * the set so we can ship to other CPUs a bit later on. + */ +#ifdef OLYMPUS_ERRATA_XCALL + if (shipped < bn_sets) { +#else + if (shipped < IDSR_BN_SETS) { +#endif + shipit(i, shipped); + nackmask |= IDSR_NACK_BIT(shipped); + cpuids[shipped++] = i; + CPUSET_DEL(set, i); + if (CPUSET_ISNULL(set)) + break; + } else + index = (int)i; + } + + CPU_STATS_ADDQ(CPU, sys, xcalls, ncpuids); +#endif + + busymask = IDSR_NACK_TO_BUSY(nackmask); + busy = nack = 0; + endtick = starttick + xc_tick_limit; + for (;;) { + idsr = getidsr(); +#if (NCPU <= IDSR_BN_SETS) + if (idsr == 0) + break; +#else + if (idsr == 0 && shipped == ncpuids) + break; +#endif + tick = gettick(); + /* + * If there is a big jump between the current tick + * count and lasttick, we have probably hit a break + * point. Adjust endtick accordingly to avoid panic. + */ + if (tick > (lasttick + xc_tick_jump_limit)) + endtick += (tick - lasttick); + lasttick = tick; + if (tick > endtick) { + if (panic_quiesce) + return; + cmn_err(CE_CONT, "send mondo timeout " + "[%d NACK %d BUSY]\nIDSR 0x%" + "" PRIx64 " cpuids:", nack, busy, idsr); +#ifdef OLYMPUS_ERRATA_XCALL + for (i = 0; i < bn_sets; i++) { +#else + for (i = 0; i < IDSR_BN_SETS; i++) { +#endif + if (idsr & (IDSR_NACK_BIT(i) | + IDSR_BUSY_BIT(i))) { + cmn_err(CE_CONT, " 0x%x", + cpuids[i]); + } + } + cmn_err(CE_CONT, "\n"); + cmn_err(CE_PANIC, "send_mondo_set: timeout"); + } + curnack = idsr & nackmask; + curbusy = idsr & busymask; +#if (NCPU > IDSR_BN_SETS) + if (shipped < ncpuids) { + uint64_t cpus_left; + uint16_t next = (uint16_t)index; + + cpus_left = ~(IDSR_NACK_TO_BUSY(curnack) | curbusy) & + busymask; + + if (cpus_left) { + do { + /* + * Sequence through and ship to the + * remainder of the CPUs in the system + * (e.g. other than the first + * (IDSR_BN_SETS)) in reverse order. + */ + lo = lowbit(cpus_left) - 1; + i = IDSR_BUSY_IDX(lo); + shipit(next, i); + shipped++; + cpuids[i] = next; + + /* + * If we've processed all the CPUs, + * exit the loop now and save + * instructions. + */ + if (shipped == ncpuids) + break; + + for ((index = ((int)next - 1)); + index >= 0; index--) + if (CPU_IN_SET(set, index)) { + next = (uint16_t)index; + break; + } + + cpus_left &= ~(1ull << lo); + } while (cpus_left); + continue; + } + } +#endif + if (curbusy) { + busy++; + continue; + } + +#ifdef SEND_MONDO_STATS + { + int n = gettick() - starttick; + if (n < 8192) + x_nack_stimes[n >> 7]++; + } +#endif + while (gettick() < (tick + sys_clock_mhz)) + ; + do { + lo = lowbit(curnack) - 1; + i = IDSR_NACK_IDX(lo); + shipit(cpuids[i], i); + curnack &= ~(1ull << lo); + } while (curnack); + nack++; + busy = 0; + } +#ifdef SEND_MONDO_STATS + { + int n = gettick() - starttick; + if (n < 8192) + x_set_stimes[n >> 7]++; + else + x_set_ltimes[(n >> 13) & 0xf]++; + } + x_set_cpus[shipped]++; +#endif +} + +/* + * Cpu private initialization. + */ +void +cpu_init_private(struct cpu *cp) +{ + if (!(IS_OLYMPUS_C(cpunodes[cp->cpu_id].implementation))) { + cmn_err(CE_PANIC, "CPU%d Impl %d: Only SPARC64-VI is supported", + cp->cpu_id, cpunodes[cp->cpu_id].implementation); + } + + adjust_hw_copy_limits(cpunodes[cp->cpu_id].ecache_size); +} + +void +cpu_setup(void) +{ + extern int at_flags; + extern int disable_delay_tlb_flush, delay_tlb_flush; + extern int cpc_has_overflow_intr; + extern int disable_text_largepages; + extern int use_text_pgsz4m; + uint64_t cpu0_log; + extern uint64_t opl_cpu0_err_log; + + /* + * Initialize Error log Scratch register for error handling. + */ + + cpu0_log = va_to_pa(&opl_cpu0_err_log); + opl_error_setup(cpu0_log); + + /* + * Enable MMU translating multiple page sizes for + * sITLB and sDTLB. + */ + opl_mpg_enable(); + + /* + * Setup chip-specific trap handlers. + */ + cpu_init_trap(); + + cache |= (CACHE_VAC | CACHE_PTAG | CACHE_IOCOHERENT); + + at_flags = EF_SPARC_32PLUS | EF_SPARC_SUN_US1 | EF_SPARC_SUN_US3; + + /* + * Use the maximum number of contexts available for SPARC64-VI + * unless it has been tuned for debugging. + * We are checking against 0 here since this value can be patched + * while booting. It can not be patched via /etc/system since it + * will be patched too late and thus cause the system to panic. + */ + if (nctxs == 0) + nctxs = MAX_NCTXS; + + /* + * Due to the number of entries in the fully-associative tlb + * this may have to be tuned lower than in spitfire. + */ + pp_slots = MIN(8, MAXPP_SLOTS); + + /* + * Block stores do not invalidate all pages of the d$, pagecopy + * et. al. need virtual translations with virtual coloring taken + * into consideration. prefetch/ldd will pollute the d$ on the + * load side. + */ + pp_consistent_coloring = PPAGE_STORE_VCOLORING | PPAGE_LOADS_POLLUTE; + + if (use_page_coloring) { + do_pg_coloring = 1; + if (use_virtual_coloring) + do_virtual_coloring = 1; + } + + isa_list = + "sparcv9+vis2 sparcv9+vis sparcv9 " + "sparcv8plus+vis2 sparcv8plus+vis sparcv8plus " + "sparcv8 sparcv8-fsmuld sparcv7 sparc"; + + cpu_hwcap_flags = AV_SPARC_VIS | AV_SPARC_VIS2; + + /* + * On SPARC64-VI, there's no hole in the virtual address space + */ + hole_start = hole_end = 0; + + /* + * The kpm mapping window. + * kpm_size: + * The size of a single kpm range. + * The overall size will be: kpm_size * vac_colors. + * kpm_vbase: + * The virtual start address of the kpm range within the kernel + * virtual address space. kpm_vbase has to be kpm_size aligned. + */ + kpm_size = (size_t)(128ull * 1024 * 1024 * 1024 * 1024); /* 128TB */ + kpm_size_shift = 47; + kpm_vbase = (caddr_t)0x8000000000000000ull; /* 8EB */ + kpm_smallpages = 1; + + /* + * The traptrace code uses either %tick or %stick for + * timestamping. We have %stick so we can use it. + */ + traptrace_use_stick = 1; + + /* + * SPARC64-VI has a performance counter overflow interrupt + */ + cpc_has_overflow_intr = 1; + + /* + * Use SPARC64-VI flush-all support + */ + if (!disable_delay_tlb_flush) + delay_tlb_flush = 1; + + /* + * Declare that this architecture/cpu combination does not support + * fpRAS. + */ + fpras_implemented = 0; + + /* + * Enable 4M pages to be used for mapping user text by default. Don't + * use large pages for initialized data segments since we may not know + * at exec() time what should be the preferred large page size for DTLB + * programming. + */ + use_text_pgsz4m = 1; + disable_text_largepages = (1 << TTE64K) | (1 << TTE512K) | + (1 << TTE32M) | (1 << TTE256M); +} + +/* + * Called by setcpudelay + */ +void +cpu_init_tick_freq(void) +{ + /* + * For SPARC64-VI we want to use the system clock rate as + * the basis for low level timing, due to support of mixed + * speed CPUs and power managment. + */ + if (system_clock_freq == 0) + cmn_err(CE_PANIC, "setcpudelay: invalid system_clock_freq"); + + sys_tick_freq = system_clock_freq; +} + +#ifdef SEND_MONDO_STATS +uint32_t x_one_stimes[64]; +uint32_t x_one_ltimes[16]; +uint32_t x_set_stimes[64]; +uint32_t x_set_ltimes[16]; +uint32_t x_set_cpus[NCPU]; +uint32_t x_nack_stimes[64]; +#endif + +/* + * Note: A version of this function is used by the debugger via the KDI, + * and must be kept in sync with this version. Any changes made to this + * function to support new chips or to accomodate errata must also be included + * in the KDI-specific version. See us3_kdi.c. + */ +void +send_one_mondo(int cpuid) +{ + int busy, nack; + uint64_t idsr, starttick, endtick, tick, lasttick; + uint64_t busymask; + + CPU_STATS_ADDQ(CPU, sys, xcalls, 1); + starttick = lasttick = gettick(); + shipit(cpuid, 0); + endtick = starttick + xc_tick_limit; + busy = nack = 0; + busymask = IDSR_BUSY; + for (;;) { + idsr = getidsr(); + if (idsr == 0) + break; + + tick = gettick(); + /* + * If there is a big jump between the current tick + * count and lasttick, we have probably hit a break + * point. Adjust endtick accordingly to avoid panic. + */ + if (tick > (lasttick + xc_tick_jump_limit)) + endtick += (tick - lasttick); + lasttick = tick; + if (tick > endtick) { + if (panic_quiesce) + return; + cmn_err(CE_PANIC, "send mondo timeout " + "(target 0x%x) [%d NACK %d BUSY]", + cpuid, nack, busy); + } + + if (idsr & busymask) { + busy++; + continue; + } + drv_usecwait(1); + shipit(cpuid, 0); + nack++; + busy = 0; + } +#ifdef SEND_MONDO_STATS + { + int n = gettick() - starttick; + if (n < 8192) + x_one_stimes[n >> 7]++; + else + x_one_ltimes[(n >> 13) & 0xf]++; + } +#endif +} + +/* + * init_mmu_page_sizes is set to one after the bootup time initialization + * via mmu_init_mmu_page_sizes, to indicate that mmu_page_sizes has a + * valid value. + * + * mmu_disable_ism_large_pages and mmu_disable_large_pages are the mmu-specific + * versions of disable_ism_large_pages and disable_large_pages, and feed back + * into those two hat variables at hat initialization time. + * + */ +int init_mmu_page_sizes = 0; +static int mmu_disable_ism_large_pages = ((1 << TTE64K) | + (1 << TTE512K) | (1 << TTE256M)); +static int mmu_disable_large_pages = 0; + +/* + * Re-initialize mmu_page_sizes and friends, for SPARC64-VI mmu support. + * Called during very early bootup from check_cpus_set(). + * Can be called to verify that mmu_page_sizes are set up correctly. + * + * Set Olympus defaults. We do not use the function parameter. + */ +/*ARGSUSED*/ +int +mmu_init_mmu_page_sizes(int32_t not_used) +{ + if (!init_mmu_page_sizes) { + mmu_page_sizes = MMU_PAGE_SIZES; + mmu_hashcnt = MAX_HASHCNT; + mmu_ism_pagesize = MMU_PAGESIZE32M; + mmu_exported_pagesize_mask = (1 << TTE8K) | + (1 << TTE64K) | (1 << TTE512K) | (1 << TTE4M) | + (1 << TTE32M) | (1 << TTE256M); + init_mmu_page_sizes = 1; + return (0); + } + return (1); +} + +/* SPARC64-VI worst case DTLB parameters */ +#ifndef LOCKED_DTLB_ENTRIES +#define LOCKED_DTLB_ENTRIES 5 /* 2 user TSBs, 2 nucleus, + OBP */ +#endif +#define TOTAL_DTLB_ENTRIES 32 +#define AVAIL_32M_ENTRIES 0 +#define AVAIL_256M_ENTRIES 0 +#define AVAIL_DTLB_ENTRIES (TOTAL_DTLB_ENTRIES - LOCKED_DTLB_ENTRIES) +static uint64_t ttecnt_threshold[MMU_PAGE_SIZES] = { + AVAIL_DTLB_ENTRIES, AVAIL_DTLB_ENTRIES, + AVAIL_DTLB_ENTRIES, AVAIL_DTLB_ENTRIES, + AVAIL_DTLB_ENTRIES, AVAIL_DTLB_ENTRIES}; + +size_t +mmu_map_pgsz(size_t pgsize) +{ + struct proc *p = curproc; + struct as *as = p->p_as; + struct hat *hat = as->a_hat; + uint_t pgsz0, pgsz1; + size_t size0, size1; + + ASSERT(mmu_page_sizes == max_mmu_page_sizes); + pgsz0 = hat->sfmmu_pgsz[0]; + pgsz1 = hat->sfmmu_pgsz[1]; + size0 = hw_page_array[pgsz0].hp_size; + size1 = hw_page_array[pgsz1].hp_size; + /* Allow use of a larger pagesize if neither TLB is reprogrammed. */ + if ((pgsz0 == TTE8K) && (pgsz1 == TTE8K)) { + return (pgsize); + /* Allow use of requested pagesize if TLB is reprogrammed to it. */ + } else if ((pgsize == size0) || (pgsize == size1)) { + return (pgsize); + /* Use larger reprogrammed TLB size if pgsize is atleast that big. */ + } else if (pgsz1 > pgsz0) { + if (pgsize >= size1) + return (size1); + /* Use smaller reprogrammed TLB size if pgsize is atleast that big. */ + } else { + if (pgsize >= size0) + return (size0); + } + return (pgsize); +} + +/* + * The function returns the mmu-specific values for the + * hat's disable_large_pages and disable_ism_large_pages variables. + */ +int +mmu_large_pages_disabled(uint_t flag) +{ + int pages_disable = 0; + + if (flag == HAT_LOAD) { + pages_disable = mmu_disable_large_pages; + } else if (flag == HAT_LOAD_SHARE) { + pages_disable = mmu_disable_ism_large_pages; + } + return (pages_disable); +} + +/* + * mmu_init_large_pages is called with the desired ism_pagesize parameter. + * It may be called from set_platform_defaults, if some value other than 32M + * is desired. mmu_ism_pagesize is the tunable. If it has a bad value, + * then only warn, since it would be bad form to panic due to a user typo. + * + * The function re-initializes the mmu_disable_ism_large_pages variable. + */ +void +mmu_init_large_pages(size_t ism_pagesize) +{ + switch (ism_pagesize) { + case MMU_PAGESIZE4M: + mmu_disable_ism_large_pages = ((1 << TTE64K) | + (1 << TTE512K) | (1 << TTE32M) | (1 << TTE256M)); + break; + case MMU_PAGESIZE32M: + mmu_disable_ism_large_pages = ((1 << TTE64K) | + (1 << TTE512K) | (1 << TTE256M)); + break; + case MMU_PAGESIZE256M: + mmu_disable_ism_large_pages = ((1 << TTE64K) | + (1 << TTE512K) | (1 << TTE32M)); + break; + default: + cmn_err(CE_WARN, "Unrecognized mmu_ism_pagesize value 0x%lx", + ism_pagesize); + break; + } +} + +/*ARGSUSED*/ +uint_t +mmu_preferred_pgsz(struct hat *hat, caddr_t addr, size_t len) +{ + sfmmu_t *sfmmup = (sfmmu_t *)hat; + uint_t pgsz0, pgsz1; + uint_t szc, maxszc = mmu_page_sizes - 1; + size_t pgsz; + extern int disable_large_pages; + + pgsz0 = (uint_t)sfmmup->sfmmu_pgsz[0]; + pgsz1 = (uint_t)sfmmup->sfmmu_pgsz[1]; + + /* + * If either of the TLBs are reprogrammed, choose + * the largest mapping size as the preferred size, + * if it fits the size and alignment constraints. + * Else return the largest mapping size that fits, + * if neither TLB is reprogrammed. + */ + if (pgsz0 > TTE8K || pgsz1 > TTE8K) { + if (pgsz1 > pgsz0) { /* First try pgsz1 */ + pgsz = hw_page_array[pgsz1].hp_size; + if ((len >= pgsz) && IS_P2ALIGNED(addr, pgsz)) + return (pgsz1); + } + if (pgsz0 > TTE8K) { /* Then try pgsz0, if !TTE8K */ + pgsz = hw_page_array[pgsz0].hp_size; + if ((len >= pgsz) && IS_P2ALIGNED(addr, pgsz)) + return (pgsz0); + } + } else { /* Otherwise pick best fit if neither TLB is reprogrammed. */ + for (szc = maxszc; szc > TTE8K; szc--) { + if (disable_large_pages & (1 << szc)) + continue; + + pgsz = hw_page_array[szc].hp_size; + if ((len >= pgsz) && IS_P2ALIGNED(addr, pgsz)) + return (szc); + } + } + return (TTE8K); +} + +/* + * Function to reprogram the TLBs when page sizes used + * by a process change significantly. + */ +void +mmu_setup_page_sizes(struct hat *hat, uint64_t *ttecnt) +{ + extern int page_szc(size_t); + uint8_t pgsz0, pgsz1; + + /* + * Don't program 2nd dtlb for kernel and ism hat + */ + if (hat->sfmmu_ismhat || hat == ksfmmup) + return; + + /* + * hat->sfmmu_pgsz[] is an array whose elements + * contain a sorted order of page sizes. Element + * 0 is the most commonly used page size, followed + * by element 1, and so on. + * + * ttecnt[] is an array of per-page-size page counts + * mapped into the process. + * + * If the HAT's choice for page sizes is unsuitable, + * we can override it here. The new values written + * to the array will be handed back to us later to + * do the actual programming of the TLB hardware. + * + */ + pgsz0 = (uint8_t)MIN(hat->sfmmu_pgsz[0], hat->sfmmu_pgsz[1]); + pgsz1 = (uint8_t)MAX(hat->sfmmu_pgsz[0], hat->sfmmu_pgsz[1]); + + /* + * This implements PAGESIZE programming of the sTLB + * if large TTE counts don't exceed the thresholds. + */ + if (ttecnt[pgsz0] < ttecnt_threshold[pgsz0]) + pgsz0 = page_szc(MMU_PAGESIZE); + if (ttecnt[pgsz1] < ttecnt_threshold[pgsz1]) + pgsz1 = page_szc(MMU_PAGESIZE); + hat->sfmmu_pgsz[0] = pgsz0; + hat->sfmmu_pgsz[1] = pgsz1; + /* otherwise, accept what the HAT chose for us */ +} + +/* + * The HAT calls this function when an MMU context is allocated so that we + * can reprogram the large TLBs appropriately for the new process using + * the context. + * + * The caller must hold the HAT lock. + */ +void +mmu_set_ctx_page_sizes(struct hat *hat) +{ + uint8_t pgsz0, pgsz1; + uint8_t new_cext; + + ASSERT(sfmmu_hat_lock_held(hat)); + /* + * Don't program 2nd dtlb for kernel and ism hat + */ + if (hat->sfmmu_ismhat || hat == ksfmmup) + return; + + /* + * If supported, reprogram the TLBs to a larger pagesize. + */ + pgsz0 = hat->sfmmu_pgsz[0]; + pgsz1 = hat->sfmmu_pgsz[1]; + ASSERT(pgsz0 < mmu_page_sizes); + ASSERT(pgsz1 < mmu_page_sizes); + new_cext = TAGACCEXT_MKSZPAIR(pgsz1, pgsz0); + if (hat->sfmmu_cext != new_cext) { + hat->sfmmu_cext = new_cext; + } + ctx_pgsz_array[hat->sfmmu_cnum] = hat->sfmmu_cext; + /* + * sfmmu_setctx_sec() will take care of the + * rest of the dirty work for us. + */ +} + +/* + * Return processor specific async error structure + * size used. + */ +int +cpu_aflt_size(void) +{ + return (sizeof (opl_async_flt_t)); +} + +/* + * The cpu_sync_log_err() function is called via the [uc]e_drain() function to + * post-process CPU events that are dequeued. As such, it can be invoked + * from softint context, from AST processing in the trap() flow, or from the + * panic flow. We decode the CPU-specific data, and take appropriate actions. + * Historically this entry point was used to log the actual cmn_err(9F) text; + * now with FMA it is used to prepare 'flt' to be converted into an ereport. + * With FMA this function now also returns a flag which indicates to the + * caller whether the ereport should be posted (1) or suppressed (0). + */ +/*ARGSUSED*/ +static int +cpu_sync_log_err(void *flt) +{ + opl_async_flt_t *opl_flt = (opl_async_flt_t *)flt; + struct async_flt *aflt = (struct async_flt *)flt; + + /* + * No extra processing of urgent error events. + * Always generate ereports for these events. + */ + if (aflt->flt_status == OPL_ECC_URGENT_TRAP) + return (1); + + /* + * Additional processing for synchronous errors. + */ + switch (opl_flt->flt_type) { + case OPL_CPU_INV_SFSR: + return (1); + + case OPL_CPU_SYNC_UE: + /* + * The validity: SFSR_MK_UE bit has been checked + * in opl_cpu_sync_error() + * No more check is required. + * + * opl_flt->flt_eid_mod and flt_eid_sid have been set by H/W, + * and they have been retrieved in cpu_queue_events() + */ + + if (opl_flt->flt_eid_mod == OPL_ERRID_MEM) { + ASSERT(aflt->flt_in_memory); + /* + * We want to skip logging only if ALL the following + * conditions are true: + * + * 1. We are not panicing already. + * 2. The error is a memory error. + * 3. There is only one error. + * 4. The error is on a retired page. + * 5. The error occurred under on_trap + * protection AFLT_PROT_EC + */ + if (!panicstr && aflt->flt_prot == AFLT_PROT_EC && + page_retire_check(aflt->flt_addr, NULL) == 0) { + /* + * Do not log an error from + * the retired page + */ + softcall(ecc_page_zero, (void *)aflt->flt_addr); + return (0); + } + if (!panicstr) + cpu_page_retire(opl_flt); + } + return (1); + + case OPL_CPU_SYNC_OTHERS: + /* + * For the following error cases, the processor HW does + * not set the flt_eid_mod/flt_eid_sid. Instead, SW will attempt + * to assign appropriate values here to reflect what we + * think is the most likely cause of the problem w.r.t to + * the particular error event. For Buserr and timeout + * error event, we will assign OPL_ERRID_CHANNEL as the + * most likely reason. For TLB parity or multiple hit + * error events, we will assign the reason as + * OPL_ERRID_CPU (cpu related problem) and set the + * flt_eid_sid to point to the cpuid. + */ + + if (opl_flt->flt_bit & (SFSR_BERR|SFSR_TO)) { + /* + * flt_eid_sid will not be used for this case. + */ + opl_flt->flt_eid_mod = OPL_ERRID_CHANNEL; + } + if (opl_flt->flt_bit & (SFSR_TLB_MUL|SFSR_TLB_PRT)) { + opl_flt->flt_eid_mod = OPL_ERRID_CPU; + opl_flt->flt_eid_sid = aflt->flt_inst; + } + + /* + * In case of no effective error bit + */ + if ((opl_flt->flt_bit & SFSR_ERRS) == 0) { + opl_flt->flt_eid_mod = OPL_ERRID_CPU; + opl_flt->flt_eid_sid = aflt->flt_inst; + } + break; + + default: + return (1); + } + return (1); +} + +/* + * Retire the bad page that may contain the flushed error. + */ +void +cpu_page_retire(opl_async_flt_t *opl_flt) +{ + struct async_flt *aflt = (struct async_flt *)opl_flt; + (void) page_retire(aflt->flt_addr, PR_UE); +} + +/* + * Invoked by error_init() early in startup and therefore before + * startup_errorq() is called to drain any error Q - + * + * startup() + * startup_end() + * error_init() + * cpu_error_init() + * errorq_init() + * errorq_drain() + * start_other_cpus() + * + * The purpose of this routine is to create error-related taskqs. Taskqs + * are used for this purpose because cpu_lock can't be grabbed from interrupt + * context. + * + */ +/*ARGSUSED*/ +void +cpu_error_init(int items) +{ + opl_err_log = (opl_errlog_t *) + kmem_alloc(ERRLOG_ALLOC_SZ, KM_SLEEP); + if ((uint64_t)opl_err_log & MMU_PAGEOFFSET) + cmn_err(CE_PANIC, "The base address of the error log " + "is not page aligned"); +} + +/* + * We route all errors through a single switch statement. + */ +void +cpu_ue_log_err(struct async_flt *aflt) +{ + switch (aflt->flt_class) { + case CPU_FAULT: + if (cpu_sync_log_err(aflt)) + cpu_ereport_post(aflt); + break; + + case BUS_FAULT: + bus_async_log_err(aflt); + break; + + default: + cmn_err(CE_WARN, "discarding async error %p with invalid " + "fault class (0x%x)", (void *)aflt, aflt->flt_class); + return; + } +} + +/* + * Routine for panic hook callback from panic_idle(). + * + * Nothing to do here. + */ +void +cpu_async_panic_callb(void) +{ +} + +/* + * Routine to return a string identifying the physical name + * associated with a memory/cache error. + */ +/*ARGSUSED*/ +int +cpu_get_mem_unum(int synd_status, ushort_t flt_synd, uint64_t flt_stat, + uint64_t flt_addr, int flt_bus_id, int flt_in_memory, + ushort_t flt_status, char *buf, int buflen, int *lenp) +{ + int synd_code; + int ret; + + /* + * An AFSR of -1 defaults to a memory syndrome. + */ + synd_code = (int)flt_synd; + + if (&plat_get_mem_unum) { + if ((ret = plat_get_mem_unum(synd_code, flt_addr, flt_bus_id, + flt_in_memory, flt_status, buf, buflen, lenp)) != 0) { + buf[0] = '\0'; + *lenp = 0; + } + return (ret); + } + buf[0] = '\0'; + *lenp = 0; + return (ENOTSUP); +} + +/* + * Wrapper for cpu_get_mem_unum() routine that takes an + * async_flt struct rather than explicit arguments. + */ +int +cpu_get_mem_unum_aflt(int synd_status, struct async_flt *aflt, + char *buf, int buflen, int *lenp) +{ + /* + * We always pass -1 so that cpu_get_mem_unum will interpret this as a + * memory error. + */ + return (cpu_get_mem_unum(synd_status, aflt->flt_synd, + (uint64_t)-1, + aflt->flt_addr, aflt->flt_bus_id, aflt->flt_in_memory, + aflt->flt_status, buf, buflen, lenp)); +} + +/* + * This routine is a more generic interface to cpu_get_mem_unum() + * that may be used by other modules (e.g. mm). + */ +/*ARGSUSED*/ +int +cpu_get_mem_name(uint64_t synd, uint64_t *afsr, uint64_t afar, + char *buf, int buflen, int *lenp) +{ + int synd_status, flt_in_memory, ret; + ushort_t flt_status = 0; + char unum[UNUM_NAMLEN]; + + /* + * Check for an invalid address. + */ + if (afar == (uint64_t)-1) + return (ENXIO); + + if (synd == (uint64_t)-1) + synd_status = AFLT_STAT_INVALID; + else + synd_status = AFLT_STAT_VALID; + + flt_in_memory = (*afsr & SFSR_MEMORY) && + pf_is_memory(afar >> MMU_PAGESHIFT); + + ret = cpu_get_mem_unum(synd_status, (ushort_t)synd, *afsr, afar, + CPU->cpu_id, flt_in_memory, flt_status, unum, + UNUM_NAMLEN, lenp); + if (ret != 0) + return (ret); + + if (*lenp >= buflen) + return (ENAMETOOLONG); + + (void) strncpy(buf, unum, buflen); + + return (0); +} + +/* + * Routine to return memory information associated + * with a physical address and syndrome. + */ +/*ARGSUSED*/ +int +cpu_get_mem_info(uint64_t synd, uint64_t afar, + uint64_t *mem_sizep, uint64_t *seg_sizep, uint64_t *bank_sizep, + int *segsp, int *banksp, int *mcidp) +{ + int synd_code = (int)synd; + + if (afar == (uint64_t)-1) + return (ENXIO); + + if (p2get_mem_info != NULL) + return ((p2get_mem_info)(synd_code, afar, + mem_sizep, seg_sizep, bank_sizep, + segsp, banksp, mcidp)); + else + return (ENOTSUP); +} + +/* + * Routine to return a string identifying the physical + * name associated with a cpuid. + */ +int +cpu_get_cpu_unum(int cpuid, char *buf, int buflen, int *lenp) +{ + int ret; + char unum[UNUM_NAMLEN]; + + if (&plat_get_cpu_unum) { + if ((ret = plat_get_cpu_unum(cpuid, unum, UNUM_NAMLEN, lenp)) + != 0) + return (ret); + } else { + return (ENOTSUP); + } + + if (*lenp >= buflen) + return (ENAMETOOLONG); + + (void) strncpy(buf, unum, *lenp); + + return (0); +} + +/* + * This routine exports the name buffer size. + */ +size_t +cpu_get_name_bufsize() +{ + return (UNUM_NAMLEN); +} + +/* + * Flush the entire ecache by ASI_L2_CNTL.U2_FLUSH + */ +void +cpu_flush_ecache(void) +{ + flush_ecache(ecache_flushaddr, cpunodes[CPU->cpu_id].ecache_size, + cpunodes[CPU->cpu_id].ecache_linesize); +} + +static uint8_t +flt_to_trap_type(struct async_flt *aflt) +{ + if (aflt->flt_status & OPL_ECC_ISYNC_TRAP) + return (TRAP_TYPE_ECC_I); + if (aflt->flt_status & OPL_ECC_DSYNC_TRAP) + return (TRAP_TYPE_ECC_D); + if (aflt->flt_status & OPL_ECC_URGENT_TRAP) + return (TRAP_TYPE_URGENT); + return (-1); +} + +/* + * Encode the data saved in the opl_async_flt_t struct into + * the FM ereport payload. + */ +/* ARGSUSED */ +static void +cpu_payload_add_aflt(struct async_flt *aflt, nvlist_t *payload, + nvlist_t *resource) +{ + opl_async_flt_t *opl_flt = (opl_async_flt_t *)aflt; + char unum[UNUM_NAMLEN]; + char sbuf[21]; /* sizeof (UINT64_MAX) + '\0' */ + int len; + + + if (aflt->flt_payload & FM_EREPORT_PAYLOAD_FLAG_SFSR) { + fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_SFSR, + DATA_TYPE_UINT64, aflt->flt_stat, NULL); + } + if (aflt->flt_payload & FM_EREPORT_PAYLOAD_FLAG_SFAR) { + fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_SFAR, + DATA_TYPE_UINT64, aflt->flt_addr, NULL); + } + if (aflt->flt_payload & FM_EREPORT_PAYLOAD_FLAG_UGESR) { + fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_UGESR, + DATA_TYPE_UINT64, aflt->flt_stat, NULL); + } + if (aflt->flt_payload & FM_EREPORT_PAYLOAD_FLAG_PC) { + fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_PC, + DATA_TYPE_UINT64, (uint64_t)aflt->flt_pc, NULL); + } + if (aflt->flt_payload & FM_EREPORT_PAYLOAD_FLAG_TL) { + fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_TL, + DATA_TYPE_UINT8, (uint8_t)aflt->flt_tl, NULL); + } + if (aflt->flt_payload & FM_EREPORT_PAYLOAD_FLAG_TT) { + fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_TT, + DATA_TYPE_UINT8, flt_to_trap_type(aflt), NULL); + } + if (aflt->flt_payload & FM_EREPORT_PAYLOAD_FLAG_PRIV) { + fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_PRIV, + DATA_TYPE_BOOLEAN_VALUE, + (aflt->flt_priv ? B_TRUE : B_FALSE), NULL); + } + if (aflt->flt_payload & FM_EREPORT_PAYLOAD_FLAG_FLT_STATUS) { + fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_FLT_STATUS, + DATA_TYPE_UINT64, (uint64_t)aflt->flt_status, NULL); + } + + switch (opl_flt->flt_eid_mod) { + case OPL_ERRID_CPU: + (void) snprintf(sbuf, sizeof (sbuf), "%llX", + (u_longlong_t)cpunodes[opl_flt->flt_eid_sid].device_id); + (void) fm_fmri_cpu_set(resource, FM_CPU_SCHEME_VERSION, + NULL, opl_flt->flt_eid_sid, + (uint8_t *)&cpunodes[opl_flt->flt_eid_sid].version, + sbuf); + fm_payload_set(payload, + FM_EREPORT_PAYLOAD_NAME_RESOURCE, + DATA_TYPE_NVLIST, resource, NULL); + break; + + case OPL_ERRID_CHANNEL: + /* + * No resource is created but the cpumem DE will find + * the defective path by retreiving EID from SFSR which is + * included in the payload. + */ + break; + + case OPL_ERRID_MEM: + (void) cpu_get_mem_unum_aflt(0, aflt, unum, UNUM_NAMLEN, &len); + (void) fm_fmri_mem_set(resource, FM_MEM_SCHEME_VERSION, + NULL, unum, NULL, (uint64_t)-1); + fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_RESOURCE, + DATA_TYPE_NVLIST, resource, NULL); + break; + + case OPL_ERRID_PATH: + /* + * No resource is created but the cpumem DE will find + * the defective path by retreiving EID from SFSR which is + * included in the payload. + */ + break; + } +} + +/* + * Returns whether fault address is valid for this error bit and + * whether the address is "in memory" (i.e. pf_is_memory returns 1). + */ +/*ARGSUSED*/ +static int +cpu_flt_in_memory(opl_async_flt_t *opl_flt, uint64_t t_afsr_bit) +{ + struct async_flt *aflt = (struct async_flt *)opl_flt; + + if (aflt->flt_status & (OPL_ECC_SYNC_TRAP)) { + return ((t_afsr_bit & SFSR_MEMORY) && + pf_is_memory(aflt->flt_addr >> MMU_PAGESHIFT)); + } + return (0); +} + +/* + * In OPL SCF does the stick synchronization. + */ +void +sticksync_slave(void) +{ +} + +/* + * In OPL SCF does the stick synchronization. + */ +void +sticksync_master(void) +{ +} + +/* + * Cpu private unitialization. OPL cpus do not use the private area. + */ +void +cpu_uninit_private(struct cpu *cp) +{ + cmp_delete_cpu(cp->cpu_id); +} + +/* + * Always flush an entire cache. + */ +void +cpu_error_ecache_flush(void) +{ + cpu_flush_ecache(); +} + +void +cpu_ereport_post(struct async_flt *aflt) +{ + char *cpu_type, buf[FM_MAX_CLASS]; + nv_alloc_t *nva = NULL; + nvlist_t *ereport, *detector, *resource; + errorq_elem_t *eqep; + char sbuf[21]; /* sizeof (UINT64_MAX) + '\0' */ + + if (aflt->flt_panic || panicstr) { + eqep = errorq_reserve(ereport_errorq); + if (eqep == NULL) + return; + ereport = errorq_elem_nvl(ereport_errorq, eqep); + nva = errorq_elem_nva(ereport_errorq, eqep); + } else { + ereport = fm_nvlist_create(nva); + } + + /* + * Create the scheme "cpu" FMRI. + */ + detector = fm_nvlist_create(nva); + resource = fm_nvlist_create(nva); + switch (cpunodes[aflt->flt_inst].implementation) { + case OLYMPUS_C_IMPL: + cpu_type = FM_EREPORT_CPU_SPARC64_VI; + break; + default: + cpu_type = FM_EREPORT_CPU_UNSUPPORTED; + break; + } + (void) snprintf(sbuf, sizeof (sbuf), "%llX", + (u_longlong_t)cpunodes[aflt->flt_inst].device_id); + (void) fm_fmri_cpu_set(detector, FM_CPU_SCHEME_VERSION, NULL, + aflt->flt_inst, (uint8_t *)&cpunodes[aflt->flt_inst].version, + sbuf); + + /* + * Encode all the common data into the ereport. + */ + (void) snprintf(buf, FM_MAX_CLASS, "%s.%s.%s", + FM_ERROR_CPU, cpu_type, aflt->flt_erpt_class); + + fm_ereport_set(ereport, FM_EREPORT_VERSION, buf, + fm_ena_generate(aflt->flt_id, FM_ENA_FMT1), detector, NULL); + + /* + * Encode the error specific data that was saved in + * the async_flt structure into the ereport. + */ + cpu_payload_add_aflt(aflt, ereport, resource); + + if (aflt->flt_panic || panicstr) { + errorq_commit(ereport_errorq, eqep, ERRORQ_SYNC); + } else { + (void) fm_ereport_post(ereport, EVCH_TRYHARD); + fm_nvlist_destroy(ereport, FM_NVA_FREE); + fm_nvlist_destroy(detector, FM_NVA_FREE); + fm_nvlist_destroy(resource, FM_NVA_FREE); + } +} + +void +cpu_run_bus_error_handlers(struct async_flt *aflt, int expected) +{ + int status; + ddi_fm_error_t de; + + bzero(&de, sizeof (ddi_fm_error_t)); + + de.fme_version = DDI_FME_VERSION; + de.fme_ena = fm_ena_generate(aflt->flt_id, FM_ENA_FMT1); + de.fme_flag = expected; + de.fme_bus_specific = (void *)aflt->flt_addr; + status = ndi_fm_handler_dispatch(ddi_root_node(), NULL, &de); + if ((aflt->flt_prot == AFLT_PROT_NONE) && (status == DDI_FM_FATAL)) + aflt->flt_panic = 1; +} + +void +cpu_errorq_dispatch(char *error_class, void *payload, size_t payload_sz, + errorq_t *eqp, uint_t flag) +{ + struct async_flt *aflt = (struct async_flt *)payload; + + aflt->flt_erpt_class = error_class; + errorq_dispatch(eqp, payload, payload_sz, flag); +} + +void +adjust_hw_copy_limits(int ecache_size) +{ + /* + * Set hw copy limits. + * + * /etc/system will be parsed later and can override one or more + * of these settings. + * + * At this time, ecache size seems only mildly relevant. + * We seem to run into issues with the d-cache and stalls + * we see on misses. + * + * Cycle measurement indicates that 2 byte aligned copies fare + * little better than doing things with VIS at around 512 bytes. + * 4 byte aligned shows promise until around 1024 bytes. 8 Byte + * aligned is faster whenever the source and destination data + * in cache and the total size is less than 2 Kbytes. The 2K + * limit seems to be driven by the 2K write cache. + * When more than 2K of copies are done in non-VIS mode, stores + * backup in the write cache. In VIS mode, the write cache is + * bypassed, allowing faster cache-line writes aligned on cache + * boundaries. + * + * In addition, in non-VIS mode, there is no prefetching, so + * for larger copies, the advantage of prefetching to avoid even + * occasional cache misses is enough to justify using the VIS code. + * + * During testing, it was discovered that netbench ran 3% slower + * when hw_copy_limit_8 was 2K or larger. Apparently for server + * applications, data is only used once (copied to the output + * buffer, then copied by the network device off the system). Using + * the VIS copy saves more L2 cache state. Network copies are + * around 1.3K to 1.5K in size for historical reasons. + * + * Therefore, a limit of 1K bytes will be used for the 8 byte + * aligned copy even for large caches and 8 MB ecache. The + * infrastructure to allow different limits for different sized + * caches is kept to allow further tuning in later releases. + */ + + if (min_ecache_size == 0 && use_hw_bcopy) { + /* + * First time through - should be before /etc/system + * is read. + * Could skip the checks for zero but this lets us + * preserve any debugger rewrites. + */ + if (hw_copy_limit_1 == 0) { + hw_copy_limit_1 = VIS_COPY_THRESHOLD; + priv_hcl_1 = hw_copy_limit_1; + } + if (hw_copy_limit_2 == 0) { + hw_copy_limit_2 = 2 * VIS_COPY_THRESHOLD; + priv_hcl_2 = hw_copy_limit_2; + } + if (hw_copy_limit_4 == 0) { + hw_copy_limit_4 = 4 * VIS_COPY_THRESHOLD; + priv_hcl_4 = hw_copy_limit_4; + } + if (hw_copy_limit_8 == 0) { + hw_copy_limit_8 = 4 * VIS_COPY_THRESHOLD; + priv_hcl_8 = hw_copy_limit_8; + } + min_ecache_size = ecache_size; + } else { + /* + * MP initialization. Called *after* /etc/system has + * been parsed. One CPU has already been initialized. + * Need to cater for /etc/system having scragged one + * of our values. + */ + if (ecache_size == min_ecache_size) { + /* + * Same size ecache. We do nothing unless we + * have a pessimistic ecache setting. In that + * case we become more optimistic (if the cache is + * large enough). + */ + if (hw_copy_limit_8 == 4 * VIS_COPY_THRESHOLD) { + /* + * Need to adjust hw_copy_limit* from our + * pessimistic uniprocessor value to a more + * optimistic UP value *iff* it hasn't been + * reset. + */ + if ((ecache_size > 1048576) && + (priv_hcl_8 == hw_copy_limit_8)) { + if (ecache_size <= 2097152) + hw_copy_limit_8 = 4 * + VIS_COPY_THRESHOLD; + else if (ecache_size <= 4194304) + hw_copy_limit_8 = 4 * + VIS_COPY_THRESHOLD; + else + hw_copy_limit_8 = 4 * + VIS_COPY_THRESHOLD; + priv_hcl_8 = hw_copy_limit_8; + } + } + } else if (ecache_size < min_ecache_size) { + /* + * A different ecache size. Can this even happen? + */ + if (priv_hcl_8 == hw_copy_limit_8) { + /* + * The previous value that we set + * is unchanged (i.e., it hasn't been + * scragged by /etc/system). Rewrite it. + */ + if (ecache_size <= 1048576) + hw_copy_limit_8 = 8 * + VIS_COPY_THRESHOLD; + else if (ecache_size <= 2097152) + hw_copy_limit_8 = 8 * + VIS_COPY_THRESHOLD; + else if (ecache_size <= 4194304) + hw_copy_limit_8 = 8 * + VIS_COPY_THRESHOLD; + else + hw_copy_limit_8 = 10 * + VIS_COPY_THRESHOLD; + priv_hcl_8 = hw_copy_limit_8; + min_ecache_size = ecache_size; + } + } + } +} + +#define VIS_BLOCKSIZE 64 + +int +dtrace_blksuword32_err(uintptr_t addr, uint32_t *data) +{ + int ret, watched; + + watched = watch_disable_addr((void *)addr, VIS_BLOCKSIZE, S_WRITE); + ret = dtrace_blksuword32(addr, data, 0); + if (watched) + watch_enable_addr((void *)addr, VIS_BLOCKSIZE, S_WRITE); + + return (ret); +} + +void +opl_cpu_reg_init() +{ + uint64_t this_cpu_log; + + /* + * We do not need to re-initialize cpu0 registers. + */ + if (cpu[getprocessorid()] == &cpu0) + return; + + /* + * Initialize Error log Scratch register for error handling. + */ + + this_cpu_log = va_to_pa((void*)(((uint64_t)opl_err_log) + + ERRLOG_BUFSZ * (getprocessorid()))); + opl_error_setup(this_cpu_log); + + /* + * Enable MMU translating multiple page sizes for + * sITLB and sDTLB. + */ + opl_mpg_enable(); +} + +/* + * Queue one event in ue_queue based on ecc_type_to_info entry. + */ +static void +cpu_queue_one_event(opl_async_flt_t *opl_flt, char *reason, + ecc_type_to_info_t *eccp) +{ + struct async_flt *aflt = (struct async_flt *)opl_flt; + + if (reason && + strlen(reason) + strlen(eccp->ec_reason) < MAX_REASON_STRING) { + (void) strcat(reason, eccp->ec_reason); + } + + opl_flt->flt_bit = eccp->ec_afsr_bit; + opl_flt->flt_type = eccp->ec_flt_type; + aflt->flt_in_memory = cpu_flt_in_memory(opl_flt, opl_flt->flt_bit); + aflt->flt_payload = eccp->ec_err_payload; + + ASSERT(aflt->flt_status & (OPL_ECC_SYNC_TRAP|OPL_ECC_URGENT_TRAP)); + cpu_errorq_dispatch(eccp->ec_err_class, + (void *)opl_flt, sizeof (opl_async_flt_t), + ue_queue, + aflt->flt_panic); +} + +/* + * Queue events on async event queue one event per error bit. + * Return number of events queued. + */ +int +cpu_queue_events(opl_async_flt_t *opl_flt, char *reason, uint64_t t_afsr_errs) +{ + struct async_flt *aflt = (struct async_flt *)opl_flt; + ecc_type_to_info_t *eccp; + int nevents = 0; + + /* + * Queue expected errors, error bit and fault type must must match + * in the ecc_type_to_info table. + */ + for (eccp = ecc_type_to_info; t_afsr_errs != 0 && eccp->ec_desc != NULL; + eccp++) { + if ((eccp->ec_afsr_bit & t_afsr_errs) != 0 && + (eccp->ec_flags & aflt->flt_status) != 0) { + /* + * UE error event can be further + * classified/breakdown into finer granularity + * based on the flt_eid_mod value set by HW. We do + * special handling here so that we can report UE + * error in finer granularity as ue_mem, + * ue_channel, ue_cpu or ue_path. + */ + if (eccp->ec_flt_type == OPL_CPU_SYNC_UE) { + opl_flt->flt_eid_mod = + (aflt->flt_stat & SFSR_EID_MOD) + >> SFSR_EID_MOD_SHIFT; + opl_flt->flt_eid_sid = + (aflt->flt_stat & SFSR_EID_SID) + >> SFSR_EID_SID_SHIFT; + /* + * Need to advance eccp pointer by flt_eid_mod + * so that we get an appropriate ecc pointer + * + * EID # of advances + * ---------------------------------- + * OPL_ERRID_MEM 0 + * OPL_ERRID_CHANNEL 1 + * OPL_ERRID_CPU 2 + * OPL_ERRID_PATH 3 + */ + eccp += opl_flt->flt_eid_mod; + } + cpu_queue_one_event(opl_flt, reason, eccp); + t_afsr_errs &= ~eccp->ec_afsr_bit; + nevents++; + } + } + + return (nevents); +} + +/* + * Sync. error wrapper functions. + * We use these functions in order to transfer here from the + * nucleus trap handler information about trap type (data or + * instruction) and trap level (0 or above 0). This way we + * get rid of using SFSR's reserved bits. + */ + +#define OPL_SYNC_TL0 0 +#define OPL_SYNC_TL1 1 +#define OPL_ISYNC_ERR 0 +#define OPL_DSYNC_ERR 1 + +void +opl_cpu_isync_tl0_error(struct regs *rp, ulong_t p_sfar, ulong_t p_sfsr) +{ + uint64_t t_sfar = p_sfar; + uint64_t t_sfsr = p_sfsr; + + opl_cpu_sync_error(rp, t_sfar, t_sfsr, + OPL_SYNC_TL0, OPL_ISYNC_ERR); +} + +void +opl_cpu_isync_tl1_error(struct regs *rp, ulong_t p_sfar, ulong_t p_sfsr) +{ + uint64_t t_sfar = p_sfar; + uint64_t t_sfsr = p_sfsr; + + opl_cpu_sync_error(rp, t_sfar, t_sfsr, + OPL_SYNC_TL1, OPL_ISYNC_ERR); +} + +void +opl_cpu_dsync_tl0_error(struct regs *rp, ulong_t p_sfar, ulong_t p_sfsr) +{ + uint64_t t_sfar = p_sfar; + uint64_t t_sfsr = p_sfsr; + + opl_cpu_sync_error(rp, t_sfar, t_sfsr, + OPL_SYNC_TL0, OPL_DSYNC_ERR); +} + +void +opl_cpu_dsync_tl1_error(struct regs *rp, ulong_t p_sfar, ulong_t p_sfsr) +{ + uint64_t t_sfar = p_sfar; + uint64_t t_sfsr = p_sfsr; + + opl_cpu_sync_error(rp, t_sfar, t_sfsr, + OPL_SYNC_TL1, OPL_DSYNC_ERR); +} + +/* + * The fj sync err handler transfers control here for UE, BERR, TO, TLB_MUL + * and TLB_PRT. + * This function is designed based on cpu_deferred_error(). + */ + +static void +opl_cpu_sync_error(struct regs *rp, ulong_t t_sfar, ulong_t t_sfsr, + uint_t tl, uint_t derr) +{ + opl_async_flt_t opl_flt; + struct async_flt *aflt; + int trampolined = 0; + char pr_reason[MAX_REASON_STRING]; + uint64_t log_sfsr; + int expected = DDI_FM_ERR_UNEXPECTED; + ddi_acc_hdl_t *hp; + + /* + * We need to look at p_flag to determine if the thread detected an + * error while dumping core. We can't grab p_lock here, but it's ok + * because we just need a consistent snapshot and we know that everyone + * else will store a consistent set of bits while holding p_lock. We + * don't have to worry about a race because SDOCORE is set once prior + * to doing i/o from the process's address space and is never cleared. + */ + uint_t pflag = ttoproc(curthread)->p_flag; + + pr_reason[0] = '\0'; + + /* + * handle the specific error + */ + bzero(&opl_flt, sizeof (opl_async_flt_t)); + aflt = (struct async_flt *)&opl_flt; + aflt->flt_id = gethrtime_waitfree(); + aflt->flt_bus_id = getprocessorid(); + aflt->flt_inst = CPU->cpu_id; + aflt->flt_stat = t_sfsr; + aflt->flt_addr = t_sfar; + aflt->flt_pc = (caddr_t)rp->r_pc; + aflt->flt_prot = (uchar_t)AFLT_PROT_NONE; + aflt->flt_class = (uchar_t)CPU_FAULT; + aflt->flt_priv = (uchar_t) + (tl == 1 ? 1 : ((rp->r_tstate & TSTATE_PRIV) ? 1 : 0)); + aflt->flt_tl = (uchar_t)tl; + aflt->flt_panic = (uchar_t)(tl != 0 || aft_testfatal != 0 || + (t_sfsr & (SFSR_TLB_MUL|SFSR_TLB_PRT)) != 0); + aflt->flt_core = (pflag & SDOCORE) ? 1 : 0; + aflt->flt_status = (derr) ? OPL_ECC_DSYNC_TRAP : OPL_ECC_ISYNC_TRAP; + + /* + * If SFSR.FV is not set, both SFSR and SFAR/SFPAR values are uncertain. + * So, clear all error bits to avoid mis-handling and force the system + * panicked. + * We skip all the procedures below down to the panic message call. + */ + if (!(t_sfsr & SFSR_FV)) { + opl_flt.flt_type = OPL_CPU_INV_SFSR; + aflt->flt_panic = 1; + aflt->flt_payload = FM_EREPORT_PAYLOAD_SYNC; + cpu_errorq_dispatch(FM_EREPORT_CPU_INV_SFSR, + (void *)&opl_flt, sizeof (opl_async_flt_t), ue_queue, + aflt->flt_panic); + fm_panic("%sErrors(s)", "invalid SFSR"); + } + + /* + * If either UE and MK bit is off, this is not valid UE error. + * If it is not valid UE error, clear UE & MK_UE bits to prevent + * mis-handling below. + * aflt->flt_stat keeps the original bits as a reference. + */ + if ((t_sfsr & (SFSR_MK_UE|SFSR_UE)) != + (SFSR_MK_UE|SFSR_UE)) { + t_sfsr &= ~(SFSR_MK_UE|SFSR_UE); + } + + /* + * If the trap occurred in privileged mode at TL=0, we need to check to + * see if we were executing in the kernel under on_trap() or t_lofault + * protection. If so, modify the saved registers so that we return + * from the trap to the appropriate trampoline routine. + */ + if (!aflt->flt_panic && aflt->flt_priv && tl == 0) { + if (curthread->t_ontrap != NULL) { + on_trap_data_t *otp = curthread->t_ontrap; + + if (otp->ot_prot & OT_DATA_EC) { + aflt->flt_prot = (uchar_t)AFLT_PROT_EC; + otp->ot_trap |= (ushort_t)OT_DATA_EC; + rp->r_pc = otp->ot_trampoline; + rp->r_npc = rp->r_pc + 4; + trampolined = 1; + } + + if ((t_sfsr & (SFSR_TO | SFSR_BERR)) && + (otp->ot_prot & OT_DATA_ACCESS)) { + aflt->flt_prot = (uchar_t)AFLT_PROT_ACCESS; + otp->ot_trap |= (ushort_t)OT_DATA_ACCESS; + rp->r_pc = otp->ot_trampoline; + rp->r_npc = rp->r_pc + 4; + trampolined = 1; + /* + * for peeks and caut_gets errors are expected + */ + hp = (ddi_acc_hdl_t *)otp->ot_handle; + if (!hp) + expected = DDI_FM_ERR_PEEK; + else if (hp->ah_acc.devacc_attr_access == + DDI_CAUTIOUS_ACC) + expected = DDI_FM_ERR_EXPECTED; + } + + } else if (curthread->t_lofault) { + aflt->flt_prot = AFLT_PROT_COPY; + rp->r_g1 = EFAULT; + rp->r_pc = curthread->t_lofault; + rp->r_npc = rp->r_pc + 4; + trampolined = 1; + } + } + + /* + * If we're in user mode or we're doing a protected copy, we either + * want the ASTON code below to send a signal to the user process + * or we want to panic if aft_panic is set. + * + * If we're in privileged mode and we're not doing a copy, then we + * need to check if we've trampolined. If we haven't trampolined, + * we should panic. + */ + if (!aflt->flt_priv || aflt->flt_prot == AFLT_PROT_COPY) { + if (t_sfsr & (SFSR_ERRS & ~(SFSR_BERR | SFSR_TO))) + aflt->flt_panic |= aft_panic; + } else if (!trampolined) { + aflt->flt_panic = 1; + } + + /* + * If we've trampolined due to a privileged TO or BERR, or if an + * unprivileged TO or BERR occurred, we don't want to enqueue an + * event for that TO or BERR. Queue all other events (if any) besides + * the TO/BERR. + */ + log_sfsr = t_sfsr; + if (trampolined) { + log_sfsr &= ~(SFSR_TO | SFSR_BERR); + } else if (!aflt->flt_priv) { + /* + * User mode, suppress messages if + * cpu_berr_to_verbose is not set. + */ + if (!cpu_berr_to_verbose) + log_sfsr &= ~(SFSR_TO | SFSR_BERR); + } + + if (((log_sfsr & SFSR_ERRS) && + (cpu_queue_events(&opl_flt, pr_reason, t_sfsr) == 0)) || + ((t_sfsr & SFSR_ERRS) == 0)) { + opl_flt.flt_type = OPL_CPU_INV_SFSR; + aflt->flt_payload = FM_EREPORT_PAYLOAD_SYNC; + cpu_errorq_dispatch(FM_EREPORT_CPU_INV_SFSR, + (void *)&opl_flt, sizeof (opl_async_flt_t), ue_queue, + aflt->flt_panic); + } + + if (t_sfsr & (SFSR_UE|SFSR_TO|SFSR_BERR)) { + cpu_run_bus_error_handlers(aflt, expected); + } + + /* + * Panic here if aflt->flt_panic has been set. Enqueued errors will + * be logged as part of the panic flow. + */ + if (aflt->flt_panic) { + if (pr_reason[0] == 0) + strcpy(pr_reason, "invalid SFSR "); + + fm_panic("%sErrors(s)", pr_reason); + } + + /* + * If we queued an error and we are going to return from the trap and + * the error was in user mode or inside of a copy routine, set AST flag + * so the queue will be drained before returning to user mode. The + * AST processing will also act on our failure policy. + */ + if (!aflt->flt_priv || aflt->flt_prot == AFLT_PROT_COPY) { + int pcb_flag = 0; + + if (t_sfsr & (SFSR_ERRS & + ~(SFSR_BERR | SFSR_TO))) + pcb_flag |= ASYNC_HWERR; + + if (t_sfsr & SFSR_BERR) + pcb_flag |= ASYNC_BERR; + + if (t_sfsr & SFSR_TO) + pcb_flag |= ASYNC_BTO; + + ttolwp(curthread)->lwp_pcb.pcb_flags |= pcb_flag; + aston(curthread); + } +} + +/*ARGSUSED*/ +void +opl_cpu_urgent_error(struct regs *rp, ulong_t p_ugesr, ulong_t tl) +{ + opl_async_flt_t opl_flt; + struct async_flt *aflt; + char pr_reason[MAX_REASON_STRING]; + + /* normalize tl */ + tl = (tl >= 2 ? 1 : 0); + pr_reason[0] = '\0'; + + bzero(&opl_flt, sizeof (opl_async_flt_t)); + aflt = (struct async_flt *)&opl_flt; + aflt->flt_id = gethrtime_waitfree(); + aflt->flt_bus_id = getprocessorid(); + aflt->flt_inst = CPU->cpu_id; + aflt->flt_stat = p_ugesr; + aflt->flt_pc = (caddr_t)rp->r_pc; + aflt->flt_class = (uchar_t)CPU_FAULT; + aflt->flt_tl = tl; + aflt->flt_priv = (uchar_t) + (tl == 1 ? 1 : ((rp->r_tstate & TSTATE_PRIV) ? 1 : 0)); + aflt->flt_status = OPL_ECC_URGENT_TRAP; + aflt->flt_panic = 1; + /* + * HW does not set mod/sid in case of urgent error. + * So we have to set it here. + */ + opl_flt.flt_eid_mod = OPL_ERRID_CPU; + opl_flt.flt_eid_sid = aflt->flt_inst; + + if (cpu_queue_events(&opl_flt, pr_reason, p_ugesr) == 0) { + opl_flt.flt_type = OPL_CPU_INV_UGESR; + aflt->flt_payload = FM_EREPORT_PAYLOAD_URGENT; + cpu_errorq_dispatch(FM_EREPORT_CPU_INV_URG, + (void *)&opl_flt, sizeof (opl_async_flt_t), + ue_queue, aflt->flt_panic); + } + + fm_panic("Urgent Error"); +} + +/* + * Initialization error counters resetting. + */ +/* ARGSUSED */ +static void +opl_ras_online(void *arg, cpu_t *cp, cyc_handler_t *hdlr, cyc_time_t *when) +{ + hdlr->cyh_func = (cyc_func_t)ras_cntr_reset; + hdlr->cyh_level = CY_LOW_LEVEL; + hdlr->cyh_arg = (void *)(uintptr_t)cp->cpu_id; + + when->cyt_when = cp->cpu_id * (((hrtime_t)NANOSEC * 10)/ NCPU); + when->cyt_interval = (hrtime_t)NANOSEC * opl_async_check_interval; +} + +void +cpu_mp_init(void) +{ + cyc_omni_handler_t hdlr; + + hdlr.cyo_online = opl_ras_online; + hdlr.cyo_offline = NULL; + hdlr.cyo_arg = NULL; + mutex_enter(&cpu_lock); + (void) cyclic_add_omni(&hdlr); + mutex_exit(&cpu_lock); +} + +/*ARGSUSED*/ +void +mmu_init_kernel_pgsz(struct hat *hat) +{ +} + +size_t +mmu_get_kernel_lpsize(size_t lpsize) +{ + uint_t tte; + + if (lpsize == 0) { + /* no setting for segkmem_lpsize in /etc/system: use default */ + return (MMU_PAGESIZE4M); + } + + for (tte = TTE8K; tte <= TTE4M; tte++) { + if (lpsize == TTEBYTES(tte)) + return (lpsize); + } + + return (TTEBYTES(TTE8K)); +} + +/* + * The following are functions that are unused in + * OPL cpu module. They are defined here to resolve + * dependencies in the "unix" module. + * Unused functions that should never be called in + * OPL are coded with ASSERT(0). + */ + +void +cpu_disable_errors(void) +{} + +void +cpu_enable_errors(void) +{ ASSERT(0); } + +/*ARGSUSED*/ +void +cpu_ce_scrub_mem_err(struct async_flt *ecc, boolean_t t) +{ ASSERT(0); } + +/*ARGSUSED*/ +void +cpu_faulted_enter(struct cpu *cp) +{} + +/*ARGSUSED*/ +void +cpu_faulted_exit(struct cpu *cp) +{} + +/*ARGSUSED*/ +void +cpu_check_allcpus(struct async_flt *aflt) +{} + +/*ARGSUSED*/ +void +cpu_ce_log_err(struct async_flt *aflt, errorq_elem_t *t) +{ ASSERT(0); } + +/*ARGSUSED*/ +void +cpu_check_ce(int flag, uint64_t pa, caddr_t va, uint_t psz) +{ ASSERT(0); } + +/*ARGSUSED*/ +void +cpu_ce_count_unum(struct async_flt *ecc, int len, char *unum) +{ ASSERT(0); } + +/*ARGSUSED*/ +void +cpu_busy_ecache_scrub(struct cpu *cp) +{} + +/*ARGSUSED*/ +void +cpu_idle_ecache_scrub(struct cpu *cp) +{} + +/* ARGSUSED */ +void +cpu_change_speed(uint64_t divisor, uint64_t arg2) +{ ASSERT(0); } + +void +cpu_init_cache_scrub(void) +{} + +/* ARGSUSED */ +int +cpu_get_mem_sid(char *unum, char *buf, int buflen, int *lenp) +{ + return (ENOTSUP); +} + +/* ARGSUSED */ +int +cpu_get_mem_addr(char *unum, char *sid, uint64_t offset, uint64_t *addrp) +{ + return (ENOTSUP); +} + +/* ARGSUSED */ +int +cpu_get_mem_offset(uint64_t flt_addr, uint64_t *offp) +{ + return (ENOTSUP); +} + +/*ARGSUSED*/ +void +itlb_rd_entry(uint_t entry, tte_t *tte, uint64_t *va_tag) +{ ASSERT(0); } + +/*ARGSUSED*/ +void +dtlb_rd_entry(uint_t entry, tte_t *tte, uint64_t *va_tag) +{ ASSERT(0); } diff --git a/usr/src/uts/sun4u/cpu/opl_olympus_asm.s b/usr/src/uts/sun4u/cpu/opl_olympus_asm.s new file mode 100644 index 0000000000..44e4983586 --- /dev/null +++ b/usr/src/uts/sun4u/cpu/opl_olympus_asm.s @@ -0,0 +1,1991 @@ +/* + * 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. + * + * Assembly code support for the Olympus-C module + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#if !defined(lint) +#include "assym.h" +#endif /* lint */ + +#include <sys/asm_linkage.h> +#include <sys/mmu.h> +#include <vm/hat_sfmmu.h> +#include <sys/machparam.h> +#include <sys/machcpuvar.h> +#include <sys/machthread.h> +#include <sys/machtrap.h> +#include <sys/privregs.h> +#include <sys/asm_linkage.h> +#include <sys/trap.h> +#include <sys/opl_olympus_regs.h> +#include <sys/opl_module.h> +#include <sys/xc_impl.h> +#include <sys/intreg.h> +#include <sys/async.h> +#include <sys/clock.h> +#include <sys/cmpregs.h> + +#ifdef TRAPTRACE +#include <sys/traptrace.h> +#endif /* TRAPTRACE */ + +/* + * Macro that flushes the entire Ecache. + * + * arg1 = ecache size + * arg2 = ecache linesize + * arg3 = ecache flush address - Not used for olympus-C + */ +#define ECACHE_FLUSHALL(arg1, arg2, arg3, tmp1) \ + mov ASI_L2_CTRL_U2_FLUSH, arg1; \ + mov ASI_L2_CTRL_RW_ADDR, arg2; \ + stxa arg1, [arg2]ASI_L2_CTRL + +/* + * SPARC64-VI MMU and Cache operations. + */ + +#if defined(lint) + +/* ARGSUSED */ +void +vtag_flushpage(caddr_t vaddr, u_int ctxnum) +{} + +#else /* lint */ + + ENTRY_NP(vtag_flushpage) + /* + * flush page from the tlb + * + * %o0 = vaddr + * %o1 = ctxnum + */ + rdpr %pstate, %o5 +#ifdef DEBUG + andcc %o5, PSTATE_IE, %g0 /* if interrupts already */ + bnz,a,pt %icc, 3f /* disabled, panic */ + nop + save %sp, -SA(MINFRAME), %sp + sethi %hi(sfmmu_panic1), %o0 + call panic + or %o0, %lo(sfmmu_panic1), %o0 + ret + restore +3: +#endif /* DEBUG */ + /* + * disable ints + */ + andn %o5, PSTATE_IE, %o4 + wrpr %o4, 0, %pstate + + /* + * Then, blow out the tlb + * Interrupts are disabled to prevent the primary ctx register + * from changing underneath us. + */ + brnz,pt %o1, 1f /* KCONTEXT? */ + sethi %hi(FLUSH_ADDR), %o3 + /* + * For KCONTEXT demaps use primary. type = page implicitly + */ + stxa %g0, [%o0]ASI_DTLB_DEMAP /* dmmu flush for KCONTEXT */ + stxa %g0, [%o0]ASI_ITLB_DEMAP /* immu flush for KCONTEXT */ + flush %o3 + b 5f + nop +1: + /* + * User demap. We need to set the primary context properly. + * Secondary context cannot be used for SPARC64-VI IMMU. + * %o0 = vaddr + * %o1 = ctxnum + * %o3 = FLUSH_ADDR + */ + sethi %hi(ctx_pgsz_array), %o4 + ldn [%o4 + %lo(ctx_pgsz_array)], %o4 + ldub [%o4 + %o1], %o4 + sll %o4, CTXREG_EXT_SHIFT, %o4 + or %o1, %o4, %o1 + wrpr %g0, 1, %tl + set MMU_PCONTEXT, %o4 + or DEMAP_PRIMARY | DEMAP_PAGE_TYPE, %o0, %o0 + ldxa [%o4]ASI_DMMU, %o2 /* rd old ctxnum */ + stxa %o1, [%o4]ASI_DMMU /* wr new ctxum */ +4: + stxa %g0, [%o0]ASI_DTLB_DEMAP + stxa %g0, [%o0]ASI_ITLB_DEMAP + stxa %o2, [%o4]ASI_DMMU /* restore old ctxnum */ + flush %o3 + wrpr %g0, 0, %tl +5: + retl + wrpr %g0, %o5, %pstate /* enable interrupts */ + SET_SIZE(vtag_flushpage) + +#endif /* lint */ + + +#if defined(lint) + +/* ARGSUSED */ +void +vtag_flushctx(u_int ctxnum) +{} + +#else /* lint */ + + ENTRY_NP(vtag_flushctx) + /* + * flush context from the tlb + * + * %o0 = ctxnum + * We disable interrupts to prevent the primary ctx register changing + * underneath us. + */ + sethi %hi(FLUSH_ADDR), %o3 + rdpr %pstate, %o2 + +#ifdef DEBUG + andcc %o2, PSTATE_IE, %g0 /* if interrupts already */ + bnz,a,pt %icc, 1f /* disabled, panic */ + nop + sethi %hi(sfmmu_panic1), %o0 + call panic + or %o0, %lo(sfmmu_panic1), %o0 +1: +#endif /* DEBUG */ + + sethi %hi(ctx_pgsz_array), %o4 + ldn [%o4 + %lo(ctx_pgsz_array)], %o4 + ldub [%o4 + %o0], %o4 + sll %o4, CTXREG_EXT_SHIFT, %o4 + or %o0, %o4, %o0 + wrpr %o2, PSTATE_IE, %pstate /* disable interrupts */ + set MMU_PCONTEXT, %o4 + set DEMAP_CTX_TYPE | DEMAP_PRIMARY, %g1 + wrpr %g0, 1, %tl + ldxa [%o4]ASI_DMMU, %o5 /* rd old ctxnum */ + stxa %o0, [%o4]ASI_DMMU /* wr new ctxum */ +4: + stxa %g0, [%g1]ASI_DTLB_DEMAP + stxa %g0, [%g1]ASI_ITLB_DEMAP + stxa %o5, [%o4]ASI_DMMU /* restore old ctxnum */ + flush %o3 + wrpr %g0, 0, %tl +5: + retl + wrpr %g0, %o2, %pstate /* enable interrupts */ + SET_SIZE(vtag_flushctx) + +#endif /* lint */ + + +#if defined(lint) + +void +vtag_flushall(void) +{} + +#else /* lint */ + + ENTRY_NP2(vtag_flushall, demap_all) + /* + * flush the tlb + */ + sethi %hi(FLUSH_ADDR), %o3 + set DEMAP_ALL_TYPE, %g1 + stxa %g0, [%g1]ASI_DTLB_DEMAP + stxa %g0, [%g1]ASI_ITLB_DEMAP + flush %o3 + retl + nop + SET_SIZE(demap_all) + SET_SIZE(vtag_flushall) + +#endif /* lint */ + + +#if defined(lint) + +/* ARGSUSED */ +void +vtag_flushpage_tl1(uint64_t vaddr, uint64_t ctxnum) +{} + +#else /* lint */ + + ENTRY_NP(vtag_flushpage_tl1) + /* + * x-trap to flush page from tlb and tsb + * + * %g1 = vaddr, zero-extended on 32-bit kernel + * %g2 = ctxnum + * + * assumes TSBE_TAG = 0 + */ + srln %g1, MMU_PAGESHIFT, %g1 + brnz,pt %g2, 1f /* KCONTEXT */ + slln %g1, MMU_PAGESHIFT, %g1 /* g1 = vaddr */ + + /* We need to demap in the kernel context */ + or DEMAP_NUCLEUS | DEMAP_PAGE_TYPE, %g1, %g1 + stxa %g0, [%g1]ASI_DTLB_DEMAP + stxa %g0, [%g1]ASI_ITLB_DEMAP + retry +1: + /* We need to demap in a user context */ + or DEMAP_PRIMARY | DEMAP_PAGE_TYPE, %g1, %g1 + sethi %hi(ctx_pgsz_array), %g4 + ldn [%g4 + %lo(ctx_pgsz_array)], %g4 + ldub [%g4 + %g2], %g4 + sll %g4, CTXREG_EXT_SHIFT, %g4 + or %g2, %g4, %g2 + + set MMU_PCONTEXT, %g4 + ldxa [%g4]ASI_DMMU, %g5 /* rd old ctxnum */ + stxa %g2, [%g4]ASI_DMMU /* wr new ctxum */ + stxa %g0, [%g1]ASI_DTLB_DEMAP + stxa %g0, [%g1]ASI_ITLB_DEMAP + stxa %g5, [%g4]ASI_DMMU /* restore old ctxnum */ + retry + SET_SIZE(vtag_flushpage_tl1) + +#endif /* lint */ + +#if defined(lint) + +/* ARGSUSED */ +void +vtag_flush_pgcnt_tl1(uint64_t vaddr, uint64_t ctx_pgcnt) +{} + +#else /* lint */ + + ENTRY_NP(vtag_flush_pgcnt_tl1) + /* + * x-trap to flush pgcnt MMU_PAGESIZE pages from tlb + * + * %g1 = vaddr, zero-extended on 32-bit kernel + * %g2 = <zero32|ctx16|pgcnt16> + * + * NOTE: this handler relies on the fact that no + * interrupts or traps can occur during the loop + * issuing the TLB_DEMAP operations. It is assumed + * that interrupts are disabled and this code is + * fetching from the kernel locked text address. + * + * assumes TSBE_TAG = 0 + */ + set 0xffff, %g4 + and %g4, %g2, %g3 /* g3 = pgcnt */ + srln %g2, 16, %g2 /* g2 = ctxnum */ + srln %g1, MMU_PAGESHIFT, %g1 + brnz,pt %g2, 1f /* KCONTEXT? */ + slln %g1, MMU_PAGESHIFT, %g1 /* g1 = vaddr */ + + /* We need to demap in the kernel context */ + or DEMAP_NUCLEUS | DEMAP_PAGE_TYPE, %g1, %g1 + set MMU_PAGESIZE, %g2 /* g2 = pgsize */ +4: + stxa %g0, [%g1]ASI_DTLB_DEMAP + stxa %g0, [%g1]ASI_ITLB_DEMAP + deccc %g3 /* decr pgcnt */ + bnz,pt %icc,4b + add %g1, %g2, %g1 /* next page */ + retry +1: + /* We need to demap in a user context */ + sethi %hi(ctx_pgsz_array), %g4 + ldn [%g4 + %lo(ctx_pgsz_array)], %g4 + or DEMAP_PRIMARY | DEMAP_PAGE_TYPE, %g1, %g1 + ldub [%g4 + %g2], %g4 + sll %g4, CTXREG_EXT_SHIFT, %g4 + or %g2, %g4, %g2 + + set MMU_PCONTEXT, %g4 + ldxa [%g4]ASI_DMMU, %g5 /* rd old ctxnum */ + stxa %g2, [%g4]ASI_DMMU /* wr new ctxum */ + + set MMU_PAGESIZE, %g2 /* g2 = pgsize */ +3: + stxa %g0, [%g1]ASI_DTLB_DEMAP + stxa %g0, [%g1]ASI_ITLB_DEMAP + deccc %g3 /* decr pgcnt */ + bnz,pt %icc,3b + add %g1, %g2, %g1 /* next page */ + + stxa %g5, [%g4]ASI_DMMU /* restore old ctxnum */ + retry + SET_SIZE(vtag_flush_pgcnt_tl1) + +#endif /* lint */ + + +#if defined(lint) + +/* ARGSUSED */ +void +vtag_flushctx_tl1(uint64_t ctxnum, uint64_t dummy) +{} + +#else /* lint */ + + ENTRY_NP(vtag_flushctx_tl1) + /* + * x-trap to flush context from tlb + * + * %g1 = ctxnum + */ + sethi %hi(ctx_pgsz_array), %g4 + ldn [%g4 + %lo(ctx_pgsz_array)], %g4 + ldub [%g4 + %g1], %g4 + sll %g4, CTXREG_EXT_SHIFT, %g4 + or %g1, %g4, %g1 + set DEMAP_CTX_TYPE | DEMAP_PRIMARY, %g4 + set MMU_PCONTEXT, %g3 + ldxa [%g3]ASI_DMMU, %g5 /* rd old ctxnum */ + stxa %g1, [%g3]ASI_DMMU /* wr new ctxum */ + stxa %g0, [%g4]ASI_DTLB_DEMAP + stxa %g0, [%g4]ASI_ITLB_DEMAP + stxa %g5, [%g3]ASI_DMMU /* restore old ctxnum */ + retry + SET_SIZE(vtag_flushctx_tl1) + +#endif /* lint */ + + +#if defined(lint) + +/*ARGSUSED*/ +void +vtag_flushall_tl1(uint64_t dummy1, uint64_t dummy2) +{} + +#else /* lint */ + + ENTRY_NP(vtag_flushall_tl1) + /* + * x-trap to flush tlb + */ + set DEMAP_ALL_TYPE, %g4 + stxa %g0, [%g4]ASI_DTLB_DEMAP + stxa %g0, [%g4]ASI_ITLB_DEMAP + retry + SET_SIZE(vtag_flushall_tl1) + +#endif /* lint */ + + +/* + * VAC (virtual address conflict) does not apply to OPL. + * VAC resolution is managed by the Olympus processor hardware. + * As a result, all OPL VAC flushing routines are no-ops. + */ + +#if defined(lint) + +/* ARGSUSED */ +void +vac_flushpage(pfn_t pfnum, int vcolor) +{} + +#else /* lint */ + + ENTRY(vac_flushpage) + retl + nop + SET_SIZE(vac_flushpage) + +#endif /* lint */ + +#if defined(lint) + +/* ARGSUSED */ +void +vac_flushpage_tl1(uint64_t pfnum, uint64_t vcolor) +{} + +#else /* lint */ + + ENTRY_NP(vac_flushpage_tl1) + retry + SET_SIZE(vac_flushpage_tl1) + +#endif /* lint */ + + +#if defined(lint) + +/* ARGSUSED */ +void +vac_flushcolor(int vcolor, pfn_t pfnum) +{} + +#else /* lint */ + + ENTRY(vac_flushcolor) + retl + nop + SET_SIZE(vac_flushcolor) + +#endif /* lint */ + + + +#if defined(lint) + +/* ARGSUSED */ +void +vac_flushcolor_tl1(uint64_t vcolor, uint64_t pfnum) +{} + +#else /* lint */ + + ENTRY(vac_flushcolor_tl1) + retry + SET_SIZE(vac_flushcolor_tl1) + +#endif /* lint */ + +#if defined(lint) + +int +idsr_busy(void) +{ + return (0); +} + +#else /* lint */ + +/* + * Determine whether or not the IDSR is busy. + * Entry: no arguments + * Returns: 1 if busy, 0 otherwise + */ + ENTRY(idsr_busy) + ldxa [%g0]ASI_INTR_DISPATCH_STATUS, %g1 + clr %o0 + btst IDSR_BUSY, %g1 + bz,a,pt %xcc, 1f + mov 1, %o0 +1: + retl + nop + SET_SIZE(idsr_busy) + +#endif /* lint */ + +#if defined(lint) + +/* ARGSUSED */ +void +init_mondo(xcfunc_t *func, uint64_t arg1, uint64_t arg2) +{} + +/* ARGSUSED */ +void +init_mondo_nocheck(xcfunc_t *func, uint64_t arg1, uint64_t arg2) +{} + +#else /* lint */ + + .global _dispatch_status_busy +_dispatch_status_busy: + .asciz "ASI_INTR_DISPATCH_STATUS error: busy" + .align 4 + +/* + * Setup interrupt dispatch data registers + * Entry: + * %o0 - function or inumber to call + * %o1, %o2 - arguments (2 uint64_t's) + */ + .seg "text" + + ENTRY(init_mondo) +#ifdef DEBUG + ! + ! IDSR should not be busy at the moment + ! + ldxa [%g0]ASI_INTR_DISPATCH_STATUS, %g1 + btst IDSR_BUSY, %g1 + bz,pt %xcc, 1f + nop + sethi %hi(_dispatch_status_busy), %o0 + call panic + or %o0, %lo(_dispatch_status_busy), %o0 +#endif /* DEBUG */ + + ALTENTRY(init_mondo_nocheck) + ! + ! interrupt vector dispatch data reg 0 + ! +1: + mov IDDR_0, %g1 + mov IDDR_1, %g2 + mov IDDR_2, %g3 + stxa %o0, [%g1]ASI_INTR_DISPATCH + + ! + ! interrupt vector dispatch data reg 1 + ! + stxa %o1, [%g2]ASI_INTR_DISPATCH + + ! + ! interrupt vector dispatch data reg 2 + ! + stxa %o2, [%g3]ASI_INTR_DISPATCH + + membar #Sync + retl + nop + SET_SIZE(init_mondo_nocheck) + SET_SIZE(init_mondo) + +#endif /* lint */ + + +#if defined(lint) + +/* ARGSUSED */ +void +shipit(int upaid, int bn) +{ return; } + +#else /* lint */ + +/* + * Ship mondo to aid using busy/nack pair bn + */ + ENTRY_NP(shipit) + sll %o0, IDCR_PID_SHIFT, %g1 ! IDCR<23:14> = agent id + sll %o1, IDCR_BN_SHIFT, %g2 ! IDCR<28:24> = b/n pair + or %g1, IDCR_OFFSET, %g1 ! IDCR<13:0> = 0x70 + or %g1, %g2, %g1 + stxa %g0, [%g1]ASI_INTR_DISPATCH ! interrupt vector dispatch + membar #Sync + retl + nop + SET_SIZE(shipit) + +#endif /* lint */ + + +#if defined(lint) + +/* ARGSUSED */ +void +flush_instr_mem(caddr_t vaddr, size_t len) +{} + +#else /* lint */ + +/* + * flush_instr_mem: + * Flush 1 page of the I-$ starting at vaddr + * %o0 vaddr + * %o1 bytes to be flushed + * + * SPARC64-VI maintains consistency of the on-chip Instruction Cache with + * the stores from all processors so that a FLUSH instruction is only needed + * to ensure pipeline is consistent. This means a single flush is sufficient at + * the end of a sequence of stores that updates the instruction stream to + * ensure correct operation. + */ + + ENTRY(flush_instr_mem) + flush %o0 ! address irrelevent + retl + nop + SET_SIZE(flush_instr_mem) + +#endif /* lint */ + + +/* + * flush_ecache: + * %o0 - 64 bit physical address + * %o1 - ecache size + * %o2 - ecache linesize + */ +#if defined(lint) + +/*ARGSUSED*/ +void +flush_ecache(uint64_t physaddr, size_t ecache_size, size_t ecache_linesize) +{} + +#else /* !lint */ + + ENTRY(flush_ecache) + + /* + * Flush the entire Ecache. + */ + ECACHE_FLUSHALL(%o1, %o2, %o0, %o4) + retl + nop + SET_SIZE(flush_ecache) + +#endif /* lint */ + +#if defined(lint) + +/*ARGSUSED*/ +void +kdi_flush_idcache(int dcache_size, int dcache_lsize, int icache_size, + int icache_lsize) +{ +} + +#else /* lint */ + + /* + * I/D cache flushing is not needed for OPL processors + */ + ENTRY(kdi_flush_idcache) + retl + nop + SET_SIZE(kdi_flush_idcache) + +#endif /* lint */ + +#ifdef TRAPTRACE +/* + * Simplified trap trace macro for OPL. Adapted from us3. + */ +#define OPL_TRAPTRACE(ptr, scr1, scr2, label) \ + CPU_INDEX(scr1, ptr); \ + sll scr1, TRAPTR_SIZE_SHIFT, scr1; \ + set trap_trace_ctl, ptr; \ + add ptr, scr1, scr1; \ + ld [scr1 + TRAPTR_LIMIT], ptr; \ + tst ptr; \ + be,pn %icc, label/**/1; \ + ldx [scr1 + TRAPTR_PBASE], ptr; \ + ld [scr1 + TRAPTR_OFFSET], scr1; \ + add ptr, scr1, ptr; \ + rd %asi, scr2; \ + wr %g0, TRAPTR_ASI, %asi; \ + rd STICK, scr1; \ + stxa scr1, [ptr + TRAP_ENT_TICK]%asi; \ + rdpr %tl, scr1; \ + stha scr1, [ptr + TRAP_ENT_TL]%asi; \ + rdpr %tt, scr1; \ + stha scr1, [ptr + TRAP_ENT_TT]%asi; \ + rdpr %tpc, scr1; \ + stna scr1, [ptr + TRAP_ENT_TPC]%asi; \ + rdpr %tstate, scr1; \ + stxa scr1, [ptr + TRAP_ENT_TSTATE]%asi; \ + stna %sp, [ptr + TRAP_ENT_SP]%asi; \ + stna %g0, [ptr + TRAP_ENT_TR]%asi; \ + stna %g0, [ptr + TRAP_ENT_F1]%asi; \ + stna %g0, [ptr + TRAP_ENT_F2]%asi; \ + stna %g0, [ptr + TRAP_ENT_F3]%asi; \ + stna %g0, [ptr + TRAP_ENT_F4]%asi; \ + wr %g0, scr2, %asi; \ + CPU_INDEX(ptr, scr1); \ + sll ptr, TRAPTR_SIZE_SHIFT, ptr; \ + set trap_trace_ctl, scr1; \ + add scr1, ptr, ptr; \ + ld [ptr + TRAPTR_OFFSET], scr1; \ + ld [ptr + TRAPTR_LIMIT], scr2; \ + st scr1, [ptr + TRAPTR_LAST_OFFSET]; \ + add scr1, TRAP_ENT_SIZE, scr1; \ + sub scr2, TRAP_ENT_SIZE, scr2; \ + cmp scr1, scr2; \ + movge %icc, 0, scr1; \ + st scr1, [ptr + TRAPTR_OFFSET]; \ +label/**/1: +#endif /* TRAPTRACE */ + + + +/* + * Macros facilitating error handling. + */ + +/* + * Save alternative global registers reg1, reg2, reg3 + * to scratchpad registers 1, 2, 3 respectively. + */ +#define OPL_SAVE_GLOBAL(reg1, reg2, reg3) \ + stxa reg1, [%g0]ASI_SCRATCHPAD ;\ + mov OPL_SCRATCHPAD_SAVE_AG2, reg1 ;\ + stxa reg2, [reg1]ASI_SCRATCHPAD ;\ + mov OPL_SCRATCHPAD_SAVE_AG3, reg1 ;\ + stxa reg3, [reg1]ASI_SCRATCHPAD + +/* + * Restore alternative global registers reg1, reg2, reg3 + * from scratchpad registers 1, 2, 3 respectively. + */ +#define OPL_RESTORE_GLOBAL(reg1, reg2, reg3) \ + mov OPL_SCRATCHPAD_SAVE_AG3, reg1 ;\ + ldxa [reg1]ASI_SCRATCHPAD, reg3 ;\ + mov OPL_SCRATCHPAD_SAVE_AG2, reg1 ;\ + ldxa [reg1]ASI_SCRATCHPAD, reg2 ;\ + ldxa [%g0]ASI_SCRATCHPAD, reg1 + +/* + * Logs value `val' into the member `offset' of a structure + * at physical address `pa' + */ +#define LOG_REG(pa, offset, val) \ + add pa, offset, pa ;\ + stxa val, [pa]ASI_MEM + +#define FLUSH_ALL_TLB(tmp1) \ + set DEMAP_ALL_TYPE, tmp1 ;\ + stxa %g0, [tmp1]ASI_ITLB_DEMAP ;\ + stxa %g0, [tmp1]ASI_DTLB_DEMAP ;\ + sethi %hi(FLUSH_ADDR), tmp1 ;\ + flush tmp1 + +/* + * Extracts the Physaddr to Logging Buffer field of the OPL_SCRATCHPAD_ERRLOG + * scratch register by zeroing all other fields. Result is in pa. + */ +#define LOG_ADDR(pa) \ + mov OPL_SCRATCHPAD_ERRLOG, pa ;\ + ldxa [pa]ASI_SCRATCHPAD, pa ;\ + sllx pa, 64-ERRLOG_REG_EIDR_SHIFT, pa ;\ + srlx pa, 64-ERRLOG_REG_EIDR_SHIFT+ERRLOG_REG_ERR_SHIFT, pa ;\ + sllx pa, ERRLOG_REG_ERR_SHIFT, pa + +/* + * Advance the per-cpu error log buffer pointer to the next + * ERRLOG_SZ entry, making sure that it will modulo (wraparound) + * ERRLOG_BUFSIZ boundary. The args logpa, bufmask, tmp are + * unused input registers for this macro. + * + * Algorithm: + * 1. logpa = contents of errorlog scratchpad register + * 2. bufmask = ERRLOG_BUFSIZ - 1 + * 3. tmp = logpa & ~(bufmask) (tmp is now logbase) + * 4. logpa += ERRLOG_SZ + * 5. logpa = logpa & bufmask (get new offset to logbase) + * 4. logpa = tmp | logpa + * 7. write logpa back into errorlog scratchpad register + * + * new logpa = (logpa & ~bufmask) | ((logpa + ERRLOG_SZ) & bufmask) + * + */ +#define UPDATE_LOGADD(logpa, bufmask, tmp) \ + set OPL_SCRATCHPAD_ERRLOG, tmp ;\ + ldxa [tmp]ASI_SCRATCHPAD, logpa ;\ + set (ERRLOG_BUFSZ-1), bufmask ;\ + andn logpa, bufmask, tmp ;\ + add logpa, ERRLOG_SZ, logpa ;\ + and logpa, bufmask, logpa ;\ + or tmp, logpa, logpa ;\ + set OPL_SCRATCHPAD_ERRLOG, tmp ;\ + stxa logpa, [tmp]ASI_SCRATCHPAD + +/* Log error status registers into the log buffer */ +#define LOG_SYNC_REG(sfsr, sfar, tmp) \ + LOG_ADDR(tmp) ;\ + LOG_REG(tmp, LOG_SFSR_OFF, sfsr) ;\ + LOG_ADDR(tmp) ;\ + mov tmp, sfsr ;\ + LOG_REG(tmp, LOG_SFAR_OFF, sfar) ;\ + rd STICK, sfar ;\ + mov sfsr, tmp ;\ + LOG_REG(tmp, LOG_STICK_OFF, sfar) ;\ + rdpr %tl, tmp ;\ + sllx tmp, 32, sfar ;\ + rdpr %tt, tmp ;\ + or sfar, tmp, sfar ;\ + mov sfsr, tmp ;\ + LOG_REG(tmp, LOG_TL_OFF, sfar) ;\ + set OPL_SCRATCHPAD_ERRLOG, tmp ;\ + ldxa [tmp]ASI_SCRATCHPAD, sfar ;\ + mov sfsr, tmp ;\ + LOG_REG(tmp, LOG_ASI3_OFF, sfar) ;\ + rdpr %tpc, sfar ;\ + mov sfsr, tmp ;\ + LOG_REG(tmp, LOG_TPC_OFF, sfar) ;\ + UPDATE_LOGADD(sfsr, sfar, tmp) + +#define LOG_UGER_REG(uger, tmp, tmp2) \ + LOG_ADDR(tmp) ;\ + mov tmp, tmp2 ;\ + LOG_REG(tmp2, LOG_UGER_OFF, uger) ;\ + mov tmp, uger ;\ + rd STICK, tmp2 ;\ + LOG_REG(tmp, LOG_STICK_OFF, tmp2) ;\ + rdpr %tl, tmp ;\ + sllx tmp, 32, tmp2 ;\ + rdpr %tt, tmp ;\ + or tmp2, tmp, tmp2 ;\ + mov uger, tmp ;\ + LOG_REG(tmp, LOG_TL_OFF, tmp2) ;\ + set OPL_SCRATCHPAD_ERRLOG, tmp2 ;\ + ldxa [tmp2]ASI_SCRATCHPAD, tmp2 ;\ + mov uger, tmp ;\ + LOG_REG(tmp, LOG_ASI3_OFF, tmp2) ;\ + rdpr %tstate, tmp2 ;\ + mov uger, tmp ;\ + LOG_REG(tmp, LOG_TSTATE_OFF, tmp2) ;\ + rdpr %tpc, tmp2 ;\ + mov uger, tmp ;\ + LOG_REG(tmp, LOG_TPC_OFF, tmp2) ;\ + UPDATE_LOGADD(uger, tmp, tmp2) + +/* + * Scrub the STICK_COMPARE register to clear error by updating + * it to a reasonable value for interrupt generation. + * Ensure that we observe the CPU_ENABLE flag so that we + * don't accidentally enable TICK interrupt in STICK_COMPARE + * i.e. no clock interrupt will be generated if CPU_ENABLE flag + * is off. + */ +#define UPDATE_STICK_COMPARE(tmp1, tmp2) \ + CPU_ADDR(tmp1, tmp2) ;\ + lduh [tmp1 + CPU_FLAGS], tmp2 ;\ + andcc tmp2, CPU_ENABLE, %g0 ;\ + set OPL_UGER_STICK_DIFF, tmp2 ;\ + rd STICK, tmp1 ;\ + add tmp1, tmp2, tmp1 ;\ + mov 1, tmp2 ;\ + sllx tmp2, TICKINT_DIS_SHFT, tmp2 ;\ + or tmp1, tmp2, tmp2 ;\ + movnz %xcc, tmp1, tmp2 ;\ + wr tmp2, %g0, STICK_COMPARE + +/* + * Reset registers that may be corrupted by IAUG_CRE error. + * To update interrupt handling related registers force the + * clock interrupt. + */ +#define IAG_CRE(tmp1, tmp2) \ + set OPL_SCRATCHPAD_ERRLOG, tmp1 ;\ + ldxa [tmp1]ASI_SCRATCHPAD, tmp1 ;\ + srlx tmp1, ERRLOG_REG_EIDR_SHIFT, tmp1 ;\ + set ERRLOG_REG_EIDR_MASK, tmp2 ;\ + and tmp1, tmp2, tmp1 ;\ + stxa tmp1, [%g0]ASI_EIDR ;\ + wr %g0, 0, SOFTINT ;\ + sethi %hi(hres_last_tick), tmp1 ;\ + ldx [tmp1 + %lo(hres_last_tick)], tmp1 ;\ + set OPL_UGER_STICK_DIFF, tmp2 ;\ + add tmp1, tmp2, tmp1 ;\ + wr tmp1, %g0, STICK ;\ + UPDATE_STICK_COMPARE(tmp1, tmp2) + + +#define CLEAR_FPREGS(tmp) \ + wr %g0, FPRS_FEF, %fprs ;\ + wr %g0, %g0, %gsr ;\ + sethi %hi(opl_clr_freg), tmp ;\ + or tmp, %lo(opl_clr_freg), tmp ;\ + ldx [tmp], %fsr ;\ + fzero %d0 ;\ + fzero %d2 ;\ + fzero %d4 ;\ + fzero %d6 ;\ + fzero %d8 ;\ + fzero %d10 ;\ + fzero %d12 ;\ + fzero %d14 ;\ + fzero %d16 ;\ + fzero %d18 ;\ + fzero %d20 ;\ + fzero %d22 ;\ + fzero %d24 ;\ + fzero %d26 ;\ + fzero %d28 ;\ + fzero %d30 ;\ + fzero %d32 ;\ + fzero %d34 ;\ + fzero %d36 ;\ + fzero %d38 ;\ + fzero %d40 ;\ + fzero %d42 ;\ + fzero %d44 ;\ + fzero %d46 ;\ + fzero %d48 ;\ + fzero %d50 ;\ + fzero %d52 ;\ + fzero %d54 ;\ + fzero %d56 ;\ + fzero %d58 ;\ + fzero %d60 ;\ + fzero %d62 ;\ + wr %g0, %g0, %fprs + +#define CLEAR_GLOBALS() \ + mov %g0, %g1 ;\ + mov %g0, %g2 ;\ + mov %g0, %g3 ;\ + mov %g0, %g4 ;\ + mov %g0, %g5 ;\ + mov %g0, %g6 ;\ + mov %g0, %g7 + +/* + * We do not clear the alternative globals here because they + * are scratch registers, i.e. there is no code that reads from + * them without write to them firstly. In other words every + * read always follows write that makes extra write to the + * alternative globals unnecessary. + */ +#define CLEAR_GEN_REGS(tmp1, label) \ + set TSTATE_KERN, tmp1 ;\ + wrpr %g0, tmp1, %tstate ;\ + mov %g0, %y ;\ + mov %g0, %asi ;\ + mov %g0, %ccr ;\ + mov %g0, %l0 ;\ + mov %g0, %l1 ;\ + mov %g0, %l2 ;\ + mov %g0, %l3 ;\ + mov %g0, %l4 ;\ + mov %g0, %l5 ;\ + mov %g0, %l6 ;\ + mov %g0, %l7 ;\ + mov %g0, %i0 ;\ + mov %g0, %i1 ;\ + mov %g0, %i2 ;\ + mov %g0, %i3 ;\ + mov %g0, %i4 ;\ + mov %g0, %i5 ;\ + mov %g0, %i6 ;\ + mov %g0, %i7 ;\ + mov %g0, %o1 ;\ + mov %g0, %o2 ;\ + mov %g0, %o3 ;\ + mov %g0, %o4 ;\ + mov %g0, %o5 ;\ + mov %g0, %o6 ;\ + mov %g0, %o7 ;\ + mov %g0, %o0 ;\ + mov %g0, %g4 ;\ + mov %g0, %g5 ;\ + mov %g0, %g6 ;\ + mov %g0, %g7 ;\ + rdpr %tl, tmp1 ;\ + cmp tmp1, 1 ;\ + be,pt %xcc, label/**/1 ;\ + rdpr %pstate, tmp1 ;\ + wrpr tmp1, PSTATE_AG|PSTATE_IG, %pstate ;\ + CLEAR_GLOBALS() ;\ + rdpr %pstate, tmp1 ;\ + wrpr tmp1, PSTATE_IG|PSTATE_MG, %pstate ;\ + CLEAR_GLOBALS() ;\ + rdpr %pstate, tmp1 ;\ + wrpr tmp1, PSTATE_MG|PSTATE_AG, %pstate ;\ + ba,pt %xcc, label/**/2 ;\ + nop ;\ +label/**/1: ;\ + wrpr tmp1, PSTATE_AG, %pstate ;\ + CLEAR_GLOBALS() ;\ + rdpr %pstate, tmp1 ;\ + wrpr tmp1, PSTATE_AG, %pstate ;\ +label/**/2: + + +/* + * Reset all window related registers + */ +#define RESET_WINREG(tmp) \ + sethi %hi(nwin_minus_one), tmp ;\ + ld [tmp + %lo(nwin_minus_one)], tmp ;\ + wrpr %g0, tmp, %cwp ;\ + wrpr %g0, tmp, %cleanwin ;\ + sub tmp, 1, tmp ;\ + wrpr %g0, tmp, %cansave ;\ + wrpr %g0, %g0, %canrestore ;\ + wrpr %g0, %g0, %otherwin ;\ + wrpr %g0, PIL_MAX, %pil ;\ + wrpr %g0, WSTATE_KERN, %wstate + + +#define RESET_PREV_TSTATE(tmp1, tmp2, label) \ + rdpr %tl, tmp1 ;\ + subcc tmp1, 1, tmp1 ;\ + bz,pt %xcc, label/**/1 ;\ + nop ;\ + wrpr tmp1, %g0, %tl ;\ + set TSTATE_KERN, tmp2 ;\ + wrpr tmp2, %g0, %tstate ;\ + wrpr %g0, %g0, %tpc ;\ + wrpr %g0, %g0, %tnpc ;\ + add tmp1, 1, tmp1 ;\ + wrpr tmp1, %g0, %tl ;\ +label/**/1: + + +/* + * %pstate, %pc, %npc are propagated to %tstate, %tpc, %tnpc, + * and we reset these regiseter here. + */ +#define RESET_CUR_TSTATE(tmp) \ + set TSTATE_KERN, tmp ;\ + wrpr %g0, tmp, %tstate ;\ + wrpr %g0, 0, %tpc ;\ + wrpr %g0, 0, %tnpc ;\ + RESET_WINREG(tmp) + +/* + * In case of urgent errors some MMU registers may be + * corrupted, so we set here some reasonable values for + * them. + */ + +#if !defined(lint) +#define RESET_MMU_REGS(tmp1, tmp2, tmp3) \ + set MMU_PCONTEXT, tmp1 ;\ + stxa %g0, [tmp1]ASI_DMMU ;\ + set MMU_SCONTEXT, tmp1 ;\ + stxa %g0, [tmp1]ASI_DMMU ;\ + sethi %hi(ktsb_base), tmp1 ;\ + ldx [tmp1 + %lo(ktsb_base)], tmp2 ;\ + mov MMU_TSB, tmp3 ;\ + stxa tmp2, [tmp3]ASI_IMMU ;\ + stxa tmp2, [tmp3]ASI_DMMU ;\ + membar #Sync + +#define RESET_TSB_TAGPTR(tmp) \ + set MMU_TAG_ACCESS, tmp ;\ + stxa %g0, [tmp]ASI_IMMU ;\ + stxa %g0, [tmp]ASI_DMMU ;\ + membar #Sync +#endif /* lint */ + +/* + * RESET_TO_PRIV() + * + * In many cases, we need to force the thread into privilege mode because + * privilege mode is only thing in which the system continue to work + * due to undeterminable user mode information that come from register + * corruption. + * + * - opl_uger_ctxt + * If the error is secondary TSB related register parity, we have no idea + * what value is supposed to be for it. + * + * The below three cases %tstate is not accessible until it is overwritten + * with some value, so we have no clue if the thread was running on user mode + * or not + * - opl_uger_pstate + * If the error is %pstate parity, it propagates to %tstate. + * - opl_uger_tstate + * No need to say the reason + * - opl_uger_r + * If the error is %ccr or %asi parity, it propagates to %tstate + * + * For the above four cases, user mode info may not be available for + * sys_trap() and user_trap() to work consistently. So we have to force + * the thread into privilege mode. + * + * Forcing the thread to privilege mode requires forcing + * regular %g7 to be CPU_THREAD. Because if it was running on user mode, + * %g7 will be set in user_trap(). Also since the %sp may be in + * an inconsistent state, we need to do a stack reset and switch to + * something we know i.e. current thread's kernel stack. + * We also reset the window registers and MMU registers just to + * make sure. + * + * To set regular %g7, we need to clear PSTATE_AG bit and need to + * use one local register. Note that we are panicking and will never + * unwind back so it is ok to clobber a local. + * + * If the thread was running in user mode, the %tpc value itself might be + * within the range of OBP addresses. %tpc must be forced to be zero to prevent + * sys_trap() from going to prom_trap() + * + */ +#define RESET_TO_PRIV(tmp, tmp1, tmp2, local) \ + RESET_WINREG(tmp) ;\ + RESET_MMU_REGS(tmp, tmp1, tmp2) ;\ + CPU_ADDR(tmp, tmp1) ;\ + ldx [tmp + CPU_THREAD], local ;\ + ldx [local + T_STACK], tmp ;\ + sub tmp, STACK_BIAS, %sp ;\ + rdpr %pstate, tmp ;\ + wrpr tmp, PSTATE_AG, %pstate ;\ + mov local, %g7 ;\ + rdpr %pstate, local ;\ + wrpr local, PSTATE_AG, %pstate ;\ + wrpr %g0, 1, %tl ;\ + set TSTATE_KERN, tmp ;\ + rdpr %cwp, tmp1 ;\ + or tmp, tmp1, tmp ;\ + wrpr tmp, %g0, %tstate ;\ + wrpr %g0, %tpc + + +#if defined(lint) + +void +ce_err(void) +{} + +#else /* lint */ + +/* + * We normally don't expect CE traps since we disable the + * 0x63 trap reporting at the start of day. There is a + * small window before we disable them, so let check for + * it. Otherwise, panic. + */ + + .align 128 + ENTRY_NP(ce_err) + mov AFSR_ECR, %g1 + ldxa [%g1]ASI_ECR, %g1 + andcc %g1, ASI_ECR_RTE_UE | ASI_ECR_RTE_CEDG, %g0 + bz,pn %xcc, 1f + nop + retry +1: + /* + * We did disabled the 0x63 trap reporting. + * This shouldn't happen - panic. + */ + set trap, %g1 + rdpr %tt, %g3 + sethi %hi(sys_trap), %g5 + jmp %g5 + %lo(sys_trap) + sub %g0, 1, %g4 + SET_SIZE(ce_err) + +#endif /* lint */ + + +#if defined(lint) + +void +ce_err_tl1(void) +{} + +#else /* lint */ + +/* + * We don't use trap for CE detection. + */ + ENTRY_NP(ce_err_tl1) + set trap, %g1 + rdpr %tt, %g3 + sethi %hi(sys_trap), %g5 + jmp %g5 + %lo(sys_trap) + sub %g0, 1, %g4 + SET_SIZE(ce_err_tl1) + +#endif /* lint */ + + +#if defined(lint) + +void +async_err(void) +{} + +#else /* lint */ + +/* + * async_err is the default handler for IAE/DAE traps. + * For OPL, we patch in the right handler at start of day. + * But if a IAE/DAE trap get generated before the handler + * is patched, panic. + */ + ENTRY_NP(async_err) + set trap, %g1 + rdpr %tt, %g3 + sethi %hi(sys_trap), %g5 + jmp %g5 + %lo(sys_trap) + sub %g0, 1, %g4 + SET_SIZE(async_err) + +#endif /* lint */ + +#if defined(lint) +void +opl_sync_trap(void) +{} +#else /* lint */ + + .seg ".data" + .global opl_clr_freg + .global opl_cpu0_err_log + + .align 16 +opl_clr_freg: + .word 0 + .align 16 + + .align MMU_PAGESIZE +opl_cpu0_err_log: + .skip MMU_PAGESIZE + +/* + * Common synchronous error trap handler (tt=0xA, 0x32) + * All TL=0 and TL>0 0xA and 0x32 traps vector to this handler. + * The error handling can be best summarized as follows: + * 0. Do TRAPTRACE if enabled. + * 1. Save globals %g1, %g2 & %g3 onto the scratchpad regs. + * 2. The SFSR register is read and verified as valid by checking + * SFSR.FV bit being set. If the SFSR.FV is not set, the + * error cases cannot be decoded/determined and the SFPAR + * register that contain the physical faultaddr is also + * not valid. Also the SPFAR is only valid for UE/TO/BERR error + * cases. Assuming the SFSR.FV is valid: + * - BERR(bus error)/TO(timeout)/UE case + * If any of these error cases are detected, read the SFPAR + * to get the faultaddress. Generate ereport. + * - TLB Parity case (only recoverable case) + * For DAE, read SFAR for the faultaddress. For IAE, + * use %tpc for faultaddress (SFAR is not valid in IAE) + * Flush all the tlbs. + * Subtract one from the recoverable error count stored in + * the error log scratch register. If the threshold limit + * is reached (zero) - generate ereport. Else + * restore globals and retry (no ereport is generated). + * - TLB Multiple hits + * For DAE, read SFAR for the faultaddress. For IAE, + * use %tpc for faultaddress (SFAR is not valid in IAE). + * Flush all tlbs and generate ereport. + * 3. TL=0 and TL>0 considerations + * - Since both TL=0 & TL>1 traps are made to vector into + * the same handler, the underlying assumption/design here is + * that any nested error condition (if happens) occurs only + * in the handler and the system is assumed to eventually + * Red-mode. With this philosophy in mind, the recoverable + * TLB Parity error case never check the TL level before it + * retry. Note that this is ok for the TL>1 case (assuming we + * don't have a nested error) since we always save the globals + * %g1, %g2 & %g3 whenever we enter this trap handler. + * - Additional TL=0 vs TL>1 handling includes: + * - For UE error occuring under TL>1, special handling + * is added to prevent the unlikely chance of a cpu-lockup + * when a UE was originally detected in user stack and + * the spill trap handler taken from sys_trap() so happened + * to reference the same UE location. Under the above + * condition (TL>1 and UE error), paranoid code is added + * to reset window regs so that spill traps can't happen + * during the unwind back to TL=0 handling. + * Note that we can do that because we are not returning + * back. + * 4. Ereport generation. + * - Ereport generation is performed when we unwind to the TL=0 + * handling code via sys_trap(). on_trap()/lofault protection + * will apply there. + * + */ + ENTRY_NP(opl_sync_trap) +#ifdef TRAPTRACE + OPL_TRAPTRACE(%g1, %g2, %g3, opl_sync_trap_lb) + rdpr %tt, %g1 +#endif /* TRAPTRACE */ + cmp %g1, T_INSTR_ERROR + bne,pt %xcc, 0f + mov MMU_SFSR, %g3 + ldxa [%g3]ASI_IMMU, %g1 ! IAE trap case tt = 0xa + andcc %g1, SFSR_FV, %g0 + bz,a,pn %xcc, 2f ! Branch if SFSR is invalid and + rdpr %tpc, %g2 ! use %tpc for faultaddr instead + + sethi %hi(SFSR_UE|SFSR_BERR|SFSR_TO), %g3 + andcc %g1, %g3, %g0 ! Check for UE/BERR/TO errors + bz,a,pt %xcc, 1f ! Branch if not UE/BERR/TO and + rdpr %tpc, %g2 ! use %tpc as faultaddr + set OPL_MMU_SFPAR, %g3 ! In the UE/BERR/TO cases, use + ba,pt %xcc, 2f ! SFPAR as faultaddr + ldxa [%g3]ASI_IMMU, %g2 +0: + ldxa [%g3]ASI_DMMU, %g1 ! DAE trap case tt = 0x32 + andcc %g1, SFSR_FV, %g0 + bnz,pt %xcc, 7f ! branch if SFSR.FV is valid + mov MMU_SFAR, %g2 ! set %g2 to use SFAR + ba,pt %xcc, 2f ! SFSR.FV is not valid, read SFAR + ldxa [%g2]ASI_DMMU, %g2 ! for faultaddr +7: + sethi %hi(SFSR_UE|SFSR_BERR|SFSR_TO), %g3 + andcc %g1, %g3, %g0 ! Check UE/BERR/TO for valid SFPAR + movnz %xcc, OPL_MMU_SFPAR, %g2 ! Use SFPAR instead of SFAR for + ldxa [%g2]ASI_DMMU, %g2 ! faultaddr +1: + sethi %hi(SFSR_TLB_PRT), %g3 + andcc %g1, %g3, %g0 + bz,pt %xcc, 8f ! branch for TLB multi-hit check + nop + /* + * This is the TLB parity error case and it is the + * only retryable error case. + * Only %g1, %g2 and %g3 are allowed + */ + FLUSH_ALL_TLB(%g3) + set OPL_SCRATCHPAD_ERRLOG, %g3 + ldxa [%g3]ASI_SCRATCHPAD, %g3 ! Read errlog scratchreg + and %g3, ERRLOG_REG_NUMERR_MASK, %g3! Extract the error count + subcc %g3, 1, %g0 ! Subtract one from the count + bz,pn %xcc, 2f ! too many TLB parity errs in a certain + nop ! period, branch to generate ereport + LOG_SYNC_REG(%g1, %g2, %g3) ! Record into the error log + set OPL_SCRATCHPAD_ERRLOG, %g3 + ldxa [%g3]ASI_SCRATCHPAD, %g2 + sub %g2, 1, %g2 ! decrement error counter by 1 + stxa %g2, [%g3]ASI_SCRATCHPAD ! update the errlog scratchreg + OPL_RESTORE_GLOBAL(%g1, %g2, %g3) + retry +8: + sethi %hi(SFSR_TLB_MUL), %g3 + andcc %g1, %g3, %g0 + bz,pt %xcc, 2f ! check for the TLB multi-hit errors + nop + FLUSH_ALL_TLB(%g3) +2: + /* + * non-retryable error handling + * now we can use other registers since + * we will not be returning back + */ + mov %g1, %g5 ! %g5 = SFSR + mov %g2, %g6 ! %g6 = SFPAR or SFAR/tpc + LOG_SYNC_REG(%g1, %g2, %g3) ! Record into the error log + + /* + * Special case for UE on user stack. + * There is a possibility that the same error may come back here + * by touching the same UE in spill trap handler taken from + * sys_trap(). It ends up with an infinite loop causing a cpu lockup. + * Conditions for this handling this case are: + * - SFSR_FV is valid and SFSR_UE is set + * - we are at TL > 1 + * If the above conditions are true, we force %cansave to be a + * big number to prevent spill trap in sys_trap(). Note that + * we will not be returning back. + */ + rdpr %tt, %g4 ! %g4 == ttype + rdpr %tl, %g1 ! %g1 == tl + cmp %g1, 1 ! Check if TL == 1 + be,pt %xcc, 3f ! branch if we came from TL=0 + nop + andcc %g5, SFSR_FV, %g0 ! see if SFSR.FV is valid + bz,pn %xcc, 4f ! branch, checking UE is meaningless + sethi %hi(SFSR_UE), %g2 + andcc %g5, %g2, %g0 ! check for UE + bz,pt %xcc, 4f ! branch if not UE + nop + RESET_WINREG(%g1) ! reset windows to prevent spills +4: + mov %g5, %g3 ! pass SFSR to the 3rd arg + mov %g6, %g2 ! pass SFAR to the 2nd arg + set opl_cpu_isync_tl1_error, %g1 + set opl_cpu_dsync_tl1_error, %g6 + cmp %g4, T_INSTR_ERROR + movne %icc, %g6, %g1 + ba,pt %icc, 6f + nop +3: + mov %g5, %g3 ! pass SFSR to the 3rd arg + mov %g6, %g2 ! pass SFAR to the 2nd arg + set opl_cpu_isync_tl0_error, %g1 + set opl_cpu_dsync_tl0_error, %g6 + cmp %g4, T_INSTR_ERROR + movne %icc, %g6, %g1 +6: + sethi %hi(sys_trap), %g5 + jmp %g5 + %lo(sys_trap) + mov PIL_15, %g4 + SET_SIZE(opl_sync_trap) +#endif /* lint */ + +#if defined(lint) +void +opl_uger_trap(void) +{} +#else /* lint */ +/* + * Common Urgent error trap handler (tt=0x40) + * All TL=0 and TL>0 0x40 traps vector to this handler. + * The error handling can be best summarized as follows: + * 1. Read the Urgent error status register (UGERSR) + * Faultaddress is N/A here and it is not collected. + * 2. Check to see if we have a multiple errors case + * If so, we enable WEAK_ED (weak error detection) bit + * to prevent any potential error storms and branch directly + * to generate ereport. (we don't decode/handle individual + * error cases when we get a multiple error situation) + * 3. Now look for the recoverable error cases which include + * IUG_DTLB, IUG_ITLB or COREERR errors. If any of the + * recoverable errors are detected, do the following: + * - Flush all tlbs. + * - Verify that we came from TL=0, if not, generate + * ereport. Note that the reason we don't recover + * at TL>0 is because the AGs might be corrupted or + * inconsistent. We can't save/restore them into + * the scratchpad regs like we did for opl_sync_trap(). + * - Check the INSTEND[5:4] bits in the UGERSR. If the + * value is 0x3 (11b), this error is not recoverable. + * Generate ereport. + * - Subtract one from the recoverable error count stored in + * the error log scratch register. If the threshold limit + * is reached (zero) - generate ereport. + * - If the count is within the limit, update the count + * in the error log register (subtract one). Log the error + * info in the log buffer. Capture traptrace if enabled. + * Retry (no ereport generated) + * 4. The rest of the error cases are unrecoverable and will + * be handled according (flushing regs, etc as required). + * For details on these error cases (UGER_CRE, UGER_CTXT, etc..) + * consult the OPL cpu/mem philosophy doc. + * Ereport will be generated for these errors. + * 5. Ereport generation. + * - Ereport generation for urgent error trap always + * result in a panic when we unwind to the TL=0 handling + * code via sys_trap(). on_trap()/lofault protection do + * not apply there. + */ + ENTRY_NP(opl_uger_trap) + set ASI_UGERSR, %g2 + ldxa [%g2]ASI_AFSR, %g1 ! Read the UGERSR reg + + set UGESR_MULTI, %g2 + andcc %g1, %g2, %g0 ! Check for Multi-errs + bz,pt %xcc, opl_uger_is_recover ! branch if not Multi-errs + nop + set AFSR_ECR, %g2 + ldxa [%g2]ASI_AFSR, %g3 ! Enable Weak error + or %g3, ASI_ECR_WEAK_ED, %g3 ! detect mode to prevent + stxa %g3, [%g2]ASI_AFSR ! potential error storms + ba %xcc, opl_uger_panic1 + nop + +opl_uger_is_recover: + set UGESR_CAN_RECOVER, %g2 ! Check for recoverable + andcc %g1, %g2, %g0 ! errors i.e.IUG_DTLB, + bz,pt %xcc, opl_uger_cre ! IUG_ITLB or COREERR + nop + + /* + * Fall thru to handle recoverable case + * Need to do the following additional checks to determine + * if this is indeed recoverable. + * 1. Error trap came from TL=0 and + * 2. INSTEND[5:4] bits in UGERSR is not 0x3 + * 3. Recoverable error count limit not reached + * + */ + FLUSH_ALL_TLB(%g3) + rdpr %tl, %g3 ! Read TL + cmp %g3, 1 ! Check if we came from TL=0 + bne,pt %xcc, opl_uger_panic ! branch if came from TL>0 + nop + srlx %g1, 4, %g2 ! shift INSTEND[5:4] -> [1:0] + and %g2, 3, %g2 ! extract the shifted [1:0] bits + cmp %g2, 3 ! check if INSTEND is recoverable + be,pt %xcc, opl_uger_panic ! panic if ([1:0] = 11b) + nop + set OPL_SCRATCHPAD_ERRLOG, %g3 + ldxa [%g3]ASI_SCRATCHPAD, %g2 ! Read errlog scratch reg + and %g2, ERRLOG_REG_NUMERR_MASK, %g3! Extract error count and + subcc %g3, 1, %g3 ! subtract one from it + bz,pt %xcc, opl_uger_panic ! If count reached zero, too many + nop ! errors, branch to generate ereport + sub %g2, 1, %g2 ! Subtract one from the count + set OPL_SCRATCHPAD_ERRLOG, %g3 ! and write back the updated + stxa %g2, [%g3]ASI_SCRATCHPAD ! count into the errlog reg + LOG_UGER_REG(%g1, %g2, %g3) ! Log the error info +#ifdef TRAPTRACE + OPL_TRAPTRACE(%g1, %g2, %g3, opl_uger_trap_lb) +#endif /* TRAPTRACE */ + retry ! retry - no ereport + + /* + * Process the rest of the unrecoverable error cases + * All error cases below ultimately branch to either + * opl_uger_panic or opl_uger_panic1. + * opl_uger_panic1 is the same as opl_uger_panic except + * for the additional execution of the RESET_TO_PRIV() + * macro that does a heavy handed reset. Read the + * comments for RESET_TO_PRIV() macro for more info. + */ +opl_uger_cre: + set UGESR_IAUG_CRE, %g2 + andcc %g1, %g2, %g0 + bz,pt %xcc, opl_uger_ctxt + nop + IAG_CRE(%g2, %g3) + set AFSR_ECR, %g2 + ldxa [%g2]ASI_AFSR, %g3 + or %g3, ASI_ECR_WEAK_ED, %g3 + stxa %g3, [%g2]ASI_AFSR + ba %xcc, opl_uger_panic + nop + +opl_uger_ctxt: + set UGESR_IAUG_TSBCTXT, %g2 + andcc %g1, %g2, %g0 + bz,pt %xcc, opl_uger_tsbp + nop + RESET_MMU_REGS(%g2, %g3, %g4) + ba %xcc, opl_uger_panic + nop + +opl_uger_tsbp: + set UGESR_IUG_TSBP, %g2 + andcc %g1, %g2, %g0 + bz,pt %xcc, opl_uger_pstate + nop + RESET_TSB_TAGPTR(%g2) + ba %xcc, opl_uger_panic + nop + +opl_uger_pstate: + set UGESR_IUG_PSTATE, %g2 + andcc %g1, %g2, %g0 + bz,pt %xcc, opl_uger_tstate + nop + RESET_CUR_TSTATE(%g2) + ba %xcc, opl_uger_panic1 + nop + +opl_uger_tstate: + set UGESR_IUG_TSTATE, %g2 + andcc %g1, %g2, %g0 + bz,pt %xcc, opl_uger_f + nop + RESET_PREV_TSTATE(%g2, %g3, opl_uger_tstate_1) + ba %xcc, opl_uger_panic1 + nop + +opl_uger_f: + set UGESR_IUG_F, %g2 + andcc %g1, %g2, %g0 + bz,pt %xcc, opl_uger_r + nop + CLEAR_FPREGS(%g2) + ba %xcc, opl_uger_panic + nop + +opl_uger_r: + set UGESR_IUG_R, %g2 + andcc %g1, %g2, %g0 + bz,pt %xcc, opl_uger_panic1 + nop + CLEAR_GEN_REGS(%g2, opl_uger_r_1) + ba %xcc, opl_uger_panic1 + nop + +opl_uger_panic: + mov %g1, %g2 ! %g2 = arg #1 + LOG_UGER_REG(%g1, %g3, %g4) + ba %xcc, opl_uger_panic_cmn + nop + +opl_uger_panic1: + mov %g1, %g2 ! %g2 = arg #1 + LOG_UGER_REG(%g1, %g3, %g4) + RESET_TO_PRIV(%g1, %g3, %g4, %l0) + + /* + * Set up the argument for sys_trap. + * %g2 = arg #1 already set above + */ +opl_uger_panic_cmn: + rdpr %tl, %g3 ! arg #2 + set opl_cpu_urgent_error, %g1 ! pc + sethi %hi(sys_trap), %g5 + jmp %g5 + %lo(sys_trap) + mov PIL_15, %g4 + SET_SIZE(opl_uger_trap) +#endif /* lint */ + +#if defined(lint) + +void +opl_serr_instr(void) +{} + +#else /* lint */ +/* + * The actual trap handler for tt=0x0a, and tt=0x32 + */ + ENTRY_NP(opl_serr_instr) + OPL_SAVE_GLOBAL(%g1,%g2,%g3) + sethi %hi(opl_sync_trap), %g3 + jmp %g3 + %lo(opl_sync_trap) + rdpr %tt, %g1 + .align 32 + SET_SIZE(opl_serr_instr) + +#endif /* lint */ + +#if defined(lint) + +void +opl_ugerr_instr(void) +{} + +#else /* lint */ +/* + * The actual trap handler for tt=0x40 + */ + ENTRY_NP(opl_ugerr_instr) + sethi %hi(opl_uger_trap), %g3 + jmp %g3 + %lo(opl_uger_trap) + nop + .align 32 + SET_SIZE(opl_ugerr_instr) + +#endif /* lint */ + +#if defined(lint) +/* + * Get timestamp (stick). + */ +/* ARGSUSED */ +void +stick_timestamp(int64_t *ts) +{ +} + +#else /* lint */ + + ENTRY_NP(stick_timestamp) + rd STICK, %g1 ! read stick reg + sllx %g1, 1, %g1 + srlx %g1, 1, %g1 ! clear npt bit + + retl + stx %g1, [%o0] ! store the timestamp + SET_SIZE(stick_timestamp) + +#endif /* lint */ + + +#if defined(lint) +/* + * Set STICK adjusted by skew. + */ +/* ARGSUSED */ +void +stick_adj(int64_t skew) +{ +} + +#else /* lint */ + + ENTRY_NP(stick_adj) + rdpr %pstate, %g1 ! save processor state + andn %g1, PSTATE_IE, %g3 + ba 1f ! cache align stick adj + wrpr %g0, %g3, %pstate ! turn off interrupts + + .align 16 +1: nop + + rd STICK, %g4 ! read stick reg + add %g4, %o0, %o1 ! adjust stick with skew + wr %o1, %g0, STICK ! write stick reg + + retl + wrpr %g1, %pstate ! restore processor state + SET_SIZE(stick_adj) + +#endif /* lint */ + +#if defined(lint) +/* + * Debugger-specific stick retrieval + */ +/*ARGSUSED*/ +int +kdi_get_stick(uint64_t *stickp) +{ + return (0); +} + +#else /* lint */ + + ENTRY_NP(kdi_get_stick) + rd STICK, %g1 + stx %g1, [%o0] + retl + mov %g0, %o0 + SET_SIZE(kdi_get_stick) + +#endif /* lint */ + +#if defined(lint) + +/*ARGSUSED*/ +int +dtrace_blksuword32(uintptr_t addr, uint32_t *data, int tryagain) +{ return (0); } + +#else + + ENTRY(dtrace_blksuword32) + save %sp, -SA(MINFRAME + 4), %sp + + rdpr %pstate, %l1 + andn %l1, PSTATE_IE, %l2 ! disable interrupts to + wrpr %g0, %l2, %pstate ! protect our FPU diddling + + rd %fprs, %l0 + andcc %l0, FPRS_FEF, %g0 + bz,a,pt %xcc, 1f ! if the fpu is disabled + wr %g0, FPRS_FEF, %fprs ! ... enable the fpu + + st %f0, [%fp + STACK_BIAS - 4] ! save %f0 to the stack +1: + set 0f, %l5 + /* + * We're about to write a block full or either total garbage + * (not kernel data, don't worry) or user floating-point data + * (so it only _looks_ like garbage). + */ + ld [%i1], %f0 ! modify the block + membar #Sync + stn %l5, [THREAD_REG + T_LOFAULT] ! set up the lofault handler + stda %d0, [%i0]ASI_BLK_COMMIT_S ! store the modified block + membar #Sync + stn %g0, [THREAD_REG + T_LOFAULT] ! remove the lofault handler + + bz,a,pt %xcc, 1f + wr %g0, %l0, %fprs ! restore %fprs + + ld [%fp + STACK_BIAS - 4], %f0 ! restore %f0 +1: + + wrpr %g0, %l1, %pstate ! restore interrupts + + ret + restore %g0, %g0, %o0 + +0: + membar #Sync + stn %g0, [THREAD_REG + T_LOFAULT] ! remove the lofault handler + + bz,a,pt %xcc, 1f + wr %g0, %l0, %fprs ! restore %fprs + + ld [%fp + STACK_BIAS - 4], %f0 ! restore %f0 +1: + + wrpr %g0, %l1, %pstate ! restore interrupts + + /* + * If tryagain is set (%i2) we tail-call dtrace_blksuword32_err() + * which deals with watchpoints. Otherwise, just return -1. + */ + brnz,pt %i2, 1f + nop + ret + restore %g0, -1, %o0 +1: + call dtrace_blksuword32_err + restore + + SET_SIZE(dtrace_blksuword32) +#endif /* lint */ + +#if defined(lint) +/*ARGSUSED*/ +void +ras_cntr_reset(void *arg) +{ +} +#else + ENTRY_NP(ras_cntr_reset) + set OPL_SCRATCHPAD_ERRLOG, %o1 + ldxa [%o1]ASI_SCRATCHPAD, %o0 + or %o0, ERRLOG_REG_NUMERR_MASK, %o0 + retl + stxa %o0, [%o1]ASI_SCRATCHPAD + SET_SIZE(ras_cntr_reset) +#endif /* lint */ + +#if defined(lint) +/* ARGSUSED */ +void +opl_error_setup(uint64_t cpu_err_log_pa) +{ +} + +#else /* lint */ + ENTRY_NP(opl_error_setup) + /* + * Initialize the error log scratchpad register + */ + ldxa [%g0]ASI_EIDR, %o2 + sethi %hi(ERRLOG_REG_EIDR_MASK), %o1 + or %o1, %lo(ERRLOG_REG_EIDR_MASK), %o1 + and %o2, %o1, %o3 + sllx %o3, ERRLOG_REG_EIDR_SHIFT, %o2 + or %o2, %o0, %o3 + or %o3, ERRLOG_REG_NUMERR_MASK, %o0 + set OPL_SCRATCHPAD_ERRLOG, %o1 + stxa %o0, [%o1]ASI_SCRATCHPAD + /* + * Disable all restrainable error traps + */ + mov AFSR_ECR, %o1 + ldxa [%o1]ASI_AFSR, %o0 + andn %o0, ASI_ECR_RTE_UE|ASI_ECR_RTE_CEDG, %o0 + retl + stxa %o0, [%o1]ASI_AFSR + SET_SIZE(opl_error_setup) +#endif /* lint */ + +#if defined(lint) +/* ARGSUSED */ +void +opl_mpg_enable(void) +{ +} +#else /* lint */ + ENTRY_NP(opl_mpg_enable) + /* + * Enable MMU translating multiple page sizes for + * sITLB and sDTLB. + */ + mov LSU_MCNTL, %o0 + ldxa [%o0] ASI_MCNTL, %o1 + or %o1, MCNTL_MPG_SITLB | MCNTL_MPG_SDTLB, %o1 + retl + stxa %o1, [%o0] ASI_MCNTL + SET_SIZE(opl_mpg_enable) +#endif /* lint */ + +#if defined(lint) +/* + * This function is called for each (enabled) CPU. We use it to + * initialize error handling related registers. + */ +/*ARGSUSED*/ +void +cpu_feature_init(void) +{} +#else /* lint */ + ENTRY(cpu_feature_init) + ! + ! get the device_id and store the device_id + ! in the appropriate cpunodes structure + ! given the cpus index + ! + CPU_INDEX(%o0, %o1) + mulx %o0, CPU_NODE_SIZE, %o0 + set cpunodes + DEVICE_ID, %o1 + ldxa [%g0] ASI_DEVICE_SERIAL_ID, %o2 + stx %o2, [%o0 + %o1] + ! + ! initialize CPU registers + ! + ba opl_cpu_reg_init + nop + SET_SIZE(cpu_feature_init) +#endif /* lint */ + +#if defined(lint) + +void +cpu_cleartickpnt(void) +{} + +#else /* lint */ + /* + * Clear the NPT (non-privileged trap) bit in the %tick/%stick + * registers. In an effort to make the change in the + * tick/stick counter as consistent as possible, we disable + * all interrupts while we're changing the registers. We also + * ensure that the read and write instructions are in the same + * line in the instruction cache. + */ + ENTRY_NP(cpu_clearticknpt) + rdpr %pstate, %g1 /* save processor state */ + andn %g1, PSTATE_IE, %g3 /* turn off */ + wrpr %g0, %g3, %pstate /* interrupts */ + rdpr %tick, %g2 /* get tick register */ + brgez,pn %g2, 1f /* if NPT bit off, we're done */ + mov 1, %g3 /* create mask */ + sllx %g3, 63, %g3 /* for NPT bit */ + ba,a,pt %xcc, 2f + .align 8 /* Ensure rd/wr in same i$ line */ +2: + rdpr %tick, %g2 /* get tick register */ + wrpr %g3, %g2, %tick /* write tick register, */ + /* clearing NPT bit */ +1: + rd STICK, %g2 /* get stick register */ + brgez,pn %g2, 3f /* if NPT bit off, we're done */ + mov 1, %g3 /* create mask */ + sllx %g3, 63, %g3 /* for NPT bit */ + ba,a,pt %xcc, 4f + .align 8 /* Ensure rd/wr in same i$ line */ +4: + rd STICK, %g2 /* get stick register */ + wr %g3, %g2, STICK /* write stick register, */ + /* clearing NPT bit */ +3: + jmp %g4 + 4 + wrpr %g0, %g1, %pstate /* restore processor state */ + + SET_SIZE(cpu_clearticknpt) + +#endif /* lint */ + +#if defined(lint) + +void +cpu_halt_cpu(void) +{} + +void +cpu_smt_pause(void) +{} + +#else /* lint */ + + /* + * Halt the current strand with the suspend instruction. + * The compiler/asm currently does not support this suspend + * instruction mnemonic, use byte code for now. + */ + ENTRY_NP(cpu_halt_cpu) + .word 0x81b01040 + retl + nop + SET_SIZE(cpu_halt_cpu) + + /* + * Pause the current strand with the sleep instruction. + * The compiler/asm currently does not support this sleep + * instruction mnemonic, use byte code for now. + */ + ENTRY_NP(cpu_smt_pause) + .word 0x81b01060 + retl + nop + SET_SIZE(cpu_smt_pause) + +#endif /* lint */ diff --git a/usr/src/uts/sun4u/cpu/opl_olympus_copy.s b/usr/src/uts/sun4u/cpu/opl_olympus_copy.s new file mode 100644 index 0000000000..6918980941 --- /dev/null +++ b/usr/src/uts/sun4u/cpu/opl_olympus_copy.s @@ -0,0 +1,3716 @@ +/* + * 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 <sys/param.h> +#include <sys/errno.h> +#include <sys/asm_linkage.h> +#include <sys/vtrace.h> +#include <sys/machthread.h> +#include <sys/clock.h> +#include <sys/asi.h> +#include <sys/fsr.h> +#include <sys/privregs.h> + +#if !defined(lint) +#include "assym.h" +#endif /* lint */ + +/* + * Pseudo-code to aid in understanding the control flow of the + * bcopy/copyin/copyout routines. + * + * On entry: + * + * ! Determine whether to use the FP register version + * ! or the leaf routine version depending on size + * ! of copy and flags. Set up error handling accordingly. + * ! The transition point depends on whether the src and + * ! dst addresses can be aligned to long word, word, + * ! half word, or byte boundaries. + * ! + * ! WARNING: <Register usage convention> + * ! For FP version, %l6 holds previous error handling and + * ! a flag: TRAMP_FLAG (low bits) + * ! for leaf routine version, %o4 holds those values. + * ! So either %l6 or %o4 is reserved and not available for + * ! any other use. + * + * if (length <= VIS_COPY_THRESHOLD) ! start with a quick test + * go to small_copy; ! to speed short copies + * + * ! src, dst long word alignable + * if (hw_copy_limit_8 == 0) ! hw_copy disabled + * go to small_copy; + * if (length <= hw_copy_limit_8) + * go to small_copy; + * go to FPBLK_copy; + * } + * if (src,dst not alignable) { + * if (hw_copy_limit_1 == 0) ! hw_copy disabled + * go to small_copy; + * if (length <= hw_copy_limit_1) + * go to small_copy; + * go to FPBLK_copy; + * } + * if (src,dst halfword alignable) { + * if (hw_copy_limit_2 == 0) ! hw_copy disabled + * go to small_copy; + * if (length <= hw_copy_limit_2) + * go to small_copy; + * go to FPBLK_copy; + * } + * if (src,dst word alignable) { + * if (hw_copy_limit_4 == 0) ! hw_copy disabled + * go to small_copy; + * if (length <= hw_copy_limit_4) + * go to small_copy; + * go to FPBLK_copy; + * } + * + * small_copy: + * Setup_leaf_rtn_error_handler; ! diffs for each entry point + * + * if (count <= 3) ! fast path for tiny copies + * go to sm_left; ! special finish up code + * else + * if (count > CHKSIZE) ! medium sized copies + * go to sm_med ! tuned by alignment + * if(src&dst not both word aligned) { + * sm_movebytes: + * move byte by byte in 4-way unrolled loop + * fall into sm_left; + * sm_left: + * move 0-3 bytes byte at a time as needed. + * restore error handler and exit. + * + * } else { ! src&dst are word aligned + * check for at least 8 bytes left, + * move word at a time, unrolled by 2 + * when fewer than 8 bytes left, + * sm_half: move half word at a time while 2 or more bytes left + * sm_byte: move final byte if necessary + * sm_exit: + * restore error handler and exit. + * } + * + * ! Medium length cases with at least CHKSIZE bytes available + * ! method: line up src and dst as best possible, then + * ! move data in 4-way unrolled loops. + * + * sm_med: + * if(src&dst unalignable) + * go to sm_movebytes + * if(src&dst halfword alignable) + * go to sm_movehalf + * if(src&dst word alignable) + * go to sm_moveword + * ! fall into long word movement + * move bytes until src is word aligned + * if not long word aligned, move a word + * move long words in 4-way unrolled loop until < 32 bytes left + * move long words in 1-way unrolled loop until < 8 bytes left + * if zero bytes left, goto sm_exit + * if one byte left, go to sm_byte + * else go to sm_half + * + * sm_moveword: + * move bytes until src is word aligned + * move words in 4-way unrolled loop until < 16 bytes left + * move words in 1-way unrolled loop until < 4 bytes left + * if zero bytes left, goto sm_exit + * if one byte left, go to sm_byte + * else go to sm_half + * + * sm_movehalf: + * move a byte if needed to align src on halfword + * move halfwords in 4-way unrolled loop until < 8 bytes left + * if zero bytes left, goto sm_exit + * if one byte left, go to sm_byte + * else go to sm_half + * + * + * FPBLK_copy: + * %l6 = curthread->t_lofault; + * if (%l6 != NULL) { + * membar #Sync + * curthread->t_lofault = .copyerr; + * caller_error_handler = TRUE ! %l6 |= 2 + * } + * + * ! for FPU testing we must not migrate cpus + * if (curthread->t_lwp == NULL) { + * ! Kernel threads do not have pcb's in which to store + * ! the floating point state, so disallow preemption during + * ! the copy. This also prevents cpu migration. + * kpreempt_disable(curthread); + * } else { + * thread_nomigrate(); + * } + * + * old_fprs = %fprs; + * old_gsr = %gsr; + * if (%fprs.fef) { + * %fprs.fef = 1; + * save current fpregs on stack using blockstore + * } else { + * %fprs.fef = 1; + * } + * + * + * do_blockcopy_here; + * + * In lofault handler: + * curthread->t_lofault = .copyerr2; + * Continue on with the normal exit handler + * + * On normal exit: + * %gsr = old_gsr; + * if (old_fprs & FPRS_FEF) + * restore fpregs from stack using blockload + * else + * zero fpregs + * %fprs = old_fprs; + * membar #Sync + * curthread->t_lofault = (%l6 & ~3); + * ! following test omitted from copyin/copyout as they + * ! will always have a current thread + * if (curthread->t_lwp == NULL) + * kpreempt_enable(curthread); + * else + * thread_allowmigrate(); + * return (0) + * + * In second lofault handler (.copyerr2): + * We've tried to restore fp state from the stack and failed. To + * prevent from returning with a corrupted fp state, we will panic. + */ + +/* + * Comments about optimization choices + * + * The initial optimization decision in this code is to determine + * whether to use the FP registers for a copy or not. If we don't + * use the FP registers, we can execute the copy as a leaf routine, + * saving a register save and restore. Also, less elaborate setup + * is required, allowing short copies to be completed more quickly. + * For longer copies, especially unaligned ones (where the src and + * dst do not align to allow simple ldx,stx operation), the FP + * registers allow much faster copy operations. + * + * The estimated extra cost of the FP path will vary depending on + * src/dst alignment, dst offset from the next 64 byte FPblock store + * boundary, remaining src data after the last full dst cache line is + * moved whether the FP registers need to be saved, and some other + * minor issues. The average additional overhead is estimated to be + * 400 clocks. Since each non-repeated/predicted tst and branch costs + * around 10 clocks, elaborate calculation would slow down to all + * longer copies and only benefit a small portion of medium sized + * copies. Rather than incur such cost, we chose fixed transition + * points for each of the alignment choices. + * + * For the inner loop, here is a comparison of the per cache line + * costs for each alignment when src&dst are in cache: + * + * byte aligned: 108 clocks slower for non-FPBLK + * half aligned: 44 clocks slower for non-FPBLK + * word aligned: 12 clocks slower for non-FPBLK + * long aligned: 4 clocks >>faster<< for non-FPBLK + * + * The long aligned loop runs faster because it does no prefetching. + * That wins if the data is not in cache or there is too little + * data to gain much benefit from prefetching. But when there + * is more data and that data is not in cache, failing to prefetch + * can run much slower. In addition, there is a 2 Kbyte store queue + * which will cause the non-FPBLK inner loop to slow for larger copies. + * The exact tradeoff is strongly load and application dependent, with + * increasing risk of a customer visible performance regression if the + * non-FPBLK code is used for larger copies. Studies of synthetic in-cache + * vs out-of-cache copy tests in user space suggest 1024 bytes as a safe + * upper limit for the non-FPBLK code. To minimize performance regression + * risk while still gaining the primary benefits of the improvements to + * the non-FPBLK code, we set an upper bound of 1024 bytes for the various + * hw_copy_limit_*. Later experimental studies using different values + * of hw_copy_limit_* can be used to make further adjustments if + * appropriate. + * + * hw_copy_limit_1 = src and dst are byte aligned but not halfword aligned + * hw_copy_limit_2 = src and dst are halfword aligned but not word aligned + * hw_copy_limit_4 = src and dst are word aligned but not longword aligned + * hw_copy_limit_8 = src and dst are longword aligned + * + * To say that src and dst are word aligned means that after + * some initial alignment activity of moving 0 to 3 bytes, + * both the src and dst will be on word boundaries so that + * word loads and stores may be used. + * + * Default values at May,2005 are: + * hw_copy_limit_1 = 256 + * hw_copy_limit_2 = 512 + * hw_copy_limit_4 = 1024 + * hw_copy_limit_8 = 1024 (or 1536 on some systems) + * + * + * If hw_copy_limit_? is set to zero, then use of FPBLK copy is + * disabled for that alignment choice. + * If hw_copy_limit_? is set to a value between 1 and VIS_COPY_THRESHOLD (256) + * the value of VIS_COPY_THRESHOLD is used. + * It is not envisioned that hw_copy_limit_? will be changed in the field + * It is provided to allow for disabling FPBLK copies and to allow + * easy testing of alternate values on future HW implementations + * that might have different cache sizes, clock rates or instruction + * timing rules. + * + * Our first test for FPBLK copies vs non-FPBLK copies checks a minimum + * threshold to speedup all shorter copies (less than 256). That + * saves an alignment test, memory reference, and enabling test + * for all short copies, or an estimated 24 clocks. + * + * The order in which these limits are checked does matter since each + * non-predicted tst and branch costs around 10 clocks. + * If src and dst are randomly selected addresses, + * 4 of 8 will not be alignable. + * 2 of 8 will be half word alignable. + * 1 of 8 will be word alignable. + * 1 of 8 will be long word alignable. + * But, tests on running kernels show that src and dst to copy code + * are typically not on random alignments. Structure copies and + * copies of larger data sizes are often on long word boundaries. + * So we test the long word alignment case first, then + * the byte alignment, then halfword, then word alignment. + * + * Several times, tests for length are made to split the code + * into subcases. These tests often allow later tests to be + * avoided. For example, within the non-FPBLK copy, we first + * check for tiny copies of 3 bytes or less. That allows us + * to use a 4-way unrolled loop for the general byte copy case + * without a test on loop entry. + * We subdivide the non-FPBLK case further into CHKSIZE bytes and less + * vs longer cases. For the really short case, we don't attempt + * align src and dst. We try to minimize special case tests in + * the shortest loops as each test adds a significant percentage + * to the total time. + * + * For the medium sized cases, we allow ourselves to adjust the + * src and dst alignment and provide special cases for each of + * the four adjusted alignment cases. The CHKSIZE that was used + * to decide between short and medium size was chosen to be 39 + * as that allows for the worst case of 7 bytes of alignment + * shift and 4 times 8 bytes for the first long word unrolling. + * That knowledge saves an initial test for length on entry into + * the medium cases. If the general loop unrolling factor were + * to be increases, this number would also need to be adjusted. + * + * For all cases in the non-FPBLK code where it is known that at + * least 4 chunks of data are available for movement, the + * loop is unrolled by four. This 4-way loop runs in 8 clocks + * or 2 clocks per data element. + * + * Instruction alignment is forced by used of .align 16 directives + * and nops which are not executed in the code. This + * combination of operations shifts the alignment of following + * loops to insure that loops are aligned so that their instructions + * fall within the minimum number of 4 instruction fetch groups. + * If instructions are inserted or removed between the .align + * instruction and the unrolled loops, then the alignment needs + * to be readjusted. Misaligned loops can add a clock per loop + * iteration to the loop timing. + * + * In a few cases, code is duplicated to avoid a branch. Since + * a non-predicted tst and branch takes 10 clocks, this savings + * is judged an appropriate time-space tradeoff. + * + * Within the FPBLK-code, the prefetch method in the inner + * loop needs to be explained as it is not standard. Two + * prefetches are issued for each cache line instead of one. + * The primary one is at the maximum reach of 8 cache lines. + * Most of the time, that maximum prefetch reach gives the + * cache line more time to reach the processor for systems with + * higher processor clocks. But, sometimes memory interference + * can cause that prefetch to be dropped. Putting a second + * prefetch at a reach of 5 cache lines catches the drops + * three iterations later and shows a measured improvement + * in performance over any similar loop with a single prefetch. + * The prefetches are placed in the loop so they overlap with + * non-memory instructions, so that there is no extra cost + * when the data is already in-cache. + * + */ + +/* + * Notes on preserving existing fp state and on membars. + * + * When a copyOP decides to use fp we may have to preserve existing + * floating point state. It is not the caller's state that we need to + * preserve - the rest of the kernel does not use fp and, anyway, fp + * registers are volatile across a call. Some examples: + * + * - userland has fp state and is interrupted (device interrupt + * or trap) and within the interrupt/trap handling we use + * bcopy() + * - another (higher level) interrupt or trap handler uses bcopy + * while a bcopy from an earlier interrupt is still active + * - an asynchronous error trap occurs while fp state exists (in + * userland or in kernel copy) and the tl0 component of the handling + * uses bcopy + * - a user process with fp state incurs a copy-on-write fault and + * hwblkpagecopy always uses fp + * + * We therefore need a per-call place in which to preserve fp state - + * using our stack is ideal (and since fp copy cannot be leaf optimized + * because of calls it makes, this is no hardship). + * + * When we have finished fp copy (with it's repeated block stores) + * we must membar #Sync so that our block stores may complete before + * we either restore the original fp state into the fp registers or + * return to a caller which may initiate other fp operations that could + * modify the fp regs we used before the block stores complete. + * + * Synchronous faults (eg, unresolvable DMMU miss) that occur while + * t_lofault is not NULL will not panic but will instead trampoline + * to the registered lofault handler. There is no need for any + * membars for these - eg, our store to t_lofault will always be visible to + * ourselves and it is our cpu which will take any trap. + * + * Asynchronous faults (eg, uncorrectable ECC error from memory) that occur + * while t_lofault is not NULL will also not panic. Since we're copying + * to or from userland the extent of the damage is known - the destination + * buffer is incomplete. So trap handlers will trampoline to the lofault + * handler in this case which should take some form of error action to + * avoid using the incomplete buffer. The trap handler also flags the + * fault so that later return-from-trap handling (for the trap that brought + * this thread into the kernel in the first place) can notify the process + * and reboot the system (or restart the service with Greenline/Contracts). + * + * Asynchronous faults (eg, uncorrectable ECC error from memory) can + * result in deferred error traps - the trap is taken sometime after + * the event and the trap PC may not be the PC of the faulting access. + * Delivery of such pending traps can be forced by a membar #Sync, acting + * as an "error barrier" in this role. To accurately apply the user/kernel + * separation described in the preceding paragraph we must force delivery + * of deferred traps affecting kernel state before we install a lofault + * handler (if we interpose a new lofault handler on an existing one there + * is no need to repeat this), and we must force delivery of deferred + * errors affecting the lofault-protected region before we clear t_lofault. + * Failure to do so results in lost kernel state being interpreted as + * affecting a copyin/copyout only, or of an error that really only + * affects copy data being interpreted as losing kernel state. + * + * Since the copy operations may preserve and later restore floating + * point state that does not belong to the caller (see examples above), + * we must be careful in how we do this in order to prevent corruption + * of another program. + * + * To make sure that floating point state is always saved and restored + * correctly, the following "big rules" must be followed when the floating + * point registers will be used: + * + * 1. %l6 always holds the caller's lofault handler. Also in this register, + * Bit 1 (FPUSED_FLAG) indicates that the floating point registers are in + * use. Bit 2 (TRAMP_FLAG) indicates that the call was to bcopy, and a + * lofault handler was set coming in. + * + * 2. The FPUSED flag indicates that all FP state has been successfully stored + * on the stack. It should not be set until this save has been completed. + * + * 3. The FPUSED flag should not be cleared on exit until all FP state has + * been restored from the stack. If an error occurs while restoring + * data from the stack, the error handler can check this flag to see if + * a restore is necessary. + * + * 4. Code run under the new lofault handler must be kept to a minimum. In + * particular, any calls to FP_ALLOWMIGRATE, which could result in a call + * to kpreempt(), should not be made until after the lofault handler has + * been restored. + */ + +/* + * VIS_COPY_THRESHOLD indicates the minimum number of bytes needed + * to "break even" using FP/VIS-accelerated memory operations. + * The FPBLK code assumes a minimum number of bytes are available + * to be moved on entry. Check that code carefully before + * reducing VIS_COPY_THRESHOLD below 256. + */ +/* + * This shadows sys/machsystm.h which can't be included due to the lack of + * _ASM guards in include files it references. Change it here, change it there. + */ +#define VIS_COPY_THRESHOLD 256 + +/* + * TEST for very short copies + * Be aware that the maximum unroll for the short unaligned case + * is SHORTCOPY+1 + */ +#define SHORTCOPY 3 +#define CHKSIZE 39 + +/* + * Indicates that we're to trampoline to the error handler. + * Entry points bcopy, copyin_noerr, and copyout_noerr use this flag. + * kcopy, copyout, xcopyout, copyin, and xcopyin do not set this flag. + */ +#define FPUSED_FLAG 1 +#define TRAMP_FLAG 2 +#define MASK_FLAGS 3 + +/* + * Number of outstanding prefetches. + * We may need more tuning when Olympus-C processor is available. + */ +#define OLYMPUS_C_PREFETCH 4 +#define OLYMPUS_C_2ND_PREFETCH 10 + +#define VIS_BLOCKSIZE 64 + +/* + * Size of stack frame in order to accomodate a 64-byte aligned + * floating-point register save area and 2 64-bit temp locations. + * All copy functions use two quadrants of fp registers; to assure a + * block-aligned two block buffer in which to save we must reserve + * three blocks on stack. Not all functions preserve %pfrs on stack + * or need to preserve %gsr but we use HWCOPYFRAMESIZE for all. + * + * _______________________________________ <-- %fp + STACK_BIAS + * | We may need to preserve 2 quadrants | + * | of fp regs, but since we do so with | + * | BST/BLD we need room in which to | + * | align to VIS_BLOCKSIZE bytes. So | + * | this area is 3 * VIS_BLOCKSIZE. | <-- - SAVED_FPREGS_OFFSET + * |-------------------------------------| + * | 8 bytes to save %fprs | <-- - SAVED_FPRS_OFFSET + * |-------------------------------------| + * | 8 bytes to save %gsr | <-- - SAVED_GSR_OFFSET + * --------------------------------------- + */ +#define HWCOPYFRAMESIZE ((VIS_BLOCKSIZE * (2 + 1)) + (2 * 8)) +#define SAVED_FPREGS_OFFSET (VIS_BLOCKSIZE * 3) +#define SAVED_FPREGS_ADJUST ((VIS_BLOCKSIZE * 2) - 1) +#define SAVED_FPRS_OFFSET (SAVED_FPREGS_OFFSET + 8) +#define SAVED_GSR_OFFSET (SAVED_FPRS_OFFSET + 8) + +/* + * Common macros used by the various versions of the block copy + * routines in this file. + */ + +/* + * In FP copies if we do not have preserved data to restore over + * the fp regs we used then we must zero those regs to avoid + * exposing portions of the data to later threads (data security). + * + * Copy functions use either quadrants 1 and 3 or 2 and 4. + * + * FZEROQ1Q3: Zero quadrants 1 and 3, ie %f0 - %f15 and %f32 - %f47 + * FZEROQ2Q4: Zero quadrants 2 and 4, ie %f16 - %f31 and %f48 - %f63 + * + * The instructions below are quicker than repeated fzero instructions + * since they can dispatch down two fp pipelines. + */ +#define FZEROQ1Q3 \ + fzero %f0 ;\ + fmovd %f0, %f2 ;\ + fmovd %f0, %f4 ;\ + fmovd %f0, %f6 ;\ + fmovd %f0, %f8 ;\ + fmovd %f0, %f10 ;\ + fmovd %f0, %f12 ;\ + fmovd %f0, %f14 ;\ + fmovd %f0, %f32 ;\ + fmovd %f0, %f34 ;\ + fmovd %f0, %f36 ;\ + fmovd %f0, %f38 ;\ + fmovd %f0, %f40 ;\ + fmovd %f0, %f42 ;\ + fmovd %f0, %f44 ;\ + fmovd %f0, %f46 + +#define FZEROQ2Q4 \ + fzero %f16 ;\ + fmovd %f0, %f18 ;\ + fmovd %f0, %f20 ;\ + fmovd %f0, %f22 ;\ + fmovd %f0, %f24 ;\ + fmovd %f0, %f26 ;\ + fmovd %f0, %f28 ;\ + fmovd %f0, %f30 ;\ + fmovd %f0, %f48 ;\ + fmovd %f0, %f50 ;\ + fmovd %f0, %f52 ;\ + fmovd %f0, %f54 ;\ + fmovd %f0, %f56 ;\ + fmovd %f0, %f58 ;\ + fmovd %f0, %f60 ;\ + fmovd %f0, %f62 + +/* + * Macros to save and restore quadrants 1 and 3 or 2 and 4 to/from the stack. + * Used to save and restore in-use fp registers when we want to use FP + * and find fp already in use and copy size still large enough to justify + * the additional overhead of this save and restore. + * + * A membar #Sync is needed before save to sync fp ops initiated before + * the call to the copy function (by whoever has fp in use); for example + * an earlier block load to the quadrant we are about to save may still be + * "in flight". A membar #Sync is required at the end of the save to + * sync our block store (the copy code is about to begin ldd's to the + * first quadrant). + * + * Similarly: a membar #Sync before restore allows the block stores of + * the copy operation to complete before we fill the quadrants with their + * original data, and a membar #Sync after restore lets the block loads + * of the restore complete before we return to whoever has the fp regs + * in use. To avoid repeated membar #Sync we make it the responsibility + * of the copy code to membar #Sync immediately after copy is complete + * and before using the BLD_*_FROMSTACK macro. + */ +#if !defined(lint) +#define BST_FPQ1Q3_TOSTACK(tmp1) \ + /* membar #Sync */ ;\ + add %fp, STACK_BIAS - SAVED_FPREGS_ADJUST, tmp1 ;\ + and tmp1, -VIS_BLOCKSIZE, tmp1 /* block align */ ;\ + stda %f0, [tmp1]ASI_BLK_P ;\ + add tmp1, VIS_BLOCKSIZE, tmp1 ;\ + stda %f32, [tmp1]ASI_BLK_P ;\ + membar #Sync + +#define BLD_FPQ1Q3_FROMSTACK(tmp1) \ + /* membar #Sync - provided at copy completion */ ;\ + add %fp, STACK_BIAS - SAVED_FPREGS_ADJUST, tmp1 ;\ + and tmp1, -VIS_BLOCKSIZE, tmp1 /* block align */ ;\ + ldda [tmp1]ASI_BLK_P, %f0 ;\ + add tmp1, VIS_BLOCKSIZE, tmp1 ;\ + ldda [tmp1]ASI_BLK_P, %f32 ;\ + membar #Sync + +#define BST_FPQ2Q4_TOSTACK(tmp1) \ + /* membar #Sync */ ;\ + add %fp, STACK_BIAS - SAVED_FPREGS_ADJUST, tmp1 ;\ + and tmp1, -VIS_BLOCKSIZE, tmp1 /* block align */ ;\ + stda %f16, [tmp1]ASI_BLK_P ;\ + add tmp1, VIS_BLOCKSIZE, tmp1 ;\ + stda %f48, [tmp1]ASI_BLK_P ;\ + membar #Sync + +#define BLD_FPQ2Q4_FROMSTACK(tmp1) \ + /* membar #Sync - provided at copy completion */ ;\ + add %fp, STACK_BIAS - SAVED_FPREGS_ADJUST, tmp1 ;\ + and tmp1, -VIS_BLOCKSIZE, tmp1 /* block align */ ;\ + ldda [tmp1]ASI_BLK_P, %f16 ;\ + add tmp1, VIS_BLOCKSIZE, tmp1 ;\ + ldda [tmp1]ASI_BLK_P, %f48 ;\ + membar #Sync +#endif + +/* + * FP_NOMIGRATE and FP_ALLOWMIGRATE. Prevent migration (or, stronger, + * prevent preemption if there is no t_lwp to save FP state to on context + * switch) before commencing a FP copy, and reallow it on completion or + * in error trampoline paths when we were using FP copy. + * + * Both macros may call other functions, so be aware that all outputs are + * forfeit after using these macros. For this reason we do not pass registers + * to use - we just use any outputs we want. + * + * Pseudo code: + * + * FP_NOMIGRATE: + * + * if (curthread->t_lwp) { + * thread_nomigrate(); + * } else { + * kpreempt_disable(); + * } + * + * FP_ALLOWMIGRATE: + * + * if (curthread->t_lwp) { + * thread_allowmigrate(); + * } else { + * kpreempt_enable(); + * } + */ + +#define FP_NOMIGRATE(label1, label2) \ + ldn [THREAD_REG + T_LWP], %o0 ;\ + brz,a,pn %o0, label1/**/f ;\ + ldsb [THREAD_REG + T_PREEMPT], %o1 ;\ + call thread_nomigrate ;\ + nop ;\ + ba label2/**/f ;\ + nop ;\ +label1: ;\ + inc %o1 ;\ + stb %o1, [THREAD_REG + T_PREEMPT] ;\ +label2: + +#define FP_ALLOWMIGRATE(label1, label2) \ + ldn [THREAD_REG + T_LWP], %o0 ;\ + brz,a,pn %o0, label1/**/f ;\ + ldsb [THREAD_REG + T_PREEMPT], %o1 ;\ + call thread_allowmigrate ;\ + nop ;\ + ba label2/**/f ;\ + nop ;\ +label1: ;\ + dec %o1 ;\ + brnz,pn %o1, label2/**/f ;\ + stb %o1, [THREAD_REG + T_PREEMPT] ;\ + ldn [THREAD_REG + T_CPU], %o0 ;\ + ldub [%o0 + CPU_KPRUNRUN], %o0 ;\ + brz,pt %o0, label2/**/f ;\ + nop ;\ + call kpreempt ;\ + rdpr %pil, %o0 ;\ +label2: + +/* + * Copy a block of storage, returning an error code if `from' or + * `to' takes a kernel pagefault which cannot be resolved. + * Returns errno value on pagefault error, 0 if all ok + */ + +#if defined(lint) + +/* ARGSUSED */ +int +kcopy(const void *from, void *to, size_t count) +{ return(0); } + +#else /* lint */ + + .seg ".text" + .align 4 + + ENTRY(kcopy) + + cmp %o2, VIS_COPY_THRESHOLD ! check for leaf rtn case + bleu,pt %ncc, .kcopy_small ! go to larger cases + xor %o0, %o1, %o3 ! are src, dst alignable? + btst 7, %o3 ! + bz,pt %ncc, .kcopy_8 ! check for longword alignment + nop + btst 1, %o3 ! + bz,pt %ncc, .kcopy_2 ! check for half-word + nop + sethi %hi(hw_copy_limit_1), %o3 ! Check copy limit + ld [%o3 + %lo(hw_copy_limit_1)], %o3 + tst %o3 + bz,pn %icc, .kcopy_small ! if zero, disable HW copy + cmp %o2, %o3 ! if length <= limit + bleu,pt %ncc, .kcopy_small ! go to small copy + nop + ba,pt %ncc, .kcopy_more ! otherwise go to large copy + nop +.kcopy_2: + btst 3, %o3 ! + bz,pt %ncc, .kcopy_4 ! check for word alignment + nop + sethi %hi(hw_copy_limit_2), %o3 ! Check copy limit + ld [%o3 + %lo(hw_copy_limit_2)], %o3 + tst %o3 + bz,pn %icc, .kcopy_small ! if zero, disable HW copy + cmp %o2, %o3 ! if length <= limit + bleu,pt %ncc, .kcopy_small ! go to small copy + nop + ba,pt %ncc, .kcopy_more ! otherwise go to large copy + nop +.kcopy_4: + ! already checked longword, must be word aligned + sethi %hi(hw_copy_limit_4), %o3 ! Check copy limit + ld [%o3 + %lo(hw_copy_limit_4)], %o3 + tst %o3 + bz,pn %icc, .kcopy_small ! if zero, disable HW copy + cmp %o2, %o3 ! if length <= limit + bleu,pt %ncc, .kcopy_small ! go to small copy + nop + ba,pt %ncc, .kcopy_more ! otherwise go to large copy + nop +.kcopy_8: + sethi %hi(hw_copy_limit_8), %o3 ! Check copy limit + ld [%o3 + %lo(hw_copy_limit_8)], %o3 + tst %o3 + bz,pn %icc, .kcopy_small ! if zero, disable HW copy + cmp %o2, %o3 ! if length <= limit + bleu,pt %ncc, .kcopy_small ! go to small copy + nop + ba,pt %ncc, .kcopy_more ! otherwise go to large copy + nop + +.kcopy_small: + sethi %hi(.sm_copyerr), %o5 ! sm_copyerr is lofault value + or %o5, %lo(.sm_copyerr), %o5 + ldn [THREAD_REG + T_LOFAULT], %o4 ! save existing handler + membar #Sync ! sync error barrier + ba,pt %ncc, .sm_do_copy ! common code + stn %o5, [THREAD_REG + T_LOFAULT] ! set t_lofault + +.kcopy_more: + save %sp, -SA(MINFRAME + HWCOPYFRAMESIZE), %sp + sethi %hi(.copyerr), %l7 ! copyerr is lofault value + or %l7, %lo(.copyerr), %l7 + ldn [THREAD_REG + T_LOFAULT], %l6 ! save existing handler + membar #Sync ! sync error barrier + ba,pt %ncc, .do_copy ! common code + stn %l7, [THREAD_REG + T_LOFAULT] ! set t_lofault + + +/* + * We got here because of a fault during bcopy_more, called from kcopy or bcopy. + * Errno value is in %g1. bcopy_more uses fp quadrants 1 and 3. + */ +.copyerr: + set .copyerr2, %l0 + membar #Sync ! sync error barrier + stn %l0, [THREAD_REG + T_LOFAULT] ! set t_lofault + btst FPUSED_FLAG, %l6 + bz %ncc, 1f + and %l6, TRAMP_FLAG, %l0 ! copy trampoline flag to %l0 + + ldx [%fp + STACK_BIAS - SAVED_GSR_OFFSET], %o2 ! restore gsr + wr %o2, 0, %gsr + + ld [%fp + STACK_BIAS - SAVED_FPRS_OFFSET], %o3 + btst FPRS_FEF, %o3 + bz,pt %icc, 4f + nop + + BLD_FPQ1Q3_FROMSTACK(%o2) + + ba,pt %ncc, 1f + wr %o3, 0, %fprs ! restore fprs + +4: + FZEROQ1Q3 + wr %o3, 0, %fprs ! restore fprs + + ! + ! Need to cater for the different expectations of kcopy + ! and bcopy. kcopy will *always* set a t_lofault handler + ! If it fires, we're expected to just return the error code + ! and *not* to invoke any existing error handler. As far as + ! bcopy is concerned, we only set t_lofault if there was an + ! existing lofault handler. In that case we're expected to + ! invoke the previously existing handler after resetting the + ! t_lofault value. + ! +1: + andn %l6, MASK_FLAGS, %l6 ! turn trampoline flag off + membar #Sync ! sync error barrier + stn %l6, [THREAD_REG + T_LOFAULT] ! restore old t_lofault + FP_ALLOWMIGRATE(5, 6) + + btst TRAMP_FLAG, %l0 + bnz,pn %ncc, 3f + nop + ret + restore %g1, 0, %o0 + +3: + ! + ! We're here via bcopy. There *must* have been an error handler + ! in place otherwise we would have died a nasty death already. + ! + jmp %l6 ! goto real handler + restore %g0, 0, %o0 ! dispose of copy window + +/* + * We got here because of a fault in .copyerr. We can't safely restore fp + * state, so we panic. + */ +fp_panic_msg: + .asciz "Unable to restore fp state after copy operation" + + .align 4 +.copyerr2: + set fp_panic_msg, %o0 + call panic + nop + +/* + * We got here because of a fault during a small kcopy or bcopy. + * No floating point registers are used by the small copies. + * Errno value is in %g1. + */ +.sm_copyerr: +1: + btst TRAMP_FLAG, %o4 + membar #Sync + andn %o4, TRAMP_FLAG, %o4 + bnz,pn %ncc, 3f + stn %o4, [THREAD_REG + T_LOFAULT] ! restore old t_lofault + retl + mov %g1, %o0 +3: + jmp %o4 ! goto real handler + mov %g0, %o0 ! + + SET_SIZE(kcopy) +#endif /* lint */ + + +/* + * Copy a block of storage - must not overlap (from + len <= to). + * Registers: l6 - saved t_lofault + * (for short copies, o4 - saved t_lofault) + * + * Copy a page of memory. + * Assumes double word alignment and a count >= 256. + */ +#if defined(lint) + +/* ARGSUSED */ +void +bcopy(const void *from, void *to, size_t count) +{} + +#else /* lint */ + + ENTRY(bcopy) + + cmp %o2, VIS_COPY_THRESHOLD ! check for leaf rtn case + bleu,pt %ncc, .bcopy_small ! go to larger cases + xor %o0, %o1, %o3 ! are src, dst alignable? + btst 7, %o3 ! + bz,pt %ncc, .bcopy_8 ! check for longword alignment + nop + btst 1, %o3 ! + bz,pt %ncc, .bcopy_2 ! check for half-word + nop + sethi %hi(hw_copy_limit_1), %o3 ! Check copy limit + ld [%o3 + %lo(hw_copy_limit_1)], %o3 + tst %o3 + bz,pn %icc, .bcopy_small ! if zero, disable HW copy + cmp %o2, %o3 ! if length <= limit + bleu,pt %ncc, .bcopy_small ! go to small copy + nop + ba,pt %ncc, .bcopy_more ! otherwise go to large copy + nop +.bcopy_2: + btst 3, %o3 ! + bz,pt %ncc, .bcopy_4 ! check for word alignment + nop + sethi %hi(hw_copy_limit_2), %o3 ! Check copy limit + ld [%o3 + %lo(hw_copy_limit_2)], %o3 + tst %o3 + bz,pn %icc, .bcopy_small ! if zero, disable HW copy + cmp %o2, %o3 ! if length <= limit + bleu,pt %ncc, .bcopy_small ! go to small copy + nop + ba,pt %ncc, .bcopy_more ! otherwise go to large copy + nop +.bcopy_4: + ! already checked longword, must be word aligned + sethi %hi(hw_copy_limit_4), %o3 ! Check copy limit + ld [%o3 + %lo(hw_copy_limit_4)], %o3 + tst %o3 + bz,pn %icc, .bcopy_small ! if zero, disable HW copy + cmp %o2, %o3 ! if length <= limit + bleu,pt %ncc, .bcopy_small ! go to small copy + nop + ba,pt %ncc, .bcopy_more ! otherwise go to large copy + nop +.bcopy_8: + sethi %hi(hw_copy_limit_8), %o3 ! Check copy limit + ld [%o3 + %lo(hw_copy_limit_8)], %o3 + tst %o3 + bz,pn %icc, .bcopy_small ! if zero, disable HW copy + cmp %o2, %o3 ! if length <= limit + bleu,pt %ncc, .bcopy_small ! go to small copy + nop + ba,pt %ncc, .bcopy_more ! otherwise go to large copy + nop + + .align 16 +.bcopy_small: + ldn [THREAD_REG + T_LOFAULT], %o4 ! save t_lofault + tst %o4 + bz,pt %icc, .sm_do_copy + nop + sethi %hi(.sm_copyerr), %o5 + or %o5, %lo(.sm_copyerr), %o5 + membar #Sync ! sync error barrier + stn %o5, [THREAD_REG + T_LOFAULT] ! install new vector + or %o4, TRAMP_FLAG, %o4 ! error should trampoline +.sm_do_copy: + cmp %o2, SHORTCOPY ! check for really short case + bleu,pt %ncc, .bc_sm_left ! + cmp %o2, CHKSIZE ! check for medium length cases + bgu,pn %ncc, .bc_med ! + or %o0, %o1, %o3 ! prepare alignment check + andcc %o3, 0x3, %g0 ! test for alignment + bz,pt %ncc, .bc_sm_word ! branch to word aligned case +.bc_sm_movebytes: + sub %o2, 3, %o2 ! adjust count to allow cc zero test +.bc_sm_notalign4: + ldub [%o0], %o3 ! read byte + stb %o3, [%o1] ! write byte + subcc %o2, 4, %o2 ! reduce count by 4 + ldub [%o0 + 1], %o3 ! repeat for a total of 4 bytes + add %o0, 4, %o0 ! advance SRC by 4 + stb %o3, [%o1 + 1] + ldub [%o0 - 2], %o3 + add %o1, 4, %o1 ! advance DST by 4 + stb %o3, [%o1 - 2] + ldub [%o0 - 1], %o3 + bgt,pt %ncc, .bc_sm_notalign4 ! loop til 3 or fewer bytes remain + stb %o3, [%o1 - 1] + add %o2, 3, %o2 ! restore count +.bc_sm_left: + tst %o2 + bz,pt %ncc, .bc_sm_exit ! check for zero length + deccc %o2 ! reduce count for cc test + ldub [%o0], %o3 ! move one byte + bz,pt %ncc, .bc_sm_exit + stb %o3, [%o1] + ldub [%o0 + 1], %o3 ! move another byte + deccc %o2 ! check for more + bz,pt %ncc, .bc_sm_exit + stb %o3, [%o1 + 1] + ldub [%o0 + 2], %o3 ! move final byte + stb %o3, [%o1 + 2] + membar #Sync ! sync error barrier + andn %o4, TRAMP_FLAG, %o4 + stn %o4, [THREAD_REG + T_LOFAULT] ! restore old t_lofault + retl + mov %g0, %o0 ! return 0 + .align 16 + nop ! instruction alignment + ! see discussion at start of file +.bc_sm_words: + lduw [%o0], %o3 ! read word +.bc_sm_wordx: + subcc %o2, 8, %o2 ! update count + stw %o3, [%o1] ! write word + add %o0, 8, %o0 ! update SRC + lduw [%o0 - 4], %o3 ! read word + add %o1, 8, %o1 ! update DST + bgt,pt %ncc, .bc_sm_words ! loop til done + stw %o3, [%o1 - 4] ! write word + addcc %o2, 7, %o2 ! restore count + bz,pt %ncc, .bc_sm_exit + deccc %o2 + bz,pt %ncc, .bc_sm_byte +.bc_sm_half: + subcc %o2, 2, %o2 ! reduce count by 2 + add %o0, 2, %o0 ! advance SRC by 2 + lduh [%o0 - 2], %o3 ! read half word + add %o1, 2, %o1 ! advance DST by 2 + bgt,pt %ncc, .bc_sm_half ! loop til done + sth %o3, [%o1 - 2] ! write half word + addcc %o2, 1, %o2 ! restore count + bz,pt %ncc, .bc_sm_exit + nop +.bc_sm_byte: + ldub [%o0], %o3 + stb %o3, [%o1] + membar #Sync ! sync error barrier + andn %o4, TRAMP_FLAG, %o4 + stn %o4, [THREAD_REG + T_LOFAULT] ! restore old t_lofault + retl + mov %g0, %o0 ! return 0 + +.bc_sm_word: + subcc %o2, 4, %o2 ! update count + bgt,pt %ncc, .bc_sm_wordx + lduw [%o0], %o3 ! read word + addcc %o2, 3, %o2 ! restore count + bz,pt %ncc, .bc_sm_exit + stw %o3, [%o1] ! write word + deccc %o2 ! reduce count for cc test + ldub [%o0 + 4], %o3 ! load one byte + bz,pt %ncc, .bc_sm_exit + stb %o3, [%o1 + 4] ! store one byte + ldub [%o0 + 5], %o3 ! load second byte + deccc %o2 + bz,pt %ncc, .bc_sm_exit + stb %o3, [%o1 + 5] ! store second byte + ldub [%o0 + 6], %o3 ! load third byte + stb %o3, [%o1 + 6] ! store third byte +.bc_sm_exit: + membar #Sync ! sync error barrier + andn %o4, TRAMP_FLAG, %o4 + stn %o4, [THREAD_REG + T_LOFAULT] ! restore old t_lofault + retl + mov %g0, %o0 ! return 0 + + .align 16 +.bc_med: + xor %o0, %o1, %o3 ! setup alignment check + btst 1, %o3 + bnz,pt %ncc, .bc_sm_movebytes ! unaligned + nop + btst 3, %o3 + bnz,pt %ncc, .bc_med_half ! halfword aligned + nop + btst 7, %o3 + bnz,pt %ncc, .bc_med_word ! word aligned + nop +.bc_med_long: + btst 3, %o0 ! check for + bz,pt %ncc, .bc_med_long1 ! word alignment + nop +.bc_med_long0: + ldub [%o0], %o3 ! load one byte + inc %o0 + stb %o3,[%o1] ! store byte + inc %o1 + btst 3, %o0 + bnz,pt %ncc, .bc_med_long0 + dec %o2 +.bc_med_long1: ! word aligned + btst 7, %o0 ! check for long word + bz,pt %ncc, .bc_med_long2 + nop + lduw [%o0], %o3 ! load word + add %o0, 4, %o0 ! advance SRC by 4 + stw %o3, [%o1] ! store word + add %o1, 4, %o1 ! advance DST by 4 + sub %o2, 4, %o2 ! reduce count by 4 +! +! Now long word aligned and have at least 32 bytes to move +! +.bc_med_long2: + sub %o2, 31, %o2 ! adjust count to allow cc zero test +.bc_med_lmove: + ldx [%o0], %o3 ! read long word + stx %o3, [%o1] ! write long word + subcc %o2, 32, %o2 ! reduce count by 32 + ldx [%o0 + 8], %o3 ! repeat for a total for 4 long words + add %o0, 32, %o0 ! advance SRC by 32 + stx %o3, [%o1 + 8] + ldx [%o0 - 16], %o3 + add %o1, 32, %o1 ! advance DST by 32 + stx %o3, [%o1 - 16] + ldx [%o0 - 8], %o3 + bgt,pt %ncc, .bc_med_lmove ! loop til 31 or fewer bytes left + stx %o3, [%o1 - 8] + addcc %o2, 24, %o2 ! restore count to long word offset + ble,pt %ncc, .bc_med_lextra ! check for more long words to move + nop +.bc_med_lword: + ldx [%o0], %o3 ! read long word + subcc %o2, 8, %o2 ! reduce count by 8 + stx %o3, [%o1] ! write long word + add %o0, 8, %o0 ! advance SRC by 8 + bgt,pt %ncc, .bc_med_lword ! loop til 7 or fewer bytes left + add %o1, 8, %o1 ! advance DST by 8 +.bc_med_lextra: + addcc %o2, 7, %o2 ! restore rest of count + bz,pt %ncc, .bc_sm_exit ! if zero, then done + deccc %o2 + bz,pt %ncc, .bc_sm_byte + nop + ba,pt %ncc, .bc_sm_half + nop + + .align 16 +.bc_med_word: + btst 3, %o0 ! check for + bz,pt %ncc, .bc_med_word1 ! word alignment + nop +.bc_med_word0: + ldub [%o0], %o3 ! load one byte + inc %o0 + stb %o3,[%o1] ! store byte + inc %o1 + btst 3, %o0 + bnz,pt %ncc, .bc_med_word0 + dec %o2 +! +! Now word aligned and have at least 36 bytes to move +! +.bc_med_word1: + sub %o2, 15, %o2 ! adjust count to allow cc zero test +.bc_med_wmove: + lduw [%o0], %o3 ! read word + stw %o3, [%o1] ! write word + subcc %o2, 16, %o2 ! reduce count by 16 + lduw [%o0 + 4], %o3 ! repeat for a total for 4 words + add %o0, 16, %o0 ! advance SRC by 16 + stw %o3, [%o1 + 4] + lduw [%o0 - 8], %o3 + add %o1, 16, %o1 ! advance DST by 16 + stw %o3, [%o1 - 8] + lduw [%o0 - 4], %o3 + bgt,pt %ncc, .bc_med_wmove ! loop til 15 or fewer bytes left + stw %o3, [%o1 - 4] + addcc %o2, 12, %o2 ! restore count to word offset + ble,pt %ncc, .bc_med_wextra ! check for more words to move + nop +.bc_med_word2: + lduw [%o0], %o3 ! read word + subcc %o2, 4, %o2 ! reduce count by 4 + stw %o3, [%o1] ! write word + add %o0, 4, %o0 ! advance SRC by 4 + bgt,pt %ncc, .bc_med_word2 ! loop til 3 or fewer bytes left + add %o1, 4, %o1 ! advance DST by 4 +.bc_med_wextra: + addcc %o2, 3, %o2 ! restore rest of count + bz,pt %ncc, .bc_sm_exit ! if zero, then done + deccc %o2 + bz,pt %ncc, .bc_sm_byte + nop + ba,pt %ncc, .bc_sm_half + nop + + .align 16 +.bc_med_half: + btst 1, %o0 ! check for + bz,pt %ncc, .bc_med_half1 ! half word alignment + nop + ldub [%o0], %o3 ! load one byte + inc %o0 + stb %o3,[%o1] ! store byte + inc %o1 + dec %o2 +! +! Now half word aligned and have at least 38 bytes to move +! +.bc_med_half1: + sub %o2, 7, %o2 ! adjust count to allow cc zero test +.bc_med_hmove: + lduh [%o0], %o3 ! read half word + sth %o3, [%o1] ! write half word + subcc %o2, 8, %o2 ! reduce count by 8 + lduh [%o0 + 2], %o3 ! repeat for a total for 4 halfwords + add %o0, 8, %o0 ! advance SRC by 8 + sth %o3, [%o1 + 2] + lduh [%o0 - 4], %o3 + add %o1, 8, %o1 ! advance DST by 8 + sth %o3, [%o1 - 4] + lduh [%o0 - 2], %o3 + bgt,pt %ncc, .bc_med_hmove ! loop til 7 or fewer bytes left + sth %o3, [%o1 - 2] + addcc %o2, 7, %o2 ! restore count + bz,pt %ncc, .bc_sm_exit + deccc %o2 + bz,pt %ncc, .bc_sm_byte + nop + ba,pt %ncc, .bc_sm_half + nop + + SET_SIZE(bcopy) + +/* + * The _more entry points are not intended to be used directly by + * any caller from outside this file. They are provided to allow + * profiling and dtrace of the portions of the copy code that uses + * the floating point registers. + * This entry is particularly important as DTRACE (at least as of + * 4/2004) does not support leaf functions. + */ + + ENTRY(bcopy_more) +.bcopy_more: + prefetch [%o0], #n_reads + save %sp, -SA(MINFRAME + HWCOPYFRAMESIZE), %sp + ldn [THREAD_REG + T_LOFAULT], %l6 ! save t_lofault + tst %l6 + bz,pt %ncc, .do_copy + nop + sethi %hi(.copyerr), %o2 + or %o2, %lo(.copyerr), %o2 + membar #Sync ! sync error barrier + stn %o2, [THREAD_REG + T_LOFAULT] ! install new vector + ! + ! We've already captured whether t_lofault was zero on entry. + ! We need to mark ourselves as being from bcopy since both + ! kcopy and bcopy use the same code path. If TRAMP_FLAG is set + ! and the saved lofault was zero, we won't reset lofault on + ! returning. + ! + or %l6, TRAMP_FLAG, %l6 + +/* + * Copies that reach here are larger than VIS_COPY_THRESHOLD bytes + * Also, use of FP registers has been tested to be enabled + */ +.do_copy: + FP_NOMIGRATE(6, 7) + + rd %fprs, %o2 ! check for unused fp + st %o2, [%fp + STACK_BIAS - SAVED_FPRS_OFFSET] ! save orig %fprs + btst FPRS_FEF, %o2 + bz,a,pt %icc, .do_blockcopy + wr %g0, FPRS_FEF, %fprs + + BST_FPQ1Q3_TOSTACK(%o2) + +.do_blockcopy: + rd %gsr, %o2 + stx %o2, [%fp + STACK_BIAS - SAVED_GSR_OFFSET] ! save gsr + or %l6, FPUSED_FLAG, %l6 + +#define REALSRC %i0 +#define DST %i1 +#define CNT %i2 +#define SRC %i3 +#define TMP %i5 + + andcc DST, VIS_BLOCKSIZE - 1, TMP + bz,pt %ncc, 2f + neg TMP + add TMP, VIS_BLOCKSIZE, TMP + + ! TMP = bytes required to align DST on FP_BLOCK boundary + ! Using SRC as a tmp here + cmp TMP, 3 + bleu,pt %ncc, 1f + sub CNT,TMP,CNT ! adjust main count + sub TMP, 3, TMP ! adjust for end of loop test +.bc_blkalign: + ldub [REALSRC], SRC ! move 4 bytes per loop iteration + stb SRC, [DST] + subcc TMP, 4, TMP + ldub [REALSRC + 1], SRC + add REALSRC, 4, REALSRC + stb SRC, [DST + 1] + ldub [REALSRC - 2], SRC + add DST, 4, DST + stb SRC, [DST - 2] + ldub [REALSRC - 1], SRC + bgu,pt %ncc, .bc_blkalign + stb SRC, [DST - 1] + + addcc TMP, 3, TMP ! restore count adjustment + bz,pt %ncc, 2f ! no bytes left? + nop +1: ldub [REALSRC], SRC + inc REALSRC + inc DST + deccc TMP + bgu %ncc, 1b + stb SRC, [DST - 1] + +2: + membar #StoreLoad + andn REALSRC, 0x7, SRC + + ! SRC - 8-byte aligned + ! DST - 64-byte aligned + ldd [SRC], %f0 + prefetch [SRC + (1 * VIS_BLOCKSIZE)], #n_reads + alignaddr REALSRC, %g0, %g0 + ldd [SRC + 0x08], %f2 + prefetch [SRC + (2 * VIS_BLOCKSIZE)], #n_reads + faligndata %f0, %f2, %f32 + ldd [SRC + 0x10], %f4 + prefetch [SRC + (3 * VIS_BLOCKSIZE)], #one_read + faligndata %f2, %f4, %f34 + ldd [SRC + 0x18], %f6 + prefetch [SRC + (4 * VIS_BLOCKSIZE)], #one_read + faligndata %f4, %f6, %f36 + ldd [SRC + 0x20], %f8 + prefetch [SRC + (5 * VIS_BLOCKSIZE)], #one_read + faligndata %f6, %f8, %f38 + ldd [SRC + 0x28], %f10 + prefetch [SRC + (6 * VIS_BLOCKSIZE)], #one_read + faligndata %f8, %f10, %f40 + ldd [SRC + 0x30], %f12 + prefetch [SRC + (7 * VIS_BLOCKSIZE)], #one_read + faligndata %f10, %f12, %f42 + ldd [SRC + 0x38], %f14 + ldd [SRC + VIS_BLOCKSIZE], %f0 + sub CNT, VIS_BLOCKSIZE, CNT + add SRC, VIS_BLOCKSIZE, SRC + prefetch [SRC + (9 * VIS_BLOCKSIZE) - VIS_BLOCKSIZE], #one_read + add REALSRC, VIS_BLOCKSIZE, REALSRC + ba,pt %ncc, 1f + prefetch [SRC + (10 * VIS_BLOCKSIZE) - VIS_BLOCKSIZE], #one_read + .align 32 +1: + ldd [SRC + 0x08], %f2 + faligndata %f12, %f14, %f44 + ldd [SRC + 0x10], %f4 + faligndata %f14, %f0, %f46 + stda %f32, [DST]ASI_BLK_P + ldd [SRC + 0x18], %f6 + faligndata %f0, %f2, %f32 + ldd [SRC + 0x20], %f8 + faligndata %f2, %f4, %f34 + ldd [SRC + 0x28], %f10 + faligndata %f4, %f6, %f36 + ldd [SRC + 0x30], %f12 + faligndata %f6, %f8, %f38 + ldd [SRC + 0x38], %f14 + prefetch [SRC + ((OLYMPUS_C_PREFETCH) * VIS_BLOCKSIZE)], #n_reads + faligndata %f8, %f10, %f40 + ldd [SRC + VIS_BLOCKSIZE], %f0 + prefetch [SRC + ((OLYMPUS_C_2ND_PREFETCH) * VIS_BLOCKSIZE)], #one_read + faligndata %f10, %f12, %f42 + prefetch [SRC + ((OLYMPUS_C_PREFETCH) * VIS_BLOCKSIZE) + 0x20], #n_reads + prefetch [SRC + ((OLYMPUS_C_2ND_PREFETCH) * VIS_BLOCKSIZE) + 0x20], #one_read + sub CNT, VIS_BLOCKSIZE, CNT + add DST, VIS_BLOCKSIZE, DST + add REALSRC, VIS_BLOCKSIZE, REALSRC + cmp CNT, VIS_BLOCKSIZE + 8 + bgu,pt %ncc, 1b + add SRC, VIS_BLOCKSIZE, SRC + + ! only if REALSRC & 0x7 is 0 + cmp CNT, VIS_BLOCKSIZE + bne %ncc, 3f + andcc REALSRC, 0x7, %g0 + bz,pt %ncc, 2f + nop +3: + faligndata %f12, %f14, %f44 + faligndata %f14, %f0, %f46 + stda %f32, [DST]ASI_BLK_P + add DST, VIS_BLOCKSIZE, DST + ba,pt %ncc, 3f + nop +2: + ldd [SRC + 0x08], %f2 + fsrc1 %f12, %f44 + ldd [SRC + 0x10], %f4 + fsrc1 %f14, %f46 + stda %f32, [DST]ASI_BLK_P + ldd [SRC + 0x18], %f6 + fsrc1 %f0, %f32 + ldd [SRC + 0x20], %f8 + fsrc1 %f2, %f34 + ldd [SRC + 0x28], %f10 + fsrc1 %f4, %f36 + ldd [SRC + 0x30], %f12 + fsrc1 %f6, %f38 + ldd [SRC + 0x38], %f14 + fsrc1 %f8, %f40 + sub CNT, VIS_BLOCKSIZE, CNT + add DST, VIS_BLOCKSIZE, DST + add SRC, VIS_BLOCKSIZE, SRC + add REALSRC, VIS_BLOCKSIZE, REALSRC + fsrc1 %f10, %f42 + fsrc1 %f12, %f44 + fsrc1 %f14, %f46 + stda %f32, [DST]ASI_BLK_P + add DST, VIS_BLOCKSIZE, DST + ba,a,pt %ncc, .bcb_exit + nop + +3: tst CNT + bz,a,pt %ncc, .bcb_exit + nop + +5: ldub [REALSRC], TMP + inc REALSRC + inc DST + deccc CNT + bgu %ncc, 5b + stb TMP, [DST - 1] +.bcb_exit: + membar #Sync + + ldx [%fp + STACK_BIAS - SAVED_GSR_OFFSET], %o2 ! restore gsr + wr %o2, 0, %gsr + + ld [%fp + STACK_BIAS - SAVED_FPRS_OFFSET], %o3 + btst FPRS_FEF, %o3 + bz,pt %icc, 4f + nop + + BLD_FPQ1Q3_FROMSTACK(%o2) + + ba,pt %ncc, 2f + wr %o3, 0, %fprs ! restore fprs +4: + FZEROQ1Q3 + wr %o3, 0, %fprs ! restore fprs +2: + membar #Sync ! sync error barrier + andn %l6, MASK_FLAGS, %l6 + stn %l6, [THREAD_REG + T_LOFAULT] ! restore old t_lofault + FP_ALLOWMIGRATE(5, 6) + ret + restore %g0, 0, %o0 + + SET_SIZE(bcopy_more) + +#endif /* lint */ + +/* + * Block copy with possibly overlapped operands. + */ + +#if defined(lint) + +/*ARGSUSED*/ +void +ovbcopy(const void *from, void *to, size_t count) +{} + +#else /* lint */ + + ENTRY(ovbcopy) + tst %o2 ! check count + bgu,a %ncc, 1f ! nothing to do or bad arguments + subcc %o0, %o1, %o3 ! difference of from and to address + + retl ! return + nop +1: + bneg,a %ncc, 2f + neg %o3 ! if < 0, make it positive +2: cmp %o2, %o3 ! cmp size and abs(from - to) + bleu %ncc, bcopy ! if size <= abs(diff): use bcopy, + .empty ! no overlap + cmp %o0, %o1 ! compare from and to addresses + blu %ncc, .ov_bkwd ! if from < to, copy backwards + nop + ! + ! Copy forwards. + ! +.ov_fwd: + ldub [%o0], %o3 ! read from address + inc %o0 ! inc from address + stb %o3, [%o1] ! write to address + deccc %o2 ! dec count + bgu %ncc, .ov_fwd ! loop till done + inc %o1 ! inc to address + + retl ! return + nop + ! + ! Copy backwards. + ! +.ov_bkwd: + deccc %o2 ! dec count + ldub [%o0 + %o2], %o3 ! get byte at end of src + bgu %ncc, .ov_bkwd ! loop till done + stb %o3, [%o1 + %o2] ! delay slot, store at end of dst + + retl ! return + nop + + SET_SIZE(ovbcopy) + +#endif /* lint */ + + +/* + * hwblkpagecopy() + * + * Copies exactly one page. This routine assumes the caller (ppcopy) + * has already disabled kernel preemption and has checked + * use_hw_bcopy. Preventing preemption also prevents cpu migration. + */ +#ifdef lint +/*ARGSUSED*/ +void +hwblkpagecopy(const void *src, void *dst) +{ } +#else /* lint */ + ENTRY(hwblkpagecopy) + ! get another window w/space for three aligned blocks of saved fpregs + prefetch [%o0], #n_reads + save %sp, -SA(MINFRAME + HWCOPYFRAMESIZE), %sp + + ! %i0 - source address (arg) + ! %i1 - destination address (arg) + ! %i2 - length of region (not arg) + ! %l0 - saved fprs + ! %l1 - pointer to saved fpregs + + rd %fprs, %l0 ! check for unused fp + btst FPRS_FEF, %l0 + bz,a,pt %icc, 1f + wr %g0, FPRS_FEF, %fprs + + BST_FPQ1Q3_TOSTACK(%l1) + +1: set PAGESIZE, CNT + mov REALSRC, SRC + + ldd [SRC], %f0 + prefetch [SRC + (1 * VIS_BLOCKSIZE)], #n_reads + ldd [SRC + 0x08], %f2 + prefetch [SRC + (2 * VIS_BLOCKSIZE)], #n_reads + fmovd %f0, %f32 + ldd [SRC + 0x10], %f4 + prefetch [SRC + (3 * VIS_BLOCKSIZE)], #one_read + fmovd %f2, %f34 + ldd [SRC + 0x18], %f6 + prefetch [SRC + (4 * VIS_BLOCKSIZE)], #one_read + fmovd %f4, %f36 + ldd [SRC + 0x20], %f8 + prefetch [SRC + (5 * VIS_BLOCKSIZE)], #one_read + fmovd %f6, %f38 + ldd [SRC + 0x28], %f10 + prefetch [SRC + (6 * VIS_BLOCKSIZE)], #one_read + fmovd %f8, %f40 + ldd [SRC + 0x30], %f12 + prefetch [SRC + (7 * VIS_BLOCKSIZE)], #one_read + fmovd %f10, %f42 + ldd [SRC + 0x38], %f14 + ldd [SRC + VIS_BLOCKSIZE], %f0 + sub CNT, VIS_BLOCKSIZE, CNT + add SRC, VIS_BLOCKSIZE, SRC + prefetch [SRC + (9 * VIS_BLOCKSIZE) - VIS_BLOCKSIZE], #one_read + ba,pt %ncc, 2f + prefetch [SRC + (10 * VIS_BLOCKSIZE) - VIS_BLOCKSIZE], #one_read + .align 32 +2: + ldd [SRC + 0x08], %f2 + fmovd %f12, %f44 + ldd [SRC + 0x10], %f4 + fmovd %f14, %f46 + stda %f32, [DST]ASI_BLK_P + ldd [SRC + 0x18], %f6 + fmovd %f0, %f32 + ldd [SRC + 0x20], %f8 + fmovd %f2, %f34 + ldd [SRC + 0x28], %f10 + fmovd %f4, %f36 + ldd [SRC + 0x30], %f12 + fmovd %f6, %f38 + ldd [SRC + 0x38], %f14 + prefetch [SRC + ((OLYMPUS_C_PREFETCH) * VIS_BLOCKSIZE)], #n_reads + fmovd %f8, %f40 + ldd [SRC + VIS_BLOCKSIZE], %f0 + prefetch [SRC + ((OLYMPUS_C_2ND_PREFETCH) * VIS_BLOCKSIZE)], #one_read + fmovd %f10, %f42 + prefetch [SRC + ((OLYMPUS_C_PREFETCH) * VIS_BLOCKSIZE) + 0x20], #n_reads + prefetch [SRC + ((OLYMPUS_C_2ND_PREFETCH) * VIS_BLOCKSIZE) + 0x20], #one_read + sub CNT, VIS_BLOCKSIZE, CNT + add DST, VIS_BLOCKSIZE, DST + cmp CNT, VIS_BLOCKSIZE + 8 + bgu,pt %ncc, 2b + add SRC, VIS_BLOCKSIZE, SRC + + ! trailing block + ldd [SRC + 0x08], %f2 + fsrc1 %f12, %f44 + ldd [SRC + 0x10], %f4 + fsrc1 %f14, %f46 + stda %f32, [DST]ASI_BLK_P + ldd [SRC + 0x18], %f6 + fsrc1 %f0, %f32 + ldd [SRC + 0x20], %f8 + fsrc1 %f2, %f34 + ldd [SRC + 0x28], %f10 + fsrc1 %f4, %f36 + ldd [SRC + 0x30], %f12 + fsrc1 %f6, %f38 + ldd [SRC + 0x38], %f14 + fsrc1 %f8, %f40 + sub CNT, VIS_BLOCKSIZE, CNT + add DST, VIS_BLOCKSIZE, DST + add SRC, VIS_BLOCKSIZE, SRC + fsrc1 %f10, %f42 + fsrc1 %f12, %f44 + fsrc1 %f14, %f46 + stda %f32, [DST]ASI_BLK_P + + membar #Sync + + btst FPRS_FEF, %l0 + bz,pt %icc, 2f + nop + + BLD_FPQ1Q3_FROMSTACK(%l3) + ba 3f + nop + +2: FZEROQ1Q3 + +3: wr %l0, 0, %fprs ! restore fprs + ret + restore %g0, 0, %o0 + + SET_SIZE(hwblkpagecopy) +#endif /* lint */ + + +/* + * Transfer data to and from user space - + * Note that these routines can cause faults + * It is assumed that the kernel has nothing at + * less than KERNELBASE in the virtual address space. + * + * Note that copyin(9F) and copyout(9F) are part of the + * DDI/DKI which specifies that they return '-1' on "errors." + * + * Sigh. + * + * So there's two extremely similar routines - xcopyin() and xcopyout() + * which return the errno that we've faithfully computed. This + * allows other callers (e.g. uiomove(9F)) to work correctly. + * Given that these are used pretty heavily, we expand the calling + * sequences inline for all flavours (rather than making wrappers). + * + * There are also stub routines for xcopyout_little and xcopyin_little, + * which currently are intended to handle requests of <= 16 bytes from + * do_unaligned. Future enhancement to make them handle 8k pages efficiently + * is left as an exercise... + */ + +/* + * Copy user data to kernel space (copyOP/xcopyOP/copyOP_noerr) + * + * General theory of operation: + * + * The only difference between copy{in,out} and + * xcopy{in,out} is in the error handling routine they invoke + * when a memory access error occurs. xcopyOP returns the errno + * while copyOP returns -1 (see above). copy{in,out}_noerr set + * a special flag (by oring the TRAMP_FLAG into the fault handler address) + * if they are called with a fault handler already in place. That flag + * causes the default handlers to trampoline to the previous handler + * upon an error. + * + * None of the copyops routines grab a window until it's decided that + * we need to do a HW block copy operation. This saves a window + * spill/fill when we're called during socket ops. The typical IO + * path won't cause spill/fill traps. + * + * This code uses a set of 4 limits for the maximum size that will + * be copied given a particular input/output address alignment. + * If the value for a particular limit is zero, the copy will be performed + * by the plain copy loops rather than FPBLK. + * + * See the description of bcopy above for more details of the + * data copying algorithm and the default limits. + * + */ + +/* + * Copy kernel data to user space (copyout/xcopyout/xcopyout_little). + */ + +#if defined(lint) + + +#else /* lint */ +/* + * We save the arguments in the following registers in case of a fault: + * kaddr - %l1 + * uaddr - %l2 + * count - %l3 + */ +#define SAVE_SRC %l1 +#define SAVE_DST %l2 +#define SAVE_COUNT %l3 + +#define SM_SAVE_SRC %g4 +#define SM_SAVE_DST %g5 +#define SM_SAVE_COUNT %o5 +#define ERRNO %l5 + + +#define REAL_LOFAULT %l4 +/* + * Generic copyio fault handler. This is the first line of defense when a + * fault occurs in (x)copyin/(x)copyout. In order for this to function + * properly, the value of the 'real' lofault handler should be in REAL_LOFAULT. + * This allows us to share common code for all the flavors of the copy + * operations, including the _noerr versions. + * + * Note that this function will restore the original input parameters before + * calling REAL_LOFAULT. So the real handler can vector to the appropriate + * member of the t_copyop structure, if needed. + */ + ENTRY(copyio_fault) + membar #Sync + mov %g1,ERRNO ! save errno in ERRNO + btst FPUSED_FLAG, %l6 + bz %ncc, 1f + nop + + ldx [%fp + STACK_BIAS - SAVED_GSR_OFFSET], %o2 + wr %o2, 0, %gsr ! restore gsr + + ld [%fp + STACK_BIAS - SAVED_FPRS_OFFSET], %o3 + btst FPRS_FEF, %o3 + bz,pt %icc, 4f + nop + + BLD_FPQ2Q4_FROMSTACK(%o2) + + ba,pt %ncc, 1f + wr %o3, 0, %fprs ! restore fprs + +4: + FZEROQ2Q4 + wr %o3, 0, %fprs ! restore fprs + +1: + andn %l6, FPUSED_FLAG, %l6 + membar #Sync + stn %l6, [THREAD_REG + T_LOFAULT] ! restore old t_lofault + FP_ALLOWMIGRATE(5, 6) + + mov SAVE_SRC, %i0 + mov SAVE_DST, %i1 + jmp REAL_LOFAULT + mov SAVE_COUNT, %i2 + + SET_SIZE(copyio_fault) + + +#endif + +#if defined(lint) + +/*ARGSUSED*/ +int +copyout(const void *kaddr, void *uaddr, size_t count) +{ return (0); } + +#else /* lint */ + + ENTRY(copyout) + + cmp %o2, VIS_COPY_THRESHOLD ! check for leaf rtn case + bleu,pt %ncc, .copyout_small ! go to larger cases + xor %o0, %o1, %o3 ! are src, dst alignable? + btst 7, %o3 ! + bz,pt %ncc, .copyout_8 ! check for longword alignment + nop + btst 1, %o3 ! + bz,pt %ncc, .copyout_2 ! check for half-word + nop + sethi %hi(hw_copy_limit_1), %o3 ! Check copy limit + ld [%o3 + %lo(hw_copy_limit_1)], %o3 + tst %o3 + bz,pn %icc, .copyout_small ! if zero, disable HW copy + cmp %o2, %o3 ! if length <= limit + bleu,pt %ncc, .copyout_small ! go to small copy + nop + ba,pt %ncc, .copyout_more ! otherwise go to large copy + nop +.copyout_2: + btst 3, %o3 ! + bz,pt %ncc, .copyout_4 ! check for word alignment + nop + sethi %hi(hw_copy_limit_2), %o3 ! Check copy limit + ld [%o3 + %lo(hw_copy_limit_2)], %o3 + tst %o3 + bz,pn %icc, .copyout_small ! if zero, disable HW copy + cmp %o2, %o3 ! if length <= limit + bleu,pt %ncc, .copyout_small ! go to small copy + nop + ba,pt %ncc, .copyout_more ! otherwise go to large copy + nop +.copyout_4: + ! already checked longword, must be word aligned + sethi %hi(hw_copy_limit_4), %o3 ! Check copy limit + ld [%o3 + %lo(hw_copy_limit_4)], %o3 + tst %o3 + bz,pn %icc, .copyout_small ! if zero, disable HW copy + cmp %o2, %o3 ! if length <= limit + bleu,pt %ncc, .copyout_small ! go to small copy + nop + ba,pt %ncc, .copyout_more ! otherwise go to large copy + nop +.copyout_8: + sethi %hi(hw_copy_limit_8), %o3 ! Check copy limit + ld [%o3 + %lo(hw_copy_limit_8)], %o3 + tst %o3 + bz,pn %icc, .copyout_small ! if zero, disable HW copy + cmp %o2, %o3 ! if length <= limit + bleu,pt %ncc, .copyout_small ! go to small copy + nop + ba,pt %ncc, .copyout_more ! otherwise go to large copy + nop + + .align 16 + nop ! instruction alignment + ! see discussion at start of file +.copyout_small: + sethi %hi(.sm_copyout_err), %o5 ! .sm_copyout_err is lofault + or %o5, %lo(.sm_copyout_err), %o5 + ldn [THREAD_REG + T_LOFAULT], %o4 ! save existing handler + membar #Sync ! sync error barrier + stn %o5, [THREAD_REG + T_LOFAULT] ! set t_lofault +.sm_do_copyout: + mov %o0, SM_SAVE_SRC + mov %o1, SM_SAVE_DST + cmp %o2, SHORTCOPY ! check for really short case + bleu,pt %ncc, .co_sm_left ! + mov %o2, SM_SAVE_COUNT + cmp %o2, CHKSIZE ! check for medium length cases + bgu,pn %ncc, .co_med ! + or %o0, %o1, %o3 ! prepare alignment check + andcc %o3, 0x3, %g0 ! test for alignment + bz,pt %ncc, .co_sm_word ! branch to word aligned case +.co_sm_movebytes: + sub %o2, 3, %o2 ! adjust count to allow cc zero test +.co_sm_notalign4: + ldub [%o0], %o3 ! read byte + subcc %o2, 4, %o2 ! reduce count by 4 + stba %o3, [%o1]ASI_USER ! write byte + inc %o1 ! advance DST by 1 + ldub [%o0 + 1], %o3 ! repeat for a total of 4 bytes + add %o0, 4, %o0 ! advance SRC by 4 + stba %o3, [%o1]ASI_USER + inc %o1 ! advance DST by 1 + ldub [%o0 - 2], %o3 + stba %o3, [%o1]ASI_USER + inc %o1 ! advance DST by 1 + ldub [%o0 - 1], %o3 + stba %o3, [%o1]ASI_USER + bgt,pt %ncc, .co_sm_notalign4 ! loop til 3 or fewer bytes remain + inc %o1 ! advance DST by 1 + add %o2, 3, %o2 ! restore count +.co_sm_left: + tst %o2 + bz,pt %ncc, .co_sm_exit ! check for zero length + nop + ldub [%o0], %o3 ! load one byte + deccc %o2 ! reduce count for cc test + bz,pt %ncc, .co_sm_exit + stba %o3,[%o1]ASI_USER ! store one byte + ldub [%o0 + 1], %o3 ! load second byte + deccc %o2 + inc %o1 + bz,pt %ncc, .co_sm_exit + stba %o3,[%o1]ASI_USER ! store second byte + ldub [%o0 + 2], %o3 ! load third byte + inc %o1 + stba %o3,[%o1]ASI_USER ! store third byte + membar #Sync ! sync error barrier + stn %o4, [THREAD_REG + T_LOFAULT] ! restore old t_lofault + retl + mov %g0, %o0 ! return 0 + .align 16 +.co_sm_words: + lduw [%o0], %o3 ! read word +.co_sm_wordx: + subcc %o2, 8, %o2 ! update count + stwa %o3, [%o1]ASI_USER ! write word + add %o0, 8, %o0 ! update SRC + lduw [%o0 - 4], %o3 ! read word + add %o1, 4, %o1 ! update DST + stwa %o3, [%o1]ASI_USER ! write word + bgt,pt %ncc, .co_sm_words ! loop til done + add %o1, 4, %o1 ! update DST + addcc %o2, 7, %o2 ! restore count + bz,pt %ncc, .co_sm_exit + nop + deccc %o2 + bz,pt %ncc, .co_sm_byte +.co_sm_half: + subcc %o2, 2, %o2 ! reduce count by 2 + lduh [%o0], %o3 ! read half word + add %o0, 2, %o0 ! advance SRC by 2 + stha %o3, [%o1]ASI_USER ! write half word + bgt,pt %ncc, .co_sm_half ! loop til done + add %o1, 2, %o1 ! advance DST by 2 + addcc %o2, 1, %o2 ! restore count + bz,pt %ncc, .co_sm_exit + nop +.co_sm_byte: + ldub [%o0], %o3 + stba %o3, [%o1]ASI_USER + membar #Sync ! sync error barrier + stn %o4, [THREAD_REG + T_LOFAULT] ! restore old t_lofault + retl + mov %g0, %o0 ! return 0 + .align 16 +.co_sm_word: + subcc %o2, 4, %o2 ! update count + bgt,pt %ncc, .co_sm_wordx + lduw [%o0], %o3 ! read word + addcc %o2, 3, %o2 ! restore count + bz,pt %ncc, .co_sm_exit + stwa %o3, [%o1]ASI_USER ! write word + deccc %o2 ! reduce count for cc test + ldub [%o0 + 4], %o3 ! load one byte + add %o1, 4, %o1 + bz,pt %ncc, .co_sm_exit + stba %o3, [%o1]ASI_USER ! store one byte + ldub [%o0 + 5], %o3 ! load second byte + deccc %o2 + inc %o1 + bz,pt %ncc, .co_sm_exit + stba %o3, [%o1]ASI_USER ! store second byte + ldub [%o0 + 6], %o3 ! load third byte + inc %o1 + stba %o3, [%o1]ASI_USER ! store third byte +.co_sm_exit: + membar #Sync ! sync error barrier + stn %o4, [THREAD_REG + T_LOFAULT] ! restore old t_lofault + retl + mov %g0, %o0 ! return 0 + + .align 16 +.co_med: + xor %o0, %o1, %o3 ! setup alignment check + btst 1, %o3 + bnz,pt %ncc, .co_sm_movebytes ! unaligned + nop + btst 3, %o3 + bnz,pt %ncc, .co_med_half ! halfword aligned + nop + btst 7, %o3 + bnz,pt %ncc, .co_med_word ! word aligned + nop +.co_med_long: + btst 3, %o0 ! check for + bz,pt %ncc, .co_med_long1 ! word alignment + nop +.co_med_long0: + ldub [%o0], %o3 ! load one byte + inc %o0 + stba %o3,[%o1]ASI_USER ! store byte + inc %o1 + btst 3, %o0 + bnz,pt %ncc, .co_med_long0 + dec %o2 +.co_med_long1: ! word aligned + btst 7, %o0 ! check for long word + bz,pt %ncc, .co_med_long2 + nop + lduw [%o0], %o3 ! load word + add %o0, 4, %o0 ! advance SRC by 4 + stwa %o3, [%o1]ASI_USER ! store word + add %o1, 4, %o1 ! advance DST by 4 + sub %o2, 4, %o2 ! reduce count by 4 +! +! Now long word aligned and have at least 32 bytes to move +! +.co_med_long2: + sub %o2, 31, %o2 ! adjust count to allow cc zero test + sub %o1, 8, %o1 ! adjust pointer to allow store in + ! branch delay slot instead of add +.co_med_lmove: + add %o1, 8, %o1 ! advance DST by 8 + ldx [%o0], %o3 ! read long word + subcc %o2, 32, %o2 ! reduce count by 32 + stxa %o3, [%o1]ASI_USER ! write long word + add %o1, 8, %o1 ! advance DST by 8 + ldx [%o0 + 8], %o3 ! repeat for a total for 4 long words + add %o0, 32, %o0 ! advance SRC by 32 + stxa %o3, [%o1]ASI_USER + ldx [%o0 - 16], %o3 + add %o1, 8, %o1 ! advance DST by 8 + stxa %o3, [%o1]ASI_USER + ldx [%o0 - 8], %o3 + add %o1, 8, %o1 ! advance DST by 8 + bgt,pt %ncc, .co_med_lmove ! loop til 31 or fewer bytes left + stxa %o3, [%o1]ASI_USER + add %o1, 8, %o1 ! advance DST by 8 + addcc %o2, 24, %o2 ! restore count to long word offset + ble,pt %ncc, .co_med_lextra ! check for more long words to move + nop +.co_med_lword: + ldx [%o0], %o3 ! read long word + subcc %o2, 8, %o2 ! reduce count by 8 + stxa %o3, [%o1]ASI_USER ! write long word + add %o0, 8, %o0 ! advance SRC by 8 + bgt,pt %ncc, .co_med_lword ! loop til 7 or fewer bytes left + add %o1, 8, %o1 ! advance DST by 8 +.co_med_lextra: + addcc %o2, 7, %o2 ! restore rest of count + bz,pt %ncc, .co_sm_exit ! if zero, then done + deccc %o2 + bz,pt %ncc, .co_sm_byte + nop + ba,pt %ncc, .co_sm_half + nop + + .align 16 + nop ! instruction alignment + ! see discussion at start of file +.co_med_word: + btst 3, %o0 ! check for + bz,pt %ncc, .co_med_word1 ! word alignment + nop +.co_med_word0: + ldub [%o0], %o3 ! load one byte + inc %o0 + stba %o3,[%o1]ASI_USER ! store byte + inc %o1 + btst 3, %o0 + bnz,pt %ncc, .co_med_word0 + dec %o2 +! +! Now word aligned and have at least 36 bytes to move +! +.co_med_word1: + sub %o2, 15, %o2 ! adjust count to allow cc zero test +.co_med_wmove: + lduw [%o0], %o3 ! read word + subcc %o2, 16, %o2 ! reduce count by 16 + stwa %o3, [%o1]ASI_USER ! write word + add %o1, 4, %o1 ! advance DST by 4 + lduw [%o0 + 4], %o3 ! repeat for a total for 4 words + add %o0, 16, %o0 ! advance SRC by 16 + stwa %o3, [%o1]ASI_USER + add %o1, 4, %o1 ! advance DST by 4 + lduw [%o0 - 8], %o3 + stwa %o3, [%o1]ASI_USER + add %o1, 4, %o1 ! advance DST by 4 + lduw [%o0 - 4], %o3 + stwa %o3, [%o1]ASI_USER + bgt,pt %ncc, .co_med_wmove ! loop til 15 or fewer bytes left + add %o1, 4, %o1 ! advance DST by 4 + addcc %o2, 12, %o2 ! restore count to word offset + ble,pt %ncc, .co_med_wextra ! check for more words to move + nop +.co_med_word2: + lduw [%o0], %o3 ! read word + subcc %o2, 4, %o2 ! reduce count by 4 + stwa %o3, [%o1]ASI_USER ! write word + add %o0, 4, %o0 ! advance SRC by 4 + bgt,pt %ncc, .co_med_word2 ! loop til 3 or fewer bytes left + add %o1, 4, %o1 ! advance DST by 4 +.co_med_wextra: + addcc %o2, 3, %o2 ! restore rest of count + bz,pt %ncc, .co_sm_exit ! if zero, then done + deccc %o2 + bz,pt %ncc, .co_sm_byte + nop + ba,pt %ncc, .co_sm_half + nop + + .align 16 + nop ! instruction alignment + nop ! see discussion at start of file + nop +.co_med_half: + btst 1, %o0 ! check for + bz,pt %ncc, .co_med_half1 ! half word alignment + nop + ldub [%o0], %o3 ! load one byte + inc %o0 + stba %o3,[%o1]ASI_USER ! store byte + inc %o1 + dec %o2 +! +! Now half word aligned and have at least 38 bytes to move +! +.co_med_half1: + sub %o2, 7, %o2 ! adjust count to allow cc zero test +.co_med_hmove: + lduh [%o0], %o3 ! read half word + subcc %o2, 8, %o2 ! reduce count by 8 + stha %o3, [%o1]ASI_USER ! write half word + add %o1, 2, %o1 ! advance DST by 2 + lduh [%o0 + 2], %o3 ! repeat for a total for 4 halfwords + add %o0, 8, %o0 ! advance SRC by 8 + stha %o3, [%o1]ASI_USER + add %o1, 2, %o1 ! advance DST by 2 + lduh [%o0 - 4], %o3 + stha %o3, [%o1]ASI_USER + add %o1, 2, %o1 ! advance DST by 2 + lduh [%o0 - 2], %o3 + stha %o3, [%o1]ASI_USER + bgt,pt %ncc, .co_med_hmove ! loop til 7 or fewer bytes left + add %o1, 2, %o1 ! advance DST by 2 + addcc %o2, 7, %o2 ! restore count + bz,pt %ncc, .co_sm_exit + deccc %o2 + bz,pt %ncc, .co_sm_byte + nop + ba,pt %ncc, .co_sm_half + nop + +/* + * We got here because of a fault during short copyout. + * Errno value is in ERRNO, but DDI/DKI says return -1 (sigh). + */ +.sm_copyout_err: + membar #Sync + stn %o4, [THREAD_REG + T_LOFAULT] ! restore old t_lofault + mov SM_SAVE_SRC, %o0 + mov SM_SAVE_DST, %o1 + mov SM_SAVE_COUNT, %o2 + ldn [THREAD_REG + T_COPYOPS], %o3 ! check for copyop handler + tst %o3 + bz,pt %ncc, 3f ! if not, return error + nop + ldn [%o3 + CP_COPYOUT], %o5 ! if handler, invoke it with + jmp %o5 ! original arguments + nop +3: + retl + or %g0, -1, %o0 ! return error value + + SET_SIZE(copyout) + +/* + * The _more entry points are not intended to be used directly by + * any caller from outside this file. They are provided to allow + * profiling and dtrace of the portions of the copy code that uses + * the floating point registers. + * This entry is particularly important as DTRACE (at least as of + * 4/2004) does not support leaf functions. + */ + + ENTRY(copyout_more) +.copyout_more: + prefetch [%o0], #n_reads + save %sp, -SA(MINFRAME + HWCOPYFRAMESIZE), %sp + set .copyout_err, REAL_LOFAULT + +/* + * Copy outs that reach here are larger than VIS_COPY_THRESHOLD bytes + */ +.do_copyout: + set copyio_fault, %l7 ! .copyio_fault is lofault val + + ldn [THREAD_REG + T_LOFAULT], %l6 ! save existing handler + membar #Sync ! sync error barrier + stn %l7, [THREAD_REG + T_LOFAULT] ! set t_lofault + + mov %i0, SAVE_SRC + mov %i1, SAVE_DST + mov %i2, SAVE_COUNT + + FP_NOMIGRATE(6, 7) + + rd %fprs, %o2 ! check for unused fp + st %o2, [%fp + STACK_BIAS - SAVED_FPRS_OFFSET] ! save orig %fprs + btst FPRS_FEF, %o2 + bz,a,pt %icc, .do_blockcopyout + wr %g0, FPRS_FEF, %fprs + + BST_FPQ2Q4_TOSTACK(%o2) + +.do_blockcopyout: + rd %gsr, %o2 + stx %o2, [%fp + STACK_BIAS - SAVED_GSR_OFFSET] ! save gsr + or %l6, FPUSED_FLAG, %l6 + + andcc DST, VIS_BLOCKSIZE - 1, TMP + mov ASI_USER, %asi + bz,pt %ncc, 2f + neg TMP + add TMP, VIS_BLOCKSIZE, TMP + + ! TMP = bytes required to align DST on FP_BLOCK boundary + ! Using SRC as a tmp here + cmp TMP, 3 + bleu,pt %ncc, 1f + sub CNT,TMP,CNT ! adjust main count + sub TMP, 3, TMP ! adjust for end of loop test +.co_blkalign: + ldub [REALSRC], SRC ! move 4 bytes per loop iteration + stba SRC, [DST]%asi + subcc TMP, 4, TMP + ldub [REALSRC + 1], SRC + add REALSRC, 4, REALSRC + stba SRC, [DST + 1]%asi + ldub [REALSRC - 2], SRC + add DST, 4, DST + stba SRC, [DST - 2]%asi + ldub [REALSRC - 1], SRC + bgu,pt %ncc, .co_blkalign + stba SRC, [DST - 1]%asi + + addcc TMP, 3, TMP ! restore count adjustment + bz,pt %ncc, 2f ! no bytes left? + nop +1: ldub [REALSRC], SRC + inc REALSRC + inc DST + deccc TMP + bgu %ncc, 1b + stba SRC, [DST - 1]%asi + +2: + membar #StoreLoad + andn REALSRC, 0x7, SRC + + ! SRC - 8-byte aligned + ! DST - 64-byte aligned + ldd [SRC], %f16 + prefetch [SRC + (1 * VIS_BLOCKSIZE)], #n_reads + alignaddr REALSRC, %g0, %g0 + ldd [SRC + 0x08], %f18 + prefetch [SRC + (2 * VIS_BLOCKSIZE)], #n_reads + faligndata %f16, %f18, %f48 + ldd [SRC + 0x10], %f20 + prefetch [SRC + (3 * VIS_BLOCKSIZE)], #one_read + faligndata %f18, %f20, %f50 + ldd [SRC + 0x18], %f22 + prefetch [SRC + (4 * VIS_BLOCKSIZE)], #one_read + faligndata %f20, %f22, %f52 + ldd [SRC + 0x20], %f24 + prefetch [SRC + (5 * VIS_BLOCKSIZE)], #one_read + faligndata %f22, %f24, %f54 + ldd [SRC + 0x28], %f26 + prefetch [SRC + (6 * VIS_BLOCKSIZE)], #one_read + faligndata %f24, %f26, %f56 + ldd [SRC + 0x30], %f28 + prefetch [SRC + (7 * VIS_BLOCKSIZE)], #one_read + faligndata %f26, %f28, %f58 + ldd [SRC + 0x38], %f30 + ldd [SRC + VIS_BLOCKSIZE], %f16 + sub CNT, VIS_BLOCKSIZE, CNT + add SRC, VIS_BLOCKSIZE, SRC + prefetch [SRC + (9 * VIS_BLOCKSIZE) - VIS_BLOCKSIZE], #one_read + add REALSRC, VIS_BLOCKSIZE, REALSRC + ba,pt %ncc, 1f + prefetch [SRC + (10 * VIS_BLOCKSIZE) - VIS_BLOCKSIZE], #one_read + .align 32 +1: + ldd [SRC + 0x08], %f18 + faligndata %f28, %f30, %f60 + ldd [SRC + 0x10], %f20 + faligndata %f30, %f16, %f62 + stda %f48, [DST]ASI_BLK_AIUS + ldd [SRC + 0x18], %f22 + faligndata %f16, %f18, %f48 + ldd [SRC + 0x20], %f24 + faligndata %f18, %f20, %f50 + ldd [SRC + 0x28], %f26 + faligndata %f20, %f22, %f52 + ldd [SRC + 0x30], %f28 + faligndata %f22, %f24, %f54 + ldd [SRC + 0x38], %f30 + prefetch [SRC + ((OLYMPUS_C_PREFETCH) * VIS_BLOCKSIZE)], #n_reads + faligndata %f24, %f26, %f56 + ldd [SRC + VIS_BLOCKSIZE], %f16 + prefetch [SRC + ((OLYMPUS_C_2ND_PREFETCH) * VIS_BLOCKSIZE)], #one_read + faligndata %f26, %f28, %f58 + prefetch [SRC + ((OLYMPUS_C_PREFETCH) * VIS_BLOCKSIZE) + 0x20], #n_reads + prefetch [SRC + ((OLYMPUS_C_2ND_PREFETCH) * VIS_BLOCKSIZE) + 0x20], #one_read + sub CNT, VIS_BLOCKSIZE, CNT + add DST, VIS_BLOCKSIZE, DST + add REALSRC, VIS_BLOCKSIZE, REALSRC + cmp CNT, VIS_BLOCKSIZE + 8 + bgu,pt %ncc, 1b + add SRC, VIS_BLOCKSIZE, SRC + + ! only if REALSRC & 0x7 is 0 + cmp CNT, VIS_BLOCKSIZE + bne %ncc, 3f + andcc REALSRC, 0x7, %g0 + bz,pt %ncc, 2f + nop +3: + faligndata %f28, %f30, %f60 + faligndata %f30, %f16, %f62 + stda %f48, [DST]ASI_BLK_AIUS + add DST, VIS_BLOCKSIZE, DST + ba,pt %ncc, 3f + nop +2: + ldd [SRC + 0x08], %f18 + fsrc1 %f28, %f60 + ldd [SRC + 0x10], %f20 + fsrc1 %f30, %f62 + stda %f48, [DST]ASI_BLK_AIUS + ldd [SRC + 0x18], %f22 + fsrc1 %f16, %f48 + ldd [SRC + 0x20], %f24 + fsrc1 %f18, %f50 + ldd [SRC + 0x28], %f26 + fsrc1 %f20, %f52 + ldd [SRC + 0x30], %f28 + fsrc1 %f22, %f54 + ldd [SRC + 0x38], %f30 + fsrc1 %f24, %f56 + sub CNT, VIS_BLOCKSIZE, CNT + add DST, VIS_BLOCKSIZE, DST + add SRC, VIS_BLOCKSIZE, SRC + add REALSRC, VIS_BLOCKSIZE, REALSRC + fsrc1 %f26, %f58 + fsrc1 %f28, %f60 + fsrc1 %f30, %f62 + stda %f48, [DST]ASI_BLK_AIUS + add DST, VIS_BLOCKSIZE, DST + ba,a,pt %ncc, 4f + nop + +3: tst CNT + bz,a %ncc, 4f + nop + +5: ldub [REALSRC], TMP + inc REALSRC + inc DST + deccc CNT + bgu %ncc, 5b + stba TMP, [DST - 1]%asi +4: + +.copyout_exit: + membar #Sync + + ldx [%fp + STACK_BIAS - SAVED_GSR_OFFSET], %o2 + wr %o2, 0, %gsr ! restore gsr + + ld [%fp + STACK_BIAS - SAVED_FPRS_OFFSET], %o3 + btst FPRS_FEF, %o3 + bz,pt %icc, 4f + nop + + BLD_FPQ2Q4_FROMSTACK(%o2) + + ba,pt %ncc, 1f + wr %o3, 0, %fprs ! restore fprs + +4: + FZEROQ2Q4 + wr %o3, 0, %fprs ! restore fprs + +1: + membar #Sync + andn %l6, FPUSED_FLAG, %l6 + stn %l6, [THREAD_REG + T_LOFAULT] ! restore old t_lofault + FP_ALLOWMIGRATE(5, 6) + ret + restore %g0, 0, %o0 + +/* + * We got here because of a fault during copyout. + * Errno value is in ERRNO, but DDI/DKI says return -1 (sigh). + */ +.copyout_err: + ldn [THREAD_REG + T_COPYOPS], %o4 ! check for copyop handler + tst %o4 + bz,pt %ncc, 2f ! if not, return error + nop + ldn [%o4 + CP_COPYOUT], %g2 ! if handler, invoke it with + jmp %g2 ! original arguments + restore %g0, 0, %g0 ! dispose of copy window +2: + ret + restore %g0, -1, %o0 ! return error value + + + SET_SIZE(copyout_more) + +#endif /* lint */ + + +#ifdef lint + +/*ARGSUSED*/ +int +xcopyout(const void *kaddr, void *uaddr, size_t count) +{ return (0); } + +#else /* lint */ + + ENTRY(xcopyout) + cmp %o2, VIS_COPY_THRESHOLD ! check for leaf rtn case + bleu,pt %ncc, .xcopyout_small ! go to larger cases + xor %o0, %o1, %o3 ! are src, dst alignable? + btst 7, %o3 ! + bz,pt %ncc, .xcopyout_8 ! + nop + btst 1, %o3 ! + bz,pt %ncc, .xcopyout_2 ! check for half-word + nop + sethi %hi(hw_copy_limit_1), %o3 ! Check copy limit + ld [%o3 + %lo(hw_copy_limit_1)], %o3 + tst %o3 + bz,pn %icc, .xcopyout_small ! if zero, disable HW copy + cmp %o2, %o3 ! if length <= limit + bleu,pt %ncc, .xcopyout_small ! go to small copy + nop + ba,pt %ncc, .xcopyout_more ! otherwise go to large copy + nop +.xcopyout_2: + btst 3, %o3 ! + bz,pt %ncc, .xcopyout_4 ! check for word alignment + nop + sethi %hi(hw_copy_limit_2), %o3 ! Check copy limit + ld [%o3 + %lo(hw_copy_limit_2)], %o3 + tst %o3 + bz,pn %icc, .xcopyout_small ! if zero, disable HW copy + cmp %o2, %o3 ! if length <= limit + bleu,pt %ncc, .xcopyout_small ! go to small copy + nop + ba,pt %ncc, .xcopyout_more ! otherwise go to large copy + nop +.xcopyout_4: + ! already checked longword, must be word aligned + sethi %hi(hw_copy_limit_4), %o3 ! Check copy limit + ld [%o3 + %lo(hw_copy_limit_4)], %o3 + tst %o3 + bz,pn %icc, .xcopyout_small ! if zero, disable HW copy + cmp %o2, %o3 ! if length <= limit + bleu,pt %ncc, .xcopyout_small ! go to small copy + nop + ba,pt %ncc, .xcopyout_more ! otherwise go to large copy + nop +.xcopyout_8: + sethi %hi(hw_copy_limit_8), %o3 ! Check copy limit + ld [%o3 + %lo(hw_copy_limit_8)], %o3 + tst %o3 + bz,pn %icc, .xcopyout_small ! if zero, disable HW copy + cmp %o2, %o3 ! if length <= limit + bleu,pt %ncc, .xcopyout_small ! go to small copy + nop + ba,pt %ncc, .xcopyout_more ! otherwise go to large copy + nop + +.xcopyout_small: + sethi %hi(.sm_xcopyout_err), %o5 ! .sm_xcopyout_err is lofault + or %o5, %lo(.sm_xcopyout_err), %o5 + ldn [THREAD_REG + T_LOFAULT], %o4 ! save existing handler + membar #Sync ! sync error barrier + ba,pt %ncc, .sm_do_copyout ! common code + stn %o5, [THREAD_REG + T_LOFAULT] ! set t_lofault + +.xcopyout_more: + save %sp, -SA(MINFRAME + HWCOPYFRAMESIZE), %sp + sethi %hi(.xcopyout_err), REAL_LOFAULT + ba,pt %ncc, .do_copyout ! common code + or REAL_LOFAULT, %lo(.xcopyout_err), REAL_LOFAULT + +/* + * We got here because of fault during xcopyout + * Errno value is in ERRNO + */ +.xcopyout_err: + ldn [THREAD_REG + T_COPYOPS], %o4 ! check for copyop handler + tst %o4 + bz,pt %ncc, 2f ! if not, return error + nop + ldn [%o4 + CP_XCOPYOUT], %g2 ! if handler, invoke it with + jmp %g2 ! original arguments + restore %g0, 0, %g0 ! dispose of copy window +2: + ret + restore ERRNO, 0, %o0 ! return errno value + +.sm_xcopyout_err: + + membar #Sync + stn %o4, [THREAD_REG + T_LOFAULT] ! restore old t_lofault + mov SM_SAVE_SRC, %o0 + mov SM_SAVE_DST, %o1 + mov SM_SAVE_COUNT, %o2 + ldn [THREAD_REG + T_COPYOPS], %o3 ! check for copyop handler + tst %o3 + bz,pt %ncc, 3f ! if not, return error + nop + ldn [%o3 + CP_XCOPYOUT], %o5 ! if handler, invoke it with + jmp %o5 ! original arguments + nop +3: + retl + or %g1, 0, %o0 ! return errno value + + SET_SIZE(xcopyout) + +#endif /* lint */ + +#ifdef lint + +/*ARGSUSED*/ +int +xcopyout_little(const void *kaddr, void *uaddr, size_t count) +{ return (0); } + +#else /* lint */ + + ENTRY(xcopyout_little) + sethi %hi(.xcopyio_err), %o5 + or %o5, %lo(.xcopyio_err), %o5 + ldn [THREAD_REG + T_LOFAULT], %o4 + membar #Sync ! sync error barrier + stn %o5, [THREAD_REG + T_LOFAULT] + mov %o4, %o5 + + subcc %g0, %o2, %o3 + add %o0, %o2, %o0 + bz,pn %ncc, 2f ! check for zero bytes + sub %o2, 1, %o4 + add %o0, %o4, %o0 ! start w/last byte + add %o1, %o2, %o1 + ldub [%o0 + %o3], %o4 + +1: stba %o4, [%o1 + %o3]ASI_AIUSL + inccc %o3 + sub %o0, 2, %o0 ! get next byte + bcc,a,pt %ncc, 1b + ldub [%o0 + %o3], %o4 + +2: + membar #Sync ! sync error barrier + stn %o5, [THREAD_REG + T_LOFAULT] ! restore old t_lofault + retl + mov %g0, %o0 ! return (0) + + SET_SIZE(xcopyout_little) + +#endif /* lint */ + +/* + * Copy user data to kernel space (copyin/xcopyin/xcopyin_little) + */ + +#if defined(lint) + +/*ARGSUSED*/ +int +copyin(const void *uaddr, void *kaddr, size_t count) +{ return (0); } + +#else /* lint */ + + ENTRY(copyin) + cmp %o2, VIS_COPY_THRESHOLD ! check for leaf rtn case + bleu,pt %ncc, .copyin_small ! go to larger cases + xor %o0, %o1, %o3 ! are src, dst alignable? + btst 7, %o3 ! + bz,pt %ncc, .copyin_8 ! check for longword alignment + nop + btst 1, %o3 ! + bz,pt %ncc, .copyin_2 ! check for half-word + nop + sethi %hi(hw_copy_limit_1), %o3 ! Check copy limit + ld [%o3 + %lo(hw_copy_limit_1)], %o3 + tst %o3 + bz,pn %icc, .copyin_small ! if zero, disable HW copy + cmp %o2, %o3 ! if length <= limit + bleu,pt %ncc, .copyin_small ! go to small copy + nop + ba,pt %ncc, .copyin_more ! otherwise go to large copy + nop +.copyin_2: + btst 3, %o3 ! + bz,pt %ncc, .copyin_4 ! check for word alignment + nop + sethi %hi(hw_copy_limit_2), %o3 ! Check copy limit + ld [%o3 + %lo(hw_copy_limit_2)], %o3 + tst %o3 + bz,pn %icc, .copyin_small ! if zero, disable HW copy + cmp %o2, %o3 ! if length <= limit + bleu,pt %ncc, .copyin_small ! go to small copy + nop + ba,pt %ncc, .copyin_more ! otherwise go to large copy + nop +.copyin_4: + ! already checked longword, must be word aligned + sethi %hi(hw_copy_limit_4), %o3 ! Check copy limit + ld [%o3 + %lo(hw_copy_limit_4)], %o3 + tst %o3 + bz,pn %icc, .copyin_small ! if zero, disable HW copy + cmp %o2, %o3 ! if length <= limit + bleu,pt %ncc, .copyin_small ! go to small copy + nop + ba,pt %ncc, .copyin_more ! otherwise go to large copy + nop +.copyin_8: + sethi %hi(hw_copy_limit_8), %o3 ! Check copy limit + ld [%o3 + %lo(hw_copy_limit_8)], %o3 + tst %o3 + bz,pn %icc, .copyin_small ! if zero, disable HW copy + cmp %o2, %o3 ! if length <= limit + bleu,pt %ncc, .copyin_small ! go to small copy + nop + ba,pt %ncc, .copyin_more ! otherwise go to large copy + nop + + .align 16 + nop ! instruction alignment + ! see discussion at start of file +.copyin_small: + sethi %hi(.sm_copyin_err), %o5 ! .sm_copyin_err is lofault + or %o5, %lo(.sm_copyin_err), %o5 + ldn [THREAD_REG + T_LOFAULT], %o4 ! set/save t_lofault, no tramp + membar #Sync ! sync error barrier + stn %o5, [THREAD_REG + T_LOFAULT] +.sm_do_copyin: + mov %o0, SM_SAVE_SRC + mov %o1, SM_SAVE_DST + cmp %o2, SHORTCOPY ! check for really short case + bleu,pt %ncc, .ci_sm_left ! + mov %o2, SM_SAVE_COUNT + cmp %o2, CHKSIZE ! check for medium length cases + bgu,pn %ncc, .ci_med ! + or %o0, %o1, %o3 ! prepare alignment check + andcc %o3, 0x3, %g0 ! test for alignment + bz,pt %ncc, .ci_sm_word ! branch to word aligned case +.ci_sm_movebytes: + sub %o2, 3, %o2 ! adjust count to allow cc zero test +.ci_sm_notalign4: + lduba [%o0]ASI_USER, %o3 ! read byte + subcc %o2, 4, %o2 ! reduce count by 4 + stb %o3, [%o1] ! write byte + add %o0, 1, %o0 ! advance SRC by 1 + lduba [%o0]ASI_USER, %o3 ! repeat for a total of 4 bytes + add %o0, 1, %o0 ! advance SRC by 1 + stb %o3, [%o1 + 1] + add %o1, 4, %o1 ! advance DST by 4 + lduba [%o0]ASI_USER, %o3 + add %o0, 1, %o0 ! advance SRC by 1 + stb %o3, [%o1 - 2] + lduba [%o0]ASI_USER, %o3 + add %o0, 1, %o0 ! advance SRC by 1 + bgt,pt %ncc, .ci_sm_notalign4 ! loop til 3 or fewer bytes remain + stb %o3, [%o1 - 1] + add %o2, 3, %o2 ! restore count +.ci_sm_left: + tst %o2 + bz,pt %ncc, .ci_sm_exit + nop + lduba [%o0]ASI_USER, %o3 ! load one byte + deccc %o2 ! reduce count for cc test + bz,pt %ncc, .ci_sm_exit + stb %o3,[%o1] ! store one byte + inc %o0 + lduba [%o0]ASI_USER, %o3 ! load second byte + deccc %o2 + bz,pt %ncc, .ci_sm_exit + stb %o3,[%o1 + 1] ! store second byte + inc %o0 + lduba [%o0]ASI_USER, %o3 ! load third byte + stb %o3,[%o1 + 2] ! store third byte + membar #Sync ! sync error barrier + stn %o4, [THREAD_REG + T_LOFAULT] ! restore old t_lofault + retl + mov %g0, %o0 ! return 0 + .align 16 +.ci_sm_words: + lduwa [%o0]ASI_USER, %o3 ! read word +.ci_sm_wordx: + subcc %o2, 8, %o2 ! update count + stw %o3, [%o1] ! write word + add %o0, 4, %o0 ! update SRC + add %o1, 8, %o1 ! update DST + lduwa [%o0]ASI_USER, %o3 ! read word + add %o0, 4, %o0 ! update SRC + bgt,pt %ncc, .ci_sm_words ! loop til done + stw %o3, [%o1 - 4] ! write word + addcc %o2, 7, %o2 ! restore count + bz,pt %ncc, .ci_sm_exit + nop + deccc %o2 + bz,pt %ncc, .ci_sm_byte +.ci_sm_half: + subcc %o2, 2, %o2 ! reduce count by 2 + lduha [%o0]ASI_USER, %o3 ! read half word + add %o0, 2, %o0 ! advance SRC by 2 + add %o1, 2, %o1 ! advance DST by 2 + bgt,pt %ncc, .ci_sm_half ! loop til done + sth %o3, [%o1 - 2] ! write half word + addcc %o2, 1, %o2 ! restore count + bz,pt %ncc, .ci_sm_exit + nop +.ci_sm_byte: + lduba [%o0]ASI_USER, %o3 + stb %o3, [%o1] + membar #Sync ! sync error barrier + stn %o4, [THREAD_REG + T_LOFAULT] ! restore old t_lofault + retl + mov %g0, %o0 ! return 0 + .align 16 +.ci_sm_word: + subcc %o2, 4, %o2 ! update count + bgt,pt %ncc, .ci_sm_wordx + lduwa [%o0]ASI_USER, %o3 ! read word + addcc %o2, 3, %o2 ! restore count + bz,pt %ncc, .ci_sm_exit + stw %o3, [%o1] ! write word + deccc %o2 ! reduce count for cc test + add %o0, 4, %o0 + lduba [%o0]ASI_USER, %o3 ! load one byte + bz,pt %ncc, .ci_sm_exit + stb %o3, [%o1 + 4] ! store one byte + inc %o0 + lduba [%o0]ASI_USER, %o3 ! load second byte + deccc %o2 + bz,pt %ncc, .ci_sm_exit + stb %o3, [%o1 + 5] ! store second byte + inc %o0 + lduba [%o0]ASI_USER, %o3 ! load third byte + stb %o3, [%o1 + 6] ! store third byte +.ci_sm_exit: + membar #Sync ! sync error barrier + stn %o4, [THREAD_REG + T_LOFAULT] ! restore old t_lofault + retl + mov %g0, %o0 ! return 0 + + .align 16 +.ci_med: + xor %o0, %o1, %o3 ! setup alignment check + btst 1, %o3 + bnz,pt %ncc, .ci_sm_movebytes ! unaligned + nop + btst 3, %o3 + bnz,pt %ncc, .ci_med_half ! halfword aligned + nop + btst 7, %o3 + bnz,pt %ncc, .ci_med_word ! word aligned + nop +.ci_med_long: + btst 3, %o0 ! check for + bz,pt %ncc, .ci_med_long1 ! word alignment + nop +.ci_med_long0: + lduba [%o0]ASI_USER, %o3 ! load one byte + inc %o0 + stb %o3,[%o1] ! store byte + inc %o1 + btst 3, %o0 + bnz,pt %ncc, .ci_med_long0 + dec %o2 +.ci_med_long1: ! word aligned + btst 7, %o0 ! check for long word + bz,pt %ncc, .ci_med_long2 + nop + lduwa [%o0]ASI_USER, %o3 ! load word + add %o0, 4, %o0 ! advance SRC by 4 + stw %o3, [%o1] ! store word + add %o1, 4, %o1 ! advance DST by 4 + sub %o2, 4, %o2 ! reduce count by 4 +! +! Now long word aligned and have at least 32 bytes to move +! +.ci_med_long2: + sub %o2, 31, %o2 ! adjust count to allow cc zero test +.ci_med_lmove: + ldxa [%o0]ASI_USER, %o3 ! read long word + subcc %o2, 32, %o2 ! reduce count by 32 + stx %o3, [%o1] ! write long word + add %o0, 8, %o0 ! advance SRC by 8 + ldxa [%o0]ASI_USER, %o3 ! repeat for a total for 4 long words + add %o0, 8, %o0 ! advance SRC by 8 + stx %o3, [%o1 + 8] + add %o1, 32, %o1 ! advance DST by 32 + ldxa [%o0]ASI_USER, %o3 + add %o0, 8, %o0 ! advance SRC by 8 + stx %o3, [%o1 - 16] + ldxa [%o0]ASI_USER, %o3 + add %o0, 8, %o0 ! advance SRC by 8 + bgt,pt %ncc, .ci_med_lmove ! loop til 31 or fewer bytes left + stx %o3, [%o1 - 8] + addcc %o2, 24, %o2 ! restore count to long word offset + ble,pt %ncc, .ci_med_lextra ! check for more long words to move + nop +.ci_med_lword: + ldxa [%o0]ASI_USER, %o3 ! read long word + subcc %o2, 8, %o2 ! reduce count by 8 + stx %o3, [%o1] ! write long word + add %o0, 8, %o0 ! advance SRC by 8 + bgt,pt %ncc, .ci_med_lword ! loop til 7 or fewer bytes left + add %o1, 8, %o1 ! advance DST by 8 +.ci_med_lextra: + addcc %o2, 7, %o2 ! restore rest of count + bz,pt %ncc, .ci_sm_exit ! if zero, then done + deccc %o2 + bz,pt %ncc, .ci_sm_byte + nop + ba,pt %ncc, .ci_sm_half + nop + + .align 16 + nop ! instruction alignment + ! see discussion at start of file +.ci_med_word: + btst 3, %o0 ! check for + bz,pt %ncc, .ci_med_word1 ! word alignment + nop +.ci_med_word0: + lduba [%o0]ASI_USER, %o3 ! load one byte + inc %o0 + stb %o3,[%o1] ! store byte + inc %o1 + btst 3, %o0 + bnz,pt %ncc, .ci_med_word0 + dec %o2 +! +! Now word aligned and have at least 36 bytes to move +! +.ci_med_word1: + sub %o2, 15, %o2 ! adjust count to allow cc zero test +.ci_med_wmove: + lduwa [%o0]ASI_USER, %o3 ! read word + subcc %o2, 16, %o2 ! reduce count by 16 + stw %o3, [%o1] ! write word + add %o0, 4, %o0 ! advance SRC by 4 + lduwa [%o0]ASI_USER, %o3 ! repeat for a total for 4 words + add %o0, 4, %o0 ! advance SRC by 4 + stw %o3, [%o1 + 4] + add %o1, 16, %o1 ! advance DST by 16 + lduwa [%o0]ASI_USER, %o3 + add %o0, 4, %o0 ! advance SRC by 4 + stw %o3, [%o1 - 8] + lduwa [%o0]ASI_USER, %o3 + add %o0, 4, %o0 ! advance SRC by 4 + bgt,pt %ncc, .ci_med_wmove ! loop til 15 or fewer bytes left + stw %o3, [%o1 - 4] + addcc %o2, 12, %o2 ! restore count to word offset + ble,pt %ncc, .ci_med_wextra ! check for more words to move + nop +.ci_med_word2: + lduwa [%o0]ASI_USER, %o3 ! read word + subcc %o2, 4, %o2 ! reduce count by 4 + stw %o3, [%o1] ! write word + add %o0, 4, %o0 ! advance SRC by 4 + bgt,pt %ncc, .ci_med_word2 ! loop til 3 or fewer bytes left + add %o1, 4, %o1 ! advance DST by 4 +.ci_med_wextra: + addcc %o2, 3, %o2 ! restore rest of count + bz,pt %ncc, .ci_sm_exit ! if zero, then done + deccc %o2 + bz,pt %ncc, .ci_sm_byte + nop + ba,pt %ncc, .ci_sm_half + nop + + .align 16 + nop ! instruction alignment + ! see discussion at start of file +.ci_med_half: + btst 1, %o0 ! check for + bz,pt %ncc, .ci_med_half1 ! half word alignment + nop + lduba [%o0]ASI_USER, %o3 ! load one byte + inc %o0 + stb %o3,[%o1] ! store byte + inc %o1 + dec %o2 +! +! Now half word aligned and have at least 38 bytes to move +! +.ci_med_half1: + sub %o2, 7, %o2 ! adjust count to allow cc zero test +.ci_med_hmove: + lduha [%o0]ASI_USER, %o3 ! read half word + subcc %o2, 8, %o2 ! reduce count by 8 + sth %o3, [%o1] ! write half word + add %o0, 2, %o0 ! advance SRC by 2 + lduha [%o0]ASI_USER, %o3 ! repeat for a total for 4 halfwords + add %o0, 2, %o0 ! advance SRC by 2 + sth %o3, [%o1 + 2] + add %o1, 8, %o1 ! advance DST by 8 + lduha [%o0]ASI_USER, %o3 + add %o0, 2, %o0 ! advance SRC by 2 + sth %o3, [%o1 - 4] + lduha [%o0]ASI_USER, %o3 + add %o0, 2, %o0 ! advance SRC by 2 + bgt,pt %ncc, .ci_med_hmove ! loop til 7 or fewer bytes left + sth %o3, [%o1 - 2] + addcc %o2, 7, %o2 ! restore count + bz,pt %ncc, .ci_sm_exit + deccc %o2 + bz,pt %ncc, .ci_sm_byte + nop + ba,pt %ncc, .ci_sm_half + nop + +.sm_copyin_err: + membar #Sync + stn %o4, [THREAD_REG + T_LOFAULT] ! restore old t_lofault + mov SM_SAVE_SRC, %o0 + mov SM_SAVE_DST, %o1 + mov SM_SAVE_COUNT, %o2 + ldn [THREAD_REG + T_COPYOPS], %o3 ! check for copyop handler + tst %o3 + bz,pt %ncc, 3f ! if not, return error + nop + ldn [%o3 + CP_COPYIN], %o5 ! if handler, invoke it with + jmp %o5 ! original arguments + nop +3: + retl + or %g0, -1, %o0 ! return errno value + + SET_SIZE(copyin) + + +/* + * The _more entry points are not intended to be used directly by + * any caller from outside this file. They are provided to allow + * profiling and dtrace of the portions of the copy code that uses + * the floating point registers. + * This entry is particularly important as DTRACE (at least as of + * 4/2004) does not support leaf functions. + */ + + ENTRY(copyin_more) +.copyin_more: + prefetch [%o0], #n_reads + save %sp, -SA(MINFRAME + HWCOPYFRAMESIZE), %sp + set .copyin_err, REAL_LOFAULT + +/* + * Copy ins that reach here are larger than VIS_COPY_THRESHOLD bytes + */ +.do_copyin: + set copyio_fault, %l7 ! .copyio_fault is lofault val + + ldn [THREAD_REG + T_LOFAULT], %l6 ! save existing handler + membar #Sync ! sync error barrier + stn %l7, [THREAD_REG + T_LOFAULT] ! set t_lofault + + mov %i0, SAVE_SRC + mov %i1, SAVE_DST + mov %i2, SAVE_COUNT + + FP_NOMIGRATE(6, 7) + + rd %fprs, %o2 ! check for unused fp + st %o2, [%fp + STACK_BIAS - SAVED_FPRS_OFFSET] ! save orig %fprs + btst FPRS_FEF, %o2 + bz,a,pt %icc, .do_blockcopyin + wr %g0, FPRS_FEF, %fprs + + BST_FPQ2Q4_TOSTACK(%o2) + +.do_blockcopyin: + rd %gsr, %o2 + stx %o2, [%fp + STACK_BIAS - SAVED_GSR_OFFSET] ! save gsr + or %l6, FPUSED_FLAG, %l6 + + andcc DST, VIS_BLOCKSIZE - 1, TMP + mov ASI_USER, %asi + bz,pt %ncc, 2f + neg TMP + add TMP, VIS_BLOCKSIZE, TMP + + ! TMP = bytes required to align DST on FP_BLOCK boundary + ! Using SRC as a tmp here + cmp TMP, 3 + bleu,pt %ncc, 1f + sub CNT,TMP,CNT ! adjust main count + sub TMP, 3, TMP ! adjust for end of loop test +.ci_blkalign: + lduba [REALSRC]%asi, SRC ! move 4 bytes per loop iteration + stb SRC, [DST] + subcc TMP, 4, TMP + lduba [REALSRC + 1]%asi, SRC + add REALSRC, 4, REALSRC + stb SRC, [DST + 1] + lduba [REALSRC - 2]%asi, SRC + add DST, 4, DST + stb SRC, [DST - 2] + lduba [REALSRC - 1]%asi, SRC + bgu,pt %ncc, .ci_blkalign + stb SRC, [DST - 1] + + addcc TMP, 3, TMP ! restore count adjustment + bz,pt %ncc, 2f ! no bytes left? + nop +1: lduba [REALSRC]%asi, SRC + inc REALSRC + inc DST + deccc TMP + bgu %ncc, 1b + stb SRC, [DST - 1] + +2: + membar #StoreLoad + andn REALSRC, 0x7, SRC + + ! SRC - 8-byte aligned + ! DST - 64-byte aligned + ldda [SRC]%asi, %f16 + prefetcha [SRC + (1 * VIS_BLOCKSIZE)]%asi, #n_reads + alignaddr REALSRC, %g0, %g0 + ldda [SRC + 0x08]%asi, %f18 + prefetcha [SRC + (2 * VIS_BLOCKSIZE)]%asi, #n_reads + faligndata %f16, %f18, %f48 + ldda [SRC + 0x10]%asi, %f20 + prefetcha [SRC + (3 * VIS_BLOCKSIZE)]%asi, #one_read + faligndata %f18, %f20, %f50 + ldda [SRC + 0x18]%asi, %f22 + prefetcha [SRC + (4 * VIS_BLOCKSIZE)]%asi, #one_read + faligndata %f20, %f22, %f52 + ldda [SRC + 0x20]%asi, %f24 + prefetcha [SRC + (5 * VIS_BLOCKSIZE)]%asi, #one_read + faligndata %f22, %f24, %f54 + ldda [SRC + 0x28]%asi, %f26 + prefetcha [SRC + (6 * VIS_BLOCKSIZE)]%asi, #one_read + faligndata %f24, %f26, %f56 + ldda [SRC + 0x30]%asi, %f28 + prefetcha [SRC + (7 * VIS_BLOCKSIZE)]%asi, #one_read + faligndata %f26, %f28, %f58 + ldda [SRC + 0x38]%asi, %f30 + ldda [SRC + VIS_BLOCKSIZE]%asi, %f16 + sub CNT, VIS_BLOCKSIZE, CNT + add SRC, VIS_BLOCKSIZE, SRC + prefetcha [SRC + (9 * VIS_BLOCKSIZE) - VIS_BLOCKSIZE]%asi, #one_read + add REALSRC, VIS_BLOCKSIZE, REALSRC + ba,pt %ncc, 1f + prefetcha [SRC + (10 * VIS_BLOCKSIZE) - VIS_BLOCKSIZE]%asi, #one_read + .align 32 +1: + ldda [SRC + 0x08]%asi, %f18 + faligndata %f28, %f30, %f60 + ldda [SRC + 0x10]%asi, %f20 + faligndata %f30, %f16, %f62 + stda %f48, [DST]ASI_BLK_P + ldda [SRC + 0x18]%asi, %f22 + faligndata %f16, %f18, %f48 + ldda [SRC + 0x20]%asi, %f24 + faligndata %f18, %f20, %f50 + ldda [SRC + 0x28]%asi, %f26 + faligndata %f20, %f22, %f52 + ldda [SRC + 0x30]%asi, %f28 + faligndata %f22, %f24, %f54 + ldda [SRC + 0x38]%asi, %f30 + prefetcha [SRC + ((OLYMPUS_C_PREFETCH) * VIS_BLOCKSIZE)]%asi, #n_reads + faligndata %f24, %f26, %f56 + ldda [SRC + VIS_BLOCKSIZE]%asi, %f16 + prefetcha [SRC + ((OLYMPUS_C_2ND_PREFETCH) * VIS_BLOCKSIZE)]%asi, #one_read + faligndata %f26, %f28, %f58 + prefetcha [SRC + ((OLYMPUS_C_PREFETCH) * VIS_BLOCKSIZE) + 0x20]%asi, #n_reads + prefetcha [SRC + ((OLYMPUS_C_2ND_PREFETCH) * VIS_BLOCKSIZE) + 0x20]%asi, #one_read + sub CNT, VIS_BLOCKSIZE, CNT + add DST, VIS_BLOCKSIZE, DST + add REALSRC, VIS_BLOCKSIZE, REALSRC + cmp CNT, VIS_BLOCKSIZE + 8 + bgu,pt %ncc, 1b + add SRC, VIS_BLOCKSIZE, SRC + + ! only if REALSRC & 0x7 is 0 + cmp CNT, VIS_BLOCKSIZE + bne %ncc, 3f + andcc REALSRC, 0x7, %g0 + bz,pt %ncc, 2f + nop +3: + faligndata %f28, %f30, %f60 + faligndata %f30, %f16, %f62 + stda %f48, [DST]ASI_BLK_P + add DST, VIS_BLOCKSIZE, DST + ba,pt %ncc, 3f + nop +2: + ldda [SRC + 0x08]%asi, %f18 + fsrc1 %f28, %f60 + ldda [SRC + 0x10]%asi, %f20 + fsrc1 %f30, %f62 + stda %f48, [DST]ASI_BLK_P + ldda [SRC + 0x18]%asi, %f22 + fsrc1 %f16, %f48 + ldda [SRC + 0x20]%asi, %f24 + fsrc1 %f18, %f50 + ldda [SRC + 0x28]%asi, %f26 + fsrc1 %f20, %f52 + ldda [SRC + 0x30]%asi, %f28 + fsrc1 %f22, %f54 + ldda [SRC + 0x38]%asi, %f30 + fsrc1 %f24, %f56 + sub CNT, VIS_BLOCKSIZE, CNT + add DST, VIS_BLOCKSIZE, DST + add SRC, VIS_BLOCKSIZE, SRC + add REALSRC, VIS_BLOCKSIZE, REALSRC + fsrc1 %f26, %f58 + fsrc1 %f28, %f60 + fsrc1 %f30, %f62 + stda %f48, [DST]ASI_BLK_P + add DST, VIS_BLOCKSIZE, DST + ba,a,pt %ncc, 4f + nop + +3: tst CNT + bz,a %ncc, 4f + nop + +5: lduba [REALSRC]ASI_USER, TMP + inc REALSRC + inc DST + deccc CNT + bgu %ncc, 5b + stb TMP, [DST - 1] +4: + +.copyin_exit: + membar #Sync + + ldx [%fp + STACK_BIAS - SAVED_GSR_OFFSET], %o2 ! restore gsr + wr %o2, 0, %gsr + + ld [%fp + STACK_BIAS - SAVED_FPRS_OFFSET], %o3 + btst FPRS_FEF, %o3 + bz,pt %icc, 4f + nop + + BLD_FPQ2Q4_FROMSTACK(%o2) + + ba,pt %ncc, 1f + wr %o3, 0, %fprs ! restore fprs + +4: + FZEROQ2Q4 + wr %o3, 0, %fprs ! restore fprs + +1: + membar #Sync ! sync error barrier + andn %l6, FPUSED_FLAG, %l6 + stn %l6, [THREAD_REG + T_LOFAULT] ! restore old t_lofault + FP_ALLOWMIGRATE(5, 6) + ret + restore %g0, 0, %o0 +/* + * We got here because of a fault during copyin + * Errno value is in ERRNO, but DDI/DKI says return -1 (sigh). + */ +.copyin_err: + ldn [THREAD_REG + T_COPYOPS], %o4 ! check for copyop handler + tst %o4 + bz,pt %ncc, 2f ! if not, return error + nop + ldn [%o4 + CP_COPYIN], %g2 ! if handler, invoke it with + jmp %g2 ! original arguments + restore %g0, 0, %g0 ! dispose of copy window +2: + ret + restore %g0, -1, %o0 ! return error value + + + SET_SIZE(copyin_more) + +#endif /* lint */ + +#ifdef lint + +/*ARGSUSED*/ +int +xcopyin(const void *uaddr, void *kaddr, size_t count) +{ return (0); } + +#else /* lint */ + + ENTRY(xcopyin) + + cmp %o2, VIS_COPY_THRESHOLD ! check for leaf rtn case + bleu,pt %ncc, .xcopyin_small ! go to larger cases + xor %o0, %o1, %o3 ! are src, dst alignable? + btst 7, %o3 ! + bz,pt %ncc, .xcopyin_8 ! check for longword alignment + nop + btst 1, %o3 ! + bz,pt %ncc, .xcopyin_2 ! check for half-word + nop + sethi %hi(hw_copy_limit_1), %o3 ! Check copy limit + ld [%o3 + %lo(hw_copy_limit_1)], %o3 + tst %o3 + bz,pn %icc, .xcopyin_small ! if zero, disable HW copy + cmp %o2, %o3 ! if length <= limit + bleu,pt %ncc, .xcopyin_small ! go to small copy + nop + ba,pt %ncc, .xcopyin_more ! otherwise go to large copy + nop +.xcopyin_2: + btst 3, %o3 ! + bz,pt %ncc, .xcopyin_4 ! check for word alignment + nop + sethi %hi(hw_copy_limit_2), %o3 ! Check copy limit + ld [%o3 + %lo(hw_copy_limit_2)], %o3 + tst %o3 + bz,pn %icc, .xcopyin_small ! if zero, disable HW copy + cmp %o2, %o3 ! if length <= limit + bleu,pt %ncc, .xcopyin_small ! go to small copy + nop + ba,pt %ncc, .xcopyin_more ! otherwise go to large copy + nop +.xcopyin_4: + ! already checked longword, must be word aligned + sethi %hi(hw_copy_limit_4), %o3 ! Check copy limit + ld [%o3 + %lo(hw_copy_limit_4)], %o3 + tst %o3 + bz,pn %icc, .xcopyin_small ! if zero, disable HW copy + cmp %o2, %o3 ! if length <= limit + bleu,pt %ncc, .xcopyin_small ! go to small copy + nop + ba,pt %ncc, .xcopyin_more ! otherwise go to large copy + nop +.xcopyin_8: + sethi %hi(hw_copy_limit_8), %o3 ! Check copy limit + ld [%o3 + %lo(hw_copy_limit_8)], %o3 + tst %o3 + bz,pn %icc, .xcopyin_small ! if zero, disable HW copy + cmp %o2, %o3 ! if length <= limit + bleu,pt %ncc, .xcopyin_small ! go to small copy + nop + ba,pt %ncc, .xcopyin_more ! otherwise go to large copy + nop + +.xcopyin_small: + sethi %hi(.sm_xcopyin_err), %o5 ! .sm_xcopyin_err is lofault value + or %o5, %lo(.sm_xcopyin_err), %o5 + ldn [THREAD_REG + T_LOFAULT], %o4 ! set/save t_lofaul + membar #Sync ! sync error barrier + ba,pt %ncc, .sm_do_copyin ! common code + stn %o5, [THREAD_REG + T_LOFAULT] + +.xcopyin_more: + save %sp, -SA(MINFRAME + HWCOPYFRAMESIZE), %sp + sethi %hi(.xcopyin_err), REAL_LOFAULT ! .xcopyin_err is lofault value + ba,pt %ncc, .do_copyin + or REAL_LOFAULT, %lo(.xcopyin_err), REAL_LOFAULT + +/* + * We got here because of fault during xcopyin + * Errno value is in ERRNO + */ +.xcopyin_err: + ldn [THREAD_REG + T_COPYOPS], %o4 ! check for copyop handler + tst %o4 + bz,pt %ncc, 2f ! if not, return error + nop + ldn [%o4 + CP_XCOPYIN], %g2 ! if handler, invoke it with + jmp %g2 ! original arguments + restore %g0, 0, %g0 ! dispose of copy window +2: + ret + restore ERRNO, 0, %o0 ! return errno value + +.sm_xcopyin_err: + + membar #Sync + stn %o4, [THREAD_REG + T_LOFAULT] ! restore old t_lofault + mov SM_SAVE_SRC, %o0 + mov SM_SAVE_DST, %o1 + mov SM_SAVE_COUNT, %o2 + ldn [THREAD_REG + T_COPYOPS], %o3 ! check for copyop handler + tst %o3 + bz,pt %ncc, 3f ! if not, return error + nop + ldn [%o3 + CP_XCOPYIN], %o5 ! if handler, invoke it with + jmp %o5 ! original arguments + nop +3: + retl + or %g1, 0, %o0 ! return errno value + + SET_SIZE(xcopyin) + +#endif /* lint */ + +#ifdef lint + +/*ARGSUSED*/ +int +xcopyin_little(const void *uaddr, void *kaddr, size_t count) +{ return (0); } + +#else /* lint */ + + ENTRY(xcopyin_little) + sethi %hi(.xcopyio_err), %o5 + or %o5, %lo(.xcopyio_err), %o5 + ldn [THREAD_REG + T_LOFAULT], %o4 + membar #Sync ! sync error barrier + stn %o5, [THREAD_REG + T_LOFAULT] + mov %o4, %o5 + + subcc %g0, %o2, %o3 + add %o0, %o2, %o0 + bz,pn %ncc, 2f ! check for zero bytes + sub %o2, 1, %o4 + add %o0, %o4, %o0 ! start w/last byte + add %o1, %o2, %o1 + lduba [%o0 + %o3]ASI_AIUSL, %o4 + +1: stb %o4, [%o1 + %o3] + inccc %o3 + sub %o0, 2, %o0 ! get next byte + bcc,a,pt %ncc, 1b + lduba [%o0 + %o3]ASI_AIUSL, %o4 + +2: + membar #Sync ! sync error barrier + stn %o5, [THREAD_REG + T_LOFAULT] ! restore old t_lofault + retl + mov %g0, %o0 ! return (0) + +.xcopyio_err: + membar #Sync ! sync error barrier + stn %o5, [THREAD_REG + T_LOFAULT] ! restore old t_lofault + retl + mov %g1, %o0 + + SET_SIZE(xcopyin_little) + +#endif /* lint */ + + +/* + * Copy a block of storage - must not overlap (from + len <= to). + * No fault handler installed (to be called under on_fault()) + */ +#if defined(lint) + +/* ARGSUSED */ +void +copyin_noerr(const void *ufrom, void *kto, size_t count) +{} + +#else /* lint */ + ENTRY(copyin_noerr) + + cmp %o2, VIS_COPY_THRESHOLD ! check for leaf rtn case + bleu,pt %ncc, .copyin_ne_small ! go to larger cases + xor %o0, %o1, %o3 ! are src, dst alignable? + btst 7, %o3 ! + bz,pt %ncc, .copyin_ne_8 ! check for longword alignment + nop + btst 1, %o3 ! + bz,pt %ncc, .copyin_ne_2 ! check for half-word + nop + sethi %hi(hw_copy_limit_1), %o3 ! Check copy limit + ld [%o3 + %lo(hw_copy_limit_1)], %o3 + tst %o3 + bz,pn %icc, .copyin_ne_small ! if zero, disable HW copy + cmp %o2, %o3 ! if length <= limit + bleu,pt %ncc, .copyin_ne_small ! go to small copy + nop + ba,pt %ncc, .copyin_noerr_more ! otherwise go to large copy + nop +.copyin_ne_2: + btst 3, %o3 ! + bz,pt %ncc, .copyin_ne_4 ! check for word alignment + nop + sethi %hi(hw_copy_limit_2), %o3 ! Check copy limit + ld [%o3 + %lo(hw_copy_limit_2)], %o3 + tst %o3 + bz,pn %icc, .copyin_ne_small ! if zero, disable HW copy + cmp %o2, %o3 ! if length <= limit + bleu,pt %ncc, .copyin_ne_small ! go to small copy + nop + ba,pt %ncc, .copyin_noerr_more ! otherwise go to large copy + nop +.copyin_ne_4: + ! already checked longword, must be word aligned + sethi %hi(hw_copy_limit_4), %o3 ! Check copy limit + ld [%o3 + %lo(hw_copy_limit_4)], %o3 + tst %o3 + bz,pn %icc, .copyin_ne_small ! if zero, disable HW copy + cmp %o2, %o3 ! if length <= limit + bleu,pt %ncc, .copyin_ne_small ! go to small copy + nop + ba,pt %ncc, .copyin_noerr_more ! otherwise go to large copy + nop +.copyin_ne_8: + sethi %hi(hw_copy_limit_8), %o3 ! Check copy limit + ld [%o3 + %lo(hw_copy_limit_8)], %o3 + tst %o3 + bz,pn %icc, .copyin_ne_small ! if zero, disable HW copy + cmp %o2, %o3 ! if length <= limit + bleu,pt %ncc, .copyin_ne_small ! go to small copy + nop + ba,pt %ncc, .copyin_noerr_more ! otherwise go to large copy + nop + +.copyin_ne_small: + ldn [THREAD_REG + T_LOFAULT], %o4 + tst %o4 + bz,pn %ncc, .sm_do_copyin + nop + sethi %hi(.sm_copyio_noerr), %o5 + or %o5, %lo(.sm_copyio_noerr), %o5 + membar #Sync ! sync error barrier + ba,pt %ncc, .sm_do_copyin + stn %o5, [THREAD_REG + T_LOFAULT] ! set/save t_lofault + +.copyin_noerr_more: + save %sp, -SA(MINFRAME + HWCOPYFRAMESIZE), %sp + sethi %hi(.copyio_noerr), REAL_LOFAULT + ba,pt %ncc, .do_copyin + or REAL_LOFAULT, %lo(.copyio_noerr), REAL_LOFAULT + +.copyio_noerr: + jmp %l6 + restore %g0,0,%g0 + +.sm_copyio_noerr: + membar #Sync + stn %o4, [THREAD_REG + T_LOFAULT] ! restore t_lofault + jmp %o4 + nop + + SET_SIZE(copyin_noerr) +#endif /* lint */ + +/* + * Copy a block of storage - must not overlap (from + len <= to). + * No fault handler installed (to be called under on_fault()) + */ + +#if defined(lint) + +/* ARGSUSED */ +void +copyout_noerr(const void *kfrom, void *uto, size_t count) +{} + +#else /* lint */ + ENTRY(copyout_noerr) + + cmp %o2, VIS_COPY_THRESHOLD ! check for leaf rtn case + bleu,pt %ncc, .copyout_ne_small ! go to larger cases + xor %o0, %o1, %o3 ! are src, dst alignable? + btst 7, %o3 ! + bz,pt %ncc, .copyout_ne_8 ! check for longword alignment + nop + btst 1, %o3 ! + bz,pt %ncc, .copyout_ne_2 ! check for half-word + nop + sethi %hi(hw_copy_limit_1), %o3 ! Check copy limit + ld [%o3 + %lo(hw_copy_limit_1)], %o3 + tst %o3 + bz,pn %icc, .copyout_ne_small ! if zero, disable HW copy + cmp %o2, %o3 ! if length <= limit + bleu,pt %ncc, .copyout_ne_small ! go to small copy + nop + ba,pt %ncc, .copyout_noerr_more ! otherwise go to large copy + nop +.copyout_ne_2: + btst 3, %o3 ! + bz,pt %ncc, .copyout_ne_4 ! check for word alignment + nop + sethi %hi(hw_copy_limit_2), %o3 ! Check copy limit + ld [%o3 + %lo(hw_copy_limit_2)], %o3 + tst %o3 + bz,pn %icc, .copyout_ne_small ! if zero, disable HW copy + cmp %o2, %o3 ! if length <= limit + bleu,pt %ncc, .copyout_ne_small ! go to small copy + nop + ba,pt %ncc, .copyout_noerr_more ! otherwise go to large copy + nop +.copyout_ne_4: + ! already checked longword, must be word aligned + sethi %hi(hw_copy_limit_4), %o3 ! Check copy limit + ld [%o3 + %lo(hw_copy_limit_4)], %o3 + tst %o3 + bz,pn %icc, .copyout_ne_small ! if zero, disable HW copy + cmp %o2, %o3 ! if length <= limit + bleu,pt %ncc, .copyout_ne_small ! go to small copy + nop + ba,pt %ncc, .copyout_noerr_more ! otherwise go to large copy + nop +.copyout_ne_8: + sethi %hi(hw_copy_limit_8), %o3 ! Check copy limit + ld [%o3 + %lo(hw_copy_limit_8)], %o3 + tst %o3 + bz,pn %icc, .copyout_ne_small ! if zero, disable HW copy + cmp %o2, %o3 ! if length <= limit + bleu,pt %ncc, .copyout_ne_small ! go to small copy + nop + ba,pt %ncc, .copyout_noerr_more ! otherwise go to large copy + nop + +.copyout_ne_small: + ldn [THREAD_REG + T_LOFAULT], %o4 + tst %o4 + bz,pn %ncc, .sm_do_copyout + nop + sethi %hi(.sm_copyio_noerr), %o5 + or %o5, %lo(.sm_copyio_noerr), %o5 + membar #Sync ! sync error barrier + ba,pt %ncc, .sm_do_copyout + stn %o5, [THREAD_REG + T_LOFAULT] ! set/save t_lofault + +.copyout_noerr_more: + save %sp, -SA(MINFRAME + HWCOPYFRAMESIZE), %sp + sethi %hi(.copyio_noerr), REAL_LOFAULT + ba,pt %ncc, .do_copyout + or REAL_LOFAULT, %lo(.copyio_noerr), REAL_LOFAULT + + SET_SIZE(copyout_noerr) +#endif /* lint */ + + +/* + * hwblkclr - clears block-aligned, block-multiple-sized regions that are + * longer than 256 bytes in length using spitfire's block stores. If + * the criteria for using this routine are not met then it calls bzero + * and returns 1. Otherwise 0 is returned indicating success. + * Caller is responsible for ensuring use_hw_bzero is true and that + * kpreempt_disable() has been called. + */ +#ifdef lint +/*ARGSUSED*/ +int +hwblkclr(void *addr, size_t len) +{ + return(0); +} +#else /* lint */ + ! %i0 - start address + ! %i1 - length of region (multiple of 64) + ! %l0 - saved fprs + ! %l1 - pointer to saved %d0 block + ! %l2 - saved curthread->t_lwp + + ENTRY(hwblkclr) + ! get another window w/space for one aligned block of saved fpregs + save %sp, -SA(MINFRAME + 2*VIS_BLOCKSIZE), %sp + + ! Must be block-aligned + andcc %i0, (VIS_BLOCKSIZE-1), %g0 + bnz,pn %ncc, 1f + nop + + ! ... and must be 256 bytes or more + cmp %i1, 256 + blu,pn %ncc, 1f + nop + + ! ... and length must be a multiple of VIS_BLOCKSIZE + andcc %i1, (VIS_BLOCKSIZE-1), %g0 + bz,pn %ncc, 2f + nop + +1: ! punt, call bzero but notify the caller that bzero was used + mov %i0, %o0 + call bzero + mov %i1, %o1 + ret + restore %g0, 1, %o0 ! return (1) - did not use block operations + +2: rd %fprs, %l0 ! check for unused fp + btst FPRS_FEF, %l0 + bz,pt %icc, 1f + nop + + ! save in-use fpregs on stack + membar #Sync + add %fp, STACK_BIAS - 65, %l1 + and %l1, -VIS_BLOCKSIZE, %l1 + stda %d0, [%l1]ASI_BLK_P + +1: membar #StoreStore|#StoreLoad|#LoadStore + wr %g0, FPRS_FEF, %fprs + wr %g0, ASI_BLK_P, %asi + + ! Clear block + fzero %d0 + fzero %d2 + fzero %d4 + fzero %d6 + fzero %d8 + fzero %d10 + fzero %d12 + fzero %d14 + + mov 256, %i3 + ba,pt %ncc, .pz_doblock + nop + +.pz_blkstart: + ! stda %d0, [%i0 + 192]%asi ! in dly slot of branch that got us here + stda %d0, [%i0 + 128]%asi + stda %d0, [%i0 + 64]%asi + stda %d0, [%i0]%asi +.pz_zinst: + add %i0, %i3, %i0 + sub %i1, %i3, %i1 +.pz_doblock: + cmp %i1, 256 + bgeu,a %ncc, .pz_blkstart + stda %d0, [%i0 + 192]%asi + + cmp %i1, 64 + blu %ncc, .pz_finish + + andn %i1, (64-1), %i3 + srl %i3, 4, %i2 ! using blocks, 1 instr / 16 words + set .pz_zinst, %i4 + sub %i4, %i2, %i4 + jmp %i4 + nop + +.pz_finish: + membar #Sync + btst FPRS_FEF, %l0 + bz,a .pz_finished + wr %l0, 0, %fprs ! restore fprs + + ! restore fpregs from stack + ldda [%l1]ASI_BLK_P, %d0 + membar #Sync + wr %l0, 0, %fprs ! restore fprs + +.pz_finished: + ret + restore %g0, 0, %o0 ! return (bzero or not) + + SET_SIZE(hwblkclr) +#endif /* lint */ + +#ifdef lint +/*ARGSUSED*/ +void +hw_pa_bcopy32(uint64_t src, uint64_t dst) +{} +#else /*!lint */ + /* + * Copy 32 bytes of data from src (%o0) to dst (%o1) + * using physical addresses. + */ + ENTRY_NP(hw_pa_bcopy32) + rdpr %pstate, %g1 + andn %g1, PSTATE_IE, %g2 + wrpr %g0, %g2, %pstate + + rdpr %pstate, %g0 + ldxa [%o0]ASI_MEM, %o2 + add %o0, 8, %o0 + ldxa [%o0]ASI_MEM, %o3 + add %o0, 8, %o0 + ldxa [%o0]ASI_MEM, %o4 + add %o0, 8, %o0 + ldxa [%o0]ASI_MEM, %o5 + membar #Sync + + stxa %o2, [%o1]ASI_MEM + add %o1, 8, %o1 + stxa %o3, [%o1]ASI_MEM + add %o1, 8, %o1 + stxa %o4, [%o1]ASI_MEM + add %o1, 8, %o1 + stxa %o5, [%o1]ASI_MEM + + retl + wrpr %g0, %g1, %pstate + + SET_SIZE(hw_pa_bcopy32) + +#endif /* lint */ + +#if defined(lint) + +int use_hw_bcopy = 1; +int use_hw_bzero = 1; +uint_t hw_copy_limit_1 = 0; +uint_t hw_copy_limit_2 = 0; +uint_t hw_copy_limit_4 = 0; +uint_t hw_copy_limit_8 = 0; + +#else /* !lint */ + + DGDEF(use_hw_bcopy) + .word 1 + DGDEF(use_hw_bzero) + .word 1 + DGDEF(hw_copy_limit_1) + .word 0 + DGDEF(hw_copy_limit_2) + .word 0 + DGDEF(hw_copy_limit_4) + .word 0 + DGDEF(hw_copy_limit_8) + .word 0 + + .align 64 + .section ".text" +#endif /* !lint */ diff --git a/usr/src/uts/sun4u/io/opl_cfg.c b/usr/src/uts/sun4u/io/opl_cfg.c new file mode 100644 index 0000000000..51da7369c0 --- /dev/null +++ b/usr/src/uts/sun4u/io/opl_cfg.c @@ -0,0 +1,2559 @@ +/* + * 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 <sys/conf.h> +#include <sys/kmem.h> +#include <sys/debug.h> +#include <sys/modctl.h> +#include <sys/autoconf.h> +#include <sys/hwconf.h> +#include <sys/ddi_impldefs.h> +#include <sys/ddi.h> +#include <sys/sunddi.h> +#include <sys/sunndi.h> +#include <sys/ndi_impldefs.h> +#include <sys/machsystm.h> +#include <sys/fcode.h> +#include <sys/promif.h> +#include <sys/promimpl.h> +#include <sys/opl_cfg.h> +#include <sys/scfd/scfostoescf.h> + +static unsigned int opl_cfg_inited; +static opl_board_cfg_t opl_boards[HWD_SBS_PER_DOMAIN]; + +/* + * Module control operations + */ + +extern struct mod_ops mod_miscops; + +static struct modlmisc modlmisc = { + &mod_miscops, /* Type of module */ + "OPL opl_cfg %I%" +}; + +static struct modlinkage modlinkage = { + MODREV_1, (void *)&modlmisc, NULL +}; + +static int opl_map_in(dev_info_t *, fco_handle_t, fc_ci_t *); +static int opl_map_out(dev_info_t *, fco_handle_t, fc_ci_t *); +static int opl_register_fetch(dev_info_t *, fco_handle_t, fc_ci_t *); +static int opl_register_store(dev_info_t *, fco_handle_t, fc_ci_t *); + +static int opl_claim_memory(dev_info_t *, fco_handle_t, fc_ci_t *); +static int opl_release_memory(dev_info_t *, fco_handle_t, fc_ci_t *); +static int opl_vtop(dev_info_t *, fco_handle_t, fc_ci_t *); + +static int opl_config_child(dev_info_t *, fco_handle_t, fc_ci_t *); + +static int opl_get_fcode_size(dev_info_t *, fco_handle_t, fc_ci_t *); +static int opl_get_fcode(dev_info_t *, fco_handle_t, fc_ci_t *); + +static int opl_map_phys(dev_info_t *, struct regspec *, caddr_t *, + ddi_device_acc_attr_t *, ddi_acc_handle_t *); +static void opl_unmap_phys(ddi_acc_handle_t *); +static int opl_get_hwd_va(dev_info_t *, fco_handle_t, fc_ci_t *); + +extern int prom_get_fcode_size(char *); +extern int prom_get_fcode(char *, char *); + +#define PROBE_STR_SIZE 64 +#define UNIT_ADDR_SIZE 64 + +opl_fc_ops_t opl_fc_ops[] = { + + { FC_MAP_IN, opl_map_in}, + { FC_MAP_OUT, opl_map_out}, + { "rx@", opl_register_fetch}, + { FC_RL_FETCH, opl_register_fetch}, + { FC_RW_FETCH, opl_register_fetch}, + { FC_RB_FETCH, opl_register_fetch}, + { "rx!", opl_register_store}, + { FC_RL_STORE, opl_register_store}, + { FC_RW_STORE, opl_register_store}, + { FC_RB_STORE, opl_register_store}, + { "claim-memory", opl_claim_memory}, + { "release-memory", opl_release_memory}, + { "vtop", opl_vtop}, + { FC_CONFIG_CHILD, opl_config_child}, + { FC_GET_FCODE_SIZE, opl_get_fcode_size}, + { FC_GET_FCODE, opl_get_fcode}, + { "get-hwd-va", opl_get_hwd_va}, + { NULL, NULL} + +}; + +extern caddr_t efcode_vaddr; +extern int efcode_size; + +#ifdef DEBUG +#define HWDDUMP_OFFSETS 1 +#define HWDDUMP_ALL_STATUS 2 +#define HWDDUMP_CHUNKS 3 +#define HWDDUMP_SBP 4 + +int hwddump_flags = HWDDUMP_SBP | HWDDUMP_CHUNKS; +#endif + +int +_init() +{ + int err = 0; + + /* + * Create a resource map for the contiguous memory allocated + * at start-of-day in startup.c + */ + err = ndi_ra_map_setup(ddi_root_node(), "opl-fcodemem"); + if (err == NDI_FAILURE) { + cmn_err(CE_WARN, "Cannot setup resource map opl-fcodemem\n"); + return (1); + } + + /* + * Put the allocated memory into the pool. + */ + (void) ndi_ra_free(ddi_root_node(), (uint64_t)efcode_vaddr, + (uint64_t)efcode_size, "opl-fcodemem", 0); + + if ((err = mod_install(&modlinkage)) != 0) { + cmn_err(CE_WARN, "opl_cfg failed to load, error=%d", err); + (void) ndi_ra_map_destroy(ddi_root_node(), "opl-fcodemem"); + } + + return (err); +} + +int +_fini(void) +{ + int ret; + + ret = (mod_remove(&modlinkage)); + if (ret != 0) + return (ret); + + (void) ndi_ra_map_destroy(ddi_root_node(), "opl-fcodemem"); + + return (ret); +} + +int +_info(modinfop) +struct modinfo *modinfop; +{ + return (mod_info(&modlinkage, modinfop)); +} + +#ifdef DEBUG +static void +opl_dump_hwd(opl_probe_t *probe) +{ + hwd_header_t *hdrp; + hwd_sb_status_t *statp; + hwd_domain_info_t *dinfop; + hwd_sb_t *sbp; + hwd_cpu_chip_t *chips; + hwd_pci_ch_t *channels; + int board, i, status; + + board = probe->pr_board; + + hdrp = probe->pr_hdr; + statp = probe->pr_sb_status; + dinfop = probe->pr_dinfo; + sbp = probe->pr_sb; + + printf("HWD: board %d\n", board); + printf("HWD:magic = 0x%x\n", hdrp->hdr_magic); + printf("HWD:version = 0x%x.%x\n", hdrp->hdr_version.major, + hdrp->hdr_version.minor); + + if (hwddump_flags & HWDDUMP_OFFSETS) { + printf("HWD:status offset = 0x%x\n", + hdrp->hdr_sb_status_offset); + printf("HWD:domain offset = 0x%x\n", + hdrp->hdr_domain_info_offset); + printf("HWD:board offset = 0x%x\n", hdrp->hdr_sb_info_offset); + } + + if (hwddump_flags & HWDDUMP_SBP) + printf("HWD:sb_t ptr = 0x%p\n", (void *)probe->pr_sb); + + if (hwddump_flags & HWDDUMP_ALL_STATUS) { + int bd; + printf("HWD:board status ="); + for (bd = 0; bd < HWD_SBS_PER_DOMAIN; bd++) + printf("%x ", statp->sb_status[bd]); + printf("\n"); + } else { + printf("HWD:board status = %d\n", statp->sb_status[board]); + } + + printf("HWD:banner name = %s\n", dinfop->dinf_banner_name); + printf("HWD:platform = %s\n", dinfop->dinf_platform_token); + + printf("HWD:chip status:\n"); + chips = &sbp->sb_cmu.cmu_cpu_chips[0]; + for (i = 0; i < HWD_CPU_CHIPS_PER_CMU; i++) { + + status = chips[i].chip_status; + printf("chip[%d] = ", i); + if (HWD_STATUS_NONE(status)) + printf("none"); + else if (HWD_STATUS_FAILED(status)) + printf("fail"); + else if (HWD_STATUS_OK(status)) + printf("ok"); + printf("\n"); + } + + if (hwddump_flags & HWDDUMP_CHUNKS) { + int chunk; + hwd_memory_t *mem = &sbp->sb_cmu.cmu_memory; + printf("HWD:chunks:\n"); + for (chunk = 0; chunk < HWD_MAX_MEM_CHUNKS; chunk++) + printf("\t%d 0x%lx 0x%lx\n", chunk, + mem->mem_chunks[chunk].chnk_start_address, + mem->mem_chunks[chunk].chnk_size); + } + + printf("HWD:channel status:\n"); + channels = &sbp->sb_pci_ch[0]; + for (i = 0; i < HWD_PCI_CHANNELS_PER_SB; i++) { + + status = channels[i].pci_status; + printf("channels[%d] = ", i); + if (HWD_STATUS_NONE(status)) + printf("none"); + else if (HWD_STATUS_FAILED(status)) + printf("fail"); + else if (HWD_STATUS_OK(status)) + printf("ok"); + printf("\n"); + } + printf("channels[%d] = ", i); + status = sbp->sb_cmu.cmu_ch.chan_status; + if (HWD_STATUS_NONE(status)) + printf("none"); + else if (HWD_STATUS_FAILED(status)) + printf("fail"); + else if (HWD_STATUS_OK(status)) + printf("ok"); + printf("\n"); +} +#endif /* DEBUG */ + +#ifdef UCTEST + /* + * For SesamI debugging, just map the SRAM directly to a kernel + * VA and read it out from there + */ + +#include <sys/vmem.h> +#include <vm/seg_kmem.h> + +/* + * 0x4081F1323000LL is the HWD base address for LSB 0. But we need to map + * at page boundaries. So, we use a base address of 0x4081F1322000LL. + * Note that this has to match the HWD base pa set in .sesami-common-defs. + * + * The size specified for the HWD in the SCF spec is 36K. But since + * we adjusted the base address by 4K, we need to use 40K for the + * mapping size to cover the HWD. And 40K is also a multiple of the + * base page size. + */ +#define OPL_HWD_BASE(lsb) \ +(0x4081F1322000LL | (((uint64_t)(lsb)) << 40)) + + void *opl_hwd_vaddr; +#endif /* UCTEST */ + +/* + * Get the hardware descriptor from SCF. + */ + +/*ARGSUSED*/ +int +opl_read_hwd(int board, hwd_header_t **hdrp, hwd_sb_status_t **statp, + hwd_domain_info_t **dinfop, hwd_sb_t **sbp) +{ + static int (*getinfop)(uint32_t, uint8_t, uint32_t, uint32_t *, + void *) = NULL; + void *hwdp; + + uint32_t key = KEY_ESCF; /* required value */ + uint8_t type = 0x40; /* SUB_OS_RECEIVE_HWD */ + uint32_t transid = board; + uint32_t datasize = HWD_DATA_SIZE; + + hwd_header_t *hd; + hwd_sb_status_t *st; + hwd_domain_info_t *di; + hwd_sb_t *sb; + + int ret; + + if (opl_boards[board].cfg_hwd == NULL) { +#ifdef UCTEST + /* + * Just map the HWD in SRAM to a kernel VA + */ + + size_t size; + pfn_t pfn; + + size = 0xA000; + + opl_hwd_vaddr = vmem_alloc(heap_arena, size, VM_SLEEP); + if (opl_hwd_vaddr == NULL) { + cmn_err(CE_NOTE, "No space for HWD"); + return (-1); + } + + pfn = btop(OPL_HWD_BASE(board)); + hat_devload(kas.a_hat, opl_hwd_vaddr, size, pfn, PROT_READ, + HAT_LOAD_NOCONSIST | HAT_LOAD_LOCK); + + hwdp = (void *)((char *)opl_hwd_vaddr + 0x1000); + opl_boards[board].cfg_hwd = hwdp; + ret = 0; +#else + + /* find the scf_service_getinfo() function */ + if (getinfop == NULL) + getinfop = (int (*)(uint32_t, uint8_t, uint32_t, + uint32_t *, + void *))modgetsymvalue("scf_service_getinfo", 0); + + if (getinfop == NULL) + return (-1); + + /* allocate memory to receive the data */ + hwdp = kmem_alloc(HWD_DATA_SIZE, KM_SLEEP); + + /* get the HWD */ + ret = (*getinfop)(key, type, transid, &datasize, hwdp); + if (ret == 0) + opl_boards[board].cfg_hwd = hwdp; + else + kmem_free(hwdp, HWD_DATA_SIZE); +#endif + } else { + hwdp = opl_boards[board].cfg_hwd; + ret = 0; + } + + /* copy the data to the destination */ + if (ret == 0) { + hd = (hwd_header_t *)hwdp; + st = (hwd_sb_status_t *) + ((char *)hwdp + hd->hdr_sb_status_offset); + di = (hwd_domain_info_t *) + ((char *)hwdp + hd->hdr_domain_info_offset); + sb = (hwd_sb_t *) + ((char *)hwdp + hd->hdr_sb_info_offset); + if (hdrp != NULL) + *hdrp = hd; + if (statp != NULL) + *statp = st; + if (dinfop != NULL) + *dinfop = di; + if (sbp != NULL) + *sbp = sb; + } + + return (ret); +} + +/* + * The opl_probe_t probe structure is used to pass all sorts of parameters + * to callback functions during probing. It also contains a snapshot of + * the hardware descriptor that is taken at the beginning of a probe. + */ +static int +opl_probe_init(opl_probe_t *probe) +{ + hwd_header_t **hdrp; + hwd_sb_status_t **statp; + hwd_domain_info_t **dinfop; + hwd_sb_t **sbp; + int board, ret; + + board = probe->pr_board; + + hdrp = &probe->pr_hdr; + statp = &probe->pr_sb_status; + dinfop = &probe->pr_dinfo; + sbp = &probe->pr_sb; + + /* + * Read the hardware descriptor. + */ + ret = opl_read_hwd(board, hdrp, statp, dinfop, sbp); + if (ret != 0) { + + cmn_err(CE_WARN, "IKP: failed to read HWD header"); + return (-1); + } + +#ifdef DEBUG + opl_dump_hwd(probe); +#endif + return (0); +} + +/* + * This function is used to obtain pointers to relevant device nodes + * which are created by Solaris at boot time. + * + * This function walks the child nodes of a given node, extracts + * the "name" property, if it exists, and passes the node to a + * callback init function. The callback determines if this node is + * interesting or not. If it is, then a pointer to the node is + * stored away by the callback for use during unprobe. + * + * The DDI get property function allocates storage for the name + * property. That needs to be freed within this function. + */ +static int +opl_init_nodes(dev_info_t *parent, opl_init_func_t init) +{ + dev_info_t *node; + char *name; + int circ, ret; + int len; + + ASSERT(parent != NULL); + + /* + * Hold parent node busy to walk its child list + */ + ndi_devi_enter(parent, &circ); + node = ddi_get_child(parent); + + while (node != NULL) { + + ret = OPL_GET_PROP(string, node, "name", &name, &len); + if (ret != DDI_PROP_SUCCESS) { + /* + * The property does not exist for this node. + */ + node = ddi_get_next_sibling(node); + continue; + } + + ret = init(node, name, len); + kmem_free(name, len); + if (ret != 0) { + + ndi_devi_exit(parent, circ); + return (-1); + } + + node = ddi_get_next_sibling(node); + } + + ndi_devi_exit(parent, circ); + + return (0); +} + +/* + * This init function finds all the interesting nodes under the + * root node and stores pointers to them. The following nodes + * are considered interesting by this implementation: + * + * "cmp" + * These are nodes that represent processor chips. + * + * "pci" + * These are nodes that represent PCI leaves. + * + * "pseudo-mc" + * These are nodes that contain memory information. + */ +static int +opl_init_root_nodes(dev_info_t *node, char *name, int len) +{ + int portid, board, chip, channel, leaf; + int ret; + + if (strncmp(name, OPL_CPU_CHIP_NODE, len) == 0) { + + ret = OPL_GET_PROP(int, node, "portid", &portid, -1); + if (ret != DDI_PROP_SUCCESS) + return (-1); + + ret = OPL_GET_PROP(int, node, "board#", &board, -1); + if (ret != DDI_PROP_SUCCESS) + return (-1); + + chip = OPL_CPU_CHIP(portid); + opl_boards[board].cfg_cpu_chips[chip] = node; + + } else if (strncmp(name, OPL_PCI_LEAF_NODE, len) == 0) { + + ret = OPL_GET_PROP(int, node, "portid", &portid, -1); + if (ret != DDI_PROP_SUCCESS) + return (-1); + + board = OPL_IO_PORTID_TO_LSB(portid); + channel = OPL_PORTID_TO_CHANNEL(portid); + + if (channel == OPL_CMU_CHANNEL) { + + opl_boards[board].cfg_cmuch_leaf = node; + + } else { + + leaf = OPL_PORTID_TO_LEAF(portid); + opl_boards[board].cfg_pcich_leaf[channel][leaf] = node; + } + } else if (strncmp(name, OPL_PSEUDO_MC_NODE, len) == 0) { + + ret = OPL_GET_PROP(int, node, "board#", &board, -1); + if (ret != DDI_PROP_SUCCESS) + return (-1); + + ASSERT((board >= 0) && (board < HWD_SBS_PER_DOMAIN)); + + opl_boards[board].cfg_pseudo_mc = node; + } + + return (0); +} + +/* + * This function initializes the OPL IKP feature. Currently, all it does + * is find the interesting nodes that Solaris has created at boot time + * for boards present at boot time and store pointers to them. This + * is useful if those boards are unprobed by DR. + */ +int +opl_init_cfg() +{ + dev_info_t *root; + + if (opl_cfg_inited == 0) { + + root = ddi_root_node(); + if ((opl_init_nodes(root, opl_init_root_nodes) != 0)) { + cmn_err(CE_WARN, "IKP: init failed"); + return (1); + } + + opl_cfg_inited = 1; + } + + return (0); +} + +/* + * When DR is initialized, we walk the device tree and acquire a hold on + * all the nodes that are interesting to IKP. This is so that the corresponding + * branches cannot be deleted. + * + * The following function informs the walk about which nodes are interesting + * so that it can hold the corresponding branches. + */ +static int +opl_hold_node(char *name) +{ + /* + * We only need to hold/release the following nodes which + * represent separate branches that must be managed. + */ + return ((strcmp(name, OPL_CPU_CHIP_NODE) == 0) || + (strcmp(name, OPL_PSEUDO_MC_NODE) == 0) || + (strcmp(name, OPL_PCI_LEAF_NODE) == 0)); +} + +static int +opl_hold_rele_devtree(dev_info_t *rdip, void *arg) +{ + + int *holdp = (int *)arg; + char *name = ddi_node_name(rdip); + + /* + * We only need to hold/release the following nodes which + * represent separate branches that must be managed. + */ + if (opl_hold_node(name) == 0) { + /* Not of interest to us */ + return (DDI_WALK_PRUNECHILD); + } + if (*holdp) { + ASSERT(!e_ddi_branch_held(rdip)); + e_ddi_branch_hold(rdip); + } else { + ASSERT(e_ddi_branch_held(rdip)); + e_ddi_branch_rele(rdip); + } + + return (DDI_WALK_PRUNECHILD); +} + +void +opl_hold_devtree() +{ + dev_info_t *dip; + int circ; + int hold = 1; + + dip = ddi_root_node(); + ndi_devi_enter(dip, &circ); + ddi_walk_devs(ddi_get_child(dip), opl_hold_rele_devtree, &hold); + ndi_devi_exit(dip, circ); +} + +void +opl_release_devtree() +{ + dev_info_t *dip; + int circ; + int hold = 0; + + dip = ddi_root_node(); + ndi_devi_enter(dip, &circ); + ddi_walk_devs(ddi_get_child(dip), opl_hold_rele_devtree, &hold); + ndi_devi_exit(dip, circ); +} + +/* + * This is a helper function that allows opl_create_node() to return a + * pointer to a newly created node to its caller. + */ +/*ARGSUSED*/ +static void +opl_set_node(dev_info_t *node, void *arg, uint_t flags) +{ + opl_probe_t *probe; + + probe = arg; + probe->pr_node = node; +} + +/* + * Function to create a node in the device tree under a specified parent. + * + * e_ddi_branch_create() allows the creation of a whole branch with a + * single call of the function. However, we only use it to create one node + * at a time in the case of non-I/O device nodes. In other words, we + * create branches by repeatedly using this function. This makes the + * code more readable. + * + * The branch descriptor passed to e_ddi_branch_create() takes two + * callbacks. The create() callback is used to set the properties of a + * newly created node. The other callback is used to return a pointer + * to the newly created node. The create() callback is passed by the + * caller of this function based on the kind of node he wishes to + * create. + * + * e_ddi_branch_create() returns with the newly created node held. We + * only need to hold the top nodes of the branches we create. We release + * the hold for the others. E.g., the "cmp" node needs to be held. Since + * we hold the "cmp" node, there is no need to hold the "core" and "cpu" + * nodes below it. + */ +static dev_info_t * +opl_create_node(opl_probe_t *probe) +{ + devi_branch_t branch; + + probe->pr_node = NULL; + + branch.arg = probe; + branch.type = DEVI_BRANCH_SID; + branch.create.sid_branch_create = probe->pr_create; + branch.devi_branch_callback = opl_set_node; + + if (e_ddi_branch_create(probe->pr_parent, &branch, NULL, 0) != 0) + return (NULL); + + ASSERT(probe->pr_node != NULL); + + if (probe->pr_hold == 0) + e_ddi_branch_rele(probe->pr_node); + + return (probe->pr_node); +} + +/* + * Function to tear down a whole branch rooted at the specified node. + * + * Although we create each node of a branch individually, we destroy + * a whole branch in one call. This is more efficient. + */ +static int +opl_destroy_node(dev_info_t *node) +{ + if (e_ddi_branch_destroy(node, NULL, 0) != 0) + return (-1); + + return (0); +} + +/* + * Set the properties for a "cpu" node. + */ +/*ARGSUSED*/ +static int +opl_create_cpu(dev_info_t *node, void *arg, uint_t flags) +{ + opl_probe_t *probe; + hwd_cpu_chip_t *chip; + hwd_core_t *core; + hwd_cpu_t *cpu; + int ret; + + probe = arg; + chip = &probe->pr_sb->sb_cmu.cmu_cpu_chips[probe->pr_cpu_chip]; + core = &chip->chip_cores[probe->pr_core]; + cpu = &core->core_cpus[probe->pr_cpu]; + OPL_UPDATE_PROP(string, node, "name", OPL_CPU_NODE); + OPL_UPDATE_PROP(string, node, "device_type", OPL_CPU_NODE); + + OPL_UPDATE_PROP(int, node, "cpuid", cpu->cpu_cpuid); + OPL_UPDATE_PROP(int, node, "reg", probe->pr_cpu); + + OPL_UPDATE_PROP(string, node, "status", "okay"); + + return (DDI_WALK_TERMINATE); +} + +/* + * Create "cpu" nodes as child nodes of a given "core" node. + */ +static int +opl_probe_cpus(opl_probe_t *probe) +{ + int i; + hwd_cpu_chip_t *chip; + hwd_core_t *core; + hwd_cpu_t *cpus; + + chip = &probe->pr_sb->sb_cmu.cmu_cpu_chips[probe->pr_cpu_chip]; + core = &chip->chip_cores[probe->pr_core]; + cpus = &core->core_cpus[0]; + + for (i = 0; i < HWD_CPUS_PER_CORE; i++) { + + /* + * Olympus-C has 2 cpus per core. + * Jupiter has 4 cpus per core. + * For the Olympus-C based platform, we expect the cpu_status + * of the non-existent cpus to be set to missing. + */ + if (!HWD_STATUS_OK(cpus[i].cpu_status)) + continue; + + probe->pr_create = opl_create_cpu; + probe->pr_cpu = i; + if (opl_create_node(probe) == NULL) { + + cmn_err(CE_WARN, "IKP: create cpu (%d-%d-%d-%d) failed", + probe->pr_board, probe->pr_cpu_chip, + probe->pr_core, probe->pr_cpu); + return (-1); + } + } + + return (0); +} + +/* + * Set the properties for a "core" node. + */ +/*ARGSUSED*/ +static int +opl_create_core(dev_info_t *node, void *arg, uint_t flags) +{ + opl_probe_t *probe; + hwd_cpu_chip_t *chip; + hwd_core_t *core; + int sharing[2]; + int ret; + + probe = arg; + chip = &probe->pr_sb->sb_cmu.cmu_cpu_chips[probe->pr_cpu_chip]; + core = &chip->chip_cores[probe->pr_core]; + + OPL_UPDATE_PROP(string, node, "name", OPL_CORE_NODE); + OPL_UPDATE_PROP(string, node, "device_type", OPL_CORE_NODE); + OPL_UPDATE_PROP(string, node, "compatible", chip->chip_compatible); + + OPL_UPDATE_PROP(int, node, "reg", probe->pr_core); + OPL_UPDATE_PROP(int, node, "manufacturer#", core->core_manufacturer); + OPL_UPDATE_PROP(int, node, "implementation#", + core->core_implementation); + OPL_UPDATE_PROP(int, node, "mask#", core->core_mask); + + OPL_UPDATE_PROP(int, node, "sparc-version", core->core_version); + OPL_UPDATE_PROP(int, node, "clock-frequency", core->core_frequency); + + OPL_UPDATE_PROP(int, node, "l1-icache-size", core->core_l1_icache_size); + OPL_UPDATE_PROP(int, node, "l1-icache-line-size", + core->core_l1_icache_line_size); + OPL_UPDATE_PROP(int, node, "l1-icache-associativity", + core->core_l1_icache_associativity); + OPL_UPDATE_PROP(int, node, "#itlb-entries", + core->core_num_itlb_entries); + + OPL_UPDATE_PROP(int, node, "l1-dcache-size", core->core_l1_dcache_size); + OPL_UPDATE_PROP(int, node, "l1-dcache-line-size", + core->core_l1_dcache_line_size); + OPL_UPDATE_PROP(int, node, "l1-dcache-associativity", + core->core_l1_dcache_associativity); + OPL_UPDATE_PROP(int, node, "#dtlb-entries", + core->core_num_dtlb_entries); + + OPL_UPDATE_PROP(int, node, "l2-cache-size", core->core_l2_cache_size); + OPL_UPDATE_PROP(int, node, "l2-cache-line-size", + core->core_l2_cache_line_size); + OPL_UPDATE_PROP(int, node, "l2-cache-associativity", + core->core_l2_cache_associativity); + sharing[0] = 0; + sharing[1] = core->core_l2_cache_sharing; + OPL_UPDATE_PROP_ARRAY(int, node, "l2-cache-sharing", sharing, 2); + + OPL_UPDATE_PROP(string, node, "status", "okay"); + + return (DDI_WALK_TERMINATE); +} + +/* + * Create "core" nodes as child nodes of a given "cmp" node. + * + * Create the branch below each "core" node". + */ +static int +opl_probe_cores(opl_probe_t *probe) +{ + int i; + hwd_cpu_chip_t *chip; + hwd_core_t *cores; + dev_info_t *parent, *node; + + chip = &probe->pr_sb->sb_cmu.cmu_cpu_chips[probe->pr_cpu_chip]; + cores = &chip->chip_cores[0]; + parent = probe->pr_parent; + + for (i = 0; i < HWD_CORES_PER_CPU_CHIP; i++) { + + if (!HWD_STATUS_OK(cores[i].core_status)) + continue; + + probe->pr_parent = parent; + probe->pr_create = opl_create_core; + probe->pr_core = i; + node = opl_create_node(probe); + if (node == NULL) { + + cmn_err(CE_WARN, "IKP: create core (%d-%d-%d) failed", + probe->pr_board, probe->pr_cpu_chip, + probe->pr_core); + return (-1); + } + + /* + * Create "cpu" nodes below "core". + */ + probe->pr_parent = node; + if (opl_probe_cpus(probe) != 0) + return (-1); + } + + return (0); +} + +/* + * Set the properties for a "cmp" node. + */ +/*ARGSUSED*/ +static int +opl_create_cpu_chip(dev_info_t *node, void *arg, uint_t flags) +{ + opl_probe_t *probe; + hwd_cpu_chip_t *chip; + opl_range_t range; + uint64_t dummy_addr; + int ret; + + probe = arg; + chip = &probe->pr_sb->sb_cmu.cmu_cpu_chips[probe->pr_cpu_chip]; + + OPL_UPDATE_PROP(string, node, "name", OPL_CPU_CHIP_NODE); + + OPL_UPDATE_PROP(int, node, "portid", chip->chip_portid); + OPL_UPDATE_PROP(int, node, "board#", probe->pr_board); + + dummy_addr = OPL_PROC_AS(probe->pr_board, probe->pr_cpu_chip); + range.rg_addr_hi = OPL_HI(dummy_addr); + range.rg_addr_lo = OPL_LO(dummy_addr); + range.rg_size_hi = 0; + range.rg_size_lo = 0; + OPL_UPDATE_PROP_ARRAY(int, node, "reg", (int *)&range, 4); + + OPL_UPDATE_PROP(int, node, "#address-cells", 1); + OPL_UPDATE_PROP(int, node, "#size-cells", 0); + + OPL_UPDATE_PROP(string, node, "status", "okay"); + + return (DDI_WALK_TERMINATE); +} + +/* + * Create "cmp" nodes as child nodes of the root node. + * + * Create the branch below each "cmp" node. + */ +static int +opl_probe_cpu_chips(opl_probe_t *probe) +{ + int i; + dev_info_t **cfg_cpu_chips; + hwd_cpu_chip_t *chips; + dev_info_t *node; + + cfg_cpu_chips = opl_boards[probe->pr_board].cfg_cpu_chips; + chips = &probe->pr_sb->sb_cmu.cmu_cpu_chips[0]; + + for (i = 0; i < HWD_CPU_CHIPS_PER_CMU; i++) { + + ASSERT(cfg_cpu_chips[i] == NULL); + + if (!HWD_STATUS_OK(chips[i].chip_status)) + continue; + + probe->pr_parent = ddi_root_node(); + probe->pr_create = opl_create_cpu_chip; + probe->pr_cpu_chip = i; + probe->pr_hold = 1; + node = opl_create_node(probe); + if (node == NULL) { + + cmn_err(CE_WARN, "IKP: create chip (%d-%d) failed", + probe->pr_board, probe->pr_cpu_chip); + return (-1); + } + + cfg_cpu_chips[i] = node; + + /* + * Create "core" nodes below "cmp". + * We hold the "cmp" node. So, there is no need to hold + * the "core" and "cpu" nodes below it. + */ + probe->pr_parent = node; + probe->pr_hold = 0; + if (opl_probe_cores(probe) != 0) + return (-1); + } + + return (0); +} + +/* + * Set the properties for a "pseudo-mc" node. + */ +/*ARGSUSED*/ +static int +opl_create_pseudo_mc(dev_info_t *node, void *arg, uint_t flags) +{ + opl_probe_t *probe; + int board, portid; + hwd_bank_t *bank; + hwd_memory_t *mem; + opl_range_t range; + opl_mc_addr_t mc[HWD_BANKS_PER_CMU]; + int status[2][7]; + int i, j; + int ret; + + probe = arg; + board = probe->pr_board; + + OPL_UPDATE_PROP(string, node, "name", OPL_PSEUDO_MC_NODE); + OPL_UPDATE_PROP(string, node, "device_type", "memory-controller"); + OPL_UPDATE_PROP(string, node, "compatible", "FJSV,oplmc"); + + portid = OPL_LSB_TO_PSEUDOMC_PORTID(board); + OPL_UPDATE_PROP(int, node, "portid", portid); + + range.rg_addr_hi = OPL_HI(OPL_MC_AS(board)); + range.rg_addr_lo = 0x200; + range.rg_size_hi = 0; + range.rg_size_lo = 0; + OPL_UPDATE_PROP_ARRAY(int, node, "reg", (int *)&range, 4); + + OPL_UPDATE_PROP(int, node, "board#", board); + OPL_UPDATE_PROP(int, node, "physical-board#", + probe->pr_sb->sb_psb_number); + + OPL_UPDATE_PROP(int, node, "#address-cells", 1); + OPL_UPDATE_PROP(int, node, "#size-cells", 2); + + mem = &probe->pr_sb->sb_cmu.cmu_memory; + + range.rg_addr_hi = OPL_HI(mem->mem_start_address); + range.rg_addr_lo = OPL_LO(mem->mem_start_address); + range.rg_size_hi = OPL_HI(mem->mem_size); + range.rg_size_lo = OPL_LO(mem->mem_size); + OPL_UPDATE_PROP_ARRAY(int, node, "sb-mem-ranges", (int *)&range, 4); + + bank = probe->pr_sb->sb_cmu.cmu_memory.mem_banks; + for (i = 0, j = 0; i < HWD_BANKS_PER_CMU; i++) { + + if (!HWD_STATUS_OK(bank[i].bank_status)) + continue; + + mc[j].mc_bank = i; + mc[j].mc_hi = OPL_HI(bank[i].bank_register_address); + mc[j].mc_lo = OPL_LO(bank[i].bank_register_address); + j++; + } + ASSERT(j > 0); + OPL_UPDATE_PROP_ARRAY(int, node, "mc-addr", (int *)mc, j*3); + + OPL_UPDATE_PROP_ARRAY(byte, node, "cs0-mc-pa-trans-table", + mem->mem_cs[0].cs_pa_mac_table, 64); + OPL_UPDATE_PROP_ARRAY(byte, node, "cs1-mc-pa-trans-table", + mem->mem_cs[1].cs_pa_mac_table, 64); + +#define CS_PER_MEM 2 + + for (i = 0, j = 0; i < CS_PER_MEM; i++) { + if (HWD_STATUS_OK(mem->mem_cs[i].cs_status) || + HWD_STATUS_FAILED(mem->mem_cs[i].cs_status)) { + status[j][0] = i; + if (HWD_STATUS_OK(mem->mem_cs[i].cs_status)) + status[j][1] = 0; + else + status[j][1] = 1; + status[j][2] = + OPL_HI(mem->mem_cs[i].cs_available_capacity); + status[j][3] = + OPL_LO(mem->mem_cs[i].cs_available_capacity); + status[j][4] = OPL_HI(mem->mem_cs[i].cs_dimm_capacity); + status[j][5] = OPL_LO(mem->mem_cs[i].cs_dimm_capacity); + status[j][6] = mem->mem_cs[i].cs_number_of_dimms; + j++; + } + } + ASSERT(j > 0); + OPL_UPDATE_PROP_ARRAY(int, node, "cs-status", (int *)status, + j*7); + + return (DDI_WALK_TERMINATE); +} + +/* + * Create "pseudo-mc" nodes + */ +static int +opl_probe_memory(opl_probe_t *probe) +{ + int board; + opl_board_cfg_t *board_cfg; + dev_info_t *node; + + board = probe->pr_board; + board_cfg = &opl_boards[board]; + + ASSERT(board_cfg->cfg_pseudo_mc == NULL); + + probe->pr_parent = ddi_root_node(); + probe->pr_create = opl_create_pseudo_mc; + probe->pr_hold = 1; + node = opl_create_node(probe); + if (node == NULL) { + + cmn_err(CE_WARN, "IKP: create pseudo-mc (%d) failed", board); + return (-1); + } + + board_cfg->cfg_pseudo_mc = node; + + return (0); +} + +/* + * Allocate the fcode ops handle. + */ +/*ARGSUSED*/ +static +fco_handle_t +opl_fc_ops_alloc_handle(dev_info_t *parent, dev_info_t *child, + void *fcode, size_t fcode_size, char *unit_address, + char *my_args) +{ + fco_handle_t rp; + phandle_t h; + char *buf; + + rp = kmem_zalloc(sizeof (struct fc_resource_list), KM_SLEEP); + rp->next_handle = fc_ops_alloc_handle(parent, child, fcode, fcode_size, + unit_address, NULL); + rp->ap = parent; + rp->child = child; + rp->fcode = fcode; + rp->fcode_size = fcode_size; + rp->my_args = my_args; + + if (unit_address) { + buf = kmem_zalloc(UNIT_ADDR_SIZE, KM_SLEEP); + (void) strcpy(buf, unit_address); + rp->unit_address = buf; + } + + /* + * Add the child's nodeid to our table... + */ + h = ddi_get_nodeid(rp->child); + fc_add_dip_to_phandle(fc_handle_to_phandle_head(rp), rp->child, h); + + return (rp); +} + + +static void +opl_fc_ops_free_handle(fco_handle_t rp) +{ + struct fc_resource *resp, *nresp; + + ASSERT(rp); + + if (rp->next_handle) + fc_ops_free_handle(rp->next_handle); + if (rp->unit_address) + kmem_free(rp->unit_address, UNIT_ADDR_SIZE); + + /* + * Release all the resources from the resource list + */ + for (resp = rp->head; resp != NULL; resp = nresp) { + nresp = resp->next; + switch (resp->type) { + + case RT_MAP: + break; + + case RT_DMA: + /* + * DMA has to be freed up at exit time. + */ + cmn_err(CE_CONT, + "opl_fc_ops_free_handle: Unexpected DMA seen!"); + break; + + case RT_CONTIGIOUS: + FC_DEBUG2(1, CE_CONT, "opl_fc_ops_free: " + "Free claim-memory resource 0x%lx size 0x%x\n", + resp->fc_contig_virt, resp->fc_contig_len); + + (void) ndi_ra_free(ddi_root_node(), + (uint64_t)resp->fc_contig_virt, + resp->fc_contig_len, "opl-fcodemem", + NDI_RA_PASS); + + break; + + default: + cmn_err(CE_CONT, "opl_fc_ops_free: " + "unknown resource type %d", resp->type); + break; + } + fc_rem_resource(rp, resp); + kmem_free(resp, sizeof (struct fc_resource)); + } + + kmem_free(rp, sizeof (struct fc_resource_list)); +} + +int +opl_fc_do_op(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) +{ + opl_fc_ops_t *op; + char *service = fc_cell2ptr(cp->svc_name); + + ASSERT(rp); + + FC_DEBUG1(1, CE_CONT, "opl_fc_do_op: <%s>\n", service); + + /* + * First try the generic fc_ops. + */ + if (fc_ops(ap, rp->next_handle, cp) == 0) + return (0); + + /* + * Now try the Jupiter-specific ops. + */ + for (op = opl_fc_ops; op->fc_service != NULL; ++op) + if (strcmp(op->fc_service, service) == 0) + return (op->fc_op(ap, rp, cp)); + + FC_DEBUG1(9, CE_CONT, "opl_fc_do_op: <%s> not serviced\n", service); + + return (-1); +} + +/* + * map-in (phys.lo phys.hi size -- virt) + */ +static int +opl_map_in(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) +{ + size_t len; + int error; + caddr_t virt; + struct fc_resource *resp; + struct regspec rspec; + ddi_device_acc_attr_t acc; + ddi_acc_handle_t h; + + if (fc_cell2int(cp->nargs) != 3) + return (fc_syntax_error(cp, "nargs must be 3")); + + if (fc_cell2int(cp->nresults) < 1) + return (fc_syntax_error(cp, "nresults must be >= 1")); + + rspec.regspec_size = len = fc_cell2size(fc_arg(cp, 0)); + rspec.regspec_bustype = fc_cell2uint(fc_arg(cp, 1)); + rspec.regspec_addr = fc_cell2uint(fc_arg(cp, 2)); + + acc.devacc_attr_version = DDI_DEVICE_ATTR_V0; + acc.devacc_attr_endian_flags = DDI_STRUCTURE_BE_ACC; + acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC; + + FC_DEBUG3(1, CE_CONT, "opl_map_in: attempting map in " + "address 0x%08x.%08x length %x\n", rspec.regspec_bustype, + rspec.regspec_addr, rspec.regspec_size); + + error = opl_map_phys(rp->child, &rspec, &virt, &acc, &h); + + if (error) { + FC_DEBUG3(1, CE_CONT, "opl_map_in: map in failed - " + "address 0x%08x.%08x length %x\n", rspec.regspec_bustype, + rspec.regspec_addr, rspec.regspec_size); + + return (fc_priv_error(cp, "opl map-in failed")); + } + + FC_DEBUG1(3, CE_CONT, "opl_map_in: returning virt %p\n", virt); + + cp->nresults = fc_int2cell(1); + fc_result(cp, 0) = fc_ptr2cell(virt); + + /* + * Log this resource ... + */ + resp = kmem_zalloc(sizeof (struct fc_resource), KM_SLEEP); + resp->type = RT_MAP; + resp->fc_map_virt = virt; + resp->fc_map_len = len; + resp->fc_map_handle = h; + fc_add_resource(rp, resp); + + return (fc_success_op(ap, rp, cp)); +} + +/* + * map-out (virt size -- ) + */ +static int +opl_map_out(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) +{ + caddr_t virt; + size_t len; + struct fc_resource *resp; + + if (fc_cell2int(cp->nargs) != 2) + return (fc_syntax_error(cp, "nargs must be 2")); + + virt = fc_cell2ptr(fc_arg(cp, 1)); + + len = fc_cell2size(fc_arg(cp, 0)); + + FC_DEBUG2(1, CE_CONT, "opl_map_out: attempting map out %p %x\n", + virt, len); + + /* + * Find if this request matches a mapping resource we set up. + */ + fc_lock_resource_list(rp); + for (resp = rp->head; resp != NULL; resp = resp->next) { + if (resp->type != RT_MAP) + continue; + if (resp->fc_map_virt != virt) + continue; + if (resp->fc_map_len == len) + break; + } + fc_unlock_resource_list(rp); + + if (resp == NULL) + return (fc_priv_error(cp, "request doesn't match a " + "known mapping")); + + opl_unmap_phys(&resp->fc_map_handle); + + /* + * remove the resource from the list and release it. + */ + fc_rem_resource(rp, resp); + kmem_free(resp, sizeof (struct fc_resource)); + + cp->nresults = fc_int2cell(0); + return (fc_success_op(ap, rp, cp)); +} + +static int +opl_register_fetch(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) +{ + size_t len; + caddr_t virt; + int error = 0; + uint64_t v; + uint64_t x; + uint32_t l; + uint16_t w; + uint8_t b; + char *service = fc_cell2ptr(cp->svc_name); + struct fc_resource *resp; + + if (fc_cell2int(cp->nargs) != 1) + return (fc_syntax_error(cp, "nargs must be 1")); + + if (fc_cell2int(cp->nresults) < 1) + return (fc_syntax_error(cp, "nresults must be >= 1")); + + virt = fc_cell2ptr(fc_arg(cp, 0)); + + /* + * Determine the access width .. we can switch on the 2nd + * character of the name which is "rx@", "rl@", "rb@" or "rw@" + */ + switch (*(service + 1)) { + case 'x': len = sizeof (x); break; + case 'l': len = sizeof (l); break; + case 'w': len = sizeof (w); break; + case 'b': len = sizeof (b); break; + } + + /* + * Check the alignment ... + */ + if (((intptr_t)virt & (len - 1)) != 0) + return (fc_priv_error(cp, "unaligned access")); + + /* + * Find if this virt is 'within' a request we know about + */ + fc_lock_resource_list(rp); + for (resp = rp->head; resp != NULL; resp = resp->next) { + if (resp->type == RT_MAP) { + if ((virt >= (caddr_t)resp->fc_map_virt) && + ((virt + len) <= + ((caddr_t)resp->fc_map_virt + resp->fc_map_len))) + break; + } else if (resp->type == RT_CONTIGIOUS) { + if ((virt >= (caddr_t)resp->fc_contig_virt) && ((virt + len) + <= ((caddr_t)resp->fc_contig_virt + + resp->fc_contig_len))) + break; + } + } + fc_unlock_resource_list(rp); + + if (resp == NULL) { + return (fc_priv_error(cp, "request not within " + "known mappings")); + } + + switch (len) { + case sizeof (x): + if (resp->type == RT_MAP) + error = ddi_peek64(rp->child, + (int64_t *)virt, (int64_t *)&x); + else /* RT_CONTIGIOUS */ + x = *(int64_t *)virt; + v = x; + break; + case sizeof (l): + if (resp->type == RT_MAP) + error = ddi_peek32(rp->child, + (int32_t *)virt, (int32_t *)&l); + else /* RT_CONTIGIOUS */ + l = *(int32_t *)virt; + v = l; + break; + case sizeof (w): + if (resp->type == RT_MAP) + error = ddi_peek16(rp->child, + (int16_t *)virt, (int16_t *)&w); + else /* RT_CONTIGIOUS */ + w = *(int16_t *)virt; + v = w; + break; + case sizeof (b): + if (resp->type == RT_MAP) + error = ddi_peek8(rp->child, + (int8_t *)virt, (int8_t *)&b); + else /* RT_CONTIGIOUS */ + b = *(int8_t *)virt; + v = b; + break; + } + + if (error == DDI_FAILURE) { + FC_DEBUG2(1, CE_CONT, "opl_register_fetch: access error " + "accessing virt %p len %d\n", virt, len); + return (fc_priv_error(cp, "access error")); + } + + FC_DEBUG3(1, CE_CONT, "register_fetch (%s) %llx %llx\n", + service, virt, v); + + cp->nresults = fc_int2cell(1); + switch (len) { + case sizeof (x): fc_result(cp, 0) = x; break; + case sizeof (l): fc_result(cp, 0) = fc_uint32_t2cell(l); break; + case sizeof (w): fc_result(cp, 0) = fc_uint16_t2cell(w); break; + case sizeof (b): fc_result(cp, 0) = fc_uint8_t2cell(b); break; + } + return (fc_success_op(ap, rp, cp)); +} + +static int +opl_register_store(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) +{ + size_t len; + caddr_t virt; + uint64_t v; + uint64_t x; + uint32_t l; + uint16_t w; + uint8_t b; + char *service = fc_cell2ptr(cp->svc_name); + struct fc_resource *resp; + int error = 0; + + if (fc_cell2int(cp->nargs) != 2) + return (fc_syntax_error(cp, "nargs must be 2")); + + virt = fc_cell2ptr(fc_arg(cp, 0)); + + /* + * Determine the access width .. we can switch on the 2nd + * character of the name which is "rx!", "rl!", "rb!" or "rw!" + */ + switch (*(service + 1)) { + case 'x': + len = sizeof (x); + x = fc_arg(cp, 1); + v = x; + break; + case 'l': + len = sizeof (l); + l = fc_cell2uint32_t(fc_arg(cp, 1)); + v = l; + break; + case 'w': + len = sizeof (w); + w = fc_cell2uint16_t(fc_arg(cp, 1)); + v = w; + break; + case 'b': + len = sizeof (b); + b = fc_cell2uint8_t(fc_arg(cp, 1)); + v = b; + break; + } + + FC_DEBUG3(1, CE_CONT, "register_store (%s) %llx %llx\n", + service, virt, v); + + /* + * Check the alignment ... + */ + if (((intptr_t)virt & (len - 1)) != 0) + return (fc_priv_error(cp, "unaligned access")); + + /* + * Find if this virt is 'within' a request we know about + */ + fc_lock_resource_list(rp); + for (resp = rp->head; resp != NULL; resp = resp->next) { + if (resp->type == RT_MAP) { + if ((virt >= (caddr_t)resp->fc_map_virt) && + ((virt + len) <= + ((caddr_t)resp->fc_map_virt + resp->fc_map_len))) + break; + } else if (resp->type == RT_CONTIGIOUS) { + if ((virt >= (caddr_t)resp->fc_contig_virt) && ((virt + len) + <= ((caddr_t)resp->fc_contig_virt + + resp->fc_contig_len))) + break; + } + } + fc_unlock_resource_list(rp); + + if (resp == NULL) + return (fc_priv_error(cp, "request not within" + "known mappings")); + + switch (len) { + case sizeof (x): + if (resp->type == RT_MAP) + error = ddi_poke64(rp->child, (int64_t *)virt, x); + else if (resp->type == RT_CONTIGIOUS) + *(uint64_t *)virt = x; + break; + case sizeof (l): + if (resp->type == RT_MAP) + error = ddi_poke32(rp->child, (int32_t *)virt, l); + else if (resp->type == RT_CONTIGIOUS) + *(uint32_t *)virt = l; + break; + case sizeof (w): + if (resp->type == RT_MAP) + error = ddi_poke16(rp->child, (int16_t *)virt, w); + else if (resp->type == RT_CONTIGIOUS) + *(uint16_t *)virt = w; + break; + case sizeof (b): + if (resp->type == RT_MAP) + error = ddi_poke8(rp->child, (int8_t *)virt, b); + else if (resp->type == RT_CONTIGIOUS) + *(uint8_t *)virt = b; + break; + } + + if (error == DDI_FAILURE) { + FC_DEBUG2(1, CE_CONT, "opl_register_store: access error " + "accessing virt %p len %d\n", virt, len); + return (fc_priv_error(cp, "access error")); + } + + cp->nresults = fc_int2cell(0); + return (fc_success_op(ap, rp, cp)); +} + +/* + * opl_claim_memory + * + * claim-memory (align size vhint -- vaddr) + */ +static int +opl_claim_memory(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) +{ + int align, size, vhint; + uint64_t answer, alen; + ndi_ra_request_t request; + struct fc_resource *resp; + + if (fc_cell2int(cp->nargs) != 3) + return (fc_syntax_error(cp, "nargs must be 3")); + + if (fc_cell2int(cp->nresults) < 1) + return (fc_syntax_error(cp, "nresults must be >= 1")); + + vhint = fc_cell2int(fc_arg(cp, 2)); + size = fc_cell2int(fc_arg(cp, 1)); + align = fc_cell2int(fc_arg(cp, 0)); + + FC_DEBUG3(1, CE_CONT, "opl_claim_memory: align=0x%x size=0x%x " + "vhint=0x%x\n", align, size, vhint); + + if (size == 0) { + cmn_err(CE_WARN, "opl_claim_memory - unable to allocate " + "contiguous memory of size zero\n"); + return (fc_priv_error(cp, "allocation error")); + } + + if (vhint) { + cmn_err(CE_WARN, "opl_claim_memory - vhint is not zero " + "vhint=0x%x - Ignoring Argument\n", vhint); + } + + bzero((caddr_t)&request, sizeof (ndi_ra_request_t)); + request.ra_flags = NDI_RA_ALLOC_BOUNDED; + request.ra_boundbase = 0; + request.ra_boundlen = 0xffffffff; + request.ra_len = size; + request.ra_align_mask = align - 1; + + if (ndi_ra_alloc(ddi_root_node(), &request, &answer, &alen, + "opl-fcodemem", NDI_RA_PASS) != NDI_SUCCESS) { + cmn_err(CE_WARN, "opl_claim_memory - unable to allocate " + "contiguous memory\n"); + return (fc_priv_error(cp, "allocation error")); + } + + FC_DEBUG2(1, CE_CONT, "opl_claim_memory: address allocated=0x%lx " + "size=0x%x\n", answer, alen); + + cp->nresults = fc_int2cell(1); + fc_result(cp, 0) = answer; + + /* + * Log this resource ... + */ + resp = kmem_zalloc(sizeof (struct fc_resource), KM_SLEEP); + resp->type = RT_CONTIGIOUS; + resp->fc_contig_virt = (void *)answer; + resp->fc_contig_len = size; + fc_add_resource(rp, resp); + + return (fc_success_op(ap, rp, cp)); +} + +/* + * opl_release_memory + * + * release-memory (size vaddr -- ) + */ +static int +opl_release_memory(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) +{ + int32_t vaddr, size; + struct fc_resource *resp; + + if (fc_cell2int(cp->nargs) != 2) + return (fc_syntax_error(cp, "nargs must be 2")); + + if (fc_cell2int(cp->nresults) != 0) + return (fc_syntax_error(cp, "nresults must be 0")); + + vaddr = fc_cell2int(fc_arg(cp, 1)); + size = fc_cell2int(fc_arg(cp, 0)); + + FC_DEBUG2(1, CE_CONT, "opl_release_memory: vaddr=0x%x size=0x%x\n", + vaddr, size); + + /* + * Find if this request matches a mapping resource we set up. + */ + fc_lock_resource_list(rp); + for (resp = rp->head; resp != NULL; resp = resp->next) { + if (resp->type != RT_CONTIGIOUS) + continue; + if (resp->fc_contig_virt != (void *)(uintptr_t)vaddr) + continue; + if (resp->fc_contig_len == size) + break; + } + fc_unlock_resource_list(rp); + + if (resp == NULL) + return (fc_priv_error(cp, "request doesn't match a " + "known mapping")); + + (void) ndi_ra_free(ddi_root_node(), vaddr, size, + "opl-fcodemem", NDI_RA_PASS); + + /* + * remove the resource from the list and release it. + */ + fc_rem_resource(rp, resp); + kmem_free(resp, sizeof (struct fc_resource)); + + cp->nresults = fc_int2cell(0); + + return (fc_success_op(ap, rp, cp)); +} + +/* + * opl_vtop + * + * vtop (vaddr -- paddr.lo paddr.hi) + */ +static int +opl_vtop(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) +{ + int vaddr; + uint64_t paddr; + struct fc_resource *resp; + + if (fc_cell2int(cp->nargs) != 1) + return (fc_syntax_error(cp, "nargs must be 1")); + + if (fc_cell2int(cp->nresults) >= 3) + return (fc_syntax_error(cp, "nresults must be less than 2")); + + vaddr = fc_cell2int(fc_arg(cp, 0)); + + /* + * Find if this request matches a mapping resource we set up. + */ + fc_lock_resource_list(rp); + for (resp = rp->head; resp != NULL; resp = resp->next) { + if (resp->type != RT_CONTIGIOUS) + continue; + if (resp->fc_contig_virt == (void *)(uintptr_t)vaddr) + break; + } + fc_unlock_resource_list(rp); + + if (resp == NULL) + return (fc_priv_error(cp, "request doesn't match a " + "known mapping")); + + paddr = va_to_pa((void *)(uintptr_t)vaddr); + + FC_DEBUG2(1, CE_CONT, "opl_vtop: vaddr=0x%x paddr=0x%x\n", + vaddr, paddr); + + cp->nresults = fc_int2cell(2); + + fc_result(cp, 0) = paddr; + fc_result(cp, 1) = 0; + + return (fc_success_op(ap, rp, cp)); +} + +static int +opl_config_child(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) +{ + fc_phandle_t h; + + if (fc_cell2int(cp->nargs) != 0) + return (fc_syntax_error(cp, "nargs must be 0")); + + if (fc_cell2int(cp->nresults) < 1) + return (fc_syntax_error(cp, "nresults must be >= 1")); + + h = fc_dip_to_phandle(fc_handle_to_phandle_head(rp), rp->child); + + cp->nresults = fc_int2cell(1); + fc_result(cp, 0) = fc_phandle2cell(h); + + return (fc_success_op(ap, rp, cp)); +} + +static int +opl_get_fcode(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) +{ + caddr_t dropin_name_virt, fcode_virt; + char *dropin_name, *fcode; + int fcode_len, status; + + if (fc_cell2int(cp->nargs) != 3) + return (fc_syntax_error(cp, "nargs must be 3")); + + if (fc_cell2int(cp->nresults) < 1) + return (fc_syntax_error(cp, "nresults must be >= 1")); + + dropin_name_virt = fc_cell2ptr(fc_arg(cp, 0)); + + fcode_virt = fc_cell2ptr(fc_arg(cp, 1)); + + fcode_len = fc_cell2int(fc_arg(cp, 2)); + + dropin_name = kmem_zalloc(FC_SVC_NAME_LEN, KM_SLEEP); + + FC_DEBUG2(1, CE_CONT, "get_fcode: %x %d\n", fcode_virt, fcode_len); + + if (copyinstr(fc_cell2ptr(dropin_name_virt), dropin_name, + FC_SVC_NAME_LEN - 1, NULL)) { + FC_DEBUG1(1, CE_CONT, "opl_get_fcode: " + "fault copying in drop in name %p\n", dropin_name_virt); + status = 0; + } else { + FC_DEBUG1(1, CE_CONT, "get_fcode: %s\n", dropin_name); + + fcode = kmem_zalloc(fcode_len, KM_SLEEP); + + if ((status = prom_get_fcode(dropin_name, fcode)) != 0) { + + if (copyout((void *)fcode, (void *)fcode_virt, + fcode_len)) { + cmn_err(CE_WARN, " opl_get_fcode: Unable " + "to copy out fcode image"); + status = 0; + } + } + + kmem_free(fcode, fcode_len); + } + + kmem_free(dropin_name, FC_SVC_NAME_LEN); + + cp->nresults = fc_int2cell(1); + fc_result(cp, 0) = status; + + return (fc_success_op(ap, rp, cp)); +} + +static int +opl_get_fcode_size(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) +{ + caddr_t virt; + char *dropin_name; + int len; + + if (fc_cell2int(cp->nargs) != 1) + return (fc_syntax_error(cp, "nargs must be 1")); + + if (fc_cell2int(cp->nresults) < 1) + return (fc_syntax_error(cp, "nresults must be >= 1")); + + virt = fc_cell2ptr(fc_arg(cp, 0)); + + dropin_name = kmem_zalloc(FC_SVC_NAME_LEN, KM_SLEEP); + + FC_DEBUG0(1, CE_CONT, "opl_get_fcode_size:\n"); + + if (copyinstr(fc_cell2ptr(virt), dropin_name, + FC_SVC_NAME_LEN - 1, NULL)) { + FC_DEBUG1(1, CE_CONT, "opl_get_fcode_size: " + "fault copying in drop in name %p\n", virt); + len = 0; + } else { + FC_DEBUG1(1, CE_CONT, "opl_get_fcode_size: %s\n", dropin_name); + + len = prom_get_fcode_size(dropin_name); + } + + kmem_free(dropin_name, FC_SVC_NAME_LEN); + + FC_DEBUG1(1, CE_CONT, "opl_get_fcode_size: fcode_len = %d\n", len); + + cp->nresults = fc_int2cell(1); + fc_result(cp, 0) = len; + + return (fc_success_op(ap, rp, cp)); +} + +static int +opl_map_phys(dev_info_t *dip, struct regspec *phys_spec, + caddr_t *addrp, ddi_device_acc_attr_t *accattrp, + ddi_acc_handle_t *handlep) +{ + ddi_map_req_t mapreq; + ddi_acc_hdl_t *acc_handlep; + int result; + struct regspec *rspecp; + + *handlep = impl_acc_hdl_alloc(KM_SLEEP, NULL); + acc_handlep = impl_acc_hdl_get(*handlep); + acc_handlep->ah_vers = VERS_ACCHDL; + acc_handlep->ah_dip = dip; + acc_handlep->ah_rnumber = 0; + acc_handlep->ah_offset = 0; + acc_handlep->ah_len = 0; + acc_handlep->ah_acc = *accattrp; + rspecp = kmem_zalloc(sizeof (struct regspec), KM_SLEEP); + *rspecp = *phys_spec; + /* + * cache a copy of the reg spec + */ + acc_handlep->ah_bus_private = rspecp; + + mapreq.map_op = DDI_MO_MAP_LOCKED; + mapreq.map_type = DDI_MT_REGSPEC; + mapreq.map_obj.rp = (struct regspec *)phys_spec; + mapreq.map_prot = PROT_READ | PROT_WRITE; + mapreq.map_flags = DDI_MF_KERNEL_MAPPING; + mapreq.map_handlep = acc_handlep; + mapreq.map_vers = DDI_MAP_VERSION; + + result = ddi_map(dip, &mapreq, 0, 0, addrp); + + if (result != DDI_SUCCESS) { + impl_acc_hdl_free(*handlep); + *handlep = (ddi_acc_handle_t)NULL; + } else { + acc_handlep->ah_addr = *addrp; + } + + return (result); +} + +static void +opl_unmap_phys(ddi_acc_handle_t *handlep) +{ + ddi_map_req_t mapreq; + ddi_acc_hdl_t *acc_handlep; + struct regspec *rspecp; + + acc_handlep = impl_acc_hdl_get(*handlep); + ASSERT(acc_handlep); + rspecp = acc_handlep->ah_bus_private; + + mapreq.map_op = DDI_MO_UNMAP; + mapreq.map_type = DDI_MT_REGSPEC; + mapreq.map_obj.rp = (struct regspec *)rspecp; + mapreq.map_prot = PROT_READ | PROT_WRITE; + mapreq.map_flags = DDI_MF_KERNEL_MAPPING; + mapreq.map_handlep = acc_handlep; + mapreq.map_vers = DDI_MAP_VERSION; + + (void) ddi_map(acc_handlep->ah_dip, &mapreq, acc_handlep->ah_offset, + acc_handlep->ah_len, &acc_handlep->ah_addr); + + impl_acc_hdl_free(*handlep); + /* + * Free the cached copy + */ + kmem_free(rspecp, sizeof (struct regspec)); + *handlep = (ddi_acc_handle_t)NULL; +} + +static int +opl_get_hwd_va(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) +{ + uint32_t portid; + void *hwd_virt; + hwd_header_t *hwd_h = NULL; + hwd_sb_t *hwd_sb = NULL; + int lsb, ch, leaf; + int status = 1; + + /* Check the argument */ + if (fc_cell2int(cp->nargs) != 2) + return (fc_syntax_error(cp, "nargs must be 2")); + + if (fc_cell2int(cp->nresults) < 1) + return (fc_syntax_error(cp, "nresults must be >= 1")); + + /* Get the parameters */ + portid = fc_cell2uint32_t(fc_arg(cp, 0)); + hwd_virt = (void *)fc_cell2ptr(fc_arg(cp, 1)); + + /* Get the ID numbers */ + lsb = OPL_IO_PORTID_TO_LSB(portid); + ch = OPL_PORTID_TO_CHANNEL(portid); + leaf = OPL_PORTID_TO_LEAF(portid); + ASSERT(OPL_IO_PORTID(lsb, ch, leaf) == portid); + + /* Set the pointer of hwd. */ + if ((hwd_h = (hwd_header_t *)opl_boards[lsb].cfg_hwd) == NULL) { + return (fc_priv_error(cp, "null hwd header")); + } + /* Set the pointer of hwd sb. */ + if ((hwd_sb = (hwd_sb_t *)((char *)hwd_h + hwd_h->hdr_sb_info_offset)) + == NULL) { + return (fc_priv_error(cp, "null hwd sb")); + } + + if (ch == OPL_CMU_CHANNEL) { + /* Copyout CMU-CH HW Descriptor */ + if (copyout((void *)&hwd_sb->sb_cmu.cmu_ch, + (void *)hwd_virt, sizeof (hwd_cmu_chan_t))) { + cmn_err(CE_WARN, "opl_get_hwd_va: " + "Unable to copy out cmuch descriptor for %x", + portid); + status = 0; + } + } else { + /* Copyout PCI-CH HW Descriptor */ + if (copyout((void *)&hwd_sb->sb_pci_ch[ch].pci_leaf[leaf], + (void *)hwd_virt, sizeof (hwd_leaf_t))) { + cmn_err(CE_WARN, "opl_get_hwd_va: " + "Unable to copy out pcich descriptor for %x", + portid); + status = 0; + } + } + + cp->nresults = fc_int2cell(1); + fc_result(cp, 0) = status; + + return (fc_success_op(ap, rp, cp)); +} + +/* + * Set the properties for a leaf node (Oberon leaf or CMU channel leaf). + */ +/*ARGSUSED*/ +static int +opl_create_leaf(dev_info_t *node, void *arg, uint_t flags) +{ + int ret; + + OPL_UPDATE_PROP(string, node, "name", OPL_PCI_LEAF_NODE); + + OPL_UPDATE_PROP(string, node, "status", "okay"); + + return (DDI_WALK_TERMINATE); +} + +static char * +opl_get_probe_string(opl_probe_t *probe, int channel, int leaf) +{ + char *probe_string; + int portid; + + probe_string = kmem_zalloc(PROBE_STR_SIZE, KM_SLEEP); + + if (channel == OPL_CMU_CHANNEL) + portid = probe->pr_sb->sb_cmu.cmu_ch.chan_portid; + else + portid = probe-> + pr_sb->sb_pci_ch[channel].pci_leaf[leaf].leaf_port_id; + + (void) sprintf(probe_string, "%x", portid); + + return (probe_string); +} + +static int +opl_probe_leaf(opl_probe_t *probe) +{ + int channel, leaf, portid, error, circ; + int board; + fco_handle_t fco_handle, *cfg_handle; + dev_info_t *parent, *leaf_node; + char unit_address[UNIT_ADDR_SIZE]; + char *probe_string; + opl_board_cfg_t *board_cfg; + + board = probe->pr_board; + channel = probe->pr_channel; + leaf = probe->pr_leaf; + parent = ddi_root_node(); + board_cfg = &opl_boards[board]; + + ASSERT(OPL_VALID_CHANNEL(channel)); + ASSERT(OPL_VALID_LEAF(leaf)); + + if (channel == OPL_CMU_CHANNEL) { + portid = probe->pr_sb->sb_cmu.cmu_ch.chan_portid; + cfg_handle = &board_cfg->cfg_cmuch_handle; + } else { + portid = probe-> + pr_sb->sb_pci_ch[channel].pci_leaf[leaf].leaf_port_id; + cfg_handle = &board_cfg->cfg_pcich_handle[channel][leaf]; + } + + /* + * Prevent any changes to leaf_node until we have bound + * it to the correct driver. + */ + ndi_devi_enter(parent, &circ); + + /* + * Ideally, fcode would be run from the "sid_branch_create" + * callback (that is the primary purpose of that callback). + * However, the fcode interpreter was written with the + * assumption that the "new_child" was linked into the + * device tree. The callback is invoked with the devinfo node + * in the DS_PROTO state. More investigation is needed before + * we can invoke the interpreter from the callback. For now, + * we create the "new_child" in the BOUND state, invoke the + * fcode interpreter and then rebind the dip to use any + * compatible properties created by fcode. + */ + + probe->pr_parent = parent; + probe->pr_create = opl_create_leaf; + probe->pr_hold = 1; + + leaf_node = opl_create_node(probe); + if (leaf_node == NULL) { + + cmn_err(CE_WARN, "IKP: create leaf (%d-%d-%d) failed", + probe->pr_board, probe->pr_channel, probe->pr_leaf); + ndi_devi_exit(parent, circ); + return (-1); + } + + /* + * The platform DR interfaces created the dip in + * bound state. Bring devinfo node down to linked + * state and hold it there until compatible + * properties are created. + */ + e_ddi_branch_rele(leaf_node); + (void) i_ndi_unconfig_node(leaf_node, DS_LINKED, 0); + ASSERT(i_ddi_node_state(leaf_node) == DS_LINKED); + e_ddi_branch_hold(leaf_node); + + mutex_enter(&DEVI(leaf_node)->devi_lock); + DEVI(leaf_node)->devi_flags |= DEVI_NO_BIND; + mutex_exit(&DEVI(leaf_node)->devi_lock); + + /* + * Drop the busy-hold on parent before calling + * fcode_interpreter to prevent potential deadlocks + */ + ndi_devi_exit(parent, circ); + + (void) sprintf(unit_address, "%x", portid); + + /* + * Get the probe string + */ + probe_string = opl_get_probe_string(probe, channel, leaf); + + /* + * The fcode pointer specified here is NULL and the fcode + * size specified here is 0. This causes the user-level + * fcode interpreter to issue a request to the fcode + * driver to get the Oberon/cmu-ch fcode. + */ + fco_handle = opl_fc_ops_alloc_handle(parent, leaf_node, + NULL, 0, unit_address, probe_string); + + error = fcode_interpreter(parent, &opl_fc_do_op, fco_handle); + + if (error != 0) { + cmn_err(CE_WARN, "IKP: Unable to probe PCI leaf (%d-%d-%d)", + probe->pr_board, probe->pr_channel, probe->pr_leaf); + + opl_fc_ops_free_handle(fco_handle); + + if (probe_string != NULL) + kmem_free(probe_string, PROBE_STR_SIZE); + + (void) opl_destroy_node(leaf_node); + } else { + *cfg_handle = fco_handle; + + if (channel == OPL_CMU_CHANNEL) + board_cfg->cfg_cmuch_probe_str = probe_string; + else + board_cfg->cfg_pcich_probe_str[channel][leaf] + = probe_string; + + /* + * Compatible properties (if any) have been created, + * so bind driver. + */ + ndi_devi_enter(parent, &circ); + ASSERT(i_ddi_node_state(leaf_node) <= DS_LINKED); + + mutex_enter(&DEVI(leaf_node)->devi_lock); + DEVI(leaf_node)->devi_flags &= ~DEVI_NO_BIND; + mutex_exit(&DEVI(leaf_node)->devi_lock); + + ndi_devi_exit(parent, circ); + + if (ndi_devi_bind_driver(leaf_node, 0) != + DDI_SUCCESS) { + cmn_err(CE_WARN, + "IKP: Unable to bind PCI leaf (%d-%d-%d)", + probe->pr_board, probe->pr_channel, + probe->pr_leaf); + } + } + + if ((error != 0) && (channel == OPL_CMU_CHANNEL)) + return (-1); + + return (0); +} + +static void +opl_init_leaves(int myboard) +{ + dev_info_t *parent, *node; + char *name; + int circ, ret; + int len, portid, board, channel, leaf; + opl_board_cfg_t *cfg; + + parent = ddi_root_node(); + + /* + * Hold parent node busy to walk its child list + */ + ndi_devi_enter(parent, &circ); + + for (node = ddi_get_child(parent); + (node != NULL); + node = ddi_get_next_sibling(node)) { + + ret = OPL_GET_PROP(string, node, "name", &name, &len); + if (ret != DDI_PROP_SUCCESS) { + /* + * The property does not exist for this node. + */ + continue; + } + + if (strncmp(name, OPL_PCI_LEAF_NODE, len) == 0) { + + ret = OPL_GET_PROP(int, node, "portid", &portid, -1); + if (ret == DDI_PROP_SUCCESS) { + + ret = OPL_GET_PROP(int, node, "board#", + &board, -1); + if ((ret != DDI_PROP_SUCCESS) || + (board != myboard)) + continue; + + cfg = &opl_boards[board]; + channel = OPL_PORTID_TO_CHANNEL(portid); + if (channel == OPL_CMU_CHANNEL) { + + if (cfg->cfg_cmuch_handle != NULL) + cfg->cfg_cmuch_leaf = node; + + } else { + + leaf = OPL_PORTID_TO_LEAF(portid); + if (cfg->cfg_pcich_handle + [channel][leaf] != NULL) + cfg->cfg_pcich_leaf + [channel][leaf] = node; + } + } + } + + kmem_free(name, len); + if (ret != DDI_PROP_SUCCESS) + break; + } + + ndi_devi_exit(parent, circ); +} + +/* + * Create "pci" node and hierarchy for the Oberon channels and the + * CMU channel. + */ +/*ARGSUSED*/ +static int +opl_probe_io(opl_probe_t *probe) +{ + + int i, j; + hwd_pci_ch_t *channels; + + if (HWD_STATUS_OK(probe->pr_sb->sb_cmu.cmu_ch.chan_status)) { + + probe->pr_channel = HWD_CMU_CHANNEL; + probe->pr_channel_status = + probe->pr_sb->sb_cmu.cmu_ch.chan_status; + probe->pr_leaf = 0; + probe->pr_leaf_status = probe->pr_channel_status; + + if (opl_probe_leaf(probe) != 0) + return (-1); + } + + channels = &probe->pr_sb->sb_pci_ch[0]; + + for (i = 0; i < HWD_PCI_CHANNELS_PER_SB; i++) { + + if (!HWD_STATUS_OK(channels[i].pci_status)) + continue; + + probe->pr_channel = i; + probe->pr_channel_status = channels[i].pci_status; + + for (j = 0; j < HWD_LEAVES_PER_PCI_CHANNEL; j++) { + + probe->pr_leaf = j; + probe->pr_leaf_status = + channels[i].pci_leaf[j].leaf_status; + + if (!HWD_STATUS_OK(probe->pr_leaf_status)) + continue; + + (void) opl_probe_leaf(probe); + } + } + opl_init_leaves(probe->pr_board); + return (0); +} + +/* + * Perform the probe in the following order: + * + * processors + * memory + * IO + * + * Each probe function returns 0 on sucess and a non-zero value on failure. + * What is a failure is determined by the implementor of the probe function. + * For example, while probing CPUs, any error encountered during probe + * is considered a failure and causes the whole probe operation to fail. + * However, for I/O, an error encountered while probing one device + * should not prevent other devices from being probed. It should not cause + * the whole probe operation to fail. + */ +int +opl_probe_sb(int board) +{ + opl_probe_t *probe; + int ret; + + if ((board < 0) || (board >= HWD_SBS_PER_DOMAIN)) + return (-1); + + ASSERT(opl_cfg_inited != 0); + + /* + * If the previous probe failed and left a partially configured + * board, we need to unprobe the board and start with a clean slate. + */ + if ((opl_boards[board].cfg_hwd != NULL) && + (opl_unprobe_sb(board) != 0)) + return (-1); + + ret = 0; + + probe = kmem_zalloc(sizeof (opl_probe_t), KM_SLEEP); + probe->pr_board = board; + + if ((opl_probe_init(probe) != 0) || + + (opl_probe_cpu_chips(probe) != 0) || + + (opl_probe_memory(probe) != 0) || + + (opl_probe_io(probe) != 0)) { + + /* + * Probe failed. Perform cleanup. + */ + (void) opl_unprobe_sb(board); + ret = -1; + } + + kmem_free(probe, sizeof (opl_probe_t)); + + return (ret); +} + +/* + * This unprobing also includes CMU-CH. + */ +/*ARGSUSED*/ +static int +opl_unprobe_io(int board) +{ + int i, j, ret; + opl_board_cfg_t *board_cfg; + dev_info_t **node; + fco_handle_t *hand; + char **probe_str; + + board_cfg = &opl_boards[board]; + + for (i = 0; i < HWD_PCI_CHANNELS_PER_SB; i++) { + + for (j = 0; j < HWD_LEAVES_PER_PCI_CHANNEL; j++) { + + node = &board_cfg->cfg_pcich_leaf[i][j]; + hand = &board_cfg->cfg_pcich_handle[i][j]; + probe_str = &board_cfg->cfg_pcich_probe_str[i][j]; + + if (*node == NULL) + continue; + + if (*hand != NULL) { + opl_fc_ops_free_handle(*hand); + *hand = NULL; + } + + if (*probe_str != NULL) { + kmem_free(*probe_str, PROBE_STR_SIZE); + *probe_str = NULL; + } + + ret = opl_destroy_node(*node); + if (ret != 0) { + + cmn_err(CE_WARN, + "IKP: destroy pci (%d-%d-%d) failed", + board, i, j); + return (-1); + } + + *node = NULL; + + } + } + + node = &board_cfg->cfg_cmuch_leaf; + hand = &board_cfg->cfg_cmuch_handle; + probe_str = &board_cfg->cfg_cmuch_probe_str; + + if (*node == NULL) + return (0); + + if (*hand != NULL) { + opl_fc_ops_free_handle(*hand); + *hand = NULL; + } + + if (*probe_str != NULL) { + kmem_free(*probe_str, PROBE_STR_SIZE); + *probe_str = NULL; + } + + if (opl_destroy_node(*node) != 0) { + + cmn_err(CE_WARN, "IKP: destroy pci (%d-%d-%d) failed", + board, OPL_CMU_CHANNEL, 0); + return (-1); + } + + *node = NULL; + + return (0); +} + +/* + * Destroy the "pseudo-mc" node for a board. + */ +static int +opl_unprobe_memory(int board) +{ + opl_board_cfg_t *board_cfg; + + board_cfg = &opl_boards[board]; + + if (board_cfg->cfg_pseudo_mc == NULL) + return (0); + + if (opl_destroy_node(board_cfg->cfg_pseudo_mc) != 0) { + + cmn_err(CE_WARN, "IKP: destroy pseudo-mc (%d) failed", board); + return (-1); + } + + board_cfg->cfg_pseudo_mc = NULL; + + return (0); +} + +/* + * Destroy the "cmp" nodes for a board. This also destroys the "core" + * and "cpu" nodes below the "cmp" nodes. + */ +static int +opl_unprobe_processors(int board) +{ + int i; + dev_info_t **cfg_cpu_chips; + + cfg_cpu_chips = opl_boards[board].cfg_cpu_chips; + + for (i = 0; i < HWD_CPU_CHIPS_PER_CMU; i++) { + + if (cfg_cpu_chips[i] == NULL) + continue; + + if (opl_destroy_node(cfg_cpu_chips[i]) != 0) { + + cmn_err(CE_WARN, + "IKP: destroy chip (%d-%d) failed", board, i); + return (-1); + } + + cfg_cpu_chips[i] = NULL; + } + + return (0); +} + +/* + * Perform the unprobe in the following order: + * + * IO + * memory + * processors + */ +int +opl_unprobe_sb(int board) +{ + if ((board < 0) || (board >= HWD_SBS_PER_DOMAIN)) + return (-1); + + ASSERT(opl_cfg_inited != 0); + + if ((opl_unprobe_io(board) != 0) || + + (opl_unprobe_memory(board) != 0) || + + (opl_unprobe_processors(board) != 0)) + + return (-1); + + if (opl_boards[board].cfg_hwd != NULL) { +#ifdef UCTEST + size_t size = 0xA000; +#endif + /* Release the memory for the HWD */ + void *hwdp = opl_boards[board].cfg_hwd; + opl_boards[board].cfg_hwd = NULL; +#ifdef UCTEST + hwdp = (void *)((char *)hwdp - 0x1000); + hat_unload(kas.a_hat, hwdp, size, HAT_UNLOAD_UNLOCK); + vmem_free(heap_arena, hwdp, size); +#else + kmem_free(hwdp, HWD_DATA_SIZE); +#endif + } + return (0); +} + +/* + * For MAC patrol support, we need to update the PA-related properties + * when there is a copy-rename event. This should be called after the + * physical copy and rename has been done by DR, and before the MAC + * patrol is restarted. + */ +int +oplcfg_pa_swap(int from, int to) +{ + dev_info_t *from_node = opl_boards[from].cfg_pseudo_mc; + dev_info_t *to_node = opl_boards[to].cfg_pseudo_mc; + opl_range_t *rangef, *ranget; + int elems; + int ret; + + if ((OPL_GET_PROP_ARRAY(int, from_node, "sb-mem-ranges", rangef, + elems) != DDI_SUCCESS) || (elems != 4)) { + /* XXX -- bad news */ + return (-1); + } + if ((OPL_GET_PROP_ARRAY(int, to_node, "sb-mem-ranges", ranget, + elems) != DDI_SUCCESS) || (elems != 4)) { + /* XXX -- bad news */ + return (-1); + } + OPL_UPDATE_PROP_ARRAY(int, from_node, "sb-mem-ranges", (int *)ranget, + 4); + OPL_UPDATE_PROP_ARRAY(int, to_node, "sb-mem-ranges", (int *)rangef, + 4); + + OPL_FREE_PROP(ranget); + OPL_FREE_PROP(rangef); + + return (0); +} diff --git a/usr/src/uts/sun4u/io/px/oberon_regs.h b/usr/src/uts/sun4u/io/px/oberon_regs.h new file mode 100644 index 0000000000..3fd69f96a7 --- /dev/null +++ b/usr/src/uts/sun4u/io/px/oberon_regs.h @@ -0,0 +1,183 @@ +/* + * 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_OBERON_REGS_H +#define _SYS_OBERON_REGS_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + + +#define UBC_ERROR_LOG_ENABLE 0x471000 +#define UBC_ERROR_STATUS_CLEAR 0x471018 +#define UBC_INTERRUPT_ENABLE 0x471008 +#define UBC_INTERRUPT_STATUS 0x471010 +#define UBC_INTERRUPT_STATUS_DMARDUEA_P 0 +#define UBC_INTERRUPT_STATUS_DMAWTUEA_P 1 +#define UBC_INTERRUPT_STATUS_MEMRDAXA_P 2 +#define UBC_INTERRUPT_STATUS_MEMWTAXA_P 3 +#define UBC_INTERRUPT_STATUS_DMARDUEB_P 8 +#define UBC_INTERRUPT_STATUS_DMAWTUEB_P 9 +#define UBC_INTERRUPT_STATUS_MEMRDAXB_P 10 +#define UBC_INTERRUPT_STATUS_MEMWTAXB_P 11 +#define UBC_INTERRUPT_STATUS_PIOWTUE_P 16 +#define UBC_INTERRUPT_STATUS_PIOWBEUE_P 17 +#define UBC_INTERRUPT_STATUS_PIORBEUE_P 18 +#define UBC_INTERRUPT_STATUS_DMARDUEA_S 32 +#define UBC_INTERRUPT_STATUS_DMAWTUEA_S 33 +#define UBC_INTERRUPT_STATUS_MEMRDAXA_S 34 +#define UBC_INTERRUPT_STATUS_MEMWTAXA_S 35 +#define UBC_INTERRUPT_STATUS_DMARDUEB_S 40 +#define UBC_INTERRUPT_STATUS_DMAWTUEB_S 41 +#define UBC_INTERRUPT_STATUS_MEMRDAXB_S 42 +#define UBC_INTERRUPT_STATUS_MEMWTAXB_S 43 +#define UBC_INTERRUPT_STATUS_PIOWTUE_S 48 +#define UBC_INTERRUPT_STATUS_PIOWBEUE_S 49 +#define UBC_INTERRUPT_STATUS_PIORBEUE_S 50 +#define UBC_ERROR_STATUS_SET 0x471020 +#define UBC_PERFORMANCE_COUNTER_SELECT 0x472000 +#define UBC_PERFORMANCE_COUNTER_ZERO 0x472008 +#define UBC_PERFORMANCE_COUNTER_ONE 0x472010 +#define UBC_PERFORMANCE_COUNTER_SEL_MASKS 0x3f3f +#define UBC_MEMORY_UE_LOG 0x471028 +#define UBC_MEMORY_UE_LOG_EID 60 +#define UBC_MEMORY_UE_LOG_EID_MASK 0x3 +#define UBC_MEMORY_UE_LOG_MARKED 48 +#define UBC_MEMORY_UE_LOG_MARKED_MASK 0x3fff +#define UBC_MARKED_MAX_CPUID_MASK 0x1ff +/* + * Class qualifiers on errors for which EID is valid. + */ +#define UBC_EID_MEM 0 +#define UBC_EID_CHANNEL 1 +#define UBC_EID_CPU 2 +#define UBC_EID_PATH 3 + +#define OBERON_UBC_ID_MAX 64 +#define OBERON_UBC_ID_IOC 0 +#define OBERON_UBC_ID_LSB 2 + +#define OBERON_PORT_ID_IOC 1 +#define OBERON_PORT_ID_IOC_MASK 0x03 +#define OBERON_PORT_ID_LSB 4 +#define OBERON_PORT_ID_LSB_MASK 0x0F + +#define INTERRUPT_MAPPING_ENTRIES_T_DESTID 21 +#define INTERRUPT_MAPPING_ENTRIES_T_DESTID_MASK 0x3ff + +#define OBERON_TLU_CONTROL_DRN_TR_DIS 35 +#define OBERON_TLU_CONTROL_CPLEP_DEN 34 +#define OBERON_TLU_CONTROL_ECRCCHK_DIS 33 +#define OBERON_TLU_CONTROL_ECRCGEN_DIS 32 + +#define TLU_SLOT_CAPABILITIES_HP 6 +#define TLU_SLOT_CAPABILITIES_HPSUP 5 +#define TLU_SLOT_CAPABILITIES_PWINDP 4 +#define TLU_SLOT_CAPABILITIES_ATINDP 3 +#define TLU_SLOT_CAPABILITIES_MRLSP 2 +#define TLU_SLOT_CAPABILITIES_PWCNTLP 1 +#define TLU_SLOT_CAPABILITIES_ATBTNP 0 + +#define DLU_INTERRUPT_MASK 0xe2048 +#define DLU_INTERRUPT_MASK_MSK_INTERRUPT_EN 31 +#define DLU_INTERRUPT_MASK_MSK_LINK_LAYER 5 +#define DLU_INTERRUPT_MASK_MSK_PHY_ERROR 4 +#define DLU_LINK_LAYER_CONFIG 0xe2200 +#define DLU_LINK_LAYER_CONFIG_VC0_EN 8 +#define DLU_LINK_LAYER_CONFIG_TLP_XMIT_FC_EN 3 +#define DLU_LINK_LAYER_CONFIG_FREQ_ACK_ENABLE 2 +#define DLU_LINK_LAYER_CONFIG_RETRY_DISABLE 1 +#define DLU_LINK_LAYER_INTERRUPT_AND_STATUS 0xe2210 +#define DLU_LINK_LAYER_INTERRUPT_AND_STATUS_INT_LINK_ERR_ACT 31 +#define DLU_LINK_LAYER_INTERRUPT_AND_STATUS_INT_PARABUS_PE 23 +#define DLU_LINK_LAYER_INTERRUPT_AND_STATUS_INT_UNSPRTD_DLLP 22 +#define DLU_LINK_LAYER_INTERRUPT_AND_STATUS_INT_SRC_ERR_TLP 17 +#define DLU_LINK_LAYER_INTERRUPT_MASK 0xe2220 +#define DLU_LINK_LAYER_INTERRUPT_MASK_MSK_LINK_ERR_ACT 31 +#define DLU_LINK_LAYER_INTERRUPT_MASK_MSK_PARABUS_PE 23 +#define DLU_LINK_LAYER_INTERRUPT_MASK_MSK_UNSPRTD_DLLP 22 +#define DLU_LINK_LAYER_INTERRUPT_MASK_MSK_SRC_ERR_TLP 17 +#define DLU_FLOW_CONTROL_UPDATE_CONTROL 0xe2240 +#define DLU_FLOW_CONTROL_UPDATE_CONTROL_FC0_U_C_EN 2 +#define DLU_FLOW_CONTROL_UPDATE_CONTROL_FC0_U_NP_EN 1 +#define DLU_FLOW_CONTROL_UPDATE_CONTROL_FC0_U_P_EN 0 +#define DLU_TXLINK_REPLAY_TIMER_THRESHOLD 0xe2410 +#define DLU_TXLINK_REPLAY_TIMER_THRESHOLD_RPLAY_TMR_THR 0 +#define DLU_TXLINK_REPLAY_TIMER_THRESHOLD_RPLAY_TMR_THR_MASK 0xfffff +#define DLU_TXLINK_REPLAY_TIMER_THRESHOLD_DEFAULT 0xc9 +#define DLU_PORT_CONTROL 0xe2b00 +#define DLU_PORT_CONTROL_CK_EN 0 +#define DLU_PORT_STATUS 0xe2b08 + +#define MMU_INTERRUPT_STATUS_TTC_DUE_P 8 +#define MMU_INTERRUPT_STATUS_TTC_DUE_S 40 +#define ILU_INTERRUPT_STATUS_IHB_UE_P 4 +#define ILU_INTERRUPT_STATUS_IHB_UE_S 36 +#define TLU_UNCORRECTABLE_ERROR_STATUS_CLEAR_ECRC_P 19 +#define TLU_UNCORRECTABLE_ERROR_STATUS_CLEAR_ECRC_S 51 +#define TLU_UNCORRECTABLE_ERROR_STATUS_CLEAR_POIS_P 12 +#define TLU_UNCORRECTABLE_ERROR_STATUS_CLEAR_POIS_S 44 +#define TLU_OTHER_EVENT_STATUS_CLEAR_EIUE_P 0 +#define TLU_OTHER_EVENT_STATUS_CLEAR_EIUE_S 32 +#define TLU_OTHER_EVENT_STATUS_CLEAR_ERBUE_P 1 +#define TLU_OTHER_EVENT_STATUS_CLEAR_ERBUE_S 33 +#define TLU_OTHER_EVENT_STATUS_CLEAR_TLUEITMO_P 7 +#define TLU_OTHER_EVENT_STATUS_CLEAR_TLUEITMO_S 39 +#define TLU_OTHER_EVENT_STATUS_CLEAR_EHBUE_P 12 +#define TLU_OTHER_EVENT_STATUS_CLEAR_EHBUE_S 44 +#define TLU_OTHER_EVENT_STATUS_CLEAR_EDBUE_P 12 +#define TLU_OTHER_EVENT_STATUS_CLEAR_EDBUE_S 44 + +#define TLU_CONTROL_DRN_TR_DIS 35 + +#define TLU_SLOT_CONTROL 0x90038 +#define TLU_SLOT_CONTROL_PWFDEN 1 +#define TLU_SLOT_STATUS 0x90040 +#define TLU_SLOT_STATUS_PSD 6 +#define TLU_SLOT_STATUS_MRLS 5 +#define TLU_SLOT_STATUS_CMDCPLT 4 +#define TLU_SLOT_STATUS_PSDC 3 +#define TLU_SLOT_STATUS_MRLC 2 +#define TLU_SLOT_STATUS_PWFD 1 +#define TLU_SLOT_STATUS_ABTN 0 + +#define FLP_PORT_CONTROL 0xe5200 +#define FLP_PORT_CONTROL_PORT_DIS 0 + +#define HOTPLUG_CONTROL 0x88000 +#define HOTPLUG_CONTROL_SLOTPON 3 +#define HOTPLUG_CONTROL_PWREN 2 +#define HOTPLUG_CONTROL_CLKEN 1 +#define HOTPLUG_CONTROL_N_PERST 0 + +#define PX_PCIEHP_PIL (LOCK_LEVEL - 1) +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_OBERON_REGS_H */ diff --git a/usr/src/uts/sun4u/io/px/px_err.c b/usr/src/uts/sun4u/io/px/px_err.c index 59a3ca3311..2ab0a6eb16 100644 --- a/usr/src/uts/sun4u/io/px/px_err.c +++ b/usr/src/uts/sun4u/io/px/px_err.c @@ -40,10 +40,83 @@ #include <px_regs.h> #include <px_csr.h> #include <sys/membar.h> +#include <sys/machcpuvar.h> +#include <sys/platform_module.h> #include "pcie_pwr.h" #include "px_lib4u.h" #include "px_err.h" #include "px_err_impl.h" +#include "oberon_regs.h" + +uint64_t px_tlu_ue_intr_mask = PX_ERR_EN_ALL; +uint64_t px_tlu_ue_log_mask = PX_ERR_EN_ALL; +uint64_t px_tlu_ue_count_mask = PX_ERR_EN_ALL; + +uint64_t px_tlu_ce_intr_mask = PX_ERR_MASK_NONE; +uint64_t px_tlu_ce_log_mask = PX_ERR_MASK_NONE; +uint64_t px_tlu_ce_count_mask = PX_ERR_MASK_NONE; + +/* + * Do not enable Link Interrupts + */ +uint64_t px_tlu_oe_intr_mask = PX_ERR_EN_ALL & ~0x80000000800; +uint64_t px_tlu_oe_log_mask = PX_ERR_EN_ALL & ~0x80000000800; +uint64_t px_tlu_oe_count_mask = PX_ERR_EN_ALL; + +uint64_t px_mmu_intr_mask = PX_ERR_EN_ALL; +uint64_t px_mmu_log_mask = PX_ERR_EN_ALL; +uint64_t px_mmu_count_mask = PX_ERR_EN_ALL; + +uint64_t px_imu_intr_mask = PX_ERR_EN_ALL; +uint64_t px_imu_log_mask = PX_ERR_EN_ALL; +uint64_t px_imu_count_mask = PX_ERR_EN_ALL; + +/* + * (1ull << ILU_INTERRUPT_ENABLE_IHB_PE_S) | + * (1ull << ILU_INTERRUPT_ENABLE_IHB_PE_P); + */ +uint64_t px_ilu_intr_mask = (((uint64_t)0x10 << 32) | 0x10); +uint64_t px_ilu_log_mask = (((uint64_t)0x10 << 32) | 0x10); +uint64_t px_ilu_count_mask = PX_ERR_EN_ALL; + +uint64_t px_ubc_intr_mask = PX_ERR_EN_ALL; +uint64_t px_ubc_log_mask = PX_ERR_EN_ALL; +uint64_t px_ubc_count_mask = PX_ERR_EN_ALL; + +uint64_t px_jbc_intr_mask = PX_ERR_EN_ALL; +uint64_t px_jbc_log_mask = PX_ERR_EN_ALL; +uint64_t px_jbc_count_mask = PX_ERR_EN_ALL; + +/* + * LPU Intr Registers are reverse encoding from the registers above. + * 1 = disable + * 0 = enable + * + * Log and Count are however still the same. + */ +uint64_t px_lpul_intr_mask = LPU_INTR_DISABLE; +uint64_t px_lpul_log_mask = PX_ERR_EN_ALL; +uint64_t px_lpul_count_mask = PX_ERR_EN_ALL; + +uint64_t px_lpup_intr_mask = LPU_INTR_DISABLE; +uint64_t px_lpup_log_mask = PX_ERR_EN_ALL; +uint64_t px_lpup_count_mask = PX_ERR_EN_ALL; + +uint64_t px_lpur_intr_mask = LPU_INTR_DISABLE; +uint64_t px_lpur_log_mask = PX_ERR_EN_ALL; +uint64_t px_lpur_count_mask = PX_ERR_EN_ALL; + +uint64_t px_lpux_intr_mask = LPU_INTR_DISABLE; +uint64_t px_lpux_log_mask = PX_ERR_EN_ALL; +uint64_t px_lpux_count_mask = PX_ERR_EN_ALL; + +uint64_t px_lpus_intr_mask = LPU_INTR_DISABLE; +uint64_t px_lpus_log_mask = PX_ERR_EN_ALL; +uint64_t px_lpus_count_mask = PX_ERR_EN_ALL; + +uint64_t px_lpug_intr_mask = LPU_INTR_DISABLE; +uint64_t px_lpug_log_mask = PX_ERR_EN_ALL; +uint64_t px_lpug_count_mask = PX_ERR_EN_ALL; /* * JBC error bit table @@ -59,7 +132,7 @@ PX_ERR_BIT_HANDLE(hdl), \ PX_ERPT_SEND(erpt), \ PX_ERR_JBC_CLASS(bit) -px_err_bit_desc_t px_err_cb_tbl[] = { +px_err_bit_desc_t px_err_jbc_tbl[] = { /* JBC FATAL - see io erpt doc, section 1.1 */ { JBC_BIT_DESC(MB_PEA, fatal_hw, jbc_fatal) }, { JBC_BIT_DESC(CPE, fatal_hw, jbc_fatal) }, @@ -105,8 +178,49 @@ px_err_bit_desc_t px_err_cb_tbl[] = { { JBC_BIT_DESC(EBUS_TO, jbc_csr, jbc_csr) } }; -#define px_err_cb_keys \ - (sizeof (px_err_cb_tbl)) / (sizeof (px_err_bit_desc_t)) +#define px_err_jbc_keys \ + (sizeof (px_err_jbc_tbl)) / (sizeof (px_err_bit_desc_t)) + +/* + * UBC error bit table + */ +#define UBC_BIT_DESC(bit, hdl, erpt) \ + UBC_INTERRUPT_STATUS_ ## bit ## _P, \ + 0, \ + PX_ERR_BIT_HANDLE(hdl), \ + PX_ERPT_SEND(erpt), \ + PX_ERR_UBC_CLASS(bit) }, \ + { UBC_INTERRUPT_STATUS_ ## bit ## _S, \ + 0, \ + PX_ERR_BIT_HANDLE(hdl), \ + PX_ERPT_SEND(erpt), \ + PX_ERR_UBC_CLASS(bit) +px_err_bit_desc_t px_err_ubc_tbl[] = { + /* UBC FATAL */ + { UBC_BIT_DESC(DMARDUEA, non_fatal, ubc_fatal) }, + { UBC_BIT_DESC(DMAWTUEA, fatal_sw, ubc_fatal) }, + { UBC_BIT_DESC(MEMRDAXA, fatal_sw, ubc_fatal) }, + { UBC_BIT_DESC(MEMWTAXA, fatal_sw, ubc_fatal) }, + { UBC_BIT_DESC(DMARDUEB, non_fatal, ubc_fatal) }, + { UBC_BIT_DESC(DMAWTUEB, fatal_sw, ubc_fatal) }, + { UBC_BIT_DESC(MEMRDAXB, fatal_sw, ubc_fatal) }, + { UBC_BIT_DESC(MEMWTAXB, fatal_sw, ubc_fatal) }, + { UBC_BIT_DESC(PIOWTUE, fatal_sw, ubc_fatal) }, + { UBC_BIT_DESC(PIOWBEUE, fatal_sw, ubc_fatal) }, + { UBC_BIT_DESC(PIORBEUE, fatal_sw, ubc_fatal) } +}; + +#define px_err_ubc_keys \ + (sizeof (px_err_ubc_tbl)) / (sizeof (px_err_bit_desc_t)) + + +char *ubc_class_eid_qualifier[] = { + "-mem", + "-channel", + "-cpu", + "-path" +}; + /* * DMC error bit tables @@ -173,6 +287,7 @@ px_err_bit_desc_t px_err_mmu_tbl[] = { }; #define px_err_mmu_keys (sizeof (px_err_mmu_tbl)) / (sizeof (px_err_bit_desc_t)) + /* * PEC error bit tables */ @@ -210,12 +325,24 @@ px_err_bit_desc_t px_err_ilu_tbl[] = { PX_ERR_BIT_HANDLE(hdl), \ PX_ERPT_SEND(erpt), \ PX_ERR_PEC_CLASS(bit) +#define TLU_UC_OB_BIT_DESC(bit, hdl, erpt) \ + TLU_UNCORRECTABLE_ERROR_STATUS_CLEAR_ ## bit ## _P, \ + 0, \ + PX_ERR_BIT_HANDLE(hdl), \ + PX_ERPT_SEND(erpt), \ + PX_ERR_PEC_OB_CLASS(bit) }, \ + { TLU_UNCORRECTABLE_ERROR_STATUS_CLEAR_ ## bit ## _S, \ + 0, \ + PX_ERR_BIT_HANDLE(hdl), \ + PX_ERPT_SEND(erpt), \ + PX_ERR_PEC_CLASS(bit) px_err_bit_desc_t px_err_tlu_ue_tbl[] = { /* PCI-E Receive Uncorrectable Errors - see io erpt doc, section 3.2 */ { TLU_UC_BIT_DESC(UR, pciex_ue, pciex_rx_ue) }, { TLU_UC_BIT_DESC(UC, pciex_ue, pciex_rx_ue) }, /* PCI-E Transmit Uncorrectable Errors - see io erpt doc, section 3.3 */ + { TLU_UC_OB_BIT_DESC(ECRC, pciex_ue, pciex_rx_ue) }, { TLU_UC_BIT_DESC(CTO, pciex_ue, pciex_tx_ue) }, { TLU_UC_BIT_DESC(ROF, pciex_ue, pciex_tx_ue) }, @@ -234,6 +361,7 @@ px_err_bit_desc_t px_err_tlu_ue_tbl[] = { #define px_err_tlu_ue_keys \ (sizeof (px_err_tlu_ue_tbl)) / (sizeof (px_err_bit_desc_t)) + /* * PEC CE errors implementation is incomplete pending PCIE generic * fabric rules. @@ -261,6 +389,7 @@ px_err_bit_desc_t px_err_tlu_ce_tbl[] = { #define px_err_tlu_ce_keys \ (sizeof (px_err_tlu_ce_tbl)) / (sizeof (px_err_bit_desc_t)) + /* pec oe errors */ #define TLU_OE_BIT_DESC(bit, hdl, erpt) \ TLU_OTHER_EVENT_STATUS_CLEAR_ ## bit ## _P, \ @@ -273,6 +402,17 @@ px_err_bit_desc_t px_err_tlu_ce_tbl[] = { PX_ERR_BIT_HANDLE(hdl), \ PX_ERPT_SEND(erpt), \ PX_ERR_PEC_CLASS(bit) +#define TLU_OE_OB_BIT_DESC(bit, hdl, erpt) \ + TLU_OTHER_EVENT_STATUS_CLEAR_ ## bit ## _P, \ + 0, \ + PX_ERR_BIT_HANDLE(hdl), \ + PX_ERPT_SEND(erpt), \ + PX_ERR_PEC_OB_CLASS(bit) }, \ + { TLU_OTHER_EVENT_STATUS_CLEAR_ ## bit ## _S, \ + 0, \ + PX_ERR_BIT_HANDLE(hdl), \ + PX_ERPT_SEND(erpt), \ + PX_ERR_PEC_OB_CLASS(bit) px_err_bit_desc_t px_err_tlu_oe_tbl[] = { /* * TLU Other Event Status (receive only) - see io erpt doc, section 3.7 @@ -288,6 +428,7 @@ px_err_bit_desc_t px_err_tlu_oe_tbl[] = { { TLU_OE_BIT_DESC(IIP, fatal_gos, pciex_oe) }, { TLU_OE_BIT_DESC(EDP, fatal_gos, pciex_oe) }, { TLU_OE_BIT_DESC(EHP, fatal_gos, pciex_oe) }, + { TLU_OE_OB_BIT_DESC(TLUEITMO, fatal_gos, pciex_oe) }, { TLU_OE_BIT_DESC(LIN, non_fatal, pciex_oe) }, { TLU_OE_BIT_DESC(LRS, non_fatal, pciex_oe) }, { TLU_OE_BIT_DESC(LDN, tlu_ldn, pciex_oe) }, @@ -303,6 +444,7 @@ px_err_bit_desc_t px_err_tlu_oe_tbl[] = { #define px_err_tlu_oe_keys \ (sizeof (px_err_tlu_oe_tbl)) / (sizeof (px_err_bit_desc_t)) + /* * All the following tables below are for LPU Interrupts. These interrupts * are *NOT* error interrupts, but event status interrupts. @@ -415,6 +557,15 @@ px_err_bit_desc_t px_err_lpug_tbl[] = { px_err_ ## pre ## _keys, \ 0 +#define MnT6_ob(pre) \ + B_FALSE, \ + &px_ ## pre ## _intr_mask, \ + &px_ ## pre ## _log_mask, \ + &px_ ## pre ## _count_mask, \ + px_err_ ## pre ## _ob_tbl, \ + px_err_ ## pre ## _ob_keys, \ + 0 + /* LPU Registers Addresses */ #define LR4(pre) \ NULL, \ @@ -436,7 +587,7 @@ px_err_bit_desc_t px_err_lpug_tbl[] = { TLU_ ## pre ## _INTERRUPT_STATUS, \ TLU_ ## pre ## _STATUS_CLEAR -/* Registers Addresses for JBC, MMU, IMU and ILU */ +/* Registers Addresses for JBC, UBC, MMU, IMU and ILU */ #define R4(pre) \ pre ## _ERROR_LOG_ENABLE, \ pre ## _INTERRUPT_ENABLE, \ @@ -449,7 +600,8 @@ px_err_bit_desc_t px_err_lpug_tbl[] = { * It is located in px_err.h */ px_err_reg_desc_t px_err_reg_tbl[] = { - { MnT6(cb), R4(JBC), "JBC Error"}, + { MnT6(jbc), R4(JBC), "JBC Error"}, + { MnT6(ubc), R4(UBC), "UBC Error"}, { MnT6(mmu), R4(MMU), "MMU Error"}, { MnT6(imu), R4(IMU), "IMU Error"}, { MnT6(tlu_ue), TR4(UNCORRECTABLE_ERROR), "TLU UE"}, @@ -461,7 +613,7 @@ px_err_reg_desc_t px_err_reg_tbl[] = { { MnT6(lpur), LR4(RECEIVE_PHY), "LPU RX Phy Layer"}, { MnT6(lpux), LR4(TRANSMIT_PHY), "LPU TX Phy Layer"}, { MnT6(lpus), LR4(LTSSM), "LPU LTSSM"}, - { MnT6(lpug), LR4(GIGABLAZE_GLUE), "LPU GigaBlaze Glue"} + { MnT6(lpug), LR4(GIGABLAZE_GLUE), "LPU GigaBlaze Glue"}, }; #define PX_ERR_REG_KEYS (sizeof (px_err_reg_tbl)) / (sizeof (px_err_reg_tbl[0])) @@ -469,7 +621,7 @@ typedef struct px_err_ss { uint64_t err_status[PX_ERR_REG_KEYS]; } px_err_ss_t; -static void px_err_snapshot(px_t *px_p, px_err_ss_t *ss, boolean_t chkjbc); +static void px_err_snapshot(px_t *px_p, px_err_ss_t *ss, boolean_t chk_cb); static int px_err_erpt_and_clr(px_t *px_p, ddi_fm_error_t *derr, px_err_ss_t *ss); static int px_err_check_severity(px_t *px_p, ddi_fm_error_t *derr, @@ -477,11 +629,11 @@ static int px_err_check_severity(px_t *px_p, ddi_fm_error_t *derr, /* * px_err_cb_intr: - * Interrupt handler for the JBC block. + * Interrupt handler for the JBC/UBC block. * o lock * o create derr - * o px_err_handle(leaf1, with jbc) - * o px_err_handle(leaf2, without jbc) + * o px_err_handle(leaf1, with cb) + * o px_err_handle(leaf2, without cb) * o dispatch (leaf1) * o dispatch (leaf2) * o unlock @@ -541,7 +693,7 @@ px_err_cb_intr(caddr_t arg) * Interrupt handler for the DMC/PEC block. * o lock * o create derr - * o px_err_handle(leaf, with jbc) + * o px_err_handle(leaf, with cb) * o dispatch (leaf) * o unlock * o handle error: fatal? fm_panic() : return INTR_CLAIMED) @@ -600,7 +752,8 @@ px_err_reg_enable(px_t *px_p, px_err_id_t id) caddr_t csr_base; pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; - if (id == PX_ERR_JBC) + /* Get the correct CSR BASE */ + if (PX_ERR_XBC(id)) csr_base = (caddr_t)pxu_p->px_address[PX_REG_XBC]; else csr_base = (caddr_t)pxu_p->px_address[PX_REG_CSR]; @@ -642,7 +795,8 @@ px_err_reg_disable(px_t *px_p, px_err_id_t id) caddr_t csr_base; pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; - if (id == PX_ERR_JBC) + /* Get the correct CSR BASE */ + if (PX_ERR_XBC(id)) csr_base = (caddr_t)(uintptr_t)pxu_p->px_address[PX_REG_XBC]; else csr_base = (caddr_t)(uintptr_t)pxu_p->px_address[PX_REG_CSR]; @@ -651,6 +805,7 @@ px_err_reg_disable(px_t *px_p, px_err_id_t id) switch (id) { case PX_ERR_JBC: + case PX_ERR_UBC: case PX_ERR_MMU: case PX_ERR_IMU: case PX_ERR_TLU_UE: @@ -687,13 +842,13 @@ px_err_reg_disable(px_t *px_p, px_err_id_t id) * @param px_p leaf in which to check access * @param derr fm err data structure to be updated * @param caller PX_TRAP_CALL | PX_INTR_CALL - * @param chkjbc whether to handle jbc registers + * @param chk_cb whether to handle cb registers * @return err PX_OK | PX_NONFATAL | * PX_FATAL_GOS | PX_FATAL_HW | PX_STUCK_FATAL */ int px_err_handle(px_t *px_p, ddi_fm_error_t *derr, int caller, - boolean_t chkjbc) + boolean_t chk_cb) { px_err_ss_t ss; int err = PX_OK; @@ -701,7 +856,7 @@ px_err_handle(px_t *px_p, ddi_fm_error_t *derr, int caller, ASSERT(MUTEX_HELD(&px_p->px_fm_mutex)); /* snap shot the current fire registers */ - px_err_snapshot(px_p, &ss, chkjbc); + px_err_snapshot(px_p, &ss, chk_cb); /* check for safe access */ px_err_safeacc_check(px_p, derr); @@ -731,14 +886,14 @@ px_err_handle(px_t *px_p, ddi_fm_error_t *derr, int caller, /* * px_err_snapshot: * Take a current snap shot of all the fire error registers. This includes - * JBC, DMC, and PEC, unless chkjbc == false; + * JBC/UBC, DMC, and PEC, unless chk_cb == false; * * @param px_p leaf in which to take the snap shot. * @param ss pre-allocated memory to store the snap shot. - * @param chkjbc boolean on whether to store jbc register. + * @param chk_cb boolean on whether to store jbc/ubc register. */ static void -px_err_snapshot(px_t *px_p, px_err_ss_t *ss, boolean_t chkjbc) +px_err_snapshot(px_t *px_p, px_err_ss_t *ss, boolean_t chk_cb) { pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; caddr_t xbc_csr_base = (caddr_t)pxu_p->px_address[PX_REG_XBC]; @@ -746,21 +901,40 @@ px_err_snapshot(px_t *px_p, px_err_ss_t *ss, boolean_t chkjbc) px_err_reg_desc_t *reg_desc; int reg_id; - /* snapshot JBC interrupt status */ - reg_id = PX_ERR_JBC; - if (chkjbc == B_TRUE) { + switch (PX_CHIP_TYPE(pxu_p)) { + case PX_CHIP_OBERON: + reg_id = PX_ERR_UBC; + break; + case PX_CHIP_FIRE: + reg_id = PX_ERR_JBC; + break; + default: + DBG(DBG_ERR_INTR, NULL, "px_err_snapshot - " + "unknown chip type: 0x%x\n", PX_CHIP_TYPE(pxu_p)); + reg_id = 0; + break; + } + + /* snapshot CB interrupt status */ + if (chk_cb == B_TRUE) { reg_desc = &px_err_reg_tbl[reg_id]; - ss->err_status[reg_id] = CSR_XR(xbc_csr_base, - reg_desc->status_addr); + /* Only look at enabled groups. */ + if (reg_desc->enabled == B_TRUE) { + ss->err_status[reg_id] = CSR_XR(xbc_csr_base, + reg_desc->status_addr); + } } else { ss->err_status[reg_id] = 0; } /* snapshot DMC/PEC interrupt status */ - for (reg_id = 1; reg_id < PX_ERR_REG_KEYS; reg_id += 1) { + for (reg_id = 2; reg_id < PX_ERR_REG_KEYS; reg_id += 1) { reg_desc = &px_err_reg_tbl[reg_id]; - ss->err_status[reg_id] = CSR_XR(pec_csr_base, - reg_desc->status_addr); + /* Only look at enabled groups. */ + if (reg_desc->enabled == B_TRUE) { + ss->err_status[reg_id] = CSR_XR(pec_csr_base, + reg_desc->status_addr); + } } } @@ -803,12 +977,15 @@ px_err_erpt_and_clr(px_t *px_p, ddi_fm_error_t *derr, px_err_ss_t *ss) /* Get the correct register description table */ err_reg_tbl = &px_err_reg_tbl[reg_id]; + /* Only look at enabled groups. */ + if (err_reg_tbl->enabled != B_TRUE) + continue; + /* Get the correct CSR BASE */ - if (reg_id == PX_ERR_JBC) { + if (PX_ERR_XBC(reg_id)) csr_base = (caddr_t)pxu_p->px_address[PX_REG_XBC]; - } else { + else csr_base = (caddr_t)pxu_p->px_address[PX_REG_CSR]; - } /* Get pointers to masks and register addresses */ log_mask = err_reg_tbl->log_mask_p; @@ -859,9 +1036,7 @@ px_err_erpt_and_clr(px_t *px_p, ddi_fm_error_t *derr, px_err_ss_t *ss) err_bit_desc->class_name); } } - } - /* Print register status */ if (ss_reg & *log_mask) DBG(DBG_ERR_INTR, rpdip, "<%x>=%16llx %s\n", @@ -1002,6 +1177,105 @@ PX_ERPT_SEND_DEC(do_not) return (PX_OK); } +/* UBC FATAL - see io erpt doc, section 1.1 */ +/* ARGSUSED */ +PX_ERPT_SEND_DEC(ubc_fatal) +{ + char buf[FM_MAX_CLASS]; + uint64_t memory_ue_log, marked; + char unum[FM_MAX_CLASS]; + int unum_length; + uint64_t device_id = 0; + uint8_t cpu_version = 0; + nvlist_t *resource = NULL; + + unum[0] = '\0'; + (void) snprintf(buf, FM_MAX_CLASS, "%s", class_name); + + memory_ue_log = CSR_XR(csr_base, UBC_MEMORY_UE_LOG); + marked = (memory_ue_log >> UBC_MEMORY_UE_LOG_MARKED) & + UBC_MEMORY_UE_LOG_MARKED_MASK; + + if ((strstr(class_name, "ubc.piowtue") != NULL) || + (strstr(class_name, "ubc.piowbeue") != NULL) || + (strstr(class_name, "ubc.piorbeue") != NULL) || + (strstr(class_name, "ubc.dmarduea") != NULL) || + (strstr(class_name, "ubc.dmardueb") != NULL)) { + int eid = (memory_ue_log >> UBC_MEMORY_UE_LOG_EID) & + UBC_MEMORY_UE_LOG_EID_MASK; + (void) strncat(buf, ubc_class_eid_qualifier[eid], + FM_MAX_CLASS); + + if (eid == UBC_EID_MEM) { + uint64_t phys_addr = memory_ue_log & + MMU_OBERON_PADDR_MASK; + uint64_t offset = (uint64_t)-1; + + resource = fm_nvlist_create(NULL); + if (&plat_get_mem_unum) { + if ((plat_get_mem_unum(0, + phys_addr, 0, B_TRUE, 0, unum, + FM_MAX_CLASS, &unum_length)) != 0) + unum[0] = '\0'; + } + fm_fmri_mem_set(resource, FM_MEM_SCHEME_VERSION, + NULL, unum, NULL, offset); + + } else if (eid == UBC_EID_CPU) { + int cpuid = (marked & UBC_MARKED_MAX_CPUID_MASK); + char sbuf[21]; /* sizeof (UINT64_MAX) + '\0' */ + + resource = fm_nvlist_create(NULL); + cpu_version = cpunodes[cpuid].version; + device_id = cpunodes[cpuid].device_id; + (void) snprintf(sbuf, sizeof (sbuf), "%lX", + device_id); + (void) fm_fmri_cpu_set(resource, + FM_CPU_SCHEME_VERSION, NULL, cpuid, + &cpu_version, sbuf); + } + } + + if (resource) { + ddi_fm_ereport_post(rpdip, buf, derr->fme_ena, + DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, + FIRE_PRIMARY, DATA_TYPE_BOOLEAN_VALUE, B_TRUE, + OBERON_UBC_ELE, DATA_TYPE_UINT64, + CSR_XR(csr_base, UBC_ERROR_LOG_ENABLE), + OBERON_UBC_IE, DATA_TYPE_UINT64, + CSR_XR(csr_base, UBC_INTERRUPT_ENABLE), + OBERON_UBC_IS, DATA_TYPE_UINT64, + CSR_XR(csr_base, UBC_INTERRUPT_STATUS), + OBERON_UBC_ESS, DATA_TYPE_UINT64, + CSR_XR(csr_base, UBC_ERROR_STATUS_SET), + OBERON_UBC_MUE, DATA_TYPE_UINT64, memory_ue_log, + OBERON_UBC_UNUM, DATA_TYPE_STRING, unum, + OBERON_UBC_DID, DATA_TYPE_UINT64, device_id, + OBERON_UBC_CPUV, DATA_TYPE_UINT32, cpu_version, + OBERON_UBC_RESOURCE, DATA_TYPE_NVLIST, resource, + NULL); + fm_nvlist_destroy(resource, FM_NVA_FREE); + } else { + ddi_fm_ereport_post(rpdip, buf, derr->fme_ena, + DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, + FIRE_PRIMARY, DATA_TYPE_BOOLEAN_VALUE, B_TRUE, + OBERON_UBC_ELE, DATA_TYPE_UINT64, + CSR_XR(csr_base, UBC_ERROR_LOG_ENABLE), + OBERON_UBC_IE, DATA_TYPE_UINT64, + CSR_XR(csr_base, UBC_INTERRUPT_ENABLE), + OBERON_UBC_IS, DATA_TYPE_UINT64, + CSR_XR(csr_base, UBC_INTERRUPT_STATUS), + OBERON_UBC_ESS, DATA_TYPE_UINT64, + CSR_XR(csr_base, UBC_ERROR_STATUS_SET), + OBERON_UBC_MUE, DATA_TYPE_UINT64, memory_ue_log, + OBERON_UBC_UNUM, DATA_TYPE_STRING, unum, + OBERON_UBC_DID, DATA_TYPE_UINT64, device_id, + OBERON_UBC_CPUV, DATA_TYPE_UINT32, cpu_version, + NULL); + } + + return (PX_OK); +} /* JBC FATAL - see io erpt doc, section 1.1 */ PX_ERPT_SEND_DEC(jbc_fatal) @@ -1352,6 +1626,7 @@ px_err_imu_rbne_handle(dev_info_t *rpdip, caddr_t csr_base, * errors for a period of time within which the occuring of the * disabled errors become rbne, that is non fatal. */ + if (!(imu_log_enable & imu_intr_enable & mask)) err = PX_FATAL_SW; @@ -1456,6 +1731,7 @@ PX_ERPT_SEND_DEC(mmu_tfar_tfsr) boolean_t pri = PX_ERR_IS_PRI(bit); (void) snprintf(buf, FM_MAX_CLASS, "%s", class_name); + ddi_fm_ereport_post(rpdip, buf, derr->fme_ena, DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, FIRE_PRIMARY, DATA_TYPE_BOOLEAN_VALUE, pri, diff --git a/usr/src/uts/sun4u/io/px/px_err.h b/usr/src/uts/sun4u/io/px/px_err.h index d050649556..e6625a249b 100644 --- a/usr/src/uts/sun4u/io/px/px_err.h +++ b/usr/src/uts/sun4u/io/px/px_err.h @@ -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,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -35,6 +34,7 @@ extern "C" { typedef enum { PX_ERR_JBC, + PX_ERR_UBC, PX_ERR_MMU, PX_ERR_IMU, PX_ERR_TLU_UE, @@ -52,6 +52,36 @@ typedef enum { void px_err_reg_enable(px_t *px_p, px_err_id_t id); void px_err_reg_disable(px_t *px_p, px_err_id_t id); +#define PX_ERR_EN_ALL -1ull +#define PX_ERR_MASK_NONE 0ull + +#define LPU_INTR_ENABLE 0ull +#define LPU_INTR_DISABLE -1ull + +extern uint64_t px_tlu_ue_intr_mask; +extern uint64_t px_tlu_ue_log_mask; +extern uint64_t px_tlu_ue_count_mask; + +extern uint64_t px_tlu_ce_intr_mask; +extern uint64_t px_tlu_ce_log_mask; +extern uint64_t px_tlu_ce_count_mask; + +extern uint64_t px_tlu_oe_intr_mask; +extern uint64_t px_tlu_oe_log_mask; +extern uint64_t px_tlu_oe_count_mask; + +extern uint64_t px_mmu_intr_mask; +extern uint64_t px_mmu_log_mask; +extern uint64_t px_mmu_count_mask; + +extern uint64_t px_imu_intr_mask; +extern uint64_t px_imu_log_mask; +extern uint64_t px_imu_count_mask; + +extern uint64_t px_ilu_intr_mask; +extern uint64_t px_ilu_log_mask; +extern uint64_t px_ilu_count_mask; + #ifdef __cplusplus } #endif diff --git a/usr/src/uts/sun4u/io/px/px_err_impl.h b/usr/src/uts/sun4u/io/px/px_err_impl.h index 8dda2220ea..223bfd6e46 100644 --- a/usr/src/uts/sun4u/io/px/px_err_impl.h +++ b/usr/src/uts/sun4u/io/px/px_err_impl.h @@ -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,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -85,6 +84,11 @@ typedef struct px_err_reg_desc { } px_err_reg_desc_t; /* + * Macro to test for the JBC or UBC error id. + */ +#define PX_ERR_XBC(id) (((id) == PX_ERR_JBC)||((id) == PX_ERR_UBC)) + +/* * Macro to create the error handling forward declaration * * The error handlers examines error, determine the nature of the error @@ -141,10 +145,11 @@ PX_ERPT_SEND_DEC(do_not); /* - * JBC error handling and ereport forward declarations + * JBC/UBC error handling and ereport forward declarations */ #define PX_ERR_JBC_CLASS(n) PCIEX_FIRE "." FIRE_JBC_ ## n +#define PX_ERR_UBC_CLASS(n) PCIEX_OBERON "." FIRE_UBC_ ## n /* * Fire JBC error Handling Forward Declarations @@ -176,6 +181,9 @@ PX_ERPT_SEND_DEC(jbc_odcd); PX_ERPT_SEND_DEC(jbc_idc); PX_ERPT_SEND_DEC(jbc_csr); +/* Oberon UBC error ereport Forward Declarations */ +PX_ERPT_SEND_DEC(ubc_fatal); + /* * DMC error handling and ereport forward declarations @@ -218,6 +226,7 @@ PX_ERPT_SEND_DEC(mmu); */ #define PX_ERR_PEC_CLASS(n) PCIEX_FIRE "." FIRE_PEC_ ## n +#define PX_ERR_PEC_OB_CLASS(n) PCIEX_OBERON "." FIRE_PEC_ ## n int px_err_tlu_lup_handle(dev_info_t *rpdip, caddr_t csr_base, ddi_fm_error_t *derr, px_err_reg_desc_t *err_reg_descr, diff --git a/usr/src/uts/sun4u/io/px/px_hlib.c b/usr/src/uts/sun4u/io/px/px_hlib.c index 90368735d7..1cd79e686c 100644 --- a/usr/src/uts/sun4u/io/px/px_hlib.c +++ b/usr/src/uts/sun4u/io/px/px_hlib.c @@ -32,9 +32,11 @@ #include <sys/machsystm.h> /* lddphys() */ #include <sys/iommutsb.h> #include <sys/pci.h> +#include <sys/hotplug/pci/pciehpc.h> #include <pcie_pwr.h> #include <px_obj.h> #include "px_regs.h" +#include "oberon_regs.h" #include "px_csr.h" #include "px_lib4u.h" @@ -45,45 +47,57 @@ /* * Registers in the PEC Module. * LPU_RESET should be set to 0ull during resume + * + * This array is in reg,chip form. PX_CHIP_UNIDENTIFIED is for all chips + * or PX_CHIP_FIRE for Fire only, or PX_CHIP_OBERON for Oberon only. */ -static uint64_t pec_config_state_regs[] = { - PEC_CORE_AND_BLOCK_INTERRUPT_ENABLE, - ILU_ERROR_LOG_ENABLE, - ILU_INTERRUPT_ENABLE, - TLU_CONTROL, - TLU_OTHER_EVENT_LOG_ENABLE, - TLU_OTHER_EVENT_INTERRUPT_ENABLE, - TLU_DEVICE_CONTROL, - TLU_LINK_CONTROL, - TLU_UNCORRECTABLE_ERROR_LOG_ENABLE, - TLU_UNCORRECTABLE_ERROR_INTERRUPT_ENABLE, - TLU_CORRECTABLE_ERROR_LOG_ENABLE, - TLU_CORRECTABLE_ERROR_INTERRUPT_ENABLE, - LPU_LINK_LAYER_INTERRUPT_MASK, - LPU_PHY_INTERRUPT_MASK, - LPU_RECEIVE_PHY_INTERRUPT_MASK, - LPU_TRANSMIT_PHY_INTERRUPT_MASK, - LPU_GIGABLAZE_GLUE_INTERRUPT_MASK, - LPU_LTSSM_INTERRUPT_MASK, - LPU_RESET, - LPU_DEBUG_CONFIG, - LPU_INTERRUPT_MASK, - LPU_LINK_LAYER_CONFIG, - LPU_FLOW_CONTROL_UPDATE_CONTROL, - LPU_TXLINK_FREQUENT_NAK_LATENCY_TIMER_THRESHOLD, - LPU_TXLINK_REPLAY_TIMER_THRESHOLD, - LPU_REPLAY_BUFFER_MAX_ADDRESS, - LPU_TXLINK_RETRY_FIFO_POINTER, - LPU_LTSSM_CONFIG2, - LPU_LTSSM_CONFIG3, - LPU_LTSSM_CONFIG4, - LPU_LTSSM_CONFIG5, - DMC_CORE_AND_BLOCK_INTERRUPT_ENABLE, - DMC_DEBUG_SELECT_FOR_PORT_A, - DMC_DEBUG_SELECT_FOR_PORT_B +static struct px_pec_regs { + uint64_t reg; + uint64_t chip; +} pec_config_state_regs[] = { + {PEC_CORE_AND_BLOCK_INTERRUPT_ENABLE, PX_CHIP_UNIDENTIFIED}, + {ILU_ERROR_LOG_ENABLE, PX_CHIP_UNIDENTIFIED}, + {ILU_INTERRUPT_ENABLE, PX_CHIP_UNIDENTIFIED}, + {TLU_CONTROL, PX_CHIP_UNIDENTIFIED}, + {TLU_OTHER_EVENT_LOG_ENABLE, PX_CHIP_UNIDENTIFIED}, + {TLU_OTHER_EVENT_INTERRUPT_ENABLE, PX_CHIP_UNIDENTIFIED}, + {TLU_DEVICE_CONTROL, PX_CHIP_UNIDENTIFIED}, + {TLU_LINK_CONTROL, PX_CHIP_UNIDENTIFIED}, + {TLU_UNCORRECTABLE_ERROR_LOG_ENABLE, PX_CHIP_UNIDENTIFIED}, + {TLU_UNCORRECTABLE_ERROR_INTERRUPT_ENABLE, PX_CHIP_UNIDENTIFIED}, + {TLU_CORRECTABLE_ERROR_LOG_ENABLE, PX_CHIP_UNIDENTIFIED}, + {TLU_CORRECTABLE_ERROR_INTERRUPT_ENABLE, PX_CHIP_UNIDENTIFIED}, + {DLU_LINK_LAYER_CONFIG, PX_CHIP_OBERON}, + {DLU_FLOW_CONTROL_UPDATE_CONTROL, PX_CHIP_OBERON}, + {DLU_TXLINK_REPLAY_TIMER_THRESHOLD, PX_CHIP_OBERON}, + {LPU_LINK_LAYER_INTERRUPT_MASK, PX_CHIP_FIRE}, + {LPU_PHY_INTERRUPT_MASK, PX_CHIP_FIRE}, + {LPU_RECEIVE_PHY_INTERRUPT_MASK, PX_CHIP_FIRE}, + {LPU_TRANSMIT_PHY_INTERRUPT_MASK, PX_CHIP_FIRE}, + {LPU_GIGABLAZE_GLUE_INTERRUPT_MASK, PX_CHIP_FIRE}, + {LPU_LTSSM_INTERRUPT_MASK, PX_CHIP_FIRE}, + {LPU_RESET, PX_CHIP_FIRE}, + {LPU_DEBUG_CONFIG, PX_CHIP_FIRE}, + {LPU_INTERRUPT_MASK, PX_CHIP_FIRE}, + {LPU_LINK_LAYER_CONFIG, PX_CHIP_FIRE}, + {LPU_FLOW_CONTROL_UPDATE_CONTROL, PX_CHIP_FIRE}, + {LPU_TXLINK_FREQUENT_NAK_LATENCY_TIMER_THRESHOLD, PX_CHIP_FIRE}, + {LPU_TXLINK_REPLAY_TIMER_THRESHOLD, PX_CHIP_FIRE}, + {LPU_REPLAY_BUFFER_MAX_ADDRESS, PX_CHIP_FIRE}, + {LPU_TXLINK_RETRY_FIFO_POINTER, PX_CHIP_FIRE}, + {LPU_LTSSM_CONFIG2, PX_CHIP_FIRE}, + {LPU_LTSSM_CONFIG3, PX_CHIP_FIRE}, + {LPU_LTSSM_CONFIG4, PX_CHIP_FIRE}, + {LPU_LTSSM_CONFIG5, PX_CHIP_FIRE}, + {DMC_CORE_AND_BLOCK_INTERRUPT_ENABLE, PX_CHIP_UNIDENTIFIED}, + {DMC_DEBUG_SELECT_FOR_PORT_A, PX_CHIP_UNIDENTIFIED}, + {DMC_DEBUG_SELECT_FOR_PORT_B, PX_CHIP_UNIDENTIFIED} }; -#define PEC_SIZE (sizeof (pec_config_state_regs)) -#define PEC_KEYS (PEC_SIZE / sizeof (uint64_t)) + +#define PEC_KEYS \ + ((sizeof (pec_config_state_regs))/sizeof (struct px_pec_regs)) + +#define PEC_SIZE (PEC_KEYS * sizeof (uint64_t)) /* * Registers for the MMU module. @@ -110,18 +124,29 @@ static uint64_t ib_config_state_regs[] = { #define IB_MAP_SIZE (INTERRUPT_MAPPING_ENTRIES * sizeof (uint64_t)) /* - * Registers for the CB module. + * Registers for the JBC module. * JBC_ERROR_STATUS_CLEAR needs to be cleared. (-1ull) */ -static uint64_t cb_config_state_regs[] = { +static uint64_t jbc_config_state_regs[] = { JBUS_PARITY_CONTROL, JBC_FATAL_RESET_ENABLE, JBC_CORE_AND_BLOCK_INTERRUPT_ENABLE, JBC_ERROR_LOG_ENABLE, JBC_INTERRUPT_ENABLE }; -#define CB_SIZE (sizeof (cb_config_state_regs)) -#define CB_KEYS (CB_SIZE / sizeof (uint64_t)) +#define JBC_SIZE (sizeof (jbc_config_state_regs)) +#define JBC_KEYS (JBC_SIZE / sizeof (uint64_t)) + +/* + * Registers for the UBC module. + * UBC_ERROR_STATUS_CLEAR needs to be cleared. (-1ull) + */ +static uint64_t ubc_config_state_regs[] = { + UBC_ERROR_LOG_ENABLE, + UBC_INTERRUPT_ENABLE +}; +#define UBC_SIZE (sizeof (ubc_config_state_regs)) +#define UBC_KEYS (UBC_SIZE / sizeof (uint64_t)) static uint64_t msiq_config_other_regs[] = { ERR_COR_MAPPING, @@ -140,20 +165,43 @@ static uint64_t msiq_config_other_regs[] = { static uint64_t msiq_suspend(devhandle_t dev_hdl, pxu_t *pxu_p); static void msiq_resume(devhandle_t dev_hdl, pxu_t *pxu_p); +static void jbc_init(caddr_t xbc_csr_base, pxu_t *pxu_p); +static void ubc_init(caddr_t xbc_csr_base, pxu_t *pxu_p); /* - * Initialize the module, but do not enable interrupts. + * Initialize the bus, but do not enable interrupts. */ /* ARGSUSED */ void hvio_cb_init(caddr_t xbc_csr_base, pxu_t *pxu_p) { + switch (PX_CHIP_TYPE(pxu_p)) { + case PX_CHIP_OBERON: + ubc_init(xbc_csr_base, pxu_p); + break; + case PX_CHIP_FIRE: + jbc_init(xbc_csr_base, pxu_p); + break; + default: + DBG(DBG_CB, NULL, "hvio_cb_init - unknown chip type: 0x%x\n", + PX_CHIP_TYPE(pxu_p)); + break; + } +} + +/* + * Initialize the JBC module, but do not enable interrupts. + */ +/* ARGSUSED */ +static void +jbc_init(caddr_t xbc_csr_base, pxu_t *pxu_p) +{ uint64_t val; /* Check if we need to enable inverted parity */ val = (1ULL << JBUS_PARITY_CONTROL_P_EN); CSR_XS(xbc_csr_base, JBUS_PARITY_CONTROL, val); - DBG(DBG_CB, NULL, "hvio_cb_init, JBUS_PARITY_CONTROL: 0x%llx\n", + DBG(DBG_CB, NULL, "jbc_init, JBUS_PARITY_CONTROL: 0x%llx\n", CSR_XR(xbc_csr_base, JBUS_PARITY_CONTROL)); val = (1 << JBC_FATAL_RESET_ENABLE_SPARE_P_INT_EN) | @@ -165,7 +213,7 @@ hvio_cb_init(caddr_t xbc_csr_base, pxu_t *pxu_p) (1 << JBC_FATAL_RESET_ENABLE_JTCEEI_P_INT_EN) | (1 << JBC_FATAL_RESET_ENABLE_JTCEER_P_INT_EN); CSR_XS(xbc_csr_base, JBC_FATAL_RESET_ENABLE, val); - DBG(DBG_CB, NULL, "hvio_cb_init, JBC_FATAL_RESET_ENABLE: 0x%llx\n", + DBG(DBG_CB, NULL, "jbc_init, JBC_FATAL_RESET_ENABLE: 0x%llx\n", CSR_XR(xbc_csr_base, JBC_FATAL_RESET_ENABLE)); /* @@ -173,26 +221,63 @@ hvio_cb_init(caddr_t xbc_csr_base, pxu_t *pxu_p) */ CSR_XS(xbc_csr_base, JBC_CORE_AND_BLOCK_INTERRUPT_ENABLE, -1ull); DBG(DBG_CB, NULL, - "hvio_cb_init, JBC_CORE_AND_BLOCK_INTERRUPT_ENABLE: 0x%llx\n", + "jbc_init, JBC_CORE_AND_BLOCK_INTERRUPT_ENABLE: 0x%llx\n", CSR_XR(xbc_csr_base, JBC_CORE_AND_BLOCK_INTERRUPT_ENABLE)); /* - * CSR_V CB's interrupt regs (log, enable, status, clear) + * CSR_V JBC's interrupt regs (log, enable, status, clear) */ - DBG(DBG_CB, NULL, "hvio_cb_init, JBC_ERROR_LOG_ENABLE: 0x%llx\n", + DBG(DBG_CB, NULL, "jbc_init, JBC_ERROR_LOG_ENABLE: 0x%llx\n", CSR_XR(xbc_csr_base, JBC_ERROR_LOG_ENABLE)); - DBG(DBG_CB, NULL, "hvio_cb_init, JBC_INTERRUPT_ENABLE: 0x%llx\n", + DBG(DBG_CB, NULL, "jbc_init, JBC_INTERRUPT_ENABLE: 0x%llx\n", CSR_XR(xbc_csr_base, JBC_INTERRUPT_ENABLE)); - DBG(DBG_CB, NULL, "hvio_cb_init, JBC_INTERRUPT_STATUS: 0x%llx\n", + DBG(DBG_CB, NULL, "jbc_init, JBC_INTERRUPT_STATUS: 0x%llx\n", CSR_XR(xbc_csr_base, JBC_INTERRUPT_STATUS)); - DBG(DBG_CB, NULL, "hvio_cb_init, JBC_ERROR_STATUS_CLEAR: 0x%llx\n", + DBG(DBG_CB, NULL, "jbc_init, JBC_ERROR_STATUS_CLEAR: 0x%llx\n", CSR_XR(xbc_csr_base, JBC_ERROR_STATUS_CLEAR)); } /* + * Initialize the UBC module, but do not enable interrupts. + */ +/* ARGSUSED */ +static void +ubc_init(caddr_t xbc_csr_base, pxu_t *pxu_p) +{ + /* + * Enable Uranus bus error log bits. + */ + CSR_XS(xbc_csr_base, UBC_ERROR_LOG_ENABLE, -1ull); + DBG(DBG_CB, NULL, "ubc_init, UBC_ERROR_LOG_ENABLE: 0x%llx\n", + CSR_XR(xbc_csr_base, UBC_ERROR_LOG_ENABLE)); + + /* + * Clear Uranus bus errors. + */ + CSR_XS(xbc_csr_base, UBC_ERROR_STATUS_CLEAR, -1ull); + DBG(DBG_CB, NULL, "ubc_init, UBC_ERROR_STATUS_CLEAR: 0x%llx\n", + CSR_XR(xbc_csr_base, UBC_ERROR_STATUS_CLEAR)); + + /* + * CSR_V UBC's interrupt regs (log, enable, status, clear) + */ + DBG(DBG_CB, NULL, "ubc_init, UBC_ERROR_LOG_ENABLE: 0x%llx\n", + CSR_XR(xbc_csr_base, UBC_ERROR_LOG_ENABLE)); + + DBG(DBG_CB, NULL, "ubc_init, UBC_INTERRUPT_ENABLE: 0x%llx\n", + CSR_XR(xbc_csr_base, UBC_INTERRUPT_ENABLE)); + + DBG(DBG_CB, NULL, "ubc_init, UBC_INTERRUPT_STATUS: 0x%llx\n", + CSR_XR(xbc_csr_base, UBC_INTERRUPT_STATUS)); + + DBG(DBG_CB, NULL, "ubc_init, UBC_ERROR_STATUS_CLEAR: 0x%llx\n", + CSR_XR(xbc_csr_base, UBC_ERROR_STATUS_CLEAR)); +} + +/* * Initialize the module, but do not enable interrupts. */ /* ARGSUSED */ @@ -269,6 +354,20 @@ tlu_init(caddr_t csr_base, pxu_t *pxu_p) (1ull << TLU_CONTROL_NPWR_EN) | TLU_CONTROL_CONFIG_DEFAULT; /* + * For Oberon, NPWR_EN is set to 0 to prevent PIO reads from blocking + * behind non-posted PIO writes. This blocking could cause a master or + * slave timeout on the host bus if multiple serialized PIOs were to + * suffer Completion Timeouts because the CTO delays for each PIO ahead + * of the read would accumulate. Since the Olympus processor can have + * only 1 PIO outstanding, there is no possibility of PIO accesses from + * a given CPU to a given device being re-ordered by the PCIe fabric; + * therefore turning off serialization should be safe from a PCIe + * ordering perspective. + */ + if (PX_CHIP_TYPE(pxu_p) == PX_CHIP_OBERON) + val &= ~(1ull << TLU_CONTROL_NPWR_EN); + + /* * Set Detect.Quiet. This will disable automatic link * re-training, if the link goes down e.g. power management * turns off power to the downstream device. This will enable @@ -1433,6 +1532,37 @@ lpu_init(caddr_t csr_base, pxu_t *pxu_p) /* ARGSUSED */ static void +dlu_init(caddr_t csr_base, pxu_t *pxu_p) +{ +uint64_t val; + + CSR_XS(csr_base, DLU_INTERRUPT_MASK, 0ull); + DBG(DBG_TLU, NULL, "dlu_init - DLU_INTERRUPT_MASK: 0x%llx\n", + CSR_XR(csr_base, DLU_INTERRUPT_MASK)); + + val = (1ull << DLU_LINK_LAYER_CONFIG_VC0_EN); + CSR_XS(csr_base, DLU_LINK_LAYER_CONFIG, val); + DBG(DBG_TLU, NULL, "dlu_init - DLU_LINK_LAYER_CONFIG: 0x%llx\n", + CSR_XR(csr_base, DLU_LINK_LAYER_CONFIG)); + + val = (1ull << DLU_FLOW_CONTROL_UPDATE_CONTROL_FC0_U_NP_EN) | + (1ull << DLU_FLOW_CONTROL_UPDATE_CONTROL_FC0_U_P_EN); + + CSR_XS(csr_base, DLU_FLOW_CONTROL_UPDATE_CONTROL, val); + DBG(DBG_TLU, NULL, "dlu_init - DLU_FLOW_CONTROL_UPDATE_CONTROL: " + "0x%llx\n", CSR_XR(csr_base, DLU_FLOW_CONTROL_UPDATE_CONTROL)); + + val = (DLU_TXLINK_REPLAY_TIMER_THRESHOLD_DEFAULT << + DLU_TXLINK_REPLAY_TIMER_THRESHOLD_RPLAY_TMR_THR); + + CSR_XS(csr_base, DLU_TXLINK_REPLAY_TIMER_THRESHOLD, val); + + DBG(DBG_TLU, NULL, "dlu_init - DLU_TXLINK_REPLAY_TIMER_THRESHOLD: " + "0x%llx\n", CSR_XR(csr_base, DLU_TXLINK_REPLAY_TIMER_THRESHOLD)); +} + +/* ARGSUSED */ +static void dmc_init(caddr_t csr_base, pxu_t *pxu_p) { uint64_t val; @@ -1478,7 +1608,20 @@ hvio_pec_init(caddr_t csr_base, pxu_t *pxu_p) ilu_init(csr_base, pxu_p); tlu_init(csr_base, pxu_p); - lpu_init(csr_base, pxu_p); + + switch (PX_CHIP_TYPE(pxu_p)) { + case PX_CHIP_OBERON: + dlu_init(csr_base, pxu_p); + break; + case PX_CHIP_FIRE: + lpu_init(csr_base, pxu_p); + break; + default: + DBG(DBG_PEC, NULL, "hvio_pec_init - unknown chip type: 0x%x\n", + PX_CHIP_TYPE(pxu_p)); + break; + } + dmc_init(csr_base, pxu_p); /* @@ -1500,27 +1643,90 @@ hvio_pec_init(caddr_t csr_base, pxu_t *pxu_p) } /* + * Convert a TTE to physical address + */ +static r_addr_t +mmu_tte_to_pa(uint64_t tte, pxu_t *pxu_p) +{ + uint64_t pa_mask; + + switch (PX_CHIP_TYPE(pxu_p)) { + case PX_CHIP_OBERON: + pa_mask = MMU_OBERON_PADDR_MASK; + break; + case PX_CHIP_FIRE: + pa_mask = MMU_FIRE_PADDR_MASK; + break; + default: + DBG(DBG_MMU, NULL, "mmu_tte_to_pa - unknown chip type: 0x%x\n", + PX_CHIP_TYPE(pxu_p)); + pa_mask = 0; + break; + } + return ((tte & pa_mask) >> MMU_PAGE_SHIFT); +} + +/* + * Return MMU bypass noncache bit for chip + */ +static r_addr_t +mmu_bypass_noncache(pxu_t *pxu_p) +{ + r_addr_t bypass_noncache_bit; + + switch (PX_CHIP_TYPE(pxu_p)) { + case PX_CHIP_OBERON: + bypass_noncache_bit = MMU_OBERON_BYPASS_NONCACHE; + break; + case PX_CHIP_FIRE: + bypass_noncache_bit = MMU_FIRE_BYPASS_NONCACHE; + break; + default: + DBG(DBG_MMU, NULL, + "mmu_bypass_nocache - unknown chip type: 0x%x\n", + PX_CHIP_TYPE(pxu_p)); + bypass_noncache_bit = 0; + break; + } + return (bypass_noncache_bit); +} + +/* + * Calculate number of TSB entries for the chip. + */ +/* ARGSUSED */ +static uint_t +mmu_tsb_entries(caddr_t csr_base, pxu_t *pxu_p) +{ + uint64_t tsb_ctrl; + uint_t obp_tsb_entries, obp_tsb_size; + + tsb_ctrl = CSR_XR(csr_base, MMU_TSB_CONTROL); + + obp_tsb_size = tsb_ctrl & 0xF; + + obp_tsb_entries = MMU_TSBSIZE_TO_TSBENTRIES(obp_tsb_size); + + return (obp_tsb_entries); +} + +/* * Initialize the module, but do not enable interrupts. */ void hvio_mmu_init(caddr_t csr_base, pxu_t *pxu_p) { - uint64_t val, i, tsb_ctrl, obp_tsb_pa, *base_tte_addr; - uint_t obp_tsb_entries, obp_tsb_size; + uint64_t val, i, obp_tsb_pa, *base_tte_addr; + uint_t obp_tsb_entries; bzero(pxu_p->tsb_vaddr, pxu_p->tsb_size); /* * Preserve OBP's TSB */ - val = CSR_XR(csr_base, MMU_TSB_CONTROL); + obp_tsb_pa = CSR_XR(csr_base, MMU_TSB_CONTROL) & MMU_TSB_PA_MASK; - tsb_ctrl = CSR_XR(csr_base, MMU_TSB_CONTROL); - - obp_tsb_pa = tsb_ctrl & 0x7FFFFFFE000; - obp_tsb_size = tsb_ctrl & 0xF; - - obp_tsb_entries = MMU_TSBSIZE_TO_TSBENTRIES(obp_tsb_size); + obp_tsb_entries = mmu_tsb_entries(csr_base, pxu_p); base_tte_addr = pxu_p->tsb_vaddr + ((pxu_p->tsb_size >> 3) - obp_tsb_entries); @@ -1609,17 +1815,54 @@ hvio_iommu_map(devhandle_t dev_hdl, pxu_t *pxu_p, tsbid_t tsbid, pages_t pages, if (io_attr & PCI_MAP_ATTR_WRITE) attr |= MMU_TTE_W; + if ((PX_CHIP_TYPE(pxu_p) == PX_CHIP_OBERON) && + (io_attr & PCI_MAP_ATTR_RO)) + attr |= MMU_TTE_RO; + + if (attr & MMU_TTE_RO) { + DBG(DBG_MMU, NULL, "hvio_iommu_map: pfn_index=0x%x " + "pages=0x%x attr = 0x%lx\n", pfn_index, pages, attr); + } + if (flags & MMU_MAP_PFN) { ddi_dma_impl_t *mp = (ddi_dma_impl_t *)addr; for (i = 0; i < pages; i++, pfn_index++, tsb_index++) { px_iopfn_t pfn = PX_GET_MP_PFN(mp, pfn_index); pxu_p->tsb_vaddr[tsb_index] = MMU_PTOB(pfn) | attr; + + /* + * Oberon will need to flush the corresponding TTEs in + * Cache. We only need to flush every cache line. + * Extra PIO's are expensive. + */ + if (PX_CHIP_TYPE(pxu_p) == PX_CHIP_OBERON) { + if ((i == (pages-1))||!((tsb_index+1) & 0x7)) { + CSR_XS(dev_hdl, + MMU_TTE_CACHE_FLUSH_ADDRESS, + (pxu_p->tsb_paddr+ + (tsb_index*MMU_TTE_SIZE))); + } + } } } else { caddr_t a = (caddr_t)addr; for (i = 0; i < pages; i++, a += MMU_PAGE_SIZE, tsb_index++) { px_iopfn_t pfn = hat_getpfnum(kas.a_hat, a); pxu_p->tsb_vaddr[tsb_index] = MMU_PTOB(pfn) | attr; + + /* + * Oberon will need to flush the corresponding TTEs in + * Cache. We only need to flush every cache line. + * Extra PIO's are expensive. + */ + if (PX_CHIP_TYPE(pxu_p) == PX_CHIP_OBERON) { + if ((i == (pages-1))||!((tsb_index+1) & 0x7)) { + CSR_XS(dev_hdl, + MMU_TTE_CACHE_FLUSH_ADDRESS, + (pxu_p->tsb_paddr+ + (tsb_index*MMU_TTE_SIZE))); + } + } } } @@ -1634,9 +1877,24 @@ hvio_iommu_demap(devhandle_t dev_hdl, pxu_t *pxu_p, tsbid_t tsbid, tsbindex_t tsb_index = PCI_TSBID_TO_TSBINDEX(tsbid); int i; - for (i = 0; i < pages; i++, tsb_index++) + for (i = 0; i < pages; i++, tsb_index++) { pxu_p->tsb_vaddr[tsb_index] = MMU_INVALID_TTE; + /* + * Oberon will need to flush the corresponding TTEs in + * Cache. We only need to flush every cache line. + * Extra PIO's are expensive. + */ + if (PX_CHIP_TYPE(pxu_p) == PX_CHIP_OBERON) { + if ((i == (pages-1))||!((tsb_index+1) & 0x7)) { + CSR_XS(dev_hdl, + MMU_TTE_CACHE_FLUSH_ADDRESS, + (pxu_p->tsb_paddr+ + (tsb_index*MMU_TTE_SIZE))); + } + } + } + return (H_EOK); } @@ -1652,7 +1910,7 @@ hvio_iommu_getmap(devhandle_t dev_hdl, pxu_t *pxu_p, tsbid_t tsbid, tte_addr = (uint64_t *)(pxu_p->tsb_vaddr) + tsb_index; if (*tte_addr & MMU_TTE_V) { - *r_addr_p = MMU_TTETOPA(*tte_addr); + *r_addr_p = mmu_tte_to_pa(*tte_addr, pxu_p); *attr_p = (*tte_addr & MMU_TTE_W) ? PCI_MAP_ATTR_WRITE:PCI_MAP_ATTR_READ; } else { @@ -1666,13 +1924,59 @@ hvio_iommu_getmap(devhandle_t dev_hdl, pxu_t *pxu_p, tsbid_t tsbid, /* ARGSUSED */ uint64_t -hvio_iommu_getbypass(devhandle_t dev_hdl, r_addr_t ra, io_attributes_t attr, - io_addr_t *io_addr_p) +hvio_get_bypass_base(pxu_t *pxu_p) +{ + uint64_t base; + + switch (PX_CHIP_TYPE(pxu_p)) { + case PX_CHIP_OBERON: + base = MMU_OBERON_BYPASS_BASE; + break; + case PX_CHIP_FIRE: + base = MMU_FIRE_BYPASS_BASE; + break; + default: + DBG(DBG_MMU, NULL, + "hvio_get_bypass_base - unknown chip type: 0x%x\n", + PX_CHIP_TYPE(pxu_p)); + base = 0; + break; + } + return (base); +} + +/* ARGSUSED */ +uint64_t +hvio_get_bypass_end(pxu_t *pxu_p) +{ + uint64_t end; + + switch (PX_CHIP_TYPE(pxu_p)) { + case PX_CHIP_OBERON: + end = MMU_OBERON_BYPASS_END; + break; + case PX_CHIP_FIRE: + end = MMU_FIRE_BYPASS_END; + break; + default: + DBG(DBG_MMU, NULL, + "hvio_get_bypass_end - unknown chip type: 0x%x\n", + PX_CHIP_TYPE(pxu_p)); + end = 0; + break; + } + return (end); +} + +/* ARGSUSED */ +uint64_t +hvio_iommu_getbypass(devhandle_t dev_hdl, pxu_t *pxu_p, r_addr_t ra, + io_attributes_t attr, io_addr_t *io_addr_p) { uint64_t pfn = MMU_BTOP(ra); - *io_addr_p = MMU_BYPASS_BASE | ra | - (pf_is_memory(pfn) ? 0 : MMU_BYPASS_NONCACHE); + *io_addr_p = hvio_get_bypass_base(pxu_p) | ra | + (pf_is_memory(pfn) ? 0 : mmu_bypass_noncache(pxu_p)); return (H_EOK); } @@ -1812,10 +2116,23 @@ hvio_intr_setstate(devhandle_t dev_hdl, sysino_t sysino, * has not been set via intr_settarget. */ uint64_t -hvio_intr_gettarget(devhandle_t dev_hdl, sysino_t sysino, cpuid_t *cpuid) +hvio_intr_gettarget(devhandle_t dev_hdl, pxu_t *pxu_p, sysino_t sysino, + cpuid_t *cpuid) { - *cpuid = CSRA_FR((caddr_t)dev_hdl, INTERRUPT_MAPPING, - SYSINO_TO_DEVINO(sysino), ENTRIES_T_JPID); + switch (PX_CHIP_TYPE(pxu_p)) { + case PX_CHIP_OBERON: + *cpuid = CSRA_FR((caddr_t)dev_hdl, INTERRUPT_MAPPING, + SYSINO_TO_DEVINO(sysino), ENTRIES_T_DESTID); + break; + case PX_CHIP_FIRE: + *cpuid = CSRA_FR((caddr_t)dev_hdl, INTERRUPT_MAPPING, + SYSINO_TO_DEVINO(sysino), ENTRIES_T_JPID); + break; + default: + DBG(DBG_CB, NULL, "hvio_intr_gettarget - " + "unknown chip type: 0x%x\n", PX_CHIP_TYPE(pxu_p)); + return (EINVAL); + } return (H_EOK); } @@ -1825,7 +2142,8 @@ hvio_intr_gettarget(devhandle_t dev_hdl, sysino_t sysino, cpuid_t *cpuid) * sysino to the target cpu value defined by the argument cpuid. */ uint64_t -hvio_intr_settarget(devhandle_t dev_hdl, sysino_t sysino, cpuid_t cpuid) +hvio_intr_settarget(devhandle_t dev_hdl, pxu_t *pxu_p, sysino_t sysino, + cpuid_t cpuid) { uint64_t val, intr_controller; @@ -1838,10 +2156,27 @@ hvio_intr_settarget(devhandle_t dev_hdl, sysino_t sysino, cpuid_t cpuid) */ intr_controller = 0x1ull << (cpuid % 4); - val = (((cpuid & INTERRUPT_MAPPING_ENTRIES_T_JPID_MASK) << - INTERRUPT_MAPPING_ENTRIES_T_JPID) | - ((intr_controller & INTERRUPT_MAPPING_ENTRIES_INT_CNTRL_NUM_MASK) - << INTERRUPT_MAPPING_ENTRIES_INT_CNTRL_NUM)); + switch (PX_CHIP_TYPE(pxu_p)) { + case PX_CHIP_OBERON: + val = (((cpuid & + INTERRUPT_MAPPING_ENTRIES_T_DESTID_MASK) << + INTERRUPT_MAPPING_ENTRIES_T_DESTID) | + ((intr_controller & + INTERRUPT_MAPPING_ENTRIES_INT_CNTRL_NUM_MASK) + << INTERRUPT_MAPPING_ENTRIES_INT_CNTRL_NUM)); + break; + case PX_CHIP_FIRE: + val = (((cpuid & INTERRUPT_MAPPING_ENTRIES_T_JPID_MASK) << + INTERRUPT_MAPPING_ENTRIES_T_JPID) | + ((intr_controller & + INTERRUPT_MAPPING_ENTRIES_INT_CNTRL_NUM_MASK) + << INTERRUPT_MAPPING_ENTRIES_INT_CNTRL_NUM)); + break; + default: + DBG(DBG_CB, NULL, "hvio_intr_settarget - " + "unknown chip type: 0x%x\n", PX_CHIP_TYPE(pxu_p)); + return (EINVAL); + } /* For EQ interrupts, set DATA MONDO bit */ if ((ino >= PX_DEFAULT_MSIQ_1ST_DEVINO) && @@ -2309,8 +2644,12 @@ hvio_suspend(devhandle_t dev_hdl, pxu_t *pxu_p) /* Save the PEC configuration states */ pxu_p->pec_config_state = config_state; for (i = 0; i < PEC_KEYS; i++) { - pxu_p->pec_config_state[i] = - CSR_XR((caddr_t)dev_hdl, pec_config_state_regs[i]); + if ((pec_config_state_regs[i].chip == PX_CHIP_TYPE(pxu_p)) || + (pec_config_state_regs[i].chip == PX_CHIP_UNIDENTIFIED)) { + pxu_p->pec_config_state[i] = + CSR_XR((caddr_t)dev_hdl, + pec_config_state_regs[i].reg); + } } /* Save the MMU configuration states */ @@ -2380,8 +2719,11 @@ hvio_resume(devhandle_t dev_hdl, devino_t devino, pxu_t *pxu_p) CSR_XS((caddr_t)dev_hdl, LPU_RESET, 0ull); for (i = 0; i < PEC_KEYS; i++) { - CSR_XS((caddr_t)dev_hdl, pec_config_state_regs[i], - pxu_p->pec_config_state[i]); + if ((pec_config_state_regs[i].chip == PX_CHIP_TYPE(pxu_p)) || + (pec_config_state_regs[i].chip == PX_CHIP_UNIDENTIFIED)) { + CSR_XS((caddr_t)dev_hdl, pec_config_state_regs[i].reg, + pxu_p->pec_config_state[i]); + } } /* Enable PCI-E interrupt */ @@ -2403,10 +2745,27 @@ hvio_resume(devhandle_t dev_hdl, devino_t devino, pxu_t *pxu_p) uint64_t hvio_cb_suspend(devhandle_t dev_hdl, pxu_t *pxu_p) { - uint64_t *config_state; - int i; + uint64_t *config_state, *cb_regs; + int i, cb_size, cb_keys; + + switch (PX_CHIP_TYPE(pxu_p)) { + case PX_CHIP_OBERON: + cb_size = UBC_SIZE; + cb_keys = UBC_KEYS; + cb_regs = ubc_config_state_regs; + break; + case PX_CHIP_FIRE: + cb_size = JBC_SIZE; + cb_keys = JBC_KEYS; + cb_regs = jbc_config_state_regs; + break; + default: + DBG(DBG_CB, NULL, "hvio_cb_suspend - unknown chip type: 0x%x\n", + PX_CHIP_TYPE(pxu_p)); + break; + } - config_state = kmem_zalloc(CB_SIZE, KM_NOSLEEP); + config_state = kmem_zalloc(cb_size, KM_NOSLEEP); if (config_state == NULL) { return (H_EIO); @@ -2414,9 +2773,9 @@ hvio_cb_suspend(devhandle_t dev_hdl, pxu_t *pxu_p) /* Save the configuration states */ pxu_p->xcb_config_state = config_state; - for (i = 0; i < CB_KEYS; i++) { + for (i = 0; i < cb_keys; i++) { pxu_p->xcb_config_state[i] = - CSR_XR((caddr_t)dev_hdl, cb_config_state_regs[i]); + CSR_XR((caddr_t)dev_hdl, cb_regs[i]); } return (H_EOK); @@ -2426,20 +2785,42 @@ void hvio_cb_resume(devhandle_t pci_dev_hdl, devhandle_t xbus_dev_hdl, devino_t devino, pxu_t *pxu_p) { - sysino_t sysino; - int i; - - /* - * No reason to have any reset bits high until an error is - * detected on the link. - */ - CSR_XS((caddr_t)xbus_dev_hdl, JBC_ERROR_STATUS_CLEAR, -1ull); + sysino_t sysino; + uint64_t *cb_regs; + int i, cb_size, cb_keys; + + switch (PX_CHIP_TYPE(pxu_p)) { + case PX_CHIP_OBERON: + cb_size = UBC_SIZE; + cb_keys = UBC_KEYS; + cb_regs = ubc_config_state_regs; + /* + * No reason to have any reset bits high until an error is + * detected on the link. + */ + CSR_XS((caddr_t)xbus_dev_hdl, UBC_ERROR_STATUS_CLEAR, -1ull); + break; + case PX_CHIP_FIRE: + cb_size = JBC_SIZE; + cb_keys = JBC_KEYS; + cb_regs = jbc_config_state_regs; + /* + * No reason to have any reset bits high until an error is + * detected on the link. + */ + CSR_XS((caddr_t)xbus_dev_hdl, JBC_ERROR_STATUS_CLEAR, -1ull); + break; + default: + DBG(DBG_CB, NULL, "hvio_cb_resume - unknown chip type: 0x%x\n", + PX_CHIP_TYPE(pxu_p)); + break; + } ASSERT(pxu_p->xcb_config_state); /* Restore the configuration states */ - for (i = 0; i < CB_KEYS; i++) { - CSR_XS((caddr_t)xbus_dev_hdl, cb_config_state_regs[i], + for (i = 0; i < cb_keys; i++) { + CSR_XS((caddr_t)xbus_dev_hdl, cb_regs[i], pxu_p->xcb_config_state[i]); } @@ -2448,7 +2829,7 @@ hvio_cb_resume(devhandle_t pci_dev_hdl, devhandle_t xbus_dev_hdl, (void) hvio_intr_setstate(pci_dev_hdl, sysino, INTR_IDLE_STATE); - kmem_free(pxu_p->xcb_config_state, CB_SIZE); + kmem_free(pxu_p->xcb_config_state, cb_size); pxu_p->xcb_config_state = NULL; } @@ -2603,3 +2984,334 @@ px_enable_detect_quiet(caddr_t csr_base) tlu_ctrl |= (1ull << TLU_REMAIN_DETECT_QUIET); CSR_XS(csr_base, TLU_CONTROL, tlu_ctrl); } + +static uint_t +oberon_hp_pwron(caddr_t csr_base) +{ + volatile uint64_t reg; + +#ifdef DEBUG + cmn_err(CE_CONT, "oberon_hp_pwron the slot\n"); +#endif + + /* Check Leaf Reset status */ + reg = CSR_XR(csr_base, ILU_ERROR_LOG_ENABLE); + if (!(reg & (1ull << ILU_ERROR_LOG_ENABLE_SPARE3))) { +#ifdef DEBUG + cmn_err(CE_WARN, "oberon_hp_pwron fails: leaf not reset\n"); +#endif + goto fail; + } + + /* Check Slot status */ + reg = CSR_XR(csr_base, TLU_SLOT_STATUS); + if (!(reg & (1ull << TLU_SLOT_STATUS_PSD)) || + (reg & (1ull << TLU_SLOT_STATUS_MRLS)) || + (reg & (1ull << TLU_SLOT_STATUS_PWFD))) { +#ifdef DEBUG + cmn_err(CE_WARN, "oberon_hp_pwron fails: slot status %lx\n", + reg); +#endif + goto fail; + } + + /* Blink power LED, this is done from pciehpc already */ + + /* Turn on slot power */ + CSR_BS(csr_base, HOTPLUG_CONTROL, PWREN); + + /* wait to check power state */ + delay(drv_usectohz(25000)); + + return (DDI_SUCCESS); + +fail: + return (DDI_FAILURE); +} + +static uint_t +oberon_hp_pwroff(caddr_t csr_base) +{ + volatile uint64_t reg; + +#ifdef DEBUG + cmn_err(CE_CONT, "oberon_hp_pwroff the slot\n"); +#endif + + /* Blink power LED, this is done from pciehpc already */ + + /* Clear Slot Event */ + CSR_BS(csr_base, TLU_SLOT_STATUS, PSDC); + + /* DRN_TR_DIS on */ + CSR_BS(csr_base, TLU_CONTROL, DRN_TR_DIS); + + /* Disable port */ + CSR_BS(csr_base, FLP_PORT_CONTROL, PORT_DIS); + + /* check time or link status */ + delay(drv_usectohz(10000)); + + /* DRN_TR_DIS off/ CK_EN off */ + reg = CSR_XR(csr_base, TLU_OTHER_EVENT_STATUS_CLEAR); + if ((reg & (1ull << TLU_OTHER_EVENT_STATUS_CLEAR_LDN_P)) || + (reg & (1ull << TLU_OTHER_EVENT_STATUS_CLEAR_LDN_S))) { + CSR_BC(csr_base, TLU_CONTROL, DRN_TR_DIS); + } + CSR_BC(csr_base, DLU_PORT_CONTROL, CK_EN); + + /* PCIE reset */ + CSR_BC(csr_base, HOTPLUG_CONTROL, N_PERST); + + /* PCIE clock stop */ + CSR_BC(csr_base, HOTPLUG_CONTROL, CLKEN); + + /* Turn off slot power */ + CSR_BC(csr_base, TLU_SLOT_CONTROL, PWFDEN); + CSR_BC(csr_base, HOTPLUG_CONTROL, PWREN); + CSR_BC(csr_base, TLU_SLOT_STATUS, PWFD); + + /* write 0 to bit 7 of ILU Error Log Enable Register */ + CSR_BS(csr_base, ILU_ERROR_LOG_ENABLE, SPARE3); + + /* Power LED off */ + reg = CSR_XR(csr_base, TLU_SLOT_CONTROL); + reg &= ~PCIE_SLOTCTL_PWR_INDICATOR_MASK; + reg = pcie_slotctl_pwr_indicator_set(reg, + PCIE_SLOTCTL_INDICATOR_STATE_OFF); + CSR_XS(csr_base, TLU_SLOT_CONTROL, reg); + + /* Indicator LED blink */ + reg = CSR_XR(csr_base, TLU_SLOT_CONTROL); + reg &= ~PCIE_SLOTCTL_ATTN_INDICATOR_MASK; + reg = pcie_slotctl_attn_indicator_set(reg, + PCIE_SLOTCTL_INDICATOR_STATE_BLINK); + CSR_XS(csr_base, TLU_SLOT_CONTROL, reg); + + /* Notify to SCF */ + CSR_BC(csr_base, HOTPLUG_CONTROL, SLOTPON); + + /* + * Check Leaf Reset + * XXX - We don't need to wait for this any more. + */ + + /* Indicator LED off */ + reg = CSR_XR(csr_base, TLU_SLOT_CONTROL); + reg &= ~PCIE_SLOTCTL_ATTN_INDICATOR_MASK; + reg = pcie_slotctl_attn_indicator_set(reg, + PCIE_SLOTCTL_INDICATOR_STATE_OFF); + CSR_XS(csr_base, TLU_SLOT_CONTROL, reg); + + return (DDI_SUCCESS); +} + +static uint_t oberon_hp_pwrledon(caddr_t csr_base) +{ + volatile uint64_t reg; + +#ifdef DEBUG + cmn_err(CE_CONT, "oberon_hp_pwrledon the slot\n"); +#endif + + CSR_BS(csr_base, TLU_SLOT_CONTROL, PWFDEN); + + /* Turn on slot clock */ + CSR_BS(csr_base, HOTPLUG_CONTROL, CLKEN); + + /* Release PCI-E Reset */ + delay(drv_usectohz(100000)); + CSR_BS(csr_base, HOTPLUG_CONTROL, N_PERST); + + /* + * Open events' mask + * This should be done from pciehpc already + */ + + /* + * Initialize Leaf + * SPLS = 00b, SPLV = 11001b, i.e. 25W + */ + reg = CSR_XR(csr_base, TLU_SLOT_CAPABILITIES); + reg &= ~(TLU_SLOT_CAPABILITIES_SPLS_MASK << + TLU_SLOT_CAPABILITIES_SPLS); + reg &= ~(TLU_SLOT_CAPABILITIES_SPLV_MASK << + TLU_SLOT_CAPABILITIES_SPLS); + reg |= (0x19 << TLU_SLOT_CAPABILITIES_SPLS); + CSR_XS(csr_base, TLU_SLOT_CAPABILITIES, reg); + + /* Enable PCIE port */ + CSR_BS(csr_base, DLU_PORT_CONTROL, CK_EN); + CSR_BC(csr_base, FLP_PORT_CONTROL, PORT_DIS); + + /* wait for the LUP_P/LUP_S */ + delay(drv_usectohz(10000)); + reg = CSR_XR(csr_base, TLU_OTHER_EVENT_STATUS_CLEAR); + if (!(reg & (1ull << TLU_OTHER_EVENT_STATUS_CLEAR_LUP_P)) && + !(reg & (1ull << TLU_OTHER_EVENT_STATUS_CLEAR_LUP_S))) + goto fail; + + /* Turn on Power LED */ + reg = CSR_XR(csr_base, TLU_SLOT_CONTROL); + reg &= ~PCIE_SLOTCTL_PWR_INDICATOR_MASK; + reg = pcie_slotctl_pwr_indicator_set(reg, + PCIE_SLOTCTL_INDICATOR_STATE_ON); + CSR_XS(csr_base, TLU_SLOT_CONTROL, reg); + + /* Notify to SCF */ + CSR_BS(csr_base, HOTPLUG_CONTROL, SLOTPON); + return (DDI_SUCCESS); + +fail: + /* Link up is failed */ + CSR_BS(csr_base, FLP_PORT_CONTROL, PORT_DIS); + CSR_BC(csr_base, DLU_PORT_CONTROL, CK_EN); + CSR_BC(csr_base, HOTPLUG_CONTROL, N_PERST); + delay(drv_usectohz(150)); + + CSR_BC(csr_base, HOTPLUG_CONTROL, CLKEN); + delay(drv_usectohz(100)); + + CSR_BC(csr_base, HOTPLUG_CONTROL, PWREN); + + reg = CSR_XR(csr_base, TLU_SLOT_CONTROL); + reg &= ~PCIE_SLOTCTL_PWR_INDICATOR_MASK; + reg = pcie_slotctl_pwr_indicator_set(reg, + PCIE_SLOTCTL_INDICATOR_STATE_OFF); + CSR_XS(csr_base, TLU_SLOT_CONTROL, reg); + + CSR_BC(csr_base, TLU_SLOT_CONTROL, PWFDEN); + + return (DDI_FAILURE); +} + +static uint_t +oberon_hpreg_get(void *cookie, off_t off) +{ + caddr_t csr_base = *(caddr_t *)cookie; + volatile uint64_t val = -1ull; + + switch (off) { + case PCIE_SLOTCAP: + val = CSR_XR(csr_base, TLU_SLOT_CAPABILITIES); + break; + case PCIE_SLOTCTL: + val = CSR_XR(csr_base, TLU_SLOT_CONTROL); + + /* Get the power state */ + val |= (CSR_XR(csr_base, HOTPLUG_CONTROL) & + (1ull << HOTPLUG_CONTROL_PWREN)) ? + 0 : PCIE_SLOTCTL_PWR_CONTROL; + break; + case PCIE_SLOTSTS: + val = CSR_XR(csr_base, TLU_SLOT_STATUS); + break; + default: +#ifdef DEBUG + cmn_err(CE_WARN, "oberon_hpreg_get(): " + "unsupported offset 0x%lx\n", off); +#endif + break; + } + + return ((uint_t)val); +} + +static uint_t +oberon_hpreg_put(void *cookie, off_t off, uint_t val) +{ + caddr_t csr_base = *(caddr_t *)cookie; + volatile uint64_t pwr_state_on, pwr_fault, reg; + uint16_t pwr_led_state, pwr_led_ctrl; + uint_t pwr_off, ret = DDI_SUCCESS; + +#ifdef DEBUG + cmn_err(CE_CONT, "oberon_hpreg_put 0x%lx: cur %x, new %x\n", + off, oberon_hpreg_get(cookie, off), val); +#endif + + switch (off) { + case PCIE_SLOTCTL: + /* + * Depending on the current state, insertion or removal + * will go through their respective sequences. + */ + reg = CSR_XR(csr_base, TLU_SLOT_CONTROL); + pwr_led_state = pcie_slotctl_pwr_indicator_get(reg); + pwr_led_ctrl = pcie_slotctl_pwr_indicator_get(val); + + pwr_state_on = CSR_BR(csr_base, HOTPLUG_CONTROL, PWREN); + pwr_off = val & PCIE_SLOTCTL_PWR_CONTROL; + + if (!pwr_off && !pwr_state_on) + ret = oberon_hp_pwron(csr_base); + else if (pwr_off && pwr_state_on) { + pwr_fault = CSR_XR(csr_base, TLU_SLOT_STATUS) & + (1ull << TLU_SLOT_STATUS_PWFD); + + if (pwr_fault) + CSR_BC(csr_base, HOTPLUG_CONTROL, PWREN); + else + ret = oberon_hp_pwroff(csr_base); + } else if (pwr_state_on && + (pwr_led_state == PCIE_SLOTCTL_INDICATOR_STATE_BLINK) && + (pwr_led_ctrl == PCIE_SLOTCTL_INDICATOR_STATE_ON)) + ret = oberon_hp_pwrledon(csr_base); + else + CSR_XS(csr_base, TLU_SLOT_CONTROL, val); + break; + case PCIE_SLOTSTS: + CSR_XS(csr_base, TLU_SLOT_STATUS, val); + break; + default: +#ifdef DEBUG + cmn_err(CE_WARN, "oberon_hpreg_put(): " + "unsupported offset 0x%lx\n", off); +#endif + ret = DDI_FAILURE; + break; + } + + return (ret); +} + +int +hvio_hotplug_init(dev_info_t *dip, void *arg) +{ + pciehpc_regops_t *regops = (pciehpc_regops_t *)arg; + px_t *px_p = DIP_TO_STATE(dip); + pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; + + if (PX_CHIP_TYPE(pxu_p) == PX_CHIP_OBERON) { + if (!CSR_BR((caddr_t)pxu_p->px_address[PX_REG_CSR], + TLU_SLOT_CAPABILITIES, HP)) { +#ifdef DEBUG + cmn_err(CE_WARN, "%s%d: hotplug capabale not set\n", + ddi_driver_name(dip), ddi_get_instance(dip)); +#endif + return (DDI_FAILURE); + } + + regops->get = oberon_hpreg_get; + regops->put = oberon_hpreg_put; + + /* cookie is the csr_base */ + regops->cookie = (void *)&pxu_p->px_address[PX_REG_CSR]; + + return (DDI_SUCCESS); + } + + return (DDI_ENOTSUP); +} + +int +hvio_hotplug_uninit(dev_info_t *dip) +{ + px_t *px_p = DIP_TO_STATE(dip); + pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; + + if (PX_CHIP_TYPE(pxu_p) == PX_CHIP_OBERON) + return (DDI_SUCCESS); + + return (DDI_FAILURE); +} diff --git a/usr/src/uts/sun4u/io/px/px_lib4u.c b/usr/src/uts/sun4u/io/px/px_lib4u.c index 02ba672adc..91d06068f6 100644 --- a/usr/src/uts/sun4u/io/px/px_lib4u.c +++ b/usr/src/uts/sun4u/io/px/px_lib4u.c @@ -44,11 +44,13 @@ #include <sys/hotplug/pci/pciehpc.h> #include <px_obj.h> #include <pcie_pwr.h> +#include "px_tools_var.h" #include <px_regs.h> #include <px_csr.h> #include <sys/machsystm.h> #include "px_lib4u.h" #include "px_err.h" +#include "oberon_regs.h" #pragma weak jbus_stst_order @@ -56,6 +58,7 @@ extern void jbus_stst_order(); ulong_t px_mmu_dvma_end = 0xfffffffful; uint_t px_ranges_phi_mask = 0xfffffffful; +uint64_t *px_oberon_ubc_scratch_regs; static int px_goto_l23ready(px_t *px_p); static int px_goto_l0(px_t *px_p); @@ -168,8 +171,11 @@ px_lib_dev_init(dev_info_t *dip, devhandle_t *dev_hdl) case FIRE_VER_20: DBG(DBG_ATTACH, dip, "FIRE Hardware Version 2.0\n"); break; + case OBERON_VER_10: + DBG(DBG_ATTACH, dip, "Oberon Hardware Version 1.0\n"); + break; default: - cmn_err(CE_WARN, "%s%d: FIRE Hardware Version Unknown\n", + cmn_err(CE_WARN, "%s%d: PX Hardware Version Unknown\n", ddi_driver_name(dip), ddi_get_instance(dip)); return (DDI_FAILURE); } @@ -197,6 +203,8 @@ px_lib_dev_init(dev_info_t *dip, devhandle_t *dev_hdl) pxu_p->tsb_size = iommu_tsb_cookie_to_size(pxu_p->tsb_cookie); pxu_p->tsb_vaddr = iommu_tsb_cookie_to_va(pxu_p->tsb_cookie); + pxu_p->tsb_paddr = va_to_pa(pxu_p->tsb_vaddr); + /* * Create "virtual-dma" property to support child devices * needing to know DVMA range. @@ -222,19 +230,39 @@ px_lib_dev_init(dev_info_t *dip, devhandle_t *dev_hdl) /* * Initialize all the interrupt handlers */ - px_err_reg_enable(px_p, PX_ERR_JBC); - px_err_reg_enable(px_p, PX_ERR_MMU); - px_err_reg_enable(px_p, PX_ERR_IMU); - px_err_reg_enable(px_p, PX_ERR_TLU_UE); - px_err_reg_enable(px_p, PX_ERR_TLU_CE); - px_err_reg_enable(px_p, PX_ERR_TLU_OE); - px_err_reg_enable(px_p, PX_ERR_ILU); - px_err_reg_enable(px_p, PX_ERR_LPU_LINK); - px_err_reg_enable(px_p, PX_ERR_LPU_PHY); - px_err_reg_enable(px_p, PX_ERR_LPU_RX); - px_err_reg_enable(px_p, PX_ERR_LPU_TX); - px_err_reg_enable(px_p, PX_ERR_LPU_LTSSM); - px_err_reg_enable(px_p, PX_ERR_LPU_GIGABLZ); + switch (PX_CHIP_TYPE(pxu_p)) { + case PX_CHIP_OBERON: + px_err_reg_enable(px_p, PX_ERR_UBC); + px_err_reg_enable(px_p, PX_ERR_MMU); + px_err_reg_enable(px_p, PX_ERR_IMU); + px_err_reg_enable(px_p, PX_ERR_TLU_UE); + px_err_reg_enable(px_p, PX_ERR_TLU_CE); + px_err_reg_enable(px_p, PX_ERR_TLU_OE); + px_err_reg_enable(px_p, PX_ERR_ILU); + + px_fabric_die_rc_ue |= PCIE_AER_UCE_UC; + break; + + case PX_CHIP_FIRE: + px_err_reg_enable(px_p, PX_ERR_JBC); + px_err_reg_enable(px_p, PX_ERR_MMU); + px_err_reg_enable(px_p, PX_ERR_IMU); + px_err_reg_enable(px_p, PX_ERR_TLU_UE); + px_err_reg_enable(px_p, PX_ERR_TLU_CE); + px_err_reg_enable(px_p, PX_ERR_TLU_OE); + px_err_reg_enable(px_p, PX_ERR_ILU); + px_err_reg_enable(px_p, PX_ERR_LPU_LINK); + px_err_reg_enable(px_p, PX_ERR_LPU_PHY); + px_err_reg_enable(px_p, PX_ERR_LPU_RX); + px_err_reg_enable(px_p, PX_ERR_LPU_TX); + px_err_reg_enable(px_p, PX_ERR_LPU_LTSSM); + px_err_reg_enable(px_p, PX_ERR_LPU_GIGABLZ); + break; + default: + cmn_err(CE_WARN, "%s%d: PX primary bus Unknown\n", + ddi_driver_name(dip), ddi_get_instance(dip)); + return (DDI_FAILURE); + } /* Initilize device handle */ *dev_hdl = (devhandle_t)csr_base; @@ -255,19 +283,36 @@ px_lib_dev_fini(dev_info_t *dip) /* * Deinitialize all the interrupt handlers */ - px_err_reg_disable(px_p, PX_ERR_JBC); - px_err_reg_disable(px_p, PX_ERR_MMU); - px_err_reg_disable(px_p, PX_ERR_IMU); - px_err_reg_disable(px_p, PX_ERR_TLU_UE); - px_err_reg_disable(px_p, PX_ERR_TLU_CE); - px_err_reg_disable(px_p, PX_ERR_TLU_OE); - px_err_reg_disable(px_p, PX_ERR_ILU); - px_err_reg_disable(px_p, PX_ERR_LPU_LINK); - px_err_reg_disable(px_p, PX_ERR_LPU_PHY); - px_err_reg_disable(px_p, PX_ERR_LPU_RX); - px_err_reg_disable(px_p, PX_ERR_LPU_TX); - px_err_reg_disable(px_p, PX_ERR_LPU_LTSSM); - px_err_reg_disable(px_p, PX_ERR_LPU_GIGABLZ); + switch (PX_CHIP_TYPE(pxu_p)) { + case PX_CHIP_OBERON: + px_err_reg_disable(px_p, PX_ERR_UBC); + px_err_reg_disable(px_p, PX_ERR_MMU); + px_err_reg_disable(px_p, PX_ERR_IMU); + px_err_reg_disable(px_p, PX_ERR_TLU_UE); + px_err_reg_disable(px_p, PX_ERR_TLU_CE); + px_err_reg_disable(px_p, PX_ERR_TLU_OE); + px_err_reg_disable(px_p, PX_ERR_ILU); + break; + case PX_CHIP_FIRE: + px_err_reg_disable(px_p, PX_ERR_JBC); + px_err_reg_disable(px_p, PX_ERR_MMU); + px_err_reg_disable(px_p, PX_ERR_IMU); + px_err_reg_disable(px_p, PX_ERR_TLU_UE); + px_err_reg_disable(px_p, PX_ERR_TLU_CE); + px_err_reg_disable(px_p, PX_ERR_TLU_OE); + px_err_reg_disable(px_p, PX_ERR_ILU); + px_err_reg_disable(px_p, PX_ERR_LPU_LINK); + px_err_reg_disable(px_p, PX_ERR_LPU_PHY); + px_err_reg_disable(px_p, PX_ERR_LPU_RX); + px_err_reg_disable(px_p, PX_ERR_LPU_TX); + px_err_reg_disable(px_p, PX_ERR_LPU_LTSSM); + px_err_reg_disable(px_p, PX_ERR_LPU_GIGABLZ); + break; + default: + cmn_err(CE_WARN, "%s%d: PX primary bus Unknown\n", + ddi_driver_name(dip), ddi_get_instance(dip)); + return (DDI_FAILURE); + } iommu_tsb_free(pxu_p->tsb_cookie); @@ -393,12 +438,14 @@ px_lib_intr_setstate(dev_info_t *dip, sysino_t sysino, int px_lib_intr_gettarget(dev_info_t *dip, sysino_t sysino, cpuid_t *cpuid) { + px_t *px_p = DIP_TO_STATE(dip); + pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; uint64_t ret; DBG(DBG_LIB_INT, dip, "px_lib_intr_gettarget: dip 0x%p sysino 0x%llx\n", dip, sysino); - if ((ret = hvio_intr_gettarget(DIP_TO_HANDLE(dip), + if ((ret = hvio_intr_gettarget(DIP_TO_HANDLE(dip), pxu_p, sysino, cpuid)) != H_EOK) { DBG(DBG_LIB_INT, dip, "hvio_intr_gettarget failed, ret 0x%lx\n", ret); @@ -414,12 +461,14 @@ px_lib_intr_gettarget(dev_info_t *dip, sysino_t sysino, cpuid_t *cpuid) int px_lib_intr_settarget(dev_info_t *dip, sysino_t sysino, cpuid_t cpuid) { + px_t *px_p = DIP_TO_STATE(dip); + pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; uint64_t ret; DBG(DBG_LIB_INT, dip, "px_lib_intr_settarget: dip 0x%p sysino 0x%llx " "cpuid 0x%x\n", dip, sysino, cpuid); - if ((ret = hvio_intr_settarget(DIP_TO_HANDLE(dip), + if ((ret = hvio_intr_settarget(DIP_TO_HANDLE(dip), pxu_p, sysino, cpuid)) != H_EOK) { DBG(DBG_LIB_INT, dip, "hvio_intr_settarget failed, ret 0x%lx\n", ret); @@ -531,10 +580,14 @@ px_lib_iommu_getmap(dev_info_t *dip, tsbid_t tsbid, io_attributes_t *attr_p, */ /*ARGSUSED*/ int -px_lib_dma_bypass_rngchk(ddi_dma_attr_t *attr_p, uint64_t *lo_p, uint64_t *hi_p) +px_lib_dma_bypass_rngchk(dev_info_t *dip, ddi_dma_attr_t *attr_p, + uint64_t *lo_p, uint64_t *hi_p) { - *lo_p = MMU_BYPASS_BASE; - *hi_p = MMU_BYPASS_END; + px_t *px_p = DIP_TO_STATE(dip); + pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; + + *lo_p = hvio_get_bypass_base(pxu_p); + *hi_p = hvio_get_bypass_end(pxu_p); return (DDI_SUCCESS); } @@ -546,12 +599,14 @@ px_lib_iommu_getbypass(dev_info_t *dip, r_addr_t ra, io_attributes_t attr, io_addr_t *io_addr_p) { uint64_t ret; + px_t *px_p = DIP_TO_STATE(dip); + pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; DBG(DBG_LIB_DMA, dip, "px_lib_iommu_getbypass: dip 0x%p ra 0x%llx " "attr 0x%x\n", dip, ra, attr); - if ((ret = hvio_iommu_getbypass(DIP_TO_HANDLE(dip), ra, attr, - io_addr_p)) != H_EOK) { + if ((ret = hvio_iommu_getbypass(DIP_TO_HANDLE(dip), pxu_p, ra, + attr, io_addr_p)) != H_EOK) { DBG(DBG_LIB_DMA, dip, "hvio_iommu_getbypass failed, ret 0x%lx\n", ret); return (DDI_FAILURE); @@ -572,12 +627,20 @@ px_lib_dma_sync(dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t handle, off_t off, size_t len, uint_t cache_flags) { ddi_dma_impl_t *mp = (ddi_dma_impl_t *)handle; + px_t *px_p = DIP_TO_STATE(dip); + pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; DBG(DBG_LIB_DMA, dip, "px_lib_dma_sync: dip 0x%p rdip 0x%p " "handle 0x%llx off 0x%x len 0x%x flags 0x%x\n", dip, rdip, handle, off, len, cache_flags); /* + * No flush needed for Oberon + */ + if (PX_CHIP_TYPE(pxu_p) == PX_CHIP_OBERON) + return (DDI_SUCCESS); + + /* * jbus_stst_order is found only in certain cpu modules. * Just return success if not present. */ @@ -1242,6 +1305,122 @@ px_lib_resume(dev_info_t *dip) hvio_resume(dev_hdl, pec_ino, pxu_p); } +/* + * Generate a unique Oberon UBC ID based on the Logicial System Board and + * the IO Channel from the portid property field. + */ +static uint64_t +oberon_get_ubc_id(dev_info_t *dip) +{ + px_t *px_p = DIP_TO_STATE(dip); + pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; + uint64_t ubc_id; + + /* + * Generate a unique 6 bit UBC ID using the 2 IO_Channel#[1:0] bits and + * the 4 LSB_ID[3:0] bits from the Oberon's portid property. + */ + ubc_id = (((pxu_p->portid >> OBERON_PORT_ID_IOC) & + OBERON_PORT_ID_IOC_MASK) | (((pxu_p->portid >> + OBERON_PORT_ID_LSB) & OBERON_PORT_ID_LSB_MASK) + << OBERON_UBC_ID_LSB)); + + return (ubc_id); +} + +/* + * Oberon does not have a UBC scratch register, so alloc an array of scratch + * registers when needed and use a unique UBC ID as an index. This code + * can be simplified if we use a pre-allocated array. They are currently + * being dynamically allocated because it's only needed by the Oberon. + */ +static void +oberon_set_cb(dev_info_t *dip, uint64_t val) +{ + uint64_t ubc_id; + + if (px_oberon_ubc_scratch_regs == NULL) + px_oberon_ubc_scratch_regs = + (uint64_t *)kmem_zalloc(sizeof (uint64_t)* + OBERON_UBC_ID_MAX, KM_SLEEP); + + ubc_id = oberon_get_ubc_id(dip); + + px_oberon_ubc_scratch_regs[ubc_id] = val; + + /* + * Check if any scratch registers are still in use. If all scratch + * registers are currently set to zero, then deallocate the scratch + * register array. + */ + for (ubc_id = 0; ubc_id < OBERON_UBC_ID_MAX; ubc_id++) { + if (px_oberon_ubc_scratch_regs[ubc_id] != NULL) + return; + } + + /* + * All scratch registers are set to zero so deallocate the scratch + * register array and set the pointer to NULL. + */ + kmem_free(px_oberon_ubc_scratch_regs, + (sizeof (uint64_t)*OBERON_UBC_ID_MAX)); + + px_oberon_ubc_scratch_regs = NULL; +} + +/* + * Oberon does not have a UBC scratch register, so use an allocated array of + * scratch registers and use the unique UBC ID as an index into that array. + */ +static uint64_t +oberon_get_cb(dev_info_t *dip) +{ + uint64_t ubc_id; + + if (px_oberon_ubc_scratch_regs == NULL) + return (0); + + ubc_id = oberon_get_ubc_id(dip); + + return (px_oberon_ubc_scratch_regs[ubc_id]); +} + +/* + * Misc Functions: + * Currently unsupported by hypervisor + */ +static uint64_t +px_get_cb(dev_info_t *dip) +{ + px_t *px_p = DIP_TO_STATE(dip); + pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; + + /* + * Oberon does not currently have Scratchpad registers. + */ + if (PX_CHIP_TYPE(pxu_p) == PX_CHIP_OBERON) + return (oberon_get_cb(dip)); + + return (CSR_XR((caddr_t)pxu_p->px_address[PX_REG_XBC], JBUS_SCRATCH_1)); +} + +static void +px_set_cb(dev_info_t *dip, uint64_t val) +{ + px_t *px_p = DIP_TO_STATE(dip); + pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; + + /* + * Oberon does not currently have Scratchpad registers. + */ + if (PX_CHIP_TYPE(pxu_p) == PX_CHIP_OBERON) { + oberon_set_cb(dip, val); + return; + } + + CSR_XS((caddr_t)pxu_p->px_address[PX_REG_XBC], JBUS_SCRATCH_1, val); +} + /*ARGSUSED*/ int px_lib_map_vconfig(dev_info_t *dip, @@ -1806,6 +1985,15 @@ px_identity_chip(px_t *px_p) return (PX_CHIP_ID(PX_CHIP_FIRE, revision, 0x00)); } + /* Check for Oberon driver binding name */ + if (strcmp(name, "pciex108e,80f8") == 0) { + DBG(DBG_ATTACH, dip, "px_identity_chip: %s%d: " + "name %s module-revision %d\n", ddi_driver_name(dip), + ddi_get_instance(dip), name, revision); + + return (PX_CHIP_ID(PX_CHIP_OBERON, revision, 0x00)); + } + DBG(DBG_ATTACH, dip, "%s%d: Unknown PCI Express Host bridge %s %x\n", ddi_driver_name(dip), ddi_get_instance(dip), name, revision); @@ -1847,8 +2035,7 @@ px_cb_add_intr(px_fault_t *fault_p) { px_t *px_p = DIP_TO_STATE(fault_p->px_fh_dip); pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; - px_cb_t *cb_p = (px_cb_t *)CSR_XR((caddr_t) - pxu_p->px_address[PX_REG_XBC], JBUS_SCRATCH_1); + px_cb_t *cb_p = (px_cb_t *)px_get_cb(fault_p->px_fh_dip); px_cb_list_t *pxl, *pxl_new; cpuid_t cpuid; @@ -1858,8 +2045,7 @@ px_cb_add_intr(px_fault_t *fault_p) mutex_init(&cb_p->cb_mutex, NULL, MUTEX_DRIVER, NULL); cb_p->px_cb_func = px_cb_intr; pxu_p->px_cb_p = cb_p; - CSR_XS((caddr_t)pxu_p->px_address[PX_REG_XBC], JBUS_SCRATCH_1, - (uint64_t)cb_p); + px_set_cb(fault_p->px_fh_dip, (uint64_t)cb_p); } else pxu_p->px_cb_p = cb_p; @@ -1967,7 +2153,7 @@ px_cb_rem_intr(px_fault_t *fault_p) mutex_exit(&cb_p->cb_mutex); mutex_destroy(&cb_p->cb_mutex); - CSR_XS((caddr_t)pxu_p->px_address[PX_REG_XBC], JBUS_SCRATCH_1, 0ull); + px_set_cb(fault_p->px_fh_dip, 0ull); kmem_free(cb_p, sizeof (px_cb_t)); } @@ -2039,8 +2225,7 @@ px_fab_get(px_t *px_p, pcie_req_id_t bdf, uint16_t offset) uint32_t val; /* Get Fire's Physical Base Address */ - range_prop = (((uint64_t)(rp[bank].parent_high & 0x7ff)) << 32) | - rp[bank].parent_low; + range_prop = px_get_range_prop(px_p, rp, bank); /* Get config space first. */ base_addr = range_prop + PX_BDF_TO_CFGADDR(bdf, offset); @@ -2058,8 +2243,7 @@ px_fab_set(px_t *px_p, pcie_req_id_t bdf, uint16_t offset, int bank = PCI_REG_ADDR_G(PCI_ADDR_CONFIG); /* Get Fire's Physical Base Address */ - range_prop = (((uint64_t)(rp[bank].parent_high & 0x7ff)) << 32) | - rp[bank].parent_low; + range_prop = px_get_range_prop(px_p, rp, bank); /* Get config space first. */ base_addr = range_prop + PX_BDF_TO_CFGADDR(bdf, offset); @@ -2170,6 +2354,31 @@ px_cpr_callb(void *arg, int code) } /* + * fetch chip's range propery's value + */ +uint64_t +px_get_range_prop(px_t *px_p, px_ranges_t *rp, int bank) +{ + pxu_t *pxu_p = (pxu_t *)px_p->px_plat_p; + uint64_t mask, range_prop; + + switch (PX_CHIP_TYPE(pxu_p)) { + case PX_CHIP_OBERON: + mask = OBERON_RANGE_PROP_MASK; + break; + case PX_CHIP_FIRE: + mask = FIRE_RANGE_PROP_MASK; + break; + default: + mask = FIRE_RANGE_PROP_MASK; + } + range_prop = (((uint64_t)(rp[bank].parent_high & mask)) << 32) | + rp[bank].parent_low; + + return (range_prop); +} + +/* * add cpr callback */ void @@ -2189,14 +2398,69 @@ px_cpr_rem_callb(px_t *px_p) } /*ARGSUSED*/ +static uint_t +px_hp_intr(caddr_t arg1, caddr_t arg2) +{ + px_t *px_p = (px_t *)arg1; + int rval; + + rval = pciehpc_intr(px_p->px_dip); + +#ifdef DEBUG + if (rval == DDI_INTR_UNCLAIMED) + cmn_err(CE_WARN, "%s%d: UNCLAIMED intr\n", + ddi_driver_name(px_p->px_dip), + ddi_get_instance(px_p->px_dip)); +#endif + + return (rval); +} + int px_lib_hotplug_init(dev_info_t *dip, void *arg) { - return (DDI_ENOTSUP); + px_t *px_p = DIP_TO_STATE(dip); + uint64_t ret; + + if ((ret = hvio_hotplug_init(dip, arg)) == DDI_SUCCESS) { + sysino_t sysino; + + if (px_lib_intr_devino_to_sysino(px_p->px_dip, + px_p->px_inos[PX_INTR_HOTPLUG], &sysino) != + DDI_SUCCESS) { +#ifdef DEBUG + cmn_err(CE_WARN, "%s%d: devino_to_sysino fails\n", + ddi_driver_name(px_p->px_dip), + ddi_get_instance(px_p->px_dip)); +#endif + return (DDI_FAILURE); + } + + VERIFY(add_ivintr(sysino, PX_PCIEHP_PIL, + (intrfunc)px_hp_intr, (caddr_t)px_p, NULL) == 0); + } + + return (ret); } -/*ARGSUSED*/ void px_lib_hotplug_uninit(dev_info_t *dip) { + if (hvio_hotplug_uninit(dip) == DDI_SUCCESS) { + px_t *px_p = DIP_TO_STATE(dip); + sysino_t sysino; + + if (px_lib_intr_devino_to_sysino(px_p->px_dip, + px_p->px_inos[PX_INTR_HOTPLUG], &sysino) != + DDI_SUCCESS) { +#ifdef DEBUG + cmn_err(CE_WARN, "%s%d: devino_to_sysino fails\n", + ddi_driver_name(px_p->px_dip), + ddi_get_instance(px_p->px_dip)); +#endif + return; + } + + rem_ivintr(sysino, NULL); + } } diff --git a/usr/src/uts/sun4u/io/px/px_lib4u.h b/usr/src/uts/sun4u/io/px/px_lib4u.h index e7c27cfb5b..5012e4a4f1 100644 --- a/usr/src/uts/sun4u/io/px/px_lib4u.h +++ b/usr/src/uts/sun4u/io/px/px_lib4u.h @@ -86,6 +86,8 @@ typedef struct pxu { uint16_t tsb_cookie; uint32_t tsb_size; uint64_t *tsb_vaddr; + uint64_t tsb_paddr; /* Only used for Oberon */ + void *msiq_mapped_p; px_cb_t *px_cb_p; @@ -136,7 +138,8 @@ typedef struct eq_rec { #define MMU_INVALID_TTE 0ull #define MMU_TTE_VALID(tte) (((tte) & MMU_TTE_V) == MMU_TTE_V) -#define MMU_TTETOPA(x) ((x & 0x7ffffffffff) >> MMU_PAGE_SHIFT) +#define MMU_OBERON_PADDR_MASK 0x7fffffffffff +#define MMU_FIRE_PADDR_MASK 0x7ffffffffff /* * control register decoding @@ -146,16 +149,26 @@ typedef struct eq_rec { #define MMU_TSBSIZE_TO_TSBENTRIES(s) ((1 << (s)) << (13 - 3)) /* - * For mmu bypass addresses, bit 43 specifies cacheability. + * For Fire mmu bypass addresses, bit 43 specifies cacheability. */ -#define MMU_BYPASS_NONCACHE (1ull << 43) +#define MMU_FIRE_BYPASS_NONCACHE (1ull << 43) + +/* + * For Oberon mmu bypass addresses, bit 47 specifies cacheability. + */ +#define MMU_OBERON_BYPASS_NONCACHE (1ull << 47) /* * The following macros define the address ranges supported for DVMA - * and mmu bypass transfers. + * and mmu bypass transfers. For Oberon, bit 63 is used for ordering. */ -#define MMU_BYPASS_BASE 0xFFFC000000000000ull -#define MMU_BYPASS_END 0xFFFC01FFFFFFFFFFull +#define MMU_FIRE_BYPASS_BASE 0xFFFC000000000000ull +#define MMU_FIRE_BYPASS_END 0xFFFC01FFFFFFFFFFull + +#define MMU_OBERON_BYPASS_BASE 0x7FFC000000000000ull +#define MMU_OBERON_BYPASS_END 0x7FFC01FFFFFFFFFFull + +#define MMU_TSB_PA_MASK 0x7FFFFFFFE000 /* * The following macros are for loading and unloading io tte @@ -164,6 +177,7 @@ typedef struct eq_rec { #define MMU_TTE_SIZE 8 #define MMU_TTE_V (1ull << 63) #define MMU_TTE_W (1ull << 1) +#define MMU_TTE_RO (1ull << 62) /* Oberon Relaxed Ordering */ #define INO_BITS 6 /* INO#s are 6 bits long */ #define IGN_BITS 5 /* IGN#s are 5 bits long */ @@ -248,7 +262,8 @@ typedef struct eq_rec { */ typedef enum { PX_CHIP_UNIDENTIFIED = 0, - PX_CHIP_FIRE = 1 + PX_CHIP_FIRE = 1, + PX_CHIP_OBERON = 2 } px_chip_id_t; /* @@ -256,16 +271,18 @@ typedef enum { * 0x00 <chip_type> <version#> <module-revision#> */ #define PX_CHIP_ID(t, v, m) (((t) << 16) | ((v) << 8) | (m)) -#define PX_ID_CHIP_TYPE(id) ((id) >> 16) -#define PX_CHIP_TYPE(pxu_p) PX_ID_CHIP_TYPE(PX_CHIP_ID((pxu_p)->chip_id)) -#define PX_CHIP_REV(pxu_p) PX_CHIP_ID(((pxu_p)->chip_id) & 0xFF) -#define PX_CHIP_VER(pxu_p) PX_CHIP_ID((((pxu_p)->chip_id) >> 8) & 0xFF) +#define PX_CHIP_TYPE(pxu_p) (((pxu_p)->chip_id) >> 16) +#define PX_CHIP_REV(pxu_p) (((pxu_p)->chip_id) & 0xFF) +#define PX_CHIP_VER(pxu_p) ((((pxu_p)->chip_id) >> 8) & 0xFF) /* * Fire hardware specific version definitions. */ #define FIRE_VER_10 PX_CHIP_ID(PX_CHIP_FIRE, 0x01, 0x00) #define FIRE_VER_20 PX_CHIP_ID(PX_CHIP_FIRE, 0x03, 0x00) +#define OBERON_VER_10 PX_CHIP_ID(PX_CHIP_OBERON, 0x00, 0x00) +#define FIRE_RANGE_PROP_MASK 0x7ff +#define OBERON_RANGE_PROP_MASK 0x7fff extern void hvio_cb_init(caddr_t xbc_csr_base, pxu_t *pxu_p); extern void hvio_ib_init(caddr_t csr_base, pxu_t *pxu_p); @@ -282,10 +299,10 @@ extern uint64_t hvio_intr_getstate(devhandle_t dev_hdl, sysino_t sysino, intr_state_t *intr_state); extern uint64_t hvio_intr_setstate(devhandle_t dev_hdl, sysino_t sysino, intr_state_t intr_state); -extern uint64_t hvio_intr_gettarget(devhandle_t dev_hdl, sysino_t sysino, - cpuid_t *cpuid); -extern uint64_t hvio_intr_settarget(devhandle_t dev_hdl, sysino_t sysino, - cpuid_t cpuid); +extern uint64_t hvio_intr_gettarget(devhandle_t dev_hdl, pxu_t *pxu_p, + sysino_t sysino, cpuid_t *cpuid); +extern uint64_t hvio_intr_settarget(devhandle_t dev_hdl, pxu_t *pxu_p, + sysino_t sysino, cpuid_t cpuid); extern uint64_t hvio_iommu_map(devhandle_t dev_hdl, pxu_t *pxu_p, tsbid_t tsbid, pages_t pages, io_attributes_t attr, void *addr, size_t pfn_index, @@ -294,8 +311,12 @@ extern uint64_t hvio_iommu_demap(devhandle_t dev_hdl, pxu_t *pxu_p, tsbid_t tsbid, pages_t pages); extern uint64_t hvio_iommu_getmap(devhandle_t dev_hdl, pxu_t *pxu_p, tsbid_t tsbid, io_attributes_t *attr_p, r_addr_t *r_addr_p); -extern uint64_t hvio_iommu_getbypass(devhandle_t dev_hdl, r_addr_t ra, - io_attributes_t attr, io_addr_t *io_addr_p); +extern uint64_t hvio_iommu_getbypass(devhandle_t dev_hdl, pxu_t *pxu_p, + r_addr_t ra, io_attributes_t attr, io_addr_t *io_addr_p); +extern uint64_t hvio_get_bypass_base(pxu_t *pxu_p); +extern uint64_t hvio_get_bypass_end(pxu_t *pxu_p); +extern uint64_t px_get_range_prop(px_t *px_p, px_ranges_t *rp, int bank); + /* * MSIQ Functions: @@ -362,6 +383,12 @@ extern void px_enable_detect_quiet(caddr_t csr_base); extern void px_lib_clr_errs(px_t *px_p); +/* + * Hotplug functions: + */ +extern int hvio_hotplug_init(dev_info_t *dip, void *arg); +extern int hvio_hotplug_uninit(dev_info_t *dip); + #ifdef __cplusplus } #endif diff --git a/usr/src/uts/sun4u/io/todopl.c b/usr/src/uts/sun4u/io/todopl.c new file mode 100644 index 0000000000..5d510d3c42 --- /dev/null +++ b/usr/src/uts/sun4u/io/todopl.c @@ -0,0 +1,321 @@ +/* + * 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" + +/* + * tod driver module for OPL (implements a soft tod) + */ + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/sysmacros.h> +#include <sys/systm.h> +#include <sys/errno.h> +#include <sys/modctl.h> +#include <sys/autoconf.h> +#include <sys/debug.h> +#include <sys/clock.h> +#include <sys/cmn_err.h> +#include <sys/prom_plat.h> +#include <sys/cpuvar.h> +#include <sys/opl_module.h> + +/* + * Debug stuff + */ +#ifdef DEBUG +int todopl_debug = 0; +#define TODOPL_DEBUG(args) if (todopl_debug) cmn_err args +#else +#define TODOPL_DEBUG(args) +#endif + +#define abs(x) ((x) < 0 ? -(x) : (x)) + +#define TODOPL_SET_THRESHOLD 30 + +static timestruc_t todopl_get(void); +static void todopl_set(timestruc_t); +static uint_t todopl_set_watchdog_timer(uint_t); +static uint_t todopl_clear_watchdog_timer(void); +static void todopl_set_power_alarm(timestruc_t); +static void todopl_clear_power_alarm(void); +static uint64_t todopl_get_cpufrequency(void); + +/* + * Module linkage information for the kernel. + */ +static struct modlmisc modlmisc = { + &mod_miscops, "Soft tod module for OPL 1.11" +}; + +static struct modlinkage modlinkage = { + MODREV_1, (void *)&modlmisc, NULL +}; + +/* + * The TOD OPL logic description. + * + * The todopl driver uses promif functions prom_opl_get_tod() and + * prom_opl_set_diff(). These functions call FJSV,get-tod and + * FJSV,set-domain-time OBP client services. + * + * At the system boot or reboot: + * + * FJSV,tod-get + * OS ---------> OBP SCF I/F + * -----------> XSCF + * <----------- + * <-------- time, diff + * time+diff, stick + * + * Note that on first powerup domain boot, diff is zero. + * + * When system updates the time via date(1m): + * + * FJSV,set-domain-time + * OS ---------> OBP SRAM + * diff_delta diff += diff_delta -------------> XSCF + * + * diff_delta = new time - current domain time (hrestime) + * + * + * In theory, FJSV,get-tod and FJSV,set-domain-time should never fails. + * But, if call to FJSV,get-tod fails on boot, the domain will be unable + * to calculate "diff" properly and synchronization between Domain and + * SP will be broken. In this particular case, we notify users that + * "there is no time synchronization" and the logic will attempt to + * resync with the SP whenever the OS tries to do a TOD update. + * (e.g. via date(1m) or NTP). + */ + +static int enable_time_sync = 1; + +int +_init(void) +{ + int64_t stick; + time_t obp_time = 0; + int64_t obp_stick; + + if (strcmp(tod_module_name, "todopl") == 0) { + /* + * Get TOD time from OBP and adjust it. + */ + prom_opl_get_tod(&obp_time, &obp_stick); + + TODOPL_DEBUG((CE_NOTE, "todopl: OBP time 0x%lx stick 0x%lx\n", + obp_time, obp_stick)); + + if (obp_time != 0) { + /* + * adjust OBP time by stick counts + */ + stick_timestamp(&stick); + obp_time += ((stick - obp_stick) / system_clock_freq); + + TODOPL_DEBUG((CE_NOTE, + "todopl: cpu stick 0x%lx sys_time 0x%lx\n", + stick, obp_time)); + } else { + /* + * A date of zero causes the root filesystem driver + * to try to set the date from the last shutdown. + */ + enable_time_sync = 0; + cmn_err(CE_WARN, "Initial date is invalid."); + cmn_err(CE_CONT, "Attempting to set the date and time " + "based on the last shutdown.\n"); + cmn_err(CE_CONT, "The time could not be synchronized " + "between Domain and Service Processor.\n"); + cmn_err(CE_CONT, "Please inspect the date and time and " + "correct if necessary.\n"); + } + + hrestime.tv_sec = obp_time; + + /* + * Check that the date has not overflowed a 32-bit integer. + */ + if (TIMESPEC_OVERFLOW(&hrestime)) { + cmn_err(CE_WARN, "Date overflow detected."); + cmn_err(CE_CONT, "Attempting to set the date and time " + "based on the last shutdown.\n"); + cmn_err(CE_CONT, "Please inspect the date and time and " + "correct if necessary.\n"); + + hrestime.tv_sec = (time_t)0; + } + + tod_ops.tod_get = todopl_get; + tod_ops.tod_set = todopl_set; + tod_ops.tod_set_watchdog_timer = todopl_set_watchdog_timer; + tod_ops.tod_clear_watchdog_timer = todopl_clear_watchdog_timer; + tod_ops.tod_set_power_alarm = todopl_set_power_alarm; + tod_ops.tod_clear_power_alarm = todopl_clear_power_alarm; + tod_ops.tod_get_cpufrequency = todopl_get_cpufrequency; + + /* + * Flag warning if user tried to use hardware watchdog + */ + if (watchdog_enable) { + cmn_err(CE_WARN, "Hardware watchdog unavailable"); + } + } + + return (mod_install(&modlinkage)); +} + +int +_fini(void) +{ + if (strcmp(tod_module_name, "todopl") == 0) + return (EBUSY); + else + return (mod_remove(&modlinkage)); +} + +int +_info(struct modinfo *modinfop) +{ + return (mod_info(&modlinkage, modinfop)); +} + + +/* + * OPL tod_get is simplified to return hrestime + * Must be called with tod_lock held. + */ +static timestruc_t +todopl_get(void) +{ + ASSERT(MUTEX_HELD(&tod_lock)); + return (hrestime); +} + +/* + * Must be called with tod_lock held. + * + * When running NTP, tod_set is called at least once per second in order + * to update the hardware clock. To minimize pressure on SP, we want only + * to record significant time changes on the SP (when date(1M) is run). + * We have 30 seconds threshold requirement before recording the time change. + */ +/* ARGSUSED */ +static void +todopl_set(timestruc_t ts) +{ + ASSERT(MUTEX_HELD(&tod_lock)); + + if (abs(ts.tv_sec - hrestime.tv_sec) > TODOPL_SET_THRESHOLD) { + /* + * Send time difference to SP + */ + if (enable_time_sync) + prom_opl_set_diff(ts.tv_sec - hrestime.tv_sec); + else { + /* + * We did not get a successful initial time + * update/sync from the SP via OBP during boot. + * Try again here. + */ + time_t obp_time = 0; + int64_t obp_stick; + int64_t stick; + + prom_opl_get_tod(&obp_time, &obp_stick); + + if (obp_time != 0) { + /* + * adjust OBP time by stick counts + */ + stick_timestamp(&stick); + obp_time += ((stick - obp_stick) / + system_clock_freq); + + /* + * Sync up by computing the diff using the + * newly acquired SP/OBP reference time + */ + prom_opl_set_diff(ts.tv_sec - obp_time); + + enable_time_sync = 1; + } + } + TODOPL_DEBUG((CE_NOTE, "todopl_set: new domain time 0x%lx\n", + ts.tv_sec)); + } +} + +/* + * No watchdog function. + */ +/* ARGSUSED */ +static uint_t +todopl_set_watchdog_timer(uint_t timeoutval) +{ + ASSERT(MUTEX_HELD(&tod_lock)); + return (0); +} + +/* + * No watchdog function + */ +static uint_t +todopl_clear_watchdog_timer(void) +{ + ASSERT(MUTEX_HELD(&tod_lock)); + return (0); +} + +/* + * Null function. + */ +/* ARGSUSED */ +static void +todopl_set_power_alarm(timestruc_t ts) +{ + ASSERT(MUTEX_HELD(&tod_lock)); +} + +/* + * Null function + */ +static void +todopl_clear_power_alarm() +{ + ASSERT(MUTEX_HELD(&tod_lock)); +} + +/* + * Get clock freq from the cpunode. This function is only called + * when use_stick = 0, otherwise, system_clock_freq gets used instead. + */ +uint64_t +todopl_get_cpufrequency(void) +{ + return (cpunodes[CPU->cpu_id].clock_freq); +} diff --git a/usr/src/uts/sun4u/ml/mach_locore.s b/usr/src/uts/sun4u/ml/mach_locore.s index 56a6254626..b430fef0cc 100644 --- a/usr/src/uts/sun4u/ml/mach_locore.s +++ b/usr/src/uts/sun4u/ml/mach_locore.s @@ -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. @@ -1191,7 +1190,13 @@ ptl1_panic(u_int reason) ! Flushing D$ erases old data in D$, so that it will not be loaded. ! Since we can afford only 2 registers (%g2 and %g3) for this job, we ! flush entire D$. + ! For FJ OPL processors (IMPL values < SPITFIRE_IMPL), DC flushing + ! is not needed. ! + GET_CPU_IMPL(%g2) + cmp %g2, SPITFIRE_IMPL + blt,pn %icc, 1f ! Skip flushing for OPL processors + nop sethi %hi(dcache_size), %g2 ld [%g2 + %lo(dcache_size)], %g2 sethi %hi(dcache_linesize), %g3 @@ -1201,6 +1206,7 @@ ptl1_panic(u_int reason) membar #Sync brnz,pt %g2, 0b sub %g2, %g3, %g2 +1: ! ! increment the entry counter. ! save CPU state if this is the first entry. diff --git a/usr/src/uts/sun4u/ml/mach_offsets.in b/usr/src/uts/sun4u/ml/mach_offsets.in index d70e3c3457..560127697e 100644 --- a/usr/src/uts/sun4u/ml/mach_offsets.in +++ b/usr/src/uts/sun4u/ml/mach_offsets.in @@ -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. @@ -19,7 +18,7 @@ \ \ CDDL HEADER END \ -\ Copyright 2005 Sun Microsystems, Inc. All rights reserved. +\ Copyright 2006 Sun Microsystems, Inc. All rights reserved. \ Use is subject to license terms. \ \ offsets.in: input file to produce assym.h using the stabs program @@ -200,6 +199,7 @@ page PAGE_SIZE tsb_info TSBINFO_SIZE tsb_tte TSBINFO_TTE tsb_va TSBINFO_VADDR + tsb_pa TSBINFO_PADDR tsb_szc TSBINFO_SZCODE tsb_next TSBINFO_NEXTPTR diff --git a/usr/src/uts/sun4u/ml/trap_table.s b/usr/src/uts/sun4u/ml/trap_table.s index 81c0089739..981749e8ee 100644 --- a/usr/src/uts/sun4u/ml/trap_table.s +++ b/usr/src/uts/sun4u/ml/trap_table.s @@ -31,6 +31,7 @@ #include <sys/asm_linkage.h> #include <sys/privregs.h> #include <sys/sun4asi.h> +#include <sys/spitregs.h> #include <sys/cheetahregs.h> #include <sys/machtrap.h> #include <sys/machthread.h> @@ -855,7 +856,9 @@ * to stop RED state entry if the store queue has many * pending bad stores (PRM, Chapter 11). */ -#define ASYNC_TRAP(ttype, ttlabel)\ +#define ASYNC_TRAP(ttype, ttlabel, table_name)\ + .global table_name ;\ +table_name: ;\ membar #Sync ;\ TT_TRACE(ttlabel) ;\ ba async_err ;\ @@ -1063,6 +1066,41 @@ tt1_dtlbmiss: * could live in this file but currently it seems better to allow * it to fall thru to sfmmu_tsb_miss. */ +#ifdef UTSB_PHYS +#define DTLB_MISS(table_name) ;\ + .global table_name/**/_dtlbmiss ;\ +table_name/**/_dtlbmiss: ;\ + HAT_PERCPU_DBSTAT(TSBMISS_DTLBMISS) /* 3 instr ifdef DEBUG */ ;\ + mov MMU_TAG_ACCESS, %g6 /* select tag acc */ ;\ + ldxa [%g0]ASI_DMMU_TSB_8K, %g1 /* g1 = tsbe ptr */ ;\ + ldxa [%g6]ASI_DMMU, %g2 /* g2 = tag access */ ;\ + sllx %g2, TAGACC_CTX_LSHIFT, %g3 ;\ + srlx %g3, TAGACC_CTX_LSHIFT, %g3 /* g3 = ctx */ ;\ + cmp %g3, INVALID_CONTEXT ;\ + ble,pn %xcc, sfmmu_kdtlb_miss ;\ + srlx %g2, TAG_VALO_SHIFT, %g7 /* g7 = tsb tag */ ;\ + mov SCRATCHPAD_UTSBREG, %g3 ;\ + ldxa [%g3]ASI_SCRATCHPAD, %g3 /* g3 = 2nd tsb reg */ ;\ + brgez,pn %g3, sfmmu_udtlb_slowpath /* branch if 2 TSBs */ ;\ + nop ;\ + ldda [%g1]ASI_QUAD_LDD_PHYS, %g4 /* g4 = tag, %g5 data */;\ + cmp %g4, %g7 ;\ + bne,pn %xcc, sfmmu_tsb_miss_tt /* no 4M TSB, miss */ ;\ + mov %g0, %g3 /* clear 4M tsbe ptr */ ;\ + TT_TRACE(trace_tsbhit) /* 2 instr ifdef TRAPTRACE */ ;\ + stxa %g5, [%g0]ASI_DTLB_IN /* trapstat expects TTE */ ;\ + retry /* in %g5 */ ;\ + unimp 0 ;\ + unimp 0 ;\ + unimp 0 ;\ + unimp 0 ;\ + unimp 0 ;\ + unimp 0 ;\ + unimp 0 ;\ + unimp 0 ;\ + unimp 0 ;\ + .align 128 +#else /* UTSB_PHYS */ #define DTLB_MISS(table_name) ;\ .global table_name/**/_dtlbmiss ;\ table_name/**/_dtlbmiss: ;\ @@ -1096,6 +1134,7 @@ table_name/**/_dtlbmiss: ;\ unimp 0 ;\ unimp 0 ;\ .align 128 +#endif /* UTSB_PHYS */ #if defined(cscope) /* @@ -1115,6 +1154,41 @@ tt1_itlbmiss: * by sfmmu_patch_ktsb at runtime. * MUST be EXACTLY 32 instructions or we'll break. */ +#ifdef UTSB_PHYS +#define ITLB_MISS(table_name) \ + .global table_name/**/_itlbmiss ;\ +table_name/**/_itlbmiss: ;\ + HAT_PERCPU_DBSTAT(TSBMISS_ITLBMISS) /* 3 instr ifdef DEBUG */ ;\ + mov MMU_TAG_ACCESS, %g6 /* select tag acc */ ;\ + ldxa [%g0]ASI_IMMU_TSB_8K, %g1 /* g1 = tsbe ptr */ ;\ + ldxa [%g6]ASI_IMMU, %g2 /* g2 = tag access */ ;\ + sllx %g2, TAGACC_CTX_LSHIFT, %g3 ;\ + srlx %g3, TAGACC_CTX_LSHIFT, %g3 /* g3 = ctx */ ;\ + cmp %g3, INVALID_CONTEXT ;\ + ble,pn %xcc, sfmmu_kitlb_miss ;\ + srlx %g2, TAG_VALO_SHIFT, %g7 /* g7 = tsb tag */ ;\ + mov SCRATCHPAD_UTSBREG, %g3 ;\ + ldxa [%g3]ASI_SCRATCHPAD, %g3 /* g3 = 2nd tsb reg */ ;\ + brgez,pn %g3, sfmmu_uitlb_slowpath /* branch if 2 TSBs */ ;\ + nop ;\ + ldda [%g1]ASI_QUAD_LDD_PHYS, %g4 /* g4 = tag, g5 = data */ ;\ + cmp %g4, %g7 ;\ + bne,pn %xcc, sfmmu_tsb_miss_tt /* br if 8k ptr miss */ ;\ + mov %g0, %g3 /* no 4M TSB */ ;\ + andcc %g5, TTE_EXECPRM_INT, %g0 /* check execute bit */ ;\ + bz,pn %icc, exec_fault ;\ + nop ;\ + TT_TRACE(trace_tsbhit) /* 2 instr ifdef TRAPTRACE */ ;\ + stxa %g5, [%g0]ASI_ITLB_IN /* trapstat expects %g5 */ ;\ + retry ;\ + unimp 0 ;\ + unimp 0 ;\ + unimp 0 ;\ + unimp 0 ;\ + unimp 0 ;\ + unimp 0 ;\ + .align 128 +#else /* UTSB_PHYS */ #define ITLB_MISS(table_name) \ .global table_name/**/_itlbmiss ;\ table_name/**/_itlbmiss: ;\ @@ -1148,6 +1222,7 @@ table_name/**/_itlbmiss: ;\ unimp 0 ;\ unimp 0 ;\ .align 128 +#endif /* UTSB_PHYS */ /* @@ -1278,7 +1353,7 @@ trap_table0: NOT; NOT; /* 006 - 007 reserved */ IMMU_EXCEPTION; /* 008 instruction access exception */ NOT; /* 009 instruction access MMU miss */ - ASYNC_TRAP(T_INSTR_ERROR, trace_gen); + ASYNC_TRAP(T_INSTR_ERROR, trace_gen, tt0_iae); /* 00A instruction access error */ NOT; NOT4; /* 00B - 00F reserved */ ILLTRAP_INSTR; /* 010 illegal instruction */ @@ -1296,7 +1371,7 @@ trap_table0: NOT; NOT; NOT4; /* 02A - 02F reserved */ DMMU_EXCEPTION; /* 030 data access exception */ NOT; /* 031 data access MMU miss */ - ASYNC_TRAP(T_DATA_ERROR, trace_gen); + ASYNC_TRAP(T_DATA_ERROR, trace_gen, tt0_dae); /* 032 data access error */ NOT; /* 033 data access protection */ DMMU_EXC_AG_NOT_ALIGNED; /* 034 mem address not aligned */ @@ -1306,7 +1381,7 @@ trap_table0: NOT; /* 038 LDQF mem address not aligned */ NOT; /* 039 STQF mem address not aligned */ NOT; NOT; NOT4; /* 03A - 03F reserved */ - NOT; /* 040 async data error */ + LABELED_BAD(tt0_asdat); /* 040 async data error */ LEVEL_INTERRUPT(1); /* 041 interrupt level 1 */ LEVEL_INTERRUPT(2); /* 042 interrupt level 2 */ LEVEL_INTERRUPT(3); /* 043 interrupt level 3 */ @@ -1432,7 +1507,7 @@ trap_table0: NOT4; NOT4; NOT4; NOT4; /* 1F0 - 1FF reserved */ trap_table1: NOT4; NOT4; NOT; NOT; /* 000 - 009 unused */ - ASYNC_TRAP(T_INSTR_ERROR + T_TL1, trace_gen); + ASYNC_TRAP(T_INSTR_ERROR + T_TL1, trace_gen, tt1_iae); /* 00A instruction access error */ NOT; NOT4; /* 00B - 00F unused */ NOT4; NOT4; NOT4; NOT4; /* 010 - 01F unused */ @@ -1441,12 +1516,14 @@ trap_table1: NOT4; NOT4; /* 028 - 02F unused */ DMMU_EXCEPTION_TL1; /* 030 data access exception */ NOT; /* 031 unused */ - ASYNC_TRAP(T_DATA_ERROR + T_TL1, trace_gen); + ASYNC_TRAP(T_DATA_ERROR + T_TL1, trace_gen, tt1_dae); /* 032 data access error */ NOT; /* 033 unused */ MISALIGN_ADDR_TL1; /* 034 mem address not aligned */ NOT; NOT; NOT; NOT4; NOT4 /* 035 - 03F unused */ - NOT4; NOT4; NOT4; NOT4; /* 040 - 04F unused */ + LABELED_BAD(tt1_asdat); /* 040 async data error */ + NOT; NOT; NOT; /* 041 - 043 unused */ + NOT4; NOT4; NOT4; /* 044 - 04F unused */ NOT4; NOT4; NOT4; NOT4; /* 050 - 05F unused */ NOT; /* 060 unused */ GOTO(kmdb_trap_tl1); /* 061 PA watchpoint */ @@ -2608,13 +2685,15 @@ mmu_trap_tl1_4: add %g6, CPU_TL1_HDLR, %g6 ! %g6 = &cpu_m.tl1_hdlr (VA) GET_CPU_IMPL(%g5) cmp %g5, CHEETAH_IMPL - bl,pn %icc, 3f - sethi %hi(dcache_line_mask), %g5 + bl,pt %icc, 3f + cmp %g5, SPITFIRE_IMPL stxa %g0, [%g7]ASI_DC_INVAL membar #Sync ba,pt %xcc, 2f - nop + nop 3: + bl,pt %icc, 2f + sethi %hi(dcache_line_mask), %g5 ld [%g5 + %lo(dcache_line_mask)], %g5 and %g6, %g5, %g5 stxa %g0, [%g5]ASI_DC_TAG @@ -2932,4 +3011,3 @@ fast_trap_dummy_call: nop #endif /* lint */ - diff --git a/usr/src/uts/sun4u/ngdr/io/dr.c b/usr/src/uts/sun4u/ngdr/io/dr.c index f9d0bd668f..2d84b9e4ef 100644 --- a/usr/src/uts/sun4u/ngdr/io/dr.c +++ b/usr/src/uts/sun4u/ngdr/io/dr.c @@ -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,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -115,7 +114,9 @@ static dr_devname_t dr_devattr[] = { { DRMACH_DEVTYPE_MEM, SBD_COMP_MEM }, { DRMACH_DEVTYPE_CPU, SBD_COMP_CPU }, { DRMACH_DEVTYPE_PCI, SBD_COMP_IO }, +#if defined(DRMACH_DEVTYPE_SBUS) { DRMACH_DEVTYPE_SBUS, SBD_COMP_IO }, +#endif #if defined(DRMACH_DEVTYPE_WCI) { DRMACH_DEVTYPE_WCI, SBD_COMP_IO }, #endif @@ -448,7 +449,7 @@ _init(void) * soft state structure each time a node is attached. */ err = ddi_soft_state_init((void **)&dr_g.softsp, - sizeof (dr_softstate_t), 1); + sizeof (dr_softstate_t), 1); if (err) return (err); @@ -546,12 +547,9 @@ dr_close(dev_t dev, int flag, int otyp, cred_t *cred_p) } /* - * Enable/disable Starcat DR features. + * Enable/disable DR features. */ -#ifndef _STARFIRE int dr_enable = 1; -int slot1_dr_enable = 1; -#endif /* _STARFIRE */ /*ARGSUSED3*/ static int @@ -576,7 +574,6 @@ dr_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, return (ENXIO); } -#ifndef _STARFIRE if (!dr_enable) { switch (cmd) { case SBD_CMD_STATUS: @@ -587,25 +584,11 @@ dr_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, return (ENOTSUP); } } -#endif /* _STARFIRE */ bd = DR_MINOR2BNUM(getminor(dev)); if (bd >= MAX_BOARDS) return (ENXIO); -#ifndef _STARFIRE - if (!slot1_dr_enable && (bd & 0x1)) { - switch (cmd) { - case SBD_CMD_STATUS: - case SBD_CMD_GETNCM: - case SBD_CMD_PASSTHRU: - break; - default: - return (ENOTSUP); - } - } -#endif /* _STARFIRE */ - /* get and initialize storage for new handle */ hp = GETSTRUCT(dr_handle_t, 1); hp->h_bd = &softsp->boards[bd]; @@ -695,7 +678,7 @@ dr_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, /* Board changed state. Log a sysevent. */ if (rv == 0) (void) drmach_log_sysevent(hp->h_bd->b_num, "", - SE_SLEEP, 1); + SE_SLEEP, 1); /* Fall through */ default: @@ -917,7 +900,7 @@ dr_copyin_iocmd(dr_handle_t *hp) bzero((caddr_t)&scmd32, sizeof (sbd_cmd32_t)); if (ddi_copyin((void *)hp->h_iap, (void *)&scmd32, - sizeof (sbd_cmd32_t), hp->h_mode)) { + sizeof (sbd_cmd32_t), hp->h_mode)) { cmn_err(CE_WARN, "%s: (32bit) failed to copyin " "sbdcmd-struct", f); @@ -944,7 +927,7 @@ dr_copyin_iocmd(dr_handle_t *hp) } else #endif /* _MULTI_DATAMODEL */ if (ddi_copyin((void *)hp->h_iap, (void *)scp, - sizeof (sbd_cmd_t), hp->h_mode) != 0) { + sizeof (sbd_cmd_t), hp->h_mode) != 0) { cmn_err(CE_WARN, "%s: failed to copyin sbdcmd-struct", f); return (EFAULT); @@ -994,7 +977,7 @@ dr_copyout_iocmd(dr_handle_t *hp) } if (ddi_copyout((void *)&scmd32, (void *)hp->h_iap, - sizeof (sbd_cmd32_t), hp->h_mode)) { + sizeof (sbd_cmd32_t), hp->h_mode)) { cmn_err(CE_WARN, "%s: (32bit) failed to copyout " "sbdcmd-struct", f); @@ -1003,7 +986,7 @@ dr_copyout_iocmd(dr_handle_t *hp) } else #endif /* _MULTI_DATAMODEL */ if (ddi_copyout((void *)scp, (void *)hp->h_iap, - sizeof (sbd_cmd_t), hp->h_mode) != 0) { + sizeof (sbd_cmd_t), hp->h_mode) != 0) { cmn_err(CE_WARN, "%s: failed to copyout sbdcmd-struct", f); return (EFAULT); @@ -1036,7 +1019,7 @@ dr_copyout_errs(dr_handle_t *hp) MAXPATHLEN); if (ddi_copyout((void *)serr32p, (void *)&((sbd_ioctl_arg32_t *)hp->h_iap)->i_err, - sizeof (sbd_error32_t), hp->h_mode)) { + sizeof (sbd_error32_t), hp->h_mode)) { cmn_err(CE_WARN, "%s: (32bit) failed to copyout", f); return (EFAULT); @@ -1046,7 +1029,7 @@ dr_copyout_errs(dr_handle_t *hp) #endif /* _MULTI_DATAMODEL */ if (ddi_copyout((void *)hp->h_err, (void *)&hp->h_iap->i_err, - sizeof (sbd_error_t), hp->h_mode)) { + sizeof (sbd_error_t), hp->h_mode)) { cmn_err(CE_WARN, "%s: failed to copyout", f); return (EFAULT); @@ -1371,7 +1354,7 @@ dr_connect(dr_handle_t *hp) /* * Board already has devices present. */ - PR_ALL("%s: devices already present (0x%x)\n", + PR_ALL("%s: devices already present (0x%lx)\n", f, DR_DEVS_PRESENT(bp)); return; } @@ -1408,7 +1391,7 @@ dr_disconnect(dr_handle_t *hp) * unattached can be disconnected. */ devset = hp->h_devset & DR_DEVS_PRESENT(bp) & - DR_DEVS_UNATTACHED(bp); + DR_DEVS_UNATTACHED(bp); if ((devset == 0) && DR_DEVS_PRESENT(bp)) { dr_op_err(CE_IGNORE, hp, ESBD_EMPTY_BD, bp->b_path); @@ -2017,8 +2000,8 @@ dr_detach_update_state(dr_handle_t *hp, hp->h_bd->b_ostate = SBD_STAT_UNCONFIGURED; (void) drv_getparm(TIME, (void *)&hp->h_bd->b_time); } else if ((bp->b_state != DR_STATE_PARTIAL) && - (DR_DEVS_ATTACHED(bp) != - DR_DEVS_PRESENT(bp))) { + (DR_DEVS_ATTACHED(bp) != + DR_DEVS_PRESENT(bp))) { /* * Some devices remain attached. */ @@ -2248,7 +2231,7 @@ dr_dev_status(dr_handle_t *hp) if (ncm > 1) sz32 += sizeof (sbd_dev_stat32_t) * (ncm - 1); pnstat = (pbsz - sizeof (sbd_stat32_t))/ - sizeof (sbd_dev_stat32_t); + sizeof (sbd_dev_stat32_t); } sz += sz32; @@ -2489,7 +2472,7 @@ dr_get_ncm(dr_handle_t *hp) devset = DR_DEVS_PRESENT(hp->h_bd); if (hp->h_sbdcmd.cmd_cm.c_id.c_type != SBD_COMP_NONE) devset &= DEVSET(hp->h_sbdcmd.cmd_cm.c_id.c_type, - DEVSET_ANYUNIT); + DEVSET_ANYUNIT); /* * Handle CPUs first to deal with possible CMP @@ -2597,7 +2580,7 @@ dr_dev2devset(sbd_comp_id_t *cid) devset = DEVSET(SBD_COMP_CPU, DEVSET_ANYUNIT); devset |= DEVSET(SBD_COMP_MEM, DEVSET_ANYUNIT); devset |= DEVSET(SBD_COMP_IO, DEVSET_ANYUNIT); - PR_ALL("%s: COMP_NONE devset = 0x%x\n", f, devset); + PR_ALL("%s: COMP_NONE devset = 0x%lx\n", f, devset); break; case SBD_COMP_CPU: @@ -2618,7 +2601,7 @@ dr_dev2devset(sbd_comp_id_t *cid) devset = DEVSET(SBD_COMP_CMP, unit); } - PR_ALL("%s: CPU devset = 0x%x\n", f, devset); + PR_ALL("%s: CPU devset = 0x%lx\n", f, devset); break; case SBD_COMP_MEM: @@ -2635,7 +2618,7 @@ dr_dev2devset(sbd_comp_id_t *cid) } else devset = DEVSET(cid->c_type, unit); - PR_ALL("%s: MEM devset = 0x%x\n", f, devset); + PR_ALL("%s: MEM devset = 0x%lx\n", f, devset); break; case SBD_COMP_IO: @@ -2647,7 +2630,7 @@ dr_dev2devset(sbd_comp_id_t *cid) } else devset = DEVSET(cid->c_type, unit); - PR_ALL("%s: IO devset = 0x%x\n", f, devset); + PR_ALL("%s: IO devset = 0x%lx\n", f, devset); break; default: @@ -2879,9 +2862,9 @@ dr_dev_found(void *data, const char *name, int unum, drmachid_t id) /* render dynamic attachment point path of this unit */ (void) snprintf(dp->du_common.sbdev_path, - sizeof (dp->du_common.sbdev_path), - (nt == SBD_COMP_MEM ? "%s::%s" : "%s::%s%d"), - bp->b_path, name, DR_UNUM2SBD_UNUM(unum)); + sizeof (dp->du_common.sbdev_path), + (nt == SBD_COMP_MEM ? "%s::%s" : "%s::%s%d"), + bp->b_path, name, DR_UNUM2SBD_UNUM(unum, nt)); dp->du_common.sbdev_id = id; DR_DEV_SET_PRESENT(&dp->du_common); @@ -3011,7 +2994,7 @@ dr_check_unit_attached(dr_common_unit_t *cp) memlist_read_lock(); for (ml = phys_install; ml; ml = ml->next) if ((endpa <= ml->address) || - (basepa >= (ml->address + ml->size))) + (basepa >= (ml->address + ml->size))) continue; else break; @@ -3208,7 +3191,7 @@ dr_board_discovery(dr_board_t *bp) * information necessary to re-configure the device * back online, e.g. memlist. */ - PR_ALL("%s: some devices LOST (0x%x)...\n", f, devs_lost); + PR_ALL("%s: some devices LOST (0x%lx)...\n", f, devs_lost); for (ut = 0; ut < MAX_CPU_UNITS_PER_BOARD; ut++) { if (!DEVSET_IN_SET(devs_lost, SBD_COMP_CPU, ut)) @@ -3256,13 +3239,13 @@ dr_board_init(dr_board_t *bp, dev_info_t *dip, int bd) bp->b_dip = dip; bp->b_dev[NIX(SBD_COMP_CPU)] = GETSTRUCT(dr_dev_unit_t, - MAX_CPU_UNITS_PER_BOARD); + MAX_CPU_UNITS_PER_BOARD); bp->b_dev[NIX(SBD_COMP_MEM)] = GETSTRUCT(dr_dev_unit_t, - MAX_MEM_UNITS_PER_BOARD); + MAX_MEM_UNITS_PER_BOARD); bp->b_dev[NIX(SBD_COMP_IO)] = GETSTRUCT(dr_dev_unit_t, - MAX_IO_UNITS_PER_BOARD); + MAX_IO_UNITS_PER_BOARD); /* * Initialize the devlists @@ -3328,19 +3311,19 @@ dr_board_destroy(dr_board_t *bp) * Free up MEM unit structs. */ FREESTRUCT(bp->b_dev[NIX(SBD_COMP_MEM)], - dr_dev_unit_t, MAX_MEM_UNITS_PER_BOARD); + dr_dev_unit_t, MAX_MEM_UNITS_PER_BOARD); bp->b_dev[NIX(SBD_COMP_MEM)] = NULL; /* * Free up CPU unit structs. */ FREESTRUCT(bp->b_dev[NIX(SBD_COMP_CPU)], - dr_dev_unit_t, MAX_CPU_UNITS_PER_BOARD); + dr_dev_unit_t, MAX_CPU_UNITS_PER_BOARD); bp->b_dev[NIX(SBD_COMP_CPU)] = NULL; /* * Free up IO unit structs. */ FREESTRUCT(bp->b_dev[NIX(SBD_COMP_IO)], - dr_dev_unit_t, MAX_IO_UNITS_PER_BOARD); + dr_dev_unit_t, MAX_IO_UNITS_PER_BOARD); bp->b_dev[NIX(SBD_COMP_IO)] = NULL; mutex_destroy(&bp->b_lock); diff --git a/usr/src/uts/sun4u/ngdr/io/dr_cpu.c b/usr/src/uts/sun4u/ngdr/io/dr_cpu.c index d9f1f17247..0c6b037777 100644 --- a/usr/src/uts/sun4u/ngdr/io/dr_cpu.c +++ b/usr/src/uts/sun4u/ngdr/io/dr_cpu.c @@ -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,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -64,7 +63,7 @@ #include <sys/mmu.h> #include <sys/x_call.h> #include <sys/cpu_module.h> -#include <sys/cheetahregs.h> +#include <sys/cpu_impl.h> #include <sys/autoconf.h> #include <sys/cmn_err.h> @@ -159,8 +158,13 @@ dr_cpu_set_prop(dr_cpu_unit_t *cp) } /* read in the CPU speed */ - clock_freq = (unsigned int)ddi_prop_get_int(DDI_DEV_T_ANY, dip, - DDI_PROP_DONTPASS, "clock-frequency", 0); + + /* + * If the property is not found in the CPU node, it has to be + * kept in the core or cmp node so we just keep looking. + */ + clock_freq = (unsigned int)ddi_prop_get_int(DDI_DEV_T_ANY, + dip, 0, "clock-frequency", 0); ASSERT(clock_freq != 0); @@ -168,6 +172,7 @@ dr_cpu_set_prop(dr_cpu_unit_t *cp) * The ecache property string is not the same * for all CPU implementations. */ + switch (cp->sbc_cpu_impl) { case BLACKBIRD_IMPL: case CHEETAH_IMPL: @@ -175,6 +180,7 @@ dr_cpu_set_prop(dr_cpu_unit_t *cp) cache_str = "ecache-size"; break; case JAGUAR_IMPL: + case OLYMPUS_C_IMPL: cache_str = "l2-cache-size"; break; case PANTHER_IMPL: @@ -189,8 +195,14 @@ dr_cpu_set_prop(dr_cpu_unit_t *cp) if (cache_str != NULL) { /* read in the ecache size */ - ecache_size = ddi_prop_get_int(DDI_DEV_T_ANY, dip, - DDI_PROP_DONTPASS, cache_str, 0); + /* + * If the property is not found in the CPU node, + * it has to be kept in the core or cmp node so + * we just keep looking. + */ + + ecache_size = ddi_prop_get_int(DDI_DEV_T_ANY, + dip, 0, cache_str, 0); } ASSERT(ecache_size != 0); @@ -280,7 +292,8 @@ dr_pre_attach_cpu(dr_handle_t *hp, dr_common_unit_t **devlist, int devnum) * one message should be printed, no matter how * many cores are actually present. */ - curr_cpu = DR_UNUM2SBD_UNUM(up->sbc_cm.sbdev_unum); + curr_cpu = DR_UNUM2SBD_UNUM(up->sbc_cm.sbdev_unum, + SBD_COMP_CPU); if (curr_cpu >= next_cpu) { cmn_err(CE_CONT, "OS configure %s", up->sbc_cm.sbdev_path); @@ -331,13 +344,12 @@ dr_attach_cpu(dr_handle_t *hp, dr_common_unit_t *cp) if (err) { DRERR_SET_C(&cp->sbdev_error, &err); - err = drmach_unconfigure(cp->sbdev_id, DRMACH_DEVI_REMOVE); + err = drmach_unconfigure(cp->sbdev_id, DEVI_BRANCH_DESTROY); if (err) sbd_err_clear(&err); } else if ((rv = cpu_configure(cpuid)) != 0) { dr_dev_err(CE_WARN, cp, dr_errno2ecode(rv)); - err = drmach_unconfigure(cp->sbdev_id, - DRMACH_DEVI_REMOVE); + err = drmach_unconfigure(cp->sbdev_id, DEVI_BRANCH_DESTROY); if (err) sbd_err_clear(&err); } @@ -421,7 +433,7 @@ dr_pre_release_cpu(dr_handle_t *hp, dr_common_unit_t **devlist, int devnum) /* allocate status struct storage. */ ds = (sbd_dev_stat_t *) kmem_zalloc(sizeof (sbd_dev_stat_t) * - MAX_CPU_UNITS_PER_BOARD, KM_SLEEP); + MAX_CPU_UNITS_PER_BOARD, KM_SLEEP); cix = dr_cpu_status(hp, devset, ds); @@ -473,7 +485,7 @@ dr_pre_release_cpu(dr_handle_t *hp, dr_common_unit_t **devlist, int devnum) if (disp_bound_threads(cp, 0)) { cmn_err(CE_WARN, "%s: thread(s) " "bound to cpu %d", - f, cp->cpu_id); + f, cp->cpu_id); } rv = -1; break; @@ -553,7 +565,8 @@ dr_pre_detach_cpu(dr_handle_t *hp, dr_common_unit_t **devlist, int devnum) * one message should be printed, no matter how * many cores are actually present. */ - curr_cpu = DR_UNUM2SBD_UNUM(up->sbc_cm.sbdev_unum); + curr_cpu = DR_UNUM2SBD_UNUM(up->sbc_cm.sbdev_unum, + SBD_COMP_CPU); if (curr_cpu >= next_cpu) { cmn_err(CE_CONT, "OS unconfigure %s\n", up->sbc_cm.sbdev_path); @@ -581,7 +594,7 @@ dr_pre_detach_cpu(dr_handle_t *hp, dr_common_unit_t **devlist, int devnum) if (disp_bound_threads(cp, 0)) { cmn_err(CE_WARN, "%s: thread(s) " "bound to cpu %d", - f, cp->cpu_id); + f, cp->cpu_id); } goto err; } @@ -618,7 +631,7 @@ dr_detach_cpu(dr_handle_t *hp, dr_common_unit_t *cp) } else if ((rv = cpu_unconfigure(cpuid)) != 0) { dr_dev_err(CE_IGNORE, cp, dr_errno2ecode(rv)); } else { - err = drmach_unconfigure(cp->sbdev_id, DRMACH_DEVI_REMOVE); + err = drmach_unconfigure(cp->sbdev_id, DEVI_BRANCH_DESTROY); if (err) { DRERR_SET_C(&cp->sbdev_error, &err); } @@ -696,7 +709,7 @@ dr_fill_cmp_stat(sbd_cpu_stat_t *csp, int ncores, int impl, sbd_cmp_stat_t *psp) * on the data for the first core. */ psp->ps_type = SBD_COMP_CMP; - psp->ps_unit = DR_UNUM2SBD_UNUM(csp->cs_unit); + psp->ps_unit = DR_UNUM2SBD_UNUM(csp->cs_unit, SBD_COMP_CMP); strncpy(psp->ps_name, csp->cs_name, sizeof (psp->ps_name)); psp->ps_cond = csp->cs_cond; psp->ps_busy = csp->cs_busy; @@ -721,7 +734,8 @@ dr_fill_cmp_stat(sbd_cpu_stat_t *csp, int ncores, int impl, sbd_cmp_stat_t *psp) * The following properties should be the same * for all the cores of the CMP. */ - ASSERT(psp->ps_unit == DR_UNUM2SBD_UNUM(csp[core].cs_unit)); + ASSERT(psp->ps_unit == DR_UNUM2SBD_UNUM( + csp[core].cs_unit, SBD_COMP_CMP)); ASSERT(psp->ps_speed == csp[core].cs_speed); psp->ps_cpuid[core] = csp[core].cs_cpuid; @@ -761,6 +775,7 @@ dr_cpu_status(dr_handle_t *hp, dr_devset_t devset, sbd_dev_stat_t *dsp) int ncpu; dr_board_t *bp; sbd_cpu_stat_t cstat[MAX_CORES_PER_CMP]; + int impl; bp = hp->h_bd; ncpu = 0; @@ -810,6 +825,11 @@ dr_cpu_status(dr_handle_t *hp, dr_devset_t devset, sbd_dev_stat_t *dsp) } dr_fill_cpu_stat(cp, &pstat, &cstat[ncores++]); + /* + * We should set impl here because the last core + * found might be EMPTY or not present. + */ + impl = cp->sbc_cpu_impl; } if (ncores == 0) { @@ -825,9 +845,10 @@ dr_cpu_status(dr_handle_t *hp, dr_devset_t devset, sbd_dev_stat_t *dsp) * found, assuming that all cores will have the * same implementation. */ - if (CPU_IMPL_IS_CMP(cp->sbc_cpu_impl)) { + + if (CPU_IMPL_IS_CMP(impl)) { psp = (sbd_cmp_stat_t *)dsp; - dr_fill_cmp_stat(cstat, ncores, cp->sbc_cpu_impl, psp); + dr_fill_cmp_stat(cstat, ncores, impl, psp); } else { ASSERT(ncores == 1); bcopy(cstat, dsp, sizeof (sbd_cpu_stat_t)); @@ -888,8 +909,8 @@ dr_cancel_cpu(dr_cpu_unit_t *up) if (cpu_flagged_nointr(up->sbc_cpu_flags)) { if (cpu_intr_disable(cp) != 0) { cmn_err(CE_WARN, "%s: failed to " - "disable interrupts on cpu %d", - f, up->sbc_cpu_id); + "disable interrupts on cpu %d", + f, up->sbc_cpu_id); } } } diff --git a/usr/src/uts/sun4u/ngdr/io/dr_io.c b/usr/src/uts/sun4u/ngdr/io/dr_io.c index fa88a8e690..ac36e971d0 100644 --- a/usr/src/uts/sun4u/ngdr/io/dr_io.c +++ b/usr/src/uts/sun4u/ngdr/io/dr_io.c @@ -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,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -117,8 +116,7 @@ dr_detach_io(dr_handle_t *hp, dr_common_unit_t *cp) err = drmach_unconfigure(cp->sbdev_id, 0); if (!err) - err = drmach_unconfigure(cp->sbdev_id, - DRMACH_DEVI_REMOVE); + err = drmach_unconfigure(cp->sbdev_id, DEVI_BRANCH_DESTROY); if (!err) err = drmach_io_post_release(cp->sbdev_id); diff --git a/usr/src/uts/sun4u/ngdr/io/dr_mem.c b/usr/src/uts/sun4u/ngdr/io/dr_mem.c index f9e5c9e0ea..7686bbab19 100644 --- a/usr/src/uts/sun4u/ngdr/io/dr_mem.c +++ b/usr/src/uts/sun4u/ngdr/io/dr_mem.c @@ -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,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -72,13 +71,8 @@ static int dr_select_mem_target(dr_handle_t *hp, dr_mem_unit_t *mp, struct memlist *ml); static void dr_init_mem_unit_data(dr_mem_unit_t *mp); -static struct memlist *memlist_dup(struct memlist *); static int memlist_canfit(struct memlist *s_mlist, struct memlist *t_mlist); -static struct memlist *memlist_del_span(struct memlist *mlist, - uint64_t base, uint64_t len); -static struct memlist *memlist_cat_span(struct memlist *mlist, - uint64_t base, uint64_t len); /* * dr_mem_unit_t.sbm_flags @@ -355,7 +349,8 @@ dr_attach_mem(dr_handle_t *hp, dr_common_unit_t *cp) /* back out if configure failed */ if (mp->sbm_cm.sbdev_error != NULL) { dr_lock_status(hp->h_bd); - err = drmach_unconfigure(cp->sbdev_id, DRMACH_DEVI_REMOVE); + err = drmach_unconfigure(cp->sbdev_id, + DEVI_BRANCH_DESTROY); if (err) sbd_err_clear(&err); dr_unlock_status(hp->h_bd); @@ -628,7 +623,7 @@ dr_detach_mem(dr_handle_t *hp, dr_common_unit_t *cp) dr_lock_status(hp->h_bd); err = drmach_unconfigure(s_mp->sbm_cm.sbdev_id, - DRMACH_DEVI_REMOVE); + DEVI_BRANCH_DESTROY); dr_unlock_status(hp->h_bd); if (err) sbd_err_clear(&err); @@ -663,7 +658,8 @@ dr_del_span_query(pfn_t base, pgcnt_t npages, memquery_t *mp) again: for (ml = mlist; ml; ml = ml->next) { if ((ml->address & sm) != sa) { - mlist = memlist_del_span(mlist, ml->address, ml->size); + mlist = memlist_del_span(mlist, + ml->address, ml->size); goto again; } } @@ -2669,28 +2665,6 @@ dr_select_mem_target(dr_handle_t *hp, /* * Memlist support. */ -static struct memlist * -memlist_dup(struct memlist *mlist) -{ - struct memlist *hl = NULL, *tl, **mlp; - - if (mlist == NULL) - return (NULL); - - mlp = &hl; - tl = *mlp; - for (; mlist; mlist = mlist->next) { - *mlp = GETSTRUCT(struct memlist, 1); - (*mlp)->address = mlist->address; - (*mlp)->size = mlist->size; - (*mlp)->prev = tl; - tl = *mlp; - mlp = &((*mlp)->next); - } - *mlp = NULL; - - return (hl); -} /* * Determine whether the source memlist (s_mlist) will @@ -2754,117 +2728,3 @@ memlist_canfit(struct memlist *s_mlist, struct memlist *t_mlist) return (rv); } - -static struct memlist * -memlist_del_span(struct memlist *mlist, uint64_t base, uint64_t len) -{ - uint64_t end; - struct memlist *ml, *tl, *nlp; - - if (mlist == NULL) - return (NULL); - - end = base + len; - if ((end <= mlist->address) || (base == end)) - return (mlist); - - for (tl = ml = mlist; ml; tl = ml, ml = nlp) { - uint64_t mend; - - nlp = ml->next; - - if (end <= ml->address) - break; - - mend = ml->address + ml->size; - if (base < mend) { - if (base <= ml->address) { - ml->address = end; - if (end >= mend) - ml->size = 0ull; - else - ml->size = mend - ml->address; - } else { - ml->size = base - ml->address; - if (end < mend) { - struct memlist *nl; - /* - * splitting an memlist entry. - */ - nl = GETSTRUCT(struct memlist, 1); - nl->address = end; - nl->size = mend - nl->address; - if ((nl->next = nlp) != NULL) - nlp->prev = nl; - nl->prev = ml; - ml->next = nl; - nlp = nl; - } - } - if (ml->size == 0ull) { - if (ml == mlist) { - if ((mlist = nlp) != NULL) - nlp->prev = NULL; - FREESTRUCT(ml, struct memlist, 1); - if (mlist == NULL) - break; - ml = nlp; - } else { - if ((tl->next = nlp) != NULL) - nlp->prev = tl; - FREESTRUCT(ml, struct memlist, 1); - ml = tl; - } - } - } - } - - return (mlist); -} - -/* - * add span without merging - */ -static struct memlist * -memlist_cat_span(struct memlist *mlist, uint64_t base, uint64_t len) -{ - struct memlist *ml, *tl, *nl; - - if (len == 0ull) - return (NULL); - - if (mlist == NULL) { - mlist = GETSTRUCT(struct memlist, 1); - mlist->address = base; - mlist->size = len; - mlist->next = mlist->prev = NULL; - - return (mlist); - } - - for (tl = ml = mlist; ml; tl = ml, ml = ml->next) { - if (base < ml->address) { - nl = GETSTRUCT(struct memlist, 1); - nl->address = base; - nl->size = len; - nl->next = ml; - if ((nl->prev = ml->prev) != NULL) - nl->prev->next = nl; - ml->prev = nl; - if (mlist == ml) - mlist = nl; - break; - } - } - - if (ml == NULL) { - nl = GETSTRUCT(struct memlist, 1); - nl->address = base; - nl->size = len; - nl->next = NULL; - nl->prev = tl; - tl->next = nl; - } - - return (mlist); -} diff --git a/usr/src/uts/sun4u/ngdr/io/dr_util.c b/usr/src/uts/sun4u/ngdr/io/dr_util.c index 7a17df1190..eaf8c95178 100644 --- a/usr/src/uts/sun4u/ngdr/io/dr_util.c +++ b/usr/src/uts/sun4u/ngdr/io/dr_util.c @@ -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,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -174,7 +173,7 @@ drerr_set_c(int log, sbd_error_t **ep, int e_code, char *fmt, ...) * Memlist support. */ void -memlist_delete(struct memlist *mlist) +dr_memlist_delete(struct memlist *mlist) { register struct memlist *ml; @@ -185,7 +184,7 @@ memlist_delete(struct memlist *mlist) } int -memlist_intersect(struct memlist *al, struct memlist *bl) +dr_memlist_intersect(struct memlist *al, struct memlist *bl) { uint64_t astart, aend, bstart, bend; @@ -220,7 +219,7 @@ memlist_intersect(struct memlist *al, struct memlist *bl) } void -memlist_coalesce(struct memlist *mlist) +dr_memlist_coalesce(struct memlist *mlist) { uint64_t end, nend; @@ -260,3 +259,199 @@ memlist_dump(struct memlist *mlist) printf("memlist> 0x%lx, 0x%lx\n", ml->address, ml->size); } #endif + +struct memlist * +dr_memlist_dup(struct memlist *mlist) +{ + struct memlist *hl = NULL, *tl, **mlp; + + if (mlist == NULL) + return (NULL); + + mlp = &hl; + tl = *mlp; + for (; mlist; mlist = mlist->next) { + *mlp = GETSTRUCT(struct memlist, 1); + (*mlp)->address = mlist->address; + (*mlp)->size = mlist->size; + (*mlp)->prev = tl; + tl = *mlp; + mlp = &((*mlp)->next); + } + *mlp = NULL; + + return (hl); +} + +struct memlist * +dr_memlist_add_span(struct memlist *mlist, uint64_t base, uint64_t len) +{ + struct memlist *ml, *tl, *nl; + + if (len == 0ull) + return (NULL); + + if (mlist == NULL) { + mlist = GETSTRUCT(struct memlist, 1); + mlist->address = base; + mlist->size = len; + mlist->next = mlist->prev = NULL; + + return (mlist); + } + + for (tl = ml = mlist; ml; tl = ml, ml = ml->next) { + if (base < ml->address) { + if ((base + len) < ml->address) { + nl = GETSTRUCT(struct memlist, 1); + nl->address = base; + nl->size = len; + nl->next = ml; + if ((nl->prev = ml->prev) != NULL) + nl->prev->next = nl; + ml->prev = nl; + if (mlist == ml) + mlist = nl; + } else { + ml->size = MAX((base + len), + (ml->address + ml->size)) - + base; + ml->address = base; + } + break; + + } else if (base <= (ml->address + ml->size)) { + ml->size = MAX((base + len), + (ml->address + ml->size)) - + MIN(ml->address, base); + ml->address = MIN(ml->address, base); + break; + } + } + if (ml == NULL) { + nl = GETSTRUCT(struct memlist, 1); + nl->address = base; + nl->size = len; + nl->next = NULL; + nl->prev = tl; + tl->next = nl; + } + + dr_memlist_coalesce(mlist); + + return (mlist); +} + +struct memlist * +dr_memlist_del_span(struct memlist *mlist, uint64_t base, uint64_t len) +{ + uint64_t end; + struct memlist *ml, *tl, *nlp; + + if (mlist == NULL) + return (NULL); + + end = base + len; + if ((end <= mlist->address) || (base == end)) + return (mlist); + + for (tl = ml = mlist; ml; tl = ml, ml = nlp) { + uint64_t mend; + + nlp = ml->next; + + if (end <= ml->address) + break; + + mend = ml->address + ml->size; + if (base < mend) { + if (base <= ml->address) { + ml->address = end; + if (end >= mend) + ml->size = 0ull; + else + ml->size = mend - ml->address; + } else { + ml->size = base - ml->address; + if (end < mend) { + struct memlist *nl; + /* + * splitting an memlist entry. + */ + nl = GETSTRUCT(struct memlist, 1); + nl->address = end; + nl->size = mend - nl->address; + if ((nl->next = nlp) != NULL) + nlp->prev = nl; + nl->prev = ml; + ml->next = nl; + nlp = nl; + } + } + if (ml->size == 0ull) { + if (ml == mlist) { + if ((mlist = nlp) != NULL) + nlp->prev = NULL; + FREESTRUCT(ml, struct memlist, 1); + if (mlist == NULL) + break; + ml = nlp; + } else { + if ((tl->next = nlp) != NULL) + nlp->prev = tl; + FREESTRUCT(ml, struct memlist, 1); + ml = tl; + } + } + } + } + + return (mlist); +} + +/* + * add span without merging + */ +struct memlist * +dr_memlist_cat_span(struct memlist *mlist, uint64_t base, uint64_t len) +{ + struct memlist *ml, *tl, *nl; + + if (len == 0ull) + return (NULL); + + if (mlist == NULL) { + mlist = GETSTRUCT(struct memlist, 1); + mlist->address = base; + mlist->size = len; + mlist->next = mlist->prev = NULL; + + return (mlist); + } + + for (tl = ml = mlist; ml; tl = ml, ml = ml->next) { + if (base < ml->address) { + nl = GETSTRUCT(struct memlist, 1); + nl->address = base; + nl->size = len; + nl->next = ml; + if ((nl->prev = ml->prev) != NULL) + nl->prev->next = nl; + ml->prev = nl; + if (mlist == ml) + mlist = nl; + break; + } + } + + if (ml == NULL) { + nl = GETSTRUCT(struct memlist, 1); + nl->address = base; + nl->size = len; + nl->next = NULL; + nl->prev = tl; + tl->next = nl; + } + + return (mlist); +} diff --git a/usr/src/uts/sun4u/ngdr/sys/dr.h b/usr/src/uts/sun4u/ngdr/sys/dr.h index f4942b6b55..c34c744120 100644 --- a/usr/src/uts/sun4u/ngdr/sys/dr.h +++ b/usr/src/uts/sun4u/ngdr/sys/dr.h @@ -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,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -48,12 +47,24 @@ extern "C" { #define DR_MAXNUM_NT 3 /* used to map sbd_comp_type_t to array index */ -#define NIX(t) \ - (((t) == SBD_COMP_CPU) ? 0 : \ - ((t) == SBD_COMP_MEM) ? 1 : \ - ((t) == SBD_COMP_IO) ? 2 : \ +#define NIX(t) \ + (((t) == SBD_COMP_CPU) ? 0 : \ + ((t) == SBD_COMP_MEM) ? 1 : \ + ((t) == SBD_COMP_IO) ? 2 : \ ((t) == SBD_COMP_CMP) ? 0 : DR_MAXNUM_NT) +#define BIX(t) \ + (((t) == SBD_COMP_CPU) ? 0 : \ + ((t) == SBD_COMP_MEM) ? 32 : \ + ((t) == SBD_COMP_IO) ? 40 : \ + ((t) == SBD_COMP_CMP) ? 0 : 0) + +#define NMASK(t) \ + (((t) == SBD_COMP_CPU) ? ((dr_devset_t)0xffffffff) : \ + ((t) == SBD_COMP_MEM) ? ((dr_devset_t)0x1) : \ + ((t) == SBD_COMP_IO) ? ((dr_devset_t)0x1ff) : \ + ((t) == SBD_COMP_CMP) ? ((dr_devset_t)0xffffffff) : 0) + /* * helper macros for constructing and reporting internal error messages. * NOTE: each module which uses one or more this these macros is expected @@ -84,22 +95,23 @@ extern "C" { /* * Format of dr_devset_t bit masks: * - * 32 16 8 0 - * |....|....|....|IIII|....|...M|CCCC|CCCC| + * 64 48 40 32 24 16 8 0 + * |....|...I|IIII|IIII|....|...M|CCCC|CCCC|CCCC|CCCC|CCCC|CCCC|CCCC|CCCC| * * 1 = indicates respective component present/attached. * I = I/O, M = Memory, C = CPU. */ -#define DEVSET_ANYUNIT (-1) -#define _NT2DEVPOS(t, u) ((NIX(t) << 3) + (u)) -#define _DEVSET_MASK 0x000f01ff -#define _CMP_DEVSET_MASK 0x11 +#define _NT2DEVPOS(t, u) (BIX(t) + (u)) +#define _DEVSET_MASK ((dr_devset_t)0x1ff01ffffffff) +#define _CMP_DEVSET_MASK ((dr_devset_t)0x11111111) +#define DEVSET_ONEUNIT ((dr_devset_t)1) +#define DEVSET_ANYUNIT (dr_devset_t)(-1) #define DEVSET(t, u) \ (((u) == DEVSET_ANYUNIT) ? \ - (dr_devset_t)((0xff << _NT2DEVPOS((t), 0)) & _DEVSET_MASK) : \ + ((NMASK(t) << _NT2DEVPOS((t), 0)) & _DEVSET_MASK) : \ ((t) == SBD_COMP_CMP) ? \ - (dr_devset_t)(_CMP_DEVSET_MASK << _NT2DEVPOS((t), (u))) : \ - (dr_devset_t)(1 << _NT2DEVPOS((t), (u)))) + (_CMP_DEVSET_MASK << _NT2DEVPOS((t), (u))) : \ + (DEVSET_ONEUNIT << _NT2DEVPOS((t), (u)))) #define DEVSET_IN_SET(ds, t, u) (((ds) & DEVSET((t), (u))) != 0) #define DEVSET_ADD(ds, t, u) ((ds) |= DEVSET((t), (u))) @@ -175,7 +187,17 @@ extern "C" { * CMP Specific Helpers */ #define DR_CMP_CORE_UNUM(cmp, core) (cmp + (core * 4)) -#define DR_UNUM2SBD_UNUM(unum) (unum & 0x3) +/* + * DR_UNUM2SBD_UNUM should be set to (unum & (max #of CMP on board - 1)) + * for all the platforms. So far, all sun4u platforms supported have + * the same limit so 0x3 works. One day we might have to make this + * a platform specific macro. + */ + +#define DR_UNUM2SBD_UNUM(n, d) ((d == SBD_COMP_IO) ? (n & 0xf) : \ + (d == SBD_COMP_CPU) ? (n & 0x3) : \ + (d == SBD_COMP_CMP) ? (n & 0x3) : \ + (n)) /* * Some stuff to assist in debug. @@ -213,7 +235,7 @@ extern uint_t dr_debug; #define DR_BSLOCK 0x01 /* for blocking status (protected by b_slock) */ typedef const char *fn_t; -typedef uint32_t dr_devset_t; /* TODO: fix limitation */ +typedef uint64_t dr_devset_t; /* TODO: fix limitation */ /* * Unsafe devices based on dr.conf prop "unsupported-io-drivers" diff --git a/usr/src/uts/sun4u/ngdr/sys/dr_util.h b/usr/src/uts/sun4u/ngdr/sys/dr_util.h index c23dd00a2d..69b0bbd84c 100644 --- a/usr/src/uts/sun4u/ngdr/sys/dr_util.h +++ b/usr/src/uts/sun4u/ngdr/sys/dr_util.h @@ -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) 2000 by Sun Microsystems, Inc. - * All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. */ #ifndef _SYS_DR_UTIL_H_ @@ -69,11 +68,32 @@ extern sbd_error_t *drerr_new_v(int e_code, char *fmt, va_list args); extern void drerr_set_c(int log, sbd_error_t **ep, int e_code, char *fmt, ...); -extern void memlist_delete(struct memlist *mlist); +extern void dr_memlist_delete(struct memlist *mlist); extern void memlist_dump(struct memlist *mlist); -extern int memlist_intersect(struct memlist *al, +extern int dr_memlist_intersect(struct memlist *al, struct memlist *bl); -extern void memlist_coalesce(struct memlist *mlist); +extern void dr_memlist_coalesce(struct memlist *mlist); +extern struct memlist *dr_memlist_dup(struct memlist *mlist); +extern struct memlist *dr_memlist_add_span(struct memlist *mlist, + uint64_t base, uint64_t len); +extern struct memlist *dr_memlist_del_span(struct memlist *mlist, + uint64_t base, uint64_t len); +extern struct memlist *dr_memlist_cat_span(struct memlist *mlist, + uint64_t base, uint64_t len); + +/* + * These are all utilities internal for DR. There are + * similar functions in common/os which have similar names. + * We rename them to make sure there is no name space + * conflict. + */ +#define memlist_delete dr_memlist_delete +#define memlist_intersect dr_memlist_intersect +#define memlist_coalesce dr_memlist_coalesce +#define memlist_dup dr_memlist_dup +#define memlist_add_span dr_memlist_add_span +#define memlist_del_span dr_memlist_del_span +#define memlist_cat_span dr_memlist_cat_span #ifdef __cplusplus } diff --git a/usr/src/uts/sun4u/opl/Makefile b/usr/src/uts/sun4u/opl/Makefile new file mode 100644 index 0000000000..dc18c8ec61 --- /dev/null +++ b/usr/src/uts/sun4u/opl/Makefile @@ -0,0 +1,147 @@ +# +# 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. +# +# ident "%Z%%M% %I% %E% SMI" +# +# This makefile drives the production of the sun4u opl platform +# module. +# +# sun4u opl implementation architecture dependent +# +# uts/sun4u/opl/Makefile + +# +# Path to the base of the uts directory tree (usually /usr/src/uts). +# +UTSBASE = ../.. + +# +# Include common rules. +# +include $(UTSBASE)/sun4u/opl/Makefile.opl + +def := TARGET= def +all := TARGET= all +install := TARGET= install +install_h := TARGET= install_h +clean := TARGET= clean +clobber := TARGET= clobber +lint := TARGET= lint +lintlib := TARGET= lintlib +modlist := TARGET= modlist +modlist := NO_STATE= -K $$MODSTATE$$$$ +modlintlib := TARGET= modlintlib +clean.lint := TARGET= clean.lint +check := TARGET= check + +# +# Default build targets. +# +.KEEP_STATE: + +def all clean clobber clean.lint: genassym unix .WAIT \ + $(OPL_CPU_KMODS) $(OPL_KMODS) + +modlist: unix $(OPL_CPU_KMODS) $(OPL_KMODS) + +lintlib: unix + +modlintlib: $(OPL_KMODS) + +IMPLEMENTED_PLATFORM = SUNW,SPARC-Enterprise +LINKED_PLATFORMS = FJSV,SPARC-Enterprise +# temporary link to the development platform name - remove before ON putback! +LINKED_PLATFORMS += SUNW,OPL-Enterprise + +# EXPORT DELETE START +# +# aes256 is delivered in the SUNWcryr package which is removed from +# the EXPORT_SRC build. +# +OPL_CRYPTO_LINKS += aes256 +# EXPORT DELETE END + +install: $(ROOT_OPL_DIR) $(USR_OPL_DIR) \ + $(USR_OPL_INC_DIR) \ + $(USR_OPL_SBIN_DIR) \ + $(USR_OPL_SBIN_EEPROM) \ + $(USR_OPL_SBIN_PRTDIAG) \ + $(USR_OPL_SBIN_TRAPSTAT) \ + $(USR_OPL_SBIN_FRUADM) \ + $(USR_OPL_LIB_DIR) \ + $(LINKED_PLATFORMS:%=$(USR_PLAT_DIR)/%) \ + $(LINKED_PLATFORMS:%=$(ROOT_PLAT_DIR)/%) \ + $(OPL_CRYPTO_LINKS) \ + genassym unix .WAIT $(OPL_CPU_KMODS) $(OPL_KMODS) \ + $(OPLMSU_OPTION) + +genassym unix $(OPL_KMODS) $(OPL_CPU_KMODS): FRC + @cd $@; pwd; $(MAKE) $(TARGET) + +$(OPL_CRYPTO_LINKS): $(ROOT_OPL_CRYPTO_DIR_64) + -$(RM) $(ROOT_OPL_CRYPTO_DIR_64)/$@ + $(SYMLINK) $(ROOT_US3_CRYPTO_LINK)/$@ $(ROOT_OPL_CRYPTO_DIR_64)/$@ + +$(OPLMSU_OPTION): FRC + @cd $@; pwd; $(MAKE) $(TARGET) + +install_h check: FRC + @cd sys; pwd; $(MAKE) $(TARGET) + +lint: modlintlib + + +# +# The 'lint.platmod' target lints the opl platform module against +# the sun4u kernel. This ends up doing all the kernel cross-checks, +# so it takes a couple of minutes. +# Due to the low ROI, it's not run by default, but it's a good +# idea to run this if you change os/opl.c. +# + +LINT_LIBS = $(LINT_LIB) \ + -L$(OPL_LINT_LIB_DIR) \ + -L$(LINT_LIB_DIR) $(LINT_KMODS:%=-l%) \ + -L$(SPARC_LIB_DIR) $(SPARC_LINTS:%=-l%) + +lint.platmod: modlintlib + @-$(ECHO) "\nOpl Platform-dependent module: global crosschecks:" + @-$(LINT) $(LINTFLAGS) $(LINT_LIBS) 2>&1 | $(LGREP.2) + +# EXPORT DELETE START + +EXPORT_SRC: + $(RM) Makefile+ + $(SED) -e "/^# EXPORT DELETE START/,/^# EXPORT DELETE END/d" \ + < Makefile > Makefile+ + $(MV) Makefile+ Makefile + $(CHMOD) 444 Makefile + +# EXPORT DELETE END + +# +# +# Include common targets. +# +include $(UTSBASE)/sun4u/opl/Makefile.targ diff --git a/usr/src/uts/sun4u/opl/Makefile.files b/usr/src/uts/sun4u/opl/Makefile.files new file mode 100644 index 0000000000..397ce7d2e5 --- /dev/null +++ b/usr/src/uts/sun4u/opl/Makefile.files @@ -0,0 +1,56 @@ +# +# 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. +# +# ident "%Z%%M% %I% %E% SMI" +# +# This Makefile defines all file modules for the directory +# uts/sun4u/opl and its children. These are the source files which +# are opl "implementation architecture" dependent. +# +# uts/sun4u/opl/Makefile.files +# + +OPL_OBJS = opl.o +DM2S_OBJS = dm2s.o +OPLKM_OBJS = oplkmdrv.o +PCICMU_OBJS = pcicmu.o pcmu_cb.o pcmu_counters.o pcmu_ecc.o \ + pcmu_ib.o pcmu_intr.o pcmu_pbm.o pcmu_util.o +OPL_PANEL_OBJS = oplpanel.o +SCFD_OBJS = scfconf.o scfdscp.o scfiomp.o scfostoescf.o \ + scfsnap.o scfhandler.o scfkstat.o scfparam.o \ + scftimer.o scfdebug.o scfinit.o scfops.o \ + scfreg.o scftrace.o scf_os_interface.o +DRMACH_OBJS = drmach.o drmach_asm.o dr_util.o drmach_err.o +DRMACH_DEPS += drmach_asm.o +OPLMSU_OBJS = oplmsu.o oplmsu_cmn_func.o oplmsu_ioctl_lrp.o oplmsu_ioctl_uwp.o +MC_OPL_OBJS = mc-opl.o + +# +# Miscellaneous +# +INC_PATH += -I$(UTSBASE)/sun4u/opl + +ASSYM_DEPS += drmach_asm.o + +.KEEP_STATE: diff --git a/usr/src/uts/sun4u/opl/Makefile.opl b/usr/src/uts/sun4u/opl/Makefile.opl new file mode 100644 index 0000000000..053452a150 --- /dev/null +++ b/usr/src/uts/sun4u/opl/Makefile.opl @@ -0,0 +1,150 @@ +# +# 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. +# +# ident "%Z%%M% %I% %E% SMI" +# +# Global definitions for sun4u opl implementation specific modules. +# +# uts/sun4u/opl/Makefile.opl +# + +# +# Define directories. +# +# +# +ROOT_OPL_DIR = $(ROOT_PLAT_DIR)/SUNW,SPARC-Enterprise +ROOT_OPL_MOD_DIR = $(ROOT_OPL_DIR)/kernel +ROOT_OPL_KERN_DIR_32 = $(ROOT_OPL_MOD_DIR) +ROOT_OPL_KERN_DIR_64 = $(ROOT_OPL_MOD_DIR)/$(SUBDIR64) +ROOT_OPL_MISC_DIR_32 = $(ROOT_OPL_MOD_DIR)/misc +ROOT_OPL_MISC_DIR_64 = $(ROOT_OPL_MOD_DIR)/misc/$(SUBDIR64) +ROOT_OPL_DRV_DIR_32 = $(ROOT_OPL_MOD_DIR)/drv +ROOT_OPL_DRV_DIR_64 = $(ROOT_OPL_MOD_DIR)/drv/$(SUBDIR64) +ROOT_OPL_CPU_DIR_32 = $(ROOT_OPL_MOD_DIR)/cpu +ROOT_OPL_CPU_DIR_64 = $(ROOT_OPL_MOD_DIR)/cpu/$(SUBDIR64) +ROOT_OPL_CRYPTO_DIR_32 = $(ROOT_OPL_MOD_DIR)/crypto +ROOT_OPL_CRYPTO_DIR_64 = $(ROOT_OPL_MOD_DIR)/crypto/$(SUBDIR64) + +ROOT_OPL_KERN_DIR = $(ROOT_OPL_KERN_DIR_$(CLASS)) +ROOT_OPL_MISC_DIR = $(ROOT_OPL_MISC_DIR_$(CLASS)) +ROOT_OPL_DRV_DIR = $(ROOT_OPL_DRV_DIR_$(CLASS)) +ROOT_OPL_CPU_DIR = $(ROOT_OPL_CPU_DIR_$(CLASS)) +ROOT_OPL_CRYPTO_DIR = $(ROOT_OPL_CRYPTO_DIR_$(CLASS)) + +ROOT_PLAT_MOD_DIRS += $(ROOT_OPL_MOD_DIR) +ROOT_PLAT_MISC_DIRS_32 += $(ROOT_OPL_MISC_DIR_32) + +USR_OPL_DIR = $(USR_PLAT_DIR)/SUNW,SPARC-Enterprise +USR_OPL_LIB_DIR = $(USR_OPL_DIR)/lib +USR_OPL_SBIN_DIR = $(USR_OPL_DIR)/sbin +USR_OPL_SBIN_EEPROM = $(USR_OPL_SBIN_DIR)/eeprom +USR_OPL_SBIN_PRTDIAG = $(USR_OPL_SBIN_DIR)/prtdiag +USR_OPL_SBIN_TRAPSTAT = $(USR_OPL_SBIN_DIR)/trapstat +USR_OPL_SBIN_FRUADM = $(USR_OPL_SBIN_DIR)/fruadm +USR_OPL_INC_DIR = $(USR_OPL_DIR)/include +USR_OPL_ISYS_DIR = $(USR_OPL_INC_DIR)/sys + +OPL_LINT_LIB_DIR = $(UTSBASE)/$(PLATFORM)/opl/lint-libs/$(OBJS_DIR) +OPLMSU_OPTION = options + +# +# Define modules. +# +OPL_KMODS = platmod +OPL_KMODS += dm2s +OPL_KMODS += oplkmdrv +OPL_KMODS += pcicmu +OPL_KMODS += oplpanel +OPL_KMODS += scfd +OPL_KMODS += dr .WAIT drmach +OPL_KMODS += oplmsu +OPL_KMODS += mc-opl + +# +# CPU modules. +# +OPL_CPU_KMODS += olympus_c + +# Links to OPL crypto modules +# +OPL_CRYPTO_LINKS = aes + +# +# Include the makefiles which define build rule templates, the +# collection of files per module, and a few specific flags. Note +# that order is significant, just as with an include path. The +# first build rule template which matches the files name will be +# used. By including these in order from most machine dependent +# to most machine independent, we allow a machine dependent file +# to be used in preference over a machine independent version +# (Such as a machine specific optimization, which preserves the +# interfaces.) +# +include $(UTSBASE)/sun4u/ngdr/Makefile.files +include $(UTSBASE)/sun4u/opl/Makefile.files + +# +# Include common rules. +# +include $(UTSBASE)/sun4u/Makefile.sun4u + +# +# Everybody needs to know how to build modstubs.o and to locate unix.o +# +UNIX_DIR = $(UTSBASE)/$(PLATFORM)/opl/unix +MODSTUBS_DIR = $(UNIX_DIR) +DSF_DIR = $(UTSBASE)/$(PLATFORM)/opl/genassym +LINTS_DIR = $(OBJS_DIR) +LINT_LIB_DIR = $(UTSBASE)/$(PLATFORM)/opl/lint-libs/$(OBJS_DIR) + +UNIX_O = $(UNIX_DIR)/$(OBJS_DIR)/unix.o + +LINT_LIB = $(LINT_LIB_DIR)/llib-lunix.ln + +# +# Define the actual specific platforms +# +MACHINE_DEFS = -D$(PLATFORM) -D_MACHDEP -DSFMMU -DMP +MACHINE_DEFS += -D_CPU_SIGNATURE + +# +# Maximum CPUID = 01111 11 01 1 = 0x1FB (507) +# Maximum CHIPID = 1 01111 11 00 0 = 0x5F8 (1528) +# +MACHINE_DEFS += -DNCPU=508 +MACHINE_DEFS += -DMAX_CPU_CHIPID=1529 +MACHINE_DEFS += -DMAX_UPA=256 +MACHINE_DEFS += -DIGN_SIZE=8 +MACHINE_DEFS += -DMAX_MEM_NODES=16 +# +# UTSB_PHYS will enable user TSB physical access for TL>0 +# +MACHINE_DEFS += -DUTSB_PHYS +MACHINE_DEFS += -D_OPL +MACHINE_DEFS += -DOLYMPUS_SHARED_FTLB +MACHINE_DEFS += -D_CMP_NO_ERROR_STEERING -D_HW_MEMSCRUB_SUPPORT +MACHINE_DEFS += -DDO_CORELEVEL_LOADBAL + +.KEEP_STATE: diff --git a/usr/src/uts/sun4u/opl/Makefile.rules b/usr/src/uts/sun4u/opl/Makefile.rules new file mode 100644 index 0000000000..a19bf3a80e --- /dev/null +++ b/usr/src/uts/sun4u/opl/Makefile.rules @@ -0,0 +1,147 @@ +# +# 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. +# +# ident "%Z%%M% %I% %E% SMI" +# +# This Makefile defines the build rules for the directory +# uts/sun4u/opl and its children. +# +# uts/sun4u/opl/Makefile.rules +# + +# +# Section 1a: C object build rules +# + +# +# inline support for DR. +# + + +$(OBJS_DIR)/dr_mem.o: $(UTSBASE)/sun4u/opl/io/dr_mem.c + $(COMPILE.c) -o $@ $(UTSBASE)/sun4u/opl/io/dr_mem.c + $(CTFCONVERT_O) + +$(OBJS_DIR)/%.o: $(UTSBASE)/sun4u/ngdr/io/%.c + $(COMPILE.c) -o $@ $< + $(CTFCONVERT_O) + +DR_IO= $(UTSBASE)/sun4u/ngdr/io +SBD_IOCTL= $(UTSBASE)/sun4u/sys/sbd_ioctl.h +SBDGENERR= $(DR_IO)/sbdgenerr + +CLEANFILES += $(SBDGENERR) +CLEANFILES += $(DR_IO)/dr_err.c + +$(DR_IO)/dr_err.c: $(SBDGENERR) $(SBD_IOCTL) + $(RM) $@ + $(SBDGENERR) ESBD < $(SBD_IOCTL) > $(DR_IO)/dr_err.c + +$(SBDGENERR): $(DR_IO)/sbdgenerr.pl + $(RM) $@ + $(CAT) $(DR_IO)/sbdgenerr.pl > $@ + $(CHMOD) +x $@ + +IL_CPP=$(CPP) -P -DINLINE -D_ASM $(AS_INC_PATH) \ + $(CPP_DEFS) $(ALWAYS_DEFS) $(ALL_DEFS) $(CONFIG_DEFS) + +DRMACH_IL= $(OBJS_DIR)/drmach.il +$(OBJS_DIR)/drmach.o := CC_XARCH_32 = -xarch=v8plusa +$(OBJS_DIR)/drmach.o: $(UTSBASE)/sun4u/opl/io/drmach.c $(DRMACH_IL) + $(COMPILE.c) $(DRMACH_IL) -o $@ $(UTSBASE)/sun4u/opl/io/drmach.c + $(CTFCONVERT_O) + +$(OBJS_DIR)/%.o: $(UTSBASE)/sun4u/opl/io/%.c + $(COMPILE.c) -o $@ $< + $(CTFCONVERT_O) + +$(OBJS_DIR)/%.o: $(UTSBASE)/sun4u/opl/io/pcicmu/%.c + $(COMPILE.c) -o $@ $< + $(CTFCONVERT_O) + +$(OBJS_DIR)/%.o: $(UTSBASE)/sun4u/opl/ml/%.s + $(COMPILE.s) -o $@ $< + +$(OBJS_DIR)/%.o: $(UTSBASE)/sun4u/opl/os/%.c + $(COMPILE.c) -o $@ $< + $(CTFCONVERT_O) + +$(OBJS_DIR)/%.o: $(UTSBASE)/sun4u/opl/io/oplpanel/%.c + $(COMPILE.c) -o $@ $< + $(CTFCONVERT_O) + +$(OBJS_DIR)/%.o: $(UTSBASE)/sun4u/opl/io/scfd/%.c + $(COMPILE.c) -o $@ $< + $(CTFCONVERT_O) + +$(OBJS_DIR)/%.o: $(UTSBASE)/sun4u/opl/io/oplmsu/%.c + $(COMPILE.c) -o $@ $< + $(CTFCONVERT_O) + +OPL_IO= $(UTSBASE)/sun4u/opl/io + +CLEANFILES += $(OPL_IO)/drmach_err.c + +$(OPL_IO)/drmach_err.c: $(SBDGENERR) $(SBD_IOCTL) + $(RM) $@ + $(SBDGENERR) EOPL < $(SBD_IOCTL) > $@ + +CLEANFILES += $(DRMACH_IL) + +$(DRMACH_IL): $(UTSBASE)/sun4u/opl/ml/drmach.il.cpp + $(IL_CPP) $(UTSBASE)/sun4u/opl/ml/drmach.il.cpp > $@ + + +# +# Section 1b: Lint object build rules +# + +$(LINTS_DIR)/%.ln: $(UTSBASE)/sun4u/ngdr/io/%.c + @($(LHEAD) $(LINT.c) $< $(LTAIL)) + +$(LINTS_DIR)/dr_mem.ln: $(UTSBASE)/sun4u/opl/io/dr_mem.c + @($(LHEAD) $(LINT.c) $(UTSBASE)/sun4u/opl/io/dr_mem.c $(LTAIL)) + +$(LINTS_DIR)/%.ln: $(UTSBASE)/sun4u/opl/io/%.c + @($(LHEAD) $(LINT.c) $< $(LTAIL)) + +$(LINTS_DIR)/%.ln: $(UTSBASE)/sun4u/opl/io/pcicmu/%.c + @($(LHEAD) $(LINT.c) $< $(LTAIL)) + +$(LINTS_DIR)/%.ln: $(UTSBASE)/sun4u/opl/ml/%.s + @($(LHEAD) $(LINT.s) $< $(LTAIL)) + +$(LINTS_DIR)/%.ln: $(UTSBASE)/sun4u/opl/os/%.c + @($(LHEAD) $(LINT.c) $< $(LTAIL)) + +$(LINTS_DIR)/%.ln: $(UTSBASE)/sun4u/opl/io/oplpanel/%.c + @($(LHEAD) $(LINT.c) $< $(LTAIL)) + +$(LINTS_DIR)/%.ln: $(UTSBASE)/sun4u/opl/io/scfd/%.c + @($(LHEAD) $(LINT.c) $< $(LTAIL)) + +$(LINTS_DIR)/%.ln: $(UTSBASE)/sun4u/opl/io/oplmsu/%.c + @($(LHEAD) $(LINT.c) $< $(LTAIL)) + +.KEEP_STATE: diff --git a/usr/src/uts/sun4u/opl/Makefile.targ b/usr/src/uts/sun4u/opl/Makefile.targ new file mode 100644 index 0000000000..c24a433d05 --- /dev/null +++ b/usr/src/uts/sun4u/opl/Makefile.targ @@ -0,0 +1,116 @@ +# +# 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. +# +# ident "%Z%%M% %I% %E% SMI" +# +# Common targets for sun4u opl implementation specific modules. +# +# uts/sun4u/opl/Makefile.targ +# + +.KEEP_STATE: + +# +# Rules for implementation subdirectories. +# +$(ROOT_OPL_DIR): $(ROOT_PLAT_DIR) + -$(INS.dir.root.sys) + +$(ROOT_OPL_MOD_DIR): $(ROOT_OPL_DIR) + -$(INS.dir.root.sys) + +$(ROOT_OPL_DRV_DIR_32): $(ROOT_OPL_MOD_DIR) + -$(INS.dir.root.sys) + +$(ROOT_OPL_DRV_DIR_64): $(ROOT_OPL_DRV_DIR_32) + -$(INS.dir.root.sys) + +$(ROOT_OPL_CPU_DIR_32): $(ROOT_OPL_MOD_DIR) + -$(INS.dir.root.sys) + +$(ROOT_OPL_CPU_DIR_64): $(ROOT_OPL_CPU_DIR_32) + -$(INS.dir.root.sys) + +$(ROOT_OPL_MISC_DIR_32): $(ROOT_OPL_MOD_DIR) + -$(INS.dir.root.sys) + +$(ROOT_OPL_MISC_DIR_64): $(ROOT_OPL_MISC_DIR_32) + -$(INS.dir.root.sys) + +$(ROOT_OPL_CRYPTO_DIR_32): $(ROOT_OPL_MOD_DIR) + -$(INS.dir.root.sys) + +$(ROOT_OPL_CRYPTO_DIR_64): $(ROOT_OPL_CRYPTO_DIR_32) + -$(INS.dir.root.sys) + +$(USR_OPL_DIR): $(USR_PLAT_DIR) + -$(INS.dir.root.sys) + +$(USR_OPL_INC_DIR): $(USR_OPL_DIR) $(USR_PSM_INCL_DIR) + $(INS.slink4) + +$(USR_OPL_SBIN_DIR): $(USR_OPL_DIR) $(USR_PSM_SBIN_DIR) + $(INS.dir.root.bin) + +$(USR_OPL_SBIN_EEPROM): $(USR_OPL_SBIN_DIR) + $(RM) -r $@; $(SYMLINK) ../../$(PLATFORM)/sbin/eeprom $@ $(CHOWNLINK) $(CHGRPLINK) + +$(USR_OPL_SBIN_PRTDIAG): $(USR_OPL_SBIN_DIR) + $(RM) -r $@; $(SYMLINK) ../../$(PLATFORM)/sbin/prtdiag $@ $(CHOWNLINK) $(CHGRPLINK) + +$(USR_OPL_SBIN_TRAPSTAT): $(USR_OPL_SBIN_DIR) + $(RM) -r $@; $(SYMLINK) ../../$(PLATFORM)/sbin/trapstat $@ $(CHOWNLINK) $(CHGRPLINK) + +$(USR_OPL_SBIN_FRUADM): $(USR_OPL_SBIN_DIR) + $(RM) -r $@; $(SYMLINK) ../../$(PLATFORM)/sbin/fruadm $@ $(CHOWNLINK) $(CHGRPLINK) + +$(LINKED_PLATFORMS:%=$(ROOT_PLAT_DIR)/%): $(ROOT_PLAT_DIR) + $(INS.slink3) + +$(LINKED_PLATFORMS:%=$(USR_PLAT_DIR)/%): $(USR_PLAT_DIR) + $(INS.slink3) + +$(USR_OPL_LIB_DIR): $(USR_OPL_DIR) $(USR_PSM_LIB_DIR) + -$(INS.dir.root.bin) + +$(USR_OPL_ISYS_DIR): $(USR_OPL_INC_DIR) + $(INS.dir.root.bin) + +$(ROOT_OPL_KERN_DIR)/%: $(OBJS_DIR)/% $(ROOT_OPL_KERN_DIR) FRC + $(INS.file) + +$(ROOT_OPL_DRV_DIR)/%: $(OBJS_DIR)/% $(ROOT_OPL_DRV_DIR) FRC + $(INS.file) + +$(ROOT_OPL_CPU_DIR)/%: $(OBJS_DIR)/% $(ROOT_OPL_CPU_DIR) FRC + $(INS.file) + +$(ROOT_OPL_MISC_DIR)/%: $(OBJS_DIR)/% $(ROOT_OPL_MISC_DIR) FRC + $(INS.file) + +# +# Include common targets. +# +include $(UTSBASE)/sun4u/opl/Makefile.rules +include $(UTSBASE)/sun4u/Makefile.targ diff --git a/usr/src/uts/sun4u/opl/dm2s/Makefile b/usr/src/uts/sun4u/opl/dm2s/Makefile new file mode 100644 index 0000000000..f97e0e7e65 --- /dev/null +++ b/usr/src/uts/sun4u/opl/dm2s/Makefile @@ -0,0 +1,105 @@ +# +# 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. +# +# ident "%Z%%M% %I% %E% SMI" +# +# This makefile drives the production of the dm2s driver +# kernel module. +# +# sun4u implementation architecture dependent +# + +# +# Path to the base of the uts directory tree (usually /usr/src/uts). +# +UTSBASE = ../../.. + +# +# Define the module and object file sets. +# + +MODULE = dm2s +OBJECTS = $(DM2S_OBJS:%=$(OBJS_DIR)/%) +LINTS = $(DM2S_OBJS:%.o=$(LINTS_DIR)/%.ln) +ROOTMODULE = $(ROOT_OPL_DRV_DIR)/$(MODULE) +CONF_SRCDIR = $(UTSBASE)/sun4u/opl/io + +# +# Include common rules. +# +include $(UTSBASE)/sun4u/opl/Makefile.opl + +# +# Define targets +# +ALL_TARGET = $(BINARY) $(SRC_CONFFILE) +LINT_TARGET = $(MODULE).lint +INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE) + +# +# Overrides +# +ALL_BUILDS = $(ALL_BUILDSONLY64) +DEF_BUILDS = $(DEF_BUILDSONLY64) +CLEANLINTFILES += $(LINT32_FILES) + +# +# lint pass one enforcement +# +CFLAGS += $(CCVERBOSE) + +# +# Turn on doubleword alignment for 64 bit registers +# +CFLAGS += -dalign + +# +# Dependency +LDFLAGS += -dy -Ndrv/scfd + +# +# 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)/sun4u/opl/Makefile.targ diff --git a/usr/src/uts/sun4u/opl/dr/Makefile b/usr/src/uts/sun4u/opl/dr/Makefile new file mode 100644 index 0000000000..31d5a8388a --- /dev/null +++ b/usr/src/uts/sun4u/opl/dr/Makefile @@ -0,0 +1,92 @@ +# +# 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. +# +# ident "%Z%%M% %I% %E% SMI" +# +# This makefile drives the production of the dr driver module. +# +# sun4u opl implementation architecture dependent +# + +# +# Path to the base of the uts directory tree (usually /usr/src/uts). +# +UTSBASE = ../../.. + +# +# Define the module and object file sets. +# +MODULE = dr +OBJECTS = $(DR_OBJS:%=$(OBJS_DIR)/%) +LINTS = $(DR_OBJS:%.o=$(LINTS_DIR)/%.ln) +ROOTMODULE = $(ROOT_OPL_DRV_DIR)/$(MODULE) +CONF_SRCDIR = $(UTSBASE)/sun4u/opl/io + +# +# Include common rules. +# +include $(UTSBASE)/sun4u/opl/Makefile.opl + +# +# Define targets +# +ALL_TARGET = $(BINARY) $(SRC_CONFFILE) +LINT_TARGET = $(MODULE).lint +INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE) + +# +# lint pass one enforcement +# +CFLAGS += $(CCVERBOSE) + +# +# module dependencies +# +LDFLAGS += -dy -Nmisc/drmach + +# +# 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)/sun4u/opl/Makefile.targ diff --git a/usr/src/uts/sun4u/opl/drmach/Makefile b/usr/src/uts/sun4u/opl/drmach/Makefile new file mode 100644 index 0000000000..80ae24dbc1 --- /dev/null +++ b/usr/src/uts/sun4u/opl/drmach/Makefile @@ -0,0 +1,116 @@ +# +# 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. +# +# ident "%Z%%M% %I% %E% SMI" +# +# This makefile drives the production of the drmach loadable module. +# +# sun4u opl implementation architecture dependent +# + +# +# Path to the base of the uts directory tree (usually /usr/src/uts). +# +UTSBASE = ../../.. + +# +# Define the module and object file sets. +# +MODULE = drmach +OBJECTS = $(DRMACH_OBJS:%=$(OBJS_DIR)/%) +LINTS = $(DRMACH_OBJS:%.o=$(LINTS_DIR)/%.ln) +ROOTMODULE = $(ROOT_OPL_MISC_DIR)/$(MODULE) + +DRMACH_OFFSETS = $(UTSBASE)/sun4u/opl/ml/drmach_offsets.in +DRMACH_OFFSETS_H = $(OBJS_DIR)/drmach_offsets.h +DRMACH_OFFSETS_C = $(OBJS_DIR)/drmach_offsets.c +DRMACH_OFFSETS_S = $(OBJS_DIR)/drmach_offsets.s +DRMACH_OFFSETS_TMP = $(OBJS_DIR)/drmach_offsets.tmp +DRMACH_OFFSETS_OUT = $(OBJS_DIR)/drmach_offsets.out + +# +# Include common rules. +# +include $(UTSBASE)/sun4u/opl/Makefile.opl + +# +# Define targets +# +ALL_TARGET = $(BINARY) +LINT_TARGET = $(MODULE).lint +INSTALL_TARGET = $(BINARY) $(ROOTMODULE) + +CLEANFILES += $(DRMACH_OFFSETS_H) $(DRMACH_OFFSETS_OUT) + +# +# lint pass one enforcement +# +CFLAGS += $(CCVERBOSE) + +# +# module dependencies +# +LDFLAGS += -dy -Nmisc/opl_cfg + +# +# 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) + +AS_INC_PATH += -I$(OBJS_DIR) + +$(DRMACH_DEPS:%=$(OBJS_DIR)/%): $(DRMACH_OFFSETS_H) + +$(DRMACH_OFFSETS_H): $(GENCONST) $(DRMACH_OFFSETS_OUT) + @cp $(DRMACH_OFFSETS_OUT) $(DRMACH_OFFSETS_H) + $(GENCONST) >> $(DRMACH_OFFSETS_H) + +$(DRMACH_OFFSETS_OUT): $(DRMACH_OFFSETS) + @grep "^#" $(DRMACH_OFFSETS) > $(DRMACH_OFFSETS_C) + $(CC) $(CFLAGS) $(CPPFLAGS) -g -S -o $(DRMACH_OFFSETS_S) $(DRMACH_OFFSETS_C) + @grep -v "^#" $(DRMACH_OFFSETS) > $(DRMACH_OFFSETS_TMP) + $(STABS) -t genassym -m $(MODEL) $(DRMACH_OFFSETS_TMP) \ + < $(DRMACH_OFFSETS_S) > $(DRMACH_OFFSETS_OUT) + @rm $(DRMACH_OFFSETS_C) $(DRMACH_OFFSETS_S) $(DRMACH_OFFSETS_TMP) + +# +# Include common targets. +# +include $(UTSBASE)/sun4u/opl/Makefile.targ diff --git a/usr/src/uts/sun4u/opl/genassym/Makefile b/usr/src/uts/sun4u/opl/genassym/Makefile new file mode 100644 index 0000000000..9b0ca0c1f7 --- /dev/null +++ b/usr/src/uts/sun4u/opl/genassym/Makefile @@ -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 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# +# This makefile drives the production of assym.h through genconst/stabs. +# +# sun4u opl implementation architecture dependent +# +# uts/sun4u/opl/genassym/Makefile +# + +# +# Path to the base of the uts directory tree (usually /usr/src/uts). +# +UTSBASE = ../../.. + +ASSYM_H = $(DSF_DIR)/$(OBJS_DIR)/assym.h +GENCONST = $(DSF_DIR)/$(OBJS_DIR)/genconst + +# +# Include common rules. +# +include $(UTSBASE)/sun4u/opl/Makefile.opl + +# +# Define targets +# +ALL_TARGET = $(ASSYM_H) + +# +# This is DSF_DIR. Use a short path. +# +DSF_DIR = . + +# +# Overrides +# +CLEANFILES = $(GENCONST) Nothing_to_remove +CLOBBERFILES = $(ASSYM_H) $(CLEANFILES) Nothing_to_remove +ALL_BUILDS = $(ALL_BUILDSONLY64) +DEF_BUILDS = $(DEF_BUILDSONLY64) + +# +# Default build targets. +# +.KEEP_STATE: + +all: $(ALL_DEPS) + +def: $(DEF_DEPS) + +clean: $(CLEAN_DEPS) + +clobber: $(CLOBBER_DEPS) + +clean.lint: + +install: def + +# +# create assym.h +# +$(GENCONST): $(GENCONST_SRC) + $(NATIVECC) -w $(ALWAYS_DEFS) $(GENCONST_DEFS) $(NATIVE_INC_PATH) \ + -o $(GENCONST) $(GENCONST_SRC) + +$(ASSYM_H): $(GENCONST) $(OFFSETS) $(PLATFORM_OFFSETS) + $(OFFSETS_CREATE) <$(OFFSETS) >$@ + $(OFFSETS_CREATE) <$(PLATFORM_OFFSETS) >>$@ + $(GENCONST) >>$@ + +# +# Include common targets. +# +include $(UTSBASE)/sun4u/opl/Makefile.targ diff --git a/usr/src/uts/sun4u/opl/io/dm2s.c b/usr/src/uts/sun4u/opl/io/dm2s.c new file mode 100644 index 0000000000..3bd528c2af --- /dev/null +++ b/usr/src/uts/sun4u/opl/io/dm2s.c @@ -0,0 +1,1291 @@ +/* + * 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" + +/* + * DM2S - Domain side Mailbox to synchronous serial device driver. + * + * Description: + * ----------- + * It is a streams driver which simulates a sync serial device on + * top of a mailbox type of communication. That is, it sends/receives + * frames as mailbox messages. The mailbox communication is provided + * by another driver, which exports the mailbox interfaces. + * + * Synchronization: + * --------------- + * This driver uses streams perimeters to simplify the synchronization. + * An inner perimeter D_MTPERMOD which protects the entire module, + * that is only one thread exists inside the perimeter, is used. As + * this driver supports only one instance and is not a high-performance + * driver, D_MTPERMOD is highly suitable. + * + * All transmission and reception of frames is done inside the service + * procedures so that all streams related operations are protected + * by the perimeters. + * + * The mailbox event handler is the only asynchronous callback which + * needs to be protected outside of the streams perimeters. This is + * done using the module private lock('ms_lock'); + * + */ + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/stream.h> +#include <sys/cred.h> +#include <sys/systm.h> +#include <sys/sunddi.h> +#include <sys/ddi.h> +#include <sys/conf.h> +#include <sys/modctl.h> +#include <sys/mkdev.h> +#include <sys/errno.h> +#include <sys/debug.h> +#include <sys/kbio.h> +#include <sys/kmem.h> +#include <sys/consdev.h> +#include <sys/file.h> +#include <sys/stropts.h> +#include <sys/strsun.h> +#include <sys/dlpi.h> +#include <sys/stat.h> +#include <sys/ser_sync.h> +#include <sys/sysmacros.h> +#include <sys/note.h> +#include <sys/sdt.h> + +#include <sys/scfd/scfdscpif.h> +#include <sys/dm2s.h> + + +#define DM2S_MODNAME "dm2s" /* Module name */ +#define DM2S_TARGET_ID 0 /* Target ID of the peer */ +#define DM2S_ID_NUM 0x4D53 /* 'M''S' */ +#define DM2S_DEF_MTU 1504 /* Def. MTU size + PPP bytes */ +#define DM2S_MAXPSZ DM2S_DEF_MTU /* Set it to the default MTU */ +#define DM2S_LOWAT (4 * 1024) /* Low water mark */ +#define DM2S_HIWAT (12 * 1024) /* High water mark */ +#define DM2S_SM_TOUT 5000 /* Small timeout (5msec) */ +#define DM2S_LG_TOUT 50000 /* Large timeout (50msec) */ +#define DM2S_MB_TOUT 10000000 /* Mailbox timeout (10sec) */ + +/* + * Global variables + */ +void *dm2s_softstate = NULL; /* Softstate pointer */ + + +/* + * Prototypes for the module related functions. + */ +int dm2s_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); +int dm2s_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); +int dm2s_info(dev_info_t *dip, ddi_info_cmd_t infocmd, + void *arg, void **result); + +/* + * Prototypes for the streams related functions. + */ +int dm2s_open(queue_t *rq, dev_t *dev, int flag, int sflag, cred_t *cr); +int dm2s_close(queue_t *rq, int flag, cred_t *cred); +int dm2s_wput(queue_t *wq, mblk_t *mp); +int dm2s_rsrv(queue_t *rq); +int dm2s_wsrv(queue_t *wq); + +/* + * Prototypes for the internal functions. + */ +void dm2s_start(queue_t *wq, dm2s_t *dm2sp); +void dm2s_event_handler(scf_event_t event, void *arg); +int dm2s_transmit(queue_t *wq, mblk_t *mp, target_id_t target, mkey_t key); +void dm2s_receive(dm2s_t *dm2sp); +void dm2s_wq_timeout(void *arg); +void dm2s_rq_timeout(void *arg); +void dm2s_bufcall_rcv(void *arg); +static clock_t dm2s_timeout_val(int error); +static void dm2s_cleanup(dm2s_t *dm2sp); +static int dm2s_mbox_init(dm2s_t *dm2sp); +static void dm2s_mbox_fini(dm2s_t *dm2sp); +static int dm2s_prep_scatgath(mblk_t *mp, uint32_t *numsg, + mscat_gath_t *sgp, int maxsg); + +#ifdef DEBUG +uint32_t dm2s_debug = DBG_WARN; +#endif /* DEBUG */ + + +/* + * Streams and module related structures. + */ +struct module_info dm2s_module_info = { + DM2S_ID_NUM, /* module ID number */ + DM2S_MODNAME, /* module name. */ + 0, /* Minimum packet size (none) */ + DM2S_MAXPSZ, /* Maximum packet size (none) */ + DM2S_HIWAT, /* queue high water mark */ + DM2S_LOWAT /* queue low water mark */ +}; + +struct qinit dm2s_rinit = { + putq, /* qi_putp */ + dm2s_rsrv, /* qi_srvp */ + dm2s_open, /* qi_qopen */ + dm2s_close, /* qi_qlcose */ + NULL, /* qi_qadmin */ + &dm2s_module_info, /* qi_minfo */ + NULL /* qi_mstat */ +}; + +struct qinit dm2s_winit = { + dm2s_wput, /* qi_putp */ + dm2s_wsrv, /* qi_srvp */ + NULL, /* qi_qopen */ + NULL, /* qi_qlcose */ + NULL, /* qi_qadmin */ + &dm2s_module_info, /* qi_minfo */ + NULL /* qi_mstat */ +}; + + +struct streamtab dm2s_streamtab = { + &dm2s_rinit, + &dm2s_winit, + NULL, + NULL +}; + +DDI_DEFINE_STREAM_OPS(dm2s_ops, nulldev, nulldev, dm2s_attach, \ + dm2s_detach, nodev, dm2s_info, D_NEW | D_MP | D_MTPERMOD, \ + &dm2s_streamtab); + + +struct modldrv modldrv = { + &mod_driverops, + "OPL Mbox to Serial Driver %I%", + &dm2s_ops +}; + +struct modlinkage modlinkage = { + MODREV_1, + &modldrv, + NULL +}; + + +/* + * _init - Module's init routine. + */ +int +_init(void) +{ + int ret; + + if (ddi_soft_state_init(&dm2s_softstate, sizeof (dm2s_t), 1) != 0) { + cmn_err(CE_WARN, "softstate initialization failed\n"); + return (DDI_FAILURE); + } + if ((ret = mod_install(&modlinkage)) != 0) { + cmn_err(CE_WARN, "mod_install failed, error = %d", ret); + ddi_soft_state_fini(&dm2s_softstate); + } + return (ret); +} + +/* + * _fini - Module's fini routine. + */ +int +_fini(void) +{ + int ret; + + if ((ret = mod_remove(&modlinkage)) != 0) { + return (ret); + } + ddi_soft_state_fini(&dm2s_softstate); + return (ret); +} + +/* + * _info - Module's info routine. + */ +int +_info(struct modinfo *modinfop) +{ + return (mod_info(&modlinkage, modinfop)); +} + +/* + * dm2s_attach - Module's attach routine. + */ +int +dm2s_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) +{ + int instance; + dm2s_t *dm2sp; + char name[20]; + + + instance = ddi_get_instance(dip); + + /* Only one instance is supported. */ + if (instance != 0) { + cmn_err(CE_WARN, "only one instance is supported"); + return (DDI_FAILURE); + } + + if (cmd != DDI_ATTACH) { + return (DDI_FAILURE); + } + if (ddi_soft_state_zalloc(dm2s_softstate, instance) != DDI_SUCCESS) { + cmn_err(CE_WARN, "softstate allocation failure"); + return (DDI_FAILURE); + } + dm2sp = (dm2s_t *)ddi_get_soft_state(dm2s_softstate, instance); + if (dm2sp == NULL) { + ddi_soft_state_free(dm2s_softstate, instance); + cmn_err(CE_WARN, "softstate allocation failure."); + return (DDI_FAILURE); + } + dm2sp->ms_dip = dip; + dm2sp->ms_major = ddi_name_to_major(ddi_get_name(dip)); + dm2sp->ms_ppa = instance; + + /* + * Get an interrupt block cookie corresponding to the + * interrupt priority of the event handler. + * Assert that the event priority is not re-defined to + * some higher priority. + */ + /* LINTED */ + ASSERT(SCF_EVENT_PRI == DDI_SOFTINT_LOW); + if (ddi_get_soft_iblock_cookie(dip, SCF_EVENT_PRI, + &dm2sp->ms_ibcookie) != DDI_SUCCESS) { + cmn_err(CE_WARN, "ddi_get_soft_iblock_cookie failed."); + goto error; + } + mutex_init(&dm2sp->ms_lock, NULL, MUTEX_DRIVER, + (void *)dm2sp->ms_ibcookie); + + dm2sp->ms_clean |= DM2S_CLEAN_LOCK; + cv_init(&dm2sp->ms_wait, NULL, CV_DRIVER, NULL); + dm2sp->ms_clean |= DM2S_CLEAN_CV; + + (void) sprintf(name, "%s%d", DM2S_MODNAME, instance); + if (ddi_create_minor_node(dip, name, S_IFCHR, instance, + DDI_PSEUDO, NULL) == DDI_FAILURE) { + ddi_remove_minor_node(dip, NULL); + cmn_err(CE_WARN, "Device node creation failed."); + goto error; + } + + dm2sp->ms_clean |= DM2S_CLEAN_NODE; + ddi_set_driver_private(dip, (caddr_t)dm2sp); + ddi_report_dev(dip); + return (DDI_SUCCESS); +error: + dm2s_cleanup(dm2sp); + return (DDI_FAILURE); +} + +/* + * dm2s_info - Module's info routine. + */ +/*ARGSUSED*/ +int +dm2s_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) +{ + dm2s_t *dm2sp; + minor_t minor; + int ret = DDI_FAILURE; + + switch (infocmd) { + case DDI_INFO_DEVT2DEVINFO: + minor = getminor((dev_t)arg); + dm2sp = (dm2s_t *)ddi_get_soft_state(dm2s_softstate, minor); + if (dm2sp == NULL) { + *result = NULL; + } else { + *result = dm2sp->ms_dip; + ret = DDI_SUCCESS; + } + break; + + case DDI_INFO_DEVT2INSTANCE: + minor = getminor((dev_t)arg); + *result = (void *)(uintptr_t)minor; + ret = DDI_SUCCESS; + break; + + default: + break; + } + return (ret); +} + +/* + * dm2s_detach - Module's detach routine. + */ +int +dm2s_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) +{ + int instance; + dm2s_t *dm2sp; + + if (cmd != DDI_DETACH) { + return (DDI_FAILURE); + } + + instance = ddi_get_instance(dip); + dm2sp = (dm2s_t *)ddi_get_soft_state(dm2s_softstate, instance); + if (dm2sp == NULL) { + return (DDI_FAILURE); + } + + mutex_enter(&dm2sp->ms_lock); + + /* Check if the mailbox is still in use. */ + if (dm2sp->ms_state & DM2S_MB_INITED) { + mutex_exit(&dm2sp->ms_lock); + cmn_err(CE_WARN, "Mailbox in use: Detach failed"); + return (DDI_FAILURE); + } + mutex_exit(&dm2sp->ms_lock); + dm2s_cleanup(dm2sp); + return (DDI_SUCCESS); +} + +/* + * dm2s_open - Device open routine. + * + * Only one open supported. Clone open is not supported. + */ +/* ARGSUSED */ +int +dm2s_open(queue_t *rq, dev_t *dev, int flag, int sflag, cred_t *cr) +{ + dm2s_t *dm2sp; + int instance = getminor(*dev); + int ret = 0; + + DPRINTF(DBG_DRV, ("dm2s_open: called\n")); + if (sflag == CLONEOPEN) { + /* Clone open not supported */ + DPRINTF(DBG_WARN, ("dm2s_open: clone open not supported\n")); + return (ENOTSUP); + } + + if (rq->q_ptr != NULL) { + DPRINTF(DBG_WARN, ("dm2s_open: already opened\n")); + return (EBUSY); + } + + if ((dm2sp = ddi_get_soft_state(dm2s_softstate, instance)) == NULL) { + DPRINTF(DBG_WARN, ("dm2s_open: instance not found\n")); + return (ENODEV); + } + + mutex_enter(&dm2sp->ms_lock); + if (dm2sp->ms_state & DM2S_OPENED) { + /* Only one open supported */ + mutex_exit(&dm2sp->ms_lock); + DPRINTF(DBG_WARN, ("dm2s_open: already opened\n")); + return (EBUSY); + } + + dm2sp->ms_state |= DM2S_OPENED; + /* Initialize the mailbox. */ + if ((ret = dm2s_mbox_init(dm2sp)) != 0) { + dm2sp->ms_state = 0; + mutex_exit(&dm2sp->ms_lock); + return (ret); + } + rq->q_ptr = WR(rq)->q_ptr = (void *)dm2sp; + dm2sp->ms_rq = rq; + dm2sp->ms_wq = WR(rq); + mutex_exit(&dm2sp->ms_lock); + + if (ret == 0) { + qprocson(rq); /* now schedule our queue */ + } + DPRINTF(DBG_DRV, ("dm2s_open: ret=%d\n", ret)); + return (ret); +} + +/* + * dm2s_close - Device close routine. + */ +/* ARGSUSED */ +int +dm2s_close(queue_t *rq, int flag, cred_t *cred) +{ + dm2s_t *dm2sp = (dm2s_t *)rq->q_ptr; + + DPRINTF(DBG_DRV, ("dm2s_close: called\n")); + if (dm2sp == NULL) { + /* Already closed once */ + return (ENODEV); + } + + /* Close the lower layer first */ + mutex_enter(&dm2sp->ms_lock); + (void) scf_mb_flush(dm2sp->ms_target, dm2sp->ms_key, MB_FLUSH_ALL); + dm2s_mbox_fini(dm2sp); + mutex_exit(&dm2sp->ms_lock); + + /* + * Now we can assume that no asynchronous callbacks exist. + * Poison the stream head so that we can't be pushed again. + */ + (void) putnextctl(rq, M_HANGUP); + qprocsoff(rq); + if (dm2sp->ms_rbufcid != 0) { + qunbufcall(rq, dm2sp->ms_rbufcid); + dm2sp->ms_rbufcid = 0; + } + if (dm2sp->ms_rq_timeoutid != 0) { + DTRACE_PROBE1(dm2s_rqtimeout__cancel, dm2s_t, dm2sp); + (void) quntimeout(dm2sp->ms_rq, dm2sp->ms_rq_timeoutid); + dm2sp->ms_rq_timeoutid = 0; + } + if (dm2sp->ms_wq_timeoutid != 0) { + DTRACE_PROBE1(dm2s_wqtimeout__cancel, dm2s_t, dm2sp); + (void) quntimeout(dm2sp->ms_wq, dm2sp->ms_wq_timeoutid); + dm2sp->ms_wq_timeoutid = 0; + } + /* + * Now we can really mark it closed. + */ + mutex_enter(&dm2sp->ms_lock); + dm2sp->ms_rq = dm2sp->ms_wq = NULL; + dm2sp->ms_state &= ~DM2S_OPENED; + mutex_exit(&dm2sp->ms_lock); + + rq->q_ptr = WR(rq)->q_ptr = NULL; + (void) qassociate(rq, -1); + DPRINTF(DBG_DRV, ("dm2s_close: successfully closed\n")); + return (0); +} + +/* + * dm2s_rsrv - Streams read side service procedure. + * + * All messages are received in the service procedure + * only. This is done to simplify the streams synchronization. + */ +int +dm2s_rsrv(queue_t *rq) +{ + mblk_t *mp; + dm2s_t *dm2sp = (dm2s_t *)rq->q_ptr; + + DPRINTF(DBG_DRV, ("dm2s_rsrv: called\n")); + ASSERT(dm2sp != NULL); + mutex_enter(&dm2sp->ms_lock); + + /* Receive if there are any messages waiting in the mailbox. */ + dm2s_receive(dm2sp); + mutex_exit(&dm2sp->ms_lock); + + /* Send the received messages up the stream. */ + while ((mp = getq(rq)) != NULL) { + if (canputnext(rq)) { + putnext(rq, mp); + } else { + putbq(rq, mp); + break; + } + } + DPRINTF(DBG_DRV, ("dm2s_rsrv: return\n")); + return (0); +} + +/* + * dm2s_wsrv - Streams write side service procedure. + * + * All messages are transmitted in the service procedure + * only. This is done to simplify the streams synchronization. + */ +int +dm2s_wsrv(queue_t *wq) +{ + dm2s_t *dm2sp = (dm2s_t *)wq->q_ptr; + + DPRINTF(DBG_DRV, ("dm2s_wsrv: called\n")); + ASSERT(dm2sp != NULL); + /* Lets cancel any timeouts waiting to be scheduled. */ + if (dm2sp->ms_wq_timeoutid != 0) { + DTRACE_PROBE1(dm2s_wqtimeout__cancel, dm2s_t, dm2sp); + (void) quntimeout(dm2sp->ms_wq, dm2sp->ms_wq_timeoutid); + dm2sp->ms_wq_timeoutid = 0; + } + mutex_enter(&dm2sp->ms_lock); + dm2s_start(wq, dm2sp); + mutex_exit(&dm2sp->ms_lock); + DPRINTF(DBG_DRV, ("dm2s_wsrv: return\n")); + return (0); +} + +/* + * dm2s_wput - Streams write side put routine. + * + * All M_DATA messages are queued so that they are transmitted in + * the service procedure. This is done to simplify the streams + * synchronization. Other messages are handled appropriately. + */ +int +dm2s_wput(queue_t *wq, mblk_t *mp) +{ + dm2s_t *dm2sp = (dm2s_t *)wq->q_ptr; + + DPRINTF(DBG_DRV, ("dm2s_wput: called\n")); + if (dm2sp == NULL) { + return (ENODEV); /* Can't happen. */ + } + + switch (mp->b_datap->db_type) { + case (M_DATA): + DPRINTF(DBG_DRV, ("dm2s_wput: M_DATA message\n")); + while (mp->b_wptr == mp->b_rptr) { + mblk_t *mp1; + + mp1 = unlinkb(mp); + freemsg(mp); + mp = mp1; + if (mp == NULL) { + return (0); + } + } + + /* + * Simply queue the message and handle it in the service + * procedure. + */ + (void) putq(wq, mp); + qenable(wq); + return (0); + + case (M_PROTO): + DPRINTF(DBG_DRV, ("dm2s_wput: M_PROTO message\n")); + /* We don't expect this */ + mp->b_datap->db_type = M_ERROR; + mp->b_rptr = mp->b_wptr = mp->b_datap->db_base; + *mp->b_wptr++ = EPROTO; + qreply(wq, mp); + return (EINVAL); + + case (M_IOCTL): + DPRINTF(DBG_DRV, ("dm2s_wput: M_IOCTL message\n")); + if (MBLKL(mp) < sizeof (struct iocblk)) { + freemsg(mp); + return (0); + } + /* + * No ioctls required to be supported by this driver, so + * return EINVAL for all ioctls. + */ + miocnak(wq, mp, 0, EINVAL); + break; + + case (M_CTL): + DPRINTF(DBG_DRV, ("dm2s_wput: M_CTL message\n")); + /* + * No M_CTL messages need to supported by this driver, + * so simply ignore them. + */ + freemsg(mp); + break; + + case (M_FLUSH): + DPRINTF(DBG_DRV, ( + "dm2s_wput: M_FLUSH message 0x%X\n", *mp->b_rptr)); + if (*mp->b_rptr & FLUSHW) { /* Flush write-side */ + (void) scf_mb_flush(dm2sp->ms_target, dm2sp->ms_key, + MB_FLUSH_SEND); + flushq(wq, FLUSHDATA); + *mp->b_rptr &= ~FLUSHW; + } + if (*mp->b_rptr & FLUSHR) { + (void) scf_mb_flush(dm2sp->ms_target, dm2sp->ms_key, + MB_FLUSH_RECEIVE); + flushq(RD(wq), FLUSHDATA); + qreply(wq, mp); + } else { + freemsg(mp); + } + break; + + default: + DPRINTF(DBG_DRV, ("dm2s_wput: UNKNOWN message\n")); + freemsg(mp); + + } + return (0); +} + +/* + * dm2s_cleanup - Cleanup routine. + */ +static void +dm2s_cleanup(dm2s_t *dm2sp) +{ + char name[20]; + + DPRINTF(DBG_DRV, ("dm2s_cleanup: called\n")); + ASSERT(dm2sp != NULL); + if (dm2sp->ms_clean & DM2S_CLEAN_NODE) { + (void) sprintf(name, "%s%d", DM2S_MODNAME, dm2sp->ms_ppa); + ddi_remove_minor_node(dm2sp->ms_dip, name); + } + if (dm2sp->ms_clean & DM2S_CLEAN_LOCK) + mutex_destroy(&dm2sp->ms_lock); + if (dm2sp->ms_clean & DM2S_CLEAN_CV) + cv_destroy(&dm2sp->ms_wait); + ddi_set_driver_private(dm2sp->ms_dip, NULL); + ddi_soft_state_free(dm2s_softstate, dm2sp->ms_ppa); +} + +/* + * dm2s_mbox_init - Mailbox specific initialization. + */ +static int +dm2s_mbox_init(dm2s_t *dm2sp) +{ + int ret; + clock_t tout; + + ASSERT(MUTEX_HELD(&dm2sp->ms_lock)); + dm2sp->ms_target = DM2S_TARGET_ID; + dm2sp->ms_key = DSCP_KEY; + dm2sp->ms_state &= ~DM2S_MB_INITED; + + /* Iterate until mailbox gets connected */ + while (!(dm2sp->ms_state & DM2S_MB_CONN)) { + DPRINTF(DBG_MBOX, ("dm2s_mbox_init: calling mb_init\n")); + ret = scf_mb_init(dm2sp->ms_target, dm2sp->ms_key, + dm2s_event_handler, (void *)dm2sp); + DPRINTF(DBG_MBOX, ("dm2s_mbox_init: mb_init ret=%d\n", ret)); + + if (ret == 0) { + dm2sp->ms_state |= DM2S_MB_INITED; + + /* Block until the mailbox is ready to communicate. */ + while (!(dm2sp->ms_state & + (DM2S_MB_CONN | DM2S_MB_DISC))) { + + if (cv_wait_sig(&dm2sp->ms_wait, + &dm2sp->ms_lock) <= 0) { + /* interrupted */ + ret = EINTR; + break; + } + } + } + + if (ret != 0) { + + DPRINTF(DBG_MBOX, + ("dm2s_mbox_init: failed/interrupted\n")); + DTRACE_PROBE1(dm2s_mbox_fail, int, ret); + dm2sp->ms_state &= ~DM2S_MB_INITED; + (void) scf_mb_fini(dm2sp->ms_target, dm2sp->ms_key); + + /* if interrupted, return immediately. */ + if (ret == EINTR) + return (ret); + + } + + if ((ret != 0) || (dm2sp->ms_state & DM2S_MB_DISC)) { + + DPRINTF(DBG_WARN, + ("dm2s_mbox_init: mbox DISC_ERROR\n")); + DTRACE_PROBE1(dm2s_mbox_fail, int, DM2S_MB_DISC); + dm2sp->ms_state &= ~DM2S_MB_INITED; + (void) scf_mb_fini(dm2sp->ms_target, dm2sp->ms_key); + + /* + * If there was failure, then wait for + * DM2S_MB_TOUT secs and retry again. + */ + + DPRINTF(DBG_MBOX, ("dm2s_mbox_init: waiting...\n")); + tout = ddi_get_lbolt() + drv_usectohz(DM2S_MB_TOUT); + ret = cv_timedwait_sig(&dm2sp->ms_wait, + &dm2sp->ms_lock, tout); + if (ret == 0) { + /* if interrupted, return immediately. */ + DPRINTF(DBG_MBOX, + ("dm2s_mbox_init: interrupted\n")); + return (EINTR); + } + } + } + + /* + * Obtain the max size of a single message. + * NOTE: There is no mechanism to update the + * upperlayers dynamically, so we expect this + * size to be atleast the default MTU size. + */ + ret = scf_mb_ctrl(dm2sp->ms_target, dm2sp->ms_key, + SCF_MBOP_MAXMSGSIZE, &dm2sp->ms_mtu); + + if ((ret == 0) && (dm2sp->ms_mtu < DM2S_DEF_MTU)) { + cmn_err(CE_WARN, "Max message size expected >= %d " + "but found %d\n", DM2S_DEF_MTU, dm2sp->ms_mtu); + ret = EIO; + } + + if (ret != 0) { + dm2sp->ms_state &= ~DM2S_MB_INITED; + (void) scf_mb_fini(dm2sp->ms_target, dm2sp->ms_key); + } + DPRINTF(DBG_MBOX, ("dm2s_mbox_init: mb_init ret=%d\n", ret)); + return (ret); +} + +/* + * dm2s_mbox_fini - Mailbox de-initialization. + */ +static void +dm2s_mbox_fini(dm2s_t *dm2sp) +{ + int ret; + + ASSERT(dm2sp != NULL); + if (dm2sp->ms_state & DM2S_MB_INITED) { + DPRINTF(DBG_MBOX, ("dm2s_mbox_fini: calling mb_fini\n")); + ret = scf_mb_fini(dm2sp->ms_target, dm2sp->ms_key); + if (ret != 0) { + cmn_err(CE_WARN, + "Failed to close the Mailbox error =%d", ret); + } + DPRINTF(DBG_MBOX, ("dm2s_mbox_fini: mb_fini ret=%d\n", ret)); + dm2sp->ms_state &= ~(DM2S_MB_INITED |DM2S_MB_CONN | + DM2S_MB_DISC); + } +} + +/* + * dm2s_event_handler - Mailbox event handler. + */ +void +dm2s_event_handler(scf_event_t event, void *arg) +{ + dm2s_t *dm2sp = (dm2s_t *)arg; + queue_t *rq; + + ASSERT(dm2sp != NULL); + mutex_enter(&dm2sp->ms_lock); + if (!(dm2sp->ms_state & DM2S_MB_INITED)) { + /* + * Ignore all events if the state flag indicates that the + * mailbox not initialized, this may happen during the close. + */ + mutex_exit(&dm2sp->ms_lock); + DPRINTF(DBG_MBOX, + ("Event(0x%X) received - Mailbox not inited\n", event)); + return; + } + switch (event) { + case SCF_MB_CONN_OK: + /* + * Now the mailbox is ready to use, lets wake up + * any one waiting for this event. + */ + dm2sp->ms_state |= DM2S_MB_CONN; + cv_broadcast(&dm2sp->ms_wait); + DPRINTF(DBG_MBOX, ("Event received = CONN_OK\n")); + break; + + case SCF_MB_MSG_DATA: + if (!DM2S_MBOX_READY(dm2sp)) { + DPRINTF(DBG_MBOX, + ("Event(MSG_DATA) received - Mailbox not READY\n")); + break; + } + /* + * A message is available in the mailbox. + * Lets enable the read service procedure + * to receive this message. + */ + if (dm2sp->ms_rq != NULL) { + qenable(dm2sp->ms_rq); + } + DPRINTF(DBG_MBOX, ("Event received = MSG_DATA\n")); + break; + + case SCF_MB_SPACE: + if (!DM2S_MBOX_READY(dm2sp)) { + DPRINTF(DBG_MBOX, + ("Event(MB_SPACE) received - Mailbox not READY\n")); + break; + } + + /* + * Now the mailbox is ready to transmit, lets + * schedule the write service procedure. + */ + if (dm2sp->ms_wq != NULL) { + qenable(dm2sp->ms_wq); + } + DPRINTF(DBG_MBOX, ("Event received = MB_SPACE\n")); + break; + case SCF_MB_DISC_ERROR: + dm2sp->ms_state |= DM2S_MB_DISC; + if (dm2sp->ms_state & DM2S_MB_CONN) { + /* + * If it was previously connected, + * then send a hangup message. + */ + rq = dm2sp->ms_rq; + if (rq != NULL) { + mutex_exit(&dm2sp->ms_lock); + /* + * Send a hangup message to indicate + * disconnect event. + */ + (void) putctl(rq, M_HANGUP); + DTRACE_PROBE1(dm2s_hangup, dm2s_t, dm2sp); + mutex_enter(&dm2sp->ms_lock); + } + } else { + /* + * Signal if the open is waiting for a + * connection. + */ + cv_broadcast(&dm2sp->ms_wait); + } + DPRINTF(DBG_MBOX, ("Event received = DISC_ERROR\n")); + break; + default: + cmn_err(CE_WARN, "Unexpected event received\n"); + break; + } + mutex_exit(&dm2sp->ms_lock); +} + +/* + * dm2s_start - Start transmission function. + * + * Send all queued messages. If the mailbox is busy, then + * start a timeout as a polling mechanism. The timeout is useful + * to not rely entirely on the SCF_MB_SPACE event. + */ +void +dm2s_start(queue_t *wq, dm2s_t *dm2sp) +{ + mblk_t *mp; + int ret; + + DPRINTF(DBG_DRV, ("dm2s_start: called\n")); + ASSERT(dm2sp != NULL); + ASSERT(MUTEX_HELD(&dm2sp->ms_lock)); + + while ((mp = getq(wq)) != NULL) { + switch (mp->b_datap->db_type) { + + case M_DATA: + ret = dm2s_transmit(wq, mp, dm2sp->ms_target, + dm2sp->ms_key); + if (ret == EBUSY || ret == ENOSPC || ret == EAGAIN) { + DPRINTF(DBG_MBOX, + ("dm2s_start: recoverable err=%d\n", ret)); + /* + * Start a timeout to retry again. + */ + if (dm2sp->ms_wq_timeoutid == 0) { + DTRACE_PROBE1(dm2s_wqtimeout__start, + dm2s_t, dm2sp); + dm2sp->ms_wq_timeoutid = qtimeout(wq, + dm2s_wq_timeout, (void *)dm2sp, + dm2s_timeout_val(ret)); + } + return; + } else if (ret != 0) { + mutex_exit(&dm2sp->ms_lock); + /* + * An error occurred with the transmission, + * flush pending messages and initiate a + * hangup. + */ + flushq(wq, FLUSHDATA); + (void) putnextctl(RD(wq), M_HANGUP); + DTRACE_PROBE1(dm2s_hangup, dm2s_t, dm2sp); + DPRINTF(DBG_WARN, + ("dm2s_start: hangup transmit err=%d\n", + ret)); + mutex_enter(&dm2sp->ms_lock); + } + break; + default: + /* + * At this point, we don't expect any other messages. + */ + freemsg(mp); + break; + } + } +} + +/* + * dm2s_receive - Read all messages from the mailbox. + * + * This function is called from the read service procedure, to + * receive the messages awaiting in the mailbox. + */ +void +dm2s_receive(dm2s_t *dm2sp) +{ + queue_t *rq = dm2sp->ms_rq; + mblk_t *mp; + int ret; + uint32_t len; + + DPRINTF(DBG_DRV, ("dm2s_receive: called\n")); + ASSERT(dm2sp != NULL); + ASSERT(MUTEX_HELD(&dm2sp->ms_lock)); + if (rq == NULL) { + return; + } + /* + * As the number of messages in the mailbox are pretty limited, + * it is safe to process all messages in one loop. + */ + while (DM2S_MBOX_READY(dm2sp) && ((ret = scf_mb_canget(dm2sp->ms_target, + dm2sp->ms_key, &len)) == 0)) { + DPRINTF(DBG_MBOX, ("dm2s_receive: mb_canget len=%d\n", len)); + if (len == 0) { + break; + } + mp = allocb(len, BPRI_MED); + if (mp == NULL) { + DPRINTF(DBG_WARN, ("dm2s_receive: allocb failed\n")); + /* + * Start a bufcall so that we can retry again + * when memory becomes available. + */ + dm2sp->ms_rbufcid = qbufcall(rq, len, BPRI_MED, + dm2s_bufcall_rcv, dm2sp); + if (dm2sp->ms_rbufcid == 0) { + DPRINTF(DBG_WARN, + ("dm2s_receive: qbufcall failed\n")); + /* + * if bufcall fails, start a timeout to + * initiate a re-try after some time. + */ + DTRACE_PROBE1(dm2s_rqtimeout__start, + dm2s_t, dm2sp); + dm2sp->ms_rq_timeoutid = qtimeout(rq, + dm2s_rq_timeout, (void *)dm2sp, + drv_usectohz(DM2S_SM_TOUT)); + } + break; + } + + /* + * Only a single scatter/gather element is enough here. + */ + dm2sp->ms_sg_rcv.msc_dptr = (caddr_t)mp->b_wptr; + dm2sp->ms_sg_rcv.msc_len = len; + DPRINTF(DBG_MBOX, ("dm2s_receive: calling getmsg\n")); + ret = scf_mb_getmsg(dm2sp->ms_target, dm2sp->ms_key, len, 1, + &dm2sp->ms_sg_rcv, 0); + DPRINTF(DBG_MBOX, ("dm2s_receive: getmsg ret=%d\n", ret)); + if (ret != 0) { + freemsg(mp); + break; + } + DMPBYTES("dm2s: Getmsg: ", len, 1, &dm2sp->ms_sg_rcv); + mp->b_wptr += len; + /* + * Queue the messages in the rq, so that the service + * procedure handles sending the messages up the stream. + */ + putq(rq, mp); + } + + if ((!DM2S_MBOX_READY(dm2sp)) || (ret != ENOMSG && ret != EMSGSIZE)) { + /* + * Some thing went wrong, flush pending messages + * and initiate a hangup. + * Note: flushing the wq initiates a faster close. + */ + mutex_exit(&dm2sp->ms_lock); + flushq(WR(rq), FLUSHDATA); + (void) putnextctl(rq, M_HANGUP); + DTRACE_PROBE1(dm2s_hangup, dm2s_t, dm2sp); + mutex_enter(&dm2sp->ms_lock); + DPRINTF(DBG_WARN, ("dm2s_receive: encountered unknown " + "condition - hangup ret=%d\n", ret)); + } +} + +/* + * dm2s_transmit - Transmit a message. + */ +int +dm2s_transmit(queue_t *wq, mblk_t *mp, target_id_t target, mkey_t key) +{ + dm2s_t *dm2sp = (dm2s_t *)wq->q_ptr; + int ret; + uint32_t len; + uint32_t numsg; + + DPRINTF(DBG_DRV, ("dm2s_transmit: called\n")); + ASSERT(dm2sp != NULL); + ASSERT(MUTEX_HELD(&dm2sp->ms_lock)); + /* + * Free the message if the mailbox is not in the connected state. + */ + if (!DM2S_MBOX_READY(dm2sp)) { + DPRINTF(DBG_MBOX, ("dm2s_transmit: mailbox not ready yet\n")); + freemsg(mp); + return (EIO); + } + + len = msgdsize(mp); + if (len > dm2sp->ms_mtu) { + /* + * Size is too big to send, free the message. + */ + DPRINTF(DBG_MBOX, ("dm2s_transmit: message too large\n")); + DTRACE_PROBE2(dm2s_msg_too_big, dm2s_t, dm2sp, uint32_t, len); + freemsg(mp); + return (0); + } + + if ((ret = dm2s_prep_scatgath(mp, &numsg, dm2sp->ms_sg_tx, + DM2S_MAX_SG)) != 0) { + DPRINTF(DBG_MBOX, ("dm2s_transmit: prep_scatgath failed\n")); + putbq(wq, mp); + return (EAGAIN); + } + DPRINTF(DBG_MBOX, ("dm2s_transmit: calling mb_putmsg numsg=%d len=%d\n", + numsg, len)); + ret = scf_mb_putmsg(target, key, len, numsg, dm2sp->ms_sg_tx, 0); + if (ret == EBUSY || ret == ENOSPC) { + DPRINTF(DBG_MBOX, + ("dm2s_transmit: mailbox busy ret=%d\n", ret)); + if (++dm2sp->ms_retries >= DM2S_MAX_RETRIES) { + /* + * If maximum retries are reached, then free the + * message. + */ + DPRINTF(DBG_MBOX, + ("dm2s_transmit: freeing msg after max retries\n")); + DTRACE_PROBE2(dm2s_retry_fail, dm2s_t, dm2sp, int, ret); + freemsg(mp); + dm2sp->ms_retries = 0; + return (0); + } + DTRACE_PROBE2(dm2s_mb_busy, dm2s_t, dm2sp, int, ret); + /* + * Queue it back, so that we can retry again. + */ + putbq(wq, mp); + return (ret); + } + DMPBYTES("dm2s: Putmsg: ", len, numsg, dm2sp->ms_sg_tx); + dm2sp->ms_retries = 0; + freemsg(mp); + DPRINTF(DBG_DRV, ("dm2s_transmit: ret=%d\n", ret)); + return (ret); +} + +/* + * dm2s_bufcall_rcv - Bufcall callaback routine. + * + * It simply enables read side queue so that the service procedure + * can retry receive operation. + */ +void +dm2s_bufcall_rcv(void *arg) +{ + dm2s_t *dm2sp = (dm2s_t *)arg; + + DPRINTF(DBG_DRV, ("dm2s_bufcall_rcv: called\n")); + mutex_enter(&dm2sp->ms_lock); + dm2sp->ms_rbufcid = 0; + if (dm2sp->ms_rq != NULL) { + qenable(dm2sp->ms_rq); + } + mutex_exit(&dm2sp->ms_lock); +} + +/* + * dm2s_rq_timeout - Timeout callback for the read side. + * + * It simply enables read side queue so that the service procedure + * can retry the receive operation. + */ +void +dm2s_rq_timeout(void *arg) +{ + dm2s_t *dm2sp = (dm2s_t *)arg; + + DPRINTF(DBG_DRV, ("dm2s_rq_timeout: called\n")); + mutex_enter(&dm2sp->ms_lock); + dm2sp->ms_rq_timeoutid = 0; + if (dm2sp->ms_rq != NULL) { + qenable(dm2sp->ms_rq); + } + mutex_exit(&dm2sp->ms_lock); +} + +/* + * dm2s_wq_timeout - Timeout callback for the write. + * + * It simply enables write side queue so that the service procedure + * can retry the transmission operation. + */ +void +dm2s_wq_timeout(void *arg) +{ + dm2s_t *dm2sp = (dm2s_t *)arg; + + DPRINTF(DBG_DRV, ("dm2s_wq_timeout: called\n")); + mutex_enter(&dm2sp->ms_lock); + dm2sp->ms_wq_timeoutid = 0; + if (dm2sp->ms_wq != NULL) { + qenable(dm2sp->ms_wq); + } + mutex_exit(&dm2sp->ms_lock); +} + +/* + * dm2s_prep_scatgath - Prepare scatter/gather elements for transmission + * of a streams message. + */ +static int +dm2s_prep_scatgath(mblk_t *mp, uint32_t *numsg, mscat_gath_t *sgp, int maxsg) +{ + uint32_t num = 0; + mblk_t *tmp = mp; + + while ((tmp != NULL) && (num < maxsg)) { + sgp[num].msc_dptr = (caddr_t)tmp->b_rptr; + sgp[num].msc_len = MBLKL(tmp); + tmp = tmp->b_cont; + num++; + } + + if (tmp != NULL) { + /* + * Number of scatter/gather elements available are not + * enough, so lets pullup the msg. + */ + if (pullupmsg(mp, -1) != 1) { + return (EAGAIN); + } + sgp[0].msc_dptr = (caddr_t)mp->b_rptr; + sgp[0].msc_len = MBLKL(mp); + num = 1; + } + *numsg = num; + return (0); +} + +/* + * dm2s_timeout_val -- Return appropriate timeout value. + * + * A small timeout value is returned for EBUSY and EAGAIN cases. This is + * because the condition is expected to be recovered sooner. + * + * A larger timeout value is returned for ENOSPC case, as the condition + * depends on the peer to release buffer space. + * NOTE: there will also be an event(SCF_MB_SPACE) but a timeout is + * used for reliability purposes. + */ +static clock_t +dm2s_timeout_val(int error) +{ + clock_t tval; + + ASSERT(error == EBUSY || error == ENOSPC || error == EAGAIN); + + if (error == EBUSY || error == EAGAIN) { + tval = DM2S_SM_TOUT; + } else { + tval = DM2S_LG_TOUT; + } + return (drv_usectohz(tval)); +} + +#ifdef DEBUG + +static void +dm2s_dump_bytes(char *str, uint32_t total_len, + uint32_t num_sg, mscat_gath_t *sgp) +{ + int i, j; + int nsg; + int len, tlen = 0; + mscat_gath_t *tp; + uint8_t *datap; +#define BYTES_PER_LINE 20 + char bytestr[BYTES_PER_LINE * 3 + 1]; + uint32_t digest = 0; + + if (!(dm2s_debug & DBG_MESG)) + return; + ASSERT(num_sg != 0); + + for (nsg = 0; (nsg < num_sg) && (tlen < total_len); nsg++) { + tp = &sgp[nsg]; + datap = (uint8_t *)tp->msc_dptr; + len = tp->msc_len; + for (i = 0; i < len; i++) { + digest += datap[i]; + } + tlen += len; + } + sprintf(bytestr, "%s Packet: Size=%d Digest=%d\n", + str, total_len, digest); + DTRACE_PROBE1(dm2s_dump_digest, unsigned char *, bytestr); + + for (nsg = 0; (nsg < num_sg) && (tlen < total_len); nsg++) { + tp = &sgp[nsg]; + datap = (uint8_t *)tp->msc_dptr; + len = tp->msc_len; + for (i = 0; i < len; ) { + for (j = 0; (j < BYTES_PER_LINE) && + (i < len); j++, i++) { + sprintf(&bytestr[j * 3], "%02X ", datap[i]); + digest += datap[i]; + } + if (j != 0) { + DTRACE_PROBE1(dm2s_dump, unsigned char *, + bytestr); + } + } + tlen += i; + } +} + +#endif /* DEBUG */ diff --git a/usr/src/uts/sun4u/opl/io/dm2s.conf b/usr/src/uts/sun4u/opl/io/dm2s.conf new file mode 100644 index 0000000000..d2256f5d38 --- /dev/null +++ b/usr/src/uts/sun4u/opl/io/dm2s.conf @@ -0,0 +1,28 @@ +# +# 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" + +name="dm2s" parent="pseudo" instance=0; diff --git a/usr/src/uts/sun4u/opl/io/dr.conf b/usr/src/uts/sun4u/opl/io/dr.conf new file mode 100644 index 0000000000..16cac68654 --- /dev/null +++ b/usr/src/uts/sun4u/opl/io/dr.conf @@ -0,0 +1,27 @@ +# +# 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. +# +# ident "%Z%%M% %I% %E% SMI" + +name="dr" parent="pseudo" instance=0; diff --git a/usr/src/uts/sun4u/opl/io/dr_mem.c b/usr/src/uts/sun4u/opl/io/dr_mem.c new file mode 100644 index 0000000000..0d4a415d7b --- /dev/null +++ b/usr/src/uts/sun4u/opl/io/dr_mem.c @@ -0,0 +1,2760 @@ +/* + * 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" + +/* + * DR memory support routines. + */ + +#include <sys/note.h> +#include <sys/debug.h> +#include <sys/types.h> +#include <sys/errno.h> +#include <sys/param.h> +#include <sys/dditypes.h> +#include <sys/kmem.h> +#include <sys/conf.h> +#include <sys/ddi.h> +#include <sys/sunddi.h> +#include <sys/sunndi.h> +#include <sys/ddi_impldefs.h> +#include <sys/ndi_impldefs.h> +#include <sys/sysmacros.h> +#include <sys/machsystm.h> +#include <sys/spitregs.h> +#include <sys/cpuvar.h> +#include <sys/promif.h> +#include <vm/seg_kmem.h> +#include <sys/lgrp.h> +#include <sys/platform_module.h> + +#include <vm/page.h> + +#include <sys/dr.h> +#include <sys/dr_util.h> +#include <sys/drmach.h> + +extern struct memlist *phys_install; +extern vnode_t retired_pages; + +/* TODO: push this reference below drmach line */ +extern int kcage_on; + +/* for the DR*INTERNAL_ERROR macros. see sys/dr.h. */ +static char *dr_ie_fmt = "%M% %d"; + +typedef enum { + DR_TP_INVALID = -1, + DR_TP_SAME, + DR_TP_LARGE, + DR_TP_NONRELOC, + DR_TP_FLOATING +} dr_target_pref_t; + +static int dr_post_detach_mem_unit(dr_mem_unit_t *mp); +static int dr_reserve_mem_spans(memhandle_t *mhp, + struct memlist *mlist); +static int dr_select_mem_target(dr_handle_t *hp, + dr_mem_unit_t *mp, struct memlist *ml); +static void dr_init_mem_unit_data(dr_mem_unit_t *mp); +static struct memlist *dr_memlist_del_retired_pages(struct memlist *ml); +static dr_target_pref_t dr_get_target_preference(dr_handle_t *hp, + dr_mem_unit_t *t_mp, dr_mem_unit_t *s_mp, + struct memlist *s_ml, struct memlist *x_ml, + struct memlist *b_ml); + +static int memlist_canfit(struct memlist *s_mlist, + struct memlist *t_mlist); +static int dr_del_mlist_query(struct memlist *mlist, + memquery_t *mp); +static struct memlist *dr_get_copy_mlist(struct memlist *s_ml, + struct memlist *t_ml, dr_mem_unit_t *s_mp, + dr_mem_unit_t *t_mp); +static struct memlist *dr_get_nonreloc_mlist(struct memlist *s_ml, + dr_mem_unit_t *s_mp); +static int dr_memlist_canfit(struct memlist *s_mlist, + struct memlist *t_mlist, dr_mem_unit_t *s_mp, + dr_mem_unit_t *t_mp); + +extern void page_unretire_pages(void); + +/* + * dr_mem_unit_t.sbm_flags + */ +#define DR_MFLAG_RESERVED 0x01 /* mem unit reserved for delete */ +#define DR_MFLAG_SOURCE 0x02 /* source brd of copy/rename op */ +#define DR_MFLAG_TARGET 0x04 /* target brd of copy/rename op */ +#define DR_MFLAG_RELOWNER 0x20 /* memory release (delete) owner */ +#define DR_MFLAG_RELDONE 0x40 /* memory release (delete) done */ + +/* helper macros */ +#define _ptob64(p) ((uint64_t)(p) << PAGESHIFT) +#define _b64top(b) ((pgcnt_t)((b) >> PAGESHIFT)) + +static struct memlist * +dr_get_memlist(dr_mem_unit_t *mp) +{ + struct memlist *mlist = NULL; + sbd_error_t *err; + static fn_t f = "dr_get_memlist"; + + PR_MEM("%s for %s...\n", f, mp->sbm_cm.sbdev_path); + + /* + * Return cached memlist, if present. + * This memlist will be present following an + * unconfigure (a.k.a: detach) of this memunit. + * It should only be used in the case were a configure + * is bringing this memunit back in without going + * through the disconnect and connect states. + */ + if (mp->sbm_mlist) { + PR_MEM("%s: found cached memlist\n", f); + + mlist = memlist_dup(mp->sbm_mlist); + } else { + uint64_t basepa = _ptob64(mp->sbm_basepfn); + + /* attempt to construct a memlist using phys_install */ + + /* round down to slice base address */ + basepa &= ~(mp->sbm_slice_size - 1); + + /* get a copy of phys_install to edit */ + memlist_read_lock(); + mlist = memlist_dup(phys_install); + memlist_read_unlock(); + + /* trim lower irrelevant span */ + if (mlist) + mlist = memlist_del_span(mlist, 0ull, basepa); + + /* trim upper irrelevant span */ + if (mlist) { + uint64_t endpa; + + basepa += mp->sbm_slice_size; + endpa = _ptob64(physmax + 1); + if (endpa > basepa) + mlist = memlist_del_span( + mlist, basepa, + endpa - basepa); + } + + if (mlist) { + /* successfully built a memlist */ + PR_MEM("%s: derived memlist from phys_install\n", f); + } + + /* if no mlist yet, try platform layer */ + if (!mlist) { + err = drmach_mem_get_memlist( + mp->sbm_cm.sbdev_id, &mlist); + if (err) { + DRERR_SET_C(&mp->sbm_cm.sbdev_error, &err); + mlist = NULL; /* paranoia */ + } + } + } + + PR_MEM("%s: memlist for %s\n", f, mp->sbm_cm.sbdev_path); + PR_MEMLIST_DUMP(mlist); + + return (mlist); +} + +typedef struct { + kcondvar_t cond; + kmutex_t lock; + int error; + int done; +} dr_release_mem_sync_t; + +/* + * Memory has been logically removed by the time this routine is called. + */ +static void +dr_mem_del_done(void *arg, int error) +{ + dr_release_mem_sync_t *ds = arg; + + mutex_enter(&ds->lock); + ds->error = error; + ds->done = 1; + cv_signal(&ds->cond); + mutex_exit(&ds->lock); +} + +/* + * When we reach here the memory being drained should have + * already been reserved in dr_pre_release_mem(). + * Our only task here is to kick off the "drain" and wait + * for it to finish. + */ +void +dr_release_mem(dr_common_unit_t *cp) +{ + dr_mem_unit_t *mp = (dr_mem_unit_t *)cp; + int err; + dr_release_mem_sync_t rms; + static fn_t f = "dr_release_mem"; + + /* check that this memory unit has been reserved */ + if (!(mp->sbm_flags & DR_MFLAG_RELOWNER)) { + DR_DEV_INTERNAL_ERROR(&mp->sbm_cm); + return; + } + + bzero((void *) &rms, sizeof (rms)); + + mutex_init(&rms.lock, NULL, MUTEX_DRIVER, NULL); + cv_init(&rms.cond, NULL, CV_DRIVER, NULL); + + mutex_enter(&rms.lock); + err = kphysm_del_start(mp->sbm_memhandle, + dr_mem_del_done, (void *) &rms); + if (err == KPHYSM_OK) { + /* wait for completion or interrupt */ + while (!rms.done) { + if (cv_wait_sig(&rms.cond, &rms.lock) == 0) { + /* then there is a pending UNIX signal */ + (void) kphysm_del_cancel(mp->sbm_memhandle); + + /* wait for completion */ + while (!rms.done) + cv_wait(&rms.cond, &rms.lock); + } + } + /* get the result of the memory delete operation */ + err = rms.error; + } + mutex_exit(&rms.lock); + + cv_destroy(&rms.cond); + mutex_destroy(&rms.lock); + + if (err != KPHYSM_OK) { + int e_code; + + switch (err) { + case KPHYSM_ENOWORK: + e_code = ESBD_NOERROR; + break; + + case KPHYSM_EHANDLE: + case KPHYSM_ESEQUENCE: + e_code = ESBD_INTERNAL; + break; + + case KPHYSM_ENOTVIABLE: + e_code = ESBD_MEM_NOTVIABLE; + break; + + case KPHYSM_EREFUSED: + e_code = ESBD_MEM_REFUSED; + break; + + case KPHYSM_ENONRELOC: + e_code = ESBD_MEM_NONRELOC; + break; + + case KPHYSM_ECANCELLED: + e_code = ESBD_MEM_CANCELLED; + break; + + case KPHYSM_ERESOURCE: + e_code = ESBD_MEMFAIL; + break; + + default: + cmn_err(CE_WARN, + "%s: unexpected kphysm error code %d," + " id 0x%p", + f, err, mp->sbm_cm.sbdev_id); + + e_code = ESBD_IO; + break; + } + + if (e_code != ESBD_NOERROR) { + dr_dev_err(CE_IGNORE, &mp->sbm_cm, e_code); + } + } +} + +void +dr_attach_mem(dr_handle_t *hp, dr_common_unit_t *cp) +{ + _NOTE(ARGUNUSED(hp)) + + dr_mem_unit_t *mp = (dr_mem_unit_t *)cp; + struct memlist *ml, *mc; + sbd_error_t *err; + static fn_t f = "dr_attach_mem"; + + PR_MEM("%s...\n", f); + + dr_lock_status(hp->h_bd); + err = drmach_configure(cp->sbdev_id, 0); + dr_unlock_status(hp->h_bd); + if (err) { + DRERR_SET_C(&cp->sbdev_error, &err); + return; + } + + ml = dr_get_memlist(mp); + for (mc = ml; mc; mc = mc->next) { + int rv; + sbd_error_t *err; + + rv = kphysm_add_memory_dynamic( + (pfn_t)(mc->address >> PAGESHIFT), + (pgcnt_t)(mc->size >> PAGESHIFT)); + if (rv != KPHYSM_OK) { + /* + * translate kphysm error and + * store in devlist error + */ + switch (rv) { + case KPHYSM_ERESOURCE: + rv = ESBD_NOMEM; + break; + + case KPHYSM_EFAULT: + rv = ESBD_FAULT; + break; + + default: + rv = ESBD_INTERNAL; + break; + } + + if (rv == ESBD_INTERNAL) { + DR_DEV_INTERNAL_ERROR(&mp->sbm_cm); + } else + dr_dev_err(CE_WARN, &mp->sbm_cm, rv); + break; + } + + err = drmach_mem_add_span( + mp->sbm_cm.sbdev_id, mc->address, mc->size); + if (err) { + DRERR_SET_C(&mp->sbm_cm.sbdev_error, &err); + break; + } + } + + memlist_delete(ml); + + /* back out if configure failed */ + if (mp->sbm_cm.sbdev_error != NULL) { + dr_lock_status(hp->h_bd); + err = drmach_unconfigure(cp->sbdev_id, 0); + if (err) + sbd_err_clear(&err); + dr_unlock_status(hp->h_bd); + } +} + +static struct memlist * +dr_memlist_del_retired_pages(struct memlist *mlist) +{ + page_t *pp; + pfn_t pfn; + kmutex_t *vphm; + vnode_t *vp = &retired_pages; + static fn_t f = "dr_memlist_del_retired_pages"; + + vphm = page_vnode_mutex(vp); + mutex_enter(vphm); + + PR_MEM("%s\n", f); + + if ((pp = vp->v_pages) == NULL) { + mutex_exit(vphm); + return (mlist); + } + + do { + ASSERT(pp != NULL); + /* + * page_downgrade happens after page_hashin, so we + * can't assert PAGE_SE. Just assert locked to catch + * changes to the retired vnode locking scheme. + */ + ASSERT(PAGE_LOCKED(pp)); + ASSERT(pp->p_vnode == &retired_pages); + + if (!page_trylock(pp, SE_SHARED)) + continue; + + pfn = page_pptonum(pp); + + ASSERT((pp->p_offset >> PAGESHIFT) == pfn); + /* + * Page retirement currently breaks large pages into PAGESIZE + * pages. If this changes, need to remove the assert and deal + * with different page sizes. + */ + ASSERT(pp->p_szc == 0); + + if (address_in_memlist(mlist, ptob(pfn), PAGESIZE)) { + mlist = memlist_del_span(mlist, ptob(pfn), PAGESIZE); + PR_MEM("deleted retired page 0x%lx (pfn 0x%lx) " + "from memlist\n", ptob(pfn), pfn); + } + + page_unlock(pp); + } while ((pp = pp->p_vpnext) != vp->v_pages); + + mutex_exit(vphm); + + return (mlist); +} + +#ifdef DEBUG +int dbg_retirecnt = 10; + +static void +dbg_page_retire(struct memlist *r_ml) +{ + struct memlist *t_ml; + page_t *pp, *epp; + pfn_t pfn, epfn; + struct memseg *seg; + + int dbg_retired = 0; + int dbg_skip = 10; + int dbg_seq = 1; + + if (r_ml == NULL) + return; + + for (t_ml = r_ml; (t_ml != NULL); t_ml = t_ml->next) { + pfn = _b64top(t_ml->address); + epfn = _b64top(t_ml->address + t_ml->size); + + for (seg = memsegs; seg != NULL; seg = seg->next) { + int retire = 0; + int skip = 0; + if (pfn >= seg->pages_end || epfn < seg->pages_base) + continue; + + pp = seg->pages; + if (pfn > seg->pages_base) + pp += pfn - seg->pages_base; + + epp = seg->epages; + if (epfn < seg->pages_end) + epp -= seg->pages_end - epfn; + + ASSERT(pp < epp); +#if 0 + while (pp < epp) { + if (PP_ISFREE(pp) && !page_isfaulty(pp)) { + if (retire++ < dbg_seq) { + page_settoxic(pp, + PAGE_IS_FAULTY); + page_retire(pp, + PAGE_IS_FAILING); + if (++dbg_retired >= + dbg_retirecnt) + return; + } else if (skip++ >= dbg_skip) { + skip = 0; + retire = 0; + dbg_seq++; + } + } + pp++; + } +#endif /* 0 */ + while (pp < epp) { + if (PP_ISFREE(pp)) { + if (retire++ < dbg_seq) { + page_retire(t_ml->address, + PR_OK); + if (++dbg_retired >= + dbg_retirecnt) + return; + } else if (skip++ >= dbg_skip) { + skip = 0; + retire = 0; + dbg_seq++; + } + } + pp++; + } + } + } +} +#endif + +static int +dr_move_memory(dr_handle_t *hp, dr_mem_unit_t *s_mp, dr_mem_unit_t *t_mp) +{ + int rv = -1; + time_t copytime; + drmachid_t cr_id; + dr_sr_handle_t *srhp = NULL; + dr_board_t *t_bp, *s_bp; + struct memlist *c_ml, *d_ml; + sbd_error_t *err; + static fn_t f = "dr_move_memory"; + + PR_MEM("%s: (INLINE) moving memory from %s to %s\n", + f, + s_mp->sbm_cm.sbdev_path, + t_mp->sbm_cm.sbdev_path); + + ASSERT(s_mp->sbm_flags & DR_MFLAG_SOURCE); + ASSERT(s_mp->sbm_peer == t_mp); + ASSERT(s_mp->sbm_mlist); + + ASSERT(t_mp->sbm_flags & DR_MFLAG_TARGET); + ASSERT(t_mp->sbm_peer == s_mp); + +#ifdef DEBUG + if (dbg_retirecnt) + dbg_page_retire(s_mp->sbm_mlist); +#endif + + /* + * create a memlist of spans to copy by removing + * the spans that have been deleted, if any, from + * the full source board memlist. s_mp->sbm_del_mlist + * will be NULL if there were no spans deleted from + * the source board. + */ + c_ml = memlist_dup(s_mp->sbm_mlist); + d_ml = s_mp->sbm_del_mlist; + while (d_ml != NULL) { + c_ml = memlist_del_span(c_ml, d_ml->address, d_ml->size); + d_ml = d_ml->next; + } + + /* + * Remove retired pages from the copy list. The page content + * need not be copied since the pages are no longer in use. + */ + PR_MEM("%s: copy list before removing retired pages (if any):\n", f); + PR_MEMLIST_DUMP(c_ml); + + c_ml = dr_memlist_del_retired_pages(c_ml); + + PR_MEM("%s: copy list after removing retired pages:\n", f); + PR_MEMLIST_DUMP(c_ml); + + /* + * With parallel copy, it shouldn't make a difference which + * CPU is the actual master during copy-rename since all + * CPUs participate in the parallel copy anyway. + */ + affinity_set(CPU_CURRENT); + + err = drmach_copy_rename_init( + t_mp->sbm_cm.sbdev_id, s_mp->sbm_cm.sbdev_id, c_ml, &cr_id); + if (err) { + DRERR_SET_C(&s_mp->sbm_cm.sbdev_error, &err); + affinity_clear(); + memlist_delete(c_ml); + return (-1); + } + + srhp = dr_get_sr_handle(hp); + ASSERT(srhp); + + copytime = lbolt; + + /* Quiesce the OS. */ + if (dr_suspend(srhp)) { + cmn_err(CE_WARN, "%s: failed to quiesce OS" + " for copy-rename", f); + + err = drmach_copy_rename_fini(cr_id); + if (err) { + /* + * no error is expected since the program has + * not yet run. + */ + + /* catch this in debug kernels */ + ASSERT(0); + + sbd_err_clear(&err); + } + + /* suspend error reached via hp */ + s_mp->sbm_cm.sbdev_error = hp->h_err; + hp->h_err = NULL; + goto done; + } + + drmach_copy_rename(cr_id); + + /* Resume the OS. */ + dr_resume(srhp); + + copytime = lbolt - copytime; + + if (err = drmach_copy_rename_fini(cr_id)) + goto done; + + /* + * Rename memory for lgroup. + * Source and target board numbers are packaged in arg. + */ + s_bp = s_mp->sbm_cm.sbdev_bp; + t_bp = t_mp->sbm_cm.sbdev_bp; + + lgrp_plat_config(LGRP_CONFIG_MEM_RENAME, + (uintptr_t)(s_bp->b_num | (t_bp->b_num << 16))); + + + PR_MEM("%s: copy-rename elapsed time = %ld ticks (%ld secs)\n", + f, copytime, copytime / hz); + + rv = 0; +done: + if (srhp) + dr_release_sr_handle(srhp); + if (err) + DRERR_SET_C(&s_mp->sbm_cm.sbdev_error, &err); + affinity_clear(); + + return (rv); +} + +/* + * If detaching node contains memory that is "non-permanent" + * then the memory adr's are simply cleared. If the memory + * is non-relocatable, then do a copy-rename. + */ +void +dr_detach_mem(dr_handle_t *hp, dr_common_unit_t *cp) +{ + int rv = 0; + dr_mem_unit_t *s_mp = (dr_mem_unit_t *)cp; + dr_mem_unit_t *t_mp; + dr_state_t state; + static fn_t f = "dr_detach_mem"; + + PR_MEM("%s...\n", f); + + /* lookup target mem unit and target board structure, if any */ + if (s_mp->sbm_flags & DR_MFLAG_SOURCE) { + t_mp = s_mp->sbm_peer; + ASSERT(t_mp != NULL); + ASSERT(t_mp->sbm_peer == s_mp); + } else { + t_mp = NULL; + } + + /* verify mem unit's state is UNREFERENCED */ + state = s_mp->sbm_cm.sbdev_state; + if (state != DR_STATE_UNREFERENCED) { + dr_dev_err(CE_IGNORE, &s_mp->sbm_cm, ESBD_STATE); + return; + } + + /* verify target mem unit's state is UNREFERENCED, if any */ + if (t_mp != NULL) { + state = t_mp->sbm_cm.sbdev_state; + if (state != DR_STATE_UNREFERENCED) { + dr_dev_err(CE_IGNORE, &t_mp->sbm_cm, ESBD_STATE); + return; + } + } + + /* + * If there is no target board (no copy/rename was needed), then + * we're done! + */ + if (t_mp == NULL) { + sbd_error_t *err; + /* + * Reprogram interconnect hardware and disable + * memory controllers for memory node that's going away. + */ + + err = drmach_mem_disable(s_mp->sbm_cm.sbdev_id); + if (err) { + DRERR_SET_C(&s_mp->sbm_cm.sbdev_error, &err); + rv = -1; + } + } else { + rv = dr_move_memory(hp, s_mp, t_mp); + PR_MEM("%s: %s memory COPY-RENAME (board %d -> %d)\n", + f, + rv ? "FAILED" : "COMPLETED", + s_mp->sbm_cm.sbdev_bp->b_num, + t_mp->sbm_cm.sbdev_bp->b_num); + + if (rv != 0) + (void) dr_cancel_mem(s_mp); + } + + if (rv == 0) { + sbd_error_t *err; + + dr_lock_status(hp->h_bd); + err = drmach_unconfigure(s_mp->sbm_cm.sbdev_id, 0); + dr_unlock_status(hp->h_bd); + if (err) + sbd_err_clear(&err); + } +} + +/* + * This routine acts as a wrapper for kphysm_del_span_query in order to + * support potential memory holes in a board's physical address space. + * It calls kphysm_del_span_query for each node in a memlist and accumulates + * the results in *mp. + */ +static int +dr_del_mlist_query(struct memlist *mlist, memquery_t *mp) +{ + struct memlist *ml; + int rv = 0; + + + if (mlist == NULL) + cmn_err(CE_WARN, "dr_del_mlist_query: mlist=NULL\n"); + + mp->phys_pages = 0; + mp->managed = 0; + mp->nonrelocatable = 0; + mp->first_nonrelocatable = (pfn_t)-1; /* XXX */ + mp->last_nonrelocatable = 0; + + for (ml = mlist; ml; ml = ml->next) { + memquery_t mq; + + rv = kphysm_del_span_query( + _b64top(ml->address), _b64top(ml->size), &mq); + if (rv) + break; + + mp->phys_pages += mq.phys_pages; + mp->managed += mq.managed; + mp->nonrelocatable += mq.nonrelocatable; + + if (mq.nonrelocatable != 0) { + if (mq.first_nonrelocatable < mp->first_nonrelocatable) + mp->first_nonrelocatable = + mq.first_nonrelocatable; + if (mq.last_nonrelocatable > mp->last_nonrelocatable) + mp->last_nonrelocatable = + mq.last_nonrelocatable; + } + } + + if (mp->nonrelocatable == 0) + mp->first_nonrelocatable = 0; /* XXX */ + + return (rv); +} + +/* + * NOTE: This routine is only partially smart about multiple + * mem-units. Need to make mem-status structure smart + * about them also. + */ +int +dr_mem_status(dr_handle_t *hp, dr_devset_t devset, sbd_dev_stat_t *dsp) +{ + int m, mix; + memdelstat_t mdst; + memquery_t mq; + dr_board_t *bp; + dr_mem_unit_t *mp; + sbd_mem_stat_t *msp; + static fn_t f = "dr_mem_status"; + + bp = hp->h_bd; + devset &= DR_DEVS_PRESENT(bp); + + for (m = mix = 0; m < MAX_MEM_UNITS_PER_BOARD; m++) { + int rv; + sbd_error_t *err; + drmach_status_t pstat; + dr_mem_unit_t *p_mp; + + if (DEVSET_IN_SET(devset, SBD_COMP_MEM, m) == 0) + continue; + + mp = dr_get_mem_unit(bp, m); + + if (mp->sbm_cm.sbdev_state == DR_STATE_EMPTY) { + /* present, but not fully initialized */ + continue; + } + + if (mp->sbm_cm.sbdev_id == (drmachid_t)0) + continue; + + /* fetch platform status */ + err = drmach_status(mp->sbm_cm.sbdev_id, &pstat); + if (err) { + DRERR_SET_C(&mp->sbm_cm.sbdev_error, &err); + continue; + } + + msp = &dsp->d_mem; + bzero((caddr_t)msp, sizeof (*msp)); + + strncpy(msp->ms_cm.c_id.c_name, pstat.type, + sizeof (msp->ms_cm.c_id.c_name)); + msp->ms_cm.c_id.c_type = mp->sbm_cm.sbdev_type; + msp->ms_cm.c_id.c_unit = SBD_NULL_UNIT; + msp->ms_cm.c_cond = mp->sbm_cm.sbdev_cond; + msp->ms_cm.c_busy = mp->sbm_cm.sbdev_busy | pstat.busy; + msp->ms_cm.c_time = mp->sbm_cm.sbdev_time; + msp->ms_cm.c_ostate = mp->sbm_cm.sbdev_ostate; + + msp->ms_totpages = mp->sbm_npages; + msp->ms_basepfn = mp->sbm_basepfn; + msp->ms_pageslost = mp->sbm_pageslost; + msp->ms_cage_enabled = kcage_on; + + if (mp->sbm_flags & DR_MFLAG_RESERVED) + p_mp = mp->sbm_peer; + else + p_mp = NULL; + + if (p_mp == NULL) { + msp->ms_peer_is_target = 0; + msp->ms_peer_ap_id[0] = '\0'; + } else if (p_mp->sbm_flags & DR_MFLAG_RESERVED) { + char *path = kmem_alloc(MAXPATHLEN, KM_SLEEP); + char *minor; + + /* + * b_dip doesn't have to be held for ddi_pathname() + * because the board struct (dr_board_t) will be + * destroyed before b_dip detaches. + */ + (void) ddi_pathname(bp->b_dip, path); + minor = strchr(p_mp->sbm_cm.sbdev_path, ':'); + + snprintf(msp->ms_peer_ap_id, + sizeof (msp->ms_peer_ap_id), "%s%s", + path, (minor == NULL) ? "" : minor); + + kmem_free(path, MAXPATHLEN); + + if (p_mp->sbm_flags & DR_MFLAG_TARGET) + msp->ms_peer_is_target = 1; + } + + if (mp->sbm_flags & DR_MFLAG_RELOWNER) + rv = kphysm_del_status(mp->sbm_memhandle, &mdst); + else + rv = KPHYSM_EHANDLE; /* force 'if' to fail */ + + if (rv == KPHYSM_OK) { + /* + * Any pages above managed is "free", + * i.e. it's collected. + */ + msp->ms_detpages += (uint_t)(mdst.collected + + mdst.phys_pages - mdst.managed); + } else { + /* + * If we're UNREFERENCED or UNCONFIGURED, + * then the number of detached pages is + * however many pages are on the board. + * I.e. detached = not in use by OS. + */ + switch (msp->ms_cm.c_ostate) { + /* + * changed to use cfgadm states + * + * was: + * case DR_STATE_UNREFERENCED: + * case DR_STATE_UNCONFIGURED: + */ + case SBD_STAT_UNCONFIGURED: + msp->ms_detpages = msp->ms_totpages; + break; + + default: + break; + } + } + + /* + * kphysm_del_span_query can report non-reloc pages = total + * pages for memory that is not yet configured + */ + if (mp->sbm_cm.sbdev_state != DR_STATE_UNCONFIGURED) { + struct memlist *ml; + + ml = dr_get_memlist(mp); + rv = ml ? dr_del_mlist_query(ml, &mq) : -1; + memlist_delete(ml); + + if (rv == KPHYSM_OK) { + msp->ms_managed_pages = mq.managed; + msp->ms_noreloc_pages = mq.nonrelocatable; + msp->ms_noreloc_first = + mq.first_nonrelocatable; + msp->ms_noreloc_last = + mq.last_nonrelocatable; + msp->ms_cm.c_sflags = 0; + if (mq.nonrelocatable) { + SBD_SET_SUSPEND(SBD_CMD_UNCONFIGURE, + msp->ms_cm.c_sflags); + } + } else { + PR_MEM("%s: kphysm_del_span_query() = %d\n", + f, rv); + } + } + + /* + * Check source unit state during copy-rename + */ + if ((mp->sbm_flags & DR_MFLAG_SOURCE) && + (mp->sbm_cm.sbdev_state == DR_STATE_UNREFERENCED || + mp->sbm_cm.sbdev_state == DR_STATE_RELEASE)) + msp->ms_cm.c_ostate = SBD_STAT_CONFIGURED; + + mix++; + dsp++; + } + + return (mix); +} + +int +dr_pre_attach_mem(dr_handle_t *hp, dr_common_unit_t **devlist, int devnum) +{ + _NOTE(ARGUNUSED(hp)) + + int err_flag = 0; + int d; + sbd_error_t *err; + static fn_t f = "dr_pre_attach_mem"; + + PR_MEM("%s...\n", f); + + for (d = 0; d < devnum; d++) { + dr_mem_unit_t *mp = (dr_mem_unit_t *)devlist[d]; + dr_state_t state; + + cmn_err(CE_CONT, "OS configure %s", mp->sbm_cm.sbdev_path); + + state = mp->sbm_cm.sbdev_state; + switch (state) { + case DR_STATE_UNCONFIGURED: + PR_MEM("%s: recovering from UNCONFIG for %s\n", + f, + mp->sbm_cm.sbdev_path); + + /* use memlist cached by dr_post_detach_mem_unit */ + ASSERT(mp->sbm_mlist != NULL); + PR_MEM("%s: re-configuring cached memlist for %s:\n", + f, mp->sbm_cm.sbdev_path); + PR_MEMLIST_DUMP(mp->sbm_mlist); + + /* kphysm del handle should be have been freed */ + ASSERT((mp->sbm_flags & DR_MFLAG_RELOWNER) == 0); + + /*FALLTHROUGH*/ + + case DR_STATE_CONNECTED: + PR_MEM("%s: reprogramming mem hardware on %s\n", + f, mp->sbm_cm.sbdev_bp->b_path); + + PR_MEM("%s: enabling %s\n", + f, mp->sbm_cm.sbdev_path); + + err = drmach_mem_enable(mp->sbm_cm.sbdev_id); + if (err) { + DRERR_SET_C(&mp->sbm_cm.sbdev_error, &err); + err_flag = 1; + } + break; + + default: + dr_dev_err(CE_WARN, &mp->sbm_cm, ESBD_STATE); + err_flag = 1; + break; + } + + /* exit for loop if error encountered */ + if (err_flag) + break; + } + + return (err_flag ? -1 : 0); +} + +int +dr_post_attach_mem(dr_handle_t *hp, dr_common_unit_t **devlist, int devnum) +{ + _NOTE(ARGUNUSED(hp)) + + int d; + static fn_t f = "dr_post_attach_mem"; + + PR_MEM("%s...\n", f); + + for (d = 0; d < devnum; d++) { + dr_mem_unit_t *mp = (dr_mem_unit_t *)devlist[d]; + struct memlist *mlist, *ml; + + mlist = dr_get_memlist(mp); + if (mlist == NULL) { + dr_dev_err(CE_WARN, &mp->sbm_cm, ESBD_MEMFAIL); + continue; + } + + /* + * Verify the memory really did successfully attach + * by checking for its existence in phys_install. + */ + memlist_read_lock(); + if (memlist_intersect(phys_install, mlist) == 0) { + memlist_read_unlock(); + + DR_DEV_INTERNAL_ERROR(&mp->sbm_cm); + + PR_MEM("%s: %s memlist not in phys_install", + f, mp->sbm_cm.sbdev_path); + + memlist_delete(mlist); + continue; + } + memlist_read_unlock(); + + for (ml = mlist; ml != NULL; ml = ml->next) { + sbd_error_t *err; + + err = drmach_mem_add_span( + mp->sbm_cm.sbdev_id, + ml->address, + ml->size); + if (err) + DRERR_SET_C(&mp->sbm_cm.sbdev_error, &err); + } + + memlist_delete(mlist); + + /* + * Destroy cached memlist, if any. + * There will be a cached memlist in sbm_mlist if + * this board is being configured directly after + * an unconfigure. + * To support this transition, dr_post_detach_mem + * left a copy of the last known memlist in sbm_mlist. + * This memlist could differ from any derived from + * hardware if while this memunit was last configured + * the system detected and deleted bad pages from + * phys_install. The location of those bad pages + * will be reflected in the cached memlist. + */ + if (mp->sbm_mlist) { + memlist_delete(mp->sbm_mlist); + mp->sbm_mlist = NULL; + } + } + + return (0); +} + +int +dr_pre_detach_mem(dr_handle_t *hp, dr_common_unit_t **devlist, int devnum) +{ + _NOTE(ARGUNUSED(hp)) + + int d; + + for (d = 0; d < devnum; d++) { + dr_mem_unit_t *mp = (dr_mem_unit_t *)devlist[d]; + + cmn_err(CE_CONT, "OS unconfigure %s", mp->sbm_cm.sbdev_path); + } + + return (0); +} + +int +dr_post_detach_mem(dr_handle_t *hp, dr_common_unit_t **devlist, int devnum) +{ + _NOTE(ARGUNUSED(hp)) + + int d, rv; + static fn_t f = "dr_post_detach_mem"; + + PR_MEM("%s...\n", f); + + rv = 0; + for (d = 0; d < devnum; d++) { + dr_mem_unit_t *mp = (dr_mem_unit_t *)devlist[d]; + + ASSERT(mp->sbm_cm.sbdev_bp == hp->h_bd); + + if (dr_post_detach_mem_unit(mp)) + rv = -1; + } + + return (rv); +} + +static void +dr_add_memory_spans(dr_mem_unit_t *mp, struct memlist *ml) +{ + static fn_t f = "dr_add_memory_spans"; + + PR_MEM("%s...", f); + PR_MEMLIST_DUMP(ml); + +#ifdef DEBUG + memlist_read_lock(); + if (memlist_intersect(phys_install, ml)) { + PR_MEM("%s:WARNING: memlist intersects with phys_install\n", f); + } + memlist_read_unlock(); +#endif + + for (; ml; ml = ml->next) { + pfn_t base; + pgcnt_t npgs; + int rv; + sbd_error_t *err; + + base = _b64top(ml->address); + npgs = _b64top(ml->size); + + rv = kphysm_add_memory_dynamic(base, npgs); + + err = drmach_mem_add_span( + mp->sbm_cm.sbdev_id, + ml->address, + ml->size); + + if (err) + DRERR_SET_C(&mp->sbm_cm.sbdev_error, &err); + + if (rv != KPHYSM_OK) { + cmn_err(CE_WARN, "%s:" + " unexpected kphysm_add_memory_dynamic" + " return value %d;" + " basepfn=0x%lx, npages=%ld\n", + f, rv, base, npgs); + + continue; + } + } +} + +static int +dr_post_detach_mem_unit(dr_mem_unit_t *s_mp) +{ + uint64_t sz = s_mp->sbm_slice_size; + uint64_t sm = sz - 1; + /* old and new below refer to PAs before and after copy-rename */ + uint64_t s_old_basepa, s_new_basepa; + uint64_t t_old_basepa, t_new_basepa; + dr_mem_unit_t *t_mp, *x_mp; + drmach_mem_info_t minfo; + struct memlist *ml; + struct memlist *t_excess_mlist; + int rv; + int s_excess_mem_deleted = 0; + sbd_error_t *err; + static fn_t f = "dr_post_detach_mem_unit"; + + PR_MEM("%s...\n", f); + + /* s_mp->sbm_del_mlist could be NULL, meaning no deleted spans */ + PR_MEM("%s: %s: deleted memlist (EMPTY maybe okay):\n", + f, s_mp->sbm_cm.sbdev_path); + PR_MEMLIST_DUMP(s_mp->sbm_del_mlist); + + /* sanity check */ + ASSERT(s_mp->sbm_del_mlist == NULL || + (s_mp->sbm_flags & DR_MFLAG_RELDONE) != 0); + + if (s_mp->sbm_flags & DR_MFLAG_SOURCE) { + t_mp = s_mp->sbm_peer; + ASSERT(t_mp != NULL); + ASSERT(t_mp->sbm_flags & DR_MFLAG_TARGET); + ASSERT(t_mp->sbm_peer == s_mp); + + ASSERT(t_mp->sbm_flags & DR_MFLAG_RELDONE); + ASSERT(t_mp->sbm_del_mlist); + + PR_MEM("%s: target %s: deleted memlist:\n", + f, t_mp->sbm_cm.sbdev_path); + PR_MEMLIST_DUMP(t_mp->sbm_del_mlist); + } else { + /* this is no target unit */ + t_mp = NULL; + } + + /* + * Verify the memory really did successfully detach + * by checking for its non-existence in phys_install. + */ + rv = 0; + memlist_read_lock(); + if (s_mp->sbm_flags & DR_MFLAG_RELDONE) { + x_mp = s_mp; + rv = memlist_intersect(phys_install, x_mp->sbm_del_mlist); + } + if (rv == 0 && t_mp && (t_mp->sbm_flags & DR_MFLAG_RELDONE)) { + x_mp = t_mp; + rv = memlist_intersect(phys_install, x_mp->sbm_del_mlist); + } + memlist_read_unlock(); + + if (rv) { + /* error: memlist still in phys_install */ + DR_DEV_INTERNAL_ERROR(&x_mp->sbm_cm); + } + + /* + * clean mem unit state and bail out if an error has been recorded. + */ + rv = 0; + if (s_mp->sbm_cm.sbdev_error) { + PR_MEM("%s: %s flags=%x", f, + s_mp->sbm_cm.sbdev_path, s_mp->sbm_flags); + DR_DEV_CLR_UNREFERENCED(&s_mp->sbm_cm); + DR_DEV_CLR_RELEASED(&s_mp->sbm_cm); + dr_device_transition(&s_mp->sbm_cm, DR_STATE_CONFIGURED); + rv = -1; + } + if (t_mp != NULL && t_mp->sbm_cm.sbdev_error != NULL) { + PR_MEM("%s: %s flags=%x", f, + s_mp->sbm_cm.sbdev_path, s_mp->sbm_flags); + DR_DEV_CLR_UNREFERENCED(&t_mp->sbm_cm); + DR_DEV_CLR_RELEASED(&t_mp->sbm_cm); + dr_device_transition(&t_mp->sbm_cm, DR_STATE_CONFIGURED); + rv = -1; + } + if (rv) + goto cleanup; + + s_old_basepa = _ptob64(s_mp->sbm_basepfn); + err = drmach_mem_get_info(s_mp->sbm_cm.sbdev_id, &minfo); + ASSERT(err == NULL); + s_new_basepa = minfo.mi_basepa; + + PR_MEM("%s:s_old_basepa: 0x%lx\n", f, s_old_basepa); + PR_MEM("%s:s_new_basepa: 0x%lx\n", f, s_new_basepa); + + if (t_mp != NULL) { + struct memlist *s_copy_mlist; + + t_old_basepa = _ptob64(t_mp->sbm_basepfn); + err = drmach_mem_get_info(t_mp->sbm_cm.sbdev_id, &minfo); + ASSERT(err == NULL); + t_new_basepa = minfo.mi_basepa; + + PR_MEM("%s:t_old_basepa: 0x%lx\n", f, t_old_basepa); + PR_MEM("%s:t_new_basepa: 0x%lx\n", f, t_new_basepa); + + /* + * Construct copy list with original source addresses. + * Used to add back excess target mem. + */ + s_copy_mlist = memlist_dup(s_mp->sbm_mlist); + for (ml = s_mp->sbm_del_mlist; ml; ml = ml->next) { + s_copy_mlist = memlist_del_span(s_copy_mlist, + ml->address, ml->size); + } + + PR_MEM("%s: source copy list:\n:", f); + PR_MEMLIST_DUMP(s_copy_mlist); + + /* + * We had to swap mem-units, so update + * memlists accordingly with new base + * addresses. + */ + for (ml = t_mp->sbm_mlist; ml; ml = ml->next) { + ml->address -= t_old_basepa; + ml->address += t_new_basepa; + } + + /* + * There is no need to explicitly rename the target delete + * memlist, because sbm_del_mlist and sbm_mlist always + * point to the same memlist for a copy/rename operation. + */ + ASSERT(t_mp->sbm_del_mlist == t_mp->sbm_mlist); + + PR_MEM("%s: renamed target memlist and delete memlist:\n", f); + PR_MEMLIST_DUMP(t_mp->sbm_mlist); + + for (ml = s_mp->sbm_mlist; ml; ml = ml->next) { + ml->address -= s_old_basepa; + ml->address += s_new_basepa; + } + + PR_MEM("%s: renamed source memlist:\n", f); + PR_MEMLIST_DUMP(s_mp->sbm_mlist); + + /* + * Keep track of dynamically added segments + * since they cannot be split if we need to delete + * excess source memory later for this board. + */ + if (t_mp->sbm_dyn_segs) + memlist_delete(t_mp->sbm_dyn_segs); + t_mp->sbm_dyn_segs = s_mp->sbm_dyn_segs; + s_mp->sbm_dyn_segs = NULL; + + /* + * Add back excess target memory. + * Subtract out the portion of the target memory + * node that was taken over by the source memory + * node. + */ + t_excess_mlist = memlist_dup(t_mp->sbm_mlist); + for (ml = s_copy_mlist; ml; ml = ml->next) { + t_excess_mlist = + memlist_del_span(t_excess_mlist, + ml->address, ml->size); + } + + /* + * Update dynamically added segs + */ + for (ml = s_mp->sbm_del_mlist; ml; ml = ml->next) { + t_mp->sbm_dyn_segs = + memlist_del_span(t_mp->sbm_dyn_segs, + ml->address, ml->size); + } + for (ml = t_excess_mlist; ml; ml = ml->next) { + t_mp->sbm_dyn_segs = + memlist_cat_span(t_mp->sbm_dyn_segs, + ml->address, ml->size); + } + PR_MEM("%s: %s: updated dynamic seg list:\n", + f, t_mp->sbm_cm.sbdev_path); + PR_MEMLIST_DUMP(t_mp->sbm_dyn_segs); + + if (t_excess_mlist != NULL) { + /* + * After the small <-> big copy-rename, + * the original address space for the + * source board may have excess to be + * deleted. This is a case different + * from the big->small excess source + * memory case listed below. + * Remove s_mp->sbm_del_mlist from + * the kernel cage glist. + */ + for (ml = s_mp->sbm_del_mlist; ml; + ml = ml->next) { + PR_MEM("%s: delete small<->big copy-" + "rename source excess memory", f); + PR_MEMLIST_DUMP(ml); + + err = drmach_mem_del_span( + s_mp->sbm_cm.sbdev_id, + ml->address, ml->size); + if (err) + DRERR_SET_C(&s_mp-> + sbm_cm.sbdev_error, &err); + ASSERT(err == NULL); + } + + /* + * mark sbm_del_mlist as been deleted so that + * we won't end up to delete it twice later + * from the span list + */ + s_excess_mem_deleted = 1; + + PR_MEM("%s: adding back remaining portion" + " of %s, memlist:\n", + f, t_mp->sbm_cm.sbdev_path); + PR_MEMLIST_DUMP(t_excess_mlist); + + dr_add_memory_spans(s_mp, t_excess_mlist); + memlist_delete(t_excess_mlist); + } + memlist_delete(s_copy_mlist); + +#ifdef DEBUG + /* + * s_mp->sbm_del_mlist may still needed + */ + PR_MEM("%s: source delete memeory flag %d", + f, s_excess_mem_deleted); + PR_MEM("%s: source delete memlist", f); + PR_MEMLIST_DUMP(s_mp->sbm_del_mlist); +#endif + + } + + if (t_mp != NULL) { + /* delete target's entire address space */ + err = drmach_mem_del_span( + t_mp->sbm_cm.sbdev_id, t_old_basepa & ~ sm, sz); + if (err) + DRERR_SET_C(&t_mp->sbm_cm.sbdev_error, &err); + ASSERT(err == NULL); + + /* + * After the copy/rename, the original address space + * for the source board (which is now located on the + * target board) may now have some excess to be deleted. + * Those excess memory on the source board are kept in + * source board's sbm_del_mlist + */ + for (ml = s_mp->sbm_del_mlist; !s_excess_mem_deleted && ml; + ml = ml->next) { + PR_MEM("%s: delete source excess memory", f); + PR_MEMLIST_DUMP(ml); + + err = drmach_mem_del_span(s_mp->sbm_cm.sbdev_id, + ml->address, ml->size); + if (err) + DRERR_SET_C(&s_mp->sbm_cm.sbdev_error, &err); + ASSERT(err == NULL); + } + + } else { + /* delete board's entire address space */ + err = drmach_mem_del_span(s_mp->sbm_cm.sbdev_id, + s_old_basepa & ~ sm, sz); + if (err) + DRERR_SET_C(&s_mp->sbm_cm.sbdev_error, &err); + ASSERT(err == NULL); + } + +cleanup: + /* clean up target mem unit */ + if (t_mp != NULL) { + memlist_delete(t_mp->sbm_del_mlist); + /* no need to delete sbm_mlist, it shares sbm_del_mlist */ + + t_mp->sbm_del_mlist = NULL; + t_mp->sbm_mlist = NULL; + t_mp->sbm_peer = NULL; + t_mp->sbm_flags = 0; + t_mp->sbm_cm.sbdev_busy = 0; + dr_init_mem_unit_data(t_mp); + + } + if (t_mp != NULL && t_mp->sbm_cm.sbdev_error == NULL) { + /* + * now that copy/rename has completed, undo this + * work that was done in dr_release_mem_done. + */ + DR_DEV_CLR_UNREFERENCED(&t_mp->sbm_cm); + DR_DEV_CLR_RELEASED(&t_mp->sbm_cm); + dr_device_transition(&t_mp->sbm_cm, DR_STATE_CONFIGURED); + } + + /* + * clean up (source) board's mem unit structure. + * NOTE: sbm_mlist is retained if no error has been record (in other + * words, when s_mp->sbm_cm.sbdev_error is NULL). This memlist is + * referred to elsewhere as the cached memlist. The cached memlist + * is used to re-attach (configure back in) this memunit from the + * unconfigured state. The memlist is retained because it may + * represent bad pages that were detected while the memory was + * configured into the OS. The OS deletes bad pages from phys_install. + * Those deletes, if any, will be represented in the cached mlist. + */ + if (s_mp->sbm_del_mlist && s_mp->sbm_del_mlist != s_mp->sbm_mlist) + memlist_delete(s_mp->sbm_del_mlist); + + if (s_mp->sbm_cm.sbdev_error && s_mp->sbm_mlist) { + memlist_delete(s_mp->sbm_mlist); + s_mp->sbm_mlist = NULL; + } + + if (s_mp->sbm_dyn_segs != NULL && s_mp->sbm_cm.sbdev_error == 0) { + memlist_delete(s_mp->sbm_dyn_segs); + s_mp->sbm_dyn_segs = NULL; + } + + s_mp->sbm_del_mlist = NULL; + s_mp->sbm_peer = NULL; + s_mp->sbm_flags = 0; + s_mp->sbm_cm.sbdev_busy = 0; + dr_init_mem_unit_data(s_mp); + + PR_MEM("%s: cached memlist for %s:", f, s_mp->sbm_cm.sbdev_path); + PR_MEMLIST_DUMP(s_mp->sbm_mlist); + + return (0); +} + +/* + * Successful return from this function will have the memory + * handle in bp->b_dev[..mem-unit...].sbm_memhandle allocated + * and waiting. This routine's job is to select the memory that + * actually has to be released (detached) which may not necessarily + * be the same memory node that came in in devlist[], + * i.e. a copy-rename is needed. + */ +int +dr_pre_release_mem(dr_handle_t *hp, dr_common_unit_t **devlist, int devnum) +{ + int d; + int err_flag = 0; + static fn_t f = "dr_pre_release_mem"; + + PR_MEM("%s...\n", f); + + for (d = 0; d < devnum; d++) { + dr_mem_unit_t *mp = (dr_mem_unit_t *)devlist[d]; + int rv; + memquery_t mq; + struct memlist *ml; + + if (mp->sbm_cm.sbdev_error) { + err_flag = 1; + continue; + } else if (!kcage_on) { + dr_dev_err(CE_WARN, &mp->sbm_cm, ESBD_KCAGE_OFF); + err_flag = 1; + continue; + } + + if (mp->sbm_flags & DR_MFLAG_RESERVED) { + /* + * Board is currently involved in a delete + * memory operation. Can't detach this guy until + * that operation completes. + */ + dr_dev_err(CE_WARN, &mp->sbm_cm, ESBD_INVAL); + err_flag = 1; + break; + } + + /* flags should be clean at this time */ + ASSERT(mp->sbm_flags == 0); + + ASSERT(mp->sbm_mlist == NULL); + ASSERT(mp->sbm_del_mlist == NULL); + if (mp->sbm_mlist != NULL) { + memlist_delete(mp->sbm_mlist); + mp->sbm_mlist = NULL; + } + + ml = dr_get_memlist(mp); + if (ml == NULL) { + err_flag = 1; + PR_MEM("%s: no memlist found for %s\n", + f, mp->sbm_cm.sbdev_path); + continue; + } + + /* + * Check whether the detaching memory requires a + * copy-rename. + */ + ASSERT(mp->sbm_npages != 0); + rv = dr_del_mlist_query(ml, &mq); + if (rv != KPHYSM_OK) { + memlist_delete(ml); + DR_DEV_INTERNAL_ERROR(&mp->sbm_cm); + err_flag = 1; + break; + } + + if (mq.nonrelocatable != 0) { + if (!(dr_cmd_flags(hp) & + (SBD_FLAG_FORCE | SBD_FLAG_QUIESCE_OKAY))) { + memlist_delete(ml); + /* caller wasn't prompted for a suspend */ + dr_dev_err(CE_WARN, &mp->sbm_cm, + ESBD_QUIESCE_REQD); + err_flag = 1; + break; + } + } + + /* allocate a kphysm handle */ + rv = kphysm_del_gethandle(&mp->sbm_memhandle); + if (rv != KPHYSM_OK) { + memlist_delete(ml); + + DR_DEV_INTERNAL_ERROR(&mp->sbm_cm); + err_flag = 1; + break; + } + mp->sbm_flags |= DR_MFLAG_RELOWNER; + + if ((mq.nonrelocatable != 0) || + dr_reserve_mem_spans(&mp->sbm_memhandle, ml)) { + /* + * Either the detaching memory node contains + * non-reloc memory or we failed to reserve the + * detaching memory node (which did _not_ have + * any non-reloc memory, i.e. some non-reloc mem + * got onboard). + */ + + if (dr_select_mem_target(hp, mp, ml)) { + int rv; + + /* + * We had no luck locating a target + * memory node to be the recipient of + * the non-reloc memory on the node + * we're trying to detach. + * Clean up be disposing the mem handle + * and the mem list. + */ + rv = kphysm_del_release(mp->sbm_memhandle); + if (rv != KPHYSM_OK) { + /* + * can do nothing but complain + * and hope helpful for debug + */ + cmn_err(CE_WARN, "%s: unexpected" + " kphysm_del_release return" + " value %d", + f, rv); + } + mp->sbm_flags &= ~DR_MFLAG_RELOWNER; + + memlist_delete(ml); + + /* make sure sbm_flags is clean */ + ASSERT(mp->sbm_flags == 0); + + dr_dev_err(CE_WARN, + &mp->sbm_cm, ESBD_NO_TARGET); + + err_flag = 1; + break; + } + + /* + * ml is not memlist_delete'd here because + * it has been assigned to mp->sbm_mlist + * by dr_select_mem_target. + */ + } else { + /* no target needed to detach this board */ + mp->sbm_flags |= DR_MFLAG_RESERVED; + mp->sbm_peer = NULL; + mp->sbm_del_mlist = ml; + mp->sbm_mlist = ml; + mp->sbm_cm.sbdev_busy = 1; + } +#ifdef DEBUG + ASSERT(mp->sbm_mlist != NULL); + + if (mp->sbm_flags & DR_MFLAG_SOURCE) { + PR_MEM("%s: release of %s requires copy/rename;" + " selected target board %s\n", + f, + mp->sbm_cm.sbdev_path, + mp->sbm_peer->sbm_cm.sbdev_path); + } else { + PR_MEM("%s: copy/rename not required to release %s\n", + f, mp->sbm_cm.sbdev_path); + } + + ASSERT(mp->sbm_flags & DR_MFLAG_RELOWNER); + ASSERT(mp->sbm_flags & DR_MFLAG_RESERVED); +#endif + } + + return (err_flag ? -1 : 0); +} + +void +dr_release_mem_done(dr_common_unit_t *cp) +{ + dr_mem_unit_t *s_mp = (dr_mem_unit_t *)cp; + dr_mem_unit_t *t_mp, *mp; + int rv; + static fn_t f = "dr_release_mem_done"; + + /* + * This unit will be flagged with DR_MFLAG_SOURCE, if it + * has a target unit. + */ + if (s_mp->sbm_flags & DR_MFLAG_SOURCE) { + t_mp = s_mp->sbm_peer; + ASSERT(t_mp != NULL); + ASSERT(t_mp->sbm_peer == s_mp); + ASSERT(t_mp->sbm_flags & DR_MFLAG_TARGET); + ASSERT(t_mp->sbm_flags & DR_MFLAG_RESERVED); + } else { + /* this is no target unit */ + t_mp = NULL; + } + + /* free delete handle */ + ASSERT(s_mp->sbm_flags & DR_MFLAG_RELOWNER); + ASSERT(s_mp->sbm_flags & DR_MFLAG_RESERVED); + rv = kphysm_del_release(s_mp->sbm_memhandle); + if (rv != KPHYSM_OK) { + /* + * can do nothing but complain + * and hope helpful for debug + */ + cmn_err(CE_WARN, "%s: unexpected kphysm_del_release" + " return value %d", f, rv); + } + s_mp->sbm_flags &= ~DR_MFLAG_RELOWNER; + + /* + * If an error was encountered during release, clean up + * the source (and target, if present) unit data. + */ +/* XXX Can we know that sbdev_error was encountered during release? */ + if (s_mp->sbm_cm.sbdev_error != NULL) { + PR_MEM("%s: %s: error %d noted\n", + f, + s_mp->sbm_cm.sbdev_path, + s_mp->sbm_cm.sbdev_error->e_code); + + if (t_mp != NULL) { + ASSERT(t_mp->sbm_del_mlist == t_mp->sbm_mlist); + t_mp->sbm_del_mlist = NULL; + + if (t_mp->sbm_mlist != NULL) { + memlist_delete(t_mp->sbm_mlist); + t_mp->sbm_mlist = NULL; + } + + t_mp->sbm_peer = NULL; + t_mp->sbm_flags = 0; + t_mp->sbm_cm.sbdev_busy = 0; + } + + if (s_mp->sbm_del_mlist != s_mp->sbm_mlist) + memlist_delete(s_mp->sbm_del_mlist); + s_mp->sbm_del_mlist = NULL; + + if (s_mp->sbm_mlist != NULL) { + memlist_delete(s_mp->sbm_mlist); + s_mp->sbm_mlist = NULL; + } + + s_mp->sbm_peer = NULL; + s_mp->sbm_flags = 0; + s_mp->sbm_cm.sbdev_busy = 0; + + /* bail out */ + return; + } + + DR_DEV_SET_RELEASED(&s_mp->sbm_cm); + dr_device_transition(&s_mp->sbm_cm, DR_STATE_RELEASE); + + if (t_mp != NULL) { + /* + * the kphysm delete operation that drained the source + * board also drained this target board. Since the source + * board drain is now known to have succeeded, we know this + * target board is drained too. + * + * because DR_DEV_SET_RELEASED and dr_device_transition + * is done here, the dr_release_dev_done should not + * fail. + */ + DR_DEV_SET_RELEASED(&t_mp->sbm_cm); + dr_device_transition(&t_mp->sbm_cm, DR_STATE_RELEASE); + + /* + * NOTE: do not transition target's board state, + * even if the mem-unit was the last configure + * unit of the board. When copy/rename completes + * this mem-unit will transitioned back to + * the configured state. In the meantime, the + * board's must remain as is. + */ + } + + /* if board(s) had deleted memory, verify it is gone */ + rv = 0; + memlist_read_lock(); + if (s_mp->sbm_del_mlist != NULL) { + mp = s_mp; + rv = memlist_intersect(phys_install, mp->sbm_del_mlist); + } + if (rv == 0 && t_mp && t_mp->sbm_del_mlist != NULL) { + mp = t_mp; + rv = memlist_intersect(phys_install, mp->sbm_del_mlist); + } + memlist_read_unlock(); + if (rv) { + cmn_err(CE_WARN, "%s: %smem-unit (%d.%d): " + "deleted memory still found in phys_install", + f, + (mp == t_mp ? "target " : ""), + mp->sbm_cm.sbdev_bp->b_num, + mp->sbm_cm.sbdev_unum); + + DR_DEV_INTERNAL_ERROR(&s_mp->sbm_cm); + return; + } + + s_mp->sbm_flags |= DR_MFLAG_RELDONE; + if (t_mp != NULL) + t_mp->sbm_flags |= DR_MFLAG_RELDONE; + + /* this should not fail */ + if (dr_release_dev_done(&s_mp->sbm_cm) != 0) { + /* catch this in debug kernels */ + ASSERT(0); + return; + } + + PR_MEM("%s: marking %s release DONE\n", + f, s_mp->sbm_cm.sbdev_path); + + s_mp->sbm_cm.sbdev_ostate = SBD_STAT_UNCONFIGURED; + + if (t_mp != NULL) { + /* should not fail */ + rv = dr_release_dev_done(&t_mp->sbm_cm); + if (rv != 0) { + /* catch this in debug kernels */ + ASSERT(0); + return; + } + + PR_MEM("%s: marking %s release DONE\n", + f, t_mp->sbm_cm.sbdev_path); + + t_mp->sbm_cm.sbdev_ostate = SBD_STAT_UNCONFIGURED; + } +} + +/*ARGSUSED*/ +int +dr_disconnect_mem(dr_mem_unit_t *mp) +{ + static fn_t f = "dr_disconnect_mem"; + update_membounds_t umb; + +#ifdef DEBUG + int state = mp->sbm_cm.sbdev_state; + ASSERT(state == DR_STATE_CONNECTED || + state == DR_STATE_UNCONFIGURED); +#endif + + PR_MEM("%s...\n", f); + + if (mp->sbm_del_mlist && mp->sbm_del_mlist != mp->sbm_mlist) + memlist_delete(mp->sbm_del_mlist); + mp->sbm_del_mlist = NULL; + + if (mp->sbm_mlist) { + memlist_delete(mp->sbm_mlist); + mp->sbm_mlist = NULL; + } + + /* + * Remove memory from lgroup + * For now, only board info is required. + */ + umb.u_board = mp->sbm_cm.sbdev_bp->b_num; + umb.u_base = (uint64_t)-1; + umb.u_len = (uint64_t)-1; + + lgrp_plat_config(LGRP_CONFIG_MEM_DEL, (uintptr_t)&umb); + + return (0); +} + +int +dr_cancel_mem(dr_mem_unit_t *s_mp) +{ + dr_mem_unit_t *t_mp; + dr_state_t state; + static fn_t f = "dr_cancel_mem"; + + state = s_mp->sbm_cm.sbdev_state; + + if (s_mp->sbm_flags & DR_MFLAG_TARGET) { + /* must cancel source board, not target board */ + /* TODO: set error */ + return (-1); + } else if (s_mp->sbm_flags & DR_MFLAG_SOURCE) { + t_mp = s_mp->sbm_peer; + ASSERT(t_mp != NULL); + ASSERT(t_mp->sbm_peer == s_mp); + + /* must always match the source board's state */ + /* TODO: is this assertion correct? */ + ASSERT(t_mp->sbm_cm.sbdev_state == state); + } else { + /* this is no target unit */ + t_mp = NULL; + } + + switch (state) { + case DR_STATE_UNREFERENCED: /* state set by dr_release_dev_done */ + ASSERT((s_mp->sbm_flags & DR_MFLAG_RELOWNER) == 0); + + if (t_mp != NULL && t_mp->sbm_del_mlist != NULL) { + PR_MEM("%s: undoing target %s memory delete\n", + f, t_mp->sbm_cm.sbdev_path); + dr_add_memory_spans(t_mp, t_mp->sbm_del_mlist); + + DR_DEV_CLR_UNREFERENCED(&t_mp->sbm_cm); + } + + if (s_mp->sbm_del_mlist != NULL) { + PR_MEM("%s: undoing %s memory delete\n", + f, s_mp->sbm_cm.sbdev_path); + + dr_add_memory_spans(s_mp, s_mp->sbm_del_mlist); + } + + /*FALLTHROUGH*/ + +/* TODO: should no longer be possible to see the release state here */ + case DR_STATE_RELEASE: /* state set by dr_release_mem_done */ + + ASSERT((s_mp->sbm_flags & DR_MFLAG_RELOWNER) == 0); + + if (t_mp != NULL) { + ASSERT(t_mp->sbm_del_mlist == t_mp->sbm_mlist); + t_mp->sbm_del_mlist = NULL; + + if (t_mp->sbm_mlist != NULL) { + memlist_delete(t_mp->sbm_mlist); + t_mp->sbm_mlist = NULL; + } + + t_mp->sbm_peer = NULL; + t_mp->sbm_flags = 0; + t_mp->sbm_cm.sbdev_busy = 0; + dr_init_mem_unit_data(t_mp); + + DR_DEV_CLR_RELEASED(&t_mp->sbm_cm); + + dr_device_transition( + &t_mp->sbm_cm, DR_STATE_CONFIGURED); + } + + if (s_mp->sbm_del_mlist != s_mp->sbm_mlist) + memlist_delete(s_mp->sbm_del_mlist); + s_mp->sbm_del_mlist = NULL; + + if (s_mp->sbm_mlist != NULL) { + memlist_delete(s_mp->sbm_mlist); + s_mp->sbm_mlist = NULL; + } + + s_mp->sbm_peer = NULL; + s_mp->sbm_flags = 0; + s_mp->sbm_cm.sbdev_busy = 0; + dr_init_mem_unit_data(s_mp); + + return (0); + + default: + PR_MEM("%s: WARNING unexpected state (%d) for %s\n", + f, (int)state, s_mp->sbm_cm.sbdev_path); + + return (-1); + } + /*NOTREACHED*/ +} + +void +dr_init_mem_unit(dr_mem_unit_t *mp) +{ + dr_state_t new_state; + + + if (DR_DEV_IS_ATTACHED(&mp->sbm_cm)) { + new_state = DR_STATE_CONFIGURED; + mp->sbm_cm.sbdev_cond = SBD_COND_OK; + } else if (DR_DEV_IS_PRESENT(&mp->sbm_cm)) { + new_state = DR_STATE_CONNECTED; + mp->sbm_cm.sbdev_cond = SBD_COND_OK; + } else if (mp->sbm_cm.sbdev_id != (drmachid_t)0) { + new_state = DR_STATE_OCCUPIED; + } else { + new_state = DR_STATE_EMPTY; + } + + if (DR_DEV_IS_PRESENT(&mp->sbm_cm)) + dr_init_mem_unit_data(mp); + + /* delay transition until fully initialized */ + dr_device_transition(&mp->sbm_cm, new_state); +} + +static void +dr_init_mem_unit_data(dr_mem_unit_t *mp) +{ + drmachid_t id = mp->sbm_cm.sbdev_id; + drmach_mem_info_t minfo; + sbd_error_t *err; + static fn_t f = "dr_init_mem_unit_data"; + update_membounds_t umb; + + PR_MEM("%s...\n", f); + + /* a little sanity checking */ + ASSERT(mp->sbm_peer == NULL); + ASSERT(mp->sbm_flags == 0); + + if (err = drmach_mem_get_info(id, &minfo)) { + DRERR_SET_C(&mp->sbm_cm.sbdev_error, &err); + return; + } + mp->sbm_basepfn = _b64top(minfo.mi_basepa); + mp->sbm_npages = _b64top(minfo.mi_size); + mp->sbm_alignment_mask = _b64top(minfo.mi_alignment_mask); + mp->sbm_slice_size = minfo.mi_slice_size; + + /* + * Add memory to lgroup + */ + umb.u_board = mp->sbm_cm.sbdev_bp->b_num; + umb.u_base = (uint64_t)mp->sbm_basepfn << MMU_PAGESHIFT; + umb.u_len = (uint64_t)mp->sbm_npages << MMU_PAGESHIFT; + + lgrp_plat_config(LGRP_CONFIG_MEM_ADD, (uintptr_t)&umb); + + PR_MEM("%s: %s (basepfn = 0x%lx, npgs = %ld)\n", + f, mp->sbm_cm.sbdev_path, mp->sbm_basepfn, mp->sbm_npages); +} + +static int +dr_reserve_mem_spans(memhandle_t *mhp, struct memlist *ml) +{ + int err; + pfn_t base; + pgcnt_t npgs; + struct memlist *mc; + static fn_t f = "dr_reserve_mem_spans"; + + PR_MEM("%s...\n", f); + + /* + * Walk the supplied memlist scheduling each span for removal + * with kphysm_del_span. It is possible that a span may intersect + * an area occupied by the cage. + */ + for (mc = ml; mc != NULL; mc = mc->next) { + base = _b64top(mc->address); + npgs = _b64top(mc->size); + + err = kphysm_del_span(*mhp, base, npgs); + if (err != KPHYSM_OK) { + cmn_err(CE_WARN, "%s memory reserve failed." + " unexpected kphysm_del_span return value %d;" + " basepfn=0x%lx npages=%ld", + f, err, base, npgs); + + return (-1); + } + } + + return (0); +} + +#define DR_SMT_NPREF_SETS 6 +#define DR_SMT_NUNITS_PER_SET MAX_BOARDS * MAX_MEM_UNITS_PER_BOARD + +/* debug counters */ +int dr_smt_realigned; +int dr_smt_preference[DR_SMT_NPREF_SETS]; + +#ifdef DEBUG +uint_t dr_ignore_board; /* if bit[bnum-1] set, board won't be candidate */ +#endif + +/* + * Find and reserve a copy/rename target board suitable for the + * given source board. + * All boards in the system are examined and categorized in relation to + * their memory size versus the source board's memory size. Order of + * preference is: + * 1st copy all source, source/target same size + * 2nd copy all source, larger target + * 3rd copy nonrelocatable source span + */ +static int +dr_select_mem_target(dr_handle_t *hp, + dr_mem_unit_t *s_mp, struct memlist *s_ml) +{ + dr_target_pref_t preference; /* lower value is higher preference */ + int idx; + dr_mem_unit_t **sets; + + int t_bd; + int t_unit; + int rv; + dr_board_t *s_bp, *t_bp; + dr_mem_unit_t *t_mp, *c_mp; + struct memlist *d_ml, *t_ml, *ml, *b_ml, *x_ml = NULL; + memquery_t s_mq = {0}; + static fn_t f = "dr_select_mem_target"; + + PR_MEM("%s...\n", f); + + ASSERT(s_ml != NULL); + + sets = GETSTRUCT(dr_mem_unit_t *, DR_SMT_NUNITS_PER_SET * + DR_SMT_NPREF_SETS); + + s_bp = hp->h_bd; + /* calculate the offset into the slice of the last source board pfn */ + ASSERT(s_mp->sbm_npages != 0); + + /* + * Find non-relocatable span on source board. + */ + rv = kphysm_del_span_query(s_mp->sbm_basepfn, s_mp->sbm_npages, &s_mq); + if (rv != KPHYSM_OK) { + PR_MEM("%s: %s: unexpected kphysm_del_span_query" + " return value %d; basepfn 0x%lx, npages %ld\n", + f, s_mp->sbm_cm.sbdev_path, rv, s_mp->sbm_basepfn, + s_mp->sbm_npages); + return (-1); + } + + ASSERT(s_mq.phys_pages != 0); + ASSERT(s_mq.nonrelocatable != 0); + + PR_MEM("%s: %s: nonrelocatable span (0x%lx..0x%lx)\n", f, + s_mp->sbm_cm.sbdev_path, s_mq.first_nonrelocatable, + s_mq.last_nonrelocatable); + + /* break down s_ml if it contains dynamic segments */ + b_ml = memlist_dup(s_ml); + + for (ml = s_mp->sbm_dyn_segs; ml; ml = ml->next) { + b_ml = memlist_del_span(b_ml, ml->address, ml->size); + b_ml = memlist_cat_span(b_ml, ml->address, ml->size); + } + + + /* + * Make one pass through all memory units on all boards + * and categorize them with respect to the source board. + */ + for (t_bd = 0; t_bd < MAX_BOARDS; t_bd++) { + /* + * The board structs are a contiguous array + * so we take advantage of that to find the + * correct board struct pointer for a given + * board number. + */ + t_bp = dr_lookup_board(t_bd); + + /* source board can not be its own target */ + if (s_bp->b_num == t_bp->b_num) + continue; + + for (t_unit = 0; t_unit < MAX_MEM_UNITS_PER_BOARD; t_unit++) { + + t_mp = dr_get_mem_unit(t_bp, t_unit); + + /* this memory node must be attached */ + if (!DR_DEV_IS_ATTACHED(&t_mp->sbm_cm)) + continue; + + /* source unit can not be its own target */ + if (s_mp == t_mp) { + /* catch this is debug kernels */ + ASSERT(0); + continue; + } + + /* + * this memory node must not already be reserved + * by some other memory delete operation. + */ + if (t_mp->sbm_flags & DR_MFLAG_RESERVED) + continue; + + /* get target board memlist */ + t_ml = dr_get_memlist(t_mp); + if (t_ml == NULL) { + cmn_err(CE_WARN, "%s: no memlist for" + " mem-unit %d, board %d", f, + t_mp->sbm_cm.sbdev_bp->b_num, + t_mp->sbm_cm.sbdev_unum); + continue; + } + + preference = dr_get_target_preference(hp, t_mp, s_mp, + t_ml, s_ml, b_ml); + + if (preference == DR_TP_INVALID) + continue; + + dr_smt_preference[preference]++; + + /* calculate index to start of preference set */ + idx = DR_SMT_NUNITS_PER_SET * preference; + /* calculate offset to respective element */ + idx += t_bd * MAX_MEM_UNITS_PER_BOARD + t_unit; + + ASSERT(idx < DR_SMT_NUNITS_PER_SET * DR_SMT_NPREF_SETS); + sets[idx] = t_mp; + } + } + + if (b_ml != NULL) + memlist_delete(b_ml); + + /* + * NOTE: this would be a good place to sort each candidate + * set in to some desired order, e.g. memory size in ascending + * order. Without an additional sorting step here, the order + * within a set is ascending board number order. + */ + + c_mp = NULL; + x_ml = NULL; + t_ml = NULL; + for (idx = 0; idx < DR_SMT_NUNITS_PER_SET * DR_SMT_NPREF_SETS; idx++) { + memquery_t mq; + + preference = (dr_target_pref_t)(idx / DR_SMT_NUNITS_PER_SET); + + ASSERT(preference != DR_TP_INVALID); + + /* cleanup t_ml after previous pass */ + if (t_ml != NULL) { + memlist_delete(t_ml); + t_ml = NULL; + } + + /* get candidate target board mem unit */ + t_mp = sets[idx]; + if (t_mp == NULL) + continue; + + /* get target board memlist */ + t_ml = dr_get_memlist(t_mp); + if (t_ml == NULL) { + cmn_err(CE_WARN, "%s: no memlist for" + " mem-unit %d, board %d", + f, + t_mp->sbm_cm.sbdev_bp->b_num, + t_mp->sbm_cm.sbdev_unum); + + continue; + } + + PR_MEM("%s: checking for no-reloc in %s, " + " basepfn=0x%lx, npages=%ld\n", + f, + t_mp->sbm_cm.sbdev_path, + t_mp->sbm_basepfn, + t_mp->sbm_npages); + + rv = dr_del_mlist_query(t_ml, &mq); + if (rv != KPHYSM_OK) { + PR_MEM("%s: kphysm_del_span_query:" + " unexpected return value %d\n", f, rv); + + continue; + } + + if (mq.nonrelocatable != 0) { + PR_MEM("%s: candidate %s has" + " nonrelocatable span [0x%lx..0x%lx]\n", + f, + t_mp->sbm_cm.sbdev_path, + mq.first_nonrelocatable, + mq.last_nonrelocatable); + + continue; + } + +#ifdef DEBUG + /* + * This is a debug tool for excluding certain boards + * from being selected as a target board candidate. + * dr_ignore_board is only tested by this driver. + * It must be set with adb, obp, /etc/system or your + * favorite debugger. + */ + if (dr_ignore_board & + (1 << (t_mp->sbm_cm.sbdev_bp->b_num - 1))) { + PR_MEM("%s: dr_ignore_board flag set," + " ignoring %s as candidate\n", + f, t_mp->sbm_cm.sbdev_path); + continue; + } +#endif + + /* + * Reserve excess source board memory, if any. + * + * Only the nonrelocatable source span will be copied + * so schedule the rest of the source mem to be deleted. + */ + switch (preference) { + case DR_TP_NONRELOC: + /* + * Get source copy memlist and use it to construct + * delete memlist. + */ + d_ml = memlist_dup(s_ml); + x_ml = dr_get_copy_mlist(s_ml, t_ml, s_mp, t_mp); + + /* XXX */ + ASSERT(d_ml != NULL); + ASSERT(x_ml != NULL); + + for (ml = x_ml; ml != NULL; ml = ml->next) { + d_ml = memlist_del_span(d_ml, ml->address, + ml->size); + } + + PR_MEM("%s: %s: reserving src brd memlist:\n", f, + s_mp->sbm_cm.sbdev_path); + PR_MEMLIST_DUMP(d_ml); + + /* reserve excess spans */ + if (dr_reserve_mem_spans(&s_mp->sbm_memhandle, + d_ml) != 0) { + /* likely more non-reloc pages appeared */ + /* TODO: restart from top? */ + continue; + } + break; + default: + d_ml = NULL; + break; + } + + s_mp->sbm_flags |= DR_MFLAG_RESERVED; + + /* + * reserve all memory on target board. + * NOTE: source board's memhandle is used. + * + * If this succeeds (eq 0), then target selection is + * complete and all unwanted memory spans, both source and + * target, have been reserved. Loop is terminated. + */ + if (dr_reserve_mem_spans(&s_mp->sbm_memhandle, t_ml) == 0) { + PR_MEM("%s: %s: target board memory reserved\n", + f, t_mp->sbm_cm.sbdev_path); + + /* a candidate target board is now reserved */ + t_mp->sbm_flags |= DR_MFLAG_RESERVED; + c_mp = t_mp; + + /* *** EXITING LOOP *** */ + break; + } + + /* did not successfully reserve the target board. */ + PR_MEM("%s: could not reserve target %s\n", + f, t_mp->sbm_cm.sbdev_path); + + /* + * NOTE: an undo of the dr_reserve_mem_span work + * will happen automatically when the memhandle + * (s_mp->sbm_memhandle) is kphysm_del_release'd. + */ + + s_mp->sbm_flags &= ~DR_MFLAG_RESERVED; + } + + /* clean up after memlist editing logic */ + if (x_ml != NULL) + memlist_delete(x_ml); + + FREESTRUCT(sets, dr_mem_unit_t *, DR_SMT_NUNITS_PER_SET * + DR_SMT_NPREF_SETS); + + /* + * c_mp will be NULL when the entire sets[] array + * has been searched without reserving a target board. + */ + if (c_mp == NULL) { + PR_MEM("%s: %s: target selection failed.\n", + f, s_mp->sbm_cm.sbdev_path); + + if (t_ml != NULL) + memlist_delete(t_ml); + + return (-1); + } + + PR_MEM("%s: found target %s for source %s\n", + f, + c_mp->sbm_cm.sbdev_path, + s_mp->sbm_cm.sbdev_path); + + s_mp->sbm_peer = c_mp; + s_mp->sbm_flags |= DR_MFLAG_SOURCE; + s_mp->sbm_del_mlist = d_ml; /* spans to be deleted, if any */ + s_mp->sbm_mlist = s_ml; + s_mp->sbm_cm.sbdev_busy = 1; + + c_mp->sbm_peer = s_mp; + c_mp->sbm_flags |= DR_MFLAG_TARGET; + c_mp->sbm_del_mlist = t_ml; /* spans to be deleted */ + c_mp->sbm_mlist = t_ml; + c_mp->sbm_cm.sbdev_busy = 1; + + return (0); +} + +/* + * Returns target preference rank: + * -1 not a valid copy-rename target board + * 0 copy all source, source/target same size + * 1 copy all source, larger target + * 2 copy nonrelocatable source span + */ +static dr_target_pref_t +dr_get_target_preference(dr_handle_t *hp, + dr_mem_unit_t *t_mp, dr_mem_unit_t *s_mp, + struct memlist *t_ml, struct memlist *s_ml, + struct memlist *b_ml) +{ + dr_target_pref_t preference; + struct memlist *s_nonreloc_ml = NULL; + drmachid_t t_id; + static fn_t f = "dr_get_target_preference"; + + t_id = t_mp->sbm_cm.sbdev_bp->b_id; + + /* + * Can the entire source board be copied? + */ + if (dr_memlist_canfit(s_ml, t_ml, s_mp, t_mp)) { + if (s_mp->sbm_npages == t_mp->sbm_npages) + preference = DR_TP_SAME; /* same size */ + else + preference = DR_TP_LARGE; /* larger target */ + } else { + /* + * Entire source won't fit so try non-relocatable memory only + * (target aligned). + */ + s_nonreloc_ml = dr_get_nonreloc_mlist(b_ml, s_mp); + if (s_nonreloc_ml == NULL) { + PR_MEM("%s: dr_get_nonreloc_mlist failed\n", f); + preference = DR_TP_INVALID; + } + if (dr_memlist_canfit(s_nonreloc_ml, t_ml, s_mp, t_mp)) + preference = DR_TP_NONRELOC; + else + preference = DR_TP_INVALID; + } + + if (s_nonreloc_ml != NULL) + memlist_delete(s_nonreloc_ml); + + /* + * Force floating board preference lower than all other boards + * if the force flag is present; otherwise disallow the board. + */ + if ((preference != DR_TP_INVALID) && drmach_board_is_floating(t_id)) { + if (dr_cmd_flags(hp) & SBD_FLAG_FORCE) + preference += DR_TP_FLOATING; + else + preference = DR_TP_INVALID; + } + + PR_MEM("%s: %s preference=%d\n", f, t_mp->sbm_cm.sbdev_path, + preference); + + return (preference); +} + +/* + * Create a memlist representing the source memory that will be copied to + * the target board. The memory to be copied is the maximum amount that + * will fit on the target board. + */ +static struct memlist * +dr_get_copy_mlist(struct memlist *s_mlist, struct memlist *t_mlist, + dr_mem_unit_t *s_mp, dr_mem_unit_t *t_mp) +{ + struct memlist *t_ml, *s_copy_ml, *s_del_ml, *ml, *x_ml; + uint64_t s_slice_mask, s_slice_base; + uint64_t t_slice_mask, t_slice_base; + static fn_t f = "dr_get_copy_mlist"; + + ASSERT(s_mlist != NULL); + ASSERT(t_mlist != NULL); + ASSERT(t_mp->sbm_slice_size == s_mp->sbm_slice_size); + + s_slice_mask = s_mp->sbm_slice_size - 1; + s_slice_base = s_mlist->address & ~s_slice_mask; + + t_slice_mask = t_mp->sbm_slice_size - 1; + t_slice_base = t_mlist->address & ~t_slice_mask; + + t_ml = memlist_dup(t_mlist); + s_del_ml = memlist_dup(s_mlist); + s_copy_ml = memlist_dup(s_mlist); + + /* XXX */ + ASSERT(t_ml != NULL); + ASSERT(s_del_ml != NULL); + ASSERT(s_copy_ml != NULL); + + /* + * To construct the source copy memlist: + * + * The target memlist is converted to the post-rename + * source addresses. This is the physical address range + * the target will have after the copy-rename. Overlaying + * and deleting this from the current source memlist will + * give the source delete memlist. The copy memlist is + * the reciprocal of the source delete memlist. + */ + for (ml = t_ml; ml != NULL; ml = ml->next) { + /* + * Normalize relative to target slice base PA + * in order to preseve slice offsets. + */ + ml->address -= t_slice_base; + /* + * Convert to source slice PA address. + */ + ml->address += s_slice_base; + } + + for (ml = t_ml; ml != NULL; ml = ml->next) { + s_del_ml = memlist_del_span(s_del_ml, ml->address, ml->size); + } + + /* + * Expand the delete mlist to fully include any dynamic segments + * it intersects with. + */ + for (x_ml = NULL, ml = s_del_ml; ml != NULL; ml = ml->next) { + uint64_t del_base = ml->address; + uint64_t del_end = ml->address + ml->size; + struct memlist *dyn; + + for (dyn = s_mp->sbm_dyn_segs; dyn != NULL; dyn = dyn->next) { + uint64_t dyn_base = dyn->address; + uint64_t dyn_end = dyn->address + dyn->size; + + if (del_base > dyn_base && del_base < dyn_end) + del_base = dyn_base; + + if (del_end > dyn_base && del_end < dyn_end) + del_end = dyn_end; + } + + x_ml = memlist_cat_span(x_ml, del_base, del_end - del_base); + } + + memlist_delete(s_del_ml); + s_del_ml = x_ml; + + for (ml = s_del_ml; ml != NULL; ml = ml->next) { + s_copy_ml = memlist_del_span(s_copy_ml, ml->address, ml->size); + } + + PR_MEM("%s: source delete mlist\n", f); + PR_MEMLIST_DUMP(s_del_ml); + + PR_MEM("%s: source copy mlist\n", f); + PR_MEMLIST_DUMP(s_copy_ml); + + memlist_delete(t_ml); + memlist_delete(s_del_ml); + + return (s_copy_ml); +} + +/* + * Scan the non-relocatable spans on the source memory + * and construct a minimum mlist that includes all non-reloc + * memory subject to target alignment, and dynamic segment + * constraints where only whole dynamic segments may be deleted. + */ +static struct memlist * +dr_get_nonreloc_mlist(struct memlist *s_ml, dr_mem_unit_t *s_mp) +{ + struct memlist *x_ml = NULL; + struct memlist *ml; + static fn_t f = "dr_get_nonreloc_mlist"; + + PR_MEM("%s: checking for split of dyn seg list:\n", f); + PR_MEMLIST_DUMP(s_mp->sbm_dyn_segs); + + for (ml = s_ml; ml; ml = ml->next) { + int rv; + uint64_t nr_base, nr_end; + memquery_t mq; + struct memlist *dyn; + + rv = kphysm_del_span_query( + _b64top(ml->address), _b64top(ml->size), &mq); + if (rv) { + memlist_delete(x_ml); + return (NULL); + } + + if (mq.nonrelocatable == 0) + continue; + + PR_MEM("%s: non-reloc span: 0x%lx, 0x%lx (%lx, %lx)\n", f, + _ptob64(mq.first_nonrelocatable), + _ptob64(mq.last_nonrelocatable), + mq.first_nonrelocatable, + mq.last_nonrelocatable); + + /* + * Align the span at both ends to allow for possible + * cage expansion. + */ + nr_base = _ptob64(mq.first_nonrelocatable); + nr_end = _ptob64(mq.last_nonrelocatable + 1); + + PR_MEM("%s: adjusted non-reloc span: 0x%lx, 0x%lx\n", + f, nr_base, nr_end); + + /* + * Expand the non-reloc span to fully include any + * dynamic segments it intersects with. + */ + for (dyn = s_mp->sbm_dyn_segs; dyn != NULL; dyn = dyn->next) { + uint64_t dyn_base = dyn->address; + uint64_t dyn_end = dyn->address + dyn->size; + + if (nr_base > dyn_base && nr_base < dyn_end) + nr_base = dyn_base; + + if (nr_end > dyn_base && nr_end < dyn_end) + nr_end = dyn_end; + } + + x_ml = memlist_cat_span(x_ml, nr_base, nr_end - nr_base); + } + + if (x_ml == NULL) { + PR_MEM("%s: source didn't have any non-reloc pages!\n", f); + return (NULL); + } + + PR_MEM("%s: %s: edited source memlist:\n", f, s_mp->sbm_cm.sbdev_path); + PR_MEMLIST_DUMP(x_ml); + + return (x_ml); +} + +/* + * Check if source memlist can fit in target memlist while maintaining + * relative offsets within board. + */ +static int +dr_memlist_canfit(struct memlist *s_mlist, struct memlist *t_mlist, + dr_mem_unit_t *s_mp, dr_mem_unit_t *t_mp) +{ + int canfit = 0; + struct memlist *s_ml, *t_ml, *ml; + uint64_t s_slice_mask, t_slice_mask; + static fn_t f = "dr_mlist_canfit"; + + s_ml = memlist_dup(s_mlist); + t_ml = memlist_dup(t_mlist); + + if (s_ml == NULL || t_ml == NULL) { + cmn_err(CE_WARN, "%s: memlist_dup failed\n", f); + goto done; + } + + s_slice_mask = s_mp->sbm_slice_size - 1; + t_slice_mask = t_mp->sbm_slice_size - 1; + + /* + * Normalize to slice relative offsets. + */ + for (ml = s_ml; ml; ml = ml->next) + ml->address &= s_slice_mask; + + for (ml = t_ml; ml; ml = ml->next) + ml->address &= t_slice_mask; + + canfit = memlist_canfit(s_ml, t_ml); +done: + memlist_delete(s_ml); + memlist_delete(t_ml); + + return (canfit); +} + +/* + * Memlist support. + */ + +/* + * Determine whether the source memlist (s_mlist) will + * fit into the target memlist (t_mlist) in terms of + * size and holes. Assumes the caller has normalized the + * memlist physical addresses for comparison. + */ +static int +memlist_canfit(struct memlist *s_mlist, struct memlist *t_mlist) +{ + int rv = 0; + struct memlist *s_ml, *t_ml; + + if ((s_mlist == NULL) || (t_mlist == NULL)) + return (0); + + s_ml = s_mlist; + for (t_ml = t_mlist; t_ml && s_ml; t_ml = t_ml->next) { + uint64_t s_start, s_end; + uint64_t t_start, t_end; + + t_start = t_ml->address; + t_end = t_start + t_ml->size; + + for (; s_ml; s_ml = s_ml->next) { + s_start = s_ml->address; + s_end = s_start + s_ml->size; + + if ((s_start < t_start) || (s_end > t_end)) + break; + } + } + + /* + * If we ran out of source memlist chunks that mean + * we found a home for all of them. + */ + if (s_ml == NULL) + rv = 1; + + return (rv); +} diff --git a/usr/src/uts/sun4u/opl/io/drmach.c b/usr/src/uts/sun4u/opl/io/drmach.c new file mode 100644 index 0000000000..3b6f520447 --- /dev/null +++ b/usr/src/uts/sun4u/opl/io/drmach.c @@ -0,0 +1,3929 @@ +/* + * 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 <sys/debug.h> +#include <sys/types.h> +#include <sys/varargs.h> +#include <sys/errno.h> +#include <sys/cred.h> +#include <sys/dditypes.h> +#include <sys/devops.h> +#include <sys/modctl.h> +#include <sys/poll.h> +#include <sys/conf.h> +#include <sys/ddi.h> +#include <sys/sunddi.h> +#include <sys/sunndi.h> +#include <sys/ndi_impldefs.h> +#include <sys/stat.h> +#include <sys/kmem.h> +#include <sys/vmem.h> +#include <sys/opl_olympus_regs.h> +#include <sys/cpuvar.h> +#include <sys/cpupart.h> +#include <sys/mem_config.h> +#include <sys/ddi_impldefs.h> +#include <sys/systm.h> +#include <sys/machsystm.h> +#include <sys/autoconf.h> +#include <sys/cmn_err.h> +#include <sys/sysmacros.h> +#include <sys/x_call.h> +#include <sys/promif.h> +#include <sys/prom_plat.h> +#include <sys/membar.h> +#include <vm/seg_kmem.h> +#include <sys/mem_cage.h> +#include <sys/stack.h> +#include <sys/archsystm.h> +#include <vm/hat_sfmmu.h> +#include <sys/pte.h> +#include <sys/mmu.h> +#include <sys/cpu_module.h> +#include <sys/obpdefs.h> +#include <sys/note.h> +#include <sys/ontrap.h> +#include <sys/cpu_sgnblk_defs.h> +#include <sys/opl.h> + + +#include <sys/promimpl.h> +#include <sys/prom_plat.h> +#include <sys/kobj.h> + +#include <sys/sysevent.h> +#include <sys/sysevent/dr.h> +#include <sys/sysevent/eventdefs.h> + +#include <sys/drmach.h> +#include <sys/dr_util.h> + +#include <sys/fcode.h> +#include <sys/opl_cfg.h> + +extern void bcopy32_il(uint64_t, uint64_t); +extern void flush_cache_il(void); +extern void drmach_sleep_il(void); + +typedef struct { + struct drmach_node *node; + void *data; +} drmach_node_walk_args_t; + +typedef struct drmach_node { + void *here; + + pnode_t (*get_dnode)(struct drmach_node *node); + int (*walk)(struct drmach_node *node, void *data, + int (*cb)(drmach_node_walk_args_t *args)); + dev_info_t *(*n_getdip)(struct drmach_node *node); + int (*n_getproplen)(struct drmach_node *node, char *name, + int *len); + int (*n_getprop)(struct drmach_node *node, char *name, + void *buf, int len); + int (*get_parent)(struct drmach_node *node, + struct drmach_node *pnode); +} drmach_node_t; + +typedef struct { + int min_index; + int max_index; + int arr_sz; + drmachid_t *arr; +} drmach_array_t; + +typedef struct { + void *isa; + + void (*dispose)(drmachid_t); + sbd_error_t *(*release)(drmachid_t); + sbd_error_t *(*status)(drmachid_t, drmach_status_t *); + + char name[MAXNAMELEN]; +} drmach_common_t; + +typedef struct { + uint32_t core_present; + uint32_t core_hotadded; + uint32_t core_started; +} drmach_cmp_t; + +typedef struct { + drmach_common_t cm; + int bnum; + int assigned; + int powered; + int connected; + int cond; + drmach_node_t *tree; + drmach_array_t *devices; + int boot_board; /* if board exists on bootup */ + drmach_cmp_t cores[OPL_MAX_COREID_PER_BOARD]; +} drmach_board_t; + +typedef struct { + drmach_common_t cm; + drmach_board_t *bp; + int unum; + int portid; + int busy; + int powered; + const char *type; + drmach_node_t *node; +} drmach_device_t; + +typedef struct drmach_cpu { + drmach_device_t dev; + processorid_t cpuid; + int sb; + int chipid; + int coreid; + int strandid; + int status; +#define OPL_CPU_HOTADDED 1 +} drmach_cpu_t; + +typedef struct drmach_mem { + drmach_device_t dev; + uint64_t slice_base; + uint64_t slice_size; + uint64_t base_pa; /* lowest installed memory base */ + uint64_t nbytes; /* size of installed memory */ + struct memlist *memlist; +} drmach_mem_t; + +typedef struct drmach_io { + drmach_device_t dev; + int channel; + int leaf; +} drmach_io_t; + +typedef struct drmach_domain_info { + uint32_t floating; + int allow_dr; +} drmach_domain_info_t; + +drmach_domain_info_t drmach_domain; + +typedef struct { + int flags; + drmach_device_t *dp; + sbd_error_t *err; + dev_info_t *dip; +} drmach_config_args_t; + +typedef struct { + drmach_board_t *obj; + int ndevs; + void *a; + sbd_error_t *(*found)(void *a, const char *, int, drmachid_t); + sbd_error_t *err; +} drmach_board_cb_data_t; + +static drmach_array_t *drmach_boards; + +static sbd_error_t *drmach_device_new(drmach_node_t *, + drmach_board_t *, int, drmachid_t *); +static sbd_error_t *drmach_cpu_new(drmach_device_t *, drmachid_t *); +static sbd_error_t *drmach_mem_new(drmach_device_t *, drmachid_t *); +static sbd_error_t *drmach_io_new(drmach_device_t *, drmachid_t *); + +static dev_info_t *drmach_node_ddi_get_dip(drmach_node_t *np); +static int drmach_node_ddi_get_prop(drmach_node_t *np, + char *name, void *buf, int len); +static int drmach_node_ddi_get_proplen(drmach_node_t *np, + char *name, int *len); + +static int drmach_get_portid(drmach_node_t *); +static sbd_error_t *drmach_i_status(drmachid_t, drmach_status_t *); +static int opl_check_dr_status(); +static void drmach_io_dispose(drmachid_t); +static sbd_error_t *drmach_io_release(drmachid_t); +static sbd_error_t *drmach_io_status(drmachid_t, drmach_status_t *); +static int drmach_init(void); +static void drmach_fini(void); +static void drmach_swap_pa(drmach_mem_t *, drmach_mem_t *); +static drmach_board_t *drmach_get_board_by_bnum(int); + +/* options for the second argument in drmach_add_remove_cpu() */ +#define HOTADD_CPU 1 +#define HOTREMOVE_CPU 2 + +#define ON_BOARD_CORE_NUM(x) (((uint_t)(x) / OPL_MAX_STRANDID_PER_CORE) & \ + (OPL_MAX_COREID_PER_BOARD - 1)) + +extern struct cpu *SIGBCPU; + +static int drmach_name2type_idx(char *); +static drmach_board_t *drmach_board_new(int, int); + +#ifdef DEBUG + +#define DRMACH_PR if (drmach_debug) printf +int drmach_debug = 1; /* set to non-zero to enable debug messages */ +#else + +#define DRMACH_PR _NOTE(CONSTANTCONDITION) if (0) printf +#endif /* DEBUG */ + + +#define DRMACH_OBJ(id) ((drmach_common_t *)id) + +#define DRMACH_IS_BOARD_ID(id) \ + ((id != 0) && \ + (DRMACH_OBJ(id)->isa == (void *)drmach_board_new)) + +#define DRMACH_IS_CPU_ID(id) \ + ((id != 0) && \ + (DRMACH_OBJ(id)->isa == (void *)drmach_cpu_new)) + +#define DRMACH_IS_MEM_ID(id) \ + ((id != 0) && \ + (DRMACH_OBJ(id)->isa == (void *)drmach_mem_new)) + +#define DRMACH_IS_IO_ID(id) \ + ((id != 0) && \ + (DRMACH_OBJ(id)->isa == (void *)drmach_io_new)) + +#define DRMACH_IS_DEVICE_ID(id) \ + ((id != 0) && \ + (DRMACH_OBJ(id)->isa == (void *)drmach_cpu_new || \ + DRMACH_OBJ(id)->isa == (void *)drmach_mem_new || \ + DRMACH_OBJ(id)->isa == (void *)drmach_io_new)) + +#define DRMACH_IS_ID(id) \ + ((id != 0) && \ + (DRMACH_OBJ(id)->isa == (void *)drmach_board_new || \ + DRMACH_OBJ(id)->isa == (void *)drmach_cpu_new || \ + DRMACH_OBJ(id)->isa == (void *)drmach_mem_new || \ + DRMACH_OBJ(id)->isa == (void *)drmach_io_new)) + +#define DRMACH_INTERNAL_ERROR() \ + drerr_new(1, EOPL_INTERNAL, drmach_ie_fmt, __LINE__) + +static char *drmach_ie_fmt = "drmach.c %d"; + +static struct { + const char *name; + const char *type; + sbd_error_t *(*new)(drmach_device_t *, drmachid_t *); +} drmach_name2type[] = { + { "cpu", DRMACH_DEVTYPE_CPU, drmach_cpu_new }, + { "pseudo-mc", DRMACH_DEVTYPE_MEM, drmach_mem_new }, + { "pci", DRMACH_DEVTYPE_PCI, drmach_io_new }, +}; + +/* utility */ +#define MBYTE (1048576ull) + +/* + * drmach autoconfiguration data structures and interfaces + */ + +extern struct mod_ops mod_miscops; + +static struct modlmisc modlmisc = { + &mod_miscops, + "OPL DR 1.1" +}; + +static struct modlinkage modlinkage = { + MODREV_1, + (void *)&modlmisc, + NULL +}; + +static krwlock_t drmach_boards_rwlock; + +typedef const char *fn_t; + +int +_init(void) +{ + int err; + + if ((err = drmach_init()) != 0) { + return (err); + } + + if ((err = mod_install(&modlinkage)) != 0) { + drmach_fini(); + } + + return (err); +} + +int +_fini(void) +{ + int err; + + if ((err = mod_remove(&modlinkage)) == 0) + drmach_fini(); + + return (err); +} + +int +_info(struct modinfo *modinfop) +{ + return (mod_info(&modlinkage, modinfop)); +} + +/* + * The following routines are used to set up the memory + * properties in the board structure. + */ + +struct drmach_mc_lookup { + int bnum; + drmach_board_t *bp; + dev_info_t *dip; /* rv - set if found */ +}; + +#define _ptob64(p) ((uint64_t)(p) << PAGESHIFT) +#define _b64top(b) ((pgcnt_t)((b) >> PAGESHIFT)) + +static int +drmach_setup_mc_info(dev_info_t *dip, drmach_mem_t *mp) +{ + uint64_t memory_ranges[128]; + int len; + struct memlist *ml; + int rv; + hwd_sb_t *hwd; + hwd_memory_t *pm; + + len = sizeof (memory_ranges); + if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, + DDI_PROP_DONTPASS, "sb-mem-ranges", + (caddr_t)&memory_ranges[0], &len) != DDI_PROP_SUCCESS) { + mp->slice_base = 0; + mp->slice_size = 0; + return (-1); + } + mp->slice_base = memory_ranges[0]; + mp->slice_size = memory_ranges[1]; + + if (!mp->dev.bp->boot_board) { + int i; + + rv = opl_read_hwd(mp->dev.bp->bnum, NULL, NULL, NULL, &hwd); + + if (rv != 0) { + return (-1); + } + + ml = NULL; + pm = &hwd->sb_cmu.cmu_memory; + for (i = 0; i < HWD_MAX_MEM_CHUNKS; i++) { + if (pm->mem_chunks[i].chnk_size > 0) { + ml = memlist_add_span(ml, + pm->mem_chunks[i].chnk_start_address, + pm->mem_chunks[i].chnk_size); + } + } + } else { + /* + * we intersect phys_install to get base_pa. + * This only works at bootup time. + */ + + memlist_read_lock(); + ml = memlist_dup(phys_install); + memlist_read_unlock(); + + ml = memlist_del_span(ml, 0ull, mp->slice_base); + if (ml) { + uint64_t basepa, endpa; + endpa = _ptob64(physmax + 1); + + basepa = mp->slice_base + mp->slice_size; + + ml = memlist_del_span(ml, basepa, endpa - basepa); + } + } + + if (ml) { + uint64_t nbytes = 0; + struct memlist *p; + for (p = ml; p; p = p->next) { + nbytes += p->size; + } + if ((mp->nbytes = nbytes) > 0) + mp->base_pa = ml->address; + else + mp->base_pa = 0; + mp->memlist = ml; + } else { + mp->base_pa = 0; + mp->nbytes = 0; + } + return (0); +} + + +struct drmach_hotcpu { + drmach_board_t *bp; + int bnum; + int core_id; + int rv; + int option; +}; + +static int +drmach_cpu_cb(dev_info_t *dip, void *arg) +{ + struct drmach_hotcpu *p = (struct drmach_hotcpu *)arg; + char name[OBP_MAXDRVNAME]; + int len = OBP_MAXDRVNAME; + int bnum, core_id, strand_id; + drmach_board_t *bp; + + if (dip == ddi_root_node()) { + return (DDI_WALK_CONTINUE); + } + + if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, + DDI_PROP_DONTPASS, "name", + (caddr_t)name, &len) != DDI_PROP_SUCCESS) { + return (DDI_WALK_PRUNECHILD); + } + + /* only cmp has board number */ + bnum = -1; + len = sizeof (bnum); + if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, + DDI_PROP_DONTPASS, OBP_BOARDNUM, + (caddr_t)&bnum, &len) != DDI_PROP_SUCCESS) { + bnum = -1; + } + + if (strcmp(name, "cmp") == 0) { + if (bnum != p->bnum) + return (DDI_WALK_PRUNECHILD); + return (DDI_WALK_CONTINUE); + } + /* we have already pruned all unwanted cores and cpu's above */ + if (strcmp(name, "core") == 0) { + return (DDI_WALK_CONTINUE); + } + if (strcmp(name, "cpu") == 0) { + processorid_t cpuid; + len = sizeof (cpuid); + if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, + DDI_PROP_DONTPASS, "cpuid", + (caddr_t)&cpuid, &len) != DDI_PROP_SUCCESS) { + p->rv = -1; + return (DDI_WALK_TERMINATE); + } + + core_id = p->core_id; + + bnum = LSB_ID(cpuid); + + if (ON_BOARD_CORE_NUM(cpuid) != core_id) + return (DDI_WALK_CONTINUE); + + bp = p->bp; + ASSERT(bnum == bp->bnum); + + if (p->option == HOTADD_CPU) { + if (prom_hotaddcpu(cpuid) != 0) { + p->rv = -1; + return (DDI_WALK_TERMINATE); + } + strand_id = STRAND_ID(cpuid); + bp->cores[core_id].core_hotadded |= (1 << strand_id); + } else if (p->option == HOTREMOVE_CPU) { + if (prom_hotremovecpu(cpuid) != 0) { + p->rv = -1; + return (DDI_WALK_TERMINATE); + } + strand_id = STRAND_ID(cpuid); + bp->cores[core_id].core_hotadded &= ~(1 << strand_id); + } + return (DDI_WALK_CONTINUE); + } + + return (DDI_WALK_PRUNECHILD); +} + + +static int +drmach_add_remove_cpu(int bnum, int core_id, int option) +{ + struct drmach_hotcpu arg; + drmach_board_t *bp; + + bp = drmach_get_board_by_bnum(bnum); + ASSERT(bp); + + arg.bp = bp; + arg.bnum = bnum; + arg.core_id = core_id; + arg.rv = 0; + arg.option = option; + ddi_walk_devs(ddi_root_node(), drmach_cpu_cb, (void *)&arg); + return (arg.rv); +} + +struct drmach_setup_core_arg { + drmach_board_t *bp; +}; + +static int +drmach_setup_core_cb(dev_info_t *dip, void *arg) +{ + struct drmach_setup_core_arg *p = (struct drmach_setup_core_arg *)arg; + char name[OBP_MAXDRVNAME]; + int len = OBP_MAXDRVNAME; + int bnum; + int core_id, strand_id; + + if (dip == ddi_root_node()) { + return (DDI_WALK_CONTINUE); + } + + if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, + DDI_PROP_DONTPASS, "name", + (caddr_t)name, &len) != DDI_PROP_SUCCESS) { + return (DDI_WALK_PRUNECHILD); + } + + /* only cmp has board number */ + bnum = -1; + len = sizeof (bnum); + if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, + DDI_PROP_DONTPASS, OBP_BOARDNUM, + (caddr_t)&bnum, &len) != DDI_PROP_SUCCESS) { + bnum = -1; + } + + if (strcmp(name, "cmp") == 0) { + if (bnum != p->bp->bnum) + return (DDI_WALK_PRUNECHILD); + return (DDI_WALK_CONTINUE); + } + /* we have already pruned all unwanted cores and cpu's above */ + if (strcmp(name, "core") == 0) { + return (DDI_WALK_CONTINUE); + } + if (strcmp(name, "cpu") == 0) { + processorid_t cpuid; + len = sizeof (cpuid); + if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, + DDI_PROP_DONTPASS, "cpuid", + (caddr_t)&cpuid, &len) != DDI_PROP_SUCCESS) { + return (DDI_WALK_TERMINATE); + } + bnum = LSB_ID(cpuid); + ASSERT(bnum == p->bp->bnum); + core_id = ON_BOARD_CORE_NUM(cpuid); + strand_id = STRAND_ID(cpuid); + p->bp->cores[core_id].core_present |= (1 << strand_id); + return (DDI_WALK_CONTINUE); + } + + return (DDI_WALK_PRUNECHILD); +} + + +static void +drmach_setup_core_info(drmach_board_t *obj) +{ + struct drmach_setup_core_arg arg; + int i; + + for (i = 0; i < OPL_MAX_COREID_PER_BOARD; i++) { + obj->cores[i].core_present = 0; + obj->cores[i].core_hotadded = 0; + obj->cores[i].core_started = 0; + } + arg.bp = obj; + ddi_walk_devs(ddi_root_node(), drmach_setup_core_cb, (void *)&arg); + + for (i = 0; i < OPL_MAX_COREID_PER_BOARD; i++) { + if (obj->boot_board) { + obj->cores[i].core_hotadded = + obj->cores[i].core_started = + obj->cores[i].core_present; + } + } +} + +/* + * drmach_node_* routines serve the purpose of separating the + * rest of the code from the device tree and OBP. This is necessary + * because of In-Kernel-Probing. Devices probed after stod, are probed + * by the in-kernel-prober, not OBP. These devices, therefore, do not + * have dnode ids. + */ + +typedef struct { + drmach_node_walk_args_t *nwargs; + int (*cb)(drmach_node_walk_args_t *args); + int err; +} drmach_node_ddi_walk_args_t; + +static int +drmach_node_ddi_walk_cb(dev_info_t *dip, void *arg) +{ + drmach_node_ddi_walk_args_t *nargs; + + nargs = (drmach_node_ddi_walk_args_t *)arg; + + /* + * dip doesn't have to be held here as we are called + * from ddi_walk_devs() which holds the dip. + */ + nargs->nwargs->node->here = (void *)dip; + + nargs->err = nargs->cb(nargs->nwargs); + + + /* + * Set "here" to NULL so that unheld dip is not accessible + * outside ddi_walk_devs() + */ + nargs->nwargs->node->here = NULL; + + if (nargs->err) + return (DDI_WALK_TERMINATE); + else + return (DDI_WALK_CONTINUE); +} + +static int +drmach_node_ddi_walk(drmach_node_t *np, void *data, + int (*cb)(drmach_node_walk_args_t *args)) +{ + drmach_node_walk_args_t args; + drmach_node_ddi_walk_args_t nargs; + + + /* initialized args structure for callback */ + args.node = np; + args.data = data; + + nargs.nwargs = &args; + nargs.cb = cb; + nargs.err = 0; + + /* + * Root node doesn't have to be held in any way. + */ + ddi_walk_devs(ddi_root_node(), drmach_node_ddi_walk_cb, + (void *)&nargs); + + return (nargs.err); +} + +static int +drmach_node_ddi_get_parent(drmach_node_t *np, drmach_node_t *pp) +{ + dev_info_t *ndip; + static char *fn = "drmach_node_ddi_get_parent"; + + ndip = np->n_getdip(np); + if (ndip == NULL) { + cmn_err(CE_WARN, "%s: NULL dip", fn); + return (-1); + } + + bcopy(np, pp, sizeof (drmach_node_t)); + + pp->here = (void *)ddi_get_parent(ndip); + if (pp->here == NULL) { + cmn_err(CE_WARN, "%s: NULL parent dip", fn); + return (-1); + } + + return (0); +} + +/*ARGSUSED*/ +static pnode_t +drmach_node_ddi_get_dnode(drmach_node_t *np) +{ + return ((pnode_t)NULL); +} + +static drmach_node_t * +drmach_node_new(void) +{ + drmach_node_t *np; + + np = kmem_zalloc(sizeof (drmach_node_t), KM_SLEEP); + + np->get_dnode = drmach_node_ddi_get_dnode; + np->walk = drmach_node_ddi_walk; + np->n_getdip = drmach_node_ddi_get_dip; + np->n_getproplen = drmach_node_ddi_get_proplen; + np->n_getprop = drmach_node_ddi_get_prop; + np->get_parent = drmach_node_ddi_get_parent; + + return (np); +} + +static void +drmach_node_dispose(drmach_node_t *np) +{ + kmem_free(np, sizeof (*np)); +} + +static dev_info_t * +drmach_node_ddi_get_dip(drmach_node_t *np) +{ + return ((dev_info_t *)np->here); +} + +static int +drmach_node_walk(drmach_node_t *np, void *param, + int (*cb)(drmach_node_walk_args_t *args)) +{ + return (np->walk(np, param, cb)); +} + +static int +drmach_node_ddi_get_prop(drmach_node_t *np, char *name, void *buf, int len) +{ + int rv = 0; + dev_info_t *ndip; + static char *fn = "drmach_node_ddi_get_prop"; + + + ndip = np->n_getdip(np); + if (ndip == NULL) { + cmn_err(CE_WARN, "%s: NULL dip", fn); + rv = -1; + } else if (ddi_getlongprop_buf(DDI_DEV_T_ANY, ndip, + DDI_PROP_DONTPASS, name, + (caddr_t)buf, &len) != DDI_PROP_SUCCESS) { + rv = -1; + } + + return (rv); +} + +static int +drmach_node_ddi_get_proplen(drmach_node_t *np, char *name, int *len) +{ + int rv = 0; + dev_info_t *ndip; + + ndip = np->n_getdip(np); + if (ndip == NULL) { + rv = -1; + } else if (ddi_getproplen(DDI_DEV_T_ANY, ndip, DDI_PROP_DONTPASS, + name, len) != DDI_PROP_SUCCESS) { + rv = -1; + } + + return (rv); +} + +static drmachid_t +drmach_node_dup(drmach_node_t *np) +{ + drmach_node_t *dup; + + dup = drmach_node_new(); + dup->here = np->here; + dup->get_dnode = np->get_dnode; + dup->walk = np->walk; + dup->n_getdip = np->n_getdip; + dup->n_getproplen = np->n_getproplen; + dup->n_getprop = np->n_getprop; + dup->get_parent = np->get_parent; + + return (dup); +} + +/* + * drmach_array provides convenient array construction, access, + * bounds checking and array destruction logic. + */ + +static drmach_array_t * +drmach_array_new(int min_index, int max_index) +{ + drmach_array_t *arr; + + arr = kmem_zalloc(sizeof (drmach_array_t), KM_SLEEP); + + arr->arr_sz = (max_index - min_index + 1) * sizeof (void *); + if (arr->arr_sz > 0) { + arr->min_index = min_index; + arr->max_index = max_index; + + arr->arr = kmem_zalloc(arr->arr_sz, KM_SLEEP); + return (arr); + } else { + kmem_free(arr, sizeof (*arr)); + return (0); + } +} + +static int +drmach_array_set(drmach_array_t *arr, int idx, drmachid_t val) +{ + if (idx < arr->min_index || idx > arr->max_index) + return (-1); + else { + arr->arr[idx - arr->min_index] = val; + return (0); + } + /*NOTREACHED*/ +} + +static int +drmach_array_get(drmach_array_t *arr, int idx, drmachid_t *val) +{ + if (idx < arr->min_index || idx > arr->max_index) + return (-1); + else { + *val = arr->arr[idx - arr->min_index]; + return (0); + } + /*NOTREACHED*/ +} + +static int +drmach_array_first(drmach_array_t *arr, int *idx, drmachid_t *val) +{ + int rv; + + *idx = arr->min_index; + while ((rv = drmach_array_get(arr, *idx, val)) == 0 && *val == NULL) + *idx += 1; + + return (rv); +} + +static int +drmach_array_next(drmach_array_t *arr, int *idx, drmachid_t *val) +{ + int rv; + + *idx += 1; + while ((rv = drmach_array_get(arr, *idx, val)) == 0 && *val == NULL) + *idx += 1; + + return (rv); +} + +static void +drmach_array_dispose(drmach_array_t *arr, void (*disposer)(drmachid_t)) +{ + drmachid_t val; + int idx; + int rv; + + rv = drmach_array_first(arr, &idx, &val); + while (rv == 0) { + (*disposer)(val); + rv = drmach_array_next(arr, &idx, &val); + } + + kmem_free(arr->arr, arr->arr_sz); + kmem_free(arr, sizeof (*arr)); +} + +static drmach_board_t * +drmach_get_board_by_bnum(int bnum) +{ + drmachid_t id; + + if (drmach_array_get(drmach_boards, bnum, &id) == 0) + return ((drmach_board_t *)id); + else + return (NULL); +} + +static pnode_t +drmach_node_get_dnode(drmach_node_t *np) +{ + return (np->get_dnode(np)); +} + +/*ARGSUSED*/ +sbd_error_t * +drmach_configure(drmachid_t id, int flags) +{ + drmach_device_t *dp; + sbd_error_t *err = NULL; + dev_info_t *rdip; + dev_info_t *fdip = NULL; + + if (DRMACH_IS_CPU_ID(id)) { + return (NULL); + } + if (!DRMACH_IS_DEVICE_ID(id)) + return (drerr_new(0, EOPL_INAPPROP, NULL)); + dp = id; + rdip = dp->node->n_getdip(dp->node); + + ASSERT(rdip); + + ASSERT(e_ddi_branch_held(rdip)); + + if (e_ddi_branch_configure(rdip, &fdip, 0) != 0) { + char *path = kmem_alloc(MAXPATHLEN, KM_SLEEP); + dev_info_t *dip = (fdip != NULL) ? fdip : rdip; + + (void) ddi_pathname(dip, path); + err = drerr_new(1, EOPL_DRVFAIL, path); + + kmem_free(path, MAXPATHLEN); + + /* If non-NULL, fdip is returned held and must be released */ + if (fdip != NULL) + ddi_release_devi(fdip); + } + + return (err); +} + + +static sbd_error_t * +drmach_device_new(drmach_node_t *node, + drmach_board_t *bp, int portid, drmachid_t *idp) +{ + int i; + int rv; + drmach_device_t proto; + sbd_error_t *err; + char name[OBP_MAXDRVNAME]; + + rv = node->n_getprop(node, "name", name, OBP_MAXDRVNAME); + if (rv) { + /* every node is expected to have a name */ + err = drerr_new(1, EOPL_GETPROP, + "device node %s: property %s", + ddi_node_name(node->n_getdip(node)), "name"); + return (err); + } + + /* + * The node currently being examined is not listed in the name2type[] + * array. In this case, the node is no interest to drmach. Both + * dp and err are initialized here to yield nothing (no device or + * error structure) for this case. + */ + i = drmach_name2type_idx(name); + + + if (i < 0) { + *idp = (drmachid_t)0; + return (NULL); + } + + /* device specific new function will set unum */ + + bzero(&proto, sizeof (proto)); + proto.type = drmach_name2type[i].type; + proto.bp = bp; + proto.node = node; + proto.portid = portid; + + return (drmach_name2type[i].new(&proto, idp)); +} + +static void +drmach_device_dispose(drmachid_t id) +{ + drmach_device_t *self = id; + + self->cm.dispose(id); +} + + +static drmach_board_t * +drmach_board_new(int bnum, int boot_board) +{ + static sbd_error_t *drmach_board_release(drmachid_t); + static sbd_error_t *drmach_board_status(drmachid_t, drmach_status_t *); + + drmach_board_t *bp; + + bp = kmem_zalloc(sizeof (drmach_board_t), KM_SLEEP); + + bp->cm.isa = (void *)drmach_board_new; + bp->cm.release = drmach_board_release; + bp->cm.status = drmach_board_status; + + (void) drmach_board_name(bnum, bp->cm.name, sizeof (bp->cm.name)); + + bp->bnum = bnum; + bp->devices = NULL; + bp->connected = boot_board; + bp->tree = drmach_node_new(); + bp->assigned = boot_board; + bp->powered = boot_board; + bp->boot_board = boot_board; + + /* + * If this is not bootup initialization, we have to wait till + * IKP sets up the device nodes in drmach_board_connect(). + */ + if (boot_board) + drmach_setup_core_info(bp); + + drmach_array_set(drmach_boards, bnum, bp); + return (bp); +} + +static void +drmach_board_dispose(drmachid_t id) +{ + drmach_board_t *bp; + + ASSERT(DRMACH_IS_BOARD_ID(id)); + bp = id; + + if (bp->tree) + drmach_node_dispose(bp->tree); + + if (bp->devices) + drmach_array_dispose(bp->devices, drmach_device_dispose); + + kmem_free(bp, sizeof (*bp)); +} + +static sbd_error_t * +drmach_board_status(drmachid_t id, drmach_status_t *stat) +{ + sbd_error_t *err = NULL; + drmach_board_t *bp; + + if (!DRMACH_IS_BOARD_ID(id)) + return (drerr_new(0, EOPL_INAPPROP, NULL)); + bp = id; + + stat->assigned = bp->assigned; + stat->powered = bp->powered; + stat->busy = 0; /* assume not busy */ + stat->configured = 0; /* assume not configured */ + stat->empty = 0; + stat->cond = bp->cond = SBD_COND_OK; + strncpy(stat->type, "System Brd", sizeof (stat->type)); + stat->info[0] = '\0'; + + if (bp->devices) { + int rv; + int d_idx; + drmachid_t d_id; + + rv = drmach_array_first(bp->devices, &d_idx, &d_id); + while (rv == 0) { + drmach_status_t d_stat; + + err = drmach_i_status(d_id, &d_stat); + if (err) + break; + + stat->busy |= d_stat.busy; + stat->configured |= d_stat.configured; + + rv = drmach_array_next(bp->devices, &d_idx, &d_id); + } + } + + return (err); +} + +int +drmach_board_is_floating(drmachid_t id) +{ + drmach_board_t *bp; + + if (!DRMACH_IS_BOARD_ID(id)) + return (0); + + bp = (drmach_board_t *)id; + + return ((drmach_domain.floating & (1 << bp->bnum)) ? 1 : 0); +} + +static int +drmach_init(void) +{ + dev_info_t *rdip; + int i, rv, len; + int *floating; + + rw_init(&drmach_boards_rwlock, NULL, RW_DEFAULT, NULL); + + drmach_boards = drmach_array_new(0, MAX_BOARDS - 1); + + rdip = ddi_root_node(); + + if (ddi_getproplen(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS, + "floating-boards", &len) != DDI_PROP_SUCCESS) { + cmn_err(CE_WARN, "Cannot get floating-boards proplen\n"); + } else { + floating = (int *)kmem_alloc(len, KM_SLEEP); + rv = ddi_prop_op(DDI_DEV_T_ANY, rdip, + PROP_LEN_AND_VAL_BUF, DDI_PROP_DONTPASS, + "floating-boards", (caddr_t)floating, &len); + if (rv != DDI_PROP_SUCCESS) { + cmn_err(CE_WARN, "Cannot get floating-boards prop\n"); + } else { + drmach_domain.floating = 0; + for (i = 0; i < len / sizeof (int); i++) { + drmach_domain.floating |= (1 << floating[i]); + } + } + kmem_free(floating, len); + } + drmach_domain.allow_dr = opl_check_dr_status(); + + rdip = ddi_get_child(ddi_root_node()); + do { + int bnum; + drmachid_t id; + + bnum = -1; + bnum = ddi_getprop(DDI_DEV_T_ANY, rdip, + DDI_PROP_DONTPASS, OBP_BOARDNUM, -1); + if (bnum == -1) + continue; + + if (drmach_array_get(drmach_boards, bnum, &id) == -1) { + cmn_err(CE_WARN, "Device node 0x%p has" + " invalid property value, %s=%d", + rdip, OBP_BOARDNUM, bnum); + goto error; + } else if (id == NULL) { + (void) drmach_board_new(bnum, 1); + } + } while ((rdip = ddi_get_next_sibling(rdip)) != NULL); + + opl_hold_devtree(); + + /* + * Initialize the IKP feature. + * + * This can be done only after DR has acquired a hold on all the + * device nodes that are interesting to IKP. + */ + if (opl_init_cfg() != 0) { + cmn_err(CE_WARN, "DR - IKP initialization failed"); + + opl_release_devtree(); + + goto error; + } + + return (0); +error: + drmach_array_dispose(drmach_boards, drmach_board_dispose); + rw_destroy(&drmach_boards_rwlock); + return (ENXIO); +} + +static void +drmach_fini(void) +{ + rw_enter(&drmach_boards_rwlock, RW_WRITER); + drmach_array_dispose(drmach_boards, drmach_board_dispose); + drmach_boards = NULL; + rw_exit(&drmach_boards_rwlock); + + /* + * Walk immediate children of the root devinfo node + * releasing holds acquired on branches in drmach_init() + */ + + opl_release_devtree(); + + rw_destroy(&drmach_boards_rwlock); +} + +/* + * Each system board contains 2 Oberon PCI bridge and + * 1 CMUCH. + * Each oberon has 2 channels. + * Each channel has 2 pci-ex leaf. + * Each CMUCH has 1 pci bus. + * + * + * Device Path: + * /pci@<portid>,reg + * + * where + * portid[10] = 0 + * portid[9:0] = LLEAF_ID[9:0] of the Oberon Channel + * + * LLEAF_ID[9:8] = 0 + * LLEAF_ID[8:4] = LSB_ID[4:0] + * LLEAF_ID[3:1] = IO Channel#[2:0] (0,1,2,3 for Oberon) + * channel 4 is pcicmu + * LLEAF_ID[0] = PCI Leaf Number (0 for leaf-A, 1 for leaf-B) + * + * Properties: + * name = pci + * device_type = "pciex" + * board# = LSBID + * reg = int32 * 2, Oberon CSR space of the leaf and the UBC space + * portid = Jupiter Bus Device ID ((LSB_ID << 3)|pciport#) + */ + +static sbd_error_t * +drmach_io_new(drmach_device_t *proto, drmachid_t *idp) +{ + drmach_io_t *ip; + + int portid; + + portid = proto->portid; + ASSERT(portid != -1); + proto->unum = portid & (MAX_IO_UNITS_PER_BOARD - 1); + + ip = kmem_zalloc(sizeof (drmach_io_t), KM_SLEEP); + bcopy(proto, &ip->dev, sizeof (ip->dev)); + ip->dev.node = drmach_node_dup(proto->node); + ip->dev.cm.isa = (void *)drmach_io_new; + ip->dev.cm.dispose = drmach_io_dispose; + ip->dev.cm.release = drmach_io_release; + ip->dev.cm.status = drmach_io_status; + ip->channel = (portid >> 1) & 0x7; + ip->leaf = (portid & 0x1); + + snprintf(ip->dev.cm.name, sizeof (ip->dev.cm.name), "%s%d", + ip->dev.type, ip->dev.unum); + + *idp = (drmachid_t)ip; + return (NULL); +} + + +static void +drmach_io_dispose(drmachid_t id) +{ + drmach_io_t *self; + + ASSERT(DRMACH_IS_IO_ID(id)); + + self = id; + if (self->dev.node) + drmach_node_dispose(self->dev.node); + + kmem_free(self, sizeof (*self)); +} + +/*ARGSUSED*/ +sbd_error_t * +drmach_pre_op(int cmd, drmachid_t id, drmach_opts_t *opts) +{ + drmach_board_t *bp = (drmach_board_t *)id; + sbd_error_t *err = NULL; + + /* allow status and ncm operations to always succeed */ + if ((cmd == SBD_CMD_STATUS) || (cmd == SBD_CMD_GETNCM)) { + return (NULL); + } + + /* check all other commands for the required option string */ + + if ((opts->size > 0) && (opts->copts != NULL)) { + + DRMACH_PR("platform options: %s\n", opts->copts); + + if (strstr(opts->copts, "opldr") == NULL) { + err = drerr_new(1, EOPL_SUPPORT, NULL); + } + } else { + err = drerr_new(1, EOPL_SUPPORT, NULL); + } + + if (!err && id && DRMACH_IS_BOARD_ID(id)) { + switch (cmd) { + case SBD_CMD_TEST: + case SBD_CMD_STATUS: + case SBD_CMD_GETNCM: + break; + case SBD_CMD_CONNECT: + if (bp->connected) + err = drerr_new(0, ESBD_STATE, NULL); + else if (!drmach_domain.allow_dr) + err = drerr_new(1, EOPL_SUPPORT, + NULL); + break; + case SBD_CMD_DISCONNECT: + if (!bp->connected) + err = drerr_new(0, ESBD_STATE, NULL); + else if (!drmach_domain.allow_dr) + err = drerr_new(1, EOPL_SUPPORT, + NULL); + break; + default: + if (!drmach_domain.allow_dr) + err = drerr_new(1, EOPL_SUPPORT, + NULL); + break; + + } + } + + return (err); +} + +/*ARGSUSED*/ +sbd_error_t * +drmach_post_op(int cmd, drmachid_t id, drmach_opts_t *opts) +{ + return (NULL); +} + +sbd_error_t * +drmach_board_assign(int bnum, drmachid_t *id) +{ + sbd_error_t *err = NULL; + + rw_enter(&drmach_boards_rwlock, RW_WRITER); + + if (drmach_array_get(drmach_boards, bnum, id) == -1) { + err = drerr_new(1, EOPL_BNUM, "%d", bnum); + } else { + drmach_board_t *bp; + + if (*id) + rw_downgrade(&drmach_boards_rwlock); + + bp = *id; + if (!(*id)) + bp = *id = + (drmachid_t)drmach_board_new(bnum, 0); + bp->assigned = 1; + } + + rw_exit(&drmach_boards_rwlock); + + return (err); +} + +/*ARGSUSED*/ +sbd_error_t * +drmach_board_connect(drmachid_t id, drmach_opts_t *opts) +{ + drmach_board_t *obj = (drmach_board_t *)id; + + if (!DRMACH_IS_BOARD_ID(id)) + return (drerr_new(0, EOPL_INAPPROP, NULL)); + + if (opl_probe_sb(obj->bnum) != 0) + return (DRMACH_INTERNAL_ERROR()); + + (void) prom_attach_notice(obj->bnum); + + drmach_setup_core_info(obj); + + obj->connected = 1; + + return (NULL); +} + +static int drmach_cache_flush_flag[NCPU]; + +/*ARGSUSED*/ +static void +drmach_flush_cache(uint64_t id, uint64_t dummy) +{ + extern void cpu_flush_ecache(void); + + cpu_flush_ecache(); + drmach_cache_flush_flag[id] = 0; +} + +static void +drmach_flush_all() +{ + cpuset_t xc_cpuset; + int i; + + xc_cpuset = cpu_ready_set; + for (i = 0; i < NCPU; i++) { + if (CPU_IN_SET(xc_cpuset, i)) { + drmach_cache_flush_flag[i] = 1; + xc_one(i, drmach_flush_cache, i, 0); + while (drmach_cache_flush_flag[i]) { + DELAY(1000); + } + } + } +} + +static int +drmach_disconnect_cpus(drmach_board_t *bp) +{ + int i, bnum; + + bnum = bp->bnum; + + for (i = 0; i < OPL_MAX_COREID_PER_BOARD; i++) { + if (bp->cores[i].core_present) { + if (bp->cores[i].core_started) + return (-1); + if (bp->cores[i].core_hotadded) { + if (drmach_add_remove_cpu(bnum, i, HOTREMOVE_CPU)) { + cmn_err(CE_WARN, + "Failed to remove CMP %d on board %d\n", + i, bnum); + return (-1); + } + } + } + } + return (0); +} + +/*ARGSUSED*/ +sbd_error_t * +drmach_board_disconnect(drmachid_t id, drmach_opts_t *opts) +{ + drmach_board_t *obj; + int rv = 0; + sbd_error_t *err = NULL; + + + if (!DRMACH_IS_BOARD_ID(id)) + return (drerr_new(0, EOPL_INAPPROP, NULL)); + + + + obj = (drmach_board_t *)id; + + if (drmach_disconnect_cpus(obj)) { + err = drerr_new(0, EOPL_DEPROBE, obj->cm.name); + return (err); + } + + rv = opl_unprobe_sb(obj->bnum); + + if (rv == 0) { + prom_detach_notice(obj->bnum); + obj->connected = 0; + + } else + err = drerr_new(0, EOPL_DEPROBE, obj->cm.name); + + return (err); +} + +static int +drmach_get_portid(drmach_node_t *np) +{ + int portid; + char type[OBP_MAXPROPNAME]; + + if (np->n_getprop(np, "portid", &portid, sizeof (portid)) == 0) + return (portid); + + /* + * Get the device_type property to see if we should + * continue processing this node. + */ + if (np->n_getprop(np, "device_type", &type, sizeof (type)) != 0) + return (-1); + + if (strcmp(type, OPL_CPU_NODE) == 0) { + /* + * We return cpuid because it has no portid + */ + if (np->n_getprop(np, "cpuid", &portid, sizeof (portid)) == 0) + return (portid); + } + + return (-1); +} + +/* + * This is a helper function to determine if a given + * node should be considered for a dr operation according + * to predefined dr type nodes and the node's name. + * Formal Parameter : The name of a device node. + * Return Value: -1, name does not map to a valid dr type. + * A value greater or equal to 0, name is a valid dr type. + */ +static int +drmach_name2type_idx(char *name) +{ + int index, ntypes; + + if (name == NULL) + return (-1); + + /* + * Determine how many possible types are currently supported + * for dr. + */ + ntypes = sizeof (drmach_name2type) / sizeof (drmach_name2type[0]); + + /* Determine if the node's name correspond to a predefined type. */ + for (index = 0; index < ntypes; index++) { + if (strcmp(drmach_name2type[index].name, name) == 0) + /* The node is an allowed type for dr. */ + return (index); + } + + /* + * If the name of the node does not map to any of the + * types in the array drmach_name2type then the node is not of + * interest to dr. + */ + return (-1); +} + +/* + * there is some complication on OPL: + * - pseudo-mc nodes do not have portid property + * - portid[9:5] of cmp node is LSB #, portid[7:3] of pci is LSB# + * - cmp has board# + * - core and cpu nodes do not have portid and board# properties + * starcat uses portid to derive the board# but that does not work + * for us. starfire reads board# property to filter the devices. + * That does not work either. So for these specific device, + * we use specific hard coded methods to get the board# - + * cpu: LSB# = CPUID[9:5] + */ + +static int +drmach_board_find_devices_cb(drmach_node_walk_args_t *args) +{ + drmach_node_t *node = args->node; + drmach_board_cb_data_t *data = args->data; + drmach_board_t *obj = data->obj; + + int rv, portid; + int bnum; + drmachid_t id; + drmach_device_t *device; + char name[OBP_MAXDRVNAME]; + + portid = drmach_get_portid(node); + /* + * core, cpu and pseudo-mc do not have portid + * we use cpuid as the portid of the cpu node + * for pseudo-mc, we do not use portid info. + */ + + rv = node->n_getprop(node, "name", name, OBP_MAXDRVNAME); + if (rv) + return (0); + + + rv = node->n_getprop(node, OBP_BOARDNUM, &bnum, sizeof (bnum)); + + if (rv) { + /* + * cpu does not have board# property. We use + * CPUID[9:5] + */ + if (strcmp("cpu", name) == 0) { + bnum = (portid >> 5) & 0x1f; + } else + return (0); + } + + + if (bnum != obj->bnum) + return (0); + + if (drmach_name2type_idx(name) < 0) { + return (0); + } + + /* + * Create a device data structure from this node data. + * The call may yield nothing if the node is not of interest + * to drmach. + */ + data->err = drmach_device_new(node, obj, portid, &id); + if (data->err) + return (-1); + else if (!id) { + /* + * drmach_device_new examined the node we passed in + * and determined that it was one not of interest to + * drmach. So, it is skipped. + */ + return (0); + } + + rv = drmach_array_set(obj->devices, data->ndevs++, id); + if (rv) { + data->err = DRMACH_INTERNAL_ERROR(); + return (-1); + } + device = id; + + data->err = (*data->found)(data->a, device->type, device->unum, id); + return (data->err == NULL ? 0 : -1); +} + +sbd_error_t * +drmach_board_find_devices(drmachid_t id, void *a, + sbd_error_t *(*found)(void *a, const char *, int, drmachid_t)) +{ + drmach_board_t *bp = (drmach_board_t *)id; + sbd_error_t *err; + int max_devices; + int rv; + drmach_board_cb_data_t data; + + + if (!DRMACH_IS_BOARD_ID(id)) + return (drerr_new(0, EOPL_INAPPROP, NULL)); + + max_devices = MAX_CPU_UNITS_PER_BOARD; + max_devices += MAX_MEM_UNITS_PER_BOARD; + max_devices += MAX_IO_UNITS_PER_BOARD; + + bp->devices = drmach_array_new(0, max_devices); + + if (bp->tree == NULL) + bp->tree = drmach_node_new(); + + data.obj = bp; + data.ndevs = 0; + data.found = found; + data.a = a; + data.err = NULL; + + rv = drmach_node_walk(bp->tree, &data, drmach_board_find_devices_cb); + if (rv == 0) + err = NULL; + else { + drmach_array_dispose(bp->devices, drmach_device_dispose); + bp->devices = NULL; + + if (data.err) + err = data.err; + else + err = DRMACH_INTERNAL_ERROR(); + } + + return (err); +} + +int +drmach_board_lookup(int bnum, drmachid_t *id) +{ + int rv = 0; + + rw_enter(&drmach_boards_rwlock, RW_READER); + if (drmach_array_get(drmach_boards, bnum, id)) { + *id = 0; + rv = -1; + } + rw_exit(&drmach_boards_rwlock); + return (rv); +} + +sbd_error_t * +drmach_board_name(int bnum, char *buf, int buflen) +{ + snprintf(buf, buflen, "SB%d", bnum); + return (NULL); +} + +sbd_error_t * +drmach_board_poweroff(drmachid_t id) +{ + drmach_board_t *bp; + sbd_error_t *err; + drmach_status_t stat; + + if (!DRMACH_IS_BOARD_ID(id)) + return (drerr_new(0, EOPL_INAPPROP, NULL)); + bp = id; + + err = drmach_board_status(id, &stat); + + if (!err) { + if (stat.configured || stat.busy) + err = drerr_new(0, EOPL_CONFIGBUSY, bp->cm.name); + else { + bp->powered = 0; + } + } + return (err); +} + +sbd_error_t * +drmach_board_poweron(drmachid_t id) +{ + drmach_board_t *bp; + + if (!DRMACH_IS_BOARD_ID(id)) + return (drerr_new(0, EOPL_INAPPROP, NULL)); + bp = id; + + bp->powered = 1; + + return (NULL); +} + +static sbd_error_t * +drmach_board_release(drmachid_t id) +{ + if (!DRMACH_IS_BOARD_ID(id)) + return (drerr_new(0, EOPL_INAPPROP, NULL)); + return (NULL); +} + +/*ARGSUSED*/ +sbd_error_t * +drmach_board_test(drmachid_t id, drmach_opts_t *opts, int force) +{ + return (NULL); +} + +sbd_error_t * +drmach_board_unassign(drmachid_t id) +{ + drmach_board_t *bp; + sbd_error_t *err; + drmach_status_t stat; + + + if (!DRMACH_IS_BOARD_ID(id)) { + return (drerr_new(0, EOPL_INAPPROP, NULL)); + } + bp = id; + + rw_enter(&drmach_boards_rwlock, RW_WRITER); + + err = drmach_board_status(id, &stat); + if (err) { + rw_exit(&drmach_boards_rwlock); + return (err); + } + if (stat.configured || stat.busy) { + err = drerr_new(0, EOPL_CONFIGBUSY, bp->cm.name); + } else { + if (drmach_array_set(drmach_boards, bp->bnum, 0) != 0) + err = DRMACH_INTERNAL_ERROR(); + else + drmach_board_dispose(bp); + } + rw_exit(&drmach_boards_rwlock); + return (err); +} + +/* + * We have to do more on OPL - e.g. set up sram tte, read cpuid, strand id, + * implementation #, etc + */ + +static sbd_error_t * +drmach_cpu_new(drmach_device_t *proto, drmachid_t *idp) +{ + static void drmach_cpu_dispose(drmachid_t); + static sbd_error_t *drmach_cpu_release(drmachid_t); + static sbd_error_t *drmach_cpu_status(drmachid_t, drmach_status_t *); + + int portid; + drmach_cpu_t *cp = NULL; + + /* portid is CPUID of the node */ + portid = proto->portid; + ASSERT(portid != -1); + + /* unum = (CMP/CHIP ID) + (ON_BOARD_CORE_NUM * MAX_CMPID_PER_BOARD) */ + proto->unum = ((portid/OPL_MAX_CPUID_PER_CMP) & + (OPL_MAX_CMPID_PER_BOARD - 1)) + + ((portid & (OPL_MAX_CPUID_PER_CMP - 1)) * + (OPL_MAX_CMPID_PER_BOARD)); + + cp = kmem_zalloc(sizeof (drmach_cpu_t), KM_SLEEP); + bcopy(proto, &cp->dev, sizeof (cp->dev)); + cp->dev.node = drmach_node_dup(proto->node); + cp->dev.cm.isa = (void *)drmach_cpu_new; + cp->dev.cm.dispose = drmach_cpu_dispose; + cp->dev.cm.release = drmach_cpu_release; + cp->dev.cm.status = drmach_cpu_status; + + snprintf(cp->dev.cm.name, sizeof (cp->dev.cm.name), "%s%d", + cp->dev.type, cp->dev.unum); + +/* + * CPU ID representation + * CPUID[9:5] = SB# + * CPUID[4:3] = Chip# + * CPUID[2:1] = Core# (Only 2 core for OPL) + * CPUID[0:0] = Strand# + */ + +/* + * reg property of the strand contains strand ID + * reg property of the parent node contains core ID + * We should use them. + */ + cp->cpuid = portid; + cp->sb = (portid >> 5) & 0x1f; + cp->chipid = (portid >> 3) & 0x3; + cp->coreid = (portid >> 1) & 0x3; + cp->strandid = portid & 0x1; + + *idp = (drmachid_t)cp; + return (NULL); +} + + +static void +drmach_cpu_dispose(drmachid_t id) +{ + drmach_cpu_t *self; + + ASSERT(DRMACH_IS_CPU_ID(id)); + + self = id; + if (self->dev.node) + drmach_node_dispose(self->dev.node); + + kmem_free(self, sizeof (*self)); +} + +static int +drmach_cpu_start(struct cpu *cp) +{ + int cpuid = cp->cpu_id; + extern int restart_other_cpu(int); + + ASSERT(MUTEX_HELD(&cpu_lock)); + ASSERT(cpunodes[cpuid].nodeid != (pnode_t)0); + + cp->cpu_flags &= ~CPU_POWEROFF; + + /* + * NOTE: restart_other_cpu pauses cpus during the + * slave cpu start. This helps to quiesce the + * bus traffic a bit which makes the tick sync + * routine in the prom more robust. + */ + DRMACH_PR("COLD START for cpu (%d)\n", cpuid); + + restart_other_cpu(cpuid); + + return (0); +} + +static sbd_error_t * +drmach_cpu_release(drmachid_t id) +{ + if (!DRMACH_IS_CPU_ID(id)) + return (drerr_new(0, EOPL_INAPPROP, NULL)); + + return (NULL); +} + +static sbd_error_t * +drmach_cpu_status(drmachid_t id, drmach_status_t *stat) +{ + drmach_cpu_t *cp; + drmach_device_t *dp; + + ASSERT(DRMACH_IS_CPU_ID(id)); + cp = (drmach_cpu_t *)id; + dp = &cp->dev; + + stat->assigned = dp->bp->assigned; + stat->powered = dp->bp->powered; + mutex_enter(&cpu_lock); + stat->configured = (cpu_get(cp->cpuid) != NULL); + mutex_exit(&cpu_lock); + stat->busy = dp->busy; + strncpy(stat->type, dp->type, sizeof (stat->type)); + stat->info[0] = '\0'; + + return (NULL); +} + +sbd_error_t * +drmach_cpu_disconnect(drmachid_t id) +{ + + if (!DRMACH_IS_CPU_ID(id)) + return (drerr_new(0, EOPL_INAPPROP, NULL)); + + return (NULL); +} + +sbd_error_t * +drmach_cpu_get_id(drmachid_t id, processorid_t *cpuid) +{ + drmach_cpu_t *cpu; + + if (!DRMACH_IS_CPU_ID(id)) + return (drerr_new(0, EOPL_INAPPROP, NULL)); + cpu = (drmach_cpu_t *)id; + + /* get from cpu directly on OPL */ + *cpuid = cpu->cpuid; + return (NULL); +} + +sbd_error_t * +drmach_cpu_get_impl(drmachid_t id, int *ip) +{ + drmach_device_t *cpu; + drmach_node_t *np; + drmach_node_t pp; + int impl; + char type[OBP_MAXPROPNAME]; + + if (!DRMACH_IS_CPU_ID(id)) + return (drerr_new(0, EOPL_INAPPROP, NULL)); + + cpu = id; + np = cpu->node; + + if (np->get_parent(np, &pp) != 0) { + return (DRMACH_INTERNAL_ERROR()); + } + + /* the parent should be core */ + + if (pp.n_getprop(&pp, "device_type", &type, sizeof (type)) != 0) { + return (drerr_new(0, EOPL_GETPROP, NULL)); + } + + if (strcmp(type, OPL_CORE_NODE) == 0) { + if (pp.n_getprop(&pp, "implementation#", + &impl, sizeof (impl)) != 0) { + return (drerr_new(0, EOPL_GETPROP, NULL)); + } + } else { + return (DRMACH_INTERNAL_ERROR()); + } + + *ip = impl; + + return (NULL); +} + +sbd_error_t * +drmach_get_dip(drmachid_t id, dev_info_t **dip) +{ + drmach_device_t *dp; + + if (!DRMACH_IS_DEVICE_ID(id)) + return (drerr_new(0, EOPL_INAPPROP, NULL)); + dp = id; + + *dip = dp->node->n_getdip(dp->node); + return (NULL); +} + +sbd_error_t * +drmach_io_is_attached(drmachid_t id, int *yes) +{ + drmach_device_t *dp; + dev_info_t *dip; + int state; + + if (!DRMACH_IS_IO_ID(id)) + return (drerr_new(0, EOPL_INAPPROP, NULL)); + dp = id; + + dip = dp->node->n_getdip(dp->node); + if (dip == NULL) { + *yes = 0; + return (NULL); + } + + state = ddi_get_devstate(dip); + *yes = ((i_ddi_node_state(dip) >= DS_ATTACHED) || + (state == DDI_DEVSTATE_UP)); + + return (NULL); +} + +struct drmach_io_cb { + char *name; /* name of the node */ + int (*func)(dev_info_t *); + int rv; +}; + +#define DRMACH_IO_POST_ATTACH 0 +#define DRMACH_IO_PRE_RELEASE 1 + +static int +drmach_io_cb_check(dev_info_t *dip, void *arg) +{ + struct drmach_io_cb *p = (struct drmach_io_cb *)arg; + char name[OBP_MAXDRVNAME]; + int len = OBP_MAXDRVNAME; + + if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, + DDI_PROP_DONTPASS, "name", + (caddr_t)name, &len) != DDI_PROP_SUCCESS) { + return (DDI_WALK_PRUNECHILD); + } + + if (strcmp(name, p->name) == 0) { + p->rv = (*p->func)(dip); + return (DDI_WALK_TERMINATE); + } + + return (DDI_WALK_CONTINUE); +} + + +static int +drmach_console_ops(drmachid_t *id, int state) +{ + drmach_io_t *obj = (drmach_io_t *)id; + struct drmach_io_cb arg; + int (*msudetp)(dev_info_t *); + int (*msuattp)(dev_info_t *); + dev_info_t *dip, *pdip; + int circ; + + /* 4 is pcicmu channel */ + if (obj->channel != 4) + return (0); + + arg.name = "serial"; + arg.func = NULL; + if (state == DRMACH_IO_PRE_RELEASE) { + msudetp = (int (*)(dev_info_t *)) + modgetsymvalue("oplmsu_dr_detach", 0); + if (msudetp != NULL) + arg.func = msudetp; + } else if (state == DRMACH_IO_POST_ATTACH) { + msuattp = (int (*)(dev_info_t *)) + modgetsymvalue("oplmsu_dr_attach", 0); + if (msuattp != NULL) + arg.func = msuattp; + } + else + return (0); + + if (arg.func == NULL) { + return (0); + } + + arg.rv = 0; + + dip = obj->dev.node->n_getdip(obj->dev.node); + if (pdip = ddi_get_parent(dip)) { + ndi_hold_devi(pdip); + ndi_devi_enter(pdip, &circ); + } else { + /* this cannot happen unless something bad happens */ + return (-1); + } + + ddi_walk_devs(dip, drmach_io_cb_check, (void *)&arg); + + if (pdip) { + ndi_devi_exit(pdip, circ); + ndi_rele_devi(pdip); + } + + return (arg.rv); +} + +sbd_error_t * +drmach_io_pre_release(drmachid_t id) +{ + int rv; + + if (!DRMACH_IS_IO_ID(id)) + return (drerr_new(0, EOPL_INAPPROP, NULL)); + + rv = drmach_console_ops(id, DRMACH_IO_PRE_RELEASE); + + if (rv != 0) + cmn_err(CE_WARN, "IO callback failed in pre-release\n"); + + return (NULL); +} + +static sbd_error_t * +drmach_io_release(drmachid_t id) +{ + if (!DRMACH_IS_IO_ID(id)) + return (drerr_new(0, EOPL_INAPPROP, NULL)); + return (NULL); +} + +sbd_error_t * +drmach_io_unrelease(drmachid_t id) +{ + if (!DRMACH_IS_IO_ID(id)) + return (drerr_new(0, EOPL_INAPPROP, NULL)); + return (NULL); +} + +/*ARGSUSED*/ +sbd_error_t * +drmach_io_post_release(drmachid_t id) +{ + return (NULL); +} + +/*ARGSUSED*/ +sbd_error_t * +drmach_io_post_attach(drmachid_t id) +{ + int rv; + + if (!DRMACH_IS_IO_ID(id)) + return (drerr_new(0, EOPL_INAPPROP, NULL)); + + rv = drmach_console_ops(id, DRMACH_IO_POST_ATTACH); + + if (rv != 0) + cmn_err(CE_WARN, "IO callback failed in post-attach\n"); + + return (0); +} + +static sbd_error_t * +drmach_io_status(drmachid_t id, drmach_status_t *stat) +{ + drmach_device_t *dp; + sbd_error_t *err; + int configured; + + ASSERT(DRMACH_IS_IO_ID(id)); + dp = id; + + err = drmach_io_is_attached(id, &configured); + if (err) + return (err); + + stat->assigned = dp->bp->assigned; + stat->powered = dp->bp->powered; + stat->configured = (configured != 0); + stat->busy = dp->busy; + strncpy(stat->type, dp->type, sizeof (stat->type)); + stat->info[0] = '\0'; + + return (NULL); +} + +static sbd_error_t * +drmach_mem_new(drmach_device_t *proto, drmachid_t *idp) +{ + static void drmach_mem_dispose(drmachid_t); + static sbd_error_t *drmach_mem_release(drmachid_t); + static sbd_error_t *drmach_mem_status(drmachid_t, drmach_status_t *); + dev_info_t *dip; + + drmach_mem_t *mp; + + mp = kmem_zalloc(sizeof (drmach_mem_t), KM_SLEEP); + proto->unum = 0; + + bcopy(proto, &mp->dev, sizeof (mp->dev)); + mp->dev.node = drmach_node_dup(proto->node); + mp->dev.cm.isa = (void *)drmach_mem_new; + mp->dev.cm.dispose = drmach_mem_dispose; + mp->dev.cm.release = drmach_mem_release; + mp->dev.cm.status = drmach_mem_status; + + snprintf(mp->dev.cm.name, + sizeof (mp->dev.cm.name), "%s", mp->dev.type); + + dip = mp->dev.node->n_getdip(mp->dev.node); + if (drmach_setup_mc_info(dip, mp) != 0) { + return (DRMACH_INTERNAL_ERROR()); + } + + *idp = (drmachid_t)mp; + return (NULL); +} + +static void +drmach_mem_dispose(drmachid_t id) +{ + drmach_mem_t *mp; + + ASSERT(DRMACH_IS_MEM_ID(id)); + + + mp = id; + + if (mp->dev.node) + drmach_node_dispose(mp->dev.node); + + if (mp->memlist) { + memlist_delete(mp->memlist); + mp->memlist = NULL; + } +} + +sbd_error_t * +drmach_mem_add_span(drmachid_t id, uint64_t basepa, uint64_t size) +{ + pfn_t basepfn = (pfn_t)(basepa >> PAGESHIFT); + pgcnt_t npages = (pgcnt_t)(size >> PAGESHIFT); + int rv; + + ASSERT(size != 0); + + if (!DRMACH_IS_MEM_ID(id)) + return (drerr_new(0, EOPL_INAPPROP, NULL)); + + kcage_range_lock(); + rv = kcage_range_add(basepfn, npages, 1); + kcage_range_unlock(); + if (rv == ENOMEM) { + cmn_err(CE_WARN, "%ld megabytes not available to kernel cage", + (size == 0 ? 0 : size / MBYTE)); + } else if (rv != 0) { + /* catch this in debug kernels */ + ASSERT(0); + + cmn_err(CE_WARN, "unexpected kcage_range_add" + " return value %d", rv); + } + + if (rv) { + return (DRMACH_INTERNAL_ERROR()); + } + else + return (NULL); +} + +sbd_error_t * +drmach_mem_del_span(drmachid_t id, uint64_t basepa, uint64_t size) +{ + pfn_t basepfn = (pfn_t)(basepa >> PAGESHIFT); + pgcnt_t npages = (pgcnt_t)(size >> PAGESHIFT); + int rv; + + if (!DRMACH_IS_MEM_ID(id)) + return (drerr_new(0, EOPL_INAPPROP, NULL)); + + if (size > 0) { + kcage_range_lock(); + rv = kcage_range_delete_post_mem_del(basepfn, npages); + kcage_range_unlock(); + if (rv != 0) { + cmn_err(CE_WARN, + "unexpected kcage_range_delete_post_mem_del" + " return value %d", rv); + return (DRMACH_INTERNAL_ERROR()); + } + } + + return (NULL); +} + +sbd_error_t * +drmach_mem_disable(drmachid_t id) +{ + if (!DRMACH_IS_MEM_ID(id)) + return (drerr_new(0, EOPL_INAPPROP, NULL)); + else { + drmach_flush_all(); + return (NULL); + } +} + +sbd_error_t * +drmach_mem_enable(drmachid_t id) +{ + if (!DRMACH_IS_MEM_ID(id)) + return (drerr_new(0, EOPL_INAPPROP, NULL)); + else + return (NULL); +} + +sbd_error_t * +drmach_mem_get_info(drmachid_t id, drmach_mem_info_t *mem) +{ + drmach_mem_t *mp; + + if (!DRMACH_IS_MEM_ID(id)) + return (drerr_new(0, EOPL_INAPPROP, NULL)); + + mp = (drmach_mem_t *)id; + + /* + * This is only used by dr to round up/down the memory + * for copying. Our unit of memory isolation is 64 MB. + */ + + mem->mi_alignment_mask = (64 * 1024 * 1024 - 1); + mem->mi_basepa = mp->base_pa; + mem->mi_size = mp->nbytes; + mem->mi_slice_size = mp->slice_size; + + return (NULL); +} + +sbd_error_t * +drmach_mem_get_base_physaddr(drmachid_t id, uint64_t *pa) +{ + drmach_mem_t *mp; + + if (!DRMACH_IS_MEM_ID(id)) + return (drerr_new(0, EOPL_INAPPROP, NULL)); + + mp = (drmach_mem_t *)id; + + *pa = mp->base_pa; + return (NULL); +} + +sbd_error_t * +drmach_mem_get_memlist(drmachid_t id, struct memlist **ml) +{ + drmach_mem_t *mem; + int rv; + struct memlist *mlist; + + if (!DRMACH_IS_MEM_ID(id)) + return (drerr_new(0, EOPL_INAPPROP, NULL)); + + mem = (drmach_mem_t *)id; + mlist = memlist_dup(mem->memlist); + +#ifdef DEBUG + /* + * Make sure the incoming memlist doesn't already + * intersect with what's present in the system (phys_install). + */ + memlist_read_lock(); + rv = memlist_intersect(phys_install, mlist); + memlist_read_unlock(); + if (rv) { + DRMACH_PR("Derived memlist intersects" + " with phys_install\n"); + memlist_dump(mlist); + + DRMACH_PR("phys_install memlist:\n"); + memlist_dump(phys_install); + + memlist_delete(mlist); + return (DRMACH_INTERNAL_ERROR()); + } + + DRMACH_PR("Derived memlist:"); + memlist_dump(mlist); +#endif + + *ml = mlist; + + return (NULL); +} + +sbd_error_t * +drmach_mem_get_slice_size(drmachid_t id, uint64_t *bytes) +{ + drmach_mem_t *mem; + + if (!DRMACH_IS_MEM_ID(id)) + return (drerr_new(0, EOPL_INAPPROP, NULL)); + + mem = (drmach_mem_t *)id; + + *bytes = mem->slice_size; + + return (NULL); +} + + +/* ARGSUSED */ +processorid_t +drmach_mem_cpu_affinity(drmachid_t id) +{ + return (CPU_CURRENT); +} + +static sbd_error_t * +drmach_mem_release(drmachid_t id) +{ + if (!DRMACH_IS_MEM_ID(id)) + return (drerr_new(0, EOPL_INAPPROP, NULL)); + return (NULL); +} + +static sbd_error_t * +drmach_mem_status(drmachid_t id, drmach_status_t *stat) +{ + drmach_mem_t *dp; + uint64_t pa, slice_size; + struct memlist *ml; + + ASSERT(DRMACH_IS_MEM_ID(id)); + dp = id; + + /* get starting physical address of target memory */ + pa = dp->base_pa; + + /* round down to slice boundary */ + slice_size = dp->slice_size; + pa &= ~(slice_size - 1); + + /* stop at first span that is in slice */ + memlist_read_lock(); + for (ml = phys_install; ml; ml = ml->next) + if (ml->address >= pa && ml->address < pa + slice_size) + break; + memlist_read_unlock(); + + stat->assigned = dp->dev.bp->assigned; + stat->powered = dp->dev.bp->powered; + stat->configured = (ml != NULL); + stat->busy = dp->dev.busy; + strncpy(stat->type, dp->dev.type, sizeof (stat->type)); + stat->info[0] = '\0'; + + return (NULL); +} + + +sbd_error_t * +drmach_board_deprobe(drmachid_t id) +{ + drmach_board_t *bp; + + if (!DRMACH_IS_BOARD_ID(id)) + return (drerr_new(0, EOPL_INAPPROP, NULL)); + + bp = id; + + cmn_err(CE_CONT, "DR: PROM detach board %d\n", bp->bnum); + + if (bp->tree) { + drmach_node_dispose(bp->tree); + bp->tree = NULL; + } + if (bp->devices) { + drmach_array_dispose(bp->devices, drmach_device_dispose); + bp->devices = NULL; + } + + bp->boot_board = 0; + + return (NULL); +} + +/*ARGSUSED*/ +static sbd_error_t * +drmach_pt_ikprobe(drmachid_t id, drmach_opts_t *opts) +{ + drmach_board_t *bp = (drmach_board_t *)id; + sbd_error_t *err = NULL; + int rv; + + if (!DRMACH_IS_BOARD_ID(id)) + return (drerr_new(0, EOPL_INAPPROP, NULL)); + + DRMACH_PR("calling opl_probe_board for bnum=%d\n", bp->bnum); + rv = opl_probe_sb(bp->bnum); + if (rv != 0) { + err = drerr_new(0, EOPL_PROBE, bp->cm.name); + return (err); + } + return (err); +} + +/*ARGSUSED*/ +static sbd_error_t * +drmach_pt_ikdeprobe(drmachid_t id, drmach_opts_t *opts) +{ + drmach_board_t *bp; + sbd_error_t *err = NULL; + int rv; + + if (!DRMACH_IS_BOARD_ID(id)) + return (drerr_new(0, EOPL_INAPPROP, NULL)); + bp = (drmach_board_t *)id; + + cmn_err(CE_CONT, "DR: in-kernel unprobe board %d\n", bp->bnum); + + rv = opl_unprobe_sb(bp->bnum); + if (rv != 0) { + err = drerr_new(0, EOPL_DEPROBE, bp->cm.name); + } + + return (err); +} + + +/*ARGSUSED*/ +sbd_error_t * +drmach_pt_readmem(drmachid_t id, drmach_opts_t *opts) +{ + struct memlist *ml; + uint64_t src_pa; + uint64_t dst_pa; + uint64_t dst; + + dst_pa = va_to_pa(&dst); + + memlist_read_lock(); + for (ml = phys_install; ml; ml = ml->next) { + uint64_t nbytes; + + src_pa = ml->address; + nbytes = ml->size; + + while (nbytes != 0ull) { + + /* copy 32 bytes at arc_pa to dst_pa */ + bcopy32_il(src_pa, dst_pa); + + /* increment by 32 bytes */ + src_pa += (4 * sizeof (uint64_t)); + + /* decrement by 32 bytes */ + nbytes -= (4 * sizeof (uint64_t)); + } + } + memlist_read_unlock(); + + return (NULL); +} + +static struct { + const char *name; + sbd_error_t *(*handler)(drmachid_t id, drmach_opts_t *opts); +} drmach_pt_arr[] = { + { "readmem", drmach_pt_readmem }, + { "ikprobe", drmach_pt_ikprobe }, + { "ikdeprobe", drmach_pt_ikdeprobe }, + + /* the following line must always be last */ + { NULL, NULL } +}; + +/*ARGSUSED*/ +sbd_error_t * +drmach_passthru(drmachid_t id, drmach_opts_t *opts) +{ + int i; + sbd_error_t *err; + + i = 0; + while (drmach_pt_arr[i].name != NULL) { + int len = strlen(drmach_pt_arr[i].name); + + if (strncmp(drmach_pt_arr[i].name, opts->copts, len) == 0) + break; + + i += 1; + } + + if (drmach_pt_arr[i].name == NULL) + err = drerr_new(0, EOPL_UNKPTCMD, opts->copts); + else + err = (*drmach_pt_arr[i].handler)(id, opts); + + return (err); +} + +sbd_error_t * +drmach_release(drmachid_t id) +{ + drmach_common_t *cp; + + if (!DRMACH_IS_DEVICE_ID(id)) + return (drerr_new(0, EOPL_INAPPROP, NULL)); + cp = id; + + return (cp->release(id)); +} + +sbd_error_t * +drmach_status(drmachid_t id, drmach_status_t *stat) +{ + drmach_common_t *cp; + sbd_error_t *err; + + rw_enter(&drmach_boards_rwlock, RW_READER); + + if (!DRMACH_IS_ID(id)) { + rw_exit(&drmach_boards_rwlock); + return (drerr_new(0, EOPL_NOTID, NULL)); + } + cp = (drmach_common_t *)id; + err = cp->status(id, stat); + + rw_exit(&drmach_boards_rwlock); + + return (err); +} + +static sbd_error_t * +drmach_i_status(drmachid_t id, drmach_status_t *stat) +{ + drmach_common_t *cp; + + if (!DRMACH_IS_ID(id)) + return (drerr_new(0, EOPL_NOTID, NULL)); + cp = id; + + return (cp->status(id, stat)); +} + +/*ARGSUSED*/ +sbd_error_t * +drmach_unconfigure(drmachid_t id, int flags) +{ + drmach_device_t *dp; + dev_info_t *rdip, *fdip = NULL; + char name[OBP_MAXDRVNAME]; + int rv; + + if (DRMACH_IS_CPU_ID(id)) + return (NULL); + + if (!DRMACH_IS_DEVICE_ID(id)) + return (drerr_new(0, EOPL_INAPPROP, NULL)); + + dp = id; + + rdip = dp->node->n_getdip(dp->node); + + ASSERT(rdip); + + rv = dp->node->n_getprop(dp->node, "name", name, OBP_MAXDRVNAME); + + if (rv) + return (NULL); + + /* + * Note: FORCE flag is no longer necessary under devfs + */ + + ASSERT(e_ddi_branch_held(rdip)); + if (e_ddi_branch_unconfigure(rdip, &fdip, 0)) { + sbd_error_t *err; + char *path = kmem_alloc(MAXPATHLEN, KM_SLEEP); + + /* + * If non-NULL, fdip is returned held and must be released. + */ + if (fdip != NULL) { + (void) ddi_pathname(fdip, path); + ndi_rele_devi(fdip); + } else { + (void) ddi_pathname(rdip, path); + } + + err = drerr_new(1, EOPL_DRVFAIL, path); + + kmem_free(path, MAXPATHLEN); + + return (err); + } + + return (NULL); +} + + +int +drmach_cpu_poweron(struct cpu *cp) +{ + int bnum, cpuid, onb_core_num, strand_id; + drmach_board_t *bp; + + DRMACH_PR("drmach_cpu_poweron: starting cpuid %d\n", cp->cpu_id); + + cpuid = cp->cpu_id; + bnum = LSB_ID(cpuid); + onb_core_num = ON_BOARD_CORE_NUM(cpuid); + strand_id = STRAND_ID(cpuid); + bp = drmach_get_board_by_bnum(bnum); + + ASSERT(bp); + if (bp->cores[onb_core_num].core_hotadded == 0) { + if (drmach_add_remove_cpu(bnum, onb_core_num, + HOTADD_CPU) != 0) { + cmn_err(CE_WARN, "Failed to add CMP %d on board %d\n", + onb_core_num, bnum); + return (EIO); + } + } + + ASSERT(MUTEX_HELD(&cpu_lock)); + + if (drmach_cpu_start(cp) != 0) { + if (bp->cores[onb_core_num].core_started == 0) { + /* + * we must undo the hotadd or no one will do that + * If this fails, we will do this again in + * drmach_board_disconnect. + */ + if (drmach_add_remove_cpu(bnum, onb_core_num, + HOTREMOVE_CPU) != 0) { + cmn_err(CE_WARN, "Failed to remove CMP %d " + "on board %d\n", + onb_core_num, bnum); + } + } + return (EBUSY); + } else { + bp->cores[onb_core_num].core_started |= (1 << strand_id); + return (0); + } +} + +int +drmach_cpu_poweroff(struct cpu *cp) +{ + int rv = 0; + processorid_t cpuid = cp->cpu_id; + + DRMACH_PR("drmach_cpu_poweroff: stopping cpuid %d\n", cp->cpu_id); + + ASSERT(MUTEX_HELD(&cpu_lock)); + + /* + * Capture all CPUs (except for detaching proc) to prevent + * crosscalls to the detaching proc until it has cleared its + * bit in cpu_ready_set. + * + * The CPU's remain paused and the prom_mutex is known to be free. + * This prevents the x-trap victim from blocking when doing prom + * IEEE-1275 calls at a high PIL level. + */ + + promsafe_pause_cpus(); + + /* + * Quiesce interrupts on the target CPU. We do this by setting + * the CPU 'not ready'- (i.e. removing the CPU from cpu_ready_set) to + * prevent it from receiving cross calls and cross traps. + * This prevents the processor from receiving any new soft interrupts. + */ + mp_cpu_quiesce(cp); + + rv = prom_stopcpu_bycpuid(cpuid); + if (rv == 0) + cp->cpu_flags = CPU_OFFLINE | CPU_QUIESCED | CPU_POWEROFF; + + start_cpus(); + + if (rv == 0) { + int bnum, onb_core_num, strand_id; + drmach_board_t *bp; + + CPU_SIGNATURE(OS_SIG, SIGST_DETACHED, SIGSUBST_NULL, cpuid); + + bnum = LSB_ID(cpuid); + onb_core_num = ON_BOARD_CORE_NUM(cpuid); + strand_id = STRAND_ID(cpuid); + bp = drmach_get_board_by_bnum(bnum); + ASSERT(bp); + + bp->cores[onb_core_num].core_started &= ~(1 << strand_id); + if (bp->cores[onb_core_num].core_started == 0) { + if (drmach_add_remove_cpu(bnum, onb_core_num, + HOTREMOVE_CPU) != 0) { + cmn_err(CE_WARN, + "Failed to remove CMP %d LSB %d\n", + onb_core_num, bnum); + return (EIO); + } + } + } + + return (rv); +} + +/*ARGSUSED*/ +int +drmach_verify_sr(dev_info_t *dip, int sflag) +{ + return (0); +} + +void +drmach_suspend_last(void) +{ +} + +void +drmach_resume_first(void) +{ +} + +/* + * Log a DR sysevent. + * Return value: 0 success, non-zero failure. + */ +int +drmach_log_sysevent(int board, char *hint, int flag, int verbose) +{ + sysevent_t *ev; + sysevent_id_t eid; + int rv, km_flag; + sysevent_value_t evnt_val; + sysevent_attr_list_t *evnt_attr_list = NULL; + char attach_pnt[MAXNAMELEN]; + + km_flag = (flag == SE_SLEEP) ? KM_SLEEP : KM_NOSLEEP; + attach_pnt[0] = '\0'; + if (drmach_board_name(board, attach_pnt, MAXNAMELEN)) { + rv = -1; + goto logexit; + } + if (verbose) + DRMACH_PR("drmach_log_sysevent: %s %s, flag: %d, verbose: %d\n", + attach_pnt, hint, flag, verbose); + + if ((ev = sysevent_alloc(EC_DR, ESC_DR_AP_STATE_CHANGE, + SUNW_KERN_PUB"dr", km_flag)) == NULL) { + rv = -2; + goto logexit; + } + evnt_val.value_type = SE_DATA_TYPE_STRING; + evnt_val.value.sv_string = attach_pnt; + if ((rv = sysevent_add_attr(&evnt_attr_list, DR_AP_ID, + &evnt_val, km_flag)) != 0) + goto logexit; + + evnt_val.value_type = SE_DATA_TYPE_STRING; + evnt_val.value.sv_string = hint; + if ((rv = sysevent_add_attr(&evnt_attr_list, DR_HINT, + &evnt_val, km_flag)) != 0) { + sysevent_free_attr(evnt_attr_list); + goto logexit; + } + + (void) sysevent_attach_attributes(ev, evnt_attr_list); + + /* + * Log the event but do not sleep waiting for its + * delivery. This provides insulation from syseventd. + */ + rv = log_sysevent(ev, SE_NOSLEEP, &eid); + +logexit: + if (ev) + sysevent_free(ev); + if ((rv != 0) && verbose) + cmn_err(CE_WARN, + "drmach_log_sysevent failed (rv %d) for %s %s\n", + rv, attach_pnt, hint); + + return (rv); +} + +#define OPL_DR_STATUS_PROP "dr-status" + +static int +opl_check_dr_status() +{ + pnode_t node; + int rtn, len; + char *str; + + node = prom_rootnode(); + if (node == OBP_BADNODE) { + return (1); + } + + len = prom_getproplen(node, OPL_DR_STATUS_PROP); + if (len == -1) { + /* + * dr-status doesn't exist when DR is activated and + * any warning messages aren't needed. + */ + return (1); + } + + str = (char *)kmem_zalloc(len+1, KM_SLEEP); + rtn = prom_getprop(node, OPL_DR_STATUS_PROP, str); + kmem_free(str, len + 1); + if (rtn == -1) { + return (1); + } else { + return (0); + } +} + +static sbd_error_t * +drmach_get_scf_addr(uint64_t *addr) +{ + caddr_t *scf_cmd_addr; + uint64_t pa; + scf_cmd_addr = (caddr_t *)modgetsymvalue("scf_avail_cmd_reg_vaddr", 0); + if (scf_cmd_addr != NULL) { + pa = (uint64_t)va_to_pa(*scf_cmd_addr); + *addr = pa; + return (NULL); + } + + return (DRMACH_INTERNAL_ERROR()); +} + +/* we are allocating memlist from TLB locked pages to avoid tlbmisses */ + +static struct memlist * +drmach_memlist_add_span(drmach_copy_rename_program_t *p, + struct memlist *mlist, uint64_t base, uint64_t len) +{ + struct memlist *ml, *tl, *nl; + + if (len == 0ull) + return (NULL); + + if (mlist == NULL) { + mlist = p->free_mlist; + if (mlist == NULL) + return (NULL); + p->free_mlist = mlist->next; + mlist->address = base; + mlist->size = len; + mlist->next = mlist->prev = NULL; + + return (mlist); + } + + for (tl = ml = mlist; ml; tl = ml, ml = ml->next) { + if (base < ml->address) { + if ((base + len) < ml->address) { + nl = p->free_mlist; + if (nl == NULL) + return (NULL); + p->free_mlist = nl->next; + nl->address = base; + nl->size = len; + nl->next = ml; + if ((nl->prev = ml->prev) != NULL) + nl->prev->next = nl; + ml->prev = nl; + if (mlist == ml) + mlist = nl; + } else { + ml->size = MAX((base + len), + (ml->address + ml->size)) - + base; + ml->address = base; + } + break; + + } else if (base <= (ml->address + ml->size)) { + ml->size = MAX((base + len), + (ml->address + ml->size)) - + MIN(ml->address, base); + ml->address = MIN(ml->address, base); + break; + } + } + if (ml == NULL) { + nl = p->free_mlist; + if (nl == NULL) + return (NULL); + p->free_mlist = nl->next; + nl->address = base; + nl->size = len; + nl->next = NULL; + nl->prev = tl; + tl->next = nl; + } + + return (mlist); +} + +/* + * The routine performs the necessary memory COPY and MC adr SWITCH. + * Both operations MUST be at the same "level" so that the stack is + * maintained correctly between the copy and switch. The switch + * portion implements a caching mechanism to guarantee the code text + * is cached prior to execution. This is to guard against possible + * memory access while the MC adr's are being modified. + * + * IMPORTANT: The _drmach_copy_rename_end() function must immediately + * follow drmach_copy_rename_prog__relocatable() so that the correct + * "length" of the drmach_copy_rename_prog__relocatable can be + * calculated. This routine MUST be a LEAF function, i.e. it can + * make NO function calls, primarily for two reasons: + * + * 1. We must keep the stack consistent across the "switch". + * 2. Function calls are compiled to relative offsets, and + * we execute this function we'll be executing it from + * a copied version in a different area of memory, thus + * the relative offsets will be bogus. + * + * Moreover, it must have the "__relocatable" suffix to inform DTrace + * providers (and anything else, for that matter) that this + * function's text is manually relocated elsewhere before it is + * executed. That is, it cannot be safely instrumented with any + * methodology that is PC-relative. + */ + +/* + * We multiply this to system_clock_frequency so we + * are setting a delay of fmem_timeout second for + * the rename command. The spec says 15 second is + * enough but the Fujitsu HW team suggested 17 sec. + */ +static int fmem_timeout = 17; +static int min_copy_size_per_sec = 20 * 1024 * 1024; +int drmach_disable_mcopy = 0; + +#define DR_DELAY_IL(ms, freq) \ + { \ + uint64_t start; \ + uint64_t nstick; \ + volatile uint64_t now; \ + nstick = ((uint64_t)ms * freq)/1000; \ + start = drmach_get_stick_il(); \ + now = start; \ + while ((now - start) <= nstick) { \ + drmach_sleep_il(); \ + now = drmach_get_stick_il(); \ + } \ + } + +static int +drmach_copy_rename_prog__relocatable(drmach_copy_rename_program_t *prog, + int cpuid) +{ + struct memlist *ml; + register int rtn; + int i; + register uint64_t curr, limit; + extern uint64_t drmach_get_stick_il(); + extern void membar_sync_il(); + extern void flush_instr_mem_il(void*); + uint64_t copy_start; + + prog->critical->stat[cpuid] = FMEM_LOOP_COPY_READY; + membar_sync_il(); + + if (prog->data->cpuid == cpuid) { + limit = drmach_get_stick_il(); + limit += prog->critical->delay; + + for (i = 0; i < NCPU; i++) { + if (CPU_IN_SET(prog->data->cpu_slave_set, i)) { + /* wait for all CPU's to be ready */ + for (;;) { + if (prog->critical->stat[i] == + FMEM_LOOP_COPY_READY) { + break; + } + } + curr = drmach_get_stick_il(); + if (curr > limit) { + prog->data->fmem_status.error = + FMEM_XC_TIMEOUT; + return (FMEM_XC_TIMEOUT); + } + } + } + prog->data->fmem_status.stat = FMEM_LOOP_COPY_READY; + membar_sync_il(); + copy_start = drmach_get_stick_il(); + } else { + for (;;) { + if (prog->data->fmem_status.stat == + FMEM_LOOP_COPY_READY) { + break; + } + if (prog->data->fmem_status.error) { + prog->data->error[cpuid] = FMEM_TERMINATE; + return (FMEM_TERMINATE); + } + } + } + + /* + * DO COPY. + */ + if (CPU_IN_SET(prog->data->cpu_copy_set, cpuid)) { + for (ml = prog->data->cpu_ml[cpuid]; ml; ml = ml->next) { + uint64_t s_pa, t_pa; + uint64_t nbytes; + + s_pa = prog->data->s_copybasepa + ml->address; + t_pa = prog->data->t_copybasepa + ml->address; + nbytes = ml->size; + + while (nbytes != 0ull) { + /* If the master has detected error, we just bail out */ + if (prog->data->fmem_status.error) { + prog->data->error[cpuid] = FMEM_TERMINATE; + return (FMEM_TERMINATE); + } + /* + * This copy does NOT use an ASI + * that avoids the Ecache, therefore + * the dst_pa addresses may remain + * in our Ecache after the dst_pa + * has been removed from the system. + * A subsequent write-back to memory + * will cause an ARB-stop because the + * physical address no longer exists + * in the system. Therefore we must + * flush out local Ecache after we + * finish the copy. + */ + + /* copy 32 bytes at src_pa to dst_pa */ + bcopy32_il(s_pa, t_pa); + + /* increment the counter to signal that we are alive */ + prog->stat->nbytes[cpuid] += 32; + + /* increment by 32 bytes */ + s_pa += (4 * sizeof (uint64_t)); + t_pa += (4 * sizeof (uint64_t)); + + /* decrement by 32 bytes */ + nbytes -= (4 * sizeof (uint64_t)); + } + } + prog->critical->stat[cpuid] = FMEM_LOOP_COPY_DONE; + membar_sync_il(); + } + + /* + * Since bcopy32_il() does NOT use an ASI to bypass + * the Ecache, we need to flush our Ecache after + * the copy is complete. + */ + flush_cache_il(); + + /* + * drmach_fmem_exec_script() + */ + if (prog->data->cpuid == cpuid) { + uint64_t last, now; + + limit = copy_start + prog->data->copy_delay; + for (i = 0; i < NCPU; i++) { + if (CPU_IN_SET(prog->data->cpu_slave_set, i)) { + for (;;) { + /* we get FMEM_LOOP_FMEM_READY in normal case */ + if (prog->critical->stat[i] == + FMEM_LOOP_FMEM_READY) { + break; + } + /* got error traps */ + if (prog->critical->stat[i] == + FMEM_COPY_ERROR) { + prog->data->fmem_status.error = + FMEM_COPY_ERROR; + return (FMEM_COPY_ERROR); + } + /* if we have not reached limit, wait more */ + curr = drmach_get_stick_il(); + if (curr <= limit) + continue; + + prog->data->slowest_cpuid = i; + prog->data->copy_wait_time = + curr - copy_start; + + /* now check if slave is alive */ + last = prog->stat->nbytes[i]; + + DR_DELAY_IL(1, prog->data->stick_freq); + + now = prog->stat->nbytes[i]; + if (now <= last) { + /* no progress, perhaps just finished */ + DR_DELAY_IL(1, prog->data->stick_freq); + if (prog->critical->stat[i] == + FMEM_LOOP_FMEM_READY) + break; + /* copy error */ + if (prog->critical->stat[i] == + FMEM_COPY_ERROR) { + prog->data->fmem_status.error = + FMEM_COPY_ERROR; + return (FMEM_COPY_ERROR); + } + prog->data->fmem_status.error = + FMEM_COPY_TIMEOUT; + return (FMEM_COPY_TIMEOUT); + } + } + } + } + prog->critical->stat[cpuid] = FMEM_LOOP_FMEM_READY; + prog->data->fmem_status.stat = FMEM_LOOP_FMEM_READY; + + membar_sync_il(); + flush_instr_mem_il((void*) (prog->critical)); + /* + * drmach_fmem_exec_script() + */ + rtn = prog->critical->fmem((void *)prog->critical, PAGESIZE); + return (rtn); + } else { + flush_instr_mem_il((void*) (prog->critical)); + /* + * drmach_fmem_loop_script() + */ + rtn = prog->critical->loop((void *)(prog->critical), + PAGESIZE, (void *)&(prog->critical->stat[cpuid])); + + prog->data->error[cpuid] = rtn; + /* slave thread does not care the rv */ + return (0); + } +} + +static void +drmach_copy_rename_end(void) +{ + /* + * IMPORTANT: This function's location MUST be located immediately + * following drmach_copy_rename_prog__relocatable to + * accurately estimate its size. Note that this assumes + * the compiler keeps these functions in the order in + * which they appear :-o + */ +} + + +static void +drmach_setup_memlist(drmach_copy_rename_program_t *p) +{ + struct memlist *ml; + caddr_t buf; + int nbytes, s; + + nbytes = PAGESIZE; + s = roundup(sizeof (struct memlist), sizeof (void *)); + p->free_mlist = NULL; + buf = p->memlist_buffer; + while (nbytes >= sizeof (struct memlist)) { + ml = (struct memlist *)buf; + ml->next = p->free_mlist; + p->free_mlist = ml; + buf += s; + nbytes -= s; + } +} + +sbd_error_t * +drmach_copy_rename_init(drmachid_t t_id, drmachid_t s_id, + struct memlist *c_ml, drmachid_t *pgm_id) +{ + drmach_mem_t *s_mem; + drmach_mem_t *t_mem; + struct memlist *x_ml; + uint64_t s_copybasepa, t_copybasepa; + uint_t len; + caddr_t bp, wp; + int s_bd, t_bd, cpuid, active_cpus, i; + uint64_t c_addr; + size_t c_size, copy_sz, sz; + static sbd_error_t *drmach_get_scf_addr(uint64_t *); + extern void drmach_fmem_loop_script(); + extern void drmach_fmem_loop_script_rtn(); + extern int drmach_fmem_exec_script(); + extern void drmach_fmem_exec_script_end(); + sbd_error_t *err; + drmach_copy_rename_program_t *prog; + void (*mc_suspend)(void); + void (*mc_resume)(void); + int (*scf_fmem_start)(int, int); + int (*scf_fmem_end)(void); + int (*scf_fmem_cancel)(void); + + if (!DRMACH_IS_MEM_ID(s_id)) + return (drerr_new(0, EOPL_INAPPROP, NULL)); + if (!DRMACH_IS_MEM_ID(t_id)) + return (drerr_new(0, EOPL_INAPPROP, NULL)); + + for (i = 0; i < NCPU; i++) { + int lsb_id, onb_core_num, strand_id; + drmach_board_t *bp; + + /* + * this kind of CPU will spin in cache + */ + if (CPU_IN_SET(cpu_ready_set, i)) + continue; + + /* + * Now check for any inactive CPU's that + * have been hotadded. This can only occur in + * error condition in drmach_cpu_poweron(). + */ + lsb_id = LSB_ID(i); + onb_core_num = ON_BOARD_CORE_NUM(i); + strand_id = STRAND_ID(i); + bp = drmach_get_board_by_bnum(lsb_id); + if (bp == NULL) + continue; + if (bp->cores[onb_core_num].core_hotadded & + (1 << strand_id)) { + if (!(bp->cores[onb_core_num].core_started & + (1 << strand_id))) { + return (DRMACH_INTERNAL_ERROR()); + } + } + } + + mc_suspend = (void (*)(void)) + modgetsymvalue("opl_mc_suspend", 0); + mc_resume = (void (*)(void)) + modgetsymvalue("opl_mc_resume", 0); + + if (mc_suspend == NULL || mc_resume == NULL) { + return (DRMACH_INTERNAL_ERROR()); + } + + scf_fmem_start = (int (*)(int, int)) + modgetsymvalue("scf_fmem_start", 0); + if (scf_fmem_start == NULL) { + return (DRMACH_INTERNAL_ERROR()); + } + scf_fmem_end = (int (*)(void)) + modgetsymvalue("scf_fmem_end", 0); + if (scf_fmem_end == NULL) { + return (DRMACH_INTERNAL_ERROR()); + } + scf_fmem_cancel = (int (*)(void)) + modgetsymvalue("scf_fmem_cancel", 0); + if (scf_fmem_cancel == NULL) { + return (DRMACH_INTERNAL_ERROR()); + } + s_mem = s_id; + t_mem = t_id; + + s_bd = s_mem->dev.bp->bnum; + t_bd = t_mem->dev.bp->bnum; + + /* calculate source and target base pa */ + + s_copybasepa = s_mem->slice_base; + t_copybasepa = t_mem->slice_base; + + /* adjust copy memlist addresses to be relative to copy base pa */ + x_ml = c_ml; + while (x_ml != NULL) { + x_ml->address -= s_copybasepa; + x_ml = x_ml->next; + } + + /* + * bp will be page aligned, since we're calling + * kmem_zalloc() with an exact multiple of PAGESIZE. + */ + wp = bp = kmem_zalloc(DRMACH_FMEM_LOCKED_PAGES * PAGESIZE, + KM_SLEEP); + + prog = (drmach_copy_rename_program_t *)(wp + + DRMACH_FMEM_DATA_PAGE * PAGESIZE); + prog->data = (drmach_copy_rename_data_t *)roundup(((uint64_t)prog + + sizeof (drmach_copy_rename_program_t)), sizeof (void *)); + + ASSERT(((uint64_t)prog->data + sizeof (drmach_copy_rename_data_t)) + <= ((uint64_t)prog + PAGESIZE)); + + prog->critical = (drmach_copy_rename_critical_t *) + (wp + DRMACH_FMEM_CRITICAL_PAGE * PAGESIZE); + + prog->memlist_buffer = (caddr_t)(wp + + DRMACH_FMEM_MLIST_PAGE * PAGESIZE); + + prog->stat = (drmach_cr_stat_t *)(wp + + DRMACH_FMEM_STAT_PAGE * PAGESIZE); + + /* LINTED */ + ASSERT(sizeof (drmach_cr_stat_t) + <= ((DRMACH_FMEM_LOCKED_PAGES - DRMACH_FMEM_STAT_PAGE) + * PAGESIZE)); + + prog->critical->scf_reg_base = (uint64_t)-1; + err = drmach_get_scf_addr(&(prog->critical->scf_reg_base)); + if (err) { + kmem_free(wp, DRMACH_FMEM_LOCKED_PAGES * PAGESIZE); + return (err); + } + + prog->critical->scf_td[0] = (s_bd & 0xff); + prog->critical->scf_td[1] = (t_bd & 0xff); + for (i = 2; i < 15; i++) { + prog->critical->scf_td[i] = 0; + } + prog->critical->scf_td[15] = ((0xaa + s_bd + t_bd) & 0xff); + + bp = (caddr_t)prog->critical; + len = sizeof (drmach_copy_rename_critical_t); + wp = (caddr_t)roundup((uint64_t)bp + len, sizeof (void *)); + + len = (uint_t)((ulong_t)drmach_copy_rename_end - + (ulong_t)drmach_copy_rename_prog__relocatable); + + /* + * We always leave 1K nop's to prevent the processor from + * speculative execution that causes memory access + */ + wp = wp + len + 1024; + + len = (uint_t)((ulong_t)drmach_fmem_exec_script_end - + (ulong_t)drmach_fmem_exec_script); + /* this is the entry point of the loop script */ + wp = wp + len + 1024; + + len = (uint_t)((ulong_t)drmach_fmem_exec_script - + (ulong_t)drmach_fmem_loop_script); + wp = wp + len + 1024; + + /* now we make sure there is 1K extra */ + + if ((wp - bp) > PAGESIZE) { + kmem_free(prog, DRMACH_FMEM_LOCKED_PAGES * PAGESIZE); + return (DRMACH_INTERNAL_ERROR()); + } + + bp = (caddr_t)prog->critical; + len = sizeof (drmach_copy_rename_critical_t); + wp = (caddr_t)roundup((uint64_t)bp + len, sizeof (void *)); + + prog->critical->run = (int (*)())(wp); + len = (uint_t)((ulong_t)drmach_copy_rename_end - + (ulong_t)drmach_copy_rename_prog__relocatable); + + bcopy((caddr_t)drmach_copy_rename_prog__relocatable, wp, len); + + wp = (caddr_t)roundup((uint64_t)wp + len, 1024); + + prog->critical->fmem = (int (*)())(wp); + len = (int)((ulong_t)drmach_fmem_exec_script_end - + (ulong_t)drmach_fmem_exec_script); + bcopy((caddr_t)drmach_fmem_exec_script, wp, len); + + len = (int)((ulong_t)drmach_fmem_exec_script_end - + (ulong_t)drmach_fmem_exec_script); + wp = (caddr_t)roundup((uint64_t)wp + len, 1024); + + prog->critical->loop = (int (*)())(wp); + len = (int)((ulong_t)drmach_fmem_exec_script - + (ulong_t)drmach_fmem_loop_script); + bcopy((caddr_t)drmach_fmem_loop_script, (void *)wp, len); + len = (int)((ulong_t)drmach_fmem_loop_script_rtn- + (ulong_t)drmach_fmem_loop_script); + prog->critical->loop_rtn = (void (*)()) (wp+len); + + /* now we are committed, call SCF, soft suspend mac patrol */ + if ((*scf_fmem_start)(s_bd, t_bd)) { + kmem_free(prog, DRMACH_FMEM_LOCKED_PAGES * PAGESIZE); + return (DRMACH_INTERNAL_ERROR()); + } + prog->data->scf_fmem_end = scf_fmem_end; + prog->data->scf_fmem_cancel = scf_fmem_cancel; + prog->data->fmem_status.op |= OPL_FMEM_SCF_START; + /* soft suspend mac patrol */ + (*mc_suspend)(); + prog->data->fmem_status.op |= OPL_FMEM_MC_SUSPEND; + prog->data->mc_resume = mc_resume; + + prog->critical->inst_loop_ret = + *(uint64_t *)(prog->critical->loop_rtn); + + /* + * 0x30800000 is op code "ba,a +0" + */ + + *(uint_t *)(prog->critical->loop_rtn) = (uint_t)(0x30800000); + + /* + * set the value of SCF FMEM TIMEOUT + */ + prog->critical->delay = fmem_timeout * system_clock_freq; + + prog->data->s_mem = (drmachid_t)s_mem; + prog->data->t_mem = (drmachid_t)t_mem; + + cpuid = CPU->cpu_id; + prog->data->cpuid = cpuid; + prog->data->cpu_ready_set = cpu_ready_set; + prog->data->cpu_slave_set = cpu_ready_set; + prog->data->slowest_cpuid = (processorid_t)-1; + prog->data->copy_wait_time = 0; + CPUSET_DEL(prog->data->cpu_slave_set, cpuid); + + for (i = 0; i < NCPU; i++) { + prog->data->cpu_ml[i] = NULL; + } + + active_cpus = 0; + if (drmach_disable_mcopy) { + active_cpus = 1; + CPUSET_ADD(prog->data->cpu_copy_set, cpuid); + } else { + for (i = 0; i < NCPU; i++) { + if (CPU_IN_SET(cpu_ready_set, i) && + CPU_ACTIVE(cpu[i])) { + CPUSET_ADD(prog->data->cpu_copy_set, i); + active_cpus++; + } + } + } + + drmach_setup_memlist(prog); + + x_ml = c_ml; + sz = 0; + while (x_ml != NULL) { + sz += x_ml->size; + x_ml = x_ml->next; + } + + copy_sz = sz/active_cpus; + copy_sz = roundup(copy_sz, MMU_PAGESIZE4M); + + while (sz > copy_sz*active_cpus) { + copy_sz += MMU_PAGESIZE4M; + } + + prog->data->stick_freq = system_clock_freq; + prog->data->copy_delay = ((copy_sz / min_copy_size_per_sec) + 2) * + system_clock_freq; + + x_ml = c_ml; + c_addr = x_ml->address; + c_size = x_ml->size; + + for (i = 0; i < NCPU; i++) { + prog->stat->nbytes[i] = 0; + if (!CPU_IN_SET(prog->data->cpu_copy_set, i)) { + continue; + } + sz = copy_sz; + + while (sz) { + if (c_size > sz) { + prog->data->cpu_ml[i] = + drmach_memlist_add_span(prog, + prog->data->cpu_ml[i], + c_addr, sz); + c_addr += sz; + c_size -= sz; + break; + } else { + sz -= c_size; + prog->data->cpu_ml[i] = drmach_memlist_add_span( + prog, prog->data->cpu_ml[i], + c_addr, c_size); + x_ml = x_ml->next; + if (x_ml != NULL) { + c_addr = x_ml->address; + c_size = x_ml->size; + } else { + goto end; + } + } + } + } +end: + prog->data->s_copybasepa = s_copybasepa; + prog->data->t_copybasepa = t_copybasepa; + prog->data->c_ml = c_ml; + *pgm_id = prog; + + return (NULL); +} + +sbd_error_t * +drmach_copy_rename_fini(drmachid_t id) +{ + drmach_copy_rename_program_t *prog = id; + sbd_error_t *err = NULL; + int rv; + + /* + * Note that we have to delay calling SCF to find out the + * status of the FMEM operation here because SCF cannot + * respond while it is suspended. + * This create a small window when we are sure about the + * base address of the system board. + * If there is any call to mc-opl to get memory unum, + * mc-opl will return UNKNOWN as the unum. + */ + + if (prog->data->c_ml != NULL) + memlist_delete(prog->data->c_ml); + + if ((prog->data->fmem_status.op & + (OPL_FMEM_SCF_START| OPL_FMEM_MC_SUSPEND)) != + (OPL_FMEM_SCF_START | OPL_FMEM_MC_SUSPEND)) { + cmn_err(CE_PANIC, "drmach_copy_rename_fini: " + "invalid op code %x\n", + prog->data->fmem_status.op); + } + + /* possible ops are SCF_START, MC_SUSPEND */ + if (prog->critical->fmem_issued) { + if (prog->data->fmem_status.error != FMEM_NO_ERROR) + cmn_err(CE_PANIC, "scf fmem request failed"); + rv = (*prog->data->scf_fmem_end)(); + if (rv) { + cmn_err(CE_PANIC, "scf_fmem_end() failed"); + } + /* + * If we get here, rename is successful. + * Do all the copy rename post processing. + */ + drmach_swap_pa((drmach_mem_t *)prog->data->s_mem, + (drmach_mem_t *)prog->data->t_mem); + } else { + if (prog->data->fmem_status.error != 0) { + cmn_err(CE_WARN, "Kernel Migration fails. 0x%x", + prog->data->fmem_status.error); + err = DRMACH_INTERNAL_ERROR(); + } + rv = (*prog->data->scf_fmem_cancel)(); + if (rv) { + cmn_err(CE_WARN, "scf_fmem_cancel() failed"); + if (!err) + err = DRMACH_INTERNAL_ERROR(); + } + } + /* soft resume mac patrol */ + (*prog->data->mc_resume)(); + + kmem_free(prog, DRMACH_FMEM_LOCKED_PAGES * PAGESIZE); + return (err); +} + +static void +drmach_lock_critical(caddr_t va) +{ + tte_t tte; + int i; + + for (i = 0; i < DRMACH_FMEM_LOCKED_PAGES; i++) { + vtag_flushpage(va, KCONTEXT); + sfmmu_memtte(&tte, va_to_pfn(va), + PROC_DATA|HAT_NOSYNC, TTE8K); + tte.tte_intlo |= TTE_LCK_INT; + sfmmu_dtlb_ld(va, KCONTEXT, &tte); + sfmmu_itlb_ld(va, KCONTEXT, &tte); + va += PAGESIZE; + } +} + +static void +drmach_unlock_critical(caddr_t va) +{ + int i; + + for (i = 0; i < DRMACH_FMEM_LOCKED_PAGES; i++) { + vtag_flushpage(va, KCONTEXT); + va += PAGESIZE; + } +} + +/*ARGSUSED*/ +static void +drmach_copy_rename_slave(struct regs *rp, drmachid_t id) +{ + drmach_copy_rename_program_t *prog = id; + register int cpuid; + extern void drmach_flush(); + extern void membar_sync_il(); + extern void drmach_flush_icache(); + on_trap_data_t otd; + + kpreempt_disable(); + cpuid = CPU->cpu_id; + + if (on_trap(&otd, OT_DATA_EC)) { + no_trap(); + drmach_unlock_critical((caddr_t)prog); + kpreempt_enable(); + prog->data->error[cpuid] = FMEM_COPY_ERROR; + prog->critical->stat[cpuid] = FMEM_LOOP_EXIT; + return; + } + + + (void) drmach_lock_critical((caddr_t)prog); + + flush_windows(); + + /* + * jmp drmach_copy_rename_prog(). + */ + + drmach_flush(prog->critical, PAGESIZE); + (void) prog->critical->run(prog, cpuid); + drmach_flush_icache(); + + no_trap(); + drmach_unlock_critical((caddr_t)prog); + + kpreempt_enable(); + + prog->critical->stat[cpuid] = FMEM_LOOP_EXIT; + membar_sync_il(); +} + +static void +drmach_swap_pa(drmach_mem_t *s_mem, drmach_mem_t *t_mem) +{ + uint64_t s_base, t_base; + drmach_board_t *s_board, *t_board; + struct memlist *ml; + + s_board = s_mem->dev.bp; + t_board = t_mem->dev.bp; + if (s_board == NULL || t_board == NULL) { + cmn_err(CE_PANIC, "Cannot locate source or target board\n"); + return; + } + s_base = s_mem->slice_base; + t_base = t_mem->slice_base; + + s_mem->slice_base = t_base; + s_mem->base_pa = (s_mem->base_pa - s_base) + t_base; + + for (ml = s_mem->memlist; ml; ml = ml->next) { + ml->address = ml->address - s_base + t_base; + } + + t_mem->slice_base = s_base; + t_mem->base_pa = (t_mem->base_pa - t_base) + s_base; + + for (ml = t_mem->memlist; ml; ml = ml->next) { + ml->address = ml->address - t_base + s_base; + } + + /* + * IKP has to update the sb-mem-ranges for mac patrol driver + * when it resumes, it will re-read the sb-mem-range property + * to get the new base address + */ + if (oplcfg_pa_swap(s_board->bnum, t_board->bnum) != 0) + cmn_err(CE_PANIC, "Could not update device nodes\n"); +} + +void +drmach_copy_rename(drmachid_t id) +{ + drmach_copy_rename_program_t *prog = id; + cpuset_t cpuset; + int cpuid; + uint64_t inst; + register int rtn; + extern int in_sync; + int old_in_sync; + extern void drmach_sys_trap(); + extern void drmach_flush(); + extern void drmach_flush_icache(); + extern uint64_t patch_inst(uint64_t *, uint64_t); + on_trap_data_t otd; + + if (prog->critical->scf_reg_base == (uint64_t)-1) { + prog->data->fmem_status.error = FMEM_SCF_ERR; + return; + } + + kpreempt_disable(); + cpuset = prog->data->cpu_ready_set; + + for (cpuid = 0; cpuid < NCPU; cpuid++) { + if (CPU_IN_SET(cpuset, cpuid)) { + prog->critical->stat[cpuid] = FMEM_LOOP_START; + prog->data->error[cpuid] = FMEM_NO_ERROR; + } + } + + old_in_sync = in_sync; + in_sync = 1; + cpuid = CPU->cpu_id; + + CPUSET_DEL(cpuset, cpuid); + + xc_some(cpuset, (xcfunc_t *)drmach_lock_critical, + (uint64_t)prog, (uint64_t)0); + + xt_some(cpuset, (xcfunc_t *)drmach_sys_trap, + (uint64_t)drmach_copy_rename_slave, (uint64_t)prog); + xt_sync(cpuset); + + (void) drmach_lock_critical((caddr_t)prog); + + if (on_trap(&otd, OT_DATA_EC)) { + rtn = FMEM_COPY_ERROR; + goto done; + } + + flush_windows(); + + /* + * jmp drmach_copy_rename_prog(). + */ + drmach_flush(prog->critical, PAGESIZE); + rtn = prog->critical->run(prog, cpuid); + drmach_flush_icache(); + + +done: + no_trap(); + if (rtn == FMEM_HW_ERROR) { + kpreempt_enable(); + prom_panic("URGENT_ERROR_TRAP is " + "detected during FMEM.\n"); + } + + /* + * In normal case, all slave CPU's are still spinning in + * the assembly code. The master has to patch the instruction + * to get them out. + * In error case, e.g. COPY_ERROR, some slave CPU's might + * have aborted and already returned and sset LOOP_EXIT status. + * Some CPU might still be copying. + * In any case, some delay is necessary to give them + * enough time to set the LOOP_EXIT status. + */ + + for (;;) { + inst = patch_inst((uint64_t *)prog->critical->loop_rtn, + prog->critical->inst_loop_ret); + if (prog->critical->inst_loop_ret == inst) { + break; + } + } + + for (cpuid = 0; cpuid < NCPU; cpuid++) { + uint64_t last, now; + if (!CPU_IN_SET(cpuset, cpuid)) { + continue; + } + last = prog->stat->nbytes[cpuid]; + /* + * Wait for all CPU to exit. + * However we do not want an infinite loop + * so we detect hangup situation here. + * If the slave CPU is still copying data, + * we will continue to wait. + * In error cases, the master has already set + * fmem_status.error to abort the copying. + * 1 m.s delay for them to abort copying and + * return to drmach_copy_rename_slave to set + * FMEM_LOOP_EXIT status should be enough. + */ + for (;;) { + if (prog->critical->stat[cpuid] == FMEM_LOOP_EXIT) + break; + drmach_sleep_il(); + drv_usecwait(1000); + now = prog->stat->nbytes[cpuid]; + if (now <= last) { + drv_usecwait(1000); + if (prog->critical->stat[cpuid] == FMEM_LOOP_EXIT) + break; + cmn_err(CE_PANIC, + "CPU %d hang during Copy Rename", cpuid); + } + last = now; + } + if (prog->data->error[cpuid] == FMEM_HW_ERROR) { + prom_panic("URGENT_ERROR_TRAP is " + "detected during FMEM.\n"); + } + } + drmach_unlock_critical((caddr_t)prog); + + in_sync = old_in_sync; + + kpreempt_enable(); + if (prog->data->fmem_status.error == 0) + prog->data->fmem_status.error = rtn; + + if (prog->data->copy_wait_time > 0) { + DRMACH_PR("Unexpected long wait time %ld seconds " + "during copy rename on CPU %d\n", + prog->data->copy_wait_time/prog->data->stick_freq, + prog->data->slowest_cpuid); + } +} diff --git a/usr/src/uts/sun4u/opl/io/mc-opl.c b/usr/src/uts/sun4u/opl/io/mc-opl.c new file mode 100644 index 0000000000..fc19d282a4 --- /dev/null +++ b/usr/src/uts/sun4u/opl/io/mc-opl.c @@ -0,0 +1,2442 @@ +/* + * 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 + */ +/* + * All Rights Reserved, Copyright (c) FUJITSU LIMITED 2006 + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <sys/sysmacros.h> +#include <sys/conf.h> +#include <sys/modctl.h> +#include <sys/stat.h> +#include <sys/async.h> +#include <sys/machsystm.h> +#include <sys/ksynch.h> +#include <sys/ddi.h> +#include <sys/sunddi.h> +#include <sys/ddifm.h> +#include <sys/fm/protocol.h> +#include <sys/fm/util.h> +#include <sys/kmem.h> +#include <sys/fm/io/opl_mc_fm.h> +#include <sys/memlist.h> +#include <sys/param.h> +#include <sys/ontrap.h> +#include <vm/page.h> +#include <sys/mc-opl.h> + +/* + * Function prototypes + */ +static int mc_open(dev_t *, int, int, cred_t *); +static int mc_close(dev_t, int, int, cred_t *); +static int mc_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); +static int mc_attach(dev_info_t *, ddi_attach_cmd_t); +static int mc_detach(dev_info_t *, ddi_detach_cmd_t); + +static int mc_board_add(mc_opl_t *mcp); +static int mc_board_del(mc_opl_t *mcp); +static int mc_suspend(mc_opl_t *mcp, uint32_t flag); +static int mc_resume(mc_opl_t *mcp, uint32_t flag); + +static void insert_mcp(mc_opl_t *mcp); +static void delete_mcp(mc_opl_t *mcp); + +static int pa_to_maddr(mc_opl_t *mcp, uint64_t pa, mc_addr_t *maddr); + +static int mc_valid_pa(mc_opl_t *mcp, uint64_t pa); + +int mc_get_mem_unum(int, uint64_t, char *, int, int *); +extern int plat_max_boards(void); + +static void mc_get_mlist(mc_opl_t *); + +#pragma weak opl_get_physical_board +extern int opl_get_physical_board(int); +static int mc_opl_get_physical_board(int); + +/* + * Configuration data structures + */ +static struct cb_ops mc_cb_ops = { + mc_open, /* open */ + mc_close, /* close */ + nulldev, /* strategy */ + nulldev, /* print */ + nodev, /* dump */ + nulldev, /* read */ + nulldev, /* write */ + mc_ioctl, /* ioctl */ + nodev, /* devmap */ + nodev, /* mmap */ + nodev, /* segmap */ + nochpoll, /* poll */ + ddi_prop_op, /* cb_prop_op */ + 0, /* streamtab */ + D_MP | D_NEW | D_HOTPLUG, /* Driver compatibility flag */ + CB_REV, /* rev */ + nodev, /* cb_aread */ + nodev /* cb_awrite */ +}; + +static struct dev_ops mc_ops = { + DEVO_REV, /* rev */ + 0, /* refcnt */ + ddi_getinfo_1to1, /* getinfo */ + nulldev, /* identify */ + nulldev, /* probe */ + mc_attach, /* attach */ + mc_detach, /* detach */ + nulldev, /* reset */ + &mc_cb_ops, /* cb_ops */ + (struct bus_ops *)0, /* bus_ops */ + nulldev /* power */ +}; + +/* + * Driver globals + */ +int mc_patrol_interval_sec = 10; + +int inject_op_delay = 5; + +mc_inst_list_t *mc_instances; +static kmutex_t mcmutex; + +void *mc_statep; + +#ifdef DEBUG +int oplmc_debug = 1; +#endif + +static int mc_debug_show_all; + +extern struct mod_ops mod_driverops; + +static struct modldrv modldrv = { + &mod_driverops, /* module type, this one is a driver */ + "OPL Memory-controller 1.1", /* module name */ + &mc_ops, /* driver ops */ +}; + +static struct modlinkage modlinkage = { + MODREV_1, /* rev */ + (void *)&modldrv, + NULL +}; + +#pragma weak opl_get_mem_unum +extern int (*opl_get_mem_unum)(int, uint64_t, char *, int, int *); + +/* + * pseudo-mc node portid format + * + * [10] = 0 + * [9] = 1 + * [8] = LSB_ID[4] = 0 + * [7:4] = LSB_ID[3:0] + * [3:0] = 0 + * + */ + +/* + * These are the module initialization routines. + */ +int +_init(void) +{ + int error; + + + if ((error = ddi_soft_state_init(&mc_statep, + sizeof (mc_opl_t), 1)) != 0) + return (error); + + mutex_init(&mcmutex, NULL, MUTEX_DRIVER, NULL); + if (&opl_get_mem_unum) + opl_get_mem_unum = mc_get_mem_unum; + + error = mod_install(&modlinkage); + if (error != 0) { + if (&opl_get_mem_unum) + opl_get_mem_unum = NULL; + mutex_destroy(&mcmutex); + ddi_soft_state_fini(&mc_statep); + } + + return (error); +} + +int +_fini(void) +{ + int error; + + if ((error = mod_remove(&modlinkage)) != 0) + return (error); + + mutex_destroy(&mcmutex); + + if (&opl_get_mem_unum) + opl_get_mem_unum = NULL; + + ddi_soft_state_fini(&mc_statep); + + return (0); +} + +int +_info(struct modinfo *modinfop) +{ + return (mod_info(&modlinkage, modinfop)); +} + +static int +mc_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) +{ + mc_opl_t *mcp; + int instance; + + /* get the instance of this devi */ + instance = ddi_get_instance(devi); + + switch (cmd) { + case DDI_ATTACH: + break; + case DDI_RESUME: + mcp = ddi_get_soft_state(mc_statep, instance); + return (mc_resume(mcp, MC_DRIVER_SUSPENDED)); + default: + return (DDI_FAILURE); + } + + + if (ddi_soft_state_zalloc(mc_statep, instance) != DDI_SUCCESS) + return (DDI_FAILURE); + + if ((mcp = ddi_get_soft_state(mc_statep, instance)) == NULL) { + goto bad; + } + + /* set informations in mc state */ + mcp->mc_dip = devi; + + if (mc_board_add(mcp)) + goto bad; + + insert_mcp(mcp); + ddi_report_dev(devi); + + return (DDI_SUCCESS); + +bad: + ddi_soft_state_free(mc_statep, instance); + return (DDI_FAILURE); +} + +/* ARGSUSED */ +static int +mc_detach(dev_info_t *devi, ddi_detach_cmd_t cmd) +{ + int instance; + mc_opl_t *mcp; + + /* get the instance of this devi */ + instance = ddi_get_instance(devi); + if ((mcp = ddi_get_soft_state(mc_statep, instance)) == NULL) { + return (DDI_FAILURE); + } + + switch (cmd) { + case DDI_SUSPEND: + return (mc_suspend(mcp, MC_DRIVER_SUSPENDED)); + case DDI_DETACH: + break; + default: + return (DDI_FAILURE); + } + + mutex_enter(&mcmutex); + if (mc_board_del(mcp) != DDI_SUCCESS) { + mutex_exit(&mcmutex); + return (DDI_FAILURE); + } + + delete_mcp(mcp); + mutex_exit(&mcmutex); + + /* free up the soft state */ + ddi_soft_state_free(mc_statep, instance); + + return (DDI_SUCCESS); +} + +/* ARGSUSED */ +static int +mc_open(dev_t *devp, int flag, int otyp, cred_t *credp) +{ + return (0); +} + +/* ARGSUSED */ +static int +mc_close(dev_t devp, int flag, int otyp, cred_t *credp) +{ + return (0); +} + +/* ARGSUSED */ +static int +mc_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, + int *rvalp) +{ + return (ENXIO); +} + +/* + * PA validity check: + * This function return 1 if the PA is valid, otherwise + * return 0. + */ + +/* ARGSUSED */ +static int +pa_is_valid(mc_opl_t *mcp, uint64_t addr) +{ + /* + * Check if the addr is on the board. + */ + if ((addr < mcp->mc_start_address) || + (mcp->mc_start_address + mcp->mc_size <= addr)) + return (0); + + if (mcp->mlist == NULL) + mc_get_mlist(mcp); + + if (mcp->mlist && address_in_memlist(mcp->mlist, addr, 0)) { + return (1); + } + return (0); +} + +/* + * mac-pa translation routines. + * + * Input: mc driver state, (LSB#, Bank#, DIMM address) + * Output: physical address + * + * Valid - return value: 0 + * Invalid - return value: -1 + */ +static int +mcaddr_to_pa(mc_opl_t *mcp, mc_addr_t *maddr, uint64_t *pa) +{ + int i; + uint64_t pa_offset = 0; + int cs = (maddr->ma_dimm_addr >> CS_SHIFT) & 1; + int bank = maddr->ma_bank; + mc_addr_t maddr1; + int bank0, bank1; + + MC_LOG("mcaddr /LSB%d/B%d/%x\n", maddr->ma_bd, bank, + maddr->ma_dimm_addr); + + /* loc validity check */ + ASSERT(maddr->ma_bd >= 0 && OPL_BOARD_MAX > maddr->ma_bd); + ASSERT(bank >= 0 && OPL_BANK_MAX > bank); + + /* Do translation */ + for (i = 0; i < PA_BITS_FOR_MAC; i++) { + int pa_bit = 0; + int mc_bit = mcp->mc_trans_table[cs][i]; + if (mc_bit < MC_ADDRESS_BITS) { + pa_bit = (maddr->ma_dimm_addr >> mc_bit) & 1; + } else if (mc_bit == MP_NONE) { + pa_bit = 0; + } else if (mc_bit == MP_BANK_0) { + pa_bit = bank & 1; + } else if (mc_bit == MP_BANK_1) { + pa_bit = (bank >> 1) & 1; + } else if (mc_bit == MP_BANK_2) { + pa_bit = (bank >> 2) & 1; + } + pa_offset |= ((uint64_t)pa_bit) << i; + } + *pa = mcp->mc_start_address + pa_offset; + MC_LOG("pa = %lx\n", *pa); + + if (pa_to_maddr(mcp, *pa, &maddr1) == -1) { + return (-1); + } + + + if (IS_MIRROR(mcp, maddr->ma_bank)) { + bank0 = maddr->ma_bank & ~(1); + bank1 = maddr1.ma_bank & ~(1); + } else { + bank0 = maddr->ma_bank; + bank1 = maddr1.ma_bank; + } + /* + * there is no need to check ma_bd because it is generated from + * mcp. They are the same. + */ + if ((bank0 == bank1) && + (maddr->ma_dimm_addr == maddr1.ma_dimm_addr)) { + return (0); + } else { + cmn_err(CE_WARN, "Translation error source /LSB%d/B%d/%x, " + "PA %lx, target /LSB%d/B%d/%x\n", + maddr->ma_bd, bank, maddr->ma_dimm_addr, + *pa, maddr1.ma_bd, maddr1.ma_bank, + maddr1.ma_dimm_addr); + return (-1); + } +} + +/* + * PA to CS (used by pa_to_maddr). + */ +static int +pa_to_cs(mc_opl_t *mcp, uint64_t pa_offset) +{ + int i; + int cs = 0; + + for (i = 0; i < PA_BITS_FOR_MAC; i++) { + /* MAC address bit<29> is arranged on the same PA bit */ + /* on both table. So we may use any table. */ + if (mcp->mc_trans_table[0][i] == CS_SHIFT) { + cs = (pa_offset >> i) & 1; + break; + } + } + return (cs); +} + +/* + * PA to DIMM (used by pa_to_maddr). + */ +/* ARGSUSED */ +static uint32_t +pa_to_dimm(mc_opl_t *mcp, uint64_t pa_offset) +{ + int i; + int cs = pa_to_cs(mcp, pa_offset); + uint32_t dimm_addr = 0; + + for (i = 0; i < PA_BITS_FOR_MAC; i++) { + int pa_bit_value = (pa_offset >> i) & 1; + int mc_bit = mcp->mc_trans_table[cs][i]; + if (mc_bit < MC_ADDRESS_BITS) { + dimm_addr |= pa_bit_value << mc_bit; + } + } + return (dimm_addr); +} + +/* + * PA to Bank (used by pa_to_maddr). + */ +static int +pa_to_bank(mc_opl_t *mcp, uint64_t pa_offset) +{ + int i; + int cs = pa_to_cs(mcp, pa_offset); + int bankno = mcp->mc_trans_table[cs][INDEX_OF_BANK_SUPPLEMENT_BIT]; + + + for (i = 0; i < PA_BITS_FOR_MAC; i++) { + int pa_bit_value = (pa_offset >> i) & 1; + int mc_bit = mcp->mc_trans_table[cs][i]; + switch (mc_bit) { + case MP_BANK_0: + bankno |= pa_bit_value; + break; + case MP_BANK_1: + bankno |= pa_bit_value << 1; + break; + case MP_BANK_2: + bankno |= pa_bit_value << 2; + break; + } + } + + return (bankno); +} + +/* + * PA to MAC address translation + * + * Input: MAC driver state, physicall adress + * Output: LSB#, Bank id, mac address + * + * Valid - return value: 0 + * Invalid - return value: -1 + */ + +int +pa_to_maddr(mc_opl_t *mcp, uint64_t pa, mc_addr_t *maddr) +{ + uint64_t pa_offset; + + /* PA validity check */ + if (!pa_is_valid(mcp, pa)) + return (-1); + + + /* Do translation */ + pa_offset = pa - mcp->mc_start_address; + + maddr->ma_bd = mcp->mc_board_num; + maddr->ma_bank = pa_to_bank(mcp, pa_offset); + maddr->ma_dimm_addr = pa_to_dimm(mcp, pa_offset); + MC_LOG("pa %lx -> mcaddr /LSB%d/B%d/%x\n", + pa_offset, maddr->ma_bd, maddr->ma_bank, maddr->ma_dimm_addr); + return (0); +} + +static void +mc_ereport_post(mc_aflt_t *mc_aflt) +{ + char buf[FM_MAX_CLASS]; + char device_path[MAXPATHLEN]; + nv_alloc_t *nva = NULL; + nvlist_t *ereport, *detector, *resource; + errorq_elem_t *eqep; + int nflts; + mc_flt_stat_t *flt_stat; + int i, n, blen; + char *p; + uint32_t values[2], synd[2], dslot[2]; + + if (panicstr) { + eqep = errorq_reserve(ereport_errorq); + if (eqep == NULL) + return; + ereport = errorq_elem_nvl(ereport_errorq, eqep); + nva = errorq_elem_nva(ereport_errorq, eqep); + } else { + ereport = fm_nvlist_create(nva); + } + + /* + * Create the scheme "dev" FMRI. + */ + detector = fm_nvlist_create(nva); + resource = fm_nvlist_create(nva); + + nflts = mc_aflt->mflt_nflts; + + ASSERT(nflts >= 1 && nflts <= 2); + + flt_stat = mc_aflt->mflt_stat[0]; + (void) ddi_pathname(mc_aflt->mflt_mcp->mc_dip, device_path); + (void) fm_fmri_dev_set(detector, FM_DEV_SCHEME_VERSION, NULL, + device_path, NULL); + + /* + * Encode all the common data into the ereport. + */ + (void) snprintf(buf, FM_MAX_CLASS, "%s.%s-%s", + MC_OPL_ERROR_CLASS, + mc_aflt->mflt_is_ptrl ? MC_OPL_PTRL_SUBCLASS : + MC_OPL_MI_SUBCLASS, + mc_aflt->mflt_erpt_class); + + MC_LOG("mc_ereport_post: ereport %s\n", buf); + + + fm_ereport_set(ereport, FM_EREPORT_VERSION, buf, + fm_ena_generate(mc_aflt->mflt_id, FM_ENA_FMT1), + detector, NULL); + + /* + * Set payload. + */ + fm_payload_set(ereport, MC_OPL_BOARD, DATA_TYPE_UINT32, + flt_stat->mf_flt_maddr.ma_bd, NULL); + + fm_payload_set(ereport, MC_OPL_PA, DATA_TYPE_UINT64, + flt_stat->mf_flt_paddr, NULL); + + if (flt_stat->mf_type == FLT_TYPE_PERMANENT_CE) { + fm_payload_set(ereport, MC_OPL_FLT_TYPE, + DATA_TYPE_UINT8, ECC_STICKY, NULL); + } + + for (i = 0; i < nflts; i++) + values[i] = mc_aflt->mflt_stat[i]->mf_flt_maddr.ma_bank; + + fm_payload_set(ereport, MC_OPL_BANK, DATA_TYPE_UINT32_ARRAY, + nflts, values, NULL); + + for (i = 0; i < nflts; i++) + values[i] = mc_aflt->mflt_stat[i]->mf_cntl; + + fm_payload_set(ereport, MC_OPL_STATUS, DATA_TYPE_UINT32_ARRAY, + nflts, values, NULL); + + for (i = 0; i < nflts; i++) + values[i] = mc_aflt->mflt_stat[i]->mf_err_add; + + fm_payload_set(ereport, MC_OPL_ERR_ADD, DATA_TYPE_UINT32_ARRAY, + nflts, values, NULL); + + for (i = 0; i < nflts; i++) + values[i] = mc_aflt->mflt_stat[i]->mf_err_log; + + fm_payload_set(ereport, MC_OPL_ERR_LOG, DATA_TYPE_UINT32_ARRAY, + nflts, values, NULL); + + for (i = 0; i < nflts; i++) { + flt_stat = mc_aflt->mflt_stat[i]; + if (flt_stat->mf_errlog_valid) { + synd[i] = flt_stat->mf_synd; + dslot[i] = flt_stat->mf_dimm_slot; + values[i] = flt_stat->mf_dram_place; + } else { + synd[i] = 0; + dslot[i] = 0; + values[i] = 0; + } + } + + fm_payload_set(ereport, MC_OPL_ERR_SYND, + DATA_TYPE_UINT32_ARRAY, nflts, synd, NULL); + + fm_payload_set(ereport, MC_OPL_ERR_DIMMSLOT, + DATA_TYPE_UINT32_ARRAY, nflts, dslot, NULL); + + fm_payload_set(ereport, MC_OPL_ERR_DRAM, + DATA_TYPE_UINT32_ARRAY, nflts, values, NULL); + + blen = MAXPATHLEN; + device_path[0] = 0; + p = &device_path[0]; + + for (i = 0; i < nflts; i++) { + int bank = flt_stat->mf_flt_maddr.ma_bank; + int psb = -1; + + flt_stat = mc_aflt->mflt_stat[i]; + psb = mc_opl_get_physical_board( + flt_stat->mf_flt_maddr.ma_bd); + + if (psb != -1) { + snprintf(p, blen, "/CMU%d/B%d", psb, bank); + } else { + snprintf(p, blen, "/CMU/B%d", bank); + } + + if (flt_stat->mf_errlog_valid) { + snprintf(p + strlen(p), blen, "/MEM%d%d%c", + bank/2, (bank & 0x1) * 2 + dslot[i] & 1, + (dslot[i] & 0x2) ? 'B' : 'A'); + } + + n = strlen(&device_path[0]); + blen = MAXPATHLEN - n; + p = &device_path[n]; + if (i < (nflts - 1)) { + snprintf(p, blen, " "); + n += 1; blen -= 1; p += 1; + } + } + + /* + * UNUM format /LSB#/B#/MEMxyZ + * where x is the MAC# = Bank#/2 + * y is slot info = (Bank# & 0x1)*2 + {0, 1} 0 for DIMM-L, 1 for DIMM-H + * DIMM-L is 0 in bit 13, DIMM-H is 1 in bit 13. + * Z is A(CS0) or B(CS1) given by bit 14 + */ + (void) fm_fmri_mem_set(resource, FM_MEM_SCHEME_VERSION, + NULL, device_path, NULL, 0); + + fm_payload_set(ereport, MC_OPL_RESOURCE, DATA_TYPE_NVLIST, + resource, NULL); + + if (panicstr) { + errorq_commit(ereport_errorq, eqep, ERRORQ_SYNC); + } else { + (void) fm_ereport_post(ereport, EVCH_TRYHARD); + fm_nvlist_destroy(ereport, FM_NVA_FREE); + fm_nvlist_destroy(detector, FM_NVA_FREE); + fm_nvlist_destroy(resource, FM_NVA_FREE); + } +} + +static void +mc_err_drain(mc_aflt_t *mc_aflt) +{ + int rv; + page_t *pp; + uint64_t errors; + uint64_t pa = (uint64_t)(-1); + + MC_LOG("mc_err_drain: %s\n", + mc_aflt->mflt_erpt_class); + /* + * we come here only when we have: + * In mirror mode: CMPE, MUE, SUE + * In normal mode: UE, Permanent CE + */ + rv = mcaddr_to_pa(mc_aflt->mflt_mcp, + &(mc_aflt->mflt_stat[0]->mf_flt_maddr), &pa); + if (rv == 0) + mc_aflt->mflt_stat[0]->mf_flt_paddr = pa; + else + mc_aflt->mflt_stat[0]->mf_flt_paddr = (uint64_t)-1; + if (rv == 0) { + MC_LOG("mc_err_drain:pa = %lx\n", pa); + pp = page_numtopp_nolock(pa >> PAGESHIFT); + + if (pp) { + /* + * Don't keep retiring and make ereports + * on bad pages in PTRL case + */ + MC_LOG("mc_err_drain:pp = %p\n", pp); + if (mc_aflt->mflt_is_ptrl) { + errors = 0; + if (page_retire_check(pa, &errors) == 0) { + MC_LOG("Page retired\n"); + return; + } + if (errors & mc_aflt->mflt_pr) { + MC_LOG("errors %lx, mflt_pr %x\n", + errors, mc_aflt->mflt_pr); + return; + } + } + MC_LOG("offline page %p error %x\n", pp, + mc_aflt->mflt_pr); + (void) page_retire(pa, mc_aflt->mflt_pr); + } + } + mc_ereport_post(mc_aflt); +} + +#define DIMM_SIZE 0x80000000 + +#define INC_DIMM_ADDR(p, n) \ + (p)->ma_dimm_addr += n; \ + (p)->ma_dimm_addr &= (DIMM_SIZE - 1) + +/* + * The restart address is actually defined in unit of PA[37:6] + * the mac patrol will convert that to dimm offset. If the + * address is not in the bank, it will continue to search for + * the next PA that is within the bank. + * + * Also the mac patrol scans the dimms based on PA, not + * dimm offset. + */ + +static int +restart_patrol(mc_opl_t *mcp, int bank, mc_addr_info_t *maddr_info) +{ + page_t *pp; + uint32_t reg; + uint64_t pa; + int rv; + int loop_count = 0; + + reg = ldphysio(MAC_PTRL_CNTL(mcp, bank)); + + /* already running, so we just return */ + if (reg & MAC_CNTL_PTRL_START) + return (0); + + if (maddr_info == NULL || (maddr_info->mi_valid == 0)) { + MAC_PTRL_START(mcp, bank); + return (0); + } + + + rv = mcaddr_to_pa(mcp, &maddr_info->mi_maddr, &pa); + if (rv != 0) { + MC_LOG("cannot convert mcaddr to pa. use auto restart\n"); + MAC_PTRL_START(mcp, bank); + return (0); + } + + /* + * pa is the last address scanned by the mac patrol + * we calculate the next restart address as follows: + * first we always advance it by 64 byte. Then begin the loop. + * loop { + * if it is not in phys_install, we advance to next 64 MB boundary + * if it is not backed by a page structure, done + * if the page is bad, advance to the next page boundary. + * else done + * if the new address exceeds the board, wrap around. + * } <stop if we come back to the same page> + */ + + if (pa < mcp->mc_start_address || pa >= (mcp->mc_start_address + + mcp->mc_size)) { + /* pa is not on this board, just retry */ + cmn_err(CE_WARN, "restart_patrol: invalid address %lx " + "on board %d\n", pa, mcp->mc_board_num); + MAC_PTRL_START(mcp, bank); + return (0); + } + + MC_LOG("restart_patrol: pa = %lx\n", pa); + if (maddr_info->mi_advance) { + uint64_t new_pa; + + if (IS_MIRROR(mcp, bank)) + new_pa = pa + 64 * 2; + else + new_pa = pa + 64; + + if (!mc_valid_pa(mcp, new_pa)) { + /* Isolation unit size is 64 MB */ +#define MC_ISOLATION_BSIZE (64 * 1024 * 1024) + MC_LOG("Invalid PA\n"); + pa = roundup(new_pa + 1, MC_ISOLATION_BSIZE); + } else { + pp = page_numtopp_nolock(new_pa >> PAGESHIFT); + if (pp != NULL) { + uint64_t errors = 0; + if (page_retire_check(new_pa, &errors) && + (errors == 0)) { + MC_LOG("Page has no error\n"); + MAC_PTRL_START(mcp, bank); + return (0); + } + /* + * skip bad pages + * and let the following loop to take care + */ + pa = roundup(new_pa + 1, PAGESIZE); + MC_LOG("Skipping bad page to %lx\n", pa); + } else { + MC_LOG("Page has no page structure\n"); + MAC_PTRL_START(mcp, bank); + return (0); + } + } + } + + /* + * if we wrap around twice, we just give up and let + * mac patrol decide. + */ + MC_LOG("pa is now %lx\n", pa); + while (loop_count <= 1) { + if (!mc_valid_pa(mcp, pa)) { + MC_LOG("pa is not valid. round up to 64 MB\n"); + pa = roundup(pa + 1, 64 * 1024 * 1024); + } else { + pp = page_numtopp_nolock(pa >> PAGESHIFT); + if (pp != NULL) { + uint64_t errors = 0; + if (page_retire_check(pa, &errors) && + (errors == 0)) { + MC_LOG("Page has no error\n"); + break; + } + /* skip bad pages */ + pa = roundup(pa + 1, PAGESIZE); + MC_LOG("Skipping bad page to %lx\n", pa); + } else { + MC_LOG("Page has no page structure\n"); + break; + } + } + if (pa >= (mcp->mc_start_address + mcp->mc_size)) { + MC_LOG("Wrap around\n"); + pa = mcp->mc_start_address; + loop_count++; + } + } + + /* retstart MAC patrol: PA[37:6] */ + MC_LOG("restart at pa = %lx\n", pa); + ST_MAC_REG(MAC_RESTART_ADD(mcp, bank), MAC_RESTART_PA(pa)); + MAC_PTRL_START_ADD(mcp, bank); + + return (0); +} + +/* + * Rewriting is used for two purposes. + * - to correct the error in memory. + * - to determine whether the error is permanent or intermittent. + * It's done by writing the address in MAC_BANKm_REWRITE_ADD + * and issuing REW_REQ command in MAC_BANKm_PTRL_CNRL. After that, + * REW_END (and REW_CE/REW_UE if some error detected) is set when + * rewrite operation is done. See 4.7.3 and 4.7.11 in Columbus2 PRM. + * + * Note that rewrite operation doesn't change RAW_UE to Marked UE. + * Therefore, we use it only CE case. + */ +static uint32_t +do_rewrite(mc_opl_t *mcp, int bank, uint32_t dimm_addr) +{ + uint32_t cntl; + int count = 0; + + /* first wait to make sure PTRL_STATUS is 0 */ + while (count++ < MAX_MC_LOOP_COUNT) { + cntl = LD_MAC_REG(MAC_PTRL_CNTL(mcp, bank)); + if (!(cntl & MAC_CNTL_PTRL_STATUS)) + break; + delay(drv_usectohz(10 * 1000)); /* 10 m.s. */ + } + if (count >= MAX_MC_LOOP_COUNT) + goto bad; + + count = 0; + + ST_MAC_REG(MAC_REWRITE_ADD(mcp, bank), dimm_addr); + MAC_REW_REQ(mcp, bank); + + do { + cntl = LD_MAC_REG(MAC_PTRL_CNTL(mcp, bank)); + if (count++ >= MAX_MC_LOOP_COUNT) { + goto bad; + } else + delay(drv_usectohz(10 * 1000)); /* 10 m.s. */ + /* + * If there are other MEMORY or PCI activities, this + * will be BUSY, else it should be set immediately + */ + } while (!(cntl & MAC_CNTL_REW_END)); + + MAC_CLEAR_ERRS(mcp, bank, MAC_CNTL_REW_ERRS); + return (cntl); +bad: + /* This is bad. Just reset the circuit */ + cmn_err(CE_WARN, "mc-opl rewrite timeout on /LSB%d/B%d\n", + mcp->mc_board_num, bank); + cntl = MAC_CNTL_REW_END; + MAC_CMD(mcp, bank, MAC_CNTL_PTRL_RESET); + MAC_CLEAR_ERRS(mcp, bank, MAC_CNTL_REW_ERRS); + return (cntl); +} + +void +mc_process_scf_log(mc_opl_t *mcp) +{ + int count = 0; + scf_log_t *p; + int bank; + + while ((p = mcp->mc_scf_log) != NULL) { + bank = p->sl_bank; + while ((LD_MAC_REG(MAC_STATIC_ERR_ADD(mcp, p->sl_bank)) + & MAC_STATIC_ERR_VLD)) { + if (count++ >= (MAX_MC_LOOP_COUNT)) { + break; + } + delay(drv_usectohz(10 * 1000)); /* 10 m.s. */ + } + + if (count < MAX_MC_LOOP_COUNT) { + ST_MAC_REG(MAC_STATIC_ERR_LOG(mcp, p->sl_bank), + p->sl_err_log); + + ST_MAC_REG(MAC_STATIC_ERR_ADD(mcp, p->sl_bank), + p->sl_err_add|MAC_STATIC_ERR_VLD); + mcp->mc_scf_retry[bank] = 0; + } else { + /* if we try too many times, just drop the req */ + if (mcp->mc_scf_retry[bank]++ <= MAX_SCF_RETRY) { + return; + } else { + cmn_err(CE_WARN, "SCF is not responding. " + "Dropping the SCF LOG\n"); + } + } + mcp->mc_scf_log = p->sl_next; + mcp->mc_scf_total--; + ASSERT(mcp->mc_scf_total >= 0); + kmem_free(p, sizeof (scf_log_t)); + } +} + +void +mc_queue_scf_log(mc_opl_t *mcp, mc_flt_stat_t *flt_stat, int bank) +{ + scf_log_t *p; + + if (mcp->mc_scf_total >= MAX_SCF_LOGS) { + cmn_err(CE_WARN, + "Max# SCF logs excceded on /LSB%d/B%d\n", + mcp->mc_board_num, bank); + return; + } + p = kmem_zalloc(sizeof (scf_log_t), KM_SLEEP); + p->sl_next = 0; + p->sl_err_add = flt_stat->mf_err_add; + p->sl_err_log = flt_stat->mf_err_log; + p->sl_bank = bank; + + if (mcp->mc_scf_log == NULL) { + /* + * we rely on mc_scf_log to detect NULL queue. + * mc_scf_log_tail is irrelevant is such case. + */ + mcp->mc_scf_log_tail = mcp->mc_scf_log = p; + } else { + mcp->mc_scf_log_tail->sl_next = p; + mcp->mc_scf_log_tail = p; + } + mcp->mc_scf_total++; +} + +/* + * This routine determines what kind of CE happens, intermittent + * or permanent as follows. (See 4.7.3 in Columbus2 PRM.) + * - Do rewrite by issuing REW_REQ command to MAC_PTRL_CNTL register. + * - If CE is still detected on the same address even after doing + * rewrite operation twice, it is determined as permanent error. + * - If error is not detected anymore, it is determined as intermittent + * error. + * - If UE is detected due to rewrite operation, it should be treated + * as UE. + */ + +/* ARGSUSED */ +static void +mc_scrub_ce(mc_opl_t *mcp, int bank, mc_flt_stat_t *flt_stat, int ptrl_error) +{ + uint32_t cntl; + int i; + + flt_stat->mf_type = FLT_TYPE_PERMANENT_CE; + /* + * rewrite request 1st time reads and correct error data + * and write to DIMM. 2nd rewrite request must be issued + * after REW_CE/UE/END is 0. When the 2nd request is completed, + * if REW_CE = 1, then it is permanent CE. + */ + for (i = 0; i < 2; i++) { + cntl = do_rewrite(mcp, bank, flt_stat->mf_err_add); + /* + * If the error becomes UE or CMPE + * we return to the caller immediately. + */ + if (cntl & MAC_CNTL_REW_UE) { + if (ptrl_error) + flt_stat->mf_cntl |= MAC_CNTL_PTRL_UE; + else + flt_stat->mf_cntl |= MAC_CNTL_MI_UE; + flt_stat->mf_type = FLT_TYPE_UE; + return; + } + if (cntl & MAC_CNTL_REW_CMPE) { + if (ptrl_error) + flt_stat->mf_cntl |= MAC_CNTL_PTRL_CMPE; + else + flt_stat->mf_cntl |= MAC_CNTL_MI_CMPE; + flt_stat->mf_type = FLT_TYPE_CMPE; + return; + } + } + if (!(cntl & MAC_CNTL_REW_CE)) { + flt_stat->mf_type = FLT_TYPE_INTERMITTENT_CE; + } + + if (flt_stat->mf_type == FLT_TYPE_PERMANENT_CE) { + /* report PERMANENT_CE to SP via SCF */ + if (!(flt_stat->mf_err_log & MAC_ERR_LOG_INVALID)) { + mc_queue_scf_log(mcp, flt_stat, bank); + } + } +} + +#define IS_CMPE(cntl, f) ((cntl) & ((f) ? MAC_CNTL_PTRL_CMPE :\ + MAC_CNTL_MI_CMPE)) +#define IS_UE(cntl, f) ((cntl) & ((f) ? MAC_CNTL_PTRL_UE : MAC_CNTL_MI_UE)) +#define IS_CE(cntl, f) ((cntl) & ((f) ? MAC_CNTL_PTRL_CE : MAC_CNTL_MI_CE)) +#define IS_OK(cntl, f) (!((cntl) & ((f) ? MAC_CNTL_PTRL_ERRS : \ + MAC_CNTL_MI_ERRS))) + + +static int +IS_CE_ONLY(uint32_t cntl, int ptrl_error) +{ + if (ptrl_error) { + return ((cntl & MAC_CNTL_PTRL_ERRS) == MAC_CNTL_PTRL_CE); + } else { + return ((cntl & MAC_CNTL_MI_ERRS) == MAC_CNTL_MI_CE); + } +} + +void +mc_write_cntl(mc_opl_t *mcp, int bank, uint32_t value) +{ + value |= mcp->mc_bank[bank].mcb_ptrl_cntl; + ST_MAC_REG(MAC_PTRL_CNTL(mcp, bank), value); +} + +static int +mc_stop(mc_opl_t *mcp, int bank) +{ + uint32_t reg; + int count = 0; + + reg = LD_MAC_REG(MAC_PTRL_CNTL(mcp, bank)); + + if (reg & MAC_CNTL_PTRL_START) + MAC_PTRL_STOP(mcp, bank); + + while (count++ <= MAX_MC_LOOP_COUNT) { + reg = LD_MAC_REG(MAC_PTRL_CNTL(mcp, bank)); + if ((reg & MAC_CNTL_PTRL_STATUS) == 0) + return (0); + delay(drv_usectohz(10 * 1000)); /* 10 m.s. */ + } + return (-1); +} + +static void +mc_read_ptrl_reg(mc_opl_t *mcp, int bank, mc_flt_stat_t *flt_stat) +{ + flt_stat->mf_cntl = LD_MAC_REG(MAC_PTRL_CNTL(mcp, bank)) & + MAC_CNTL_PTRL_ERRS; + flt_stat->mf_err_add = LD_MAC_REG(MAC_PTRL_ERR_ADD(mcp, bank)); + flt_stat->mf_err_log = LD_MAC_REG(MAC_PTRL_ERR_LOG(mcp, bank)); + flt_stat->mf_flt_maddr.ma_bd = mcp->mc_board_num; + flt_stat->mf_flt_maddr.ma_bank = bank; + flt_stat->mf_flt_maddr.ma_dimm_addr = flt_stat->mf_err_add; +} + +static void +mc_read_mi_reg(mc_opl_t *mcp, int bank, mc_flt_stat_t *flt_stat) +{ + uint32_t status, old_status; + + status = LD_MAC_REG(MAC_PTRL_CNTL(mcp, bank)) & + MAC_CNTL_MI_ERRS; + old_status = 0; + + /* we keep reading until the status is stable */ + while (old_status != status) { + old_status = status; + flt_stat->mf_err_add = + LD_MAC_REG(MAC_MI_ERR_ADD(mcp, bank)); + flt_stat->mf_err_log = + LD_MAC_REG(MAC_MI_ERR_LOG(mcp, bank)); + status = LD_MAC_REG(MAC_PTRL_CNTL(mcp, bank)) & + MAC_CNTL_MI_ERRS; + if (status == old_status) { + break; + } + } + + flt_stat->mf_cntl = status; + flt_stat->mf_flt_maddr.ma_bd = mcp->mc_board_num; + flt_stat->mf_flt_maddr.ma_bank = bank; + flt_stat->mf_flt_maddr.ma_dimm_addr = flt_stat->mf_err_add; +} + + +/* + * Error philosophy for mirror mode: + * + * PTRL (The error address for both banks are same, since ptrl stops if it + * detects error.) + * - Compaire error Report CMPE. + * + * - UE-UE Report MUE. No rewrite. + * + * - UE-* UE-(CE/OK). Rewrite to scrub UE. Report SUE. + * + * - CE-* CE-(CE/OK). Scrub to determine if CE is permanent. + * If CE is permanent, inform SCF. Once for each + * Dimm. If CE becomes UE or CMPE, go back to above. + * + * + * MI (The error addresses for each bank are the same or different.) + * - Compair error If addresses are the same. Just CMPE. + * If addresses are different (this could happen + * as a result of scrubbing. Report each seperately. + * Only report error info on each side. + * + * - UE-UE Addresses are the same. Report MUE. + * Addresses are different. Report SUE on each bank. + * Rewrite to clear UE. + * + * - UE-* UE-(CE/OK) + * Rewrite to clear UE. Report SUE for the bank. + * + * - CE-* CE-(CE/OK). Scrub to determine if CE is permanent. + * If CE becomes UE or CMPE, go back to above. + * + */ + +static int +mc_process_error_mir(mc_opl_t *mcp, mc_aflt_t *mc_aflt, mc_flt_stat_t *flt_stat) +{ + int ptrl_error = mc_aflt->mflt_is_ptrl; + int i; + int rv = 0; + + MC_LOG("process mirror errors cntl[0] = %x, cntl[1] = %x\n", + flt_stat[0].mf_cntl, flt_stat[1].mf_cntl); + + if (ptrl_error) { + if (((flt_stat[0].mf_cntl | flt_stat[1].mf_cntl) + & MAC_CNTL_PTRL_ERRS) == 0) + return (0); + } else { + if (((flt_stat[0].mf_cntl | flt_stat[1].mf_cntl) + & MAC_CNTL_MI_ERRS) == 0) + return (0); + } + + /* + * First we take care of the case of CE + * because they can become UE or CMPE + */ + for (i = 0; i < 2; i++) { + if (IS_CE_ONLY(flt_stat[i].mf_cntl, ptrl_error)) { + MC_LOG("CE detected on bank %d\n", + flt_stat[i].mf_flt_maddr.ma_bank); + mc_scrub_ce(mcp, flt_stat[i].mf_flt_maddr.ma_bank, + &flt_stat[i], ptrl_error); + rv = 1; + } + } + + /* The above scrubbing can turn CE into UE or CMPE */ + + /* + * Now we distinguish two cases: same address or not + * the same address. It might seem more intuitive to + * distinguish PTRL v.s. MI error but it is more + * complicated that way. + */ + + if (flt_stat[0].mf_err_add == flt_stat[1].mf_err_add) { + + if (IS_CMPE(flt_stat[0].mf_cntl, ptrl_error) || + IS_CMPE(flt_stat[1].mf_cntl, ptrl_error)) { + flt_stat[0].mf_type = FLT_TYPE_CMPE; + flt_stat[1].mf_type = FLT_TYPE_CMPE; + mc_aflt->mflt_erpt_class = MC_OPL_CMPE; + MC_LOG("cmpe error detected\n"); + mc_aflt->mflt_nflts = 2; + mc_aflt->mflt_stat[0] = &flt_stat[0]; + mc_aflt->mflt_stat[1] = &flt_stat[1]; + mc_aflt->mflt_pr = PR_UE; + mc_err_drain(mc_aflt); + return (1); + } + + if (IS_UE(flt_stat[0].mf_cntl, ptrl_error) && + IS_UE(flt_stat[1].mf_cntl, ptrl_error)) { + /* Both side are UE's */ + + MAC_SET_ERRLOG_INFO(&flt_stat[0]); + MAC_SET_ERRLOG_INFO(&flt_stat[1]); + MC_LOG("MUE detected\n"); + flt_stat[0].mf_type = flt_stat[1].mf_type = + FLT_TYPE_MUE; + mc_aflt->mflt_erpt_class = MC_OPL_MUE; + mc_aflt->mflt_nflts = 2; + mc_aflt->mflt_stat[0] = &flt_stat[0]; + mc_aflt->mflt_stat[1] = &flt_stat[1]; + mc_aflt->mflt_pr = PR_UE; + mc_err_drain(mc_aflt); + return (1); + } + + /* Now the only case is UE/CE, UE/OK, or don't care */ + for (i = 0; i < 2; i++) { + if (IS_UE(flt_stat[i].mf_cntl, ptrl_error)) { + /* If we have CE, we would have done REW */ + if (IS_OK(flt_stat[i^1].mf_cntl, ptrl_error)) { + (void) do_rewrite(mcp, + flt_stat[i].mf_flt_maddr.ma_bank, + flt_stat[i].mf_flt_maddr.ma_dimm_addr); + } + flt_stat[i].mf_type = FLT_TYPE_UE; + MAC_SET_ERRLOG_INFO(&flt_stat[i]); + mc_aflt->mflt_erpt_class = MC_OPL_SUE; + mc_aflt->mflt_stat[0] = &flt_stat[i]; + mc_aflt->mflt_nflts = 1; + mc_aflt->mflt_pr = PR_MCE; + mc_err_drain(mc_aflt); + /* Once we hit a UE/CE or UE/OK case, done */ + return (1); + } + } + + } else { + /* + * addresses are different. That means errors + * on the 2 banks are not related at all. + */ + for (i = 0; i < 2; i++) { + if (IS_CMPE(flt_stat[i].mf_cntl, ptrl_error)) { + flt_stat[i].mf_type = FLT_TYPE_CMPE; + mc_aflt->mflt_erpt_class = MC_OPL_CMPE; + MC_LOG("cmpe error detected\n"); + mc_aflt->mflt_nflts = 1; + mc_aflt->mflt_stat[0] = &flt_stat[i]; + mc_aflt->mflt_pr = PR_UE; + mc_err_drain(mc_aflt); + /* no more report on this bank */ + flt_stat[i].mf_cntl = 0; + rv = 1; + } + } + + for (i = 0; i < 2; i++) { + if (IS_UE(flt_stat[i].mf_cntl, ptrl_error)) { + (void) do_rewrite(mcp, + flt_stat[i].mf_flt_maddr.ma_bank, + flt_stat[i].mf_flt_maddr.ma_dimm_addr); + flt_stat[i].mf_type = FLT_TYPE_UE; + MAC_SET_ERRLOG_INFO(&flt_stat[i]); + mc_aflt->mflt_erpt_class = MC_OPL_SUE; + mc_aflt->mflt_stat[0] = &flt_stat[i]; + mc_aflt->mflt_nflts = 1; + mc_aflt->mflt_pr = PR_MCE; + mc_err_drain(mc_aflt); + rv = 1; + } + } + } + return (rv); +} + +static void +mc_error_handler_mir(mc_opl_t *mcp, int bank, mc_addr_info_t *maddr) +{ + mc_aflt_t mc_aflt; + mc_flt_stat_t flt_stat[2], mi_flt_stat[2]; + int other_bank; + + if (mc_stop(mcp, bank)) { + cmn_err(CE_WARN, "Cannot stop Memory Patrol at /LSB%d/B%d\n", + mcp->mc_board_num, bank); + return; + } + bzero(&mc_aflt, sizeof (mc_aflt_t)); + bzero(&flt_stat, 2 * sizeof (mc_flt_stat_t)); + bzero(&mi_flt_stat, 2 * sizeof (mc_flt_stat_t)); + + mc_aflt.mflt_mcp = mcp; + mc_aflt.mflt_id = gethrtime(); + + /* Now read all the registers into flt_stat */ + + MC_LOG("Reading registers of bank %d\n", bank); + /* patrol registers */ + mc_read_ptrl_reg(mcp, bank, &flt_stat[0]); + + ASSERT(maddr); + maddr->mi_maddr = flt_stat[0].mf_flt_maddr; + + MC_LOG("ptrl registers cntl %x add %x log %x\n", + flt_stat[0].mf_cntl, + flt_stat[0].mf_err_add, + flt_stat[0].mf_err_log); + + /* MI registers */ + mc_read_mi_reg(mcp, bank, &mi_flt_stat[0]); + + MC_LOG("MI registers cntl %x add %x log %x\n", + mi_flt_stat[0].mf_cntl, + mi_flt_stat[0].mf_err_add, + mi_flt_stat[0].mf_err_log); + + other_bank = bank^1; + + MC_LOG("Reading registers of bank %d\n", other_bank); + + ASSERT(mcp->mc_bank[other_bank].mcb_status & BANK_INSTALLED); + + mc_read_ptrl_reg(mcp, other_bank, &flt_stat[1]); + MC_LOG("ptrl registers cntl %x add %x log %x\n", + flt_stat[1].mf_cntl, + flt_stat[1].mf_err_add, + flt_stat[1].mf_err_log); + + /* MI registers */ + mc_read_mi_reg(mcp, other_bank, &mi_flt_stat[1]); + MC_LOG("MI registers cntl %x add %x log %x\n", + mi_flt_stat[1].mf_cntl, + mi_flt_stat[1].mf_err_add, + mi_flt_stat[1].mf_err_log); + + /* clear errors once we read all the registers */ + MAC_CLEAR_ERRS(mcp, other_bank, + (MAC_CNTL_PTRL_ERRS|MAC_CNTL_MI_ERRS)); + + MAC_CLEAR_ERRS(mcp, bank, (MAC_CNTL_PTRL_ERRS|MAC_CNTL_MI_ERRS)); + + /* Process PTRL errors first */ + + /* if not error mode, cntl1 is 0 */ + if ((flt_stat[0].mf_err_add & MAC_ERR_ADD_INVALID) || + (flt_stat[0].mf_err_log & MAC_ERR_LOG_INVALID)) + flt_stat[0].mf_cntl = 0; + + if ((flt_stat[1].mf_err_add & MAC_ERR_ADD_INVALID) || + (flt_stat[1].mf_err_log & MAC_ERR_LOG_INVALID)) + flt_stat[1].mf_cntl = 0; + + mc_aflt.mflt_is_ptrl = 1; + maddr->mi_valid = mc_process_error_mir(mcp, &mc_aflt, &flt_stat[0]); + + mc_aflt.mflt_is_ptrl = 0; + mc_process_error_mir(mcp, &mc_aflt, &mi_flt_stat[0]); +} + +static int +mc_process_error(mc_opl_t *mcp, int bank, mc_aflt_t *mc_aflt, + mc_flt_stat_t *flt_stat) +{ + int ptrl_error = mc_aflt->mflt_is_ptrl; + int rv = 0; + + mc_aflt->mflt_erpt_class = NULL; + if (IS_UE(flt_stat->mf_cntl, ptrl_error)) { + MC_LOG("UE deteceted\n"); + flt_stat->mf_type = FLT_TYPE_UE; + mc_aflt->mflt_erpt_class = MC_OPL_UE; + mc_aflt->mflt_pr = PR_UE; + MAC_SET_ERRLOG_INFO(flt_stat); + rv = 1; + } else if (IS_CE(flt_stat->mf_cntl, ptrl_error)) { + MC_LOG("CE deteceted\n"); + MAC_SET_ERRLOG_INFO(flt_stat); + + /* Error type can change after scrubing */ + mc_scrub_ce(mcp, bank, flt_stat, ptrl_error); + + if (flt_stat->mf_type == FLT_TYPE_PERMANENT_CE) { + mc_aflt->mflt_erpt_class = MC_OPL_CE; + mc_aflt->mflt_pr = PR_MCE; + } else if (flt_stat->mf_type == FLT_TYPE_UE) { + mc_aflt->mflt_erpt_class = MC_OPL_UE; + mc_aflt->mflt_pr = PR_UE; + } + rv = 1; + } + MC_LOG("mc_process_error: fault type %x erpt %s\n", + flt_stat->mf_type, + mc_aflt->mflt_erpt_class); + if (mc_aflt->mflt_erpt_class) { + mc_aflt->mflt_stat[0] = flt_stat; + mc_aflt->mflt_nflts = 1; + mc_err_drain(mc_aflt); + } + return (rv); +} + +static void +mc_error_handler(mc_opl_t *mcp, int bank, mc_addr_info_t *maddr) +{ + mc_aflt_t mc_aflt; + mc_flt_stat_t flt_stat, mi_flt_stat; + + if (mc_stop(mcp, bank)) { + cmn_err(CE_WARN, "Cannot stop Memory Patrol at /LSB%d/B%d\n", + mcp->mc_board_num, bank); + return; + } + + bzero(&mc_aflt, sizeof (mc_aflt_t)); + bzero(&flt_stat, sizeof (mc_flt_stat_t)); + bzero(&mi_flt_stat, sizeof (mc_flt_stat_t)); + + mc_aflt.mflt_mcp = mcp; + mc_aflt.mflt_id = gethrtime(); + + /* patrol registers */ + mc_read_ptrl_reg(mcp, bank, &flt_stat); + + ASSERT(maddr); + maddr->mi_maddr = flt_stat.mf_flt_maddr; + + MC_LOG("ptrl registers cntl %x add %x log %x\n", + flt_stat.mf_cntl, + flt_stat.mf_err_add, + flt_stat.mf_err_log); + + /* MI registers */ + mc_read_mi_reg(mcp, bank, &mi_flt_stat); + + MC_LOG("MI registers cntl %x add %x log %x\n", + mi_flt_stat.mf_cntl, + mi_flt_stat.mf_err_add, + mi_flt_stat.mf_err_log); + + /* clear errors once we read all the registers */ + MAC_CLEAR_ERRS(mcp, bank, (MAC_CNTL_PTRL_ERRS|MAC_CNTL_MI_ERRS)); + + mc_aflt.mflt_is_ptrl = 1; + if ((flt_stat.mf_cntl & MAC_CNTL_PTRL_ERRS) && + ((flt_stat.mf_err_add & MAC_ERR_ADD_INVALID) == 0) && + ((flt_stat.mf_err_log & MAC_ERR_LOG_INVALID) == 0)) { + maddr->mi_valid = mc_process_error(mcp, bank, + &mc_aflt, &flt_stat); + } + mc_aflt.mflt_is_ptrl = 0; + if ((mi_flt_stat.mf_cntl & MAC_CNTL_MI_ERRS) && + ((mi_flt_stat.mf_err_add & MAC_ERR_ADD_INVALID) == 0) && + ((mi_flt_stat.mf_err_log & MAC_ERR_LOG_INVALID) == 0)) { + mc_process_error(mcp, bank, &mc_aflt, &mi_flt_stat); + } +} + +/* + * memory patrol error handling algorithm: + * timeout() is used to do periodic polling + * This is the flow chart. + * timeout -> + * mc_check_errors() + * if memory bank is installed, read the status register + * if any error bit is set, + * -> mc_error_handler() + * -> mc_stop() + * -> read all error regsiters + * -> mc_process_error() + * determine error type + * rewrite to clear error or scrub to determine CE type + * inform SCF on permanent CE + * -> mc_err_drain + * page offline processing + * -> mc_ereport_post() + */ + +static void +mc_check_errors_func(mc_opl_t *mcp) +{ + mc_addr_info_t maddr_info; + int i, error_count = 0; + uint32_t stat, cntl; + + /* + * scan errors. + */ + for (i = 0; i < BANKNUM_PER_SB; i++) { + if (mcp->mc_bank[i].mcb_status & BANK_INSTALLED) { + stat = ldphysio(MAC_PTRL_STAT(mcp, i)); + cntl = ldphysio(MAC_PTRL_CNTL(mcp, i)); + if (cntl & MAC_CNTL_PTRL_ADD_MAX) { + mcp->mc_period++; + MC_LOG("mc period %ld on " + "/LSB%d/B%d\n", mcp->mc_period, + mcp->mc_board_num, i); + MAC_CLEAR_MAX(mcp, i); + } + if (mc_debug_show_all) { + MC_LOG("/LSB%d/B%d stat %x cntl %x\n", + mcp->mc_board_num, i, + stat, cntl); + } + if (stat & (MAC_STAT_PTRL_ERRS|MAC_STAT_MI_ERRS)) { + maddr_info.mi_valid = 0; + maddr_info.mi_advance = 1; + if (IS_MIRROR(mcp, i)) + mc_error_handler_mir(mcp, i, + &maddr_info); + else + mc_error_handler(mcp, i, &maddr_info); + + error_count++; + restart_patrol(mcp, i, &maddr_info); + } else { + restart_patrol(mcp, i, NULL); + } + } + } + mc_process_scf_log(mcp); + if (error_count > 0) + mcp->mc_last_error += error_count; + else + mcp->mc_last_error = 0; +} + +/* this is just a wrapper for the above func */ + +static void +mc_check_errors(void *arg) +{ + mc_opl_t *mcp = (mc_opl_t *)arg; + clock_t interval; + + /* + * scan errors. + */ + mutex_enter(&mcp->mc_lock); + mcp->mc_tid = 0; + if ((mcp->mc_status & MC_POLL_RUNNING) && + !(mcp->mc_status & MC_SOFT_SUSPENDED)) { + mc_check_errors_func(mcp); + + if (mcp->mc_last_error > 0) { + interval = (mcp->mc_interval_hz) >> mcp->mc_last_error; + if (interval < 1) + interval = 1; + } else + interval = mcp->mc_interval_hz; + + mcp->mc_tid = timeout(mc_check_errors, mcp, + interval); + } + mutex_exit(&mcp->mc_lock); +} + +static void +get_ptrl_start_address(mc_opl_t *mcp, int bank, mc_addr_t *maddr) +{ + maddr->ma_bd = mcp->mc_board_num; + maddr->ma_bank = bank; + maddr->ma_dimm_addr = 0; +} + +typedef struct mc_mem_range { + uint64_t addr; + uint64_t size; +} mc_mem_range_t; + +static int +get_base_address(mc_opl_t *mcp) +{ + mc_mem_range_t *mem_range; + int len; + + if (ddi_getlongprop(DDI_DEV_T_ANY, mcp->mc_dip, DDI_PROP_DONTPASS, + "sb-mem-ranges", (caddr_t)&mem_range, &len) != DDI_SUCCESS) { + return (DDI_FAILURE); + } + + mcp->mc_start_address = mem_range->addr; + mcp->mc_size = mem_range->size; + + kmem_free(mem_range, len); + return (DDI_SUCCESS); +} + +struct mc_addr_spec { + uint32_t bank; + uint32_t phys_hi; + uint32_t phys_lo; +}; + +#define REGS_PA(m, i) ((((uint64_t)m[i].phys_hi)<<32) | m[i].phys_lo) + +static char *mc_tbl_name[] = { + "cs0-mc-pa-trans-table", + "cs1-mc-pa-trans-table" +}; + +static int +mc_valid_pa(mc_opl_t *mcp, uint64_t pa) +{ + struct memlist *ml; + + if (mcp->mlist == NULL) + mc_get_mlist(mcp); + + for (ml = mcp->mlist; ml; ml = ml->next) { + if (ml->address <= pa && pa < (ml->address + ml->size)) + return (1); + } + return (0); +} + +static void +mc_memlist_delete(struct memlist *mlist) +{ + struct memlist *ml; + + for (ml = mlist; ml; ml = mlist) { + mlist = ml->next; + kmem_free(ml, sizeof (struct memlist)); + } +} + +static struct memlist * +mc_memlist_dup(struct memlist *mlist) +{ + struct memlist *hl = NULL, *tl, **mlp; + + if (mlist == NULL) + return (NULL); + + mlp = &hl; + tl = *mlp; + for (; mlist; mlist = mlist->next) { + *mlp = kmem_alloc(sizeof (struct memlist), KM_SLEEP); + (*mlp)->address = mlist->address; + (*mlp)->size = mlist->size; + (*mlp)->prev = tl; + tl = *mlp; + mlp = &((*mlp)->next); + } + *mlp = NULL; + + return (hl); +} + + +static struct memlist * +mc_memlist_del_span(struct memlist *mlist, uint64_t base, uint64_t len) +{ + uint64_t end; + struct memlist *ml, *tl, *nlp; + + if (mlist == NULL) + return (NULL); + + end = base + len; + if ((end <= mlist->address) || (base == end)) + return (mlist); + + for (tl = ml = mlist; ml; tl = ml, ml = nlp) { + uint64_t mend; + + nlp = ml->next; + + if (end <= ml->address) + break; + + mend = ml->address + ml->size; + if (base < mend) { + if (base <= ml->address) { + ml->address = end; + if (end >= mend) + ml->size = 0ull; + else + ml->size = mend - ml->address; + } else { + ml->size = base - ml->address; + if (end < mend) { + struct memlist *nl; + /* + * splitting an memlist entry. + */ + nl = kmem_alloc(sizeof (struct memlist), + KM_SLEEP); + nl->address = end; + nl->size = mend - nl->address; + if ((nl->next = nlp) != NULL) + nlp->prev = nl; + nl->prev = ml; + ml->next = nl; + nlp = nl; + } + } + if (ml->size == 0ull) { + if (ml == mlist) { + if ((mlist = nlp) != NULL) + nlp->prev = NULL; + kmem_free(ml, sizeof (struct memlist)); + if (mlist == NULL) + break; + ml = nlp; + } else { + if ((tl->next = nlp) != NULL) + nlp->prev = tl; + kmem_free(ml, sizeof (struct memlist)); + ml = tl; + } + } + } + } + + return (mlist); +} + +static void +mc_get_mlist(mc_opl_t *mcp) +{ + struct memlist *mlist; + + memlist_read_lock(); + mlist = mc_memlist_dup(phys_install); + memlist_read_unlock(); + + if (mlist) { + mlist = mc_memlist_del_span(mlist, 0ull, mcp->mc_start_address); + } + + if (mlist) { + uint64_t startpa, endpa; + + startpa = mcp->mc_start_address + mcp->mc_size; + endpa = ptob(physmax + 1); + if (endpa > startpa) { + mlist = mc_memlist_del_span(mlist, + startpa, endpa - startpa); + } + } + + if (mlist) { + mcp->mlist = mlist; + } +} + +int +mc_board_add(mc_opl_t *mcp) +{ + struct mc_addr_spec *macaddr; + int len, i, bk, cc; + mc_addr_info_t maddr; + uint32_t mirr; + + mutex_init(&mcp->mc_lock, NULL, MUTEX_DRIVER, NULL); + + /* + * Get configurations from "pseudo-mc" node which includes: + * board# : LSB number + * mac-addr : physical base address of MAC registers + * csX-mac-pa-trans-table: translation table from DIMM address + * to physical address or vice versa. + */ + mcp->mc_board_num = (int)ddi_getprop(DDI_DEV_T_ANY, mcp->mc_dip, + DDI_PROP_DONTPASS, "board#", -1); + + /* + * Get start address in this CAB. It can be gotten from + * "sb-mem-ranges" property. + */ + + if (get_base_address(mcp) == DDI_FAILURE) { + mutex_destroy(&mcp->mc_lock); + return (DDI_FAILURE); + } + /* get mac-pa trans tables */ + for (i = 0; i < MC_TT_CS; i++) { + len = MC_TT_ENTRIES; + cc = ddi_getlongprop_buf(DDI_DEV_T_ANY, mcp->mc_dip, + DDI_PROP_DONTPASS, mc_tbl_name[i], + (caddr_t)mcp->mc_trans_table[i], &len); + + if (cc != DDI_SUCCESS) { + bzero(mcp->mc_trans_table[i], MC_TT_ENTRIES); + } + } + mcp->mlist = NULL; + + mc_get_mlist(mcp); + + /* initialize bank informations */ + cc = ddi_getlongprop(DDI_DEV_T_ANY, mcp->mc_dip, DDI_PROP_DONTPASS, + "mc-addr", (caddr_t)&macaddr, &len); + if (cc != DDI_SUCCESS) { + cmn_err(CE_WARN, "Cannot get mc-addr. err=%d\n", cc); + mutex_destroy(&mcp->mc_lock); + return (DDI_FAILURE); + } + + for (i = 0; i < len / sizeof (struct mc_addr_spec); i++) { + struct mc_bank *bankp; + uint32_t reg; + + /* + * setup bank + */ + bk = macaddr[i].bank; + bankp = &(mcp->mc_bank[bk]); + bankp->mcb_status = BANK_INSTALLED; + bankp->mcb_reg_base = REGS_PA(macaddr, i); + + reg = LD_MAC_REG(MAC_PTRL_CNTL(mcp, bk)); + bankp->mcb_ptrl_cntl = (reg & MAC_CNTL_PTRL_PRESERVE_BITS); + + /* + * check if mirror mode + */ + mirr = LD_MAC_REG(MAC_MIRR(mcp, bk)); + + if (mirr & MAC_MIRR_MIRROR_MODE) { + MC_LOG("Mirror -> /LSB%d/B%d\n", + mcp->mc_board_num, bk); + bankp->mcb_status |= BANK_MIRROR_MODE; + /* + * The following bit is only used for + * error injection. We should clear it + */ + if (mirr & MAC_MIRR_BANK_EXCLUSIVE) + ST_MAC_REG(MAC_MIRR(mcp, bk), + 0); + } + + /* + * restart if not mirror mode or the other bank + * of the mirror is not running + */ + if (!(mirr & MAC_MIRR_MIRROR_MODE) || + !(mcp->mc_bank[bk^1].mcb_status & + BANK_PTRL_RUNNING)) { + MC_LOG("Starting up /LSB%d/B%d\n", + mcp->mc_board_num, bk); + get_ptrl_start_address(mcp, bk, &maddr.mi_maddr); + maddr.mi_valid = 1; + maddr.mi_advance = 0; + restart_patrol(mcp, bk, &maddr); + } else { + MC_LOG("Not starting up /LSB%d/B%d\n", + mcp->mc_board_num, bk); + } + bankp->mcb_status |= BANK_PTRL_RUNNING; + } + kmem_free(macaddr, len); + + /* + * set interval in HZ. + */ + for (i = 0; i < BANKNUM_PER_SB; i++) { + mcp->mc_scf_retry[i] = 0; + } + mcp->mc_last_error = 0; + mcp->mc_period = 0; + + mcp->mc_interval_hz = drv_usectohz(mc_patrol_interval_sec * 1000000); + /* restart memory patrol checking */ + mcp->mc_status |= MC_POLL_RUNNING; + mcp->mc_tid = timeout(mc_check_errors, mcp, mcp->mc_interval_hz); + + return (DDI_SUCCESS); +} + +int +mc_board_del(mc_opl_t *mcp) +{ + int i; + scf_log_t *p; + timeout_id_t tid = 0; + + /* + * cleanup mac state + */ + mutex_enter(&mcp->mc_lock); + for (i = 0; i < BANKNUM_PER_SB; i++) { + if (mcp->mc_bank[i].mcb_status & BANK_INSTALLED) { + if (mc_stop(mcp, i)) { + mutex_exit(&mcp->mc_lock); + return (-1); + } + mcp->mc_bank[i].mcb_status &= ~BANK_INSTALLED; + } + } + + /* stop memory patrol checking */ + if (mcp->mc_status & MC_POLL_RUNNING) { + mcp->mc_status &= ~MC_POLL_RUNNING; + tid = mcp->mc_tid; + mcp->mc_tid = 0; + } + + /* just throw away all the scf logs */ + while ((p = mcp->mc_scf_log) != NULL) { + mcp->mc_scf_log = p->sl_next; + mcp->mc_scf_total--; + kmem_free(p, sizeof (scf_log_t)); + } + + if (mcp->mlist) + mc_memlist_delete(mcp->mlist); + + mutex_exit(&mcp->mc_lock); + if (tid) + (void) untimeout(tid); + + mutex_destroy(&mcp->mc_lock); + return (DDI_SUCCESS); +} + +int +mc_suspend(mc_opl_t *mcp, uint32_t flag) +{ + timeout_id_t tid = 0; + int i; + /* stop memory patrol checking */ + mutex_enter(&mcp->mc_lock); + if (mcp->mc_status & MC_POLL_RUNNING) { + for (i = 0; i < BANKNUM_PER_SB; i++) { + if (mcp->mc_bank[i].mcb_status & BANK_INSTALLED) { + if (mc_stop(mcp, i)) { + mutex_exit(&mcp->mc_lock); + return (-1); + } + } + } + mcp->mc_status &= ~MC_POLL_RUNNING; + tid = mcp->mc_tid; + } + mcp->mc_status |= flag; + mcp->mc_tid = 0; + mutex_exit(&mcp->mc_lock); + if (tid) + (void) untimeout(tid); + + return (DDI_SUCCESS); +} + +/* caller must clear the SUSPEND bits or this will do nothing */ + +int +mc_resume(mc_opl_t *mcp, uint32_t flag) +{ + int i; + uint64_t basepa; + + mutex_enter(&mcp->mc_lock); + basepa = mcp->mc_start_address; + if (get_base_address(mcp) == DDI_FAILURE) { + mutex_exit(&mcp->mc_lock); + return (DDI_FAILURE); + } + + if (basepa != mcp->mc_start_address) { + if (mcp->mlist) + mc_memlist_delete(mcp->mlist); + mcp->mlist = NULL; + mc_get_mlist(mcp); + } + + mcp->mc_status &= ~flag; + mcp->mc_list->mc_start_address = mcp->mc_start_address; + + if (mcp->mc_status & (MC_SOFT_SUSPENDED | MC_DRIVER_SUSPENDED)) { + mutex_exit(&mcp->mc_lock); + return (DDI_SUCCESS); + } + + if (!(mcp->mc_status & MC_POLL_RUNNING)) { + /* restart memory patrol checking */ + mcp->mc_status |= MC_POLL_RUNNING; + for (i = 0; i < BANKNUM_PER_SB; i++) { + if (mcp->mc_bank[i].mcb_status & BANK_INSTALLED) { + restart_patrol(mcp, i, NULL); + } + } + /* check error asap */ + mcp->mc_tid = timeout(mc_check_errors, mcp, 1); + } + mutex_exit(&mcp->mc_lock); + + return (DDI_SUCCESS); +} + +static mc_opl_t * +mc_pa_to_mcp(uint64_t pa) +{ + mc_inst_list_t *p; + ASSERT(MUTEX_HELD(&mcmutex)); + for (p = mc_instances; p; p = p->next) { + /* if mac patrol is suspended, we cannot rely on it */ + if (!(p->mc_opl->mc_status & MC_POLL_RUNNING) || + (p->mc_opl->mc_status & MC_SOFT_SUSPENDED)) + continue; + if ((p->mc_start_address <= pa) && + (pa < (p->mc_start_address + p->mc_size))) { + return (p->mc_opl); + } + } + return (NULL); +} + +/* + * Get Physical Board number from Logical one. + */ +static int +mc_opl_get_physical_board(int sb) +{ + if (&opl_get_physical_board) { + return (opl_get_physical_board(sb)); + } + + cmn_err(CE_NOTE, "!opl_get_physical_board() not loaded\n"); + return (-1); +} + +/* ARGSUSED */ +int +mc_get_mem_unum(int synd_code, uint64_t flt_addr, char *buf, int buflen, + int *lenp) +{ + mc_opl_t *mcp; + int bank; + int sb; + + mutex_enter(&mcmutex); + + if (((mcp = mc_pa_to_mcp(flt_addr)) == NULL) || + (!pa_is_valid(mcp, flt_addr))) { + mutex_exit(&mcmutex); + if (snprintf(buf, buflen, "UNKNOWN") >= buflen) { + return (ENOSPC); + } else { + if (lenp) + *lenp = strlen(buf); + } + return (0); + } + + bank = pa_to_bank(mcp, flt_addr - mcp->mc_start_address); + sb = mc_opl_get_physical_board(mcp->mc_board_num); + + if (sb == -1) { + mutex_exit(&mcmutex); + return (ENXIO); + } + + if (snprintf(buf, buflen, "/CMU%d/B%d", sb, bank) >= buflen) { + mutex_exit(&mcmutex); + return (ENOSPC); + } else { + if (lenp) + *lenp = strlen(buf); + } + mutex_exit(&mcmutex); + return (0); +} + +int +opl_mc_suspend() +{ + mc_opl_t *mcp; + mc_inst_list_t *p; + + mutex_enter(&mcmutex); + + for (p = mc_instances; p; p = p->next) { + mcp = p->mc_opl; + (void) mc_suspend(mcp, MC_SOFT_SUSPENDED); + } + + mutex_exit(&mcmutex); + return (0); +} + +int +opl_mc_resume() +{ + mc_opl_t *mcp; + mc_inst_list_t *p; + + mutex_enter(&mcmutex); + + for (p = mc_instances; p; p = p->next) { + mcp = p->mc_opl; + (void) mc_resume(mcp, MC_SOFT_SUSPENDED); + } + + mutex_exit(&mcmutex); + return (0); +} + +static void +insert_mcp(mc_opl_t *mcp) +{ + mc_inst_list_t *p; + + p = kmem_zalloc(sizeof (mc_inst_list_t), KM_SLEEP); + p->mc_opl = mcp; + p->mc_board_num = mcp->mc_board_num; + p->mc_start_address = mcp->mc_start_address; + p->mc_size = mcp->mc_size; + mcp->mc_list = p; + + mutex_enter(&mcmutex); + + p->next = mc_instances; + mc_instances = p; + + mutex_exit(&mcmutex); +} + +static void +delete_mcp(mc_opl_t *mcp) +{ + mc_inst_list_t *prev, *current; + mc_inst_list_t *p; + + p = mcp->mc_list; + + if (mc_instances == p) { + mc_instances = p->next; + kmem_free(p, sizeof (mc_inst_list_t)); + return; + } + prev = mc_instances; + for (current = mc_instances; current != NULL; current = current->next) { + if (current == p) { + prev->next = p->next; + kmem_free(p, sizeof (mc_inst_list_t)); + return; + } + prev = current; + } +} + +/* Error injection interface */ + +/* ARGSUSED */ +int +mc_inject_error(int error_type, uint64_t pa, uint32_t flags) +{ + mc_opl_t *mcp; + int bank; + uint32_t dimm_addr; + uint32_t cntl; + mc_addr_info_t maddr; + uint32_t data, stat; + int both_sides = 0; + uint64_t pa0; + on_trap_data_t otd; + extern void cpu_flush_ecache(void); + + MC_LOG("HW mc_inject_error(%x, %lx, %x)\n", error_type, pa, flags); + + mutex_enter(&mcmutex); + + if ((mcp = mc_pa_to_mcp(pa)) == NULL) { + mutex_exit(&mcmutex); + MC_LOG("mc_inject_error: invalid pa\n"); + return (ENOTSUP); + } + + mutex_enter(&mcp->mc_lock); + mutex_exit(&mcmutex); + + if (mcp->mc_status & (MC_SOFT_SUSPENDED | MC_DRIVER_SUSPENDED)) { + mutex_exit(&mcp->mc_lock); + MC_LOG("mc-opl has been suspended. No error injection.\n"); + return (EBUSY); + } + + /* convert pa to offset within the board */ + MC_LOG("pa %lx, offset %lx\n", pa, pa - mcp->mc_start_address); + + if (!pa_is_valid(mcp, pa)) { + mutex_exit(&mcp->mc_lock); + return (EINVAL); + } + + pa0 = pa - mcp->mc_start_address; + + bank = pa_to_bank(mcp, pa0); + + if (flags & MC_INJECT_FLAG_OTHER) + bank = bank ^ 1; + + if (MC_INJECT_MIRROR(error_type) && !IS_MIRROR(mcp, bank)) { + mutex_exit(&mcp->mc_lock); + MC_LOG("Not mirror mode\n"); + return (EINVAL); + } + + dimm_addr = pa_to_dimm(mcp, pa0); + + MC_LOG("injecting error to /LSB%d/B%d/D%x\n", + mcp->mc_board_num, bank, dimm_addr); + + + switch (error_type) { + case MC_INJECT_INTERMITTENT_MCE: + case MC_INJECT_PERMANENT_MCE: + case MC_INJECT_MUE: + both_sides = 1; + } + + if (flags & MC_INJECT_FLAG_RESET) + ST_MAC_REG(MAC_EG_CNTL(mcp, bank), 0); + + ST_MAC_REG(MAC_EG_ADD(mcp, bank), dimm_addr & MAC_EG_ADD_MASK); + + if (both_sides) { + ST_MAC_REG(MAC_EG_CNTL(mcp, bank^1), 0); + ST_MAC_REG(MAC_EG_ADD(mcp, bank^1), + dimm_addr & MAC_EG_ADD_MASK); + } + + switch (error_type) { + case MC_INJECT_UE: + case MC_INJECT_SUE: + case MC_INJECT_MUE: + if (flags & MC_INJECT_FLAG_PATH) { + cntl = MAC_EG_ADD_FIX + |MAC_EG_FORCE_READ00|MAC_EG_FORCE_READ16 + |MAC_EG_DERR_ONCE; + } else { + cntl = MAC_EG_ADD_FIX|MAC_EG_FORCE_DERR00 + |MAC_EG_FORCE_DERR16|MAC_EG_DERR_ONCE; + } + flags |= MC_INJECT_FLAG_ST; + break; + case MC_INJECT_INTERMITTENT_CE: + case MC_INJECT_INTERMITTENT_MCE: + if (flags & MC_INJECT_FLAG_PATH) { + cntl = MAC_EG_ADD_FIX + |MAC_EG_FORCE_READ00 + |MAC_EG_DERR_ONCE; + } else { + cntl = MAC_EG_ADD_FIX + |MAC_EG_FORCE_DERR16 + |MAC_EG_DERR_ONCE; + } + flags |= MC_INJECT_FLAG_ST; + break; + case MC_INJECT_PERMANENT_CE: + case MC_INJECT_PERMANENT_MCE: + if (flags & MC_INJECT_FLAG_PATH) { + cntl = MAC_EG_ADD_FIX + |MAC_EG_FORCE_READ00 + |MAC_EG_DERR_ALWAYS; + } else { + cntl = MAC_EG_ADD_FIX + |MAC_EG_FORCE_DERR16 + |MAC_EG_DERR_ALWAYS; + } + flags |= MC_INJECT_FLAG_ST; + break; + case MC_INJECT_CMPE: + data = 0xabcdefab; + stphys(pa, data); + cpu_flush_ecache(); + MC_LOG("CMPE: writing data %x to %lx\n", data, pa); + ST_MAC_REG(MAC_MIRR(mcp, bank), MAC_MIRR_BANK_EXCLUSIVE); + stphys(pa, data ^ 0xffffffff); + cpu_flush_ecache(); + ST_MAC_REG(MAC_MIRR(mcp, bank), 0); + MC_LOG("CMPE: write new data %xto %lx\n", data, pa); + cntl = 0; + break; + case MC_INJECT_NOP: + cntl = 0; + break; + default: + MC_LOG("mc_inject_error: invalid option\n"); + cntl = 0; + } + + if (cntl) { + ST_MAC_REG(MAC_EG_CNTL(mcp, bank), cntl & MAC_EG_SETUP_MASK); + ST_MAC_REG(MAC_EG_CNTL(mcp, bank), cntl); + + if (both_sides) { + ST_MAC_REG(MAC_EG_CNTL(mcp, bank^1), cntl & + MAC_EG_SETUP_MASK); + ST_MAC_REG(MAC_EG_CNTL(mcp, bank^1), cntl); + } + } + + /* + * For all injection cases except compare error, we + * must write to the PA to trigger the error. + */ + + if (flags & MC_INJECT_FLAG_ST) { + data = 0xf0e0d0c0; + MC_LOG("Writing %x to %lx\n", data, pa); + stphys(pa, data); + cpu_flush_ecache(); + } + + delay(inject_op_delay * drv_usectohz(1000 * 1000)); + + + if (flags & MC_INJECT_FLAG_LD) { + if (flags & MC_INJECT_FLAG_NO_TRAP) { + if (on_trap(&otd, OT_DATA_EC)) { + no_trap(); + MC_LOG("Trap occurred\n"); + } else { + MC_LOG("On-trap Reading from %lx\n", pa); + data = ldphys(pa); + no_trap(); + MC_LOG("data = %x\n", data); + } + } else { + MC_LOG("Reading from %lx\n", pa); + data = ldphys(pa); + MC_LOG("data = %x\n", data); + } + } + + if (flags & MC_INJECT_FLAG_RESTART) { + delay(inject_op_delay * drv_usectohz(1000 * 1000)); + + MC_LOG("Restart patrol\n"); + if (mc_stop(mcp, bank)) { + cmn_err(CE_WARN, "Cannot stop Memory Patrol at " + "/LSB%d/B%d\n", mcp->mc_board_num, bank); + mutex_exit(&mcp->mc_lock); + return (EIO); + } + maddr.mi_maddr.ma_bd = mcp->mc_board_num; + maddr.mi_maddr.ma_bank = bank; + maddr.mi_maddr.ma_dimm_addr = dimm_addr; + maddr.mi_valid = 1; + maddr.mi_advance = 0; + restart_patrol(mcp, bank, &maddr); + } + + if (flags & MC_INJECT_FLAG_POLL) { + delay(inject_op_delay * drv_usectohz(1000 * 1000)); + + MC_LOG("Poll patrol error\n"); + stat = LD_MAC_REG(MAC_PTRL_STAT(mcp, bank)); + cntl = LD_MAC_REG(MAC_PTRL_CNTL(mcp, bank)); + if (stat & (MAC_STAT_PTRL_ERRS|MAC_STAT_MI_ERRS)) { + maddr.mi_valid = 0; + maddr.mi_advance = 1; + if (IS_MIRROR(mcp, bank)) + mc_error_handler_mir(mcp, bank, + &maddr); + else + mc_error_handler(mcp, bank, &maddr); + + restart_patrol(mcp, bank, &maddr); + } else + restart_patrol(mcp, bank, NULL); + } + + mutex_exit(&mcp->mc_lock); + return (0); +} + +void +mc_stphysio(uint64_t pa, uint32_t data) +{ + MC_LOG("0x%x -> pa(%lx)\n", data, pa); + stphysio(pa, data); +} + +uint32_t +mc_ldphysio(uint64_t pa) +{ + uint32_t rv; + + rv = ldphysio(pa); + MC_LOG("pa(%lx) = 0x%x\n", pa, rv); + return (rv); +} diff --git a/usr/src/uts/sun4u/opl/io/mc-opl.conf b/usr/src/uts/sun4u/opl/io/mc-opl.conf new file mode 100644 index 0000000000..4b769e4928 --- /dev/null +++ b/usr/src/uts/sun4u/opl/io/mc-opl.conf @@ -0,0 +1,26 @@ +# +# 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 +# +# +# All Rights Reserved, Copyright (c) FUJITSU LIMITED 2006 +# +#pragma ident "%Z%%M% %I% %E% SMI" + +ddi-forceattach=1; diff --git a/usr/src/uts/sun4u/opl/io/oplkmdrv.c b/usr/src/uts/sun4u/opl/io/oplkmdrv.c new file mode 100644 index 0000000000..cf7d238c04 --- /dev/null +++ b/usr/src/uts/sun4u/opl/io/oplkmdrv.c @@ -0,0 +1,1107 @@ +/* + * 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" + +/* + * OPL IPSec Key Management Driver. + * + * This driver runs on a OPL Domain. It processes requests received + * from the OPL Service Processor (SP) via mailbox message. It passes + * these requests to the sckmd daemon by means of an /ioctl interface. + * + * Requests received from the SP consist of IPsec security associations + * (SAs) needed to secure the communication between SC and Domain daemons + * communicating using DSCP. + */ + +#include <sys/types.h> +#include <sys/cmn_err.h> +#include <sys/kmem.h> +#include <sys/errno.h> +#include <sys/file.h> +#include <sys/open.h> +#include <sys/stat.h> +#include <sys/conf.h> +#include <sys/ddi.h> +#include <sys/cmn_err.h> +#include <sys/sunddi.h> +#include <sys/sunndi.h> +#include <sys/ddi_impldefs.h> +#include <sys/ndi_impldefs.h> +#include <sys/modctl.h> +#include <sys/disp.h> +#include <sys/note.h> +#include <sys/byteorder.h> +#include <sys/sdt.h> + +#include <sys/scfd/scfdscpif.h> +#include <sys/oplkm_msg.h> +#include <sys/sckm_io.h> +#include <sys/oplkm.h> + +#define OKM_NODENAME "oplkmdrv" /* Node name */ +#define OKM_TARGET_ID 0 /* Target ID */ +#define OKM_SM_TOUT 5000 /* small timeout (5msec) */ +#define OKM_LG_TOUT 50000 /* large timeout (50msec) */ +#define OKM_MB_TOUT 10000000 /* Mailbox timeout (10sec) */ + +okms_t okms_global; /* Global instance structure */ + +#ifdef DEBUG +uint32_t okm_debug = DBG_WARN; +#endif + +/* + * Prototypes for the module related functions. + */ +int okm_attach(dev_info_t *devi, ddi_attach_cmd_t cmd); +int okm_detach(dev_info_t *devi, ddi_detach_cmd_t cmd); +int okm_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result); +int okm_open(dev_t *devp, int flag, int otyp, struct cred *cred); +int okm_close(dev_t dev, int flag, int otyp, struct cred *cred); +int okm_ioctl(dev_t dev, int cmd, intptr_t data, int flag, + cred_t *cred, int *rvalp); + +/* + * Prototypes for the internal functions. + */ +int okm_get_req(okms_t *okmsp, sckm_ioctl_getreq_t *ireqp, + intptr_t data, int flag); +int okm_process_req(okms_t *okmsp, okm_req_hdr_t *reqp, uint32_t len, + sckm_ioctl_getreq_t *ireqp, intptr_t data, int flag); +int okm_process_status(okms_t *okmsp, sckm_ioctl_status_t *ireply); +void okm_event_handler(scf_event_t event, void *arg); +int okm_send_reply(okms_t *okmsp, uint32_t transid, uint32_t status, + uint32_t sadb_err, uint32_t sadb_ver); +int block_until_ready(okms_t *okmsp); +static int okm_copyin_ioctl_getreq(intptr_t userarg, + sckm_ioctl_getreq_t *driverarg, int flag); +static int okm_copyout_ioctl_getreq(sckm_ioctl_getreq_t *driverarg, + intptr_t userarg, int flag); +static void okm_cleanup(okms_t *okmsp); +static int okm_mbox_init(okms_t *okmsp); +static void okm_mbox_fini(okms_t *okmsp); +static clock_t okm_timeout_val(int error); + + +struct cb_ops okm_cb_ops = { + okm_open, /* open */ + okm_close, /* close */ + nodev, /* strategy */ + nodev, /* print */ + nodev, /* dump */ + nodev, /* read */ + nodev, /* write */ + okm_ioctl, /* ioctl */ + nodev, /* devmap */ + nodev, /* mmap */ + nodev, /* segmap */ + nochpoll, /* poll */ + ddi_prop_op, /* prop_op */ + 0, /* streamtab */ + D_NEW | D_MP /* Driver compatibility flag */ +}; + +struct dev_ops okm_ops = { + DEVO_REV, /* devo_rev, */ + 0, /* refcnt */ + okm_info, /* get_dev_info */ + nulldev, /* identify */ + nulldev, /* probe */ + okm_attach, /* attach */ + okm_detach, /* detach */ + nodev, /* reset */ + &okm_cb_ops, /* driver operations */ + (struct bus_ops *)0 /* no bus operations */ +}; + +struct modldrv modldrv = { + &mod_driverops, + "OPL Key Management Driver v%I%", + &okm_ops, +}; + +struct modlinkage modlinkage = { + MODREV_1, + &modldrv, + NULL +}; + + +/* + * _init - Module's init routine. + */ +int +_init(void) +{ + int ret; + + if ((ret = mod_install(&modlinkage)) != 0) { + cmn_err(CE_WARN, "mod_install failed, error = %d", ret); + } + return (ret); +} + +/* + * _fini - Module's fini routine. + */ +int +_fini(void) +{ + int ret; + + if ((ret = mod_remove(&modlinkage)) != 0) { + return (ret); + } + return (ret); +} + +/* + * _info - Module's info routine. + */ +int +_info(struct modinfo *modinfop) +{ + return (mod_info(&modlinkage, modinfop)); +} + +/* + * okm_attach - Module's attach routine. + * + * Description: Initializes the modules state structure and create + * the minor device node. + */ +int +okm_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) +{ + int instance; + okms_t *okmsp = &okms_global; + + instance = ddi_get_instance(dip); + + /* Only one instance is supported. */ + if (instance != 0) { + return (DDI_FAILURE); + } + + if (cmd != DDI_ATTACH) { + return (DDI_FAILURE); + } + + okmsp->km_dip = dip; + okmsp->km_major = ddi_name_to_major(ddi_get_name(dip)); + okmsp->km_inst = instance; + + /* + * Get an interrupt block cookie corresponding to the + * interrupt priority of the event handler. + * Assert that the event priority is not redefined to + * some other priority. + */ + /* LINTED */ + ASSERT(SCF_EVENT_PRI == DDI_SOFTINT_LOW); + if (ddi_get_soft_iblock_cookie(dip, SCF_EVENT_PRI, + &okmsp->km_ibcookie) != DDI_SUCCESS) { + cmn_err(CE_WARN, "ddi_get_soft_iblock_cookie failed."); + return (DDI_FAILURE); + } + mutex_init(&okmsp->km_lock, NULL, MUTEX_DRIVER, + (void *)okmsp->km_ibcookie); + okmsp->km_clean |= OKM_CLEAN_LOCK; + cv_init(&okmsp->km_wait, NULL, CV_DRIVER, NULL); + okmsp->km_clean |= OKM_CLEAN_CV; + + /* + * set clean_node ahead as remove_node has to be called even + * if create node fails. + */ + okmsp->km_clean |= OKM_CLEAN_NODE; + if (ddi_create_minor_node(dip, OKM_NODENAME, S_IFCHR, + instance, NULL, NULL) == DDI_FAILURE) { + cmn_err(CE_WARN, "Device node creation failed"); + okm_cleanup(okmsp); + return (DDI_FAILURE); + } + + ddi_set_driver_private(dip, (caddr_t)okmsp); + ddi_report_dev(dip); + return (DDI_SUCCESS); +} + +/* + * okm_detach - Module's detach routine. + * + * Description: Cleans up the module's state structures and any other + * relevant data. + */ +int +okm_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) +{ + okms_t *okmsp; + + if (cmd != DDI_DETACH) { + return (DDI_FAILURE); + } + + if ((okmsp = ddi_get_driver_private(dip)) == NULL) { + return (DDI_FAILURE); + } + + mutex_enter(&okmsp->km_lock); + /* + * Check if the mailbox is still in use. + */ + if (okmsp->km_state & OKM_MB_INITED) { + mutex_exit(&okmsp->km_lock); + cmn_err(CE_WARN, "Detach failure: Mailbox in use"); + return (DDI_FAILURE); + } + mutex_exit(&okmsp->km_lock); + okm_cleanup(okmsp); + ddi_set_driver_private(dip, NULL); + return (DDI_SUCCESS); +} + +/* + * okm_info - Module's info routine. + */ +/* ARGSUSED */ +int +okm_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) +{ + okms_t *okmsp; + minor_t minor; + int ret = DDI_FAILURE; + + switch (infocmd) { + case DDI_INFO_DEVT2DEVINFO: + minor = getminor((dev_t)arg); + okmsp = ddi_get_driver_private(dip); + if (okmsp == NULL) { + *result = NULL; + } else { + *result = okmsp->km_dip; + ret = DDI_SUCCESS; + } + break; + + case DDI_INFO_DEVT2INSTANCE: + minor = getminor((dev_t)arg); + *result = (void *)(uintptr_t)minor; + ret = DDI_SUCCESS; + + default: + break; + } + return (ret); +} + +/* + * okm_open - Device open routine. + * + * Description: Initializes the mailbox and waits until the mailbox + * gets connected. Only one open at a time is supported. + */ +/*ARGSUSED*/ +int +okm_open(dev_t *devp, int flag, int otyp, struct cred *cred) +{ + okms_t *okmsp = &okms_global; + int ret = 0; + + DPRINTF(DBG_DRV, ("okm_open: called\n")); + mutex_enter(&okmsp->km_lock); + if (okmsp->km_state & OKM_OPENED) { + /* Only one open supported */ + mutex_exit(&okmsp->km_lock); + DPRINTF(DBG_WARN, ("okm_open: already opened\n")); + return (EBUSY); + } + okmsp->km_state |= OKM_OPENED; + ret = block_until_ready(okmsp); + if (ret != 0) { + okmsp->km_state &= ~OKM_OPENED; + } + mutex_exit(&okmsp->km_lock); + DPRINTF(DBG_DRV, ("okm_open: ret=%d\n", ret)); + return (ret); +} + +/* + * block_until_ready - Function to wait until the mailbox is ready to use. + * + * Description: It initializes the mailbox and waits for the mailbox + * state to transition to connected. + */ +int +block_until_ready(okms_t *okmsp) +{ + int ret = 0; + + DPRINTF(DBG_DRV, ("block_until_ready: called\n")); + ASSERT(MUTEX_HELD(&okmsp->km_lock)); + + if (okmsp->km_state & OKM_MB_DISC) { + DPRINTF(DBG_DRV, ("block_until_ready: closing the mailbox\n")); + okm_mbox_fini(okmsp); + } + if (okmsp->km_state & OKM_MB_CONN) { + DPRINTF(DBG_DRV, ("block_until_ready: mailbox connected\n")); + return (0); + } + /* + * Initialize mailbox. + */ + if ((ret = okm_mbox_init(okmsp)) != 0) { + DPRINTF(DBG_MBOX, + ("block_until_ready: mailbox init failed ret=%d\n", ret)); + return (ret); + } + DPRINTF(DBG_DRV, ("block_until_ready: ret=%d", ret)); + return (ret); +} + +/* + * okm_close - Device close routine. + * + * Description: Closes the mailbox. + */ +/*ARGSUSED*/ +int +okm_close(dev_t dev, int flag, int otyp, struct cred *cred) +{ + okms_t *okmsp = &okms_global; + + DPRINTF(DBG_DRV, ("okm_close: called\n")); + /* Close the lower layer first */ + mutex_enter(&okmsp->km_lock); + okm_mbox_fini(okmsp); + okmsp->km_state = 0; + mutex_exit(&okmsp->km_lock); + return (0); +} + + +/* + * okm_ioctl - Device ioctl routine. + * + * Description: Processes ioctls from the daemon. + */ +/*ARGSUSED*/ +int +okm_ioctl(dev_t dev, int cmd, intptr_t data, int flag, cred_t *cred, int *rvalp) +{ + okms_t *okmsp = &okms_global; + sckm_ioctl_getreq_t ireq; + sckm_ioctl_status_t istatus; + int ret = 0; + + switch (cmd) { + case SCKM_IOCTL_GETREQ: + + DPRINTF(DBG_DRV, ("okm_ioctl: GETREQ\n")); + if (okm_copyin_ioctl_getreq(data, &ireq, flag)) { + return (EFAULT); + } + + ret = okm_get_req(okmsp, &ireq, data, flag); + DPRINTF(DBG_DRV, ("okm_ioctl: GETREQ ret=%d\n", ret)); + break; + + case SCKM_IOCTL_STATUS: + + DPRINTF(DBG_DRV, ("okm_ioctl: STATUS\n")); + if (ddi_copyin((caddr_t)data, &istatus, + sizeof (sckm_ioctl_status_t), flag)) { + return (EFAULT); + } + ret = okm_process_status(okmsp, &istatus); + DPRINTF(DBG_DRV, ("okm_ioctl: STATUS ret=%d\n", ret)); + break; + + default: + DPRINTF(DBG_DRV, ("okm_ioctl: UNKNOWN ioctl\n")); + ret = EINVAL; + } + return (ret); +} + +/* + * okm_get_req - Get a request from the mailbox. + * + * Description: It blocks until a message is received, then processes + * the message and returns it to the requestor. + */ +int +okm_get_req(okms_t *okmsp, sckm_ioctl_getreq_t *ireqp, intptr_t data, int flag) +{ + okm_req_hdr_t *reqp; + caddr_t msgbuf; + uint32_t len; + int ret; + + DPRINTF(DBG_DRV, ("okm_getreq: called\n")); + mutex_enter(&okmsp->km_lock); + if ((ret = block_until_ready(okmsp)) != 0) { + mutex_exit(&okmsp->km_lock); + DPRINTF(DBG_WARN, ("okm_getreq: failed ret=%d\n", ret)); + return (ret); + } + + if (okmsp->km_reqp != NULL) { + DPRINTF(DBG_DRV, ("okm_getreq: req cached\n")); + reqp = okmsp->km_reqp; + len = okmsp->km_reqlen; + okmsp->km_reqp = NULL; + okmsp->km_reqlen = 0; + } else { +retry: + while (OKM_MBOX_READY(okmsp) && + ((ret = scf_mb_canget(okmsp->km_target, + okmsp->km_key, &len)) != 0)) { + if (ret != ENOMSG) { + DPRINTF(DBG_WARN, ("okm_getreq: Unknown " + "mbox failure=%d\n", ret)); + mutex_exit(&okmsp->km_lock); + return (EIO); + } + DPRINTF(DBG_MBOX, ("okm_getreq: waiting for mesg\n")); + if (cv_wait_sig(&okmsp->km_wait, + &okmsp->km_lock) <= 0) { + mutex_exit(&okmsp->km_lock); + DPRINTF(DBG_DRV, ("okm_getreq:interrupted\n")); + return (EINTR); + } + } + if (!OKM_MBOX_READY(okmsp)) { + mutex_exit(&okmsp->km_lock); + DPRINTF(DBG_WARN, ("okm_getreq: mailbox not ready\n")); + return (EIO); + } + ASSERT(len != 0); + msgbuf = kmem_alloc(len, KM_SLEEP); + okmsp->km_sg_rcv.msc_dptr = msgbuf; + okmsp->km_sg_rcv.msc_len = len; + + DPRINTF(DBG_MBOX, ("okm_getreq: getmsg\n")); + ret = scf_mb_getmsg(okmsp->km_target, okmsp->km_key, len, 1, + &okmsp->km_sg_rcv, 0); + if (ret == ENOMSG || ret == EMSGSIZE) { + kmem_free(msgbuf, len); + DPRINTF(DBG_MBOX, ("okm_getreq: nomsg ret=%d\n", ret)); + goto retry; + } else if (ret != 0) { + kmem_free(msgbuf, len); + mutex_exit(&okmsp->km_lock); + DPRINTF(DBG_WARN, + ("okm_getreq: Unknown mbox failure=%d\n", ret)); + return (EIO); + } + + /* check message length */ + if (len < sizeof (okm_req_hdr_t)) { + /* protocol error, drop message */ + kmem_free(msgbuf, len); + mutex_exit(&okmsp->km_lock); + DPRINTF(DBG_WARN, ("okm_getreq: Bad message\n")); + return (EBADMSG); + } + + reqp = (okm_req_hdr_t *)msgbuf; + reqp->krq_version = ntohl(reqp->krq_version); + reqp->krq_transid = ntohl(reqp->krq_transid); + reqp->krq_cmd = ntohl(reqp->krq_cmd); + reqp->krq_reserved = ntohl(reqp->krq_reserved); + + /* check version of the message received */ + if (reqp->krq_version != OKM_PROTOCOL_VERSION) { + okm_send_reply(okmsp, reqp->krq_transid, + OKM_ERR_VERSION, 0, 0); + kmem_free(msgbuf, len); + mutex_exit(&okmsp->km_lock); + DPRINTF(DBG_WARN, ("okm_getreq: Unknown version=%d\n", + reqp->krq_version)); + return (EBADMSG); + } + } + + /* process message */ + ret = okm_process_req(okmsp, reqp, len, ireqp, data, flag); + if (okmsp->km_reqp == NULL) { + /* + * The message is not saved, so free the buffer. + */ + kmem_free(reqp, len); + } + mutex_exit(&okmsp->km_lock); + DPRINTF(DBG_DRV, ("okm_getreq: ret=%d\n", ret)); + return (ret); +} + + +/* + * okm_process_req - Process the request. + * + * Description: Validate the request and then give the request to the + * daemon. + */ +int +okm_process_req(okms_t *okmsp, okm_req_hdr_t *reqp, uint32_t len, + sckm_ioctl_getreq_t *ireqp, intptr_t data, int flag) +{ + void *req_datap = (void *)(((char *)reqp) + sizeof (okm_req_hdr_t)); + int sadb_msglen = len - sizeof (okm_req_hdr_t); + + DPRINTF(DBG_DRV, ("okm_process_req: called\n")); + DUMP_REQ(reqp, len); + + switch (reqp->krq_cmd) { + case OKM_MSG_SADB: + /* sanity check request */ + if (sadb_msglen <= 0) { + okm_send_reply(okmsp, reqp->krq_transid, + OKM_ERR_SADB_MSG, 0, 0); + DPRINTF(DBG_WARN, ("okm_process_req: bad message\n")); + return (EBADMSG); + } + + /* + * Save the message, prior to giving it to the daemon. + */ + okmsp->km_reqp = reqp; + okmsp->km_reqlen = len; + + if (ireqp->buf_len < len) { + DPRINTF(DBG_WARN, + ("okm_process_req: not enough space\n")); + return (ENOSPC); + } + + ireqp->transid = reqp->krq_transid; + ireqp->type = SCKM_IOCTL_REQ_SADB; + if (ddi_copyout(req_datap, ireqp->buf, sadb_msglen, flag)) { + DPRINTF(DBG_WARN, + ("okm_process_req: copyout failed\n")); + return (EFAULT); + } + ireqp->buf_len = sadb_msglen; + if (okm_copyout_ioctl_getreq(ireqp, data, flag)) { + DPRINTF(DBG_WARN, + ("okm_process_req: copyout failed\n")); + return (EFAULT); + } + break; + + default: + cmn_err(CE_WARN, "Unknown cmd 0x%x received", reqp->krq_cmd); + /* + * Received an unknown command, send corresponding + * error message. + */ + okm_send_reply(okmsp, reqp->krq_transid, OKM_ERR_BAD_CMD, 0, 0); + return (EBADMSG); + } + DPRINTF(DBG_DRV, ("okm_process_req: ret=0\n")); + return (0); +} + +/* + * okm_process_status - Process the status from the daemon. + * + * Description: Processes the status received from the daemon and sends + * corresponding message to the SP. + */ +int +okm_process_status(okms_t *okmsp, sckm_ioctl_status_t *ireply) +{ + uint32_t status; + uint32_t sadb_msg_errno = 0; + uint32_t sadb_msg_version = 0; + okm_req_hdr_t *reqp = okmsp->km_reqp; + int ret; + + DPRINTF(DBG_DRV, ("okm_process_status: called\n")); + mutex_enter(&okmsp->km_lock); + if ((ret = block_until_ready(okmsp)) != 0) { + mutex_exit(&okmsp->km_lock); + DPRINTF(DBG_WARN, + ("okm_process_status: Unknown failure=%d\n", ret)); + return (ret); + } + + /* fail if no status is expected, or if it does not match */ + if (!okmsp->km_reqp || (reqp->krq_transid != ireply->transid)) { + mutex_exit(&okmsp->km_lock); + DPRINTF(DBG_WARN, + ("okm_process_status: req/transid mismatch\n")); + return (EINVAL); + } + + switch (ireply->status) { + case SCKM_IOCTL_STAT_SUCCESS: + DPRINTF(DBG_DRV, ("okm_process_status: SUCCESS\n")); + status = OKM_SUCCESS; + break; + case SCKM_IOCTL_STAT_ERR_PFKEY: + DPRINTF(DBG_DRV, ("okm_process_status: PFKEY ERROR\n")); + status = OKM_ERR_SADB_PFKEY; + sadb_msg_errno = ireply->sadb_msg_errno; + break; + case SCKM_IOCTL_STAT_ERR_REQ: + DPRINTF(DBG_DRV, ("okm_process_status: REQ ERROR\n")); + status = OKM_ERR_DAEMON; + break; + case SCKM_IOCTL_STAT_ERR_VERSION: + DPRINTF(DBG_DRV, ("okm_process_status: SADB VERSION ERROR\n")); + status = OKM_ERR_SADB_VERSION; + sadb_msg_version = ireply->sadb_msg_version; + break; + case SCKM_IOCTL_STAT_ERR_TIMEOUT: + DPRINTF(DBG_DRV, ("okm_process_status: TIMEOUT ERR\n")); + status = OKM_ERR_SADB_TIMEOUT; + break; + case SCKM_IOCTL_STAT_ERR_OTHER: + DPRINTF(DBG_DRV, ("okm_process_status: OTHER ERR\n")); + status = OKM_ERR_DAEMON; + break; + case SCKM_IOCTL_STAT_ERR_SADB_TYPE: + DPRINTF(DBG_DRV, ("okm_process_status: SADB TYPE ERR\n")); + status = OKM_ERR_SADB_BAD_TYPE; + break; + default: + cmn_err(CE_WARN, "SCKM daemon returned invalid status %d\n", + ireply->status); + status = OKM_ERR_DAEMON; + } + ret = okm_send_reply(okmsp, ireply->transid, status, + sadb_msg_errno, sadb_msg_version); + /* + * Clean up the cached request now. + */ + if (ret == 0) { + kmem_free(okmsp->km_reqp, okmsp->km_reqlen); + okmsp->km_reqp = NULL; + okmsp->km_reqlen = 0; + } + mutex_exit(&okmsp->km_lock); + DPRINTF(DBG_DRV, ("okm_process_status: ret=%d\n", ret)); + return (ret); +} + +/* + * okm_copyin_ioctl_getreq - copy-in the ioctl request from the daemon. + */ + +static int +okm_copyin_ioctl_getreq(intptr_t userarg, sckm_ioctl_getreq_t *driverarg, + int flag) +{ +#ifdef _MULTI_DATAMODEL + switch (ddi_model_convert_from(flag & FMODELS)) { + case DDI_MODEL_ILP32: { + sckm_ioctl_getreq32_t driverarg32; + if (ddi_copyin((caddr_t)userarg, &driverarg32, + sizeof (sckm_ioctl_getreq32_t), flag)) { + return (EFAULT); + } + driverarg->transid = driverarg32.transid; + driverarg->type = driverarg32.type; + driverarg->buf = (caddr_t)(uintptr_t)driverarg32.buf; + driverarg->buf_len = driverarg32.buf_len; + break; + } + case DDI_MODEL_NONE: { + if (ddi_copyin((caddr_t)userarg, &driverarg, + sizeof (sckm_ioctl_getreq_t), flag)) { + return (EFAULT); + } + break; + } + } +#else /* ! _MULTI_DATAMODEL */ + if (ddi_copyin((caddr_t)userarg, &driverarg, + sizeof (sckm_ioctl_getreq_t), flag)) { + return (EFAULT); + } +#endif /* _MULTI_DATAMODEL */ + return (0); +} + + +/* + * okm_copyout_ioctl_getreq - copy-out the request to the daemon. + */ +static int +okm_copyout_ioctl_getreq(sckm_ioctl_getreq_t *driverarg, intptr_t userarg, + int flag) +{ +#ifdef _MULTI_DATAMODEL + switch (ddi_model_convert_from(flag & FMODELS)) { + case DDI_MODEL_ILP32: { + sckm_ioctl_getreq32_t driverarg32; + driverarg32.transid = driverarg->transid; + driverarg32.type = driverarg->type; + driverarg32.buf = (caddr32_t)(uintptr_t)driverarg->buf; + driverarg32.buf_len = driverarg->buf_len; + if (ddi_copyout(&driverarg32, (caddr_t)userarg, + sizeof (sckm_ioctl_getreq32_t), flag)) { + return (EFAULT); + } + break; + } + case DDI_MODEL_NONE: + if (ddi_copyout(driverarg, (caddr_t)userarg, + sizeof (sckm_ioctl_getreq_t), flag)) { + return (EFAULT); + } + break; + } +#else /* ! _MULTI_DATAMODEL */ + if (ddi_copyout(driverarg, (caddr_t)userarg, + sizeof (sckm_ioctl_getreq_t), flag)) { + return (EFAULT); + } +#endif /* _MULTI_DATAMODEL */ + return (0); +} + +/* + * okm_cleanup - Cleanup routine. + */ +static void +okm_cleanup(okms_t *okmsp) +{ + + ASSERT(okmsp != NULL); + if (okmsp->km_clean & OKM_CLEAN_NODE) { + ddi_remove_minor_node(okmsp->km_dip, NULL); + } + if (okmsp->km_clean & OKM_CLEAN_LOCK) + mutex_destroy(&okmsp->km_lock); + if (okmsp->km_clean & OKM_CLEAN_CV) + cv_destroy(&okmsp->km_wait); + if (okmsp->km_reqp != NULL) { + kmem_free(okmsp->km_reqp, okmsp->km_reqlen); + okmsp->km_reqp = NULL; + okmsp->km_reqlen = 0; + } + ddi_set_driver_private(okmsp->km_dip, NULL); +} + +/* + * okm_mbox_init - Mailbox specific initialization. + */ +static int +okm_mbox_init(okms_t *okmsp) +{ + int ret; + clock_t tout; + + ASSERT(MUTEX_HELD(&okmsp->km_lock)); + okmsp->km_target = OKM_TARGET_ID; + okmsp->km_key = DKMD_KEY; + okmsp->km_state &= ~OKM_MB_INITED; + + /* Iterate until mailbox gets connected */ + while (!(okmsp->km_state & OKM_MB_CONN)) { + DPRINTF(DBG_MBOX, ("okm_mbox_init: calling mb_init\n")); + ret = scf_mb_init(okmsp->km_target, okmsp->km_key, + okm_event_handler, (void *)okmsp); + DPRINTF(DBG_MBOX, ("okm_mbox_init: mb_init ret=%d\n", ret)); + + if (ret == 0) { + okmsp->km_state |= OKM_MB_INITED; + + /* Block until the mailbox is ready to communicate. */ + while (!(okmsp->km_state & + (OKM_MB_CONN | OKM_MB_DISC))) { + + if (cv_wait_sig(&okmsp->km_wait, + &okmsp->km_lock) <= 0) { + /* interrupted */ + ret = EINTR; + break; + } + } + } + + if (ret != 0) { + + DPRINTF(DBG_MBOX, + ("okm_mbox_init: failed/interrupted\n")); + DTRACE_PROBE1(okm_mbox_fail, int, ret); + okmsp->km_state &= ~OKM_MB_INITED; + (void) scf_mb_fini(okmsp->km_target, okmsp->km_key); + + /* if interrupted, return immediately. */ + if (ret == EINTR) + return (ret); + + } + + if ((ret != 0) || (okmsp->km_state & OKM_MB_DISC)) { + + DPRINTF(DBG_WARN, + ("okm_mbox_init: mbox DISC_ERROR\n")); + DTRACE_PROBE1(okm_mbox_fail, int, OKM_MB_DISC); + okmsp->km_state &= ~OKM_MB_INITED; + (void) scf_mb_fini(okmsp->km_target, okmsp->km_key); + + /* + * If there was failure, then wait for + * OKM_MB_TOUT secs and retry again. + */ + + DPRINTF(DBG_MBOX, ("okm_mbox_init: waiting...\n")); + tout = ddi_get_lbolt() + drv_usectohz(OKM_MB_TOUT); + ret = cv_timedwait_sig(&okmsp->km_wait, + &okmsp->km_lock, tout); + if (ret == 0) { + /* if interrupted, return immediately. */ + DPRINTF(DBG_MBOX, + ("okm_mbox_init: interrupted\n")); + return (EINTR); + } + } + } + + ret = scf_mb_ctrl(okmsp->km_target, okmsp->km_key, + SCF_MBOP_MAXMSGSIZE, &okmsp->km_maxsz); + + /* + * The max msg size should be at least the size of reply + * we need to send. + */ + if ((ret == 0) && (okmsp->km_maxsz < sizeof (okm_rep_hdr_t))) { + cmn_err(CE_WARN, "Max message size expected >= %ld " + "but found %d\n", sizeof (okm_rep_hdr_t), okmsp->km_maxsz); + ret = EIO; + } + if (ret != 0) { + okmsp->km_state &= ~OKM_MB_INITED; + (void) scf_mb_fini(okmsp->km_target, okmsp->km_key); + } + DPRINTF(DBG_MBOX, ("okm_mbox_init: mb_init ret=%d\n", ret)); + return (ret); +} + +/* + * okm_mbox_fini - Mailbox de-initialization. + */ +static void +okm_mbox_fini(okms_t *okmsp) +{ + int ret = 0; + + ASSERT(MUTEX_HELD(&okmsp->km_lock)); + if (okmsp->km_state & OKM_MB_INITED) { + DPRINTF(DBG_MBOX, ("okm_mbox_fini: calling mb_fini\n")); + ret = scf_mb_fini(okmsp->km_target, okmsp->km_key); + DPRINTF(DBG_MBOX, ("okm_mbox_fini: mb_fini ret=%d\n", ret)); + if (ret != 0) { + cmn_err(CE_WARN, + "Failed to close the Mailbox error=%d", ret); + } + okmsp->km_state &= ~(OKM_MB_INITED | OKM_MB_CONN | OKM_MB_DISC); + } +} + +/* + * okm_event_handler - Mailbox event handler. + * + * Description: Implements a state machine to handle all the mailbox + * events. For each event, it sets the appropriate state + * flag and wakes up the threads waiting for that event. + */ +void +okm_event_handler(scf_event_t event, void *arg) +{ + okms_t *okmsp = (okms_t *)arg; + + DPRINTF(DBG_MBOX, ("okm_event_handler: called\n")); + ASSERT(okmsp != NULL); + mutex_enter(&okmsp->km_lock); + if (!(okmsp->km_state & OKM_MB_INITED)) { + /* + * Ignore all events if the state flag indicates that the + * mailbox not initialized, this may happen during the close. + */ + mutex_exit(&okmsp->km_lock); + DPRINTF(DBG_MBOX, + ("okm_event_handler: event=0x%X - mailbox not inited \n", + event)); + return; + } + switch (event) { + case SCF_MB_CONN_OK: + DPRINTF(DBG_MBOX, ("okm_event_handler: Event CONN_OK\n")); + /* + * Now the mailbox is ready to use, lets wake up + * any one waiting for this event. + */ + okmsp->km_state |= OKM_MB_CONN; + cv_broadcast(&okmsp->km_wait); + break; + + case SCF_MB_MSG_DATA: + DPRINTF(DBG_MBOX, ("okm_event_handler: Event MSG_DATA\n")); + /* + * A message is available in the mailbox, + * wakeup if any one is ready to read the message. + */ + if (OKM_MBOX_READY(okmsp)) { + cv_broadcast(&okmsp->km_wait); + } + break; + + case SCF_MB_SPACE: + DPRINTF(DBG_MBOX, ("okm_event_handler: Event MB_SPACE\n")); + /* + * Now the mailbox is ready to transmit, lets + * wakeup if any one is waiting to write. + */ + if (OKM_MBOX_READY(okmsp)) { + cv_broadcast(&okmsp->km_wait); + } + break; + case SCF_MB_DISC_ERROR: + DPRINTF(DBG_MBOX, ("okm_event_handler: Event DISC_ERROR\n")); + okmsp->km_state &= ~OKM_MB_CONN; + okmsp->km_state |= OKM_MB_DISC; + cv_broadcast(&okmsp->km_wait); + break; + default: + cmn_err(CE_WARN, "Unexpected event received\n"); + } + mutex_exit(&okmsp->km_lock); +} + +/* + * okm_send_reply - Send a mailbox reply message. + */ +int +okm_send_reply(okms_t *okmsp, uint32_t transid, + uint32_t status, uint32_t sadb_err, uint32_t sadb_ver) +{ + okm_rep_hdr_t reply; + int ret = EIO; + + DPRINTF(DBG_DRV, ("okm_send_reply: called\n")); + ASSERT(MUTEX_HELD(&okmsp->km_lock)); + reply.krp_version = htonl(OKM_PROTOCOL_VERSION); + reply.krp_transid = htonl(transid); + reply.krp_status = htonl(status); + reply.krp_sadb_errno = htonl(sadb_err); + reply.krp_sadb_version = htonl(sadb_ver); + okmsp->km_sg_tx.msc_dptr = (caddr_t)&reply; + okmsp->km_sg_tx.msc_len = sizeof (reply); + DUMP_REPLY(&reply); + + while (OKM_MBOX_READY(okmsp)) { + DPRINTF(DBG_MBOX, ("okm_send_reply: sending reply\n")); + ret = scf_mb_putmsg(okmsp->km_target, okmsp->km_key, + sizeof (reply), 1, &okmsp->km_sg_tx, 0); + DPRINTF(DBG_MBOX, ("okm_send_reply: putmsg ret=%d\n", ret)); + if (ret == EBUSY || ret == ENOSPC) { + /* mailbox is busy, poll/retry */ + if (cv_timedwait_sig(&okmsp->km_wait, + &okmsp->km_lock, okm_timeout_val(ret)) == 0) { + /* interrupted */ + ret = EINTR; + DPRINTF(DBG_DRV, + ("okm_send_reply: interrupted\n")); + break; + } + } else { + break; + } + } + DPRINTF(DBG_DRV, ("okm_send_reply: ret=%d\n", ret)); + return (ret); +} + +/* + * okm_timeout_val -- Return appropriate timeout value. + * + * A small timeout value is returned for EBUSY as the mailbox busy + * condition may go away sooner and we are expected to poll. + * + * A larger timeout value is returned for ENOSPC case, as the condition + * depends on the peer to release buffer space. + * NOTE: there will also be an event(SCF_MB_SPACE) but a timeout is + * used for reliability purposes. + */ +static clock_t +okm_timeout_val(int error) +{ + clock_t tval; + + ASSERT(error == EBUSY || error == ENOSPC); + + if (error == EBUSY) { + tval = OKM_SM_TOUT; + } else { + tval = OKM_LG_TOUT; + } + return (drv_usectohz(tval)); +} + +#ifdef DEBUG +static void +okm_print_req(okm_req_hdr_t *reqp, uint32_t len) +{ + uint8_t *datap = (uint8_t *)(((char *)reqp) + sizeof (okm_req_hdr_t)); + int msglen = len - sizeof (okm_req_hdr_t); + int i, j; +#define BYTES_PER_LINE 20 + char bytestr[BYTES_PER_LINE * 3 + 1]; + + if (!(okm_debug & DBG_MESG)) + return; + printf("OKM: Request ver=%d transid=%d cmd=%s\n", + reqp->krq_version, reqp->krq_transid, + ((reqp->krq_cmd == OKM_MSG_SADB) ? "MSG_SADB" : "UNKNOWN")); + for (i = 0; i < msglen; ) { + for (j = 0; (j < BYTES_PER_LINE) && (i < msglen); j++, i++) { + sprintf(&bytestr[j * 3], "%02X ", datap[i]); + } + if (j != 0) { + printf("\t%s\n", bytestr); + } + } +} + +static void +okm_print_rep(okm_rep_hdr_t *repp) +{ + if (!(okm_debug & DBG_MESG)) + return; + printf("OKM: Reply Ver=%d Transid=%d Status=%d ", + repp->krp_version, repp->krp_transid, repp->krp_status); + printf("Sadb_errno=%d Sadb_ver=%d\n", repp->krp_sadb_errno, + repp->krp_sadb_version); +} +#endif diff --git a/usr/src/uts/sun4u/opl/io/oplkmdrv.conf b/usr/src/uts/sun4u/opl/io/oplkmdrv.conf new file mode 100644 index 0000000000..20e8f7773d --- /dev/null +++ b/usr/src/uts/sun4u/opl/io/oplkmdrv.conf @@ -0,0 +1,28 @@ +# +# 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" + +name="oplkmdrv" parent="pseudo" instance=0; diff --git a/usr/src/uts/sun4u/opl/io/oplmsu/oplmsu.c b/usr/src/uts/sun4u/opl/io/oplmsu/oplmsu.c new file mode 100644 index 0000000000..b947a22da9 --- /dev/null +++ b/usr/src/uts/sun4u/opl/io/oplmsu/oplmsu.c @@ -0,0 +1,2471 @@ +/* + * 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 + */ +/* + * All Rights Reserved, Copyright (c) FUJITSU LIMITED 2006 + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/errno.h> +#include <sys/modctl.h> +#include <sys/stat.h> +#include <sys/kmem.h> +#include <sys/ksynch.h> +#include <sys/stream.h> +#include <sys/stropts.h> +#include <sys/termio.h> +#include <sys/ddi.h> +#include <sys/file.h> +#include <sys/disp.h> +#include <sys/sunddi.h> +#include <sys/sunldi.h> +#include <sys/sunndi.h> +#include <sys/kbio.h> +#include <sys/prom_plat.h> +#include <sys/oplmsu/oplmsu.h> +#include <sys/oplmsu/oplmsu_proto.h> + +extern int ddi_create_internal_pathname(dev_info_t *, char *, int, minor_t); + +#define MOD_ID 0xe145 +#define MOD_NAME "oplmsu" + +#define META_NAME "oplmsu" +#define USER_NAME "a" + +struct module_info oplmsu_mod_info = { + MOD_ID, + MOD_NAME, + 0, + 16384, + 14336, + 2048 +}; + +struct qinit oplmsu_urinit = { + NULL, + oplmsu_ursrv, + oplmsu_open, + oplmsu_close, + NULL, + &oplmsu_mod_info, + NULL +}; + +struct qinit oplmsu_uwinit = { + oplmsu_uwput, + oplmsu_uwsrv, + oplmsu_open, + oplmsu_close, + NULL, + &oplmsu_mod_info, + NULL +}; + +struct qinit oplmsu_lrinit = { + oplmsu_lrput, + oplmsu_lrsrv, + oplmsu_open, + oplmsu_close, + NULL, + &oplmsu_mod_info, + NULL +}; + +struct qinit oplmsu_lwinit = { + NULL, + oplmsu_lwsrv, + oplmsu_open, + oplmsu_close, + NULL, + &oplmsu_mod_info, + NULL +}; + +struct streamtab oplmsu_info = { + &oplmsu_urinit, + &oplmsu_uwinit, + &oplmsu_lrinit, + &oplmsu_lwinit +}; + +static struct cb_ops cb_oplmsu_ops = { + nulldev, /* cb_open */ + nulldev, /* cb_close */ + nodev, /* cb_strategy */ + nodev, /* cb_print */ + nodev, /* cb_dump */ + nodev, /* cb_read */ + nodev, /* cb_write */ + nodev, /* cb_ioctl */ + nodev, /* cb_devmap */ + nodev, /* cb_mmap */ + nodev, /* cb_segmap */ + nochpoll, /* cb_chpoll */ + ddi_prop_op, /* cb_prop_op */ + (&oplmsu_info), /* cb_stream */ + (int)(D_NEW|D_MP|D_HOTPLUG) /* cb_flag */ +}; + +static struct dev_ops oplmsu_ops = { + DEVO_REV, /* devo_rev */ + 0, /* devo_refcnt */ + (oplmsu_getinfo), /* devo_getinfo */ + (nulldev), /* devo_identify */ + (nulldev), /* devo_probe */ + (oplmsu_attach), /* devo_attach */ + (oplmsu_detach), /* devo_detach */ + (nodev), /* devo_reset */ + &(cb_oplmsu_ops), /* devo_cb_ops */ + (struct bus_ops *)NULL, /* devo_bus_ops */ + NULL /* devo_power */ +}; + +struct modldrv modldrv = { + &mod_driverops, + "OPL serial mux driver %I%", + &oplmsu_ops +}; + +struct modlinkage modlinkage = { + MODREV_1, + (void *)&modldrv, + NULL +}; + +uinst_t oplmsu_uinst_local; /* upper_instance_table structure */ +uinst_t *oplmsu_uinst = &oplmsu_uinst_local; +int oplmsu_queue_flag; /* Enable/disable queueing flag */ +int oplmsu_check_su; /* Check super-user flag */ + +#ifdef DEBUG +int oplmsu_debug_mode = 0; /* Enable/disable debug mode */ +int oplmsu_trace_on; /* Enable/disable trace */ +uint_t oplmsu_ltrc_size; /* Trace buffer size */ +msu_trc_t *oplmsu_ltrc_top; /* Top of trace data area */ +msu_trc_t *oplmsu_ltrc_tail; /* Tail of trace data area */ +msu_trc_t *oplmsu_ltrc_cur; /* Current pointer of trace data area */ +ulong_t oplmsu_ltrc_ccnt; /* Current counter */ +kmutex_t oplmsu_ltrc_lock; /* Lock table for trace mode */ +#endif + +/* oplmsu_conf_st */ +#define MSU_CONFIGURED 2 +#define MSU_CONFIGURING 1 +#define MSU_UNCONFIGURED 0 + +static kmutex_t oplmsu_bthrd_excl; +static kthread_id_t oplmsu_bthrd_id = NULL; +static int oplmsu_conf_st = MSU_UNCONFIGURED; +static kcondvar_t oplmsu_conf_cv; + + +/* + * Locking hierarcy of oplmsu driver. This driver have 5 locks in uinst_t. + * + * Each mutex guards as follows. + * + * uinst_t->lock: This mutex is read/write mutex. + * read lock : acquired if the member of uinst_t is refered only. + * write lock: acquired if the member of uinst_t is changed. + * + * uinst_t->u_lock: This mutex is normal mutex. + * This mutex is acquired at reading/changing the member of all upath_t. + * + * uinst_t->l_lock: This mutex is normal mutex. + * This mutex is acquired at reading/changing the member of all lpath_t. + * + * uinst_t->c_lock: This mutex is normal mutex. + * This mutex is acquired at reading/changing the member of the ctrl_t. + * + * oplmsu_bthrd_excl: This mutex is normal mutex. + * This mutex is used only to start/stop the configuring thread of the + * multiplexed STREAMS. + * This mutex is exclusively acquired with the above-mentioned 4 mutexes. + * + * To guard of the deadlock by cross locking, the base locking hierarcy + * is as follows: + * + * uisnt->lock ==> uinst->u_lock ==> uinst->l_lock ==> uinst->c_lock + * + */ + + +int +_init(void) +{ + int rval; + + /* Initialize R/W lock for uinst_t */ + rw_init(&oplmsu_uinst->lock, "uinst rwlock", RW_DRIVER, NULL); + + /* Initialize mutex for upath_t */ + mutex_init(&oplmsu_uinst->u_lock, "upath lock", MUTEX_DRIVER, NULL); + + /* Initialize mutex for lpath_t */ + mutex_init(&oplmsu_uinst->l_lock, "lpath lock", MUTEX_DRIVER, NULL); + + /* Initialize mutex for ctrl_t */ + mutex_init(&oplmsu_uinst->c_lock, "ctrl lock", MUTEX_DRIVER, NULL); + + /* Initialize mutex for protecting background thread */ + mutex_init(&oplmsu_bthrd_excl, NULL, MUTEX_DRIVER, NULL); + + /* Initialize condition variable */ + cv_init(&oplmsu_conf_cv, NULL, CV_DRIVER, NULL); + + rval = mod_install(&modlinkage); + if (rval != DDI_SUCCESS) { + cv_destroy(&oplmsu_conf_cv); + mutex_destroy(&oplmsu_bthrd_excl); + mutex_destroy(&oplmsu_uinst->c_lock); + mutex_destroy(&oplmsu_uinst->l_lock); + mutex_destroy(&oplmsu_uinst->u_lock); + rw_destroy(&oplmsu_uinst->lock); + } + return (rval); +} + +int +_fini(void) +{ + int rval; + + rval = mod_remove(&modlinkage); + if (rval == DDI_SUCCESS) { + cv_destroy(&oplmsu_conf_cv); + mutex_destroy(&oplmsu_bthrd_excl); + mutex_destroy(&oplmsu_uinst->c_lock); + mutex_destroy(&oplmsu_uinst->l_lock); + mutex_destroy(&oplmsu_uinst->u_lock); + rw_destroy(&oplmsu_uinst->lock); + } + return (rval); +} + +int +_info(struct modinfo *modinfop) +{ + return (mod_info(&modlinkage, modinfop)); +} + +/* ARGSUSED */ +int +oplmsu_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp) +{ + dev_t dev = (dev_t)arg; + minor_t inst; + int rval = DDI_SUCCESS; + + switch (cmd) { + case DDI_INFO_DEVT2DEVINFO : + if (oplmsu_uinst->msu_dip == NULL) { + rval = DDI_FAILURE; + } else { + *resultp = oplmsu_uinst->msu_dip; + } + break; + + case DDI_INFO_DEVT2INSTANCE : + inst = getminor(dev) & ~(META_NODE_MASK|USER_NODE_MASK); + *resultp = (void *)(uintptr_t)inst; + break; + + default : + rval = DDI_FAILURE; + break; + } + return (rval); +} + +int +oplmsu_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) +{ + minor_t meta_minor, user_minor; + int rval = 0; + int instance; +#define CNTRL(c) ((c) & 037) + char abt_ch_seq[3] = { '\r', '~', CNTRL('b') }; + + if (cmd == DDI_RESUME) { + return (DDI_SUCCESS); + } + + if (cmd != DDI_ATTACH) { + return (DDI_FAILURE); + } + + instance = ddi_get_instance(dip); + if (instance != 0) { + cmn_err(CE_WARN, "oplmsu: attach: " + "Invaild instance => %d", instance); + return (DDI_FAILURE); + } + + /* Create minor number for meta control node */ + meta_minor = instance | META_NODE_MASK; + /* Create minor number for user access node */ + user_minor = instance | USER_NODE_MASK; + + /* Create minor node for user access */ + rval = ddi_create_minor_node(dip, USER_NAME, S_IFCHR, user_minor, + DDI_NT_SERIAL, 0); + if (rval != DDI_SUCCESS) { + cmn_err(CE_WARN, "oplmsu: attach: " + "ddi_create_minor_node failed. errno = %d", rval); + ddi_remove_minor_node(dip, NULL); + return (rval); + } + + /* Create minor node for meta control */ + rval = ddi_create_internal_pathname(dip, META_NAME, S_IFCHR, + meta_minor); + if (rval != DDI_SUCCESS) { + cmn_err(CE_WARN, "oplmsu: attach: " + "ddi_create_internal_pathname failed. errno = %d", rval); + ddi_remove_minor_node(dip, NULL); + return (rval); + } + + rw_enter(&oplmsu_uinst->lock, RW_WRITER); + + /* Get each properties */ + oplmsu_check_su = ddi_prop_get_int(DDI_DEV_T_ANY, dip, + (DDI_PROP_DONTPASS|DDI_PROP_NOTPROM), "check-superuser", 1); + + /* + * Initialize members of uinst_t + */ + + oplmsu_uinst->inst_status = INST_STAT_UNCONFIGURED; + oplmsu_uinst->path_num = UNDEFINED; + oplmsu_uinst->msu_dip = dip; + (void) strcpy(oplmsu_uinst->abts, abt_ch_seq); + +#ifdef DEBUG + oplmsu_trace_on = ddi_prop_get_int(DDI_DEV_T_ANY, dip, + (DDI_PROP_DONTPASS|DDI_PROP_NOTPROM), "trace-mode", 1); + oplmsu_ltrc_size = (uint_t)ddi_prop_get_int(DDI_DEV_T_ANY, dip, + (DDI_PROP_DONTPASS|DDI_PROP_NOTPROM), "trace-bufsize", 128); + + if (oplmsu_trace_on == MSU_TRACE_ON) { + /* Initialize mutex for msu_trc_t */ + mutex_init(&oplmsu_ltrc_lock, "trc lock", MUTEX_DRIVER, NULL); + + mutex_enter(&oplmsu_ltrc_lock); + oplmsu_ltrc_top = (msu_trc_t *)kmem_zalloc( + (sizeof (msu_trc_t) * oplmsu_ltrc_size), KM_SLEEP); + oplmsu_ltrc_cur = (msu_trc_t *)(oplmsu_ltrc_top - 1); + oplmsu_ltrc_tail = + (msu_trc_t *)(oplmsu_ltrc_top + (oplmsu_ltrc_size - 1)); + mutex_exit(&oplmsu_ltrc_lock); + } +#endif + rw_exit(&oplmsu_uinst->lock); + ddi_report_dev(dip); + return (rval); +} + +int +oplmsu_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) +{ + lpath_t *lpath, *next_lpath; + + if (cmd == DDI_SUSPEND) { + return (DDI_SUCCESS); + } + + if (cmd != DDI_DETACH) { + return (DDI_FAILURE); + } + + rw_enter(&oplmsu_uinst->lock, RW_WRITER); + + /* Delete all upath_t */ + oplmsu_delete_upath_info(); + + /* Delete all lpath_t */ + mutex_enter(&oplmsu_uinst->l_lock); + lpath = oplmsu_uinst->first_lpath; + oplmsu_uinst->first_lpath = NULL; + oplmsu_uinst->last_lpath = NULL; + mutex_exit(&oplmsu_uinst->l_lock); + +#ifdef DEBUG + if (oplmsu_trace_on == MSU_TRACE_ON) { + mutex_enter(&oplmsu_ltrc_lock); + if (oplmsu_ltrc_top != NULL) { + kmem_free(oplmsu_ltrc_top, + (sizeof (msu_trc_t) * oplmsu_ltrc_size)); + } + oplmsu_ltrc_top = NULL; + oplmsu_ltrc_cur = NULL; + oplmsu_ltrc_tail = NULL; + mutex_exit(&oplmsu_ltrc_lock); + + mutex_destroy(&oplmsu_ltrc_lock); + } +#endif + rw_exit(&oplmsu_uinst->lock); + + while (lpath) { + if (lpath->rbuf_id) { + unbufcall(lpath->rbuf_id); + } + + if (lpath->rtout_id) { + untimeout(lpath->rtout_id); + } + + if (lpath->rbuftbl) { + kmem_free(lpath->rbuftbl, sizeof (struct buf_tbl)); + } + + cv_destroy(&lpath->sw_cv); + next_lpath = lpath->l_next; + kmem_free(lpath, sizeof (lpath_t)); + lpath = next_lpath; + } + ddi_remove_minor_node(dip, NULL); + return (DDI_SUCCESS); +} + +/* ARGSUSED */ +int +oplmsu_open(queue_t *urq, dev_t *dev, int oflag, int sflag, cred_t *cred_p) +{ + ctrl_t *ctrl; + minor_t mindev = 0; + minor_t qmindev = 0; + major_t majdev; + ulong_t node_flag; + + DBG_PRINT((CE_NOTE, "oplmsu: open: " + "devt = 0x%lx, sflag = 0x%x", *dev, sflag)); + + if (sflag == CLONEOPEN) { + return (EINVAL); + } + + /* Get minor device number */ + qmindev = (minor_t)getminor(*dev); + /* Get node type */ + node_flag = MSU_NODE_TYPE(qmindev); + if ((node_flag != MSU_NODE_USER) && (node_flag != MSU_NODE_META)) { + return (EINVAL); + } + + mutex_enter(&oplmsu_bthrd_excl); + if ((node_flag == MSU_NODE_USER) && + (oplmsu_conf_st != MSU_CONFIGURED)) { /* User access & First open */ + int cv_rval; + + DBG_PRINT((CE_NOTE, "oplmsu: open: " + "oplmsu_conf_st = %x", oplmsu_conf_st)); + + if (oplmsu_conf_st == MSU_UNCONFIGURED) { + oplmsu_conf_st = MSU_CONFIGURING; + + /* Start up background thread */ + oplmsu_bthrd_id = thread_create(NULL, 2 * DEFAULTSTKSZ, + oplmsu_setup, (void *)oplmsu_uinst, 0, &p0, TS_RUN, + minclsyspri); + } + + /* + * Wait with cv_wait_sig() until background thread is + * completed. + */ + while (oplmsu_conf_st == MSU_CONFIGURING) { + cv_rval = + cv_wait_sig(&oplmsu_conf_cv, &oplmsu_bthrd_excl); + if (cv_rval == 0) { + mutex_exit(&oplmsu_bthrd_excl); + return (EINTR); + } + } + } + mutex_exit(&oplmsu_bthrd_excl); + + rw_enter(&oplmsu_uinst->lock, RW_WRITER); + + /* + * If the node which will open is meta-control-node or + * user-access-node, and q_ptr, this is queue_t queue + * table member, is not NULL, then oplmsu returns + * SUCCESS immidiately. + * This process is used to protect dual open. + */ + + if ((urq != NULL) && (urq->q_ptr != NULL)) { + rw_exit(&oplmsu_uinst->lock); + return (SUCCESS); + } + + /* + * If the node which will open is User-Access-Node, and instance + * status of oplmsu is no ONLINE, then oplmsu_open process fails + * with return value 'EIO'. + */ + + if ((node_flag == MSU_NODE_USER) && + (oplmsu_uinst->inst_status != INST_STAT_ONLINE)) { + rw_exit(&oplmsu_uinst->lock); + return (EIO); + } + + mindev |= qmindev; /* Create minor device number */ + majdev = getmajor(*dev); /* Get major device number */ + *dev = makedevice(majdev, mindev); /* Make device number */ + + /* Allocate kernel memory for ctrl_t */ + ctrl = (ctrl_t *)kmem_zalloc(sizeof (ctrl_t), KM_SLEEP); + + /* + * Initialize members of ctrl_t + */ + ctrl->minor = (minor_t)mindev; + ctrl->queue = urq; + ctrl->sleep_flag = CV_WAKEUP; + ctrl->node_type = node_flag; + ctrl->wbuftbl = + (struct buf_tbl *)kmem_zalloc(sizeof (struct buf_tbl), KM_SLEEP); + cv_init(&ctrl->cvp, "oplmsu ctrl_tbl condvar", CV_DRIVER, NULL); + + mutex_enter(&oplmsu_uinst->c_lock); + + if (node_flag == MSU_NODE_USER) { /* User access node */ + + oplmsu_uinst->user_ctrl = ctrl; + oplmsu_queue_flag = 0; + + } else { /* Meta control node */ + + oplmsu_uinst->meta_ctrl = ctrl; + } + + RD(urq)->q_ptr = ctrl; + WR(urq)->q_ptr = ctrl; + + mutex_exit(&oplmsu_uinst->c_lock); + rw_exit(&oplmsu_uinst->lock); + + OPLMSU_TRACE(urq, (mblk_t *)node_flag, MSU_TRC_OPN); + + qprocson(urq); /* Enable put and service routine */ + return (SUCCESS); +} + +/* ARGSUSED */ +int +oplmsu_close(queue_t *urq, int flag, cred_t *cred_p) +{ + ctrl_t *ctrl; + minor_t qmindev = 0; + lpath_t *lpath; + ulong_t node_flag; + bufcall_id_t wbuf_id; + timeout_id_t wtout_id; + + rw_enter(&oplmsu_uinst->lock, RW_READER); + mutex_enter(&oplmsu_uinst->l_lock); + mutex_enter(&oplmsu_uinst->c_lock); + if ((ctrl = urq->q_ptr) == NULL) { + mutex_exit(&oplmsu_uinst->c_lock); + mutex_exit(&oplmsu_uinst->l_lock); + rw_exit(&oplmsu_uinst->lock); + + DBG_PRINT((CE_NOTE, "oplmsu: close: " + "close has already been completed")); + return (FAILURE); + } + qmindev = ctrl->minor; + + DBG_PRINT((CE_NOTE, "oplmsu: close: ctrl->minor = 0x%x", qmindev)); + + node_flag = MSU_NODE_TYPE(qmindev); + if (node_flag > MSU_NODE_META) { + mutex_exit(&oplmsu_uinst->c_lock); + mutex_exit(&oplmsu_uinst->l_lock); + rw_exit(&oplmsu_uinst->lock); + return (EINVAL); + } + + /* + * Check that queue which is waiting for response from lower stream + * exist. If queue exists, oplmsu sets CV_SLEEP to sleep_flag. + */ + + for (lpath = oplmsu_uinst->first_lpath; lpath; ) { + if (((RD(urq) == lpath->hndl_uqueue) || + (WR(urq) == lpath->hndl_uqueue)) && + (lpath->hndl_mp != NULL)) { + ctrl->sleep_flag = CV_SLEEP; + break; + } + + lpath = lpath->l_next; + } + mutex_exit(&oplmsu_uinst->l_lock); + rw_exit(&oplmsu_uinst->lock); + + /* If sleep_flag is not CV_SLEEP, oplmsu calls cv_wait. */ + if (lpath) { + while (ctrl->sleep_flag != CV_WAKEUP) { + cv_wait(&ctrl->cvp, &oplmsu_uinst->c_lock); + } + } + + flushq(RD(urq), FLUSHALL); + flushq(WR(urq), FLUSHALL); + mutex_exit(&oplmsu_uinst->c_lock); + qprocsoff(urq); /* Disable queuing of queue */ + + rw_enter(&oplmsu_uinst->lock, RW_WRITER); + switch (node_flag) { + case MSU_NODE_USER : /* User access node */ + oplmsu_uinst->user_ctrl = NULL; + oplmsu_queue_flag = 0; + break; + + case MSU_NODE_META : /* Meta control node */ + oplmsu_uinst->meta_ctrl = NULL; + break; + + default : + cmn_err(CE_WARN, "oplmsu: close: node_flag = 0x%lx", node_flag); + } + + ctrl->minor = NULL; + ctrl->queue = NULL; + wbuf_id = ctrl->wbuf_id; + wtout_id = ctrl->wtout_id; + ctrl->wbuf_id = 0; + ctrl->wtout_id = 0; + + cv_destroy(&ctrl->cvp); + kmem_free(ctrl->wbuftbl, sizeof (struct buf_tbl)); + ctrl->wbuftbl = NULL; + + RD(urq)->q_ptr = NULL; + WR(urq)->q_ptr = NULL; + rw_exit(&oplmsu_uinst->lock); + + if (wbuf_id != 0) { + unbufcall(wbuf_id); + } + + if (wtout_id != 0) { + untimeout(wtout_id); + } + + /* Free kernel memory for ctrl_t */ + kmem_free(ctrl, sizeof (ctrl_t)); + + OPLMSU_TRACE(urq, (mblk_t *)node_flag, MSU_TRC_CLS); + return (SUCCESS); +} + +/* + * Upper write put procedure + */ +int +oplmsu_uwput(queue_t *uwq, mblk_t *mp) +{ + + if (mp == NULL) { + return (SUCCESS); + } + + if ((uwq == NULL) || (uwq->q_ptr == NULL)) { + freemsg(mp); + return (SUCCESS); + } + + OPLMSU_TRACE(uwq, mp, MSU_TRC_UI); + + rw_enter(&oplmsu_uinst->lock, RW_READER); + if (mp->b_datap->db_type == M_FLUSH) { + oplmsu_wcmn_flush_hndl(uwq, mp, RW_READER); + } else if (mp->b_datap->db_type >= QPCTL) { + ctrl_t *ctrl; + + mutex_enter(&oplmsu_uinst->c_lock); + ctrl = (ctrl_t *)uwq->q_ptr; + + /* Link high priority message to local queue */ + oplmsu_link_high_primsg(&ctrl->first_upri_hi, + &ctrl->last_upri_hi, mp); + + mutex_exit(&oplmsu_uinst->c_lock); + oplmsu_wcmn_high_qenable(WR(uwq), RW_READER); + } else { + putq(WR(uwq), mp); + } + rw_exit(&oplmsu_uinst->lock); + return (SUCCESS); +} + +/* + * Upper write service procedure + */ +int +oplmsu_uwsrv(queue_t *uwq) +{ + struct iocblk *iocp = NULL; + mblk_t *mp = NULL; + int rval; + + if ((uwq == NULL) || (uwq->q_ptr == NULL)) { + return (FAILURE); + } + + rw_enter(&oplmsu_uinst->lock, RW_READER); + + /* Handle high priority message */ + while (mp = oplmsu_wcmn_high_getq(uwq)) { + if (mp->b_datap->db_type == M_FLUSH) { + oplmsu_wcmn_flush_hndl(uwq, mp, RW_READER); + continue; + } + + if (oplmsu_wcmn_through_hndl(uwq, mp, MSU_HIGH, RW_READER) == + FAILURE) { + rw_exit(&oplmsu_uinst->lock); + return (SUCCESS); + } + } + rw_exit(&oplmsu_uinst->lock); + + /* Handle normal priority message */ + while (mp = getq(uwq)) { + rval = SUCCESS; + switch (mp->b_datap->db_type) { + case M_IOCTL : + iocp = (struct iocblk *)mp->b_rptr; + switch (iocp->ioc_cmd) { + case I_PLINK : + if (oplmsu_cmn_pullup_msg(uwq, mp) != FAILURE) { + rval = oplmsu_uwioctl_iplink(uwq, mp); + } + break; + + case I_PUNLINK : + if (oplmsu_cmn_pullup_msg(uwq, mp) != FAILURE) { + rval = oplmsu_uwioctl_ipunlink(uwq, mp); + } + break; + + case TCSETS : /* FALLTHRU */ + case TCSETSW : /* FALLTHRU */ + case TCSETSF : /* FALLTHRU */ + case TIOCMSET : /* FALLTHRU */ + case TIOCSPPS : /* FALLTHRU */ + case TIOCSWINSZ : /* FALLTHRU */ + case TIOCSSOFTCAR : + rval = oplmsu_uwioctl_termios(uwq, mp); + break; + + default : + rw_enter(&oplmsu_uinst->lock, RW_READER); + rval = oplmsu_wcmn_through_hndl(uwq, mp, + MSU_NORM, RW_READER); + rw_exit(&oplmsu_uinst->lock); + break; + } + break; + + default : + rw_enter(&oplmsu_uinst->lock, RW_READER); + rval = oplmsu_wcmn_through_hndl(uwq, mp, MSU_NORM, + RW_READER); + rw_exit(&oplmsu_uinst->lock); + break; + } + + if (rval == FAILURE) { + break; + } + } + return (SUCCESS); +} + +/* + * Lower write service procedure + */ +int +oplmsu_lwsrv(queue_t *lwq) +{ + mblk_t *mp; + queue_t *dst_queue; + lpath_t *lpath; + + rw_enter(&oplmsu_uinst->lock, RW_READER); + while (mp = getq(lwq)) { + if (mp->b_datap->db_type >= QPCTL) { + rw_exit(&oplmsu_uinst->lock); + OPLMSU_TRACE(WR(lwq), mp, MSU_TRC_LO); + putnext(WR(lwq), mp); + rw_enter(&oplmsu_uinst->lock, RW_READER); + continue; + } + + dst_queue = WR(lwq); + if (canputnext(dst_queue)) { + rw_exit(&oplmsu_uinst->lock); + OPLMSU_TRACE(dst_queue, mp, MSU_TRC_LO); + putnext(dst_queue, mp); + rw_enter(&oplmsu_uinst->lock, RW_READER); + } else { + putbq(WR(lwq), mp); + break; + } + } + + mutex_enter(&oplmsu_uinst->l_lock); + lpath = (lpath_t *)lwq->q_ptr; + if (lpath->uwq_flag != 0) { + qenable(WR(lpath->uwq_queue)); + lpath->uwq_flag = 0; + lpath->uwq_queue = NULL; + } + mutex_exit(&oplmsu_uinst->l_lock); + rw_exit(&oplmsu_uinst->lock); + return (SUCCESS); +} + +/* + * Lower read put procedure + */ +int +oplmsu_lrput(queue_t *lrq, mblk_t *mp) +{ + + if (mp == NULL) { + return (SUCCESS); + } + + if ((lrq == NULL) || (lrq->q_ptr == NULL)) { + freemsg(mp); + return (SUCCESS); + } + + OPLMSU_TRACE(lrq, mp, MSU_TRC_LI); + + if (mp->b_datap->db_type == M_FLUSH) { + rw_enter(&oplmsu_uinst->lock, RW_READER); + oplmsu_rcmn_flush_hndl(lrq, mp); + rw_exit(&oplmsu_uinst->lock); + } else if (mp->b_datap->db_type >= QPCTL) { + lpath_t *lpath; + + rw_enter(&oplmsu_uinst->lock, RW_READER); + mutex_enter(&oplmsu_uinst->l_lock); + lpath = lrq->q_ptr; + + /* Link high priority message to local queue */ + oplmsu_link_high_primsg(&lpath->first_lpri_hi, + &lpath->last_lpri_hi, mp); + + mutex_exit(&oplmsu_uinst->l_lock); + rw_exit(&oplmsu_uinst->lock); + oplmsu_rcmn_high_qenable(lrq); + } else { + putq(lrq, mp); + } + return (SUCCESS); +} + +/* + * Lower read service procedure + */ +int +oplmsu_lrsrv(queue_t *lrq) +{ + mblk_t *mp; + boolean_t aborted; + int rval; + + if ((lrq == NULL) || (lrq->q_ptr == NULL)) { + return (FAILURE); + } + + /* Handle normal priority message */ + while (mp = getq(lrq)) { + if (mp->b_datap->db_type >= QPCTL) { + cmn_err(CE_WARN, "oplmsu: lr-srv: " + "Invalid db_type => %x", mp->b_datap->db_type); + } + + switch (mp->b_datap->db_type) { + case M_DATA : + aborted = B_FALSE; + rw_enter(&oplmsu_uinst->lock, RW_READER); + if ((abort_enable == KIOCABORTALTERNATE) && + (RD(oplmsu_uinst->lower_queue) == lrq)) { + uchar_t *rx_char = mp->b_rptr; + lpath_t *lpath; + + mutex_enter(&oplmsu_uinst->l_lock); + lpath = lrq->q_ptr; + while (rx_char != mp->b_wptr) { + if (*rx_char == *lpath->abt_char) { + lpath->abt_char++; + if (*lpath->abt_char == '\0') { + abort_sequence_enter((char *)NULL); + lpath->abt_char + = oplmsu_uinst->abts; + aborted = B_TRUE; + break; + } + } else { + lpath->abt_char = (*rx_char == + *oplmsu_uinst->abts) ? + oplmsu_uinst->abts + 1 : + oplmsu_uinst->abts; + } + rx_char++; + } + mutex_exit(&oplmsu_uinst->l_lock); + } + rw_exit(&oplmsu_uinst->lock); + + if (aborted) { + freemsg(mp); + continue; + } + + /* + * When 1st byte of the received M_DATA is XON or, + * 1st byte is XOFF and 2nd byte is XON. + */ + + if ((*(mp->b_rptr) == MSU_XON) || + (((mp->b_wptr - mp->b_rptr) == 2) && + ((*(mp->b_rptr) == MSU_XOFF) && + (*(mp->b_rptr + 1) == MSU_XON)))) { + /* Path switching by XOFF/XON */ + if (oplmsu_lrdata_xoffxon(lrq, mp) == FAILURE) { + return (SUCCESS); + } + } else { + rw_enter(&oplmsu_uinst->lock, RW_READER); + rval = + oplmsu_rcmn_through_hndl(lrq, mp, MSU_NORM); + rw_exit(&oplmsu_uinst->lock); + + if (rval == FAILURE) { + return (SUCCESS); + } + } + break; + + case M_BREAK : + if ((mp->b_wptr - mp->b_rptr) == 0 && msgdsize(mp) + == 0) { + rw_enter(&oplmsu_uinst->lock, RW_READER); + if ((abort_enable != KIOCABORTALTERNATE) && + (RD(oplmsu_uinst->lower_queue) == lrq)) { + abort_sequence_enter((char *)NULL); + } + rw_exit(&oplmsu_uinst->lock); + freemsg(mp); + break; + } + /* FALLTHRU */ + + default : + rw_enter(&oplmsu_uinst->lock, RW_READER); + (void) oplmsu_rcmn_through_hndl(lrq, mp, MSU_NORM); + rw_exit(&oplmsu_uinst->lock); + break; + } + } + return (SUCCESS); +} + +/* + * Upper read service procedure + */ +int +oplmsu_ursrv(queue_t *urq) +{ + mblk_t *mp; + queue_t *dst_queue; + lpath_t *lpath; + ctrl_t *ctrl; + int res_chk = 0; + + rw_enter(&oplmsu_uinst->lock, RW_READER); + while (mp = getq(urq)) { + if (mp->b_datap->db_type >= QPCTL) { + if ((mp->b_datap->db_type == M_IOCACK) || + (mp->b_datap->db_type == M_IOCNAK)) { + res_chk = 1; + } + rw_exit(&oplmsu_uinst->lock); + OPLMSU_TRACE(RD(urq), mp, MSU_TRC_UO); + putnext(RD(urq), mp); + + rw_enter(&oplmsu_uinst->lock, RW_READER); + mutex_enter(&oplmsu_uinst->l_lock); + lpath = oplmsu_uinst->first_lpath; + while (lpath) { + qenable(RD(lpath->lower_queue)); + lpath = lpath->l_next; + } + mutex_exit(&oplmsu_uinst->l_lock); + + if (res_chk == 1) { + mutex_enter(&oplmsu_uinst->c_lock); + ctrl = (ctrl_t *)urq->q_ptr; + if (ctrl != NULL) { + if (ctrl->wait_queue != NULL) { + qenable(WR(ctrl->wait_queue)); + ctrl->wait_queue = NULL; + } + } + mutex_exit(&oplmsu_uinst->c_lock); + res_chk = 0; + } + continue; + } + + dst_queue = RD(urq); + if (canputnext(dst_queue)) { + rw_exit(&oplmsu_uinst->lock); + OPLMSU_TRACE(dst_queue, mp, MSU_TRC_UO); + putnext(dst_queue, mp); + rw_enter(&oplmsu_uinst->lock, RW_READER); + } else { + putbq(urq, mp); + break; + } + } + + mutex_enter(&oplmsu_uinst->c_lock); + ctrl = urq->q_ptr; + if (ctrl->lrq_flag != 0) { + qenable(ctrl->lrq_queue); + ctrl->lrq_flag = 0; + ctrl->lrq_queue = NULL; + } + mutex_exit(&oplmsu_uinst->c_lock); + rw_exit(&oplmsu_uinst->lock); + return (SUCCESS); +} + +int +oplmsu_open_msu(dev_info_t *dip, ldi_ident_t *lip, ldi_handle_t *lhp) +{ + dev_t devt; + int rval; + + /* Allocate LDI identifier */ + rval = ldi_ident_from_dip(dip, lip); + if (rval != 0) { + cmn_err(CE_WARN, "oplmsu: open-msu: " + "ldi_ident_from_dip failed. errno = %d", rval); + return (rval); + } + + /* Open oplmsu(meta ctrl node) */ + devt = makedevice(ddi_driver_major(dip), META_NODE_MASK); + rval = + ldi_open_by_dev(&devt, OTYP_CHR, (FREAD|FWRITE), kcred, lhp, *lip); + if (rval != 0) { + cmn_err(CE_WARN, "oplmsu: open-msu: " + "ldi_open_by_dev failed. errno = %d", rval); + ldi_ident_release(*lip); + } + return (rval); +} + +int +oplmsu_plink_serial(dev_info_t *dip, ldi_handle_t msu_lh, int *id) +{ + ldi_ident_t li = NULL; + ldi_handle_t lh = NULL; + int param; + int rval; + char pathname[MSU_PATHNAME_SIZE]; + char wrkbuf[MSU_PATHNAME_SIZE]; + + /* Create physical path-name for serial */ + ddi_pathname(dip, wrkbuf); + *(wrkbuf + strlen(wrkbuf)) = '\0'; + sprintf(pathname, "/devices%s:%c", wrkbuf, 'a'+ ddi_get_instance(dip)); + + /* Allocate LDI identifier */ + rval = ldi_ident_from_dip(dip, &li); + if (rval != 0) { + cmn_err(CE_WARN, "oplmsu: plink-serial: " + "%s ldi_ident_from_dip failed. errno = %d", pathname, rval); + return (rval); + } + + /* Open serial */ + rval = ldi_open_by_name(pathname, (FREAD|FWRITE|FEXCL), kcred, &lh, li); + if (rval != 0) { + cmn_err(CE_WARN, "oplmsu: plink-serial: " + "%s open failed. errno = %d", pathname, rval); + ldi_ident_release(li); + return (rval); + } + + /* Try to remove the top module from the stream */ + param = 0; + while ((ldi_ioctl(lh, I_POP, (intptr_t)0, FKIOCTL, kcred, ¶m)) + == 0) { + continue; + } + + /* Issue ioctl(I_PLINK) */ + param = 0; + rval = ldi_ioctl(msu_lh, I_PLINK, (intptr_t)lh, FKIOCTL, kcred, ¶m); + if (rval != 0) { + cmn_err(CE_WARN, "oplmsu: plink-serial: " + "%s ioctl(I_PLINK) failed. errno = %d", pathname, rval); + } + + (void) ldi_close(lh, (FREAD|FWRITE|FEXCL), kcred); + ldi_ident_release(li); + + *id = param; /* Save link-id */ + return (rval); +} + +int +oplmsu_set_lpathnum(int lnk_id, int instance) +{ + lpath_t *lpath; + int rval = SUCCESS; + + rw_enter(&oplmsu_uinst->lock, RW_READER); + mutex_enter(&oplmsu_uinst->l_lock); + lpath = oplmsu_uinst->first_lpath; + while (lpath) { + if ((lpath->path_no == UNDEFINED) && + (lpath->link_id == lnk_id)) { + lpath->path_no = instance; /* Set instance number */ + lpath->src_upath = NULL; + lpath->status = MSU_SETID_NU; + break; + } + lpath = lpath->l_next; + } + mutex_exit(&oplmsu_uinst->l_lock); + rw_exit(&oplmsu_uinst->lock); + + if (lpath == NULL) { + rval = EINVAL; + } + return (rval); +} + +int +oplmsu_dr_attach(dev_info_t *dip) +{ + ldi_ident_t msu_li = NULL; + ldi_handle_t msu_lh = NULL; + upath_t *upath; + int len; + int instance; + int lnk_id = 0; + int param = 0; + int rval; + + /* Get instance for serial */ + instance = ddi_get_instance(dip); + + rw_enter(&oplmsu_uinst->lock, RW_WRITER); + mutex_enter(&oplmsu_uinst->u_lock); + + /* Get current number of paths */ + oplmsu_uinst->path_num = oplmsu_get_pathnum(); + + /* Check specified upath_t */ + upath = oplmsu_uinst->first_upath; + while (upath) { + if (instance == upath->path_no) { + break; + } + upath = upath->u_next; + } + mutex_exit(&oplmsu_uinst->u_lock); + rw_exit(&oplmsu_uinst->lock); + + if (upath != NULL) { + cmn_err(CE_WARN, "oplmsu: attach(dr): " + "Instance %d already exist", instance); + return (EINVAL); + } + + /* Open oplmsu */ + rval = oplmsu_open_msu(oplmsu_uinst->msu_dip, &msu_li, &msu_lh); + if (rval != 0) { + cmn_err(CE_WARN, "oplmsu: attach(dr): " + "msu open failed. errno = %d", rval); + return (rval); + } + + /* Connect two streams */ + rval = oplmsu_plink_serial(dip, msu_lh, &lnk_id); + if (rval != 0) { + cmn_err(CE_WARN, "oplmsu: attach(dr): " + "i_plink failed. errno = %d", rval); + (void) ldi_close(msu_lh, (FREAD|FWRITE), kcred); + ldi_ident_release(msu_li); + return (rval); + } + + rval = oplmsu_set_lpathnum(lnk_id, instance); + if (rval != 0) { + cmn_err(CE_WARN, "oplmsu: attach(dr): " + "Link id %d is not found", lnk_id); + /* Issue ioctl(I_PUNLINK) */ + (void) ldi_ioctl(msu_lh, I_PUNLINK, (intptr_t)lnk_id, FKIOCTL, + kcred, ¶m); + (void) ldi_close(msu_lh, (FREAD|FWRITE), kcred); + ldi_ident_release(msu_li); + return (rval); + } + + /* Add the path */ + rval = oplmsu_config_add(dip); + if (rval != 0) { + cmn_err(CE_WARN, "oplmsu: attach(dr): " + "Failed to add the path. errno = %d", rval); + /* Issue ioctl(I_PUNLINK) */ + (void) ldi_ioctl(msu_lh, I_PUNLINK, (intptr_t)lnk_id, FKIOCTL, + kcred, ¶m); + + (void) ldi_close(msu_lh, (FREAD|FWRITE), kcred); + ldi_ident_release(msu_li); + return (rval); + } + + /* Start to use the path */ + rval = oplmsu_config_start(instance); + if (rval != 0) { + struct msu_path *mpath; + struct msu_dev *mdev; + + cmn_err(CE_WARN, "oplmsu: attach(dr): " + "Failed to start the path. errno = %d", rval); + + len = sizeof (struct msu_path) + sizeof (struct msu_dev); + mpath = (struct msu_path *)kmem_zalloc((size_t)len, KM_SLEEP); + mpath->num = 1; + mdev = (struct msu_dev *)(mpath + 1); + mdev->dip = dip; + + /* Delete the path */ + if ((oplmsu_config_del(mpath)) == 0) { + /* Issue ioctl(I_PUNLINK) */ + (void) ldi_ioctl(msu_lh, I_PUNLINK, (intptr_t)lnk_id, + FKIOCTL, kcred, ¶m); + } + kmem_free(mpath, (size_t)len); + } + + /* Close oplmsu */ + (void) ldi_close(msu_lh, (FREAD|FWRITE), kcred); + ldi_ident_release(msu_li); + return (rval); +} + +int +oplmsu_dr_detach(dev_info_t *dip) +{ + ldi_ident_t msu_li = NULL; + ldi_handle_t msu_lh = NULL; + struct msu_path *mpath; + struct msu_dev *mdev; + upath_t *upath; + lpath_t *lpath; + int len; + int instance; + int count = 0; + int param = 0; + int status; + int rval; + + /* Get instance for serial */ + instance = ddi_get_instance(dip); + + rw_enter(&oplmsu_uinst->lock, RW_WRITER); + mutex_enter(&oplmsu_uinst->u_lock); + + /* Get current number of paths */ + oplmsu_uinst->path_num = oplmsu_get_pathnum(); + + rval = FAILURE; + + /* Check specified upath_t */ + upath = oplmsu_uinst->first_upath; + while (upath) { + if (instance == upath->path_no) { + /* Save status of specified path */ + status = upath->status; + rval = SUCCESS; + } + upath = upath->u_next; + count += 1; + } + mutex_exit(&oplmsu_uinst->u_lock); + rw_exit(&oplmsu_uinst->lock); + + if (rval == FAILURE) { + if (count <= 1) { + cmn_err(CE_WARN, "oplmsu: detach(dr): " + "Instance %d is last path", instance); + } else { + cmn_err(CE_WARN, "oplmsu: detach(dr): " + "Instance %d doesn't find", instance); + } + return (EINVAL); + } + + /* Check status of specified path */ + if ((status == MSU_PSTAT_ACTIVE) || (status == MSU_PSTAT_STANDBY)) { + /* Stop to use the path */ + rval = oplmsu_config_stop(instance); + if (rval != 0) { + cmn_err(CE_WARN, "oplmsu: detach(dr): " + "Failed to stop the path. errno = %d", rval); + return (rval); + } + } + + /* Prepare to unlink the path */ + rval = oplmsu_config_disc(instance); + if (rval != 0) { + cmn_err(CE_WARN, "oplmsu: detach(dr): " + "Failed to disconnect the path. errno = %d", rval); + return (rval); + } + + rw_enter(&oplmsu_uinst->lock, RW_READER); + mutex_enter(&oplmsu_uinst->l_lock); + lpath = oplmsu_uinst->first_lpath; + while (lpath) { + if (lpath->path_no == instance) { /* Get link ID */ + break; + } + lpath = lpath->l_next; + } + mutex_exit(&oplmsu_uinst->l_lock); + rw_exit(&oplmsu_uinst->lock); + + if (lpath == NULL) { + cmn_err(CE_WARN, "oplmsu: detach(dr): Can not find link ID"); + return (EINVAL); + } + + /* Open oplmsu */ + rval = oplmsu_open_msu(oplmsu_uinst->msu_dip, &msu_li, &msu_lh); + if (rval != 0) { + cmn_err(CE_WARN, "oplmsu: detach(dr): " + "msu open failed. errno = %d", rval); + return (rval); + } + + /* Issue ioctl(I_PUNLINK) */ + rval = ldi_ioctl(msu_lh, I_PUNLINK, (intptr_t)lpath->link_id, FKIOCTL, + kcred, ¶m); + if (rval != 0) { + cmn_err(CE_WARN, "oplmsu: detach(dr): " + "ioctl(I_PUNLINK) failed. errno = %d", rval); + (void) ldi_close(msu_lh, (FREAD|FWRITE), kcred); + ldi_ident_release(msu_li); + return (rval); + } + + /* Close oplmsu(meta node) */ + (void) ldi_close(msu_lh, (FREAD|FWRITE), kcred); + ldi_ident_release(msu_li); + + len = sizeof (struct msu_path) + sizeof (struct msu_dev); + mpath = (struct msu_path *)kmem_zalloc((size_t)len, KM_SLEEP); + mpath->num = 1; + mdev = (struct msu_dev *)(mpath + 1); + mdev->dip = dip; + + /* Delete the path */ + rval = oplmsu_config_del(mpath); + if (rval != 0) { + cmn_err(CE_WARN, "oplmsu: detach(dr): " + "Failed to delete the path. errno = %d", rval); + } + + kmem_free(mpath, (size_t)len); + return (rval); +} + +/* + * The ebus and the serial device path under a given CMU_CH chip + * is expected to be always at the same address. So, it is safe + * to hard-code the pathnames as below. + */ +#define EBUS_PATH "ebus@1" +#define SERIAL_PATH "serial@14,400000" +#define EBUS_SERIAL_PATH ("/" EBUS_PATH "/" SERIAL_PATH) + +/* + * Given the CMU_CH dip, find the serial device dip. + */ +dev_info_t * +oplmsu_find_ser_dip(dev_info_t *cmuch_dip) +{ + int circ1, circ2; + dev_info_t *ebus_dip; + dev_info_t *ser_dip = NULL; + + ndi_devi_enter(cmuch_dip, &circ1); + ebus_dip = ndi_devi_findchild(cmuch_dip, EBUS_PATH); + + DBG_PRINT((CE_NOTE, "oplmsu: find-serial-dip: " + "ebus_dip = %p", ebus_dip)); + + if (ebus_dip != NULL) { + ndi_devi_enter(ebus_dip, &circ2); + ser_dip = ndi_devi_findchild(ebus_dip, SERIAL_PATH); + + DBG_PRINT((CE_NOTE, "oplmsu: find-serial-dip: " + "ser_dip = %p", ser_dip)); + ndi_devi_exit(ebus_dip, circ2); + } + ndi_devi_exit(cmuch_dip, circ1); + return (ser_dip); +} + +/* + * Find all console related serial devices. + */ +int +oplmsu_find_serial(ser_devl_t **ser_dl) +{ + dev_info_t *root_dip; + dev_info_t *cmuch_dip; + dev_info_t *dip; + ser_devl_t *wrk_ser_dl; + int circ; + int count = 0; + char pathname[MSU_PATHNAME_SIZE]; + dev_t devt; + char *namep; + + root_dip = ddi_root_node(); + ndi_devi_enter(root_dip, &circ); + cmuch_dip = ddi_get_child(root_dip); + + while (cmuch_dip != NULL) { + namep = ddi_binding_name(cmuch_dip); /* Get binding name */ + if (namep == NULL) { + cmuch_dip = ddi_get_next_sibling(cmuch_dip); + continue; + } + + DBG_PRINT((CE_NOTE, "oplmsu: find-serial: name => %s", namep)); + + if ((strcmp(namep, MSU_CMUCH_FF) != 0) && + (strcmp(namep, MSU_CMUCH_DC) != 0)) { +#ifdef DEBUG + if (strcmp(namep, MSU_CMUCH_DBG) != 0) { + cmuch_dip = ddi_get_next_sibling(cmuch_dip); + continue; + } +#else + cmuch_dip = ddi_get_next_sibling(cmuch_dip); + continue; +#endif + } + + (void) ddi_pathname(cmuch_dip, pathname); + DBG_PRINT((CE_NOTE, + "oplmsu: find-serial: cmu-ch path => %s", pathname)); + (void) strcat(pathname, EBUS_SERIAL_PATH); + + /* + * Call ddi_pathname_to_dev_t to forceload and attach + * the required drivers. + */ + devt = ddi_pathname_to_dev_t(pathname); + DBG_PRINT((CE_NOTE, "oplmsu: find-serial: serial device " + "dev_t = %lx", devt)); + if ((devt != NODEV) && + ((dip = oplmsu_find_ser_dip(cmuch_dip)) != NULL)) { + wrk_ser_dl = (ser_devl_t *) + kmem_zalloc(sizeof (ser_devl_t), KM_SLEEP); + wrk_ser_dl->dip = dip; + count += 1; + + if (*ser_dl != NULL) { + wrk_ser_dl->next = *ser_dl; + } + *ser_dl = wrk_ser_dl; + } + cmuch_dip = ddi_get_next_sibling(cmuch_dip); + } + ndi_devi_exit(root_dip, circ); + return (count); +} + +/* Configure STREAM */ +void +oplmsu_conf_stream(uinst_t *msu_uinst) +{ + ldi_ident_t msu_li = NULL; + ldi_handle_t msu_lh = NULL; + struct msu_path *mpath; + struct msu_dev *mdev; + ser_devl_t *ser_dl = NULL, *next_ser_dl; + int *plink_id; + int size; + int i; + int param; + int connected = 0; + int devcnt = 0; + int rval; + + DBG_PRINT((CE_NOTE, + "oplmsu: conf-stream: stream configuration start!")); + + /* Find serial devices */ + devcnt = oplmsu_find_serial(&ser_dl); + if ((devcnt == 0) || (ser_dl == NULL)) { + cmn_err(CE_WARN, "oplmsu: conf-stream: " + "Discovered serial device = %d", devcnt); + return; + } + + /* Open oplmsu */ + rval = oplmsu_open_msu(msu_uinst->msu_dip, &msu_li, &msu_lh); + if (rval != 0) { + cmn_err(CE_WARN, "oplmsu: conf-stream: " + "msu open failed. errno = %d", rval); + return; + } + + size = (sizeof (struct msu_path) + (sizeof (struct msu_dev) * devcnt)); + mpath = (struct msu_path *)kmem_zalloc((size_t)size, KM_SLEEP); + plink_id = (int *)kmem_zalloc((sizeof (int) * devcnt), KM_SLEEP); + + mdev = (struct msu_dev *)(mpath + 1); + for (i = 0; i < devcnt; i++) { + /* Connect two streams */ + rval = oplmsu_plink_serial(ser_dl->dip, msu_lh, &plink_id[i]); + if (rval != 0) { + cmn_err(CE_WARN, "oplmsu: conf-stream: " + "i_plink failed. errno = %d", rval); + next_ser_dl = ser_dl->next; + kmem_free(ser_dl, sizeof (ser_devl_t)); + ser_dl = next_ser_dl; + continue; + } + + rval = oplmsu_set_lpathnum(plink_id[i], + ddi_get_instance(ser_dl->dip)); + if (rval != 0) { + cmn_err(CE_WARN, "oplmsu: conf-stream: " + "Link id %d is not found", plink_id[i]); + /* Issue ioctl(I_PUNLINK) */ + (void) ldi_ioctl(msu_lh, I_PUNLINK, + (intptr_t)plink_id[i], FKIOCTL, kcred, ¶m); + next_ser_dl = ser_dl->next; + kmem_free(ser_dl, sizeof (ser_devl_t)); + ser_dl = next_ser_dl; + continue; + } + + mdev->dip = ser_dl->dip; + next_ser_dl = ser_dl->next; + kmem_free(ser_dl, sizeof (ser_devl_t)); + ser_dl = next_ser_dl; + + mdev++; + connected++; + } + + if (connected == 0) { + cmn_err(CE_WARN, "oplmsu: conf-stream: " + "Connected paths = %d", connected); + (void) ldi_close(msu_lh, (FREAD|FWRITE), kcred); + ldi_ident_release(msu_li); + kmem_free(plink_id, (sizeof (int) * devcnt)); + kmem_free(mpath, size); + return; + } + + /* Setup all structure */ + mpath->num = connected; + rval = oplmsu_config_new(mpath); + if (rval != 0) { + cmn_err(CE_WARN, "oplmsu: conf-stream: " + "Failed to create all paths. errno = %d", rval); + oplmsu_unlinks(msu_lh, plink_id, devcnt); + (void) ldi_close(msu_lh, (FREAD|FWRITE), kcred); + ldi_ident_release(msu_li); + kmem_free(plink_id, (sizeof (int) * devcnt)); + kmem_free(mpath, size); + return; + } + + /* Start to use all paths */ + rval = oplmsu_config_start(MSU_PATH_ALL); + if (rval != 0) { + cmn_err(CE_WARN, "oplmsu: conf-stream: " + "Failed to start all paths. errno = %d", rval); + + /* Delete the path */ + rval = oplmsu_config_del(mpath); + if (rval == 0) { + oplmsu_unlinks(msu_lh, plink_id, devcnt); + } + } + + (void) ldi_close(msu_lh, (FREAD|FWRITE), kcred); + ldi_ident_release(msu_li); + kmem_free(plink_id, (sizeof (int) * devcnt)); + kmem_free(mpath, size); + + DBG_PRINT((CE_NOTE, "oplmsu: conf-stream: stream configuration end!")); +} + +void +oplmsu_unlinks(ldi_handle_t msu_lh, int *plink_id, int devcnt) +{ + int i; + int param = 0; + + for (i = 0; i < devcnt; i++) { + if (plink_id[i] == 0) { + continue; + } + + /* Issue ioctl(I_PUNLINK) */ + (void) ldi_ioctl(msu_lh, I_PUNLINK, (intptr_t)plink_id[i], + FKIOCTL, kcred, ¶m); + } +} + +void +oplmsu_setup(uinst_t *msu_uinst) +{ + + DBG_PRINT((CE_NOTE, "oplmsu: setup: Background thread start!")); + + mutex_enter(&oplmsu_bthrd_excl); + if (oplmsu_conf_st == MSU_CONFIGURING) { + mutex_exit(&oplmsu_bthrd_excl); + oplmsu_conf_stream(msu_uinst); /* Configure stream */ + mutex_enter(&oplmsu_bthrd_excl); + oplmsu_conf_st = MSU_CONFIGURED; + cv_broadcast(&oplmsu_conf_cv); /* Wake up from cv_wait_sig() */ + } + + if (oplmsu_bthrd_id != NULL) { + oplmsu_bthrd_id = NULL; + } + mutex_exit(&oplmsu_bthrd_excl); + + DBG_PRINT((CE_NOTE, "oplmsu: setup: Background thread end!")); + + thread_exit(); +} + +int +oplmsu_create_upath(dev_info_t *dip) +{ + upath_t *upath; + lpath_t *lpath; + dev_info_t *cmuch_dip; + int instance; + int lsb; + + cmuch_dip = ddi_get_parent(ddi_get_parent(dip)); + lsb = ddi_prop_get_int(DDI_DEV_T_ANY, cmuch_dip, 0, MSU_BOARD_PROP, + FAILURE); + if (lsb == FAILURE) { + return (lsb); + } + + instance = ddi_get_instance(dip); + + mutex_enter(&oplmsu_uinst->l_lock); + lpath = oplmsu_uinst->first_lpath; + while (lpath) { + if (lpath->path_no == instance) { + break; + } + lpath = lpath->l_next; + } + + if (lpath == NULL) { + mutex_exit(&oplmsu_uinst->l_lock); + return (ENODEV); + } + + upath = (upath_t *)kmem_zalloc(sizeof (upath_t), KM_SLEEP); + + /* + * Initialize members of upath_t + */ + + upath->path_no = instance; + upath->lpath = lpath; + upath->ser_devcb.dip = dip; + upath->ser_devcb.lsb = lsb; + oplmsu_cmn_set_upath_sts(upath, MSU_PSTAT_STOP, MSU_PSTAT_EMPTY, + MSU_STOP); + + lpath->src_upath = NULL; + lpath->status = MSU_EXT_NOTUSED; + mutex_exit(&oplmsu_uinst->l_lock); + + oplmsu_link_upath(upath); + return (SUCCESS); +} + +/* Setup new upper instance structure */ +int +oplmsu_config_new(struct msu_path *mpath) +{ + struct msu_dev *mdev; + int i; + int rval = SUCCESS; + + DBG_PRINT((CE_NOTE, "oplmsu: conf-new: config_new() called")); + ASSERT(mpath); + + if (mpath->num == 0) { + cmn_err(CE_WARN, "oplmsu: conf-new: " + "Number of paths = %d", mpath->num); + return (EINVAL); + } + + rw_enter(&oplmsu_uinst->lock, RW_WRITER); + + mutex_enter(&oplmsu_uinst->l_lock); + rval = oplmsu_check_lpath_usable(); + mutex_exit(&oplmsu_uinst->l_lock); + + if (rval == BUSY) { /* Check whether Lower path is usable */ + rw_exit(&oplmsu_uinst->lock); + cmn_err(CE_WARN, "oplmsu: conf-new: " + "Other processing is using this device"); + return (EBUSY); + } + + /* + * Because the OPLMSU instance already exists when the upper path + * table exists, the configure_new processing cannot be done. + */ + + mutex_enter(&oplmsu_uinst->u_lock); + + if ((oplmsu_uinst->first_upath != NULL) || + (oplmsu_uinst->last_upath != NULL)) { + mutex_exit(&oplmsu_uinst->u_lock); + rw_exit(&oplmsu_uinst->lock); + cmn_err(CE_WARN, "oplmsu: conf-new: upath_t already exist"); + return (EINVAL); + } + + /* + * Because the config_new processing has already been done + * if oplmsu_uinst->path_num isn't -1, this processing cannot be + * continued. + */ + + if (oplmsu_uinst->path_num != UNDEFINED) { + mutex_exit(&oplmsu_uinst->u_lock); + rw_exit(&oplmsu_uinst->lock); + cmn_err(CE_WARN, "oplmsu: conf-new: " + "conf-new processing has already been completed"); + return (EINVAL); + } + + /* + * Only the number of specified paths makes the upper path + * information tables. + */ + + mdev = (struct msu_dev *)(mpath + 1); + for (i = 0; i < mpath->num; i++) { + /* + * Associate upper path information table with lower path + * information table. + * + * If the upper path information table and the lower path + * information table cannot be associated, the link list of + * the upper path information table is released. + */ + rval = oplmsu_create_upath(mdev->dip); + if (rval != SUCCESS) { + oplmsu_delete_upath_info(); + mutex_exit(&oplmsu_uinst->u_lock); + rw_exit(&oplmsu_uinst->lock); + cmn_err(CE_WARN, "oplmsu: conf-new: " + "Failed to create upath %d", rval); + return (rval); + } + + mdev++; + } + + /* + * Setup members of uinst_t + */ + + oplmsu_uinst->inst_status = oplmsu_get_inst_status(); + oplmsu_uinst->path_num = mpath->num; + oplmsu_uinst->lower_queue = NULL; + mutex_exit(&oplmsu_uinst->u_lock); + rw_exit(&oplmsu_uinst->lock); + return (SUCCESS); +} + +/* Add path information */ +int +oplmsu_config_add(dev_info_t *dip) +{ + upath_t *upath; + int instance; + int rval = SUCCESS; + + DBG_PRINT((CE_NOTE, "oplmsu: conf-add: config_add() called")); + ASSERT(dip); + + instance = ddi_get_instance(dip); + rw_enter(&oplmsu_uinst->lock, RW_WRITER); + + if (oplmsu_uinst->path_num == UNDEFINED) { + rw_exit(&oplmsu_uinst->lock); + cmn_err(CE_WARN, "oplmsu: conf-add: " + "conf-new processing has not been completed yet"); + return (EINVAL); + } + + mutex_enter(&oplmsu_uinst->u_lock); + upath = oplmsu_search_upath_info(instance); + if (upath != NULL) { + mutex_exit(&oplmsu_uinst->u_lock); + rw_exit(&oplmsu_uinst->lock); + cmn_err(CE_WARN, "oplmsu: conf-add: " + "Proper upath_t doesn't find"); + return (EINVAL); + } + + rval = oplmsu_create_upath(dip); + if (rval != SUCCESS) { + mutex_exit(&oplmsu_uinst->u_lock); + rw_exit(&oplmsu_uinst->lock); + cmn_err(CE_WARN, "oplmsu: conf-add: " + "Failed to create upath %d", rval); + return (rval); + } + + oplmsu_uinst->inst_status = oplmsu_get_inst_status(); + oplmsu_uinst->path_num = oplmsu_get_pathnum(); + mutex_exit(&oplmsu_uinst->u_lock); + rw_exit(&oplmsu_uinst->lock); + return (SUCCESS); +} + +/* Delete each path information */ +int +oplmsu_config_del(struct msu_path *mpath) +{ + struct msu_dev *mdev; + upath_t *upath; + lpath_t *lpath; + int rval = SUCCESS; + int use_flag; + int i; + + DBG_PRINT((CE_NOTE, "oplmsu: conf-del: config_del() called")); + ASSERT(mpath); + + mdev = (struct msu_dev *)(mpath + 1); + + rw_enter(&oplmsu_uinst->lock, RW_WRITER); + mutex_enter(&oplmsu_uinst->u_lock); + for (i = 0; i < mpath->num; i++) { + upath = oplmsu_search_upath_info(ddi_get_instance(mdev->dip)); + if (upath == NULL) { + cmn_err(CE_WARN, "oplmsu: conf-del: " + "Proper upath_t doesn't find"); + rval = ENODEV; + mdev++; + continue; + } + + lpath = upath->lpath; + if (lpath == NULL) { + if ((upath->traditional_status == MSU_WSTP_ACK) || + (upath->traditional_status == MSU_WSTR_ACK) || + (upath->traditional_status == MSU_WPTH_CHG) || + (upath->traditional_status == MSU_WTCS_ACK) || + (upath->traditional_status == MSU_WTMS_ACK) || + (upath->traditional_status == MSU_WPPS_ACK) || + (upath->traditional_status == MSU_WWSZ_ACK) || + (upath->traditional_status == MSU_WCAR_ACK)) { + cmn_err(CE_WARN, "oplmsu: conf-del: " + "Other processing is using this device"); + rval = EBUSY; + mdev++; + continue; + } + + if ((upath->status != MSU_PSTAT_DISCON) || + (upath->traditional_status != MSU_DISCON)) { + cmn_err(CE_WARN, "oplmsu: conf-del: " + "Status of path is improper"); + rval = EINVAL; + mdev++; + continue; + } + } else { + mutex_enter(&oplmsu_uinst->l_lock); + use_flag = oplmsu_set_ioctl_path(lpath, NULL, NULL); + if (use_flag == BUSY) { + mutex_exit(&oplmsu_uinst->l_lock); + cmn_err(CE_WARN, "oplmsu: conf-del: " + "Other processing is using lower path"); + rval = EBUSY; + mdev++; + continue; + } + + if (((upath->status != MSU_PSTAT_STOP) || + (upath->traditional_status != MSU_STOP)) && + ((upath->status != MSU_PSTAT_FAIL) || + (upath->traditional_status != MSU_FAIL))) { + oplmsu_clear_ioctl_path(lpath); + mutex_exit(&oplmsu_uinst->l_lock); + cmn_err(CE_WARN, "oplmsu: conf-del: " + "Status of path isn't 'Offline:stop/fail'"); + rval = EINVAL; + mdev++; + continue; + } + lpath->src_upath = NULL; + lpath->status = MSU_SETID_NU; + oplmsu_clear_ioctl_path(lpath); + mutex_exit(&oplmsu_uinst->l_lock); + } + oplmsu_unlink_upath(upath); /* Unlink upath_t */ + kmem_free(upath, sizeof (upath_t)); + mdev++; + } + + oplmsu_uinst->inst_status = oplmsu_get_inst_status(); + oplmsu_uinst->path_num = oplmsu_get_pathnum(); + mutex_exit(&oplmsu_uinst->u_lock); + rw_exit(&oplmsu_uinst->lock); + return (rval); +} + +/* Stop to use the path */ +int +oplmsu_config_stop(int pathnum) +{ + upath_t *upath, *altn_upath; + lpath_t *lpath, *altn_lpath; + queue_t *stp_queue = NULL; + queue_t *dst_queue = NULL; + mblk_t *nmp = NULL, *fmp = NULL; + ctrl_t *ctrl; + int term_ioctl, term_stat; + int use_flag; + + DBG_PRINT((CE_NOTE, + "oplmsu: conf-stop: config_stop(%d) called", pathnum)); + + if (pathnum == MSU_PATH_ALL) { + cmn_err(CE_WARN, "oplmsu: conf-stop: " + "All path can't be transferred to the status of " + "'Offline:stop'"); + return (EINVAL); + } + + rw_enter(&oplmsu_uinst->lock, RW_WRITER); + mutex_enter(&oplmsu_uinst->u_lock); + + upath = oplmsu_search_upath_info(pathnum); /* Search upath_t */ + if (upath == NULL) { + mutex_exit(&oplmsu_uinst->u_lock); + rw_exit(&oplmsu_uinst->lock); + cmn_err(CE_WARN, "oplmsu: conf-stop: " + "Proper upath_t doesn't find"); + return (ENODEV); + } + + lpath = upath->lpath; + if (lpath == NULL) { + mutex_exit(&oplmsu_uinst->u_lock); + rw_exit(&oplmsu_uinst->lock); + cmn_err(CE_WARN, "oplmsu: conf-stop: " + "Proper lpath_t doesn't exist"); + return (ENODEV); + } + + mutex_enter(&oplmsu_uinst->l_lock); + + /* Check status of lpath_t */ + use_flag = oplmsu_set_ioctl_path(lpath, NULL, NULL); + if (use_flag == BUSY) { + mutex_exit(&oplmsu_uinst->l_lock); + mutex_exit(&oplmsu_uinst->u_lock); + rw_exit(&oplmsu_uinst->lock); + cmn_err(CE_WARN, "oplmsu: conf-stop: " + "Other processing is using lower path"); + return (EBUSY); + } + + if (upath->status == MSU_PSTAT_FAIL) { + oplmsu_clear_ioctl_path(lpath); + mutex_exit(&oplmsu_uinst->l_lock); + mutex_exit(&oplmsu_uinst->u_lock); + rw_exit(&oplmsu_uinst->lock); + return (EIO); + } else if ((upath->status == MSU_PSTAT_STOP) && + (upath->traditional_status == MSU_STOP)) { + oplmsu_clear_ioctl_path(lpath); + mutex_exit(&oplmsu_uinst->l_lock); + mutex_exit(&oplmsu_uinst->u_lock); + rw_exit(&oplmsu_uinst->lock); + return (SUCCESS); + } else if ((upath->status == MSU_PSTAT_STANDBY) && + (upath->traditional_status == MSU_STANDBY)) { + oplmsu_cmn_set_upath_sts(upath, MSU_PSTAT_STOP, + upath->status, MSU_STOP); + oplmsu_clear_ioctl_path(lpath); + lpath->src_upath = NULL; + lpath->status = MSU_EXT_NOTUSED; + + oplmsu_uinst->inst_status = oplmsu_get_inst_status(); + mutex_exit(&oplmsu_uinst->l_lock); + mutex_exit(&oplmsu_uinst->u_lock); + rw_exit(&oplmsu_uinst->lock); + return (SUCCESS); + } else if ((upath->status == MSU_PSTAT_ACTIVE) && + (upath->traditional_status == MSU_ACTIVE)) { + altn_upath = oplmsu_search_standby(); + if (altn_upath == NULL) { /* Alternate path doesn't exist */ + DBG_PRINT((CE_NOTE, "oplmsu: conf-stop: " + "Alternate upper path doesn't find")); + oplmsu_clear_ioctl_path(lpath); + mutex_exit(&oplmsu_uinst->l_lock); + mutex_exit(&oplmsu_uinst->u_lock); + rw_exit(&oplmsu_uinst->lock); + return (EINVAL); + } + + if ((fmp = allocb(sizeof (char), BPRI_LO)) == NULL) { + oplmsu_clear_ioctl_path(lpath); + mutex_exit(&oplmsu_uinst->l_lock); + mutex_exit(&oplmsu_uinst->u_lock); + rw_exit(&oplmsu_uinst->lock); + return (ENOSR); + } + + if (oplmsu_stop_prechg(&nmp, &term_ioctl, &term_stat) != + SUCCESS) { + oplmsu_clear_ioctl_path(lpath); + mutex_exit(&oplmsu_uinst->l_lock); + mutex_exit(&oplmsu_uinst->u_lock); + rw_exit(&oplmsu_uinst->lock); + freeb(fmp); + return (ENOSR); + } + + altn_lpath = altn_upath->lpath; + use_flag = oplmsu_set_ioctl_path(altn_lpath, NULL, NULL); + if (use_flag == BUSY) { + oplmsu_clear_ioctl_path(lpath); + mutex_exit(&oplmsu_uinst->l_lock); + mutex_exit(&oplmsu_uinst->u_lock); + rw_exit(&oplmsu_uinst->lock); + + cmn_err(CE_WARN, "oplmsu: conf-stop: " + "Other processing is using alternate lower path"); + freeb(fmp); + freemsg(nmp); + return (EBUSY); + } + + dst_queue = WR(altn_lpath->lower_queue); + + /* termios is not held. Change alternate path to MSU_ACTIVE */ + if (nmp == NULL) { + altn_upath->traditional_status = term_stat; + altn_lpath->src_upath = upath; + altn_lpath->status = MSU_EXT_VOID; + + oplmsu_uinst->lower_queue = NULL; + + ctrl = oplmsu_uinst->user_ctrl; + if (ctrl != NULL) { + mutex_enter(&oplmsu_uinst->c_lock); + stp_queue = WR(ctrl->queue); + mutex_exit(&oplmsu_uinst->c_lock); + noenable(stp_queue); + oplmsu_queue_flag = 1; + } + + /* Make M_FLUSH and send to alternate path */ + oplmsu_cmn_set_mflush(fmp); + putq(dst_queue, fmp); + + /* Change status of alternate path */ + oplmsu_cmn_set_upath_sts(altn_upath, MSU_PSTAT_ACTIVE, + altn_upath->status, MSU_ACTIVE); + + oplmsu_clear_ioctl_path(altn_lpath); + altn_lpath->uinst = oplmsu_uinst; + altn_lpath->src_upath = NULL; + altn_lpath->status = MSU_EXT_NOTUSED; + + /* Notify of the active path changing */ + prom_opl_switch_console(altn_upath->ser_devcb.lsb); + + /* Send XON to notify active path */ + (void) oplmsu_cmn_put_xoffxon(dst_queue, MSU_XON_4); + + /* Send XOFF to notify all standby paths */ + oplmsu_cmn_putxoff_standby(); + + oplmsu_uinst->lower_queue = RD(dst_queue); + ctrl = oplmsu_uinst->user_ctrl; + + /* Switch active path of oplmsu */ + if (ctrl != NULL) { + queue_t *altn_queue; + + mutex_enter(&oplmsu_uinst->c_lock); + altn_queue = WR(ctrl->queue); + mutex_exit(&oplmsu_uinst->c_lock); + + /* Restart queuing of user access node */ + enableok(altn_queue); + + oplmsu_queue_flag = 0; + mutex_exit(&oplmsu_uinst->l_lock); + mutex_exit(&oplmsu_uinst->u_lock); + oplmsu_wcmn_high_qenable(altn_queue, RW_WRITER); + mutex_enter(&oplmsu_uinst->u_lock); + mutex_enter(&oplmsu_uinst->l_lock); + } + + /* Stop previous active path */ + oplmsu_cmn_set_upath_sts(upath, MSU_PSTAT_STOP, + upath->status, MSU_STOP); + + lpath->uinst = NULL; + lpath->src_upath = NULL; + lpath->status = MSU_EXT_NOTUSED; + oplmsu_clear_ioctl_path(lpath); + + oplmsu_uinst->inst_status = oplmsu_get_inst_status(); + mutex_exit(&oplmsu_uinst->l_lock); + mutex_exit(&oplmsu_uinst->u_lock); + rw_exit(&oplmsu_uinst->lock); + return (SUCCESS); + } + + /* Send termios information to alternate path */ + if (canput(dst_queue)) { + altn_upath->traditional_status = term_stat; + altn_lpath->src_upath = upath; + altn_lpath->status = MSU_EXT_VOID; + + upath->traditional_status = MSU_WSTP_ACK; + lpath->uinst = NULL; + + oplmsu_uinst->lower_queue = NULL; + + ctrl = oplmsu_uinst->user_ctrl; + if (ctrl != NULL) { + mutex_enter(&oplmsu_uinst->c_lock); + stp_queue = WR(ctrl->queue); + mutex_exit(&oplmsu_uinst->c_lock); + noenable(stp_queue); + oplmsu_queue_flag = 1; + } + + mutex_exit(&oplmsu_uinst->l_lock); + mutex_exit(&oplmsu_uinst->u_lock); + rw_exit(&oplmsu_uinst->lock); + oplmsu_cmn_set_mflush(fmp); + putq(dst_queue, fmp); + putq(dst_queue, nmp); + + mutex_enter(&oplmsu_uinst->l_lock); + lpath->sw_flag = 1; + while (lpath->sw_flag != 0) { + /* Wait for the completion of path switching */ + cv_wait(&lpath->sw_cv, &oplmsu_uinst->l_lock); + } + mutex_exit(&oplmsu_uinst->l_lock); + return (SUCCESS); + } else { + oplmsu_clear_ioctl_path(altn_lpath); + oplmsu_clear_ioctl_path(lpath); + mutex_exit(&oplmsu_uinst->l_lock); + mutex_exit(&oplmsu_uinst->u_lock); + rw_exit(&oplmsu_uinst->lock); + freeb(fmp); + freemsg(nmp); + return (FAILURE); + } + /* NOTREACHED */ + } else { + oplmsu_clear_ioctl_path(lpath); + mutex_exit(&oplmsu_uinst->l_lock); + mutex_exit(&oplmsu_uinst->u_lock); + rw_exit(&oplmsu_uinst->lock); + + cmn_err(CE_WARN, "oplmsu: conf-stop: " + "Status of path is improper"); + return (EINVAL); + } + /* NOTREACHED */ +} + +/* Start to use path */ +int +oplmsu_config_start(int pathnum) +{ + upath_t *upath = NULL; + lpath_t *lpath = NULL; + queue_t *dst_queue, *main_rq = NULL; + int msu_tty_port; + + DBG_PRINT((CE_NOTE, + "oplmsu: conf-start: config_start(%d) called", pathnum)); + + rw_enter(&oplmsu_uinst->lock, RW_WRITER); + mutex_enter(&oplmsu_uinst->u_lock); + + if (oplmsu_get_inst_status() == INST_STAT_BUSY) { + mutex_exit(&oplmsu_uinst->u_lock); + rw_exit(&oplmsu_uinst->lock); + return (EBUSY); + } + + if (pathnum == MSU_PATH_ALL) { + (void) oplmsu_search_min_stop_path(); + } + + for (upath = oplmsu_uinst->first_upath; upath; ) { + if ((pathnum != MSU_PATH_ALL) && (upath->path_no != pathnum)) { + upath = upath->u_next; + continue; + } + + if (upath->path_no == pathnum) { + lpath = upath->lpath; + if (lpath == NULL) { + mutex_exit(&oplmsu_uinst->u_lock); + rw_exit(&oplmsu_uinst->lock); + cmn_err(CE_WARN, "oplmsu: conf-start: " + "Proper lpath_t doesn't exist"); + return (EINVAL); + } + + oplmsu_cmn_set_upath_sts(upath, MSU_PSTAT_STANDBY, + upath->status, MSU_STANDBY); + + mutex_enter(&oplmsu_uinst->l_lock); + lpath->src_upath = NULL; + lpath->status = MSU_EXT_NOTUSED; + mutex_exit(&oplmsu_uinst->l_lock); + mutex_exit(&oplmsu_uinst->u_lock); + rw_exit(&oplmsu_uinst->lock); + return (SUCCESS); + } + + /* + * with PATH_ALL + */ + lpath = upath->lpath; + if (lpath == NULL) { + upath = upath->u_next; + + DBG_PRINT((CE_WARN, "oplmsu: conf-start: " + "Proper lpath_t doesn't exist")); + continue; + } + + msu_tty_port = ddi_prop_get_int(DDI_DEV_T_ANY, + oplmsu_uinst->msu_dip, 0, MSU_TTY_PORT_PROP, -1); + + if (upath->ser_devcb.lsb == msu_tty_port) { + /* Notify of the active path changing */ + prom_opl_switch_console(upath->ser_devcb.lsb); + + oplmsu_cmn_set_upath_sts(upath, MSU_PSTAT_ACTIVE, + upath->status, MSU_ACTIVE); + + mutex_enter(&oplmsu_uinst->l_lock); + main_rq = RD(lpath->lower_queue); + dst_queue = WR(lpath->lower_queue); + lpath->src_upath = NULL; + lpath->status = MSU_EXT_NOTUSED; + lpath->uinst = oplmsu_uinst; + mutex_exit(&oplmsu_uinst->l_lock); + + /* Send XON to notify active path */ + (void) oplmsu_cmn_put_xoffxon(dst_queue, MSU_XON_4); + } else { + oplmsu_cmn_set_upath_sts(upath, MSU_PSTAT_STANDBY, + upath->status, MSU_STANDBY); + + mutex_enter(&oplmsu_uinst->l_lock); + lpath->src_upath = NULL; + lpath->status = MSU_EXT_NOTUSED; + mutex_exit(&oplmsu_uinst->l_lock); + } + upath = upath->u_next; + } + + if (main_rq == NULL) { + upath_t *altn_upath; + lpath_t *altn_lpath; + + altn_upath = oplmsu_search_standby(); + if (altn_upath) { + oplmsu_cmn_set_upath_sts(altn_upath, MSU_PSTAT_ACTIVE, + altn_upath->status, MSU_ACTIVE); + + /* Notify of the active path changing */ + prom_opl_switch_console(altn_upath->ser_devcb.lsb); + + altn_lpath = altn_upath->lpath; + if (altn_lpath) { + mutex_enter(&oplmsu_uinst->l_lock); + main_rq = RD(altn_lpath->lower_queue); + dst_queue = WR(altn_lpath->lower_queue); + altn_lpath->src_upath = NULL; + altn_lpath->status = MSU_EXT_NOTUSED; + altn_lpath->uinst = oplmsu_uinst; + mutex_exit(&oplmsu_uinst->l_lock); + + /* Send XON to notify active path */ + (void) oplmsu_cmn_put_xoffxon(dst_queue, + MSU_XON_4); + } else { + cmn_err(CE_WARN, "oplmsu: conf-start: " + "Proper alternate lpath_t doesn't exist"); + } + } else { + cmn_err(CE_WARN, "oplmsu: conf-start: " + "Proper alternate upath_t doesn't exist"); + } + } + + mutex_enter(&oplmsu_uinst->l_lock); + + /* Send XOFF to notify all standby paths */ + oplmsu_cmn_putxoff_standby(); + + /* Change active path of oplmsu */ + oplmsu_uinst->lower_queue = main_rq; + oplmsu_uinst->inst_status = oplmsu_get_inst_status(); + mutex_exit(&oplmsu_uinst->l_lock); + mutex_exit(&oplmsu_uinst->u_lock); + rw_exit(&oplmsu_uinst->lock); + return (SUCCESS); +} + +/* Prepare of unlink path */ +int +oplmsu_config_disc(int pathnum) +{ + upath_t *upath; + lpath_t *lpath; + int use_flag; + + DBG_PRINT((CE_NOTE, + "oplmsu: conf-disc: config_disc(%d) called", pathnum)); + + rw_enter(&oplmsu_uinst->lock, RW_READER); + mutex_enter(&oplmsu_uinst->u_lock); + + upath = oplmsu_search_upath_info(pathnum); + if (upath == NULL) { + mutex_exit(&oplmsu_uinst->u_lock); + rw_exit(&oplmsu_uinst->lock); + cmn_err(CE_WARN, "oplmsu: conf-disc: " + "Proper upath_t doesn't find"); + return (EINVAL); + } + + if ((upath->status == MSU_PSTAT_DISCON) || + (upath->traditional_status == MSU_DISCON)) { + mutex_exit(&oplmsu_uinst->u_lock); + rw_exit(&oplmsu_uinst->lock); + return (SUCCESS); + } else if (((upath->status != MSU_PSTAT_STOP) || + (upath->traditional_status != MSU_STOP)) && + ((upath->status != MSU_PSTAT_FAIL) || + (upath->traditional_status != MSU_FAIL))) { + mutex_exit(&oplmsu_uinst->u_lock); + rw_exit(&oplmsu_uinst->lock); + cmn_err(CE_WARN, "oplmsu: conf-disc: " + "Status of path is improper"); + return (EINVAL); + } + + lpath = upath->lpath; + if (lpath == NULL) { + mutex_exit(&oplmsu_uinst->u_lock); + rw_exit(&oplmsu_uinst->lock); + cmn_err(CE_WARN, "oplmsu: conf-disc: " + "Proper lpath_t doesn't exist"); + return (ENODEV); + } + + mutex_enter(&oplmsu_uinst->l_lock); + + /* Check lower path status */ + use_flag = oplmsu_set_ioctl_path(lpath, NULL, NULL); + if (use_flag == BUSY) { + mutex_exit(&oplmsu_uinst->l_lock); + mutex_exit(&oplmsu_uinst->u_lock); + rw_exit(&oplmsu_uinst->lock); + cmn_err(CE_WARN, "oplmsu: conf-disc: " + "Other processing is using lower path"); + return (EBUSY); + } + + upath->status = MSU_PSTAT_STOP; + upath->traditional_status = MSU_SETID; + + oplmsu_clear_ioctl_path(lpath); + mutex_exit(&oplmsu_uinst->l_lock); + mutex_exit(&oplmsu_uinst->u_lock); + rw_exit(&oplmsu_uinst->lock); + return (SUCCESS); +} diff --git a/usr/src/uts/sun4u/opl/io/oplmsu/oplmsu_cmn_func.c b/usr/src/uts/sun4u/opl/io/oplmsu/oplmsu_cmn_func.c new file mode 100644 index 0000000000..05e7b69bd9 --- /dev/null +++ b/usr/src/uts/sun4u/opl/io/oplmsu/oplmsu_cmn_func.c @@ -0,0 +1,1845 @@ +/* + * 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 + */ +/* + * All Rights Reserved, Copyright (c) FUJITSU LIMITED 2006 + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/errno.h> +#include <sys/modctl.h> +#include <sys/stat.h> +#include <sys/kmem.h> +#include <sys/ksynch.h> +#include <sys/stream.h> +#include <sys/stropts.h> +#include <sys/termio.h> +#include <sys/ddi.h> +#include <sys/file.h> +#include <sys/disp.h> +#include <sys/sunddi.h> +#include <sys/sunldi.h> +#include <sys/sunndi.h> +#include <sys/strsun.h> +#include <sys/oplmsu/oplmsu.h> +#include <sys/oplmsu/oplmsu_proto.h> + +/* + * Link upper_path_table structure + * + * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) + * -. uinst_t->lock : M [RW_WRITER] + * -. uinst_t->u_lock : M + * -. uinst_t->l_lock : A + * -. uinst_t->c_lock : A + */ +void +oplmsu_link_upath(upath_t *add_upath) +{ + + ASSERT(add_upath != NULL); + ASSERT(RW_WRITE_HELD(&oplmsu_uinst->lock)); + ASSERT(MUTEX_HELD(&oplmsu_uinst->u_lock)); + + if (oplmsu_uinst->first_upath == NULL) { + oplmsu_uinst->first_upath = add_upath; + add_upath->u_prev = NULL; + } else { + upath_t *last_upath; + + last_upath = oplmsu_uinst->last_upath; + last_upath->u_next = add_upath; + add_upath->u_prev = last_upath; + } + + oplmsu_uinst->last_upath = add_upath; + add_upath->u_next = NULL; +} + +/* + * Unlink upper_path_table structure + * + * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) + * -. uinst_t->lock : M [RW_WRITER] + * -. uinst_t->u_lock : P + * -. uinst_t->l_lock : P + * -. uinst_t->c_lock : P + */ +void +oplmsu_unlink_upath(upath_t *del_upath) +{ + upath_t **first, **last; + + ASSERT(RW_WRITE_HELD(&oplmsu_uinst->lock)); + + first = &oplmsu_uinst->first_upath; + last = &oplmsu_uinst->last_upath; + + if ((*first != del_upath) && (*last != del_upath)) { + del_upath->u_prev->u_next = del_upath->u_next; + del_upath->u_next->u_prev = del_upath->u_prev; + } else { + if (*first == del_upath) { + *first = (*first)->u_next; + if (*first) { + (*first)->u_prev = NULL; + } + } + + if (*last == del_upath) { + *last = (*last)->u_prev; + if (*last) { + (*last)->u_next = NULL; + } + } + } + + del_upath->u_next = NULL; + del_upath->u_prev = NULL; +} + +/* + * Link lower_path_table structure + * + * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) + * -. uinst_t->lock : M [RW_WRITER] + * -. uinst_t->u_lock : A + * -. uinst_t->l_lock : M + * -. uinst_t->c_lock : A + */ +void +oplmsu_link_lpath(lpath_t *add_lpath) +{ + + ASSERT(add_lpath != NULL); + ASSERT(RW_WRITE_HELD(&oplmsu_uinst->lock)); + + if (oplmsu_uinst->first_lpath == NULL) { + oplmsu_uinst->first_lpath = add_lpath; + add_lpath->l_prev = NULL; + } else { + lpath_t *last_lpath; + + last_lpath = oplmsu_uinst->last_lpath; + last_lpath->l_next = add_lpath; + add_lpath->l_prev = last_lpath; + } + + oplmsu_uinst->last_lpath = add_lpath; + add_lpath->l_next = NULL; +} + +/* + * Unlink lower_path_table structure + * + * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) + * -. uinst_t->lock : M [RW_WRITER] + * -. uinst_t->u_lock : P + * -. uinst_t->l_lock : P + * -. uinst_t->c_lock : P + */ +void +oplmsu_unlink_lpath(lpath_t *del_lpath) +{ + lpath_t **first, **last; + + ASSERT(RW_WRITE_HELD(&oplmsu_uinst->lock)); + + first = &oplmsu_uinst->first_lpath; + last = &oplmsu_uinst->last_lpath; + + if ((*first != del_lpath) && (*last != del_lpath)) { + del_lpath->l_prev->l_next = del_lpath->l_next; + del_lpath->l_next->l_prev = del_lpath->l_prev; + } else { + if (*first == del_lpath) { + *first = (*first)->l_next; + if (*first) { + (*first)->l_prev = NULL; + } + } + + if (*last == del_lpath) { + *last = (*last)->l_prev; + if (*last) { + (*last)->l_next = NULL; + } + } + } + + del_lpath->l_next = NULL; + del_lpath->l_prev = NULL; +} + +/* + * Link msgb structure of high priority + * + * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) + * -. uinst_t->lock : M [RW_READER] + * -. uinst_t->u_lock : A + * -. uinst_t->l_lock : A [It depends on caller] + * -. uinst_t->c_lock : A [It depends on caller] + */ +void +oplmsu_link_high_primsg(mblk_t **first, mblk_t **last, mblk_t *add_msg) +{ + + ASSERT(add_msg != NULL); + ASSERT(RW_READ_HELD(&oplmsu_uinst->lock)); + + if (*first == NULL) { + *first = add_msg; + add_msg->b_prev = NULL; + } else { + (*last)->b_next = add_msg; + add_msg->b_prev = *last; + } + + *last = add_msg; + add_msg->b_next = NULL; +} + +/* + * Check whether lower path is usable by lower path info table address + * + * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) + * -. uinst_t->lock : M [RW_READER or RW_WRITER] + * -. uinst_t->u_lock : A + * -. uinst_t->l_lock : M + * -. uinst_t->c_lock : P + */ +int +oplmsu_check_lpath_usable(void) +{ + lpath_t *lpath; + int rval = SUCCESS; + + ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock)); + ASSERT(MUTEX_HELD(&oplmsu_uinst->l_lock)); + + lpath = oplmsu_uinst->first_lpath; + while (lpath) { + if ((lpath->hndl_uqueue != NULL) || (lpath->hndl_mp != NULL)) { + rval = BUSY; + break; + } + lpath = lpath->l_next; + } + return (rval); +} + +/* + * Search upath_t by path number + * + * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) + * -. uinst_t->lock : M [RW_READER or RW_WRITER] + * -. uinst_t->u_lock : M + * -. uinst_t->l_lock : A + * -. uinst_t->c_lock : P + */ +upath_t * +oplmsu_search_upath_info(int path_no) +{ + upath_t *upath; + + ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock)); + ASSERT(MUTEX_HELD(&oplmsu_uinst->u_lock)); + + upath = oplmsu_uinst->first_upath; + while (upath) { + if (upath->path_no == path_no) { + break; + } + upath = upath->u_next; + } + return (upath); +} + +/* + * Send M_IOCACK(or M_IOCNAK) message to stream + * + * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) + * -. uinst_t->lock : P + * -. uinst_t->u_lock : P + * -. uinst_t->l_lock : P + * -. uinst_t->c_lock : P + */ +void +oplmsu_iocack(queue_t *q, mblk_t *mp, int errno) +{ + struct iocblk *iocp = NULL; + + ASSERT(mp != NULL); + + iocp = (struct iocblk *)mp->b_rptr; + iocp->ioc_error = errno; + + if (errno) { /* Error */ + mp->b_datap->db_type = M_IOCNAK; + iocp->ioc_rval = FAILURE; + + OPLMSU_TRACE(q, mp, MSU_TRC_UO); + qreply(q, mp); + } else { /* Good */ + mp->b_datap->db_type = M_IOCACK; + iocp->ioc_rval = SUCCESS; + + OPLMSU_TRACE(q, mp, MSU_TRC_UO); + qreply(q, mp); + } +} + +/* + * Delete all upath_t + * + * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) + * -. uinst_t->lock : M [RW_WRITER] + * -. uinst_t->u_lock : M + * -. uinst_t->l_lock : A + * -. uinst_t->c_lock : A + */ +void +oplmsu_delete_upath_info(void) +{ + upath_t *upath, *next_upath; + + ASSERT(RW_WRITE_HELD(&oplmsu_uinst->lock)); + ASSERT(MUTEX_HELD(&oplmsu_uinst->u_lock)); + + upath = oplmsu_uinst->first_upath; + oplmsu_uinst->first_upath = NULL; + oplmsu_uinst->last_upath = NULL; + + while (upath) { + next_upath = upath->u_next; + kmem_free(upath, sizeof (upath_t)); + upath = next_upath; + } +} + +/* + * Set queue and ioctl to lpath_t + * + * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) + * -. uinst_t->lock : M [RW_READER or RW_WRITER] + * -. uinst_t->u_lock : A + * -. uinst_t->l_lock : M + * -. uinst_t->c_lock : P + */ +int +oplmsu_set_ioctl_path(lpath_t *lpath, queue_t *hndl_queue, mblk_t *mp) +{ + int rval = SUCCESS; + + ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock)); + ASSERT(MUTEX_HELD(&oplmsu_uinst->l_lock)); + + if ((lpath->hndl_uqueue == NULL) && (lpath->hndl_mp == NULL) && + (lpath->sw_flag == 0)) { + if ((lpath->status == MSU_EXT_NOTUSED) || + (lpath->status == MSU_EXT_ACTIVE_CANDIDATE) || + (lpath->status == MSU_SETID_NU)) { + if (hndl_queue == NULL) { + lpath->hndl_uqueue = hndl_queue; + } else { + lpath->hndl_uqueue = WR(hndl_queue); + } + lpath->hndl_mp = mp; + } else { + rval = BUSY; + } + } else { + rval = BUSY; + } + return (rval); +} + +/* + * Clear queue and ioctl to lpath_t + * + * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) + * -. uinst_t->lock : M [RW_READER or RW_WRITER] + * -. uinst_t->u_lock : A + * -. uinst_t->l_lock : M + * -. uinst_t->c_lock : P + */ +void +oplmsu_clear_ioctl_path(lpath_t *lpath) +{ + + ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock)); + ASSERT(MUTEX_HELD(&oplmsu_uinst->l_lock)); + + lpath->hndl_uqueue = NULL; + lpath->hndl_mp = NULL; +} + +/* + * Get instanse status from status of upath_t + * + * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) + * -. uinst_t->lock : M [RW_READER or RW_WRITER] + * -. uinst_t->u_lock : M + * -. uinst_t->l_lock : A + * -. uinst_t->c_lock : P + */ +int +oplmsu_get_inst_status(void) +{ + upath_t *upath; + int sts, pre_sts = INST_STAT_UNCONFIGURED; + + ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock)); + ASSERT(MUTEX_HELD(&oplmsu_uinst->u_lock)); + + upath = oplmsu_uinst->first_upath; + while (upath) { + if (((upath->status == MSU_PSTAT_ACTIVE) && + (upath->traditional_status == MSU_ACTIVE)) || + ((upath->status == MSU_PSTAT_STANDBY) && + (upath->traditional_status == MSU_STANDBY))) { + sts = INST_STAT_ONLINE; + } else if (((upath->status == MSU_PSTAT_STOP) && + (upath->traditional_status == MSU_STOP)) || + ((upath->status == MSU_PSTAT_FAIL) && + (upath->traditional_status == MSU_FAIL))) { + sts = INST_STAT_OFFLINE; + } else if (((upath->status == MSU_PSTAT_DISCON) && + (upath->traditional_status == MSU_DISCON)) || + ((upath->status == MSU_PSTAT_EMPTY) && + (upath->traditional_status == MSU_EMPTY))) { + sts = INST_STAT_UNCONFIGURED; + } else { + sts = INST_STAT_BUSY; + } + + if (pre_sts > sts) { + pre_sts = sts; + } + upath = upath->u_next; + } + return (pre_sts); +} + +/* + * Search path of "online:standby" status + * + * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) + * -. uinst_t->lock : M [RW_READER or RW_WRITER] + * -. uinst_t->u_lock : M + * -. uinst_t->l_lock : A + * -. uinst_t->c_lock : P + */ +upath_t * +oplmsu_search_standby(void) +{ + upath_t *upath, *altn_upath = NULL; + int max_pathnum = UNDEFINED; + + ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock)); + ASSERT(MUTEX_HELD(&oplmsu_uinst->u_lock)); + + upath = oplmsu_uinst->first_upath; + while (upath) { + if ((upath->status == MSU_PSTAT_STANDBY) && + (upath->traditional_status == MSU_STANDBY) && + (upath->lpath != NULL)) { + if ((max_pathnum == UNDEFINED) || + (max_pathnum > upath->path_no)) { + max_pathnum = upath->path_no; + altn_upath = upath; + } + } + upath = upath->u_next; + } + return (altn_upath); +} + +/* + * Search path of "offline:stop" status, and minimum path number + * + * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) + * -. uinst_t->lock : M [RW_READER or RW_WRITER] + * -. uinst_t->u_lock : M + * -. uinst_t->l_lock : P + * -. uinst_t->c_lock : P + */ +void +oplmsu_search_min_stop_path(void) +{ + upath_t *upath, *min_upath; + lpath_t *lpath; + int min_no = UNDEFINED; + int active_flag = 0; + + ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock)); + ASSERT(MUTEX_HELD(&oplmsu_uinst->u_lock)); + + upath = oplmsu_uinst->first_upath; + while (upath) { + if ((upath->status == MSU_PSTAT_ACTIVE) && + (upath->traditional_status == MSU_ACTIVE)) { + active_flag = 1; + break; + } else if ((upath->status == MSU_PSTAT_STOP) && + (upath->traditional_status == MSU_STOP)) { + if (upath->lpath != NULL) { + if ((min_no == UNDEFINED) || + (upath->path_no < min_no)) { + lpath = upath->lpath; + mutex_enter(&oplmsu_uinst->l_lock); + if (lpath->status == MSU_EXT_NOTUSED) { + min_upath = upath; + min_no = upath->path_no; + } + mutex_exit(&oplmsu_uinst->l_lock); + } + } + } + upath = upath->u_next; + } + + if (active_flag == 0) { + lpath = min_upath->lpath; + mutex_enter(&oplmsu_uinst->l_lock); + lpath->src_upath = NULL; + lpath->status = MSU_EXT_ACTIVE_CANDIDATE; + mutex_exit(&oplmsu_uinst->l_lock); + } +} + +/* + * Get the total number of serial paths + * + * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) + * -. uinst_t->lock : M [RW_WRITER] + * -. uinst_t->u_lock : M + * -. uinst_t->l_lock : A + * -. uinst_t->c_lock : A + */ +int +oplmsu_get_pathnum(void) +{ + upath_t *upath; + int total_num = 0; + + ASSERT(RW_WRITE_HELD(&oplmsu_uinst->lock)); + ASSERT(MUTEX_HELD(&oplmsu_uinst->u_lock)); + + if (oplmsu_uinst->first_upath != NULL) { + upath = oplmsu_uinst->first_upath; + while (upath) { + total_num++; + upath = upath->u_next; + } + } + return (total_num); +} + +/* + * Put XOFF/ XON message on write queue + * + * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) + * -. uinst_t->lock : M [RW_READER or RW_WRITER] + * -. uinst_t->u_lock : A + * -. uinst_t->l_lock : A + * -. uinst_t->c_lock : A + */ +int +oplmsu_cmn_put_xoffxon(queue_t *queue, int data) +{ + mblk_t *mp; + int rval = SUCCESS; + + /* Send M_START */ + if ((mp = allocb(0, BPRI_LO)) != NULL) { + mp->b_datap->db_type = M_START; + putq(queue, mp); + + /* Send M_DATA(XOFF, XON) */ + if ((mp = allocb(sizeof (int), BPRI_LO)) != NULL) { + *(uint_t *)mp->b_rptr = data; + mp->b_wptr = mp->b_rptr + sizeof (int); + putq(queue, mp); + } else { + rval = FAILURE; + } + } else { + rval = FAILURE; + } + return (rval); +} + +/* + * Put XOFF message on write queue for all standby paths + * + * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) + * -. uinst_t->lock : M [RW_READER or RW_WRITER] + * -. uinst_t->u_lock : M + * -. uinst_t->l_lock : M + * -. uinst_t->c_lock : P + */ +void +oplmsu_cmn_putxoff_standby(void) +{ + upath_t *upath; + lpath_t *lpath; + + ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock)); + ASSERT(MUTEX_HELD(&oplmsu_uinst->u_lock)); + ASSERT(MUTEX_HELD(&oplmsu_uinst->l_lock)); + + upath = oplmsu_uinst->first_upath; + while (upath) { + lpath = upath->lpath; + if ((upath->status != MSU_PSTAT_STANDBY) || + (lpath == NULL)) { + upath = upath->u_next; + continue; + } + + (void) oplmsu_cmn_put_xoffxon( + WR(lpath->lower_queue), MSU_XOFF_4); + upath = upath->u_next; + } +} + +/* + * Set M_FLUSH message + * + * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) + * -. uinst_t->lock : A [RW_READER or RW_WRITER] + * -. uinst_t->u_lock : A + * -. uinst_t->l_lock : A + * -. uinst_t->c_lock : A + */ +void +oplmsu_cmn_set_mflush(mblk_t *mp) +{ + + mp->b_datap->db_type = M_FLUSH; + *mp->b_rptr = FLUSHW; + mp->b_wptr = mp->b_rptr + sizeof (char); +} + +/* + * Set status informations of upath_t + * + * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) + * -. uinst_t->lock : M [RW_READER or RW_WRITER] + * -. uinst_t->u_lock : M + * -. uinst_t->l_lock : A + * -. uinst_t->c_lock : A + */ +void +oplmsu_cmn_set_upath_sts(upath_t *upath, int sts, int prev_sts, + ulong_t trad_sts) +{ + + ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock)); + ASSERT(MUTEX_HELD(&oplmsu_uinst->u_lock)); + + upath->status = sts; + upath->prev_status = prev_sts; + upath->traditional_status = trad_sts; +} + +/* + * Allocate a message block + * + * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) + * -. uinst_t->lock : M [RW_READER] + * -. uinst_t->u_lock : A + * -. uinst_t->l_lock : P + * -. uinst_t->c_lock : P + */ +int +oplmsu_cmn_allocmb(queue_t *q, mblk_t *mp, mblk_t **nmp, size_t size, + int rw_flag) +{ + int rval = SUCCESS; + + ASSERT(RW_READ_HELD(&oplmsu_uinst->lock)); + + if ((*nmp = (mblk_t *)allocb(size, BPRI_LO)) == NULL) { + oplmsu_cmn_bufcall(q, mp, size, rw_flag); + rval = FAILURE; + } else { + (*nmp)->b_wptr = (*nmp)->b_rptr + size; + } + return (rval); +} + +/* + * Copy a message + * + * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) + * -. uinst_t->lock : M [RW_READER] + * -. uinst_t->u_lock : A + * -. uinst_t->l_lock : P + * -. uinst_t->c_lock : P + */ +int +oplmsu_cmn_copymb(queue_t *q, mblk_t *mp, mblk_t **nmp, mblk_t *cmp, + int rw_flag) +{ + int rval = SUCCESS; + + ASSERT(RW_READ_HELD(&oplmsu_uinst->lock)); + + if ((*nmp = copymsg(cmp)) == NULL) { + oplmsu_cmn_bufcall(q, mp, msgsize(cmp), rw_flag); + rval = FAILURE; + } + return (rval); +} + +/* + * bufcall request + * + * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) + * -. uinst_t->lock : M [RW_READER] + * -. uinst_t->u_lock : A + * -. uinst_t->l_lock : P + * -. uinst_t->c_lock : P + */ +void +oplmsu_cmn_bufcall(queue_t *q, mblk_t *mp, size_t size, int rw_flag) +{ + + ASSERT(RW_READ_HELD(&oplmsu_uinst->lock)); + + if (rw_flag == MSU_WRITE_SIDE) { + ctrl_t *ctrl; + + putbq(q, mp); + + mutex_enter(&oplmsu_uinst->c_lock); + ctrl = (ctrl_t *)q->q_ptr; + if (ctrl->wbuf_id != 0) { + mutex_exit(&oplmsu_uinst->c_lock); + return; + } + + ctrl->wbuftbl->q = q; + ctrl->wbuftbl->rw_flag = rw_flag; + ctrl->wbuf_id = bufcall(size, BPRI_LO, oplmsu_cmn_bufcb, + (void *)ctrl->wbuftbl); + + if (ctrl->wbuf_id == 0) { + if (ctrl->wtout_id != 0) { + mutex_exit(&oplmsu_uinst->c_lock); + return; + } + + ctrl->wtout_id = timeout(oplmsu_cmn_bufcb, + (void *)ctrl->wbuftbl, drv_usectohz(MSU_TM_500MS)); + } + mutex_exit(&oplmsu_uinst->c_lock); + } else if (rw_flag == MSU_READ_SIDE) { + lpath_t *lpath; + mblk_t *wrk_msg; + + mutex_enter(&oplmsu_uinst->l_lock); + lpath = (lpath_t *)q->q_ptr; + if (mp->b_datap->db_type >= QPCTL) { + if (lpath->first_lpri_hi == NULL) { + lpath->last_lpri_hi = mp; + mp->b_next = NULL; + } else { + wrk_msg = lpath->first_lpri_hi; + wrk_msg->b_prev = mp; + mp->b_next = wrk_msg; + } + mp->b_prev = NULL; + lpath->first_lpri_hi = mp; + } else { + putbq(q, mp); + } + + if (lpath->rbuf_id != 0) { + mutex_exit(&oplmsu_uinst->l_lock); + return; + } + + lpath->rbuftbl->q = q; + lpath->rbuftbl->rw_flag = rw_flag; + lpath->rbuf_id = bufcall(size, BPRI_LO, oplmsu_cmn_bufcb, + (void *)lpath->rbuftbl); + + if (lpath->rbuf_id == 0) { + if (lpath->rtout_id != 0) { + mutex_exit(&oplmsu_uinst->l_lock); + return; + } + + lpath->rtout_id = timeout(oplmsu_cmn_bufcb, + (void *)lpath->rbuftbl, drv_usectohz(MSU_TM_500MS)); + } + mutex_exit(&oplmsu_uinst->l_lock); + } +} + +/* + * Previous sequence for active path change + * + * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) + * -. uinst_t->lock : M [RW_READER] + * -. uinst_t->u_lock : A + * -. uinst_t->l_lock : P + * -. uinst_t->c_lock : P + */ +int +oplmsu_cmn_prechg(queue_t *q, mblk_t *mp, int rw_flag, mblk_t **term_mp, + int *term_ioctl, int *term_stat) +{ + + ASSERT(RW_READ_HELD(&oplmsu_uinst->lock)); + + if (oplmsu_uinst->tcsets_p != NULL) { + struct iocblk *iocp; + + if (oplmsu_cmn_copymb(q, mp, term_mp, oplmsu_uinst->tcsets_p, + rw_flag) == -1) { + return (FAILURE); + } + + iocp = (struct iocblk *)(*term_mp)->b_rptr; + *term_ioctl = iocp->ioc_cmd; + *term_stat = MSU_WTCS_ACK; + } else if (oplmsu_uinst->tiocmset_p != NULL) { + if (oplmsu_cmn_copymb(q, mp, term_mp, oplmsu_uinst->tiocmset_p, + rw_flag) == -1) { + return (FAILURE); + } + + *term_ioctl = TIOCMSET; + *term_stat = MSU_WTMS_ACK; + } else if (oplmsu_uinst->tiocspps_p != NULL) { + if (oplmsu_cmn_copymb(q, mp, term_mp, oplmsu_uinst->tiocspps_p, + rw_flag) == -1) { + return (FAILURE); + } + + *term_ioctl = TIOCSPPS; + *term_stat = MSU_WPPS_ACK; + } else if (oplmsu_uinst->tiocswinsz_p != NULL) { + if (oplmsu_cmn_copymb(q, mp, term_mp, + oplmsu_uinst->tiocswinsz_p, rw_flag) == -1) { + return (FAILURE); + } + + *term_ioctl = TIOCSWINSZ; + *term_stat = MSU_WWSZ_ACK; + } else if (oplmsu_uinst->tiocssoftcar_p != NULL) { + if (oplmsu_cmn_copymb(q, mp, term_mp, + oplmsu_uinst->tiocssoftcar_p, rw_flag) == -1) { + return (FAILURE); + } + + *term_ioctl = TIOCSSOFTCAR; + *term_stat = MSU_WCAR_ACK; + } else { + *term_stat = MSU_WPTH_CHG; + *term_mp = NULL; + } + return (SUCCESS); +} + +/* + * Pick up termios to re-set + * + * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) + * -. uinst_t->lock : M [RW_READER or RW_WRITER] + * -. uinst_t->u_lock : A + * -. uinst_t->l_lock : A + * -. uinst_t->c_lock : A + */ +int +oplmsu_stop_prechg(mblk_t **term_mp, int *term_ioctl, int *term_stat) +{ + + ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock)); + + if (oplmsu_uinst->tcsets_p != NULL) { + struct iocblk *iocp; + + if ((*term_mp = copymsg(oplmsu_uinst->tcsets_p)) == NULL) { + return (FAILURE); + } + + iocp = (struct iocblk *)(*term_mp)->b_rptr; + *term_ioctl = iocp->ioc_cmd; + *term_stat = MSU_WTCS_ACK; + } else if (oplmsu_uinst->tiocmset_p != NULL) { + if ((*term_mp = copymsg(oplmsu_uinst->tiocmset_p)) == NULL) { + return (FAILURE); + } + + *term_ioctl = TIOCMSET; + *term_stat = MSU_WTMS_ACK; + } else if (oplmsu_uinst->tiocspps_p != NULL) { + if ((*term_mp = copymsg(oplmsu_uinst->tiocspps_p)) == NULL) { + return (FAILURE); + } + + *term_ioctl = TIOCSPPS; + *term_stat = MSU_WPPS_ACK; + } else if (oplmsu_uinst->tiocswinsz_p != NULL) { + if ((*term_mp = copymsg(oplmsu_uinst->tiocswinsz_p)) == NULL) { + return (FAILURE); + } + + *term_ioctl = TIOCSWINSZ; + *term_stat = MSU_WWSZ_ACK; + } else if (oplmsu_uinst->tiocssoftcar_p != NULL) { + if ((*term_mp = copymsg(oplmsu_uinst->tiocssoftcar_p)) + == NULL) { + return (FAILURE); + } + + *term_ioctl = TIOCSSOFTCAR; + *term_stat = MSU_WCAR_ACK; + } else { + *term_stat = MSU_WPTH_CHG; + *term_mp = NULL; + } + return (SUCCESS); +} + +/* + * Previous sequence for active path change termio + * + * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) + * -. uinst_t->lock : M [RW_READER] + * -. uinst_t->u_lock : A + * -. uinst_t->l_lock : P + * -. uinst_t->c_lock : P + */ +int +oplmsu_cmn_prechg_termio(queue_t *q, mblk_t *mp, int rw_flag, int prev_flag, + mblk_t **term_mp, int *term_stat) +{ + + ASSERT(RW_READ_HELD(&oplmsu_uinst->lock)); + + if ((prev_flag == MSU_TIOS_TCSETS) && + (oplmsu_uinst->tiocmset_p != NULL)) { + if (oplmsu_cmn_copymb(q, mp, term_mp, oplmsu_uinst->tiocmset_p, + rw_flag) == FAILURE) { + return (FAILURE); + } + + *term_stat = MSU_WTMS_ACK; + } else if ((prev_flag <= MSU_TIOS_MSET) && + (oplmsu_uinst->tiocspps_p != NULL)) { + if (oplmsu_cmn_copymb(q, mp, term_mp, oplmsu_uinst->tiocspps_p, + rw_flag) == FAILURE) { + return (FAILURE); + } + + *term_stat = MSU_WPPS_ACK; + } else if ((prev_flag <= MSU_TIOS_PPS) && + (oplmsu_uinst->tiocswinsz_p != NULL)) { + if (oplmsu_cmn_copymb(q, mp, term_mp, + oplmsu_uinst->tiocswinsz_p, rw_flag) == FAILURE) { + return (FAILURE); + } + + *term_stat = MSU_WWSZ_ACK; + } else if ((prev_flag <= MSU_TIOS_WINSZP) && + (oplmsu_uinst->tiocssoftcar_p != NULL)) { + if (oplmsu_cmn_copymb(q, mp, term_mp, + oplmsu_uinst->tiocssoftcar_p, rw_flag) == FAILURE) { + return (FAILURE); + } + + *term_stat = MSU_WCAR_ACK; + } else if (prev_flag <= MSU_TIOS_SOFTCAR) { + *term_mp = NULL; + *term_stat = MSU_WPTH_CHG; + } + return (SUCCESS); +} + +/* + * Pull up messages + * + * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) + * -. uinst_t->lock : P + * -. uinst_t->u_lock : P + * -. uinst_t->l_lock : P + * -. uinst_t->c_lock : P + */ +int +oplmsu_cmn_pullup_msg(queue_t *q, mblk_t *mp) +{ + mblk_t *nmp = NULL; + + if ((mp != NULL) && (mp->b_cont != NULL) && + (mp->b_cont->b_cont != NULL)) { + if ((nmp = msgpullup(mp->b_cont, -1)) == NULL) { + oplmsu_iocack(q, mp, ENOSR); + return (FAILURE); + } else { + freemsg(mp->b_cont); + mp->b_cont = nmp; + } + } + return (SUCCESS); +} + +/* + * Wake up flow control + * + * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) + * -. uinst_t->lock : M [RW_READER or RW_WRITER] + * -. uinst_t->u_lock : P + * -. uinst_t->l_lock : P + * -. uinst_t->c_lock : P + */ +void +oplmsu_cmn_wakeup(queue_t *q) +{ + ctrl_t *ctrl; + + ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock)); + + mutex_enter(&oplmsu_uinst->c_lock); + ctrl = (ctrl_t *)q->q_ptr; + if (ctrl->sleep_flag == CV_SLEEP) { + ctrl->sleep_flag = CV_WAKEUP; + cv_signal(&ctrl->cvp); + } + mutex_exit(&oplmsu_uinst->c_lock); +} + +/* + * bufcall() and timeout() callback entry for read/write stream + * + * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) + * -. uinst_t->lock : P + * -. uinst_t->u_lock : P + * -. uinst_t->l_lock : P + * -. uinst_t->c_lock : P + */ +void +oplmsu_cmn_bufcb(void *arg) +{ + struct buf_tbl *buftbl = arg; + lpath_t *lpath; + ctrl_t *ctrl; + queue_t *q; + int lq_flag = 0; + + rw_enter(&oplmsu_uinst->lock, RW_WRITER); + mutex_enter(&oplmsu_uinst->l_lock); + + lpath = oplmsu_uinst->first_lpath; + while (lpath) { + if ((buftbl == lpath->rbuftbl) && + (buftbl->rw_flag == MSU_READ_SIDE)) { + if ((lpath->rbuf_id == 0) && (lpath->rtout_id == 0)) { + mutex_exit(&oplmsu_uinst->l_lock); + rw_exit(&oplmsu_uinst->lock); + } else { + q = lpath->rbuftbl->q; + lpath->rbuftbl->q = NULL; + lpath->rbuftbl->rw_flag = UNDEFINED; + + if (lpath->rbuf_id) { + lpath->rbuf_id = 0; + } else { + lpath->rtout_id = 0; + } + mutex_exit(&oplmsu_uinst->l_lock); + + if (oplmsu_queue_flag == 1) { + lq_flag = 1; + oplmsu_queue_flag = 0; + } + + rw_exit(&oplmsu_uinst->lock); + oplmsu_rcmn_high_qenable(q); + + if (lq_flag == 1) { + rw_enter(&oplmsu_uinst->lock, + RW_WRITER); + oplmsu_queue_flag = 1; + rw_exit(&oplmsu_uinst->lock); + } + } + return; + } + lpath = lpath->l_next; + } + mutex_exit(&oplmsu_uinst->l_lock); + + mutex_enter(&oplmsu_uinst->c_lock); + if ((ctrl = oplmsu_uinst->user_ctrl) != NULL) { + if ((buftbl == ctrl->wbuftbl) && + (buftbl->rw_flag == MSU_WRITE_SIDE)) { + oplmsu_wbufcb_posthndl(ctrl); + mutex_exit(&oplmsu_uinst->c_lock); + rw_exit(&oplmsu_uinst->lock); + return; + } + } + + if ((ctrl = oplmsu_uinst->meta_ctrl) != NULL) { + if ((buftbl == ctrl->wbuftbl) && + (buftbl->rw_flag == MSU_WRITE_SIDE)) { + oplmsu_wbufcb_posthndl(ctrl); + mutex_exit(&oplmsu_uinst->c_lock); + rw_exit(&oplmsu_uinst->lock); + return; + } + } + mutex_exit(&oplmsu_uinst->c_lock); + rw_exit(&oplmsu_uinst->lock); +} + +/* + * bufcall() or timeout() callback post handling for write stream + * + * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) + * -. uinst_t->lock : M [RW_WRITER] + * -. uinst_t->u_lock : P + * -. uinst_t->l_lock : P + * -. uinst_t->c_lock : M + */ +void +oplmsu_wbufcb_posthndl(ctrl_t *ctrl) +{ + queue_t *q; + int lq_flag = 0; + + ASSERT(RW_WRITE_HELD(&oplmsu_uinst->lock)); + ASSERT(MUTEX_HELD(&oplmsu_uinst->c_lock)); + + if ((ctrl->wbuf_id == 0) && (ctrl->wtout_id == 0)) { + return; + } + + q = ctrl->wbuftbl->q; + ctrl->wbuftbl->q = NULL; + ctrl->wbuftbl->rw_flag = UNDEFINED; + if (ctrl->wbuf_id) { + ctrl->wbuf_id = 0; + } else { + ctrl->wtout_id = 0; + } + + if (oplmsu_queue_flag == 1) { + lq_flag = 1; + oplmsu_queue_flag = 0; + } + + mutex_exit(&oplmsu_uinst->c_lock); + oplmsu_wcmn_high_qenable(q, RW_WRITER); + mutex_enter(&oplmsu_uinst->c_lock); + + if (lq_flag == 1) { + oplmsu_queue_flag = 1; + } +} + +/* + * COMMON FUNCTIONS FOR WRITE STREAM + */ + +/* + * Check control node and driver privilege + * + * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) + * -. uinst_t->lock : M [RW_READER or RW_WRITER] + * -. uinst_t->u_lock : A + * -. uinst_t->l_lock : A + * -. uinst_t->c_lock : P + */ +int +oplmsu_wcmn_chknode(queue_t *q, int node, mblk_t *mp) +{ + struct iocblk *iocp; + + ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock)); + + mutex_enter(&oplmsu_uinst->c_lock); + if (((ctrl_t *)q->q_ptr)->node_type != node) { + mutex_exit(&oplmsu_uinst->c_lock); + cmn_err(CE_WARN, "oplmsu: chk-node: ctrl node type = %d", node); + return (EINVAL); + } + mutex_exit(&oplmsu_uinst->c_lock); + + /* Check super-user by oplmsu.conf */ + if (oplmsu_check_su != 0) { + iocp = (struct iocblk *)mp->b_rptr; + if (drv_priv(iocp->ioc_cr) != 0) { + cmn_err(CE_WARN, "oplmsu: chk-node: Permission denied"); + return (EPERM); + } + } + return (SUCCESS); +} + +/* + * Flush handle for write side stream + * + * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) + * -. uinst_t->lock : M [RW_READER or RW_WRITER] + * -. uinst_t->u_lock : P + * -. uinst_t->l_lock : P + * -. uinst_t->c_lock : P + */ +void +oplmsu_wcmn_flush_hndl(queue_t *q, mblk_t *mp, krw_t rw) +{ + queue_t *dst_queue = NULL; + + ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock)); + + if (*mp->b_rptr & FLUSHW) { /* Write side */ + flushq(q, FLUSHDATA); + } + + dst_queue = oplmsu_uinst->lower_queue; + if (dst_queue == NULL) { + if (*mp->b_rptr & FLUSHR) { + flushq(RD(q), FLUSHDATA); + *mp->b_rptr &= ~FLUSHW; + + rw_exit(&oplmsu_uinst->lock); + OPLMSU_TRACE(q, mp, MSU_TRC_UO); + qreply(q, mp); + rw_enter(&oplmsu_uinst->lock, rw); + } else { + freemsg(mp); + } + } else { + putq(WR(dst_queue), mp); + } +} + +/* + * Through message handle for write side stream + * + * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) + * -. uinst_t->lock : M [RW_READER or RW_WRITER] + * -. uinst_t->u_lock : P + * -. uinst_t->l_lock : P + * -. uinst_t->c_lock : P + */ +int +oplmsu_wcmn_through_hndl(queue_t *q, mblk_t *mp, int pri_flag, krw_t rw) +{ + queue_t *usr_queue = NULL, *dst_queue = NULL; + ctrl_t *ctrl; + + ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock)); + + mutex_enter(&oplmsu_uinst->c_lock); + if ((ctrl = oplmsu_uinst->user_ctrl) != NULL) { + usr_queue = ctrl->queue; + mutex_exit(&oplmsu_uinst->c_lock); + } else { + mutex_exit(&oplmsu_uinst->c_lock); + if (mp->b_datap->db_type == M_IOCTL) { + rw_exit(&oplmsu_uinst->lock); + oplmsu_iocack(q, mp, ENODEV); + rw_enter(&oplmsu_uinst->lock, rw); + } else { + freemsg(mp); + } + return (SUCCESS); + } + + if (oplmsu_uinst->lower_queue != NULL) { + dst_queue = WR(oplmsu_uinst->lower_queue); + } else { + cmn_err(CE_WARN, "!oplmsu: through-lwq: " + "Active path doesn't exist"); + + if (mp->b_datap->db_type == M_IOCTL) { + rw_exit(&oplmsu_uinst->lock); + oplmsu_iocack(q, mp, ENODEV); + rw_enter(&oplmsu_uinst->lock, rw); + } else { + freemsg(mp); + } + return (SUCCESS); + } + + if ((usr_queue == WR(q)) || (usr_queue == RD(q))) { + if (pri_flag == MSU_HIGH) { + putq(dst_queue, mp); + } else { + if (canput(dst_queue)) { + putq(dst_queue, mp); + } else { + oplmsu_wcmn_norm_putbq(WR(q), mp, dst_queue); + return (FAILURE); + } + } + } else { + cmn_err(CE_WARN, "oplmsu: through-lwq: " + "Inappropriate message for this node"); + + if (mp->b_datap->db_type == M_IOCTL) { + rw_exit(&oplmsu_uinst->lock); + oplmsu_iocack(q, mp, ENODEV); + rw_enter(&oplmsu_uinst->lock, rw); + } else { + freemsg(mp); + } + } + return (SUCCESS); +} + +/* + * Get high priority message from buffer for upper write stream + * + * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) + * -. uinst_t->lock : M [RW_READER or RW_WRITER] + * -. uinst_t->u_lock : A + * -. uinst_t->l_lock : A + * -. uinst_t->c_lock : P + */ +mblk_t * +oplmsu_wcmn_high_getq(queue_t *uwq) +{ + mblk_t *mp; + ctrl_t *ctrl; + + ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock)); + + mutex_enter(&oplmsu_uinst->c_lock); + ctrl = (ctrl_t *)uwq->q_ptr; + mp = ctrl->first_upri_hi; + if (mp != NULL) { + if (mp->b_next == NULL) { + ctrl->first_upri_hi = NULL; + ctrl->last_upri_hi = NULL; + } else { + ctrl->first_upri_hi = mp->b_next; + mp->b_next->b_prev = NULL; + mp->b_next = NULL; + } + mp->b_prev = NULL; + } + mutex_exit(&oplmsu_uinst->c_lock); + return (mp); +} + +/* + * putbq() function for normal priority message of write stream + * + * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) + * -. uinst_t->lock : M [RW_READER or RW_WRITER] + * -. uinst_t->u_lock : A + * -. uinst_t->l_lock : P + * -. uinst_t->c_lock : P + */ +void +oplmsu_wcmn_norm_putbq(queue_t *uwq, mblk_t *mp, queue_t *dq) +{ + lpath_t *lpath; + + ASSERT(mp != NULL); + ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock)); + + mutex_enter(&oplmsu_uinst->l_lock); + lpath = (lpath_t *)dq->q_ptr; + lpath->uwq_flag = 1; + lpath->uwq_queue = uwq; + mutex_exit(&oplmsu_uinst->l_lock); + putbq(uwq, mp); +} + +/* + * Restart queuing for high priority message of write stream when flow control + * failed + * + * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) + * -. uinst_t->lock : M [RW_READER or RW_WRITER] + * -. uinst_t->u_lock : P + * -. uinst_t->l_lock : P + * -. uinst_t->c_lock : P + */ +void +oplmsu_wcmn_high_qenable(queue_t *q, krw_t rw) +{ + mblk_t *mp; + + ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock)); + + if (oplmsu_queue_flag == 1) { + return; + } + + /* Handle high priority message */ + while (mp = oplmsu_wcmn_high_getq(WR(q))) { + if (mp->b_datap->db_type & M_FLUSH) { + oplmsu_wcmn_flush_hndl(q, mp, rw); + continue; + } + + if (oplmsu_wcmn_through_hndl(q, mp, MSU_HIGH, rw) == FAILURE) { + return; + } + } + qenable(WR(q)); /* enable upper write queue */ +} + +/* + * COMMON FUNCTIONS FOR READ STREAM + */ + +/* + * Flush handle for read side stream + * + * Requires lock ( M: mandatory P: prohibited A: allowed + * -. uinst_t->lock : M [RW_READER] + * -. uinst_t->u_lock : P + * -. uinst_t->l_lock : P + * -. uinst_t->c_lock : P + */ +void +oplmsu_rcmn_flush_hndl(queue_t *q, mblk_t *mp) +{ + queue_t *dst_queue = NULL; + ctrl_t *ctrl; + + ASSERT(RW_READ_HELD(&oplmsu_uinst->lock)); + + if (*mp->b_rptr & FLUSHR) { + /* Remove only data messages from read queue */ + flushq(q, FLUSHDATA); + } + + mutex_enter(&oplmsu_uinst->c_lock); + if ((ctrl = oplmsu_uinst->user_ctrl) != NULL) { + dst_queue = RD(ctrl->queue); + mutex_exit(&oplmsu_uinst->c_lock); + + if (dst_queue != NULL) { + putq(dst_queue, mp); + } else { + if (*mp->b_rptr & FLUSHW) { + flushq(WR(q), FLUSHDATA); + *mp->b_rptr &= ~FLUSHR; + + rw_exit(&oplmsu_uinst->lock); + OPLMSU_TRACE(q, mp, MSU_TRC_LO); + qreply(q, mp); + rw_enter(&oplmsu_uinst->lock, RW_READER); + } else { + freemsg(mp); + } + } + } else { + mutex_exit(&oplmsu_uinst->c_lock); + if (*mp->b_rptr & FLUSHW) { + flushq(WR(q), FLUSHDATA); + *mp->b_rptr &= ~FLUSHR; + + rw_exit(&oplmsu_uinst->lock); + OPLMSU_TRACE(q, mp, MSU_TRC_LO); + qreply(q, mp); + rw_enter(&oplmsu_uinst->lock, RW_READER); + } else { + freemsg(mp); + } + } +} + +/* + * Through message handle for read side stream + * + * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) + * -. uinst_t->lock : M [RW_READER] + * -. uinst_t->u_lock : A + * -. uinst_t->l_lock : P + * -. uinst_t->c_lock : P + */ +int +oplmsu_rcmn_through_hndl(queue_t *q, mblk_t *mp, int pri_flag) +{ + lpath_t *lpath; + ctrl_t *ctrl; + queue_t *dst_queue = NULL; + int act_flag; + + ASSERT(RW_READ_HELD(&oplmsu_uinst->lock)); + + mutex_enter(&oplmsu_uinst->l_lock); + lpath = (lpath_t *)q->q_ptr; + if (lpath->uinst != NULL) { + act_flag = ACTIVE_RES; + } else { + act_flag = NOT_ACTIVE_RES; + } + mutex_exit(&oplmsu_uinst->l_lock); + + mutex_enter(&oplmsu_uinst->c_lock); + if (((ctrl = oplmsu_uinst->user_ctrl) != NULL) && + (((mp->b_datap->db_type == M_IOCACK) || + (mp->b_datap->db_type == M_IOCNAK)) || (act_flag == ACTIVE_RES))) { + dst_queue = RD(ctrl->queue); + } else { + mutex_exit(&oplmsu_uinst->c_lock); + freemsg(mp); + return (SUCCESS); + } + + if (pri_flag == MSU_HIGH) { + putq(dst_queue, mp); + } else { + if (canput(dst_queue)) { + putq(dst_queue, mp); + } else { + /* + * Place a normal priority message at the head of + * read queue + */ + + ctrl = (ctrl_t *)dst_queue->q_ptr; + ctrl->lrq_flag = 1; + ctrl->lrq_queue = q; + mutex_exit(&oplmsu_uinst->c_lock); + putbq(q, mp); + return (FAILURE); + } + } + mutex_exit(&oplmsu_uinst->c_lock); + return (SUCCESS); +} + +/* + * Restart queuing for high priority message of read stream + * when flow control failed + * + * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) + * -. uinst_t->lock : P + * -. uinst_t->u_lock : P + * -. uinst_t->l_lock : P + * -. uinst_t->c_lock : P + */ +void +oplmsu_rcmn_high_qenable(queue_t *q) +{ + mblk_t *mp; + struct iocblk *iocp = NULL; + lpath_t *lpath; + int rval; + + rw_enter(&oplmsu_uinst->lock, RW_READER); + + for (;;) { /* Handle high priority message */ + mutex_enter(&oplmsu_uinst->l_lock); + lpath = (lpath_t *)q->q_ptr; + if ((mp = lpath->first_lpri_hi) == NULL) { + mutex_exit(&oplmsu_uinst->l_lock); + break; + } + + if (mp->b_next == NULL) { + lpath->first_lpri_hi = NULL; + lpath->last_lpri_hi = NULL; + } else { + lpath->first_lpri_hi = mp->b_next; + mp->b_next->b_prev = NULL; + mp->b_next = NULL; + } + mp->b_prev = NULL; + mutex_exit(&oplmsu_uinst->l_lock); + + rval = SUCCESS; + switch (mp->b_datap->db_type) { + case M_IOCACK : /* FALLTHRU */ + case M_IOCNAK : + iocp = (struct iocblk *)mp->b_rptr; + switch (iocp->ioc_cmd) { + case TCSETS : /* FALLTHRU */ + case TCSETSW : /* FALLTHRU */ + case TCSETSF : /* FALLTHRU */ + case TIOCMSET : /* FALLTHRU */ + case TIOCSPPS : /* FALLTHRU */ + case TIOCSWINSZ : /* FALLTHRU */ + case TIOCSSOFTCAR : + rw_exit(&oplmsu_uinst->lock); + rval = oplmsu_lrioctl_termios(q, mp); + rw_enter(&oplmsu_uinst->lock, RW_WRITER); + break; + + default : + rval = oplmsu_rcmn_through_hndl( + q, mp, MSU_HIGH); + if (rval == FAILURE) { + rw_exit(&oplmsu_uinst->lock); + return; + } + } + break; + + case M_ERROR : + rw_exit(&oplmsu_uinst->lock); + rval = oplmsu_lrmsg_error(q, mp); + rw_enter(&oplmsu_uinst->lock, RW_WRITER); + break; + + case M_FLUSH : + oplmsu_rcmn_flush_hndl(q, mp); + break; + + default : + rval = oplmsu_rcmn_through_hndl(q, mp, MSU_HIGH); + if (rval == FAILURE) { + rw_exit(&oplmsu_uinst->lock); + return; + } + } + + if (rval == FAILURE) { + break; + } + } + + rw_exit(&oplmsu_uinst->lock); + qenable(q); /* Enable lower read queue */ +} + +#ifdef DEBUG +/* + * Online trace + * + * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) + * -. uinst_t->lock : P + * -. uinst_t->u_lock : P + * -. uinst_t->l_lock : P + * -. uinst_t->c_lock : P + */ +void +oplmsu_cmn_trace(queue_t *q, mblk_t *mp, int op) +{ + struct iocblk *iocp; + + if ((op < MSU_TRC_UI) || (op > MSU_TRC_CLS)) { + return; + } + + mutex_enter(&oplmsu_ltrc_lock); + + if (oplmsu_debug_mode & MSU_DPRINT_ON) { + oplmsu_cmn_msglog(mp, op); + } + + /* Trace current counter */ + drv_getparm(LBOLT, (void *)&oplmsu_ltrc_ccnt); + + if (oplmsu_ltrc_cur == oplmsu_ltrc_tail) { + oplmsu_ltrc_cur = oplmsu_ltrc_top; + } else { + oplmsu_ltrc_cur++; + } + oplmsu_ltrc_cur->q = q; + oplmsu_ltrc_cur->mp = mp; + + switch (op) { + case MSU_TRC_UI : + oplmsu_ltrc_cur->op[0] = 'u'; + oplmsu_ltrc_cur->op[1] = 'i'; + break; + + case MSU_TRC_UO : + oplmsu_ltrc_cur->op[0] = 'u'; + oplmsu_ltrc_cur->op[1] = 'o'; + break; + + case MSU_TRC_LI : + oplmsu_ltrc_cur->op[0] = 'l'; + oplmsu_ltrc_cur->op[1] = 'i'; + break; + + case MSU_TRC_LO : + oplmsu_ltrc_cur->op[0] = 'l'; + oplmsu_ltrc_cur->op[1] = 'o'; + break; + + case MSU_TRC_OPN : + oplmsu_ltrc_cur->op[0] = 'o'; + oplmsu_ltrc_cur->op[1] = 'p'; + break; + + case MSU_TRC_CLS : + oplmsu_ltrc_cur->op[0] = 'c'; + oplmsu_ltrc_cur->op[1] = 'l'; + break; + } + + if ((op == MSU_TRC_LI) || (op == MSU_TRC_LO)) { + mutex_enter(&oplmsu_uinst->l_lock); + oplmsu_ltrc_cur->pathno = ((lpath_t *)q->q_ptr)->path_no; + mutex_exit(&oplmsu_uinst->l_lock); + } else { + oplmsu_ltrc_cur->pathno = 0; + } + + if ((op == MSU_TRC_OPN) || (op == MSU_TRC_CLS)) { + oplmsu_ltrc_cur->msg_type = 0; + oplmsu_ltrc_cur->msg_cmd = 0; + oplmsu_ltrc_cur->data = 0; + + switch ((ulong_t)mp) { + case MSU_NODE_USER : + oplmsu_ltrc_cur->data = MSU_TRC_USER; + break; + + case MSU_NODE_META : + oplmsu_ltrc_cur->data = MSU_TRC_META; + break; + } + oplmsu_ltrc_cur->mp = NULL; + } else { + oplmsu_ltrc_cur->msg_type = mp->b_datap->db_type; + iocp = (struct iocblk *)mp->b_rptr; + oplmsu_ltrc_cur->msg_cmd = iocp->ioc_cmd; + + if ((mp->b_datap->db_type == M_IOCTL) || + (mp->b_datap->db_type == M_IOCACK) || + (mp->b_datap->db_type == M_IOCNAK)) { + oplmsu_ltrc_cur->msg_cmd = iocp->ioc_cmd; + + if (mp->b_cont != NULL) { + oplmsu_ltrc_cur->data = + (ulong_t)mp->b_cont->b_rptr; + } else { + oplmsu_ltrc_cur->data = 0; + } + } else { + oplmsu_ltrc_cur->msg_cmd = 0; + + if (mp->b_rptr == NULL) { + oplmsu_ltrc_cur->data = 0; + } else { + oplmsu_ltrc_cur->data = *(ulong_t *)mp->b_rptr; + } + } + } + mutex_exit(&oplmsu_ltrc_lock); +} + +/* + * Display message log to console + * + * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed )) + * -. uinst_t->lock : P + * -. uinst_t->u_lock : P + * -. uinst_t->l_lock : P + * -. uinst_t->c_lock : P + */ +void +oplmsu_cmn_msglog(mblk_t *mp, int direction) +{ + uchar_t *cur = NULL; + mblk_t *tmp_mp = NULL; + ulong_t len; + ulong_t line; + ulong_t col; + ulong_t row; + ulong_t count; + char buffer[70]; + char *bufp; + + if (mp == NULL) { + return; + } + + switch (direction) { + case 0: + cmn_err(CE_NOTE, "!---------- Upper in --------"); + break; + + case 1: + cmn_err(CE_NOTE, "!---------- Upper out -------"); + break; + + case 2: + cmn_err(CE_NOTE, "!---------- Lower in --------"); + break; + + case 3: + cmn_err(CE_NOTE, "!---------- Lower out -------"); + break; + + default: + return; + } + + for (tmp_mp = mp; tmp_mp; tmp_mp = tmp_mp->b_cont) { + cmn_err(CE_NOTE, "!db_type = 0x%02x", tmp_mp->b_datap->db_type); + + len = tmp_mp->b_wptr - tmp_mp->b_rptr; + line = (len + 31) / 32; + cur = (uchar_t *)tmp_mp->b_rptr; + count = 0; + + for (col = 0; col < line; col++) { + bufp = buffer; + + for (row = 0; row < 32; row++) { + if (row != 0 && (row % 8) == 0) { + *bufp = ' '; + bufp++; + } + sprintf(bufp, "%02x", *cur); + bufp += 2; + cur++; + count++; + + if (count >= len) { + break; + } + } + *bufp = '\0'; + cmn_err(CE_NOTE, "!%s", buffer); + + if (count >= len) { + break; + } + } + } +} + +void +oplmsu_cmn_prt_pathname(dev_info_t *dip) +{ + char pathname[128]; + char wrkbuf[128]; + + ddi_pathname(dip, wrkbuf); + *(wrkbuf + strlen(wrkbuf)) = '\0'; + sprintf(pathname, "/devices%s:%c", wrkbuf, 'a'+ ddi_get_instance(dip)); + + DBG_PRINT((CE_NOTE, "oplmsu: debug-info: " + "Active path change to path => %s", pathname)); +} +#endif diff --git a/usr/src/uts/sun4u/opl/io/oplmsu/oplmsu_ioctl_lrp.c b/usr/src/uts/sun4u/opl/io/oplmsu/oplmsu_ioctl_lrp.c new file mode 100644 index 0000000000..28df173a08 --- /dev/null +++ b/usr/src/uts/sun4u/opl/io/oplmsu/oplmsu_ioctl_lrp.c @@ -0,0 +1,780 @@ +/* + * 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 + */ +/* + * All Rights Reserved, Copyright (c) FUJITSU LIMITED 2006 + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/errno.h> +#include <sys/modctl.h> +#include <sys/stat.h> +#include <sys/kmem.h> +#include <sys/ksynch.h> +#include <sys/stream.h> +#include <sys/stropts.h> +#include <sys/termio.h> +#include <sys/ddi.h> +#include <sys/file.h> +#include <sys/disp.h> +#include <sys/sunddi.h> +#include <sys/sunldi.h> +#include <sys/sunndi.h> +#include <sys/prom_plat.h> +#include <sys/oplmsu/oplmsu.h> +#include <sys/oplmsu/oplmsu_proto.h> + +/* + * LOWER READ SERVICE PROCEDURE + */ + +/* termios ioctl response received */ +int +oplmsu_lrioctl_termios(queue_t *lrq, mblk_t *mp) +{ + upath_t *upath, *altn_upath = NULL, *stp_upath = NULL; + lpath_t *lpath, *altn_lpath = NULL, *stp_lpath = NULL; + struct iocblk *iocp, *temp_iocp = NULL; + mblk_t *hndl_mp, *nmp = NULL, *fmp = NULL; + queue_t *dst_queue; + int term_ioctl, term_stat, sts; + int ack_flag, termio_flag, chkflag; + ulong_t trad_sts; + + rw_enter(&oplmsu_uinst->lock, RW_READER); + iocp = (struct iocblk *)mp->b_rptr; + + mutex_enter(&oplmsu_uinst->u_lock); + mutex_enter(&oplmsu_uinst->l_lock); + lpath = (lpath_t *)lrq->q_ptr; + hndl_mp = lpath->hndl_mp; + + upath = oplmsu_search_upath_info(lpath->path_no); + trad_sts = upath->traditional_status; + mutex_exit(&oplmsu_uinst->l_lock); + mutex_exit(&oplmsu_uinst->u_lock); + + if (((iocp->ioc_cmd == TCSETS) && (trad_sts == MSU_WTCS_ACK)) || + ((iocp->ioc_cmd == TCSETSW) && (trad_sts == MSU_WTCS_ACK)) || + ((iocp->ioc_cmd == TCSETSF) && (trad_sts == MSU_WTCS_ACK)) || + ((iocp->ioc_cmd == TIOCMSET) && (trad_sts == MSU_WTMS_ACK)) || + ((iocp->ioc_cmd == TIOCSPPS) && (trad_sts == MSU_WPPS_ACK)) || + ((iocp->ioc_cmd == TIOCSWINSZ) && (trad_sts == MSU_WWSZ_ACK)) || + ((iocp->ioc_cmd == TIOCSSOFTCAR) && (trad_sts == MSU_WCAR_ACK))) { + if (mp->b_datap->db_type == M_IOCACK) { + ack_flag = ACK_RES; + } else { + ack_flag = NAK_RES; + } + } else { + rw_exit(&oplmsu_uinst->lock); + freemsg(mp); + cmn_err(CE_WARN, "oplmsu: lr-termios: " + "Status of path is improper"); + return (SUCCESS); + } + + switch (trad_sts) { + case MSU_WTCS_ACK : + termio_flag = MSU_TIOS_TCSETS; + break; + + case MSU_WTMS_ACK : + termio_flag = MSU_TIOS_MSET; + break; + + case MSU_WPPS_ACK : + termio_flag = MSU_TIOS_PPS; + break; + + case MSU_WWSZ_ACK : + termio_flag = MSU_TIOS_WINSZP; + break; + + case MSU_WCAR_ACK : + termio_flag = MSU_TIOS_SOFTCAR; + break; + + default : + termio_flag = MSU_TIOS_END; + break; + } + + if (hndl_mp == NULL) { + switch (trad_sts) { + case MSU_WTCS_ACK : /* FALLTHRU */ + case MSU_WTMS_ACK : /* FALLTHRU */ + case MSU_WPPS_ACK : /* FALLTHRU */ + case MSU_WWSZ_ACK : /* FALLTHRU */ + case MSU_WCAR_ACK : + chkflag = MSU_CMD_STOP; + break; + + default : + chkflag = FAILURE; + break; + } + } else { + /* xoff/xon received */ + if (hndl_mp->b_datap->db_type == M_DATA) { + chkflag = MSU_CMD_ACTIVE; + } else { /* Normal termios */ + temp_iocp = (struct iocblk *)hndl_mp->b_rptr; + chkflag = temp_iocp->ioc_cmd; + } + } + + if ((chkflag == MSU_CMD_ACTIVE) || (chkflag == MSU_CMD_STOP)) { + if (ack_flag == ACK_RES) { /* M_IOCACK received */ + ctrl_t *ctrl; + + if (oplmsu_cmn_prechg_termio(lrq, mp, MSU_READ_SIDE, + termio_flag, &nmp, &term_stat) == FAILURE) { + rw_exit(&oplmsu_uinst->lock); + return (FAILURE); + } + + OPLMSU_RWLOCK_UPGRADE(); + mutex_enter(&oplmsu_uinst->u_lock); + if (term_stat != MSU_WPTH_CHG) { + upath->traditional_status = term_stat; + mutex_exit(&oplmsu_uinst->u_lock); + rw_exit(&oplmsu_uinst->lock); + freemsg(mp); + + OPLMSU_TRACE(RD(lrq), nmp, MSU_TRC_LO); + + /* Continue sending termios ioctls */ + qreply(RD(lrq), nmp); + return (SUCCESS); + } + freemsg(mp); + + /* Change status of new active path */ + oplmsu_cmn_set_upath_sts(upath, MSU_PSTAT_ACTIVE, + upath->status, MSU_ACTIVE); + + mutex_enter(&oplmsu_uinst->l_lock); + lpath->uinst = oplmsu_uinst; + dst_queue = lpath->hndl_uqueue; + + ctrl = oplmsu_uinst->user_ctrl; + if ((chkflag == MSU_CMD_ACTIVE) && (hndl_mp != NULL)) { + /* Put a message(M_DATA) on a queue */ + if (ctrl != NULL) { + mutex_enter(&oplmsu_uinst->c_lock); + putq(RD(ctrl->queue), hndl_mp); + mutex_exit(&oplmsu_uinst->c_lock); + } + } + + oplmsu_clear_ioctl_path(lpath); + stp_upath = lpath->src_upath; + lpath->src_upath = NULL; + lpath->status = MSU_EXT_NOTUSED; + + /* Notify of the active path changing */ + prom_opl_switch_console(upath->ser_devcb.lsb); + + /* Send XON to notify active path */ + (void) oplmsu_cmn_put_xoffxon(WR(lrq), MSU_XON_4); + + stp_lpath = stp_upath->lpath; + stp_lpath->uinst = NULL; + oplmsu_clear_ioctl_path(stp_lpath); + stp_lpath->src_upath = NULL; + stp_lpath->status = MSU_EXT_NOTUSED; + + /* Change status of stopped or old-active path */ + if (chkflag == MSU_CMD_STOP) { + sts = MSU_PSTAT_STOP; + trad_sts = MSU_STOP; + } else { /* == MSU_CMD_ACTIVE */ + sts = MSU_PSTAT_STANDBY; + trad_sts = MSU_STANDBY; + } + oplmsu_cmn_set_upath_sts(stp_upath, sts, + stp_upath->status, trad_sts); + + /* Send XOFF to notify all standby paths */ + oplmsu_cmn_putxoff_standby(); + oplmsu_uinst->lower_queue = lrq; + oplmsu_uinst->inst_status = oplmsu_get_inst_status(); + mutex_exit(&oplmsu_uinst->l_lock); + mutex_exit(&oplmsu_uinst->u_lock); + + /* Change active path of user node */ + if (ctrl != NULL) { + queue_t *temp_queue; + + mutex_enter(&oplmsu_uinst->c_lock); + temp_queue = WR(ctrl->queue); + mutex_exit(&oplmsu_uinst->c_lock); + + /* Reschedule a queue for service */ + enableok(temp_queue); + + oplmsu_queue_flag = 0; + oplmsu_wcmn_high_qenable(temp_queue, RW_WRITER); + } + rw_exit(&oplmsu_uinst->lock); + + if (nmp != NULL) { + freemsg(nmp); + } + + /* Wake up oplmsu_config_stop */ + mutex_enter(&oplmsu_uinst->l_lock); + if (stp_lpath->sw_flag) { + stp_lpath->sw_flag = 0; + cv_signal(&stp_lpath->sw_cv); + } + mutex_exit(&oplmsu_uinst->l_lock); + return (SUCCESS); + } else { /* M_IOCNAK received */ + mutex_enter(&oplmsu_uinst->u_lock); + mutex_enter(&oplmsu_uinst->l_lock); + if ((chkflag == MSU_CMD_ACTIVE) && + (lpath->hndl_uqueue == NULL)) { + oplmsu_clear_ioctl_path(lpath); + stp_upath = lpath->src_upath; + lpath->src_upath = NULL; + lpath->status = MSU_EXT_NOTUSED; + mutex_exit(&oplmsu_uinst->l_lock); + + oplmsu_cmn_set_upath_sts(upath, + MSU_PSTAT_STANDBY, upath->status, + MSU_STANDBY); + mutex_exit(&oplmsu_uinst->u_lock); + + if (hndl_mp != NULL) { + freemsg(hndl_mp); + } + + OPLMSU_RWLOCK_UPGRADE(); + mutex_enter(&oplmsu_uinst->u_lock); + oplmsu_uinst->inst_status = + oplmsu_get_inst_status(); + mutex_exit(&oplmsu_uinst->u_lock); + rw_exit(&oplmsu_uinst->lock); + return (SUCCESS); + } else if ((chkflag == MSU_CMD_STOP) && + (lpath->src_upath != NULL) && + (lpath->src_upath->lpath->sw_flag)) { + /* MSU_CMD_STOP for active path */ + + dst_queue = RD(lpath->hndl_uqueue); + stp_upath = lpath->src_upath; + + /* Search alternate path from standby paths */ + altn_upath = oplmsu_search_standby(); + if (altn_upath == NULL) { + altn_upath = upath; + } + + mutex_exit(&oplmsu_uinst->l_lock); + if (oplmsu_cmn_allocmb(lrq, mp, &fmp, + sizeof (char), MSU_READ_SIDE) == FAILURE) { + mutex_exit(&oplmsu_uinst->u_lock); + rw_exit(&oplmsu_uinst->lock); + return (FAILURE); + } + + if (oplmsu_cmn_prechg(lrq, mp, MSU_READ_SIDE, + &nmp, &term_ioctl, &term_stat) == FAILURE) { + mutex_exit(&oplmsu_uinst->u_lock); + rw_exit(&oplmsu_uinst->lock); + freeb(fmp); + return (FAILURE); + } + + altn_upath->traditional_status = term_stat; + altn_lpath = altn_upath->lpath; + + mutex_enter(&oplmsu_uinst->l_lock); + altn_lpath->hndl_mp = hndl_mp; + altn_lpath->hndl_uqueue = dst_queue; + altn_lpath->src_upath = stp_upath; + altn_lpath->status = MSU_EXT_VOID; + dst_queue = RD(altn_lpath->lower_queue); + + oplmsu_cmn_set_upath_sts(upath, MSU_PSTAT_FAIL, + upath->status, MSU_FAIL); + + oplmsu_clear_ioctl_path(lpath); + lpath->src_upath = NULL; + lpath->status = MSU_EXT_NOTUSED; + mutex_exit(&oplmsu_uinst->l_lock); + mutex_exit(&oplmsu_uinst->u_lock); + + OPLMSU_RWLOCK_UPGRADE(); + mutex_enter(&oplmsu_uinst->u_lock); + oplmsu_uinst->inst_status = + oplmsu_get_inst_status(); + mutex_exit(&oplmsu_uinst->u_lock); + rw_exit(&oplmsu_uinst->lock); + freemsg(mp); + oplmsu_cmn_set_mflush(fmp); + + OPLMSU_TRACE(dst_queue, fmp, MSU_TRC_LO); + qreply(dst_queue, fmp); + + OPLMSU_TRACE(dst_queue, nmp, MSU_TRC_LO); + qreply(dst_queue, nmp); + return (SUCCESS); + } + } + } else if ((chkflag == TCSETS) || (chkflag == TCSETSW) || + (chkflag == TCSETSF) || (chkflag == TIOCMSET) || + (chkflag == TIOCSPPS) || (chkflag == TIOCSWINSZ) || + (chkflag == TIOCSSOFTCAR)) { + mutex_enter(&oplmsu_uinst->u_lock); + mutex_enter(&oplmsu_uinst->l_lock); + + if ((ack_flag == ACK_RES) && + (lpath->hndl_uqueue != NULL)) { /* M_IOCACK received */ + mutex_exit(&oplmsu_uinst->l_lock); + mutex_exit(&oplmsu_uinst->u_lock); + if (oplmsu_cmn_copymb(lrq, mp, &nmp, hndl_mp, + MSU_READ_SIDE) == FAILURE) { + rw_exit(&oplmsu_uinst->lock); + return (FAILURE); + } + + OPLMSU_RWLOCK_UPGRADE(); + switch (chkflag) { + case TCSETS : /* FALLTHRU */ + case TCSETSW : /* FALLTHRU */ + case TCSETSF : + if (oplmsu_uinst->tcsets_p != NULL) { + freemsg(oplmsu_uinst->tcsets_p); + } + oplmsu_uinst->tcsets_p = nmp; + break; + + case TIOCMSET : + if (oplmsu_uinst->tiocmset_p != NULL) { + freemsg(oplmsu_uinst->tiocmset_p); + } + oplmsu_uinst->tiocmset_p = nmp; + break; + + case TIOCSPPS : + if (oplmsu_uinst->tiocspps_p != NULL) { + freemsg(oplmsu_uinst->tiocspps_p); + } + oplmsu_uinst->tiocspps_p = nmp; + break; + + case TIOCSWINSZ : + if (oplmsu_uinst->tiocswinsz_p != NULL) { + freemsg(oplmsu_uinst->tiocswinsz_p); + } + oplmsu_uinst->tiocswinsz_p = nmp; + break; + + case TIOCSSOFTCAR : + if (oplmsu_uinst->tiocssoftcar_p != NULL) { + freemsg(oplmsu_uinst->tiocssoftcar_p); + } + oplmsu_uinst->tiocssoftcar_p = nmp; + break; + } + + mutex_enter(&oplmsu_uinst->u_lock); + mutex_enter(&oplmsu_uinst->l_lock); + upath->traditional_status = lpath->status; + nmp = lpath->hndl_mp; + nmp->b_datap->db_type = M_IOCACK; + dst_queue = RD(lpath->hndl_uqueue); + bcopy(mp->b_rptr, nmp->b_rptr, sizeof (struct iocblk)); + + oplmsu_clear_ioctl_path(lpath); + lpath->src_upath = NULL; + lpath->status = MSU_EXT_NOTUSED; + mutex_exit(&oplmsu_uinst->l_lock); + mutex_exit(&oplmsu_uinst->u_lock); + freemsg(mp); + putq(dst_queue, nmp); + + /* Check sleep flag and wake up thread */ + oplmsu_cmn_wakeup(dst_queue); + rw_exit(&oplmsu_uinst->lock); + return (SUCCESS); + } else if ((ack_flag == NAK_RES) && + (lpath->hndl_uqueue != NULL)) { /* M_IOCNAK received */ + upath->traditional_status = lpath->status; + + nmp = lpath->hndl_mp; + nmp->b_datap->db_type = M_IOCNAK; + dst_queue = RD(lpath->hndl_uqueue); + + oplmsu_clear_ioctl_path(lpath); + lpath->src_upath = NULL; + lpath->status = MSU_EXT_NOTUSED; + mutex_exit(&oplmsu_uinst->l_lock); + mutex_exit(&oplmsu_uinst->u_lock); + freemsg(mp); + putq(dst_queue, nmp); + + /* Check sleep flag and wake up thread */ + oplmsu_cmn_wakeup(dst_queue); + rw_exit(&oplmsu_uinst->lock); + return (SUCCESS); + } + } + + mutex_enter(&oplmsu_uinst->u_lock); + switch (upath->status) { + case MSU_PSTAT_FAIL : + upath->traditional_status = MSU_FAIL; + break; + + case MSU_PSTAT_STOP : + upath->traditional_status = MSU_STOP; + break; + + case MSU_PSTAT_STANDBY : + upath->traditional_status = MSU_STANDBY; + break; + + case MSU_PSTAT_ACTIVE : + upath->traditional_status = MSU_ACTIVE; + break; + } + + mutex_enter(&oplmsu_uinst->l_lock); + oplmsu_clear_ioctl_path(lpath); + mutex_exit(&oplmsu_uinst->l_lock); + mutex_exit(&oplmsu_uinst->u_lock); + rw_exit(&oplmsu_uinst->lock); + freemsg(mp); + return (SUCCESS); +} + +/* M_ERROR or M_HANGUP response received */ +int +oplmsu_lrmsg_error(queue_t *lrq, mblk_t *mp) +{ + upath_t *upath, *altn_upath = NULL; + lpath_t *lpath, *altn_lpath = NULL; + mblk_t *nmp = NULL, *fmp = NULL; + queue_t *dst_queue = NULL; + ctrl_t *ctrl; + int term_stat, term_ioctl; + + rw_enter(&oplmsu_uinst->lock, RW_READER); + mutex_enter(&oplmsu_uinst->c_lock); + ctrl = oplmsu_uinst->user_ctrl; + if (ctrl != NULL) { + dst_queue = RD(ctrl->queue); + } + mutex_exit(&oplmsu_uinst->c_lock); + + mutex_enter(&oplmsu_uinst->u_lock); + mutex_enter(&oplmsu_uinst->l_lock); + lpath = (lpath_t *)lrq->q_ptr; + upath = oplmsu_search_upath_info(lpath->path_no); + + if ((lpath->status == MSU_LINK_NU) || + (lpath->status == MSU_SETID_NU) || + (upath->traditional_status == MSU_WSTR_ACK) || + (upath->traditional_status == MSU_WTCS_ACK) || + (upath->traditional_status == MSU_WTMS_ACK) || + (upath->traditional_status == MSU_WPPS_ACK) || + (upath->traditional_status == MSU_WWSZ_ACK) || + (upath->traditional_status == MSU_WCAR_ACK) || + (upath->traditional_status == MSU_WSTP_ACK) || + (upath->traditional_status == MSU_WPTH_CHG)) { + mutex_exit(&oplmsu_uinst->l_lock); + mutex_exit(&oplmsu_uinst->u_lock); + rw_exit(&oplmsu_uinst->lock); + freemsg(mp); + } else if ((upath->traditional_status == MSU_MAKE_INST) || + (upath->traditional_status == MSU_STOP) || + (upath->traditional_status == MSU_STANDBY) || + (upath->traditional_status == MSU_SETID) || + (upath->traditional_status == MSU_LINK)) { + oplmsu_cmn_set_upath_sts(upath, MSU_PSTAT_FAIL, upath->status, + MSU_FAIL); + mutex_exit(&oplmsu_uinst->l_lock); + mutex_exit(&oplmsu_uinst->u_lock); + rw_exit(&oplmsu_uinst->lock); + freemsg(mp); + } else if (upath->traditional_status == MSU_FAIL) { + mutex_exit(&oplmsu_uinst->l_lock); + mutex_exit(&oplmsu_uinst->u_lock); + rw_exit(&oplmsu_uinst->lock); + freemsg(mp); + } else if (upath->traditional_status == MSU_ACTIVE) { + altn_upath = oplmsu_search_standby(); + if (altn_upath == NULL) { + oplmsu_cmn_set_upath_sts(upath, MSU_PSTAT_FAIL, + upath->status, MSU_FAIL); + + oplmsu_clear_ioctl_path(lpath); + lpath->src_upath = NULL; + lpath->status = MSU_EXT_NOTUSED; + lpath->uinst = NULL; + mutex_exit(&oplmsu_uinst->l_lock); + mutex_exit(&oplmsu_uinst->u_lock); + + OPLMSU_RWLOCK_UPGRADE(); + oplmsu_uinst->lower_queue = NULL; + rw_exit(&oplmsu_uinst->lock); + freemsg(mp); + return (SUCCESS); + } + + mutex_exit(&oplmsu_uinst->l_lock); + if (oplmsu_cmn_allocmb(lrq, mp, &fmp, sizeof (char), + MSU_READ_SIDE) == FAILURE) { + mutex_exit(&oplmsu_uinst->u_lock); + rw_exit(&oplmsu_uinst->lock); + return (FAILURE); + } + + if (oplmsu_cmn_prechg(lrq, mp, MSU_READ_SIDE, &nmp, &term_ioctl, + &term_stat) == FAILURE) { + mutex_exit(&oplmsu_uinst->u_lock); + rw_exit(&oplmsu_uinst->lock); + freeb(fmp); + return (FAILURE); + } + + oplmsu_cmn_set_upath_sts(upath, MSU_PSTAT_FAIL, + upath->status, MSU_FAIL); + + mutex_enter(&oplmsu_uinst->l_lock); + lpath->uinst = NULL; + + altn_upath->traditional_status = term_stat; + altn_lpath = altn_upath->lpath; + + altn_lpath->hndl_mp = NULL; + altn_lpath->hndl_uqueue = NULL; + altn_lpath->src_upath = upath; + altn_lpath->status = MSU_EXT_VOID; + dst_queue = RD(altn_lpath->lower_queue); + mutex_exit(&oplmsu_uinst->l_lock); + mutex_exit(&oplmsu_uinst->u_lock); + + OPLMSU_RWLOCK_UPGRADE(); + oplmsu_uinst->lower_queue = NULL; + oplmsu_cmn_set_mflush(fmp); + + if (ctrl != NULL) { + mutex_enter(&oplmsu_uinst->c_lock); + noenable(WR(ctrl->queue)); + mutex_exit(&oplmsu_uinst->c_lock); + + oplmsu_queue_flag = 1; + } + + rw_exit(&oplmsu_uinst->lock); + freemsg(mp); + + OPLMSU_TRACE(dst_queue, fmp, MSU_TRC_LO); + qreply(dst_queue, fmp); + OPLMSU_TRACE(dst_queue, nmp, MSU_TRC_LO); + qreply(dst_queue, nmp); + } + return (SUCCESS); +} + +/* M_DATA[xoff/xon] was received from serial port */ +int +oplmsu_lrdata_xoffxon(queue_t *lrq, mblk_t *mp) +{ + upath_t *upath, *stp_upath = NULL; + lpath_t *lpath, *stp_lpath = NULL; + mblk_t *nmp = NULL, *fmp = NULL; + ctrl_t *ctrl; + int term_stat, term_ioctl; + + rw_enter(&oplmsu_uinst->lock, RW_READER); + mutex_enter(&oplmsu_uinst->u_lock); + mutex_enter(&oplmsu_uinst->l_lock); + + if (oplmsu_uinst->lower_queue != NULL) { + /* Get lower path of active status */ + stp_lpath = (lpath_t *)oplmsu_uinst->lower_queue->q_ptr; + if (stp_lpath != NULL) { + stp_upath = + oplmsu_search_upath_info(stp_lpath->path_no); + } + } + + lpath = (lpath_t *)lrq->q_ptr; + upath = oplmsu_search_upath_info(lpath->path_no); + + if ((stp_upath != NULL) && (stp_upath != upath)) { + if ((stp_upath->status != MSU_PSTAT_ACTIVE) || + (stp_upath->traditional_status != MSU_ACTIVE)) { + mutex_exit(&oplmsu_uinst->l_lock); + mutex_exit(&oplmsu_uinst->u_lock); + rw_exit(&oplmsu_uinst->lock); + putbq(lrq, mp); + return (FAILURE); + } + } + + if ((upath->status == MSU_PSTAT_ACTIVE) && + ((upath->traditional_status == MSU_ACTIVE) || + (upath->traditional_status == MSU_WTCS_ACK) || + (upath->traditional_status == MSU_WTMS_ACK) || + (upath->traditional_status == MSU_WPPS_ACK) || + (upath->traditional_status == MSU_WWSZ_ACK) || + (upath->traditional_status == MSU_WCAR_ACK))) { + mutex_exit(&oplmsu_uinst->l_lock); + mutex_exit(&oplmsu_uinst->u_lock); + oplmsu_rcmn_through_hndl(lrq, mp, MSU_NORM); + rw_exit(&oplmsu_uinst->lock); + return (SUCCESS); + } else if ((upath->status != MSU_PSTAT_STANDBY) || + (upath->traditional_status != MSU_STANDBY)) { + mutex_exit(&oplmsu_uinst->l_lock); + mutex_exit(&oplmsu_uinst->u_lock); + rw_exit(&oplmsu_uinst->lock); + freemsg(mp); + cmn_err(CE_WARN, "oplmsu: lr-xoffxon: " + "Can't change to specified path"); + return (SUCCESS); + } + mutex_exit(&oplmsu_uinst->l_lock); + + if (oplmsu_cmn_allocmb(lrq, mp, &fmp, sizeof (char), MSU_READ_SIDE) == + FAILURE) { + mutex_exit(&oplmsu_uinst->u_lock); + rw_exit(&oplmsu_uinst->lock); + return (FAILURE); + } + + if (oplmsu_cmn_prechg(lrq, mp, MSU_READ_SIDE, &nmp, &term_ioctl, + &term_stat) == FAILURE) { + mutex_exit(&oplmsu_uinst->u_lock); + rw_exit(&oplmsu_uinst->lock); + freeb(fmp); + return (FAILURE); + } + + oplmsu_cmn_set_mflush(fmp); + upath->traditional_status = term_stat; + + mutex_enter(&oplmsu_uinst->l_lock); + lpath->hndl_mp = mp; + lpath->hndl_uqueue = NULL; + lpath->src_upath = stp_upath; + lpath->status = MSU_EXT_VOID; + + mutex_enter(&oplmsu_uinst->c_lock); + ctrl = oplmsu_uinst->user_ctrl; + if (term_stat != MSU_WPTH_CHG) { + /* + * Send termios to new active path and wait response + */ + if (ctrl != NULL) { + noenable(WR(ctrl->queue)); + } + mutex_exit(&oplmsu_uinst->c_lock); + mutex_exit(&oplmsu_uinst->l_lock); + mutex_exit(&oplmsu_uinst->u_lock); + rw_exit(&oplmsu_uinst->lock); + + OPLMSU_TRACE(RD(lrq), fmp, MSU_TRC_LO); + qreply(RD(lrq), fmp); + OPLMSU_TRACE(RD(lrq), nmp, MSU_TRC_LO); + qreply(RD(lrq), nmp); + } else { + /* + * No termios messages are received. Change active path. + */ + + oplmsu_cmn_set_upath_sts(upath, MSU_PSTAT_ACTIVE, upath->status, + MSU_ACTIVE); + + lpath->uinst = oplmsu_uinst; + lpath->src_upath = NULL; + lpath->status = MSU_EXT_NOTUSED; + + /* Notify of the active path changing */ + prom_opl_switch_console(upath->ser_devcb.lsb); + + putq(WR(lrq), fmp); + + /* Send XON to notify active path */ + (void) oplmsu_cmn_put_xoffxon(WR(lrq), MSU_XON_4); + + if (lpath->hndl_mp != NULL) { + /* Put a message(M_DATA) on a queue */ + if (ctrl != NULL) { + putq(RD(ctrl->queue), lpath->hndl_mp); + } + } + + oplmsu_clear_ioctl_path(lpath); + + if (ctrl != NULL) { + noenable(WR(ctrl->queue)); + } + + if ((stp_upath != NULL) && (stp_lpath != NULL)) { + /* Change the status of stop path */ + oplmsu_cmn_set_upath_sts(stp_upath, MSU_PSTAT_STANDBY, + stp_upath->status, MSU_STANDBY); + + oplmsu_clear_ioctl_path(stp_lpath); + stp_lpath->uinst = NULL; + stp_lpath->src_upath = NULL; + stp_lpath->status = MSU_EXT_NOTUSED; + } +#ifdef DEBUG + oplmsu_cmn_prt_pathname(upath->ser_devcb.dip); +#endif + /* Send XOFF to notify all standby paths */ + oplmsu_cmn_putxoff_standby(); + mutex_exit(&oplmsu_uinst->c_lock); + mutex_exit(&oplmsu_uinst->l_lock); + mutex_exit(&oplmsu_uinst->u_lock); + + OPLMSU_RWLOCK_UPGRADE(); + mutex_enter(&oplmsu_uinst->u_lock); + oplmsu_uinst->lower_queue = lrq; + oplmsu_uinst->inst_status = oplmsu_get_inst_status(); + mutex_exit(&oplmsu_uinst->u_lock); + + if (ctrl != NULL) { + queue_t *temp_queue; + + mutex_enter(&oplmsu_uinst->c_lock); + temp_queue = WR(ctrl->queue); + mutex_exit(&oplmsu_uinst->c_lock); + + /* Reschedule a queue for service */ + enableok(temp_queue); + + oplmsu_queue_flag = 0; + oplmsu_wcmn_high_qenable(temp_queue, RW_WRITER); + } + rw_exit(&oplmsu_uinst->lock); + } + return (SUCCESS); +} diff --git a/usr/src/uts/sun4u/opl/io/oplmsu/oplmsu_ioctl_uwp.c b/usr/src/uts/sun4u/opl/io/oplmsu/oplmsu_ioctl_uwp.c new file mode 100644 index 0000000000..b64a1e8121 --- /dev/null +++ b/usr/src/uts/sun4u/opl/io/oplmsu/oplmsu_ioctl_uwp.c @@ -0,0 +1,471 @@ +/* + * 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 + */ +/* + * All Rights Reserved, Copyright (c) FUJITSU LIMITED 2006 + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/errno.h> +#include <sys/modctl.h> +#include <sys/stat.h> +#include <sys/kmem.h> +#include <sys/ksynch.h> +#include <sys/stream.h> +#include <sys/stropts.h> +#include <sys/termio.h> +#include <sys/ddi.h> +#include <sys/file.h> +#include <sys/disp.h> +#include <sys/sunddi.h> +#include <sys/sunldi.h> +#include <sys/sunndi.h> +#include <sys/oplmsu/oplmsu.h> +#include <sys/oplmsu/oplmsu_proto.h> + +/* + * UPPER WRITE SERVICE PROCEDURE + */ + +/* I_PLINK ioctl command received */ +int +oplmsu_uwioctl_iplink(queue_t *uwq, mblk_t *mp) +{ + struct linkblk *lbp; + lpath_t *lpath; + int ncode; + + if (mp == NULL) { + return (EINVAL); + } + + if ((mp->b_cont->b_wptr - mp->b_cont->b_rptr) < + sizeof (struct linkblk)) { + cmn_err(CE_WARN, "oplmsu: uw-iplink: Invalid data length"); + oplmsu_iocack(uwq, mp, EINVAL); + return (EINVAL); + } + + lbp = (struct linkblk *)mp->b_cont->b_rptr; + rw_enter(&oplmsu_uinst->lock, RW_WRITER); + + /* + * Check whether this is called by super-user privilege. + * uwq => Queue of meta control node + */ + + ncode = oplmsu_wcmn_chknode(uwq, MSU_NODE_META, mp); + if (ncode != SUCCESS) { + rw_exit(&oplmsu_uinst->lock); + oplmsu_iocack(uwq, mp, ncode); + return (ncode); + } + + /* Allocate kernel memory for lpath_t */ + lpath = (lpath_t *)kmem_zalloc(sizeof (lpath_t), KM_NOSLEEP); + if (lpath == NULL) { + rw_exit(&oplmsu_uinst->lock); + cmn_err(CE_WARN, "oplmsu: uw-iplink: " + "Failed to allocate kernel memory"); + oplmsu_iocack(uwq, mp, ENOMEM); + return (ENOMEM); + } + + /* + * Initialize members of lpath_t + */ + + lpath->rbuftbl = + (struct buf_tbl *)kmem_zalloc(sizeof (struct buf_tbl), KM_NOSLEEP); + if (lpath->rbuftbl == NULL) { + rw_exit(&oplmsu_uinst->lock); + kmem_free(lpath, sizeof (lpath_t)); + cmn_err(CE_WARN, "oplmsu: uw-iplink: " + "Failed to allocate kernel memory"); + oplmsu_iocack(uwq, mp, ENOMEM); + return (ENOMEM); + } + + cv_init(&lpath->sw_cv, "oplmsu lpath condvar", CV_DRIVER, NULL); + lpath->src_upath = NULL; + lpath->status = MSU_EXT_NOTUSED; + lpath->lower_queue = lbp->l_qbot; /* Set lower queue pointer */ + lpath->link_id = lbp->l_index; /* Set Link-ID */ + lpath->path_no = UNDEFINED; /* Set initial path number */ + lpath->abt_char = oplmsu_uinst->abts; /* Set abort character seq */ + + WR(lpath->lower_queue)->q_ptr = lpath; + RD(lpath->lower_queue)->q_ptr = lpath; + + oplmsu_link_lpath(lpath); /* Link lpath_t */ + rw_exit(&oplmsu_uinst->lock); + oplmsu_iocack(uwq, mp, 0); + return (SUCCESS); +} + +/* I_PUNLINK ioctl command received */ +int +oplmsu_uwioctl_ipunlink(queue_t *uwq, mblk_t *mp) +{ + struct linkblk *lbp; + upath_t *upath; + lpath_t *lpath; + mblk_t *hmp = NULL, *next_hmp = NULL; + bufcall_id_t rbuf_id; + timeout_id_t rtout_id; + int ncode; + int use_flag; + + if (mp == NULL) { + return (EINVAL); + } + + if ((mp->b_cont->b_wptr - mp->b_cont->b_rptr) < + sizeof (struct linkblk)) { + cmn_err(CE_WARN, "oplmsu: uw-ipunlink: Invalid data length"); + oplmsu_iocack(uwq, mp, ENOSR); + return (ENOSR); + } + + lbp = (struct linkblk *)mp->b_cont->b_rptr; + rw_enter(&oplmsu_uinst->lock, RW_WRITER); + + /* + * Check whether this is called by super-user privilege. + * uwq => Queue of meta control node + */ + + ncode = oplmsu_wcmn_chknode(uwq, MSU_NODE_META, mp); + if (ncode != SUCCESS) { + rw_exit(&oplmsu_uinst->lock); + oplmsu_iocack(uwq, mp, ncode); + return (ncode); + } + + mutex_enter(&oplmsu_uinst->u_lock); + mutex_enter(&oplmsu_uinst->l_lock); + + /* + * Search for a corresponding lower path information table to + * lbp->l_qbot from the lower queue address. + */ + + lpath = oplmsu_uinst->first_lpath; + while (lpath) { + if ((lpath->lower_queue == RD(lbp->l_qbot)) || + (lpath->lower_queue == WR(lbp->l_qbot))) { + break; + } + lpath = lpath->l_next; + } + + if (lpath == NULL) { + mutex_exit(&oplmsu_uinst->l_lock); + mutex_exit(&oplmsu_uinst->u_lock); + rw_exit(&oplmsu_uinst->lock); + cmn_err(CE_WARN, "oplmsu: uw-ipunlink: " + "Proper lpath_t doesn't find"); + oplmsu_iocack(uwq, mp, EINVAL); + return (EINVAL); + } + + /* lpath_t come into the busy status */ + use_flag = oplmsu_set_ioctl_path(lpath, uwq, NULL); + if (use_flag == BUSY) { + mutex_exit(&oplmsu_uinst->l_lock); + mutex_exit(&oplmsu_uinst->u_lock); + rw_exit(&oplmsu_uinst->lock); + cmn_err(CE_WARN, "oplmsu: uw-ipunlink: " + "Other processing is using lower path"); + oplmsu_iocack(uwq, mp, EBUSY); + return (EBUSY); + } + + /* upath_t is retrieved by using the path number */ + upath = oplmsu_search_upath_info(lpath->path_no); + if (upath != NULL) { /* When the upath_t exists */ + switch (upath->status) { + case MSU_PSTAT_STOP : /* FALLTHRU */ + case MSU_PSTAT_FAIL : + /* + * When traditional_status is MSU_SETID, the path + * status is changed into the state of disconnect. + */ + + if (upath->traditional_status == MSU_SETID) { + oplmsu_cmn_set_upath_sts(upath, + MSU_PSTAT_DISCON, upath->status, + MSU_DISCON); + upath->lpath = NULL; + break; + } + + /* + * When traditional_status isn't MSU_SETID, + * the error is reported. + */ + + default : + /* + * When upath->status isn't MSU_PSTAT_STOP or + * MSU_PSTAT_FAIL, the error is reported. + */ + + oplmsu_clear_ioctl_path(lpath); + mutex_exit(&oplmsu_uinst->l_lock); + cmn_err(CE_WARN, "oplmsu: uw-ipunlink: " + "trad_status = %lx", upath->traditional_status); + cmn_err(CE_WARN, "oplmsu: uw-ipunlink: " + "status = %d", upath->status); + mutex_exit(&oplmsu_uinst->u_lock); + rw_exit(&oplmsu_uinst->lock); + oplmsu_iocack(uwq, mp, EINVAL); + return (EINVAL); + } + } else { + /* + * This pattern is no upper info table before config_add or + * after config_del. + */ + + /* + * When the upper path table doesn't exist, path is deleted + * with config_del/config_add ioctl processed. + */ + + if ((lpath->status != MSU_LINK_NU) && + (lpath->status != MSU_SETID_NU)) { + oplmsu_clear_ioctl_path(lpath); + mutex_exit(&oplmsu_uinst->l_lock); + mutex_exit(&oplmsu_uinst->u_lock); + rw_exit(&oplmsu_uinst->lock); + oplmsu_iocack(uwq, mp, EINVAL); + return (EINVAL); + } + } + + oplmsu_uinst->inst_status = oplmsu_get_inst_status(); + oplmsu_clear_ioctl_path(lpath); + + /* Free high priority message */ + if (lpath->first_lpri_hi != NULL) { + cmn_err(CE_WARN, "oplmsu: uw-ipunlink: " + "Free high-priority message by unlinking lower path"); + + for (hmp = lpath->first_lpri_hi; hmp; ) { + next_hmp = hmp->b_next; + freemsg(hmp); + hmp = next_hmp; + } + lpath->first_lpri_hi = NULL; + lpath->last_lpri_hi = NULL; + } + + rbuf_id = lpath->rbuf_id; + rtout_id = lpath->rtout_id; + lpath->rbuf_id = 0; + lpath->rtout_id = 0; + + kmem_free(lpath->rbuftbl, sizeof (struct buf_tbl)); + lpath->rbuftbl = NULL; + cv_destroy(&lpath->sw_cv); + oplmsu_unlink_lpath(lpath); + kmem_free(lpath, sizeof (lpath_t)); + + mutex_exit(&oplmsu_uinst->l_lock); + mutex_exit(&oplmsu_uinst->u_lock); + rw_exit(&oplmsu_uinst->lock); + + if (rbuf_id != 0) { + unbufcall(rbuf_id); + } + + if (rtout_id != 0) { + untimeout(rtout_id); + } + oplmsu_iocack(uwq, mp, 0); + return (SUCCESS); +} + +/* termio ioctl command received */ +int +oplmsu_uwioctl_termios(queue_t *uwq, mblk_t *mp) +{ + struct iocblk *iocp = NULL; + queue_t *dst_queue; + upath_t *upath = NULL; + lpath_t *lpath = NULL; + mblk_t *nmp = NULL; + ctrl_t *ctrl; + int term_stat; + int use_flag; + + if (mp == NULL) { + return (EINVAL); + } + + if (mp->b_cont == NULL) { + cmn_err(CE_WARN, "oplmsu: uw-termios: " + "b_cont data block is NULL"); + oplmsu_iocack(uwq, mp, EINVAL); + return (FAILURE); + } + + if (mp->b_cont->b_rptr == NULL) { + cmn_err(CE_WARN, "oplmsu: uw-termios: " + "b_rptr data pointer is NULL"); + oplmsu_iocack(uwq, mp, EINVAL); + return (EINVAL); + } + + iocp = (struct iocblk *)mp->b_rptr; + rw_enter(&oplmsu_uinst->lock, RW_READER); + + /* + * Check control node type + * uwq : Queue of user control node + */ + + mutex_enter(&oplmsu_uinst->c_lock); + ctrl = (ctrl_t *)uwq->q_ptr; + if (ctrl != NULL) { + if (ctrl->node_type != MSU_NODE_USER) { + mutex_exit(&oplmsu_uinst->c_lock); + rw_exit(&oplmsu_uinst->lock); + cmn_err(CE_WARN, "oplmsu: uw-termios: " + "ctrl node type = %d", ctrl->node_type); + oplmsu_iocack(uwq, mp, EINVAL); + return (EINVAL); + } + } + mutex_exit(&oplmsu_uinst->c_lock); + + switch (iocp->ioc_cmd) { + case TCSETS : /* FALLTHRU */ + case TCSETSW : /* FALLTHRU */ + case TCSETSF : + term_stat = MSU_WTCS_ACK; + break; + + case TIOCMSET : + term_stat = MSU_WTMS_ACK; + break; + + case TIOCSPPS : + term_stat = MSU_WPPS_ACK; + break; + + case TIOCSWINSZ : + term_stat = MSU_WWSZ_ACK; + break; + + case TIOCSSOFTCAR : + term_stat = MSU_WCAR_ACK; + break; + + default : + rw_exit(&oplmsu_uinst->lock); + cmn_err(CE_WARN, "oplmsu: uw-termios: ioctl mismatch"); + oplmsu_iocack(uwq, mp, EINVAL); + return (EINVAL); + } + + if (oplmsu_uinst->lower_queue == NULL) { + rw_exit(&oplmsu_uinst->lock); + cmn_err(CE_WARN, "!oplmsu: uw-termios: " + "Active path doesn't exist"); + oplmsu_iocack(uwq, mp, ENODEV); + return (FAILURE); + } + + lpath = oplmsu_uinst->lower_queue->q_ptr; + if (lpath == NULL) { + rw_exit(&oplmsu_uinst->lock); + cmn_err(CE_WARN, "oplmsu: uw-termios: " + "Proper lpath_t doesn't exist"); + oplmsu_iocack(uwq, mp, EINVAL); + return (EINVAL); + } + + if (oplmsu_cmn_copymb(uwq, mp, &nmp, mp, MSU_WRITE_SIDE) == FAILURE) { + rw_exit(&oplmsu_uinst->lock); + return (FAILURE); + } + + mutex_enter(&oplmsu_uinst->u_lock); + mutex_enter(&oplmsu_uinst->l_lock); + + upath = oplmsu_search_upath_info(lpath->path_no); + if (upath == NULL) { + mutex_exit(&oplmsu_uinst->l_lock); + mutex_exit(&oplmsu_uinst->u_lock); + rw_exit(&oplmsu_uinst->lock); + cmn_err(CE_WARN, "oplmsu: uw-termios: " + "Proper upath_t doesn't find"); + oplmsu_iocack(uwq, mp, EINVAL); + return (EINVAL); + } + + /* Set ioctl command to lower path info table */ + use_flag = oplmsu_set_ioctl_path(lpath, uwq, mp); + if (use_flag == BUSY) { + mutex_exit(&oplmsu_uinst->l_lock); + mutex_exit(&oplmsu_uinst->u_lock); + freemsg(nmp); + + if (ctrl != NULL) { + mutex_enter(&oplmsu_uinst->c_lock); + ctrl->wait_queue = uwq; + mutex_exit(&oplmsu_uinst->c_lock); + rw_exit(&oplmsu_uinst->lock); + + putbq(uwq, mp); + return (SUCCESS); + } else { + rw_exit(&oplmsu_uinst->lock); + oplmsu_iocack(uwq, mp, EBUSY); + return (EBUSY); + } + } + + /* Set destination queue (active path) */ + dst_queue = WR(oplmsu_uinst->lower_queue); + if (canput(dst_queue)) { + lpath->src_upath = NULL; + lpath->status = upath->traditional_status; + upath->traditional_status = term_stat; + mutex_exit(&oplmsu_uinst->l_lock); + mutex_exit(&oplmsu_uinst->u_lock); + rw_exit(&oplmsu_uinst->lock); + + putq(dst_queue, nmp); + return (SUCCESS); + } else { + oplmsu_clear_ioctl_path(lpath); + mutex_exit(&oplmsu_uinst->l_lock); + mutex_exit(&oplmsu_uinst->u_lock); + + freemsg(nmp); + oplmsu_wcmn_norm_putbq(WR(uwq), mp, dst_queue); + rw_exit(&oplmsu_uinst->lock); + return (FAILURE); + } +} diff --git a/usr/src/uts/sun4u/opl/io/oplpanel/oplpanel.c b/usr/src/uts/sun4u/opl/io/oplpanel/oplpanel.c new file mode 100644 index 0000000000..0de3baa0b2 --- /dev/null +++ b/usr/src/uts/sun4u/opl/io/oplpanel/oplpanel.c @@ -0,0 +1,414 @@ +/* + * 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 + */ +/* + * All Rights Reserved, Copyright (c) FUJITSU LIMITED 2006 + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <sys/time.h> +#include <sys/errno.h> +#include <sys/cmn_err.h> +#include <sys/param.h> +#include <sys/modctl.h> +#include <sys/conf.h> +#include <sys/open.h> +#include <sys/stat.h> +#include <sys/ddi.h> +#include <sys/sunddi.h> +#include <sys/file.h> +#include <sys/intr.h> +#include <sys/machsystm.h> + +#define PNLIE_MASK 0x010 /* interrupt enable/disable */ +#define PNLINT_MASK 0x001 /* interrupted flag */ + +#ifdef DEBUG +int panel_debug = 0; +static void panel_ddi_put8(ddi_acc_handle_t, uint8_t *, uint8_t); +#define DCMN_ERR(x) if (panel_debug) cmn_err x + +#else + +#define DCMN_ERR(x) +#define panel_ddi_put8(x, y, z) ddi_put8(x, y, z) + +#endif + +static int panel_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); +static int panel_attach(dev_info_t *, ddi_attach_cmd_t); +static int panel_detach(dev_info_t *, ddi_detach_cmd_t); +static uint_t panel_intr(caddr_t); +static int panel_open(dev_t *, int, int, cred_t *); +static int panel_close(dev_t, int, int, cred_t *); + +static char *panel_name = "oplpanel"; +int panel_enable = 1; /* enable or disable */ + +extern uint32_t cpc_level15_inum; /* in cpc_subr.c */ + +struct panel_state { + dev_info_t *dip; + ddi_iblock_cookie_t iblock_cookie; + ddi_acc_handle_t panel_regs_handle; + uint8_t *panelregs; /* mapping address */ + uint8_t panelregs_state; /* keeping regs. */ +}; + +struct cb_ops panel_cb_ops = { + nodev, /* open */ + nodev, /* close */ + nodev, /* strategy */ + nodev, /* print */ + nodev, /* dump */ + nodev, /* read */ + nodev, /* write */ + nodev, /* ioctl */ + nodev, /* devmap */ + nodev, /* mmap */ + nodev, /* segmap */ + nochpoll, /* poll */ + nodev, /* prop_op */ + NULL, /* streamtab */ + D_NEW | D_MP | D_HOTPLUG, /* flag */ + CB_REV, /* cb_rev */ + nodev, /* async I/O read entry point */ + nodev /* async I/O write entry point */ +}; + +static struct dev_ops panel_dev_ops = { + DEVO_REV, /* driver build version */ + 0, /* device reference count */ + panel_getinfo, /* getinfo */ + nulldev, /* identify */ + nulldev, /* probe */ + panel_attach, /* attach */ + panel_detach, /* detach */ + nulldev, /* reset */ + &panel_cb_ops, /* cb_ops */ + NULL, /* bus_ops */ + nulldev /* power */ +}; + +/* module configuration stuff */ +static void *panelstates; +extern struct mod_ops mod_driverops; + +static struct modldrv modldrv = { + &mod_driverops, + "OPL panel driver %I%", + &panel_dev_ops +}; + +static struct modlinkage modlinkage = { + MODREV_1, + &modldrv, + 0 +}; + + +int +_init(void) +{ + int status; + + DCMN_ERR((CE_CONT, "%s: _init\n", panel_name)); + + status = ddi_soft_state_init(&panelstates, + sizeof (struct panel_state), 0); + if (status != 0) { + cmn_err(CE_WARN, "%s: ddi_soft_state_init failed.", + panel_name); + return (status); + } + + status = mod_install(&modlinkage); + if (status != 0) { + ddi_soft_state_fini(&panelstates); + } + + return (status); +} + +int +_fini(void) +{ + /* + * Can't unload to make sure the panel switch always works. + */ + return (EBUSY); +} + +int +_info(struct modinfo *modinfop) +{ + return (mod_info(&modlinkage, modinfop)); +} + +static int +panel_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) +{ + + int instance; + struct panel_state *statep = NULL; + + ddi_device_acc_attr_t access_attr = { + DDI_DEVICE_ATTR_V0, + DDI_STRUCTURE_BE_ACC, + DDI_STRICTORDER_ACC + }; + + instance = ddi_get_instance(dip); + + DCMN_ERR((CE_CONT, "%s%d: attach\n", panel_name, instance)); + + switch (cmd) { + case DDI_ATTACH: + DCMN_ERR((CE_CONT, "%s%d: DDI_ATTACH\n", + panel_name, instance)); + break; + + case DDI_RESUME: + DCMN_ERR((CE_CONT, "%s%d: DDI_RESUME\n", + panel_name, instance)); + + if ((statep = (struct panel_state *) + ddi_get_soft_state(panelstates, instance)) == NULL) { + cmn_err(CE_WARN, "%s%d: ddi_get_soft_state failed.", + panel_name, instance); + return (DDI_FAILURE); + } + + /* enable the interrupt just in case */ + panel_ddi_put8(statep->panel_regs_handle, statep->panelregs, + statep->panelregs_state); + return (DDI_SUCCESS); + + default: + return (DDI_FAILURE); + } + + /* + * Attach routine + */ + + /* alloc and get soft state */ + if (ddi_soft_state_zalloc(panelstates, instance) != DDI_SUCCESS) { + cmn_err(CE_WARN, "%s%d: ddi_soft_state_zalloc failed.", + panel_name, instance); + goto attach_failed2; + } + if ((statep = (struct panel_state *) + ddi_get_soft_state(panelstates, instance)) == NULL) { + cmn_err(CE_WARN, "%s%d: ddi_get_soft_state failed.", + panel_name, instance); + goto attach_failed1; + } + + /* set the dip in the soft state */ + statep->dip = dip; + + /* mapping register */ + if (ddi_regs_map_setup(dip, 0, (caddr_t *)&statep->panelregs, + 0, 0, /* the entire space is mapped */ + &access_attr, &statep->panel_regs_handle) != DDI_SUCCESS) { + cmn_err(CE_WARN, "%s%d: ddi_regs_map_setup failed.", + panel_name, instance); + goto attach_failed1; + } + + /* setup the interrupt handler */ + ddi_get_iblock_cookie(dip, 0, &statep->iblock_cookie); + if (ddi_add_intr(dip, 0, &statep->iblock_cookie, 0, &panel_intr, + (caddr_t)statep) != DDI_SUCCESS) { + cmn_err(CE_WARN, "%s%d: cannot add interrupt handler.", + panel_name, instance); + goto attach_failed0; + } + + /* ATTACH SUCCESS */ + + /* announce the device */ + ddi_report_dev(dip); + + /* turn on interrupt */ + statep->panelregs_state = 0 | PNLIE_MASK; + panel_ddi_put8(statep->panel_regs_handle, statep->panelregs, + statep->panelregs_state); + + return (DDI_SUCCESS); + +attach_failed0: + ddi_regs_map_free(&statep->panel_regs_handle); +attach_failed1: + ddi_soft_state_free(panelstates, instance); +attach_failed2: + DCMN_ERR((CE_NOTE, "%s%d: attach failed", panel_name, instance)); + return (DDI_FAILURE); +} + +static int +panel_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) +{ + int instance; + struct panel_state *statep; + + instance = ddi_get_instance(dip); + + DCMN_ERR((CE_CONT, "%s%d: detach\n", panel_name, instance)); + + if ((statep = (struct panel_state *) + ddi_get_soft_state(panelstates, instance)) == NULL) { + cmn_err(CE_WARN, "%s%d: ddi_get_soft_state failed.", + panel_name, instance); + return (DDI_FAILURE); + } + + switch (cmd) { + case DDI_DETACH: + DCMN_ERR((CE_CONT, "%s%d: DDI_DETACH\n", + panel_name, instance)); + + /* turn off interrupt */ + statep->panelregs_state &= ~PNLIE_MASK; + panel_ddi_put8(statep->panel_regs_handle, statep->panelregs, + statep->panelregs_state); + + /* free all resources for the dip */ + ddi_remove_intr(dip, 0, statep->iblock_cookie); + + /* need not free iblock_cookie */ + ddi_regs_map_free(&statep->panel_regs_handle); + ddi_soft_state_free(panelstates, instance); + + return (DDI_SUCCESS); + + case DDI_SUSPEND: + DCMN_ERR((CE_CONT, "%s%d: DDI_SUSPEND\n", + panel_name, instance)); + return (DDI_SUCCESS); + + default: + return (DDI_FAILURE); + + } + /* Not reached */ +} + +/*ARGSUSED*/ +static int +panel_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp) +{ + struct panel_state *statep; + int instance; + dev_t dev = (dev_t)arg; + + instance = getminor(dev); + + DCMN_ERR((CE_CONT, "%s%d: getinfo\n", panel_name, instance)); + + switch (cmd) { + case DDI_INFO_DEVT2DEVINFO: + if ((statep = (struct panel_state *) + ddi_get_soft_state(panelstates, instance)) == NULL) { + cmn_err(CE_WARN, "%s%d: ddi_get_soft_state failed.", + panel_name, instance); + *resultp = NULL; + return (DDI_FAILURE); + } + *resultp = statep->dip; + break; + case DDI_INFO_DEVT2INSTANCE: + *resultp = (void *)(uintptr_t)instance; + break; + default: + return (DDI_FAILURE); + } + + return (DDI_SUCCESS); +} + +static uint_t +panel_intr(caddr_t arg) +{ + int instance; + struct panel_state *statep = (struct panel_state *)arg; + + instance = ddi_get_instance(statep->dip); + + DCMN_ERR((CE_CONT, "%s%d: intr\n", panel_name, instance)); + + /* to confirm the validity of the interrupt */ + if (!(ddi_get8(statep->panel_regs_handle, statep->panelregs) & + PNLINT_MASK)) { + cmn_err(CE_WARN, "%s%d: spurious interrupt detected.", + panel_name, instance); + return (DDI_INTR_UNCLAIMED); + } + + /* clear the PNLINT bit */ + panel_ddi_put8(statep->panel_regs_handle, statep->panelregs, + statep->panelregs_state | PNLINT_MASK); + + if (panel_enable) { + /* avoid double panic */ + panel_enable = 0; + + /* + * Re-enqueue the cpc interrupt handler for PIL15 here since we + * are not unwinding back to the interrupt handler subsystem. + * This is to allow potential cpc overflow interrupts to + * function while we go thru the panic flow. Note that this + * logic could be implemented in panic_enter_hw(), we do + * it here for now as it is less risky. This particular + * condition is only specific to OPL hardware and we want + * to minimize exposure of this new logic to other existing + * platforms. + */ + intr_enqueue_req(PIL_15, cpc_level15_inum); + + cmn_err(CE_PANIC, + "System Panel Driver: Emergency panic request " + "detected!"); + /* Not reached */ + } + + return (DDI_INTR_CLAIMED); +} + +#ifdef DEBUG +static void +panel_ddi_put8(ddi_acc_handle_t handle, uint8_t *dev_addr, uint8_t value) +{ + if (panel_debug) { + cmn_err(CE_CONT, "%s: old value = 0x%x\n", + panel_name, ddi_get8(handle, dev_addr)); + cmn_err(CE_CONT, "%s: writing value = 0x%x\n", + panel_name, value); + ddi_put8(handle, dev_addr, value); + cmn_err(CE_CONT, "%s: new value = 0x%x\n", + panel_name, ddi_get8(handle, dev_addr)); + } else { + ddi_put8(handle, dev_addr, value); + } +} +#endif diff --git a/usr/src/uts/sun4u/opl/io/oplpanel/oplpanel.conf b/usr/src/uts/sun4u/opl/io/oplpanel/oplpanel.conf new file mode 100644 index 0000000000..4a639e42f2 --- /dev/null +++ b/usr/src/uts/sun4u/opl/io/oplpanel/oplpanel.conf @@ -0,0 +1,29 @@ +# +# 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 +# +# +# All Rights Reserved, Copyright (c) FUJITSU LIMITED 2005 +# +#pragma ident "%Z%%M% %I% %E% SMI" +# +# force attach panel driver +# +ddi-forceattach=1; +interrupt-priorities=0xf; diff --git a/usr/src/uts/sun4u/opl/io/options.conf b/usr/src/uts/sun4u/opl/io/options.conf new file mode 100644 index 0000000000..ecf2bf358e --- /dev/null +++ b/usr/src/uts/sun4u/opl/io/options.conf @@ -0,0 +1,42 @@ +# +# 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. +# +#ident "%Z%%M% %I% %E% SMI" +# +# The property "ttymodes" defines the default termios modes +# (upon driver open) for the console ttys on OPL platform. +# +# ttymodes=<string> +# +# The format of <string> is the same format as the output of +# the "-g" option to /usr/bin/stty. Some standard termios modes +# have been included for reference: +# +# For SVID compliance, use these modes, +# "522:1805:4b7:2b:7f:1c:23:40:4:0:0:0:11:13:1a:19:12:f:17:16" +# +# + +name="options" class="root" +ttymodes="2502:1805:800000bd:8a3b:3:1c:7f:15:4:0:0:0:11:13:1a:19:12:f:17:16"; diff --git a/usr/src/uts/sun4u/opl/io/pcicmu/pcicmu.c b/usr/src/uts/sun4u/opl/io/pcicmu/pcicmu.c new file mode 100644 index 0000000000..a3dcec894a --- /dev/null +++ b/usr/src/uts/sun4u/opl/io/pcicmu/pcicmu.c @@ -0,0 +1,2202 @@ +/* + * 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" + +/* + * OPL CMU-CH PCI nexus driver. + * + */ + +#include <sys/types.h> +#include <sys/sysmacros.h> +#include <sys/systm.h> +#include <sys/intreg.h> +#include <sys/intr.h> +#include <sys/machsystm.h> +#include <sys/conf.h> +#include <sys/stat.h> +#include <sys/kmem.h> +#include <sys/async.h> +#include <sys/ivintr.h> +#include <sys/sunddi.h> +#include <sys/sunndi.h> +#include <sys/ndifm.h> +#include <sys/ontrap.h> +#include <sys/ddi_impldefs.h> +#include <sys/ddi_subrdefs.h> +#include <sys/epm.h> +#include <sys/spl.h> +#include <sys/fm/util.h> +#include <sys/fm/util.h> +#include <sys/fm/protocol.h> +#include <sys/fm/io/pci.h> +#include <sys/fm/io/sun4upci.h> +#include <sys/pcicmu/pcicmu.h> + +#include <sys/cmn_err.h> +#include <sys/time.h> +#include <sys/pci.h> +#include <sys/modctl.h> +#include <sys/open.h> +#include <sys/errno.h> +#include <sys/file.h> + + +uint32_t pcmu_spurintr_duration = 60000000; /* One minute */ + +/* + * The variable controls the default setting of the command register + * for pci devices. See pcmu_init_child() for details. + * + * This flags also controls the setting of bits in the bridge control + * register pci to pci bridges. See pcmu_init_child() for details. + */ +ushort_t pcmu_command_default = PCI_COMM_SERR_ENABLE | + PCI_COMM_WAIT_CYC_ENAB | + PCI_COMM_PARITY_DETECT | + PCI_COMM_ME | + PCI_COMM_MAE | + PCI_COMM_IO; +/* + * The following driver parameters are defined as variables to allow + * patching for debugging and tuning. Flags that can be set on a per + * PBM basis are bit fields where the PBM device instance number maps + * to the bit position. + */ +#ifdef DEBUG +uint64_t pcmu_debug_flags = 0; +#endif +uint_t ecc_error_intr_enable = 1; + +uint_t pcmu_ecc_afsr_retries = 100; /* XXX - what's a good value? */ + +uint_t pcmu_intr_retry_intv = 5; /* for interrupt retry reg */ +uint_t pcmu_panic_on_fatal_errors = 1; /* should be 1 at beta */ + +hrtime_t pcmu_intrpend_timeout = 5ll * NANOSEC; /* 5 seconds in nanoseconds */ + +uint64_t pcmu_errtrig_pa = 0x0; + + +/* + * The following value is the number of consecutive unclaimed interrupts that + * will be tolerated for a particular ino_p before the interrupt is deemed to + * be jabbering and is blocked. + */ +uint_t pcmu_unclaimed_intr_max = 20; + +/* + * function prototypes for dev ops routines: + */ +static int pcmu_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); +static int pcmu_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); +static int pcmu_info(dev_info_t *dip, ddi_info_cmd_t infocmd, + void *arg, void **result); +static int pcmu_open(dev_t *devp, int flags, int otyp, cred_t *credp); +static int pcmu_close(dev_t dev, int flags, int otyp, cred_t *credp); +static int pcmu_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, + cred_t *credp, int *rvalp); +static int pcmu_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, + int flags, char *name, caddr_t valuep, int *lengthp); +static int pcmu_ctlops_poke(pcmu_t *pcmu_p, peekpoke_ctlops_t *in_args); +static int pcmu_ctlops_peek(pcmu_t *pcmu_p, peekpoke_ctlops_t *in_args, + void *result); + +static int map_pcmu_registers(pcmu_t *, dev_info_t *); +static void unmap_pcmu_registers(pcmu_t *); +static void pcmu_pbm_clear_error(pcmu_pbm_t *); + +static int pcmu_ctlops(dev_info_t *, dev_info_t *, ddi_ctl_enum_t, + void *, void *); +static int pcmu_map(dev_info_t *, dev_info_t *, ddi_map_req_t *, + off_t, off_t, caddr_t *); +static int pcmu_intr_ops(dev_info_t *, dev_info_t *, ddi_intr_op_t, + ddi_intr_handle_impl_t *, void *); + +static uint32_t pcmu_identity_init(pcmu_t *pcmu_p); +static int pcmu_intr_setup(pcmu_t *pcmu_p); +static void pcmu_pbm_errstate_get(pcmu_t *pcmu_p, + pcmu_pbm_errstate_t *pbm_err_p); +static int pcmu_obj_setup(pcmu_t *pcmu_p); +static void pcmu_obj_destroy(pcmu_t *pcmu_p); +static void pcmu_obj_resume(pcmu_t *pcmu_p); +static void pcmu_obj_suspend(pcmu_t *pcmu_p); + +static void u2u_ittrans_init(pcmu_t *, u2u_ittrans_data_t **); +static void u2u_ittrans_resume(u2u_ittrans_data_t **); +static void u2u_ittrans_uninit(u2u_ittrans_data_t *); + +static pcmu_ksinfo_t *pcmu_name_kstat; + +/* + * bus ops and dev ops structures: + */ +static struct bus_ops pcmu_bus_ops = { + BUSO_REV, + pcmu_map, + 0, + 0, + 0, + i_ddi_map_fault, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + pcmu_ctlops, + ddi_bus_prop_op, + ndi_busop_get_eventcookie, /* (*bus_get_eventcookie)(); */ + ndi_busop_add_eventcall, /* (*bus_add_eventcall)(); */ + ndi_busop_remove_eventcall, /* (*bus_remove_eventcall)(); */ + ndi_post_event, /* (*bus_post_event)(); */ + NULL, /* (*bus_intr_ctl)(); */ + NULL, /* (*bus_config)(); */ + NULL, /* (*bus_unconfig)(); */ + NULL, /* (*bus_fm_init)(); */ + NULL, /* (*bus_fm_fini)(); */ + NULL, /* (*bus_fm_access_enter)(); */ + NULL, /* (*bus_fm_access_fini)(); */ + NULL, /* (*bus_power)(); */ + pcmu_intr_ops /* (*bus_intr_op)(); */ +}; + +struct cb_ops pcmu_cb_ops = { + pcmu_open, /* open */ + pcmu_close, /* close */ + nodev, /* strategy */ + nodev, /* print */ + nodev, /* dump */ + nodev, /* read */ + nodev, /* write */ + pcmu_ioctl, /* ioctl */ + nodev, /* devmap */ + nodev, /* mmap */ + nodev, /* segmap */ + nochpoll, /* poll */ + pcmu_prop_op, /* cb_prop_op */ + NULL, /* streamtab */ + D_NEW | D_MP | D_HOTPLUG, /* Driver compatibility flag */ + CB_REV, /* rev */ + nodev, /* int (*cb_aread)() */ + nodev /* int (*cb_awrite)() */ +}; + +static struct dev_ops pcmu_ops = { + DEVO_REV, + 0, + pcmu_info, + nulldev, + 0, + pcmu_attach, + pcmu_detach, + nodev, + &pcmu_cb_ops, + &pcmu_bus_ops, + 0 +}; + +/* + * module definitions: + */ +extern struct mod_ops mod_driverops; + +static struct modldrv modldrv = { + &mod_driverops, /* Type of module - driver */ + "OPL CMU-CH PCI Nexus driver %I%", /* Name of module. */ + &pcmu_ops, /* driver ops */ +}; + +static struct modlinkage modlinkage = { + MODREV_1, (void *)&modldrv, NULL +}; + +/* + * driver global data: + */ +void *per_pcmu_state; /* per-pbm soft state pointer */ +kmutex_t pcmu_global_mutex; /* attach/detach common struct lock */ +errorq_t *pcmu_ecc_queue = NULL; /* per-system ecc handling queue */ + +extern void pcmu_child_cfg_save(dev_info_t *dip); +extern void pcmu_child_cfg_restore(dev_info_t *dip); + +int +_init(void) +{ + int e; + + /* + * Initialize per-pci bus soft state pointer. + */ + e = ddi_soft_state_init(&per_pcmu_state, sizeof (pcmu_t), 1); + if (e != 0) + return (e); + + /* + * Initialize global mutexes. + */ + mutex_init(&pcmu_global_mutex, NULL, MUTEX_DRIVER, NULL); + + /* + * Create the performance kstats. + */ + pcmu_kstat_init(); + + /* + * Install the module. + */ + e = mod_install(&modlinkage); + if (e != 0) { + ddi_soft_state_fini(&per_pcmu_state); + mutex_destroy(&pcmu_global_mutex); + } + return (e); +} + +int +_fini(void) +{ + int e; + + /* + * Remove the module. + */ + e = mod_remove(&modlinkage); + if (e != 0) { + return (e); + } + + /* + * Destroy pcmu_ecc_queue, and set it to NULL. + */ + if (pcmu_ecc_queue) { + errorq_destroy(pcmu_ecc_queue); + pcmu_ecc_queue = NULL; + } + + /* + * Destroy the performance kstats. + */ + pcmu_kstat_fini(); + + /* + * Free the per-pci and per-CMU-CH soft state info and destroy + * mutex for per-CMU-CH soft state. + */ + ddi_soft_state_fini(&per_pcmu_state); + mutex_destroy(&pcmu_global_mutex); + return (e); +} + +int +_info(struct modinfo *modinfop) +{ + return (mod_info(&modlinkage, modinfop)); +} + +/*ARGSUSED*/ +static int +pcmu_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) +{ + int instance = getminor((dev_t)arg) >> 8; + pcmu_t *pcmu_p = get_pcmu_soft_state(instance); + + switch (infocmd) { + case DDI_INFO_DEVT2INSTANCE: + *result = (void *)(uintptr_t)instance; + return (DDI_SUCCESS); + + case DDI_INFO_DEVT2DEVINFO: + if (pcmu_p == NULL) + return (DDI_FAILURE); + *result = (void *)pcmu_p->pcmu_dip; + return (DDI_SUCCESS); + + default: + return (DDI_FAILURE); + } +} + + +/* device driver entry points */ +/* + * attach entry point: + */ +static int +pcmu_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) +{ + pcmu_t *pcmu_p; + int instance = ddi_get_instance(dip); + + switch (cmd) { + case DDI_ATTACH: + PCMU_DBG0(PCMU_DBG_ATTACH, dip, "DDI_ATTACH\n"); + + /* + * Allocate and get the per-pci soft state structure. + */ + if (alloc_pcmu_soft_state(instance) != DDI_SUCCESS) { + cmn_err(CE_WARN, "%s%d: can't allocate pci state", + ddi_driver_name(dip), instance); + goto err_bad_pcmu_softstate; + } + pcmu_p = get_pcmu_soft_state(instance); + pcmu_p->pcmu_dip = dip; + mutex_init(&pcmu_p->pcmu_mutex, NULL, MUTEX_DRIVER, NULL); + pcmu_p->pcmu_soft_state = PCMU_SOFT_STATE_CLOSED; + pcmu_p->pcmu_open_count = 0; + + /* + * Get key properties of the pci bridge node. + */ + if (get_pcmu_properties(pcmu_p, dip) == DDI_FAILURE) { + goto err_bad_pcmu_prop; + } + + /* + * Map in the registers. + */ + if (map_pcmu_registers(pcmu_p, dip) == DDI_FAILURE) { + goto err_bad_reg_prop; + } + if (pcmu_obj_setup(pcmu_p) != DDI_SUCCESS) { + goto err_bad_objs; + } + + if (ddi_create_minor_node(dip, "devctl", S_IFCHR, + (uint_t)instance<<8 | 0xff, + DDI_NT_NEXUS, 0) != DDI_SUCCESS) { + goto err_bad_devctl_node; + } + + /* + * Due to unresolved hardware issues, disable PCIPM until + * the problem is fully understood. + * + * pcmu_pwr_setup(pcmu_p, dip); + */ + + ddi_report_dev(dip); + + pcmu_p->pcmu_state = PCMU_ATTACHED; + PCMU_DBG0(PCMU_DBG_ATTACH, dip, "attach success\n"); + break; + +err_bad_objs: + ddi_remove_minor_node(dip, "devctl"); +err_bad_devctl_node: + unmap_pcmu_registers(pcmu_p); +err_bad_reg_prop: + free_pcmu_properties(pcmu_p); +err_bad_pcmu_prop: + mutex_destroy(&pcmu_p->pcmu_mutex); + free_pcmu_soft_state(instance); +err_bad_pcmu_softstate: + return (DDI_FAILURE); + + case DDI_RESUME: + PCMU_DBG0(PCMU_DBG_ATTACH, dip, "DDI_RESUME\n"); + + /* + * Make sure the CMU-CH control registers + * are configured properly. + */ + pcmu_p = get_pcmu_soft_state(instance); + mutex_enter(&pcmu_p->pcmu_mutex); + + /* + * Make sure this instance has been suspended. + */ + if (pcmu_p->pcmu_state != PCMU_SUSPENDED) { + PCMU_DBG0(PCMU_DBG_ATTACH, dip, + "instance NOT suspended\n"); + mutex_exit(&pcmu_p->pcmu_mutex); + return (DDI_FAILURE); + } + pcmu_obj_resume(pcmu_p); + pcmu_p->pcmu_state = PCMU_ATTACHED; + + pcmu_child_cfg_restore(dip); + + mutex_exit(&pcmu_p->pcmu_mutex); + break; + + default: + PCMU_DBG0(PCMU_DBG_ATTACH, dip, "unsupported attach op\n"); + return (DDI_FAILURE); + } + + return (DDI_SUCCESS); +} + +/* + * detach entry point: + */ +static int +pcmu_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) +{ + int instance = ddi_get_instance(dip); + pcmu_t *pcmu_p = get_pcmu_soft_state(instance); + int len; + + /* + * Make sure we are currently attached + */ + if (pcmu_p->pcmu_state != PCMU_ATTACHED) { + PCMU_DBG0(PCMU_DBG_ATTACH, dip, + "failed - instance not attached\n"); + return (DDI_FAILURE); + } + + mutex_enter(&pcmu_p->pcmu_mutex); + + switch (cmd) { + case DDI_DETACH: + PCMU_DBG0(PCMU_DBG_DETACH, dip, "DDI_DETACH\n"); + pcmu_obj_destroy(pcmu_p); + + /* + * Free the pci soft state structure and the rest of the + * resources it's using. + */ + free_pcmu_properties(pcmu_p); + unmap_pcmu_registers(pcmu_p); + mutex_exit(&pcmu_p->pcmu_mutex); + mutex_destroy(&pcmu_p->pcmu_mutex); + free_pcmu_soft_state(instance); + + /* Free the interrupt-priorities prop if we created it. */ + if (ddi_getproplen(DDI_DEV_T_ANY, dip, + DDI_PROP_NOTPROM | DDI_PROP_DONTPASS, + "interrupt-priorities", &len) == DDI_PROP_SUCCESS) { + (void) ddi_prop_remove(DDI_DEV_T_NONE, dip, + "interrupt-priorities"); + } + return (DDI_SUCCESS); + + case DDI_SUSPEND: + pcmu_child_cfg_save(dip); + pcmu_obj_suspend(pcmu_p); + pcmu_p->pcmu_state = PCMU_SUSPENDED; + + mutex_exit(&pcmu_p->pcmu_mutex); + return (DDI_SUCCESS); + + default: + PCMU_DBG0(PCMU_DBG_DETACH, dip, "unsupported detach op\n"); + mutex_exit(&pcmu_p->pcmu_mutex); + return (DDI_FAILURE); + } +} + + +/*LINTLIBRARY*/ + +/* ARGSUSED3 */ +static int +pcmu_open(dev_t *devp, int flags, int otyp, cred_t *credp) +{ + pcmu_t *pcmu_p; + + if (otyp != OTYP_CHR) { + return (EINVAL); + } + + /* + * Get the soft state structure for the device. + */ + pcmu_p = DEV_TO_SOFTSTATE(*devp); + if (pcmu_p == NULL) { + return (ENXIO); + } + + /* + * Handle the open by tracking the device state. + */ + PCMU_DBG2(PCMU_DBG_OPEN, pcmu_p->pcmu_dip, + "devp=%x: flags=%x\n", devp, flags); + mutex_enter(&pcmu_p->pcmu_mutex); + if (flags & FEXCL) { + if (pcmu_p->pcmu_soft_state != PCMU_SOFT_STATE_CLOSED) { + mutex_exit(&pcmu_p->pcmu_mutex); + PCMU_DBG0(PCMU_DBG_OPEN, pcmu_p->pcmu_dip, "busy\n"); + return (EBUSY); + } + pcmu_p->pcmu_soft_state = PCMU_SOFT_STATE_OPEN_EXCL; + } else { + if (pcmu_p->pcmu_soft_state == PCMU_SOFT_STATE_OPEN_EXCL) { + mutex_exit(&pcmu_p->pcmu_mutex); + PCMU_DBG0(PCMU_DBG_OPEN, pcmu_p->pcmu_dip, "busy\n"); + return (EBUSY); + } + pcmu_p->pcmu_soft_state = PCMU_SOFT_STATE_OPEN; + } + pcmu_p->pcmu_open_count++; + mutex_exit(&pcmu_p->pcmu_mutex); + return (0); +} + + +/* ARGSUSED */ +static int +pcmu_close(dev_t dev, int flags, int otyp, cred_t *credp) +{ + pcmu_t *pcmu_p; + + if (otyp != OTYP_CHR) { + return (EINVAL); + } + + pcmu_p = DEV_TO_SOFTSTATE(dev); + if (pcmu_p == NULL) { + return (ENXIO); + } + + PCMU_DBG2(PCMU_DBG_CLOSE, pcmu_p->pcmu_dip, + "dev=%x: flags=%x\n", dev, flags); + mutex_enter(&pcmu_p->pcmu_mutex); + pcmu_p->pcmu_soft_state = PCMU_SOFT_STATE_CLOSED; + pcmu_p->pcmu_open_count = 0; + mutex_exit(&pcmu_p->pcmu_mutex); + return (0); +} + +/* ARGSUSED */ +static int +pcmu_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, + cred_t *credp, int *rvalp) +{ + pcmu_t *pcmu_p; + dev_info_t *dip; + struct devctl_iocdata *dcp; + uint_t bus_state; + int rv = 0; + + pcmu_p = DEV_TO_SOFTSTATE(dev); + if (pcmu_p == NULL) { + return (ENXIO); + } + + dip = pcmu_p->pcmu_dip; + PCMU_DBG2(PCMU_DBG_IOCTL, dip, "dev=%x: cmd=%x\n", dev, cmd); + + /* + * We can use the generic implementation for these ioctls + */ + switch (cmd) { + case DEVCTL_DEVICE_GETSTATE: + case DEVCTL_DEVICE_ONLINE: + case DEVCTL_DEVICE_OFFLINE: + case DEVCTL_BUS_GETSTATE: + return (ndi_devctl_ioctl(dip, cmd, arg, mode, 0)); + } + + /* + * read devctl ioctl data + */ + if (ndi_dc_allochdl((void *)arg, &dcp) != NDI_SUCCESS) + return (EFAULT); + + switch (cmd) { + + case DEVCTL_DEVICE_RESET: + PCMU_DBG0(PCMU_DBG_IOCTL, dip, "DEVCTL_DEVICE_RESET\n"); + rv = ENOTSUP; + break; + + + case DEVCTL_BUS_QUIESCE: + PCMU_DBG0(PCMU_DBG_IOCTL, dip, "DEVCTL_BUS_QUIESCE\n"); + if (ndi_get_bus_state(dip, &bus_state) == NDI_SUCCESS) { + if (bus_state == BUS_QUIESCED) { + break; + } + } + (void) ndi_set_bus_state(dip, BUS_QUIESCED); + break; + + case DEVCTL_BUS_UNQUIESCE: + PCMU_DBG0(PCMU_DBG_IOCTL, dip, "DEVCTL_BUS_UNQUIESCE\n"); + if (ndi_get_bus_state(dip, &bus_state) == NDI_SUCCESS) { + if (bus_state == BUS_ACTIVE) { + break; + } + } + (void) ndi_set_bus_state(dip, BUS_ACTIVE); + break; + + case DEVCTL_BUS_RESET: + PCMU_DBG0(PCMU_DBG_IOCTL, dip, "DEVCTL_BUS_RESET\n"); + rv = ENOTSUP; + break; + + case DEVCTL_BUS_RESETALL: + PCMU_DBG0(PCMU_DBG_IOCTL, dip, "DEVCTL_BUS_RESETALL\n"); + rv = ENOTSUP; + break; + + default: + rv = ENOTTY; + } + + ndi_dc_freehdl(dcp); + return (rv); +} + +static int pcmu_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, + int flags, char *name, caddr_t valuep, int *lengthp) +{ + return (ddi_prop_op(dev, dip, prop_op, flags, name, valuep, lengthp)); +} +/* bus driver entry points */ + +/* + * bus map entry point: + * + * if map request is for an rnumber + * get the corresponding regspec from device node + * build a new regspec in our parent's format + * build a new map_req with the new regspec + * call up the tree to complete the mapping + */ +static int +pcmu_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp, + off_t off, off_t len, caddr_t *addrp) +{ + pcmu_t *pcmu_p = get_pcmu_soft_state(ddi_get_instance(dip)); + struct regspec p_regspec; + ddi_map_req_t p_mapreq; + int reglen, rval, r_no; + pci_regspec_t reloc_reg, *rp = &reloc_reg; + + PCMU_DBG2(PCMU_DBG_MAP, dip, "rdip=%s%d:", + ddi_driver_name(rdip), ddi_get_instance(rdip)); + + if (mp->map_flags & DDI_MF_USER_MAPPING) { + return (DDI_ME_UNIMPLEMENTED); + } + + switch (mp->map_type) { + case DDI_MT_REGSPEC: + reloc_reg = *(pci_regspec_t *)mp->map_obj.rp; /* dup whole */ + break; + + case DDI_MT_RNUMBER: + r_no = mp->map_obj.rnumber; + PCMU_DBG1(PCMU_DBG_MAP | PCMU_DBG_CONT, dip, " r#=%x", r_no); + + if (ddi_getlongprop(DDI_DEV_T_NONE, rdip, DDI_PROP_DONTPASS, + "reg", (caddr_t)&rp, ®len) != DDI_SUCCESS) { + return (DDI_ME_RNUMBER_RANGE); + } + + if (r_no < 0 || r_no >= reglen / sizeof (pci_regspec_t)) { + kmem_free(rp, reglen); + return (DDI_ME_RNUMBER_RANGE); + } + rp += r_no; + break; + + default: + return (DDI_ME_INVAL); + } + PCMU_DBG0(PCMU_DBG_MAP | PCMU_DBG_CONT, dip, "\n"); + + /* use "assigned-addresses" to relocate regspec within pci space */ + if (rval = pcmu_reloc_reg(dip, rdip, pcmu_p, rp)) { + goto done; + } + + /* adjust regspec according to mapping request */ + if (len) { + rp->pci_size_low = (uint_t)len; + } + rp->pci_phys_low += off; + + /* use "ranges" to translate relocated pci regspec into parent space */ + if (rval = pcmu_xlate_reg(pcmu_p, rp, &p_regspec)) { + goto done; + } + + p_mapreq = *mp; /* dup the whole structure */ + p_mapreq.map_type = DDI_MT_REGSPEC; + p_mapreq.map_obj.rp = &p_regspec; + rval = ddi_map(dip, &p_mapreq, 0, 0, addrp); + +done: + if (mp->map_type == DDI_MT_RNUMBER) { + kmem_free(rp - r_no, reglen); + } + return (rval); +} + +#ifdef DEBUG +int pcmu_peekfault_cnt = 0; +int pcmu_pokefault_cnt = 0; +#endif /* DEBUG */ + +static int +pcmu_do_poke(pcmu_t *pcmu_p, peekpoke_ctlops_t *in_args) +{ + pcmu_pbm_t *pcbm_p = pcmu_p->pcmu_pcbm_p; + int err = DDI_SUCCESS; + on_trap_data_t otd; + + mutex_enter(&pcbm_p->pcbm_pokeflt_mutex); + pcbm_p->pcbm_ontrap_data = &otd; + + /* Set up protected environment. */ + if (!on_trap(&otd, OT_DATA_ACCESS)) { + uintptr_t tramp = otd.ot_trampoline; + + otd.ot_trampoline = (uintptr_t)&poke_fault; + err = do_poke(in_args->size, (void *)in_args->dev_addr, + (void *)in_args->host_addr); + otd.ot_trampoline = tramp; + } else { + err = DDI_FAILURE; + } + + /* + * Read the async fault register for the PBM to see it sees + * a master-abort. + */ + pcmu_pbm_clear_error(pcbm_p); + + if (otd.ot_trap & OT_DATA_ACCESS) { + err = DDI_FAILURE; + } + + /* Take down protected environment. */ + no_trap(); + + pcbm_p->pcbm_ontrap_data = NULL; + mutex_exit(&pcbm_p->pcbm_pokeflt_mutex); + +#ifdef DEBUG + if (err == DDI_FAILURE) + pcmu_pokefault_cnt++; +#endif + return (err); +} + + +static int +pcmu_ctlops_poke(pcmu_t *pcmu_p, peekpoke_ctlops_t *in_args) +{ + return (pcmu_do_poke(pcmu_p, in_args)); +} + +/* ARGSUSED */ +static int +pcmu_do_peek(pcmu_t *pcmu_p, peekpoke_ctlops_t *in_args) +{ + int err = DDI_SUCCESS; + on_trap_data_t otd; + + if (!on_trap(&otd, OT_DATA_ACCESS)) { + uintptr_t tramp = otd.ot_trampoline; + + otd.ot_trampoline = (uintptr_t)&peek_fault; + err = do_peek(in_args->size, (void *)in_args->dev_addr, + (void *)in_args->host_addr); + otd.ot_trampoline = tramp; + } else + err = DDI_FAILURE; + + no_trap(); + +#ifdef DEBUG + if (err == DDI_FAILURE) + pcmu_peekfault_cnt++; +#endif + return (err); +} + + +static int +pcmu_ctlops_peek(pcmu_t *pcmu_p, peekpoke_ctlops_t *in_args, void *result) +{ + result = (void *)in_args->host_addr; + return (pcmu_do_peek(pcmu_p, in_args)); +} + +/* + * control ops entry point: + * + * Requests handled completely: + * DDI_CTLOPS_INITCHILD see pcmu_init_child() for details + * DDI_CTLOPS_UNINITCHILD + * DDI_CTLOPS_REPORTDEV see report_dev() for details + * DDI_CTLOPS_XLATE_INTRS nothing to do + * DDI_CTLOPS_IOMIN cache line size if streaming otherwise 1 + * DDI_CTLOPS_REGSIZE + * DDI_CTLOPS_NREGS + * DDI_CTLOPS_NINTRS + * DDI_CTLOPS_DVMAPAGESIZE + * DDI_CTLOPS_POKE + * DDI_CTLOPS_PEEK + * DDI_CTLOPS_QUIESCE + * DDI_CTLOPS_UNQUIESCE + * + * All others passed to parent. + */ +static int +pcmu_ctlops(dev_info_t *dip, dev_info_t *rdip, + ddi_ctl_enum_t op, void *arg, void *result) +{ + pcmu_t *pcmu_p = get_pcmu_soft_state(ddi_get_instance(dip)); + + switch (op) { + case DDI_CTLOPS_INITCHILD: + return (pcmu_init_child(pcmu_p, (dev_info_t *)arg)); + + case DDI_CTLOPS_UNINITCHILD: + return (pcmu_uninit_child(pcmu_p, (dev_info_t *)arg)); + + case DDI_CTLOPS_REPORTDEV: + return (pcmu_report_dev(rdip)); + + case DDI_CTLOPS_IOMIN: + /* + * If we are using the streaming cache, align at + * least on a cache line boundary. Otherwise use + * whatever alignment is passed in. + */ + return (DDI_SUCCESS); + + case DDI_CTLOPS_REGSIZE: + *((off_t *)result) = pcmu_get_reg_set_size(rdip, *((int *)arg)); + return (DDI_SUCCESS); + + case DDI_CTLOPS_NREGS: + *((uint_t *)result) = pcmu_get_nreg_set(rdip); + return (DDI_SUCCESS); + + case DDI_CTLOPS_DVMAPAGESIZE: + *((ulong_t *)result) = 0; + return (DDI_SUCCESS); + + case DDI_CTLOPS_POKE: + return (pcmu_ctlops_poke(pcmu_p, (peekpoke_ctlops_t *)arg)); + + case DDI_CTLOPS_PEEK: + return (pcmu_ctlops_peek(pcmu_p, (peekpoke_ctlops_t *)arg, + result)); + + case DDI_CTLOPS_AFFINITY: + break; + + case DDI_CTLOPS_QUIESCE: + return (DDI_FAILURE); + + case DDI_CTLOPS_UNQUIESCE: + return (DDI_FAILURE); + + default: + break; + } + + /* + * Now pass the request up to our parent. + */ + PCMU_DBG2(PCMU_DBG_CTLOPS, dip, + "passing request to parent: rdip=%s%d\n", + ddi_driver_name(rdip), ddi_get_instance(rdip)); + return (ddi_ctlops(dip, rdip, op, arg, result)); +} + + +/* ARGSUSED */ +static int +pcmu_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op, + ddi_intr_handle_impl_t *hdlp, void *result) +{ + pcmu_t *pcmu_p = get_pcmu_soft_state(ddi_get_instance(dip)); + int ret = DDI_SUCCESS; + + switch (intr_op) { + case DDI_INTROP_GETCAP: + /* GetCap will always fail for all non PCI devices */ + (void) pci_intx_get_cap(rdip, (int *)result); + break; + case DDI_INTROP_SETCAP: + ret = DDI_ENOTSUP; + break; + case DDI_INTROP_ALLOC: + *(int *)result = hdlp->ih_scratch1; + break; + case DDI_INTROP_FREE: + break; + case DDI_INTROP_GETPRI: + *(int *)result = hdlp->ih_pri ? hdlp->ih_pri : 0; + break; + case DDI_INTROP_SETPRI: + break; + case DDI_INTROP_ADDISR: + ret = pcmu_add_intr(dip, rdip, hdlp); + break; + case DDI_INTROP_REMISR: + ret = pcmu_remove_intr(dip, rdip, hdlp); + break; + case DDI_INTROP_ENABLE: + ret = pcmu_ib_update_intr_state(pcmu_p, rdip, hdlp, + PCMU_INTR_STATE_ENABLE); + break; + case DDI_INTROP_DISABLE: + ret = pcmu_ib_update_intr_state(pcmu_p, rdip, hdlp, + PCMU_INTR_STATE_DISABLE); + break; + case DDI_INTROP_SETMASK: + ret = pci_intx_set_mask(rdip); + break; + case DDI_INTROP_CLRMASK: + ret = pci_intx_clr_mask(rdip); + break; + case DDI_INTROP_GETPENDING: + ret = pci_intx_get_pending(rdip, (int *)result); + break; + case DDI_INTROP_NINTRS: + case DDI_INTROP_NAVAIL: + *(int *)result = i_ddi_get_nintrs(rdip); + break; + case DDI_INTROP_SUPPORTED_TYPES: + /* PCI nexus driver supports only fixed interrupts */ + *(int *)result = i_ddi_get_nintrs(rdip) ? + DDI_INTR_TYPE_FIXED : 0; + break; + default: + ret = DDI_ENOTSUP; + break; + } + + return (ret); +} + +/* + * CMU-CH specifics implementation: + * interrupt mapping register + * PBM configuration + * ECC and PBM error handling + */ + +/* called by pcmu_attach() DDI_ATTACH to initialize pci objects */ +static int +pcmu_obj_setup(pcmu_t *pcmu_p) +{ + int ret; + + mutex_enter(&pcmu_global_mutex); + pcmu_p->pcmu_rev = ddi_prop_get_int(DDI_DEV_T_ANY, pcmu_p->pcmu_dip, + DDI_PROP_DONTPASS, "module-revision#", 0); + + pcmu_ib_create(pcmu_p); + pcmu_cb_create(pcmu_p); + pcmu_ecc_create(pcmu_p); + pcmu_pbm_create(pcmu_p); + pcmu_err_create(pcmu_p); + if ((ret = pcmu_intr_setup(pcmu_p)) != DDI_SUCCESS) + goto done; + + pcmu_kstat_create(pcmu_p); +done: + mutex_exit(&pcmu_global_mutex); + if (ret != DDI_SUCCESS) { + cmn_err(CE_NOTE, "Interrupt register failure, returning 0x%x\n", + ret); + } + return (ret); +} + +/* called by pcmu_detach() DDI_DETACH to destroy pci objects */ +static void +pcmu_obj_destroy(pcmu_t *pcmu_p) +{ + mutex_enter(&pcmu_global_mutex); + + pcmu_kstat_destroy(pcmu_p); + pcmu_pbm_destroy(pcmu_p); + pcmu_err_destroy(pcmu_p); + pcmu_ecc_destroy(pcmu_p); + pcmu_cb_destroy(pcmu_p); + pcmu_ib_destroy(pcmu_p); + pcmu_intr_teardown(pcmu_p); + + mutex_exit(&pcmu_global_mutex); +} + +/* called by pcmu_attach() DDI_RESUME to (re)initialize pci objects */ +static void +pcmu_obj_resume(pcmu_t *pcmu_p) +{ + mutex_enter(&pcmu_global_mutex); + + pcmu_ib_configure(pcmu_p->pcmu_ib_p); + pcmu_ecc_configure(pcmu_p); + pcmu_ib_resume(pcmu_p->pcmu_ib_p); + u2u_ittrans_resume((u2u_ittrans_data_t **) + &(pcmu_p->pcmu_cb_p->pcb_ittrans_cookie)); + + pcmu_pbm_configure(pcmu_p->pcmu_pcbm_p); + + pcmu_cb_resume(pcmu_p->pcmu_cb_p); + + pcmu_pbm_resume(pcmu_p->pcmu_pcbm_p); + + mutex_exit(&pcmu_global_mutex); +} + +/* called by pcmu_detach() DDI_SUSPEND to suspend pci objects */ +static void +pcmu_obj_suspend(pcmu_t *pcmu_p) +{ + mutex_enter(&pcmu_global_mutex); + + pcmu_pbm_suspend(pcmu_p->pcmu_pcbm_p); + pcmu_ib_suspend(pcmu_p->pcmu_ib_p); + pcmu_cb_suspend(pcmu_p->pcmu_cb_p); + + mutex_exit(&pcmu_global_mutex); +} + +static int +pcmu_intr_setup(pcmu_t *pcmu_p) +{ + dev_info_t *dip = pcmu_p->pcmu_dip; + pcmu_pbm_t *pcbm_p = pcmu_p->pcmu_pcbm_p; + pcmu_cb_t *pcb_p = pcmu_p->pcmu_cb_p; + int i, no_of_intrs; + + /* + * Get the interrupts property. + */ + if (ddi_getlongprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS, + "interrupts", (caddr_t)&pcmu_p->pcmu_inos, + &pcmu_p->pcmu_inos_len) != DDI_SUCCESS) { + cmn_err(CE_PANIC, "%s%d: no interrupts property\n", + ddi_driver_name(dip), ddi_get_instance(dip)); + } + + /* + * figure out number of interrupts in the "interrupts" property + * and convert them all into ino. + */ + i = ddi_getprop(DDI_DEV_T_ANY, dip, 0, "#interrupt-cells", 1); + i = CELLS_1275_TO_BYTES(i); + no_of_intrs = pcmu_p->pcmu_inos_len / i; + for (i = 0; i < no_of_intrs; i++) { + pcmu_p->pcmu_inos[i] = + PCMU_IB_MONDO_TO_INO(pcmu_p->pcmu_inos[i]); + } + + pcb_p->pcb_no_of_inos = no_of_intrs; + if (i = pcmu_ecc_register_intr(pcmu_p)) { + goto teardown; + } + + intr_dist_add(pcmu_cb_intr_dist, pcb_p); + pcmu_ecc_enable_intr(pcmu_p); + + if (i = pcmu_pbm_register_intr(pcbm_p)) { + intr_dist_rem(pcmu_cb_intr_dist, pcb_p); + goto teardown; + } + intr_dist_add(pcmu_pbm_intr_dist, pcbm_p); + pcmu_ib_intr_enable(pcmu_p, pcmu_p->pcmu_inos[CBNINTR_PBM]); + + intr_dist_add_weighted(pcmu_ib_intr_dist_all, pcmu_p->pcmu_ib_p); + return (DDI_SUCCESS); +teardown: + pcmu_intr_teardown(pcmu_p); + return (i); +} + +/* + * pcmu_fix_ranges - fixes the config space entry of the "ranges" + * property on CMU-CH platforms + */ +void +pcmu_fix_ranges(pcmu_ranges_t *rng_p, int rng_entries) +{ + int i; + for (i = 0; i < rng_entries; i++, rng_p++) { + if ((rng_p->child_high & PCI_REG_ADDR_M) == PCI_ADDR_CONFIG) + rng_p->parent_low |= rng_p->child_high; + } +} + +/* + * map_pcmu_registers + * + * This function is called from the attach routine to map the registers + * accessed by this driver. + * + * used by: pcmu_attach() + * + * return value: DDI_FAILURE on failure + */ +static int +map_pcmu_registers(pcmu_t *pcmu_p, dev_info_t *dip) +{ + ddi_device_acc_attr_t attr; + + attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; + attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; + + attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC; + if (ddi_regs_map_setup(dip, 0, &pcmu_p->pcmu_address[0], 0, 0, + &attr, &pcmu_p->pcmu_ac[0]) != DDI_SUCCESS) { + cmn_err(CE_WARN, "%s%d: unable to map reg entry 0\n", + ddi_driver_name(dip), ddi_get_instance(dip)); + return (DDI_FAILURE); + } + + /* + * We still use pcmu_address[2] + */ + if (ddi_regs_map_setup(dip, 2, &pcmu_p->pcmu_address[2], 0, 0, + &attr, &pcmu_p->pcmu_ac[2]) != DDI_SUCCESS) { + cmn_err(CE_WARN, "%s%d: unable to map reg entry 2\n", + ddi_driver_name(dip), ddi_get_instance(dip)); + ddi_regs_map_free(&pcmu_p->pcmu_ac[0]); + return (DDI_FAILURE); + } + + /* + * The second register set contains the bridge's configuration + * header. This header is at the very beginning of the bridge's + * configuration space. This space has litte-endian byte order. + */ + attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; + if (ddi_regs_map_setup(dip, 1, &pcmu_p->pcmu_address[1], 0, + PCI_CONF_HDR_SIZE, &attr, &pcmu_p->pcmu_ac[1]) != DDI_SUCCESS) { + + cmn_err(CE_WARN, "%s%d: unable to map reg entry 1\n", + ddi_driver_name(dip), ddi_get_instance(dip)); + ddi_regs_map_free(&pcmu_p->pcmu_ac[0]); + return (DDI_FAILURE); + } + PCMU_DBG2(PCMU_DBG_ATTACH, dip, "address (%p,%p)\n", + pcmu_p->pcmu_address[0], pcmu_p->pcmu_address[1]); + return (DDI_SUCCESS); +} + +/* + * unmap_pcmu_registers: + * + * This routine unmap the registers mapped by map_pcmu_registers. + * + * used by: pcmu_detach() + * + * return value: none + */ +static void +unmap_pcmu_registers(pcmu_t *pcmu_p) +{ + ddi_regs_map_free(&pcmu_p->pcmu_ac[0]); + ddi_regs_map_free(&pcmu_p->pcmu_ac[1]); + ddi_regs_map_free(&pcmu_p->pcmu_ac[2]); +} + +/* + * These convenience wrappers relies on map_pcmu_registers() to setup + * pcmu_address[0-2] correctly at first. + */ +static uintptr_t +get_reg_base(pcmu_t *pcmu_p) +{ + return ((uintptr_t)pcmu_p->pcmu_address[2]); +} + +/* The CMU-CH config reg base is always the 2nd reg entry */ +static uintptr_t +get_config_reg_base(pcmu_t *pcmu_p) +{ + return ((uintptr_t)(pcmu_p->pcmu_address[1])); +} + +uint64_t +ib_get_map_reg(pcmu_ib_mondo_t mondo, uint32_t cpu_id) +{ + return ((mondo) | (cpu_id << PCMU_INTR_MAP_REG_TID_SHIFT) | + PCMU_INTR_MAP_REG_VALID); + +} + +uint32_t +ib_map_reg_get_cpu(volatile uint64_t reg) +{ + return ((reg & PCMU_INTR_MAP_REG_TID) >> + PCMU_INTR_MAP_REG_TID_SHIFT); +} + +uint64_t * +ib_intr_map_reg_addr(pcmu_ib_t *pib_p, pcmu_ib_ino_t ino) +{ + uint64_t *addr; + + ASSERT(ino & 0x20); + addr = (uint64_t *)(pib_p->pib_obio_intr_map_regs + + (((uint_t)ino & 0x1f) << 3)); + return (addr); +} + +uint64_t * +ib_clear_intr_reg_addr(pcmu_ib_t *pib_p, pcmu_ib_ino_t ino) +{ + uint64_t *addr; + + ASSERT(ino & 0x20); + addr = (uint64_t *)(pib_p->pib_obio_clear_intr_regs + + (((uint_t)ino & 0x1f) << 3)); + return (addr); +} + +uintptr_t +pcmu_ib_setup(pcmu_ib_t *pib_p) +{ + pcmu_t *pcmu_p = pib_p->pib_pcmu_p; + uintptr_t a = get_reg_base(pcmu_p); + + pib_p->pib_ign = PCMU_ID_TO_IGN(pcmu_p->pcmu_id); + pib_p->pib_max_ino = PCMU_MAX_INO; + pib_p->pib_obio_intr_map_regs = a + PCMU_IB_OBIO_INTR_MAP_REG_OFFSET; + pib_p->pib_obio_clear_intr_regs = + a + PCMU_IB_OBIO_CLEAR_INTR_REG_OFFSET; + return (a); +} + +/* + * Return the cpuid to to be used for an ino. + * + * On multi-function pci devices, functions have separate devinfo nodes and + * interrupts. + * + * This function determines if there is already an established slot-oriented + * interrupt-to-cpu binding established, if there is then it returns that + * cpu. Otherwise a new cpu is selected by intr_dist_cpuid(). + * + * The devinfo node we are trying to associate a cpu with is + * ino_p->pino_ih_head->ih_dip. + */ +uint32_t +pcmu_intr_dist_cpuid(pcmu_ib_t *pib_p, pcmu_ib_ino_info_t *ino_p) +{ + dev_info_t *rdip = ino_p->pino_ih_head->ih_dip; + dev_info_t *prdip = ddi_get_parent(rdip); + pcmu_ib_ino_info_t *sino_p; + dev_info_t *sdip; + dev_info_t *psdip; + char *buf1 = NULL, *buf2 = NULL; + char *s1, *s2, *s3; + int l2; + int cpu_id; + + /* must be CMU-CH driver parent (not ebus) */ + if (strcmp(ddi_driver_name(prdip), "pcicmu") != 0) + goto newcpu; + + /* + * From PCI 1275 binding: 2.2.1.3 Unit Address representation: + * Since the "unit-number" is the address that appears in on Open + * Firmware 'device path', it follows that only the DD and DD,FF + * forms of the text representation can appear in a 'device path'. + * + * The rdip unit address is of the form "DD[,FF]". Define two + * unit address strings that represent same-slot use: "DD" and "DD,". + * The first compare uses strcmp, the second uses strncmp. + */ + s1 = ddi_get_name_addr(rdip); + if (s1 == NULL) { + goto newcpu; + } + + buf1 = kmem_alloc(MAXNAMELEN, KM_SLEEP); /* strcmp */ + buf2 = kmem_alloc(MAXNAMELEN, KM_SLEEP); /* strncmp */ + s1 = strcpy(buf1, s1); + s2 = strcpy(buf2, s1); + + s1 = strrchr(s1, ','); + if (s1) { + *s1 = '\0'; /* have "DD,FF" */ + s1 = buf1; /* search via strcmp "DD" */ + + s2 = strrchr(s2, ','); + *(s2 + 1) = '\0'; + s2 = buf2; + l2 = strlen(s2); /* search via strncmp "DD," */ + } else { + (void) strcat(s2, ","); /* have "DD" */ + l2 = strlen(s2); /* search via strncmp "DD," */ + } + + /* + * Search the established ino list for devinfo nodes bound + * to an ino that matches one of the slot use strings. + */ + ASSERT(MUTEX_HELD(&pib_p->pib_ino_lst_mutex)); + for (sino_p = pib_p->pib_ino_lst; sino_p; sino_p = sino_p->pino_next) { + /* skip self and non-established */ + if ((sino_p == ino_p) || (sino_p->pino_established == 0)) + continue; + + /* skip non-siblings */ + sdip = sino_p->pino_ih_head->ih_dip; + psdip = ddi_get_parent(sdip); + if (psdip != prdip) + continue; + + /* must be CMU-CH driver parent (not ebus) */ + if (strcmp(ddi_driver_name(psdip), "pcicmu") != 0) + continue; + + s3 = ddi_get_name_addr(sdip); + if ((s1 && (strcmp(s1, s3) == 0)) || + (strncmp(s2, s3, l2) == 0)) { + extern int intr_dist_debug; + + if (intr_dist_debug) { + cmn_err(CE_CONT, "intr_dist: " + "pcicmu`pcmu_intr_dist_cpuid " + "%s#%d %s: cpu %d established " + "by %s#%d %s\n", ddi_driver_name(rdip), + ddi_get_instance(rdip), + ddi_deviname(rdip, buf1), + sino_p->pino_cpuid, + ddi_driver_name(sdip), + ddi_get_instance(sdip), + ddi_deviname(sdip, buf2)); + } + break; + } + } + + /* If a slot use match is found then use established cpu */ + if (sino_p) { + cpu_id = sino_p->pino_cpuid; /* target established cpu */ + goto out; + } + +newcpu: cpu_id = intr_dist_cpuid(); /* target new cpu */ + +out: if (buf1) + kmem_free(buf1, MAXNAMELEN); + if (buf2) + kmem_free(buf2, MAXNAMELEN); + return (cpu_id); +} + +void +pcmu_cb_teardown(pcmu_t *pcmu_p) +{ + pcmu_cb_t *pcb_p = pcmu_p->pcmu_cb_p; + + u2u_ittrans_uninit((u2u_ittrans_data_t *)pcb_p->pcb_ittrans_cookie); +} + +int +pcmu_ecc_add_intr(pcmu_t *pcmu_p, int inum, pcmu_ecc_intr_info_t *eii_p) +{ + uint32_t mondo; + + mondo = ((pcmu_p->pcmu_cb_p->pcb_ign << PCMU_INO_BITS) | + pcmu_p->pcmu_inos[inum]); + + VERIFY(add_ivintr(mondo, pcmu_pil[inum], pcmu_ecc_intr, + (caddr_t)eii_p, NULL) == 0); + return (PCMU_ATTACH_RETCODE(PCMU_ECC_OBJ, + PCMU_OBJ_INTR_ADD, DDI_SUCCESS)); +} + +/* ARGSUSED */ +void +pcmu_ecc_rem_intr(pcmu_t *pcmu_p, int inum, pcmu_ecc_intr_info_t *eii_p) +{ + uint32_t mondo; + + mondo = ((pcmu_p->pcmu_cb_p->pcb_ign << PCMU_INO_BITS) | + pcmu_p->pcmu_inos[inum]); + rem_ivintr(mondo, NULL); +} + +void +pcmu_pbm_configure(pcmu_pbm_t *pcbm_p) +{ + pcmu_t *pcmu_p = pcbm_p->pcbm_pcmu_p; + dev_info_t *dip = pcmu_p->pcmu_dip; + +#define pbm_err ((PCMU_PCI_AFSR_E_MASK << PCMU_PCI_AFSR_PE_SHIFT) | \ + (PCMU_PCI_AFSR_E_MASK << PCMU_PCI_AFSR_SE_SHIFT)) +#define csr_err (PCI_STAT_PERROR | PCI_STAT_S_PERROR | \ + PCI_STAT_R_MAST_AB | PCI_STAT_R_TARG_AB | \ + PCI_STAT_S_TARG_AB | PCI_STAT_S_PERROR) + + /* + * Clear any PBM errors. + */ + *pcbm_p->pcbm_async_flt_status_reg = pbm_err; + + /* + * Clear error bits in configuration status register. + */ + PCMU_DBG1(PCMU_DBG_ATTACH, dip, + "pcmu_pbm_configure: conf status reg=%x\n", csr_err); + + pcbm_p->pcbm_config_header->ch_status_reg = csr_err; + + PCMU_DBG1(PCMU_DBG_ATTACH, dip, + "pcmu_pbm_configure: conf status reg==%x\n", + pcbm_p->pcbm_config_header->ch_status_reg); + + (void) ndi_prop_update_int(DDI_DEV_T_ANY, dip, "latency-timer", + (int)pcbm_p->pcbm_config_header->ch_latency_timer_reg); +#undef pbm_err +#undef csr_err +} + +uint_t +pcmu_pbm_disable_errors(pcmu_pbm_t *pcbm_p) +{ + pcmu_t *pcmu_p = pcbm_p->pcbm_pcmu_p; + pcmu_ib_t *pib_p = pcmu_p->pcmu_ib_p; + + /* + * Disable error and streaming byte hole interrupts via the + * PBM control register. + */ + *pcbm_p->pcbm_ctrl_reg &= ~PCMU_PCI_CTRL_ERR_INT_EN; + + /* + * Disable error interrupts via the interrupt mapping register. + */ + pcmu_ib_intr_disable(pib_p, + pcmu_p->pcmu_inos[CBNINTR_PBM], PCMU_IB_INTR_NOWAIT); + return (BF_NONE); +} + +void +pcmu_cb_setup(pcmu_t *pcmu_p) +{ + uint64_t csr, csr_pa, pa; + pcmu_cb_t *pcb_p = pcmu_p->pcmu_cb_p; + + pcb_p->pcb_ign = PCMU_ID_TO_IGN(pcmu_p->pcmu_id); + pa = (uint64_t)hat_getpfnum(kas.a_hat, pcmu_p->pcmu_address[0]); + pcb_p->pcb_base_pa = pa = pa >> (32 - MMU_PAGESHIFT) << 32; + pcb_p->pcb_map_pa = pa + PCMU_IB_OBIO_INTR_MAP_REG_OFFSET; + pcb_p->pcb_clr_pa = pa + PCMU_IB_OBIO_CLEAR_INTR_REG_OFFSET; + pcb_p->pcb_obsta_pa = pa + PCMU_IB_OBIO_INTR_STATE_DIAG_REG; + + csr_pa = pa + PCMU_CB_CONTROL_STATUS_REG_OFFSET; + csr = lddphysio(csr_pa); + + /* + * Clear any pending address parity errors. + */ + if (csr & PCMU_CB_CONTROL_STATUS_APERR) { + csr |= PCMU_CB_CONTROL_STATUS_APERR; + cmn_err(CE_WARN, "clearing UPA address parity error\n"); + } + csr |= PCMU_CB_CONTROL_STATUS_APCKEN; + csr &= ~PCMU_CB_CONTROL_STATUS_IAP; + stdphysio(csr_pa, csr); + + u2u_ittrans_init(pcmu_p, + (u2u_ittrans_data_t **)&pcb_p->pcb_ittrans_cookie); +} + +void +pcmu_ecc_setup(pcmu_ecc_t *pecc_p) +{ + pecc_p->pecc_ue.pecc_errpndg_mask = 0; + pecc_p->pecc_ue.pecc_offset_mask = PCMU_ECC_UE_AFSR_DW_OFFSET; + pecc_p->pecc_ue.pecc_offset_shift = PCMU_ECC_UE_AFSR_DW_OFFSET_SHIFT; + pecc_p->pecc_ue.pecc_size_log2 = 3; +} + +static uintptr_t +get_pbm_reg_base(pcmu_t *pcmu_p) +{ + return ((uintptr_t)(pcmu_p->pcmu_address[0])); +} + +void +pcmu_pbm_setup(pcmu_pbm_t *pcbm_p) +{ + pcmu_t *pcmu_p = pcbm_p->pcbm_pcmu_p; + + /* + * Get the base virtual address for the PBM control block. + */ + uintptr_t a = get_pbm_reg_base(pcmu_p); + + /* + * Get the virtual address of the PCI configuration header. + * This should be mapped little-endian. + */ + pcbm_p->pcbm_config_header = + (config_header_t *)get_config_reg_base(pcmu_p); + + /* + * Get the virtual addresses for control, error and diag + * registers. + */ + pcbm_p->pcbm_ctrl_reg = (uint64_t *)(a + PCMU_PCI_CTRL_REG_OFFSET); + pcbm_p->pcbm_diag_reg = (uint64_t *)(a + PCMU_PCI_DIAG_REG_OFFSET); + pcbm_p->pcbm_async_flt_status_reg = + (uint64_t *)(a + PCMU_PCI_ASYNC_FLT_STATUS_REG_OFFSET); + pcbm_p->pcbm_async_flt_addr_reg = + (uint64_t *)(a + PCMU_PCI_ASYNC_FLT_ADDR_REG_OFFSET); +} + +/*ARGSUSED*/ +void +pcmu_pbm_teardown(pcmu_pbm_t *pcbm_p) +{ +} + +int +pcmu_get_numproxy(dev_info_t *dip) +{ + return (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, + "#upa-interrupt-proxies", 1)); +} + +int +pcmu_get_portid(dev_info_t *dip) +{ + return (ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, + "portid", -1)); +} + +/* + * CMU-CH Performance Events. + */ +static pcmu_kev_mask_t +pcicmu_pcmu_events[] = { + {"pio_cycles_b", 0xf}, {"interrupts", 0x11}, + {"upa_inter_nack", 0x12}, {"pio_reads", 0x13}, + {"pio_writes", 0x14}, + {"clear_pic", 0x1f} +}; + +/* + * Create the picN kstat's. + */ +void +pcmu_kstat_init() +{ + pcmu_name_kstat = (pcmu_ksinfo_t *)kmem_alloc(sizeof (pcmu_ksinfo_t), + KM_NOSLEEP); + + if (pcmu_name_kstat == NULL) { + cmn_err(CE_WARN, "pcicmu : no space for kstat\n"); + } else { + pcmu_name_kstat->pic_no_evs = + sizeof (pcicmu_pcmu_events) / sizeof (pcmu_kev_mask_t); + pcmu_name_kstat->pic_shift[0] = PCMU_SHIFT_PIC0; + pcmu_name_kstat->pic_shift[1] = PCMU_SHIFT_PIC1; + pcmu_create_name_kstat("pcmup", + pcmu_name_kstat, pcicmu_pcmu_events); + } +} + +/* + * Called from _fini() + */ +void +pcmu_kstat_fini() +{ + if (pcmu_name_kstat != NULL) { + pcmu_delete_name_kstat(pcmu_name_kstat); + kmem_free(pcmu_name_kstat, sizeof (pcmu_ksinfo_t)); + pcmu_name_kstat = NULL; + } +} + +/* + * Create the performance 'counters' kstat. + */ +void +pcmu_add_upstream_kstat(pcmu_t *pcmu_p) +{ + pcmu_cntr_pa_t *cntr_pa_p = &pcmu_p->pcmu_uks_pa; + uint64_t regbase = va_to_pa((void *)get_reg_base(pcmu_p)); + + cntr_pa_p->pcr_pa = regbase + PCMU_PERF_PCR_OFFSET; + cntr_pa_p->pic_pa = regbase + PCMU_PERF_PIC_OFFSET; + pcmu_p->pcmu_uksp = pcmu_create_cntr_kstat(pcmu_p, "pcmup", + NUM_OF_PICS, pcmu_cntr_kstat_pa_update, cntr_pa_p); +} + +/* + * u2u_ittrans_init() is caled from in pci.c's pcmu_cb_setup() per CMU. + * Second argument "ittrans_cookie" is address of pcb_ittrans_cookie in + * pcb_p member. allocated interrupt block is returned in it. + */ +static void +u2u_ittrans_init(pcmu_t *pcmu_p, u2u_ittrans_data_t **ittrans_cookie) +{ + + u2u_ittrans_data_t *u2u_trans_p; + ddi_device_acc_attr_t attr; + int ret; + int board; + + /* + * Allocate the data structure to support U2U's + * interrupt target translations. + */ + u2u_trans_p = (u2u_ittrans_data_t *) + kmem_zalloc(sizeof (u2u_ittrans_data_t), KM_SLEEP); + + /* + * Get other properties, "board#" + */ + board = ddi_getprop(DDI_DEV_T_ANY, pcmu_p->pcmu_dip, + DDI_PROP_DONTPASS, "board#", -1); + + u2u_trans_p->u2u_board = board; + + if (board == -1) { + /* this cannot happen on production systems */ + cmn_err(CE_PANIC, "u2u:Invalid property;board = %d", board); + } + + /* + * Initialize interrupt target translations mutex. + */ + mutex_init(&(u2u_trans_p->u2u_ittrans_lock), "u2u_ittrans_lock", + MUTEX_DEFAULT, NULL); + + /* + * Get U2U's registers space by ddi_regs_map_setup(9F) + */ + attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; + attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; + attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC; + + ret = ddi_regs_map_setup(pcmu_p->pcmu_dip, + REGS_INDEX_OF_U2U, (caddr_t *)(&(u2u_trans_p->u2u_regs_base)), + 0, 0, &attr, &(u2u_trans_p->u2u_acc)); + + /* + * check result of ddi_regs_map_setup(). + */ + if (ret != DDI_SUCCESS) { + cmn_err(CE_PANIC, "u2u%d: registers map setup failed", board); + } + + /* + * Read Port-id(1 byte) in u2u + */ + u2u_trans_p->u2u_port_id = *(volatile int32_t *) + (u2u_trans_p->u2u_regs_base + U2U_PID_REGISTER_OFFSET); + + if (pcmu_p->pcmu_id != u2u_trans_p->u2u_port_id) { + cmn_err(CE_PANIC, "u2u%d: Invalid Port-ID", board); + } + + *ittrans_cookie = u2u_trans_p; +} + +/* + * u2u_ittras_resume() is called from pcmu_obj_resume() at DDI_RESUME entry. + */ +static void +u2u_ittrans_resume(u2u_ittrans_data_t **ittrans_cookie) +{ + + u2u_ittrans_data_t *u2u_trans_p; + u2u_ittrans_id_t *ittrans_id_p; + uintptr_t data_reg_addr; + int ix; + + u2u_trans_p = *ittrans_cookie; + + /* + * Set U2U Data Register + */ + for (ix = 0; ix < U2U_DATA_NUM; ix++) { + ittrans_id_p = &(u2u_trans_p->u2u_ittrans_id[ix]); + data_reg_addr = u2u_trans_p->u2u_regs_base + + U2U_DATA_REGISTER_OFFSET + (ix * sizeof (uint64_t)); + if (ittrans_id_p->u2u_ino_map_reg == NULL) { + /* This index was not set */ + continue; + } + *(volatile uint32_t *) (data_reg_addr) = + (uint32_t)ittrans_id_p->u2u_tgt_cpu_id; + + } +} + +/* + * u2u_ittras_uninit() is called from ib_destroy() at detach, + * or occuring error in attach. + */ +static void +u2u_ittrans_uninit(u2u_ittrans_data_t *ittrans_cookie) +{ + + if (ittrans_cookie == NULL) { + return; /* not support */ + } + + if (ittrans_cookie == (u2u_ittrans_data_t *)(-1)) { + return; /* illeagal case */ + } + + ddi_regs_map_free(&(ittrans_cookie->u2u_acc)); + mutex_destroy(&(ittrans_cookie->u2u_ittrans_lock)); + kmem_free((void *)ittrans_cookie, sizeof (u2u_ittrans_data_t)); +} + +/* + * This routine,u2u_translate_tgtid(, , cpu_id, pino_map_reg), + * searches index having same value of pino_map_reg, or empty. + * Then, stores cpu_id in a U2U Data Register as this index, + * and return this index. + */ +int +u2u_translate_tgtid(pcmu_t *pcmu_p, uint_t cpu_id, + volatile uint64_t *pino_map_reg) +{ + + int index = -1; + int ix; + int err_level; /* severity level for cmn_err */ + u2u_ittrans_id_t *ittrans_id_p; + uintptr_t data_reg_addr; + u2u_ittrans_data_t *ittrans_cookie; + + ittrans_cookie = + (u2u_ittrans_data_t *)(pcmu_p->pcmu_cb_p->pcb_ittrans_cookie); + + if (ittrans_cookie == NULL) { + return (cpu_id); + } + + if (ittrans_cookie == (u2u_ittrans_data_t *)(-1)) { + return (-1); /* illeagal case */ + } + + mutex_enter(&(ittrans_cookie->u2u_ittrans_lock)); + + /* + * Decide index No. of U2U Data registers in either + * already used by same pino_map_reg, or empty. + */ + for (ix = 0; ix < U2U_DATA_NUM; ix++) { + ittrans_id_p = &(ittrans_cookie->u2u_ittrans_id[ix]); + if (ittrans_id_p->u2u_ino_map_reg == pino_map_reg) { + /* already used this pino_map_reg */ + index = ix; + break; + } + if (index == -1 && + ittrans_id_p->u2u_ino_map_reg == NULL) { + index = ix; + } + } + + if (index == -1) { + if (panicstr) { + err_level = CE_WARN; + } else { + err_level = CE_PANIC; + } + cmn_err(err_level, "u2u%d:No more U2U-Data regs!!", + ittrans_cookie->u2u_board); + return (cpu_id); + } + + /* + * For U2U + * set cpu_id into u2u_data_reg by index. + * ((uint64_t)(u2u_regs_base + * + U2U_DATA_REGISTER_OFFSET))[index] = cpu_id; + */ + + data_reg_addr = ittrans_cookie->u2u_regs_base + + U2U_DATA_REGISTER_OFFSET + + (index * sizeof (uint64_t)); + + /* + * Set cpu_id into U2U Data register[index] + */ + *(volatile uint32_t *) (data_reg_addr) = (uint32_t)cpu_id; + + /* + * Setup for software, excepting at panicing. + * and rebooting, etc...? + */ + if (!panicstr) { + ittrans_id_p = &(ittrans_cookie->u2u_ittrans_id[index]); + ittrans_id_p->u2u_tgt_cpu_id = cpu_id; + ittrans_id_p->u2u_ino_map_reg = pino_map_reg; + } + + mutex_exit(&(ittrans_cookie->u2u_ittrans_lock)); + + return (index); +} + +/* + * u2u_ittrans_cleanup() is called from common_pcmu_ib_intr_disable() + * after called intr_rem_cpu(mondo). + */ +void +u2u_ittrans_cleanup(u2u_ittrans_data_t *ittrans_cookie, + volatile uint64_t *pino_map_reg) +{ + + int ix; + u2u_ittrans_id_t *ittrans_id_p; + + if (ittrans_cookie == NULL) { + return; + } + + if (ittrans_cookie == (u2u_ittrans_data_t *)(-1)) { + return; /* illeagal case */ + } + + mutex_enter(&(ittrans_cookie->u2u_ittrans_lock)); + + for (ix = 0; ix < U2U_DATA_NUM; ix++) { + ittrans_id_p = &(ittrans_cookie->u2u_ittrans_id[ix]); + if (ittrans_id_p->u2u_ino_map_reg == pino_map_reg) { + ittrans_id_p->u2u_ino_map_reg = NULL; + break; + } + } + + mutex_exit(&(ittrans_cookie->u2u_ittrans_lock)); +} + +/* + * pcmu_ecc_classify, called by ecc_handler to classify ecc errors + * and determine if we should panic or not. + */ +void +pcmu_ecc_classify(uint64_t err, pcmu_ecc_errstate_t *ecc_err_p) +{ + struct async_flt *ecc = &ecc_err_p->ecc_aflt; + /* LINTED */ + pcmu_t *pcmu_p = ecc_err_p->ecc_ii_p.pecc_p->pecc_pcmu_p; + + ASSERT(MUTEX_HELD(&pcmu_p->pcmu_err_mutex)); + + ecc_err_p->ecc_bridge_type = PCI_OPLCMU; /* RAGS */ + /* + * Get the parent bus id that caused the error. + */ + ecc_err_p->ecc_dev_id = (ecc_err_p->ecc_afsr & PCMU_ECC_UE_AFSR_ID) + >> PCMU_ECC_UE_AFSR_ID_SHIFT; + /* + * Determine the doubleword offset of the error. + */ + ecc_err_p->ecc_dw_offset = (ecc_err_p->ecc_afsr & + PCMU_ECC_UE_AFSR_DW_OFFSET) >> PCMU_ECC_UE_AFSR_DW_OFFSET_SHIFT; + /* + * Determine the primary error type. + */ + switch (err) { + case PCMU_ECC_UE_AFSR_E_PIO: + if (ecc_err_p->pecc_pri) { + ecc->flt_erpt_class = PCI_ECC_PIO_UE; + } else { + ecc->flt_erpt_class = PCI_ECC_SEC_PIO_UE; + } + /* For CMU-CH, a UE is always fatal. */ + ecc->flt_panic = 1; + break; + + default: + return; + } +} + +/* + * pcmu_pbm_classify, called by pcmu_pbm_afsr_report to classify piow afsr. + */ +int +pcmu_pbm_classify(pcmu_pbm_errstate_t *pbm_err_p) +{ + uint32_t e; + int nerr = 0; + char **tmp_class; + + if (pbm_err_p->pcbm_pri) { + tmp_class = &pbm_err_p->pcbm_pci.pcmu_err_class; + e = PBM_AFSR_TO_PRIERR(pbm_err_p->pbm_afsr); + pbm_err_p->pbm_log = FM_LOG_PCI; + } else { + tmp_class = &pbm_err_p->pbm_err_class; + e = PBM_AFSR_TO_SECERR(pbm_err_p->pbm_afsr); + pbm_err_p->pbm_log = FM_LOG_PBM; + } + + if (e & PCMU_PCI_AFSR_E_MA) { + *tmp_class = pbm_err_p->pcbm_pri ? PCI_MA : PCI_SEC_MA; + nerr++; + } + return (nerr); +} + +/* + * Function used to clear PBM/PCI/IOMMU error state after error handling + * is complete. Only clearing error bits which have been logged. Called by + * pcmu_pbm_err_handler and pcmu_bus_exit. + */ +static void +pcmu_clear_error(pcmu_t *pcmu_p, pcmu_pbm_errstate_t *pbm_err_p) +{ + pcmu_pbm_t *pcbm_p = pcmu_p->pcmu_pcbm_p; + + ASSERT(MUTEX_HELD(&pcbm_p->pcbm_pcmu_p->pcmu_err_mutex)); + + *pcbm_p->pcbm_ctrl_reg = pbm_err_p->pbm_ctl_stat; + *pcbm_p->pcbm_async_flt_status_reg = pbm_err_p->pbm_afsr; + pcbm_p->pcbm_config_header->ch_status_reg = + pbm_err_p->pcbm_pci.pcmu_cfg_stat; +} + +/*ARGSUSED*/ +int +pcmu_pbm_err_handler(dev_info_t *dip, ddi_fm_error_t *derr, + const void *impl_data, int caller) +{ + int fatal = 0; + int nonfatal = 0; + int unknown = 0; + uint32_t prierr, secerr; + pcmu_pbm_errstate_t pbm_err; + pcmu_t *pcmu_p = (pcmu_t *)impl_data; + int ret = 0; + + ASSERT(MUTEX_HELD(&pcmu_p->pcmu_err_mutex)); + pcmu_pbm_errstate_get(pcmu_p, &pbm_err); + + derr->fme_ena = derr->fme_ena ? derr->fme_ena : + fm_ena_generate(0, FM_ENA_FMT1); + + prierr = PBM_AFSR_TO_PRIERR(pbm_err.pbm_afsr); + secerr = PBM_AFSR_TO_SECERR(pbm_err.pbm_afsr); + + if (derr->fme_flag == DDI_FM_ERR_PEEK) { + /* + * For ddi_peek treat all events as nonfatal. We only + * really call this function so that pcmu_clear_error() + * and ndi_fm_handler_dispatch() will get called. + */ + nonfatal++; + goto done; + } else if (derr->fme_flag == DDI_FM_ERR_POKE) { + /* + * For ddi_poke we can treat as nonfatal if the + * following conditions are met : + * 1. Make sure only primary error is MA/TA + * 2. Make sure no secondary error + * 3. check pci config header stat reg to see MA/TA is + * logged. We cannot verify only MA/TA is recorded + * since it gets much more complicated when a + * PCI-to-PCI bridge is present. + */ + if ((prierr == PCMU_PCI_AFSR_E_MA) && !secerr && + (pbm_err.pcbm_pci.pcmu_cfg_stat & PCI_STAT_R_MAST_AB)) { + nonfatal++; + goto done; + } + } + + if (prierr || secerr) { + ret = pcmu_pbm_afsr_report(dip, derr->fme_ena, &pbm_err); + if (ret == DDI_FM_FATAL) { + fatal++; + } else { + nonfatal++; + } + } + + ret = pcmu_cfg_report(dip, derr, &pbm_err.pcbm_pci, caller, prierr); + if (ret == DDI_FM_FATAL) { + fatal++; + } else if (ret == DDI_FM_NONFATAL) { + nonfatal++; + } + +done: + if (ret == DDI_FM_FATAL) { + fatal++; + } else if (ret == DDI_FM_NONFATAL) { + nonfatal++; + } else if (ret == DDI_FM_UNKNOWN) { + unknown++; + } + + /* Cleanup and reset error bits */ + pcmu_clear_error(pcmu_p, &pbm_err); + + return (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL : + (unknown ? DDI_FM_UNKNOWN : DDI_FM_OK))); +} + +int +pcmu_check_error(pcmu_t *pcmu_p) +{ + pcmu_pbm_t *pcbm_p = pcmu_p->pcmu_pcbm_p; + uint16_t pcmu_cfg_stat; + uint64_t pbm_afsr; + + ASSERT(MUTEX_HELD(&pcmu_p->pcmu_err_mutex)); + + pcmu_cfg_stat = pcbm_p->pcbm_config_header->ch_status_reg; + pbm_afsr = *pcbm_p->pcbm_async_flt_status_reg; + + if ((pcmu_cfg_stat & (PCI_STAT_S_PERROR | PCI_STAT_S_TARG_AB | + PCI_STAT_R_TARG_AB | PCI_STAT_R_MAST_AB | + PCI_STAT_S_SYSERR | PCI_STAT_PERROR)) || + (PBM_AFSR_TO_PRIERR(pbm_afsr))) { + return (1); + } + return (0); + +} + +/* + * Function used to gather PBM/PCI error state for the + * pcmu_pbm_err_handler. This function must be called while pcmu_err_mutex + * is held. + */ +static void +pcmu_pbm_errstate_get(pcmu_t *pcmu_p, pcmu_pbm_errstate_t *pbm_err_p) +{ + pcmu_pbm_t *pcbm_p = pcmu_p->pcmu_pcbm_p; + + ASSERT(MUTEX_HELD(&pcmu_p->pcmu_err_mutex)); + bzero(pbm_err_p, sizeof (pcmu_pbm_errstate_t)); + + /* + * Capture all pbm error state for later logging + */ + pbm_err_p->pbm_bridge_type = PCI_OPLCMU; /* RAGS */ + pbm_err_p->pcbm_pci.pcmu_cfg_stat = + pcbm_p->pcbm_config_header->ch_status_reg; + pbm_err_p->pbm_ctl_stat = *pcbm_p->pcbm_ctrl_reg; + pbm_err_p->pcbm_pci.pcmu_cfg_comm = + pcbm_p->pcbm_config_header->ch_command_reg; + pbm_err_p->pbm_afsr = *pcbm_p->pcbm_async_flt_status_reg; + pbm_err_p->pbm_afar = *pcbm_p->pcbm_async_flt_addr_reg; + pbm_err_p->pcbm_pci.pcmu_pa = *pcbm_p->pcbm_async_flt_addr_reg; +} + +static void +pcmu_pbm_clear_error(pcmu_pbm_t *pcbm_p) +{ + uint64_t pbm_afsr; + + /* + * for poke() support - called from POKE_FLUSH. Spin waiting + * for MA, TA or SERR to be cleared by a pcmu_pbm_error_intr(). + * We have to wait for SERR too in case the device is beyond + * a pci-pci bridge. + */ + pbm_afsr = *pcbm_p->pcbm_async_flt_status_reg; + while (((pbm_afsr >> PCMU_PCI_AFSR_PE_SHIFT) & + (PCMU_PCI_AFSR_E_MA | PCMU_PCI_AFSR_E_TA))) { + pbm_afsr = *pcbm_p->pcbm_async_flt_status_reg; + } +} + +void +pcmu_err_create(pcmu_t *pcmu_p) +{ + /* + * PCI detected ECC errorq, to schedule async handling + * of ECC errors and logging. + * The errorq is created here but destroyed when _fini is called + * for the pci module. + */ + if (pcmu_ecc_queue == NULL) { + pcmu_ecc_queue = errorq_create("pcmu_ecc_queue", + (errorq_func_t)pcmu_ecc_err_drain, + (void *)NULL, + ECC_MAX_ERRS, sizeof (pcmu_ecc_errstate_t), + PIL_2, ERRORQ_VITAL); + if (pcmu_ecc_queue == NULL) + panic("failed to create required system error queue"); + } + + /* + * Initialize error handling mutex. + */ + mutex_init(&pcmu_p->pcmu_err_mutex, NULL, MUTEX_DRIVER, + (void *)pcmu_p->pcmu_fm_ibc); +} + +void +pcmu_err_destroy(pcmu_t *pcmu_p) +{ + mutex_destroy(&pcmu_p->pcmu_err_mutex); +} + +/* + * Function used to post PCI block module specific ereports. + */ +void +pcmu_pbm_ereport_post(dev_info_t *dip, uint64_t ena, + pcmu_pbm_errstate_t *pbm_err) +{ + char *aux_msg; + uint32_t prierr, secerr; + pcmu_t *pcmu_p; + int instance = ddi_get_instance(dip); + + ena = ena ? ena : fm_ena_generate(0, FM_ENA_FMT1); + + pcmu_p = get_pcmu_soft_state(instance); + prierr = PBM_AFSR_TO_PRIERR(pbm_err->pbm_afsr); + secerr = PBM_AFSR_TO_SECERR(pbm_err->pbm_afsr); + if (prierr) + aux_msg = "PCI primary error: Master Abort"; + else if (secerr) + aux_msg = "PCI secondary error: Master Abort"; + else + aux_msg = ""; + cmn_err(CE_WARN, "%s %s: %s %s=0x%lx, %s=0x%lx, %s=0x%lx %s=0x%x", + (pcmu_p->pcmu_pcbm_p)->pcbm_nameinst_str, + (pcmu_p->pcmu_pcbm_p)->pcbm_nameaddr_str, + aux_msg, + PCI_PBM_AFAR, pbm_err->pbm_afar, + PCI_PBM_AFSR, pbm_err->pbm_afsr, + PCI_PBM_CSR, pbm_err->pbm_ctl_stat, + "portid", pcmu_p->pcmu_id); +} diff --git a/usr/src/uts/sun4u/opl/io/pcicmu/pcmu_cb.c b/usr/src/uts/sun4u/opl/io/pcicmu/pcmu_cb.c new file mode 100644 index 0000000000..7cb0950247 --- /dev/null +++ b/usr/src/uts/sun4u/opl/io/pcicmu/pcmu_cb.c @@ -0,0 +1,288 @@ +/* + * 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" + +/* + * CMU-CH Control Block object + */ +#include <sys/types.h> +#include <sys/kmem.h> +#include <sys/systm.h> +#include <sys/async.h> +#include <sys/sunddi.h> +#include <sys/ddi_impldefs.h> +#include <sys/pcicmu/pcicmu.h> +#include <sys/machsystm.h> + +/*LINTLIBRARY*/ + +extern uint64_t xc_tick_jump_limit; + +void +pcmu_cb_create(pcmu_t *pcmu_p) +{ + pcmu_cb_t *pcb_p = (pcmu_cb_t *) + kmem_zalloc(sizeof (pcmu_cb_t), KM_SLEEP); + mutex_init(&pcb_p->pcb_intr_lock, NULL, MUTEX_DRIVER, NULL); + pcmu_p->pcmu_cb_p = pcb_p; + pcb_p->pcb_pcmu_p = pcmu_p; + pcmu_cb_setup(pcmu_p); +} + +void +pcmu_cb_destroy(pcmu_t *pcmu_p) +{ + pcmu_cb_t *pcb_p = pcmu_p->pcmu_cb_p; + + intr_dist_rem(pcmu_cb_intr_dist, pcb_p); + pcmu_cb_teardown(pcmu_p); + pcmu_p->pcmu_cb_p = NULL; + mutex_destroy(&pcb_p->pcb_intr_lock); + kmem_free(pcb_p, sizeof (pcmu_cb_t)); +} + +uint64_t +pcmu_cb_ino_to_map_pa(pcmu_cb_t *pcb_p, pcmu_ib_ino_t ino) +{ + return (pcb_p->pcb_map_pa + ((ino & 0x1f) << 3)); +} + +uint64_t +pcmu_cb_ino_to_clr_pa(pcmu_cb_t *pcb_p, pcmu_ib_ino_t ino) +{ + return (pcb_p->pcb_clr_pa + ((ino & 0x1f) << 3)); +} + +static void +pcmu_cb_set_nintr_reg(pcmu_cb_t *pcb_p, pcmu_ib_ino_t ino, uint64_t value) +{ + uint64_t pa = pcmu_cb_ino_to_clr_pa(pcb_p, ino); + + PCMU_DBG3(PCMU_DBG_CB|PCMU_DBG_CONT, NULL, + "pci-%x pcmu_cb_set_nintr_reg: ino=%x PA=%016llx\n", + pcb_p->pcb_pcmu_p->pcmu_id, ino, pa); + + stdphysio(pa, value); + (void) lddphysio(pa); /* flush the previous write */ +} + +/* + * enable an internal interrupt source: + * if an interrupt is shared by both sides, record it in pcb_inos[] and + * cb will own its distribution. + */ +void +pcmu_cb_enable_nintr(pcmu_t *pcmu_p, pcmu_cb_nintr_index_t idx) +{ + pcmu_cb_t *pcb_p = pcmu_p->pcmu_cb_p; + pcmu_ib_ino_t ino = PCMU_IB_MONDO_TO_INO(pcmu_p->pcmu_inos[idx]); + pcmu_ib_mondo_t mondo = PCMU_CB_INO_TO_MONDO(pcb_p, ino); + uint32_t cpu_id; + uint64_t reg, pa; + pcmu_ib_t *pib_p = pcb_p->pcb_pcmu_p->pcmu_ib_p; + volatile uint64_t *imr_p = ib_intr_map_reg_addr(pib_p, ino); + + ASSERT(idx < CBNINTR_MAX); + pa = pcmu_cb_ino_to_map_pa(pcb_p, ino); + + mutex_enter(&pcb_p->pcb_intr_lock); + cpu_id = intr_dist_cpuid(); + + cpu_id = u2u_translate_tgtid(pib_p->pib_pcmu_p, cpu_id, imr_p); + + reg = ib_get_map_reg(mondo, cpu_id); + stdphysio(pa, reg); + + ASSERT(pcb_p->pcb_inos[idx] == 0); + pcb_p->pcb_inos[idx] = ino; + + pcmu_cb_set_nintr_reg(pcb_p, ino, PCMU_CLEAR_INTR_REG_IDLE); + mutex_exit(&pcb_p->pcb_intr_lock); + + PCMU_DBG3(PCMU_DBG_CB|PCMU_DBG_CONT, NULL, + "pci-%x pcmu_cb_enable_nintr: ino=%x cpu_id=%x\n", + pcmu_p->pcmu_id, ino, cpu_id); + PCMU_DBG2(PCMU_DBG_CB|PCMU_DBG_CONT, NULL, + "\tPA=%016llx data=%016llx\n", pa, reg); +} + +static void +pcmu_cb_disable_nintr_reg(pcmu_cb_t *pcb_p, pcmu_ib_ino_t ino, int wait) +{ + uint64_t tmp, map_reg_pa = pcmu_cb_ino_to_map_pa(pcb_p, ino); + ASSERT(MUTEX_HELD(&pcb_p->pcb_intr_lock)); + + /* mark interrupt invalid in mapping register */ + tmp = lddphysio(map_reg_pa) & ~PCMU_INTR_MAP_REG_VALID; + stdphysio(map_reg_pa, tmp); + (void) lddphysio(map_reg_pa); /* flush previous write */ + + if (wait) { + hrtime_t start_time; + hrtime_t prev, curr, interval, jump; + hrtime_t intr_timeout; + uint64_t state_reg_pa = pcb_p->pcb_obsta_pa; + uint_t shift = (ino & 0x1f) << 1; + + /* busy wait if there is interrupt being processed */ + /* unless panic or timeout for interrupt pending is reached */ + + intr_timeout = pcmu_intrpend_timeout; + jump = TICK_TO_NSEC(xc_tick_jump_limit); + start_time = curr = gethrtime(); + while ((((lddphysio(state_reg_pa) >> shift) & + PCMU_CLEAR_INTR_REG_MASK) == + PCMU_CLEAR_INTR_REG_PENDING) && !panicstr) { + /* + * If we have a really large jump in hrtime, it is most + * probably because we entered the debugger (or OBP, + * in general). So, we adjust the timeout accordingly + * to prevent declaring an interrupt timeout. The + * master-interrupt mechanism in OBP should deliver + * the interrupts properly. + */ + prev = curr; + curr = gethrtime(); + interval = curr - prev; + if (interval > jump) + intr_timeout += interval; + if (curr - start_time > intr_timeout) { + cmn_err(CE_WARN, "pcmu@%x " + "pcmu_cb_disable_nintr_reg(%lx,%x) timeout", + pcb_p->pcb_pcmu_p->pcmu_id, map_reg_pa, + PCMU_CB_INO_TO_MONDO(pcb_p, ino)); + break; + } + } + } +} + +void +pcmu_cb_disable_nintr(pcmu_cb_t *pcb_p, pcmu_cb_nintr_index_t idx, int wait) +{ + pcmu_ib_t *pib_p = pcb_p->pcb_pcmu_p->pcmu_ib_p; + volatile uint64_t *imr_p; + pcmu_ib_ino_t ino = pcb_p->pcb_inos[idx]; + ASSERT(idx < CBNINTR_MAX); + ASSERT(ino); + + imr_p = ib_intr_map_reg_addr(pib_p, ino); + mutex_enter(&pcb_p->pcb_intr_lock); + pcmu_cb_disable_nintr_reg(pcb_p, ino, wait); + pcmu_cb_set_nintr_reg(pcb_p, ino, PCMU_CLEAR_INTR_REG_PENDING); + pcb_p->pcb_inos[idx] = 0; + mutex_exit(&pcb_p->pcb_intr_lock); + u2u_ittrans_cleanup((u2u_ittrans_data_t *)(pcb_p->pcb_ittrans_cookie), + imr_p); +} + +void +pcmu_cb_clear_nintr(pcmu_cb_t *pcb_p, pcmu_cb_nintr_index_t idx) +{ + pcmu_ib_ino_t ino = pcb_p->pcb_inos[idx]; + ASSERT(idx < CBNINTR_MAX); + ASSERT(ino); + pcmu_cb_set_nintr_reg(pcb_p, ino, PCMU_CLEAR_INTR_REG_IDLE); +} + +void +pcmu_cb_intr_dist(void *arg) +{ + int i; + pcmu_cb_t *pcb_p = (pcmu_cb_t *)arg; + + mutex_enter(&pcb_p->pcb_intr_lock); + for (i = 0; i < pcb_p->pcb_no_of_inos; i++) { + uint64_t mr_pa; + volatile uint64_t imr; + pcmu_ib_mondo_t mondo; + uint32_t cpu_id; + pcmu_ib_t *pib_p = pcb_p->pcb_pcmu_p->pcmu_ib_p; + volatile uint64_t *imr_p; + + pcmu_ib_ino_t ino = pcb_p->pcb_inos[i]; + if (!ino) /* skip non-shared interrupts */ + continue; + + mr_pa = pcmu_cb_ino_to_map_pa(pcb_p, ino); + imr = lddphysio(mr_pa); + if (!PCMU_IB_INO_INTR_ISON(imr)) + continue; + + mondo = PCMU_CB_INO_TO_MONDO(pcb_p, ino); + cpu_id = intr_dist_cpuid(); + imr_p = ib_intr_map_reg_addr(pib_p, ino); + + cpu_id = u2u_translate_tgtid(pib_p->pib_pcmu_p, cpu_id, imr_p); + + pcmu_cb_disable_nintr_reg(pcb_p, ino, PCMU_IB_INTR_WAIT); + stdphysio(mr_pa, ib_get_map_reg(mondo, cpu_id)); + (void) lddphysio(mr_pa); /* flush previous write */ + } + mutex_exit(&pcb_p->pcb_intr_lock); +} + +void +pcmu_cb_suspend(pcmu_cb_t *pcb_p) +{ + int i, inos = pcb_p->pcb_no_of_inos; + ASSERT(!pcb_p->pcb_imr_save); + pcb_p->pcb_imr_save = kmem_alloc(inos * sizeof (uint64_t), KM_SLEEP); + + /* + * save the internal interrupts' mapping registers content + * + * The PBM IMR really doesn't need to be saved, as it is + * different per side and is handled by pcmu_pbm_suspend/resume. + * But it complicates the logic. + */ + for (i = 0; i < inos; i++) { + uint64_t pa; + pcmu_ib_ino_t ino = pcb_p->pcb_inos[i]; + if (!ino) + continue; + pa = pcmu_cb_ino_to_map_pa(pcb_p, ino); + pcb_p->pcb_imr_save[i] = lddphysio(pa); + } +} + +void +pcmu_cb_resume(pcmu_cb_t *pcb_p) +{ + int i; + for (i = 0; i < pcb_p->pcb_no_of_inos; i++) { + uint64_t pa; + pcmu_ib_ino_t ino = pcb_p->pcb_inos[i]; + if (!ino) + continue; + pa = pcmu_cb_ino_to_map_pa(pcb_p, ino); + pcmu_cb_set_nintr_reg(pcb_p, ino, PCMU_CLEAR_INTR_REG_IDLE); + stdphysio(pa, pcb_p->pcb_imr_save[i]); /* restore IMR */ + } + kmem_free(pcb_p->pcb_imr_save, + pcb_p->pcb_no_of_inos * sizeof (uint64_t)); + pcb_p->pcb_imr_save = NULL; +} diff --git a/usr/src/uts/sun4u/opl/io/pcicmu/pcmu_counters.c b/usr/src/uts/sun4u/opl/io/pcicmu/pcmu_counters.c new file mode 100644 index 0000000000..aee1a922f8 --- /dev/null +++ b/usr/src/uts/sun4u/opl/io/pcicmu/pcmu_counters.c @@ -0,0 +1,253 @@ +/* + * 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 <sys/types.h> +#include <sys/async.h> +#include <sys/sunddi.h> +#include <sys/sunndi.h> +#include <sys/ddi_impldefs.h> +#include <sys/pcicmu/pcicmu.h> +#include <sys/machsystm.h> +#include <sys/kstat.h> + +/*LINTLIBRARY*/ + +static kstat_t *pcmu_create_picN_kstat(char *, int, int, int, + pcmu_kev_mask_t *); + +void +pcmu_kstat_create(pcmu_t *pcmu_p) +{ + pcmu_add_upstream_kstat(pcmu_p); +} + +void +pcmu_kstat_destroy(pcmu_t *pcmu_p) +{ + pcmu_rem_upstream_kstat(pcmu_p); +} + +void +pcmu_create_name_kstat(char *name, pcmu_ksinfo_t *pp, pcmu_kev_mask_t *ev) +{ + int i; + + for (i = 0; i < NUM_OF_PICS; i++) { + pp->pic_name_ksp[i] = pcmu_create_picN_kstat(name, + i, pp->pic_shift[i], pp->pic_no_evs, ev); + + if (pp->pic_name_ksp[i] == NULL) { + cmn_err(CE_WARN, "pci: unable to create name kstat"); + } + } +} + +void +pcmu_delete_name_kstat(pcmu_ksinfo_t *pp) +{ + int i; + + if (pp == NULL) { + return; + } + for (i = 0; i < NUM_OF_PICS; i++) { + if (pp->pic_name_ksp[i] != NULL) + kstat_delete(pp->pic_name_ksp[i]); + } +} + +/* + * Create the picN kstat. Returns a pointer to the + * kstat which the driver must store to allow it + * to be deleted when necessary. + */ +static kstat_t * +pcmu_create_picN_kstat(char *mod_name, int pic, int pic_shift, + int num_ev, pcmu_kev_mask_t *ev_array) +{ + struct kstat_named *pic_named_data; + int inst = 0; + int event; + char pic_name[30]; + kstat_t *picN_ksp = NULL; + + (void) sprintf(pic_name, "pic%d", pic); + if ((picN_ksp = kstat_create(mod_name, inst, pic_name, + "bus", KSTAT_TYPE_NAMED, num_ev, NULL)) == NULL) { + cmn_err(CE_WARN, "%s %s : kstat create failed", + mod_name, pic_name); + + /* + * It is up to the calling function to delete any kstats + * that may have been created already. We just + * return NULL to indicate an error has occured. + */ + return (NULL); + } + + pic_named_data = (struct kstat_named *)picN_ksp->ks_data; + + /* + * Write event names and their associated pcr masks. The + * last entry in the array (clear_pic) is added seperately + * below as the pic value must be inverted. + */ + for (event = 0; event < num_ev - 1; event++) { + pic_named_data[event].value.ui64 = + (ev_array[event].pcr_mask << pic_shift); + + kstat_named_init(&pic_named_data[event], + ev_array[event].event_name, KSTAT_DATA_UINT64); + } + + /* + * add the clear_pic entry. + */ + pic_named_data[event].value.ui64 = + (uint64_t)~(ev_array[event].pcr_mask << pic_shift); + + kstat_named_init(&pic_named_data[event], + ev_array[event].event_name, KSTAT_DATA_UINT64); + + kstat_install(picN_ksp); + return (picN_ksp); +} + +/* + * Create the "counters" kstat. + */ +kstat_t *pcmu_create_cntr_kstat(pcmu_t *pcmu_p, char *name, + int num_pics, int (*update)(kstat_t *, int), + void *cntr_addr_p) +{ + struct kstat_named *counters_named_data; + struct kstat *counters_ksp; + dev_info_t *dip = pcmu_p->pcmu_dip; + char *drv_name = (char *)ddi_driver_name(dip); + int drv_instance = ddi_get_instance(dip); + char pic_str[10]; + int i; + + /* + * Size of kstat is num_pics + 1 as it + * also contains the %pcr + */ + if ((counters_ksp = kstat_create(name, drv_instance, + "counters", "bus", KSTAT_TYPE_NAMED, num_pics + 1, + KSTAT_FLAG_WRITABLE)) == NULL) { + cmn_err(CE_WARN, "%s%d counters kstat_create failed", + drv_name, drv_instance); + return (NULL); + } + + counters_named_data = (struct kstat_named *)(counters_ksp->ks_data); + + /* initialize the named kstats */ + kstat_named_init(&counters_named_data[0], "pcr", KSTAT_DATA_UINT64); + + for (i = 0; i < num_pics; i++) { + (void) sprintf(pic_str, "pic%d", i); + kstat_named_init(&counters_named_data[i+1], + pic_str, KSTAT_DATA_UINT64); + } + + /* + * Store the register offset's in the kstat's + * private field so that they are available + * to the update function. + */ + counters_ksp->ks_private = (void *)cntr_addr_p; + counters_ksp->ks_update = update; + kstat_install(counters_ksp); + return (counters_ksp); +} + +/* + * kstat update function. Handles reads/writes + * from/to kstat. + */ +int +pcmu_cntr_kstat_update(kstat_t *ksp, int rw) +{ + struct kstat_named *data_p; + pcmu_cntr_addr_t *cntr_addr_p = ksp->ks_private; + uint64_t pic; + + data_p = (struct kstat_named *)ksp->ks_data; + if (rw == KSTAT_WRITE) { + *cntr_addr_p->pcr_addr = data_p[0].value.ui64; + return (0); + } else { + pic = *cntr_addr_p->pic_addr; + data_p[0].value.ui64 = *cntr_addr_p->pcr_addr; + + /* pic0 : lo 32 bits */ + data_p[1].value.ui64 = (pic <<32) >> 32; + /* pic1 : hi 32 bits */ + data_p[2].value.ui64 = pic >> 32; + } + return (0); +} + +/* + * kstat update function using physical addresses. + */ +int +pcmu_cntr_kstat_pa_update(kstat_t *ksp, int rw) +{ + struct kstat_named *data_p; + pcmu_cntr_pa_t *cntr_pa_p = (pcmu_cntr_pa_t *)ksp->ks_private; + uint64_t pic; + + data_p = (struct kstat_named *)ksp->ks_data; + + if (rw == KSTAT_WRITE) { + stdphysio(cntr_pa_p->pcr_pa, data_p[0].value.ui64); + return (0); + } else { + pic = lddphysio(cntr_pa_p->pic_pa); + data_p[0].value.ui64 = lddphysio(cntr_pa_p->pcr_pa); + + /* pic0 : lo 32 bits */ + data_p[1].value.ui64 = (pic << 32) >> 32; + /* pic1 : hi 32 bits */ + data_p[2].value.ui64 = pic >> 32; + } + return (0); +} + + +/* + * Matched with pcmu_add_upstream_kstat() + */ +void +pcmu_rem_upstream_kstat(pcmu_t *pcmu_p) +{ + if (pcmu_p->pcmu_uksp != NULL) + kstat_delete(pcmu_p->pcmu_uksp); + pcmu_p->pcmu_uksp = NULL; +} diff --git a/usr/src/uts/sun4u/opl/io/pcicmu/pcmu_ecc.c b/usr/src/uts/sun4u/opl/io/pcicmu/pcmu_ecc.c new file mode 100644 index 0000000000..b54cf7bd78 --- /dev/null +++ b/usr/src/uts/sun4u/opl/io/pcicmu/pcmu_ecc.c @@ -0,0 +1,469 @@ +/* + * 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" + +/* + * CMU-CH ECC support + */ + +#include <sys/types.h> +#include <sys/systm.h> +#include <sys/kmem.h> +#include <sys/sunddi.h> +#include <sys/intr.h> +#include <sys/async.h> +#include <sys/ddi_impldefs.h> +#include <sys/machsystm.h> +#include <sys/sysmacros.h> +#include <sys/fm/protocol.h> +#include <sys/fm/util.h> +#include <sys/fm/io/pci.h> +#include <sys/fm/io/sun4upci.h> +#include <sys/fm/io/ddi.h> +#include <sys/pcicmu/pcicmu.h> + +/*LINTLIBRARY*/ + +static void pcmu_ecc_disable(pcmu_ecc_t *, int); +static uint64_t pcmu_ecc_read_afsr(pcmu_ecc_intr_info_t *); +static void pcmu_ecc_ereport_post(dev_info_t *dip, + pcmu_ecc_errstate_t *ecc_err); + +clock_t pcmu_pecc_panic_delay = 200; + +void +pcmu_ecc_create(pcmu_t *pcmu_p) +{ + uint64_t pcb_base_pa = pcmu_p->pcmu_cb_p->pcb_base_pa; + pcmu_ecc_t *pecc_p; + /* LINTED variable */ + dev_info_t *dip = pcmu_p->pcmu_dip; + + pecc_p = (pcmu_ecc_t *)kmem_zalloc(sizeof (pcmu_ecc_t), KM_SLEEP); + pecc_p->pecc_pcmu_p = pcmu_p; + pcmu_p->pcmu_pecc_p = pecc_p; + + pecc_p->pecc_ue.pecc_p = pecc_p; + pecc_p->pecc_ue.pecc_type = CBNINTR_UE; + + pcmu_ecc_setup(pecc_p); + + /* + * Determine the virtual addresses of the streaming cache + * control/status and flush registers. + */ + pecc_p->pecc_csr_pa = pcb_base_pa + PCMU_ECC_CSR_OFFSET; + pecc_p->pecc_ue.pecc_afsr_pa = pcb_base_pa + PCMU_UE_AFSR_OFFSET; + pecc_p->pecc_ue.pecc_afar_pa = pcb_base_pa + PCMU_UE_AFAR_OFFSET; + + PCMU_DBG1(PCMU_DBG_ATTACH, dip, "pcmu_ecc_create: csr=%x\n", + pecc_p->pecc_csr_pa); + PCMU_DBG2(PCMU_DBG_ATTACH, dip, + "pcmu_ecc_create: ue_afsr=%x, ue_afar=%x\n", + pecc_p->pecc_ue.pecc_afsr_pa, pecc_p->pecc_ue.pecc_afar_pa); + + pcmu_ecc_configure(pcmu_p); + + /* + * Register routines to be called from system error handling code. + */ + bus_func_register(BF_TYPE_ERRDIS, + (busfunc_t)pcmu_ecc_disable_nowait, pecc_p); +} + +int +pcmu_ecc_register_intr(pcmu_t *pcmu_p) +{ + pcmu_ecc_t *pecc_p = pcmu_p->pcmu_pecc_p; + int ret; + + /* + * Install the UE error interrupt handlers. + */ + ret = pcmu_ecc_add_intr(pcmu_p, CBNINTR_UE, &pecc_p->pecc_ue); + return (ret); +} + +void +pcmu_ecc_destroy(pcmu_t *pcmu_p) +{ + pcmu_ecc_t *pecc_p = pcmu_p->pcmu_pecc_p; + + PCMU_DBG0(PCMU_DBG_DETACH, pcmu_p->pcmu_dip, "pcmu_ecc_destroy:\n"); + + /* + * Disable UE ECC error interrupts. + */ + pcmu_ecc_disable_wait(pecc_p); + + /* + * Remove the ECC interrupt handlers. + */ + pcmu_ecc_rem_intr(pcmu_p, CBNINTR_UE, &pecc_p->pecc_ue); + + /* + * Unregister our error handling functions. + */ + bus_func_unregister(BF_TYPE_ERRDIS, + (busfunc_t)pcmu_ecc_disable_nowait, pecc_p); + /* + * If a timer has been set, unset it. + */ + (void) untimeout(pecc_p->pecc_tout_id); + kmem_free(pecc_p, sizeof (pcmu_ecc_t)); + pcmu_p->pcmu_pecc_p = NULL; +} + +void +pcmu_ecc_configure(pcmu_t *pcmu_p) +{ + pcmu_ecc_t *pecc_p = pcmu_p->pcmu_pecc_p; + uint64_t l; + /* LINTED variable */ + dev_info_t *dip = pcmu_p->pcmu_dip; + + /* + * Clear any pending ECC errors. + */ + PCMU_DBG0(PCMU_DBG_ATTACH, dip, + "pcmu_ecc_configure: clearing UE errors\n"); + l = (PCMU_ECC_UE_AFSR_E_MASK << PCMU_ECC_UE_AFSR_PE_SHIFT) | + (PCMU_ECC_UE_AFSR_E_MASK << PCMU_ECC_UE_AFSR_SE_SHIFT); + stdphysio(pecc_p->pecc_ue.pecc_afsr_pa, l); + + /* + * Enable ECC error detections via the control register. + */ + PCMU_DBG0(PCMU_DBG_ATTACH, dip, + "pcmu_ecc_configure: enabling UE detection\n"); + l = PCMU_ECC_CTRL_ECC_EN; + if (ecc_error_intr_enable) + l |= PCMU_ECC_CTRL_UE_INTEN; + stdphysio(pecc_p->pecc_csr_pa, l); +} + +void +pcmu_ecc_enable_intr(pcmu_t *pcmu_p) +{ + pcmu_cb_enable_nintr(pcmu_p, CBNINTR_UE); +} + +void +pcmu_ecc_disable_wait(pcmu_ecc_t *pecc_p) +{ + pcmu_ecc_disable(pecc_p, PCMU_IB_INTR_WAIT); +} + +uint_t +pcmu_ecc_disable_nowait(pcmu_ecc_t *pecc_p) +{ + pcmu_ecc_disable(pecc_p, PCMU_IB_INTR_NOWAIT); + return (BF_NONE); +} + +static void +pcmu_ecc_disable(pcmu_ecc_t *pecc_p, int wait) +{ + pcmu_cb_t *pcb_p = pecc_p->pecc_pcmu_p->pcmu_cb_p; + uint64_t csr_pa = pecc_p->pecc_csr_pa; + uint64_t csr = lddphysio(csr_pa); + + csr &= ~(PCMU_ECC_CTRL_UE_INTEN); + stdphysio(csr_pa, csr); + pcmu_cb_disable_nintr(pcb_p, CBNINTR_UE, wait); +} + +/* + * I/O ECC error handling: + * + * Below are the generic functions that handle detected ECC errors. + * + * The registered interrupt handler is pcmu_ecc_intr(), it's function + * is to receive the error, capture some state, and pass that on to + * the pcmu_ecc_err_handler() for reporting purposes. + * + * pcmu_ecc_err_handler() gathers more state(via pcmu_ecc_errstate_get) + * and attempts to handle and report the error. pcmu_ecc_err_handler() + * must determine if we need to panic due to this error (via + * pcmu_ecc_classify, which also decodes the * ECC afsr), and if any + * side effects exist that may have caused or are due * to this error. + * PBM errors related to the ECC error may exist, to report + * them we call pcmu_pbm_err_handler(). + * + * To report the error we must also get the syndrome and unum, which can not + * be done in high level interrupted context. Therefore we have an error + * queue(pcmu_ecc_queue) which we dispatch errors to, to report the errors + * (pcmu_ecc_err_drain()). + * + * pcmu_ecc_err_drain() will be called when either the softint is triggered + * or the system is panicing. Either way it will gather more information + * about the error from the CPU(via ecc_cpu_call(), ecc.c), attempt to + * retire the faulty page(if error is a UE), and report the detected error. + * + */ + +/* + * Function used to get ECC AFSR register + */ +static uint64_t +pcmu_ecc_read_afsr(pcmu_ecc_intr_info_t *ecc_ii_p) +{ + ASSERT(ecc_ii_p->pecc_type == CBNINTR_UE); + return (lddphysio(ecc_ii_p->pecc_afsr_pa)); +} + +/* + * IO detected ECC error interrupt handler, calls pcmu_ecc_err_handler to post + * error reports and handle the interrupt. Re-entry into pcmu_ecc_err_handler + * is protected by the per-chip mutex pcmu_err_mutex. + */ +uint_t +pcmu_ecc_intr(caddr_t a) +{ + pcmu_ecc_intr_info_t *ecc_ii_p = (pcmu_ecc_intr_info_t *)a; + pcmu_ecc_t *pecc_p = ecc_ii_p->pecc_p; + pcmu_t *pcmu_p = pecc_p->pecc_pcmu_p; + pcmu_ecc_errstate_t ecc_err; + int ret = DDI_FM_OK; + + bzero(&ecc_err, sizeof (pcmu_ecc_errstate_t)); + ecc_err.ecc_ena = fm_ena_generate(0, FM_ENA_FMT1); /* RAGS */ + ecc_err.ecc_ii_p = *ecc_ii_p; + ecc_err.pecc_p = pecc_p; + ecc_err.ecc_caller = PCI_ECC_CALL; + + mutex_enter(&pcmu_p->pcmu_err_mutex); + ret = pcmu_ecc_err_handler(&ecc_err); + mutex_exit(&pcmu_p->pcmu_err_mutex); + if (ret == DDI_FM_FATAL) { + /* + * Need delay here to allow CPUs to handle related traps, + * such as FRUs for USIIIi systems. + */ + DELAY(pcmu_pecc_panic_delay); + cmn_err(CE_PANIC, "Fatal PCI UE Error"); + } + + return (DDI_INTR_CLAIMED); +} + +/* + * Function used to gather IO ECC error state. + */ +static void +pcmu_ecc_errstate_get(pcmu_ecc_errstate_t *ecc_err_p) +{ + pcmu_ecc_t *pecc_p; + uint_t bus_id; + + ASSERT(ecc_err_p); + + pecc_p = ecc_err_p->ecc_ii_p.pecc_p; + bus_id = pecc_p->pecc_pcmu_p->pcmu_id; + + ASSERT(MUTEX_HELD(&pecc_p->pecc_pcmu_p->pcmu_err_mutex)); + /* + * Read the fault registers. + */ + ecc_err_p->ecc_afsr = pcmu_ecc_read_afsr(&ecc_err_p->ecc_ii_p); + ecc_err_p->ecc_afar = lddphysio(ecc_err_p->ecc_ii_p.pecc_afar_pa); + + ecc_err_p->ecc_offset = ((ecc_err_p->ecc_afsr & + ecc_err_p->ecc_ii_p.pecc_offset_mask) >> + ecc_err_p->ecc_ii_p.pecc_offset_shift) << + ecc_err_p->ecc_ii_p.pecc_size_log2; + + ecc_err_p->ecc_aflt.flt_id = gethrtime(); + ecc_err_p->ecc_aflt.flt_stat = ecc_err_p->ecc_afsr; + ecc_err_p->ecc_aflt.flt_addr = P2ALIGN(ecc_err_p->ecc_afar, 64) + + ecc_err_p->ecc_offset; + ecc_err_p->ecc_aflt.flt_bus_id = bus_id; + ecc_err_p->ecc_aflt.flt_inst = 0; + ecc_err_p->ecc_aflt.flt_status = ECC_IOBUS; + ecc_err_p->ecc_aflt.flt_in_memory = 0; + ecc_err_p->ecc_aflt.flt_class = BUS_FAULT; +} + +/* + * pcmu_ecc_check: Called by pcmu_ecc_err_handler() this function is responsible + * for calling pcmu_pbm_err_handler() and calling their children error + * handlers(via ndi_fm_handler_dispatch()). + */ +static int +pcmu_ecc_check(pcmu_ecc_t *pecc_p, uint64_t fme_ena) +{ + ddi_fm_error_t derr; + int ret; + pcmu_t *pcmu_p; + + + ASSERT(MUTEX_HELD(&pecc_p->pecc_pcmu_p->pcmu_err_mutex)); + + bzero(&derr, sizeof (ddi_fm_error_t)); + derr.fme_version = DDI_FME_VERSION; + derr.fme_ena = fme_ena; + ret = DDI_FM_NONFATAL; + + /* + * Need to report any PBM errors which may have caused or + * resulted from this error. + */ + pcmu_p = pecc_p->pecc_pcmu_p; + if (pcmu_pbm_err_handler(pcmu_p->pcmu_dip, &derr, (void *)pcmu_p, + PCI_ECC_CALL) == DDI_FM_FATAL) + ret = DDI_FM_FATAL; + + if (ret == DDI_FM_FATAL) + return (DDI_FM_FATAL); + else + return (DDI_FM_NONFATAL); +} + +/* + * Function used to handle and log IO detected ECC errors, can be called by + * pcmu_ecc_intr and pcmu_err_callback(trap callback). Protected by + * pcmu_err_mutex. + */ +int +pcmu_ecc_err_handler(pcmu_ecc_errstate_t *ecc_err_p) +{ + /* LINTED variable */ + uint64_t pri_err, sec_err; + pcmu_ecc_intr_info_t *ecc_ii_p = &ecc_err_p->ecc_ii_p; + pcmu_ecc_t *pecc_p = ecc_ii_p->pecc_p; + /* LINTED variable */ + pcmu_t *pcmu_p; + pcmu_cb_t *pcb_p; + int fatal = 0; + int nonfatal = 0; + + ASSERT(MUTEX_HELD(&pecc_p->pecc_pcmu_p->pcmu_err_mutex)); + + pcmu_p = pecc_p->pecc_pcmu_p; + pcb_p = pecc_p->pecc_pcmu_p->pcmu_cb_p; + + pcmu_ecc_errstate_get(ecc_err_p); + pri_err = (ecc_err_p->ecc_afsr >> PCMU_ECC_UE_AFSR_PE_SHIFT) & + PCMU_ECC_UE_AFSR_E_MASK; + + sec_err = (ecc_err_p->ecc_afsr >> PCMU_ECC_UE_AFSR_SE_SHIFT) & + PCMU_ECC_UE_AFSR_E_MASK; + + switch (ecc_ii_p->pecc_type) { + case CBNINTR_UE: + if (pri_err) { + ecc_err_p->ecc_aflt.flt_synd = 0; + ecc_err_p->pecc_pri = 1; + pcmu_ecc_classify(pri_err, ecc_err_p); + errorq_dispatch(pcmu_ecc_queue, (void *)ecc_err_p, + sizeof (pcmu_ecc_errstate_t), + ecc_err_p->ecc_aflt.flt_panic); + } + if (sec_err) { + pcmu_ecc_errstate_t ecc_sec_err; + + ecc_sec_err = *ecc_err_p; + ecc_sec_err.pecc_pri = 0; + pcmu_ecc_classify(sec_err, &ecc_sec_err); + pcmu_ecc_ereport_post(pcmu_p->pcmu_dip, + &ecc_sec_err); + } + /* + * Check for PCI bus errors that may have resulted from or + * caused this UE. + */ + if (ecc_err_p->ecc_caller == PCI_ECC_CALL && + pcmu_ecc_check(pecc_p, ecc_err_p->ecc_ena) == DDI_FM_FATAL) + ecc_err_p->ecc_aflt.flt_panic = 1; + + if (ecc_err_p->ecc_aflt.flt_panic) { + /* + * Disable all further errors since this will be + * treated as a fatal error. + */ + (void) pcmu_ecc_disable_nowait(pecc_p); + fatal++; + } + break; + + default: + return (DDI_FM_OK); + } + /* Clear the errors */ + stdphysio(ecc_ii_p->pecc_afsr_pa, ecc_err_p->ecc_afsr); + /* + * Clear the interrupt if called by pcmu_ecc_intr and UE error + * or if called by pcmu_ecc_intr and CE error and delayed CE + * interrupt handling is turned off. + */ + if (ecc_err_p->ecc_caller == PCI_ECC_CALL && + ecc_ii_p->pecc_type == CBNINTR_UE && !fatal) + pcmu_cb_clear_nintr(pcb_p, ecc_ii_p->pecc_type); + if (!fatal && !nonfatal) + return (DDI_FM_OK); + else if (fatal) + return (DDI_FM_FATAL); + return (DDI_FM_NONFATAL); +} + +/* + * Function used to drain pcmu_ecc_queue, either during panic or after softint + * is generated, to log IO detected ECC errors. + */ +void +pcmu_ecc_err_drain(void *not_used, pcmu_ecc_errstate_t *ecc_err) +{ + struct async_flt *ecc = &ecc_err->ecc_aflt; + pcmu_t *pcmu_p = ecc_err->pecc_p->pecc_pcmu_p; + + ecc_cpu_call(ecc, ecc_err->ecc_unum, ECC_IO_UE); + ecc_err->ecc_err_type = "U"; + pcmu_ecc_ereport_post(pcmu_p->pcmu_dip, ecc_err); +} + +/* + * Function used to post IO detected ECC ereports. + */ +static void +pcmu_ecc_ereport_post(dev_info_t *dip, pcmu_ecc_errstate_t *ecc_err) +{ + char *aux_msg; + pcmu_t *pcmu_p; + int instance = ddi_get_instance(dip); + + pcmu_p = get_pcmu_soft_state(instance); + if (ecc_err->pecc_pri) { + aux_msg = "PIO primary uncorrectable error"; + } else { + aux_msg = "PIO secondary uncorrectable error"; + } + cmn_err(CE_WARN, "%s %s: %s %s=0x%lx, %s=0x%lx, %s=0x%x", + (pcmu_p->pcmu_pcbm_p)->pcbm_nameinst_str, + (pcmu_p->pcmu_pcbm_p)->pcbm_nameaddr_str, + aux_msg, PCI_ECC_AFSR, ecc_err->ecc_afsr, + PCI_ECC_AFAR, ecc_err->ecc_aflt.flt_addr, + "portid", ecc_err->ecc_aflt.flt_bus_id); +} diff --git a/usr/src/uts/sun4u/opl/io/pcicmu/pcmu_ib.c b/usr/src/uts/sun4u/opl/io/pcicmu/pcmu_ib.c new file mode 100644 index 0000000000..1befbb3ade --- /dev/null +++ b/usr/src/uts/sun4u/opl/io/pcicmu/pcmu_ib.c @@ -0,0 +1,747 @@ +/* + * 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" + +/* + * CMU-CH Interrupt Block + */ + +#include <sys/types.h> +#include <sys/kmem.h> +#include <sys/async.h> +#include <sys/systm.h> +#include <sys/spl.h> +#include <sys/sunddi.h> +#include <sys/machsystm.h> +#include <sys/ddi_impldefs.h> +#include <sys/pcicmu/pcicmu.h> + +/*LINTLIBRARY*/ +static uint_t pcmu_ib_intr_reset(void *arg); + +extern uint64_t xc_tick_jump_limit; + +void +pcmu_ib_create(pcmu_t *pcmu_p) +{ + pcmu_ib_t *pib_p; + uintptr_t a; + int i; + + /* + * Allocate interrupt block state structure and link it to + * the pci state structure. + */ + pib_p = kmem_zalloc(sizeof (pcmu_ib_t), KM_SLEEP); + pcmu_p->pcmu_ib_p = pib_p; + pib_p->pib_pcmu_p = pcmu_p; + + a = pcmu_ib_setup(pib_p); + + /* + * Determine virtual addresses of interrupt mapping, clear and diag + * registers that have common offsets. + */ + pib_p->pib_intr_retry_timer_reg = + (uint64_t *)(a + PCMU_IB_INTR_RETRY_TIMER_OFFSET); + pib_p->pib_obio_intr_state_diag_reg = + (uint64_t *)(a + PCMU_IB_OBIO_INTR_STATE_DIAG_REG); + + PCMU_DBG2(PCMU_DBG_ATTACH, pcmu_p->pcmu_dip, + "pcmu_ib_create: obio_imr=%x, obio_cir=%x\n", + pib_p->pib_obio_intr_map_regs, pib_p->pib_obio_clear_intr_regs); + PCMU_DBG2(PCMU_DBG_ATTACH, pcmu_p->pcmu_dip, + "pcmu_ib_create: retry_timer=%x, obio_diag=%x\n", + pib_p->pib_intr_retry_timer_reg, + pib_p->pib_obio_intr_state_diag_reg); + + pib_p->pib_ino_lst = (pcmu_ib_ino_info_t *)NULL; + mutex_init(&pib_p->pib_intr_lock, NULL, MUTEX_DRIVER, NULL); + mutex_init(&pib_p->pib_ino_lst_mutex, NULL, MUTEX_DRIVER, NULL); + + PCMU_DBG1(PCMU_DBG_ATTACH, pcmu_p->pcmu_dip, + "pcmu_ib_create: numproxy=%x\n", pcmu_p->pcmu_numproxy); + for (i = 1; i <= pcmu_p->pcmu_numproxy; i++) { + set_intr_mapping_reg(pcmu_p->pcmu_id, + (uint64_t *)pib_p->pib_upa_imr[i - 1], i); + } + + pcmu_ib_configure(pib_p); + bus_func_register(BF_TYPE_RESINTR, pcmu_ib_intr_reset, pib_p); +} + +void +pcmu_ib_destroy(pcmu_t *pcmu_p) +{ + pcmu_ib_t *pib_p = pcmu_p->pcmu_ib_p; + + PCMU_DBG0(PCMU_DBG_IB, pcmu_p->pcmu_dip, "pcmu_ib_destroy\n"); + bus_func_unregister(BF_TYPE_RESINTR, pcmu_ib_intr_reset, pib_p); + + intr_dist_rem_weighted(pcmu_ib_intr_dist_all, pib_p); + mutex_destroy(&pib_p->pib_ino_lst_mutex); + mutex_destroy(&pib_p->pib_intr_lock); + + pcmu_ib_free_ino_all(pib_p); + + kmem_free(pib_p, sizeof (pcmu_ib_t)); + pcmu_p->pcmu_ib_p = NULL; +} + +void +pcmu_ib_configure(pcmu_ib_t *pib_p) +{ + *pib_p->pib_intr_retry_timer_reg = pcmu_intr_retry_intv; +} + +/* + * can only used for CMU-CH internal interrupts ue, pbm + */ +void +pcmu_ib_intr_enable(pcmu_t *pcmu_p, pcmu_ib_ino_t ino) +{ + pcmu_ib_t *pib_p = pcmu_p->pcmu_ib_p; + pcmu_ib_mondo_t mondo = PCMU_IB_INO_TO_MONDO(pib_p, ino); + volatile uint64_t *imr_p = ib_intr_map_reg_addr(pib_p, ino); + uint_t cpu_id; + + /* + * Determine the cpu for the interrupt. + */ + mutex_enter(&pib_p->pib_intr_lock); + cpu_id = intr_dist_cpuid(); + cpu_id = u2u_translate_tgtid(pcmu_p, cpu_id, imr_p); + PCMU_DBG2(PCMU_DBG_IB, pcmu_p->pcmu_dip, + "pcmu_ib_intr_enable: ino=%x cpu_id=%x\n", ino, cpu_id); + + *imr_p = ib_get_map_reg(mondo, cpu_id); + PCMU_IB_INO_INTR_CLEAR(ib_clear_intr_reg_addr(pib_p, ino)); + mutex_exit(&pib_p->pib_intr_lock); +} + +/* + * Disable the interrupt via its interrupt mapping register. + * Can only be used for internal interrupts: ue, pbm. + * If called under interrupt context, wait should be set to 0 + */ +void +pcmu_ib_intr_disable(pcmu_ib_t *pib_p, pcmu_ib_ino_t ino, int wait) +{ + volatile uint64_t *imr_p = ib_intr_map_reg_addr(pib_p, ino); + volatile uint64_t *state_reg_p = PCMU_IB_INO_INTR_STATE_REG(pib_p, ino); + hrtime_t start_time; + hrtime_t prev, curr, interval, jump; + hrtime_t intr_timeout; + + /* disable the interrupt */ + mutex_enter(&pib_p->pib_intr_lock); + PCMU_IB_INO_INTR_OFF(imr_p); + *imr_p; /* flush previous write */ + mutex_exit(&pib_p->pib_intr_lock); + + if (!wait) + goto wait_done; + + intr_timeout = pcmu_intrpend_timeout; + jump = TICK_TO_NSEC(xc_tick_jump_limit); + start_time = curr = gethrtime(); + /* busy wait if there is interrupt being processed */ + while (PCMU_IB_INO_INTR_PENDING(state_reg_p, ino) && !panicstr) { + /* + * If we have a really large jump in hrtime, it is most + * probably because we entered the debugger (or OBP, + * in general). So, we adjust the timeout accordingly + * to prevent declaring an interrupt timeout. The + * master-interrupt mechanism in OBP should deliver + * the interrupts properly. + */ + prev = curr; + curr = gethrtime(); + interval = curr - prev; + if (interval > jump) + intr_timeout += interval; + if (curr - start_time > intr_timeout) { + pcmu_pbm_t *pcbm_p = pib_p->pib_pcmu_p->pcmu_pcbm_p; + cmn_err(CE_WARN, + "%s:%s: pcmu_ib_intr_disable timeout %x", + pcbm_p->pcbm_nameinst_str, + pcbm_p->pcbm_nameaddr_str, ino); + break; + } + } +wait_done: + PCMU_IB_INO_INTR_PEND(ib_clear_intr_reg_addr(pib_p, ino)); + u2u_ittrans_cleanup((u2u_ittrans_data_t *) + (PCMU_IB2CB(pib_p)->pcb_ittrans_cookie), imr_p); +} + +/* can only used for CMU-CH internal interrupts ue, pbm */ +void +pcmu_ib_nintr_clear(pcmu_ib_t *pib_p, pcmu_ib_ino_t ino) +{ + uint64_t *clr_reg = ib_clear_intr_reg_addr(pib_p, ino); + PCMU_IB_INO_INTR_CLEAR(clr_reg); +} + +/* + * distribute PBM and UPA interrupts. ino is set to 0 by caller if we + * are dealing with UPA interrupts (without inos). + */ +void +pcmu_ib_intr_dist_nintr(pcmu_ib_t *pib_p, pcmu_ib_ino_t ino, + volatile uint64_t *imr_p) +{ + volatile uint64_t imr = *imr_p; + uint32_t cpu_id; + + if (!PCMU_IB_INO_INTR_ISON(imr)) + return; + + cpu_id = intr_dist_cpuid(); + + if (ino) { + cpu_id = u2u_translate_tgtid(pib_p->pib_pcmu_p, cpu_id, imr_p); + } + + if (ib_map_reg_get_cpu(*imr_p) == cpu_id) { + return; + } + *imr_p = ib_get_map_reg(PCMU_IB_IMR2MONDO(imr), cpu_id); + imr = *imr_p; /* flush previous write */ +} + +static void +pcmu_ib_intr_dist(pcmu_ib_t *pib_p, pcmu_ib_ino_info_t *ino_p) +{ + uint32_t cpu_id = ino_p->pino_cpuid; + pcmu_ib_ino_t ino = ino_p->pino_ino; + volatile uint64_t imr, *imr_p, *state_reg; + hrtime_t start_time; + hrtime_t prev, curr, interval, jump; + hrtime_t intr_timeout; + + ASSERT(MUTEX_HELD(&pib_p->pib_ino_lst_mutex)); + imr_p = ib_intr_map_reg_addr(pib_p, ino); + state_reg = PCMU_IB_INO_INTR_STATE_REG(pib_p, ino); + + /* disable interrupt, this could disrupt devices sharing our slot */ + PCMU_IB_INO_INTR_OFF(imr_p); + imr = *imr_p; /* flush previous write */ + + /* busy wait if there is interrupt being processed */ + intr_timeout = pcmu_intrpend_timeout; + jump = TICK_TO_NSEC(xc_tick_jump_limit); + start_time = curr = gethrtime(); + while (PCMU_IB_INO_INTR_PENDING(state_reg, ino) && !panicstr) { + /* + * If we have a really large jump in hrtime, it is most + * probably because we entered the debugger (or OBP, + * in general). So, we adjust the timeout accordingly + * to prevent declaring an interrupt timeout. The + * master-interrupt mechanism in OBP should deliver + * the interrupts properly. + */ + prev = curr; + curr = gethrtime(); + interval = curr - prev; + if (interval > jump) + intr_timeout += interval; + if (curr - start_time > intr_timeout) { + pcmu_pbm_t *pcbm_p = pib_p->pib_pcmu_p->pcmu_pcbm_p; + cmn_err(CE_WARN, + "%s:%s: pcmu_ib_intr_dist(%p,%x) timeout", + pcbm_p->pcbm_nameinst_str, + pcbm_p->pcbm_nameaddr_str, + imr_p, PCMU_IB_INO_TO_MONDO(pib_p, ino)); + break; + } + } + cpu_id = u2u_translate_tgtid(pib_p->pib_pcmu_p, cpu_id, imr_p); + *imr_p = ib_get_map_reg(PCMU_IB_IMR2MONDO(imr), cpu_id); + imr = *imr_p; /* flush previous write */ +} + +/* + * Redistribute interrupts of the specified weight. The first call has a weight + * of weight_max, which can be used to trigger initialization for + * redistribution. The inos with weight [weight_max, inf.) should be processed + * on the "weight == weight_max" call. This first call is followed by calls + * of decreasing weights, inos of that weight should be processed. The final + * call specifies a weight of zero, this can be used to trigger processing of + * stragglers. + */ +void +pcmu_ib_intr_dist_all(void *arg, int32_t weight_max, int32_t weight) +{ + pcmu_ib_t *pib_p = (pcmu_ib_t *)arg; + pcmu_ib_ino_info_t *ino_p; + ih_t *ih_lst; + int32_t dweight; + int i; + + mutex_enter(&pib_p->pib_ino_lst_mutex); + + /* Perform special processing for first call of a redistribution. */ + if (weight == weight_max) { + for (ino_p = pib_p->pib_ino_lst; ino_p; + ino_p = ino_p->pino_next) { + + /* + * Clear pino_established of each ino on first call. + * The pino_established field may be used by a pci + * nexus driver's pcmu_intr_dist_cpuid implementation + * when detection of established pci slot-cpu binding + * for multi function pci cards. + */ + ino_p->pino_established = 0; + + /* + * recompute the pino_intr_weight based on the device + * weight of all devinfo nodes sharing the ino (this + * will allow us to pick up new weights established by + * i_ddi_set_intr_weight()). + */ + ino_p->pino_intr_weight = 0; + for (i = 0, ih_lst = ino_p->pino_ih_head; + i < ino_p->pino_ih_size; + i++, ih_lst = ih_lst->ih_next) { + dweight = i_ddi_get_intr_weight(ih_lst->ih_dip); + if (dweight > 0) + ino_p->pino_intr_weight += dweight; + } + } + } + + for (ino_p = pib_p->pib_ino_lst; ino_p; ino_p = ino_p->pino_next) { + /* + * Get the weight of the ino and determine if we are going to + * process call. We wait until an pcmu_ib_intr_dist_all call of + * the proper weight occurs to support redistribution of all + * heavy weighted interrupts first (across all nexus driver + * instances). This is done to ensure optimal + * INTR_WEIGHTED_DIST behavior. + */ + if ((weight == ino_p->pino_intr_weight) || + ((weight >= weight_max) && + (ino_p->pino_intr_weight >= weight_max))) { + /* select cpuid to target and mark ino established */ + ino_p->pino_cpuid = pcmu_intr_dist_cpuid(pib_p, ino_p); + ino_p->pino_established = 1; + + /* Add device weight of ino devinfos to targeted cpu. */ + for (i = 0, ih_lst = ino_p->pino_ih_head; + i < ino_p->pino_ih_size; + i++, ih_lst = ih_lst->ih_next) { + dweight = i_ddi_get_intr_weight(ih_lst->ih_dip); + intr_dist_cpuid_add_device_weight( + ino_p->pino_cpuid, ih_lst->ih_dip, dweight); + } + + /* program the hardware */ + pcmu_ib_intr_dist(pib_p, ino_p); + } + } + mutex_exit(&pib_p->pib_ino_lst_mutex); +} + +/* + * Reset interrupts to IDLE. This function is called during + * panic handling after redistributing interrupts; it's needed to + * support dumping to network devices after 'sync' from OBP. + * + * N.B. This routine runs in a context where all other threads + * are permanently suspended. + */ +static uint_t +pcmu_ib_intr_reset(void *arg) +{ + pcmu_ib_t *pib_p = (pcmu_ib_t *)arg; + pcmu_ib_ino_t ino; + uint64_t *clr_reg; + + /* + * Note that we only actually care about interrupts that are + * potentially from network devices. + */ + for (ino = 0; ino <= pib_p->pib_max_ino; ino++) { + clr_reg = ib_clear_intr_reg_addr(pib_p, ino); + PCMU_IB_INO_INTR_CLEAR(clr_reg); + } + return (BF_NONE); +} + +void +pcmu_ib_suspend(pcmu_ib_t *pib_p) +{ + pcmu_ib_ino_info_t *ip; + + /* save ino_lst interrupts' mapping registers content */ + mutex_enter(&pib_p->pib_ino_lst_mutex); + for (ip = pib_p->pib_ino_lst; ip; ip = ip->pino_next) { + ip->pino_map_reg_save = *ip->pino_map_reg; + } + mutex_exit(&pib_p->pib_ino_lst_mutex); +} + +void +pcmu_ib_resume(pcmu_ib_t *pib_p) +{ + pcmu_ib_ino_info_t *ip; + + /* restore ino_lst interrupts' mapping registers content */ + mutex_enter(&pib_p->pib_ino_lst_mutex); + for (ip = pib_p->pib_ino_lst; ip; ip = ip->pino_next) { + PCMU_IB_INO_INTR_CLEAR(ip->pino_clr_reg); /* set intr to idle */ + *ip->pino_map_reg = ip->pino_map_reg_save; /* restore IMR */ + } + mutex_exit(&pib_p->pib_ino_lst_mutex); +} + +/* + * locate ino_info structure on pib_p->pib_ino_lst according to ino# + * returns NULL if not found. + */ +pcmu_ib_ino_info_t * +pcmu_ib_locate_ino(pcmu_ib_t *pib_p, pcmu_ib_ino_t ino_num) +{ + pcmu_ib_ino_info_t *ino_p = pib_p->pib_ino_lst; + ASSERT(MUTEX_HELD(&pib_p->pib_ino_lst_mutex)); + + for (; ino_p && ino_p->pino_ino != ino_num; ino_p = ino_p->pino_next); + return (ino_p); +} + +#define PCMU_IB_INO_TO_SLOT(ino) \ + (PCMU_IB_IS_OBIO_INO(ino) ? 0xff : ((ino) & 0x1f) >> 2) + +pcmu_ib_ino_info_t * +pcmu_ib_new_ino(pcmu_ib_t *pib_p, pcmu_ib_ino_t ino_num, ih_t *ih_p) +{ + pcmu_ib_ino_info_t *ino_p = kmem_alloc(sizeof (pcmu_ib_ino_info_t), + KM_SLEEP); + ino_p->pino_ino = ino_num; + ino_p->pino_slot_no = PCMU_IB_INO_TO_SLOT(ino_num); + ino_p->pino_ib_p = pib_p; + ino_p->pino_clr_reg = ib_clear_intr_reg_addr(pib_p, ino_num); + ino_p->pino_map_reg = ib_intr_map_reg_addr(pib_p, ino_num); + ino_p->pino_unclaimed = 0; + + /* + * cannot disable interrupt since we might share slot + * PCMU_IB_INO_INTR_OFF(ino_p->pino_map_reg); + */ + + ih_p->ih_next = ih_p; + ino_p->pino_ih_head = ih_p; + ino_p->pino_ih_tail = ih_p; + ino_p->pino_ih_start = ih_p; + ino_p->pino_ih_size = 1; + + ino_p->pino_next = pib_p->pib_ino_lst; + pib_p->pib_ino_lst = ino_p; + return (ino_p); +} + +/* the ino_p is retrieved by previous call to pcmu_ib_locate_ino() */ +void +pcmu_ib_delete_ino(pcmu_ib_t *pib_p, pcmu_ib_ino_info_t *ino_p) +{ + pcmu_ib_ino_info_t *list = pib_p->pib_ino_lst; + ASSERT(MUTEX_HELD(&pib_p->pib_ino_lst_mutex)); + if (list == ino_p) { + pib_p->pib_ino_lst = list->pino_next; + } else { + for (; list->pino_next != ino_p; list = list->pino_next); + list->pino_next = ino_p->pino_next; + } +} + +/* free all ino when we are detaching */ +void +pcmu_ib_free_ino_all(pcmu_ib_t *pib_p) +{ + pcmu_ib_ino_info_t *tmp = pib_p->pib_ino_lst; + pcmu_ib_ino_info_t *next = NULL; + while (tmp) { + next = tmp->pino_next; + kmem_free(tmp, sizeof (pcmu_ib_ino_info_t)); + tmp = next; + } +} + +void +pcmu_ib_ino_add_intr(pcmu_t *pcmu_p, pcmu_ib_ino_info_t *ino_p, ih_t *ih_p) +{ + pcmu_ib_ino_t ino = ino_p->pino_ino; + pcmu_ib_t *pib_p = ino_p->pino_ib_p; + volatile uint64_t *state_reg = PCMU_IB_INO_INTR_STATE_REG(pib_p, ino); + hrtime_t start_time; + hrtime_t prev, curr, interval, jump; + hrtime_t intr_timeout; + + ASSERT(pib_p == pcmu_p->pcmu_ib_p); + ASSERT(MUTEX_HELD(&pib_p->pib_ino_lst_mutex)); + + /* disable interrupt, this could disrupt devices sharing our slot */ + PCMU_IB_INO_INTR_OFF(ino_p->pino_map_reg); + *ino_p->pino_map_reg; + + /* do NOT modify the link list until after the busy wait */ + + /* + * busy wait if there is interrupt being processed. + * either the pending state will be cleared by the interrupt wrapper + * or the interrupt will be marked as blocked indicating that it was + * jabbering. + */ + intr_timeout = pcmu_intrpend_timeout; + jump = TICK_TO_NSEC(xc_tick_jump_limit); + start_time = curr = gethrtime(); + while ((ino_p->pino_unclaimed <= pcmu_unclaimed_intr_max) && + PCMU_IB_INO_INTR_PENDING(state_reg, ino) && !panicstr) { + /* + * If we have a really large jump in hrtime, it is most + * probably because we entered the debugger (or OBP, + * in general). So, we adjust the timeout accordingly + * to prevent declaring an interrupt timeout. The + * master-interrupt mechanism in OBP should deliver + * the interrupts properly. + */ + prev = curr; + curr = gethrtime(); + interval = curr - prev; + if (interval > jump) + intr_timeout += interval; + if (curr - start_time > intr_timeout) { + pcmu_pbm_t *pcbm_p = pcmu_p->pcmu_pcbm_p; + cmn_err(CE_WARN, + "%s:%s: pcmu_ib_ino_add_intr %x timeout", + pcbm_p->pcbm_nameinst_str, + pcbm_p->pcbm_nameaddr_str, ino); + break; + } + } + + /* link up pcmu_ispec_t portion of the ppd */ + ih_p->ih_next = ino_p->pino_ih_head; + ino_p->pino_ih_tail->ih_next = ih_p; + ino_p->pino_ih_tail = ih_p; + + ino_p->pino_ih_start = ino_p->pino_ih_head; + ino_p->pino_ih_size++; + + /* + * if the interrupt was previously blocked (left in pending state) + * because of jabber we need to clear the pending state in case the + * jabber has gone away. + */ + if (ino_p->pino_unclaimed > pcmu_unclaimed_intr_max) { + cmn_err(CE_WARN, + "%s%d: pcmu_ib_ino_add_intr: ino 0x%x has been unblocked", + ddi_driver_name(pcmu_p->pcmu_dip), + ddi_get_instance(pcmu_p->pcmu_dip), + ino_p->pino_ino); + ino_p->pino_unclaimed = 0; + PCMU_IB_INO_INTR_CLEAR(ino_p->pino_clr_reg); + } + + /* re-enable interrupt */ + PCMU_IB_INO_INTR_ON(ino_p->pino_map_reg); + *ino_p->pino_map_reg; +} + +/* + * removes pcmu_ispec_t from the ino's link list. + * uses hardware mutex to lock out interrupt threads. + * Side effects: interrupt belongs to that ino is turned off on return. + * if we are sharing PCI slot with other inos, the caller needs + * to turn it back on. + */ +void +pcmu_ib_ino_rem_intr(pcmu_t *pcmu_p, pcmu_ib_ino_info_t *ino_p, ih_t *ih_p) +{ + int i; + pcmu_ib_ino_t ino = ino_p->pino_ino; + ih_t *ih_lst = ino_p->pino_ih_head; + volatile uint64_t *state_reg = + PCMU_IB_INO_INTR_STATE_REG(ino_p->pino_ib_p, ino); + hrtime_t start_time; + hrtime_t prev, curr, interval, jump; + hrtime_t intr_timeout; + + ASSERT(MUTEX_HELD(&ino_p->pino_ib_p->pib_ino_lst_mutex)); + /* disable interrupt, this could disrupt devices sharing our slot */ + PCMU_IB_INO_INTR_OFF(ino_p->pino_map_reg); + *ino_p->pino_map_reg; + + /* do NOT modify the link list until after the busy wait */ + + /* + * busy wait if there is interrupt being processed. + * either the pending state will be cleared by the interrupt wrapper + * or the interrupt will be marked as blocked indicating that it was + * jabbering. + */ + intr_timeout = pcmu_intrpend_timeout; + jump = TICK_TO_NSEC(xc_tick_jump_limit); + start_time = curr = gethrtime(); + while ((ino_p->pino_unclaimed <= pcmu_unclaimed_intr_max) && + PCMU_IB_INO_INTR_PENDING(state_reg, ino) && !panicstr) { + /* + * If we have a really large jump in hrtime, it is most + * probably because we entered the debugger (or OBP, + * in general). So, we adjust the timeout accordingly + * to prevent declaring an interrupt timeout. The + * master-interrupt mechanism in OBP should deliver + * the interrupts properly. + */ + prev = curr; + curr = gethrtime(); + interval = curr - prev; + if (interval > jump) + intr_timeout += interval; + if (curr - start_time > intr_timeout) { + pcmu_pbm_t *pcbm_p = pcmu_p->pcmu_pcbm_p; + cmn_err(CE_WARN, + "%s:%s: pcmu_ib_ino_rem_intr %x timeout", + pcbm_p->pcbm_nameinst_str, + pcbm_p->pcbm_nameaddr_str, ino); + break; + } + } + + if (ino_p->pino_ih_size == 1) { + if (ih_lst != ih_p) + goto not_found; + /* no need to set head/tail as ino_p will be freed */ + goto reset; + } + + /* + * if the interrupt was previously blocked (left in pending state) + * because of jabber we need to clear the pending state in case the + * jabber has gone away. + */ + if (ino_p->pino_unclaimed > pcmu_unclaimed_intr_max) { + cmn_err(CE_WARN, + "%s%d: pcmu_ib_ino_rem_intr: ino 0x%x has been unblocked", + ddi_driver_name(pcmu_p->pcmu_dip), + ddi_get_instance(pcmu_p->pcmu_dip), + ino_p->pino_ino); + ino_p->pino_unclaimed = 0; + PCMU_IB_INO_INTR_CLEAR(ino_p->pino_clr_reg); + } + + /* search the link list for ih_p */ + for (i = 0; (i < ino_p->pino_ih_size) && (ih_lst->ih_next != ih_p); + i++, ih_lst = ih_lst->ih_next); + if (ih_lst->ih_next != ih_p) { + goto not_found; + } + + /* remove ih_p from the link list and maintain the head/tail */ + ih_lst->ih_next = ih_p->ih_next; + if (ino_p->pino_ih_head == ih_p) { + ino_p->pino_ih_head = ih_p->ih_next; + } + if (ino_p->pino_ih_tail == ih_p) { + ino_p->pino_ih_tail = ih_lst; + } + ino_p->pino_ih_start = ino_p->pino_ih_head; +reset: + if (ih_p->ih_config_handle) { + pci_config_teardown(&ih_p->ih_config_handle); + } + kmem_free(ih_p, sizeof (ih_t)); + ino_p->pino_ih_size--; + + return; +not_found: + PCMU_DBG2(PCMU_DBG_R_INTX, ino_p->pino_ib_p->pib_pcmu_p->pcmu_dip, + "ino_p=%x does not have ih_p=%x\n", ino_p, ih_p); +} + +ih_t * +pcmu_ib_ino_locate_intr(pcmu_ib_ino_info_t *ino_p, + dev_info_t *rdip, uint32_t inum) +{ + ih_t *ih_lst = ino_p->pino_ih_head; + int i; + for (i = 0; i < ino_p->pino_ih_size; i++, ih_lst = ih_lst->ih_next) { + if (ih_lst->ih_dip == rdip && ih_lst->ih_inum == inum) { + return (ih_lst); + } + } + return ((ih_t *)NULL); +} + +ih_t * +pcmu_ib_alloc_ih(dev_info_t *rdip, uint32_t inum, + uint_t (*int_handler)(caddr_t int_handler_arg1, caddr_t int_handler_arg2), + caddr_t int_handler_arg1, + caddr_t int_handler_arg2) +{ + ih_t *ih_p; + + ih_p = kmem_alloc(sizeof (ih_t), KM_SLEEP); + ih_p->ih_dip = rdip; + ih_p->ih_inum = inum; + ih_p->ih_intr_state = PCMU_INTR_STATE_DISABLE; + ih_p->ih_handler = int_handler; + ih_p->ih_handler_arg1 = int_handler_arg1; + ih_p->ih_handler_arg2 = int_handler_arg2; + ih_p->ih_config_handle = NULL; + return (ih_p); +} + +int +pcmu_ib_update_intr_state(pcmu_t *pcmu_p, dev_info_t *rdip, + ddi_intr_handle_impl_t *hdlp, uint_t new_intr_state) +{ + pcmu_ib_t *pib_p = pcmu_p->pcmu_ib_p; + pcmu_ib_ino_info_t *ino_p; + pcmu_ib_mondo_t mondo; + ih_t *ih_p; + int ret = DDI_FAILURE; + + mutex_enter(&pib_p->pib_ino_lst_mutex); + + if ((mondo = PCMU_IB_INO_TO_MONDO(pcmu_p->pcmu_ib_p, + PCMU_IB_MONDO_TO_INO((int32_t)hdlp->ih_vector))) == 0) { + mutex_exit(&pib_p->pib_ino_lst_mutex); + return (ret); + } + + if (ino_p = pcmu_ib_locate_ino(pib_p, PCMU_IB_MONDO_TO_INO(mondo))) { + if (ih_p = pcmu_ib_ino_locate_intr(ino_p, + rdip, hdlp->ih_inum)) { + ih_p->ih_intr_state = new_intr_state; + ret = DDI_SUCCESS; + } + } + mutex_exit(&pib_p->pib_ino_lst_mutex); + return (ret); +} diff --git a/usr/src/uts/sun4u/opl/io/pcicmu/pcmu_intr.c b/usr/src/uts/sun4u/opl/io/pcicmu/pcmu_intr.c new file mode 100644 index 0000000000..7f523f6280 --- /dev/null +++ b/usr/src/uts/sun4u/opl/io/pcicmu/pcmu_intr.c @@ -0,0 +1,340 @@ +/* + * 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" + +/* + * CMU-CH nexus interrupt handling: + * PCI device interrupt handler wrapper + * pil lookup routine + * PCI device interrupt related initchild code + */ + +#include <sys/types.h> +#include <sys/kmem.h> +#include <sys/async.h> +#include <sys/spl.h> +#include <sys/sunddi.h> +#include <sys/machsystm.h> +#include <sys/ddi_impldefs.h> +#include <sys/pcicmu/pcicmu.h> +#include <sys/sdt.h> + +uint_t pcmu_intr_wrapper(caddr_t arg); + +/* + * interrupt jabber: + * + * When an interrupt line is jabbering, every time the state machine for the + * associated ino is idled, a new mondo will be sent and the ino will go into + * the pending state again. The mondo will cause a new call to + * pcmu_intr_wrapper() which normally idles the ino's state machine which would + * precipitate another trip round the loop. + * The loop can be broken by preventing the ino's state machine from being + * idled when an interrupt line is jabbering. See the comment at the + * beginning of pcmu_intr_wrapper() explaining how the 'interrupt jabber + * protection' code does this. + */ + + +/* + * If the unclaimed interrupt count has reached the limit set by + * pcmu_unclaimed_intr_max within the time limit, then all interrupts + * on this ino is blocked by not idling the interrupt state machine. + */ +static int +pcmu_spurintr(pcmu_ib_ino_info_t *ino_p) { + int i; + ih_t *ih_p = ino_p->pino_ih_start; + pcmu_t *pcmu_p = ino_p->pino_ib_p->pib_pcmu_p; + char *err_fmt_str; + + if (ino_p->pino_unclaimed > pcmu_unclaimed_intr_max) { + return (DDI_INTR_CLAIMED); + } + if (!ino_p->pino_unclaimed) { + ino_p->pino_spurintr_begin = ddi_get_lbolt(); + } + ino_p->pino_unclaimed++; + if (ino_p->pino_unclaimed <= pcmu_unclaimed_intr_max) { + goto clear; + } + if (drv_hztousec(ddi_get_lbolt() - ino_p->pino_spurintr_begin) + > pcmu_spurintr_duration) { + ino_p->pino_unclaimed = 0; + goto clear; + } + err_fmt_str = "%s%d: ino 0x%x blocked"; + goto warn; +clear: + /* clear the pending state */ + PCMU_IB_INO_INTR_CLEAR(ino_p->pino_clr_reg); + err_fmt_str = "!%s%d: spurious interrupt from ino 0x%x"; +warn: + cmn_err(CE_WARN, err_fmt_str, NAMEINST(pcmu_p->pcmu_dip), + ino_p->pino_ino); + for (i = 0; i < ino_p->pino_ih_size; i++, ih_p = ih_p->ih_next) { + cmn_err(CE_CONT, "!%s-%d#%x ", NAMEINST(ih_p->ih_dip), + ih_p->ih_inum); + } + cmn_err(CE_CONT, "!\n"); + return (DDI_INTR_CLAIMED); +} + +/* + * pcmu_intr_wrapper + * + * This routine is used as wrapper around interrupt handlers installed by child + * device drivers. This routine invokes the driver interrupt handlers and + * examines the return codes. + * There is a count of unclaimed interrupts kept on a per-ino basis. If at + * least one handler claims the interrupt then the counter is halved and the + * interrupt state machine is idled. If no handler claims the interrupt then + * the counter is incremented by one and the state machine is idled. + * If the count ever reaches the limit value set by pcmu_unclaimed_intr_max + * then the interrupt state machine is not idled thus preventing any further + * interrupts on that ino. The state machine will only be idled again if a + * handler is subsequently added or removed. + * + * return value: DDI_INTR_CLAIMED if any handlers claimed the interrupt, + * DDI_INTR_UNCLAIMED otherwise. + */ +uint_t +pcmu_intr_wrapper(caddr_t arg) +{ + pcmu_ib_ino_info_t *ino_p = (pcmu_ib_ino_info_t *)arg; + uint_t result = 0, r; + ih_t *ih_p = ino_p->pino_ih_start; + int i; +#ifdef DEBUG + pcmu_t *pcmu_p = ino_p->pino_ib_p->pib_pcmu_p; +#endif + + + for (i = 0; i < ino_p->pino_ih_size; i++, ih_p = ih_p->ih_next) { + dev_info_t *dip = ih_p->ih_dip; + uint_t (*handler)() = ih_p->ih_handler; + caddr_t arg1 = ih_p->ih_handler_arg1; + caddr_t arg2 = ih_p->ih_handler_arg2; + + if (ih_p->ih_intr_state == PCMU_INTR_STATE_DISABLE) { + PCMU_DBG3(PCMU_DBG_INTR, pcmu_p->pcmu_dip, + "pcmu_intr_wrapper: %s%d interrupt %d is " + "disabled\n", ddi_driver_name(dip), + ddi_get_instance(dip), ino_p->pino_ino); + continue; + } + + DTRACE_PROBE4(pcmu__interrupt__start, dev_info_t, dip, + void *, handler, caddr_t, arg1, caddr_t, arg2); + + r = (*handler)(arg1, arg2); + DTRACE_PROBE4(pcmu__interrupt__complete, dev_info_t, dip, + void *, handler, caddr_t, arg1, int, r); + + result += r; + } + + if (!result) { + return (pcmu_spurintr(ino_p)); + } + ino_p->pino_unclaimed = 0; + /* clear the pending state */ + PCMU_IB_INO_INTR_CLEAR(ino_p->pino_clr_reg); + return (DDI_INTR_CLAIMED); +} + +int +pcmu_add_intr(dev_info_t *dip, dev_info_t *rdip, ddi_intr_handle_impl_t *hdlp) +{ + pcmu_t *pcmu_p = get_pcmu_soft_state(ddi_get_instance(dip)); + pcmu_ib_t *pib_p = pcmu_p->pcmu_ib_p; + ih_t *ih_p; + pcmu_ib_ino_t ino; + pcmu_ib_ino_info_t *ino_p; /* pulse interrupts have no ino */ + pcmu_ib_mondo_t mondo; + uint32_t cpu_id; + int ret; + + ino = PCMU_IB_MONDO_TO_INO(hdlp->ih_vector); + + PCMU_DBG3(PCMU_DBG_A_INTX, dip, "pcmu_add_intr: rdip=%s%d ino=%x\n", + ddi_driver_name(rdip), ddi_get_instance(rdip), ino); + + if (ino > pib_p->pib_max_ino) { + PCMU_DBG1(PCMU_DBG_A_INTX, dip, "ino %x is invalid\n", ino); + return (DDI_INTR_NOTFOUND); + } + + if ((mondo = PCMU_IB_INO_TO_MONDO(pcmu_p->pcmu_ib_p, ino)) == 0) + goto fail1; + + ino = PCMU_IB_MONDO_TO_INO(mondo); + + mutex_enter(&pib_p->pib_ino_lst_mutex); + ih_p = pcmu_ib_alloc_ih(rdip, hdlp->ih_inum, + hdlp->ih_cb_func, hdlp->ih_cb_arg1, hdlp->ih_cb_arg2); + + if (ino_p = pcmu_ib_locate_ino(pib_p, ino)) { /* sharing ino */ + uint32_t intr_index = hdlp->ih_inum; + if (pcmu_ib_ino_locate_intr(ino_p, rdip, intr_index)) { + PCMU_DBG1(PCMU_DBG_A_INTX, dip, + "dup intr #%d\n", intr_index); + goto fail3; + } + + /* + * add default weight(0) to the cpu that we are + * already targeting + */ + cpu_id = ino_p->pino_cpuid; + intr_dist_cpuid_add_device_weight(cpu_id, rdip, 0); + pcmu_ib_ino_add_intr(pcmu_p, ino_p, ih_p); + goto ino_done; + } + + ino_p = pcmu_ib_new_ino(pib_p, ino, ih_p); + hdlp->ih_vector = mondo; + + PCMU_DBG2(PCMU_DBG_A_INTX, dip, "pcmu_add_intr: pil=0x%x mondo=0x%x\n", + hdlp->ih_pri, hdlp->ih_vector); + + DDI_INTR_ASSIGN_HDLR_N_ARGS(hdlp, + (ddi_intr_handler_t *)pcmu_intr_wrapper, (caddr_t)ino_p, NULL); + + ret = i_ddi_add_ivintr(hdlp); + + /* + * Restore original interrupt handler + * and arguments in interrupt handle. + */ + DDI_INTR_ASSIGN_HDLR_N_ARGS(hdlp, ih_p->ih_handler, + ih_p->ih_handler_arg1, ih_p->ih_handler_arg2); + + if (ret != DDI_SUCCESS) { + goto fail4; + } + /* Save the pil for this ino */ + ino_p->pino_pil = hdlp->ih_pri; + + /* clear and enable interrupt */ + PCMU_IB_INO_INTR_CLEAR(ino_p->pino_clr_reg); + + /* select cpu for sharing and removal */ + cpu_id = pcmu_intr_dist_cpuid(pib_p, ino_p); + ino_p->pino_cpuid = cpu_id; + ino_p->pino_established = 1; + intr_dist_cpuid_add_device_weight(cpu_id, rdip, 0); + + cpu_id = u2u_translate_tgtid(pib_p->pib_pcmu_p, + cpu_id, ino_p->pino_map_reg); + *ino_p->pino_map_reg = ib_get_map_reg(mondo, cpu_id); + *ino_p->pino_map_reg; +ino_done: + mutex_exit(&pib_p->pib_ino_lst_mutex); +done: + PCMU_DBG2(PCMU_DBG_A_INTX, dip, "done! Interrupt 0x%x pil=%x\n", + hdlp->ih_vector, hdlp->ih_pri); + return (DDI_SUCCESS); +fail4: + pcmu_ib_delete_ino(pib_p, ino_p); +fail3: + if (ih_p->ih_config_handle) + pci_config_teardown(&ih_p->ih_config_handle); + mutex_exit(&pib_p->pib_ino_lst_mutex); + kmem_free(ih_p, sizeof (ih_t)); +fail1: + PCMU_DBG2(PCMU_DBG_A_INTX, dip, "Failed! Interrupt 0x%x pil=%x\n", + hdlp->ih_vector, hdlp->ih_pri); + return (DDI_FAILURE); +} + +int +pcmu_remove_intr(dev_info_t *dip, dev_info_t *rdip, + ddi_intr_handle_impl_t *hdlp) +{ + pcmu_t *pcmu_p = get_pcmu_soft_state(ddi_get_instance(dip)); + pcmu_ib_t *pib_p = pcmu_p->pcmu_ib_p; + pcmu_ib_ino_t ino; + pcmu_ib_mondo_t mondo; + pcmu_ib_ino_info_t *ino_p; /* non-pulse only */ + ih_t *ih_p; /* non-pulse only */ + + ino = PCMU_IB_MONDO_TO_INO(hdlp->ih_vector); + + PCMU_DBG3(PCMU_DBG_R_INTX, dip, "pcmu_rem_intr: rdip=%s%d ino=%x\n", + ddi_driver_name(rdip), ddi_get_instance(rdip), ino); + + /* Translate the interrupt property */ + mondo = PCMU_IB_INO_TO_MONDO(pcmu_p->pcmu_ib_p, ino); + if (mondo == 0) { + PCMU_DBG1(PCMU_DBG_R_INTX, dip, + "can't get mondo for ino %x\n", ino); + return (DDI_FAILURE); + } + ino = PCMU_IB_MONDO_TO_INO(mondo); + + mutex_enter(&pib_p->pib_ino_lst_mutex); + ino_p = pcmu_ib_locate_ino(pib_p, ino); + if (!ino_p) { + mutex_exit(&pib_p->pib_ino_lst_mutex); + return (DDI_SUCCESS); + } + + ih_p = pcmu_ib_ino_locate_intr(ino_p, rdip, hdlp->ih_inum); + pcmu_ib_ino_rem_intr(pcmu_p, ino_p, ih_p); + intr_dist_cpuid_rem_device_weight(ino_p->pino_cpuid, rdip); + if (ino_p->pino_ih_size == 0) { + PCMU_IB_INO_INTR_PEND(ib_clear_intr_reg_addr(pib_p, ino)); + hdlp->ih_vector = mondo; + i_ddi_rem_ivintr(hdlp); + pcmu_ib_delete_ino(pib_p, ino_p); + } + + /* re-enable interrupt only if mapping register still shared */ + if (ino_p->pino_ih_size) { + PCMU_IB_INO_INTR_ON(ino_p->pino_map_reg); + *ino_p->pino_map_reg; + } + mutex_exit(&pib_p->pib_ino_lst_mutex); + if (ino_p->pino_ih_size == 0) { + kmem_free(ino_p, sizeof (pcmu_ib_ino_info_t)); + } + PCMU_DBG1(PCMU_DBG_R_INTX, dip, "success! mondo=%x\n", mondo); + return (DDI_SUCCESS); +} + +/* + * free the pcmu_inos array allocated during pcmu_intr_setup. the actual + * interrupts are torn down by their respective block destroy routines: + * cb_destroy, pcmu_pbm_destroy, and ib_destroy. + */ +void +pcmu_intr_teardown(pcmu_t *pcmu_p) +{ + kmem_free(pcmu_p->pcmu_inos, pcmu_p->pcmu_inos_len); + pcmu_p->pcmu_inos = NULL; + pcmu_p->pcmu_inos_len = 0; +} diff --git a/usr/src/uts/sun4u/opl/io/pcicmu/pcmu_pbm.c b/usr/src/uts/sun4u/opl/io/pcicmu/pcmu_pbm.c new file mode 100644 index 0000000000..26891fa6fd --- /dev/null +++ b/usr/src/uts/sun4u/opl/io/pcicmu/pcmu_pbm.c @@ -0,0 +1,290 @@ +/* + * 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" + +/* + * CMU-CH PBM implementation: + * initialization + * Bus error interrupt handler + */ + +#include <sys/types.h> +#include <sys/kmem.h> +#include <sys/spl.h> +#include <sys/sysmacros.h> +#include <sys/sunddi.h> +#include <sys/fm/protocol.h> +#include <sys/fm/util.h> +#include <sys/machsystm.h> +#include <sys/async.h> +#include <sys/ddi_impldefs.h> +#include <sys/ontrap.h> +#include <sys/pcicmu/pcicmu.h> +#include <sys/membar.h> +#include <sys/ivintr.h> + +/*LINTLIBRARY*/ + +static uint_t pcmu_pbm_error_intr(caddr_t a); + +/* The nexus interrupt priority values */ +int pcmu_pil[] = {14, 14, 14, 14, 14, 14}; + +void +pcmu_pbm_create(pcmu_t *pcmu_p) +{ + pcmu_pbm_t *pcbm_p; + int len; + dev_info_t *dip = pcmu_p->pcmu_dip; + + /* + * Allocate a state structure for the PBM and cross-link it + * to its per pci node state structure. + */ + pcbm_p = (pcmu_pbm_t *)kmem_zalloc(sizeof (pcmu_pbm_t), KM_SLEEP); + pcmu_p->pcmu_pcbm_p = pcbm_p; + pcbm_p->pcbm_pcmu_p = pcmu_p; + + len = snprintf(pcbm_p->pcbm_nameinst_str, + sizeof (pcbm_p->pcbm_nameinst_str), "%s%d", NAMEINST(dip)); + pcbm_p->pcbm_nameaddr_str = pcbm_p->pcbm_nameinst_str + ++len; + (void) snprintf(pcbm_p->pcbm_nameaddr_str, + sizeof (pcbm_p->pcbm_nameinst_str) - len, "%s@%s", NAMEADDR(dip)); + + pcmu_pbm_setup(pcbm_p); + + PCMU_DBG4(PCMU_DBG_ATTACH, dip, + "pcmu_pbm_create: ctrl=%x, afsr=%x, afar=%x, diag=%x\n", + pcbm_p->pcbm_ctrl_reg, pcbm_p->pcbm_async_flt_status_reg, + pcbm_p->pcbm_async_flt_addr_reg, pcbm_p->pcbm_diag_reg); + PCMU_DBG1(PCMU_DBG_ATTACH, dip, "pcmu_pbm_create: conf=%x\n", + pcbm_p->pcbm_config_header); + + /* + * Register a function to disable pbm error interrupts during a panic. + */ + bus_func_register(BF_TYPE_ERRDIS, + (busfunc_t)pcmu_pbm_disable_errors, pcbm_p); + + /* + * create the interrupt-priorities property if it doesn't + * already exist to provide a hint as to the PIL level for + * our interrupt. + */ + if (ddi_getproplen(DDI_DEV_T_ANY, dip, + DDI_PROP_DONTPASS, "interrupt-priorities", + &len) != DDI_PROP_SUCCESS) { + /* Create the interrupt-priorities property. */ + (void) ddi_prop_create(DDI_DEV_T_NONE, dip, + DDI_PROP_CANSLEEP, "interrupt-priorities", + (caddr_t)pcmu_pil, sizeof (pcmu_pil)); + } + pcmu_pbm_configure(pcbm_p); +} + +int +pcmu_pbm_register_intr(pcmu_pbm_t *pcbm_p) +{ + pcmu_t *pcmu_p = pcbm_p->pcbm_pcmu_p; + uint32_t mondo; + int r = DDI_SUCCESS; + + pcmu_ib_nintr_clear(pcmu_p->pcmu_ib_p, pcmu_p->pcmu_inos[CBNINTR_PBM]); + + /* + * Install the PCI error interrupt handler. + */ + mondo = PCMU_IB_INO_TO_MONDO(pcmu_p->pcmu_ib_p, + pcmu_p->pcmu_inos[CBNINTR_PBM]); + + VERIFY(add_ivintr(mondo, pcmu_pil[CBNINTR_PBM], pcmu_pbm_error_intr, + (caddr_t)pcmu_p, NULL) == 0); + + pcbm_p->pcbm_iblock_cookie = (void *)(uintptr_t)pcmu_pil[CBNINTR_PBM]; + + /* + * Create the pokefault mutex at the PIL below the error interrupt. + */ + + mutex_init(&pcbm_p->pcbm_pokeflt_mutex, NULL, MUTEX_DRIVER, + (void *)(uintptr_t)ipltospl(spltoipl( + (int)(uintptr_t)pcbm_p->pcbm_iblock_cookie) - 1)); + + return (PCMU_ATTACH_RETCODE(PCMU_PBM_OBJ, PCMU_OBJ_INTR_ADD, r)); +} + +void +pcmu_pbm_destroy(pcmu_t *pcmu_p) +{ + pcmu_pbm_t *pcbm_p = pcmu_p->pcmu_pcbm_p; + pcmu_ib_t *pib_p = pcmu_p->pcmu_ib_p; + uint32_t mondo; + + PCMU_DBG0(PCMU_DBG_DETACH, pcmu_p->pcmu_dip, "pcmu_pbm_destroy:\n"); + + mondo = PCMU_IB_INO_TO_MONDO(pcmu_p->pcmu_ib_p, + pcmu_p->pcmu_inos[CBNINTR_PBM]); + + /* + * Free the pokefault mutex. + */ + mutex_destroy(&pcbm_p->pcbm_pokeflt_mutex); + + /* + * Remove the error interrupt. + */ + intr_dist_rem(pcmu_pbm_intr_dist, pcbm_p); + pcmu_ib_intr_disable(pib_p, + pcmu_p->pcmu_inos[CBNINTR_PBM], PCMU_IB_INTR_WAIT); + rem_ivintr(mondo, NULL); + + /* + * Remove the error disable function. + */ + bus_func_unregister(BF_TYPE_ERRDIS, + (busfunc_t)pcmu_pbm_disable_errors, pcbm_p); + + pcmu_pbm_teardown(pcbm_p); + + /* + * Free the pbm state structure. + */ + kmem_free(pcbm_p, sizeof (pcmu_pbm_t)); + pcmu_p->pcmu_pcbm_p = NULL; +} + +static uint_t +pcmu_pbm_error_intr(caddr_t a) +{ + pcmu_t *pcmu_p = (pcmu_t *)a; + pcmu_pbm_t *pcbm_p = pcmu_p->pcmu_pcbm_p; + ddi_fm_error_t derr; + int err = DDI_FM_OK; + on_trap_data_t *otp = pcbm_p->pcbm_ontrap_data; + + bzero(&derr, sizeof (ddi_fm_error_t)); + derr.fme_version = DDI_FME_VERSION; + mutex_enter(&pcmu_p->pcmu_err_mutex); + if ((otp != NULL) && (otp->ot_prot & OT_DATA_ACCESS)) { + /* + * ddi_poke protection, check nexus and children for + * expected errors. + */ + otp->ot_trap |= OT_DATA_ACCESS; + membar_sync(); + derr.fme_flag = DDI_FM_ERR_POKE; + err = pcmu_pbm_err_handler(pcmu_p->pcmu_dip, &derr, + (void *)pcmu_p, PCI_INTR_CALL); + } else if (pcmu_check_error(pcmu_p) != 0) { + /* + * unprotected error, check for all errors. + */ + if (pcmu_errtrig_pa) { + (void) ldphysio(pcmu_errtrig_pa); + } + derr.fme_flag = DDI_FM_ERR_UNEXPECTED; + err = pcmu_pbm_err_handler(pcmu_p->pcmu_dip, &derr, + (void *)pcmu_p, PCI_INTR_CALL); + } + + if (err == DDI_FM_FATAL) { + if (pcmu_panic_on_fatal_errors) { + mutex_exit(&pcmu_p->pcmu_err_mutex); + cmn_err(CE_PANIC, "%s-%d: Fatal PCI bus error(s)\n", + ddi_driver_name(pcmu_p->pcmu_dip), + ddi_get_instance(pcmu_p->pcmu_dip)); + } + } + + mutex_exit(&pcmu_p->pcmu_err_mutex); + pcmu_ib_nintr_clear(pcmu_p->pcmu_ib_p, pcmu_p->pcmu_inos[CBNINTR_PBM]); + return (DDI_INTR_CLAIMED); +} + +void +pcmu_pbm_suspend(pcmu_pbm_t *pcbm_p) +{ + pcmu_t *pcmu_p = pcbm_p->pcbm_pcmu_p; + pcmu_ib_ino_t ino = pcmu_p->pcmu_inos[CBNINTR_PBM]; + pcbm_p->pcbm_imr_save = *ib_intr_map_reg_addr(pcmu_p->pcmu_ib_p, ino); +} + +void +pcmu_pbm_resume(pcmu_pbm_t *pcbm_p) +{ + pcmu_t *pcmu_p = pcbm_p->pcbm_pcmu_p; + pcmu_ib_ino_t ino = pcmu_p->pcmu_inos[CBNINTR_PBM]; + + pcmu_ib_nintr_clear(pcmu_p->pcmu_ib_p, ino); + *ib_intr_map_reg_addr(pcmu_p->pcmu_ib_p, ino) = pcbm_p->pcbm_imr_save; +} + +void +pcmu_pbm_intr_dist(void *arg) +{ + pcmu_pbm_t *pcbm_p = (pcmu_pbm_t *)arg; + pcmu_t *pcmu_p = pcbm_p->pcbm_pcmu_p; + pcmu_ib_t *pib_p = pcmu_p->pcmu_ib_p; + pcmu_ib_ino_t ino = + PCMU_IB_MONDO_TO_INO(pcmu_p->pcmu_inos[CBNINTR_PBM]); + mutex_enter(&pib_p->pib_intr_lock); + pcmu_ib_intr_dist_nintr(pib_p, ino, ib_intr_map_reg_addr(pib_p, ino)); + mutex_exit(&pib_p->pib_intr_lock); +} + +/* + * Function used to log PBM AFSR register bits and to lookup and fault + * handle associated with PBM AFAR register. Called by + * pcmu_pbm_err_handler with pcmu_err_mutex held. + */ +int +pcmu_pbm_afsr_report(dev_info_t *dip, uint64_t fme_ena, + pcmu_pbm_errstate_t *pbm_err_p) +{ + int fatal = 0; + /* LINTED variable */ + pcmu_t *pcmu_p = get_pcmu_soft_state(ddi_get_instance(dip)); + + ASSERT(MUTEX_HELD(&pcmu_p->pcmu_err_mutex)); + + pbm_err_p->pcbm_pri = PBM_PRIMARY; + (void) pcmu_pbm_classify(pbm_err_p); + + /* + * We are currently not dealing with the multiple error + * case, for any secondary errors we will panic. + */ + pbm_err_p->pcbm_pri = PBM_SECONDARY; + if (pcmu_pbm_classify(pbm_err_p)) { + fatal++; + pcmu_pbm_ereport_post(dip, fme_ena, pbm_err_p); + } + + if (fatal) { + return (DDI_FM_FATAL); + } + return (DDI_FM_NONFATAL); +} diff --git a/usr/src/uts/sun4u/opl/io/pcicmu/pcmu_util.c b/usr/src/uts/sun4u/opl/io/pcicmu/pcmu_util.c new file mode 100644 index 0000000000..6cd0383a23 --- /dev/null +++ b/usr/src/uts/sun4u/opl/io/pcicmu/pcmu_util.c @@ -0,0 +1,707 @@ +/* + * 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" + +/* + * CMU-CH nexus utility routines: + * property and config routines for attach() + * reg/intr/range/assigned-address property routines for bus_map() + * init_child() + * fault handling + * debug functions + */ + +#include <sys/types.h> +#include <sys/kmem.h> +#include <sys/async.h> +#include <sys/sysmacros.h> +#include <sys/sunddi.h> +#include <sys/sunndi.h> +#include <sys/fm/protocol.h> +#include <sys/fm/io/pci.h> +#include <sys/fm/util.h> +#include <sys/ddi_impldefs.h> +#include <sys/pcicmu/pcicmu.h> +#include <sys/promif.h> + +/*LINTLIBRARY*/ + +/* + * get_pcmu_properties + * + * This function is called from the attach routine to get the key + * properties of the pci nodes. + * + * used by: pcmu_attach() + * + * return value: DDI_FAILURE on failure + */ +int +get_pcmu_properties(pcmu_t *pcmu_p, dev_info_t *dip) +{ + int i; + + /* + * Get the device's port id. + */ + if ((pcmu_p->pcmu_id = (uint32_t)pcmu_get_portid(dip)) == -1u) { + cmn_err(CE_WARN, "%s%d: no portid property\n", + ddi_driver_name(dip), ddi_get_instance(dip)); + return (DDI_FAILURE); + } + + /* + * Get the bus-ranges property. + */ + i = sizeof (pcmu_p->pcmu_bus_range); + if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, + "bus-range", (caddr_t)&pcmu_p->pcmu_bus_range, &i) != DDI_SUCCESS) { + cmn_err(CE_WARN, "%s%d: no bus-range property\n", + ddi_driver_name(dip), ddi_get_instance(dip)); + return (DDI_FAILURE); + } + PCMU_DBG2(PCMU_DBG_ATTACH, dip, + "get_pcmu_properties: bus-range (%x,%x)\n", + pcmu_p->pcmu_bus_range.lo, pcmu_p->pcmu_bus_range.hi); + + /* + * Get the ranges property. + */ + if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "ranges", + (caddr_t)&pcmu_p->pcmu_ranges, &pcmu_p->pcmu_ranges_length) != + DDI_SUCCESS) { + cmn_err(CE_WARN, "%s%d: no ranges property\n", + ddi_driver_name(dip), ddi_get_instance(dip)); + return (DDI_FAILURE); + } + pcmu_fix_ranges(pcmu_p->pcmu_ranges, + pcmu_p->pcmu_ranges_length / sizeof (pcmu_ranges_t)); + + /* + * Determine the number upa slot interrupts. + */ + pcmu_p->pcmu_numproxy = pcmu_get_numproxy(pcmu_p->pcmu_dip); + PCMU_DBG1(PCMU_DBG_ATTACH, dip, "get_pcmu_properties: numproxy=%d\n", + pcmu_p->pcmu_numproxy); + return (DDI_SUCCESS); +} + +/* + * free_pcmu_properties: + * + * This routine frees the memory used to cache the + * "ranges" properties of the pci bus device node. + * + * used by: pcmu_detach() + * + * return value: none + */ +void +free_pcmu_properties(pcmu_t *pcmu_p) +{ + kmem_free(pcmu_p->pcmu_ranges, pcmu_p->pcmu_ranges_length); +} + +/* + * pcmu_reloc_reg + * + * If the "reg" entry (*pcmu_rp) is relocatable, lookup "assigned-addresses" + * property to fetch corresponding relocated address. + * + * used by: pcmu_map() + * + * return value: + * + * DDI_SUCCESS - on success + * DDI_ME_INVAL - regspec is invalid + */ +int +pcmu_reloc_reg(dev_info_t *dip, dev_info_t *rdip, pcmu_t *pcmu_p, + pci_regspec_t *rp) +{ + int assign_len, assign_entries, i; + pci_regspec_t *assign_p; + register uint32_t phys_hi = rp->pci_phys_hi; + register uint32_t mask = PCI_REG_ADDR_M | PCI_CONF_ADDR_MASK; + register uint32_t phys_addr = phys_hi & mask; + + PCMU_DBG5(PCMU_DBG_MAP | PCMU_DBG_CONT, dip, + "\tpcmu_reloc_reg fr: %x.%x.%x %x.%x\n", + rp->pci_phys_hi, rp->pci_phys_mid, rp->pci_phys_low, + rp->pci_size_hi, rp->pci_size_low); + + if ((phys_hi & PCI_RELOCAT_B) || !(phys_hi & PCI_ADDR_MASK)) { + return (DDI_SUCCESS); + } + + /* phys_mid must be 0 regardless space type. XXX-64 bit mem space */ + if (rp->pci_phys_mid != 0 || rp->pci_size_hi != 0) { + PCMU_DBG0(PCMU_DBG_MAP | PCMU_DBG_CONT, pcmu_p->pcmu_dip, + "phys_mid or size_hi not 0\n"); + return (DDI_ME_INVAL); + } + + if (ddi_getlongprop(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS, + "assigned-addresses", (caddr_t)&assign_p, &assign_len)) { + return (DDI_ME_INVAL); + } + + assign_entries = assign_len / sizeof (pci_regspec_t); + for (i = 0; i < assign_entries; i++, assign_p++) { + if ((assign_p->pci_phys_hi & mask) == phys_addr) { + rp->pci_phys_low += assign_p->pci_phys_low; + break; + } + } + kmem_free(assign_p - i, assign_len); + PCMU_DBG5(PCMU_DBG_MAP | PCMU_DBG_CONT, dip, + "\tpcmu_reloc_reg to: %x.%x.%x %x.%x\n", + rp->pci_phys_hi, rp->pci_phys_mid, rp->pci_phys_low, + rp->pci_size_hi, rp->pci_size_low); + return (i < assign_entries ? DDI_SUCCESS : DDI_ME_INVAL); +} + +/* + * use "ranges" to translate relocated pci regspec into parent space + */ +int +pcmu_xlate_reg(pcmu_t *pcmu_p, pci_regspec_t *pcmu_rp, struct regspec *new_rp) +{ + int n; + pcmu_ranges_t *rng_p = pcmu_p->pcmu_ranges; + int rng_n = pcmu_p->pcmu_ranges_length / sizeof (pcmu_ranges_t); + + uint32_t space_type = PCI_REG_ADDR_G(pcmu_rp->pci_phys_hi); + uint32_t reg_end, reg_begin = pcmu_rp->pci_phys_low; + uint32_t sz = pcmu_rp->pci_size_low; + + uint32_t rng_begin, rng_end; + + if (space_type == PCI_REG_ADDR_G(PCI_ADDR_CONFIG)) { + if (reg_begin > PCI_CONF_HDR_SIZE) { + return (DDI_ME_INVAL); + } + sz = sz ? MIN(sz, PCI_CONF_HDR_SIZE) : PCI_CONF_HDR_SIZE; + reg_begin += pcmu_rp->pci_phys_hi; + } + reg_end = reg_begin + sz - 1; + + for (n = 0; n < rng_n; n++, rng_p++) { + if (space_type != PCI_REG_ADDR_G(rng_p->child_high)) { + continue; /* not the same space type */ + } + + rng_begin = rng_p->child_low; + if (space_type == PCI_REG_ADDR_G(PCI_ADDR_CONFIG)) { + rng_begin += rng_p->child_high; + } + rng_end = rng_begin + rng_p->size_low - 1; + if (reg_begin >= rng_begin && reg_end <= rng_end) { + break; + } + } + if (n >= rng_n) { + return (DDI_ME_REGSPEC_RANGE); + } + + new_rp->regspec_addr = reg_begin - rng_begin + rng_p->parent_low; + new_rp->regspec_bustype = rng_p->parent_high; + new_rp->regspec_size = sz; + PCMU_DBG4(PCMU_DBG_MAP | PCMU_DBG_CONT, pcmu_p->pcmu_dip, + "\tpcmu_xlate_reg: entry %d new_rp %x.%x %x\n", + n, new_rp->regspec_bustype, new_rp->regspec_addr, sz); + return (DDI_SUCCESS); +} + + +/* + * pcmu_report_dev + * + * This function is called from our control ops routine on a + * DDI_CTLOPS_REPORTDEV request. + * + * The display format is + * + * <name><inst> at <pname><pinst> device <dev> function <func> + * + * where + * + * <name> this device's name property + * <inst> this device's instance number + * <name> parent device's name property + * <inst> parent device's instance number + * <dev> this device's device number + * <func> this device's function number + */ +int +pcmu_report_dev(dev_info_t *dip) +{ + if (dip == (dev_info_t *)0) { + return (DDI_FAILURE); + } + cmn_err(CE_CONT, "?PCI-device: %s@%s, %s%d\n", ddi_node_name(dip), + ddi_get_name_addr(dip), ddi_driver_name(dip), + ddi_get_instance(dip)); + return (DDI_SUCCESS); +} + +/* + * name_child + * + * This function is called from pcmu_init_child to name a node. It is + * also passed as a callback for node merging functions. + * + * return value: DDI_SUCCESS, DDI_FAILURE + */ +static int +name_child(dev_info_t *child, char *name, int namelen) +{ + pci_regspec_t *pcmu_rp; + int reglen; + uint_t func; + char **unit_addr; + uint_t n; + + /* + * Set the address portion of the node name based on + * unit-address property, if it exists. + * The interpretation of the unit-address is DD[,F] + * where DD is the device id and F is the function. + */ + if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, child, + DDI_PROP_DONTPASS, "unit-address", &unit_addr, &n) == + DDI_PROP_SUCCESS) { + if (n != 1 || *unit_addr == NULL || **unit_addr == 0) { + cmn_err(CE_WARN, "unit-address property in %s.conf" + " not well-formed", ddi_driver_name(child)); + ddi_prop_free(unit_addr); + return (DDI_FAILURE); + } + (void) snprintf(name, namelen, "%s", *unit_addr); + ddi_prop_free(unit_addr); + return (DDI_SUCCESS); + } + + /* + * The unit-address property is does not exist. Set the address + * portion of the node name based on the function and device number. + */ + if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, + "reg", (int **)&pcmu_rp, (uint_t *)®len) == DDI_SUCCESS) { + if (((reglen * sizeof (int)) % sizeof (pci_regspec_t)) != 0) { + cmn_err(CE_WARN, "reg property not well-formed"); + return (DDI_FAILURE); + } + + func = PCI_REG_FUNC_G(pcmu_rp[0].pci_phys_hi); + if (func != 0) { + (void) snprintf(name, namelen, "%x,%x", + PCI_REG_DEV_G(pcmu_rp[0].pci_phys_hi), func); + } else { + (void) snprintf(name, namelen, "%x", + PCI_REG_DEV_G(pcmu_rp[0].pci_phys_hi)); + } + ddi_prop_free(pcmu_rp); + return (DDI_SUCCESS); + } + cmn_err(CE_WARN, "cannot name pci child '%s'", ddi_node_name(child)); + return (DDI_FAILURE); +} + +int +pcmu_uninit_child(pcmu_t *pcmu_p, dev_info_t *child) +{ + PCMU_DBG2(PCMU_DBG_CTLOPS, pcmu_p->pcmu_dip, + "DDI_CTLOPS_UNINITCHILD: arg=%s%d\n", + ddi_driver_name(child), ddi_get_instance(child)); + + ddi_set_name_addr(child, NULL); + ddi_remove_minor_node(child, NULL); + impl_rem_dev_props(child); + + PCMU_DBG0(PCMU_DBG_PWR, ddi_get_parent(child), "\n\n"); + return (DDI_SUCCESS); +} + +/* + * pcmu_init_child + * + * This function is called from our control ops routine on a + * DDI_CTLOPS_INITCHILD request. It builds and sets the device's + * parent private data area. + * + * used by: pcmu_ctlops() + * + * return value: none + */ +int +pcmu_init_child(pcmu_t *pcmu_p, dev_info_t *child) +{ + char name[10]; + ddi_acc_handle_t config_handle; + uint8_t bcr; + uint8_t header_type; + + if (name_child(child, name, 10) != DDI_SUCCESS) + return (DDI_FAILURE); + ddi_set_name_addr(child, name); + + PCMU_DBG2(PCMU_DBG_PWR, ddi_get_parent(child), + "INITCHILD: config regs setup for %s@%s\n", + ddi_node_name(child), ddi_get_name_addr(child)); + + /* + * Map the child configuration space to for initialization. + * We assume the obp will do the following in the devices + * config space: + * + * Set the latency-timer register to values appropriate + * for the devices on the bus (based on other devices + * MIN_GNT and MAX_LAT registers. + * + * Set the fast back-to-back enable bit in the command + * register if it's supported and all devices on the bus + * have the capability. + * + */ + if (pci_config_setup(child, &config_handle) != DDI_SUCCESS) { + ddi_set_name_addr(child, NULL); + return (DDI_FAILURE); + } + + /* + * Determine the configuration header type. + */ + header_type = pci_config_get8(config_handle, PCI_CONF_HEADER); + PCMU_DBG2(PCMU_DBG_INIT_CLD, pcmu_p->pcmu_dip, "%s: header_type=%x\n", + ddi_driver_name(child), header_type); + + /* + * If the device has a bus control register then program it + * based on the settings in the command register. + */ + if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_ONE) { + bcr = pci_config_get8(config_handle, PCI_BCNF_BCNTRL); + if (pcmu_command_default & PCI_COMM_PARITY_DETECT) + bcr |= PCI_BCNF_BCNTRL_PARITY_ENABLE; + if (pcmu_command_default & PCI_COMM_SERR_ENABLE) + bcr |= PCI_BCNF_BCNTRL_SERR_ENABLE; + bcr |= PCI_BCNF_BCNTRL_MAST_AB_MODE; + pci_config_put8(config_handle, PCI_BCNF_BCNTRL, bcr); + } + + pci_config_teardown(&config_handle); + return (DDI_SUCCESS); +} + +/* + * pcmu_get_reg_set_size + * + * Given a dev info pointer to a pci child and a register number, this + * routine returns the size element of that reg set property. + * + * used by: pcmu_ctlops() - DDI_CTLOPS_REGSIZE + * + * return value: size of reg set on success, zero on error + */ +off_t +pcmu_get_reg_set_size(dev_info_t *child, int rnumber) +{ + pci_regspec_t *pcmu_rp; + off_t size; + int i; + + if (rnumber < 0) { + return (0); + } + + /* + * Get the reg property for the device. + */ + if (ddi_getlongprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, "reg", + (caddr_t)&pcmu_rp, &i) != DDI_SUCCESS) { + return (0); + } + + if (rnumber >= (i / (int)sizeof (pci_regspec_t))) { + kmem_free(pcmu_rp, i); + return (0); + } + + size = pcmu_rp[rnumber].pci_size_low | + ((uint64_t)pcmu_rp[rnumber].pci_size_hi << 32); + kmem_free(pcmu_rp, i); + return (size); +} + + +/* + * pcmu_get_nreg_set + * + * Given a dev info pointer to a pci child, this routine returns the + * number of sets in its "reg" property. + * + * used by: pcmu_ctlops() - DDI_CTLOPS_NREGS + * + * return value: # of reg sets on success, zero on error + */ +uint_t +pcmu_get_nreg_set(dev_info_t *child) +{ + pci_regspec_t *pcmu_rp; + int i, n; + + /* + * Get the reg property for the device. + */ + if (ddi_getlongprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, "reg", + (caddr_t)&pcmu_rp, &i) != DDI_SUCCESS) { + return (0); + } + n = i / (int)sizeof (pci_regspec_t); + kmem_free(pcmu_rp, i); + return (n); +} + +int +pcmu_cfg_report(dev_info_t *dip, ddi_fm_error_t *derr, + pcmu_errstate_t *pcmu_err_p, int caller, uint32_t prierr) +{ + int fatal = 0; + int nonfatal = 0; + int i; + pcmu_t *pcmu_p; + int instance = ddi_get_instance(dip); + + ASSERT(dip); + + pcmu_p = get_pcmu_soft_state(instance); + + derr->fme_ena = derr->fme_ena ? derr->fme_ena : + fm_ena_generate(0, FM_ENA_FMT1); + + for (i = 0; pci_err_tbl[i].err_class != NULL; i++) { + if (pcmu_err_p->pcmu_cfg_stat & pci_err_tbl[i].reg_bit) { + char buf[FM_MAX_CLASS]; + char *aux_msg = NULL; + + switch (pci_err_tbl[i].reg_bit) { + case PCI_STAT_R_MAST_AB: + aux_msg = "Recieved Master Abort"; + /* LINTED fallthrough on case statement */ + case PCI_STAT_R_TARG_AB: + if (aux_msg != NULL) + aux_msg = "Recieved Target Abort"; + if (prierr) { + /* + * piow case are already handled in + * pcmu_pbm_afsr_report() + */ + break; + } + if (caller != PCI_TRAP_CALL) { + /* + * if we haven't come from trap handler + * we won't have an address + */ + fatal++; + } + break; + default: + /* + * dpe on dma write or ta on dma + */ + nonfatal++; + break; + } + (void) snprintf(buf, FM_MAX_CLASS, "%s %s: %s %s", + (pcmu_p->pcmu_pcbm_p)->pcbm_nameinst_str, + (pcmu_p->pcmu_pcbm_p)->pcbm_nameaddr_str, + "PCI config space:", aux_msg); + cmn_err(CE_WARN, "%s %s=0x%p", buf, + "pbm-csr", (pcmu_p->pcmu_pcbm_p)->pcbm_ctrl_reg); + } + } + + if (fatal) + return (DDI_FM_FATAL); + else if (nonfatal) + return (DDI_FM_NONFATAL); + + return (DDI_FM_OK); +} + +void +pcmu_child_cfg_save(dev_info_t *dip) +{ + dev_info_t *cdip; + int ret = DDI_SUCCESS; + + /* + * Save the state of the configuration headers of child + * nodes. + */ + + for (cdip = ddi_get_child(dip); cdip != NULL; + cdip = ddi_get_next_sibling(cdip)) { + + /* + * Not interested in children who are not already + * init'ed. They will be set up in pcmu_init_child(). + */ + if (i_ddi_node_state(cdip) < DS_INITIALIZED) { + PCMU_DBG2(PCMU_DBG_DETACH, dip, "DDI_SUSPEND: skipping " + "%s%d not in CF1\n", ddi_driver_name(cdip), + ddi_get_instance(cdip)); + + continue; + } + + /* + * Only save config registers if not already saved by child. + */ + if (ddi_prop_exists(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS, + SAVED_CONFIG_REGS) == 1) { + + continue; + } + + /* + * The nexus needs to save config registers. Create a property + * so it knows to restore on resume. + */ + ret = ndi_prop_create_boolean(DDI_DEV_T_NONE, cdip, + "nexus-saved-config-regs"); + + if (ret != DDI_PROP_SUCCESS) { + cmn_err(CE_WARN, "%s%d can't update prop %s", + ddi_driver_name(cdip), ddi_get_instance(cdip), + "nexus-saved-config-regs"); + } + + (void) pci_save_config_regs(cdip); + } +} + +void +pcmu_child_cfg_restore(dev_info_t *dip) +{ + dev_info_t *cdip; + + /* + * Restore config registers for children that did not save + * their own registers. Children pwr states are UNKNOWN after + * a resume since it is possible for the PM framework to call + * resume without an actual power cycle. (ie if suspend fails). + */ + for (cdip = ddi_get_child(dip); cdip != NULL; + cdip = ddi_get_next_sibling(cdip)) { + + /* + * Not interested in children who are not already + * init'ed. They will be set up by pcmu_init_child(). + */ + if (i_ddi_node_state(cdip) < DS_INITIALIZED) { + PCMU_DBG2(PCMU_DBG_DETACH, dip, + "DDI_RESUME: skipping %s%d not in CF1\n", + ddi_driver_name(cdip), ddi_get_instance(cdip)); + continue; + } + + /* + * Only restore config registers if saved by nexus. + */ + if (ddi_prop_exists(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS, + "nexus-saved-config-regs") == 1) { + (void) pci_restore_config_regs(cdip); + + PCMU_DBG2(PCMU_DBG_PWR, dip, + "DDI_RESUME: nexus restoring %s%d config regs\n", + ddi_driver_name(cdip), ddi_get_instance(cdip)); + + if (ndi_prop_remove(DDI_DEV_T_NONE, cdip, + "nexus-saved-config-regs") != DDI_PROP_SUCCESS) { + cmn_err(CE_WARN, "%s%d can't remove prop %s", + ddi_driver_name(cdip), + ddi_get_instance(cdip), + "nexus-saved-config-regs"); + } + } + } +} + +#ifdef DEBUG +extern uint64_t pcmu_debug_flags; + +pcmu_dflag_to_str_t pcmu_dflag_strings [] = { + {PCMU_DBG_ATTACH, "pcmu_attach"}, + {PCMU_DBG_DETACH, "pcmu_detach"}, + {PCMU_DBG_MAP, "pcmu_map"}, + {PCMU_DBG_A_INTX, "pcmu_add_intx"}, + {PCMU_DBG_R_INTX, "pcmu_rem_intx"}, + {PCMU_DBG_INIT_CLD, "pcmu_init_child"}, + {PCMU_DBG_CTLOPS, "pcmu_ctlops"}, + {PCMU_DBG_INTR, "pcmu_intr_wrapper"}, + {PCMU_DBG_ERR_INTR, "pcmu_pbm_error_intr"}, + {PCMU_DBG_BUS_FAULT, "pcmu_fault"}, + {PCMU_DBG_IB, "pcmu_ib"}, + {PCMU_DBG_CB, "pcmu_cb"}, + {PCMU_DBG_PBM, "pcmu_pbm"}, + {PCMU_DBG_OPEN, "pcmu_open"}, + {PCMU_DBG_CLOSE, "pcmu_close"}, + {PCMU_DBG_IOCTL, "pcmu_ioctl"}, + {PCMU_DBG_PWR, "pcmu_pwr"} +}; + +void +pcmu_debug(uint64_t flag, dev_info_t *dip, char *fmt, + uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5) +{ + char *s = "pcmu unknown"; + uint_t cont = 0; + int i; + int no_rec = (sizeof (pcmu_dflag_strings) / + sizeof (pcmu_dflag_to_str_t)); + + if (flag & PCMU_DBG_CONT) { + flag &= ~PCMU_DBG_CONT; + cont = 1; + } + if ((pcmu_debug_flags & flag) == flag) { + for (i = 0; i < no_rec; i++) { + if (pcmu_dflag_strings[i].flag == flag) { + s = pcmu_dflag_strings[i].string; + break; + } + } + if (s && cont == 0) { + prom_printf("%s(%d): %s: ", ddi_driver_name(dip), + ddi_get_instance(dip), s); + } + prom_printf(fmt, a1, a2, a3, a4, a5); + } +} +#endif diff --git a/usr/src/uts/sun4u/opl/io/scfd/scf_os_interface.c b/usr/src/uts/sun4u/opl/io/scfd/scf_os_interface.c new file mode 100644 index 0000000000..f99b860329 --- /dev/null +++ b/usr/src/uts/sun4u/opl/io/scfd/scf_os_interface.c @@ -0,0 +1,143 @@ +/* + * 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 + */ +/* + * All Rights Reserved, Copyright (c) FUJITSU LIMITED 2006 + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <sys/sunddi.h> +#include <sys/ddi.h> +#include <sys/kobj.h> + +#include <sys/scfd/scfsys.h> +#include <sys/scfd/scfostoescf.h> + +#define XSCF_DATA_LEN 16 +#define SCF_RETRY_COUNT 10 + + +static int +scf_os_putinfo(uint8_t type, char *datap, uint32_t length) +{ + int rv, count; + + rv = 0; + + count = SCF_RETRY_COUNT; + while (count-- > 0) { + rv = scf_service_putinfo(KEY_ESCF, type, 0, length, + (void *)datap); + if (rv == EBUSY) { + /* 5 sec delay */ + delay(5 * drv_usectohz(1000000)); + continue; + } + break; + }; + + return (rv); +} + +static int +scf_os_getinfo(uint8_t type, char *datap, uint32_t *lengthp) +{ + int rv, count; + + rv = 0; + count = SCF_RETRY_COUNT; + while (count-- > 0) { + rv = scf_service_getinfo(KEY_ESCF, type, 0, lengthp, + (void *)datap); + if (rv == EBUSY) { + /* 5 sec delay */ + delay(5 * drv_usectohz(1000000)); + continue; + } + break; + }; + + return (rv); +} + +/* + * scf_fmem_start() + * + * Description: Before starting rename memory, + * sending the message + * from OS to XSCF. + * + */ +int +scf_fmem_start(int s_bd, int t_bd) +{ + char data[XSCF_DATA_LEN]; + + bzero(data, XSCF_DATA_LEN); + data[0] = (char)s_bd; + data[1] = (char)t_bd; + + return (scf_os_putinfo(SUB_OS_SEND_PRE_FMEMA, + data, XSCF_DATA_LEN)); +} + +/* + * scf_fmem_end() + * + * Description: After doing rename memory, sending the message + * from OS to XSCF. + * + */ +int +scf_fmem_end() +{ + char data[XSCF_DATA_LEN]; + int rv; + uint32_t len; + + bzero(data, XSCF_DATA_LEN); + len = XSCF_DATA_LEN; + rv = scf_os_getinfo(SUB_OS_SEND_COMPLETE_FMEMA, + data, &len); + + if (rv == 0) { + /* 0 is OK and everything less than 0 is BAD but TBD */ + if (len > 0) + rv = (int)data[0]; + else + rv = -1; + } + return (rv); +} + +/* + * scf_fmem_cancel() + * + * Description: If the status failed after doing rename memory + * and check the result, sending the message from OS to XSCF. + * + */ +int +scf_fmem_cancel() +{ + return (scf_os_putinfo(SUB_OS_SEND_CANCEL_FMEMA, 0, 0)); +} diff --git a/usr/src/uts/sun4u/opl/io/scfd/scfconf.c b/usr/src/uts/sun4u/opl/io/scfd/scfconf.c new file mode 100644 index 0000000000..c6e9e11646 --- /dev/null +++ b/usr/src/uts/sun4u/opl/io/scfd/scfconf.c @@ -0,0 +1,1124 @@ +/* + * 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 + */ +/* + * All Rights Reserved, Copyright (c) FUJITSU LIMITED 2006 + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/stat.h> +#include <sys/file.h> +#include <sys/types.h> +#include <sys/conf.h> +#include <sys/kmem.h> +#include <sys/ddi.h> +#include <sys/sunddi.h> + +#include <sys/scfd/scfparam.h> +#include <sys/scfd/scfdscpif.h> + +static struct driver_minor_data { + char *name; + int type; + int minor_num; +} scf_minor[] = { + { "pwrctl", S_IFCHR, SCF_USER_INSTANCE }, + { "rasctl", S_IFCHR, SCF_USER_INSTANCE }, + { "rcictl", S_IFCHR, SCF_USER_INSTANCE }, + SCF_DBG_IOMP_INSTANCE + { NULL, 0} +}; + + +/* + * Function list + */ +void scf_resource_free_dev(scf_state_t *statep); +void scf_reload_conf(scf_state_t *statep); + +/* + * External function + */ +extern void scf_dscp_init(void); +extern void scf_dscp_fini(void); + +/* + * External value + */ +extern int scf_devbusy_wait_time; +extern int scf_cmdend_wait_time; +extern int scf_online_wait_time; +extern int scf_rxbuff_wait_time; +extern int scf_dscp_ack_wait_time; +extern int scf_dscp_end_wait_time; +extern int scf_dscp_txbusy_time; +extern int scf_dscp_callback_time; +extern int scf_shutdown_wait_time; +extern int scf_poff_wait_time; +extern int scf_halt_wait_time; + + +/* + * scf_attach() + * + * Description: Driver attach() entry processing. + * + */ +int +scf_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) +{ +#define SCF_FUNC_NAME "scf_attach() " + scf_state_t *statep; + int instance; + struct driver_minor_data *dmdp; + int ret = DDI_FAILURE; + char wk_pathname[MAXPATHLEN]; + timeout_id_t save_tmids[SCF_TIMERCD_MAX]; + int tm_stop_cnt; + + SCFDBGMSG2(SCF_DBGFLAG_DDI, + SCF_FUNC_NAME ": start instance = %d name = %s", + ddi_get_instance(dip), ddi_get_name(dip)); + SC_DBG_DRV_TRACE(TC_ATTACH|TC_IN, __LINE__, &cmd, + sizeof (ddi_attach_cmd_t)); + + if (strcmp(ddi_get_name(dip), SCF_DRIVER_NAME) == 0) { + /* pseudo device */ + if (cmd == DDI_ATTACH) { + SCFDBGMSG(SCF_DBGFLAG_DDI, "pseudo attach proc"); + mutex_enter(&scf_comtbl.attach_mutex); + + /* get instance number */ + instance = ddi_get_instance(dip); + + /* allocate softstate */ + if (ddi_soft_state_zalloc(scfstate, instance) != + DDI_SUCCESS) { + SC_DBG_DRV_TRACE(TC_ATTACH|TC_ERR, __LINE__, + "attach ", 8); + cmn_err(CE_WARN, + "%s: scf_attach: " + "ddi_soft_state_zalloc failed.\n", + scf_driver_name); + + mutex_exit(&scf_comtbl.attach_mutex); + goto END_attach; + } + + /* get softstate */ + if ((statep = ddi_get_soft_state(scfstate, instance)) == + NULL) { + SC_DBG_DRV_TRACE(TC_ATTACH|TC_ERR, __LINE__, + "attach ", 8); + cmn_err(CE_WARN, + "%s: scf_attach: " + "ddi_get_soft_state failed.\n", + scf_driver_name); + ddi_soft_state_free(scfstate, instance); + + mutex_exit(&scf_comtbl.attach_mutex); + goto END_attach; + } + + /* retain dip in soft state */ + statep->dip = dip; + + /* create minor node */ + for (dmdp = scf_minor; dmdp->name != NULL; dmdp++) { + if (ddi_create_minor_node(dip, dmdp->name, + dmdp->type, dmdp->minor_num, + DDI_PSEUDO, 0) == DDI_FAILURE) { + SC_DBG_DRV_TRACE(TC_ATTACH|TC_ERR, + __LINE__, "attach ", 8); + cmn_err(CE_WARN, + "%s: scf_attach: " + "ddi_create_minor_node " + "failed.\n", + scf_driver_name); + + /* remove minor node */ + if (scf_comtbl.resource_flag & + DID_MNODE) { + ddi_remove_minor_node(dip, + NULL); + scf_comtbl.resource_flag &= + (~DID_MNODE); + } + + /* soft state free */ + ddi_soft_state_free(scfstate, instance); + + mutex_exit(&scf_comtbl.attach_mutex); + goto END_attach; + } + scf_comtbl.resource_flag |= DID_MNODE; + SCFDBGMSG(SCF_DBGFLAG_DDI, + "ddi_create_minor_node() is success"); + } + + scf_comtbl.scf_pseudo_p = statep; + + mutex_exit(&scf_comtbl.attach_mutex); + } + ret = DDI_SUCCESS; + goto END_attach; + } + + /* get SCF Driver mutex */ + mutex_enter(&scf_comtbl.attach_mutex); + + if (!(scf_comtbl.resource_flag & DID_MUTEX_ALL)) { + + if (ddi_get_iblock_cookie(dip, 0, &scf_comtbl.iblock_cookie) != + DDI_SUCCESS) { + SC_DBG_DRV_TRACE(TC_ATTACH|TC_ERR, __LINE__, + "attach ", 8); + cmn_err(CE_WARN, + "%s: scf_attach: " + "ddi_get_iblock_cookie failed.\n", + scf_driver_name); + + mutex_exit(&scf_comtbl.attach_mutex); + goto END_attach; + } + + mutex_init(&scf_comtbl.all_mutex, NULL, MUTEX_DRIVER, + scf_comtbl.iblock_cookie); + scf_comtbl.resource_flag |= DID_MUTEX_ALL; + } + if (!(scf_comtbl.resource_flag & DID_MUTEX_SI)) { + + if (ddi_get_soft_iblock_cookie(dip, SCF_EVENT_PRI, + &scf_comtbl.soft_iblock_cookie) != + DDI_SUCCESS) { + SC_DBG_DRV_TRACE(TC_ATTACH|TC_ERR, __LINE__, + "attach ", 8); + cmn_err(CE_WARN, + "%s: scf_attach: " + "ddi_get_soft_iblock_cookie failed.\n", + scf_driver_name); + + mutex_exit(&scf_comtbl.attach_mutex); + goto END_attach; + } + + mutex_init(&scf_comtbl.si_mutex, NULL, MUTEX_DRIVER, + scf_comtbl.soft_iblock_cookie); + scf_comtbl.resource_flag |= DID_MUTEX_SI; + } + /* add software interrupt handler */ + if (!(scf_comtbl.resource_flag & DID_SOFTINTR)) { + if (ddi_add_softintr(dip, SCF_EVENT_PRI, + &scf_comtbl.scf_softintr_id, NULL, NULL, + &scf_softintr, NULL) != DDI_SUCCESS) { + SC_DBG_DRV_TRACE(TC_ATTACH | TC_ERR, __LINE__, + "attach ", 8); + cmn_err(CE_WARN, + "%s: scf_attach: ddi_add_softintr failed.", + scf_driver_name); + goto ATTACH_failed; + } + scf_comtbl.resource_flag |= DID_SOFTINTR; + } + /* kstat resource initialize */ + if (!(scf_comtbl.resource_flag & DID_KSTAT)) { + scf_kstat_init(); + scf_comtbl.resource_flag |= DID_KSTAT; + } + + mutex_exit(&scf_comtbl.attach_mutex); + + /* Lock driver mutex */ + mutex_enter(&scf_comtbl.all_mutex); + + /* get instance number */ + instance = ddi_get_instance(dip); + + switch (cmd) { + case DDI_ATTACH: + /* DDI_ATTACH */ + SCFDBGMSG(SCF_DBGFLAG_DDI, "attach proc"); + /* allocate softstate */ + if (ddi_soft_state_zalloc(scfstate, instance) != DDI_SUCCESS) { + SC_DBG_DRV_TRACE(TC_ATTACH|TC_ERR, __LINE__, + "attach ", 8); + cmn_err(CE_WARN, + "%s: scf_attach: " + "ddi_soft_state_zalloc failed.\n", + scf_driver_name); + + /* Unlock driver mutex */ + mutex_exit(&scf_comtbl.all_mutex); + goto END_attach; + } + + /* get softstate */ + if ((statep = ddi_get_soft_state(scfstate, instance)) == NULL) { + SC_DBG_DRV_TRACE(TC_ATTACH|TC_ERR, __LINE__, + "attach ", 8); + cmn_err(CE_WARN, + "%s: scf_attach: ddi_get_soft_state failed.\n", + scf_driver_name); + ddi_soft_state_free(scfstate, instance); + + /* Unlock driver mutex */ + mutex_exit(&scf_comtbl.all_mutex); + goto END_attach; + } + + /* pathname get (use cmn_err) */ + if (ddi_pathname(dip, &wk_pathname[0]) != 0) { + sprintf(&statep->pathname[0], "%s(%s%d)", + &wk_pathname[0], ddi_get_name(dip), instance); + } else { + sprintf(&statep->pathname[0], "(%s%d)", + ddi_get_name(dip), instance); + } + + /* retain dip in soft state */ + statep->dip = dip; + + /* create minor node */ + sprintf(wk_pathname, "%s%d", ddi_get_name(dip), instance); + if (ddi_create_minor_node(dip, wk_pathname, S_IFCHR, instance, + DDI_PSEUDO, 0) == DDI_FAILURE) { + SC_DBG_DRV_TRACE(TC_ATTACH|TC_ERR, __LINE__, + "attach ", 8); + cmn_err(CE_WARN, + "%s: scf_attach: " + "ddi_create_minor_node failed.\n", + scf_driver_name); + goto ATTACH_failed; + } + statep->resource_flag |= S_DID_MNODE; + + statep->instance = instance; + + /* get configuration file */ + scf_reload_conf(statep); + + /* map SCF registers */ + if (scf_map_regs(dip, statep) != 0) { + SC_DBG_DRV_TRACE(TC_ATTACH|TC_ERR, __LINE__, + "attach ", 8); + goto ATTACH_failed; + } + + /* add interrupt handler */ + if (ddi_add_intr(dip, 0, NULL, 0, &scf_intr, (caddr_t)statep) != + DDI_SUCCESS) { + SC_DBG_DRV_TRACE(TC_ATTACH|TC_ERR, __LINE__, + "attach ", 8); + cmn_err(CE_WARN, + "%s: scf_attach: ddi_add_intr failed.\n", + scf_driver_name); + goto ATTACH_failed; + } + statep->resource_flag |= S_DID_INTR; + + SCF_DBG_IOMP_ADD(statep); + + /* DSCP inteface initialize */ + if (!(scf_comtbl.resource_flag & DID_DSCPINIT)) { + scf_dscp_init(); + scf_comtbl.resource_flag |= DID_DSCPINIT; + } + + /* permit SCF intr */ + scf_permit_intr(statep, 1); + + /* first attach */ + if ((scf_comtbl.scf_path_p == NULL) && + (scf_comtbl.scf_exec_p == NULL)) { + /* no execute scf device */ + if (scf_comtbl.watchdog_after_resume) { + scf_comtbl.alive_running = SCF_ALIVE_START; + scf_comtbl.watchdog_after_resume = 0; + } + scf_chg_scf(statep, PATH_STAT_ACTIVE); + scf_comtbl.scf_pchg_event_sub = EVENT_SUB_PCHG_WAIT; + scf_next_cmd_check(statep); + } else { + /* exists execute scf device */ + scf_chg_scf(statep, PATH_STAT_STANDBY); + } + scf_comtbl.attach_count++; + + ddi_report_dev(dip); + + /* Collect the timers which need to be stopped */ + tm_stop_cnt = scf_timer_stop_collect(save_tmids, + SCF_TIMERCD_MAX); + + /* Unlock driver mutex */ + mutex_exit(&scf_comtbl.all_mutex); + + /* Timer stop */ + if (tm_stop_cnt != 0) { + scf_timer_untimeout(save_tmids, SCF_TIMERCD_MAX); + } + + ret = DDI_SUCCESS; + goto END_attach; + + case DDI_RESUME: + SCFDBGMSG(SCF_DBGFLAG_DDI, "resume proc"); + /* get softstate */ + if ((statep = ddi_get_soft_state(scfstate, instance)) == NULL) { + SC_DBG_DRV_TRACE(TC_ATTACH|TC_ERR, __LINE__, + "attach ", 8); + cmn_err(CE_WARN, + "%s: scf_attach: ddi_get_soft_state failed.\n", + scf_driver_name); + + /* Unlock driver mutex */ + mutex_exit(&scf_comtbl.all_mutex); + goto END_attach; + } + + /* Transmitting stop release by SUSPEND */ + scf_comtbl.scf_suspend_sendstop = 0; + /* queue update */ + scf_del_queue(statep); + if ((statep->old_path_status == PATH_STAT_ACTIVE) || + (statep->old_path_status == PATH_STAT_STANDBY)) { + if ((scf_comtbl.scf_path_p == NULL) && + (scf_comtbl.scf_exec_p == NULL)) { + scf_comtbl.suspend_flag = 0; + if (scf_comtbl.watchdog_after_resume) { + scf_comtbl.alive_running = + SCF_ALIVE_START; + scf_comtbl.watchdog_after_resume = 0; + } + /* permit SCF intr */ + scf_permit_intr(statep, 1); + scf_chg_scf(statep, PATH_STAT_ACTIVE); + scf_comtbl.scf_pchg_event_sub = + EVENT_SUB_PCHG_WAIT; + scf_next_cmd_check(statep); + scf_comtbl.scf_report_event_sub = + EVENT_SUB_REPORT_RUN_WAIT; + } else { + /* exists execute SCF device */ + scf_chg_scf(statep, PATH_STAT_STANDBY); + /* permit SCF intr */ + scf_permit_intr(statep, 1); + } + } else { + scf_chg_scf(statep, statep->old_path_status); + } + + /* Collect the timers which need to be stopped */ + tm_stop_cnt = scf_timer_stop_collect(save_tmids, + SCF_TIMERCD_MAX); + + /* Unlock driver mutex */ + mutex_exit(&scf_comtbl.all_mutex); + + /* Timer stop */ + if (tm_stop_cnt != 0) { + scf_timer_untimeout(save_tmids, SCF_TIMERCD_MAX); + } + + ret = DDI_SUCCESS; + goto END_attach; + + default: + SC_DBG_DRV_TRACE(TC_ATTACH|TC_ERR, __LINE__, "attach ", 8); + /* Unlock driver mutex */ + mutex_exit(&scf_comtbl.all_mutex); + goto END_attach; + } + +/* + * ATTACH_failed + */ + ATTACH_failed: + + scf_resource_free_dev(statep); + + if ((scf_comtbl.scf_exec_p == NULL) && + (scf_comtbl.scf_path_p == NULL) && + (scf_comtbl.scf_wait_p == NULL) && + (scf_comtbl.scf_suspend_p == NULL) && + (scf_comtbl.scf_stop_p == NULL) && + (scf_comtbl.scf_disc_p == NULL) && + (scf_comtbl.scf_err_p == NULL)) { + /* last SCF device */ + + /* DSCP interface area release */ + if (scf_comtbl.resource_flag & DID_DSCPINIT) { + scf_dscp_fini(); + scf_comtbl.resource_flag &= (~DID_DSCPINIT); + } + + /* All timer stop */ + scf_timer_all_stop(); + + /* Collect the timers which need to be stopped */ + tm_stop_cnt = + scf_timer_stop_collect(save_tmids, SCF_TIMERCD_MAX); + + /* Unlock driver mutex */ + mutex_exit(&scf_comtbl.all_mutex); + + /* Timer stop */ + if (tm_stop_cnt != 0) { + scf_timer_untimeout(save_tmids, SCF_TIMERCD_MAX); + } + + mutex_enter(&scf_comtbl.attach_mutex); + + /* destroy kstat resources */ + if (scf_comtbl.resource_flag & DID_KSTAT) { + scf_kstat_fini(); + scf_comtbl.resource_flag &= (~DID_KSTAT); + } + + mutex_exit(&scf_comtbl.attach_mutex); + } else { + /* Unlock driver mutex */ + mutex_exit(&scf_comtbl.all_mutex); + } + + ddi_soft_state_free(scfstate, instance); + +/* + * END_attach + */ + END_attach: + + SC_DBG_DRV_TRACE(TC_ATTACH|TC_OUT, __LINE__, &ret, sizeof (int)); + SCFDBGMSG1(SCF_DBGFLAG_DDI, SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +/* + * scf_detach() + * + * Description: Driver detach() entry processing. + * + */ +int +scf_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_detach() " + scf_state_t *statep; + int instance; + struct scf_cmd scf_cmd; + scf_short_buffer_t sbuf; + int ret = DDI_FAILURE; + scf_state_t *next_path = 0; + int cv_ret; + clock_t wk_time; + timeout_id_t save_tmids[SCF_TIMERCD_MAX]; + int tm_stop_cnt; + + SCFDBGMSG2(SCF_DBGFLAG_DDI, + SCF_FUNC_NAME ": start instance = %d name = %s", + ddi_get_instance(dip), ddi_get_name(dip)); + SC_DBG_DRV_TRACE(TC_DETACH|TC_IN, __LINE__, &cmd, + sizeof (ddi_detach_cmd_t)); + + if (strcmp(ddi_get_name(dip), SCF_DRIVER_NAME) == 0) { + if (cmd == DDI_DETACH) { + SCFDBGMSG(SCF_DBGFLAG_DDI, "pseudo detach proc"); + mutex_enter(&scf_comtbl.attach_mutex); + + /* get instance number */ + instance = ddi_get_instance(dip); + + /* remove minor node */ + if (scf_comtbl.resource_flag & DID_MNODE) { + ddi_remove_minor_node(dip, NULL); + scf_comtbl.resource_flag &= (~DID_MNODE); + SCFDBGMSG(SCF_DBGFLAG_DDI, + "ddi_remove_minor_node() is success"); + } + + /* soft state free */ + ddi_soft_state_free(scfstate, instance); + + scf_comtbl.scf_pseudo_p = NULL; + + mutex_exit(&scf_comtbl.attach_mutex); + } + ret = DDI_SUCCESS; + goto END_detach; + } + bzero((void *)&sbuf.b[0], SCF_S_CNT_16); + + /* Lock driver mutex */ + mutex_enter(&scf_comtbl.all_mutex); + + switch (cmd) { + case DDI_DETACH: + SCFDBGMSG(SCF_DBGFLAG_DDI, "detach proc"); + /* get instance number */ + instance = ddi_get_instance(dip); + + /* get softstate */ + if ((statep = ddi_get_soft_state(scfstate, instance)) == NULL) { + SC_DBG_DRV_TRACE(TC_DETACH|TC_ERR, __LINE__, + "detach ", 8); + cmn_err(CE_WARN, + "%s: scf_detach: ddi_get_soft_state failed.\n", + scf_driver_name); + + /* Unlock driver mutex */ + mutex_exit(&scf_comtbl.all_mutex); + goto END_detach; + } + + if ((scf_comtbl.scf_exec_p == statep) || + (scf_comtbl.scf_path_p == statep)) { + if ((next_path = scf_comtbl.scf_wait_p) == 0) { + if (scf_last_detach_mode == 0) { + /* Last deveice detach is error */ + SC_DBG_DRV_TRACE(TC_DETACH|TC_MSG, + __LINE__, "detach ", 8); + /* Unlock driver mutex */ + mutex_exit(&scf_comtbl.all_mutex); + goto END_detach; + } + } + } + + /* SCF command transmit sync stop */ + (void) scf_make_send_cmd(&scf_cmd, SCF_USE_STOP); + + scf_del_queue(statep); + scf_comtbl.attach_count--; + + /* forbid interrupt */ + scf_forbid_intr(statep); + + if (next_path) { + /* SCF path change */ + scf_comtbl.scf_wait_p = next_path->next; + scf_chg_scf(next_path, PATH_STAT_ACTIVE); + scf_comtbl.scf_pchg_event_sub = EVENT_SUB_PCHG_WAIT; + scf_next_cmd_check(next_path); + } + /* SCF command sync start */ + (void) scf_make_send_cmd(&scf_cmd, SCF_USE_START); + SCF_DBG_IOMP_DEL(statep); + + scf_resource_free_dev(statep); + + /* free resources allocated in driver */ + if ((scf_comtbl.scf_exec_p == NULL) && + (scf_comtbl.scf_path_p == NULL) && + (scf_comtbl.scf_wait_p == NULL) && + (scf_comtbl.scf_suspend_p == NULL) && + (scf_comtbl.scf_stop_p == NULL) && + (scf_comtbl.scf_disc_p == NULL) && + (scf_comtbl.scf_err_p == NULL)) { + /* last device */ + + /* DSCP interface area release */ + if (scf_comtbl.resource_flag & DID_DSCPINIT) { + scf_dscp_fini(); + scf_comtbl.resource_flag &= (~DID_DSCPINIT); + } + + /* All timer stop */ + scf_timer_all_stop(); + + /* Collect the timers which need to be stopped */ + tm_stop_cnt = scf_timer_stop_collect(save_tmids, + SCF_TIMERCD_MAX); + + /* Unlock driver mutex */ + mutex_exit(&scf_comtbl.all_mutex); + + /* Timer stop */ + if (tm_stop_cnt != 0) { + scf_timer_untimeout(save_tmids, + SCF_TIMERCD_MAX); + } + + SCF_DBG_TEST_TIMER_STOP; + + mutex_enter(&scf_comtbl.attach_mutex); + + /* destroy kstat resources */ + if (scf_comtbl.resource_flag & DID_KSTAT) { + scf_kstat_fini(); + scf_comtbl.resource_flag &= (~DID_KSTAT); + } + + mutex_exit(&scf_comtbl.attach_mutex); + } else { + /* Collect the timers which need to be stopped */ + tm_stop_cnt = scf_timer_stop_collect(save_tmids, + SCF_TIMERCD_MAX); + + /* Unlock driver mutex */ + mutex_exit(&scf_comtbl.all_mutex); + + /* Timer stop */ + if (tm_stop_cnt != 0) { + scf_timer_untimeout(save_tmids, + SCF_TIMERCD_MAX); + } + } + + /* soft state free */ + ddi_soft_state_free(scfstate, instance); + + ret = DDI_SUCCESS; + goto END_detach; + + case DDI_SUSPEND: + SCFDBGMSG(SCF_DBGFLAG_DDI, "suspend proc"); + + /* get instance number */ + instance = ddi_get_instance(dip); + + /* get softstate */ + if ((statep = ddi_get_soft_state(scfstate, instance)) == NULL) { + SC_DBG_DRV_TRACE(TC_DETACH|TC_ERR, __LINE__, + "detach ", 8); + cmn_err(CE_WARN, + "%s: scf_detach: ddi_get_soft_state failed.\n", + scf_driver_name); + + /* Unlock driver mutex */ + mutex_exit(&scf_comtbl.all_mutex); + goto END_detach; + } + + if ((scf_comtbl.scf_exec_p == statep) || + (scf_comtbl.scf_path_p == statep)) { + /* report "Shutdown start" to SCF */ + scf_comtbl.suspend_flag = 1; + + /* + * if watching cpu stop it, but set flag for + * restart after resume + */ + if (scf_comtbl.alive_running == SCF_ALIVE_START) { + scf_comtbl.watchdog_after_resume = 1; + scf_comtbl.alive_running = SCF_ALIVE_STOP; + } + scf_comtbl.scf_alive_event_sub = EVENT_SUB_ALSP_WAIT; + scf_next_cmd_check(statep); + /* SUSPEND wait state */ + wk_time = drv_usectohz(SCF_MIL2MICRO(scf_timer_value_get + (SCF_TIMERCD_CMDEND)) + ddi_get_lbolt()); + scf_comtbl.suspend_wait = 1; + while (scf_comtbl.suspend_wait != 0) { + cv_ret = cv_timedwait_sig + (&scf_comtbl.suspend_wait_cv, + &scf_comtbl.all_mutex, wk_time); + if (cv_ret == 0) { + scf_comtbl.suspend_wait = 0; + SC_DBG_DRV_TRACE(TC_KILL, __LINE__, + &scf_comtbl.suspend_wait_cv, + sizeof (kcondvar_t)); + break; + } else if (cv_ret == (-1)) { + scf_comtbl.suspend_wait = 0; + SC_DBG_DRV_TRACE(TC_DETACH|TC_ERR, + __LINE__, "detach ", 8); + break; + } + } + } + + scf_del_queue(statep); + scf_chg_scf(statep, PATH_STAT_EMPTY); + + /* forbid interrupt */ + scf_forbid_intr(statep); + + /* Collect the timers which need to be stopped */ + tm_stop_cnt = + scf_timer_stop_collect(save_tmids, SCF_TIMERCD_MAX); + + /* Unlock driver mutex */ + mutex_exit(&scf_comtbl.all_mutex); + + /* Timer stop */ + if (tm_stop_cnt != 0) { + scf_timer_untimeout(save_tmids, SCF_TIMERCD_MAX); + } + + ret = DDI_SUCCESS; + goto END_detach; + + default: + SC_DBG_DRV_TRACE(TC_DETACH|TC_ERR, __LINE__, "detach ", 8); + /* Unlock driver mutex */ + mutex_exit(&scf_comtbl.all_mutex); + break; + + } + +/* + * END_detach + */ + END_detach: + + SC_DBG_DRV_TRACE(TC_DETACH|TC_OUT, __LINE__, &ret, sizeof (int)); + SCFDBGMSG1(SCF_DBGFLAG_DDI, SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +/* + * scf_resource_free_dev() + * + * Description: Release processing of device resources. + * + */ +void +scf_resource_free_dev(scf_state_t *statep) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_resource_free_dev() " + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_DDI, SCF_FUNC_NAME ": start"); + + /* remove intr */ + if (statep->resource_flag & S_DID_INTR) { + ddi_remove_intr(statep->dip, 0, scf_comtbl.iblock_cookie); + statep->resource_flag &= (~S_DID_INTR); + SCFDBGMSG(SCF_DBGFLAG_DDI, "ddi_remove_intr() is success"); + } + + /* remove minor node */ + if (statep->resource_flag & S_DID_MNODE) { + ddi_remove_minor_node(statep->dip, NULL); + statep->resource_flag &= (~S_DID_MNODE); + SCFDBGMSG(SCF_DBGFLAG_DDI, + "ddi_remove_minor_node() is success"); + } + + /* unmap SCF registers */ + scf_unmap_regs(statep); + + SCFDBGMSG(SCF_DBGFLAG_DDI, SCF_FUNC_NAME ": end"); +} + + +/* + * scf_getinfo() + * + * Description: Driver getinfo() entry processing. + * + */ +/* ARGSUSED */ +int +scf_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_getinfo() " + scf_state_t *statep; + int ret; + int instance; + + SCFDBGMSG1(SCF_DBGFLAG_OPCLS, SCF_FUNC_NAME ": start instance = %d", + getminor((dev_t)arg)); + + instance = getminor((dev_t)arg); + if (SCF_CHECK_INSTANCE(instance)) { + instance = SCF_USER_INSTANCE; + } + + switch (cmd) { + case DDI_INFO_DEVT2INSTANCE: + *resultp = (void *)(uintptr_t)instance; + ret = DDI_SUCCESS; + goto END_getinfo; + case DDI_INFO_DEVT2DEVINFO: + statep = (scf_state_t *)ddi_get_soft_state(scfstate, instance); + if (statep != NULL) { + *resultp = statep->dip; + ret = DDI_SUCCESS; + goto END_getinfo; + } + default: + SC_DBG_DRV_TRACE(TC_GETINFO|TC_ERR, __LINE__, "getinfo ", 8); + *resultp = NULL; + ret = DDI_FAILURE; + } + +/* + * END_getinfo + */ + END_getinfo: + + SC_DBG_DRV_TRACE(TC_GETINFO|TC_OUT, __LINE__, &ret, sizeof (int)); + SCFDBGMSG1(SCF_DBGFLAG_OPCLS, SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +/* + * scf_reload_conf() + * + * Description: Read in processing of driver configuration file. + * + */ +void +scf_reload_conf(scf_state_t *statep) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_reload_conf() " + dev_info_t *dip; + int get_prm; + char *wkcharp = NULL; + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_DDI, SCF_FUNC_NAME ": start"); + + if (scf_comtbl.reload_conf_flag == FLAG_OFF) { + dip = statep->dip; + + /* + * get driver control mode value + */ + + /* SCFHALT after processing mode */ + get_prm = ddi_prop_get_int(DDI_DEV_T_ANY, dip, + (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM), + "scf_halt_proc_mode", (-1)); + if (get_prm != (-1)) { + scf_halt_proc_mode = (uint_t)get_prm; + } + + /* + * get alive check function parameter value + */ + /* Operation of alive check function */ + if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, + (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM), + "scf-alive-check-function", &wkcharp) == + DDI_PROP_SUCCESS) { + if (strcmp(wkcharp, SCF_ALIVE_FUNC_ON) == 0) { + scf_comtbl.alive_running = SCF_ALIVE_START; + } else if (strcmp(wkcharp, SCF_ALIVE_FUNC_OFF) == 0) { + scf_comtbl.alive_running = SCF_ALIVE_STOP; + } + ddi_prop_free(wkcharp); + } + + /* Interrupt interval time */ + get_prm = ddi_prop_get_int(DDI_DEV_T_ANY, dip, + (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM), + "scf-alive-interval-time", (-1)); + if (get_prm != (-1)) { + SCF_MIN_TO_10SEC(get_prm); + scf_alive_interval_time = (uchar_t)get_prm; + } + /* Monitoring timeout */ + get_prm = ddi_prop_get_int(DDI_DEV_T_ANY, dip, + (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM), + "scf-alive-monitor-time", (-1)); + if (get_prm != (-1)) { + SCF_MIN_TO_10SEC(get_prm); + scf_alive_monitor_time = (uchar_t)get_prm; + } + /* Panic timeout */ + get_prm = ddi_prop_get_int(DDI_DEV_T_ANY, dip, + (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM), + "scf-alive-panic-time", (-1)); + if (get_prm != (-1)) { + SCF_MIN_TO_10SEC(get_prm); + scf_alive_panic_time = (ushort_t)get_prm; + } + + if ((scf_alive_interval_time < INTERVAL_TIME_MIN) || + (scf_alive_interval_time > INTERVAL_TIME_MAX) || + (scf_alive_monitor_time < MONITOR_TIME_MIN) || + (scf_alive_monitor_time > MONITOR_TIME_MAX) || + ((scf_alive_panic_time != PANIC_TIME_NONE) && + (scf_alive_panic_time < PANIC_TIME_MIN)) || + (scf_alive_panic_time > PANIC_TIME_MAX)) { + scf_alive_interval_time = INTERVAL_TIME_DEF; + scf_alive_monitor_time = MONITOR_TIME_DEF; + scf_alive_panic_time = PANIC_TIME_DEF; + } + if (scf_alive_interval_time >= scf_alive_monitor_time) { + scf_alive_monitor_time = + scf_alive_interval_time + MONITOR_TIME_CORRECT; + } + + /* + * get system interface control value + */ + + /* SCFIOCRDCTRL wait timer value */ + get_prm = ddi_prop_get_int(DDI_DEV_T_ANY, dip, + (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM), + "scf_rdctrl_sense_wait", (-1)); + if ((get_prm >= SCF_SEC2MICRO(1)) && + (get_prm <= SCF_SEC2MICRO(120))) { + scf_rdctrl_sense_wait = (uint_t)get_prm; + } + + /* Buff full wait retry timer value */ + get_prm = ddi_prop_get_int(DDI_DEV_T_ANY, dip, + (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM), + "scf_buf_ful_rtime", (-1)); + if (get_prm >= 0) { + scf_buf_ful_rtime = (uint_t)get_prm; + } + + /* RCI busy wait retry timer value */ + get_prm = ddi_prop_get_int(DDI_DEV_T_ANY, dip, + (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM), + "scf_rci_busy_rtime", (-1)); + if (get_prm >= 0) { + scf_rci_busy_rtime = (uint_t)get_prm; + } + + /* Tx sum retry counter */ + get_prm = ddi_prop_get_int(DDI_DEV_T_ANY, dip, + (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM), + "scf_tesum_rcnt", (-1)); + if (get_prm >= 0) { + scf_tesum_rcnt = (uint_t)get_prm; + } + + /* Rx sum retry counter */ + get_prm = ddi_prop_get_int(DDI_DEV_T_ANY, dip, + (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM), + "scf_resum_rcnt", (-1)); + if (get_prm >= 0) { + scf_resum_rcnt = (uint_t)get_prm; + } + + /* Command to retry counter */ + get_prm = ddi_prop_get_int(DDI_DEV_T_ANY, dip, + (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM), + "scf_cmd_to_rcnt", (-1)); + if (get_prm >= 0) { + scf_cmd_to_rcnt = (uint_t)get_prm; + } + + /* Command device busy retry counter */ + get_prm = ddi_prop_get_int(DDI_DEV_T_ANY, dip, + (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM), + "scf_devbusy_wait_rcnt", (-1)); + if (get_prm >= 0) { + scf_devbusy_wait_rcnt = (uint_t)get_prm; + } + + /* SCF online retry counter */ + get_prm = ddi_prop_get_int(DDI_DEV_T_ANY, dip, + (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM), + "scf_online_wait_rcnt", (-1)); + if (get_prm >= 0) { + scf_online_wait_rcnt = (uint_t)get_prm; + } + + /* SCF path change retry counter */ + get_prm = ddi_prop_get_int(DDI_DEV_T_ANY, dip, + (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM), + "scf_path_change_max", (-1)); + if (get_prm >= 0) { + scf_path_change_max = (uint_t)get_prm; + } + + /* + * get timer control value + */ + + /* SCF command busy watch timer value */ + get_prm = ddi_prop_get_int(DDI_DEV_T_ANY, dip, + (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM), + "scf_devbusy_wait_time", (-1)); + if (get_prm >= 0) { + scf_devbusy_wait_time = (uint_t)get_prm; + } + + /* SCF command completion watch value */ + get_prm = ddi_prop_get_int(DDI_DEV_T_ANY, dip, + (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM), + "scf_cmdend_wait_time", (-1)); + if (get_prm >= 0) { + scf_cmdend_wait_time = (uint_t)get_prm; + } + + /* SCF online watch timer value */ + get_prm = ddi_prop_get_int(DDI_DEV_T_ANY, dip, + (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM), + "scf_online_wait_time", (-1)); + if (get_prm >= 0) { + scf_online_wait_time = (uint_t)get_prm; + } + + /* Next receive wait timer value */ + get_prm = ddi_prop_get_int(DDI_DEV_T_ANY, dip, + (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM), + "scf_rxbuff_wait_time", (-1)); + if (get_prm >= 0) { + scf_rxbuff_wait_time = (uint_t)get_prm; + } + + /* DSCP interface TxACK watch timer value */ + get_prm = ddi_prop_get_int(DDI_DEV_T_ANY, dip, + (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM), + "scf_dscp_ack_wait_time", (-1)); + if (get_prm >= 0) { + scf_dscp_ack_wait_time = (uint_t)get_prm; + } + + /* DSCP interface TxEND watch timer value */ + get_prm = ddi_prop_get_int(DDI_DEV_T_ANY, dip, + (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM), + "scf_dscp_end_wait_time", (-1)); + if (get_prm >= 0) { + scf_dscp_end_wait_time = (uint_t)get_prm; + } + + /* DSCP interface busy watch timer value */ + get_prm = ddi_prop_get_int(DDI_DEV_T_ANY, dip, + (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM), + "scf_dscp_txbusy_time", (-1)); + if (get_prm >= 0) { + scf_dscp_txbusy_time = (uint_t)get_prm; + } + + /* DSCP interface callback timer value */ + get_prm = ddi_prop_get_int(DDI_DEV_T_ANY, dip, + (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM), + "scf_dscp_callback_time", (-1)); + if (get_prm >= 0) { + scf_dscp_callback_time = (uint_t)get_prm; + } + + /* Timer value set */ + scf_timer_init(); + + scf_comtbl.reload_conf_flag = FLAG_ON; + } + + SCFDBGMSG(SCF_DBGFLAG_DDI, SCF_FUNC_NAME ": end"); +} diff --git a/usr/src/uts/sun4u/opl/io/scfd/scfd.conf b/usr/src/uts/sun4u/opl/io/scfd/scfd.conf new file mode 100644 index 0000000000..56f2c038f2 --- /dev/null +++ b/usr/src/uts/sun4u/opl/io/scfd/scfd.conf @@ -0,0 +1,52 @@ +# +# 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 +# +# +# All Rights Reserved, Copyright (c) FUJITSU LIMITED 2006 +# +#pragma ident "%Z%%M% %I% %E% SMI" + +# Begin (do not edit) +name="scfd" parent="pseudo" instance=200; +ddi-forceattach=1; +interrupt-priorities=0x9; +# End (do not edit) + +# When scf-alive-check-function is set to "on", starts the Alive check +# function by XSCF. If XSCF detected abnormality of the domain, OS panic of +# the domain is executed. The default is "off". +# "on" : Starts the Alive check function +# "off" : Stops the Alive check function +scf-alive-check-function="off"; + +# You can set the Alive check interval time for the Alive check function. +# Specify this parameter in minutes. The range is 1 - 10 minutes. +# The default is 2 minutes. +scf-alive-interval-time=2; + +# You can set the Alive check monitoring time for the Alive check function. +# Specify this parameter in minutes. The range is 3 - 30 minutes. +# The default is 6 minutes. +scf-alive-monitor-time=6; + +# You can set the monitoring time for the OS panic monitoring of Alive +# check function. Specify this parameter in minutes. The range is +# 30 - 360 minutes. The default is 30 minutes. +scf-alive-panic-time=30; diff --git a/usr/src/uts/sun4u/opl/io/scfd/scfdebug.c b/usr/src/uts/sun4u/opl/io/scfd/scfdebug.c new file mode 100644 index 0000000000..6eab9238bf --- /dev/null +++ b/usr/src/uts/sun4u/opl/io/scfd/scfdebug.c @@ -0,0 +1,2028 @@ +/* + * 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 + */ +/* + * All Rights Reserved, Copyright (c) FUJITSU LIMITED 2006 + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/ksynch.h> +#include <sys/types.h> +#include <sys/file.h> +#include <sys/conf.h> +#include <sys/cmn_err.h> +#include <sys/kmem.h> +#include <sys/errno.h> +#include <sys/ddi.h> +#include <sys/sunddi.h> + +#include <sys/scfd/scfparam.h> +#include <sys/scfd/scfdscp.h> + +#ifdef DEBUG +/* + * Debug control value and flag + */ +uint_t scf_debug_test_sys_int_flag = SCF_DBF_SYS_INTR_OFF; +uint_t scf_debug_test_rxbuff_nosum_check_flag = SCF_DBF_RXBUFF_NOSUM_CHECK_OFF; +uint_t scf_debug_test_sys_event_flag = SCF_DBF_SYS_EVENT_OFF; +uint_t scf_debug_test_sys_poff_flag = SCF_DBF_SYS_POFF_OFF; +uint_t scf_debug_test_dscp_int_flag = SCF_DBF_DSCP_INT_OFF; +uint_t scf_debug_test_cmdr_busy = SCF_DBC_CMDR_BUSY_CLEAR; +uint_t scf_debug_test_cmdexr_busy = SCF_DBC_CMDEXR_BUSY_CLEAR; +uint_t scf_debug_test_path_check = SCF_DBC_PATH_CHECK_CLEAR; +uint_t scf_debug_test_path_check_rtn = SCF_DBC_PATH_CHECK_RTN_CLEAR; +uint_t scf_debug_test_offline_check = SCF_DBC_OFFLINE_CHECK_CLEAR; +uint_t scf_debug_test_offline_check_rtn = SCF_DBC_OFFLINE_CHECK_RTN_CLEAR; +uint_t scf_debug_test_dscp_call_flag = SCF_DBF_DSCP_CALL_OFF; +uint_t scf_debug_test_osescf_call_flag = SCF_DBF_OSESCF_CALL_OFF; + +uint_t scf_no_make_sum_s = SCF_DBF_NO_MAKE_SUM_S_OFF; +uint_t scf_no_make_sum_l = SCF_DBF_NO_MAKE_SUM_L_OFF; + +uint_t scf_debug_nofirm_sys = SCF_DBF_NOFIRM_SYS_OFF; +uint_t scf_debug_scfint_time = SCF_DBT_SCFINT_TIME_100MS; +uint_t scf_debug_nofirm_dscp = SCF_DBF_NOFIRM_DSCP_OFF; +uint_t scf_debug_idbcint_time = SCF_DBT_IDBCINT_TIME_100MS; +uint_t scf_debug_test_dscp_loopback = SCF_DBF_DSCP_LOOPBACK_OFF; +uint_t scf_debug_nooffline_check = SCF_DBF_NOOFFLINE_CHECK_OFF; +uint_t scf_debug_no_dscp_path = SCF_DBF_NO_DSCP_PATH_OFF; +uint_t scf_debug_no_alive = SCF_DBF_NO_ALIVE_OFF; +uint_t scf_debug_norxsum_check = SCF_DBF_NORXSUM_CHECK_OFF; +uint_t scf_debug_no_int_reason = SCF_DBF_NO_INT_REASON_OFF; + +uint_t scf_debug_no_device = SCF_DBF_NO_DEVICE_OFF; + +scf_regs_t *scf_debug_scf_regs; +scf_regs_c_t *scf_debug_scf_regs_c; +scf_dscp_sram_t *scf_debug_scf_dscp_sram; +scf_sys_sram_t *scf_debug_scf_sys_sram; +scf_interface_t *scf_debug_scf_interface; +scf_if_drvtrc_t *scf_debug_scf_reg_drvtrc; + +scf_regs_t scf_debug_scf_regs_tbl; +scf_regs_c_t scf_debug_scf_regs_c_tbl; +scf_dscp_sram_t scf_debug_scf_dscp_sram_tbl; +scf_sys_sram_t scf_debug_scf_sys_sram_tbl; +scf_interface_t scf_debug_scf_interface_tbl; +struct { + uint8_t data[0x00001000]; + +} scf_debug_scf_reg_drvtrc_tbl; + +struct { + uint16_t STATUS; + uint16_t INT_ST; + uint32_t STATUS_ExR; + uint32_t rxsize; + uint32_t RDATA0; + uint32_t RDATA1; + uint32_t RDATA2; + uint32_t RDATA3; + uint32_t POFF_FACTOR; + uint32_t EVENT[8 * 4]; +} scf_debug_test_sys_int_tbl; + +struct { + uint8_t DSR; + uint8_t rev01; + uint16_t TxDSR_C_FLAG; + uint16_t TxDSR_OFFSET; + uint32_t rxsize; + uint16_t RxDCR_C_FLAG; + uint16_t RxDCR_OFFSET; + uint32_t RxDCR_LENGTH; + uint32_t rsv14; + uint32_t rsv18; +} scf_debug_test_dscp_int_tbl; + +uint32_t scf_debug_rdata[4] = {0, 0, 0, 0}; + +timeout_id_t scf_debug_test_intr_id = 0; +timeout_id_t scf_debug_test_alive_id = 0; +uint_t scf_debug_test_alive_flag = FLAG_OFF; + +/* + * Function list + */ +int scf_debug_cmdthrough(intptr_t arg, int mode); +int scf_debug_test(intptr_t arg, int mode); +void scf_debug_test_intr_tout(void *arg); +void scf_debug_test_intr(scf_state_t *statep); +void scf_debug_test_intr_scfint(scf_state_t *statep); +void scf_debug_test_intr_cmdend(scf_state_t *statep); +void scf_debug_test_intr_poff(void); +void scf_debug_test_dsens(struct scf_cmd *scfcmdp, scf_int_reason_t *int_rp, + int len); +void scf_debug_test_intr_dscp_dsr(scf_state_t *statep); +void scf_debug_test_intr_dscp_rxtx(scf_state_t *statep, uint8_t dsr); +void scf_debug_test_alive_start(scf_state_t *statep); +void scf_debug_test_alive_stop(scf_state_t *statep); +void scf_debug_test_alive_intr_tout(void *arg); +void scf_debug_test_send_cmd(struct scf_state *statep, + struct scf_cmd *scfcmdp); +void scf_debug_test_txreq_send(scf_state_t *statep, scf_dscp_dsc_t *dsc_p); +void scf_debug_test_event_handler(scf_event_t mevent, void *arg); +void scf_debug_test_timer_stop(void); +void scf_debug_test_map_regs(scf_state_t *statep); +void scf_debug_test_unmap_regs(scf_state_t *statep); + +/* + * External function + */ +extern int scf_dscp_init(void); +extern void scf_dscp_fini(void); +extern void scf_dscp_start(uint32_t factor); +extern void scf_dscp_stop(uint32_t factor); +extern int scf_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); +extern int scf_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); + +extern int scf_fmem_start(int s_bd, int t_bd); +extern int scf_fmem_end(void); +extern int scf_fmem_cancel(void); + +int +scf_debug_cmdthrough(intptr_t arg, int mode) +{ +#define SCF_FUNC_NAME "scf_debug_cmdthrough() " + int ret = 0; + scfcmdthrough_t *scfcmdthrough_p = NULL; + struct scf_cmd scf_cmd; + + SCFDBGMSG(SCF_DBGFLAG_DBG, SCF_FUNC_NAME ": start"); + + scfcmdthrough_p = + kmem_zalloc((size_t)(sizeof (scfcmdthrough_t)), + KM_SLEEP); + if (ddi_copyin((void *)arg, (void *)scfcmdthrough_p, + sizeof (scfcmdthrough_t), mode) != 0) { + SC_DBG_DRV_TRACE(TC_ERR, __LINE__, "dbg_cmdt", 8); + ret = EFAULT; + goto END_cmdthrough; + } + + mutex_enter(&scf_comtbl.all_mutex); + + switch (scfcmdthrough_p->mode) { + case SCF_CMDTHROUGH_START: + scf_comtbl.debugxscf_flag = 1; + + mutex_exit(&scf_comtbl.all_mutex); + break; + + case SCF_CMDTHROUGH_STOP: + scf_comtbl.debugxscf_flag = 0; + + mutex_exit(&scf_comtbl.all_mutex); + break; + + case SCF_CMDTHROUGH_CMD: + if (!scf_comtbl.debugxscf_flag) { + SC_DBG_DRV_TRACE(TC_ERR, __LINE__, "dbg_cmdt", 8); + mutex_exit(&scf_comtbl.all_mutex); + ret = EINVAL; + goto END_cmdthrough; + } + scf_cmd.cmd = (unsigned char)scfcmdthrough_p->code; + scf_cmd.subcmd = (unsigned char)(scfcmdthrough_p->code >> 8); + + switch (scfcmdthrough_p->cmdtype) { + case SCF_CMDTHROUGH_TYPE_NN: + case SCF_CMDTHROUGH_TYPE_NS: + case SCF_CMDTHROUGH_TYPE_NL: + scf_cmd.scount = 0; + break; + + case SCF_CMDTHROUGH_TYPE_SN: + case SCF_CMDTHROUGH_TYPE_SS: + case SCF_CMDTHROUGH_TYPE_SL: + if (scfcmdthrough_p->sbufleng > SCF_S_CNT_16) { + SC_DBG_DRV_TRACE(TC_ERR, __LINE__, + "dbg_cmdt", 8); + mutex_exit(&scf_comtbl.all_mutex); + ret = EINVAL; + goto END_cmdthrough; + } + scf_cmd.scount = scfcmdthrough_p->sbufleng; + break; + + case SCF_CMDTHROUGH_TYPE_LN: + case SCF_CMDTHROUGH_TYPE_LS: + if (scfcmdthrough_p->sbufleng > SCF_L_CNT_MAX) { + SC_DBG_DRV_TRACE(TC_ERR, __LINE__, + "dbg_cmdt", 8); + mutex_exit(&scf_comtbl.all_mutex); + ret = EINVAL; + goto END_cmdthrough; + } + scf_cmd.scount = scfcmdthrough_p->sbufleng; + break; + + default: + SC_DBG_DRV_TRACE(TC_ERR, __LINE__, "dbg_cmdt", 8); + mutex_exit(&scf_comtbl.all_mutex); + ret = EINVAL; + goto END_cmdthrough; + } + + switch (scfcmdthrough_p->cmdtype) { + case SCF_CMDTHROUGH_TYPE_NN: + case SCF_CMDTHROUGH_TYPE_SN: + scf_cmd.flag = SCF_USE_S_BUF; + break; + + case SCF_CMDTHROUGH_TYPE_NS: + case SCF_CMDTHROUGH_TYPE_SS: + scf_cmd.flag = SCF_USE_SSBUF; + break; + + case SCF_CMDTHROUGH_TYPE_NL: + case SCF_CMDTHROUGH_TYPE_SL: + scf_cmd.flag = SCF_USE_SLBUF; + break; + + case SCF_CMDTHROUGH_TYPE_LN: + scf_cmd.flag = SCF_USE_L_BUF; + break; + + case SCF_CMDTHROUGH_TYPE_LS: + scf_cmd.flag = SCF_USE_LSBUF; + break; + } + scf_cmd.sbuf = &scfcmdthrough_p->sbuf[0]; + scf_cmd.scount = scfcmdthrough_p->sbufleng; + scf_cmd.rbuf = &scfcmdthrough_p->rbuf[0]; + scf_cmd.rcount = SCF_L_CNT_MAX; + scf_cmd.rbufleng = 0; + scf_cmd.status = 0; + + ret = scf_send_cmd_check_bufful(&scf_cmd); + + scfcmdthrough_p->rbufleng = scf_cmd.rbufleng; + scfcmdthrough_p->status = scf_cmd.status; + + mutex_exit(&scf_comtbl.all_mutex); + + if (ret != 0) { + SC_DBG_DRV_TRACE(TC_ERR, __LINE__, "dbg_cmdt", 8); + goto END_cmdthrough; + } + if (ddi_copyout((void *)scfcmdthrough_p, (void *)arg, + sizeof (scfcmdthrough_t), mode) != 0) { + SC_DBG_DRV_TRACE(TC_ERR, __LINE__, "dbg_cmdt", 8); + ret = EFAULT; + } + break; + + default: + SC_DBG_DRV_TRACE(TC_ERR, __LINE__, "dbg_cmdt", 8); + mutex_exit(&scf_comtbl.all_mutex); + ret = EINVAL; + } + +/* + * END_cmdthrough + */ + END_cmdthrough: + + if (scfcmdthrough_p) { + kmem_free((void *)scfcmdthrough_p, + (size_t)(sizeof (scfcmdthrough_t))); + } + SCFDBGMSG1(SCF_DBGFLAG_DBG, SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +int +scf_debug_test(intptr_t arg, int mode) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_debug_test() " + scf_state_t *statep; + int func_ret = 0; + int ret = 0; + + scf_scfioctest_t *test_p = NULL; + caddr_t data_addr = NULL; + caddr_t msc_dptr = NULL; + uint32_t msc_len; + uint8_t *wk_out_p; + int ii; + int jj; + + target_id_t target_id; + mkey_t mkey; + uint_t func_arg; + uint32_t data_len; + uint32_t num_sg; + mscat_gath_t *sgp = NULL; + mflush_type_t flush_type; + uint32_t op; + + uint32_t key; + uint8_t type; + uint32_t transid; + uint32_t length; + uint16_t offset_low; + uint16_t offset_hight; + int kmem_size = 0; + int kmem_size2 = 0; + timeout_id_t save_tmids[SCF_TIMERCD_MAX]; + int tm_stop_cnt; + + SCFDBGMSG(SCF_DBGFLAG_DBG, SCF_FUNC_NAME ": start"); + + test_p = kmem_zalloc((size_t)(sizeof (scf_scfioctest_t)), KM_SLEEP); + if (ddi_copyin((void *)arg, (void *)test_p, + sizeof (scf_scfioctest_t), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "ioctl ", 8); + ret = EFAULT; + goto END_test; + } + + mutex_enter(&scf_comtbl.all_mutex); + + if (scf_comtbl.scf_exec_p != NULL) { + statep = scf_comtbl.scf_exec_p; + } else if (scf_comtbl.scf_path_p != NULL) { + statep = scf_comtbl.scf_path_p; + } else if (scf_comtbl.scf_wait_p != NULL) { + statep = scf_comtbl.scf_wait_p; + } else if (scf_comtbl.scf_err_p != NULL) { + statep = scf_comtbl.scf_err_p; + } + + test_p->scf_debugxscf = scf_comtbl.debugxscf_flag; + + switch (test_p->mode & TEST_MODE_MASK_LOW) { + case TEST_NONE: + SCFDBGMSG(SCF_DBGFLAG_DBG, "TEST_NONE"); + break; + + case TEST_CONF_RESET: + SCFDBGMSG(SCF_DBGFLAG_DBG, "TEST_CONF_RESET"); + + /* Not use info */ + scf_debug_test_sys_int_flag = SCF_DBF_SYS_INTR_OFF; + scf_debug_test_rxbuff_nosum_check_flag = + SCF_DBF_RXBUFF_NOSUM_CHECK_OFF; + scf_debug_test_dscp_int_flag = SCF_DBF_DSCP_INT_OFF; + scf_debug_test_cmdr_busy = SCF_DBC_CMDR_BUSY_CLEAR; + scf_debug_test_cmdexr_busy = SCF_DBC_CMDEXR_BUSY_CLEAR; + scf_debug_test_path_check = SCF_DBC_PATH_CHECK_CLEAR; + scf_debug_test_path_check_rtn = SCF_DBC_PATH_CHECK_RTN_CLEAR; + scf_debug_test_offline_check = SCF_DBC_OFFLINE_CHECK_CLEAR; + scf_debug_test_offline_check_rtn = + SCF_DBC_OFFLINE_CHECK_RTN_CLEAR; + scf_debug_test_dscp_call_flag = SCF_DBF_DSCP_CALL_OFF; + scf_debug_test_osescf_call_flag = SCF_DBF_OSESCF_CALL_OFF; + break; + + case TEST_CONF_DEBUG_MSG: + SCFDBGMSG(SCF_DBGFLAG_DBG, "TEST_CONF_DEBUG_MSG"); + + /* + * IN: + * info[0] : trace massege flag + */ + scf_trace_msg_flag = test_p->info[0]; + break; + + case TEST_CONF_CMD_BUSY: + SCFDBGMSG(SCF_DBGFLAG_DBG, "TEST_CONF_CMD_BUSY"); + + /* + * IN: + * info[0] : command busy count + * info[1] : command ex busy count + */ + scf_debug_test_cmdr_busy = test_p->info[0]; + scf_debug_test_cmdexr_busy = test_p->info[1]; + break; + + case TEST_CONF_SCF_PATH: + SCFDBGMSG(SCF_DBGFLAG_DBG, "TEST_CONF_SCF_PATH"); + + /* + * IN: + * info[0] : scf_path_check count + * info[1] : scf_path_check return + * info[2] : scf_offline_check count + * info[3] : scf_offline_check return + */ + scf_debug_test_path_check = test_p->info[0]; + scf_debug_test_path_check_rtn = test_p->info[1]; + scf_debug_test_offline_check = test_p->info[2]; + scf_debug_test_offline_check_rtn = test_p->info[3]; + break; + + case TEST_CONF_DSCP_LOOPBACK: + SCFDBGMSG(SCF_DBGFLAG_DBG, "TEST_CONF_DSCP_LOOPBACK"); + + /* + * IN: + * info[0] : loopback mode + */ + scf_debug_test_dscp_loopback = + (test_p->info[0]) ? + SCF_DBF_DSCP_LOOPBACK_ON : SCF_DBF_DSCP_LOOPBACK_OFF; + break; + + case TEST_INT_SYS: + SCFDBGMSG(SCF_DBGFLAG_DBG, "TEST_INT_SYS"); + + /* + * IN: + * info[0] : STR/ISR register + * info[1] : STExR register + * info[2] : receive data size + * info[3] : RxDR register 0 + * info[4] : RxDR register 1 + * info[5] : RxDR register 2 + * info[6] : RxDR register 3 + */ + if (scf_debug_scfint_time != 0) { + if (scf_debug_test_sys_int_flag == + SCF_DBF_SYS_INTR_OFF) { + if (statep != NULL) { + scf_debug_test_sys_int_flag = + SCF_DBF_SYS_INTR_ON; + + scf_debug_test_sys_int_tbl.STATUS = + (uint16_t) + (test_p->info[0] >> 16); + scf_debug_test_sys_int_tbl.INT_ST |= + (uint16_t)test_p->info[0]; + scf_debug_test_sys_int_tbl.STATUS_ExR = + test_p->info[1]; + scf_debug_test_sys_int_tbl.rxsize = + test_p->info[2]; + scf_debug_test_sys_int_tbl.RDATA0 = + test_p->info[3]; + scf_debug_test_sys_int_tbl.RDATA1 = + test_p->info[4]; + scf_debug_test_sys_int_tbl.RDATA2 = + test_p->info[5]; + scf_debug_test_sys_int_tbl.RDATA3 = + test_p->info[6]; + + if (scf_debug_test_intr_id == 0) { + scf_debug_test_intr_id = + timeout((void (*)())scf_debug_test_intr_tout, + (void *)statep, + drv_usectohz(SCF_MIL2MICRO(scf_debug_scfint_time))); + } + } else { + SC_DBG_DRV_TRACE(TC_ERR, __LINE__, + "dbg_test", 8); + ret = EIO; + } + } else { + SC_DBG_DRV_TRACE(TC_ERR, __LINE__, + "dbg_test", 8); + ret = EBUSY; + } + } + break; + + case TEST_INT_SYS_POFF: + SCFDBGMSG(SCF_DBGFLAG_DBG, "TEST_INT_SYS_POFF"); + + /* + * IN: + * info[0] : POFF factor + */ + if (scf_debug_test_sys_poff_flag == SCF_DBF_SYS_POFF_OFF) { + if (statep != NULL) { + scf_debug_test_sys_poff_flag = + SCF_DBF_SYS_POFF_ON; + + scf_debug_test_sys_int_tbl.POFF_FACTOR = + test_p->info[0]; + } else { + SC_DBG_DRV_TRACE(TC_ERR, __LINE__, + "dbg_test", 8); + ret = EIO; + } + } else { + SC_DBG_DRV_TRACE(TC_ERR, __LINE__, "dbg_test", 8); + ret = EBUSY; + } + break; + + case TEST_INT_SYS_EVENT: + SCFDBGMSG(SCF_DBGFLAG_DBG, "TEST_INT_SYS_EVENT"); + + /* + * IN: + * info[0] - info[7] : Event 0 + * info[8] - info[15] : Event 1 + * info[16] - info[23] : Event 2 + * info[24] - info[31] : Event 3 + */ + if (scf_debug_test_sys_event_flag == FLAG_OFF) { + if (statep != NULL) { + scf_debug_test_sys_event_flag = + SCF_DBF_SYS_EVENT_ON; + + for (ii = 0; ii < TEST_INFO_MAX; ii++) { + scf_debug_test_sys_int_tbl.EVENT[ii] = + test_p->info[ii]; + } + } else { + SC_DBG_DRV_TRACE(TC_ERR, __LINE__, + "dbg_test", 8); + ret = EIO; + } + } else { + SC_DBG_DRV_TRACE(TC_ERR, __LINE__, "dbg_test", 8); + ret = EBUSY; + } + break; + + case TEST_INT_DSCP: + SCFDBGMSG(SCF_DBGFLAG_DBG, "TEST_INT_DSCP"); + + /* + * IN: + * info[0] : DSR/ISR register + * info[1] : TxDSR_C_FLAG/TxDSR_OFFSET register + * info[2] : RxDCR_C_FLAG/RxDCR_OFFSET register + * info[3] : RxDCR_LENGTH register + */ + if (scf_debug_idbcint_time != 0) { + if (scf_debug_test_dscp_int_flag == + SCF_DBF_DSCP_INT_OFF) { + if (statep != NULL) { + scf_debug_test_dscp_int_flag = SCF_DBF_DSCP_INT_ON; + scf_debug_test_sys_int_flag = SCF_DBF_SYS_INTR_ON; + + scf_debug_test_dscp_int_tbl.DSR = (uint8_t)(test_p->info[0] >> 16); + scf_debug_test_sys_int_tbl.INT_ST |= (uint16_t)test_p->info[0]; + scf_debug_test_dscp_int_tbl.TxDSR_C_FLAG = + (uint16_t)(test_p->info[1] >> 16); + scf_debug_test_dscp_int_tbl.TxDSR_OFFSET = + (uint16_t)test_p->info[1]; + scf_debug_test_dscp_int_tbl.RxDCR_C_FLAG = + (uint16_t)(test_p->info[2] >> 16); + + offset_low = SCF_TXBUFFSIZE * SCF_TX_SRAM_MAXCOUNT / DSC_OFFSET_CONVERT; + offset_hight = offset_low + + SCF_RXBUFFSIZE * SCF_RX_SRAM_MAXCOUNT / DSC_OFFSET_CONVERT; + if ((test_p->info[2] >= offset_low) && + (test_p->info[2] < offset_hight)) { + scf_debug_test_dscp_int_tbl.RxDCR_OFFSET = + (uint16_t)test_p->info[2]; + } else { + scf_debug_test_dscp_int_tbl.RxDCR_OFFSET = offset_low; + } + scf_debug_test_dscp_int_tbl.RxDCR_LENGTH = test_p->info[3]; + + if ((scf_debug_test_dscp_int_tbl.RxDCR_OFFSET >= offset_low) && + (scf_debug_test_dscp_int_tbl.RxDCR_LENGTH != 0)) { + /* Data copy to SRAM */ + ii = scf_debug_test_dscp_int_tbl.RxDCR_OFFSET * + DSC_OFFSET_CONVERT; + wk_out_p = + (uint8_t *)&statep->scf_dscp_sram->DATA[ii]; + for (ii = 0; ii < scf_debug_test_dscp_int_tbl.RxDCR_LENGTH; + ii++, wk_out_p++) { + SCF_DDI_PUT8(statep, statep->scf_dscp_sram_handle, + wk_out_p, (uint8_t)ii); + } + } + + if (scf_debug_test_intr_id == 0) { + scf_debug_test_intr_id = + timeout((void (*)())scf_debug_test_intr_tout, + (void *)statep, + drv_usectohz(SCF_MIL2MICRO(scf_debug_idbcint_time))); + } + } else { + SC_DBG_DRV_TRACE(TC_ERR, __LINE__, + "dbg_test", 8); + ret = EIO; + } + } else { + SC_DBG_DRV_TRACE(TC_ERR, __LINE__, + "dbg_test", 8); + ret = EBUSY; + } + } + break; + + case TEST_SYS_CALL_INT: + SCFDBGMSG(SCF_DBGFLAG_DBG, "TEST_SYS_CALL_INT"); + + /* Not use info */ + if (scf_debug_scfint_time != 0) { + if (statep != NULL) { + if (scf_debug_test_intr_id == 0) { + scf_debug_test_intr_id = + timeout((void (*)())scf_debug_test_intr_tout, + (void *)statep, + drv_usectohz(SCF_MIL2MICRO(scf_debug_scfint_time))); + } + } else { + SC_DBG_DRV_TRACE(TC_ERR, __LINE__, + "dbg_test", 8); + ret = EIO; + } + } + break; + + case TEST_DSCP_CALL_RESET: + SCFDBGMSG(SCF_DBGFLAG_DBG, "TEST_DSCP_CALL_RESET"); + + /* Not use info */ + + scf_debug_test_dscp_call_flag = SCF_DBF_DSCP_CALL_OFF; + break; + + + case TEST_DSCP_CALL_INIT: + SCFDBGMSG(SCF_DBGFLAG_DBG, "TEST_DSCP_CALL_INIT"); + + /* + * IN: + * info[0] : target_id + * info[1] : mkey + */ + target_id = (target_id_t)test_p->info[0]; + mkey = (mkey_t)test_p->info[1]; + + /* + * scf_mb_init(target_id_t target_id, mkey_t mkey, + * void (*event_handler) (scf_event_t mevent, void *arg), + * void *arg); + */ + + func_arg = 0x01020304; + + scf_debug_test_dscp_call_flag = SCF_DBF_DSCP_CALL_ON; + + mutex_exit(&scf_comtbl.all_mutex); + if (test_p->data[0] == 1) { + func_ret = scf_mb_init(target_id, mkey, NULL, + (void *)&func_arg); + } else { + func_ret = scf_mb_init(target_id, mkey, + scf_debug_test_event_handler, + (void *)&func_arg); + } + mutex_enter(&scf_comtbl.all_mutex); + + scf_debug_test_dscp_call_flag = SCF_DBF_DSCP_CALL_OFF; + break; + + case TEST_DSCP_CALL_FINI: + SCFDBGMSG(SCF_DBGFLAG_DBG, "TEST_DSCP_CALL_FINI"); + + /* + * IN: + * info[0] : target_id + * info[1] : mkey + */ + target_id = (target_id_t)test_p->info[0]; + mkey = (mkey_t)test_p->info[1]; + + /* scf_mb_fini(target_id_t target_id, mkey_t mkey); */ + + scf_debug_test_dscp_call_flag = SCF_DBF_DSCP_CALL_ON; + + mutex_exit(&scf_comtbl.all_mutex); + func_ret = scf_mb_fini(target_id, mkey); + mutex_enter(&scf_comtbl.all_mutex); + + scf_debug_test_dscp_call_flag = SCF_DBF_DSCP_CALL_OFF; + break; + + case TEST_DSCP_CALL_PUTMSG: + SCFDBGMSG(SCF_DBGFLAG_DBG, "TEST_DSCP_CALL_PUTMSG"); + + /* + * IN: + * info[0] : target_id + * info[1] : mkey + * info[2] : data_len + * info[3] : num_sg + */ + target_id = (target_id_t)test_p->info[0]; + mkey = (mkey_t)test_p->info[1]; + data_len = (uint32_t)test_p->info[2]; + num_sg = (uint32_t)test_p->info[3]; + + /* + * scf_mb_putmsg(target_id_t target_id, mkey_t mkey, + * uint32_t data_len, uint32_t num_sg, mscat_gath_t *sgp, + * clock_t timeout); + */ + + + if (data_len != 0) { + kmem_size = data_len; + data_addr = (caddr_t)kmem_zalloc(kmem_size, KM_SLEEP); + } + if (num_sg != 0) { + kmem_size2 = sizeof (mscat_gath_t) * num_sg; + sgp = (mscat_gath_t *)kmem_zalloc(kmem_size2, KM_SLEEP); + } + + msc_dptr = data_addr; + msc_len = data_len; + for (ii = 0; ii < num_sg; ii++) { + if (msc_len != 0) { + sgp[ii].msc_dptr = msc_dptr; + if ((msc_len < 0x00000010) || + (ii == (num_sg - 1))) { + sgp[ii].msc_len = msc_len; + } else { + sgp[ii].msc_len = 0x00000010; + } + msc_len -= sgp[ii].msc_len; + for (jj = 0; jj < sgp[ii].msc_len; jj++, + msc_dptr++) { + *msc_dptr = jj; + } + } else { + sgp[ii].msc_dptr = NULL; + sgp[ii].msc_len = 0; + } + } + + scf_debug_test_dscp_call_flag = SCF_DBF_DSCP_CALL_ON; + + mutex_exit(&scf_comtbl.all_mutex); + if (test_p->data[0] == 1) { + func_ret = scf_mb_putmsg(target_id, mkey, data_len, + num_sg, NULL, 0); + } else if (test_p->data[0] == 2) { + sgp->msc_len = 0x00000010; + sgp->msc_dptr = NULL; + func_ret = scf_mb_putmsg(target_id, mkey, data_len, + num_sg, sgp, 0); + } else if (test_p->data[0] == 3) { + sgp->msc_len += 1; + func_ret = scf_mb_putmsg(target_id, mkey, data_len, + num_sg, sgp, 0); + } else { + func_ret = scf_mb_putmsg(target_id, mkey, data_len, + num_sg, sgp, 0); + } + mutex_enter(&scf_comtbl.all_mutex); + + if (data_len != 0) + bcopy((void *)data_addr, (void *)&test_p->rdata[0], + data_len); + + if (data_addr != NULL) kmem_free(data_addr, kmem_size); + if (sgp != NULL) kmem_free(sgp, kmem_size2); + + scf_debug_test_dscp_call_flag = SCF_DBF_DSCP_CALL_OFF; + break; + + case TEST_DSCP_CALL_CANGET: + SCFDBGMSG(SCF_DBGFLAG_DBG, "TEST_DSCP_CALL_CANGET"); + + /* + * IN: + * info[0] : target_id + * info[1] : mkey + * OUT: + * info[2] : data_len + */ + target_id = (target_id_t)test_p->info[0]; + mkey = (mkey_t)test_p->info[1]; + data_len = 0xffffffff; + + /* + * scf_mb_canget(target_id_t target_id, mkey_t mkey, + * uint32_t *data_lenp); + */ + + scf_debug_test_dscp_call_flag = SCF_DBF_DSCP_CALL_ON; + + mutex_exit(&scf_comtbl.all_mutex); + if (test_p->data[0] == 1) { + func_ret = scf_mb_canget(target_id, mkey, NULL); + } else { + func_ret = scf_mb_canget(target_id, mkey, + (uint32_t *)&data_len); + } + mutex_enter(&scf_comtbl.all_mutex); + + scf_debug_test_dscp_call_flag = SCF_DBF_DSCP_CALL_OFF; + + test_p->info[2] = (uint_t)data_len; + + break; + + case TEST_DSCP_CALL_GETMSG: + SCFDBGMSG(SCF_DBGFLAG_DBG, "TEST_DSCP_CALL_GETMSG"); + + /* + * IN: + * info[0] : target_id + * info[1] : mkey + * info[2] : data_len + * info[3] : num_sg + */ + target_id = (target_id_t)test_p->info[0]; + mkey = (mkey_t)test_p->info[1]; + data_len = (uint32_t)test_p->info[2]; + num_sg = (uint32_t)test_p->info[3]; + + /* + * scf_mb_getmsg(target_id_t target_id, mkey_t mkey, + * uint32_t data_len, uint32_t num_sg, mscat_gath_t *sgp, + * clock_t timeout); + */ + + if (data_len != 0) { + kmem_size = data_len; + data_addr = (caddr_t)kmem_zalloc(kmem_size, KM_SLEEP); + } + if (num_sg != 0) { + kmem_size2 = sizeof (mscat_gath_t) * num_sg; + sgp = (mscat_gath_t *)kmem_zalloc(kmem_size2, KM_SLEEP); + } + + msc_dptr = data_addr; + msc_len = data_len; + for (ii = 0; ii < num_sg; ii++) { + if (msc_len != 0) { + sgp[ii].msc_dptr = msc_dptr; + if ((msc_len < 0x00000010) || + (ii == (num_sg - 1))) { + sgp[ii].msc_len = msc_len; + } else { + sgp[ii].msc_len = 0x00000010; + } + msc_len -= sgp[ii].msc_len; + for (jj = 0; jj < sgp[ii].msc_len; jj++, + msc_dptr++) { + *msc_dptr = jj; + } + } else { + sgp[ii].msc_dptr = NULL; + sgp[ii].msc_len = 0; + } + } + + scf_debug_test_dscp_call_flag = SCF_DBF_DSCP_CALL_ON; + + mutex_exit(&scf_comtbl.all_mutex); + if (test_p->data[0] == 1) { + func_ret = scf_mb_getmsg(target_id, mkey, data_len, + num_sg, NULL, 0); + } else if (test_p->data[0] == 2) { + sgp->msc_len = 0x00000010; + sgp->msc_dptr = NULL; + func_ret = scf_mb_getmsg(target_id, mkey, data_len, + num_sg, sgp, 0); + } else if (test_p->data[0] == 3) { + sgp->msc_len += 1; + func_ret = scf_mb_getmsg(target_id, mkey, data_len, + num_sg, sgp, 0); + } else { + func_ret = scf_mb_getmsg(target_id, mkey, data_len, + num_sg, sgp, 0); + } + mutex_enter(&scf_comtbl.all_mutex); + + if (data_len != 0) + bcopy((void *)data_addr, (void *)&test_p->rdata[0], + data_len); + + if (data_addr != NULL) kmem_free(data_addr, kmem_size); + if (sgp != NULL) kmem_free(sgp, kmem_size2); + + scf_debug_test_dscp_call_flag = SCF_DBF_DSCP_CALL_OFF; + break; + + case TEST_DSCP_CALL_FLUSH: + SCFDBGMSG(SCF_DBGFLAG_DBG, "TEST_DSCP_CALL_FLUSH"); + + /* + * IN: + * info[0] : target_id + * info[1] : mkey + * info[2] : flush_type + */ + target_id = (target_id_t)test_p->info[0]; + mkey = (mkey_t)test_p->info[1]; + flush_type = (mflush_type_t)test_p->info[2]; + + /* + * scf_mb_flush(target_id_t target_id, mkey_t mkey, + * mflush_type_t flush_type); + */ + + scf_debug_test_dscp_call_flag = SCF_DBF_DSCP_CALL_ON; + + mutex_exit(&scf_comtbl.all_mutex); + func_ret = scf_mb_flush(target_id, mkey, flush_type); + mutex_enter(&scf_comtbl.all_mutex); + + scf_debug_test_dscp_call_flag = SCF_DBF_DSCP_CALL_OFF; + break; + + case TEST_DSCP_CALL_CTRL: + SCFDBGMSG(SCF_DBGFLAG_DBG, "TEST_DSCP_CALL_CTRL"); + + /* + * IN: + * info[0] : target_id + * info[1] : mkey + * info[2] : op + * OUT: + * info[3] : arg + */ + target_id = (target_id_t)test_p->info[0]; + mkey = (mkey_t)test_p->info[1]; + op = test_p->info[2]; + + /* + * scf_mb_ctrl(target_id_t target_id, mkey_t mkey, + * uint32_t op, void *arg); + */ + + scf_debug_test_dscp_call_flag = SCF_DBF_DSCP_CALL_ON; + + mutex_exit(&scf_comtbl.all_mutex); + if (test_p->data[0] == 1) { + func_ret = scf_mb_ctrl(target_id, mkey, op, NULL); + } else { + func_ret = scf_mb_ctrl(target_id, mkey, op, + (void *)&func_arg); + } + mutex_enter(&scf_comtbl.all_mutex); + + scf_debug_test_dscp_call_flag = SCF_DBF_DSCP_CALL_OFF; + + test_p->info[3] = (uint_t)func_arg; + + break; + + case TEST_DSCP_CALL_OTHER: + SCFDBGMSG(SCF_DBGFLAG_DBG, "TEST_DSCP_CALL_OTHER"); + + /* + * IN: + * info[0] : function code + * info[1] : factor + * OUT: + * info[3] : return code + */ + switch (test_p->info[0]) { + case 0x00000001: + test_p->info[3] = scf_dscp_init(); + break; + + case 0x00000002: + scf_dscp_fini(); + break; + + case 0x00000003: + scf_dscp_start(test_p->info[1]); + break; + + case 0x00000004: + scf_dscp_stop(test_p->info[1]); + break; + + case 0x00000101: + if (test_p->info[1] == 0xffffffff) { + for (ii = 0; ii < SCF_TIMERCD_MAX; ii++) { + scf_timer_start(ii); + } + } else { + scf_timer_start(test_p->info[1]); + } + break; + + case 0x00000102: + if (test_p->info[1] == 0xffffffff) { + scf_timer_all_stop(); + } else { + scf_timer_stop(test_p->info[1]); + } + break; + + case 0x00000103: + func_ret = scf_timer_check(test_p->info[1]); + break; + + case 0x00000104: + func_ret = scf_timer_value_get(test_p->info[1]); + break; + + case 0x00000200: + if (statep != NULL) { + SCF_SRAM_TRACE(statep, DTC_ONLINETO); + SCF_SRAM_TRACE(statep, DTC_ONLINE); + SCF_SRAM_TRACE(statep, DTC_OFFLINE); + + SCF_SRAM_TRACE(statep, DTC_SENDDATA); + + SCF_SRAM_TRACE(statep, DTC_RECVDATA); + + SCF_SRAM_TRACE(statep, DTC_ERRRTN); + SCF_SRAM_TRACE(statep, DTC_RCI_BUF_FUL); + SCF_SRAM_TRACE(statep, DTC_RCI_BUSY); + SCF_SRAM_TRACE(statep, DTC_INTERFACE); + SCF_SRAM_TRACE(statep, DTC_E_NOT_SUPPORT); + SCF_SRAM_TRACE(statep, DTC_E_PARAM); + SCF_SRAM_TRACE(statep, DTC_E_SCFC_PATH); + SCF_SRAM_TRACE(statep, DTC_E_RCI_ACCESS); + SCF_SRAM_TRACE(statep, DTC_E_SEQUENCE); + + SCF_SRAM_TRACE(statep, DTC_RSUMERR); + + SCF_SRAM_TRACE(statep, DTC_DSCP_TXREQ); + + SCF_SRAM_TRACE(statep, DTC_DSCP_RXACK); + + SCF_SRAM_TRACE(statep, DTC_DSCP_RXEND); + + SCF_SRAM_TRACE(statep, DTC_DSCP_RXREQ); + + SCF_SRAM_TRACE(statep, DTC_DSCP_TXACK); + SCF_SRAM_TRACE(statep, DTC_DSCP_ACKTO); + SCF_SRAM_TRACE(statep, DTC_DSCP_ENDTO); + + SCF_SRAM_TRACE(statep, DTC_DSCP_TXEND); + + SCF_SRAM_TRACE(statep, DTC_SENDDATA_SRAM); + SCF_SRAM_TRACE(statep, DTC_RECVDATA_SRAM); + SCF_SRAM_TRACE(statep, DTC_DSCP_SENDDATA); + SCF_SRAM_TRACE(statep, DTC_DSCP_RECVDATA); + + SCF_SRAM_TRACE(statep, DTC_CMD); + SCF_SRAM_TRACE(statep, DTC_INT); + SCF_SRAM_TRACE(statep, DTC_CMDTO); + SCF_SRAM_TRACE(statep, DTC_CMDBUSYTO); + SCF_SRAM_TRACE(statep, 0x99); + } + break; + + case 0x00010000: + if (statep != NULL) { + mutex_exit(&scf_comtbl.all_mutex); + func_ret = scf_detach(statep->dip, DDI_SUSPEND); + func_ret = + scf_detach(scf_comtbl.scf_pseudo_p->dip, + DDI_SUSPEND); + + drv_usecwait(5000000); + + func_ret = + scf_attach(scf_comtbl.scf_pseudo_p->dip, + DDI_RESUME); + func_ret = scf_attach(statep->dip, DDI_RESUME); + mutex_enter(&scf_comtbl.all_mutex); + } + break; + + case 0x00019990: + case 0x00019991: + mutex_exit(&scf_comtbl.all_mutex); + mutex_enter(&scf_comtbl.si_mutex); + if (test_p->info[0] & 0x00000001) { + scf_comtbl.scf_softintr_dscp_kicked = FLAG_ON; + } else { + scf_comtbl.scf_softintr_dscp_kicked = FLAG_OFF; + } + mutex_exit(&scf_comtbl.si_mutex); + scf_softintr(NULL); + mutex_enter(&scf_comtbl.all_mutex); + break; + + case 0x00019998: + mutex_exit(&scf_comtbl.all_mutex); + scf_panic_callb(1); + mutex_enter(&scf_comtbl.all_mutex); + break; + + case 0x00019999: + mutex_exit(&scf_comtbl.all_mutex); + scf_shutdown_callb(1); + mutex_enter(&scf_comtbl.all_mutex); + break; + + case 0x00020000: + func_ret = scf_offline_check(statep, FLAG_OFF); + func_ret = scf_offline_check(statep, FLAG_ON); + func_ret = scf_cmdbusy_check(statep); + break; + + default: + break; + } + break; + + case TEST_OSESCF_CALL_RESET: + SCFDBGMSG(SCF_DBGFLAG_DBG, "TEST_OSESCF_CALL_RESET"); + + /* Not use info */ + scf_debug_test_osescf_call_flag = SCF_DBF_OSESCF_CALL_OFF; + break; + + case TEST_OSESCF_CALL_PUTINFO: + SCFDBGMSG(SCF_DBGFLAG_DBG, "TEST_OSESCF_CALL_PUTINFO"); + + /* + * IN: + * info[0] : key + * info[1] : type + * info[2] : transid + * info[3] : length + */ + key = (uint32_t)test_p->info[0]; + type = (uint8_t)test_p->info[1]; + transid = (uint32_t)test_p->info[2]; + length = (uint32_t)test_p->info[3]; + + /* + * scf_service_putinfo(uint32_t key, uint8_t type, + * uint32_t transid, uint32_t length, void *datap); + */ + + if (length != 0) { + kmem_size = length; + data_addr = (caddr_t)kmem_zalloc(kmem_size, KM_SLEEP); + } + + msc_dptr = data_addr; + for (ii = 0; ii < length; ii++, msc_dptr++) { + *msc_dptr = ii; + } + + scf_debug_test_osescf_call_flag = SCF_DBF_OSESCF_CALL_ON; + + mutex_exit(&scf_comtbl.all_mutex); + if (test_p->data[0] == 1) { + func_ret = scf_service_putinfo(key, type, transid, + length, NULL); + } else { + func_ret = scf_service_putinfo(key, type, transid, + length, (void *)data_addr); + } + mutex_enter(&scf_comtbl.all_mutex); + + if (length != 0) + bcopy((void *)data_addr, (void *)&test_p->rdata[0], + length); + + if (data_addr != NULL) kmem_free(data_addr, kmem_size); + + scf_debug_test_osescf_call_flag = SCF_DBF_OSESCF_CALL_OFF; + + break; + + case TEST_OSESCF_CALL_GETINFO: + SCFDBGMSG(SCF_DBGFLAG_DBG, "TEST_OSESCF_CALL_GETINFO"); + + /* + * IN: + * info[0] : key + * info[1] : type + * info[2] : transid + * info[3] : length + * OUT: + * info[3] : length + */ + key = (uint32_t)test_p->info[0]; + type = (uint8_t)test_p->info[1]; + transid = (uint32_t)test_p->info[2]; + length = (uint32_t)test_p->info[3]; + + /* + * scf_service_getinfo(uint32_t key, uint8_t type, + * uint32_t transid, uint32_t *lengthp, void *datap); + */ + if (length != 0) { + kmem_size = length; + data_addr = (caddr_t)kmem_zalloc(kmem_size, KM_SLEEP); + } + + msc_dptr = data_addr; + for (ii = 0; ii < length; ii++, msc_dptr++) { + *msc_dptr = 0x7f; + } + + scf_debug_test_osescf_call_flag = SCF_DBF_OSESCF_CALL_ON; + + mutex_exit(&scf_comtbl.all_mutex); + if (test_p->data[0] == 1) { + func_ret = scf_service_getinfo(key, type, transid, + (uint32_t *)&length, NULL); + } else if (test_p->data[0] == 2) { + func_ret = scf_service_getinfo(key, type, transid, + NULL, (void *)data_addr); + } else { + func_ret = scf_service_getinfo(key, type, transid, + (uint32_t *)&length, (void *)data_addr); + } + mutex_enter(&scf_comtbl.all_mutex); + + if (scf_debug_nofirm_sys == SCF_DBF_NOFIRM_SYS_ON) { + length = kmem_size; + msc_dptr = data_addr; + for (ii = 0; ii < length; ii++, msc_dptr++) { + *msc_dptr = ii; + } + } + if (length != 0) + bcopy((void *)data_addr, (void *)&test_p->rdata[0], + length); + + if (data_addr != NULL) kmem_free(data_addr, kmem_size); + + scf_debug_test_osescf_call_flag = SCF_DBF_OSESCF_CALL_OFF; + + test_p->info[3] = (uint_t)length; + break; + + case TEST_FMEM_START: + SCFDBGMSG(SCF_DBGFLAG_DBG, "TEST_FMEM_START"); + + /* + * IN: + * info[0] : lsb_1 + * info[1] : lsb_2 + */ + + /* + * scf_fmem_start(int s_bd, int t_bd); + */ + + mutex_exit(&scf_comtbl.all_mutex); + func_ret = scf_fmem_start(test_p->info[0], test_p->info[1]); + mutex_enter(&scf_comtbl.all_mutex); + break; + + case TEST_FMEM_END: + SCFDBGMSG(SCF_DBGFLAG_DBG, "TEST_FMEM_END"); + + /* + * scf_fmem_end(void); + */ + + mutex_exit(&scf_comtbl.all_mutex); + func_ret = scf_fmem_end(); + mutex_enter(&scf_comtbl.all_mutex); + + break; + + case TEST_FMEM_CANCEL: + SCFDBGMSG(SCF_DBGFLAG_DBG, "TEST_FMEM_CANCEL"); + + /* + * scf_fmem_cancel(void); + */ + + mutex_exit(&scf_comtbl.all_mutex); + func_ret = scf_fmem_cancel(); + mutex_enter(&scf_comtbl.all_mutex); + + break; + + default: + SCFDBGMSG(SCF_DBGFLAG_DBG, "Undefine mod"); + + SC_DBG_DRV_TRACE(TC_ERR, __LINE__, "dbg_test", 8); + ret = EINVAL; + break; + } + + test_p->rtncode = func_ret; + + /* Collect the timers which need to be stopped */ + tm_stop_cnt = scf_timer_stop_collect(save_tmids, SCF_TIMERCD_MAX); + + /* Unlock driver mutex */ + mutex_exit(&scf_comtbl.all_mutex); + + /* Timer stop */ + if (tm_stop_cnt != 0) { + scf_timer_untimeout(save_tmids, SCF_TIMERCD_MAX); + } + + if (ret == 0) { + if (ddi_copyout((void *)test_p, (void *)arg, + sizeof (scf_scfioctest_t), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "ioctl ", 8); + ret = EFAULT; + } + } + +/* + * END_test + */ + END_test: + + if (test_p) { + kmem_free((void *)test_p, + (size_t)(sizeof (scf_scfioctest_t))); + } + + SCFDBGMSG1(SCF_DBGFLAG_DBG, SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +void +scf_debug_test_intr_tout(void *arg) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_debug_test_intr_tout() " + + SCFDBGMSG(SCF_DBGFLAG_DBG, SCF_FUNC_NAME ": start"); + + mutex_enter(&scf_comtbl.all_mutex); + + if (scf_debug_test_intr_id != 0) { + scf_debug_test_intr_id = 0; + + mutex_exit(&scf_comtbl.all_mutex); + + scf_intr(arg); + } else { + mutex_exit(&scf_comtbl.all_mutex); + } + + SCFDBGMSG(SCF_DBGFLAG_DBG, SCF_FUNC_NAME ": end"); +} + + +void +scf_debug_test_intr(scf_state_t *statep) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_debug_test_intr() " + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_DBG, SCF_FUNC_NAME ": start"); + + statep->reg_int_st = scf_debug_test_sys_int_tbl.INT_ST; + + if (SCF_DBG_CHECK_NODEVICE) { + SCF_DDI_PUT16(statep, statep->scf_regs_c_handle, + &statep->scf_regs_c->INT_ST, statep->reg_int_st); + } + + SCFDBGMSG1(SCF_DBGFLAG_DBG, "set ISR = 0x%04x", statep->reg_int_st); + + scf_debug_test_sys_int_tbl.INT_ST = 0; + + if ((statep->reg_int_st & INT_ST_IDBCINT) == 0) { + scf_debug_test_dscp_int_flag = SCF_DBF_DSCP_INT_OFF; + } + if ((statep->reg_int_st & INT_ST_SCFINT) == 0) { + scf_debug_test_sys_int_flag = SCF_DBF_SYS_INTR_OFF; + } + + SCFDBGMSG(SCF_DBGFLAG_DBG, SCF_FUNC_NAME ": end"); +} + + +void +scf_debug_test_intr_scfint(scf_state_t *statep) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_debug_test_intr_scfint() " + uint16_t wk_STATUS; + uint32_t wk_STATUS_ExR; + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_DBG, SCF_FUNC_NAME ": start"); + + if ((scf_debug_test_sys_int_tbl.STATUS & STATUS_MODE_CHANGED) == 0) { + wk_STATUS = + statep->reg_status & + (STATUS_SECURE_MODE | STATUS_BOOT_MODE); + scf_debug_test_sys_int_tbl.STATUS &= + ~(STATUS_SECURE_MODE | STATUS_BOOT_MODE); + scf_debug_test_sys_int_tbl.STATUS |= wk_STATUS; + } + statep->reg_status = scf_debug_test_sys_int_tbl.STATUS; + + if (SCF_DBG_CHECK_NODEVICE) { + SCF_DDI_PUT16(statep, statep->scf_regs_handle, + &statep->scf_regs->STATUS, statep->reg_status); + } + + SCFDBGMSG1(SCF_DBGFLAG_DBG, "set STR = 0x%04x", statep->reg_status); + + scf_debug_test_sys_int_tbl.STATUS = 0; + + if ((scf_debug_test_sys_int_tbl.STATUS_ExR & + STATUS_SCF_STATUS_CHANGE) == 0) { + wk_STATUS_ExR = statep->reg_status_exr & + (STATUS_SCF_STATUS | STATUS_SCF_NO); + scf_debug_test_sys_int_tbl.STATUS_ExR &= + ~(STATUS_SCF_STATUS | STATUS_SCF_NO); + scf_debug_test_sys_int_tbl.STATUS_ExR |= wk_STATUS_ExR; + } + statep->reg_status_exr = scf_debug_test_sys_int_tbl.STATUS_ExR; + + if (SCF_DBG_CHECK_NODEVICE) { + SCF_DDI_PUT32(statep, statep->scf_regs_handle, + &statep->scf_regs->STATUS_ExR, statep->reg_status_exr); + } + + SCFDBGMSG1(SCF_DBGFLAG_DBG, "set STExR = 0x%08x", + statep->reg_status_exr); + + scf_debug_test_sys_int_tbl.STATUS_ExR = 0; + + if ((statep->reg_status & STATUS_CMD_COMPLETE) == 0) { + scf_debug_test_sys_int_flag = SCF_DBF_SYS_INTR_OFF; + } + + SCFDBGMSG(SCF_DBGFLAG_DBG, SCF_FUNC_NAME ": end"); +} + + +void +scf_debug_test_intr_cmdend(scf_state_t *statep) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_debug_test_intr_cmdend() " + uint_t ii; + uint8_t *wk_charp; + uint8_t sum = SCF_MAGICNUMBER_S; + uint32_t sum4 = SCF_MAGICNUMBER_L; + uint32_t wk_data; + uint8_t *wk_out_p; + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_DBG, SCF_FUNC_NAME ": start"); + + if (scf_debug_test_sys_int_tbl.rxsize < SCF_S_CNT_16) { + if ((scf_debug_rdata[0] == 0) && + (scf_debug_rdata[1] == 0) && + (scf_debug_rdata[2] == 0) && + (scf_debug_rdata[3] == 0)) { + statep->reg_rdata[0] = + scf_debug_test_sys_int_tbl.RDATA0; + statep->reg_rdata[1] = + scf_debug_test_sys_int_tbl.RDATA1; + statep->reg_rdata[2] = + scf_debug_test_sys_int_tbl.RDATA2; + statep->reg_rdata[3] = + scf_debug_test_sys_int_tbl.RDATA3; + } else { + statep->reg_rdata[0] = scf_debug_rdata[0]; + statep->reg_rdata[1] = scf_debug_rdata[1]; + statep->reg_rdata[2] = scf_debug_rdata[2]; + statep->reg_rdata[3] = scf_debug_rdata[3]; + } + } else { + statep->reg_rdata[0] = scf_debug_test_sys_int_tbl.rxsize; + statep->reg_rdata[1] = 0; + if (scf_debug_test_sys_int_tbl.RDATA2 != 0) { + statep->reg_rdata[2] = + scf_debug_test_sys_int_tbl.RDATA2; + scf_debug_test_rxbuff_nosum_check_flag = + SCF_DBF_RXBUFF_NOSUM_CHECK_OFF; + } else { + statep->reg_rdata[2] = 0; + scf_debug_test_rxbuff_nosum_check_flag = + SCF_DBF_RXBUFF_NOSUM_CHECK_ON; + } + statep->reg_rdata[3] = scf_debug_test_sys_int_tbl.RDATA3; + + if ((scf_comtbl.scf_exec_cmd_id == 0) && + (scf_comtbl.scf_cmd_intr.cmd == CMD_INT_REASON)) { + wk_out_p = (uint8_t *)&statep->scf_sys_sram->DATA[0]; + for (ii = 0; ii < scf_debug_test_sys_int_tbl.rxsize; + ii++, wk_out_p++) { + SCF_DDI_PUT8(statep, + statep->scf_sys_sram_handle, wk_out_p, + 0x00); + } + } else { + wk_data = 0x00010203; + wk_out_p = (uint8_t *)&statep->scf_sys_sram->DATA[0]; + for (ii = 0; ii < scf_debug_test_sys_int_tbl.rxsize; + ii++, wk_out_p++) { + SCF_DDI_PUT8(statep, + statep->scf_sys_sram_handle, wk_out_p, + ii); + if ((ii % 4) == 0) { + wk_data = (ii & 0x000000ff) << 24; + } else if ((ii % 4) == 1) { + wk_data |= (ii & 0x000000ff) << 16; + } else if ((ii % 4) == 2) { + wk_data |= (ii & 0x000000ff) << 8; + } else { + wk_data |= (ii & 0x000000ff); + sum4 += wk_data; + } + } + } + + if (scf_no_make_sum_l == SCF_DBF_NO_MAKE_SUM_L_OFF) { + statep->reg_rdata[2] = sum4; + } + } + + wk_charp = (uint8_t *)&statep->reg_rdata[0]; + for (ii = 0; ii < SCF_S_CNT_15; ii++, wk_charp++) { + sum += (*wk_charp); + } + + if (scf_no_make_sum_s == SCF_DBF_NO_MAKE_SUM_S_OFF) { + *wk_charp = sum; + } + + SCFDBGMSG4(SCF_DBGFLAG_DBG, "set RxDR = 0x%08x 0x%08x 0x%08x 0x%08x", + statep->reg_rdata[0], statep->reg_rdata[1], + statep->reg_rdata[2], statep->reg_rdata[3]); + + scf_debug_test_sys_int_flag = SCF_DBF_SYS_INTR_OFF; + + SCFDBGMSG(SCF_DBGFLAG_DBG, SCF_FUNC_NAME ": end"); +} + + +void +scf_debug_test_intr_poff(void) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_debug_test_intr_poff() " + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_DBG, SCF_FUNC_NAME ": start"); + + scf_comtbl.scf_poff_id = scf_debug_test_sys_int_tbl.POFF_FACTOR; + + SCFDBGMSG1(SCF_DBGFLAG_DBG, "set POFF factor = 0x%02x", + scf_comtbl.scf_poff_id); + + scf_debug_test_sys_poff_flag = SCF_DBF_SYS_POFF_OFF; + + SCFDBGMSG(SCF_DBGFLAG_DBG, SCF_FUNC_NAME ": end"); +} + +void +scf_debug_test_dsens(struct scf_cmd *scfcmdp, scf_int_reason_t *int_rp, int len) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_debug_test_dsens() " + int wk_len = len; + uint8_t *wk_in_p; + uint8_t *wk_out_p; + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_DBG, SCF_FUNC_NAME ": start"); + + if (wk_len == 0) { + wk_len = SCF_INT_CNT_MAX; + scfcmdp->rbufleng = wk_len; + } + + wk_in_p = (uint8_t *)&scf_debug_test_sys_int_tbl.EVENT[0]; + wk_out_p = (uint8_t *)int_rp; + bcopy((void *)wk_in_p, (void *)wk_out_p, wk_len); + + scf_debug_test_sys_event_flag = SCF_DBF_SYS_EVENT_OFF; + + SCFDBGMSG(SCF_DBGFLAG_DBG, SCF_FUNC_NAME ": end"); +} + + +void +scf_debug_test_intr_dscp_dsr(scf_state_t *statep) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_debug_test_intr_dscp_dsr() " + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_DBG, SCF_FUNC_NAME ": start"); + + statep->reg_dsr = scf_debug_test_dscp_int_tbl.DSR; + + if (SCF_DBG_CHECK_NODEVICE) { + SCF_DDI_PUT8(statep, statep->scf_regs_handle, + &statep->scf_regs->DSR, statep->reg_dsr); + } + + SCFDBGMSG1(SCF_DBGFLAG_DBG, "set DSR = 0x%02x", statep->reg_dsr); + + scf_debug_test_dscp_int_tbl.DSR = 0; + + if ((statep->reg_dsr & (DSR_RxREQ | DSR_TxACK | DSR_TxEND)) == 0) { + scf_debug_test_dscp_int_flag = SCF_DBF_DSCP_INT_OFF; + } + + SCFDBGMSG(SCF_DBGFLAG_DBG, SCF_FUNC_NAME ": end"); +} + + +void +scf_debug_test_intr_dscp_rxtx(scf_state_t *statep, uint8_t dsr) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_debug_test_intr_dscp_rxtx() " + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_DBG, SCF_FUNC_NAME ": start"); + + if (dsr & DSR_RxREQ) { + statep->reg_rxdcr_c_flag = + (scf_debug_test_dscp_int_tbl.RxDCR_C_FLAG | + DSC_FLAG_DEFAULT); + statep->reg_rxdcr_c_length = + scf_debug_test_dscp_int_tbl.RxDCR_LENGTH; + if (scf_debug_test_dscp_int_tbl.RxDCR_LENGTH != 0) { + if (scf_debug_test_dscp_int_tbl.RxDCR_OFFSET != + DSC_OFFSET_NOTHING) { + statep->reg_rxdcr_c_offset = + scf_debug_test_dscp_int_tbl.RxDCR_OFFSET; + } else { + statep->reg_rxdcr_c_offset = + (SCF_TX_SRAM_MAXCOUNT * SCF_RXBUFFSIZE / + DSC_OFFSET_CONVERT); + } + } else { + statep->reg_rxdcr_c_offset = DSC_OFFSET_NOTHING; + } + + SCFDBGMSG3(SCF_DBGFLAG_DBG, + "set RxDCR = 0x%04x 0x%04x 0x%08x", + statep->reg_rxdcr_c_flag, + statep->reg_rxdcr_c_offset, + statep->reg_rxdcr_c_length); + + if ((dsr & DSR_TxEND) == 0) { + scf_debug_test_dscp_int_flag = SCF_DBF_DSCP_INT_OFF; + } + + } else if (dsr == DSR_TxEND) { + statep->reg_txdsr_c_flag = + (statep->reg_txdcr_c_flag & 0xff00) | + scf_debug_test_dscp_int_tbl.TxDSR_C_FLAG; + if (scf_debug_test_dscp_int_tbl.TxDSR_OFFSET == 0) { + statep->reg_txdsr_c_offset = statep->reg_txdcr_c_offset; + } else { + statep->reg_txdsr_c_offset = + scf_debug_test_dscp_int_tbl.TxDSR_OFFSET; + } + + SCFDBGMSG2(SCF_DBGFLAG_DBG, "set TxDSR = 0x%04x 0x%04x", + statep->reg_rxdcr_c_flag, + statep->reg_rxdcr_c_offset); + + scf_debug_test_dscp_int_flag = SCF_DBF_DSCP_INT_OFF; + } + + SCFDBGMSG(SCF_DBGFLAG_DBG, SCF_FUNC_NAME ": end"); +} + + +void +scf_debug_test_alive_start(scf_state_t *statep) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_debug_test_alive_start() " + uint8_t wk_int8; + uint_t alive_timer; + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_DBG, SCF_FUNC_NAME ": start"); + + wk_int8 = SCF_DDI_GET8(statep, statep->scf_regs_handle, + &statep->scf_regs->ATR); + + switch (wk_int8 & ATR_INTERVAL) { + case ATR_INTERVAL_30S: + alive_timer = 30000; + break; + + case ATR_INTERVAL_60S: + alive_timer = 60000; + break; + + case ATR_INTERVAL_120S: + alive_timer = 120000; + break; + + default: + alive_timer = 0; + break; + } + if ((alive_timer != 0) && (scf_debug_test_alive_id == 0)) { + scf_debug_test_sys_int_flag = SCF_DBF_SYS_INTR_ON; + scf_debug_test_sys_int_tbl.INT_ST |= INT_ST_ALIVEINT; + scf_debug_test_alive_id = + timeout((void (*)())scf_debug_test_alive_intr_tout, + (void *)statep, + drv_usectohz(SCF_MIL2MICRO(alive_timer))); + scf_debug_test_alive_flag = FLAG_ON; + } + + SCFDBGMSG(SCF_DBGFLAG_DBG, SCF_FUNC_NAME ": end"); +} + + +/* ARGSUSED */ +void +scf_debug_test_alive_stop(scf_state_t *statep) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_debug_test_alive_stop() " + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_DBG, SCF_FUNC_NAME ": start"); + + scf_debug_test_alive_flag = FLAG_OFF; + + SCFDBGMSG(SCF_DBGFLAG_DBG, SCF_FUNC_NAME ": end"); +} + + +void +scf_debug_test_alive_intr_tout(void *arg) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_debug_test_alive_intr_tout() " + + SCFDBGMSG(SCF_DBGFLAG_DBG, SCF_FUNC_NAME ": start"); + + mutex_enter(&scf_comtbl.all_mutex); + + scf_debug_test_alive_id = 0; + + if (scf_debug_test_alive_flag == FLAG_ON) { + scf_debug_test_alive_start(arg); + + mutex_exit(&scf_comtbl.all_mutex); + + scf_intr(arg); + } else { + mutex_exit(&scf_comtbl.all_mutex); + } + + + SCFDBGMSG(SCF_DBGFLAG_DBG, SCF_FUNC_NAME ": end"); +} + + +void +scf_debug_test_send_cmd(scf_state_t *statep, struct scf_cmd *scfcmdp) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_debug_test_send_cmd() " + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_DBG, SCF_FUNC_NAME ": start"); + + if (scf_debug_scfint_time != 0) { + scf_debug_test_sys_int_flag = SCF_DBF_SYS_INTR_ON; + scf_debug_test_sys_int_tbl.INT_ST |= INT_ST_SCFINT; + + scf_debug_test_sys_int_tbl.STATUS = STATUS_CMD_COMPLETE; + scf_debug_test_sys_int_tbl.STATUS_ExR = 0; + + switch (scfcmdp->flag) { + case SCF_USE_SSBUF: + case SCF_USE_LSBUF: + scf_debug_test_sys_int_tbl.rxsize = scfcmdp->rcount; + scf_debug_test_sys_int_tbl.RDATA0 = 0x00010203; + scf_debug_test_sys_int_tbl.RDATA1 = 0x04050607; + scf_debug_test_sys_int_tbl.RDATA2 = 0x08090a0b; + scf_debug_test_sys_int_tbl.RDATA3 = 0x0c0d0e0f; + break; + + case SCF_USE_SLBUF: + scf_debug_test_sys_int_tbl.rxsize = scfcmdp->rcount; + scf_debug_test_sys_int_tbl.RDATA0 = scfcmdp->rcount; + scf_debug_test_sys_int_tbl.RDATA1 = 0; + scf_debug_test_sys_int_tbl.RDATA2 = 0; + scf_debug_test_sys_int_tbl.RDATA3 = 0; + break; + + default: + scf_debug_test_sys_int_tbl.rxsize = 0; + scf_debug_test_sys_int_tbl.RDATA0 = 0; + scf_debug_test_sys_int_tbl.RDATA1 = 0; + scf_debug_test_sys_int_tbl.RDATA2 = 0; + scf_debug_test_sys_int_tbl.RDATA3 = 0; + break; + } + + if (scf_debug_test_intr_id == 0) { + scf_debug_test_intr_id = + timeout((void (*)())scf_debug_test_intr_tout, + (void *)statep, + drv_usectohz(SCF_MIL2MICRO(scf_debug_scfint_time))); + } + } + + SCFDBGMSG(SCF_DBGFLAG_DBG, SCF_FUNC_NAME ": end"); +} + + +void +scf_debug_test_txreq_send(scf_state_t *statep, scf_dscp_dsc_t *dsc_p) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_debug_test_txreq_send() " + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_DBG, SCF_FUNC_NAME ": start"); + + if (scf_debug_idbcint_time != 0) { + scf_debug_test_dscp_int_flag = SCF_DBF_DSCP_INT_ON; + scf_debug_test_sys_int_tbl.INT_ST |= INT_ST_IDBCINT; + + if (dsc_p->dinfo.base.length != 0) { + if (scf_debug_test_dscp_loopback == + SCF_DBF_DSCP_LOOPBACK_ON) { + scf_debug_test_dscp_int_tbl.DSR = + (DSR_RxREQ | DSR_TxACK | DSR_TxEND); + + scf_debug_test_dscp_int_tbl.RxDCR_C_FLAG = + dsc_p->dinfo.base.c_flag; + scf_debug_test_dscp_int_tbl.RxDCR_OFFSET = + dsc_p->dinfo.base.offset; + scf_debug_test_dscp_int_tbl.RxDCR_LENGTH = + dsc_p->dinfo.base.length; + } else { + scf_debug_test_dscp_int_tbl.DSR = + (DSR_TxACK | DSR_TxEND); + } + } else { + scf_debug_test_dscp_int_tbl.DSR = DSR_TxEND; + } + + scf_debug_test_dscp_int_tbl.TxDSR_C_FLAG = + (dsc_p->dinfo.base.c_flag & 0xff00) | DSC_STATUS_NORMAL; + scf_debug_test_dscp_int_tbl.TxDSR_OFFSET = + dsc_p->dinfo.base.offset; + + if (scf_debug_test_intr_id == 0) { + scf_debug_test_intr_id = + timeout((void (*)())scf_debug_test_intr_tout, + (void *)statep, + drv_usectohz(SCF_MIL2MICRO(scf_debug_idbcint_time))); + } + } + + SCFDBGMSG(SCF_DBGFLAG_DBG, SCF_FUNC_NAME ": end"); +} + + +/* ARGSUSED */ +void +scf_debug_test_event_handler(scf_event_t mevent, void *arg) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_debug_test_event_handler() " + + SCFDBGMSG1(SCF_DBGFLAG_DBG, SCF_FUNC_NAME ": start mevent = %d", + mevent); + SCFDBGMSG(SCF_DBGFLAG_DBG, "======================================="); + + switch (mevent) { + case SCF_MB_CONN_OK: + SCFDBGMSG(SCF_DBGFLAG_DBG, "SCF_MB_CONN_OK"); + break; + case SCF_MB_MSG_DATA: + SCFDBGMSG(SCF_DBGFLAG_DBG, "SCF_MB_MSG_DATA"); + break; + case SCF_MB_SPACE: + SCFDBGMSG(SCF_DBGFLAG_DBG, "SCF_MB_SPACE"); + break; + case SCF_MB_DISC_ERROR: + SCFDBGMSG(SCF_DBGFLAG_DBG, "SCF_MB_DISC_ERROR"); + break; + default: + SCFDBGMSG(SCF_DBGFLAG_DBG, "Undefine event code"); + break; + } + + SCFDBGMSG(SCF_DBGFLAG_DBG, "======================================="); + SCFDBGMSG(SCF_DBGFLAG_DBG, SCF_FUNC_NAME ": end"); +} + + +void +scf_debug_test_timer_stop() +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_debug_test_timer_stop() " + timeout_id_t save_tmid[4]; + int timer_cnt = 0; + int ii; + + SCFDBGMSG(SCF_DBGFLAG_DBG, SCF_FUNC_NAME ": start"); + + mutex_enter(&scf_comtbl.all_mutex); + + if (scf_debug_test_intr_id != 0) { + save_tmid[timer_cnt] = scf_debug_test_intr_id; + scf_debug_test_intr_id = 0; + timer_cnt++; + } + if (scf_debug_test_alive_id != 0) { + save_tmid[timer_cnt] = scf_debug_test_alive_id; + scf_debug_test_alive_id = 0; + timer_cnt++; + } + + mutex_exit(&scf_comtbl.all_mutex); + + for (ii = 0; ii < timer_cnt; ii++) { + (void) untimeout(save_tmid[ii]); + } + + SCFDBGMSG(SCF_DBGFLAG_DBG, SCF_FUNC_NAME ": end"); +} + + +void +scf_debug_test_map_regs(scf_state_t *statep) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_debug_test_map_regs() " + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_DBG, SCF_FUNC_NAME ": start"); + + statep->scf_regs = &scf_debug_scf_regs_tbl; + statep->scf_regs_c = &scf_debug_scf_regs_c_tbl; + statep->scf_dscp_sram = &scf_debug_scf_dscp_sram_tbl; + statep->scf_sys_sram = &scf_debug_scf_sys_sram_tbl; + statep->scf_interface = &scf_debug_scf_interface_tbl; + statep->scf_reg_drvtrc = (void *)&scf_debug_scf_reg_drvtrc_tbl; + statep->scf_reg_drvtrc_len = + (off_t)sizeof (scf_debug_scf_reg_drvtrc_tbl); + + statep->resource_flag |= + (S_DID_REG1 | S_DID_REG2 | S_DID_REG3 | + S_DID_REG4 | S_DID_REG5 | S_DID_REG6); + + SCFDBGMSG(SCF_DBGFLAG_DBG, SCF_FUNC_NAME ": end"); +} + + +void +scf_debug_test_unmap_regs(scf_state_t *statep) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_debug_test_unmap_regs() " + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_DBG, SCF_FUNC_NAME ": start"); + + statep->scf_regs = NULL; + statep->scf_regs_c = NULL; + statep->scf_dscp_sram = NULL; + statep->scf_sys_sram = NULL; + statep->scf_interface = NULL; + statep->scf_reg_drvtrc = NULL; + + statep->resource_flag &= + ~(S_DID_REG1 | S_DID_REG2 | S_DID_REG3 | + S_DID_REG4 | S_DID_REG5 | S_DID_REG6); + + SCFDBGMSG(SCF_DBGFLAG_DBG, SCF_FUNC_NAME ": end"); +} +#endif /* DEBUG */ diff --git a/usr/src/uts/sun4u/opl/io/scfd/scfdscp.c b/usr/src/uts/sun4u/opl/io/scfd/scfdscp.c new file mode 100644 index 0000000000..bdee1377b4 --- /dev/null +++ b/usr/src/uts/sun4u/opl/io/scfd/scfdscp.c @@ -0,0 +1,4450 @@ +/* + * 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 + */ +/* + * All Rights Reserved, Copyright (c) FUJITSU LIMITED 2006 + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/ksynch.h> +#include <sys/types.h> +#include <sys/cmn_err.h> +#include <sys/kmem.h> +#include <sys/errno.h> +#include <sys/ddi.h> +#include <sys/sunddi.h> + +#include <sys/scfd/scfparam.h> +#include <sys/scfd/scfdscp.h> + +/* + * DSCP control table + */ +scf_dscp_comtbl_t scf_dscp_comtbl; /* DSCP control table */ + +mkey_t scf_dscp_mkey_search[] = { + DSCP_KEY, /* DSCP mailbox interface key */ + DKMD_KEY /* DKMD mailbox interface key */ + /* Add mailbox key */ +}; + +/* + * SCF driver system control intafece function + */ +void scf_dscp_init(void); +void scf_dscp_fini(void); +void scf_dscp_start(uint32_t factor); +void scf_dscp_stop(uint32_t factor); +void scf_dscp_intr(scf_state_t *statep); + +/* + * Timeout function : from SCF driver timer contorol function + */ +void scf_dscp_ack_tout(void); +void scf_dscp_end_tout(void); +void scf_dscp_busy_tout(void); +void scf_dscp_callback_tout(void); +void scf_dscp_callback(void); + +/* + * Interrupt function : from scf_dscp_intr() + */ +void scf_dscp_txack_recv(scf_state_t *statep); +void scf_dscp_txend_recv(scf_state_t *statep); +void scf_dscp_rxreq_recv(scf_state_t *statep); + +/* + * Main and Tx/Rx interface function + */ +void scf_dscp_txend_notice(scf_dscp_main_t *mainp); +void scf_dscp_txrelbusy_notice(scf_dscp_main_t *mainp); +void scf_dscp_rxreq_notice(scf_dscp_main_t *mainp); +void scf_dscp_rxdata_notice(scf_dscp_main_t *mainp); + +/* + * Tx subroutine function + */ +void scf_dscp_send_matrix(void); +void scf_dscp_txreq_send(scf_state_t *statep, scf_dscp_dsc_t *dsc_p); + +/* + * Rx subroutine function + */ +void scf_dscp_recv_matrix(void); +void scf_dscp_rxack_send(scf_state_t *statep); +void scf_dscp_rxend_send(scf_state_t *statep, scf_dscp_dsc_t *dsc_p); + +/* + * subroutine function + */ +void scf_dscp_dscbuff_free_all(void); +void scf_dscp_txdscbuff_free(scf_dscp_main_t *mainp); +void scf_dscp_rxdscbuff_free(scf_dscp_main_t *mainp); +void scf_dscp_rdata_free(scf_dscp_main_t *mainp); +void scf_dscp_event_queue(scf_dscp_main_t *mainp, scf_event_t mevent); +void scf_dscp_event_queue_free(scf_dscp_main_t *mainp); +scf_dscp_main_t *scf_dscp_mkey2mainp(mkey_t mkey); +scf_dscp_main_t *scf_dscp_id2mainp(uint8_t id); +uint16_t scf_dscp_sram_get(void); +void scf_dscp_sram_free(uint16_t offset); + + +/* + * DSCP Driver interface function + */ + +/* + * scf_mb_init() + * + * Description: Initialize the mailbox and register a callback for receiving + * events related to the specified mailbox. + * Arguments: + * + * target_id - The target_id of the peer. It must be 0 on a Domain. + * mkey - mailbox key + * event_handler- handler to be called for all events related + * to a mailbox. It should be called back with + * the event type and the registered argument. + * + * arg - A callback argument to be passed back to the + * event_handler. + * + * Return Values: returns 0 on success, otherwise any meaningful errno + * values are returned, some of the notable error values + * are given below. + * EINVAL - Invalid values. + * EEXIST - Already OPEN. + * EIO - DSCP I/F path not available. + */ +int +scf_mb_init(target_id_t target_id, mkey_t mkey, + void (*event_handler) (scf_event_t mevent, void *arg), void *arg) +{ +#define SCF_FUNC_NAME "scf_mb_init() " + scf_dscp_main_t *mainp; /* Main table address */ + scf_dscp_dsc_t *dsc_p; /* TxDSC address */ + int path_ret; /* SCF path status return value */ + int ret = 0; /* Return value */ + timeout_id_t save_tmids[SCF_TIMERCD_MAX]; + int tm_stop_cnt; + + SCFDBGMSG1(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start mkey = 0x%08x", + mkey); + SC_DBG_DRV_TRACE(TC_MB_INIT | TC_IN, __LINE__, &mkey, sizeof (mkey)); + + /* Lock driver mutex */ + mutex_enter(&scf_comtbl.all_mutex); + + /* Check target_id */ + if (target_id != 0) { + /* Invalid "target_id" */ + SC_DBG_DRV_TRACE(TC_MB_INIT | TC_ERRCD, __LINE__, &target_id, + sizeof (target_id)); + ret = EINVAL; + goto END_mb_init; + } + + /* Get main table address from "mkey" */ + mainp = scf_dscp_mkey2mainp(mkey); + + /* Check mainp address */ + if (mainp == NULL) { + /* Invalid "mkey" */ + SC_DBG_DRV_TRACE(TC_MB_INIT | TC_ERRCD, __LINE__, &mkey, + sizeof (mkey)); + ret = EINVAL; + goto END_mb_init; + } + + /* Check "event_handler" address */ + if (event_handler == NULL) { + /* Invalid "event_handler" */ + SC_DBG_DRV_TRACE(TC_MB_INIT | TC_ERRCD, __LINE__, + &event_handler, sizeof (event_handler)); + ret = EINVAL; + goto END_mb_init; + } + + /* Get SCF path status */ + path_ret = scf_path_check(NULL); + + /* Check SCF path status */ + if (path_ret == SCF_PATH_HALT) { + /* SCF path status is halt */ + SC_DBG_DRV_TRACE(TC_MB_INIT | TC_ERRCD, __LINE__, &path_ret, + sizeof (path_ret)); + ret = EIO; + goto END_mb_init; + } + + /* Check main status */ + if (mainp->status != SCF_ST_IDLE) { + /* Main status != A0 */ + SC_DBG_DRV_TRACE(TC_MB_INIT | TC_ERRCD, __LINE__, + &mainp->status, sizeof (mainp->status)); + ret = EEXIST; + goto END_mb_init; + } + + /* Initialize flag */ + mainp->conn_chk_flag = FLAG_OFF; + mainp->putmsg_busy_flag = FLAG_OFF; + + /* Get TxDSC address */ + dsc_p = &scf_dscp_comtbl.tx_dscp[scf_dscp_comtbl.tx_put]; + + /* Make Tx descriptor : INIT_REQ */ + dsc_p->dinfo.base.c_flag = DSC_FLAG_DEFAULT; + dsc_p->dinfo.base.offset = DSC_OFFSET_NOTHING; + dsc_p->dinfo.base.length = 0; + dsc_p->dinfo.base.dscp_datap = NULL; + dsc_p->dinfo.bdcr.id = mainp->id & DSC_CNTL_MASK_ID; + dsc_p->dinfo.bdcr.code = DSC_CNTL_INIT_REQ; + + /* Update Tx descriptor offset */ + if (scf_dscp_comtbl.tx_put == scf_dscp_comtbl.tx_last) { + scf_dscp_comtbl.tx_put = scf_dscp_comtbl.tx_first; + } else { + scf_dscp_comtbl.tx_put++; + } + + /* Update Tx descriptor count */ + scf_dscp_comtbl.tx_dsc_count++; + + /* Change TxDSC status (SB2) */ + SCF_SET_DSC_STATUS(dsc_p, SCF_TX_ST_TXREQ_SEND_WAIT); + + /* Call send matrix */ + scf_dscp_send_matrix(); + + /* Change main status (B0) */ + SCF_SET_STATUS(mainp, SCF_ST_EST_TXEND_RECV_WAIT); + + /* Save parameter */ + mainp->event_handler = event_handler; + mainp->arg = arg; + mainp->target_id = target_id; + mainp->mkey = mkey; + +/* + * END_mb_init + */ + END_mb_init: + + /* Collect the timers which need to be stopped */ + tm_stop_cnt = scf_timer_stop_collect(save_tmids, SCF_TIMERCD_MAX); + + /* Unlock driver mutex */ + mutex_exit(&scf_comtbl.all_mutex); + + /* Timer stop */ + if (tm_stop_cnt != 0) { + scf_timer_untimeout(save_tmids, SCF_TIMERCD_MAX); + } + + SC_DBG_DRV_TRACE(TC_MB_INIT | TC_OUT, __LINE__, &ret, sizeof (ret)); + SCFDBGMSG1(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +/* + * scf_mb_fini() + * + * Description: Cleanup the mailbox and unregister an event_handler, + * if it is registered. + * + * target_id - The target_id of the peer. It must be 0 on a Domain. + * mkey - mailbox key + * + * Return Values: returns 0 on success, otherwise any meaningful errno + * values are returned, some of the notable error values + * are given below. + * EINVAL - Invalid values. + * EBADF - Specified target_id is not OPEN. + */ +int +scf_mb_fini(target_id_t target_id, mkey_t mkey) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_mb_fini() " + scf_dscp_main_t *mainp; /* Main table address */ + scf_dscp_dsc_t *dsc_p; /* TxDSC address */ + int path_ret; /* SCF path status return value */ + int ret = 0; /* Return value */ + timeout_id_t save_tmids[SCF_TIMERCD_MAX]; + int tm_stop_cnt; + + SCFDBGMSG1(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start mkey = 0x%08x", + mkey); + SC_DBG_DRV_TRACE(TC_MB_FINI | TC_IN, __LINE__, &mkey, sizeof (mkey)); + + /* Lock driver mutex */ + mutex_enter(&scf_comtbl.all_mutex); + + /* Check target_id */ + if (target_id != 0) { + /* Invalid "target_id" */ + SC_DBG_DRV_TRACE(TC_MB_FINI | TC_ERRCD, __LINE__, &target_id, + sizeof (target_id)); + ret = EINVAL; + goto END_mb_fini; + } + + /* Get main table address from "mkey" */ + mainp = scf_dscp_mkey2mainp(mkey); + + /* Check mainp address */ + if (mainp == NULL) { + /* Invalid "mkey" */ + SC_DBG_DRV_TRACE(TC_MB_FINI | TC_ERRCD, __LINE__, &mkey, + sizeof (mkey)); + ret = EINVAL; + goto END_mb_fini; + } + + /* Get SCF path status */ + path_ret = scf_path_check(NULL); + + /* Check SCF path status */ + if (path_ret == SCF_PATH_HALT) { + /* SCF path status is halt */ + if (mainp->status != SCF_ST_IDLE) { + /* TxDSC buffer release */ + scf_dscp_txdscbuff_free(mainp); + + /* RxDSC buffer release */ + scf_dscp_rxdscbuff_free(mainp); + + /* All queing event release */ + scf_dscp_event_queue_free(mainp); + + /* All receive buffer release */ + scf_dscp_rdata_free(mainp); + + /* event_handler and arg NULL */ + mainp->event_handler = NULL; + mainp->arg = NULL; + + /* Change main status (A0) */ + SCF_SET_STATUS(mainp, SCF_ST_IDLE); + } + goto END_mb_fini; + } + + /* Check main status */ + switch (mainp->status) { + case SCF_ST_EST_TXEND_RECV_WAIT: /* Main status (B0) */ + case SCF_ST_ESTABLISHED: /* Main status (C0) */ + /* Get TxDSC address */ + dsc_p = &scf_dscp_comtbl.tx_dscp[scf_dscp_comtbl.tx_put]; + + /* Make Tx descriptor : FINI_REQ */ + dsc_p->dinfo.base.c_flag = DSC_FLAG_DEFAULT; + dsc_p->dinfo.base.offset = DSC_OFFSET_NOTHING; + dsc_p->dinfo.base.length = 0; + dsc_p->dinfo.base.dscp_datap = NULL; + dsc_p->dinfo.bdcr.id = mainp->id & DSC_CNTL_MASK_ID; + dsc_p->dinfo.bdcr.code = DSC_CNTL_FINI_REQ; + + /* Update Tx descriptor offset */ + if (scf_dscp_comtbl.tx_put == scf_dscp_comtbl.tx_last) { + scf_dscp_comtbl.tx_put = scf_dscp_comtbl.tx_first; + } else { + scf_dscp_comtbl.tx_put++; + } + + /* Update Tx descriptor count */ + scf_dscp_comtbl.tx_dsc_count++; + + /* Change TxDSC status (SB2) */ + SCF_SET_DSC_STATUS(dsc_p, SCF_TX_ST_TXREQ_SEND_WAIT); + + /* Call send matrix */ + scf_dscp_send_matrix(); + + /* Change main status (D0) */ + SCF_SET_STATUS(mainp, SCF_ST_CLOSE_TXEND_RECV_WAIT); + + /* TxEND(FINI) receive wait */ + SC_DBG_DRV_TRACE(TC_W_SIG, __LINE__, &mainp->fini_cv, + sizeof (kcondvar_t)); + mainp->fini_wait_flag = FLAG_ON; + while (mainp->fini_wait_flag == FLAG_ON) { + cv_wait(&mainp->fini_cv, &scf_comtbl.all_mutex); + } + + /* TxDSC buffer release */ + scf_dscp_txdscbuff_free(mainp); + + /* RxDSC buffer release */ + scf_dscp_rxdscbuff_free(mainp); + + /* All queing event release */ + scf_dscp_event_queue_free(mainp); + + /* All receive buffer release */ + scf_dscp_rdata_free(mainp); + + /* event_handler and arg NULL */ + mainp->event_handler = NULL; + mainp->arg = NULL; + + /* Change main status (A0) */ + SCF_SET_STATUS(mainp, SCF_ST_IDLE); + break; + + case SCF_ST_EST_FINI_WAIT: /* Main status (C1) */ + /* TxDSC buffer release */ + scf_dscp_txdscbuff_free(mainp); + + /* RxDSC buffer release */ + scf_dscp_rxdscbuff_free(mainp); + + /* All queing event release */ + scf_dscp_event_queue_free(mainp); + + /* All receive buffer release */ + scf_dscp_rdata_free(mainp); + + /* event_handler and arg NULL */ + mainp->event_handler = NULL; + mainp->arg = NULL; + + /* Change main status (A0) */ + SCF_SET_STATUS(mainp, SCF_ST_IDLE); + break; + + case SCF_ST_IDLE: /* Main status (A0) */ + /* Main status == A0 is NOP */ + break; + + default: + /* Not open */ + SC_DBG_DRV_TRACE(TC_MB_FINI | TC_ERRCD, __LINE__, + &mainp->status, TC_INFO_SIZE); + ret = EBADF; + break; + } + +/* + * END_mb_fini + */ + END_mb_fini: + + /* Collect the timers which need to be stopped */ + tm_stop_cnt = scf_timer_stop_collect(save_tmids, SCF_TIMERCD_MAX); + + /* Unlock driver mutex */ + mutex_exit(&scf_comtbl.all_mutex); + + /* Timer stop */ + if (tm_stop_cnt != 0) { + scf_timer_untimeout(save_tmids, SCF_TIMERCD_MAX); + } + + SC_DBG_DRV_TRACE(TC_MB_FINI | TC_OUT, __LINE__, &ret, sizeof (ret)); + SCFDBGMSG1(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +/* + * scf_mb_putmsg() + * + * Description: Send a message via the mailbox identified by mkey. The message + * need to be sent either completely or none. That is, no partial + * messages should be sent. + * + * If a 0 timeout value is specified, then it should act as + * a non-blocking interface, that is, it should either send + * the message immediately or return appropriate error. + * If a timeout value is specified, then it can blocked + * until either the message is sent successfully or timedout. + * + * Arguments: + * + * target_id - The target_id of the peer. It must be 0 on a Domain. + * mkey - Unique key corresponding to a mailbox. + * data_len - Total length of the data to be sent. + * num_sg - Number of scatter/gather elements in the argument sgp. + * sgp - Scatter/gather list pointer. + * timeout - timeout value in milliseconds. If 0 specified, no waiting + * is required. + * + * Return Values: returns 0 on success, otherwise any meaningful errno + * values are returned, some of the notable error values + * are given below. + * + * EINVAL - Invalid values. + * EBADF - Specified target_id is not OPEN. + * EBUSY - Driver is BUSY. + * ENOSPC - Not enough space to send the message. + * EIO - DSCP I/F path not available. + */ +/* ARGSUSED */ +int +scf_mb_putmsg(target_id_t target_id, mkey_t mkey, uint32_t data_len, + uint32_t num_sg, mscat_gath_t *sgp, clock_t timeout) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_mb_putmsg() " + scf_dscp_main_t *mainp; /* Main table address */ + scf_dscp_dsc_t *dsc_p; /* Current TxDSC address */ + caddr_t wkaddr; /* Working value : buffer address */ + uint32_t wkleng = 0; /* Working value : length */ + uint32_t wkoffset; /* Working value : Tx SRAM offset */ + int ii; /* Working value : counter */ + int path_ret; /* SCF path status return value */ + int ret = 0; /* Return value */ + timeout_id_t save_tmids[SCF_TIMERCD_MAX]; + int tm_stop_cnt; + + SCFDBGMSG1(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start mkey = 0x%08x", + mkey); + SC_DBG_DRV_TRACE(TC_MB_PUTMSG | TC_IN, __LINE__, &mkey, sizeof (mkey)); + + /* Lock driver mutex */ + mutex_enter(&scf_comtbl.all_mutex); + + /* Check target_id */ + if (target_id != 0) { + /* Invalid "target_id" */ + SC_DBG_DRV_TRACE(TC_MB_PUTMSG | TC_ERRCD, __LINE__, &target_id, + sizeof (target_id)); + ret = EINVAL; + goto END_mb_putmsg; + } + + /* Get main table address from "mkey" */ + mainp = scf_dscp_mkey2mainp(mkey); + + /* Check mainp address */ + if (mainp == NULL) { + /* Invalid "mkey" */ + SC_DBG_DRV_TRACE(TC_MB_PUTMSG | TC_ERRCD, __LINE__, &mkey, + sizeof (mkey)); + ret = EINVAL; + goto END_mb_putmsg; + } + + /* Get SCF path status */ + path_ret = scf_path_check(NULL); + + /* Check SCF path status */ + if (path_ret == SCF_PATH_HALT) { + /* SCF path status halt */ + SC_DBG_DRV_TRACE(TC_MB_PUTMSG | TC_ERRCD, __LINE__, &path_ret, + sizeof (path_ret)); + ret = EIO; + goto END_mb_putmsg; + } + + /* Check main status */ + switch (mainp->status) { + case SCF_ST_ESTABLISHED: /* Main status (C0) */ + /* Check "data_len" is "maxdatalen" */ + if (data_len > scf_dscp_comtbl.maxdatalen) { + /* Invalid "data_len" */ + SC_DBG_DRV_TRACE(TC_MB_PUTMSG | TC_ERRCD, __LINE__, + &data_len, sizeof (data_len)); + ret = EINVAL; + goto END_mb_putmsg; + } + + /* Check "data_len" is 0 */ + if (data_len == 0) { + goto END_mb_putmsg; + } + + /* + * Check "num_sg" is not 0, and "sgp" is not NULL + */ + if ((num_sg == 0) || (sgp == NULL)) { + /* Invalid "num_sg" or "sgp" */ + SC_DBG_DRV_TRACE(TC_MB_PUTMSG | TC_ERRCD, __LINE__, + &num_sg, sizeof (num_sg)); + ret = EINVAL; + goto END_mb_putmsg; + } + + /* Get total data length : "num_sg" */ + for (ii = 0; ii < num_sg; ii++) { + if ((sgp[ii].msc_len == 0) || + (sgp[ii].msc_dptr != NULL)) { + /* + * Add total data length + */ + wkleng += sgp[ii].msc_len; + } else { + /* Invalid "sgp" */ + SC_DBG_DRV_TRACE(TC_MB_PUTMSG | TC_ERRCD, + __LINE__, &ii, sizeof (ii)); + ret = EINVAL; + goto END_mb_putmsg; + } + } + + /* + * Check "data_len" and "wkleng" + */ + if (data_len != wkleng) { + /* Invalid "data_len" */ + SC_DBG_DRV_TRACE(TC_MB_PUTMSG | TC_ERRCD, __LINE__, + &data_len, sizeof (data_len)); + ret = EINVAL; + goto END_mb_putmsg; + } + + /* + * Check Tx SRAM space + */ + if (scf_dscp_comtbl.tx_dsc_count >= + scf_dscp_comtbl.txdsc_busycount) { + /* No space of Tx SRAM */ + SC_DBG_DRV_TRACE(TC_MB_PUTMSG | TC_ERRCD, __LINE__, + &scf_dscp_comtbl.tx_dsc_count, + sizeof (scf_dscp_comtbl.tx_dsc_count)); + + /* putmsg ENOSPC counter up */ + mainp->memo_putmsg_enospc_cnt++; + + mainp->putmsg_busy_flag = FLAG_ON; + ret = ENOSPC; + goto END_mb_putmsg; + } + + /* Tx buffer allocation */ + wkaddr = (caddr_t)kmem_zalloc(wkleng, KM_SLEEP); + + /* Get Tx SRAM offset */ + wkoffset = scf_dscp_sram_get(); + /* Check Tx SRAM offset */ + if (wkoffset == TX_SRAM_GET_ERROR) { + /* Tx SRAM offset failure */ + SC_DBG_DRV_TRACE(TC_MB_PUTMSG | TC_ERRCD, __LINE__, + &wkoffset, sizeof (wkoffset)); + + /* Send data release */ + kmem_free(wkaddr, wkleng); + + /* putmsg busy counter up */ + mainp->memo_putmsg_busy_cnt++; + + ret = EBUSY; + goto END_mb_putmsg; + } + + /* Get TxDSC address */ + dsc_p = &scf_dscp_comtbl.tx_dscp[scf_dscp_comtbl.tx_put]; + + /* Make Tx descriptor : DATA_REQ */ + dsc_p->dinfo.base.c_flag = DSC_FLAG_DEFAULT; + dsc_p->dinfo.base.offset = (uint16_t)wkoffset; + dsc_p->dinfo.base.length = wkleng; + dsc_p->dinfo.base.dscp_datap = wkaddr; + dsc_p->dinfo.bdcr.id = mainp->id & DSC_CNTL_MASK_ID; + dsc_p->dinfo.bdcr.code = DSC_CNTL_DATA_REQ; + + /* Data copy to Tx buffer */ + for (ii = 0; ii < num_sg; ii++) { + if (sgp[ii].msc_len != 0) { + bcopy(sgp[ii].msc_dptr, wkaddr, + sgp[ii].msc_len); + wkaddr += sgp[ii].msc_len; + } + } + + /* Update Tx descriptor offset */ + if (scf_dscp_comtbl.tx_put == scf_dscp_comtbl.tx_last) { + scf_dscp_comtbl.tx_put = scf_dscp_comtbl.tx_first; + } else { + scf_dscp_comtbl.tx_put++; + } + + /* Update Tx descriptor count */ + scf_dscp_comtbl.tx_dsc_count++; + + /* Change TxDSC status (SB0) */ + SCF_SET_DSC_STATUS(dsc_p, + SCF_TX_ST_SRAM_TRANS_WAIT); + + /* Call send matrix */ + scf_dscp_send_matrix(); + + /* Tx DATA_REQ counter */ + mainp->memo_tx_data_req_cnt++; + break; + + case SCF_ST_EST_FINI_WAIT: /* Main status (C1) */ + /* Main status == C1 is NOP */ + break; + + default: + /* Not open */ + SC_DBG_DRV_TRACE(TC_MB_PUTMSG | TC_ERRCD, __LINE__, + &mainp->status, TC_INFO_SIZE); + ret = EBADF; + break; + } + +/* + * END_mb_putmsg + */ + END_mb_putmsg: + + /* Collect the timers which need to be stopped */ + tm_stop_cnt = scf_timer_stop_collect(save_tmids, SCF_TIMERCD_MAX); + + /* Unlock driver mutex */ + mutex_exit(&scf_comtbl.all_mutex); + + /* Timer stop */ + if (tm_stop_cnt != 0) { + scf_timer_untimeout(save_tmids, SCF_TIMERCD_MAX); + } + + SC_DBG_DRV_TRACE(TC_MB_PUTMSG | TC_OUT, __LINE__, &ret, sizeof (ret)); + SCFDBGMSG1(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +/* + * scf_mb_canget() + * + * Description: Checks if a message received in the specified mailbox. + * If there is a message received, then the length of the + * message is passed via the argument data_lenp. Otherwise, + * return an appropriate error value. + * + * Arguments: + * + * target_id - The target_id of the peer. It must be 0 on a Domain. + * mkey - Unique key corresponding to a mailbox. + * data_lenp - A pointer to uint32_t, in which the size of the message + * is returned. + * + * Return Values: returns 0 if a message is present, otherwise an appropriate + * errno value is returned. + * + * EINVAL - Invalid values. + * EBADF - Specified target_id is not OPEN. + * ENOMSG - No message available. + * EIO - DSCP I/F path not available. + */ +int +scf_mb_canget(target_id_t target_id, mkey_t mkey, uint32_t *data_lenp) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_mb_canget() " + scf_dscp_main_t *mainp; /* Main table address */ + scf_rdata_que_t *rdt_p; /* Current receive data queue address */ + int path_ret; /* SCF path status return value */ + int ret = 0; /* Return value */ + + SCFDBGMSG1(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start mkey = 0x%08x", + mkey); + SC_DBG_DRV_TRACE(TC_MB_CANGET | TC_IN, __LINE__, &mkey, sizeof (mkey)); + /* Lock driver mutex */ + mutex_enter(&scf_comtbl.all_mutex); + + /* Check target_id */ + if (target_id != 0) { + /* Invalid "target_id" */ + SC_DBG_DRV_TRACE(TC_MB_CANGET | TC_ERRCD, __LINE__, &target_id, + sizeof (target_id)); + ret = EINVAL; + goto END_mb_canget; + } + + /* Get main table address from "mkey" */ + mainp = scf_dscp_mkey2mainp(mkey); + + /* Check mainp address */ + if (mainp == NULL) { + /* Invalid "mkey" */ + SC_DBG_DRV_TRACE(TC_MB_CANGET | TC_ERRCD, __LINE__, &mkey, + sizeof (mkey)); + ret = EINVAL; + goto END_mb_canget; + } + + /* Get SCF path status */ + path_ret = scf_path_check(NULL); + + /* Check SCF path status */ + if (path_ret == SCF_PATH_HALT) { + /* SCF path status halt */ + SC_DBG_DRV_TRACE(TC_MB_CANGET | TC_ERRCD, __LINE__, &path_ret, + sizeof (path_ret)); + ret = EIO; + goto END_mb_canget; + } + + /* Check main status */ + switch (mainp->status) { + case SCF_ST_ESTABLISHED: /* Main status (C0) */ + case SCF_ST_EST_FINI_WAIT: /* Main status (C1) */ + /* Check "data_lenp" address */ + if (data_lenp == NULL) { + /* Invalid "data_lenp" */ + SC_DBG_DRV_TRACE(TC_MB_CANGET | TC_ERRCD, __LINE__, + &data_lenp, sizeof (data_lenp)); + + ret = EINVAL; + goto END_mb_canget; + } + + /* Check receive data count */ + if (mainp->rd_count != 0) { + /* Set receive data length */ + rdt_p = &mainp->rd_datap[mainp->rd_get]; + *data_lenp = rdt_p->length; + } else { + /* Set receive data length is 0 : No messages */ + SC_DBG_DRV_TRACE(TC_MB_CANGET, __LINE__, + &mainp->rd_count, + sizeof (mainp->rd_count)); + *data_lenp = 0; + ret = ENOMSG; + } + break; + + default: + /* Not open */ + SC_DBG_DRV_TRACE(TC_MB_CANGET | TC_ERRCD, __LINE__, + &mainp->status, TC_INFO_SIZE); + ret = EBADF; + break; + } + +/* + * END_mb_canget + */ + END_mb_canget: + + /* Unlock driver mutex */ + mutex_exit(&scf_comtbl.all_mutex); + + SC_DBG_DRV_TRACE(TC_MB_CANGET | TC_OUT, __LINE__, &ret, sizeof (ret)); + SCFDBGMSG1(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +/* + * scf_mb_getmsg() + * + * Description: Get a message from the specified mailbox. A message need to + * be received either completely or none, that is, no partial + * messages should be received. + * + * If a 0 timeout value is specified, then it should act as a + * non-blocking interface, that is, it should either return + * a message from the mailbox or return appropriate error. + * If a timeout value is specified, then it can blocked + * until either the message is received successfully or timedout. + * + * Arguments: + * + * target_id - The target_id of the peer. It must be 0 on a Domain. + * mkey - Unique key corresponding to a mailbox. + * data_len - Total length of data buffers passed via scatter/gather list. + * num_sg - Number of scatter/gather elements in the argument sgp. + * sgp - Scatter/gather list pointer. + * timeout - timeout value in milliseconds. If 0 specified, no waiting + * is required. + * + * Return Values: returns 0 on success, otherwise any meaningful errno + * values are returned, some of the notable error values + * are given below. + * + * EINVAL - Invalid values. + * EBADF - Specified target_id is not OPEN. + * EMSGSIZE - Specified receive data size unmatched. + * ENOMSG - No message available. + * EIO - DSCP I/F path not available. + */ +/* ARGSUSED */ +int +scf_mb_getmsg(target_id_t target_id, mkey_t mkey, uint32_t data_len, + uint32_t num_sg, mscat_gath_t *sgp, clock_t timeout) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_mb_getmsg() " + scf_dscp_main_t *mainp; /* Main table address */ + scf_rdata_que_t *rdt_p; /* Current receive data queue address */ + caddr_t wkaddr; /* Working value : buffer address */ + uint32_t wkleng = 0; /* Working value : length */ + int ii; /* Working value : counter */ + int path_ret; /* SCF path status return value */ + int ret = 0; /* Return value */ + + SCFDBGMSG1(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start mkey = 0x%08x", + mkey); + SC_DBG_DRV_TRACE(TC_MB_GETMSG | TC_IN, __LINE__, &mkey, sizeof (mkey)); + /* Lock driver mutex */ + mutex_enter(&scf_comtbl.all_mutex); + + /* Check target_id */ + if (target_id != 0) { + /* Invalid "target_id" */ + SC_DBG_DRV_TRACE(TC_MB_GETMSG | TC_ERRCD, __LINE__, &target_id, + sizeof (target_id)); + ret = EINVAL; + goto END_mb_getmsg; + } + + /* Get main table address from "mkey" */ + mainp = scf_dscp_mkey2mainp(mkey); + + /* Check mainp address */ + if (mainp == NULL) { + /* Invalid "mkey" */ + SC_DBG_DRV_TRACE(TC_MB_GETMSG | TC_ERRCD, __LINE__, &mkey, + sizeof (mkey)); + ret = EINVAL; + goto END_mb_getmsg; + } + + /* Get SCF path status */ + path_ret = scf_path_check(NULL); + + /* Check SCF path status */ + if (path_ret == SCF_PATH_HALT) { + /* SCF path status halt */ + SC_DBG_DRV_TRACE(TC_MB_GETMSG | TC_ERRCD, __LINE__, &path_ret, + sizeof (path_ret)); + ret = EIO; + goto END_mb_getmsg; + } + + switch (mainp->status) { + case SCF_ST_ESTABLISHED: /* Main status (C0) */ + case SCF_ST_EST_FINI_WAIT: /* Main status (C1) */ + /* Check "data_len" */ + if ((data_len == 0) || + (data_len > scf_dscp_comtbl.maxdatalen)) { + /* Unmatched "data_len" */ + SC_DBG_DRV_TRACE(TC_MB_GETMSG | TC_ERRCD, __LINE__, + &data_len, sizeof (data_len)); + ret = EMSGSIZE; + goto END_mb_getmsg; + } + + /* Is num_sg and sgp valid? */ + if ((num_sg == 0) || (sgp == NULL)) { + /* Invalid "num_sg" or "sgp" */ + SC_DBG_DRV_TRACE(TC_MB_GETMSG | TC_ERRCD, + __LINE__, &num_sg, sizeof (num_sg)); + ret = EINVAL; + goto END_mb_getmsg; + } + /* Is there receive data? */ + if (mainp->rd_count == 0) { + /* No message */ + SC_DBG_DRV_TRACE(TC_MB_GETMSG, __LINE__, + &mainp->rd_count, + sizeof (mainp->rd_count)); + ret = ENOMSG; + goto END_mb_getmsg; + } + + /* Get total data length : "num_sg" */ + for (ii = 0; ii < num_sg; ii++) { + if ((sgp[ii].msc_len == 0) || + (sgp[ii].msc_dptr != NULL)) { + /* + * Add total data length + */ + wkleng += sgp[ii].msc_len; + } else { + /* Invalid "sgp" */ + SC_DBG_DRV_TRACE(TC_MB_GETMSG | TC_ERRCD, + __LINE__, &sgp, sizeof (sgp)); + ret = EINVAL; + goto END_mb_getmsg; + } + } + /* Check "data_len" and "wkleng" */ + if (data_len != wkleng) { + /* Unmatched "data_len" */ + SC_DBG_DRV_TRACE(TC_MB_GETMSG | TC_ERRCD, __LINE__, + &data_len, sizeof (data_len)); + ret = EMSGSIZE; + goto END_mb_getmsg; + } + + /* Get receive data queue address */ + rdt_p = &mainp->rd_datap[mainp->rd_get]; + + /* Check "data_len" and receive data length */ + if (data_len != rdt_p->length) { + /* Unmatched data_len */ + SC_DBG_DRV_TRACE(TC_MB_GETMSG | TC_ERRCD, + __LINE__, &data_len, sizeof (data_len)); + ret = EMSGSIZE; + goto END_mb_getmsg; + } + + /* Data copy to "sgp" */ + wkaddr = rdt_p->rdatap; + for (ii = 0; ii < num_sg; ii++) { + if (sgp[ii].msc_len != 0) { + bcopy(wkaddr, sgp[ii].msc_dptr, + sgp[ii].msc_len); + wkaddr += sgp[ii].msc_len; + } + } + /* Receve data release */ + kmem_free(rdt_p->rdatap, rdt_p->length); + rdt_p->rdatap = NULL; + + /* Update receive data queue */ + if (mainp->rd_get == mainp->rd_last) { + mainp->rd_get = mainp->rd_first; + } else { + mainp->rd_get++; + } + + /* Update receive data queue count */ + mainp->rd_count--; + break; + + default: + /* Not open */ + SC_DBG_DRV_TRACE(TC_MB_GETMSG | TC_ERRCD, __LINE__, + &mainp->status, TC_INFO_SIZE); + ret = EBADF; + break; + } + +/* + * END_mb_getmsg + */ + END_mb_getmsg: + + /* Unlock driver mutex */ + mutex_exit(&scf_comtbl.all_mutex); + + SC_DBG_DRV_TRACE(TC_MB_GETMSG | TC_OUT, __LINE__, &ret, sizeof (ret)); + SCFDBGMSG1(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +/* + * scf_mb_flush() + * + * Description: Flush messages from a specified mailbox. + * + * Arguments: + * + * target_id - The target_id of the peer. It must be 0 on a Domain. + * mkey - Unique key corresponding to a mailbox. + * flush_type - Specifies what type of flush is desired. + * + * Return Values: returns 0 on success, otherwise any meaningful errno + * values are returned. + * EINVAL - Invalid values. + * EBADF - Specified target_id is not OPEN. + */ +int +scf_mb_flush(target_id_t target_id, mkey_t mkey, mflush_type_t flush_type) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_mb_flush() " + scf_dscp_main_t *mainp; /* Main table address */ + int ret = 0; /* Return value */ + + SCFDBGMSG1(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start mkey = 0x%08x", + mkey); + SC_DBG_DRV_TRACE(TC_MB_FLUSH | TC_IN, __LINE__, &mkey, sizeof (mkey)); + + /* Lock driver mutex */ + mutex_enter(&scf_comtbl.all_mutex); + + /* Check target_id */ + if (target_id != 0) { + /* Invalid "target_id" */ + SC_DBG_DRV_TRACE(TC_MB_FLUSH | TC_ERRCD, __LINE__, &target_id, + sizeof (target_id)); + ret = EINVAL; + goto END_mb_flush; + } + + /* Get main table address from "mkey" */ + mainp = scf_dscp_mkey2mainp(mkey); + + /* Check mainp address */ + if (mainp == NULL) { + /* Invalid "mkey" */ + SC_DBG_DRV_TRACE(TC_MB_FLUSH | TC_ERRCD, __LINE__, &mkey, + sizeof (mkey)); + ret = EINVAL; + goto END_mb_flush; + } + + switch (mainp->status) { + case SCF_ST_EST_TXEND_RECV_WAIT: /* Main status (B0) */ + case SCF_ST_ESTABLISHED: /* Main status (C0) */ + case SCF_ST_EST_FINI_WAIT: /* Main status (C1) */ + switch (flush_type) { + case MB_FLUSH_SEND: + case MB_FLUSH_RECEIVE: + case MB_FLUSH_ALL: + if (flush_type != MB_FLUSH_RECEIVE) { + /* TxDSC buffer release */ + scf_dscp_txdscbuff_free(mainp); + } + if (flush_type != MB_FLUSH_SEND) { + /* RxDSC buffer release */ + scf_dscp_rxdscbuff_free(mainp); + + /* All queing event release */ + scf_dscp_event_queue_free(mainp); + + /* All receive buffer release */ + scf_dscp_rdata_free(mainp); + } + break; + + default: + + /* Invalid "flush_type" */ + SC_DBG_DRV_TRACE(TC_MB_FLUSH | TC_ERRCD, __LINE__, + &flush_type, sizeof (flush_type)); + ret = EINVAL; + break; + } + break; + + default: + /* Not open */ + SC_DBG_DRV_TRACE(TC_MB_FLUSH | TC_ERRCD, __LINE__, + &mainp->status, TC_INFO_SIZE); + ret = EBADF; + break; + } + +/* + * END_mb_flush + */ + END_mb_flush: + + /* Unlock driver mutex */ + mutex_exit(&scf_comtbl.all_mutex); + + SC_DBG_DRV_TRACE(TC_MB_FLUSH | TC_OUT, __LINE__, &ret, sizeof (ret)); + SCFDBGMSG1(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +/* + * scf_mb_ctrl() + * + * Description: This interface provides a way to obtain any specific + * properties of a mailbox, such as maximum size of the + * message which could be transmitted/received etc. + * + * Arguments: + * + * target_id - The target_id of the peer. It must be 0 on a Domain. + * mkey - Unique key corresponding to a mailbox. + * op - an operation. + * arg - argument specific to the operation. + * + * Return Values: returns 0 on success, otherwise any meaningful errno + * values are returned. + * + * EINVAL - Invalid values. + * EBADF - Specified target_id is not OPEN. + * ENOTSUP - Not supported. + */ +int +scf_mb_ctrl(target_id_t target_id, mkey_t mkey, uint32_t op, void *arg) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_mb_ctrl() " + scf_dscp_main_t *mainp; /* Main table address */ + uint32_t *wkarg; /* Working value : arg */ + int ret = 0; /* Return value */ + + SCFDBGMSG1(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start mkey = 0x%08x", + mkey); + SC_DBG_DRV_TRACE(TC_MB_CTRL | TC_IN, __LINE__, &mkey, sizeof (mkey)); + + /* Lock driver mutex */ + mutex_enter(&scf_comtbl.all_mutex); + + /* Check target_id */ + if (target_id != 0) { + /* Invalid "target_id" */ + SC_DBG_DRV_TRACE(TC_MB_CTRL | TC_ERRCD, __LINE__, &target_id, + sizeof (target_id)); + ret = EINVAL; + goto END_mb_ctrl; + } + + /* Get main table address from "mkey" */ + mainp = scf_dscp_mkey2mainp(mkey); + + /* Check mainp address */ + if (mainp == NULL) { + /* Invalid "mkey" */ + SC_DBG_DRV_TRACE(TC_MB_CTRL | TC_ERRCD, __LINE__, &mkey, + sizeof (mkey)); + ret = EINVAL; + goto END_mb_ctrl; + } + + switch (mainp->status) { + case SCF_ST_EST_TXEND_RECV_WAIT: /* Main status (B0) */ + case SCF_ST_ESTABLISHED: /* Main status (C0) */ + case SCF_ST_EST_FINI_WAIT: /* Main status (C1) */ + /* Check "arg" address */ + if (arg == NULL) { + /* Invalid "arg" */ + SC_DBG_DRV_TRACE(TC_MB_CTRL | TC_ERRCD, __LINE__, + &arg, sizeof (arg)); + ret = EINVAL; + goto END_mb_ctrl; + } + + /* Check "op" */ + switch (op) { + case SCF_MBOP_MAXMSGSIZE: + /* + * Notifies max send/receive + * data size + */ + SC_DBG_DRV_TRACE(TC_MB_CTRL, __LINE__, + &scf_dscp_comtbl.maxdatalen, + sizeof (scf_dscp_comtbl.maxdatalen)); + + /* Setsend/receive data size */ + wkarg = (uint32_t *)arg; + *wkarg = scf_dscp_comtbl.maxdatalen; + break; + + default: + /* Not support */ + SC_DBG_DRV_TRACE(TC_MB_CTRL, __LINE__, &op, + sizeof (op)); + ret = ENOTSUP; + break; + } + break; + + default: + /* Not open */ + SC_DBG_DRV_TRACE(TC_MB_CTRL | TC_ERRCD, + __LINE__, &mainp->status, TC_INFO_SIZE); + ret = EBADF; + break; + } + +/* + * END_mb_ctrl + */ + END_mb_ctrl: + + /* Unlock driver mutex */ + mutex_exit(&scf_comtbl.all_mutex); + + SC_DBG_DRV_TRACE(TC_MB_CTRL | TC_OUT, __LINE__, &ret, sizeof (ret)); + SCFDBGMSG1(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +/* + * SCF driver system control intafece function + */ + +/* + * scf_dscp_init() + * + * Description: DSCP control area initialization processing. + * + */ +void +scf_dscp_init(void) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_dscp_init() " + scf_dscp_main_t *mainp = NULL; /* Main table address */ + scf_dscp_dsc_t *dsc_p; /* TxDSC address */ + scf_tx_sram_t *sram_p; /* Tx SRAM address */ + int ii; /* Working value : counter */ + int jj; /* Working value : counter */ + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start"); + + /* + * DSCP common table initialization + */ + /* Set size value */ + scf_dscp_comtbl.maxdatalen = SCF_MB_MAXDATALEN; + scf_dscp_comtbl.total_buffsize = SCF_TOTAL_BUFFSIZE; + scf_dscp_comtbl.txbuffsize = SCF_TXBUFFSIZE; + scf_dscp_comtbl.rxbuffsize = SCF_RXBUFFSIZE; + + /* Set max count */ + scf_dscp_comtbl.txsram_maxcount = SCF_TX_SRAM_MAXCOUNT; + scf_dscp_comtbl.rxsram_maxcount = SCF_RX_SRAM_MAXCOUNT; + scf_dscp_comtbl.txdsc_maxcount = SCF_TXDSC_MAXCOUNT; + scf_dscp_comtbl.rxdsc_maxcount = SCF_RXDSC_MAXCOUNT; + scf_dscp_comtbl.txdsc_busycount = SCF_TXDSC_BUSYCOUNT; + scf_dscp_comtbl.rxdsc_busycount = SCF_RXDSC_BUSYCOUNT; + + /* Set re-try max count */ + scf_dscp_comtbl.tx_ackto_maxretry_cnt = SCF_TX_ACKTO_MAXRETRAYCOUNT; + scf_dscp_comtbl.tx_endto_maxretry_cnt = SCF_TX_ENDTO_MAXRETRAYCOUNT; + scf_dscp_comtbl.tx_busy_maxretry_cnt = SCF_TX_BUSY_MAXRETRAYCOUNT; + scf_dscp_comtbl.tx_interface_maxretry_cnt = SCF_TX_IF_MAXRETRAYCOUNT; + scf_dscp_comtbl.tx_nak_maxretry_cnt = SCF_TX_NAK_MAXRETRAYCOUNT; + scf_dscp_comtbl.tx_notsup_maxretry_cnt = SCF_TX_NOTSUP_MAXRETRAYCOUNT; + scf_dscp_comtbl.tx_prmerr_maxretry_cnt = SCF_TX_PRMERR_MAXRETRAYCOUNT; + scf_dscp_comtbl.tx_seqerr_maxretry_cnt = SCF_TX_SEQERR_MAXRETRAYCOUNT; + scf_dscp_comtbl.tx_other_maxretry_cnt = SCF_TX_OTHER_MAXRETRAYCOUNT; + scf_dscp_comtbl.tx_send_maxretry_cnt = SCF_TX_SEND_MAXRETRAYCOUNT; + + /* TxDSC/RxDSC table allocation */ + scf_dscp_comtbl.tx_dscsize = + sizeof (scf_dscp_dsc_t) * (scf_dscp_comtbl.txdsc_maxcount + + SCF_TXDSC_LOCALCOUNT); + scf_dscp_comtbl.tx_dscp = + (scf_dscp_dsc_t *)kmem_zalloc(scf_dscp_comtbl.tx_dscsize, + KM_SLEEP); + + scf_dscp_comtbl.rx_dscsize = + sizeof (scf_dscp_dsc_t) * (scf_dscp_comtbl.rxdsc_maxcount); + scf_dscp_comtbl.rx_dscp = + (scf_dscp_dsc_t *)kmem_zalloc(scf_dscp_comtbl.rx_dscsize, + KM_SLEEP); + + /* Tx SRAM table allocation */ + scf_dscp_comtbl.tx_sramsize = + sizeof (scf_tx_sram_t) * scf_dscp_comtbl.txsram_maxcount; + scf_dscp_comtbl.tx_sramp = + (scf_tx_sram_t *)kmem_zalloc(scf_dscp_comtbl.tx_sramsize, + KM_SLEEP); + + /* + * TxDSC table initialization + */ + /* Get TxDSC table address */ + dsc_p = scf_dscp_comtbl.tx_dscp; + for (ii = 0; ii < scf_dscp_comtbl.txdsc_maxcount; ii++, dsc_p++) { + /* Init SRAM offset */ + dsc_p->dinfo.base.offset = DSC_OFFSET_NOTHING; + } + + /* Set Tx offset */ + scf_dscp_comtbl.tx_first = 0; + scf_dscp_comtbl.tx_last = + (uint16_t)(scf_dscp_comtbl.txdsc_maxcount - 1); + scf_dscp_comtbl.tx_put = 0; + scf_dscp_comtbl.tx_get = 0; + scf_dscp_comtbl.tx_local = (uint16_t)scf_dscp_comtbl.txdsc_maxcount; + scf_dscp_comtbl.tx_dscp[scf_dscp_comtbl.tx_local].dinfo.base.offset = + DSC_OFFSET_NOTHING; + + /* + * Tx STAM offset initialization + */ + /* Get Tx SRAM table address */ + sram_p = scf_dscp_comtbl.tx_sramp; + for (ii = 0; ii < scf_dscp_comtbl.txsram_maxcount; ii++, sram_p++) { + /* Init SRAM offset */ + sram_p->offset = + (uint16_t)(scf_dscp_comtbl.txbuffsize * ii / + DSC_OFFSET_CONVERT); + } + + /* Set Tx SRAM offset */ + scf_dscp_comtbl.tx_sram_first = 0; + scf_dscp_comtbl.tx_sram_last = (scf_dscp_comtbl.txsram_maxcount - 1); + scf_dscp_comtbl.tx_sram_put = 0; + + /* + * RxDSC table initialization + */ + /* Set Rx offset */ + scf_dscp_comtbl.rx_first = 0; + scf_dscp_comtbl.rx_last = + (uint16_t)(scf_dscp_comtbl.rxdsc_maxcount - 1); + scf_dscp_comtbl.rx_put = 0; + scf_dscp_comtbl.rx_get = 0; + + /* + * Main table initialization + */ + /* Get Top main table address */ + mainp = &scf_dscp_comtbl.scf_dscp_main[0]; + + /* Check main table */ + for (ii = 0; ii < MBIF_MAX; ii++, mainp++) { + /* Set table id */ + mainp->id = ii & DSC_CNTL_MASK_ID; + + /* Set event/recive queue max count */ + mainp->ev_maxcount = SCF_MB_EVQUE_MAXCOUNT; + mainp->rd_maxcount = SCF_RDQUE_MAXCOUNT; + mainp->rd_busycount = SCF_RDQUE_BUSYCOUNT; + + /* Set fint() condition variable */ + cv_init(&mainp->fini_cv, NULL, CV_DRIVER, NULL); + mainp->cv_init_flag = FLAG_ON; + + /* event/receive data queue table allocation */ + mainp->ev_quesize = + sizeof (scf_event_que_t) * mainp->ev_maxcount; + mainp->ev_quep = + (scf_event_que_t *)kmem_zalloc(mainp->ev_quesize, + KM_SLEEP); + mainp->rd_datasize = + sizeof (scf_rdata_que_t) * mainp->ev_maxcount; + mainp->rd_datap = + (scf_rdata_que_t *)kmem_zalloc(mainp->rd_datasize, + KM_SLEEP); + + /* Event queue initialization */ + for (jj = 0; jj < mainp->ev_maxcount; jj++) { + mainp->ev_quep[jj].mevent = (scf_event_t)(-1); + } + mainp->ev_first = 0; + mainp->ev_last = (uint16_t)(mainp->ev_maxcount - 1); + mainp->ev_put = 0; + mainp->ev_get = 0; + + /* Receive data queue initialization */ + mainp->rd_first = 0; + mainp->rd_last = (uint16_t)(mainp->rd_maxcount - 1); + mainp->rd_put = 0; + mainp->rd_get = 0; + } + + /* Initialize success flag ON */ + scf_dscp_comtbl.dscp_init_flag = FLAG_ON; + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end"); +} + + +/* + * scf_dscp_fini() + * + * Description: DSCP control area release processing. + * + */ +void +scf_dscp_fini(void) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_dscp_fini() " + scf_dscp_main_t *mainp; /* Main table address */ + int ii; /* Working value : counter */ + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start"); + + /* + * Main table resources release + */ + /* Get Top main table address */ + mainp = &scf_dscp_comtbl.scf_dscp_main[0]; + + /* Check main table */ + for (ii = 0; ii < MBIF_MAX; ii++, mainp++) { + /* All receive buffer release */ + scf_dscp_rdata_free(mainp); + + /* Check fint() condition variable */ + if (mainp->cv_init_flag == FLAG_ON) { + /* Destroy fint() condition variable */ + cv_destroy(&mainp->fini_cv); + mainp->cv_init_flag = FLAG_OFF; + } + + /* Check event queue table allocation */ + if (mainp->ev_quep != NULL) { + /* Event queue table release */ + kmem_free(mainp->ev_quep, mainp->ev_quesize); + mainp->ev_quep = NULL; + } + + /* Check receive data table queue allocation */ + if (mainp->rd_datap != NULL) { + /* Receive data queue table release */ + kmem_free(mainp->rd_datap, mainp->rd_datasize); + mainp->rd_datap = NULL; + } + } + + /* + * DSCP common table resources release + */ + /* All timer stop */ + scf_timer_stop(SCF_TIMERCD_DSCP_ACK); + scf_timer_stop(SCF_TIMERCD_DSCP_END); + scf_timer_stop(SCF_TIMERCD_DSCP_CALLBACK); + scf_timer_stop(SCF_TIMERCD_DSCP_BUSY); + + /* All DSC buffer release */ + scf_dscp_dscbuff_free_all(); + + /* Check TxDSC table allocation */ + if (scf_dscp_comtbl.tx_dscp != NULL) { + /* TxDSC table release */ + kmem_free(scf_dscp_comtbl.tx_dscp, + scf_dscp_comtbl.tx_dscsize); + scf_dscp_comtbl.tx_dscp = NULL; + } + + /* Check RxDSC table allocation */ + if (scf_dscp_comtbl.rx_dscp != NULL) { + /* RxDSC table release */ + kmem_free(scf_dscp_comtbl.rx_dscp, + scf_dscp_comtbl.rx_dscsize); + scf_dscp_comtbl.rx_dscp = NULL; + } + + /* Check Tx SRAM table allocation */ + if (scf_dscp_comtbl.tx_sramp != NULL) { + /* Tx SRAM table release */ + kmem_free(scf_dscp_comtbl.tx_sramp, + scf_dscp_comtbl.tx_sramsize); + scf_dscp_comtbl.tx_sramp = NULL; + } + + /* Initialize success flag ON */ + scf_dscp_comtbl.dscp_init_flag = FLAG_OFF; + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end"); +} + + +/* + * scf_dscp_start() + * + * Description: DSCP interface start processing. + * + */ +void +scf_dscp_start(uint32_t factor) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_dscp_start() " + scf_dscp_main_t *mainp; /* Main table address */ + scf_dscp_dsc_t *dsc_p; /* TxDSC address */ + int ii; /* Working value : counter */ + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG1(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start factor = 0x%08x", + factor); + + /* Check local control data flag */ + if (scf_dscp_comtbl.tx_local_use_flag == FLAG_ON) { + /* Get local data TxDSC address */ + dsc_p = &scf_dscp_comtbl.tx_dscp[scf_dscp_comtbl.tx_local]; + + /* Change TxDSC status (SA0) */ + SCF_SET_DSC_STATUS(dsc_p, SCF_TX_ST_IDLE); + + /* TxREQ send exec flag OFF */ + scf_dscp_comtbl.tx_exec_flag = FLAG_OFF; + } + + /* Check pending send TxDSC */ + if (scf_dscp_comtbl.tx_dsc_count != 0) { + /* Get TxDSC address */ + dsc_p = &scf_dscp_comtbl.tx_dscp[scf_dscp_comtbl.tx_get]; + + /* Check TxDSC status */ + switch (dsc_p->status) { + case SCF_TX_ST_TXREQ_SEND_WAIT: /* TxDSC status (SB2) */ + /* Check send data length */ + if (dsc_p->dinfo.base.length != 0) { + /* Try again SRAM transfer */ + + /* Change TxDSC status (SB0) */ + SCF_SET_DSC_STATUS(dsc_p, + SCF_TX_ST_SRAM_TRANS_WAIT); + } + break; + + case SCF_TX_ST_TXACK_RECV_WAIT: /* TxDSC status (SC0) */ + case SCF_TX_ST_TXEND_RECV_WAIT: /* TxDSC status (SC1) */ + /* Try again TxREQ send */ + + /* Change TxDSC status (SB2) */ + SCF_SET_DSC_STATUS(dsc_p, SCF_TX_ST_TXREQ_SEND_WAIT); + break; + + default: + /* TxDSC status != SB2 or SC0 or SC1 is NOP */ + break; + } + } + + /* Check pending RxDSC */ + while (scf_dscp_comtbl.rx_dsc_count != 0) { + /* Get RxDSC address */ + dsc_p = &scf_dscp_comtbl.rx_dscp[scf_dscp_comtbl.rx_get]; + + /* Check receive data */ + if (dsc_p->dinfo.base.dscp_datap != NULL) { + /* Receive data release */ + kmem_free(dsc_p->dinfo.base.dscp_datap, + dsc_p->dinfo.base.length); + dsc_p->dinfo.base.dscp_datap = NULL; + } + + /* Change RxDSC status (RA0) */ + SCF_SET_DSC_STATUS(dsc_p, SCF_RX_ST_IDLE); + + /* Update Rx descriptor offset */ + if (scf_dscp_comtbl.rx_get == scf_dscp_comtbl.rx_last) { + scf_dscp_comtbl.rx_get = scf_dscp_comtbl.rx_first; + } else { + scf_dscp_comtbl.rx_get++; + } + + /* Update Rx descriptor count */ + scf_dscp_comtbl.rx_dsc_count--; + + /* RxREQ receive exec flag OFF */ + scf_dscp_comtbl.rx_exec_flag = FLAG_OFF; + } + + /* Check SCF path change */ + if (factor == FACTOR_PATH_CHG) { + /* Tx re-try counter initialization */ + scf_dscp_comtbl.tx_ackto_retry_cnt = 0; + scf_dscp_comtbl.tx_endto_retry_cnt = 0; + + scf_dscp_comtbl.tx_busy_retry_cnt = 0; + scf_dscp_comtbl.tx_interface_retry_cnt = 0; + scf_dscp_comtbl.tx_nak_retry_cnt = 0; + scf_dscp_comtbl.tx_notsuop_retry_cnt = 0; + scf_dscp_comtbl.tx_prmerr_retry_cnt = 0; + scf_dscp_comtbl.tx_seqerr_retry_cnt = 0; + scf_dscp_comtbl.tx_other_retry_cnt = 0; + scf_dscp_comtbl.tx_send_retry_cnt = 0; + + /* + * SCF path change flag ON : + * local control data send(DSCP_PATH) + */ + scf_dscp_comtbl.dscp_path_flag = FLAG_ON; + } else { + /* SCF online processing */ + + /* Get Top main table address */ + mainp = &scf_dscp_comtbl.scf_dscp_main[0]; + + /* Check main table */ + for (ii = 0; ii < MBIF_MAX; ii++, mainp++) { + /* Check main status */ + switch (mainp->status) { + case SCF_ST_EST_TXEND_RECV_WAIT: /* Main status (B0) */ + case SCF_ST_ESTABLISHED: /* Main status (C0) */ + /* + * Connect check flag ON : + * local control data send(CONN_CHK) + */ + mainp->conn_chk_flag = FLAG_ON; + break; + + default: + /* Connect check flag OFF */ + mainp->conn_chk_flag = FLAG_OFF; + break; + } + } + } + + /* Call send matrix */ + scf_dscp_send_matrix(); + + /* Call receive matrix */ + scf_dscp_recv_matrix(); + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end"); +} + + +/* + * scf_dscp_stop() + * + * Description: DSCP interface stop processing. + * + */ +void +scf_dscp_stop(uint32_t factor) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_dscp_stop() " + scf_dscp_main_t *mainp; /* Main table address */ + int ii; /* Working value : counter */ + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG1(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start factor = 0x%08x", + factor); + + /* Check stop factor */ + if ((factor == FACTOR_PATH_HALT) || (factor == FACTOR_PATH_STOP)) { + /* memo counter up */ + scf_dscp_comtbl.scf_stop_memo_cnt++; + + /* Get Top main table address */ + mainp = &scf_dscp_comtbl.scf_dscp_main[0]; + + /* Check main table */ + for (ii = 0; ii < MBIF_MAX; ii++, mainp++) { + /* Check main status */ + switch (mainp->status) { + case SCF_ST_EST_TXEND_RECV_WAIT: /* Main status (B0) */ + case SCF_ST_ESTABLISHED: /* Main status (C0) */ + /* SCF_MB_DISC_ERROR event queuing */ + scf_dscp_event_queue(mainp, SCF_MB_DISC_ERROR); + + /* Change main status (C1) */ + SCF_SET_STATUS(mainp, SCF_ST_EST_FINI_WAIT); + + break; + + case SCF_ST_CLOSE_TXEND_RECV_WAIT: + /* Main status (D0) */ + /* Signal to fini() wait */ + mainp->fini_wait_flag = FLAG_OFF; + cv_signal(&mainp->fini_cv); + SC_DBG_DRV_TRACE(TC_SIGNAL, __LINE__, + &mainp->fini_cv, sizeof (kcondvar_t)); + break; + + default: + /* Main status != B0 or C0 or D0 is NOP */ + break; + } + } + } + + /* Tx timer stop */ + scf_timer_stop(SCF_TIMERCD_DSCP_ACK); + scf_timer_stop(SCF_TIMERCD_DSCP_END); + scf_timer_stop(SCF_TIMERCD_DSCP_BUSY); + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end"); +} + + +/* + * scf_dscp_intr() + * + * Description: The corresponding function is called according to the + * interruption factor from SCF. + * + */ +void +scf_dscp_intr(scf_state_t *statep) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_dscp_intr() " + /* Working value : Interrupt check flag */ + int interrupt = FLAG_OFF; + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start"); + + /* Get DSR register */ + statep->reg_dsr = SCF_DDI_GET8(statep, statep->scf_regs_handle, + &statep->scf_regs->DSR); + SC_DBG_DRV_TRACE(TC_R_DSR, __LINE__, &statep->reg_dsr, + sizeof (statep->reg_dsr)); + + /* DSR register interrupt clear */ + SCF_DDI_PUT8(statep, statep->scf_regs_handle, &statep->scf_regs->DSR, + statep->reg_dsr); + SC_DBG_DRV_TRACE(TC_W_DSR, __LINE__, &statep->reg_dsr, + sizeof (statep->reg_dsr)); + + /* Regster read sync */ + scf_rs8 = SCF_DDI_GET8(statep, statep->scf_regs_handle, + &statep->scf_regs->DSR); + + SCF_DBG_TEST_INTR_DSCP_DSR(statep); + + SCFDBGMSG1(SCF_DBGFLAG_REG, "DSR = 0x%02x", statep->reg_dsr); + + if ((statep->reg_dsr & DSR_RxREQ) != 0) { /* RxREQ interrupt */ + SCFDBGMSG(SCF_DBGFLAG_DSCP, "RxREQ interrupt"); + + interrupt = FLAG_ON; + /* Get RxDCR register */ + statep->reg_rxdcr_c_flag = + SCF_DDI_GET16(statep, statep->scf_regs_handle, + &statep->scf_regs->RxDCR_C_FLAG); + SC_DBG_DRV_TRACE(TC_R_RxDCR_C_FLAG, __LINE__, + &statep->reg_rxdcr_c_flag, + sizeof (statep->reg_rxdcr_c_flag)); + + statep->reg_rxdcr_c_offset = + SCF_DDI_GET16(statep, statep->scf_regs_handle, + &statep->scf_regs->RxDCR_OFFSET); + SC_DBG_DRV_TRACE(TC_R_RxDCR_OFFSET, __LINE__, + &statep->reg_rxdcr_c_offset, + sizeof (statep->reg_rxdcr_c_offset)); + + statep->reg_rxdcr_c_length = + SCF_DDI_GET32(statep, statep->scf_regs_handle, + &statep->scf_regs->RxDCR_LENGTH); + SC_DBG_DRV_TRACE(TC_R_RxDCR_LENGTH, __LINE__, + &statep->reg_rxdcr_c_length, + sizeof (statep->reg_rxdcr_c_length)); + + /* SRAM trace */ + SCF_SRAM_TRACE(statep, DTC_DSCP_RXREQ); + + SCF_DBG_TEST_INTR_DSCP_RXTX(statep, statep->reg_dsr); + + SC_DBG_DRV_TRACE(TC_RxREQ, __LINE__, + &statep->reg_rxdcr_c_flag, 8); + + SCFDBGMSG3(SCF_DBGFLAG_REG, "RxDCR = 0x%04x 0x%04x 0x%08x", + statep->reg_rxdcr_c_flag, statep->reg_rxdcr_c_offset, + statep->reg_rxdcr_c_length); + + /* Call RxRERQ interrupt processing */ + scf_dscp_rxreq_recv(statep); + } + + if ((statep->reg_dsr & DSR_TxACK) != 0) { /* TxACK interrupt */ + SCFDBGMSG(SCF_DBGFLAG_DSCP, "TxACK interrupt"); + + interrupt = FLAG_ON; + + SC_DBG_DRV_TRACE(TC_TxACK, __LINE__, NULL, 0); + + /* SRAM trace */ + SCF_SRAM_TRACE(statep, DTC_DSCP_TXACK); + + /* Call TxACK interrupt processing */ + scf_dscp_txack_recv(statep); + } + + if ((statep->reg_dsr & DSR_TxEND) != 0) { /* TxEND interrupt */ + SCFDBGMSG(SCF_DBGFLAG_DSCP, "TxEND interrupt"); + + interrupt = FLAG_ON; + + /* Get TxDSR register */ + statep->reg_txdsr_c_flag = + SCF_DDI_GET16(statep, statep->scf_regs_handle, + &statep->scf_regs->TxDSR_C_FLAG); + SC_DBG_DRV_TRACE(TC_R_TxDSR_C_FLAG, __LINE__, + &statep->reg_txdsr_c_flag, + sizeof (statep->reg_txdsr_c_flag)); + + statep->reg_txdsr_c_offset = + SCF_DDI_GET16(statep, statep->scf_regs_handle, + &statep->scf_regs->TxDSR_OFFSET); + SC_DBG_DRV_TRACE(TC_R_TxDSR_OFFSET, __LINE__, + &statep->reg_txdsr_c_offset, + sizeof (statep->reg_txdsr_c_offset)); + + /* SRAM trace */ + SCF_SRAM_TRACE(statep, DTC_DSCP_TXEND); + + SCF_DBG_TEST_INTR_DSCP_RXTX(statep, DSR_TxEND); + + SC_DBG_DRV_TRACE(TC_TxEND, __LINE__, + &statep->reg_txdsr_c_flag, 4); + + SCFDBGMSG2(SCF_DBGFLAG_REG, "TxDSR = 0x%04x 0x%04x", + statep->reg_txdsr_c_flag, statep->reg_txdsr_c_offset); + + /* Call TxEND interrupt processing */ + scf_dscp_txend_recv(statep); + } + + if (interrupt == FLAG_OFF) { + SC_DBG_DRV_TRACE(TC_ERRCD, __LINE__, &statep->reg_dsr, + sizeof (statep->reg_dsr)); + statep->no_int_dsr_cnt++; + } + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end"); +} + + +/* + * Timeout function : from SCF driver timer contorol function + */ + +/* + * scf_dscp_ack_tout() + * + * Description: TxACK reception surveillance timeout processing is performed. + * SCF path change factor. + * + */ +void +scf_dscp_ack_tout(void) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_dscp_ack_tout() " + scf_dscp_dsc_t *dsc_p; /* TxDSC address */ + scf_state_t *statep; /* Soft state pointer */ + int path_ret; /* SCF path status return value */ + uchar_t cmd; + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start"); + + /* Check TxREQ send exec */ + if (scf_dscp_comtbl.tx_exec_flag == FLAG_OFF) { + goto END_dscp_ack_tout; + } + + /* memo counter up */ + scf_dscp_comtbl.tx_ackto_memo_cnt++; + + /* TxREQ send exec flag OFF */ + scf_dscp_comtbl.tx_exec_flag = FLAG_OFF; + + /* Check local control data flag */ + if (scf_dscp_comtbl.tx_local_use_flag == FLAG_OFF) { + /* Get TxDSC address */ + dsc_p = &scf_dscp_comtbl.tx_dscp[scf_dscp_comtbl.tx_get]; + } else { + /* Get local data TxDSC address */ + dsc_p = &scf_dscp_comtbl.tx_dscp[scf_dscp_comtbl.tx_local]; + } + + /* Check TxDSC status */ + if (dsc_p->status == SCF_TX_ST_TXACK_RECV_WAIT) { + /* TxDSC status (SC0) */ + /* Check re-try counter */ + if ((scf_dscp_comtbl.tx_ackto_retry_cnt < + scf_dscp_comtbl.tx_ackto_maxretry_cnt) && + (scf_dscp_comtbl.tx_send_retry_cnt < + scf_dscp_comtbl.tx_send_maxretry_cnt)) { + /* re-try count up */ + scf_dscp_comtbl.tx_ackto_retry_cnt++; + scf_dscp_comtbl.tx_send_retry_cnt++; + + /* Change TxDSC status (SB2) */ + SCF_SET_DSC_STATUS(dsc_p, SCF_TX_ST_TXREQ_SEND_WAIT); + + /* Call send matrix */ + scf_dscp_send_matrix(); + } else { + /* TxACK re-try timeout error */ + SC_DBG_DRV_TRACE(TC_ERRCD, __LINE__, + &scf_dscp_comtbl.tx_ackto_retry_cnt, + sizeof (scf_dscp_comtbl.tx_ackto_retry_cnt)); + + /* Get SCF path status */ + path_ret = scf_path_check(&statep); + + /* Check SCF path status */ + if (path_ret == SCF_PATH_ONLINE) { + cmd = (uchar_t)(dsc_p->dinfo.base.c_flag >> 8); + cmn_err(CE_WARN, + "%s,DSCP ack response timeout " + "occurred. " + "DSCP command = 0x%02x\n", + &statep->pathname[0], cmd); + + /* SRAM trace */ + SCF_SRAM_TRACE(statep, DTC_DSCP_ACKTO); + + /* SCF path change */ + statep->scf_herr |= HERR_DSCP_ACKTO; + scf_path_change(statep); + } + } + } + +/* + * END_dscp_ack_tout + */ + END_dscp_ack_tout: + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end"); +} + + +/* + * scf_dscp_end_tout() + * + * Description: TxEND reception surveillance timeout processing is performed. + * SCF path change factor. + * + */ +void +scf_dscp_end_tout(void) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_dscp_end_tout() " + scf_dscp_dsc_t *dsc_p; /* TxDSC address */ + scf_state_t *statep; /* Soft state pointer */ + int path_ret; /* SCF path status return value */ + uchar_t cmd; + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start"); + + /* Check TxREQ send exec */ + if (scf_dscp_comtbl.tx_exec_flag == FLAG_OFF) { + goto END_dscp_end_tout; + } + + /* memo counter up */ + scf_dscp_comtbl.tx_endto_memo_cnt++; + + /* TxREQ send exec flag OFF */ + scf_dscp_comtbl.tx_exec_flag = FLAG_OFF; + + /* Check local control data flag */ + if (scf_dscp_comtbl.tx_local_use_flag == FLAG_OFF) { + /* Get TxDSC address */ + dsc_p = &scf_dscp_comtbl.tx_dscp[scf_dscp_comtbl.tx_get]; + } else { + /* Get local data TxDSC address */ + dsc_p = &scf_dscp_comtbl.tx_dscp[scf_dscp_comtbl.tx_local]; + } + + /* Check TxDSC status */ + if (dsc_p->status == SCF_TX_ST_TXEND_RECV_WAIT) { + /* TxDSC status (SC1) */ + /* Check re-try counter */ + if ((scf_dscp_comtbl.tx_endto_retry_cnt < + scf_dscp_comtbl.tx_endto_maxretry_cnt) && + (scf_dscp_comtbl.tx_send_retry_cnt < + scf_dscp_comtbl.tx_send_maxretry_cnt)) { + /* re-try count up */ + scf_dscp_comtbl.tx_endto_retry_cnt++; + scf_dscp_comtbl.tx_send_retry_cnt++; + + /* Change TxDSC status (SB2) */ + SCF_SET_DSC_STATUS(dsc_p, SCF_TX_ST_TXREQ_SEND_WAIT); + + /* Call send matrix */ + scf_dscp_send_matrix(); + } else { + /* TxEND re-try timeout error */ + SC_DBG_DRV_TRACE(TC_ERRCD, __LINE__, + &scf_dscp_comtbl.tx_endto_retry_cnt, + sizeof (scf_dscp_comtbl.tx_endto_retry_cnt)); + + /* Get SCF path status */ + path_ret = scf_path_check(&statep); + + /* Check SCF path status */ + if (path_ret == SCF_PATH_ONLINE) { + cmd = (uchar_t)(dsc_p->dinfo.base.c_flag >> 8); + cmn_err(CE_WARN, + "%s,DSCP end response timeout " + "occurred. " + "DSCP command = 0x%02x\n", + &statep->pathname[0], cmd); + + /* SRAM trace */ + SCF_SRAM_TRACE(statep, DTC_DSCP_ENDTO); + + /* SCF path change */ + statep->scf_herr |= HERR_DSCP_ENDTO; + scf_path_change(statep); + } + } + } + +/* + * END_dscp_end_tout + */ + END_dscp_end_tout: + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end"); +} + + +/* + * scf_dscp_busy_tout() + * + * Description: Busy timeout performs TxREQ transmission again. + * + */ +void +scf_dscp_busy_tout(void) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_dscp_busy_tout() " + scf_dscp_dsc_t *dsc_p; /* TxDSC address */ + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start"); + + /* Check pending send TxDSC or local control TxDSC */ + if ((scf_dscp_comtbl.tx_dsc_count == 0) && + (scf_dscp_comtbl.tx_local_use_flag == FLAG_OFF)) { + goto END_dscp_busy_tout; + } + + /* Check local control data flag */ + if (scf_dscp_comtbl.tx_local_use_flag == FLAG_OFF) { + /* Get TxDSC address */ + dsc_p = &scf_dscp_comtbl.tx_dscp[scf_dscp_comtbl.tx_get]; + } else { + /* Get local data TxDSC address */ + dsc_p = &scf_dscp_comtbl.tx_dscp[scf_dscp_comtbl.tx_local]; + } + + /* Check TxDSC status */ + if (dsc_p->status == SCF_TX_ST_TXREQ_SEND_WAIT) { + /* TxDSC status (SB2) */ + /* Call send matrix */ + scf_dscp_send_matrix(); + } + +/* + * END_dscp_busy_tout + */ + END_dscp_busy_tout: + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end"); +} + + +/* + * scf_dscp_callback_tout() + * + * Description: Callbak timeout performs soft interrupt again. + * + */ +void +scf_dscp_callback_tout(void) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_dscp_callback_tout() " + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start"); + + /* Soft interrupt : call scf_dscp_callback() */ + if (mutex_tryenter(&scf_comtbl.si_mutex) != 0) { + scf_comtbl.scf_softintr_dscp_kicked = FLAG_ON; + ddi_trigger_softintr(scf_comtbl.scf_softintr_id); + mutex_exit(&scf_comtbl.si_mutex); + } + + /* Callback timer start */ + scf_timer_start(SCF_TIMERCD_DSCP_CALLBACK); + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end"); +} + + +/* + * scf_dscp_callback() + * + * Description: Event queue is taken out and a callback entry is called. + * + */ +void +scf_dscp_callback(void) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_dscp_callback() " + scf_dscp_main_t *mainp; /* Main table address */ + /* Working value : event_handler */ + void (*wkevent_handler)(scf_event_t, void *); + scf_event_t wkmevent; /* Working value : mevent */ + void *wkarg; /* Working value : arg */ + /* Working value : next event processing check flag */ + int event_flag = FLAG_OFF; + int ii; /* Working value : counter */ + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start"); + + /* Check callback entry exec flag */ + if (scf_dscp_comtbl.callback_exec_flag == FLAG_ON) { + goto END_dscp_callback; + } + + /* Set callback entry exec flag */ + scf_dscp_comtbl.callback_exec_flag = FLAG_ON; + +/* + * CALLBACK_START + */ + CALLBACK_START: + + /* Get Top main table address */ + mainp = &scf_dscp_comtbl.scf_dscp_main[0]; + /* Check all main table */ + for (ii = 0; ii < MBIF_MAX; ii++, mainp++) { + /* Check event count */ + if (mainp->ev_count != 0) { + /* Next event processing flag ON */ + event_flag = FLAG_ON; + + /* Get event info */ + wkmevent = mainp->ev_quep[mainp->ev_get].mevent; + + /* Update event queue offset */ + if (mainp->ev_get == mainp->ev_last) { + mainp->ev_get = mainp->ev_first; + } else { + mainp->ev_get++; + } + + /* Update event queue count */ + mainp->ev_count--; + + /* Get callback enntry and arg */ + wkevent_handler = mainp->event_handler; + wkarg = mainp->arg; + + /* Check event_handler address */ + if (wkevent_handler != NULL) { + /* Check main status */ + switch (mainp->status) { + case SCF_ST_ESTABLISHED: + /* Main status (C0) */ + case SCF_ST_EST_FINI_WAIT: + /* Main status (C1) */ + + /* Unlock driver mutex */ + mutex_exit(&scf_comtbl.all_mutex); + + /* Call event handler */ + wkevent_handler(wkmevent, wkarg); + + SC_DBG_DRV_TRACE(TC_MB_CALLBACK, + __LINE__, &wkmevent, + sizeof (wkmevent)); + SCFDBGMSG1(SCF_DBGFLAG_DSCP, + "DSCP callback mevent = %d", + wkmevent); + + /* Lock driver mutex */ + mutex_enter(&scf_comtbl.all_mutex); + break; + + default: + /* + * Main status != C0 or C1 is NOP + */ + break; + } + } + } + } + + /* Check next event processing */ + if (event_flag == FLAG_ON) { + event_flag = FLAG_OFF; + goto CALLBACK_START; + } + + /* Clear callback entry exec flag */ + scf_dscp_comtbl.callback_exec_flag = FLAG_OFF; + +/* + * END_dscp_callback + */ + END_dscp_callback: + + /* CALLBACK timer stop */ + scf_timer_stop(SCF_TIMERCD_DSCP_CALLBACK); + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end"); +} + + + +/* + * Interrupt function : from scf_dscp_intr() + */ + +/* + * scf_dscp_txack_recv() + * + * Description: TxACK reception processing is performed. + * + */ +/* ARGSUSED */ +void +scf_dscp_txack_recv(scf_state_t *statep) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_dscp_txack_recv() " + scf_dscp_dsc_t *dsc_p; /* TxDSC address */ + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start"); + + /* Check TxREQ send exec */ + if (scf_dscp_comtbl.tx_exec_flag == FLAG_OFF) { + goto END_dscp_txack_recv; + } + + /* Check local control data flag */ + if (scf_dscp_comtbl.tx_local_use_flag == FLAG_OFF) { + /* Get TxDSC address */ + dsc_p = &scf_dscp_comtbl.tx_dscp[scf_dscp_comtbl.tx_get]; + } else { + /* Get local data TxDSC address */ + dsc_p = &scf_dscp_comtbl.tx_dscp[scf_dscp_comtbl.tx_local]; + } + + /* Check TxDSC status */ + if (dsc_p->status == SCF_TX_ST_TXACK_RECV_WAIT) { + /* TxDSC status (SC0) */ + /* Error counter initialization */ + scf_dscp_comtbl.tx_ackto_retry_cnt = 0; + + /* TxACK timer stop */ + scf_timer_stop(SCF_TIMERCD_DSCP_ACK); + + /* TxEND timer start */ + scf_timer_start(SCF_TIMERCD_DSCP_END); + + /* Change TxDSC status (SC1) */ + SCF_SET_DSC_STATUS(dsc_p, SCF_TX_ST_TXEND_RECV_WAIT); + } + +/* + * END_dscp_txack_recv + */ + END_dscp_txack_recv: + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end"); +} + + +/* + * scf_dscp_txend_recv() + * + * Description: TxEND reception is received and processing is carried out by + * completion information. + * + */ +void +scf_dscp_txend_recv(scf_state_t *statep) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_dscp_txend_recv() " + scf_dscp_main_t *mainp; /* Main table address */ + scf_dscp_dsc_t *dsc_p; /* TxDSC address */ + scf_dscreg_t wk_dsc; /* Work TxDSC */ + /* Working value : TxDSC release check flag */ + int norel_txdsc = FLAG_OFF; + /* Working value : SCF path change flag */ + int path_change = FLAG_OFF; + int ii; /* Working value : counter */ + uchar_t cmd; + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start"); + + /* Check TxREQ send exec */ + if (scf_dscp_comtbl.tx_exec_flag == FLAG_OFF) { + goto END_dscp_txend_recv; + } + + /* Check local control data flag */ + if (scf_dscp_comtbl.tx_local_use_flag == FLAG_OFF) { + /* Get TxDSC address */ + dsc_p = &scf_dscp_comtbl.tx_dscp[scf_dscp_comtbl.tx_get]; + } else { + /* Get local data TxDSC address */ + dsc_p = &scf_dscp_comtbl.tx_dscp[scf_dscp_comtbl.tx_local]; + } + + /* Save TxDSR status information in TxDSC */ + wk_dsc.base.c_flag = statep->reg_txdsr_c_flag; + dsc_p->dinfo.bdsr.status = wk_dsc.bdsr.status; + SCFDBGMSG1(SCF_DBGFLAG_DSCP, "TxEND status = 0x%02x", + dsc_p->dinfo.bdsr.status); + + /* Check TxREQ offset and TxEND offset */ + if (dsc_p->dinfo.base.offset != statep->reg_txdsr_c_offset) { + goto END_dscp_txend_recv; + } + + /* TxACK and TxEND timer stop */ + scf_timer_stop(SCF_TIMERCD_DSCP_ACK); + scf_timer_stop(SCF_TIMERCD_DSCP_END); + + /* Get main table address from "id" */ + mainp = scf_dscp_id2mainp(dsc_p->dinfo.bdcr.id); + + /* + * Check mainp address or local control data(DSCP_PATH) + */ + if ((mainp == NULL) && + (dsc_p->dinfo.bdcr.id != DSC_CNTL_LOCAL)) { + goto END_dscp_txend_recv; + } + + cmd = (uchar_t)(dsc_p->dinfo.base.c_flag >> 8); + + /* Check TxDSC status */ + switch (dsc_p->status) { + case SCF_TX_ST_TXACK_RECV_WAIT: + /* TxDSC status (SC0) */ + case SCF_TX_ST_TXEND_RECV_WAIT: + /* TxDSC status (SC1) */ + /* Check TxREQ end status */ + switch (dsc_p->dinfo.bdsr.status) { + case DSC_STATUS_NORMAL: /* Normal end */ + /* Error counter initialization */ + scf_dscp_comtbl.tx_ackto_retry_cnt = 0; + scf_dscp_comtbl.tx_endto_retry_cnt = 0; + scf_dscp_comtbl.tx_busy_retry_cnt = 0; + scf_dscp_comtbl.tx_interface_retry_cnt = 0; + scf_dscp_comtbl.tx_nak_retry_cnt = 0; + scf_dscp_comtbl.tx_notsuop_retry_cnt = 0; + scf_dscp_comtbl.tx_prmerr_retry_cnt = 0; + scf_dscp_comtbl.tx_seqerr_retry_cnt = 0; + scf_dscp_comtbl.tx_other_retry_cnt = 0; + scf_dscp_comtbl.tx_send_retry_cnt = 0; + + /* Check local control data(DSCP_PATH) */ + if (dsc_p->dinfo.bdcr.id != DSC_CNTL_LOCAL) { + /* TxEND notice to main matrix */ + scf_dscp_txend_notice(mainp); + } + break; + + case DSC_STATUS_BUF_BUSY: /* Buffer busy */ + SC_DBG_DRV_TRACE(TC_ERRCD, __LINE__, + &dsc_p->dinfo.base.c_flag, TC_INFO_SIZE); + + /* memo counter up */ + scf_dscp_comtbl.tx_busy_memo_cnt++; + + /* Check re-try counter */ + if ((scf_dscp_comtbl.tx_busy_retry_cnt < + scf_dscp_comtbl.tx_busy_maxretry_cnt) && + (scf_dscp_comtbl.tx_send_retry_cnt < + scf_dscp_comtbl.tx_send_maxretry_cnt)) { + /* re-try count up */ + scf_dscp_comtbl.tx_busy_retry_cnt++; + scf_dscp_comtbl.tx_send_retry_cnt++; + + /* TxREQ busy timer start */ + scf_timer_start(SCF_TIMERCD_DSCP_BUSY); + + /* Change TxDSC status (SB2) */ + SCF_SET_DSC_STATUS(dsc_p, + SCF_TX_ST_TXREQ_SEND_WAIT); + + /* TxDSC not release */ + norel_txdsc = FLAG_ON; + } else { + /* Buffer busy end re-try error */ + cmn_err(CE_WARN, + "%s,Buffer busy occurred in XSCF. " + "DSCP command = 0x%02x\n", + &statep->pathname[0], cmd); + + /* Check local control data(DSCP_PATH) */ + if (dsc_p->dinfo.bdcr.id != DSC_CNTL_LOCAL) { + /* TxEND notice to main matrix */ + scf_dscp_txend_notice(mainp); + } else { + /* DSCP path change send flag ON */ + scf_dscp_comtbl.dscp_path_flag = + FLAG_ON; + } + } + break; + + case DSC_STATUS_INTERFACE: /* Interface error */ + SC_DBG_DRV_TRACE(TC_ERRCD, __LINE__, + &dsc_p->dinfo.base.c_flag, TC_INFO_SIZE); + + /* memo counter up */ + scf_dscp_comtbl.tx_interface_memo_cnt++; + + /* Check re-try counter */ + if ((scf_dscp_comtbl.tx_interface_retry_cnt < + scf_dscp_comtbl.tx_interface_maxretry_cnt) && + (scf_dscp_comtbl.tx_send_retry_cnt < + scf_dscp_comtbl.tx_send_maxretry_cnt)) { + /* re-try count up */ + scf_dscp_comtbl.tx_interface_retry_cnt++; + scf_dscp_comtbl.tx_send_retry_cnt++; + + /* Change TxDSC status (SB2) */ + SCF_SET_DSC_STATUS(dsc_p, + SCF_TX_ST_TXREQ_SEND_WAIT); + + /* TxDSC not release */ + norel_txdsc = FLAG_ON; + } else { + /* Interface error end re-try error */ + cmn_err(CE_WARN, + "%s,Detected the interface error by " + "XSCF. DSCP command = 0x%02x\n", + &statep->pathname[0], cmd); + + /* Set hard error flag */ + statep->scf_herr |= HERR_DSCP_INTERFACE; + + /* SCF path change flag ON */ + path_change = FLAG_ON; + } + break; + + case DSC_STATUS_CONN_NAK: /* Connection refusal */ + SC_DBG_DRV_TRACE(TC_ERRCD, __LINE__, + &dsc_p->dinfo.base.c_flag, TC_INFO_SIZE); + + /* memo counter up */ + scf_dscp_comtbl.tx_nak_memo_cnt++; + + /* Check re-try counter */ + if ((scf_dscp_comtbl.tx_nak_retry_cnt < + scf_dscp_comtbl.tx_nak_maxretry_cnt) && + (scf_dscp_comtbl.tx_send_retry_cnt < + scf_dscp_comtbl.tx_send_maxretry_cnt)) { + /* re-try count up */ + scf_dscp_comtbl.tx_nak_retry_cnt++; + scf_dscp_comtbl.tx_send_retry_cnt++; + + /* Change TxDSC status (SB2) */ + SCF_SET_DSC_STATUS(dsc_p, + SCF_TX_ST_TXREQ_SEND_WAIT); + + /* TxDSC not release */ + norel_txdsc = FLAG_ON; + } else { + /* Connection refusal end re-try error */ + + /* Check local control data(DSCP_PATH) */ + if (dsc_p->dinfo.bdcr.id != DSC_CNTL_LOCAL) { + /* TxEND notice to main matrix */ + scf_dscp_txend_notice(mainp); + } else { + /* Set hard error flag */ + statep->scf_herr |= HERR_DSCP_INTERFACE; + + /* SCF path change flag ON */ + path_change = FLAG_ON; + } + } + break; + + case DSC_STATUS_E_NOT_SUPPORT: /* Not support */ + SC_DBG_DRV_TRACE(TC_ERRCD, __LINE__, + &dsc_p->dinfo.base.c_flag, TC_INFO_SIZE); + + /* memo counter up */ + scf_dscp_comtbl.tx_notsuop_memo_cnt++; + + /* Check re-try counter */ + if ((scf_dscp_comtbl.tx_notsuop_retry_cnt < + scf_dscp_comtbl.tx_notsup_maxretry_cnt) && + (scf_dscp_comtbl.tx_send_retry_cnt < + scf_dscp_comtbl.tx_send_maxretry_cnt)) { + /* re-try count up */ + scf_dscp_comtbl.tx_notsuop_retry_cnt++; + scf_dscp_comtbl.tx_send_retry_cnt++; + + /* Change TxDSC status (SB2) */ + SCF_SET_DSC_STATUS(dsc_p, + SCF_TX_ST_TXREQ_SEND_WAIT); + + /* TxDSC not release */ + norel_txdsc = FLAG_ON; + } else { + /* Not support end re-try error */ + cmn_err(CE_WARN, + "%s,Detected the not support command " + "by XSCF. DSCP command = 0x%02x\n", + &statep->pathname[0], cmd); + + /* Check local control data(DSCP_PATH) */ + if (dsc_p->dinfo.bdcr.id != DSC_CNTL_LOCAL) { + /* TxEND notice to main matrix */ + scf_dscp_txend_notice(mainp); + } else { + /* DSCP path change send flag ON */ + scf_dscp_comtbl.dscp_path_flag = + FLAG_ON; + } + } + break; + + case DSC_STATUS_E_PARAM: /* Parameter error */ + SC_DBG_DRV_TRACE(TC_ERRCD, __LINE__, + &dsc_p->dinfo.base.c_flag, TC_INFO_SIZE); + + /* memo counter up */ + scf_dscp_comtbl.tx_prmerr_memo_cnt++; + + /* Check re-try counter */ + if ((scf_dscp_comtbl.tx_prmerr_retry_cnt < + scf_dscp_comtbl.tx_prmerr_maxretry_cnt) && + (scf_dscp_comtbl.tx_send_retry_cnt < + scf_dscp_comtbl.tx_send_maxretry_cnt)) { + /* re-try count up */ + scf_dscp_comtbl.tx_prmerr_retry_cnt++; + scf_dscp_comtbl.tx_send_retry_cnt++; + + /* Change TxDSC status (SB2) */ + SCF_SET_DSC_STATUS(dsc_p, + SCF_TX_ST_TXREQ_SEND_WAIT); + + /* TxDSC not release */ + norel_txdsc = FLAG_ON; + } else { + /* Parameter error end re-try error */ + cmn_err(CE_WARN, + "%s,Detected the invalid parameter by " + "XSCF. DSCP command = 0x%02x\n", + &statep->pathname[0], cmd); + + /* Check local control data(DSCP_PATH) */ + if (dsc_p->dinfo.bdcr.id != DSC_CNTL_LOCAL) { + /* TxEND notice to main matrix */ + scf_dscp_txend_notice(mainp); + } else { + /* DSCP path change send flag ON */ + scf_dscp_comtbl.dscp_path_flag = + FLAG_ON; + } + } + break; + + case DSC_STATUS_E_SEQUENCE: /* Sequence error */ + SC_DBG_DRV_TRACE(TC_ERRCD, __LINE__, + &dsc_p->dinfo.base.c_flag, TC_INFO_SIZE); + + /* memo counter up */ + scf_dscp_comtbl.tx_seqerr_memo_cnt++; + + /* Check re-try counter */ + if ((scf_dscp_comtbl.tx_seqerr_retry_cnt < + scf_dscp_comtbl.tx_seqerr_maxretry_cnt) && + (scf_dscp_comtbl.tx_send_retry_cnt < + scf_dscp_comtbl.tx_send_maxretry_cnt)) { + /* re-try count up */ + scf_dscp_comtbl.tx_seqerr_retry_cnt++; + scf_dscp_comtbl.tx_send_retry_cnt++; + + /* Change TxDSC status (SB2) */ + SCF_SET_DSC_STATUS(dsc_p, + SCF_TX_ST_TXREQ_SEND_WAIT); + + /* TxDSC not release */ + norel_txdsc = FLAG_ON; + } else { + /* Sequence error end re-try error */ + cmn_err(CE_WARN, + "%s,Detected the sequence error by " + "XSCF. DSCP command = 0x%02x\n", + &statep->pathname[0], cmd); + + /* Check local control data(DSCP_PATH) */ + if (dsc_p->dinfo.bdcr.id != DSC_CNTL_LOCAL) { + /* TxEND notice to main matrix */ + scf_dscp_txend_notice(mainp); + } else { + /* DSCP path change send flag ON */ + scf_dscp_comtbl.dscp_path_flag = + FLAG_ON; + } + } + break; + + default: /* Other status */ + SC_DBG_DRV_TRACE(TC_ERRCD, __LINE__, + &dsc_p->dinfo.base.c_flag, TC_INFO_SIZE); + + /* memo counter up */ + scf_dscp_comtbl.tx_other_memo_cnt++; + + /* Check re-try counter */ + if ((scf_dscp_comtbl.tx_other_retry_cnt < + scf_dscp_comtbl.tx_other_maxretry_cnt) && + (scf_dscp_comtbl.tx_send_retry_cnt < + scf_dscp_comtbl.tx_send_maxretry_cnt)) { + /* re-try count up */ + scf_dscp_comtbl.tx_other_retry_cnt++; + scf_dscp_comtbl.tx_send_retry_cnt++; + + /* Change TxDSC status (SB2) */ + SCF_SET_DSC_STATUS(dsc_p, + SCF_TX_ST_TXREQ_SEND_WAIT); + + /* TxDSC not release */ + norel_txdsc = FLAG_ON; + } else { + /* Other error end re-try error */ + cmn_err(CE_WARN, + "%s,Invalid status value was notified " + "from XSCF. DSCP command = 0x%02x, " + "Status value = 0x%02x\n", + &statep->pathname[0], cmd, + (uchar_t) + dsc_p->dinfo.base.c_flag); + + /* Check local control data(DSCP_PATH) */ + if (dsc_p->dinfo.bdcr.id != DSC_CNTL_LOCAL) { + /* TxEND notice to main matrix */ + scf_dscp_txend_notice(mainp); + } else { + /* DSCP path change send flag ON */ + scf_dscp_comtbl.dscp_path_flag = + FLAG_ON; + } + } + break; + } + break; + + default: + /* TxDSC status != SC0 or SC1 is NOP */ + break; + } + + /* Check TxDSC not release */ + if (norel_txdsc == FLAG_OFF) { + /* Check send data */ + if (dsc_p->dinfo.base.dscp_datap != NULL) { + /* Send data release */ + kmem_free(dsc_p->dinfo.base.dscp_datap, + dsc_p->dinfo.base.length); + dsc_p->dinfo.base.dscp_datap = NULL; + } + + /* Check SRAM data */ + if (dsc_p->dinfo.base.offset != DSC_OFFSET_NOTHING) { + /* Send SRAM data release */ + scf_dscp_sram_free(dsc_p->dinfo.base.offset); + dsc_p->dinfo.base.offset = DSC_OFFSET_NOTHING; + } + + /* Change TxDSC status (SA0) */ + SCF_SET_DSC_STATUS(dsc_p, SCF_TX_ST_IDLE); + + /* Check use local control TxDSC flag */ + if (scf_dscp_comtbl.tx_local_use_flag == FLAG_OFF) { + /* Update Tx descriptor offset */ + if (scf_dscp_comtbl.tx_get == scf_dscp_comtbl.tx_last) { + scf_dscp_comtbl.tx_get = + scf_dscp_comtbl.tx_first; + } else { + scf_dscp_comtbl.tx_get++; + } + + /* Update Tx descriptor count */ + scf_dscp_comtbl.tx_dsc_count--; + + /* Get Top main table address */ + mainp = &scf_dscp_comtbl.scf_dscp_main[0]; + /* Check main table */ + for (ii = 0; ii < MBIF_MAX; ii++, mainp++) { + /* Check putmsg busy release */ + if ((mainp->putmsg_busy_flag == FLAG_ON) && + (scf_dscp_comtbl.tx_dsc_count < + scf_dscp_comtbl.txdsc_busycount)) { + /* putmsg busy flag OFF */ + mainp->putmsg_busy_flag = FLAG_OFF; + + /* TxREL_BUSY notice to main matrix */ + scf_dscp_txrelbusy_notice(mainp); + } + } + } else { + /* Initialize use local control TxDSC flag */ + scf_dscp_comtbl.tx_local_use_flag = FLAG_OFF; + + /* DSCP path change send flag OFF */ + scf_dscp_comtbl.dscp_path_flag = FLAG_OFF; + } + } + /* TxREQ send exec flag OFF */ + scf_dscp_comtbl.tx_exec_flag = FLAG_OFF; + + /* Check SCF path change flag */ + if (path_change == FLAG_OFF) { + /* Call send matrix */ + scf_dscp_send_matrix(); + } else { + /* SCF path change */ + scf_path_change(statep); + } + +/* + * END_dscp_txend_recv + */ + END_dscp_txend_recv: + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end"); +} + + +/* + * scf_dscp_rxreq_recv() + * + * Description: TxREQ reception notifies to a main control matrix. + * + */ +void +scf_dscp_rxreq_recv(scf_state_t *statep) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_dscp_rxreq_recv() " + scf_dscp_main_t *mainp; /* Main table address */ + scf_dscp_dsc_t *dsc_p; /* RxDSC address */ + uint16_t offset_low; /* Working value : offset */ + uint16_t offset_hight; /* Working value : offset */ + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start"); + + /* Check pending RxDSC */ + if (scf_dscp_comtbl.rx_dsc_count == 0) { + /* Get RxDSC address */ + dsc_p = &scf_dscp_comtbl.rx_dscp[scf_dscp_comtbl.rx_put]; + + /* Save RxDCR information in RxDSC */ + dsc_p->dinfo.base.c_flag = statep->reg_rxdcr_c_flag; + dsc_p->dinfo.base.offset = statep->reg_rxdcr_c_offset; + dsc_p->dinfo.base.length = statep->reg_rxdcr_c_length; + dsc_p->dinfo.bdsr.status = DSC_STATUS_NORMAL; + dsc_p->dinfo.base.dscp_datap = NULL; + + /* Update Rx descriptor offset */ + if (scf_dscp_comtbl.rx_put == scf_dscp_comtbl.rx_last) { + scf_dscp_comtbl.rx_put = scf_dscp_comtbl.rx_first; + } else { + scf_dscp_comtbl.rx_put++; + } + + /* Update Rx descriptor count */ + scf_dscp_comtbl.rx_dsc_count++; + + /* RxREQ receive exec flag ON */ + scf_dscp_comtbl.rx_exec_flag = FLAG_ON; + + /* Get main table address from "id" */ + mainp = scf_dscp_id2mainp(dsc_p->dinfo.bdcr.id); + + offset_low = (uint16_t)(scf_dscp_comtbl.txbuffsize * + scf_dscp_comtbl.txsram_maxcount / DSC_OFFSET_CONVERT); + + SCF_DBG_MAKE_LOOPBACK(offset_low); + + offset_hight = + (uint16_t)(offset_low + scf_dscp_comtbl.rxbuffsize * + scf_dscp_comtbl.rxsram_maxcount / DSC_OFFSET_CONVERT); + + /* Check mainp address and offset */ + if ((mainp != NULL) && + (((dsc_p->dinfo.base.offset >= offset_low) && + (dsc_p->dinfo.base.offset < offset_hight)) || + (dsc_p->dinfo.base.offset == DSC_OFFSET_NOTHING))) { + /* RxREQ notice to main matrix */ + scf_dscp_rxreq_notice(mainp); + } else { + /* Invalid "id" or "offset" */ + SC_DBG_DRV_TRACE(TC_ERRCD, __LINE__, + &dsc_p->dinfo.base.c_flag, TC_INFO_SIZE); + SCFDBGMSG(SCF_DBGFLAG_DSCP, "Invalid id or offset"); + + /* Set end status : Parameter error */ + dsc_p->dinfo.bdsr.status = DSC_STATUS_E_PARAM; + + /* Change RxDSC status (RB3) */ + SCF_SET_DSC_STATUS(dsc_p, SCF_RX_ST_RXEND_SEND_WAIT); + + /* Call receive matrix */ + scf_dscp_recv_matrix(); + } + } + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end"); +} + + +/* + * Main and Tx/Rx interface function + */ + +/* + * scf_dscp_txend_notice() + * + * Description: The TxEND reception is notified of by Tx matrix and handle it + * with data code. + * + */ +void +scf_dscp_txend_notice(scf_dscp_main_t *mainp) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_dscp_txend_notice() " + scf_dscp_dsc_t *dsc_p; /* TxDSC address */ + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start"); + + /* Check local control data flag */ + if (scf_dscp_comtbl.tx_local_use_flag == FLAG_OFF) { + /* Get TxDSC address */ + dsc_p = &scf_dscp_comtbl.tx_dscp[scf_dscp_comtbl.tx_get]; + } else { + /* Get local data TxDSC address */ + dsc_p = &scf_dscp_comtbl.tx_dscp[scf_dscp_comtbl.tx_local]; + } + + /* TxREQ code check */ + switch (dsc_p->dinfo.bdcr.code) { + case DSC_CNTL_INIT_REQ: /* INIT_REQ */ + /* Check main status */ + if (mainp->status == SCF_ST_EST_TXEND_RECV_WAIT) { + /* Main status (B0) */ + /* Check end status */ + if (dsc_p->dinfo.bdsr.status == DSC_STATUS_NORMAL) { + /* SCF_MB_CONN_OK event queuing */ + scf_dscp_event_queue(mainp, SCF_MB_CONN_OK); + + /* Change main status (C0) */ + SCF_SET_STATUS(mainp, SCF_ST_ESTABLISHED); + } else { + /* Not normal end status */ + + /* SCF_MB_DISC_ERROR event queuing */ + scf_dscp_event_queue(mainp, SCF_MB_DISC_ERROR); + + /* Change main status (C1) */ + SCF_SET_STATUS(mainp, SCF_ST_EST_FINI_WAIT); + } + } + break; + + case DSC_CNTL_FINI_REQ: /* FINI_REQ */ + /* Check main status */ + if (mainp->status == SCF_ST_CLOSE_TXEND_RECV_WAIT) { + /* Main status (D0) */ + /* Signal to fini() wait */ + mainp->fini_wait_flag = FLAG_OFF; + cv_signal(&mainp->fini_cv); + SC_DBG_DRV_TRACE(TC_SIGNAL, __LINE__, &mainp->fini_cv, + sizeof (kcondvar_t)); + } + break; + + case DSC_CNTL_CONN_CHK: /* CONN_CHK */ + /* Check main status */ + switch (mainp->status) { + case SCF_ST_EST_TXEND_RECV_WAIT: /* Main status (B0) */ + case SCF_ST_ESTABLISHED: /* Main status (C0) */ + /* CONN_CHK flag OFF */ + mainp->conn_chk_flag = FLAG_OFF; + /* Check end status */ + if (dsc_p->dinfo.bdsr.status != DSC_STATUS_NORMAL) { + /* SCF_MB_DISC_ERROR event queuing */ + scf_dscp_event_queue(mainp, SCF_MB_DISC_ERROR); + + /* Change main status (C1) */ + SCF_SET_STATUS(mainp, SCF_ST_EST_FINI_WAIT); + } + break; + + default: + /* Main status != B0 or C0 is NOP */ + break; + } + break; + + case DSC_CNTL_DATA_REQ: /* DATA_REQ */ + /* Tx DATA_REQ ok counter up */ + mainp->memo_tx_data_req_ok_cnt++; + break; + + default: + /* Undefine TxREQ code is NOP */ + break; + } + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end"); +} + + +/* + * scf_dscp_txrelbusy_notice() + * + * Description: Tx busy release is notified of by Tx matrix and perform event + * queue processing. + * + */ +void +scf_dscp_txrelbusy_notice(scf_dscp_main_t *mainp) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_dscp_txrelbusy_notice() " + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start"); + + /* Check main status */ + if (mainp->status == SCF_ST_ESTABLISHED) { /* Main status (C0) */ + /* SCF_MB_SPACE event queuing */ + scf_dscp_event_queue(mainp, SCF_MB_SPACE); + } + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end"); +} + + +/* + * scf_dscp_rxreq_notice() + * + * Description: The RxREQ reception is notified of by Rx matrix and handle it + * with data code. + * + */ +void +scf_dscp_rxreq_notice(scf_dscp_main_t *mainp) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_dscp_rxreq_notice() " + scf_dscp_dsc_t *dsc_p; /* RxDSC address */ + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start"); + + /* Get RxDSC address */ + dsc_p = &scf_dscp_comtbl.rx_dscp[scf_dscp_comtbl.rx_get]; + + /* RxREQ code check */ + switch (dsc_p->dinfo.bdcr.code) { + case DSC_CNTL_INIT_REQ: /* INIT_REQ */ + /* Set end status : Not support */ + dsc_p->dinfo.bdsr.status = DSC_STATUS_E_NOT_SUPPORT; + + /* Change RxDSC status (RB3) */ + SCF_SET_DSC_STATUS(dsc_p, SCF_RX_ST_RXEND_SEND_WAIT); + + /* Call receive matrix */ + scf_dscp_recv_matrix(); + break; + + case DSC_CNTL_FINI_REQ: /* FINI_REQ */ + /* Check main status */ + switch (mainp->status) { + case SCF_ST_EST_TXEND_RECV_WAIT: /* Main status (B0) */ + case SCF_ST_ESTABLISHED: /* Main status (C0) */ + /* SCF_MB_DISC_ERROR event queuing */ + scf_dscp_event_queue(mainp, SCF_MB_DISC_ERROR); + + /* Change main status (C1) */ + SCF_SET_STATUS(mainp, SCF_ST_EST_FINI_WAIT); + break; + + default: + /* Main status != B0 or C0 is NOP */ + break; + } + + /* Set end status : Normal end */ + dsc_p->dinfo.bdsr.status = DSC_STATUS_NORMAL; + + /* Change RxDSC status (RB3) */ + SCF_SET_DSC_STATUS(dsc_p, SCF_RX_ST_RXEND_SEND_WAIT); + + /* Call receive matrix */ + scf_dscp_recv_matrix(); + break; + + case DSC_CNTL_DATA_REQ: /* DATA_REQ */ + /* Rx DATA_REQ counter up */ + mainp->memo_rx_data_req_cnt++; + + /* Check receive data length */ + if (dsc_p->dinfo.base.length <= scf_dscp_comtbl.maxdatalen) { + /* Check receive data queue space */ + if (mainp->rd_count < mainp->rd_busycount) { + /* Set end status : Normal end */ + dsc_p->dinfo.bdsr.status = DSC_STATUS_NORMAL; + + /* Check main status */ + if (mainp->status == SCF_ST_ESTABLISHED) { + /* Main status (C0) */ + /* Change RxDSC status (RB0) */ + SCF_SET_DSC_STATUS(dsc_p, + SCF_RX_ST_RXACK_SEND_WAIT); + } else { + /* Change RxDSC status (RB3) */ + SCF_SET_DSC_STATUS(dsc_p, + SCF_RX_ST_RXEND_SEND_WAIT); + } + } else { + /* No space of receive data queue */ + + /* Set end status : Buffer busy */ + dsc_p->dinfo.bdsr.status = DSC_STATUS_BUF_BUSY; + + /* Change RxDSC status (RB3) */ + SCF_SET_DSC_STATUS(dsc_p, + SCF_RX_ST_RXEND_SEND_WAIT); + } + } else { + /* Invalid deta length */ + SC_DBG_DRV_TRACE(TC_ERRCD, __LINE__, + &dsc_p->dinfo.base.length, + sizeof (dsc_p->dinfo.base.length)); + + /* Set end status : Parameter error */ + dsc_p->dinfo.bdsr.status = DSC_STATUS_E_PARAM; + + /* Change RxDSC status (RB3) */ + SCF_SET_DSC_STATUS(dsc_p, SCF_RX_ST_RXEND_SEND_WAIT); + } + + /* Call receive matrix */ + scf_dscp_recv_matrix(); + break; + + case DSC_CNTL_CONN_CHK: /* CONN_CHK */ + /* Check main status */ + if (mainp->status == SCF_ST_ESTABLISHED) { + /* Main status (C0) */ + /* Set end status : Normal end */ + dsc_p->dinfo.bdsr.status = DSC_STATUS_NORMAL; + } else { + /* Set end status : Connection refusal */ + dsc_p->dinfo.bdsr.status = DSC_STATUS_CONN_NAK; + } + + /* Change RxDSC status (RB3) */ + SCF_SET_DSC_STATUS(dsc_p, SCF_RX_ST_RXEND_SEND_WAIT); + + /* Call receive matrix */ + scf_dscp_recv_matrix(); + break; + + default: + /* Invalid RxREQ code */ + SC_DBG_DRV_TRACE(TC_ERRCD, __LINE__, &dsc_p->dinfo.base.c_flag, + TC_INFO_SIZE); + + /* Set end status : Parameter error */ + dsc_p->dinfo.bdsr.status = DSC_STATUS_E_PARAM; + + /* Change RxDSC status (RB3) */ + SCF_SET_DSC_STATUS(dsc_p, SCF_RX_ST_RXEND_SEND_WAIT); + + /* Call receive matrix */ + scf_dscp_recv_matrix(); + break; + } + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end"); +} + + +/* + * scf_dscp_rxdata_notice() + * + * Description: It is notified from a Rx control matrix, the received data are + * read from SRAM, + * and the notice of a receive data event is performed. + * + */ +void +scf_dscp_rxdata_notice(scf_dscp_main_t *mainp) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_dscp_rxdata_notice() " + scf_dscp_dsc_t *dsc_p; /* RxDSC address */ + scf_rdata_que_t *rdt_p; /* Receive data queue address */ + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start"); + + /* Get RxDSC address */ + dsc_p = &scf_dscp_comtbl.rx_dscp[scf_dscp_comtbl.rx_get]; + + /* Check main status */ + switch (mainp->status) { + case SCF_ST_ESTABLISHED: /* Main status (C0) */ + case SCF_ST_EST_FINI_WAIT: /* Main status (C1) */ + /* Check receive data queue space */ + if (mainp->rd_count < mainp->rd_busycount) { + /* Receive data queing */ + rdt_p = &mainp->rd_datap[mainp->rd_put]; + rdt_p->rdatap = dsc_p->dinfo.base.dscp_datap; + dsc_p->dinfo.base.dscp_datap = NULL; + rdt_p->length = dsc_p->dinfo.base.length; + + /* Update receive data queue offset */ + if (mainp->rd_put == mainp->rd_last) { + mainp->rd_put = mainp->rd_first; + } else { + mainp->rd_put++; + } + + /* Update receive data queue count */ + mainp->rd_count++; + + /* SCF_MB_MSG_DATA event queuing */ + scf_dscp_event_queue(mainp, SCF_MB_MSG_DATA); + + /* Rx DATA_REQ ok counter up */ + mainp->memo_rx_data_req_ok_cnt++; + } else { + /* No space of receive data queue */ + SC_DBG_DRV_TRACE(TC_ERRCD, __LINE__, &mainp->rd_count, + sizeof (mainp->rd_count)); + SCFDBGMSG(SCF_DBGFLAG_DSCP, + "No space of receive data queue"); + + /* Check receive data */ + if (dsc_p->dinfo.base.dscp_datap != NULL) { + /* Receive data release */ + kmem_free(dsc_p->dinfo.base.dscp_datap, + dsc_p->dinfo.base.length); + dsc_p->dinfo.base.dscp_datap = NULL; + } + + /* Set end status : Buffer busy */ + dsc_p->dinfo.bdsr.status = DSC_STATUS_BUF_BUSY; + + /* Change RxDSC status (RB3) */ + SCF_SET_DSC_STATUS(dsc_p, SCF_RX_ST_RXEND_SEND_WAIT); + } + break; + + case SCF_ST_CLOSE_TXEND_RECV_WAIT: /* Main status (D0) */ + /* Check receive data */ + if (dsc_p->dinfo.base.dscp_datap != NULL) { + /* Receive data release */ + kmem_free(dsc_p->dinfo.base.dscp_datap, + dsc_p->dinfo.base.length); + dsc_p->dinfo.base.dscp_datap = NULL; + } + + /* Set end status : Normal end */ + dsc_p->dinfo.bdsr.status = DSC_STATUS_NORMAL; + + /* Change RxDSC status (RB3) */ + SCF_SET_DSC_STATUS(dsc_p, SCF_RX_ST_RXEND_SEND_WAIT); + break; + + default: + SC_DBG_DRV_TRACE(TC_ERRCD, __LINE__, &mainp->status, + TC_INFO_SIZE); + SCFDBGMSG(SCF_DBGFLAG_DSCP, "Sequence error"); + + /* Check receive data */ + if (dsc_p->dinfo.base.dscp_datap != NULL) { + /* Receive data release */ + kmem_free(dsc_p->dinfo.base.dscp_datap, + dsc_p->dinfo.base.length); + dsc_p->dinfo.base.dscp_datap = NULL; + } + + /* Set end status : Sequence error */ + dsc_p->dinfo.bdsr.status = DSC_STATUS_E_SEQUENCE; + + /* Change RxDSC status (RB3) */ + SCF_SET_DSC_STATUS(dsc_p, SCF_RX_ST_RXEND_SEND_WAIT); + break; + } + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end"); +} + + +/* + * Tx subroutine function + */ + +/* + * scf_dscp_send_matrix() + * + * Description: The Request to Send by a Tx descriptor state is performed. + * + */ +void +scf_dscp_send_matrix(void) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_dscp_send_matrix() " + scf_dscp_main_t *mainp; /* Main table address */ + scf_dscp_dsc_t *dsc_p; /* TxDSC address */ + scf_state_t *statep; /* Soft state pointer */ + uint8_t *wk_in_p; /* Working value : input address */ + uint8_t *wk_out_p; /* Working value : output address */ + /* Working value : next processing check flag */ + int next_send_req = FLAG_OFF; + int path_ret; /* SCF path status return value */ + int timer_ret; /* Timer check return value */ + int ii; /* Working value : counter */ + uint16_t tx_local = scf_dscp_comtbl.tx_local; + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start"); + + SCF_DBG_MAKE_NO_DSCP_PATH(scf_dscp_comtbl.dscp_path_flag); + +/* + * SEND_MATRIX_START + */ + SEND_MATRIX_START: + + /* Check use local control TxDSC send */ + if ((scf_dscp_comtbl.tx_local_use_flag == FLAG_OFF) && + /* Check DSCP path change data send */ + (scf_dscp_comtbl.dscp_path_flag == FLAG_ON)) { + /* Set use local control TxDSC flag */ + scf_dscp_comtbl.tx_local_use_flag = FLAG_ON; + + /* Get local data TxDSC address */ + dsc_p = &scf_dscp_comtbl.tx_dscp[tx_local]; + + /* Make Tx descriptor : DSCP_PATH */ + dsc_p->dinfo.base.c_flag = DSC_FLAG_DEFAULT; + dsc_p->dinfo.base.offset = DSC_OFFSET_NOTHING; + dsc_p->dinfo.base.length = 0; + dsc_p->dinfo.base.dscp_datap = NULL; + dsc_p->dinfo.bdcr.id = DSC_CNTL_LOCAL; + dsc_p->dinfo.bdcr.code = DSC_CNTL_DSCP_PATH; + + /* Change TxDSC status (SB2) */ + SCF_SET_DSC_STATUS(dsc_p, SCF_TX_ST_TXREQ_SEND_WAIT); + } else if ((scf_dscp_comtbl.tx_local_use_flag == FLAG_OFF) && + (scf_dscp_comtbl.dscp_path_flag == FLAG_OFF)) { + /* Initialize use local control TxDSC flag */ + scf_dscp_comtbl.tx_local_use_flag = FLAG_OFF; + + /* Get TxDSC address */ + dsc_p = &scf_dscp_comtbl.tx_dscp[scf_dscp_comtbl.tx_get]; + + /* Get top main table address */ + mainp = &scf_dscp_comtbl.scf_dscp_main[0]; + for (ii = 0; ii < MBIF_MAX; ii++, mainp++) { + /* + * Check DSCP connect data send and not local + * control TxDSC send + */ + if ((mainp->conn_chk_flag == FLAG_OFF) || + (scf_dscp_comtbl.tx_local_use_flag == + FLAG_ON)) { + break; + } + /* Check main status */ + switch (mainp->status) { + case SCF_ST_EST_TXEND_RECV_WAIT: + /* Main status (B0) */ + case SCF_ST_ESTABLISHED: + /* Main status (C0) */ + /* + * Set use local control TxDSC flag + */ + scf_dscp_comtbl.tx_local_use_flag = FLAG_ON; + + /* + * Get local data TxDSC address + */ + dsc_p = &scf_dscp_comtbl.tx_dscp[tx_local]; + + /* + * Make Tx descriptor : CONN_CHK + */ + dsc_p->dinfo.base.c_flag = DSC_FLAG_DEFAULT; + dsc_p->dinfo.base.offset = DSC_OFFSET_NOTHING; + dsc_p->dinfo.base.length = 0; + dsc_p->dinfo.base.dscp_datap = NULL; + dsc_p->dinfo.bdcr.id = mainp->id & 0x0f; + dsc_p->dinfo.bdcr.code = DSC_CNTL_CONN_CHK; + + /* Change TxDSC status (SB2) */ + SCF_SET_DSC_STATUS(dsc_p, + SCF_TX_ST_TXREQ_SEND_WAIT); + break; + + default: + /* + * Clear DSCP connect check flag + */ + mainp->conn_chk_flag = FLAG_OFF; + break; + } + } + } else { + /* Get local data TxDSC address */ + dsc_p = &scf_dscp_comtbl.tx_dscp[tx_local]; + } + + /* Check pending send TxDSC or local control TxDSC */ + if ((scf_dscp_comtbl.tx_dsc_count == 0) && + (scf_dscp_comtbl.tx_local_use_flag == FLAG_OFF)) { + goto END_dscp_send_matrix; + } + + /* Get SCF path status */ + path_ret = scf_path_check(&statep); + /* Check TxDSC status */ + switch (dsc_p->status) { + case SCF_TX_ST_IDLE: /* TxDSC status (SA0) */ + /* TxDSC status == SA0 is next processing */ + if (scf_dscp_comtbl.tx_local_use_flag == FLAG_OFF) { + /* Update Tx descriptor offset */ + if (scf_dscp_comtbl.tx_get == scf_dscp_comtbl.tx_last) { + scf_dscp_comtbl.tx_get = + scf_dscp_comtbl.tx_first; + } else { + scf_dscp_comtbl.tx_get++; + } + + /* Update Tx descriptor count */ + scf_dscp_comtbl.tx_dsc_count--; + } else { + /* Initialize use local control TxDSC flag */ + scf_dscp_comtbl.tx_local_use_flag = FLAG_OFF; + } + + /* Next processing flag ON */ + next_send_req = FLAG_ON; + break; + + case SCF_TX_ST_SRAM_TRANS_WAIT: /* TxDSC status (SB0) */ + /* Check SCF path status */ + if (path_ret != SCF_PATH_ONLINE) { + break; + } + /* Data copy to SRAM */ + ii = dsc_p->dinfo.base.offset * DSC_OFFSET_CONVERT; + wk_in_p = (uint8_t *)dsc_p->dinfo.base.dscp_datap; + wk_out_p = (uint8_t *)&statep->scf_dscp_sram->DATA[ii]; + for (ii = 0; ii < dsc_p->dinfo.base.length; + ii++, wk_in_p++, wk_out_p++) { + SCF_DDI_PUT8(statep, statep->scf_dscp_sram_handle, + wk_out_p, *wk_in_p); + } + + /* Change TxDSC status (SB2) */ + SCF_SET_DSC_STATUS(dsc_p, SCF_TX_ST_TXREQ_SEND_WAIT); + + /* Next processing flag ON */ + next_send_req = FLAG_ON; + break; + + case SCF_TX_ST_TXREQ_SEND_WAIT: /* TxDSC status (SB2) */ + /* Get timer status */ + timer_ret = scf_timer_check(SCF_TIMERCD_DSCP_BUSY); + /* Check TxREQ busy timer exec */ + if (timer_ret == SCF_TIMER_EXEC) { + break; + } + /* Check SCF path status */ + if (path_ret != SCF_PATH_ONLINE) { + break; + } + /* Check TxREQ send exec */ + if (scf_dscp_comtbl.tx_exec_flag == FLAG_OFF) { + /* TxREQ send */ + scf_dscp_txreq_send(statep, dsc_p); + + /* Check send data length */ + if (dsc_p->dinfo.base.length != 0) { + /* TxACK timer start */ + scf_timer_start(SCF_TIMERCD_DSCP_ACK); + + /* + * Change TxDSC status (SC0) + */ + SCF_SET_DSC_STATUS(dsc_p, + SCF_TX_ST_TXACK_RECV_WAIT); + } else { + /* TxEND timer start */ + scf_timer_start(SCF_TIMERCD_DSCP_END); + + /* + * Change TxDSC status (SC1) + */ + SCF_SET_DSC_STATUS(dsc_p, + SCF_TX_ST_TXEND_RECV_WAIT); + } + } + break; + + default: + /* TxDSC status != SA0 or SB0 or SB2 is NOP */ + break; + } + + /* Check next send processing */ + if (next_send_req == FLAG_ON) { + next_send_req = FLAG_OFF; + goto SEND_MATRIX_START; + } + +/* + * END_dscp_send_matrix + */ + END_dscp_send_matrix: + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end"); +} + + +/* + * scf_dscp_txreq_send() + * + * Description: TxREQ is transmitted by hard access. + * + */ +void +scf_dscp_txreq_send(scf_state_t *statep, scf_dscp_dsc_t *dsc_p) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_dscp_txreq_send() " + uint8_t *wk_in_p; /* Working value : input address */ + uint8_t *wk_out_p; /* Working value : output address */ + uint32_t wkleng; /* Working value : length */ + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start"); + + /* Set control flag */ + dsc_p->dinfo.bdsr.status = 0; + dsc_p->dinfo.base.c_flag |= DSC_FLAG_DEFAULT; + + /* Write TxDCR register */ + statep->reg_txdcr_c_flag = dsc_p->dinfo.base.c_flag; + SCF_DDI_PUT16(statep, statep->scf_regs_handle, + &statep->scf_regs->TxDCR_C_FLAG, statep->reg_txdcr_c_flag); + SC_DBG_DRV_TRACE(TC_W_TxDCR_C_FLAG, __LINE__, + &statep->reg_txdcr_c_flag, sizeof (statep->reg_txdcr_c_flag)); + + statep->reg_txdcr_c_offset = dsc_p->dinfo.base.offset; + SCF_DDI_PUT16(statep, statep->scf_regs_handle, + &statep->scf_regs->TxDCR_OFFSET, statep->reg_txdcr_c_offset); + SC_DBG_DRV_TRACE(TC_W_TxDCR_OFFSET, __LINE__, + &statep->reg_txdcr_c_offset, + sizeof (statep->reg_txdcr_c_offset)); + + statep->reg_txdcr_c_length = dsc_p->dinfo.base.length; + SCF_DDI_PUT32(statep, statep->scf_regs_handle, + &statep->scf_regs->TxDCR_LENGTH, statep->reg_txdcr_c_length); + SC_DBG_DRV_TRACE(TC_W_TxDCR_LENGTH, __LINE__, + &statep->reg_txdcr_c_length, + sizeof (statep->reg_txdcr_c_length)); + + /* Write DCR register : TxREQ interrupt */ + statep->reg_dcr = DCR_TxREQ; + SCF_DDI_PUT8(statep, statep->scf_regs_handle, + &statep->scf_regs->DCR, statep->reg_dcr); + SC_DBG_DRV_TRACE(TC_W_DCR, __LINE__, &statep->reg_dcr, + sizeof (statep->reg_dcr)); + + /* Register read sync */ + scf_rs8 = SCF_DDI_GET8(statep, statep->scf_regs_handle, + &statep->scf_regs->DCR); + + SC_DBG_DRV_TRACE(TC_TxREQ, __LINE__, &statep->reg_txdcr_c_flag, 8); + + SCFDBGMSG1(SCF_DBGFLAG_REG, "DCR = 0x%02x", statep->reg_dcr); + SCFDBGMSG3(SCF_DBGFLAG_REG, "TxDCR = 0x%04x 0x%04x 0x%08x", + statep->reg_txdcr_c_flag, statep->reg_txdcr_c_offset, + statep->reg_txdcr_c_length); + + /* TxREQ send exec flag ON */ + scf_dscp_comtbl.tx_exec_flag = FLAG_ON; + + /* SRAM trace */ + SCF_SRAM_TRACE(statep, DTC_DSCP_TXREQ); + if (dsc_p->dinfo.base.length != 0) { + wk_in_p = (uint8_t *)dsc_p->dinfo.base.dscp_datap; + wk_out_p = (uint8_t *)&statep->memo_scf_drvtrc.INFO[0]; + if (dsc_p->dinfo.base.length > + sizeof (statep->memo_scf_drvtrc.INFO)) { + wkleng = sizeof (statep->memo_scf_drvtrc.INFO); + } else { + wkleng = dsc_p->dinfo.base.length; + } + bcopy(wk_in_p, wk_out_p, wkleng); + SCF_SRAM_TRACE(statep, DTC_DSCP_SENDDATA); + } + + SCF_DBG_TEST_TXREQ_SEND(statep, dsc_p); + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end"); +} + + +/* + * Rx subroutine function + */ + +/* + * scf_dscp_recv_matrix() + * + * Description: TxREQ received performs the corresponding response request. + * + */ +void +scf_dscp_recv_matrix(void) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_dscp_recv_matrix() " + scf_dscp_main_t *mainp; /* Main table address */ + scf_dscp_dsc_t *dsc_p; /* TxDSC address */ + scf_state_t *statep; /* Soft state pointer */ + caddr_t wkaddr; /* Working value : buffer address */ + uint8_t *wk_in_p; /* Working value : input address */ + uint8_t *wk_out_p; /* Working value : output address */ + uint32_t wkleng; /* Working value : length */ + uint32_t info_size; + /* Working value : next receive processing check flag */ + int next_resp_req = FLAG_OFF; + int path_ret; /* SCF path status return value */ + int ii; /* Working value : counter */ + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start"); + +/* + * RECV_MATRIX_START + */ + RECV_MATRIX_START: + + /* Check pending RxDSC */ + if (scf_dscp_comtbl.rx_dsc_count == 0) { + goto END_dscp_recv_matrix; + } + + /* Get RxDSC address */ + dsc_p = &scf_dscp_comtbl.rx_dscp[scf_dscp_comtbl.rx_get]; + + /* Get SCF path status */ + path_ret = scf_path_check(&statep); + + /* Check RxDSC status */ + switch (dsc_p->status) { + case SCF_RX_ST_RXACK_SEND_WAIT: /* RxDSC status (RB0) */ + /* Check SCF path status */ + if (path_ret != SCF_PATH_ONLINE) { + break; + } + /* Check receive data length */ + if (dsc_p->dinfo.base.length != 0) { + /* Rx buffer allocation */ + wkaddr = (caddr_t)kmem_zalloc(dsc_p->dinfo.base.length, + KM_NOSLEEP); + + /* Set Rx buffer address */ + dsc_p->dinfo.base.dscp_datap = wkaddr; + + /* RxACK send */ + scf_dscp_rxack_send(statep); + + /* Change RxDSC status (RB1) */ + SCF_SET_DSC_STATUS(dsc_p, + SCF_RX_ST_SRAM_TRANS_WAIT); + } else { + /* Change RxDSC status (RB3) */ + SCF_SET_DSC_STATUS(dsc_p, SCF_RX_ST_RXEND_SEND_WAIT); + break; + } + /* Next receive processing flag ON */ + next_resp_req = FLAG_ON; + + break; + + case SCF_RX_ST_SRAM_TRANS_WAIT: /* RxDSC status (RB1) */ + /* Check SCF path status */ + if (path_ret != SCF_PATH_ONLINE) { + break; + } + /* Get main table address from "id" */ + mainp = scf_dscp_id2mainp(dsc_p->dinfo.bdcr.id); + + /* Check mainp address */ + if (mainp != NULL) { + /* Data copy from SRAM */ + ii = dsc_p->dinfo.base.offset * DSC_OFFSET_CONVERT; + wk_in_p = &statep->scf_dscp_sram->DATA[ii]; + wk_out_p = (uint8_t *)dsc_p->dinfo.base.dscp_datap; + for (ii = 0; ii < dsc_p->dinfo.base.length; ii++, + wk_in_p++, wk_out_p++) { + *wk_out_p = SCF_DDI_GET8(statep, + statep->scf_dscp_sram_handle, wk_in_p); + } + + /* Set end status : Normal end */ + dsc_p->dinfo.bdsr.status = DSC_STATUS_NORMAL; + + /* Change RxDSC status (RB3) */ + SCF_SET_DSC_STATUS(dsc_p, SCF_RX_ST_RXEND_SEND_WAIT); + + /* STAM trace */ + info_size = sizeof (statep->memo_scf_drvtrc.INFO); + if (dsc_p->dinfo.base.length != 0) { + wk_in_p = + (uint8_t *)dsc_p->dinfo.base.dscp_datap; + wk_out_p = &statep->memo_scf_drvtrc.INFO[0]; + if (dsc_p->dinfo.base.length > info_size) { + wkleng = info_size; + } else { + wkleng = dsc_p->dinfo.base.length; + } + bcopy(wk_in_p, wk_out_p, wkleng); + SCF_SRAM_TRACE(statep, DTC_DSCP_RECVDATA); + } + + /* Receive data notice to main matrix */ + scf_dscp_rxdata_notice(mainp); + } else { + /* Invalid "id" */ + SC_DBG_DRV_TRACE(TC_ERRCD, __LINE__, + &dsc_p->dinfo.base.c_flag, TC_INFO_SIZE); + SCFDBGMSG(SCF_DBGFLAG_DSCP, "Invalid id"); + + /* Set end status : Parameter error */ + dsc_p->dinfo.bdsr.status = DSC_STATUS_E_PARAM; + + /* Change RxDSC status (RB3) */ + SCF_SET_DSC_STATUS(dsc_p, SCF_RX_ST_RXEND_SEND_WAIT); + } + + /* Next receive processing flag ON */ + next_resp_req = FLAG_ON; + break; + + case SCF_RX_ST_RXEND_SEND_WAIT: /* RxDSC status (RB3) */ + /* Is SCF path online? */ + if (path_ret != SCF_PATH_ONLINE) { + break; + } + /* RxEND send */ + scf_dscp_rxend_send(statep, dsc_p); + + /* Change RxDSC status (RA0) */ + SCF_SET_DSC_STATUS(dsc_p, SCF_RX_ST_IDLE); + + /* Update Rx descriptor offset */ + if (scf_dscp_comtbl.rx_get == scf_dscp_comtbl.rx_last) { + scf_dscp_comtbl.rx_get = scf_dscp_comtbl.rx_first; + } else { + scf_dscp_comtbl.rx_get++; + } + + /* Update Rx descriptor count */ + scf_dscp_comtbl.rx_dsc_count--; + + /* RxREQ receive exec flag OFF */ + scf_dscp_comtbl.rx_exec_flag = FLAG_OFF; + break; + + default: + /* RxDSC status == RA0 is NOP */ + break; + } + + /* Check next receive processing */ + if (next_resp_req == FLAG_ON) { + next_resp_req = FLAG_OFF; + goto RECV_MATRIX_START; + } + +/* + * END_dscp_recv_matrix + */ + END_dscp_recv_matrix: + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end"); +} + + +/* + * scf_dscp_rxack_send() + * + * Description: RxACK is transmitted by hard access. + * + */ +void +scf_dscp_rxack_send(scf_state_t *statep) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_dscp_rxack_send() " + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start"); + + /* Write DCR register : RxACK interrupt */ + statep->reg_dcr = DCR_RxACK; + SCF_DDI_PUT8(statep, statep->scf_regs_handle, + &statep->scf_regs->DCR, statep->reg_dcr); + SC_DBG_DRV_TRACE(TC_W_DCR, __LINE__, &statep->reg_dcr, + sizeof (statep->reg_dcr)); + + /* Register read sync */ + scf_rs8 = SCF_DDI_GET8(statep, statep->scf_regs_handle, + &statep->scf_regs->DCR); + + SC_DBG_DRV_TRACE(TC_RxACK, __LINE__, NULL, 0); + + SCFDBGMSG1(SCF_DBGFLAG_REG, "DCR = 0x%02x", statep->reg_dcr); + + /* SRAM trace */ + SCF_SRAM_TRACE(statep, DTC_DSCP_RXACK); + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end"); +} + + +/* + * scf_dscp_rxend_send() + * + * Description: RxEND is transmitted by hard access. + * + */ +void +scf_dscp_rxend_send(scf_state_t *statep, scf_dscp_dsc_t *dsc_p) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_dscp_rxend_send() " + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start"); + + /* Write RxDSR register */ + statep->reg_rxdsr_c_flag = dsc_p->dinfo.base.c_flag; + SCF_DDI_PUT16(statep, statep->scf_regs_handle, + &statep->scf_regs->RxDSR_C_FLAG, statep->reg_rxdsr_c_flag); + SC_DBG_DRV_TRACE(TC_W_RxDSR_C_FLAG, __LINE__, &statep->reg_rxdsr_c_flag, + sizeof (statep->reg_rxdsr_c_flag)); + + statep->reg_rxdsr_c_offset = dsc_p->dinfo.base.offset; + SCF_DDI_PUT16(statep, statep->scf_regs_handle, + &statep->scf_regs->RxDSR_OFFSET, statep->reg_rxdsr_c_offset); + SC_DBG_DRV_TRACE(TC_W_RxDSR_OFFSET, __LINE__, + &statep->reg_rxdsr_c_offset, + sizeof (statep->reg_rxdsr_c_offset)); + + /* Write DCR register : RxEND interrupt */ + statep->reg_dcr = DCR_RxEND; + SCF_DDI_PUT8(statep, statep->scf_regs_handle, + &statep->scf_regs->DCR, statep->reg_dcr); + SC_DBG_DRV_TRACE(TC_W_DCR, __LINE__, &statep->reg_dcr, + sizeof (statep->reg_dcr)); + + /* Register read sync */ + scf_rs8 = SCF_DDI_GET8(statep, statep->scf_regs_handle, + &statep->scf_regs->DCR); + + SC_DBG_DRV_TRACE(TC_RxEND, __LINE__, &statep->reg_rxdsr_c_flag, 4); + + SCFDBGMSG1(SCF_DBGFLAG_REG, "DCR = 0x%02x", statep->reg_dcr); + SCFDBGMSG2(SCF_DBGFLAG_REG, "RxDSR = 0x%04x 0x%04x", + statep->reg_rxdsr_c_flag, statep->reg_rxdsr_c_offset); + + /* SRAM trace */ + SCF_SRAM_TRACE(statep, DTC_DSCP_RXEND); + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end"); +} + + +/* + * subroutine function + */ + +/* + * scf_dscp_dscbuff_free_all() + * + * Description: All descripter buffer release processing. + * + */ +void +scf_dscp_dscbuff_free_all(void) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_dscp_dscbuff_free_all() " + scf_dscp_dsc_t *dsc_p; /* TxDSC address */ + int ii; /* Working value : counter */ + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start"); + + /* Get TxDSC address */ + dsc_p = scf_dscp_comtbl.tx_dscp; + + if (dsc_p != NULL) { + /* Check TxDSC */ + for (ii = 0; ii < scf_dscp_comtbl.txdsc_maxcount; ii++, + dsc_p++) { + /* Check TxDSC status */ + if (dsc_p->status == SCF_TX_ST_IDLE) { + continue; + } + /* TxDSC status not (SA0) */ + /* Check send data */ + if (dsc_p->dinfo.base.dscp_datap != NULL) { + /* Send data release */ + kmem_free(dsc_p->dinfo.base.dscp_datap, + dsc_p->dinfo.base.length); + dsc_p->dinfo.base.dscp_datap = NULL; + } + + /* Check SRAM data */ + if (dsc_p->dinfo.base.offset != DSC_OFFSET_NOTHING) { + /* Send SRAM data release */ + scf_dscp_sram_free(dsc_p->dinfo.base.offset); + dsc_p->dinfo.base.offset = DSC_OFFSET_NOTHING; + } + + /* Change TxDSC status (SA0) */ + SCF_SET_DSC_STATUS(dsc_p, SCF_TX_ST_IDLE); + } + + /* Tx flag initialization */ + scf_dscp_comtbl.tx_exec_flag = FLAG_OFF; + scf_dscp_comtbl.dscp_path_flag = FLAG_OFF; + scf_dscp_comtbl.tx_local_use_flag = FLAG_OFF; + + /* TxDSC counter/offset initialization */ + scf_dscp_comtbl.tx_get = scf_dscp_comtbl.tx_put; + scf_dscp_comtbl.tx_dsc_count = 0; + + /* Tx re-try counter initialization */ + scf_dscp_comtbl.tx_ackto_retry_cnt = 0; + scf_dscp_comtbl.tx_endto_retry_cnt = 0; + + scf_dscp_comtbl.tx_busy_retry_cnt = 0; + scf_dscp_comtbl.tx_interface_retry_cnt = 0; + scf_dscp_comtbl.tx_nak_retry_cnt = 0; + scf_dscp_comtbl.tx_notsuop_retry_cnt = 0; + scf_dscp_comtbl.tx_prmerr_retry_cnt = 0; + scf_dscp_comtbl.tx_seqerr_retry_cnt = 0; + scf_dscp_comtbl.tx_other_retry_cnt = 0; + scf_dscp_comtbl.tx_send_retry_cnt = 0; + } + + /* Get RxDSC address */ + dsc_p = scf_dscp_comtbl.rx_dscp; + + if (dsc_p != NULL) { + /* Check RxDSC */ + for (ii = 0; ii < scf_dscp_comtbl.rxdsc_maxcount; ii++, + dsc_p++) { + /* Check RxDSC status */ + if (dsc_p->status == SCF_RX_ST_IDLE) { + continue; + } + /* RxDSC status not (RA0) */ + /* Check receive data */ + if (dsc_p->dinfo.base.dscp_datap != NULL) { + /* Receive data release */ + kmem_free(dsc_p->dinfo.base.dscp_datap, + dsc_p->dinfo.base.length); + dsc_p->dinfo.base.dscp_datap = NULL; + } + + /* Change RxDSC status (RA0) */ + SCF_SET_DSC_STATUS(dsc_p, SCF_RX_ST_IDLE); + } + + /* Rx flag initialization */ + scf_dscp_comtbl.rx_exec_flag = FLAG_OFF; + + /* RxDSC counter/offset initialization */ + scf_dscp_comtbl.rx_get = scf_dscp_comtbl.rx_put; + scf_dscp_comtbl.rx_dsc_count = 0; + } + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end"); +} + + +/* + * scf_dscp_txdscbuff_free() + * + * Description: Tx descripter buffer release processing. + * + */ +void +scf_dscp_txdscbuff_free(scf_dscp_main_t *mainp) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_dscp_txdscbuff_free() " + scf_dscp_dsc_t *dsc_p; /* TxDSC address */ + uint16_t wkget; /* Working value : get offset */ + int ii; /* Working value : counter */ + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start"); + + /* Get TxDSC offser */ + wkget = scf_dscp_comtbl.tx_get; + + /* Check TxDSC */ + for (ii = 0; ii < scf_dscp_comtbl.tx_dsc_count; ii++) { + /* Get TxDSC address */ + dsc_p = &scf_dscp_comtbl.tx_dscp[wkget]; + + /* Update Tx descriptor offset */ + if (wkget == scf_dscp_comtbl.tx_last) { + wkget = scf_dscp_comtbl.tx_first; + } else { + wkget++; + } + + /* Check main use data */ + if (mainp->id != dsc_p->dinfo.bdcr.id) { + continue; + } + /* Check TxDSC status */ + switch (dsc_p->status) { + case SCF_TX_ST_SRAM_TRANS_WAIT: + /* TxDSC status not (SB0) */ + case SCF_TX_ST_TXREQ_SEND_WAIT: + /* TxDSC status not (SB2) */ + /* Check send data */ + if (dsc_p->dinfo.base.dscp_datap != NULL) { + /* Send data release */ + kmem_free(dsc_p->dinfo.base.dscp_datap, + dsc_p->dinfo.base.length); + dsc_p->dinfo.base.dscp_datap = NULL; + } + + /* Check SRAM data */ + if (dsc_p->dinfo.base.offset != DSC_OFFSET_NOTHING) { + /* Send SRAM data release */ + scf_dscp_sram_free(dsc_p->dinfo.base.offset); + dsc_p->dinfo.base.offset = DSC_OFFSET_NOTHING; + } + + /* Change TxDSC status (SA0) */ + SCF_SET_DSC_STATUS(dsc_p, SCF_TX_ST_IDLE); + break; + + default: + /* TxDSC status != SB0 or SB2 is NOP */ + break; + } + } + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end"); +} + + +/* + * scf_dscp_rxdscbuff_free() + * + * Description: Rx descripter buffer release processing. + * + */ +void +scf_dscp_rxdscbuff_free(scf_dscp_main_t *mainp) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_dscp_rxdscbuff_free() " + scf_dscp_dsc_t *dsc_p; /* TxDSC address */ + uint16_t wkget; /* Working value : get offset */ + int ii; /* Working value : counter */ + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start"); + + /* Get RxDSC offser */ + wkget = scf_dscp_comtbl.rx_get; + + /* Check RxDSC */ + for (ii = 0; ii < scf_dscp_comtbl.rx_dsc_count; ii++) { + /* Get RxDSC address */ + dsc_p = &scf_dscp_comtbl.rx_dscp[wkget]; + + /* Update Rx descriptor offset */ + if (wkget == scf_dscp_comtbl.rx_last) { + wkget = scf_dscp_comtbl.rx_first; + } else { + wkget++; + } + + /* Check main use data */ + if (mainp->id != dsc_p->dinfo.bdcr.id) { + continue; + } + /* Check RxDSC status */ + if (dsc_p->status != SCF_RX_ST_IDLE) { + /* TxDSC status not (RA0) */ + /* Check receive data */ + if (dsc_p->dinfo.base.dscp_datap != NULL) { + /* Receive data release */ + kmem_free(dsc_p->dinfo.base.dscp_datap, + dsc_p->dinfo.base.length); + dsc_p->dinfo.base.dscp_datap = NULL; + } + + /* Change RxDSC status (RA0) */ + SCF_SET_DSC_STATUS(dsc_p, SCF_RX_ST_IDLE); + + /* Rx flag initialization */ + scf_dscp_comtbl.rx_exec_flag = FLAG_OFF; + + /* RxDSC counter/offset initialization */ + scf_dscp_comtbl.rx_get = scf_dscp_comtbl.rx_put; + scf_dscp_comtbl.rx_dsc_count = 0; + break; + } + } + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end"); +} + + +/* + * scf_dscp_rdata_free() + * + * Description: All receive data buffer release processing. + * + */ +void +scf_dscp_rdata_free(scf_dscp_main_t *mainp) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_dscp_rdata_free() " + /* Current receive data queue address */ + scf_rdata_que_t *rdt_p; + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start"); + + while (mainp->rd_count != 0) { + /* Get receive data queue address */ + rdt_p = &mainp->rd_datap[mainp->rd_get]; + + /* Check receive data buffer */ + if (rdt_p->rdatap != NULL) { + /* Receve data release */ + kmem_free(rdt_p->rdatap, rdt_p->length); + rdt_p->rdatap = NULL; + } + + /* Update receive data queue */ + if (mainp->rd_get == mainp->rd_last) { + mainp->rd_get = mainp->rd_first; + } else { + mainp->rd_get++; + } + + /* Update receive data queue count */ + mainp->rd_count--; + } + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end"); +} + + +/* + * scf_dscp_event_queue() + * + * Description: Event queueing processing. + * + */ +void +scf_dscp_event_queue(scf_dscp_main_t *mainp, scf_event_t mevent) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_dscp_event_queue() " + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start"); + + /* Check DISC ERROR event */ + if (mevent == SCF_MB_DISC_ERROR) { + /* TxDSC buffer release */ + scf_dscp_txdscbuff_free(mainp); + + /* RxDSC buffer release */ + scf_dscp_rxdscbuff_free(mainp); + + /* All queing event release */ + scf_dscp_event_queue_free(mainp); + + /* All receive buffer release */ + scf_dscp_rdata_free(mainp); + } + + /* Event queing */ + mainp->ev_quep[mainp->ev_put].mevent = mevent; + + /* Update event queue offset */ + if (mainp->ev_put == mainp->ev_last) { + mainp->ev_put = mainp->ev_first; + } else { + mainp->ev_put++; + } + + /* Update event queue count */ + mainp->ev_count++; + + /* Soft interrupt : call scf_dscp_callback() */ + if (mutex_tryenter(&scf_comtbl.si_mutex) != 0) { + scf_comtbl.scf_softintr_dscp_kicked = FLAG_ON; + ddi_trigger_softintr(scf_comtbl.scf_softintr_id); + mutex_exit(&scf_comtbl.si_mutex); + } + + /* Callback timer start */ + scf_timer_start(SCF_TIMERCD_DSCP_CALLBACK); + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end"); +} + + +/* + * scf_dscp_event_queue_free() + * + * Description: Event queue release processing. + * + */ +void +scf_dscp_event_queue_free(scf_dscp_main_t *mainp) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_dscp_event_queue_free() " + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start"); + + /* All queing event release */ + mainp->ev_get = mainp->ev_put; + mainp->ev_count = 0; + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end"); +} + + +/* + * scf_dscp_mkey2mainp() + * + * Description: Get MAIN control table address processing by mkey. + * + */ +scf_dscp_main_t * +scf_dscp_mkey2mainp(mkey_t mkey) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_dscp_mkey2mainp() " + /* Return value : Main table address */ + scf_dscp_main_t *mainp = NULL; + int ii; /* Working value : counter */ + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start"); + + for (ii = 0; ii < MBIF_MAX; ii++) { + /* Check "mkey" at search table */ + if (mkey == scf_dscp_mkey_search[ii]) { + /* Set mainp address */ + mainp = &scf_dscp_comtbl.scf_dscp_main[ii]; + break; + } + } + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end"); + return (mainp); +} + + +/* + * scf_dscp_id2mainp() + * + * Description: Get MAIN control table address processing by id. + * + */ +scf_dscp_main_t * +scf_dscp_id2mainp(uint8_t id) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_dscp_id2mainp() " + /* Return value : Main table address */ + scf_dscp_main_t *mainp = NULL; + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start"); + + /* Check "id" */ + if (id < MBIF_MAX) { + /* Set mainp address */ + mainp = &scf_dscp_comtbl.scf_dscp_main[id]; + } + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end"); + return (mainp); +} + + +/* + * scf_dscp_sram_get() + * + * Description: Tx SRAM alloc processing. + * + */ +uint16_t +scf_dscp_sram_get(void) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_dscp_sram_get() " + scf_tx_sram_t *sram_p; /* Tx SRAM table address */ + int ii; /* Working value : counter */ + /* Return value : Tx SRAM offset */ + uint16_t offset = TX_SRAM_GET_ERROR; + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start"); + + /* Check Tx SRAM space */ + if (scf_dscp_comtbl.tx_sram_count >= + scf_dscp_comtbl.txsram_maxcount) { + goto END_dscp_sram_get; + } + + /* Check all Tx SRAM table */ + for (ii = 0; ii < scf_dscp_comtbl.txsram_maxcount; ii++) { + /* Get Tx SRAM table address */ + sram_p = &scf_dscp_comtbl.tx_sramp[scf_dscp_comtbl.tx_sram_put]; + + /* Update Tx SRAM offset */ + if (scf_dscp_comtbl.tx_sram_put == + scf_dscp_comtbl.tx_sram_last) { + scf_dscp_comtbl.tx_sram_put = + scf_dscp_comtbl.tx_sram_first; + } else { + scf_dscp_comtbl.tx_sram_put++; + } + + /* Check Tx SRAM use */ + if (sram_p->use_flag == FLAG_OFF) { + /* Tx SRAM use flag ON */ + sram_p->use_flag = FLAG_ON; + + /* Get Tx SRAM offset */ + offset = sram_p->offset; + + /* Update Tx SRAM count */ + scf_dscp_comtbl.tx_sram_count++; + break; + } + } + +/* + * END_dscp_sram_get + */ + END_dscp_sram_get: + + SCFDBGMSG1(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end offset = 0x%04x", + offset); + return (offset); +} + + +/* + * scf_dscp_sram_free() + * + * Description: Tx SRAM release processing + * + */ +void +scf_dscp_sram_free(uint16_t offset) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_dscp_sram_free() " + scf_tx_sram_t *sram_p; /* Tx SRAM table address */ + uint16_t wkget; /* Working value : get offset */ + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG1(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start offset = 0x%04x", + offset); + + /* "offset" to Tx SRAM get offset */ + wkget = (uint16_t)(offset + / (scf_dscp_comtbl.txbuffsize / DSC_OFFSET_CONVERT)); + + /* Check Tx SRAM get offset */ + if (wkget < scf_dscp_comtbl.txsram_maxcount) { + /* Get Tx SRAM table address */ + sram_p = &scf_dscp_comtbl.tx_sramp[wkget]; + + /* Check "offset" */ + if (offset == sram_p->offset) { + /* Tx SRAM use flag OFF */ + sram_p->use_flag = FLAG_OFF; + + /* Update Tx SRAM count */ + scf_dscp_comtbl.tx_sram_count--; + } + } + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end"); +} diff --git a/usr/src/uts/sun4u/opl/io/scfd/scfhandler.c b/usr/src/uts/sun4u/opl/io/scfd/scfhandler.c new file mode 100644 index 0000000000..e926481551 --- /dev/null +++ b/usr/src/uts/sun4u/opl/io/scfd/scfhandler.c @@ -0,0 +1,3458 @@ +/* + * 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 + */ +/* + * All Rights Reserved, Copyright (c) FUJITSU LIMITED 2006 + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/ksynch.h> +#include <sys/types.h> +#include <sys/conf.h> +#include <sys/cmn_err.h> +#include <sys/kmem.h> +#include <sys/errno.h> +#include <sys/ddi.h> +#include <sys/sunddi.h> + +#include <sys/scfd/scfparam.h> + +/* + * Function list + */ +uint_t scf_intr(caddr_t arg); +int scf_intr_cmdcmp(scf_state_t *statep); +void scf_intr_cmdcmp_driver(scf_state_t *statep, struct scf_cmd *scfcmdp); +int scf_intr_dsens(struct scf_cmd *scfcmdp, scf_int_reason_t *int_rp, + int len); +void scf_status_change(scf_state_t *statep); +void scf_next_cmd_check(scf_state_t *statep); +void scf_next_rxdata_get(void); +void scf_online_wait_tout(void); +void scf_cmdbusy_tout(void); +void scf_cmdend_tout(void); +void scf_report_send_wait_tout(void); +void scf_alivecheck_intr(scf_state_t *statep); +void scf_path_change(scf_state_t *statep); +void scf_halt(uint_t mode); +void scf_panic_callb(int code); +void scf_shutdown_callb(int code); +uint_t scf_softintr(caddr_t arg); +void scf_cmdwait_status_set(void); + +/* + * External function + */ +extern void scf_dscp_start(uint32_t factor); +extern void scf_dscp_stop(uint32_t factor); +extern void scf_dscp_intr(scf_state_t *state); +extern void scf_dscp_callback(void); + +extern void do_shutdown(void); + + +/* + * scf_intr() + * + * Description: Interrupt handler entry processing. + * + */ +uint_t +scf_intr(caddr_t arg) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_intr() " + scf_state_t *statep = (void *)arg; + int path_change = 0; + uint_t ret = DDI_INTR_CLAIMED; + timeout_id_t save_tmids[SCF_TIMERCD_MAX]; + int tm_stop_cnt; + + SCFDBGMSG(SCF_DBGFLAG_SYS, SCF_FUNC_NAME ": start"); + SC_DBG_DRV_TRACE(TC_INTR|TC_IN, __LINE__, &arg, sizeof (caddr_t)); + + /* Lock driver mutex */ + mutex_enter(&scf_comtbl.all_mutex); + + /* Path status check */ + if (scf_check_state(statep) == PATH_STAT_EMPTY) { + SC_DBG_DRV_TRACE(TC_INTR|TC_ERR, __LINE__, "intr ", 8); + goto END_intr; + } + + /* PANIC exec status */ + if (scf_panic_exec_flag) { + /* SCF interrupt disable(CR) */ + SCF_P_DDI_PUT16(statep->scf_regs_c_handle, + &statep->scf_regs_c->CONTROL, CONTROL_DISABLE); + /* Register read sync */ + scf_rs16 = SCF_P_DDI_GET16(statep->scf_regs_c_handle, + &statep->scf_regs_c->CONTROL); + + /* SCF Status register interrupt(STR) : clear */ + SCF_P_DDI_PUT16(statep->scf_regs_handle, + &statep->scf_regs->STATUS, 0xffff); + + /* SCF Status extended register(STExR) : interrupt clear */ + SCF_P_DDI_PUT32(statep->scf_regs_handle, + &statep->scf_regs->STATUS_ExR, 0xffffffff); + + /* DSCP buffer status register(DSR) : interrupt clear */ + SCF_P_DDI_PUT8(statep->scf_regs_handle, + &statep->scf_regs->DSR, 0xff); + + /* SCF interrupt status register(ISR) : interrupt clear */ + SCF_P_DDI_PUT16(statep->scf_regs_c_handle, + &statep->scf_regs_c->INT_ST, + (INT_ST_PATHCHGIE | CONTROL_ALIVEINE)); + scf_rs16 = SCF_P_DDI_GET16(statep->scf_regs_c_handle, + &statep->scf_regs_c->INT_ST); + goto END_intr; + } + + /* Check hard error after or interrupt disable status */ + if ((statep->scf_herr & HERR_EXEC) || + (!(statep->resource_flag & S_DID_REGENB))) { + SC_DBG_DRV_TRACE(TC_INTR|TC_ERR, __LINE__, "intr ", 8); + + /* Interrupt disable */ + scf_forbid_intr(statep); + + /* SCF Status register interrupt(STR) : clear */ + SCF_DDI_PUT16(statep, statep->scf_regs_handle, + &statep->scf_regs->STATUS, 0xffff); + + /* SCF Status extended register(STExR) : interrupt clear */ + SCF_DDI_PUT32(statep, statep->scf_regs_handle, + &statep->scf_regs->STATUS_ExR, 0xffffffff); + + /* DSCP buffer status register(DSR) : interrupt clear */ + SCF_DDI_PUT8(statep, statep->scf_regs_handle, + &statep->scf_regs->DSR, 0xff); + + /* SCF interrupt status register(ISR) : interrupt clear */ + SCF_DDI_PUT16(statep, statep->scf_regs_c_handle, + &statep->scf_regs_c->INT_ST, + (INT_ST_PATHCHGIE | CONTROL_ALIVEINE)); + scf_rs16 = SCF_DDI_GET16(statep, statep->scf_regs_c_handle, + &statep->scf_regs_c->INT_ST); + goto END_intr; + } + + /* Get SCF interrupt register */ + statep->reg_int_st = SCF_DDI_GET16(statep, statep->scf_regs_c_handle, + &statep->scf_regs_c->INT_ST); + SC_DBG_DRV_TRACE(TC_R_INT_ST, __LINE__, &statep->reg_int_st, + sizeof (statep->reg_int_st)); + + /* SCF interrupt register interrupt clear */ + SCF_DDI_PUT16(statep, statep->scf_regs_c_handle, + &statep->scf_regs_c->INT_ST, statep->reg_int_st); + SC_DBG_DRV_TRACE(TC_W_INT_ST, __LINE__, &statep->reg_int_st, + sizeof (statep->reg_int_st)); + /* Register read sync */ + scf_rs16 = SCF_DDI_GET16(statep, statep->scf_regs_c_handle, + &statep->scf_regs_c->INT_ST); + + SCF_DBG_TEST_INTR(statep); + + SCFDBGMSG1(SCF_DBGFLAG_REG, "ISR = 0x%04x", statep->reg_int_st); + + /* Get SCF status register */ + statep->reg_status = SCF_DDI_GET16(statep, + statep->scf_regs_handle, &statep->scf_regs->STATUS); + SC_DBG_DRV_TRACE(TC_R_STATUS, __LINE__, &statep->reg_status, + sizeof (statep->reg_status)); + + /* Get SCF status extended register */ + statep->reg_status_exr = SCF_DDI_GET32(statep, + statep->scf_regs_handle, &statep->scf_regs->STATUS_ExR); + SC_DBG_DRV_TRACE(TC_R_STATUS_ExR, __LINE__, &statep->reg_status_exr, + sizeof (statep->reg_status_exr)); + + /* Get SCF command register */ + statep->reg_command = SCF_DDI_GET16(statep, + statep->scf_regs_handle, &statep->scf_regs->COMMAND); + SC_DBG_DRV_TRACE(TC_R_COMMAND, __LINE__, &statep->reg_command, + sizeof (statep->reg_command)); + + /* Get SCF command extended register */ + statep->reg_command_exr = SCF_DDI_GET8(statep, statep->scf_regs_handle, + &statep->scf_regs->COMMAND_ExR); + SC_DBG_DRV_TRACE(TC_R_COMMAND_ExR, __LINE__, &statep->reg_command_exr, + sizeof (statep->reg_command_exr)); + + SCF_DBG_TEST_INTR_SCFINT(statep); + + /* SRAM trace */ + SCF_SRAM_TRACE(statep, DTC_INT); + + /* Check SCF path change interrupt */ + if (statep->reg_int_st & CONTROL_PATHCHGIE) { + /* Check interrupt SCF path */ + if ((statep != scf_comtbl.scf_exec_p) && + (statep != scf_comtbl.scf_path_p)) { + path_change = 1; + goto END_intr; + } + } + + /* Check Alive Interrupt */ + if (statep->reg_int_st & INT_ST_ALIVEINT) { + /* Check interrupt SCF path */ + if ((statep == scf_comtbl.scf_exec_p) || + (statep == scf_comtbl.scf_path_p)) { + /* Alive check interrupt */ + scf_alivecheck_intr(statep); + } else { + /* not active SCF path */ + SC_DBG_DRV_TRACE(TC_INTR|TC_ERR, __LINE__, + "intr ", 8); + /* Alive interrupt disable */ + scf_alivecheck_stop(statep); + } + } + + /* Check SCF interrupt */ + if (statep->reg_int_st & INT_ST_SCFINT) { + SC_DBG_DRV_TRACE(TC_RSTS, __LINE__, &statep->reg_command, + TC_INFO_SIZE); + + SCFDBGMSG2(SCF_DBGFLAG_REG, "STR = 0x%04x STExR = 0x%08x", + statep->reg_status, statep->reg_status_exr); + + /* Check active SCF path */ + if ((statep == scf_comtbl.scf_exec_p) || + (statep == scf_comtbl.scf_path_p)) { + + /* Mode changed bit valid */ + if ((statep->reg_status & STATUS_MODE_CHANGED) || + (statep->reg_status & STATUS_CMD_COMPLETE)) { + /* Check secure mode status */ + if ((statep->reg_status & STATUS_SECURE_MODE) == + STATUS_MODE_LOCK) { + /* Mode status LOCK */ + scf_dm_secure_mode = SCF_STAT_MODE_LOCK; + if (((scf_comtbl.scf_mode_sw & + STATUS_SECURE_MODE) != + STATUS_MODE_LOCK) && + (scf_comtbl.alive_running == + SCF_ALIVE_START)) { + /* Alive check start */ + scf_comtbl.scf_alive_event_sub = + EVENT_SUB_ALST_WAIT; + } + } else { + scf_dm_secure_mode = + SCF_STAT_MODE_UNLOCK; + } + scf_comtbl.scf_mode_sw = + (statep->reg_status & + (STATUS_BOOT_MODE | + STATUS_SECURE_MODE)); + } + + /* Check command complete */ + if ((scf_comtbl.scf_cmd_exec_flag) && + (statep->reg_status & STATUS_CMD_COMPLETE)) { + /* SCF command complete processing */ + path_change = scf_intr_cmdcmp(statep); + if (path_change) { + goto END_intr; + } + } + } else { + /* SCF Status register interrupt clear */ + SCF_DDI_PUT16(statep, statep->scf_regs_handle, + &statep->scf_regs->STATUS, statep->reg_status); + SC_DBG_DRV_TRACE(TC_W_STATUS, __LINE__, + &statep->reg_status, + sizeof (statep->reg_status)); + /* Register read sync */ + scf_rs16 = SCF_DDI_GET16(statep, + statep->scf_regs_handle, + &statep->scf_regs->STATUS); + + /* SCF Status extended register interrupt clear */ + SCF_DDI_PUT32(statep, statep->scf_regs_handle, + &statep->scf_regs->STATUS_ExR, + statep->reg_status_exr); + SC_DBG_DRV_TRACE(TC_W_STATUS_ExR, __LINE__, + &statep->reg_status_exr, + sizeof (statep->reg_status_exr)); + /* Register read sync */ + scf_rs32 = SCF_DDI_GET32(statep, + statep->scf_regs_handle, + &statep->scf_regs->STATUS_ExR); + goto END_intr; + } + + /* Check SCF status change */ + if (statep->reg_status_exr & STATUS_SCF_STATUS_CHANGE) { + /* SCF status change processing */ + scf_status_change(statep); + } + + /* SCF Status register interrupt clear */ + SCF_DDI_PUT16(statep, statep->scf_regs_handle, + &statep->scf_regs->STATUS, statep->reg_status); + SC_DBG_DRV_TRACE(TC_W_STATUS, __LINE__, &statep->reg_status, + sizeof (statep->reg_status)); + /* Register read sync */ + scf_rs16 = SCF_DDI_GET16(statep, statep->scf_regs_handle, + &statep->scf_regs->STATUS); + + /* SCF Status extended register interrupt clear */ + SCF_DDI_PUT32(statep, statep->scf_regs_handle, + &statep->scf_regs->STATUS_ExR, statep->reg_status_exr); + SC_DBG_DRV_TRACE(TC_W_STATUS_ExR, __LINE__, + &statep->reg_status_exr, + sizeof (statep->reg_status_exr)); + /* Register read sync */ + scf_rs32 = SCF_DDI_GET32(statep, statep->scf_regs_handle, + &statep->scf_regs->STATUS_ExR); + + /* SHUTDOWN/POFF/EVENT/ALIVE save */ + if (statep->reg_status & + (STATUS_SHUTDOWN | STATUS_POFF | STATUS_EVENT)) { + scf_comtbl.scf_event_flag |= (statep->reg_status & + (STATUS_SHUTDOWN | STATUS_POFF | STATUS_EVENT)); + } + + /* POWER_FAILURE save */ + if (statep->reg_status_exr & STATUS_POWER_FAILURE) { + scf_comtbl.scf_event_flag |= STATUS_SHUTDOWN; + } + + /* Check next receive data timer exec */ + if (scf_timer_check(SCF_TIMERCD_NEXTRECV) == + SCF_TIMER_NOT_EXEC) { + /* Next command send check */ + scf_next_cmd_check(statep); + } + } + + /* Check next command send */ + if ((scf_comtbl.scf_cmd_exec_flag == 0) && + (scf_comtbl.cmd_busy_wait != 0)) { + scf_comtbl.cmd_busy_wait = 0; + /* Signal to command wait */ + cv_signal(&scf_comtbl.cmdwait_cv); + SC_DBG_DRV_TRACE(TC_SIGNAL, __LINE__, &scf_comtbl.cmdwait_cv, + sizeof (kcondvar_t)); + } + + /* Check DSCP Communication Buffer Interrupt */ + if (statep->reg_int_st & INT_ST_IDBCINT) { + /* Check interrupt SCF path */ + if ((statep == scf_comtbl.scf_exec_p) || + (statep == scf_comtbl.scf_path_p)) { + scf_dscp_intr(statep); + } else { + /* not active SCF path */ + SC_DBG_DRV_TRACE(TC_INTR|TC_ERR, __LINE__, + "intr ", 8); + /* DSCP buffer status register interrupt clear */ + SCF_DDI_PUT8(statep, statep->scf_regs_handle, + &statep->scf_regs->DSR, 0xff); + /* Register read sync */ + scf_rs8 = SCF_DDI_GET8(statep, statep->scf_regs_handle, + &statep->scf_regs->DSR); + } + } + + if ((statep->reg_int_st & INT_ST_ALL) == 0) { + /* Unclamed counter up */ + scf_comtbl.scf_unclamed_cnt++; + + /* Get control register */ + statep->reg_control = SCF_DDI_GET16(statep, + statep->scf_regs_c_handle, + &statep->scf_regs_c->CONTROL); + SC_DBG_DRV_TRACE(TC_R_CONTROL, __LINE__, &statep->reg_control, + sizeof (statep->reg_control)); + scf_comtbl.scf_unclamed.CONTROL = statep->reg_control; + + scf_comtbl.scf_unclamed.INT_ST = statep->reg_int_st; + + /* Get SCF command register */ + statep->reg_command = SCF_DDI_GET16(statep, + statep->scf_regs_handle, &statep->scf_regs->COMMAND); + SC_DBG_DRV_TRACE(TC_R_COMMAND, __LINE__, &statep->reg_command, + sizeof (statep->reg_command)); + scf_comtbl.scf_unclamed.COMMAND = statep->reg_command; + + /* Get SCF status register */ + statep->reg_status = SCF_DDI_GET16(statep, + statep->scf_regs_handle, &statep->scf_regs->STATUS); + SC_DBG_DRV_TRACE(TC_R_STATUS, __LINE__, &statep->reg_status, + sizeof (statep->reg_status)); + scf_comtbl.scf_unclamed.STATUS = statep->reg_status; + + /* Get SCF status extended register */ + statep->reg_status_exr = SCF_DDI_GET32(statep, + statep->scf_regs_handle, &statep->scf_regs->STATUS_ExR); + SC_DBG_DRV_TRACE(TC_R_STATUS_ExR, __LINE__, + &statep->reg_status_exr, + sizeof (statep->reg_status_exr)); + scf_comtbl.scf_unclamed.STATUS_ExR = statep->reg_status_exr; + + /* Get DSR register */ + statep->reg_dsr = SCF_DDI_GET8(statep, statep->scf_regs_handle, + &statep->scf_regs->DSR); + SC_DBG_DRV_TRACE(TC_R_DSR, __LINE__, &statep->reg_dsr, + sizeof (statep->reg_dsr)); + scf_comtbl.scf_unclamed.DSR = statep->reg_dsr; + } + +/* + * END_intr + */ + END_intr: + + /* Check SCF path change */ + if (path_change) { + scf_path_change(statep); + } + + /* Collect the timers which need to be stopped */ + tm_stop_cnt = scf_timer_stop_collect(save_tmids, SCF_TIMERCD_MAX); + + /* Unlock driver mutex */ + mutex_exit(&scf_comtbl.all_mutex); + + /* Timer stop */ + if (tm_stop_cnt != 0) { + scf_timer_untimeout(save_tmids, SCF_TIMERCD_MAX); + } + + SC_DBG_DRV_TRACE(TC_INTR|TC_OUT, __LINE__, &ret, sizeof (uint_t)); + SCFDBGMSG1(SCF_DBGFLAG_SYS, SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +/* + * scf_intr_cmdcmp() + * + * Description: SCF command complete processing. + * + */ +int +scf_intr_cmdcmp(scf_state_t *statep) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_intr_cmdcmp() " + struct scf_cmd *scfcmdp; + uint8_t sum; + uint32_t sum4; + uint8_t *wk_in_p8; + uint32_t *wk_in_p32; + uint8_t *wk_in_p; + uint8_t *wk_out_p; + uint_t wkleng; + uint_t wkleng2; + uint_t rcount; + uint_t rxbuff_cnt; + uint_t rxbuff_flag = 0; + char sumerr_msg[16]; + int info_size; + int ii; + int ret = 0; + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_SYS, SCF_FUNC_NAME ": start"); + + if (scf_comtbl.scf_exec_cmd_id) { + /* SCF command start for ioctl */ + scfcmdp = scf_comtbl.scf_cmdp; + } else { + /* SCF command start for interrupt */ + scfcmdp = &scf_comtbl.scf_cmd_intr; + } + scfcmdp->stat0 = (statep->reg_status & STATUS_CMD_RTN_CODE) >> 4; + scfcmdp->status = statep->reg_status; + + scf_timer_stop(SCF_TIMERCD_CMDEND); + scf_comtbl.scf_cmd_exec_flag = 0; + statep->cmd_to_rcnt = 0; + + statep->reg_rdata[0] = SCF_DDI_GET32(statep, statep->scf_regs_handle, + &statep->scf_regs->RDATA0); + statep->reg_rdata[1] = SCF_DDI_GET32(statep, statep->scf_regs_handle, + &statep->scf_regs->RDATA1); + SC_DBG_DRV_TRACE(TC_R_RDATA0, __LINE__, & statep->reg_rdata[0], + sizeof (statep->reg_rdata[0]) + sizeof (statep->reg_rdata[1])); + statep->reg_rdata[2] = SCF_DDI_GET32(statep, statep->scf_regs_handle, + &statep->scf_regs->RDATA2); + statep->reg_rdata[3] = SCF_DDI_GET32(statep, statep->scf_regs_handle, + &statep->scf_regs->RDATA3); + SC_DBG_DRV_TRACE(TC_R_RDATA2, __LINE__, &statep->reg_rdata[2], + sizeof (statep->reg_rdata[2]) + sizeof (statep->reg_rdata[3])); + + SCF_DBG_TEST_INTR_CMDEND(statep); + + SCFDBGMSG1(SCF_DBGFLAG_SYS, "command complete status = 0x%04x", + scfcmdp->stat0); + SCFDBGMSG4(SCF_DBGFLAG_REG, "RxDR = 0x%08x 0x%08x 0x%08x 0x%08x", + statep->reg_rdata[0], statep->reg_rdata[1], + statep->reg_rdata[2], statep->reg_rdata[3]); + + /* SRAM trace */ + SCF_SRAM_TRACE(statep, DTC_RECVDATA); + + SCF_DBG_XSCF_SET_STATUS + + /* Check command return value */ + switch (scfcmdp->stat0) { + case NORMAL_END: + /* Norman end */ + statep->tesum_rcnt = 0; + + SCF_DBG_XSCF_SET_LENGTH + + /* Make Rx register sum */ + sum = SCF_MAGICNUMBER_S; + wk_in_p8 = (uint8_t *)&statep->reg_rdata[0]; + for (ii = 0; ii < SCF_S_CNT_15; ii++, wk_in_p8++) { + sum += *wk_in_p8; + } + + SCF_DBG_MAKE_RXSUM(sum, *wk_in_p8); + + /* Check Rx register sum */ + if (sum != *wk_in_p8) { + SCFDBGMSG2(SCF_DBGFLAG_SYS, + "Rx sum failure 0x%02x 0x%02x", sum, *wk_in_p8); + SC_DBG_DRV_TRACE(TC_INTR|TC_ERR, __LINE__, + "intr ", 8); + scfcmdp->stat0 = SCF_STAT0_RDATA_SUM; + strcpy(&sumerr_msg[0], "SCF device"); + statep->resum_rcnt++; + goto CHECK_rxsum_start; + } + + if (scfcmdp->flag == SCF_USE_SLBUF) { + /* + * SCF_USE_SLBUF + */ + scfcmdp->rbufleng = statep->reg_rdata[0]; + if (scfcmdp->rbufleng > SCF_L_CNT_MAX) { + /* Invalid receive data length */ + SCFDBGMSG1(SCF_DBGFLAG_SYS, + "Invalid receive data length = 0x%08x", + scfcmdp->rbufleng); + SC_DBG_DRV_TRACE(TC_INTR|TC_ERR, __LINE__, + "intr ", 8); + scfcmdp->stat0 = SCF_STAT0_RDATA_SUM; + strcpy(&sumerr_msg[0], "SRAM"); + statep->resum_rcnt++; + goto CHECK_rxsum_start; + } + + if (scfcmdp->rbufleng == 0) { + statep->resum_rcnt = 0; + goto CHECK_rxsum_start; + } + /* Check receive data division mode */ + if ((scf_comtbl.scf_exec_cmd_id) && + (scfcmdp->rbufleng > scf_rxbuff_max_size)) { + scf_comtbl.scf_rem_rxbuff_size = + scfcmdp->rbufleng - scf_rxbuff_max_size; + rxbuff_cnt = scf_rxbuff_max_size; + rxbuff_flag = 1; + } else { + rxbuff_cnt = scfcmdp->rbufleng; + rxbuff_flag = 0; + } + + /* Receive data copy */ + wk_in_p = (uint8_t *)&statep->scf_sys_sram->DATA[0]; + wk_out_p = (uint8_t *)&scfcmdp->rbuf[0]; + for (ii = 0; ii < rxbuff_cnt; + ii++, wk_in_p++, wk_out_p++) { + *wk_out_p = SCF_DDI_GET8(statep, + statep->scf_sys_sram_handle, wk_in_p); + } + + /* SRAM trace */ + if (rxbuff_cnt > scf_sram_trace_data_size) { + rcount = scf_sram_trace_data_size; + } else { + rcount = rxbuff_cnt; + } + wk_in_p = (uint8_t *)scfcmdp->rbuf; + info_size = sizeof (statep->memo_scf_drvtrc.INFO); + while (rcount != 0) { + bzero((void *)&statep->memo_scf_drvtrc.INFO[0], + info_size); + wk_out_p = &statep->memo_scf_drvtrc.INFO[0]; + if (rcount > info_size) { + wkleng = info_size; + } else { + wkleng = rcount; + } + rcount -= wkleng; + bcopy(wk_in_p, wk_out_p, wkleng); + SCF_SRAM_TRACE(statep, DTC_RECVDATA_SRAM); + wk_in_p += wkleng; + } + + /* Check receive data division mode */ + if (rxbuff_flag != 0) { + goto CHECK_rxsum_start; + } + + /* Make SRAM data sum */ + sum4 = SCF_MAGICNUMBER_L; + wkleng2 = scfcmdp->rbufleng; + wkleng = scfcmdp->rbufleng / 4; + wk_in_p32 = (void *)scfcmdp->rbuf; + for (ii = 0; ii < wkleng; ii++, wk_in_p32++) { + sum4 += *wk_in_p32; + } + if ((wkleng2 % 4) == 3) { + sum4 += ((scfcmdp->rbuf[wkleng2 - 3] << 24) | + (scfcmdp->rbuf[wkleng2 - 2] << 16) | + (scfcmdp->rbuf[wkleng2 - 1] << 8)); + + } else if ((wkleng2 % 4) == 2) { + sum4 += ((scfcmdp->rbuf[wkleng2 - 2] << 24) | + (scfcmdp->rbuf[wkleng2 - 1] << 16)); + } else if ((wkleng2 % 4) == 1) { + sum4 += (scfcmdp->rbuf[wkleng2 - 1] << 24); + } + + SCF_DBG_MAKE_RXSUM_L(sum4, statep->reg_rdata[2]); + + /* Check SRAM data sum */ + if (sum4 == statep->reg_rdata[2]) { + statep->resum_rcnt = 0; + } else { + SCFDBGMSG2(SCF_DBGFLAG_SYS, + "Rx sum failure 0x%08x 0x%08x", + sum4, statep->reg_rdata[2]); + SC_DBG_DRV_TRACE(TC_INTR|TC_ERR, + __LINE__, "intr ", 8); + scfcmdp->stat0 = SCF_STAT0_RDATA_SUM; + strcpy(&sumerr_msg[0], "SRAM"); + statep->resum_rcnt++; + } + } else { + if ((scfcmdp->flag == SCF_USE_SSBUF) || + (scfcmdp->flag == SCF_USE_LSBUF)) { + /* + * SCF_USE_SSBUF/SCF_USE_LSBUF + */ + if (scfcmdp->rcount < SCF_S_CNT_16) { + wkleng = scfcmdp->rcount; + } else { + wkleng = SCF_S_CNT_16; + } + scfcmdp->rbufleng = wkleng; + if (wkleng != 0) { + /* Receive data copy */ + bcopy((void *)&statep->reg_rdata[0], + (void *)scfcmdp->rbuf, wkleng); + } + } else { + /* + * SCF_USE_S_BUF/SCF_USE_L_BUF + */ + scfcmdp->rbufleng = 0; + } + statep->resum_rcnt = 0; + } + +/* + * CHECK_rxsum_start + */ + CHECK_rxsum_start: + + /* Check Rx sum re-try out */ + if ((scfcmdp->stat0 == SCF_STAT0_RDATA_SUM) && + (statep->resum_rcnt > scf_resum_rcnt)) { + /* SRAM trace */ + SCF_SRAM_TRACE(statep, DTC_RSUMERR); + + SC_DBG_DRV_TRACE(TC_INTR|TC_ERR, __LINE__, + "intr ", 8); + cmn_err(CE_WARN, + "%s,Failed the receive data SUM of %s. " + "SCF command = 0x%02x%02x\n", + &statep->pathname[0], &sumerr_msg[0], + scfcmdp->subcmd, scfcmdp->cmd); + statep->scf_herr |= HERR_RESUM; + ret = 1; + goto END_intr_cmdcmp; + } + break; + + case INTERFACE: + /* Interface error */ + SC_DBG_DRV_TRACE(TC_INTR|TC_ERR, __LINE__, "intr ", 8); + + /* SRAM trace */ + SCF_SRAM_TRACE(statep, DTC_INTERFACE); + + statep->tesum_rcnt++; + /* Check interface error re-try out */ + if (statep->tesum_rcnt > scf_tesum_rcnt) { + cmn_err(CE_WARN, + "%s,Detected the interface error by XSCF. " + "SCF command = 0x%02x%02x\n", + &statep->pathname[0], scfcmdp->subcmd, + scfcmdp->cmd); + statep->scf_herr |= HERR_TESUM; + ret = 1; + goto END_intr_cmdcmp; + } + break; + + case BUF_FUL: + /* Buff full */ + SC_DBG_DRV_TRACE(TC_INTR|TC_MSG, __LINE__, "intr ", 8); + + /* SRAM trace */ + SCF_SRAM_TRACE(statep, DTC_RCI_BUF_FUL); + + break; + + case RCI_BUSY: + /* RCI busy */ + SC_DBG_DRV_TRACE(TC_INTR|TC_MSG, __LINE__, "intr ", 8); + + /* SRAM trace */ + SCF_SRAM_TRACE(statep, DTC_RCI_BUSY); + + break; + + case E_NOT_SUPPORT: + /* Not support command/sub command */ + SC_DBG_DRV_TRACE(TC_INTR|TC_ERR, __LINE__, "intr ", 8); + + /* SRAM trace */ + SCF_SRAM_TRACE(statep, DTC_E_NOT_SUPPORT); + + cmn_err(CE_WARN, + "%s,Detected the not support command by XSCF. " + "SCF command = 0x%02x%02x\n", + &statep->pathname[0], scfcmdp->subcmd, + scfcmdp->cmd); + break; + + case E_PARAM: + /* Parameter error */ + + /* Check command is SB configuration change */ + if ((scfcmdp->cmd == CMD_DR) && (scfcmdp->subcmd == + SUB_SB_CONF_CHG)) { + scfcmdp->rbufleng = SCF_S_CNT_16; + /* Receive data copy */ + if (scfcmdp->rcount < SCF_S_CNT_16) { + wkleng = scfcmdp->rcount; + } else { + wkleng = SCF_S_CNT_16; + } + if (wkleng != 0) { + bcopy((void *)&statep->reg_rdata[0], + (void *)scfcmdp->rbuf, wkleng); + } + } else { + SC_DBG_DRV_TRACE(TC_INTR|TC_ERR, __LINE__, + "intr ", 8); + + /* SRAM trace */ + SCF_SRAM_TRACE(statep, DTC_E_PARAM); + + cmn_err(CE_WARN, + "%s,Detected the invalid parameter by XSCF. " + "SCF command = 0x%02x%02x\n", + &statep->pathname[0], scfcmdp->subcmd, + scfcmdp->cmd); + } + break; + + case E_RCI_ACCESS: + /* RCI access error */ + SC_DBG_DRV_TRACE(TC_INTR|TC_ERR, __LINE__, "intr ", 8); + + /* SRAM trace */ + SCF_SRAM_TRACE(statep, DTC_E_RCI_ACCESS); + + cmn_err(CE_WARN, + "%s,RCI access error occurred in XSCF. " + "SCF command = 0x%02x%02x\n", + &statep->pathname[0], scfcmdp->subcmd, + scfcmdp->cmd); + break; + + case E_SCFC_NOPATH: + /* No SCFC path */ + SC_DBG_DRV_TRACE(TC_INTR|TC_ERR, __LINE__, "intr ", 8); + + /* SRAM trace */ + SCF_SRAM_TRACE(statep, DTC_E_SCFC_PATH); + + if (scf_comtbl.scf_exec_p) { + scf_chg_scf(scf_comtbl.scf_exec_p, PATH_STAT_ACTIVE); + scf_comtbl.scf_path_p = scf_comtbl.scf_exec_p; + scf_comtbl.scf_exec_p = 0; + } + scf_comtbl.scf_pchg_event_sub = EVENT_SUB_PCHG_WAIT; + break; + + case RCI_NS: + /* Not support RCI */ + SC_DBG_DRV_TRACE(TC_INTR|TC_MSG, __LINE__, "intr ", 8); + cmn_err(CE_WARN, + "%s,Cannot use RCI interface. " + "SCF command = 0x%02x%02x\n", + &statep->pathname[0], scfcmdp->subcmd, + scfcmdp->cmd); + break; + + default: + SC_DBG_DRV_TRACE(TC_INTR|TC_ERR, __LINE__, "intr ", 8); + + /* SRAM trace */ + SCF_SRAM_TRACE(statep, DTC_ERRRTN | scfcmdp->stat0); + + cmn_err(CE_WARN, + "%s,Invalid status value was notified from XSCF. " + "SCF command = 0x%02x%02x, Status value = 0x%04x\n", + &statep->pathname[0], scfcmdp->subcmd, + scfcmdp->cmd, scfcmdp->status); + scfcmdp->stat0 = E_NOT_SUPPORT; + break; + } + + /* Check SCF command start for interrupt */ + if (scf_comtbl.scf_exec_cmd_id == 0) { + /* SCF command start for interrupt processing */ + scf_intr_cmdcmp_driver(statep, scfcmdp); + } else { + /* Check ioctl command end wait */ + if (scf_comtbl.cmd_end_wait != 0) { + /* Check command return value */ + switch (scfcmdp->stat0) { + case NORMAL_END: + case BUF_FUL: + case RCI_BUSY: + case E_NOT_SUPPORT: + case E_PARAM: + case E_RCI_ACCESS: + case RCI_NS: + if ((scfcmdp->stat0 == NORMAL_END) && + (scfcmdp->cmd == CMD_ALIVE_CHECK)) { + if (scfcmdp->subcmd == + SUB_ALIVE_START) { + scf_alivecheck_start(statep); + } else { + scf_alivecheck_stop(statep); + } + } + if ((scfcmdp->stat0 == NORMAL_END) && + (rxbuff_flag)) { + break; + } + + scf_comtbl.cmd_end_wait = 0; + /* Signal to command end wait */ + cv_signal(&scf_comtbl.cmdend_cv); + SC_DBG_DRV_TRACE(TC_SIGNAL, __LINE__, + &scf_comtbl.cmdend_cv, + sizeof (kcondvar_t)); + break; + + default: + /* INTERFACE */ + /* E_SCFC_NOPATH */ + /* Rx DATA SUM ERROR */ + + /* Set command retry send flag */ + scf_comtbl.scf_cmd_resend_req |= RESEND_IOCTL; + break; + } + } + } + + /* Check receive data division mode */ + if (rxbuff_flag == 1) { + /* Next receive data timer start */ + scf_timer_start(SCF_TIMERCD_NEXTRECV); + scf_comtbl.scf_cmd_exec_flag = 1; + } + +/* + * END_intr_cmdcmp + */ + END_intr_cmdcmp: + + SCFDBGMSG1(SCF_DBGFLAG_SYS, SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +/* + * scf_intr_cmdcmp_driver() + * + * Description: SCF command complete. start for interrupt processing. + * + */ +void +scf_intr_cmdcmp_driver(scf_state_t *statep, struct scf_cmd *scfcmdp) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_intr_cmdcmp_driver() " + int shutdown_flag = 0; + int poff_flag; + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_SYS, SCF_FUNC_NAME ": start"); + + /* Check command code */ + switch (scfcmdp->cmd) { + case CMD_SCFI_PATH: /* SCF Path change command */ + /* Check command return value */ + if (scfcmdp->stat0 != NORMAL_END) { + scf_comtbl.scf_pchg_event_sub = EVENT_SUB_PCHG_WAIT; + + /* Set command retry send flag */ + scf_comtbl.scf_cmd_resend_req |= RESEND_PCHG; + break; + } + + /* Check SCF path change status */ + if (scf_comtbl.scf_path_p != NULL) { + scf_chg_scf(scf_comtbl.scf_path_p, PATH_STAT_ACTIVE); + scf_comtbl.scf_exec_p = scf_comtbl.scf_path_p; + scf_comtbl.scf_path_p = NULL; + /* FMEMA interface */ + scf_avail_cmd_reg_vaddr = + (caddr_t)&statep->scf_regs->COMMAND; + + scf_comtbl.path_change_rcnt = 0; + } + + /* Check Alive check exec */ + if (scf_comtbl.alive_running == SCF_ALIVE_START) { + scf_comtbl.scf_alive_event_sub = EVENT_SUB_ALST_WAIT; + } else { + scf_comtbl.scf_alive_event_sub = EVENT_SUB_NONE; + if (scf_comtbl.suspend_wait == 1) { + scf_comtbl.suspend_wait = 0; + scf_comtbl.scf_suspend_sendstop = 1; + cv_signal(&scf_comtbl.suspend_wait_cv); + SC_DBG_DRV_TRACE(TC_SIGNAL, __LINE__, + &scf_comtbl.suspend_wait_cv, + sizeof (kcondvar_t)); + } + } + scf_comtbl.scf_pchg_event_sub = EVENT_SUB_NONE; + + scf_comtbl.scf_event_flag |= STATUS_EVENT; + + SCF_DBG_NO_INT_REASON; + + /* DSCP interface start */ + scf_dscp_start(FACTOR_PATH_CHG); + break; + + case CMD_PART_POW_CTR: /* power control command */ + /* Check command return value */ + if (scfcmdp->stat0 != NORMAL_END) { + switch (scfcmdp->stat0) { + case BUF_FUL: + case RCI_BUSY: + case E_NOT_SUPPORT: + case E_PARAM: + case E_RCI_ACCESS: + case RCI_NS: + scf_comtbl.scf_poff_event_sub = EVENT_SUB_NONE; + break; + + default: + /* INTERFACE */ + /* E_SCFC_NOPATH */ + /* Rx DATA SUM ERROR */ + scf_comtbl.scf_poff_event_sub = + EVENT_SUB_POFF_WAIT; + + /* Set command retry send flag */ + scf_comtbl.scf_cmd_resend_req |= RESEND_POFF; + break; + } + break; + } + + poff_flag = 0; + scf_comtbl.scf_poff_id = + (uchar_t)((statep->reg_rdata[0] & + 0xFF000000) >> 24); + + SCF_DBG_TEST_INTR_POFF; + + if (scf_comtbl.scf_poff_id == POFF_ID_PANEL) { + /* PANEL */ + if ((scf_comtbl.scf_mode_sw & STATUS_SECURE_MODE) != + STATUS_MODE_LOCK) { + /* Not LOCK */ + SC_DBG_DRV_TRACE(TC_INTR, __LINE__, + "intr ", 8); + if (scf_comtbl.scf_shutdownreason == 0) { + poff_flag = 1; + scf_comtbl.scf_shutdownreason = + REASON_XSCFPOFF; + } + cmn_err(CE_NOTE, + "%s: System shutdown by panel " + "request.\n", scf_driver_name); + } + } else if ((scf_comtbl.scf_poff_id & POFF_ID_MASK) == + POFF_ID_RCI) { + /* RCI */ + SC_DBG_DRV_TRACE(TC_INTR, __LINE__, "intr ", 8); + if (scf_comtbl.scf_shutdownreason == 0) { + poff_flag = 1; + scf_comtbl.scf_shutdownreason = REASON_RCIPOFF; + } + cmn_err(CE_NOTE, + "%s: System shutdown from RCI.\n", + scf_driver_name); + } else if (scf_comtbl.scf_poff_id == POFF_ID_XSCF) { + /* XSCF */ + SC_DBG_DRV_TRACE(TC_INTR, __LINE__, "intr ", 8); + if (scf_comtbl.scf_shutdownreason == 0) { + poff_flag = 1; + scf_comtbl.scf_shutdownreason = REASON_XSCFPOFF; + } + cmn_err(CE_NOTE, + "%s: System shutdown by XSCF " + "request.\n", scf_driver_name); + } + + if (poff_flag) { + cmn_err(CE_CONT, + "%s: Shutdown was executed.\n", + scf_driver_name); + /* System shutdown start */ + do_shutdown(); + } + + scf_comtbl.scf_poff_event_sub = EVENT_SUB_NONE; + break; + + case CMD_INT_REASON: /* Event information command */ + /* Check command return value */ + if ((scfcmdp->stat0 != NORMAL_END) && + (scfcmdp->stat0 != SCF_STAT0_RDATA_SUM)) { + switch (scfcmdp->stat0) { + case BUF_FUL: + case RCI_BUSY: + case E_NOT_SUPPORT: + case E_PARAM: + case E_RCI_ACCESS: + case RCI_NS: + scf_comtbl.scf_shut_event_sub = EVENT_SUB_NONE; + break; + + default: + /* INTERFACE */ + /* E_SCFC_NORATH */ + if (scf_comtbl.scf_shut_event_sub == + EVENT_SUB_SHUT_EXEC) { + scf_comtbl.scf_shut_event_sub = + EVENT_SUB_SHUT_WAIT; + } else { + scf_comtbl.scf_shut_event_sub = + EVENT_SUB_WAIT; + } + + /* Set command retry send flag */ + scf_comtbl.scf_cmd_resend_req |= RESEND_SHUT; + break; + } + break; + } + + /* Check factor detail disp */ + if ((scfcmdp->stat0 == SCF_STAT0_RDATA_SUM) && + (scfcmdp->subcmd == SUB_INT_REASON_DISP)) { + /* Send detail re-disp */ + scf_comtbl.int_reason_retry = 1; + if (scf_comtbl.scf_shut_event_sub == + EVENT_SUB_SHUT_EXEC) { + scf_comtbl.scf_shut_event_sub = + EVENT_SUB_SHUT_WAIT; + } else { + scf_comtbl.scf_shut_event_sub = EVENT_SUB_WAIT; + } + break; + } + + if (scfcmdp->stat0 == NORMAL_END) { + + SCF_DBG_TEST_DSENS(scfcmdp, (void *)scfcmdp->rbuf, + (int)scfcmdp->rbufleng); + + scf_comtbl.int_reason_retry = 0; + /* + * Event interrupt factor check + * processing + */ + shutdown_flag = scf_intr_dsens(scfcmdp, + (void *)scfcmdp->rbuf, (int)scfcmdp->rbufleng); + } else { + if (scf_comtbl.scf_shut_event_sub == + EVENT_SUB_SHUT_EXEC) { + shutdown_flag = DEV_SENSE_SHUTDOWN; + } + } + if (shutdown_flag == DEV_SENSE_SHUTDOWN) { + cmn_err(CE_CONT, + "%s: Shutdown was executed.\n", + scf_driver_name); + /* System shutdown start */ + do_shutdown(); + } + scf_comtbl.scf_shut_event_sub = EVENT_SUB_NONE; + break; + + case CMD_ALIVE_CHECK: /* Alive check command */ + /* Check command return value */ + switch (scfcmdp->stat0) { + case NORMAL_END: + case BUF_FUL: + case RCI_BUSY: + case E_NOT_SUPPORT: + case E_PARAM: + case E_SCFC_NOPATH: + case E_RCI_ACCESS: + case RCI_NS: + if (scfcmdp->stat0 == NORMAL_END) { + if (scfcmdp->subcmd == SUB_ALIVE_START) { + scf_alivecheck_start(statep); + } else { + scf_alivecheck_stop(statep); + } + } + + if ((scf_comtbl.scf_alive_event_sub == + EVENT_SUB_ALSP_EXEC) && + (scf_comtbl.suspend_wait)) { + /* Signal to suspend wait */ + scf_comtbl.suspend_wait = 0; + scf_comtbl.scf_suspend_sendstop = 1; + cv_signal(&scf_comtbl.suspend_wait_cv); + SC_DBG_DRV_TRACE(TC_SIGNAL, __LINE__, + &scf_comtbl.suspend_wait_cv, + sizeof (kcondvar_t)); + } + if ((scf_comtbl.scf_alive_event_sub == + EVENT_SUB_ALST_EXEC) || + (scf_comtbl.scf_alive_event_sub == + EVENT_SUB_ALSP_EXEC)) { + scf_comtbl.scf_alive_event_sub = EVENT_SUB_NONE; + } + break; + + default: + /* INTERFACE */ + /* Rx DATA SUM ERROR */ + if (scf_comtbl.alive_running == SCF_ALIVE_START) { + scf_comtbl.scf_alive_event_sub = + EVENT_SUB_ALST_WAIT; + } else { + scf_comtbl.scf_alive_event_sub = + EVENT_SUB_ALSP_WAIT; + } + + /* Set command retry send flag */ + if ((scfcmdp->subcmd == SUB_ALIVE_START) && + (scf_comtbl.scf_alive_event_sub == + EVENT_SUB_ALST_WAIT)) { + scf_comtbl.scf_cmd_resend_req |= RESEND_ALST; + } else if ((scfcmdp->subcmd == SUB_ALIVE_STOP) && + (scf_comtbl.scf_alive_event_sub == + EVENT_SUB_ALSP_WAIT)) { + scf_comtbl.scf_cmd_resend_req |= RESEND_ALSP; + } + break; + } + break; + + case CMD_REPORT: /* Report command */ + /* Check command return value */ + switch (scfcmdp->stat0) { + case NORMAL_END: + case BUF_FUL: + case RCI_BUSY: + case E_NOT_SUPPORT: + case E_PARAM: + case E_SCFC_NOPATH: + case E_RCI_ACCESS: + case RCI_NS: + if ((scfcmdp->stat0 == NORMAL_END) && + (scf_comtbl.alive_running == SCF_ALIVE_START)) { + /* Check Alive check exec */ + scf_comtbl.scf_alive_event_sub = + EVENT_SUB_ALST_WAIT; + } + + if ((scf_comtbl.scf_report_event_sub == + EVENT_SUB_REPORT_RUN_EXEC) || + (scf_comtbl.scf_report_event_sub == + EVENT_SUB_REPORT_SHOT_EXEC)) { + scf_comtbl.scf_report_event_sub = + EVENT_SUB_NONE; + } + + if (scfcmdp->stat0 == BUF_FUL) { + if (scf_comtbl.report_buf_ful_rcnt != + scf_buf_ful_rcnt) { + scf_comtbl.report_buf_ful_rcnt++; + scf_timer_start(SCF_TIMERCD_BUF_FUL); + } else { + scf_comtbl.report_buf_ful_rcnt = 0; + } + } else { + scf_comtbl.report_buf_ful_rcnt = 0; + } + + if (scfcmdp->stat0 == RCI_BUSY) { + if (scf_comtbl.report_rci_busy_rcnt != + scf_rci_busy_rcnt) { + scf_comtbl.report_rci_busy_rcnt++; + scf_timer_start(SCF_TIMERCD_RCI_BUSY); + } else { + scf_comtbl.report_rci_busy_rcnt = 0; + } + } else { + scf_comtbl.report_rci_busy_rcnt = 0; + } + break; + + default: + /* INTERFACE */ + /* Rx DATA SUM ERROR */ + if (scf_comtbl.scf_report_event_sub == + EVENT_SUB_REPORT_RUN_EXEC) { + scf_comtbl.scf_report_event_sub = + EVENT_SUB_REPORT_RUN_WAIT; + + /* Set command retry send flag */ + scf_comtbl.scf_cmd_resend_req |= + RESEND_REPORT_RUN; + } else { + scf_comtbl.scf_report_event_sub = + EVENT_SUB_REPORT_SHUT_WAIT; + + /* Set command retry send flag */ + scf_comtbl.scf_cmd_resend_req |= + RESEND_REPORT_SHUT; + } + break; + } + break; + } + + SCFDBGMSG(SCF_DBGFLAG_SYS, SCF_FUNC_NAME ": end"); +} + + +/* + * scf_intr_dsens() + * + * Description: Event factor check processing. + * + */ +/* ARGSUSED */ +int +scf_intr_dsens(struct scf_cmd *scfcmdp, scf_int_reason_t *int_rp, int len) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_intr_dsens() " + scf_int_reason_t *rbuf; + uchar_t category_code; + uchar_t sub_status; + uchar_t category_type; + time_t timestamp; + int ret = 0; + int ent = 0; + int getevent_flag; + int max_ent; + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_SYS, SCF_FUNC_NAME ": start"); + + rbuf = int_rp; + max_ent = len / SCF_INT_REASON_SIZE; + if (max_ent > 4) { + max_ent = 4; + } + + /* entry count loop */ + while ((rbuf->b[4]) && (ent < max_ent)) { + /* Save last event */ + bcopy((void *)&rbuf->b[0], (void *)&scf_comtbl.last_event[0], + SCF_INT_REASON_SIZE); + + /* Check SCFIOCEVENTLIST */ + getevent_flag = scf_push_getevent(&rbuf->b[0]); + if (getevent_flag == 0) { + /* wake up waiting thread */ + cv_signal(&scf_comtbl.getevent_cv); + SC_DBG_DRV_TRACE(TC_SIGNAL, __LINE__, + &scf_comtbl.getevent_cv, sizeof (kcondvar_t)); + } + + /* get category code of the sense */ + category_code = rbuf->b[4] & (~DEV_SENSE_SHUTDOWN); + sub_status = rbuf->b[4]; + category_type = rbuf->b[6]; + SC_DBG_DRV_TRACE(TC_DSENS, __LINE__, &rbuf->b[0], 8); + SC_DBG_DRV_TRACE(TC_DSENS, __LINE__, &rbuf->b[8], 8); + SCFDBGMSG4(SCF_DBGFLAG_REG, + "SENSE = 0x%08x 0x%08x 0x%08x 0x%08x", + rbuf->four_bytes_access[0], rbuf->four_bytes_access[1], + rbuf->four_bytes_access[2], rbuf->four_bytes_access[3]); + + switch (category_code) { + case DEV_SENSE_FANUNIT: + /* fan unit failure */ + SC_DBG_DRV_TRACE(TC_INTR|TC_ERR, __LINE__, + "intr_dse", 8); + + if (category_type == DEV_SENSE_ATTR_OWN) { + cmn_err(CE_WARN, + "%s: fan unit failure" + ", sub status = 0x%02x\n", + scf_driver_name, sub_status); + if ((sub_status & DEV_SENSE_SHUTDOWN) && + (scf_comtbl.scf_shutdownreason == 0)) { + scf_comtbl.scf_shutdownreason = + REASON_SHUTDOWN_FAN; + ret = DEV_SENSE_SHUTDOWN; + } + } else { + cmn_err(CE_WARN, + "%s: fan unit failure on " + "RCI(addr = 0x%08x)" + ", FAN#%d, sub status = 0x%02x,\n" + "sense info =" + " 0x%02x 0x%02x 0x%02x 0x%02x" + " 0x%02x 0x%02x 0x%02x 0x%02x\n", + scf_driver_name, + rbuf->four_bytes_access[0], + rbuf->b[9], sub_status, + rbuf->b[0], rbuf->b[1], + rbuf->b[2], rbuf->b[3], + rbuf->b[8], rbuf->b[9], + rbuf->b[10], rbuf->b[11]); + } + break; + + case DEV_SENSE_PWRUNIT: + /* power unit failure */ + SC_DBG_DRV_TRACE(TC_INTR|TC_ERR, __LINE__, + "intr_dse", 8); + + if (category_type == DEV_SENSE_ATTR_OWN) { + cmn_err(CE_WARN, + "%s: power supply unit failure" + ", sub status = 0x%02x\n", + scf_driver_name, sub_status); + if ((sub_status & DEV_SENSE_SHUTDOWN) && + (scf_comtbl.scf_shutdownreason == 0)) { + scf_comtbl.scf_shutdownreason = + REASON_SHUTDOWN_PSU; + ret = DEV_SENSE_SHUTDOWN; + } + } else { + cmn_err(CE_WARN, + "%s: power supply unit failure on " + "RCI(addr = 0x%08x)" + ", FEP#%d, sub status = 0x%02x,\n" + "sense info =" + " 0x%02x 0x%02x 0x%02x 0x%02x" + " 0x%02x 0x%02x 0x%02x 0x%02x\n", + scf_driver_name, + rbuf->four_bytes_access[0], + rbuf->b[11], + sub_status, + rbuf->b[0], rbuf->b[1], + rbuf->b[2], rbuf->b[3], + rbuf->b[8], rbuf->b[9], + rbuf->b[10], rbuf->b[11]); + } + break; + + case DEV_SENSE_UPS: + /* UPS failure */ + SC_DBG_DRV_TRACE(TC_INTR|TC_ERR, __LINE__, + "intr_dse", 8); + + if (category_type != DEV_SENSE_ATTR_OWN) { + break; + } + + switch (rbuf->b[8] & DEV_SENSE_UPS_MASK) { + case DEV_SENSE_UPS_LOWBAT: + SC_DBG_DRV_TRACE(TC_INTR|TC_ERR, __LINE__, + "intr_dse", 8); + cmn_err(CE_WARN, + "%s: UPS low battery" + " was detected, sub status = 0x%02x\n", + scf_driver_name, sub_status); + break; + + default: + SC_DBG_DRV_TRACE(TC_INTR|TC_ERR, + __LINE__, "intr_dse", 8); + cmn_err(CE_WARN, + "%s: UPS failure" + " was detected, sub status = 0x%02x\n", + scf_driver_name, sub_status); + break; + } + if ((sub_status & DEV_SENSE_SHUTDOWN) && + (scf_comtbl.scf_shutdownreason == 0)) { + scf_comtbl.scf_shutdownreason = + REASON_SHUTDOWN_UPS; + ret = DEV_SENSE_SHUTDOWN; + } + break; + + case DEV_SENSE_THERMAL: + /* thermal failure */ + SC_DBG_DRV_TRACE(TC_INTR|TC_ERR, __LINE__, + "intr_dse", 8); + + if (category_type == DEV_SENSE_ATTR_OWN) { + cmn_err(CE_WARN, + "%s: thermal alarm" + ", sub status = 0x%02x\n", + scf_driver_name, sub_status); + if ((sub_status & DEV_SENSE_SHUTDOWN) && + (scf_comtbl.scf_shutdownreason == 0)) { + scf_comtbl.scf_shutdownreason = + REASON_SHUTDOWN_THERMAL; + ret = DEV_SENSE_SHUTDOWN; + } + } else { + cmn_err(CE_WARN, + "%s: thermal alarm on " + "RCI(addr = 0x%08x)" + ", SENSOR#%d, sub status = 0x%02x,\n" + "sense info =" + " 0x%02x 0x%02x 0x%02x 0x%02x" + " 0x%02x 0x%02x 0x%02x 0x%02x\n", + scf_driver_name, + rbuf->four_bytes_access[0], + rbuf->b[9], sub_status, + rbuf->b[0], rbuf->b[1], + rbuf->b[2], rbuf->b[3], + rbuf->b[8], rbuf->b[9], + rbuf->b[10], rbuf->b[11]); + } + break; + + case DEV_SENSE_PWRSR: + /* power stop */ + SC_DBG_DRV_TRACE(TC_INTR|TC_ERR, __LINE__, + "intr_dse", 8); + + if (category_type != DEV_SENSE_ATTR_OWN) { + break; + } + + SC_DBG_DRV_TRACE(TC_INTR|TC_ERR, __LINE__, + "intr_dse", 8); + cmn_err(CE_WARN, + "%s: Input power down was detected. " + "UPS is activated" + ", sub status = 0x%02x\n", + scf_driver_name, sub_status); + if (sub_status & DEV_SENSE_SHUTDOWN) { + if (scf_comtbl.shutdown_start_reported == 0) { + scf_comtbl.poff_factor = + SCF_POFF_FACTOR_PFAIL; + } + if (scf_comtbl.scf_shutdownreason == 0) { + scf_comtbl.scf_shutdownreason = + REASON_SHUTDOWN_UPS; + ret = DEV_SENSE_SHUTDOWN; + } + } + break; + + case DEV_SENSE_NODE: + /* node error */ + SC_DBG_DRV_TRACE(TC_INTR|TC_ERR, __LINE__, + "intr_dse", 8); + + if (category_type == DEV_SENSE_ATTR_OWN) { + break; + } + + cmn_err(CE_WARN, + "%s: node error on RCI(addr = 0x%08x)" + ", sub status = 0x%02x,\n" + "sense info =" + " 0x%02x 0x%02x 0x%02x 0x%02x" + " 0x%02x 0x%02x 0x%02x 0x%02x\n", + scf_driver_name, + rbuf->four_bytes_access[0], + sub_status, + rbuf->b[0], rbuf->b[1], + rbuf->b[2], rbuf->b[3], + rbuf->b[8], rbuf->b[9], + rbuf->b[10], rbuf->b[11]); + if (rbuf->b[9] == DEV_SENSE_NODE_STCKTO) { + scf_comtbl.rcidown_event_flag = 1; + scf_comtbl.scfreport_rcidown.rci_addr = + rbuf->four_bytes_access[0]; + scf_comtbl.scfreport_rcidown.report_sense[0] = + REPORT_STAT_RCIDWN; + scf_comtbl.scfreport_rcidown.report_sense[1] = + rbuf->b[9]; + scf_comtbl.scfreport_rcidown.report_sense[2] = + rbuf->b[10]; + scf_comtbl.scfreport_rcidown.report_sense[3] = + rbuf->b[11]; + scf_comtbl.scfreport_rcidown.timestamp = + ddi_get_time(); + /* wake up waiting thread */ + cv_signal(&scf_comtbl.rsense_cv); + SC_DBG_DRV_TRACE(TC_SIGNAL, __LINE__, + &scf_comtbl.rsense_cv, + sizeof (kcondvar_t)); + } + break; + + case DEV_SENSE_SYS_REPORT: + /* system status report */ + timestamp = ddi_get_time(); + (void) scf_push_reportsense(rbuf->four_bytes_access[0], + &rbuf->b[8], timestamp); + /* wake up waiting thread */ + cv_signal(&scf_comtbl.rsense_cv); + SC_DBG_DRV_TRACE(TC_SIGNAL, __LINE__, + &scf_comtbl.rsense_cv, sizeof (kcondvar_t)); + break; + + case DEV_SENSE_PANIC_REQ: + /* panic request */ + cmn_err(CE_PANIC, + "%s: panic request from RCI(addr = 0x%08x)\n", + scf_driver_name, + rbuf->four_bytes_access[0]); + break; + + case DEV_SENSE_IONODESTAT: + /* I/O node status */ + if (category_type == DEV_SENSE_ATTR_OWN) { + break; + } + + cmn_err(CE_NOTE, + "%s: I/O node status sense from " + "RCI(addr = 0x%08x), " + "sub status = 0x%02x,\n" + "sense info = 0x%02x 0x%02x 0x%02x 0x%02x" + " 0x%02x 0x%02x 0x%02x 0x%02x\n", + scf_driver_name, + rbuf->four_bytes_access[0], + sub_status, + rbuf->b[0], rbuf->b[1], + rbuf->b[2], rbuf->b[3], + rbuf->b[8], rbuf->b[9], + rbuf->b[10], rbuf->b[11]); + break; + + case DEV_SENSE_STATUS_RPT: + /* Deveice status print */ + if (scf_comtbl.rdctrl_end_wait) { + /* rdctrl devsense? (for SCFIOCRDCTRL) */ + /* keep devsense info */ + scf_comtbl.rdctrl_sense_category_code = + category_code; + bcopy((void *)&rbuf->b[0], + (void *)&scf_comtbl.rdctrl_sense[0], + SCF_INT_REASON_SIZE); + cv_signal(&scf_comtbl.rdcsense_cv); + SC_DBG_DRV_TRACE(TC_SIGNAL, __LINE__, + &scf_comtbl.rdcsense_cv, + sizeof (kcondvar_t)); + } + break; + + default: + /* Devive status print */ + if (((category_code & 0xf0) == DEV_SENSE_RCI_PATH40) && + (scf_comtbl.rdctrl_end_wait)) { + /* rdctrl devsense (for SCFIOCRDCTRL) */ + /* keep devsense info */ + scf_comtbl.rdctrl_sense_category_code = + category_code; + bcopy((void *)&rbuf->b[0], + (void *)&scf_comtbl.rdctrl_sense[0], + SCF_INT_REASON_SIZE); + cv_signal(&scf_comtbl.rdcsense_cv); + SC_DBG_DRV_TRACE(TC_SIGNAL, __LINE__, + &scf_comtbl.rdcsense_cv, + sizeof (kcondvar_t)); + } + break; + + } + +/* + * NEXT_intr_dsens + */ + NEXT_intr_dsens: + + rbuf = (void *)((char *)rbuf + SCF_INT_REASON_SIZE); + ent++; + } + + SCFDBGMSG1(SCF_DBGFLAG_SYS, SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +/* + * scf_status_change() + * + * Description: SCF status change processing. + * + */ +void +scf_status_change(scf_state_t *statep) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_status_change() " + uint8_t scf_unit; + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_SYS, SCF_FUNC_NAME ": start"); + + /* Check SCF status */ + if ((statep->reg_status_exr & STATUS_SCF_STATUS) == STATUS_SCF_ONLINE) { + /* + * SCF online + */ + if (scf_comtbl.scf_status == SCF_STATUS_OFFLINE) { + cmn_err(CE_NOTE, "%s: SCF online.\n", scf_driver_name); + } + scf_comtbl.scf_status = SCF_STATUS_ONLINE; + + /* SRAM trace */ + SCF_SRAM_TRACE(statep, DTC_ONLINE); + + /* Check online wait timer exec */ + if (scf_timer_check(SCF_TIMERCD_ONLINE) == SCF_TIMER_NOT_EXEC) { + /* DCSP interface re-start */ + scf_dscp_stop(FACTOR_OFFLINE); + scf_dscp_start(FACTOR_ONLINE); + } else { + /* DCSP interface start */ + scf_dscp_start(FACTOR_ONLINE); + + /* SCF online timer stop */ + scf_timer_stop(SCF_TIMERCD_ONLINE); + + /* Check SCF command exec */ + if (scf_comtbl.scf_cmd_exec_flag) { + /* Set command wait status */ + scf_cmdwait_status_set(); + scf_comtbl.scf_cmd_exec_flag = 0; + } + + /* Check Alive check exec */ + if (scf_comtbl.alive_running == SCF_ALIVE_START) { + scf_comtbl.scf_alive_event_sub = + EVENT_SUB_ALST_WAIT; + } + } + } else { + /* + * SCF offline + */ + if (scf_comtbl.scf_status != SCF_STATUS_OFFLINE) { + if (statep->reg_status_exr & STATUS_SCF_NO) { + scf_unit = 1; + } else { + scf_unit = 0; + } + cmn_err(CE_WARN, + "%s: SCF went to offline mode. unit=%d", + scf_driver_name, scf_unit); + } + scf_comtbl.scf_status = SCF_STATUS_OFFLINE; + + /* SRAM trace */ + SCF_SRAM_TRACE(statep, DTC_OFFLINE); + + /* Check online wait timer exec */ + if (scf_timer_check(SCF_TIMERCD_ONLINE) == SCF_TIMER_NOT_EXEC) { + /* DCSP interface stop */ + scf_dscp_stop(FACTOR_OFFLINE); + + statep->online_to_rcnt = 0; + /* SCF online timer start */ + scf_timer_start(SCF_TIMERCD_ONLINE); + } + } + + SCFDBGMSG(SCF_DBGFLAG_SYS, SCF_FUNC_NAME ": end"); +} + + +/* + * scf_next_cmd_check() + * + * Description: Next command send and check processing. + * + */ +void +scf_next_cmd_check(scf_state_t *statep) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_next_cmd_check() " + struct scf_cmd *scfcmdp = &scf_comtbl.scf_cmd_intr; + int offline_ret; + int cmdbusy_ret; + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_SYS, SCF_FUNC_NAME ": start"); + + /* Check suspend send stop */ + if (scf_comtbl.scf_suspend_sendstop) { + goto END_next_cmd_check; + } + + if ((scf_comtbl.scf_path_p == NULL) && + (scf_comtbl.scf_pchg_event_sub == EVENT_SUB_PCHG_WAIT)) { + scf_chg_scf(statep, PATH_STAT_ACTIVE); + scf_comtbl.scf_path_p = statep; + } + + if (scf_comtbl.scf_cmd_exec_flag == 0) { + /* send comannd for interrupt */ + offline_ret = scf_offline_check(statep, FLAG_ON); + cmdbusy_ret = scf_cmdbusy_check(statep); + + if ((offline_ret != SCF_PATH_ONLINE) || + (cmdbusy_ret != SCF_COMMAND_READY)) { + goto END_next_cmd_check; + } + } + + /* Check SCF Path change request */ + if ((scf_comtbl.scf_cmd_exec_flag == 0) && + (scf_comtbl.scf_pchg_event_sub == EVENT_SUB_PCHG_WAIT)) { + /* Send SCF Path change command */ + scfcmdp->cmd = CMD_SCFI_PATH; + scfcmdp->subcmd = SUB_CMD_PATH; + bzero((void *)&scf_comtbl.scf_sbuf[0], SCF_S_CNT_16); + scf_comtbl.scf_sbuf[0] = CMD_PATH_TYPE_SCFD; + scfcmdp->sbuf = &scf_comtbl.scf_sbuf[0]; + scfcmdp->scount = SCF_S_CNT_15; + scfcmdp->rcount = 0; + scfcmdp->flag = SCF_USE_S_BUF; + if ((scf_comtbl.scf_cmd_resend_req & RESEND_PCHG) != 0) { + scf_comtbl.scf_cmd_resend_flag = 1; + scf_comtbl.scf_cmd_resend_req &= ~RESEND_PCHG; + } + scf_i_send_cmd(scfcmdp, statep); + scf_comtbl.scf_pchg_event_sub = EVENT_SUB_PCHG_EXEC; + } + + if (scf_comtbl.scf_cmd_exec_flag == 0) { + /* Check shutdown event information request */ + if ((scf_comtbl.scf_shut_event_sub == EVENT_SUB_NONE) && + (scf_comtbl.scf_event_flag & STATUS_SHUTDOWN)) { + scf_comtbl.scf_event_flag &= + (~(STATUS_SHUTDOWN | STATUS_EVENT)); + scf_comtbl.scf_shut_event_sub = EVENT_SUB_SHUT_WAIT; + } + if (scf_comtbl.scf_shut_event_sub == EVENT_SUB_SHUT_WAIT) { + /* Send event information command */ + scfcmdp->cmd = CMD_INT_REASON; + if (scf_comtbl.int_reason_retry == 0) { + scfcmdp->subcmd = SUB_INT_REASON_DISP; + } else { + scfcmdp->subcmd = SUB_INT_REASON_RETRY; + } + scfcmdp->scount = 0; + scfcmdp->rbuf = &scf_comtbl.scf_rbuf[0]; + scfcmdp->rcount = SCF_INT_CNT_MAX; + scfcmdp->flag = SCF_USE_SLBUF; + if ((scf_comtbl.scf_cmd_resend_req & RESEND_SHUT) != + 0) { + scf_comtbl.scf_cmd_resend_flag = 1; + scf_comtbl.scf_cmd_resend_req &= ~RESEND_SHUT; + } + scf_i_send_cmd(scfcmdp, statep); + scf_comtbl.scf_shut_event_sub = EVENT_SUB_SHUT_EXEC; + } + } + + if (scf_comtbl.scf_cmd_exec_flag == 0) { + /* Check power off factor request */ + if ((scf_comtbl.scf_poff_event_sub == EVENT_SUB_NONE) && + (scf_comtbl.scf_event_flag & STATUS_POFF)) { + scf_comtbl.scf_event_flag &= (~STATUS_POFF); + scf_comtbl.scf_poff_event_sub = EVENT_SUB_POFF_WAIT; + } + if (scf_comtbl.scf_poff_event_sub == EVENT_SUB_POFF_WAIT) { + /* Send power off factor command */ + scfcmdp->cmd = CMD_PART_POW_CTR; + scfcmdp->subcmd = SUB_POFFID; + scfcmdp->scount = 0; + scfcmdp->rbuf = &scf_comtbl.scf_rbuf[0]; + scfcmdp->rcount = SCF_S_CNT_15; + scfcmdp->flag = SCF_USE_SSBUF; + if ((scf_comtbl.scf_cmd_resend_req & RESEND_POFF) != + 0) { + scf_comtbl.scf_cmd_resend_flag = 1; + scf_comtbl.scf_cmd_resend_req &= ~RESEND_POFF; + } + scf_i_send_cmd(scfcmdp, statep); + scf_comtbl.scf_poff_event_sub = EVENT_SUB_POFF_EXEC; + } + } + + if (scf_comtbl.scf_cmd_exec_flag == 0) { + /* Check event information request */ + if ((scf_comtbl.scf_shut_event_sub == EVENT_SUB_NONE) && + (scf_comtbl.scf_event_flag & STATUS_EVENT)) { + scf_comtbl.scf_event_flag &= (~STATUS_EVENT); + scf_comtbl.scf_shut_event_sub = EVENT_SUB_WAIT; + } + if (scf_comtbl.scf_shut_event_sub == EVENT_SUB_WAIT) { + /* Send event information command */ + scfcmdp->cmd = CMD_INT_REASON; + if (scf_comtbl.int_reason_retry == 0) { + scfcmdp->subcmd = SUB_INT_REASON_DISP; + } else { + scfcmdp->subcmd = SUB_INT_REASON_RETRY; + } + scfcmdp->scount = 0; + scfcmdp->rbuf = &scf_comtbl.scf_rbuf[0]; + scfcmdp->rcount = SCF_INT_CNT_MAX; + scfcmdp->flag = SCF_USE_SLBUF; + if ((scf_comtbl.scf_cmd_resend_req & RESEND_SHUT) != + 0) { + scf_comtbl.scf_cmd_resend_flag = 1; + scf_comtbl.scf_cmd_resend_req &= ~RESEND_SHUT; + } + scf_i_send_cmd(scfcmdp, statep); + scf_comtbl.scf_shut_event_sub = EVENT_SUB_EXEC; + } + } + + if ((scf_comtbl.scf_cmd_exec_flag == 0) && + ((scf_timer_check(SCF_TIMERCD_BUF_FUL) == + SCF_TIMER_NOT_EXEC) && + (scf_timer_check(SCF_TIMERCD_RCI_BUSY) == + SCF_TIMER_NOT_EXEC))) { + /* Check report request */ + if (scf_comtbl.scf_report_event_sub == + EVENT_SUB_REPORT_RUN_WAIT) { + /* Send report(System running) command */ + scfcmdp->cmd = CMD_REPORT; + scfcmdp->subcmd = SUB_SYSTEM_STATUS_RPT; + bzero((void *)&scf_comtbl.scf_sbuf[0], SCF_S_CNT_16); + scf_comtbl.scf_sbuf[0] = REPORT_STAT_SYSTEM_RUNNING; + scf_comtbl.scf_sbuf[1] = 0; + scf_comtbl.scf_sbuf[2] = 0; + scf_comtbl.scf_sbuf[3] = 0; + scfcmdp->sbuf = &scf_comtbl.scf_sbuf[0]; + scfcmdp->scount = SCF_S_CNT_15; + scfcmdp->rcount = 0; + scfcmdp->flag = SCF_USE_S_BUF; + if ((scf_comtbl.scf_cmd_resend_req & + RESEND_REPORT_RUN) != 0) { + scf_comtbl.scf_cmd_resend_flag = 1; + scf_comtbl.scf_cmd_resend_req &= + ~RESEND_REPORT_RUN; + } + scf_i_send_cmd(scfcmdp, statep); + scf_comtbl.scf_report_event_sub = + EVENT_SUB_REPORT_RUN_EXEC; + scf_comtbl.scf_last_report = SCF_SYSTEM_RUNNING; + } else if (scf_comtbl.scf_report_event_sub == + EVENT_SUB_REPORT_SHUT_WAIT) { + /* Send report(Shutdown start) command */ + scfcmdp->cmd = CMD_REPORT; + scfcmdp->subcmd = SUB_SYSTEM_STATUS_RPT; + bzero((void *)&scf_comtbl.scf_sbuf[0], + SCF_S_CNT_16); + scf_comtbl.scf_sbuf[0] = + REPORT_STAT_SHUTDOWN_START; + scf_comtbl.scf_sbuf[1] = + scf_poff_factor[scf_comtbl.poff_factor][0]; + scf_comtbl.scf_sbuf[2] = + scf_poff_factor[scf_comtbl.poff_factor][1]; + scf_comtbl.scf_sbuf[3] = + scf_poff_factor[scf_comtbl.poff_factor][2]; + scfcmdp->sbuf = &scf_comtbl.scf_sbuf[0]; + scfcmdp->scount = SCF_S_CNT_15; + scfcmdp->rcount = 0; + scfcmdp->flag = SCF_USE_S_BUF; + if ((scf_comtbl.scf_cmd_resend_req & + RESEND_REPORT_SHUT) != 0) { + scf_comtbl.scf_cmd_resend_flag = 1; + scf_comtbl.scf_cmd_resend_req &= + ~RESEND_REPORT_SHUT; + } + scf_i_send_cmd(scfcmdp, statep); + scf_comtbl.scf_report_event_sub = + EVENT_SUB_REPORT_SHOT_EXEC; + scf_comtbl.scf_last_report = SCF_SHUTDOWN_START; + scf_comtbl.shutdown_start_reported = 1; + } + } + + if (scf_comtbl.scf_cmd_exec_flag == 0) { + /* Check alive check request */ + if (scf_comtbl.scf_alive_event_sub == EVENT_SUB_ALST_WAIT) { + /* Send alive check start command */ + scfcmdp->cmd = CMD_ALIVE_CHECK; + scfcmdp->subcmd = SUB_ALIVE_START; + bzero((void *)&scf_comtbl.scf_sbuf[0], SCF_S_CNT_16); + scf_comtbl.scf_sbuf[0] = scf_alive_watch_code; + scf_comtbl.scf_sbuf[1] = scf_alive_phase_code; + scf_alive_phase_code++; + scf_comtbl.scf_sbuf[2] = scf_alive_interval_time; + scf_comtbl.scf_sbuf[3] = scf_alive_monitor_time; + scf_comtbl.scf_sbuf[4] = + (uchar_t)(scf_alive_panic_time >> 8); + scf_comtbl.scf_sbuf[5] = + (uchar_t)(scf_alive_panic_time); + scfcmdp->sbuf = &scf_comtbl.scf_sbuf[0]; + scfcmdp->scount = SCF_S_CNT_15; + scfcmdp->rcount = 0; + scfcmdp->flag = SCF_USE_S_BUF; + if ((scf_comtbl.scf_cmd_resend_req & RESEND_ALST) != + 0) { + scf_comtbl.scf_cmd_resend_flag = 1; + scf_comtbl.scf_cmd_resend_req &= ~RESEND_ALST; + } + scf_i_send_cmd(scfcmdp, statep); + scf_comtbl.scf_alive_event_sub = EVENT_SUB_ALST_EXEC; + } else if (scf_comtbl.scf_alive_event_sub == + EVENT_SUB_ALSP_WAIT) { + /* Send alive check stop command */ + scfcmdp->cmd = CMD_ALIVE_CHECK; + scfcmdp->subcmd = SUB_ALIVE_STOP; + scfcmdp->scount = 0; + scfcmdp->rcount = 0; + scfcmdp->flag = SCF_USE_S_BUF; + if ((scf_comtbl.scf_cmd_resend_req & RESEND_ALSP) != + 0) { + scf_comtbl.scf_cmd_resend_flag = 1; + scf_comtbl.scf_cmd_resend_req &= ~RESEND_ALSP; + } + scf_i_send_cmd(scfcmdp, statep); + scf_comtbl.scf_alive_event_sub = EVENT_SUB_ALSP_EXEC; + } + } + + /* Check send wait */ + if ((scf_comtbl.scf_cmd_exec_flag == 0) && (scf_comtbl.cmd_end_wait)) { + if ((scf_comtbl.scf_cmd_resend_req & RESEND_IOCTL) != 0) { + scf_comtbl.scf_cmd_resend_flag = 1; + scf_comtbl.scf_cmd_resend_req &= ~RESEND_IOCTL; + } + scf_i_send_cmd(scf_comtbl.scf_cmdp, statep); + + scf_comtbl.scf_exec_cmd_id = 1; + } + + /* Signal to command wait */ + if ((scf_comtbl.scf_cmd_exec_flag == 0) && + (scf_comtbl.cmd_busy_wait != 0)) { + scf_comtbl.cmd_busy_wait = 0; + cv_signal(&scf_comtbl.cmdwait_cv); + SC_DBG_DRV_TRACE(TC_SIGNAL, __LINE__, &scf_comtbl.cmdwait_cv, + sizeof (kcondvar_t)); + } + +/* + * END_next_cmd_check + */ + END_next_cmd_check: + + SCFDBGMSG(SCF_DBGFLAG_SYS, SCF_FUNC_NAME ": end"); +} + + +/* + * scf_next_rxdata_get() + * + * Description: Next receive data Read processing. + * + */ +void +scf_next_rxdata_get(void) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_next_rxdata_get() " + scf_state_t *statep; + struct scf_cmd *scfcmdp; + uint32_t sum4; + uint8_t *wk_in_p; + uint8_t *wk_out_p; + uint32_t *wk_in_p32; + uint_t wk_leng; + uint_t rxbuff_cnt; + uint_t rxbuff_offset; + int path_ret; + int ii; + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_SYS, SCF_FUNC_NAME ": start"); + + /* Check command send exec */ + if (scf_comtbl.scf_cmd_exec_flag == 0) { + goto END_next_rxdata_get; + } + + /* Get SCF path status */ + path_ret = scf_path_check(&statep); + /* Check SCF path status */ + if (path_ret != SCF_PATH_ONLINE) { + goto END_next_rxdata_get; + } + + /* Check remainder receive data size */ + if (scf_comtbl.scf_rem_rxbuff_size == 0) { + goto END_next_rxdata_get; + } + + + scfcmdp = scf_comtbl.scf_cmdp; + rxbuff_offset = scfcmdp->rbufleng - scf_comtbl.scf_rem_rxbuff_size; + if (scf_comtbl.scf_rem_rxbuff_size > scf_rxbuff_max_size) { + rxbuff_cnt = scf_rxbuff_max_size; + } else { + rxbuff_cnt = scf_comtbl.scf_rem_rxbuff_size; + } + scf_comtbl.scf_rem_rxbuff_size -= rxbuff_cnt; + + /* Receive data copy */ + wk_in_p = (uint8_t *)&statep->scf_sys_sram->DATA[rxbuff_offset]; + wk_out_p = (uint8_t *)&scfcmdp->rbuf[rxbuff_offset]; + for (ii = 0; ii < rxbuff_cnt; ii++, wk_in_p++, wk_out_p++) { + *wk_out_p = SCF_DDI_GET8(statep, statep->scf_sys_sram_handle, + wk_in_p); + } + + /* Check remainder receive data size */ + if (scf_comtbl.scf_rem_rxbuff_size != 0) { + /* Next receive data timer start */ + scf_timer_start(SCF_TIMERCD_NEXTRECV); + goto END_next_rxdata_get; + } + + /* Remainder receive data end */ + scf_comtbl.scf_cmd_exec_flag = 0; + + /* Make SRAM data sum */ + sum4 = SCF_MAGICNUMBER_L; + wk_leng = scfcmdp->rbufleng / 4; + wk_in_p32 = (void *)scfcmdp->rbuf; + for (ii = 0; ii < wk_leng; ii++, wk_in_p32++) { + sum4 += *wk_in_p32; + } + if ((scfcmdp->rbufleng % 4) == 3) { + sum4 += ((scfcmdp->rbuf[scfcmdp->rbufleng - 3] << 24) | + (scfcmdp->rbuf[scfcmdp->rbufleng - 2] << 16) | + (scfcmdp->rbuf[scfcmdp->rbufleng - 1] << 8)); + } else if ((scfcmdp->rbufleng % 4) == 2) { + sum4 += ((scfcmdp->rbuf[scfcmdp->rbufleng - 2] << 24) | + (scfcmdp->rbuf[scfcmdp->rbufleng - 1] << 16)); + } else if ((scfcmdp->rbufleng % 4) == 1) { + sum4 += (scfcmdp->rbuf[scfcmdp->rbufleng - 1] << 24); + } + + SCF_DBG_MAKE_RXSUM_L(sum4, statep->reg_rdata[2]); + + /* Check SRAM data sum */ + if (sum4 == statep->reg_rdata[2]) { + statep->resum_rcnt = 0; + + scf_comtbl.cmd_end_wait = 0; + /* Signal to command end wait */ + cv_signal(&scf_comtbl.cmdend_cv); + SC_DBG_DRV_TRACE(TC_SIGNAL, __LINE__, &scf_comtbl.cmdend_cv, + sizeof (kcondvar_t)); + + /* Next command send check */ + scf_next_cmd_check(statep); + } else { + SC_DBG_DRV_TRACE(TC_ERR, __LINE__, "next_rx ", 8); + scfcmdp->stat0 = SCF_STAT0_RDATA_SUM; + statep->resum_rcnt++; + + /* Check Rx sum re-try out */ + if (statep->resum_rcnt > scf_resum_rcnt) { + /* SRAM trace */ + SCF_SRAM_TRACE(statep, DTC_RSUMERR); + + SC_DBG_DRV_TRACE(TC_ERR, __LINE__, "next_rx ", 8); + cmn_err(CE_WARN, + "%s,Failed the receive data SUM of " + "SRAM. SCF command =0x%02x%02x\n", + &statep->pathname[0], + scfcmdp->subcmd, scfcmdp->cmd); + statep->scf_herr |= HERR_RESUM; + scf_path_change(statep); + } else { + /* Set command wait status */ + scf_cmdwait_status_set(); + + scf_comtbl.scf_cmd_exec_flag = 0; + + /* Next command send check */ + scf_next_cmd_check(statep); + } + } + +/* + * END_next_rxdata_get + */ + END_next_rxdata_get: + + SCFDBGMSG(SCF_DBGFLAG_SYS, SCF_FUNC_NAME ": end"); +} + + +/* + * scf_online_wait_tout() + * + * Description: SCF online monitor timeout processing. + * + */ +void +scf_online_wait_tout(void) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_online_wait_tout() " + scf_state_t *statep = NULL; + scf_state_t *wkstatep = NULL; + scf_state_t *wait_top_statep = NULL; + int online_flag = 0; + int ii; + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_SYS, SCF_FUNC_NAME ": start"); + + /* Get SCF path status */ + statep = scf_comtbl.scf_exec_p; + if (statep == NULL) { + statep = scf_comtbl.scf_path_p; + } + /* Check SCF path status */ + if (statep == NULL) { + goto END_online_wait_tout; + } + + SC_DBG_DRV_TRACE(TC_ERR, __LINE__, "onlin_to", 8); + /* Get SCF status extended register */ + statep->reg_status_exr = SCF_DDI_GET32(statep, + statep->scf_regs_handle, &statep->scf_regs->STATUS_ExR); + SC_DBG_DRV_TRACE(TC_R_STATUS_ExR, __LINE__, + &statep->reg_status_exr, sizeof (statep->reg_status_exr)); + + /* Check SCF status */ + if ((statep->reg_status_exr & STATUS_SCF_STATUS) == STATUS_SCF_ONLINE) { + /* + * SCF online + */ + SCFDBGMSG(SCF_DBGFLAG_SYS, "SCF path online"); + if (scf_comtbl.scf_status == SCF_STATUS_OFFLINE) { + cmn_err(CE_NOTE, "%s: SCF online.\n", scf_driver_name); + } + scf_comtbl.scf_status = SCF_STATUS_ONLINE; + + /* SRAM trace */ + SCF_SRAM_TRACE(statep, DTC_ONLINE); + + /* DCSP interface start */ + scf_dscp_start(FACTOR_ONLINE); + + /* Check Alive check exec */ + if (scf_comtbl.alive_running == SCF_ALIVE_START) { + scf_comtbl.scf_alive_event_sub = EVENT_SUB_ALST_WAIT; + } + + /* Check command send exec */ + if (scf_comtbl.scf_cmd_exec_flag) { + /* Set command wait status */ + scf_cmdwait_status_set(); + scf_comtbl.scf_cmd_exec_flag = 0; + } + + /* Next command send check */ + scf_next_cmd_check(statep); + + /* Check next command send */ + if (scf_comtbl.cmd_busy_wait != 0) { + scf_comtbl.cmd_busy_wait = 0; + /* Signal to command wait */ + cv_signal(&scf_comtbl.cmdwait_cv); + SC_DBG_DRV_TRACE(TC_SIGNAL, __LINE__, + &scf_comtbl.cmdwait_cv, sizeof (kcondvar_t)); + } + } else { + /* + * SCF offline + */ + + /* Check standby path */ + if ((wkstatep = scf_comtbl.scf_wait_p) != NULL) { + wait_top_statep = wkstatep; + for (ii = 0; ii < scf_path_change_max; ii++) { + /* Get SCF status extended register */ + wkstatep->reg_status_exr = + SCF_DDI_GET32(wkstatep, + wkstatep->scf_regs_handle, + &wkstatep->scf_regs->STATUS_ExR); + SC_DBG_DRV_TRACE(TC_R_STATUS_ExR, __LINE__, + &wkstatep->reg_status_exr, + sizeof (wkstatep->reg_status_exr)); + + /* Check SCF status */ + if ((wkstatep->reg_status_exr & + STATUS_SCF_STATUS) == + STATUS_SCF_ONLINE) { + /* SCF path change process */ + online_flag = 1; + scf_path_change(wkstatep); + break; + } + + /* SCF path change */ + scf_comtbl.scf_wait_p = wkstatep->next; + scf_chg_scf(wkstatep, PATH_STAT_STANDBY); + + /* Check standby path */ + wkstatep = scf_comtbl.scf_wait_p; + if (wkstatep == NULL) { + /* Not change path */ + break; + } + if (wkstatep != wait_top_statep) { + /* Next SCF path */ + continue; + } else { + /* Not change path */ + break; + } + } + } + + if (online_flag != 0) { + goto END_online_wait_tout; + } + + scf_comtbl.scf_status = SCF_STATUS_OFFLINE; + + statep->online_to_rcnt++; + + /* Check re-try out */ + if (statep->online_to_rcnt <= scf_online_wait_rcnt) { + /* SCF online timer start */ + scf_timer_start(SCF_TIMERCD_ONLINE); + goto END_online_wait_tout; + } + + SC_DBG_DRV_TRACE(TC_ERR, __LINE__, "onlin_to", 8); + + /* SRAM trace */ + SCF_SRAM_TRACE(statep, DTC_ONLINETO); + + scf_comtbl.scf_cmd_exec_flag = 0; + + /* Timer stop */ + scf_timer_stop(SCF_TIMERCD_CMDBUSY); + scf_timer_stop(SCF_TIMERCD_CMDEND); + scf_timer_stop(SCF_TIMERCD_ONLINE); + scf_timer_stop(SCF_TIMERCD_NEXTRECV); + scf_timer_stop(SCF_TIMERCD_BUF_FUL); + scf_timer_stop(SCF_TIMERCD_RCI_BUSY); + + if (scf_comtbl.suspend_wait) { + /* Signal to suspend wait */ + scf_comtbl.suspend_wait = 0; + scf_comtbl.scf_suspend_sendstop = 1; + cv_signal(&scf_comtbl.suspend_wait_cv); + SC_DBG_DRV_TRACE(TC_SIGNAL, __LINE__, + &scf_comtbl.suspend_wait_cv, + sizeof (kcondvar_t)); + } + if (scf_comtbl.cmd_end_wait != 0) { + /* Signal to command end wait */ + scf_comtbl.cmd_end_wait = 0; + scf_comtbl.scf_cmdp->stat0 = SCF_STAT0_NOT_PATH; + cv_signal(&scf_comtbl.cmdend_cv); + SC_DBG_DRV_TRACE(TC_SIGNAL, __LINE__, + &scf_comtbl.cmdend_cv, + sizeof (kcondvar_t)); + } + if (scf_comtbl.cmd_busy_wait != 0) { + /* Signal to command wait */ + scf_comtbl.cmd_busy_wait = 0; + cv_signal(&scf_comtbl.cmdwait_cv); + SC_DBG_DRV_TRACE(TC_SIGNAL, __LINE__, + &scf_comtbl.cmdwait_cv, + sizeof (kcondvar_t)); + } + + /* DCSP interface stop */ + scf_dscp_stop(FACTOR_PATH_STOP); + } + +/* + * END_online_wait_tout + */ + END_online_wait_tout: + + SCFDBGMSG(SCF_DBGFLAG_SYS, SCF_FUNC_NAME ": end"); +} + + +/* + * scf_cmdbusy_tout() + * + * Description: SCF command busy monitor timeout processing. + * + */ +void +scf_cmdbusy_tout(void) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_cmdbusy_tout() " + scf_state_t *statep; + int path_ret; + uint8_t wk_int8; + uint16_t wk_int16; + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_SYS, SCF_FUNC_NAME ": start"); + + /* Get SCF path status */ + path_ret = scf_path_check(&statep); + /* Check SCF path status */ + if ((path_ret != SCF_PATH_ONLINE) && (path_ret != SCF_PATH_CHANGE)) { + goto END_cmdbusy_tout; + } + + SC_DBG_DRV_TRACE(TC_ERR, __LINE__, "cmdbusy ", 8); + + /* SRAM trace */ + SCF_SRAM_TRACE(statep, DTC_CMDBUSYTO); + + /* Get SCF command register */ + wk_int16 = SCF_DDI_GET16(statep, statep->scf_regs_handle, + &statep->scf_regs->COMMAND); + SC_DBG_DRV_TRACE(TC_R_COMMAND, __LINE__, &wk_int16, sizeof (wk_int16)); + wk_int8 = SCF_DDI_GET8(statep, statep->scf_regs_handle, + &statep->scf_regs->COMMAND_ExR); + SC_DBG_DRV_TRACE(TC_R_COMMAND_ExR, __LINE__, &wk_int8, + sizeof (wk_int8)); + + /* Check busy flag */ + if (((wk_int16 & COMMAND_BUSY) == 0x0000) && + ((wk_int8 & COMMAND_ExR_BUSY) == 0x00)) { + SCFDBGMSG(SCF_DBGFLAG_SYS, "SCF command ready"); + /* Next command send check */ + scf_next_cmd_check(statep); + } else { + statep->devbusy_to_rcnt++; + + /* Check re-try out */ + if (statep->devbusy_to_rcnt <= scf_devbusy_wait_rcnt) { + /* SCF online timer start */ + scf_timer_start(SCF_TIMERCD_CMDBUSY); + goto END_cmdbusy_tout; + } + + if ((wk_int16 & COMMAND_BUSY) != 0x0000) { + SC_DBG_DRV_TRACE(TC_ERR, __LINE__, "cmdbusy ", 8); + cmn_err(CE_WARN, + "%s,Busy state of SCF command is " + "not released.\n", &statep->pathname[0]); + } else { + SC_DBG_DRV_TRACE(TC_ERR, __LINE__, "cmdbusy ", 8); + cmn_err(CE_WARN, + "%s,Busy state of XSCF is not released.\n", + &statep->pathname[0]); + } + statep->scf_herr |= HERR_BUSY_RTO; + scf_path_change(statep); + } + +/* + * END_cmdbusy_tout + */ + END_cmdbusy_tout: + + SCFDBGMSG(SCF_DBGFLAG_SYS, SCF_FUNC_NAME ": end"); +} + +/* + * scf_cmdend_tout() + * + * Description: SCF command complete monitor timeout processing. + * + */ +void +scf_cmdend_tout(void) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_cmdend_tout() " + scf_state_t *statep; + int path_ret; + struct scf_cmd *scfcmdp; + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_SYS, SCF_FUNC_NAME ": start"); + + /* Get SCF path status */ + path_ret = scf_path_check(&statep); + /* Check SCF path status */ + if ((path_ret != SCF_PATH_ONLINE) && (path_ret != SCF_PATH_CHANGE)) { + goto END_cmdend_tout; + } + + SC_DBG_DRV_TRACE(TC_ERR, __LINE__, "cmd_to ", 8); + + /* SRAM trace */ + SCF_SRAM_TRACE(statep, DTC_CMDTO); + + /* error memo */ + scf_comtbl.memo_cmd_to_cnt++; + statep->memo_cmd_to_cnt++; + + if (scf_comtbl.scf_exec_cmd_id) { + /* Comand send for ioctl */ + scfcmdp = scf_comtbl.scf_cmdp; + } else { + /* Comand send for interrupt */ + scfcmdp = &scf_comtbl.scf_cmd_intr; + } + + statep->cmd_to_rcnt++; + + /* Check re-try out */ + if (statep->cmd_to_rcnt <= scf_cmd_to_rcnt) { + /* Set command wait status */ + scf_cmdwait_status_set(); + + scf_comtbl.scf_cmd_exec_flag = 0; + + /* Next command send check */ + scf_next_cmd_check(statep); + } else { + SC_DBG_DRV_TRACE(TC_ERR, __LINE__, "cmd_to ", 8); + cmn_err(CE_WARN, + "%s,SCF command timeout occurred. " + "SCF command = 0x%02x%02x\n", + &statep->pathname[0], + scfcmdp->subcmd, scfcmdp->cmd); + statep->scf_herr |= HERR_CMD_RTO; + scf_path_change(statep); + } + +/* + * END_cmdend_tout + */ + END_cmdend_tout: + + SCFDBGMSG(SCF_DBGFLAG_SYS, SCF_FUNC_NAME ": end"); +} + + +/* + * scf_report_send_wait_tout() + * + * Description: Report command send wait timeout processing. + * + */ +void +scf_report_send_wait_tout(void) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_report_send_wait_tout() " + scf_state_t *statep; + int next_send = 0; + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_SYS, SCF_FUNC_NAME ": start"); + + /* Get SCF path status */ + (void) scf_path_check(&statep); + /* Check SCF path status */ + if (statep != NULL) { + /* Last send report send */ + if (scf_comtbl.scf_last_report == SCF_SYSTEM_RUNNING) { + scf_comtbl.scf_report_event_sub = + EVENT_SUB_REPORT_RUN_WAIT; + next_send = 1; + } else if (scf_comtbl.scf_last_report == + EVENT_SUB_REPORT_SHOT_EXEC) { + scf_comtbl.scf_report_event_sub = + EVENT_SUB_REPORT_SHUT_WAIT; + next_send = 1; + } + if (next_send) { + /* Next command send check */ + scf_next_cmd_check(statep); + } + } + + SCFDBGMSG(SCF_DBGFLAG_SYS, SCF_FUNC_NAME ": end"); +} + + +/* + * scf_alivecheck_intr() + * + * Description: Alive check timeout interrupt processing. + * + */ +void +scf_alivecheck_intr(scf_state_t *statep) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_alivecheck_intr() " + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_SYS, SCF_FUNC_NAME ": start"); + + /* Check alive check exec */ + if (scf_comtbl.alive_running == SCF_ALIVE_START) { + scf_comtbl.scf_alive_int_count--; + + if (scf_comtbl.scf_alive_int_count == 0) { + /* Alive check register set */ + statep->reg_acr = scf_acr_phase_code | ACR_ALIVE_INT; + SCF_DDI_PUT8(statep, statep->scf_regs_handle, + &statep->scf_regs->ACR, statep->reg_acr); + SC_DBG_DRV_TRACE(TC_W_ACR, __LINE__, &statep->reg_acr, + sizeof (statep->reg_acr)); + /* Register read sync */ + scf_rs8 = SCF_DDI_GET8(statep, statep->scf_regs_handle, + &statep->scf_regs->ACR); + + SCFDBGMSG1(SCF_DBGFLAG_REG, "ACR = 0x%02x", + statep->reg_acr); + + scf_acr_phase_code++; + scf_comtbl.scf_alive_int_count = + scf_alive_interval_time / 3; + } + } + + SCFDBGMSG(SCF_DBGFLAG_SYS, SCF_FUNC_NAME ": end"); +} + + +/* + * scf_path_change() + * + * Description: SCF pass change processing. + * + */ +void +scf_path_change(scf_state_t *statep) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_path_change() " + scf_state_t *wkstatep; + scf_state_t *act_statep = NULL; + uint_t path_change = 0; + uint_t halt_flag = 0; + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_SYS, SCF_FUNC_NAME ": start"); + + if (statep->scf_herr != 0) { + act_statep = statep; + + statep->scf_herr |= HERR_EXEC; + + /* Interrupt disable */ + scf_forbid_intr(statep); + + /* Change statep */ + if (scf_comtbl.scf_path_p == statep) { + scf_comtbl.scf_path_p = NULL; + path_change = FACTOR_PATH_HALT; + } else if (scf_comtbl.scf_exec_p == statep) { + scf_comtbl.scf_exec_p = NULL; + path_change = FACTOR_PATH_HALT; + } else { + if ((statep->path_status == PATH_STAT_STANDBY) || + (statep->path_status == PATH_STAT_STOP)) { + scf_del_queue(statep); + } + } + if ((statep->path_status == PATH_STAT_ACTIVE) || + (statep->path_status == PATH_STAT_STANDBY) || + (statep->path_status == PATH_STAT_STOP)) { + scf_chg_scf(statep, PATH_STAT_FAIL); + } + } else { + /* SCF path change interrupt or SCF online wait timeout */ + if (scf_comtbl.scf_exec_p != NULL) { + act_statep = scf_comtbl.scf_exec_p; + } else if (scf_comtbl.scf_path_p != NULL) { + act_statep = scf_comtbl.scf_path_p; + } + if ((act_statep != NULL) && (scf_comtbl.scf_wait_p != NULL)) { + /* Interrupt disable */ + scf_forbid_intr(act_statep); + /* Interrupt enable */ + scf_permit_intr(act_statep, 1); + + scf_comtbl.scf_exec_p = NULL; + scf_comtbl.scf_path_p = NULL; + path_change = FACTOR_PATH_STOP; + + scf_chg_scf(act_statep, PATH_STAT_STANDBY); + } + } + + if (path_change) { + /* FMEMA interface */ + scf_avail_cmd_reg_vaddr = NULL; + + /* Check standby path */ + if ((wkstatep = scf_comtbl.scf_wait_p) != NULL) { + if (path_change == FACTOR_PATH_HALT) { + /* Check SCF path change retry */ + if (scf_comtbl.path_change_rcnt < + scf_path_change_max) { + scf_comtbl.path_change_rcnt++; + } else { + /* SCF path change retry over */ + halt_flag = FACTOR_PATH_HALT; + } + } + } else { + /* Not change path */ + halt_flag = FACTOR_PATH_HALT; + } + + if (halt_flag == 0) { + if (wkstatep != act_statep) { + cmn_err(CE_CONT, + "%s: SCFC path changed. (%s --> %s)\n", + scf_driver_name, + &act_statep->pathname[0], + &wkstatep->pathname[0]); + } + + /* Timer stop */ + scf_timer_stop(SCF_TIMERCD_CMDBUSY); + scf_timer_stop(SCF_TIMERCD_CMDEND); + scf_timer_stop(SCF_TIMERCD_ONLINE); + scf_timer_stop(SCF_TIMERCD_NEXTRECV); + + /* Set command wait status */ + scf_cmdwait_status_set(); + + scf_comtbl.scf_alive_event_sub = EVENT_SUB_NONE; + scf_comtbl.scf_cmd_exec_flag = 0; + /* Send path change */ + scf_comtbl.scf_wait_p = wkstatep->next; + scf_comtbl.scf_pchg_event_sub = EVENT_SUB_PCHG_WAIT; + scf_next_cmd_check(wkstatep); + + /* DCSP interface stop */ + scf_dscp_stop(FACTOR_PATH_CHG); + } + } + + if (halt_flag) { + SC_DBG_DRV_TRACE(TC_ERR, __LINE__, "path_chg", 8); + + scf_comtbl.path_change_rcnt = 0; + + scf_comtbl.scf_cmd_exec_flag = 0; + + /* Timer stop */ + scf_timer_stop(SCF_TIMERCD_CMDBUSY); + scf_timer_stop(SCF_TIMERCD_CMDEND); + scf_timer_stop(SCF_TIMERCD_ONLINE); + scf_timer_stop(SCF_TIMERCD_NEXTRECV); + scf_timer_stop(SCF_TIMERCD_BUF_FUL); + scf_timer_stop(SCF_TIMERCD_RCI_BUSY); + + if (scf_comtbl.suspend_wait) { + /* Signal to suspend wait */ + scf_comtbl.suspend_wait = 0; + scf_comtbl.scf_suspend_sendstop = 1; + cv_signal(&scf_comtbl.suspend_wait_cv); + SC_DBG_DRV_TRACE(TC_SIGNAL, __LINE__, + &scf_comtbl.suspend_wait_cv, + sizeof (kcondvar_t)); + } + if (scf_comtbl.cmd_end_wait != 0) { + /* Signal to command end wait */ + scf_comtbl.cmd_end_wait = 0; + scf_comtbl.scf_cmdp->stat0 = SCF_STAT0_NOT_PATH; + cv_signal(&scf_comtbl.cmdend_cv); + SC_DBG_DRV_TRACE(TC_SIGNAL, __LINE__, + &scf_comtbl.cmdend_cv, sizeof (kcondvar_t)); + } + if (scf_comtbl.cmd_busy_wait != 0) { + /* Signal to command wait */ + scf_comtbl.cmd_busy_wait = 0; + cv_signal(&scf_comtbl.cmdwait_cv); + SC_DBG_DRV_TRACE(TC_SIGNAL, __LINE__, + &scf_comtbl.cmdwait_cv, sizeof (kcondvar_t)); + } + + /* DCSP interface stop */ + scf_dscp_stop(halt_flag); + + if (halt_flag == FACTOR_PATH_HALT) { + /* Not change path(SCF HALT) */ + + /* FMEMA interface */ + scf_avail_cmd_reg_vaddr = NULL; + + cmn_err(CE_WARN, + "%s: SCF HALT was detected.\n", + scf_driver_name); + + /* SCF HALT after processing */ + scf_halt(scf_halt_proc_mode); + } + + } + + SCFDBGMSG(SCF_DBGFLAG_SYS, SCF_FUNC_NAME ": end"); +} + + +/* + * scf_halt() + * + * Description: SCFHALT shutdown/panic processing. + * + */ +void +scf_halt(uint_t mode) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_halt() " + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_SYS, SCF_FUNC_NAME ": start"); + + SC_DBG_DRV_TRACE(TC_ERRCD, __LINE__, &mode, sizeof (mode)); + + switch (mode) { + case HALTPROC_SHUTDOWN: + cmn_err(CE_CONT, + "%s: Shutdown was executed.\n", + scf_driver_name); + /* System shutdown start */ + if (scf_comtbl.scf_shutdownreason == 0) { + scf_comtbl.scf_shutdownreason = REASON_SHUTDOWN_HALT; + do_shutdown(); + } + break; + + case HALTPROC_PANIC: + /* System panic */ + cmn_err(CE_PANIC, + "%s: Executed panic by SCF HALT.\n", + scf_driver_name); + break; + + default: + break; + } + + SCFDBGMSG(SCF_DBGFLAG_SYS, SCF_FUNC_NAME ": end"); +} + + +/* + * scf_panic_callb() + * + * Description: Panic entry processing. + * + */ +/* ARGSUSED */ +void +scf_panic_callb(int code) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_panic_callb() " + scf_state_t *statep; + scf_state_t *save__exec_p; + struct scf_cmd scf_cmd; + scf_short_buffer_t sbuf; + unsigned short status; + int counter; + int report_succeeded = 0; + int path_flag = 0; + int path_counter = 0; + int report_counter = 0; + int ii = 0; + int new_report = 0; + + SCFDBGMSG1(SCF_DBGFLAG_FOCK, SCF_FUNC_NAME ": start code = %d", + code); + SCF_PANIC_TRACE(__LINE__); + + /* Check panic after */ + if (scf_panic_reported) { + SCF_PANIC_TRACE(__LINE__); + return; + } + + /* Check double panic */ + if (scf_panic_exec_flag) { + SCF_PANIC_TRACE(__LINE__); + return; + } + + /* Check shutdown exec */ + if (scf_comtbl.scf_shutdown_exec_flag) { + SCF_PANIC_TRACE(__LINE__); + return; + } + + /* Set panic exec flag */ + scf_panic_exec_flag = 1; + + save__exec_p = scf_comtbl.scf_exec_p; + /* wait */ + drv_usecwait(SCF_MIL2MICRO(scf_panic_exec_wait_time)); + + if ((statep = scf_comtbl.scf_exec_p) != NULL) { + /* Exec SCF path interrupt disable */ + /* SCF interrupt disable(CR) */ + SCF_P_DDI_PUT16(statep->scf_regs_c_handle, + &statep->scf_regs_c->CONTROL, CONTROL_DISABLE); + /* Register read sync */ + status = SCF_P_DDI_GET16(statep->scf_regs_c_handle, + &statep->scf_regs_c->CONTROL); + + /* SCF Status register interrupt(STR) : clear */ + SCF_P_DDI_PUT16(statep->scf_regs_handle, + &statep->scf_regs->STATUS, 0xffff); + + /* SCF Status extended register(STExR) : interrupt clear */ + SCF_P_DDI_PUT32(statep->scf_regs_handle, + &statep->scf_regs->STATUS_ExR, 0xffffffff); + + /* DSCP buffer status register(DSR) : interrupt clear */ + SCF_P_DDI_PUT8(statep->scf_regs_handle, + &statep->scf_regs->DSR, 0xff); + + /* SCF interrupt status register(ISR) : interrupt clear */ + SCF_P_DDI_PUT16(statep->scf_regs_c_handle, + &statep->scf_regs_c->INT_ST, + (INT_ST_PATHCHGIE | CONTROL_ALIVEINE)); + status = SCF_P_DDI_GET16(statep->scf_regs_c_handle, + &statep->scf_regs_c->INT_ST); + } + + if ((statep = scf_comtbl.scf_path_p) != NULL) { + /* Path change SCF path interrupt disable */ + /* SCF interrupt disable(CR) */ + SCF_P_DDI_PUT16(statep->scf_regs_c_handle, + &statep->scf_regs_c->CONTROL, CONTROL_DISABLE); + /* Register read sync */ + status = SCF_P_DDI_GET16(statep->scf_regs_c_handle, + &statep->scf_regs_c->CONTROL); + + /* SCF Status register interrupt(STR) : clear */ + SCF_P_DDI_PUT16(statep->scf_regs_handle, + &statep->scf_regs->STATUS, 0xffff); + + /* SCF Status extended register(STExR) : interrupt clear */ + SCF_P_DDI_PUT32(statep->scf_regs_handle, + &statep->scf_regs->STATUS_ExR, 0xffffffff); + + /* DSCP buffer status register(DSR) : interrupt clear */ + SCF_P_DDI_PUT8(statep->scf_regs_handle, + &statep->scf_regs->DSR, 0xff); + + /* SCF interrupt status register(ISR) : interrupt clear */ + SCF_P_DDI_PUT16(statep->scf_regs_c_handle, + &statep->scf_regs_c->INT_ST, + (INT_ST_PATHCHGIE | CONTROL_ALIVEINE)); + status = SCF_P_DDI_GET16(statep->scf_regs_c_handle, + &statep->scf_regs_c->INT_ST); + } + + statep = scf_comtbl.scf_wait_p; + while (statep != NULL) { /* Standby SCF path interrupt disable */ + /* SCF interrupt disable(CR) */ + SCF_P_DDI_PUT16(statep->scf_regs_c_handle, + &statep->scf_regs_c->CONTROL, CONTROL_DISABLE); + /* Register read sync */ + status = SCF_P_DDI_GET16(statep->scf_regs_c_handle, + &statep->scf_regs_c->CONTROL); + + /* SCF Status register interrupt(STR) : clear */ + SCF_P_DDI_PUT16(statep->scf_regs_handle, + &statep->scf_regs->STATUS, 0xffff); + + /* SCF Status extended register(STExR) : interrupt clear */ + SCF_P_DDI_PUT32(statep->scf_regs_handle, + &statep->scf_regs->STATUS_ExR, 0xffffffff); + + /* DSCP buffer status register(DSR) : interrupt clear */ + SCF_P_DDI_PUT8(statep->scf_regs_handle, + &statep->scf_regs->DSR, 0xff); + + /* SCF interrupt status register(ISR) : interrupt clear */ + SCF_P_DDI_PUT16(statep->scf_regs_c_handle, + &statep->scf_regs_c->INT_ST, + (INT_ST_PATHCHGIE | CONTROL_ALIVEINE)); + status = SCF_P_DDI_GET16(statep->scf_regs_c_handle, + &statep->scf_regs_c->INT_ST); + + statep = statep->next; + } + + status = 0; + + /* Check comand exec */ + if (scf_comtbl.scf_cmd_exec_flag == 0) { + statep = scf_comtbl.scf_exec_p; + if (statep == NULL) { + statep = scf_comtbl.scf_path_p; + if (statep == NULL) { + statep = scf_comtbl.scf_wait_p; + if (statep == NULL) { + /* Not use SCF path */ + SCF_PANIC_TRACE(__LINE__); + goto END_scf_panic_callb; + } + path_flag = 1; + } + } + goto START_scf_panic; + } + + statep = scf_comtbl.scf_exec_p; + if (statep == NULL) { + statep = scf_comtbl.scf_path_p; + if (statep == NULL) { + statep = scf_comtbl.scf_wait_p; + if (statep == NULL) { + SCF_PANIC_TRACE(__LINE__); + goto END_scf_panic_callb; + } + /* wait */ + drv_usecwait(SCF_MIL2MICRO((scf_cmdend_wait_time_panic * + scf_cmdend_wait_rcnt_panic))); + path_flag = 1; + } + } + if (path_flag == 0) { + for (ii = 0; ii < scf_cmdend_wait_rcnt_panic; ii++) { + /* wait */ + drv_usecwait + (SCF_MIL2MICRO(scf_cmdend_wait_time_panic)); + + /* Get SCF status register */ + status = SCF_P_DDI_GET16(statep->scf_regs_handle, + &statep->scf_regs->STATUS); + scf_panic_trc_status = status; + + if (status & STATUS_CMD_COMPLETE) { + /* Command complete */ + break; + } + } + SCF_P_DDI_PUT16(statep->scf_regs_handle, + &statep->scf_regs->STATUS, 0xffff); + } + +/* + * START_scf_panic + */ + START_scf_panic: + + counter = scf_panic_report_maxretry; + do { +/* + * START_scf_panic_loop + */ + START_scf_panic_loop: + + /* Check SCF path change */ + if (path_flag == 0) { + goto START_report_send; + } + + scf_cmd.cmd = CMD_SCFI_PATH; + scf_cmd.subcmd = SUB_CMD_PATH; + bzero((void *)&sbuf.b[0], SCF_S_CNT_16); + sbuf.b[0] = REPORT_STAT_PANIC; + scf_cmd.scount = CMD_PATH_TYPE_SCFD; + scf_cmd.sbuf = &sbuf.b[0]; + scf_cmd.rcount = 0; + scf_cmd.flag = SCF_USE_S_BUF; + scf_p_send_cmd(&scf_cmd, statep); + + /* Check command complete */ + for (ii = 0; ii < scf_cmdend_wait_rcnt_panic; ii++) { + /* wait */ + drv_usecwait(SCF_MIL2MICRO(scf_cmdend_wait_time_panic)); + + /* Get SCF status register */ + status = SCF_P_DDI_GET16(statep->scf_regs_handle, + &statep->scf_regs->STATUS); + scf_panic_trc_status = status; + + if (status & STATUS_CMD_COMPLETE) { + /* Command complete */ + break; + } + } + SCF_P_DDI_PUT16(statep->scf_regs_handle, + &statep->scf_regs->STATUS, 0xffff); + + if (ii == scf_cmdend_wait_rcnt_panic) { + /* Not command complete */ + if (path_counter < 1) { + path_counter++; + goto START_scf_panic_loop; + } + SCF_PANIC_TRACE(__LINE__); + goto END_scf_panic_callb; + } + switch ((status & STATUS_CMD_RTN_CODE) >> 4) { + case NORMAL_END: + counter = scf_panic_report_maxretry; + path_flag = 0; + report_counter = 0; + break; + default: + if (path_counter < 1) { + path_flag = 1; + path_counter++; + goto START_scf_panic_loop; + } + SCF_PANIC_TRACE(__LINE__); + goto END_scf_panic_callb; + } + +/* + * START_report_send + */ + START_report_send: + + if (new_report) { + /* new report panic */ + scf_cmd.cmd = CMD_REPORT; + scf_cmd.subcmd = SUB_SYSTEM_STATUS_RPT_NOPATH; + } else { + /* report panic */ + scf_cmd.cmd = CMD_REPORT; + scf_cmd.subcmd = SUB_SYSTEM_STATUS_RPT; + } + bzero((void *)&sbuf.b[0], SCF_S_CNT_16); + sbuf.b[0] = REPORT_STAT_PANIC; + scf_cmd.scount = SCF_S_CNT_15; + scf_cmd.sbuf = &sbuf.b[0]; + scf_cmd.rcount = 0; + scf_cmd.flag = SCF_USE_S_BUF; + scf_p_send_cmd(&scf_cmd, statep); + scf_panic_exec_flag2 = 1; + + /* Check command complete */ + for (ii = 0; ii < scf_cmdend_wait_rcnt_panic; ii++) { + /* wait */ + drv_usecwait(SCF_MIL2MICRO(scf_cmdend_wait_time_panic)); + + /* Get SCF status register */ + status = SCF_P_DDI_GET16(statep->scf_regs_handle, + &statep->scf_regs->STATUS); + scf_panic_trc_status = status; + + if (status & STATUS_CMD_COMPLETE) { + /* Command complete */ + break; + } + } + SCF_P_DDI_PUT16(statep->scf_regs_handle, + &statep->scf_regs->STATUS, 0xffff); + + if (ii == scf_cmdend_wait_rcnt_panic) { + /* Not command complete */ + if (report_counter < 1) { + report_counter++; + goto START_scf_panic_loop; + } + SCF_PANIC_TRACE(__LINE__); + goto END_scf_panic_callb; + } + + switch ((status & STATUS_CMD_RTN_CODE) >> 4) { + case NORMAL_END: + /* command success */ + report_succeeded = 1; + SCF_PANIC_TRACE(__LINE__); + goto END_scf_panic_callb; + + case BUF_FUL: + counter--; + if (counter > 0) { + drv_usecwait(SCF_MIL2MICRO(scf_buf_ful_rtime)); + } + break; + + case RCI_BUSY: + counter--; + if (counter > 0) { + drv_usecwait(SCF_MIL2MICRO(scf_rci_busy_rtime)); + } + break; + + case INTERFACE: + counter--; + break; + + case E_SCFC_NOPATH: + if (new_report == 0) { + path_flag = 1; + path_counter = 0; + goto START_scf_panic_loop; + } + + default: + /* E_NOT_SUPPORT */ + /* E_PARAM */ + /* E_RCI_ACCESS */ + /* RCI_NS */ + goto END_scf_panic_callb; + } + + } while (counter > 0); + +/* + * END_scf_panic_callb + */ + END_scf_panic_callb: + + scf_comtbl.scf_exec_p = save__exec_p; + if (report_succeeded) { + SCF_PANIC_TRACE(__LINE__); + scf_panic_reported = 1; + } else { + SCF_PANIC_TRACE(__LINE__); + cmn_err(CE_WARN, "%s: cannot report PANIC.\n", scf_driver_name); + } + + SCFDBGMSG(SCF_DBGFLAG_FOCK, SCF_FUNC_NAME ": end"); +} + + +/* + * scf_shutdown_callb() + * + * Description: Shutdown entry processing. + * + */ +/* ARGSUSED */ +void +scf_shutdown_callb(int code) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_shutdown_callb() " + scf_state_t *statep; + int ret; + struct scf_cmd scf_cmd; + scf_short_buffer_t sbuf; + + SCFDBGMSG1(SCF_DBGFLAG_FOCK, SCF_FUNC_NAME ": start code = %d", + code); + + mutex_enter(&scf_comtbl.all_mutex); + + /* Check panic exec or shutdown exec */ + if ((scf_panic_exec_flag) || (scf_comtbl.scf_shutdown_exec_flag)) { + SCFDBGMSG(SCF_DBGFLAG_SYS, "After Panic or shutdown"); + goto END_scf_shutdown_callb99; + } + + scf_comtbl.scf_shutdown_exec_flag = 1; + + /* SCF command transmit sync stop */ + ret = scf_make_send_cmd(&scf_cmd, SCF_USE_STOP); + if (ret != 0) { + SC_DBG_DRV_TRACE(TC_SHUTDOWN|TC_ERR, __LINE__, "i_ioctl ", 8); + goto END_scf_shutdown_callb; + } + + scf_comtbl.shutdown_start_reported = 1; + + bzero((void *)&sbuf.b[0], SCF_S_CNT_16); + sbuf.b[0] = REPORT_STAT_SHUTDOWN_START; + sbuf.b[1] = scf_poff_factor[scf_comtbl.poff_factor][0]; + sbuf.b[2] = scf_poff_factor[scf_comtbl.poff_factor][1]; + sbuf.b[3] = scf_poff_factor[scf_comtbl.poff_factor][2]; + scf_cmd.cmd = CMD_REPORT; + scf_cmd.subcmd = SUB_SYSTEM_STATUS_RPT_NOPATH; + scf_cmd.scount = SCF_S_CNT_15; + scf_cmd.sbuf = &sbuf.b[0]; + scf_cmd.rcount = 0; + scf_cmd.flag = (SCF_USE_S_BUF | SCF_USE_SP); + scf_comtbl.scf_last_report = SCF_SHUTDOWN_START; + + ret = scf_send_cmd_check_bufful(&scf_cmd); + if (ret != 0) { + SC_DBG_DRV_TRACE(TC_SHUTDOWN|TC_ERR, __LINE__, "shutdown", 8); + goto END_scf_shutdown_callb; + } + /* SCF command send sync re-stop */ + ret = scf_make_send_cmd(&scf_cmd, SCF_USE_STOP); + if (ret != 0) { + SC_DBG_DRV_TRACE(TC_SHUTDOWN|TC_ERR, __LINE__, "shutdown", 8); + goto END_scf_shutdown_callb; + } + + /* Check alive check exec */ + if (scf_comtbl.alive_running == SCF_ALIVE_START) { + scf_cmd.cmd = CMD_ALIVE_CHECK; + scf_cmd.subcmd = SUB_ALIVE_STOP; + scf_cmd.scount = 0; + scf_cmd.rcount = 0; + scf_cmd.flag = (SCF_USE_S_BUF | SCF_USE_SP); + ret = scf_send_cmd_check_bufful(&scf_cmd); + scf_comtbl.alive_running = SCF_ALIVE_STOP; + if (ret != 0) { + SC_DBG_DRV_TRACE(TC_SHUTDOWN|TC_ERR, __LINE__, + "shutdown", 8); + goto END_scf_shutdown_callb; + } + /* SCF command send sync re-stop */ + ret = scf_make_send_cmd(&scf_cmd, SCF_USE_STOP); + } + +/* + * END_scf_shutdown_callb + */ +END_scf_shutdown_callb: + + if ((statep = scf_comtbl.scf_exec_p) == NULL) { + statep = scf_comtbl.scf_path_p; + } + scf_comtbl.scf_exec_p = 0; + scf_comtbl.scf_path_p = 0; + if (statep) { + /* Exec device interrupt disable */ + scf_forbid_intr(statep); + scf_chg_scf(statep, PATH_STAT_STOP); + } + + while (scf_comtbl.scf_wait_p) { + /* Standby device interrupt disable */ + statep = scf_comtbl.scf_wait_p; + scf_comtbl.scf_wait_p = statep->next; + scf_forbid_intr(statep); + scf_chg_scf(statep, PATH_STAT_STOP); + } + + /* SCF command send sync start */ + (void) scf_make_send_cmd(&scf_cmd, SCF_USE_START); + + /* DCSP interface stop */ + scf_dscp_stop(FACTOR_PATH_STOP); + +/* + * END_scf_shutdown_callb99 + */ +END_scf_shutdown_callb99: + + mutex_exit(&scf_comtbl.all_mutex); + + SCFDBGMSG(SCF_DBGFLAG_FOCK, SCF_FUNC_NAME ": end"); +} + + +/* + * scf_softintr() + * + * Description: Soft interrupt entry processing. (for DSCP callback) + * + */ +/* ARGSUSED */ +uint_t +scf_softintr(caddr_t arg) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_softintr() " + uint_t ret = DDI_INTR_CLAIMED; + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": start"); + + mutex_enter(&scf_comtbl.si_mutex); + if (scf_comtbl.scf_softintr_dscp_kicked == FLAG_ON) { + /* Lock driver mutex */ + mutex_enter(&scf_comtbl.all_mutex); + + /* Check panic exec and shutdown exec */ + if ((scf_panic_exec_flag == 0) && + (scf_comtbl.scf_shutdown_exec_flag == 0)) { + scf_dscp_callback(); + } + + /* Unlock driver mutex */ + mutex_exit(&scf_comtbl.all_mutex); + + scf_comtbl.scf_softintr_dscp_kicked = FLAG_OFF; + } + mutex_exit(&scf_comtbl.si_mutex); + + SCFDBGMSG(SCF_DBGFLAG_DSCP, SCF_FUNC_NAME ": end"); + return (ret); +} + + +/* + * scf_cmdwait_status_set() + * + * Description: Check and setting command status. + * + */ +void +scf_cmdwait_status_set(void) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_cmdwait_status_set() " + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_SYS, SCF_FUNC_NAME ": start"); + + /* Set command wait status */ + if (scf_comtbl.scf_pchg_event_sub == EVENT_SUB_PCHG_EXEC) { + scf_comtbl.scf_pchg_event_sub = EVENT_SUB_PCHG_WAIT; + + /* Set command retry send flag */ + scf_comtbl.scf_cmd_resend_req |= RESEND_PCHG; + } + + if (scf_comtbl.scf_poff_event_sub == EVENT_SUB_POFF_EXEC) { + scf_comtbl.scf_poff_event_sub = EVENT_SUB_POFF_WAIT; + + /* Set command retry send flag */ + scf_comtbl.scf_cmd_resend_req |= RESEND_POFF; + } + + switch (scf_comtbl.scf_shut_event_sub) { + case EVENT_SUB_SHUT_EXEC: + scf_comtbl.scf_shut_event_sub = EVENT_SUB_SHUT_WAIT; + + /* Set command retry send flag */ + scf_comtbl.scf_cmd_resend_req |= RESEND_SHUT; + break; + + case EVENT_SUB_EXEC: + scf_comtbl.scf_shut_event_sub = EVENT_SUB_WAIT; + + /* Set command retry send flag */ + scf_comtbl.scf_cmd_resend_req |= RESEND_SHUT; + break; + + default: + break; + } + + switch (scf_comtbl.scf_alive_event_sub) { + case EVENT_SUB_ALST_EXEC: + scf_comtbl.scf_alive_event_sub = EVENT_SUB_ALST_WAIT; + + /* Set command retry send flag */ + scf_comtbl.scf_cmd_resend_req |= RESEND_ALST; + break; + + case EVENT_SUB_ALSP_EXEC: + scf_comtbl.scf_alive_event_sub = EVENT_SUB_ALSP_WAIT; + + /* Set command retry send flag */ + scf_comtbl.scf_cmd_resend_req |= RESEND_ALSP; + break; + + default: + break; + } + + switch (scf_comtbl.scf_report_event_sub) { + case EVENT_SUB_REPORT_RUN_EXEC: + scf_comtbl.scf_report_event_sub = EVENT_SUB_REPORT_RUN_WAIT; + + /* Set command retry send flag */ + scf_comtbl.scf_cmd_resend_req |= RESEND_REPORT_RUN; + break; + + case EVENT_SUB_REPORT_SHOT_EXEC: + scf_comtbl.scf_report_event_sub = EVENT_SUB_REPORT_SHUT_WAIT; + + /* Set command retry send flag */ + scf_comtbl.scf_cmd_resend_req |= RESEND_REPORT_SHUT; + break; + + default: + break; + } + + if (scf_comtbl.scf_cmd_exec_flag) { + if (scf_comtbl.cmd_end_wait) { + /* Set command retry send flag */ + scf_comtbl.scf_cmd_resend_req |= RESEND_IOCTL; + } + } + + SCFDBGMSG(SCF_DBGFLAG_SYS, SCF_FUNC_NAME ": end"); +} diff --git a/usr/src/uts/sun4u/opl/io/scfd/scfinit.c b/usr/src/uts/sun4u/opl/io/scfd/scfinit.c new file mode 100644 index 0000000000..8b45427e2e --- /dev/null +++ b/usr/src/uts/sun4u/opl/io/scfd/scfinit.c @@ -0,0 +1,301 @@ +/* + * 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 + */ +/* + * All Rights Reserved, Copyright (c) FUJITSU LIMITED 2006 + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/conf.h> +#include <sys/kmem.h> +#include <sys/devops.h> +#include <sys/modctl.h> +#include <sys/cmn_err.h> +#include <sys/ddi.h> +#include <sys/sunddi.h> + +#include <sys/scfd/scfparam.h> + + +/* + * character/block entry point structure + */ +static struct cb_ops scf_cb_ops = { + scf_open, /* open */ + scf_close, /* close */ + nodev, /* strategy */ + nodev, /* print */ + nodev, /* dump */ + nodev, /* read */ + nodev, /* write */ + scf_ioctl, /* ioctl */ + nodev, /* devmap */ + nodev, /* mmap */ + nodev, /* segmap */ + nochpoll, /* poll */ + ddi_prop_op, /* prop_op */ + (struct streamtab *)NULL, /* streamtab */ + D_NEW | D_MP /* flag */ +}; + +/* + * device operations structure + */ +static struct dev_ops scf_dev_ops = { + DEVO_REV, /* dev_ops revision */ + 0, /* reference */ + scf_getinfo, /* getinfo */ + nulldev, /* identify */ + nulldev, /* probe */ + scf_attach, /* attach */ + scf_detach, /* detach */ + nodev, /* reset */ + &scf_cb_ops, /* cb_ops */ + (struct bus_ops *)NULL, /* bus_ops */ + NULL /* power entry */ +}; + +/* + * linkage structure for loadable driver + */ +extern struct mod_ops mod_driverops; +static struct modldrv scf_modldrv = { + &mod_driverops, /* mod_driverops */ + SCF_DRIVER_VERSION, /* version number */ + &scf_dev_ops /* dev_ops */ +}; + +/* + * module linkage structure + */ +static struct modlinkage scf_modlinkage = { + MODREV_1, /* modlinkage revision */ + (void *)&scf_modldrv, /* linkage */ + (void *)NULL /* (end of linkage) */ +}; + +/* + * Function list + */ +void scf_free_resource(void); + +/* + * _init() + * + * Description: Install and initialization processing of module. + * + */ +int +_init(void) +{ +#define SCF_FUNC_NAME "_init() " + int error; + + SCFDBGMSG(SCF_DBGFLAG_DDI, SCF_FUNC_NAME ": start"); + + /* initialize software state */ + error = ddi_soft_state_init(&scfstate, sizeof (scf_state_t), 0); + if (error != 0) { + cmn_err(CE_WARN, "%s: _init: ddi_soft_state_init failed.\n", + scf_driver_name); + goto END_init; + } + + SCF_DBG_DRV_TRACE_INIT; + + /* Last report code initialize */ + scf_comtbl.scf_last_report = NOT_SEND_REPORT; + + /* XSCF status initialize */ + scf_comtbl.scf_status = SCF_STATUS_UNKNOWN; + + /* allocate memory */ + scf_comtbl.report_sensep = + (scfreport_t *)kmem_zalloc((size_t)(sizeof (scfreport_t) * + scf_report_sense_pool_max), KM_SLEEP); + scf_comtbl.getevent_sensep = + (scfevent_t *)kmem_zalloc((size_t)(sizeof (scfevent_t) * + scf_getevent_pool_max), KM_SLEEP); + scf_comtbl.resource_flag |= DID_ALLOCBUF; + + /* initialize mutex */ + mutex_init(&scf_comtbl.attach_mutex, NULL, MUTEX_DRIVER, 0); + scf_comtbl.resource_flag |= DID_MUTEX_ATH; + mutex_init(&scf_comtbl.si_mutex, NULL, MUTEX_DRIVER, 0); + scf_comtbl.resource_flag |= DID_MUTEX_SI; + mutex_init(&scf_comtbl.trc_mutex, NULL, MUTEX_DRIVER, 0); + scf_comtbl.resource_flag |= DID_MUTEX_TRC; + + /* initialize cv */ + cv_init(&scf_comtbl.cmd_cv, NULL, CV_DRIVER, NULL); + cv_init(&scf_comtbl.cmdend_cv, NULL, CV_DRIVER, NULL); + cv_init(&scf_comtbl.cmdwait_cv, NULL, CV_DRIVER, NULL); + cv_init(&scf_comtbl.cmdbusy_cv, NULL, CV_DRIVER, NULL); + cv_init(&scf_comtbl.rsense_cv, NULL, CV_DRIVER, NULL); + cv_init(&scf_comtbl.rdcsense_cv, NULL, CV_DRIVER, NULL); + cv_init(&scf_comtbl.rdctrl_cv, NULL, CV_DRIVER, NULL); + cv_init(&scf_comtbl.getevent_cv, NULL, CV_DRIVER, NULL); + cv_init(&scf_comtbl.suspend_wait_cv, NULL, CV_DRIVER, NULL); + scf_comtbl.resource_flag |= DID_CV; + + /* install module into system */ + error = mod_install(&scf_modlinkage); + if (error != 0) { + cmn_err(CE_WARN, "%s: _init: mod_install failed.\n", + scf_driver_name); + /* release driver resources */ + scf_free_resource(); + } + +/* + * END_init + */ + END_init: + + SCFDBGMSG1(SCF_DBGFLAG_DDI, SCF_FUNC_NAME ": end return = %d", error); + return (error); +} + + +/* + * _fini() + * + * Description: Remove processing of module. + * + */ +int +_fini(void) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "_fini() " + int error; + + SCFDBGMSG(SCF_DBGFLAG_DDI, SCF_FUNC_NAME ": start"); + + /* remove module from system */ + error = mod_remove(&scf_modlinkage); + if (error == 0) { + /* release driver resources */ + scf_free_resource(); + } + + SCFDBGMSG1(SCF_DBGFLAG_DDI, SCF_FUNC_NAME ": end return = %d", error); + return (error); +} + + +/* + * _info() + * + * Description: Return module information. + * + */ +int +_info(struct modinfo *modinfop) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "_info() " + int error; + + SCFDBGMSG(SCF_DBGFLAG_DDI, SCF_FUNC_NAME ": start"); + + /* return module infomarion */ + error = mod_info(&scf_modlinkage, modinfop); + + SCFDBGMSG1(SCF_DBGFLAG_DDI, SCF_FUNC_NAME ": end return = %d", error); + return (error); +} + + +/* + * scf_free_resource() + * + * Description: Release processing of driver resources. + * + */ +/* ARGSUSED */ +void +scf_free_resource(void) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_free_resource() " + + SCFDBGMSG(SCF_DBGFLAG_DDI, SCF_FUNC_NAME ": start"); + + SCF_DBG_IOMP_FREE; + + /* System interface area release */ + if (scf_comtbl.report_sensep != NULL) { + kmem_free((void *)scf_comtbl.report_sensep, + (size_t)(sizeof (scfreport_t) * + scf_report_sense_pool_max)); + scf_comtbl.report_sensep = NULL; + } + if (scf_comtbl.getevent_sensep != NULL) { + kmem_free((void *)scf_comtbl.getevent_sensep, + (size_t)(sizeof (scfevent_t) * scf_getevent_pool_max)); + scf_comtbl.getevent_sensep = NULL; + } + scf_comtbl.resource_flag &= (~DID_ALLOCBUF); + + /* destroy cv */ + if (scf_comtbl.resource_flag & DID_CV) { + cv_destroy(&scf_comtbl.cmd_cv); + cv_destroy(&scf_comtbl.cmdend_cv); + cv_destroy(&scf_comtbl.cmdwait_cv); + cv_destroy(&scf_comtbl.cmdbusy_cv); + cv_destroy(&scf_comtbl.rsense_cv); + cv_destroy(&scf_comtbl.rdcsense_cv); + cv_destroy(&scf_comtbl.rdctrl_cv); + cv_destroy(&scf_comtbl.getevent_cv); + cv_destroy(&scf_comtbl.suspend_wait_cv); + scf_comtbl.resource_flag &= (~DID_CV); + } + + /* remove softint */ + if (scf_comtbl.resource_flag & DID_SOFTINTR) { + ddi_remove_softintr(scf_comtbl.scf_softintr_id); + scf_comtbl.resource_flag &= (~DID_SOFTINTR); + } + + /* destroy mutex */ + if (scf_comtbl.resource_flag & DID_MUTEX_TRC) { + mutex_destroy(&scf_comtbl.trc_mutex); + scf_comtbl.resource_flag &= (~DID_MUTEX_TRC); + } + if (scf_comtbl.resource_flag & DID_MUTEX_ALL) { + mutex_destroy(&scf_comtbl.all_mutex); + scf_comtbl.resource_flag &= (~DID_MUTEX_ALL); + } + if (scf_comtbl.resource_flag & DID_MUTEX_SI) { + mutex_destroy(&scf_comtbl.si_mutex); + scf_comtbl.resource_flag &= (~DID_MUTEX_SI); + } + if (scf_comtbl.resource_flag & DID_MUTEX_ATH) { + mutex_destroy(&scf_comtbl.attach_mutex); + scf_comtbl.resource_flag &= (~DID_MUTEX_ATH); + } + + /* release software state */ + ddi_soft_state_fini(&scfstate); + + SCFDBGMSG(SCF_DBGFLAG_DDI, SCF_FUNC_NAME ": end"); +} diff --git a/usr/src/uts/sun4u/opl/io/scfd/scfiomp.c b/usr/src/uts/sun4u/opl/io/scfd/scfiomp.c new file mode 100644 index 0000000000..d427fcb399 --- /dev/null +++ b/usr/src/uts/sun4u/opl/io/scfd/scfiomp.c @@ -0,0 +1,2286 @@ +/* + * 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 + */ +/* + * All Rights Reserved, Copyright (c) FUJITSU LIMITED 2006 + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <sys/file.h> +#include <sys/errno.h> +#include <sys/open.h> +#include <sys/uio.h> +#include <sys/cred.h> +#include <sys/kmem.h> +#include <sys/ddi.h> +#include <sys/sunddi.h> + +#include <sys/scfd/scfparam.h> + +#ifdef DEBUG +/* + * Function list + */ +void scf_add_scf(scf_state_t *statep); +void scf_del_scf(scf_state_t *statep); +int scf_meta_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, + cred_t *cred_p, int *rval_p, int u_mode); +int scf_inst_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, + cred_t *cred_p, int *rval_p, int u_mode); +void scf_inst_getstat32(scf_state_t *statep, + struct fiompstatus_32 *status32_p, char *message_p, int flag); +void scf_inst_getstat(scf_state_t *statep, + struct fiompstatus *status_p, char *message_p, int flag); +void scf_path_stmsg(scf_state_t *statep, char *message_p); + +/* + * External function + */ +extern void scf_dscp_stop(uint32_t factor); + + +/* + * Multi path control table add + */ +void +scf_add_scf(scf_state_t *statep) +{ +#define SCF_FUNC_NAME "scf_add_scf() " + scf_state_t **iomp_scf; + int alloc_size; + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG1(SCF_DBGFLAG_SYS, SCF_FUNC_NAME ": start instance = %d", + statep->instance); + + alloc_size = (sizeof (scf_state_t *) * (statep->instance + 1)); + if (alloc_size < (sizeof (scf_state_t *) * SCF_MAX_INSTANCE)) { + alloc_size = (sizeof (scf_state_t *) * SCF_MAX_INSTANCE); + } + if ((scf_comtbl.alloc_size < alloc_size) || + (scf_comtbl.iomp_scf == 0)) { + /* IOMP control table re-get */ + iomp_scf = (scf_state_t **)kmem_zalloc((size_t)(alloc_size), + KM_SLEEP); + if (scf_comtbl.alloc_size != 0) { + bcopy(scf_comtbl.iomp_scf, iomp_scf, + scf_comtbl.alloc_size); + kmem_free((void *)scf_comtbl.iomp_scf, + (size_t)scf_comtbl.alloc_size); + } + scf_comtbl.iomp_scf = iomp_scf; + scf_comtbl.alloc_size = alloc_size; + } + scf_comtbl.iomp_scf[statep->instance] = statep; + /* SCF path count up */ + if (scf_comtbl.path_num < (statep->instance + 1)) { + scf_comtbl.path_num = statep->instance + 1; + } + + SCFDBGMSG(SCF_DBGFLAG_SYS, SCF_FUNC_NAME ": end"); +} + +/* + * Multi path control table delete + */ +void +scf_del_scf(scf_state_t *statep) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_del_scf() " + int ii; + int path_num = 0; + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG1(SCF_DBGFLAG_SYS, SCF_FUNC_NAME ": start instance = %d", + statep->instance); + + scf_comtbl.iomp_scf[statep->instance] = 0; + + /* SCF path count up */ + for (ii = 0; ii < scf_comtbl.alloc_size / sizeof (scf_state_t *); + ii++) { + if (scf_comtbl.iomp_scf[ii]) { + path_num = scf_comtbl.iomp_scf[ii]->instance + 1; + } + } + scf_comtbl.path_num = path_num; + + SCFDBGMSG(SCF_DBGFLAG_SYS, SCF_FUNC_NAME ": end"); +} + + +/* + * Meta management ioctl + */ +/* ARGSUSED */ +int +scf_meta_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cred_p, + int *rval_p, int u_mode) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_meta_ioctl() " + int ret = 0; + int all_num; + int path_num; + + SCFDBGMSG1(SCF_DBGFLAG_IOMP, + SCF_FUNC_NAME ": start cmd = 0x%08x", (uint_t)cmd); + + switch ((unsigned int)cmd) { + case FIOMPNEW: + SCFDBGMSG(SCF_DBGFLAG_IOMP, "FIOMPNEW proc"); + + ret = ENOTTY; + break; + + case FIOMPENCAP: + SCFDBGMSG(SCF_DBGFLAG_IOMP, "FIOMPENCAP proc"); + + ret = ENOTTY; + break; + + case FIOMPDEVINFO: + SCFDBGMSG(SCF_DBGFLAG_IOMP, "FIOMPDEVINFO proc"); + + if (u_mode == DDI_MODEL_ILP32) { + /* DDI_MODEL_ILP32 */ + struct fiomp_devinfo_32 *fiomp_devinfo32_p; + + fiomp_devinfo32_p = + (struct fiomp_devinfo_32 *)kmem_zalloc + ((size_t)(sizeof (struct fiomp_devinfo_32)), + KM_SLEEP); + + if (ddi_copyin((void *)arg, + (void *)fiomp_devinfo32_p, + sizeof (struct fiomp_devinfo_32), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "m_ioctl ", 8); + ret = EFAULT; + goto END_DEVINFO32; + } + if (fiomp_devinfo32_p->inst_no != 0) { + /* Invalid inst_no */ + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "m_ioctl ", 8); + ret = EINVAL; + goto END_DEVINFO32; + } + mutex_enter(&scf_comtbl.attach_mutex); + if (!(scf_comtbl.resource_flag & DID_MUTEX_ALL)) { + /* Not attach device */ + path_num = 0; + } else { + /* Is attach device */ + mutex_enter(&scf_comtbl.all_mutex); + + path_num = scf_comtbl.path_num; + + mutex_exit(&scf_comtbl.all_mutex); + } + mutex_exit(&scf_comtbl.attach_mutex); + /* Set output information */ + strcpy(fiomp_devinfo32_p->real_name, SCF_REAL_NAME); + strcpy(fiomp_devinfo32_p->user_path, SCF_USER_PATH); + fiomp_devinfo32_p->path_num = path_num; + fiomp_devinfo32_p->mpmode = FIOMP_FALSE; + fiomp_devinfo32_p->autopath = FIOMP_TRUE; + fiomp_devinfo32_p->block = FIOMP_TRUE; + fiomp_devinfo32_p->needsync = FIOMP_FALSE; + if (ddi_copyout((void *)fiomp_devinfo32_p, + (void *)arg, sizeof (struct fiomp_devinfo_32), + mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "m_ioctl ", 8); + ret = EFAULT; + } + +/* + * END_DEVINFO32 + */ + END_DEVINFO32: + + if (fiomp_devinfo32_p) { + kmem_free((void *)fiomp_devinfo32_p, + (size_t)(sizeof (struct fiomp_devinfo_32))); + } + } else { + /* DDI_MODEL_NONE */ + struct fiomp_devinfo *fiomp_devinfo_p; + + fiomp_devinfo_p = + (struct fiomp_devinfo *)kmem_zalloc + ((size_t)(sizeof (struct fiomp_devinfo)), + KM_SLEEP); + + if (ddi_copyin((void *)arg, (void *)fiomp_devinfo_p, + sizeof (struct fiomp_devinfo), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "m_ioctl ", 8); + ret = EFAULT; + goto END_DEVINFO; + } + if (fiomp_devinfo_p->inst_no != 0) { + /* Invalid inst_no */ + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "m_ioctl ", 8); + ret = EINVAL; + goto END_DEVINFO; + } + mutex_enter(&scf_comtbl.attach_mutex); + if (!(scf_comtbl.resource_flag & DID_MUTEX_ALL)) { + /* Not attach device */ + path_num = 0; + } else { + /* Is attach device */ + mutex_enter(&scf_comtbl.all_mutex); + + path_num = scf_comtbl.path_num; + + mutex_exit(&scf_comtbl.all_mutex); + } + mutex_exit(&scf_comtbl.attach_mutex); + /* Set output information */ + strcpy(fiomp_devinfo_p->real_name, + SCF_REAL_NAME); + strcpy(fiomp_devinfo_p->user_path, + SCF_USER_PATH); + fiomp_devinfo_p->path_num = path_num; + fiomp_devinfo_p->mpmode = FIOMP_FALSE; + fiomp_devinfo_p->autopath = FIOMP_TRUE; + fiomp_devinfo_p->block = FIOMP_TRUE; + fiomp_devinfo_p->needsync = FIOMP_FALSE; + if (ddi_copyout((void *)fiomp_devinfo_p, + (void *)arg, sizeof (struct fiomp_devinfo), + mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "m_ioctl ", 8); + ret = EFAULT; + } + +/* + * END_DEVINFO + */ + END_DEVINFO: + + if (fiomp_devinfo_p) { + kmem_free((void *)fiomp_devinfo_p, + (size_t)(sizeof (struct fiomp_devinfo))); + } + } + break; + + case FIOMPALLINSTNUM: + SCFDBGMSG(SCF_DBGFLAG_IOMP, "FIOMPALLINSTNUM proc"); + + mutex_enter(&scf_comtbl.attach_mutex); + /* Set output information */ + if (!(scf_comtbl.resource_flag & DID_MUTEX_ALL)) { + /* Not attach device */ + all_num = 0; + } else { + /* Is attach device */ + all_num = 1; + } + mutex_exit(&scf_comtbl.attach_mutex); + if (ddi_copyout((void *)&all_num, (void *)arg, + sizeof (int), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "m_ioctl ", 8); + ret = EFAULT; + } + break; + + case FIOMPALLDEVINFO: + SCFDBGMSG(SCF_DBGFLAG_IOMP, "FIOMPALLDEVINFO proc"); + + if (u_mode == DDI_MODEL_ILP32) { + /* DDI_MODEL_ILP32 */ + struct fiomp_all_devinfo_32 fiomp_all_devinfo32; + struct fiomp_devinfo_32 *fiomp_devinfo32_p; + + fiomp_devinfo32_p = + (struct fiomp_devinfo_32 *)kmem_zalloc + ((size_t)(sizeof (struct fiomp_devinfo_32)), + KM_SLEEP); + + if (ddi_copyin((void *)arg, (void *)&fiomp_all_devinfo32, + sizeof (struct fiomp_all_devinfo_32), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "m_ioctl ", 8); + ret = EFAULT; + goto END_ALLDEVINFO32; + } + if (fiomp_all_devinfo32.num != 1) { + /* Set 1 in num */ + fiomp_all_devinfo32.num = 1; + } else { + if (ddi_copyin((void *)(uintptr_t)fiomp_all_devinfo32.devinfo, + (void *)fiomp_devinfo32_p, + sizeof (struct fiomp_devinfo_32), + mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "m_ioctl ", 8); + ret = EFAULT; + goto END_ALLDEVINFO32; + } + mutex_enter(&scf_comtbl.attach_mutex); + if (!(scf_comtbl.resource_flag & DID_MUTEX_ALL)) { + /* Not attach device */ + path_num = 0; + } else { + /* Is attach device */ + mutex_enter(&scf_comtbl.all_mutex); + + path_num = scf_comtbl.path_num; + + mutex_exit(&scf_comtbl.all_mutex); + } + mutex_exit(&scf_comtbl.attach_mutex); + /* Set output information */ + fiomp_devinfo32_p->inst_no = 0; + strcpy(fiomp_devinfo32_p->real_name, SCF_REAL_NAME); + strcpy(fiomp_devinfo32_p->user_path, SCF_USER_PATH); + fiomp_devinfo32_p->path_num = path_num; + fiomp_devinfo32_p->mpmode = FIOMP_FALSE; + fiomp_devinfo32_p->autopath = FIOMP_TRUE; + fiomp_devinfo32_p->block = FIOMP_TRUE; + fiomp_devinfo32_p->needsync = FIOMP_FALSE; + if (ddi_copyout((void *)fiomp_devinfo32_p, + (void *)(uintptr_t)fiomp_all_devinfo32.devinfo, + sizeof (struct fiomp_devinfo_32), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "m_ioctl ", 8); + ret = EFAULT; + goto END_ALLDEVINFO32; + } + } + if (ddi_copyout((void *)&fiomp_all_devinfo32, (void *)arg, + sizeof (struct fiomp_all_devinfo_32), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "m_ioctl ", 8); + ret = EFAULT; + } + +/* + * END_ALLDEVINFO32 + */ + END_ALLDEVINFO32: + + if (fiomp_devinfo32_p) { + kmem_free((void *)fiomp_devinfo32_p, + (size_t)(sizeof (struct fiomp_devinfo_32))); + } + } else { + /* DDI_MODEL_NONE */ + struct fiomp_all_devinfo fiomp_all_devinfo; + struct fiomp_devinfo *fiomp_devinfo_p; + + fiomp_devinfo_p = + (struct fiomp_devinfo *)kmem_zalloc + ((size_t)(sizeof (struct fiomp_devinfo)), + KM_SLEEP); + + if (ddi_copyin((void *)arg, (void *)&fiomp_all_devinfo, + sizeof (struct fiomp_all_devinfo), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "m_ioctl ", 8); + ret = EFAULT; + goto END_ALLDEVINFO; + } + if (fiomp_all_devinfo.num != 1) { + /* Set 1 in num */ + fiomp_all_devinfo.num = 1; + } else { + if (ddi_copyin((void *)fiomp_all_devinfo.devinfo, + (void *)fiomp_devinfo_p, + sizeof (struct fiomp_devinfo), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "m_ioctl ", 8); + ret = EFAULT; + goto END_ALLDEVINFO; + } + mutex_enter(&scf_comtbl.attach_mutex); + if (!(scf_comtbl.resource_flag & DID_MUTEX_ALL)) { + /* Not attach device */ + path_num = 0; + } else { + /* Is attach device */ + mutex_enter(&scf_comtbl.all_mutex); + + path_num = scf_comtbl.path_num; + + mutex_exit(&scf_comtbl.all_mutex); + } + mutex_exit(&scf_comtbl.attach_mutex); + /* Set output information */ + fiomp_devinfo_p->inst_no = 0; + strcpy(fiomp_devinfo_p->real_name, SCF_REAL_NAME); + strcpy(fiomp_devinfo_p->user_path, SCF_USER_PATH); + fiomp_devinfo_p->path_num = path_num; + fiomp_devinfo_p->mpmode = FIOMP_FALSE; + fiomp_devinfo_p->autopath = FIOMP_TRUE; + fiomp_devinfo_p->block = FIOMP_TRUE; + fiomp_devinfo_p->needsync = FIOMP_FALSE; + if (ddi_copyout((void *)fiomp_devinfo_p, + (void *)fiomp_all_devinfo.devinfo, + sizeof (struct fiomp_devinfo), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "m_ioctl ", 8); + ret = EFAULT; + goto END_ALLDEVINFO; + } + } + if (ddi_copyout((void *)&fiomp_all_devinfo, (void *)arg, + sizeof (struct fiomp_all_devinfo), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "m_ioctl ", 8); + ret = EFAULT; + } + +/* + * END_ALLDEVINFO + */ + END_ALLDEVINFO: + + if (fiomp_devinfo_p) { + kmem_free((void *)fiomp_devinfo_p, + (size_t)(sizeof (struct fiomp_devinfo))); + } + } + break; + + case FIOMPGETEVENT: + SCFDBGMSG(SCF_DBGFLAG_IOMP, "FIOMPGETEVENT proc"); + + ret = ENOTTY; + break; + + default: + /* undefined */ + SCFDBGMSG(SCF_DBGFLAG_IOMP, "undefined ioctl command"); + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "m_ioctl ", 8); + ret = ENOTTY; + } + +/* + * END_meta_ioctl + */ + END_meta_ioctl: + + SCFDBGMSG1(SCF_DBGFLAG_IOMP, SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + +/* + * Instans management ioctl + */ +/* ARGSUSED */ +int +scf_inst_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cred_p, + int *rval_p, int u_mode) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_inst_ioctl() " + scf_state_t *statep; + scf_state_t *wkstatep; + struct scf_cmd scf_cmd; + int ret = 0; + int all_num; + int pathnum; + int ii; + int jj; + int num_cmp_flag = 0; + int alloc_num; + + SCFDBGMSG1(SCF_DBGFLAG_IOMP, + SCF_FUNC_NAME ": start cmd = 0x%08x", (uint_t)cmd); + + mutex_enter(&scf_comtbl.attach_mutex); + if (!(scf_comtbl.resource_flag & DID_MUTEX_ALL)) { + /* Not attach device */ + mutex_exit(&scf_comtbl.attach_mutex); + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "i_ioctl ", 8); + ret = ENXIO; + goto END_inst_ioctl; + } + mutex_exit(&scf_comtbl.attach_mutex); + + switch ((unsigned int)cmd) { + case FIOMPMAXPATHNUM: + SCFDBGMSG(SCF_DBGFLAG_IOMP, "FIOMPMAXPATHNUM proc"); + + mutex_enter(&scf_comtbl.all_mutex); + /* Set output information */ + all_num = scf_comtbl.path_num; + mutex_exit(&scf_comtbl.all_mutex); + if (ddi_copyout((void *)&all_num, (void *)arg, + sizeof (int), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "i_ioctl ", 8); + ret = EFAULT; + } + break; + + case FIOMPSETPROP: + SCFDBGMSG(SCF_DBGFLAG_IOMP, "FIOMPSETPROP proc"); + + ret = ENOTTY; + break; + + case FIOMPGETPROP: + SCFDBGMSG(SCF_DBGFLAG_IOMP, "FIOMPGETPROP proc"); + + if (u_mode == DDI_MODEL_ILP32) { + /* DDI_MODEL_ILP32 */ + struct fiompprop_32 fiompprop32; + char *work_name_p = 0; + char *iomp_name_p = 0; + char *iomp_real_name_p = 0; + char *iomp_user_path_p = 0; + char *iomp_status_p = 0; + caddr32_t *iomp_path_p = 0; + caddr32_t *iomp_logical_path_p = 0; + caddr32_t *iomp_path_status_p = 0; + caddr32_t *iomp_path_block_p = 0; + char *iomp_path = 0; + char *iomp_logical_path = 0; + char *iomp_path_status = 0; + char *iomp_path_block = 0; + + if (ddi_copyin((void *)arg, (void *)&fiompprop32, + sizeof (struct fiompprop_32), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "i_ioctl ", 8); + ret = EFAULT; + goto END_inst_ioctl; + } + alloc_num = fiompprop32.num; + iomp_name_p = (char *)kmem_zalloc((size_t)(FIOMP_MAX_STR), + KM_SLEEP); + iomp_real_name_p = (char *)kmem_zalloc((size_t)(FIOMP_MAX_STR), + KM_SLEEP); + iomp_user_path_p = (char *)kmem_zalloc((size_t)(FIOMP_MAX_STR), + KM_SLEEP); + iomp_status_p = (char *)kmem_zalloc((size_t)(FIOMP_MAX_STR), + KM_SLEEP); + if (fiompprop32.num != 0) { + /* buffer allocation */ + work_name_p = (char *)kmem_zalloc + ((size_t)(FIOMP_MAX_STR), KM_SLEEP); + iomp_path_p = (caddr32_t *)kmem_zalloc + ((size_t)((sizeof (caddr32_t)) * alloc_num), KM_SLEEP); + iomp_logical_path_p = (caddr32_t *)kmem_zalloc + ((size_t)((sizeof (caddr32_t)) * alloc_num), KM_SLEEP); + iomp_path_status_p = (caddr32_t *)kmem_zalloc + ((size_t)((sizeof (caddr32_t)) * alloc_num), KM_SLEEP); + iomp_path_block_p = (caddr32_t *)kmem_zalloc + ((size_t)((sizeof (caddr32_t)) * alloc_num), KM_SLEEP); + iomp_path = (char *)kmem_zalloc + ((size_t)(FIOMP_MAX_STR * alloc_num), KM_SLEEP); + iomp_logical_path = (char *)kmem_zalloc + ((size_t)(FIOMP_MAX_STR * alloc_num), KM_SLEEP); + iomp_path_status = (char *)kmem_zalloc + ((size_t)(FIOMP_MAX_STR * alloc_num), KM_SLEEP); + iomp_path_block = (char *)kmem_zalloc + ((size_t)(FIOMP_MAX_STR * alloc_num), KM_SLEEP); + } + + mutex_enter(&scf_comtbl.all_mutex); + if (fiompprop32.num != scf_comtbl.path_num) { + /* + * When different from appointed num, perform only num setting + */ + fiompprop32.num = scf_comtbl.path_num; + num_cmp_flag = 1; + } else { + /* Set output information */ + strcpy(iomp_name_p, SCF_IOMP_NAME); + strcpy(iomp_real_name_p, SCF_REAL_NAME); + strcpy(iomp_user_path_p, SCF_USER_PATH); + if ((scf_comtbl.scf_path_p) || (scf_comtbl.scf_exec_p)) { + strcpy(iomp_status_p, "online"); + } else if ((scf_comtbl.scf_stop_p) || + (scf_comtbl.scf_err_p)) { + strcpy(iomp_status_p, "offline"); + } else { + strcpy(iomp_status_p, "unconfigured"); + } + for (ii = 0, jj = 0; ii < fiompprop32.num; + ii++, jj += FIOMP_MAX_STR) { + /* Output information setting every pass */ + iomp_path[jj] = '\0'; + iomp_logical_path[jj] = '\0'; + iomp_path_status[jj] = '\0'; + iomp_path_block[jj] = '\0'; + if ((statep = scf_comtbl.iomp_scf[ii]) != 0) { + if (ddi_pathname(statep->dip, + work_name_p)) { + sprintf(&iomp_path[jj], "%s:scfc%d", + work_name_p, statep->instance); + } + sprintf(&iomp_logical_path[jj], + "/dev/FJSVhwr/scfc%d", + statep->instance); + switch (statep->path_status) { + case FIOMP_STAT_ACTIVE: + strcpy(&iomp_path_status[jj], + "active"); + break; + case FIOMP_STAT_STANDBY: + strcpy(&iomp_path_status[jj], + "standby"); + break; + case FIOMP_STAT_STOP: + strcpy(&iomp_path_status[jj], + "stop"); + break; + case FIOMP_STAT_FAIL: + strcpy(&iomp_path_status[jj], + "fail"); + break; + case FIOMP_STAT_DISCON: + strcpy(&iomp_path_status[jj], + "disconnected"); + break; + default: + strcpy(&iomp_path_status[jj], + "empty"); + } + strcpy(&iomp_path_block[jj], "block"); + } + } + } + mutex_exit(&scf_comtbl.all_mutex); + if (num_cmp_flag == 0) { + if (ddi_copyout((void *)iomp_name_p, + (void *)(uintptr_t)fiompprop32.iomp_name, + FIOMP_MAX_STR, mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "i_ioctl ", 8); + ret = EFAULT; + goto END_GETPROP32; + } + if (ddi_copyout((void *)iomp_real_name_p, + (void *)(uintptr_t)fiompprop32.iomp_real_name, + FIOMP_MAX_STR, mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "i_ioctl ", 8); + ret = EFAULT; + goto END_GETPROP32; + } + if (ddi_copyout((void *)iomp_user_path_p, + (void *)(uintptr_t)fiompprop32.iomp_user_path, + FIOMP_MAX_STR, mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "i_ioctl ", 8); + ret = EFAULT; + goto END_GETPROP32; + } + if (ddi_copyout((void *)iomp_status_p, + (void *)(uintptr_t)fiompprop32.iomp_status, + FIOMP_MAX_STR, mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "i_ioctl ", 8); + ret = EFAULT; + goto END_GETPROP32; + } + if (fiompprop32.num) { + if (fiompprop32.iomp_path) { + if (ddi_copyin((void *)(uintptr_t)fiompprop32.iomp_path, + (void *)iomp_path_p, + ((sizeof (caddr32_t)) * fiompprop32.num), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "i_ioctl ", 8); + ret = EFAULT; + goto END_GETPROP32; + } + } + if (fiompprop32.iomp_logical_path) { + if (ddi_copyin((void *)(uintptr_t)fiompprop32.iomp_logical_path, + (void *)iomp_logical_path_p, + ((sizeof (caddr32_t)) * fiompprop32.num), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "i_ioctl ", 8); + ret = EFAULT; + goto END_GETPROP32; + } + } + if (fiompprop32.iomp_path_status) { + if (ddi_copyin((void *)(uintptr_t)fiompprop32.iomp_path_status, + (void *)iomp_path_status_p, + ((sizeof (caddr32_t)) * fiompprop32.num), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "i_ioctl ", 8); + ret = EFAULT; + goto END_GETPROP32; + } + } + if (fiompprop32.iomp_path_block) { + if (ddi_copyin((void *)(uintptr_t)fiompprop32.iomp_path_block, + (void *)iomp_path_block_p, + ((sizeof (caddr32_t)) * fiompprop32.num), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "i_ioctl ", 8); + ret = EFAULT; + goto END_GETPROP32; + } + } + } + for (ii = 0, jj = 0; ii < fiompprop32.num; + ii++, jj += FIOMP_MAX_STR) { + if (iomp_path_p[ii]) { + if (ddi_copyout((void *)&iomp_path[jj], + (void *)(uintptr_t)iomp_path_p[ii], + FIOMP_MAX_STR, mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "i_ioctl ", 8); + ret = EFAULT; + goto END_GETPROP32; + } + } + if (iomp_logical_path_p[ii]) { + if (ddi_copyout((void *)&iomp_logical_path[jj], + (void *)(uintptr_t)iomp_logical_path_p[ii], + FIOMP_MAX_STR, mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "i_ioctl ", 8); + ret = EFAULT; + goto END_GETPROP32; + } + } + if (iomp_path_status_p[ii]) { + if (ddi_copyout((void *)&iomp_path_status[jj], + (void *)(uintptr_t)iomp_path_status_p[ii], + FIOMP_MAX_STR, mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "i_ioctl ", 8); + ret = EFAULT; + goto END_GETPROP32; + } + } + if (iomp_path_block_p[ii]) { + if (ddi_copyout((void *)&iomp_path_block[jj], + (void *)(uintptr_t)iomp_path_block_p[ii], + FIOMP_MAX_STR, mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "i_ioctl ", 8); + ret = EFAULT; + goto END_GETPROP32; + } + } + } + } + if (ddi_copyout((void *)&fiompprop32, (void *)arg, + sizeof (struct fiompprop_32), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "i_ioctl ", 8); + ret = EFAULT; + } + +/* + * END_GETPROP32 + */ + END_GETPROP32: + + /* Buffer release */ + if (work_name_p) { + kmem_free((void *)work_name_p, (size_t)FIOMP_MAX_STR); + } + if (iomp_name_p) { + kmem_free((void *)iomp_name_p, (size_t)FIOMP_MAX_STR); + } + if (iomp_real_name_p) { + kmem_free((void *)iomp_real_name_p, (size_t)FIOMP_MAX_STR); + } + if (iomp_user_path_p) { + kmem_free((void *)iomp_user_path_p, (size_t)FIOMP_MAX_STR); + } + if (iomp_status_p) { + kmem_free((void *)iomp_status_p, (size_t)FIOMP_MAX_STR); + } + if (iomp_path_p) { + kmem_free((void *)iomp_path_p, + (size_t)((sizeof (caddr32_t)) * alloc_num)); + } + if (iomp_logical_path_p) { + kmem_free((void *)iomp_logical_path_p, + (size_t)((sizeof (caddr32_t)) * alloc_num)); + } + if (iomp_path_status_p) { + kmem_free((void *)iomp_path_status_p, + (size_t)((sizeof (caddr32_t)) * alloc_num)); + } + if (iomp_path_block_p) { + kmem_free((void *)iomp_path_block_p, + (size_t)((sizeof (caddr32_t)) * alloc_num)); + } + if (iomp_path) { + kmem_free((void *)iomp_path, + (size_t)(FIOMP_MAX_STR * alloc_num)); + } + if (iomp_logical_path) { + kmem_free((void *)iomp_logical_path, + (size_t)(FIOMP_MAX_STR * alloc_num)); + } + if (iomp_path_status) { + kmem_free((void *)iomp_path_status, + (size_t)(FIOMP_MAX_STR * alloc_num)); + } + if (iomp_path_block) { + kmem_free((void *)iomp_path_block, + (size_t)(FIOMP_MAX_STR * alloc_num)); + } + } else { + /* DDI_MODEL_NONE */ + struct fiompprop fiompprop; + char *work_name_p = 0; + char *iomp_name_p = 0; + char *iomp_real_name_p = 0; + char *iomp_user_path_p = 0; + char *iomp_status_p = 0; + caddr_t *iomp_path_p = 0; + caddr_t *iomp_logical_path_p = 0; + caddr_t *iomp_path_status_p = 0; + caddr_t *iomp_path_block_p = 0; + char *iomp_path = 0; + char *iomp_logical_path = 0; + char *iomp_path_status = 0; + char *iomp_path_block = 0; + + if (ddi_copyin((void *)arg, (void *)&fiompprop, + sizeof (struct fiompprop), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "i_ioctl ", 8); + ret = EFAULT; + goto END_inst_ioctl; + } + alloc_num = fiompprop.num; + if (fiompprop.num != 0) { + /* Buffer allocation */ + work_name_p = (char *)kmem_zalloc + ((size_t)(FIOMP_MAX_STR), KM_SLEEP); + iomp_name_p = (char *)kmem_zalloc + ((size_t)(FIOMP_MAX_STR), KM_SLEEP); + iomp_real_name_p = (char *)kmem_zalloc + ((size_t)(FIOMP_MAX_STR), KM_SLEEP); + iomp_user_path_p = (char *)kmem_zalloc + ((size_t)(FIOMP_MAX_STR), KM_SLEEP); + iomp_status_p = (char *)kmem_zalloc + ((size_t)(FIOMP_MAX_STR), KM_SLEEP); + iomp_path_p = (caddr_t *)kmem_zalloc + ((size_t)((sizeof (caddr_t)) * alloc_num), KM_SLEEP); + iomp_logical_path_p = (caddr_t *)kmem_zalloc + ((size_t)((sizeof (caddr_t)) * alloc_num), KM_SLEEP); + iomp_path_status_p = (caddr_t *)kmem_zalloc + ((size_t)((sizeof (caddr_t)) * alloc_num), KM_SLEEP); + iomp_path_block_p = (caddr_t *)kmem_zalloc + ((size_t)((sizeof (caddr_t)) * alloc_num), KM_SLEEP); + iomp_path = (char *)kmem_zalloc + ((size_t)(FIOMP_MAX_STR * alloc_num), KM_SLEEP); + iomp_logical_path = (char *)kmem_zalloc + ((size_t)(FIOMP_MAX_STR * alloc_num), KM_SLEEP); + iomp_path_status = (char *)kmem_zalloc + ((size_t)(FIOMP_MAX_STR * alloc_num), KM_SLEEP); + iomp_path_block = (char *)kmem_zalloc + ((size_t)(FIOMP_MAX_STR * alloc_num), KM_SLEEP); + } + + mutex_enter(&scf_comtbl.all_mutex); + if (fiompprop.num != scf_comtbl.path_num) { + /* + * When different from appointed num, perform only num setting + */ + fiompprop.num = scf_comtbl.path_num; + num_cmp_flag = 1; + } else { + /* Set output information */ + strcpy(iomp_name_p, SCF_IOMP_NAME); + strcpy(iomp_real_name_p, SCF_REAL_NAME); + strcpy(iomp_user_path_p, SCF_USER_PATH); + if ((scf_comtbl.scf_path_p) || (scf_comtbl.scf_exec_p)) { + strcpy(iomp_status_p, "online"); + } else if ((scf_comtbl.scf_stop_p) || (scf_comtbl.scf_err_p)) { + strcpy(iomp_status_p, "offline"); + } else { + strcpy(iomp_status_p, "unconfigured"); + } + for (ii = 0, jj = 0; ii < fiompprop.num; + ii++, jj += FIOMP_MAX_STR) { + /* Output information setting every pass */ + iomp_path[jj] = '\0'; + iomp_logical_path[jj] = '\0'; + iomp_path_status[jj] = '\0'; + iomp_path_block[jj] = '\0'; + if ((statep = scf_comtbl.iomp_scf[ii]) != 0) { + if (ddi_pathname(statep->dip, work_name_p)) { + sprintf(&iomp_path[jj], "%s:scfc%d", + work_name_p, statep->instance); + } + sprintf(&iomp_logical_path[jj], + "/dev/FJSVhwr/scfc%d", + statep->instance); + switch (statep->path_status) { + case FIOMP_STAT_ACTIVE: + strcpy(&iomp_path_status[jj], + "active"); + break; + case FIOMP_STAT_STANDBY: + strcpy(&iomp_path_status[jj], + "standby"); + break; + case FIOMP_STAT_STOP: + strcpy(&iomp_path_status[jj], + "stop"); + break; + case FIOMP_STAT_FAIL: + strcpy(&iomp_path_status[jj], + "fail"); + break; + case FIOMP_STAT_DISCON: + strcpy(&iomp_path_status[jj], + "disconnected"); + break; + default: + strcpy(&iomp_path_status[jj], + "empty"); + } + strcpy(&iomp_path_block[jj], "block"); + } + } + } + mutex_exit(&scf_comtbl.all_mutex); + if (num_cmp_flag == 0) { + if (ddi_copyout((void *)iomp_name_p, + (void *)fiompprop.iomp_name, + FIOMP_MAX_STR, mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "i_ioctl ", 8); + ret = EFAULT; + goto END_GETPROP; + } + if (ddi_copyout((void *)iomp_real_name_p, + (void *)fiompprop.iomp_real_name, + FIOMP_MAX_STR, mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "i_ioctl ", 8); + ret = EFAULT; + goto END_GETPROP; + } + if (ddi_copyout((void *)iomp_user_path_p, + (void *)fiompprop.iomp_user_path, + FIOMP_MAX_STR, mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "i_ioctl ", 8); + ret = EFAULT; + goto END_GETPROP; + } + if (ddi_copyout((void *)iomp_status_p, + (void *)fiompprop.iomp_status, + FIOMP_MAX_STR, mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "i_ioctl ", 8); + ret = EFAULT; + goto END_GETPROP; + } + if (fiompprop.num) { + if (fiompprop.iomp_path) { + if (ddi_copyin((void *)fiompprop.iomp_path, + (void *)iomp_path_p, + ((sizeof (caddr_t)) * fiompprop.num), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "i_ioctl ", 8); + ret = EFAULT; + goto END_GETPROP; + } + } + if (fiompprop.iomp_logical_path) { + if (ddi_copyin((void *)fiompprop.iomp_logical_path, + (void *)iomp_logical_path_p, + ((sizeof (caddr_t)) * fiompprop.num), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "i_ioctl ", 8); + ret = EFAULT; + goto END_GETPROP; + } + } + if (fiompprop.iomp_path_status) { + if (ddi_copyin((void *)fiompprop.iomp_path_status, + (void *)iomp_path_status_p, + ((sizeof (caddr_t)) * fiompprop.num), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "i_ioctl ", 8); + ret = EFAULT; + goto END_GETPROP; + } + } + if (fiompprop.iomp_path_block) { + if (ddi_copyin((void *)fiompprop.iomp_path_block, + (void *)iomp_path_block_p, + ((sizeof (caddr_t)) * fiompprop.num), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "i_ioctl ", 8); + ret = EFAULT; + goto END_GETPROP; + } + } + } + for (ii = 0, jj = 0; ii < fiompprop.num; + ii++, jj += FIOMP_MAX_STR) { + if (iomp_path_p[ii]) { + if (ddi_copyout((void *)&iomp_path[jj], + (void *)iomp_path_p[ii], + FIOMP_MAX_STR, mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "i_ioctl ", 8); + ret = EFAULT; + goto END_GETPROP; + } + } + if (iomp_logical_path_p[ii]) { + if (ddi_copyout((void *)&iomp_logical_path[jj], + (void *)iomp_logical_path_p[ii], + FIOMP_MAX_STR, mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "i_ioctl ", 8); + ret = EFAULT; + goto END_GETPROP; + } + } + if (iomp_path_status_p[ii]) { + if (ddi_copyout((void *)&iomp_path_status[jj], + (void *)iomp_path_status_p[ii], + FIOMP_MAX_STR, mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "i_ioctl ", 8); + ret = EFAULT; + goto END_GETPROP; + } + } + if (iomp_path_block_p[ii]) { + if (ddi_copyout((void *)&iomp_path_block[jj], + (void *)iomp_path_block_p[ii], + FIOMP_MAX_STR, mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "i_ioctl ", 8); + ret = EFAULT; + goto END_GETPROP; + } + } + } + } + if (ddi_copyout((void *)&fiompprop, (void *)arg, + sizeof (struct fiompprop), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "i_ioctl ", 8); + ret = EFAULT; + } + +/* + * END_GETPROP + */ + END_GETPROP: + + /* Buffer release */ + if (work_name_p) { + kmem_free((void *)work_name_p, (size_t)FIOMP_MAX_STR); + } + if (iomp_name_p) { + kmem_free((void *)iomp_name_p, (size_t)FIOMP_MAX_STR); + } + if (iomp_real_name_p) { + kmem_free((void *)iomp_real_name_p, (size_t)FIOMP_MAX_STR); + } + if (iomp_user_path_p) { + kmem_free((void *)iomp_user_path_p, (size_t)FIOMP_MAX_STR); + } + if (iomp_status_p) { + kmem_free((void *)iomp_status_p, (size_t)FIOMP_MAX_STR); + } + if (iomp_path_p) { + kmem_free((void *)iomp_path_p, + (size_t)((sizeof (caddr_t)) * alloc_num)); + } + if (iomp_logical_path_p) { + kmem_free((void *)iomp_logical_path_p, + (size_t)((sizeof (caddr_t)) * alloc_num)); + } + if (iomp_path_status_p) { + kmem_free((void *)iomp_path_status_p, + (size_t)((sizeof (caddr_t)) * alloc_num)); + } + if (iomp_path_block_p) { + kmem_free((void *)iomp_path_block_p, + (size_t)((sizeof (caddr_t)) * alloc_num)); + } + if (iomp_path) { + kmem_free((void *)iomp_path, + (size_t)(FIOMP_MAX_STR * alloc_num)); + } + if (iomp_logical_path) { + kmem_free((void *)iomp_logical_path, + (size_t)(FIOMP_MAX_STR * alloc_num)); + } + if (iomp_path_status) { + kmem_free((void *)iomp_path_status, + (size_t)(FIOMP_MAX_STR * alloc_num)); + } + if (iomp_path_block) { + kmem_free((void *)iomp_path_block, + (size_t)(FIOMP_MAX_STR * alloc_num)); + } + } + break; + + case FIOMPDESTROY: + SCFDBGMSG(SCF_DBGFLAG_IOMP, "FIOMPDESTROY proc"); + ret = ENOTTY; + break; + + case FIOMPSTOP: + SCFDBGMSG(SCF_DBGFLAG_IOMP, "FIOMPSTOP proc"); + + if (ddi_copyin((void *)arg, (void *)&pathnum, + sizeof (int), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "i_ioctl ", 8); + ret = EFAULT; + goto END_inst_ioctl; + } + mutex_enter(&scf_comtbl.all_mutex); + if (pathnum == FIOMP_PATH_ALL) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "i_ioctl ", 8); + ret = EINVAL; + + mutex_exit(&scf_comtbl.all_mutex); + goto END_inst_ioctl; + } else { + /* PATH appointment */ + if (scf_comtbl.path_num < (pathnum + 1)) { + /* Invalid PATH */ + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "i_ioctl ", 8); + ret = EINVAL; + + mutex_exit(&scf_comtbl.all_mutex); + goto END_inst_ioctl; + } + if ((statep = scf_comtbl.iomp_scf[pathnum]) != 0) { + /* SCF command send sync stop */ + ret = scf_make_send_cmd(&scf_cmd, SCF_USE_STOP); + if (ret != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "i_ioctl ", 8); + goto END_STOP; + } + if ((statep->path_status != FIOMP_STAT_ACTIVE) && + (statep->path_status != FIOMP_STAT_STANDBY)) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "i_ioctl ", 8); + ret = EINVAL; + } else { + if (statep->path_status == FIOMP_STAT_ACTIVE) { + /* Exec SCF device appointment */ + if (scf_comtbl.scf_wait_p == 0) { + /* Last deveice stop is error */ + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, + __LINE__, "i_ioctl ", 8); + ret = EINVAL; + } else { + /* Device interrupt disable */ + scf_forbid_intr(statep); + scf_chg_scf(statep, FIOMP_STAT_STOP); + /* Send path change command */ + statep = scf_comtbl.scf_wait_p; + scf_comtbl.scf_wait_p = statep->next; + scf_chg_scf(statep, FIOMP_STAT_ACTIVE); + scf_comtbl.scf_exec_p = 0; + scf_comtbl.scf_path_p = 0; + scf_comtbl.scf_pchg_event_sub = + EVENT_SUB_PCHG_WAIT; + scf_next_cmd_check(statep); + + /* DCSP interface stop */ + scf_dscp_stop(FACTOR_PATH_CHG); + } + } else { + /* Not exec device appointment */ + scf_del_queue(statep); + scf_forbid_intr(statep); + scf_chg_scf(statep, FIOMP_STAT_STOP); + } + } +/* + * END_STOP + */ + END_STOP: + + /* SCF command send sync start */ + (void) scf_make_send_cmd(&scf_cmd, SCF_USE_START); + } else { + /* Appointed path is already out of managemen */ + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "i_ioctl ", 8); + ret = EINVAL; + } + } + mutex_exit(&scf_comtbl.all_mutex); + break; + + case FIOMPSTART: + SCFDBGMSG(SCF_DBGFLAG_IOMP, "FIOMPSTART proc"); + + if (ddi_copyin((void *)arg, (void *)&pathnum, + sizeof (int), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "i_ioctl ", 8); + ret = EFAULT; + goto END_inst_ioctl; + } + mutex_enter(&scf_comtbl.all_mutex); + if (pathnum == FIOMP_PATH_ALL) { + /* PATH_ALL appointment */ + if ((statep = scf_comtbl.scf_stop_p) != 0) { + /* Check stop queue */ + scf_comtbl.scf_stop_p = 0; + while (statep) { + wkstatep = statep->next; + /* Interupt disable */ + scf_permit_intr(statep, 1); + if ((scf_comtbl.scf_path_p) || + (scf_comtbl.scf_exec_p)) { + scf_chg_scf(statep, FIOMP_STAT_STANDBY); + } else { + if (scf_comtbl.watchdog_after_resume) { + scf_comtbl.alive_running = SCF_ALIVE_START; + scf_comtbl.watchdog_after_resume = 0; + } + scf_chg_scf(statep, FIOMP_STAT_ACTIVE); + /* Send path change command */ + scf_comtbl.scf_exec_p = 0; + scf_comtbl.scf_path_p = 0; + + scf_comtbl.scf_pchg_event_sub = EVENT_SUB_PCHG_WAIT; + scf_next_cmd_check(statep); + } + statep = wkstatep; + } + } + } else { + /* PATH appointment */ + if (scf_comtbl.path_num < (pathnum + 1)) { + /* Invalid PATH */ + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "i_ioctl ", 8); + ret = EINVAL; + mutex_exit(&scf_comtbl.all_mutex); + goto END_inst_ioctl; + } + if ((statep = scf_comtbl.iomp_scf[pathnum]) != 0) { + if (statep->path_status == FIOMP_STAT_STOP) { + /* Check stop queue */ + scf_del_queue(statep); + /* Interrupt enable */ + scf_permit_intr(statep, 1); + if ((scf_comtbl.scf_path_p) || + (scf_comtbl.scf_exec_p)) { + scf_chg_scf(statep, FIOMP_STAT_STANDBY); + } else { + if (scf_comtbl.watchdog_after_resume) { + scf_comtbl.alive_running = SCF_ALIVE_START; + scf_comtbl.watchdog_after_resume = 0; + } + scf_chg_scf(statep, FIOMP_STAT_ACTIVE); + /* Send path change command */ + scf_comtbl.scf_exec_p = 0; + scf_comtbl.scf_path_p = 0; + scf_comtbl.scf_pchg_event_sub = EVENT_SUB_PCHG_WAIT; + scf_next_cmd_check(statep); + } + } else { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, + __LINE__, "i_ioctl ", 8); + ret = EINVAL; + } + } else { + /* Appointed path is already out of managemen */ + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "i_ioctl ", 8); + ret = EINVAL; + } + } + mutex_exit(&scf_comtbl.all_mutex); + break; + + case FIOMPRECOVER: + SCFDBGMSG(SCF_DBGFLAG_IOMP, "FIOMPRECOVER proc"); + + if (ddi_copyin((void *)arg, (void *)&pathnum, + sizeof (int), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "i_ioctl ", 8); + ret = EFAULT; + goto END_inst_ioctl; + } + mutex_enter(&scf_comtbl.all_mutex); + if (pathnum == FIOMP_PATH_ALL) { + /* PATH_ALL appointment */ + + /* Check fail queue */ + if ((statep = scf_comtbl.scf_err_p) != 0) { + scf_comtbl.scf_err_p = 0; + while (statep) { + wkstatep = statep->next; + /* Interrupt enable */ + scf_forbid_intr(statep); + statep->scf_herr = 0; + statep->tesum_rcnt = 0; + statep->resum_rcnt = 0; + statep->cmd_to_rcnt = 0; + scf_chg_scf(statep, FIOMP_STAT_STOP); + statep = wkstatep; + } + } + } else { + /* PATH appointment */ + if (scf_comtbl.path_num < (pathnum + 1)) { + /* Invalid PATH */ + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "i_ioctl ", 8); + ret = EINVAL; + mutex_exit(&scf_comtbl.all_mutex); + goto END_inst_ioctl; + } + if ((statep = scf_comtbl.iomp_scf[pathnum]) != 0) { + if (statep->path_status == FIOMP_STAT_FAIL) { + scf_del_queue(statep); + scf_forbid_intr(statep); + statep->scf_herr = 0; + statep->tesum_rcnt = 0; + statep->resum_rcnt = 0; + statep->cmd_to_rcnt = 0; + scf_chg_scf(statep, FIOMP_STAT_STOP); + } else { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, + __LINE__, "i_ioctl ", 8); + ret = EINVAL; + } + } else { + /* Appointed path is already out of managemen */ + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "i_ioctl ", 8); + ret = EINVAL; + } + } + mutex_exit(&scf_comtbl.all_mutex); + break; + + case FIOMPLIST: + SCFDBGMSG(SCF_DBGFLAG_IOMP, "FIOMPLIST proc"); + + if (u_mode == DDI_MODEL_ILP32) { + /* DDI_MODEL_ILP32 */ + struct fiompdev_32 fiompdev32; + char *work_name_p = 0; + caddr32_t *devs_p = 0; + char *devs = 0; + + if (ddi_copyin((void *)arg, (void *)&fiompdev32, + sizeof (struct fiompdev_32), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "i_ioctl ", 8); + ret = EFAULT; + goto END_inst_ioctl; + } + if (fiompdev32.api_level != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "i_ioctl ", 8); + ret = EINVAL; + goto END_inst_ioctl; + } + alloc_num = fiompdev32.num; + if (fiompdev32.num != 0) { + /* Buffer allocation */ + work_name_p = (char *)kmem_zalloc((size_t)(FIOMP_MAX_STR), + KM_SLEEP); + devs_p = (caddr32_t *)kmem_zalloc + ((size_t)((sizeof (caddr32_t)) * alloc_num), KM_SLEEP); + devs = (char *)kmem_zalloc + ((size_t)(FIOMP_MAX_STR * alloc_num), KM_SLEEP); + } + + mutex_enter(&scf_comtbl.all_mutex); + if (fiompdev32.num != scf_comtbl.path_num) { + /* + * When different from appointed num, perform only num setting + */ + fiompdev32.num = scf_comtbl.path_num; + num_cmp_flag = 1; + } else { + /* Set output information */ + fiompdev32.inst_no = 0; + fiompdev32.inst_minor = SCF_INST_INSTANCE; + fiompdev32.user_minor = SCF_USER_INSTANCE; + fiompdev32.mpmode = FIOMP_FALSE; + fiompdev32.autopath = FIOMP_TRUE; + fiompdev32.needsync = FIOMP_FALSE; + for (ii = 0, jj = 0; ii < fiompdev32.num; + ii++, jj += FIOMP_MAX_STR) { + /* Output information setting every pass */ + devs[jj] = '\0'; + if ((statep = scf_comtbl.iomp_scf[ii]) != 0) { + if (ddi_pathname(statep->dip, work_name_p)) { + sprintf(&devs[jj], "%s:scfc%d", + work_name_p, statep->instance); + } + } + } + } + mutex_exit(&scf_comtbl.all_mutex); + if ((num_cmp_flag == 0) && (fiompdev32.num != 0)) { + if (fiompdev32.devs) { + if (ddi_copyin((void *)(uintptr_t)fiompdev32.devs, + (void *)devs_p, + ((sizeof (caddr32_t)) * fiompdev32.num), + mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "i_ioctl ", 8); + ret = EFAULT; + goto END_LIST32; + } + } + for (ii = 0, jj = 0; ii < fiompdev32.num; + ii++, jj += FIOMP_MAX_STR) { + if (devs_p[ii]) { + if (ddi_copyout((void *)&devs[jj], + (void *)(uintptr_t)devs_p[ii], + FIOMP_MAX_STR, mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, + __LINE__, "i_ioctl ", 8); + ret = EFAULT; + goto END_LIST32; + } + } + } + } + if (ddi_copyout((void *)&fiompdev32, (void *)arg, + sizeof (struct fiompdev_32), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "i_ioctl ", 8); + ret = EFAULT; + } + +/* + * END_LIST32 + */ + END_LIST32: + + /* Buffer release */ + if (work_name_p) { + kmem_free((void *)work_name_p, (size_t)FIOMP_MAX_STR); + } + if (devs_p) { + kmem_free((void *)devs_p, + (size_t)((sizeof (caddr32_t)) * alloc_num)); + } + if (devs) { + kmem_free((void *)devs, + (size_t)(FIOMP_MAX_STR * alloc_num)); + } + } else { + /* DDI_MODEL_NONE */ + struct fiompdev fiompdev; + char *work_name_p = 0; + caddr_t *devs_p = 0; + char *devs = 0; + + if (ddi_copyin((void *)arg, (void *)&fiompdev, + sizeof (struct fiompdev), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "i_ioctl ", 8); + ret = EFAULT; + goto END_inst_ioctl; + } + if (fiompdev.api_level != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "i_ioctl ", 8); + ret = EINVAL; + goto END_inst_ioctl; + } + alloc_num = fiompdev.num; + if (fiompdev.num != 0) { + /* Buffer allocation */ + work_name_p = (char *)kmem_zalloc + ((size_t)(FIOMP_MAX_STR), KM_SLEEP); + devs_p = (caddr_t *)kmem_zalloc + ((size_t)((sizeof (caddr_t)) * alloc_num), KM_SLEEP); + devs = (char *)kmem_zalloc + ((size_t)(FIOMP_MAX_STR * alloc_num), KM_SLEEP); + } + + mutex_enter(&scf_comtbl.all_mutex); + if (fiompdev.num != scf_comtbl.path_num) { + /* + * When different from appointed num, perform only num setting + */ + fiompdev.num = scf_comtbl.path_num; + num_cmp_flag = 1; + } else { + /* Set output information */ + fiompdev.inst_no = 0; + fiompdev.inst_minor = SCF_INST_INSTANCE; + fiompdev.user_minor = SCF_USER_INSTANCE; + fiompdev.mpmode = FIOMP_FALSE; + fiompdev.autopath = FIOMP_TRUE; + fiompdev.needsync = FIOMP_FALSE; + for (ii = 0, jj = 0; ii < fiompdev.num; + ii++, jj += FIOMP_MAX_STR) { + /* Output information setting every pass */ + devs[jj] = '\0'; + if ((statep = scf_comtbl.iomp_scf[ii]) != 0) { + if (ddi_pathname(statep->dip, work_name_p)) { + sprintf(&devs[jj], "%s:scfc%d", + work_name_p, statep->instance); + } + } + } + } + mutex_exit(&scf_comtbl.all_mutex); + if ((num_cmp_flag == 0) && (fiompdev.num != 0)) { + if (fiompdev.devs) { + if (ddi_copyin((void *)fiompdev.devs, + (void *)devs_p, + ((sizeof (caddr_t)) * fiompdev.num), + mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "i_ioctl ", 8); + ret = EFAULT; + goto END_LIST; + } + } + for (ii = 0, jj = 0; ii < fiompdev.num; + ii++, jj += FIOMP_MAX_STR) { + if (devs_p[ii]) { + if (ddi_copyout((void *)&devs[jj], + (void *)devs_p[ii], + FIOMP_MAX_STR, mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, + __LINE__, "i_ioctl ", 8); + ret = EFAULT; + goto END_LIST; + } + } + } + } + if (ddi_copyout((void *)&fiompdev, (void *)arg, + sizeof (struct fiompdev), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "i_ioctl ", 8); + ret = EFAULT; + } + +/* + * END_LIST + */ + END_LIST: + + /* Buffer release */ + if (work_name_p) { + kmem_free((void *)work_name_p, (size_t)FIOMP_MAX_STR); + } + if (devs_p) { + kmem_free((void *)devs_p, + (size_t)((sizeof (caddr_t)) * alloc_num)); + } + if (devs) { + kmem_free((void *)devs, + (size_t)(FIOMP_MAX_STR * alloc_num)); + } + } + break; + + case FIOMPSTATUS: + SCFDBGMSG(SCF_DBGFLAG_IOMP, "FIOMPSTATUS proc"); + + if (u_mode == DDI_MODEL_ILP32) { /* DDI_MODEL_ILP32 */ + struct fiompstatus_32 fiompstatus32; + char *message_p; + + message_p = (char *)kmem_zalloc + ((size_t)(FIOMP_MAX_STR), KM_SLEEP); + + if (ddi_copyin((void *)arg, (void *)&fiompstatus32, + sizeof (struct fiompstatus_32), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "i_ioctl ", 8); + ret = EFAULT; + goto END_STATUS32; + } + pathnum = fiompstatus32.pathnum; + if (pathnum == FIOMP_PATH_ALL) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "i_ioctl ", 8); + ret = EINVAL; + goto END_STATUS32; + } + mutex_enter(&scf_comtbl.all_mutex); + if (scf_comtbl.path_num < (pathnum + 1)) { + /* Invalid path */ + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "i_ioctl ", 8); + ret = EINVAL; + mutex_exit(&scf_comtbl.all_mutex); + goto END_STATUS32; + } + if ((statep = scf_comtbl.iomp_scf[pathnum]) != 0) { + scf_inst_getstat32(statep, &fiompstatus32, + message_p, 1); + } else { + /* + * Appointed path is already out of management + */ + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "i_ioctl ", 8); + ret = EINVAL; + mutex_exit(&scf_comtbl.all_mutex); + goto END_STATUS32; + } + mutex_exit(&scf_comtbl.all_mutex); + if (ddi_copyout((void *)message_p, + (void *)(uintptr_t)fiompstatus32.message, + FIOMP_MAX_STR, mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "i_ioctl ", 8); + ret = EFAULT; + goto END_STATUS32; + } + + if (ddi_copyout((void *)&fiompstatus32, (void *)arg, + sizeof (struct fiompstatus_32), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "i_ioctl ", 8); + ret = EFAULT; + } + +/* + * END_STATUS32 + */ + END_STATUS32: + + if (message_p) { + kmem_free((void *)message_p, + (size_t)FIOMP_MAX_STR); + } + } else { /* DDI_MODEL_NONE */ + struct fiompstatus fiompstatus; + char *message_p; + + message_p = (char *)kmem_zalloc + ((size_t)(FIOMP_MAX_STR), KM_SLEEP); + + if (ddi_copyin((void *)arg, (void *)&fiompstatus, + sizeof (struct fiompstatus), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "i_ioctl ", 8); + ret = EFAULT; + goto END_STATUS; + } + pathnum = fiompstatus.pathnum; + if (pathnum == FIOMP_PATH_ALL) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "i_ioctl ", 8); + ret = EINVAL; + goto END_STATUS; + } + mutex_enter(&scf_comtbl.all_mutex); + if (scf_comtbl.path_num < (pathnum + 1)) { + /* Invalid path */ + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "i_ioctl ", 8); + ret = EINVAL; + mutex_exit(&scf_comtbl.all_mutex); + goto END_STATUS; + } + if ((statep = scf_comtbl.iomp_scf[pathnum]) != 0) { + scf_inst_getstat(statep, &fiompstatus, + message_p, 1); + } else { + /* + * Appointed path is already out of managemen + */ + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "i_ioctl ", 8); + ret = EINVAL; + mutex_exit(&scf_comtbl.all_mutex); + goto END_STATUS; + } + mutex_exit(&scf_comtbl.all_mutex); + if (ddi_copyout((void *)message_p, + (void *)fiompstatus.message, + FIOMP_MAX_STR, mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "i_ioctl ", 8); + ret = EFAULT; + goto END_STATUS; + } + + if (ddi_copyout((void *)&fiompstatus, + (void *)arg, sizeof (struct fiompstatus), + mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "i_ioctl ", 8); + ret = EFAULT; + } + +/* + * END_STATUS + */ + END_STATUS: + + if (message_p) { + kmem_free((void *)message_p, + (size_t)FIOMP_MAX_STR); + } + } + break; + + case FIOMPADD: + SCFDBGMSG(SCF_DBGFLAG_IOMP, "FIOMPADD proc"); + + ret = ENOTTY; + break; + + case FIOMPDEL: + SCFDBGMSG(SCF_DBGFLAG_IOMP, "FIOMPDEL proc"); + + ret = ENOTTY; + break; + + case FIOMPACTIVE: + SCFDBGMSG(SCF_DBGFLAG_IOMP, "FIOMPACTIVE proc"); + + ret = ENOTTY; + break; + + case FIOMPDISCONNECT: + SCFDBGMSG(SCF_DBGFLAG_IOMP, "FIOMPDISCONNECT proc"); + + if (ddi_copyin((void *)arg, (void *)&pathnum, + sizeof (int), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "i_ioctl ", 8); + ret = EFAULT; + goto END_inst_ioctl; + } + mutex_enter(&scf_comtbl.all_mutex); + if (pathnum == FIOMP_PATH_ALL) { + /* PATH_ALL appointment */ + + /* Check stop queue */ + if ((statep = scf_comtbl.scf_stop_p) != 0) { + scf_comtbl.scf_stop_p = 0; + while (statep) { + wkstatep = statep->next; + scf_chg_scf(statep, FIOMP_STAT_DISCON); + statep = wkstatep; + } + } + /* Check fail queue */ + if ((statep = scf_comtbl.scf_err_p) != 0) { + scf_comtbl.scf_err_p = 0; + while (statep) { + wkstatep = statep->next; + scf_chg_scf(statep, FIOMP_STAT_DISCON); + statep = wkstatep; + } + } + } else { + /* PATH appointment */ + if (scf_comtbl.path_num < (pathnum + 1)) { + /* Invalid path */ + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "i_ioctl ", 8); + ret = EINVAL; + mutex_exit(&scf_comtbl.all_mutex); + goto END_inst_ioctl; + } + if ((statep = scf_comtbl.iomp_scf[pathnum]) != 0) { + if ((statep->path_status == FIOMP_STAT_STOP) || + (statep->path_status == + FIOMP_STAT_FAIL)) { + scf_del_queue(statep); + scf_chg_scf(statep, FIOMP_STAT_DISCON); + } else { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, + __LINE__, "i_ioctl ", 8); + ret = EINVAL; + } + } else { + /* Appointed path is already out of managemen */ + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "i_ioctl ", 8); + ret = EINVAL; + } + } + + mutex_exit(&scf_comtbl.all_mutex); + break; + + case FIOMPCONNECT: + SCFDBGMSG(SCF_DBGFLAG_IOMP, "FIOMPCONNECT proc"); + + if (ddi_copyin((void *)arg, (void *)&pathnum, + sizeof (int), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "i_ioctl ", 8); + ret = EFAULT; + goto END_inst_ioctl; + } + mutex_enter(&scf_comtbl.all_mutex); + if (pathnum == FIOMP_PATH_ALL) { + /* PATH_ALL appointment */ + + /* Check disconnect queue */ + if ((statep = scf_comtbl.scf_disc_p) != 0) { + scf_comtbl.scf_disc_p = 0; + while (statep) { + wkstatep = statep->next; + if (statep->scf_herr) { + scf_chg_scf(statep, + FIOMP_STAT_FAIL); + } else { + scf_chg_scf(statep, + FIOMP_STAT_STOP); + } + statep = wkstatep; + } + } + } else { + /* PATH appointment */ + if (scf_comtbl.path_num < (pathnum + 1)) { + /* Invalid path */ + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "i_ioctl ", 8); + ret = EINVAL; + mutex_exit(&scf_comtbl.all_mutex); + goto END_inst_ioctl; + } + if ((statep = scf_comtbl.iomp_scf[pathnum]) != 0) { + if (statep->path_status == FIOMP_STAT_DISCON) { + scf_del_queue(statep); + if (statep->scf_herr) { + scf_chg_scf(statep, + FIOMP_STAT_FAIL); + } else { + scf_chg_scf(statep, + FIOMP_STAT_STOP); + } + } else { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, + __LINE__, "i_ioctl ", 8); + ret = EINVAL; + } + } else { + /* Appointed path is already out of managemen */ + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "i_ioctl ", 8); + ret = EINVAL; + } + } + mutex_exit(&scf_comtbl.all_mutex); + break; + + case FIOMPSTANDBY: + SCFDBGMSG(SCF_DBGFLAG_IOMP, "FIOMPSTANDBY proc"); + + ret = ENOTTY; + break; + + case FIOMPBLOCK: + SCFDBGMSG(SCF_DBGFLAG_IOMP, "FIOMPBLOCK proc"); + + ret = ENOTTY; + break; + + case FIOMPUNBLOCK: + SCFDBGMSG(SCF_DBGFLAG_IOMP, "FIOMPUNBLOCK proc"); + + ret = ENOTTY; + break; + + case FIOMPDIAGON: + SCFDBGMSG(SCF_DBGFLAG_IOMP, "FIOMPDIAGON proc"); + + ret = ENOTTY; + break; + + case FIOMPDIAGOFF: + SCFDBGMSG(SCF_DBGFLAG_IOMP, "FIOMPDIAGOFF proc"); + + ret = ENOTTY; + break; + + case FIOMPGETALLSTAT: + SCFDBGMSG(SCF_DBGFLAG_IOMP, "FIOMPGETALLSTAT proc"); + + if (u_mode == DDI_MODEL_ILP32) { + /* DDI_MODEL_ILP32 */ + struct fiomp_all_stat_32 fiomp_all_stat32; + struct fiompstatus_32 *fiompstatus32_p = 0; + char *message_p = 0; + + if (ddi_copyin((void *)arg, (void *)&fiomp_all_stat32, + sizeof (struct fiomp_all_stat_32), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "i_ioctl ", 8); + ret = EFAULT; + goto END_inst_ioctl; + } + alloc_num = fiomp_all_stat32.num; + if (fiomp_all_stat32.num != 0) { + /* Buffer allocation */ + fiompstatus32_p = + (struct fiompstatus_32 *)kmem_zalloc + ((size_t)((sizeof (struct fiompstatus_32)) * alloc_num), + KM_SLEEP); + message_p = (char *)kmem_zalloc + ((size_t)(FIOMP_MAX_STR * alloc_num), KM_SLEEP); + } + + if (fiomp_all_stat32.num != 0) { + if (ddi_copyin((void *)(uintptr_t)fiomp_all_stat32.status, + (void *)fiompstatus32_p, + ((sizeof (struct fiompstatus_32)) * + fiomp_all_stat32.num), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "i_ioctl ", 8); + ret = EFAULT; + goto END_GETALLSTAT32; + } + } + mutex_enter(&scf_comtbl.all_mutex); + if (scf_comtbl.path_num != fiomp_all_stat32.num) { + /* + * When different from appointed num, perform only num setting + */ + fiomp_all_stat32.num = scf_comtbl.path_num; + num_cmp_flag = 1; + } else { + /* Output information setting every pass */ + for (ii = 0, jj = 0; ii < fiomp_all_stat32.num; + ii++, jj += FIOMP_MAX_STR) { + statep = scf_comtbl.iomp_scf[ii]; + scf_inst_getstat32(statep, &fiompstatus32_p[ii], + &message_p[jj], 1); + } + } + mutex_exit(&scf_comtbl.all_mutex); + if (num_cmp_flag == 0 && fiomp_all_stat32.num != 0) { + if (ddi_copyout((void *)fiompstatus32_p, + (void *)(uintptr_t)fiomp_all_stat32.status, + ((sizeof (struct fiompstatus_32)) * + fiomp_all_stat32.num), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "i_ioctl ", 8); + ret = EFAULT; + goto END_GETALLSTAT32; + } + for (ii = 0, jj = 0; ii < fiomp_all_stat32.num; + ii++, jj += FIOMP_MAX_STR) { + if (ddi_copyout((void *)&message_p[jj], + (void *)(uintptr_t)fiompstatus32_p[ii].message, + FIOMP_MAX_STR, mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "i_ioctl ", 8); + ret = EFAULT; + goto END_GETALLSTAT32; + } + } + } + if (ddi_copyout((void *)&fiomp_all_stat32, (void *)arg, + sizeof (struct fiomp_all_stat_32), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "i_ioctl ", 8); + ret = EFAULT; + } + +/* + * END_GETALLSTAT32 + */ + END_GETALLSTAT32: + + /* Buffer release */ + if (fiompstatus32_p) { + kmem_free((void *)fiompstatus32_p, + (size_t)((sizeof (struct fiompstatus_32)) * alloc_num)); + } + if (message_p) { + kmem_free((void *)message_p, + (size_t)(FIOMP_MAX_STR * alloc_num)); + } + } else { + /* DDI_MODEL_NONE */ + struct fiomp_all_stat fiomp_all_stat; + struct fiompstatus *fiompstatus_p = 0; + char *message_p = 0; + + if (ddi_copyin((void *)arg, (void *)&fiomp_all_stat, + sizeof (struct fiomp_all_stat), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "i_ioctl ", 8); + ret = EFAULT; + goto END_inst_ioctl; + } + alloc_num = fiomp_all_stat.num; + if (fiomp_all_stat.num != 0) { + /* Buffer allocation */ + fiompstatus_p = + (struct fiompstatus *)kmem_zalloc + ((size_t)((sizeof (struct fiompstatus)) * alloc_num), + KM_SLEEP); + message_p = (char *)kmem_zalloc + ((size_t)(FIOMP_MAX_STR * alloc_num), KM_SLEEP); + } + + if (fiomp_all_stat.num != 0) { + if (ddi_copyin((void *)fiomp_all_stat.status, + (void *)fiompstatus_p, + ((sizeof (struct fiompstatus)) * fiomp_all_stat.num), + mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "i_ioctl ", 8); + ret = EFAULT; + goto END_GETALLSTAT; + } + } + mutex_enter(&scf_comtbl.all_mutex); + if (scf_comtbl.path_num != fiomp_all_stat.num) { + /* + * When different from appointed num, perform only num setting + */ + fiomp_all_stat.num = scf_comtbl.path_num; + num_cmp_flag = 1; + } else { + /* Output information setting every pass */ + for (ii = 0, jj = 0; ii < fiomp_all_stat.num; + ii++, jj += FIOMP_MAX_STR) { + statep = scf_comtbl.iomp_scf[ii]; + scf_inst_getstat(statep, &fiompstatus_p[ii], + &message_p[jj], 1); + } + } + mutex_exit(&scf_comtbl.all_mutex); + if (num_cmp_flag == 0 && fiomp_all_stat.num != 0) { + if (ddi_copyout((void *)fiompstatus_p, + (void *)fiomp_all_stat.status, + ((sizeof (struct fiompstatus)) * fiomp_all_stat.num), + mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "i_ioctl ", 8); + ret = EFAULT; + goto END_GETALLSTAT; + } + for (ii = 0, jj = 0; ii < fiomp_all_stat.num; + ii++, jj += FIOMP_MAX_STR) { + if (ddi_copyout((void *)&message_p[jj], + (void *)fiompstatus_p[ii].message, + FIOMP_MAX_STR, mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "i_ioctl ", 8); + ret = EFAULT; + goto END_GETALLSTAT; + } + } + } + if (ddi_copyout((void *)&fiomp_all_stat, (void *)arg, + sizeof (struct fiomp_all_stat), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "i_ioctl ", 8); + ret = EFAULT; + } + +/* + * END_GETALLSTAT + */ + END_GETALLSTAT: + + /* Buffer release */ + if (fiompstatus_p) { + kmem_free((void *)fiompstatus_p, + (size_t)((sizeof (struct fiompstatus)) * alloc_num)); + } + if (message_p) { + kmem_free((void *)message_p, + (size_t)(FIOMP_MAX_STR * alloc_num)); + } + } + break; + + case FIOMPCHG: + SCFDBGMSG(SCF_DBGFLAG_IOMP, "FIOMPCHG proc"); + + ret = ENOTTY; + break; + + case FIOMPGETEVENT: + SCFDBGMSG(SCF_DBGFLAG_IOMP, "FIOMPGETEVENT proc"); + + ret = ENOTTY; + break; + + default: + /* undefined */ + SCFDBGMSG(SCF_DBGFLAG_IOMP, "undefined ioctl command"); + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "i_ioctl ", 8); + ret = ENOTTY; + } + +/* + * END_inst_ioctl + */ + END_inst_ioctl: + + SCFDBGMSG1(SCF_DBGFLAG_IOMP, SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + +/* + * Make path status : FIOMPSTATUS, FIOMPGETALLSTAT : 32bit-64bit + */ +void +scf_inst_getstat32(scf_state_t *statep, struct fiompstatus_32 *status32_p, + char *message_p, int flag) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_inst_getstat32() " + int path_status; + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_IOMP, SCF_FUNC_NAME ": start"); + + if (statep) { + if (flag) { + /* Current status */ + path_status = statep->path_status; + } else { + /* Former status */ + path_status = statep->old_path_status; + } + /* Set status */ + switch (path_status) { + case FIOMP_STAT_ACTIVE: + status32_p->status = FIOMP_STAT_ACTIVE; + break; + case FIOMP_STAT_STANDBY: + status32_p->status = FIOMP_STAT_STANDBY; + break; + case FIOMP_STAT_STOP: + status32_p->status = FIOMP_STAT_STOP; + break; + case FIOMP_STAT_DISCON: + status32_p->status = FIOMP_STAT_DISCON; + break; + case FIOMP_STAT_FAIL: + status32_p->status = FIOMP_STAT_FAIL; + break; + default: + status32_p->status = FIOMP_STAT_EMPTY; + } + /* IOMP details message making */ + scf_path_stmsg(statep, message_p); + } else { + status32_p->status = FIOMP_STAT_EMPTY; + message_p[0] = '\0'; + } + status32_p->block_status = FIOMP_BSTAT_BLOCK; + + SCFDBGMSG(SCF_DBGFLAG_IOMP, SCF_FUNC_NAME ": end"); +} + +/* + * Make path status : FIOMPSTATUS, FIOMPGETALLSTAT : 64bit-64bit/32bit-32bit + */ +void +scf_inst_getstat(scf_state_t *statep, struct fiompstatus *status_p, + char *message_p, int flag) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_inst_getstat() " + int path_status; + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_IOMP, SCF_FUNC_NAME ": start"); + + if (statep) { + if (flag) { + /* Current status */ + path_status = statep->path_status; + } else { + /* Former status */ + path_status = statep->old_path_status; + } + /* Set status */ + switch (path_status) { + case FIOMP_STAT_ACTIVE: + status_p->status = FIOMP_STAT_ACTIVE; + break; + case FIOMP_STAT_STANDBY: + status_p->status = FIOMP_STAT_STANDBY; + break; + case FIOMP_STAT_STOP: + status_p->status = FIOMP_STAT_STOP; + break; + case FIOMP_STAT_DISCON: + status_p->status = FIOMP_STAT_DISCON; + break; + case FIOMP_STAT_FAIL: + status_p->status = FIOMP_STAT_FAIL; + break; + default: + status_p->status = FIOMP_STAT_EMPTY; + } + /* IOMP details message making */ + scf_path_stmsg(statep, message_p); + } else { + status_p->status = FIOMP_STAT_EMPTY; + message_p[0] = '\0'; + } + status_p->block_status = FIOMP_BSTAT_BLOCK; + + SCFDBGMSG(SCF_DBGFLAG_IOMP, SCF_FUNC_NAME ": end"); +} + +/* + * IOMP details message making + */ +void +scf_path_stmsg(scf_state_t *statep, char *message_p) + +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_path_stmsg() " + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_IOMP, SCF_FUNC_NAME ": start"); + + if (statep->scf_herr & HERR_TESUM) { + strcpy(message_p, "Command error"); + } else if (statep->scf_herr & HERR_RESUM) { + strcpy(message_p, "Sumcheck error"); + } else if (statep->scf_herr & HERR_CMD_RTO) { + strcpy(message_p, "Command timeout"); + } else if (statep->scf_herr & HERR_BUSY_RTO) { + strcpy(message_p, "Command busy timeout"); + } else if (statep->scf_herr & HERR_DSCP_INTERFACE) { + strcpy(message_p, "SCF communication path error"); + } else if (statep->scf_herr & HERR_DSCP_ACKTO) { + strcpy(message_p, "DSCP ack response timeout"); + } else if (statep->scf_herr & HERR_DSCP_ENDTO) { + strcpy(message_p, "DSCP end response timeout"); + } else { + strcpy(message_p, "Good"); + } + + SCFDBGMSG(SCF_DBGFLAG_IOMP, SCF_FUNC_NAME ": end"); +} +#endif diff --git a/usr/src/uts/sun4u/opl/io/scfd/scfkstat.c b/usr/src/uts/sun4u/opl/io/scfd/scfkstat.c new file mode 100644 index 0000000000..be531bfedc --- /dev/null +++ b/usr/src/uts/sun4u/opl/io/scfd/scfkstat.c @@ -0,0 +1,219 @@ +/* + * 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 + */ +/* + * All Rights Reserved, Copyright (c) FUJITSU LIMITED 2006 + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <sys/kmem.h> +#include <sys/file.h> +#include <sys/errno.h> +#include <sys/open.h> +#include <sys/cred.h> +#include <sys/ddi.h> +#include <sys/sunddi.h> +#include <sys/kstat.h> + +#include <sys/scfd/scfparam.h> + + +/* + * for kstat_named_create(9F) + */ +typedef struct _scf_kstat_named_list { + char *name; + uchar_t data_type; +} scf_kstat_named_list; + +static scf_kstat_named_list scf_kstat_system_list[] = { + {SCF_STATUS_KSTAT_NAMED, KSTAT_DATA_CHAR}, + {SCF_BOOT_MODE_KSTAT_NAMED, KSTAT_DATA_CHAR}, + {SCF_SECURE_MODE_KSTAT_NAMED, KSTAT_DATA_CHAR}, + {SCF_EVENT_KSTAT_NAMED, KSTAT_DATA_CHAR}, + {SCF_ALIVE_KSTAT_NAMED, KSTAT_DATA_CHAR}, +}; + + +/* + * prototype + */ +static kstat_t *scf_kstat_named_init(char *name, + scf_kstat_named_list *kstat_list, int ndata, + int (*update)(struct kstat *, int)); +static int scf_kstat_sys_update(kstat_t *ksp, int rw); + + +/* + * from scf_attach() + */ +/* DDI_ATTACH */ +void +scf_kstat_init() +{ +#define SCF_FUNC_NAME "scf_kstat_init() " + scf_kstat_private_t *private; + + ASSERT(MUTEX_HELD(&scf_comtbl.attach_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_KSTAT, SCF_FUNC_NAME ": start"); + + private = scf_comtbl.kstat_private = + kmem_zalloc(sizeof (scf_kstat_private_t), KM_SLEEP); + + /* NAMED state */ + private->ksp_scf = scf_kstat_named_init(SCF_SYSTEM_KSTAT_NAME, + scf_kstat_system_list, SCF_KSTAT_SYS_NAMED_NDATA, + scf_kstat_sys_update); + + SCFDBGMSG(SCF_DBGFLAG_KSTAT, SCF_FUNC_NAME ": end"); +} + + +/* + * from scf_detach() + */ +/* DDI_DETACH */ +void +scf_kstat_fini() +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_kstat_fini() " + scf_kstat_private_t *private = scf_comtbl.kstat_private; + + ASSERT(MUTEX_HELD(&scf_comtbl.attach_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_KSTAT, SCF_FUNC_NAME ": start"); + + if (private->ksp_scf != NULL) { + kstat_delete(private->ksp_scf); + } + + kmem_free(private, sizeof (scf_kstat_private_t)); + + scf_comtbl.kstat_private = NULL; + + SCFDBGMSG(SCF_DBGFLAG_KSTAT, SCF_FUNC_NAME ": end"); +} + + +/* + * scf_kstat_named_init() + * kstat_create(KSTAT_TYPE_NAMED) + kstat_named_init() + kstat_install() + */ +static kstat_t * +scf_kstat_named_init(char *name, scf_kstat_named_list *kstat_list, int ndata, + int (*update)(struct kstat *, int)) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_kstat_named_init() " + kstat_t *scf_ksp; + kstat_named_t *scf_named_ksp; + int ii; + + ASSERT(MUTEX_HELD(&scf_comtbl.attach_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_KSTAT, SCF_FUNC_NAME ": start"); + + scf_ksp = kstat_create(SCF_DRIVER_NAME, 0, name, "misc", + KSTAT_TYPE_NAMED, ndata, KSTAT_FLAG_PERSISTENT); + if (scf_ksp == NULL) { + cmn_err(CE_WARN, "%s: kstat_create failed.", scf_driver_name); + return (NULL); + } + scf_named_ksp = (kstat_named_t *)(scf_ksp->ks_data); + + /* + * initialize the named kstat + */ + for (ii = 0; ii < ndata; ii++, scf_named_ksp++) { + kstat_named_init(scf_named_ksp, kstat_list[ii].name, + kstat_list[ii].data_type); + } + + scf_ksp->ks_update = update; + scf_ksp->ks_lock = (void *)&(scf_comtbl.all_mutex); + + scf_ksp->ks_private = &scf_comtbl; + + kstat_install(scf_ksp); + + SCFDBGMSG(SCF_DBGFLAG_KSTAT, SCF_FUNC_NAME ": end"); + return (scf_ksp); +} + + +/* + * "scf" update + */ +static int +scf_kstat_sys_update(kstat_t *ksp, int rw) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_kstat_sys_update() " + kstat_named_t *sysksp; + scf_comtbl_t *softsp; + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_KSTAT, SCF_FUNC_NAME ": start"); + + sysksp = (kstat_named_t *)ksp->ks_data; + softsp = (scf_comtbl_t *)ksp->ks_private; + + /* this is a read-only kstat */ + if (rw == KSTAT_WRITE) { + return (EACCES); + } + + if (softsp->scf_status == SCF_STATUS_ONLINE) { + sysksp[SCF_KSTAT_SYS_NAMED_STATUS].value.c[0] = + SCF_STAT_STATUS_ONLINE; + } else { + sysksp[SCF_KSTAT_SYS_NAMED_STATUS].value.c[0] = + SCF_STAT_STATUS_OFFLINE; + } + + if ((softsp->scf_mode_sw & STATUS_BOOT_MODE) == STATUS_MODE_AUTO_BOOT) { + sysksp[SCF_KSTAT_SYS_NAMED_BOOT_MODE].value.c[0] = + SCF_STAT_MODE_LOCK; + } else { + sysksp[SCF_KSTAT_SYS_NAMED_BOOT_MODE].value.c[0] = + SCF_STAT_MODE_UNLOCK; + } + + if ((softsp->scf_mode_sw & STATUS_SECURE_MODE) == STATUS_MODE_LOCK) { + sysksp[SCF_KSTAT_SYS_NAMED_SECURE_MODE].value.c[0] = + SCF_STAT_MODE_AUTO_BOOT; + } else { + sysksp[SCF_KSTAT_SYS_NAMED_SECURE_MODE].value.c[0] = + SCF_STAT_MODE_OBP_STOP; + } + + sysksp[SCF_KSTAT_SYS_NAMED_EVENT].value.c[0] = + (char)softsp->last_event[4]; + sysksp[SCF_KSTAT_SYS_NAMED_ALIVE].value.c[0] = + softsp->alive_running; + + SCFDBGMSG(SCF_DBGFLAG_KSTAT, SCF_FUNC_NAME ": end"); + return (0); +} diff --git a/usr/src/uts/sun4u/opl/io/scfd/scfops.c b/usr/src/uts/sun4u/opl/io/scfd/scfops.c new file mode 100644 index 0000000000..3a8a194b8d --- /dev/null +++ b/usr/src/uts/sun4u/opl/io/scfd/scfops.c @@ -0,0 +1,3470 @@ +/* + * 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 + */ +/* + * All Rights Reserved, Copyright (c) FUJITSU LIMITED 2006 + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <sys/file.h> +#include <sys/errno.h> +#include <sys/open.h> +#include <sys/uio.h> +#include <sys/cred.h> +#include <sys/kmem.h> +#include <sys/ddi.h> +#include <sys/sunddi.h> + +#include <sys/scfd/scfparam.h> +#include <sys/scfd/scfio32.h> + +/* + * Function list + */ +int scf_open(dev_t *devp, int flag, int otyp, cred_t *cred_p); +int scf_close(dev_t dev, int flag, int otyp, cred_t *cred_p); +int scf_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cred_p, + int *rval_p); +int scf_ioc_reportstat(intptr_t arg, int mode, int *rval_p, int u_mode); +int scf_ioc_clearlcd(intptr_t arg, int mode, int *rval_p, int u_mode); +int scf_ioc_wrlcd(intptr_t arg, int mode, int *rval_p, int u_mode); +int scf_ioc_getdiskled(intptr_t arg, int mode, int *rval_p, int u_mode); +int scf_ioc_setdiskled(intptr_t arg, int mode, int *rval_p, int u_mode); +int scf_ioc_getsdownreason(intptr_t arg, int mode, int *rval_p, int u_mode); +int scf_ioc_optiondisp(intptr_t arg, int mode, int *rval_p, int u_mode); +int scf_ioc_getpciconfig(intptr_t arg, int mode, int *rval_p, int u_mode); +int scf_ioc_hac(intptr_t arg, int mode, int *rval_p, int u_mode); +int scf_ioc_hstadrsinfo(intptr_t arg, int mode, int *rval_p, int u_mode); +int scf_ioc_rdclistmax(intptr_t arg, int mode, int *rval_p, int u_mode); +int scf_ioc_rdclistx(intptr_t arg, int mode, int *rval_p, int u_mode); +int scf_ioc_rdctrl(intptr_t arg, int mode, int *rval_p, int u_mode); +int scf_ioc_opecall(intptr_t arg, int mode, int *rval_p, int u_mode); +int scf_ioc_getreport(intptr_t arg, int mode, int *rval_p, int u_mode); +int scf_ioc_rcipwr(intptr_t arg, int mode, int *rval_p, int u_mode); +int scf_ioc_panicreq(intptr_t arg, int mode, int *rval_p, int u_mode); +int scf_ioc_panicchk(intptr_t arg, int mode, int *rval_p, int u_mode); +int scf_ioc_parmset(intptr_t arg, int mode, int *rval_p, int u_mode); +int scf_ioc_parmget(intptr_t arg, int mode, int *rval_p, int u_mode); +int scf_ioc_autopwrset(intptr_t arg, int mode, int *rval_p, int u_mode); +int scf_ioc_autopwrget(intptr_t arg, int mode, int *rval_p, int u_mode); +int scf_ioc_autopwrclr(intptr_t arg, int mode, int *rval_p, int u_mode); +int scf_ioc_autopwrfpoff(intptr_t arg, int mode, int *rval_p, int u_mode); +int scf_ioc_autopwrexset(intptr_t arg, int mode, int *rval_p, int u_mode); +int scf_ioc_autopwrexget(intptr_t arg, int mode, int *rval_p, int u_mode); +int scf_ioc_dr(intptr_t arg, int mode, int *rval_p, int u_mode); +int scf_ioc_eventlist(intptr_t arg, int mode, int *rval_p, int u_mode); +int scf_ioc_getevent(intptr_t arg, int mode, int *rval_p, int u_mode); +int scf_ioc_setmadmevent(intptr_t arg, int mode, int *rval_p, int u_mode); +int scf_ioc_remcscmd(intptr_t arg, int mode, int *rval_p, int u_mode); +int scf_ioc_remcsfile(intptr_t arg, int mode, int *rval_p, int u_mode); +int scf_ioc_sparecmd(intptr_t arg, int mode, int *rval_p, int u_mode); +int scf_ioc_setphpinfo(intptr_t arg, int mode, int *rval_p, int u_mode); +int scf_ioc_pciresetreq(intptr_t arg, int mode, int *rval_p, int u_mode); +int scf_push_reportsense(unsigned int rci_addr, unsigned char *sense, + time_t timestamp); +int scf_pop_reportsense(scfreport_t *rsense); +int scf_push_getevent(unsigned char *event_p); +int scf_pop_getevent(scfevent_t *event_p); +int scf_valid_date(int year, int month, int date); +int scf_check_pon_time(scfautopwrtime_t *ptime); +int scf_check_poff_time(scfautopwrtime_t *ptime); + +/* + * scf_open() + * + * Description: Driver open() entry processing. + * + */ +/* ARGSUSED */ +int +scf_open(dev_t *devp, int flag, int otyp, cred_t *cred_p) +{ +#define SCF_FUNC_NAME "scf_open() " + int ret = 0; + int instance; + + SCFDBGMSG1(SCF_DBGFLAG_OPCLS, SCF_FUNC_NAME ": start instance = %d", + getminor(*devp)); + SC_DBG_DRV_TRACE(TC_OPEN|TC_IN, __LINE__, NULL, 0); + + /* get instance */ + instance = getminor(*devp); + if (SCF_CHECK_INSTANCE(instance)) { + /* is the device character ? */ + if (otyp != OTYP_CHR) { + SC_DBG_DRV_TRACE(TC_OPEN|TC_ERR, __LINE__, + "open ", 8); + ret = EINVAL; + } + } else { + SC_DBG_DRV_TRACE(TC_OPEN|TC_ERR, __LINE__, "open ", 8); + ret = EINVAL; + } + + SC_DBG_DRV_TRACE(TC_OPEN|TC_OUT, __LINE__, &ret, sizeof (int)); + SCFDBGMSG1(SCF_DBGFLAG_OPCLS, SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +/* + * close entry + */ +/* ARGSUSED */ +int +scf_close(dev_t dev, int flag, int otyp, cred_t *cred_p) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_close() " + int ret = 0; + + SCFDBGMSG1(SCF_DBGFLAG_OPCLS, SCF_FUNC_NAME ": start instance = %d", + getminor(dev)); + SC_DBG_DRV_TRACE(TC_CLOSE|TC_IN, __LINE__, NULL, 0); + + SC_DBG_DRV_TRACE(TC_CLOSE|TC_OUT, __LINE__, &ret, sizeof (int)); + SCFDBGMSG(SCF_DBGFLAG_OPCLS, SCF_FUNC_NAME ": end"); + return (ret); +} + + +/* + * scf_ioctl() + * + * Description: Driver ioctl() entry processing. + * + */ +int +scf_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cred_p, + int *rval_p) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_ioctl() " + int ret = 0; + int instance; + int u_mode; + timeout_id_t save_tmids[SCF_TIMERCD_MAX]; + int tm_stop_cnt; + + SCFDBGMSG1(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": start instance = %d", + getminor(dev)); + SC_DBG_DRV_TRACE(TC_IOCTL|TC_IN, __LINE__, &cmd, sizeof (int)); + +#ifdef _MULTI_DATAMODEL + /* DDI_MODEL_ILP32: SCF driver 64bit, upper 32bit */ + /* DDI_MODEL_NONE : SCF driver64bit, upper 64bit */ + u_mode = ddi_model_convert_from(mode & FMODELS); +#else /* ! _MULTI_DATAMODEL */ + /* DDI_MODEL_NONE : SCF driver 32bit, upper 32bit */ + u_mode = DDI_MODEL_NONE; +#endif /* _MULTI_DATAMODEL */ + + /* get instance */ + instance = getminor(dev); + + SCF_DBG_IOMP_PROC; + + if (instance == SCF_USER_INSTANCE) { + + mutex_enter(&scf_comtbl.attach_mutex); + if (!(scf_comtbl.resource_flag & DID_MUTEX_ALL)) { + /* Not attach device */ + SCFDBGMSG(SCF_DBGFLAG_IOCTL, "Not attach device"); + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "ioctl ", 8); + mutex_exit(&scf_comtbl.attach_mutex); + ret = ENXIO; + goto END_ioctl; + } + mutex_exit(&scf_comtbl.attach_mutex); + + if (drv_priv(cred_p) != 0) { + /* Not super-user */ + if ((cmd != SCFIOCHSTADRSINFO) && + (cmd != SCFIOCRDCLISTMAX) && + (cmd != SCFIOCRDCLISTX)) { + SCFDBGMSG(SCF_DBGFLAG_IOCTL, "Not super-user"); + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "ioctl ", 8); + ret = EPERM; + goto END_ioctl; + } + } + mutex_enter(&scf_comtbl.all_mutex); + + /* Suspend flag check */ + if (scf_comtbl.suspend_flag) { + SCFDBGMSG(SCF_DBGFLAG_IOCTL, "suspend execute"); + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "ioctl ", 8); + mutex_exit(&scf_comtbl.all_mutex); + ret = EBUSY; + goto END_ioctl; + } + + mutex_exit(&scf_comtbl.all_mutex); + + SCF_DBG_IOCTL_PROC; + + switch ((uint_t)cmd) { + /* + * RAS control interface + */ + case SCFIOCREPORTSTAT: + ret = scf_ioc_reportstat(arg, mode, rval_p, u_mode); + break; + + case SCFIOCCLEARLCD: + ret = scf_ioc_clearlcd(arg, mode, rval_p, u_mode); + break; + + case SCFIOCWRLCD: + ret = scf_ioc_wrlcd(arg, mode, rval_p, u_mode); + break; + + case SCFIOCGETDISKLED: + ret = scf_ioc_getdiskled(arg, mode, rval_p, u_mode); + break; + + case SCFIOCSETDISKLED: + ret = scf_ioc_setdiskled(arg, mode, rval_p, u_mode); + break; + + case SCFIOCGETSDOWNREASON: + ret = scf_ioc_getsdownreason(arg, mode, rval_p, u_mode); + break; + + /* + * System infomarion interface + */ + case SCFIOCOPTIONDISP: + ret = scf_ioc_optiondisp(arg, mode, rval_p, u_mode); + break; + + case SCFIOCGETPCICONFIG: + ret = scf_ioc_getpciconfig(arg, mode, rval_p, u_mode); + break; + + /* + * RCI control interface + */ + case SCFIOCHAC: + ret = scf_ioc_hac(arg, mode, rval_p, u_mode); + break; + + case SCFIOCHSTADRSINFO: + ret = scf_ioc_hstadrsinfo(arg, mode, rval_p, u_mode); + break; + + case SCFIOCRDCLISTMAX: + ret = scf_ioc_rdclistmax(arg, mode, rval_p, u_mode); + break; + + case SCFIOCRDCLISTX: + ret = scf_ioc_rdclistx(arg, mode, rval_p, u_mode); + break; + + case SCFIOCRDCTRL: + ret = scf_ioc_rdctrl(arg, mode, rval_p, u_mode); + break; + + case SCFIOCOPECALL: + ret = scf_ioc_opecall(arg, mode, rval_p, u_mode); + break; + + case SCFIOCGETREPORT: + ret = scf_ioc_getreport(arg, mode, rval_p, u_mode); + break; + + case SCFIOCRCIPWR: + ret = scf_ioc_rcipwr(arg, mode, rval_p, u_mode); + break; + + case SCFIOCPANICREQ: + ret = scf_ioc_panicreq(arg, mode, rval_p, u_mode); + break; + + case SCFIOCPANICCHK: + ret = scf_ioc_panicchk(arg, mode, rval_p, u_mode); + break; + + case SCFIOCPARMSET: + ret = scf_ioc_parmset(arg, mode, rval_p, u_mode); + break; + + case SCFIOCPARMGET: + ret = scf_ioc_parmget(arg, mode, rval_p, u_mode); + break; + + /* + * APCS control interface + */ + case SCFIOCAUTOPWRSET: + ret = scf_ioc_autopwrset(arg, mode, rval_p, u_mode); + break; + + case SCFIOCAUTOPWRGET: + case SCFIOCSYSAUTOPWRGET: + ret = scf_ioc_autopwrget(arg, mode, rval_p, u_mode); + break; + + case SCFIOCSYSAUTOPWRCLR: + ret = scf_ioc_autopwrclr(arg, mode, rval_p, u_mode); + break; + + case SCFIOCAUTOPWRFPOFF: + ret = scf_ioc_autopwrfpoff(arg, mode, rval_p, u_mode); + break; + + case SCFIOCAUTOPWREXSET: + ret = scf_ioc_autopwrexset(arg, mode, rval_p, u_mode); + break; + + case SCFIOCAUTOPWREXGET: + ret = scf_ioc_autopwrexget(arg, mode, rval_p, u_mode); + break; + + /* + * FJDR control interface + */ + case SCFIOCDR: + ret = scf_ioc_dr(arg, mode, rval_p, u_mode); + break; + + /* + * MADM REMCS interface + */ + case SCFIOCEVENTLIST: + ret = scf_ioc_eventlist(arg, mode, rval_p, u_mode); + break; + + case SCFIOCGETEVENT: + ret = scf_ioc_getevent(arg, mode, rval_p, u_mode); + break; + + case SCFIOCSETMADMEVENT: + ret = scf_ioc_setmadmevent(arg, mode, rval_p, u_mode); + break; + + case SCFIOCREMCSCMD: + ret = scf_ioc_remcscmd(arg, mode, rval_p, u_mode); + break; + + case SCFIOCREMCSFILE: + ret = scf_ioc_remcsfile(arg, mode, rval_p, u_mode); + break; + + case SCFIOCSPARECMD: + ret = scf_ioc_sparecmd(arg, mode, rval_p, u_mode); + break; + + /* + * Kernel interface + */ + case SCFIOCSETPHPINFO: + ret = scf_ioc_setphpinfo(arg, mode, rval_p, u_mode); + break; + + case SCFIOCPCIRESETREQ: + ret = scf_ioc_pciresetreq(arg, mode, rval_p, u_mode); + break; + + default: + SCFDBGMSG(SCF_DBGFLAG_IOCTL, "undefined ioctl command"); + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "ioctl ", 8); + ret = ENOTTY; + break; + } + } else { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "ioctl ", 8); + ret = ENXIO; + } + +/* + * END_ioctl + */ + END_ioctl: + + if (scf_comtbl.resource_flag & DID_MUTEX_ALL) { + /* + * untimeout() processing of the timer which stopped a timer by + * ioctl processing + * Call of driver mutex status is prohibited. + */ + /* Lock driver mutex */ + mutex_enter(&scf_comtbl.all_mutex); + + /* Collect the timers which need to be stopped */ + tm_stop_cnt = scf_timer_stop_collect(save_tmids, + SCF_TIMERCD_MAX); + + /* Unlock driver mutex */ + mutex_exit(&scf_comtbl.all_mutex); + + /* Timer stop */ + if (tm_stop_cnt != 0) { + scf_timer_untimeout(save_tmids, SCF_TIMERCD_MAX); + } + } + + SC_DBG_DRV_TRACE(TC_IOCTL|TC_OUT, __LINE__, &ret, sizeof (int)); + SCFDBGMSG1(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +/* + * scf_ioc_reportstat() + * + * Description: SCFIOCREPORTSTAT ioctl command processing. + * + */ +/* ARGSUSED */ +int +scf_ioc_reportstat(intptr_t arg, int mode, int *rval_p, int u_mode) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_ioc_reportstat() " + int ret = 0; + struct scf_cmd scf_cmd; + scf_short_buffer_t sbuf; + scf_state_t *wk_statep; + + SCFDBGMSG(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": start"); + + bzero((void *)&sbuf.b[0], SCF_S_CNT_16); + switch (arg) { + case SCF_SHUTDOWN_START: + mutex_enter(&scf_comtbl.all_mutex); + + scf_comtbl.shutdown_start_reported = 1; + sbuf.b[0] = REPORT_STAT_SHUTDOWN_START; + sbuf.b[1] = scf_poff_factor[scf_comtbl.poff_factor][0]; + sbuf.b[2] = scf_poff_factor[scf_comtbl.poff_factor][1]; + sbuf.b[3] = scf_poff_factor[scf_comtbl.poff_factor][2]; + break; + + case SCF_SYSTEM_RUNNING: + mutex_enter(&scf_comtbl.all_mutex); + + sbuf.b[0] = REPORT_STAT_SYSTEM_RUNNING; + sbuf.b[1] = 0; + sbuf.b[2] = 0; + sbuf.b[3] = 0; + break; + + default: + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "ioctl ", 8); + ret = EINVAL; + goto END_reportstat; + } + + if ((scf_comtbl.scf_report_event_sub == EVENT_SUB_REPORT_RUN_WAIT) || + (scf_comtbl.scf_report_event_sub == + EVENT_SUB_REPORT_SHUT_WAIT)) { + scf_comtbl.scf_report_event_sub = EVENT_SUB_NONE; + } + + scf_cmd.cmd = CMD_REPORT; + scf_cmd.subcmd = SUB_SYSTEM_STATUS_RPT; + scf_cmd.scount = SCF_S_CNT_15; + scf_cmd.sbuf = &sbuf.b[0]; + scf_cmd.rcount = 0; + scf_cmd.flag = SCF_USE_S_BUF; + scf_comtbl.scf_last_report = arg; + + ret = scf_send_cmd_check_bufful(&scf_cmd); + + if ((ret == EBUSY) && + (scf_cmd.stat0 == SCF_STAT0_NOT_PATH) && + (arg == SCF_SHUTDOWN_START)) { + wk_statep = scf_comtbl.scf_stop_p; + ret = EIO; + if (wk_statep != NULL) { + scf_del_queue(wk_statep); + /* Interrupt enable */ + scf_permit_intr(wk_statep, 1); + scf_chg_scf(wk_statep, PATH_STAT_ACTIVE); + scf_comtbl.scf_exec_p = wk_statep; + /* SCF command send sync stop */ + ret = scf_make_send_cmd(&scf_cmd, SCF_USE_STOP); + if (ret == 0) { + /* new report shutdown */ + scf_cmd.subcmd = SUB_SYSTEM_STATUS_RPT_NOPATH; + scf_cmd.flag = (SCF_USE_S_BUF | SCF_USE_SP); + ret = scf_send_cmd_check_bufful(&scf_cmd); + if (ret == 0) { + /* + * SCF command send sync re-stop + */ + ret = scf_make_send_cmd(&scf_cmd, + SCF_USE_STOP); + } + } + /* FIOMPSTART exec status */ + if ((wk_statep == scf_comtbl.scf_exec_p) || + (wk_statep == scf_comtbl.scf_path_p)) { + if (scf_comtbl.watchdog_after_resume) { + /* + * Alive check status recovery + */ + scf_comtbl.alive_running = + SCF_ALIVE_START; + scf_comtbl.watchdog_after_resume = 0; + } + scf_chg_scf(wk_statep, PATH_STAT_ACTIVE); + /* SCF path change send */ + scf_comtbl.scf_exec_p = 0; + scf_comtbl.scf_path_p = 0; + scf_comtbl.scf_pchg_event_sub = + EVENT_SUB_PCHG_WAIT; + scf_next_cmd_check(wk_statep); + } + /* SCF command send sync start */ + (void) scf_make_send_cmd(&scf_cmd, SCF_USE_START); + } + } + + mutex_exit(&scf_comtbl.all_mutex); + +/* + * END_reportstat + */ + END_reportstat: + + SCFDBGMSG1(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +/* + * scf_ioc_clearlcd() + * + * Description: SCFIOCCLEARLCD ioctl command processing. + * + */ +/* ARGSUSED */ +int +scf_ioc_clearlcd(intptr_t arg, int mode, int *rval_p, int u_mode) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_ioc_clearlcd() " + int ret = 0; + struct scf_cmd scf_cmd; + scf_short_buffer_t sbuf; + int ii; + + SCFDBGMSG(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": start"); + + scf_cmd.cmd = CMD_PHASE; + scf_cmd.rcount = 0; + scf_cmd.flag = SCF_USE_L_BUF; + + switch (arg) { + case SCF_CLRLCD_SEQ: + scf_cmd.subcmd = SUB_PHASE_PRINT; + scf_cmd.scount = 1; + scf_cmd.sbuf = &sbuf.b[0]; + + mutex_enter(&scf_comtbl.all_mutex); + + for (ii = 0; ii < SCF_WRLCD_MAX; ii++) { + scf_comtbl.lcd_seq_mes[ii] = '\0'; + sbuf.b[ii] = '\0'; + } + + ret = scf_send_cmd_check_bufful(&scf_cmd); + + mutex_exit(&scf_comtbl.all_mutex); + break; + + default: + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "ioctl ", 8); + ret = EINVAL; + break; + } + + SCFDBGMSG1(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +/* + * scf_ioc_wrlcd() + * + * Description: SCFIOCWRLCD ioctl command processing. + * + */ +/* ARGSUSED */ +int +scf_ioc_wrlcd(intptr_t arg, int mode, int *rval_p, int u_mode) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_ioc_wrlcd() " + int ret = 0; + struct scf_cmd scf_cmd; + scf_short_buffer_t sbuf; + scfwrlcd_t scfwrlcd; + scfwrlcd32_t scfwrlcd32; + int ii; + + SCFDBGMSG(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": start"); + + if (u_mode == DDI_MODEL_ILP32) { + /* DDI_MODEL_ILP32 */ + if (ddi_copyin((void *)arg, (void *)&scfwrlcd32, + sizeof (scfwrlcd32_t), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "ioctl ", 8); + ret = EFAULT; + goto END_wrlcd; + } + scfwrlcd.lcd_type = scfwrlcd32.lcd_type; + scfwrlcd.length = scfwrlcd32.length; + scfwrlcd.string = (unsigned char *)(uintptr_t)scfwrlcd32.string; + } else { + /* DDI_MODEL_NONE */ + if (ddi_copyin((void *)arg, (void *)&scfwrlcd, + sizeof (scfwrlcd_t), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "ioctl ", 8); + ret = EFAULT; + goto END_wrlcd; + } + } + + if (scfwrlcd.length < 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "ioctl ", 8); + ret = EINVAL; + goto END_wrlcd; + } + if (scfwrlcd.length > SCF_WRLCD_MAX) { + scfwrlcd.length = SCF_WRLCD_MAX; + } + for (ii = 0; ii < SCF_WRLCD_MAX + 1; ii++) { + sbuf.b[ii] = '\0'; + } + sbuf.b[scfwrlcd.length] = '\0'; + + if (ddi_copyin((void *)scfwrlcd.string, (void *)&sbuf.b[0], + (size_t)scfwrlcd.length, mode)) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "ioctl ", 8); + ret = EFAULT; + goto END_wrlcd; + } + + scf_cmd.cmd = CMD_PHASE; + scf_cmd.scount = scfwrlcd.length + 1; + scf_cmd.sbuf = &sbuf.b[0]; + scf_cmd.rcount = 0; + scf_cmd.flag = SCF_USE_L_BUF; + + switch (scfwrlcd.lcd_type) { + case SCF_WRLCD_SEQ: + scf_cmd.subcmd = SUB_PHASE_PRINT; + + mutex_enter(&scf_comtbl.all_mutex); + bcopy((void *)&sbuf.b[0], (void *)&scf_comtbl.lcd_seq_mes[0], + SCF_WRLCD_MAX); + + ret = scf_send_cmd_check_bufful(&scf_cmd); + + mutex_exit(&scf_comtbl.all_mutex); + break; + + default: + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "ioctl ", 8); + ret = EINVAL; + break; + } + +/* + * END_wrlcd + */ + END_wrlcd: + + SCFDBGMSG1(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +/* + * scf_ioc_getdiskled() + * + * Description: SCFIOCGETDISKLED ioctl command processing. + * + */ +/* ARGSUSED */ +int +scf_ioc_getdiskled(intptr_t arg, int mode, int *rval_p, int u_mode) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_ioc_getdiskled() " + int ret = 0; + struct scf_cmd scf_cmd; + scf_short_buffer_t rbuf; + scfiocgetdiskled_t *scfiocgetdiskled_p = NULL; + + SCFDBGMSG(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": start"); + + scfiocgetdiskled_p = kmem_zalloc((size_t)(sizeof (scfiocgetdiskled_t)), + KM_SLEEP); + + if (ddi_copyin((void *)arg, (void *)scfiocgetdiskled_p, + sizeof (scfiocgetdiskled_t), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "ioctl ", 8); + ret = EFAULT; + goto END_getdiskled; + } + + scf_cmd.cmd = CMD_DOMAIN_INFO; + scf_cmd.subcmd = SUB_DISK_LED_DISP; + scf_cmd.sbuf = &scfiocgetdiskled_p->path[0]; + scf_cmd.scount = SCF_DISK_LED_PATH_MAX; + scf_cmd.rbuf = &rbuf.b[0]; + scf_cmd.rcount = SCF_S_CNT_15; + scf_cmd.flag = SCF_USE_LSBUF; + + mutex_enter(&scf_comtbl.all_mutex); + + ret = scf_send_cmd_check_bufful(&scf_cmd); + + mutex_exit(&scf_comtbl.all_mutex); + + if (ret == 0) { + scfiocgetdiskled_p->led = rbuf.b[0]; + + if (ddi_copyout((void *)scfiocgetdiskled_p, (void *)arg, + sizeof (scfiocgetdiskled_t), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "ioctl ", 8); + ret = EFAULT; + } + } + +/* + * END_getdiskled + */ + END_getdiskled: + + if (scfiocgetdiskled_p) { + kmem_free((void *)scfiocgetdiskled_p, + (size_t)(sizeof (scfiocgetdiskled_t))); + } + + SCFDBGMSG1(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +/* + * scf_ioc_setdiskled() + * + * Description: SCFIOCSETDISKLED ioctl command processing. + * + */ +/* ARGSUSED */ +int +scf_ioc_setdiskled(intptr_t arg, int mode, int *rval_p, int u_mode) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_ioc_setdiskled() " + int ret = 0; + struct scf_cmd scf_cmd; + scfiocgetdiskled_t *scfiocgetdiskled_p = NULL; + + SCFDBGMSG(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": start"); + + scfiocgetdiskled_p = kmem_zalloc((size_t)(sizeof (scfiocgetdiskled_t)), + KM_SLEEP); + + if (ddi_copyin((void *)arg, (void *)scfiocgetdiskled_p, + sizeof (scfiocgetdiskled_t), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "ioctl ", 8); + ret = EFAULT; + goto END_setdiskled; + } + + switch (scfiocgetdiskled_p->led) { + case SCF_DISK_LED_ON: + scf_cmd.subcmd = SUB_DISK_LED_ON; + break; + + case SCF_DISK_LED_BLINK: + scf_cmd.subcmd = SUB_DISK_LED_BLINK; + break; + + case SCF_DISK_LED_OFF: + scf_cmd.subcmd = SUB_DISK_LED_OFF; + break; + + default: + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "ioctl ", 8); + ret = EINVAL; + goto END_setdiskled; + } + + scf_cmd.cmd = CMD_DOMAIN_INFO; + scf_cmd.sbuf = &scfiocgetdiskled_p->path[0]; + scf_cmd.scount = SCF_DISK_LED_PATH_MAX; + scf_cmd.rcount = 0; + scf_cmd.flag = SCF_USE_L_BUF; + + mutex_enter(&scf_comtbl.all_mutex); + + ret = scf_send_cmd_check_bufful(&scf_cmd); + + mutex_exit(&scf_comtbl.all_mutex); + +/* + * END_setdiskled + */ + END_setdiskled: + + if (scfiocgetdiskled_p) { + kmem_free((void *)scfiocgetdiskled_p, + (size_t)(sizeof (scfiocgetdiskled_t))); + } + + SCFDBGMSG1(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +/* + * scf_ioc_getsdownreason() + * + * Description: SCFIOCGETSDOWNREASON ioctl command processing. + * + */ +/* ARGSUSED */ +int +scf_ioc_getsdownreason(intptr_t arg, int mode, int *rval_p, int u_mode) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_ioc_getsdownreason() " + int ret = 0; + + SCFDBGMSG(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": start"); + + if (ddi_copyout((void *)&scf_comtbl.scf_shutdownreason, + (void *)arg, sizeof (int), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "ioctl ", 8); + ret = EFAULT; + } + + SCFDBGMSG1(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +/* + * scf_ioc_optiondisp() + * + * Description: SCFIOCOPTIONDISP ioctl command processing. + * + */ +/* ARGSUSED */ +int +scf_ioc_optiondisp(intptr_t arg, int mode, int *rval_p, int u_mode) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_ioc_optiondisp() " + int ret = 0; + struct scf_cmd scf_cmd; + scfoption_t scfoption; + + SCFDBGMSG(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": start"); + + bzero((void *)&scfoption, sizeof (scfoption_t)); + + scf_cmd.cmd = CMD_DOMAIN_INFO; + scf_cmd.subcmd = SUB_OPTION_DISP; + scf_cmd.sbuf = 0; + scf_cmd.scount = 0; + scf_cmd.rbuf = &scfoption.rbuf[0]; + scf_cmd.rcount = SCF_S_CNT_15; + scf_cmd.flag = SCF_USE_SSBUF; + + mutex_enter(&scf_comtbl.all_mutex); + + ret = scf_send_cmd_check_bufful(&scf_cmd); + + mutex_exit(&scf_comtbl.all_mutex); + + if (ret == 0) { + if (ddi_copyout((void *)&scfoption, (void *)arg, + sizeof (scfoption_t), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "ioctl ", 8); + ret = EFAULT; + } + } + + SCFDBGMSG1(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +/* + * scf_ioc_getpciconfig() + * + * Description: SCFIOCGETPCICONFIG ioctl command processing. + * + */ +/* ARGSUSED */ +int +scf_ioc_getpciconfig(intptr_t arg, int mode, int *rval_p, int u_mode) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_ioc_getpciconfig() " + int ret = 0; + struct scf_cmd scf_cmd; + scfiocgetpciconfig_t *scfiocgetpciconfig_p = NULL; + + SCFDBGMSG(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": start"); + + scfiocgetpciconfig_p = + kmem_zalloc((size_t)(sizeof (scfiocgetpciconfig_t)), KM_SLEEP); + + if (ddi_copyin((void *)arg, (void *)scfiocgetpciconfig_p, + sizeof (scfiocgetpciconfig_t), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "ioctl ", 8); + ret = EFAULT; + goto END_getpciconfig; + } + + scf_cmd.cmd = CMD_DOMAIN_INFO; + scf_cmd.subcmd = SUB_PCI_DISP; + scf_cmd.sbuf = &scfiocgetpciconfig_p->sbuf[0]; + scf_cmd.scount = SCF_S_CNT_15; + scf_cmd.rbuf = &scfiocgetpciconfig_p->rbuf[0]; + scf_cmd.rcount = SCF_L_CNT_MAX; + scf_cmd.flag = SCF_USE_SLBUF; + + mutex_enter(&scf_comtbl.all_mutex); + + ret = scf_send_cmd_check_bufful(&scf_cmd); + + mutex_exit(&scf_comtbl.all_mutex); + + if (ret == 0) { + if (ddi_copyout((void *)scfiocgetpciconfig_p, + (void *)arg, sizeof (scfiocgetpciconfig_t), + mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "ioctl ", 8); + ret = EFAULT; + } + } + +/* + * END_getpciconfig + */ + END_getpciconfig: + + if (scfiocgetpciconfig_p) { + kmem_free((void *)scfiocgetpciconfig_p, + (size_t)(sizeof (scfiocgetpciconfig_t))); + } + + SCFDBGMSG1(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +/* + * scf_ioc_hac() + * + * Description: SCFIOCHAC ioctl command processing. + * + */ +/* ARGSUSED */ +int +scf_ioc_hac(intptr_t arg, int mode, int *rval_p, int u_mode) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_ioc_hac() " + int ret = 0; + struct scf_cmd scf_cmd; + scf_short_buffer_t sbuf; + scfhac_t scfhac; + + SCFDBGMSG(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": start"); + + if (ddi_copyin((void *)arg, (void *)&scfhac, + sizeof (scfhac_t), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "ioctl ", 8); + ret = EFAULT; + goto END_hac; + } + + if (scfhac.sub_command == SUB_HOSTADDR_DISP2) { + mutex_enter(&scf_comtbl.all_mutex); + if (scf_save_hac_flag != 0) { + mutex_exit(&scf_comtbl.all_mutex); + if (ddi_copyout((void *)&scf_save_hac, (void *)arg, + sizeof (scfhac_t), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "ioctl ", 8); + ret = EFAULT; + } + goto END_hac; + } else { + mutex_exit(&scf_comtbl.all_mutex); + } + scfhac.sub_command = SUB_HOSTADDR_DISP; + } + scf_cmd.cmd = CMD_RCI_CTL; + scf_cmd.subcmd = scfhac.sub_command; + scf_cmd.sbuf = &scfhac.sbuf[0]; + scf_cmd.scount = SCF_S_CNT_15; + scf_cmd.rbuf = &scfhac.rbuf[0]; + scf_cmd.rcount = SCF_S_CNT_15; + + switch (scfhac.sub_command) { + case SUB_REMOTE_POWCTL_SET: + scf_cmd.flag = SCF_USE_S_BUF; + break; + + case SCF_SUB_REMOTE_POWCTL_SET: + bzero((void *)&sbuf.b[0], SCF_S_CNT_16); + sbuf.b[0] = scfhac.sbuf[6]; + sbuf.b[1] = scfhac.sbuf[7]; + scf_cmd.sbuf = &sbuf.b[0]; + scf_cmd.subcmd = SUB_REMOTE_POWCTL_SET; + scf_cmd.flag = SCF_USE_S_BUF; + break; + + case SUB_HOSTADDR_DISP: + case SUB_DEVICE_INFO: + scf_cmd.flag = SCF_USE_SSBUF; + break; + + default: + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "ioctl ", 8); + ret = EINVAL; + goto END_hac; + } + + mutex_enter(&scf_comtbl.all_mutex); + + ret = scf_send_cmd_check_bufful(&scf_cmd); + + if (ret == 0) { + if (scfhac.sub_command == SUB_HOSTADDR_DISP) { + bcopy((void *)&scfhac, (void *)&scf_save_hac, + sizeof (scfhac_t)); + scf_save_hac_flag = 1; + } + + mutex_exit(&scf_comtbl.all_mutex); + + if (ddi_copyout((void *)&scfhac, (void *)arg, sizeof (scfhac_t), + mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "ioctl ", 8); + ret = EFAULT; + } + } else { + mutex_exit(&scf_comtbl.all_mutex); + } + +/* + * END_hac + */ + END_hac: + + SCFDBGMSG1(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +/* + * scf_ioc_hstadrsinfo() + * + * Description: SCFIOCHSTADRSINFO ioctl command processing. + * + */ +/* ARGSUSED */ +int +scf_ioc_hstadrsinfo(intptr_t arg, int mode, int *rval_p, int u_mode) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_ioc_hstadrsinfo() " + int ret = 0; + struct scf_cmd scf_cmd; + scf_short_buffer_t rbuf; + + SCFDBGMSG(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": start"); + + scf_cmd.cmd = CMD_RCI_CTL; + scf_cmd.subcmd = SUB_HOSTADDR_DISP; + scf_cmd.scount = 0; + scf_cmd.rbuf = &rbuf.b[0]; + scf_cmd.rcount = SCF_S_CNT_12; + scf_cmd.flag = SCF_USE_SSBUF; + + mutex_enter(&scf_comtbl.all_mutex); + + ret = scf_send_cmd_check_bufful(&scf_cmd); + + if (ret == 0) { + bcopy((void *)&rbuf.b[0], (void *)&scf_save_hac.rbuf[0], + SCF_S_CNT_12); + scf_save_hac_flag = 1; + + mutex_exit(&scf_comtbl.all_mutex); + + if (ddi_copyout((void *)&rbuf.b[0], (void *)arg, SCF_S_CNT_12, + mode) < 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "ioctl ", 8); + ret = EFAULT; + } + } else { + mutex_exit(&scf_comtbl.all_mutex); + } + + SCFDBGMSG1(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +/* + * scf_ioc_rdclistmax() + * + * Description: SCFIOCRDCLISTMAX ioctl command processing. + * + */ +/* ARGSUSED */ +int +scf_ioc_rdclistmax(intptr_t arg, int mode, int *rval_p, int u_mode) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_ioc_rdclistmax() " + int ret = 0; + int scfrdclistmax; + + SCFDBGMSG(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": start"); + + scfrdclistmax = (scf_rci_max * SCF_DEVLIST_MAXCNT); + + if (ddi_copyout((void *)&scfrdclistmax, (void *)arg, sizeof (int), + mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "ioctl ", 8); + ret = EFAULT; + } + + SCFDBGMSG1(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +/* + * scf_ioc_rdclistx() + * + * Description: SCFIOCRDCLISTX ioctl command processing. + * + */ +/* ARGSUSED */ +int +scf_ioc_rdclistx(intptr_t arg, int mode, int *rval_p, int u_mode) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_ioc_rdclistx() " + int ret = 0; + struct scf_cmd scf_cmd; + scf_short_buffer_t sbuf; + scfrdclistx_t *rdclistxp = NULL; + scfrdclistx_t *rdclistxp_wk = NULL; + union wk_buffer { + uchar_t b[8]; + uint_t four_bytes_access[2]; + } *rbuf_wk; + int ii; + int jj; + + SCFDBGMSG(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": start"); + + mutex_enter(&scf_comtbl.all_mutex); + + rdclistxp = + (scfrdclistx_t *)kmem_zalloc((size_t)(sizeof (scfrdclistx_t) * + scf_rci_max * SCF_DEVLIST_MAXCNT), KM_SLEEP); + rdclistxp_wk = + (scfrdclistx_t *)kmem_zalloc((size_t)(sizeof (scfrdclistx_t) * + scf_rci_max), KM_SLEEP); + + bzero((void *)&sbuf.b[0], SCF_S_CNT_16); + + /* set device class */ + sbuf.four_bytes_access[0] = 0x00000fff; + sbuf.b[4] = 0; /* 0 system */ + + scf_cmd.cmd = CMD_RCI_CTL; + scf_cmd.subcmd = SUB_DEVICE_LIST; + scf_cmd.scount = SCF_S_CNT_15; + scf_cmd.sbuf = &sbuf.b[0]; + scf_cmd.rcount = scf_rci_max * SCF_DEVLIST_ENTSIZE; + scf_cmd.rbuf = (uchar_t *)rdclistxp_wk; + scf_cmd.flag = SCF_USE_SLBUF; + + ret = scf_send_cmd_check_bufful(&scf_cmd); + + if (ret != 0) { + mutex_exit(&scf_comtbl.all_mutex); + goto END_rdclistx; + } + + rbuf_wk = (union wk_buffer *)rdclistxp_wk; + for (jj = 0; jj < (scf_cmd.rbufleng / SCF_DEVLIST_ENTSIZE); + jj++) { + if (rbuf_wk->four_bytes_access[0] == NULL) { + break; + } + rdclistxp[jj].rci_addr = rbuf_wk->four_bytes_access[0]; + rdclistxp[jj].status = rbuf_wk->b[4]; + rdclistxp[jj].dev_class = + ((ushort_t)rbuf_wk->b[5] << 8) + + (ushort_t)rbuf_wk->b[6]; + rdclistxp[jj].sub_class = rbuf_wk->b[7]; + rbuf_wk++; + } + + /* set device class */ + sbuf.four_bytes_access[0] = 0x00000fff; + sbuf.b[4] = 1; /* 1 system */ + + scf_cmd.cmd = CMD_RCI_CTL; + scf_cmd.subcmd = SUB_DEVICE_LIST; + scf_cmd.scount = SCF_S_CNT_15; + scf_cmd.sbuf = &sbuf.b[0]; + scf_cmd.rcount = scf_rci_max * SCF_DEVLIST_ENTSIZE; + scf_cmd.rbuf = (uchar_t *)rdclistxp_wk; + scf_cmd.flag = SCF_USE_SLBUF; + + ret = scf_send_cmd_check_bufful(&scf_cmd); + + if (ret != 0) { + mutex_exit(&scf_comtbl.all_mutex); + goto END_rdclistx; + } + + mutex_exit(&scf_comtbl.all_mutex); + + rbuf_wk = (union wk_buffer *)rdclistxp_wk; + for (ii = 0; ii < (scf_cmd.rbufleng / SCF_DEVLIST_ENTSIZE); ii++) { + if (rbuf_wk->four_bytes_access[0] == NULL) { + break; + } + rdclistxp[ii + jj].rci_addr = rbuf_wk->four_bytes_access[0]; + rdclistxp[ii + jj].status = rbuf_wk->b[4]; + rdclistxp[ii + jj].dev_class = + ((ushort_t)rbuf_wk->b[5] << 8) + + (ushort_t)rbuf_wk->b[6]; + rdclistxp[ii + jj].sub_class = rbuf_wk->b[7]; + rbuf_wk++; + } + + /* return number of data */ + *rval_p = (ii + jj); + + if (ii + jj) { + if (ddi_copyout((void *)rdclistxp, (void *)arg, + (size_t)(sizeof (scfrdclistx_t) * (ii + jj)), + mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "ioctl ", 8); + ret = EFAULT; + } + } + +/* + * END_rdclistx + */ + END_rdclistx: + + if (rdclistxp) { + kmem_free((void *)rdclistxp, (size_t)(sizeof (scfrdclistx_t) * + scf_rci_max * SCF_DEVLIST_MAXCNT)); + } + if (rdclistxp_wk) { + kmem_free((void *)rdclistxp_wk, + (size_t)(sizeof (scfrdclistx_t) * scf_rci_max)); + } + + SCFDBGMSG1(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +/* + * scf_ioc_rdctrl() + * + * Description: SCFIOCRDCTRL ioctl command processing. + * + */ +/* ARGSUSED */ +int +scf_ioc_rdctrl(intptr_t arg, int mode, int *rval_p, int u_mode) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_ioc_rdctrl() " + int ret = 0; + struct scf_cmd scf_cmd; + scfrdctrl_t scfrdctrl; + int got_sense = 0; + clock_t lb; + int ii; + + SCFDBGMSG(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": start"); + + if (ddi_copyin((void *)arg, (void *)&scfrdctrl, + sizeof (scfrdctrl_t), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "ioctl ", 8); + ret = EFAULT; + goto END_rdctrl; + } + if ((scfrdctrl.sub_cmd != SUB_DEVICE_STATUS_RPT) && + (scfrdctrl.sub_cmd != SCF_SUB_DEVICE_STATUS_RPT) && + ((scfrdctrl.sub_cmd | SCF_RCI_PATH_PARITY) != + SCF_RCI_PATH_40)) { + /* wrong sub_cmd */ + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "ioctl ", 8); + ret = EINVAL; + goto END_rdctrl; + } + + mutex_enter(&scf_comtbl.all_mutex); + + while (scf_comtbl.rdctrl_busy) { + SC_DBG_DRV_TRACE(TC_W_SIG, __LINE__, &scf_comtbl.rdctrl_cv, + sizeof (kcondvar_t)); + if (cv_wait_sig(&scf_comtbl.rdctrl_cv, + &scf_comtbl.all_mutex) == 0) { + SC_DBG_DRV_TRACE(TC_KILL, __LINE__, + &scf_comtbl.rdctrl_cv, sizeof (kcondvar_t)); + mutex_exit(&scf_comtbl.all_mutex); + ret = EINTR; + goto END_rdctrl; + } + } + scf_comtbl.rdctrl_busy = 1; + + for (ii = scfrdctrl.scount; ii < SCF_S_CNT_32; ii++) { + scfrdctrl.sbuf[ii] = 0; + } + if ((scfrdctrl.sub_cmd == SUB_DEVICE_STATUS_RPT) || + (scfrdctrl.sub_cmd == SCF_SUB_DEVICE_STATUS_RPT)) { + scf_cmd.flag = SCF_USE_S_BUF; + } else { + /* SUB_RCI_PATH_4* */ + scf_cmd.flag = SCF_USE_L_BUF; + /* Parameter size set */ + if (scfrdctrl.scount > 6) { + scfrdctrl.sbuf[5] = (scfrdctrl.scount - 6); + } else { + scfrdctrl.sbuf[5] = 0; + } + } + scf_cmd.cmd = CMD_RCI_CTL; + if (scfrdctrl.sub_cmd == SCF_SUB_DEVICE_STATUS_RPT) { + scf_cmd.subcmd = SUB_DEVICE_STATUS_RPT; + } else if (scfrdctrl.sub_cmd == + (SCF_RCI_PATH_40 & (~SCF_RCI_PATH_PARITY))) { + scf_cmd.subcmd = SCF_RCI_PATH_40; + } else { + scf_cmd.subcmd = scfrdctrl.sub_cmd; + } + scf_comtbl.rdctrl_sense_category_code = 0; + scf_cmd.sbuf = &scfrdctrl.sbuf[0]; + scf_cmd.scount = SCF_S_CNT_32; + scf_cmd.rcount = 0; + ret = scf_send_cmd_check_bufful(&scf_cmd); + + if (ret != 0) { + goto END_rdctrl_signal; + } + + /* wait for sense */ + lb = ddi_get_lbolt(); + while (scf_comtbl.rdctrl_sense_category_code == 0) { + SC_DBG_DRV_TRACE(TC_T_WAIT, __LINE__, &scf_comtbl.rdcsense_cv, + sizeof (kcondvar_t)); + scf_comtbl.rdctrl_end_wait = 1; + if (cv_timedwait(&scf_comtbl.rdcsense_cv, &scf_comtbl.all_mutex, + drv_usectohz(scf_rdctrl_sense_wait) + lb) == (-1)) { + /* time out */ + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "ioctl ", 8); + ret = ENODATA; + goto END_rdctrl_signal; + } + } + + /* check RCI-addr and category code */ + if ((bcmp((void *)&scf_comtbl.rdctrl_sense[0], + (void *)&scfrdctrl.sbuf[0], 4) == 0) && + (((scf_comtbl.rdctrl_sense_category_code) == + (scfrdctrl.sub_cmd & (~SCF_RCI_PATH_PARITY))) || + ((scf_comtbl.rdctrl_sense_category_code == + DEV_SENSE_STATUS_RPT) && + ((scfrdctrl.sub_cmd == SUB_DEVICE_STATUS_RPT) || + (scfrdctrl.sub_cmd == SCF_SUB_DEVICE_STATUS_RPT))))) { + bcopy((void *)&scf_comtbl.rdctrl_sense[0], + (void *)&scfrdctrl.sense[0], 4); + bcopy((void *)&scf_comtbl.rdctrl_sense[8], + (void *)&scfrdctrl.sense[4], (SCF_INT_REASON_SIZE - 4)); + got_sense = 1; + } else { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "ioctl ", 8); + ret = ENODATA; + } + +/* + * END_rdctrl_signal + */ + END_rdctrl_signal: + + scf_comtbl.rdctrl_end_wait = 0; + scf_comtbl.rdctrl_busy = 0; + cv_signal(&scf_comtbl.rdctrl_cv); + SC_DBG_DRV_TRACE(TC_SIGNAL, __LINE__, &scf_comtbl.rdctrl_cv, + sizeof (kcondvar_t)); + mutex_exit(&scf_comtbl.all_mutex); + if (got_sense) { + if (ddi_copyout((void *)&scfrdctrl, (void *)arg, + sizeof (scfrdctrl_t), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "ioctl ", 8); + ret = EFAULT; + } + } + +/* + * END_rdctrl + */ + END_rdctrl: + + SCFDBGMSG1(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +/* + * scf_ioc_opecall() + * + * Description: SCFIOCOPECALL ioctl command processing. + * + */ +/* ARGSUSED */ +int +scf_ioc_opecall(intptr_t arg, int mode, int *rval_p, int u_mode) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_ioc_opecall() " + int ret = 0; + struct scf_cmd scf_cmd; + scfhac_t scfhac; + + SCFDBGMSG(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": start"); + + if (ddi_copyin((void *)arg, (void *)&scfhac, sizeof (scfhac_t), + mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "ioctl ", 8); + ret = EFAULT; + goto END_opecall; + } + + scf_cmd.cmd = CMD_REPORT; + scf_cmd.subcmd = scfhac.sub_command; + scf_cmd.scount = SCF_S_CNT_15; + scf_cmd.sbuf = &scfhac.sbuf[0]; + scf_cmd.rcount = SCF_S_CNT_15; + scf_cmd.rbuf = &scfhac.rbuf[0]; + + switch (scfhac.sub_command) { + case SUB_OPECALL_ON_SET: + case SUB_OPECALL_OFF_SET: + scf_cmd.flag = SCF_USE_S_BUF; + break; + + case SUB_OPECALL_DISP: + scf_cmd.flag = SCF_USE_SSBUF; + break; + + default: + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "ioctl ", 8); + ret = EINVAL; + goto END_opecall; + } + + mutex_enter(&scf_comtbl.all_mutex); + + ret = scf_send_cmd_check_bufful(&scf_cmd); + + mutex_exit(&scf_comtbl.all_mutex); + + if (ret == 0) { + if (ddi_copyout((void *)&scfhac, (void *)arg, sizeof (scfhac_t), + mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "ioctl ", 8); + ret = EFAULT; + } + } + +/* + * END_opecall + */ + END_opecall: + + SCFDBGMSG1(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +/* + * scf_ioc_getreport() + * + * Description: SCFIOCGETREPORT ioctl command processing. + * + */ +/* ARGSUSED */ +int +scf_ioc_getreport(intptr_t arg, int mode, int *rval_p, int u_mode) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_ioc_getreport() " + scfreport_t scfreport; + scfreport32_t scfreport32; + scfreport_t *scfreport_p; + int ret = 0; + int loop_flag = 1; + + SCFDBGMSG(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": start"); + + if (u_mode == DDI_MODEL_ILP32) { + /* DDI_MODEL_ILP32 */ + if (ddi_copyin((void *)arg, (void *)&scfreport32, + sizeof (scfreport32_t), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "ioctl ", 8); + ret = EFAULT; + goto END_getreport; + } + scfreport.flag = scfreport32.flag; + } else { + /* DDI_MODEL_NONE */ + if (ddi_copyin((void *)arg, (void *)&scfreport, + sizeof (scfreport_t), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "ioctl ", 8); + ret = EFAULT; + goto END_getreport; + } + } + + switch (scfreport.flag) { + case GETREPORT_WAIT: + case GETREPORT_WAIT_AND_RCIDWN: + mutex_enter(&scf_comtbl.all_mutex); + + scfreport_p = (scfreport_t *)&scf_comtbl.scfreport_rcidown.flag; + while (loop_flag) { + if (scf_pop_reportsense(&scfreport) == 0) { + break; + } + if ((scfreport.flag == GETREPORT_WAIT_AND_RCIDWN) && + (scf_comtbl.rcidown_event_flag)) { + scfreport.rci_addr = scfreport_p->rci_addr; + scfreport.report_sense[0] = + scfreport_p->report_sense[0]; + scfreport.report_sense[1] = + scfreport_p->report_sense[1]; + scfreport.report_sense[2] = + scfreport_p->report_sense[2]; + scfreport.report_sense[3] = + scfreport_p->report_sense[3]; + scfreport.timestamp = scfreport_p->timestamp; + scf_comtbl.rcidown_event_flag = 0; + break; + } + SC_DBG_DRV_TRACE(TC_W_SIG, __LINE__, + &scf_comtbl.rsense_cv, sizeof (kcondvar_t)); + if (cv_wait_sig(&scf_comtbl.rsense_cv, + &scf_comtbl.all_mutex) == 0) { + SC_DBG_DRV_TRACE(TC_KILL, __LINE__, + &scf_comtbl.rsense_cv, + sizeof (kcondvar_t)); + + mutex_exit(&scf_comtbl.all_mutex); + ret = EINTR; + goto END_getreport; + } + } + + mutex_exit(&scf_comtbl.all_mutex); + break; + + case GETREPORT_NOWAIT: + mutex_enter(&scf_comtbl.all_mutex); + + if (scf_pop_reportsense(&scfreport) < 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "ioctl ", 8); + mutex_exit(&scf_comtbl.all_mutex); + ret = ENODATA; + goto END_getreport; + } + + mutex_exit(&scf_comtbl.all_mutex); + break; + + default: + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "ioctl ", 8); + ret = EINVAL; + goto END_getreport; + } + + if (u_mode == DDI_MODEL_ILP32) { + /* DDI_MODEL_ILP32 */ + if ((scfreport.timestamp < INT32_MIN) || + (scfreport.timestamp > INT32_MAX)) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "ioctl ", 8); + ret = EOVERFLOW; + goto END_getreport; + } + + scfreport32.rci_addr = scfreport.rci_addr; + scfreport32.report_sense[0] = scfreport.report_sense[0]; + scfreport32.report_sense[1] = scfreport.report_sense[1]; + scfreport32.report_sense[2] = scfreport.report_sense[2]; + scfreport32.report_sense[3] = scfreport.report_sense[3]; + scfreport32.timestamp = (time32_t)scfreport.timestamp; + + if (ddi_copyout((void *)&scfreport32, (void *)arg, + sizeof (scfreport32_t), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "ioctl ", 8); + ret = EFAULT; + } + } else { + /* DDI_MODEL_NONE */ + if (ddi_copyout((void *)&scfreport, (void *)arg, + sizeof (scfreport_t), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "ioctl ", 8); + ret = EFAULT; + } + } + +/* + * END_getreport + */ + END_getreport: + + SCFDBGMSG1(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +/* + * scf_ioc_rcipwr() + * + * Description: SCFIOCRCIPWR ioctl command processing. + * + */ +/* ARGSUSED */ +int +scf_ioc_rcipwr(intptr_t arg, int mode, int *rval_p, int u_mode) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_ioc_rcipwr() " + int ret = 0; + struct scf_cmd scf_cmd; + scf_short_buffer_t sbuf; + scf_short_buffer_t rbuf; + scfrcipwr_t scfrcipwr; + + SCFDBGMSG(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": start"); + + if (ddi_copyin((void *)arg, (void *)&scfrcipwr, + sizeof (scfrcipwr_t), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "ioctl ", 8); + ret = EFAULT; + goto END_rcipwr; + } + + scf_cmd.cmd = CMD_RCI_CTL; + scf_cmd.subcmd = SUB_HOSTADDR_DISP; + scf_cmd.scount = 0; + scf_cmd.rbuf = &rbuf.b[0]; + scf_cmd.rcount = SCF_S_CNT_12; + scf_cmd.flag = SCF_USE_SSBUF; + + mutex_enter(&scf_comtbl.all_mutex); + + ret = scf_send_cmd_check_bufful(&scf_cmd); + + if (ret != 0) { + mutex_exit(&scf_comtbl.all_mutex); + goto END_rcipwr; + } + + /* check RCI-address */ + if ((scfrcipwr.rci_addr == rbuf.four_bytes_access[0]) || + (scfrcipwr.rci_addr == SCF_CMD_SYSTEM_ADDR)) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "ioctl ", 8); + mutex_exit(&scf_comtbl.all_mutex); + ret = EINVAL; + goto END_rcipwr; + } + + bzero((void *)&sbuf.b[0], SCF_S_CNT_16); + + switch (scfrcipwr.sub_cmd) { + case RCI_PWR_ON: + scf_cmd.subcmd = SUB_PON; + break; + + case RCI_PWR_OFF: + scf_cmd.subcmd = SUB_FPOFF; + break; + + case RCI_SYS_RESET: + scf_cmd.subcmd = SUB_RESET; + break; + + case RCI_PWR_NOR_OFF: + scf_cmd.subcmd = SUB_POFF; + break; + + default: + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "ioctl ", 8); + mutex_exit(&scf_comtbl.all_mutex); + ret = EINVAL; + goto END_rcipwr; + } + + scf_cmd.cmd = CMD_PART_POW_CTR; + scf_cmd.scount = SCF_S_CNT_15; + sbuf.four_bytes_access[0] = scfrcipwr.rci_addr; + scf_cmd.sbuf = &sbuf.b[0]; + scf_cmd.rcount = 0; + scf_cmd.flag = SCF_USE_S_BUF; + + ret = scf_send_cmd_check_bufful(&scf_cmd); + + mutex_exit(&scf_comtbl.all_mutex); + +/* + * END_rcipwr + */ + END_rcipwr: + + SCFDBGMSG1(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +/* + * scf_ioc_panicreq() + * + * Description: SCFIOCPANICREQ ioctl command processing. + * + */ +/* ARGSUSED */ +int +scf_ioc_panicreq(intptr_t arg, int mode, int *rval_p, int u_mode) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_ioc_panicreq() " + int ret = 0; + struct scf_cmd scf_cmd; + scf_short_buffer_t sbuf; + scf_short_buffer_t rbuf; + + SCFDBGMSG(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": start"); + + scf_cmd.cmd = CMD_RCI_CTL; + scf_cmd.subcmd = SUB_HOSTADDR_DISP; + scf_cmd.scount = 0; + scf_cmd.rbuf = &rbuf.b[0]; + scf_cmd.rcount = SCF_S_CNT_12; + scf_cmd.flag = SCF_USE_SSBUF; + + mutex_enter(&scf_comtbl.all_mutex); + + ret = scf_send_cmd_check_bufful(&scf_cmd); + + if (ret != 0) { + mutex_exit(&scf_comtbl.all_mutex); + goto END_panicreq; + } + + /* check RCI-address */ + if (((uint_t)arg == rbuf.four_bytes_access[0]) || + (arg == SCF_CMD_SYSTEM_ADDR)) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "ioctl ", 8); + mutex_exit(&scf_comtbl.all_mutex); + ret = EINVAL; + goto END_panicreq; + } + + bzero((void *)&sbuf.b[0], SCF_S_CNT_16); + sbuf.four_bytes_access[0] = (unsigned int)arg; + scf_cmd.cmd = CMD_RCI_CTL; + scf_cmd.subcmd = SUB_PANIC; + scf_cmd.scount = SCF_S_CNT_15; + scf_cmd.sbuf = &sbuf.b[0]; + scf_cmd.rcount = 0; + scf_cmd.flag = SCF_USE_S_BUF; + + ret = scf_send_cmd_check_bufful(&scf_cmd); + + mutex_exit(&scf_comtbl.all_mutex); + +/* + * END_panicreq + */ + END_panicreq: + + SCFDBGMSG1(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +/* + * scf_ioc_panicchk() + * + * Description: SCFIOCPANICCHK ioctl command processing. + * + */ +/* ARGSUSED */ +int +scf_ioc_panicchk(intptr_t arg, int mode, int *rval_p, int u_mode) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_ioc_panicchk() " + int ret = 0; + + SCFDBGMSG(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": start"); + + if (ddi_copyout((void *)&scf_panic_exec_flag2, (void *)arg, + sizeof (int), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "ioctl ", 8); + ret = EFAULT; + } + + SCFDBGMSG1(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +/* + * scf_ioc_parmset() + * + * Description: SCFIOCPARMSET ioctl command processing. + * + */ +/* ARGSUSED */ +int +scf_ioc_parmset(intptr_t arg, int mode, int *rval_p, int u_mode) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_ioc_parmset() " + int ret = 0; + scfparam_t scfparam; + + SCFDBGMSG(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": start"); + + if (ddi_copyin((void *)arg, (void *)&scfparam, + sizeof (scfparam_t), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "ioctl ", 8); + ret = EFAULT; + goto END_parmset; + } + + switch (scfparam.parm) { + case SCF_PARM_RDCTRL_TIMER: + if ((scfparam.value >= SCF_SEC2MICRO(1)) && + (scfparam.value <= SCF_SEC2MICRO(120))) { + mutex_enter(&scf_comtbl.all_mutex); + scf_rdctrl_sense_wait = + scfparam.value - (scfparam.value % 500000); + mutex_exit(&scf_comtbl.all_mutex); + } else { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "ioctl ", 8); + ret = EINVAL; + goto END_parmset; + } + break; + + default: + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "ioctl ", 8); + ret = EINVAL; + goto END_parmset; + } + + if (ddi_copyout((void *)&scfparam, (void *)arg, + sizeof (scfparam_t), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "ioctl ", 8); + ret = EFAULT; + } + +/* + * END_parmset + */ + END_parmset: + + SCFDBGMSG1(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +/* + * scf_ioc_parmget() + * + * Description: SCFIOCPARMGET ioctl command processing. + * + */ +/* ARGSUSED */ +int +scf_ioc_parmget(intptr_t arg, int mode, int *rval_p, int u_mode) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_ioc_parmget() " + int ret = 0; + scfparam_t scfparam; + + SCFDBGMSG(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": start"); + + if (ddi_copyin((void *)arg, (void *)&scfparam, + sizeof (scfparam_t), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "ioctl ", 8); + ret = EFAULT; + goto END_parmget; + } + + switch (scfparam.parm) { + case SCF_PARM_RDCTRL_TIMER: + mutex_enter(&scf_comtbl.all_mutex); + scfparam.value = scf_rdctrl_sense_wait; + mutex_exit(&scf_comtbl.all_mutex); + + break; + + default: + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "ioctl ", 8); + ret = EINVAL; + goto END_parmget; + } + + if (ddi_copyout((void *)&scfparam, (void *)arg, + sizeof (scfparam_t), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "ioctl ", 8); + ret = EFAULT; + } + +/* + * END_parmget + */ + END_parmget: + + SCFDBGMSG1(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +/* + * scf_ioc_autopwrset() + * + * Description: SCFIOCAUTOPWRSET ioctl command processing. + * + */ +/* ARGSUSED */ +int +scf_ioc_autopwrset(intptr_t arg, int mode, int *rval_p, int u_mode) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_ioc_autopwrset() " + int ret = 0; + struct scf_cmd scf_cmd; + scf_short_buffer_t sbuf; + scfautopwr_t scfautopwr; + int ii; + int jj; + + SCFDBGMSG(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": start"); + + if (ddi_copyin((void *)arg, (void *)&scfautopwr, + sizeof (scfautopwr_t), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "ioctl ", 8); + ret = EFAULT; + goto END_autopwrset; + } + + if ((scfautopwr.valid_entries < 0) || (scfautopwr.valid_entries > 5)) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "ioctl ", 8); + ret = EINVAL; + goto END_autopwrset; + } + + bzero((void *)&sbuf.b[0], 5 * SCF_S_CNT_16); + + for (ii = 0, jj = 0; ii < scfautopwr.valid_entries; ii++, + jj = ii * SCF_S_CNT_16) { + /* check pon time */ + if (scf_check_pon_time(&scfautopwr.ptime[ii]) < 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "ioctl ", 8); + ret = EINVAL; + goto END_autopwrset; + } + + if (scf_check_poff_time(&scfautopwr.ptime[ii]) < 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "ioctl ", 8); + ret = EINVAL; + goto END_autopwrset; + } + + sbuf.b[jj] = (uchar_t)(scfautopwr.ptime[ii].pon_year >> 8); + sbuf.b[jj + 1] = (uchar_t)scfautopwr.ptime[ii].pon_year; + sbuf.b[jj + 2] = (uchar_t)scfautopwr.ptime[ii].pon_month; + sbuf.b[jj + 3] = (uchar_t)scfautopwr.ptime[ii].pon_date; + sbuf.b[jj + 4] = (uchar_t)scfautopwr.ptime[ii].pon_hour; + sbuf.b[jj + 5] = (uchar_t)scfautopwr.ptime[ii].pon_minute; + sbuf.b[jj + 6] = 0; + sbuf.b[jj + 7] = 0; + + sbuf.b[jj + 8] = (uchar_t)(scfautopwr.ptime[ii].poff_year >> 8); + sbuf.b[jj + 9] = (uchar_t)scfautopwr.ptime[ii].poff_year; + sbuf.b[jj + 10] = (uchar_t)scfautopwr.ptime[ii].poff_month; + sbuf.b[jj + 11] = (uchar_t)scfautopwr.ptime[ii].poff_date; + sbuf.b[jj + 12] = (uchar_t)scfautopwr.ptime[ii].poff_hour; + sbuf.b[jj + 13] = (uchar_t)scfautopwr.ptime[ii].poff_minute; + sbuf.b[jj + 14] = 0; + sbuf.b[jj + 15] = 0; + } + + scf_cmd.cmd = CMD_SYS_AUTOPOW; + scf_cmd.subcmd = SUB_SYS_AUTO_ONOFF_SET; + scf_cmd.scount = 5 * SCF_S_CNT_16; + scf_cmd.sbuf = &sbuf.b[0]; + scf_cmd.rcount = 0; + scf_cmd.flag = SCF_USE_L_BUF; + + mutex_enter(&scf_comtbl.all_mutex); + + ret = scf_send_cmd_check_bufful(&scf_cmd); + + mutex_exit(&scf_comtbl.all_mutex); + +/* + * END_autopwrset + */ + END_autopwrset: + + SCFDBGMSG1(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +/* + * scf_ioc_autopwrget() + * + * Description: SCFIOCAUTOPWRGET or SCFIOCSYSAUTOPWRGET + * ioctl command processing. + * + */ +/* ARGSUSED */ +int +scf_ioc_autopwrget(intptr_t arg, int mode, int *rval_p, int u_mode) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_ioc_autopwrget() " + int ret = 0; + struct scf_cmd scf_cmd; + scf_short_buffer_t rbuf; + scfautopwr_t scfautopwr; + int ii; + int jj; + + SCFDBGMSG(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": start"); + + bzero((void *)&scfautopwr, sizeof (scfautopwr_t)); + + scf_cmd.cmd = CMD_SYS_AUTOPOW; + scf_cmd.subcmd = SUB_SYS_AUTO_ONOFF_DISP; + scf_cmd.scount = 0; + scf_cmd.rbuf = &rbuf.b[0]; + scf_cmd.rcount = 5 * SCF_S_CNT_16; + scf_cmd.flag = SCF_USE_SLBUF; + + mutex_enter(&scf_comtbl.all_mutex); + + ret = scf_send_cmd_check_bufful(&scf_cmd); + + mutex_exit(&scf_comtbl.all_mutex); + + if (ret != 0) { + goto END_autopwrget; + } + + for (ii = 0, jj = 0; ii < (scf_cmd.rbufleng / SCF_S_CNT_16); + ii++, jj = ii * SCF_S_CNT_16) { + scfautopwr.ptime[ii].pon_year = + (int)(rbuf.b[jj] << 8) | (int)rbuf.b[jj + 1]; + scfautopwr.ptime[ii].pon_month = (int)rbuf.b[jj + 2]; + scfautopwr.ptime[ii].pon_date = (int)rbuf.b[jj + 3]; + scfautopwr.ptime[ii].pon_hour = (int)rbuf.b[jj + 4]; + scfautopwr.ptime[ii].pon_minute = (int)rbuf.b[jj + 5]; + + scfautopwr.ptime[ii].poff_year = + (int)(rbuf.b[jj + 8] << 8) | (int)rbuf.b[jj + 9]; + scfautopwr.ptime[ii].poff_month = (int)rbuf.b[jj + 10]; + scfautopwr.ptime[ii].poff_date = (int)rbuf.b[jj + 11]; + scfautopwr.ptime[ii].poff_hour = (int)rbuf.b[jj + 12]; + scfautopwr.ptime[ii].poff_minute = (int)rbuf.b[jj + 13]; + } + scfautopwr.valid_entries = 5; + + if (ddi_copyout((void *)&scfautopwr, (void *)arg, + sizeof (scfautopwr_t), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "ioctl ", 8); + ret = EFAULT; + } + +/* + * END_autopwrget + */ + END_autopwrget: + + SCFDBGMSG1(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +/* + * scf_ioc_autopwrclr() + * + * Description: SCFIOCSYSAUTOPWRCLR ioctl command processing. + * + */ +/* ARGSUSED */ +int +scf_ioc_autopwrclr(intptr_t arg, int mode, int *rval_p, int u_mode) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_ioc_autopwrclr() " + int ret = 0; + struct scf_cmd scf_cmd; + + SCFDBGMSG(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": start"); + + scf_cmd.cmd = CMD_SYS_AUTOPOW; + scf_cmd.subcmd = SUB_SYS_AUTO_ONOFF_CLRAR; + scf_cmd.scount = 0; + scf_cmd.rcount = 0; + scf_cmd.flag = SCF_USE_S_BUF; + + mutex_enter(&scf_comtbl.all_mutex); + + ret = scf_send_cmd_check_bufful(&scf_cmd); + + mutex_exit(&scf_comtbl.all_mutex); + + SCFDBGMSG1(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +/* + * scf_ioc_autopwrfpoff() + * + * Description: SCFIOCAUTOPWRFPOFF ioctl command processing. + * + */ +/* ARGSUSED */ +int +scf_ioc_autopwrfpoff(intptr_t arg, int mode, int *rval_p, int u_mode) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_ioc_autopwrfpoff() " + int ret = 0; + struct scf_cmd scf_cmd; + scf_short_buffer_t sbuf; + scfautopwrtime_t scfautopwrtime; + + SCFDBGMSG(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": start"); + + if (ddi_copyin((void *)arg, (void *)&scfautopwrtime, + sizeof (scfautopwrtime_t), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "ioctl ", 8); + ret = EFAULT; + goto END_autopwrfpoff; + } + bzero((void *)&sbuf.b[0], 5 * SCF_S_CNT_16); + if (scf_check_poff_time(&scfautopwrtime) < 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "ioctl ", 8); + ret = EINVAL; + goto END_autopwrfpoff; + } + sbuf.b[0] = (uchar_t)(scfautopwrtime.poff_year >> 8); + sbuf.b[1] = (uchar_t)scfautopwrtime.poff_year; + sbuf.b[2] = (uchar_t)scfautopwrtime.poff_month; + sbuf.b[3] = (uchar_t)scfautopwrtime.poff_date; + sbuf.b[4] = (uchar_t)scfautopwrtime.poff_hour; + sbuf.b[5] = (uchar_t)scfautopwrtime.poff_minute; + + scf_cmd.cmd = CMD_SYS_AUTOPOW; + scf_cmd.subcmd = SUB_FORCED_POFF_SET; + scf_cmd.scount = SCF_S_CNT_15; + scf_cmd.sbuf = &sbuf.b[0]; + scf_cmd.rcount = 0; + scf_cmd.flag = SCF_USE_S_BUF; + + mutex_enter(&scf_comtbl.all_mutex); + + ret = scf_send_cmd_check_bufful(&scf_cmd); + + mutex_exit(&scf_comtbl.all_mutex); + +/* + * END_autopwrfpoff + */ + END_autopwrfpoff: + + SCFDBGMSG1(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +/* + * scf_ioc_autopwrexset() + * + * Description: SCFIOCAUTOPWREXSET ioctl command processing. + * + */ +/* ARGSUSED */ +int +scf_ioc_autopwrexset(intptr_t arg, int mode, int *rval_p, int u_mode) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_ioc_autopwrexset() " + int ret = 0; + struct scf_cmd scf_cmd; + scf_short_buffer_t sbuf; + scfautopwrex_t scfautopwrex; + + SCFDBGMSG(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": start"); + + bzero((void *)&sbuf.b[0], SCF_S_CNT_16); + if (ddi_copyin((void *)arg, (void *)&scfautopwrex, + sizeof (scfautopwrex_t), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "ioctl ", 8); + ret = EFAULT; + goto END_autopwrexset; + } + + switch (scfautopwrex.rpwr_mode) { + case AUTOPWREX_RESTORE: + case AUTOPWREX_NOPON: + case AUTOPWREX_AUTOPON: + break; + + default: + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "ioctl ", 8); + ret = EINVAL; + goto END_autopwrexset; + } + + scf_cmd.cmd = CMD_SYS_AUTOPOW; + scf_cmd.subcmd = SUB_PRESET_MODE_SET; + scf_cmd.scount = SCF_S_CNT_15; + sbuf.b[0] = (unsigned char)scfautopwrex.rpwr_mode; + scf_cmd.sbuf = &sbuf.b[0]; + scf_cmd.rcount = 0; + scf_cmd.flag = SCF_USE_S_BUF; + + mutex_enter(&scf_comtbl.all_mutex); + + ret = scf_send_cmd_check_bufful(&scf_cmd); + + mutex_exit(&scf_comtbl.all_mutex); + +/* + * END_autopwrexset + */ + END_autopwrexset: + + SCFDBGMSG1(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +/* + * scf_ioc_autopwrexget() + * + * Description: SCFIOCAUTOPWREXGET ioctl command processing. + * + */ +/* ARGSUSED */ +int +scf_ioc_autopwrexget(intptr_t arg, int mode, int *rval_p, int u_mode) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_ioc_autopwrexget() " + int ret = 0; + struct scf_cmd scf_cmd; + scf_short_buffer_t rbuf; + scfautopwrex_t scfautopwrex; + + SCFDBGMSG(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": start"); + + bzero((void *)&scfautopwrex, sizeof (scfautopwrex_t)); + + scf_cmd.cmd = CMD_SYS_AUTOPOW; + scf_cmd.subcmd = SUB_PRESET_MODE_DISP; + scf_cmd.scount = 0; + scf_cmd.rcount = SCF_S_CNT_15; + scf_cmd.rbuf = &rbuf.b[0]; + scf_cmd.flag = SCF_USE_SSBUF; + + mutex_enter(&scf_comtbl.all_mutex); + + ret = scf_send_cmd_check_bufful(&scf_cmd); + + mutex_exit(&scf_comtbl.all_mutex); + + if (ret == 0) { + scfautopwrex.rpwr_mode = (int)rbuf.b[0]; + + if (ddi_copyout((void *)&scfautopwrex, (void *)arg, + sizeof (scfautopwrex_t), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "ioctl ", 8); + ret = EFAULT; + } + } + + SCFDBGMSG1(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +/* + * scf_ioc_dr() + * + * Description: SCFIOCDR ioctl command processing. + * + */ +/* ARGSUSED */ +int +scf_ioc_dr(intptr_t arg, int mode, int *rval_p, int u_mode) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_ioc_dr() " + int ret = 0; + struct scf_cmd scf_cmd; + scfdr_t *scfdr_p = NULL; + + SCFDBGMSG(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": start"); + + scfdr_p = kmem_zalloc((size_t)(sizeof (scfdr_t)), KM_SLEEP); + + if (ddi_copyin((void *)arg, (void *)scfdr_p, sizeof (scfdr_t), + mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "ioctl ", 8); + ret = EFAULT; + goto END_dr; + } + + scf_cmd.cmd = CMD_DR; + scf_cmd.subcmd = scfdr_p->sub_command; + scf_cmd.sbuf = &scfdr_p->sbuf[0]; + scf_cmd.scount = SCF_S_CNT_15; + + switch (scfdr_p->sub_command) { + case SUB_SB_CONF_CHG: + scf_cmd.rbuf = &scfdr_p->rbuf[0]; + scf_cmd.rcount = SCF_S_CNT_16; + scf_cmd.flag = SCF_USE_S_BUF; + break; + + case SUB_SB_BUILD_COMP: + scf_cmd.rcount = 0; + scf_cmd.flag = SCF_USE_S_BUF; + break; + + case SUB_SB_SENSE_ALL: + scf_cmd.rbuf = &scfdr_p->rbuf[0]; + scf_cmd.rcount = sizeof (scfdr_p->sbuf); + scf_cmd.flag = SCF_USE_SLBUF; + break; + + case SUB_SB_SENSE: + scf_cmd.rbuf = &scfdr_p->rbuf[0]; + scf_cmd.rcount = SCF_S_CNT_15; + scf_cmd.flag = SCF_USE_SSBUF; + break; + + default: + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "ioctl ", 8); + ret = EINVAL; + goto END_dr; + } + + mutex_enter(&scf_comtbl.all_mutex); + + ret = scf_send_cmd_check_bufful(&scf_cmd); + + mutex_exit(&scf_comtbl.all_mutex); + + if (ret != 0) { + if (scf_cmd.stat0 == E_PARAM) { + ret = EINVAL; + } else { + goto END_dr; + } + } + + if (ddi_copyout((void *)scfdr_p, (void *)arg, sizeof (scfdr_t), + mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "ioctl ", 8); + ret = EFAULT; + } + +/* + * END_dr + */ + END_dr: + + if (scfdr_p) { + kmem_free((void *)scfdr_p, (size_t)(sizeof (scfdr_t))); + } + + SCFDBGMSG1(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +/* + * scf_ioc_eventlist() + * + * Description: SCFIOCEVENTLIST ioctl command processing. + * + */ +/* ARGSUSED */ +int +scf_ioc_eventlist(intptr_t arg, int mode, int *rval_p, int u_mode) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_ioc_eventlist() " + int ret = 0; + scfeventlist_t *scfeventlist_p = NULL; + + SCFDBGMSG(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": start"); + + scfeventlist_p = kmem_zalloc((size_t)(sizeof (scfeventlist_t)), + KM_SLEEP); + + if (ddi_copyin((void *)arg, (void *)scfeventlist_p, + sizeof (scfeventlist_t), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "ioctl ", 8); + ret = EFAULT; + goto END_eventlist; + } + if (scfeventlist_p->listcnt > SCF_EVENTLIST_MAX) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "ioctl ", 8); + ret = EINVAL; + goto END_eventlist; + } + + mutex_enter(&scf_comtbl.all_mutex); + + bcopy((void *)scfeventlist_p, (void *)&scf_comtbl.getevent_tbl.listcnt, + sizeof (scfeventlist_t)); + + mutex_exit(&scf_comtbl.all_mutex); + +/* + * END_eventlist + */ + END_eventlist: + + if (scfeventlist_p) { + kmem_free((void *)scfeventlist_p, + (size_t)(sizeof (scfeventlist_t))); + } + + SCFDBGMSG1(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +/* + * scf_ioc_getevent() + * + * Description: SCFIOCGETEVENT ioctl command processing. + * + */ +/* ARGSUSED */ +int +scf_ioc_getevent(intptr_t arg, int mode, int *rval_p, int u_mode) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_ioc_getevent() " + int ret = 0; + scfevent_t scfevent; + scfevent32_t scfevent32; + int loop_flag = 1; + + SCFDBGMSG(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": start"); + + if (u_mode == DDI_MODEL_ILP32) { + /* DDI_MODEL_ILP32 */ + if (ddi_copyin((void *)arg, (void *)&scfevent32, + sizeof (scfevent32_t), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "ioctl ", 8); + ret = EFAULT; + goto END_getevent; + } + scfevent.flag = scfevent32.flag; + } else { + /* DDI_MODEL_NONE */ + if (ddi_copyin((void *)arg, (void *)&scfevent, + sizeof (scfevent_t), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "ioctl ", 8); + ret = EFAULT; + goto END_getevent; + } + } + + switch (scfevent.flag) { + case GETEVENT_WAIT: + mutex_enter(&scf_comtbl.all_mutex); + + while (loop_flag) { + if (scf_pop_getevent(&scfevent) == 0) { + break; + } + SC_DBG_DRV_TRACE(TC_W_SIG, __LINE__, + &scf_comtbl.getevent_cv, sizeof (kcondvar_t)); + if (cv_wait_sig(&scf_comtbl.getevent_cv, + &scf_comtbl.all_mutex) == 0) { + SC_DBG_DRV_TRACE(TC_KILL, __LINE__, + &scf_comtbl.getevent_cv, + sizeof (kcondvar_t)); + + mutex_exit(&scf_comtbl.all_mutex); + ret = EINTR; + goto END_getevent; + } + } + + mutex_exit(&scf_comtbl.all_mutex); + break; + + case GETEVENT_NOWAIT: + mutex_enter(&scf_comtbl.all_mutex); + + if (scf_pop_getevent(&scfevent) < 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "ioctl ", 8); + + mutex_exit(&scf_comtbl.all_mutex); + ret = ENODATA; + goto END_getevent; + } + + mutex_exit(&scf_comtbl.all_mutex); + break; + + default: + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "ioctl ", 8); + ret = EINVAL; + goto END_getevent; + } + + if (u_mode == DDI_MODEL_ILP32) { + /* DDI_MODEL_ILP32 */ + if ((scfevent.timestamp < INT32_MIN) || + (scfevent.timestamp > INT32_MAX)) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "ioctl ", 8); + ret = EOVERFLOW; + goto END_getevent; + } + bcopy((void *)&scfevent.rci_addr, (void *)&scfevent32.rci_addr, + SCF_INT_REASON_SIZE); + scfevent32.timestamp = (time32_t)scfevent.timestamp; + + if (ddi_copyout((void *)&scfevent32, (void *)arg, + sizeof (scfevent32_t), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "ioctl ", 8); + ret = EFAULT; + } + } else { + /* DDI_MODEL_NONE */ + if (ddi_copyout((void *)&scfevent, (void *)arg, + sizeof (scfevent_t), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "ioctl ", 8); + ret = EFAULT; + } + } + +/* + * END_getevent + */ + END_getevent: + + SCFDBGMSG1(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +/* + * scf_ioc_setmadmevent() + * + * Description: SCFIOCSETMADMEVENT ioctl command processing. + * + */ +/* ARGSUSED */ +int +scf_ioc_setmadmevent(intptr_t arg, int mode, int *rval_p, int u_mode) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_ioc_setmadmevent() " + int ret = 0; + struct scf_cmd scf_cmd; + scfiocsetmadmevent_t *scfiocsetmadmevent_p = NULL; + + SCFDBGMSG(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": start"); + + scfiocsetmadmevent_p = + kmem_zalloc((size_t)(sizeof (scfiocsetmadmevent_t)), + KM_SLEEP); + + if (ddi_copyin((void *)arg, (void *)scfiocsetmadmevent_p, + sizeof (scfiocsetmadmevent_t), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "ioctl ", 8); + ret = EFAULT; + goto END_setmadmevent; + } + + if (scfiocsetmadmevent_p->size > SCF_L_CNT_MAX) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "ioctl ", 8); + ret = EINVAL; + goto END_setmadmevent; + } + + scf_cmd.cmd = CMD_ERRLOG; + scf_cmd.subcmd = SUB_ERRLOG_SET_MADMIN; + scf_cmd.sbuf = &scfiocsetmadmevent_p->buf[0]; + scf_cmd.scount = scfiocsetmadmevent_p->size; + scf_cmd.rcount = 0; + scf_cmd.flag = SCF_USE_L_BUF; + + mutex_enter(&scf_comtbl.all_mutex); + + ret = scf_send_cmd_check_bufful(&scf_cmd); + + mutex_exit(&scf_comtbl.all_mutex); + +/* + * END_setmadmevent + */ + END_setmadmevent: + + if (scfiocsetmadmevent_p) { + kmem_free((void *)scfiocsetmadmevent_p, + (size_t)(sizeof (scfiocsetmadmevent_t))); + } + + SCFDBGMSG1(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +/* + * scf_ioc_remcscmd() + * + * Description: SCFIOCREMCSCMD ioctl command processing. + * + */ +/* ARGSUSED */ +int +scf_ioc_remcscmd(intptr_t arg, int mode, int *rval_p, int u_mode) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_ioc_remcscmd() " + int ret = 0; + struct scf_cmd scf_cmd; + scf_short_buffer_t rbuf; + scfiocremcscmd_t scfiocremcscmd; + + SCFDBGMSG(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": start"); + + if (ddi_copyin((void *)arg, (void *)&scfiocremcscmd, + sizeof (scfiocremcscmd_t), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "ioctl ", 8); + ret = EFAULT; + goto END_remcscmd; + } + + if (scfiocremcscmd.size > SCF_S_CNT_15) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "ioctl ", 8); + ret = EINVAL; + goto END_remcscmd; + } + + scf_cmd.cmd = CMD_REMCS_SPT; + + switch (scfiocremcscmd.sub_command) { + case SUB_CMD_EX_REMCS: + scf_cmd.subcmd = scfiocremcscmd.sub_command; + scf_cmd.scount = scfiocremcscmd.size; + scf_cmd.sbuf = &scfiocremcscmd.buf[0]; + scf_cmd.rcount = SCF_S_CNT_15; + scf_cmd.rbuf = &rbuf.b[0]; + scf_cmd.flag = SCF_USE_SSBUF; + break; + default: + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "ioctl ", 8); + ret = EINVAL; + goto END_remcscmd; + } + + mutex_enter(&scf_comtbl.all_mutex); + + ret = scf_send_cmd_check_bufful(&scf_cmd); + + mutex_exit(&scf_comtbl.all_mutex); + + if (ret == 0) { + scfiocremcscmd.size = scf_cmd.rbufleng; + if (scfiocremcscmd.size != 0) { + bcopy((void *)&rbuf.b[0], + (void *)&scfiocremcscmd.buf[0], + scfiocremcscmd.size); + } + + if (ddi_copyout((void *)&scfiocremcscmd, (void *)arg, + sizeof (scfiocremcscmd_t), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "ioctl ", 8); + ret = EFAULT; + } + } + +/* + * END_remcscmd + */ + END_remcscmd: + + SCFDBGMSG1(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +/* + * scf_ioc_remcsfile() + * + * Description: SCFIOCREMCSFILE ioctl command processing. + * + */ +/* ARGSUSED */ +int +scf_ioc_remcsfile(intptr_t arg, int mode, int *rval_p, int u_mode) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_ioc_remcsfile() " + int ret = 0; + struct scf_cmd scf_cmd; + scf_short_buffer_t rbuf; + scfiocremcsfile_t *scfiocremcsfile_p = NULL; + + SCFDBGMSG(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": start"); + + scfiocremcsfile_p = kmem_zalloc((size_t)(sizeof (scfiocremcsfile_t)), + KM_SLEEP); + + if (ddi_copyin((void *)arg, (void *)scfiocremcsfile_p, + sizeof (scfiocremcsfile_t), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "ioctl ", 8); + ret = EFAULT; + goto END_remcsfile; + } + + if (scfiocremcsfile_p->size > SCF_L_CNT_MAX) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "ioctl ", 8); + ret = EINVAL; + goto END_remcsfile; + } + + scf_cmd.cmd = CMD_FILE_DOWNLOAD; + scf_cmd.subcmd = scfiocremcsfile_p->sub_command; + + switch (scfiocremcsfile_p->sub_command) { + case SUB_FILEUP_READY: + if (scfiocremcsfile_p->size > SCF_L_CNT_MAX) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "ioctl ", 8); + ret = EINVAL; + goto END_remcsfile; + } + scf_cmd.scount = scfiocremcsfile_p->size; + scf_cmd.sbuf = &scfiocremcsfile_p->buf[0]; + scf_cmd.rcount = SCF_S_CNT_15; + scf_cmd.rbuf = &rbuf.b[0]; + scf_cmd.flag = SCF_USE_LSBUF; + break; + + case SUB_FILEUP_SET: + scf_cmd.scount = scfiocremcsfile_p->size; + scf_cmd.sbuf = &scfiocremcsfile_p->buf[0]; + scf_cmd.rcount = 0; + scf_cmd.flag = SCF_USE_L_BUF; + break; + + case SUB_TRANSFER_STOP: + scf_cmd.scount = 0; + scf_cmd.rcount = 0; + scf_cmd.flag = SCF_USE_S_BUF; + break; + + default: + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "ioctl ", 8); + ret = EINVAL; + goto END_remcsfile; + } + + mutex_enter(&scf_comtbl.all_mutex); + + ret = scf_send_cmd_check_bufful(&scf_cmd); + + mutex_exit(&scf_comtbl.all_mutex); + + if (ret == 0) { + scfiocremcsfile_p->size = scf_cmd.rbufleng; + if (scfiocremcsfile_p->size != 0) { + bcopy((void *)&rbuf.b[0], + (void *)&scfiocremcsfile_p->buf[0], + scfiocremcsfile_p->size); + } + + if (ddi_copyout((void *)scfiocremcsfile_p, (void *)arg, + sizeof (scfiocremcsfile_t), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "ioctl ", 8); + ret = EFAULT; + } + } + +/* + * END_remcsfile + */ + END_remcsfile: + + if (scfiocremcsfile_p) { + kmem_free((void *)scfiocremcsfile_p, + (size_t)(sizeof (scfiocremcsfile_t))); + } + + SCFDBGMSG1(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +/* + * scf_ioc_sparecmd() + * + * Description: SCFIOCSPARECMD ioctl command processing. + * + */ +/* ARGSUSED */ +int +scf_ioc_sparecmd(intptr_t arg, int mode, int *rval_p, int u_mode) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_ioc_sparecmd() " + int ret = 0; + struct scf_cmd scf_cmd; + scfiocsparecmd_t *scfiocsparecmd_p = NULL; + uint_t madm_scount; + + SCFDBGMSG(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": start"); + + scfiocsparecmd_p = kmem_zalloc((size_t)(sizeof (scfiocsparecmd_t)), + KM_SLEEP); + + if (ddi_copyin((void *)arg, (void *)scfiocsparecmd_p, + sizeof (scfiocsparecmd_t), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "ioctl ", 8); + ret = EFAULT; + goto END_sparecmd; + } + + if (scfiocsparecmd_p->size > SCF_L_CNT_MAX) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "ioctl ", 8); + ret = EINVAL; + goto END_sparecmd; + } + + scf_cmd.cmd = CMD_SPARE; + scf_cmd.subcmd = scfiocsparecmd_p->spare_sub_command; + scf_cmd.sbuf = &scfiocsparecmd_p->buf[0]; + scf_cmd.rbuf = &scfiocsparecmd_p->buf[0]; + scf_cmd.cexr[0] = scfiocsparecmd_p->command; + scf_cmd.cexr[1] = scfiocsparecmd_p->sub_command; + + switch (scfiocsparecmd_p->spare_sub_command) { + case SUB_SPARE_SS: + scf_cmd.scount = SCF_S_CNT_12; + scf_cmd.rcount = SCF_S_CNT_12; + scf_cmd.flag = SCF_USE_SSBUF; + break; + + case SUB_SPARE_SL: + scf_cmd.scount = SCF_S_CNT_12; + scf_cmd.rcount = SCF_L_CNT_MAX; + scf_cmd.flag = SCF_USE_SLBUF; + break; + + case SUB_SPARE_LS: + madm_scount = (scfiocsparecmd_p->size + SCF_S_CNT_15) & + SCF_LENGTH_16BYTE_CNV; + scf_cmd.scount = madm_scount; + scf_cmd.rcount = SCF_S_CNT_12; + scf_cmd.flag = SCF_USE_LSBUF; + break; + + default: + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "ioctl ", 8); + ret = EINVAL; + goto END_sparecmd; + } + + mutex_enter(&scf_comtbl.all_mutex); + + ret = scf_send_cmd_check_bufful(&scf_cmd); + + mutex_exit(&scf_comtbl.all_mutex); + + if (ret == 0) { + scfiocsparecmd_p->size = scf_cmd.rbufleng; + if (ddi_copyout((void *)scfiocsparecmd_p, (void *)arg, + sizeof (scfiocsparecmd_t), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "ioctl ", 8); + ret = EFAULT; + } + } + +/* + * END_sparecmd + */ + END_sparecmd: + + if (scfiocsparecmd_p) { + kmem_free((void *)scfiocsparecmd_p, + (size_t)(sizeof (scfiocsparecmd_t))); + } + + SCFDBGMSG1(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +/* + * scf_ioc_setphpinfo() + * + * Description: SCFIOCSETPHPINFO ioctl command processing. + * + */ +/* ARGSUSED */ +int +scf_ioc_setphpinfo(intptr_t arg, int mode, int *rval_p, int u_mode) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_ioc_setphpinfo() " + int ret = 0; + struct scf_cmd scf_cmd; + scfsetphpinfo_t *scfsetphpinfo_p = NULL; + + SCFDBGMSG(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": start"); + + scfsetphpinfo_p = kmem_zalloc((size_t)(sizeof (scfsetphpinfo_t)), + KM_SLEEP); + + if (ddi_copyin((void *)arg, (void *)scfsetphpinfo_p, + sizeof (scfsetphpinfo_t), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "ioctl ", 8); + ret = EFAULT; + goto END_setphpinfo; + } + + if (scfsetphpinfo_p->size > SCF_L_CNT_MAX) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "ioctl ", 8); + ret = EINVAL; + goto END_setphpinfo; + } + + scf_cmd.cmd = CMD_DOMAIN_INFO; + scf_cmd.subcmd = SUB_PCI_HP_CONFIG; + scf_cmd.sbuf = &scfsetphpinfo_p->buf[0]; + scf_cmd.scount = scfsetphpinfo_p->size; + scf_cmd.rcount = 0; + scf_cmd.flag = SCF_USE_L_BUF; + + mutex_enter(&scf_comtbl.all_mutex); + + ret = scf_send_cmd_check_bufful(&scf_cmd); + + mutex_exit(&scf_comtbl.all_mutex); + +/* + * END_setphpinfo + */ + END_setphpinfo: + + if (scfsetphpinfo_p) { + kmem_free((void *)scfsetphpinfo_p, + (size_t)(sizeof (scfsetphpinfo_t))); + } + + SCFDBGMSG1(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +/* + * scf_ioc_pciresetreq() + * + * Description: SCFIOCPCIRESETREQ ioctl command processing. + * + */ +/* ARGSUSED */ +int +scf_ioc_pciresetreq(intptr_t arg, int mode, int *rval_p, int u_mode) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_ioc_pciresetreq() " + int ret = 0; + struct scf_cmd scf_cmd; + scfpciresetreq_t *scfpciresetreq_p = NULL; + + SCFDBGMSG(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": start"); + + scfpciresetreq_p = kmem_zalloc((size_t)(sizeof (scfpciresetreq_t)), + KM_SLEEP); + + if (ddi_copyin((void *)arg, (void *)scfpciresetreq_p, + sizeof (scfpciresetreq_t), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "ioctl ", 8); + ret = EFAULT; + goto END_pciresetreq; + } + + if (scfpciresetreq_p->size > SCF_L_CNT_MAX) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "ioctl ", 8); + ret = EINVAL; + goto END_pciresetreq; + } + + scf_cmd.cmd = CMD_DOMAIN_INFO; + scf_cmd.subcmd = SUB_PHP_RESET; + scf_cmd.sbuf = &scfpciresetreq_p->sbuf[0]; + scf_cmd.scount = scfpciresetreq_p->size; + scf_cmd.rbuf = &scfpciresetreq_p->rbuf[0]; + scf_cmd.rcount = SCF_S_CNT_15; + scf_cmd.flag = SCF_USE_L_BUF; + + mutex_enter(&scf_comtbl.all_mutex); + + ret = scf_send_cmd_check_bufful(&scf_cmd); + + mutex_exit(&scf_comtbl.all_mutex); + + if (ret == 0) { + if (ddi_copyout((void *)scfpciresetreq_p, (void *)arg, + sizeof (scfpciresetreq_t), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "ioctl ", 8); + ret = EFAULT; + } + } + +/* + * END_pciresetreq + */ + END_pciresetreq: + + if (scfpciresetreq_p) { + kmem_free((void *)scfpciresetreq_p, + (size_t)(sizeof (scfpciresetreq_t))); + } + + SCFDBGMSG1(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +/* + * scf_push_reportsense() + * + * Description: Set processing of SCFIOCGETREPORT information. + * + */ +int +scf_push_reportsense(unsigned int rci_addr, unsigned char *sense, + time_t timestamp) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_push_reportsense() " + int top = scf_comtbl.report_sense_top; + scfreport_t *rsensep = scf_comtbl.report_sensep; + int overflow = 0; + int ret = 0; + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": start"); + + if (rsensep[top].flag != 0) { + SCFDBGMSG(SCF_DBGFLAG_IOCTL, "reportsense overflow"); + overflow = 1; + /* increment counter */ + scf_comtbl.scf_rsense_overflow++; + } + + rsensep[top].flag = 1; + rsensep[top].rci_addr = rci_addr; + bcopy((void *)&sense[0], (void *)&rsensep[top].report_sense[0], 4); + rsensep[top].timestamp = timestamp; + + scf_comtbl.report_sense_top = + ((scf_report_sense_pool_max - 1) == top) ? 0 : top + 1; + + if (overflow) { + scf_comtbl.report_sense_oldest = scf_comtbl.report_sense_top; + } + + SCFDBGMSG1(SCF_DBGFLAG_IOCTL, + SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +/* + * scf_pop_reportsense() + * + * Description: Get processing of SCFIOCGETREPORT information. + * + */ +int +scf_pop_reportsense(scfreport_t *rsense) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_pop_reportsense() " + int oldest = scf_comtbl.report_sense_oldest; + scfreport_t *drv_rsensep = scf_comtbl.report_sensep; + int ret = (-1); + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": start"); + + if (drv_rsensep[oldest].flag != 0) { + rsense->rci_addr = drv_rsensep[oldest].rci_addr; + bcopy((void *)&drv_rsensep[oldest].report_sense[0], + (void *)&rsense->report_sense[0], 4); + rsense->timestamp = drv_rsensep[oldest].timestamp; + /* clear flag */ + drv_rsensep[oldest].flag = 0; + scf_comtbl.report_sense_oldest = + ((scf_report_sense_pool_max - 1) == oldest) + ? 0 : oldest + 1; + ret = 0; + } + + SCFDBGMSG1(SCF_DBGFLAG_IOCTL, + SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +/* + * scf_push_getevent() + * + * Description: Set processing of SCFIOCGETEVENT information. + * + */ +int +scf_push_getevent(unsigned char *event_p) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_push_getevent() " + int top = scf_comtbl.getevent_sense_top; + scfevent_t *scfevent_p = scf_comtbl.getevent_sensep; + int overflow = 0; + int ii; + time_t timestamp; + int ret = 1; + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": start"); + + /* Event check */ + for (ii = 0; ii < scf_comtbl.getevent_tbl.listcnt; ii++) { + if (event_p[4] == scf_comtbl.getevent_tbl.codelist[ii]) { + ret = 0; + break; + } + } + if (ret == 0) { + /* Event set */ + if (scfevent_p[top].flag != 0) { + SCFDBGMSG(SCF_DBGFLAG_IOCTL, "getevent overflow"); + overflow = 1; + /* increment counter */ + scf_comtbl.scf_getevent_overflow++; + } + timestamp = ddi_get_time(); + scfevent_p[top].flag = 1; + bcopy((void *)event_p, (void *)&scfevent_p[top].rci_addr, + SCF_INT_REASON_SIZE); + scfevent_p[top].timestamp = timestamp; + scf_comtbl.getevent_sense_top = + ((scf_getevent_pool_max - 1) == top) ? 0 : top + 1; + if (overflow) { + scf_comtbl.getevent_sense_oldest = + scf_comtbl.getevent_sense_top; + } + } + + SCFDBGMSG1(SCF_DBGFLAG_IOCTL, + SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +/* + * scf_pop_reportsense() + * + * Description: Get processing of SCFIOCGETEVENT information. + * + */ +int +scf_pop_getevent(scfevent_t *event_p) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_pop_getevent() " + int oldest = scf_comtbl.getevent_sense_oldest; + scfevent_t *scfevent_p = scf_comtbl.getevent_sensep; + int ret = (-1); + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": start"); + + if (scfevent_p[oldest].flag != 0) { + bcopy((void *)&scfevent_p[oldest].rci_addr, + (void *)&event_p->rci_addr, SCF_INT_REASON_SIZE); + event_p->timestamp = scfevent_p[oldest].timestamp; + /* clear flag */ + scfevent_p[oldest].flag = 0; + scf_comtbl.getevent_sense_oldest = + ((scf_getevent_pool_max - 1) == oldest) + ? 0 : oldest + 1; + ret = 0; + } + + SCFDBGMSG1(SCF_DBGFLAG_IOCTL, + SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +/* + * scf_valid_date() + * + * Description: Validity check processing of date. + * + */ +int +scf_valid_date(int year, int month, int date) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_valid_date() " + int leap = 0; + int ret = 0; + static int scf_m2d[2][12] = { + { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, + { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } + }; + + SCFDBGMSG(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": start"); + + if ((year % 400) == 0) { + leap = 1; + } else { + if ((year % 100) == 0) { + leap = 0; + } else { + if ((year % 4) == 0) { + leap = 1; + } + } + } + if (scf_m2d[leap][month - 1] < date) { + ret = 1; + } + + SCFDBGMSG1(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +/* + * scf_check_pon_time() + * + * Description: Power-on time range check processing. + * + */ +int +scf_check_pon_time(scfautopwrtime_t *ptime) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_check_pon_time() " + int ret = (-1); + + SCFDBGMSG(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": start"); + + /* check date, time */ + if ((ptime->pon_year == 0) && (ptime->pon_month == 0) && + (ptime->pon_date == 0) && (ptime->pon_hour == 0) && + (ptime->pon_minute == 0)) { + ret = 0; + goto END_check_pon_time; + } + + /* check date, time */ + if ((ptime->pon_year < 1970) || (ptime->pon_year > 9999)) { + goto END_check_pon_time; + } + if ((ptime->pon_month < 1) || (ptime->pon_month > 12)) { + goto END_check_pon_time; + } + if (ptime->pon_date < 1) { + goto END_check_pon_time; + } + if ((ptime->pon_hour < 0) || (ptime->pon_hour > 23)) { + goto END_check_pon_time; + } + if ((ptime->pon_minute < 0) || (ptime->pon_minute > 59)) { + goto END_check_pon_time; + } + if (scf_valid_date(ptime->pon_year, + ptime->pon_month, ptime->pon_date)) { + goto END_check_pon_time; + } + ret = 0; + +/* + * END_check_pon_time + */ + END_check_pon_time: + SCFDBGMSG1(SCF_DBGFLAG_IOCTL, + SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +/* + * scf_check_poff_time() + * + * Description: Power-off time range check processing. + * + */ +int +scf_check_poff_time(scfautopwrtime_t *ptime) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_check_poff_time() " + int ret = (-1); + + SCFDBGMSG(SCF_DBGFLAG_IOCTL, SCF_FUNC_NAME ": start"); + + /* all zero? */ + if ((ptime->poff_year == 0) && (ptime->poff_month == 0) && + (ptime->poff_date == 0) && (ptime->poff_hour == 0) && + (ptime->poff_minute == 0)) { + if ((ptime->flag != 0) || (ptime->sarea != 0)) { + goto END_check_poff_time; + } + ret = 0; + goto END_check_poff_time; + } + + /* check date, time */ + if ((ptime->poff_year < 1970) || (ptime->poff_year > 9999)) { + goto END_check_poff_time; + } + if ((ptime->poff_month < 1) || (ptime->poff_month > 12)) { + goto END_check_poff_time; + } + if (ptime->poff_date < 1) { + goto END_check_poff_time; + } + if ((ptime->poff_hour < 0) || (ptime->poff_hour > 23)) { + goto END_check_poff_time; + } + if ((ptime->poff_minute < 0) || (ptime->poff_minute > 59)) { + goto END_check_poff_time; + } + if (scf_valid_date(ptime->poff_year, ptime->poff_month, + ptime->poff_date)) { + goto END_check_poff_time; + } + ret = 0; + +/* + * END_check_poff_time + */ + END_check_poff_time: + SCFDBGMSG1(SCF_DBGFLAG_IOCTL, + SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} diff --git a/usr/src/uts/sun4u/opl/io/scfd/scfostoescf.c b/usr/src/uts/sun4u/opl/io/scfd/scfostoescf.c new file mode 100644 index 0000000000..8d56e398cf --- /dev/null +++ b/usr/src/uts/sun4u/opl/io/scfd/scfostoescf.c @@ -0,0 +1,307 @@ +/* + * 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 + */ +/* + * All Rights Reserved, Copyright (c) FUJITSU LIMITED 2006 + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/ksynch.h> +#include <sys/types.h> +#include <sys/cmn_err.h> +#include <sys/kmem.h> +#include <sys/errno.h> +#include <sys/ddi.h> +#include <sys/sunddi.h> + +#include <sys/scfd/scfparam.h> + + +/* + * scf_service_putinfo() + * + * Description: Data request to send processing from the OS to ESCF. + * + */ +/* ARGSUSED */ +int +scf_service_putinfo(uint32_t key, uint8_t type, uint32_t transid, + uint32_t length, void *datap) +{ +#define SCF_FUNC_NAME "scf_service_putinfo() " + scf_cmd_t scf_cmd; /* SCF command table */ + uchar_t *bufp = NULL; /* Working value : buff addr */ + int ret = 0; /* Return value */ + timeout_id_t save_tmids[SCF_TIMERCD_MAX]; + int tm_stop_cnt; + + SCFDBGMSG(SCF_DBGFLAG_SRV, SCF_FUNC_NAME ": start"); + SC_DBG_DRV_TRACE(TC_S_PUTINFO | TC_IN, __LINE__, &key, sizeof (key)); + + /* SCF command table clear */ + bzero((void *)&scf_cmd, sizeof (scf_cmd_t)); + + /* Lock driver mutex */ + mutex_enter(&scf_comtbl.all_mutex); + + /* Check "key" */ + if (key != KEY_ESCF) { + /* Invalid "key" */ + SC_DBG_DRV_TRACE(TC_S_PUTINFO | TC_ERRCD, __LINE__, &key, + sizeof (key)); + ret = EINVAL; + goto END_service_putinfo; + } + + /* Check "length" and "datap" */ + if ((length != 0) && (datap == NULL)) { + /* Invalid "length" or "datap" */ + SC_DBG_DRV_TRACE(TC_S_PUTINFO | TC_ERRCD, __LINE__, &length, + sizeof (length)); + ret = EINVAL; + goto END_service_putinfo; + } + + /* Check "length" is max length */ + if (length > SCF_L_CNT_MAX) { + /* Invalid "length" */ + SC_DBG_DRV_TRACE(TC_S_PUTINFO | TC_ERRCD, __LINE__, &length, + sizeof (length)); + ret = EINVAL; + goto END_service_putinfo; + } + + /* Check putinfo exec flag */ + if (scf_comtbl.putinfo_exec_flag == FLAG_ON) { + /* Multiplex, putinfo */ + SC_DBG_DRV_TRACE(TC_S_PUTINFO, __LINE__, + &scf_comtbl.putinfo_exec_flag, + sizeof (scf_comtbl.putinfo_exec_flag)); + ret = EBUSY; + goto END_service_putinfo; + } + + /* putinfo exec flag ON */ + scf_comtbl.putinfo_exec_flag = FLAG_ON; + + /* Check "length" is 0 */ + if (length != 0) { + /* Send buffer allocation */ + bufp = (uchar_t *)kmem_zalloc(length, KM_SLEEP); + + /* Data copy to send buffer */ + bcopy(datap, bufp, length); + } + + /* Make SCF command */ + scf_cmd.flag = SCF_USE_L_BUF; + scf_cmd.cmd = CMD_OS_XSCF_CTL; + scf_cmd.subcmd = type; + scf_cmd.sbuf = bufp; + scf_cmd.scount = length; + scf_cmd.rbuf = NULL; + scf_cmd.rcount = 0; + + /* Send SCF command */ + ret = scf_send_cmd_check_bufful(&scf_cmd); + + /* Check send buffer */ + if (bufp != NULL) { + /* Send data release */ + kmem_free((void *)bufp, length); + } + + /* putinfo exec flag OFF */ + scf_comtbl.putinfo_exec_flag = FLAG_OFF; + +/* + * END_service_putinfo + */ + END_service_putinfo: + + /* Collect the timers which need to be stopped */ + tm_stop_cnt = scf_timer_stop_collect(save_tmids, SCF_TIMERCD_MAX); + + /* Unlock driver mutex */ + mutex_exit(&scf_comtbl.all_mutex); + + /* Timer stop */ + if (tm_stop_cnt != 0) { + scf_timer_untimeout(save_tmids, SCF_TIMERCD_MAX); + } + + SC_DBG_DRV_TRACE(TC_S_PUTINFO | TC_OUT, __LINE__, &ret, sizeof (ret)); + SCFDBGMSG1(SCF_DBGFLAG_SRV, SCF_FUNC_NAME ": end return = %d", ret); + + return (ret); +} + + +/* + * scf_service_getinfo() + * + * Description: Data request to receive processing from the OS to ESCF. + * + */ +int +scf_service_getinfo(uint32_t key, uint8_t type, uint32_t transid, + uint32_t *lengthp, void *datap) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_service_getinfo() " + scf_cmd_t scf_cmd; /* SCF command table */ + scf_short_buffer_t sbuf; /* Send buffer */ + uchar_t *bufp = NULL; /* Working value : buff addr */ + uint_t wkleng; /* Working value : length */ + int ret = 0; /* Return value */ + timeout_id_t save_tmids[SCF_TIMERCD_MAX]; + int tm_stop_cnt; + + SCFDBGMSG(SCF_DBGFLAG_SRV, SCF_FUNC_NAME ": start"); + SC_DBG_DRV_TRACE(TC_S_GETINFO | TC_IN, __LINE__, &key, sizeof (key)); + + /* SCF command table/Send buffer clear */ + bzero((void *)&scf_cmd, sizeof (scf_cmd_t)); + bzero((void *)&sbuf.b[0], SCF_S_CNT_16); + + /* Lock driver mutex */ + mutex_enter(&scf_comtbl.all_mutex); + + /* Check "key" */ + if (key != KEY_ESCF) { + /* Invalid "key" */ + SC_DBG_DRV_TRACE(TC_S_GETINFO | TC_ERRCD, __LINE__, &key, + sizeof (key)); + ret = EINVAL; + goto END_service_getinfo; + } + + /* Check "lengthp" and "datap" */ + if (lengthp == NULL) { + /* Invalid "lengthp" */ + SC_DBG_DRV_TRACE(TC_S_GETINFO | TC_ERRCD, __LINE__, &lengthp, + sizeof (lengthp)); + ret = EINVAL; + goto END_service_getinfo; + } + + /* Check "lengthp" is max length */ + if (*lengthp > SCF_L_CNT_MAX) { + /* Invalid "lengthp" */ + SC_DBG_DRV_TRACE(TC_S_GETINFO | TC_ERRCD, __LINE__, lengthp, + sizeof (*lengthp)); + ret = EINVAL; + goto END_service_getinfo; + } + + /* Check, parameter "length" and "datap" */ + if ((*lengthp != 0) && (datap == NULL)) { + /* Invalid "lengthp" or "datap" */ + SC_DBG_DRV_TRACE(TC_S_GETINFO | TC_ERRCD, __LINE__, lengthp, + sizeof (*lengthp)); + ret = EINVAL; + goto END_service_getinfo; + } + + /* Check getinfo exec flag */ + if (scf_comtbl.getinfo_exec_flag == FLAG_ON) { + /* Multiplex, getinfo */ + SC_DBG_DRV_TRACE(TC_S_GETINFO, __LINE__, + &scf_comtbl.getinfo_exec_flag, + sizeof (scf_comtbl.getinfo_exec_flag)); + ret = EBUSY; + goto END_service_getinfo; + } + + /* getinfo exec flag ON */ + scf_comtbl.getinfo_exec_flag = FLAG_ON; + + /* Check "lengthp" is 0 */ + if (*lengthp != 0) { + /* + * Receive buffer allocation + */ + wkleng = *lengthp; + bufp = (uchar_t *)kmem_zalloc(wkleng, KM_SLEEP); + } else { + wkleng = 0; + } + + /* Make SCF command */ + sbuf.four_bytes_access[0] = transid; + scf_cmd.flag = SCF_USE_SLBUF; + scf_cmd.cmd = CMD_OS_XSCF_CTL; + scf_cmd.subcmd = type; + scf_cmd.scount = SCF_S_CNT_15; + scf_cmd.sbuf = &sbuf.b[0]; + scf_cmd.rcount = wkleng; + scf_cmd.rbuf = bufp; + + /* Send SCF command */ + ret = scf_send_cmd_check_bufful(&scf_cmd); + + /* Check return code */ + if (ret == 0) { + /* Set receive length */ + if (*lengthp > scf_cmd.rbufleng) { + /* Set receive data length */ + *lengthp = scf_cmd.rbufleng; + } + + /* Check receive data length is not 0 */ + if (*lengthp != 0) { + /* Data copy to "datap" */ + bcopy(bufp, datap, *lengthp); + } + } + + /* Check receive buffer */ + if (bufp != NULL) { + /* + * Receive data release + */ + kmem_free((void *)bufp, wkleng); + } + + /* getinfo exec flag OFF */ + scf_comtbl.getinfo_exec_flag = FLAG_OFF; + +/* + * END_service_getinfo + */ + END_service_getinfo: + + /* Collect the timers which need to be stopped */ + tm_stop_cnt = scf_timer_stop_collect(save_tmids, SCF_TIMERCD_MAX); + + /* Unlock driver mutex */ + mutex_exit(&scf_comtbl.all_mutex); + + /* Timer stop */ + if (tm_stop_cnt != 0) { + scf_timer_untimeout(save_tmids, SCF_TIMERCD_MAX); + } + + SC_DBG_DRV_TRACE(TC_S_GETINFO | TC_OUT, __LINE__, &ret, sizeof (ret)); + SCFDBGMSG1(SCF_DBGFLAG_SRV, SCF_FUNC_NAME ": end return = %d", ret); + + return (ret); +} diff --git a/usr/src/uts/sun4u/opl/io/scfd/scfparam.c b/usr/src/uts/sun4u/opl/io/scfd/scfparam.c new file mode 100644 index 0000000000..d1cadc0598 --- /dev/null +++ b/usr/src/uts/sun4u/opl/io/scfd/scfparam.c @@ -0,0 +1,147 @@ +/* + * 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 + */ +/* + * All Rights Reserved, Copyright (c) FUJITSU LIMITED 2006 + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/conf.h> +#include <sys/cmn_err.h> +#include <sys/errno.h> +#include <sys/time.h> +#include <sys/ddi.h> +#include <sys/sunddi.h> + +#include <sys/scfd/scfsys.h> + +/* + * Common table + */ +scf_comtbl_t scf_comtbl; /* SCF driver common table */ +void *scfstate; /* root of soft state */ +char *scf_driver_name = SCF_DRIVER_NAME; /* SCF driver name */ + +/* + * SCF driver control mode + */ +uint_t scf_halt_proc_mode = HALTPROC_STOP; /* SCFHALT after processing mode */ +uint_t scf_last_detach_mode = 0; /* Last detach mode */ + +/* + * SRAM trace date size + */ +uint_t scf_sram_trace_data_size = 12; /* Get SRAM trace data size */ + +/* + * Wait timer value (Micro-second) + */ +uint_t scf_rdctrl_sense_wait = 60000000; + /* SCFIOCRDCTRL wait timer value (60s) */ + +/* + * Wait timer value (Milli-second) + */ +uint_t scf_buf_ful_rtime = 500; + /* Buff full wait retry timer value (500ms) */ +uint_t scf_rci_busy_rtime = 3000; /* RCI busy wait retry timer value (3s) */ + +/* + * Re-try counter + */ +uint_t scf_buf_ful_rcnt = 10; /* Buff full retry counter */ +uint_t scf_rci_busy_rcnt = 15; /* RCI busy retry counter */ +uint_t scf_tesum_rcnt = 1; /* Tx sum retry counter */ +uint_t scf_resum_rcnt = 1; /* Rx sum retry counter */ +uint_t scf_cmd_to_rcnt = 1; /* Command to retry counter */ +uint_t scf_devbusy_wait_rcnt = 6; /* Command device busy retry counter */ +uint_t scf_online_wait_rcnt = 6; /* SCF online retry counter */ +uint_t scf_path_change_max = 4; /* SCF path change retry counter */ + +/* + * Max value + */ +uint_t scf_report_sense_pool_max = 96; /* Report sense max */ +uint_t scf_getevent_pool_max = 96; /* SCFIOCGETEVENT max */ +uint_t scf_rci_max = 32 + 94; /* RCI device max */ +uint_t scf_rxbuff_max_size = 4096; /* SCF command data division max size */ + +/* + * Poff factor (reported on shutdown start) + */ +unsigned char scf_poff_factor[2][3] = { + { 0x00, 0x00, 0x00 }, /* Shutdown (except pfail) */ + { 0x01, 0x00, 0x00 }}; /* Shutdown by pfail */ + +/* + * Alive check parameter + */ +uchar_t scf_alive_watch_code = 0x10; /* alive code for SCF driver */ +uchar_t scf_alive_phase_code = 0x00; /* alive phase code */ +uchar_t scf_alive_interval_time = INTERVAL_TIME_DEF; /* interval time */ +uchar_t scf_alive_monitor_time = MONITOR_TIME_DEF; /* monitor timeout */ +ushort_t scf_alive_panic_time = PANIC_TIME_DEF; /* panic timeout */ + +uchar_t scf_acr_phase_code = 0x00; /* Alive check register phase code */ + +/* + * FMEMA interface + */ +caddr_t scf_avail_cmd_reg_vaddr = 0; /* SCF Command register address */ + +/* + * Send break interface + */ +int scf_dm_secure_mode = 0; /* secure mode */ + +/* + * ioctl control value and flag + */ +int scf_save_hac_flag = 0; /* Host address disp flag */ +scfhac_t scf_save_hac; /* Host address disp save */ + +/* + * Register read sync value + */ +uint8_t scf_rs8; +uint16_t scf_rs16; +uint32_t scf_rs32; + +/* + * Panic value + */ +uint_t scf_panic_reported = 0; /* Panic report after */ +uint_t scf_panic_report_maxretry = 15; /* Same as busy_maxretry */ +uint_t scf_cmdend_wait_time_panic = 1000; + /* SCF command end wait timer value (1s) */ +uint_t scf_cmdend_wait_rcnt_panic = 4; /* SCF command end retry counter */ + +uint_t scf_panic_exec_wait_time = 100; /* Panic wait timer value (100ms) */ +uint_t scf_panic_exec_flag = 0; /* Panic exec flag */ +uint_t scf_panic_exec_flag2 = 0; /* Panic exec flag (report send) */ + +/* + * Panic trace + */ +ushort_t scf_panic_trc_w_off = 0; /* Panic trcae next write offset */ +uint16_t scf_panic_trc_command = 0; /* Panic SCF command register memo */ +uint16_t scf_panic_trc_status = 0; /* Panic SCF status register memo */ +ushort_t scf_panic_trc[16]; /* Panic trace area */ diff --git a/usr/src/uts/sun4u/opl/io/scfd/scfreg.c b/usr/src/uts/sun4u/opl/io/scfd/scfreg.c new file mode 100644 index 0000000000..bfb8d40eba --- /dev/null +++ b/usr/src/uts/sun4u/opl/io/scfd/scfreg.c @@ -0,0 +1,1977 @@ +/* + * 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 + */ +/* + * All Rights Reserved, Copyright (c) FUJITSU LIMITED 2006 + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/conf.h> +#include <sys/cmn_err.h> +#include <sys/errno.h> +#include <sys/time.h> +#include <sys/kmem.h> +#include <sys/ddi.h> +#include <sys/sunddi.h> + +#include <sys/scfd/scfparam.h> + + +/* + * SCF command send control area save + */ +struct scf_cmd scfcmd_save; +uchar_t scf_sbuf_save[SCF_L_CNT_MAX]; +uchar_t scf_rbuf_save[SCF_L_CNT_MAX]; + +/* + * Function list + */ +int scf_map_regs(dev_info_t *dip, scf_state_t *statep); +void scf_unmap_regs(scf_state_t *statep); +int scf_send_cmd_check_bufful(struct scf_cmd *scfcmdp); +int scf_send_cmd(struct scf_cmd *scfcmdp); +void scf_i_send_cmd(struct scf_cmd *scfcmdp, struct scf_state *statep); +void scf_p_send_cmd(struct scf_cmd *scfcmdp, struct scf_state *statep); +int scf_path_check(scf_state_t **statep); +int scf_offline_check(scf_state_t *statep, uint_t timer_exec_flag); +int scf_cmdbusy_check(scf_state_t *statep); +void scf_alivecheck_start(scf_state_t *statep); +void scf_alivecheck_stop(scf_state_t *statep); +void scf_forbid_intr(struct scf_state *statep); +void scf_permit_intr(struct scf_state *statep, int flag); +int scf_check_state(scf_state_t *statep); +void scf_chg_scf(scf_state_t *statep, int status); +void scf_del_queue(scf_state_t *statep); +int scf_make_send_cmd(struct scf_cmd *scfcmdp, uint_t flag); +void scf_sram_trace_init(struct scf_state *statep); +void scf_sram_trace(struct scf_state *statep, uint8_t log_id); + +/* + * External function + */ +extern void scf_dscp_stop(uint32_t factor); + + +/* + * scf_map_regs() + * + * Description: Register and SRAM map processing. + * + */ +int +scf_map_regs(dev_info_t *dip, scf_state_t *statep) +{ +#define SCF_FUNC_NAME "scf_map_regs() " + int ret = 1; + uint32_t wkoffset = 0; + + ddi_device_acc_attr_t access_attr = { + DDI_DEVICE_ATTR_V0, + DDI_STRUCTURE_BE_ACC, + DDI_STRICTORDER_ACC + }; + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_SYS, SCF_FUNC_NAME ": start"); + + SCF_DBG_TEST_MAP_REGS(statep); + + /* map register 1 : SCF register */ + if (ddi_regs_map_setup(dip, REG_INDEX_SCF, + (caddr_t *)&statep->scf_regs, 0, 0, &access_attr, + &statep->scf_regs_handle) != DDI_SUCCESS) { + SC_DBG_DRV_TRACE(TC_ERR, __LINE__, "map_regs", 8); + cmn_err(CE_WARN, + "%s: scf_map_regs: ddi_regs_map_setup failed.\n", + scf_driver_name); + goto END_map_regs; + } + statep->resource_flag |= S_DID_REG1; + + /* map register 2 : SCF contorol register */ + if (ddi_regs_map_setup(dip, REG_INDEX_SCFCNTL, + (caddr_t *)&statep->scf_regs_c, 0, 0, &access_attr, + &statep->scf_regs_c_handle) != DDI_SUCCESS) { + SC_DBG_DRV_TRACE(TC_ERR, __LINE__, "map_regs", 8); + cmn_err(CE_WARN, + "%s: scf_map_regs: ddi_regs_map_setup failed.\n", + scf_driver_name); + goto END_map_regs; + } + statep->resource_flag |= S_DID_REG2; + + /* get size of register 3 : SCF DSCP SRAM */ + if (ddi_dev_regsize(dip, REG_INDEX_DSCPSRAM, + &statep->scf_dscp_sram_len) != DDI_SUCCESS) { + SC_DBG_DRV_TRACE(TC_ERR, __LINE__, "map_regs", 8); + cmn_err(CE_WARN, + "%s: scf_map_regs: ddi_dev_regsize failed.\n", + scf_driver_name); + goto END_map_regs; + } + /* check size */ + if (statep->scf_dscp_sram_len < SRAM_MAX_DSCP) { + SC_DBG_DRV_TRACE(TC_ERR, __LINE__, "map_regs", 8); + cmn_err(CE_WARN, + "%s: scf_map_regs: ddi_dev_regsize failed.\n", + scf_driver_name); + goto END_map_regs; + } else if (statep->scf_dscp_sram_len > SRAM_MAX_DSCP) { + statep->scf_dscp_sram_len = SRAM_MAX_DSCP; + } + /* map register 3 : SCF DSCP SRAM */ + if (ddi_regs_map_setup(dip, REG_INDEX_DSCPSRAM, + (caddr_t *)&statep->scf_dscp_sram, 0, + (offset_t)statep->scf_dscp_sram_len, &access_attr, + &statep->scf_dscp_sram_handle) != DDI_SUCCESS) { + SC_DBG_DRV_TRACE(TC_ERR, __LINE__, "map_regs", 8); + cmn_err(CE_WARN, + "%s: scf_map_regs: ddi_regs_map_setup failed.\n", + scf_driver_name); + goto END_map_regs; + } + statep->resource_flag |= S_DID_REG3; + + /* get size of register 4 : SCF system SRAM */ + if (ddi_dev_regsize(dip, REG_INDEX_SYSTEMSRAM, + &statep->scf_sys_sram_len) != DDI_SUCCESS) { + SC_DBG_DRV_TRACE(TC_ERR, __LINE__, "map_regs", 8); + cmn_err(CE_WARN, + "%s: scf_map_regs: ddi_dev_regsize failed.\n", + scf_driver_name); + goto END_map_regs; + } + /* check size */ + if (statep->scf_sys_sram_len < SRAM_MAX_SYSTEM) { + SC_DBG_DRV_TRACE(TC_ERR, __LINE__, "map_regs", 8); + cmn_err(CE_WARN, + "%s: scf_map_regs: ddi_dev_regsize failed.\n", + scf_driver_name); + goto END_map_regs; + } else if (statep->scf_sys_sram_len > SRAM_MAX_SYSTEM) { + statep->scf_sys_sram_len = SRAM_MAX_SYSTEM; + } + /* map register 4 : SCF system SRAM */ + if (ddi_regs_map_setup(dip, REG_INDEX_SYSTEMSRAM, + (caddr_t *)&statep->scf_sys_sram, 0, + (offset_t)statep->scf_sys_sram_len, &access_attr, + &statep->scf_sys_sram_handle) != DDI_SUCCESS) { + SC_DBG_DRV_TRACE(TC_ERR, __LINE__, "map_regs", 8); + cmn_err(CE_WARN, + "%s: scf_map_regs: ddi_regs_map_setup failed.\n", + scf_driver_name); + goto END_map_regs; + } + statep->resource_flag |= S_DID_REG4; + + /* get size of register 5 : SCF interface block */ + if (ddi_dev_regsize(dip, REG_INDEX_INTERFACE, + &statep->scf_interface_len) != DDI_SUCCESS) { + SC_DBG_DRV_TRACE(TC_ERR, __LINE__, "map_regs", 8); + cmn_err(CE_WARN, + "%s: scf_map_regs: ddi_dev_regsize failed.\n", + scf_driver_name); + goto END_map_regs; + } + /* check size */ + if (statep->scf_interface_len < sizeof (scf_interface_t)) { + SC_DBG_DRV_TRACE(TC_ERR, __LINE__, "map_regs", 8); + cmn_err(CE_WARN, + "%s: scf_map_regs: ddi_dev_regsize failed.\n", + scf_driver_name); + goto END_map_regs; + } else { + statep->scf_interface_len = sizeof (scf_interface_t); + } + /* map register 5 : SCF interface block */ + if (ddi_regs_map_setup(dip, REG_INDEX_INTERFACE, + (caddr_t *)&statep->scf_interface, 0, + (offset_t)statep->scf_interface_len, &access_attr, + &statep->scf_interface_handle) != DDI_SUCCESS) { + SC_DBG_DRV_TRACE(TC_ERR, __LINE__, "map_regs", 8); + cmn_err(CE_WARN, + "%s: scf_map_regs: ddi_regs_map_setup failed.\n", + scf_driver_name); + goto END_map_regs; + } + statep->resource_flag |= S_DID_REG5; + + /* get size of register : SRAM driver trace */ + wkoffset = SCF_DDI_GET32(statep, statep->scf_interface_handle, + &statep->scf_interface->DRVTRC_OFFSET); + statep->scf_reg_drvtrc_len = + SCF_DDI_GET32(statep, statep->scf_interface_handle, + &statep->scf_interface->DRVTRC_SIZE); + + if ((wkoffset != 0) && (statep->scf_reg_drvtrc_len != 0)) { + /* map register : SRAM driver trace */ + if (ddi_regs_map_setup(dip, REG_INDEX_INTERFACE, + (caddr_t *)&statep->scf_reg_drvtrc, wkoffset, + (offset_t)statep->scf_reg_drvtrc_len, &access_attr, + &statep->scf_reg_drvtrc_handle) != DDI_SUCCESS) { + SC_DBG_DRV_TRACE(TC_ERR, __LINE__, "map_regs", 8); + cmn_err(CE_WARN, + "%s: scf_map_regs: " + "ddi_regs_map_setup failed.\n", + scf_driver_name); + goto END_map_regs; + } + statep->resource_flag |= S_DID_REG6; + } + + /* SRAM trace initialize */ + scf_sram_trace_init(statep); + + ret = 0; + +/* + * END_map_regs + */ + END_map_regs: + + SCFDBGMSG1(SCF_DBGFLAG_SYS, SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +/* + * scf_unmap_regs() + * + * Description: Register and SRAM un-map processing. + * + */ +void +scf_unmap_regs(scf_state_t *statep) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_unmap_regs() " + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_SYS, SCF_FUNC_NAME ": start"); + + SCF_DBG_TEST_UNMAP_REGS(statep); + + /* Register and SRAM un-map */ + if (statep->resource_flag & S_DID_REG1) { + ddi_regs_map_free(&statep->scf_regs_handle); + statep->resource_flag &= ~S_DID_REG1; + } + + if (statep->resource_flag & S_DID_REG2) { + ddi_regs_map_free(&statep->scf_regs_c_handle); + statep->resource_flag &= ~S_DID_REG2; + } + + if (statep->resource_flag & S_DID_REG3) { + ddi_regs_map_free(&statep->scf_dscp_sram_handle); + statep->resource_flag &= ~S_DID_REG3; + } + + if (statep->resource_flag & S_DID_REG4) { + ddi_regs_map_free(&statep->scf_sys_sram_handle); + statep->resource_flag &= ~S_DID_REG4; + } + + if (statep->resource_flag & S_DID_REG5) { + ddi_regs_map_free(&statep->scf_interface_handle); + statep->resource_flag &= ~S_DID_REG5; + } + + if (statep->resource_flag & S_DID_REG6) { + ddi_regs_map_free(&statep->scf_reg_drvtrc_handle); + statep->resource_flag &= ~S_DID_REG6; + } + + SCFDBGMSG(SCF_DBGFLAG_SYS, SCF_FUNC_NAME ": end"); +} + + +/* + * scf_send_cmd_check_bufful() + * + * Description: SCF command send and buffer busy check processing. + * + */ +int +scf_send_cmd_check_bufful(struct scf_cmd *scfcmdp) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_send_cmd_check_bufful() " + int ret = 0; + int buf_ful_cnt = scf_buf_ful_rcnt; + int rci_busy_cnt = scf_rci_busy_rcnt; + clock_t lb; + struct scf_state *statep; + int cv_ret; + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_SYS, SCF_FUNC_NAME ": start"); + + ret = scf_send_cmd(scfcmdp); + + while (((scfcmdp->stat0 == BUF_FUL) && (buf_ful_cnt != 0)) || + ((scfcmdp->stat0 == RCI_BUSY) && (rci_busy_cnt != 0))) { + if (scfcmdp->stat0 == BUF_FUL) { + buf_ful_cnt--; + lb = ddi_get_lbolt(); + lb += drv_usectohz(SCF_MIL2MICRO(scf_buf_ful_rtime)); + cv_ret = 0; + while (cv_ret != (-1)) { + SC_DBG_DRV_TRACE(TC_T_WAIT, __LINE__, + &scf_comtbl.cmdbusy_cv, + sizeof (kcondvar_t)); + if ((cv_ret = + cv_timedwait_sig(&scf_comtbl.cmdbusy_cv, + &scf_comtbl.all_mutex, lb)) == 0) { + SC_DBG_DRV_TRACE(TC_KILL, __LINE__, + &scf_comtbl.cmdbusy_cv, + sizeof (kcondvar_t)); + ret = EINTR; + goto END_send_cmd_check_bufful; + } + } + } else if (scfcmdp->stat0 == RCI_BUSY) { + rci_busy_cnt--; + lb = ddi_get_lbolt(); + lb += drv_usectohz(SCF_MIL2MICRO(scf_rci_busy_rtime)); + cv_ret = 0; + while (cv_ret != (-1)) { + SC_DBG_DRV_TRACE(TC_T_WAIT, __LINE__, + &scf_comtbl.cmdbusy_cv, + sizeof (kcondvar_t)); + if ((cv_ret = + cv_timedwait_sig(&scf_comtbl.cmdbusy_cv, + &scf_comtbl.all_mutex, lb)) == 0) { + SC_DBG_DRV_TRACE(TC_KILL, __LINE__, + &scf_comtbl.cmdbusy_cv, + sizeof (kcondvar_t)); + ret = EINTR; + goto END_send_cmd_check_bufful; + } + } + } else { + break; + } + ret = scf_send_cmd(scfcmdp); + } + + if (scf_comtbl.scf_exec_p) { + statep = scf_comtbl.scf_exec_p; + } else if (scf_comtbl.scf_path_p) { + statep = scf_comtbl.scf_path_p; + } + if (statep != NULL) { + if ((scfcmdp->stat0 == BUF_FUL) && (buf_ful_cnt == 0)) { + cmn_err(CE_WARN, + "%s,Buffer busy occurred in XSCF. " + "SCF command = 0x%02x%02x\n", + &statep->pathname[0], + scfcmdp->subcmd, scfcmdp->cmd); + } else if ((scfcmdp->stat0 == RCI_BUSY) && + (rci_busy_cnt == 0)) { + cmn_err(CE_WARN, + "%s,RCI busy occurred in XSCF. " + "SCF command = 0x%02x%02x\n", + &statep->pathname[0], + scfcmdp->subcmd, scfcmdp->cmd); + } + } + +/* + * END_send_cmd_check_bufful + */ + END_send_cmd_check_bufful: + + SCFDBGMSG1(SCF_DBGFLAG_SYS, SCF_FUNC_NAME ": end return = %d", ret); + return (ret); + +} + + +/* + * scf_send_cmd() + * + * Description: Synchronized SCF command send processing. + * + */ +int +scf_send_cmd(struct scf_cmd *scfcmdp) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_send_cmd() " + struct scf_state *statep; + int ret = 0; + int offline_ret; + int cmdbusy_ret; + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_SYS, SCF_FUNC_NAME ": start"); + + scfcmdp->stat0 = 0; + /* Check SCF command send sync re-start */ + if (scfcmdp->flag == SCF_USE_START) { + if (scf_comtbl.path_stop_flag != 0) { + /* Check path stop */ + scf_comtbl.path_stop_flag = 0; + goto END_scf_send_cmd; + } + goto END_scf_send_cmd99; + } + /* Check SCF command send sync re-stop */ + if ((scfcmdp->flag == SCF_USE_STOP) && + (scf_comtbl.path_stop_flag != 0)) { + goto STOP_scf_send_cmd; + } + /* Check SCF command send sync stop status */ + if ((scfcmdp->flag & SCF_USE_SP) != 0) { + goto SP_scf_send_cmd; + } + /* IOCTL/DETACH/SUSPEND send sync */ + while (scf_comtbl.cmd_busy != 0) { + scf_comtbl.cmd_wait += 1; + SC_DBG_DRV_TRACE(TC_SIGNAL, __LINE__, &scf_comtbl.cmd_cv, + sizeof (kcondvar_t)); + if (cv_wait_sig(&scf_comtbl.cmd_cv, + &scf_comtbl.all_mutex) == 0) { + SC_DBG_DRV_TRACE(TC_KILL, __LINE__, &scf_comtbl.cmd_cv, + sizeof (kcondvar_t)); + scf_comtbl.cmd_wait -= 1; + ret = EINTR; + goto END_scf_send_cmd99; + } + scf_comtbl.cmd_wait -= 1; + } + scf_comtbl.cmd_busy = 1; + +/* + * STOP_scf_send_cmd + */ + STOP_scf_send_cmd: + + /* Check SUSPEND flag */ + if (scf_comtbl.suspend_flag) { + ret = EBUSY; + scfcmdp->stat0 = SCF_STAT0_NOT_PATH; + goto END_scf_send_cmd; + } + + (void) scf_path_check(&statep); + if (statep == NULL) { + /* not exec SCF device */ + ret = EIO; + scfcmdp->stat0 = SCF_STAT0_NOT_PATH; + goto END_scf_send_cmd; + } + + offline_ret = scf_offline_check(statep, FLAG_ON); + cmdbusy_ret = scf_cmdbusy_check(statep); + + /* send comannd for interrupt */ + while ((scf_comtbl.scf_cmd_exec_flag != 0) || + (offline_ret != SCF_PATH_ONLINE) || + (cmdbusy_ret != SCF_COMMAND_READY)) { + scf_comtbl.cmd_busy_wait = 1; + SC_DBG_DRV_TRACE(TC_SIGNAL, __LINE__, &scf_comtbl.cmdwait_cv, + sizeof (kcondvar_t)); + if (cv_wait_sig(&scf_comtbl.cmdwait_cv, + &scf_comtbl.all_mutex) == 0) { + SC_DBG_DRV_TRACE(TC_KILL, __LINE__, + &scf_comtbl.cmdwait_cv, sizeof (kcondvar_t)); + scf_comtbl.cmd_busy_wait = 0; + ret = EINTR; + goto END_scf_send_cmd; + } + scf_comtbl.cmd_busy_wait = 0; + + (void) scf_path_check(&statep); + if (statep == NULL) { + /* not exec SCF device */ + ret = EIO; + scfcmdp->stat0 = SCF_STAT0_NOT_PATH; + goto END_scf_send_cmd; + } + + offline_ret = scf_offline_check(statep, FLAG_ON); + cmdbusy_ret = scf_cmdbusy_check(statep); + + if ((scf_comtbl.scf_cmd_exec_flag == 0) && + (offline_ret != SCF_PATH_ONLINE)) { + scf_timer_stop(SCF_TIMERCD_CMDBUSY); + scf_timer_stop(SCF_TIMERCD_ONLINE); + ret = EBUSY; + scfcmdp->stat0 = SCF_STAT0_NOT_PATH; + goto END_scf_send_cmd; + } + } + +/* + * SP_scf_send_cmd + */ + SP_scf_send_cmd: + + /* Check SUSPEND flag */ + if (scf_comtbl.suspend_flag) { + ret = EBUSY; + scfcmdp->stat0 = SCF_STAT0_NOT_PATH; + goto END_scf_send_cmd; + } + if ((statep = scf_comtbl.scf_exec_p) == 0) { + ret = EIO; + scfcmdp->stat0 = SCF_STAT0_NOT_PATH; + goto END_scf_send_cmd; + } + + if (scfcmdp->flag == SCF_USE_STOP) { + /* SCF command send sync stop */ + scf_comtbl.path_stop_flag = 1; + goto END_scf_send_cmd99; + } + + bcopy((char *)scfcmdp, (char *)&scfcmd_save, sizeof (struct scf_cmd)); + if (scfcmdp->sbuf != NULL) { + scfcmd_save.sbuf = &scf_sbuf_save[0]; + if (scfcmdp->scount) { + bcopy(scfcmdp->sbuf, scf_sbuf_save, scfcmdp->scount); + } + } + if (scfcmdp->rbuf != NULL) { + scfcmd_save.rbuf = &scf_rbuf_save[0]; + } + scfcmd_save.flag &= (~SCF_USE_SP); + scf_i_send_cmd(&scfcmd_save, statep); + scf_comtbl.scf_cmdp = &scfcmd_save; + + scf_comtbl.scf_exec_cmd_id = 1; + + scf_comtbl.cmd_end_wait = 1; + while (scf_comtbl.cmd_end_wait != 0) { + SC_DBG_DRV_TRACE(TC_SIGNAL, __LINE__, &scf_comtbl.cmdend_cv, + sizeof (kcondvar_t)); + if (cv_wait_sig(&scf_comtbl.cmdend_cv, + &scf_comtbl.all_mutex) == 0) { + SC_DBG_DRV_TRACE(TC_KILL, __LINE__, + &scf_comtbl.cmdend_cv, sizeof (kcondvar_t)); + scf_comtbl.cmd_end_wait = 0; + ret = EINTR; + goto END_scf_send_cmd; + } + } + scfcmdp->stat0 = scfcmd_save.stat0; + scfcmdp->rbufleng = scfcmd_save.rbufleng; + scfcmdp->status = scfcmd_save.status; + if (scfcmdp->rbuf != NULL) { + if (scfcmdp->rbufleng < scfcmdp->rcount) { + bcopy(&scf_rbuf_save[0], scfcmdp->rbuf, + scfcmdp->rbufleng); + } else { + bcopy(&scf_rbuf_save[0], scfcmdp->rbuf, + scfcmdp->rcount); + } + } + scf_comtbl.cmd_end_wait = 0; + + switch (scfcmdp->stat0) { + case NORMAL_END: + break; + + case E_NOT_SUPPORT: + case RCI_NS: + ret = ENOTSUP; + break; + + default: + /* BUF_FUL/RCI_BUSY/other */ + ret = EIO; + } + + if ((scfcmdp->flag & SCF_USE_SP) != 0) { + goto END_scf_send_cmd99; + } + +/* + * END_scf_send_cmd + */ + END_scf_send_cmd: + + scf_comtbl.cmd_busy = 0; + if (scf_comtbl.cmd_wait) { + cv_signal(&scf_comtbl.cmd_cv); + SC_DBG_DRV_TRACE(TC_SIGNAL, __LINE__, &scf_comtbl.cmd_cv, + sizeof (kcondvar_t)); + } + + if ((scfcmdp->flag & SCF_USE_SP) != 0) { + scf_comtbl.path_stop_flag = 0; + } + +/* + * END_scf_send_cmd99 + */ + END_scf_send_cmd99: + + SCFDBGMSG1(SCF_DBGFLAG_SYS, SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +/* + * scf_i_send_cmd() + * + * Description: SCF command send processing. (for hard access) + * + */ +void +scf_i_send_cmd(struct scf_cmd *scfcmdp, struct scf_state *statep) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_i_send_cmd() " + uint8_t sdata[16]; + uint8_t *wk_charp; + uint8_t sum = SCF_MAGICNUMBER_S; + uint32_t sum4 = SCF_MAGICNUMBER_L; + int scount; + int wkleng; + int ii; + uint8_t *wk_in_p; + uint8_t *wk_out_p; + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_SYS, SCF_FUNC_NAME ": start"); + + bzero((void *)sdata, 16); + + switch (scfcmdp->flag) { + case SCF_USE_S_BUF: + case SCF_USE_SSBUF: + case SCF_USE_SLBUF: + /* + * Use Tx data register, Not use Tx buffer data + */ + /* Set Tx data register memo */ + wk_charp = (uint8_t *)&scfcmdp->sbuf[0]; + if (scfcmdp->scount < SCF_S_CNT_16) { + scount = scfcmdp->scount; + } else { + scount = SCF_S_CNT_15; + } + for (ii = 0; ii < scount; ii++, wk_charp++) { + sdata[ii] = *wk_charp; + } + + /* Set CMD_SPARE data */ + if (scfcmdp->cmd == CMD_SPARE) { + sdata[12] = scfcmdp->cexr[0]; + sdata[13] = scfcmdp->cexr[1]; + } + + break; + + case SCF_USE_L_BUF: + case SCF_USE_LSBUF: + /* + * Use Tx data register, Use Tx buffer data + */ + /* Make Tx buffer data sum */ + for (ii = 0; ii < (scfcmdp->scount / 4); ii++) { + sum4 += ((scfcmdp->sbuf[ii * 4 + 0] << 24) | + (scfcmdp->sbuf[ii * 4 + 1] << 16) | + (scfcmdp->sbuf[ii * 4 + 2] << 8) | + (scfcmdp->sbuf[ii * 4 + 3])); + } + if ((scfcmdp->scount % 4) == 3) { + sum4 += ((scfcmdp->sbuf[ii * 4 + 0] << 24) | + (scfcmdp->sbuf[ii * 4 + 1] << 16) | + (scfcmdp->sbuf[ii * 4 + 2] << 8)); + } else if ((scfcmdp->scount % 4) == 2) { + sum4 += ((scfcmdp->sbuf[ii * 4 + 0] << 24) | + (scfcmdp->sbuf[ii * 4 + 1] << 16)); + } else if ((scfcmdp->scount % 4) == 1) { + sum4 += (scfcmdp->sbuf[ii * 4 + 0] << 24); + } + + /* Set Tx data register memo : data length */ + wk_charp = (uint8_t *)&scfcmdp->scount; + for (ii = 0; ii < 4; ii++, wk_charp++) { + sdata[ii] = *wk_charp; + } + + /* Set Tx data register memo : sum */ + wk_charp = (uint8_t *)&sum4; + for (ii = 8; ii < 12; ii++, wk_charp++) { + sdata[ii] = *wk_charp; + } + + /* Set CMD_SPARE data */ + if (scfcmdp->cmd == CMD_SPARE) { + sdata[12] = scfcmdp->cexr[0]; + sdata[13] = scfcmdp->cexr[1]; + } + + /* SRAM data write */ + wk_in_p = (uint8_t *)scfcmdp->sbuf; + wk_out_p = (uint8_t *)&statep->scf_sys_sram->DATA[0]; + for (ii = 0; ii < scfcmdp->scount; + ii++, wk_in_p++, wk_out_p++) { + SCF_DDI_PUT8(statep, statep->scf_sys_sram_handle, + wk_out_p, *wk_in_p); + } + + break; + } + + /* Make Tx data sum */ + for (ii = 0; ii < SCF_S_CNT_15; ii++) { + sum += sdata[ii]; + } + /* Set Tx data sum */ + sdata[15] = sum; + + /* TxDATA register set */ + statep->reg_tdata[0] = + (sdata[0] << 24) | (sdata[1] << 16) | + (sdata[2] << 8) | sdata[3]; + SCF_DDI_PUT32(statep, statep->scf_regs_handle, + &statep->scf_regs->TDATA0, statep->reg_tdata[0]); + + statep->reg_tdata[1] = + (sdata[4] << 24) | (sdata[5] << 16) | + (sdata[6] << 8) | sdata[7]; + SCF_DDI_PUT32(statep, statep->scf_regs_handle, + &statep->scf_regs->TDATA1, statep->reg_tdata[1]); + + SC_DBG_DRV_TRACE(TC_W_TDATA0, __LINE__, &statep->reg_tdata[0], + sizeof (statep->reg_tdata[0]) + sizeof (statep->reg_tdata[1])); + + statep->reg_tdata[2] = + (sdata[8] << 24) | (sdata[9] << 16) | + (sdata[10] << 8) | sdata[11]; + SCF_DDI_PUT32(statep, statep->scf_regs_handle, + &statep->scf_regs->TDATA2, statep->reg_tdata[2]); + + statep->reg_tdata[3] = + (sdata[12] << 24) | (sdata[13] << 16) | + (sdata[14] << 8) | sdata[15]; + SCF_DDI_PUT32(statep, statep->scf_regs_handle, + &statep->scf_regs->TDATA3, statep->reg_tdata[3]); + + SC_DBG_DRV_TRACE(TC_W_TDATA2, __LINE__, &statep->reg_tdata[2], + sizeof (statep->reg_tdata[2]) + sizeof (statep->reg_tdata[3])); + + /* SCF command extendedregister set */ + if (scf_comtbl.scf_cmd_resend_flag == 0) { + statep->reg_command_exr = 0x00; + } else { + scf_comtbl.scf_cmd_resend_flag = 0; + statep->reg_command_exr = COMMAND_ExR_RETRY; + } + SCF_DDI_PUT8(statep, statep->scf_regs_handle, + &statep->scf_regs->COMMAND_ExR, statep->reg_command_exr); + SC_DBG_DRV_TRACE(TC_W_COMMAND_ExR, __LINE__, &statep->reg_command_exr, + sizeof (statep->reg_command_exr)); + + /* SCF command register set */ + statep->reg_command = ((scfcmdp->subcmd << 8) | scfcmdp->cmd); + + /* Set sub command code */ + SCF_DDI_PUT8(statep, statep->scf_regs_handle, + (uint8_t *)&statep->scf_regs->COMMAND, + (uint8_t)(statep->reg_command >> 8)); + /* Set command code : SCF interrupt */ + SCF_DDI_PUT8(statep, statep->scf_regs_handle, + (uint8_t *)&statep->scf_regs->COMMAND + 1, + (uint8_t)statep->reg_command); + + SC_DBG_DRV_TRACE(TC_W_COMMAND, __LINE__, &statep->reg_command, + sizeof (statep->reg_command)); + /* Register read sync */ + scf_rs16 = SCF_DDI_GET16(statep, statep->scf_regs_handle, + &statep->scf_regs->COMMAND); + + SCFDBGMSG2(SCF_DBGFLAG_REG, "CMD = 0x%04x CMDExR = 0x%02x", + statep->reg_command, statep->reg_command_exr); + SCFDBGMSG4(SCF_DBGFLAG_REG, "TxDR = 0x%08x 0x%08x 0x%08x 0x%08x", + statep->reg_tdata[0], statep->reg_tdata[1], + statep->reg_tdata[2], statep->reg_tdata[3]); + + scf_comtbl.scf_cmd_exec_flag = 1; + scf_comtbl.scf_exec_cmd_id = 0; + + /* SCF command timer start */ + scf_timer_start(SCF_TIMERCD_CMDEND); + + /* SRAM trace */ + SCF_SRAM_TRACE(statep, DTC_CMD); + SCF_SRAM_TRACE(statep, DTC_SENDDATA); + + if (((scfcmdp->flag == SCF_USE_L_BUF) || + (scfcmdp->flag == SCF_USE_LSBUF)) && + (scfcmdp->scount != 0)) { + if (scfcmdp->scount > scf_sram_trace_data_size) { + scount = scf_sram_trace_data_size; + } else { + scount = scfcmdp->scount; + } + wk_in_p = (uint8_t *)scfcmdp->sbuf; + while (scount != 0) { + bzero((void *)&statep->memo_scf_drvtrc.INFO[0], + sizeof (statep->memo_scf_drvtrc.INFO)); + wk_out_p = (uint8_t *)&statep->memo_scf_drvtrc.INFO[0]; + if (scount > sizeof (statep->memo_scf_drvtrc.INFO)) { + wkleng = sizeof (statep->memo_scf_drvtrc.INFO); + } else { + wkleng = scount; + } + scount -= wkleng; + bcopy(wk_in_p, wk_out_p, wkleng); + SCF_SRAM_TRACE(statep, DTC_SENDDATA_SRAM); + wk_in_p += wkleng; + } + } + + SC_DBG_DRV_TRACE(TC_SEND, __LINE__, &scfcmdp->flag, 8); + SC_DBG_DRV_TRACE(TC_SEND, __LINE__, &scfcmdp->scount, 8); + + SCF_DBG_TEST_SEND_CMD(statep, scfcmdp); + + SCFDBGMSG(SCF_DBGFLAG_SYS, SCF_FUNC_NAME ": end"); +} + + +/* + * panic send cmd function + */ +void +scf_p_send_cmd(struct scf_cmd *scfcmdp, struct scf_state *statep) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_p_send_cmd() " + uint8_t sdata[16]; + uint8_t *wk_charp; + uint8_t sum = SCF_MAGICNUMBER_S; + uint32_t sum4 = SCF_MAGICNUMBER_L; + int scount; + int ii; + uint8_t *wk_in_p; + uint8_t *wk_out_p; + uint16_t wk_int16; + + SCFDBGMSG(SCF_DBGFLAG_FOCK, SCF_FUNC_NAME ": start"); + + bzero((void *)sdata, 16); + + switch (scfcmdp->flag) { + case SCF_USE_S_BUF: + case SCF_USE_SSBUF: + case SCF_USE_SLBUF: + /* + * Use Tx data register, Not use Tx buffer data + */ + /* Set Tx data register memo */ + wk_charp = (uint8_t *)&scfcmdp->sbuf[0]; + if (scfcmdp->scount < SCF_S_CNT_16) { + scount = scfcmdp->scount; + } else { + scount = SCF_S_CNT_15; + } + for (ii = 0; ii < scount; ii++, wk_charp++) { + sdata[ii] = *wk_charp; + } + + break; + + case SCF_USE_L_BUF: + case SCF_USE_LSBUF: + /* + * Use Tx data register, Use Tx buffer data + */ + /* Make Tx buffer data sum */ + for (ii = 0; ii < (scfcmdp->scount / 4); ii++) { + sum4 += ((scfcmdp->sbuf[ii * 4 + 0] << 24) | + (scfcmdp->sbuf[ii * 4 + 1] << 16) | + (scfcmdp->sbuf[ii * 4 + 2] << 8) | + (scfcmdp->sbuf[ii * 4 + 3])); + } + if ((scfcmdp->scount % 4) == 3) { + sum4 += ((scfcmdp->sbuf[ii * 4 + 0] << 24) | + (scfcmdp->sbuf[ii * 4 + 1] << 16) | + (scfcmdp->sbuf[ii * 4 + 2] << 8)); + } else if ((scfcmdp->scount % 4) == 2) { + sum4 += ((scfcmdp->sbuf[ii * 4 + 0] << 24) | + (scfcmdp->sbuf[ii * 4 + 1] << 16)); + } else if ((scfcmdp->scount % 4) == 1) { + sum4 += (scfcmdp->sbuf[ii * 4 + 0] << 24); + } + + /* Set Tx data register memo : data length */ + wk_charp = (uint8_t *)&scfcmdp->scount; + for (ii = 0; ii < 4; ii++, wk_charp++) { + sdata[ii] = *wk_charp; + } + + /* Set Tx data register memo : sum */ + wk_charp = (uint8_t *)&sum4; + for (ii = 8; ii < 12; ii++, wk_charp++) { + sdata[ii] = *wk_charp; + } + + /* Set CMD_SPARE data */ + if (scfcmdp->cmd == CMD_SPARE) { + sdata[12] = scfcmdp->cexr[0]; + sdata[13] = scfcmdp->cexr[1]; + } + + /* SRAM data write */ + wk_in_p = (uint8_t *)scfcmdp->sbuf; + wk_out_p = (uint8_t *)&statep->scf_sys_sram->DATA[0]; + for (ii = 0; ii < scfcmdp->scount; + ii++, wk_in_p++, wk_out_p++) { + SCF_P_DDI_PUT8(statep->scf_sys_sram_handle, + wk_out_p, *wk_in_p); + } + + break; + } + + /* Make Tx data sum */ + for (ii = 0; ii < SCF_S_CNT_15; ii++) { + sum += sdata[ii]; + } + /* Set Tx data sum */ + sdata[15] = sum; + + /* TxDATA register set */ + SCF_P_DDI_PUT32(statep->scf_regs_handle, &statep->scf_regs->TDATA0, + (sdata[0] << 24) | (sdata[1] << 16) | + (sdata[2] << 8) | sdata[3]); + SCF_P_DDI_PUT32(statep->scf_regs_handle, &statep->scf_regs->TDATA1, + (sdata[4] << 24) | (sdata[5] << 16) | + (sdata[6] << 8) | sdata[7]); + SCF_P_DDI_PUT32(statep->scf_regs_handle, &statep->scf_regs->TDATA2, + (sdata[8] << 24) | (sdata[9] << 16) | + (sdata[10] << 8) | sdata[11]); + SCF_P_DDI_PUT32(statep->scf_regs_handle, &statep->scf_regs->TDATA3, + (sdata[12] << 24) | (sdata[13] << 16) | + (sdata[14] << 8) | sdata[15]); + + /* SCF command extendedregister set */ + SCF_P_DDI_PUT8(statep->scf_regs_handle, + &statep->scf_regs->COMMAND_ExR, 0x00); + + /* SCF command register set */ + SCF_P_DDI_PUT8(statep->scf_regs_handle, + (uint8_t *)&statep->scf_regs->COMMAND, + (uint8_t)scfcmdp->subcmd); + SCF_P_DDI_PUT8(statep->scf_regs_handle, + (uint8_t *)&statep->scf_regs->COMMAND + 1, + (uint8_t)scfcmdp->cmd); + /* Register read sync */ + wk_int16 = SCF_P_DDI_GET16(statep->scf_regs_handle, + &statep->scf_regs->COMMAND); + scf_panic_trc_command = wk_int16; + + SCFDBGMSG(SCF_DBGFLAG_FOCK, SCF_FUNC_NAME ": end"); +} + + +/* + * SCF path status check + */ +int +scf_path_check(scf_state_t **statep) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_path_check() " + int ret; + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_SYS, SCF_FUNC_NAME ": start"); + + if (scf_comtbl.scf_exec_p != NULL) { + /* SCF path exec status */ + if (statep != NULL) { + *statep = scf_comtbl.scf_exec_p; + } + + ret = scf_offline_check(scf_comtbl.scf_exec_p, FLAG_ON); + + } else if (scf_comtbl.scf_path_p != NULL) { + /* SCF path change status */ + if (statep != NULL) { + *statep = scf_comtbl.scf_path_p; + } + + ret = scf_offline_check(scf_comtbl.scf_path_p, FLAG_ON); + + if (ret == SCF_PATH_ONLINE) { + SCFDBGMSG(SCF_DBGFLAG_SYS, "SCF path change status"); + ret = SCF_PATH_CHANGE; + } + + } else { + /* SCF path halt status */ + if (statep != NULL) { + *statep = NULL; + } + + SCFDBGMSG(SCF_DBGFLAG_SYS, "SCF path halt status"); + ret = SCF_PATH_HALT; + + } + + SCF_DBG_MAKE_PATH_CHECK(ret); + + SCFDBGMSG1(SCF_DBGFLAG_SYS, SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +/* + * ESCF offline check + */ +int +scf_offline_check(scf_state_t *statep, uint_t timer_exec_flag) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_offline_check() " + int ret; + uint8_t scf_unit; + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_SYS, SCF_FUNC_NAME ": start"); + + /* Get SCF Status extended register */ + statep->reg_status_exr = SCF_DDI_GET32(statep, statep->scf_regs_handle, + &statep->scf_regs->STATUS_ExR); + SC_DBG_DRV_TRACE(TC_R_STATUS_ExR, __LINE__, &statep->reg_status_exr, + sizeof (statep->reg_status_exr)); + + SCF_DBG_MAKE_ONLINE(statep->reg_status_exr); + + /* Check SCF online */ + if ((statep->reg_status_exr & STATUS_SCF_STATUS) == STATUS_SCF_ONLINE) { + if (scf_comtbl.scf_status == SCF_STATUS_OFFLINE) { + cmn_err(CE_NOTE, "%s: SCF online.\n", scf_driver_name); + } + scf_comtbl.scf_status = SCF_STATUS_ONLINE; + + if (timer_exec_flag == FLAG_ON) { + /* Check online wait timer exec */ + if (scf_timer_check(SCF_TIMERCD_ONLINE) == + SCF_TIMER_NOT_EXEC) { + ret = SCF_PATH_ONLINE; + } else { + ret = SCF_PATH_OFFLINE_DRV; + } + } else { + ret = SCF_PATH_ONLINE; + } + } else { + if (scf_comtbl.scf_status != SCF_STATUS_OFFLINE) { + if (statep->reg_status_exr & STATUS_SCF_NO) { + scf_unit = 1; + } else { + scf_unit = 0; + } + cmn_err(CE_WARN, + "%s: SCF went to offline mode. unit=%d", + scf_driver_name, scf_unit); + } + scf_comtbl.scf_status = SCF_STATUS_OFFLINE; + + if (timer_exec_flag == FLAG_ON) { + /* Check online wait timer exec */ + if (scf_timer_check(SCF_TIMERCD_ONLINE) == + SCF_TIMER_NOT_EXEC) { + /* DCSP interface stop */ + scf_dscp_stop(FACTOR_OFFLINE); + + /* SCF online timer start */ + statep->online_to_rcnt = 0; + scf_timer_start(SCF_TIMERCD_ONLINE); + } + } + SCFDBGMSG(SCF_DBGFLAG_SYS, "SCF path offline"); + ret = SCF_PATH_OFFLINE; + } + + SCF_DBG_MAKE_OFFLINE_CHECK(ret); + + SCFDBGMSG1(SCF_DBGFLAG_SYS, SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +/* + * SCF command busy check + */ +int +scf_cmdbusy_check(scf_state_t *statep) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_cmdbusy_check() " + int ret; + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_SYS, SCF_FUNC_NAME ": start"); + + SCF_DBG_RTN_MAKE_CMD_READY; + + /* Get SCF command register */ + statep->reg_command = SCF_DDI_GET16(statep, statep->scf_regs_handle, + &statep->scf_regs->COMMAND); + SC_DBG_DRV_TRACE(TC_R_COMMAND, __LINE__, &statep->reg_command, + sizeof (statep->reg_command)); + statep->reg_command_exr = SCF_DDI_GET8(statep, statep->scf_regs_handle, + &statep->scf_regs->COMMAND_ExR); + SC_DBG_DRV_TRACE(TC_R_COMMAND_ExR, __LINE__, &statep->reg_command_exr, + sizeof (statep->reg_command_exr)); + + SCF_DBG_MAKE_CMD_BUSY(statep->reg_command, statep->reg_command_exr); + + /* Check busy flag */ + if (((statep->reg_command & COMMAND_BUSY) == 0x0000) && + ((statep->reg_command_exr & COMMAND_ExR_BUSY) == 0x00)) { + /* Check busy timer exec */ + if (scf_timer_check(SCF_TIMERCD_CMDBUSY) == + SCF_TIMER_NOT_EXEC) { + ret = SCF_COMMAND_READY; + SCFDBGMSG(SCF_DBGFLAG_SYS, "SCF command busy"); + } else { + ret = SCF_COMMAND_BUSY_DRV; + SCFDBGMSG(SCF_DBGFLAG_SYS, "SCF command exr busy"); + } + } else { + if (scf_comtbl.scf_cmd_exec_flag == FLAG_OFF) { + /* Check busy timer exec */ + if (scf_timer_check(SCF_TIMERCD_CMDBUSY) == + SCF_TIMER_NOT_EXEC) { + /* busy timer start */ + statep->devbusy_to_rcnt = 0; + scf_timer_start(SCF_TIMERCD_CMDBUSY); + } + } + ret = SCF_COMMAND_BUSY; + } + + SCFDBGMSG1(SCF_DBGFLAG_SYS, SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +void +scf_alivecheck_start(scf_state_t *statep) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_alivecheck_start() " + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_SYS, SCF_FUNC_NAME ": start"); + + /* Check alive check exec */ + if (scf_comtbl.alive_running == SCF_ALIVE_START) { + /* Alive check value initialize */ + scf_acr_phase_code = 0; + scf_comtbl.scf_alive_int_count = scf_alive_interval_time / 3; + + /* Alive timer register initialize */ + statep->reg_atr = ATR_INTERVAL_STOP; + SCF_DDI_PUT8(statep, statep->scf_regs_handle, + &statep->scf_regs->ATR, statep->reg_atr); + SC_DBG_DRV_TRACE(TC_W_ATR, __LINE__, &statep->reg_atr, + sizeof (statep->reg_atr)); + /* Register read sync */ + scf_rs8 = SCF_DDI_GET8(statep, statep->scf_regs_handle, + &statep->scf_regs->ATR); + + /* Alive Interrupt enable */ + statep->reg_control |= CONTROL_ALIVEINE; + SCF_DDI_PUT16(statep, statep->scf_regs_c_handle, + &statep->scf_regs_c->CONTROL, statep->reg_control); + SC_DBG_DRV_TRACE(TC_W_CONTROL, __LINE__, &statep->reg_control, + sizeof (statep->reg_control)); + /* Register read sync */ + scf_rs16 = SCF_DDI_GET16(statep, statep->scf_regs_c_handle, + &statep->scf_regs_c->CONTROL); + + /* Alive timer register set */ + statep->reg_atr = ATR_INTERVAL_30S; + SCF_DDI_PUT8(statep, statep->scf_regs_handle, + &statep->scf_regs->ATR, statep->reg_atr); + SC_DBG_DRV_TRACE(TC_W_ATR, __LINE__, &statep->reg_atr, + sizeof (statep->reg_atr)); + /* Register read sync */ + scf_rs8 = SCF_DDI_GET8(statep, statep->scf_regs_handle, + &statep->scf_regs->ATR); + + /* Alive check register set */ + statep->reg_acr = scf_acr_phase_code | ACR_ALIVE_INT; + SCF_DDI_PUT8(statep, statep->scf_regs_handle, + &statep->scf_regs->ACR, statep->reg_acr); + SC_DBG_DRV_TRACE(TC_W_ACR, __LINE__, &statep->reg_acr, + sizeof (statep->reg_acr)); + /* Register read sync */ + scf_rs8 = SCF_DDI_GET8(statep, statep->scf_regs_handle, + &statep->scf_regs->ACR); + + SCFDBGMSG1(SCF_DBGFLAG_REG, "ACR = 0x%02x", statep->reg_acr); + + scf_acr_phase_code++; + + SCF_DBG_TEST_ALIVE_START(statep); + } + + SCFDBGMSG(SCF_DBGFLAG_SYS, SCF_FUNC_NAME ": end"); +} + + +void +scf_alivecheck_stop(scf_state_t *statep) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_alivecheck_stop() " + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_SYS, SCF_FUNC_NAME ": start"); + + /* Alive Interrupt disable */ + statep->reg_control &= (~CONTROL_ALIVEINE); + SCF_DDI_PUT16(statep, statep->scf_regs_c_handle, + &statep->scf_regs_c->CONTROL, statep->reg_control); + SC_DBG_DRV_TRACE(TC_W_CONTROL, __LINE__, &statep->reg_control, + sizeof (statep->reg_control)); + /* Register read sync */ + scf_rs16 = SCF_DDI_GET16(statep, statep->scf_regs_c_handle, + &statep->scf_regs_c->CONTROL); + + /* Alive timer register clear */ + statep->reg_atr = ATR_INTERVAL_STOP; + SCF_DDI_PUT8(statep, statep->scf_regs_handle, + &statep->scf_regs->ATR, statep->reg_atr); + SC_DBG_DRV_TRACE(TC_W_ATR, __LINE__, &statep->reg_atr, + sizeof (statep->reg_atr)); + /* Register read sync */ + scf_rs8 = SCF_DDI_GET8(statep, statep->scf_regs_handle, + &statep->scf_regs->ATR); + + SCF_DBG_TEST_ALIVE_STOP(statep); + + SCFDBGMSG(SCF_DBGFLAG_SYS, SCF_FUNC_NAME ": end"); +} + + +/* + * forbid SCF interrupt + */ +void +scf_forbid_intr(struct scf_state *statep) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_forbid_intr() " + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_SYS, SCF_FUNC_NAME ": start"); + + /* Interrupt disable */ + statep->reg_control = CONTROL_DISABLE; + SCF_DDI_PUT16(statep, statep->scf_regs_c_handle, + &statep->scf_regs_c->CONTROL, statep->reg_control); + SC_DBG_DRV_TRACE(TC_W_CONTROL, __LINE__, &statep->reg_control, + sizeof (statep->reg_control)); + /* Register read sync */ + scf_rs16 = SCF_DDI_GET16(statep, statep->scf_regs_c_handle, + &statep->scf_regs_c->CONTROL); + + scf_alivecheck_stop(statep); + + statep->resource_flag &= (~S_DID_REGENB); + + SCFDBGMSG(SCF_DBGFLAG_SYS, SCF_FUNC_NAME ": end"); +} + + +/* + * permit SCF interrupt + */ +void +scf_permit_intr(struct scf_state *statep, int flag) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_permit_intr() " + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_SYS, SCF_FUNC_NAME ": start"); + + if (flag) { + /* SCF Status register interrupt clear */ + SCF_DDI_PUT16(statep, statep->scf_regs_handle, + &statep->scf_regs->STATUS, 0xffff); + /* Register read sync */ + scf_rs16 = SCF_DDI_GET16(statep, statep->scf_regs_handle, + &statep->scf_regs->STATUS); + + /* SCF Status extended register interrupt clear */ + SCF_DDI_PUT32(statep, statep->scf_regs_handle, + &statep->scf_regs->STATUS_ExR, 0xffffffff); + /* Register read sync */ + scf_rs32 = SCF_DDI_GET32(statep, statep->scf_regs_handle, + &statep->scf_regs->STATUS_ExR); + + /* DSCP buffer status register interrupt clear */ + SCF_DDI_PUT8(statep, statep->scf_regs_handle, + &statep->scf_regs->DSR, 0xff); + /* Register read sync */ + scf_rs8 = SCF_DDI_GET8(statep, statep->scf_regs_handle, + &statep->scf_regs->DSR); + + /* SCF interrupt status register interrupt clear */ + SCF_DDI_PUT16(statep, statep->scf_regs_c_handle, + &statep->scf_regs_c->INT_ST, + (INT_ST_PATHCHGIE | CONTROL_ALIVEINE)); + /* Register read sync */ + scf_rs16 = SCF_DDI_GET16(statep, statep->scf_regs_c_handle, + &statep->scf_regs_c->INT_ST); + } + + /* Interrupt enable */ + statep->reg_control = CONTROL_ENABLE; + SCF_DDI_PUT16(statep, statep->scf_regs_c_handle, + &statep->scf_regs_c->CONTROL, statep->reg_control); + SC_DBG_DRV_TRACE(TC_W_CONTROL, __LINE__, &statep->reg_control, + sizeof (statep->reg_control)); + /* Register read sync */ + scf_rs16 = SCF_DDI_GET16(statep, statep->scf_regs_c_handle, + &statep->scf_regs_c->CONTROL); + + statep->resource_flag |= S_DID_REGENB; + + SCFDBGMSG(SCF_DBGFLAG_SYS, SCF_FUNC_NAME ": end"); +} + + +/* + * Path status check + */ +int +scf_check_state(scf_state_t *statep) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_check_state() " + scf_state_t *wkstatep; + int ret; + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_SYS, SCF_FUNC_NAME ": start"); + + if (statep != NULL) { + if ((statep == scf_comtbl.scf_exec_p) || + (statep == scf_comtbl.scf_path_p)) { + /* PATH_STAT_ACTIVE status */ + ret = PATH_STAT_ACTIVE; + } else { + wkstatep = scf_comtbl.scf_wait_p; + while (wkstatep) { + if (statep == wkstatep) { + /* PATH_STAT_STANDBY status */ + ret = PATH_STAT_STANDBY; + goto END_check_state; + } else { + wkstatep = wkstatep->next; + } + } + wkstatep = scf_comtbl.scf_stop_p; + while (wkstatep) { + if (statep == wkstatep) { + /* PATH_STAT_STOP status */ + ret = PATH_STAT_STOP; + goto END_check_state; + } else { + wkstatep = wkstatep->next; + } + } + wkstatep = scf_comtbl.scf_err_p; + while (wkstatep) { + if (statep == wkstatep) { + /* PATH_STAT_FAIL status */ + ret = PATH_STAT_FAIL; + goto END_check_state; + } else { + wkstatep = wkstatep->next; + } + } + wkstatep = scf_comtbl.scf_disc_p; + while (wkstatep) { + if (statep == wkstatep) { + /* PATH_STAT_DISCON status */ + ret = PATH_STAT_DISCON; + goto END_check_state; + } else { + wkstatep = wkstatep->next; + } + } + /* scf_comtbl.scf_suspend_p queue */ + /* PATH_STAT_DISCON status */ + ret = PATH_STAT_EMPTY; + } + } else { + /* PATH_STAT_DISCON status */ + ret = PATH_STAT_EMPTY; + } + +/* + * END_check_state + */ + END_check_state: + + SCFDBGMSG1(SCF_DBGFLAG_SYS, SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +/* + * Multi path status change and queue change + */ +void +scf_chg_scf(scf_state_t *statep, int status) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_chg_scf() " + scf_state_t *wkstatep; + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG2(SCF_DBGFLAG_SYS, + SCF_FUNC_NAME ": start instance = %d status = %d", + statep->instance, statep->path_status); + + /* Set path status */ + if (statep->path_status != status) { + statep->old_path_status = statep->path_status; + statep->path_status = status; + } + switch (status) { + case PATH_STAT_ACTIVE: + /* Not queue change */ + break; + + case PATH_STAT_EMPTY: + /* Change empty queue */ + if (scf_comtbl.scf_suspend_p) { + wkstatep = scf_comtbl.scf_suspend_p; + while (wkstatep->next) { + wkstatep = wkstatep->next; + } + wkstatep->next = statep; + } else { + scf_comtbl.scf_suspend_p = statep; + } + statep->next = 0; + break; + + case PATH_STAT_STANDBY: + /* Change standby queue */ + if (scf_comtbl.scf_wait_p) { + wkstatep = scf_comtbl.scf_wait_p; + while (wkstatep->next) { + wkstatep = wkstatep->next; + } + wkstatep->next = statep; + } else { + scf_comtbl.scf_wait_p = statep; + } + statep->next = 0; + break; + + case PATH_STAT_STOP: + /* Change stop queue */ + if (scf_comtbl.scf_stop_p) { + wkstatep = scf_comtbl.scf_stop_p; + while (wkstatep->next) { + wkstatep = wkstatep->next; + } + wkstatep->next = statep; + } else { + scf_comtbl.scf_stop_p = statep; + } + statep->next = 0; + break; + + case PATH_STAT_FAIL: + /* Change fail queue */ + if (scf_comtbl.scf_err_p) { + wkstatep = scf_comtbl.scf_err_p; + while (wkstatep->next) { + wkstatep = wkstatep->next; + } + wkstatep->next = statep; + } else { + scf_comtbl.scf_err_p = statep; + } + statep->next = 0; + break; + + case PATH_STAT_DISCON: + /* Change disconnect queue */ + if (scf_comtbl.scf_disc_p) { + wkstatep = scf_comtbl.scf_disc_p; + while (wkstatep->next) { + wkstatep = wkstatep->next; + } + wkstatep->next = statep; + } else { + scf_comtbl.scf_disc_p = statep; + } + statep->next = 0; + break; + } + SCFDBGMSG1(SCF_DBGFLAG_SYS, SCF_FUNC_NAME ": end status = %d", + statep->path_status); +} + +/* + * Multi path queue check and delete queue + */ +void +scf_del_queue(scf_state_t *statep) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_del_queue() " + scf_state_t *wkstatep; + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG1(SCF_DBGFLAG_SYS, SCF_FUNC_NAME ": start instance = %d", + statep->instance); + + if ((wkstatep = scf_comtbl.scf_exec_p) == statep) { + /* Delete active(exec) queue */ + scf_comtbl.scf_exec_p = NULL; + return; + } else if ((wkstatep = scf_comtbl.scf_path_p) == statep) { + /* Delete active(path change) queue */ + scf_comtbl.scf_path_p = NULL; + return; + } else { + if ((wkstatep = scf_comtbl.scf_suspend_p) != 0) { + /* Delete empty(suspend) queue */ + if (wkstatep == statep) { + scf_comtbl.scf_suspend_p = wkstatep->next; + return; + } else { + while (wkstatep->next) { + if (wkstatep->next == statep) { + wkstatep->next = statep->next; + return; + } + wkstatep = wkstatep->next; + } + } + } + if ((wkstatep = scf_comtbl.scf_wait_p) != 0) { + /* Delete standby(wait) queue */ + if (wkstatep == statep) { + scf_comtbl.scf_wait_p = wkstatep->next; + return; + } else { + while (wkstatep->next) { + if (wkstatep->next == statep) { + wkstatep->next = statep->next; + return; + } + wkstatep = wkstatep->next; + } + } + } + if ((wkstatep = scf_comtbl.scf_err_p) != 0) { + /* Delete fail(error) queue */ + if (wkstatep == statep) { + scf_comtbl.scf_err_p = wkstatep->next; + return; + } else { + while (wkstatep->next) { + if (wkstatep->next == statep) { + wkstatep->next = statep->next; + return; + } + wkstatep = wkstatep->next; + } + } + } + if ((wkstatep = scf_comtbl.scf_stop_p) != 0) { + /* Delete stop queue */ + if (wkstatep == statep) { + scf_comtbl.scf_stop_p = wkstatep->next; + return; + } else { + while (wkstatep->next) { + if (wkstatep->next == statep) { + wkstatep->next = statep->next; + return; + } + wkstatep = wkstatep->next; + } + } + } + if ((wkstatep = scf_comtbl.scf_disc_p) != 0) { + /* Delete disconnect queue */ + if (wkstatep == statep) { + scf_comtbl.scf_disc_p = wkstatep->next; + return; + } else { + while (wkstatep->next) { + if (wkstatep->next == statep) { + wkstatep->next = statep->next; + return; + } + wkstatep = wkstatep->next; + } + } + } + } + SCFDBGMSG(SCF_DBGFLAG_SYS, SCF_FUNC_NAME ": end"); +} + + +/* + * SCF command send sync + */ +int +scf_make_send_cmd(struct scf_cmd *scfcmdp, uint_t flag) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_make_send_cmd() " + /* falg = SCF_USE_STOP : SCF command stop wait */ + /* falg = SCF_USE_START : SCF_USE_STOP signal */ + + int ret; + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG1(SCF_DBGFLAG_SYS, SCF_FUNC_NAME ": start flag = 0x%08x", + flag); + + scfcmdp->cmd = 0; + scfcmdp->subcmd = 0; + scfcmdp->scount = 0; + scfcmdp->sbuf = NULL; + scfcmdp->rcount = 0; + scfcmdp->rbuf = NULL; + scfcmdp->flag = flag; + ret = scf_send_cmd_check_bufful(scfcmdp); + + SCFDBGMSG1(SCF_DBGFLAG_SYS, SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +/* + * scf_sram_trace_init() + * + * SRAM trace initialize processing. + * + */ +void +scf_sram_trace_init(struct scf_state *statep) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_sram_trace_init() " + uint8_t wk_drv_id; + uint32_t wk_data_top; + uint32_t wk_data_last; + uint32_t wk_data_write; + off_t min_len; + uint8_t *wk_in_p; + uint8_t *wk_out_p; + int wk_leng; + int ii; + uint8_t drv_name[DRV_ID_SIZE]; + uint8_t *wk_drv_vl = (uint8_t *)SCF_DRIVER_VERSION; + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_TRACE, SCF_FUNC_NAME ": start"); + + /* Check SRAM map */ + if (statep->resource_flag & S_DID_REG6) { + wk_drv_id = + SCF_DDI_GET8(statep, statep->scf_reg_drvtrc_handle, + &statep->scf_reg_drvtrc->DRV_ID[0]); + wk_data_top = + SCF_DDI_GET32(statep, statep->scf_reg_drvtrc_handle, + &statep->scf_reg_drvtrc->DATA_TOP); + wk_data_last = + SCF_DDI_GET32(statep, statep->scf_reg_drvtrc_handle, + &statep->scf_reg_drvtrc->DATA_LAST); + wk_data_write = + SCF_DDI_GET32(statep, statep->scf_reg_drvtrc_handle, + &statep->scf_reg_drvtrc->DATA_WRITE); + if ((wk_drv_id == 0) || + (wk_data_top != statep->memo_DATA_TOP) || + (wk_data_last != statep->memo_DATA_LAST) || + ((wk_data_write >= wk_data_top) && + (wk_data_write <= wk_data_last))) { + /* Make SRAM driver trace header */ + min_len = (off_t)(sizeof (scf_if_drvtrc_t) + + sizeof (scf_drvtrc_ent_t)); + if (statep->scf_reg_drvtrc_len >= min_len) { + statep->memo_DATA_TOP = + (uint32_t)(sizeof (scf_if_drvtrc_t)); + statep->memo_DATA_WRITE = + (uint32_t)(sizeof (scf_if_drvtrc_t)); + statep->memo_DATA_LAST = + (uint32_t)(statep->scf_reg_drvtrc_len - + sizeof (scf_drvtrc_ent_t)); + } else { + statep->memo_DATA_TOP = 0; + statep->memo_DATA_WRITE = 0; + statep->memo_DATA_LAST = 0; + } + SCF_DDI_PUT32(statep, statep->scf_reg_drvtrc_handle, + &statep->scf_reg_drvtrc->DATA_TOP, + statep->memo_DATA_TOP); + SCF_DDI_PUT32(statep, statep->scf_reg_drvtrc_handle, + &statep->scf_reg_drvtrc->DATA_WRITE, + statep->memo_DATA_WRITE); + SCF_DDI_PUT32(statep, statep->scf_reg_drvtrc_handle, + &statep->scf_reg_drvtrc->DATA_LAST, + statep->memo_DATA_LAST); + } else { + statep->memo_DATA_TOP = SCF_DDI_GET32(statep, + statep->scf_reg_drvtrc_handle, + &statep->scf_reg_drvtrc->DATA_TOP); + statep->memo_DATA_WRITE = SCF_DDI_GET32(statep, + statep->scf_reg_drvtrc_handle, + &statep->scf_reg_drvtrc->DATA_WRITE); + statep->memo_DATA_LAST = SCF_DDI_GET32(statep, + statep->scf_reg_drvtrc_handle, + &statep->scf_reg_drvtrc->DATA_LAST); + } + + wk_leng = sizeof (SCF_DRIVER_VERSION); + if (wk_leng > DRV_ID_SIZE) { + wk_leng = DRV_ID_SIZE; + } + wk_in_p = wk_drv_vl; + wk_out_p = (uint8_t *)&drv_name[0]; + for (ii = 0; ii < wk_leng; ii++, wk_in_p++, wk_out_p++) { + *wk_out_p = *wk_in_p; + } + for (; ii < DRV_ID_SIZE; ii++, wk_out_p++) { + *wk_out_p = ' '; + } + wk_in_p = (uint8_t *)&drv_name[0]; + wk_out_p = (uint8_t *)&statep->scf_reg_drvtrc->DRV_ID[0]; + for (ii = 0; ii < DRV_ID_SIZE; ii++, wk_in_p++, wk_out_p++) { + SCF_DDI_PUT8(statep, statep->scf_reg_drvtrc_handle, + wk_out_p, *wk_in_p); + } + } else { + statep->memo_DATA_TOP = 0; + statep->memo_DATA_WRITE = 0; + statep->memo_DATA_LAST = 0; + } + + SCFDBGMSG(SCF_DBGFLAG_TRACE, SCF_FUNC_NAME ": end"); +} + + +/* + * scf_sram_trace() + * + * SRAM trace get processing. + * + */ +void +scf_sram_trace(struct scf_state *statep, uint8_t log_id) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_sram_trace() " + uint8_t *wk_in_p; + uint8_t *wk_out_p; + clock_t clock_val; + uint32_t log_time; + uint8_t wk_log_id; + int ii; + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_TRACE, SCF_FUNC_NAME ": start"); + + if (statep->memo_DATA_WRITE) { + statep->memo_scf_drvtrc.LOG_ID = log_id; + clock_val = ddi_get_lbolt(); + log_time = (uint32_t)(drv_hztousec(clock_val) / 100000); + statep->memo_scf_drvtrc.LOG_TIME[0] = (uint8_t)(log_time >> 16); + statep->memo_scf_drvtrc.LOG_TIME[1] = (uint8_t)(log_time >> 8); + statep->memo_scf_drvtrc.LOG_TIME[2] = (uint8_t)(log_time); + + if ((log_id & DTC_MASK_HIGH) == DTC_ERRRTN) { + wk_log_id = DTC_ERRRTN; + } else { + wk_log_id = log_id; + } + + /* Check log id */ + switch (wk_log_id) { + case DTC_ONLINETO: /* SCF online timeout */ + case DTC_ONLINE: /* SCF online start */ + case DTC_OFFLINE: /* SCF offline start */ + SCF_SET_SRAM_DATA2_2(0, statep->reg_control, + statep->reg_int_st); + SCF_SET_SRAM_DATA2_2(4, statep->reg_command, + statep->reg_status); + SCF_SET_SRAM_DATA4_1(8, statep->reg_status_exr); + break; + + case DTC_SENDDATA: /* SCF send command data */ + SCF_SET_SRAM_DATA4_3(0, statep->reg_tdata[0], + statep->reg_tdata[2], statep->reg_tdata[3]); + break; + + case DTC_RECVDATA: /* SCF recv command data */ + SCF_SET_SRAM_DATA4_3(0, statep->reg_rdata[0], + statep->reg_rdata[2], statep->reg_rdata[3]); + break; + + case DTC_ERRRTN: /* SCF command retuen error */ + SCF_SET_SRAM_DATA4_3(0, statep->reg_tdata[0], + statep->reg_tdata[1], statep->reg_tdata[2]); + break; + + + case DTC_RSUMERR: /* SCF command receive sum error */ + SCF_SET_SRAM_DATA4_3(0, statep->reg_rdata[0], + statep->reg_rdata[1], statep->reg_rdata[2]); + break; + + case DTC_DSCP_TXREQ: /* DSCP TxREQ request */ + SCF_SET_SRAM_DATA2_2(0, statep->reg_control, + statep->reg_int_st); + SCF_SET_SRAM_DATA1_2(4, statep->reg_dcr, + statep->reg_dsr); + SCF_SET_SRAM_DATA2_1(6, statep->reg_txdcr_c_flag); + SCF_SET_SRAM_DATA4_1(8, statep->reg_txdcr_c_length); + break; + + case DTC_DSCP_RXACK: /* DSCP RxACK request */ + SCF_SET_SRAM_DATA2_2(0, statep->reg_control, + statep->reg_int_st); + SCF_SET_SRAM_DATA1_2(4, statep->reg_dcr, + statep->reg_dsr); + SCF_SET_SRAM_DATA2_1(6, statep->reg_rxdcr_c_flag); + SCF_SET_SRAM_DATA2_2(8, statep->reg_rxdcr_c_offset, 0); + break; + + case DTC_DSCP_RXEND: /* DSCP RxEND request */ + SCF_SET_SRAM_DATA2_2(0, statep->reg_control, + statep->reg_int_st); + SCF_SET_SRAM_DATA1_2(4, statep->reg_dcr, + statep->reg_dsr); + SCF_SET_SRAM_DATA2_1(6, statep->reg_rxdsr_c_flag); + SCF_SET_SRAM_DATA2_2(8, statep->reg_rxdsr_c_offset, 0); + break; + + case DTC_DSCP_RXREQ: + SCF_SET_SRAM_DATA2_2(0, statep->reg_control, + statep->reg_int_st); + SCF_SET_SRAM_DATA1_2(4, statep->reg_dcr, + statep->reg_dsr); + SCF_SET_SRAM_DATA2_1(6, statep->reg_rxdcr_c_flag); + SCF_SET_SRAM_DATA4_1(8, statep->reg_rxdcr_c_length); + break; + + + case DTC_DSCP_TXACK: /* DSCP TxACK interrupt */ + case DTC_DSCP_ACKTO: /* DSCP ACK timeout */ + case DTC_DSCP_ENDTO: /* DSCP END timeout */ + SCF_SET_SRAM_DATA2_2(0, statep->reg_control, + statep->reg_int_st); + SCF_SET_SRAM_DATA1_2(4, statep->reg_dcr, + statep->reg_dsr); + SCF_SET_SRAM_DATA2_1(6, statep->reg_txdcr_c_flag); + SCF_SET_SRAM_DATA2_2(8, statep->reg_txdcr_c_offset, 0); + break; + + case DTC_DSCP_TXEND: /* DSCP TxEND interrupt */ + SCF_SET_SRAM_DATA2_2(0, statep->reg_control, + statep->reg_int_st); + SCF_SET_SRAM_DATA1_2(4, statep->reg_dcr, + statep->reg_dsr); + SCF_SET_SRAM_DATA2_1(6, statep->reg_txdsr_c_flag); + SCF_SET_SRAM_DATA2_2(8, statep->reg_txdsr_c_offset, 0); + break; + + case DTC_SENDDATA_SRAM: /* SCF send command data for SRAM */ + case DTC_RECVDATA_SRAM: /* SCF recv command data for SRAM */ + case DTC_DSCP_SENDDATA: /* DSCP send data */ + case DTC_DSCP_RECVDATA: /* DSCP send data */ + /* Information is already set */ + break; + + case DTC_CMD: /* SCF command start */ + case DTC_INT: /* SCF interrupt */ + case DTC_CMDTO: /* SCF command timeout */ + case DTC_CMDBUSYTO: /* SCF command busy timeout */ + default: + SCF_SET_SRAM_DATA2_2(0, statep->reg_control, + statep->reg_int_st); + SCF_SET_SRAM_DATA2_2(4, statep->reg_command, + statep->reg_status); + SCF_SET_SRAM_DATA1_2(8, statep->reg_command_exr, + (statep->reg_status_exr >> 24)); + SCF_SET_SRAM_DATA1_2(10, statep->reg_acr, + statep->reg_atr); + break; + } + /* Set trace data */ + wk_in_p = (uint8_t *)&statep->memo_scf_drvtrc.LOG_ID; + wk_out_p = (uint8_t *)statep->scf_reg_drvtrc + + statep->memo_DATA_WRITE; + for (ii = 0; ii < sizeof (scf_drvtrc_ent_t); + ii++, wk_in_p++, wk_out_p++) { + SCF_DDI_PUT8(statep, statep->scf_reg_drvtrc_handle, + wk_out_p, *wk_in_p); + } + + /* Next offset update */ + statep->memo_DATA_WRITE += sizeof (scf_drvtrc_ent_t); + if (statep->memo_DATA_WRITE > statep->memo_DATA_LAST) { + statep->memo_DATA_WRITE = statep->memo_DATA_TOP; + } + SCF_DDI_PUT32(statep, statep->scf_reg_drvtrc_handle, + &statep->scf_reg_drvtrc->DATA_WRITE, + statep->memo_DATA_WRITE); + } + + SCFDBGMSG(SCF_DBGFLAG_TRACE, SCF_FUNC_NAME ": end"); +} diff --git a/usr/src/uts/sun4u/opl/io/scfd/scfsnap.c b/usr/src/uts/sun4u/opl/io/scfd/scfsnap.c new file mode 100644 index 0000000000..e85a5e12e4 --- /dev/null +++ b/usr/src/uts/sun4u/opl/io/scfd/scfsnap.c @@ -0,0 +1,766 @@ +/* + * 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 + */ +/* + * All Rights Reserved, Copyright (c) FUJITSU LIMITED 2006 + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <sys/file.h> +#include <sys/conf.h> +#include <sys/cmn_err.h> +#include <sys/kmem.h> +#include <sys/errno.h> +#include <sys/time.h> +#include <sys/ddi.h> +#include <sys/sunddi.h> + +#include <sys/scfd/scfparam.h> +#include <sys/scfd/scfdscp.h> + +#ifdef DEBUG +/* + * Function list + */ +int scf_snapshotsize(intptr_t arg, int mode); +int scf_get_snapize(int type, int info); +int scf_snapshot(intptr_t arg, int mode); +int scf_get_snap(int type, int info, scfsnap_value_t *snap_p, + int snap_size); + + +/* + * External function + */ +extern scf_dscp_comtbl_t scf_dscp_comtbl; + + +/* + * scf_snapshotsize() + */ +int +scf_snapshotsize(intptr_t arg, int mode) +{ +#define SCF_FUNC_NAME "scf_snapshotsize() " + int snap_size; + scfsnapsize_t scfsnapsize; + int ret = 0; + + SCFDBGMSG(SCF_DBGFLAG_SNAP, SCF_FUNC_NAME ": start"); + + if (ddi_copyin((void *)arg, (void *)&scfsnapsize, + sizeof (scfsnapsize_t), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "dbg_snap", 8); + ret = EFAULT; + goto END_snapshotsize; + } + + if (mutex_tryenter(&scf_comtbl.all_mutex) != 0) { + snap_size = scf_get_snapize(scfsnapsize.type, scfsnapsize.info); + + mutex_exit(&scf_comtbl.all_mutex); + + if (snap_size == (-1)) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "dbg_snap", 8); + ret = EINVAL; + goto END_snapshotsize; + } + + scfsnapsize.size = snap_size; + + if (ddi_copyout((void *)&scfsnapsize, (void *)arg, + sizeof (scfsnapsize_t), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "dbg_snap", 8); + ret = EFAULT; + } + } else { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "dbg_snap", 8); + ret = EBUSY; + } + +/* + * END_snapshotsize + */ + END_snapshotsize: + + SCFDBGMSG1(SCF_DBGFLAG_SNAP, SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +/* + * scf_get_snapize() + */ +int +scf_get_snapize(int type, int info) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_get_snapize() " + scf_state_t *statep = NULL; + int wk_size; + int ii; + int snap_driver_size; + int snap_register_size; + int snap_sram_size; + int ret = 0; + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG1(SCF_DBGFLAG_SNAP, SCF_FUNC_NAME ": start type = %d", type); + + if (info == SCFSNAPINFO_AUTO) { + statep = scf_comtbl.scf_exec_p; + if (statep == NULL) { + statep = scf_comtbl.scf_path_p; + } + } else if (info < scf_comtbl.path_num) { + statep = scf_comtbl.iomp_scf[info]; + } else { + SC_DBG_DRV_TRACE(TC_ERR, __LINE__, "snapsize", 8); + ret = (-1); + goto END_get_snapize; + } + + /* Set driver area size */ + wk_size = DRV_ID_SIZE; + wk_size = sizeof (scfsnap_value_t) + + ((wk_size + SCF_S_CNT_15) & SCF_LENGTH_16BYTE_CNV); + snap_driver_size = wk_size; + + wk_size = sizeof (scf_timer); + wk_size = sizeof (scfsnap_value_t) + + ((wk_size + SCF_S_CNT_15) & SCF_LENGTH_16BYTE_CNV); + snap_driver_size += wk_size; + + wk_size = sizeof (scf_comtbl_t); + wk_size = sizeof (scfsnap_value_t) + + ((wk_size + SCF_S_CNT_15) & SCF_LENGTH_16BYTE_CNV); + snap_driver_size += wk_size; + + if (statep != NULL) { + wk_size = sizeof (scf_state_t); + wk_size = sizeof (scfsnap_value_t) + + ((wk_size + SCF_S_CNT_15) & SCF_LENGTH_16BYTE_CNV); + snap_driver_size += wk_size; + } + + wk_size = sizeof (scf_dscp_comtbl_t); + wk_size = sizeof (scfsnap_value_t) + + ((wk_size + SCF_S_CNT_15) & SCF_LENGTH_16BYTE_CNV); + snap_driver_size += wk_size; + + if (scf_dscp_comtbl.tx_dscp != NULL) { + wk_size = scf_dscp_comtbl.tx_dscsize; + wk_size = sizeof (scfsnap_value_t) + + ((wk_size + SCF_S_CNT_15) & SCF_LENGTH_16BYTE_CNV); + snap_driver_size += wk_size; + } + + if (scf_dscp_comtbl.rx_dscp != NULL) { + wk_size = scf_dscp_comtbl.rx_dscsize; + wk_size = sizeof (scfsnap_value_t) + + ((wk_size + SCF_S_CNT_15) & SCF_LENGTH_16BYTE_CNV); + snap_driver_size += wk_size; + } + + if (scf_dscp_comtbl.tx_sramp != NULL) { + wk_size = scf_dscp_comtbl.tx_sramsize; + wk_size = sizeof (scfsnap_value_t) + + ((wk_size + SCF_S_CNT_15) & SCF_LENGTH_16BYTE_CNV); + snap_driver_size += wk_size; + } + + for (ii = 0; ii < MBIF_MAX; ii++) { + if (scf_dscp_comtbl.scf_dscp_main[ii].ev_quep != NULL) { + wk_size = scf_dscp_comtbl.scf_dscp_main[ii].ev_quesize; + wk_size = sizeof (scfsnap_value_t) + + ((wk_size + SCF_S_CNT_15) & + SCF_LENGTH_16BYTE_CNV); + snap_driver_size += wk_size; + } + if (scf_dscp_comtbl.scf_dscp_main[ii].rd_datap != NULL) { + wk_size = scf_dscp_comtbl.scf_dscp_main[ii].rd_datasize; + wk_size = sizeof (scfsnap_value_t) + + ((wk_size + SCF_S_CNT_15) & + SCF_LENGTH_16BYTE_CNV); + snap_driver_size += wk_size; + } + } + + /* Set register area size */ + if (statep != NULL) { + wk_size = sizeof (scf_regs_t) + sizeof (scf_regs_c_t); + wk_size = sizeof (scfsnap_value_t) + + ((wk_size + SCF_S_CNT_15) & SCF_LENGTH_16BYTE_CNV); + snap_register_size = wk_size; + } else { + snap_register_size = 0; + } + + /* Set sram area size */ + if (statep != NULL) { + wk_size = sizeof (scf_dscp_sram_t) + + sizeof (scf_sys_sram_t) + statep->scf_reg_drvtrc_len; + wk_size = sizeof (scfsnap_value_t) + + ((wk_size + SCF_S_CNT_15) & SCF_LENGTH_16BYTE_CNV); + snap_sram_size = wk_size; + } else { + snap_sram_size = 0; + } + + switch (type) { + case SCFSNAPTYPE_ALL: + /* Set all area snap size */ + if (statep != NULL) { + ret = snap_driver_size + snap_register_size + + snap_sram_size; + } else { + ret = snap_driver_size; + } + break; + + case SCFSNAPTYPE_DRIVER: + /* Set driver area snap size */ + ret = snap_driver_size; + break; + + case SCFSNAPTYPE_REGISTER: + /* Set register area snap size */ + ret = snap_register_size; + break; + + case SCFSNAPTYPE_SRAM: + /* Set use SRAM area snap size */ + ret = snap_sram_size; + break; + + default: + /* Invalid parameter */ + SC_DBG_DRV_TRACE(TC_ERR, __LINE__, "snapsize", 8); + ret = (-1); + break; + } + +/* + * END_get_snapize + */ + END_get_snapize: + + SCFDBGMSG1(SCF_DBGFLAG_SNAP, SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +/* + * scf_snapshot() + */ +int +scf_snapshot(intptr_t arg, int mode) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_snapshot() " + int snap_size; + scfsnap_t scfsnap; + scfsnap32_t scfsnap32; + scfsnap_value_t *scfsnap_p = NULL; + int ret = 0; + + SCFDBGMSG(SCF_DBGFLAG_SNAP, SCF_FUNC_NAME ": start"); + +#ifdef _MULTI_DATAMODEL + switch (ddi_model_convert_from(mode & FMODELS)) { + case DDI_MODEL_ILP32: + if (ddi_copyin((void *)arg, (void *)&scfsnap32, + sizeof (scfsnap32_t), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "dbg_snap", 8); + ret = EFAULT; + goto END_snapshot; + } + scfsnap.type = scfsnap32.type; + scfsnap.info = scfsnap32.info; + break; + + case DDI_MODEL_NONE: + if (ddi_copyin((void *)arg, (void *)&scfsnap, + sizeof (scfsnap_t), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "dbg_snap", 8); + ret = EFAULT; + goto END_snapshot; + } + break; + } +#else /* ! _MULTI_DATAMODEL */ + if (ddi_copyin((void *)arg, (void *)&scfsnap, + sizeof (scfsnap_t), mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "dbg_snap", 8); + ret = EFAULT; + goto END_snapshot; + } +#endif /* _MULTI_DATAMODEL */ + + if (mutex_tryenter(&scf_comtbl.all_mutex) != 0) { + + snap_size = scf_get_snapize(scfsnap.type, scfsnap.info); + + if (snap_size == (-1)) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "dbg_snap", 8); + mutex_exit(&scf_comtbl.all_mutex); + ret = EINVAL; + goto END_snapshot; + } + + if (snap_size != 0) { + scfsnap_p = kmem_zalloc((size_t)snap_size, KM_SLEEP); + + ret = scf_get_snap(scfsnap.type, scfsnap.info, + scfsnap_p, snap_size); + } else { + ret = ENODATA; + } + + mutex_exit(&scf_comtbl.all_mutex); + } else { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, "dbg_snap", 8); + ret = EBUSY; + } + + if (ret == 0) { + +#ifdef _MULTI_DATAMODEL + switch (ddi_model_convert_from(mode & FMODELS)) { + case DDI_MODEL_ILP32: + if (ddi_copyout((void *)scfsnap_p, + (void *)(uintptr_t)scfsnap32.ss_entries, + (size_t)snap_size, mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "dbg_snap", 8); + ret = EFAULT; + } + + break; + + case DDI_MODEL_NONE: + if (ddi_copyout((void *)scfsnap_p, + (void *)scfsnap.ss_entries, + (size_t)snap_size, mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "dbg_snap", 8); + ret = EFAULT; + } + break; + } + +#else /* ! _MULTI_DATAMODEL */ + if (ddi_copyout((void *)scfsnap_p, (void *)scfsnap.ss_entries, + (size_t)snap_size, mode) != 0) { + SC_DBG_DRV_TRACE(TC_IOCTL|TC_ERR, __LINE__, + "dbg_snap", 8); + ret = EFAULT; + } +#endif /* _MULTI_DATAMODEL */ + } + +/* + * END_snapshot + */ + END_snapshot: + + if (scfsnap_p) { + kmem_free((void *)scfsnap_p, + (size_t)snap_size); + } + + SCFDBGMSG1(SCF_DBGFLAG_SNAP, SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +/* + * scf_get_snap() + */ +int +scf_get_snap(int type, int info, scfsnap_value_t *snap_top_p, int snap_size) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_get_snap() " + scf_state_t *statep; + scfsnap_value_t *snap_p; + int wk_size; + int wk_nextoff; + int exec_model; + uint8_t *wk_in_p; + uint8_t *wk_out_p; + scf_dscp_main_t *mainp; + scf_regs_t *wk_regs_p; + scf_regs_c_t *wk_regs_c_p; + int ii; + + int ret = 0; + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG1(SCF_DBGFLAG_SNAP, SCF_FUNC_NAME ": start type = %d", type); + +#ifdef _MULTI_DATAMODEL + exec_model = SCF_DRIVER_64BIT; +#else /* ! _MULTI_DATAMODEL */ + exec_model = SCF_DRIVER_32BIT; +#endif /* _MULTI_DATAMODEL */ + + if ((scf_get_snapize(type, info) > snap_size) || (snap_size <= 0)) { + SC_DBG_DRV_TRACE(TC_ERR, __LINE__, "snapshot", 8); + ret = EINVAL; + goto END_get_snap; + } + + if (info == SCFSNAPINFO_AUTO) { + statep = scf_comtbl.scf_exec_p; + if (statep == NULL) { + statep = scf_comtbl.scf_path_p; + } + } else if (info < scf_comtbl.path_num) { + statep = scf_comtbl.iomp_scf[info]; + } else { + SC_DBG_DRV_TRACE(TC_ERR, __LINE__, "snapshot", 8); + ret = EINVAL; + goto END_get_snap; + } + + snap_p = snap_top_p; + wk_nextoff = 0; + if ((type == SCFSNAPTYPE_ALL) || (type == SCFSNAPTYPE_DRIVER)) { + /* Set driver vl area */ + strcpy((char *)&snap_p->ss_name[0], SNAP_SCF_DRIVER_VL); + wk_size = sizeof (SCF_DRIVER_VERSION); + if (wk_size > DRV_ID_SIZE) { + wk_size = DRV_ID_SIZE; + } + wk_nextoff += (sizeof (scfsnap_value_t) + + ((wk_size + SCF_S_CNT_15) & SCF_LENGTH_16BYTE_CNV)); + snap_p->ss_flag = exec_model; + snap_p->ss_size = wk_size; + snap_p->ss_nextoff = wk_nextoff; + bcopy((void *)SCF_DRIVER_VERSION, + (void *)(snap_p + 1), wk_size); + snap_p = (void *)((caddr_t)snap_top_p + wk_nextoff); + + /* Set driver timer area */ + strcpy((char *)&snap_p->ss_name[0], SNAP_SCF_TIMER_TBL); + wk_size = sizeof (scf_timer); + wk_nextoff += (sizeof (scfsnap_value_t) + + ((wk_size + SCF_S_CNT_15) & SCF_LENGTH_16BYTE_CNV)); + snap_p->ss_flag = exec_model; + snap_p->ss_size = wk_size; + snap_p->ss_nextoff = wk_nextoff; + bcopy((void *)scf_timer, (void *)(snap_p + 1), wk_size); + snap_p = (void *)((caddr_t)snap_top_p + wk_nextoff); + + /* Set driver common area */ + strcpy((char *)&snap_p->ss_name[0], SNAP_SCF_COMTBL); + wk_size = sizeof (scf_comtbl); + wk_nextoff += (sizeof (scfsnap_value_t) + + ((wk_size + SCF_S_CNT_15) & SCF_LENGTH_16BYTE_CNV)); + snap_p->ss_flag = exec_model; + snap_p->ss_size = wk_size; + snap_p->ss_nextoff = wk_nextoff; + bcopy((void *)&scf_comtbl, (void *)(snap_p + 1), wk_size); + snap_p = (void *)((caddr_t)snap_top_p + wk_nextoff); + + if (statep != NULL) { + /* Set device area */ + strcpy((char *)&snap_p->ss_name[0], SNAP_SCF_STATE); + wk_size = sizeof (scf_state_t); + wk_nextoff += (sizeof (scfsnap_value_t) + + ((wk_size + SCF_S_CNT_15) & + SCF_LENGTH_16BYTE_CNV)); + snap_p->ss_flag = exec_model; + snap_p->ss_size = wk_size; + snap_p->ss_nextoff = wk_nextoff; + bcopy((void *)statep, (void *)(snap_p + 1), wk_size); + snap_p = (void *)((caddr_t)snap_top_p + wk_nextoff); + } + + /* Set driver DSCP common area */ + strcpy((char *)&snap_p->ss_name[0], SNAP_SCF_DSCP_COMTBL); + wk_size = sizeof (scf_dscp_comtbl_t); + wk_nextoff += (sizeof (scfsnap_value_t) + + ((wk_size + SCF_S_CNT_15) & SCF_LENGTH_16BYTE_CNV)); + snap_p->ss_flag = exec_model; + snap_p->ss_size = wk_size; + snap_p->ss_nextoff = wk_nextoff; + bcopy((void *)&scf_dscp_comtbl, (void *)(snap_p + 1), wk_size); + snap_p = (void *)((caddr_t)snap_top_p + wk_nextoff); + + /* Set driver DSCP TxDSC area */ + if (scf_dscp_comtbl.tx_dscp != NULL) { + strcpy((char *)&snap_p->ss_name[0], + SNAP_SCF_DSCP_TXDSC); + wk_size = scf_dscp_comtbl.tx_dscsize; + wk_nextoff += (sizeof (scfsnap_value_t) + + ((wk_size + SCF_S_CNT_15) & + SCF_LENGTH_16BYTE_CNV)); + snap_p->ss_flag = exec_model; + snap_p->ss_size = wk_size; + snap_p->ss_nextoff = wk_nextoff; + bcopy((void *)scf_dscp_comtbl.tx_dscp, + (void *)(snap_p + 1), wk_size); + snap_p = (void *)((caddr_t)snap_top_p + wk_nextoff); + } + + /* Set driver DSCP RxDSC area */ + if (scf_dscp_comtbl.rx_dscp != NULL) { + strcpy((char *)&snap_p->ss_name[0], + SNAP_SCF_DSCP_RXDSC); + wk_size = scf_dscp_comtbl.rx_dscsize; + wk_nextoff += (sizeof (scfsnap_value_t) + + ((wk_size + SCF_S_CNT_15) & + SCF_LENGTH_16BYTE_CNV)); + snap_p->ss_flag = exec_model; + snap_p->ss_size = wk_size; + snap_p->ss_nextoff = wk_nextoff; + bcopy((void *)scf_dscp_comtbl.rx_dscp, + (void *)(snap_p + 1), wk_size); + snap_p = (void *)((caddr_t)snap_top_p + wk_nextoff); + } + + /* Set driver DSCP Tx SRAM area */ + if (scf_dscp_comtbl.tx_sramp != NULL) { + strcpy((char *)&snap_p->ss_name[0], + SNAP_SCF_DSCP_TXSRAM); + wk_size = scf_dscp_comtbl.tx_sramsize; + wk_nextoff += (sizeof (scfsnap_value_t) + + ((wk_size + SCF_S_CNT_15) & + SCF_LENGTH_16BYTE_CNV)); + snap_p->ss_flag = exec_model; + snap_p->ss_size = wk_size; + snap_p->ss_nextoff = wk_nextoff; + bcopy((void *)scf_dscp_comtbl.tx_sramp, + (void *)(snap_p + 1), wk_size); + snap_p = (void *)((caddr_t)snap_top_p + wk_nextoff); + } + + for (ii = 0; ii < MBIF_MAX; ii++) { + mainp = &scf_dscp_comtbl.scf_dscp_main[ii]; + /* Set driver DSCP Event data area */ + if (mainp->ev_quep != NULL) { + strcpy((char *)&snap_p->ss_name[0], + SNAP_SCF_DSCP_EVENT); + wk_size = mainp->ev_quesize; + wk_nextoff += (sizeof (scfsnap_value_t) + + ((wk_size + SCF_S_CNT_15) & + SCF_LENGTH_16BYTE_CNV)); + snap_p->ss_flag = exec_model; + snap_p->ss_size = wk_size; + snap_p->ss_nextoff = wk_nextoff; + bcopy((void *)mainp->ev_quep, + (void *)(snap_p + 1), wk_size); + snap_p = (void *)((caddr_t)snap_top_p + + wk_nextoff); + } + /* Set driver DSCP Recv data area */ + if (mainp->rd_datap != NULL) { + strcpy((char *)&snap_p->ss_name[0], + SNAP_SCF_DSCP_RDATA); + wk_size = mainp->rd_datasize; + wk_nextoff += (sizeof (scfsnap_value_t) + + ((wk_size + SCF_S_CNT_15) & + SCF_LENGTH_16BYTE_CNV)); + snap_p->ss_flag = exec_model; + snap_p->ss_size = wk_size; + snap_p->ss_nextoff = wk_nextoff; + bcopy((void *)mainp->rd_datap, + (void *)(snap_p + 1), wk_size); + snap_p = (void *)((caddr_t)snap_top_p + + wk_nextoff); + } + } + } + + if ((type == SCFSNAPTYPE_ALL) || (type == SCFSNAPTYPE_REGISTER)) { + if (statep != NULL) { + /* Set register area */ + strcpy((char *)&snap_p->ss_name[0], SNAP_REGISTER); + wk_size = sizeof (scf_regs_t) + sizeof (scf_regs_c_t); + wk_nextoff += (sizeof (scfsnap_value_t) + + ((wk_size + SCF_S_CNT_15) & + SCF_LENGTH_16BYTE_CNV)); + snap_p->ss_flag = exec_model; + snap_p->ss_size = wk_size; + snap_p->ss_nextoff = wk_nextoff; + + wk_regs_p = (scf_regs_t *)(snap_p + 1); + wk_regs_p->COMMAND = SCF_DDI_GET16(statep, + statep->scf_regs_handle, + &statep->scf_regs->COMMAND); + wk_regs_p->STATUS = SCF_DDI_GET16(statep, + statep->scf_regs_handle, + &statep->scf_regs->STATUS); + wk_regs_p->VERSION = SCF_DDI_GET8(statep, + statep->scf_regs_handle, + &statep->scf_regs->VERSION); + wk_regs_p->TDATA0 = SCF_DDI_GET32(statep, + statep->scf_regs_handle, + &statep->scf_regs->TDATA0); + wk_regs_p->TDATA1 = SCF_DDI_GET32(statep, + statep->scf_regs_handle, + &statep->scf_regs->TDATA1); + wk_regs_p->TDATA2 = SCF_DDI_GET32(statep, + statep->scf_regs_handle, + &statep->scf_regs->TDATA2); + wk_regs_p->TDATA3 = SCF_DDI_GET32(statep, + statep->scf_regs_handle, + &statep->scf_regs->TDATA3); + wk_regs_p->RDATA0 = SCF_DDI_GET32(statep, + statep->scf_regs_handle, + &statep->scf_regs->RDATA0); + wk_regs_p->RDATA1 = SCF_DDI_GET32(statep, + statep->scf_regs_handle, + &statep->scf_regs->RDATA1); + wk_regs_p->RDATA2 = SCF_DDI_GET32(statep, + statep->scf_regs_handle, + &statep->scf_regs->RDATA2); + wk_regs_p->RDATA3 = SCF_DDI_GET32(statep, + statep->scf_regs_handle, + &statep->scf_regs->RDATA3); + wk_regs_p->COMMAND_ExR = SCF_DDI_GET8(statep, + statep->scf_regs_handle, + &statep->scf_regs->COMMAND_ExR); + wk_regs_p->ACR = SCF_DDI_GET8(statep, + statep->scf_regs_handle, + &statep->scf_regs->ACR); + wk_regs_p->ATR = SCF_DDI_GET8(statep, + statep->scf_regs_handle, + &statep->scf_regs->ATR); + wk_regs_p->STATUS_ExR = SCF_DDI_GET32(statep, + statep->scf_regs_handle, + &statep->scf_regs->STATUS_ExR); + wk_regs_p->DCR = SCF_DDI_GET8(statep, + statep->scf_regs_handle, + &statep->scf_regs->DCR); + wk_regs_p->DSR = SCF_DDI_GET8(statep, + statep->scf_regs_handle, + &statep->scf_regs->DSR); + wk_regs_p->TxDCR_C_FLAG = SCF_DDI_GET16(statep, + statep->scf_regs_handle, + &statep->scf_regs->TxDCR_C_FLAG); + wk_regs_p->TxDCR_OFFSET = SCF_DDI_GET16(statep, + statep->scf_regs_handle, + &statep->scf_regs->TxDCR_OFFSET); + wk_regs_p->TxDCR_LENGTH = SCF_DDI_GET32(statep, + statep->scf_regs_handle, + &statep->scf_regs->TxDCR_LENGTH); + wk_regs_p->TxDSR_C_FLAG = SCF_DDI_GET16(statep, + statep->scf_regs_handle, + &statep->scf_regs->TxDSR_C_FLAG); + wk_regs_p->TxDSR_OFFSET = SCF_DDI_GET16(statep, + statep->scf_regs_handle, + &statep->scf_regs->TxDSR_OFFSET); + wk_regs_p->RxDCR_C_FLAG = SCF_DDI_GET16(statep, + statep->scf_regs_handle, + &statep->scf_regs->RxDCR_C_FLAG); + wk_regs_p->RxDCR_OFFSET = SCF_DDI_GET16(statep, + statep->scf_regs_handle, + &statep->scf_regs->RxDCR_OFFSET); + wk_regs_p->RxDCR_LENGTH = SCF_DDI_GET32(statep, + statep->scf_regs_handle, + &statep->scf_regs->RxDCR_LENGTH); + wk_regs_p->RxDSR_C_FLAG = SCF_DDI_GET16(statep, + statep->scf_regs_handle, + &statep->scf_regs->RxDSR_C_FLAG); + wk_regs_p->RxDSR_OFFSET = SCF_DDI_GET16(statep, + statep->scf_regs_handle, + &statep->scf_regs->RxDSR_OFFSET); + + wk_regs_c_p = (scf_regs_c_t *)(wk_regs_p + 1); + wk_regs_c_p->CONTROL = SCF_DDI_GET16(statep, + statep->scf_regs_c_handle, + &statep->scf_regs_c->CONTROL); + wk_regs_c_p->INT_ST = SCF_DDI_GET16(statep, + statep->scf_regs_c_handle, + &statep->scf_regs_c->INT_ST); + + snap_p = (void *)((caddr_t)snap_top_p + wk_nextoff); + } else { + if (type == SCFSNAPTYPE_REGISTER) { + ret = ENODATA; + } + } + } + + + if ((type == SCFSNAPTYPE_ALL) || (type == SCFSNAPTYPE_SRAM)) { + if (statep != NULL) { + /* Set use SRAM area */ + strcpy((char *)&snap_p->ss_name[0], SNAP_SRAM); + wk_size = sizeof (scf_dscp_sram_t) + + sizeof (scf_sys_sram_t) + + statep->scf_reg_drvtrc_len; + wk_nextoff += (sizeof (scfsnap_value_t) + + ((wk_size + SCF_S_CNT_15) & + SCF_LENGTH_16BYTE_CNV)); + snap_p->ss_flag = exec_model; + snap_p->ss_size = wk_size; + snap_p->ss_nextoff = wk_nextoff; + + wk_in_p = (uint8_t *)&statep->scf_dscp_sram->DATA[0]; + wk_out_p = (uint8_t *)(snap_p + 1); + for (ii = 0; ii < sizeof (scf_dscp_sram_t); + ii++, wk_in_p++, wk_out_p++) { + *wk_out_p = SCF_DDI_GET8(statep, + statep->scf_dscp_sram_handle, wk_in_p); + } + + wk_in_p = (uint8_t *)&statep->scf_sys_sram->DATA[0]; + for (ii = 0; ii < sizeof (scf_sys_sram_t); + ii++, wk_in_p++, wk_out_p++) { + *wk_out_p = SCF_DDI_GET8(statep, + statep->scf_sys_sram_handle, wk_in_p); + } + + wk_in_p = (uint8_t *)statep->scf_reg_drvtrc; + for (ii = 0; ii < statep->scf_reg_drvtrc_len; + ii++, wk_in_p++, wk_out_p++) { + *wk_out_p = SCF_DDI_GET8(statep, + statep->scf_reg_drvtrc_handle, wk_in_p); + } + snap_p = (void *)((caddr_t)snap_top_p + wk_nextoff); + } else { + if (type == SCFSNAPTYPE_SRAM) { + ret = ENODATA; + } + } + } + +/* + * END_get_snap + */ + END_get_snap: + + SCFDBGMSG1(SCF_DBGFLAG_SNAP, SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} +#endif /* DEBUG */ diff --git a/usr/src/uts/sun4u/opl/io/scfd/scftimer.c b/usr/src/uts/sun4u/opl/io/scfd/scftimer.c new file mode 100644 index 0000000000..104b31439e --- /dev/null +++ b/usr/src/uts/sun4u/opl/io/scfd/scftimer.c @@ -0,0 +1,603 @@ +/* + * 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 + */ +/* + * All Rights Reserved, Copyright (c) FUJITSU LIMITED 2006 + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/ksynch.h> +#include <sys/types.h> +#include <sys/conf.h> +#include <sys/cmn_err.h> +#include <sys/kmem.h> +#include <sys/errno.h> +#include <sys/ddi.h> +#include <sys/sunddi.h> + +#include <sys/scfd/scfparam.h> + +/* + * Timer control table and control flag + */ +static int scf_timer_stop_flag = FLAG_OFF; /* Timer stop flag */ +scf_timer_t scf_timer[SCF_TIMERCD_MAX]; /* Timer contorol table */ + +/* + * Timer value + */ + /* SCF command busy watch timer */ +int scf_devbusy_wait_time = SCF_TIMER_VALUE_DEVBUSY; + /* SCF command completion watch timer */ +int scf_cmdend_wait_time = SCF_TIMER_VALUE_CMDEND; + /* SCF online watch timer */ +int scf_online_wait_time = SCF_TIMER_VALUE_ONLINE; + /* Next receive wait timer */ +int scf_rxbuff_wait_time = SCF_TIMER_VALUE_NEXTRCV; + /* DSCP interface TxACK watch timer */ +int scf_dscp_ack_wait_time = SCF_TIMER_VALUE_DSCP_ACK; + /* DSCP interface TxEND watch timer */ +int scf_dscp_end_wait_time = SCF_TIMER_VALUE_DSCP_END; + /* DSCP interface busy watch timer */ +int scf_dscp_txbusy_time = SCF_TIMER_VALUE_DSCP_BUSY; + /* DSCP interface callback timer */ +int scf_dscp_callback_time = SCF_TIMER_VALUE_DSCP_CALLBACK; + +/* + * Function list + */ +void scf_timer_init(void); +void scf_timer_start(int tmcd); +void scf_timer_stop(int tmcd); +void scf_timer_all_stop(void); +int scf_timer_check(int tmcd); +uint32_t scf_timer_value_get(int tmcd); +void scf_tout(void *arg); +int scf_timer_stop_collect(timeout_id_t *tmids, int size); +void scf_timer_untimeout(timeout_id_t *tmids, int size); + +/* + * External function + */ +extern void scf_cmdbusy_tout(void); +extern void scf_cmdend_tout(void); +extern void scf_online_wait_tout(void); +extern void scf_next_rxdata_get(void); +extern void scf_dscp_ack_tout(void); +extern void scf_dscp_end_tout(void); +extern void scf_dscp_busy_tout(void); +extern void scf_dscp_callback_tout(void); +extern void scf_report_send_wait_tout(void); + +/* + * scf_timer_init() + * + * Description: Timer initialization processing. + * + */ +void +scf_timer_init(void) +{ +#define SCF_FUNC_NAME "scf_timer_init() " + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_TIMER, SCF_FUNC_NAME ": start"); + + /* Set timer code and timer value */ + scf_timer[SCF_TIMERCD_CMDBUSY].value = scf_devbusy_wait_time; + scf_timer[SCF_TIMERCD_CMDBUSY].tbl[0].code = SCF_TIMERCD_CMDBUSY; + scf_timer[SCF_TIMERCD_CMDBUSY].tbl[1].code = SCF_TIMERCD_CMDBUSY; + + scf_timer[SCF_TIMERCD_CMDEND].value = scf_cmdend_wait_time; + scf_timer[SCF_TIMERCD_CMDEND].tbl[0].code = SCF_TIMERCD_CMDEND; + scf_timer[SCF_TIMERCD_CMDEND].tbl[1].code = SCF_TIMERCD_CMDEND; + + scf_timer[SCF_TIMERCD_ONLINE].value = scf_online_wait_time; + scf_timer[SCF_TIMERCD_ONLINE].tbl[0].code = SCF_TIMERCD_ONLINE; + scf_timer[SCF_TIMERCD_ONLINE].tbl[1].code = SCF_TIMERCD_ONLINE; + + scf_timer[SCF_TIMERCD_NEXTRECV].value = scf_rxbuff_wait_time; + scf_timer[SCF_TIMERCD_NEXTRECV].tbl[0].code = SCF_TIMERCD_NEXTRECV; + scf_timer[SCF_TIMERCD_NEXTRECV].tbl[1].code = SCF_TIMERCD_NEXTRECV; + + scf_timer[SCF_TIMERCD_DSCP_ACK].value = scf_dscp_ack_wait_time; + scf_timer[SCF_TIMERCD_DSCP_ACK].tbl[0].code = SCF_TIMERCD_DSCP_ACK; + scf_timer[SCF_TIMERCD_DSCP_ACK].tbl[1].code = SCF_TIMERCD_DSCP_ACK; + + scf_timer[SCF_TIMERCD_DSCP_END].value = scf_dscp_end_wait_time; + scf_timer[SCF_TIMERCD_DSCP_END].tbl[0].code = SCF_TIMERCD_DSCP_END; + scf_timer[SCF_TIMERCD_DSCP_END].tbl[1].code = SCF_TIMERCD_DSCP_END; + + scf_timer[SCF_TIMERCD_DSCP_BUSY].value = scf_dscp_txbusy_time; + scf_timer[SCF_TIMERCD_DSCP_BUSY].tbl[0].code = SCF_TIMERCD_DSCP_BUSY; + scf_timer[SCF_TIMERCD_DSCP_BUSY].tbl[1].code = SCF_TIMERCD_DSCP_BUSY; + + scf_timer[SCF_TIMERCD_DSCP_CALLBACK].value = scf_dscp_callback_time; + scf_timer[SCF_TIMERCD_DSCP_CALLBACK].tbl[0].code = + SCF_TIMERCD_DSCP_CALLBACK; + scf_timer[SCF_TIMERCD_DSCP_CALLBACK].tbl[1].code = + SCF_TIMERCD_DSCP_CALLBACK; + + scf_timer[SCF_TIMERCD_BUF_FUL].value = scf_buf_ful_rtime; + scf_timer[SCF_TIMERCD_BUF_FUL].tbl[0].code = SCF_TIMERCD_BUF_FUL; + scf_timer[SCF_TIMERCD_BUF_FUL].tbl[1].code = SCF_TIMERCD_BUF_FUL; + + scf_timer[SCF_TIMERCD_RCI_BUSY].value = scf_rci_busy_rtime; + scf_timer[SCF_TIMERCD_RCI_BUSY].tbl[0].code = SCF_TIMERCD_RCI_BUSY; + scf_timer[SCF_TIMERCD_RCI_BUSY].tbl[1].code = SCF_TIMERCD_RCI_BUSY; + + SCFDBGMSG(SCF_DBGFLAG_TIMER, SCF_FUNC_NAME ": end"); +} + + +/* + * scf_timer_start() + * + * Description: Timer start subroutine. + * + */ +void +scf_timer_start(int tmcd) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_timer_start() " + scf_timer_t *tm_p; /* Timer table address */ + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG1(SCF_DBGFLAG_TIMER, SCF_FUNC_NAME ": start tmcd = %d", tmcd); + + /* Check timer code */ + if (tmcd >= SCF_TIMERCD_MAX) { + goto END_timer_start; + } + + /* Get timer table address */ + tm_p = &scf_timer[tmcd]; + + /* Check timer value and timer start flag */ + if ((tm_p->value == 0) || (tm_p->start == FLAG_ON)) { + goto END_timer_start; + } + + /* Check timer stop flag */ + if (tm_p->stop == FLAG_OFF) { + /* + * Timer start and judgment + */ + /* Change timer table side */ + tm_p->side = (tm_p->side == 0) ? 1 : 0; + + /* timer start */ + tm_p->tbl[tm_p->side].id = timeout(scf_tout, + &tm_p->tbl[tm_p->side], + drv_usectohz(SCF_MIL2MICRO(tm_p->value))); + + /* Timer start flag ON */ + tm_p->start = FLAG_ON; + + SC_DBG_DRV_TRACE(TC_T_START, __LINE__, &tmcd, sizeof (tmcd)); + SCFDBGMSG(SCF_DBGFLAG_TIMER, "timeout() call"); + } else { + /* + * Timer restart and judgment + */ + SCFDBGMSG(SCF_DBGFLAG_TIMER, "timer restart"); + + /* Check current table timer use */ + if (tm_p->tbl[tm_p->side].id != 0) { + /* Change timer table side */ + tm_p->side = (tm_p->side == 0) ? 1 : 0; + } + + /* Timer start and restart flag ON */ + tm_p->start = FLAG_ON; + tm_p->restart = FLAG_ON; + } + +/* + * END_timer_start + */ + END_timer_start: + + SCFDBGMSG(SCF_DBGFLAG_TIMER, SCF_FUNC_NAME ": end"); +} + + +/* + * scf_timer_stop() + * + * Description: Timer stop subroutine. + * + */ +void +scf_timer_stop(int tmcd) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_timer_stop() " + scf_timer_t *tm_p; /* Timer table address */ + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG1(SCF_DBGFLAG_TIMER, SCF_FUNC_NAME ": start tmcd = %d", tmcd); + + /* Check timer code */ + if (tmcd < SCF_TIMERCD_MAX) { + /* Get timer table address */ + tm_p = &scf_timer[tmcd]; + + /* Check timer start flag */ + if (tm_p->start == FLAG_ON) { + /* + * Timer start and judgment + */ + + /* Timer start and restart flag OFF */ + tm_p->start = FLAG_OFF; + tm_p->restart = FLAG_OFF; + + /* Timer stop flag ON */ + tm_p->stop = FLAG_ON; + scf_timer_stop_flag = FLAG_ON; + } + } + + SCFDBGMSG(SCF_DBGFLAG_TIMER, SCF_FUNC_NAME ": end"); +} + + +/* + * scf_timer_all_stop() + * + * Description: Timer all stop subroutine. + * + */ +void +scf_timer_all_stop(void) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_timer_all_stop() " + int tm_cd; + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_TIMER, SCF_FUNC_NAME ": start"); + + for (tm_cd = 0; tm_cd < SCF_TIMERCD_MAX; tm_cd++) { + scf_timer_stop(tm_cd); + } + + SCFDBGMSG(SCF_DBGFLAG_TIMER, SCF_FUNC_NAME ": end"); +} + + +/* + * scf_timer_check() + * + * Description: Timer status check subroutine. + * + */ +int +scf_timer_check(int tmcd) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_timer_check() " + scf_timer_t *tm_p; /* Timer table address */ + int ret = SCF_TIMER_NOT_EXEC; /* Return value */ + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG1(SCF_DBGFLAG_TIMER, SCF_FUNC_NAME ": start tmcd = %d", tmcd); + + /* Check timer code */ + if (tmcd < SCF_TIMERCD_MAX) { + /* Get timer table address */ + tm_p = &scf_timer[tmcd]; + + /* Check timer start flag */ + if (tm_p->start == FLAG_ON) { + /* Timer exec state */ + ret = SCF_TIMER_EXEC; + } + } + + SCFDBGMSG1(SCF_DBGFLAG_TIMER, SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +/* + * scf_timer_value_get() + * + * Description: Timer value get subroutine. + * + */ +uint32_t +scf_timer_value_get(int tmcd) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_timer_value_get() " + uint32_t ret = 0; /* Return value */ + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG1(SCF_DBGFLAG_TIMER, SCF_FUNC_NAME ": start tmcd = %d", tmcd); + + /* Check timer code */ + if (tmcd < SCF_TIMERCD_MAX) { + /* Set timer value */ + ret = scf_timer[tmcd].value; + } + + SCFDBGMSG1(SCF_DBGFLAG_TIMER, SCF_FUNC_NAME ": end return = %d", ret); + return (ret); +} + + +/* + * scf_tout() + * + * Description: Timeout main processing. + * + */ +void +scf_tout(void *arg) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_tout() " + scf_timer_tbl_t *tm_tblp = (scf_timer_tbl_t *)arg; + scf_timer_t *tm_p; /* Timer table address */ + timeout_id_t save_tmids[SCF_TIMERCD_MAX]; + int tm_stop_cnt; + + SCFDBGMSG1(SCF_DBGFLAG_TIMER, SCF_FUNC_NAME ": start tmcd = %d", + tm_tblp->code); + + SC_DBG_DRV_TRACE(TC_T_TOUT | TC_IN, __LINE__, &tm_tblp->code, + sizeof (tm_tblp->code)); + + /* Lock driver mutex */ + mutex_enter(&scf_comtbl.all_mutex); + + /* Get timer table address */ + tm_p = &scf_timer[tm_tblp->code]; + + /* Check timer exec state */ + if ((tm_p->start == FLAG_ON) && (tm_tblp->id != 0) && + (tm_p->stop == FLAG_OFF)) { + /* Timer flag OFF and timer id clear */ + tm_p->start = FLAG_OFF; + tm_tblp->id = 0; + + /* Check timer code */ + switch (tm_tblp->code) { + case SCF_TIMERCD_CMDBUSY: + /* SCF command busy watch timeout */ + scf_cmdbusy_tout(); + break; + + case SCF_TIMERCD_CMDEND: + /* SCF command completion watch timeout */ + scf_cmdend_tout(); + break; + + case SCF_TIMERCD_ONLINE: + /* SCF online watch timeout */ + scf_online_wait_tout(); + break; + + case SCF_TIMERCD_NEXTRECV: + /* Next receive wait timeout */ + scf_next_rxdata_get(); + break; + + case SCF_TIMERCD_DSCP_ACK: + /* DSCP interface TxACK watch timeout */ + scf_dscp_ack_tout(); + break; + + case SCF_TIMERCD_DSCP_END: + /* DSCP interface TxEND watch timeout */ + scf_dscp_end_tout(); + break; + + case SCF_TIMERCD_DSCP_BUSY: + /* DSCP interface busy watch timeout */ + scf_dscp_busy_tout(); + break; + + case SCF_TIMERCD_DSCP_CALLBACK: + /* DSCP interface callback timeout */ + scf_dscp_callback_tout(); + break; + + case SCF_TIMERCD_BUF_FUL: + /* SCF command BUF_FUL timeout */ + case SCF_TIMERCD_RCI_BUSY: + /* SCF command RCI_BUSY timeout */ + scf_report_send_wait_tout(); + break; + + default: + /* NOP */ + break; + } + } else { + /* Timer flag OFF and timer id clear */ + tm_p->stop = FLAG_OFF; + tm_tblp->id = 0; + + /* Check timer restart flag */ + if (tm_p->restart == FLAG_ON) { + /* + * Timer start and judgment + */ + /* timer start */ + tm_p->tbl[tm_p->side].id = timeout(scf_tout, + &tm_p->tbl[tm_p->side], + drv_usectohz(SCF_MIL2MICRO(tm_p->value))); + + /* Timer start flag is already ON */ + + /* Timer restart flag OFF */ + tm_p->restart = FLAG_OFF; + + SC_DBG_DRV_TRACE(TC_T_START, __LINE__, &tm_tblp->code, + sizeof (tm_tblp->code)); + SCFDBGMSG(SCF_DBGFLAG_TIMER, "timeout() call"); + } + } + + /* Collect the timers which need to be stopped */ + tm_stop_cnt = scf_timer_stop_collect(save_tmids, SCF_TIMERCD_MAX); + + /* Unlock driver mutex */ + mutex_exit(&scf_comtbl.all_mutex); + + /* Timer stop */ + if (tm_stop_cnt != 0) { + scf_timer_untimeout(save_tmids, SCF_TIMERCD_MAX); + } + + SC_DBG_DRV_TRACE(TC_T_TOUT | TC_OUT, __LINE__, NULL, 0); + SCFDBGMSG(SCF_DBGFLAG_TIMER, SCF_FUNC_NAME ": end"); +} + + +/* + * scf_timer_stop_collect() + * + * Description: Collect the timers which need to be stopped. + * + */ +int +scf_timer_stop_collect(timeout_id_t *tmids, int size) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_timer_stop_collect() " + scf_timer_t *tm_p; /* Timer table address */ + int ii; /* Working value : counter */ + int tm_stop_cnt = 0; /* Timer stop counter */ + + ASSERT(MUTEX_HELD(&scf_comtbl.all_mutex)); + + SCFDBGMSG(SCF_DBGFLAG_TIMER, SCF_FUNC_NAME ": start"); + + /* Clear save timer table */ + bzero((caddr_t)tmids, (sizeof (timeout_id_t) * size)); + + /* Check timer stop factor */ + if (scf_timer_stop_flag == FLAG_OFF) { + goto END_timer_stop_collect; + } + + /* Timer stop flag OFF */ + scf_timer_stop_flag = FLAG_OFF; + + /* Get timer table address */ + tm_p = &scf_timer[0]; + + /* Check all timer table */ + for (ii = 0; ii < size; ii++, tm_p++) { + /* Check timer stop flag */ + if (tm_p->stop == FLAG_ON) { + /* Timer stop flag OFF */ + tm_p->stop = FLAG_OFF; + + /* Check timer side 0 table timer use */ + if (tm_p->tbl[0].id != 0) { + /* Save stop timer id */ + tmids[tm_stop_cnt++] = tm_p->tbl[0].id; + + /* Timer id clear */ + tm_p->tbl[0].id = 0; + + SC_DBG_DRV_TRACE(TC_T_STOP, __LINE__, &ii, + sizeof (ii)); + } + + /* Check timer side 1 table timer use */ + if (tm_p->tbl[1].id != 0) { + /* Save stop timer id */ + tmids[tm_stop_cnt++] = tm_p->tbl[1].id; + + /* Timer id clear */ + tm_p->tbl[1].id = 0; + + SC_DBG_DRV_TRACE(TC_T_STOP, __LINE__, &ii, + sizeof (ii)); + } + } + /* Check timer restart flag */ + if (tm_p->restart == FLAG_ON) { + /* + * Timer start and judgment + */ + + /* timer start */ + tm_p->tbl[tm_p->side].id = timeout(scf_tout, + &tm_p->tbl[tm_p->side], + drv_usectohz(SCF_MIL2MICRO(tm_p->value))); + + /* Timer start flag ON */ + tm_p->restart = FLAG_OFF; + + SC_DBG_DRV_TRACE(TC_T_START, __LINE__, &ii, + sizeof (ii)); + } + } + +/* + * END_timer_stop_collect + */ + END_timer_stop_collect: + + SCFDBGMSG1(SCF_DBGFLAG_TIMER, SCF_FUNC_NAME ": end tm_stop_cnt = %d", + tm_stop_cnt); + return (tm_stop_cnt); +} + + +/* + * scf_timer_untimeout() + * + * Description: Timer stop subroutine. + * + */ +void +scf_timer_untimeout(timeout_id_t *tmids, int size) +{ +#undef SCF_FUNC_NAME +#define SCF_FUNC_NAME "scf_timer_untimeout() " + int ii; /* Working value : counter */ + + SCFDBGMSG(SCF_DBGFLAG_TIMER, SCF_FUNC_NAME ": start"); + + /* Save timer id stop */ + for (ii = 0; ii < size; ii++) { + if (tmids[ii] != 0) { + (void) untimeout(tmids[ii]); + } + } + + SCFDBGMSG(SCF_DBGFLAG_TIMER, SCF_FUNC_NAME ": end"); +} diff --git a/usr/src/uts/sun4u/opl/io/scfd/scftrace.c b/usr/src/uts/sun4u/opl/io/scfd/scftrace.c new file mode 100644 index 0000000000..1477d4f492 --- /dev/null +++ b/usr/src/uts/sun4u/opl/io/scfd/scftrace.c @@ -0,0 +1,152 @@ +/* + * 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 + */ +/* + * All Rights Reserved, Copyright (c) FUJITSU LIMITED 2006 + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/conf.h> +#include <sys/cmn_err.h> +#include <sys/errno.h> +#include <sys/time.h> +#include <sys/ddi.h> +#include <sys/sunddi.h> + +#include <sys/scfd/scfparam.h> + +#ifdef DEBUG +/* + * SCF driver trace flag + */ +ushort_t scf_trace_exec = 1; /* 1:trace exec, 0:Trace no exec */ + +ushort_t scf_trace_flag = 0xff00; +/* + * xxxx xxxx : scf_trace_flag + * 1 : Error trace exec + * 1 : Busy trace exec + * 1 : Messege trace exec + * 1 : RD register trace exec + * 1 : WR register trace exec + * 1 : Timer trace exec + * 1 : Func out trace exec + * 1 : Func in trace exec + */ + +/* + * SCF driver trace debug flag + */ +uint_t scf_trace_msg_flag = 0x00000000; /* trace massege flag */ + + +/* + * Function list + */ +void scf_trace(ushort_t code, ushort_t line, uchar_t *info, ushort_t size); + + +/* + * scf_trace() + * + * SCF Driver trace get processing. + * + * 0 +--------------+ + * | sorce line | trace get source line + * 2 +--------------+ + * | time | trace get time (100ms) + * 4 +--------------+ + * | triger code | trace triger code + * 6 +--------------+ + * | info size | infomarion size + * 8 +--------------+ + * | | + * A + + + * | | + * C + info + infomarion + * | | + * E + + + * | | + * 10 +--------------+ + * + */ +void +scf_trace(ushort_t code, ushort_t line, uchar_t *info, ushort_t size) +{ + scf_trctbl_t trace_wk; + scf_trctbl_t *trcp; + uchar_t *in_p; + uchar_t *out_p; + clock_t clock_val; + int ii; + int trcflag = 0; + + if ((scf_trace_exec) && + ((code & scf_trace_flag) || (!(code & 0xFF00)))) { + if (scf_comtbl.resource_flag & DID_MUTEX_TRC) { + mutex_enter(&scf_comtbl.trc_mutex); + trcflag = 1; + } + } + + if (!trcflag) { + return; + } + + trcp = (scf_trctbl_t *)&trace_wk.line; + trcp->line = line; + clock_val = ddi_get_lbolt(); + trcp->tmvl = (ushort_t)(drv_hztousec(clock_val) / 100000); + trcp->code = code; + trcp->size = size; + for (ii = 0; ii < sizeof (trace_wk.info); ii++) { + if (ii < size) { + trcp->info[ii] = *(info+ii); + } else { + trcp->info[ii] = 0; + } + } + + if (trcflag) { + in_p = (uchar_t *)trcp; + out_p = (uchar_t *)scf_comtbl.trace_w; + scf_comtbl.trace_w++; + if (scf_comtbl.trace_w == scf_comtbl.trace_l) { + scf_comtbl.trace_w = scf_comtbl.trace_f; + } + for (ii = 0; ii < 16; ii++, in_p++, out_p++) *out_p = *in_p; + if (trcp->code & (TC_ERR | TC_ERRCD)) { + in_p = (uchar_t *)trcp; + out_p = (uchar_t *)scf_comtbl.err_trace_w; + for (ii = 0; ii < 16; ii++, in_p++, out_p++) + *out_p = *in_p; + scf_comtbl.err_trace_w++; + if (scf_comtbl.err_trace_w == scf_comtbl.err_trace_l) { + scf_comtbl.err_trace_w = scf_comtbl.err_trace_f; + } + } + } + + if (trcflag) { + mutex_exit(&scf_comtbl.trc_mutex); + } +} +#endif diff --git a/usr/src/uts/sun4u/opl/mc-opl/Makefile b/usr/src/uts/sun4u/opl/mc-opl/Makefile new file mode 100644 index 0000000000..d089913fa3 --- /dev/null +++ b/usr/src/uts/sun4u/opl/mc-opl/Makefile @@ -0,0 +1,98 @@ +# +# 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. +# +#ident "%Z%%M% %I% %E% SMI" +# +# This makefile drives the production of the mc-opl driver kernel +# module. +# +# sun4u oplimplementation architecture dependent +# +# uts/sun4u/opl/mc-opl/Makefile +# +# +#Path to the base of the uts directory tree(/usr/src/uts) +# +UTSBASE = ../../.. + +# +#Define the module and object file sets. +# +MODULE = mc-opl +OBJECTS = $(MC_OPL_OBJS:%=$(OBJS_DIR)/%) +LINTS = $(MC_OPL_OBJS:%.o=$(LINTS_DIR)/%.ln) +ROOTMODULE = $(ROOT_OPL_DRV_DIR)/$(MODULE) +CONF_SRCDIR = $(UTSBASE)/sun4u/opl/io + +# +# Include common rules. +# +include $(UTSBASE)/sun4u/opl/Makefile.opl + +# +# Define targets +# +ALL_TARGET = $(BINARY) +LINT_TARGET = $(MODULE).lint +INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE) + +# +# lint pass one enforcement +# +CFLAGS += $(CCVERBOSE) -I../sys + +# +# Turn on doubleword alignment for 64 bit registers +# +# CFLAGS +# MC_EMULATION - emulate mac patrol registers +# +CFLAGS += -dalign -DMC_EMULATION +#CFLAGS += -dalign + +# +# 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)/sun4u/opl/Makefile.targ diff --git a/usr/src/uts/sun4u/opl/ml/drmach.il.cpp b/usr/src/uts/sun4u/opl/ml/drmach.il.cpp new file mode 100644 index 0000000000..24d9c195c2 --- /dev/null +++ b/usr/src/uts/sun4u/opl/ml/drmach.il.cpp @@ -0,0 +1,198 @@ +/* + * 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 file is through cpp before being used as + * an inline. It contains support routines used + * only by DR for the copy-rename sequence. + */ + +#if defined(lint) +#include <sys/types.h> +#endif /* lint */ + +#ifndef INLINE + +#include <sys/asm_linkage.h> + +#else /* INLINE */ + +#define ENTRY_NP(x) .inline x,0 +#define retl /* nop */ +#define SET_SIZE(x) .end + +#endif /* INLINE */ + +#include <sys/privregs.h> +#include <sys/sun4asi.h> +#include <sys/machparam.h> + +#include <sys/intreg.h> +#include <sys/opl_olympus_regs.h> + +/* + * Bcopy routine used by DR to copy + * between physical addresses. + * Borrowed from Starfire DR 2.6. + */ +#if defined(lint) + +/*ARGSUSED*/ +void +bcopy32_il(uint64_t paddr1, uint64_t paddr2) +{} + +#else /* lint */ + + ENTRY_NP(bcopy32_il) + .register %g2, #scratch + .register %g3, #scratch + rdpr %pstate, %g0 + ldxa [%o0]ASI_MEM, %o2 + add %o0, 8, %o0 + ldxa [%o0]ASI_MEM, %o3 + add %o0, 8, %o0 + ldxa [%o0]ASI_MEM, %g1 + add %o0, 8, %o0 + ldxa [%o0]ASI_MEM, %g2 + + stxa %o2, [%o1]ASI_MEM + add %o1, 8, %o1 + stxa %o3, [%o1]ASI_MEM + add %o1, 8, %o1 + stxa %g1, [%o1]ASI_MEM + add %o1, 8, %o1 + stxa %g2, [%o1]ASI_MEM + + retl + nop + SET_SIZE(bcopy32_il) + +#endif /* lint */ + +#if defined(lint) + +/*ARGSUSED*/ +void +flush_cache_il(void) +{} + +#else /* lint */ + + ENTRY_NP(flush_cache_il) + rdpr %pstate, %o3 + andn %o3, PSTATE_IE, %o4 + wrpr %g0, %o4, %pstate + mov ASI_L2_CTRL_U2_FLUSH, %o4 + mov ASI_L2_CTRL_RW_ADDR, %o5 + stxa %o4, [%o5]ASI_L2_CTRL + ! retl + wrpr %g0, %o3, %pstate ! restore earlier pstate + SET_SIZE(flush_cache_il) + +#endif /* lint */ + +#if defined(lint) +/* ARGUSED */ +uint64_t +drmach_get_stick_il(void) +{} + +#else /* lint */ + ENTRY_NP(drmach_get_stick_il) + retl + rd STICK, %o0 + SET_SIZE(drmach_get_stick_il) +#endif /* lint */ + +#if defined(lint) +/* ARGUSED */ +void +membar_sync_il(void) +{} + +#else /* lint */ + ENTRY_NP(membar_sync_il) + retl + membar #Sync + SET_SIZE(membar_sync_il) +#endif /* lint */ + + +#if defined(lint) + +/* ARGSUSED */ +void +flush_instr_mem_il(caddr_t vaddr) +{} + +#else /* lint */ + +/* + * flush_instr_mem: + * Flush 1 page of the I-$ starting at vaddr + * %o0 vaddr + * + * SPARC64-VI maintains consistency of the on-chip Instruction Cache with + * the stores from all processors so that a FLUSH instruction is only needed + * to ensure pipeline is consistent. This means a single flush is sufficient at + * the end of a sequence of stores that updates the instruction stream to + * ensure correct operation. + */ + + ENTRY_NP(flush_instr_mem_il) + flush %o0 ! address irrelevent + retl + nop + SET_SIZE(flush_instr_mem_il) + +#endif /* lint */ + +#if defined(lint) + +/* ARGSUSED */ +void +drmach_sleep_il(void) +{} + +#else /* lint */ + +/* + * drmach-sleep_il: + * + * busy loop wait can affect performance of the sibling strand + * the sleep instruction can be used to avoid that. + */ + + ENTRY_NP(drmach_sleep_il) +.word 0x81b01060 + retl + nop + SET_SIZE(flush_instr_mem_il) + +#endif /* lint */ diff --git a/usr/src/uts/sun4u/opl/ml/drmach_asm.s b/usr/src/uts/sun4u/opl/ml/drmach_asm.s new file mode 100644 index 0000000000..870b954b7c --- /dev/null +++ b/usr/src/uts/sun4u/opl/ml/drmach_asm.s @@ -0,0 +1,507 @@ +/* + * 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 file is through cpp before being used as + * an inline. It contains support routines used + * only by DR for the copy-rename sequence. + */ + +#if defined(lint) +#include <sys/types.h> +#else +#include "assym.h" +#include "drmach_offsets.h" +#endif /* lint */ + +#include <sys/asm_linkage.h> +#include <sys/param.h> +#include <sys/privregs.h> +#include <sys/spitregs.h> +#include <sys/mmu.h> +#include <sys/machthread.h> +#include <sys/pte.h> +#include <sys/stack.h> +#include <sys/vis.h> +#include <sys/intreg.h> +#include <sys/cheetahregs.h> +#include <sys/drmach.h> + +#if !defined(lint) + +/* + * turn off speculative mode to prevent unwanted memory access + * when we are in the FMEM loops + */ + +#define FJSV_SPECULATIVE_OFF(reg, tmp1, tmp2) \ + rdpr %pstate, reg ;\ + andn reg, PSTATE_IE, tmp1 ;\ + wrpr %g0, tmp1, %pstate ;\ + ldxa [%g0]ASI_MCNTL, tmp1 ;\ + set 1, tmp2 ;\ + sllx tmp2, MCNTL_SPECULATIVE_SHIFT, tmp2 ;\ + or tmp1, tmp2, tmp1 ;\ + stxa tmp1, [%g0]ASI_MCNTL ;\ + membar #Sync +#endif + + +#if defined(lint) +/*ARGSUSED*/ +void +drmach_fmem_loop_script(caddr_t critical, int size, caddr_t stat) +{ return; } +#else /* lint */ + .align 8 + ENTRY_NP(drmach_fmem_loop_script) + /* turn off speculative mode */ + FJSV_SPECULATIVE_OFF(%o5, %o3, %o4); + + /* read the critical region to get everything in the cache */ + mov %o0, %o3 +0: + ldx [%o3], %o4 + sub %o1, 8, %o1 + brnz %o1, 0b + add %o3, 8, %o3 + + /* clear L2_CTRL_UGE_TRAP error bit */ + mov ASI_L2_CTRL_RW_ADDR, %o1 + ldxa [%o1]ASI_L2_CTRL, %o3 + sethi %hi(ASI_L2_CTRL_UGE_TRAP), %o4 + btst %o3, %o4 + bz,pn %xcc, 1f + nop + stxa %o4, [%o1]ASI_L2_CTRL + + /* now tell the master CPU that we are ready */ +1: + set FMEM_LOOP_FMEM_READY, %o3 + stb %o3, [%o2] + membar #Sync + ba 5f + nop + + /* + * note that we branch to 5f, which branches right back to 2 here. + * The trick is that when that branch instruction has already been + * patched to a branch to itself - an infinite loop. + * The master thread will patch it back to "ba 2b" when it + * completes. + */ + + /* Once we are back, we first check if there has been any + * L2_CTRL_UGE_TRAP errors, if so we have to fail the + * operation. This will cause a panic because the system + * is already in inconsistent state. + */ +2: + mov %g0, %o1 + mov ASI_L2_CTRL_RW_ADDR, %o3 + ldxa [%o3]ASI_L2_CTRL, %o3 + sethi %hi(ASI_L2_CTRL_UGE_TRAP), %o4 + btst %o3, %o4 + bz,pn %xcc, 3f + mov %g0, %o4 + set FMEM_HW_ERROR, %o4 + + /* set error code and stat code */ +3: + set FMEM_LOOP_DONE, %o3 + stb %o3, [%o2] + + /* turn on speculative mode again */ + ldxa [%g0]ASI_MCNTL, %o0 + set 1, %o1 + sllx %o1, MCNTL_SPECULATIVE_SHIFT, %o1 + andn %o0, %o1, %o0 + ba 4f + nop +.align 32 +4: + stxa %o0, [%g0]ASI_MCNTL + membar #Sync + wrpr %g0, %o5, %pstate + retl + mov %o4, %o0 +.align 8 +5: + ALTENTRY(drmach_fmem_loop_script_rtn) + /* + * busy wait will affect sibling strands so + * we put sleep instruction in the delay slot + */ + ba 2b +.word 0x81b01060 + nop + SET_SIZE(drmach_fmem_loop_script) +#endif /* lint */ + +#if defined(lint) +/*ARGSUSED*/ +void +drmach_flush_icache(void) +{ return; } +#else /* lint */ + .align 8 + ENTRY_NP(drmach_flush_icache) + stxa %g0, [%g0]ASI_ALL_FLUSH_L1I + membar #Sync + retl + nop + SET_SIZE(drmach_flush_icache) +#endif + +#if defined(lint) +/*ARGSUSED*/ +int +drmach_fmem_exec_script(caddr_t critical, int size) +{ return (0); } +#else /* lint */ +.align 32 + ENTRY_NP(drmach_fmem_exec_script) + /* turn off speculative mode */ + FJSV_SPECULATIVE_OFF(%o5, %o3, %o4); + /* save locals to save area */ + add %o0, SAVE_LOCAL, %o2 + stx %l0, [%o2+8*0] + stx %l1, [%o2+8*1] + stx %l2, [%o2+8*2] + stx %l3, [%o2+8*3] + stx %l4, [%o2+8*4] + stx %l5, [%o2+8*5] + stx %l6, [%o2+8*6] + stx %l7, [%o2+8*7] + mov %o5, %l6 + /* l7 is set only when FMEM cmd is issued to SCF */ + mov %g0, %l7 + + /* read the critical region to put everything in the cache */ + mov %o0, %o2 +0: + ldx [%o2], %o4 + sub %o1, 8, %o1 + brnz %o1, 0b + add %o2, 8, %o2 + ba 4f + nop + + /* we branch to 4f but eventually we branch back here to finish up */ +1: + mov %l6, %o5 + /* + * save some registers for debugging + * l0 - SCF_REG_BASE + * l1 - SCF_TD + * l2 - SCF_TD + 8 + * l5 - DELAY + */ + add %o0, SAVE_LOG, %o1 + stx %l0, [%o1+8*0] + stx %l1, [%o1+8*1] + stx %l2, [%o1+8*2] + stx %l5, [%o1+8*3] + + add %o0, FMEM_ISSUED, %o1 + st %l7, [%o1] + + /* Check for L2_CTRL_UGE_TRAP error */ + mov ASI_L2_CTRL_RW_ADDR, %l0 + ldxa [%l0]ASI_L2_CTRL, %l1 + sethi %hi(ASI_L2_CTRL_UGE_TRAP), %l2 + btst %l1, %l2 + bz,pn %xcc, 2f + nop + mov FMEM_HW_ERROR, %o4 +2: + /* restore all locals */ + add %o0, SAVE_LOCAL, %o1 + ldx [%o1+8*0], %l0 + ldx [%o1+8*1], %l1 + ldx [%o1+8*2], %l2 + ldx [%o1+8*3], %l3 + ldx [%o1+8*4], %l4 + ldx [%o1+8*5], %l5 + ldx [%o1+8*6], %l6 + ldx [%o1+8*7], %l7 + + /* turn on speculative mode */ + ldxa [%g0]ASI_MCNTL, %o1 + set 1, %o2 + sllx %o2, MCNTL_SPECULATIVE_SHIFT, %o2 + andn %o1, %o2, %o1 + ba 3f + nop +.align 32 +3: + stxa %o1, [%g0]ASI_MCNTL + membar #Sync + /* return error code here */ + mov %o4, %o0 + retl + wrpr %g0, %o5, %pstate + + /* clear L2_CTRL_UGE_TRAP error bit */ +4: + mov ASI_L2_CTRL_RW_ADDR, %l0 + ldxa [%l0]ASI_L2_CTRL, %l1 + sethi %hi(ASI_L2_CTRL_UGE_TRAP), %l2 + btst %l1, %l2 + bz,pn %xcc, 5f + nop + stxa %l2, [%l0]ASI_L2_CTRL +5: + /* set up the register locations and parameters */ + ldx [%o0 + SCF_REG_BASE], %l0 + ldx [%o0 + SCF_TD], %l1 + ldx [%o0 + SCF_TD+8], %l2 + ldx [%o0 + DELAY], %l5 + + /* check if SCF is busy */ + add %l0, SCF_COMMAND, %o1 + lduha [%o1]ASI_IO, %o2 + sethi %hi(SCF_CMD_BUSY), %o3 + btst %o2, %o3 + be %xcc, 6f + nop + ba 1b + mov FMEM_SCF_BUSY, %o4 + + /* clear STATUS bit */ +6: + add %l0, SCF_STATUS, %o1 + lduha [%o1]ASI_IO, %o2 + sethi %hi(SCF_STATUS_READY), %o3 + btst %o2, %o3 + be %xcc, 7f + nop + stha %o3, [%o1]ASI_IO + + /* clear CMD_COMPLETE bit */ +7: + mov SCF_STATUS_CMD_COMPLETE, %o3 + btst %o2, %o3 + be,a %xcc, 8f + nop + stha %o3, [%o1]ASI_IO +8: + add %l0, (SCF_TDATA+0xe), %o1 + mov %l2, %o4 + mov SCF_RETRY_CNT, %o5 + + sethi %hi(0xffff), %l2 + or %l2, %lo(0xffff), %l2 + + and %o4, %l2, %o3 + + /* + * o1 points to SCFBASE.SCF_TDATA[0xe] + * l0 points to SCFBASE + * crticial->SCF_TD[0] = source board # + * crticial->SCF_TD[1] = target board # + * l1 = critical->SCF_TD[0 - 7] + * l2 = 0xffff + * o4 = critical->SCF_TD[8 - 15] + * o3 = (*o4) & 0xffff + + /* + * Because there is no parity protection on the ebus + * we read the data back after the write to verify + * we write 2 bytes at a time. + * If the data read is not the same as data written + * we retry up to a limit of FMEM_RETRY_OUT + */ +9: + stha %o3, [%o1]ASI_IO + lduha [%o1]ASI_IO, %o2 + sub %o5, 1, %o5 + brz,a %o5, 1b + mov FMEM_RETRY_OUT, %o4 + cmp %o2, %o3 + bne,a 9b + nop + + sub %o1, %l0, %o2 + cmp %o2, (SCF_TDATA+0x8) + bne %xcc, 2f + srlx %o4, 16, %o4 + mov %l1, %o4 + + /* if we have reach TDATA+8, we switch to l1 */ + /* XXX: Why we need 2 loops??? */ +2: + sub %o1, 2, %o1 + mov SCF_RETRY_CNT, %o5 + and %o4, %l2, %o3 + + sub %o1, %l0, %o2 + cmp %o2, (SCF_TDATA) + bge,a 9b + nop + + /* if we reach TDATA, we are done */ + + /* read from SCF back to our buffer for debugging */ + add %l0, (SCF_TDATA), %o1 + ldxa [%o1]ASI_IO, %o2 + stx %o2, [%o0+SCF_TD] + + add %l0, (SCF_TDATA+8), %o1 + ldxa [%o1]ASI_IO, %o2 + stx %o2, [%o0+SCF_TD+8] + + + rd STICK, %l1 + add %l5, %l1, %l5 + + /* Now tell SCF to do it */ + add %l0, SCF_COMMAND, %o1 + + /* 0x10A6 is the magic command */ + sethi %hi(0x10A6), %o2 + or %o2, %lo(0x10A6), %o2 + stha %o2, [%o1]ASI_IO + + mov 1, %l7 ! FMEM is issued + + add %l0, SCF_STATUS, %o1 + sethi %hi(SCF_STATUS_READY), %o2 + mov SCF_STATUS_CMD_COMPLETE, %o3 + + /* read STATUS_READY bit and clear it only if it is set */ + /* XXX: this STATUS_READY checking seems meaningless */ +3: + lduha [%o1]ASI_IO, %o4 + btst %o2, %o4 + be %xcc, 4f ! STATUS_READY is not set + nop + stha %o2, [%o1]ASI_IO ! Clear if the bit is set + + /* check CMD_COMPLETE bit and clear */ +4: + btst %o3, %o4 + be %xcc, 5f ! CMD_COMPLETE is not set + nop + stha %o3, [%o1]ASI_IO ! Now we are done and clear it + mov FMEM_NO_ERROR, %o4 + ba %xcc, 6f + nop + + /* timeout delay checking */ +5: + rd STICK, %l2 + cmp %l5, %l2 + bge %xcc, 3b + nop + mov FMEM_TIMEOUT, %o4 + + /* we are done or timed out */ +6: + ba,a 1b + nop + SET_SIZE(drmach_fmem_exec_script) +#endif /* lint */ + +#if defined(lint) +/*ARGSUSED*/ +void +drmach_fmem_exec_script_end(caddr_t critical, int size) +{ return; } +#else /* lint */ + ENTRY_NP(drmach_fmem_exec_script_end) + nop + SET_SIZE(drmach_fmem_exec_script_end) +#endif /* lint */ + +#if defined(lint) +uint64_t +patch_inst(uint64_t *x, uint64_t y) +{ + *x = y; + return (0); +} + +#else /* lint */ + + ENTRY_NP(patch_inst) + ldx [%o0], %o2 + casx [%o0], %o2, %o1 + flush %o0 + membar #Sync + ldx [%o0], %o2 + retl + mov %o2, %o0 + SET_SIZE(patch_inst) + +#endif /* lint */ + +#if defined(lint) +void +drmach_sys_trap() +{ +} +#else /* lint */ + ENTRY_NP(drmach_sys_trap) + mov -1, %g4 + set sys_trap, %g5 + jmp %g5 + nop + SET_SIZE(drmach_sys_trap) +#endif /* lint */ + +#if defined(lint) +uint64_t +drmach_get_stick() +{ + return (0); +} +#else /* lint */ + ENTRY_NP(drmach_get_stick) + retl + rd STICK, %o0 + SET_SIZE(drmach_get_stick) +#endif /* lint */ + +#if defined(lint) +/*ARGSUSED*/ +void +drmach_flush(void) +{} + +#else /* lint */ + ENTRY_NP(drmach_flush) + mov %o0, %o2 +0: + flush %o2 + sub %o1, 8, %o1 + brnz %o1, 0b + add %o2, 8, %o2 + retl + nop + SET_SIZE(drmach_flush) +#endif /* lint */ diff --git a/usr/src/uts/sun4u/opl/ml/drmach_offsets.in b/usr/src/uts/sun4u/opl/ml/drmach_offsets.in new file mode 100644 index 0000000000..de88434a7e --- /dev/null +++ b/usr/src/uts/sun4u/opl/ml/drmach_offsets.in @@ -0,0 +1,60 @@ +\ +\ Copyright 2006 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 +\ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <sys/sysmacros.h> +#include <sys/param.h> +#include <sys/machparam.h> +#include <sys/systm.h> +#include <sys/machsystm.h> +#include <sys/cpuvar.h> + +#include <sys/drmach.h> + +drmach_copy_rename_critical_t DRMACH_COPY_RENAME_CRITICAL_SIZE + scf_reg_base + scf_td + save_log + save_local + pstate + delay + run + fmem + loop + loop_rtn + inst_loop_ret + fmem_issued + +drmach_scf_regs_t SCF_REG_SIZE + scf_command + scf_status + scf_version + scf_tdata + scf_rdata + +drmach_fmem_mbox_t FMEM_MBOX_SIZE + stat + error diff --git a/usr/src/uts/sun4u/opl/olympus_c/Makefile b/usr/src/uts/sun4u/opl/olympus_c/Makefile new file mode 100644 index 0000000000..1cfb812323 --- /dev/null +++ b/usr/src/uts/sun4u/opl/olympus_c/Makefile @@ -0,0 +1,116 @@ +# +# 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. +# +# ident "%Z%%M% %I% %E% SMI" +# +# This makefile drives the production of the OPL specific +# Olympus-C driver module. +# +# uts/sun4u/opl/olympus_c/Makefile +# + +# +# Path to the base of the uts directory tree (usually /usr/src/uts). +# +UTSBASE = ../../.. + +# +# Define the module and object file sets. +# +MODULE = FJSV,SPARC64-VI +OBJECTS = $(OLYMPUS_OBJS:%=$(OBJS_DIR)/%) +LINTS = $(OLYMPUS_OBJS:%.o=$(LINTS_DIR)/%.ln) +ROOTMODULE = $(ROOT_OPL_CPU_DIR)/$(MODULE) + +CPU_DIR = . +HERE = ../olympus_c + +# +# Include common rules. +# +include $(UTSBASE)/sun4u/opl/Makefile.opl + +# +# Override defaults +# +CLEANFILES += $(CPULIB) $(SYM_MOD) + +# +# Define targets +# +ALL_TARGET = $(SYM_MOD) +LINT_TARGET = $(MODULE).lint +INSTALL_TARGET = def $(BINARY) $(ROOTMODULE) $(ROOTSOFTLINKS) + +# +# Overrides +# +ALL_BUILDS = $(ALL_BUILDSONLY64) +DEF_BUILDS = $(DEF_BUILDSONLY64) +CLEANLINTFILES += $(LINT32_FILES) + +# +# lint pass one enforcement +# +OLYMPUS_C_DEFS += -DOLYMPUS_C +CFLAGS += $(CCVERBOSE) $(OLYMPUS_C_DEFS) + +CPPFLAGS += -DCPU_MODULE -DOLYMPUS_C +AS_CPPFLAGS += -DCPU_MODULE -DOLYMPUS_C + +# +# Default build targets. +# +.KEEP_STATE: + +all: $(ALL_DEPS) + +def: $(DEF_DEPS) + +clean: $(CLEAN_DEPS) + +clobber: $(CLOBBER_DEPS) + +lint: $(LINT_DEPS) + +modlintlib: $(MODLINTLIB_DEPS) + +clean.lint: $(CLEAN_LINT_DEPS) + +install: $(INSTALL_DEPS) + +$(CPULIB): $(BINARY) + $(BUILD.SO) $(BINARY) + +$(SYM_MOD): $(UNIX_O) $(CPULIB) + @$(ECHO) "resolving symbols against unix.o" + @(cd $(UNIX_DIR); pwd; \ + CPU_DIR=$(HERE) SYM_MOD=$(HERE)/$(SYM_MOD) $(MAKE) symcheck) + +$(ROOTSOFTLINKS): $(ROOTMODULE) + $(RM) $@; $(SYMLINK) $(MODULE) $@ $(CHOWNLINK) $(CHGRPLINK) + +# Include common targets. +# +include $(UTSBASE)/sun4u/opl/Makefile.targ diff --git a/usr/src/uts/sun4u/opl/oplkmdrv/Makefile b/usr/src/uts/sun4u/opl/oplkmdrv/Makefile new file mode 100644 index 0000000000..6645855b82 --- /dev/null +++ b/usr/src/uts/sun4u/opl/oplkmdrv/Makefile @@ -0,0 +1,100 @@ +# +# 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. +# +# ident "%Z%%M% %I% %E% SMI" +# +# This makefile drives the production of the oplkmdrv driver +# kernel module. +# +# sun4u implementation architecture dependent +# + +# +# Path to the base of the uts directory tree (usually /usr/src/uts). +# +UTSBASE = ../../.. +INC_PATH += -I$(UTSBASE)/sun4u/starcat/ + +# +# Define the module and object file sets. +# + +MODULE = oplkmdrv +OBJECTS = $(OPLKM_OBJS:%=$(OBJS_DIR)/%) +LINTS = $(OPLKM_OBJS:%.o=$(LINTS_DIR)/%.ln) +ROOTMODULE = $(ROOT_OPL_DRV_DIR)/$(MODULE) +CONF_SRCDIR = $(UTSBASE)/sun4u/opl/io + +# +# Include common rules. +# +include $(UTSBASE)/sun4u/opl/Makefile.opl + +# +# Define targets +# +ALL_TARGET = $(BINARY) $(SRC_CONFFILE) +LINT_TARGET = $(MODULE).lint +INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE) + +# +# lint pass one enforcement +# +CFLAGS += $(CCVERBOSE) + +# +# Turn on doubleword alignment for 64 bit registers +# +CFLAGS += -dalign + +# +# Dependency +# +LDFLAGS += -dy -Ndrv/scfd + +# +# 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)/sun4u/opl/Makefile.targ diff --git a/usr/src/uts/sun4u/opl/oplmsu/Makefile b/usr/src/uts/sun4u/opl/oplmsu/Makefile new file mode 100644 index 0000000000..851e374f41 --- /dev/null +++ b/usr/src/uts/sun4u/opl/oplmsu/Makefile @@ -0,0 +1,88 @@ +# +# 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 makefile drives the production of the oplmsu driver +# loadable module. +# +# sun4u opl implementation architecture dependent +# + +# +# Path to the base of the uts directory tree (usually /usr/src/uts). +# +UTSBASE = ../../.. + +# +# Define the module and object file sets. +# +MODULE = oplmsu +OBJECTS = $(OPLMSU_OBJS:%=$(OBJS_DIR)/%) +LINTS = $(OPLMSU_OBJS:%.o=$(LINTS_DIR)/%.ln) +ROOTMODULE = $(ROOT_OPL_DRV_DIR)/$(MODULE) + +# +# Include common rules. +# +include $(UTSBASE)/sun4u/opl/Makefile.opl + +# +# Define targets +# +ALL_TARGET = $(BINARY) +LINT_TARGET = $(MODULE).lint +INSTALL_TARGET = $(BINARY) $(ROOTMODULE) + +# +# lint pass one enforcement +# +CFLAGS += $(CCVERBOSE) -I../sys +LDFLAGS += -dy -Ndrv/su + +# +# 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)/sun4u/opl/Makefile.targ diff --git a/usr/src/uts/sun4u/opl/oplpanel/Makefile b/usr/src/uts/sun4u/opl/oplpanel/Makefile new file mode 100644 index 0000000000..5d2f757b40 --- /dev/null +++ b/usr/src/uts/sun4u/opl/oplpanel/Makefile @@ -0,0 +1,87 @@ +# +# 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 makefile drives the production of the oplpanel driver +# loadable module. +# +# sun4u opl implementation architecture dependent +# + +# +# Path to the base of the uts directory tree (usually /usr/src/uts). +# +UTSBASE = ../../.. + +# +# Define the module and object file sets. +# +MODULE = oplpanel +OBJECTS = $(OPL_PANEL_OBJS:%=$(OBJS_DIR)/%) +LINTS = $(OPL_PANEL_OBJS:%.o=$(LINTS_DIR)/%.ln) +ROOTMODULE = $(ROOT_OPL_DRV_DIR)/$(MODULE) +CONF_SRCDIR = $(UTSBASE)/sun4u/opl/io/oplpanel + +# +# Include common rules. +# +include $(UTSBASE)/sun4u/opl/Makefile.opl + +# +# Define targets +# +ALL_TARGET = $(BINARY) $(SRC_CONFFILE) +LINT_TARGET = $(MODULE).lint +INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE) + +# +# lint pass one enforcement +# +CFLAGS += $(CCVERBOSE) -I../sys + +# +# 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)/sun4u/opl/Makefile.targ diff --git a/usr/src/uts/sun4u/opl/options/Makefile b/usr/src/uts/sun4u/opl/options/Makefile new file mode 100644 index 0000000000..44b6f3a7b3 --- /dev/null +++ b/usr/src/uts/sun4u/opl/options/Makefile @@ -0,0 +1,86 @@ +# +# 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. +# +#ident "%Z%%M% %I% %E% SMI" +# +# uts/sun4u/opl/options/Makefile +# +# This makefile drives the production of the opl options conf file +# +# sparc architecture dependent +# +# +# Path to the base of the uts directory tree (usually /usr/src/uts). +# +UTSBASE = ../../.. + +# +# Define the module and object file sets. +# +MODULE = options +ROOTMODULE = $(ROOT_OPL_DRV_DIR)/$(MODULE) +CONF_SRCDIR = $(UTSBASE)/sun4u/opl/io + +# +# Include common rules. +# +include $(UTSBASE)/sun4u/opl/Makefile.opl + +# +# Define targets +# +ALL_TARGET = $(SRC_CONFILE) +LINT_TARGET = +INSTALL_TARGET = $(ROOT_OPL_DRV_DIR) $(ROOT_CONFFILE) + +# +# Overrides. +# +CFLAGS += $(CCVERBOSE) + +# +# Default build targets. +# +.KEEP_STATE: + +all: $(ALL_DEPS) + +def: $(DEF_DEPS) + +clean: $(CLEAN_DEPS) + +clobber: $(CLOBBER_DEPS) + +lint: $(LINT_DEPS) + +modlintlib: $(MODLINTLIB_DEPS) + +clean.lint: $(CLEAN_LINT_DEPS) + +install: $(INSTALL_DEPS) + +# +# Include common targets. +# +include $(UTSBASE)/sparc/Makefile.targ diff --git a/usr/src/uts/sun4u/opl/os/opl.c b/usr/src/uts/sun4u/opl/os/opl.c new file mode 100644 index 0000000000..c9cfe717ae --- /dev/null +++ b/usr/src/uts/sun4u/opl/os/opl.c @@ -0,0 +1,855 @@ +/* + * 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 <sys/cpuvar.h> +#include <sys/systm.h> +#include <sys/sysmacros.h> +#include <sys/promif.h> +#include <sys/platform_module.h> +#include <sys/cmn_err.h> +#include <sys/errno.h> +#include <sys/machsystm.h> +#include <sys/bootconf.h> +#include <sys/nvpair.h> +#include <sys/kobj.h> +#include <sys/mem_cage.h> +#include <sys/opl.h> +#include <sys/scfd/scfostoescf.h> +#include <sys/cpu_sgnblk_defs.h> +#include <sys/utsname.h> +#include <sys/ddi.h> +#include <sys/sunndi.h> +#include <sys/lgrp.h> +#include <sys/memnode.h> +#include <sys/sysmacros.h> +#include <vm/vm_dep.h> + +int (*opl_get_mem_unum)(int, uint64_t, char *, int, int *); + +/* Memory for fcode claims. 16k times # maximum possible IO units */ +#define EFCODE_SIZE (OPL_MAX_BOARDS * OPL_MAX_IO_UNITS_PER_BOARD * 0x4000) +int efcode_size = EFCODE_SIZE; + +#define OPL_MC_MEMBOARD_SHIFT 38 /* Boards on 256BG boundary */ + +/* Set the maximum number of boards for DR */ +int opl_boards = OPL_MAX_BOARDS; + +void sgn_update_all_cpus(ushort_t, uchar_t, uchar_t); + +extern int tsb_lgrp_affinity; + +int opl_tsb_spares = (OPL_MAX_BOARDS) * (OPL_MAX_PCICH_UNITS_PER_BOARD) * + (OPL_MAX_TSBS_PER_PCICH); + +pgcnt_t opl_startup_cage_size = 0; + +static struct memlist *opl_memlist_per_board(struct memlist *ml); + +int +set_platform_max_ncpus(void) +{ + return (OPL_MAX_CPU_PER_BOARD * OPL_MAX_BOARDS); +} + +int +set_platform_tsb_spares(void) +{ + return (MIN(opl_tsb_spares, MAX_UPA)); +} + +#pragma weak mmu_init_large_pages + +void +set_platform_defaults(void) +{ + extern char *tod_module_name; + extern void cpu_sgn_update(ushort_t, uchar_t, uchar_t, int); + extern int ts_dispatch_extended; + extern void mmu_init_large_pages(size_t); + + /* Set the CPU signature function pointer */ + cpu_sgn_func = cpu_sgn_update; + + /* Set appropriate tod module for OPL platform */ + ASSERT(tod_module_name == NULL); + tod_module_name = "todopl"; + + /* + * Use the alternate TS dispatch table, which is better tuned + * for large servers. + */ + if (ts_dispatch_extended == -1) + ts_dispatch_extended = 1; + + if ((mmu_page_sizes == max_mmu_page_sizes) && + (mmu_ism_pagesize != MMU_PAGESIZE32M)) { + if (&mmu_init_large_pages) + mmu_init_large_pages(mmu_ism_pagesize); + } + + tsb_lgrp_affinity = 1; +} + +/* + * Convert logical a board number to a physical one. + */ + +#define LSBPROP "board#" +#define PSBPROP "physical-board#" + +int +opl_get_physical_board(int id) +{ + dev_info_t *root_dip, *dip = NULL; + char *dname = NULL; + int circ; + + pnode_t pnode; + char pname[MAXSYSNAME] = {0}; + + int lsb_id; /* Logical System Board ID */ + int psb_id; /* Physical System Board ID */ + + + /* + * This function is called on early stage of bootup when the + * kernel device tree is not initialized yet, and also + * later on when the device tree is up. We want to try + * the fast track first. + */ + root_dip = ddi_root_node(); + if (root_dip) { + /* Get from devinfo node */ + ndi_devi_enter(root_dip, &circ); + for (dip = ddi_get_child(root_dip); dip; + dip = ddi_get_next_sibling(dip)) { + + dname = ddi_node_name(dip); + if (strncmp(dname, "pseudo-mc", 9) != 0) + continue; + + if ((lsb_id = (int)ddi_getprop(DDI_DEV_T_ANY, dip, + DDI_PROP_DONTPASS, LSBPROP, -1)) == -1) + continue; + + if (id == lsb_id) { + if ((psb_id = (int)ddi_getprop(DDI_DEV_T_ANY, + dip, DDI_PROP_DONTPASS, PSBPROP, -1)) + == -1) { + ndi_devi_exit(root_dip, circ); + return (-1); + } else { + ndi_devi_exit(root_dip, circ); + return (psb_id); + } + } + } + ndi_devi_exit(root_dip, circ); + } + + /* + * We do not have the kernel device tree, or we did not + * find the node for some reason (let's say the kernel + * device tree was modified), let's try the OBP tree. + */ + pnode = prom_rootnode(); + for (pnode = prom_childnode(pnode); pnode; + pnode = prom_nextnode(pnode)) { + + if ((prom_getprop(pnode, "name", (caddr_t)pname) == -1) || + (strncmp(pname, "pseudo-mc", 9) != 0)) + continue; + + if (prom_getprop(pnode, LSBPROP, (caddr_t)&lsb_id) == -1) + continue; + + if (id == lsb_id) { + if (prom_getprop(pnode, PSBPROP, + (caddr_t)&psb_id) == -1) { + return (-1); + } else { + return (psb_id); + } + } + } + + return (-1); +} + +/* + * For OPL it's possible that memory from two or more successive boards + * will be contiguous across the boards, and therefore represented as a + * single chunk. + * This function splits such chunks down the board boundaries. + */ +static struct memlist * +opl_memlist_per_board(struct memlist *ml) +{ + uint64_t ssize, low, high, boundary; + struct memlist *head, *tail, *new; + + ssize = (1ull << OPL_MC_MEMBOARD_SHIFT); + + head = tail = NULL; + + for (; ml; ml = ml->next) { + low = (uint64_t)ml->address; + high = low+(uint64_t)(ml->size); + while (low < high) { + boundary = roundup(low+1, ssize); + boundary = MIN(high, boundary); + new = kmem_zalloc(sizeof (struct memlist), KM_SLEEP); + new->address = low; + new->size = boundary - low; + if (head == NULL) + head = new; + if (tail) { + tail->next = new; + new->prev = tail; + } + tail = new; + low = boundary; + } + } + return (head); +} + +void +set_platform_cage_params(void) +{ + extern pgcnt_t total_pages; + extern struct memlist *phys_avail; + struct memlist *ml, *tml; + int ret; + + if (kernel_cage_enable) { + pgcnt_t preferred_cage_size; + + preferred_cage_size = + MAX(opl_startup_cage_size, total_pages / 256); + + ml = opl_memlist_per_board(phys_avail); + + kcage_range_lock(); + /* + * Note: we are assuming that post has load the + * whole show in to the high end of memory. Having + * taken this leap, we copy the whole of phys_avail + * the glist and arrange for the cage to grow + * downward (descending pfns). + */ + ret = kcage_range_init(ml, 1); + + /* free the memlist */ + do { + tml = ml->next; + kmem_free(ml, sizeof (struct memlist)); + ml = tml; + } while (ml != NULL); + + if (ret == 0) + kcage_init(preferred_cage_size); + kcage_range_unlock(); + } + + if (kcage_on) + cmn_err(CE_NOTE, "!DR Kernel Cage is ENABLED"); + else + cmn_err(CE_NOTE, "!DR Kernel Cage is DISABLED"); +} + +/*ARGSUSED*/ +int +plat_cpu_poweron(struct cpu *cp) +{ + int (*opl_cpu_poweron)(struct cpu *) = NULL; + + opl_cpu_poweron = + (int (*)(struct cpu *))kobj_getsymvalue("drmach_cpu_poweron", 0); + + if (opl_cpu_poweron == NULL) + return (ENOTSUP); + else + return ((opl_cpu_poweron)(cp)); + +} + +/*ARGSUSED*/ +int +plat_cpu_poweroff(struct cpu *cp) +{ + int (*opl_cpu_poweroff)(struct cpu *) = NULL; + + opl_cpu_poweroff = + (int (*)(struct cpu *))kobj_getsymvalue("drmach_cpu_poweroff", 0); + + if (opl_cpu_poweroff == NULL) + return (ENOTSUP); + else + return ((opl_cpu_poweroff)(cp)); + +} + +int +plat_max_boards(void) +{ + return (OPL_MAX_BOARDS); +} + +int +plat_max_cpu_units_per_board(void) +{ + return (OPL_MAX_CPU_PER_BOARD); +} + +int +plat_max_mem_units_per_board(void) +{ + return (OPL_MAX_MEM_UNITS_PER_BOARD); +} + +int +plat_max_io_units_per_board(void) +{ + return (OPL_MAX_IO_UNITS_PER_BOARD); +} + +int +plat_max_cmp_units_per_board(void) +{ + return (OPL_MAX_CMP_UNITS_PER_BOARD); +} + +int +plat_max_core_units_per_board(void) +{ + return (OPL_MAX_CORE_UNITS_PER_BOARD); +} + +int +plat_pfn_to_mem_node(pfn_t pfn) +{ + return (pfn >> mem_node_pfn_shift); +} + +/* ARGSUSED */ +void +plat_build_mem_nodes(u_longlong_t *list, size_t nelems) +{ + size_t elem; + pfn_t basepfn; + pgcnt_t npgs; + uint64_t boundary, ssize; + uint64_t low, high; + + /* + * OPL mem slices are always aligned on a 256GB boundary. + */ + mem_node_pfn_shift = OPL_MC_MEMBOARD_SHIFT - MMU_PAGESHIFT; + mem_node_physalign = 0; + + /* + * Boot install lists are arranged <addr, len>, <addr, len>, ... + */ + ssize = (1ull << OPL_MC_MEMBOARD_SHIFT); + for (elem = 0; elem < nelems; elem += 2) { + low = (uint64_t)list[elem]; + high = low+(uint64_t)(list[elem+1]); + while (low < high) { + boundary = roundup(low+1, ssize); + boundary = MIN(high, boundary); + basepfn = btop(low); + npgs = btop(boundary - low); + mem_node_add_slice(basepfn, basepfn + npgs - 1); + low = boundary; + } + } +} + +/* + * Find the CPU associated with a slice at boot-time. + */ +void +plat_fill_mc(pnode_t nodeid) +{ + int board; + int memnode; + struct { + uint64_t addr; + uint64_t size; + } mem_range; + + if (prom_getprop(nodeid, "board#", (caddr_t)&board) < 0) { + panic("Can not find board# property in mc node %x", nodeid); + } + if (prom_getprop(nodeid, "sb-mem-ranges", (caddr_t)&mem_range) < 0) { + panic("Can not find sb-mem-ranges property in mc node %x", + nodeid); + } + memnode = mem_range.addr >> OPL_MC_MEMBOARD_SHIFT; + plat_assign_lgrphand_to_mem_node(board, memnode); +} + +/* + * Return the platform handle for the lgroup containing the given CPU + * + * For OPL, lgroup platform handle == board #. + */ + +extern int mpo_disabled; +extern lgrp_handle_t lgrp_default_handle; + +lgrp_handle_t +plat_lgrp_cpu_to_hand(processorid_t id) +{ + lgrp_handle_t plathand; + + /* + * Return the real platform handle for the CPU until + * such time as we know that MPO should be disabled. + * At that point, we set the "mpo_disabled" flag to true, + * and from that point on, return the default handle. + * + * By the time we know that MPO should be disabled, the + * first CPU will have already been added to a leaf + * lgroup, but that's ok. The common lgroup code will + * double check that the boot CPU is in the correct place, + * and in the case where mpo should be disabled, will move + * it to the root if necessary. + */ + if (mpo_disabled) { + /* If MPO is disabled, return the default (UMA) handle */ + plathand = lgrp_default_handle; + } else + plathand = (lgrp_handle_t)LSB_ID(id); + return (plathand); +} + +/* + * Platform specific lgroup initialization + */ +void +plat_lgrp_init(void) +{ + extern uint32_t lgrp_expand_proc_thresh; + extern uint32_t lgrp_expand_proc_diff; + + /* + * Set tuneables for the OPL architecture + * + * lgrp_expand_proc_thresh is the minimum load on the lgroups + * this process is currently running on before considering + * expanding threads to another lgroup. + * + * lgrp_expand_proc_diff determines how much less the remote lgroup + * must be loaded before expanding to it. + * + * Since remote latencies can be costly, attempt to keep 3 threads + * within the same lgroup before expanding to the next lgroup. + */ + lgrp_expand_proc_thresh = LGRP_LOADAVG_THREAD_MAX * 3; + lgrp_expand_proc_diff = LGRP_LOADAVG_THREAD_MAX; +} + +/* + * Platform notification of lgroup (re)configuration changes + */ +/*ARGSUSED*/ +void +plat_lgrp_config(lgrp_config_flag_t evt, uintptr_t arg) +{ + update_membounds_t *umb; + lgrp_config_mem_rename_t lmr; + int sbd, tbd; + lgrp_handle_t hand, shand, thand; + int mnode, snode, tnode; + pfn_t start, end; + + if (mpo_disabled) + return; + + switch (evt) { + + case LGRP_CONFIG_MEM_ADD: + /* + * Establish the lgroup handle to memnode translation. + */ + umb = (update_membounds_t *)arg; + + hand = umb->u_board; + mnode = plat_pfn_to_mem_node(umb->u_base >> MMU_PAGESHIFT); + plat_assign_lgrphand_to_mem_node(hand, mnode); + + break; + + case LGRP_CONFIG_MEM_DEL: + /* + * Special handling for possible memory holes. + */ + umb = (update_membounds_t *)arg; + hand = umb->u_board; + if ((mnode = plat_lgrphand_to_mem_node(hand)) != -1) { + 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); + } + } + + break; + + case LGRP_CONFIG_MEM_RENAME: + /* + * During a DR copy-rename operation, all of the memory + * on one board is moved to another board -- but the + * addresses/pfns and memnodes don't change. This means + * the memory has changed locations without changing identity. + * + * Source is where we are copying from and target is where we + * are copying to. After source memnode is copied to target + * memnode, the physical addresses of the target memnode are + * renamed to match what the source memnode had. Then target + * memnode can be removed and source memnode can take its + * place. + * + * To do this, swap the lgroup handle to memnode mappings for + * the boards, so target lgroup will have source memnode and + * source lgroup will have empty target memnode which is where + * its memory will go (if any is added to it later). + * + * Then source memnode needs to be removed from its lgroup + * and added to the target lgroup where the memory was living + * but under a different name/memnode. The memory was in the + * target memnode and now lives in the source memnode with + * different physical addresses even though it is the same + * memory. + */ + sbd = arg & 0xffff; + tbd = (arg & 0xffff0000) >> 16; + shand = sbd; + thand = tbd; + snode = plat_lgrphand_to_mem_node(shand); + tnode = plat_lgrphand_to_mem_node(thand); + + /* + * Special handling for possible memory holes. + */ + if (tnode != -1 && mem_node_config[tnode].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); + } + + plat_assign_lgrphand_to_mem_node(thand, snode); + plat_assign_lgrphand_to_mem_node(shand, tnode); + + lmr.lmem_rename_from = shand; + lmr.lmem_rename_to = thand; + + /* + * Remove source memnode of copy rename from its lgroup + * and add it to its new target lgroup + */ + lgrp_config(LGRP_CONFIG_MEM_RENAME, (uintptr_t)snode, + (uintptr_t)&lmr); + + break; + + default: + break; + } +} + +/* + * Return latency between "from" and "to" lgroups + * + * This latency number can only be used for relative comparison + * between lgroups on the running system, cannot be used across platforms, + * and may not reflect the actual latency. It is platform and implementation + * specific, so platform gets to decide its value. It would be nice if the + * number was at least proportional to make comparisons more meaningful though. + * NOTE: The numbers below are supposed to be load latencies for uncached + * memory divided by 10. + * + * XXX latency values for Columbus, not Columbus2. Should be fixed later when + * we know the actual numbers for Columbus2. + */ +int +plat_lgrp_latency(lgrp_handle_t from, lgrp_handle_t to) +{ + /* + * Return min remote latency when there are more than two lgroups + * (root and child) and getting latency between two different lgroups + * or root is involved + */ + if (lgrp_optimizations() && (from != to || + from == LGRP_DEFAULT_HANDLE || to == LGRP_DEFAULT_HANDLE)) + return (27); + else + return (25); +} + +/* + * Return platform handle for root lgroup + */ +lgrp_handle_t +plat_lgrp_root_hand(void) +{ + if (mpo_disabled) + return (lgrp_default_handle); + + return (LGRP_DEFAULT_HANDLE); +} + +/*ARGSUSED*/ +void +plat_freelist_process(int mnode) +{ +} + +void +load_platform_drivers(void) +{ + (void) i_ddi_attach_pseudo_node("dr"); +} + +/* + * No platform drivers on this platform + */ +char *platform_module_list[] = { + (char *)0 +}; + +/*ARGSUSED*/ +void +plat_tod_fault(enum tod_fault_type tod_bad) +{ +} + +/*ARGSUSED*/ +void +cpu_sgn_update(ushort_t sgn, uchar_t state, uchar_t sub_state, int cpuid) +{ + static void (*scf_panic_callback)(int); + static void (*scf_shutdown_callback)(int); + + /* + * This is for notifing system panic/shutdown to SCF. + * In case of shutdown and panic, SCF call back + * function should be called. + * <SCF call back functions> + * scf_panic_callb() : panicsys()->panic_quiesce_hw() + * scf_shutdown_callb(): halt() or power_down() or reboot_machine() + * cpuid should be -1 and state should be SIGST_EXIT. + */ + if (state == SIGST_EXIT && cpuid == -1) { + + /* + * find the symbol for the SCF panic callback routine in driver + */ + if (scf_panic_callback == NULL) + scf_panic_callback = (void (*)(int)) + modgetsymvalue("scf_panic_callb", 0); + if (scf_shutdown_callback == NULL) + scf_shutdown_callback = (void (*)(int)) + modgetsymvalue("scf_shutdown_callb", 0); + + switch (sub_state) { + case SIGSUBST_PANIC: + if (scf_panic_callback == NULL) { + cmn_err(CE_NOTE, "!cpu_sgn_update: " + "scf_panic_callb not found\n"); + return; + } + scf_panic_callback(SIGSUBST_PANIC); + break; + + case SIGSUBST_HALT: + if (scf_shutdown_callback == NULL) { + cmn_err(CE_NOTE, "!cpu_sgn_update: " + "scf_shutdown_callb not found\n"); + return; + } + scf_shutdown_callback(SIGSUBST_HALT); + break; + + case SIGSUBST_ENVIRON: + if (scf_shutdown_callback == NULL) { + cmn_err(CE_NOTE, "!cpu_sgn_update: " + "scf_shutdown_callb not found\n"); + return; + } + scf_shutdown_callback(SIGSUBST_ENVIRON); + break; + + case SIGSUBST_REBOOT: + if (scf_shutdown_callback == NULL) { + cmn_err(CE_NOTE, "!cpu_sgn_update: " + "scf_shutdown_callb not found\n"); + return; + } + scf_shutdown_callback(SIGSUBST_REBOOT); + break; + } + } +} + +/*ARGSUSED*/ +int +plat_get_mem_unum(int synd_code, uint64_t flt_addr, int flt_bus_id, + int flt_in_memory, ushort_t flt_status, + char *buf, int buflen, int *lenp) +{ + /* + * check if it's a Memory error. + */ + if (flt_in_memory) { + if (opl_get_mem_unum != NULL) { + return (opl_get_mem_unum(synd_code, flt_addr, + buf, buflen, lenp)); + } else { + return (ENOTSUP); + } + } else { + return (ENOTSUP); + } +} + +/*ARGSUSED*/ +int +plat_get_cpu_unum(int cpuid, char *buf, int buflen, int *lenp) +{ + uint_t sb; + + sb = opl_get_physical_board(LSB_ID(cpuid)); + if (sb == -1) { + return (ENXIO); + } + + if (snprintf(buf, buflen, "CMU%d", sb) >= buflen) { + return (ENOSPC); + } else { + if (lenp) + *lenp = strlen(buf); + return (0); + } +} + +#define SCF_PUTINFO(f, s, p) \ + f(KEY_ESCF, 0x01, 0, s, p) +void +plat_nodename_set(void) +{ + void *datap; + static int (*scf_service_function)(uint32_t, uint8_t, + uint32_t, uint32_t, void *); + int counter = 5; + + /* + * find the symbol for the SCF put routine in driver + */ + if (scf_service_function == NULL) + scf_service_function = + (int (*)(uint32_t, uint8_t, uint32_t, uint32_t, void *)) + modgetsymvalue("scf_service_putinfo", 0); + + /* + * If the symbol was found, call it. Otherwise, log a note (but not to + * the console). + */ + + if (scf_service_function == NULL) { + cmn_err(CE_NOTE, + "!plat_nodename_set: scf_service_putinfo not found\n"); + return; + } + + datap = + (struct utsname *)kmem_zalloc(sizeof (struct utsname), KM_SLEEP); + + if (datap == NULL) { + return; + } + + bcopy((struct utsname *)&utsname, + (struct utsname *)datap, sizeof (struct utsname)); + + while ((SCF_PUTINFO(scf_service_function, + sizeof (struct utsname), datap) == EBUSY) && (counter-- > 0)) { + delay(10 * drv_usectohz(1000000)); + } + if (counter == 0) + cmn_err(CE_NOTE, + "!plat_nodename_set: " + "scf_service_putinfo not responding\n"); + + kmem_free(datap, sizeof (struct utsname)); +} + +caddr_t efcode_vaddr = NULL; + +/* + * Preallocate enough memory for fcode claims. + */ + +caddr_t +efcode_alloc(caddr_t alloc_base) +{ + caddr_t efcode_alloc_base = (caddr_t)roundup((uintptr_t)alloc_base, + MMU_PAGESIZE); + caddr_t vaddr; + + /* + * allocate the physical memory for the Oberon fcode. + */ + if ((vaddr = (caddr_t)BOP_ALLOC(bootops, efcode_alloc_base, + efcode_size, MMU_PAGESIZE)) == NULL) + cmn_err(CE_PANIC, "Cannot allocate Efcode Memory"); + + efcode_vaddr = vaddr; + + return (efcode_alloc_base + efcode_size); +} + +caddr_t +plat_startup_memlist(caddr_t alloc_base) +{ + caddr_t tmp_alloc_base; + + tmp_alloc_base = efcode_alloc(alloc_base); + tmp_alloc_base = + (caddr_t)roundup((uintptr_t)tmp_alloc_base, ecache_alignsize); + return (tmp_alloc_base); +} + +void +startup_platform(void) +{ +} diff --git a/usr/src/uts/sun4u/opl/pcicmu/Makefile b/usr/src/uts/sun4u/opl/pcicmu/Makefile new file mode 100644 index 0000000000..f610c04f77 --- /dev/null +++ b/usr/src/uts/sun4u/opl/pcicmu/Makefile @@ -0,0 +1,93 @@ +# +# 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. +# +# ident "%Z%%M% %I% %E% SMI" +# +# This makefile drives the production of the pcicmu driver kernel module +# +# sun4u opl implementation architecture dependent +# +# uts/sun4u/opl/pcicmu/Makefile +# + +# +# Path to the base of the uts directory tree (usually /usr/src/uts). +# +UTSBASE = ../../.. + +# +# Define the module and object file sets. +# +MODULE = pcicmu +OBJECTS = $(PCICMU_OBJS:%=$(OBJS_DIR)/%) +LINTS = $(PCICMU_OBJS:%.o=$(LINTS_DIR)/%.ln) +ROOTMODULE = $(ROOT_OPL_DRV_DIR)/$(MODULE) + +# +# Include common rules. +# +include $(UTSBASE)/sun4u/opl/Makefile.opl + +# +# Define targets +# +ALL_TARGET = $(BINARY) +LINT_TARGET = $(MODULE).lint +INSTALL_TARGET = $(BINARY) $(ROOTMODULE) + +# +# lint pass one enforcement +# +CFLAGS += $(CCVERBOSE) -I../sys + +# +# Turn on doubleword alignment for 64 bit registers +# +CFLAGS += -dalign + +# +# 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)/sun4u/opl/Makefile.targ diff --git a/usr/src/uts/sun4u/opl/platmod/Makefile b/usr/src/uts/sun4u/opl/platmod/Makefile new file mode 100644 index 0000000000..92016eac00 --- /dev/null +++ b/usr/src/uts/sun4u/opl/platmod/Makefile @@ -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 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# +# This makefile drives the production of the sun4u opl platform +# module. +# +# sun4u opl implementation architecture dependent +# +# uts/sun4u/opl/platmod/Makefile +# + +# +# Path to the base of the uts directory tree (usually /usr/src/uts). +# +UTSBASE = ../../.. +# +# Define the module and object file sets. +# +MODULE = platmod +OBJECTS = $(OPL_OBJS:%=$(OBJS_DIR)/%) +LINTS = $(OPL_OBJS:%.o=$(LINTS_DIR)/%.ln) +ROOTMODULE = $(ROOT_OPL_MISC_DIR)/$(MODULE) +PLAT_DIR = . + +# +# Include common rules. +# +include $(UTSBASE)/sun4u/opl/Makefile.opl + +# +# Override defaults +# +CLEANFILES += $(PLATLIB) + +# +# Define targets +# +ALL_TARGET = $(PLATLIB) +LINT_TARGET = $(MODULE).lint +INSTALL_TARGET = $(BINARY) $(ROOTMODULE) + +# +# lint pass one enforcement +# +CFLAGS += $(CCVERBOSE) + +# +# Default build targets. +# +.KEEP_STATE: + +all: $(ALL_DEPS) + +def: $(DEF_DEPS) + +clean: $(CLEAN_DEPS) + +clobber: $(CLOBBER_DEPS) + +lint: $(LINT_DEPS) + +modlintlib: $(MODLINTLIB_DEPS) + +clean.lint: $(CLEAN_LINT_DEPS) + +install: $(INSTALL_DEPS) + +$(PLATLIB): $(BINARY) + $(LD) -o $(PLATLIB) -G $(BINARY) -h misc/platmod + +# +# Include common targets. +# +include $(UTSBASE)/sun4u/opl/Makefile.targ diff --git a/usr/src/uts/sun4u/opl/scfd/Makefile b/usr/src/uts/sun4u/opl/scfd/Makefile new file mode 100644 index 0000000000..79c2ff8813 --- /dev/null +++ b/usr/src/uts/sun4u/opl/scfd/Makefile @@ -0,0 +1,88 @@ +# +# 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. +# +# ident "%Z%%M% %I% %E% SMI" +# +# This makefile drives the production of the scfd driver +# loadable module. +# +# sun4u opl implementation architecture dependent +# +# Path to the base of the uts directory tree (usually /usr/src/uts). +# +# uts/sun4u/opl/scf/Makefile + +UTSBASE = ../../.. + +# +# Define the module and object file sets. +# +MODULE = scfd +OBJECTS = $(SCFD_OBJS:%=$(OBJS_DIR)/%) +LINTS = $(SCFD_OBJS:%.o=$(LINTS_DIR)/%.ln) +ROOTMODULE = $(ROOT_OPL_DRV_DIR)/$(MODULE) +CONF_SRCDIR = $(UTSBASE)/sun4u/opl/io/$(MODULE) + +# +# Include common rules. +# +include $(UTSBASE)/sun4u/opl/Makefile.opl + +# +# Define targets +# +ALL_TARGET = $(BINARY) $(SRC_CONFFILE) +LINT_TARGET = $(MODULE).lint +INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE) + +# +# lint pass one enforcement +# +CFLAGS += $(CCVERBOSE) + +# +# Default build targets. +# +.KEEP_STATE: + +all: $(ALL_DEPS) + +def: $(DEF_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)/sun4u/opl/Makefile.targ diff --git a/usr/src/uts/sun4u/opl/sys/Makefile b/usr/src/uts/sun4u/opl/sys/Makefile new file mode 100644 index 0000000000..254fe817e4 --- /dev/null +++ b/usr/src/uts/sun4u/opl/sys/Makefile @@ -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 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# +# uts/sun4u/opl/sys/Makefile +# + + +UTSBASE = ../../.. + +# +# include global definitions +# +include ../Makefile.opl + +# +# Override defaults. +# +FILEMODE = 644 +OWNER = bin +GROUP = bin + +HDRS= opl_hwdesc.h + +CHKHDRS= dm2s.h \ + drmach.h \ + fiomp.h \ + mc-opl.h \ + oplkm.h \ + oplkm_msg.h + +OPLMSUHDRS= oplmsu.h \ + oplmsu_proto.h + +PCICMUHDRS= pcicmu.h \ + pcmu_cb.h \ + pcmu_counters.h \ + pcmu_ecc.h \ + pcmu_err.h \ + pcmu_ib.h \ + pcmu_pbm.h \ + pcmu_types.h \ + pcmu_util.h + +SCFDHDRS= iomp_drv.h \ + opcio.h \ + scfdebug.h \ + scfdscp.h \ + scfdscpif.h \ + scfio32.h \ + scfkstat.h \ + scfostoescf.h \ + scfparam.h \ + scfreg.h \ + scfsnap.h \ + scfstate.h \ + scfsys.h \ + scftimer.h \ + scftrace.h + +NGDRHDRS= $(UTSBASE)/sun4u/ngdr/sys/dr.h \ + $(UTSBASE)/sun4u/ngdr/sys/dr_util.h + +ROOTHDRS= $(HDRS:%=$(USR_OPL_ISYS_DIR)/%) + +ROOTDIR= $(ROOT)/usr/share/src +ROOTDIRS= $(ROOTDIR)/uts $(ROOTDIR)/uts/$(PLATFORM) + +ROOTLINK= $(ROOTDIR)/uts/$(PLATFORM)/sys +LINKDEST= ../../../../platform/$(PLATFORM)/include/sys + +CHECKHDRS= $(HDRS:%.h=%.check) \ + $(CHKHDRS:%.h=%.check) \ + $(OPLMSUHDRS:%.h=oplmsu/%.check) \ + $(PCICMUHDRS:%.h=pcicmu/%.check) \ + $(SCFDHDRS:%.h=scfd/%.check) \ + $(NGDRHDRS:%.h=%.check) + +.KEEP_STATE: + +.PARALLEL: $(CHECKHDRS) $(ROOTHDRS) + +install_h: $(ROOTDIRS) .WAIT $(ROOTHDRS) $(ROOTLINK) + +check: $(CHECKHDRS) + +# +# install rules +# +$(USR_OPL_ISYS_DIR)/%: % $(USR_OPL_ISYS_DIR) + $(INS.file) + +$(ROOTDIRS): + $(INS.dir.bin.bin) + +# -r because this used to be a directory and is now a link. +$(ROOTLINK): $(ROOTDIRS) + -$(RM) -r $@; $(SYMLINK) $(LINKDEST) $@ $(CHOWNLINK) $(CHGRPLINK) + +FRC: + +include ../Makefile.targ diff --git a/usr/src/uts/sun4u/opl/sys/dm2s.h b/usr/src/uts/sun4u/opl/sys/dm2s.h new file mode 100644 index 0000000000..9718a1a4d4 --- /dev/null +++ b/usr/src/uts/sun4u/opl/sys/dm2s.h @@ -0,0 +1,110 @@ +/* + * 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 _DDM2S_H +#define _DDM2S_H + +#pragma ident "%Z%%M% %I% %E% SMI" + + +#ifdef __cplusplus +extern "C" { +#endif + +#define DM2S_MAX_SG 20 /* Max. scatter-gather elements */ +#define DM2S_MAX_RETRIES 3 /* Max. number of retries */ + +/* + * Instance structure. + */ +typedef struct dm2s { + dev_info_t *ms_dip; /* Devinfo pointer */ + major_t ms_major; /* Major number */ + uint32_t ms_ppa; /* Device instance */ + mkey_t ms_key; /* Mailbox key */ + target_id_t ms_target; /* Target-id */ + + ddi_iblock_cookie_t ms_ibcookie; /* Interrupt block cookie */ + kmutex_t ms_lock; /* Lock to protect this structure */ + kcondvar_t ms_wait; /* Cond. var to signal events */ + + uint32_t ms_mtu; /* MTU supported */ + queue_t *ms_rq; /* Read side queue */ + queue_t *ms_wq; /* Write side queuee */ + uint32_t ms_state; /* State of the device */ + + uint32_t ms_retries; /* Number of retries */ + timeout_id_t ms_rq_timeoutid; /* Timeout id for read queue */ + timeout_id_t ms_wq_timeoutid; /* Timeout id for write queue */ + bufcall_id_t ms_rbufcid; /* Buffcall-id for the read */ + + uint64_t ms_obytes; /* Number of output bytes */ + uint64_t ms_ibytes; /* Number of input bytes */ + + uint32_t ms_clean; /* Cleanup flags */ + mscat_gath_t ms_sg_rcv; /* Scatter-gather for receive */ + mscat_gath_t ms_sg_tx[DM2S_MAX_SG]; /* scatter-gather for Tx */ +} dm2s_t; + +/* ms_state flags */ +#define DM2S_MB_INITED 0x00000001 /* Mailbox initialized */ +#define DM2S_MB_CONN 0x00000002 /* Mailbox in connected state */ +#define DM2S_MB_DISC 0x00000004 /* Mailbox is disconnected */ +#define DM2S_OPENED 0x00000008 /* Device opened */ + +#define DM2S_MBOX_READY(x) ((x)->ms_state & DM2S_MB_CONN) + +/* ms_clean flags */ +#define DM2S_CLEAN_LOCK 0x00000001 +#define DM2S_CLEAN_CV 0x00000002 +#define DM2S_CLEAN_NODE 0x00000004 + +#ifdef DEBUG +/* + * Debug levels + */ +#define DBG_DRV 0x01 /* driver related traces */ +#define DBG_MBOX 0x02 /* Mailbox traces */ +#define DBG_MESG 0x04 /* Mailbox Message traces */ +#define DBG_WARN 0x10 /* warning type traces */ + +static void dm2s_dump_bytes(char *str, uint32_t total_len, + uint32_t num_sg, mscat_gath_t *sgp); + +#define DPRINTF(f, x) if (f & dm2s_debug) printf x +#define DMPBYTES(s, l, n, sg) dm2s_dump_bytes(s, l, n, sg) + +#else /* DEBUG */ + +#define DPRINTF(f, x) +#define DMPBYTES(s, l, n, sg) + +#endif /* DEBUG */ + +#ifdef __cplusplus +} +#endif + +#endif /* _DDM2S_H */ diff --git a/usr/src/uts/sun4u/opl/sys/drmach.h b/usr/src/uts/sun4u/opl/sys/drmach.h new file mode 100644 index 0000000000..3a336b6422 --- /dev/null +++ b/usr/src/uts/sun4u/opl/sys/drmach.h @@ -0,0 +1,355 @@ +/* + * 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_DRMACH_H_ +#define _SYS_DRMACH_H_ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _ASM +#include <sys/types.h> +#include <sys/memlist.h> +#include <sys/processor.h> +#include <sys/cpuvar.h> +#include <sys/sbd_ioctl.h> +#include <sys/sysevent.h> +#include <sys/ddi.h> +#include <sys/sunddi.h> +#include <sys/sunndi.h> +#include <sys/ddi_impldefs.h> +#include <sys/pte.h> +#include <sys/opl.h> +#endif + + +#define MAX_BOARDS plat_max_boards() +#define MAX_CPU_UNITS_PER_BOARD plat_max_cpu_units_per_board() +#define MAX_MEM_UNITS_PER_BOARD plat_max_mem_units_per_board() +#define MAX_IO_UNITS_PER_BOARD plat_max_io_units_per_board() +#define MAX_CMP_UNITS_PER_BOARD plat_max_cmp_units_per_board() +/* + * DR uses MAX_CORES_PER_CMP as number of virtual CPU within a CMP + */ +#define MAX_CORES_PER_CMP OPL_MAX_CPU_PER_CMP + + +/* returned with drmach_board_find_devices callback */ +#define DRMACH_DEVTYPE_CPU "cpu" +#define DRMACH_DEVTYPE_MEM "memory" +#define DRMACH_DEVTYPE_PCI "pci" + +#define FMEM_LOOP_START 1 +#define FMEM_LOOP_COPY_READY 2 +#define FMEM_LOOP_COPY_DONE 3 +#define FMEM_LOOP_FMEM_READY 4 +#define FMEM_LOOP_RENAME_DONE 5 +#define FMEM_LOOP_DONE 6 +#define FMEM_LOOP_EXIT 7 + +#define FMEM_NO_ERROR 0 +#define FMEM_OBP_FAIL 1 +#define FMEM_XC_TIMEOUT 2 +#define FMEM_COPY_TIMEOUT 3 +#define FMEM_SCF_BUSY 4 +#define FMEM_RETRY_OUT 5 +#define FMEM_TIMEOUT 6 +#define FMEM_HW_ERROR 7 +#define FMEM_TERMINATE 8 +#define FMEM_COPY_ERROR 9 +#define FMEM_SCF_ERR 10 + +#define SCF_CMD_BUSY 0x8000 +#define SCF_STATUS_READY 0x8000 +#define SCF_STATUS_SHUTDOWN 0x4000 +#define SCF_STATUS_POFF 0x2000 +#define SCF_STATUS_EVENT 0x1000 +#define SCF_STATUS_TIMER_ADJUST 0x0800 +#define SCF_STATUS_ALIVE 0x0400 +#define SCF_STATUS_MODE_CHANGED 0x0200 +#define SCF_STATUS_CMD_U_PARITY 0x0100 +#define SCF_STATUS_CMD_RTN_CODE 0x00f0 +#define SCF_STATUS_MODE_SWITCH 0x000c +#define SCF_STATUS_CMD_COMPLETE 0x0002 +#define SCF_STATUS_CMD_L_PARITY 0x0001 + +#define SCF_RETRY_CNT 15 + +#ifndef _ASM + +/* + * OPL platform specific routines currently only defined + * in opl.c and referenced by DR. + */ + +typedef void *drmachid_t; + +/* + * We have to split up the copy rename data structure + * into several pieces: + * 1. critical region that must be locked in TLB and must + * be physically contiguous/no ecache conflict. + * This region contains the assembly code that handles + * the rename programming, the slave code that loops + * until the master script completes and all data + * required to do the programming. + * + * It also contains the status of each CPU because the + * master must wait for all the slaves to get ready before + * it can program the SCF. + * + * We do not need the error code in the critical section. + * It is not set until the FMEM is done. + * 2. relocatable section that must be locked in TLB. All data + * referenced in this section must also be locked in TLB to + * avoid tlbmiss. + * + * We will also put everything else in this section even it + * does not need such protection. + */ +typedef struct { + int16_t scf_command; + int8_t scf_rsv1[2]; + int16_t scf_status; + int8_t scf_rsv2[2]; + int8_t scf_version; + int8_t scf_rsv3[3]; + int8_t scf_rsv4[4]; + uint8_t scf_tdata[16]; + uint8_t scf_rdata[16]; +} drmach_scf_regs_t; + + + +typedef struct { + volatile uint_t stat; + volatile uint_t error; + int op; +#define OPL_FMEM_SCF_START 0x1 +#define OPL_FMEM_MC_SUSPEND 0x2 +} drmach_fmem_mbox_t; + +typedef struct { + uint64_t scf_reg_base; + uint8_t scf_td[16]; + uint64_t save_log[8]; + uint64_t save_local[8]; + uint64_t pstate; + uint64_t delay; + int (*run)(void *arg, int cpuid); + int (*fmem)(void *arg, size_t sz); + int (*loop)(void *arg1, size_t sz, void *arg2); + void (*loop_rtn)(void *arg); + uint64_t inst_loop_ret; + int fmem_issued; + volatile uchar_t stat[NCPU]; +} drmach_copy_rename_critical_t; + +typedef struct { + uint64_t s_copybasepa; + uint64_t t_copybasepa; + drmachid_t s_mem; + drmachid_t t_mem; + cpuset_t cpu_ready_set; + cpuset_t cpu_slave_set; + cpuset_t cpu_copy_set; + processorid_t cpuid; + drmach_fmem_mbox_t fmem_status; + volatile uchar_t error[NCPU]; + struct memlist *c_ml; + struct memlist *cpu_ml[NCPU]; + caddr_t locked_va; + tte_t locked_tte; + void (*mc_resume)(void); + int (*scf_fmem_end)(void); + int (*scf_fmem_cancel)(void); + uint64_t copy_delay; + uint64_t stick_freq; + uint64_t copy_wait_time; + processorid_t slowest_cpuid; +} drmach_copy_rename_data_t; + +typedef struct { + uint64_t nbytes[NCPU]; +} drmach_cr_stat_t; + +typedef struct { + drmach_copy_rename_critical_t *critical; + drmach_copy_rename_data_t *data; + caddr_t memlist_buffer; + struct memlist *free_mlist; + drmach_cr_stat_t *stat; +} drmach_copy_rename_program_t; + +#define DRMACH_FMEM_LOCKED_PAGES 4 +#define DRMACH_FMEM_DATA_PAGE 0 +#define DRMACH_FMEM_CRITICAL_PAGE 1 +#define DRMACH_FMEM_MLIST_PAGE 2 +#define DRMACH_FMEM_STAT_PAGE 3 + +/* + * layout of the FMEM buffers: + * 1st 8k page + * +--------------------------------+ + * |drmach_copy_rename_program_t | + * +--------------------------------+ + * |drmach_copy_rename_data_t | + * | | + * +--------------------------------+ + * + * 2nd 8k page + * +--------------------------------+ + * |drmach_copy_rename_critical_t | + * | | + * +--------------------------------+ + * |run (drmach_copy_rename_prog__relocatable) + * |(roundup boundary to 1K) | + * +--------------------------------+ + * | fmem_script | + * |(roundup boundary to 1K) | + * +--------------------------------+ + * |loop_script | + * | | + * +--------------------------------+ + * |at least 1K NOP/0's | + * | | + * +--------------------------------+ + * + * 3rd 8k page + * +--------------------------------+ + * |memlist_buffer (free_mlist) | + * | | + * +--------------------------------+ + * + * 4th 8k page - drmach_cr_stat_t. + * + */ + +typedef struct { + boolean_t assigned; + boolean_t powered; + boolean_t configured; + boolean_t busy; + boolean_t empty; + sbd_cond_t cond; + char type[MAXNAMELEN]; + char info[MAXPATHLEN]; /* TODO: what size? */ +} drmach_status_t; + +typedef struct { + int size; + char *copts; +} drmach_opts_t; + +typedef struct { + uint64_t mi_basepa; + uint64_t mi_size; + uint64_t mi_slice_size; + uint64_t mi_alignment_mask; +} drmach_mem_info_t; + +extern sbd_error_t *drmach_mem_get_info(drmachid_t, drmach_mem_info_t *); +extern int drmach_board_is_floating(drmachid_t); + +extern sbd_error_t *drmach_copy_rename_init( + drmachid_t dst_id, + drmachid_t src_id, struct memlist *src_copy_ml, + drmachid_t *pgm_id); +extern sbd_error_t *drmach_copy_rename_fini(drmachid_t id); +extern void drmach_copy_rename(drmachid_t id); + +extern sbd_error_t *drmach_pre_op(int cmd, drmachid_t id, + drmach_opts_t *opts); +extern sbd_error_t *drmach_post_op(int cmd, drmachid_t id, + drmach_opts_t *opts); + +extern sbd_error_t *drmach_board_assign(int bnum, drmachid_t *id); +extern sbd_error_t *drmach_board_connect(drmachid_t id, + drmach_opts_t *opts); +extern sbd_error_t *drmach_board_deprobe(drmachid_t id); +extern sbd_error_t *drmach_board_disconnect(drmachid_t id, + drmach_opts_t *opts); +extern sbd_error_t *drmach_board_find_devices(drmachid_t id, void *a, + sbd_error_t *(*found)(void *a, const char *, int, drmachid_t)); +extern int drmach_board_lookup(int bnum, drmachid_t *id); +extern sbd_error_t *drmach_passthru(drmachid_t id, + drmach_opts_t *opts); + +extern sbd_error_t *drmach_board_name(int bnum, char *buf, int buflen); + +extern sbd_error_t *drmach_board_poweroff(drmachid_t id); +extern sbd_error_t *drmach_board_poweron(drmachid_t id); +extern sbd_error_t *drmach_board_test(drmachid_t id, drmach_opts_t *opts, + int force); + +extern sbd_error_t *drmach_board_unassign(drmachid_t id); + +extern sbd_error_t *drmach_configure(drmachid_t id, int flags); + +extern sbd_error_t *drmach_cpu_disconnect(drmachid_t id); +extern sbd_error_t *drmach_cpu_get_id(drmachid_t id, processorid_t *cpuid); +extern sbd_error_t *drmach_cpu_get_impl(drmachid_t id, int *ip); +extern void drmach_cpu_flush_ecache_sync(void); + +extern sbd_error_t *drmach_get_dip(drmachid_t id, dev_info_t **dip); + +extern sbd_error_t *drmach_io_is_attached(drmachid_t id, int *yes); +extern sbd_error_t *drmach_io_post_attach(drmachid_t id); +extern sbd_error_t *drmach_io_post_release(drmachid_t id); +extern sbd_error_t *drmach_io_pre_release(drmachid_t id); +extern sbd_error_t *drmach_io_unrelease(drmachid_t id); + +extern sbd_error_t *drmach_mem_add_span(drmachid_t id, + uint64_t basepa, uint64_t size); +extern sbd_error_t *drmach_mem_del_span(drmachid_t id, + uint64_t basepa, uint64_t size); +extern sbd_error_t *drmach_mem_disable(drmachid_t id); +extern sbd_error_t *drmach_mem_enable(drmachid_t id); +extern sbd_error_t *drmach_mem_get_base_physaddr(drmachid_t id, + uint64_t *pa); +extern sbd_error_t *drmach_mem_get_memlist(drmachid_t id, + struct memlist **ml); +extern sbd_error_t *drmach_mem_get_slice_size(drmachid_t, uint64_t *); + +extern sbd_error_t *drmach_release(drmachid_t id); +extern sbd_error_t *drmach_status(drmachid_t id, drmach_status_t *stat); +extern sbd_error_t *drmach_unconfigure(drmachid_t id, int flags); +extern int drmach_log_sysevent(int board, char *hint, int flag, + int verbose); + +extern int drmach_verify_sr(dev_info_t *dip, int sflag); +extern void drmach_suspend_last(); +extern void drmach_resume_first(); + +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_DRMACH_H_ */ diff --git a/usr/src/uts/sun4u/opl/sys/fiomp.h b/usr/src/uts/sun4u/opl/sys/fiomp.h new file mode 100644 index 0000000000..b3110a6dab --- /dev/null +++ b/usr/src/uts/sun4u/opl/sys/fiomp.h @@ -0,0 +1,240 @@ +/* + * 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 _FIOMP_H +#define _FIOMP_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +#define FIOMP_TRUE 1 +#define FIOMP_FALSE 0 + +#define FIOMP_MAX_STR 1024 /* same as FILENAME_MAX */ + +#define FIOMP_PATH_ALL (-1) + +/* ioctl base */ +#define FIOMPC ('f' << 8) + +/* + * ioctl for the meta management node + */ + +/* create a new multi-path */ +#define FIOMPNEW (FIOMPC|0x0) +/* encapsulate using devices */ +#define FIOMPENCAP (FIOMPC|0x1) +struct fiompdev { + int api_level; /* API level = 0 */ + int inst_no; /* instance number */ + minor_t inst_minor; /* instance management node */ + minor_t user_minor; /* user access node */ + int num; /* number of devices */ + char **devs; /* device names */ + int mpmode; /* multi pathing */ + int autopath; /* automatic path change */ + int block; /* able to block physical device */ + int needsync; /* need synchronize path status */ + void *ext; /* for extension = NULL */ +}; + +/* get an instance device's information */ +#define FIOMPDEVINFO (FIOMPC|0x2) +struct fiomp_devinfo { + int inst_no; /* instance number */ + char real_name[FIOMP_MAX_STR]; /* instance management node */ + char user_path[FIOMP_MAX_STR]; /* user access path */ + int path_num; /* number of paths */ + int mpmode; /* multi pathing */ + int autopath; /* automatic path change */ + int block; /* able to block physical device */ + int needsync; /* need synchronize path status */ + void *ext; /* for extension = NULL */ +}; + +/* get number of all instances */ +#define FIOMPALLINSTNUM (FIOMPC|0x3) + +/* get all device's informations */ +#define FIOMPALLDEVINFO (FIOMPC|0x4) +struct fiomp_all_devinfo { + int num; /* number of instances */ + struct fiomp_devinfo *devinfo; /* device informations */ +}; + +/* keep 0x5 - 0xf for reserve */ + +/* + * ioctl for instance management nodes + */ +/* get max number of paths */ +#define FIOMPMAXPATHNUM (FIOMPC|0x10) + +/* set the device's property */ +#define FIOMPSETPROP (FIOMPC|0x11) + +/* get the device's property */ +#define FIOMPGETPROP (FIOMPC|0x12) +struct fiompprop { + char *iomp_name; /* instance name */ + char *iomp_real_name; + /* instance management node (/devices) */ + char *iomp_user_path; /* instance management node (/dev) */ + char *iomp_status; /* status of the instance */ + int num; /* number of paths */ + char **iomp_path; /* target device nodes (/devices) */ + char **iomp_logical_path; /* target device nodes (/dev) */ + char **iomp_path_status; /* status of target devices */ + char **iomp_path_block; /* access block */ +}; + +/* destroy the instance */ +#define FIOMPDESTROY (FIOMPC|0x13) + +/* stop the path */ +#define FIOMPSTOP (FIOMPC|0x14) + +/* start the path */ +#define FIOMPSTART (FIOMPC|0x15) + +/* list all paths */ +#define FIOMPLIST (FIOMPC|0x16) + +/* get the path status */ +#define FIOMPSTATUS (FIOMPC|0x17) +struct fiompstatus { + int pathnum; /* path number */ + int status; /* FIOMP_STAT_xxxx */ + char *message; /* some messages */ + int block_status; /* access block status */ + void *ext; /* reservesd (= NULL) */ +}; + +/* status */ +#define FIOMP_STAT_ACTIVE PATH_STAT_ACTIVE +#define FIOMP_STAT_STANDBY PATH_STAT_STANDBY +#define FIOMP_STAT_STOP PATH_STAT_STOP +#define FIOMP_STAT_FAIL PATH_STAT_FAIL +#define FIOMP_STAT_DISCON PATH_STAT_DISCON +#define FIOMP_STAT_ENCAP PATH_STAT_ENCAP +#define FIOMP_STAT_EMPTY PATH_STAT_EMPTY + +/* access block status */ +#define FIOMP_BSTAT_BLOCK 1 +#define FIOMP_BSTAT_UNBLOCK 0 + +/* add, delete */ +#define FIOMPADD (FIOMPC|0x18) +#define FIOMPDEL (FIOMPC|0x19) +struct fiomppath { + int num; /* number of paths */ + char **devs; /* device names */ +}; + +/* active, stabdby */ +#define FIOMPACTIVE (FIOMPC|0x1a) +#define FIOMPSTANDBY (FIOMPC|0x1b) + +/* block, unblock */ +#define FIOMPBLOCK (FIOMPC|0x1c) +#define FIOMPUNBLOCK (FIOMPC|0x1d) + +/* diagnostic mode ON,OFF */ +#define FIOMPDIAGON (FIOMPC|0x1e) +#define FIOMPDIAGOFF (FIOMPC|0x1f) +struct fiomp_diag_mode { + int pathnum; /* path for diagnostic */ + int level; /* = 0 */ +}; + +/* get all status */ +#define FIOMPGETALLSTAT (FIOMPC|0x20) +struct fiomp_all_stat { + int num; /* number of paths */ + struct fiompstatus *status; /* path status */ +}; + +/* change the status of paths */ +#define FIOMPCHG (FIOMPC|0x21) +struct fiompchg { + int num; /* number of all paths */ + struct fiompstatus *set_status; /* setting values */ + struct fiompstatus *pre_status; /* previous values */ + struct fiompstatus *status; /* current values */ +}; + +/* recover the failed path */ +#define FIOMPRECOVER (FIOMPC|0x22) + +/* disconnect/reconnect the path */ +#define FIOMPDISCONNECT (FIOMPC|0x23) +#define FIOMPCONNECT (FIOMPC|0x24) + +/* keep 0x25 - 0x2f for reserve */ + +/* + * Common ioctl + */ +/* get event */ +#define FIOMPGETEVENT (FIOMPC|0x30) +struct fiompevent { + int event; /* event type = FIOMP_EVT_xx */ + int num; /* instance number(meta management) or */ + /* number of all path(instance management) */ + struct fiompstatus *pre_status; /* previous status */ + struct fiompstatus *status; /* current status */ +}; + +/* event type */ +#define FIOMP_EVT_NONE 0x0 +#define FIOMP_EVT_NEW 0x1 +#define FIOMP_EVT_DESTROY 0x2 +#define FIOMP_EVT_STAT 0x101 +#define FIOMP_EVT_PATHS 0x102 + +/* + * Device property + */ +#define FIOMP_PROP_NAME "iomp-name" +#define FIOMP_PROP_REAL_NAME "iomp-real-name" +#define FIOMP_PROP_PATH_N "iomp-path-" +#define FIOMP_PROP_USER_PATH "iomp-user-path" +#define FIOMP_PROP_LOGIC_PATH_N "iomp-logical-path-" +#define FIOMP_PROP_STATUS "iomp-status" +#define FIOMP_PROP_PATH_NUM "iomp-path-num" +#define FIOMP_PROP_STATUS_N "iomp-path-status-" + +#define FIOMP_PROP_BLOCK_N "iomp-path-block-" +#define FIOMP_PROP_BLOCK_DEFAULT "iomp-path-block-default" + +#ifdef __cplusplus +} +#endif + +#endif /* _FIOMP_H */ diff --git a/usr/src/uts/sun4u/opl/sys/mc-opl.h b/usr/src/uts/sun4u/opl/sys/mc-opl.h new file mode 100644 index 0000000000..b3aa57b2a9 --- /dev/null +++ b/usr/src/uts/sun4u/opl/sys/mc-opl.h @@ -0,0 +1,342 @@ +/* + * 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_MC_OPL_H +#define _SYS_MC_OPL_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +#include <sys/note.h> + +#ifdef DEBUG +#define MC_LOG if (oplmc_debug) printf +extern int oplmc_debug; +#else +#define MC_LOG _NOTE(CONSTANTCONDITION) if (0) printf +#endif + +/* + * load/store MAC register + */ +extern uint32_t mc_ldphysio(uint64_t); +extern void mc_stphysio(uint64_t, uint32_t); +#define LD_MAC_REG(paddr) mc_ldphysio(paddr) +#define ST_MAC_REG(paddr, data) mc_stphysio((paddr), (data)) + +#define BANKNUM_PER_SB 8 + +typedef struct scf_log { + struct scf_log *sl_next; + int sl_bank; + uint32_t sl_err_add; + uint32_t sl_err_log; +} scf_log_t; + +typedef struct mc_opl_state { + struct mc_opl_state *next; + dev_info_t *mc_dip; + uint32_t mc_status; +#define MC_POLL_RUNNING 0x1 +#define MC_SOFT_SUSPENDED 0x2 /* suspended by DR */ +#define MC_DRIVER_SUSPENDED 0x4 /* DDI_SUSPEND */ + uint32_t mc_board_num; /* board# */ + uint64_t mc_start_address; /* sb-mem-ranges */ + uint64_t mc_size; + struct mc_bank { + uint32_t mcb_status; +#define BANK_INSTALLED 0x80000000 +#define BANK_MIRROR_MODE 0x40000000 /* 0: normal 1: mirror */ +#define BANK_PTRL_RUNNING 0x00000001 + uint64_t mcb_reg_base; + uint32_t mcb_ptrl_cntl; + } mc_bank[BANKNUM_PER_SB]; + uchar_t mc_trans_table[2][64]; /* csX-mac-pa-trans-table */ + clock_t mc_interval_hz; + timeout_id_t mc_tid; + kmutex_t mc_lock; + scf_log_t *mc_scf_log; + scf_log_t *mc_scf_log_tail; + int mc_scf_total; +#define MAX_SCF_LOGS 64 + struct mc_inst_list *mc_list; + struct memlist *mlist; + int mc_scf_retry[BANKNUM_PER_SB]; + int mc_last_error; +#define MAX_SCF_RETRY 10 + uint64_t mc_period; /* number of times memory scanned */ +} mc_opl_t; + +typedef struct mc_inst_list { + struct mc_inst_list *next; + mc_opl_t *mc_opl; + uint32_t mc_board_num; + uint64_t mc_start_address; + uint64_t mc_size; +} mc_inst_list_t; + +#define IS_MIRROR(mcp, bn) ((mcp)->mc_bank[bn].mcb_status\ + & BANK_MIRROR_MODE) +typedef struct mc_addr { + int ma_bd; /* board number */ + int ma_bank; /* bank number */ + uint32_t ma_dimm_addr; /* DIMM address (same format as ERR_ADD) */ +} mc_addr_t; + +typedef struct mc_addr_info { + struct mc_addr mi_maddr; + int mi_valid; + int mi_advance; +} mc_addr_info_t; + +typedef struct mc_flt_stat { + uint32_t mf_type; /* fault type */ +#define FLT_TYPE_CMPE 0x0001 +#define FLT_TYPE_UE 0x0002 +#define FLT_TYPE_PERMANENT_CE 0x0003 +#define FLT_TYPE_INTERMITTENT_CE 0x0004 +#define FLT_TYPE_SUE 0x0005 +#define FLT_TYPE_MUE 0x0006 + uint32_t mf_cntl; /* MAC_BANKm_PTRL_CNTL Register */ + uint32_t mf_err_add; /* MAC_BANKm_{PTRL|MI}_ERR_ADD Register */ + uint32_t mf_err_log; /* MAC_BANKm_{PTRL|MI}_ERR_LOG Register */ + uint32_t mf_synd; + uchar_t mf_errlog_valid; + uchar_t mf_dimm_slot; + uchar_t mf_dram_place; + uint64_t mf_flt_paddr; /* faulty physical address */ + mc_addr_t mf_flt_maddr; /* faulty DIMM address */ +} mc_flt_stat_t; + +typedef struct mc_aflt { + uint64_t mflt_id; /* gethrtime() at time of fault */ + mc_opl_t *mflt_mcp; /* mc-opl structure */ + char *mflt_erpt_class; /* ereport class name */ + int mflt_is_ptrl; /* detected by PTRL or MI */ + int mflt_nflts; /* 1 or 2 */ + int mflt_pr; /* page retire flags */ + mc_flt_stat_t *mflt_stat[2]; /* fault status */ +} mc_aflt_t; + +#define MAC_PTRL_STAT(mcp, i) (mcp->mc_bank[i].mcb_reg_base) +#define MAC_PTRL_CNTL(mcp, i) (mcp->mc_bank[i].mcb_reg_base + 0x10) +#define MAC_PTRL_ERR_ADD(mcp, i) (mcp->mc_bank[i].mcb_reg_base + 0x20) +#define MAC_PTRL_ERR_LOG(mcp, i) (mcp->mc_bank[i].mcb_reg_base + 0x24) +#define MAC_MI_ERR_ADD(mcp, i) (mcp->mc_bank[i].mcb_reg_base + 0x28) +#define MAC_MI_ERR_LOG(mcp, i) (mcp->mc_bank[i].mcb_reg_base + 0x2c) +#define MAC_STATIC_ERR_ADD(mcp, i) (mcp->mc_bank[i].mcb_reg_base + 0x30) +#define MAC_STATIC_ERR_LOG(mcp, i) (mcp->mc_bank[i].mcb_reg_base + 0x34) +#define MAC_RESTART_ADD(mcp, i) (mcp->mc_bank[i].mcb_reg_base + 0x40) +#define MAC_REWRITE_ADD(mcp, i) (mcp->mc_bank[i].mcb_reg_base + 0x44) +#define MAC_EG_ADD(mcp, i) (mcp->mc_bank[i].mcb_reg_base + 0x48) +#define MAC_EG_CNTL(mcp, i) (mcp->mc_bank[i].mcb_reg_base + 0x4c) +#define MAC_MIRR(mcp, i) (mcp->mc_bank[i].mcb_reg_base + 0x50) + +/* use PA[37:6] */ +#define MAC_RESTART_PA(pa) ((pa >> 6) & 0xffffffff) +/* + * MAC_BANKm_PTRL_STAT_Register + */ +#define MAC_STAT_PTRL_CE 0x00000020 +#define MAC_STAT_PTRL_UE 0x00000010 +#define MAC_STAT_PTRL_CMPE 0x00000008 +#define MAC_STAT_MI_CE 0x00000004 +#define MAC_STAT_MI_UE 0x00000002 +#define MAC_STAT_MI_CMPE 0x00000001 + +#define MAC_STAT_PTRL_ERRS (MAC_STAT_PTRL_CE|MAC_STAT_PTRL_UE\ + |MAC_STAT_PTRL_CMPE) +#define MAC_STAT_MI_ERRS (MAC_STAT_MI_CE|MAC_STAT_MI_UE\ + |MAC_STAT_MI_CMPE) + +/* + * MAC_BANKm_PTRL_CTRL_Register + */ +#define MAC_CNTL_PTRL_START 0x80000000 +#define MAC_CNTL_USE_RESTART_ADD 0x40000000 +#define MAC_CNTL_PTRL_STOP 0x20000000 +#define MAC_CNTL_PTRL_INTERVAL 0x1c000000 +#define MAC_CNTL_PTRL_RESET 0x02000000 +#define MAC_CNTL_PTRL_STATUS 0x01000000 +#define MAC_CNTL_REW_REQ 0x00800000 +#define MAC_CNTL_REW_RESET 0x00400000 +#define MAC_CNTL_CS0_DEG_MODE 0x00200000 +#define MAC_CNTL_PTRL_CE 0x00008000 +#define MAC_CNTL_PTRL_UE 0x00004000 +#define MAC_CNTL_PTRL_CMPE 0x00002000 +#define MAC_CNTL_MI_CE 0x00001000 +#define MAC_CNTL_MI_UE 0x00000800 +#define MAC_CNTL_MI_CMPE 0x00000400 +#define MAC_CNTL_REW_CE 0x00000200 +#define MAC_CNTL_REW_UE 0x00000100 +#define MAC_CNTL_REW_END 0x00000080 +#define MAC_CNTL_PTRL_ADD_MAX 0x00000040 +#define MAC_CNTL_REW_CMPE 0x00000020 + +#define MAC_CNTL_PTRL_PRESERVE_BITS (MAC_CNTL_PTRL_INTERVAL) + +#define MAC_CNTL_PTRL_ERRS (MAC_CNTL_PTRL_CE|MAC_CNTL_PTRL_UE\ + |MAC_CNTL_PTRL_CMPE) +#define MAC_CNTL_MI_ERRS (MAC_CNTL_MI_CE|MAC_CNTL_MI_UE\ + |MAC_CNTL_MI_CMPE) +#define MAC_CNTL_REW_ERRS (MAC_CNTL_REW_CE|MAC_CNTL_REW_CMPE|\ + MAC_CNTL_REW_UE|MAC_CNTL_REW_END) +#define MAC_CNTL_ALL_ERRS (MAC_CNTL_PTRL_ERRS|\ + MAC_CNTL_MI_ERRS|MAC_CNTL_REW_ERRS) + +#define MAC_ERRLOG_SYND_SHIFT 16 +#define MAC_ERRLOG_SYND_MASK 0xffff +#define MAC_ERRLOG_DIMMSLOT_SHIFT 13 +#define MAC_ERRLOG_DIMMSLOT_MASK 0x7 +#define MAC_ERRLOG_DRAM_PLACE_SHIFT 8 +#define MAC_ERRLOG_DRAM_PLACE_MASK 0x1f + +#define MAC_SET_ERRLOG_INFO(flt_stat) \ + (flt_stat)->mf_errlog_valid = 1; \ + (flt_stat)->mf_synd = ((flt_stat)->mf_err_log >> \ + MAC_ERRLOG_SYND_SHIFT) & \ + MAC_ERRLOG_SYND_MASK; \ + (flt_stat)->mf_dimm_slot = ((flt_stat)->mf_err_log >> \ + MAC_ERRLOG_DIMMSLOT_SHIFT) & \ + MAC_ERRLOG_DIMMSLOT_MASK; \ + (flt_stat)->mf_dram_place = ((flt_stat)->mf_err_log >> \ + MAC_ERRLOG_DRAM_PLACE_SHIFT) & \ + MAC_ERRLOG_DRAM_PLACE_MASK; + +extern void mc_write_cntl(mc_opl_t *, int, uint32_t); +#define MAC_CMD(mcp, i, cmd) mc_write_cntl(mcp, i, cmd) + +#define MAC_PTRL_START_ADD(mcp, i) MAC_CMD((mcp), (i),\ + MAC_CNTL_PTRL_START|MAC_CNTL_USE_RESTART_ADD) +#define MAC_PTRL_START(mcp, i) MAC_CMD((mcp), (i), MAC_CNTL_PTRL_START) +#define MAC_PTRL_STOP(mcp, i) MAC_CMD((mcp), (i), MAC_CNTL_PTRL_STOP) +#define MAC_PTRL_RESET(mcp, i) MAC_CMD((mcp), (i), MAC_CNTL_PTRL_RESET) +#define MAC_REW_REQ(mcp, i) MAC_CMD((mcp), (i), MAC_CNTL_REW_REQ) +#define MAC_REW_RESET(mcp, i) MAC_CMD((mcp), (i), MAC_CNTL_REW_RESET) +#define MAC_CLEAR_ERRS(mcp, i, errs) MAC_CMD((mcp), (i), errs) +#define MAC_CLEAR_ALL_ERRS(mcp, i) MAC_CMD((mcp), (i),\ + MAC_CNTL_ALL_ERRS) +#define MAC_CLEAR_MAX(mcp, i) \ + MAC_CMD((mcp), (i), MAC_CNTL_PTRL_ADD_MAX) + + +/* + * MAC_BANKm_PTRL/MI_ERR_ADD/LOG_Register + */ +#define MAC_ERR_ADD_INVALID 0x80000000 +#define MAC_ERR_LOG_INVALID 0x00000080 + +/* + * MAC_BANKm_STATIC_ERR_ADD_Register + */ +#define MAC_STATIC_ERR_VLD 0x80000000 + +/* + * MAC_BANKm_MIRR_Register + */ +#define MAC_MIRR_MIRROR_MODE 0x80000000 +#define MAC_MIRR_BANK_EXCLUSIVE 0x40000000 + +#define OPL_BOARD_MAX 16 +#define OPL_BANK_MAX 8 + +/* + * MAC_BANKm_EG_ADD_Register + */ +#define MAC_EG_ADD_MASK 0x7ffffffc +/* + * To set the EG_CNTL register, bit[26-25] and + * bit[21-20] must be cleared. Then the other + * control bit should be set. Then the bit[26-25] + * and bit[21-20] should be set while other bits + * should be the same as before. + */ +#define MAC_EG_CNTL_MASK 0x06300000 + +#define MAC_EG_ADD_FIX 0x80000000 +#define MAC_EG_FORCE_DERR00 0x40000000 +#define MAC_EG_FORCE_DERR16 0x20000000 +#define MAC_EG_FORCE_DERR64 0x10000000 +#define MAC_EG_FORCE_DERR80 0x08000000 +#define MAC_EG_DERR_ALWAYS 0x02000000 +#define MAC_EG_DERR_ONCE 0x04000000 +#define MAC_EG_DERR_NOP 0x06000000 +#define MAC_EG_FORCE_READ00 0x00800000 +#define MAC_EG_FORCE_READ16 0x00400000 +#define MAC_EG_RDERR_ALWAYS 0x00100000 +#define MAC_EG_RDERR_ONCE 0x00200000 +#define MAC_EG_RDERR_NOP 0x00300000 + +#define MAC_EG_SETUP_MASK 0xf9cfffff + +/* For MAC-PA translation */ +#define MC_ADDRESS_BITS 31 +#define PA_BITS_FOR_MAC 39 +#define INDEX_OF_BANK_SUPPLEMENT_BIT 39 +#define MP_NONE 128 +#define MP_BANK_0 129 +#define MP_BANK_1 130 +#define MP_BANK_2 131 + +#define CS_SHIFT 29 +#define MC_TT_ENTRIES 64 +#define MC_TT_CS 2 + + +#define MAX_MC_LOOP_COUNT 100 + +/* export interface for error injection */ +extern int mc_inject_error(int error_type, uint64_t pa, uint32_t flags); + +#define MC_INJECT_NOP 0x0 +#define MC_INJECT_INTERMITTENT_CE 0x1 +#define MC_INJECT_PERMANENT_CE 0x2 +#define MC_INJECT_UE 0x3 +#define MC_INJECT_INTERMITTENT_MCE 0x11 +#define MC_INJECT_PERMANENT_MCE 0x12 +#define MC_INJECT_SUE 0x13 +#define MC_INJECT_MUE 0x14 +#define MC_INJECT_CMPE 0x15 + +#define MC_INJECT_MIRROR_MODE 0x10 +#define MC_INJECT_MIRROR(x) (x & MC_INJECT_MIRROR_MODE) + +#define MC_INJECT_FLAG_NO_TRAP 0x1 +#define MC_INJECT_FLAG_RESTART 0x2 +#define MC_INJECT_FLAG_POLL 0x4 +#define MC_INJECT_FLAG_RESET 0x8 +#define MC_INJECT_FLAG_OTHER 0x10 +#define MC_INJECT_FLAG_LD 0x20 +#define MC_INJECT_FLAG_ST 0x40 +#define MC_INJECT_FLAG_PATH 0x80 + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_MC_OPL_H */ diff --git a/usr/src/uts/sun4u/opl/sys/opl_hwdesc.h b/usr/src/uts/sun4u/opl/sys/opl_hwdesc.h new file mode 100644 index 0000000000..19fffe91df --- /dev/null +++ b/usr/src/uts/sun4u/opl/sys/opl_hwdesc.h @@ -0,0 +1,511 @@ +/* + * 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_OPL_HWDESC_H +#define _SYS_OPL_HWDESC_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Hardware Descriptor. + */ + +#define HWD_SBS_PER_DOMAIN 32 /* System boards per domain */ +#define HWD_CPUS_PER_CORE 4 /* Strands per physical core */ +#define HWD_CORES_PER_CPU_CHIP 4 /* Cores per processor chip */ +#define HWD_CPU_CHIPS_PER_CMU 4 /* Processor chips per CMU */ +#define HWD_SCS_PER_CMU 4 /* System controllers per CMU */ +#define HWD_DIMMS_PER_CMU 32 /* Memory DIMMs per CMU */ +#define HWD_IOCS_PER_IOU 2 /* Oberon chips per I/O unit */ +#define HWD_PCI_CHANNELS_PER_IOC 2 /* PCI channels per Oberon chip */ +#define HWD_LEAVES_PER_PCI_CHANNEL 2 /* Leaves per PCI channel */ +#define HWD_PCI_CHANNELS_PER_SB 4 /* PCI channels per system board */ +#define HWD_CMU_CHANNEL 4 /* CMU channel number */ +#define HWD_IO_BOATS_PER_IOU 6 /* I/O boats per I/O unit */ +#define HWD_BANKS_PER_CMU 8 /* Memory banks per CMU */ +#define HWD_MAX_MEM_CHUNKS 8 /* Chunks per board */ + +typedef uint32_t hwd_stat_t; /* component status */ + +/* + * Values for hwd_stat_t. + */ +#define HWD_STAT_UNKNOWN 0x0000 /* No status yet */ +#define HWD_STAT_PRESENT 0x0001 /* Present */ +#define HWD_STAT_MISS 0x0002 /* Missing */ +#define HWD_STAT_MISCONFIG 0x0003 /* Misconfigured */ +#define HWD_STAT_PASS 0x0004 /* Ok */ +#define HWD_STAT_FAIL 0x0080 /* Failed by XSCF */ +#define HWD_STAT_FAIL_OBP 0x0081 /* Failed by POST/OBP */ +#define HWD_STAT_FAIL_OS 0x0082 /* Failed by OS */ + +#define HWD_STAT_FAILED 0x0080 + +#define HWD_MASK_NOT_USED 0x8000 /* If this bit is set, the component */ + /* is not used (even if it presents) */ + +#define HWD_STATUS_FAILED(stat) ((stat) & HWD_STAT_FAILED) +#define HWD_STATUS_OK(stat) ((stat) == HWD_STAT_PASS) +#define HWD_STATUS_PRESENT(stat) \ + ((stat) & (HWD_STAT_PRESENT | HWD_STAT_PASS)) +#define HWD_STATUS_NONE(stat) \ + (((stat) == HWD_STAT_UNKNOWN) || ((stat) == HWD_STAT_MISS)) + +#define HWD_VERSION_MAJOR 1 +#define HWD_VERSION_MINOR 1 + +/* + * Hardware Descriptor Header. + * + * Some fields occur repeatedly in different structures: + * + * spare* This field is for future use. + * + * filler* This field is used to show alignment. This could also + * be used in the future for something. + * + * check_sum This contains the check sum of the structure it resides in. + */ +typedef struct { + uint32_t hdr_magic; /* magic code ('HWDE') */ + struct hwdesc_version { + uint16_t major; + uint16_t minor; + } hdr_version; /* structure version */ + + /* + * Domain Identifier. The OPL system can have + * upto 24 domains so domain id can be 0 - 23. + */ + uint8_t hdr_domain_id; + char hdr_filler[3]; + + /* + * offsets from the beginning of the header to: + * - SB status information (hwd_sb_status_t) + * - domain information (hwd_domain_info_t) + * - SB information (hwd_sb_info_t). + */ + uint32_t hdr_sb_status_offset; + uint32_t hdr_domain_info_offset; + uint32_t hdr_sb_info_offset; + + uint32_t hdr_spare[9]; + uint32_t hdr_check_sum; +} hwd_header_t; + +/* + * SB Status + */ +typedef struct { + hwd_stat_t sb_status[HWD_SBS_PER_DOMAIN]; /* status of all LSBs */ + uint32_t sb_spare[15]; + uint32_t sb_check_sum; +} hwd_sb_status_t; + +/* + * SP -> Domain Information. + */ +typedef struct { + uint32_t dinf_reset_factor; /* domain reset reason */ + uint32_t dinf_host_id; /* domain unique id */ + uint64_t dinf_system_frequency; /* Hz */ + uint64_t dinf_stick_frequency; /* Hz */ + uint32_t dinf_scf_command_timeout; /* SCF i/f timeout seconds */ + uint32_t dinf_model_info; /* FF1/2 DC1/2/3 */ + uint8_t dinf_mac_address[6]; /* system MAC address */ + uint8_t dinf_filler1[10]; + uint8_t dinf_dr_status; /* 0: DR capable, !0: no DR */ + uint8_t dinf_filler2[7]; + /* + * Specification of degeneracy operation of POST by XSCF + * 0x00: off + * 0x20: component + * 0x40: board + * 0x80: system + */ + uint8_t dinf_config_policy; + /* + * Specification of diagnosis operation of POST by XSCF + * 0x00: off + * 0x20: min + * 0x40: max + */ + uint8_t dinf_diag_level; + /* + * Specification of boot operation of OBP by XSCF + * 0x00: It follows other settings. + * 0x80: Auto boot is not done. + */ + uint8_t dinf_boot_mode; + uint8_t dinf_spare1[5]; + int64_t dinf_cpu_start_time; /* seconds since the Epoch */ + char dinf_banner_name[64]; /* system banner string */ + char dinf_platform_token[64]; /* platform name */ + uint32_t dinf_floating_board_bitmap; /* bit 0 = SB0 ... */ + uint32_t dinf_spare2[12]; + uint32_t dinf_check_sum; +} hwd_domain_info_t; + +/* + * CPU Strand + */ +typedef struct { + hwd_stat_t cpu_status; + char cpu_component_name[32]; + uint16_t cpu_cpuid; /* 0x0000, 0x0001, ... 0x01ff */ + uint16_t cpu_filler; + uint32_t cpu_spare[6]; +} hwd_cpu_t; + +/* + * CPU Core + */ +typedef struct { + hwd_stat_t core_status; + char core_component_name[32]; + uint32_t core_filler1; + uint64_t core_frequency; /* Hz */ + uint64_t core_config; /* bus config reg */ + uint64_t core_version; /* processor VER */ + uint16_t core_manufacturer; /* VER.manuf */ + uint16_t core_implementation; /* VER.impl */ + uint8_t core_mask; /* VER.mask */ + uint8_t core_filler2[3]; + uint32_t core_l1_icache_size; + uint16_t core_l1_icache_line_size; + uint16_t core_l1_icache_associativity; + uint32_t core_num_itlb_entries; + uint32_t core_l1_dcache_size; + uint16_t core_l1_dcache_line_size; + uint16_t core_l1_dcache_associativity; + uint32_t core_num_dtlb_entries; + uint32_t core_spare1[4]; + uint32_t core_l2_cache_size; + uint16_t core_l2_cache_line_size; + uint16_t core_l2_cache_associativity; + uint32_t core_l2_cache_sharing; /* bit N:coreN */ + uint32_t core_spare2[5]; + hwd_cpu_t core_cpus[HWD_CPUS_PER_CORE]; + uint32_t core_spare3[4]; +} hwd_core_t; + +/* + * CPU Chip + */ +typedef struct { + hwd_stat_t chip_status; + char chip_component_name[32]; /* example: "CPU#x" */ + char chip_fru_name[32]; /* example: "CPU#x" */ + char chip_compatible[32]; /* example: "FJSV,SPARC64-VI" */ + /* + * Jupiter Bus Device ID + * 0x0400, 0x0408, ... , 0x05f8 + */ + uint16_t chip_portid; + uint16_t chip_filler; + uint32_t chip_spare1[6]; + hwd_core_t chip_cores[HWD_CORES_PER_CPU_CHIP]; + uint32_t chip_spare2[4]; +} hwd_cpu_chip_t; + +/* + * SC + */ +typedef struct { + hwd_stat_t sc_status; + uint32_t sc_filler; + /* + * Top address of SC registers in this XSB + */ + uint64_t sc_register_address; +} hwd_sc_t; + +/* + * Bank + */ +typedef struct { + hwd_stat_t bank_status; + hwd_stat_t bank_cs_status[2]; /* DIMM pair status */ + uint32_t bank_filler1; + uint64_t bank_register_address; /* address of mem patrol regs */ + uint8_t bank_mac_ocd; /* calibrated MAC OCD value */ + uint8_t bank_filler2[3]; + uint8_t bank_dimm_ocd[4][2]; /* calibrated DIMM OCD value */ + uint32_t bank_tune; /* for POST use */ + uint32_t bank_spare[2]; +} hwd_bank_t; + +/* + * Chunk + */ +typedef struct { + uint64_t chnk_start_address; + uint64_t chnk_size; +} hwd_chunk_t; + +/* + * Dimm + */ +typedef struct { + hwd_stat_t dimm_status; + uint32_t dimm_filler1; + uint64_t dimm_capacity; /* bytes */ + uint64_t dimm_available_capacity; /* bytes */ + uint8_t dimm_rank; /* 1 or 2 */ + uint8_t dimm_filler2[7]; + char dimm_component_name[32]; /* "MEM#xyz" */ + char dimm_fru_name[32]; /* "MEM#xyz" */ +} hwd_dimm_t; + +/* + * CS + */ +typedef struct { + hwd_stat_t cs_status; + uint8_t cs_number_of_dimms; + uint8_t cs_filler[3]; + uint64_t cs_available_capacity; + uint64_t cs_dimm_capacity; + uint8_t cs_dimm_badd[8]; /* Value to initialize MAC by POST */ + uint16_t cs_dimm_add[8]; /* Value to initialize MAC by POST */ + uint8_t cs_pa_mac_table[64]; /* PA <-> MAC address conversion */ +} hwd_cs_t; + +/* + * Memory + */ +typedef struct { + uint64_t mem_start_address; /* Memory start for this LSB */ + uint64_t mem_size; /* Memory size for this LSB */ + hwd_bank_t mem_banks[HWD_BANKS_PER_CMU]; + /* + * Mirroring mode: + * 0x00 or 0x01 + * 0x00 : not 'memory mirror mode' + * 0x01 : 'memory mirror mode' + */ + uint8_t mem_mirror_mode; /* mirroring mode */ + /* + * Memory configuration: + * 0x01 : 1 divided mode + * 0x02 : 2 divided mode + * 0x04 : 4 divided mode + * + * It is always set to 0x04 at the XSB mode. + */ + uint8_t mem_division_mode; + uint8_t mem_piece_number; /* 0-3 memory slot group used */ + uint8_t mem_cs_interleave; /* 1:cs interleave, 0:not */ + uint32_t mem_filler[3]; + uint8_t mem_available_bitmap[512]; /* for POST use */ + uint8_t mem_degrade_bitmap[16384]; /* for POST use */ + hwd_chunk_t mem_chunks[HWD_MAX_MEM_CHUNKS]; + hwd_dimm_t mem_dimms[HWD_DIMMS_PER_CMU]; + hwd_cs_t mem_cs[2]; +} hwd_memory_t; + +typedef struct { + hwd_stat_t scf_status; + char scf_component_name[32]; /* "SCFI#z" */ +} hwd_scf_interface_t; + +typedef struct { + hwd_stat_t tty_status; + char tty_component_name[32]; /* "TTY#z" */ +} hwd_tty_t; + +typedef struct { + uint8_t fver_major; /* firmware major version */ + uint8_t fver_minor; /* firmware minor version */ + uint8_t fver_local; /* firmware local version */ + uint8_t fver_filler; +} hwd_fmem_version_t; + +typedef struct { + hwd_stat_t fmem_status; /* status of flash */ + char fmem_component_name[32]; + uint8_t fmem_used; /* non-zero: fmem is used */ + uint8_t fmem_filler[3]; + hwd_fmem_version_t fmem_version; + uint32_t fmem_spare; +} hwd_fmem_t; + +/* + * CMU CH + */ +typedef struct { + hwd_stat_t chan_status; + /* + * CMU_CH port ID + * LSB0 is 0x0008, LSB1 is 0x0018, ... , LSB15 is 0x00f8 + */ + uint16_t chan_portid; + uint16_t chan_filler; + char chan_component_name[32]; /* "U2P#z" */ + hwd_scf_interface_t chan_scf_interface; + hwd_tty_t chan_serial; + hwd_fmem_t chan_fmem[2]; +} hwd_cmu_chan_t; + +/* + * CMU + */ +typedef struct { + char cmu_component_name[32]; /* example: "CxS0y" */ + char cmu_fru_name[32]; /* example: "Cabinet#x-CMU#y" */ + + hwd_cpu_chip_t cmu_cpu_chips[HWD_CPU_CHIPS_PER_CMU]; /* CPU */ + hwd_sc_t cmu_scs[HWD_SCS_PER_CMU]; /* SC */ + hwd_memory_t cmu_memory; /* Memory */ + hwd_cmu_chan_t cmu_ch; /* CMU CH */ + uint32_t cmu_spare[32]; +} hwd_cmu_t; + +typedef struct { + hwd_stat_t slot_status; + char slot_name[16]; +} hwd_slot_t; + +/* + * IO Boat + */ +typedef struct { + hwd_stat_t iob_status; + char iob_component_name[32]; + char iob_fru_name[32]; + /* + * IO_Boat type + * 0x01 : PCI-X Slot Type + * 0x02 : PCI Express Slot Type + */ + uint32_t iob_type; /* PCI-X or PCI Express */ + uint64_t iob_io_box_info; /* location of I/O */ + /* + * Information of switch on IO_boat + * use only switch_status[0] when PCI-X type IO_boat + */ + hwd_stat_t iob_switch_status[3]; /* PCIE switch statuses */ + /* + * Information of bridge on IO_boat + * use only when PCI-X type IO_boat + */ + hwd_stat_t iob_bridge_status[3]; /* PCIX bridge statuses */ + hwd_slot_t iob_slot[6]; /* PCI slot names */ + uint32_t iob_spare[8]; +} hwd_io_boat_t; + +/* IOU PCI Express Slot */ +typedef struct { + uint32_t iou_type; /* 0: empty, 1: card, 2: IO boat */ + hwd_slot_t iou_slot; + hwd_io_boat_t iou_io_boat; +} hwd_iou_slot_t; + +typedef struct { + hwd_stat_t ff_onb_switch_status; + uint8_t ff_onb_filler[64]; + hwd_stat_t ff_onb_bridge_status; + hwd_stat_t ff_onb_sas_status; + hwd_stat_t ff_onb_gbe_status; + hwd_iou_slot_t ff_onb_slot; + hwd_slot_t ff_onb_xslot; +} hwd_ff_onboard_t; + +typedef struct { + hwd_stat_t ioua_status; /* IOUA status */ + char ioua_component_name[32]; + char ioua_fru_name[32]; + hwd_stat_t ioua_bridge_status; + hwd_stat_t ioua_sas_status; + hwd_stat_t ioua_gbe_status; +} hwd_ioua_t; + +typedef struct { + uint8_t iou_desc_filler[80]; + hwd_iou_slot_t iou_desc_slot; +} hwd_iou_slot_desc_t; + +typedef struct { + hwd_stat_t leaf_status; + uint16_t leaf_port_id; /* portid (logical leaf id) */ + uint8_t leaf_filler[6]; + uint32_t leaf_slot_type; /* card or boat */ + union { + hwd_ff_onboard_t leaf_ff_onboard; + hwd_ioua_t leaf_ioua; + hwd_iou_slot_desc_t leaf_iou_slot; + uint8_t leaf_spare[448]; + } leaf_u; + uint64_t leaf_cfgio_offset; /* config space offset */ + uint64_t leaf_cfgio_size; /* config space size */ + uint64_t leaf_mem32_offset; /* offset of mem32 area */ + uint64_t leaf_mem32_size; /* size of mem32 area */ + uint64_t leaf_mem64_offset; /* offset of mem64 area */ + uint64_t leaf_mem64_size; /* size of mem64 area */ +} hwd_leaf_t; + +/* + * PCI CH + */ +typedef struct { + hwd_stat_t pci_status; /* PCI CH status */ + char pci_component_name[32]; + char pci_fru_name[32]; + uint8_t pci_filler[12]; + hwd_leaf_t pci_leaf[HWD_LEAVES_PER_PCI_CHANNEL]; +} hwd_pci_ch_t; + +/* + * System Board + */ +typedef struct { + /* + * SB + */ + hwd_stat_t sb_status; + uint8_t sb_mode; /* 0:PSB 1:XSB */ + uint8_t sb_psb_number; /* PSB number for this LSB */ + uint8_t sb_filler1[10]; + + hwd_cmu_t sb_cmu; /* CMU */ + + hwd_pci_ch_t sb_pci_ch[HWD_PCI_CHANNELS_PER_SB]; /* PCI CH */ + + uint32_t sb_spare[31]; + uint32_t sb_check_sum; +} hwd_sb_t; + +#define HWD_DATA_SIZE (36 * 1024) /* Size of HWD data from SCF */ + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_OPL_HWDESC_H */ diff --git a/usr/src/uts/sun4u/opl/sys/oplkm.h b/usr/src/uts/sun4u/opl/sys/oplkm.h new file mode 100644 index 0000000000..30c613de5b --- /dev/null +++ b/usr/src/uts/sun4u/opl/sys/oplkm.h @@ -0,0 +1,103 @@ +/* + * 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_OPLKM_H +#define _SYS_OPLKM_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + + +/* + * Device instance structure. + */ +typedef struct okms { + dev_info_t *km_dip; /* Devinfo pointer */ + major_t km_major; /* Major number */ + uint32_t km_inst; /* Device instance */ + mkey_t km_key; /* Mailbox key */ + target_id_t km_target; /* Target-id */ + + ddi_iblock_cookie_t km_ibcookie; /* Interrupt block cookie */ + kmutex_t km_lock; /* Lock to protect this structure */ + kcondvar_t km_wait; /* Cond. var to signal events */ + uint32_t km_state; /* State of the device */ + uint32_t km_maxsz; /* Max msg size */ + + uint32_t km_retries; /* Number of retries */ + uint32_t km_clean; /* Cleanup flags */ + mscat_gath_t km_sg_rcv; /* Scatter-gather for Rx */ + mscat_gath_t km_sg_tx; /* Scatter-gather for Tx */ + + okm_req_hdr_t *km_reqp; /* Cached request */ + int km_reqlen; /* Request length */ +} okms_t; + +/* km_state flags */ +#define OKM_MB_INITED 0x00000001 /* Mailbox initialized */ +#define OKM_MB_CONN 0x00000002 /* Mailbox in connected state */ +#define OKM_MB_DISC 0x00000004 /* Mailbox is disconnected */ +#define OKM_OPENED 0x00000008 /* Device opened */ + +#define OKM_MBOX_READY(x) (((x)->km_state & OKM_MB_CONN) && \ + !((x)->km_state & OKM_MB_DISC)) + +/* km_clean flags */ +#define OKM_CLEAN_LOCK 0x00000001 +#define OKM_CLEAN_CV 0x00000002 +#define OKM_CLEAN_NODE 0x00000004 + +#ifdef DEBUG +/* + * Debug levels + */ +#define DBG_DRV 0x01 /* driver related traces */ +#define DBG_MBOX 0x02 /* Mailbox traces */ +#define DBG_MESG 0x04 /* Mailbox Message traces */ +#define DBG_WARN 0x10 /* warning type traces */ + +static void okm_print_req(okm_req_hdr_t *reqp, uint32_t len); +static void okm_print_rep(okm_rep_hdr_t *repp); + +#define DPRINTF(f, x) if (f & okm_debug) printf x +#define DUMP_REQ(r, l) okm_print_req(r, l) +#define DUMP_REPLY(r) okm_print_rep(r) + +#else /* DEBUG */ + +#define DPRINTF(f, x) +#define DUMP_REQ(r, l) +#define DUMP_REPLY(r) + +#endif /* DEBUG */ + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_OPLKM_H */ diff --git a/usr/src/uts/sun4u/opl/sys/oplkm_msg.h b/usr/src/uts/sun4u/opl/sys/oplkm_msg.h new file mode 100644 index 0000000000..2e49a63e0f --- /dev/null +++ b/usr/src/uts/sun4u/opl/sys/oplkm_msg.h @@ -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 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _SYS_OPLKM_MSG_H +#define _SYS_OPLKM_MSG_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * This header file describes the format of the mailbox messages + * exchanged between the OPL key management driver on a OPL Domain + * and the OPL Service Processor. + */ + + +/* + * Request message header. + */ +typedef struct okm_req_hdr { + uint32_t krq_version; /* Protocol version */ + uint32_t krq_transid; /* Transaction ID */ + uint32_t krq_cmd; /* Request */ + uint32_t krq_reserved; /* Reserved */ +} okm_req_hdr_t; + +/* + * Reply message header. + */ +typedef struct okm_rep_hdr { + uint32_t krp_version; /* protocol version */ + uint32_t krp_transid; /* Transaction ID */ + uint32_t krp_status; /* Status */ + uint32_t krp_sadb_errno; /* PF_KEY errno, if applicable */ + uint32_t krp_sadb_version; /* PF_KEY version, if applicable */ +} okm_rep_hdr_t; + +/* + * Version of this current protocol. + */ +#define OKM_PROTOCOL_VERSION 1 + + +/* + * Message types. + */ +#define OKM_MSG_SADB 0x1 /* SADB message from SP */ + +/* + * Values for sckm_msg_rep_hdr status field. + */ +#define OKM_SUCCESS 0x0 /* Operation succeeded */ +#define OKM_ERR_VERSION 0x1 /* Unexpected version */ +#define OKM_ERR_SADB_PFKEY 0x2 /* PF_KEY returned an error */ +#define OKM_ERR_SADB_MSG 0x3 /* bad SADB msg detect by driver */ +#define OKM_ERR_DAEMON 0x4 /* Error communicating with daemon */ +#define OKM_ERR_BAD_CMD 0x5 /* unknown command */ +#define OKM_ERR_SADB_VERSION 0x6 /* bad SADB version */ +#define OKM_ERR_SADB_TIMEOUT 0x7 /* no response from key engine */ +#define OKM_ERR_SADB_BAD_TYPE 0x8 /* bad SADB msg type */ + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_OPLKM_MSG_H */ diff --git a/usr/src/uts/sun4u/opl/sys/oplmsu/oplmsu.h b/usr/src/uts/sun4u/opl/sys/oplmsu/oplmsu.h new file mode 100644 index 0000000000..f738979706 --- /dev/null +++ b/usr/src/uts/sun4u/opl/sys/oplmsu/oplmsu.h @@ -0,0 +1,358 @@ +/* + * 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 + */ +/* + * All Rights Reserved, Copyright (c) FUJITSU LIMITED 2006 + */ + +#ifndef _OPLMSU_H +#define _OPLMSU_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +/* ack_flag */ +#define ACK_RES 0 +#define NAK_RES -1 + +/* active_flag */ +#define ACTIVE_RES 0 +#define NOT_ACTIVE_RES -1 + +/* undefined path number */ +#define UNDEFINED -1 + +/* sleep and wakeup control flag */ +#define CV_WAKEUP 0 +#define CV_SLEEP 1 + +/* write/read control flag */ +#define MSU_WRITE_SIDE 0 +#define MSU_READ_SIDE 1 + +/* message priority */ +#define MSU_HIGH 1 +#define MSU_NORM 0 + +/* miscellaneous */ +#define SUCCESS 0 +#define FAILURE -1 +#if !defined(BUSY) /* warning: macro redefined */ +#define BUSY -2 +#endif + +/* timeout interval */ +#define MSU_TM_500MS 500000 /* 500ms */ + +/* XON/XOFF code */ +#define MSU_XON 0x11 +#define MSU_XOFF 0x13 +#define MSU_XON_4 (MSU_XON << 24|MSU_XON << 16|MSU_XON << 8|MSU_XON) +#define MSU_XOFF_4 (MSU_XOFF << 24|MSU_XOFF << 16|MSU_XOFF << 8|MSU_XOFF) + +/* main path code used by MSU_CMD_START ioctl */ +#define MAINPATHCODE 0x1000 +#define MSU_OBP_CONSOLE -2 + +/* maximum number of minor device number */ +#define MAXDEVMINOR 256 + +/* node mask */ +#define USER_NODE_MASK 0x00000000 /* user control node */ +#define META_NODE_MASK 0x00010000 /* meta control node */ + +/* node_flag */ +#define MSU_NODE_USER 0 /* user control node */ +#define MSU_NODE_META 1 /* meta control node */ + +/* node_flag check macro */ +#define MSU_NODE_TYPE(dev) \ + (((dev) & (META_NODE_MASK|USER_NODE_MASK)) >> 16) + +/* termio_flag */ +#define MSU_TIOS_TCSETS 1 /* TCSETS */ +#define MSU_TIOS_MSET 2 /* TIOCMSET */ +#define MSU_TIOS_PPS 3 /* TIOCSPPS */ +#define MSU_TIOS_WINSZP 4 /* TIOCSWINSZ */ +#define MSU_TIOS_SOFTCAR 5 /* TIOCSSOFTCAR */ +#define MSU_TIOS_END 6 /* termios end */ + +/* binding name */ +#define MSU_CMUCH_FF "pci10cf,138f" +#define MSU_CMUCH_DC "pci10cf,1390" +#ifdef DEBUG +#define MSU_CMUCH_DBG "pci108e,8000" +#endif + +/* tty-port# properties */ +#define MSU_TTY_PORT_PROP "tty-port#" + +/* board# properties */ +#define MSU_BOARD_PROP "board#" + +/* + * oplmsu command code + */ +#define MSU_CMD ('f' << 8) +#define MSU_CMD_STOP (MSU_CMD|0x14) +#define MSU_CMD_START (MSU_CMD|0x15) +#define MSU_CMD_ACTIVE (MSU_CMD|0x1a) + +#define MSU_PATH_ALL (-1) /* path all instruction */ + +/* + * oplmsu path status for status member on upper path info table + */ +#define MSU_PSTAT_EMPTY 0 +#define MSU_PSTAT_ACTIVE 1 +#define MSU_PSTAT_STANDBY 2 +#define MSU_PSTAT_STOP 3 +#define MSU_PSTAT_FAIL 4 +#define MSU_PSTAT_DISCON 5 +#define MSU_PSTAT_ENCAP 6 + +/* + * oplmsu additional status for traditional_status member on + * upper path info table + */ +#define MSU_UNLINK 0 /* initial state */ +#define MSU_EMPTY 1 /* MSU_STAT_EMPTY(00) state */ +#define MSU_LINK_NU 2 /* link state(no link ID, no upper path info) */ +#define MSU_SETID_NU 3 /* set ID state(link ID, no upper path info) */ +#define MSU_MAKE_INST 4 /* create instance node state */ +#define MSU_STOP 5 /* MSU_STAT_STOP(03) state */ +#define MSU_WSTR_ACK 6 /* wait ack/nak of MSU_CMD_START state */ +#define MSU_STANDBY 7 /* MSU_STAT_STANDBY(02) state */ +#define MSU_WTCS_ACK 8 /* wait ack/nak of TCSETS state */ +#define MSU_WTMS_ACK 9 /* wait ack/nak of TIOCMSET state */ +#define MSU_WPPS_ACK 10 /* wait ack/nak of TIOCSPPS state */ +#define MSU_WWSZ_ACK 11 /* wait ack/nak of TIOCSWINSZ state */ +#define MSU_WCAR_ACK 12 /* wait ack/nak of TIOCSSOFTCAR state */ +#define MSU_ACTIVE 13 /* MSU_STAT_ACTIVE(01) state */ +#define MSU_WSTP_ACK 14 /* wait ack/nak of MSU_CMD_STOP state */ +#define MSU_FAIL 15 /* MSU_STAT_FAIL(04) state */ +#define MSU_WCHK_ACK 16 /* wait ack/nak of OPLMSUSELFTEST */ +#define MSU_SETID 17 /* set ID state(link ID, upper path info) */ +#define MSU_DISCON 18 /* MSU_STAT_DISCON(05) state */ +#define MSU_LINK 19 /* link state(no link ID, upper path info) */ +#define MSU_WPTH_CHG 20 /* wait ack/nak of OPLMSUPATHCHG state */ + +/* + * oplmsu instance status for inst_status member on + * upper instance info talbe + */ +#define INST_STAT_BUSY -1 /* busy */ +#define INST_STAT_ONLINE 10 /* online */ +#define INST_STAT_OFFLINE 11 /* offline */ +#define INST_STAT_UNCONFIGURED 12 /* unconfigured */ + +/* + * oplmsu lower path Info table ext status for ext member on + * lower path info table + */ +#define MSU_EXT_NOTUSED -1 /* not used (default) */ +#define MSU_EXT_ACTIVE_CANDIDATE -2 /* active path candidate by */ + /* MSU_CMD_START */ +#define MSU_EXT_VOID -3 /* void status */ + +/* oplmsu/su pathname size */ +#define MSU_PATHNAME_SIZE 128 + +/* control block(path parameter) */ +struct msu_path { + int num; /* total number of paths */ + int reserved; /* reserved */ +}; + +/* control block(device parameter) */ +struct msu_dev { + dev_info_t *dip; /* pointer to dev_info_t */ +}; + +/* serial device control block */ +typedef struct serial_devcb { + dev_info_t *dip; /* pointer to dev_info_t */ + int lsb; /* LSB number */ +} ser_devcb_t; + +/* serial device countrl block list */ +typedef struct serial_devlist { + struct serial_devlist *next; + dev_info_t *dip; /* pointer to dev_info_t */ +} ser_devl_t; + +/* upper path table */ +typedef struct upper_path_table { + struct upper_path_table *u_next; + struct upper_path_table *u_prev; + struct lower_path_table *lpath; + int path_no; + int reserved; + int status; + int prev_status; + ulong_t traditional_status; + ser_devcb_t ser_devcb; +} upath_t; + +/* lower path table */ +typedef struct lower_path_table { + struct lower_path_table *l_next; + struct lower_path_table *l_prev; + mblk_t *first_lpri_hi; + mblk_t *last_lpri_hi; + mblk_t *hndl_mp; + queue_t *hndl_uqueue; + queue_t *lower_queue; + queue_t *uwq_queue; + struct upper_instance_table *uinst; + char *abt_char; + struct buf_tbl *rbuftbl; + bufcall_id_t rbuf_id; + timeout_id_t rtout_id; + upath_t *src_upath; + long status; + int path_no; + int link_id; + int uwq_flag; + int sw_flag; + kcondvar_t sw_cv; +} lpath_t; + +/* control table */ +typedef struct control_table { + struct control_table *c_next; + struct control_table *c_prev; + mblk_t *first_upri_hi; + mblk_t *last_upri_hi; + queue_t *queue; + queue_t *lrq_queue; + queue_t *wait_queue; + minor_t minor; + int node_type; + struct buf_tbl *wbuftbl; + bufcall_id_t wbuf_id; + timeout_id_t wtout_id; + int lrq_flag; + int sleep_flag; + kcondvar_t cvp; +} ctrl_t; + +#define MSU_MAX_ABTSLEN 24 /* maximum length for abort sequence */ + +/* upper instance table */ +typedef struct upper_instance_table { + upath_t *first_upath; + upath_t *last_upath; + lpath_t *first_lpath; + lpath_t *last_lpath; + ctrl_t *meta_ctrl; + ctrl_t *user_ctrl; + queue_t *lower_queue; + dev_info_t *msu_dip; + int inst_status; + int path_num; + int reserved[2]; + krwlock_t lock; + kmutex_t u_lock; + kmutex_t l_lock; + kmutex_t c_lock; + mblk_t *tcsets_p; + mblk_t *tiocmset_p; + mblk_t *tiocspps_p; + mblk_t *tiocswinsz_p; + mblk_t *tiocssoftcar_p; + char abts[MSU_MAX_ABTSLEN]; +} uinst_t; + +/* queue table for bufcall() and timeout() */ +struct buf_tbl { + queue_t *q; + int rw_flag; +}; + + +/* rwlock macro */ +#define OPLMSU_RWLOCK_UPGRADE() { \ + if (rw_tryupgrade(&oplmsu_uinst->lock) == 0) { \ + rw_exit(&oplmsu_uinst->lock); \ + rw_enter(&oplmsu_uinst->lock, RW_WRITER); \ + } \ +} + +#ifdef DEBUG +typedef struct tracedata { + queue_t *q; + mblk_t *mp; + char op[3]; + uchar_t msg_type; + int pathno; + int msg_cmd; + ulong_t data; +} msu_trc_t; + +#define MSU_TRC_USER ('u' << 24|'s' << 16|'e' << 8|'r') +#define MSU_TRC_META ('m' << 24|'e' << 16|'t' << 8|'a') + +/* oplmsu_trace_on */ +#define MSU_TRACE_OFF 0 +#define MSU_TRACE_ON 1 + +/* oplmsu_debug_mode */ +#define MSU_DPRINT_ON 1 /* enable print log */ + +/* op type */ +#define MSU_TRC_UI 0 /* upper input */ +#define MSU_TRC_UO 1 /* upper output */ +#define MSU_TRC_LI 2 /* lower input */ +#define MSU_TRC_LO 3 /* lower output */ +#define MSU_TRC_OPN 4 /* open */ +#define MSU_TRC_CLS 5 /* close */ + +/* trace macro */ +#define OPLMSU_TRACE(q, mp, op) { \ + if (oplmsu_trace_on == MSU_TRACE_ON) { \ + oplmsu_cmn_trace(q, mp, op); \ + } \ +} + +/* debug print macro */ +#define DBG_PRINT(args) { \ + if (oplmsu_debug_mode & MSU_DPRINT_ON) { \ + cmn_err args; \ + } \ +} + +#else /* ! DEBUG */ + +/* trace macro */ +#define OPLMSU_TRACE(q, mp, op) + +/* debug print macro */ +#define DBG_PRINT(args) +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _OPLMSU_H */ diff --git a/usr/src/uts/sun4u/opl/sys/oplmsu/oplmsu_proto.h b/usr/src/uts/sun4u/opl/sys/oplmsu/oplmsu_proto.h new file mode 100644 index 0000000000..2481917f4e --- /dev/null +++ b/usr/src/uts/sun4u/opl/sys/oplmsu/oplmsu_proto.h @@ -0,0 +1,166 @@ +/* + * 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 + */ +/* + * All Rights Reserved, Copyright (c) FUJITSU LIMITED 2006 + */ + +#ifndef _OPLMSU_PROTO_H +#define _OPLMSU_PROTO_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * PROTOTYPE DECLARATIONS + */ + +int oplmsu_attach(dev_info_t *, ddi_attach_cmd_t); +int oplmsu_detach(dev_info_t *, ddi_detach_cmd_t); +int oplmsu_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); +int oplmsu_open(queue_t *, dev_t *, int, int, cred_t *); +int oplmsu_close(queue_t *, int, cred_t *); +int oplmsu_uwput(queue_t *, mblk_t *); +int oplmsu_uwsrv(queue_t *); +int oplmsu_lwsrv(queue_t *); +int oplmsu_lrput(queue_t *, mblk_t *); +int oplmsu_lrsrv(queue_t *); +int oplmsu_ursrv(queue_t *); + +int oplmsu_open_msu(dev_info_t *, ldi_ident_t *, ldi_handle_t *); +int oplmsu_plink_serial(dev_info_t *, ldi_handle_t, int *); +int oplmsu_set_lpathnum(int, int); +int oplmsu_dr_attach(dev_info_t *); +int oplmsu_dr_detach(dev_info_t *); +int oplmsu_find_serial(ser_devl_t **); +dev_info_t *oplmsu_find_ser_dip(dev_info_t *); +void oplmsu_conf_stream(uinst_t *); +void oplmsu_unlinks(ldi_handle_t, int *, int); +void oplmsu_setup(uinst_t *); +int oplmsu_create_upath(dev_info_t *); +int oplmsu_config_new(struct msu_path *); +int oplmsu_config_add(dev_info_t *); +int oplmsu_config_del(struct msu_path *); +int oplmsu_config_stop(int); +int oplmsu_config_start(int); +int oplmsu_config_disc(int); + +/* + * UPPER WRITE SERVICE PROCEDURE + */ +int oplmsu_uwioctl_iplink(queue_t *, mblk_t *); +int oplmsu_uwioctl_ipunlink(queue_t *, mblk_t *); +int oplmsu_uwioctl_termios(queue_t *, mblk_t *); + +/* + * LOWER READ SERVICE PROCEDURE + */ +int oplmsu_lrioctl_termios(queue_t *, mblk_t *); +int oplmsu_lrmsg_error(queue_t *, mblk_t *); +int oplmsu_lrdata_xoffxon(queue_t *, mblk_t *); + +/* + * COMMON FUNCTIONS + */ +void oplmsu_link_upath(upath_t *); +void oplmsu_unlink_upath(upath_t *); +void oplmsu_link_lpath(lpath_t *); +void oplmsu_unlink_lpath(lpath_t *); +void oplmsu_link_high_primsg(mblk_t **, mblk_t **, mblk_t *); +int oplmsu_check_lpath_usable(void); +upath_t *oplmsu_search_upath_info(int); + +void oplmsu_iocack(queue_t *, mblk_t *, int); +void oplmsu_delete_upath_info(void); +int oplmsu_set_ioctl_path(lpath_t *, queue_t *, mblk_t *); +void oplmsu_clear_ioctl_path(lpath_t *); + +int oplmsu_get_inst_status(void); +upath_t *oplmsu_search_standby(void); +void oplmsu_search_min_stop_path(void); +int oplmsu_get_pathnum(void); +int oplmsu_cmn_put_xoffxon(queue_t *, int); +void oplmsu_cmn_putxoff_standby(void); +void oplmsu_cmn_set_mflush(mblk_t *); +void oplmsu_cmn_set_upath_sts(upath_t *, int, int, ulong_t); +int oplmsu_cmn_allocmb(queue_t *, mblk_t *, mblk_t **, size_t, int); +int oplmsu_cmn_copymb(queue_t *, mblk_t *, mblk_t **, mblk_t *, int); +void oplmsu_cmn_bufcall(queue_t *, mblk_t *, size_t, int); +int oplmsu_cmn_prechg(queue_t *, mblk_t *, int, mblk_t **, int *, int *); +int oplmsu_stop_prechg(mblk_t **, int *, int *); +int oplmsu_cmn_prechg_termio(queue_t *, mblk_t *, int, int, mblk_t **, + int *); +int oplmsu_cmn_pullup_msg(queue_t *, mblk_t *); + +void oplmsu_cmn_wakeup(queue_t *); +void oplmsu_cmn_bufcb(void *); +void oplmsu_wbufcb_posthndl(ctrl_t *); + +/* + * common functions for write stream + */ +int oplmsu_wcmn_chknode(queue_t *, int, mblk_t *); +void oplmsu_wcmn_flush_hndl(queue_t *, mblk_t *, krw_t); +int oplmsu_wcmn_through_hndl(queue_t *, mblk_t *, int, krw_t); +mblk_t *oplmsu_wcmn_high_getq(queue_t *); +void oplmsu_wcmn_norm_putbq(queue_t *, mblk_t *, queue_t *); +void oplmsu_wcmn_high_qenable(queue_t *, krw_t); + +/* + * common functions for read stream + */ +void oplmsu_rcmn_flush_hndl(queue_t *, mblk_t *); +int oplmsu_rcmn_through_hndl(queue_t *, mblk_t *, int); +void oplmsu_rcmn_high_qenable(queue_t *); + + +#ifdef DEBUG +void oplmsu_cmn_trace(queue_t *, mblk_t *, int); +void oplmsu_cmn_msglog(mblk_t *, int); +void oplmsu_cmn_prt_pathname(dev_info_t *); +#endif + + +/* + * GLOBAL VARIABLES + */ +extern uinst_t *oplmsu_uinst; +extern int oplmsu_queue_flag; +extern int oplmsu_check_su; + +#ifdef DEBUG +extern int oplmsu_debug_mode; +extern int oplmsu_trace_on; +extern uint_t oplmsu_ltrc_size; +extern msu_trc_t *oplmsu_ltrc_top; +extern msu_trc_t *oplmsu_ltrc_tail; +extern msu_trc_t *oplmsu_ltrc_cur; +extern ulong_t oplmsu_ltrc_ccnt; +extern kmutex_t oplmsu_ltrc_lock; +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _OPLMSU_PROTO_H */ diff --git a/usr/src/uts/sun4u/opl/sys/pcicmu/pcicmu.h b/usr/src/uts/sun4u/opl/sys/pcicmu/pcicmu.h new file mode 100644 index 0000000000..9e533c0cf8 --- /dev/null +++ b/usr/src/uts/sun4u/opl/sys/pcicmu/pcicmu.h @@ -0,0 +1,450 @@ +/* + * 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_PCICMU_H +#define _SYS_PCICMU_H + +#pragma ident "%Z%%M% %I% %E% SMI" + + +#ifdef __cplusplus +extern "C" { +#endif + +#include <sys/pci.h> +#include <sys/pci_intr_lib.h> +#include <sys/pcicmu/pcmu_types.h> +#include <sys/pcicmu/pcmu_ib.h> +#include <sys/pcicmu/pcmu_cb.h> +#include <sys/pcicmu/pcmu_ecc.h> +#include <sys/pcicmu/pcmu_pbm.h> +#include <sys/pcicmu/pcmu_counters.h> +#include <sys/pcicmu/pcmu_util.h> +#include <sys/pcicmu/pcmu_err.h> + + +/* + * The following typedef is used to represent a + * 1275 "bus-range" property of a PCI Bus node. + */ +struct pcmu_bus_range { + uint32_t lo; + uint32_t hi; +}; + +/* + * Structure to represent an entry in the + * "ranges" property of a device node. + */ +struct pcmu_ranges { + uint32_t child_high; + uint32_t child_mid; + uint32_t child_low; + uint32_t parent_high; + uint32_t parent_low; + uint32_t size_high; + uint32_t size_low; +}; + +typedef enum { + PCMU_NEW, + PCMU_ATTACHED, + PCMU_DETACHED, + PCMU_SUSPENDED +} pcmu_state_t; + +typedef enum { + PCMU_PBM_OBJ, + PCMU_ECC_OBJ, + PCMU_CB_OBJ +} pcmu_obj_t; + +typedef enum { + PCMU_OBJ_INTR_ADD, + PCMU_OBJ_INTR_REMOVE +} pcmu_obj_op_t; + +#define PCI_OPLCMU "pcicmu" + +/* + * pcicmu soft state structure. + */ +struct pcicmu { + /* + * State flags and mutex: + */ + pcmu_state_t pcmu_state; + uint_t pcmu_soft_state; + uint_t pcmu_open_count; + kmutex_t pcmu_mutex; + + /* + * Links to other state structures: + */ + dev_info_t *pcmu_dip; /* devinfo structure */ + pcmu_ib_t *pcmu_ib_p; /* interrupt block */ + pcmu_cb_t *pcmu_cb_p; /* control block */ + pcmu_pbm_t *pcmu_pcbm_p; /* PBM block */ + pcmu_ecc_t *pcmu_pecc_p; /* ECC error block */ + + /* + * other state info: + */ + uint_t pcmu_id; /* Jupiter device id */ + uint32_t pcmu_rev; /* Bus bridge chip identification */ + + /* + * pci device node properties: + */ + pcmu_bus_range_t pcmu_bus_range; /* "bus-range" */ + pcmu_ranges_t *pcmu_ranges; /* "ranges" data & length */ + int pcmu_ranges_length; + uint32_t *pcmu_inos; /* inos from "interrupts" prop */ + int pcmu_inos_len; /* "interrupts" length */ + int pcmu_numproxy; /* upa interrupt proxies */ + + /* + * register mapping: + */ + caddr_t pcmu_address[4]; + ddi_acc_handle_t pcmu_ac[4]; + + /* + * Performance counters kstat. + */ + pcmu_cntr_pa_t pcmu_uks_pa; + kstat_t *pcmu_uksp; /* ptr to upstream kstat */ + kmutex_t pcmu_err_mutex; /* per chip error handling mutex */ + + /* Fault Management support */ + int pcmu_fm_cap; + ddi_iblock_cookie_t pcmu_fm_ibc; +}; + +/* + * pcmu_soft_state values. + */ +#define PCMU_SOFT_STATE_OPEN 0x01 +#define PCMU_SOFT_STATE_OPEN_EXCL 0x02 +#define PCMU_SOFT_STATE_CLOSED 0x04 + +/* + * CMU-CH and PBM soft state macros: + */ +#define PCMU_AP_MINOR_NUM_TO_INSTANCE(x) ((x) >> 8) + +#define get_pcmu_soft_state(i) \ + ((pcmu_t *)ddi_get_soft_state(per_pcmu_state, (i))) + +#define alloc_pcmu_soft_state(i) \ + ddi_soft_state_zalloc(per_pcmu_state, (i)) + +#define free_pcmu_soft_state(i) \ + ddi_soft_state_free(per_pcmu_state, (i)) + +#define DEV_TO_SOFTSTATE(dev) ((pcmu_t *)ddi_get_soft_state(per_pcmu_state, \ + PCMU_AP_MINOR_NUM_TO_INSTANCE(getminor(dev)))) + +#define PCMU_ATTACH_RETCODE(obj, op, err) \ + ((err) ? (obj) << 8 | (op) << 4 | (err) & 0xf : DDI_SUCCESS) + + +/* + * Performance counters information. + */ +#define PCMU_SHIFT_PIC0 8 +#define PCMU_SHIFT_PIC1 0 + +/* + * CMU-CH-specific register offsets & bit field positions. + */ + +/* + * Offsets of global registers: + */ +#define PCMU_CB_DEVICE_ID_REG_OFFSET 0x00000000 /* RAGS */ +#define PCMU_CB_CONTROL_STATUS_REG_OFFSET 0x00000010 + +/* + * CMU-CH performance counters offsets. + */ +#define PCMU_PERF_PCR_OFFSET 0x00000100 +#define PCMU_PERF_PIC_OFFSET 0x00000108 + +/* + * Offsets of registers in the interrupt block: + */ +#define PCMU_IB_OBIO_INTR_MAP_REG_OFFSET 0x00001000 +#define PCMU_IB_OBIO_CLEAR_INTR_REG_OFFSET 0x00001800 + +/* + * Offsets of registers in the PBM block: + */ +#define PCMU_PCI_PBM_REG_BASE 0x00002000 /* RAGS */ +#define PCMU_PCI_CTRL_REG_OFFSET 0x00000000 +#define PCMU_PCI_ASYNC_FLT_STATUS_REG_OFFSET 0x00000010 +#define PCMU_PCI_ASYNC_FLT_ADDR_REG_OFFSET 0x00000018 +#define PCMU_PCI_DIAG_REG_OFFSET 0x00000020 + +/* + * CMU-CH control register bit definitions: + */ +#define PCMU_CB_CONTROL_STATUS_MODE 0x0000000000000001ull +#define PCMU_CB_CONTROL_STATUS_IMPL 0xf000000000000000ull +#define PCMU_CB_CONTROL_STATUS_IMPL_SHIFT 60 +#define PCMU_CB_CONTROL_STATUS_VER 0x0f00000000000000ull +#define PCMU_CB_CONTROL_STATUS_VER_SHIFT 56 + +/* + * CMU-CH ECC UE AFSR bit definitions: + */ +#define PCMU_ECC_UE_AFSR_BYTEMASK 0x0000ffff00000000ull +#define PCMU_ECC_UE_AFSR_BYTEMASK_SHIFT 32 +#define PCMU_ECC_UE_AFSR_DW_OFFSET 0x00000000e0000000ull +#define PCMU_ECC_UE_AFSR_DW_OFFSET_SHIFT 29 +#define PCMU_ECC_UE_AFSR_ID 0x000000001f000000ull +#define PCMU_ECC_UE_AFSR_ID_SHIFT 24 +#define PCMU_ECC_UE_AFSR_BLK 0x0000000000800000ull + +/* + * CMU-CH pci control register bits: + */ +#define PCMU_PCI_CTRL_ARB_PARK 0x0000000000200000ull +#define PCMU_PCI_CTRL_WAKEUP_EN 0x0000000000000200ull +#define PCMU_PCI_CTRL_ERR_INT_EN 0x0000000000000100ull +#define PCMU_PCI_CTRL_ARB_EN_MASK 0x000000000000000full + +/* + * CMU-CH PCI asynchronous fault status register bit definitions: + */ +#define PCMU_PCI_AFSR_PE_SHIFT 60 +#define PCMU_PCI_AFSR_SE_SHIFT 56 +#define PCMU_PCI_AFSR_E_MA 0x0000000000000008ull +#define PCMU_PCI_AFSR_E_TA 0x0000000000000004ull +#define PCMU_PCI_AFSR_E_RTRY 0x0000000000000002ull +#define PCMU_PCI_AFSR_E_PERR 0x0000000000000001ull +#define PCMU_PCI_AFSR_E_MASK 0x000000000000000full +#define PCMU_PCI_AFSR_BYTEMASK 0x0000ffff00000000ull +#define PCMU_PCI_AFSR_BYTEMASK_SHIFT 32 +#define PCMU_PCI_AFSR_BLK 0x0000000080000000ull +#define PCMU_PCI_AFSR_MID 0x000000003e000000ull +#define PCMU_PCI_AFSR_MID_SHIFT 25 + +/* + * CMU-CH PCI diagnostic register bit definitions: + */ +#define PCMU_PCI_DIAG_DIS_DWSYNC 0x0000000000000010ull + +#define PBM_AFSR_TO_PRIERR(afsr) \ + (afsr >> PCMU_PCI_AFSR_PE_SHIFT & PCMU_PCI_AFSR_E_MASK) +#define PBM_AFSR_TO_SECERR(afsr) \ + (afsr >> PCMU_PCI_AFSR_SE_SHIFT & PCMU_PCI_AFSR_E_MASK) + +#define PCMU_ID_TO_IGN(pcmu_id) ((pcmu_ign_t)UPAID_TO_IGN(pcmu_id)) + + +/* + * Number of dispatch target entries. + */ +#define U2U_DATA_NUM 16 + +/* + * Offsets of registers in the Interrupt Dispatch Table: + */ +#define U2U_MODE_STATUS_REGISTER_OFFSET 0x00000000 +#define U2U_PID_REGISTER_OFFSET 0x00000008 +#define U2U_DATA_REGISTER_OFFSET 0x00000010 + +/* + * Mode Status register bit definitions: + */ +#define U2U_MS_IEV 0x00000040 /* bit-6: Interrupt Extension enable */ + +/* + * Index number of U2U registers in OBP's "regs-property" of CMU-CH + */ +#define REGS_INDEX_OF_U2U 3 + +/* + * The following two difinitions are used to control target id + * for Interrupt dispatch data by software. + */ +typedef struct u2u_ittrans_id { + uint_t u2u_tgt_cpu_id; /* target CPU ID */ + uint_t u2u_rsv1; /* reserved */ + volatile uint64_t *u2u_ino_map_reg; /* u2u intr. map register */ +} u2u_ittrans_id_t; + +typedef struct u2u_ittrans_data { + kmutex_t u2u_ittrans_lock; + uintptr_t u2u_regs_base; /* "reg" property */ + ddi_acc_handle_t u2u_acc; /* pointer to acc */ + uint_t u2u_port_id; /* "PID" register n U2U */ + uint_t u2u_board; /* "board#" property */ + u2u_ittrans_id_t u2u_ittrans_id[U2U_DATA_NUM]; +} u2u_ittrans_data_t; + + +/* + * Offsets of registers in the interrupt block: + */ + +#define PCMU_IB_UPA0_INTR_MAP_REG_OFFSET 0x6000 +#define PCMU_IB_UPA1_INTR_MAP_REG_OFFSET 0x8000 +#define PCMU_IB_SLOT_CLEAR_INTR_REG_OFFSET 0x1400 +#define PCMU_IB_OBIO_INTR_STATE_DIAG_REG 0xA808 +#define PCMU_IB_INTR_RETRY_TIMER_OFFSET 0x1A00 + +/* + * Offsets of registers in the ECC block: + */ +#define PCMU_ECC_CSR_OFFSET 0x20 +#define PCMU_UE_AFSR_OFFSET 0x30 +#define PCMU_UE_AFAR_OFFSET 0x38 + +/* + * CMU-CH control register bit definitions: + */ +#define PCMU_CB_CONTROL_STATUS_IGN 0x0007c00000000000ull +#define PCMU_CB_CONTROL_STATUS_IGN_SHIFT 46 +#define PCMU_CB_CONTROL_STATUS_APCKEN 0x0000000000000008ull +#define PCMU_CB_CONTROL_STATUS_APERR 0x0000000000000004ull +#define PCMU_CB_CONTROL_STATUS_IAP 0x0000000000000002ull + +/* + * CMU-CH interrupt mapping register bit definitions: + */ +#define PCMU_INTR_MAP_REG_VALID 0x0000000080000000ull +#define PCMU_INTR_MAP_REG_TID 0x000000007C000000ull +#define PCMU_INTR_MAP_REG_IGN 0x00000000000007C0ull +#define PCMU_INTR_MAP_REG_INO 0x000000000000003full +#define PCMU_INTR_MAP_REG_TID_SHIFT 26 +#define PCMU_INTR_MAP_REG_IGN_SHIFT 6 + +/* + * CMU-CH clear interrupt register bit definitions: + */ +#define PCMU_CLEAR_INTR_REG_MASK 0x0000000000000003ull +#define PCMU_CLEAR_INTR_REG_IDLE 0x0000000000000000ull +#define PCMU_CLEAR_INTR_REG_RECEIVED 0x0000000000000001ull +#define PCMU_CLEAR_INTR_REG_RSVD 0x0000000000000002ull +#define PCMU_CLEAR_INTR_REG_PENDING 0x0000000000000003ull + +/* + * CMU-CH ECC control register bit definitions: + */ +#define PCMU_ECC_CTRL_ECC_EN 0x8000000000000000ull +#define PCMU_ECC_CTRL_UE_INTEN 0x4000000000000000ull + +/* + * CMU-CH ECC UE AFSR bit definitions: + */ +#define PCMU_ECC_UE_AFSR_PE_SHIFT 61 +#define PCMU_ECC_UE_AFSR_SE_SHIFT 58 +#define PCMU_ECC_UE_AFSR_E_MASK 0x0000000000000007ull +#define PCMU_ECC_UE_AFSR_E_PIO 0x0000000000000004ull + +/* + * CMU-CH PCI diagnostic register bit definitions: + */ +#define PCMU_PCI_DIAG_DIS_RETRY 0x0000000000000040ull +#define PCMU_PCI_DIAG_DIS_INTSYNC 0x0000000000000020ull + + +#define NAMEINST(dip) ddi_driver_name(dip), ddi_get_instance(dip) +#define NAMEADDR(dip) ddi_node_name(dip), ddi_get_name_addr(dip) + + +/* + * CMU-CH Tunables + */ +extern uint32_t pcmu_spurintr_duration; /* spurious interupt duration */ +extern ushort_t pcmu_command_default; /* default command */ +extern uint_t ecc_error_intr_enable; /* ECC error intr */ +extern uint_t pcmu_ecc_afsr_retries; /* num ECC afsr retries */ +extern uint_t pcmu_intr_retry_intv; /* intr retry interval */ +extern uint_t pcmu_panic_on_fatal_errors; /* PANIC on fatal errors */ +extern uint_t pcmu_unclaimed_intr_max; /* Max unclaimed interrupts */ +extern hrtime_t pcmu_intrpend_timeout; /* intr pending timeout */ + + +extern void *per_pcmu_state; /* per-pbm soft state pointer */ +extern kmutex_t pcmu_global_mutex; /* attach/detach common struct lock */ +extern uint64_t pcmu_errtrig_pa; + + +/* + * Prototypes. + */ +extern void pcmu_post_uninit_child(pcmu_t *); +extern void pcmu_kstat_init(void); +extern void pcmu_kstat_fini(void); +extern void pcmu_add_upstream_kstat(pcmu_t *); +extern void pcmu_fix_ranges(pcmu_ranges_t *, int); +extern uint_t pcmu_pbm_disable_errors(pcmu_pbm_t *); +extern uint32_t ib_map_reg_get_cpu(volatile uint64_t); +extern uint64_t *ib_intr_map_reg_addr(pcmu_ib_t *, pcmu_ib_ino_t); +extern uint64_t *ib_clear_intr_reg_addr(pcmu_ib_t *, pcmu_ib_ino_t); +extern void pcmu_cb_setup(pcmu_t *); +extern void pcmu_cb_teardown(pcmu_t *); +extern int cb_register_intr(pcmu_t *); +extern void cb_enable_intr(pcmu_t *); +extern uint64_t cb_ino_to_map_pa(pcmu_cb_t *, pcmu_ib_ino_t); +extern uint64_t cb_ino_to_clr_pa(pcmu_cb_t *, pcmu_ib_ino_t); +extern int cb_remove_xintr(pcmu_t *, dev_info_t *, dev_info_t *, + pcmu_ib_ino_t, pcmu_ib_mondo_t); +extern uint32_t pcmu_intr_dist_cpuid(pcmu_ib_t *, pcmu_ib_ino_info_t *); +extern void pcmu_ecc_setup(pcmu_ecc_t *); +extern ushort_t pcmu_ecc_get_synd(uint64_t); +extern void pcmu_pbm_setup(pcmu_pbm_t *); +extern void pcmu_pbm_teardown(pcmu_pbm_t *); +extern uintptr_t pcmu_ib_setup(pcmu_ib_t *); +extern int pcmu_get_numproxy(dev_info_t *); +extern int pcmu_ecc_add_intr(pcmu_t *, int, pcmu_ecc_intr_info_t *); +extern void pcmu_ecc_rem_intr(pcmu_t *, int, pcmu_ecc_intr_info_t *); +extern int pcmu_pbm_err_handler(dev_info_t *, ddi_fm_error_t *, + const void *, int); +extern void pcmu_ecc_classify(uint64_t, pcmu_ecc_errstate_t *); +extern int pcmu_pbm_classify(pcmu_pbm_errstate_t *); +extern int pcmu_check_error(pcmu_t *); +extern void set_intr_mapping_reg(int, uint64_t *, int); +extern uint32_t pcmu_class_to_pil(dev_info_t *rdip); +extern int pcmu_add_intr(dev_info_t *dip, dev_info_t *rdip, + ddi_intr_handle_impl_t *hdlp); +extern int pcmu_remove_intr(dev_info_t *dip, dev_info_t *rdip, + ddi_intr_handle_impl_t *hdlp); +extern void pcmu_intr_teardown(pcmu_t *pcmu_p); + +extern int u2u_translate_tgtid(pcmu_t *, uint_t, volatile uint64_t *); +extern void u2u_ittrans_cleanup(u2u_ittrans_data_t *, volatile uint64_t *); +void pcmu_err_create(pcmu_t *pcmu_p); +void pcmu_err_destroy(pcmu_t *pcmu_p); +void pcmu_pbm_ereport_post(dev_info_t *dip, uint64_t ena, + pcmu_pbm_errstate_t *pbm_err); +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_PCICMU_H */ diff --git a/usr/src/uts/sun4u/opl/sys/pcicmu/pcmu_cb.h b/usr/src/uts/sun4u/opl/sys/pcicmu/pcmu_cb.h new file mode 100644 index 0000000000..9690a3b23b --- /dev/null +++ b/usr/src/uts/sun4u/opl/sys/pcicmu/pcmu_cb.h @@ -0,0 +1,81 @@ +/* + * 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_PCMU_CB_H +#define _SYS_PCMU_CB_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +enum pcmu_cb_nintr_index { + CBNINTR_PBM = 0, /* not shared */ + CBNINTR_UE = 1, /* shared */ + CBNINTR_CE = 2, /* shared */ + CBNINTR_POWER_FAIL = 3, /* shared */ + CBNINTR_THERMAL = 4, /* shared */ + CBNINTR_MAX /* max */ +}; + +/* + * control block soft state structure: + */ +struct pcmu_cb { + pcmu_t *pcb_pcmu_p; + pcmu_ign_t pcb_ign; /* interrupt grp# */ + kmutex_t pcb_intr_lock; /* guards add/rem intr and intr dist */ + uint32_t pcb_no_of_inos; /* # of actual inos, including PBM */ + uint32_t pcb_inos[CBNINTR_MAX]; /* subset of pcmu_p->pcmu_inos array */ + uint64_t pcb_base_pa; /* PA of CSR bank, 2nd "reg" */ + uint64_t pcb_map_pa; /* map reg base PA */ + uint64_t pcb_clr_pa; /* clr reg base PA */ + uint64_t pcb_obsta_pa; /* sta reg base PA */ + uint64_t *pcb_imr_save; + caddr_t pcb_ittrans_cookie; /* intr tgt translation */ +}; + +#define PCMU_CB_INO_TO_MONDO(pcb_p, ino) \ + ((pcb_p)->pcb_ign << PCMU_INO_BITS | (ino)) + +/* + * Prototypes. + */ +extern void pcmu_cb_create(pcmu_t *pcmu_p); +extern void pcmu_cb_destroy(pcmu_t *pcmu_p); +extern void pcmu_cb_suspend(pcmu_cb_t *cb_p); +extern void pcmu_cb_resume(pcmu_cb_t *cb_p); +extern void pcmu_cb_enable_nintr(pcmu_t *pcmu_p, pcmu_cb_nintr_index_t idx); +extern void pcmu_cb_disable_nintr(pcmu_cb_t *cb_p, + pcmu_cb_nintr_index_t idx, int wait); +extern void pcmu_cb_clear_nintr(pcmu_cb_t *cb_p, pcmu_cb_nintr_index_t idx); +extern void pcmu_cb_intr_dist(void *arg); + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_PCMU_CB_H */ diff --git a/usr/src/uts/sun4u/opl/sys/pcicmu/pcmu_counters.h b/usr/src/uts/sun4u/opl/sys/pcicmu/pcmu_counters.h new file mode 100644 index 0000000000..ed63d7ffba --- /dev/null +++ b/usr/src/uts/sun4u/opl/sys/pcicmu/pcmu_counters.h @@ -0,0 +1,78 @@ +/* + * 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_PCMU_COUNTERS_H +#define _SYS_PCMU_COUNTERS_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +#define NUM_OF_PICS 2 + +/* + * used to build array of event-names and pcr-mask values + */ +typedef struct pcmu_kev_mask { + char *event_name; /* Event name */ + uint64_t pcr_mask; /* PCR mask */ +} pcmu_kev_mask_t; + +typedef struct pcmu_ksinfo { + uint8_t pic_no_evs; /* number of events */ + uint8_t pic_shift[NUM_OF_PICS]; /* PIC shift */ + kstat_t *pic_name_ksp[NUM_OF_PICS]; /* kstat names */ +} pcmu_ksinfo_t; + +typedef struct pcmu_cntr_addr { + uint64_t *pcr_addr; + uint64_t *pic_addr; +} pcmu_cntr_addr_t; + +typedef struct pcmu_cntr_pa { + uint64_t pcr_pa; + uint64_t pic_pa; +} pcmu_cntr_pa_t; + +/* + * Prototypes. + */ +extern void pcmu_create_name_kstat(char *, pcmu_ksinfo_t *, pcmu_kev_mask_t *); +extern void pcmu_delete_name_kstat(pcmu_ksinfo_t *); +extern kstat_t *pcmu_create_cntr_kstat(pcmu_t *, char *, int, + int (*update)(kstat_t *, int), void *); +extern int pcmu_cntr_kstat_update(kstat_t *, int); +extern int pcmu_cntr_kstat_pa_update(kstat_t *, int); +extern void pcmu_kstat_create(pcmu_t *); +extern void pcmu_kstat_destroy(pcmu_t *); +extern void pcmu_rem_upstream_kstat(pcmu_t *); + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_PCMU_COUNTERS_H */ diff --git a/usr/src/uts/sun4u/opl/sys/pcicmu/pcmu_ecc.h b/usr/src/uts/sun4u/opl/sys/pcicmu/pcmu_ecc.h new file mode 100644 index 0000000000..7062f5cdca --- /dev/null +++ b/usr/src/uts/sun4u/opl/sys/pcicmu/pcmu_ecc.h @@ -0,0 +1,75 @@ +/* + * 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_PCMU_ECC_H +#define _SYS_PCMU_ECC_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +struct pcmu_ecc_intr_info { + pcmu_ecc_t *pecc_p; + int pecc_type; /* CBNINTR_UE */ + uint64_t pecc_afsr_pa; /* ECC AFSR phsyical address */ + uint64_t pecc_afar_pa; /* ECC AFAR physical address */ + + /* + * Implementation-specific masks & shift values. + */ + uint64_t pecc_errpndg_mask; /* 0 if not applicable. */ /* RAGS */ + uint64_t pecc_offset_mask; + uint_t pecc_offset_shift; + uint_t pecc_size_log2; +}; + +struct pcmu_ecc { + pcmu_t *pecc_pcmu_p; + volatile uint64_t pecc_csr_pa; /* ECC control & status reg */ + struct pcmu_ecc_intr_info pecc_ue; /* ECC UE error intr info */ + timeout_id_t pecc_tout_id; +}; + +/* + * Prototypes + */ +extern void pcmu_ecc_create(pcmu_t *pcmu_p); +extern int pcmu_ecc_register_intr(pcmu_t *pcmu_p); +extern void pcmu_ecc_destroy(pcmu_t *pcmu_p); +extern void pcmu_ecc_configure(pcmu_t *pcmu_p); +extern void pcmu_ecc_enable_intr(pcmu_t *pcmu_p); +extern void pcmu_ecc_disable_wait(pcmu_ecc_t *pecc_p); +extern uint_t pcmu_ecc_disable_nowait(pcmu_ecc_t *pecc_p); +extern uint_t pcmu_ecc_intr(caddr_t a); +extern int pcmu_ecc_err_handler(pcmu_ecc_errstate_t *ecc_err_p); +extern void pcmu_ecc_err_drain(void *not_used, pcmu_ecc_errstate_t *ecc_err); + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_PCMU_ECC_H */ diff --git a/usr/src/uts/sun4u/opl/sys/pcicmu/pcmu_err.h b/usr/src/uts/sun4u/opl/sys/pcicmu/pcmu_err.h new file mode 100644 index 0000000000..89b4ed8de7 --- /dev/null +++ b/usr/src/uts/sun4u/opl/sys/pcicmu/pcmu_err.h @@ -0,0 +1,135 @@ +/* + * 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_PCMU_ERR_H +#define _SYS_PCMU_ERR_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/ddifm.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _KERNEL + +#define PBM_PRIMARY 1 +#define PBM_SECONDARY 0 +#define PBM_NONFATAL 0 +#define PBM_FATAL 1 +#define FM_LOG_PCI 0 +#define FM_LOG_PBM 1 +#define ECC_MAX_ERRS 6 +#define TARGET_MAX_ERRS 6 + +/* + * Since pcmu_pbm_err_handler() is called by various interrupt/trap/callback + * handlers, it is necessary for it to know where it is being called from. + * Below are the flags passed to pcmu_pbm_err_handler() to give it knowledge + * of it's caller. + */ +#define PCI_TRAP_CALL 0x0 +#define PCI_CB_CALL 0x1 +#define PCI_INTR_CALL 0x2 +#define PCI_BUS_EXIT_CALL 0x3 +#define PCI_ECC_CALL 0x4 + +extern errorq_t *pcmu_ecc_queue; /* per-system ecc handling queue */ + +struct pcmu_errstate { + char *pcmu_err_class; + uint16_t pcmu_cfg_stat; + uint16_t pcmu_cfg_comm; + uint64_t pcmu_pa; +}; + +/* + * pbm errstate use to encompass the state for all errors + * detected by the pci block + */ +struct pcmu_pbm_errstate { + char *pbm_err_class; + int pcbm_pri; + int pbm_log; + uint32_t pbm_err; + uint32_t pbm_multi; + char *pbm_bridge_type; + uint64_t pbm_ctl_stat; + uint64_t pbm_afsr; + uint64_t pbm_afar; + uint64_t pbm_va_log; + uint64_t pbm_err_sl; + uint64_t pcbm_pcix_stat; + uint32_t pcbm_pcix_pfar; + pcmu_errstate_t pcbm_pci; + char *pcmu_pbm_terr_class; +}; + +/* + * ecc errstate used to store all state captured, + * upon detection of an ecc error. + */ +struct pcmu_ecc_errstate { + char *ecc_bridge_type; + pcmu_ecc_t *pecc_p; + uint64_t ecc_afsr; + uint64_t ecc_afar; + uint64_t ecc_offset; + uint64_t ecc_dev_id; + uint64_t ecc_dw_offset; + struct async_flt ecc_aflt; + pcmu_ecc_intr_info_t ecc_ii_p; + uint64_t ecc_ctrl; + int pecc_pri; + char ecc_unum[UNUM_NAMLEN]; + uint64_t ecc_ena; + uint64_t ecc_err_addr; + char *ecc_err_type; + int pecc_pg_ret; + nvlist_t *ecc_fmri; + int ecc_caller; +}; + +extern int pcmu_fm_init_child(dev_info_t *dip, dev_info_t *tdip, int cap, + ddi_iblock_cookie_t *ibc); +extern void pcmu_bus_enter(dev_info_t *dip, ddi_acc_handle_t handle); +extern void pcmu_bus_exit(dev_info_t *dip, ddi_acc_handle_t handle); +extern void pcmu_pbm_ereport_post(dev_info_t *dip, uint64_t ena, + pcmu_pbm_errstate_t *pbm_err); +extern void pcmu_fm_acc_setup(ddi_map_req_t *mp, dev_info_t *rdip); +extern int pcmu_handle_lookup(dev_info_t *dip, int type, uint64_t fme_ena, + void *afar); +extern void pcmu_fm_create(pcmu_t *pcmu_p); +extern void pcmu_fm_destroy(pcmu_t *pcmu_p); +extern int pcmu_err_callback(dev_info_t *dip, ddi_fm_error_t *derr, + const void *impl_data); +#endif /* _KERNEL */ + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_PCMU_ERR_H */ diff --git a/usr/src/uts/sun4u/opl/sys/pcicmu/pcmu_ib.h b/usr/src/uts/sun4u/opl/sys/pcicmu/pcmu_ib.h new file mode 100644 index 0000000000..24c5bfee6a --- /dev/null +++ b/usr/src/uts/sun4u/opl/sys/pcicmu/pcmu_ib.h @@ -0,0 +1,173 @@ +/* + * 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_PCMU_IB_H +#define _SYS_PCMU_IB_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +#include <sys/ddi_subrdefs.h> + +typedef uint8_t pcmu_ib_ino_t; +typedef uint16_t pcmu_ib_mondo_t; + +/* + * The following structure represents an interrupt entry for an INO. + */ +typedef struct ih { + dev_info_t *ih_dip; /* devinfo structure */ + uint32_t ih_inum; /* interrupt number for this device */ + uint_t ih_intr_state; /* Only used for fixed interrupts */ + uint_t (*ih_handler)(); /* interrupt handler */ + caddr_t ih_handler_arg1; /* interrupt handler argument #1 */ + caddr_t ih_handler_arg2; /* interrupt handler argument #2 */ + ddi_acc_handle_t ih_config_handle; /* config space reg map handle */ + struct ih *ih_next; /* next entry in list */ +} ih_t; + +/* + * ino structure : one per CMU-CH ino with interrupt registered + */ +typedef struct pcmu_ib_ino_info { + struct pcmu_ib_ino_info *pino_next; + pcmu_ib_ino_t pino_ino; /* INO number - 8 bit */ + uint8_t pino_slot_no; /* PCI slot number 0-8 */ + uint16_t pino_ih_size; /* size of the pci intrspec list */ + ih_t *pino_ih_head; /* intr spec (part of ppd) list head */ + ih_t *pino_ih_tail; /* intr spec (part of ppd) list tail */ + ih_t *pino_ih_start; /* starting point in intr spec list */ + pcmu_ib_t *pino_ib_p; /* link back to interrupt block state */ + volatile uint64_t *pino_clr_reg; /* ino interrupt clear register */ + volatile uint64_t *pino_map_reg; /* ino interrupt mapping register */ + uint64_t pino_map_reg_save; /* = *pino_map_reg if saved */ + uint32_t pino_pil; /* PIL for this ino */ + volatile uint_t pino_unclaimed; /* number of unclaimed interrupts */ + clock_t pino_spurintr_begin; /* begin time of spurious intr series */ + int pino_established; /* ino has been associated with a cpu */ + uint32_t pino_cpuid; /* cpu that ino is targeting */ + int32_t pino_intr_weight; /* intr weight of devices sharing ino */ +} pcmu_ib_ino_info_t; + +/* + * interrupt block soft state structure: + */ +struct pcmu_ib { + pcmu_t *pib_pcmu_p; /* link back to pci soft state */ + pcmu_ign_t pib_ign; /* interrupt group # */ + uintptr_t pib_obio_intr_map_regs; /* onboard intr map register */ + uintptr_t pib_obio_clear_intr_regs; /* onboard intr clear reg */ + volatile uint64_t *pib_upa_imr[2]; /* UPA expansion intr map register */ + uint64_t pib_upa_imr_state[2]; /* UPA intr map state */ /* RAGS */ + volatile uint64_t *pib_intr_retry_timer_reg; /* intr retry register */ + volatile uint64_t *pib_obio_intr_state_diag_reg; /* onboard intr st. */ + uint_t pib_max_ino; /* largest supported INO */ + pcmu_ib_ino_info_t *pib_ino_lst; /* ino link list */ + kmutex_t pib_ino_lst_mutex; /* mutex for ino link list */ + kmutex_t pib_intr_lock; /* lock for internal intr */ +}; + +#define PCMU_MAX_INO 0x3f +#define PCMU_INO_BITS 6 /* INO#s are 6 bits long */ + +/* + * Only used for fixed or legacy interrupts + */ +#define PCMU_INTR_STATE_DISABLE 0 /* disabled */ +#define PCMU_INTR_STATE_ENABLE 1 /* enabled */ + +#define PCMU_IB_INTR_WAIT 1 /* wait for inter completion */ +#define PCMU_IB_INTR_NOWAIT 0 /* handling intr, no wait */ + +#define PCMU_IB2CB(pib_p) ((pib_p)->pib_pcmu_p->pcmu_cb_p) + +#define PCMU_IB_MONDO_TO_INO(mondo) ((pcmu_ib_ino_t)((mondo) & 0x3f)) +#define PCMU_IB_INO_INTR_ON(reg_p) *(reg_p) |= PCMU_INTR_MAP_REG_VALID +#define PCMU_IB_INO_INTR_OFF(reg_p) *(reg_p) &= ~PCMU_INTR_MAP_REG_VALID +#define PCMU_IB_INO_INTR_STATE_REG(pib_p, ino) \ + (pib_p->pib_obio_intr_state_diag_reg) + +#define PCMU_IB_INO_INTR_PENDING(reg_p, ino) \ + (((*(reg_p) >> (((ino) & 0x1f) << 1)) & \ + PCMU_CLEAR_INTR_REG_MASK) == PCMU_CLEAR_INTR_REG_PENDING) + +#define PCMU_IB_INO_INTR_CLEAR(reg_p) *(reg_p) = PCMU_CLEAR_INTR_REG_IDLE +#define PCMU_IB_INO_INTR_PEND(reg_p) *(reg_p) = PCMU_CLEAR_INTR_REG_PENDING +#define PCMU_IB_INO_INTR_ISON(imr) ((imr) >> 31) + +#define PCMU_IB_IMR2MONDO(imr) ((imr) & \ + (PCMU_INTR_MAP_REG_IGN | PCMU_INTR_MAP_REG_INO)) + +#define PCMU_IB_IS_OBIO_INO(ino) (ino & 0x20) + +#define PCMU_IB_IGN_TO_MONDO(ign, ino) (((ign) << PCMU_INO_BITS) | (ino)) +#define PCMU_IB_INO_TO_MONDO(pib_p, ino) \ + PCMU_IB_IGN_TO_MONDO((pib_p)->pib_ign, ino) + + +extern int pcmu_pil[]; + +/* + * Prototypes + */ +extern void pcmu_ib_create(pcmu_t *pcmu_p); +extern void pcmu_ib_destroy(pcmu_t *pcmu_p); +extern void pcmu_ib_configure(pcmu_ib_t *pib_p); +extern uint64_t ib_get_map_reg(pcmu_ib_mondo_t mondo, uint32_t cpu_id); +extern void pcmu_ib_intr_enable(pcmu_t *pcmu_p, pcmu_ib_ino_t ino); +extern void pcmu_ib_intr_disable(pcmu_ib_t *pib_p, pcmu_ib_ino_t ino, int wait); +extern void pcmu_ib_nintr_clear(pcmu_ib_t *pib_p, pcmu_ib_ino_t ino); +extern void pcmu_ib_suspend(pcmu_ib_t *pib_p); +extern void pcmu_ib_resume(pcmu_ib_t *pib_p); +extern pcmu_ib_ino_info_t *pcmu_ib_locate_ino(pcmu_ib_t *pib_p, + pcmu_ib_ino_t ino_num); +extern pcmu_ib_ino_info_t *pcmu_ib_new_ino(pcmu_ib_t *pib_p, + pcmu_ib_ino_t ino_num, ih_t *ih_p); +extern void pcmu_ib_delete_ino(pcmu_ib_t *pib_p, pcmu_ib_ino_info_t *ino_p); +extern void pcmu_ib_free_ino_all(pcmu_ib_t *pib_p); +extern int pcmu_ib_update_intr_state(pcmu_t *pcmu_p, dev_info_t *rdip, + ddi_intr_handle_impl_t *hdlp, uint_t new_intr_state); +extern void pcmu_ib_ino_add_intr(pcmu_t *pcmu_p, + pcmu_ib_ino_info_t *ino_p, ih_t *ih_p); +extern void pcmu_ib_ino_rem_intr(pcmu_t *pcmu_p, + pcmu_ib_ino_info_t *ino_p, ih_t *ih_p); +extern ih_t *pcmu_ib_ino_locate_intr(pcmu_ib_ino_info_t *ino_p, + dev_info_t *dip, uint32_t inum); +extern ih_t *pcmu_ib_alloc_ih(dev_info_t *dip, uint32_t inum, + uint_t (*int_handler)(caddr_t int_handler_arg1, caddr_t int_handler_arg2), + caddr_t int_handler_arg1, caddr_t int_handler_arg2); +extern void pcmu_ib_intr_dist_nintr(pcmu_ib_t *pib_p, pcmu_ib_ino_t ino, + volatile uint64_t *imr_p); +extern void pcmu_ib_intr_dist_all(void *arg, + int32_t max_weight, int32_t weight); + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_PCMU_IB_H */ diff --git a/usr/src/uts/sun4u/opl/sys/pcicmu/pcmu_pbm.h b/usr/src/uts/sun4u/opl/sys/pcicmu/pcmu_pbm.h new file mode 100644 index 0000000000..340be4ff8a --- /dev/null +++ b/usr/src/uts/sun4u/opl/sys/pcicmu/pcmu_pbm.h @@ -0,0 +1,99 @@ +/* + * 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_PCMU_PBM_H +#define _SYS_PCMU_PBM_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <sys/dditypes.h> +#include <sys/ontrap.h> +#include <sys/callb.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * The following structure represents the pci configuration header + * for CMU-CH PBM. + */ +typedef struct config_header { + volatile uint16_t ch_vendor_id; + volatile uint16_t ch_device_id; + volatile uint16_t ch_command_reg; + volatile uint16_t ch_status_reg; + volatile uint8_t ch_revision_id_reg; + volatile uint8_t ch_programming_if_code_reg; + volatile uint8_t ch_sub_class_reg; + volatile uint8_t ch_base_class_reg; + volatile uint8_t ch_cache_line_size_reg; + volatile uint8_t ch_latency_timer_reg; + volatile uint8_t ch_header_type_reg; +} config_header_t; + +#define PBM_NAMESTR_BUFLEN 64 + +/* + * CMU-CH pbm block soft state structure: + */ +struct pcmu_pbm { + pcmu_t *pcbm_pcmu_p; /* link back to the soft state */ + + volatile uint64_t *pcbm_ctrl_reg; /* PBM control reg */ + volatile uint64_t *pcbm_async_flt_status_reg; /* PBM AFSR reg */ + volatile uint64_t *pcbm_async_flt_addr_reg; /* PBM AFAR reg */ + volatile uint64_t *pcbm_diag_reg; /* PBM diag reg */ + + config_header_t *pcbm_config_header; /* PBM config header */ + uint64_t pcbm_imr_save; /* intr map save area */ + ddi_iblock_cookie_t pcbm_iblock_cookie; /* PBM error intr priority */ + + on_trap_data_t *pcbm_ontrap_data; /* ddi_poke support */ + kmutex_t pcbm_pokeflt_mutex; /* poke mutex */ + ddi_acc_handle_t pcbm_excl_handle; /* cautious IO access handle */ + char pcbm_nameinst_str[PBM_NAMESTR_BUFLEN]; /* driver name & inst */ + char *pcbm_nameaddr_str; /* node name & address */ +}; + +/* + * Prototypes + */ +extern void pcmu_pbm_create(pcmu_t *pcmu_p); +extern void pcmu_pbm_destroy(pcmu_t *pcmu_p); +extern void pcmu_pbm_configure(pcmu_pbm_t *pcbm_p); +extern void pcmu_pbm_suspend(pcmu_pbm_t *pcbm_p); +extern void pcmu_pbm_resume(pcmu_pbm_t *pcbm_p); +extern void pcmu_pbm_intr_dist(void *arg); +extern int pcmu_pbm_register_intr(pcmu_pbm_t *pcbm_p); +extern int pcmu_pbm_afsr_report(dev_info_t *dip, uint64_t fme_ena, + pcmu_pbm_errstate_t *pbm_err_p); + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_PCMU_PBM_H */ diff --git a/usr/src/uts/sun4u/opl/sys/pcicmu/pcmu_types.h b/usr/src/uts/sun4u/opl/sys/pcicmu/pcmu_types.h new file mode 100644 index 0000000000..7fccf74f3e --- /dev/null +++ b/usr/src/uts/sun4u/opl/sys/pcicmu/pcmu_types.h @@ -0,0 +1,54 @@ +/* + * 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_PCMU_TYPES_H +#define _SYS_PCMU_TYPES_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct pcicmu pcmu_t; +typedef struct pcmu_cb pcmu_cb_t; +typedef struct pcmu_ib pcmu_ib_t; +typedef struct pcmu_pbm pcmu_pbm_t; +typedef uint16_t pcmu_ign_t; +typedef struct pcmu_errstate pcmu_errstate_t; +typedef struct pcmu_ecc_errstate pcmu_ecc_errstate_t; +typedef struct pcmu_pbm_errstate pcmu_pbm_errstate_t; +typedef struct pcmu_cb_errstate pcmu_cb_errstate_t; +typedef struct pcmu_bus_range pcmu_bus_range_t; +typedef struct pcmu_ranges pcmu_ranges_t; +typedef enum pcmu_cb_nintr_index pcmu_cb_nintr_index_t; +typedef struct pcmu_ecc pcmu_ecc_t; +typedef struct pcmu_ecc_intr_info pcmu_ecc_intr_info_t; + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_PCMU_TYPES_H */ diff --git a/usr/src/uts/sun4u/opl/sys/pcicmu/pcmu_util.h b/usr/src/uts/sun4u/opl/sys/pcicmu/pcmu_util.h new file mode 100644 index 0000000000..31ba222cd1 --- /dev/null +++ b/usr/src/uts/sun4u/opl/sys/pcicmu/pcmu_util.h @@ -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 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _SYS_PCMU_UTIL_H +#define _SYS_PCMU_UTIL_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + + +/* + * Prototypes + */ +extern int pcmu_init_child(pcmu_t *, dev_info_t *); +extern int pcmu_uninit_child(pcmu_t *, dev_info_t *); +extern int pcmu_report_dev(dev_info_t *); +extern int get_pcmu_properties(pcmu_t *, dev_info_t *); +extern void free_pcmu_properties(pcmu_t *); +extern int pcmu_get_portid(dev_info_t *); +extern int pcmu_reloc_reg(dev_info_t *, dev_info_t *, pcmu_t *, + pci_regspec_t *); +extern int pcmu_xlate_reg(pcmu_t *, pci_regspec_t *, struct regspec *); +extern off_t pcmu_get_reg_set_size(dev_info_t *, int); +extern uint_t pcmu_get_nreg_set(dev_info_t *); +extern uint64_t pcmu_get_cfg_pabase(pcmu_t *); +extern int pcmu_cfg_report(dev_info_t *, ddi_fm_error_t *, + pcmu_errstate_t *, int, uint32_t); + +#ifdef DEBUG + +extern uint64_t pcmu_debug_flags; + +typedef struct pcmu_dflag_to_str { + uint64_t flag; + char *string; +} pcmu_dflag_to_str_t; + +#define PCMU_DBG_ATTACH 0x1ull +#define PCMU_DBG_DETACH 0x2ull +#define PCMU_DBG_MAP 0x4ull +#define PCMU_DBG_A_INTX 0x8ull +#define PCMU_DBG_R_INTX 0x10ull +#define PCMU_DBG_INIT_CLD 0x20ull +#define PCMU_DBG_CTLOPS 0x40ull +#define PCMU_DBG_INTR 0x80ull +#define PCMU_DBG_ERR_INTR 0x100ull +#define PCMU_DBG_BUS_FAULT 0x200ull +#define PCMU_DBG_IB (0x20ull << 32) +#define PCMU_DBG_CB (0x40ull << 32) +#define PCMU_DBG_PBM (0x80ull << 32) +#define PCMU_DBG_CONT (0x100ull << 32) +#define PCMU_DBG_OPEN (0x1000ull << 32) +#define PCMU_DBG_CLOSE (0x2000ull << 32) +#define PCMU_DBG_IOCTL (0x4000ull << 32) +#define PCMU_DBG_PWR (0x8000ull << 32) + + +#define PCMU_DBG0(flag, dip, fmt) \ + pcmu_debug(flag, dip, fmt, 0, 0, 0, 0, 0); + +#define PCMU_DBG1(flag, dip, fmt, a1) \ + pcmu_debug(flag, dip, fmt, (uintptr_t)(a1), 0, 0, 0, 0); + +#define PCMU_DBG2(flag, dip, fmt, a1, a2) \ + pcmu_debug(flag, dip, fmt, (uintptr_t)(a1), (uintptr_t)(a2), 0, 0, 0); + +#define PCMU_DBG3(flag, dip, fmt, a1, a2, a3) \ + pcmu_debug(flag, dip, fmt, (uintptr_t)(a1), \ + (uintptr_t)(a2), (uintptr_t)(a3), 0, 0); + +#define PCMU_DBG4(flag, dip, fmt, a1, a2, a3, a4) \ + pcmu_debug(flag, dip, fmt, (uintptr_t)(a1), \ + (uintptr_t)(a2), (uintptr_t)(a3), \ + (uintptr_t)(a4), 0); + +#define PCMU_DBG5(flag, dip, fmt, a1, a2, a3, a4, a5) \ + pcmu_debug(flag, dip, fmt, (uintptr_t)(a1), \ + (uintptr_t)(a2), (uintptr_t)(a3), \ + (uintptr_t)(a4), (uintptr_t)(a5)); + +extern void pcmu_debug(uint64_t, dev_info_t *, char *, + uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t); +#else /* DEBUG */ + +#define PCMU_DBG0(flag, dip, fmt) +#define PCMU_DBG1(flag, dip, fmt, a1) +#define PCMU_DBG2(flag, dip, fmt, a1, a2) +#define PCMU_DBG3(flag, dip, fmt, a1, a2, a3) +#define PCMU_DBG4(flag, dip, fmt, a1, a2, a3, a4) +#define PCMU_DBG5(flag, dip, fmt, a1, a2, a3, a4, a5) + +#endif /* DEBUG */ + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_PCMU_UTIL_H */ diff --git a/usr/src/uts/sun4u/opl/sys/scfd/iomp_drv.h b/usr/src/uts/sun4u/opl/sys/scfd/iomp_drv.h new file mode 100644 index 0000000000..224a90b3a9 --- /dev/null +++ b/usr/src/uts/sun4u/opl/sys/scfd/iomp_drv.h @@ -0,0 +1,134 @@ +/* + * 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 + */ +/* + * All Rights Reserved, Copyright (c) FUJITSU LIMITED 2006 + */ + +#ifndef _IOMP_DRV_H +#define _IOMP_DRV_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +#include <sys/types.h> +#include <sys/types32.h> +#include <sys/fiomp.h> + +#define SCF_IOMP_NAME "mscf0" +#define SCF_REAL_NAME "/pseudo/scfd@200:mscf0" +#define SCF_LOGCAL_PATH "/dev/FJSVhwr/scfc" +#define SCF_USER_PATH "/dev/FJSVhwr/pwrctl" + +#define SCF_MAX_STR 256 +#define FIOMP_STAT_ONLINE 10 +#define FIOMP_STAT_OFFLINE 11 +#define FIOMP_STAT_UNCONFIGURED 12 + +#define FIOMP_STAT_RECOVER 20 + +#define FIOMP_STAT_BUSY -1 + +struct fiompdev_32 { + int api_level; /* API level = 0 */ + int inst_no; /* instance number */ + minor32_t inst_minor; /* instance management node */ + minor32_t user_minor; /* user access node */ + int num; /* number of devices */ + caddr32_t devs; /* device names */ + int mpmode; /* multi pathing */ + int autopath; /* automatic path change */ + int block; /* able to block physical device */ + int needsync; /* need synchronize path status */ + caddr32_t ext; /* for extension = NULL */ +}; + +struct fiomp_devinfo_32 { + int inst_no; /* instance number */ + char real_name[FIOMP_MAX_STR]; /* instance management node */ + char user_path[FIOMP_MAX_STR]; /* user access path */ + int path_num; /* number of paths */ + int mpmode; /* multi pathing */ + int autopath; /* automatic path change */ + int block; /* able to block physical device */ + int needsync; /* need synchronize path status */ + caddr32_t ext; /* for extension = NULL */ +}; + +struct fiomp_all_devinfo_32 { + int num; /* number of instances */ + caddr32_t devinfo; /* device informations */ +}; + +struct fiompprop_32 { + caddr32_t iomp_name; /* instance name */ + caddr32_t iomp_real_name; + /* instance management node (/devices) */ + caddr32_t iomp_user_path; + /* instance management node (/dev) */ + caddr32_t iomp_status; /* status of the instance */ + int num; /* number of paths */ + caddr32_t iomp_path; /* target device nodes (/devices) */ + caddr32_t iomp_logical_path; /* target device nodes (/dev) */ + caddr32_t iomp_path_status; /* status of target devices */ + caddr32_t iomp_path_block; /* access block */ +}; + +struct fiompstatus_32 { + int pathnum; /* path number */ + int status; /* FIOMP_STAT_xxxx */ + caddr32_t message; /* some messages */ + int block_status; /* access block status */ + caddr32_t ext; /* reservesd (= NULL) */ +}; + +struct fiomppath_32 { + int num; /* number of paths */ + caddr32_t devs; /* device names */ +}; + +struct fiomp_all_stat_32 { + int num; /* number of paths */ + caddr32_t status; /* path status */ +}; + +struct fiompchg_32 { + int num; /* number of all paths */ + caddr32_t set_status; /* setting values */ + caddr32_t pre_status; /* previous values */ + caddr32_t status; /* current values */ +}; + +struct fiompevent_32 { + int event; /* event type = FIOMP_EVT_xx */ + int num; /* instance number(meta management) or */ + /* number of all path(instance management) */ + caddr32_t pre_status; /* previous status */ + caddr32_t status; /* current status */ +}; + +#ifdef __cplusplus +} +#endif + +#endif /* _IOMP_DRV_H */ diff --git a/usr/src/uts/sun4u/opl/sys/scfd/opcio.h b/usr/src/uts/sun4u/opl/sys/scfd/opcio.h new file mode 100644 index 0000000000..fc085e1b1a --- /dev/null +++ b/usr/src/uts/sun4u/opl/sys/scfd/opcio.h @@ -0,0 +1,326 @@ +/* + * 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 + */ +/* + * All Rights Reserved, Copyright (c) FUJITSU LIMITED 2006 + */ + +#ifndef _SYS_OPCIO_H +#define _SYS_OPCIO_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +#include <sys/ioccom.h> + +/* + * ioctl + */ +#define SCFIOC 'p'<<8 + +/* + * ioctl + */ +#define SCFIOCCLEARLCD (SCFIOC|10|0x80040000) +#define SCFIOCWRLCD (SCFIOC|11|0x800c0000) +#define SCFIOCREPORTSTAT (SCFIOC|22|0x80040000) +#define SCFIOCHAC (SCFIOC|28|0x80810000) +#define SCFIOCRDCLIST (SCFIOC|37|0xc00c0000) +#define SCFIOCHSTADRSINFO (SCFIOC|41|0x40040000) +#define SCFIOCAUTOPWRSET (SCFIOC|42|0x80f40000) +#define SCFIOCAUTOPWRGET (SCFIOC|43|0x40f40000) +#define SCFIOCAUTOPWREXSET (SCFIOC|44|0x80100000) +#define SCFIOCAUTOPWREXGET (SCFIOC|45|0x40100000) +#define SCFIOCAUTOPWRFPOFF (SCFIOC|46|0x80f40000) +#define SCFIOCRCIPWR (SCFIOC|48|0xc0080000) +#define SCFIOCGETREPORT (SCFIOC|49|0x40100000) +#define SCFIOCRDCLISTMAX (SCFIOC|50|0x40040000) +#define SCFIOCRDCLISTX (SCFIOC|51|0x800c0000) +#define SCFIOCRDCTRL (SCFIOC|52|0xc0820000) +#define SCFIOCPANICREQ (SCFIOC|53|0x80040000) +#define SCFIOCSYSAUTOPWRGET (SCFIOC|60|0x20000000) +#define SCFIOCOPECALL (SCFIOC|62|0x20000000) +#define SCFIOCSYSAUTOPWRCLR (SCFIOC|66|0x20000000) +#define SCFIOCPANICCHK (SCFIOC|67|0x80040000) +#define SCFIOCDR (SCFIOC|68|0x80040000) +#define SCFIOCEVENTLIST (SCFIOC|70|0x80040000) +#define SCFIOCGETEVENT (SCFIOC|71|0x80040000) +#define SCFIOCOPTIONDISP (SCFIOC|80|0x80040000) +#define SCFIOCPARMSET (SCFIOC|82|0x80040000) +#define SCFIOCPARMGET (SCFIOC|83|0x80040000) + +#define SCFIOCGETDISKLED (SCFIOC|101|0x80040000) +#define SCFIOCSETDISKLED (SCFIOC|102|0x80040000) +#define SCFIOCGETSDOWNREASON (SCFIOC|103|0x80040000) +#define SCFIOCGETPCICONFIG (SCFIOC|104|0x80040000) +#define SCFIOCSETMADMEVENT (SCFIOC|105|0x80040000) +#define SCFIOCREMCSCMD (SCFIOC|106|0x80040000) +#define SCFIOCSPARECMD (SCFIOC|107|0x80040000) +#define SCFIOCREMCSFILE (SCFIOC|108|0x80040000) + +#define SCFIOCSETPHPINFO (SCFIOC|1|0xe0000000) +#define SCFIOCPCIRESETREQ (SCFIOC|2|0xe0000000) + +/* SCFIOCOPECALL */ +#define SUB_OPECALL_DISP 0x10 /* OP call disp */ +#define SUB_OPECALL_ON_SET 0x20 /* OP call ON set */ +#define SUB_OPECALL_OFF_SET 0x31 /* OP call OFF set */ + +/* SCFIOCCLEARLCD */ +#define SCF_CLRLCD_SEQ 0 + +/* SCFIOCWRLCD */ +typedef struct scfwrlcd { + int lcd_type; + int length; + unsigned char *string; +} scfwrlcd_t; +/* for lcd_type field */ +#define SCF_WRLCD_SEQ 0 + +#define SCF_WRLCD_MAX 32 + +/* SCFIOCREPORTSTAT */ +#define SCF_SHUTDOWN_START 0 +#define SCF_SYSTEM_RUNNING 1 +#define SCF_RE_REPORT 9 + +/* SCFIOCHAC */ +typedef struct scfhac { + unsigned char sbuf[64]; + unsigned char rbuf[64]; + unsigned char sub_command; +} scfhac_t; +/* for sub_command field */ +#define SUB_HOSTADDR_DISP 0x00 /* Host address disp */ +#define SUB_REMOTE_POWCTL_SET 0x11 /* Remote power control set */ +#define SCF_SUB_REMOTE_POWCTL_SET 0x10 +#define SUB_DEVICE_INFO 0x0c /* Device information disp */ + +/* SCFIOCAUTOPWRSET, SCFIOCAUTOPWRGET, SCFIOCAUTOPWRFPOFF */ +typedef struct scfautopwrtime { + int pon_year; /* 1970 - 9999 */ + int pon_month; /* 1 - 12 */ + int pon_date; /* 1 - 31 */ + int pon_hour; /* 0 - 23 */ + int pon_minute; /* 0 - 59 */ + int poff_year; /* 1970 - 9999 */ + int poff_month; /* 1 - 12 */ + int poff_date; /* 1 - 31 */ + int poff_hour; /* 0 - 23 */ + int poff_minute; /* 0 - 59 */ + int flag; + int sarea; +} scfautopwrtime_t; + +typedef struct scfautopwr { + int valid_entries; + struct scfautopwrtime ptime[5]; +} scfautopwr_t; + +/* SCFIOCAUTOPWREXSET, SCFIOCAUTOPWREXGET */ +typedef struct scfautopwrex { + int rpwr_mode; + int rpwr_time; /* minutes */ + int w_time; /* minutes */ + int a_time; /* minutes */ +} scfautopwrex_t; +/* for rpwr_mode field */ +#define AUTOPWREX_RESTORE 0x00 +#define AUTOPWREX_NOPON 0x01 +#define AUTOPWREX_AUTOPON 0x80 + +/* SCFIOCRCIPWR */ +typedef struct scfrcipwr { + int sub_cmd; + unsigned int rci_addr; +} scfrcipwr_t; +/* for sub_cmd field */ +#define RCI_PWR_ON 0x80 +#define RCI_PWR_OFF 0x40 +#define RCI_SYS_RESET 0x20 +#define RCI_PFCTR 0x00 +#define RCI_PWR_NOR_OFF 0x41 + +/* SCFIOCGETREPORT */ +typedef struct scfreport { + int flag; + unsigned int rci_addr; + unsigned char report_sense[4]; + time_t timestamp; +} scfreport_t; +/* for flag field */ +#define GETREPORT_WAIT 1 +#define GETREPORT_NOWAIT 2 +#define GETREPORT_WAIT_AND_RCIDWN 3 + +/* SCFIOCRDCLISTX */ +typedef struct scfrdclistx { + unsigned int rci_addr; + unsigned char status; + unsigned short dev_class; + unsigned char sub_class; +} scfrdclistx_t; + +/* SCFIOCRDCTRL */ +typedef struct scfrdctrl { + unsigned char sub_cmd; + unsigned char scount; + unsigned char sbuf[64]; + unsigned char sense[64]; +} scfrdctrl_t; +/* for sub_cmd field */ +#define SUB_DEVICE_STATUS_RPT 0x14 /* Device status print */ +#define SCF_SUB_DEVICE_STATUS_RPT 0x71 +#define SCF_RCI_PATH_40 0x50 /* RCI device request */ + +/* SCFIOCDR */ +typedef struct scfdr { + unsigned char sbuf[16]; + unsigned char rbuf[16 * 64]; + unsigned char sub_command; +} scfdr_t; +/* for sub_command field */ +#define SUB_SB_CONF_CHG 0x11 /* SB configuration change */ +#define SUB_SB_SENSE 0x00 /* SB status disp */ +#define SUB_SB_SENSE_ALL 0x18 /* SB status all disp */ +#define SUB_SB_BUILD_COMP 0x12 /* SB build completion */ + +/* SCFIOCEVENTLIST */ +#define SCF_EVENTLIST_MAX 128 +typedef struct scfeventlist { + int listcnt; + unsigned char codelist[SCF_EVENTLIST_MAX]; +} scfeventlist_t; + +/* SCFIOCGETEVENT */ +typedef struct scfevent { + int flag; + unsigned int rci_addr; + unsigned char code; + unsigned char size; + unsigned char rsv[2]; + unsigned char event_sense[24]; + time_t timestamp; +} scfevent_t; +/* for flag field */ +#define GETEVENT_WAIT 1 +#define GETEVENT_NOWAIT 2 + +/* SCFIOCOPTIONDISP */ +typedef struct scfoption { + unsigned char rbuf[16]; +} scfoption_t; + +/* SCFIOCPARMSET, SCFIOCPARMGET */ +typedef struct scfparam { + int parm; + int value; +} scfparam_t; +/* for parm field */ +#define SCF_PARM_RDCTRL_TIMER 0x00000001 + +/* SCFIOCGETDISKLED/SCFIOCSETDISKLED */ +#define SCF_DISK_LED_PATH_MAX 512 +typedef struct scfiocgetdiskled { + unsigned char path[SCF_DISK_LED_PATH_MAX]; + unsigned char led; +} scfiocgetdiskled_t; +/* for led field */ +#define SCF_DISK_LED_ON 0x01 +#define SCF_DISK_LED_BLINK 0x02 +#define SCF_DISK_LED_OFF 0x04 + +/* SCFIOCGETSDOWNREASON */ +#define REASON_NOTHING 0x00000000 /* reason nothing */ +#define REASON_SHUTDOWN_FAN 0x00000001 /* Fan unit failure */ +#define REASON_SHUTDOWN_PSU 0x00000002 /* Power unit failure */ +#define REASON_SHUTDOWN_THERMAL 0x00000006 /* Thermal failure */ +#define REASON_SHUTDOWN_UPS 0x00000007 /* UPS failure */ +#define REASON_RCIPOFF 0x00000100 /* RCI POFF */ +#define REASON_XSCFPOFF 0x00000103 /* XSCF POFF */ +#define REASON_SHUTDOWN_HALT 0xffffffff /* SCF HALT */ + +/* SCFIOCGETPCICONFIG */ +typedef struct scfiocgetpciconfig { + unsigned char sbuf[16]; + unsigned char rbuf[65536]; +} scfiocgetpciconfig_t; + +/* SCFIOCSETMADMEVENT */ +typedef struct scfiocsetmadmevent { + unsigned char buf[65536]; + unsigned int size; +} scfiocsetmadmevent_t; + +/* SCFIOCREMCSCMD */ +typedef struct scfiocremcscmd { + unsigned char buf[16]; + unsigned int size; + unsigned char sub_command; +} scfiocremcscmd_t; +/* for sub_command field */ +#define SUB_CMD_EX_REMCS 0x01 + +/* SCFIOCREMCSFILE */ +typedef struct scfiocremcsfile { + unsigned char buf[65536]; + unsigned int size; + unsigned char sub_command; +} scfiocremcsfile_t; +/* for sub_command field */ +#define SUB_FILEUP_READY 0x10 +#define SUB_FILEUP_SET 0x20 +#define SUB_TRANSFER_STOP 0x40 + +/* SCFIOCSPARECMD */ +typedef struct scfiocsparecmd { + unsigned char buf[65536]; + unsigned int size; + unsigned char command; + unsigned char sub_command; + unsigned char spare_sub_command; +} scfiocsparecmd_t; +/* for sub_command field */ +#define SUB_SPARE_SS 0x00 /* Type SS */ +#define SUB_SPARE_SL 0x11 /* Type SL */ +#define SUB_SPARE_LS 0x12 /* Type LS */ + +/* SCFIOCSETPHPINFO */ +typedef struct scfsetphpinfo { + unsigned char buf[65536]; + unsigned int size; +} scfsetphpinfo_t; + +/* SCFIOCPCIRESETREQ */ +typedef struct scfpciresetreq { + unsigned char sbuf[65536]; + unsigned char rbuf[16]; + unsigned int size; +} scfpciresetreq_t; + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_OPCIO_H */ diff --git a/usr/src/uts/sun4u/opl/sys/scfd/scfdebug.h b/usr/src/uts/sun4u/opl/sys/scfd/scfdebug.h new file mode 100644 index 0000000000..a441947757 --- /dev/null +++ b/usr/src/uts/sun4u/opl/sys/scfd/scfdebug.h @@ -0,0 +1,308 @@ +/* + * 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 + */ +/* + * All Rights Reserved, Copyright (c) FUJITSU LIMITED 2006 + */ + +#ifndef _SCFDEBUG_H +#define _SCFDEBUG_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +#include <sys/scfd/scfdscp.h> + +/* + * ioctl + */ +#define SCFIOCDEBUG 'd'<<8 + +/* + * ioctl + */ +#define SCFIOCCMDTHROUGH (SCFIOC|1|0xf0000000) +#define SCFIOCTEST (SCFIOCDEBUG|2|0x80040000) + +/* SCFIOCCMDTHROUGH */ +typedef struct scfcmdthrough { + unsigned short mode; + unsigned short cmdtype; + unsigned short code; + unsigned int sbufleng; + unsigned int rbufleng; + unsigned short status; + unsigned char sbuf[65536 + 16]; + unsigned char rbuf[1024 * 512]; +} scfcmdthrough_t; +/* for mode field */ +#define SCF_CMDTHROUGH_START 0 /* command through start */ +#define SCF_CMDTHROUGH_STOP 1 /* command through stop */ +#define SCF_CMDTHROUGH_CMD 2 /* command through */ +/* for cmdtype field */ +#define SCF_CMDTHROUGH_TYPE_NN 0 /* WRITE:Nothing READ:Nothing */ +#define SCF_CMDTHROUGH_TYPE_NS 1 /* WRITE:Nothing READ:Small */ +#define SCF_CMDTHROUGH_TYPE_NL 2 /* WRITE:Nothing READ:Larg */ +#define SCF_CMDTHROUGH_TYPE_SN 3 /* WRITE:Small READ:Nothing */ +#define SCF_CMDTHROUGH_TYPE_SS 4 /* WRITE:Small READ:Small */ +#define SCF_CMDTHROUGH_TYPE_SL 5 /* WRITE:Small READ:Larg */ +#define SCF_CMDTHROUGH_TYPE_LN 6 /* WRITE:Larg READ:Nothing */ +#define SCF_CMDTHROUGH_TYPE_LS 7 /* WRITE:Larg READ:Small */ + +#define TEST_INFO_MAX 32 + +/* SCFIOCTEST */ +typedef struct scf_scfioctest_tbl { + uint_t mode; + uint_t rci_addr; + uint_t data[2]; + uint_t rsv1; + uint_t rsc2; + uint_t scf_debugxscf; + uint_t rtncode; + uint_t info[TEST_INFO_MAX]; + uint8_t rdata[SRAM_MAX_SYSTEM]; +} scf_scfioctest_t; +/* for mode field (Low 2byte) */ +#define TEST_MODE_MASK_HIGHT 0xffff0000 +#define TEST_MODE_MASK_LOW 0x0000ffff +#define TEST_NONE 0x00000000 + +/* Config mode : for mode field (Low 2byte) */ +#define TEST_CONF 0x00000100 +#define TEST_CONF_RESET 0x00000100 +#define TEST_CONF_DEBUG_MSG 0x00000101 +#define TEST_CONF_CMD_BUSY 0x00000181 +#define TEST_CONF_DSCP_LOOPBACK 0x00000182 +#define TEST_CONF_SCF_PATH 0x00000183 + +/* Interrupt mode : for mode field (Low 2byte) */ +#define TEST_INT 0x00000200 +#define TEST_INT_RESET 0x00000200 +#define TEST_INT_SYS 0x00000201 +#define TEST_INT_SYS_POFF 0x00000202 +#define TEST_INT_SYS_EVENT 0x00000203 +#define TEST_INT_DSCP 0x00000204 + +/* SYS func call mode : for mode field (Low 2byte) */ +#define TEST_SYS_CALL 0x00001000 +#define TEST_SYS_CALL_RESET 0x00001000 +#define TEST_SYS_CALL_INT 0x00001001 + +/* DSCP func call mode : for mode field (Low 2byte) */ +#define TEST_DSCP_CALL 0x00001100 +#define TEST_DSCP_CALL_RESET 0x00001100 +#define TEST_DSCP_CALL_INIT 0x00001101 +#define TEST_DSCP_CALL_FINI 0x00001102 +#define TEST_DSCP_CALL_PUTMSG 0x00001103 +#define TEST_DSCP_CALL_CANGET 0x00001104 +#define TEST_DSCP_CALL_GETMSG 0x00001105 +#define TEST_DSCP_CALL_FLUSH 0x00001106 +#define TEST_DSCP_CALL_CTRL 0x00001107 +#define TEST_DSCP_CALL_OTHER 0x00001108 + +/* OSESCF func callmode : for mode field (Low 2byte) */ +#define TEST_OSESCF_CALL 0x00001200 +#define TEST_OSESCF_CALL_RESET 0x00001200 +#define TEST_OSESCF_CALL_PUTINFO 0x00001201 +#define TEST_OSESCF_CALL_GETINFO 0x00001202 + +/* FMEM OSESCF func callmode : for mode field (Low 2byte) */ +#define TEST_FMEM_START 0x00001211 +#define TEST_FMEM_END 0x00001212 +#define TEST_FMEM_CANCEL 0x00001213 + +/* + * External vwlue + */ +extern uint_t scf_debug_test_sys_int_flag; +extern uint_t scf_debug_test_rxbuff_nosum_check_flag; +extern uint_t scf_debug_test_sys_event_flag; +extern uint_t scf_debug_test_sys_poff_flag; +extern uint_t scf_debug_test_dscp_int_flag; +extern uint_t scf_debug_test_cmdr_busy; +extern uint_t scf_debug_test_cmdexr_busy; +extern uint_t scf_debug_test_copyin; +extern uint_t scf_debug_test_copyout; +extern uint_t scf_debug_test_kmem; +extern uint_t scf_debug_test_path_check; +extern uint_t scf_debug_test_path_check_rtn; +extern uint_t scf_debug_test_offline_check; +extern uint_t scf_debug_test_offline_check_rtn; +extern uint_t scf_debug_test_dscp_call_flag; +extern uint_t scf_debug_test_osescf_call_flag; + +extern uint_t scf_no_make_sum_s; +extern uint_t scf_no_make_sum_l; + +extern uint_t scf_debug_nofirm_sys; +extern uint_t scf_debug_scfint_time; +extern uint_t scf_debug_nofirm_dscp; +extern uint_t scf_debug_idbcint_time; +extern uint_t scf_debug_test_dscp_loopback; +extern uint_t scf_debug_nooffline_check; +extern uint_t scf_debug_no_dscp_path; +extern uint_t scf_debug_no_alive; +extern uint_t scf_debug_norxsum_check; +extern uint_t scf_debug_no_int_reason; +extern uint_t scf_debug_no_device; + +/* + * External function + */ +extern int scf_debug_cmdthrough(intptr_t arg, int mode); +extern int scf_debug_test(intptr_t arg, int mode); +extern void scf_debug_test_intr_tout(void *arg); +extern void scf_debug_test_intr(scf_state_t *statep); +extern void scf_debug_test_intr_scfint(scf_state_t *statep); +extern void scf_debug_test_intr_cmdend(scf_state_t *statep); +extern void scf_debug_test_intr_poff(void); +extern void scf_debug_test_dsens(struct scf_cmd *scfcmdp, + scf_int_reason_t *int_rp, int len); +extern void scf_debug_test_intr_dscp_dsr(scf_state_t *statep); +extern void scf_debug_test_intr_dscp_rxtx(scf_state_t *statep, uint8_t dsr); +extern void scf_debug_test_alive_start(scf_state_t *statep); +extern void scf_debug_test_alive_stop(scf_state_t *statep); +extern void scf_debug_test_alive_intr_tout(void *arg); +extern void scf_debug_test_send_cmd(struct scf_state *statep, + struct scf_cmd *scfcmdp); +extern void scf_debug_test_txreq_send(scf_state_t *statep, + scf_dscp_dsc_t *dsc_p); +extern void scf_debug_test_event_handler(scf_event_t mevent, void *arg); +extern void scf_debug_test_timer_stop(void); +extern void scf_debug_test_map_regs(scf_state_t *statep); +extern void scf_debug_test_unmap_regs(scf_state_t *statep); + +/* + * Debug flag and value define + */ +/* scf_debug_test_sys_int_flag */ +#define SCF_DBF_SYS_INTR_OFF 0 +#define SCF_DBF_SYS_INTR_ON 1 + +/* scf_debug_test_rxbuff_nosum_check_flag */ +#define SCF_DBF_RXBUFF_NOSUM_CHECK_OFF 0 +#define SCF_DBF_RXBUFF_NOSUM_CHECK_ON 1 + +/* scf_debug_test_sys_event_flag */ +#define SCF_DBF_SYS_EVENT_OFF 0 +#define SCF_DBF_SYS_EVENT_ON 1 + +/* scf_debug_test_sys_poff_flag */ +#define SCF_DBF_SYS_POFF_OFF 0 +#define SCF_DBF_SYS_POFF_ON 1 + +/* scf_debug_test_dscp_int_flag */ +#define SCF_DBF_DSCP_INT_OFF 0 +#define SCF_DBF_DSCP_INT_ON 1 + +/* scf_debug_test_cmdr_busy */ +#define SCF_DBC_CMDR_BUSY_CLEAR 0x00000000 + +/* scf_debug_test_cmdexr_busy */ +#define SCF_DBC_CMDEXR_BUSY_CLEAR 0x00000000 + +/* scf_debug_test_copyin */ +#define SCF_DBC_COPYIN_CLEAR 0x00000000 + +/* scf_debug_test_copyout */ +#define SCF_DBC_COPYOUT_CLEAR 0x00000000 + +/* scf_debug_test_kmem */ +#define SCF_DBC_KMEM_CLEAR 0x00000000 + +/* scf_debug_test_path_check */ +#define SCF_DBC_PATH_CHECK_CLEAR 0x00000000 + +/* scf_debug_test_path_check_rtn */ +#define SCF_DBC_PATH_CHECK_RTN_CLEAR 0x00000000 + +/* scf_debug_test_offline_check */ +#define SCF_DBC_OFFLINE_CHECK_CLEAR 0x00000000 + +/* scf_debug_test_offline_check_rtn */ +#define SCF_DBC_OFFLINE_CHECK_RTN_CLEAR 0x00000000 + +/* scf_debug_test_dscp_call_flag */ +#define SCF_DBF_DSCP_CALL_OFF 0 +#define SCF_DBF_DSCP_CALL_ON 1 + +/* scf_debug_test_osescf_call_flag */ +#define SCF_DBF_OSESCF_CALL_OFF 0 +#define SCF_DBF_OSESCF_CALL_ON 1 + +/* scf_no_make_sum_s */ +#define SCF_DBF_NO_MAKE_SUM_S_OFF 0 +#define SCF_DBF_NO_MAKE_SUM_S_ON 1 + +/* scf_no_make_sum_l */ +#define SCF_DBF_NO_MAKE_SUM_L_OFF 0 +#define SCF_DBF_NO_MAKE_SUM_L_ON 1 + +/* scf_debug_nofirm_sys */ +#define SCF_DBF_NOFIRM_SYS_OFF 0 +#define SCF_DBF_NOFIRM_SYS_ON 1 + +/* scf_debug_scfint_time */ +#define SCF_DBT_SCFINT_TIME_100MS 100 + +/* scf_debug_nofirm_dscp */ +#define SCF_DBF_NOFIRM_DSCP_OFF 0 +#define SCF_DBF_NOFIRM_DSCP_ON 1 + +/* scf_debug_idbcint_time */ +#define SCF_DBT_IDBCINT_TIME_100MS 100 + +/* scf_debug_test_dscp_loopback */ +#define SCF_DBF_DSCP_LOOPBACK_OFF 0 +#define SCF_DBF_DSCP_LOOPBACK_ON 1 + +/* scf_debug_nooffline_check */ +#define SCF_DBF_NOOFFLINE_CHECK_OFF 0 +#define SCF_DBF_NOOFFLINE_CHECK_ON 1 + +/* scf_debug_no_dscp_path */ +#define SCF_DBF_NO_DSCP_PATH_OFF 0 +#define SCF_DBF_NO_DSCP_PATH_ON 1 + +/* scf_debug_no_alive */ +#define SCF_DBF_NO_ALIVE_OFF 0 +#define SCF_DBF_NO_ALIVE_ON 1 + +/* scf_debug_norxsum_check */ +#define SCF_DBF_NORXSUM_CHECK_OFF 0 +#define SCF_DBF_NORXSUM_CHECK_ON 1 + +/* scf_debug_no_int_reason */ +#define SCF_DBF_NO_INT_REASON_OFF 0 +#define SCF_DBF_NO_INT_REASON_ON 1 + +/* scf_debug_no_device */ +#define SCF_DBF_NO_DEVICE_OFF 0 +#define SCF_DBF_NO_DEVICE_ON 1 + +#ifdef __cplusplus +} +#endif + +#endif /* _SCFDEBUG_H */ diff --git a/usr/src/uts/sun4u/opl/sys/scfd/scfdscp.h b/usr/src/uts/sun4u/opl/sys/scfd/scfdscp.h new file mode 100644 index 0000000000..1d8c8cc740 --- /dev/null +++ b/usr/src/uts/sun4u/opl/sys/scfd/scfdscp.h @@ -0,0 +1,468 @@ +/* + * 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 + */ +/* + * All Rights Reserved, Copyright (c) FUJITSU LIMITED 2006 + */ + +#ifndef _SCFDSCP_H +#define _SCFDSCP_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +#include <sys/scfd/scfdscpif.h> +/* + * Discriptor define + */ +#define SCF_TOTAL_BUFFSIZE 0x00010000 /* Total buff size (64KB) */ +#define SCF_MB_MAXDATALEN 0x00000600 /* Message data max length */ +#define SCF_TXBUFFSIZE SCF_MB_MAXDATALEN /* Tx buff size (1.5KB) */ +#define SCF_RXBUFFSIZE SCF_MB_MAXDATALEN /* Rx buff size (1.5KB) */ +#define SCF_TX_SRAM_MAXCOUNT 16 /* Tx SRAM max count (0x6000) */ +#define SCF_RX_SRAM_MAXCOUNT 26 /* Rx SRAM max count (0x6000) */ + +#define SCF_TXDSC_CNTROLCOUNT (2 * MBIF_MAX) /* TxDSC control count */ +#define SCF_TXDSC_LOCALCOUNT 1 /* TxDSC local count (DSCP_PATH/CONN_CHK) */ + +#define SCF_TXDSC_MAXCOUNT (SCF_TX_SRAM_MAXCOUNT + SCF_TXDSC_CNTROLCOUNT) + /* TxDSC max count (0x6000) */ +#define SCF_RXDSC_MAXCOUNT SCF_RX_SRAM_MAXCOUNT + /* RxDSC max count (0x9c00) */ + +#define SCF_TXDSC_BUSYCOUNT SCF_TX_SRAM_MAXCOUNT /* TxDSC busy count */ +#define SCF_RXDSC_BUSYCOUNT SCF_RX_SRAM_MAXCOUNT /* RxDSC busy count */ + +/* + * Re-try max count define + */ +#define SCF_TX_ACKTO_MAXRETRAYCOUNT 1 /* TxACK timeout */ +#define SCF_TX_ENDTO_MAXRETRAYCOUNT 1 /* TxEND timeout */ + +#define SCF_TX_BUSY_MAXRETRAYCOUNT 10 /* TxEND Busy */ +#define SCF_TX_IF_MAXRETRAYCOUNT 1 /* TxEND Interface error */ +#define SCF_TX_NAK_MAXRETRAYCOUNT 1 /* TxEND Connection refusal */ +#define SCF_TX_NOTSUP_MAXRETRAYCOUNT 1 /* TxEND Not support */ +#define SCF_TX_PRMERR_MAXRETRAYCOUNT 1 /* TxEND Parameter error */ +#define SCF_TX_SEQERR_MAXRETRAYCOUNT 1 /* TxEND Sequence error */ +#define SCF_TX_OTHER_MAXRETRAYCOUNT 1 /* TxEND other error */ +#define SCF_TX_SEND_MAXRETRAYCOUNT 3 /* TxEND send */ + +/* + * Que max count define + */ +#define SCF_RDQUE_MAXCOUNT SCF_RXDSC_MAXCOUNT /* Recv data */ +#define SCF_RDQUE_BUSYCOUNT SCF_RDQUE_MAXCOUNT /* Recv data */ + +#define SCF_MB_EVQUE_MAXCOUNT (SCF_RDQUE_MAXCOUNT + 4) /* Event */ + +/* + * Mailbox interface code + */ +typedef enum { + MBIF_DSCP, /* DSCP mailbox interface code */ + MBIF_DKMD, /* DKMD mailbox interface code */ + /* Add mailbox interface code */ + MBIF_MAX /* Max interface code */ +} scf_mbif_t; + +/* + * Callback event queue + */ +typedef struct scf_event_que { + scf_event_t mevent; /* Event types */ +} scf_event_que_t; + +/* + * Recv data queue + */ +typedef struct scf_rdata_que { + caddr_t rdatap; /* Recv data address */ + uint32_t length; /* Recv data length */ +} scf_rdata_que_t; + +/* + * DSCP main control table + */ +typedef struct scf_dscp_main { + /* main status */ + uint16_t status; /* Main status */ + uint16_t old_status; /* Old main status */ + uint8_t id; /* Table No. */ + uint8_t rsv[3]; /* reserved */ + + /* flag/code */ + uint_t conn_chk_flag; /* DSCP connect check flag */ + + /* init() parameter */ + target_id_t target_id; /* Target ID specifying the peer */ + mkey_t mkey; /* Data type for mailbox key */ + void (*event_handler)(scf_event_t, void *); + /* event handler function */ + scf_event_t mevent; /* Event types */ + void *arg; /* Callback argument */ + + /* cv_init() condition */ + uint_t cv_init_flag; /* cv_init call flag */ + kcondvar_t fini_cv; /* fint() condition variables */ + uint_t fini_wait_flag; /* fini wait flag */ + + /* flag */ + uint_t putmsg_busy_flag; /* putmsg busy flag */ + + /* memo counter */ + uint_t memo_tx_data_req_cnt; /* Tx DATA_REQ counter */ + uint_t memo_tx_data_req_ok_cnt; /* Tx DATA_REQ ok counter */ + uint_t memo_rx_data_req_cnt; /* Rx DATA_REQ counter */ + uint_t memo_rx_data_req_ok_cnt; /* Rx DATA_REQ ok counter */ + uint_t memo_putmsg_busy_cnt; /* putmsg busy counter */ + uint_t memo_putmsg_enospc_cnt; /* putmsg ENOSPC counter */ + + /* Event/Recv data regulation counter */ + uint_t ev_maxcount; /* Event max count */ + uint_t rd_maxcount; /* Recv data max count */ + uint_t rd_busycount; /* Recv data busy count */ + + /* Event/Recv data working counter */ + uint_t ev_count; /* Use event count */ + uint_t rd_count; /* Use recv data count */ + + /* Event/Recv data table address and size */ + scf_event_que_t *ev_quep; /* Event table pointer */ + uint_t ev_quesize; /* Event table size */ + scf_rdata_que_t *rd_datap; /* Recv data table pointer */ + uint_t rd_datasize; /* Recv data table size */ + + /* Event/Recv data offset */ + uint16_t ev_first; /* Event first */ + uint16_t ev_last; /* Event last */ + uint16_t ev_put; /* Event put */ + uint16_t ev_get; /* Event get */ + uint16_t rd_first; /* Recv data first */ + uint16_t rd_last; /* Recv data last */ + uint16_t rd_put; /* Recv data put */ + uint16_t rd_get; /* Recv data get */ +} scf_dscp_main_t; + +/* + * DCR/DSR register table + */ +typedef union scf_dscreg { + /* Basic code format */ + struct { + uint16_t c_flag; /* Control flag (DCR/DSR) */ + uint16_t offset; /* SRAM offset (DCR/DSR) */ + uint32_t length; /* Data length (DCR) */ + caddr_t dscp_datap; /* KMEM data address */ + } base; + /* TxDCR/RxDCR bit format */ + struct { /* DCR bit format */ + unsigned id : 4; /* control id */ + unsigned code : 4; /* control code */ + + unsigned emergency : 1; /* emergency flag */ + unsigned interrupt : 1; /* interrupt flag */ + unsigned : 2; + unsigned first : 1; /* first data flag */ + unsigned last : 1; /* last data flag */ + unsigned : 2; + } bdcr; + /* TxDSR/RxDSR bit format */ + struct { /* DSR bit format */ + unsigned id : 4; /* control id */ + unsigned code : 4; /* control code */ + + unsigned status : 8; /* complete status */ + } bdsr; +} scf_dscreg_t; + +/* + * DSCP Tx/Rx discriptor table + */ +typedef struct scf_dscp_dsc { + /* TxDSC/RxDSC status */ + uint16_t status; /* Tx/Rx status */ + uint16_t old_status; /* Old Tx/Rx status */ + + /* DCR/DSR interface area */ + scf_dscreg_t dinfo; /* DCR/DSR register table */ +} scf_dscp_dsc_t; + +/* + * DSCP Tx SRAM table + */ +typedef struct scf_tx_sram { + uint16_t use_flag; /* Tx SRAM use flag */ + uint16_t offset; /* Tx SRAM offset */ +} scf_tx_sram_t; + +/* + * DSCP common table + */ +typedef struct scf_dscp_comtbl { + /* DSCP main control table */ + scf_dscp_main_t scf_dscp_main[MBIF_MAX]; /* DSCP main table */ + + /* flag/code */ + uint_t dscp_init_flag; /* DSCP interface init flag */ + uint_t tx_exec_flag; /* TxREQ exec flag */ + uint_t rx_exec_flag; /* RxREQ exec flag */ + uint_t callback_exec_flag; /* Callback exec flag */ + uint_t dscp_path_flag; /* DSCP path change flag */ + uint_t tx_local_use_flag; /* Use local control TxDSC flag */ + + /* size */ + uint_t maxdatalen; /* Message data max length */ + uint_t total_buffsize; /* Total buff size */ + uint_t txbuffsize; /* Tx buff size */ + uint_t rxbuffsize; /* Rx buff size */ + + /* TxDSC/RxDSC/Event regulation counter */ + uint_t txsram_maxcount; /* TxDSC SRAM max count */ + uint_t rxsram_maxcount; /* RxDSC SRAM max count */ + uint_t txdsc_maxcount; /* TxDSC max count */ + uint_t rxdsc_maxcount; /* RxDSC max count */ + uint_t txdsc_busycount; /* TxDSC busy count */ + uint_t rxdsc_busycount; /* RxDSC busy count */ + + /* TxDSC re-try max count */ + uint_t tx_ackto_maxretry_cnt; /* TxACK timeout */ + uint_t tx_endto_maxretry_cnt; /* TxEND timeout */ + + uint_t tx_busy_maxretry_cnt; /* TxEND busy */ + uint_t tx_interface_maxretry_cnt; /* TxEND Interface error */ + uint_t tx_nak_maxretry_cnt; /* TxEND Connection refusal */ + uint_t tx_notsup_maxretry_cnt; /* TxEND Not support */ + uint_t tx_prmerr_maxretry_cnt; /* TxEND Parameter error */ + uint_t tx_seqerr_maxretry_cnt; /* TxEND Sequence erro */ + uint_t tx_other_maxretry_cnt; /* TxEND other error */ + uint_t tx_send_maxretry_cnt; /* TxEND send */ + + /* TxDSC/RxDSC working counter */ + uint_t tx_dsc_count; /* Use TxDSC count */ + uint_t rx_dsc_count; /* Use RxDSC count */ + uint_t tx_sram_count; /* Use Tx SRAM count */ + + /* TxDSC/RxDSC working re-try counter */ + uint_t tx_ackto_retry_cnt; /* TxACK timeout */ + uint_t tx_endto_retry_cnt; /* TxEND timeout */ + + uint_t tx_busy_retry_cnt; /* TxEND busy */ + uint_t tx_interface_retry_cnt; /* TxEND Interface error */ + uint_t tx_nak_retry_cnt; /* TxEND Connection refusal */ + uint_t tx_notsuop_retry_cnt; /* TxEND Not support */ + uint_t tx_prmerr_retry_cnt; /* TxEND Parameter error */ + uint_t tx_seqerr_retry_cnt; /* TxEND Sequence error */ + uint_t tx_other_retry_cnt; /* TxEND other error */ + uint_t tx_send_retry_cnt; /* TxEND send */ + + /* TxDSC/RxDSC memo counter */ + uint_t tx_ackto_memo_cnt; /* TxACK timeout */ + uint_t tx_endto_memo_cnt; /* TxEND timeout */ + uint_t tx_busy_memo_cnt; /* TxEND busy */ + uint_t tx_interface_memo_cnt; /* TxEND Interface error */ + uint_t tx_nak_memo_cnt; /* TxEND Connection refusal */ + uint_t tx_notsuop_memo_cnt; /* TxEND Not support */ + uint_t tx_prmerr_memo_cnt; /* TxEND Parameter error */ + uint_t tx_seqerr_memo_cnt; /* TxEND Sequence error */ + uint_t tx_other_memo_cnt; /* TxEND other error */ + uint_t scf_stop_memo_cnt; /* SCF path stop */ + + /* TxDSC table address and size */ + scf_dscp_dsc_t *tx_dscp; /* TxDSC table pointer */ + uint_t tx_dscsize; /* TxDSC table size */ + /* RxDSC table address and size */ + scf_dscp_dsc_t *rx_dscp; /* RxDSC table pointer */ + uint_t rx_dscsize; /* RxDSC table size */ + /* Tx SRAM table address and size */ + scf_tx_sram_t *tx_sramp; /* Tx SRAM table pointer */ + uint_t tx_sramsize; /* Tx SRAM table size */ + + /* TxDSC offset */ + uint16_t tx_first; /* TxDSC first offset */ + uint16_t tx_last; /* TxDSC last offset */ + uint16_t tx_put; /* TxDSC put offset */ + uint16_t tx_get; /* TxDSC get offset */ + uint16_t tx_local; /* Local control TxDSC offset */ + + /* TxDSC/RxDSC offset */ + uint16_t rx_first; /* RxDSC first offset */ + uint16_t rx_last; /* RxDSC last offset */ + uint16_t rx_put; /* RxDSC put offset */ + uint16_t rx_get; /* RxDSC get offset */ + + /* Tx SRAM offset */ + uint16_t tx_sram_first; /* Tx SRAM first offset */ + uint16_t tx_sram_last; /* Tx SRAM last offset */ + uint16_t tx_sram_put; /* Tx SRAM put offset */ + +} scf_dscp_comtbl_t; + +/* + * DSCP main status (scf_dscp_main_t : status) + */ + /* (A0) Cconnection idle state */ +#define SCF_ST_IDLE 0x0000 + +#ifdef _SCF_SP_SIDE + /* (A1) init() after, INIT_REQ recv state */ +#define SCF_ST_EST_INIT_REQ_RECV_WAIT 0x0001 +#else /* _SCF_SP_SIDE */ + /* (B0) Send INIT_REQ, TxEND recv wait state */ +#define SCF_ST_EST_TXEND_RECV_WAIT 0x0010 +#endif /* _SCF_SP_SIDE */ + + /* (C0) Connection establishment state */ +#define SCF_ST_ESTABLISHED 0x0020 + /* (C1) Recv FINI_REQ, fini() wait state */ +#define SCF_ST_EST_FINI_WAIT 0x0021 + /* (D0) Send FINI_REQ, TxEND recv wait state */ +#define SCF_ST_CLOSE_TXEND_RECV_WAIT 0x0030 + +/* + * DSCP Tx discriptor status (scf_dscp_dsc_t : status) + */ + /* (SA0) Idle state */ +#define SCF_TX_ST_IDLE 0x0000 + /* (SB0) TxREQ send wait & SRAM trans wait state */ +#define SCF_TX_ST_SRAM_TRANS_WAIT 0x0010 + +#ifdef _SCF_SP_SIDE + /* (SB1) TxREQ send wait & SRAM trans comp wait state */ +#define SCF_TX_ST_SRAM_COMP_WAIT 0x0011 +#endif /* _SCF_SP_SIDE */ + + /* (SB2) TxREQ send wait & TxREQ send wait state */ +#define SCF_TX_ST_TXREQ_SEND_WAIT 0x0012 + /* (SC0) Send TxREQ, TxACK recv wait state */ +#define SCF_TX_ST_TXACK_RECV_WAIT 0x0020 + /* (SC1) Send TxREQ, TxEND recv wait state */ +#define SCF_TX_ST_TXEND_RECV_WAIT 0x0021 + +/* + * DSCP Rx discriptor status (scf_dscp_dsc_t : status) + */ + /* (RA0) Idle state */ +#define SCF_RX_ST_IDLE 0x0000 + /* (RB0) Recv RxREQ, RxACK send wait state */ +#define SCF_RX_ST_RXACK_SEND_WAIT 0x0010 + /* (RB1) Recv RxREQ, SRAM trans wait state */ +#define SCF_RX_ST_SRAM_TRANS_WAIT 0x0011 + +#ifdef _SCF_SP_SIDE + /* (RB2) Recv RxREQ, SRAM comp wait state */ +#define SCF_RX_ST_SRAM_COMP_WAIT 0x0012 +#endif /* _SCF_SP_SIDE */ + + /* (RB3) Recv RxREQ, RxEND send wait state */ +#define SCF_RX_ST_RXEND_SEND_WAIT 0x0013 + +/* + * DSC controlflag (scf_dscreg_t : c_flag) + */ +#define DSC_FLAG_DEFAULT 0x004c /* Default flag */ + /* emergency=0, interrupt=1, first=1, last=0 */ +/* + * DSC controlflag (scf_dscreg_t : id) + */ +#define DSC_CNTL_MASK_ID 0x0f /* Mask id */ + +#define DSC_CNTL_DSCP 0x0 /* DSCP mailbox interface */ +#define DSC_CNTL_DKMD 0x1 /* DKMD mailbox interface */ +#define DSC_CNTL_LOCAL 0xe /* Local interface */ +#define DSC_CNTL_POST 0xf /* Post diag interface (not use) */ + +/* + * DSC controlflag (scf_dscreg_t : code) + */ +#define DSC_CNTL_MASK_CODE 0x0f /* Mask code */ + +#define DSC_CNTL_DATA_REQ 0x0 /* DATA REQ */ +#define DSC_CNTL_INIT_REQ 0x1 /* INIT_REQ */ +#define DSC_CNTL_FINI_REQ 0x2 /* FINI_REQ */ +#define DSC_CNTL_FLUSH_REQ 0x3 /* FLUSH_REQ */ +#define DSC_CNTL_CONN_CHK 0xf /* CONN_CHK */ + +/* + * DSC controlflag (scf_dscreg_t : code) id = DSC_CNTL_LOCAL + */ +#define DSC_CNTL_DSCP_PATH 0x0 /* DSCP_PATH */ + +/* + * DSC controlflag (scf_dscreg_t : status) + */ +#define DSC_STATUS_NORMAL 0x00 /* Normal end */ +#define DSC_STATUS_BUF_BUSY 0x01 /* Buffer busy */ +#define DSC_STATUS_INTERFACE 0x03 /* Interface error */ +#define DSC_STATUS_CONN_NAK 0x04 /* Connection refusal */ +#define DSC_STATUS_E_NOT_SUPPORT 0x08 /* Not support */ +#define DSC_STATUS_E_PARAM 0x09 /* Parameter error */ +#define DSC_STATUS_E_SEQUENCE 0x0d /* Sequence error */ + +/* + * DSC controlflag (scf_dscreg_t : offset) + */ +#define DSC_OFFSET_NOTHING 0xffff /* DSC offset nothing value */ +#define DSC_OFFSET_CONVERT 16 /* DSC offset convert size */ + +/* + * scf_dscp_sram_get() return value + */ +#define TX_SRAM_GET_ERROR 0xffff /* Tx SRAM get error value */ + +/* + * Main status change macro + */ +#define SCF_SET_STATUS(p, st) \ + p->old_status = p->status; \ + p->status = st; \ + SCFDBGMSG2(SCF_DBGFLAG_DSCP, \ + "main status change = 0x%04x 0x%04x", \ + p->status, p->old_status) +/* + * TxDSC/RxDSC status change macro + */ +#define SCF_SET_DSC_STATUS(p, st) \ + p->old_status = p->status; \ + p->status = st; \ + SCFDBGMSG2(SCF_DBGFLAG_DSCP, \ + "DSC status change = 0x%04x 0x%04x", \ + p->status, p->old_status) + +/* + * Use scf_dscp_tx_mat_notice() code + */ +#define TxEND (uint8_t)0x80 /* TxEND */ +#define TxREL_BUSY (uint8_t)0xf0 /* Relese busy */ + +/* + * Use scf_dscp_rx_mat_notice() code + */ +#define RxREQ (uint8_t)0x80 /* RxREQ */ +#define RxDATA (uint8_t)0xf0 /* RxDATA */ + +#ifdef __cplusplus +} +#endif + +#endif /* _SCFDSCP_H */ diff --git a/usr/src/uts/sun4u/opl/sys/scfd/scfdscpif.h b/usr/src/uts/sun4u/opl/sys/scfd/scfdscpif.h new file mode 100644 index 0000000000..713555dde1 --- /dev/null +++ b/usr/src/uts/sun4u/opl/sys/scfd/scfdscpif.h @@ -0,0 +1,104 @@ +/* + * 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 + */ +/* + * All Rights Reserved, Copyright (c) FUJITSU LIMITED 2005 + */ + +#ifndef _SCFDSCPIF_H +#define _SCFDSCPIF_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef uint32_t mkey_t; /* Data type for mailbox key */ +typedef uint32_t target_id_t; /* Target ID specifying the peer */ + +/* + * Mailbox event types are defined as below. + */ +typedef enum { + SCF_MB_CONN_OK, /* Connection OK event */ + SCF_MB_MSG_DATA, /* A new message has received */ + SCF_MB_SPACE, /* Mailbox has space */ + SCF_MB_DISC_ERROR /* Disconnect error */ +} scf_event_t; + +#define SCF_EVENT_PRI DDI_SOFTINT_LOW /* Event handler priority */ + +/* + * A scatter/gather data structure used for sending/receiving mailbox + * messages. + */ +typedef struct mscat_gath { + caddr_t msc_dptr; /* pointer to the data buffer */ + uint32_t msc_len; /* Length of data in the data buffer */ +} mscat_gath_t; + + +/* + * Mailbox Flush types. + */ +typedef enum { + MB_FLUSH_SEND = 0x01, /* Flush all messages on the send side */ + MB_FLUSH_RECEIVE, /* Flush all messages on the recieve side */ + MB_FLUSH_ALL /* Flush messages on the both sides */ +} mflush_type_t; + +int scf_mb_init(target_id_t target_id, mkey_t mkey, + void (*event_handler)(scf_event_t mevent, void *arg), void *arg); + +int scf_mb_fini(target_id_t target_id, mkey_t mkey); + +int scf_mb_putmsg(target_id_t target_id, mkey_t mkey, uint32_t data_len, + uint32_t num_sg, mscat_gath_t *sgp, clock_t timeout); + +int scf_mb_canget(target_id_t target_id, mkey_t mkey, uint32_t *data_lenp); + +int scf_mb_getmsg(target_id_t target_id, mkey_t mkey, uint32_t data_len, + uint32_t num_sg, mscat_gath_t *sgp, clock_t timeout); + +int scf_mb_flush(target_id_t target_id, uint32_t key, mflush_type_t flush_type); + +int scf_mb_ctrl(target_id_t target_id, uint32_t key, uint32_t op, void *arg); + + +/* + * The following are the operations defined for scf_mb_ctrl(). + */ + +/* + * Return the maximum message length which could be received/transmitted + * on the specified mailbox. The value is returned via the argument(arg), + * which will be treated as a pointer to an uint32_t. + */ +#define SCF_MBOP_MAXMSGSIZE 0x00000001 + +#define DSCP_KEY ('D' << 24 | 'S' << 16 | 'C' << 8 | 'P') +#define DKMD_KEY ('D' << 24 | 'K' << 16 | 'M' << 8 | 'D') + +#ifdef __cplusplus +} +#endif + +#endif /* _SCFDSCPIF_H */ diff --git a/usr/src/uts/sun4u/opl/sys/scfd/scfio32.h b/usr/src/uts/sun4u/opl/sys/scfd/scfio32.h new file mode 100644 index 0000000000..16483f2bab --- /dev/null +++ b/usr/src/uts/sun4u/opl/sys/scfd/scfio32.h @@ -0,0 +1,68 @@ +/* + * 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 + */ +/* + * All Rights Reserved, Copyright (c) FUJITSU LIMITED 2006 + */ + +#ifndef _SCFIO32_H +#define _SCFIO32_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +#include <sys/types32.h> + +/* SCFIOCWRLCD 32bit */ +typedef struct scfwrlcd32 { + int lcd_type; + int length; + caddr32_t string; +} scfwrlcd32_t; + + +/* SCFIOCGETREPORT 32bit */ +typedef struct scfreport32 { + int flag; + unsigned int rci_addr; + unsigned char report_sense[4]; + time32_t timestamp; +} scfreport32_t; + + +/* SCFIOCGETEVENT 32bit */ +typedef struct scfevent32 { + int flag; + unsigned int rci_addr; + unsigned char code; + unsigned char size; + unsigned char rsv[2]; + unsigned char event_sense[24]; + time32_t timestamp; +} scfevent32_t; + +#ifdef __cplusplus +} +#endif + +#endif /* _SCFIO32_H */ diff --git a/usr/src/uts/sun4u/opl/sys/scfd/scfkstat.h b/usr/src/uts/sun4u/opl/sys/scfd/scfkstat.h new file mode 100644 index 0000000000..a3b4a1d731 --- /dev/null +++ b/usr/src/uts/sun4u/opl/sys/scfd/scfkstat.h @@ -0,0 +1,102 @@ +/* + * 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 + */ +/* + * All Rights Reserved, Copyright (c) FUJITSU LIMITED 2006 + */ + +#ifndef _SCFKSTAT_H +#define _SCFKSTAT_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * kstat_create(9F) ID parameter + * module = "scfd" + * class = "misc" + */ +/* name = "??" */ +#define SCF_SYSTEM_KSTAT_NAME "scf" + +/* + * kstat_named_init(9F) ID parameter + */ +/* name == "scf" */ +#define SCF_STATUS_KSTAT_NAMED "status" +#define SCF_BOOT_MODE_KSTAT_NAMED "boot_mode" +#define SCF_SECURE_MODE_KSTAT_NAMED "secure_mode" +#define SCF_EVENT_KSTAT_NAMED "event" +#define SCF_ALIVE_KSTAT_NAMED "alive" + +/* + * "scf" KSTAT_TYPE_NAMED item + */ +/* named == "status" */ +#define SCF_STAT_STATUS_OFFLINE 0 +#define SCF_STAT_STATUS_ONLINE 1 + +/* named == "boot_mode" */ +#define SCF_STAT_MODE_OBP_STOP 0 +#define SCF_STAT_MODE_AUTO_BOOT 1 + +/* named == "secure_mode" */ +#define SCF_STAT_MODE_UNLOCK 0 +#define SCF_STAT_MODE_LOCK 1 + +/* named == "watch" */ +#define SCF_STAT_ALIVE_OFF 0 +#define SCF_STAT_ALIVE_ON 1 + + +/* + * SCF driver kstat entry point + */ +/* from scf_attach() */ +void scf_kstat_init(); /* DDI_ATTACH */ + +/* from scf_detach() */ +void scf_kstat_fini(); /* DDI_DETACH */ + +/* + * private variables for kstat routine + */ +typedef struct scf_kstat_private { + /* kstat_t */ + kstat_t *ksp_scf; +} scf_kstat_private_t; + +/* "scf" */ +#define SCF_KSTAT_SYS_NAMED_STATUS 0 +#define SCF_KSTAT_SYS_NAMED_BOOT_MODE 1 +#define SCF_KSTAT_SYS_NAMED_SECURE_MODE 2 +#define SCF_KSTAT_SYS_NAMED_EVENT 3 +#define SCF_KSTAT_SYS_NAMED_ALIVE 4 + +#define SCF_KSTAT_SYS_NAMED_NDATA 5 + +#ifdef __cplusplus +} +#endif + +#endif /* _SCFKSTAT_H */ diff --git a/usr/src/uts/sun4u/opl/sys/scfd/scfostoescf.h b/usr/src/uts/sun4u/opl/sys/scfd/scfostoescf.h new file mode 100644 index 0000000000..0c49a17147 --- /dev/null +++ b/usr/src/uts/sun4u/opl/sys/scfd/scfostoescf.h @@ -0,0 +1,54 @@ +/* + * 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 + */ +/* + * All Rights Reserved, Copyright (c) FUJITSU LIMITED 2006 + */ + +#ifndef _SCFOSTOESCF_H +#define _SCFOSTOESCF_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +/* OS to ESCF key */ +#define KEY_ESCF ('E' << 24 | 'S' << 16 | 'C' << 8 | 'F') + + + +/* + * External function + */ + +extern int scf_service_putinfo(uint32_t, uint8_t, uint32_t, uint32_t, void *); +extern int scf_service_getinfo(uint32_t, uint8_t, uint32_t, uint32_t *, void *); + +#define SUB_OS_SEND_PRE_FMEMA 0x10 +#define SUB_OS_SEND_CANCEL_FMEMA 0x15 +#define SUB_OS_SEND_COMPLETE_FMEMA 0x43 + +#ifdef __cplusplus +} +#endif + +#endif /* _SCFOSTOESCF_H */ diff --git a/usr/src/uts/sun4u/opl/sys/scfd/scfparam.h b/usr/src/uts/sun4u/opl/sys/scfd/scfparam.h new file mode 100644 index 0000000000..b5f1dd7bdd --- /dev/null +++ b/usr/src/uts/sun4u/opl/sys/scfd/scfparam.h @@ -0,0 +1,158 @@ +/* + * 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 + */ +/* + * All Rights Reserved, Copyright (c) FUJITSU LIMITED 2006 + */ + +#ifndef _SCFPARAM_H +#define _SCFPARAM_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +#include <sys/scfd/scfsys.h> +#include <sys/scfd/scfostoescf.h> + +/* + * Common table + */ +extern scf_comtbl_t scf_comtbl; /* SCF driver common table */ +extern void *scfstate; /* root of soft state */ +extern char *scf_driver_name; /* SCF driver name */ + +/* + * SCF driver control mode + */ +extern uint_t scf_halt_proc_mode; /* SCFHALT after processing mode */ +extern uint_t scf_last_detach_mode; /* Last detach mode */ + +/* + * SRAM trace date size + */ +extern uint_t scf_sram_trace_data_size; /* Get SRAM trace data size */ +extern uint_t scf_trace_rxdata_size; /* Rx data trace size */ + +/* + * Wait timer value (Micro-second) + */ +extern uint_t scf_rdctrl_sense_wait; + /* SCFIOCRDCTRL wait timer value (60s) */ + +/* + * Wait timer value + */ +extern uint_t scf_buf_ful_rtime; + /* Buff full wait retry timer value (500ms) */ +extern uint_t scf_rci_busy_rtime; + /* RCI busy wait retry timer value (3s) */ + +/* + * Re-try counter + */ +extern uint_t scf_buf_ful_rcnt; /* Buff full retry counter */ +extern uint_t scf_rci_busy_rcnt; /* RCI busy retry counter */ +extern uint_t scf_tesum_rcnt; /* Tx sum retry counter */ +extern uint_t scf_resum_rcnt; /* Rx sum retry counter */ +extern uint_t scf_cmd_to_rcnt; /* Command to retry counter */ +extern uint_t scf_devbusy_wait_rcnt; /* Command device busy retry counter */ +extern uint_t scf_online_wait_rcnt; /* SCF online retry counter */ +extern uint_t scf_path_change_max; /* SCF path change retry counter */ + +/* + * Max value + */ +extern uint_t scf_report_sense_pool_max; /* Report sense max */ +extern uint_t scf_getevent_pool_max; /* SCFIOCGETEVENT max */ +extern uint_t scf_rci_max; /* RCI device max */ +extern uint_t scf_rxbuff_max_size; /* SCF command data division max size */ + +/* + * Poff factor (reported on shutdown start) + */ +unsigned char scf_poff_factor[2][3]; +#define SCF_POFF_FACTOR_NORMAL 0 +#define SCF_POFF_FACTOR_PFAIL 1 + +/* + * Alive check parameter + */ +extern uchar_t scf_alive_watch_code; /* Watch code for SCF driver */ +extern uchar_t scf_alive_phase_code; /* Watch phase code */ +extern uchar_t scf_alive_interval_time; /* interval time */ +extern uchar_t scf_alive_monitor_time; /* monitor timeout */ +extern ushort_t scf_alive_panic_time; /* panic timeout */ + +extern uchar_t scf_acr_phase_code; /* Alive check register phase code */ + +/* + * FMEMA interface + */ +extern caddr_t scf_avail_cmd_reg_vaddr; /* SCF Command register address */ + +/* + * Send break interface + */ +extern int scf_dm_secure_mode; /* secure mode */ + +/* + * ioctl control value and flag + */ +extern int scf_save_hac_flag; /* Host address disp flag */ +extern scfhac_t scf_save_hac; /* Host address disp save */ + +/* + * Register read sync value + */ +extern uint8_t scf_rs8; +extern uint16_t scf_rs16; +extern uint32_t scf_rs32; + +/* + * Panic value + */ +extern uint_t scf_panic_reported; /* Panic report after */ +extern uint_t scf_panic_report_maxretry; /* Same as busy_maxretry */ +extern uint_t scf_cmdend_wait_time_panic; + /* SCF command end wait timer value (1s) */ +extern uint_t scf_cmdend_wait_rcnt_panic; /* SCF command end retry counter */ + +extern uint_t scf_panic_exec_wait_time; /* Panic wait timer value (100ms) */ +extern uint_t scf_panic_exec_flag; /* Panic exec flag */ +extern uint_t scf_panic_exec_flag2; /* Panic exec flag (report send) */ + +/* + * Panic trace + */ +extern ushort_t scf_panic_trc_w_off; /* Panic trcae next write offset */ +extern uint16_t scf_panic_trc_command; /* Panic SCF command register memo */ +extern uint16_t scf_panic_trc_status; /* Panic SCF status register memo */ +extern ushort_t scf_panic_trc[16]; /* Panic trace area */ +#define SCF_PANIC_TRACE(x) \ + (scf_panic_trc[scf_panic_trc_w_off++ & 0x000f] = (ushort_t)x) + +#ifdef __cplusplus +} +#endif + +#endif /* _SCFPARAM_H */ diff --git a/usr/src/uts/sun4u/opl/sys/scfd/scfreg.h b/usr/src/uts/sun4u/opl/sys/scfd/scfreg.h new file mode 100644 index 0000000000..5d5924d03b --- /dev/null +++ b/usr/src/uts/sun4u/opl/sys/scfd/scfreg.h @@ -0,0 +1,581 @@ +/* + * 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 + */ +/* + * All Rights Reserved, Copyright (c) FUJITSU LIMITED 2006 + */ + +#ifndef _SCFREG_H +#define _SCFREG_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * register map count + */ +#define SCF_REGMAP_COUNT 5 /* register map cnt */ + +/* + * register and SRAM max size + */ +#define SRAM_MAX_DSCP 0x00010000 /* SCF system SRAM max size */ +#define SRAM_MAX_SYSTEM 0x00010000 /* SCF DSCP SRAM max size */ +#define SRAM_MAX_INTERFACE 0x00060000 /* SCF interface max size */ +#define SRAM_MAX_DRVDRVE 0x00001000 /* SCF SRAM driver trac */ + +/* + * SCF registers + */ +typedef struct scf_regs { + uint16_t COMMAND; /* SCF command register */ + uint8_t rsv002[2]; /* reserved */ + uint16_t STATUS; /* SCF status register */ + uint8_t rsv006[2]; /* reserved */ + uint8_t VERSION; /* SCF version register */ + uint8_t rsv009[3]; /* reserved */ + uint8_t rsv00c[4]; /* reserved */ + + uint32_t TDATA0; /* SCF Tx DATA0 register */ + uint32_t TDATA1; /* SCF Tx DATA1 register */ + uint32_t TDATA2; /* SCF Tx DATA2 register */ + uint32_t TDATA3; /* SCF Tx DATA3 register */ + + uint32_t RDATA0; /* SCF Rx DATA0 register */ + uint32_t RDATA1; /* SCF Rx DATA1 register */ + uint32_t RDATA2; /* SCF Rx DATA2 register */ + uint32_t RDATA3; /* SCF Rx DATA3 register */ + + uint8_t rsv030[16]; /* reserved */ + uint8_t rsv040[2]; /* reserved */ + uint8_t COMMAND_ExR; /* SCF command extended register */ + uint8_t rsv043; /* reserved */ + uint8_t FIRMREQ1; /* Firmware request register1 */ + uint8_t FIRMREQ0; /* Firmware request register0 */ + uint8_t rsv046[2]; /* reserved */ + uint8_t ACR; /* Alive check register */ + uint8_t ATR; /* Alive timer register */ + uint8_t rsv04a[6]; /* reserved */ + + uint8_t rsv050[4]; /* reserved */ + uint32_t STATUS_ExR; /* SCFI status extended register */ + uint8_t rsv058[8]; /* reserved */ + uint8_t rsv060[160]; /* reserved */ + + uint8_t DCR; /* DSCP buffer control register */ + uint8_t DSR; /* DSCP buffer status register */ + uint8_t rsv102[14]; /* reserved */ + + uint16_t TxDCR_C_FLAG; /* DSCP Tx DSC control register */ + uint16_t TxDCR_OFFSET; /* DSCP Tx DSC control register */ + uint32_t TxDCR_LENGTH; /* DSCP Tx DSC control register */ + uint16_t TxDSR_C_FLAG; /* DSCP Tx DSC status register */ + uint16_t TxDSR_OFFSET; /* DSCP Tx DSC status register */ + uint8_t rsv11c[4]; /* reserved */ + + uint16_t RxDCR_C_FLAG; /* DSCP Rx DSC control register */ + uint16_t RxDCR_OFFSET; /* DSCP Rx DSC control register */ + uint32_t RxDCR_LENGTH; /* DSCP Rx DSC control register */ + uint16_t RxDSR_C_FLAG; /* DSCP Rx DSC status register */ + uint16_t RxDSR_OFFSET; /* DSCP Rx DSC status register */ + uint8_t rsv12c[4]; /* reserved */ +} scf_regs_t; + +/* + * SCF control registers + */ +typedef struct scf_regs_c { + uint16_t CONTROL; /* SCF Control register */ + uint8_t rsv02[2]; /* reserved */ + uint16_t INT_ST; /* SCF Interrupt Status register */ + uint8_t rsv06[2]; /* reserved */ +} scf_regs_c_t; + +/* + * System buffer (SRAM) + */ +typedef struct scf_sys_sram { + uint8_t DATA[SRAM_MAX_SYSTEM]; /* System Tx/Rx buffer */ +} scf_sys_sram_t; + +/* + * DSCP buffer (SRAM) + */ +typedef struct scf_dscp_sram { + uint8_t DATA[SRAM_MAX_DSCP]; /* DSCP Tx/Rx buffer */ +} scf_dscp_sram_t; + +/* + * Interface buffer hedder (SRAM) + */ +typedef struct scf_interface { + uint32_t other1[0x40 / 4]; /* other area */ + uint32_t DRVTRC_OFFSET; /* SCF driver trace offset */ + uint32_t DRVTRC_SIZE; /* SCF driver trace size */ + uint32_t other2[0xa8 / 4]; /* other area */ +} scf_interface_t; + +/* + * SCF driver trace table + */ +#define DRV_ID_SIZE 16 + +typedef struct scf_if_drvtrc { + uint8_t DRV_ID[DRV_ID_SIZE]; /* driver ID */ + uint32_t DATA_TOP; /* trace data top offset */ + uint32_t DATA_LAST; /* trace data last offset */ + uint32_t DATA_WRITE; /* trace data write offset */ + uint8_t rsv01c[4]; /* reserved */ +} scf_if_drvtrc_t; + +/* + * SRAM driver trace entry + */ +typedef struct scf_drvtrc_ent { + uint8_t LOG_ID; /* log ID */ + uint8_t LOG_TIME[3]; /* log time */ + uint8_t INFO[12]; /* log info */ +} scf_drvtrc_ent_t; + +/* + * SRAM trace log ID + */ +#define DTC_CMD 0x01 /* SCF command start */ +#define DTC_INT 0x02 /* SCF interrupt */ +#define DTC_SENDDATA 0x03 /* SCF send command data */ +#define DTC_RECVDATA 0x04 /* SCF recv command data */ +#define DTC_SENDDATA_SRAM 0x05 /* SCF send command data for SRAM */ +#define DTC_RECVDATA_SRAM 0x06 /* SCF recv command data for SRAM */ +#define DTC_CMDTO 0x11 /* SCF command timeout */ +#define DTC_CMDBUSYTO 0x12 /* SCF command busy timeout */ +#define DTC_ONLINETO 0x13 /* SCF online timeout */ +#define DTC_ERRRTN 0x20 /* SCF command retuen error */ +#define DTC_RCI_BUF_FUL 0x21 /* SCF command return for buff full */ +#define DTC_RCI_BUSY 0x22 /* SCF command return for rci busy */ +#define DTC_INTERFACE 0x23 /* SCF command return for */ + /* interface error */ +#define DTC_E_NOT_SUPPORT 0x28 /* SCF command return for */ + /* not support */ +#define DTC_E_PARAM 0x29 /* SCF command return for */ + /* parameter error */ +#define DTC_E_SCFC_PATH 0x2a /* SCF command return for */ + /* SCFI path error */ +#define DTC_E_RCI_ACCESS 0x2b /* SCF command return for */ + /* RCI access error */ +#define DTC_E_SEQUENCE 0x2d /* SCF command return for */ + /* sequence error */ +#define DTC_RSUMERR 0x31 /* SCF command receive sum error */ +#define DTC_ONLINE 0x32 /* SCF offline start */ +#define DTC_OFFLINE 0x33 /* SCF offline start */ +#define DTC_DSCP_TXREQ 0x41 /* DSCP TxREQ request */ +#define DTC_DSCP_RXACK 0x42 /* DSCP RxACK request */ +#define DTC_DSCP_RXEND 0x43 /* DSCP RxEND request */ +#define DTC_DSCP_RXREQ 0x44 /* DSCP RxREQ interrupt */ +#define DTC_DSCP_TXACK 0x45 /* DSCP TxACK interrupt */ +#define DTC_DSCP_TXEND 0x46 /* DSCP TxEND interrupt */ +#define DTC_DSCP_SENDDATA 0x47 /* DSCP send data */ +#define DTC_DSCP_RECVDATA 0x48 /* DSCP recv data */ +#define DTC_DSCP_ACKTO 0x51 /* DSCP ACK timeout */ +#define DTC_DSCP_ENDTO 0x52 /* DSCP END timeout */ + +#define DTC_MASK_HIGH 0xf0 /* mask high */ + +/* SRAM trace define */ +#define SCF_SRAM_TRACE(a, b) scf_sram_trace(a, b) + +#define SCF_SET_SRAM_DATA1_2(a, b, c) \ + statep->memo_scf_drvtrc.INFO[a] = (uint8_t)(b); \ + statep->memo_scf_drvtrc.INFO[a + 1] = (uint8_t)(c) + +#define SCF_SET_SRAM_DATA2_1(a, b) \ + statep->memo_scf_drvtrc.INFO[a] = (uint8_t)(b >> 8); \ + statep->memo_scf_drvtrc.INFO[a + 1] = (uint8_t)(b) + +#define SCF_SET_SRAM_DATA2_2(a, b, c) \ + statep->memo_scf_drvtrc.INFO[a] = (uint8_t)(b >> 8); \ + statep->memo_scf_drvtrc.INFO[a + 1] = (uint8_t)(b); \ + statep->memo_scf_drvtrc.INFO[a + 2] = (uint8_t)(c >> 8); \ + statep->memo_scf_drvtrc.INFO[a + 3] = (uint8_t)(c) + +#define SCF_SET_SRAM_DATA4_1(a, b) \ + statep->memo_scf_drvtrc.INFO[a] = (uint8_t)(b >> 24); \ + statep->memo_scf_drvtrc.INFO[a + 1] = (uint8_t)(b >> 16); \ + statep->memo_scf_drvtrc.INFO[a + 2] = (uint8_t)(b >> 8); \ + statep->memo_scf_drvtrc.INFO[a + 3] = (uint8_t)(b) + +#define SCF_SET_SRAM_DATA4_3(a, b, c, d) \ + statep->memo_scf_drvtrc.INFO[a] = (uint8_t)(b >> 24); \ + statep->memo_scf_drvtrc.INFO[a + 1] = (uint8_t)(b >> 16); \ + statep->memo_scf_drvtrc.INFO[a + 2] = (uint8_t)(b >> 8); \ + statep->memo_scf_drvtrc.INFO[a + 3] = (uint8_t)(b); \ + statep->memo_scf_drvtrc.INFO[a + 4] = (uint8_t)(c >> 24); \ + statep->memo_scf_drvtrc.INFO[a + 5] = (uint8_t)(c >> 16); \ + statep->memo_scf_drvtrc.INFO[a + 6] = (uint8_t)(c >> 8); \ + statep->memo_scf_drvtrc.INFO[a + 7] = (uint8_t)(c); \ + statep->memo_scf_drvtrc.INFO[a + 8] = (uint8_t)(d >> 24); \ + statep->memo_scf_drvtrc.INFO[a + 9] = (uint8_t)(d >> 16); \ + statep->memo_scf_drvtrc.INFO[a + 10] = (uint8_t)(d >> 8); \ + statep->memo_scf_drvtrc.INFO[a + 11] = (uint8_t)(d) + +/* + * SCF registers define + */ + +/* COMMAND : SCF command register define */ +#define COMMAND_BUSY 0x8000 /* Command interface busy */ +#define COMMAND_SUBCODE 0x7f00 /* Command subcode */ +#define COMMAND_CODE 0x00ff /* Command code */ + +#define CMD_SCFI_PATH 0x10 /* SCF path change */ +#define SUB_CMD_PATH 0x00 /* Command path change */ + +#define CMD_PATH_TYPE_SCFD 0x01 /* Command path type(scfd) */ + +#define CMD_ALIVE_CHECK 0x20 /* Alive check */ +#define SUB_ALIVE_START 0x30 /* Start */ +#define SUB_ALIVE_STOP 0x50 /* Stop */ + +#define CMD_REPORT 0x21 /* Report */ +#define SUB_SYSTEM_STATUS_RPT 0x40 /* System status */ +#define SUB_SYSTEM_STATUS_RPT_NOPATH 0x51 + /* System status (no path check) */ + +#define CMD_PHASE 0x22 /* Domain phase print */ +#define SUB_PHASE_PRINT 0x10 /* Phase print */ + +#define CMD_PART_POW_CTR 0x30 /* power control */ +#define SUB_PON 0x01 /* Power on */ +#define SUB_POFF 0x02 /* Power off */ +#define SUB_FPOFF 0x13 /* Forced power off */ +#define SUB_RESET 0x04 /* Power reset */ +#define SUB_POFFID 0x19 /* Power off factor */ + +#define CMD_SYS_AUTOPOW 0x35 /* System automatic power control */ +#define SUB_SYS_AUTO_ONOFF_SET 0x01 /* on/off time set */ +#define SUB_SYS_AUTO_ONOFF_DISP 0x02 /* on/off time disp */ +#define SUB_SYS_AUTO_ONOFF_CLRAR 0x04 /* on/off time clear */ +#define SUB_FORCED_POFF_SET 0x08 /* Forced power off time set */ +#define SUB_PRESET_MODE_DISP 0x10 /* Power resume mode disp */ +#define SUB_PRESET_MODE_SET 0x20 /* Power resume mode set */ + +#define CMD_RCI_CTL 0x40 /* RCI control */ +#define SUB_HOSTADDR_DISP2 0xff /* Host address disp 2 */ +#define SUB_DEVICE_LIST 0x0a /* Device list disp */ +#define SUB_PANIC 0x03 /* Panic request */ + +#define CMD_INT_REASON 0x50 /* Event information */ +#define SUB_INT_REASON_DISP 0x10 /* Factor detail disp */ +#define SUB_INT_REASON_RETRY 0x01 /* Factor detail re-disp */ + +#define CMD_FILE_DOWNLOAD 0x74 /* File dounload or upload */ + +#define CMD_DOMAIN_INFO 0x81 /* Domain information */ +#define SUB_OPTION_DISP 0x04 /* Option disp */ +#define SUB_PCI_HP_CONFIG 0x52 /* PCI configuration set */ +#define SUB_PCI_DISP 0x54 /* PCI configuration disp */ +#define SUB_PHP_RESET 0x61 /* PHP Reset */ +#define SUB_DISK_LED_DISP 0x70 /* DISK LED disp */ +#define SUB_DISK_LED_ON 0x73 /* DISK LED on */ +#define SUB_DISK_LED_BLINK 0x75 /* DISK LED blink */ +#define SUB_DISK_LED_OFF 0x76 /* DISK LED off */ + +#define CMD_DR 0xa2 /* DR function */ + +#define CMD_ERRLOG 0xb0 /* Error log control */ +#define SUB_ERRLOG_SET_MADMIN 0x26 /* Log set madmin */ + +#define CMD_REMCS_SPT 0xc3 /* REMCS command */ + +#define CMD_SPARE 0xc4 /* SPARE command */ + +#define CMD_OS_XSCF_CTL 0xc5 /* OS to ESCF */ + +/* STATUS : SCF status register define */ +#define STATUS_SCF_READY 0x8000 /* bit15: SCF READY */ +#define STATUS_SHUTDOWN 0x4000 /* bit14: SHUTDOWN */ +#define STATUS_POFF 0x2000 /* bit13: POFF */ +#define STATUS_EVENT 0x1000 /* bit12: EVENT */ +#define STATUS_TIMER_ADJUST 0x0800 /* bit11: TIMER ADJUST */ +#define STATUS_ALIVE 0x0400 /* bit10: ALIVE (Not use) */ +#define STATUS_MODE_CHANGED 0x0200 /* bit 9: MODE CHANGED */ +#define STATUS_U_PARITY 0x0100 /* bit 8: U Parity (Not use */ +#define STATUS_CMD_RTN_CODE 0x00f0 /* bit 7-4: CMD return code */ +#define STATUS_SECURE_MODE 0x0008 /* bit 3: secure mode status */ +#define STATUS_BOOT_MODE 0x0004 /* bit 2: boot mode status */ +#define STATUS_CMD_COMPLETE 0x0002 /* bit 1: Command complete */ +#define STATUS_L_PARITY 0x0001 /* bit 0: L Parity (Not use) */ + +/* secure mode status */ +#define STATUS_MODE_UNLOCK 0x0000 /* UNLOCK */ +#define STATUS_MODE_LOCK 0x0008 /* LOCK */ + +/* boot mode status */ +#define STATUS_MODE_OBP_STOP 0x0000 /* OBP stop */ +#define STATUS_MODE_AUTO_BOOT 0x0004 /* Auto boot */ + +/* STATUS_CMD_RTN_CODE : Command return value */ +#define NORMAL_END 0x00 /* Normal end */ +#define BUF_FUL 0x01 /* Buff full */ +#define RCI_BUSY 0x02 /* RCI busy */ +#define INTERFACE 0x03 /* Parity/Sum error */ + +#define E_NOT_SUPPORT 0x08 /* Not support */ +#define E_PARAM 0x09 /* Parameter error */ +#define E_SCFC_NOPATH 0x0a /* No SCFC path */ +#define E_RCI_ACCESS 0x0b /* RCI access error */ +#define E_HARD 0x0c /* Hard error */ +#define RCI_NS 0x0f /* Not support RCI */ + +/* COMMAND_ExR : SCF command extended register define */ +#define COMMAND_ExR_BUSY 0x80 /* Command busy */ +#define COMMAND_ExR_RETRY 0x40 /* Command retry */ + +/* STATUS_ExR : SCF status extended register define */ +#define STATUS_POWER_FAILURE 0x80000000 /* Power failure */ +#define STATUS_SCF_STATUS_CHANGE 0x40000000 /* SCF status change */ +#define STATUS_SCF_STATUS 0x20000000 /* SCF status */ +#define STATUS_SCF_NO 0x10000000 /* Offline SCF No. */ +#define STATUS_STATUS_DETAIL 0x0000ffff /* Return code detail code */ + +#define STATUS_SCF_ONLINE 0x20000000 /* SCF status online */ +#define STATUS_SCF_OFFLINE 0x00000000 /* SCF status offline */ + +/* ACR : Alive check register define */ +#define ACR_ALIVE_INT 0x80 /* Alive Interrupt for SCF */ +#define ACR_PHASE_CODE 0x7f /* Phase code */ + +/* ATR : Alive timer register define */ +#define ATR_INTERVAL 0x07 /* Interrupt interval */ +#define ATR_INTERVAL_STOP 0x00 /* Interrupt interval stop */ +#define ATR_INTERVAL_30S 0x01 /* Interrupt interval 30 s */ +#define ATR_INTERVAL_60S 0x02 /* Interrupt interval 1 min */ +#define ATR_INTERVAL_120S 0x04 /* Interrupt interval 2 min */ + +/* DCR : DSCP Buffer Control Register */ + /* Domain to SCF data transfer request isuued */ +#define DCR_TxREQ (uint8_t)0x80 + /* SCF to domain data transfer request accepted */ +#define DCR_RxACK 0x40 + /* SCF to domain data transfer request end */ +#define DCR_RxEND 0x20 + +/* DSR : DSCP Buffer Status Register */ + /* SCF to domain data transfer request issued */ +#define DSR_RxREQ (uint8_t)0x80 + /* domain to SCF data transfer request accepted */ +#define DSR_TxACK 0x40 + /* domain to SCF data transfer request end */ +#define DSR_TxEND 0x20 + +/* Tx/Rx SUM magicnumber */ +#define SCF_MAGICNUMBER_S 0xaa /* Small Buffer SUM */ +#define SCF_MAGICNUMBER_L (uint32_t)0xaaaaaaaa /* Large Buffer SUM */ + +/* Length border conversion */ +#define SCF_LENGTH_16BYTE_CNV 0xfffffff0 /* 16byte border conversion */ + + +/* + * SCF registers define + */ + +/* CONTROL/INT_ST : SCF Control/SCF Interrupt Status register define */ + + /* SCF Path Change Interrupt enable */ +#define CONTROL_PATHCHGIE 0x8000 + /* SCF Interrupt enable */ +#define CONTROL_SCFIE 0x4000 + /* DSCP Communication Buffer Interrupt enable */ +#define CONTROL_IDBCIE 0x2000 + /* Alive Interrupt enable */ +#define CONTROL_ALIVEINE 0x1000 + /* interrupt enable */ +#define CONTROL_ENABLE \ + (CONTROL_PATHCHGIE | CONTROL_SCFIE | CONTROL_IDBCIE) + /* interrupt disable */ +#define CONTROL_DISABLE 0x0000 + + /* SCF Path Change Interrupt */ +#define INT_ST_PATHCHGIE 0x8000 + /* SCF interrupt */ +#define INT_ST_SCFINT 0x4000 + /* DSCP Communication Buffer Interrupt */ +#define INT_ST_IDBCINT 0x2000 + /* Alive Interrupt */ +#define INT_ST_ALIVEINT 0x1000 + + /* All Interrupt */ +#define INT_ST_ALL \ + (INT_ST_PATHCHGIE | INT_ST_SCFINT | INT_ST_IDBCINT | INT_ST_ALIVEINT) + +/* Machine address */ +#define SCF_CMD_SYSTEM_ADDR 0x00000000 /* Owner address */ + +/* status */ +#define REPORT_STAT_PANIC 0x01 /* panic */ +#define REPORT_STAT_SHUTDOWN_START 0x02 /* shutdown start */ +#define REPORT_STAT_SYSTEM_RUNNING 0x0a /* system running */ +#define REPORT_STAT_RCIDWN (uint8_t)0xf0 /* rci down */ + +/* POFF ID */ +#define POFF_ID_PANEL 0x00 /* panel */ +#define POFF_ID_RCI 0x20 /* RCI */ +#define POFF_ID_XSCF 0x03 /* XSCF */ +#define POFF_ID_MASK 0xf0 + +/* category type */ +#define DEV_SENSE_ATTR_OWN 0x00 /* Owner host */ +#define DEV_SENSE_ATTR_OTHER 0x01 /* Other host */ +#define DEV_SENSE_ATTR_IO 0x80 /* I/O unit */ + +/* Remote Device Control */ +#define RCI_DEVCLASS_MASK 0xfff /* mask for device class */ +#define RCI_DEVCLASS_CPU_START 0x001 /* CPU start */ +#define RCI_DEVCLASS_CPU_END 0x0ff /* CPU end */ +#define RCI_DEVCLASS_DISK_START 0x400 /* disk start */ +#define RCI_DEVCLASS_DISK_END 0x4ff /* disk end */ + +#define RMT_DEV_CLASS_START_SHIFT 16 + +/* sense */ +#define DEV_SENSE_SHUTDOWN 0x80 /* need shutdown bit */ + +#define DEV_SENSE_FANUNIT 0x01 /* fan unit error */ + +#define DEV_SENSE_PWRUNIT 0x02 /* power unit error */ + +#define DEV_SENSE_UPS 0x05 /* UPS error */ +#define DEV_SENSE_UPS_MASK 0x0f +#define DEV_SENSE_UPS_LOWBAT 0x8 /* Low Battery */ + +#define DEV_SENSE_THERMAL 0x06 /* thermal error */ + +#define DEV_SENSE_PWRSR 0x07 /* power stop/resume */ +#define DEV_SENSE_PWRSR_MASK 0x0f +#define DEV_SENSE_PWRSR_STOP 0x8 /* power stop */ + +#define DEV_SENSE_NODE 0x08 /* node error */ +#define DEV_SENSE_NODE_STCKTO 0x90 /* status check timeout */ + +#define DEV_SENSE_RCI_PATH40 0x40 /* Devive status print */ +#define DEV_SENSE_SYS_REPORT 0x60 /* system status report */ +#define DEV_SENSE_PANIC_REQ 0x61 /* panic request */ +#define DEV_SENSE_IONODESTAT 0x62 /* I/O node status */ +#define DEV_SENSE_STATUS_RPT 0x71 /* Deveice status print */ + + +/* + * SCF command send control + */ +typedef struct scf_cmd { + uint_t flag; /* buff type flag */ + uchar_t cmd; /* SCF command code */ + uchar_t subcmd; /* SCF sub command code */ + ushort_t stat0; /* Interrupt status */ + uint_t scount; /* Tx data count */ + uint_t rcount; /* Rx data count */ + uchar_t *sbuf; /* Tx buff address */ + uchar_t *rbuf; /* Rx buff address */ + uint_t rbufleng; /* recv data leng */ + ushort_t status; /* SCF status reg */ + uchar_t cexr[4]; /* Command extension info */ +} scf_cmd_t; + +/* SCF interrupt error status make */ +#define SCF_STAT0_RDATA_SUM 0xf0 /* Rx data sum error */ +#define SCF_STAT0_NOT_PATH 0xff /* Non change path */ + +/* SCF comannd buff type */ +#define SCF_USE_S_BUF 0 /* Tx : -/S Rx : - */ +#define SCF_USE_SSBUF 1 /* Tx : -/S Rx : S */ +#define SCF_USE_SLBUF 2 /* Tx : -/S Rx : L */ +#define SCF_USE_L_BUF 3 /* Tx : L Rx : - */ +#define SCF_USE_LSBUF 4 /* Tx : L Tx : S */ + +#define SCF_USE_STOP 0x7e +#define SCF_USE_START 0x7f +#define SCF_USE_SP (uint8_t)0x80 + +/* SCF command size */ +#define SCF_S_CNT_32 32 /* TxRx Small buff size */ +#define SCF_S_CNT_16 16 /* TxRx Small buff size */ +#define SCF_S_CNT_15 15 /* Small buff cnt 15byte */ +#define SCF_S_CNT_12 12 /* Small buff cnt 12byte */ +#define SCF_S_CNT_8 8 /* Small buff cnt 8byte */ + +#define SCF_L_CNT_MAX SRAM_MAX_SYSTEM + /* Command buffer max size (64Kyte) */ + +#define SCF_SBUFR_SIZE 64 /* RDCTL data size */ +#define SCF_SHORT_BUFFER_SIZE (16 * 5) /* Short bauuer size (16byte * 5) */ +#define SCF_SHORT_BUFFER_SIZE_4BYTE (SCF_SHORT_BUFFER_SIZE / 4) +#define SCF_INT_REASON_SIZE 32 /* INT_REASON size */ +#define SCF_INT_CNT_MAX (SCF_INT_REASON_SIZE * 4) + /* INT_REASON max size (128yte) */ +#define SCF_DEVLIST_MAXCNT 2 /* Device list max count */ +#define SCF_DEVLIST_ENTSIZE 8 /* Device list entry size */ + + +/* CMD_RCI_CTL SUB_RCI_PATH_4* value */ +#define SCF_RCI_PATH_PARITY 0x10 /* SUB_RCI_PATH_4* parity */ + +/* Alive check function value */ +#define SCF_ALIVE_FUNC_ON "on" /* parameter alive start */ +#define SCF_ALIVE_FUNC_OFF "off" /* parameter alive stop */ + +#define SCF_ALIVE_START 1 /* Alive check start */ +#define SCF_ALIVE_STOP 0 /* Alive check stop */ + +/* Alive check timer value (10s) */ +#define INTERVAL_TIME_MIN 0x06 /* interval time min (1min) */ +#define INTERVAL_TIME_MAX 0x3c /* cycle_time max (10min) */ +#define INTERVAL_TIME_DEF 0x0c /* cycle_time default (2min) */ +#define MONITOR_TIME_MIN 0x12 /* watch_time min (3min) */ +#define MONITOR_TIME_MAX 0xb4 /* monitor time max (30min) */ +#define MONITOR_TIME_DEF 0x24 /* monitor default (6min) */ +#define PANIC_TIME_MIN 0x00b4 /* panic time min (30min) */ +#define PANIC_TIME_MAX 0x0870 /* panic time max (360min) */ +#define PANIC_TIME_DEF 0x00b4 /* panic time default (30min) */ +#define PANIC_TIME_NONE 0x0000 /* no panic time monitor */ + +#define MONITOR_TIME_CORRECT 0x03 /* monitor time correct (30sec) */ + +#define SCF_MIN_TO_10SEC(a) a = a * 6; /* minutes to 10 seconds */ + +/* Short buffer structure */ +typedef union scf_short_buffer { + uchar_t b[SCF_SHORT_BUFFER_SIZE]; + uint_t four_bytes_access[SCF_SHORT_BUFFER_SIZE_4BYTE]; +} scf_short_buffer_t; + +/* Event information structure */ +typedef union scf_int_reason { + uchar_t b[SCF_INT_CNT_MAX]; + uint_t four_bytes_access[SCF_INT_CNT_MAX / 4]; +} scf_int_reason_t; + +#ifdef __cplusplus +} +#endif + +#endif /* _SCFREG_H */ diff --git a/usr/src/uts/sun4u/opl/sys/scfd/scfsnap.h b/usr/src/uts/sun4u/opl/sys/scfd/scfsnap.h new file mode 100644 index 0000000000..c19e94f6b6 --- /dev/null +++ b/usr/src/uts/sun4u/opl/sys/scfd/scfsnap.h @@ -0,0 +1,111 @@ +/* + * 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 + */ +/* + * All Rights Reserved, Copyright (c) FUJITSU LIMITED 2006 + */ + +#ifndef _SCFSNAP_H +#define _SCFSNAP_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * ioctl + */ +#define SCFIOCSNAP 's'<<8 + +/* + * ioctl + */ +#define SCFIOCSNAPSHOTSIZE (SCFIOCSNAP|1|0x80040000) +#define SCFIOCSNAPSHOT (SCFIOCSNAP|2|0x80040000) + +/* SCFIOCSNAPSHOTSIZE */ +typedef struct scfsnapsize { + int type; + int info; + int size; +} scfsnapsize_t; + +/* SCFIOCSNAPSHOT */ +typedef struct scfsnap_value { + char ss_name[32]; + int ss_flag; + int ss_rsv1; + int ss_size; + int ss_nextoff; +} scfsnap_value_t; +/* for ss_name field */ +#define SNAP_SCF_DRIVER_VL "scf_driver_vl" +#define SNAP_SCF_COMTBL "scf_comtbl" +#define SNAP_SCF_STATE "scf_state" +#define SNAP_SCF_TIMER_TBL "scf_timer" +#define SNAP_SCF_DSCP_COMTBL "scf_dscp_comtbl" +#define SNAP_SCF_DSCP_TXDSC "scf_dscp_txdsc" +#define SNAP_SCF_DSCP_RXDSC "scf_dscp_rxdsc" +#define SNAP_SCF_DSCP_TXSRAM "scf_dscp_txsram" +#define SNAP_SCF_DSCP_EVENT "scf_dscp_event" +#define SNAP_SCF_DSCP_RDATA "scf_dscp_rdata" +#define SNAP_REGISTER "REGISTER" +#define SNAP_SRAM "SRAM" + +/* for ss_flag field */ +#define SCF_DRIVER_64BIT 64 +#define SCF_DRIVER_32BIT 32 + +typedef struct scfsnap { + int type; + int info; + scfsnap_value_t *ss_entries; +} scfsnap_t; +/* for 32bit */ +typedef struct scfsnap32 { + int type; + int info; + caddr32_t ss_entries; +} scfsnap32_t; +/* for type field */ +#define SCFSNAPTYPE_ALL 1 +#define SCFSNAPTYPE_DRIVER 2 +#define SCFSNAPTYPE_REGISTER 3 +#define SCFSNAPTYPE_SRAM 4 + +/* for info field */ +#define SCFSNAPINFO_AUTO (-1) + +/* + * External function + */ +extern int scf_snapshotsize(intptr_t arg, int mode); +extern int scf_get_snapize(int type, int info); +extern int scf_snapshot(intptr_t arg, int mode); +extern int scf_get_snap(int type, int info, scfsnap_value_t *snap_p, + int snap_size); + +#ifdef __cplusplus +} +#endif + +#endif /* _SCFSNAP_H */ diff --git a/usr/src/uts/sun4u/opl/sys/scfd/scfstate.h b/usr/src/uts/sun4u/opl/sys/scfd/scfstate.h new file mode 100644 index 0000000000..9a7dce7ec9 --- /dev/null +++ b/usr/src/uts/sun4u/opl/sys/scfd/scfstate.h @@ -0,0 +1,197 @@ +/* + * 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 + */ +/* + * All Rights Reserved, Copyright (c) FUJITSU LIMITED 2006 + */ + +#ifndef _SCFSTATE_H +#define _SCFSTATE_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +#include <sys/scfd/scfreg.h> + +/* + * SCF driver's software state structure + */ +typedef struct scf_state { + /* SCF device infomation pointer */ + dev_info_t *dip; /* device infomation */ + + /* SCF state table address */ + struct scf_state *next; /* next state addr */ + + /* flag */ + uint_t resource_flag; /* resource allocate flag */ + uint_t scf_herr; /* Hard error flag */ + + /* Register hardware register */ + scf_regs_t *scf_regs; /* SCF register */ + scf_regs_c_t *scf_regs_c; /* SCF contorol register */ + scf_dscp_sram_t *scf_dscp_sram; /* SCF DSCP SRAM */ + scf_sys_sram_t *scf_sys_sram; /* SCF system SRAM */ + scf_interface_t *scf_interface; /* SCF interface block */ + scf_if_drvtrc_t *scf_reg_drvtrc; /* SRAM driver trace */ + + /* Register data access handle */ + ddi_acc_handle_t scf_regs_handle; /* SCF register */ + ddi_acc_handle_t scf_regs_c_handle; /* SCF contorol register */ + ddi_acc_handle_t scf_dscp_sram_handle; /* SCF DSCP SRAM */ + ddi_acc_handle_t scf_sys_sram_handle; /* SCF system SRAM */ + ddi_acc_handle_t scf_interface_handle; /* SCF interface block */ + ddi_acc_handle_t scf_reg_drvtrc_handle; /* SRAM driver trace block */ + + /* Register size */ + off_t scf_dscp_sram_len; /* SCF system SRAM */ + off_t scf_sys_sram_len; /* SCF DSCP SRAM */ + off_t scf_interface_len; /* SCF interface block */ + off_t scf_reg_drvtrc_len; /* SRAM driver trace */ + + /* error retry count */ + uint_t tesum_rcnt; /* Send sum check error */ + uint_t resum_rcnt; /* Recv sum check error */ + uint_t cmd_to_rcnt; /* Command timeout error */ + uint_t devbusy_to_rcnt; /* Command busy timeout error */ + uint_t online_to_rcnt; /* SCF online timeout error */ + + /* error counter memo */ + uint_t memo_cmd_to_cnt; /* CMD timeout counter */ + uint_t no_int_dsr_cnt; /* DSR no interrupt counter */ + uint_t fail_count; /* SCF path fail counter */ + + /* IOMP control area */ + int instance; /* instance */ + int path_status; /* IOMP path status */ + int old_path_status; /* IOMP old path status */ + + /* Register memo */ + uint16_t reg_control; /* SCF INT control */ + uint16_t reg_int_st; /* SCF INT status */ + uint16_t reg_command; /* SCF command */ + uint16_t reg_status; /* SCF status */ + uint32_t reg_tdata[4]; /* SCF Tx data */ + uint32_t reg_rdata[4]; /* SCF Rx data0 */ + uint8_t reg_command_exr; /* SCF command extended */ + uint32_t reg_status_exr; /* SCF status extended */ + uint8_t reg_acr; /* Alive check */ + uint8_t reg_atr; /* Alive timer */ + uint8_t reg_dcr; /* DSCP buffer control */ + uint8_t reg_dsr; /* DSCP buffer status */ + uint16_t reg_txdcr_c_flag; /* DSCP Tx descriptor control */ + uint16_t reg_txdcr_c_offset; /* DSCP Tx descriptor control */ + uint32_t reg_txdcr_c_length; /* DSCP Tx descriptor control */ + uint16_t reg_txdsr_c_flag; /* DSCP Tx descriptor status */ + uint16_t reg_txdsr_c_offset; /* DSCP Tx descriptor status */ + uint16_t reg_rxdcr_c_flag; /* DSCP Rx descriptor control */ + uint16_t reg_rxdcr_c_offset; /* DSCP Rx descriptor control */ + uint32_t reg_rxdcr_c_length; /* DSCP Rx descriptor control */ + uint16_t reg_rxdsr_c_flag; /* DSCP Rx descriptor status */ + uint16_t reg_rxdsr_c_offset; /* DSCP Rx descriptor status */ + + /* SRAM driver trace memo */ + uint32_t memo_DATA_TOP; /* trace data top offset */ + uint32_t memo_DATA_LAST; /* trace data last offset */ + uint32_t memo_DATA_WRITE; /* trace data write offset */ + scf_drvtrc_ent_t memo_scf_drvtrc; /* SRAM driver trace */ + + /* SCF device value */ + char pathname[256]; /* SCFC pathname */ +} scf_state_t; + +/* + * (resource_flag) macro for resource allocate flag + */ +#define S_DID_REG1 (1 << 0) +#define S_DID_REG2 (1 << 1) +#define S_DID_REG3 (1 << 2) +#define S_DID_REG4 (1 << 3) +#define S_DID_REG5 (1 << 4) +#define S_DID_REG6 (1 << 5) + +#define S_DID_INTR (1 << 8) +#define S_DID_MNODE (1 << 9) + +#define S_DID_REGENB ((uint_t)1 << 31) + +/* + * (scf_herr) hard error code + */ +#define HERR_TESUM (1 << 0) +#define HERR_RESUM (1 << 1) +#define HERR_CMD_RTO (1 << 2) +#define HERR_BUSY_RTO (1 << 3) + +#define HERR_DSCP_INTERFACE (1 << 8) +#define HERR_DSCP_ACKTO (1 << 9) +#define HERR_DSCP_ENDTO (1 << 10) + +#define HERR_EXEC ((uint_t)1 << 31) + +/* ddi_dev_regsize(), ddi_regs_map_setup register index number define */ +#define REG_INDEX_SCF 0 /* SCF register */ +#define REG_INDEX_SCFCNTL 1 /* SCF contorol register */ +#define REG_INDEX_DSCPSRAM 2 /* SCF DSCP SRAM */ +#define REG_INDEX_SYSTEMSRAM 3 /* SCF system SRAM */ +#define REG_INDEX_INTERFACE 4 /* SCF interface block(driver trace) */ + +/* + * scf_path_check()/scf_offline_check() return code + */ +#define SCF_PATH_ONLINE 0 /* SCF path exec state */ +#define SCF_PATH_OFFLINE 1 /* SCF path offline state */ +#define SCF_PATH_OFFLINE_DRV 2 /* SCF path offline-drv state */ +#define SCF_PATH_CHANGE 3 /* SCF path change state */ +#define SCF_PATH_HALT (-1) /* SCF path halt state */ + +/* + * scf_cmdbusy_check() return code + */ +#define SCF_COMMAND_READY 0 /* SCF command ready state */ +#define SCF_COMMAND_BUSY 1 /* SCF command busy state */ +#define SCF_COMMAND_BUSY_DRV 2 /* SCF command busy-drv state */ + +/* + * scf_dscp_start()/scf_dscp_stop() arg "factor" value + */ +#define FACTOR_ONLINE 0 /* Factor SCF online */ +#define FACTOR_OFFLINE 1 /* Factor SCF offline */ +#define FACTOR_PATH_CHG 2 /* Factor SCF path change */ +#define FACTOR_PATH_STOP 3 /* Factor IOMP all path stop */ +#define FACTOR_PATH_HALT 4 /* Factor SCF path halt */ + +/* path status (path_status) */ +#define PATH_STAT_ACTIVE 1 +#define PATH_STAT_STANDBY 2 +#define PATH_STAT_STOP 3 +#define PATH_STAT_FAIL 4 +#define PATH_STAT_DISCON 5 +#define PATH_STAT_ENCAP 6 +#define PATH_STAT_EMPTY 0 + +#ifdef __cplusplus +} +#endif + +#endif /* _SCFSTATE_H */ diff --git a/usr/src/uts/sun4u/opl/sys/scfd/scfsys.h b/usr/src/uts/sun4u/opl/sys/scfd/scfsys.h new file mode 100644 index 0000000000..dc0b106cdd --- /dev/null +++ b/usr/src/uts/sun4u/opl/sys/scfd/scfsys.h @@ -0,0 +1,862 @@ +/* + * 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 + */ +/* + * All Rights Reserved, Copyright (c) FUJITSU LIMITED 2006 + */ + +#ifndef _SCFSYS_H +#define _SCFSYS_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +#include <sys/scfd/opcio.h> +#include <sys/scfd/scfstate.h> +#include <sys/scfd/scftimer.h> +#include <sys/scfd/scfkstat.h> +#include <sys/scfd/scfostoescf.h> + +#ifndef TRUE +#define TRUE (1) +#endif + +#ifndef FALSE +#define FALSE (0) +#endif + +#define FLAG_ON (1) +#define FLAG_OFF (0) + +#define SCF_DRIVER_VERSION "SCF driver 1.5" +#define SCF_DRIVER_NAME "scfd" +#define SCF_DEVICE_NAME "scfc" + +/* instance number */ +#define SCF_USER_INSTANCE 200 /* instance */ + +#define SCF_MAX_INSTANCE 80 /* Max instance */ + +/* SCFHALT after processing mode define */ +#define HALTPROC_STOP 0 /* processing stop mode (default) */ +#define HALTPROC_SHUTDOWN 1 /* processing shutdown mode */ +#define HALTPROC_PANIC 2 /* processing panic mode */ + +/* + * External function + */ +extern int scf_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); +extern int scf_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); +extern void scf_resource_free_dev(scf_state_t *statep); +extern int scf_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, + void *arg, void **resultp); +extern void scf_reload_conf(scf_state_t *statep); + +extern int scf_open(dev_t *devp, int flag, int otyp, cred_t *cred_p); +extern int scf_close(dev_t dev, int flag, int otyp, cred_t *cred_p); +extern int scf_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, + cred_t *cred_p, int *rval_p); +extern int scf_ioc_reportstat(intptr_t arg, int mode, int *rval_p, + int u_mode); +extern int scf_ioc_clearlcd(intptr_t arg, int mode, int *rval_p, + int u_mode); +extern int scf_ioc_wrlcd(intptr_t arg, int mode, int *rval_p, int u_mode); +extern int scf_ioc_getdiskled(intptr_t arg, int mode, int *rval_p, + int u_mode); +extern int scf_ioc_setdiskled(intptr_t arg, int mode, int *rval_p, + int u_mode); +extern int scf_ioc_getsdownreason(intptr_t arg, int mode, int *rval_p, + int u_mode); +extern int scf_ioc_optiondisp(intptr_t arg, int mode, int *rval_p, + int u_mode); +extern int scf_ioc_getpciconfig(intptr_t arg, int mode, int *rval_p, + int u_mode); +extern int scf_ioc_hac(intptr_t arg, int mode, int *rval_p, int u_mode); +extern int scf_ioc_hstadrsinfo(intptr_t arg, int mode, int *rval_p, + int u_mode); +extern int scf_ioc_rdclistmax(intptr_t arg, int mode, int *rval_p, + int u_mode); +extern int scf_ioc_rdclistx(intptr_t arg, int mode, int *rval_p, + int u_mode); +extern int scf_ioc_rdctrl(intptr_t arg, int mode, int *rval_p, int u_mode); +extern int scf_ioc_opecall(intptr_t arg, int mode, int *rval_p, + int u_mode); +extern int scf_ioc_getreport(intptr_t arg, int mode, int *rval_p, + int u_mode); +extern int scf_ioc_rcipwr(intptr_t arg, int mode, int *rval_p, int u_mode); +extern int scf_ioc_panicreq(intptr_t arg, int mode, int *rval_p, + int u_mode); +extern int scf_ioc_panicchk(intptr_t arg, int mode, int *rval_p, + int u_mode); +extern int scf_ioc_parmset(intptr_t arg, int mode, int *rval_p, + int u_mode); +extern int scf_ioc_parmget(intptr_t arg, int mode, int *rval_p, + int u_mode); +extern int scf_ioc_autopwrset(intptr_t arg, int mode, int *rval_p, + int u_mode); +extern int scf_ioc_autopwrget(intptr_t arg, int mode, int *rval_p, + int u_mode); +extern int scf_ioc_autopwrclr(intptr_t arg, int mode, int *rval_p, + int u_mode); +extern int scf_ioc_autopwrfpoff(intptr_t arg, int mode, int *rval_p, + int u_mode); +extern int scf_ioc_autopwrexset(intptr_t arg, int mode, int *rval_p, + int u_mode); +extern int scf_ioc_autopwrexget(intptr_t arg, int mode, int *rval_p, + int u_mode); +extern int scf_ioc_dr(intptr_t arg, int mode, int *rval_p, int u_mode); +extern int scf_ioc_eventlist(intptr_t arg, int mode, int *rval_p, + int u_mode); +extern int scf_ioc_getevent(intptr_t arg, int mode, int *rval_p, + int u_mode); +extern int scf_ioc_setmadmevent(intptr_t arg, int mode, int *rval_p, + int u_mode); +extern int scf_ioc_remcscmd(intptr_t arg, int mode, int *rval_p, + int u_mode); +extern int scf_ioc_remcsfile(intptr_t arg, int mode, int *rval_p, + int u_mode); +extern int scf_ioc_sparecmd(intptr_t arg, int mode, int *rval_p, + int u_mode); +extern int scf_ioc_setphpinfo(intptr_t arg, int mode, int *rval_p, + int u_mode); +extern int scf_ioc_pciresetreq(intptr_t arg, int mode, int *rval_p, + int u_mode); +extern int scf_push_reportsense(unsigned int rci_addr, + unsigned char *sense, time_t timestamp); +extern int scf_pop_reportsense(scfreport_t *rsense); +extern int scf_push_getevent(unsigned char *event_p); +extern int scf_pop_getevent(scfevent_t *event_p); +extern int scf_valid_date(int year, int month, int date); +extern int scf_check_pon_time(scfautopwrtime_t *ptime); +extern int scf_check_poff_time(scfautopwrtime_t *ptime); + +extern uint_t scf_intr(caddr_t arg); +extern int scf_intr_cmdcmp(scf_state_t *statep); +extern void scf_intr_cmdcmp_driver(scf_state_t *statep, + struct scf_cmd *scfcmdp); +extern int scf_intr_dsens(struct scf_cmd *scfcmdp, + scf_int_reason_t *int_rp, int len); +extern void scf_status_change(scf_state_t *statep); +extern void scf_next_cmd_check(scf_state_t *statep); +extern void scf_next_rxdata_get(void); +extern void scf_online_wait_tout(void); +extern void scf_cmdbusy_tout(void); +extern void scf_cmdend_tout(void); +extern void scf_report_send_wait_tout(void); +extern void scf_alivecheck_intr(scf_state_t *statep); +extern void scf_path_change(scf_state_t *statep); +extern void scf_halt(uint_t mode); +extern void scf_panic_callb(int code); +extern void scf_shutdown_callb(int code); +extern uint_t scf_softintr(caddr_t arg); +extern void scf_cmdwait_status_set(void); + +extern int scf_map_regs(dev_info_t *dip, scf_state_t *statep); +extern void scf_unmap_regs(scf_state_t *statep); +extern int scf_send_cmd_check_bufful(struct scf_cmd *scfcmdp); +extern int scf_send_cmd(struct scf_cmd *scfcmdp); +extern void scf_i_send_cmd(struct scf_cmd *scfcmdp, + struct scf_state *statep); +extern void scf_p_send_cmd(struct scf_cmd *scfcmdp, + struct scf_state *statep); +extern int scf_path_check(scf_state_t **statep); +extern int scf_offline_check(scf_state_t *statep, uint_t timer_exec_flag); +extern int scf_cmdbusy_check(scf_state_t *statep); +extern void scf_alivecheck_start(scf_state_t *statep); +extern void scf_alivecheck_stop(scf_state_t *statep); +extern void scf_forbid_intr(struct scf_state *statep); +extern void scf_permit_intr(struct scf_state *statep, int flag); +extern int scf_check_state(scf_state_t *statep); +extern void scf_chg_scf(scf_state_t *statep, int status); +extern void scf_del_queue(scf_state_t *statep); +extern int scf_make_send_cmd(struct scf_cmd *scfcmdp, uint_t flag); +extern void scf_sram_trace_init(struct scf_state *statep); +extern void scf_sram_trace(struct scf_state *statep, uint8_t log_id); + +#ifdef DEBUG +#include <sys/scfd/scftrace.h> +#include <sys/scfd/iomp_drv.h> +#include <sys/scfd/scfdebug.h> +#include <sys/scfd/scfsnap.h> + +#define SCF_META_INSTANCE (SCF_USER_INSTANCE + 1) + /* meta management instance */ +#define SCF_INST_INSTANCE (SCF_USER_INSTANCE + 2) + /* instance management instance */ + +extern void scf_add_scf(scf_state_t *statep); +extern void scf_del_scf(scf_state_t *statep); +extern int scf_meta_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, + cred_t *cred_p, int *rval_p, int u_mode); +extern int scf_inst_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, + cred_t *cred_p, int *rval_p, int u_mode); +extern void scf_inst_getstat32(scf_state_t *statep, + struct fiompstatus_32 *status32_p, char *message_p, + int flag); +extern void scf_inst_getstat(scf_state_t *statep, + struct fiompstatus *status_p, char *message_p, + int flag); + +#define SCF_DDI_PUT8(a, b, c, d) \ + if (scf_debug_no_device == SCF_DBF_NO_DEVICE_ON) { \ + uint8_t *cp = (uint8_t *)c; \ + *cp = d; \ + } else { \ + ddi_put8(b, c, d); \ + } + +#define SCF_DDI_PUT16(a, b, c, d) \ + if (scf_debug_no_device == SCF_DBF_NO_DEVICE_ON) { \ + uint16_t *cp = (uint16_t *)c; \ + *cp = d; \ + } else { \ + ddi_put16(b, c, d); \ + } + +#define SCF_DDI_PUT32(a, b, c, d) \ + if (scf_debug_no_device == SCF_DBF_NO_DEVICE_ON) { \ + uint32_t *cp = (uint32_t *)c; \ + *cp = d; \ + } else { \ + ddi_put32(b, c, d); \ + } + +#define SCF_DDI_GET8(a, b, c) \ + (scf_debug_no_device == SCF_DBF_NO_DEVICE_ON) ? \ + *((uint8_t *)c) : ddi_get8(b, c) + +#define SCF_DDI_GET16(a, b, c) \ + (scf_debug_no_device == SCF_DBF_NO_DEVICE_ON) ? \ + *((uint16_t *)c) : ddi_get16(b, c) + +#define SCF_DDI_GET32(a, b, c) \ + (scf_debug_no_device == SCF_DBF_NO_DEVICE_ON) ? \ + *((uint32_t *)c) : ddi_get32(b, c) + +#define SCF_P_DDI_PUT8(a, b, c) \ + if (scf_debug_no_device == SCF_DBF_NO_DEVICE_ON) { \ + uint8_t *bp = (uint8_t *)b; \ + *bp = c; \ + } else { \ + ddi_put8(a, b, c); \ + } + +#define SCF_P_DDI_PUT16(a, b, c) \ + if (scf_debug_no_device == SCF_DBF_NO_DEVICE_ON) { \ + uint16_t *bp = (uint16_t *)b; \ + *bp = c; \ + } else { \ + ddi_put16(a, b, c); \ + } + +#define SCF_P_DDI_PUT32(a, b, c) \ + if (scf_debug_no_device == SCF_DBF_NO_DEVICE_ON) { \ + uint32_t *bp = (uint32_t *)b; \ + *bp = c; \ + } else { \ + ddi_put32(a, b, c); \ + } + +#define SCF_P_DDI_GET8(a, b) \ + (scf_debug_no_device == SCF_DBF_NO_DEVICE_ON) ? \ + *((uint8_t *)b) : ddi_get8(a, b) + +#define SCF_P_DDI_GET16(a, b) \ + (scf_debug_no_device == SCF_DBF_NO_DEVICE_ON) ? \ + *((uint16_t *)b) : ddi_get16(a, b) + +#define SCF_P_DDI_GET32(a, b) \ + (scf_debug_no_device == SCF_DBF_NO_DEVICE_ON) ? \ + *((uint32_t *)b) : ddi_get32(a, b) + +#define SCF_CHECK_INSTANCE(a) \ + (a == SCF_USER_INSTANCE) || \ + (a == SCF_META_INSTANCE) || \ + (a == SCF_INST_INSTANCE) + +#define SCF_DBG_DRV_TRACE_TBL \ + scf_trctbl_t *trace_f; \ + scf_trctbl_t *trace_l; \ + scf_trctbl_t *trace_w; \ + scf_trctbl_t *err_trace_f; \ + scf_trctbl_t *err_trace_l; \ + scf_trctbl_t *err_trace_w; \ + scf_trctbl_t trace_table[TC_NRM_CNT]; \ + scf_trctbl_t err_trace_table[TC_ERR_CNT]; \ + int path_num; \ + int alloc_size; \ + scf_state_t **iomp_scf; + +#define SC_DBG_DRV_TRACE(a, b, c, d) \ + scf_trace((ushort_t)(a), (ushort_t)(b), (uchar_t *)(c), (ushort_t)(d)) + +#define SCF_DBG_DRV_TRACE_INIT \ + scf_comtbl.trace_f = (scf_trctbl_t *)&scf_comtbl.trace_table[0]; \ + scf_comtbl.trace_l \ + = (scf_trctbl_t *)&scf_comtbl.trace_table[TC_NRM_CNT]; \ + scf_comtbl.trace_w = (scf_trctbl_t *)&scf_comtbl.trace_table[0]; \ + scf_comtbl.err_trace_f \ + = (scf_trctbl_t *)&scf_comtbl.err_trace_table[0]; \ + scf_comtbl.err_trace_l \ + = (scf_trctbl_t *)&scf_comtbl.err_trace_table[TC_ERR_CNT]; \ + scf_comtbl.err_trace_w \ + = (scf_trctbl_t *)&scf_comtbl.err_trace_table[0]; + +#define SCFDBGMSG(f, s) if (f & scf_trace_msg_flag) \ + cmn_err(CE_CONT, "scfd:debug:%04d: " s, __LINE__) +#define SCFDBGMSG1(f, s, a) if (f & scf_trace_msg_flag) \ + cmn_err(CE_CONT, "scfd:debug:%04d: " s, __LINE__, a) +#define SCFDBGMSG2(f, s, a, b) if (f & scf_trace_msg_flag) \ + cmn_err(CE_CONT, "scfd:debug:%04d: " s, __LINE__, a, b) +#define SCFDBGMSG3(f, s, a, b, c) if (f & scf_trace_msg_flag) \ + cmn_err(CE_CONT, "scfd:debug:%04d: " s, __LINE__, a, b, c) +#define SCFDBGMSG4(f, s, a, b, c, d) if (f & scf_trace_msg_flag) \ + cmn_err(CE_CONT, "scfd:debug:%04d: " s, __LINE__, a, b, c, d) + +#define SCF_DBG_IOMP_INSTANCE \ + { "mscf0", S_IFCHR, SCF_INST_INSTANCE }, \ + { "mscf", S_IFCHR, SCF_META_INSTANCE }, + +#define SCF_DBG_IOMP_PROC \ + if (instance == SCF_META_INSTANCE) { \ + if (drv_priv(cred_p) != 0) { \ + ret = EPERM; \ + goto END_ioctl; \ + } \ + ret = scf_meta_ioctl(dev, cmd, arg, mode, cred_p, rval_p, \ + u_mode); \ + goto END_ioctl; \ + } else if (instance == SCF_INST_INSTANCE) { \ + if (drv_priv(cred_p) != 0) { \ + ret = EPERM; \ + goto END_ioctl; \ + } \ + ret = scf_inst_ioctl(dev, cmd, arg, mode, cred_p, rval_p, \ + u_mode); \ + goto END_ioctl; \ + } + +#define SCF_DBG_IOMP_ADD(a) \ + { \ + scf_add_scf(a); \ + } + +#define SCF_DBG_IOMP_DEL(a) \ + { \ + scf_del_scf(a); \ + } + +#define SCF_DBG_IOMP_FREE \ + { \ + if (scf_comtbl.iomp_scf != NULL) { \ + kmem_free((void *)scf_comtbl.iomp_scf, \ + (size_t)scf_comtbl.alloc_size); \ + scf_comtbl.iomp_scf = NULL; \ + scf_comtbl.alloc_size = 0; \ + scf_comtbl.path_num = 0; \ + } \ + } + +#define SCF_DBG_IOCTL_PROC \ + if ((uint_t)cmd == SCFIOCCMDTHROUGH) { \ + ret = scf_debug_cmdthrough(arg, mode); \ + goto END_ioctl; \ + } else if ((uint_t)cmd == SCFIOCTEST) { \ + ret = scf_debug_test(arg, mode); \ + goto END_ioctl; \ + } else if ((uint_t)cmd == SCFIOCSNAPSHOTSIZE) { \ + ret = scf_snapshotsize(arg, mode); \ + goto END_ioctl; \ + } else if ((uint_t)cmd == SCFIOCSNAPSHOT) { \ + ret = scf_snapshot(arg, mode); \ + goto END_ioctl; \ + } + +#define SCF_DBG_TEST_TIMER_STOP \ + { \ + scf_debug_test_timer_stop(); \ + } + +#define SCF_DBG_TEST_INTR(a) \ + { \ + if ((scf_debug_test_sys_int_flag == SCF_DBF_SYS_INTR_ON) || \ + (scf_debug_test_dscp_int_flag == SCF_DBF_DSCP_INT_ON)) \ + scf_debug_test_intr(a); \ + } + +#define SCF_DBG_TEST_INTR_SCFINT(a) \ + { \ + if (scf_debug_test_sys_int_flag == SCF_DBF_SYS_INTR_ON) \ + scf_debug_test_intr_scfint(a); \ + } + +#define SCF_DBG_TEST_INTR_CMDEND(a) \ + { \ + if (scf_debug_test_sys_int_flag == SCF_DBF_SYS_INTR_ON) \ + scf_debug_test_intr_cmdend(a); \ + } + +#define SCF_DBG_MAKE_RXSUM(a, b) \ + { \ + if (scf_debug_norxsum_check != SCF_DBF_NORXSUM_CHECK_OFF) \ + a = b; \ + } + +#define SCF_DBG_MAKE_RXSUM_L(a, b) \ + { \ + if (scf_debug_test_rxbuff_nosum_check_flag == \ + SCF_DBF_RXBUFF_NOSUM_CHECK_ON) { \ + a = b; \ + scf_debug_test_rxbuff_nosum_check_flag \ + = SCF_DBF_RXBUFF_NOSUM_CHECK_OFF; \ + } \ + } + +#define SCF_DBG_NO_INT_REASON \ + { \ + if (scf_debug_no_int_reason) \ + scf_comtbl.scf_event_flag &= (~STATUS_EVENT); \ + } + +#define SCF_DBG_TEST_INTR_POFF \ + { \ + if (scf_debug_test_sys_poff_flag == SCF_DBF_NO_INT_REASON_ON) \ + scf_debug_test_intr_poff(); \ + } + +#define SCF_DBG_TEST_DSENS(a, b, c) \ + { \ + if (scf_debug_test_sys_event_flag == SCF_DBF_SYS_EVENT_ON) \ + scf_debug_test_dsens(a, b, c); \ + } + +#define SCF_DBG_TEST_SEND_CMD(a, b) \ + { \ + if (scf_debug_nofirm_sys == SCF_DBF_NOFIRM_SYS_ON) \ + scf_debug_test_send_cmd(a, b); \ + } + +#define SCF_DBG_MAKE_PATH_CHECK(a) \ + { \ + if (scf_debug_test_path_check != SCF_DBC_PATH_CHECK_CLEAR) { \ + scf_debug_test_path_check--; \ + if (scf_debug_test_path_check == SCF_DBC_PATH_CHECK_CLEAR) \ + a = scf_debug_test_path_check_rtn; \ + } \ + } + +#define SCF_DBG_MAKE_ONLINE(a) \ + { \ + if (scf_debug_nooffline_check != SCF_DBF_NOOFFLINE_CHECK_OFF) \ + a = STATUS_SCF_ONLINE; \ + } + +#define SCF_DBG_MAKE_OFFLINE_CHECK(a) \ + { \ + if (scf_debug_test_offline_check != SCF_DBC_OFFLINE_CHECK_CLEAR) { \ + scf_debug_test_offline_check--; \ + if (scf_debug_test_offline_check \ + == SCF_DBC_OFFLINE_CHECK_CLEAR) \ + a = scf_debug_test_offline_check_rtn; \ + } \ + } + +#define SCF_DBG_RTN_MAKE_CMD_READY \ + { \ + if (scf_debug_nofirm_sys == SCF_DBF_NOFIRM_SYS_ON) \ + return (SCF_COMMAND_READY); \ + } + +#define SCF_DBG_MAKE_CMD_BUSY(a, b) \ + { \ + if (scf_debug_test_cmdr_busy != SCF_DBC_CMDR_BUSY_CLEAR) { \ + scf_debug_test_cmdr_busy--; \ + if (scf_debug_test_cmdr_busy == SCF_DBC_CMDR_BUSY_CLEAR) \ + a |= COMMAND_BUSY; \ + } \ + if (scf_debug_test_cmdexr_busy != SCF_DBC_CMDEXR_BUSY_CLEAR) { \ + scf_debug_test_cmdexr_busy--; \ + if (scf_debug_test_cmdexr_busy == SCF_DBC_CMDEXR_BUSY_CLEAR) \ + b |= COMMAND_ExR_BUSY; \ + } \ + } + +#define SCF_DBG_TEST_ALIVE_START(a) \ + { \ + if (scf_debug_no_alive == SCF_DBF_NO_ALIVE_ON) \ + scf_debug_test_alive_start(a); \ + } + +#define SCF_DBG_TEST_ALIVE_STOP(a) \ + { \ + if (scf_debug_no_alive == SCF_DBF_NO_ALIVE_ON) \ + scf_debug_test_alive_stop(a); \ + } + +#define SCF_DBG_TEST_INTR_DSCP_DSR(a) \ + { \ + if (scf_debug_test_dscp_int_flag == SCF_DBF_DSCP_INT_ON) \ + scf_debug_test_intr_dscp_dsr(a); \ + } + +#define SCF_DBG_TEST_INTR_DSCP_RXTX(a, b) \ + { \ + if (scf_debug_test_dscp_int_flag == SCF_DBF_DSCP_INT_ON) \ + scf_debug_test_intr_dscp_rxtx(a, b); \ + } + +#define SCF_DBG_MAKE_LOOPBACK(a) \ + { \ + if (scf_debug_test_dscp_loopback == SCF_DBF_DSCP_LOOPBACK_ON) \ + a = 0; \ + } + +#define SCF_DBG_MAKE_NO_DSCP_PATH(a) \ + { \ + if (scf_debug_no_dscp_path == SCF_DBF_NO_DSCP_PATH_ON) \ + a = FLAG_OFF; \ + } + +#define SCF_DBG_TEST_TXREQ_SEND(a, b) \ + { \ + if (scf_debug_nofirm_dscp == SCF_DBF_NOFIRM_DSCP_ON) \ + scf_debug_test_txreq_send(a, b); \ + } + +#define SCF_DBG_TEST_MAP_REGS(a) \ + { \ + if (scf_debug_no_device == SCF_DBF_NO_DEVICE_ON) { \ + scf_debug_test_map_regs(a); \ + scf_sram_trace_init(a); \ + ret = 0; \ + goto END_map_regs; \ + } \ + } + +#define SCF_DBG_TEST_UNMAP_REGS(a) \ + { \ + if (scf_debug_no_device == SCF_DBF_NO_DEVICE_ON) { \ + scf_debug_test_unmap_regs(a); \ + SCFDBGMSG(SCF_DBGFLAG_SYS, "scf_unmap_regs(): end"); \ + return; \ + } \ + } + +#define SCF_DBG_XSCF_SET_STATUS \ + if (scf_comtbl.debugxscf_flag) { \ + if (scfcmdp->stat0 != NORMAL_END) { \ + scfcmdp->rbufleng = 0; \ + scfcmdp->stat0 = NORMAL_END; \ + } \ + } + +#define SCF_DBG_XSCF_SET_LENGTH \ + if (scf_comtbl.debugxscf_flag) { \ + if (((scfcmdp->status & STATUS_CMD_RTN_CODE) >> 4) != \ + NORMAL_END) { \ + scfcmdp->rbufleng = 0; \ + break; \ + } \ + } + +#define SCF_DBG_CHECK_NODEVICE \ + scf_debug_no_device == SCF_DBF_NO_DEVICE_ON + +#else /* DEBUG */ + +#define SCF_DDI_PUT8(a, b, c, d) ddi_put8(b, c, d) +#define SCF_DDI_PUT16(a, b, c, d) ddi_put16(b, c, d) +#define SCF_DDI_PUT32(a, b, c, d) ddi_put32(b, c, d) +#define SCF_DDI_GET8(a, b, c) ddi_get8(b, c) +#define SCF_DDI_GET16(a, b, c) ddi_get16(b, c) +#define SCF_DDI_GET32(a, b, c) ddi_get32(b, c) + +#define SCF_P_DDI_PUT8(a, b, c) ddi_put8(a, b, c) +#define SCF_P_DDI_PUT16(a, b, c) ddi_put16(a, b, c) +#define SCF_P_DDI_PUT32(a, b, c) ddi_put32(a, b, c) +#define SCF_P_DDI_GET8(a, b) ddi_get8(a, b) +#define SCF_P_DDI_GET16(a, b) ddi_get16(a, b) +#define SCF_P_DDI_GET32(a, b) ddi_get32(a, b) + +#define SCF_CHECK_INSTANCE(a) (a == SCF_USER_INSTANCE) + +#define SCF_DBG_DRV_TRACE_TBL +#define SC_DBG_DRV_TRACE(a, b, c, d) +#define SCF_DBG_DRV_TRACE_INIT + +#define SCFDBGMSG(f, s) +#define SCFDBGMSG1(f, s, a) +#define SCFDBGMSG2(f, s, a, b) +#define SCFDBGMSG3(f, s, a, b, c) +#define SCFDBGMSG4(f, s, a, b, c, d) + +#define SCF_DBG_INIT +#define SCF_DBG_IOMP_INSTANCE +#define SCF_DBG_IOMP_PROC +#define SCF_DBG_IOCTL_PROC +#define SCF_DBG_IOMP_ADD(a) +#define SCF_DBG_IOMP_DEL(a) +#define SCF_DBG_IOMP_FREE +#define SCF_DBG_TEST_TIMER_STOP +#define SCF_DBG_TEST_INTR(a) +#define SCF_DBG_TEST_INTR_SCFINT(a) +#define SCF_DBG_TEST_INTR_CMDEND(a) +#define SCF_DBG_MAKE_RXSUM(a, b) +#define SCF_DBG_MAKE_RXSUM_L(a, b) +#define SCF_DBG_NO_INT_REASON +#define SCF_DBG_TEST_INTR_POFF +#define SCF_DBG_TEST_DSENS(a, b, c) +#define SCF_DBG_TEST_SEND_CMD(a, b) +#define SCF_DBG_MAKE_PATH_CHECK(a) +#define SCF_DBG_MAKE_ONLINE(a) +#define SCF_DBG_MAKE_OFFLINE_CHECK(a) +#define SCF_DBG_RTN_MAKE_CMD_READY +#define SCF_DBG_MAKE_CMD_BUSY(a, b) +#define SCF_DBG_TEST_ALIVE_START(a) +#define SCF_DBG_TEST_ALIVE_STOP(a) +#define SCF_DBG_TEST_INTR_DSCP_DSR(a) +#define SCF_DBG_TEST_INTR_DSCP_RXTX(a, b) +#define SCF_DBG_MAKE_LOOPBACK(a) +#define SCF_DBG_MAKE_NO_DSCP_PATH(a) +#define SCF_DBG_TEST_TXREQ_SEND(a, b) +#define SCF_DBG_TEST_MAP_REGS(a) +#define SCF_DBG_TEST_UNMAP_REGS(a) +#define SCF_DBG_DDI_PUT(a, b) +#define SCF_DBG_DDI_GET(a) +#define SCF_DBG_XSCF_SET_STATUS +#define SCF_DBG_XSCF_SET_LENGTH + +#endif /* DEBUG */ + +/* + * SCF driver common table + */ +typedef struct scf_comtbl { + /* mutex resource */ + kmutex_t all_mutex; /* scf driver mutex */ + kmutex_t trc_mutex; /* scf driver trace mutex */ + kmutex_t attach_mutex; /* attach mutex */ + kmutex_t si_mutex; /* softintr mutex */ + + /* cookie */ + ddi_iblock_cookie_t iblock_cookie; /* SCFI-Interrupt */ + ddi_iblock_cookie_t soft_iblock_cookie; /* softintr cookie */ + + /* condition variables */ + kcondvar_t cmd_cv; /* command send */ + kcondvar_t cmdwait_cv; /* command send wait */ + kcondvar_t cmdend_cv; /* command send end */ + kcondvar_t cmdbusy_cv; /* command busy send wait */ + kcondvar_t rsense_cv; /* report sense */ + kcondvar_t rdcsense_cv; /* SCFIOCRDCTRL & sense */ + kcondvar_t rdctrl_cv; /* SCFIOCRDCTRL command */ + kcondvar_t getevent_cv; /* SCFIOCGETEVENT */ + kcondvar_t suspend_wait_cv; /* suspend cv */ + + /* ID */ + ddi_softintr_t scf_softintr_id; /* softintr id */ + + /* SCF state table address */ + scf_state_t *scf_pseudo_p; /* pseudo device state */ + scf_state_t *scf_exec_p; /* SCF exec state */ + scf_state_t *scf_path_p; /* SCF path change state */ + scf_state_t *scf_wait_p; /* Standby state */ + scf_state_t *scf_stop_p; /* Stop state */ + scf_state_t *scf_err_p; /* error state */ + scf_state_t *scf_disc_p; /* Disconnect state */ + scf_state_t *scf_suspend_p; /* Suspend stste */ + + /* flag and counter */ + uint_t resource_flag; /* resource allocate flag */ + uint_t scf_event_flag; /* SCF event flag */ + uint_t poff_factor; /* Shutdown factor */ + uint_t cmd_busy; /* cmd send busy flag */ + uint_t cmd_wait; /* cmd send wait counter */ + uint_t cmd_busy_wait; /* cmd busy send wait flag */ + uint_t cmd_end_wait; /* cmd send end wait flag */ + uint_t rdctrl_busy; /* SCFIOCRDCTRL busy flag */ + uint_t rdctrl_end_wait; /* SCFIOCRDCTRL cmd end wait flag */ + uint_t alive_running; /* Alive check exec flag */ + uint_t watchdog_after_resume; /* watch cpu after resume flag */ + uint_t scf_shutdown_exec_flag; /* SCFIOCSHUTDOWN call flag */ + uint_t shutdown_start_reported; /* SCFIOCREPORTSTAT(shutdown) call */ + uint_t scf_exec_cmd_id; /* SCF command exec id */ + uint_t scf_cmd_exec_flag; /* SCF command exec flag */ + uint_t putinfo_exec_flag; /* scf_service_putinfo() exec flag */ + uint_t getinfo_exec_flag; /* scf_service_getinfo() exec flag */ + uint_t debugxscf_flag; /* SCFIOCCMDTHROUGH exec flag */ + uint_t suspend_wait; /* Suspend wait flag */ + uint_t suspend_flag; /* Suspend flag */ + uint_t scf_suspend_sendstop; /* Suspend send stop flag */ + uint_t scf_softintr_dscp_kicked; /* Softintr DSCP kick flag */ + uint_t int_reason_retry; /* INT_REASON retry flag */ + uint_t scf_alive_int_count; /* Alive check interrupt counter */ + uint_t reload_conf_flag; /* configuration file load flag */ + uint_t scf_cmd_resend_flag; /* SCF command re send flag */ + uint_t scf_cmd_resend_req; /* SCF command re send flag */ + uint_t path_stop_flag; /* command send stop flag */ + + uint_t report_buf_ful_rcnt; /* Report command BUF_FUL */ + /* retry counter */ + uint_t report_rci_busy_rcnt; /* Report command RCI_BUSY */ + /* retry counter */ + uint_t path_change_rcnt; /* SCF path change retry counter */ + + /* status information */ + ushort_t scf_mode_sw; /* Mode switch status */ + uchar_t scf_poff_id; /* POFF interrupt id */ + uint_t scf_shutdownreason; /* Shutdown reason */ + uint_t scf_status; /* XSCF status */ + + /* SCF command control code */ + uint_t scf_pchg_event_sub; /* SCF path change status */ + uint_t scf_poff_event_sub; /* POFF event status */ + uint_t scf_shut_event_sub; /* SHUTDOWN event status */ + uint_t scf_alive_event_sub; /* ALIVE event status */ + uint_t scf_report_event_sub; /* REPORT processing status */ + + /* SCF command control */ + scf_cmd_t *scf_cmdp; /* SCF command table address */ + uint_t scf_last_report; /* Last report */ + uint_t scf_rem_rxbuff_size; /* remainder receive data size */ + + /* SCF command interrupt area */ + scf_cmd_t scf_cmd_intr; /* SCF comand table(Interrupt use) */ + uchar_t scf_sbuf[SCF_S_CNT_16]; /* Tx Small buffer table */ + uchar_t scf_rbuf[SCF_INT_CNT_MAX]; /* Rx Large buffer table */ + uchar_t last_event[SCF_INT_REASON_SIZE]; /* Last event table */ + + /* ioctl control area */ + scfreport_t *report_sensep; /* SCFIOCGETREPORT save address */ + int report_sense_top; /* SCFIOCGETREPORT save offset(push) */ + int report_sense_oldest; /* SCFIOCGETREPORT save offset(pop) */ + uint_t rcidown_event_flag; /* SCFIOCGETREPORT rci down flag */ + scfreport_t scfreport_rcidown; /* SCFIOCGETREPORT rci down area */ + + scfevent_t *getevent_sensep; /* SCFIOCGETEVENT save address */ + int getevent_sense_top; /* SCFIOCGETEVENT save offset(push) */ + int getevent_sense_oldest; /* SCFIOCGETEVENT save offset(pop) */ + + scfeventlist_t getevent_tbl; /* SCFIOCEVENTLIST list table */ + + uchar_t lcd_seq_mes[SCF_WRLCD_MAX]; + /* SCFIOCCLEARLCD and SCFIOCWRLCD message */ + + uchar_t rdctrl_sense_category_code; /* SCFIOCRDCTL sub command */ + uchar_t rdctrl_sense[SCF_SBUFR_SIZE]; /* SCFIOCRDCTL information */ + + /* memo counter */ + uint_t attach_count; /* SCF attach count */ + + /* error memo counter */ + uint_t memo_cmd_to_cnt; /* CMD timeout memo */ + uint_t scf_rsense_overflow; /* SCFIOCGETREPORT overflow memo */ + uint_t scf_getevent_overflow; /* SCFIOCGETEVENT overflow memo */ + + /* Unclaimed interrupt register log */ + uint_t scf_unclamed_cnt; /* Unclaimed interrupt counter */ + struct { + uint16_t CONTROL; /* SCF Control register */ + uint16_t INT_ST; /* SCF Interrupt Status register */ + uint16_t COMMAND; /* SCF command register */ + uint16_t STATUS; /* SCF status register */ + uint32_t STATUS_ExR; /* SCFI status extended register */ + uint8_t DSR; /* DSCP buffer status register */ + } scf_unclamed; + + /* kstat private area */ + scf_kstat_private_t *kstat_private; /* for kstat area */ + + SCF_DBG_DRV_TRACE_TBL /* SCF driver trace */ +} scf_comtbl_t; + + +/* + * (resource_flag) macro for resource allocate flag + */ +#define DID_MUTEX_ATH (1 << 0) +#define DID_MUTEX_ALL (1 << 1) +#define DID_MUTEX_TRC (1 << 2) +#define DID_MUTEX_SI (1 << 3) + +#define DID_CV (1 << 4) +#define DID_KSTAT (1 << 5) +#define DID_ALLOCBUF (1 << 6) +#define DID_ALIVECHECK (1 << 7) + +#define DID_MNODE (1 << 8) +#define DID_SOFTINTR (1 << 9) + +#define DID_DSCPINIT (1 << 10) + +/* + * XSCF status defaine (scf_status) + */ +#define SCF_STATUS_OFFLINE 0 /* XSCF status is offline */ +#define SCF_STATUS_ONLINE 1 /* XSCF status is online */ +#define SCF_STATUS_UNKNOWN 2 /* XSCF status is unknown */ + +/* + * SCF command control status + */ +#define EVENT_SUB_NONE 0 /* None status */ +/* (scf_pchg_event_sub) SCF path change status */ +#define EVENT_SUB_PCHG_WAIT 1 /* SCF path change command wait */ +#define EVENT_SUB_PCHG_EXEC 2 /* SCF path change command exec */ +/* (scf_poff_event_sub) POFF event status */ +#define EVENT_SUB_POFF_WAIT 1 /* POFF factor command wait */ +#define EVENT_SUB_POFF_EXEC 2 /* POFF factor command exec */ +/* (scf_shut_event_sub) SHUTDOWN event status */ +#define EVENT_SUB_SHUT_WAIT 1 /* command wait (SHUTDOWN) */ +#define EVENT_SUB_SHUT_EXEC 2 /* command exec (SHUTDOWN) */ +#define EVENT_SUB_WAIT 3 /* command wait (EVENT) */ +#define EVENT_SUB_EXEC 4 /* command exec (EVENT) */ +/* (scf_alive_event_sub) ALIVE event status */ +#define EVENT_SUB_ALST_WAIT 1 /* Alive start command wait */ +#define EVENT_SUB_ALST_EXEC 2 /* Alive start command exec */ +#define EVENT_SUB_ALSP_WAIT 3 /* Alive stop command wait */ +#define EVENT_SUB_ALSP_EXEC 4 /* Alive stop command exec */ +/* (scf_report_event_sub) REPORT processing status */ +#define EVENT_SUB_REPORT_RUN_WAIT 1 /* Report (runnning) send wait */ +#define EVENT_SUB_REPORT_RUN_EXEC 2 /* Report (runnning) send exec */ +#define EVENT_SUB_REPORT_SHUT_WAIT 3 /* Report (shutdown) send wait */ +#define EVENT_SUB_REPORT_SHOT_EXEC 4 /* Report (shutdown) send exec */ + +/* (scf_last_report) define */ +#define NOT_SEND_REPORT 0xffffffff /* Not report send */ + +/* scf_cmd_resend_req define */ +#define RESEND_IOCTL (1 << 0) /* Comand from ioctl */ +#define RESEND_PCHG (1 << 1) /* SCF Path change command */ +#define RESEND_POFF (1 << 2) /* Power supply control command */ +#define RESEND_SHUT (1 << 3) /* Event information command */ +#define RESEND_ALST (1 << 4) /* Alive check command (start) */ +#define RESEND_ALSP (1 << 5) /* Alive check command (stop) */ +#define RESEND_REPORT_RUN (1 << 6) /* Report command (system running) */ +#define RESEND_REPORT_SHUT (1 << 7) /* Report command (shutdown start) */ + +#ifdef __cplusplus +} +#endif + +#endif /* _SCFSYS_H */ diff --git a/usr/src/uts/sun4u/opl/sys/scfd/scftimer.h b/usr/src/uts/sun4u/opl/sys/scfd/scftimer.h new file mode 100644 index 0000000000..d8f356974b --- /dev/null +++ b/usr/src/uts/sun4u/opl/sys/scfd/scftimer.h @@ -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 + */ +/* + * All Rights Reserved, Copyright (c) FUJITSU LIMITED 2006 + */ + +#ifndef _SCFTIMER_H +#define _SCFTIMER_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Timer code + */ +typedef enum { + SCF_TIMERCD_CMDBUSY, /* SCF command busy watch timer */ + SCF_TIMERCD_CMDEND, /* SCF command completion watch timer */ + SCF_TIMERCD_ONLINE, /* SCF online watch timer */ + SCF_TIMERCD_NEXTRECV, /* Next receive wait timer */ + SCF_TIMERCD_DSCP_ACK, /* DSCP interface TxACK watch timer */ + SCF_TIMERCD_DSCP_END, /* DSCP interface TxEND watch timer */ + SCF_TIMERCD_DSCP_BUSY, /* DSCP interface busy watch timer */ + SCF_TIMERCD_DSCP_CALLBACK, /* DSCP interface callback timer */ + SCF_TIMERCD_BUF_FUL, /* SCF command BUF_FUL retray timer */ + SCF_TIMERCD_RCI_BUSY, /* SCF command RCI_BUSY retray timer */ + SCF_TIMERCD_MAX /* Max timer code */ +} scf_tm_code_t; + +/* + * Timer table + */ +typedef struct scf_timer_tbl { + uint8_t code; /* Timer code */ + uint8_t rsv[3]; /* reserved */ + timeout_id_t id; /* Timer ID */ +} scf_timer_tbl_t; + +/* + * Timer control table + */ +typedef struct scf_timer { + scf_timer_tbl_t tbl[2]; + uint8_t start; /* Timer start flag */ + uint8_t restart; /* Timer restart flag */ + uint8_t stop; /* Timer stop flag */ + uint8_t side; /* Use table side */ + uint32_t value; /* Timer value */ +} scf_timer_t; + +/* + * scf_timer_check() return value + */ +#define SCF_TIMER_NOT_EXEC 0 +#define SCF_TIMER_EXEC 1 + +/* + * Timer value (ms) + */ + /* SCF command busy timer value (10s) */ +#define SCF_TIMER_VALUE_DEVBUSY 10000 + /* SCF command completion timer value (60s) */ +#define SCF_TIMER_VALUE_CMDEND 60000 + /* SCF online timer value (10s) */ +#define SCF_TIMER_VALUE_ONLINE 10000 + /* Next receive timer value (20ms) */ +#define SCF_TIMER_VALUE_NEXTRCV 20 + /* DSCP interface timer value (60s) */ +#define SCF_TIMER_VALUE_DSCP_ACK 60000 + /* DSCP interface TxEND timer value (60s) */ +#define SCF_TIMER_VALUE_DSCP_END 60000 + /* DSCP interface busy timer value (2s) */ +#define SCF_TIMER_VALUE_DSCP_BUSY 2000 + /* DSCP interface callback timer value (20ms) */ +#define SCF_TIMER_VALUE_DSCP_CALLBACK 20 + +/* + * Timer value convert macro + */ +#define SCF_MIL2MICRO(x) ((x) * 1000) +#define SCF_SEC2MICRO(x) ((x) * 1000000) + +/* + * External function + */ +extern void scf_timer_init(void); +extern void scf_timer_start(int); +extern void scf_timer_stop(int); +extern void scf_timer_all_stop(void); +extern int scf_timer_check(int); +extern uint32_t scf_timer_value_get(int); +extern void scf_tout(void *); +extern int scf_timer_stop_collect(timeout_id_t *tmids, int size); +extern void scf_timer_untimeout(timeout_id_t *tmids, int size); + +extern scf_timer_t scf_timer[SCF_TIMERCD_MAX]; + +#ifdef __cplusplus +} +#endif + +#endif /* _SCFTIMER_H */ diff --git a/usr/src/uts/sun4u/opl/sys/scfd/scftrace.h b/usr/src/uts/sun4u/opl/sys/scfd/scftrace.h new file mode 100644 index 0000000000..42f504370e --- /dev/null +++ b/usr/src/uts/sun4u/opl/sys/scfd/scftrace.h @@ -0,0 +1,215 @@ +/* + * 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 + */ +/* + * All Rights Reserved, Copyright (c) FUJITSU LIMITED 2006 + */ + +#ifndef _SCFTRACE_H +#define _SCFTRACE_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +#include <sys/scfd/scfstate.h> + +#define TC_INFO_SIZE 8 + +/* SCF driver trace table */ +typedef struct scf_trctbl { + ushort_t line; /* sorce kine No. */ + ushort_t tmvl; /* trace time (100ms) */ + ushort_t code; /* trace code */ + ushort_t size; /* info size */ + uchar_t info[TC_INFO_SIZE]; /* detail info */ +} scf_trctbl_t; + +#define TC_NRM_CNT 1920 /* normal trace entry count */ +#define TC_ERR_CNT 128 /* error trace entry count */ + +#define SCF_DBGFLAG_REG 0x00000001 + +#define SCF_DBGFLAG_IOCTL 0x00000010 +#define SCF_DBGFLAG_SYS 0x00000020 +#define SCF_DBGFLAG_DSCP 0x00000040 +#define SCF_DBGFLAG_SRV 0x00000080 + +#define SCF_DBGFLAG_IOMP 0x00000100 +#define SCF_DBGFLAG_KSTAT 0x00000200 +#define SCF_DBGFLAG_FOCK 0x00000400 + +#define SCF_DBGFLAG_DDI 0x00001000 +#define SCF_DBGFLAG_OPCLS 0x00002000 +#define SCF_DBGFLAG_TIMER 0x00004000 + +#define SCF_DBGFLAG_SNAP 0x00010000 +#define SCF_DBGFLAG_TRACE 0x00020000 +#define SCF_DBGFLAG_DBG 0x00080000 + +#define SCF_DBGFLAG_ALL 0xffffffff + +/* + * trace code define + */ +#define TC_ERR 0x8000 +#define TC_ERRCD 0x4000 +#define TC_MSG 0x2000 +#define TC_R_REG 0x1000 +#define TC_W_REG 0x0800 +#define TC_R_CONTROL (TC_R_REG | 0x0001) +#define TC_R_INT_ST (TC_R_REG | 0x0002) +#define TC_R_COMMAND (TC_R_REG | 0x0011) +#define TC_R_COMMAND_ExR (TC_R_REG | 0x0012) +#define TC_R_STATUS (TC_R_REG | 0x0013) +#define TC_R_STATUS_ExR (TC_R_REG | 0x0014) +#define TC_R_TDATA0 (TC_R_REG | 0x0020) +#define TC_R_TDATA1 (TC_R_REG | 0x0021) +#define TC_R_TDATA2 (TC_R_REG | 0x0022) +#define TC_R_TDATA3 (TC_R_REG | 0x0023) +#define TC_R_RDATA0 (TC_R_REG | 0x0030) +#define TC_R_RDATA1 (TC_R_REG | 0x0031) +#define TC_R_RDATA2 (TC_R_REG | 0x0032) +#define TC_R_RDATA3 (TC_R_REG | 0x0033) +#define TC_R_ACR (TC_R_REG | 0x0040) +#define TC_R_ATR (TC_R_REG | 0x0041) +#define TC_R_DCR (TC_R_REG | 0x0050) +#define TC_R_DSR (TC_R_REG | 0x0051) +#define TC_R_TxDCR_C_FLAG (TC_R_REG | 0x0052) +#define TC_R_TxDCR_OFFSET (TC_R_REG | 0x0053) +#define TC_R_TxDCR_LENGTH (TC_R_REG | 0x0054) +#define TC_R_TxDSR_C_FLAG (TC_R_REG | 0x0055) +#define TC_R_TxDSR_OFFSET (TC_R_REG | 0x0056) +#define TC_R_RxDCR_C_FLAG (TC_R_REG | 0x0057) +#define TC_R_RxDCR_OFFSET (TC_R_REG | 0x0058) +#define TC_R_RxDCR_LENGTH (TC_R_REG | 0x0059) +#define TC_R_RxDSR_C_FLAG (TC_R_REG | 0x005a) +#define TC_R_RxDSR_OFFSET (TC_R_REG | 0x005b) + +#define TC_W_CONTROL (TC_W_REG | 0x0001) +#define TC_W_INT_ST (TC_W_REG | 0x0002) +#define TC_W_COMMAND (TC_W_REG | 0x0011) +#define TC_W_COMMAND_ExR (TC_W_REG | 0x0012) +#define TC_W_STATUS (TC_W_REG | 0x0013) +#define TC_W_STATUS_ExR (TC_W_REG | 0x0014) +#define TC_W_TDATA0 (TC_W_REG | 0x0020) +#define TC_W_TDATA1 (TC_W_REG | 0x0021) +#define TC_W_TDATA2 (TC_W_REG | 0x0022) +#define TC_W_TDATA3 (TC_W_REG | 0x0023) +#define TC_W_RDATA0 (TC_W_REG | 0x0030) +#define TC_W_RDATA1 (TC_W_REG | 0x0031) +#define TC_W_RDATA2 (TC_W_REG | 0x0032) +#define TC_W_RDATA3 (TC_W_REG | 0x0033) +#define TC_W_ACR (TC_W_REG | 0x0040) +#define TC_W_ATR (TC_W_REG | 0x0041) +#define TC_W_DCR (TC_W_REG | 0x0050) +#define TC_W_DSR (TC_W_REG | 0x0051) +#define TC_W_TxDCR_C_FLAG (TC_W_REG | 0x0052) +#define TC_W_TxDCR_OFFSET (TC_W_REG | 0x0053) +#define TC_W_TxDCR_LENGTH (TC_W_REG | 0x0054) +#define TC_W_TxDSR_C_FLAG (TC_W_REG | 0x0055) +#define TC_W_TxDSR_OFFSET (TC_W_REG | 0x0056) +#define TC_W_RxDCR_C_FLAG (TC_W_REG | 0x0057) +#define TC_W_RxDCR_OFFSET (TC_W_REG | 0x0058) +#define TC_W_RxDCR_LENGTH (TC_W_REG | 0x0059) +#define TC_W_RxDSR_C_FLAG (TC_W_REG | 0x005a) +#define TC_W_RxDSR_OFFSET (TC_W_REG | 0x005b) + +#define TC_TIMER 0x0400 +#define TC_T_TOUT (TC_TIMER | 0x0001) +#define TC_T_START (TC_TIMER | 0x0002) +#define TC_T_STOP (TC_TIMER | 0x0003) + +#define TC_OUT 0x0200 +#define TC_IN 0x0100 + +/* scfconf.c */ +#define TC_PROBE 0x0001 +#define TC_ATTACH 0x0002 +#define TC_DETACH 0x0003 +#define TC_GETINFO 0x0004 + +/* scfopt.c */ +#define TC_OPEN 0x0011 +#define TC_CLOSE 0x0012 +#define TC_IOCTL 0x0013 +#define TC_CHPOLL 0x0014 + +/* scfhandler.c */ +#define TC_INTR 0x0021 +#define TC_DSENS 0x0022 +#define TC_SHUTDOWN 0x0023 + +/* scfreg.c scfhandler.c */ +#define TC_SEND 0x0031 +#define TC_RSTS 0x0032 + +/* kernel function code */ +#define TC_SIGNAL 0x0041 +#define TC_W_SIG 0x0042 +#define TC_T_WAIT 0x0043 +#define TC_KILL 0x004f + +/* DSCP function code */ +#define TC_MB_INIT 0x0081 +#define TC_MB_FINI 0x0082 +#define TC_MB_PUTMSG 0x0083 +#define TC_MB_CANGET 0x0084 +#define TC_MB_GETMSG 0x0085 +#define TC_MB_FLUSH 0x0086 +#define TC_MB_CTRL 0x0087 +#define TC_MB_INTR 0x0088 +#define TC_MB_CALLBACK 0x0089 + +#define TC_TxREQ 0x00a1 +#define TC_RxACK 0x00a5 +#define TC_RxEND 0x00a6 +#define TC_RxREQ 0x00a4 +#define TC_TxACK 0x00a2 +#define TC_TxEND 0x00a3 + +/* OS to SCF function code */ +#define TC_S_PUTINFO 0x0091 +#define TC_S_GETINFO 0x0092 + +/* + * SCF driver trace flag + */ +extern ushort_t scf_trace_exec; /* 1:trace exec, 0:Trace no exec */ +extern ushort_t scf_trace_flag; + +/* + * SCF driver trace debug flag + */ +extern uint_t scf_trace_msg_flag; /* trace massege flag */ + +/* + * External function + */ +extern void scf_trace(ushort_t code, ushort_t line, + uchar_t *info, ushort_t size); + +#ifdef __cplusplus +} +#endif + +#endif /* _SCFTRACE_H */ diff --git a/usr/src/uts/sun4u/opl/unix/Makefile b/usr/src/uts/sun4u/opl/unix/Makefile new file mode 100644 index 0000000000..0be4aed67f --- /dev/null +++ b/usr/src/uts/sun4u/opl/unix/Makefile @@ -0,0 +1,191 @@ +# +# 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. +# +# ident "%Z%%M% %I% %E% SMI" +# +# This makefile drives the production of unix (and unix.o). +# +# sun4u opl implementation architecture dependent +# +# uts/sun4u/opl/unix/Makefile +# + +# +# Path to the base of the uts directory tree (usually /usr/src/uts). +# +UTSBASE = ../../.. + +# +# Define the module and object file sets. +# +UNIX = unix +OBJECTS = $(SPECIAL_OBJS:%=$(OBJS_DIR)/%) \ + $(CORE_OBJS:%=$(OBJS_DIR)/%) \ + $(MACH_NOT_YET_KMODS:%=$(OBJS_DIR)/%) +LINTS = $(SPECIAL_OBJS:%.o=$(LINTS_DIR)/%.ln) \ + $(CORE_OBJS:%.o=$(LINTS_DIR)/%.ln) \ + $(MACH_NOT_YET_KMODS:%.o=$(LINTS_DIR)/%.ln) \ + $(LINTS_DIR)/vers.ln \ + $(LINTS_DIR)/modstubs.ln +ROOTMODULE = $(ROOT_OPL_KERN_DIR)/$(UNIX) +UNIX_BIN = $(OBJS_DIR)/$(UNIX) + +KRTLD_32 = misc/krtld +KRTLD_64 = misc/$(SUBDIR64)/krtld +KRTLD = $(KRTLD_$(CLASS)) + +LIBS = $(GENLIB) $(PLATLIB) $(CPULIB) + +GENUNIX = genunix +GENUNIX_DIR = ../../$(GENUNIX) +GENOPTS = -L $(GENUNIX_DIR)/$(OBJS_DIR) -l $(GENUNIX) + +CPU_DIR = . +CPUOPTS = -L $(CPU_DIR)/$(OBJS_DIR) -l $(CPUNAME) + +PLAT_DIR = ../../platmod +PLATOPTS = -L $(PLAT_DIR)/$(OBJS_DIR) -l $(PLATMOD) + +LIBOPTS = $(GENOPTS) $(PLATOPTS) $(CPUOPTS) + +CTFEXTRAOBJS = $(OBJS_DIR)/vers.o + +# +# Include common rules. +# +include $(UTSBASE)/sun4u/opl/Makefile.opl + +# +# Define targets +# +ALL_TARGET = $(UNIX_BIN) +LINT_TARGET = $(LINT_LIB) +INSTALL_TARGET = $(UNIX_BIN) $(ROOTMODULE) + +# +# Overrides +# +ALL_BUILDS = $(ALL_BUILDSONLY64) +DEF_BUILDS = $(DEF_BUILDSONLY64) +SYM_BUILDS = $(DEF_BUILDSONLY64) +CLEANLINTFILES += $(LINT32_FILES) + +# +# This is UNIX_DIR. Use a short path. +# +UNIX_DIR = . + +# +# Overrides +# +CLEANFILES += $(UNIX_O) $(MODSTUBS_O) $(OBJS_DIR)/vers.c \ + $(OBJS_DIR)/vers.o $(CPU_OBJ) $(CPULIB) \ + $(DTRACESTUBS_O) $(DTRACESTUBS) + +CLOBBERFILES = $(CLEANFILES) $(UNIX_BIN) +CLEANLINTFILES += $(LINT_LIB) + +# +# lint pass one enforcement +# Turn on doubleword alignment for 64 bit counter timer registers +# +CFLAGS += $(CCVERBOSE) -dalign + +# +# Default build targets. +# +.KEEP_STATE: + +all: $(ALL_DEPS) + +def: $(DEF_DEPS) + +clean: $(CLEAN_DEPS) + +clobber: $(CLOBBER_DEPS) + +lint: $(LINT_DEPS) + +clean.lint: $(CLEAN_LINT_DEPS) + +install: $(INSTALL_DEPS) + +symcheck: $(SYM_DEPS) + +$(UNIX_BIN): $(UNIX_O) $(MODSTUBS_O) $(MAPFILE) $(LIBS) $(DTRACESTUBS) + $(LD) -dy -b -o $@ -e _start -I $(KRTLD) -M $(MAPFILE) \ + $(UNIX_O) $(MODSTUBS_O) $(LIBOPTS) $(DTRACESTUBS) + $(CTFMERGE_UNIQUIFY_AGAINST_GENUNIX) + $(POST_PROCESS) + +symcheck.targ: $(UNIX_O) $(MODSTUBS_O) $(LIBS) $(DTRACESTUBS) + $(LD) -dy -b -o $(SYM_MOD) -M $(MAPFILE) \ + $(UNIX_O) $(MODSTUBS_O) $(LIBOPTS) $(DTRACESTUBS) + +$(UNIX_O): $(OBJECTS) $(OBJS_DIR)/vers.o + $(LD) -r -o $@ $(OBJECTS) $(OBJS_DIR)/vers.o + +# +# Special rules for generating assym.h for inclusion in assembly files. +# +$(DSF_DIR)/$(OBJS_DIR)/assym.h: FRC + @cd $(DSF_DIR); pwd; $(MAKE) all.targ + +$(GENLIB): FRC + @(cd $(GENLIB_DIR); pwd; $(MAKE) all.targ) + @pwd + +$(PLATLIB): + ?@(cd $(PLAT_DIR); pwd; $(MAKE) all.targ) + ?@pwd + +# +# CPU_OBJ now comprises of 2 object files which come from sun4 common +# and from architecture dependent code. OBJS_DIR is prepended where +# CPU_OBJ is defined to allow for building multiple CPU_OBJ's +# +$(CPULIB): $(CPU_OBJ) + $(LD) -o $@ -G -h 'cpu/$$CPU' $(CPU_OBJ) + +# +# The global lint target builds the kernel lint library (llib-lunix.ln) +# which is equivalent to a lint of /unix.o. Then all kernel modules for +# this architecture are linted against the kernel lint library. +# +# Note: lint errors in the kernel lint library will be repeated for +# each module. It is important that the kernel lint library +# be clean to keep the textual output to a reasonable level. +# + +$(LINT_LIB): $(LINT_LIB_DIR) $(LINTS) + @-$(ECHO) "\n$(UNIX): (library construction):" + @$(LINT) -o $(UNIX) $(LINTFLAGS) $(LINTS) + @$(MV) $(@F) $@ + +lintlib: $(LINT_DEPS) + +# +# Include common targets. +# +include $(UTSBASE)/sun4u/opl/Makefile.targ diff --git a/usr/src/uts/sun4u/opl_cfg/Makefile b/usr/src/uts/sun4u/opl_cfg/Makefile new file mode 100644 index 0000000000..88416310b1 --- /dev/null +++ b/usr/src/uts/sun4u/opl_cfg/Makefile @@ -0,0 +1,103 @@ +# +# 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/sun4u/opl_cfg/Makefile +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# +# This makefile drives the production of the opl_cfg Jupiter Bus +# Configurator +# +# sun4u implementation architecture dependent +# + +# +# Path to the base of the uts directory tree (usually /usr/src/uts). +# +UTSBASE = ../.. + +# +# Define the module and object file sets. +# +MODULE = opl_cfg +OBJECTS = $(OPLCFG_OBJS:%=$(OBJS_DIR)/%) +LINTS = $(OPLCFG_OBJS:%.o=$(LINTS_DIR)/%.ln) +ROOTMODULE = $(ROOT_PSM_MISC_DIR)/$(MODULE) + +# +# Include common rules. +# +include $(UTSBASE)/sun4u/Makefile.sun4u + +# +# Define targets +# +ALL_TARGET = $(BINARY) +LINT_TARGET = $(MODULE).lint +INSTALL_TARGET = $(BINARY) $(ROOTMODULE) + +# +# lint pass one enforcement +# +CFLAGS += $(CCVERBOSE) + +# +# module dependencies +# +LDFLAGS += -dy -Nmisc/fcodem -Nmisc/busra + +# +# OPL specific header files +# +INC_PATH += -I$(UTSBASE)/sun4u/opl/ +# +# Turn on doubleword alignment for 64 bit registers +# +CFLAGS += -dalign + +# +# 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)/sun4u/Makefile.targ diff --git a/usr/src/uts/sun4u/opl_pcbe/Makefile b/usr/src/uts/sun4u/opl_pcbe/Makefile new file mode 100644 index 0000000000..51a9c171e7 --- /dev/null +++ b/usr/src/uts/sun4u/opl_pcbe/Makefile @@ -0,0 +1,84 @@ +# +# 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. +# +#ident "%Z%%M% %I% %E% SMI" +# +# uts/sun4u/opl_pcbe/Makefile +# +# This Makefile builds the SPARC64 VI Performance Counter BackEnd (PCBE). +# + +UTSBASE = ../.. + +# +# Define module and object file sets. +# +MODULE = pcbe.4.6 +OBJECTS = $(OPL_PCBE_OBJS:%=$(OBJS_DIR)/%) +LINTS = $(OPL_PCBE_OBJS:%.o=$(LINTS_DIR)/%.ln) +ROOTMODULE = $(USR_PCBE_DIR)/$(MODULE) + +# +# Include common rules. +# +include $(UTSBASE)/sun4u/Makefile.sun4u + +# +# Define targets. +# +ALL_TARGET = $(BINARY) +LINT_MODULE = opl_pcbe +LINT_TARGET = $(LINT_MODULE).lint +INSTALL_TARGET = $(BINARY) $(ROOTMODULE) + +# +# lint pass one enforcement +# +CFLAGS += $(CCVERBOSE) + +# +# Default build targets. +# +.KEEP_STATE: + +all: $(ALL_DEPS) + +def: $(DEF_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)/sun4u/Makefile.targ diff --git a/usr/src/uts/sun4u/os/cmp.c b/usr/src/uts/sun4u/os/cmp.c index 792ccddc6f..22f7a0a772 100644 --- a/usr/src/uts/sun4u/os/cmp.c +++ b/usr/src/uts/sun4u/os/cmp.c @@ -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. @@ -88,9 +87,11 @@ cmp_delete_cpu(processorid_t cpuid) * Register is set to either the lowest numbered on-line sibling core, if * one exists, or else to this core. */ +/* ARGSUSED */ void cmp_error_resteer(processorid_t cpuid) { +#ifndef _CMP_NO_ERROR_STEERING cpuset_t mycores; cpu_t *cpu; chipid_t chipid; @@ -120,6 +121,10 @@ cmp_error_resteer(processorid_t cpuid) if (i == NCPU) { xc_one(cpuid, (xcfunc_t *)set_cmp_error_steering, 0, 0); } +#else + /* Not all CMP's support (e.g. Olympus-C by Fujitsu) error steering */ + return; +#endif /* _CMP_NO_ERROR_STEERING */ } chipid_t @@ -147,12 +152,27 @@ chip_plat_get_chipid(cpu_t *cp) } /* - * We don't have any multi-threaded cores on sun4u yet. + * Return the "core id" for the given cpu_t + * The "core id" space spans uniquely across all + * cpu chips. */ id_t chip_plat_get_coreid(cpu_t *cp) { - return (cp->cpu_id); + int impl; + + impl = cpunodes[cp->cpu_id].implementation; + + if (IS_OLYMPUS_C(impl)) { + /* + * Currently only Fujitsu Olympus-c processor supports + * multi-stranded cores. Return the cpu_id with + * the strand bit masked out. + */ + return ((id_t)((uint_t)cp->cpu_id & ~(0x1))); + } else { + return (cp->cpu_id); + } } void @@ -167,7 +187,7 @@ chip_plat_define_chip(cpu_t *cp, chip_def_t *cd) if (IS_JAGUAR(impl)) { cd->chipd_type = CHIP_CMP_SPLIT_CACHE; - } else if (IS_PANTHER(impl)) { + } else if (IS_PANTHER(impl) || IS_OLYMPUS_C(impl)) { cd->chipd_type = CHIP_CMP_SHARED_CACHE; } else { cd->chipd_type = CHIP_DEFAULT; diff --git a/usr/src/uts/sun4u/os/cpr_impl.c b/usr/src/uts/sun4u/os/cpr_impl.c index d3b451381e..b66b18d098 100644 --- a/usr/src/uts/sun4u/os/cpr_impl.c +++ b/usr/src/uts/sun4u/os/cpr_impl.c @@ -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,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -1714,7 +1713,7 @@ i_cpr_prom_pages(int action) static void i_cpr_save_tlbinfo(void) { - cti_t cti; + cti_t cti = {0}; /* * during resume - shortly after jumping into the cpr module, @@ -1731,8 +1730,13 @@ i_cpr_save_tlbinfo(void) cti.writer = NULL; cti.filter = i_cpr_lnb; cti.index = cpunodes[CPU->cpu_id].dtlb_size - 1; - cti.skip = (1 << utsb_dtlb_ttenum); - cti.skip |= (1 << utsb4m_dtlb_ttenum); + + if (utsb_dtlb_ttenum != -1) + cti.skip = (1 << utsb_dtlb_ttenum); + + if (utsb4m_dtlb_ttenum != -1) + cti.skip |= (1 << utsb4m_dtlb_ttenum); + i_cpr_scan_tlb(&cti); i_cpr_make_tte(&cti, &i_cpr_data_page, datava); i_cpr_make_tte(&cti, curthread, datava); diff --git a/usr/src/uts/sun4u/os/fillsysinfo.c b/usr/src/uts/sun4u/os/fillsysinfo.c index fcdfbf7fed..5ab2acb13d 100644 --- a/usr/src/uts/sun4u/os/fillsysinfo.c +++ b/usr/src/uts/sun4u/os/fillsysinfo.c @@ -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,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -357,7 +356,9 @@ int get_portid(pnode_t node, pnode_t *cmpp) { int portid; + int i; char dev_type[OBP_MAXPROPNAME]; + pnode_t cpu_parent; if (cmpp != NULL) *cmpp = OBP_NONODE; @@ -369,14 +370,24 @@ get_portid(pnode_t node, pnode_t *cmpp) if (GETPROP(node, "device_type", (caddr_t)&dev_type) == -1) return (-1); - /* On a CMP core, the "portid" is in the parent */ + /* + * For a virtual cpu node that is a CMP core, the "portid" + * is in the parent node. + * For a virtual cpu node that is a CMT strand, the "portid" is + * in its grandparent node. + * So we iterate up as far as 2 levels to get the "portid". + */ if (strcmp(dev_type, "cpu") == 0) { - node = prom_parentnode(node); - if (GETPROP(node, "portid", (caddr_t)&portid) != -1) { - if (cmpp != NULL) - *cmpp = node; - - return (portid); + cpu_parent = node = prom_parentnode(node); + for (i = 0; i < 2; i++) { + if (node == OBP_NONODE || node == OBP_BADNODE) + break; + if (GETPROP(node, "portid", (caddr_t)&portid) != -1) { + if (cmpp != NULL) + *cmpp = cpu_parent; + return (portid); + } + node = prom_parentnode(node); } } @@ -458,6 +469,7 @@ fill_cpu(pnode_t node) cpunode = &cpunodes[cpuid]; cpunode->portid = portid; + cpunode->nodeid = node; if (cpu_get_cpu_unum(cpuid, unum, UNUM_NAMLEN, &size) != 0) { cpunode->fru_fmri[0] = '\0'; @@ -466,10 +478,24 @@ fill_cpu(pnode_t node) "%s%s", CPU_FRU_FMRI, unum); } + if (cmpnode) { + /* + * For the CMT case, the parent "core" node contains + * properties needed below, use it instead of the + * cpu node. + */ + if ((GETPROP(cmpnode, "device_type", namebuf) > 0) && + (strcmp(namebuf, "core") == 0)) { + node = cmpnode; + } + } + (void) GETPROP(node, (cmpnode ? "compatible" : "name"), namebuf); namebufp = namebuf; if (strncmp(namebufp, "SUNW,", 5) == 0) namebufp += 5; + else if (strncmp(namebufp, "FJSV,", 5) == 0) + namebufp += 5; (void) strcpy(cpunode->name, namebufp); (void) GETPROP(node, "implementation#", @@ -507,8 +533,6 @@ fill_cpu(pnode_t node) ASSERT(tlbsize < USHRT_MAX); /* since we cast it */ cpunode->dtlb_size = (ushort_t)tlbsize; - cpunode->nodeid = node; - if (cmpnode != OBP_NONODE) { /* * If the CPU has a level 3 cache, then it will be the @@ -580,32 +604,42 @@ int get_portid_ddi(dev_info_t *dip, dev_info_t **cmpp) { int portid; + int i; char dev_type[OBP_MAXPROPNAME]; int len = OBP_MAXPROPNAME; + dev_info_t *cpu_parent; if (cmpp != NULL) *cmpp = NULL; if ((portid = ddi_prop_get_int(DDI_DEV_T_ANY, dip, - DDI_PROP_DONTPASS, "portid", -1)) != -1) + DDI_PROP_DONTPASS, "portid", -1)) != -1) return (portid); if ((portid = ddi_prop_get_int(DDI_DEV_T_ANY, dip, - DDI_PROP_DONTPASS, "upa-portid", -1)) != -1) + DDI_PROP_DONTPASS, "upa-portid", -1)) != -1) return (portid); if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF, - DDI_PROP_DONTPASS, "device_type", (caddr_t)dev_type, - &len) != 0) + DDI_PROP_DONTPASS, "device_type", (caddr_t)dev_type, + &len) != 0) return (-1); - /* On a CMP core, the "portid" is in the parent */ + /* + * For a virtual cpu node that is a CMP core, the "portid" + * is in the parent node. + * For a virtual cpu node that is a CMT strand, the "portid" is + * in its grandparent node. + * So we iterate up as far as 2 levels to get the "portid". + */ if (strcmp(dev_type, "cpu") == 0) { - dip = ddi_get_parent(dip); - if ((portid = ddi_prop_get_int(DDI_DEV_T_ANY, dip, - DDI_PROP_DONTPASS, "portid", -1)) != -1) { - if (cmpp != NULL) - *cmpp = dip; - - return (portid); + cpu_parent = dip = ddi_get_parent(dip); + for (i = 0; dip != NULL && i < 2; i++) { + if ((portid = ddi_prop_get_int(DDI_DEV_T_ANY, dip, + DDI_PROP_DONTPASS, "portid", -1)) != -1) { + if (cmpp != NULL) + *cmpp = cpu_parent; + return (portid); + } + dip = ddi_get_parent(dip); } } @@ -618,7 +652,6 @@ get_portid_ddi(dev_info_t *dip, dev_info_t **cmpp) * since it is called very early in the boot cycle before (before * setup_ddi()). Sigh...someday this will all be cleaned up. */ - void fill_cpu_ddi(dev_info_t *dip) { @@ -626,11 +659,12 @@ fill_cpu_ddi(dev_info_t *dip) struct cpu_node *cpunode; processorid_t cpuid; int portid; - int len; + int len = OBP_MAXPROPNAME; int tlbsize; dev_info_t *cmpnode; char namebuf[OBP_MAXPROPNAME], unum[UNUM_NAMLEN]; char *namebufp; + char dev_type[OBP_MAXPROPNAME]; if ((portid = get_portid_ddi(dip, &cmpnode)) == -1) { cmn_err(CE_PANIC, "portid not found"); @@ -649,6 +683,20 @@ fill_cpu_ddi(dev_info_t *dip) cpunode = &cpunodes[cpuid]; cpunode->portid = portid; + cpunode->nodeid = ddi_get_nodeid(dip); + + if (cmpnode != NULL) { + /* + * For the CMT case, the parent "core" node contains + * properties needed below, use it instead of the + * cpu node. + */ + if ((ddi_prop_op(DDI_DEV_T_ANY, cmpnode, PROP_LEN_AND_VAL_BUF, + DDI_PROP_DONTPASS, "device_type", + (caddr_t)dev_type, &len) == DDI_PROP_SUCCESS) && + (strcmp(dev_type, "core") == 0)) + dip = cmpnode; + } if (cpu_get_cpu_unum(cpuid, unum, UNUM_NAMLEN, &len) != 0) { cpunode->fru_fmri[0] = '\0'; @@ -665,6 +713,8 @@ fill_cpu_ddi(dev_info_t *dip) namebufp = namebuf; if (strncmp(namebufp, "SUNW,", 5) == 0) namebufp += 5; + else if (strncmp(namebufp, "FJSV,", 5) == 0) + namebufp += 5; (void) strcpy(cpunode->name, namebufp); cpunode->implementation = ddi_prop_get_int(DDI_DEV_T_ANY, dip, @@ -678,7 +728,7 @@ fill_cpu_ddi(dev_info_t *dip) cpunode->version = REMAP_CHEETAH_MASK(cpunode->version); } - cpunode->clock_freq = ddi_prop_get_int(DDI_DEV_T_ANY, dip, + cpunode->clock_freq = (uint32_t)ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "clock-frequency", 0); ASSERT(cpunode->clock_freq != 0); @@ -700,8 +750,6 @@ fill_cpu_ddi(dev_info_t *dip) ASSERT(tlbsize < USHRT_MAX); /* since we cast it */ cpunode->dtlb_size = (ushort_t)tlbsize; - cpunode->nodeid = ddi_get_nodeid(dip); - if (cmpnode != NULL) { /* * If the CPU has a level 3 cache, then that is it's diff --git a/usr/src/uts/sun4u/os/mach_startup.c b/usr/src/uts/sun4u/os/mach_startup.c index 1b09512a33..816a93c19c 100644 --- a/usr/src/uts/sun4u/os/mach_startup.c +++ b/usr/src/uts/sun4u/os/mach_startup.c @@ -29,6 +29,7 @@ #include <sys/archsystm.h> #include <sys/vm.h> #include <sys/cpu.h> +#include <sys/cpupart.h> #include <sys/atomic.h> #include <sys/reboot.h> #include <sys/kdi.h> @@ -71,6 +72,22 @@ struct fpras_chkfngrp *fpras_chkfngrps_base; int fpras_frequency = -1; int64_t fpras_interval = -1; +/* + * Halt idling cpus optimization + * + * This optimation is only enabled in platforms that have + * the CPU halt support. The cpu_halt_cpu() support is provided + * in the cpu module and it is referenced here with a pragma weak. + * The presence of this routine automatically enable the halt idling + * cpus functionality if the global switch enable_halt_idle_cpus + * is set (default is set). + * + */ +#pragma weak cpu_halt_cpu +extern void cpu_halt_cpu(); + +int enable_halt_idle_cpus = 1; /* global switch */ + void setup_trap_table(void) { @@ -174,18 +191,206 @@ mach_memscrub(void) * Startup memory scrubber, if not running fpu emulation code. */ +#ifndef _HW_MEMSCRUB_SUPPORT if (fpu_exists) { if (memscrub_init()) { cmn_err(CE_WARN, "Memory scrubber failed to initialize"); } } +#endif /* _HW_MEMSCRUB_SUPPORT */ +} + +/* + * Halt the calling CPU until awoken via an interrupt + * This routine should only be invoked if cpu_halt_cpu() + * exists and is supported, see mach_cpu_halt_idle() + */ +static void +cpu_halt(void) +{ + cpu_t *cpup = CPU; + processorid_t cpun = cpup->cpu_id; + cpupart_t *cp = cpup->cpu_part; + int hset_update = 1; + uint_t pstate; + extern uint_t getpstate(void); + extern void setpstate(uint_t); + + /* + * If this CPU is online, and there's multiple CPUs + * in the system, then we should notate our halting + * by adding ourselves to the partition's halted CPU + * bitmap. This allows other CPUs to find/awaken us when + * work becomes available. + */ + if (CPU->cpu_flags & CPU_OFFLINE || ncpus == 1) + hset_update = 0; + + /* + * Add ourselves to the partition's halted CPUs bitmask + * and set our HALTED flag, if necessary. + * + * When a thread becomes runnable, it is placed on the queue + * and then the halted cpuset is checked to determine who + * (if anyone) should be awoken. We therefore need to first + * add ourselves to the halted cpuset, and then check if there + * is any work available. + */ + if (hset_update) { + cpup->cpu_disp_flags |= CPU_DISP_HALTED; + membar_producer(); + CPUSET_ATOMIC_ADD(cp->cp_haltset, cpun); + } + + /* + * Check to make sure there's really nothing to do. + * Work destined for this CPU may become available after + * this check. We'll be notified through the clearing of our + * bit in the halted CPU bitmask, and a poke. + */ + if (disp_anywork()) { + if (hset_update) { + cpup->cpu_disp_flags &= ~CPU_DISP_HALTED; + CPUSET_ATOMIC_DEL(cp->cp_haltset, cpun); + } + return; + } + + /* + * We're on our way to being halted. + * + * Disable interrupts now, so that we'll awaken immediately + * after halting if someone tries to poke us between now and + * the time we actually halt. + * + * We check for the presence of our bit after disabling interrupts. + * If it's cleared, we'll return. If the bit is cleared after + * we check then the poke will pop us out of the halted state. + * + * The ordering of the poke and the clearing of the bit by cpu_wakeup + * is important. + * cpu_wakeup() must clear, then poke. + * cpu_halt() must disable interrupts, then check for the bit. + */ + pstate = getpstate(); + setpstate(pstate & ~PSTATE_IE); + + if (hset_update && !CPU_IN_SET(cp->cp_haltset, cpun)) { + cpup->cpu_disp_flags &= ~CPU_DISP_HALTED; + setpstate(pstate); + return; + } + + /* + * The check for anything locally runnable is here for performance + * and isn't needed for correctness. disp_nrunnable ought to be + * in our cache still, so it's inexpensive to check, and if there + * is anything runnable we won't have to wait for the poke. + */ + if (cpup->cpu_disp->disp_nrunnable != 0) { + if (hset_update) { + cpup->cpu_disp_flags &= ~CPU_DISP_HALTED; + CPUSET_ATOMIC_DEL(cp->cp_haltset, cpun); + } + setpstate(pstate); + return; + } + + /* + * Halt the strand. + */ + if (&cpu_halt_cpu) + cpu_halt_cpu(); + + /* + * We're no longer halted + */ + setpstate(pstate); + if (hset_update) { + cpup->cpu_disp_flags &= ~CPU_DISP_HALTED; + CPUSET_ATOMIC_DEL(cp->cp_haltset, cpun); + } +} + +/* + * If "cpu" is halted, then wake it up clearing its halted bit in advance. + * Otherwise, see if other CPUs in the cpu partition are halted and need to + * be woken up so that they can steal the thread we placed on this CPU. + * This function is only used on MP systems. + * This function should only be invoked if cpu_halt_cpu() + * exists and is supported, see mach_cpu_halt_idle() + */ +static void +cpu_wakeup(cpu_t *cpu, int bound) +{ + uint_t cpu_found; + int result; + cpupart_t *cp; + + cp = cpu->cpu_part; + if (CPU_IN_SET(cp->cp_haltset, cpu->cpu_id)) { + /* + * Clear the halted bit for that CPU since it will be + * poked in a moment. + */ + CPUSET_ATOMIC_DEL(cp->cp_haltset, cpu->cpu_id); + /* + * We may find the current CPU present in the halted cpuset + * if we're in the context of an interrupt that occurred + * before we had a chance to clear our bit in cpu_halt(). + * Poking ourself is obviously unnecessary, since if + * we're here, we're not halted. + */ + if (cpu != CPU) + poke_cpu(cpu->cpu_id); + return; + } else { + /* + * This cpu isn't halted, but it's idle or undergoing a + * context switch. No need to awaken anyone else. + */ + if (cpu->cpu_thread == cpu->cpu_idle_thread || + cpu->cpu_disp_flags & CPU_DISP_DONTSTEAL) + return; + } + + /* + * No need to wake up other CPUs if the thread we just enqueued + * is bound. + */ + if (bound) + return; + + /* + * See if there's any other halted CPUs. If there are, then + * select one, and awaken it. + * It's possible that after we find a CPU, somebody else + * will awaken it before we get the chance. + * In that case, look again. + */ + do { + CPUSET_FIND(cp->cp_haltset, cpu_found); + if (cpu_found == CPUSET_NOTINSET) + return; + + ASSERT(cpu_found >= 0 && cpu_found < NCPU); + CPUSET_ATOMIC_XDEL(cp->cp_haltset, cpu_found, result); + } while (result < 0); + + if (cpu_found != CPU->cpu_id) + poke_cpu(cpu_found); } void mach_cpu_halt_idle() { - /* no suport for halting idle CPU */ + if (enable_halt_idle_cpus) { + if (&cpu_halt_cpu) { + idle_cpu = cpu_halt; + disp_enq_thread = cpu_wakeup; + } + } } /*ARGSUSED*/ diff --git a/usr/src/uts/sun4u/pcbe/opl_pcbe.c b/usr/src/uts/sun4u/pcbe/opl_pcbe.c new file mode 100644 index 0000000000..084043e38e --- /dev/null +++ b/usr/src/uts/sun4u/pcbe/opl_pcbe.c @@ -0,0 +1,619 @@ +/* + * 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. + */ + +/* + * SPARC64 VI Performance Counter Backend + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/cpuvar.h> +#include <sys/systm.h> +#include <sys/cmn_err.h> +#include <sys/cpc_impl.h> +#include <sys/cpc_pcbe.h> +#include <sys/modctl.h> +#include <sys/machsystm.h> +#include <sys/sdt.h> +#include <sys/cpu_impl.h> + +static int opl_pcbe_init(void); +static uint_t opl_pcbe_ncounters(void); +static const char *opl_pcbe_impl_name(void); +static const char *opl_pcbe_cpuref(void); +static char *opl_pcbe_list_events(uint_t picnum); +static char *opl_pcbe_list_attrs(void); +static uint64_t opl_pcbe_event_coverage(char *event); +static uint64_t opl_pcbe_overflow_bitmap(void); +static int opl_pcbe_configure(uint_t picnum, char *event, uint64_t preset, + uint32_t flags, uint_t nattrs, kcpc_attr_t *attrs, void **data, + void *token); +static void opl_pcbe_program(void *token); +static void opl_pcbe_allstop(void); +static void opl_pcbe_sample(void *token); +static void opl_pcbe_free(void *config); + +extern void ultra_setpcr(uint64_t); +extern uint64_t ultra_getpcr(void); +extern void ultra_setpic(uint64_t); +extern uint64_t ultra_getpic(void); +extern uint64_t ultra_gettick(void); + +pcbe_ops_t opl_pcbe_ops = { + PCBE_VER_1, + CPC_CAP_OVERFLOW_INTERRUPT, + opl_pcbe_ncounters, + opl_pcbe_impl_name, + opl_pcbe_cpuref, + opl_pcbe_list_events, + opl_pcbe_list_attrs, + opl_pcbe_event_coverage, + opl_pcbe_overflow_bitmap, + opl_pcbe_configure, + opl_pcbe_program, + opl_pcbe_allstop, + opl_pcbe_sample, + opl_pcbe_free +}; + +typedef struct _opl_pcbe_config { + uint8_t opl_picno; /* From 0 to 7 */ + uint32_t opl_bits; /* %pcr event code unshifted */ + uint32_t opl_flags; /* user/system/priv */ + uint32_t opl_pic; /* unshifted raw %pic value */ +} opl_pcbe_config_t; + +struct nametable { + const uint8_t bits; + const char *name; +}; + +#define PIC_MASK (((uint64_t)1 << 32) - 1) + +#define SPARC64_VI_PCR_PRIVPIC UINT64_C(1) + +#define CPC_SPARC64_VI_PCR_USR_SHIFT 2 +#define CPC_SPARC64_VI_PCR_SYS_SHIFT 1 + +#define CPC_SPARC64_VI_PCR_PICL_SHIFT 4 +#define CPC_SPARC64_VI_PCR_PICU_SHIFT 11 +#define CPC_SPARC64_VI_PCR_PIC_MASK UINT64_C(0x3f) + +#define CPC_SPARC64_VI_NPIC 8 + +#define CPC_SPARC64_VI_PCR_ULRO_SHIFT 3 +#define CPC_SPARC64_VI_PCR_SC_SHIFT 18 +#define CPC_SPARC64_VI_PCR_SC_MASK UINT64_C(0x7) +#define CPC_SPARC64_VI_PCR_NC_SHIFT 22 +#define CPC_SPARC64_VI_PCR_NC_MASK UINT64_C(0x7) +#define CPC_SPARC64_VI_PCR_OVRO_SHIFT 26 +#define CPC_SPARC64_VI_PCR_OVF_SHIFT 32 +#define CPC_SPARC64_VI_PCR_OVF_MASK UINT64_C(0xffff) + +#define SPARC64_VI_PCR_SYS (UINT64_C(1) << CPC_SPARC64_VI_PCR_SYS_SHIFT) +#define SPARC64_VI_PCR_USR (UINT64_C(1) << CPC_SPARC64_VI_PCR_USR_SHIFT) +#define SPARC64_VI_PCR_ULRO (UINT64_C(1) << CPC_SPARC64_VI_PCR_ULRO_SHIFT) +#define SPARC64_VI_PCR_OVRO (UINT64_C(1) << CPC_SPARC64_VI_PCR_OVRO_SHIFT) +#define SPARC64_VI_PCR_OVF (CPC_SPARC64_VI_PCR_OVF_MASK << \ + CPC_SPARC64_VI_PCR_OVF_SHIFT) + +#define SPARC64_VI_NUM_PIC_PAIRS 4 + +#define SPARC64_VI_PCR_SEL_PIC(pcr, picno) { \ + pcr &= ~((CPC_SPARC64_VI_PCR_SC_MASK \ + << CPC_SPARC64_VI_PCR_SC_SHIFT)); \ + \ + pcr |= (((picno) & CPC_SPARC64_VI_PCR_SC_MASK) \ + << CPC_SPARC64_VI_PCR_SC_SHIFT); \ +} + +#define SPARC64_VI_PCR_SEL_EVENT(pcr, sl, su) { \ + pcr &= ~((CPC_SPARC64_VI_PCR_PIC_MASK \ + << CPC_SPARC64_VI_PCR_PICL_SHIFT) \ + | (CPC_SPARC64_VI_PCR_PIC_MASK \ + << CPC_SPARC64_VI_PCR_PICU_SHIFT)); \ + \ + pcr |= (((sl) & CPC_SPARC64_VI_PCR_PIC_MASK) \ + << CPC_SPARC64_VI_PCR_PICL_SHIFT); \ + pcr |= (((su) & CPC_SPARC64_VI_PCR_PIC_MASK) \ + << CPC_SPARC64_VI_PCR_PICU_SHIFT); \ +} + +#define NT_END 0xFF + +static const uint64_t allstopped = SPARC64_VI_PCR_PRIVPIC | + SPARC64_VI_PCR_ULRO | SPARC64_VI_PCR_OVRO; + +#define SPARC64_VI_EVENTS_comm \ + {0x0, "cycle_counts"}, \ + {0x1, "instruction_counts"}, \ + {0x8, "load_store_instructions"}, \ + {0x9, "branch_instructions"}, \ + {0xa, "floating_instructions"}, \ + {0xb, "impdep2_instructions"}, \ + {0xc, "prefetch_instructions"} + +static const struct nametable SPARC64_VI_names_l0[] = { + SPARC64_VI_EVENTS_comm, + {0x16, "trap_int_vector"}, + {0x20, "write_op_uTLB"}, + {0x30, "sx_miss_wait_pf"}, + {0x31, "jbus_cpi_count"}, + {NT_END, ""} +}; + +static const struct nametable SPARC64_VI_names_u0[] = { + SPARC64_VI_EVENTS_comm, + {0x16, "trap_all"}, + {0x20, "write_if_uTLB"}, + {0x30, "sx_miss_wait_dm"}, + {0x31, "jbus_bi_count"}, + {NT_END, ""} +}; + +static const struct nametable SPARC64_VI_names_l1[] = { + SPARC64_VI_EVENTS_comm, + {0x16, "trap_spill"}, + {0x20, "write_op_uTLB"}, + {0x30, "sx_miss_count_pf"}, + {0x31, "jbus_cpd_count"}, + {NT_END, ""} +}; + +static const struct nametable SPARC64_VI_names_u1[] = { + SPARC64_VI_EVENTS_comm, + {0x16, "trap_int_level"}, + {0x20, "write_if_uTLB"}, + {0x30, "sx_miss_count_dm"}, + {0x31, "jbus_cpb_count"}, + {NT_END, ""} +}; + +static const struct nametable SPARC64_VI_names_l2[] = { + SPARC64_VI_EVENTS_comm, + {0x16, "trap_trap_inst"}, + {0x20, "op_r_iu_req_mi_go"}, + {0x30, "sx_read_count_pf"}, + {NT_END, ""} +}; + +static const struct nametable SPARC64_VI_names_u2[] = { + SPARC64_VI_EVENTS_comm, + {0x16, "trap_fill"}, + {0x20, "if_r_iu_req_mi_go"}, + {0x30, "sx_read_count_dm"}, + {NT_END, ""} +}; + +static const struct nametable SPARC64_VI_names_l3[] = { + SPARC64_VI_EVENTS_comm, + {0x16, "trap_DMMU_miss"}, + {0x20, "op_wait_all"}, + {0x30, "dvp_count_pf"}, + {NT_END, ""} +}; + +static const struct nametable SPARC64_VI_names_u3[] = { + SPARC64_VI_EVENTS_comm, + {0x16, "trap_IMMU_miss"}, + {0x20, "if_wait_all"}, + {0x30, "dvp_count_dm"}, + {NT_END, ""} +}; + +#undef SPARC64_VI_EVENTS_comm + +static const struct nametable *SPARC64_VI_names[CPC_SPARC64_VI_NPIC] = { + SPARC64_VI_names_l0, + SPARC64_VI_names_u0, + SPARC64_VI_names_l1, + SPARC64_VI_names_u1, + SPARC64_VI_names_l2, + SPARC64_VI_names_u2, + SPARC64_VI_names_l3, + SPARC64_VI_names_u3 +}; + +opl_pcbe_config_t nullpic[CPC_SPARC64_VI_NPIC] = { + {0, 0x3f, 0, 0}, + {1, 0x3f, 0, 0}, + {2, 0x3f, 0, 0}, + {3, 0x3f, 0, 0}, + {4, 0x3f, 0, 0}, + {5, 0x3f, 0, 0}, + {6, 0x3f, 0, 0}, + {7, 0x3f, 0, 0} +}; + +static const struct nametable **events; +static const char *opl_impl_name; +static const char *opl_cpuref; +static char *pic_events[CPC_SPARC64_VI_NPIC]; + +static const char *sp_6_ref = "See the \"SPARC64 VI User's Manual\" " + "for descriptions of these events."; + +static int +opl_pcbe_init(void) +{ + const struct nametable *n; + int i; + size_t size; + + /* + * Discover type of CPU + * + * Point nametable to that CPU's table + */ + switch (ULTRA_VER_IMPL(ultra_getver())) { + case OLYMPUS_C_IMPL: + events = SPARC64_VI_names; + opl_impl_name = "SPARC64 VI"; + opl_cpuref = sp_6_ref; + break; + default: + return (-1); + } + + /* + * Initialize the list of events for each PIC. + * Do two passes: one to compute the size necessary and another + * to copy the strings. Need room for event, comma, and NULL terminator. + */ + for (i = 0; i < CPC_SPARC64_VI_NPIC; i++) { + size = 0; + for (n = events[i]; n->bits != NT_END; n++) + size += strlen(n->name) + 1; + pic_events[i] = kmem_alloc(size + 1, KM_SLEEP); + *pic_events[i] = '\0'; + for (n = events[i]; n->bits != NT_END; n++) { + (void) strcat(pic_events[i], n->name); + (void) strcat(pic_events[i], ","); + } + /* + * Remove trailing comma. + */ + pic_events[i][size - 1] = '\0'; + } + + return (0); +} + +static uint_t +opl_pcbe_ncounters(void) +{ + return (CPC_SPARC64_VI_NPIC); +} + +static const char * +opl_pcbe_impl_name(void) +{ + return (opl_impl_name); +} + +static const char * +opl_pcbe_cpuref(void) +{ + return (opl_cpuref); +} + +static char * +opl_pcbe_list_events(uint_t picnum) +{ + ASSERT(picnum >= 0 && picnum < cpc_ncounters); + + return (pic_events[picnum]); +} + +static char * +opl_pcbe_list_attrs(void) +{ + return (""); +} + +static const struct nametable * +find_event(int regno, char *name) +{ + const struct nametable *n; + + n = events[regno]; + + for (; n->bits != NT_END; n++) + if (strcmp(name, n->name) == 0) + return (n); + + return (NULL); +} + +static uint64_t +opl_pcbe_event_coverage(char *event) +{ + uint64_t bitmap = 0; + + int i; + for (i = 0; i < CPC_SPARC64_VI_NPIC; i++) { + if (find_event(i, event) != NULL) + bitmap |= (1 << i); + } + + return (bitmap); +} + +/* + * XXX: Need to check if overflow bits can be cleared here. + */ +static uint64_t +opl_pcbe_overflow_bitmap(void) +{ + uint64_t pcr; + + pcr = ultra_getpcr(); + return ((pcr & SPARC64_VI_PCR_OVF) >> CPC_SPARC64_VI_PCR_OVF_SHIFT); +} + +/*ARGSUSED*/ +static int +opl_pcbe_configure(uint_t picnum, char *event, uint64_t preset, uint32_t flags, + uint_t nattrs, kcpc_attr_t *attrs, void **data, void *token) +{ + opl_pcbe_config_t *conf; + const struct nametable *n; + opl_pcbe_config_t *other_config; + + /* + * If we've been handed an existing configuration, we need only preset + * the counter value. + */ + if (*data != NULL) { + conf = *data; + conf->opl_pic = (uint32_t)preset; + return (0); + } + + if (picnum < 0 || picnum >= CPC_SPARC64_VI_NPIC) + return (CPC_INVALID_PICNUM); + + if (nattrs != 0) + return (CPC_INVALID_ATTRIBUTE); + + /* + * Find other requests that will be programmed with this one, and ensure + * the flags don't conflict. + */ + if (((other_config = kcpc_next_config(token, NULL, NULL)) != NULL) && + (other_config->opl_flags != flags)) + return (CPC_CONFLICTING_REQS); + + if ((n = find_event(picnum, event)) == NULL) + return (CPC_INVALID_EVENT); + + conf = kmem_alloc(sizeof (opl_pcbe_config_t), KM_SLEEP); + + conf->opl_picno = picnum; + conf->opl_bits = (uint32_t)n->bits; + conf->opl_flags = flags; + conf->opl_pic = (uint32_t)preset; + + *data = conf; + return (0); +} + +static void +opl_pcbe_program(void *token) +{ + opl_pcbe_config_t *pic[CPC_SPARC64_VI_NPIC]; + opl_pcbe_config_t *firstconfig; + opl_pcbe_config_t *tmp; + uint64_t pcr; + uint64_t curpic; + uint8_t bitmap = 0; /* for used pic config */ + int i; + opl_pcbe_config_t dummypic[CPC_SPARC64_VI_NPIC]; + + /* Get next pic config */ + firstconfig = tmp = kcpc_next_config(token, NULL, NULL); + + while (tmp != NULL) { + ASSERT(tmp->opl_picno < CPC_SPARC64_VI_NPIC); + ASSERT(firstconfig->opl_flags == tmp->opl_flags); + pic[tmp->opl_picno] = tmp; + bitmap |= (uint8_t)(1 << tmp->opl_picno); + tmp = kcpc_next_config(token, tmp, NULL); + } + if (bitmap == 0) + panic("opl_pcbe: token %p has no configs", token); + + /* Fill in unused pic config */ + for (i = 0; i < CPC_SPARC64_VI_NPIC; i++) { + if (bitmap & (1 << i)) + continue; + + dummypic[i] = nullpic[i]; + dummypic[i].opl_flags = firstconfig->opl_flags; + pic[i] = &nullpic[i]; + } + + /* + * For each counter pair, initialize event settings and + * counter values. + */ + ultra_setpcr(allstopped); + pcr = allstopped; + pcr &= ~SPARC64_VI_PCR_ULRO; + for (i = 0; i < SPARC64_VI_NUM_PIC_PAIRS; i++) { + SPARC64_VI_PCR_SEL_PIC(pcr, i); + SPARC64_VI_PCR_SEL_EVENT(pcr, pic[i*2]->opl_bits, + pic[i*2 + 1]->opl_bits); + + ultra_setpcr(pcr); + curpic = (uint64_t)(pic[i*2]->opl_pic | + ((uint64_t)pic[i*2 + 1]->opl_pic << 32)); + ultra_setpic(curpic); + } + + /* + * For each counter pair, enable the trace flags to start + * counting. Re-read the counters to sample the counter value now + * and use that as the baseline for future samples. + */ + + /* Set pcr */ + pcr = ultra_getpcr(); + pcr |= (SPARC64_VI_PCR_ULRO | SPARC64_VI_PCR_OVRO); + if (pic[0]->opl_flags & CPC_COUNT_USER) + pcr |= SPARC64_VI_PCR_USR; + if (pic[0]->opl_flags & CPC_COUNT_SYSTEM) + pcr |= SPARC64_VI_PCR_SYS; + + /* Set counter values */ + for (i = 0; i < SPARC64_VI_NUM_PIC_PAIRS; i++) { + SPARC64_VI_PCR_SEL_PIC(pcr, i); + SPARC64_VI_PCR_SEL_EVENT(pcr, pic[i*2]->opl_bits, + pic[i*2 + 1]->opl_bits); + + ultra_setpcr(pcr); + curpic = ultra_getpic(); + pic[i*2]->opl_pic = (uint32_t)(curpic & PIC_MASK); + pic[i*2 + 1]->opl_pic = (uint32_t)(curpic >> 32); + } + +} + +static void +opl_pcbe_allstop(void) +{ + ultra_setpcr(allstopped); +} + + +static void +opl_pcbe_sample(void *token) +{ + uint64_t curpic; + uint64_t pcr; + int64_t diff; + uint64_t *pic_data[CPC_SPARC64_VI_NPIC]; + uint64_t *dtmp; + opl_pcbe_config_t *pic[CPC_SPARC64_VI_NPIC]; + opl_pcbe_config_t *ctmp; + opl_pcbe_config_t *firstconfig; + uint8_t bitmap = 0; /* for used pic config */ + int i; + opl_pcbe_config_t dummypic[CPC_SPARC64_VI_NPIC]; + uint64_t dummypic_data[CPC_SPARC64_VI_NPIC]; + + /* Get next pic config */ + firstconfig = ctmp = kcpc_next_config(token, NULL, &dtmp); + + while (ctmp != NULL) { + ASSERT(ctmp->opl_picno < CPC_SPARC64_VI_NPIC); + ASSERT(firstconfig->opl_flags == ctmp->opl_flags); + pic[ctmp->opl_picno] = ctmp; + pic_data[ctmp->opl_picno] = dtmp; + bitmap |= (uint8_t)(1 << ctmp->opl_picno); + ctmp = kcpc_next_config(token, ctmp, &dtmp); + } + if (bitmap == 0) + panic("opl_pcbe: token %p has no configs", token); + + /* Fill in unuse pic config */ + for (i = 0; i < CPC_SPARC64_VI_NPIC; i++) { + if (bitmap & (1 << i)) + continue; + + dummypic[i] = nullpic[i]; + dummypic[i].opl_flags = firstconfig->opl_flags; + pic[i] = &dummypic[i]; + + dummypic_data[i] = 0; + pic_data[i] = &dummypic_data[i]; + } + + pcr = ultra_getpcr(); + pcr |= (SPARC64_VI_PCR_ULRO | SPARC64_VI_PCR_OVRO); + + for (i = 0; i < SPARC64_VI_NUM_PIC_PAIRS; i++) { + SPARC64_VI_PCR_SEL_PIC(pcr, i); + SPARC64_VI_PCR_SEL_EVENT(pcr, pic[i*2]->opl_bits, + pic[i*2 + 1]->opl_bits); + + ultra_setpcr(pcr); + curpic = ultra_getpic(); + + diff = (int64_t)((uint32_t)(curpic & PIC_MASK) - + pic[i*2]->opl_pic); + if (diff < 0) + diff += (1ll << 32); + *pic_data[i*2] += diff; + + diff = (int64_t)((uint32_t)(curpic >> 32) - + pic[i*2 + 1]->opl_pic); + if (diff < 0) + diff += (1ll << 32); + *pic_data[i*2 + 1] += diff; + + pic[i*2]->opl_pic = (uint32_t)(curpic & PIC_MASK); + pic[i*2 + 1]->opl_pic = (uint32_t)(curpic >> 32); + } + +} + +static void +opl_pcbe_free(void *config) +{ + kmem_free(config, sizeof (opl_pcbe_config_t)); +} + + +static struct modlpcbe modlpcbe = { + &mod_pcbeops, + "SPARC64 VI Performance Counters v%I%", + &opl_pcbe_ops +}; + +static struct modlinkage modl = { + MODREV_1, + &modlpcbe, +}; + +int +_init(void) +{ + if (opl_pcbe_init() != 0) + return (ENOTSUP); + return (mod_install(&modl)); +} + +int +_fini(void) +{ + return (mod_remove(&modl)); +} + +int +_info(struct modinfo *mi) +{ + return (mod_info(&modl, mi)); +} diff --git a/usr/src/uts/sun4u/serengeti/io/sbdp_mem.c b/usr/src/uts/sun4u/serengeti/io/sbdp_mem.c index 633ba07a6a..a11ad815a5 100644 --- a/usr/src/uts/sun4u/serengeti/io/sbdp_mem.c +++ b/usr/src/uts/sun4u/serengeti/io/sbdp_mem.c @@ -20,7 +20,7 @@ */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -1495,7 +1495,7 @@ mc_check_sibling_cpu(pnode_t nodeid) * be attempted if any of the cores are marked * as being in reset. */ - for (i = 0; i < SBD_MAX_CORES_PER_CMP; i++) { + for (i = 0; i < SBDP_MAX_CORES_PER_CMP; i++) { unit = SG_PORTID_TO_CPU_UNIT(portid, i); if (sbdp_is_cpu_present(wnode, bd, unit) && sbdp_is_cpu_in_reset(wnode, bd, unit)) { diff --git a/usr/src/uts/sun4u/serengeti/sys/sbdp_mem.h b/usr/src/uts/sun4u/serengeti/sys/sbdp_mem.h index 31fb658c84..c84e84d242 100644 --- a/usr/src/uts/sun4u/serengeti/sys/sbdp_mem.h +++ b/usr/src/uts/sun4u/serengeti/sys/sbdp_mem.h @@ -20,7 +20,7 @@ */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -38,6 +38,7 @@ extern "C" { #define SBDP_MAX_MCS_PER_NODE 4 #define SBDP_MAX_MEM_NODES_PER_BOARD 4 +#define SBDP_MAX_CORES_PER_CMP 2 typedef uint64_t mc_dc_regs_t[SBDP_MAX_MCS_PER_NODE]; diff --git a/usr/src/uts/sun4u/starcat/io/drmach.c b/usr/src/uts/sun4u/starcat/io/drmach.c index c967a81fe2..417991781b 100644 --- a/usr/src/uts/sun4u/starcat/io/drmach.c +++ b/usr/src/uts/sun4u/starcat/io/drmach.c @@ -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. @@ -2841,65 +2840,6 @@ drmach_fini(void) mutex_destroy(&drmach_i_lock); } -static struct memlist * -memlist_add_span(struct memlist *mlist, uint64_t base, uint64_t len) -{ - struct memlist *ml, *tl, *nl; - - if (len == 0ull) - return (NULL); - - if (mlist == NULL) { - mlist = GETSTRUCT(struct memlist, 1); - mlist->address = base; - mlist->size = len; - mlist->next = mlist->prev = NULL; - - return (mlist); - } - - for (tl = ml = mlist; ml; tl = ml, ml = ml->next) { - if (base < ml->address) { - if ((base + len) < ml->address) { - nl = GETSTRUCT(struct memlist, 1); - nl->address = base; - nl->size = len; - nl->next = ml; - if ((nl->prev = ml->prev) != NULL) - nl->prev->next = nl; - ml->prev = nl; - if (mlist == ml) - mlist = nl; - } else { - ml->size = MAX((base + len), - (ml->address + ml->size)) - - base; - ml->address = base; - } - break; - - } else if (base <= (ml->address + ml->size)) { - ml->size = MAX((base + len), - (ml->address + ml->size)) - - MIN(ml->address, base); - ml->address = MIN(ml->address, base); - break; - } - } - if (ml == NULL) { - nl = GETSTRUCT(struct memlist, 1); - nl->address = base; - nl->size = len; - nl->next = NULL; - nl->prev = tl; - tl->next = nl; - } - - memlist_coalesce(mlist); - - return (mlist); -} - static void drmach_mem_read_madr(drmach_mem_t *mp, int bank, uint64_t *madr) { @@ -5032,14 +4972,14 @@ sbd_error_t * drmach_board_test(drmachid_t id, drmach_opts_t *opts, int force) { drmach_board_t *bp; - drmach_device_t *dp[SBD_MAX_CORES_PER_CMP]; + drmach_device_t *dp[MAX_CORES_PER_CMP]; dr_mbox_msg_t *obufp; sbd_error_t *err; dr_testboard_reply_t tbr; int cpylen; char *copts; int is_io; - cpu_flag_t oflags[SBD_MAX_CORES_PER_CMP]; + cpu_flag_t oflags[MAX_CORES_PER_CMP]; if (!DRMACH_IS_BOARD_ID(id)) return (drerr_new(0, ESTC_INAPPROP, NULL)); @@ -5137,7 +5077,7 @@ drmach_board_test(drmachid_t id, drmach_opts_t *opts, int force) int i; mutex_enter(&cpu_lock); - for (i = 0; i < SBD_MAX_CORES_PER_CMP; i++) { + for (i = 0; i < MAX_CORES_PER_CMP; i++) { if (dp[i] != NULL) { (void) drmach_iocage_cpu_return(dp[i], oflags[i]); @@ -7641,7 +7581,7 @@ drmach_iocage_cmp_acquire(drmach_device_t **dpp, cpu_flag_t *oflags) * and attempt to acquire them. Bail out if an * error is encountered. */ - for (curr = 0; curr < SBD_MAX_CORES_PER_CMP; curr++) { + for (curr = 0; curr < MAX_CORES_PER_CMP; curr++) { /* check for the end of the list */ if (dpp[curr] == NULL) { diff --git a/usr/src/uts/sun4u/starcat/io/fcgp2.c b/usr/src/uts/sun4u/starcat/io/fcgp2.c index a557d00df3..8635cde443 100644 --- a/usr/src/uts/sun4u/starcat/io/fcgp2.c +++ b/usr/src/uts/sun4u/starcat/io/fcgp2.c @@ -20,7 +20,7 @@ */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -120,9 +120,9 @@ struct gfc_ops_v gp2_pov[] = { { "rb!", gfc_register_store}, { "claim-address", gfc_claim_address}, { "master-interrupt", gfc_master_intr}, - { "schizo,claim-memory", gfc_claim_memory}, - { "schizo,release-memory", gfc_release_memory}, - { "schizo,vtop", gfc_vtop}, + { "claim-memory", gfc_claim_memory}, + { "release-memory", gfc_release_memory}, + { "vtop", gfc_vtop}, { FC_CONFIG_CHILD, gfc_config_child}, { FC_GET_FCODE_SIZE, gfc_get_fcode_size}, { FC_GET_FCODE, gfc_get_fcode}, @@ -653,7 +653,7 @@ gfc_claim_address(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) /* * gfc_claim_memory * - * schizo,claim-memory ( align size vhint -- vaddr) + * claim-memory ( align size vhint -- vaddr) */ static int gfc_claim_memory(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) @@ -723,7 +723,7 @@ gfc_claim_memory(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) /* * gfc_release_memory * - * schizo,release-memory ( size vaddr -- ) + * release-memory ( size vaddr -- ) */ static int gfc_release_memory(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) @@ -777,7 +777,7 @@ gfc_release_memory(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) /* * gfc_vtop * - * schizo,vtop ( vaddr -- paddr.lo paddr.hi) + * vtop ( vaddr -- paddr.lo paddr.hi) */ static int gfc_vtop(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp) diff --git a/usr/src/uts/sun4u/starcat/os/starcat.c b/usr/src/uts/sun4u/starcat/os/starcat.c index 16de2c1046..207e3b6cdb 100644 --- a/usr/src/uts/sun4u/starcat/os/starcat.c +++ b/usr/src/uts/sun4u/starcat/os/starcat.c @@ -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,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -1236,7 +1235,7 @@ efcode_alloc(caddr_t alloc_base) } caddr_t -starcat_startup_memlist(caddr_t alloc_base) +plat_startup_memlist(caddr_t alloc_base) { caddr_t tmp_alloc_base; diff --git a/usr/src/uts/sun4u/starfire/io/drmach.c b/usr/src/uts/sun4u/starfire/io/drmach.c index d57939fdce..ed322c68a7 100644 --- a/usr/src/uts/sun4u/starfire/io/drmach.c +++ b/usr/src/uts/sun4u/starfire/io/drmach.c @@ -1142,65 +1142,6 @@ drmach_write_mc_asr(drmachid_t id, uint_t mcreg) return (err); } -static struct memlist * -memlist_add_span(struct memlist *mlist, uint64_t base, uint64_t len) -{ - struct memlist *ml, *tl, *nl; - - if (len == 0ull) - return (NULL); - - if (mlist == NULL) { - mlist = GETSTRUCT(struct memlist, 1); - mlist->address = base; - mlist->size = len; - mlist->next = mlist->prev = NULL; - - return (mlist); - } - - for (tl = ml = mlist; ml; tl = ml, ml = ml->next) { - if (base < ml->address) { - if ((base + len) < ml->address) { - nl = GETSTRUCT(struct memlist, 1); - nl->address = base; - nl->size = len; - nl->next = ml; - if ((nl->prev = ml->prev) != NULL) - nl->prev->next = nl; - ml->prev = nl; - if (mlist == ml) - mlist = nl; - } else { - ml->size = MAX((base + len), - (ml->address + ml->size)) - - base; - ml->address = base; - } - break; - - } else if (base <= (ml->address + ml->size)) { - ml->size = MAX((base + len), - (ml->address + ml->size)) - - MIN(ml->address, base); - ml->address = MIN(ml->address, base); - break; - } - } - if (ml == NULL) { - nl = GETSTRUCT(struct memlist, 1); - nl->address = base; - nl->size = len; - nl->next = NULL; - nl->prev = tl; - tl->next = nl; - } - - memlist_coalesce(mlist); - - return (mlist); -} - static sbd_error_t * drmach_prep_rename_script(drmach_device_t *s_mem, drmach_device_t *t_mem, uint64_t t_slice_offset, caddr_t buf, int buflen) @@ -3696,7 +3637,6 @@ drmach_unconfigure(drmachid_t id, int flags) drmach_device_t *dp; pnode_t nodeid; dev_info_t *dip, *fdip = NULL; - uint_t ddi_flags; if (!DRMACH_IS_DEVICE_ID(id)) return (drerr_new(0, ESTF_INAPPROP, NULL)); @@ -3717,17 +3657,15 @@ drmach_unconfigure(drmachid_t id, int flags) */ ddi_release_devi(dip); - ddi_flags = 0; - - if (flags & DRMACH_DEVI_REMOVE) - ddi_flags |= DEVI_BRANCH_DESTROY | DEVI_BRANCH_EVENT; + if (flags & DEVI_BRANCH_DESTROY) + flags |= DEVI_BRANCH_EVENT; /* * Force flag is no longer necessary. See starcat/io/drmach.c * for details. */ ASSERT(e_ddi_branch_held(dip)); - if (e_ddi_branch_unconfigure(dip, &fdip, ddi_flags)) { + if (e_ddi_branch_unconfigure(dip, &fdip, flags)) { sbd_error_t *err; char *path = kmem_alloc(MAXPATHLEN, KM_SLEEP); diff --git a/usr/src/uts/sun4u/sys/Makefile b/usr/src/uts/sun4u/sys/Makefile index 0de14065cc..ae9c0bf71c 100644 --- a/usr/src/uts/sun4u/sys/Makefile +++ b/usr/src/uts/sun4u/sys/Makefile @@ -75,6 +75,7 @@ $(CLOSED_BUILD)CLOSED_SUN4_HDRS= \ HDRS= \ cheetahregs.h \ cpr_impl.h \ + cpu_impl.h \ ecc_kstat.h \ envctrl.h \ envctrl_gen.h \ @@ -90,6 +91,7 @@ HDRS= \ machsystm.h \ machthread.h \ mmu.h \ + opl_module.h \ prom_plat.h \ pte.h \ sbd_ioctl.h \ @@ -116,6 +118,7 @@ $(CLOSED_BUILD)CLOSED_HDRS= \ memtestio_chp.h \ memtestio_ja.h \ memtestio_jg.h \ + memtestio_oc.h \ memtestio_pn.h \ memtestio_sf.h \ memtestio_sr.h \ diff --git a/usr/src/uts/sun4u/sys/cheetahregs.h b/usr/src/uts/sun4u/sys/cheetahregs.h index 8d0878be3e..e932d96d2e 100644 --- a/usr/src/uts/sun4u/sys/cheetahregs.h +++ b/usr/src/uts/sun4u/sys/cheetahregs.h @@ -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. @@ -30,6 +29,7 @@ #pragma ident "%Z%%M% %I% %E% SMI" #include <sys/machasi.h> +#include <sys/cpu_impl.h> #ifdef _KERNEL #include <sys/fpras.h> #endif /* _KERNEL */ @@ -43,66 +43,6 @@ extern "C" { #endif /* - * Definitions of UltraSparc III cpu implementations as specified - * in version register - */ -#define CHEETAH_IMPL 0x14 -#define IS_CHEETAH(impl) ((impl) == CHEETAH_IMPL) -#define CHEETAH_MAJOR_VERSION(rev) (((rev) >> 4) & 0xf) -#define CHEETAH_MINOR_VERSION(rev) ((rev) & 0xf) - -/* - * Definitions of UltraSPARC III+ cpu implementation as specified - * in version register - */ -#define CHEETAH_PLUS_IMPL 0x15 -#define IS_CHEETAH_PLUS(impl) ((impl) == CHEETAH_PLUS_IMPL) -#define CHEETAH_PLUS_MAJOR_VERSION(rev) CHEETAH_MAJOR_VERSION(rev) -#define CHEETAH_PLUS_MINOR_VERSION(rev) CHEETAH_MINOR_VERSION(rev) - -/* - * Definitions of UltraSPARC IIIi cpu implementation as specified - * in version register. Jalapeno major and minor rev's are in - * the same location and are the same size as Cheetah/Cheetah+. - */ -#define JALAPENO_IMPL 0x16 -#define IS_JALAPENO(impl) ((impl) == JALAPENO_IMPL) -#define JALAPENO_MAJOR_VERSION(rev) CHEETAH_MAJOR_VERSION(rev) -#define JALAPENO_MINOR_VERSION(rev) CHEETAH_MINOR_VERSION(rev) - -/* - * Definitions of UltraSPARC IV cpu implementation as specified - * in version register. Jaguar major and minor rev's are in - * the same location and are the same size as Cheetah/Cheetah+. - */ -#define JAGUAR_IMPL 0x18 -#define IS_JAGUAR(impl) ((impl) == JAGUAR_IMPL) -#define JAGUAR_MAJOR_VERSION(rev) CHEETAH_MAJOR_VERSION(rev) -#define JAGUAR_MINOR_VERSION(rev) CHEETAH_MINOR_VERSION(rev) - -/* - * Definitions of UltraSPARC IIIi+ cpu implementation as specified - * in version register. Serrano major and minor rev's are in - * the same location and are the same size as Cheetah/Cheetah+. - */ -#define SERRANO_IMPL 0x22 -#define IS_SERRANO(impl) ((impl) == SERRANO_IMPL) -#define SERRANO_MAJOR_VERSION(rev) CHEETAH_MAJOR_VERSION(rev) -#define SERRANO_MINOR_VERSION(rev) CHEETAH_MINOR_VERSION(rev) - -/* - * Definitions of UltraSPARC IV+ cpu implementation as specified - * in version register. Panther major and minor rev's are in - * the same location and are the same size as Cheetah/Cheetah+. - */ -#define PANTHER_IMPL 0x19 -#define IS_PANTHER(impl) ((impl) == PANTHER_IMPL) -#define PANTHER_MAJOR_VERSION(rev) CHEETAH_MAJOR_VERSION(rev) -#define PANTHER_MINOR_VERSION(rev) CHEETAH_MINOR_VERSION(rev) - -#define CPU_IMPL_IS_CMP(impl) (IS_JAGUAR(impl) || IS_PANTHER(impl)) - -/* * Cheetah includes the process info in its mask to make things * more difficult. The process is the low bit of the major mask, * so to convert to the netlist major: diff --git a/usr/src/uts/sun4u/sys/cpu_impl.h b/usr/src/uts/sun4u/sys/cpu_impl.h new file mode 100644 index 0000000000..6984b921e5 --- /dev/null +++ b/usr/src/uts/sun4u/sys/cpu_impl.h @@ -0,0 +1,110 @@ +/* + * 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_CPU_IMPL_H +#define _SYS_CPU_IMPL_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Definitions of UltraSparc III cpu implementations as specified + * in version register + */ +#define CHEETAH_IMPL 0x14 +#define IS_CHEETAH(impl) ((impl) == CHEETAH_IMPL) +#define CHEETAH_MAJOR_VERSION(rev) (((rev) >> 4) & 0xf) +#define CHEETAH_MINOR_VERSION(rev) ((rev) & 0xf) + +/* + * Definitions of UltraSPARC III+ cpu implementation as specified + * in version register + */ +#define CHEETAH_PLUS_IMPL 0x15 +#define IS_CHEETAH_PLUS(impl) ((impl) == CHEETAH_PLUS_IMPL) +#define CHEETAH_PLUS_MAJOR_VERSION(rev) CHEETAH_MAJOR_VERSION(rev) +#define CHEETAH_PLUS_MINOR_VERSION(rev) CHEETAH_MINOR_VERSION(rev) + +/* + * Definitions of UltraSPARC IIIi cpu implementation as specified + * in version register. Jalapeno major and minor rev's are in + * the same location and are the same size as Cheetah/Cheetah+. + */ +#define JALAPENO_IMPL 0x16 +#define IS_JALAPENO(impl) ((impl) == JALAPENO_IMPL) +#define JALAPENO_MAJOR_VERSION(rev) CHEETAH_MAJOR_VERSION(rev) +#define JALAPENO_MINOR_VERSION(rev) CHEETAH_MINOR_VERSION(rev) + +/* + * Definitions of UltraSPARC IV cpu implementation as specified + * in version register. Jaguar major and minor rev's are in + * the same location and are the same size as Cheetah/Cheetah+. + */ +#define JAGUAR_IMPL 0x18 +#define IS_JAGUAR(impl) ((impl) == JAGUAR_IMPL) +#define JAGUAR_MAJOR_VERSION(rev) CHEETAH_MAJOR_VERSION(rev) +#define JAGUAR_MINOR_VERSION(rev) CHEETAH_MINOR_VERSION(rev) + +/* + * Definitions of UltraSPARC IIIi+ cpu implementation as specified + * in version register. Serrano major and minor rev's are in + * the same location and are the same size as Cheetah/Cheetah+. + */ +#define SERRANO_IMPL 0x22 +#define IS_SERRANO(impl) ((impl) == SERRANO_IMPL) +#define SERRANO_MAJOR_VERSION(rev) CHEETAH_MAJOR_VERSION(rev) +#define SERRANO_MINOR_VERSION(rev) CHEETAH_MINOR_VERSION(rev) + +/* + * Definitions of UltraSPARC IV+ cpu implementation as specified + * in version register. Panther major and minor rev's are in + * the same location and are the same size as Cheetah/Cheetah+. + */ +#define PANTHER_IMPL 0x19 +#define IS_PANTHER(impl) ((impl) == PANTHER_IMPL) +#define PANTHER_MAJOR_VERSION(rev) CHEETAH_MAJOR_VERSION(rev) +#define PANTHER_MINOR_VERSION(rev) CHEETAH_MINOR_VERSION(rev) + + +/* + * Definitions of Olympus-C cpu implementations as specified + * in version register + */ +#define OLYMPUS_C_IMPL 0x6 +#define IS_OLYMPUS_C(impl) ((impl) == OLYMPUS_C_IMPL) +#define OLYMPUS_REV_MASK(x) (((x) >> 28) & 0x7) +#define OLYMPUS_C_A 0 + +#define CPU_IMPL_IS_CMP(impl) (IS_JAGUAR(impl) || \ + IS_PANTHER(impl) || IS_OLYMPUS_C(impl)) + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_CPU_IMPL_H */ diff --git a/usr/src/uts/sun4u/sys/cpu_module.h b/usr/src/uts/sun4u/sys/cpu_module.h index a6ed4be5a6..0df1b445c7 100644 --- a/usr/src/uts/sun4u/sys/cpu_module.h +++ b/usr/src/uts/sun4u/sys/cpu_module.h @@ -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,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -61,9 +60,10 @@ void cpu_kdi_init(struct kdi *); * * set Panther CPU implementation details * - * mmu_init_mmu_page_sizes changes the mmu_page_sizes variable from - * The default 4 page sizes to 6 page sizes for Panther-only domains, - * and is called from fillsysinfo.c:check_cpus_set at early bootup time. + * On Panther-only domains and Olympus-C, mmu_init_mmu_page_sizes + * changes the mmu_page_sizes variable from the default 4 page sizes + * to 6 page sizes and is called from fillsysinfo.c:check_cpus_set + * at early bootup time. */ void cpu_fiximp(pnode_t dnode); #pragma weak cpu_fix_allpanther diff --git a/usr/src/uts/sun4u/sys/machasi.h b/usr/src/uts/sun4u/sys/machasi.h index 0d87c1d6c7..8b37b98c18 100644 --- a/usr/src/uts/sun4u/sys/machasi.h +++ b/usr/src/uts/sun4u/sys/machasi.h @@ -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,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -58,6 +57,8 @@ extern "C" { #define ASI_INTR_DISPATCH_STATUS 0x48 /* interrupt vector dispatch status */ #define ASI_INTR_RECEIVE_STATUS 0x49 /* interrupt vector receive status */ +#define ASI_SCRATCHPAD 0x4F /* Scratchpad registers ASI */ + #define ASI_BLK_AIUP 0x70 /* block as if user primary */ #define ASI_BLK_AIUS 0x71 /* block as if user secondary */ diff --git a/usr/src/uts/sun4u/sys/machclock.h b/usr/src/uts/sun4u/sys/machclock.h index 90dda0c282..3bd3ad7e7b 100644 --- a/usr/src/uts/sun4u/sys/machclock.h +++ b/usr/src/uts/sun4u/sys/machclock.h @@ -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,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -52,7 +51,7 @@ extern "C" { * (see <sys/clock.h> file for more information) */ -#if defined(CHEETAH) || defined(HUMMINGBIRD) +#if defined(CHEETAH) || defined(HUMMINGBIRD) || defined(OLYMPUS_C) /* * At least 3.9MHz, for slower %stick-based systems. diff --git a/usr/src/uts/sun4u/sys/machparam.h b/usr/src/uts/sun4u/sys/machparam.h index fe7fc55757..de12ef0ec1 100644 --- a/usr/src/uts/sun4u/sys/machparam.h +++ b/usr/src/uts/sun4u/sys/machparam.h @@ -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. @@ -291,7 +290,7 @@ extern "C" { #define PFN_TO_BUSTYPE(pfn) (((pfn) >> 19) & 0x1FF) #define BUSTYPE_TO_PFN(btype, pfn) \ - (((btype) << 19) | ((pfn) & 0x7FFFF)) + (((pfn_t)(btype) << 19) | ((pfn) & 0x7FFFF)) #define IO_BUSTYPE(pfn) ((PFN_TO_BUSTYPE(pfn) & 0x100) >> 8) #ifdef _STARFIRE diff --git a/usr/src/uts/sun4u/sys/machthread.h b/usr/src/uts/sun4u/sys/machthread.h index 0b9648002a..d2f0a31e0a 100644 --- a/usr/src/uts/sun4u/sys/machthread.h +++ b/usr/src/uts/sun4u/sys/machthread.h @@ -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. @@ -33,6 +32,7 @@ #include <sys/sun4asi.h> #include <sys/machasi.h> #include <sys/bitmap.h> +#include <sys/opl_olympus_regs.h> #ifdef __cplusplus extern "C" { @@ -75,6 +75,15 @@ extern "C" { lduwa [r]ASI_IO, r; \ wrpr scr, 0, %pstate +#elif defined(_OPL) +/* + * For OPL platform, we get CPU_INDEX from ASI_EIDR. + */ +#define CPU_INDEX(r, scr) \ + ldxa [%g0]ASI_EIDR, r; \ + and r, 0xfff, r + + #else /* _STARFIRE */ /* diff --git a/usr/src/uts/sun4u/sys/opl.h b/usr/src/uts/sun4u/sys/opl.h new file mode 100644 index 0000000000..69fef17266 --- /dev/null +++ b/usr/src/uts/sun4u/sys/opl.h @@ -0,0 +1,80 @@ +/* + * 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 _OPL_H +#define _OPL_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +#define OPL_MAX_CPU_PER_CMP 4 +#define OPL_MAX_CORES_PER_CMP 4 +#define OPL_MAX_STRANDS_PER_CORE 2 +#define OPL_MAX_CMP_UNITS_PER_BOARD 4 +#define OPL_MAX_BOARDS 16 +#define OPL_MAX_CPU_PER_BOARD \ + (OPL_MAX_CPU_PER_CMP * OPL_MAX_CMP_UNITS_PER_BOARD) +#define OPL_MAX_MEM_UNITS_PER_BOARD 1 +#define OPL_MAX_IO_UNITS_PER_BOARD 16 +#define OPL_MAX_PCICH_UNITS_PER_BOARD 4 +#define OPL_MAX_TSBS_PER_PCICH 2 +#define OPL_MAX_CORE_UNITS_PER_BOARD \ + (OPL_MAX_CORES_PER_CMP * OPL_MAX_CMP_UNITS_PER_BOARD) + +#define OPL_MAX_COREID_PER_CMP 4 +#define OPL_MAX_STRANDID_PER_CORE 2 +#define OPL_MAX_CPUID_PER_CMP (OPL_MAX_COREID_PER_CMP * \ + OPL_MAX_STRANDID_PER_CORE) +#define OPL_MAX_CMPID_PER_BOARD 4 +#define OPL_MAX_CPUID_PER_BOARD \ + (OPL_MAX_CPUID_PER_CMP * OPL_MAX_CMPID_PER_BOARD) +#define OPL_MAX_COREID_PER_BOARD \ + (OPL_MAX_COREID_PER_CMP * OPL_MAX_CMPID_PER_BOARD) +/* + * Macros to extract LSB_ID, CHIP_ID, CORE_ID, and STRAND_ID + * from the given cpuid. + */ +#define LSB_ID(x) (((uint_t)(x)/OPL_MAX_CPUID_PER_BOARD) & \ + (OPL_MAX_BOARDS - 1)) +#define CHIP_ID(x) (((uint_t)(x)/OPL_MAX_CPUID_PER_CMP) & \ + (OPL_MAX_CMPID_PER_BOARD - 1)) +#define CORE_ID(x) (((uint_t)(x)/OPL_MAX_STRANDID_PER_CORE) & \ + (OPL_MAX_COREID_PER_CMP - 1)) +#define STRAND_ID(x) ((uint_t)(x) & (OPL_MAX_STRANDID_PER_CORE - 1)) + +extern int plat_max_boards(void); +extern int plat_max_cpu_units_per_board(void); +extern int plat_max_mem_units_per_board(void); +extern int plat_max_io_units_per_board(void); +extern int plat_max_cmp_units_per_board(void); + +#ifdef __cplusplus +} +#endif + +#endif /* _OPL_H */ diff --git a/usr/src/uts/sun4u/sys/opl_cfg.h b/usr/src/uts/sun4u/sys/opl_cfg.h new file mode 100644 index 0000000000..021c3881c5 --- /dev/null +++ b/usr/src/uts/sun4u/sys/opl_cfg.h @@ -0,0 +1,306 @@ +/* + * 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_OPL_CFG_H +#define _SYS_OPL_CFG_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Hardware Descriptor. + */ + +#include <sys/opl_hwdesc.h> + +#define OPL_PSB_MODE 0x0 +#define OPL_XSB_MODE 0x1 + +#define OPL_LSBID_MASK 0x1f + +/* + * CPU device portid: + * + * 1 0 0 0 0 0 0 0 0 0 0 + * 0 9 8 7 6 5 4 3 2 1 0 + * --------------------------------------- + * | 1 | LSB ID | CHIP | CORE | CPU | + * --------------------------------------- + */ +#define OPL_CPUID_TO_LSB(devid) ((devid >> 5) & OPL_LSBID_MASK) +#define OPL_CPU_CHIP(devid) ((devid >> 3) & 0x3) +#define OPL_CORE(devid) ((devid >> 1) & 0x3) +#define OPL_CPU(devid) ((devid & 0x001)) + +#define OPL_PORTID(board, chip) ((1 << 10) | (board << 5) | (chip << 3)) + +#define OPL_CPUID(board, chip, core, cpu) \ + \ + ((board << 5) | (chip << 3) | (core << 1) | (cpu)) + +/* + * Dummy address space for a chip. + */ +#define OPL_PROC_AS(board, chip) \ + \ + ((1ULL << 46) | ((uint64_t)board << 40) | (1ULL << 39) | \ + (1ULL << 33) | ((uint64_t)chip << 4)) + +/* + * pseudo-mc portid: + * + * 1 0 0 0 0 0 0 0 0 0 0 + * 0 9 8 7 6 5 4 3 2 1 0 + * ------------------------------------- + * | 0 | 1 | LSB ID | 0 | + * ------------------------------------- + */ +#define OPL_LSB_TO_PSEUDOMC_PORTID(board) ((1 << 9) | (board << 4)) + +/* + * Dummy address space for a pseudo memory node + */ +#define OPL_MC_AS(board) \ + \ + ((1ULL << 46) | ((uint64_t)board << 40) | (1ULL << 39) | \ + (1ULL << 33)) + +/* + * Defines used by the Jupiter bus-specific library (lfc_jupiter.so). + * This library gets loaded into the user-level fcode interpreter + * and provides bus-specific methods that are used by the Oberon + * and the CMU-channel fcode drivers. + */ +/* + * + * IO port id: + * + * 1 0 0 0 0 0 0 0 0 0 0 + * 0 9 8 7 6 5 4 3 2 1 0 + * --------------------------------------- + * | 0 0 | LSB ID | IO CHAN | LEAF | + * --------------------------------------- + */ +#define OPL_PORTID_MASK 0x7FF +#define OPL_IO_PORTID_TO_LSB(portid) (((portid) >> 4) & OPL_LSBID_MASK) +#define OPL_PORTID_TO_CHANNEL(portid) (((portid) >> 1) & 0x7) +#define OPL_PORTID_TO_LEAF(portid) ((portid) & 0x1) +#define OPL_IO_PORTID(lsb, ch, leaf) \ + (((lsb & OPL_LSBID_MASK) << 4) | ((ch & 0x7) << 1) | (leaf & 0x1)) + +#define OPL_ADDR_TO_LSB(hi) (((hi) >> 8) & OPL_LSBID_MASK) +#define OPL_ADDR_TO_CHANNEL(hi) (((hi) >> 5) & 0x7) +#define OPL_ADDR_TO_LEAF(hi, lo) \ + (!(((hi) >> 7) & 0x1) && (((lo) >> 20) == 0x7)) + +#define OPL_ADDR_HI(lsb, ch) \ + ((1 << 14) | ((lsb & OPL_LSBID_MASK) << 8) | ((ch & 0x7) << 5)) + +#define OPL_CMU_CHANNEL 4 +#define OPL_OBERON_CHANNEL(ch) ((ch >= 0) && (ch <= 3)) +#define OPL_VALID_CHANNEL(ch) ((ch >= 0) && (ch <= 4)) +#define OPL_VALID_LEAF(leaf) ((leaf == 0) || (leaf == 1)) + +#if defined(_KERNEL) + +/* + * We store the pointers to the following device nodes in this structure: + * "pseudo-mc" + * "cmp" + * "pci" + * + * These nodes represent the different branches we create in the device + * tree for each board during probe. We store them so that when a board + * is unprobed, we can easily locate the branches and destroy them. + */ +typedef struct { + dev_info_t *cfg_pseudo_mc; + dev_info_t *cfg_cpu_chips[HWD_CPU_CHIPS_PER_CMU]; + dev_info_t *cfg_cmuch_leaf; + fco_handle_t cfg_cmuch_handle; + char *cfg_cmuch_probe_str; + dev_info_t *cfg_pcich_leaf[HWD_PCI_CHANNELS_PER_SB] + [HWD_LEAVES_PER_PCI_CHANNEL]; + fco_handle_t cfg_pcich_handle[HWD_PCI_CHANNELS_PER_SB] + [HWD_LEAVES_PER_PCI_CHANNEL]; + char *cfg_pcich_probe_str[HWD_PCI_CHANNELS_PER_SB] + [HWD_LEAVES_PER_PCI_CHANNEL]; + void *cfg_hwd; +} opl_board_cfg_t; + +/* + * Prototypes for the callback functions used in the DDI functions + * used to perform device tree operations. + * + * init functions are used to find device nodes that are created + * by Solaris during boot. + * + * create functions are used to initialize device nodes during DR. + */ +typedef int (*opl_init_func_t)(dev_info_t *, char *, int); +typedef int (*opl_create_func_t)(dev_info_t *, void *, uint_t); + +/* + * The following probe structure carries all the information required + * at various points during probe. This structure serves two purposes: + * + * 1. It allows us to streamline functions and have them accept just + * a single argument. + * + * 2. It allows us to pass information to the DDI callbacks. DDI + * callbacks are allowed only one argument. It also allows + * us to return information from those callbacks. + * + * The probe structure carries a snapshot of the hardware descriptor + * taken at the beginning of a probe. + */ +typedef struct { + hwd_header_t *pr_hdr; + hwd_sb_status_t *pr_sb_status; + hwd_domain_info_t *pr_dinfo; + hwd_sb_t *pr_sb; + + int pr_board; + int pr_cpu_chip; + int pr_core; + int pr_cpu; + int pr_channel; + int pr_channel_status; + int pr_leaf; + int pr_leaf_status; + + opl_create_func_t pr_create; + dev_info_t *pr_parent; + dev_info_t *pr_node; + int pr_hold; +} opl_probe_t; + +#define OPL_STR_LEN 256 + +#define OPL_HI(value) ((uint32_t)((uint64_t)(value) >> 32)) +#define OPL_LO(value) ((uint32_t)(value)) + +typedef struct { + uint32_t addr_hi; + uint32_t addr_lo; +} opl_addr_t; + +typedef struct { + uint32_t rg_addr_hi; + uint32_t rg_addr_lo; + uint32_t rg_size_hi; + uint32_t rg_size_lo; +} opl_range_t; + +typedef struct { + int mc_bank; + uint32_t mc_hi; + uint32_t mc_lo; +} opl_mc_addr_t; + +/* + * Convenience macros for DDI property operations. The functions that + * DDI provides for getting and updating properties are not symmetric + * either in their names or in the number of arguments. These macros + * hide the gory details and provide a symmetric way to get and + * set properties. + */ +#define opl_prop_get_string(dip, name, bufp, lenp) \ + ddi_getlongprop(DDI_DEV_T_ANY, dip, \ + DDI_PROP_DONTPASS, name, (caddr_t)bufp, lenp) + +#define opl_prop_get_int(dip, name, value, defvalue) \ +( \ + *(value) = ddi_getprop(DDI_DEV_T_ANY, dip, \ + DDI_PROP_DONTPASS, name, defvalue), \ + (*(value) == defvalue) ? DDI_PROP_NOT_FOUND : DDI_PROP_SUCCESS \ +) + +#define opl_prop_get_int_array(dip, name, data, nelems) \ + ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, \ + DDI_PROP_DONTPASS, name, (int **)&data, (uint_t *)&nelems) + +#define OPL_GET_PROP(type, dip, name, value, arg) \ + opl_prop_get_##type(dip, name, value, arg) + +#define OPL_GET_PROP_ARRAY(type, dip, name, values, nvalues) \ + opl_prop_get_##type##_array(dip, name, values, nvalues) + +#define OPL_FREE_PROP(data) \ + ddi_prop_free((void *)data) + +#define OPL_UPDATE_PROP_ERR(ret, name) \ + if (ret != DDI_PROP_SUCCESS) { \ + cmn_err(CE_WARN, "%s (%d): %s update property error (%d)",\ + __FILE__, __LINE__, name, ret); \ + return (DDI_WALK_ERROR); \ + } + +#define OPL_UPDATE_PROP(type, dip, name, value) \ + ret = ndi_prop_update_##type(DDI_DEV_T_NONE, dip, name, value); \ + OPL_UPDATE_PROP_ERR(ret, name) + + +#define OPL_UPDATE_PROP_ARRAY(type, dip, name, values, nvalues) \ + ret = ndi_prop_update_##type##_array(DDI_DEV_T_NONE, dip, \ + name, values, nvalues); \ + OPL_UPDATE_PROP_ERR(ret, name) + +/* + * Node names for the different nodes supported in OPL. + */ +#define OPL_PSEUDO_MC_NODE "pseudo-mc" +#define OPL_CPU_CHIP_NODE "cmp" +#define OPL_CORE_NODE "core" +#define OPL_CPU_NODE "cpu" +#define OPL_PCI_LEAF_NODE "pci" + +typedef struct { + char *fc_service; + fc_ops_t *fc_op; +} opl_fc_ops_t; + +/* + * Functions used by drmach + */ +extern int opl_probe_sb(int); +extern int opl_unprobe_sb(int); +extern int opl_read_hwd(int, hwd_header_t **, hwd_sb_status_t **, + hwd_domain_info_t **, hwd_sb_t **); +extern void opl_hold_devtree(void); +extern void opl_release_devtree(void); +extern int oplcfg_pa_swap(int from, int to); +extern int opl_init_cfg(); + +#endif /* _KERNEL */ + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_OPL_CFG_H */ diff --git a/usr/src/uts/sun4u/sys/opl_module.h b/usr/src/uts/sun4u/sys/opl_module.h new file mode 100644 index 0000000000..80ef0acb31 --- /dev/null +++ b/usr/src/uts/sun4u/sys/opl_module.h @@ -0,0 +1,159 @@ +/* + * 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_OPL_MODULE_H +#define _SYS_OPL_MODULE_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/async.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _KERNEL + +/* + * Sets trap table entry ttentry by overwriting eight instructions from ttlabel. + */ +#define OPL_SET_TRAP(ttentry, ttlabel) \ + bcopy((const void *)&ttlabel, &ttentry, 32); \ + flush_instr_mem((caddr_t)&ttentry, 32); + +/* + * Define for max size of "reason" string in panic flows. Since this is on + * the stack, we want to keep it as small as is reasonable. + */ +#define MAX_REASON_STRING 40 + +/* + * These error types are specific to Olympus and are used internally for the + * opl fault structure flt_type field. + */ +#define OPL_CPU_SYNC_UE 1 +#define OPL_CPU_SYNC_OTHERS 2 +#define OPL_CPU_URGENT 3 +#define OPL_CPU_INV_SFSR 4 +#define OPL_CPU_INV_UGESR 5 + +#ifndef _ASM + +/* + * Define Olympus family (SPARC64-VI) specific asynchronous error structure + */ +typedef struct olympus_async_flt { + struct async_flt cmn_asyncflt; /* common - see sun4u/sys/async.h */ + ushort_t flt_type; /* types of faults - cpu specific */ + uint64_t flt_bit; /* fault bit for this log msg */ + ushort_t flt_eid_mod; /* module ID (type of hardware) */ + ushort_t flt_eid_sid; /* source ID */ +} opl_async_flt_t; + +/* + * Error type table struct. + */ +typedef struct ecc_type_to_info { + uint64_t ec_afsr_bit; /* SFSR bit of error */ + char *ec_reason; /* Short error description */ + uint_t ec_flags; /* Trap type error should be seen at */ + int ec_flt_type; /* Used for error logging */ + char *ec_desc; /* Long error description */ + uint64_t ec_err_payload; /* FM ereport payload information */ + char *ec_err_class; /* FM ereport class */ +} ecc_type_to_info_t; + +/* + * Redefine fault status bit field definitions taken from + * "async.h". Reused reserved Ultrasparc3 specific fault status + * bits here since they are by definition mutually exclusive + * w.r.t. OPL + */ +#define OPL_ECC_ISYNC_TRAP 0x0100 +#define OPL_ECC_DSYNC_TRAP 0x0200 +#define OPL_ECC_SYNC_TRAP (OPL_ECC_ISYNC_TRAP|OPL_ECC_DSYNC_TRAP) +#define OPL_ECC_URGENT_TRAP 0x0400 + +#define TRAP_TYPE_URGENT 0x40 + +/* + * Since all the files share a bunch of routines between each other + * we will put all the "extern" definitions in this header file so that we + * don't have to repeat it all in every file. + */ + +/* + * functions that are defined in the OPL,SPARC64-VI cpu module: + */ +extern void shipit(int, int); +extern void cpu_page_retire(opl_async_flt_t *opl_flt); +extern void cpu_init_trap(void); +extern void cpu_error_ecache_flush(void); +extern void flush_ecache(uint64_t physaddr, size_t ecachesize, size_t linesize); +extern void stick_adj(int64_t skew); +extern void stick_timestamp(int64_t *ts); +extern void hwblkpagecopy(const void *src, void *dst); +extern void opl_error_setup(uint64_t); +extern void opl_mpg_enable(void); +extern int cpu_queue_events(opl_async_flt_t *, char *, uint64_t); +extern void ras_cntr_reset(void *); + +/* + * variables and structures that are defined outside the FJSV,SPARC64-VI + * cpu module: + */ +extern uint64_t xc_tick_limit; +extern uint64_t xc_tick_jump_limit; + +/* + * Labels used for the trap_table patching + */ +extern uint32_t tt0_iae; +extern uint32_t tt1_iae; +extern uint32_t tt0_dae; +extern uint32_t tt1_dae; +extern uint32_t tt0_asdat; +extern uint32_t tt1_asdat; + +extern void opl_serr_instr(void); +extern void opl_ugerr_instr(void); + +/* + * D$ and I$ global parameters. + */ +extern int dcache_size; +extern int dcache_linesize; +extern int icache_size; +extern int icache_linesize; + +#endif /* _ASM */ + +#endif /* _KERNEL */ + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_OPL_MODULE_H */ diff --git a/usr/src/uts/sun4u/sys/opl_olympus_regs.h b/usr/src/uts/sun4u/sys/opl_olympus_regs.h new file mode 100644 index 0000000000..ff482ce8a6 --- /dev/null +++ b/usr/src/uts/sun4u/sys/opl_olympus_regs.h @@ -0,0 +1,311 @@ +/* + * 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_OPL_OLYMPUS_REGS_H +#define _SYS_OPL_OLYMPUS_REGS_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/machasi.h> +#include <sys/cpu_impl.h> + +/* + * This file is cpu dependent. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _ASM +/* + * assembler doesn't understand the 'ull' suffix for C constants so + * use the inttypes.h macros and undefine them here for assembly code + */ +#undef INT64_C +#define INT64_C(x) (x) +#undef UINT64_C +#define UINT64_C(x) (x) +#endif /* _ASM */ + +/* + * Synchronous Fault Physical Address Register + */ +#define OPL_MMU_SFPAR 0x78 + +/* + * ASI_MCNTL: MEMORY CONTROL Register layout (ASI 0x45, VA 8) + * + * +-------------------------+---------+--------+--------+-----+---------+ + * | reserved [63:17] | NC_Cache|fw_fITLB|fw_fDTLB|00000|JPS1_TSBP| + * +-------------------------+---------+--------+--------+-----+---------+ + * 16 15 14 13-9 8 + * +---------+---------+------+ + * |mpg_sITLB|mpg_sDTLB|000000| + * +---------+---------+------+ + * 7 6 5-0 + */ +#define ASI_MCNTL 0x45 +#define LSU_MCNTL 0x8 /* vaddr offset of ASI_MCNTL */ +#define MCNTL_FW_FDTLB INT64_C(0x0000000000004000) +#define MCNTL_FW_FITLB INT64_C(0x0000000000008000) +#define MCNTL_JPS1_TSBP INT64_C(0x0000000000000100) +#define MCNTL_MPG_SITLB INT64_C(0x0000000000000080) +#define MCNTL_MPG_SDTLB INT64_C(0x0000000000000040) +#define MCNTL_SPECULATIVE_SHIFT 41 /* bit 41 is speculative mode bit */ + +/* + * ASI_UGESR: URGENT ERROR STATES layout (ASI 0x4C, VA 0x8) + * + * +--------+---+----+----+---+---+--+--+---+---+-+----+----+----+ + * |0[63:23]|CRE|TSBX|TSBP|PST|TST| F| R|SDC|WDT|0|DTLB|ITLB|CORE| + * +--------+---+----+----+---+---+--+--+---+---+-+----+----+----+ + * 22 21 20 19 18 17 16 15 14 10 9 8 + * +-------+----+---+---+---+ + * |INSTEND|PRIV|DAE|IAE|UGE| + * +-------+----+---+---+---+ + * 5 4 3 2 1 0 + * + */ +#define ASI_UGERSR 0x8 +#define UGESR_IAUG_CRE INT64_C(0x0000000000400000) +#define UGESR_IAUG_TSBCTXT INT64_C(0x0000000000200000) +#define UGESR_IUG_TSBP INT64_C(0x0000000000100000) +#define UGESR_IUG_PSTATE INT64_C(0x0000000000080000) +#define UGESR_IUG_TSTATE INT64_C(0x0000000000040000) +#define UGESR_IUG_F INT64_C(0x0000000000020000) +#define UGESR_IUG_R INT64_C(0x0000000000010000) +#define UGESR_AUG_SDC INT64_C(0x0000000000008000) +#define UGESR_IUG_WDT INT64_C(0x0000000000004000) +#define UGESR_IUG_DTLB INT64_C(0x0000000000000400) +#define UGESR_IUG_ITLB INT64_C(0x0000000000000200) +#define UGESR_IUG_COREERR INT64_C(0x0000000000000100) +#define UGESR_PRIV INT64_C(0x0000000000000008) +#define UGESR_MULTI_DAE INT64_C(0x0000000000000004) +#define UGESR_MULTI_IAE INT64_C(0x0000000000000002) +#define UGESR_MULTI_UGE INT64_C(0x0000000000000001) + +#define UGESR_CAN_RECOVER (UGESR_IUG_DTLB | \ + UGESR_IUG_ITLB | \ + UGESR_IUG_COREERR) + +#define UGESR_MULTI (UGESR_MULTI_DAE | \ + UGESR_MULTI_IAE | \ + UGESR_MULTI_UGE) + +#define UGESR_NOSYNC_PANIC (UGESR_IAUG_CRE | \ + UGESR_AUG_SDC | \ + UGESR_MULTI_DAE | \ + UGESR_MULTI_IAE | \ + UGESR_MULTI_UGE) +/* + * The value means 10000 Mz per 10ms. + */ +#define OPL_UGER_STICK_DIFF 10000 + + +/* + * ASI_ECR: Control of Error Action layout (ASI 0x4C, VA 0x10) + * + * +-------------------------+------+--------+-----+-------+-----------+ + * | reserved [63:10] |RTE_UE|RTE_CEDG|0...0|WEAK_ED|UGE_HANDLER| + * +-------------------------+------+--------+-----+-------+-----------+ + * 9 8 7 - 2 1 0 + * + */ +#define ASI_ECR ASI_AFSR +#define AFSR_ECR 0x10 +#define ASI_ECR_RTE_UE INT64_C(0x0000000000000200) +#define ASI_ECR_RTE_CEDG INT64_C(0x0000000000000100) +#define ASI_ECR_WEAK_ED INT64_C(0x0000000000000002) +#define ASI_ECR_UGE_HANDLER INT64_C(0x0000000000000001) + + +/* + * ASI_L2_CTRL: Level-2 Cache Control Register (ASI 0x6A, VA 0x10) + * + * +---------------------+--------+-----+---------+----+--------+ + * | reserved[63:25] |UGE_TRAP|0...0|NUMINSWAY|0..0|U2_FLUSH| + * +---------------------+--------+-----+---------+----+--------+ + * 24 23 19 18 16 15 1 0 + * + */ +#define ASI_L2_CTRL 0x6A /* L2$ Control Register */ +#define ASI_L2_CTRL_RW_ADDR 0x10 +#define ASI_L2_CTRL_UGE_TRAP INT64_C(0x0000000001000000) +#define ASI_L2_CTRL_NUMINSWAY_MASK INT64_C(0x0000000000070000) +#define ASI_L2_CTRL_U2_FLUSH INT64_C(0x0000000000000001) + + +/* + * Synchronous Fault Status Register Layout (ASI 0x50/0x58, VA 0x18) + * + * IMMU and DMMU maintain their own SFSR Register + * + * +----+----+-----+----+--+-----+--+---+-+----+--+--+-----+--+-+ + * |TLB#|0..0|index|0..0|MK| EID |UE|UPA|0|mTLB|NC|NF| ASI |TM|0| + * +----+----+-----+----+--+-----+--+---+-+----+--+--+-----+--+-+ + * 63 62 61 58 48 46 45 32 31 30 28 27 25 24 23 16 15 14 + * +----+-+---+--+-+--+--+ + * | FT |E| CT|PR|W|OW|FV| + * +----+-+---+--+-+--+--+ + * 13 7 6 5 4 3 2 1 0 + * + */ +#define SFSR_MK_UE INT64_C(0x0000400000000000) +#define SFSR_EID_MOD INT64_C(0x0000300000000000) +#define SFSR_EID_SID INT64_C(0x00000FFF00000000) +#define SFSR_UE INT64_C(0x0000000080000000) +#define SFSR_BERR INT64_C(0x0000000040000000) +#define SFSR_TO INT64_C(0x0000000020000000) +#define SFSR_TLB_MUL INT64_C(0x0000000008000000) +#define SFSR_TLB_PRT INT64_C(0x0000000004000000) + +#define SFSR_EID_MOD_SHIFT 44 +#define SFSR_EID_SID_SHIFT 32 + +/* + * Error Mark ID: Module Type + */ +#define OPL_ERRID_MEM 0 +#define OPL_ERRID_CHANNEL 1 +#define OPL_ERRID_CPU 2 +#define OPL_ERRID_PATH 3 + + +#define SFSR_ERRS (SFSR_UE | SFSR_BERR | \ + SFSR_TO | SFSR_TLB_MUL | \ + SFSR_TLB_PRT) + +#define SFSR_MEMORY (SFSR_UE | \ + SFSR_BERR | \ + SFSR_TO) + +/* + * Miscellaneous ASI definitions + */ +#define ASI_IIU_INST_TRAP 0x60 /* Instruction breakpoint */ +#define ASI_ALL_FLUSH_L1I 0x67 /* Flush Level-1 Inst. cache */ +#define ASI_L2_TAG_READ 0x6B /* L2 Diagnostics Tag Read */ +#define ASI_L2_TAG_READ_REG 0x6C /* L2 Diagnostics Tag Read Register */ +#define ASI_EIDR 0x6E /* Urgent errors */ +#define ASI_CACHE_INV 0x74 /* Cache invalidation */ +#define ASI_ERR_INJCT 0x76 /* Error injection */ + +/* + * Address of ASI scratch register. ASI 0x4F + */ +#define OPL_SCRATCHPAD_SAVE_AG1 0x00 /* used for saving global registers */ +#define OPL_SCRATCHPAD_SAVE_AG2 0x08 /* used for saving global registers */ +#define OPL_SCRATCHPAD_SAVE_AG3 0x10 /* used for saving global registers */ +#define OPL_SCRATCHPAD_ERRLOG 0x18 /* keeps EIDR, log's PA & err counter */ +#define OPL_SCRATCHPAD_UTSBREG4 0x20 +#define OPL_SCRATCHPAD_UNUSED5 0x28 +#define OPL_SCRATCHPAD_UNUSED6 0x30 +#define OPL_SCRATCHPAD_UNUSED7 0x38 + +/* + * Error log scratchpad register format. + * + * +--------+-------------------+----------+ + * |ASI_EIDR| PA to logging buf | # of err | + * +--------+-------------------+----------+ + * 63 50 49 6 5 0 + * + */ + +#define ERRLOG_REG_LOGPA_MASK INT64_C(0x0003ffffffffffc0) /* PA to log */ +#define ERRLOG_REG_NUMERR_MASK INT64_C(0x000000000000003f) /* Counter */ +#define ERRLOG_REG_EIDR_MASK INT64_C(0x0000000000003fff) /* EIDR */ + +#define ERRLOG_REG_EIDR_SHIFT 50 +#define ERRLOG_REG_ERR_SHIFT 6 +#define ERRLOG_REG_EIDR(reg) ((reg >> ERRLOG_REG_EIDR_SHIFT) & \ + ERRLOG_REG_EIDR_MASK) +#define ERRLOG_REG_LOGPA(reg) (reg & ERRLOG_REG_LOGPA_MASK) +#define ERRLOG_REG_NUMERR(reg) (reg & ERRLOG_REG_NUMERR_MASK) + +#define ERRLOG_BUFSZ 0x2000 +#define ERRLOG_SZ (1 << ERRLOG_REG_ERR_SHIFT) +#define ERRLOG_ALLOC_SZ (ERRLOG_BUFSZ * 512) + +/* + * Olympus-C default cache parameters. + */ +#define OPL_DCACHE_SIZE 0x20000 +#define OPL_DCACHE_LSIZE 0x40 +#define OPL_ICACHE_SIZE 0x20000 +#define OPL_ICACHE_LSIZE 0x40 +#define OPL_ECACHE_SIZE 0x600000 +#define OPL_ECACHE_LSIZE 0x100 +#define OPL_ECACHE_NWAY 12 +#define OPL_ECACHE_SETSIZE 0x80000 + +/* + * The minimum size needed to ensure consistency on a virtually address + * cache. Computed by taking the largest virtually indexed cache and dividing + * by its associativity. + */ +#define OPL_VAC_SIZE 0x4000 + +/* these are field offsets for opl_errlog structure */ +#define LOG_STICK_OFF 0x0 +#define LOG_TL_OFF 0x8 +#define LOG_ASI3_OFF 0x10 +#define LOG_SFSR_OFF 0x18 +#define LOG_SFAR_OFF 0x20 + +#define LOG_UGER_OFF 0x18 +#define LOG_TSTATE_OFF 0x20 +#define LOG_TPC_OFF 0x28 + +#ifndef _ASM +typedef struct opl_errlog { + uint64_t stick; + uint32_t tl; + uint32_t tt; + uint64_t asi3; + union { + struct { + uint64_t sfsr; + union { + uint64_t sfar; + uint64_t sfpar; + } sync_addr; + } sync; + struct { + uint64_t ugesr; + uint64_t tstate; + } ugesr; + } reg; + uint64_t tpc; +} opl_errlog_t; +#endif /* _ASM */ + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_OPL_OLYMPUS_REGS_H */ diff --git a/usr/src/uts/sun4u/sys/prom_plat.h b/usr/src/uts/sun4u/sys/prom_plat.h index c557eee0a1..646da1c7cc 100644 --- a/usr/src/uts/sun4u/sys/prom_plat.h +++ b/usr/src/uts/sun4u/sys/prom_plat.h @@ -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,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -265,6 +264,15 @@ extern int prom_starfire_move_cpu0(uint_t cpuid); extern void prom_starfire_init_console(uint_t cpuid); /* + * OPL-specific routines + */ +extern void prom_opl_get_tod(time_t *time, int64_t *stickval); +extern void prom_opl_set_diff(int64_t diff); +extern int prom_attach_notice(int bn); +extern int prom_detach_notice(int bn); +extern int prom_opl_switch_console(int bn); + +/* * The client program implementation is required to provide a wrapper * to the client handler, for the 32 bit client program to 64 bit cell-sized * client interface handler (switch stack, etc.). This function is not diff --git a/usr/src/uts/sun4u/sys/pte.h b/usr/src/uts/sun4u/sys/pte.h index 988b57fb68..0734bf5411 100644 --- a/usr/src/uts/sun4u/sys/pte.h +++ b/usr/src/uts/sun4u/sys/pte.h @@ -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,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -43,7 +42,9 @@ extern "C" { * use a V8 compiler all manipulations in C will be done using the bit fields * or as 2 integers. In assembly code we will deal with it as a double (using * ldx and stx). The structure is defined to force a double alignment. - * Note that USIIi uses bits <47:40> for diag, and <49:48> are reserved. + * Note that USIIi uses bits [47:41] for diag, and [49:48] are reserved. + * Note that pa[46:32] includes USIIi diag bits [46:41] and USIII reserved + * bits [46:43]. */ typedef union { struct tte { @@ -55,9 +56,9 @@ typedef union { uint32_t hmenum:3; /* sw - # of hment in hme_blk */ uint32_t rsv:7; /* former rsv:1 lockcnt:6 */ - uint32_t sz2:1; /* Panther sz2[48] */ - uint32_t diag:5; /* See USII Note above. */ - uint32_t pahi:11; /* pa[42:32] */ + uint32_t sz2:1; /* sz2[48] Panther, Olympus-C */ + uint32_t diag:1; /* See USII Note above. */ + uint32_t pahi:15; /* pa[46:32] See Note above */ uint32_t palo:19; /* pa[31:13] */ uint32_t no_sync:1; /* sw - ghost unload */ @@ -146,16 +147,20 @@ typedef union { #define TTE_PAGEMASK(sz) (~TTE_PAGE_OFFSET(sz)) #define TTE_PFNMASK(sz) (~(TTE_PAGE_OFFSET(sz) >> MMU_PAGESHIFT)) -#define TTE_PA_LSHIFT 21 /* used to do sllx on tte to get pa */ +#define TTE_PA_LSHIFT 17 /* used to do sllx on tte to get pa */ #ifndef _ASM #define TTE_PASHIFT 19 /* used to manage pahi and palo */ #define TTE_PALOMASK ((1 << TTE_PASHIFT) -1) -/* PFN is defined as bits [40-13] of the physical address */ +/* + * Spitfire PFN is defined as bits [40:13] of the physical address. + * Cheetah PFN is defined as bits [42:13] of the physical address. + * Olympus-C PFN is defined as bits [46:13] of the physical address. + */ #define TTE_TO_TTEPFN(ttep) \ - ((((ttep)->tte_pahi << TTE_PASHIFT) | (ttep)->tte_palo) & \ - TTE_PFNMASK(TTE_CSZ(ttep))) + (((((pfn_t)((ttep)->tte_pahi)) << TTE_PASHIFT) | \ + (ttep)->tte_palo) & TTE_PFNMASK(TTE_CSZ(ttep))) /* * This define adds the vaddr page offset to obtain a correct pfn */ @@ -198,11 +203,11 @@ typedef union { #define TTE_PROT_INT (TTE_WRPRM_INT | TTE_PRIV_INT) /* - * Define to clear the high-order 2 bits of the 43-bit PA in a tte. The - * Spitfire tte has PFN in [40-13] and uses [42-41] as part of Diag bits. + * Define to clear the high-order 6 bits of the 47-bit PA in a tte. The + * Spitfire tte has PFN in [40:13] and uses [46:41] as part of Diag bits. */ -#define TTE_SPITFIRE_PFNHI_CLEAR 0x3 -#define TTE_SPITFIRE_PFNHI_SHIFT 32+9 +#define TTE_SPITFIRE_PFNHI_CLEAR 0x3f +#define TTE_SPITFIRE_PFNHI_SHIFT 41 #ifndef ASM @@ -265,7 +270,7 @@ typedef union { (ttep)->tte_bit.nfo = 1; \ (ttep)->tte_bit.ie = 1; \ (ttep)->tte_bit.sz2 = 1; \ - (ttep)->tte_bit.pahi = 0x7ff; \ + (ttep)->tte_bit.pahi = 0x7fff; \ (ttep)->tte_bit.palo = 0x7ffff; \ (ttep)->tte_bit.exec_perm = 1; \ (ttep)->tte_bit.l = 1; \ diff --git a/usr/src/uts/sun4u/sys/sbd_ioctl.h b/usr/src/uts/sun4u/sys/sbd_ioctl.h index 6826e28e9f..a917f3833f 100644 --- a/usr/src/uts/sun4u/sys/sbd_ioctl.h +++ b/usr/src/uts/sun4u/sys/sbd_ioctl.h @@ -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,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -148,7 +147,9 @@ typedef struct { #define is_suspend is_cm.c_sflags #define is_time is_cm.c_time -#define SBD_MAX_CORES_PER_CMP 2 +/* This constant must be the max of the max cores on all platforms */ + +#define SBD_MAX_CORES_PER_CMP 8 typedef struct { sbd_cm_stat_t ps_cm; @@ -577,6 +578,23 @@ typedef struct { #define ESGT_NOT_SUPP 4027 /* Operation not supported */ #define ESGT_NO_MEM 4028 /* No Memory */ +/* opl error codes */ + +#define EOPL_GETPROP 5001 /* Cannot read property value */ +#define EOPL_BNUM 5002 /* Invalid board number */ +#define EOPL_CONFIGBUSY 5003 + /* Cannot proceed; Board is configured or busy */ +#define EOPL_PROBE 5004 /* Firmware probe failed */ +#define EOPL_DEPROBE 5005 /* Firmware deprobe failed */ +#define EOPL_SUPPORT 5006 /* Operation not supported */ +#define EOPL_DRVFAIL 5007 /* Device driver failure */ +#define EOPL_UNKPTCMD 5008 /* Unrecognized platform command */ +#define EOPL_NOTID 5009 /* drmach parameter is not a valid ID */ +#define EOPL_INAPPROP 5010 + /* drmach parameter is inappropriate for operation */ +#define EOPL_INTERNAL 5011 /* Unexpected internal condition */ +#define EOPL_FINDDEVICE 5012 /* Firmware cannot find node. */ + #ifdef __cplusplus } #endif diff --git a/usr/src/uts/sun4u/todopl/Makefile b/usr/src/uts/sun4u/todopl/Makefile new file mode 100644 index 0000000000..28db86792f --- /dev/null +++ b/usr/src/uts/sun4u/todopl/Makefile @@ -0,0 +1,88 @@ +# +# 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" +# +# uts/sun4u/todopl/Makefile +# +# This makefile drives the production of the todopl +# kernel module. +# + +# +# Path to the base of the uts directory tree (usually /usr/src/uts). +# +UTSBASE = ../.. + +# +# Define the module and object file sets. +# +MODULE = todopl +OBJECTS = $(TODOPL_OBJS:%=$(OBJS_DIR)/%) +LINTS = $(TODOPL_OBJS:%.o=$(LINTS_DIR)/%.ln) +ROOTMODULE = $(ROOT_PSM_TOD_DIR)/$(MODULE) + +# +# Include common rules. +# +include $(UTSBASE)/sun4u/Makefile.sun4u + +INC_PATH += -I$(UTSBASE)/sun4u/opl +# +# Define targets +# +ALL_TARGET = $(BINARY) +LINT_TARGET = $(MODULE).lint +INSTALL_TARGET = $(BINARY) $(ROOTMODULE) + +# +# module dependencies +# +LDFLAGS += -dy + +# +# 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)/sun4u/Makefile.targ diff --git a/usr/src/uts/sun4u/vm/mach_sfmmu.c b/usr/src/uts/sun4u/vm/mach_sfmmu.c index fae0ac0caf..b9cf3266f0 100644 --- a/usr/src/uts/sun4u/vm/mach_sfmmu.c +++ b/usr/src/uts/sun4u/vm/mach_sfmmu.c @@ -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,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -191,6 +190,7 @@ sfmmu_remap_kernel(void) sfmmu_set_tlb(); } +#ifndef UTSB_PHYS /* * Unmap all references to user TSBs from the TLB of the current processor. */ @@ -216,6 +216,7 @@ sfmmu_clear_user_tsbs() va += MMU_PAGESIZE; } } +#endif /* UTSB_PHYS */ /* * Setup the kernel's locked tte's @@ -242,9 +243,11 @@ sfmmu_set_tlb(void) (void) prom_dtlb_load(index - 2, *(uint64_t *)&ktext_tte, textva); index -= 3; +#ifndef UTSB_PHYS utsb_dtlb_ttenum = index--; utsb4m_dtlb_ttenum = index--; sfmmu_clear_user_tsbs(); +#endif /* UTSB_PHYS */ if (!ktsb_phys && enable_bigktsb) { int i; diff --git a/usr/src/uts/sun4u/vm/mach_sfmmu.h b/usr/src/uts/sun4u/vm/mach_sfmmu.h index 730162e8fe..66640afb9e 100644 --- a/usr/src/uts/sun4u/vm/mach_sfmmu.h +++ b/usr/src/uts/sun4u/vm/mach_sfmmu.h @@ -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,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -40,15 +39,33 @@ #include <sys/x_call.h> #include <sys/cheetahregs.h> #include <sys/spitregs.h> +#include <sys/opl_olympus_regs.h> + #ifdef __cplusplus extern "C" { #endif /* - * Define UTSB_PHYS if user TSB is always accessed via physical address. - * On sun4u platform, user TSB is accessed via virtual address. + * On sun4u platforms, user TSBs are accessed via virtual address by default. + * Platforms that support ASI_SCRATCHPAD registers can define UTSB_PHYS in the + * platform Makefile to access user TSBs via physical address but must also + * designate one ASI_SCRATCHPAD register to hold the second user TSB. To + * designate the user TSB scratchpad register, platforms must provide a + * definition for SCRATCHPAD_UTSBREG below. + * + * Platforms that use UTSB_PHYS do not allocate 2 locked TLB entries to access + * the user TSBs. */ -#undef UTSB_PHYS +#if defined(UTSB_PHYS) + +#if defined(_OPL) +#define SCRATCHPAD_UTSBREG OPL_SCRATCHPAD_UTSBREG4 +#else +#error "Compiling UTSB_PHYS but no SCRATCHPAD_UTSBREG specified" +#endif + +#endif /* UTSB_PHYS */ + #ifdef _ASM @@ -80,8 +97,6 @@ extern "C" { movrnz qlp, ASI_MEM, tmp; \ mov tmp, %asi -#define SETUP_UTSB_ATOMIC_ASI(tmp1, tmp2) \ - mov ASI_NQUAD_LD, %asi /* * Macro to swtich to alternate global register on sun4u platforms * (not applicable to sun4v platforms) @@ -225,6 +240,8 @@ label/**/1: bnz,pt %xcc, label/**/4; /* if ref bit set-skip ahead */ \ nop; \ GET_CPU_IMPL(tmp1); \ + cmp tmp1, SPITFIRE_IMPL; \ + blt %icc, label/**/2; /* skip flush if FJ-OPL cpus */ \ cmp tmp1, CHEETAH_IMPL; \ bl,a %icc, label/**/1; \ /* update reference bit */ \ @@ -272,6 +289,8 @@ label/**/4: \ bnz,pn %xcc, label/**/4; /* nothing to do */ \ nop; \ GET_CPU_IMPL(tmp1); \ + cmp tmp1, SPITFIRE_IMPL; \ + blt %icc, label/**/2; /* skip flush if FJ-OPL cpus */ \ cmp tmp1, CHEETAH_IMPL; \ bl,a %icc, label/**/1; \ /* update reference bit */ \ @@ -294,6 +313,8 @@ label/**/4: \ /* END CSTYLED */ +#ifndef UTSB_PHYS + /* * Synthesize TSB base register contents for a process with * a single TSB. @@ -359,21 +380,6 @@ label/**/_tsbreg_vamask: ;\ or tsbreg, tmp3, tsbreg ;\ /* END CSTYLED */ -/* - * Load TSB base register. In the single TSB case this register - * contains utsb_vabase, bits 21:13 of tsbinfo->tsb_va, and the - * TSB size code in bits 2:0. See hat_sfmmu.h for the layout in - * the case where we have multiple TSBs per process. - * - * In: - * tsbreg = value to load (ro) - */ -#define LOAD_TSBREG(tsbreg, tmp1, tmp2) \ - mov MMU_TSB, tmp1; \ - sethi %hi(FLUSH_ADDR), tmp2; \ - stxa tsbreg, [tmp1]ASI_DMMU; /* dtsb reg */ \ - stxa tsbreg, [tmp1]ASI_IMMU; /* itsb reg */ \ - flush tmp2 /* * Load the locked TSB TLB entry. @@ -424,7 +430,7 @@ label/**/_resv_offset: ;\ sllx tmp1, (64 - MMU_PAGESHIFT4M), tmp1 ;\ srlx tmp1, (64 - MMU_PAGESHIFT4M), tmp1 ;\ or tmp1, resva, resva ;\ -9: /* END CSYLED */ +9: /* END CSTYLED */ /* * Determine the pointer of the entry in the first TSB to probe given @@ -438,7 +444,7 @@ label/**/_resv_offset: ;\ * Out: tsbe_ptr = TSB entry address * * Note: This function is patched at runtime for performance reasons. - * Any changes here require sfmmu_patch_utsb fixed. + * Any changes here require sfmmu_patch_utsb fixed. */ #define GET_1ST_TSBE_PTR(tsbp8k, tsbe_ptr, tmp, label) \ @@ -454,54 +460,6 @@ label/**/_get_1st_tsbe_ptr: ;\ or tsbe_ptr, tmp, tsbe_ptr \ /* END CSTYLED */ - -/* - * Will probe the first TSB, and if it finds a match, will insert it - * into the TLB and retry. - * - * tsbe_ptr = precomputed first TSB entry pointer (in, ro) - * vpg_4m = 4M virtual page number for tag matching (in, ro) - * label = where to branch to if this is a miss (text) - * %asi = atomic ASI to use for the TSB access - * - * For trapstat, we have to explicily use these registers. - * g4 = location tag will be retrieved into from TSB (out) - * g5 = location data(tte) will be retrieved into from TSB (out) - */ -#define PROBE_1ST_DTSB(tsbe_ptr, vpg_4m, label) /* g4/g5 clobbered */ \ - /* BEGIN CSTYLED */ \ - ldda [tsbe_ptr]%asi, %g4 /* g4 = tag, g5 = data */ ;\ - cmp %g4, vpg_4m /* compare tag w/ TSB */ ;\ - bne,pn %xcc, label/**/1 /* branch if !match */ ;\ - nop ;\ - TT_TRACE(trace_tsbhit) ;\ - DTLB_STUFF(%g5, %g1, %g2, %g3, %g4) ;\ - /* trapstat expects tte in %g5 */ ;\ - retry /* retry faulted instruction */ ;\ -label/**/1: \ - /* END CSTYLED */ - - -/* - * Same as above, only if the TTE doesn't have the execute - * bit set, will branch to exec_fault directly. - */ -#define PROBE_1ST_ITSB(tsbe_ptr, vpg_4m, label) \ - /* BEGIN CSTYLED */ \ - ldda [tsbe_ptr]%asi, %g4 /* g4 = tag, g5 = data */ ;\ - cmp %g4, vpg_4m /* compare tag w/ TSB */ ;\ - bne,pn %xcc, label/**/1 /* branch if !match */ ;\ - nop ;\ - andcc %g5, TTE_EXECPRM_INT, %g0 /* check execute bit */ ;\ - bz,pn %icc, exec_fault ;\ - nop ;\ - TT_TRACE(trace_tsbhit) ;\ - ITLB_STUFF(%g5, %g1, %g2, %g3, %g4) ;\ - retry /* retry faulted instruction */ ;\ -label/**/1: \ - /* END CSTYLED */ - - /* * Determine the base address of the second TSB given the 8K TSB * pointer register contents. @@ -565,6 +523,196 @@ label/**/_get_2nd_tsb_base: ;\ /* tmp1 = TSB size code */ \ GET_TSBE_POINTER(MMU_PAGESHIFT4M, tsbe_ptr, tagacc, tmp1, tmp2) +#endif /* UTSB_PHYS */ + + +#ifdef UTSB_PHYS + +/* + * Synthesize a TSB base register contents for a process. + * + * In: + * tsbinfo = TSB info pointer (ro) + * tsbreg, tmp1 = scratch registers + * Out: + * tsbreg = value to program into TSB base register + */ + +#define MAKE_UTSBREG_PHYS(tsbinfo, tsbreg, tmp1) \ + ldx [tsbinfo + TSBINFO_PADDR], tsbreg; \ + lduh [tsbinfo + TSBINFO_SZCODE], tmp1; \ + and tmp1, TSB_SOFTSZ_MASK, tmp1; \ + or tsbreg, tmp1, tsbreg; \ + +/* + * Load TSB base register into a dedicated scratchpad register. + * This register contains utsb_pabase in bits 63:13, and TSB size + * code in bits 2:0. + * + * In: + * tsbreg = value to load (ro) + * regnum = constant or register + * tmp1 = scratch register + * Out: + * Specified scratchpad register updated + * + * Note: If this is enabled on Panther, a membar #Sync is required + * following an ASI store to the scratchpad registers. + */ + +#define SET_UTSBREG(regnum, tsbreg, tmp1) \ + mov regnum, tmp1; \ + stxa tsbreg, [tmp1]ASI_SCRATCHPAD; /* save tsbreg */ \ + +/* + * Get TSB base register from the scratchpad + * + * In: + * regnum = constant or register + * tsbreg = scratch + * Out: + * tsbreg = tsbreg from the specified scratchpad register + */ + +#define GET_UTSBREG(regnum, tsbreg) \ + mov regnum, tsbreg; \ + ldxa [tsbreg]ASI_SCRATCHPAD, tsbreg + +/* + * Determine the pointer of the entry in the first TSB to probe given + * the 8K TSB pointer register contents. + * + * In: + * tagacc = tag access register + * tsbe_ptr = 8K TSB pointer register + * tmp = scratch registers + * + * Out: tsbe_ptr = TSB entry address + * + * Note: This macro is a nop since the 8K TSB pointer register + * is the entry pointer and does not need to be decoded. + * It is defined to allow for code sharing with sun4v. + */ + +#define GET_1ST_TSBE_PTR(tagacc, tsbe_ptr, tmp1, tmp2) + +/* + * Get the location in the 2nd TSB of the tsbe for this fault. + * Assumes that the second TSB only contains 4M mappings. + * + * In: + * tagacc = tag access register (not clobbered) + * tsbe = 2nd TSB base register + * tmp1, tmp2 = scratch registers + * Out: + * tsbe = pointer to the tsbe in the 2nd TSB + */ + +#define GET_2ND_TSBE_PTR(tagacc, tsbe, tmp1, tmp2) \ + and tsbe, TSB_SOFTSZ_MASK, tmp2; /* tmp2=szc */ \ + andn tsbe, TSB_SOFTSZ_MASK, tsbe; /* tsbbase */ \ + mov TSB_ENTRIES(0), tmp1; /* nentries in TSB size 0 */ \ + sllx tmp1, tmp2, tmp1; /* tmp1 = nentries in TSB */ \ + sub tmp1, 1, tmp1; /* mask = nentries - 1 */ \ + srlx tagacc, MMU_PAGESHIFT4M, tmp2; \ + and tmp2, tmp1, tmp1; /* tsbent = virtpage & mask */ \ + sllx tmp1, TSB_ENTRY_SHIFT, tmp1; /* entry num --> ptr */ \ + add tsbe, tmp1, tsbe /* add entry offset to TSB base */ + +/* + * Read the 2nd TSB base register. This is not done in GET_2ND_TSBE_PTR as + * an optimization since the TLB miss trap handler entries have potentially + * already loaded the 2nd TSB base reg when we invoke GET_2ND_TSBE_PTR. + * + * Out: + * tsbreg = contents of the 2nd TSB base register + */ +#define GET_2ND_TSBREG(tsbreg) \ + GET_UTSBREG(SCRATCHPAD_UTSBREG, tsbreg); + +/* + * Load the 2nd TSB base into a dedicated scratchpad register which + * is used as a pseudo TSB base register. + * + * In: + * tsbreg = value to load (ro) + * regnum = constant or register + * tmp1 = scratch register + * Out: + * Specified scratchpad register updated + */ +#define LOAD_2ND_TSBREG(tsbreg, tmp1) \ + SET_UTSBREG(SCRATCHPAD_UTSBREG, tsbreg, tmp1); + +#endif /* UTSB_PHYS */ + + +/* + * Load TSB base register. In the single TSB case this register + * contains utsb_vabase, bits 21:13 of tsbinfo->tsb_va, and the + * TSB size code in bits 2:0. See hat_sfmmu.h for the layout in + * the case where we have multiple TSBs per process. + * + * In: + * tsbreg = value to load (ro) + */ +#define LOAD_TSBREG(tsbreg, tmp1, tmp2) \ + mov MMU_TSB, tmp1; \ + sethi %hi(FLUSH_ADDR), tmp2; \ + stxa tsbreg, [tmp1]ASI_DMMU; /* dtsb reg */ \ + stxa tsbreg, [tmp1]ASI_IMMU; /* itsb reg */ \ + flush tmp2 + +#ifdef UTSB_PHYS +#define UTSB_PROBE_ASI ASI_QUAD_LDD_PHYS +#else +#define UTSB_PROBE_ASI ASI_NQUAD_LD +#endif + +/* + * Will probe the first TSB, and if it finds a match, will insert it + * into the TLB and retry. + * + * tsbe_ptr = precomputed first TSB entry pointer (in, ro) + * vpg_4m = 4M virtual page number for tag matching (in, ro) + * label = where to branch to if this is a miss (text) + * %asi = atomic ASI to use for the TSB access + * + * For trapstat, we have to explicily use these registers. + * g4 = location tag will be retrieved into from TSB (out) + * g5 = location data(tte) will be retrieved into from TSB (out) + */ +#define PROBE_1ST_DTSB(tsbe_ptr, vpg_4m, label) /* g4/g5 clobbered */ \ + /* BEGIN CSTYLED */ \ + ldda [tsbe_ptr]UTSB_PROBE_ASI, %g4 /* g4 = tag, g5 = data */ ;\ + cmp %g4, vpg_4m /* compare tag w/ TSB */ ;\ + bne,pn %xcc, label/**/1 /* branch if !match */ ;\ + nop ;\ + TT_TRACE(trace_tsbhit) ;\ + DTLB_STUFF(%g5, %g1, %g2, %g3, %g4) ;\ + /* trapstat expects tte in %g5 */ ;\ + retry /* retry faulted instruction */ ;\ +label/**/1: \ + /* END CSTYLED */ + +/* + * Same as above, only if the TTE doesn't have the execute + * bit set, will branch to exec_fault directly. + */ +#define PROBE_1ST_ITSB(tsbe_ptr, vpg_4m, label) \ + /* BEGIN CSTYLED */ \ + ldda [tsbe_ptr]UTSB_PROBE_ASI, %g4 /* g4 = tag, g5 = data */ ;\ + cmp %g4, vpg_4m /* compare tag w/ TSB */ ;\ + bne,pn %xcc, label/**/1 /* branch if !match */ ;\ + nop ;\ + andcc %g5, TTE_EXECPRM_INT, %g0 /* check execute bit */ ;\ + bz,pn %icc, exec_fault ;\ + nop ;\ + TT_TRACE(trace_tsbhit) ;\ + ITLB_STUFF(%g5, %g1, %g2, %g3, %g4) ;\ + retry /* retry faulted instruction */ ;\ +label/**/1: \ + /* END CSTYLED */ /* * vpg_4m = 4M virtual page number for tag matching (in) @@ -577,7 +725,7 @@ label/**/_get_2nd_tsb_base: ;\ */ #define PROBE_2ND_DTSB(tsbe_ptr, vpg_4m, label) \ /* BEGIN CSTYLED */ \ - ldda [tsbe_ptr]%asi, %g4 /* g4 = tag, g5 = data */ ;\ + ldda [tsbe_ptr]UTSB_PROBE_ASI, %g4 /* g4 = tag, g5 = data */ ;\ /* since we are looking at 2nd tsb, if it's valid, it must be 4M */ ;\ cmp %g4, vpg_4m ;\ bne,pn %xcc, label/**/1 ;\ @@ -599,7 +747,7 @@ label/**/1: \ */ #define PROBE_2ND_ITSB(tsbe_ptr, vpg_4m, label) \ /* BEGIN CSTYLED */ \ - ldda [tsbe_ptr]%asi, %g4 /* g4 = tag, g5 = data */ ;\ + ldda [tsbe_ptr]UTSB_PROBE_ASI, %g4 /* g4 = tag, g5 = data */ ;\ cmp %g4, vpg_4m /* compare tag w/ TSB */ ;\ bne,pn %xcc, sfmmu_tsb_miss_tt /* branch if !match */ ;\ or %g0, TTE4M, %g6 ;\ @@ -621,7 +769,7 @@ label/**/1: ;\ */ #define PROBE_2ND_ITSB(tsbe_ptr, vpg_4m, label) \ /* BEGIN CSTYLED */ \ - ldda [tsbe_ptr]%asi, %g4 /* g4 = tag, g5 = data */ ;\ + ldda [tsbe_ptr]UTSB_PROBE_ASI, %g4 /* g4 = tag, g5 = data */ ;\ cmp %g4, vpg_4m /* compare tag w/ TSB */ ;\ bne,pn %xcc, sfmmu_tsb_miss_tt /* branch if !match */ ;\ or %g0, TTE4M, %g6 ;\ diff --git a/usr/src/uts/sun4u/vm/mach_sfmmu_asm.s b/usr/src/uts/sun4u/vm/mach_sfmmu_asm.s index 18ba9d3441..0a68ce88f7 100644 --- a/usr/src/uts/sun4u/vm/mach_sfmmu_asm.s +++ b/usr/src/uts/sun4u/vm/mach_sfmmu_asm.s @@ -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,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -338,7 +337,11 @@ sfmmu_load_mmustate(sfmmu_t *sfmmup) or %o0, %lo(sfmmu_panic5), %o0 ! give up. 4: stxa %o0,[%o5]ASI_DMMU ! Setup tag access +#ifdef OLYMPUS_SHARED_FTLB + stxa %g1,[%g0]ASI_DTLB_IN +#else stxa %g1,[%g3]ASI_DTLB_ACCESS ! Displace entry at idx +#endif membar #Sync retl wrpr %g0, %o3, %pstate ! enable interrupts @@ -399,16 +402,24 @@ sfmmu_load_mmustate(sfmmu_t *sfmmup) /* * set ktsb_phys to 1 if the processor supports ASI_QUAD_LDD_PHYS. * returns the detection value in %o0. + * + * Currently ASI_QUAD_LDD_PHYS is supported in processors as follows + * - cheetah+ and later (greater or equal to CHEETAH_PLUS_IMPL) + * - FJ OPL Olympus-C and later (less than SPITFIRE_IMPL) + * */ ENTRY_NP(sfmmu_setup_4lp) GET_CPU_IMPL(%o0); cmp %o0, CHEETAH_PLUS_IMPL - blt,a,pt %icc, 4f + bge,pt %icc, 4f + mov 1, %o1 + cmp %o0, SPITFIRE_IMPL + bge,a,pn %icc, 3f clr %o1 +4: set ktsb_phys, %o2 - mov 1, %o1 st %o1, [%o2] -4: retl +3: retl mov %o1, %o0 SET_SIZE(sfmmu_setup_4lp) @@ -446,7 +457,24 @@ sfmmu_load_mmustate(sfmmu_t *sfmmup) */ ldx [%o0 + SFMMU_TSB], %o1 ! %o1 = first tsbinfo ldx [%o1 + TSBINFO_NEXTPTR], %g2 ! %g2 = second tsbinfo - brz,pt %g2, 4f + +#ifdef UTSB_PHYS + /* + * UTSB_PHYS accesses user TSBs via physical addresses. The first + * TSB is in the MMU I/D TSB Base registers. The second TSB uses a + * designated ASI_SCRATCHPAD register as a pseudo TSB base register. + */ + MAKE_UTSBREG_PHYS(%o1, %o2, %o3) ! %o2 = first utsbreg + LOAD_TSBREG(%o2, %o3, %o4) ! write TSB base register + + brz,a,pt %g2, 2f + mov -1, %o2 ! use -1 if no second TSB + + MAKE_UTSBREG_PHYS(%g2, %o2, %o3) ! %o2 = second utsbreg +2: + LOAD_2ND_TSBREG(%o2, %o3) ! write 2nd pseudo TSB base register +#else /* UTSB_PHYS */ + brz,pt %g2, 4f nop /* * We have a second TSB for this process, so we need to @@ -485,6 +513,7 @@ sfmmu_load_mmustate(sfmmu_t *sfmmup) sll %o2, DTACC_SHIFT, %o2 ! %o1 = first TSB TLB index RESV_OFFSET(%o1, %g3, %o3, sfmmu_tsb_1st) ! or-in bits of TSB VA LOAD_TSBTTE(%o1, %o2, %g3, %o4) ! load first TSB locked TTE +#endif /* UTSB_PHYS */ 6: ldx [%o0 + SFMMU_ISMBLKPA], %o1 ! copy members of sfmmu CPU_TSBMISS_AREA(%o2, %o3) ! we need to access from @@ -639,4 +668,3 @@ prefetch_tsbe_write(struct tsbe *tsbep) #ifndef lint #endif /* lint */ - diff --git a/usr/src/uts/sun4v/Makefile.workarounds b/usr/src/uts/sun4v/Makefile.workarounds index 0945c5cfcb..40a76c9693 100644 --- a/usr/src/uts/sun4v/Makefile.workarounds +++ b/usr/src/uts/sun4v/Makefile.workarounds @@ -33,3 +33,4 @@ WORKAROUND_DEFS = WORKAROUND_DEFS += -DQCN_POLLING # XXXQ +WORKAROUND_DEFS += -DDO_CORELEVEL_LOADBAL diff --git a/usr/src/uts/sun4v/io/px/px_lib4v.c b/usr/src/uts/sun4v/io/px/px_lib4v.c index 188a5d8d9d..d0477106d0 100644 --- a/usr/src/uts/sun4v/io/px/px_lib4v.c +++ b/usr/src/uts/sun4v/io/px/px_lib4v.c @@ -419,6 +419,17 @@ px_lib_iommu_getmap(dev_info_t *dip, tsbid_t tsbid, io_attributes_t *attr_p, return (DDI_SUCCESS); } +/* + * fetch chip's range propery's value. For sun4v, config space base + * is not used (pxtool_get_phys_addr) will return zero, so just return + * zero for px_get_range_prop(). + */ +/*ARGSUSED*/ +uint64_t +px_get_range_prop(px_t *px_p, px_ranges_t *rp, int bank) +{ + return (0); +} /* * Checks dma attributes against system bypass ranges @@ -427,7 +438,8 @@ px_lib_iommu_getmap(dev_info_t *dip, tsbid_t tsbid, io_attributes_t *attr_p, */ /*ARGSUSED*/ int -px_lib_dma_bypass_rngchk(ddi_dma_attr_t *attr_p, uint64_t *lo_p, uint64_t *hi_p) +px_lib_dma_bypass_rngchk(dev_info_t *dip, ddi_dma_attr_t *attr_p, + uint64_t *lo_p, uint64_t *hi_p) { if ((attr_p->dma_attr_addr_lo != 0ull) || (attr_p->dma_attr_addr_hi != UINT64_MAX)) { |