diff options
author | Dan McDonald <danmcd@mnx.io> | 2022-07-11 11:42:08 -0400 |
---|---|---|
committer | Dan McDonald <danmcd@mnx.io> | 2022-07-11 11:42:08 -0400 |
commit | 2392c818d2f71eb00ab8baf8acc9129b4b48b4cd (patch) | |
tree | 4cd6eb41c8d3365a0da6670107ad42a4823dc6bf | |
parent | 291a32a88d9418d4adb17301929fb9bee9146b72 (diff) | |
parent | 9174bfaa08ca3aa4c0a12e840c4bd4f2570237a0 (diff) | |
download | illumos-joyent-2392c818d2f71eb00ab8baf8acc9129b4b48b4cd.tar.gz |
[illumos-gate merge]
commit 9174bfaa08ca3aa4c0a12e840c4bd4f2570237a0
14780 remove aoutexec module
14806 system(5) dacf is not SPARC specific
commit e27085df90712f99e5ea3d44ab0b83c73ac1bf52
14580 loader.efi: detect console from ConOut/ConOutDev
commit 92ee55c7e1c76d6edfc89c4ad988922d56888580
14706 Tidy up the rpc_soc.3nsl manual
commit 06d7f587729595e6085b8b33777ff119f3a9b767
14785 vioscsi timeout list insertion error
commit c0586b874d9179e81ca8a124fa6caf98fddb7696
14783 pvscsi modernization
commit 93686a1e2cbe9bdcb1d8d3bf1870465ba0a43b1c
14782 sd.c warning message: "Unable to clean up memory" misguided
44 files changed, 2500 insertions, 6402 deletions
diff --git a/usr/src/boot/Makefile.version b/usr/src/boot/Makefile.version index 6ec72af057..3f11cd86eb 100644 --- a/usr/src/boot/Makefile.version +++ b/usr/src/boot/Makefile.version @@ -34,4 +34,4 @@ LOADER_VERSION = 1.1 # Use date like formatting here, YYYY.MM.DD.XX, without leading zeroes. # The version is processed from left to right, the version number can only # be increased. -BOOT_VERSION = $(LOADER_VERSION)-2022.06.27.1 +BOOT_VERSION = $(LOADER_VERSION)-2022.07.04.1 diff --git a/usr/src/boot/efi/include/efidevp.h b/usr/src/boot/efi/include/efidevp.h index bd8f304922..ed2f55fd73 100644 --- a/usr/src/boot/efi/include/efidevp.h +++ b/usr/src/boot/efi/include/efidevp.h @@ -154,9 +154,48 @@ typedef struct _ACPI_EXTENDED_HID_DEVICE_PATH { #define PNP_EISA_ID_MASK 0xffff #define EISA_ID_TO_NUM(_Id) ((_Id) >> 16) + /* - * + * ACPI _ADR Device Path SubType. + */ +#define ACPI_ADR_DP 0x03 + +/* + * The _ADR device path is used to contain video output device attributes to + * support the Graphics Output Protocol. + * The device path can contain multiple _ADR entries if multiple video output + * devices are displaying the same output. */ +typedef struct { + EFI_DEVICE_PATH Header; + /* + * _ADR value. For video output devices the value of this + * field comes from Table B-2 of the ACPI 3.0 specification. At + * least one _ADR value is required. + */ + UINT32 ADR; + /* + * This device path may optionally contain more than one _ADR entry. + */ +} ACPI_ADR_DEVICE_PATH; + +#define ACPI_ADR_DISPLAY_TYPE_OTHER 0 +#define ACPI_ADR_DISPLAY_TYPE_VGA 1 +#define ACPI_ADR_DISPLAY_TYPE_TV 2 +#define ACPI_ADR_DISPLAY_TYPE_EXTERNAL_DIGITAL 3 +#define ACPI_ADR_DISPLAY_TYPE_INTERNAL_DIGITAL 4 + +#define ACPI_DISPLAY_ADR(_DeviceIdScheme, _HeadId, _NonVgaOutput, \ + _BiosCanDetect, _VendorInfo, _Type, _Port, _Index) \ + ((UINT32)( ((UINT32)((_DeviceIdScheme) & 0x1) << 31) | \ + (((_HeadId) & 0x7) << 18) | \ + (((_NonVgaOutput) & 0x1) << 17) | \ + (((_BiosCanDetect) & 0x1) << 16) | \ + (((_VendorInfo) & 0xf) << 12) | \ + (((_Type) & 0xf) << 8) | \ + (((_Port) & 0xf) << 4) | \ + ((_Index) & 0xf) )) + #define MESSAGING_DEVICE_PATH 0x03 #define MSG_ATAPI_DP 0x01 diff --git a/usr/src/boot/efi/loader/main.c b/usr/src/boot/efi/loader/main.c index 82b0936cde..9c3a6a2c46 100644 --- a/usr/src/boot/efi/loader/main.c +++ b/usr/src/boot/efi/loader/main.c @@ -61,6 +61,7 @@ EFI_GUID imgid = LOADED_IMAGE_PROTOCOL; EFI_GUID smbios = SMBIOS_TABLE_GUID; EFI_GUID smbios3 = SMBIOS3_TABLE_GUID; EFI_GUID inputid = SIMPLE_TEXT_INPUT_PROTOCOL; +EFI_GUID serialio = SERIAL_IO_PROTOCOL; extern void acpi_detect(void); extern void efi_getsmap(void); @@ -489,12 +490,214 @@ interactive_interrupt(const char *msg) return (false); } +static void +setenv_int(const char *key, int val) +{ + char buf[20]; + + (void) snprintf(buf, sizeof (buf), "%d", val); + (void) setenv(key, buf, 1); +} + +/* + * Parse ConOut (the list of consoles active) and see if we can find a + * serial port and/or a video port. It would be nice to also walk the + * ACPI name space to map the UID for the serial port to a port. The + * latter is especially hard. + */ +static int +parse_uefi_con_out(void) +{ + int how, rv; + int vid_seen = 0, com_seen = 0, seen = 0; + size_t sz; + char buf[4096], *ep; + EFI_DEVICE_PATH *node; + ACPI_HID_DEVICE_PATH *acpi; + UART_DEVICE_PATH *uart; + bool pci_pending = false; + + how = 0; + sz = sizeof (buf); + rv = efi_global_getenv("ConOut", buf, &sz); + if (rv != EFI_SUCCESS) + rv = efi_global_getenv("ConOutDev", buf, &sz); + if (rv != EFI_SUCCESS) { + /* + * If we don't have any ConOut default to video. + * non-server systems may not have serial. + */ + goto out; + } + ep = buf + sz; + node = (EFI_DEVICE_PATH *)buf; + while ((char *)node < ep) { + if (IsDevicePathEndType(node)) { + if (pci_pending && vid_seen == 0) + vid_seen = ++seen; + } + pci_pending = false; + if (DevicePathType(node) == ACPI_DEVICE_PATH && + (DevicePathSubType(node) == ACPI_DP || + DevicePathSubType(node) == ACPI_EXTENDED_DP)) { + /* Check for Serial node */ + acpi = (void *)node; + if (EISA_ID_TO_NUM(acpi->HID) == 0x501) { + setenv_int("efi_8250_uid", acpi->UID); + com_seen = ++seen; + } + } else if (DevicePathType(node) == MESSAGING_DEVICE_PATH && + DevicePathSubType(node) == MSG_UART_DP) { + com_seen = ++seen; + uart = (void *)node; + setenv_int("efi_com_speed", uart->BaudRate); + } else if (DevicePathType(node) == ACPI_DEVICE_PATH && + DevicePathSubType(node) == ACPI_ADR_DP) { + /* Check for AcpiAdr() Node for video */ + vid_seen = ++seen; + } else if (DevicePathType(node) == HARDWARE_DEVICE_PATH && + DevicePathSubType(node) == HW_PCI_DP) { + /* + * Note, vmware fusion has a funky console device + * PciRoot(0x0)/Pci(0xf,0x0) + * which we can only detect at the end since we also + * have to cope with: + * PciRoot(0x0)/Pci(0x1f,0x0)/Serial(0x1) + * so only match it if it's last. + */ + pci_pending = true; + } + node = NextDevicePathNode(node); /* Skip the end node */ + } + + /* + * Truth table for RB_MULTIPLE | RB_SERIAL + * Value Result + * 0 Use only video console + * RB_SERIAL Use only serial console + * RB_MULTIPLE Use both video and serial console + * (but video is primary so gets rc messages) + * both Use both video and serial console + * (but serial is primary so gets rc messages) + * + * Try to honor this as best we can. If only one of serial / video + * found, then use that. Otherwise, use the first one we found. + * This also implies if we found nothing, default to video. + */ + how = 0; + if (vid_seen && com_seen) { + how |= RB_MULTIPLE; + if (com_seen < vid_seen) + how |= RB_SERIAL; + } else if (com_seen) + how |= RB_SERIAL; +out: + return (how); +} + caddr_t ptov(uintptr_t x) { return ((caddr_t)x); } +static int +efi_serial_get_uid(EFI_DEVICE_PATH *devpath) +{ + ACPI_HID_DEVICE_PATH *acpi; + + while (!IsDevicePathEnd(devpath)) { + if (DevicePathType(devpath) == ACPI_DEVICE_PATH && + (DevicePathSubType(devpath) == ACPI_DP || + DevicePathSubType(devpath) == ACPI_EXTENDED_DP)) { + acpi = (ACPI_HID_DEVICE_PATH *)devpath; + if (EISA_ID_TO_NUM(acpi->HID) == 0x501) { + return (acpi->UID); + } + } + + devpath = NextDevicePathNode(devpath); + } + return (-1); +} + +/* + * Walk serialio protocol handle array and find index for serial console + * device. The problem is, we check for acpi UID value, but we can not be sure, + * if it will start from 0 or 1. + */ +static const char * +uefi_serial_console(void) +{ + UINTN bufsz; + EFI_STATUS status; + EFI_HANDLE *handles; + int i, nhandles; + unsigned long uid, lowest; + char *env, *ep; + extern struct console ttya; + extern struct console ttyb; + extern struct console ttyc; + extern struct console ttyd; + + env = getenv("efi_8250_uid"); + if (env == NULL) + return (NULL); + (void) unsetenv("efi_8250_uid"); + errno = 0; + uid = strtoul(env, &ep, 10); + if (errno != 0 || *ep != '\0') + return (NULL); + + /* if uid is 0, this is first serial port */ + if (uid == 0) + return (ttya.c_name); + + /* + * get buffer size + */ + bufsz = 0; + handles = NULL; + status = BS->LocateHandle(ByProtocol, &serialio, NULL, &bufsz, handles); + if (status != EFI_BUFFER_TOO_SMALL) + return (NULL); + if ((handles = malloc(bufsz)) == NULL) + return (NULL); + + /* + * get handle array + */ + status = BS->LocateHandle(ByProtocol, &serialio, NULL, &bufsz, handles); + if (EFI_ERROR(status)) { + free(handles); + return (NULL); + } + nhandles = (int)(bufsz / sizeof (EFI_HANDLE)); + + lowest = 255; /* high enough value */ + for (i = 0; i < nhandles; i++) { + EFI_DEVICE_PATH *devpath; + unsigned long _uid; + + devpath = efi_lookup_devpath(handles[i]); + _uid = efi_serial_get_uid(devpath); + if (_uid < lowest) + lowest = _uid; + } + free(handles); + switch (uid - lowest) { + case 0: + return (ttya.c_name); + case 1: + return (ttyb.c_name); + case 2: + return (ttyc.c_name); + case 3: + return (ttyd.c_name); + } + return (NULL); +} + EFI_STATUS main(int argc, CHAR16 *argv[]) { @@ -504,6 +707,7 @@ main(int argc, CHAR16 *argv[]) void *ptr; bool has_kbd; char *s; + const char *serial; EFI_DEVICE_PATH *imgpath; CHAR16 *text; EFI_STATUS status; @@ -527,25 +731,43 @@ main(int argc, CHAR16 *argv[]) /* Get our loaded image protocol interface structure. */ (void) OpenProtocolByHandle(IH, &imgid, (void **)&img); - /* Init the time source */ - efi_time_init(); - - has_kbd = has_keyboard(); - /* * XXX Chicken-and-egg problem; we want to have console output * early, but some console attributes may depend on reading from * eg. the boot device, which we can't do yet. We can use * printf() etc. once this is done. */ + setenv("console", "text", 1); + howto = parse_uefi_con_out(); + serial = uefi_serial_console(); cons_probe(); efi_getsmap(); + if ((s = getenv("efi_com_speed")) != NULL) { + char *name; + + (void) snprintf(var, sizeof (var), "%s,8,n,1,-", s); + if (asprintf(&name, "%s-mode", serial) > 0) { + (void) setenv (name, var, 1); + free(name); + } + if (asprintf(&name, "%s-spcr-mode", serial) > 0) { + (void) setenv (name, var, 1); + free(name); + } + (void) unsetenv("efi_com_speed"); + } + + /* Init the time source */ + efi_time_init(); + /* * Initialise the block cache. Set the upper limit. */ bcache_init(32768, 512); + has_kbd = has_keyboard(); + /* * Parse the args to set the console settings, etc * iPXE may be setup to pass these in. Or the optional argument in the @@ -558,7 +780,6 @@ main(int argc, CHAR16 *argv[]) * args from UCS-2 to ASCII (16 to 8 bit) as they are copied (though * this method is flawed for non-ASCII characters). */ - howto = 0; for (i = 1; i < argc; i++) { if (argv[i][0] == '-') { for (j = 1; argv[i][j] != 0; j++) { @@ -647,13 +868,15 @@ main(int argc, CHAR16 *argv[]) */ if (howto & RB_MULTIPLE) { if (howto & RB_SERIAL) - setenv("console", "ttya text", 1); + (void) snprintf(var, sizeof (var), "%s text", serial); else - setenv("console", "text ttya", 1); + (void) snprintf(var, sizeof (var), "text %s", serial); } else if (howto & RB_SERIAL) { - setenv("console", "ttya", 1); - } else - setenv("console", "text", 1); + (void) snprintf(var, sizeof (var), "%s", serial); + } else { + (void) snprintf(var, sizeof (var), "text"); + } + (void) setenv("console", var, 1); if ((s = getenv("fail_timeout")) != NULL) fail_timeout = strtol(s, NULL, 10); diff --git a/usr/src/cmd/sgs/Makefile b/usr/src/cmd/sgs/Makefile index 3b34e0a882..42547e014f 100644 --- a/usr/src/cmd/sgs/Makefile +++ b/usr/src/cmd/sgs/Makefile @@ -23,6 +23,7 @@ # Copyright 2016 RackTop Systems. # Copyright 2017 Joyent, Inc. # Copyright 2019 OmniOS Community Edition (OmniOSce) Association. +# Copyright 2022 Garrett D'Amore <garrett@damore.org> # include $(SRC)/cmd/Makefile.cmd @@ -81,10 +82,7 @@ SUBDIRS-common= libconv \ .WAIT \ demo_rdb -SUBDIRS-i386= -SUBDIRS-sparc= rtld.4.x - -SUBDIRS= $(SUBDIRS-common) $(SUBDIRS-$(MACH)) +SUBDIRS= $(SUBDIRS-common) # Messaging support # @@ -153,10 +151,8 @@ $(SUBDIRS): FRC FRC: # -# Cross-reference customization: ignore the directories named by XRPRUNE, -# and tweak the file globs slightly. +# Cross-reference customization: tweak the file globs slightly. # -XRPRUNE= rtld.4.x abi XRADD= *.msg mapfile* XRDEL= Makefile* kobj_* diff --git a/usr/src/cmd/sgs/ldd/common/ldd.c b/usr/src/cmd/sgs/ldd/common/ldd.c index c686b51e0e..8680d95ea0 100644 --- a/usr/src/cmd/sgs/ldd/common/ldd.c +++ b/usr/src/cmd/sgs/ldd/common/ldd.c @@ -38,11 +38,9 @@ * file with a dynamic executable stub. The runtime linker (ld.so.1) actually * provides the diagnostic output, according to the environment variables set. * - * If neither -d nor -r is specified, we set only LD_TRACE_LOADED_OBJECTS_[AE]. + * If neither -d nor -r is specified, we set only LD_TRACE_LOADED_OBJECTS_E. * The runtime linker will print the pathnames of all dynamic objects it - * loads, and then exit. Note that we distiguish between ELF and AOUT objects - * when setting this environment variable - AOUT executables cause the mapping - * of sbcp, the dependencies of which the user isn't interested in. + * loads, and then exit. * * If -d or -r is specified, we also set LD_WARN=1; the runtime linker will * perform its normal relocations and issue warning messages for unresolved @@ -126,7 +124,6 @@ #include "msg.h" static int elf_check(int, char *, char *, Elf *, int); -static int aout_check(int, char *, char *, int, int); static int run(int, char *, char *, const char *, int); @@ -136,7 +133,6 @@ static int run(int, char *, char *, const char *, int); */ static char bind[] = "LD_BIND_NOW= ", load_elf[] = "LD_TRACE_LOADED_OBJECTS_E= ", - load_aout[] = "LD_TRACE_LOADED_OBJECTS_A= ", path[] = "LD_TRACE_SEARCH_PATHS= ", verb[] = "LD_VERBOSE= ", warn[] = "LD_WARN= ", @@ -356,8 +352,7 @@ main(int argc, char **argv, char **envp) } /* - * Get the files elf descriptor and process it as an elf or - * a.out (4.x) file. + * Get the files elf descriptor and process it as an elf file. */ elf = elf_begin(var, ELF_C_READ, (Elf *)0); switch (elf_kind(elf)) { @@ -366,21 +361,15 @@ main(int argc, char **argv, char **envp) cname, fname); error = 1; break; - case ELF_K_COFF: - (void) fprintf(stderr, MSG_INTL(MSG_USP_UNKNOWN), - cname, fname); - error = 1; - break; case ELF_K_ELF: if (elf_check(nfile, fname, cname, elf, fflag) != 0) error = 1; break; + case ELF_K_COFF: default: - /* - * This is either an unknown file or an aout format - */ - if (aout_check(nfile, fname, cname, var, fflag) != 0) - error = 1; + (void) fprintf(stderr, MSG_INTL(MSG_USP_UNKNOWN), + cname, fname); + error = 1; break; } (void) elf_end(elf); @@ -570,52 +559,6 @@ elf_check(int nfile, char *fname, char *cname, Elf *elf, int fflag) return (run(nfile, cname, fname, conv_lddstub(class), class)); } -static int -aout_check(int nfile, char *fname, char *cname, int fd, int fflag) -{ - struct exec32 aout; - int err; - - if (lseek(fd, 0, SEEK_SET) != 0) { - err = errno; - (void) fprintf(stderr, MSG_INTL(MSG_SYS_LSEEK), cname, fname, - strerror(err)); - return (1); - } - if (read(fd, (char *)&aout, sizeof (aout)) != sizeof (aout)) { - err = errno; - (void) fprintf(stderr, MSG_INTL(MSG_SYS_READ), cname, fname, - strerror(err)); - return (1); - } - if (aout.a_machtype != M_SPARC) { - (void) fprintf(stderr, MSG_INTL(MSG_USP_UNKNOWN), cname, fname); - return (1); - } - if (N_BADMAG(aout) || !aout.a_dynamic) { - (void) fprintf(stderr, MSG_INTL(MSG_USP_NODYNORSO), cname, - fname); - return (1); - } - if (!fflag && (geteuid() == 0)) { - (void) fprintf(stderr, MSG_INTL(MSG_USP_AOUTINS), cname, fname); - return (1); - } - - /* - * Run the required program. - */ - if ((aout.a_magic == ZMAGIC) && (aout.a_entry <= sizeof (aout))) { - load = load_elf; - return (run(nfile, cname, fname, conv_lddstub(ELFCLASS32), - ELFCLASS32)); - } else { - load = load_aout; - return (run(nfile, cname, fname, (const char *)fname, - ELFCLASS32)); - } -} - /* * Run the required program, setting the preload and trace environment @@ -708,9 +651,8 @@ run(int nfile, char *cname, char *fname, const char *ename, int class) } /* - * The pointer "load" has be assigned to load_elf[] or - * load_aout[]. Use the size of load_elf[] as the size - * of load_aout[] is the same. + * The pointer "load" has be assigned to load_elf[]. + * Use the size of load_elf[]. */ load[sizeof (load_elf) - 2] = '2'; } else diff --git a/usr/src/cmd/sgs/ldd/common/ldd.msg b/usr/src/cmd/sgs/ldd/common/ldd.msg index 2f2301cd44..e5e40569d7 100644 --- a/usr/src/cmd/sgs/ldd/common/ldd.msg +++ b/usr/src/cmd/sgs/ldd/common/ldd.msg @@ -1,5 +1,6 @@ # # Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved. +# Copyright 2022 Garrett D'Amore <garrett@damore.org> # # CDDL HEADER START # @@ -46,7 +47,6 @@ @ MSG_USP_NOHDR "%s: %s: file built with ?N (NOHDR) mapfile option\n" @ MSG_USP_UNKNOWN "%s: %s: unsupported or unknown file type\n" @ MSG_USP_ELFINS "%s: %s: file has insecure interpreter %s\n" -@ MSG_USP_AOUTINS "%s: %s: insecure a.out file\n" @ MSG_USP_NOTEXEC "%s: %s: is not executable\n" @@ -69,8 +69,6 @@ # System error messages -@ MSG_SYS_LSEEK "%s: %s: cannot lseek file: %s\n" -@ MSG_SYS_READ "%s: %s: cannot read file: %s\n" @ MSG_SYS_FORK "%s: cannot fork: %s\n" @ MSG_SYS_OPEN "%s: %s: cannot open file: %s\n" diff --git a/usr/src/cmd/sgs/prof/common/prof.c b/usr/src/cmd/sgs/prof/common/prof.c index 3de4437a31..caee53618b 100644 --- a/usr/src/cmd/sgs/prof/common/prof.c +++ b/usr/src/cmd/sgs/prof/common/prof.c @@ -209,7 +209,6 @@ struct snymEntry { }; -#define AOUTHSZ (filhdr.f_opthdr) PROF_FILE filhdr; /* profile file descriptor */ Elf32_Shdr *scnhdrp; /* pointer to first section header */ /* (space by _prof_Malloc) */ diff --git a/usr/src/cmd/sgs/rtld.4.x/Makefile b/usr/src/cmd/sgs/rtld.4.x/Makefile deleted file mode 100644 index 660f5d2697..0000000000 --- a/usr/src/cmd/sgs/rtld.4.x/Makefile +++ /dev/null @@ -1,45 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -# Copyright (c) 1990 by Sun Microsystems, Inc. -# Copyright 2019 OmniOS Community Edition (OmniOSce) Association. -# - -#include library definitions -include ../../../lib/Makefile.lib - -FILE= ld.so -ROOTFILE= $(ROOTLIBDIR)/$(FILE) - -FILEMODE= 755 - -$(ROOTLIBDIR)/%: % - $(INS.file) - -.KEEP_STATE: - -all: - -install: $(ROOTFILE) - -clean: - -clobber: clean diff --git a/usr/src/cmd/sgs/rtld.4.x/Makefile.4.x b/usr/src/cmd/sgs/rtld.4.x/Makefile.4.x deleted file mode 100644 index 463a24382a..0000000000 --- a/usr/src/cmd/sgs/rtld.4.x/Makefile.4.x +++ /dev/null @@ -1,51 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -# -# ident "%Z%%M% %I% %E% SMI" -# -# Copyright 2003 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -# On a 4.x machine (fourdotx), point ROOT at the header files you're using, -# and do: -# -# % sccs edit ld.so -# % make -f Makefile.4.x all -# <test it a lot> -# % sccs delget ld.so -# -# Unfortunately, at least <sys/isa_defs.h>, <sys/feature_tests.h> and <libelf.h> -# contain an '#error' line that makes the 4.x cpp choke (even though it -# shouldn't parse the error clause). You may need to delete the '#' sign to -# compile each object. - -OBJS= rtldlib.o rtld.4.x.o rtsubrs.o div.o umultiply.o rem.o zero.o - -all: ${OBJS} - ld -o ld.so -Bsymbolic -assert nosymbolic -assert pure-text ${OBJS} - -%.o:%.s - as -k -P -I$(ROOT)/usr/include -D_SYS_SYS_S -D_ASM $< - mv -f a.out $*.o - -%.o:%.c - cc -c -O -I$(ROOT)/usr/include -pic -D_NO_LONGLONG $< diff --git a/usr/src/cmd/sgs/rtld.4.x/div.s b/usr/src/cmd/sgs/rtld.4.x/div.s deleted file mode 100644 index 5a09c9d960..0000000000 --- a/usr/src/cmd/sgs/rtld.4.x/div.s +++ /dev/null @@ -1,437 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ - -! .seg "data" -! .asciz "Copyr 1986 Sun Micro" - .seg "text" - -#ident "%Z%%M% %I% %E% SMI" - -/* - * Copyright 1986 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -/* - * divison/remainder - * - * Input is: - * dividend -- the thing being divided - * divisor -- how many ways to divide - * Important parameters: - * N -- how many bits per iteration we try to get - * as our current guess: - * WORDSIZE -- how many bits altogether we're talking about: - * obviously: - * A derived constant: - * TOPBITS -- how many bits are in the top "decade" of a number: - * - * Important variables are: - * Q -- the partial quotient under development -- initally 0 - * R -- the remainder so far -- initially == the dividend - * ITER -- number of iterations of the main division loop will - * be required. Equal to CEIL( lg2(quotient)/4 ) - * Note that this is log_base_(2^4) of the quotient. - * V -- the current comparand -- initially divisor*2^(ITER*4-1) - * Cost: - * current estimate for non-large dividend is - * CEIL( lg2(quotient) / 4 ) x ( 10 + 74/2 ) + C - * a large dividend is one greater than 2^(31-4 ) and takes a - * different path, as the upper bits of the quotient must be developed - * one bit at a time. - */ - -#include <sys/trap.h> -#include <sys/asm_linkage.h> - - - - - - - - - ! working variable - - -/* - * this is the recursive definition of how we develop quotient digits. - * it takes three important parameters: - * $1 -- the current depth, 1<=$1<=4 - * $2 -- the current accumulation of quotient bits - * 4 -- max depth - * We add a new bit to $2 and either recurse or - * insert the bits in the quotient. - * Dynamic input: - * %o3 -- current remainder - * %o2 -- current quotient - * %o5 -- current comparand - * cc -- set on current value of %o3 - * Dynamic output: - * %o3', %o2', %o5', cc' - */ - - - - - -! RTENTRY(.udiv) ! unsigned divide - .global .udiv -.udiv: - b divide - mov 0,%g1 ! result always positive - -! RTENTRY(.div) ! SIGNED DIVIDE - .global .div -.div: - orcc %o1,%o0,%g0 ! are either %o0 or %o1 negative - bge divide ! if not, skip this junk - xor %o1,%o0,%g1 ! record sign of result in sign of %g1 - tst %o1 - bge 2f - tst %o0 - ! %o1 < 0 - bge divide - neg %o1 - 2: - ! %o0 < 0 - neg %o0 - ! FALL THROUGH - - -divide: -! compute size of quotient, scale comparand - orcc %o1,%g0,%o5 ! movcc %o1,%o5 - bnz 0f ! if %o1 != 0 - mov %o0,%o3 - ba zero_divide - nop -0: - cmp %o3,%o5 - blu got_result ! if %o3<%o5 already, there's no point in continuing - mov 0,%o2 - sethi %hi(1<<(32-4 -1)),%g2 - cmp %o3,%g2 - blu not_really_big - mov 0,%o4 - ! - ! here, the %o0 is >= 2^(31-4) or so. We must be careful here, as - ! our usual 4-at-a-shot divide step will cause overflow and havoc. The - ! total number of bits in the result here is 4*%o4+%g3, where %g3 <= 4. - ! compute %o4, in an unorthodox manner: know we need to Shift %o5 into - ! the top decade: so don't even bother to compare to %o3. - 1: - cmp %o5,%g2 - bgeu 3f - mov 1,%g3 - sll %o5,4,%o5 - b 1b - inc %o4 - ! now compute %g3 - 2: addcc %o5,%o5,%o5 - bcc not_too_big ! bcc not_too_big - add %g3,1,%g3 - ! - ! here if the %o1 overflowed when Shifting - ! this means that %o3 has the high-order bit set - ! restore %o5 and subtract from %o3 - sll %g2,4 ,%g2 ! high order bit - srl %o5,1,%o5 ! rest of %o5 - add %o5,%g2,%o5 - b do_single_div - sub %g3,1,%g3 - not_too_big: - 3: cmp %o5,%o3 - blu 2b - nop - be do_single_div - nop - ! %o5 > %o3: went too far: back up 1 step - ! srl %o5,1,%o5 - ! dec %g3 - ! do single-bit divide steps - ! - ! we have to be careful here. We know that %o3 >= %o5, so we can do the - ! first divide step without thinking. BUT, the others are conditional, - ! and are only done if %o3 >= 0. Because both %o3 and %o5 may have the high- - ! order bit set in the first step, just falling into the regular - ! division loop will mess up the first time around. - ! So we unroll slightly... - do_single_div: - deccc %g3 - bl end_regular_divide - nop - sub %o3,%o5,%o3 - mov 1,%o2 - b,a end_single_divloop - single_divloop: - sll %o2,1,%o2 - bl 1f - srl %o5,1,%o5 - ! %o3 >= 0 - sub %o3,%o5,%o3 - b 2f - inc %o2 - 1: ! %o3 < 0 - add %o3,%o5,%o3 - dec %o2 - 2: - end_single_divloop: - deccc %g3 - bge single_divloop - tst %o3 - b,a end_regular_divide - -not_really_big: -1: - sll %o5,4,%o5 - cmp %o5,%o3 - bleu 1b - inccc %o4 - be got_result - dec %o4 -do_regular_divide: - -! do the main division iteration - tst %o3 -! fall through into divide loop -divloop: - sll %o2,4,%o2 - !depth 1, accumulated bits 0 - bl L.1.16 - srl %o5,1,%o5 - ! remainder is positive - subcc %o3,%o5,%o3 - !depth 2, accumulated bits 1 - bl L.2.17 - srl %o5,1,%o5 - ! remainder is positive - subcc %o3,%o5,%o3 - !depth 3, accumulated bits 3 - bl L.3.19 - srl %o5,1,%o5 - ! remainder is positive - subcc %o3,%o5,%o3 - !depth 4, accumulated bits 7 - bl L.4.23 - srl %o5,1,%o5 - ! remainder is positive - subcc %o3,%o5,%o3 - b 9f - add %o2, (7*2+1), %o2 - -L.4.23: ! remainder is negative - addcc %o3,%o5,%o3 - b 9f - add %o2, (7*2-1), %o2 - - - - -L.3.19: ! remainder is negative - addcc %o3,%o5,%o3 - !depth 4, accumulated bits 5 - bl L.4.21 - srl %o5,1,%o5 - ! remainder is positive - subcc %o3,%o5,%o3 - b 9f - add %o2, (5*2+1), %o2 - -L.4.21: ! remainder is negative - addcc %o3,%o5,%o3 - b 9f - add %o2, (5*2-1), %o2 - - - - - - - -L.2.17: ! remainder is negative - addcc %o3,%o5,%o3 - !depth 3, accumulated bits 1 - bl L.3.17 - srl %o5,1,%o5 - ! remainder is positive - subcc %o3,%o5,%o3 - !depth 4, accumulated bits 3 - bl L.4.19 - srl %o5,1,%o5 - ! remainder is positive - subcc %o3,%o5,%o3 - b 9f - add %o2, (3*2+1), %o2 - -L.4.19: ! remainder is negative - addcc %o3,%o5,%o3 - b 9f - add %o2, (3*2-1), %o2 - - - - -L.3.17: ! remainder is negative - addcc %o3,%o5,%o3 - !depth 4, accumulated bits 1 - bl L.4.17 - srl %o5,1,%o5 - ! remainder is positive - subcc %o3,%o5,%o3 - b 9f - add %o2, (1*2+1), %o2 - -L.4.17: ! remainder is negative - addcc %o3,%o5,%o3 - b 9f - add %o2, (1*2-1), %o2 - - - - - - - - - - -L.1.16: ! remainder is negative - addcc %o3,%o5,%o3 - !depth 2, accumulated bits -1 - bl L.2.15 - srl %o5,1,%o5 - ! remainder is positive - subcc %o3,%o5,%o3 - !depth 3, accumulated bits -1 - bl L.3.15 - srl %o5,1,%o5 - ! remainder is positive - subcc %o3,%o5,%o3 - !depth 4, accumulated bits -1 - bl L.4.15 - srl %o5,1,%o5 - ! remainder is positive - subcc %o3,%o5,%o3 - b 9f - add %o2, (-1*2+1), %o2 - -L.4.15: ! remainder is negative - addcc %o3,%o5,%o3 - b 9f - add %o2, (-1*2-1), %o2 - - - - -L.3.15: ! remainder is negative - addcc %o3,%o5,%o3 - !depth 4, accumulated bits -3 - bl L.4.13 - srl %o5,1,%o5 - ! remainder is positive - subcc %o3,%o5,%o3 - b 9f - add %o2, (-3*2+1), %o2 - -L.4.13: ! remainder is negative - addcc %o3,%o5,%o3 - b 9f - add %o2, (-3*2-1), %o2 - - - - - - - -L.2.15: ! remainder is negative - addcc %o3,%o5,%o3 - !depth 3, accumulated bits -3 - bl L.3.13 - srl %o5,1,%o5 - ! remainder is positive - subcc %o3,%o5,%o3 - !depth 4, accumulated bits -5 - bl L.4.11 - srl %o5,1,%o5 - ! remainder is positive - subcc %o3,%o5,%o3 - b 9f - add %o2, (-5*2+1), %o2 - -L.4.11: ! remainder is negative - addcc %o3,%o5,%o3 - b 9f - add %o2, (-5*2-1), %o2 - - - - -L.3.13: ! remainder is negative - addcc %o3,%o5,%o3 - !depth 4, accumulated bits -7 - bl L.4.9 - srl %o5,1,%o5 - ! remainder is positive - subcc %o3,%o5,%o3 - b 9f - add %o2, (-7*2+1), %o2 - -L.4.9: ! remainder is negative - addcc %o3,%o5,%o3 - b 9f - add %o2, (-7*2-1), %o2 - - - - - - - - - - - 9: - -end_regular_divide: - deccc %o4 - bge divloop - tst %o3 - bl,a got_result - dec %o2 - - -got_result: - tst %g1 - bl,a 1f - neg %o2 ! quotient <- -%o2 - -1: - retl - mov %o2,%o0 ! quotient <- %o2 - - -zero_divide: - ta ST_DIV0 ! divide by zero trap - retl ! if handled, ignored, return - mov 0, %o0 diff --git a/usr/src/cmd/sgs/rtld.4.x/elf_boot.h b/usr/src/cmd/sgs/rtld.4.x/elf_boot.h deleted file mode 100644 index d9f38bad4f..0000000000 --- a/usr/src/cmd/sgs/rtld.4.x/elf_boot.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright (c) 1990 Sun Microsystems, Inc. - */ - -#ifndef _ELF_BOOT_H -#define _ELF_BOOT_H - -#ident "%Z%%M% %I% %E% SMI" - -/* - * Attribute/value structures used to bootstrap ELF-based dynamic linker. - */ - -#ifndef _ASM -typedef struct { - Elf32_Sword eb_tag; /* what this one is */ - union { /* possible values */ - Elf32_Word eb_val; - Elf32_Addr eb_ptr; - Elf32_Off eb_off; - } eb_un; -} Elf32_Boot; -#endif /* _ASM */ - -/* - * Attributes - */ -#define EB_NULL 0 /* (void) last entry */ -#define EB_DYNAMIC 1 /* (*) dynamic structure of subject */ -#define EB_LDSO_BASE 2 /* (caddr_t) base address of ld.so */ -#define EB_ARGV 3 /* (caddr_t) argument vector */ -#define EB_ENVP 4 /* (char **) environment strings */ -#define EB_AUXV 5 /* (auxv_t *) auxiliary vector */ -#define EB_DEVZERO 6 /* (int) fd for /dev/zero */ -#define EB_PAGESIZE 7 /* (int) page size */ -#define EB_MAX 8 /* number of "EBs" */ - -#endif /* _ELF_BOOT_H */ diff --git a/usr/src/cmd/sgs/rtld.4.x/ld.so b/usr/src/cmd/sgs/rtld.4.x/ld.so Binary files differdeleted file mode 100644 index 256acfb125..0000000000 --- a/usr/src/cmd/sgs/rtld.4.x/ld.so +++ /dev/null diff --git a/usr/src/cmd/sgs/rtld.4.x/rem.s b/usr/src/cmd/sgs/rtld.4.x/rem.s deleted file mode 100644 index b9d64b3173..0000000000 --- a/usr/src/cmd/sgs/rtld.4.x/rem.s +++ /dev/null @@ -1,436 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ - -! .seg "data" -! .asciz "Copyr 1986 Sun Micro" - .seg "text" - -#ident "%Z%%M% %I% %E% SMI" - -/* - * Copyright 1986 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -/* - * divison/remainder - * - * Input is: - * dividend -- the thing being divided - * divisor -- how many ways to divide - * Important parameters: - * N -- how many bits per iteration we try to get - * as our current guess: - * WORDSIZE -- how many bits altogether we're talking about: - * obviously: - * A derived constant: - * TOPBITS -- how many bits are in the top "decade" of a number: - * - * Important variables are: - * Q -- the partial quotient under development -- initally 0 - * R -- the remainder so far -- initially == the dividend - * ITER -- number of iterations of the main division loop will - * be required. Equal to CEIL( lg2(quotient)/4 ) - * Note that this is log_base_(2^4) of the quotient. - * V -- the current comparand -- initially divisor*2^(ITER*4-1) - * Cost: - * current estimate for non-large dividend is - * CEIL( lg2(quotient) / 4 ) x ( 10 + 74/2 ) + C - * a large dividend is one greater than 2^(31-4 ) and takes a - * different path, as the upper bits of the quotient must be developed - * one bit at a time. - */ - -#include <sys/trap.h> -#include <sys/asm_linkage.h> - - - - - - - - - ! working variable - - -/* - * this is the recursive definition of how we develop quotient digits. - * it takes three important parameters: - * $1 -- the current depth, 1<=$1<=4 - * $2 -- the current accumulation of quotient bits - * 4 -- max depth - * We add a new bit to $2 and either recurse or - * insert the bits in the quotient. - * Dynamic input: - * %o3 -- current remainder - * %o2 -- current quotient - * %o5 -- current comparand - * cc -- set on current value of %o3 - * Dynamic output: - * %o3', %o2', %o5', cc' - */ - - - - -! RTENTRY(.urem) ! UNSIGNED REMAINDER - .global .urem -.urem: - b divide - mov 0,%g1 ! result always positive - -! RTENTRY(.rem) ! SIGNED REMAINDER - .global .rem -.rem: - orcc %o1,%o0,%g0 ! are either %o0 or %o1 negative - bge divide ! if not, skip this junk - mov %o0,%g1 ! record sign of result in sign of %g1 - tst %o1 - bge 2f - tst %o0 - ! %o1 < 0 - bge divide - neg %o1 - 2: - ! %o0 < 0 - neg %o0 - ! FALL THROUGH - - -divide: -! compute size of quotient, scale comparand - orcc %o1,%g0,%o5 ! movcc %o1,%o5 - bnz 0f ! if %o1 != 0 - mov %o0,%o3 - ba zero_divide - nop -0: - cmp %o3,%o5 - blu got_result ! if %o3<%o5 already, there's no point in continuing - mov 0,%o2 - sethi %hi(1<<(32-4 -1)),%g2 - cmp %o3,%g2 - blu not_really_big - mov 0,%o4 - ! - ! here, the %o0 is >= 2^(31-4) or so. We must be careful here, as - ! our usual 4-at-a-shot divide step will cause overflow and havoc. The - ! total number of bits in the result here is 4*%o4+%g3, where %g3 <= 4. - ! compute %o4, in an unorthodox manner: know we need to Shift %o5 into - ! the top decade: so don't even bother to compare to %o3. - 1: - cmp %o5,%g2 - bgeu 3f - mov 1,%g3 - sll %o5,4,%o5 - b 1b - inc %o4 - ! now compute %g3 - 2: addcc %o5,%o5,%o5 - bcc not_too_big ! bcc not_too_big - add %g3,1,%g3 - ! - ! here if the %o1 overflowed when Shifting - ! this means that %o3 has the high-order bit set - ! restore %o5 and subtract from %o3 - sll %g2,4 ,%g2 ! high order bit - srl %o5,1,%o5 ! rest of %o5 - add %o5,%g2,%o5 - b do_single_div - sub %g3,1,%g3 - not_too_big: - 3: cmp %o5,%o3 - blu 2b - nop - be do_single_div - nop - ! %o5 > %o3: went too far: back up 1 step - ! srl %o5,1,%o5 - ! dec %g3 - ! do single-bit divide steps - ! - ! we have to be careful here. We know that %o3 >= %o5, so we can do the - ! first divide step without thinking. BUT, the others are conditional, - ! and are only done if %o3 >= 0. Because both %o3 and %o5 may have the high- - ! order bit set in the first step, just falling into the regular - ! division loop will mess up the first time around. - ! So we unroll slightly... - do_single_div: - deccc %g3 - bl end_regular_divide - nop - sub %o3,%o5,%o3 - mov 1,%o2 - b,a end_single_divloop - single_divloop: - sll %o2,1,%o2 - bl 1f - srl %o5,1,%o5 - ! %o3 >= 0 - sub %o3,%o5,%o3 - b 2f - inc %o2 - 1: ! %o3 < 0 - add %o3,%o5,%o3 - dec %o2 - 2: - end_single_divloop: - deccc %g3 - bge single_divloop - tst %o3 - b,a end_regular_divide - -not_really_big: -1: - sll %o5,4,%o5 - cmp %o5,%o3 - bleu 1b - inccc %o4 - be got_result - dec %o4 -do_regular_divide: - -! do the main division iteration - tst %o3 -! fall through into divide loop -divloop: - sll %o2,4,%o2 - !depth 1, accumulated bits 0 - bl L.1.16 - srl %o5,1,%o5 - ! remainder is positive - subcc %o3,%o5,%o3 - !depth 2, accumulated bits 1 - bl L.2.17 - srl %o5,1,%o5 - ! remainder is positive - subcc %o3,%o5,%o3 - !depth 3, accumulated bits 3 - bl L.3.19 - srl %o5,1,%o5 - ! remainder is positive - subcc %o3,%o5,%o3 - !depth 4, accumulated bits 7 - bl L.4.23 - srl %o5,1,%o5 - ! remainder is positive - subcc %o3,%o5,%o3 - b 9f - add %o2, (7*2+1), %o2 - -L.4.23: ! remainder is negative - addcc %o3,%o5,%o3 - b 9f - add %o2, (7*2-1), %o2 - - - - -L.3.19: ! remainder is negative - addcc %o3,%o5,%o3 - !depth 4, accumulated bits 5 - bl L.4.21 - srl %o5,1,%o5 - ! remainder is positive - subcc %o3,%o5,%o3 - b 9f - add %o2, (5*2+1), %o2 - -L.4.21: ! remainder is negative - addcc %o3,%o5,%o3 - b 9f - add %o2, (5*2-1), %o2 - - - - - - - -L.2.17: ! remainder is negative - addcc %o3,%o5,%o3 - !depth 3, accumulated bits 1 - bl L.3.17 - srl %o5,1,%o5 - ! remainder is positive - subcc %o3,%o5,%o3 - !depth 4, accumulated bits 3 - bl L.4.19 - srl %o5,1,%o5 - ! remainder is positive - subcc %o3,%o5,%o3 - b 9f - add %o2, (3*2+1), %o2 - -L.4.19: ! remainder is negative - addcc %o3,%o5,%o3 - b 9f - add %o2, (3*2-1), %o2 - - - - -L.3.17: ! remainder is negative - addcc %o3,%o5,%o3 - !depth 4, accumulated bits 1 - bl L.4.17 - srl %o5,1,%o5 - ! remainder is positive - subcc %o3,%o5,%o3 - b 9f - add %o2, (1*2+1), %o2 - -L.4.17: ! remainder is negative - addcc %o3,%o5,%o3 - b 9f - add %o2, (1*2-1), %o2 - - - - - - - - - - -L.1.16: ! remainder is negative - addcc %o3,%o5,%o3 - !depth 2, accumulated bits -1 - bl L.2.15 - srl %o5,1,%o5 - ! remainder is positive - subcc %o3,%o5,%o3 - !depth 3, accumulated bits -1 - bl L.3.15 - srl %o5,1,%o5 - ! remainder is positive - subcc %o3,%o5,%o3 - !depth 4, accumulated bits -1 - bl L.4.15 - srl %o5,1,%o5 - ! remainder is positive - subcc %o3,%o5,%o3 - b 9f - add %o2, (-1*2+1), %o2 - -L.4.15: ! remainder is negative - addcc %o3,%o5,%o3 - b 9f - add %o2, (-1*2-1), %o2 - - - - -L.3.15: ! remainder is negative - addcc %o3,%o5,%o3 - !depth 4, accumulated bits -3 - bl L.4.13 - srl %o5,1,%o5 - ! remainder is positive - subcc %o3,%o5,%o3 - b 9f - add %o2, (-3*2+1), %o2 - -L.4.13: ! remainder is negative - addcc %o3,%o5,%o3 - b 9f - add %o2, (-3*2-1), %o2 - - - - - - - -L.2.15: ! remainder is negative - addcc %o3,%o5,%o3 - !depth 3, accumulated bits -3 - bl L.3.13 - srl %o5,1,%o5 - ! remainder is positive - subcc %o3,%o5,%o3 - !depth 4, accumulated bits -5 - bl L.4.11 - srl %o5,1,%o5 - ! remainder is positive - subcc %o3,%o5,%o3 - b 9f - add %o2, (-5*2+1), %o2 - -L.4.11: ! remainder is negative - addcc %o3,%o5,%o3 - b 9f - add %o2, (-5*2-1), %o2 - - - - -L.3.13: ! remainder is negative - addcc %o3,%o5,%o3 - !depth 4, accumulated bits -7 - bl L.4.9 - srl %o5,1,%o5 - ! remainder is positive - subcc %o3,%o5,%o3 - b 9f - add %o2, (-7*2+1), %o2 - -L.4.9: ! remainder is negative - addcc %o3,%o5,%o3 - b 9f - add %o2, (-7*2-1), %o2 - - - - - - - - - - - 9: - -end_regular_divide: - deccc %o4 - bge divloop - tst %o3 - bl,a got_result - add %o3,%o1,%o3 - - -got_result: - tst %g1 - bl,a 1f - neg %o3 ! remainder <- -%o3 - -1: - retl - mov %o3,%o0 ! remainder <- %o3 - - -zero_divide: - ta ST_DIV0 ! divide by zero trap - retl ! if handled, ignored, return - mov 0, %o0 diff --git a/usr/src/cmd/sgs/rtld.4.x/rtld.4.x.c b/usr/src/cmd/sgs/rtld.4.x/rtld.4.x.c deleted file mode 100644 index 627331942e..0000000000 --- a/usr/src/cmd/sgs/rtld.4.x/rtld.4.x.c +++ /dev/null @@ -1,567 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2003 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - * - * Binary compatibility ld.so. Intercepts the reference of a pre-SVR4 - * SunOS executable to the dynamic linker, and then redirects to the - * "real" post-SVR4 SunOS ld.so. - */ -#pragma ident "%Z%%M% %I% %E% SMI" - -/* - * Import data structures (N.B.: from 5.x). - */ -#include <sys/types.h> -#include <sys/mman.h> -#include <sys/fcntl.h> -#include <sys/stat.h> -#include <sys/sysconfig.h> -#include <sys/auxv.h> -#include <sys/archsystm.h> -#include <elf.h> -#include <link.h> - -/* - * Relocation manifest constants and macros. - */ -#define ALIGN(x, a) ((int)(x) & ~((int)(a) - 1)) -#define ROUND(x, a) (((int)(x) + ((int)(a) - 1)) & \ - ~((int)(a) - 1)) -#define DYNAMIC_VERSION2 2 -#define RELOC_SIZE (sizeof (struct relocation_info)) -#define RELOCOFF(x) (x)->v2->ld_rel -#define MASK(n) ((1<<(n))-1) -#define IN_RANGE(v, n) ((-(1<<((n)-1))) <= (v) && (v) < (1<<((n)-1))) - -void aout_reloc_write(); - -/* - * 4.x SunOS Dynamic Link Editor public definitions (much derived from - * SunOS 4.x <link.h>.) - */ - -/* - * Dynamic linking information. With the exception of - * ld_loaded (determined at execution time) and ld_stab_hash (a special - * case of relocation handled at execution time), the values in this - * structure reflect offsets from the containing link_dynamic structure. - */ -struct link_dynamic_1 { - struct link_map *ld_loaded; /* list of loaded objects */ - long ld_need; /* list of needed objects */ - long ld_rules; /* search rules for library objects */ - long ld_got; /* global offset table */ - long ld_plt; /* procedure linkage table */ - long ld_rel; /* relocation table */ - long ld_hash; /* symbol hash table */ - long ld_stab; /* symbol table itself */ - long (*ld_stab_hash)(); /* "pointer" to symbol hash function */ - long ld_buckets; /* number of hash buckets */ - long ld_symbols; /* symbol strings */ - long ld_symb_size; /* size of symbol strings */ - long ld_text; /* size of text area */ -}; - -struct link_dynamic_2 { - struct link_map *ld_loaded; /* list of loaded objects */ - long ld_need; /* list of needed objects */ - long ld_rules; /* search rules for library objects */ - long ld_got; /* global offset table */ - long ld_plt; /* procedure linkage table */ - long ld_rel; /* relocation table */ - long ld_hash; /* symbol hash table */ - long ld_stab; /* symbol table itself */ - long (*ld_stab_hash)(); /* "pointer" to symbol hash function */ - long ld_buckets; /* number of hash buckets */ - long ld_symbols; /* symbol strings */ - long ld_symb_size; /* size of symbol strings */ - long ld_text; /* size of text area */ - long ld_plt_sz; /* size of procedure linkage table */ -}; - -/* - * Debugger interface structure. - */ -struct ld_debug { - int ldd_version; /* version # of interface */ - int ldd_in_debugger; /* a debugger is running us */ - int ldd_sym_loaded; /* we loaded some symbols */ - char *ldd_bp_addr; /* place for ld-generated bpt */ - int ldd_bp_inst; /* instruction which was there */ - struct rtc_symb *ldd_cp; /* commons we built */ -}; - -/* - * Structure associated with each object which may be or which requires - * execution-time link editing. Used by the run-time linkage editor to - * identify needed objects and symbol definitions and references. - */ -struct link_dynamic { - int ld_version; - struct ld_debug *ldd; - union { - struct link_dynamic_1 *ld_1; - struct link_dynamic_2 *ld_2; - } ld_un; -}; - -struct old_link_dynamic { - int ld_version; /* version # of this structure */ - union { - struct link_dynamic_1 ld_1; - } ld_un; - - int in_debugging; - int sym_loaded; - char *bp_addr; - int bp_inst; - struct rtc_symb *cp; /* pointer to an array of runtime */ - /* allocated common symbols. */ -}; - -#define v2 ld_un.ld_2 /* short hands */ -#define v1 ld_un.ld_1 - -/* - * SunOS 4.x SPARC relocation types and relocation record. Note that - * these, among other things, make this program not portable to things - * other than SPARC. - */ -enum reloc_type { - RELOC_8, RELOC_16, RELOC_32, /* simplest relocs */ - RELOC_DISP8, RELOC_DISP16, RELOC_DISP32, - /* Disp's (pc-rel) */ - RELOC_WDISP30, RELOC_WDISP22, /* SR word disp's */ - RELOC_HI22, RELOC_22, /* SR 22-bit relocs */ - RELOC_13, RELOC_LO10, /* SR 13&10-bit relocs */ - RELOC_SFA_BASE, RELOC_SFA_OFF13, /* SR S.F.A. relocs */ - RELOC_BASE10, RELOC_BASE13, RELOC_BASE22, - /* PIC GOT references */ - RELOC_PC10, RELOC_PC22, /* PIC reference to GOT */ - RELOC_JMP_TBL, /* PIC call */ - RELOC_SEGOFF16, /* .so offset-in-segment */ - RELOC_GLOB_DAT, RELOC_JMP_SLOT, RELOC_RELATIVE, - /* ld.so relocation types */ -}; - -struct relocation_info { - unsigned long int r_address; /* relocation addr */ - unsigned int r_index :24; /* segment index or symbol index */ - unsigned int r_extern : 1; /* if F, r_index==SEG#; if T, SYM idx */ - int : 2; /* <unused> */ - enum reloc_type r_type : 5; /* type of relocation to perform */ - long int r_addend; /* addend for relocation value */ -}; - -/* - * Size of relocations. - */ -#define GETRELSZ(x) \ - (x->ld_version < 2 ? \ - ((struct old_link_dynamic *)x)->v1.ld_hash - \ - ((struct old_link_dynamic *)x)->v1.ld_rel : \ - (x)->v2->ld_hash - (x)->v2->ld_rel) - -/* - * Interface between crt0 & ld.so. - */ -struct crt_i1 { - int crt_baseaddr; /* Address ld.so is at */ - int crt_dzfd; /* /dev/zero file descriptor */ - int crt_rlfd; /* ld.so file descriptor */ - struct link_dynamic *crt_udp; /* "main_" dynamic */ - char **crt_ep; /* environment strings */ - caddr_t crt_breakp; /* place to put initial breakpoint */ -}; - -/* - * Structure we provide to ELF ld.so upon entry. - */ -Elf32_Boot eb[EB_MAX]; - -/* - * Global data. - */ -char *program_name; /* used in messages */ - -/* - * 4.0 ld.so main entry point. - */ -rtld(version, ip, dp, argp) - int version; /* interface version */ - struct crt_i1 *ip; /* interface passed from program */ - register struct link_dynamic *dp; /* ld.so dynamic pointer */ - caddr_t argp; /* pointer to begining of args */ -{ - char *ldso; /* name of what we really want to be */ - int i, p; /* working */ - int r; /* working (# of *our* relocations */ - int page_size = 0; /* size of a page */ - struct relocation_info *rp; /* working pointer to our relocs */ - int fd; /* fd assigned to ld.so */ - Elf32_Ehdr *ehdr; /* ELF header of ld.so */ - Elf32_Phdr *phdr; /* first Phdr in file */ - Elf32_Phdr *pptr; /* working Phdr */ - Elf32_Phdr *lph; /* last loadable Phdr */ - Elf32_Phdr *fph = 0; /* first loadable Phdr */ - caddr_t maddr; /* pointer to mapping claim */ - Elf32_Off mlen; /* total mapping claim */ - caddr_t faddr; /* first program mapping of ld.so */ - Elf32_Off foff; /* file offset for segment mapping */ - Elf32_Off flen; /* file length for segment mapping */ - caddr_t addr; /* working mapping address */ - caddr_t zaddr; /* /dev/zero working mapping addr */ - Elf32_Boot *ebp; /* communication with ld.so */ - struct stat sb; /* stat buffer for sizing */ - auxv_t *ap; /* working aux pointer */ - void (* wrt)(); /* address of write/iflush routine */ - - /* - * ld.so must itself be relocated, take care of this now. - * We can not refer to global data before this step is - * complete. Perform the relocation by stepping over all - * entries in the relocation table and turn them into - * absolute addresses. Note that, in order to avoid invoking - * as yet unrelocated items, we perform the relocation count - * by counting rather than risk invoking subroutine calls - * to intrinsic .div or .mul routines. Note also that we - * assume that there are no symbolic relocations to be - * performed here. - */ - dp->v2 = (struct link_dynamic_2 *) - ((caddr_t)dp->v2 + ip->crt_baseaddr); - r = 0; - i = GETRELSZ(dp); - while (i != 0) { - i -= RELOC_SIZE; - r++; - } - rp = (struct relocation_info *)(RELOCOFF(dp) + - (dp->ld_version < DYNAMIC_VERSION2 ? - (int)dp : ip->crt_baseaddr)); - - /* - * Determine the location of the routine that will write the relocation. - * This hasn't yet been relocated so determine the real address using - * our base address. - */ - wrt = (void (*)())((caddr_t)aout_reloc_write + ip->crt_baseaddr); - - /* - * Relocate ourselves - we only need RELOC_RELATIVE and RELOC_32. - * Note, if panic() was called its probable that it will barf as the - * corresponding plt wouldn't have been relocated yet. - */ - for (i = 0; i < r; i++) { - long *where = (long *)((caddr_t)rp->r_address + ip->crt_baseaddr); - long what = ip->crt_baseaddr; - long value; - - switch (rp->r_type) { - case RELOC_RELATIVE: - what += *where << (32-22); - value = (*where & ~MASK(22)) | ((what >> (32-22)) & MASK(22)); - wrt(where, value); - where++; - what += (*where & MASK(10)); - value = (*where & ~MASK(10)) | (what & MASK(10)); - wrt(where, value); - break; - - case RELOC_32: - what += *where; - wrt(where, what); - break; - - default: - panic("unknown relocation type %d\n", rp->r_type); - break; - } - rp++; - } - - /* - * We're relocated, we can now initialize things referencing - * static storage. - */ - ldso = "/usr/lib/ld.so.1"; - - /* - * Close off the file descriptor used to get us here -- let it - * be available for the next (probable) use below. - */ - (void) close(ip->crt_rlfd); - - /* - * Discover things about our environment: auxiliary vector (if - * any), arguments, program name, and the like. - */ - ebp = eb; - program_name = (char *)(argp + sizeof (int)); - if (version != 1) - panic("bad startup interface version of %d", - version); - ebp->eb_tag = EB_DYNAMIC, - (ebp++)->eb_un.eb_ptr = (Elf32_Addr)ip->crt_udp; - ebp->eb_tag = EB_ARGV, (ebp++)->eb_un.eb_ptr = (Elf32_Addr)program_name; - ebp->eb_tag = EB_ENVP, (ebp++)->eb_un.eb_ptr = (Elf32_Addr)ip->crt_ep; - ebp->eb_tag = EB_DEVZERO, - (ebp++)->eb_un.eb_val = (Elf32_Word)ip->crt_dzfd; - for (addr = (caddr_t)ip->crt_ep; *addr; addr += sizeof (char *)) - ; - addr += sizeof (char *); - - /* - * The kernel sends us an abbreviated aux vector with some - * potentially handy stuff that saves us on syscalls. - * - * Notes on 1226113 - * - * The f77 compiler shipped as part of SC1.0 on 4.x creates binaries - * that use the _fix_libc_ feature of acc. This makes the resulting - * executable object dependent on the undocumented behaviour of - * libc's .rem and .div routines e.g. that .div returns the - * remainder in %o3 (and similarly .rem returns the division in %o3). - * - * The only simple solution is to disable hardware divide for - * all 4.x applications so that the old software routines that have - * this "support" in them are used instead. And we do that by - * clearing the divide-in-hardware flag from the aux vector before - * libc's .init routine gets to see it. Awful isn't it. - */ - ebp->eb_tag = EB_AUXV, (ebp++)->eb_un.eb_ptr = (Elf32_Addr)addr; - for (ap = (auxv_t *)addr; ap->a_type != AT_NULL; ap++) - if (ap->a_type == AT_PAGESZ) { - page_size = ap->a_un.a_val; - ebp->eb_tag = EB_PAGESIZE, (ebp++)->eb_un.eb_val = - (Elf32_Word)page_size; - } else if (ap->a_type == AT_SUN_HWCAP) - ap->a_un.a_val &= ~AV_SPARC_HWDIV_32x32; - - /* - * If we didn't get a page size from looking in the auxiliary - * vector, we need to get one now. - */ - if (page_size == 0) { - page_size = sysconfig(_CONFIG_PAGESIZE); - ebp->eb_tag = EB_PAGESIZE, (ebp++)->eb_un.eb_val = - (Elf32_Word)page_size; - } - - /* - * Map in the ELF-based ld.so. Note that we're mapping it as - * an ELF database, not as a program -- we just want to walk it's - * data structures. Further mappings will actually establish the - * program in the address space. - */ - if ((fd = open(ldso, O_RDONLY)) == -1) - panic("unable to open %s", ldso); - if (fstat(fd, &sb) == -1) - panic("unable to find size of %s", ldso); - ehdr = (Elf32_Ehdr *)mmap(0, sb.st_size, PROT_READ | PROT_EXEC, - MAP_SHARED, fd, 0); - if (ehdr == (Elf32_Ehdr *)-1) - panic("unable to map %s", ldso); - - /* - * Validate the file we're looking at, ensure it has the correct - * ELF structures, such as: ELF magic numbers, coded for SPARC, - * is a ".so", etc. - */ - if (ehdr->e_ident[EI_MAG0] != ELFMAG0 || - ehdr->e_ident[EI_MAG1] != ELFMAG1 || - ehdr->e_ident[EI_MAG2] != ELFMAG2 || - ehdr->e_ident[EI_MAG3] != ELFMAG3) - panic("%s is not an ELF file", ldso); - if (ehdr->e_ident[EI_CLASS] != ELFCLASS32 || - ehdr->e_ident[EI_DATA] != ELFDATA2MSB) - panic("%s has wrong class or data encoding", ldso); - if (ehdr->e_type != ET_DYN) - panic("%s is not a shared object", ldso); - if ((ehdr->e_machine != EM_SPARC) && - (ehdr->e_machine != EM_SPARC32PLUS)) - panic("%s is not a valid SPARC object: e_machine: %x", - ldso, ehdr->e_machine); - if (ehdr->e_version > EV_CURRENT) - panic("%s has bad ELF version of %d", ldso, ehdr->e_version); - - /* - * Point at program headers and start figuring out what to load. - */ - phdr = (Elf32_Phdr *)((caddr_t)ehdr + ehdr->e_phoff); - for (p = 0, pptr = phdr; p < (int)ehdr->e_phnum; p++, - pptr = (Elf32_Phdr *)((caddr_t)pptr + ehdr->e_phentsize)) - if (pptr->p_type == PT_LOAD) { - if (fph == 0) { - fph = pptr; - } else if (pptr->p_vaddr <= lph->p_vaddr) - panic( - "%s invalid program header - segments out of order", ldso); - lph = pptr; - } - - /* - * We'd better have at least one loadable segment. - */ - if (fph == 0) - panic("%s has no loadable segments", ldso); - - /* - * Map enough address space to hold the program (as opposed to the - * file) represented by ld.so. The amount to be assigned is the - * range between the end of the last loadable segment and the - * beginning of the first PLUS the alignment of the first segment. - * mmap() can assign us any page-aligned address, but the relocations - * assume the alignments included in the program header. As an - * optimization, however, let's assume that mmap() will actually - * give us an aligned address -- since if it does, we can save - * an munmap() later on. If it doesn't -- then go try it again. - */ - mlen = ROUND((lph->p_vaddr + lph->p_memsz) - - ALIGN(fph->p_vaddr, page_size), page_size); - maddr = (caddr_t)mmap(0, mlen, PROT_READ | PROT_EXEC, - MAP_SHARED, fd, 0); - if (maddr == (caddr_t)-1) - panic("unable to reserve space for %s", ldso); - faddr = (caddr_t)ROUND(maddr, fph->p_align); - - /* - * Check to see whether alignment skew was really needed. - */ - if (faddr != maddr) { - (void) munmap(maddr, mlen); - mlen = ROUND((lph->p_vaddr + lph->p_memsz) - - ALIGN(fph->p_vaddr, fph->p_align) + fph->p_align, - page_size); - maddr = (caddr_t)mmap(0, mlen, PROT_READ | PROT_EXEC, - MAP_SHARED, fd, 0); - if (maddr == (caddr_t)-1) - panic("unable to reserve space for %s", ldso); - faddr = (caddr_t)ROUND(maddr, fph->p_align); - } - ebp->eb_tag = EB_LDSO_BASE, (ebp++)->eb_un.eb_ptr = (Elf32_Addr)faddr; - - /* - * We have the address space reserved, so map each loadable segment. - */ - for (pptr = phdr; (pptr - phdr) < (int)ehdr->e_phnum; pptr++) { - - /* - * Skip non-loadable segments or segments that don't occupy - * any memory. - */ - if ((pptr->p_type != PT_LOAD) || (pptr->p_memsz == 0)) - continue; - - /* - * Determine the file offset to which the mapping will - * directed (must be aligned) and how much to map (might - * be more than the file in the case of .bss.) - */ - foff = ALIGN(pptr->p_offset, page_size); - flen = pptr->p_memsz + (pptr->p_offset - foff); - - /* - * Set address of this segment relative to our base. - */ - addr = (caddr_t)ALIGN(faddr + pptr->p_vaddr, page_size); - - /* - * Unmap anything form the last mapping address to this - * one. - */ - if (addr - maddr) { - (void) munmap(maddr, addr - maddr); - mlen -= addr - maddr; - } - - /* - * Determine the mapping protection from the section - * attributes. - */ - i = 0; - if (pptr->p_flags & PF_R) - i |= PROT_READ; - if (pptr->p_flags & PF_W) - i |= PROT_WRITE; - if (pptr->p_flags & PF_X) - i |= PROT_EXEC; - if ((caddr_t)mmap((caddr_t)addr, flen, i, - MAP_FIXED | MAP_PRIVATE, fd, foff) == (caddr_t)-1) - panic("unable to map a segment from %s", ldso); - - /* - * If the memory occupancy of the segment overflows the - * definition in the file, we need to "zero out" the - * end of the mapping we've established, and if necessary, - * map some more space from /dev/zero. - */ - if (pptr->p_memsz > pptr->p_filesz) { - foff = (int)faddr + pptr->p_vaddr + pptr->p_filesz; - zaddr = (caddr_t)ROUND(foff, page_size); - _zero(foff, zaddr - foff); - r = (faddr + pptr->p_vaddr + pptr->p_memsz) - zaddr; - if (r > 0) - if ((caddr_t)mmap((caddr_t)zaddr, r, i, - MAP_FIXED | MAP_PRIVATE, ip->crt_dzfd, - 0) == (caddr_t)-1) - panic( - "unable to map .bss /dev/zero for %s", - ldso); - } - - /* - * Update the mapping claim pointer. - */ - maddr = addr + ROUND(flen, page_size); - mlen -= maddr - addr; - } - - /* - * Unmap any final reservation. - */ - if (mlen > 0) - (void) munmap(maddr, mlen); - - /* - * Clean up file descriptor space we've consumed. Pass along - * the /dev/zero file descriptor we got -- every cycle counts. - */ - (void) close(fd); - - /* - * The call itself. Note that we start 1 instruction word in. - * The ELF ld.so contains an "entry vector" of branch instructions, - * which, for our interest are: - * +0: ba, a <normal startup> - * +4: ba, a <compatibility startup> - * By starting at the compatibility startup, the ELF ld.so knows - * that a pointer to "eb" is available to it and further knows - * how to calculate the offset to the program's arguments and - * other structures. - */ - ebp->eb_tag = EB_NULL, ebp->eb_un.eb_val = 0; - (*((void (*)())(ehdr->e_entry + faddr + sizeof (long))))(eb); - return (0); -} diff --git a/usr/src/cmd/sgs/rtld.4.x/rtldlib.s b/usr/src/cmd/sgs/rtld.4.x/rtldlib.s deleted file mode 100644 index dcaf82ac45..0000000000 --- a/usr/src/cmd/sgs/rtld.4.x/rtldlib.s +++ /dev/null @@ -1,145 +0,0 @@ -! CDDL HEADER START -! -! The contents of this file are subject to the terms of the -! Common Development and Distribution License (the "License"). -! You may not use this file except in compliance with the License. -! -! You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -! or http://www.opensolaris.org/os/licensing. -! See the License for the specific language governing permissions -! and limitations under the License. -! -! When distributing Covered Code, include this CDDL HEADER in each -! file and include the License file at usr/src/OPENSOLARIS.LICENSE. -! If applicable, add the following below this CDDL HEADER, with the -! fields enclosed by brackets "[]" replaced with your own identifying -! information: Portions Copyright [yyyy] [name of copyright owner] -! -! CDDL HEADER END -! -! Copyright 2010 Sun Microsystems, Inc. All rights reserved. -! Use is subject to license terms. -! -! SPARC support routines for 4.x compatibility dynamic linker. - -#include <sys/asm_linkage.h> ! N.B.: although this is the 4.x -#include <sys/syscall.h> ! compatibility stuff, it actually - ! runs only on the SVR4 base, and - ! is compiled in an SVR4 .h environment - -#define AT_FDCWD 0xffd19553 - -! ld.so bootstrap. Called from crt0 of a dynamically linked program with: -! %i0: version number (always 1) -! %i1: address of crt0 structure, which contains: -! +0 base address of where we are mapped -! +4 open file descriptor for /dev/zero -! +8 open file descriptor for ld.so -! +c a.out _DYNAMIC address -! +10 environment strings -! +14 break address for adb/dbx - -start_rtld: - save %sp,-SA(MINFRAME),%sp ! build frame -L1: - call 1f ! get absolute address of _GOT_ - nop -1: - sethi %hi(__GLOBAL_OFFSET_TABLE_ - (L1 - 1b)), %l7 -L2: - or %l7, %lo(__GLOBAL_OFFSET_TABLE_ - (L1 - L2)), %l7 - add %l7, %o7, %l7 - mov %i0, %o0 ! pass version through - add %fp, %i1, %l0 ! get interface pointer - mov %l0, %o1 ! ptr to interface structure - ld [%l0], %l2 ! address where ld.so is mapped in - ld [%l7], %l1 ! ptr to ld.so first entry in globtable - add %l2, %l1, %o2 ! relocate ld.so _DYNAMIC - add %fp, 0xd8, %o3 ! point to arg count (is it safe?) - ld [%l7 + _rtld], %g1 ! manually fix pic reference to rtld - add %g1, %l2, %g1 ! by adding offset to GOT entry - jmpl %g1, %o7 ! go there - nop ! delay - mov 0,%o0 - mov %o0,%i0 - ret - restore - - -! -! aout_reloc_write -! Update a relocation offset, the value replaces any original -! value in the relocation offset. -! - - .global _aout_reloc_write - -_aout_reloc_write: - st %o1, [%o0] ! Store value in the offset - retl - iflush %o0 ! Flush instruction memory - - -! Special system call stubs to save system call overhead - - .global _open, _mmap, _munmap, _read, _write, _lseek, _close - .global _fstat, _sysconfig, __exit -_open: ! open(path, oflags, mode) => - mov %o2, %o3 ! openat(AT_FDCWD, path, oflag, mode) - mov %o1, %o2 - mov %o0, %o1 - sethi %hi(AT_FDCWD), %o0 - or %o0, %lo(AT_FDCWD), %o0 - ba __syscall - mov SYS_openat, %g1 - -_mmap: - sethi %hi(0x80000000), %g1 ! MAP_NEW - or %g1, %o3, %o3 - ba __syscall - mov SYS_mmap, %g1 - -_munmap: - ba __syscall - mov SYS_munmap, %g1 - -_read: - ba __syscall - mov SYS_read, %g1 - -_write: - ba __syscall - mov SYS_write, %g1 - -_lseek: - ba __syscall - mov SYS_lseek, %g1 - -_close: - ba __syscall - mov SYS_close, %g1 - -_fstat: ! fstat(fd, statb) => - mov %g0, %o3 ! fstatat(fd, NULL, statb, 0) - mov %o1, %o2 - mov %g0, %o1 - ba __syscall - mov SYS_fstatat, %g1 - -_sysconfig: - ba __syscall - mov SYS_sysconfig, %g1 - -__exit: - mov SYS_exit, %g1 - -__syscall: - t 0x8 ! call the system call - bcs __err_exit ! test for error - nop - retl ! return - nop - -__err_exit: - retl ! return - mov -1, %o0 diff --git a/usr/src/cmd/sgs/rtld.4.x/rtsubrs.c b/usr/src/cmd/sgs/rtld.4.x/rtsubrs.c deleted file mode 100644 index f08a707a94..0000000000 --- a/usr/src/cmd/sgs/rtld.4.x/rtsubrs.c +++ /dev/null @@ -1,251 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -#pragma ident "%Z%%M% %I% %E% SMI" - -/* - * Copyright (c) 1987, 1988, 1989, 1990 by Sun Microsystems, Inc. - */ - -/* Copyright (c) 1988 AT&T */ -/* All Rights Reserved */ - -/* - * Subroutines for the 4.0 compatibility run-time link editor. - */ -#include <varargs.h> -#include <sys/types.h> - -/* - * Local "printf" & stdio facilities. - */ -int stdout = 1; /* File descriptor for output */ -int stderr = 2; /* File descriptor for errors */ - -static char *printn(); -static void prf(); -static void doprf(); -static int _write(); - -/* - * printf - */ -/*VARARGS1*/ -printf(fmt, va_alist) - char *fmt; - va_dcl -{ - va_list x1; - - va_start(x1); - prf(stdout, fmt, x1); - va_end(x1); -} - -/* - * fprintf - */ -/*VARARGS2*/ -fprintf(fd, fmt, va_alist) - int fd; - char *fmt; - va_dcl -{ - va_list x1; - - va_start(x1); - prf(fd, fmt, x1); - va_end(x1); -} - -/* - * panic - */ -/*VARARGS2*/ -panic(fmt, va_alist) - char *fmt; - va_dcl -{ - va_list x1; - extern char *program_name; - - va_start(x1); - prf(stderr, "%s (4.x.ld.so): ", program_name); - prf(stderr, fmt, x1); - prf(stderr, "\n", x1); - va_end(x1); - _exit(127); - /* NOTREACHED */ -} - -/* - * sprintf - */ -/*VARARGS2*/ -sprintf(cp, fmt, va_alist) - char *cp; - char *fmt; - va_dcl -{ - va_list x1; - - va_start(x1); - doprf(-1, fmt, x1, cp); - va_end(x1); -} - -/* - * printf worker functions - */ -static void -prf(fd, fmt, adx) - int fd; - char *fmt; - va_list adx; -{ - char linebuf[128]; - - doprf(fd, fmt, adx, linebuf); -} - -static void -doprf(fd, fmt, adx, linebuf) - int fd; - register char *fmt; - register va_list adx; - char *linebuf; -{ - register int c; /* Character temporary */ - register char *lbp; /* Pointer into stack buffer */ - register char *s; /* %s temporary */ - int i; /* General integer temporary */ - int b; /* Conversion base */ - -#define PUTCHAR(c) { \ - if (lbp >= &linebuf[128]) { \ - _write(fd, linebuf, lbp - &linebuf[0]); \ - lbp = &linebuf[0]; \ - } \ - *lbp++ = (c); \ - } - - lbp = &linebuf[0]; -loop: - while ((c = *fmt++) != '%') { - if (c == '\0') { - _write(fd, linebuf, lbp - &linebuf[0]); - return; - } - PUTCHAR(c); - } -again: - c = *fmt++; - /* THIS CODE IS VAX DEPENDENT IN HANDLING %l? AND %c */ - switch (c) { - - case 'x': case 'X': - b = 16; - goto number; - case 'd': case 'D': - case 'u': /* what a joke */ - b = 10; - goto number; - case 'o': case 'O': - b = 8; -number: - lbp = printn(fd, va_arg(adx, u_long), b, &linebuf[0], lbp, - &linebuf[128]); - break; - - case 'c': - b = va_arg(adx, int); - for (i = 24; i >= 0; i -= 8) - if (c = (b >> i) & 0x7f) { - PUTCHAR(c); - } - break; - - case 's': - s = va_arg(adx, char *); - while (c = *s++) { - PUTCHAR(c); - } - break; - - case '%': - PUTCHAR('%'); - break; - } - goto loop; -} - -/* - * Printn prints a number n in base b. - */ -static char * -printn(fd, n, b, linebufp, lbp, linebufend) - int fd; /* File descriptor to get output */ - u_long n; /* Number */ - int b; /* Base */ - char *linebufp; /* Buffer location */ - register char *lbp; /* Current offset in buffer */ - char *linebufend; /* Where buffer ends */ -{ - char prbuf[11]; /* Local result accumulator */ - register char *cp; - -#undef PUTCHAR -#define PUTCHAR(c) { \ - if (lbp >= linebufend) { \ - _write(fd, linebufp, lbp - linebufp); \ - lbp = linebufp; \ - } \ - *lbp++ = (c); \ - } - - if (b == 10 && (int)n < 0) { - PUTCHAR('-'); - n = (unsigned)(-(int)n); - } - cp = prbuf; - do { - *cp++ = "0123456789abcdef"[n%b]; - n /= b; - } while (n); - do { - PUTCHAR(*--cp); - } while (cp > prbuf); - return (lbp); -} - -static int -_write(fd, buf, len) - int fd; - char *buf; - int len; -{ - - if (fd == -1) { - *(buf + len) = '\0'; - return (0); - } - return (write(fd, buf, len)); -} diff --git a/usr/src/cmd/sgs/rtld.4.x/umultiply.s b/usr/src/cmd/sgs/rtld.4.x/umultiply.s deleted file mode 100644 index 2547339a7e..0000000000 --- a/usr/src/cmd/sgs/rtld.4.x/umultiply.s +++ /dev/null @@ -1,348 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * .seg "data" - * .asciz "Copyr 1987 Sun Micro" - * .align 4 - */ - .seg "text" - -#ident "%Z%%M% %I% %E% SMI" - -! Copyright (c) 1987 by Sun Microsystems, Inc. - - -#include <sys/asm_linkage.h> - -/* - * procedure to perform a 32 by 32 unsigned integer multiply. - * pass the multiplier into %o0, and the multiplicand into %o1 - * the least significant 32 bits of the result will be returned in %o0, - * and the most significant in %o1 - * - * Most unsigned integer multiplies involve small numbers, so it is - * worthwhile to optimize for short multiplies at the expense of long - * multiplies. This code checks the size of the multiplier, and has - * special cases for the following: - * - * 4 or fewer bit multipliers: 19 or 21 instruction cycles - * 8 or fewer bit multipliers: 26 or 28 instruction cycles - * 12 or fewer bit multipliers: 34 or 36 instruction cycles - * 16 or fewer bit multipliers: 42 or 44 instruction cycles - * - * Long multipliers require 58 or 60 instruction cycles: - * - * This code indicates that overflow has occured, by leaving the Z condition - * code clear. The following call sequence would be used if you wish to - * deal with overflow: - * - * call .umul - * nop ( or set up last parameter here ) - * bnz overflow_code (or tnz to overflow handler) - */ - -! RTENTRY(.umul) - .global .umul -.umul: - wr %o0, %y ! multiplier to Y register - - andncc %o0, 0xf, %o4 ! mask out lower 4 bits; if branch - ! taken, %o4, N and V have been cleared - - be umul_4bit ! 4-bit multiplier - sethi %hi(0xffff0000), %o5 ! mask for 16-bit case; have to - ! wait 3 instructions after wd - ! before %y has stabilized anyway - - andncc %o0, 0xff, %o4 - be,a umul_8bit ! 8-bit multiplier - mulscc %o4, %o1, %o4 ! first iteration of 9 - - andncc %o0, 0xfff, %o4 - be,a umul_12bit ! 12-bit multiplier - mulscc %o4, %o1, %o4 ! first iteration of 13 - - andcc %o0, %o5, %o4 - be,a umul_16bit ! 16-bit multiplier - mulscc %o4, %o1, %o4 ! first iteration of 17 - - andcc %g0, %g0, %o4 ! zero the partial product - ! and clear N and V conditions - ! - ! long multiply - ! - mulscc %o4, %o1, %o4 ! first iteration of 33 - mulscc %o4, %o1, %o4 - mulscc %o4, %o1, %o4 - mulscc %o4, %o1, %o4 - mulscc %o4, %o1, %o4 - mulscc %o4, %o1, %o4 - mulscc %o4, %o1, %o4 - mulscc %o4, %o1, %o4 - mulscc %o4, %o1, %o4 - mulscc %o4, %o1, %o4 - mulscc %o4, %o1, %o4 - mulscc %o4, %o1, %o4 - mulscc %o4, %o1, %o4 - mulscc %o4, %o1, %o4 - mulscc %o4, %o1, %o4 - mulscc %o4, %o1, %o4 - mulscc %o4, %o1, %o4 - mulscc %o4, %o1, %o4 - mulscc %o4, %o1, %o4 - mulscc %o4, %o1, %o4 - mulscc %o4, %o1, %o4 - mulscc %o4, %o1, %o4 - mulscc %o4, %o1, %o4 - mulscc %o4, %o1, %o4 - mulscc %o4, %o1, %o4 - mulscc %o4, %o1, %o4 - mulscc %o4, %o1, %o4 - mulscc %o4, %o1, %o4 - mulscc %o4, %o1, %o4 - mulscc %o4, %o1, %o4 - mulscc %o4, %o1, %o4 - mulscc %o4, %o1, %o4 ! 32nd iteration - mulscc %o4, %g0, %o4 ! last iteration only shifts - ! - ! For unsigned multiplies, a pure shifty-add approach yields the - ! correct result. Signed multiplies introduce complications. - ! - ! With 32-bit twos-complement numbers, -x can be represented as - ! - ! ((2 - (x/(2**32)) mod 2) * 2**32. - ! - ! To simplify the equations, the radix point can be moved to just - ! to the left of the sign bit. So: - ! - ! x * y = (xy) mod 2 - ! -x * y = (2 - x) mod 2 * y = (2y - xy) mod 2 - ! x * -y = x * (2 - y) mod 2 = (2x - xy) mod 2 - ! -x * -y = (2 - x) * (2 - y) = (4 - 2x - 2y + xy) mod 2 - ! - ! Because of the way the shift into the partial product is calculated - ! (N xor V), the extra term is automagically removed for negative - ! multiplicands, so no adjustment is necessary. - ! - ! But for unsigned multiplies, the high-order bit of the multiplicand - ! is incorrectly treated as a sign bit. For unsigned multiplies where - ! the high-order bit of the multiplicand is one, the result is - ! - ! xy - y * (2**32) - ! - ! we fix that here - ! - tst %o1 - bge 1f - nop - - add %o4, %o0, %o4 ! add (2**32) * %o0; bits 63-32 - ! of the product are in %o4 - ! - ! The multiply hasn't overflowed if the high-order bits are 0 - ! - ! if you are not interested in detecting overflow, - ! replace the following code with: - ! - ! 1: - ! rd %y, %o0 - ! retl - ! mov %o4, %o1 - ! -1: - rd %y, %o0 - retl ! leaf routine return - addcc %o4, %g0, %o1 ! return high-order bits and set Z if - ! high order bits are 0 - ! - ! 4-bit multiply - ! -umul_4bit: - mulscc %o4, %o1, %o4 ! first iteration of 5 - mulscc %o4, %o1, %o4 - mulscc %o4, %o1, %o4 - mulscc %o4, %o1, %o4 ! 4th iteration - mulscc %o4, %g0, %o4 ! last iteration only shifts - - rd %y, %o5 - ! - ! The folowing code adds (2**32) * %o0 to the product if the - ! multiplicand had it's high bit set (see 32-bit case for explanation) - ! - tst %o1 - bge 2f - sra %o4, 28, %o1 ! right shift high bits by 28 bits - - add %o1, %o0, %o1 - ! - ! The multiply hasn't overflowed if high-order bits are 0 - ! - ! if you are not interested in detecting overflow, - ! replace the following code with: - ! - ! 2: - ! sll %o4, 4, %o0 - ! srl %o5, 28, %o5 - ! retl - ! or %o5, %o0, %o0 - ! -2: - sll %o4, 4, %o0 ! left shift middle bits by 4 bits - srl %o5, 28, %o5 ! right shift low bits by 28 bits - or %o5, %o0, %o0 ! merge for true product - retl ! leaf routine return - tst %o1 ! set Z if high order bits are 0 - ! - ! 8-bit multiply - ! -umul_8bit: - mulscc %o4, %o1, %o4 ! second iteration of 9 - mulscc %o4, %o1, %o4 - mulscc %o4, %o1, %o4 - mulscc %o4, %o1, %o4 - mulscc %o4, %o1, %o4 - mulscc %o4, %o1, %o4 - mulscc %o4, %o1, %o4 ! 8th iteration - mulscc %o4, %g0, %o4 ! last iteration only shifts - - rd %y, %o5 - ! - ! The folowing code adds (2**32) * %o0 to the product if the - ! multiplicand had it's high bit set (see 32-bit case for explanation) - ! - tst %o1 - bge 3f - sra %o4, 24, %o1 ! right shift high bits by 24 bits - - add %o1, %o0, %o1 - ! - ! The multiply hasn't overflowed if high-order bits are 0 - ! - ! if you are not interested in detecting overflow, - ! replace the following code with: - ! - ! 3: - ! sll %o4, 8, %o0 - ! srl %o5, 24, %o5 - ! retl - ! or %o5, %o0, %o0 - ! -3: - sll %o4, 8, %o0 ! left shift middle bits by 8 bits - srl %o5, 24, %o5 ! right shift low bits by 24 bits - or %o5, %o0, %o0 ! merge for true product - retl ! leaf routine return - tst %o1 ! set Z if high order bits are 0 - ! - ! 12-bit multiply - ! -umul_12bit: - mulscc %o4, %o1, %o4 ! second iteration of 13 - mulscc %o4, %o1, %o4 - mulscc %o4, %o1, %o4 - mulscc %o4, %o1, %o4 - mulscc %o4, %o1, %o4 - mulscc %o4, %o1, %o4 - mulscc %o4, %o1, %o4 - mulscc %o4, %o1, %o4 - mulscc %o4, %o1, %o4 - mulscc %o4, %o1, %o4 - mulscc %o4, %o1, %o4 ! 12th iteration - mulscc %o4, %g0, %o4 ! last iteration only shifts - - rd %y, %o5 - ! - ! The folowing code adds (2**32) * %o0 to the product if the - ! multiplicand had it's high bit set (see 32-bit case for explanation) - ! - tst %o1 - bge 4f - sra %o4, 20, %o1 ! right shift high bits by 20 bits - - add %o1, %o0, %o1 - ! - ! The multiply hasn't overflowed if high-order bits are 0 - ! - ! if you are not interested in detecting overflow, - ! replace the following code with: - ! - ! 4: - ! sll %o4, 12, %o0 - ! srl %o5, 20, %o5 - ! retl - ! or %o5, %o0, %o0 - ! -4: - sll %o4, 12, %o0 ! left shift middle bits by 12 bits - srl %o5, 20, %o5 ! right shift low bits by 20 bits - or %o5, %o0, %o0 ! merge for true product - retl ! leaf routine return - tst %o1 ! set Z if high order bits are 0 - ! - ! 16-bit multiply - ! -umul_16bit: - mulscc %o4, %o1, %o4 ! second iteration of 17 - mulscc %o4, %o1, %o4 - mulscc %o4, %o1, %o4 - mulscc %o4, %o1, %o4 - mulscc %o4, %o1, %o4 - mulscc %o4, %o1, %o4 - mulscc %o4, %o1, %o4 - mulscc %o4, %o1, %o4 - mulscc %o4, %o1, %o4 - mulscc %o4, %o1, %o4 - mulscc %o4, %o1, %o4 - mulscc %o4, %o1, %o4 - mulscc %o4, %o1, %o4 - mulscc %o4, %o1, %o4 - mulscc %o4, %o1, %o4 ! 16th iteration - mulscc %o4, %g0, %o4 ! last iteration only shifts - - rd %y, %o5 - ! - ! The folowing code adds (2**32) * %o0 to the product if the - ! multiplicand had it's high bit set (see 32-bit case for explanation) - ! - tst %o1 - bge 5f - sra %o4, 16, %o1 ! right shift high bits by 16 bits - - add %o1, %o0, %o1 - ! - ! The multiply hasn't overflowed if high-order bits are 0 - ! - ! if you are not interested in detecting overflow, - ! replace the following code with: - ! - ! 5: - ! sll %o4, 16, %o0 - ! srl %o5, 16, %o5 - ! retl - ! or %o5, %o0, %o0 - ! -5: - sll %o4, 16, %o0 ! left shift middle bits by 16 bits - srl %o5, 16, %o5 ! right shift low bits by 16 bits - or %o5, %o0, %o0 ! merge for true product - retl ! leaf routine return - tst %o1 ! set Z if high order bits are 0 diff --git a/usr/src/cmd/sgs/rtld.4.x/zero.s b/usr/src/cmd/sgs/rtld.4.x/zero.s deleted file mode 100644 index d1efb94138..0000000000 --- a/usr/src/cmd/sgs/rtld.4.x/zero.s +++ /dev/null @@ -1,65 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright (c) 1990, 1991 Sun Microsystems, Inc. - */ - -#ident "%Z%%M% %I% %E% SMI" - -/* - * Routine to zero out a section of memory (the tail end of the data segment - * upto a page boundary). First nibble off any bytes up to the first double - * aligned word, and then clear doubles until the byte count is zero. Note, - * this assumes the count specified has been rounded to end on a double word - * boundary. - * - * %o0 = addr, %o1 = len - */ - - .seg "text" - .global __zero -__zero: - tst %o1 ! Have we any count at all? - ba 3f ! Go find out, - clr %g1 ! but prepare for long loop - -! Byte clearing loop - -0: - inc %o0 ! Bump address - deccc %o1 ! Decrement count -3: - bz 1f ! If no count left, exit - andcc %o0, 7, %g0 ! Is the address less than double-word aligned? - bnz,a 0b ! Branch if so - clrb [%o0] ! but clear the current byte anyway - -! Double clearing loop - -2: - std %g0, [%o0] ! Clear next 8 bytes - subcc %o1, 8, %o1 ! Decrement count - bnz 2b ! Branch if any left - inc 8, %o0 ! but always increment address by 8 -1: - retl ! Go home - nop diff --git a/usr/src/man/man3nsl/rpc_soc.3nsl b/usr/src/man/man3nsl/rpc_soc.3nsl index f69344409f..6177874fda 100644 --- a/usr/src/man/man3nsl/rpc_soc.3nsl +++ b/usr/src/man/man3nsl/rpc_soc.3nsl @@ -4,7 +4,7 @@ .\" 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] -.TH RPC_SOC 3NSL "May 13, 2017" +.TH RPC_SOC 3NSL "May 22, 2022" .SH NAME rpc_soc, authdes_create, authunix_create, authunix_create_default, callrpc, clnt_broadcast, clntraw_create, clnttcp_create, clntudp_bufcreate, @@ -14,7 +14,6 @@ svc_getreq, svc_register, svc_unregister, svcfd_create, svcraw_create, svctcp_create, svcudp_bufcreate, svcudp_create, xdr_authunix_parms \- obsolete library routines for RPC .SH SYNOPSIS -.LP .nf #define PORTMAP #include <rpc/rpc.h> @@ -23,7 +22,8 @@ library routines for RPC .LP .nf \fBAUTH *\fR\fBauthdes_create\fR(\fBchar *\fR\fIname\fR, \fBuint_t\fR \fIwindow\fR, - \fBstruct sockaddr_in *\fR\fIsyncaddr\fR, \fBdes_block *\fR\fIckey\fR); + \fBstruct sockaddr_in *\fR\fIsyncaddr\fR, \fBdes_block *\fR\fIckey\fR, + \fBint\fR \fIcalltype\fR, \fBAUTH **\fR\fIretauth\fR); .fi .LP @@ -39,7 +39,7 @@ library routines for RPC .LP .nf -\fBcallrpc\fR(\fBchar *\fR\fIhost\fR, \fBrpcprog_t\fR \fIprognum\fR, \fBrpcvers_t\fR \fIversnum\fR, +\fBint\fR \fBcallrpc\fR(\fBchar *\fR\fIhost\fR, \fBrpcprog_t\fR \fIprognum\fR, \fBrpcvers_t\fR \fIversnum\fR, \fBrpcproc_t\fR \fIprocnum\fR, \fBxdrproc_t\fR \fIinproc\fR, \fBchar *\fR\fIin\fR, \fBxdrproc_t\fR \fIoutproc\fR, \fBchar *\fR\fIout\fR); .fi @@ -48,7 +48,7 @@ library routines for RPC .nf \fBenum\fR \fBclnt_stat_clnt_broadcast\fR(\fBrpcprog_t\fR \fIprognum\fR, \fBrpcvers_t\fR \fIversnum\fR, \fBrpcproc_t\fR \fIprocnum\fR, \fBxdrproc_t\fR \fIinproc\fR, \fBchar *\fR\fIin\fR, - \fBxdrproc_t\fR \fIoutproc\fR, \fBchar *\fR\fIout\fR, \fBresultproc_t\fR\fIeachresult\fR); + \fBxdrproc_t\fR \fIoutproc\fR, \fBchar *\fR\fIout\fR, \fBresultproc_t\fR \fIeachresult\fR); .fi .LP @@ -72,8 +72,8 @@ library routines for RPC .LP .nf -\fBCLIENT *\fR\fBclntudp_create\fR(\fBstruct sockaddr_in *\fR\fIaddr\fR, - \fBrpcprog_t\fR \fIprognum\fR, \fBstruct timeval\fR \fIwait\fR, \fBint *\fR\fIfdp\fR); +\fBCLIENT *\fR\fBclntudp_create\fR(\fBstruct sockaddr_in *\fR\fIaddr\fR, \fBrpcprog_t\fR \fIprognum\fR, + \fBrpcvers_t\fR \fIversnum\fR, \fBstruct timeval\fR \fIwait\fR, \fBint *\fR\fIfdp\fR); .fi .LP @@ -164,14 +164,14 @@ int svc_fds; .LP .nf -\fB\fR\fBregisterrpc\fR(\fBrpcprog_t\fR \fIprognum\fR, \fBrpcvers_t\fR \fIversnum\fR, \fBrpcproc_t\fR \fIprocnum\fR, +\fBint\fR \fBregisterrpc\fR(\fBrpcprog_t\fR \fIprognum\fR, \fBrpcvers_t\fR \fIversnum\fR, \fBrpcproc_t\fR \fIprocnum\fR, \fBchar *(*procname)()\fR, \fBxdrproc_t\fR \fIinproc\fR, \fBxdrproc_t\fR \fIoutproc\fR); .fi .LP .nf -\fBbool_t\fR\fBsvc_register\fR(\fBSVCXPRT *\fR\fIxprt\fR, \fBrpcprog_t\fR \fIprognum\fR, \fBrpcvers_t\fR \fIversnum\fR, - \fBvoid (*\fR\fIdispatch()\fR, \fBint\fR \fIprotocol\fR); +\fBbool_t\fR \fBsvc_register\fR(\fBSVCXPRT *\fR\fIxprt\fR, \fBrpcprog_t\fR \fIprognum\fR, \fBrpcvers_t\fR \fIversnum\fR, + \fBvoid (*)\fR\fIdispatch()\fR, \fBint\fR \fIprotocol\fR); .fi .LP @@ -185,7 +185,6 @@ int svc_fds; .fi .SH DESCRIPTION -.LP \fBRPC\fR routines allow C programs to make procedure calls on other machines across the network. First, the client calls a procedure to send a request to the server. Upon receipt of the request, the server calls a dispatch routine to @@ -198,7 +197,6 @@ routines. The preferred routine is given after the description of the routine. New programs should use the preferred routines, as support for the older interfaces may be dropped in future releases. .SS "File Descriptors" -.LP Transport independent \fBRPC\fR uses \fBTLI\fR as its transport interface instead of sockets. .sp @@ -211,7 +209,6 @@ with both \fBlibrpcsoc\fR and \fBlibnsl\fR. If the user passed \fBlibnsl\fR only, then the routine will return a \fBTLI\fR file descriptor and not a socket. .SS "Routines" -.LP The following routines require that the header \fB<rpc/rpc.h>\fR be included. The symbol \fBPORTMAP\fR should be defined so that the appropriate function declarations for the old interfaces are included through the header files. @@ -223,9 +220,9 @@ declarations for the old interfaces are included through the header files. .RS 30n \fBauthdes_create()\fR is the first of two routines which interface to the \fBRPC\fR secure authentication system, known as \fBDES\fR authentication. The -second is \fBauthdes_getucred()\fR, below. Note: the keyserver daemon -\fBkeyserv\fR(8) must be running for the \fBDES\fR authentication system to -work. +second is \fBauthdes_getucred()\fR, see \fBsecure_rpc\fR(3NSL). Note: the +keyserver daemon \fBkeyserv\fR(8) must be running for the \fBDES\fR +authentication system to work. .sp \fBauthdes_create()\fR, used on the client side, returns an authentication handle that will enable the use of the secure authentication system. The first @@ -236,13 +233,13 @@ using \fBuser2netname()\fR. See \fBsecure_rpc\fR(3NSL). The second field is window on the validity of the client credential, given in seconds. A small window is more secure than a large one, but choosing too small of a window will increase the frequency of resynchronizations because of clock drift. The -third parameter \fIsyncaddr\fR is optional. If it is \fBNULL,\fR then the +third parameter \fIsyncaddr\fR is optional. If it is \fBNULL\fR, then the authentication system will assume that the local clock is always in sync with the server's clock, and will not attempt resynchronizations. If an address is supplied, however, then the system will use the address for consulting the remote time service whenever resynchronization is required. This parameter is usually the address of the \fBRPC\fR server itself. The final parameter -\fIckey\fR is also optional. If it is \fBNULL,\fR then the authentication +\fIckey\fR is also optional. If it is \fBNULL\fR, then the authentication system will generate a random \fBDES\fR key to be used for the encryption of credentials. If it is supplied, however, then it will be used instead. .sp @@ -256,10 +253,10 @@ This routine exists for backward compatibility only, and it is made obsolete by \fB\fBauthunix_create()\fR\fR .ad .RS 30n -Create and return an \fBRPC\fR authentication handle that contains .UX +Create and return an \fBRPC\fR authentication handle that contains UNIX authentication information. The parameter \fIhost\fR is the name of the machine -on which the information was created; \fIuid\fR is the user's user \fBID;\fR -\fIgid\fR is the user's current group \fBID;\fR \fIgrouplen\fR and +on which the information was created; \fIuid\fR is the user's user \fBID\fR; +\fIgid\fR is the user's current group \fBID\fR; \fIgrouplen\fR and \fIgidlistp\fR refer to a counted array of groups to which the user belongs. .sp It is not very difficult to impersonate a user. @@ -320,13 +317,13 @@ where \fIout\fR is the same as \fIout\fR passed to \fBclnt_broadcast()\fR, except that the remote procedure's output is decoded there; \fIaddr\fR points to the address of the machine that sent the results. If \fBeachresult()\fR returns \fB0\fR, \fBclnt_broadcast()\fR waits for more replies; otherwise it -returns with appropriate status. If \fBeachresult()\fR is \fBNULL,\fR +returns with appropriate status. If \fBeachresult()\fR is \fBNULL\fR, \fBclnt_broadcast()\fR returns without waiting for any replies. .sp Broadcast packets are limited in size to the maximum transfer unit of the -transports involved. For Ethernet, the callers argument size is approximately +transports involved. For Ethernet, the caller's argument size is approximately 1500 bytes. Since the call message is sent to all connected networks, it may -potentially lead to broadcast storms. \fBclnt_broadcast()\fR uses SB AUTH_SYS +potentially lead to broadcast storms. \fBclnt_broadcast()\fR uses \fBAUTH_SYS\fR credentials by default. See \fBrpc_clnt_auth\fR(3NSL). This routine exists for backward compatibility only, and is made obsolete by \fBrpc_broadcast()\fR. See \fBrpc_clnt_calls\fR(3NSL). @@ -365,7 +362,7 @@ that the remote program is listening on. The remote \fBrpcbind\fR service is consulted for this information. The parameter \fI*fdp\fR is a file descriptor, which may be open and bound; if it is \fBRPC_ANYSOCK\fR, then this routine opens a new one and sets \fI*fdp\fR. Refer to the \fBFile Descriptor\fR section -for more information. Since \fBTCP-based\fR \fBRPC\fR uses buffered \fBI/O,\fR +for more information. Since \fBTCP\fR-based \fBRPC\fR uses buffered \fBI/O\fR, the user may specify the size of the send and receive buffers with the parameters \fIsendsz\fR and \fIrecvsz\fR. Values of \fB0\fR choose suitable defaults. This routine returns \fBNULL\fR if it fails. @@ -381,7 +378,8 @@ This routine exists for backward compatibility only. \fBclnt_create()\fR, \fB\fBclntudp_bufcreate()\fR\fR .ad .RS 30n -Create a client handle for the remote program \fIprognum\fR, on \fIversnum\fR; +Create a client handle for the remote program \fIprognum\fR, version +\fIversnum\fR; the client uses \fBUDP/IP\fR as the transport. The remote program is located at the Internet address \fIaddr\fR. If \fIaddr\fR->\fIsin_port\fR is \fB0\fR, it is set to port on which the remote program is listening on (the remote @@ -397,7 +395,7 @@ error can be printed using the \fBclnt_pcreateerror()\fR routine. See \fBrpc_clnt_create\fR(3NSL). .sp The user can specify the maximum packet size for sending and receiving by using -\fIsendsz\fR and \fIrecvsz\fR arguments for \fBUDP-based\fR \fBRPC\fR messages. +\fIsendsz\fR and \fIrecvsz\fR arguments for \fBUDP\fR-based \fBRPC\fR messages. .sp If \fIaddr\fR->\fIsin_port\fR is \fB0\fR and the requested version number \fIversnum\fR is not registered with the remote portmap service, it returns a @@ -418,7 +416,7 @@ This routine exists for backward compatibility only. \fBclnt_tli_create()\fR or This routine creates an \fBRPC\fR client handle for the remote program \fIprognum\fR, version \fIversnum\fR; the client uses \fBUDP/IP\fR as a transport. The remote program is located at Internet address \fIaddr\fR. If -\fIaddr\fR->\fIsin_port\fR is \fB0\fR, then it is set to actual port that the +\fIaddr\fR->\fIsin_port\fR is \fB0\fR, then it is set to the actual port that the remote program is listening on. The remote \fBrpcbind\fR service is consulted for this information. The parameter \fI*fdp\fR is a file descriptor, which may be open and bound; if it is \fBRPC_ANYSOCK\fR, then this routine opens a new @@ -430,7 +428,7 @@ total time for the call to time out is specified by \fBclnt_call()\fR. See success, otherwise it returns \fBNULL\fR. The error can be printed using the \fBclnt_pcreateerror()\fR routine. See \fBrpc_clnt_create\fR(3NSL). .sp -Since \fBUDP-based\fR \fBRPC\fR messages can only hold up to 8 Kbytes of +Since \fBUDP\fR-based \fBRPC\fR messages can only hold up to 8 Kbytes of encoded data, this transport cannot be used for procedures that take large arguments or return huge results. .sp @@ -487,8 +485,8 @@ provided by \fBrpcb_getaddr()\fR. See \fBrpcbind\fR(3NSL). .RS 30n A user interface to the \fBportmap\fR service, which returns a list of the current \fBRPC\fR program-to-port mappings on the host located at \fBIP\fR -address \fIaddr\fR. This routine can return \fBNULL .\fR The command -`\fBrpcinfo\fR\fB-p\fR' uses this routine. +address \fIaddr\fR. This routine can return \fBNULL\fR. The command +`\fBrpcinfo\fR \fB-p\fR' uses this routine. .sp This routine exists for backward compatibility only, enhanced functionality is provided by \fBrpcb_getmaps()\fR. See \fBrpcbind\fR(3NSL). @@ -505,9 +503,9 @@ on which waits a service that supports program \fIprognum\fR, version \fIversnum\fR, and speaks the transport protocol associated with \fIprotocol\fR. The value of \fIprotocol\fR is most likely \fBIPPROTO_UDP\fR or \fBIPPROTO_TCP\fR. A return value of \fB0\fR means that the mapping does not -exist or that the \fBRPC\fR system failured to contact the remote \fBportmap\fR +exist or that the \fBRPC\fR system failed to contact the remote \fBportmap\fR service. In the latter case, the global variable \fBrpc_createerr\fR contains -the \fB RPC\fR status. +the \fBRPC\fR status. .sp This routine exists for backward compatibility only, enhanced functionality is provided by \fBrpcb_getaddr()\fR. See \fBrpcbind\fR(3NSL). @@ -525,7 +523,7 @@ an \fBRPC\fR on the behalf of the caller to a procedure on that host. succeeds. The definitions of other parameters are discussed in \fBcallrpc()\fR and \fBclnt_call()\fR. See \fBrpc_clnt_calls\fR(3NSL). .sp -This procedure is only available for the UDP transport. +This procedure is only available for the \fBUDP\fR transport. .sp If the requested remote procedure is not registered with the remote \fBportmap\fR then no error response is returned and the call times out. Also, @@ -562,8 +560,8 @@ provided by \fBrpcb_set()\fR. See \fBrpcbind\fR(3NSL). .RS 30n A user interface to the \fBportmap\fR service, which destroys all mapping between the triple [\fIprognum\fR, \fIversnum\fR, \fIall-protocols\fR] and -\fIport\fR on the machine's \fBportmap\fR service. This routine returns one if -it succeeds, \fB0\fR otherwise. +\fIport\fR on the machine's \fBportmap\fR service. This routine returns +\fB1\fR if it succeeds, \fB0\fR otherwise. .sp This routine exists for backward compatibility only, enhanced functionality is provided by \fBrpcb_unset()\fR. See \fBrpcbind\fR(3NSL). @@ -578,7 +576,7 @@ provided by \fBrpcb_unset()\fR. See \fBrpcbind\fR(3NSL). A global variable reflecting the \fBRPC\fR service side's read file descriptor bit mask; it is suitable as a parameter to the \fBselect()\fR call. This is only of interest if a service implementor does not call \fBsvc_run()\fR, but -rather does his own asynchronous event processing. This variable is read-only , +rather does his own asynchronous event processing. This variable is read-only, yet it may change after calls to \fBsvc_getreq()\fR or any creation routines. Do not pass its address to \fBselect()\fR! Similar to \fBsvc_fdset\fR, but limited to 32 descriptors. @@ -660,15 +658,15 @@ obsoletes it. \fB\fBsvctcp_create()\fR\fR .ad .RS 30n -This routine creates a \fBTCP/IP-based\fR \fBRPC\fR service transport, to which +This routine creates a \fBTCP/IP\fR-based \fBRPC\fR service transport, to which it returns a pointer. The transport is associated with the file descriptor \fIfd\fR, which may be \fBRPC_ANYSOCK\fR, in which case a new file descriptor is created. If the file descriptor is not bound to a local \fBTCP\fR port, then this routine binds it to an arbitrary port. Refer to the \fBFile Descriptor\fR section for more information. Upon completion, \fIxprt\fR->\fBxp_fd\fR is the transport's file descriptor, and \fIxprt\fR->\fBxp_port\fR is the transport's -port number. This routine returns \fBNULL\fR if it fails. Since \fBTCP-based\fR -\fBRPC\fR uses buffered \fBI/O,\fR users may specify the size of buffers; +port number. This routine returns \fBNULL\fR if it fails. Since \fBTCP\fR-based +\fBRPC\fR uses buffered \fBI/O\fR, users may specify the size of buffers; values of \fB0\fR choose suitable defaults. .sp This routine exists for backward compatibility only. \fBsvc_create()\fR, @@ -682,7 +680,7 @@ This routine exists for backward compatibility only. \fBsvc_create()\fR, \fB\fBsvcudp_bufcreate()\fR\fR .ad .RS 30n -This routine creates a \fBUDP/IP-based\fR \fBRPC\fR service transport, to which +This routine creates a \fBUDP/IP\fR-based \fBRPC\fR service transport, to which it returns a pointer. The transport is associated with the file descriptor \fIfd\fR. If \fIfd\fR is \fBRPC_ANYSOCK\fR then a new file descriptor is created. If the file descriptor is not bound to a local \fBUDP\fR port, then @@ -692,7 +690,8 @@ this routine binds it to an arbitrary port. Upon completion, Descriptor\fR section for more information. This routine returns \fBNULL\fR if it fails. .sp -The user specifies the maximum packet size for sending and receiving UDP-based +The user specifies the maximum packet size for sending and receiving +\fBUDP\fR-based \fBRPC\fR messages by using the \fIsendsz\fR and \fIrecvsz\fR parameters. .sp This routine exists for backward compatibility only. \fBsvc_tli_create()\fR, or @@ -705,7 +704,7 @@ This routine exists for backward compatibility only. \fBsvc_tli_create()\fR, or \fB\fBsvcudp_create()\fR\fR .ad .RS 30n -This routine creates a \fBUDP/IP-based\fR \fBRPC\fR service transport, to which +This routine creates a \fBUDP/IP\fR-based \fBRPC\fR service transport, to which it returns a pointer. The transport is associated with the file descriptor \fIfd\fR, which may be \fBRPC_ANYSOCK\fR, in which case a new file descriptor is created. If the file descriptor is not bound to a local \fBUDP\fR port, then @@ -714,7 +713,7 @@ this routine binds it to an arbitrary port. Upon completion, \fIxprt\fR->\fBxp_port\fR is the transport's port number. This routine returns \fBNULL\fR if it fails. .sp -Since \fBUDP-based\fR \fBRPC\fR messages can only hold up to 8 Kbytes of +Since \fBUDP\fR-based \fBRPC\fR messages can only hold up to 8 Kbytes of encoded data, this transport cannot be used for procedures that take large arguments or return huge results. .sp @@ -729,7 +728,7 @@ This routine exists for backward compatibility only. \fBsvc_create()\fR, \fB\fBregisterrpc()\fR\fR .ad .RS 30n -Register program \fIprognum\fR, procedure \fIprocname\fR, and version +Register program \fIprognum\fR, procedure \fIprocnum\fR, and version \fIversnum\fR with the \fBRPC\fR service package. If a request arrives for program \fIprognum\fR, version \fIversnum\fR, and procedure \fIprocnum\fR, \fIprocname\fR is called with a pointer to its parameter(s). \fIprocname\fR @@ -799,7 +798,6 @@ This routine exists for backward compatibility only, and is made obsolete by .RE .SH ATTRIBUTES -.LP See \fBattributes\fR(7) for descriptions of the following attributes: .sp @@ -814,7 +812,6 @@ MT-Level Unsafe .TE .SH SEE ALSO -.LP .BR select (3C), .BR libnsl (3LIB), .BR netdir (3NSL), @@ -836,6 +833,5 @@ MT-Level Unsafe .BR rpcbind (8), .BR rpcinfo (8) .SH NOTES -.LP These interfaces are unsafe in multithreaded applications. Unsafe interfaces should be called only from the main thread. diff --git a/usr/src/man/man4d/pvscsi.4d b/usr/src/man/man4d/pvscsi.4d new file mode 100644 index 0000000000..16ce2a4a82 --- /dev/null +++ b/usr/src/man/man4d/pvscsi.4d @@ -0,0 +1,59 @@ +.\" +.\" This file and its contents are supplied under the terms of the +.\" Common Development and Distribution License ("CDDL"), version 1.0. +.\" You may only use this file in accordance with the terms of version +.\" 1.0 of the CDDL. +.\" +.\" A full copy of the text of the CDDL should have accompanied this +.\" source. A copy of the CDDL is also available via the Internet at +.\" http://www.illumos.org/license/CDDL. +.\" +.\" +.\" Copyright 2022 RackTop Systems, Inc. +.\" +.Dd July 1, 2022 +.Dt PVSCSI 4D +.Os +.Sh NAME +.Nm pvscsi +.Nd VMware SCSI driver +.Sh DESCRIPTION +The +.Nm +driver provides a paravirtual SCSI transport, allowing +access to SCSI targets exposed to guests using VMware's +paravirtualization support. +The driver supports the following capabilities: +.Bl -dash +.It +Dynamic hot-plug (if supported by the host) +.It +Honors packet timeouts specified in +.Xr scsi_pkt 9S +.It +Reset of target or logical unit via +.Xr scsi_reset 9F +.It +Abort for individual commands via +.Xr scsi_abort 9F +.It +Command queueing (both tagged and untagged) +.El +.Pp +The +.Nm +driver is based on +.Xr iport 9 , +and uses a single iport per PCI function, +with a unit-address of "iport0". +Children of the iport use a unit-address with the +format "target,lun", where both target and lun are +presented as hexadecimal values. +.Sh SEE ALSO +.Xr sd 4D , +.Xr st 4D , +.Xr scsi 5 , +.Xr iport 9 , +.Xr scsi_abort 9F , +.Xr scsi_reset 9F , +.Xr scsi_pkt 9S diff --git a/usr/src/man/man5/system.5 b/usr/src/man/man5/system.5 index ff7b84c0b7..b4cef157ba 100644 --- a/usr/src/man/man5/system.5 +++ b/usr/src/man/man5/system.5 @@ -3,15 +3,15 @@ .\" Copyright 2016 Hans Rosenfeld <rosenfeld@grumpf.hope-2000.org> .\" Copyright 2019 OmniOS Community Edition (OmniOSce) Association. .\" Copyright 2019 Peter Tribble +.\" Copyright 2022 Garrett D'Amore <garrett@damore.org> .\" Copyright 1989 AT&T .\" 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] -.TH SYSTEM 5 "Apr 20, 2019" +.TH SYSTEM 5 "June 30, 2022" .SH NAME system \- system configuration information file .SH DESCRIPTION -.LP The \fBsystem\fR file is used for customizing the operation of the operating system kernel. The recommended procedure is to preserve the original \fBsystem\fR file before modifying it. @@ -52,54 +52,36 @@ namespace. The following namespaces are currently supported on all platforms: .sp .ne 2 .na -\fB\fBdrv\fR\fR +\fBdacf\fR .ad .RS 10n -Modules in this namespace are device drivers. +These modules provide rules and actions for device auto-configuration. .RE .sp .ne 2 .na -\fB\fBexec\fR\fR +\fB\fBdrv\fR\fR .ad .RS 10n -Modules in this namespace are execution format modules. The following -\fBexec\fR modules are currently provided: -.sp -.ne 2 -.na -\fBOnly on SPARC systems:\fR -.ad -.RS 28n -.sp -.in +2 -.nf -aoutexec -.fi -.in -2 -.sp - +Modules in this namespace are device drivers. .RE .sp .ne 2 .na -\fBOn SPARC and IA systems:\fR +\fB\fBexec\fR\fR .ad -.RS 28n +.RS 10n +Modules in this namespace are execution format modules. The following +\fBexec\fR modules are currently provided: .sp -.in +2 +.ne 2 .nf elfexec intpexec javaexec .fi -.in -2 -.sp - -.RE - .RE .sp @@ -160,36 +142,6 @@ These modules do not fit into any of the above categories, so are considered .sp .LP -SPARC only: -.sp -.ne 2 -.na -\fB\fBdacf\fR\fR -.ad -.RS 8n -These modules provide rules and actions for device auto-configuration. -.RE - -.sp -.ne 2 -.na -\fB\fBtod\fR\fR -.ad -.RS 8n -These modules provide support for the time of day hardware. -.RE - -.sp -.ne 2 -.na -\fB\fBcpu\fR\fR -.ad -.RS 8n -These modules provide \fBCPU\fR-specific kernel routines. -.RE - -.sp -.LP A description of each of the supported commands follows: .sp .ne 2 @@ -299,9 +251,7 @@ escape sequences are supported within the quoted string: .RE .SH EXAMPLES -.LP \fBExample 1 \fRA sample \fBsystem\fR file. -.sp .LP The following is a sample \fBsystem\fR file. @@ -350,12 +300,10 @@ set moddebug | 0x40 .sp .SH SEE ALSO -.LP .BR boot (8), .BR init (8), .BR kernel (8) .SH WARNINGS -.LP Use care when modifying the \fBsystem\fR file; it modifies the operation of the kernel. If you preserved the original \fBsystem\fR file, you can boot using \fBboot -a\fR, which will ask you to specify the path to the saved file. This @@ -364,5 +312,4 @@ file that will work, you may specify \fB/dev/null\fR. This acts as an empty \fBsystem\fR file, and the system will attempt to boot using its default settings. .SH NOTES -.LP The \fBsystem\fR files are read only once, at boot time. diff --git a/usr/src/pkg/manifests/driver-storage-pvscsi.p5m b/usr/src/pkg/manifests/driver-storage-pvscsi.p5m index 7fa494c305..8196674e71 100644 --- a/usr/src/pkg/manifests/driver-storage-pvscsi.p5m +++ b/usr/src/pkg/manifests/driver-storage-pvscsi.p5m @@ -30,5 +30,5 @@ dir path=kernel/drv/$(ARCH64) group=sys file path=kernel/drv/$(ARCH64)/pvscsi group=sys driver name=pvscsi class=scsi-self-identifying alias=pci15ad,7c0 license lic_CDDL license=lic_CDDL -license usr/src/uts/intel/io/scsi/adapters/pvscsi/THIRDPARTYLICENSE \ - license=usr/src/uts/intel/io/scsi/adapters/pvscsi/THIRDPARTYLICENSE +license usr/src/uts/common/io/scsi/adapters/pvscsi/THIRDPARTYLICENSE \ + license=usr/src/uts/common/io/scsi/adapters/pvscsi/THIRDPARTYLICENSE diff --git a/usr/src/pkg/manifests/system-kernel.p5m b/usr/src/pkg/manifests/system-kernel.p5m index 208bd86844..4ab8a619b7 100644 --- a/usr/src/pkg/manifests/system-kernel.p5m +++ b/usr/src/pkg/manifests/system-kernel.p5m @@ -276,7 +276,6 @@ file path=kernel/drv/vnic.conf group=sys file path=kernel/drv/wc.conf group=sys dir path=kernel/exec group=sys dir path=kernel/exec/$(ARCH64) group=sys -$(sparc_ONLY)file path=kernel/exec/$(ARCH64)/aoutexec group=sys mode=0755 file path=kernel/exec/$(ARCH64)/elfexec group=sys mode=0755 file path=kernel/exec/$(ARCH64)/intpexec group=sys mode=0755 dir path=kernel/firmware group=sys diff --git a/usr/src/tools/findunref/exception_list.open b/usr/src/tools/findunref/exception_list.open index ebf81e1c4e..25a4d3efd7 100644 --- a/usr/src/tools/findunref/exception_list.open +++ b/usr/src/tools/findunref/exception_list.open @@ -85,7 +85,6 @@ # Ignore internal packages, scripts, and tools that are intentionally not # built or used during a nightly. # -./usr/src/cmd/sgs/rtld.4.x ./usr/src/prototypes ./usr/src/cmd/pools/poold/com/sun/solaris/*/*/package.html ./usr/src/uts/intel/io/acpica/cmp_ca.sh diff --git a/usr/src/uts/common/Makefile.files b/usr/src/uts/common/Makefile.files index 9f0a12ff88..e1317ed98f 100644 --- a/usr/src/uts/common/Makefile.files +++ b/usr/src/uts/common/Makefile.files @@ -1959,6 +1959,8 @@ SKD_OBJS = skd.o NVME_OBJS = nvme.o +PVSCSI_OBJS = pvscsi.o + # # Build up defines and paths. # @@ -2341,4 +2343,3 @@ MLXCX_OBJS += mlxcx.o mlxcx_dma.o mlxcx_cmd.o mlxcx_intr.o mlxcx_gld.o \ # ENA_OBJS += ena.o ena_admin.o ena_dma.o ena_gld.o ena_hw.o ena_intr.o \ ena_stats.o ena_tx.o ena_rx.o - diff --git a/usr/src/uts/common/Makefile.rules b/usr/src/uts/common/Makefile.rules index 265ec59b39..2665615198 100644 --- a/usr/src/uts/common/Makefile.rules +++ b/usr/src/uts/common/Makefile.rules @@ -403,6 +403,10 @@ $(OBJS_DIR)/%.o: $(UTSBASE)/common/io/scsi/adapters/pmcs/%.c $(OBJS_DIR)/%.o: $(UTSBASE)/common/io/scsi/adapters/pmcs/%.bin $(COMPILE.b) -o $@ $< +$(OBJS_DIR)/%.o: $(UTSBASE)/common/io/scsi/adapters/pvscsi/%.c + $(COMPILE.c) -o $@ $< + $(CTFCONVERT_O) + $(OBJS_DIR)/%.o: $(COMMONBASE)/fsreparse/%.c $(COMPILE.c) -o $@ $< $(CTFCONVERT_O) diff --git a/usr/src/uts/common/conf/param.c b/usr/src/uts/common/conf/param.c index 942a1fe619..93481c378e 100644 --- a/usr/src/uts/common/conf/param.c +++ b/usr/src/uts/common/conf/param.c @@ -24,6 +24,7 @@ * Copyright (c) 1983, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright 2017, Joyent, Inc. * Copyright 2012 Milan Jurik. All rights reserved. + * Copyright 2022 Garrett D'Amore <garrett@damore.org> */ #include <sys/types.h> @@ -337,11 +338,6 @@ short elfmagic = 0x7f45; short intpmagic = 0x2321; short jmagic = 0x504b; -#if defined(__sparc) -short aout_nmagic = NMAGIC; -short aout_zmagic = ZMAGIC; -short aout_omagic = OMAGIC; -#endif short nomagic = 0; /* @@ -351,9 +347,6 @@ short nomagic = 0; #define ELF64MAGIC_STRING "\x7f""ELF\x2" #define INTPMAGIC_STRING "#!" #define JAVAMAGIC_STRING "PK\003\004" -#define AOUT_OMAGIC_STRING "\x1""\x07" /* 0407 */ -#define AOUT_NMAGIC_STRING "\x1""\x08" /* 0410 */ -#define AOUT_ZMAGIC_STRING "\x1""\x0b" /* 0413 */ #define NOMAGIC_STRING "" #define SHBIN_CNTL(x) ((x)&037) @@ -365,11 +358,6 @@ char elf64magicstr[] = ELF64MAGIC_STRING; char intpmagicstr[] = INTPMAGIC_STRING; char shbinmagicstr[] = SHBINMAGIC_STRING; char javamagicstr[] = JAVAMAGIC_STRING; -#if defined(__sparc) -char aout_nmagicstr[] = AOUT_NMAGIC_STRING; -char aout_zmagicstr[] = AOUT_ZMAGIC_STRING; -char aout_omagicstr[] = AOUT_OMAGIC_STRING; -#endif char nomagicstr[] = NOMAGIC_STRING; char *execswnames[] = { @@ -380,11 +368,6 @@ char *execswnames[] = { "intpexec", "shbinexec", "javaexec", -#if defined(__sparc) - "aoutexec", - "aoutexec", - "aoutexec", -#endif NULL, NULL, NULL @@ -398,11 +381,6 @@ struct execsw execsw[] = { { intpmagicstr, 0, 2, NULL, NULL, NULL }, { shbinmagicstr, 0, SHBINMAGIC_LEN, NULL, NULL, NULL }, { javamagicstr, 0, 4, NULL, NULL, NULL }, -#if defined(__sparc) - { aout_zmagicstr, 2, 2, NULL, NULL, NULL }, - { aout_nmagicstr, 2, 2, NULL, NULL, NULL }, - { aout_omagicstr, 2, 2, NULL, NULL, NULL }, -#endif { nomagicstr, 0, 0, NULL, NULL, NULL }, { nomagicstr, 0, 0, NULL, NULL, NULL }, { nomagicstr, 0, 0, NULL, NULL, NULL }, diff --git a/usr/src/uts/common/exec/aout/aout.c b/usr/src/uts/common/exec/aout/aout.c deleted file mode 100644 index 5dbb2ed28c..0000000000 --- a/usr/src/uts/common/exec/aout/aout.c +++ /dev/null @@ -1,348 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (the "License"). - * You may not use this file except in compliance with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - * Copyright (c) 2011 Bayard G. Bell. All rights reserved. - * Copyright 2015, Joyent, Inc. - */ - -#include <sys/types.h> -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/fpu/fpusystm.h> -#include <sys/sysmacros.h> -#include <sys/signal.h> -#include <sys/cred.h> -#include <sys/user.h> -#include <sys/errno.h> -#include <sys/vnode.h> -#include <sys/mman.h> -#include <sys/kmem.h> -#include <sys/proc.h> -#include <sys/pathname.h> -#include <sys/cmn_err.h> -#include <sys/debug.h> -#include <sys/exec.h> -#include <sys/exechdr.h> -#include <sys/auxv.h> -#include <sys/core.h> -#include <sys/vmparam.h> -#include <sys/archsystm.h> -#include <sys/fs/swapnode.h> -#include <sys/modctl.h> -#include <vm/anon.h> -#include <vm/as.h> -#include <vm/seg.h> - -static int aoutexec(vnode_t *vp, execa_t *uap, uarg_t *args, - intpdata_t *idatap, int level, long *execsz, int setid, - caddr_t exec_file, cred_t *cred, int *brand_action); -static int get_aout_head(struct vnode **vpp, struct exdata *edp, long *execsz, - int *isdyn); -static int aoutcore(vnode_t *vp, proc_t *pp, cred_t *credp, - rlim64_t rlimit, int sig, core_content_t content); -extern int elf32exec(vnode_t *, execa_t *, uarg_t *, intpdata_t *, int, - long *, int, caddr_t, cred_t *, int); -extern int elf32core(vnode_t *, proc_t *, cred_t *, rlim64_t, int, - core_content_t); - -static struct execsw nesw = { - aout_nmagicstr, - 2, - 2, - aoutexec, - aoutcore -}; - -static struct execsw zesw = { - aout_zmagicstr, - 2, - 2, - aoutexec, - aoutcore -}; - -static struct execsw oesw = { - aout_omagicstr, - 2, - 2, - aoutexec, - aoutcore -}; - -/* - * Module linkage information for the kernel. - */ -static struct modlexec nexec = { - &mod_execops, "exec for NMAGIC", &nesw -}; - -static struct modlexec zexec = { - &mod_execops, "exec for ZMAGIC", &zesw -}; - -static struct modlexec oexec = { - &mod_execops, "exec for OMAGIC", &oesw -}; - -static struct modlinkage modlinkage = { - MODREV_1, &nexec, &zexec, &oexec, NULL -}; - -int -_init(void) -{ - return (mod_install(&modlinkage)); -} - -int -_fini(void) -{ - return (mod_remove(&modlinkage)); -} - -int -_info(struct modinfo *modinfop) -{ - return (mod_info(&modlinkage, modinfop)); -} - - -/*ARGSUSED*/ -static int -aoutexec(vnode_t *vp, struct execa *uap, struct uarg *args, - struct intpdata *idatap, int level, long *execsz, int setid, - caddr_t exec_file, cred_t *cred, int *brand_action) -{ - auxv32_t auxflags_auxv32; - int error; - struct exdata edp, edpout; - struct execenv exenv; - proc_t *pp = ttoproc(curthread); - struct vnode *nvp; - int pagetext, pagedata; - int dataprot = PROT_ALL; - int textprot = PROT_ALL & ~PROT_WRITE; - int isdyn; - - - args->to_model = DATAMODEL_ILP32; - *execsz = btopr(SINCR) + btopr(SSIZE) + btopr(NCARGS32-1); - - /* - * Read in and validate the file header. - */ - if (error = get_aout_head(&vp, &edp, execsz, &isdyn)) - return (error); - - if (error = chkaout(&edp)) - return (error); - - /* - * Take a quick look to see if it looks like we will have - * enough swap space for the program to get started. This - * is not a guarantee that we will succeed, but it is definitely - * better than finding this out after we are committed to the - * new memory image. Maybe what is needed is a way to "prereserve" - * swap space for some segment mappings here. - * - * But with shared libraries the process can make it through - * the exec only to have ld.so fail to get the program going - * because its mmap's will not be able to succeed if the system - * is running low on swap space. In fact this is a far more - * common failure mode, but we cannot do much about this here - * other than add some slop to our anonymous memory resources - * requirements estimate based on some guess since we cannot know - * what else the program will really need to get to a useful state. - * - * XXX - The stack size (clrnd(SSIZE + btopr(nargc))) should also - * be used when checking for swap space. This requires some work - * since nargc is actually determined in exec_args() which is done - * after this check and hence we punt for now. - * - * nargc = SA(nc + (na + 4) * NBPW) + sizeof (struct rwindow); - */ - if (CURRENT_TOTAL_AVAILABLE_SWAP < btopr(edp.ux_dsize) + btopr(SSIZE)) - return (ENOMEM); - - /* - * Load the trap 0 interpreter. - */ - if (error = lookupname("/usr/4lib/sbcp", UIO_SYSSPACE, FOLLOW, - NULLVPP, &nvp)) { - goto done; - } - if (error = elf32exec(nvp, uap, args, idatap, level, execsz, - setid, exec_file, cred, brand_action)) { - VN_RELE(nvp); - return (error); - } - VN_RELE(nvp); - - /* - * Determine the a.out's characteristics. - */ - getexinfo(&edp, &edpout, &pagetext, &pagedata); - - /* - * Load the a.out's text and data. - */ - if (error = execmap(edp.vp, edp.ux_txtorg, edp.ux_tsize, - (size_t)0, edp.ux_toffset, textprot, pagetext, 0)) - goto done; - if (error = execmap(edp.vp, edp.ux_datorg, edp.ux_dsize, - edp.ux_bsize, edp.ux_doffset, dataprot, pagedata, 0)) - goto done; - - exenv.ex_bssbase = (caddr_t)edp.ux_datorg; - exenv.ex_brkbase = (caddr_t)edp.ux_datorg; - exenv.ex_brksize = edp.ux_dsize + edp.ux_bsize; - exenv.ex_magic = edp.ux_mag; - exenv.ex_vp = edp.vp; - setexecenv(&exenv); - - /* - * It's time to manipulate the process aux vectors. - * We need to update the AT_SUN_AUXFLAGS aux vector to set - * the AF_SUN_NOPLM flag. - */ - if (copyin(args->auxp_auxflags, &auxflags_auxv32, - sizeof (auxflags_auxv32)) != 0) - return (EFAULT); - - ASSERT(auxflags_auxv32.a_type == AT_SUN_AUXFLAGS); - auxflags_auxv32.a_un.a_val |= AF_SUN_NOPLM; - if (copyout(&auxflags_auxv32, args->auxp_auxflags, - sizeof (auxflags_auxv32)) != 0) - return (EFAULT); - -done: - if (error != 0) - psignal(pp, SIGKILL); - else { - /* - * Ensure that the max fds do not exceed 256 (this is - * applicable to 4.x binaries, which is why we only - * do it on a.out files). - */ - struct rlimit64 fdno_rlim; - rctl_alloc_gp_t *gp = rctl_rlimit_set_prealloc(1); - - mutex_enter(&curproc->p_lock); - (void) rctl_rlimit_get(rctlproc_legacy[RLIMIT_NOFILE], curproc, - &fdno_rlim); - if (fdno_rlim.rlim_cur > 256) { - fdno_rlim.rlim_cur = fdno_rlim.rlim_max = 256; - (void) rctl_rlimit_set(rctlproc_legacy[RLIMIT_NOFILE], - curproc, &fdno_rlim, gp, - rctlproc_flags[RLIMIT_NOFILE], - rctlproc_signals[RLIMIT_NOFILE], CRED()); - } else if (fdno_rlim.rlim_max > 256) { - fdno_rlim.rlim_max = 256; - (void) rctl_rlimit_set(rctlproc_legacy[RLIMIT_NOFILE], - curproc, &fdno_rlim, gp, - rctlproc_flags[RLIMIT_NOFILE], - rctlproc_signals[RLIMIT_NOFILE], CRED()); - } - mutex_exit(&curproc->p_lock); - - rctl_prealloc_destroy(gp); - } - - return (error); -} - -/* - * Read in and validate the file header. - */ -static int -get_aout_head(struct vnode **vpp, struct exdata *edp, long *execsz, int *isdyn) -{ - struct vnode *vp = *vpp; - struct exec filhdr; - int error; - ssize_t resid; - rlim64_t limit; - rlim64_t roundlimit; - - if (error = vn_rdwr(UIO_READ, vp, (caddr_t)&filhdr, - (ssize_t)sizeof (filhdr), (offset_t)0, UIO_SYSSPACE, 0, - (rlim64_t)0, CRED(), &resid)) - return (error); - - if (resid != 0) - return (ENOEXEC); - - switch (filhdr.a_magic) { - case OMAGIC: - filhdr.a_data += filhdr.a_text; - filhdr.a_text = 0; - break; - case ZMAGIC: - case NMAGIC: - break; - default: - return (ENOEXEC); - } - - /* - * Check total memory requirements (in pages) for a new process - * against the available memory or upper limit of memory allowed. - * - * For the 64-bit kernel, the limit can be set large enough so that - * rounding it up to a page can overflow, so we check for btopr() - * overflowing here by comparing it with the unrounded limit in pages. - */ - *execsz += btopr(filhdr.a_text + filhdr.a_data); - limit = btop(curproc->p_vmem_ctl); - roundlimit = btopr(curproc->p_vmem_ctl); - if ((roundlimit > limit && *execsz > roundlimit) || - (roundlimit < limit && *execsz > limit)) { - mutex_enter(&curproc->p_lock); - (void) rctl_action(rctlproc_legacy[RLIMIT_VMEM], - curproc->p_rctls, curproc, RCA_SAFE); - mutex_exit(&curproc->p_lock); - return (ENOMEM); - } - - edp->ux_mach = filhdr.a_machtype; - edp->ux_tsize = filhdr.a_text; - edp->ux_dsize = filhdr.a_data; - edp->ux_bsize = filhdr.a_bss; - edp->ux_mag = filhdr.a_magic; - edp->ux_toffset = gettfile(&filhdr); - edp->ux_doffset = getdfile(&filhdr); - edp->ux_txtorg = gettmem(&filhdr); - edp->ux_datorg = getdmem(&filhdr); - edp->ux_entloc = (caddr_t)(uintptr_t)filhdr.a_entry; - edp->vp = vp; - *isdyn = filhdr.a_dynamic; - - return (0); -} - -static int -aoutcore(vnode_t *vp, proc_t *pp, struct cred *credp, rlim64_t rlimit, int sig, - core_content_t content) -{ - return (elf32core(vp, pp, credp, rlimit, sig, content)); -} diff --git a/usr/src/uts/intel/io/scsi/adapters/pvscsi/THIRDPARTYLICENSE b/usr/src/uts/common/io/scsi/adapters/pvscsi/THIRDPARTYLICENSE index a5904d3673..a5904d3673 100644 --- a/usr/src/uts/intel/io/scsi/adapters/pvscsi/THIRDPARTYLICENSE +++ b/usr/src/uts/common/io/scsi/adapters/pvscsi/THIRDPARTYLICENSE diff --git a/usr/src/uts/intel/io/scsi/adapters/pvscsi/THIRDPARTYLICENSE.descrip b/usr/src/uts/common/io/scsi/adapters/pvscsi/THIRDPARTYLICENSE.descrip index 8f7aabf325..8f7aabf325 100644 --- a/usr/src/uts/intel/io/scsi/adapters/pvscsi/THIRDPARTYLICENSE.descrip +++ b/usr/src/uts/common/io/scsi/adapters/pvscsi/THIRDPARTYLICENSE.descrip diff --git a/usr/src/uts/common/io/scsi/adapters/pvscsi/pvscsi.c b/usr/src/uts/common/io/scsi/adapters/pvscsi/pvscsi.c new file mode 100644 index 0000000000..1b560be437 --- /dev/null +++ b/usr/src/uts/common/io/scsi/adapters/pvscsi/pvscsi.c @@ -0,0 +1,1947 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2016 Nexenta Systems, Inc. + * Copyright 2022 RackTop Systems, Inc. + */ + +#include <sys/atomic.h> +#include <sys/cmn_err.h> +#include <sys/cpuvar.h> +#include <sys/ddi.h> +#include <sys/id32.h> +#include <sys/kmem.h> +#include <sys/list.h> +#include <sys/modctl.h> +#include <sys/pci.h> +#include <sys/scsi/scsi.h> +#include <sys/sunddi.h> +#include <sys/sysmacros.h> +#include <sys/types.h> +#include <sys/note.h> + +#include "pvscsi.h" +#include "pvscsi_var.h" + +/* we can support any of the interrupt types */ +int pvscsi_intr_types = \ + DDI_INTR_TYPE_MSIX|DDI_INTR_TYPE_MSI|DDI_INTR_TYPE_FIXED; +int pvscsi_ring_pages = PVSCSI_DEFAULT_NUM_PAGES_PER_RING; +int pvscsi_msg_ring_pages = PVSCSI_DEFAULT_NUM_PAGES_MSG_RING; +static int pvscsi_hz; + +static int pvscsi_abort(struct scsi_address *, struct scsi_pkt *); +static void pvscsi_timeout(void *); +static void pvscsi_setup_rings(pvscsi_softc_t *); +static void pvscsi_complete_cmds(pvscsi_softc_t *, pvscsi_cmd_t *); +static boolean_t pvscsi_cmd_init(pvscsi_softc_t *, pvscsi_cmd_t *, int); +static void pvscsi_cmd_fini(pvscsi_cmd_t *); + +/* HBA DMA attributes */ +static ddi_dma_attr_t pvscsi_dma_attr = { + .dma_attr_version = DMA_ATTR_V0, + .dma_attr_addr_lo = 0, + .dma_attr_addr_hi = 0xFFFFFFFFFFFFFFFFull, + .dma_attr_count_max = 0xFFFFFFFFFFFFFFFFull, + .dma_attr_align = PAGE_SIZE, + .dma_attr_burstsizes = 1, + .dma_attr_minxfer = 1, + .dma_attr_maxxfer = 0xFFFFFFFFFFFFFFFFull, + .dma_attr_seg = 0xFFFFFFFFFFFFFFFFull, + .dma_attr_sgllen = 1, + .dma_attr_granular = 1, + .dma_attr_flags = 0 +}; + +/* DMA attributes for buffer I/O */ +static ddi_dma_attr_t pvscsi_io_dma_attr = { + .dma_attr_version = DMA_ATTR_V0, + .dma_attr_addr_lo = 0, + .dma_attr_addr_hi = 0xFFFFFFFFFFFFFFFFull, + .dma_attr_count_max = 0x7FFFFFFFll, + .dma_attr_align = 1, + .dma_attr_burstsizes = 1, + .dma_attr_minxfer = 1, + .dma_attr_maxxfer = PAGE_SIZE * PVSCSI_MAX_SG_SIZE, + .dma_attr_seg = 0xFFFFFFFFFFFFFFFFull, + .dma_attr_sgllen = PVSCSI_MAX_SG_SIZE, + .dma_attr_granular = 1, + .dma_attr_flags = 0 +}; + +/* + * The structures are always little endian (VMware only runs + * on little endian CPUs), but we only run on LE processors, + * and NEVERSWAP avoids needing to use DDI accessor functions. + * (It would be incredibly bizarre to have a VMware guest running + * with a different endianness than the hypervisor.) + */ +static ddi_device_acc_attr_t pvscsi_mmio_attr = { + .devacc_attr_version = DDI_DEVICE_ATTR_V1, + .devacc_attr_endian_flags = DDI_NEVERSWAP_ACC, + .devacc_attr_dataorder = DDI_STRICTORDER_ACC, + .devacc_attr_access = DDI_DEFAULT_ACC +}; + +static ddi_device_acc_attr_t pvscsi_dma_attrs = { + .devacc_attr_version = DDI_DEVICE_ATTR_V1, + .devacc_attr_endian_flags = DDI_NEVERSWAP_ACC, + .devacc_attr_dataorder = DDI_STRICTORDER_ACC, + .devacc_attr_access = DDI_DEFAULT_ACC, +}; + +static void +pvscsi_add_to_queue(pvscsi_softc_t *pvs, pvscsi_cmd_t *cmd) +{ + pvscsi_cmd_t *r; + list_t *l; + + /* + * We insert in order of expiration, with the earliest + * expirations at the front. This logic assumes that most + * commands will have the same timeout, and is optimized + * to minimize walking the list. It allows timeouts to + * run without looking at more than one node that has not + * yet expired. + */ + ASSERT(mutex_owned(&pvs->lock)); + + l = &pvs->cmd_queue; + for (r = list_tail(l); r != NULL; r = list_prev(l, r)) { + /* this subtraction is safe if lbolt wraps */ + if (((cmd->start + cmd->timeout) - + (r->start + r->timeout)) >= 0) { + list_insert_after(l, r, cmd); + return; + } + } + + list_insert_head(l, cmd); +} + +static uint32_t +pvscsi_reg_read(pvscsi_softc_t *pvs, uint32_t offset) +{ + uint32_t ret; + + ASSERT((offset & (sizeof (uint32_t) - 1)) == 0); + + ret = ddi_get32(pvs->mmio_handle, + (uint32_t *)(pvs->mmio_base + offset)); + + return (ret); +} + +static void +pvscsi_reg_write(pvscsi_softc_t *pvs, uint32_t offset, uint32_t value) +{ + ASSERT((offset & (sizeof (uint32_t) - 1)) == 0); + + ddi_put32(pvs->mmio_handle, (uint32_t *)(pvs->mmio_base + offset), + value); +} + +static void +pvscsi_write_cmd_desc(pvscsi_softc_t *pvs, uint32_t cmd, void *desc, size_t len) +{ + len /= sizeof (uint32_t); + pvscsi_reg_write(pvs, PVSCSI_REG_OFFSET_COMMAND, cmd); + ddi_rep_put32(pvs->mmio_handle, (uint32_t *)desc, + (uint32_t *)(pvs->mmio_base + PVSCSI_REG_OFFSET_COMMAND_DATA), + len, DDI_DEV_NO_AUTOINCR); +} + +static uint32_t +pvscsi_read_intr_status(pvscsi_softc_t *pvs) +{ + return (pvscsi_reg_read(pvs, PVSCSI_REG_OFFSET_INTR_STATUS)); +} + +static void +pvscsi_write_intr_status(pvscsi_softc_t *pvs, uint32_t val) +{ + pvscsi_reg_write(pvs, PVSCSI_REG_OFFSET_INTR_STATUS, val); +} + +static pvscsi_cmd_t * +pvscsi_reclaim_cmds(pvscsi_softc_t *pvs) +{ + pvscsi_cmd_t *head = NULL; + pvscsi_cmd_t **tail = &head; + pvscsi_cmd_t *cmd; + + ASSERT(mutex_owned(&pvs->lock)); + while ((cmd = list_remove_head(&pvs->cmd_queue)) != NULL) { + list_remove(&pvs->cmd_queue, cmd); + *tail = cmd; + tail = &cmd->next_cmd; + *tail = NULL; + cmd->host_status = BTSTAT_BUSRESET; + } + return (head); +} + +static void +pvscsi_stop_hba(pvscsi_softc_t *pvs) +{ + pvscsi_write_cmd_desc(pvs, PVSCSI_CMD_ADAPTER_RESET, NULL, 0); + pvscsi_reg_write(pvs, PVSCSI_REG_OFFSET_INTR_MASK, 0); + /* read interrupt status to flush PCI write buffers */ + (void) pvscsi_read_intr_status(pvs); +} + +static void +pvscsi_start_hba(pvscsi_softc_t *pvs) +{ + pvscsi_setup_rings(pvs); + pvscsi_reg_write(pvs, PVSCSI_REG_OFFSET_INTR_MASK, + PVSCSI_INTR_CMPL_MASK | PVSCSI_INTR_MSG_MASK); +} + +static void +pvscsi_reset_bus(pvscsi_softc_t *pvs) +{ + pvscsi_write_cmd_desc(pvs, PVSCSI_CMD_RESET_BUS, NULL, 0); +} + +/* + * pvscsi_restart_hba resets the HBA, and reconfigures it. It also + * completes all commands that have not been already completed with + * a reset. + */ +static void +pvscsi_restart_hba(pvscsi_softc_t *pvs) +{ + pvscsi_cmd_t *cmd; + + mutex_enter(&pvs->lock); + pvscsi_stop_hba(pvs); + cmd = pvscsi_reclaim_cmds(pvs); + pvscsi_start_hba(pvs); + mutex_exit(&pvs->lock); + + /* run the completions from the reclaimed commands */ + pvscsi_complete_cmds(pvs, cmd); +} + +static void +pvscsi_submit_nonrw_io(pvscsi_softc_t *pvs) +{ + pvscsi_reg_write(pvs, PVSCSI_REG_OFFSET_KICK_NON_RW_IO, 0); +} + +static void +pvscsi_submit_rw_io(pvscsi_softc_t *pvs) +{ + pvscsi_reg_write(pvs, PVSCSI_REG_OFFSET_KICK_RW_IO, 0); +} + +static pvscsi_cmd_t * +pvscsi_process_comp_ring(pvscsi_softc_t *pvs) +{ + pvscsi_cmd_t **pnext_cmd; + pvscsi_cmd_t *cmd; + pvscsi_cmd_t *head = NULL; + struct PVSCSIRingsState *sdesc = RINGS_STATE(pvs); + uint32_t cmp_ne = sdesc->cmpNumEntriesLog2; + + ASSERT(mutex_owned(&pvs->lock)); + + pnext_cmd = &head; + + (void) ddi_dma_sync(pvs->state_buf.dmah, 0, 0, DDI_DMA_SYNC_FORKERNEL); + + while (sdesc->cmpConsIdx != sdesc->cmpProdIdx) { + struct PVSCSIRingCmpDesc *cdesc; + + (void) ddi_dma_sync(pvs->cmp_ring_buf.dmah, 0, 0, + DDI_DMA_SYNC_FORKERNEL); + + cdesc = CMP_RING(pvs) + (sdesc->cmpConsIdx & MASK(cmp_ne)); + + if ((cmd = id32_lookup((uint32_t)cdesc->context)) != NULL) { + cmd->next_cmd = NULL; + + /* Save command status for further processing */ + cmd->host_status = cdesc->hostStatus; + cmd->scsi_status = cdesc->scsiStatus; + cmd->transferred = cdesc->dataLen; + + *pnext_cmd = cmd; + pnext_cmd = &cmd->next_cmd; + + list_remove(&pvs->cmd_queue, cmd); + } + + sdesc->cmpConsIdx++; + } + (void) ddi_dma_sync(pvs->state_buf.dmah, 0, 0, DDI_DMA_SYNC_FORDEV); + + return (head); +} + +static pvscsi_msg_t * +pvscsi_process_msg_ring(pvscsi_softc_t *pvs) +{ + pvscsi_msg_t *msg; + struct PVSCSIRingsState *sdesc = RINGS_STATE(pvs); + struct PVSCSIRingMsgDesc *mdesc; + struct PVSCSIMsgDescDevStatusChanged *desc; + uint32_t msg_ne = sdesc->msgNumEntriesLog2; + + (void) ddi_dma_sync(pvs->state_buf.dmah, 0, 0, DDI_DMA_SYNC_FORKERNEL); + + if (sdesc->msgProdIdx == sdesc->msgConsIdx) { + return (NULL); + } + + (void) ddi_dma_sync(pvs->msg_ring_buf.dmah, 0, 0, + DDI_DMA_SYNC_FORKERNEL); + + mdesc = MSG_RING(pvs) + (sdesc->msgConsIdx & MASK(msg_ne)); + + switch (mdesc->type) { + case PVSCSI_MSG_DEV_ADDED: + case PVSCSI_MSG_DEV_REMOVED: + desc = (struct PVSCSIMsgDescDevStatusChanged *)mdesc; + msg = kmem_alloc(sizeof (pvscsi_msg_t), KM_NOSLEEP); + if (msg == NULL) + return (NULL); + msg->pvs = pvs; + msg->type = mdesc->type; + msg->target = desc->target; + msg->lun = desc->lun[1]; /* T10 format */ + break; + default: + dev_err(pvs->dip, CE_WARN, "!unknown msg type: %d", + mdesc->type); + return (NULL); + } + + sdesc->msgConsIdx++; + (void) ddi_dma_sync(pvs->state_buf.dmah, 0, 0, DDI_DMA_SYNC_FORDEV); + return (msg); +} + +static void +pvscsi_handle_msg(void *arg) +{ + pvscsi_msg_t *msg = arg; + pvscsi_softc_t *pvs = msg->pvs; + char addr[8]; + + (void) snprintf(addr, sizeof (addr), "%x", msg->target); + + if (msg->lun == 0) { + switch (msg->type) { + case PVSCSI_MSG_DEV_ADDED: + (void) scsi_hba_tgtmap_tgt_add(pvs->tgtmap, + SCSI_TGT_SCSI_DEVICE, addr, NULL); + break; + case PVSCSI_MSG_DEV_REMOVED: + (void) scsi_hba_tgtmap_tgt_remove(pvs->tgtmap, + SCSI_TGT_SCSI_DEVICE, addr); + break; + } + } else { + scsi_hba_tgtmap_scan_luns(pvs->tgtmap, addr); + } + kmem_free(msg, sizeof (pvscsi_msg_t)); +} + +static void +pvscsi_abort_cmd(pvscsi_softc_t *pvs, pvscsi_cmd_t *cmd) +{ + struct PVSCSICmdDescAbortCmd acmd; + + bzero(&acmd, sizeof (acmd)); + acmd.target = cmd->target; + acmd.context = cmd->ctx; + pvscsi_write_cmd_desc(pvs, PVSCSI_CMD_ABORT_CMD, &acmd, sizeof (acmd)); +} + +static void +pvscsi_map_buffers(pvscsi_cmd_t *cmd, struct PVSCSIRingReqDesc *rdesc) +{ + struct scsi_pkt *pkt = cmd->pkt; + + rdesc->dataLen = 0; + rdesc->dataAddr = 0; + if (pkt == NULL || pkt->pkt_numcookies == 0) { + return; + } + + pkt->pkt_resid = 0; + + if (pkt->pkt_numcookies > 1) { + size_t len = 0; + struct PVSCSISGElement *sgl = cmd->sgl; + + for (uint_t i = 0; i < pkt->pkt_numcookies; i++) { + sgl[i].addr = pkt->pkt_cookies[i].dmac_laddress; + sgl[i].length = pkt->pkt_cookies[i].dmac_size; + sgl[i].flags = 0; + len += pkt->pkt_cookies[i].dmac_size; + } + rdesc->flags |= PVSCSI_FLAG_CMD_WITH_SG_LIST; + rdesc->dataAddr = cmd->sgl_pa; + rdesc->dataLen = len; + (void) ddi_dma_sync(cmd->sgl_dmah, 0, 0, DDI_DMA_SYNC_FORDEV); + } else { + rdesc->flags = 0; + rdesc->dataAddr = pkt->pkt_cookies[0].dmac_laddress; + rdesc->dataLen = pkt->pkt_cookies[0].dmac_size; + } + pkt->pkt_resid = rdesc->dataLen; +} + +static void +pvscsi_comp_cmd(pvscsi_cmd_t *cmd) +{ + struct scsi_pkt *pkt = cmd->pkt; + uint8_t status = cmd->scsi_status; + + pkt->pkt_state |= (STATE_GOT_BUS | STATE_GOT_TARGET | STATE_SENT_CMD | + STATE_GOT_STATUS); + if (pkt->pkt_numcookies > 0) { + pkt->pkt_state |= STATE_XFERRED_DATA; + } + pkt->pkt_reason = CMD_CMPLT; + pkt->pkt_resid -= cmd->transferred; + *(pkt->pkt_scbp) = status; + + if (status == STATUS_CHECK) { + /* + * Our virtual HBA *always* does ARQ, and it never + * is more than 20 bytes, so no need to try to handle + * extended versions of it. + */ + struct scsi_arq_status *ars = (void *)(pkt->pkt_scbp); + int len = min(pkt->pkt_scblen, SENSE_LENGTH); + + pkt->pkt_state |= STATE_ARQ_DONE; + ars->sts_rqpkt_resid = 0; + bcopy(cmd->arq_sense, &ars->sts_sensedata, len); + ars->sts_rqpkt_reason = CMD_CMPLT; + *(uint8_t *)&ars->sts_rqpkt_status = STATUS_GOOD; + ars->sts_rqpkt_state = STATE_GOT_BUS | + STATE_GOT_TARGET | STATE_SENT_CMD | + STATE_XFERRED_DATA | STATE_GOT_STATUS; + } +} + +static void +pvscsi_set_status(pvscsi_softc_t *pvs, pvscsi_cmd_t *cmd) +{ + struct scsi_pkt *pkt = cmd->pkt; + uint32_t host_status = cmd->host_status; + + switch (host_status) { + case BTSTAT_SUCCESS: + case BTSTAT_LINKED_COMMAND_COMPLETED: + case BTSTAT_LINKED_COMMAND_COMPLETED_WITH_FLAG: + pvscsi_comp_cmd(cmd); + break; + case BTSTAT_DATARUN: + pkt->pkt_reason = CMD_DATA_OVR; + pkt->pkt_state |= (STATE_GOT_BUS | STATE_GOT_TARGET | + STATE_SENT_CMD | STATE_GOT_STATUS | + STATE_XFERRED_DATA); + pkt->pkt_resid -= cmd->transferred; + break; + case BTSTAT_SELTIMEO: + pkt->pkt_reason = CMD_DEV_GONE; + pkt->pkt_state |= STATE_GOT_BUS; + break; + case BTSTAT_TAGREJECT: + pkt->pkt_reason = CMD_TAG_REJECT; + pkt->pkt_state |= (STATE_GOT_BUS | STATE_GOT_TARGET | + STATE_SENT_CMD | STATE_GOT_STATUS); + break; + case BTSTAT_BADMSG: + pkt->pkt_reason = CMD_BADMSG; + pkt->pkt_state |= (STATE_GOT_BUS | STATE_GOT_TARGET | + STATE_SENT_CMD | STATE_GOT_STATUS); + break; + case BTSTAT_SENTRST: + case BTSTAT_RECVRST: + pkt->pkt_reason = CMD_RESET; + pkt->pkt_state |= (STATE_GOT_BUS | STATE_GOT_TARGET | + STATE_SENT_CMD | STATE_GOT_STATUS); + pkt->pkt_statistics |= STAT_DEV_RESET; + pkt->pkt_resid -= cmd->transferred; + break; + case BTSTAT_BUSRESET: + pkt->pkt_reason = CMD_RESET; + pkt->pkt_state |= (STATE_GOT_BUS | STATE_GOT_TARGET | + STATE_SENT_CMD | STATE_GOT_STATUS); + pkt->pkt_statistics |= STAT_BUS_RESET; + pkt->pkt_resid -= cmd->transferred; + break; + case BTSTAT_ABORTQUEUE: + if (cmd->expired) { + pkt->pkt_reason = CMD_TIMEOUT; + pkt->pkt_statistics |= STAT_TIMEOUT; + } else { + pkt->pkt_reason = CMD_ABORTED; + pkt->pkt_statistics |= STAT_ABORTED; + } + pkt->pkt_state |= (STATE_GOT_BUS | STATE_GOT_TARGET | + STATE_SENT_CMD | STATE_GOT_STATUS); + pkt->pkt_resid -= cmd->transferred; + break; + case BTSTAT_HAHARDWARE: + case BTSTAT_INVPHASE: + case BTSTAT_HATIMEOUT: + case BTSTAT_NORESPONSE: + case BTSTAT_DISCONNECT: + case BTSTAT_HASOFTWARE: + case BTSTAT_BUSFREE: + case BTSTAT_SENSFAILED: + case BTSTAT_DATA_UNDERRUN: + pkt->pkt_reason = CMD_TRAN_ERR; + pkt->pkt_state |= (STATE_GOT_BUS | STATE_GOT_TARGET | + STATE_SENT_CMD | STATE_GOT_STATUS); + pkt->pkt_resid -= cmd->transferred; + break; + default: + dev_err(pvs->dip, CE_WARN, + "!unknown host status code: %d", host_status); + pkt->pkt_reason = CMD_TRAN_ERR; + pkt->pkt_state |= (STATE_GOT_BUS | STATE_GOT_TARGET | + STATE_SENT_CMD | STATE_GOT_STATUS); + break; + } +} + +/* + * pvscsi_complete_cmds processes a linked list of + * commands that have been completed. This is done + * without acquiring any locks. + */ +static void +pvscsi_complete_cmds(pvscsi_softc_t *pvs, pvscsi_cmd_t *cmd) +{ + struct scsi_pkt *pkt; + + while (cmd != NULL) { + pvscsi_cmd_t *next = cmd->next_cmd; + + cmd->next_cmd = NULL; + + if (((pkt = cmd->pkt) == NULL) || (cmd->poll)) { + atomic_or_8(&cmd->done, 1); + } else { + pvscsi_set_status(pvs, cmd); + scsi_hba_pkt_comp(pkt); + } + + cmd = next; + } +} + +static void +pvscsi_dev_reset(pvscsi_softc_t *pvs, int target, int lun) +{ + struct PVSCSICmdDescResetDevice cmd = { 0 }; + + cmd.target = target; + cmd.lun[1] = lun & 0xff; + pvscsi_write_cmd_desc(pvs, PVSCSI_CMD_RESET_DEVICE, &cmd, sizeof (cmd)); +} + +static boolean_t +pvscsi_poll_cmd_until(pvscsi_softc_t *pvs, pvscsi_cmd_t *cmd, clock_t usec) +{ + while (usec > 0) { + pvscsi_cmd_t *done; + if (cmd->done) { + return (B_TRUE); + } + mutex_enter(&pvs->lock); + done = pvscsi_process_comp_ring(pvs); + mutex_exit(&pvs->lock); + + pvscsi_complete_cmds(pvs, done); + drv_usecwait(10); + usec -= 10; + } + + return (B_FALSE); +} + +static void +pvscsi_poll_cmd(pvscsi_softc_t *pvs, pvscsi_cmd_t *cmd) +{ + if (pvscsi_poll_cmd_until(pvs, cmd, drv_hztousec(cmd->timeout))) { + return; + } + + /* now we try an abort first */ + pvscsi_abort_cmd(pvs, cmd); + if (pvscsi_poll_cmd_until(pvs, cmd, 2)) { + return; + } + /* well that failed... try reset */ + pvscsi_dev_reset(pvs, cmd->target, cmd->lun); + if (pvscsi_poll_cmd_until(pvs, cmd, 2)) { + return; + } + /* still trying... reset the bus */ + pvscsi_reset_bus(pvs); + if (pvscsi_poll_cmd_until(pvs, cmd, 2)) { + return; + } + /* full up adapter reset -- be brutal */ + pvscsi_restart_hba(pvs); +} + +static void +pvscsi_abort_all(pvscsi_softc_t *pvs, pvscsi_device_t *pd) +{ + pvscsi_cmd_t *cmd; + + mutex_enter(&pvs->lock); + list_t *l = &pvs->cmd_queue; + for (cmd = list_head(l); cmd != NULL; cmd = list_next(l, cmd)) { + if ((pd->target == cmd->target) && (pd->lun == cmd->lun)) { + pvscsi_abort_cmd(pvs, cmd); + } + } + mutex_exit(&pvs->lock); +} + +static int +pvscsi_transport_command(pvscsi_softc_t *pvs, pvscsi_cmd_t *cmd) +{ + struct PVSCSIRingReqDesc *rdesc; + struct PVSCSIRingsState *sdesc = RINGS_STATE(pvs); + uint32_t req_ne = sdesc->reqNumEntriesLog2; + + cmd->done = 0; + cmd->expired = 0; + + mutex_enter(&pvs->lock); + + if ((sdesc->reqProdIdx - sdesc->cmpConsIdx) >= (1 << req_ne)) { + mutex_exit(&pvs->lock); + return (TRAN_BUSY); + } + + rdesc = REQ_RING(pvs) + (sdesc->reqProdIdx & MASK(req_ne)); + + rdesc->bus = 0; + rdesc->target = cmd->target; + bzero(rdesc->lun, sizeof (rdesc->lun)); + /* Matches other implementations; can pvscsi support luns > 255? */ + rdesc->lun[1] = cmd->lun & 0xff; + + bzero(cmd->arq_sense, sizeof (cmd->arq_sense)); + rdesc->context = cmd->ctx; + rdesc->senseLen = sizeof (cmd->arq_sense); + rdesc->senseAddr = cmd->arq_pa; + rdesc->tag = cmd->tag; + rdesc->vcpuHint = CPU->cpu_id; + rdesc->cdbLen = cmd->cdblen; + rdesc->flags = cmd->dma_dir; + bcopy(cmd->cdb, rdesc->cdb, cmd->cdblen); + pvscsi_map_buffers(cmd, rdesc); + + (void) ddi_dma_sync(pvs->req_ring_buf.dmah, 0, 0, DDI_DMA_SYNC_FORDEV); + + sdesc->reqProdIdx++; + (void) ddi_dma_sync(pvs->state_buf.dmah, 0, 0, DDI_DMA_SYNC_FORDEV); + + pvscsi_add_to_queue(pvs, cmd); + + switch (cmd->cdb[0]) { + case SCMD_READ: + case SCMD_WRITE: + case SCMD_READ_G1: + case SCMD_WRITE_G1: + case SCMD_READ_G4: + case SCMD_WRITE_G4: + case SCMD_READ_G5: + case SCMD_WRITE_G5: + pvscsi_submit_rw_io(pvs); + break; + default: + pvscsi_submit_nonrw_io(pvs); + break; + } + + if (pvs->timeout == 0) { + /* drivers above should supply, but give a default */ + pvs->timeout = timeout(pvscsi_timeout, pvs, pvscsi_hz * 8); + } + mutex_exit(&pvs->lock); + + return (TRAN_ACCEPT); +} + +static int +pvscsi_setup_dma_buffer(pvscsi_softc_t *pvs, size_t length, + pvscsi_dma_buf_t *buf) +{ + if ((ddi_dma_alloc_handle(pvs->dip, &pvscsi_dma_attr, + DDI_DMA_SLEEP, NULL, &buf->dmah)) != DDI_SUCCESS) { + dev_err(pvs->dip, CE_WARN, "!failed to alloc DMA handle"); + return (DDI_FAILURE); + } + + if ((ddi_dma_mem_alloc(buf->dmah, length, &pvscsi_dma_attrs, + DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, &buf->addr, + &length, &buf->acch)) != DDI_SUCCESS) { + dev_err(pvs->dip, CE_WARN, "!failed to alloc DMA memory"); + return (DDI_FAILURE); + } + + if ((ddi_dma_addr_bind_handle(buf->dmah, NULL, buf->addr, + length, DDI_DMA_CONSISTENT | DDI_DMA_RDWR, DDI_DMA_SLEEP, + NULL, NULL, NULL)) != DDI_SUCCESS) { + dev_err(pvs->dip, CE_WARN, "!failed to bind DMA buffer"); + return (DDI_FAILURE); + } + + buf->pa = ddi_dma_cookie_one(buf->dmah)->dmac_laddress; + + return (DDI_SUCCESS); +} + +static void +pvscsi_free_dma_buffer(pvscsi_dma_buf_t *buf) +{ + if (buf->pa != 0) { + (void) ddi_dma_unbind_handle(buf->dmah); + } + if (buf->acch != NULL) { + ddi_dma_mem_free(&buf->acch); + } + if (buf->dmah != NULL) { + ddi_dma_free_handle(&buf->dmah); + } +} + +static int +pvscsi_allocate_rings(pvscsi_softc_t *pvs) +{ + /* allocate DMA buffer for rings state */ + if (pvscsi_setup_dma_buffer(pvs, PAGE_SIZE, &pvs->state_buf) != + DDI_SUCCESS) { + return (DDI_FAILURE); + } + + /* allocate DMA buffer for request ring */ + pvs->req_pages = MIN(pvscsi_ring_pages, PVSCSI_MAX_NUM_PAGES_REQ_RING); + pvs->req_depth = pvs->req_pages * PVSCSI_MAX_NUM_REQ_ENTRIES_PER_PAGE; + if (pvscsi_setup_dma_buffer(pvs, pvs->req_pages * PAGE_SIZE, + &pvs->req_ring_buf) != DDI_SUCCESS) { + return (DDI_FAILURE); + } + + /* allocate completion ring */ + pvs->cmp_pages = MIN(pvscsi_ring_pages, PVSCSI_MAX_NUM_PAGES_CMP_RING); + if (pvscsi_setup_dma_buffer(pvs, pvs->cmp_pages * PAGE_SIZE, + &pvs->cmp_ring_buf) != DDI_SUCCESS) { + return (DDI_FAILURE); + } + + /* allocate message ring */ + pvs->msg_pages = MIN(pvscsi_msg_ring_pages, + PVSCSI_MAX_NUM_PAGES_MSG_RING); + if (pvscsi_setup_dma_buffer(pvs, pvs->msg_pages * PAGE_SIZE, + &pvs->msg_ring_buf) != DDI_SUCCESS) { + return (DDI_FAILURE); + } + + return (DDI_SUCCESS); +} + +static void +pvscsi_free_rings(pvscsi_softc_t *pvs) +{ + pvscsi_free_dma_buffer(&pvs->msg_ring_buf); + pvscsi_free_dma_buffer(&pvs->cmp_ring_buf); + pvscsi_free_dma_buffer(&pvs->req_ring_buf); + pvscsi_free_dma_buffer(&pvs->state_buf); +} + +static void +pvscsi_setup_rings(pvscsi_softc_t *pvs) +{ + int i; + struct PVSCSICmdDescSetupMsgRing cmd_msg = { 0 }; + struct PVSCSICmdDescSetupRings cmd = { 0 }; + uint64_t base; + + cmd.ringsStatePPN = pvs->state_buf.pa >> PAGE_SHIFT; + cmd.reqRingNumPages = pvs->req_pages; + cmd.cmpRingNumPages = pvs->cmp_pages; + + /* Setup request ring */ + base = pvs->req_ring_buf.pa; + for (i = 0; i < pvs->req_pages; i++) { + cmd.reqRingPPNs[i] = base >> PAGE_SHIFT; + base += PAGE_SIZE; + } + + /* Setup completion ring */ + base = pvs->cmp_ring_buf.pa; + for (i = 0; i < pvs->cmp_pages; i++) { + cmd.cmpRingPPNs[i] = base >> PAGE_SHIFT; + base += PAGE_SIZE; + } + + bzero(RINGS_STATE(pvs), PAGE_SIZE); + bzero(REQ_RING(pvs), pvs->req_pages * PAGE_SIZE); + bzero(CMP_RING(pvs), pvs->cmp_pages * PAGE_SIZE); + + /* Issue SETUP command */ + pvscsi_write_cmd_desc(pvs, PVSCSI_CMD_SETUP_RINGS, &cmd, sizeof (cmd)); + + /* Setup message ring */ + cmd_msg.numPages = pvs->msg_pages; + base = pvs->msg_ring_buf.pa; + + for (i = 0; i < pvs->msg_pages; i++) { + cmd_msg.ringPPNs[i] = base >> PAGE_SHIFT; + base += PAGE_SIZE; + } + bzero(MSG_RING(pvs), pvs->msg_pages * PAGE_SIZE); + + pvscsi_write_cmd_desc(pvs, PVSCSI_CMD_SETUP_MSG_RING, &cmd_msg, + sizeof (cmd_msg)); +} + +static int +pvscsi_setup_io(pvscsi_softc_t *pvs) +{ + int offset, rcount, rn, type; + int ret = DDI_FAILURE; + off_t regsize; + pci_regspec_t *regs; + uint_t regs_length; + + if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, pvs->dip, + DDI_PROP_DONTPASS, "reg", (int **)®s, + ®s_length) != DDI_PROP_SUCCESS) { + dev_err(pvs->dip, CE_WARN, "!failed to lookup 'reg' property"); + return (DDI_FAILURE); + } + + rcount = regs_length * sizeof (int) / sizeof (pci_regspec_t); + + for (offset = PCI_CONF_BASE0; offset <= PCI_CONF_BASE5; offset += 4) { + for (rn = 0; rn < rcount; ++rn) { + if (PCI_REG_REG_G(regs[rn].pci_phys_hi) == offset) { + type = regs[rn].pci_phys_hi & PCI_ADDR_MASK; + break; + } + } + + if (rn >= rcount) + continue; + + if (type != PCI_ADDR_IO) { + if (ddi_dev_regsize(pvs->dip, rn, + ®size) != DDI_SUCCESS) { + dev_err(pvs->dip, CE_WARN, + "!failed to get size of reg %d", rn); + goto out; + } + if (regsize == PVSCSI_MEM_SPACE_SIZE) { + if (ddi_regs_map_setup(pvs->dip, rn, + &pvs->mmio_base, 0, 0, + &pvscsi_mmio_attr, + &pvs->mmio_handle) != DDI_SUCCESS) { + dev_err(pvs->dip, CE_WARN, + "!failed to map MMIO BAR"); + goto out; + } + ret = DDI_SUCCESS; + break; + } + } + } + +out: + ddi_prop_free(regs); + + return (ret); +} + +static int +pvscsi_enable_intrs(pvscsi_softc_t *pvs) +{ + int i, rc, intr_caps; + + if ((rc = ddi_intr_get_cap(pvs->intr_handles[0], &intr_caps)) != + DDI_SUCCESS) { + dev_err(pvs->dip, CE_WARN, "!failed to get interrupt caps"); + return (DDI_FAILURE); + } + + if ((intr_caps & DDI_INTR_FLAG_BLOCK) != 0) { + if ((rc = ddi_intr_block_enable(pvs->intr_handles, + pvs->intr_cnt)) != DDI_SUCCESS) { + dev_err(pvs->dip, CE_WARN, + "!failed to enable interrupt block"); + } + } else { + for (i = 0; i < pvs->intr_cnt; i++) { + if ((rc = ddi_intr_enable(pvs->intr_handles[i])) == + DDI_SUCCESS) + continue; + dev_err(pvs->dip, CE_WARN, + "!failed to enable interrupt"); + while (--i >= 0) + (void) ddi_intr_disable(pvs->intr_handles[i]); + break; + } + } + + return (rc); +} + +static uint32_t +pvscsi_intr(caddr_t arg1, caddr_t arg2) +{ + pvscsi_softc_t *pvs = (pvscsi_softc_t *)arg1; + uint32_t status; + pvscsi_cmd_t *cmd; + pvscsi_msg_t *msg; + uint32_t rv = DDI_INTR_CLAIMED; + _NOTE(ARGUNUSED(arg2)); + + mutex_enter(&pvs->lock); + status = pvscsi_read_intr_status(pvs); + if ((status & PVSCSI_INTR_ALL_SUPPORTED) != 0) { + pvscsi_write_intr_status(pvs, status); + } else if (pvs->intr_type == DDI_INTR_TYPE_FIXED) { + rv = DDI_INTR_UNCLAIMED; + } + if (pvs->detach) { + mutex_exit(&pvs->lock); + return (rv); + } + cmd = pvscsi_process_comp_ring(pvs); + msg = pvscsi_process_msg_ring(pvs); + + /* + * Do this under the lock, so that we won't dispatch + * if we are detaching + */ + if (msg != NULL) { + if (ddi_taskq_dispatch(pvs->tq, pvscsi_handle_msg, msg, + DDI_NOSLEEP) != DDI_SUCCESS) { + dev_err(pvs->dip, CE_WARN, + "!failed to dispatch discovery"); + } + } + mutex_exit(&pvs->lock); + + pvscsi_complete_cmds(pvs, cmd); + + return (rv); +} + +static void +pvscsi_free_intrs(pvscsi_softc_t *pvs) +{ + for (int i = 0; i < pvs->intr_cnt; i++) { + (void) ddi_intr_disable(pvs->intr_handles[i]); + (void) ddi_intr_remove_handler(pvs->intr_handles[i]); + (void) ddi_intr_free(pvs->intr_handles[i]); + } + pvs->intr_cnt = 0; +} + +static int +pvscsi_register_isr(pvscsi_softc_t *pvs, int type) +{ + int navail, nactual; + int i; + + if (ddi_intr_get_navail(pvs->dip, type, &navail) != DDI_SUCCESS || + navail == 0) { + dev_err(pvs->dip, CE_WARN, + "!failed to get number of available interrupts of type %d", + type); + return (DDI_FAILURE); + } + navail = MIN(navail, PVSCSI_MAX_INTRS); + + if (ddi_intr_alloc(pvs->dip, pvs->intr_handles, type, 0, navail, + &nactual, DDI_INTR_ALLOC_NORMAL) != DDI_SUCCESS || nactual == 0) { + dev_err(pvs->dip, CE_WARN, "!failed to allocate %d interrupts", + navail); + return (DDI_FAILURE); + } + + pvs->intr_cnt = nactual; + + if (ddi_intr_get_pri(pvs->intr_handles[0], (uint_t *)&pvs->intr_pri) != + DDI_SUCCESS) { + dev_err(pvs->dip, CE_WARN, "!failed to get interrupt priority"); + pvscsi_free_intrs(pvs); + return (DDI_FAILURE); + } + + for (i = 0; i < nactual; i++) { + if (ddi_intr_add_handler(pvs->intr_handles[i], pvscsi_intr, + (caddr_t)pvs, NULL) != DDI_SUCCESS) { + dev_err(pvs->dip, CE_WARN, + "!failed to add intr handler"); + pvscsi_free_intrs(pvs); + return (DDI_FAILURE); + } + } + + pvs->intr_type = type; + return (DDI_SUCCESS); +} + +static int +pvscsi_setup_isr(pvscsi_softc_t *pvs) +{ + int types; + + if (ddi_intr_get_supported_types(pvs->dip, &types) != DDI_SUCCESS) { + dev_err(pvs->dip, CE_WARN, "!failed to get interrupt types"); + return (DDI_FAILURE); + } + + types &= pvscsi_intr_types; + if (types == 0) { + dev_err(pvs->dip, CE_WARN, "!no supported interrupt types"); + return (DDI_FAILURE); + } + + + if (((types & DDI_INTR_TYPE_MSIX) != 0) && + (pvscsi_register_isr(pvs, DDI_INTR_TYPE_MSIX) == DDI_SUCCESS)) { + return (DDI_SUCCESS); + } + if (((types & DDI_INTR_TYPE_MSI) != 0) && + (pvscsi_register_isr(pvs, DDI_INTR_TYPE_MSI) == DDI_SUCCESS)) { + return (DDI_SUCCESS); + } + if (((types & DDI_INTR_TYPE_FIXED) != 0) && + (pvscsi_register_isr(pvs, DDI_INTR_TYPE_FIXED) == DDI_SUCCESS)) { + return (DDI_SUCCESS); + } + + dev_err(pvs->dip, CE_WARN, "!failed installing any interrupt handler"); + return (DDI_FAILURE); +} + + +static void +pvscsi_timeout(void *arg) +{ + pvscsi_softc_t *pvs; + pvscsi_cmd_t *cmd; + pvscsi_cmd_t *reclaimed = NULL; + list_t *l; + clock_t now; + + pvs = arg; + l = &pvs->cmd_queue; + now = ddi_get_lbolt(); + + mutex_enter(&pvs->lock); + if (pvs->timeout == 0) { + mutex_exit(&pvs->lock); + return; + } + + for (cmd = list_head(l); cmd != NULL; cmd = list_next(l, cmd)) { + clock_t overdue; + + /* polling takes care of it's own timeouts */ + if (cmd->poll) { + continue; + } + + overdue = now - (cmd->start + cmd->timeout); + + /* + * We keep the list of requests sorted by expiration + * time, so we hopefully won't need to walk through + * many of these. This check is safe if lbolt wraps. + */ + if (overdue <= 0) { + break; + } + + /* first we try aborting */ + if (!cmd->expired) { + atomic_or_8(&cmd->expired, 1); + dev_err(pvs->dip, CE_WARN, "!cmd timed out (%lds)", + drv_hztousec(cmd->timeout)/1000000); + continue; + } + + /* if we're less than 2 seconds overdue, wait for abort */ + if (overdue <= pvscsi_hz * 2) { + continue; + } + + /* next it's a reset of the device */ + if (overdue <= pvscsi_hz * 8) { + pvscsi_dev_reset(pvs, cmd->target, cmd->lun); + break; + } + + /* next it's a reset of the bus */ + if (overdue <= pvscsi_hz * 16) { + pvscsi_reset_bus(pvs); + break; + } + + /* finally it's a reset of the entire adapter */ + dev_err(pvs->dip, CE_WARN, "!adapter hung? restarting..."); + mutex_enter(&pvs->lock); + pvscsi_stop_hba(pvs); + reclaimed = pvscsi_reclaim_cmds(pvs); + pvscsi_start_hba(pvs); + mutex_exit(&pvs->lock); + break; + } + + /* see if reset or abort completed anything */ + cmd = pvscsi_process_comp_ring(pvs); + + /* reschedule us if we still have requests pending */ + if (!list_is_empty(l)) { + pvs->timeout = timeout(pvscsi_timeout, pvs, pvscsi_hz); + } + + mutex_exit(&pvs->lock); + + /* if we had things that got completed, then do the callbacks */ + pvscsi_complete_cmds(pvs, reclaimed); + pvscsi_complete_cmds(pvs, cmd); +} + +static int +pvscsi_start(struct scsi_address *ap, struct scsi_pkt *pkt) +{ + pvscsi_cmd_t *cmd = pkt->pkt_ha_private; + struct scsi_device *sd; + pvscsi_device_t *pd; + pvscsi_softc_t *pvs; + int rc; + + /* make sure the packet is sane */ + if ((pkt->pkt_numcookies > PVSCSI_MAX_SG_SIZE) || + ((pkt->pkt_dma_flags & DDI_DMA_RDWR) == DDI_DMA_RDWR) || + (pkt->pkt_cdblen > sizeof (cmd->cdb)) || + ((sd = scsi_address_device(ap)) == NULL) || + ((pd = scsi_device_hba_private_get(sd)) == NULL) || + ((pvs = pd->pvs) == NULL)) { + return (TRAN_BADPKT); + } + + ASSERT(cmd->pkt == pkt); + + cmd->poll = ((pkt->pkt_flags & FLAG_NOINTR) != 0); + + if (pkt->pkt_flags & (FLAG_HTAG|FLAG_HEAD)) { + cmd->tag = MSG_HEAD_QTAG; + } else if (pkt->pkt_flags & FLAG_OTAG) { + cmd->tag = MSG_ORDERED_QTAG; + } else { /* also FLAG_STAG */ + cmd->tag = MSG_SIMPLE_QTAG; + } + + bcopy(pkt->pkt_cdbp, cmd->cdb, pkt->pkt_cdblen); + cmd->cdblen = pkt->pkt_cdblen; + bzero(&cmd->cmd_scb, sizeof (cmd->cmd_scb)); + + /* + * Reinitialize some fields because the packet may + * have been resubmitted. + */ + pkt->pkt_reason = CMD_CMPLT; + pkt->pkt_state = 0; + pkt->pkt_statistics = 0; + + /* Zero status byte - but only if present */ + if (pkt->pkt_scblen > 0) { + *(pkt->pkt_scbp) = 0; + } + + if (pkt->pkt_numcookies > 0) { + if (pkt->pkt_dma_flags & DDI_DMA_READ) { + cmd->dma_dir = PVSCSI_FLAG_CMD_DIR_TOHOST; + } else if (pkt->pkt_dma_flags & DDI_DMA_WRITE) { + cmd->dma_dir = PVSCSI_FLAG_CMD_DIR_TODEVICE; + } else { + cmd->dma_dir = 0; + } + } + + cmd->target = pd->target; + cmd->lun = pd->lun; + cmd->start = ddi_get_lbolt(); + cmd->timeout = pkt->pkt_time * pvscsi_hz; + + rc = pvscsi_transport_command(pvs, cmd); + + if (cmd->poll && rc == TRAN_ACCEPT) { + pvscsi_poll_cmd(pvs, cmd); + pvscsi_set_status(pvs, cmd); + } + + return (rc); +} + + +static int +pvscsi_parse_ua(const char *ua, int *target, int *lun) +{ + char *end; + long num; + if (((ddi_strtol(ua, &end, 16, &num)) != 0) || + ((*end != ',') && (*end != 0))) { + return (DDI_FAILURE); + } + *target = (int)num; + if (*end == 0) { + *lun = 0; + return (DDI_SUCCESS); + } + end++; + if ((ddi_strtol(end, &end, 16, &num) != 0) || (*end != 0)) { + return (DDI_FAILURE); + } + *lun = (int)num; + return (DDI_SUCCESS); +} + +static uint32_t +pvscsi_max_targets(pvscsi_softc_t *pvs) +{ + pvscsi_dma_buf_t db; + struct PVSCSIConfigPageController cpc; + struct PVSCSICmdDescConfigCmd cmd; + + bzero(&db, sizeof (db)); + + /* NB: config pages fit in a single page */ + if (pvscsi_setup_dma_buffer(pvs, PAGE_SIZE, &db) != DDI_SUCCESS) { + dev_err(pvs->dip, CE_WARN, + "!failed to setup config page DMA"); + return (PVSCSI_MAXTGTS); + } + + bzero(&cmd, sizeof (cmd)); + cmd.configPageAddress = PVSCSI_CONFIG_CONTROLLER_ADDRESS; + cmd.configPageAddress <<= 32; + cmd.configPageNum = PVSCSI_CONFIG_PAGE_CONTROLLER; + cmd.cmpAddr = db.pa; + + pvscsi_write_cmd_desc(pvs, PVSCSI_CMD_CONFIG, &cmd, sizeof (cmd)); + (void) ddi_dma_sync(db.dmah, 0, 0, DDI_DMA_SYNC_FORKERNEL); + bcopy(db.addr, &cpc, sizeof (cpc)); + pvscsi_free_dma_buffer(&db); + + + if ((cpc.header.scsiStatus == STATUS_GOOD) && + (cpc.header.hostStatus == BTSTAT_SUCCESS) && + (cpc.numPhys > 0)) { + return (cpc.numPhys); + } + + dev_err(pvs->dip, CE_WARN, "!failed to determine max targets"); + return (PVSCSI_MAXTGTS); +} + +static boolean_t +pvscsi_probe_target(pvscsi_softc_t *pvs, int target) +{ + pvscsi_cmd_t cmd; + + if (!pvscsi_cmd_init(pvs, &cmd, KM_SLEEP)) { + pvscsi_cmd_fini(&cmd); + return (B_FALSE); + } + /* NB: CDB 0 is a TUR which is perfect for our needs */ + bzero(cmd.cdb, sizeof (cmd.cdb)); + cmd.poll = B_TRUE; + cmd.dma_dir = 0; + cmd.target = target; + cmd.lun = 0; + cmd.start = ddi_get_lbolt(); + cmd.timeout = pvscsi_hz; + + if (pvscsi_transport_command(pvs, &cmd) != TRAN_ACCEPT) { + pvscsi_cmd_fini(&cmd); + return (B_FALSE); + } + pvscsi_poll_cmd(pvs, &cmd); + + switch (cmd.host_status) { + case BTSTAT_SUCCESS: + case BTSTAT_LINKED_COMMAND_COMPLETED: + case BTSTAT_LINKED_COMMAND_COMPLETED_WITH_FLAG: + /* We don't care about the actual SCSI status */ + pvscsi_cmd_fini(&cmd); + return (B_TRUE); + } + + pvscsi_cmd_fini(&cmd); + return (B_FALSE); +} + +static int +pvscsi_tgt_init(dev_info_t *dip, dev_info_t *child, scsi_hba_tran_t *tran, + struct scsi_device *sd) +{ + /* + * Assumption: the HBA framework only asks us to have a single + * target initialized per address at any given time. + */ + pvscsi_device_t *pd; + pvscsi_softc_t *pvs; + const char *ua; + + if (((scsi_hba_iport_unit_address(dip)) == NULL) || + ((pvs = tran->tran_hba_private) == NULL) || + ((ua = scsi_device_unit_address(sd)) == NULL)) { + return (DDI_FAILURE); + } + + /* parse the unit address */ + pd = kmem_zalloc(sizeof (*pd), KM_SLEEP); + if (pvscsi_parse_ua(ua, &pd->target, &pd->lun) != DDI_SUCCESS) { + kmem_free(pd, sizeof (*pd)); + return (DDI_FAILURE); + } + pd->pvs = pvs; + scsi_device_hba_private_set(sd, pd); + + mutex_enter(&pvs->lock); + list_insert_tail(&pvs->devices, pd); + mutex_exit(&pvs->lock); + return (DDI_SUCCESS); +} + +static void +pvscsi_tgt_free(dev_info_t *dip, dev_info_t *child, scsi_hba_tran_t *tran, + struct scsi_device *sd) +{ + pvscsi_device_t *pd; + pvscsi_softc_t *pvs; + + if (((scsi_hba_iport_unit_address(dip)) == NULL) || + ((pvs = tran->tran_hba_private) == NULL) || + ((pd = scsi_device_hba_private_get(sd)) == NULL)) { + return; + } + scsi_device_hba_private_set(sd, NULL); + mutex_enter(&pvs->lock); + list_remove(&pvs->devices, pd); + mutex_exit(&pvs->lock); + + kmem_free(pd, sizeof (*pd)); +} + +static int +pvscsi_reset(struct scsi_address *ap, int level) +{ + struct scsi_device *sd; + pvscsi_device_t *pd; + pvscsi_softc_t *pvs; + pvscsi_cmd_t *cmd; + + if (((sd = scsi_address_device(ap)) == NULL) || + ((pd = scsi_device_hba_private_get(sd)) == NULL) || + ((pvs = pd->pvs) == NULL)) { + return (0); + } + switch (level) { + case RESET_ALL: + case RESET_BUS: + pvscsi_reset_bus(pvs); + break; + case RESET_TARGET: + /* reset both the lun and lun 0 */ + pvscsi_dev_reset(pvs, pd->target, pd->lun); + pvscsi_dev_reset(pvs, pd->target, 0); + break; + case RESET_LUN: + pvscsi_dev_reset(pvs, pd->target, pd->lun); + break; + default: + return (0); + } + + /* reset may have caused some completions */ + mutex_enter(&pvs->lock); + cmd = pvscsi_process_comp_ring(pvs); + mutex_exit(&pvs->lock); + + pvscsi_complete_cmds(pvs, cmd); + return (1); +} + +static int +pvscsi_abort(struct scsi_address *ap, struct scsi_pkt *pkt) +{ + struct scsi_device *sd; + pvscsi_device_t *pd; + pvscsi_softc_t *pvs; + pvscsi_cmd_t *cmd; + + if (pkt != NULL) { + /* abort single command */ + cmd = pkt->pkt_ha_private; + pvs = cmd->pvs; + pvscsi_abort_cmd(pvs, cmd); + } else if ((ap != NULL) && + ((sd = scsi_address_device(ap)) != NULL) && + ((pd = scsi_device_hba_private_get(sd)) != NULL) && + ((pvs = pd->pvs) != NULL)) { + /* abort all commands on the bus */ + pvscsi_abort_all(pvs, pd); + } else { + return (0); + } + + /* abort may have caused some completions */ + mutex_enter(&pvs->lock); + cmd = pvscsi_process_comp_ring(pvs); + mutex_exit(&pvs->lock); + + pvscsi_complete_cmds(pvs, cmd); + + return (1); +} + +static int +pvscsi_getcap(struct scsi_address *ap, char *cap, int whom) +{ + _NOTE(ARGUNUSED(ap)); + _NOTE(ARGUNUSED(whom)); + + if (cap == NULL) { + return (-1); + } + + switch (scsi_hba_lookup_capstr(cap)) { + case SCSI_CAP_ARQ: + case SCSI_CAP_UNTAGGED_QING: + case SCSI_CAP_TAGGED_QING: + return (1); + default: + return (-1); + } +} + +static int +pvscsi_setcap(struct scsi_address *ap, char *cap, int value, int whom) +{ + _NOTE(ARGUNUSED(ap)); + _NOTE(ARGUNUSED(value)); + _NOTE(ARGUNUSED(whom)); + + if (cap == NULL) { + return (-1); + } + + switch (scsi_hba_lookup_capstr(cap)) { + case SCSI_CAP_ARQ: + case SCSI_CAP_UNTAGGED_QING: + case SCSI_CAP_TAGGED_QING: + return (0); /* not changeable */ + default: + return (-1); + } +} + +static void +pvscsi_cmd_fini(pvscsi_cmd_t *cmd) +{ + if (cmd->arq_pa != 0) { + (void) ddi_dma_unbind_handle(cmd->arq_dmah); + cmd->arq_dmah = NULL; + } + if (cmd->arq_dmah != NULL) { + ddi_dma_free_handle(&cmd->arq_dmah); + cmd->arq_dmah = NULL; + } + if (cmd->sgl_pa != 0) { + (void) ddi_dma_unbind_handle(cmd->sgl_dmah); + cmd->sgl_pa = 0; + } + if (cmd->sgl_acch != NULL) { + ddi_dma_mem_free(&cmd->sgl_acch); + cmd->sgl_acch = NULL; + cmd->sgl = NULL; + } + if (cmd->sgl_dmah != NULL) { + ddi_dma_free_handle(&cmd->sgl_dmah); + cmd->sgl_dmah = NULL; + } + if (cmd->ctx != 0) { + id32_free(cmd->ctx); + cmd->ctx = 0; + } +} + +static void +pvscsi_pkt_dtor(struct scsi_pkt *pkt, scsi_hba_tran_t *tran) +{ + pvscsi_cmd_t *cmd = pkt->pkt_ha_private; + pvscsi_cmd_fini(cmd); +} + +static boolean_t +pvscsi_cmd_init(pvscsi_softc_t *pvs, pvscsi_cmd_t *cmd, int sleep) +{ + int (*cb)(caddr_t); + size_t len; + caddr_t kaddr; + + cb = sleep == KM_SLEEP ? DDI_DMA_SLEEP : DDI_DMA_DONTWAIT; + + bzero(cmd, sizeof (*cmd)); + cmd->ctx = id32_alloc(cmd, sleep); + if (cmd->ctx == 0) { + dev_err(pvs->dip, CE_WARN, + "!failed to allocate 32-bit context id"); + return (B_FALSE); + } + + /* allocate DMA resources for scatter/gather list */ + if (ddi_dma_alloc_handle(pvs->dip, &pvscsi_dma_attr, cb, NULL, + &cmd->sgl_dmah) != DDI_SUCCESS) { + dev_err(pvs->dip, CE_WARN, + "!failed to allocate DMA handle for SG list"); + return (B_FALSE); + } + if (ddi_dma_mem_alloc(cmd->sgl_dmah, PAGE_SIZE, &pvscsi_dma_attrs, + DDI_DMA_CONSISTENT, cb, NULL, &kaddr, &len, &cmd->sgl_acch) != + DDI_SUCCESS) { + dev_err(pvs->dip, CE_WARN, + "!failed to allocate DMA memory for SG list"); + return (B_FALSE); + } + cmd->sgl = (void *)kaddr; + if (ddi_dma_addr_bind_handle(cmd->sgl_dmah, NULL, kaddr, + PAGE_SIZE, DDI_DMA_WRITE | DDI_DMA_CONSISTENT, cb, NULL, + NULL, NULL) != DDI_DMA_MAPPED) { + dev_err(pvs->dip, CE_WARN, "!failed to bind SGL list"); + return (B_FALSE); + } + cmd->sgl_pa = ddi_dma_cookie_one(cmd->sgl_dmah)->dmac_laddress; + + /* allocate DMA resource for auto-sense-request */ + if (ddi_dma_alloc_handle(pvs->dip, &pvscsi_dma_attr, + cb, NULL, &cmd->arq_dmah) != DDI_SUCCESS) { + dev_err(pvs->dip, CE_WARN, + "!failed to allocate DMA handle for ARQ buffer"); + return (B_FALSE); + } + + if (ddi_dma_addr_bind_handle(cmd->arq_dmah, NULL, + (void *)cmd->arq_sense, SENSE_LENGTH, + DDI_DMA_READ | DDI_DMA_CONSISTENT, cb, NULL, + NULL, NULL) != DDI_DMA_MAPPED) { + dev_err(pvs->dip, CE_WARN, "!failed to bind ARQ buffer"); + return (B_FALSE); + } + cmd->arq_pa = ddi_dma_cookie_one(cmd->arq_dmah)->dmac_laddress; + return (B_TRUE); +} + +static int +pvscsi_pkt_ctor(struct scsi_pkt *pkt, scsi_hba_tran_t *tran, int sleep) +{ + pvscsi_cmd_t *cmd = pkt->pkt_ha_private; + pvscsi_softc_t *pvs = tran->tran_hba_private; + + if (!pvscsi_cmd_init(pvs, cmd, sleep)) { + pvscsi_pkt_dtor(pkt, tran); + return (-1); + } + cmd->pkt = pkt; + return (0); +} + +static void +pvscsi_teardown_pkt(struct scsi_pkt *pkt) +{ + _NOTE(ARGUNUSED(pkt)); + /* nothing to do */ +} + +static int +pvscsi_setup_pkt(struct scsi_pkt *pkt, int (*cb)(caddr_t), caddr_t arg) +{ + /* all work is done in start */ + return (0); +} + +static int +pvscsi_hba_setup(pvscsi_softc_t *pvs) +{ + scsi_hba_tran_t *tran; + + tran = scsi_hba_tran_alloc(pvs->dip, SCSI_HBA_CANSLEEP); + ASSERT(tran != NULL); + + tran->tran_hba_private = pvs; + tran->tran_start = pvscsi_start; + tran->tran_reset = pvscsi_reset; + tran->tran_abort = pvscsi_abort; + tran->tran_getcap = pvscsi_getcap; + tran->tran_setcap = pvscsi_setcap; + tran->tran_pkt_constructor = pvscsi_pkt_ctor; + tran->tran_pkt_destructor = pvscsi_pkt_dtor; + tran->tran_setup_pkt = pvscsi_setup_pkt; + tran->tran_teardown_pkt = pvscsi_teardown_pkt; + tran->tran_tgt_init = pvscsi_tgt_init; + tran->tran_tgt_free = pvscsi_tgt_free; + tran->tran_hba_len = sizeof (pvscsi_cmd_t); + + tran->tran_interconnect_type = INTERCONNECT_PARALLEL; + + if (scsi_hba_attach_setup(pvs->dip, &pvscsi_io_dma_attr, tran, + SCSI_HBA_HBA | SCSI_HBA_TRAN_CDB | SCSI_HBA_TRAN_SCB | + SCSI_HBA_ADDR_COMPLEX) != + DDI_SUCCESS) { + scsi_hba_tran_free(tran); + dev_err(pvs->dip, CE_WARN, "!failed to attach HBA"); + return (DDI_FAILURE); + } + + pvs->tran = tran; + return (DDI_SUCCESS); +} + +static void +pvscsi_teardown(pvscsi_softc_t *pvs) +{ + timeout_id_t tid; + + pvscsi_stop_hba(pvs); + + if (pvs->tq != NULL) { + ddi_taskq_destroy(pvs->tq); + } + mutex_enter(&pvs->lock); + tid = pvs->timeout; + pvs->timeout = 0; + mutex_exit(&pvs->lock); + + if (tid != 0) { + (void) untimeout(tid); + } + + pvscsi_free_intrs(pvs); + pvscsi_free_rings(pvs); + + if (pvs->mmio_handle != NULL) { + ddi_regs_map_free(&pvs->mmio_handle); + } + + if (pvs->tran != NULL) { + scsi_hba_tran_free(pvs->tran); + } + mutex_destroy(&pvs->lock); + list_destroy(&pvs->cmd_queue); + list_destroy(&pvs->devices); + + kmem_free(pvs, sizeof (*pvs)); +} + +static int +pvscsi_iport_attach(dev_info_t *dip) +{ + scsi_hba_tran_t *tran; + dev_info_t *parent; + pvscsi_softc_t *pvs; + char *ua; + uint32_t max_targets; + + if (((parent = ddi_get_parent(dip)) == NULL) || + ((tran = ddi_get_driver_private(parent)) == NULL) || + ((pvs = tran->tran_hba_private) == NULL) || + ((ua = scsi_hba_iport_unit_address(dip)) == NULL) || + (strcmp(ua, "iport0") != 0)) { + return (DDI_FAILURE); + } + + /* store our softc on the iport private tran */ + tran = ddi_get_driver_private(dip); + tran->tran_hba_private = pvs; + + /* setup the target map - allow 100ms for settle / sync times */ + if (scsi_hba_tgtmap_create(dip, SCSI_TM_PERADDR, 100000, + 100000, pvs, NULL, NULL, &pvs->tgtmap) != DDI_SUCCESS) { + dev_err(pvs->dip, CE_WARN, "!failed to create target map"); + return (DDI_FAILURE); + } + + /* reset hardware and setup the rings */ + mutex_enter(&pvs->lock); + pvs->detach = B_FALSE; /* in case of reattach */ + pvscsi_start_hba(pvs); + + max_targets = pvs->max_targets = pvscsi_max_targets(pvs); + mutex_exit(&pvs->lock); + + for (uint32_t i = 0; i < max_targets; i++) { + char addr[8]; + if (pvscsi_probe_target(pvs, i)) { + (void) snprintf(addr, sizeof (addr), "%x", i); + (void) scsi_hba_tgtmap_tgt_add(pvs->tgtmap, + SCSI_TGT_SCSI_DEVICE, addr, NULL); + } + } + + return (DDI_SUCCESS); +} + +static int +pvscsi_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) +{ + pvscsi_softc_t *pvs; + + if (cmd != DDI_ATTACH) { + return (DDI_FAILURE); + } + + if (scsi_hba_iport_unit_address(dip) != NULL) { + return (pvscsi_iport_attach(dip)); + } + + pvs = kmem_zalloc(sizeof (*pvs), KM_SLEEP); + + /* Setup HBA instance */ + pvs->dip = dip; + + /* + * mutex initialization - note that we always run below + * lock level, so we can get by without interrupt priorities + */ + mutex_init(&pvs->lock, NULL, MUTEX_DRIVER, NULL); + list_create(&pvs->cmd_queue, sizeof (pvscsi_cmd_t), + offsetof(pvscsi_cmd_t, queue_node)); + list_create(&pvs->devices, sizeof (pvscsi_device_t), + offsetof(pvscsi_device_t, node)); + + if ((pvscsi_setup_io(pvs)) != DDI_SUCCESS) { + dev_err(pvs->dip, CE_WARN, "!failed to setup I/O region"); + pvscsi_teardown(pvs); + return (DDI_FAILURE); + } + + pvscsi_stop_hba(pvs); + + if ((pvscsi_allocate_rings(pvs)) != DDI_SUCCESS) { + dev_err(pvs->dip, CE_WARN, "!failed to allocate DMA rings"); + pvscsi_teardown(pvs); + return (DDI_FAILURE); + } + + if (pvscsi_setup_isr(pvs) != DDI_SUCCESS) { + dev_err(pvs->dip, CE_WARN, "!failed to setup ISR"); + pvscsi_teardown(pvs); + return (DDI_FAILURE); + } + + /* enable interrupts */ + if (pvscsi_enable_intrs(pvs) != DDI_SUCCESS) { + dev_err(pvs->dip, CE_WARN, "!failed to enable interrupts"); + pvscsi_teardown(pvs); + return (DDI_FAILURE); + } + + pvs->tq = ddi_taskq_create(dip, "iport", 1, TASKQ_DEFAULTPRI, 0); + if (pvs->tq == NULL) { + dev_err(pvs->dip, CE_WARN, "!failed creating tq"); + pvscsi_teardown(pvs); + return (DDI_FAILURE); + } + if (pvscsi_hba_setup(pvs) != DDI_SUCCESS) { + dev_err(pvs->dip, CE_WARN, "!failed to setup HBA"); + pvscsi_teardown(pvs); + return (DDI_FAILURE); + } + + if (scsi_hba_iport_register(dip, "iport0") != 0) { + dev_err(pvs->dip, CE_WARN, "failed to register iport"); + /* detach cannot fail since we didn't setup the iport */ + (void) scsi_hba_detach(dip); + pvscsi_teardown(pvs); + return (DDI_FAILURE); + } + + return (DDI_SUCCESS); +} + +static int +pvscsi_iport_detach(dev_info_t *dip) +{ + pvscsi_softc_t *pvs; + scsi_hba_tran_t *tran; + const char *ua; + pvscsi_cmd_t *reclaimed; + + if (((ua = scsi_hba_iport_unit_address(dip)) == NULL) || + (strcmp(ua, "iport0") != 0) || + ((tran = ddi_get_driver_private(dip)) == NULL) || + ((pvs = tran->tran_hba_private) == NULL)) { + return (DDI_FAILURE); + } + + /* stop the HBA */ + mutex_enter(&pvs->lock); + pvs->detach = B_TRUE; + pvscsi_stop_hba(pvs); + mutex_exit(&pvs->lock); + + /* drain the taskq - nothing else will post to it */ + ddi_taskq_wait(pvs->tq); + + /* reset the HBA */ + mutex_enter(&pvs->lock); + reclaimed = pvscsi_reclaim_cmds(pvs); + mutex_exit(&pvs->lock); + + /* + * If we had any commands, complete them so we can + * reclaim the resources. There really should not be any. + */ + pvscsi_complete_cmds(pvs, reclaimed); + + scsi_hba_tgtmap_destroy(pvs->tgtmap); + pvs->tgtmap = NULL; + + return (DDI_SUCCESS); +} + +static int +pvscsi_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) +{ + pvscsi_softc_t *pvs; + scsi_hba_tran_t *tran; + + if (cmd != DDI_DETACH) { + return (DDI_FAILURE); + } + + if (scsi_hba_iport_unit_address(dip) != NULL) { + return (pvscsi_iport_detach(dip)); + } + + if (((tran = ddi_get_driver_private(dip)) == NULL) || + ((pvs = tran->tran_hba_private) == NULL)) { + /* this can only mean we aren't attached yet */ + return (DDI_SUCCESS); + } + if (scsi_hba_detach(dip) != DDI_SUCCESS) { + return (DDI_FAILURE); + } + + pvscsi_teardown(pvs); + + return (DDI_SUCCESS); +} + +static int +pvscsi_quiesce(dev_info_t *dip) +{ + scsi_hba_tran_t *tran; + pvscsi_softc_t *pvs; + + if (((tran = ddi_get_driver_private(dip)) == NULL) || + ((pvs = tran->tran_hba_private) == NULL)) { + return (DDI_SUCCESS); + } + + pvscsi_stop_hba(pvs); + + return (DDI_SUCCESS); +} + +static struct dev_ops pvscsi_ops = { + .devo_rev = DEVO_REV, + .devo_refcnt = 0, + .devo_getinfo = nodev, + .devo_identify = nulldev, + .devo_probe = nulldev, + .devo_attach = pvscsi_attach, + .devo_detach = pvscsi_detach, + .devo_reset = nodev, + .devo_cb_ops = NULL, + .devo_bus_ops = NULL, + .devo_power = NULL, + .devo_quiesce = pvscsi_quiesce +}; + +#define PVSCSI_IDENT "VMware PVSCSI" + +static struct modldrv modldrv = { + &mod_driverops, + PVSCSI_IDENT, + &pvscsi_ops, +}; + +static struct modlinkage modlinkage = { + MODREV_1, + &modldrv, + NULL +}; + +int +_init(void) +{ + int ret; + + /* get HZ - DDI compliant */ + pvscsi_hz = drv_usectohz(1000000); + + if ((ret = scsi_hba_init(&modlinkage)) != 0) { + cmn_err(CE_WARN, "!scsi_hba_init() failed"); + return (ret); + } + + if ((ret = mod_install(&modlinkage)) != 0) { + cmn_err(CE_WARN, "!mod_install() failed"); + scsi_hba_fini(&modlinkage); + } + + return (ret); +} + +int +_info(struct modinfo *modinfop) +{ + return (mod_info(&modlinkage, modinfop)); +} + +int +_fini(void) +{ + int ret; + + if ((ret = mod_remove(&modlinkage)) == 0) { + scsi_hba_fini(&modlinkage); + } + + return (ret); +} diff --git a/usr/src/uts/intel/io/scsi/adapters/pvscsi/pvscsi.h b/usr/src/uts/common/io/scsi/adapters/pvscsi/pvscsi.h index cbf507a9b8..cbf507a9b8 100644 --- a/usr/src/uts/intel/io/scsi/adapters/pvscsi/pvscsi.h +++ b/usr/src/uts/common/io/scsi/adapters/pvscsi/pvscsi.h diff --git a/usr/src/uts/common/io/scsi/adapters/pvscsi/pvscsi_var.h b/usr/src/uts/common/io/scsi/adapters/pvscsi/pvscsi_var.h new file mode 100644 index 0000000000..ec68ef1471 --- /dev/null +++ b/usr/src/uts/common/io/scsi/adapters/pvscsi/pvscsi_var.h @@ -0,0 +1,126 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2016 Nexenta Systems, Inc. + * Copyright 2022 RackTop Systems, Inc. + */ + +#ifndef _PVSCSI_VAR_H_ +#define _PVSCSI_VAR_H_ + +typedef struct pvscsi_dma_buf { + ddi_dma_handle_t dmah; + caddr_t addr; + uint64_t pa; + ddi_acc_handle_t acch; +} pvscsi_dma_buf_t; + +#define PVSCSI_MAX_IO_PAGES 256 +#define PVSCSI_MAX_IO_SIZE (PVSCSI_MAX_IO_PAGES * PAGE_SIZE) +#define PVSCSI_MAX_SG_SIZE (PVSCSI_MAX_IO_PAGES + 1) + +typedef struct pvscsi_cmd { + struct scsi_pkt *pkt; + struct scsi_arq_status cmd_scb; + uint8_t cdb[SCSI_CDB_SIZE]; + size_t cdblen; + uint8_t tag; + uint8_t scsi_status; + uint32_t host_status; + uint64_t transferred; + boolean_t poll; + int target; + int lun; + uint32_t ctx; + list_node_t queue_node; + clock_t timeout; + clock_t start; + struct pvscsi_softc *pvs; + struct pvscsi_cmd *next_cmd; + + ddi_dma_handle_t sgl_dmah; + ddi_acc_handle_t sgl_acch; + uint64_t sgl_pa; + struct PVSCSISGElement *sgl; + + uint64_t arq_pa; + uint8_t arq_sense[SENSE_LENGTH]; + ddi_dma_handle_t arq_dmah; + + uint32_t dma_dir; + + uint8_t done; + uint8_t expired; +} pvscsi_cmd_t; + +typedef struct pvscsi_msg { + struct pvscsi_softc *pvs; + int type; + int target; + int lun; +} pvscsi_msg_t; + +typedef struct pvscsi_device { + list_node_t node; + struct pvscsi_softc *pvs; + int target; + int lun; +} pvscsi_device_t; + +typedef struct pvscsi_softc { + dev_info_t *dip; + scsi_hba_tran_t *tran; + scsi_hba_tgtmap_t *tgtmap; + pvscsi_dma_buf_t state_buf; + pvscsi_dma_buf_t req_ring_buf; + uint_t req_pages; + uint_t req_depth; + pvscsi_dma_buf_t cmp_ring_buf; + uint_t cmp_pages; + pvscsi_dma_buf_t msg_ring_buf; + uint_t msg_pages; + ddi_acc_handle_t mmio_handle; + caddr_t mmio_base; + int intr_cnt; + int intr_pri; + int intr_type; + uint32_t max_targets; + ddi_intr_handle_t intr_handles[PVSCSI_MAX_INTRS]; + list_t cmd_queue; + list_t devices; + kmutex_t lock; + ddi_taskq_t *tq; + timeout_id_t timeout; + boolean_t detach; +} pvscsi_softc_t; + +#define REQ_RING(pvs) \ + ((struct PVSCSIRingReqDesc *)((pvs)->req_ring_buf.addr)) + +#define CMP_RING(pvs) \ + ((struct PVSCSIRingCmpDesc *)((pvs)->cmp_ring_buf.addr)) + +#define MSG_RING(pvs) \ + ((struct PVSCSIRingMsgDesc *)((pvs)->msg_ring_buf.addr)) + +#define RINGS_STATE(pvs) \ + ((struct PVSCSIRingsState *)((pvs)->state_buf.addr)) + +#define PVSCSI_MAXTGTS 16 + +#define PAGE_SIZE 4096 +#define PAGE_SHIFT 12 + +#define PVSCSI_DEFAULT_NUM_PAGES_PER_RING 8 +#define PVSCSI_DEFAULT_NUM_PAGES_MSG_RING 1 + +#endif /* _PVSCSI_VAR_H_ */ diff --git a/usr/src/uts/common/io/scsi/targets/sd.c b/usr/src/uts/common/io/scsi/targets/sd.c index 105258d102..43a1ee2a47 100644 --- a/usr/src/uts/common/io/scsi/targets/sd.c +++ b/usr/src/uts/common/io/scsi/targets/sd.c @@ -10546,25 +10546,16 @@ sdclose(dev_t dev, int flag, int otyp, cred_t *cred_p) /* * Destroy the cache (if it exists) which was - * allocated for the write maps since this is - * the last close for this media. + * allocated for the write maps, as long as no + * other outstanding commands for the device exist. + * (If we don't destroy it here, we will do so later + * on detach. More likely we'll just reuse it on + * a future open.) */ - if (un->un_wm_cache) { - /* - * Check if there are pending commands. - * and if there are give a warning and - * do not destroy the cache. - */ - if (un->un_ncmds_in_driver > 0) { - scsi_log(SD_DEVINFO(un), - sd_label, CE_WARN, - "Unable to clean up memory " - "because of pending I/O\n"); - } else { - kmem_cache_destroy( - un->un_wm_cache); - un->un_wm_cache = NULL; - } + if ((un->un_wm_cache != NULL) && + (un->un_ncmds_in_driver == 0)) { + kmem_cache_destroy(un->un_wm_cache); + un->un_wm_cache = NULL; } } } diff --git a/usr/src/uts/common/io/vioscsi/vioscsi.c b/usr/src/uts/common/io/vioscsi/vioscsi.c index c647740672..0c83b33489 100644 --- a/usr/src/uts/common/io/vioscsi/vioscsi.c +++ b/usr/src/uts/common/io/vioscsi/vioscsi.c @@ -467,7 +467,7 @@ vioscsi_tran_start(struct scsi_address *ap, struct scsi_pkt *pkt) /* * List empty, or this one expires before others: */ - list_insert_tail(l, req); + list_insert_head(l, req); } if (vd->vd_timeout == 0) { vd->vd_timeout = timeout(vioscsi_dev_timeout, vd, diff --git a/usr/src/uts/common/os/mmapobj.c b/usr/src/uts/common/os/mmapobj.c index d14a4ef005..819d32116d 100644 --- a/usr/src/uts/common/os/mmapobj.c +++ b/usr/src/uts/common/os/mmapobj.c @@ -22,6 +22,7 @@ * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * Copyright 2014 Joyent, Inc. All rights reserved. + * Copyright 2022 Garrett D'Amore <garrett@damore.org> */ #include <sys/types.h> @@ -179,19 +180,6 @@ struct mobj_stats { uint_t mobjs_lib_va_add_delete; uint_t mobjs_lib_va_create_failure; uint_t mobjs_min_align; -#if defined(__sparc) - uint_t mobjs_aout_uzero_fault; - uint_t mobjs_aout_64bit_try; - uint_t mobjs_aout_noexec; - uint_t mobjs_aout_e2big; - uint_t mobjs_aout_lib; - uint_t mobjs_aout_fixed; - uint_t mobjs_aout_zfoddiff; - uint_t mobjs_aout_map_bss; - uint_t mobjs_aout_bss_fail; - uint_t mobjs_aout_nlist; - uint_t mobjs_aout_addr_in_use; -#endif } mobj_stats; #define MOBJ_STAT_ADD(stat) ((mobj_stats.mobjs_##stat)++) @@ -2059,244 +2047,6 @@ doelfwork(Ehdr *ehdrp, vnode_t *vp, mmapobj_result_t *mrp, return (error); } -#if defined(__sparc) -/* - * Hack to support 64 bit kernels running AOUT 4.x programs. - * This is the sizeof (struct nlist) for a 32 bit kernel. - * Since AOUT programs are 32 bit only, they will never use the 64 bit - * sizeof (struct nlist) and thus creating a #define is the simplest - * way around this since this is a format which is not being updated. - * This will be used in the place of sizeof (struct nlist) below. - */ -#define NLIST_SIZE (0xC) - -static int -doaoutwork(vnode_t *vp, mmapobj_result_t *mrp, - uint_t *num_mapped, struct exec *hdr, cred_t *fcred) -{ - int error; - size_t size; - size_t osize; - size_t nsize; /* nlist size */ - size_t msize; - size_t zfoddiff; - caddr_t addr; - caddr_t start_addr; - struct as *as = curproc->p_as; - int prot = PROT_USER | PROT_READ | PROT_EXEC; - uint_t mflag = MAP_PRIVATE | _MAP_LOW32; - offset_t off = 0; - int segnum = 0; - uint_t to_map; - int is_library = 0; - struct segvn_crargs crargs = SEGVN_ZFOD_ARGS(PROT_ZFOD, PROT_ALL); - - /* Only 32bit apps supported by this file format */ - if (get_udatamodel() != DATAMODEL_ILP32) { - MOBJ_STAT_ADD(aout_64bit_try); - return (ENOTSUP); - } - - /* Check to see if this is a library */ - if (hdr->a_magic == ZMAGIC && hdr->a_entry < PAGESIZE) { - is_library = 1; - } - - /* - * Can't execute code from "noexec" mounted filesystem. Unlike ELF, - * aout libraries are always mapped with something PROT_EXEC, so this - * doesn't need to be checked for specific parts - */ - if ((vp->v_vfsp->vfs_flag & VFS_NOEXEC) != 0) { - MOBJ_STAT_ADD(aout_noexec); - return (EACCES); - } - - /* - * There are 2 ways to calculate the mapped size of executable: - * 1) rounded text size + data size + bss size. - * 2) starting offset for text + text size + data size + text relocation - * size + data relocation size + room for nlist data structure. - * - * The larger of the two sizes will be used to map this binary. - */ - osize = P2ROUNDUP(hdr->a_text, PAGESIZE) + hdr->a_data + hdr->a_bss; - - off = hdr->a_magic == ZMAGIC ? 0 : sizeof (struct exec); - - nsize = off + hdr->a_text + hdr->a_data + hdr->a_trsize + - hdr->a_drsize + NLIST_SIZE; - - size = MAX(osize, nsize); - if (size != nsize) { - nsize = 0; - } - - /* - * 1 seg for text and 1 seg for initialized data. - * 1 seg for bss (if can't fit in leftover space of init data) - * 1 seg for nlist if needed. - */ - to_map = 2 + (nsize ? 1 : 0) + - (hdr->a_bss > PAGESIZE - P2PHASE(hdr->a_data, PAGESIZE) ? 1 : 0); - if (*num_mapped < to_map) { - *num_mapped = to_map; - MOBJ_STAT_ADD(aout_e2big); - return (E2BIG); - } - - /* Reserve address space for the whole mapping */ - if (is_library) { - /* We'll let VOP_MAP below pick our address for us */ - addr = NULL; - MOBJ_STAT_ADD(aout_lib); - } else { - /* - * default start address for fixed binaries from AOUT 4.x - * standard. - */ - MOBJ_STAT_ADD(aout_fixed); - mflag |= MAP_FIXED; - addr = (caddr_t)0x2000; - as_rangelock(as); - if (as_gap(as, size, &addr, &size, 0, NULL) != 0) { - as_rangeunlock(as); - MOBJ_STAT_ADD(aout_addr_in_use); - return (EADDRINUSE); - } - crargs.flags |= MAP_NORESERVE; - error = as_map(as, addr, size, segvn_create, &crargs); - ASSERT(addr == (caddr_t)0x2000); - as_rangeunlock(as); - } - - start_addr = addr; - osize = size; - - /* - * Map as large as we need, backed by file, this will be text, and - * possibly the nlist segment. We map over this mapping for bss and - * initialized data segments. - */ - error = VOP_MAP(vp, off, as, &addr, size, prot, PROT_ALL, - mflag, fcred, NULL); - if (error) { - if (!is_library) { - (void) as_unmap(as, start_addr, osize); - } - return (error); - } - - /* pickup the value of start_addr and osize for libraries */ - start_addr = addr; - osize = size; - - /* - * We have our initial reservation/allocation so we need to use fixed - * addresses from now on. - */ - mflag |= MAP_FIXED; - - mrp[0].mr_addr = addr; - mrp[0].mr_msize = hdr->a_text; - mrp[0].mr_fsize = hdr->a_text; - mrp[0].mr_offset = 0; - mrp[0].mr_prot = PROT_READ | PROT_EXEC; - mrp[0].mr_flags = MR_HDR_AOUT; - - - /* - * Map initialized data. We are mapping over a portion of the - * previous mapping which will be unmapped in VOP_MAP below. - */ - off = P2ROUNDUP((offset_t)(hdr->a_text), PAGESIZE); - msize = off; - addr += off; - size = hdr->a_data; - error = VOP_MAP(vp, off, as, &addr, size, PROT_ALL, PROT_ALL, - mflag, fcred, NULL); - if (error) { - (void) as_unmap(as, start_addr, osize); - return (error); - } - msize += size; - mrp[1].mr_addr = addr; - mrp[1].mr_msize = size; - mrp[1].mr_fsize = size; - mrp[1].mr_offset = 0; - mrp[1].mr_prot = PROT_READ | PROT_WRITE | PROT_EXEC; - mrp[1].mr_flags = 0; - - /* Need to zero out remainder of page */ - addr += hdr->a_data; - zfoddiff = P2PHASE((size_t)addr, PAGESIZE); - if (zfoddiff) { - label_t ljb; - - MOBJ_STAT_ADD(aout_zfoddiff); - zfoddiff = PAGESIZE - zfoddiff; - if (on_fault(&ljb)) { - no_fault(); - MOBJ_STAT_ADD(aout_uzero_fault); - (void) as_unmap(as, start_addr, osize); - return (EFAULT); - } - uzero(addr, zfoddiff); - no_fault(); - } - msize += zfoddiff; - segnum = 2; - - /* Map bss */ - if (hdr->a_bss > zfoddiff) { - struct segvn_crargs crargs = - SEGVN_ZFOD_ARGS(PROT_ZFOD, PROT_ALL); - MOBJ_STAT_ADD(aout_map_bss); - addr += zfoddiff; - size = hdr->a_bss - zfoddiff; - as_rangelock(as); - (void) as_unmap(as, addr, size); - error = as_map(as, addr, size, segvn_create, &crargs); - as_rangeunlock(as); - msize += size; - - if (error) { - MOBJ_STAT_ADD(aout_bss_fail); - (void) as_unmap(as, start_addr, osize); - return (error); - } - mrp[2].mr_addr = addr; - mrp[2].mr_msize = size; - mrp[2].mr_fsize = 0; - mrp[2].mr_offset = 0; - mrp[2].mr_prot = PROT_READ | PROT_WRITE | PROT_EXEC; - mrp[2].mr_flags = 0; - - addr += size; - segnum = 3; - } - - /* - * If we have extra bits left over, we need to include that in how - * much we mapped to make sure the nlist logic is correct - */ - msize = P2ROUNDUP(msize, PAGESIZE); - - if (nsize && msize < nsize) { - MOBJ_STAT_ADD(aout_nlist); - mrp[segnum].mr_addr = addr; - mrp[segnum].mr_msize = nsize - msize; - mrp[segnum].mr_fsize = 0; - mrp[segnum].mr_offset = 0; - mrp[segnum].mr_prot = PROT_READ | PROT_EXEC; - mrp[segnum].mr_flags = 0; - } - - *num_mapped = to_map; - return (0); -} -#endif - /* * These are the two types of files that we can interpret and we want to read * in enough info to cover both types when looking at the initial header. @@ -2417,17 +2167,6 @@ mmapobj_map_interpret(vnode_t *vp, mmapobj_result_t *mrp, padding, fcred)); } -#if defined(__sparc) - /* On sparc, check for 4.X AOUT format */ - switch (((struct exec *)header)->a_magic) { - case OMAGIC: - case ZMAGIC: - case NMAGIC: - return (doaoutwork(vp, mrp, num_mapped, - (struct exec *)lheader, fcred)); - } -#endif - /* Unsupported type */ MOBJ_STAT_ADD(unsupported); return (ENOTSUP); diff --git a/usr/src/uts/common/sys/exec.h b/usr/src/uts/common/sys/exec.h index d66a8dc15d..0d5b4c4611 100644 --- a/usr/src/uts/common/sys/exec.h +++ b/usr/src/uts/common/sys/exec.h @@ -21,6 +21,7 @@ /* * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2022 Garrett D'Amore <garrett@damore.org> */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ @@ -198,22 +199,12 @@ extern kmutex_t execsw_lock; extern short elfmagic; extern short intpmagic; extern short javamagic; -#if defined(__sparc) -extern short aout_zmagic; -extern short aout_nmagic; -extern short aout_omagic; -#endif extern short nomagic; extern char elf32magicstr[]; extern char elf64magicstr[]; extern char intpmagicstr[]; extern char javamagicstr[]; -#if defined(__sparc) -extern char aout_nmagicstr[]; -extern char aout_zmagicstr[]; -extern char aout_omagicstr[]; -#endif extern char nomagicstr[]; extern int exec_args(execa_t *, uarg_t *, intpdata_t *, void **); @@ -274,18 +265,6 @@ extern int core_seg(proc_t *, vnode_t *, u_offset_t, caddr_t, size_t, extern int core_write(vnode_t *, enum uio_seg, u_offset_t, const void *, size_t, rlim64_t, cred_t *); -/* a.out stuff */ - -struct exec; - -extern caddr_t gettmem(struct exec *exp); -extern caddr_t getdmem(struct exec *exp); -extern ulong_t getdfile(struct exec *exp); -extern uint_t gettfile(struct exec *exp); -extern int chkaout(struct exdata *exp); -extern void getexinfo(struct exdata *edp_in, struct exdata *edp_out, - int *pagetext, int *pagedata); - #endif /* _KERNEL */ #ifdef __cplusplus diff --git a/usr/src/uts/intel/Makefile.files b/usr/src/uts/intel/Makefile.files index 4df166d8ef..14ac1eb7fb 100644 --- a/usr/src/uts/intel/Makefile.files +++ b/usr/src/uts/intel/Makefile.files @@ -421,11 +421,6 @@ VMXNET3S_OBJS = vmxnet3_main.o \ vmxnet3_utils.o # -# VMware PVSCSI SCSI Controller -# -PVSCSI_OBJS = pvscsi.o - -# # Intel Temperature Module # CORETEMP_OBJS = coretemp.o diff --git a/usr/src/uts/intel/Makefile.rules b/usr/src/uts/intel/Makefile.rules index 1df186ae41..d473288c66 100644 --- a/usr/src/uts/intel/Makefile.rules +++ b/usr/src/uts/intel/Makefile.rules @@ -229,10 +229,6 @@ $(OBJS_DIR)/%.o: $(UTSBASE)/intel/io/scsi/adapters/arcmsr/%.c $(COMPILE.c) -o $@ $< $(CTFCONVERT_O) -$(OBJS_DIR)/%.o: $(UTSBASE)/intel/io/scsi/targets/%.c - $(COMPILE.c) -o $@ $< - $(CTFCONVERT_O) - $(OBJS_DIR)/%.o: $(UTSBASE)/intel/io/vgatext/%.c $(COMPILE.c) -o $@ $< $(CTFCONVERT_O) @@ -241,10 +237,6 @@ $(OBJS_DIR)/%.o: $(UTSBASE)/intel/io/vmxnet3s/%.c $(COMPILE.c) -o $@ $< $(CTFCONVERT_O) -$(OBJS_DIR)/%.o: $(UTSBASE)/intel/io/scsi/adapters/pvscsi/%.c - $(COMPILE.c) -o $@ $< - $(CTFCONVERT_O) - $(OBJS_DIR)/%.o: $(UTSBASE)/intel/nskern/%.s $(COMPILE.s) -o $@ $< diff --git a/usr/src/uts/intel/io/scsi/adapters/pvscsi/pvscsi.c b/usr/src/uts/intel/io/scsi/adapters/pvscsi/pvscsi.c deleted file mode 100644 index 6230ca1c70..0000000000 --- a/usr/src/uts/intel/io/scsi/adapters/pvscsi/pvscsi.c +++ /dev/null @@ -1,2700 +0,0 @@ -/* - * This file and its contents are supplied under the terms of the - * Common Development and Distribution License ("CDDL"), version 1.0. - * You may only use this file in accordance with the terms of version - * 1.0 of the CDDL. - * - * A full copy of the text of the CDDL should have accompanied this - * source. A copy of the CDDL is also available via the Internet at - * http://www.illumos.org/license/CDDL. - */ - -/* - * Copyright 2016 Nexenta Systems, Inc. - */ - -#include <sys/atomic.h> -#include <sys/cmn_err.h> -#include <sys/conf.h> -#include <sys/cpuvar.h> -#include <sys/ddi.h> -#include <sys/errno.h> -#include <sys/fs/dv_node.h> -#include <sys/kmem.h> -#include <sys/kmem_impl.h> -#include <sys/list.h> -#include <sys/modctl.h> -#include <sys/pci.h> -#include <sys/scsi/scsi.h> -#include <sys/sunddi.h> -#include <sys/sysmacros.h> -#include <sys/time.h> -#include <sys/types.h> - -#include "pvscsi.h" -#include "pvscsi_var.h" - -int pvscsi_enable_msi = 1; -int pvscsi_ring_pages = PVSCSI_DEFAULT_NUM_PAGES_PER_RING; -int pvscsi_msg_ring_pages = PVSCSI_DEFAULT_NUM_PAGES_MSG_RING; - -static int pvscsi_abort(struct scsi_address *ap, struct scsi_pkt *pkt); - -static void *pvscsi_sstate; - -/* HBA DMA attributes */ -static ddi_dma_attr_t pvscsi_hba_dma_attr = { - .dma_attr_version = DMA_ATTR_V0, - .dma_attr_addr_lo = 0x0000000000000000ull, - .dma_attr_addr_hi = 0xFFFFFFFFFFFFFFFFull, - .dma_attr_count_max = 0x000000007FFFFFFFull, - .dma_attr_align = 0x0000000000000001ull, - .dma_attr_burstsizes = 0x7ff, - .dma_attr_minxfer = 0x00000001u, - .dma_attr_maxxfer = 0x00000000FFFFFFFFull, - .dma_attr_seg = 0x00000000FFFFFFFFull, - .dma_attr_sgllen = 1, - .dma_attr_granular = 0x00000200u, - .dma_attr_flags = 0 -}; - -/* DMA attributes for req/comp rings */ -static ddi_dma_attr_t pvscsi_ring_dma_attr = { - .dma_attr_version = DMA_ATTR_V0, - .dma_attr_addr_lo = 0x0000000000000000ull, - .dma_attr_addr_hi = 0xFFFFFFFFFFFFFFFFull, - .dma_attr_count_max = 0x000000007FFFFFFFull, - .dma_attr_align = 0x0000000000000001ull, - .dma_attr_burstsizes = 0x7ff, - .dma_attr_minxfer = 0x00000001u, - .dma_attr_maxxfer = 0x00000000FFFFFFFFull, - .dma_attr_seg = 0x00000000FFFFFFFFull, - .dma_attr_sgllen = 1, - .dma_attr_granular = 0x00000001u, - .dma_attr_flags = 0 -}; - -/* DMA attributes for buffer I/O */ -static ddi_dma_attr_t pvscsi_io_dma_attr = { - .dma_attr_version = DMA_ATTR_V0, - .dma_attr_addr_lo = 0x0000000000000000ull, - .dma_attr_addr_hi = 0xFFFFFFFFFFFFFFFFull, - .dma_attr_count_max = 0x000000007FFFFFFFull, - .dma_attr_align = 0x0000000000000001ull, - .dma_attr_burstsizes = 0x7ff, - .dma_attr_minxfer = 0x00000001u, - .dma_attr_maxxfer = 0x00000000FFFFFFFFull, - .dma_attr_seg = 0x00000000FFFFFFFFull, - .dma_attr_sgllen = PVSCSI_MAX_SG_SIZE, - .dma_attr_granular = 0x00000200u, - .dma_attr_flags = 0 -}; - -static ddi_device_acc_attr_t pvscsi_mmio_attr = { - DDI_DEVICE_ATTR_V1, - DDI_STRUCTURE_LE_ACC, - DDI_STRICTORDER_ACC, - DDI_DEFAULT_ACC -}; - -static ddi_device_acc_attr_t pvscsi_dma_attrs = { - DDI_DEVICE_ATTR_V0, - DDI_STRUCTURE_LE_ACC, - DDI_STRICTORDER_ACC, - DDI_DEFAULT_ACC, -}; - -static void -pvscsi_add_to_queue(pvscsi_cmd_t *cmd) -{ - pvscsi_softc_t *pvs = cmd->cmd_pvs; - - ASSERT(pvs != NULL); - ASSERT(mutex_owned(&pvs->mutex)); - ASSERT(!list_link_active(&(cmd)->cmd_queue_node)); - - list_insert_tail(&pvs->cmd_queue, cmd); - pvs->cmd_queue_len++; -} - -static void -pvscsi_remove_from_queue(pvscsi_cmd_t *cmd) -{ - pvscsi_softc_t *pvs = cmd->cmd_pvs; - - ASSERT(pvs != NULL); - ASSERT(mutex_owned(&pvs->mutex)); - ASSERT(list_link_active(&cmd->cmd_queue_node)); - ASSERT(pvs->cmd_queue_len > 0); - - if (list_link_active(&cmd->cmd_queue_node)) { - list_remove(&pvs->cmd_queue, cmd); - pvs->cmd_queue_len--; - } -} - -static uint64_t -pvscsi_map_ctx(pvscsi_softc_t *pvs, pvscsi_cmd_ctx_t *io_ctx) -{ - return (io_ctx - pvs->cmd_ctx + 1); -} - -static pvscsi_cmd_ctx_t * -pvscsi_lookup_ctx(pvscsi_softc_t *pvs, pvscsi_cmd_t *cmd) -{ - pvscsi_cmd_ctx_t *ctx, *end; - - end = &pvs->cmd_ctx[pvs->req_depth]; - for (ctx = pvs->cmd_ctx; ctx < end; ctx++) { - if (ctx->cmd == cmd) - return (ctx); - } - - return (NULL); -} - -static pvscsi_cmd_ctx_t * -pvscsi_resolve_ctx(pvscsi_softc_t *pvs, uint64_t ctx) -{ - if (ctx > 0 && ctx <= pvs->req_depth) - return (&pvs->cmd_ctx[ctx - 1]); - else - return (NULL); -} - -static boolean_t -pvscsi_acquire_ctx(pvscsi_softc_t *pvs, pvscsi_cmd_t *cmd) -{ - pvscsi_cmd_ctx_t *ctx; - - if (list_is_empty(&pvs->cmd_ctx_pool)) - return (B_FALSE); - - ctx = (pvscsi_cmd_ctx_t *)list_remove_head(&pvs->cmd_ctx_pool); - ASSERT(ctx != NULL); - - ctx->cmd = cmd; - cmd->ctx = ctx; - - return (B_TRUE); -} - -static void -pvscsi_release_ctx(pvscsi_cmd_t *cmd) -{ - pvscsi_softc_t *pvs = cmd->cmd_pvs; - - ASSERT(mutex_owned(&pvs->mutex)); - - cmd->ctx->cmd = NULL; - list_insert_tail(&pvs->cmd_ctx_pool, cmd->ctx); - cmd->ctx = NULL; -} - -static uint32_t -pvscsi_reg_read(pvscsi_softc_t *pvs, uint32_t offset) -{ - uint32_t ret; - - ASSERT((offset & (sizeof (uint32_t) - 1)) == 0); - - ret = ddi_get32(pvs->mmio_handle, - (uint32_t *)(pvs->mmio_base + offset)); - - return (ret); -} - -static void -pvscsi_reg_write(pvscsi_softc_t *pvs, uint32_t offset, uint32_t value) -{ - ASSERT((offset & (sizeof (uint32_t) - 1)) == 0); - - ddi_put32(pvs->mmio_handle, (uint32_t *)(pvs->mmio_base + offset), - value); -} - -static void -pvscsi_write_cmd_desc(pvscsi_softc_t *pvs, uint32_t cmd, void *desc, size_t len) -{ - len /= sizeof (uint32_t); - pvscsi_reg_write(pvs, PVSCSI_REG_OFFSET_COMMAND, cmd); - ddi_rep_put32(pvs->mmio_handle, (uint32_t *)desc, - (uint32_t *)(pvs->mmio_base + PVSCSI_REG_OFFSET_COMMAND_DATA), - len, DDI_DEV_NO_AUTOINCR); -} - -static uint32_t -pvscsi_read_intr_status(pvscsi_softc_t *pvs) -{ - return (pvscsi_reg_read(pvs, PVSCSI_REG_OFFSET_INTR_STATUS)); -} - -static void -pvscsi_write_intr_status(pvscsi_softc_t *pvs, uint32_t val) -{ - pvscsi_reg_write(pvs, PVSCSI_REG_OFFSET_INTR_STATUS, val); -} - -static void -pvscsi_mask_intr(pvscsi_softc_t *pvs) -{ - mutex_enter(&pvs->intr_mutex); - - VERIFY(pvs->intr_lock_counter >= 0); - - if (++pvs->intr_lock_counter == 1) - pvscsi_reg_write(pvs, PVSCSI_REG_OFFSET_INTR_MASK, 0); - - mutex_exit(&pvs->intr_mutex); -} - -static void -pvscsi_unmask_intr(pvscsi_softc_t *pvs) -{ - mutex_enter(&pvs->intr_mutex); - - VERIFY(pvs->intr_lock_counter > 0); - - if (--pvs->intr_lock_counter == 0) { - pvscsi_reg_write(pvs, PVSCSI_REG_OFFSET_INTR_MASK, - PVSCSI_INTR_CMPL_MASK | PVSCSI_INTR_MSG_MASK); - } - - mutex_exit(&pvs->intr_mutex); -} - -static void -pvscsi_reset_hba(pvscsi_softc_t *pvs) -{ - pvscsi_write_cmd_desc(pvs, PVSCSI_CMD_ADAPTER_RESET, NULL, 0); -} - -static void -pvscsi_reset_bus(pvscsi_softc_t *pvs) -{ - pvscsi_write_cmd_desc(pvs, PVSCSI_CMD_RESET_BUS, NULL, 0); -} - -static void -pvscsi_submit_nonrw_io(pvscsi_softc_t *pvs) -{ - pvscsi_reg_write(pvs, PVSCSI_REG_OFFSET_KICK_NON_RW_IO, 0); -} - -static void -pvscsi_submit_rw_io(pvscsi_softc_t *pvs) -{ - pvscsi_reg_write(pvs, PVSCSI_REG_OFFSET_KICK_RW_IO, 0); -} - - -static int -pvscsi_inquiry_target(pvscsi_softc_t *pvs, int target, struct scsi_inquiry *inq) -{ - int len = sizeof (struct scsi_inquiry); - int ret = -1; - struct buf *b; - struct scsi_address ap; - struct scsi_pkt *pkt; - uint8_t cdb[CDB_GROUP0]; - - ap.a_hba_tran = pvs->tran; - ap.a_target = (ushort_t)target; - ap.a_lun = (uchar_t)0; - - if ((b = scsi_alloc_consistent_buf(&ap, (struct buf *)NULL, len, - B_READ, NULL_FUNC, NULL)) == NULL) - return (-1); - - if ((pkt = scsi_init_pkt(&ap, (struct scsi_pkt *)NULL, b, - CDB_GROUP0, sizeof (struct scsi_arq_status), 0, 0, - NULL_FUNC, NULL)) == NULL) - goto free_buf; - - cdb[0] = SCMD_INQUIRY; - cdb[1] = 0; - cdb[2] = 0; - cdb[3] = (len & 0xff00) >> 8; - cdb[4] = (len & 0x00ff); - cdb[5] = 0; - - if (inq != NULL) - bzero(inq, sizeof (*inq)); - bcopy(cdb, pkt->pkt_cdbp, CDB_GROUP0); - bzero((struct scsi_inquiry *)b->b_un.b_addr, sizeof (*inq)); - - if ((ret = scsi_poll(pkt)) == 0 && inq != NULL) - bcopy(b->b_un.b_addr, inq, sizeof (*inq)); - - scsi_destroy_pkt(pkt); - -free_buf: - scsi_free_consistent_buf(b); - - return (ret); -} - -static int -pvscsi_config_one(dev_info_t *pdip, pvscsi_softc_t *pvs, int target, - dev_info_t **childp) -{ - char **compatible = NULL; - char *nodename = NULL; - dev_info_t *dip; - int inqrc; - int ncompatible = 0; - pvscsi_device_t *devnode; - struct scsi_inquiry inq; - - ASSERT(DEVI_BUSY_OWNED(pdip)); - - /* Inquiry target */ - inqrc = pvscsi_inquiry_target(pvs, target, &inq); - - /* Find devnode */ - for (devnode = list_head(&pvs->devnodes); devnode != NULL; - devnode = list_next(&pvs->devnodes, devnode)) { - if (devnode->target == target) - break; - } - - if (devnode != NULL) { - if (inqrc != 0) { - /* Target disappeared, drop devnode */ - if (i_ddi_devi_attached(devnode->pdip)) { - char *devname; - /* Get full devname */ - devname = kmem_alloc(MAXPATHLEN, KM_SLEEP); - (void) ddi_deviname(devnode->pdip, devname); - /* Clean cache and name */ - (void) devfs_clean(devnode->parent, devname + 1, - DV_CLEAN_FORCE); - kmem_free(devname, MAXPATHLEN); - } - - (void) ndi_devi_offline(devnode->pdip, NDI_DEVI_REMOVE); - - list_remove(&pvs->devnodes, devnode); - kmem_free(devnode, sizeof (*devnode)); - } else if (childp != NULL) { - /* Target exists */ - *childp = devnode->pdip; - } - return (NDI_SUCCESS); - } else if (inqrc != 0) { - /* Target doesn't exist */ - return (NDI_FAILURE); - } - - scsi_hba_nodename_compatible_get(&inq, NULL, inq.inq_dtype, NULL, - &nodename, &compatible, &ncompatible); - if (nodename == NULL) - goto free_nodename; - - if (ndi_devi_alloc(pdip, nodename, DEVI_SID_NODEID, - &dip) != NDI_SUCCESS) { - dev_err(pvs->dip, CE_WARN, "!failed to alloc device instance"); - goto free_nodename; - } - - if (ndi_prop_update_string(DDI_DEV_T_NONE, dip, - "device-type", "scsi") != DDI_PROP_SUCCESS || - ndi_prop_update_int(DDI_DEV_T_NONE, dip, - "target", target) != DDI_PROP_SUCCESS || - ndi_prop_update_int(DDI_DEV_T_NONE, dip, - "lun", 0) != DDI_PROP_SUCCESS || - ndi_prop_update_int(DDI_DEV_T_NONE, dip, - "pm-capable", 1) != DDI_PROP_SUCCESS || - ndi_prop_update_string_array(DDI_DEV_T_NONE, dip, - "compatible", compatible, ncompatible) != DDI_PROP_SUCCESS) { - dev_err(pvs->dip, CE_WARN, - "!failed to update props for target %d", target); - goto free_devi; - } - - if ((devnode = kmem_zalloc(sizeof (*devnode), KM_NOSLEEP)) == NULL) - goto free_devi; - - if (ndi_devi_online(dip, NDI_ONLINE_ATTACH) != NDI_SUCCESS) { - dev_err(pvs->dip, CE_WARN, "!failed to online target %d", - target); - kmem_free(devnode, sizeof (*devnode)); - goto free_devi; - } - - devnode->target = target; - devnode->pdip = dip; - devnode->parent = pdip; - list_insert_tail(&pvs->devnodes, devnode); - - if (childp != NULL) - *childp = dip; - - scsi_hba_nodename_compatible_free(nodename, compatible); - - return (NDI_SUCCESS); - -free_devi: - ndi_prop_remove_all(dip); - (void) ndi_devi_free(dip); -free_nodename: - scsi_hba_nodename_compatible_free(nodename, compatible); - - return (NDI_FAILURE); -} - -static int -pvscsi_config_all(dev_info_t *pdip, pvscsi_softc_t *pvs) -{ - int target; - - for (target = 0; target < PVSCSI_MAXTGTS; target++) { - /* ndi_devi_enter is done in pvscsi_bus_config */ - (void) pvscsi_config_one(pdip, pvs, target, NULL); - } - - return (NDI_SUCCESS); -} - -static pvscsi_cmd_t * -pvscsi_process_comp_ring(pvscsi_softc_t *pvs) -{ - pvscsi_cmd_t **pnext_cmd = NULL; - pvscsi_cmd_t *cmd; - pvscsi_cmd_t *head = NULL; - struct PVSCSIRingsState *sdesc = RINGS_STATE(pvs); - uint32_t cmp_ne = sdesc->cmpNumEntriesLog2; - - ASSERT(mutex_owned(&pvs->rx_mutex)); - - while (sdesc->cmpConsIdx != sdesc->cmpProdIdx) { - pvscsi_cmd_ctx_t *ctx; - struct PVSCSIRingCmpDesc *cdesc; - - cdesc = CMP_RING(pvs) + (sdesc->cmpConsIdx & MASK(cmp_ne)); - membar_consumer(); - - ctx = pvscsi_resolve_ctx(pvs, cdesc->context); - ASSERT(ctx != NULL); - - if ((cmd = ctx->cmd) != NULL) { - cmd->next_cmd = NULL; - - /* Save command status for further processing */ - cmd->cmp_stat.host_status = cdesc->hostStatus; - cmd->cmp_stat.scsi_status = cdesc->scsiStatus; - cmd->cmp_stat.data_len = cdesc->dataLen; - - /* Mark this command as arrived from hardware */ - cmd->flags |= PVSCSI_FLAG_HW_STATUS; - - if (head == NULL) { - head = cmd; - head->tail_cmd = cmd; - } else { - head->tail_cmd = cmd; - } - - if (pnext_cmd == NULL) { - pnext_cmd = &cmd->next_cmd; - } else { - *pnext_cmd = cmd; - pnext_cmd = &cmd->next_cmd; - } - } - - membar_consumer(); - sdesc->cmpConsIdx++; - } - - return (head); -} - -static pvscsi_msg_t * -pvscsi_process_msg_ring(pvscsi_softc_t *pvs) -{ - pvscsi_msg_t *msg; - struct PVSCSIRingsState *sdesc = RINGS_STATE(pvs); - struct PVSCSIRingMsgDesc *mdesc; - struct PVSCSIMsgDescDevStatusChanged *desc; - uint32_t msg_ne = sdesc->msgNumEntriesLog2; - - ASSERT(mutex_owned(&pvs->rx_mutex)); - - if (sdesc->msgProdIdx == sdesc->msgConsIdx) - return (NULL); - - mdesc = MSG_RING(pvs) + (sdesc->msgConsIdx & MASK(msg_ne)); - membar_consumer(); - - switch (mdesc->type) { - case PVSCSI_MSG_DEV_ADDED: - case PVSCSI_MSG_DEV_REMOVED: - desc = (struct PVSCSIMsgDescDevStatusChanged *)mdesc; - msg = kmem_alloc(sizeof (pvscsi_msg_t), KM_NOSLEEP); - if (msg == NULL) - return (NULL); - msg->msg_pvs = pvs; - msg->type = mdesc->type; - msg->target = desc->target; - break; - default: - dev_err(pvs->dip, CE_WARN, "!unknown msg type: %d", - mdesc->type); - return (NULL); - } - - membar_consumer(); - sdesc->msgConsIdx++; - - return (msg); -} - -static void -pvscsi_handle_msg(void *arg) -{ - pvscsi_msg_t *msg = (pvscsi_msg_t *)arg; - dev_info_t *dip = msg->msg_pvs->dip; - int circ; - - ndi_devi_enter(dip, &circ); - (void) pvscsi_config_one(dip, msg->msg_pvs, msg->target, NULL); - ndi_devi_exit(dip, circ); - - kmem_free(msg, sizeof (pvscsi_msg_t)); -} - -static int -pvscsi_abort_cmd(pvscsi_cmd_t *cmd, pvscsi_cmd_t **pending) -{ - pvscsi_softc_t *pvs = cmd->cmd_pvs; - pvscsi_cmd_t *c; - pvscsi_cmd_t *done; - struct PVSCSICmdDescAbortCmd acmd; - - dev_err(pvs->dip, CE_WARN, "!aborting command %p", (void *)cmd); - - ASSERT(mutex_owned(&pvs->rx_mutex)); - ASSERT(mutex_owned(&pvs->tx_mutex)); - - /* Check if the cmd was already completed by the HBA */ - *pending = done = pvscsi_process_comp_ring(pvs); - for (c = done; c != NULL; c = c->next_cmd) { - if (c == cmd) - return (CMD_CMPLT); - } - - /* Check if cmd was really scheduled by the HBA */ - if (pvscsi_lookup_ctx(pvs, cmd) == NULL) - return (CMD_CMPLT); - - /* Abort cmd in the HBA */ - bzero(&acmd, sizeof (acmd)); - acmd.target = cmd->cmd_target; - acmd.context = pvscsi_map_ctx(pvs, cmd->ctx); - pvscsi_write_cmd_desc(pvs, PVSCSI_CMD_ABORT_CMD, &acmd, sizeof (acmd)); - - /* Check if cmd was completed by the HBA before it could be aborted */ - if ((done = pvscsi_process_comp_ring(pvs)) != NULL) { - done->tail_cmd->next_cmd = *pending; - *pending = done; - for (c = done; c != NULL; c = c->next_cmd) { - if (c == cmd) - return (CMD_CMPLT); - } - } - - /* Release I/O ctx */ - mutex_enter(&pvs->mutex); - if (cmd->ctx != NULL) - pvscsi_release_ctx(cmd); - /* Remove cmd from the queue */ - pvscsi_remove_from_queue(cmd); - mutex_exit(&pvs->mutex); - - /* Insert cmd at the beginning of the list */ - cmd->next_cmd = *pending; - *pending = cmd; - - dev_err(pvs->dip, CE_WARN, "!command %p aborted", (void *)cmd); - - return (CMD_ABORTED); -} - -static void -pvscsi_map_buffers(pvscsi_cmd_t *cmd, struct PVSCSIRingReqDesc *rdesc) -{ - int i; - - ASSERT(cmd->ctx); - ASSERT(cmd->cmd_dmaccount > 0 && cmd->cmd_dmaccount <= - PVSCSI_MAX_SG_SIZE); - - rdesc->dataLen = cmd->cmd_dma_count; - rdesc->dataAddr = 0; - - if (cmd->cmd_dma_count == 0) - return; - - if (cmd->cmd_dmaccount > 1) { - struct PVSCSISGElement *sgl = CMD_CTX_SGLIST_VA(cmd->ctx); - - for (i = 0; i < cmd->cmd_dmaccount; i++) { - sgl[i].addr = cmd->cached_cookies[i].dmac_laddress; - sgl[i].length = cmd->cached_cookies[i].dmac_size; - sgl[i].flags = 0; - } - rdesc->flags |= PVSCSI_FLAG_CMD_WITH_SG_LIST; - rdesc->dataAddr = (uint64_t)CMD_CTX_SGLIST_PA(cmd->ctx); - } else { - rdesc->dataAddr = cmd->cached_cookies[0].dmac_laddress; - } -} - -static void -pvscsi_comp_cmd(pvscsi_cmd_t *cmd, uint8_t status) -{ - struct scsi_pkt *pkt = CMD2PKT(cmd); - - pkt->pkt_state |= (STATE_GOT_BUS | STATE_GOT_TARGET | STATE_SENT_CMD | - STATE_GOT_STATUS); - if ((cmd->flags & PVSCSI_FLAG_DMA_VALID) != 0) - pkt->pkt_state |= STATE_XFERRED_DATA; - pkt->pkt_reason = CMD_CMPLT; - pkt->pkt_resid = 0; - *(pkt->pkt_scbp) = status; -} - -static void -pvscsi_set_status(pvscsi_cmd_t *cmd) -{ - pvscsi_softc_t *pvs = cmd->cmd_pvs; - struct scsi_pkt *pkt = CMD2PKT(cmd); - uchar_t scsi_status = cmd->cmp_stat.scsi_status; - uint32_t host_status = cmd->cmp_stat.host_status; - - if (scsi_status != STATUS_GOOD && - (host_status == BTSTAT_SUCCESS || - (host_status == BTSTAT_LINKED_COMMAND_COMPLETED) || - (host_status == BTSTAT_LINKED_COMMAND_COMPLETED_WITH_FLAG))) { - if (scsi_status == STATUS_CHECK) { - struct scsi_arq_status *astat = (void*)(pkt->pkt_scbp); - uint8_t *sensedata; - int arq_size; - - *pkt->pkt_scbp = scsi_status; - pkt->pkt_state |= STATE_ARQ_DONE; - - if ((cmd->flags & PVSCSI_FLAG_XARQ) != 0) { - arq_size = (cmd->cmd_rqslen >= - SENSE_BUFFER_SIZE) ? SENSE_BUFFER_SIZE : - cmd->cmd_rqslen; - - astat->sts_rqpkt_resid = SENSE_BUFFER_SIZE - - arq_size; - sensedata = (uint8_t *)&astat->sts_sensedata; - bcopy(cmd->arqbuf->b_un.b_addr, sensedata, - arq_size); - - pkt->pkt_state |= STATE_XARQ_DONE; - } else { - astat->sts_rqpkt_resid = 0; - } - - astat->sts_rqpkt_statistics = 0; - astat->sts_rqpkt_reason = CMD_CMPLT; - (*(uint8_t *)&astat->sts_rqpkt_status) = STATUS_GOOD; - astat->sts_rqpkt_state = STATE_GOT_BUS | - STATE_GOT_TARGET | STATE_SENT_CMD | - STATE_XFERRED_DATA | STATE_GOT_STATUS; - } - pvscsi_comp_cmd(cmd, scsi_status); - - return; - } - - switch (host_status) { - case BTSTAT_SUCCESS: - case BTSTAT_LINKED_COMMAND_COMPLETED: - case BTSTAT_LINKED_COMMAND_COMPLETED_WITH_FLAG: - pvscsi_comp_cmd(cmd, STATUS_GOOD); - break; - case BTSTAT_DATARUN: - pkt->pkt_reason = CMD_DATA_OVR; - pkt->pkt_state |= (STATE_GOT_BUS | STATE_GOT_TARGET | - STATE_SENT_CMD | STATE_GOT_STATUS | - STATE_XFERRED_DATA); - pkt->pkt_resid = 0; - break; - case BTSTAT_DATA_UNDERRUN: - pkt->pkt_reason = pkt->pkt_state |= (STATE_GOT_BUS | - STATE_GOT_TARGET | STATE_SENT_CMD | STATE_GOT_STATUS); - pkt->pkt_resid = cmd->dma_count - cmd->cmp_stat.data_len; - if (pkt->pkt_resid != cmd->dma_count) - pkt->pkt_state |= STATE_XFERRED_DATA; - break; - case BTSTAT_SELTIMEO: - pkt->pkt_reason = CMD_DEV_GONE; - pkt->pkt_state |= STATE_GOT_BUS; - break; - case BTSTAT_TAGREJECT: - pkt->pkt_reason = CMD_TAG_REJECT; - pkt->pkt_state |= (STATE_GOT_BUS | STATE_GOT_TARGET | - STATE_SENT_CMD | STATE_GOT_STATUS); - break; - case BTSTAT_BADMSG: - pkt->pkt_reason = CMD_BADMSG; - pkt->pkt_state |= (STATE_GOT_BUS | STATE_GOT_TARGET | - STATE_SENT_CMD | STATE_GOT_STATUS); - break; - case BTSTAT_SENTRST: - case BTSTAT_RECVRST: - case BTSTAT_BUSRESET: - pkt->pkt_reason = CMD_RESET; - pkt->pkt_state |= (STATE_GOT_BUS | STATE_GOT_TARGET | - STATE_SENT_CMD | STATE_GOT_STATUS); - break; - case BTSTAT_ABORTQUEUE: - pkt->pkt_reason = CMD_ABORTED; - pkt->pkt_state |= (STATE_GOT_BUS | STATE_GOT_TARGET | - STATE_SENT_CMD | STATE_GOT_STATUS); - break; - case BTSTAT_HAHARDWARE: - case BTSTAT_INVPHASE: - case BTSTAT_HATIMEOUT: - case BTSTAT_NORESPONSE: - case BTSTAT_DISCONNECT: - case BTSTAT_HASOFTWARE: - case BTSTAT_BUSFREE: - case BTSTAT_SENSFAILED: - pkt->pkt_reason = CMD_TRAN_ERR; - pkt->pkt_state |= (STATE_GOT_BUS | STATE_GOT_TARGET | - STATE_SENT_CMD | STATE_GOT_STATUS); - break; - default: - dev_err(pvs->dip, CE_WARN, - "!unknown host status code: %d", host_status); - pkt->pkt_reason = CMD_TRAN_ERR; - pkt->pkt_state |= (STATE_GOT_BUS | STATE_GOT_TARGET | - STATE_SENT_CMD | STATE_GOT_STATUS); - break; - } -} - -static void -pvscsi_complete_chained(void *arg) -{ - pvscsi_cmd_t *cmd = (pvscsi_cmd_t *)arg; - pvscsi_cmd_t *c; - struct scsi_pkt *pkt; - - while (cmd != NULL) { - pvscsi_softc_t *pvs = cmd->cmd_pvs; - - c = cmd->next_cmd; - cmd->next_cmd = NULL; - - pkt = CMD2PKT(cmd); - if (pkt == NULL) - return; - - if ((cmd->flags & PVSCSI_FLAG_IO_IOPB) != 0 && - (cmd->flags & PVSCSI_FLAG_IO_READ) != 0) { - (void) ddi_dma_sync(cmd->cmd_dmahdl, 0, 0, - DDI_DMA_SYNC_FORCPU); - } - - mutex_enter(&pvs->mutex); - /* Release I/O ctx */ - if (cmd->ctx != NULL) - pvscsi_release_ctx(cmd); - /* Remove command from queue */ - pvscsi_remove_from_queue(cmd); - mutex_exit(&pvs->mutex); - - if ((cmd->flags & PVSCSI_FLAG_HW_STATUS) != 0) { - pvscsi_set_status(cmd); - } else { - ASSERT((cmd->flags & PVSCSI_FLAGS_NON_HW_COMPLETION) != - 0); - - if ((cmd->flags & PVSCSI_FLAG_TIMED_OUT) != 0) { - cmd->pkt->pkt_reason = CMD_TIMEOUT; - cmd->pkt->pkt_statistics |= - (STAT_TIMEOUT | STAT_ABORTED); - } else if ((cmd->flags & PVSCSI_FLAG_ABORTED) != 0) { - cmd->pkt->pkt_reason = CMD_ABORTED; - cmd->pkt->pkt_statistics |= - (STAT_TIMEOUT | STAT_ABORTED); - } else if ((cmd->flags & PVSCSI_FLAGS_RESET) != 0) { - cmd->pkt->pkt_reason = CMD_RESET; - if ((cmd->flags & PVSCSI_FLAG_RESET_BUS) != 0) { - cmd->pkt->pkt_statistics |= - STAT_BUS_RESET; - } else { - cmd->pkt->pkt_statistics |= - STAT_DEV_RESET; - } - } - } - - cmd->flags |= PVSCSI_FLAG_DONE; - cmd->flags &= ~PVSCSI_FLAG_TRANSPORT; - - if ((pkt->pkt_flags & FLAG_NOINTR) == 0 && - pkt->pkt_comp != NULL) - (*pkt->pkt_comp)(pkt); - - cmd = c; - } -} - -static void -pvscsi_dev_reset(pvscsi_softc_t *pvs, int target) -{ - struct PVSCSICmdDescResetDevice cmd = { 0 }; - - cmd.target = target; - pvscsi_write_cmd_desc(pvs, PVSCSI_CMD_RESET_DEVICE, &cmd, sizeof (cmd)); -} - -static int -pvscsi_poll_cmd(pvscsi_softc_t *pvs, pvscsi_cmd_t *cmd) -{ - boolean_t seen_intr; - int cycles = (cmd->pkt->pkt_time * 1000000) / USECS_TO_WAIT; - int i; - pvscsi_cmd_t *dcmd; - struct scsi_pkt *pkt = CMD2PKT(cmd); - - /* - * Make sure we're not missing any commands completed - * concurrently before we have actually disabled interrupts. - */ - mutex_enter(&pvs->rx_mutex); - dcmd = pvscsi_process_comp_ring(pvs); - mutex_exit(&pvs->rx_mutex); - - pvscsi_complete_chained(dcmd); - - while ((cmd->flags & PVSCSI_FLAG_DONE) == 0) { - seen_intr = B_FALSE; - - /* Disable interrupts from H/W */ - pvscsi_mask_intr(pvs); - - /* Wait for interrupt to arrive */ - for (i = 0; i < cycles; i++) { - uint32_t status; - - mutex_enter(&pvs->rx_mutex); - mutex_enter(&pvs->intr_mutex); - status = pvscsi_read_intr_status(pvs); - if ((status & PVSCSI_INTR_ALL_SUPPORTED) != 0) { - /* Check completion ring */ - mutex_exit(&pvs->intr_mutex); - dcmd = pvscsi_process_comp_ring(pvs); - mutex_exit(&pvs->rx_mutex); - seen_intr = B_TRUE; - break; - } else { - mutex_exit(&pvs->intr_mutex); - mutex_exit(&pvs->rx_mutex); - drv_usecwait(USECS_TO_WAIT); - } - } - - /* Enable interrupts from H/W */ - pvscsi_unmask_intr(pvs); - - if (!seen_intr) { - /* No interrupts seen from device during the timeout */ - mutex_enter(&pvs->tx_mutex); - mutex_enter(&pvs->rx_mutex); - if ((cmd->flags & PVSCSI_FLAGS_COMPLETION) != 0) { - /* Command was cancelled asynchronously */ - dcmd = NULL; - } else if ((pvscsi_abort_cmd(cmd, - &dcmd)) == CMD_ABORTED) { - /* Command was cancelled in hardware */ - pkt->pkt_state |= (STAT_TIMEOUT | STAT_ABORTED); - pkt->pkt_statistics |= (STAT_TIMEOUT | - STAT_ABORTED); - pkt->pkt_reason = CMD_TIMEOUT; - } - mutex_exit(&pvs->rx_mutex); - mutex_exit(&pvs->tx_mutex); - - /* - * Complete commands that might be on completion list. - * Target command can also be on the list in case it was - * completed before it could be actually cancelled. - */ - break; - } - - pvscsi_complete_chained(dcmd); - - if (!seen_intr) - break; - } - - return (TRAN_ACCEPT); -} - -static void -pvscsi_abort_all(struct scsi_address *ap, pvscsi_softc_t *pvs, - pvscsi_cmd_t **pending, int marker_flag) -{ - int qlen = pvs->cmd_queue_len; - pvscsi_cmd_t *cmd, *pcmd, *phead = NULL; - - ASSERT(mutex_owned(&pvs->rx_mutex)); - ASSERT(mutex_owned(&pvs->tx_mutex)); - - /* - * Try to abort all queued commands, merging commands waiting - * for completion into a single list to complete them at one - * time when mutex is released. - */ - while (qlen > 0) { - mutex_enter(&pvs->mutex); - cmd = list_remove_head(&pvs->cmd_queue); - ASSERT(cmd != NULL); - - qlen--; - - if (ap == NULL || ap->a_target == cmd->cmd_target) { - int c = --pvs->cmd_queue_len; - - mutex_exit(&pvs->mutex); - - if (pvscsi_abort_cmd(cmd, &pcmd) == CMD_ABORTED) { - /* - * Assume command is completely cancelled now, - * so mark it as requested. - */ - cmd->flags |= marker_flag; - } - - qlen -= (c - pvs->cmd_queue_len); - - /* - * Now merge current pending commands with - * previous ones. - */ - if (phead == NULL) { - phead = pcmd; - } else if (pcmd != NULL) { - phead->tail_cmd->next_cmd = pcmd; - phead->tail_cmd = pcmd->tail_cmd; - } - } else { - list_insert_tail(&pvs->cmd_queue, cmd); - mutex_exit(&pvs->mutex); - } - } - - *pending = phead; -} - -static void -pvscsi_quiesce_notify(pvscsi_softc_t *pvs) -{ - mutex_enter(&pvs->mutex); - if (pvs->cmd_queue_len == 0 && - (pvs->flags & PVSCSI_HBA_QUIESCE_PENDING) != 0) { - pvs->flags &= ~PVSCSI_HBA_QUIESCE_PENDING; - cv_broadcast(&pvs->quiescevar); - } - mutex_exit(&pvs->mutex); -} - -static int -pvscsi_transport_command(pvscsi_softc_t *pvs, pvscsi_cmd_t *cmd) -{ - struct PVSCSIRingReqDesc *rdesc; - struct PVSCSIRingsState *sdesc = RINGS_STATE(pvs); - struct scsi_pkt *pkt = CMD2PKT(cmd); - uint32_t req_ne = sdesc->reqNumEntriesLog2; - - mutex_enter(&pvs->tx_mutex); - mutex_enter(&pvs->mutex); - if (!pvscsi_acquire_ctx(pvs, cmd)) { - mutex_exit(&pvs->mutex); - mutex_exit(&pvs->tx_mutex); - dev_err(pvs->dip, CE_WARN, "!no free ctx available"); - return (TRAN_BUSY); - } - - if ((sdesc->reqProdIdx - sdesc->cmpConsIdx) >= (1 << req_ne)) { - pvscsi_release_ctx(cmd); - mutex_exit(&pvs->mutex); - mutex_exit(&pvs->tx_mutex); - dev_err(pvs->dip, CE_WARN, "!no free I/O slots available"); - return (TRAN_BUSY); - } - mutex_exit(&pvs->mutex); - - cmd->flags |= PVSCSI_FLAG_TRANSPORT; - - rdesc = REQ_RING(pvs) + (sdesc->reqProdIdx & MASK(req_ne)); - - bzero(&rdesc->lun, sizeof (rdesc->lun)); - - rdesc->bus = 0; - rdesc->target = cmd->cmd_target; - - if ((cmd->flags & PVSCSI_FLAG_XARQ) != 0) { - bzero((void*)cmd->arqbuf->b_un.b_addr, SENSE_BUFFER_SIZE); - rdesc->senseLen = SENSE_BUFFER_SIZE; - rdesc->senseAddr = cmd->arqc.dmac_laddress; - } else { - rdesc->senseLen = 0; - rdesc->senseAddr = 0; - } - - rdesc->vcpuHint = CPU->cpu_id; - rdesc->cdbLen = cmd->cmdlen; - bcopy(cmd->cmd_cdb, rdesc->cdb, cmd->cmdlen); - - /* Setup tag info */ - if ((cmd->flags & PVSCSI_FLAG_TAG) != 0) - rdesc->tag = cmd->tag; - else - rdesc->tag = MSG_SIMPLE_QTAG; - - /* Setup I/O direction and map data buffers */ - if ((cmd->flags & PVSCSI_FLAG_DMA_VALID) != 0) { - if ((cmd->flags & PVSCSI_FLAG_IO_READ) != 0) - rdesc->flags = PVSCSI_FLAG_CMD_DIR_TOHOST; - else - rdesc->flags = PVSCSI_FLAG_CMD_DIR_TODEVICE; - pvscsi_map_buffers(cmd, rdesc); - } else { - rdesc->flags = 0; - } - - rdesc->context = pvscsi_map_ctx(pvs, cmd->ctx); - membar_producer(); - - sdesc->reqProdIdx++; - membar_producer(); - - mutex_enter(&pvs->mutex); - cmd->timeout_lbolt = ddi_get_lbolt() + SEC_TO_TICK(pkt->pkt_time); - pkt->pkt_state |= (STATE_GOT_BUS | STATE_GOT_TARGET | STATE_SENT_CMD); - pvscsi_add_to_queue(cmd); - - switch (cmd->pkt->pkt_cdbp[0]) { - case SCMD_READ: - case SCMD_WRITE: - case SCMD_READ_G1: - case SCMD_WRITE_G1: - case SCMD_READ_G4: - case SCMD_WRITE_G4: - case SCMD_READ_G5: - case SCMD_WRITE_G5: - ASSERT((cmd->flags & PVSCSI_FLAG_DMA_VALID) != 0); - pvscsi_submit_rw_io(pvs); - break; - default: - pvscsi_submit_nonrw_io(pvs); - break; - } - mutex_exit(&pvs->mutex); - mutex_exit(&pvs->tx_mutex); - - return (TRAN_ACCEPT); -} - -static int -pvscsi_reset_generic(pvscsi_softc_t *pvs, struct scsi_address *ap) -{ - boolean_t bus_reset = (ap == NULL); - int flags; - pvscsi_cmd_t *done, *aborted; - - flags = bus_reset ? PVSCSI_FLAG_RESET_BUS : PVSCSI_FLAG_RESET_DEV; - - mutex_enter(&pvs->tx_mutex); - mutex_enter(&pvs->rx_mutex); - /* Try to process pending requests */ - done = pvscsi_process_comp_ring(pvs); - - /* Abort all pending requests */ - pvscsi_abort_all(ap, pvs, &aborted, flags); - - /* Reset at hardware level */ - if (bus_reset) { - pvscsi_reset_bus(pvs); - /* Should never happen after bus reset */ - ASSERT(pvscsi_process_comp_ring(pvs) == NULL); - } else { - pvscsi_dev_reset(pvs, ap->a_target); - } - mutex_exit(&pvs->rx_mutex); - mutex_exit(&pvs->tx_mutex); - - pvscsi_complete_chained(done); - pvscsi_complete_chained(aborted); - - return (1); -} - -static void -pvscsi_cmd_ext_free(pvscsi_cmd_t *cmd) -{ - struct scsi_pkt *pkt = CMD2PKT(cmd); - - if ((cmd->flags & PVSCSI_FLAG_CDB_EXT) != 0) { - kmem_free(pkt->pkt_cdbp, cmd->cmdlen); - cmd->flags &= ~PVSCSI_FLAG_CDB_EXT; - } - if ((cmd->flags & PVSCSI_FLAG_SCB_EXT) != 0) { - kmem_free(pkt->pkt_scbp, cmd->statuslen); - cmd->flags &= ~PVSCSI_FLAG_SCB_EXT; - } - if ((cmd->flags & PVSCSI_FLAG_PRIV_EXT) != 0) { - kmem_free(pkt->pkt_private, cmd->tgtlen); - cmd->flags &= ~PVSCSI_FLAG_PRIV_EXT; - } -} - -/* ARGSUSED pvs */ -static int -pvscsi_cmd_ext_alloc(pvscsi_softc_t *pvs, pvscsi_cmd_t *cmd, int kf) -{ - struct scsi_pkt *pkt = CMD2PKT(cmd); - void *buf; - - if (cmd->cmdlen > sizeof (cmd->cmd_cdb)) { - if ((buf = kmem_zalloc(cmd->cmdlen, kf)) == NULL) - return (DDI_FAILURE); - pkt->pkt_cdbp = buf; - cmd->flags |= PVSCSI_FLAG_CDB_EXT; - } - - if (cmd->statuslen > sizeof (cmd->cmd_scb)) { - if ((buf = kmem_zalloc(cmd->statuslen, kf)) == NULL) - goto out; - pkt->pkt_scbp = buf; - cmd->flags |= PVSCSI_FLAG_SCB_EXT; - cmd->cmd_rqslen = (cmd->statuslen - sizeof (cmd->cmd_scb)); - } - - if (cmd->tgtlen > sizeof (cmd->tgt_priv)) { - if ((buf = kmem_zalloc(cmd->tgtlen, kf)) == NULL) - goto out; - pkt->pkt_private = buf; - cmd->flags |= PVSCSI_FLAG_PRIV_EXT; - } - - return (DDI_SUCCESS); - -out: - pvscsi_cmd_ext_free(cmd); - - return (DDI_FAILURE); -} - -static int -pvscsi_setup_dma_buffer(pvscsi_softc_t *pvs, size_t length, - pvscsi_dma_buf_t *buf) -{ - ddi_dma_cookie_t cookie; - uint_t ccount; - - if ((ddi_dma_alloc_handle(pvs->dip, &pvscsi_ring_dma_attr, - DDI_DMA_SLEEP, NULL, &buf->dma_handle)) != DDI_SUCCESS) { - dev_err(pvs->dip, CE_WARN, "!failed to allocate DMA handle"); - return (DDI_FAILURE); - } - - if ((ddi_dma_mem_alloc(buf->dma_handle, length, &pvscsi_dma_attrs, - DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, &buf->addr, - &buf->real_length, &buf->acc_handle)) != DDI_SUCCESS) { - dev_err(pvs->dip, CE_WARN, - "!failed to allocate %ld bytes for DMA buffer", length); - ddi_dma_free_handle(&buf->dma_handle); - return (DDI_FAILURE); - } - - if ((ddi_dma_addr_bind_handle(buf->dma_handle, NULL, buf->addr, - buf->real_length, DDI_DMA_CONSISTENT | DDI_DMA_RDWR, DDI_DMA_SLEEP, - NULL, &cookie, &ccount)) != DDI_SUCCESS) { - dev_err(pvs->dip, CE_WARN, "!failed to bind DMA buffer"); - ddi_dma_free_handle(&buf->dma_handle); - ddi_dma_mem_free(&buf->acc_handle); - return (DDI_FAILURE); - } - - /* TODO Support multipart SG regions */ - ASSERT(ccount == 1); - - buf->pa = cookie.dmac_laddress; - - return (DDI_SUCCESS); -} - -static void -pvscsi_free_dma_buffer(pvscsi_dma_buf_t *buf) -{ - ddi_dma_free_handle(&buf->dma_handle); - ddi_dma_mem_free(&buf->acc_handle); -} - -static int -pvscsi_setup_sg(pvscsi_softc_t *pvs) -{ - int i; - pvscsi_cmd_ctx_t *ctx; - size_t size = pvs->req_depth * sizeof (pvscsi_cmd_ctx_t); - - ctx = pvs->cmd_ctx = kmem_zalloc(size, KM_SLEEP); - - for (i = 0; i < pvs->req_depth; ++i, ++ctx) { - list_insert_tail(&pvs->cmd_ctx_pool, ctx); - if (pvscsi_setup_dma_buffer(pvs, PAGE_SIZE, - &ctx->dma_buf) != DDI_SUCCESS) - goto cleanup; - } - - return (DDI_SUCCESS); - -cleanup: - for (; i >= 0; --i, --ctx) { - list_remove(&pvs->cmd_ctx_pool, ctx); - pvscsi_free_dma_buffer(&ctx->dma_buf); - } - kmem_free(pvs->cmd_ctx, size); - - return (DDI_FAILURE); -} - -static void -pvscsi_free_sg(pvscsi_softc_t *pvs) -{ - int i; - pvscsi_cmd_ctx_t *ctx = pvs->cmd_ctx; - - for (i = 0; i < pvs->req_depth; ++i, ++ctx) { - list_remove(&pvs->cmd_ctx_pool, ctx); - pvscsi_free_dma_buffer(&ctx->dma_buf); - } - - kmem_free(pvs->cmd_ctx, pvs->req_pages << PAGE_SHIFT); -} - -static int -pvscsi_allocate_rings(pvscsi_softc_t *pvs) -{ - /* Allocate DMA buffer for rings state */ - if (pvscsi_setup_dma_buffer(pvs, PAGE_SIZE, - &pvs->rings_state_buf) != DDI_SUCCESS) - return (DDI_FAILURE); - - /* Allocate DMA buffer for request ring */ - pvs->req_pages = MIN(pvscsi_ring_pages, PVSCSI_MAX_NUM_PAGES_REQ_RING); - pvs->req_depth = pvs->req_pages * PVSCSI_MAX_NUM_REQ_ENTRIES_PER_PAGE; - if (pvscsi_setup_dma_buffer(pvs, pvs->req_pages * PAGE_SIZE, - &pvs->req_ring_buf) != DDI_SUCCESS) - goto free_rings_state; - - /* Allocate completion ring */ - pvs->cmp_pages = MIN(pvscsi_ring_pages, PVSCSI_MAX_NUM_PAGES_CMP_RING); - if (pvscsi_setup_dma_buffer(pvs, pvs->cmp_pages * PAGE_SIZE, - &pvs->cmp_ring_buf) != DDI_SUCCESS) - goto free_req_buf; - - /* Allocate message ring */ - pvs->msg_pages = MIN(pvscsi_msg_ring_pages, - PVSCSI_MAX_NUM_PAGES_MSG_RING); - if (pvscsi_setup_dma_buffer(pvs, pvs->msg_pages * PAGE_SIZE, - &pvs->msg_ring_buf) != DDI_SUCCESS) - goto free_cmp_buf; - - return (DDI_SUCCESS); - -free_cmp_buf: - pvscsi_free_dma_buffer(&pvs->cmp_ring_buf); -free_req_buf: - pvscsi_free_dma_buffer(&pvs->req_ring_buf); -free_rings_state: - pvscsi_free_dma_buffer(&pvs->rings_state_buf); - - return (DDI_FAILURE); -} - -static void -pvscsi_free_rings(pvscsi_softc_t *pvs) -{ - pvscsi_free_dma_buffer(&pvs->msg_ring_buf); - pvscsi_free_dma_buffer(&pvs->cmp_ring_buf); - pvscsi_free_dma_buffer(&pvs->req_ring_buf); - pvscsi_free_dma_buffer(&pvs->rings_state_buf); -} - -static void -pvscsi_setup_rings(pvscsi_softc_t *pvs) -{ - int i; - struct PVSCSICmdDescSetupMsgRing cmd_msg = { 0 }; - struct PVSCSICmdDescSetupRings cmd = { 0 }; - uint64_t base; - - cmd.ringsStatePPN = pvs->rings_state_buf.pa >> PAGE_SHIFT; - cmd.reqRingNumPages = pvs->req_pages; - cmd.cmpRingNumPages = pvs->cmp_pages; - - /* Setup request ring */ - base = pvs->req_ring_buf.pa; - for (i = 0; i < pvs->req_pages; i++) { - cmd.reqRingPPNs[i] = base >> PAGE_SHIFT; - base += PAGE_SIZE; - } - - /* Setup completion ring */ - base = pvs->cmp_ring_buf.pa; - for (i = 0; i < pvs->cmp_pages; i++) { - cmd.cmpRingPPNs[i] = base >> PAGE_SHIFT; - base += PAGE_SIZE; - } - - bzero(RINGS_STATE(pvs), PAGE_SIZE); - bzero(REQ_RING(pvs), pvs->req_pages * PAGE_SIZE); - bzero(CMP_RING(pvs), pvs->cmp_pages * PAGE_SIZE); - - /* Issue SETUP command */ - pvscsi_write_cmd_desc(pvs, PVSCSI_CMD_SETUP_RINGS, &cmd, sizeof (cmd)); - - /* Setup message ring */ - cmd_msg.numPages = pvs->msg_pages; - base = pvs->msg_ring_buf.pa; - - for (i = 0; i < pvs->msg_pages; i++) { - cmd_msg.ringPPNs[i] = base >> PAGE_SHIFT; - base += PAGE_SIZE; - } - bzero(MSG_RING(pvs), pvs->msg_pages * PAGE_SIZE); - - pvscsi_write_cmd_desc(pvs, PVSCSI_CMD_SETUP_MSG_RING, &cmd_msg, - sizeof (cmd_msg)); -} - -static int -pvscsi_setup_io(pvscsi_softc_t *pvs) -{ - int offset, rcount, rn, type; - int ret = DDI_FAILURE; - off_t regsize; - pci_regspec_t *regs; - uint_t regs_length; - - if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, pvs->dip, - DDI_PROP_DONTPASS, "reg", (int **)®s, - ®s_length) != DDI_PROP_SUCCESS) { - dev_err(pvs->dip, CE_WARN, "!failed to lookup 'reg' property"); - return (DDI_FAILURE); - } - - rcount = regs_length * sizeof (int) / sizeof (pci_regspec_t); - - for (offset = PCI_CONF_BASE0; offset <= PCI_CONF_BASE5; offset += 4) { - for (rn = 0; rn < rcount; ++rn) { - if (PCI_REG_REG_G(regs[rn].pci_phys_hi) == offset) { - type = regs[rn].pci_phys_hi & PCI_ADDR_MASK; - break; - } - } - - if (rn >= rcount) - continue; - - if (type != PCI_ADDR_IO) { - if (ddi_dev_regsize(pvs->dip, rn, - ®size) != DDI_SUCCESS) { - dev_err(pvs->dip, CE_WARN, - "!failed to get size of reg %d", rn); - goto out; - } - if (regsize == PVSCSI_MEM_SPACE_SIZE) { - if (ddi_regs_map_setup(pvs->dip, rn, - &pvs->mmio_base, 0, 0, - &pvscsi_mmio_attr, - &pvs->mmio_handle) != DDI_SUCCESS) { - dev_err(pvs->dip, CE_WARN, - "!failed to map MMIO BAR"); - goto out; - } - ret = DDI_SUCCESS; - break; - } - } - } - -out: - ddi_prop_free(regs); - - return (ret); -} - -static void -pvscsi_free_io(pvscsi_softc_t *pvs) -{ - ddi_regs_map_free(&pvs->mmio_handle); -} - -static int -pvscsi_enable_intrs(pvscsi_softc_t *pvs) -{ - int i, rc, intr_caps; - - if ((rc = ddi_intr_get_cap(pvs->intr_htable[0], &intr_caps)) != - DDI_SUCCESS) { - dev_err(pvs->dip, CE_WARN, "!failed to get interrupt caps"); - return (DDI_FAILURE); - } - - if ((intr_caps & DDI_INTR_FLAG_BLOCK) != 0) { - if ((rc = ddi_intr_block_enable(pvs->intr_htable, - pvs->intr_cnt)) != DDI_SUCCESS) { - dev_err(pvs->dip, CE_WARN, - "!failed to enable interrupt block"); - } - } else { - for (i = 0; i < pvs->intr_cnt; i++) { - if ((rc = ddi_intr_enable(pvs->intr_htable[i])) == - DDI_SUCCESS) - continue; - dev_err(pvs->dip, CE_WARN, - "!failed to enable interrupt"); - while (--i >= 0) - (void) ddi_intr_disable(pvs->intr_htable[i]); - break; - } - } - - /* Unmask interrupts */ - if (rc == DDI_SUCCESS) { - pvscsi_reg_write(pvs, PVSCSI_REG_OFFSET_INTR_MASK, - PVSCSI_INTR_CMPL_MASK | PVSCSI_INTR_MSG_MASK); - } - - return (rc); -} - -/* ARGSUSED arg2 */ -static uint32_t -pvscsi_intr_handler(caddr_t arg1, caddr_t arg2) -{ - boolean_t handled; - pvscsi_softc_t *pvs = (pvscsi_softc_t *)arg1; - uint32_t status; - - mutex_enter(&pvs->intr_mutex); - if (pvs->num_pollers > 0) { - mutex_exit(&pvs->intr_mutex); - return (DDI_INTR_CLAIMED); - } - - if (pvscsi_enable_msi) { - handled = B_TRUE; - } else { - status = pvscsi_read_intr_status(pvs); - handled = (status & PVSCSI_INTR_ALL_SUPPORTED) != 0; - if (handled) - pvscsi_write_intr_status(pvs, status); - } - mutex_exit(&pvs->intr_mutex); - - if (handled) { - boolean_t qnotify; - pvscsi_cmd_t *pending; - pvscsi_msg_t *msg; - - mutex_enter(&pvs->rx_mutex); - pending = pvscsi_process_comp_ring(pvs); - msg = pvscsi_process_msg_ring(pvs); - mutex_exit(&pvs->rx_mutex); - - mutex_enter(&pvs->mutex); - qnotify = HBA_QUIESCE_PENDING(pvs); - mutex_exit(&pvs->mutex); - - if (pending != NULL && ddi_taskq_dispatch(pvs->comp_tq, - pvscsi_complete_chained, pending, - DDI_NOSLEEP) == DDI_FAILURE) - pvscsi_complete_chained(pending); - - if (msg != NULL && ddi_taskq_dispatch(pvs->msg_tq, - pvscsi_handle_msg, msg, DDI_NOSLEEP) == DDI_FAILURE) { - dev_err(pvs->dip, CE_WARN, - "!failed to process msg type %d for target %d", - msg->type, msg->target); - kmem_free(msg, sizeof (pvscsi_msg_t)); - } - - if (qnotify) - pvscsi_quiesce_notify(pvs); - } - - return (handled ? DDI_INTR_CLAIMED : DDI_INTR_UNCLAIMED); -} - -static int -pvscsi_register_isr(pvscsi_softc_t *pvs, int type) -{ - int navail, nactual; - int i; - - if (ddi_intr_get_navail(pvs->dip, type, &navail) != DDI_SUCCESS || - navail == 0) { - dev_err(pvs->dip, CE_WARN, - "!failed to get number of available interrupts of type %d", - type); - return (DDI_FAILURE); - } - navail = MIN(navail, PVSCSI_MAX_INTRS); - - pvs->intr_size = navail * sizeof (ddi_intr_handle_t); - if ((pvs->intr_htable = kmem_alloc(pvs->intr_size, KM_SLEEP)) == NULL) { - dev_err(pvs->dip, CE_WARN, - "!failed to allocate %d bytes for interrupt hashtable", - pvs->intr_size); - return (DDI_FAILURE); - } - - if (ddi_intr_alloc(pvs->dip, pvs->intr_htable, type, 0, navail, - &nactual, DDI_INTR_ALLOC_NORMAL) != DDI_SUCCESS || nactual == 0) { - dev_err(pvs->dip, CE_WARN, "!failed to allocate %d interrupts", - navail); - goto free_htable; - } - - pvs->intr_cnt = nactual; - - if (ddi_intr_get_pri(pvs->intr_htable[0], - (uint_t *)&pvs->intr_pri) != DDI_SUCCESS) { - dev_err(pvs->dip, CE_WARN, "!failed to get interrupt priority"); - goto free_intrs; - } - - for (i = 0; i < nactual; i++) { - if (ddi_intr_add_handler(pvs->intr_htable[i], - pvscsi_intr_handler, (caddr_t)pvs, NULL) != DDI_SUCCESS) { - dev_err(pvs->dip, CE_WARN, - "!failed to add interrupt handler"); - goto free_intrs; - } - } - - return (DDI_SUCCESS); - -free_intrs: - for (i = 0; i < nactual; i++) - (void) ddi_intr_free(pvs->intr_htable[i]); -free_htable: - kmem_free(pvs->intr_htable, pvs->intr_size); - - return (DDI_FAILURE); -} - -static void -pvscsi_free_intr_resources(pvscsi_softc_t *pvs) -{ - int i; - - for (i = 0; i < pvs->intr_cnt; i++) { - (void) ddi_intr_disable(pvs->intr_htable[i]); - (void) ddi_intr_remove_handler(pvs->intr_htable[i]); - (void) ddi_intr_free(pvs->intr_htable[i]); - } - kmem_free(pvs->intr_htable, pvs->intr_size); -} - -static int -pvscsi_setup_isr(pvscsi_softc_t *pvs) -{ - int intr_types; - - if (ddi_intr_get_supported_types(pvs->dip, - &intr_types) != DDI_SUCCESS) { - dev_err(pvs->dip, CE_WARN, - "!failed to get supported interrupt types"); - return (DDI_FAILURE); - } - - if ((intr_types & DDI_INTR_TYPE_MSIX) != 0 && pvscsi_enable_msi) { - if (pvscsi_register_isr(pvs, - DDI_INTR_TYPE_MSIX) == DDI_SUCCESS) { - pvs->intr_type = DDI_INTR_TYPE_MSIX; - } else { - dev_err(pvs->dip, CE_WARN, - "!failed to install MSI-X interrupt handler"); - } - } else if ((intr_types & DDI_INTR_TYPE_MSI) != 0 && pvscsi_enable_msi) { - if (pvscsi_register_isr(pvs, - DDI_INTR_TYPE_MSI) == DDI_SUCCESS) { - pvs->intr_type = DDI_INTR_TYPE_MSI; - } else { - dev_err(pvs->dip, CE_WARN, - "!failed to install MSI interrupt handler"); - } - } else if ((intr_types & DDI_INTR_TYPE_FIXED) != 0) { - if (pvscsi_register_isr(pvs, - DDI_INTR_TYPE_FIXED) == DDI_SUCCESS) { - pvs->intr_type = DDI_INTR_TYPE_FIXED; - } else { - dev_err(pvs->dip, CE_WARN, - "!failed to install FIXED interrupt handler"); - } - } - - return (pvs->intr_type == 0 ? DDI_FAILURE : DDI_SUCCESS); -} - -static void -pvscsi_wd_thread(pvscsi_softc_t *pvs) -{ - clock_t now; - pvscsi_cmd_t *expired, *c, *cn, **pnext; - - mutex_enter(&pvs->mutex); - for (;;) { - expired = NULL; - pnext = NULL; - now = ddi_get_lbolt(); - - for (c = list_head(&pvs->cmd_queue); c != NULL; ) { - cn = list_next(&pvs->cmd_queue, c); - - /* - * Commands with 'FLAG_NOINTR' are watched using their - * own timeouts, so we should not touch them. - */ - if ((c->pkt->pkt_flags & FLAG_NOINTR) == 0 && - now > c->timeout_lbolt) { - dev_err(pvs->dip, CE_WARN, - "!expired command: %p (%ld > %ld)", - (void *)c, now, c->timeout_lbolt); - pvscsi_remove_from_queue(c); - if (expired == NULL) - expired = c; - if (pnext == NULL) { - pnext = &c->next_cmd; - } else { - *pnext = c; - pnext = &c->next_cmd; - } - } - c = cn; - } - mutex_exit(&pvs->mutex); - - /* Now cancel all expired commands */ - if (expired != NULL) { - struct scsi_address sa = {0}; - /* Build a fake SCSI address */ - sa.a_hba_tran = pvs->tran; - while (expired != NULL) { - c = expired->next_cmd; - sa.a_target = expired->cmd_target; - sa.a_lun = 0; - (void) pvscsi_abort(&sa, CMD2PKT(expired)); - expired = c; - } - } - - mutex_enter(&pvs->mutex); - if ((pvs->flags & PVSCSI_DRIVER_SHUTDOWN) != 0) { - /* Finish job */ - break; - } - if (cv_reltimedwait(&pvs->wd_condvar, &pvs->mutex, - SEC_TO_TICK(1), TR_CLOCK_TICK) > 0) { - /* Explicitly woken up, finish job */ - break; - } - } - - /* Confirm thread termination */ - cv_signal(&pvs->syncvar); - mutex_exit(&pvs->mutex); -} - -static int -pvscsi_ccache_constructor(void *buf, void *cdrarg, int kmflags) -{ - int (*callback)(caddr_t); - uint_t cookiec; - pvscsi_cmd_t *cmd = (pvscsi_cmd_t *)buf; - pvscsi_softc_t *pvs = cdrarg; - struct scsi_address ap; - - callback = (kmflags == KM_SLEEP) ? DDI_DMA_SLEEP : DDI_DMA_DONTWAIT; - ap.a_hba_tran = pvs->tran; - ap.a_target = 0; - ap.a_lun = 0; - - /* Allocate a DMA handle for data transfers */ - if ((ddi_dma_alloc_handle(pvs->dip, &pvs->io_dma_attr, callback, - NULL, &cmd->cmd_dmahdl)) != DDI_SUCCESS) { - dev_err(pvs->dip, CE_WARN, "!failed to allocate DMA handle"); - return (-1); - } - - /* Setup ARQ buffer */ - if ((cmd->arqbuf = scsi_alloc_consistent_buf(&ap, (struct buf *)NULL, - SENSE_BUFFER_SIZE, B_READ, callback, NULL)) == NULL) { - dev_err(pvs->dip, CE_WARN, "!failed to allocate ARQ buffer"); - goto free_handle; - } - - if (ddi_dma_alloc_handle(pvs->dip, &pvs->hba_dma_attr, - callback, NULL, &cmd->arqhdl) != DDI_SUCCESS) { - dev_err(pvs->dip, CE_WARN, - "!failed to allocate DMA handle for ARQ buffer"); - goto free_arqbuf; - } - - if (ddi_dma_buf_bind_handle(cmd->arqhdl, cmd->arqbuf, - (DDI_DMA_READ | DDI_DMA_CONSISTENT), callback, NULL, - &cmd->arqc, &cookiec) != DDI_SUCCESS) { - dev_err(pvs->dip, CE_WARN, "!failed to bind ARQ buffer"); - goto free_arqhdl; - } - - return (0); - -free_arqhdl: - ddi_dma_free_handle(&cmd->arqhdl); -free_arqbuf: - scsi_free_consistent_buf(cmd->arqbuf); -free_handle: - ddi_dma_free_handle(&cmd->cmd_dmahdl); - - return (-1); -} - -/* ARGSUSED cdrarg */ -static void -pvscsi_ccache_destructor(void *buf, void *cdrarg) -{ - pvscsi_cmd_t *cmd = (pvscsi_cmd_t *)buf; - - if (cmd->cmd_dmahdl != NULL) { - (void) ddi_dma_unbind_handle(cmd->cmd_dmahdl); - ddi_dma_free_handle(&cmd->cmd_dmahdl); - cmd->cmd_dmahdl = NULL; - } - - if (cmd->arqhdl != NULL) { - (void) ddi_dma_unbind_handle(cmd->arqhdl); - ddi_dma_free_handle(&cmd->arqhdl); - cmd->arqhdl = NULL; - } - - if (cmd->arqbuf != NULL) { - scsi_free_consistent_buf(cmd->arqbuf); - cmd->arqbuf = NULL; - } -} - -/* tran_* entry points and setup */ -/* ARGSUSED hba_dip tgt_dip hba_tran */ -static int -pvscsi_tgt_init(dev_info_t *hba_dip, dev_info_t *tgt_dip, - scsi_hba_tran_t *hba_tran, struct scsi_device *sd) -{ - pvscsi_softc_t *pvs = SDEV2PRIV(sd); - - ASSERT(pvs != NULL); - - if (sd->sd_address.a_target >= PVSCSI_MAXTGTS) - return (DDI_FAILURE); - - return (DDI_SUCCESS); -} - -static int -pvscsi_start(struct scsi_address *ap, struct scsi_pkt *pkt) -{ - boolean_t poll = ((pkt->pkt_flags & FLAG_NOINTR) != 0); - int rc; - pvscsi_cmd_t *cmd = PKT2CMD(pkt); - pvscsi_softc_t *pvs = ap->a_hba_tran->tran_hba_private; - - ASSERT(cmd->pkt == pkt); - ASSERT(cmd->cmd_pvs == pvs); - - /* - * Reinitialize some fields because the packet may - * have been resubmitted. - */ - pkt->pkt_reason = CMD_CMPLT; - pkt->pkt_state = 0; - pkt->pkt_statistics = 0; - - /* Zero status byte */ - *(pkt->pkt_scbp) = 0; - - if ((cmd->flags & PVSCSI_FLAG_DMA_VALID) != 0) { - ASSERT(cmd->cmd_dma_count != 0); - pkt->pkt_resid = cmd->cmd_dma_count; - - /* - * Consistent packets need to be synced first - * (only for data going out). - */ - if ((cmd->flags & PVSCSI_FLAG_IO_IOPB) != 0) { - (void) ddi_dma_sync(cmd->cmd_dmahdl, 0, 0, - DDI_DMA_SYNC_FORDEV); - } - } - - cmd->cmd_target = ap->a_target; - - mutex_enter(&pvs->mutex); - if (HBA_IS_QUIESCED(pvs) && !poll) { - mutex_exit(&pvs->mutex); - return (TRAN_BUSY); - } - mutex_exit(&pvs->mutex); - - rc = pvscsi_transport_command(pvs, cmd); - - if (poll) { - pvscsi_cmd_t *dcmd; - boolean_t qnotify; - - if (rc == TRAN_ACCEPT) - rc = pvscsi_poll_cmd(pvs, cmd); - - mutex_enter(&pvs->rx_mutex); - dcmd = pvscsi_process_comp_ring(pvs); - mutex_exit(&pvs->rx_mutex); - - mutex_enter(&pvs->mutex); - qnotify = HBA_QUIESCE_PENDING(pvs); - mutex_exit(&pvs->mutex); - - pvscsi_complete_chained(dcmd); - - if (qnotify) - pvscsi_quiesce_notify(pvs); - } - - return (rc); -} - -static int -pvscsi_reset(struct scsi_address *ap, int level) -{ - pvscsi_softc_t *pvs = AP2PRIV(ap); - - switch (level) { - case RESET_ALL: - return (pvscsi_reset_generic(pvs, NULL)); - case RESET_TARGET: - ASSERT(ap != NULL); - return (pvscsi_reset_generic(pvs, ap)); - default: - return (0); - } -} - -static int -pvscsi_abort(struct scsi_address *ap, struct scsi_pkt *pkt) -{ - boolean_t qnotify = B_FALSE; - pvscsi_cmd_t *pending; - pvscsi_softc_t *pvs = ap->a_hba_tran->tran_hba_private; - - mutex_enter(&pvs->tx_mutex); - mutex_enter(&pvs->rx_mutex); - if (pkt != NULL) { - /* Abort single command */ - pvscsi_cmd_t *cmd = PKT2CMD(pkt); - - if (pvscsi_abort_cmd(cmd, &pending) == CMD_ABORTED) { - /* Assume command is completely cancelled now */ - cmd->flags |= PVSCSI_FLAG_ABORTED; - } - } else { - /* Abort all commands on the bus */ - pvscsi_abort_all(ap, pvs, &pending, PVSCSI_FLAG_ABORTED); - } - qnotify = HBA_QUIESCE_PENDING(pvs); - mutex_exit(&pvs->rx_mutex); - mutex_exit(&pvs->tx_mutex); - - pvscsi_complete_chained(pending); - - if (qnotify) - pvscsi_quiesce_notify(pvs); - - return (1); -} - -/* ARGSUSED tgtonly */ -static int -pvscsi_getcap(struct scsi_address *ap, char *cap, int tgtonly) -{ - pvscsi_softc_t *pvs = ap->a_hba_tran->tran_hba_private; - - if (cap == NULL) - return (-1); - - switch (scsi_hba_lookup_capstr(cap)) { - case SCSI_CAP_ARQ: - return ((pvs->flags & PVSCSI_HBA_AUTO_REQUEST_SENSE) != 0); - case SCSI_CAP_UNTAGGED_QING: - return (1); - default: - return (-1); - } -} - -/* ARGSUSED tgtonly */ -static int -pvscsi_setcap(struct scsi_address *ap, char *cap, int value, int tgtonly) -{ - pvscsi_softc_t *pvs = ap->a_hba_tran->tran_hba_private; - - if (cap == NULL) - return (-1); - - switch (scsi_hba_lookup_capstr(cap)) { - case SCSI_CAP_ARQ: - mutex_enter(&pvs->mutex); - if (value == 0) - pvs->flags &= ~PVSCSI_HBA_AUTO_REQUEST_SENSE; - else - pvs->flags |= PVSCSI_HBA_AUTO_REQUEST_SENSE; - mutex_exit(&pvs->mutex); - return (1); - default: - return (0); - } -} - -static void -pvscsi_destroy_pkt(struct scsi_address *ap, struct scsi_pkt *pkt) -{ - pvscsi_cmd_t *cmd = PKT2CMD(pkt); - pvscsi_softc_t *pvs = ap->a_hba_tran->tran_hba_private; - - ASSERT(cmd->cmd_pvs == pvs); - - if ((cmd->flags & PVSCSI_FLAG_DMA_VALID) != 0) { - cmd->flags &= ~PVSCSI_FLAG_DMA_VALID; - (void) ddi_dma_unbind_handle(cmd->cmd_dmahdl); - } - - if (cmd->ctx != NULL) { - mutex_enter(&pvs->mutex); - pvscsi_release_ctx(cmd); - mutex_exit(&pvs->mutex); - } - - if ((cmd->flags & PVSCSI_FLAGS_EXT) != 0) - pvscsi_cmd_ext_free(cmd); - - kmem_cache_free(pvs->cmd_cache, cmd); -} - -static struct scsi_pkt * -pvscsi_init_pkt(struct scsi_address *ap, struct scsi_pkt *pkt, struct buf *bp, - int cmdlen, int statuslen, int tgtlen, int flags, int (*callback)(), - caddr_t arg) -{ - boolean_t is_new; - int kf = (callback == SLEEP_FUNC) ? KM_SLEEP: KM_NOSLEEP; - int rc, i; - pvscsi_cmd_t *cmd; - pvscsi_softc_t *pvs; - - pvs = ap->a_hba_tran->tran_hba_private; - ASSERT(pvs != NULL); - - /* Allocate a new SCSI packet */ - if (pkt == NULL) { - ddi_dma_handle_t saved_dmahdl, saved_arqhdl; - struct buf *saved_arqbuf; - ddi_dma_cookie_t saved_arqc; - - is_new = B_TRUE; - - if ((cmd = kmem_cache_alloc(pvs->cmd_cache, kf)) == NULL) - return (NULL); - - saved_dmahdl = cmd->cmd_dmahdl; - saved_arqhdl = cmd->arqhdl; - saved_arqbuf = cmd->arqbuf; - saved_arqc = cmd->arqc; - - bzero(cmd, sizeof (pvscsi_cmd_t) - - sizeof (cmd->cached_cookies)); - - cmd->cmd_pvs = pvs; - cmd->cmd_dmahdl = saved_dmahdl; - cmd->arqhdl = saved_arqhdl; - cmd->arqbuf = saved_arqbuf; - cmd->arqc = saved_arqc; - - pkt = &cmd->cached_pkt; - pkt->pkt_ha_private = (opaque_t)cmd; - pkt->pkt_address = *ap; - pkt->pkt_scbp = (uint8_t *)&cmd->cmd_scb; - pkt->pkt_cdbp = (uint8_t *)&cmd->cmd_cdb; - pkt->pkt_private = (opaque_t)&cmd->tgt_priv; - - cmd->tgtlen = tgtlen; - cmd->statuslen = statuslen; - cmd->cmdlen = cmdlen; - cmd->pkt = pkt; - cmd->ctx = NULL; - - /* Allocate extended buffers */ - if ((cmdlen > sizeof (cmd->cmd_cdb)) || - (statuslen > sizeof (cmd->cmd_scb)) || - (tgtlen > sizeof (cmd->tgt_priv))) { - if (pvscsi_cmd_ext_alloc(pvs, cmd, kf) != DDI_SUCCESS) { - dev_err(pvs->dip, CE_WARN, - "!extent allocation failed"); - goto out; - } - } - } else { - is_new = B_FALSE; - - cmd = PKT2CMD(pkt); - cmd->flags &= PVSCSI_FLAGS_PERSISTENT; - } - - ASSERT((cmd->flags & PVSCSI_FLAG_TRANSPORT) == 0); - - if ((flags & PKT_XARQ) != 0) - cmd->flags |= PVSCSI_FLAG_XARQ; - - /* Handle partial DMA transfers */ - if (cmd->cmd_nwin > 0) { - if (++cmd->cmd_winindex >= cmd->cmd_nwin) - return (NULL); - if (ddi_dma_getwin(cmd->cmd_dmahdl, cmd->cmd_winindex, - &cmd->cmd_dma_offset, &cmd->cmd_dma_len, - &cmd->cmd_dmac, &cmd->cmd_dmaccount) == DDI_FAILURE) - return (NULL); - goto handle_dma_cookies; - } - - /* Setup data buffer */ - if (bp != NULL && bp->b_bcount > 0 && - (cmd->flags & PVSCSI_FLAG_DMA_VALID) == 0) { - int dma_flags; - - ASSERT(cmd->cmd_dmahdl != NULL); - - if ((bp->b_flags & B_READ) != 0) { - cmd->flags |= PVSCSI_FLAG_IO_READ; - dma_flags = DDI_DMA_READ; - } else { - cmd->flags &= ~PVSCSI_FLAG_IO_READ; - dma_flags = DDI_DMA_WRITE; - } - if ((flags & PKT_CONSISTENT) != 0) { - cmd->flags |= PVSCSI_FLAG_IO_IOPB; - dma_flags |= DDI_DMA_CONSISTENT; - } - if ((flags & PKT_DMA_PARTIAL) != 0) - dma_flags |= DDI_DMA_PARTIAL; - - rc = ddi_dma_buf_bind_handle(cmd->cmd_dmahdl, bp, - dma_flags, callback, arg, &cmd->cmd_dmac, - &cmd->cmd_dmaccount); - if (rc == DDI_DMA_PARTIAL_MAP) { - (void) ddi_dma_numwin(cmd->cmd_dmahdl, - &cmd->cmd_nwin); - cmd->cmd_winindex = 0; - (void) ddi_dma_getwin(cmd->cmd_dmahdl, - cmd->cmd_winindex, &cmd->cmd_dma_offset, - &cmd->cmd_dma_len, &cmd->cmd_dmac, - &cmd->cmd_dmaccount); - } else if (rc != 0 && rc != DDI_DMA_MAPPED) { - switch (rc) { - case DDI_DMA_NORESOURCES: - bioerror(bp, 0); - break; - case DDI_DMA_BADATTR: - case DDI_DMA_NOMAPPING: - bioerror(bp, EFAULT); - break; - case DDI_DMA_TOOBIG: - default: - bioerror(bp, EINVAL); - break; - } - cmd->flags &= ~PVSCSI_FLAG_DMA_VALID; - goto out; - } - -handle_dma_cookies: - ASSERT(cmd->cmd_dmaccount > 0); - if (cmd->cmd_dmaccount > PVSCSI_MAX_SG_SIZE) { - dev_err(pvs->dip, CE_WARN, - "!invalid cookie count: %d (max %d)", - cmd->cmd_dmaccount, PVSCSI_MAX_SG_SIZE); - bioerror(bp, EINVAL); - goto out; - } - - cmd->flags |= PVSCSI_FLAG_DMA_VALID; - cmd->cmd_dma_count = cmd->cmd_dmac.dmac_size; - cmd->cmd_total_dma_count += cmd->cmd_dmac.dmac_size; - - cmd->cached_cookies[0] = cmd->cmd_dmac; - - /* - * Calculate total amount of bytes for this I/O and - * store cookies for further processing. - */ - for (i = 1; i < cmd->cmd_dmaccount; i++) { - ddi_dma_nextcookie(cmd->cmd_dmahdl, &cmd->cmd_dmac); - cmd->cached_cookies[i] = cmd->cmd_dmac; - cmd->cmd_dma_count += cmd->cmd_dmac.dmac_size; - cmd->cmd_total_dma_count += cmd->cmd_dmac.dmac_size; - } - - pkt->pkt_resid = (bp->b_bcount - cmd->cmd_total_dma_count); - } - - return (pkt); - -out: - if (is_new) - pvscsi_destroy_pkt(ap, pkt); - - return (NULL); -} - -/* ARGSUSED ap */ -static void -pvscsi_dmafree(struct scsi_address *ap, struct scsi_pkt *pkt) -{ - pvscsi_cmd_t *cmd = PKT2CMD(pkt); - - if ((cmd->flags & PVSCSI_FLAG_DMA_VALID) != 0) { - (void) ddi_dma_unbind_handle(cmd->cmd_dmahdl); - cmd->flags &= ~PVSCSI_FLAG_DMA_VALID; - } -} - -/* ARGSUSED ap */ -static void -pvscsi_sync_pkt(struct scsi_address *ap, struct scsi_pkt *pkt) -{ - pvscsi_cmd_t *cmd = PKT2CMD(pkt); - - if (cmd->cmd_dmahdl != NULL) { - (void) ddi_dma_sync(cmd->cmd_dmahdl, 0, 0, - (cmd->flags & PVSCSI_FLAG_IO_READ) ? - DDI_DMA_SYNC_FORCPU : DDI_DMA_SYNC_FORDEV); - } - -} - -/* ARGSUSED ap flag callback arg */ -static int -pvscsi_reset_notify(struct scsi_address *ap, int flag, - void (*callback)(caddr_t), caddr_t arg) -{ - return (DDI_FAILURE); -} - -static int -pvscsi_quiesce_hba(dev_info_t *dip) -{ - pvscsi_softc_t *pvs; - scsi_hba_tran_t *tran; - - if ((tran = ddi_get_driver_private(dip)) == NULL || - (pvs = TRAN2PRIV(tran)) == NULL) - return (-1); - - mutex_enter(&pvs->mutex); - if (!HBA_IS_QUIESCED(pvs)) - pvs->flags |= PVSCSI_HBA_QUIESCED; - - if (pvs->cmd_queue_len != 0) { - /* Outstanding commands present, wait */ - pvs->flags |= PVSCSI_HBA_QUIESCE_PENDING; - cv_wait(&pvs->quiescevar, &pvs->mutex); - ASSERT(pvs->cmd_queue_len == 0); - } - mutex_exit(&pvs->mutex); - - /* Suspend taskq delivery and complete all scheduled tasks */ - ddi_taskq_suspend(pvs->msg_tq); - ddi_taskq_wait(pvs->msg_tq); - ddi_taskq_suspend(pvs->comp_tq); - ddi_taskq_wait(pvs->comp_tq); - - return (0); -} - -static int -pvscsi_unquiesce_hba(dev_info_t *dip) -{ - pvscsi_softc_t *pvs; - scsi_hba_tran_t *tran; - - if ((tran = ddi_get_driver_private(dip)) == NULL || - (pvs = TRAN2PRIV(tran)) == NULL) - return (-1); - - mutex_enter(&pvs->mutex); - if (!HBA_IS_QUIESCED(pvs)) { - mutex_exit(&pvs->mutex); - return (0); - } - ASSERT(pvs->cmd_queue_len == 0); - pvs->flags &= ~PVSCSI_HBA_QUIESCED; - mutex_exit(&pvs->mutex); - - /* Resume taskq delivery */ - ddi_taskq_resume(pvs->msg_tq); - ddi_taskq_resume(pvs->comp_tq); - - return (0); -} - -static int -pvscsi_bus_config(dev_info_t *pdip, uint_t flags, ddi_bus_config_op_t op, - void *arg, dev_info_t **childp) -{ - char *p; - int circ; - int ret = NDI_FAILURE; - long target = 0; - pvscsi_softc_t *pvs; - scsi_hba_tran_t *tran; - - tran = ddi_get_driver_private(pdip); - pvs = tran->tran_hba_private; - - ndi_devi_enter(pdip, &circ); - switch (op) { - case BUS_CONFIG_ONE: - if ((p = strrchr((char *)arg, '@')) != NULL && - ddi_strtol(p + 1, NULL, 16, &target) == 0) - ret = pvscsi_config_one(pdip, pvs, (int)target, childp); - break; - case BUS_CONFIG_DRIVER: - case BUS_CONFIG_ALL: - ret = pvscsi_config_all(pdip, pvs); - break; - default: - break; - } - - if (ret == NDI_SUCCESS) - ret = ndi_busop_bus_config(pdip, flags, op, arg, childp, 0); - ndi_devi_exit(pdip, circ); - - return (ret); -} - -static int -pvscsi_hba_setup(pvscsi_softc_t *pvs) -{ - scsi_hba_tran_t *hba_tran; - - hba_tran = pvs->tran = scsi_hba_tran_alloc(pvs->dip, - SCSI_HBA_CANSLEEP); - ASSERT(pvs->tran != NULL); - - hba_tran->tran_hba_private = pvs; - hba_tran->tran_tgt_private = NULL; - - hba_tran->tran_tgt_init = pvscsi_tgt_init; - hba_tran->tran_tgt_free = NULL; - hba_tran->tran_tgt_probe = scsi_hba_probe; - - hba_tran->tran_start = pvscsi_start; - hba_tran->tran_reset = pvscsi_reset; - hba_tran->tran_abort = pvscsi_abort; - hba_tran->tran_getcap = pvscsi_getcap; - hba_tran->tran_setcap = pvscsi_setcap; - hba_tran->tran_init_pkt = pvscsi_init_pkt; - hba_tran->tran_destroy_pkt = pvscsi_destroy_pkt; - - hba_tran->tran_dmafree = pvscsi_dmafree; - hba_tran->tran_sync_pkt = pvscsi_sync_pkt; - hba_tran->tran_reset_notify = pvscsi_reset_notify; - - hba_tran->tran_quiesce = pvscsi_quiesce_hba; - hba_tran->tran_unquiesce = pvscsi_unquiesce_hba; - hba_tran->tran_bus_reset = NULL; - - hba_tran->tran_add_eventcall = NULL; - hba_tran->tran_get_eventcookie = NULL; - hba_tran->tran_post_event = NULL; - hba_tran->tran_remove_eventcall = NULL; - - hba_tran->tran_bus_config = pvscsi_bus_config; - - hba_tran->tran_interconnect_type = INTERCONNECT_SAS; - - if (scsi_hba_attach_setup(pvs->dip, &pvs->hba_dma_attr, hba_tran, - SCSI_HBA_TRAN_CDB | SCSI_HBA_TRAN_SCB | SCSI_HBA_TRAN_CLONE) != - DDI_SUCCESS) { - dev_err(pvs->dip, CE_WARN, "!failed to attach HBA"); - scsi_hba_tran_free(hba_tran); - pvs->tran = NULL; - return (-1); - } - - return (0); -} - -static int -pvscsi_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) -{ - int instance; - pvscsi_softc_t *pvs; - char buf[32]; - - ASSERT(scsi_hba_iport_unit_address(dip) == NULL); - - switch (cmd) { - case DDI_ATTACH: - case DDI_RESUME: - break; - default: - return (DDI_FAILURE); - } - - instance = ddi_get_instance(dip); - - /* Allocate softstate information */ - if (ddi_soft_state_zalloc(pvscsi_sstate, instance) != DDI_SUCCESS) { - cmn_err(CE_WARN, - "!ddi_soft_state_zalloc() failed for instance %d", - instance); - return (DDI_FAILURE); - } - - if ((pvs = ddi_get_soft_state(pvscsi_sstate, instance)) == NULL) { - cmn_err(CE_WARN, "!failed to get soft state for instance %d", - instance); - goto fail; - } - - /* - * Indicate that we are 'sizeof (scsi_*(9S))' clean, we use - * scsi_pkt_size() instead. - */ - scsi_size_clean(dip); - - /* Setup HBA instance */ - pvs->instance = instance; - pvs->dip = dip; - pvs->hba_dma_attr = pvscsi_hba_dma_attr; - pvs->ring_dma_attr = pvscsi_ring_dma_attr; - pvs->io_dma_attr = pvscsi_io_dma_attr; - mutex_init(&pvs->mutex, "pvscsi instance mutex", MUTEX_DRIVER, NULL); - mutex_init(&pvs->intr_mutex, "pvscsi instance interrupt mutex", - MUTEX_DRIVER, NULL); - mutex_init(&pvs->rx_mutex, "pvscsi rx ring mutex", MUTEX_DRIVER, NULL); - mutex_init(&pvs->tx_mutex, "pvscsi tx ring mutex", MUTEX_DRIVER, NULL); - list_create(&pvs->cmd_ctx_pool, sizeof (pvscsi_cmd_ctx_t), - offsetof(pvscsi_cmd_ctx_t, list)); - list_create(&pvs->devnodes, sizeof (pvscsi_device_t), - offsetof(pvscsi_device_t, list)); - list_create(&pvs->cmd_queue, sizeof (pvscsi_cmd_t), - offsetof(pvscsi_cmd_t, cmd_queue_node)); - cv_init(&pvs->syncvar, "pvscsi synchronization cv", CV_DRIVER, NULL); - cv_init(&pvs->wd_condvar, "pvscsi watchdog cv", CV_DRIVER, NULL); - cv_init(&pvs->quiescevar, "pvscsi quiesce cv", CV_DRIVER, NULL); - - (void) sprintf(buf, "pvscsi%d_cache", instance); - pvs->cmd_cache = kmem_cache_create(buf, sizeof (pvscsi_cmd_t), 0, - pvscsi_ccache_constructor, pvscsi_ccache_destructor, NULL, - (void *)pvs, NULL, 0); - if (pvs->cmd_cache == NULL) { - dev_err(pvs->dip, CE_WARN, - "!failed to create a cache for SCSI commands"); - goto fail; - } - - if ((pvscsi_setup_io(pvs)) != DDI_SUCCESS) { - dev_err(pvs->dip, CE_WARN, "!failed to setup I/O region"); - goto free_cache; - } - - pvscsi_reset_hba(pvs); - - if ((pvscsi_allocate_rings(pvs)) != DDI_SUCCESS) { - dev_err(pvs->dip, CE_WARN, "!failed to allocate DMA rings"); - goto free_io; - } - - pvscsi_setup_rings(pvs); - - if (pvscsi_setup_isr(pvs) != DDI_SUCCESS) { - dev_err(pvs->dip, CE_WARN, "!failed to setup ISR"); - goto free_rings; - } - - if (pvscsi_setup_sg(pvs) != DDI_SUCCESS) { - dev_err(pvs->dip, CE_WARN, "!failed to setup S/G"); - goto free_intr; - } - - if (pvscsi_hba_setup(pvs) != 0) { - dev_err(pvs->dip, CE_WARN, "!failed to setup HBA"); - goto free_sg; - } - - if ((pvs->comp_tq = ddi_taskq_create(pvs->dip, "comp_tq", - MIN(UINT16_MAX, ncpus), TASKQ_DEFAULTPRI, 0)) == NULL) { - dev_err(pvs->dip, CE_WARN, - "!failed to create completion taskq"); - goto free_sg; - } - - if ((pvs->msg_tq = ddi_taskq_create(pvs->dip, "msg_tq", - 1, TASKQ_DEFAULTPRI, 0)) == NULL) { - dev_err(pvs->dip, CE_WARN, - "!failed to create message taskq"); - goto free_comp_tq; - } - - if (pvscsi_enable_intrs(pvs) != DDI_SUCCESS) { - dev_err(pvs->dip, CE_WARN, "!failed to enable interrupts"); - goto free_msg_tq; - } - - /* Launch watchdog thread */ - pvs->wd_thread = thread_create(NULL, 0, pvscsi_wd_thread, pvs, 0, &p0, - TS_RUN, minclsyspri); - - return (DDI_SUCCESS); - -free_msg_tq: - ddi_taskq_destroy(pvs->msg_tq); -free_comp_tq: - ddi_taskq_destroy(pvs->comp_tq); -free_sg: - pvscsi_free_sg(pvs); -free_intr: - pvscsi_free_intr_resources(pvs); -free_rings: - pvscsi_reset_hba(pvs); - pvscsi_free_rings(pvs); -free_io: - pvscsi_free_io(pvs); -free_cache: - kmem_cache_destroy(pvs->cmd_cache); -fail: - ddi_soft_state_free(pvscsi_sstate, instance); - - return (DDI_FAILURE); -} - -static int -pvscsi_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) -{ - int instance; - pvscsi_softc_t *pvs; - - switch (cmd) { - case DDI_DETACH: - break; - default: - return (DDI_FAILURE); - } - - instance = ddi_get_instance(dip); - if ((pvs = ddi_get_soft_state(pvscsi_sstate, instance)) == NULL) { - cmn_err(CE_WARN, "!failed to get soft state for instance %d", - instance); - return (DDI_FAILURE); - } - - pvscsi_reset_hba(pvs); - pvscsi_free_intr_resources(pvs); - - /* Shutdown message taskq */ - ddi_taskq_wait(pvs->msg_tq); - ddi_taskq_destroy(pvs->msg_tq); - - /* Shutdown completion taskq */ - ddi_taskq_wait(pvs->comp_tq); - ddi_taskq_destroy(pvs->comp_tq); - - /* Shutdown watchdog thread */ - mutex_enter(&pvs->mutex); - pvs->flags |= PVSCSI_DRIVER_SHUTDOWN; - cv_signal(&pvs->wd_condvar); - cv_wait(&pvs->syncvar, &pvs->mutex); - mutex_exit(&pvs->mutex); - - pvscsi_free_sg(pvs); - pvscsi_free_rings(pvs); - pvscsi_free_io(pvs); - - kmem_cache_destroy(pvs->cmd_cache); - - mutex_destroy(&pvs->mutex); - mutex_destroy(&pvs->intr_mutex); - mutex_destroy(&pvs->rx_mutex); - - cv_destroy(&pvs->syncvar); - cv_destroy(&pvs->wd_condvar); - cv_destroy(&pvs->quiescevar); - - ddi_soft_state_free(pvscsi_sstate, instance); - ddi_prop_remove_all(dip); - - return (DDI_SUCCESS); -} - -static int -pvscsi_ioctl(dev_t dev, int cmd, intptr_t data, int mode, cred_t *credp, - int *rval) -{ - int ret; - - if (ddi_get_soft_state(pvscsi_sstate, getminor(dev)) == NULL) { - cmn_err(CE_WARN, "!invalid device instance: %d", getminor(dev)); - return (ENXIO); - } - - /* Try to handle command in a common way */ - if ((ret = scsi_hba_ioctl(dev, cmd, data, mode, credp, rval)) != ENOTTY) - return (ret); - - cmn_err(CE_WARN, "!unsupported IOCTL command: 0x%X", cmd); - - return (ENXIO); -} - -static int -pvscsi_quiesce(dev_info_t *devi) -{ - scsi_hba_tran_t *tran; - pvscsi_softc_t *pvs; - - if ((tran = ddi_get_driver_private(devi)) == NULL) - return (DDI_SUCCESS); - - if ((pvs = tran->tran_hba_private) == NULL) - return (DDI_SUCCESS); - - /* Mask all interrupts from device */ - pvscsi_reg_write(pvs, PVSCSI_REG_OFFSET_INTR_MASK, 0); - - /* Reset the HBA */ - pvscsi_reset_hba(pvs); - - return (DDI_SUCCESS); -} - -/* module */ - -static struct cb_ops pvscsi_cb_ops = { - .cb_open = scsi_hba_open, - .cb_close = scsi_hba_close, - .cb_strategy = nodev, - .cb_print = nodev, - .cb_dump = nodev, - .cb_read = nodev, - .cb_write = nodev, - .cb_ioctl = pvscsi_ioctl, - .cb_devmap = nodev, - .cb_mmap = nodev, - .cb_segmap = nodev, - .cb_chpoll = nochpoll, - .cb_prop_op = ddi_prop_op, - .cb_str = NULL, - .cb_flag = D_MP, - .cb_rev = CB_REV, - .cb_aread = nodev, - .cb_awrite = nodev -}; - -static struct dev_ops pvscsi_ops = { - .devo_rev = DEVO_REV, - .devo_refcnt = 0, - .devo_getinfo = ddi_no_info, - .devo_identify = nulldev, - .devo_probe = nulldev, - .devo_attach = pvscsi_attach, - .devo_detach = pvscsi_detach, - .devo_reset = nodev, - .devo_cb_ops = &pvscsi_cb_ops, - .devo_bus_ops = NULL, - .devo_power = NULL, - .devo_quiesce = pvscsi_quiesce -}; - -#define PVSCSI_IDENT "VMware PVSCSI" - -static struct modldrv modldrv = { - &mod_driverops, - PVSCSI_IDENT, - &pvscsi_ops, -}; - -static struct modlinkage modlinkage = { - MODREV_1, - &modldrv, - NULL -}; - -int -_init(void) -{ - int ret; - - if ((ret = ddi_soft_state_init(&pvscsi_sstate, - sizeof (struct pvscsi_softc), PVSCSI_INITIAL_SSTATE_ITEMS)) != 0) { - cmn_err(CE_WARN, "!ddi_soft_state_init() failed"); - return (ret); - } - - if ((ret = scsi_hba_init(&modlinkage)) != 0) { - cmn_err(CE_WARN, "!scsi_hba_init() failed"); - ddi_soft_state_fini(&pvscsi_sstate); - return (ret); - } - - if ((ret = mod_install(&modlinkage)) != 0) { - cmn_err(CE_WARN, "!mod_install() failed"); - ddi_soft_state_fini(&pvscsi_sstate); - scsi_hba_fini(&modlinkage); - } - - return (ret); -} - -int -_info(struct modinfo *modinfop) -{ - return (mod_info(&modlinkage, modinfop)); -} - -int -_fini(void) -{ - int ret; - - if ((ret = mod_remove(&modlinkage)) == 0) { - ddi_soft_state_fini(&pvscsi_sstate); - scsi_hba_fini(&modlinkage); - } - - return (ret); -} diff --git a/usr/src/uts/intel/io/scsi/adapters/pvscsi/pvscsi_var.h b/usr/src/uts/intel/io/scsi/adapters/pvscsi/pvscsi_var.h deleted file mode 100644 index f675376556..0000000000 --- a/usr/src/uts/intel/io/scsi/adapters/pvscsi/pvscsi_var.h +++ /dev/null @@ -1,236 +0,0 @@ -/* - * This file and its contents are supplied under the terms of the - * Common Development and Distribution License ("CDDL"), version 1.0. - * You may only use this file in accordance with the terms of version - * 1.0 of the CDDL. - * - * A full copy of the text of the CDDL should have accompanied this - * source. A copy of the CDDL is also available via the Internet at - * http://www.illumos.org/license/CDDL. - */ - -/* - * Copyright 2016 Nexenta Systems, Inc. - */ - -#ifndef _PVSCSI_VAR_H_ -#define _PVSCSI_VAR_H_ - -typedef struct pvscsi_dma_buf { - ddi_dma_handle_t dma_handle; - caddr_t addr; - uint64_t pa; - size_t real_length; - ddi_acc_handle_t acc_handle; -} pvscsi_dma_buf_t; - -#define PVSCSI_TGT_PRIV_SIZE 2 - -#define PVSCSI_FLAG_CDB_EXT 0x0001 -#define PVSCSI_FLAG_SCB_EXT 0x0002 -#define PVSCSI_FLAG_PRIV_EXT 0x0004 -#define PVSCSI_FLAG_TAG 0x0008 -#define PVSCSI_FLAG_IO_READ 0x0010 -#define PVSCSI_FLAG_IO_IOPB 0x0040 -#define PVSCSI_FLAG_DONE 0x0080 -#define PVSCSI_FLAG_DMA_VALID 0x0100 -#define PVSCSI_FLAG_XARQ 0x0200 -#define PVSCSI_FLAG_HW_STATUS 0x0400 -#define PVSCSI_FLAG_TIMED_OUT 0x0800 -#define PVSCSI_FLAG_ABORTED 0x1000 -#define PVSCSI_FLAG_RESET_BUS 0x2000 -#define PVSCSI_FLAG_RESET_DEV 0x4000 -#define PVSCSI_FLAG_TRANSPORT 0x8000 - -/* Flags that must remain during SCSI packet retransmission */ -#define PVSCSI_FLAGS_PERSISTENT \ - (PVSCSI_FLAG_CDB_EXT |\ - PVSCSI_FLAG_SCB_EXT |\ - PVSCSI_FLAG_PRIV_EXT |\ - PVSCSI_FLAG_TAG |\ - PVSCSI_FLAG_IO_READ |\ - PVSCSI_FLAG_IO_IOPB |\ - PVSCSI_FLAG_DMA_VALID |\ - PVSCSI_FLAG_XARQ) - -#define PVSCSI_FLAGS_RESET \ - (PVSCSI_FLAG_RESET_BUS |\ - PVSCSI_FLAG_RESET_DEV) - -#define PVSCSI_FLAGS_NON_HW_COMPLETION \ - (PVSCSI_FLAG_TIMED_OUT |\ - PVSCSI_FLAG_ABORTED |\ - PVSCSI_FLAGS_RESET) - -#define PVSCSI_FLAGS_COMPLETION \ - (PVSCSI_FLAG_HW_STATUS |\ - PVSCSI_FLAGS_NON_HW_COMPLETION) - -#define PVSCSI_FLAGS_EXT \ - (PVSCSI_FLAG_CDB_EXT |\ - PVSCSI_FLAG_SCB_EXT |\ - PVSCSI_FLAG_PRIV_EXT) - -typedef struct pvscsi_cmd_ctx { - pvscsi_dma_buf_t dma_buf; - struct pvscsi_cmd *cmd; - list_node_t list; -} pvscsi_cmd_ctx_t; - -typedef struct pvscsi_cmp_desc_stat { - uchar_t scsi_status; - uint32_t host_status; - uint64_t data_len; -} pvscsi_cmp_desc_stat_t; - -#define PVSCSI_MAX_IO_PAGES 256 -#define PVSCSI_MAX_IO_SIZE (PVSCSI_MAX_IO_PAGES * PAGE_SIZE) -#define PVSCSI_MAX_SG_SIZE (PVSCSI_MAX_IO_PAGES + 1) - -typedef struct pvscsi_cmd { - struct scsi_pkt *pkt; - uint8_t cmd_cdb[SCSI_CDB_SIZE]; - struct scsi_arq_status cmd_scb; - uint64_t tgt_priv[PVSCSI_TGT_PRIV_SIZE]; - size_t tgtlen; - size_t cmdlen; - size_t statuslen; - uint8_t tag; - int flags; - ulong_t dma_count; - pvscsi_cmp_desc_stat_t cmp_stat; - pvscsi_cmd_ctx_t *ctx; - ddi_dma_handle_t cmd_dmahdl; - ddi_dma_cookie_t cmd_dmac; - uint_t cmd_dmaccount; - uint_t cmd_winindex; - uint_t cmd_nwin; - off_t cmd_dma_offset; - size_t cmd_dma_len; - uint_t cmd_dma_count; - uint_t cmd_total_dma_count; - int cmd_target; - list_node_t cmd_queue_node; - clock_t timeout_lbolt; - struct pvscsi_softc *cmd_pvs; - struct pvscsi_cmd *next_cmd; - struct pvscsi_cmd *tail_cmd; - struct buf *arqbuf; - ddi_dma_cookie_t arqc; - ddi_dma_handle_t arqhdl; - int cmd_rqslen; - struct scsi_pkt cached_pkt; - ddi_dma_cookie_t cached_cookies[PVSCSI_MAX_SG_SIZE]; -} pvscsi_cmd_t; - -#define AP2PRIV(ap) ((ap)->a_hba_tran->tran_hba_private) -#define CMD2PKT(cmd) ((struct scsi_pkt *)((cmd)->pkt)) -#define PKT2CMD(pkt) ((pvscsi_cmd_t *)((pkt)->pkt_ha_private)) -#define SDEV2PRIV(sd) ((sd)->sd_address.a_hba_tran->tran_hba_private) -#define TRAN2PRIV(tran) ((pvscsi_softc_t *)(tran)->tran_hba_private) - -#define CMD_CTX_SGLIST_VA(cmd_ctx) \ - ((struct PVSCSISGElement *) \ - (((pvscsi_cmd_ctx_t *)(cmd_ctx))->dma_buf.addr)) - -#define CMD_CTX_SGLIST_PA(cmd_ctx) \ - ((((pvscsi_cmd_ctx_t *)(cmd_ctx))->dma_buf.pa)) - -typedef struct pvscsi_msg { - struct pvscsi_softc *msg_pvs; - int type; - int target; -} pvscsi_msg_t; - -/* Driver-wide flags */ -#define PVSCSI_DRIVER_SHUTDOWN 0x01 -#define PVSCSI_HBA_QUIESCED 0x02 -#define PVSCSI_HBA_QUIESCE_PENDING 0x04 -#define PVSCSI_HBA_AUTO_REQUEST_SENSE 0x08 - -#define HBA_IS_QUIESCED(pvs) (((pvs)->flags & PVSCSI_HBA_QUIESCED) != 0) -#define HBA_QUIESCE_PENDING(pvs) \ - (((pvs)->flags & PVSCSI_HBA_QUIESCE_PENDING) != 0 && \ - ((pvs)->cmd_queue_len == 0)) - -typedef struct pvscsi_softc { - dev_info_t *dip; - int instance; - scsi_hba_tran_t *tran; - ddi_dma_attr_t hba_dma_attr; - ddi_dma_attr_t io_dma_attr; - ddi_dma_attr_t ring_dma_attr; - pvscsi_dma_buf_t rings_state_buf; - pvscsi_dma_buf_t req_ring_buf; - uint_t req_pages; - uint_t req_depth; - pvscsi_dma_buf_t cmp_ring_buf; - uint_t cmp_pages; - pvscsi_dma_buf_t msg_ring_buf; - uint_t msg_pages; - ddi_acc_handle_t pci_config_handle; - ddi_acc_handle_t mmio_handle; - caddr_t mmio_base; - int intr_type; - int intr_size; - int intr_cnt; - int intr_pri; - int flags; - ddi_intr_handle_t *intr_htable; - pvscsi_cmd_ctx_t *cmd_ctx; - list_t cmd_ctx_pool; - list_t cmd_queue; - int cmd_queue_len; - kcondvar_t wd_condvar; - kmutex_t mutex; - kmutex_t rx_mutex; - kmutex_t tx_mutex; - kmutex_t intr_mutex; - struct kmem_cache *cmd_cache; - list_t devnodes; - kcondvar_t syncvar; - kcondvar_t quiescevar; - kthread_t *wd_thread; - int intr_lock_counter; - int num_pollers; - ddi_taskq_t *comp_tq; - ddi_taskq_t *msg_tq; -} pvscsi_softc_t; - -typedef struct pvscsi_device { - list_node_t list; - int target; - dev_info_t *pdip; - dev_info_t *parent; -} pvscsi_device_t; - -#define REQ_RING(pvs) \ - ((struct PVSCSIRingReqDesc *) \ - (((pvscsi_softc_t *)(pvs))->req_ring_buf.addr)) - -#define CMP_RING(pvs) \ - ((struct PVSCSIRingCmpDesc *) \ - (((pvscsi_softc_t *)(pvs))->cmp_ring_buf.addr)) - -#define MSG_RING(pvs) \ - ((struct PVSCSIRingMsgDesc *) \ - (((pvscsi_softc_t *)(pvs))->msg_ring_buf.addr)) - -#define RINGS_STATE(pvs) \ - ((struct PVSCSIRingsState *)(((pvscsi_softc_t *)\ - (pvs))->rings_state_buf.addr)) - -#define PVSCSI_INITIAL_SSTATE_ITEMS 16 - -#define SENSE_BUFFER_SIZE SENSE_LENGTH -#define USECS_TO_WAIT 1000 - -#define PVSCSI_MAXTGTS 16 - -#define PAGE_SIZE 4096 -#define PAGE_SHIFT 12 - -#define PVSCSI_DEFAULT_NUM_PAGES_PER_RING 8 -#define PVSCSI_DEFAULT_NUM_PAGES_MSG_RING 1 - -#endif /* _PVSCSI_VAR_H_ */ diff --git a/usr/src/uts/sparc/Makefile.sparc b/usr/src/uts/sparc/Makefile.sparc index ec7b4441a8..52de9c61c9 100644 --- a/usr/src/uts/sparc/Makefile.sparc +++ b/usr/src/uts/sparc/Makefile.sparc @@ -351,7 +351,7 @@ DRV_KMODS += pcic # # Exec Class Modules (/kernel/exec): # -EXEC_KMODS += aoutexec elfexec intpexec shbinexec javaexec +EXEC_KMODS += elfexec intpexec shbinexec javaexec # # Scheduling Class Modules (/kernel/sched): diff --git a/usr/src/uts/sparc/aoutexec/Makefile b/usr/src/uts/sparc/aoutexec/Makefile deleted file mode 100644 index 225726fc7c..0000000000 --- a/usr/src/uts/sparc/aoutexec/Makefile +++ /dev/null @@ -1,88 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. -# -# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. -# See the License for the specific language governing permissions -# and limitations under the License. -# -# When distributing Covered Code, include this CDDL HEADER in each -# file and include the License file at usr/src/OPENSOLARIS.LICENSE. -# If applicable, add the following below this CDDL HEADER, with the -# fields enclosed by brackets "[]" replaced with your own identifying -# information: Portions Copyright [yyyy] [name of copyright owner] -# -# CDDL HEADER END -# -# -# uts/sparc/aoutexec/Makefile -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# Copyright (c) 2011 Bayard G. Bell. All rights reserved. -# -# This makefile drives the production of the aoutexec exec kernel -# module (binary compatibility). -# -# 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 = aoutexec -OBJECTS = $(AOUTEXEC_OBJS:%=$(OBJS_DIR)/%) -ROOTMODULE = $(ROOT_EXEC_DIR)/$(MODULE) - -# -# Include common rules. -# -include $(UTSBASE)/sparc/Makefile.sparc - -# -# Define targets -# -ALL_TARGET = $(BINARY) -INSTALL_TARGET = $(BINARY) $(ROOTMODULE) - -# -# For now, disable these warnings; maintainers should endeavor -# to investigate and remove these for maximum coverage. -# Please do not carry these forward to new Makefiles. -# -CFLAGS += $(CCVERBOSE) -CERRWARN += -_gcc=-Wno-parentheses - -# -# Define dependency on elfexec -# -LDFLAGS += -N exec/elfexec - -# -# Default build targets. -# -.KEEP_STATE: - -def: $(DEF_DEPS) - -all: $(ALL_DEPS) - -clean: $(CLEAN_DEPS) - -clobber: $(CLOBBER_DEPS) - -install: $(INSTALL_DEPS) - -# -# Include common targets. -# -include $(UTSBASE)/sparc/Makefile.targ diff --git a/usr/src/uts/sun4/vm/vm_dep.c b/usr/src/uts/sun4/vm/vm_dep.c index 835d321c1d..1243162085 100644 --- a/usr/src/uts/sun4/vm/vm_dep.c +++ b/usr/src/uts/sun4/vm/vm_dep.c @@ -22,6 +22,7 @@ * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * Copyright 2016 Joyent, Inc. + * Copyright 2022 Garrett D'Amore <garrett@damore.org> */ /* @@ -426,82 +427,6 @@ chkaout(struct exdata *exp) return (ENOEXEC); } -/* - * The following functions return information about an a.out - * which is used when a program is executed. - */ - -/* - * Return the load memory address for the data segment. - */ -caddr_t -getdmem(struct exec *exp) -{ - /* - * XXX - Sparc Reference Hack approaching - * Remember that we are loading - * 8k executables into a 4k machine - * DATA_ALIGN == 2 * PAGESIZE - */ - if (exp->a_text) - return ((caddr_t)(roundup(USRTEXT + exp->a_text, DATA_ALIGN))); - else - return ((caddr_t)USRTEXT); -} - -/* - * Return the starting disk address for the data segment. - */ -ulong_t -getdfile(struct exec *exp) -{ - if (exp->a_magic == ZMAGIC) - return (exp->a_text); - else - return (sizeof (struct exec) + exp->a_text); -} - -/* - * Return the load memory address for the text segment. - */ - -/*ARGSUSED*/ -caddr_t -gettmem(struct exec *exp) -{ - return ((caddr_t)USRTEXT); -} - -/* - * Return the file byte offset for the text segment. - */ -uint_t -gettfile(struct exec *exp) -{ - if (exp->a_magic == ZMAGIC) - return (0); - else - return (sizeof (struct exec)); -} - -void -getexinfo( - struct exdata *edp_in, - struct exdata *edp_out, - int *pagetext, - int *pagedata) -{ - *edp_out = *edp_in; /* structure copy */ - - if ((edp_in->ux_mag == ZMAGIC) && - ((edp_in->vp->v_flag & VNOMAP) == 0)) { - *pagetext = 1; - *pagedata = 1; - } else { - *pagetext = 0; - *pagedata = 0; - } -} /* * Return non 0 value if the address may cause a VAC alias with KPM mappings. @@ -747,7 +672,7 @@ map_pgszcvec(caddr_t addr, size_t size, uintptr_t off, int flags, int type, * * page_counters[page_size][region_size] * - * page_size: TTE size code of pages on page_size freelist. + * page_size: TTE size code of pages on page_size freelist. * * region_size: TTE size code of a candidate larger page made up * made up of contiguous free page_size pages. @@ -757,7 +682,7 @@ map_pgszcvec(caddr_t addr, size_t size, uintptr_t off, int flags, int type, * made up of page_size free pages can be coalesced into a * regsion_size page. Yuck! Lets try an example: * - * page_counters[1][3] is the table element used for identifying + * page_counters[1][3] is the table element used for identifying * candidate 4M pages from contiguous pages off the 64K free list. * Each index in the page_counters[1][3].array spans 4M. Its the * number of free 512K size (regsion_size - 1) groups of contiguous |