summaryrefslogtreecommitdiff
path: root/drivers/staging/unisys
diff options
context:
space:
mode:
authorAndré Fabian Silva Delgado <emulatorman@parabola.nu>2015-09-08 01:01:14 -0300
committerAndré Fabian Silva Delgado <emulatorman@parabola.nu>2015-09-08 01:01:14 -0300
commite5fd91f1ef340da553f7a79da9540c3db711c937 (patch)
treeb11842027dc6641da63f4bcc524f8678263304a3 /drivers/staging/unisys
parent2a9b0348e685a63d97486f6749622b61e9e3292f (diff)
Linux-libre 4.2-gnu
Diffstat (limited to 'drivers/staging/unisys')
-rw-r--r--drivers/staging/unisys/Kconfig10
-rw-r--r--drivers/staging/unisys/Makefile8
-rw-r--r--drivers/staging/unisys/common-spar/include/channels/controlframework.h62
-rw-r--r--drivers/staging/unisys/common-spar/include/channels/diagchannel.h427
-rw-r--r--drivers/staging/unisys/common-spar/include/diagnostics/appos_subsystems.h310
-rw-r--r--drivers/staging/unisys/include/channel.h (renamed from drivers/staging/unisys/common-spar/include/channels/channel.h)35
-rw-r--r--drivers/staging/unisys/include/channel_guid.h (renamed from drivers/staging/unisys/common-spar/include/channels/channel_guid.h)0
-rw-r--r--drivers/staging/unisys/include/diagchannel.h43
-rw-r--r--drivers/staging/unisys/include/guestlinuxdebug.h3
-rw-r--r--drivers/staging/unisys/include/iochannel.h (renamed from drivers/staging/unisys/common-spar/include/channels/iochannel.h)450
-rw-r--r--drivers/staging/unisys/include/periodic_work.h10
-rw-r--r--drivers/staging/unisys/include/procobjecttree.h47
-rw-r--r--drivers/staging/unisys/include/sparstop.h30
-rw-r--r--drivers/staging/unisys/include/timskmod.h153
-rw-r--r--drivers/staging/unisys/include/uisqueue.h396
-rw-r--r--drivers/staging/unisys/include/uisthread.h42
-rw-r--r--drivers/staging/unisys/include/uisutils.h299
-rw-r--r--drivers/staging/unisys/include/vbushelper.h2
-rw-r--r--drivers/staging/unisys/include/version.h (renamed from drivers/staging/unisys/common-spar/include/version.h)0
-rw-r--r--drivers/staging/unisys/include/visorbus.h222
-rw-r--r--drivers/staging/unisys/uislib/Kconfig10
-rw-r--r--drivers/staging/unisys/uislib/Makefile12
-rw-r--r--drivers/staging/unisys/uislib/uislib.c1372
-rw-r--r--drivers/staging/unisys/uislib/uisqueue.c322
-rw-r--r--drivers/staging/unisys/uislib/uisthread.c69
-rw-r--r--drivers/staging/unisys/uislib/uisutils.c137
-rw-r--r--drivers/staging/unisys/virthba/Kconfig13
-rw-r--r--drivers/staging/unisys/virthba/Makefile12
-rw-r--r--drivers/staging/unisys/virthba/virthba.c1572
-rw-r--r--drivers/staging/unisys/virthba/virthba.h27
-rw-r--r--drivers/staging/unisys/virtpci/Kconfig10
-rw-r--r--drivers/staging/unisys/virtpci/Makefile10
-rw-r--r--drivers/staging/unisys/virtpci/virtpci.c1394
-rw-r--r--drivers/staging/unisys/virtpci/virtpci.h103
-rw-r--r--drivers/staging/unisys/visorbus/Kconfig9
-rw-r--r--drivers/staging/unisys/visorbus/Makefile13
-rw-r--r--drivers/staging/unisys/visorbus/controlvmchannel.h (renamed from drivers/staging/unisys/common-spar/include/channels/controlvmchannel.h)304
-rw-r--r--drivers/staging/unisys/visorbus/controlvmcompletionstatus.h (renamed from drivers/staging/unisys/common-spar/include/controlvmcompletionstatus.h)0
-rw-r--r--drivers/staging/unisys/visorbus/iovmcall_gnuc.h (renamed from drivers/staging/unisys/common-spar/include/iovmcall_gnuc.h)0
-rw-r--r--drivers/staging/unisys/visorbus/periodic_work.c (renamed from drivers/staging/unisys/visorutil/periodic_work.c)56
-rw-r--r--drivers/staging/unisys/visorbus/vbuschannel.h (renamed from drivers/staging/unisys/common-spar/include/channels/vbuschannel.h)2
-rw-r--r--drivers/staging/unisys/visorbus/vbusdeviceinfo.h (renamed from drivers/staging/unisys/common-spar/include/vbusdeviceinfo.h)0
-rw-r--r--drivers/staging/unisys/visorbus/visorbus_main.c1518
-rw-r--r--drivers/staging/unisys/visorbus/visorbus_private.h69
-rw-r--r--drivers/staging/unisys/visorbus/visorchannel.c (renamed from drivers/staging/unisys/visorchannel/visorchannel_funcs.c)468
-rw-r--r--drivers/staging/unisys/visorbus/visorchipset.c (renamed from drivers/staging/unisys/visorchipset/visorchipset_main.c)1552
-rw-r--r--drivers/staging/unisys/visorbus/vmcallinterface.h (renamed from drivers/staging/unisys/common-spar/include/vmcallinterface.h)16
-rw-r--r--drivers/staging/unisys/visorchannel/Kconfig10
-rw-r--r--drivers/staging/unisys/visorchannel/Makefile12
-rw-r--r--drivers/staging/unisys/visorchannel/globals.h27
-rw-r--r--drivers/staging/unisys/visorchannel/visorchannel.h76
-rw-r--r--drivers/staging/unisys/visorchannel/visorchannel_main.c50
-rw-r--r--drivers/staging/unisys/visorchipset/Kconfig11
-rw-r--r--drivers/staging/unisys/visorchipset/Makefile15
-rw-r--r--drivers/staging/unisys/visorchipset/file.c160
-rw-r--r--drivers/staging/unisys/visorchipset/file.h27
-rw-r--r--drivers/staging/unisys/visorchipset/globals.h42
-rw-r--r--drivers/staging/unisys/visorchipset/parser.c430
-rw-r--r--drivers/staging/unisys/visorchipset/parser.h46
-rw-r--r--drivers/staging/unisys/visorchipset/visorchipset.h236
-rw-r--r--drivers/staging/unisys/visorchipset/visorchipset_umode.h35
-rw-r--r--drivers/staging/unisys/visornic/Kconfig15
-rw-r--r--drivers/staging/unisys/visornic/Makefile10
-rw-r--r--drivers/staging/unisys/visornic/visornic_main.c2140
-rw-r--r--drivers/staging/unisys/visorutil/Kconfig9
-rw-r--r--drivers/staging/unisys/visorutil/Makefile9
-rw-r--r--drivers/staging/unisys/visorutil/charqueue.c127
-rw-r--r--drivers/staging/unisys/visorutil/charqueue.h37
-rw-r--r--drivers/staging/unisys/visorutil/memregion.h43
-rw-r--r--drivers/staging/unisys/visorutil/memregion_direct.c207
-rw-r--r--drivers/staging/unisys/visorutil/visorkmodutils.c71
71 files changed, 5411 insertions, 10053 deletions
diff --git a/drivers/staging/unisys/Kconfig b/drivers/staging/unisys/Kconfig
index 19fcb3465..778f9d05f 100644
--- a/drivers/staging/unisys/Kconfig
+++ b/drivers/staging/unisys/Kconfig
@@ -4,16 +4,14 @@
menuconfig UNISYSSPAR
bool "Unisys SPAR driver support"
depends on X86_64
+ select PCI
+ select ACPI
---help---
Support for the Unisys SPAR drivers
if UNISYSSPAR
-source "drivers/staging/unisys/visorutil/Kconfig"
-source "drivers/staging/unisys/visorchannel/Kconfig"
-source "drivers/staging/unisys/visorchipset/Kconfig"
-source "drivers/staging/unisys/uislib/Kconfig"
-source "drivers/staging/unisys/virtpci/Kconfig"
-source "drivers/staging/unisys/virthba/Kconfig"
+source "drivers/staging/unisys/visorbus/Kconfig"
+source "drivers/staging/unisys/visornic/Kconfig"
endif # UNISYSSPAR
diff --git a/drivers/staging/unisys/Makefile b/drivers/staging/unisys/Makefile
index 68b9925e7..a515ebc4f 100644
--- a/drivers/staging/unisys/Makefile
+++ b/drivers/staging/unisys/Makefile
@@ -1,9 +1,5 @@
#
# Makefile for Unisys SPAR drivers
#
-obj-$(CONFIG_UNISYS_VISORUTIL) += visorutil/
-obj-$(CONFIG_UNISYS_VISORCHANNEL) += visorchannel/
-obj-$(CONFIG_UNISYS_VISORCHIPSET) += visorchipset/
-obj-$(CONFIG_UNISYS_UISLIB) += uislib/
-obj-$(CONFIG_UNISYS_VIRTPCI) += virtpci/
-obj-$(CONFIG_UNISYS_VIRTHBA) += virthba/
+obj-$(CONFIG_UNISYS_VISORBUS) += visorbus/
+obj-$(CONFIG_UNISYS_VISORNIC) += visornic/
diff --git a/drivers/staging/unisys/common-spar/include/channels/controlframework.h b/drivers/staging/unisys/common-spar/include/channels/controlframework.h
deleted file mode 100644
index 33d9caf33..000000000
--- a/drivers/staging/unisys/common-spar/include/channels/controlframework.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/* Copyright (C) 2010 - 2013 UNISYS CORPORATION
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
- * NON INFRINGEMENT. See the GNU General Public License for more
- * details.
- */
-
-/*
- * Module Name:
- * controlframework.h
- *
- * Abstract: This file defines common structures in the unmanaged
- * Ultravisor (mostly EFI) space.
- *
- */
-
-#ifndef _CONTROL_FRAMEWORK_H_
-#define _CONTROL_FRAMEWORK_H_
-
-#include <linux/types.h>
-#include "channel.h"
-
-struct spar_segment_state {
- u16 enabled:1; /* Bit 0: May enter other states */
- u16 active:1; /* Bit 1: Assigned to active partition */
- u16 alive:1; /* Bit 2: Configure message sent to
- * service/server */
- u16 revoked:1; /* Bit 3: similar to partition state
- * ShuttingDown */
- u16 allocated:1; /* Bit 4: memory (device/port number)
- * has been selected by Command */
- u16 known:1; /* Bit 5: has been introduced to the
- * service/guest partition */
- u16 ready:1; /* Bit 6: service/Guest partition has
- * responded to introduction */
- u16 operating:1; /* Bit 7: resource is configured and
- * operating */
- /* Note: don't use high bit unless we need to switch to ushort
- * which is non-compliant */
-};
-
-static const struct spar_segment_state segment_state_running = {
- 1, 1, 1, 0, 1, 1, 1, 1
-};
-
-static const struct spar_segment_state segment_state_paused = {
- 1, 1, 1, 0, 1, 1, 1, 0
-};
-
-static const struct spar_segment_state segment_state_standby = {
- 1, 1, 0, 0, 1, 1, 1, 0
-};
-
-#endif /* _CONTROL_FRAMEWORK_H_ not defined */
diff --git a/drivers/staging/unisys/common-spar/include/channels/diagchannel.h b/drivers/staging/unisys/common-spar/include/channels/diagchannel.h
deleted file mode 100644
index e8fb8678a..000000000
--- a/drivers/staging/unisys/common-spar/include/channels/diagchannel.h
+++ /dev/null
@@ -1,427 +0,0 @@
-/* Copyright (C) 2010 - 2013 UNISYS CORPORATION
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
- * NON INFRINGEMENT. See the GNU General Public License for more
- * details.
- */
-
-/*++
- *
- * Module Name:
- *
- * diagchannel.h
- *
- * Abstract:
- *
- * This file defines the DiagChannel protocol. This protocol is used to aid in
- * preserving event data sent by external applications. This protocol provides
- * a region for event data to reside in. This data will eventually be sent to
- * the Boot Partition where it will be committed to memory and/or disk. This
- * file contains platform-independent data that can be built using any
- * Supervisor build environment (Windows, Linux, EFI).
- *
-*/
-
-#ifndef _DIAG_CHANNEL_H_
-#define _DIAG_CHANNEL_H_
-
-#include <linux/uuid.h>
-#include "channel.h"
-
-/* {EEA7A573-DB82-447c-8716-EFBEAAAE4858} */
-#define SPAR_DIAG_CHANNEL_PROTOCOL_UUID \
- UUID_LE(0xeea7a573, 0xdb82, 0x447c, \
- 0x87, 0x16, 0xef, 0xbe, 0xaa, 0xae, 0x48, 0x58)
-
-static const uuid_le spar_diag_channel_protocol_uuid =
- SPAR_DIAG_CHANNEL_PROTOCOL_UUID;
-
-/* {E850F968-3263-4484-8CA5-2A35D087A5A8} */
-#define ULTRA_DIAG_ROOT_CHANNEL_PROTOCOL_GUID \
- UUID_LE(0xe850f968, 0x3263, 0x4484, \
- 0x8c, 0xa5, 0x2a, 0x35, 0xd0, 0x87, 0xa5, 0xa8)
-
-#define ULTRA_DIAG_CHANNEL_PROTOCOL_SIGNATURE ULTRA_CHANNEL_PROTOCOL_SIGNATURE
-
-/* Must increment this whenever you insert or delete fields within this channel
-* struct. Also increment whenever you change the meaning of fields within this
-* channel struct so as to break pre-existing software. Note that you can
-* usually add fields to the END of the channel struct withOUT needing to
-* increment this. */
-#define ULTRA_DIAG_CHANNEL_PROTOCOL_VERSIONID 2
-
-#define SPAR_DIAG_CHANNEL_OK_CLIENT(ch)\
- (spar_check_channel_client(ch,\
- spar_diag_channel_protocol_uuid,\
- "diag",\
- sizeof(struct spar_diag_channel_protocol),\
- ULTRA_DIAG_CHANNEL_PROTOCOL_VERSIONID,\
- ULTRA_DIAG_CHANNEL_PROTOCOL_SIGNATURE))
-
-#define SPAR_DIAG_CHANNEL_OK_SERVER(bytes)\
- (spar_check_channel_server(spar_diag_channel_protocol_uuid,\
- "diag",\
- sizeof(struct spar_diag_channel_protocol),\
- bytes))
-
-#define MAX_MODULE_NAME_SIZE 128 /* Maximum length of module name... */
-#define MAX_ADDITIONAL_INFO_SIZE 256 /* Maximum length of any additional info
- * accompanying event... */
-#define MAX_SUBSYSTEMS 64 /* Maximum number of subsystems allowed in
- * DiagChannel... */
-#define LOW_SUBSYSTEMS 32 /* Half of MAX_SUBSYSTEMS to allow 64-bit
- * math */
-#define SUBSYSTEM_DEBUG 0 /* Standard subsystem for debug events */
-#define SUBSYSTEM_DEFAULT 1 /* Default subsystem for legacy calls to
- * ReportEvent */
-
-/* few useful subsystem mask values */
-#define SUBSYSTEM_MASK_DEBUG 0x01 /* Standard subsystem for debug
- * events */
-#define SUBSYSTEM_MASK_DEFAULT 0x02 /* Default subsystem for legacy calls to
- * ReportEvents */
-
-/* Event parameter "Severity" is overloaded with Cause in byte 2 and Severity in
- * byte 0, bytes 1 and 3 are reserved */
-#define SEVERITY_MASK 0x0FF /* mask out all but the Severity in byte 0 */
-#define CAUSE_MASK 0x0FF0000 /* mask out all but the cause in byte 2 */
-#define CAUSE_SHIFT_AMT 16 /* shift 2 bytes to place it in byte 2 */
-
-/* SubsystemSeverityFilter */
-#define SEVERITY_FILTER_MASK 0x0F /* mask out the Cause half, SeverityFilter is
- * in the lower nibble */
-#define CAUSE_FILTER_MASK 0xF0 /* mask out the Severity half, CauseFilter is in
- * the upper nibble */
-#define CAUSE_FILTER_SHIFT_AMT 4 /* shift amount to place it in lower or upper
- * nibble */
-
-/* Copied from EFI's EFI_TIME struct in efidef.h. EFI headers are not allowed
-* in some of the Supervisor areas, such as Monitor, so it has been "ported" here
-* for use in diagnostic event timestamps... */
-struct diag_efi_time {
- u16 year; /* 1998 - 20XX */
- u8 month; /* 1 - 12 */
- u8 day; /* 1 - 31 */
- u8 hour; /* 0 - 23 */
- u8 minute; /* 0 - 59 */
- u8 second; /* 0 - 59 */
- u8 pad1;
- u32 nanosecond; /* 0 - 999, 999, 999 */
- s16 timezone; /* -1440 to 1440 or 2047 */
- u8 daylight;
- u8 pad2;
-};
-
-enum spar_component_types {
- ULTRA_COMPONENT_GUEST = 0,
- ULTRA_COMPONENT_MONITOR = 0x01,
- ULTRA_COMPONENT_CCM = 0x02, /* Common Control module */
- /* RESERVED 0x03 - 0x7 */
-
- /* Ultravisor Components */
- ULTRA_COMPONENT_BOOT = 0x08,
- ULTRA_COMPONENT_IDLE = 0x09,
- ULTRA_COMPONENT_CONTROL = 0x0A,
- ULTRA_COMPONENT_LOGGER = 0x0B,
- ULTRA_COMPONENT_ACPI = 0X0C,
- /* RESERVED 0x0D - 0x0F */
-
- /* sPAR Components */
- ULTRA_COMPONENT_COMMAND = 0x10,
- ULTRA_COMPONENT_IODRIVER = 0x11,
- ULTRA_COMPONENT_CONSOLE = 0x12,
- ULTRA_COMPONENT_OPERATIONS = 0x13,
- ULTRA_COMPONENT_MANAGEMENT = 0x14,
- ULTRA_COMPONENT_DIAG = 0x15,
- ULTRA_COMPONENT_HWDIAG = 0x16,
- ULTRA_COMPONENT_PSERVICES = 0x17,
- ULTRA_COMPONENT_PDIAG = 0x18
- /* RESERVED 0x18 - 0x1F */
-};
-
-/* Structure: diag_channel_event Purpose: Contains attributes that make up an
- * event to be written to the DIAG_CHANNEL memory. Attributes: EventId: Id of
- * the diagnostic event to write to memory. Severity: Severity of the event
- * (Error, Info, etc). ModuleName: Module/file name where event originated.
- * LineNumber: Line number in module name where event originated. Timestamp:
- * Date/time when event was received by ReportEvent, and written to DiagChannel.
- * Reserved: Padding to align structure on a 64-byte cache line boundary.
- * AdditionalInfo: Array of characters for additional event info (may be
- * empty). */
-struct diag_channel_event {
- u32 event_id;
- u32 severity;
- u8 module_name[MAX_MODULE_NAME_SIZE];
- u32 line_number;
- struct diag_efi_time timestamp; /* Size = 16 bytes */
- u32 partition_number; /* Filled in by Diag Switch as pool blocks are
- * filled */
- u16 vcpu_number;
- u16 lcpu_number;
- u8 component_type; /* ULTRA_COMPONENT_TYPES */
- u8 subsystem;
- u16 reserved0; /* pad to u64 alignment */
- u32 block_no; /* filled in by DiagSwitch as pool blocks are
- * filled */
- u32 block_no_high;
- u32 event_no; /* filled in by DiagSwitch as pool blocks are
- * filled */
- u32 event_no_high;
-
- /* The block_no and event_no fields are set only by DiagSwitch
- * and referenced only by WinDiagDisplay formatting tool as
- * additional diagnostic information. Other tools including
- * WinDiagDisplay currently ignore these 'Reserved' bytes. */
- u8 reserved[8];
- u8 additional_info[MAX_ADDITIONAL_INFO_SIZE];
-
- /* NOTE: Changes to diag_channel_event generally need to be reflected in
- * existing copies *
- * - for AppOS at
- * GuestLinux/visordiag_early/supervisor_diagchannel.h *
- * - for WinDiagDisplay at
- * EFI/Ultra/Tools/WinDiagDisplay/WinDiagDisplay/diagstruct.h */
-};
-
-/* Levels of severity for diagnostic events, in order from lowest severity to
-* highest (i.e. fatal errors are the most severe, and should always be logged,
-* but info events rarely need to be logged except during debugging). The values
-* DIAG_SEVERITY_ENUM_BEGIN and DIAG_SEVERITY_ENUM_END are not valid severity
-* values. They exist merely to dilineate the list, so that future additions
-* won't require changes to the driver (i.e. when checking for out-of-range
-* severities in SetSeverity). The values DIAG_SEVERITY_OVERRIDE and
-* DIAG_SEVERITY_SHUTOFF are not valid severity values for logging events but
-* they are valid for controlling the amount of event data. This enum is also
-* defined in DotNet\sParFramework\ControlFramework\ControlFramework.cs. If a
-* change is made to this enum, they should also be reflected in that file. */
-enum diag_severity {
- DIAG_SEVERITY_ENUM_BEGIN = 0,
- DIAG_SEVERITY_OVERRIDE = DIAG_SEVERITY_ENUM_BEGIN,
- DIAG_SEVERITY_VERBOSE = DIAG_SEVERITY_OVERRIDE, /* 0 */
- DIAG_SEVERITY_INFO = DIAG_SEVERITY_VERBOSE + 1, /* 1 */
- DIAG_SEVERITY_WARNING = DIAG_SEVERITY_INFO + 1, /* 2 */
- DIAG_SEVERITY_ERR = DIAG_SEVERITY_WARNING + 1, /* 3 */
- DIAG_SEVERITY_PRINT = DIAG_SEVERITY_ERR + 1, /* 4 */
- DIAG_SEVERITY_SHUTOFF = DIAG_SEVERITY_PRINT + 1, /* 5 */
- DIAG_SEVERITY_ENUM_END = DIAG_SEVERITY_SHUTOFF, /* 5 */
- DIAG_SEVERITY_NONFATAL_ERR = DIAG_SEVERITY_ERR,
- DIAG_SEVERITY_FATAL_ERR = DIAG_SEVERITY_PRINT
-};
-
-/* Event Cause enums
-*
-* Levels of cause for diagnostic events, in order from least to greatest cause
-* Internal errors are most urgent since ideally they should never exist
-* Invalid requests are preventable by avoiding invalid inputs
-* Operations errors depend on environmental factors which may impact which
-* requests are possible
-* Manifest provides intermediate value to capture firmware and configuration
-* version information
-* Trace provides suplimental debug information in release firmware
-* Unknown Log captures unclasified LogEvent calls.
-* Debug is the least urgent since it provides suplimental debug information only
-* in debug firmware
-* Unknown Debug captures unclassified DebugEvent calls.
-* This enum is also defined in
-* DotNet\sParFramework\ControlFramework\ControlFramework.cs.
-* If a change is made to this enum, they should also be reflected in that
-* file. */
-
-/* A cause value "DIAG_CAUSE_FILE_XFER" together with a severity value of
-* "DIAG_SEVERITY_PRINT" (=4), is used for transferring text or binary file to
-* the Diag partition. This cause-severity combination will be used by Logger
-* DiagSwitch to segregate events into block types. The files are transferred in
-* 256 byte chunks maximum, in the AdditionalInfo field of the diag_channel_event
-* structure. In the file transfer mode, some event fields will have different
-* meaning: EventId specifies the file offset, severity specifies the block type,
-* ModuleName specifies the filename, LineNumber specifies the number of valid
-* data bytes in an event and AdditionalInfo contains up to 256 bytes of data. */
-
-/* The Diag DiagWriter appends event blocks to events.raw as today, and for data
- * blocks uses diag_channel_event
- * PartitionNumber to extract and append 'AdditionalInfo' to filename (specified
- * by ModuleName). */
-
-/* The Dell PDiag uses this new mechanism to stash DSET .zip onto the
- * 'diagnostic' virtual disk. */
-enum diag_cause {
- DIAG_CAUSE_UNKNOWN = 0,
- DIAG_CAUSE_UNKNOWN_DEBUG = DIAG_CAUSE_UNKNOWN + 1, /* 1 */
- DIAG_CAUSE_DEBUG = DIAG_CAUSE_UNKNOWN_DEBUG + 1, /* 2 */
- DIAG_CAUSE_UNKNOWN_LOG = DIAG_CAUSE_DEBUG + 1, /* 3 */
- DIAG_CAUSE_TRACE = DIAG_CAUSE_UNKNOWN_LOG + 1, /* 4 */
- DIAG_CAUSE_MANIFEST = DIAG_CAUSE_TRACE + 1, /* 5 */
- DIAG_CAUSE_OPERATIONS_ERROR = DIAG_CAUSE_MANIFEST + 1, /* 6 */
- DIAG_CAUSE_INVALID_REQUEST = DIAG_CAUSE_OPERATIONS_ERROR + 1, /* 7 */
- DIAG_CAUSE_INTERNAL_ERROR = DIAG_CAUSE_INVALID_REQUEST + 1, /* 8 */
- DIAG_CAUSE_FILE_XFER = DIAG_CAUSE_INTERNAL_ERROR + 1, /* 9 */
- DIAG_CAUSE_ENUM_END = DIAG_CAUSE_FILE_XFER /* 9 */
-};
-
-/* Event Cause category defined into the byte 2 of Severity */
-#define CAUSE_DEBUG (DIAG_CAUSE_DEBUG << CAUSE_SHIFT_AMT)
-#define CAUSE_TRACE (DIAG_CAUSE_TRACE << CAUSE_SHIFT_AMT)
-#define CAUSE_MANIFEST (DIAG_CAUSE_MANIFEST << CAUSE_SHIFT_AMT)
-#define CAUSE_OPERATIONS_ERROR (DIAG_CAUSE_OPERATIONS_ERROR << CAUSE_SHIFT_AMT)
-#define CAUSE_INVALID_REQUEST (DIAG_CAUSE_INVALID_REQUEST << CAUSE_SHIFT_AMT)
-#define CAUSE_INTERNAL_ERROR (DIAG_CAUSE_INTERNAL_ERROR << CAUSE_SHIFT_AMT)
-#define CAUSE_FILE_XFER (DIAG_CAUSE_FILE_XFER << CAUSE_SHIFT_AMT)
-#define CAUSE_ENUM_END CAUSE_FILE_XFER
-
-/* Combine Cause and Severity categories into one */
-#define CAUSE_DEBUG_SEVERITY_VERBOSE \
- (CAUSE_DEBUG | DIAG_SEVERITY_VERBOSE)
-#define CAUSE_TRACE_SEVERITY_VERBOSE \
- (CAUSE_TRACE | DIAG_SEVERITY_VERBOSE)
-#define CAUSE_MANIFEST_SEVERITY_VERBOSE\
- (CAUSE_MANIFEST | DIAG_SEVERITY_VERBOSE)
-#define CAUSE_OPERATIONS_SEVERITY_VERBOSE \
- (CAUSE_OPERATIONS_ERROR | DIAG_SEVERITY_VERBOSE)
-#define CAUSE_INVALID_SEVERITY_VERBOSE \
- (CAUSE_INVALID_REQUEST | DIAG_SEVERITY_VERBOSE)
-#define CAUSE_INTERNAL_SEVERITY_VERBOSE \
- (CAUSE_INTERNAL_ERROR | DIAG_SEVERITY_VERBOSE)
-
-#define CAUSE_DEBUG_SEVERITY_INFO \
- (CAUSE_DEBUG | DIAG_SEVERITY_INFO)
-#define CAUSE_TRACE_SEVERITY_INFO \
- (CAUSE_TRACE | DIAG_SEVERITY_INFO)
-#define CAUSE_MANIFEST_SEVERITY_INFO \
- (CAUSE_MANIFEST | DIAG_SEVERITY_INFO)
-#define CAUSE_OPERATIONS_SEVERITY_INFO \
- (CAUSE_OPERATIONS_ERROR | DIAG_SEVERITY_INFO)
-#define CAUSE_INVALID_SEVERITY_INFO \
- (CAUSE_INVALID_REQUEST | DIAG_SEVERITY_INFO)
-#define CAUSE_INTERNAL_SEVERITY_INFO \
- (CAUSE_INTERNAL_ERROR | DIAG_SEVERITY_INFO)
-
-#define CAUSE_DEBUG_SEVERITY_WARN \
- (CAUSE_DEBUG | DIAG_SEVERITY_WARNING)
-#define CAUSE_TRACE_SEVERITY_WARN \
- (CAUSE_TRACE | DIAG_SEVERITY_WARNING)
-#define CAUSE_MANIFEST_SEVERITY_WARN \
- (CAUSE_MANIFEST | DIAG_SEVERITY_WARNING)
-#define CAUSE_OPERATIONS_SEVERITY_WARN \
- (CAUSE_OPERATIONS_ERROR | DIAG_SEVERITY_WARNING)
-#define CAUSE_INVALID_SEVERITY_WARN \
- (CAUSE_INVALID_REQUEST | DIAG_SEVERITY_WARNING)
-#define CAUSE_INTERNAL_SEVERITY_WARN \
- (CAUSE_INTERNAL_ERROR | DIAG_SEVERITY_WARNING)
-
-#define CAUSE_DEBUG_SEVERITY_ERR \
- (CAUSE_DEBUG | DIAG_SEVERITY_ERR)
-#define CAUSE_TRACE_SEVERITY_ERR \
- (CAUSE_TRACE | DIAG_SEVERITY_ERR)
-#define CAUSE_MANIFEST_SEVERITY_ERR \
- (CAUSE_MANIFEST | DIAG_SEVERITY_ERR)
-#define CAUSE_OPERATIONS_SEVERITY_ERR \
- (CAUSE_OPERATIONS_ERROR | DIAG_SEVERITY_ERR)
-#define CAUSE_INVALID_SEVERITY_ERR \
- (CAUSE_INVALID_REQUEST | DIAG_SEVERITY_ERR)
-#define CAUSE_INTERNAL_SEVERITY_ERR \
- (CAUSE_INTERNAL_ERROR | DIAG_SEVERITY_ERR)
-
-#define CAUSE_DEBUG_SEVERITY_PRINT \
- (CAUSE_DEBUG | DIAG_SEVERITY_PRINT)
-#define CAUSE_TRACE_SEVERITY_PRINT \
- (CAUSE_TRACE | DIAG_SEVERITY_PRINT)
-#define CAUSE_MANIFEST_SEVERITY_PRINT \
- (CAUSE_MANIFEST | DIAG_SEVERITY_PRINT)
-#define CAUSE_OPERATIONS_SEVERITY_PRINT \
- (CAUSE_OPERATIONS_ERROR | DIAG_SEVERITY_PRINT)
-#define CAUSE_INVALID_SEVERITY_PRINT \
- (CAUSE_INVALID_REQUEST | DIAG_SEVERITY_PRINT)
-#define CAUSE_INTERNAL_SEVERITY_PRINT \
- (CAUSE_INTERNAL_ERROR | DIAG_SEVERITY_PRINT)
-#define CAUSE_FILE_XFER_SEVERITY_PRINT \
- (CAUSE_FILE_XFER | DIAG_SEVERITY_PRINT)
-
-/* Structure: diag_channel_protocol_header
- *
- * Purpose: Contains attributes that make up the header specific to the
- * DIAG_CHANNEL area.
- *
- * Attributes:
- *
- * DiagLock: Diag Channel spinlock.
- *
- *IsChannelInitialized: 1 iff SignalInit was called for this channel; otherwise
- * 0, and assume the channel is not ready for use yet.
- *
- * Reserved: Padding to align the fields in this structure.
- *
- *SubsystemSeverityFilter: Level of severity on a subsystem basis that controls
- * whether events are logged. Any event's severity for a
- * particular subsystem below this level will be discarded.
- */
-struct diag_channel_protocol_header {
- u32 diag_lock;
- u8 channel_initialized;
- u8 reserved[3];
- u8 subsystem_severity_filter[64];
-};
-
-/* The Diagram for the Diagnostic Channel: */
-/* ----------------------- */
-/* | Channel Header | Defined by ULTRA_CHANNEL_PROTOCOL */
-/* ----------------------- */
-/* | Signal Queue Header | Defined by SIGNAL_QUEUE_HEADER */
-/* ----------------------- */
-/* | DiagChannel Header | Defined by diag_channel_protocol_header */
-/* ----------------------- */
-/* | Channel Event Info | Defined by diag_channel_event*MAX_EVENTS */
-/* ----------------------- */
-/* | Reserved | Reserved (pad out to 4MB) */
-/* ----------------------- */
-
-/* Offsets/sizes for diagnostic channel attributes... */
-#define DIAG_CH_QUEUE_HEADER_OFFSET (sizeof(struct channel_header))
-#define DIAG_CH_QUEUE_HEADER_SIZE (sizeof(struct signal_queue_header))
-#define DIAG_CH_PROTOCOL_HEADER_OFFSET \
- (DIAG_CH_QUEUE_HEADER_OFFSET + DIAG_CH_QUEUE_HEADER_SIZE)
-#define DIAG_CH_PROTOCOL_HEADER_SIZE \
- (sizeof(struct diag_channel_protocol_header))
-#define DIAG_CH_EVENT_OFFSET \
- (DIAG_CH_PROTOCOL_HEADER_OFFSET + DIAG_CH_PROTOCOL_HEADER_SIZE)
-#define DIAG_CH_SIZE (4096 * 1024)
-
-/* For Control and Idle Partitions with larger (8 MB) diagnostic(root)
- * channels */
-#define DIAG_CH_LRG_SIZE (2 * DIAG_CH_SIZE) /* 8 MB */
-
-/*
- * Structure: spar_diag_channel_protocol
- *
- * Purpose: Contains attributes that make up the DIAG_CHANNEL memory.
- *
- * Attributes:
- *
- * CommonChannelHeader: Header info common to all channels.
- *
- * QueueHeader: Queue header common to all channels - used to determine where to
- * store event.
- *
- * DiagChannelHeader: Diagnostic channel header info (see
- * diag_channel_protocol_header comments).
- *
- * Events: Area where diagnostic events (up to MAX_EVENTS) are written.
- *
- *Reserved: Reserved area to allow for correct channel size padding.
-*/
-struct spar_diag_channel_protocol {
- struct channel_header common_channel_header;
- struct signal_queue_header queue_header;
- struct diag_channel_protocol_header diag_channel_header;
- struct diag_channel_event events[(DIAG_CH_SIZE - DIAG_CH_EVENT_OFFSET) /
- sizeof(struct diag_channel_event)];
-};
-
-#endif
diff --git a/drivers/staging/unisys/common-spar/include/diagnostics/appos_subsystems.h b/drivers/staging/unisys/common-spar/include/diagnostics/appos_subsystems.h
deleted file mode 100644
index 18cc9ed27..000000000
--- a/drivers/staging/unisys/common-spar/include/diagnostics/appos_subsystems.h
+++ /dev/null
@@ -1,310 +0,0 @@
-/* Copyright (C) 2010 - 2013 UNISYS CORPORATION
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
- * NON INFRINGEMENT. See the GNU General Public License for more
- * details.
- */
-
-/* Please note that this file is to be used ONLY for defining diagnostic
- * subsystem values for the appos (sPAR Linux service partitions) component.
- */
-#ifndef __APPOS_SUBSYSTEMS_H__
-#define __APPOS_SUBSYSTEMS_H__
-
-#ifdef __KERNEL__
-#include <linux/kernel.h>
-#include <linux/string.h>
-#else
-#include <stdio.h>
-#include <string.h>
-#endif
-
-static inline char *
-subsys_unknown_to_s(int subsys, char *s, int n)
-{
- snprintf(s, n, "SUBSYS-%-2.2d", subsys);
- s[n - 1] = '\0';
- return s;
-}
-
-#define SUBSYS_TO_MASK(subsys) (1ULL << (subsys))
-
-/* The first SUBSYS_APPOS_MAX subsystems are the same for each AppOS type
- * (IOVM, SMS, etc.) The rest have unique values for each AppOS type.
- */
-#define SUBSYS_APPOS_MAX 16
-
-#define SUBSYS_APPOS_DEFAULT 1 /* or "other" */
-#define SUBSYS_APPOS_CHIPSET 2 /* controlvm and other */
- /* low-level sPAR activity */
-#define SUBSYS_APPOS_BUS 3 /* sPAR bus */
-/* DAK #define SUBSYS_APPOS_DIAG 4 // diagnostics and dump */
-#define SUBSYS_APPOS_CHANNELACCESS 5 /* generic channel access */
-#define SUBSYS_APPOS_NICCLIENT 6 /* virtual NIC client */
-#define SUBSYS_APPOS_HBACLIENT 7 /* virtual HBA client */
-#define SUBSYS_APPOS_CONSOLESERIAL 8 /* sPAR virtual serial console */
-#define SUBSYS_APPOS_UISLIB 9 /* */
-#define SUBSYS_APPOS_VRTCUPDD 10 /* */
-#define SUBSYS_APPOS_WATCHDOG 11 /* watchdog timer and healthcheck */
-#define SUBSYS_APPOS_13 13 /* available */
-#define SUBSYS_APPOS_14 14 /* available */
-#define SUBSYS_APPOS_15 15 /* available */
-#define SUBSYS_APPOS_16 16 /* available */
-static inline char *
-subsys_generic_to_s(int subsys, char *s, int n)
-{
- switch (subsys) {
- case SUBSYS_APPOS_DEFAULT:
- strncpy(s, "APPOS_DEFAULT", n);
- break;
- case SUBSYS_APPOS_CHIPSET:
- strncpy(s, "APPOS_CHIPSET", n);
- break;
- case SUBSYS_APPOS_BUS:
- strncpy(s, "APPOS_BUS", n);
- break;
- case SUBSYS_APPOS_CHANNELACCESS:
- strncpy(s, "APPOS_CHANNELACCESS", n);
- break;
- case SUBSYS_APPOS_NICCLIENT:
- strncpy(s, "APPOS_NICCLIENT", n);
- break;
- case SUBSYS_APPOS_HBACLIENT:
- strncpy(s, "APPOS_HBACLIENT", n);
- break;
- case SUBSYS_APPOS_CONSOLESERIAL:
- strncpy(s, "APPOS_CONSOLESERIAL", n);
- break;
- case SUBSYS_APPOS_UISLIB:
- strncpy(s, "APPOS_UISLIB", n);
- break;
- case SUBSYS_APPOS_VRTCUPDD:
- strncpy(s, "APPOS_VRTCUPDD", n);
- break;
- case SUBSYS_APPOS_WATCHDOG:
- strncpy(s, "APPOS_WATCHDOG", n);
- break;
- case SUBSYS_APPOS_13:
- strncpy(s, "APPOS_13", n);
- break;
- case SUBSYS_APPOS_14:
- strncpy(s, "APPOS_14", n);
- break;
- case SUBSYS_APPOS_15:
- strncpy(s, "APPOS_15", n);
- break;
- case SUBSYS_APPOS_16:
- strncpy(s, "APPOS_16", n);
- break;
- default:
- subsys_unknown_to_s(subsys, s, n);
- break;
- }
- s[n - 1] = '\0';
- return s;
-}
-
-/* CONSOLE */
-
-#define SUBSYS_CONSOLE_VIDEO (SUBSYS_APPOS_MAX + 1) /* 17 */
-#define SUBSYS_CONSOLE_KBDMOU (SUBSYS_APPOS_MAX + 2) /* 18 */
-#define SUBSYS_CONSOLE_04 (SUBSYS_APPOS_MAX + 4)
-#define SUBSYS_CONSOLE_05 (SUBSYS_APPOS_MAX + 5)
-#define SUBSYS_CONSOLE_06 (SUBSYS_APPOS_MAX + 6)
-#define SUBSYS_CONSOLE_07 (SUBSYS_APPOS_MAX + 7)
-#define SUBSYS_CONSOLE_08 (SUBSYS_APPOS_MAX + 8)
-#define SUBSYS_CONSOLE_09 (SUBSYS_APPOS_MAX + 9)
-#define SUBSYS_CONSOLE_10 (SUBSYS_APPOS_MAX + 10)
-#define SUBSYS_CONSOLE_11 (SUBSYS_APPOS_MAX + 11)
-#define SUBSYS_CONSOLE_12 (SUBSYS_APPOS_MAX + 12)
-#define SUBSYS_CONSOLE_13 (SUBSYS_APPOS_MAX + 13)
-#define SUBSYS_CONSOLE_14 (SUBSYS_APPOS_MAX + 14)
-#define SUBSYS_CONSOLE_15 (SUBSYS_APPOS_MAX + 15)
-#define SUBSYS_CONSOLE_16 (SUBSYS_APPOS_MAX + 16)
-#define SUBSYS_CONSOLE_17 (SUBSYS_APPOS_MAX + 17)
-#define SUBSYS_CONSOLE_18 (SUBSYS_APPOS_MAX + 18)
-#define SUBSYS_CONSOLE_19 (SUBSYS_APPOS_MAX + 19)
-#define SUBSYS_CONSOLE_20 (SUBSYS_APPOS_MAX + 20)
-#define SUBSYS_CONSOLE_21 (SUBSYS_APPOS_MAX + 21)
-#define SUBSYS_CONSOLE_22 (SUBSYS_APPOS_MAX + 22)
-#define SUBSYS_CONSOLE_23 (SUBSYS_APPOS_MAX + 23)
-#define SUBSYS_CONSOLE_24 (SUBSYS_APPOS_MAX + 24)
-#define SUBSYS_CONSOLE_25 (SUBSYS_APPOS_MAX + 25)
-#define SUBSYS_CONSOLE_26 (SUBSYS_APPOS_MAX + 26)
-#define SUBSYS_CONSOLE_27 (SUBSYS_APPOS_MAX + 27)
-#define SUBSYS_CONSOLE_28 (SUBSYS_APPOS_MAX + 28)
-#define SUBSYS_CONSOLE_29 (SUBSYS_APPOS_MAX + 29)
-#define SUBSYS_CONSOLE_30 (SUBSYS_APPOS_MAX + 30)
-#define SUBSYS_CONSOLE_31 (SUBSYS_APPOS_MAX + 31)
-#define SUBSYS_CONSOLE_32 (SUBSYS_APPOS_MAX + 32)
-#define SUBSYS_CONSOLE_33 (SUBSYS_APPOS_MAX + 33)
-#define SUBSYS_CONSOLE_34 (SUBSYS_APPOS_MAX + 34)
-#define SUBSYS_CONSOLE_35 (SUBSYS_APPOS_MAX + 35)
-#define SUBSYS_CONSOLE_36 (SUBSYS_APPOS_MAX + 36)
-#define SUBSYS_CONSOLE_37 (SUBSYS_APPOS_MAX + 37)
-#define SUBSYS_CONSOLE_38 (SUBSYS_APPOS_MAX + 38)
-#define SUBSYS_CONSOLE_39 (SUBSYS_APPOS_MAX + 39)
-#define SUBSYS_CONSOLE_40 (SUBSYS_APPOS_MAX + 40)
-#define SUBSYS_CONSOLE_41 (SUBSYS_APPOS_MAX + 41)
-#define SUBSYS_CONSOLE_42 (SUBSYS_APPOS_MAX + 42)
-#define SUBSYS_CONSOLE_43 (SUBSYS_APPOS_MAX + 43)
-#define SUBSYS_CONSOLE_44 (SUBSYS_APPOS_MAX + 44)
-#define SUBSYS_CONSOLE_45 (SUBSYS_APPOS_MAX + 45)
-#define SUBSYS_CONSOLE_46 (SUBSYS_APPOS_MAX + 46)
-
-static inline char *
-subsys_console_to_s(int subsys, char *s, int n)
-{
- switch (subsys) {
- case SUBSYS_CONSOLE_VIDEO:
- strncpy(s, "CONSOLE_VIDEO", n);
- break;
- case SUBSYS_CONSOLE_KBDMOU:
- strncpy(s, "CONSOLE_KBDMOU", n);
- break;
- case SUBSYS_CONSOLE_04:
- strncpy(s, "CONSOLE_04", n);
- break;
- case SUBSYS_CONSOLE_05:
- strncpy(s, "CONSOLE_05", n);
- break;
- case SUBSYS_CONSOLE_06:
- strncpy(s, "CONSOLE_06", n);
- break;
- case SUBSYS_CONSOLE_07:
- strncpy(s, "CONSOLE_07", n);
- break;
- case SUBSYS_CONSOLE_08:
- strncpy(s, "CONSOLE_08", n);
- break;
- case SUBSYS_CONSOLE_09:
- strncpy(s, "CONSOLE_09", n);
- break;
- case SUBSYS_CONSOLE_10:
- strncpy(s, "CONSOLE_10", n);
- break;
- case SUBSYS_CONSOLE_11:
- strncpy(s, "CONSOLE_11", n);
- break;
- case SUBSYS_CONSOLE_12:
- strncpy(s, "CONSOLE_12", n);
- break;
- case SUBSYS_CONSOLE_13:
- strncpy(s, "CONSOLE_13", n);
- break;
- case SUBSYS_CONSOLE_14:
- strncpy(s, "CONSOLE_14", n);
- break;
- case SUBSYS_CONSOLE_15:
- strncpy(s, "CONSOLE_15", n);
- break;
- case SUBSYS_CONSOLE_16:
- strncpy(s, "CONSOLE_16", n);
- break;
- case SUBSYS_CONSOLE_17:
- strncpy(s, "CONSOLE_17", n);
- break;
- case SUBSYS_CONSOLE_18:
- strncpy(s, "CONSOLE_18", n);
- break;
- case SUBSYS_CONSOLE_19:
- strncpy(s, "CONSOLE_19", n);
- break;
- case SUBSYS_CONSOLE_20:
- strncpy(s, "CONSOLE_20", n);
- break;
- case SUBSYS_CONSOLE_21:
- strncpy(s, "CONSOLE_21", n);
- break;
- case SUBSYS_CONSOLE_22:
- strncpy(s, "CONSOLE_22", n);
- break;
- case SUBSYS_CONSOLE_23:
- strncpy(s, "CONSOLE_23", n);
- break;
- case SUBSYS_CONSOLE_24:
- strncpy(s, "CONSOLE_24", n);
- break;
- case SUBSYS_CONSOLE_25:
- strncpy(s, "CONSOLE_25", n);
- break;
- case SUBSYS_CONSOLE_26:
- strncpy(s, "CONSOLE_26", n);
- break;
- case SUBSYS_CONSOLE_27:
- strncpy(s, "CONSOLE_27", n);
- break;
- case SUBSYS_CONSOLE_28:
- strncpy(s, "CONSOLE_28", n);
- break;
- case SUBSYS_CONSOLE_29:
- strncpy(s, "CONSOLE_29", n);
- break;
- case SUBSYS_CONSOLE_30:
- strncpy(s, "CONSOLE_30", n);
- break;
- case SUBSYS_CONSOLE_31:
- strncpy(s, "CONSOLE_31", n);
- break;
- case SUBSYS_CONSOLE_32:
- strncpy(s, "CONSOLE_32", n);
- break;
- case SUBSYS_CONSOLE_33:
- strncpy(s, "CONSOLE_33", n);
- break;
- case SUBSYS_CONSOLE_34:
- strncpy(s, "CONSOLE_34", n);
- break;
- case SUBSYS_CONSOLE_35:
- strncpy(s, "CONSOLE_35", n);
- break;
- case SUBSYS_CONSOLE_36:
- strncpy(s, "CONSOLE_36", n);
- break;
- case SUBSYS_CONSOLE_37:
- strncpy(s, "CONSOLE_37", n);
- break;
- case SUBSYS_CONSOLE_38:
- strncpy(s, "CONSOLE_38", n);
- break;
- case SUBSYS_CONSOLE_39:
- strncpy(s, "CONSOLE_39", n);
- break;
- case SUBSYS_CONSOLE_40:
- strncpy(s, "CONSOLE_40", n);
- break;
- case SUBSYS_CONSOLE_41:
- strncpy(s, "CONSOLE_41", n);
- break;
- case SUBSYS_CONSOLE_42:
- strncpy(s, "CONSOLE_42", n);
- break;
- case SUBSYS_CONSOLE_43:
- strncpy(s, "CONSOLE_43", n);
- break;
- case SUBSYS_CONSOLE_44:
- strncpy(s, "CONSOLE_44", n);
- break;
- case SUBSYS_CONSOLE_45:
- strncpy(s, "CONSOLE_45", n);
- break;
- case SUBSYS_CONSOLE_46:
- strncpy(s, "CONSOLE_46", n);
- break;
- default:
- subsys_unknown_to_s(subsys, s, n);
- break;
- }
- s[n - 1] = '\0';
- return s;
-}
-
-#endif
diff --git a/drivers/staging/unisys/common-spar/include/channels/channel.h b/drivers/staging/unisys/include/channel.h
index 6fb6e5b3d..da0b5387f 100644
--- a/drivers/staging/unisys/common-spar/include/channels/channel.h
+++ b/drivers/staging/unisys/include/channel.h
@@ -114,41 +114,6 @@ ULTRA_CHANNELCLI_STRING(u32 v)
(((o) == CHANNELCLI_BUSY) && ((n) == CHANNELCLI_OWNED)) || (0)) \
? (1) : (0))
-#define SPAR_CHANNEL_CLIENT_CHK_TRANSITION(old, new, id, log, \
- file, line) \
- do { \
- if (!ULTRA_VALID_CHANNELCLI_TRANSITION(old, new)) \
- pr_info("%s Channel StateTransition INVALID! (%s) %s(%d)-->%s(%d) @%s:%d\n", \
- id, "CliState<x>", \
- ULTRA_CHANNELCLI_STRING(old), \
- old, \
- ULTRA_CHANNELCLI_STRING(new), \
- new, \
- pathname_last_n_nodes((u8 *)file, 4), \
- line); \
- } while (0)
-
-#define SPAR_CHANNEL_CLIENT_TRANSITION(ch, id, newstate, log) \
- do { \
- SPAR_CHANNEL_CLIENT_CHK_TRANSITION( \
- readl(&(((struct channel_header __iomem *)\
- (ch))->cli_state_os)), \
- newstate, id, log, __FILE__, __LINE__); \
- pr_info("%s Channel StateTransition (%s) %s(%d)-->%s(%d) @%s:%d\n", \
- id, "CliStateOS", \
- ULTRA_CHANNELCLI_STRING( \
- readl(&((struct channel_header __iomem *)\
- (ch))->cli_state_os)), \
- readl(&((struct channel_header __iomem *)\
- (ch))->cli_state_os), \
- ULTRA_CHANNELCLI_STRING(newstate), \
- newstate, \
- pathname_last_n_nodes(__FILE__, 4), __LINE__); \
- writel(newstate, &((struct channel_header __iomem *)\
- (ch))->cli_state_os); \
- mb(); /* required for channel synch */ \
- } while (0)
-
/* Values for ULTRA_CHANNEL_PROTOCOL.CliErrorBoot: */
/* throttling invalid boot channel statetransition error due to client
* disabled */
diff --git a/drivers/staging/unisys/common-spar/include/channels/channel_guid.h b/drivers/staging/unisys/include/channel_guid.h
index 706363fc3..706363fc3 100644
--- a/drivers/staging/unisys/common-spar/include/channels/channel_guid.h
+++ b/drivers/staging/unisys/include/channel_guid.h
diff --git a/drivers/staging/unisys/include/diagchannel.h b/drivers/staging/unisys/include/diagchannel.h
new file mode 100644
index 000000000..d2d35685d
--- /dev/null
+++ b/drivers/staging/unisys/include/diagchannel.h
@@ -0,0 +1,43 @@
+/* Copyright (C) 2010 - 2013 UNISYS CORPORATION
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ */
+
+#ifndef _DIAG_CHANNEL_H_
+#define _DIAG_CHANNEL_H_
+
+#define MAX_MODULE_NAME_SIZE 128 /* Maximum length of module name... */
+#define MAX_ADDITIONAL_INFO_SIZE 256 /* Maximum length of any additional
+ * info accompanying event...
+ */
+
+/* Levels of severity for diagnostic events, in order from lowest severity to
+ * highest (i.e. fatal errors are the most severe, and should always be logged,
+ * but info events rarely need to be logged except during debugging). The
+ * values DIAG_SEVERITY_ENUM_BEGIN and DIAG_SEVERITY_ENUM_END are not valid
+ * severity values. They exist merely to dilineate the list, so that future
+ * additions won't require changes to the driver (i.e. when checking for
+ * out-of-range severities in SetSeverity). The values DIAG_SEVERITY_OVERRIDE
+ * and DIAG_SEVERITY_SHUTOFF are not valid severity values for logging events
+ * but they are valid for controlling the amount of event data. Changes made
+ * to the enum, need to be reflected in s-Par.
+ */
+enum diag_severity {
+ DIAG_SEVERITY_VERBOSE = 0,
+ DIAG_SEVERITY_INFO = 1,
+ DIAG_SEVERITY_WARNING = 2,
+ DIAG_SEVERITY_ERR = 3,
+ DIAG_SEVERITY_PRINT = 4,
+};
+
+#endif
diff --git a/drivers/staging/unisys/include/guestlinuxdebug.h b/drivers/staging/unisys/include/guestlinuxdebug.h
index 957a627d0..82ee56539 100644
--- a/drivers/staging/unisys/include/guestlinuxdebug.h
+++ b/drivers/staging/unisys/include/guestlinuxdebug.h
@@ -22,7 +22,6 @@
* ISSUE_IO_VMCALL_POSTCODE_SEVERITY */
/******* INFO ON ISSUE_POSTCODE_LINUX() BELOW *******/
-#include "vmcallinterface.h"
enum driver_pc { /* POSTCODE driver identifier tuples */
/* visorchipset driver files */
VISOR_CHIPSET_PC = 0xA0,
@@ -135,7 +134,7 @@ enum event_pc { /* POSTCODE event identifier tuples */
#define POSTCODE_SEVERITY_ERR DIAG_SEVERITY_ERR
#define POSTCODE_SEVERITY_WARNING DIAG_SEVERITY_WARNING
#define POSTCODE_SEVERITY_INFO DIAG_SEVERITY_PRINT /* TODO-> Info currently
- * doesnt show, so we
+ * doesn't show, so we
* set info=warning */
/* example call of POSTCODE_LINUX_2(VISOR_CHIPSET_PC, POSTCODE_SEVERITY_ERR);
* Please also note that the resulting postcode is in hex, so if you are
diff --git a/drivers/staging/unisys/common-spar/include/channels/iochannel.h b/drivers/staging/unisys/include/iochannel.h
index 3bd7579e1..a55981234 100644
--- a/drivers/staging/unisys/common-spar/include/channels/iochannel.h
+++ b/drivers/staging/unisys/include/iochannel.h
@@ -4,45 +4,34 @@
#define __IOCHANNEL_H__
/*
-* Everything needed for IOPart-GuestPart communication is define in
-* this file. Note: Everything is OS-independent because this file is
-* used by Windows, Linux and possible EFI drivers. */
+ * Everything needed for IOPart-GuestPart communication is define in
+ * this file. Note: Everything is OS-independent because this file is
+ * used by Windows, Linux and possible EFI drivers. */
/*
-* Communication flow between the IOPart and GuestPart uses the channel headers
-* channel state. The following states are currently being used:
-* UNINIT(All Zeroes), CHANNEL_ATTACHING, CHANNEL_ATTACHED, CHANNEL_OPENED
-*
-* additional states will be used later. No locking is needed to switch between
-* states due to the following rules:
-*
-* 1. IOPart is only the only partition allowed to change from UNIT
-* 2. IOPart is only the only partition allowed to change from
-* CHANNEL_ATTACHING
-* 3. GuestPart is only the only partition allowed to change from
-* CHANNEL_ATTACHED
-*
-* The state changes are the following: IOPart sees the channel is in UNINIT,
-* UNINIT -> CHANNEL_ATTACHING (performed only by IOPart)
-* CHANNEL_ATTACHING -> CHANNEL_ATTACHED (performed only by IOPart)
-* CHANNEL_ATTACHED -> CHANNEL_OPENED (performed only by GuestPart)
-*/
+ * Communication flow between the IOPart and GuestPart uses the channel headers
+ * channel state. The following states are currently being used:
+ * UNINIT(All Zeroes), CHANNEL_ATTACHING, CHANNEL_ATTACHED, CHANNEL_OPENED
+ *
+ * additional states will be used later. No locking is needed to switch between
+ * states due to the following rules:
+ *
+ * 1. IOPart is only the only partition allowed to change from UNIT
+ * 2. IOPart is only the only partition allowed to change from
+ * CHANNEL_ATTACHING
+ * 3. GuestPart is only the only partition allowed to change from
+ * CHANNEL_ATTACHED
+ *
+ * The state changes are the following: IOPart sees the channel is in UNINIT,
+ * UNINIT -> CHANNEL_ATTACHING (performed only by IOPart)
+ * CHANNEL_ATTACHING -> CHANNEL_ATTACHED (performed only by IOPart)
+ * CHANNEL_ATTACHED -> CHANNEL_OPENED (performed only by GuestPart)
+ */
#include <linux/uuid.h>
-#include "vmcallinterface.h"
-
-#define _ULTRA_CONTROLVM_CHANNEL_INLINE_
#include <linux/dma-direction.h>
-#include "controlvmchannel.h"
-#include "vbuschannel.h"
-#undef _ULTRA_CONTROLVM_CHANNEL_INLINE_
#include "channel.h"
-
-/*
- * CHANNEL Guids
- */
-
#include "channel_guid.h"
#define ULTRA_VHBA_CHANNEL_PROTOCOL_SIGNATURE ULTRA_CHANNEL_PROTOCOL_SIGNATURE
@@ -51,10 +40,11 @@
ULTRA_CHANNEL_PROTOCOL_SIGNATURE
/* Must increment these whenever you insert or delete fields within this channel
-* struct. Also increment whenever you change the meaning of fields within this
-* channel struct so as to break pre-existing software. Note that you can
-* usually add fields to the END of the channel struct withOUT needing to
-* increment this. */
+ * struct. Also increment whenever you change the meaning of fields within this
+ * channel struct so as to break pre-existing software. Note that you can
+ * usually add fields to the END of the channel struct withOUT needing to
+ * increment this.
+ */
#define ULTRA_VHBA_CHANNEL_PROTOCOL_VERSIONID 2
#define ULTRA_VNIC_CHANNEL_PROTOCOL_VERSIONID 2
#define ULTRA_VSWITCH_CHANNEL_PROTOCOL_VERSIONID 1
@@ -72,55 +62,26 @@
ULTRA_VNIC_CHANNEL_PROTOCOL_SIGNATURE))
/*
-* Everything necessary to handle SCSI & NIC traffic between Guest Partition and
-* IO Partition is defined below. */
+ * Everything necessary to handle SCSI & NIC traffic between Guest Partition and
+ * IO Partition is defined below.
+ */
/*
-* Defines and enums.
-*/
+ * Defines and enums.
+ */
#define MINNUM(a, b) (((a) < (b)) ? (a) : (b))
#define MAXNUM(a, b) (((a) > (b)) ? (a) : (b))
/* these define the two queues per data channel between iopart and
- * ioguestparts */
+ * ioguestparts
+ */
#define IOCHAN_TO_IOPART 0 /* used by ioguestpart to 'insert' signals to
* iopart */
-#define IOCHAN_FROM_GUESTPART 0 /* used by iopart to 'remove' signals from
- * ioguestpart - same queue as previous queue */
-#define IOCHAN_TO_GUESTPART 1 /* used by iopart to 'insert' signals to
- * ioguestpart */
#define IOCHAN_FROM_IOPART 1 /* used by ioguestpart to 'remove' signals from
* iopart - same queue as previous queue */
-/* these define the two queues per control channel between controlpart and "its"
- * guests, which includes the iopart */
-#define CTRLCHAN_TO_CTRLGUESTPART 0 /* used by ctrlguestpart to 'insert' signals
- * to ctrlpart */
-#define CTLRCHAN_FROM_CTRLPART 0 /* used by ctrlpart to 'remove' signals from
- * ctrlquestpart - same queue as previous
- * queue */
-
-#define CTRLCHAN_TO_CTRLPART 1 /* used by ctrlpart to 'insert' signals to
- * ctrlguestpart */
-#define CTRLCHAN_FROM_CTRLGUESTPART 1 /* used by ctrguestpart to 'remove'
- * signals from ctrlpart - same queue as
- * previous queue */
-
-/* these define the Event & Ack queues per control channel Events are generated
-* by CTRLGUESTPART and sent to CTRLPART; Acks are generated by CTRLPART and sent
-* to CTRLGUESTPART. */
-#define CTRLCHAN_EVENT_TO_CTRLPART 2 /* used by ctrlguestpart to 'insert' Events
- * to ctrlpart */
-#define CTRLCHAN_EVENT_FROM_CTRLGUESTPART 2 /* used by ctrlpart to 'remove'
- * Events from ctrlguestpart */
-
-#define CTRLCHAN_ACK_TO_CTRLGUESTPART 3 /* used by ctrlpart to 'insert' Acks to
- * ctrlguestpart */
-#define CTRLCHAN_ACK_FROM_CTRLPART 3 /* used by ctrlguestpart to 'remove' Events
- * from ctrlpart */
-
/* size of cdb - i.e., scsi cmnd */
#define MAX_CMND_SIZE 16
@@ -128,28 +89,6 @@
#define MAX_PHYS_INFO 64
-/* Because GuestToGuestCopy is limited to 4KiB segments, and we have limited the
-* Emulex Driver to 256 scatter list segments via the lpfc_sg_seg_cnt parameter
-* to 256, the maximum I/O size is limited to 256 * 4 KiB = 1 MB */
-#define MAX_IO_SIZE (1024*1024) /* 1 MB */
-
-/* NOTE 1: lpfc defines its support for segments in
-* #define LPFC_SG_SEG_CNT 64
-*
-* NOTE 2: In Linux, frags array in skb is currently allocated to be
-* MAX_SKB_FRAGS size, which is 18 which is smaller than MAX_PHYS_INFO for
-* now. */
-
-#ifndef MAX_SERIAL_NUM
-#define MAX_SERIAL_NUM 32
-#endif /* MAX_SERIAL_NUM */
-
-#define MAX_SCSI_BUSES 1
-#define MAX_SCSI_TARGETS 8
-#define MAX_SCSI_LUNS 16
-#define MAX_SCSI_FROM_HOST 0xFFFFFFFF /* Indicator to use Physical HBA
- * SCSI Host value */
-
/* various types of network packets that can be sent in cmdrsp */
enum net_types {
NET_RCV_POST = 0, /* submit buffer to hold receiving
@@ -173,7 +112,7 @@ enum net_types {
/* uisnic -> virtnic */
NET_MACADDR, /* indicates the client has requested to update
* its MAC addr */
- NET_MACADDR_ACK, /* MAC address */
+ NET_MACADDR_ACK, /* MAC address */
};
@@ -182,19 +121,12 @@ enum net_types {
#define ETH_MIN_DATA_SIZE 46 /* minimum eth data size */
#define ETH_MIN_PACKET_SIZE (ETH_HEADER_SIZE + ETH_MIN_DATA_SIZE)
-#define ETH_DEF_DATA_SIZE 1500 /* default data size */
-#define ETH_DEF_PACKET_SIZE (ETH_HEADER_SIZE + ETH_DEF_DATA_SIZE)
-
#define ETH_MAX_MTU 16384 /* maximum data size */
#ifndef MAX_MACADDR_LEN
#define MAX_MACADDR_LEN 6 /* number of bytes in MAC address */
#endif /* MAX_MACADDR_LEN */
-#define ETH_IS_LOCALLY_ADMINISTERED(address) \
- (((u8 *)(address))[0] & ((u8)0x02))
-#define NIC_VENDOR_ID 0x0008000B
-
/* various types of scsi task mgmt commands */
enum task_mgmt_types {
TASK_MGMT_ABORT_TASK = 1,
@@ -209,32 +141,16 @@ enum vdisk_mgmt_types {
VDISK_MGMT_RELEASE,
};
-/* this is used in the vdest field */
-#define VDEST_ALL 0xFFFF
-
-#define MIN_NUMSIGNALS 64
-#define MAX_NUMSIGNALS 4096
-
-/* MAX_NET_RCV_BUF specifies the number of rcv buffers that are created by each
-* guest's virtnic and posted to uisnic. Uisnic, for each channel, keeps the rcv
-* buffers posted and uses them to receive data on behalf of the guest's virtnic.
-* NOTE: the num_rcv_bufs is configurable for each VNIC. So the following is
-* simply an upperlimit on what each VNIC can provide. Setting it to half of the
-* NUMSIGNALS to prevent queue full deadlocks */
-#define MAX_NET_RCV_BUFS (MIN_NUMSIGNALS / 2)
-
-/*
- * structs with pragma pack */
-
-/* ///////////// BEGIN PRAGMA PACK PUSH 1 ///////////////////////// */
-/* ///////////// ONLY STRUCT TYPE SHOULD BE BELOW */
-
-#pragma pack(push, 1)
+struct phys_info {
+ u64 pi_pfn;
+ u16 pi_off;
+ u16 pi_len;
+} __packed;
struct guest_phys_info {
u64 address;
u64 length;
-};
+} __packed;
#define GPI_ENTRIES_PER_PAGE (PAGE_SIZE / sizeof(struct guest_phys_info))
@@ -242,12 +158,12 @@ struct uisscsi_dest {
u32 channel; /* channel == bus number */
u32 id; /* id == target number */
u32 lun; /* lun == logical unit number */
-};
+} __packed;
struct vhba_wwnn {
u32 wwnn1;
u32 wwnn2;
-};
+} __packed;
/* WARNING: Values stired in this structure must contain maximum counts (not
* maximum values). */
@@ -264,7 +180,7 @@ struct vhba_config_max { /* 20 bytes */
* bus */
/* max io size is often determined by the resource of the hba. e.g */
/* max scatter gather list length * page size / sector size */
-};
+} __packed;
struct uiscmdrsp_scsi {
void *scsicmd; /* the handle to the cmd that was received -
@@ -287,13 +203,7 @@ struct uiscmdrsp_scsi {
u8 scsistat; /* the scsi status */
u8 addlstat; /* non-scsi status - covers cases like timeout
* needed by windows guests */
-#define ADDL_RESET 1
-#define ADDL_TIMEOUT 2
-#define ADDL_INTERNAL_ERROR 3
#define ADDL_SEL_TIMEOUT 4
-#define ADDL_CMD_TIMEOUT 5
-#define ADDL_BAD_TARGET 6
-#define ADDL_RETRY 7
/* the following fields are need to determine the result of command */
u8 sensebuf[MAX_SENSE_SIZE]; /* sense info in case cmd failed; */
@@ -301,17 +211,19 @@ struct uiscmdrsp_scsi {
/* see that struct for details. */
void *vdisk; /* contains pointer to the vdisk so that we can clean up
* when the IO completes. */
- int no_disk_result; /* used to return no disk inquiry result */
- /* when no_disk_result is set to 1, */
- /* scsi.scsistat is SAM_STAT_GOOD */
- /* scsi.addlstat is 0 */
- /* scsi.linuxstat is SAM_STAT_GOOD */
- /* That is, there is NO error. */
-};
-
-/*
-* Defines to support sending correct inquiry result when no disk is
-* configured. */
+ int no_disk_result;
+ /* used to return no disk inquiry result
+ * when no_disk_result is set to 1,
+ * scsi.scsistat is SAM_STAT_GOOD
+ * scsi.addlstat is 0
+ * scsi.linuxstat is SAM_STAT_GOOD
+ * That is, there is NO error.
+ */
+} __packed;
+
+/* Defines to support sending correct inquiry result when no disk is
+ * configured.
+ */
/* From SCSI SPC2 -
*
@@ -324,26 +236,22 @@ struct uiscmdrsp_scsi {
*connected to this logical unit.
*/
-#define DEV_NOT_PRESENT 0x7f /* old name - compatibility */
#define DEV_NOT_CAPABLE 0x7f /* peripheral qualifier of 0x3 */
- /* peripheral type of 0x1f */
- /* specifies no device but target present */
+ /* peripheral type of 0x1f */
+ /* specifies no device but target present */
#define DEV_DISK_CAPABLE_NOT_PRESENT 0x20 /* peripheral qualifier of 0x1 */
/* peripheral type of 0 - disk */
/* specifies device capable, but not present */
-#define DEV_PROC_CAPABLE_NOT_PRESENT 0x23 /* peripheral qualifier of 0x1 */
- /* peripheral type of 3 - processor */
- /* specifies device capable, but not present */
-
#define DEV_HISUPPORT 0x10 /* HiSup = 1; shows support for report luns */
- /* must be returned for lun 0. */
+ /* must be returned for lun 0. */
/* NOTE: Linux code assumes inquiry contains 36 bytes. Without checking length
-* in buf[4] some linux code accesses bytes beyond 5 to retrieve vendor, product
-* & revision. Yikes! So let us always send back 36 bytes, the minimum for
-* inquiry result. */
+ * in buf[4] some linux code accesses bytes beyond 5 to retrieve vendor, product
+ * & revision. Yikes! So let us always send back 36 bytes, the minimum for
+ * inquiry result.
+ */
#define NO_DISK_INQUIRY_RESULT_LEN 36
#define MIN_INQUIRY_RESULT_LEN 5 /* we need at least 5 bytes minimum for inquiry
@@ -394,21 +302,21 @@ struct uiscmdrsp_scsi {
} while (0)
/*
-* Struct & Defines to support sense information.
-*/
+ * Struct & Defines to support sense information.
+ */
/* The following struct is returned in sensebuf field in uiscmdrsp_scsi. It is
-* initialized in exactly the manner that is recommended in Windows (hence the
-* odd values).
-* When set, these fields will have the following values:
-* ErrorCode = 0x70 indicates current error
-* Valid = 1 indicates sense info is valid
-* SenseKey contains sense key as defined by SCSI specs.
-* AdditionalSenseCode contains sense key as defined by SCSI specs.
-* AdditionalSenseCodeQualifier contains qualifier to sense code as defined by
-* scsi docs.
-* AdditionalSenseLength contains will be sizeof(sense_data)-8=10.
-*/
+ * initialized in exactly the manner that is recommended in Windows (hence the
+ * odd values).
+ * When set, these fields will have the following values:
+ * ErrorCode = 0x70 indicates current error
+ * Valid = 1 indicates sense info is valid
+ * SenseKey contains sense key as defined by SCSI specs.
+ * AdditionalSenseCode contains sense key as defined by SCSI specs.
+ * AdditionalSenseCodeQualifier contains qualifier to sense code as defined by
+ * scsi docs.
+ * AdditionalSenseLength contains will be sizeof(sense_data)-8=10.
+ */
struct sense_data {
u8 errorcode:7;
u8 valid:1;
@@ -425,38 +333,7 @@ struct sense_data {
u8 additional_sense_code_qualifier;
u8 fru_code;
u8 sense_key_specific[3];
-};
-
-/* some SCSI ADSENSE codes */
-#ifndef SCSI_ADSENSE_LUN_NOT_READY
-#define SCSI_ADSENSE_LUN_NOT_READY 0x04
-#endif /* */
-#ifndef SCSI_ADSENSE_ILLEGAL_COMMAND
-#define SCSI_ADSENSE_ILLEGAL_COMMAND 0x20
-#endif /* */
-#ifndef SCSI_ADSENSE_ILLEGAL_BLOCK
-#endif /* */
-#ifndef SCSI_ADSENSE_ILLEGAL_BLOCK
-#define SCSI_ADSENSE_ILLEGAL_BLOCK 0x21
-#endif /* */
-#ifndef SCSI_ADSENSE_INVALID_CDB
-#define SCSI_ADSENSE_INVALID_CDB 0x24
-#endif /* */
-#ifndef SCSI_ADSENSE_INVALID_LUN
-#define SCSI_ADSENSE_INVALID_LUN 0x25
-#endif /* */
-#ifndef SCSI_ADWRITE_PROTECT
-#define SCSI_ADWRITE_PROTECT 0x27
-#endif /* */
-#ifndef SCSI_ADSENSE_MEDIUM_CHANGED
-#define SCSI_ADSENSE_MEDIUM_CHANGED 0x28
-#endif /* */
-#ifndef SCSI_ADSENSE_BUS_RESET
-#define SCSI_ADSENSE_BUS_RESET 0x29
-#endif /* */
-#ifndef SCSI_ADSENSE_NO_MEDIA_IN_DEVICE
-#define SCSI_ADSENSE_NO_MEDIA_IN_DEVICE 0x3a
-#endif /* */
+} __packed;
struct net_pkt_xmt {
int len; /* full length of data in the packet */
@@ -484,34 +361,33 @@ struct net_pkt_xmt {
* guest memory to get to the header. uisnic needs ethhdr to
* determine how to route the packet.
*/
-};
+} __packed;
struct net_pkt_xmtdone {
u32 xmt_done_result; /* result of NET_XMIT */
-#define XMIT_SUCCESS 0
-#define XMIT_FAILED 1
-};
+} __packed;
/* RCVPOST_BUF_SIZe must be at most page_size(4096) - cache_line_size (64) The
-* reason is because dev_skb_alloc which is used to generate RCV_POST skbs in
-* virtnic requires that there is "overhead" in the buffer, and pads 16 bytes. I
-* prefer to use 1 full cache line size for "overhead" so that transfers are
-* better. IOVM requires that a buffer be represented by 1 phys_info structure
-* which can only cover page_size. */
+ * reason is because dev_skb_alloc which is used to generate RCV_POST skbs in
+ * virtnic requires that there is "overhead" in the buffer, and pads 16 bytes. I
+ * prefer to use 1 full cache line size for "overhead" so that transfers are
+ * better. IOVM requires that a buffer be represented by 1 phys_info structure
+ * which can only cover page_size.
+ */
#define RCVPOST_BUF_SIZE 4032
#define MAX_NET_RCV_CHAIN \
((ETH_MAX_MTU+ETH_HEADER_SIZE + RCVPOST_BUF_SIZE-1) / RCVPOST_BUF_SIZE)
struct net_pkt_rcvpost {
/* rcv buf size must be large enough to include ethernet data len +
- * ethernet header len - we are choosing 2K because it is guaranteed
- * to be describable */
+ * ethernet header len - we are choosing 2K because it is guaranteed
+ * to be describable */
struct phys_info frag; /* physical page information for the
* single fragment 2K rcv buf */
u64 unique_num; /* This is used to make sure that
* receive posts are returned to */
- /* the Adapter which sent them origonally. */
-};
+ /* the Adapter which we sent them originally. */
+} __packed;
struct net_pkt_rcv {
/* the number of receive buffers that can be chained */
@@ -525,34 +401,34 @@ struct net_pkt_rcv {
/* NOTE: first rcvbuf in the chain will also be provided in net.buf. */
u64 unique_num;
u32 rcvs_dropped_delta;
-};
+} __packed;
struct net_pkt_enbdis {
void *context;
u16 enable; /* 1 = enable, 0 = disable */
-};
+} __packed;
struct net_pkt_macaddr {
void *context;
u8 macaddr[MAX_MACADDR_LEN]; /* 6 bytes */
-};
+} __packed;
/* cmd rsp packet used for VNIC network traffic */
struct uiscmdrsp_net {
enum net_types type;
void *buf;
union {
- struct net_pkt_xmt xmt; /* used for NET_XMIT */
+ struct net_pkt_xmt xmt; /* used for NET_XMIT */
struct net_pkt_xmtdone xmtdone; /* used for NET_XMIT_DONE */
struct net_pkt_rcvpost rcvpost; /* used for NET_RCV_POST */
- struct net_pkt_rcv rcv; /* used for NET_RCV */
+ struct net_pkt_rcv rcv; /* used for NET_RCV */
struct net_pkt_enbdis enbdis; /* used for NET_RCV_ENBDIS, */
- /* NET_RCV_ENBDIS_ACK, */
- /* NET_RCV_PROMSIC, */
- /* and NET_CONNECT_STATUS */
+ /* NET_RCV_ENBDIS_ACK, */
+ /* NET_RCV_PROMSIC, */
+ /* and NET_CONNECT_STATUS */
struct net_pkt_macaddr macaddr;
};
-};
+} __packed;
struct uiscmdrsp_scsitaskmgmt {
enum task_mgmt_types tasktype;
@@ -564,43 +440,45 @@ struct uiscmdrsp_scsitaskmgmt {
void *scsicmd;
/* This is some handle that the guest has saved off for its own use.
- * Its value is preserved by iopart & returned as is in the task mgmt
- * rsp. */
+ * Its value is preserved by iopart & returned as is in the task
+ * mgmt rsp.
+ */
void *notify;
- /* For linux guests, this is a pointer to wait_queue_head that a
+ /* For linux guests, this is a pointer to wait_queue_head that a
* thread is waiting on to see if the taskmgmt command has completed.
* For windows guests, this is a pointer to a location that a waiting
* thread is testing to see if the taskmgmt command has completed.
* When the rsp is received by guest, the thread receiving the
* response uses this to notify the thread waiting for taskmgmt
* command completion. Its value is preserved by iopart & returned
- * as is in the task mgmt rsp. */
+ * as is in the task mgmt rsp.
+ */
void *notifyresult;
/* this is a handle to location in guest where the result of the
- * taskmgmt command (result field) is to saved off when the response
- * is handled. Its value is preserved by iopart & returned as is in
- * the task mgmt rsp. */
+ * taskmgmt command (result field) is to saved off when the response
+ * is handled. Its value is preserved by iopart & returned as is in
+ * the task mgmt rsp.
+ */
char result;
/* result of taskmgmt command - set by IOPart - values are: */
#define TASK_MGMT_FAILED 0
-#define TASK_MGMT_SUCCESS 1
-};
+} __packed;
/* The following is used by uissd to send disk add/remove notifications to
* Guest */
/* Note that the vHba pointer is not used by the Client/Guest side. */
struct uiscmdrsp_disknotify {
- u8 add; /* 0-remove, 1-add */
+ u8 add; /* 0-remove, 1-add */
void *v_hba; /* Pointer to vhba_info for channel info to
* route msg */
u32 channel, id, lun; /* SCSI Path of Disk to added or removed */
-};
+} __packed;
/* The following is used by virthba/vSCSI to send the Acquire/Release commands
-* to the IOVM. */
+ * to the IOVM. */
struct uiscmdrsp_vdiskmgmt {
enum vdisk_mgmt_types vdisktype;
@@ -611,36 +489,38 @@ struct uiscmdrsp_vdiskmgmt {
void *scsicmd;
/* This is some handle that the guest has saved off for its own use.
- * Its value is preserved by iopart & returned as is in the task mgmt
- * rsp. */
+ * Its value is preserved by iopart & returned as is in the task
+ * mgmt rsp.
+ */
void *notify;
/* For linux guests, this is a pointer to wait_queue_head that a
- * thread is waiting on to see if the taskmgmt command has completed.
- * For windows guests, this is a pointer to a location that a waiting
- * thread is testing to see if the taskmgmt command has completed.
- * When the rsp is received by guest, the thread receiving the
- * response uses this to notify the thread waiting for taskmgmt
- * command completion. Its value is preserved by iopart & returned
- * as is in the task mgmt rsp. */
+ * thread is waiting on to see if the tskmgmt command has completed.
+ * For win32 guests, this is a pointer to a location that a waiting
+ * thread is testing to see if the taskmgmt command has completed.
+ * When the rsp is received by guest, the thread receiving the
+ * response uses this to notify the thread waiting for taskmgmt
+ * command completion. Its value is preserved by iopart & returned
+ * as is in the task mgmt rsp.
+ */
void *notifyresult;
/* this is a handle to location in guest where the result of the
- * taskmgmt command (result field) is to saved off when the response
- * is handled. Its value is preserved by iopart & returned as is in
- * the task mgmt rsp. */
+ * taskmgmt command (result field) is to saved off when the response
+ * is handled. Its value is preserved by iopart & returned as is in
+ * the task mgmt rsp.
+ */
char result;
/* result of taskmgmt command - set by IOPart - values are: */
#define VDISK_MGMT_FAILED 0
-#define VDISK_MGMT_SUCCESS 1
-};
+} __packed;
/* keeping cmd & rsp info in one structure for now cmd rsp packet for scsi */
struct uiscmdrsp {
char cmdtype;
- /* describes what type of information is in the struct */
+/* describes what type of information is in the struct */
#define CMD_SCSI_TYPE 1
#define CMD_NET_TYPE 2
#define CMD_SCSITASKMGMT_TYPE 3
@@ -654,63 +534,44 @@ struct uiscmdrsp {
struct uiscmdrsp_vdiskmgmt vdiskmgmt;
};
void *private_data; /* used to send the response when the cmd is
- * done (scsi & scsittaskmgmt). */
+ * done (scsi & scsittaskmgmt). */
struct uiscmdrsp *next; /* General Purpose Queue Link */
struct uiscmdrsp *activeQ_next; /* Used to track active commands */
- struct uiscmdrsp *activeQ_prev; /* Used to track active commands */
-};
-
+ struct uiscmdrsp *activeQ_prev; /* Used to track active commands */
+} __packed;
+
+struct iochannel_vhba {
+ struct vhba_wwnn wwnn; /* 8 bytes */
+ struct vhba_config_max max; /* 20 bytes */
+} __packed; /* total = 28 bytes */
+struct iochannel_vnic {
+ u8 macaddr[6]; /* 6 bytes */
+ u32 num_rcv_bufs; /* 4 bytes */
+ u32 mtu; /* 4 bytes */
+ uuid_le zone_uuid; /* 16 bytes */
+} __packed;
/* This is just the header of the IO channel. It is assumed that directly after
-* this header there is a large region of memory which contains the command and
-* response queues as specified in cmd_q and rsp_q SIGNAL_QUEUE_HEADERS. */
+ * this header there is a large region of memory which contains the command and
+ * response queues as specified in cmd_q and rsp_q SIGNAL_QUEUE_HEADERS.
+ */
struct spar_io_channel_protocol {
struct channel_header channel_header;
struct signal_queue_header cmd_q;
struct signal_queue_header rsp_q;
union {
- struct {
- struct vhba_wwnn wwnn; /* 8 bytes */
- struct vhba_config_max max; /* 20 bytes */
- } vhba; /* 28 */
- struct {
- u8 macaddr[MAX_MACADDR_LEN]; /* 6 bytes */
- u32 num_rcv_bufs; /* 4 */
- u32 mtu; /* 4 */
- uuid_le zone_uuid; /* 16 */
- } vnic; /* total 30 */
- };
+ struct iochannel_vhba vhba;
+ struct iochannel_vnic vnic;
+ } __packed;
#define MAX_CLIENTSTRING_LEN 1024
u8 client_string[MAX_CLIENTSTRING_LEN];/* NULL terminated - so holds
* max - 1 bytes */
-};
+} __packed;
-#pragma pack(pop)
-/* ///////////// END PRAGMA PACK PUSH 1 /////////////////////////// */
-
-/* define offsets to members of struct uiscmdrsp */
-#define OFFSET_CMDTYPE offsetof(struct uiscmdrsp, cmdtype)
-#define OFFSET_SCSI offsetof(struct uiscmdrsp, scsi)
-#define OFFSET_NET offsetof(struct uiscmdrsp, net)
-#define OFFSET_SCSITASKMGMT offsetof(struct uiscmdrsp, scsitaskmgmt)
-#define OFFSET_NEXT offsetof(struct uiscmdrsp, next)
-
-/* define offsets to members of struct uiscmdrsp_net */
-#define OFFSET_TYPE offsetof(struct uiscmdrsp_net, type)
-#define OFFSET_BUF offsetof(struct uiscmdrsp_net, buf)
-#define OFFSET_XMT offsetof(struct uiscmdrsp_net, xmt)
-#define OFFSET_XMT_DONE_RESULT offsetof(struct uiscmdrsp_net, xmtdone)
-#define OFFSET_RCVPOST offsetof(struct uiscmdrsp_net, rcvpost)
-#define OFFSET_RCV_DONE_LEN offsetof(struct uiscmdrsp_net, rcv)
-#define OFFSET_ENBDIS offsetof(struct uiscmdrsp_net, enbdis)
-
-/* define offsets to members of struct net_pkt_rcvpost */
-#define OFFSET_TOTALLEN offsetof(struct net_pkt_rcvpost, totallen)
-#define OFFSET_FRAG offsetof(struct net_pkt_rcvpost, frag)
/*
-* INLINE functions for initializing and accessing I/O data channels
-*/
+ * INLINE functions for initializing and accessing I/O data channels
+ */
#define SIZEOF_PROTOCOL (COVER(sizeof(struct spar_io_channel_protocol), 64))
#define SIZEOF_CMDRSP (COVER(sizeof(struct uiscmdrsp), 64))
@@ -719,16 +580,15 @@ struct spar_io_channel_protocol {
2 * MIN_NUMSIGNALS * SIZEOF_CMDRSP, 4096)
/*
-* INLINE function for expanding a guest's pfn-off-size into multiple 4K page
-* pfn-off-size entires.
-*/
+ * INLINE function for expanding a guest's pfn-off-size into multiple 4K page
+ * pfn-off-size entires.
+ */
/* we deal with 4K page sizes when we it comes to passing page information
* between */
/* Guest and IOPartition. */
#define PI_PAGE_SIZE 0x1000
#define PI_PAGE_MASK 0x0FFF
-#define PI_PAGE_SHIFT 12
/* returns next non-zero index on success or zero on failure (i.e. out of
* room)
diff --git a/drivers/staging/unisys/include/periodic_work.h b/drivers/staging/unisys/include/periodic_work.h
index 26ec10bdf..4e19c28dc 100644
--- a/drivers/staging/unisys/include/periodic_work.h
+++ b/drivers/staging/unisys/include/periodic_work.h
@@ -18,7 +18,9 @@
#ifndef __PERIODIC_WORK_H__
#define __PERIODIC_WORK_H__
-#include "timskmod.h"
+#include <linux/seq_file.h>
+#include <linux/slab.h>
+
/* PERIODIC_WORK an opaque structure to users.
* Fields are declared only in the implementation .c files.
@@ -31,8 +33,8 @@ struct periodic_work *visor_periodic_work_create(ulong jiffy_interval,
void *workfuncarg,
const char *devnam);
void visor_periodic_work_destroy(struct periodic_work *pw);
-BOOL visor_periodic_work_nextperiod(struct periodic_work *pw);
-BOOL visor_periodic_work_start(struct periodic_work *pw);
-BOOL visor_periodic_work_stop(struct periodic_work *pw);
+bool visor_periodic_work_nextperiod(struct periodic_work *pw);
+bool visor_periodic_work_start(struct periodic_work *pw);
+bool visor_periodic_work_stop(struct periodic_work *pw);
#endif
diff --git a/drivers/staging/unisys/include/procobjecttree.h b/drivers/staging/unisys/include/procobjecttree.h
deleted file mode 100644
index 809c67942..000000000
--- a/drivers/staging/unisys/include/procobjecttree.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/* procobjecttree.h
- *
- * Copyright (C) 2010 - 2013 UNISYS CORPORATION
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
- * NON INFRINGEMENT. See the GNU General Public License for more
- * details.
- */
-
-/** @file *********************************************************************
- *
- * This describes the interfaces necessary for creating a tree of types,
- * objects, and properties in /proc.
- *
- ******************************************************************************
- */
-
-#ifndef __PROCOBJECTTREE_H__
-#define __PROCOBJECTTREE_H__
-
-#include "timskmod.h"
-
-/* These are opaque structures to users.
- * Fields are declared only in the implementation .c files.
- */
-typedef struct MYPROCOBJECT_Tag MYPROCOBJECT;
-typedef struct MYPROCTYPE_Tag MYPROCTYPE;
-
-MYPROCOBJECT *visor_proc_CreateObject(MYPROCTYPE *type, const char *name,
- void *context);
-void visor_proc_DestroyObject(MYPROCOBJECT *obj);
-MYPROCTYPE *visor_proc_CreateType(struct proc_dir_entry *procRootDir,
- const char **name,
- const char **propertyNames,
- void (*show_property)(struct seq_file *,
- void *, int));
-void visor_proc_DestroyType(MYPROCTYPE *type);
-
-#endif
diff --git a/drivers/staging/unisys/include/sparstop.h b/drivers/staging/unisys/include/sparstop.h
deleted file mode 100644
index 05837399a..000000000
--- a/drivers/staging/unisys/include/sparstop.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/* sparstop.h
- *
- * Copyright (C) 2010 - 2013 UNISYS CORPORATION
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
- * NON INFRINGEMENT. See the GNU General Public License for more
- * details.
- */
-
-#ifndef __SPARSTOP_H__
-#define __SPARSTOP_H__
-
-#include "timskmod.h"
-#include "version.h"
-#include <linux/ctype.h>
-
-typedef void (*SPARSTOP_COMPLETE_FUNC) (void *context, int status);
-
-int sp_stop(void *context, SPARSTOP_COMPLETE_FUNC get_complete_func);
-void test_remove_stop_device(void);
-
-#endif
diff --git a/drivers/staging/unisys/include/timskmod.h b/drivers/staging/unisys/include/timskmod.h
deleted file mode 100644
index cde2494ad..000000000
--- a/drivers/staging/unisys/include/timskmod.h
+++ /dev/null
@@ -1,153 +0,0 @@
-/* timskmod.h
- *
- * Copyright (C) 2010 - 2013 UNISYS CORPORATION
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
- * NON INFRINGEMENT. See the GNU General Public License for more
- * details.
- */
-
-#ifndef __TIMSKMOD_H__
-#define __TIMSKMOD_H__
-
-#include <linux/version.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/device.h>
-#include <linux/kobject.h>
-#include <linux/sysfs.h>
-#include <linux/fs.h>
-#include <linux/string.h>
-#include <linux/sched.h>
-#include <linux/spinlock.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/interrupt.h>
-#include <linux/wait.h>
-#include <linux/vmalloc.h>
-#include <linux/proc_fs.h>
-#include <linux/cdev.h>
-#include <linux/types.h>
-#include <asm/irq.h>
-#include <linux/io.h>
-#include <asm/dma.h>
-#include <linux/uaccess.h>
-#include <linux/list.h>
-#include <linux/poll.h>
-/* #define EXPORT_SYMTAB */
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/fcntl.h>
-#include <linux/workqueue.h>
-#include <linux/kthread.h>
-#include <linux/seq_file.h>
-#include <linux/mm.h>
-
-/* #define DEBUG */
-#ifndef BOOL
-#define BOOL int
-#endif
-#define FALSE 0
-#define TRUE 1
-#if !defined SUCCESS
-#define SUCCESS 0
-#endif
-#define MIN(a, b) (((a) < (b)) ? (a) : (b))
-#define MAX(a, b) (((a) > (b)) ? (a) : (b))
-#define STRUCTSEQUAL(x, y) (memcmp(&x, &y, sizeof(x)) == 0)
-#ifndef HOSTADDRESS
-#define HOSTADDRESS unsigned long long
-#endif
-
-#define sizeofmember(TYPE, MEMBER) (sizeof(((TYPE *)0)->MEMBER))
-/** "Covered quotient" function */
-#define COVQ(v, d) (((v) + (d) - 1) / (d))
-#define SWAPPOINTERS(p1, p2) \
- do { \
- void *SWAPPOINTERS_TEMP = (void *)p1; \
- (void *)(p1) = (void *)(p2); \
- (void *)(p2) = SWAPPOINTERS_TEMP; \
- } while (0)
-
-#define WARNDRV(fmt, args...) LOGWRN(fmt, ## args)
-#define SECUREDRV(fmt, args...) LOGWRN(fmt, ## args)
-
-#define PRINTKDEV(devname, fmt, args...) LOGINFDEV(devname, fmt, ## args)
-#define TBDDEV(devname, fmt, args...) LOGERRDEV(devname, fmt, ## args)
-#define HUHDEV(devname, fmt, args...) LOGERRDEV(devname, fmt, ## args)
-#define ERRDEV(devname, fmt, args...) LOGERRDEV(devname, fmt, ## args)
-#define ERRDEVX(devno, fmt, args...) LOGERRDEVX(devno, fmt, ## args)
-#define WARNDEV(devname, fmt, args...) LOGWRNDEV(devname, fmt, ## args)
-#define SECUREDEV(devname, fmt, args...) LOGWRNDEV(devname, fmt, ## args)
-#define INFODEV(devname, fmt, args...) LOGINFDEV(devname, fmt, ## args)
-#define INFODEVX(devno, fmt, args...) LOGINFDEVX(devno, fmt, ## args)
-
-/** Verifies the consistency of your PRIVATEDEVICEDATA structure using
- * conventional "signature" fields:
- * <p>
- * - sig1 should contain the size of the structure
- * - sig2 should contain a pointer to the beginning of the structure
- */
-#define DDLOOKSVALID(dd) \
- ((dd != NULL) && \
- ((dd)->sig1 == sizeof(PRIVATEDEVICEDATA)) && \
- ((dd)->sig2 == dd))
-
-/** Verifies the consistency of your PRIVATEFILEDATA structure using
- * conventional "signature" fields:
- * <p>
- * - sig1 should contain the size of the structure
- * - sig2 should contain a pointer to the beginning of the structure
- */
-#define FDLOOKSVALID(fd) \
- ((fd != NULL) && \
- ((fd)->sig1 == sizeof(PRIVATEFILEDATA)) && \
- ((fd)->sig2 == fd))
-
-/** Sleep for an indicated number of seconds (for use in kernel mode).
- * x - the number of seconds to sleep.
- */
-#define SLEEP(x) \
- do { __set_current_state(TASK_INTERRUPTIBLE); \
- schedule_timeout((x)*HZ); \
- } while (0)
-
-/** Sleep for an indicated number of jiffies (for use in kernel mode).
- * x - the number of jiffies to sleep.
- */
-#define SLEEPJIFFIES(x) \
- do { __set_current_state(TASK_INTERRUPTIBLE); \
- schedule_timeout(x); \
- } while (0)
-
-static inline struct cdev *cdev_alloc_init(struct module *owner,
- const struct file_operations *fops)
-{
- struct cdev *cdev = NULL;
-
- cdev = cdev_alloc();
- if (!cdev)
- return NULL;
- cdev->ops = fops;
- cdev->owner = owner;
-
- /* Note that the memory allocated for cdev will be deallocated
- * when the usage count drops to 0, because it is controlled
- * by a kobject of type ktype_cdev_dynamic. (This
- * deallocation could very well happen outside of our kernel
- * module, like via the cdev_put in __fput() for example.)
- */
- return cdev;
-}
-
-extern int unisys_spar_platform;
-
-#endif
diff --git a/drivers/staging/unisys/include/uisqueue.h b/drivers/staging/unisys/include/uisqueue.h
deleted file mode 100644
index 08ba16ea8..000000000
--- a/drivers/staging/unisys/include/uisqueue.h
+++ /dev/null
@@ -1,396 +0,0 @@
-/* uisqueue.h
- *
- * Copyright (C) 2010 - 2013 UNISYS CORPORATION
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
- * NON INFRINGEMENT. See the GNU General Public License for more
- * details.
- */
-
-/*
- * Unisys IO Virtualization header NOTE: This file contains only Linux
- * specific structs. All OS-independent structs are in iochannel.h.xx
- */
-
-#ifndef __UISQUEUE_H__
-#define __UISQUEUE_H__
-
-#include "linux/version.h"
-#include "iochannel.h"
-#include <linux/atomic.h>
-#include <linux/semaphore.h>
-#include <linux/uuid.h>
-
-#include "controlvmchannel.h"
-#include "controlvmcompletionstatus.h"
-
-struct uisqueue_info {
- struct channel_header __iomem *chan;
- /* channel containing queues in which scsi commands &
- * responses are queued
- */
- u64 packets_sent;
- u64 packets_received;
- u64 interrupts_sent;
- u64 interrupts_received;
- u64 max_not_empty_cnt;
- u64 total_wakeup_cnt;
- u64 non_empty_wakeup_cnt;
-
- struct {
- struct signal_queue_header reserved1; /* */
- struct signal_queue_header reserved2; /* */
- } safe_uis_queue;
- unsigned int (*send_int_if_needed)(struct uisqueue_info *info,
- unsigned int whichcqueue,
- unsigned char issue_irq_if_empty,
- u64 irq_handle,
- unsigned char io_termination);
-};
-
-/* uisqueue_put_cmdrsp_with_lock_client queues a commmand or response
- * to the specified queue, at the tail if the queue is full but
- * oktowait == 0, then it return 0 indicating failure. otherwise it
- * wait for the queue to become non-full. If command is queued, return
- * 1 for success.
- */
-#define DONT_ISSUE_INTERRUPT 0
-#define ISSUE_INTERRUPT 1
-
-#define DONT_WAIT 0
-#define OK_TO_WAIT 1
-#define UISLIB_LOCK_PREFIX \
- ".section .smp_locks,\"a\"\n" \
- _ASM_ALIGN "\n" \
- _ASM_PTR "661f\n" /* address */ \
- ".previous\n" \
- "661:\n\tlock; "
-
-unsigned long long uisqueue_interlocked_or(unsigned long long __iomem *tgt,
- unsigned long long set);
-unsigned long long uisqueue_interlocked_and(unsigned long long __iomem *tgt,
- unsigned long long set);
-
-int uisqueue_put_cmdrsp_with_lock_client(struct uisqueue_info *queueinfo,
- struct uiscmdrsp *cmdrsp,
- unsigned int queue,
- void *insertlock,
- unsigned char issue_irq_if_empty,
- u64 irq_handle,
- char oktowait,
- u8 *channel_id);
-
-/* uisqueue_get_cmdrsp gets the cmdrsp entry at the head of the queue
- * and copies it to the area pointed by cmdrsp param.
- * returns 0 if queue is empty, 1 otherwise
- */
-int
-
-uisqueue_get_cmdrsp(struct uisqueue_info *queueinfo, void *cmdrsp,
- unsigned int queue);
-
-#define MAX_NAME_SIZE_UISQUEUE 64
-
-struct extport_info {
- u8 valid:1;
- /* if 1, indicates this extport slot is occupied
- * if 0, indicates that extport slot is unoccupied */
-
- u32 num_devs_using;
- /* When extport is added, this is set to 0. For exports
- * located in NETWORK switches:
- * Each time a VNIC, i.e., intport, is added to the switch this
- * is used to assign a pref_pnic for the VNIC and when assigned
- * to a VNIC this counter is incremented. When a VNIC is
- * deleted, the extport corresponding to the VNIC's pref_pnic
- * is located and its num_devs_using is decremented. For VNICs,
- * num_devs_using is basically used to load-balance transmit
- * traffic from VNICs.
- */
-
- struct switch_info *swtch;
- struct pci_id pci_id;
- char name[MAX_NAME_SIZE_UISQUEUE];
- union {
- struct vhba_wwnn wwnn;
- unsigned char macaddr[MAX_MACADDR_LEN];
- };
-};
-
-struct device_info {
- void __iomem *chanptr;
- u64 channel_addr;
- u64 channel_bytes;
- uuid_le channel_uuid;
- uuid_le instance_uuid;
- struct irq_info intr;
- struct switch_info *swtch;
- char devid[30]; /* "vbus<busno>:dev<devno>" */
- u16 polling;
- struct semaphore interrupt_callback_lock;
- u32 bus_no;
- u32 dev_no;
- int (*interrupt)(void *);
- void *interrupt_context;
- void *private_data;
- struct list_head list_polling_device_channels;
- unsigned long long moved_to_tail_cnt;
- unsigned long long first_busy_cnt;
- unsigned long long last_on_list_cnt;
-};
-
-enum switch_type {
- RECOVERY_LAN = 1,
- IB_LAN = 2
-};
-
-struct bus_info {
- u32 bus_no, device_count;
- struct device_info **device;
- u64 guest_handle, recv_bus_irq_handle;
- uuid_le bus_inst_uuid;
- struct ultra_vbus_channel_protocol __iomem *bus_channel;
- int bus_channel_bytes;
- struct proc_dir_entry *proc_dir; /* proc/uislib/vbus/<x> */
- struct proc_dir_entry *proc_info; /* proc/uislib/vbus/<x>/info */
- char name[25];
- char partition_name[99];
- struct bus_info *next;
- u8 local_vnic; /* 1 if local vnic created internally
- * by IOVM; 0 otherwise... */
-};
-
-struct sn_list_entry {
- struct uisscsi_dest pdest; /* scsi bus, target, lun for
- * phys disk */
- u8 sernum[MAX_SERIAL_NUM]; /* serial num of physical
- * disk.. The length is always
- * MAX_SERIAL_NUM, padded with
- * spaces */
- struct sn_list_entry *next;
-};
-
-/*
- * IO messages sent to UisnicControlChanFunc & UissdControlChanFunc by
- * code that processes the ControlVm channel messages.
- */
-
-enum iopart_msg_type {
- IOPART_ADD_VNIC,
- IOPART_DEL_VNIC,
- IOPART_DEL_ALL_VNICS,
- IOPART_ADD_VHBA,
- IOPART_ADD_VDISK,
- IOPART_DEL_VHBA,
- IOPART_DEL_VDISK,
- IOPART_DEL_ALL_VDISKS_FOR_VHBA,
- IOPART_DEL_ALL_VHBAS,
- IOPART_ATTACH_PHBA,
- IOPART_DETACH_PHBA, /* 10 */
- IOPART_ATTACH_PNIC,
- IOPART_DETACH_PNIC,
- IOPART_DETACH_VHBA,
- IOPART_DETACH_VNIC,
- IOPART_PAUSE_VDISK,
- IOPART_RESUME_VDISK,
- IOPART_ADD_DEVICE, /* add generic device */
- IOPART_DEL_DEVICE, /* del generic device */
-};
-
-struct add_virt_iopart {
- void *chanptr; /* pointer to data channel */
- u64 guest_handle; /* used to convert guest physical
- * address to real physical address
- * for DMA, for ex. */
- u64 recv_bus_irq_handle; /* used to register to receive
- * bus level interrupts. */
- struct irq_info intr; /* contains recv & send
- * interrupt info */
- /* recvInterruptHandle is used to register to receive
- * interrupts on the data channel. Used by GuestLinux/Windows
- * IO drivers to connect to interrupt. sendInterruptHandle is
- * used by IOPart drivers as parameter to
- * Issue_VMCALL_IO_QUEUE_TRANSITION to interrupt thread in
- * guest linux/windows IO drivers when data channel queue for
- * vhba/vnic goes from EMPTY to NON-EMPTY. */
- struct switch_info *swtch; /* pointer to the virtual
- * switch to which the vnic is
- * connected */
-
- u8 use_g2g_copy; /* Used to determine if a virtual HBA
- * needs to use G2G copy. */
- u8 filler[7];
-
- u32 bus_no;
- u32 dev_no;
- char *params;
- ulong params_bytes;
-
-};
-
-struct add_vdisk_iopart {
- void *chanptr; /* pointer to data channel */
- int implicit;
- struct uisscsi_dest vdest; /* scsi bus, target, lun for virt disk */
- struct uisscsi_dest pdest; /* scsi bus, target, lun for phys disk */
- u8 sernum[MAX_SERIAL_NUM]; /* serial num of physical disk */
- u32 serlen; /* length of serial num */
-};
-
-struct del_vdisk_iopart {
- void *chanptr; /* pointer to data channel */
- struct uisscsi_dest vdest; /* scsi bus, target, lun for virt disk */
-};
-
-struct del_virt_iopart {
- void *chanptr; /* pointer to data channel */
-};
-
-struct det_virt_iopart { /* detach internal port */
- void *chanptr; /* pointer to data channel */
- struct switch_info *swtch;
-};
-
-struct paures_vdisk_iopart {
- void *chanptr; /* pointer to data channel */
- struct uisscsi_dest vdest; /* scsi bus, target, lun for virt disk */
-};
-
-struct add_switch_iopart { /* add switch */
- struct switch_info *swtch;
- char *params;
- ulong params_bytes;
-};
-
-struct del_switch_iopart { /* destroy switch */
- struct switch_info *swtch;
-};
-
-struct io_msgs {
- enum iopart_msg_type msgtype;
-
- /* additional params needed by some messages */
- union {
- struct add_virt_iopart add_vhba;
- struct add_virt_iopart add_vnic;
- struct add_vdisk_iopart add_vdisk;
- struct del_virt_iopart del_vhba;
- struct del_virt_iopart del_vnic;
- struct det_virt_iopart det_vhba;
- struct det_virt_iopart det_vnic;
- struct del_vdisk_iopart del_vdisk;
- struct del_virt_iopart del_all_vdisks_for_vhba;
- struct add_virt_iopart add_device;
- struct del_virt_iopart del_device;
- struct det_virt_iopart det_intport;
- struct add_switch_iopart add_switch;
- struct del_switch_iopart del_switch;
- struct extport_info *ext_port; /* for attach or detach
- * pnic/generic delete all
- * vhbas/allvnics need no
- * parameters */
- struct paures_vdisk_iopart paures_vdisk;
- };
-};
-
-/*
-* Guest messages sent to VirtControlChanFunc by code that processes
-* the ControlVm channel messages.
-*/
-
-enum guestpart_msg_type {
- GUEST_ADD_VBUS,
- GUEST_ADD_VHBA,
- GUEST_ADD_VNIC,
- GUEST_DEL_VBUS,
- GUEST_DEL_VHBA,
- GUEST_DEL_VNIC,
- GUEST_DEL_ALL_VHBAS,
- GUEST_DEL_ALL_VNICS,
- GUEST_DEL_ALL_VBUSES, /* deletes all vhbas & vnics on all
- * buses and deletes all buses */
- GUEST_PAUSE_VHBA,
- GUEST_PAUSE_VNIC,
- GUEST_RESUME_VHBA,
- GUEST_RESUME_VNIC
-};
-
-struct add_vbus_guestpart {
- void __iomem *chanptr; /* pointer to data channel for bus -
- * NOT YET USED */
- u32 bus_no; /* bus number to be created/deleted */
- u32 dev_count; /* max num of devices on bus */
- uuid_le bus_uuid; /* indicates type of bus */
- uuid_le instance_uuid; /* instance guid for device */
-};
-
-struct del_vbus_guestpart {
- u32 bus_no; /* bus number to be deleted */
- /* once we start using the bus's channel, add can dump busNo
- * into the channel header and then delete will need only one
- * parameter, chanptr. */
-};
-
-struct add_virt_guestpart {
- void __iomem *chanptr; /* pointer to data channel */
- u32 bus_no; /* bus number for the operation */
- u32 device_no; /* number of device on the bus */
- uuid_le instance_uuid; /* instance guid for device */
- struct irq_info intr; /* recv/send interrupt info */
- /* recvInterruptHandle contains info needed in order to
- * register to receive interrupts on the data channel.
- * sendInterruptHandle contains handle which is provided to
- * monitor VMCALL that will cause an interrupt to be generated
- * for the other end.
- */
-};
-
-struct pause_virt_guestpart {
- void __iomem *chanptr; /* pointer to data channel */
-};
-
-struct resume_virt_guestpart {
- void __iomem *chanptr; /* pointer to data channel */
-};
-
-struct del_virt_guestpart {
- void __iomem *chanptr; /* pointer to data channel */
-};
-
-struct init_chipset_guestpart {
- u32 bus_count; /* indicates the max number of busses */
- u32 switch_count; /* indicates the max number of switches */
-};
-
-struct guest_msgs {
- enum guestpart_msg_type msgtype;
-
- /* additional params needed by messages */
- union {
- struct add_vbus_guestpart add_vbus;
- struct add_virt_guestpart add_vhba;
- struct add_virt_guestpart add_vnic;
- struct pause_virt_guestpart pause_vhba;
- struct pause_virt_guestpart pause_vnic;
- struct resume_virt_guestpart resume_vhba;
- struct resume_virt_guestpart resume_vnic;
- struct del_vbus_guestpart del_vbus;
- struct del_virt_guestpart del_vhba;
- struct del_virt_guestpart del_vnic;
- struct del_vbus_guestpart del_all_vhbas;
- struct del_vbus_guestpart del_all_vnics;
- /* del_all_vbuses needs no parameters */
- };
- struct init_chipset_guestpart init_chipset;
-
-};
-
-#endif /* __UISQUEUE_H__ */
diff --git a/drivers/staging/unisys/include/uisthread.h b/drivers/staging/unisys/include/uisthread.h
deleted file mode 100644
index 52c3eb4de..000000000
--- a/drivers/staging/unisys/include/uisthread.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/* uisthread.h
- *
- * Copyright (C) 2010 - 2013 UNISYS CORPORATION
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
- * NON INFRINGEMENT. See the GNU General Public License for more
- * details.
- */
-
-/*****************************************************************************/
-/* Unisys thread utilities header */
-/*****************************************************************************/
-
-#ifndef __UISTHREAD_H__
-#define __UISTHREAD_H__
-
-#include "linux/completion.h"
-
-struct uisthread_info {
- struct task_struct *task;
- int id;
- struct completion has_stopped;
-};
-
-/* returns 0 for failure, 1 for success */
-int uisthread_start(
- struct uisthread_info *thrinfo,
- int (*threadfn)(void *),
- void *thrcontext,
- char *name);
-
-void uisthread_stop(struct uisthread_info *thrinfo);
-
-#endif /* __UISTHREAD_H__ */
diff --git a/drivers/staging/unisys/include/uisutils.h b/drivers/staging/unisys/include/uisutils.h
deleted file mode 100644
index c7d0ba8aa..000000000
--- a/drivers/staging/unisys/include/uisutils.h
+++ /dev/null
@@ -1,299 +0,0 @@
-/* uisutils.h
- *
- * Copyright (C) 2010 - 2013 UNISYS CORPORATION
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
- * NON INFRINGEMENT. See the GNU General Public License for more
- * details.
- */
-
-/*
- * Unisys Virtual HBA utilities header
- */
-
-#ifndef __UISUTILS__H__
-#define __UISUTILS__H__
-#include <linux/string.h>
-#include <linux/io.h>
-#include <linux/sched.h>
-#include <linux/gfp.h>
-#include <linux/uuid.h>
-#include <linux/if_ether.h>
-
-#include "vmcallinterface.h"
-#include "channel.h"
-#include "uisthread.h"
-#include "uisqueue.h"
-#include "diagnostics/appos_subsystems.h"
-#include "vbusdeviceinfo.h"
-#include <linux/atomic.h>
-
-/* This is the MAGIC number stuffed by virthba in host->this_id. Used to
- * identify virtual hbas.
- */
-#define UIS_MAGIC_VHBA 707
-
-/* global function pointers that act as callback functions into
- * uisnicmod, uissdmod, and virtpcimod
- */
-extern int (*uisnic_control_chan_func)(struct io_msgs *);
-extern int (*uissd_control_chan_func)(struct io_msgs *);
-extern int (*virt_control_chan_func)(struct guest_msgs *);
-
-/* Return values of above callback functions: */
-#define CCF_ERROR 0 /* completed and failed */
-#define CCF_OK 1 /* completed successfully */
-#define CCF_PENDING 2 /* operation still pending */
-extern atomic_t uisutils_registered_services;
-
-struct req_handler_info {
- uuid_le switch_uuid;
- int (*controlfunc)(struct io_msgs *);
- unsigned long min_channel_bytes;
- int (*server_channel_ok)(unsigned long channel_bytes);
- int (*server_channel_init)(void *x, unsigned char *client_str,
- u32 client_str_len, u64 bytes);
- char switch_type_name[99];
- struct list_head list_link; /* links into ReqHandlerInfo_list */
-};
-
-struct req_handler_info *req_handler_find(uuid_le switch_uuid);
-
-#define uislib_ioremap_cache(addr, size) \
- dbg_ioremap_cache(addr, size, __FILE__, __LINE__)
-
-static inline void __iomem *
-dbg_ioremap_cache(u64 addr, unsigned long size, char *file, int line)
-{
- void __iomem *new;
-
- new = ioremap_cache(addr, size);
- return new;
-}
-
-#define uislib_ioremap(addr, size) dbg_ioremap(addr, size, __FILE__, __LINE__)
-
-static inline void *
-dbg_ioremap(u64 addr, unsigned long size, char *file, int line)
-{
- void *new;
-
- new = ioremap(addr, size);
- return new;
-}
-
-#define uislib_iounmap(addr) dbg_iounmap(addr, __FILE__, __LINE__)
-
-static inline void
-dbg_iounmap(void __iomem *addr, char *file, int line)
-{
- iounmap(addr);
-}
-
-#define PROC_READ_BUFFER_SIZE 131072 /* size of the buffer to allocate to
- * hold all of /proc/XXX/info */
-int uisutil_add_proc_line_ex(int *total, char **buffer, int *buffer_remaining,
- char *format, ...);
-
-int uisctrl_register_req_handler(int type, void *fptr,
- struct ultra_vbus_deviceinfo *chipset_driver_info);
-
-unsigned char *util_map_virt(struct phys_info *sg);
-void util_unmap_virt(struct phys_info *sg);
-unsigned char *util_map_virt_atomic(struct phys_info *sg);
-void util_unmap_virt_atomic(void *buf);
-int uislib_client_inject_add_bus(u32 bus_no, uuid_le inst_uuid,
- u64 channel_addr, ulong n_channel_bytes);
-int uislib_client_inject_del_bus(u32 bus_no);
-
-int uislib_client_inject_add_vhba(u32 bus_no, u32 dev_no,
- u64 phys_chan_addr, u32 chan_bytes,
- int is_test_addr, uuid_le inst_uuid,
- struct irq_info *intr);
-int uislib_client_inject_pause_vhba(u32 bus_no, u32 dev_no);
-int uislib_client_inject_resume_vhba(u32 bus_no, u32 dev_no);
-int uislib_client_inject_del_vhba(u32 bus_no, u32 dev_no);
-int uislib_client_inject_add_vnic(u32 bus_no, u32 dev_no,
- u64 phys_chan_addr, u32 chan_bytes,
- int is_test_addr, uuid_le inst_uuid,
- struct irq_info *intr);
-int uislib_client_inject_pause_vnic(u32 bus_no, u32 dev_no);
-int uislib_client_inject_resume_vnic(u32 bus_no, u32 dev_no);
-int uislib_client_inject_del_vnic(u32 bus_no, u32 dev_no);
-#ifdef STORAGE_CHANNEL
-u64 uislib_storage_channel(int client_id);
-#endif
-int uislib_get_owned_pdest(struct uisscsi_dest *pdest);
-
-int uislib_send_event(enum controlvm_id id,
- struct controlvm_message_packet *event);
-
-/* structure used by vhba & vnic to keep track of queue & thread info */
-struct chaninfo {
- struct uisqueue_info *queueinfo;
- /* this specifies the queue structures for a channel */
- /* ALLOCATED BY THE OTHER END - WE JUST GET A POINTER TO THE MEMORY */
- spinlock_t insertlock;
- /* currently used only in virtnic when sending data to uisnic */
- /* to synchronize the inserts into the signal queue */
- struct uisthread_info threadinfo;
- /* this specifies the thread structures used by the thread that */
- /* handles this channel */
-};
-
-/* this is the wait code for all the threads - it is used to get
-* something from a queue choices: wait_for_completion_interruptible,
-* _timeout, interruptible_timeout
-*/
-#define UIS_THREAD_WAIT_MSEC(x) { \
- set_current_state(TASK_INTERRUPTIBLE); \
- schedule_timeout(msecs_to_jiffies(x)); \
-}
-
-#define UIS_THREAD_WAIT_USEC(x) { \
- set_current_state(TASK_INTERRUPTIBLE); \
- schedule_timeout(usecs_to_jiffies(x)); \
-}
-
-#define UIS_THREAD_WAIT UIS_THREAD_WAIT_MSEC(5)
-
-#define UIS_THREAD_WAIT_SEC(x) { \
- set_current_state(TASK_INTERRUPTIBLE); \
- schedule_timeout((x)*HZ); \
-}
-
-/* This is a hack until we fix IOVM to initialize the channel header
- * correctly at DEVICE_CREATE time, INSTEAD OF waiting until
- * DEVICE_CONFIGURE time.
- */
-static inline void
-wait_for_valid_guid(uuid_le __iomem *guid)
-{
- uuid_le tmpguid;
-
- while (1) {
- memcpy_fromio((void *)&tmpguid,
- (void __iomem *)guid, sizeof(uuid_le));
- if (uuid_le_cmp(tmpguid, NULL_UUID_LE) != 0)
- break;
- UIS_THREAD_WAIT_SEC(5);
- }
-}
-
-static inline unsigned int
-issue_vmcall_io_controlvm_addr(u64 *control_addr, u32 *control_bytes)
-{
- struct vmcall_io_controlvm_addr_params params;
- int result = VMCALL_SUCCESS;
- u64 physaddr;
-
- physaddr = virt_to_phys(&params);
- ISSUE_IO_VMCALL(VMCALL_IO_CONTROLVM_ADDR, physaddr, result);
- if (VMCALL_SUCCESSFUL(result)) {
- *control_addr = params.address;
- *control_bytes = params.channel_bytes;
- }
- return result;
-}
-
-static inline unsigned int issue_vmcall_io_diag_addr(u64 *diag_channel_addr)
-{
- struct vmcall_io_diag_addr_params params;
- int result = VMCALL_SUCCESS;
- u64 physaddr;
-
- physaddr = virt_to_phys(&params);
- ISSUE_IO_VMCALL(VMCALL_IO_DIAG_ADDR, physaddr, result);
- if (VMCALL_SUCCESSFUL(result))
- *diag_channel_addr = params.address;
- return result;
-}
-
-static inline unsigned int issue_vmcall_io_visorserial_addr(u64 *channel_addr)
-{
- struct vmcall_io_visorserial_addr_params params;
- int result = VMCALL_SUCCESS;
- u64 physaddr;
-
- physaddr = virt_to_phys(&params);
- ISSUE_IO_VMCALL(VMCALL_IO_VISORSERIAL_ADDR, physaddr, result);
- if (VMCALL_SUCCESSFUL(result))
- *channel_addr = params.address;
- return result;
-}
-
-static inline s64 issue_vmcall_query_guest_virtual_time_offset(void)
-{
- u64 result = VMCALL_SUCCESS;
- u64 physaddr = 0;
-
- ISSUE_IO_VMCALL(VMCALL_QUERY_GUEST_VIRTUAL_TIME_OFFSET, physaddr,
- result);
- return result;
-}
-
-struct log_info_t {
- unsigned long long last_cycles;
- unsigned long long delta_sum[64];
- unsigned long long delta_cnt[64];
- unsigned long long max_delta[64];
- unsigned long long min_delta[64];
-};
-
-static inline int issue_vmcall_update_physical_time(u64 adjustment)
-{
- int result = VMCALL_SUCCESS;
-
- ISSUE_IO_VMCALL(VMCALL_UPDATE_PHYSICAL_TIME, adjustment, result);
- return result;
-}
-
-static inline unsigned int issue_vmcall_channel_mismatch(const char *chname,
- const char *item_name, u32 line_no,
- const char *path_n_fn)
-{
- struct vmcall_channel_version_mismatch_params params;
- int result = VMCALL_SUCCESS;
- u64 physaddr;
- char *last_slash = NULL;
-
- strlcpy(params.chname, chname, sizeof(params.chname));
- strlcpy(params.item_name, item_name, sizeof(params.item_name));
- params.line_no = line_no;
-
- last_slash = strrchr(path_n_fn, '/');
- if (last_slash != NULL) {
- last_slash++;
- strlcpy(params.file_name, last_slash, sizeof(params.file_name));
- } else
- strlcpy(params.file_name,
- "Cannot determine source filename",
- sizeof(params.file_name));
-
- physaddr = virt_to_phys(&params);
- ISSUE_IO_VMCALL(VMCALL_CHANNEL_VERSION_MISMATCH, physaddr, result);
- return result;
-}
-
-#define UIS_DAEMONIZE(nam)
-void *uislib_cache_alloc(struct kmem_cache *cur_pool, char *fn, int ln);
-#define UISCACHEALLOC(cur_pool) uislib_cache_alloc(cur_pool, __FILE__, __LINE__)
-void uislib_cache_free(struct kmem_cache *cur_pool, void *p, char *fn, int ln);
-#define UISCACHEFREE(cur_pool, p) \
- uislib_cache_free(cur_pool, p, __FILE__, __LINE__)
-
-void uislib_enable_channel_interrupts(u32 bus_no, u32 dev_no,
- int (*interrupt)(void *),
- void *interrupt_context);
-void uislib_disable_channel_interrupts(u32 bus_no, u32 dev_no);
-void uislib_force_channel_interrupt(u32 bus_no, u32 dev_no);
-
-#endif /* __UISUTILS__H__ */
diff --git a/drivers/staging/unisys/include/vbushelper.h b/drivers/staging/unisys/include/vbushelper.h
index 84abe5f99..f272975b2 100644
--- a/drivers/staging/unisys/include/vbushelper.h
+++ b/drivers/staging/unisys/include/vbushelper.h
@@ -18,8 +18,6 @@
#ifndef __VBUSHELPER_H__
#define __VBUSHELPER_H__
-#include "vbusdeviceinfo.h"
-
/* TARGET_HOSTNAME specified as -DTARGET_HOSTNAME=\"thename\" on the
* command line */
diff --git a/drivers/staging/unisys/common-spar/include/version.h b/drivers/staging/unisys/include/version.h
index 83d1da7a2..83d1da7a2 100644
--- a/drivers/staging/unisys/common-spar/include/version.h
+++ b/drivers/staging/unisys/include/version.h
diff --git a/drivers/staging/unisys/include/visorbus.h b/drivers/staging/unisys/include/visorbus.h
new file mode 100644
index 000000000..e4a21e42e
--- /dev/null
+++ b/drivers/staging/unisys/include/visorbus.h
@@ -0,0 +1,222 @@
+/* visorbus.h
+ *
+ * Copyright (C) 2010 - 2013 UNISYS CORPORATION
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ */
+
+/*
+ * This header file is to be included by other kernel mode components that
+ * implement a particular kind of visor_device. Each of these other kernel
+ * mode components is called a visor device driver. Refer to visortemplate
+ * for a minimal sample visor device driver.
+ *
+ * There should be nothing in this file that is private to the visorbus
+ * bus implementation itself.
+ *
+ */
+
+#ifndef __VISORBUS_H__
+#define __VISORBUS_H__
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/poll.h>
+#include <linux/kernel.h>
+#include <linux/uuid.h>
+
+#include "periodic_work.h"
+#include "channel.h"
+
+struct visor_driver;
+struct visor_device;
+extern struct bus_type visorbus_type;
+
+typedef void (*visorbus_state_complete_func) (struct visor_device *dev,
+ int status);
+struct visorchipset_state {
+ u32 created:1;
+ u32 attached:1;
+ u32 configured:1;
+ u32 running:1;
+ /* Add new fields above. */
+ /* Remaining bits in this 32-bit word are unused. */
+};
+
+/** This struct describes a specific Supervisor channel, by providing its
+ * GUID, name, and sizes.
+ */
+struct visor_channeltype_descriptor {
+ const uuid_le guid;
+ const char *name;
+};
+
+/** Information provided by each visor driver when it registers with the
+ * visorbus driver.
+ */
+struct visor_driver {
+ const char *name;
+ const char *version;
+ const char *vertag;
+ const char *build_date;
+ const char *build_time;
+ struct module *owner;
+
+ /** Types of channels handled by this driver, ending with 0 GUID.
+ * Our specialized BUS.match() method knows about this list, and
+ * uses it to determine whether this driver will in fact handle a
+ * new device that it has detected.
+ */
+ struct visor_channeltype_descriptor *channel_types;
+
+ /** Called when a new device comes online, by our probe() function
+ * specified by driver.probe() (triggered ultimately by some call
+ * to driver_register() / bus_add_driver() / driver_attach()).
+ */
+ int (*probe)(struct visor_device *dev);
+
+ /** Called when a new device is removed, by our remove() function
+ * specified by driver.remove() (triggered ultimately by some call
+ * to device_release_driver()).
+ */
+ void (*remove)(struct visor_device *dev);
+
+ /** Called periodically, whenever there is a possibility that
+ * "something interesting" may have happened to the channel state.
+ */
+ void (*channel_interrupt)(struct visor_device *dev);
+
+ /** Called to initiate a change of the device's state. If the return
+ * valu`e is < 0, there was an error and the state transition will NOT
+ * occur. If the return value is >= 0, then the state transition was
+ * INITIATED successfully, and complete_func() will be called (or was
+ * just called) with the final status when either the state transition
+ * fails or completes successfully.
+ */
+ int (*pause)(struct visor_device *dev,
+ visorbus_state_complete_func complete_func);
+ int (*resume)(struct visor_device *dev,
+ visorbus_state_complete_func complete_func);
+
+ /** These fields are for private use by the bus driver only. */
+ struct device_driver driver;
+ struct driver_attribute version_attr;
+};
+
+#define to_visor_driver(x) container_of(x, struct visor_driver, driver)
+
+/** A device type for things "plugged" into the visorbus bus */
+
+struct visor_device {
+ /** visor driver can use the visorchannel member with the functions
+ * defined in visorchannel.h to access the channel
+ */
+ struct visorchannel *visorchannel;
+ uuid_le channel_type_guid;
+ u64 channel_bytes;
+
+ /** These fields are for private use by the bus driver only.
+ * A notable exception is that the visor driver can use
+ * visor_get_drvdata() and visor_set_drvdata() to retrieve or stash
+ * private visor driver specific data within the device member.
+ */
+ struct device device;
+ struct list_head list_all;
+ struct periodic_work *periodic_work;
+ bool being_removed;
+ bool responded_to_device_create;
+ struct kobject kobjdevmajorminor; /* visorbus<x>/dev<y>/devmajorminor/*/
+ struct {
+ int major, minor;
+ void *attr; /* private use by devmajorminor_attr.c you can
+ * change this constant to whatever you
+ * want; */
+ } devnodes[5];
+ /* the code will detect and behave appropriately) */
+ struct semaphore visordriver_callback_lock;
+ bool pausing;
+ bool resuming;
+ u32 chipset_bus_no;
+ u32 chipset_dev_no;
+ struct visorchipset_state state;
+ uuid_le type;
+ uuid_le inst;
+ u8 *name;
+ u8 *description;
+ struct controlvm_message_header *pending_msg_hdr;
+ void *vbus_hdr_info;
+ u32 switch_no;
+ u32 internal_port_no;
+ uuid_le partition_uuid;
+};
+
+#define to_visor_device(x) container_of(x, struct visor_device, device)
+
+#ifndef STANDALONE_CLIENT
+int visorbus_register_visor_driver(struct visor_driver *);
+void visorbus_unregister_visor_driver(struct visor_driver *);
+int visorbus_read_channel(struct visor_device *dev,
+ unsigned long offset, void *dest,
+ unsigned long nbytes);
+int visorbus_write_channel(struct visor_device *dev,
+ unsigned long offset, void *src,
+ unsigned long nbytes);
+int visorbus_clear_channel(struct visor_device *dev,
+ unsigned long offset, u8 ch, unsigned long nbytes);
+int visorbus_registerdevnode(struct visor_device *dev,
+ const char *name, int major, int minor);
+void visorbus_enable_channel_interrupts(struct visor_device *dev);
+void visorbus_disable_channel_interrupts(struct visor_device *dev);
+#endif
+
+/* Note that for visorchannel_create()
+ * <channel_bytes> and <guid> arguments may be 0 if we are a channel CLIENT.
+ * In this case, the values can simply be read from the channel header.
+ */
+struct visorchannel *visorchannel_create(u64 physaddr,
+ unsigned long channel_bytes,
+ gfp_t gfp, uuid_le guid);
+struct visorchannel *visorchannel_create_with_lock(u64 physaddr,
+ unsigned long channel_bytes,
+ gfp_t gfp, uuid_le guid);
+void visorchannel_destroy(struct visorchannel *channel);
+int visorchannel_read(struct visorchannel *channel, ulong offset,
+ void *local, ulong nbytes);
+int visorchannel_write(struct visorchannel *channel, ulong offset,
+ void *local, ulong nbytes);
+int visorchannel_clear(struct visorchannel *channel, ulong offset,
+ u8 ch, ulong nbytes);
+bool visorchannel_signalremove(struct visorchannel *channel, u32 queue,
+ void *msg);
+bool visorchannel_signalinsert(struct visorchannel *channel, u32 queue,
+ void *msg);
+int visorchannel_signalqueue_slots_avail(struct visorchannel *channel,
+ u32 queue);
+int visorchannel_signalqueue_max_slots(struct visorchannel *channel, u32 queue);
+u64 visorchannel_get_physaddr(struct visorchannel *channel);
+ulong visorchannel_get_nbytes(struct visorchannel *channel);
+char *visorchannel_id(struct visorchannel *channel, char *s);
+char *visorchannel_zoneid(struct visorchannel *channel, char *s);
+u64 visorchannel_get_clientpartition(struct visorchannel *channel);
+int visorchannel_set_clientpartition(struct visorchannel *channel,
+ u64 partition_handle);
+uuid_le visorchannel_get_uuid(struct visorchannel *channel);
+char *visorchannel_uuid_id(uuid_le *guid, char *s);
+void visorchannel_debug(struct visorchannel *channel, int num_queues,
+ struct seq_file *seq, u32 off);
+void __iomem *visorchannel_get_header(struct visorchannel *channel);
+
+#define BUS_ROOT_DEVICE UINT_MAX
+struct visor_device *visorbus_get_device_by_id(u32 bus_no, u32 dev_no,
+ struct visor_device *from);
+#endif
diff --git a/drivers/staging/unisys/uislib/Kconfig b/drivers/staging/unisys/uislib/Kconfig
deleted file mode 100644
index c39a0a21a..000000000
--- a/drivers/staging/unisys/uislib/Kconfig
+++ /dev/null
@@ -1,10 +0,0 @@
-#
-# Unisys uislib configuration
-#
-
-config UNISYS_UISLIB
- tristate "Unisys uislib driver"
- select UNISYS_VISORCHIPSET
- ---help---
- If you say Y here, you will enable the Unisys uislib driver.
-
diff --git a/drivers/staging/unisys/uislib/Makefile b/drivers/staging/unisys/uislib/Makefile
deleted file mode 100644
index 860f494f1..000000000
--- a/drivers/staging/unisys/uislib/Makefile
+++ /dev/null
@@ -1,12 +0,0 @@
-#
-# Makefile for Unisys uislib
-#
-
-obj-$(CONFIG_UNISYS_UISLIB) += visoruislib.o
-
-visoruislib-y := uislib.o uisqueue.o uisthread.o uisutils.o
-
-ccflags-y += -Idrivers/staging/unisys/include
-ccflags-y += -Idrivers/staging/unisys/visorchipset
-ccflags-y += -Idrivers/staging/unisys/common-spar/include
-ccflags-y += -Idrivers/staging/unisys/common-spar/include/channels
diff --git a/drivers/staging/unisys/uislib/uislib.c b/drivers/staging/unisys/uislib/uislib.c
deleted file mode 100644
index f93d0bb11..000000000
--- a/drivers/staging/unisys/uislib/uislib.c
+++ /dev/null
@@ -1,1372 +0,0 @@
-/* uislib.c
- *
- * Copyright (C) 2010 - 2013 UNISYS CORPORATION
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
- * NON INFRINGEMENT. See the GNU General Public License for more
- * details.
- */
-
-/* @ALL_INSPECTED */
-#define EXPORT_SYMTAB
-#include <linux/kernel.h>
-#include <linux/highmem.h>
-#ifdef CONFIG_MODVERSIONS
-#include <config/modversions.h>
-#endif
-#include <linux/module.h>
-#include <linux/debugfs.h>
-
-#include <linux/types.h>
-#include <linux/uuid.h>
-
-#include <linux/version.h>
-#include "diagnostics/appos_subsystems.h"
-#include "uisutils.h"
-#include "vbuschannel.h"
-
-#include <linux/proc_fs.h>
-#include <linux/uaccess.h> /* for copy_from_user */
-#include <linux/ctype.h> /* for toupper */
-#include <linux/list.h>
-
-#include "sparstop.h"
-#include "visorchipset.h"
-#include "version.h"
-#include "guestlinuxdebug.h"
-
-#define SET_PROC_OWNER(x, y)
-
-#define POLLJIFFIES_NORMAL 1
-/* Choose whether or not you want to wakeup the request-polling thread
- * after an IO termination:
- * this is shorter than using __FILE__ (full path name) in
- * debug/info/error messages
- */
-#define CURRENT_FILE_PC UISLIB_PC_uislib_c
-#define __MYFILE__ "uislib.c"
-
-/* global function pointers that act as callback functions into virtpcimod */
-int (*virt_control_chan_func)(struct guest_msgs *);
-
-static int debug_buf_valid;
-static char *debug_buf; /* Note this MUST be global,
- * because the contents must */
-static unsigned int chipset_inited;
-
-#define WAIT_ON_CALLBACK(handle) \
- do { \
- if (handle) \
- break; \
- UIS_THREAD_WAIT; \
- } while (1)
-
-static struct bus_info *bus_list;
-static rwlock_t bus_list_lock;
-static int bus_list_count; /* number of buses in the list */
-static int max_bus_count; /* maximum number of buses expected */
-static u64 phys_data_chan;
-static int platform_no;
-
-static struct uisthread_info incoming_ti;
-static BOOL incoming_started = FALSE;
-static LIST_HEAD(poll_dev_chan);
-static unsigned long long tot_moved_to_tail_cnt;
-static unsigned long long tot_wait_cnt;
-static unsigned long long tot_wakeup_cnt;
-static unsigned long long tot_schedule_cnt;
-static int en_smart_wakeup = 1;
-static DEFINE_SEMAPHORE(poll_dev_lock); /* unlocked */
-static DECLARE_WAIT_QUEUE_HEAD(poll_dev_wake_q);
-static int poll_dev_start;
-
-#define CALLHOME_PROC_ENTRY_FN "callhome"
-#define CALLHOME_THROTTLED_PROC_ENTRY_FN "callhome_throttled"
-
-#define DIR_DEBUGFS_ENTRY "uislib"
-static struct dentry *dir_debugfs;
-
-#define PLATFORMNUMBER_DEBUGFS_ENTRY_FN "platform"
-static struct dentry *platformnumber_debugfs_read;
-
-#define CYCLES_BEFORE_WAIT_DEBUGFS_ENTRY_FN "cycles_before_wait"
-static struct dentry *cycles_before_wait_debugfs_read;
-
-#define SMART_WAKEUP_DEBUGFS_ENTRY_FN "smart_wakeup"
-static struct dentry *smart_wakeup_debugfs_entry;
-
-#define INFO_DEBUGFS_ENTRY_FN "info"
-static struct dentry *info_debugfs_entry;
-
-static unsigned long long cycles_before_wait, wait_cycles;
-
-/*****************************************************/
-/* local functions */
-/*****************************************************/
-
-static ssize_t info_debugfs_read(struct file *file, char __user *buf,
- size_t len, loff_t *offset);
-static const struct file_operations debugfs_info_fops = {
- .read = info_debugfs_read,
-};
-
-static void
-init_msg_header(struct controlvm_message *msg, u32 id, uint rsp, uint svr)
-{
- memset(msg, 0, sizeof(struct controlvm_message));
- msg->hdr.id = id;
- msg->hdr.flags.response_expected = rsp;
- msg->hdr.flags.server = svr;
-}
-
-static __iomem void *init_vbus_channel(u64 ch_addr, u32 ch_bytes)
-{
- void __iomem *ch = uislib_ioremap_cache(ch_addr, ch_bytes);
-
- if (!ch)
- return NULL;
-
- if (!SPAR_VBUS_CHANNEL_OK_CLIENT(ch)) {
- uislib_iounmap(ch);
- return NULL;
- }
- return ch;
-}
-
-static int
-create_bus(struct controlvm_message *msg, char *buf)
-{
- u32 bus_no, dev_count;
- struct bus_info *tmp, *bus;
- size_t size;
-
- if (max_bus_count == bus_list_count) {
- POSTCODE_LINUX_3(BUS_CREATE_FAILURE_PC, max_bus_count,
- POSTCODE_SEVERITY_ERR);
- return CONTROLVM_RESP_ERROR_MAX_BUSES;
- }
-
- bus_no = msg->cmd.create_bus.bus_no;
- dev_count = msg->cmd.create_bus.dev_count;
-
- POSTCODE_LINUX_4(BUS_CREATE_ENTRY_PC, bus_no, dev_count,
- POSTCODE_SEVERITY_INFO);
-
- size =
- sizeof(struct bus_info) +
- (dev_count * sizeof(struct device_info *));
- bus = kzalloc(size, GFP_ATOMIC);
- if (!bus) {
- POSTCODE_LINUX_3(BUS_CREATE_FAILURE_PC, bus_no,
- POSTCODE_SEVERITY_ERR);
- return CONTROLVM_RESP_ERROR_KMALLOC_FAILED;
- }
-
- /* Currently by default, the bus Number is the GuestHandle.
- * Configure Bus message can override this.
- */
- if (msg->hdr.flags.test_message) {
- /* This implies we're the IOVM so set guest handle to 0... */
- bus->guest_handle = 0;
- bus->bus_no = bus_no;
- bus->local_vnic = 1;
- } else {
- bus->bus_no = bus_no;
- bus->guest_handle = bus_no;
- }
- sprintf(bus->name, "%d", (int)bus->bus_no);
- bus->device_count = dev_count;
- bus->device =
- (struct device_info **)((char *)bus + sizeof(struct bus_info));
- bus->bus_inst_uuid = msg->cmd.create_bus.bus_inst_uuid;
- bus->bus_channel_bytes = 0;
- bus->bus_channel = NULL;
-
- /* add bus to our bus list - but check for duplicates first */
- read_lock(&bus_list_lock);
- for (tmp = bus_list; tmp; tmp = tmp->next) {
- if (tmp->bus_no == bus->bus_no)
- break;
- }
- read_unlock(&bus_list_lock);
- if (tmp) {
- /* found a bus already in the list with same bus_no -
- * reject add
- */
- POSTCODE_LINUX_3(BUS_CREATE_FAILURE_PC, bus->bus_no,
- POSTCODE_SEVERITY_ERR);
- kfree(bus);
- return CONTROLVM_RESP_ERROR_ALREADY_DONE;
- }
- if ((msg->cmd.create_bus.channel_addr != 0) &&
- (msg->cmd.create_bus.channel_bytes != 0)) {
- bus->bus_channel_bytes = msg->cmd.create_bus.channel_bytes;
- bus->bus_channel =
- init_vbus_channel(msg->cmd.create_bus.channel_addr,
- msg->cmd.create_bus.channel_bytes);
- }
- /* the msg is bound for virtpci; send guest_msgs struct to callback */
- if (!msg->hdr.flags.server) {
- struct guest_msgs cmd;
-
- cmd.msgtype = GUEST_ADD_VBUS;
- cmd.add_vbus.bus_no = bus_no;
- cmd.add_vbus.chanptr = bus->bus_channel;
- cmd.add_vbus.dev_count = dev_count;
- cmd.add_vbus.bus_uuid = msg->cmd.create_bus.bus_data_type_uuid;
- cmd.add_vbus.instance_uuid = msg->cmd.create_bus.bus_inst_uuid;
- if (!virt_control_chan_func) {
- POSTCODE_LINUX_3(BUS_CREATE_FAILURE_PC, bus->bus_no,
- POSTCODE_SEVERITY_ERR);
- kfree(bus);
- return CONTROLVM_RESP_ERROR_VIRTPCI_DRIVER_FAILURE;
- }
- if (!virt_control_chan_func(&cmd)) {
- POSTCODE_LINUX_3(BUS_CREATE_FAILURE_PC, bus->bus_no,
- POSTCODE_SEVERITY_ERR);
- kfree(bus);
- return
- CONTROLVM_RESP_ERROR_VIRTPCI_DRIVER_CALLBACK_ERROR;
- }
- }
-
- /* add bus at the head of our list */
- write_lock(&bus_list_lock);
- if (!bus_list) {
- bus_list = bus;
- } else {
- bus->next = bus_list;
- bus_list = bus;
- }
- bus_list_count++;
- write_unlock(&bus_list_lock);
-
- POSTCODE_LINUX_3(BUS_CREATE_EXIT_PC, bus->bus_no,
- POSTCODE_SEVERITY_INFO);
- return CONTROLVM_RESP_SUCCESS;
-}
-
-static int
-destroy_bus(struct controlvm_message *msg, char *buf)
-{
- int i;
- struct bus_info *bus, *prev = NULL;
- struct guest_msgs cmd;
- u32 bus_no;
-
- bus_no = msg->cmd.destroy_bus.bus_no;
-
- read_lock(&bus_list_lock);
-
- bus = bus_list;
- while (bus) {
- if (bus->bus_no == bus_no)
- break;
- prev = bus;
- bus = bus->next;
- }
-
- if (!bus) {
- read_unlock(&bus_list_lock);
- return CONTROLVM_RESP_ERROR_ALREADY_DONE;
- }
-
- /* verify that this bus has no devices. */
- for (i = 0; i < bus->device_count; i++) {
- if (bus->device[i]) {
- read_unlock(&bus_list_lock);
- return CONTROLVM_RESP_ERROR_BUS_DEVICE_ATTACHED;
- }
- }
- read_unlock(&bus_list_lock);
-
- if (msg->hdr.flags.server)
- goto remove;
-
- /* client messages require us to call the virtpci callback associated
- with this bus. */
- cmd.msgtype = GUEST_DEL_VBUS;
- cmd.del_vbus.bus_no = bus_no;
- if (!virt_control_chan_func)
- return CONTROLVM_RESP_ERROR_VIRTPCI_DRIVER_FAILURE;
-
- if (!virt_control_chan_func(&cmd))
- return CONTROLVM_RESP_ERROR_VIRTPCI_DRIVER_CALLBACK_ERROR;
-
- /* finally, remove the bus from the list */
-remove:
- write_lock(&bus_list_lock);
- if (prev) /* not at head */
- prev->next = bus->next;
- else
- bus_list = bus->next;
- bus_list_count--;
- write_unlock(&bus_list_lock);
-
- if (bus->bus_channel) {
- uislib_iounmap(bus->bus_channel);
- bus->bus_channel = NULL;
- }
-
- kfree(bus);
- return CONTROLVM_RESP_SUCCESS;
-}
-
-static int create_device(struct controlvm_message *msg, char *buf)
-{
- struct device_info *dev;
- struct bus_info *bus;
- struct guest_msgs cmd;
- u32 bus_no, dev_no;
- int result = CONTROLVM_RESP_SUCCESS;
- u64 min_size = MIN_IO_CHANNEL_SIZE;
- struct req_handler_info *req_handler;
-
- bus_no = msg->cmd.create_device.bus_no;
- dev_no = msg->cmd.create_device.dev_no;
-
- POSTCODE_LINUX_4(DEVICE_CREATE_ENTRY_PC, dev_no, bus_no,
- POSTCODE_SEVERITY_INFO);
-
- dev = kzalloc(sizeof(*dev), GFP_ATOMIC);
- if (!dev) {
- POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC, dev_no, bus_no,
- POSTCODE_SEVERITY_ERR);
- return CONTROLVM_RESP_ERROR_KMALLOC_FAILED;
- }
-
- dev->channel_uuid = msg->cmd.create_device.data_type_uuid;
- dev->intr = msg->cmd.create_device.intr;
- dev->channel_addr = msg->cmd.create_device.channel_addr;
- dev->bus_no = bus_no;
- dev->dev_no = dev_no;
- sema_init(&dev->interrupt_callback_lock, 1); /* unlocked */
- sprintf(dev->devid, "vbus%u:dev%u", (unsigned)bus_no, (unsigned)dev_no);
- /* map the channel memory for the device. */
- if (msg->hdr.flags.test_message) {
- dev->chanptr = (void __iomem *)__va(dev->channel_addr);
- } else {
- req_handler = req_handler_find(dev->channel_uuid);
- if (req_handler)
- /* generic service handler registered for this
- * channel
- */
- min_size = req_handler->min_channel_bytes;
- if (min_size > msg->cmd.create_device.channel_bytes) {
- POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC, dev_no,
- bus_no, POSTCODE_SEVERITY_ERR);
- result = CONTROLVM_RESP_ERROR_CHANNEL_SIZE_TOO_SMALL;
- goto cleanup;
- }
- dev->chanptr =
- uislib_ioremap_cache(dev->channel_addr,
- msg->cmd.create_device.channel_bytes);
- if (!dev->chanptr) {
- result = CONTROLVM_RESP_ERROR_IOREMAP_FAILED;
- POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC, dev_no,
- bus_no, POSTCODE_SEVERITY_ERR);
- goto cleanup;
- }
- }
- dev->instance_uuid = msg->cmd.create_device.dev_inst_uuid;
- dev->channel_bytes = msg->cmd.create_device.channel_bytes;
-
- read_lock(&bus_list_lock);
- for (bus = bus_list; bus; bus = bus->next) {
- if (bus->bus_no != bus_no)
- continue;
- /* make sure the device number is valid */
- if (dev_no >= bus->device_count) {
- result = CONTROLVM_RESP_ERROR_MAX_DEVICES;
- POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC, dev_no,
- bus_no, POSTCODE_SEVERITY_ERR);
- read_unlock(&bus_list_lock);
- goto cleanup;
- }
- /* make sure this device is not already set */
- if (bus->device[dev_no]) {
- POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC,
- dev_no, bus_no,
- POSTCODE_SEVERITY_ERR);
- result = CONTROLVM_RESP_ERROR_ALREADY_DONE;
- read_unlock(&bus_list_lock);
- goto cleanup;
- }
- read_unlock(&bus_list_lock);
- /* the msg is bound for virtpci; send
- * guest_msgs struct to callback
- */
- if (msg->hdr.flags.server) {
- bus->device[dev_no] = dev;
- POSTCODE_LINUX_4(DEVICE_CREATE_SUCCESS_PC, dev_no,
- bus_no, POSTCODE_SEVERITY_INFO);
- return CONTROLVM_RESP_SUCCESS;
- }
- if (uuid_le_cmp(dev->channel_uuid,
- spar_vhba_channel_protocol_uuid) == 0) {
- wait_for_valid_guid(&((struct channel_header __iomem *)
- (dev->chanptr))->chtype);
- if (!SPAR_VHBA_CHANNEL_OK_CLIENT(dev->chanptr)) {
- POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC,
- dev_no, bus_no,
- POSTCODE_SEVERITY_ERR);
- result = CONTROLVM_RESP_ERROR_CHANNEL_INVALID;
- goto cleanup;
- }
- cmd.msgtype = GUEST_ADD_VHBA;
- cmd.add_vhba.chanptr = dev->chanptr;
- cmd.add_vhba.bus_no = bus_no;
- cmd.add_vhba.device_no = dev_no;
- cmd.add_vhba.instance_uuid = dev->instance_uuid;
- cmd.add_vhba.intr = dev->intr;
- } else if (uuid_le_cmp(dev->channel_uuid,
- spar_vnic_channel_protocol_uuid) == 0) {
- wait_for_valid_guid(&((struct channel_header __iomem *)
- (dev->chanptr))->chtype);
- if (!SPAR_VNIC_CHANNEL_OK_CLIENT(dev->chanptr)) {
- POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC,
- dev_no, bus_no,
- POSTCODE_SEVERITY_ERR);
- result = CONTROLVM_RESP_ERROR_CHANNEL_INVALID;
- goto cleanup;
- }
- cmd.msgtype = GUEST_ADD_VNIC;
- cmd.add_vnic.chanptr = dev->chanptr;
- cmd.add_vnic.bus_no = bus_no;
- cmd.add_vnic.device_no = dev_no;
- cmd.add_vnic.instance_uuid = dev->instance_uuid;
- cmd.add_vhba.intr = dev->intr;
- } else {
- POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC, dev_no,
- bus_no, POSTCODE_SEVERITY_ERR);
- result = CONTROLVM_RESP_ERROR_CHANNEL_TYPE_UNKNOWN;
- goto cleanup;
- }
-
- if (!virt_control_chan_func) {
- POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC, dev_no,
- bus_no, POSTCODE_SEVERITY_ERR);
- result = CONTROLVM_RESP_ERROR_VIRTPCI_DRIVER_FAILURE;
- goto cleanup;
- }
-
- if (!virt_control_chan_func(&cmd)) {
- POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC, dev_no,
- bus_no, POSTCODE_SEVERITY_ERR);
- result =
- CONTROLVM_RESP_ERROR_VIRTPCI_DRIVER_CALLBACK_ERROR;
- goto cleanup;
- }
-
- bus->device[dev_no] = dev;
- POSTCODE_LINUX_4(DEVICE_CREATE_SUCCESS_PC, dev_no,
- bus_no, POSTCODE_SEVERITY_INFO);
- return CONTROLVM_RESP_SUCCESS;
- }
- read_unlock(&bus_list_lock);
-
- POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC, dev_no, bus_no,
- POSTCODE_SEVERITY_ERR);
- result = CONTROLVM_RESP_ERROR_BUS_INVALID;
-
-cleanup:
- if (!msg->hdr.flags.test_message) {
- uislib_iounmap(dev->chanptr);
- dev->chanptr = NULL;
- }
-
- kfree(dev);
- return result;
-}
-
-static int pause_device(struct controlvm_message *msg)
-{
- u32 bus_no, dev_no;
- struct bus_info *bus;
- struct device_info *dev;
- struct guest_msgs cmd;
- int retval = CONTROLVM_RESP_SUCCESS;
-
- bus_no = msg->cmd.device_change_state.bus_no;
- dev_no = msg->cmd.device_change_state.dev_no;
-
- read_lock(&bus_list_lock);
- for (bus = bus_list; bus; bus = bus->next) {
- if (bus->bus_no == bus_no) {
- /* make sure the device number is valid */
- if (dev_no >= bus->device_count) {
- retval = CONTROLVM_RESP_ERROR_DEVICE_INVALID;
- } else {
- /* make sure this device exists */
- dev = bus->device[dev_no];
- if (!dev) {
- retval =
- CONTROLVM_RESP_ERROR_ALREADY_DONE;
- }
- }
- break;
- }
- }
- if (!bus)
- retval = CONTROLVM_RESP_ERROR_BUS_INVALID;
-
- read_unlock(&bus_list_lock);
- if (retval == CONTROLVM_RESP_SUCCESS) {
- /* the msg is bound for virtpci; send
- * guest_msgs struct to callback
- */
- if (uuid_le_cmp(dev->channel_uuid,
- spar_vhba_channel_protocol_uuid) == 0) {
- cmd.msgtype = GUEST_PAUSE_VHBA;
- cmd.pause_vhba.chanptr = dev->chanptr;
- } else if (uuid_le_cmp(dev->channel_uuid,
- spar_vnic_channel_protocol_uuid) == 0) {
- cmd.msgtype = GUEST_PAUSE_VNIC;
- cmd.pause_vnic.chanptr = dev->chanptr;
- } else {
- return CONTROLVM_RESP_ERROR_CHANNEL_TYPE_UNKNOWN;
- }
- if (!virt_control_chan_func)
- return CONTROLVM_RESP_ERROR_VIRTPCI_DRIVER_FAILURE;
- if (!virt_control_chan_func(&cmd)) {
- return
- CONTROLVM_RESP_ERROR_VIRTPCI_DRIVER_CALLBACK_ERROR;
- }
- }
- return retval;
-}
-
-static int resume_device(struct controlvm_message *msg)
-{
- u32 bus_no, dev_no;
- struct bus_info *bus;
- struct device_info *dev;
- struct guest_msgs cmd;
- int retval = CONTROLVM_RESP_SUCCESS;
-
- bus_no = msg->cmd.device_change_state.bus_no;
- dev_no = msg->cmd.device_change_state.dev_no;
-
- read_lock(&bus_list_lock);
- for (bus = bus_list; bus; bus = bus->next) {
- if (bus->bus_no == bus_no) {
- /* make sure the device number is valid */
- if (dev_no >= bus->device_count) {
- retval = CONTROLVM_RESP_ERROR_DEVICE_INVALID;
- } else {
- /* make sure this device exists */
- dev = bus->device[dev_no];
- if (!dev) {
- retval =
- CONTROLVM_RESP_ERROR_ALREADY_DONE;
- }
- }
- break;
- }
- }
-
- if (!bus)
- retval = CONTROLVM_RESP_ERROR_BUS_INVALID;
-
- read_unlock(&bus_list_lock);
- /* the msg is bound for virtpci; send
- * guest_msgs struct to callback
- */
- if (retval == CONTROLVM_RESP_SUCCESS) {
- if (uuid_le_cmp(dev->channel_uuid,
- spar_vhba_channel_protocol_uuid) == 0) {
- cmd.msgtype = GUEST_RESUME_VHBA;
- cmd.resume_vhba.chanptr = dev->chanptr;
- } else if (uuid_le_cmp(dev->channel_uuid,
- spar_vnic_channel_protocol_uuid) == 0) {
- cmd.msgtype = GUEST_RESUME_VNIC;
- cmd.resume_vnic.chanptr = dev->chanptr;
- } else {
- return CONTROLVM_RESP_ERROR_CHANNEL_TYPE_UNKNOWN;
- }
- if (!virt_control_chan_func)
- return CONTROLVM_RESP_ERROR_VIRTPCI_DRIVER_FAILURE;
- if (!virt_control_chan_func(&cmd)) {
- return
- CONTROLVM_RESP_ERROR_VIRTPCI_DRIVER_CALLBACK_ERROR;
- }
- }
- return retval;
-}
-
-static int destroy_device(struct controlvm_message *msg, char *buf)
-{
- u32 bus_no, dev_no;
- struct bus_info *bus;
- struct device_info *dev;
- struct guest_msgs cmd;
- int retval = CONTROLVM_RESP_SUCCESS;
-
- bus_no = msg->cmd.destroy_device.bus_no;
- dev_no = msg->cmd.destroy_device.bus_no;
-
- read_lock(&bus_list_lock);
- for (bus = bus_list; bus; bus = bus->next) {
- if (bus->bus_no == bus_no) {
- /* make sure the device number is valid */
- if (dev_no >= bus->device_count) {
- retval = CONTROLVM_RESP_ERROR_DEVICE_INVALID;
- } else {
- /* make sure this device exists */
- dev = bus->device[dev_no];
- if (!dev) {
- retval =
- CONTROLVM_RESP_ERROR_ALREADY_DONE;
- }
- }
- break;
- }
- }
-
- if (!bus)
- retval = CONTROLVM_RESP_ERROR_BUS_INVALID;
- read_unlock(&bus_list_lock);
- if (retval == CONTROLVM_RESP_SUCCESS) {
- /* the msg is bound for virtpci; send
- * guest_msgs struct to callback
- */
- if (uuid_le_cmp(dev->channel_uuid,
- spar_vhba_channel_protocol_uuid) == 0) {
- cmd.msgtype = GUEST_DEL_VHBA;
- cmd.del_vhba.chanptr = dev->chanptr;
- } else if (uuid_le_cmp(dev->channel_uuid,
- spar_vnic_channel_protocol_uuid) == 0) {
- cmd.msgtype = GUEST_DEL_VNIC;
- cmd.del_vnic.chanptr = dev->chanptr;
- } else {
- return
- CONTROLVM_RESP_ERROR_CHANNEL_TYPE_UNKNOWN;
- }
- if (!virt_control_chan_func) {
- return
- CONTROLVM_RESP_ERROR_VIRTPCI_DRIVER_FAILURE;
- }
- if (!virt_control_chan_func(&cmd)) {
- return
- CONTROLVM_RESP_ERROR_VIRTPCI_DRIVER_CALLBACK_ERROR;
- }
-/* you must disable channel interrupts BEFORE you unmap the channel,
- * because if you unmap first, there may still be some activity going
- * on which accesses the channel and you will get a "unable to handle
- * kernel paging request"
- */
- if (dev->polling)
- uislib_disable_channel_interrupts(bus_no, dev_no);
- /* unmap the channel memory for the device. */
- if (!msg->hdr.flags.test_message)
- uislib_iounmap(dev->chanptr);
- kfree(dev);
- bus->device[dev_no] = NULL;
- }
- return retval;
-}
-
-static int
-init_chipset(struct controlvm_message *msg, char *buf)
-{
- POSTCODE_LINUX_2(CHIPSET_INIT_ENTRY_PC, POSTCODE_SEVERITY_INFO);
-
- max_bus_count = msg->cmd.init_chipset.bus_count;
- platform_no = msg->cmd.init_chipset.platform_number;
- phys_data_chan = 0;
-
- /* We need to make sure we have our functions registered
- * before processing messages. If we are a test vehicle the
- * test_message for init_chipset will be set. We can ignore the
- * waits for the callbacks, since this will be manually entered
- * from a user. If no test_message is set, we will wait for the
- * functions.
- */
- if (!msg->hdr.flags.test_message)
- WAIT_ON_CALLBACK(virt_control_chan_func);
-
- chipset_inited = 1;
- POSTCODE_LINUX_2(CHIPSET_INIT_EXIT_PC, POSTCODE_SEVERITY_INFO);
-
- return CONTROLVM_RESP_SUCCESS;
-}
-
-static int delete_bus_glue(u32 bus_no)
-{
- struct controlvm_message msg;
-
- init_msg_header(&msg, CONTROLVM_BUS_DESTROY, 0, 0);
- msg.cmd.destroy_bus.bus_no = bus_no;
- if (destroy_bus(&msg, NULL) != CONTROLVM_RESP_SUCCESS)
- return 0;
- return 1;
-}
-
-static int delete_device_glue(u32 bus_no, u32 dev_no)
-{
- struct controlvm_message msg;
-
- init_msg_header(&msg, CONTROLVM_DEVICE_DESTROY, 0, 0);
- msg.cmd.destroy_device.bus_no = bus_no;
- msg.cmd.destroy_device.dev_no = dev_no;
- if (destroy_device(&msg, NULL) != CONTROLVM_RESP_SUCCESS)
- return 0;
- return 1;
-}
-
-int
-uislib_client_inject_add_bus(u32 bus_no, uuid_le inst_uuid,
- u64 channel_addr, ulong n_channel_bytes)
-{
- struct controlvm_message msg;
-
- /* step 0: init the chipset */
- POSTCODE_LINUX_3(CHIPSET_INIT_ENTRY_PC, bus_no, POSTCODE_SEVERITY_INFO);
-
- if (!chipset_inited) {
- /* step: initialize the chipset */
- init_msg_header(&msg, CONTROLVM_CHIPSET_INIT, 0, 0);
- /* this change is needed so that console will come up
- * OK even when the bus 0 create comes in late. If the
- * bus 0 create is the first create, then the add_vnic
- * will work fine, but if the bus 0 create arrives
- * after number 4, then the add_vnic will fail, and the
- * ultraboot will fail.
- */
- msg.cmd.init_chipset.bus_count = 23;
- msg.cmd.init_chipset.switch_count = 0;
- if (init_chipset(&msg, NULL) != CONTROLVM_RESP_SUCCESS)
- return 0;
- POSTCODE_LINUX_3(CHIPSET_INIT_EXIT_PC, bus_no,
- POSTCODE_SEVERITY_INFO);
- }
-
- /* step 1: create a bus */
- POSTCODE_LINUX_3(BUS_CREATE_ENTRY_PC, bus_no,
- POSTCODE_SEVERITY_WARNING);
- init_msg_header(&msg, CONTROLVM_BUS_CREATE, 0, 0);
- msg.cmd.create_bus.bus_no = bus_no;
- msg.cmd.create_bus.dev_count = 23; /* devNo+1; */
- msg.cmd.create_bus.channel_addr = channel_addr;
- msg.cmd.create_bus.channel_bytes = n_channel_bytes;
- if (create_bus(&msg, NULL) != CONTROLVM_RESP_SUCCESS) {
- POSTCODE_LINUX_3(BUS_CREATE_FAILURE_PC, bus_no,
- POSTCODE_SEVERITY_ERR);
- return 0;
- }
- POSTCODE_LINUX_3(BUS_CREATE_EXIT_PC, bus_no, POSTCODE_SEVERITY_INFO);
-
- return 1;
-}
-EXPORT_SYMBOL_GPL(uislib_client_inject_add_bus);
-
-int
-uislib_client_inject_del_bus(u32 bus_no)
-{
- return delete_bus_glue(bus_no);
-}
-EXPORT_SYMBOL_GPL(uislib_client_inject_del_bus);
-
-int
-uislib_client_inject_pause_vhba(u32 bus_no, u32 dev_no)
-{
- struct controlvm_message msg;
- int rc;
-
- init_msg_header(&msg, CONTROLVM_DEVICE_CHANGESTATE, 0, 0);
- msg.cmd.device_change_state.bus_no = bus_no;
- msg.cmd.device_change_state.dev_no = dev_no;
- msg.cmd.device_change_state.state = segment_state_standby;
- rc = pause_device(&msg);
- if (rc != CONTROLVM_RESP_SUCCESS)
- return rc;
- return 0;
-}
-EXPORT_SYMBOL_GPL(uislib_client_inject_pause_vhba);
-
-int
-uislib_client_inject_resume_vhba(u32 bus_no, u32 dev_no)
-{
- struct controlvm_message msg;
- int rc;
-
- init_msg_header(&msg, CONTROLVM_DEVICE_CHANGESTATE, 0, 0);
- msg.cmd.device_change_state.bus_no = bus_no;
- msg.cmd.device_change_state.dev_no = dev_no;
- msg.cmd.device_change_state.state = segment_state_running;
- rc = resume_device(&msg);
- if (rc != CONTROLVM_RESP_SUCCESS)
- return rc;
- return 0;
-}
-EXPORT_SYMBOL_GPL(uislib_client_inject_resume_vhba);
-
-int
-uislib_client_inject_add_vhba(u32 bus_no, u32 dev_no,
- u64 phys_chan_addr, u32 chan_bytes,
- int is_test_addr, uuid_le inst_uuid,
- struct irq_info *intr)
-{
- struct controlvm_message msg;
-
- /* chipset init'ed with bus bus has been previously created -
- * Verify it still exists step 2: create the VHBA device on the
- * bus
- */
- POSTCODE_LINUX_4(VHBA_CREATE_ENTRY_PC, dev_no, bus_no,
- POSTCODE_SEVERITY_INFO);
-
- init_msg_header(&msg, CONTROLVM_DEVICE_CREATE, 0, 0);
- if (is_test_addr)
- /* signify that the physical channel address does NOT
- * need to be ioremap()ed
- */
- msg.hdr.flags.test_message = 1;
- msg.cmd.create_device.bus_no = bus_no;
- msg.cmd.create_device.dev_no = dev_no;
- msg.cmd.create_device.dev_inst_uuid = inst_uuid;
- if (intr)
- msg.cmd.create_device.intr = *intr;
- else
- memset(&msg.cmd.create_device.intr, 0,
- sizeof(struct irq_info));
- msg.cmd.create_device.channel_addr = phys_chan_addr;
- if (chan_bytes < MIN_IO_CHANNEL_SIZE) {
- POSTCODE_LINUX_4(VHBA_CREATE_FAILURE_PC, chan_bytes,
- MIN_IO_CHANNEL_SIZE, POSTCODE_SEVERITY_ERR);
- return 0;
- }
- msg.cmd.create_device.channel_bytes = chan_bytes;
- msg.cmd.create_device.data_type_uuid = spar_vhba_channel_protocol_uuid;
- if (create_device(&msg, NULL) != CONTROLVM_RESP_SUCCESS) {
- POSTCODE_LINUX_4(VHBA_CREATE_FAILURE_PC, dev_no, bus_no,
- POSTCODE_SEVERITY_ERR);
- return 0;
- }
- POSTCODE_LINUX_4(VHBA_CREATE_SUCCESS_PC, dev_no, bus_no,
- POSTCODE_SEVERITY_INFO);
- return 1;
-}
-EXPORT_SYMBOL_GPL(uislib_client_inject_add_vhba);
-
-int
-uislib_client_inject_del_vhba(u32 bus_no, u32 dev_no)
-{
- return delete_device_glue(bus_no, dev_no);
-}
-EXPORT_SYMBOL_GPL(uislib_client_inject_del_vhba);
-
-int
-uislib_client_inject_add_vnic(u32 bus_no, u32 dev_no,
- u64 phys_chan_addr, u32 chan_bytes,
- int is_test_addr, uuid_le inst_uuid,
- struct irq_info *intr)
-{
- struct controlvm_message msg;
-
- /* chipset init'ed with bus bus has been previously created -
- * Verify it still exists step 2: create the VNIC device on the
- * bus
- */
- POSTCODE_LINUX_4(VNIC_CREATE_ENTRY_PC, dev_no, bus_no,
- POSTCODE_SEVERITY_INFO);
-
- init_msg_header(&msg, CONTROLVM_DEVICE_CREATE, 0, 0);
- if (is_test_addr)
- /* signify that the physical channel address does NOT
- * need to be ioremap()ed
- */
- msg.hdr.flags.test_message = 1;
- msg.cmd.create_device.bus_no = bus_no;
- msg.cmd.create_device.dev_no = dev_no;
- msg.cmd.create_device.dev_inst_uuid = inst_uuid;
- if (intr)
- msg.cmd.create_device.intr = *intr;
- else
- memset(&msg.cmd.create_device.intr, 0,
- sizeof(struct irq_info));
- msg.cmd.create_device.channel_addr = phys_chan_addr;
- if (chan_bytes < MIN_IO_CHANNEL_SIZE) {
- POSTCODE_LINUX_4(VNIC_CREATE_FAILURE_PC, chan_bytes,
- MIN_IO_CHANNEL_SIZE, POSTCODE_SEVERITY_ERR);
- return 0;
- }
- msg.cmd.create_device.channel_bytes = chan_bytes;
- msg.cmd.create_device.data_type_uuid = spar_vnic_channel_protocol_uuid;
- if (create_device(&msg, NULL) != CONTROLVM_RESP_SUCCESS) {
- POSTCODE_LINUX_4(VNIC_CREATE_FAILURE_PC, dev_no, bus_no,
- POSTCODE_SEVERITY_ERR);
- return 0;
- }
-
- POSTCODE_LINUX_4(VNIC_CREATE_SUCCESS_PC, dev_no, bus_no,
- POSTCODE_SEVERITY_INFO);
- return 1;
-}
-EXPORT_SYMBOL_GPL(uislib_client_inject_add_vnic);
-
-int
-uislib_client_inject_pause_vnic(u32 bus_no, u32 dev_no)
-{
- struct controlvm_message msg;
- int rc;
-
- init_msg_header(&msg, CONTROLVM_DEVICE_CHANGESTATE, 0, 0);
- msg.cmd.device_change_state.bus_no = bus_no;
- msg.cmd.device_change_state.dev_no = dev_no;
- msg.cmd.device_change_state.state = segment_state_standby;
- rc = pause_device(&msg);
- if (rc != CONTROLVM_RESP_SUCCESS)
- return -1;
- return 0;
-}
-EXPORT_SYMBOL_GPL(uislib_client_inject_pause_vnic);
-
-int
-uislib_client_inject_resume_vnic(u32 bus_no, u32 dev_no)
-{
- struct controlvm_message msg;
- int rc;
-
- init_msg_header(&msg, CONTROLVM_DEVICE_CHANGESTATE, 0, 0);
- msg.cmd.device_change_state.bus_no = bus_no;
- msg.cmd.device_change_state.dev_no = dev_no;
- msg.cmd.device_change_state.state = segment_state_running;
- rc = resume_device(&msg);
- if (rc != CONTROLVM_RESP_SUCCESS)
- return -1;
- return 0;
-}
-EXPORT_SYMBOL_GPL(uislib_client_inject_resume_vnic);
-
-int
-uislib_client_inject_del_vnic(u32 bus_no, u32 dev_no)
-{
- return delete_device_glue(bus_no, dev_no);
-}
-EXPORT_SYMBOL_GPL(uislib_client_inject_del_vnic);
-
-void *
-uislib_cache_alloc(struct kmem_cache *cur_pool, char *fn, int ln)
-{
- /* __GFP_NORETRY means "ok to fail", meaning kmalloc() can
- * return NULL. If you do NOT specify __GFP_NORETRY, Linux
- * will go to extreme measures to get memory for you (like,
- * invoke oom killer), which will probably cripple the system.
- */
- void *p = kmem_cache_alloc(cur_pool, GFP_ATOMIC | __GFP_NORETRY);
-
- if (!p)
- return NULL;
- return p;
-}
-EXPORT_SYMBOL_GPL(uislib_cache_alloc);
-
-void
-uislib_cache_free(struct kmem_cache *cur_pool, void *p, char *fn, int ln)
-{
- if (!p)
- return;
- kmem_cache_free(cur_pool, p);
-}
-EXPORT_SYMBOL_GPL(uislib_cache_free);
-
-/*****************************************************/
-/* proc filesystem callback functions */
-/*****************************************************/
-
-#define PLINE(...) uisutil_add_proc_line_ex(&tot, buff, \
- buff_len, __VA_ARGS__)
-
-static int
-info_debugfs_read_helper(char **buff, int *buff_len)
-{
- int i, tot = 0;
- struct bus_info *bus;
-
- if (PLINE("\nBuses:\n") < 0)
- goto err_done;
-
- read_lock(&bus_list_lock);
- for (bus = bus_list; bus; bus = bus->next) {
- if (PLINE(" bus=0x%p, busNo=%d, deviceCount=%d\n",
- bus, bus->bus_no, bus->device_count) < 0)
- goto err_done_unlock;
-
- if (PLINE(" Devices:\n") < 0)
- goto err_done_unlock;
-
- for (i = 0; i < bus->device_count; i++) {
- if (bus->device[i]) {
- if (PLINE(" busNo %d, device[%i]: 0x%p, chanptr=0x%p, swtch=0x%p\n",
- bus->bus_no, i, bus->device[i],
- bus->device[i]->chanptr,
- bus->device[i]->swtch) < 0)
- goto err_done_unlock;
-
- if (PLINE(" first_busy_cnt=%llu, moved_to_tail_cnt=%llu, last_on_list_cnt=%llu\n",
- bus->device[i]->first_busy_cnt,
- bus->device[i]->moved_to_tail_cnt,
- bus->device[i]->last_on_list_cnt) < 0)
- goto err_done_unlock;
- }
- }
- }
- read_unlock(&bus_list_lock);
-
- if (PLINE("UisUtils_Registered_Services: %d\n",
- atomic_read(&uisutils_registered_services)) < 0)
- goto err_done;
- if (PLINE("cycles_before_wait %llu wait_cycles:%llu\n",
- cycles_before_wait, wait_cycles) < 0)
- goto err_done;
- if (PLINE("tot_wakeup_cnt %llu:tot_wait_cnt %llu:tot_schedule_cnt %llu\n",
- tot_wakeup_cnt, tot_wait_cnt, tot_schedule_cnt) < 0)
- goto err_done;
- if (PLINE("en_smart_wakeup %d\n", en_smart_wakeup) < 0)
- goto err_done;
- if (PLINE("tot_moved_to_tail_cnt %llu\n", tot_moved_to_tail_cnt) < 0)
- goto err_done;
-
- return tot;
-
-err_done_unlock:
- read_unlock(&bus_list_lock);
-err_done:
- return -1;
-}
-
-static ssize_t info_debugfs_read(struct file *file, char __user *buf,
- size_t len, loff_t *offset)
-{
- char *temp;
- int total_bytes = 0;
- int remaining_bytes = PROC_READ_BUFFER_SIZE;
-
-/* *start = buf; */
- if (!debug_buf) {
- debug_buf = vmalloc(PROC_READ_BUFFER_SIZE);
-
- if (!debug_buf)
- return -ENOMEM;
- }
-
- temp = debug_buf;
-
- if ((*offset == 0) || (!debug_buf_valid)) {
- /* if the read fails, then -1 will be returned */
- total_bytes = info_debugfs_read_helper(&temp, &remaining_bytes);
- debug_buf_valid = 1;
- } else {
- total_bytes = strlen(debug_buf);
- }
-
- return simple_read_from_buffer(buf, len, offset,
- debug_buf, total_bytes);
-}
-
-static struct device_info *find_dev(u32 bus_no, u32 dev_no)
-{
- struct bus_info *bus;
- struct device_info *dev = NULL;
-
- read_lock(&bus_list_lock);
- for (bus = bus_list; bus; bus = bus->next) {
- if (bus->bus_no == bus_no) {
- /* make sure the device number is valid */
- if (dev_no >= bus->device_count)
- break;
- dev = bus->device[dev_no];
- break;
- }
- }
- read_unlock(&bus_list_lock);
- return dev;
-}
-
-/* This thread calls the "interrupt" function for each device that has
- * enabled such using uislib_enable_channel_interrupts(). The "interrupt"
- * function typically reads and processes the devices's channel input
- * queue. This thread repeatedly does this, until the thread is told to stop
- * (via uisthread_stop()). Sleeping rules:
- * - If we have called the "interrupt" function for all devices, and all of
- * them have reported "nothing processed" (returned 0), then we will go to
- * sleep for a maximum of POLLJIFFIES_NORMAL jiffies.
- * - If anyone calls uislib_force_channel_interrupt(), the above jiffy
- * sleep will be interrupted, and we will resume calling the "interrupt"
- * function for all devices.
- * - The list of devices is dynamically re-ordered in order to
- * attempt to preserve fairness. Whenever we spin thru the list of
- * devices and call the dev->interrupt() function, if we find
- * devices which report that there is still more work to do, the
- * the first such device we find is moved to the end of the device
- * list. This ensures that extremely busy devices don't starve out
- * less-busy ones.
- *
- */
-static int process_incoming(void *v)
-{
- unsigned long long cur_cycles, old_cycles, idle_cycles, delta_cycles;
- struct list_head *new_tail = NULL;
- int i;
-
- UIS_DAEMONIZE("dev_incoming");
- for (i = 0; i < 16; i++) {
- old_cycles = get_cycles();
- wait_event_timeout(poll_dev_wake_q,
- 0, POLLJIFFIES_NORMAL);
- cur_cycles = get_cycles();
- if (wait_cycles == 0) {
- wait_cycles = (cur_cycles - old_cycles);
- } else {
- if (wait_cycles < (cur_cycles - old_cycles))
- wait_cycles = (cur_cycles - old_cycles);
- }
- }
- cycles_before_wait = wait_cycles;
- idle_cycles = 0;
- poll_dev_start = 0;
- while (1) {
- struct list_head *lelt, *tmp;
- struct device_info *dev = NULL;
-
- /* poll each channel for input */
- down(&poll_dev_lock);
- new_tail = NULL;
- list_for_each_safe(lelt, tmp, &poll_dev_chan) {
- int rc = 0;
-
- dev = list_entry(lelt, struct device_info,
- list_polling_device_channels);
- down(&dev->interrupt_callback_lock);
- if (dev->interrupt)
- rc = dev->interrupt(dev->interrupt_context);
- else
- continue;
- up(&dev->interrupt_callback_lock);
- if (rc) {
- /* dev->interrupt returned, but there
- * is still more work to do.
- * Reschedule work to occur as soon as
- * possible. */
- idle_cycles = 0;
- if (!new_tail) {
- dev->first_busy_cnt++;
- if (!
- (list_is_last
- (lelt,
- &poll_dev_chan))) {
- new_tail = lelt;
- dev->moved_to_tail_cnt++;
- } else {
- dev->last_on_list_cnt++;
- }
- }
- }
- if (kthread_should_stop())
- break;
- }
- if (new_tail) {
- tot_moved_to_tail_cnt++;
- list_move_tail(new_tail, &poll_dev_chan);
- }
- up(&poll_dev_lock);
- cur_cycles = get_cycles();
- delta_cycles = cur_cycles - old_cycles;
- old_cycles = cur_cycles;
-
- /* At this point, we have scanned thru all of the
- * channels, and at least one of the following is true:
- * - there is no input waiting on any of the channels
- * - we have received a signal to stop this thread
- */
- if (kthread_should_stop())
- break;
- if (en_smart_wakeup == 0xFF)
- break;
- /* wait for POLLJIFFIES_NORMAL jiffies, or until
- * someone wakes up poll_dev_wake_q,
- * whichever comes first only do a wait when we have
- * been idle for cycles_before_wait cycles.
- */
- if (idle_cycles > cycles_before_wait) {
- poll_dev_start = 0;
- tot_wait_cnt++;
- wait_event_timeout(poll_dev_wake_q,
- poll_dev_start,
- POLLJIFFIES_NORMAL);
- poll_dev_start = 1;
- } else {
- tot_schedule_cnt++;
- schedule();
- idle_cycles = idle_cycles + delta_cycles;
- }
- }
- complete_and_exit(&incoming_ti.has_stopped, 0);
-}
-
-static BOOL
-initialize_incoming_thread(void)
-{
- if (incoming_started)
- return TRUE;
- if (!uisthread_start(&incoming_ti,
- &process_incoming, NULL, "dev_incoming")) {
- return FALSE;
- }
- incoming_started = TRUE;
- return TRUE;
-}
-
-/* Add a new device/channel to the list being processed by
- * process_incoming().
- * <interrupt> - indicates the function to call periodically.
- * <interrupt_context> - indicates the data to pass to the <interrupt>
- * function.
- */
-void
-uislib_enable_channel_interrupts(u32 bus_no, u32 dev_no,
- int (*interrupt)(void *),
- void *interrupt_context)
-{
- struct device_info *dev;
-
- dev = find_dev(bus_no, dev_no);
- if (!dev)
- return;
-
- down(&poll_dev_lock);
- initialize_incoming_thread();
- dev->interrupt = interrupt;
- dev->interrupt_context = interrupt_context;
- dev->polling = TRUE;
- list_add_tail(&dev->list_polling_device_channels,
- &poll_dev_chan);
- up(&poll_dev_lock);
-}
-EXPORT_SYMBOL_GPL(uislib_enable_channel_interrupts);
-
-/* Remove a device/channel from the list being processed by
- * process_incoming().
- */
-void
-uislib_disable_channel_interrupts(u32 bus_no, u32 dev_no)
-{
- struct device_info *dev;
-
- dev = find_dev(bus_no, dev_no);
- if (!dev)
- return;
- down(&poll_dev_lock);
- list_del(&dev->list_polling_device_channels);
- dev->polling = FALSE;
- dev->interrupt = NULL;
- up(&poll_dev_lock);
-}
-EXPORT_SYMBOL_GPL(uislib_disable_channel_interrupts);
-
-static void
-do_wakeup_polling_device_channels(struct work_struct *dummy)
-{
- if (!poll_dev_start) {
- poll_dev_start = 1;
- wake_up(&poll_dev_wake_q);
- }
-}
-
-static DECLARE_WORK(work_wakeup_polling_device_channels,
- do_wakeup_polling_device_channels);
-
-/* Call this function when you want to send a hint to process_incoming() that
- * your device might have more requests.
- */
-void
-uislib_force_channel_interrupt(u32 bus_no, u32 dev_no)
-{
- if (en_smart_wakeup == 0)
- return;
- if (poll_dev_start)
- return;
- /* The point of using schedule_work() instead of just doing
- * the work inline is to force a slight delay before waking up
- * the process_incoming() thread.
- */
- tot_wakeup_cnt++;
- schedule_work(&work_wakeup_polling_device_channels);
-}
-EXPORT_SYMBOL_GPL(uislib_force_channel_interrupt);
-
-/*****************************************************/
-/* Module Init & Exit functions */
-/*****************************************************/
-
-static int __init
-uislib_mod_init(void)
-{
- if (!unisys_spar_platform)
- return -ENODEV;
-
- /* initialize global pointers to NULL */
- bus_list = NULL;
- bus_list_count = 0;
- max_bus_count = 0;
- rwlock_init(&bus_list_lock);
- virt_control_chan_func = NULL;
-
- /* Issue VMCALL_GET_CONTROLVM_ADDR to get CtrlChanPhysAddr and
- * then map this physical address to a virtual address. */
- POSTCODE_LINUX_2(DRIVER_ENTRY_PC, POSTCODE_SEVERITY_INFO);
-
- dir_debugfs = debugfs_create_dir(DIR_DEBUGFS_ENTRY, NULL);
- if (dir_debugfs) {
- info_debugfs_entry = debugfs_create_file(
- INFO_DEBUGFS_ENTRY_FN, 0444, dir_debugfs, NULL,
- &debugfs_info_fops);
-
- platformnumber_debugfs_read = debugfs_create_u32(
- PLATFORMNUMBER_DEBUGFS_ENTRY_FN, 0444, dir_debugfs,
- &platform_no);
-
- cycles_before_wait_debugfs_read = debugfs_create_u64(
- CYCLES_BEFORE_WAIT_DEBUGFS_ENTRY_FN, 0666, dir_debugfs,
- &cycles_before_wait);
-
- smart_wakeup_debugfs_entry = debugfs_create_bool(
- SMART_WAKEUP_DEBUGFS_ENTRY_FN, 0666, dir_debugfs,
- &en_smart_wakeup);
- }
-
- POSTCODE_LINUX_3(DRIVER_EXIT_PC, 0, POSTCODE_SEVERITY_INFO);
- return 0;
-}
-
-static void __exit
-uislib_mod_exit(void)
-{
- if (debug_buf) {
- vfree(debug_buf);
- debug_buf = NULL;
- }
-
- debugfs_remove(info_debugfs_entry);
- debugfs_remove(smart_wakeup_debugfs_entry);
- debugfs_remove(cycles_before_wait_debugfs_read);
- debugfs_remove(platformnumber_debugfs_read);
- debugfs_remove(dir_debugfs);
-}
-
-module_init(uislib_mod_init);
-module_exit(uislib_mod_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Usha Srinivasan");
-MODULE_ALIAS("uislib");
- /* this is extracted during depmod and kept in modules.dep */
diff --git a/drivers/staging/unisys/uislib/uisqueue.c b/drivers/staging/unisys/uislib/uisqueue.c
deleted file mode 100644
index d46dd7428..000000000
--- a/drivers/staging/unisys/uislib/uisqueue.c
+++ /dev/null
@@ -1,322 +0,0 @@
-/* uisqueue.c
- *
- * Copyright (C) 2010 - 2013 UNISYS CORPORATION
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
- * NON INFRINGEMENT. See the GNU General Public License for more
- * details.
- */
-
-/* @ALL_INSPECTED */
-#include <linux/kernel.h>
-#include <linux/module.h>
-
-#include "uisutils.h"
-
-/* this is shorter than using __FILE__ (full path name) in
- * debug/info/error messages */
-#define CURRENT_FILE_PC UISLIB_PC_uisqueue_c
-#define __MYFILE__ "uisqueue.c"
-
-#define CHECK_CACHE_ALIGN 0
-
-/*****************************************************/
-/* Exported functions */
-/*****************************************************/
-
-/*
- * Routine Description:
- * Tries to insert the prebuilt signal pointed to by pSignal into the nth
- * Queue of the Channel pointed to by pChannel
- *
- * Parameters:
- * pChannel: (IN) points to the IO Channel
- * Queue: (IN) nth Queue of the IO Channel
- * pSignal: (IN) pointer to the signal
- *
- * Assumptions:
- * - pChannel, Queue and pSignal are valid.
- * - If insertion fails due to a full queue, the caller will determine the
- * retry policy (e.g. wait & try again, report an error, etc.).
- *
- * Return value:
- * 1 if the insertion succeeds, 0 if the queue was full.
- */
-unsigned char spar_signal_insert(struct channel_header __iomem *ch, u32 queue,
- void *sig)
-{
- void __iomem *psignal;
- unsigned int head, tail, nof;
-
- struct signal_queue_header __iomem *pqhdr =
- (struct signal_queue_header __iomem *)
- ((char __iomem *)ch + readq(&ch->ch_space_offset))
- + queue;
-
- /* capture current head and tail */
- head = readl(&pqhdr->head);
- tail = readl(&pqhdr->tail);
-
- /* queue is full if (head + 1) % n equals tail */
- if (((head + 1) % readl(&pqhdr->max_slots)) == tail) {
- nof = readq(&pqhdr->num_overflows) + 1;
- writeq(nof, &pqhdr->num_overflows);
- return 0;
- }
-
- /* increment the head index */
- head = (head + 1) % readl(&pqhdr->max_slots);
-
- /* copy signal to the head location from the area pointed to
- * by pSignal
- */
- psignal = (char __iomem *)pqhdr + readq(&pqhdr->sig_base_offset) +
- (head * readl(&pqhdr->signal_size));
- memcpy_toio(psignal, sig, readl(&pqhdr->signal_size));
-
- mb(); /* channel synch */
- writel(head, &pqhdr->head);
-
- writeq(readq(&pqhdr->num_sent) + 1, &pqhdr->num_sent);
- return 1;
-}
-EXPORT_SYMBOL_GPL(spar_signal_insert);
-
-/*
- * Routine Description:
- * Removes one signal from Channel pChannel's nth Queue at the
- * time of the call and copies it into the memory pointed to by
- * pSignal.
- *
- * Parameters:
- * pChannel: (IN) points to the IO Channel
- * Queue: (IN) nth Queue of the IO Channel
- * pSignal: (IN) pointer to where the signals are to be copied
- *
- * Assumptions:
- * - pChannel and Queue are valid.
- * - pSignal points to a memory area large enough to hold queue's SignalSize
- *
- * Return value:
- * 1 if the removal succeeds, 0 if the queue was empty.
- */
-unsigned char
-spar_signal_remove(struct channel_header __iomem *ch, u32 queue, void *sig)
-{
- void __iomem *psource;
- unsigned int head, tail;
- struct signal_queue_header __iomem *pqhdr =
- (struct signal_queue_header __iomem *)((char __iomem *)ch +
- readq(&ch->ch_space_offset)) + queue;
-
- /* capture current head and tail */
- head = readl(&pqhdr->head);
- tail = readl(&pqhdr->tail);
-
- /* queue is empty if the head index equals the tail index */
- if (head == tail) {
- writeq(readq(&pqhdr->num_empty) + 1, &pqhdr->num_empty);
- return 0;
- }
-
- /* advance past the 'empty' front slot */
- tail = (tail + 1) % readl(&pqhdr->max_slots);
-
- /* copy signal from tail location to the area pointed to by pSignal */
- psource = (char __iomem *)pqhdr + readq(&pqhdr->sig_base_offset) +
- (tail * readl(&pqhdr->signal_size));
- memcpy_fromio(sig, psource, readl(&pqhdr->signal_size));
-
- mb(); /* channel synch */
- writel(tail, &pqhdr->tail);
-
- writeq(readq(&pqhdr->num_received) + 1,
- &pqhdr->num_received);
- return 1;
-}
-EXPORT_SYMBOL_GPL(spar_signal_remove);
-
-/*
- * Routine Description:
- * Removes all signals present in Channel pChannel's nth Queue at the
- * time of the call and copies them into the memory pointed to by
- * pSignal. Returns the # of signals copied as the value of the routine.
- *
- * Parameters:
- * pChannel: (IN) points to the IO Channel
- * Queue: (IN) nth Queue of the IO Channel
- * pSignal: (IN) pointer to where the signals are to be copied
- *
- * Assumptions:
- * - pChannel and Queue are valid.
- * - pSignal points to a memory area large enough to hold Queue's MaxSignals
- * # of signals, each of which is Queue's SignalSize.
- *
- * Return value:
- * # of signals copied.
- */
-unsigned int spar_signal_remove_all(struct channel_header *ch, u32 queue,
- void *sig)
-{
- void *psource;
- unsigned int head, tail, count = 0;
- struct signal_queue_header *pqhdr =
- (struct signal_queue_header *)((char *)ch +
- ch->ch_space_offset) + queue;
-
- /* capture current head and tail */
- head = pqhdr->head;
- tail = pqhdr->tail;
-
- /* queue is empty if the head index equals the tail index */
- if (head == tail)
- return 0;
-
- while (head != tail) {
- /* advance past the 'empty' front slot */
- tail = (tail + 1) % pqhdr->max_slots;
-
- /* copy signal from tail location to the area pointed
- * to by pSignal
- */
- psource =
- (char *)pqhdr + pqhdr->sig_base_offset +
- (tail * pqhdr->signal_size);
- memcpy((char *)sig + (pqhdr->signal_size * count),
- psource, pqhdr->signal_size);
-
- mb(); /* channel synch */
- pqhdr->tail = tail;
-
- count++;
- pqhdr->num_received++;
- }
-
- return count;
-}
-
-/*
- * Routine Description:
- * Determine whether a signal queue is empty.
- *
- * Parameters:
- * pChannel: (IN) points to the IO Channel
- * Queue: (IN) nth Queue of the IO Channel
- *
- * Return value:
- * 1 if the signal queue is empty, 0 otherwise.
- */
-unsigned char spar_signalqueue_empty(struct channel_header __iomem *ch,
- u32 queue)
-{
- struct signal_queue_header __iomem *pqhdr =
- (struct signal_queue_header __iomem *)((char __iomem *)ch +
- readq(&ch->ch_space_offset)) + queue;
- return readl(&pqhdr->head) == readl(&pqhdr->tail);
-}
-EXPORT_SYMBOL_GPL(spar_signalqueue_empty);
-
-unsigned long long
-uisqueue_interlocked_or(unsigned long long __iomem *tgt,
- unsigned long long set)
-{
- unsigned long long i;
- unsigned long long j;
-
- j = readq(tgt);
- do {
- i = j;
- j = cmpxchg((__force unsigned long long *)tgt, i, i | set);
-
- } while (i != j);
-
- return j;
-}
-EXPORT_SYMBOL_GPL(uisqueue_interlocked_or);
-
-unsigned long long
-uisqueue_interlocked_and(unsigned long long __iomem *tgt,
- unsigned long long set)
-{
- unsigned long long i;
- unsigned long long j;
-
- j = readq(tgt);
- do {
- i = j;
- j = cmpxchg((__force unsigned long long *)tgt, i, i & set);
-
- } while (i != j);
-
- return j;
-}
-EXPORT_SYMBOL_GPL(uisqueue_interlocked_and);
-
-static u8
-do_locked_client_insert(struct uisqueue_info *queueinfo,
- unsigned int whichqueue,
- void *signal,
- spinlock_t *lock,
- u8 *channel_id)
-{
- unsigned long flags;
- u8 rc = 0;
-
- spin_lock_irqsave(lock, flags);
- if (!spar_channel_client_acquire_os(queueinfo->chan, channel_id))
- goto unlock;
- if (spar_signal_insert(queueinfo->chan, whichqueue, signal)) {
- queueinfo->packets_sent++;
- rc = 1;
- }
- spar_channel_client_release_os(queueinfo->chan, channel_id);
-unlock:
- spin_unlock_irqrestore((spinlock_t *)lock, flags);
- return rc;
-}
-
-int
-uisqueue_put_cmdrsp_with_lock_client(struct uisqueue_info *queueinfo,
- struct uiscmdrsp *cmdrsp,
- unsigned int whichqueue,
- void *insertlock,
- unsigned char issue_irq_if_empty,
- u64 irq_handle,
- char oktowait, u8 *channel_id)
-{
- while (!do_locked_client_insert(queueinfo, whichqueue, cmdrsp,
- (spinlock_t *)insertlock,
- channel_id)) {
- if (oktowait != OK_TO_WAIT)
- return 0; /* failed to queue */
-
- /* try again */
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(msecs_to_jiffies(10));
- }
- return 1;
-}
-EXPORT_SYMBOL_GPL(uisqueue_put_cmdrsp_with_lock_client);
-
-/* uisqueue_get_cmdrsp gets the cmdrsp entry at the head of the queue
- * returns NULL if queue is empty */
-int
-uisqueue_get_cmdrsp(struct uisqueue_info *queueinfo,
- void *cmdrsp, unsigned int whichqueue)
-{
- if (!spar_signal_remove(queueinfo->chan, whichqueue, cmdrsp))
- return 0;
-
- queueinfo->packets_received++;
-
- return 1; /* Success */
-}
-EXPORT_SYMBOL_GPL(uisqueue_get_cmdrsp);
diff --git a/drivers/staging/unisys/uislib/uisthread.c b/drivers/staging/unisys/uislib/uisthread.c
deleted file mode 100644
index d3c973b61..000000000
--- a/drivers/staging/unisys/uislib/uisthread.c
+++ /dev/null
@@ -1,69 +0,0 @@
-/* uisthread.c
- *
- * Copyright (C) 2010 - 2013 UNISYS CORPORATION
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
- * NON INFRINGEMENT. See the GNU General Public License for more
- * details.
- */
-
-/* @ALL_INSPECTED */
-#include <asm/processor.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/kthread.h>
-#include "uisutils.h"
-#include "uisthread.h"
-
-/* this is shorter than using __FILE__ (full path name) in
- * debug/info/error messages
- */
-#define CURRENT_FILE_PC UISLIB_PC_uisthread_c
-#define __MYFILE__ "uisthread.c"
-
-/*****************************************************/
-/* Exported functions */
-/*****************************************************/
-
-/* returns 0 for failure, 1 for success */
-int
-uisthread_start(struct uisthread_info *thrinfo,
- int (*threadfn)(void *), void *thrcontext, char *name)
-{
- /* used to stop the thread */
- init_completion(&thrinfo->has_stopped);
- thrinfo->task = kthread_run(threadfn, thrcontext, name);
- if (IS_ERR(thrinfo->task)) {
- thrinfo->id = 0;
- return 0; /* failure */
- }
- thrinfo->id = thrinfo->task->pid;
- return 1;
-}
-EXPORT_SYMBOL_GPL(uisthread_start);
-
-void
-uisthread_stop(struct uisthread_info *thrinfo)
-{
- int stopped = 0;
-
- if (thrinfo->id == 0)
- return; /* thread not running */
-
- kthread_stop(thrinfo->task);
- /* give up if the thread has NOT died in 1 minute */
- if (wait_for_completion_timeout(&thrinfo->has_stopped, 60 * HZ))
- stopped = 1;
-
- if (stopped)
- thrinfo->id = 0;
-}
-EXPORT_SYMBOL_GPL(uisthread_stop);
diff --git a/drivers/staging/unisys/uislib/uisutils.c b/drivers/staging/unisys/uislib/uisutils.c
deleted file mode 100644
index 26ab76526..000000000
--- a/drivers/staging/unisys/uislib/uisutils.c
+++ /dev/null
@@ -1,137 +0,0 @@
-/* uisutils.c
- *
- * Copyright (C) 2010 - 2013 UNISYS CORPORATION
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
- * NON INFRINGEMENT. See the GNU General Public License for more
- * details.
- */
-
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/types.h>
-#include <linux/uuid.h>
-#include <linux/spinlock.h>
-#include <linux/list.h>
-#include "uisutils.h"
-#include "version.h"
-#include "vbushelper.h"
-#include <linux/skbuff.h>
-#ifdef CONFIG_HIGHMEM
-#include <linux/highmem.h>
-#endif
-
-/* this is shorter than using __FILE__ (full path name) in
- * debug/info/error messages
- */
-#define CURRENT_FILE_PC UISLIB_PC_uisutils_c
-#define __MYFILE__ "uisutils.c"
-
-/* exports */
-atomic_t uisutils_registered_services = ATOMIC_INIT(0);
- /* num registrations via
- * uisctrl_register_req_handler() or
- * uisctrl_register_req_handler_ex() */
-
-/*****************************************************/
-/* Utility functions */
-/*****************************************************/
-
-int
-uisutil_add_proc_line_ex(int *total, char **buffer, int *buffer_remaining,
- char *format, ...)
-{
- va_list args;
- int len;
-
- va_start(args, format);
- len = vsnprintf(*buffer, *buffer_remaining, format, args);
- va_end(args);
- if (len >= *buffer_remaining) {
- *buffer += *buffer_remaining;
- *total += *buffer_remaining;
- *buffer_remaining = 0;
- return -1;
- }
- *buffer_remaining -= len;
- *buffer += len;
- *total += len;
- return len;
-}
-EXPORT_SYMBOL_GPL(uisutil_add_proc_line_ex);
-
-int
-uisctrl_register_req_handler(int type, void *fptr,
- struct ultra_vbus_deviceinfo *chipset_driver_info)
-{
- switch (type) {
- case 2:
- if (fptr) {
- if (!virt_control_chan_func)
- atomic_inc(&uisutils_registered_services);
- virt_control_chan_func = fptr;
- } else {
- if (virt_control_chan_func)
- atomic_dec(&uisutils_registered_services);
- virt_control_chan_func = NULL;
- }
- break;
-
- default:
- return 0;
- }
- if (chipset_driver_info)
- bus_device_info_init(chipset_driver_info, "chipset", "uislib",
- VERSION, NULL);
-
- return 1;
-}
-EXPORT_SYMBOL_GPL(uisctrl_register_req_handler);
-
-/*
- * unsigned int uisutil_copy_fragsinfo_from_skb(unsigned char *calling_ctx,
- * void *skb_in,
- * unsigned int firstfraglen,
- * unsigned int frags_max,
- * struct phys_info frags[])
- *
- * calling_ctx - input - a string that is displayed to show
- * who called * this func
- * void *skb_in - skb whose frag info we're copying type is hidden so we
- * don't need to include skbbuff in uisutils.h which is
- * included in non-networking code.
- * unsigned int firstfraglen - input - length of first fragment in skb
- * unsigned int frags_max - input - max len of frags array
- * struct phys_info frags[] - output - frags array filled in on output
- * return value indicates number of
- * entries filled in frags
- */
-
-static LIST_HEAD(req_handler_info_list); /* list of struct req_handler_info */
-static DEFINE_SPINLOCK(req_handler_info_list_lock);
-
-struct req_handler_info *
-req_handler_find(uuid_le switch_uuid)
-{
- struct list_head *lelt, *tmp;
- struct req_handler_info *entry = NULL;
-
- spin_lock(&req_handler_info_list_lock);
- list_for_each_safe(lelt, tmp, &req_handler_info_list) {
- entry = list_entry(lelt, struct req_handler_info, list_link);
- if (uuid_le_cmp(entry->switch_uuid, switch_uuid) == 0) {
- spin_unlock(&req_handler_info_list_lock);
- return entry;
- }
- }
- spin_unlock(&req_handler_info_list_lock);
- return NULL;
-}
diff --git a/drivers/staging/unisys/virthba/Kconfig b/drivers/staging/unisys/virthba/Kconfig
deleted file mode 100644
index dfadfc491..000000000
--- a/drivers/staging/unisys/virthba/Kconfig
+++ /dev/null
@@ -1,13 +0,0 @@
-#
-# Unisys virthba configuration
-#
-
-config UNISYS_VIRTHBA
- tristate "Unisys virthba driver"
- depends on SCSI
- select UNISYS_VISORCHIPSET
- select UNISYS_UISLIB
- select UNISYS_VIRTPCI
- ---help---
- If you say Y here, you will enable the Unisys virthba driver.
-
diff --git a/drivers/staging/unisys/virthba/Makefile b/drivers/staging/unisys/virthba/Makefile
deleted file mode 100644
index a4e403739..000000000
--- a/drivers/staging/unisys/virthba/Makefile
+++ /dev/null
@@ -1,12 +0,0 @@
-#
-# Makefile for Unisys virthba
-#
-
-obj-$(CONFIG_UNISYS_VIRTHBA) += virthba.o
-
-ccflags-y += -Idrivers/staging/unisys/include
-ccflags-y += -Idrivers/staging/unisys/uislib
-ccflags-y += -Idrivers/staging/unisys/visorchipset
-ccflags-y += -Idrivers/staging/unisys/virtpci
-ccflags-y += -Idrivers/staging/unisys/common-spar/include
-ccflags-y += -Idrivers/staging/unisys/common-spar/include/channels
diff --git a/drivers/staging/unisys/virthba/virthba.c b/drivers/staging/unisys/virthba/virthba.c
deleted file mode 100644
index d9001cca0..000000000
--- a/drivers/staging/unisys/virthba/virthba.c
+++ /dev/null
@@ -1,1572 +0,0 @@
-/* virthba.c
- *
- * Copyright (C) 2010 - 2013 UNISYS CORPORATION
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
- * NON INFRINGEMENT. See the GNU General Public License for more
- * details.
- */
-
-#define EXPORT_SYMTAB
-
-/* if you want to turn on some debugging of write device data or read
- * device data, define these two undefs. You will probably want to
- * customize the code which is here since it was written assuming
- * reading and writing a specific data file df.64M.txt which is a
- * 64Megabyte file created by Art Nilson using a scritp I wrote called
- * cr_test_data.pl. The data file consists of 256 byte lines of text
- * which start with an 8 digit sequence number, a colon, and then
- * letters after that */
-
-#include <linux/kernel.h>
-#ifdef CONFIG_MODVERSIONS
-#include <config/modversions.h>
-#endif
-
-#include "diagnostics/appos_subsystems.h"
-#include "uisutils.h"
-#include "uisqueue.h"
-#include "uisthread.h"
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/spinlock.h>
-#include <linux/device.h>
-#include <linux/slab.h>
-#include <scsi/scsi.h>
-#include <scsi/scsi_host.h>
-#include <scsi/scsi_cmnd.h>
-#include <scsi/scsi_device.h>
-#include <asm/param.h>
-#include <linux/debugfs.h>
-#include <linux/types.h>
-
-#include "virthba.h"
-#include "virtpci.h"
-#include "visorchipset.h"
-#include "version.h"
-#include "guestlinuxdebug.h"
-/* this is shorter than using __FILE__ (full path name) in
- * debug/info/error messages
- */
-#define CURRENT_FILE_PC VIRT_HBA_PC_virthba_c
-#define __MYFILE__ "virthba.c"
-
-/* NOTE: L1_CACHE_BYTES >=128 */
-#define DEVICE_ATTRIBUTE struct device_attribute
-
- /* MAX_BUF = 6 lines x 10 MAXVHBA x 80 characters
- * = 4800 bytes ~ 2^13 = 8192 bytes
- */
-#define MAX_BUF 8192
-
-/*****************************************************/
-/* Forward declarations */
-/*****************************************************/
-static int virthba_probe(struct virtpci_dev *dev,
- const struct pci_device_id *id);
-static void virthba_remove(struct virtpci_dev *dev);
-static int virthba_abort_handler(struct scsi_cmnd *scsicmd);
-static int virthba_bus_reset_handler(struct scsi_cmnd *scsicmd);
-static int virthba_device_reset_handler(struct scsi_cmnd *scsicmd);
-static int virthba_host_reset_handler(struct scsi_cmnd *scsicmd);
-static const char *virthba_get_info(struct Scsi_Host *shp);
-static int virthba_ioctl(struct scsi_device *dev, int cmd, void __user *arg);
-static int virthba_queue_command_lck(struct scsi_cmnd *scsicmd,
- void (*virthba_cmnd_done)
- (struct scsi_cmnd *));
-
-static const struct x86_cpu_id unisys_spar_ids[] = {
- { X86_VENDOR_INTEL, 6, 62, X86_FEATURE_ANY },
- {}
-};
-
-/* Autoload */
-MODULE_DEVICE_TABLE(x86cpu, unisys_spar_ids);
-
-#ifdef DEF_SCSI_QCMD
-static DEF_SCSI_QCMD(virthba_queue_command)
-#else
-#define virthba_queue_command virthba_queue_command_lck
-#endif
-
-static int virthba_slave_alloc(struct scsi_device *scsidev);
-static int virthba_slave_configure(struct scsi_device *scsidev);
-static void virthba_slave_destroy(struct scsi_device *scsidev);
-static int process_incoming_rsps(void *);
-static int virthba_serverup(struct virtpci_dev *virtpcidev);
-static int virthba_serverdown(struct virtpci_dev *virtpcidev, u32 state);
-static void do_disk_add_remove(struct work_struct *work);
-static void virthba_serverdown_complete(struct work_struct *work);
-static ssize_t info_debugfs_read(struct file *file, char __user *buf,
- size_t len, loff_t *offset);
-static ssize_t enable_ints_write(struct file *file,
- const char __user *buffer, size_t count,
- loff_t *ppos);
-
-/*****************************************************/
-/* Globals */
-/*****************************************************/
-
-static int rsltq_wait_usecs = 4000; /* Default 4ms */
-static unsigned int max_buff_len;
-
-/* Module options */
-static char *virthba_options = "NONE";
-
-static const struct pci_device_id virthba_id_table[] = {
- {PCI_DEVICE(PCI_VENDOR_ID_UNISYS, PCI_DEVICE_ID_VIRTHBA)},
- {0},
-};
-
-/* export virthba_id_table */
-MODULE_DEVICE_TABLE(pci, virthba_id_table);
-
-static struct workqueue_struct *virthba_serverdown_workqueue;
-
-static struct virtpci_driver virthba_driver = {
- .name = "uisvirthba",
- .version = VERSION,
- .vertag = NULL,
- .id_table = virthba_id_table,
- .probe = virthba_probe,
- .remove = virthba_remove,
- .resume = virthba_serverup,
- .suspend = virthba_serverdown
-};
-
-/* The Send and Recive Buffers of the IO Queue may both be full */
-#define MAX_PENDING_REQUESTS (MIN_NUMSIGNALS*2)
-#define INTERRUPT_VECTOR_MASK 0x3F
-
-struct scsipending {
- char cmdtype; /* Type of pointer that is being stored */
- void *sent; /* The Data being tracked */
- /* struct scsi_cmnd *type for virthba_queue_command */
- /* struct uiscmdrsp *type for management commands */
-};
-
-#define VIRTHBA_ERROR_COUNT 30
-#define IOS_ERROR_THRESHOLD 1000
-struct virtdisk_info {
- u32 valid;
- u32 channel, id, lun; /* Disk Path */
- atomic_t ios_threshold;
- atomic_t error_count;
- struct virtdisk_info *next;
-};
-
-/* Each Scsi_Host has a host_data area that contains this struct. */
-struct virthba_info {
- struct Scsi_Host *scsihost;
- struct virtpci_dev *virtpcidev;
- struct list_head dev_info_list;
- struct chaninfo chinfo;
- struct irq_info intr; /* use recvInterrupt info to receive
- interrupts when IOs complete */
- int interrupt_vector;
- struct scsipending pending[MAX_PENDING_REQUESTS]; /* Tracks the requests
- that have been */
- /* forwarded to the IOVM and haven't returned yet */
- unsigned int nextinsert; /* Start search for next pending
- free slot here */
- spinlock_t privlock;
- bool serverdown;
- bool serverchangingstate;
- unsigned long long acquire_failed_cnt;
- unsigned long long interrupts_rcvd;
- unsigned long long interrupts_notme;
- unsigned long long interrupts_disabled;
- struct work_struct serverdown_completion;
- u64 __iomem *flags_addr;
- atomic_t interrupt_rcvd;
- wait_queue_head_t rsp_queue;
- struct virtdisk_info head;
-};
-
-/* Work Data for dar_work_queue */
-struct diskaddremove {
- u8 add; /* 0-remove, 1-add */
- struct Scsi_Host *shost; /* Scsi Host for this virthba instance */
- u32 channel, id, lun; /* Disk Path */
- struct diskaddremove *next;
-};
-
-#define virtpci_dev_to_virthba_virthba_get_info(d) \
- container_of(d, struct virthba_info, virtpcidev)
-
-static DEVICE_ATTRIBUTE *virthba_shost_attrs[];
-static struct scsi_host_template virthba_driver_template = {
- .name = "Unisys Virtual HBA",
- .info = virthba_get_info,
- .ioctl = virthba_ioctl,
- .queuecommand = virthba_queue_command,
- .eh_abort_handler = virthba_abort_handler,
- .eh_device_reset_handler = virthba_device_reset_handler,
- .eh_bus_reset_handler = virthba_bus_reset_handler,
- .eh_host_reset_handler = virthba_host_reset_handler,
- .shost_attrs = virthba_shost_attrs,
-
-#define VIRTHBA_MAX_CMNDS 128
- .can_queue = VIRTHBA_MAX_CMNDS,
- .sg_tablesize = 64, /* largest number of address/length pairs */
- .this_id = -1,
- .slave_alloc = virthba_slave_alloc,
- .slave_configure = virthba_slave_configure,
- .slave_destroy = virthba_slave_destroy,
- .use_clustering = ENABLE_CLUSTERING,
-};
-
-struct virthba_devices_open {
- struct virthba_info *virthbainfo;
-};
-
-static const struct file_operations debugfs_info_fops = {
- .read = info_debugfs_read,
-};
-
-static const struct file_operations debugfs_enable_ints_fops = {
- .write = enable_ints_write,
-};
-
-/*****************************************************/
-/* Structs */
-/*****************************************************/
-
-#define VIRTHBASOPENMAX 1
-/* array of open devices maintained by open() and close(); */
-static struct virthba_devices_open virthbas_open[VIRTHBASOPENMAX];
-static struct dentry *virthba_debugfs_dir;
-
-/*****************************************************/
-/* Local Functions */
-/*****************************************************/
-static int
-add_scsipending_entry(struct virthba_info *vhbainfo, char cmdtype, void *new)
-{
- unsigned long flags;
- int insert_location;
-
- spin_lock_irqsave(&vhbainfo->privlock, flags);
- insert_location = vhbainfo->nextinsert;
- while (vhbainfo->pending[insert_location].sent) {
- insert_location = (insert_location + 1) % MAX_PENDING_REQUESTS;
- if (insert_location == (int)vhbainfo->nextinsert) {
- spin_unlock_irqrestore(&vhbainfo->privlock, flags);
- return -1;
- }
- }
-
- vhbainfo->pending[insert_location].cmdtype = cmdtype;
- vhbainfo->pending[insert_location].sent = new;
- vhbainfo->nextinsert = (insert_location + 1) % MAX_PENDING_REQUESTS;
- spin_unlock_irqrestore(&vhbainfo->privlock, flags);
-
- return insert_location;
-}
-
-static unsigned int
-add_scsipending_entry_with_wait(struct virthba_info *vhbainfo, char cmdtype,
- void *new)
-{
- int insert_location = add_scsipending_entry(vhbainfo, cmdtype, new);
-
- while (insert_location == -1) {
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(msecs_to_jiffies(10));
- insert_location = add_scsipending_entry(vhbainfo, cmdtype, new);
- }
-
- return (unsigned int)insert_location;
-}
-
-static void *
-del_scsipending_entry(struct virthba_info *vhbainfo, uintptr_t del)
-{
- unsigned long flags;
- void *sent = NULL;
-
- if (del < MAX_PENDING_REQUESTS) {
- spin_lock_irqsave(&vhbainfo->privlock, flags);
- sent = vhbainfo->pending[del].sent;
-
- vhbainfo->pending[del].cmdtype = 0;
- vhbainfo->pending[del].sent = NULL;
- spin_unlock_irqrestore(&vhbainfo->privlock, flags);
- }
-
- return sent;
-}
-
-/* dar_work_queue (Disk Add/Remove) */
-static struct work_struct dar_work_queue;
-static struct diskaddremove *dar_work_queue_head;
-static spinlock_t dar_work_queue_lock;
-static unsigned short dar_work_queue_sched;
-#define QUEUE_DISKADDREMOVE(dar) { \
- spin_lock_irqsave(&dar_work_queue_lock, flags); \
- if (!dar_work_queue_head) { \
- dar_work_queue_head = dar; \
- dar->next = NULL; \
- } \
- else { \
- dar->next = dar_work_queue_head; \
- dar_work_queue_head = dar; \
- } \
- if (!dar_work_queue_sched) { \
- schedule_work(&dar_work_queue); \
- dar_work_queue_sched = 1; \
- } \
- spin_unlock_irqrestore(&dar_work_queue_lock, flags); \
-}
-
-static inline void
-send_disk_add_remove(struct diskaddremove *dar)
-{
- struct scsi_device *sdev;
- int error;
-
- sdev = scsi_device_lookup(dar->shost, dar->channel, dar->id, dar->lun);
- if (sdev) {
- if (!(dar->add))
- scsi_remove_device(sdev);
- } else if (dar->add) {
- error =
- scsi_add_device(dar->shost, dar->channel, dar->id,
- dar->lun);
- }
- kfree(dar);
-}
-
-/*****************************************************/
-/* dar_work_queue Handler Thread */
-/*****************************************************/
-static void
-do_disk_add_remove(struct work_struct *work)
-{
- struct diskaddremove *dar;
- struct diskaddremove *tmphead;
- int i = 0;
- unsigned long flags;
-
- spin_lock_irqsave(&dar_work_queue_lock, flags);
- tmphead = dar_work_queue_head;
- dar_work_queue_head = NULL;
- dar_work_queue_sched = 0;
- spin_unlock_irqrestore(&dar_work_queue_lock, flags);
- while (tmphead) {
- dar = tmphead;
- tmphead = dar->next;
- send_disk_add_remove(dar);
- i++;
- }
-}
-
-/*****************************************************/
-/* Routine to add entry to dar_work_queue */
-/*****************************************************/
-static void
-process_disk_notify(struct Scsi_Host *shost, struct uiscmdrsp *cmdrsp)
-{
- struct diskaddremove *dar;
- unsigned long flags;
-
- dar = kzalloc(sizeof(*dar), GFP_ATOMIC);
- if (dar) {
- dar->add = cmdrsp->disknotify.add;
- dar->shost = shost;
- dar->channel = cmdrsp->disknotify.channel;
- dar->id = cmdrsp->disknotify.id;
- dar->lun = cmdrsp->disknotify.lun;
- QUEUE_DISKADDREMOVE(dar);
- }
-}
-
-/*****************************************************/
-/* Probe Remove Functions */
-/*****************************************************/
-static irqreturn_t
-virthba_isr(int irq, void *dev_id)
-{
- struct virthba_info *virthbainfo = (struct virthba_info *)dev_id;
- struct channel_header __iomem *channel_header;
- struct signal_queue_header __iomem *pqhdr;
- u64 mask;
- unsigned long long rc1;
-
- if (!virthbainfo)
- return IRQ_NONE;
- virthbainfo->interrupts_rcvd++;
- channel_header = virthbainfo->chinfo.queueinfo->chan;
- if (((readq(&channel_header->features)
- & ULTRA_IO_IOVM_IS_OK_WITH_DRIVER_DISABLING_INTS) != 0) &&
- ((readq(&channel_header->features) &
- ULTRA_IO_DRIVER_DISABLES_INTS) !=
- 0)) {
- virthbainfo->interrupts_disabled++;
- mask = ~ULTRA_CHANNEL_ENABLE_INTS;
- rc1 = uisqueue_interlocked_and(virthbainfo->flags_addr, mask);
- }
- if (spar_signalqueue_empty(channel_header, IOCHAN_FROM_IOPART)) {
- virthbainfo->interrupts_notme++;
- return IRQ_NONE;
- }
- pqhdr = (struct signal_queue_header __iomem *)
- ((char __iomem *)channel_header +
- readq(&channel_header->ch_space_offset)) + IOCHAN_FROM_IOPART;
- writeq(readq(&pqhdr->num_irq_received) + 1,
- &pqhdr->num_irq_received);
- atomic_set(&virthbainfo->interrupt_rcvd, 1);
- wake_up_interruptible(&virthbainfo->rsp_queue);
- return IRQ_HANDLED;
-}
-
-static int
-virthba_probe(struct virtpci_dev *virtpcidev, const struct pci_device_id *id)
-{
- int error;
- struct Scsi_Host *scsihost;
- struct virthba_info *virthbainfo;
- int rsp;
- int i;
- irq_handler_t handler = virthba_isr;
- struct channel_header __iomem *channel_header;
- struct signal_queue_header __iomem *pqhdr;
- u64 mask;
-
- POSTCODE_LINUX_2(VHBA_PROBE_ENTRY_PC, POSTCODE_SEVERITY_INFO);
- /* call scsi_host_alloc to register a scsi host adapter
- * instance - this virthba that has just been created is an
- * instance of a scsi host adapter. This scsi_host_alloc
- * function allocates a new Scsi_Host struct & performs basic
- * initialization. The host is not published to the scsi
- * midlayer until scsi_add_host is called.
- */
-
- /* arg 2 passed in length of extra space we want allocated
- * with scsi_host struct for our own use scsi_host_alloc
- * assign host_no
- */
- scsihost = scsi_host_alloc(&virthba_driver_template,
- sizeof(struct virthba_info));
- if (!scsihost)
- return -ENODEV;
-
- scsihost->this_id = UIS_MAGIC_VHBA;
- /* linux treats max-channel differently than max-id & max-lun.
- * In the latter cases, those two values result in 0 to max-1
- * (inclusive) being scanned. But in the case of channels, the
- * scan is 0 to max (inclusive); so we will subtract one from
- * the max-channel value.
- */
- scsihost->max_channel = (unsigned)virtpcidev->scsi.max.max_channel;
- scsihost->max_id = (unsigned)virtpcidev->scsi.max.max_id;
- scsihost->max_lun = (unsigned)virtpcidev->scsi.max.max_lun;
- scsihost->cmd_per_lun = (unsigned)virtpcidev->scsi.max.cmd_per_lun;
- scsihost->max_sectors =
- (unsigned short)(virtpcidev->scsi.max.max_io_size >> 9);
- scsihost->sg_tablesize =
- (unsigned short)(virtpcidev->scsi.max.max_io_size / PAGE_SIZE);
- if (scsihost->sg_tablesize > MAX_PHYS_INFO)
- scsihost->sg_tablesize = MAX_PHYS_INFO;
-
- /* this creates "host%d" in sysfs. If 2nd argument is NULL,
- * then this generic /sys/devices/platform/host? device is
- * created and /sys/scsi_host/host? ->
- * /sys/devices/platform/host? If 2nd argument is not NULL,
- * then this generic /sys/devices/<path>/host? is created and
- * host? points to that device instead.
- */
- error = scsi_add_host(scsihost, &virtpcidev->generic_dev);
- if (error) {
- POSTCODE_LINUX_2(VHBA_PROBE_FAILURE_PC, POSTCODE_SEVERITY_ERR);
- /* decr refcount on scsihost which was incremented by
- * scsi_add_host so the scsi_host gets deleted
- */
- scsi_host_put(scsihost);
- return -ENODEV;
- }
-
- virthbainfo = (struct virthba_info *)scsihost->hostdata;
- memset(virthbainfo, 0, sizeof(struct virthba_info));
- for (i = 0; i < VIRTHBASOPENMAX; i++) {
- if (!virthbas_open[i].virthbainfo) {
- virthbas_open[i].virthbainfo = virthbainfo;
- break;
- }
- }
- virthbainfo->interrupt_vector = -1;
- virthbainfo->chinfo.queueinfo = &virtpcidev->queueinfo;
- virthbainfo->virtpcidev = virtpcidev;
- spin_lock_init(&virthbainfo->chinfo.insertlock);
-
- init_waitqueue_head(&virthbainfo->rsp_queue);
- spin_lock_init(&virthbainfo->privlock);
- memset(&virthbainfo->pending, 0, sizeof(virthbainfo->pending));
- virthbainfo->serverdown = false;
- virthbainfo->serverchangingstate = false;
-
- virthbainfo->intr = virtpcidev->intr;
- /* save of host within virthba_info */
- virthbainfo->scsihost = scsihost;
-
- /* save of host within virtpci_dev */
- virtpcidev->scsi.scsihost = scsihost;
-
- /* Setup workqueue for serverdown messages */
- INIT_WORK(&virthbainfo->serverdown_completion,
- virthba_serverdown_complete);
-
- writeq(readq(&virthbainfo->chinfo.queueinfo->chan->features) |
- ULTRA_IO_CHANNEL_IS_POLLING,
- &virthbainfo->chinfo.queueinfo->chan->features);
- /* start thread that will receive scsicmnd responses */
-
- channel_header = virthbainfo->chinfo.queueinfo->chan;
- pqhdr = (struct signal_queue_header __iomem *)
- ((char __iomem *)channel_header +
- readq(&channel_header->ch_space_offset)) + IOCHAN_FROM_IOPART;
- virthbainfo->flags_addr = &pqhdr->features;
-
- if (!uisthread_start(&virthbainfo->chinfo.threadinfo,
- process_incoming_rsps,
- virthbainfo, "vhba_incoming")) {
- /* decr refcount on scsihost which was incremented by
- * scsi_add_host so the scsi_host gets deleted
- */
- POSTCODE_LINUX_2(VHBA_PROBE_FAILURE_PC, POSTCODE_SEVERITY_ERR);
- scsi_host_put(scsihost);
- return -ENODEV;
- }
- virthbainfo->interrupt_vector =
- virthbainfo->intr.recv_irq_handle & INTERRUPT_VECTOR_MASK;
- rsp = request_irq(virthbainfo->interrupt_vector, handler, IRQF_SHARED,
- scsihost->hostt->name, virthbainfo);
- if (rsp != 0) {
- virthbainfo->interrupt_vector = -1;
- POSTCODE_LINUX_2(VHBA_PROBE_FAILURE_PC, POSTCODE_SEVERITY_ERR);
- } else {
- u64 __iomem *features_addr =
- &virthbainfo->chinfo.queueinfo->chan->features;
- mask = ~(ULTRA_IO_CHANNEL_IS_POLLING |
- ULTRA_IO_DRIVER_DISABLES_INTS);
- uisqueue_interlocked_and(features_addr, mask);
- mask = ULTRA_IO_DRIVER_ENABLES_INTS;
- uisqueue_interlocked_or(features_addr, mask);
- rsltq_wait_usecs = 4000000;
- }
-
- scsi_scan_host(scsihost);
-
- POSTCODE_LINUX_2(VHBA_PROBE_EXIT_PC, POSTCODE_SEVERITY_INFO);
- return 0;
-}
-
-static void
-virthba_remove(struct virtpci_dev *virtpcidev)
-{
- struct virthba_info *virthbainfo;
- struct Scsi_Host *scsihost =
- (struct Scsi_Host *)virtpcidev->scsi.scsihost;
-
- virthbainfo = (struct virthba_info *)scsihost->hostdata;
- if (virthbainfo->interrupt_vector != -1)
- free_irq(virthbainfo->interrupt_vector, virthbainfo);
-
- scsi_remove_host(scsihost);
-
- uisthread_stop(&virthbainfo->chinfo.threadinfo);
-
- /* decr refcount on scsihost which was incremented by
- * scsi_add_host so the scsi_host gets deleted
- */
- scsi_host_put(scsihost);
-}
-
-static int
-forward_vdiskmgmt_command(enum vdisk_mgmt_types vdiskcmdtype,
- struct Scsi_Host *scsihost,
- struct uisscsi_dest *vdest)
-{
- struct uiscmdrsp *cmdrsp;
- struct virthba_info *virthbainfo =
- (struct virthba_info *)scsihost->hostdata;
- int notifyresult = 0xffff;
- wait_queue_head_t notifyevent;
-
- if (virthbainfo->serverdown || virthbainfo->serverchangingstate)
- return FAILED;
-
- cmdrsp = kzalloc(SIZEOF_CMDRSP, GFP_ATOMIC);
- if (!cmdrsp)
- return FAILED; /* reject */
-
- init_waitqueue_head(&notifyevent);
-
- /* issue VDISK_MGMT_CMD
- * set type to command - as opposed to task mgmt
- */
- cmdrsp->cmdtype = CMD_VDISKMGMT_TYPE;
- /* specify the event that has to be triggered when this cmd is
- * complete
- */
- cmdrsp->vdiskmgmt.notify = (void *)&notifyevent;
- cmdrsp->vdiskmgmt.notifyresult = (void *)&notifyresult;
-
- /* save destination */
- cmdrsp->vdiskmgmt.vdisktype = vdiskcmdtype;
- cmdrsp->vdiskmgmt.vdest.channel = vdest->channel;
- cmdrsp->vdiskmgmt.vdest.id = vdest->id;
- cmdrsp->vdiskmgmt.vdest.lun = vdest->lun;
- cmdrsp->vdiskmgmt.scsicmd =
- (void *)(uintptr_t)
- add_scsipending_entry_with_wait(virthbainfo, CMD_VDISKMGMT_TYPE,
- (void *)cmdrsp);
-
- uisqueue_put_cmdrsp_with_lock_client(virthbainfo->chinfo.queueinfo,
- cmdrsp, IOCHAN_TO_IOPART,
- &virthbainfo->chinfo.insertlock,
- DONT_ISSUE_INTERRUPT, (u64)NULL,
- OK_TO_WAIT, "vhba");
- wait_event(notifyevent, notifyresult != 0xffff);
- kfree(cmdrsp);
- return SUCCESS;
-}
-
-/*****************************************************/
-/* Scsi Host support functions */
-/*****************************************************/
-
-static int
-forward_taskmgmt_command(enum task_mgmt_types tasktype,
- struct scsi_device *scsidev)
-{
- struct uiscmdrsp *cmdrsp;
- struct virthba_info *virthbainfo =
- (struct virthba_info *)scsidev->host->hostdata;
- int notifyresult = 0xffff;
- wait_queue_head_t notifyevent;
-
- if (virthbainfo->serverdown || virthbainfo->serverchangingstate)
- return FAILED;
-
- cmdrsp = kzalloc(SIZEOF_CMDRSP, GFP_ATOMIC);
- if (!cmdrsp)
- return FAILED; /* reject */
-
- init_waitqueue_head(&notifyevent);
-
- /* issue TASK_MGMT_ABORT_TASK */
- /* set type to command - as opposed to task mgmt */
- cmdrsp->cmdtype = CMD_SCSITASKMGMT_TYPE;
- /* specify the event that has to be triggered when this */
- /* cmd is complete */
- cmdrsp->scsitaskmgmt.notify = (void *)&notifyevent;
- cmdrsp->scsitaskmgmt.notifyresult = (void *)&notifyresult;
-
- /* save destination */
- cmdrsp->scsitaskmgmt.tasktype = tasktype;
- cmdrsp->scsitaskmgmt.vdest.channel = scsidev->channel;
- cmdrsp->scsitaskmgmt.vdest.id = scsidev->id;
- cmdrsp->scsitaskmgmt.vdest.lun = scsidev->lun;
- cmdrsp->scsitaskmgmt.scsicmd =
- (void *)(uintptr_t)
- add_scsipending_entry_with_wait(virthbainfo,
- CMD_SCSITASKMGMT_TYPE,
- (void *)cmdrsp);
-
- uisqueue_put_cmdrsp_with_lock_client(virthbainfo->chinfo.queueinfo,
- cmdrsp, IOCHAN_TO_IOPART,
- &virthbainfo->chinfo.insertlock,
- DONT_ISSUE_INTERRUPT, (u64)NULL,
- OK_TO_WAIT, "vhba");
- wait_event(notifyevent, notifyresult != 0xffff);
- kfree(cmdrsp);
- return SUCCESS;
-}
-
-/* The abort handler returns SUCCESS if it has succeeded to make LLDD
- * and all related hardware forget about the scmd.
- */
-static int
-virthba_abort_handler(struct scsi_cmnd *scsicmd)
-{
- /* issue TASK_MGMT_ABORT_TASK */
- struct scsi_device *scsidev;
- struct virtdisk_info *vdisk;
-
- scsidev = scsicmd->device;
- for (vdisk = &((struct virthba_info *)scsidev->host->hostdata)->head;
- vdisk->next; vdisk = vdisk->next) {
- if ((scsidev->channel == vdisk->channel) &&
- (scsidev->id == vdisk->id) &&
- (scsidev->lun == vdisk->lun)) {
- if (atomic_read(&vdisk->error_count) <
- VIRTHBA_ERROR_COUNT) {
- atomic_inc(&vdisk->error_count);
- POSTCODE_LINUX_2(VHBA_COMMAND_HANDLER_PC,
- POSTCODE_SEVERITY_INFO);
- } else
- atomic_set(&vdisk->ios_threshold,
- IOS_ERROR_THRESHOLD);
- }
- }
- return forward_taskmgmt_command(TASK_MGMT_ABORT_TASK, scsicmd->device);
-}
-
-static int
-virthba_bus_reset_handler(struct scsi_cmnd *scsicmd)
-{
- /* issue TASK_MGMT_TARGET_RESET for each target on the bus */
- struct scsi_device *scsidev;
- struct virtdisk_info *vdisk;
-
- scsidev = scsicmd->device;
- for (vdisk = &((struct virthba_info *)scsidev->host->hostdata)->head;
- vdisk->next; vdisk = vdisk->next) {
- if ((scsidev->channel == vdisk->channel) &&
- (scsidev->id == vdisk->id) &&
- (scsidev->lun == vdisk->lun)) {
- if (atomic_read(&vdisk->error_count) <
- VIRTHBA_ERROR_COUNT) {
- atomic_inc(&vdisk->error_count);
- POSTCODE_LINUX_2(VHBA_COMMAND_HANDLER_PC,
- POSTCODE_SEVERITY_INFO);
- } else
- atomic_set(&vdisk->ios_threshold,
- IOS_ERROR_THRESHOLD);
- }
- }
- return forward_taskmgmt_command(TASK_MGMT_BUS_RESET, scsicmd->device);
-}
-
-static int
-virthba_device_reset_handler(struct scsi_cmnd *scsicmd)
-{
- /* issue TASK_MGMT_LUN_RESET */
- struct scsi_device *scsidev;
- struct virtdisk_info *vdisk;
-
- scsidev = scsicmd->device;
- for (vdisk = &((struct virthba_info *)scsidev->host->hostdata)->head;
- vdisk->next; vdisk = vdisk->next) {
- if ((scsidev->channel == vdisk->channel) &&
- (scsidev->id == vdisk->id) &&
- (scsidev->lun == vdisk->lun)) {
- if (atomic_read(&vdisk->error_count) <
- VIRTHBA_ERROR_COUNT) {
- atomic_inc(&vdisk->error_count);
- POSTCODE_LINUX_2(VHBA_COMMAND_HANDLER_PC,
- POSTCODE_SEVERITY_INFO);
- } else
- atomic_set(&vdisk->ios_threshold,
- IOS_ERROR_THRESHOLD);
- }
- }
- return forward_taskmgmt_command(TASK_MGMT_LUN_RESET, scsicmd->device);
-}
-
-static int
-virthba_host_reset_handler(struct scsi_cmnd *scsicmd)
-{
- /* issue TASK_MGMT_TARGET_RESET for each target on each bus for host */
- return SUCCESS;
-}
-
-static char virthba_get_info_str[256];
-
-static const char *
-virthba_get_info(struct Scsi_Host *shp)
-{
- /* Return version string */
- sprintf(virthba_get_info_str, "virthba, version %s\n", VIRTHBA_VERSION);
- return virthba_get_info_str;
-}
-
-static int
-virthba_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
-{
- return -EINVAL;
-}
-
-/* This returns SCSI_MLQUEUE_DEVICE_BUSY if the signal queue to IOpart
- * is full.
- */
-static int
-virthba_queue_command_lck(struct scsi_cmnd *scsicmd,
- void (*virthba_cmnd_done)(struct scsi_cmnd *))
-{
- struct scsi_device *scsidev = scsicmd->device;
- int insert_location;
- unsigned char op;
- unsigned char *cdb = scsicmd->cmnd;
- struct Scsi_Host *scsihost = scsidev->host;
- struct uiscmdrsp *cmdrsp;
- unsigned int i;
- struct virthba_info *virthbainfo =
- (struct virthba_info *)scsihost->hostdata;
- struct scatterlist *sg = NULL;
- struct scatterlist *sgl = NULL;
- int sg_failed = 0;
-
- if (virthbainfo->serverdown || virthbainfo->serverchangingstate)
- return SCSI_MLQUEUE_DEVICE_BUSY;
- cmdrsp = kzalloc(SIZEOF_CMDRSP, GFP_ATOMIC);
- if (!cmdrsp)
- return 1; /* reject the command */
-
- /* now saving everything we need from scsi_cmd into cmdrsp
- * before we queue cmdrsp set type to command - as opposed to
- * task mgmt
- */
- cmdrsp->cmdtype = CMD_SCSI_TYPE;
- /* save the pending insertion location. Deletion from pending
- * will return the scsicmd pointer for completion
- */
- insert_location =
- add_scsipending_entry(virthbainfo, CMD_SCSI_TYPE, (void *)scsicmd);
- if (insert_location != -1) {
- cmdrsp->scsi.scsicmd = (void *)(uintptr_t)insert_location;
- } else {
- kfree(cmdrsp);
- return SCSI_MLQUEUE_DEVICE_BUSY;
- }
- /* save done function that we have call when cmd is complete */
- scsicmd->scsi_done = virthba_cmnd_done;
- /* save destination */
- cmdrsp->scsi.vdest.channel = scsidev->channel;
- cmdrsp->scsi.vdest.id = scsidev->id;
- cmdrsp->scsi.vdest.lun = scsidev->lun;
- /* save datadir */
- cmdrsp->scsi.data_dir = scsicmd->sc_data_direction;
- memcpy(cmdrsp->scsi.cmnd, cdb, MAX_CMND_SIZE);
-
- cmdrsp->scsi.bufflen = scsi_bufflen(scsicmd);
-
- /* keep track of the max buffer length so far. */
- if (cmdrsp->scsi.bufflen > max_buff_len)
- max_buff_len = cmdrsp->scsi.bufflen;
-
- if (scsi_sg_count(scsicmd) > MAX_PHYS_INFO) {
- del_scsipending_entry(virthbainfo, (uintptr_t)insert_location);
- kfree(cmdrsp);
- return 1; /* reject the command */
- }
-
- /* This is what we USED to do when we assumed we were running */
- /* uissd & virthba on the same Linux system. */
- /* cmdrsp->scsi.buffer = scsicmd->request_buffer; */
- /* The following code does NOT make that assumption. */
- /* convert buffer to phys information */
- if (scsi_sg_count(scsicmd) == 0) {
- if (scsi_bufflen(scsicmd) > 0) {
- BUG_ON(scsi_sg_count(scsicmd) == 0);
- }
- } else {
- /* buffer is scatterlist - copy it out */
- sgl = scsi_sglist(scsicmd);
-
- for_each_sg(sgl, sg, scsi_sg_count(scsicmd), i) {
- cmdrsp->scsi.gpi_list[i].address = sg_phys(sg);
- cmdrsp->scsi.gpi_list[i].length = sg->length;
- }
-
- if (sg_failed) {
- /* BUG(); ***** For now, let it fail in uissd
- * if it is a problem, as it might just
- * work
- */
- }
-
- cmdrsp->scsi.guest_phys_entries = scsi_sg_count(scsicmd);
- }
-
- op = cdb[0];
- i = uisqueue_put_cmdrsp_with_lock_client(virthbainfo->chinfo.queueinfo,
- cmdrsp, IOCHAN_TO_IOPART,
- &virthbainfo->chinfo.
- insertlock,
- DONT_ISSUE_INTERRUPT,
- (u64)NULL, DONT_WAIT, "vhba");
- if (i == 0) {
- /* queue must be full - and we said don't wait - return busy */
- kfree(cmdrsp);
- del_scsipending_entry(virthbainfo, (uintptr_t)insert_location);
- return SCSI_MLQUEUE_DEVICE_BUSY;
- }
-
- /* we're done with cmdrsp space - data from it has been copied
- * into channel - free it now.
- */
- kfree(cmdrsp);
- return 0; /* non-zero implies host/device is busy */
-}
-
-static int
-virthba_slave_alloc(struct scsi_device *scsidev)
-{
- /* this called by the midlayer before scan for new devices -
- * LLD can alloc any struct & do init if needed.
- */
- struct virtdisk_info *vdisk;
- struct virtdisk_info *tmpvdisk;
- struct virthba_info *virthbainfo;
- struct Scsi_Host *scsihost = (struct Scsi_Host *)scsidev->host;
-
- virthbainfo = (struct virthba_info *)scsihost->hostdata;
- if (!virthbainfo)
- return 0; /* even though we errored, treat as success */
-
- for (vdisk = &virthbainfo->head; vdisk->next; vdisk = vdisk->next) {
- if (vdisk->next->valid &&
- (vdisk->next->channel == scsidev->channel) &&
- (vdisk->next->id == scsidev->id) &&
- (vdisk->next->lun == scsidev->lun))
- return 0;
- }
- tmpvdisk = kzalloc(sizeof(*tmpvdisk), GFP_ATOMIC);
- if (!tmpvdisk)
- return 0;
-
- tmpvdisk->channel = scsidev->channel;
- tmpvdisk->id = scsidev->id;
- tmpvdisk->lun = scsidev->lun;
- tmpvdisk->valid = 1;
- vdisk->next = tmpvdisk;
- return 0; /* success */
-}
-
-static int
-virthba_slave_configure(struct scsi_device *scsidev)
-{
- return 0; /* success */
-}
-
-static void
-virthba_slave_destroy(struct scsi_device *scsidev)
-{
- /* midlevel calls this after device has been quiesced and
- * before it is to be deleted.
- */
- struct virtdisk_info *vdisk, *delvdisk;
- struct virthba_info *virthbainfo;
- struct Scsi_Host *scsihost = (struct Scsi_Host *)scsidev->host;
-
- virthbainfo = (struct virthba_info *)scsihost->hostdata;
- for (vdisk = &virthbainfo->head; vdisk->next; vdisk = vdisk->next) {
- if (vdisk->next->valid &&
- (vdisk->next->channel == scsidev->channel) &&
- (vdisk->next->id == scsidev->id) &&
- (vdisk->next->lun == scsidev->lun)) {
- delvdisk = vdisk->next;
- vdisk->next = vdisk->next->next;
- kfree(delvdisk);
- return;
- }
- }
-}
-
-/*****************************************************/
-/* Scsi Cmnd support thread */
-/*****************************************************/
-
-static void
-do_scsi_linuxstat(struct uiscmdrsp *cmdrsp, struct scsi_cmnd *scsicmd)
-{
- struct virtdisk_info *vdisk;
- struct scsi_device *scsidev;
- struct sense_data *sd;
-
- scsidev = scsicmd->device;
- memcpy(scsicmd->sense_buffer, cmdrsp->scsi.sensebuf, MAX_SENSE_SIZE);
- sd = (struct sense_data *)scsicmd->sense_buffer;
-
- /* Do not log errors for disk-not-present inquiries */
- if ((cmdrsp->scsi.cmnd[0] == INQUIRY) &&
- (host_byte(cmdrsp->scsi.linuxstat) == DID_NO_CONNECT) &&
- (cmdrsp->scsi.addlstat == ADDL_SEL_TIMEOUT))
- return;
-
- /* Okay see what our error_count is here.... */
- for (vdisk = &((struct virthba_info *)scsidev->host->hostdata)->head;
- vdisk->next; vdisk = vdisk->next) {
- if ((scsidev->channel != vdisk->channel) ||
- (scsidev->id != vdisk->id) ||
- (scsidev->lun != vdisk->lun))
- continue;
-
- if (atomic_read(&vdisk->error_count) < VIRTHBA_ERROR_COUNT) {
- atomic_inc(&vdisk->error_count);
- atomic_set(&vdisk->ios_threshold, IOS_ERROR_THRESHOLD);
- }
- }
-}
-
-static void
-do_scsi_nolinuxstat(struct uiscmdrsp *cmdrsp, struct scsi_cmnd *scsicmd)
-{
- struct scsi_device *scsidev;
- unsigned char buf[36];
- struct scatterlist *sg;
- unsigned int i;
- char *thispage;
- char *thispage_orig;
- int bufind = 0;
- struct virtdisk_info *vdisk;
-
- scsidev = scsicmd->device;
- if ((cmdrsp->scsi.cmnd[0] == INQUIRY) &&
- (cmdrsp->scsi.bufflen >= MIN_INQUIRY_RESULT_LEN)) {
- if (cmdrsp->scsi.no_disk_result == 0)
- return;
-
- /* Linux scsi code is weird; it wants
- * a device at Lun 0 to issue report
- * luns, but we don't want a disk
- * there so we'll present a processor
- * there. */
- SET_NO_DISK_INQUIRY_RESULT(buf, cmdrsp->scsi.bufflen,
- scsidev->lun,
- DEV_DISK_CAPABLE_NOT_PRESENT,
- DEV_NOT_CAPABLE);
-
- if (scsi_sg_count(scsicmd) == 0) {
- if (scsi_bufflen(scsicmd) > 0) {
- BUG_ON(scsi_sg_count(scsicmd) ==
- 0);
- }
- memcpy(scsi_sglist(scsicmd), buf,
- cmdrsp->scsi.bufflen);
- return;
- }
-
- sg = scsi_sglist(scsicmd);
- for (i = 0; i < scsi_sg_count(scsicmd); i++) {
- thispage_orig = kmap_atomic(sg_page(sg + i));
- thispage = (void *)((unsigned long)thispage_orig |
- sg[i].offset);
- memcpy(thispage, buf + bufind, sg[i].length);
- kunmap_atomic(thispage_orig);
- bufind += sg[i].length;
- }
- } else {
- vdisk = &((struct virthba_info *)scsidev->host->hostdata)->head;
- for ( ; vdisk->next; vdisk = vdisk->next) {
- if ((scsidev->channel != vdisk->channel) ||
- (scsidev->id != vdisk->id) ||
- (scsidev->lun != vdisk->lun))
- continue;
-
- if (atomic_read(&vdisk->ios_threshold) > 0) {
- atomic_dec(&vdisk->ios_threshold);
- if (atomic_read(&vdisk->ios_threshold) == 0) {
- atomic_set(&vdisk->error_count, 0);
- }
- }
- }
- }
-}
-
-static void
-complete_scsi_command(struct uiscmdrsp *cmdrsp, struct scsi_cmnd *scsicmd)
-{
- /* take what we need out of cmdrsp and complete the scsicmd */
- scsicmd->result = cmdrsp->scsi.linuxstat;
- if (cmdrsp->scsi.linuxstat)
- do_scsi_linuxstat(cmdrsp, scsicmd);
- else
- do_scsi_nolinuxstat(cmdrsp, scsicmd);
-
- if (scsicmd->scsi_done)
- scsicmd->scsi_done(scsicmd);
-}
-
-static inline void
-complete_vdiskmgmt_command(struct uiscmdrsp *cmdrsp)
-{
- /* copy the result of the taskmgmt and */
- /* wake up the error handler that is waiting for this */
- *(int *)cmdrsp->vdiskmgmt.notifyresult = cmdrsp->vdiskmgmt.result;
- wake_up_all((wait_queue_head_t *)cmdrsp->vdiskmgmt.notify);
-}
-
-static inline void
-complete_taskmgmt_command(struct uiscmdrsp *cmdrsp)
-{
- /* copy the result of the taskmgmt and */
- /* wake up the error handler that is waiting for this */
- *(int *)cmdrsp->scsitaskmgmt.notifyresult =
- cmdrsp->scsitaskmgmt.result;
- wake_up_all((wait_queue_head_t *)cmdrsp->scsitaskmgmt.notify);
-}
-
-static void
-drain_queue(struct virthba_info *virthbainfo, struct chaninfo *dc,
- struct uiscmdrsp *cmdrsp)
-{
- unsigned long flags;
- int qrslt = 0;
- struct scsi_cmnd *scsicmd;
- struct Scsi_Host *shost = virthbainfo->scsihost;
-
- while (1) {
- spin_lock_irqsave(&virthbainfo->chinfo.insertlock, flags);
- if (!spar_channel_client_acquire_os(dc->queueinfo->chan,
- "vhba")) {
- spin_unlock_irqrestore(&virthbainfo->chinfo.insertlock,
- flags);
- virthbainfo->acquire_failed_cnt++;
- break;
- }
- qrslt = uisqueue_get_cmdrsp(dc->queueinfo, cmdrsp,
- IOCHAN_FROM_IOPART);
- spar_channel_client_release_os(dc->queueinfo->chan, "vhba");
- spin_unlock_irqrestore(&virthbainfo->chinfo.insertlock, flags);
- if (qrslt == 0)
- break;
- if (cmdrsp->cmdtype == CMD_SCSI_TYPE) {
- /* scsicmd location is returned by the
- * deletion
- */
- scsicmd = del_scsipending_entry(virthbainfo,
- (uintptr_t)
- cmdrsp->scsi.scsicmd);
- if (!scsicmd)
- break;
- /* complete the orig cmd */
- complete_scsi_command(cmdrsp, scsicmd);
- } else if (cmdrsp->cmdtype == CMD_SCSITASKMGMT_TYPE) {
- if (!del_scsipending_entry(virthbainfo,
- (uintptr_t)cmdrsp->scsitaskmgmt.scsicmd))
- break;
- complete_taskmgmt_command(cmdrsp);
- } else if (cmdrsp->cmdtype == CMD_NOTIFYGUEST_TYPE) {
- /* The vHba pointer has no meaning in
- * a Client/Guest Partition. Let's be
- * safe and set it to NULL now. Do
- * not use it here! */
- cmdrsp->disknotify.v_hba = NULL;
- process_disk_notify(shost, cmdrsp);
- } else if (cmdrsp->cmdtype == CMD_VDISKMGMT_TYPE) {
- if (!del_scsipending_entry(virthbainfo,
- (uintptr_t)
- cmdrsp->vdiskmgmt.scsicmd))
- break;
- complete_vdiskmgmt_command(cmdrsp);
- }
- /* cmdrsp is now available for reuse */
- }
-}
-
-/* main function for the thread that waits for scsi commands to arrive
- * in a specified queue
- */
-static int
-process_incoming_rsps(void *v)
-{
- struct virthba_info *virthbainfo = v;
- struct chaninfo *dc = &virthbainfo->chinfo;
- struct uiscmdrsp *cmdrsp = NULL;
- const int SZ = sizeof(struct uiscmdrsp);
- u64 mask;
- unsigned long long rc1;
-
- UIS_DAEMONIZE("vhba_incoming");
- /* alloc once and reuse */
- cmdrsp = kmalloc(SZ, GFP_ATOMIC);
- if (!cmdrsp) {
- complete_and_exit(&dc->threadinfo.has_stopped, 0);
- return 0;
- }
- mask = ULTRA_CHANNEL_ENABLE_INTS;
- while (1) {
- if (kthread_should_stop())
- break;
- wait_event_interruptible_timeout(virthbainfo->rsp_queue,
- (atomic_read(&virthbainfo->interrupt_rcvd) == 1),
- usecs_to_jiffies(rsltq_wait_usecs));
- atomic_set(&virthbainfo->interrupt_rcvd, 0);
- /* drain queue */
- drain_queue(virthbainfo, dc, cmdrsp);
- rc1 = uisqueue_interlocked_or(virthbainfo->flags_addr, mask);
- }
-
- kfree(cmdrsp);
-
- complete_and_exit(&dc->threadinfo.has_stopped, 0);
-}
-
-/*****************************************************/
-/* Debugfs filesystem functions */
-/*****************************************************/
-
-static ssize_t info_debugfs_read(struct file *file,
- char __user *buf, size_t len, loff_t *offset)
-{
- ssize_t bytes_read = 0;
- int str_pos = 0;
- u64 phys_flags_addr;
- int i;
- struct virthba_info *virthbainfo;
- char *vbuf;
-
- if (len > MAX_BUF)
- len = MAX_BUF;
- vbuf = kzalloc(len, GFP_KERNEL);
- if (!vbuf)
- return -ENOMEM;
-
- for (i = 0; i < VIRTHBASOPENMAX; i++) {
- if (!virthbas_open[i].virthbainfo)
- continue;
-
- virthbainfo = virthbas_open[i].virthbainfo;
-
- str_pos += scnprintf(vbuf + str_pos,
- len - str_pos, "max_buff_len:%u\n",
- max_buff_len);
-
- str_pos += scnprintf(vbuf + str_pos, len - str_pos,
- "\nvirthba result queue poll wait:%d usecs.\n",
- rsltq_wait_usecs);
- str_pos += scnprintf(vbuf + str_pos, len - str_pos,
- "\ninterrupts_rcvd = %llu, interrupts_disabled = %llu\n",
- virthbainfo->interrupts_rcvd,
- virthbainfo->interrupts_disabled);
- str_pos += scnprintf(vbuf + str_pos,
- len - str_pos, "\ninterrupts_notme = %llu,\n",
- virthbainfo->interrupts_notme);
- phys_flags_addr = virt_to_phys((__force void *)
- virthbainfo->flags_addr);
- str_pos += scnprintf(vbuf + str_pos, len - str_pos,
- "flags_addr = %p, phys_flags_addr=0x%016llx, FeatureFlags=%llu\n",
- virthbainfo->flags_addr, phys_flags_addr,
- (__le64)readq(virthbainfo->flags_addr));
- str_pos += scnprintf(vbuf + str_pos,
- len - str_pos, "acquire_failed_cnt:%llu\n",
- virthbainfo->acquire_failed_cnt);
- str_pos += scnprintf(vbuf + str_pos, len - str_pos, "\n");
- }
-
- bytes_read = simple_read_from_buffer(buf, len, offset, vbuf, str_pos);
- kfree(vbuf);
- return bytes_read;
-}
-
-static ssize_t enable_ints_write(struct file *file, const char __user *buffer,
- size_t count, loff_t *ppos)
-{
- char buf[4];
- int i, new_value;
- struct virthba_info *virthbainfo;
-
- u64 __iomem *features_addr;
- u64 mask;
-
- if (count >= ARRAY_SIZE(buf))
- return -EINVAL;
-
- buf[count] = '\0';
- if (copy_from_user(buf, buffer, count))
- return -EFAULT;
-
- i = kstrtoint(buf, 10, &new_value);
-
- if (i != 0)
- return -EFAULT;
-
- /* set all counts to new_value usually 0 */
- for (i = 0; i < VIRTHBASOPENMAX; i++) {
- if (virthbas_open[i].virthbainfo) {
- virthbainfo = virthbas_open[i].virthbainfo;
- features_addr =
- &virthbainfo->chinfo.queueinfo->chan->features;
- if (new_value == 1) {
- mask = ~(ULTRA_IO_CHANNEL_IS_POLLING |
- ULTRA_IO_DRIVER_DISABLES_INTS);
- uisqueue_interlocked_and(features_addr, mask);
- mask = ULTRA_IO_DRIVER_ENABLES_INTS;
- uisqueue_interlocked_or(features_addr, mask);
- rsltq_wait_usecs = 4000000;
- } else {
- mask = ~(ULTRA_IO_DRIVER_ENABLES_INTS |
- ULTRA_IO_DRIVER_DISABLES_INTS);
- uisqueue_interlocked_and(features_addr, mask);
- mask = ULTRA_IO_CHANNEL_IS_POLLING;
- uisqueue_interlocked_or(features_addr, mask);
- rsltq_wait_usecs = 4000;
- }
- }
- }
- return count;
-}
-
-/* As per VirtpciFunc returns 1 for success and 0 for failure */
-static int
-virthba_serverup(struct virtpci_dev *virtpcidev)
-{
- struct virthba_info *virthbainfo =
- (struct virthba_info *)((struct Scsi_Host *)virtpcidev->scsi.
- scsihost)->hostdata;
-
- if (!virthbainfo->serverdown)
- return 1;
-
- if (virthbainfo->serverchangingstate)
- return 0;
-
- virthbainfo->serverchangingstate = true;
- /* Must transition channel to ATTACHED state BEFORE we
- * can start using the device again
- */
- SPAR_CHANNEL_CLIENT_TRANSITION(virthbainfo->chinfo.queueinfo->chan,
- dev_name(&virtpcidev->generic_dev),
- CHANNELCLI_ATTACHED, NULL);
-
- /* Start Processing the IOVM Response Queue Again */
- if (!uisthread_start(&virthbainfo->chinfo.threadinfo,
- process_incoming_rsps,
- virthbainfo, "vhba_incoming")) {
- return 0;
- }
- virthbainfo->serverdown = false;
- virthbainfo->serverchangingstate = false;
-
- return 1;
-}
-
-static void
-virthba_serverdown_complete(struct work_struct *work)
-{
- struct virthba_info *virthbainfo;
- struct virtpci_dev *virtpcidev;
- int i;
- struct scsipending *pendingdel = NULL;
- struct scsi_cmnd *scsicmd = NULL;
- struct uiscmdrsp *cmdrsp;
- unsigned long flags;
-
- virthbainfo = container_of(work, struct virthba_info,
- serverdown_completion);
-
- /* Stop Using the IOVM Response Queue (queue should be drained
- * by the end)
- */
- uisthread_stop(&virthbainfo->chinfo.threadinfo);
-
- /* Fail Commands that weren't completed */
- spin_lock_irqsave(&virthbainfo->privlock, flags);
- for (i = 0; i < MAX_PENDING_REQUESTS; i++) {
- pendingdel = &virthbainfo->pending[i];
- switch (pendingdel->cmdtype) {
- case CMD_SCSI_TYPE:
- scsicmd = (struct scsi_cmnd *)pendingdel->sent;
- scsicmd->result = DID_RESET << 16;
- if (scsicmd->scsi_done)
- scsicmd->scsi_done(scsicmd);
- break;
- case CMD_SCSITASKMGMT_TYPE:
- cmdrsp = (struct uiscmdrsp *)pendingdel->sent;
- wake_up_all((wait_queue_head_t *)
- cmdrsp->scsitaskmgmt.notify);
- *(int *)cmdrsp->scsitaskmgmt.notifyresult =
- TASK_MGMT_FAILED;
- break;
- case CMD_VDISKMGMT_TYPE:
- cmdrsp = (struct uiscmdrsp *)pendingdel->sent;
- *(int *)cmdrsp->vdiskmgmt.notifyresult =
- VDISK_MGMT_FAILED;
- wake_up_all((wait_queue_head_t *)
- cmdrsp->vdiskmgmt.notify);
- break;
- default:
- break;
- }
- pendingdel->cmdtype = 0;
- pendingdel->sent = NULL;
- }
- spin_unlock_irqrestore(&virthbainfo->privlock, flags);
-
- virtpcidev = virthbainfo->virtpcidev;
-
- virthbainfo->serverdown = true;
- virthbainfo->serverchangingstate = false;
- /* Return the ServerDown response to Command */
- visorchipset_device_pause_response(virtpcidev->bus_no,
- virtpcidev->device_no, 0);
-}
-
-/* As per VirtpciFunc returns 1 for success and 0 for failure */
-static int
-virthba_serverdown(struct virtpci_dev *virtpcidev, u32 state)
-{
- int stat = 1;
-
- struct virthba_info *virthbainfo =
- (struct virthba_info *)((struct Scsi_Host *)virtpcidev->scsi.
- scsihost)->hostdata;
-
- if (!virthbainfo->serverdown && !virthbainfo->serverchangingstate) {
- virthbainfo->serverchangingstate = true;
- queue_work(virthba_serverdown_workqueue,
- &virthbainfo->serverdown_completion);
- } else if (virthbainfo->serverchangingstate) {
- stat = 0;
- }
-
- return stat;
-}
-
-/*****************************************************/
-/* Module Init & Exit functions */
-/*****************************************************/
-
-static int __init
-virthba_parse_line(char *str)
-{
- return 1;
-}
-
-static void __init
-virthba_parse_options(char *line)
-{
- char *next = line;
-
- POSTCODE_LINUX_2(VHBA_CREATE_ENTRY_PC, POSTCODE_SEVERITY_INFO);
- if (!line || !*line)
- return;
- while ((line = next)) {
- next = strchr(line, ' ');
- if (next)
- *next++ = 0;
- virthba_parse_line(line);
- }
-
- POSTCODE_LINUX_2(VHBA_CREATE_EXIT_PC, POSTCODE_SEVERITY_INFO);
-}
-
-static int __init
-virthba_mod_init(void)
-{
- int error;
- int i;
-
- if (!unisys_spar_platform)
- return -ENODEV;
-
- POSTCODE_LINUX_2(VHBA_CREATE_ENTRY_PC, POSTCODE_SEVERITY_INFO);
- virthba_parse_options(virthba_options);
-
- error = virtpci_register_driver(&virthba_driver);
- if (error < 0) {
- POSTCODE_LINUX_3(VHBA_CREATE_FAILURE_PC, error,
- POSTCODE_SEVERITY_ERR);
- } else {
- /* create the debugfs directories and entries */
- virthba_debugfs_dir = debugfs_create_dir("virthba", NULL);
- debugfs_create_file("info", S_IRUSR, virthba_debugfs_dir,
- NULL, &debugfs_info_fops);
- debugfs_create_u32("rqwait_usecs", S_IRUSR | S_IWUSR,
- virthba_debugfs_dir, &rsltq_wait_usecs);
- debugfs_create_file("enable_ints", S_IWUSR,
- virthba_debugfs_dir, NULL,
- &debugfs_enable_ints_fops);
- /* Initialize dar_work_queue */
- INIT_WORK(&dar_work_queue, do_disk_add_remove);
- spin_lock_init(&dar_work_queue_lock);
-
- /* clear out array */
- for (i = 0; i < VIRTHBASOPENMAX; i++)
- virthbas_open[i].virthbainfo = NULL;
- /* Initialize the serverdown workqueue */
- virthba_serverdown_workqueue =
- create_singlethread_workqueue("virthba_serverdown");
- if (!virthba_serverdown_workqueue) {
- POSTCODE_LINUX_2(VHBA_CREATE_FAILURE_PC,
- POSTCODE_SEVERITY_ERR);
- error = -1;
- }
- }
-
- POSTCODE_LINUX_2(VHBA_CREATE_EXIT_PC, POSTCODE_SEVERITY_INFO);
- return error;
-}
-
-static ssize_t
-virthba_acquire_lun(struct device *cdev, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct uisscsi_dest vdest;
- struct Scsi_Host *shost = class_to_shost(cdev);
- int i;
-
- i = sscanf(buf, "%d-%d-%d", &vdest.channel, &vdest.id, &vdest.lun);
- if (i != 3)
- return i;
-
- return forward_vdiskmgmt_command(VDISK_MGMT_ACQUIRE, shost, &vdest);
-}
-
-static ssize_t
-virthba_release_lun(struct device *cdev, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct uisscsi_dest vdest;
- struct Scsi_Host *shost = class_to_shost(cdev);
- int i;
-
- i = sscanf(buf, "%d-%d-%d", &vdest.channel, &vdest.id, &vdest.lun);
- if (i != 3)
- return i;
-
- return forward_vdiskmgmt_command(VDISK_MGMT_RELEASE, shost, &vdest);
-}
-
-#define CLASS_DEVICE_ATTR(_name, _mode, _show, _store) \
- struct device_attribute class_device_attr_##_name = \
- __ATTR(_name, _mode, _show, _store)
-
-static CLASS_DEVICE_ATTR(acquire_lun, S_IWUSR, NULL, virthba_acquire_lun);
-static CLASS_DEVICE_ATTR(release_lun, S_IWUSR, NULL, virthba_release_lun);
-
-static DEVICE_ATTRIBUTE *virthba_shost_attrs[] = {
- &class_device_attr_acquire_lun,
- &class_device_attr_release_lun,
- NULL
-};
-
-static void __exit
-virthba_mod_exit(void)
-{
- virtpci_unregister_driver(&virthba_driver);
- /* unregister is going to call virthba_remove */
- /* destroy serverdown completion workqueue */
- if (virthba_serverdown_workqueue) {
- destroy_workqueue(virthba_serverdown_workqueue);
- virthba_serverdown_workqueue = NULL;
- }
-
- debugfs_remove_recursive(virthba_debugfs_dir);
-}
-
-/* specify function to be run at module insertion time */
-module_init(virthba_mod_init);
-
-/* specify function to be run when module is removed */
-module_exit(virthba_mod_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Usha Srinivasan");
-MODULE_ALIAS("uisvirthba");
- /* this is extracted during depmod and kept in modules.dep */
-/* module parameter */
-module_param(virthba_options, charp, S_IRUGO);
diff --git a/drivers/staging/unisys/virthba/virthba.h b/drivers/staging/unisys/virthba/virthba.h
deleted file mode 100644
index 59901668d..000000000
--- a/drivers/staging/unisys/virthba/virthba.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/* virthba.h
- *
- * Copyright (C) 2010 - 2013 UNISYS CORPORATION
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
- * NON INFRINGEMENT. See the GNU General Public License for more
- * details.
- */
-
-/*
- * Unisys Virtual HBA driver header
- */
-
-#ifndef __VIRTHBA_H__
-#define __VIRTHBA_H__
-
-#define VIRTHBA_VERSION "01.00"
-
-#endif /* __VIRTHBA_H__ */
diff --git a/drivers/staging/unisys/virtpci/Kconfig b/drivers/staging/unisys/virtpci/Kconfig
deleted file mode 100644
index 6d19482ce..000000000
--- a/drivers/staging/unisys/virtpci/Kconfig
+++ /dev/null
@@ -1,10 +0,0 @@
-#
-# Unisys virtpci configuration
-#
-
-config UNISYS_VIRTPCI
- tristate "Unisys virtpci driver"
- select UNISYS_UISLIB
- ---help---
- If you say Y here, you will enable the Unisys virtpci driver.
-
diff --git a/drivers/staging/unisys/virtpci/Makefile b/drivers/staging/unisys/virtpci/Makefile
deleted file mode 100644
index a26c69621..000000000
--- a/drivers/staging/unisys/virtpci/Makefile
+++ /dev/null
@@ -1,10 +0,0 @@
-#
-# Makefile for Unisys virtpci
-#
-
-obj-$(CONFIG_UNISYS_VIRTPCI) += virtpci.o
-
-ccflags-y += -Idrivers/staging/unisys/include
-ccflags-y += -Idrivers/staging/unisys/uislib
-ccflags-y += -Idrivers/staging/unisys/common-spar/include
-ccflags-y += -Idrivers/staging/unisys/common-spar/include/channels
diff --git a/drivers/staging/unisys/virtpci/virtpci.c b/drivers/staging/unisys/virtpci/virtpci.c
deleted file mode 100644
index d5ad01783..000000000
--- a/drivers/staging/unisys/virtpci/virtpci.c
+++ /dev/null
@@ -1,1394 +0,0 @@
-/* virtpci.c
- *
- * Copyright (C) 2010 - 2013 UNISYS CORPORATION
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
- * NON INFRINGEMENT. See the GNU General Public License for more
- * details.
- */
-
-#define EXPORT_SYMTAB
-
-#include <linux/kernel.h>
-#ifdef CONFIG_MODVERSIONS
-#include <config/modversions.h>
-#endif
-#include "diagnostics/appos_subsystems.h"
-#include "uisutils.h"
-#include "vbuschannel.h"
-#include "vbushelper.h"
-#include <linux/types.h>
-#include <linux/io.h>
-#include <linux/uuid.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/device.h>
-#include <linux/list.h>
-#include <linux/slab.h>
-#include <linux/mod_devicetable.h>
-#include <linux/if_ether.h>
-#include <linux/version.h>
-#include <linux/debugfs.h>
-#include "version.h"
-#include "guestlinuxdebug.h"
-#include "timskmod.h"
-
-struct driver_private {
- struct kobject kobj;
- struct klist klist_devices;
- struct klist_node knode_bus;
- struct module_kobject *mkobj;
- struct device_driver *driver;
-};
-
-#define to_driver(obj) container_of(obj, struct driver_private, kobj)
-
-/* bus_id went away in 2.6.30 - the size was 20 bytes, so we'll define
- * it ourselves, and a macro to make getting the field a bit simpler.
- */
-#ifndef BUS_ID_SIZE
-#define BUS_ID_SIZE 20
-#endif
-
-#define BUS_ID(x) dev_name(x)
-
-/* MAX_BUF = 4 busses x ( 32 devices/bus + 1 busline) x 80 characters
- * = 10,560 bytes ~ 2^14 = 16,384 bytes
- */
-#define MAX_BUF 16384
-
-#include "virtpci.h"
-
-/* this is shorter than using __FILE__ (full path name) in
- * debug/info/error messages
- */
-#define CURRENT_FILE_PC VIRT_PCI_PC_virtpci_c
-#define __MYFILE__ "virtpci.c"
-
-#define VIRTPCI_VERSION "01.00"
-
-/*****************************************************/
-/* Forward declarations */
-/*****************************************************/
-
-static int delete_vbus_device(struct device *vbus, void *data);
-static int match_busid(struct device *dev, void *data);
-static void virtpci_bus_release(struct device *dev);
-static void virtpci_device_release(struct device *dev);
-static int virtpci_device_add(struct device *parentbus, int devtype,
- struct add_virt_guestpart *addparams,
- struct scsi_adap_info *scsi,
- struct net_adap_info *net);
-static int virtpci_device_del(struct device *parentbus, int devtype,
- struct vhba_wwnn *wwnn, unsigned char macaddr[]);
-static int virtpci_device_serverdown(struct device *parentbus, int devtype,
- struct vhba_wwnn *wwnn,
- unsigned char macaddr[]);
-static int virtpci_device_serverup(struct device *parentbus, int devtype,
- struct vhba_wwnn *wwnn,
- unsigned char macaddr[]);
-static ssize_t virtpci_driver_attr_show(struct kobject *kobj,
- struct attribute *attr, char *buf);
-static ssize_t virtpci_driver_attr_store(struct kobject *kobj,
- struct attribute *attr,
- const char *buf, size_t count);
-static int virtpci_bus_match(struct device *dev, struct device_driver *drv);
-static int virtpci_uevent(struct device *dev, struct kobj_uevent_env *env);
-static int virtpci_device_probe(struct device *dev);
-static int virtpci_device_remove(struct device *dev);
-
-static ssize_t info_debugfs_read(struct file *file, char __user *buf,
- size_t len, loff_t *offset);
-
-static const struct file_operations debugfs_info_fops = {
- .read = info_debugfs_read,
-};
-
-/*****************************************************/
-/* Globals */
-/*****************************************************/
-
-/* methods in bus_type struct allow the bus code to serve as an
- * intermediary between the device core and individual device core and
- * individual drivers
- */
-static struct bus_type virtpci_bus_type = {
- .name = "uisvirtpci",
- .match = virtpci_bus_match,
- .uevent = virtpci_uevent,
-};
-
-static struct device virtpci_rootbus_device = {
- .init_name = "vbusroot", /* root bus */
- .release = virtpci_bus_release
-};
-
-/* filled in with info about parent chipset driver when we register with it */
-static struct ultra_vbus_deviceinfo chipset_driver_info;
-
-static const struct sysfs_ops virtpci_driver_sysfs_ops = {
- .show = virtpci_driver_attr_show,
- .store = virtpci_driver_attr_store,
-};
-
-static struct kobj_type virtpci_driver_kobj_type = {
- .sysfs_ops = &virtpci_driver_sysfs_ops,
-};
-
-static struct virtpci_dev *vpcidev_list_head;
-static DEFINE_RWLOCK(vpcidev_list_lock);
-
-/* filled in with info about this driver, wrt it servicing client busses */
-static struct ultra_vbus_deviceinfo bus_driver_info;
-
-/*****************************************************/
-/* debugfs entries */
-/*****************************************************/
-/* dentry is used to create the debugfs entry directory
- * for virtpci
- */
-static struct dentry *virtpci_debugfs_dir;
-
-struct virtpci_busdev {
- struct device virtpci_bus_device;
-};
-
-/*****************************************************/
-/* Local functions */
-/*****************************************************/
-
-static inline
-int WAIT_FOR_IO_CHANNEL(struct spar_io_channel_protocol __iomem *chanptr)
-{
- int count = 120;
-
- while (count > 0) {
- if (SPAR_CHANNEL_SERVER_READY(&chanptr->channel_header))
- return 1;
- UIS_THREAD_WAIT_SEC(1);
- count--;
- }
- return 0;
-}
-
-/* Write the contents of <info> to the ULTRA_VBUS_CHANNEL_PROTOCOL.ChpInfo. */
-static int write_vbus_chp_info(struct spar_vbus_channel_protocol *chan,
- struct ultra_vbus_deviceinfo *info)
-{
- int off;
-
- if (!chan)
- return -1;
-
- off = sizeof(struct channel_header) + chan->hdr_info.chp_info_offset;
- if (chan->hdr_info.chp_info_offset == 0) {
- return -1;
- }
- memcpy(((u8 *)(chan)) + off, info, sizeof(*info));
- return 0;
-}
-
-/* Write the contents of <info> to the ULTRA_VBUS_CHANNEL_PROTOCOL.BusInfo. */
-static int write_vbus_bus_info(struct spar_vbus_channel_protocol *chan,
- struct ultra_vbus_deviceinfo *info)
-{
- int off;
-
- if (!chan)
- return -1;
-
- off = sizeof(struct channel_header) + chan->hdr_info.bus_info_offset;
- if (chan->hdr_info.bus_info_offset == 0)
- return -1;
- memcpy(((u8 *)(chan)) + off, info, sizeof(*info));
- return 0;
-}
-
-/* Write the contents of <info> to the
- * ULTRA_VBUS_CHANNEL_PROTOCOL.DevInfo[<devix>].
- */
-static int
-write_vbus_dev_info(struct spar_vbus_channel_protocol *chan,
- struct ultra_vbus_deviceinfo *info, int devix)
-{
- int off;
-
- if (!chan)
- return -1;
-
- off =
- (sizeof(struct channel_header) +
- chan->hdr_info.dev_info_offset) +
- (chan->hdr_info.device_info_struct_bytes * devix);
- if (chan->hdr_info.dev_info_offset == 0)
- return -1;
-
- memcpy(((u8 *)(chan)) + off, info, sizeof(*info));
- return 0;
-}
-
-/* adds a vbus
- * returns 0 failure, 1 success,
- */
-static int add_vbus(struct add_vbus_guestpart *addparams)
-{
- int ret;
- struct device *vbus;
-
- vbus = kzalloc(sizeof(*vbus), GFP_ATOMIC);
-
- POSTCODE_LINUX_2(VPCI_CREATE_ENTRY_PC, POSTCODE_SEVERITY_INFO);
- if (!vbus)
- return 0;
-
- dev_set_name(vbus, "vbus%d", addparams->bus_no);
- vbus->release = virtpci_bus_release;
- vbus->parent = &virtpci_rootbus_device; /* root bus is parent */
- vbus->bus = &virtpci_bus_type; /* bus type */
- vbus->platform_data = (__force void *)addparams->chanptr;
-
- /* register a virt bus device -
- * this bus shows up under /sys/devices with .name value
- * "virtpci%d" any devices added to this bus then show up under
- * /sys/devices/virtpci0
- */
- ret = device_register(vbus);
- if (ret) {
- POSTCODE_LINUX_2(VPCI_CREATE_FAILURE_PC, POSTCODE_SEVERITY_ERR);
- return 0;
- }
- write_vbus_chp_info(vbus->platform_data /* chanptr */,
- &chipset_driver_info);
- write_vbus_bus_info(vbus->platform_data /* chanptr */,
- &bus_driver_info);
- POSTCODE_LINUX_2(VPCI_CREATE_EXIT_PC, POSTCODE_SEVERITY_INFO);
- return 1;
-}
-
-/* for CHANSOCK wwwnn/max are AUTO-GENERATED; for normal channels,
- * wwnn/max are in the channel header.
- */
-#define GET_SCSIADAPINFO_FROM_CHANPTR(chanptr) { \
- memcpy_fromio(&scsi.wwnn, \
- &((struct spar_io_channel_protocol __iomem *) \
- chanptr)->vhba.wwnn, \
- sizeof(struct vhba_wwnn)); \
- memcpy_fromio(&scsi.max, \
- &((struct spar_io_channel_protocol __iomem *) \
- chanptr)->vhba.max, \
- sizeof(struct vhba_config_max)); \
- }
-
-/* adds a vhba
- * returns 0 failure, 1 success,
- */
-static int add_vhba(struct add_virt_guestpart *addparams)
-{
- int i;
- struct scsi_adap_info scsi;
- struct device *vbus;
- unsigned char busid[BUS_ID_SIZE];
-
- POSTCODE_LINUX_2(VPCI_CREATE_ENTRY_PC, POSTCODE_SEVERITY_INFO);
- if (!WAIT_FOR_IO_CHANNEL
- ((struct spar_io_channel_protocol __iomem *)addparams->chanptr)) {
- POSTCODE_LINUX_2(VPCI_CREATE_FAILURE_PC, POSTCODE_SEVERITY_ERR);
- return 0;
- }
-
- GET_SCSIADAPINFO_FROM_CHANPTR(addparams->chanptr);
-
- /* find bus device with the busid that matches match_busid */
- sprintf(busid, "vbus%d", addparams->bus_no);
- vbus = bus_find_device(&virtpci_bus_type, NULL,
- (void *)busid, match_busid);
- if (!vbus)
- return 0;
-
- i = virtpci_device_add(vbus, VIRTHBA_TYPE, addparams, &scsi, NULL);
- if (i) {
- POSTCODE_LINUX_3(VPCI_CREATE_EXIT_PC, i,
- POSTCODE_SEVERITY_INFO);
- }
- return i;
-}
-
-/* for CHANSOCK macaddr is AUTO-GENERATED; for normal channels,
- * macaddr is in the channel header.
- */
-#define GET_NETADAPINFO_FROM_CHANPTR(chanptr) { \
- memcpy_fromio(net.mac_addr, \
- ((struct spar_io_channel_protocol __iomem *) \
- chanptr)->vnic.macaddr, \
- MAX_MACADDR_LEN); \
- net.num_rcv_bufs = \
- readl(&((struct spar_io_channel_protocol __iomem *)\
- chanptr)->vnic.num_rcv_bufs); \
- net.mtu = readl(&((struct spar_io_channel_protocol __iomem *) \
- chanptr)->vnic.mtu); \
- memcpy_fromio(&net.zone_uuid, \
- &((struct spar_io_channel_protocol __iomem *)\
- chanptr)->vnic.zone_uuid, \
- sizeof(uuid_le)); \
-}
-
-/* adds a vnic
- * returns 0 failure, 1 success,
- */
-static int
-add_vnic(struct add_virt_guestpart *addparams)
-{
- int i;
- struct net_adap_info net;
- struct device *vbus;
- unsigned char busid[BUS_ID_SIZE];
-
- POSTCODE_LINUX_2(VPCI_CREATE_ENTRY_PC, POSTCODE_SEVERITY_INFO);
- if (!WAIT_FOR_IO_CHANNEL
- ((struct spar_io_channel_protocol __iomem *)addparams->chanptr)) {
- POSTCODE_LINUX_2(VPCI_CREATE_FAILURE_PC, POSTCODE_SEVERITY_ERR);
- return 0;
- }
-
- GET_NETADAPINFO_FROM_CHANPTR(addparams->chanptr);
-
- /* find bus device with the busid that matches match_busid */
- sprintf(busid, "vbus%d", addparams->bus_no);
- vbus = bus_find_device(&virtpci_bus_type, NULL,
- (void *)busid, match_busid);
- if (!vbus)
- return 0;
-
- i = virtpci_device_add(vbus, VIRTNIC_TYPE, addparams, NULL, &net);
- if (i) {
- POSTCODE_LINUX_3(VPCI_CREATE_EXIT_PC, i,
- POSTCODE_SEVERITY_INFO);
- return 1;
- }
- return 0;
-}
-
-/* delete vbus
- * returns 0 failure, 1 success,
- */
-static int
-delete_vbus(struct del_vbus_guestpart *delparams)
-{
- struct device *vbus;
- unsigned char busid[BUS_ID_SIZE];
-
- /* find bus device with the busid that matches match_busid */
- sprintf(busid, "vbus%d", delparams->bus_no);
- vbus = bus_find_device(&virtpci_bus_type, NULL,
- (void *)busid, match_busid);
- if (!vbus)
- return 0;
-
- /* ensure that bus has no devices? -- TBD */
- return 1;
-}
-
-static int
-delete_vbus_device(struct device *vbus, void *data)
-{
- struct device *dev = &virtpci_rootbus_device;
-
- if ((data) && match_busid(vbus, (void *)BUS_ID(dev))) {
- /* skip it - don't delete root bus */
- return 0; /* pretend no error */
- }
- device_unregister(vbus);
- kfree(vbus);
- return 0; /* no error */
-}
-
-/* pause vhba
-* returns 0 failure, 1 success,
-*/
-static int pause_vhba(struct pause_virt_guestpart *pauseparams)
-{
- int i;
- struct scsi_adap_info scsi;
-
- GET_SCSIADAPINFO_FROM_CHANPTR(pauseparams->chanptr);
-
- i = virtpci_device_serverdown(NULL /*no parent bus */, VIRTHBA_TYPE,
- &scsi.wwnn, NULL);
- return i;
-}
-
-/* pause vnic
- * returns 0 failure, 1 success,
- */
-static int pause_vnic(struct pause_virt_guestpart *pauseparams)
-{
- int i;
- struct net_adap_info net;
-
- GET_NETADAPINFO_FROM_CHANPTR(pauseparams->chanptr);
-
- i = virtpci_device_serverdown(NULL /*no parent bus */, VIRTNIC_TYPE,
- NULL, net.mac_addr);
- return i;
-}
-
-/* resume vhba
- * returns 0 failure, 1 success,
- */
-static int resume_vhba(struct resume_virt_guestpart *resumeparams)
-{
- int i;
- struct scsi_adap_info scsi;
-
- GET_SCSIADAPINFO_FROM_CHANPTR(resumeparams->chanptr);
-
- i = virtpci_device_serverup(NULL /*no parent bus */, VIRTHBA_TYPE,
- &scsi.wwnn, NULL);
- return i;
-}
-
-/* resume vnic
-* returns 0 failure, 1 success,
-*/
-static int
-resume_vnic(struct resume_virt_guestpart *resumeparams)
-{
- int i;
- struct net_adap_info net;
-
- GET_NETADAPINFO_FROM_CHANPTR(resumeparams->chanptr);
-
- i = virtpci_device_serverup(NULL /*no parent bus */, VIRTNIC_TYPE,
- NULL, net.mac_addr);
- return i;
-}
-
-/* delete vhba
-* returns 0 failure, 1 success,
-*/
-static int delete_vhba(struct del_virt_guestpart *delparams)
-{
- int i;
- struct scsi_adap_info scsi;
-
- GET_SCSIADAPINFO_FROM_CHANPTR(delparams->chanptr);
-
- i = virtpci_device_del(NULL /*no parent bus */, VIRTHBA_TYPE,
- &scsi.wwnn, NULL);
- if (i) {
- return 1;
- }
- return 0;
-}
-
-/* deletes a vnic
- * returns 0 failure, 1 success,
- */
-static int delete_vnic(struct del_virt_guestpart *delparams)
-{
- int i;
- struct net_adap_info net;
-
- GET_NETADAPINFO_FROM_CHANPTR(delparams->chanptr);
-
- i = virtpci_device_del(NULL /*no parent bus */, VIRTNIC_TYPE, NULL,
- net.mac_addr);
- return i;
-}
-
-#define DELETE_ONE_VPCIDEV(vpcidev) { \
- device_unregister(&vpcidev->generic_dev); \
- kfree(vpcidev); \
-}
-
-/* deletes all vhbas and vnics
- * returns 0 failure, 1 success,
- */
-static void delete_all(void)
-{
- int count = 0;
- unsigned long flags;
- struct virtpci_dev *tmpvpcidev, *nextvpcidev;
-
- /* delete the entire vhba/vnic list in one shot */
- write_lock_irqsave(&vpcidev_list_lock, flags);
- tmpvpcidev = vpcidev_list_head;
- vpcidev_list_head = NULL;
- write_unlock_irqrestore(&vpcidev_list_lock, flags);
-
- /* delete one vhba/vnic at a time */
- while (tmpvpcidev) {
- nextvpcidev = tmpvpcidev->next;
- /* delete the vhba/vnic at tmpvpcidev */
- DELETE_ONE_VPCIDEV(tmpvpcidev);
- tmpvpcidev = nextvpcidev;
- count++;
- }
-
- /* now delete each vbus */
- bus_for_each_dev(&virtpci_bus_type, NULL, (void *)1,
- delete_vbus_device);
-}
-
-/* deletes all vnics or vhbas
- * returns 0 failure, 1 success,
- */
-static int delete_all_virt(enum virtpci_dev_type devtype,
- struct del_vbus_guestpart *delparams)
-{
- int i;
- unsigned char busid[BUS_ID_SIZE];
- struct device *vbus;
-
- /* find bus device with the busid that matches match_busid */
- sprintf(busid, "vbus%d", delparams->bus_no);
- vbus = bus_find_device(&virtpci_bus_type, NULL,
- (void *)busid, match_busid);
- if (!vbus)
- return 0;
-
- if ((devtype != VIRTHBA_TYPE) && (devtype != VIRTNIC_TYPE))
- return 0;
-
- /* delete all vhbas/vnics */
- i = virtpci_device_del(vbus, devtype, NULL, NULL);
- return 1;
-}
-
-static int virtpci_ctrlchan_func(struct guest_msgs *msg)
-{
- switch (msg->msgtype) {
- case GUEST_ADD_VBUS:
- return add_vbus(&msg->add_vbus);
- case GUEST_ADD_VHBA:
- return add_vhba(&msg->add_vhba);
- case GUEST_ADD_VNIC:
- return add_vnic(&msg->add_vnic);
- case GUEST_DEL_VBUS:
- return delete_vbus(&msg->del_vbus);
- case GUEST_DEL_VHBA:
- return delete_vhba(&msg->del_vhba);
- case GUEST_DEL_VNIC:
- return delete_vnic(&msg->del_vhba);
- case GUEST_DEL_ALL_VHBAS:
- return delete_all_virt(VIRTHBA_TYPE, &msg->del_all_vhbas);
- case GUEST_DEL_ALL_VNICS:
- return delete_all_virt(VIRTNIC_TYPE, &msg->del_all_vnics);
- case GUEST_DEL_ALL_VBUSES:
- delete_all();
- return 1;
- case GUEST_PAUSE_VHBA:
- return pause_vhba(&msg->pause_vhba);
- case GUEST_PAUSE_VNIC:
- return pause_vnic(&msg->pause_vnic);
- case GUEST_RESUME_VHBA:
- return resume_vhba(&msg->resume_vhba);
- case GUEST_RESUME_VNIC:
- return resume_vnic(&msg->resume_vnic);
- default:
- return 0;
- }
-}
-
-/* same as driver_helper in bus.c linux */
-static int match_busid(struct device *dev, void *data)
-{
- const char *name = data;
-
- if (strcmp(name, BUS_ID(dev)) == 0)
- return 1;
- return 0;
-}
-
-/*****************************************************/
-/* Bus functions */
-/*****************************************************/
-
-static const struct pci_device_id *
-virtpci_match_device(const struct pci_device_id *ids,
- const struct virtpci_dev *dev)
-{
- while (ids->vendor || ids->subvendor || ids->class_mask) {
- if ((ids->vendor == dev->vendor) &&
- (ids->device == dev->device))
- return ids;
-
- ids++;
- }
- return NULL;
-}
-
-/* NOTE: !!!!!! This function is called when a new device is added
-* for this bus. Or, it is called for existing devices when a new
-* driver is added for this bus. It returns nonzero if a given device
-* can be handled by the given driver.
-*/
-static int virtpci_bus_match(struct device *dev, struct device_driver *drv)
-{
- struct virtpci_dev *virtpcidev = device_to_virtpci_dev(dev);
- struct virtpci_driver *virtpcidrv = driver_to_virtpci_driver(drv);
- int match = 0;
-
- /* check ids list for a match */
- if (virtpci_match_device(virtpcidrv->id_table, virtpcidev))
- match = 1;
-
- return match; /* 0 - no match; 1 - yes it matches */
-}
-
-static int virtpci_uevent(struct device *dev, struct kobj_uevent_env *env)
-{
- /* add variables to the environment prior to the generation of
- * hotplug events to user space
- */
- if (add_uevent_var(env, "VIRTPCI_VERSION=%s", VIRTPCI_VERSION))
- return -ENOMEM;
- return 0;
-}
-
-/* For a child device just created on a client bus, fill in
- * information about the driver that is controlling this device into
- * the appropriate slot within the vbus channel of the bus
- * instance.
- */
-static void fix_vbus_dev_info(struct device *dev, int dev_no, int dev_type,
- struct virtpci_driver *virtpcidrv)
-{
- struct device *vbus;
- void *chan;
- struct ultra_vbus_deviceinfo dev_info;
- const char *stype;
-
- if (!dev)
- return;
- if (!virtpcidrv)
- return;
-
- vbus = dev->parent;
- if (!vbus)
- return;
-
- chan = vbus->platform_data;
- if (!chan)
- return;
-
- switch (dev_type) {
- case PCI_DEVICE_ID_VIRTHBA:
- stype = "vHBA";
- break;
- case PCI_DEVICE_ID_VIRTNIC:
- stype = "vNIC";
- break;
- default:
- stype = "unknown";
- break;
- }
- bus_device_info_init(&dev_info, stype,
- virtpcidrv->name,
- virtpcidrv->version,
- virtpcidrv->vertag);
- write_vbus_dev_info(chan, &dev_info, dev_no);
-
- /* Re-write bus+chipset info, because it is possible that this
- * was previously written by our good counterpart, visorbus.
- */
- write_vbus_chp_info(chan, &chipset_driver_info);
- write_vbus_bus_info(chan, &bus_driver_info);
-}
-
-/* This function is called to query the existence of a specific device
-* and whether this driver can work with it. It should return -ENODEV
-* in case of failure.
-*/
-static int virtpci_device_probe(struct device *dev)
-{
- struct virtpci_dev *virtpcidev = device_to_virtpci_dev(dev);
- struct virtpci_driver *virtpcidrv =
- driver_to_virtpci_driver(dev->driver);
- const struct pci_device_id *id;
- int error = 0;
-
- POSTCODE_LINUX_2(VPCI_PROBE_ENTRY_PC, POSTCODE_SEVERITY_INFO);
- /* static match and static probe vs dynamic match & dynamic
- * probe - do we care?.
- */
- if (!virtpcidrv->id_table)
- return -ENODEV;
-
- id = virtpci_match_device(virtpcidrv->id_table, virtpcidev);
- if (!id)
- return -ENODEV;
-
- /* increment reference count */
- get_device(dev);
-
- /* if virtpcidev is not already claimed & probe function is
- * valid, probe it
- */
- if (!virtpcidev->mydriver && virtpcidrv->probe) {
- /* call the probe function - virthba or virtnic probe
- * is what it should be
- */
- error = virtpcidrv->probe(virtpcidev, id);
- if (!error) {
- fix_vbus_dev_info(dev, virtpcidev->device_no,
- virtpcidev->device, virtpcidrv);
- virtpcidev->mydriver = virtpcidrv;
- POSTCODE_LINUX_2(VPCI_PROBE_EXIT_PC,
- POSTCODE_SEVERITY_INFO);
- } else {
- put_device(dev);
- }
- }
- POSTCODE_LINUX_2(VPCI_PROBE_FAILURE_PC, POSTCODE_SEVERITY_ERR);
- return error; /* -ENODEV for probe failure */
-}
-
-static int virtpci_device_remove(struct device *dev_)
-{
- /* dev_ passed in is the HBA device which we called
- * generic_dev in our virtpcidev struct
- */
- struct virtpci_dev *virtpcidev = device_to_virtpci_dev(dev_);
- struct virtpci_driver *virtpcidrv = virtpcidev->mydriver;
-
- if (virtpcidrv) {
- /* TEMP: assuming we have only one such driver for now */
- if (virtpcidrv->remove)
- virtpcidrv->remove(virtpcidev);
- virtpcidev->mydriver = NULL;
- }
-
- put_device(dev_);
- return 0;
-}
-
-/*****************************************************/
-/* Bus functions */
-/*****************************************************/
-
-static void virtpci_bus_release(struct device *dev)
-{
-}
-
-/*****************************************************/
-/* Adapter functions */
-/*****************************************************/
-
-/* scsi is expected to be NULL for VNIC add
- * net is expected to be NULL for VHBA add
- */
-static int virtpci_device_add(struct device *parentbus, int devtype,
- struct add_virt_guestpart *addparams,
- struct scsi_adap_info *scsi,
- struct net_adap_info *net)
-{
- struct virtpci_dev *virtpcidev = NULL;
- struct virtpci_dev *tmpvpcidev = NULL, *prev;
- unsigned long flags;
- int ret;
- struct spar_io_channel_protocol __iomem *io_chan = NULL;
- struct device *dev;
-
- POSTCODE_LINUX_2(VPCI_CREATE_ENTRY_PC, POSTCODE_SEVERITY_INFO);
-
- if ((devtype != VIRTHBA_TYPE) && (devtype != VIRTNIC_TYPE)) {
- POSTCODE_LINUX_3(VPCI_CREATE_FAILURE_PC, devtype,
- POSTCODE_SEVERITY_ERR);
- return 0;
- }
-
- /* add a Virtual Device */
- virtpcidev = kzalloc(sizeof(*virtpcidev), GFP_ATOMIC);
- if (!virtpcidev) {
- POSTCODE_LINUX_2(MALLOC_FAILURE_PC, POSTCODE_SEVERITY_ERR);
- return 0;
- }
-
- /* initialize stuff unique to virtpci_dev struct */
- virtpcidev->devtype = devtype;
- if (devtype == VIRTHBA_TYPE) {
- virtpcidev->device = PCI_DEVICE_ID_VIRTHBA;
- virtpcidev->scsi = *scsi;
- } else {
- virtpcidev->device = PCI_DEVICE_ID_VIRTNIC;
- virtpcidev->net = *net;
- }
- virtpcidev->vendor = PCI_VENDOR_ID_UNISYS;
- virtpcidev->bus_no = addparams->bus_no;
- virtpcidev->device_no = addparams->device_no;
-
- virtpcidev->queueinfo.chan = addparams->chanptr;
- virtpcidev->queueinfo.send_int_if_needed = NULL;
-
- /* Set up safe queue... */
- io_chan = (struct spar_io_channel_protocol __iomem *)
- virtpcidev->queueinfo.chan;
-
- virtpcidev->intr = addparams->intr;
-
- /* initialize stuff in the device portion of the struct */
- virtpcidev->generic_dev.bus = &virtpci_bus_type;
- virtpcidev->generic_dev.parent = parentbus;
- virtpcidev->generic_dev.release = virtpci_device_release;
-
- dev_set_name(&virtpcidev->generic_dev, "%x:%x",
- addparams->bus_no, addparams->device_no);
-
- /* add the vhba/vnic to virtpci device list - but check for
- * duplicate wwnn/macaddr first
- */
- write_lock_irqsave(&vpcidev_list_lock, flags);
- for (tmpvpcidev = vpcidev_list_head; tmpvpcidev;
- tmpvpcidev = tmpvpcidev->next) {
- if (devtype == VIRTHBA_TYPE) {
- if ((tmpvpcidev->scsi.wwnn.wwnn1 == scsi->wwnn.wwnn1) &&
- (tmpvpcidev->scsi.wwnn.wwnn2 == scsi->wwnn.wwnn2)) {
- /* duplicate - already have vpcidev
- with this wwnn */
- break;
- }
- } else
- if (memcmp
- (tmpvpcidev->net.mac_addr, net->mac_addr,
- MAX_MACADDR_LEN) == 0) {
- /* duplicate - already have vnic with this wwnn */
- break;
- }
- }
- if (tmpvpcidev) {
- /* found a vhba/vnic already in the list with same
- * wwnn or macaddr - reject add
- */
- write_unlock_irqrestore(&vpcidev_list_lock, flags);
- kfree(virtpcidev);
- POSTCODE_LINUX_2(VPCI_CREATE_FAILURE_PC, POSTCODE_SEVERITY_ERR);
- return 0;
- }
-
- /* add it at the head */
- if (!vpcidev_list_head) {
- vpcidev_list_head = virtpcidev;
- } else {
- /* insert virtpcidev at the head of our linked list of
- * vpcidevs
- */
- virtpcidev->next = vpcidev_list_head;
- vpcidev_list_head = virtpcidev;
- }
-
- write_unlock_irqrestore(&vpcidev_list_lock, flags);
-
- /* Must transition channel to ATTACHED state BEFORE
- * registering the device, because polling of the channel
- * queues can begin at any time after device_register().
- */
- dev = &virtpcidev->generic_dev;
- SPAR_CHANNEL_CLIENT_TRANSITION(addparams->chanptr,
- BUS_ID(dev),
- CHANNELCLI_ATTACHED, NULL);
-
- /* don't register until device has been added to
- * list. Otherwise, a device_unregister from this function can
- * cause a "scheduling while atomic".
- */
- ret = device_register(&virtpcidev->generic_dev);
- /* NOTE: THIS IS CALLING HOTPLUG virtpci_hotplug!!!
- * This call to device_register results in virtpci_bus_match
- * being called !!!!! And, if match returns success, then
- * virtpcidev->generic_dev.driver is setup to core_driver,
- * i.e., virtpci and the probe function
- * virtpcidev->generic_dev.driver->probe is called which
- * results in virtpci_device_probe being called. And if
- * virtpci_device_probe is successful
- */
- if (ret) {
- dev = &virtpcidev->generic_dev;
- SPAR_CHANNEL_CLIENT_TRANSITION(addparams->chanptr,
- BUS_ID(dev),
- CHANNELCLI_DETACHED, NULL);
- /* remove virtpcidev, the one we just added, from the list */
- write_lock_irqsave(&vpcidev_list_lock, flags);
- for (tmpvpcidev = vpcidev_list_head, prev = NULL;
- tmpvpcidev;
- prev = tmpvpcidev, tmpvpcidev = tmpvpcidev->next) {
- if (tmpvpcidev == virtpcidev) {
- if (prev)
- prev->next = tmpvpcidev->next;
- else
- vpcidev_list_head = tmpvpcidev->next;
- break;
- }
- }
- write_unlock_irqrestore(&vpcidev_list_lock, flags);
- kfree(virtpcidev);
- return 0;
- }
-
- POSTCODE_LINUX_2(VPCI_CREATE_EXIT_PC, POSTCODE_SEVERITY_INFO);
- return 1;
-}
-
-static int virtpci_device_serverdown(struct device *parentbus,
- int devtype,
- struct vhba_wwnn *wwnn,
- unsigned char macaddr[])
-{
- int pausethisone = 0;
- bool found = false;
- struct virtpci_dev *tmpvpcidev, *prevvpcidev;
- struct virtpci_driver *vpcidriver;
- unsigned long flags;
- int rc = 0;
-
- if ((devtype != VIRTHBA_TYPE) && (devtype != VIRTNIC_TYPE))
- return 0;
-
- /* find the vhba or vnic in virtpci device list */
- write_lock_irqsave(&vpcidev_list_lock, flags);
-
- for (tmpvpcidev = vpcidev_list_head, prevvpcidev = NULL;
- (tmpvpcidev && !found);
- prevvpcidev = tmpvpcidev, tmpvpcidev = tmpvpcidev->next) {
- if (tmpvpcidev->devtype != devtype)
- continue;
-
- if (devtype == VIRTHBA_TYPE) {
- pausethisone =
- ((tmpvpcidev->scsi.wwnn.wwnn1 == wwnn->wwnn1) &&
- (tmpvpcidev->scsi.wwnn.wwnn2 == wwnn->wwnn2));
- /* devtype is vhba, we're pausing vhba whose
- * wwnn matches the current device's wwnn
- */
- } else { /* VIRTNIC_TYPE */
- pausethisone =
- memcmp(tmpvpcidev->net.mac_addr, macaddr,
- MAX_MACADDR_LEN) == 0;
- /* devtype is vnic, we're pausing vnic whose
- * macaddr matches the current device's macaddr */
- }
-
- if (!pausethisone)
- continue;
-
- found = true;
- vpcidriver = tmpvpcidev->mydriver;
- rc = vpcidriver->suspend(tmpvpcidev, 0);
- }
- write_unlock_irqrestore(&vpcidev_list_lock, flags);
-
- if (!found)
- return 0;
-
- return rc;
-}
-
-static int virtpci_device_serverup(struct device *parentbus,
- int devtype,
- struct vhba_wwnn *wwnn,
- unsigned char macaddr[])
-{
- int resumethisone = 0;
- bool found = false;
- struct virtpci_dev *tmpvpcidev, *prevvpcidev;
- struct virtpci_driver *vpcidriver;
- unsigned long flags;
- int rc = 0;
-
- if ((devtype != VIRTHBA_TYPE) && (devtype != VIRTNIC_TYPE))
- return 0;
-
-
- /* find the vhba or vnic in virtpci device list */
- write_lock_irqsave(&vpcidev_list_lock, flags);
-
- for (tmpvpcidev = vpcidev_list_head, prevvpcidev = NULL;
- (tmpvpcidev && !found);
- prevvpcidev = tmpvpcidev, tmpvpcidev = tmpvpcidev->next) {
- if (tmpvpcidev->devtype != devtype)
- continue;
-
- if (devtype == VIRTHBA_TYPE) {
- resumethisone =
- ((tmpvpcidev->scsi.wwnn.wwnn1 == wwnn->wwnn1) &&
- (tmpvpcidev->scsi.wwnn.wwnn2 == wwnn->wwnn2));
- /* devtype is vhba, we're resuming vhba whose
- * wwnn matches the current device's wwnn */
- } else { /* VIRTNIC_TYPE */
- resumethisone =
- memcmp(tmpvpcidev->net.mac_addr, macaddr,
- MAX_MACADDR_LEN) == 0;
- /* devtype is vnic, we're resuming vnic whose
- * macaddr matches the current device's macaddr */
- }
-
- if (!resumethisone)
- continue;
-
- found = true;
- vpcidriver = tmpvpcidev->mydriver;
- /* This should be done at BUS resume time, but an
- * existing problem prevents us from ever getting a bus
- * resume... This hack would fail to work should we
- * ever have a bus that contains NO devices, since we
- * would never even get here in that case.
- */
- fix_vbus_dev_info(&tmpvpcidev->generic_dev,
- tmpvpcidev->device_no,
- tmpvpcidev->device, vpcidriver);
- rc = vpcidriver->resume(tmpvpcidev);
- }
-
- write_unlock_irqrestore(&vpcidev_list_lock, flags);
-
- if (!found)
- return 0;
-
- return rc;
-}
-
-static int virtpci_device_del(struct device *parentbus,
- int devtype, struct vhba_wwnn *wwnn,
- unsigned char macaddr[])
-{
- int count = 0, all = 0, delthisone;
- struct virtpci_dev *tmpvpcidev, *prevvpcidev, *dellist = NULL;
- unsigned long flags;
-
-#define DEL_CONTINUE { \
- prevvpcidev = tmpvpcidev;\
- tmpvpcidev = tmpvpcidev->next;\
- continue; \
-}
-
- if ((devtype != VIRTHBA_TYPE) && (devtype != VIRTNIC_TYPE))
- return 0;
-
- /* see if we are to delete all - NOTE: all implies we have a
- * valid parentbus
- */
- all = ((devtype == VIRTHBA_TYPE) && (!wwnn)) ||
- ((devtype == VIRTNIC_TYPE) && (!macaddr));
-
- /* find all the vhba or vnic or both in virtpci device list
- * keep list of ones we are deleting so we can call
- * device_unregister after we release the lock; otherwise we
- * encounter "schedule while atomic"
- */
- write_lock_irqsave(&vpcidev_list_lock, flags);
- for (tmpvpcidev = vpcidev_list_head, prevvpcidev = NULL; tmpvpcidev;) {
- if (tmpvpcidev->devtype != devtype)
- DEL_CONTINUE;
-
- if (all) {
- delthisone =
- (tmpvpcidev->generic_dev.parent == parentbus);
- /* we're deleting all vhbas or vnics on the
- * specified parent bus
- */
- } else if (devtype == VIRTHBA_TYPE) {
- delthisone =
- ((tmpvpcidev->scsi.wwnn.wwnn1 == wwnn->wwnn1) &&
- (tmpvpcidev->scsi.wwnn.wwnn2 == wwnn->wwnn2));
- /* devtype is vhba, we're deleting vhba whose
- * wwnn matches the current device's wwnn
- */
- } else { /* VIRTNIC_TYPE */
- delthisone =
- memcmp(tmpvpcidev->net.mac_addr, macaddr,
- MAX_MACADDR_LEN) == 0;
- /* devtype is vnic, we're deleting vnic whose
- * macaddr matches the current device's macaddr
- */
- }
-
- if (!delthisone)
- DEL_CONTINUE;
-
- /* take vhba/vnic out of the list */
- if (prevvpcidev)
- /* not at head */
- prevvpcidev->next = tmpvpcidev->next;
- else
- vpcidev_list_head = tmpvpcidev->next;
-
- /* add it to our deletelist */
- tmpvpcidev->next = dellist;
- dellist = tmpvpcidev;
-
- count++;
- if (!all)
- break; /* done */
- /* going to top of loop again - set tmpvpcidev to next
- * one we're to process
- */
- if (prevvpcidev)
- tmpvpcidev = prevvpcidev->next;
- else
- tmpvpcidev = vpcidev_list_head;
- }
- write_unlock_irqrestore(&vpcidev_list_lock, flags);
-
- if (!all && (count == 0))
- return 0;
-
- /* now delete each one from delete list */
- while (dellist) {
- /* save next */
- tmpvpcidev = dellist->next;
- /* delete the vhba/vnic at dellist */
- DELETE_ONE_VPCIDEV(dellist);
- /* do next */
- dellist = tmpvpcidev;
- }
-
- return count;
-}
-
-static void virtpci_device_release(struct device *dev_)
-{
- /* this function is called when the last reference to the
- * device is removed
- */
-}
-
-/*****************************************************/
-/* Driver functions */
-/*****************************************************/
-
-#define kobj_to_device_driver(obj) container_of(obj, struct device_driver, kobj)
-#define attribute_to_driver_attribute(obj) \
- container_of(obj, struct driver_attribute, attr)
-
-static ssize_t virtpci_driver_attr_show(struct kobject *kobj,
- struct attribute *attr,
- char *buf)
-{
- struct driver_attribute *dattr = attribute_to_driver_attribute(attr);
- ssize_t ret = 0;
-
- struct driver_private *dprivate = to_driver(kobj);
- struct device_driver *driver = dprivate->driver;
-
- if (dattr->show)
- ret = dattr->show(driver, buf);
-
- return ret;
-}
-
-static ssize_t virtpci_driver_attr_store(struct kobject *kobj,
- struct attribute *attr,
- const char *buf, size_t count)
-{
- struct driver_attribute *dattr = attribute_to_driver_attribute(attr);
- ssize_t ret = 0;
-
- struct driver_private *dprivate = to_driver(kobj);
- struct device_driver *driver = dprivate->driver;
-
- if (dattr->store)
- ret = dattr->store(driver, buf, count);
-
- return ret;
-}
-
-/* register a new virtpci driver */
-int virtpci_register_driver(struct virtpci_driver *drv)
-{
- int result = 0;
-
- if (!drv->id_table)
- return 1;
- /* initialize core driver fields needed to call driver_register */
- drv->core_driver.name = drv->name; /* name of driver in sysfs */
- drv->core_driver.bus = &virtpci_bus_type; /* type of bus this
- * driver works with */
- drv->core_driver.probe = virtpci_device_probe; /* called to query the
- * existence of a
- * specific device and
- * whether this driver
- *can work with it */
- drv->core_driver.remove = virtpci_device_remove; /* called when the
- * device is removed
- * from the system */
- /* register with core */
- result = driver_register(&drv->core_driver);
- /* calls bus_add_driver which calls driver_attach and
- * module_add_driver
- */
- if (result)
- return result; /* failed */
-
- drv->core_driver.p->kobj.ktype = &virtpci_driver_kobj_type;
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(virtpci_register_driver);
-
-void virtpci_unregister_driver(struct virtpci_driver *drv)
-{
- driver_unregister(&drv->core_driver);
- /* driver_unregister calls bus_remove_driver
- * bus_remove_driver calls device_detach
- * device_detach calls device_release_driver for each of the
- * driver's devices
- * device_release driver calls drv->remove which is
- * virtpci_device_remove
- * virtpci_device_remove calls virthba_remove
- */
-}
-EXPORT_SYMBOL_GPL(virtpci_unregister_driver);
-
-/*****************************************************/
-/* debugfs filesystem functions */
-/*****************************************************/
-struct print_vbus_info {
- int *str_pos;
- char *buf;
- size_t *len;
-};
-
-static int print_vbus(struct device *vbus, void *data)
-{
- struct print_vbus_info *p = (struct print_vbus_info *)data;
-
- *p->str_pos += scnprintf(p->buf + *p->str_pos, *p->len - *p->str_pos,
- "bus_id:%s\n", dev_name(vbus));
- return 0;
-}
-
-static ssize_t info_debugfs_read(struct file *file, char __user *buf,
- size_t len, loff_t *offset)
-{
- ssize_t bytes_read = 0;
- int str_pos = 0;
- struct virtpci_dev *tmpvpcidev;
- unsigned long flags;
- struct print_vbus_info printparam;
- char *vbuf;
-
- if (len > MAX_BUF)
- len = MAX_BUF;
- vbuf = kzalloc(len, GFP_KERNEL);
- if (!vbuf)
- return -ENOMEM;
-
- str_pos += scnprintf(vbuf + str_pos, len - str_pos,
- " Virtual PCI Bus devices\n");
- printparam.str_pos = &str_pos;
- printparam.buf = vbuf;
- printparam.len = &len;
- bus_for_each_dev(&virtpci_bus_type, NULL, (void *)&printparam,
- print_vbus);
-
- str_pos += scnprintf(vbuf + str_pos, len - str_pos,
- "\n Virtual PCI devices\n");
- read_lock_irqsave(&vpcidev_list_lock, flags);
- tmpvpcidev = vpcidev_list_head;
- while (tmpvpcidev) {
- if (tmpvpcidev->devtype == VIRTHBA_TYPE) {
- str_pos += scnprintf(vbuf + str_pos, len - str_pos,
- "[%d:%d] VHba:%08x:%08x max-config:%d-%d-%d-%d",
- tmpvpcidev->bus_no,
- tmpvpcidev->device_no,
- tmpvpcidev->scsi.wwnn.wwnn1,
- tmpvpcidev->scsi.wwnn.wwnn2,
- tmpvpcidev->scsi.max.max_channel,
- tmpvpcidev->scsi.max.max_id,
- tmpvpcidev->scsi.max.max_lun,
- tmpvpcidev->scsi.max.cmd_per_lun);
- } else {
- str_pos += scnprintf(vbuf + str_pos, len - str_pos,
- "[%d:%d] VNic:%pM num_rcv_bufs:%d mtu:%d",
- tmpvpcidev->bus_no,
- tmpvpcidev->device_no,
- tmpvpcidev->net.mac_addr,
- tmpvpcidev->net.num_rcv_bufs,
- tmpvpcidev->net.mtu);
- }
- str_pos += scnprintf(vbuf + str_pos,
- len - str_pos, " chanptr:%p\n",
- tmpvpcidev->queueinfo.chan);
- tmpvpcidev = tmpvpcidev->next;
- }
- read_unlock_irqrestore(&vpcidev_list_lock, flags);
-
- str_pos += scnprintf(vbuf + str_pos, len - str_pos, "\n");
- bytes_read = simple_read_from_buffer(buf, len, offset, vbuf, str_pos);
- kfree(vbuf);
- return bytes_read;
-}
-
-/*****************************************************/
-/* Module Init & Exit functions */
-/*****************************************************/
-
-static int __init virtpci_mod_init(void)
-{
- int ret;
-
- if (!unisys_spar_platform)
- return -ENODEV;
-
- POSTCODE_LINUX_2(VPCI_CREATE_ENTRY_PC, POSTCODE_SEVERITY_INFO);
-
- ret = bus_register(&virtpci_bus_type);
- /* creates /sys/bus/uisvirtpci which contains devices &
- * drivers directory
- */
- if (ret) {
- POSTCODE_LINUX_3(VPCI_CREATE_FAILURE_PC, ret,
- POSTCODE_SEVERITY_ERR);
- return ret;
- }
- bus_device_info_init(&bus_driver_info, "clientbus", "virtpci",
- VERSION, NULL);
-
- /* create a root bus used to parent all the virtpci buses. */
- ret = device_register(&virtpci_rootbus_device);
- if (ret) {
- bus_unregister(&virtpci_bus_type);
- POSTCODE_LINUX_3(VPCI_CREATE_FAILURE_PC, ret,
- POSTCODE_SEVERITY_ERR);
- return ret;
- }
-
- if (!uisctrl_register_req_handler(2, (void *)&virtpci_ctrlchan_func,
- &chipset_driver_info)) {
- POSTCODE_LINUX_2(VPCI_CREATE_FAILURE_PC, POSTCODE_SEVERITY_ERR);
- device_unregister(&virtpci_rootbus_device);
- bus_unregister(&virtpci_bus_type);
- return -1;
- }
-
- /* create debugfs directory and info file inside. */
- virtpci_debugfs_dir = debugfs_create_dir("virtpci", NULL);
- debugfs_create_file("info", S_IRUSR, virtpci_debugfs_dir,
- NULL, &debugfs_info_fops);
- POSTCODE_LINUX_2(VPCI_CREATE_EXIT_PC, POSTCODE_SEVERITY_INFO);
- return 0;
-}
-
-static void __exit virtpci_mod_exit(void)
-{
- /* unregister the callback function */
- device_unregister(&virtpci_rootbus_device);
- bus_unregister(&virtpci_bus_type);
- debugfs_remove_recursive(virtpci_debugfs_dir);
-}
-
-module_init(virtpci_mod_init);
-module_exit(virtpci_mod_exit);
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Usha Srinivasan");
-MODULE_ALIAS("uisvirtpci");
-
diff --git a/drivers/staging/unisys/virtpci/virtpci.h b/drivers/staging/unisys/virtpci/virtpci.h
deleted file mode 100644
index 9d85f55e8..000000000
--- a/drivers/staging/unisys/virtpci/virtpci.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/* virtpci.h
- *
- * Copyright (C) 2010 - 2013 UNISYS CORPORATION
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
- * NON INFRINGEMENT. See the GNU General Public License for more
- * details.
- */
-
-/*
- * Unisys Virtual PCI driver header
- */
-
-#ifndef __VIRTPCI_H__
-#define __VIRTPCI_H__
-
-#include "uisqueue.h"
-#include <linux/version.h>
-#include <linux/uuid.h>
-
-#define PCI_DEVICE_ID_VIRTHBA 0xAA00
-#define PCI_DEVICE_ID_VIRTNIC 0xAB00
-
-struct scsi_adap_info {
- void *scsihost; /* scsi host if this device is a scsi hba */
- struct vhba_wwnn wwnn; /* the world wide node name of vhba */
- struct vhba_config_max max; /* various max specifications used
- * to config vhba */
-};
-
-struct net_adap_info {
- struct net_device *netdev; /* network device if this
- * device is a NIC */
- u8 mac_addr[MAX_MACADDR_LEN];
- int num_rcv_bufs;
- unsigned mtu;
- uuid_le zone_uuid;
-};
-
-enum virtpci_dev_type {
- VIRTHBA_TYPE = 0,
- VIRTNIC_TYPE = 1,
- VIRTBUS_TYPE = 6,
-};
-
-struct virtpci_dev {
- enum virtpci_dev_type devtype; /* indicates type of the
- * virtual pci device */
- struct virtpci_driver *mydriver; /* which driver has allocated
- * this device */
- unsigned short vendor; /* vendor id for device */
- unsigned short device; /* device id for device */
- u32 bus_no; /* number of bus on which device exists */
- u32 device_no; /* device's number on the bus */
- struct irq_info intr; /* interrupt info */
- struct device generic_dev; /* generic device */
- union {
- struct scsi_adap_info scsi;
- struct net_adap_info net;
- };
-
- struct uisqueue_info queueinfo; /* holds ptr to channel where cmds &
- * rsps are queued & retrieved */
- struct virtpci_dev *next; /* points to next virtpci device */
-};
-
-struct virtpci_driver {
- struct list_head node;
- const char *name; /* the name of the driver in sysfs */
- const char *version;
- const char *vertag;
- const struct pci_device_id *id_table; /* must be non-NULL for probe
- * to be called */
- int (*probe)(struct virtpci_dev *dev,
- const struct pci_device_id *id); /* device inserted */
- void (*remove)(struct virtpci_dev *dev); /* Device removed (NULL if
- * not a hot-plug capable
- * driver) */
- int (*suspend)(struct virtpci_dev *dev,
- u32 state); /* Device suspended */
- int (*resume)(struct virtpci_dev *dev); /* Device woken up */
- int (*enable_wake)(struct virtpci_dev *dev,
- u32 state, int enable); /* Enable wake event */
- struct device_driver core_driver; /* VIRTPCI core fills this in */
-};
-
-#define driver_to_virtpci_driver(in_drv) \
- container_of(in_drv, struct virtpci_driver, core_driver)
-#define device_to_virtpci_dev(in_dev) \
- container_of(in_dev, struct virtpci_dev, generic_dev)
-
-int virtpci_register_driver(struct virtpci_driver *);
-void virtpci_unregister_driver(struct virtpci_driver *);
-
-#endif /* __VIRTPCI_H__ */
diff --git a/drivers/staging/unisys/visorbus/Kconfig b/drivers/staging/unisys/visorbus/Kconfig
new file mode 100644
index 000000000..9b299ac86
--- /dev/null
+++ b/drivers/staging/unisys/visorbus/Kconfig
@@ -0,0 +1,9 @@
+#
+# Unisys visorbus configuration
+#
+
+config UNISYS_VISORBUS
+ tristate "Unisys visorbus driver"
+ depends on UNISYSSPAR
+ ---help---
+ If you say Y here, you will enable the Unisys visorbus driver.
diff --git a/drivers/staging/unisys/visorbus/Makefile b/drivers/staging/unisys/visorbus/Makefile
new file mode 100644
index 000000000..fa27ee5f3
--- /dev/null
+++ b/drivers/staging/unisys/visorbus/Makefile
@@ -0,0 +1,13 @@
+#
+# Makefile for Unisys visorbus
+#
+
+obj-$(CONFIG_UNISYS_VISORBUS) += visorbus.o
+
+visorbus-y := visorbus_main.o
+visorbus-y += visorchannel.o
+visorbus-y += visorchipset.o
+visorbus-y += periodic_work.o
+
+ccflags-y += -Idrivers/staging/unisys/include
+ccflags-y += -Idrivers/staging/unisys/visorutil
diff --git a/drivers/staging/unisys/common-spar/include/channels/controlvmchannel.h b/drivers/staging/unisys/visorbus/controlvmchannel.h
index a66db7968..a50d9cf4b 100644
--- a/drivers/staging/unisys/common-spar/include/channels/controlvmchannel.h
+++ b/drivers/staging/unisys/visorbus/controlvmchannel.h
@@ -18,59 +18,75 @@
#include <linux/uuid.h>
#include "channel.h"
-#include "controlframework.h"
-
-typedef u64 GUEST_PHYSICAL_ADDRESS;
-
-enum { INVALID_GUEST_FIRMWARE, SAMPLE_GUEST_FIRMWARE,
- TIANO32_GUEST_FIRMWARE, TIANO64_GUEST_FIRMWARE
-};
/* {2B3C2D10-7EF5-4ad8-B966-3448B7386B3D} */
#define SPAR_CONTROLVM_CHANNEL_PROTOCOL_UUID \
UUID_LE(0x2b3c2d10, 0x7ef5, 0x4ad8, \
- 0xb9, 0x66, 0x34, 0x48, 0xb7, 0x38, 0x6b, 0x3d)
-
-static const uuid_le spar_controlvm_channel_protocol_uuid =
- SPAR_CONTROLVM_CHANNEL_PROTOCOL_UUID;
+ 0xb9, 0x66, 0x34, 0x48, 0xb7, 0x38, 0x6b, 0x3d)
#define ULTRA_CONTROLVM_CHANNEL_PROTOCOL_SIGNATURE \
ULTRA_CHANNEL_PROTOCOL_SIGNATURE
-#define CONTROLVM_MESSAGE_MAX 64
+#define CONTROLVM_MESSAGE_MAX 64
/* Must increment this whenever you insert or delete fields within
-* this channel struct. Also increment whenever you change the meaning
-* of fields within this channel struct so as to break pre-existing
-* software. Note that you can usually add fields to the END of the
-* channel struct withOUT needing to increment this. */
+ * this channel struct. Also increment whenever you change the meaning
+ * of fields within this channel struct so as to break pre-existing
+ * software. Note that you can usually add fields to the END of the
+ * channel struct withOUT needing to increment this.
+ */
#define ULTRA_CONTROLVM_CHANNEL_PROTOCOL_VERSIONID 1
#define SPAR_CONTROLVM_CHANNEL_OK_CLIENT(ch) \
spar_check_channel_client(ch, \
- spar_controlvm_channel_protocol_uuid, \
+ SPAR_CONTROLVM_CHANNEL_PROTOCOL_UUID, \
"controlvm", \
sizeof(struct spar_controlvm_channel_protocol), \
ULTRA_CONTROLVM_CHANNEL_PROTOCOL_VERSIONID, \
ULTRA_CONTROLVM_CHANNEL_PROTOCOL_SIGNATURE)
-#define MY_DEVICE_INDEX 0
-#define MAX_MACDATA_LEN 8 /* number of bytes for MAC address in config packet */
#define MAX_SERIAL_NUM 32
-#define DISK_ZERO_PUN_NUMBER 1 /* Target ID on the SCSI bus for LUN 0 */
-#define DISK_ZERO_LUN_NUMBER 3 /* Logical Unit Number */
-
-/* Defines for various channel queues... */
+/* Defines for various channel queues */
#define CONTROLVM_QUEUE_REQUEST 0
#define CONTROLVM_QUEUE_RESPONSE 1
-#define CONTROLVM_QUEUE_EVENT 2
+#define CONTROLVM_QUEUE_EVENT 2
#define CONTROLVM_QUEUE_ACK 3
-/* Max number of messages stored during IOVM creation to be reused
- * after crash */
+/* Max num of messages stored during IOVM creation to be reused after crash */
#define CONTROLVM_CRASHMSG_MAX 2
-/** Ids for commands that may appear in either queue of a ControlVm channel.
+struct spar_segment_state {
+ u16 enabled:1; /* Bit 0: May enter other states */
+ u16 active:1; /* Bit 1: Assigned to active partition */
+ u16 alive:1; /* Bit 2: Configure message sent to
+ * service/server */
+ u16 revoked:1; /* Bit 3: similar to partition state
+ * ShuttingDown */
+ u16 allocated:1; /* Bit 4: memory (device/port number)
+ * has been selected by Command */
+ u16 known:1; /* Bit 5: has been introduced to the
+ * service/guest partition */
+ u16 ready:1; /* Bit 6: service/Guest partition has
+ * responded to introduction */
+ u16 operating:1; /* Bit 7: resource is configured and
+ * operating */
+ /* Note: don't use high bit unless we need to switch to ushort
+ * which is non-compliant */
+};
+
+static const struct spar_segment_state segment_state_running = {
+ 1, 1, 1, 0, 1, 1, 1, 1
+};
+
+static const struct spar_segment_state segment_state_paused = {
+ 1, 1, 1, 0, 1, 1, 1, 0
+};
+
+static const struct spar_segment_state segment_state_standby = {
+ 1, 1, 0, 0, 1, 1, 1, 0
+};
+
+/* Ids for commands that may appear in either queue of a ControlVm channel.
*
* Commands that are initiated by the command partition (CP), by an IO or
* console service partition (SP), or by a guest partition (GP)are:
@@ -84,60 +100,49 @@ static const uuid_le spar_controlvm_channel_protocol_uuid =
*/
enum controlvm_id {
CONTROLVM_INVALID = 0,
- /* SWITCH commands required Parameter: SwitchNumber */
- /* BUS commands required Parameter: BusNumber */
- CONTROLVM_BUS_CREATE = 0x101, /* CP --> SP, GP */
- CONTROLVM_BUS_DESTROY = 0x102, /* CP --> SP, GP */
- CONTROLVM_BUS_CONFIGURE = 0x104, /* CP --> SP */
- CONTROLVM_BUS_CHANGESTATE = 0x105, /* CP --> SP, GP */
- CONTROLVM_BUS_CHANGESTATE_EVENT = 0x106, /* SP, GP --> CP */
-/* DEVICE commands required Parameter: BusNumber, DeviceNumber */
-
- CONTROLVM_DEVICE_CREATE = 0x201, /* CP --> SP, GP */
- CONTROLVM_DEVICE_DESTROY = 0x202, /* CP --> SP, GP */
- CONTROLVM_DEVICE_CONFIGURE = 0x203, /* CP --> SP */
- CONTROLVM_DEVICE_CHANGESTATE = 0x204, /* CP --> SP, GP */
- CONTROLVM_DEVICE_CHANGESTATE_EVENT = 0x205, /* SP, GP --> CP */
- CONTROLVM_DEVICE_RECONFIGURE = 0x206, /* CP --> Boot */
-/* DISK commands required Parameter: BusNumber, DeviceNumber */
- CONTROLVM_DISK_CREATE = 0x221, /* CP --> SP */
- CONTROLVM_DISK_DESTROY = 0x222, /* CP --> SP */
- CONTROLVM_DISK_CONFIGURE = 0x223, /* CP --> SP */
- CONTROLVM_DISK_CHANGESTATE = 0x224, /* CP --> SP */
+ /* SWITCH commands required Parameter: SwitchNumber */
+ /* BUS commands required Parameter: BusNumber */
+ CONTROLVM_BUS_CREATE = 0x101, /* CP --> SP, GP */
+ CONTROLVM_BUS_DESTROY = 0x102, /* CP --> SP, GP */
+ CONTROLVM_BUS_CONFIGURE = 0x104, /* CP --> SP */
+ CONTROLVM_BUS_CHANGESTATE = 0x105, /* CP --> SP, GP */
+ CONTROLVM_BUS_CHANGESTATE_EVENT = 0x106, /* SP, GP --> CP */
+/* DEVICE commands required Parameter: BusNumber, DeviceNumber */
+
+ CONTROLVM_DEVICE_CREATE = 0x201, /* CP --> SP, GP */
+ CONTROLVM_DEVICE_DESTROY = 0x202, /* CP --> SP, GP */
+ CONTROLVM_DEVICE_CONFIGURE = 0x203, /* CP --> SP */
+ CONTROLVM_DEVICE_CHANGESTATE = 0x204, /* CP --> SP, GP */
+ CONTROLVM_DEVICE_CHANGESTATE_EVENT = 0x205, /* SP, GP --> CP */
+ CONTROLVM_DEVICE_RECONFIGURE = 0x206, /* CP --> Boot */
/* CHIPSET commands */
- CONTROLVM_CHIPSET_INIT = 0x301, /* CP --> SP, GP */
- CONTROLVM_CHIPSET_STOP = 0x302, /* CP --> SP, GP */
- CONTROLVM_CHIPSET_SHUTDOWN = 0x303, /* CP --> SP */
- CONTROLVM_CHIPSET_READY = 0x304, /* CP --> SP */
- CONTROLVM_CHIPSET_SELFTEST = 0x305, /* CP --> SP */
+ CONTROLVM_CHIPSET_INIT = 0x301, /* CP --> SP, GP */
+ CONTROLVM_CHIPSET_STOP = 0x302, /* CP --> SP, GP */
+ CONTROLVM_CHIPSET_READY = 0x304, /* CP --> SP */
+ CONTROLVM_CHIPSET_SELFTEST = 0x305, /* CP --> SP */
};
struct irq_info {
- /**< specifies interrupt info. It is used to send interrupts
- * for this channel. The peer at the end of this channel
- * who has registered an interrupt (using recv fields
- * above) will receive the interrupt. Passed as a parameter
- * to Issue_VMCALL_IO_QUEUE_TRANSITION, which generates the
- * interrupt. Currently this is used by IOPart-SP to wake
- * up GP when Data Channel transitions from empty to
- * non-empty.*/
- u64 send_irq_handle;
-
- /**< specifies interrupt handle. It is used to retrieve the
+ u64 reserved1;
+
+ /* specifies interrupt handle. It is used to retrieve the
* corresponding interrupt pin from Monitor; and the
* interrupt pin is used to connect to the corresponding
- * interrupt. Used by IOPart-GP only. */
+ * interrupt. Used by IOPart-GP only.
+ */
u64 recv_irq_handle;
- /**< specifies interrupt vector. It, interrupt pin, and shared are
+ /* specifies interrupt vector. It, interrupt pin, and shared are
* used to connect to the corresponding interrupt. Used by
- * IOPart-GP only. */
+ * IOPart-GP only.
+ */
u32 recv_irq_vector;
- /**< specifies if the recvInterrupt is shared. It, interrupt pin
- * and vector are used to connect to 0 = not shared; 1 = shared.
- * the corresponding interrupt. Used by IOPart-GP only. */
+ /* specifies if the recvInterrupt is shared. It, interrupt pin
+ * and vector are used to connect to 0 = not shared; 1 = shared.
+ * the corresponding interrupt. Used by IOPart-GP only.
+ */
u8 recv_irq_shared;
u8 reserved[3]; /* Natural alignment purposes */
};
@@ -151,20 +156,19 @@ struct pci_id {
};
struct efi_spar_indication {
- u64 boot_to_fw_ui:1; /* Bit 0: Stop in uefi ui */
- u64 clear_nvram:1; /* Bit 1: Clear NVRAM */
- u64 clear_cmos:1; /* Bit 2: Clear CMOS */
- u64 boot_to_tool:1; /* Bit 3: Run install tool */
+ u64 boot_to_fw_ui:1; /* Bit 0: Stop in uefi ui */
+ u64 clear_nvram:1; /* Bit 1: Clear NVRAM */
+ u64 clear_cmos:1; /* Bit 2: Clear CMOS */
+ u64 boot_to_tool:1; /* Bit 3: Run install tool */
/* remaining bits are available */
};
enum ultra_chipset_feature {
ULTRA_CHIPSET_FEATURE_REPLY = 0x00000001,
ULTRA_CHIPSET_FEATURE_PARA_HOTPLUG = 0x00000002,
- ULTRA_CHIPSET_FEATURE_PCIVBUS = 0x00000004
};
-/** This is the common structure that is at the beginning of every
+/* This is the common structure that is at the beginning of every
* ControlVm message (both commands and responses) in any ControlVm
* queue. Commands are easily distinguished from responses by
* looking at the flags.response field.
@@ -181,26 +185,26 @@ struct controlvm_message_header {
u32 completion_status; /* Error status code or result of
* message completion */
struct {
- u32 failed:1; /**< =1 in a response to * signify
+ u32 failed:1; /* =1 in a response to * signify
* failure */
- u32 response_expected:1; /**< =1 in all messages that expect a
- * response (Control ignores this
- * bit) */
- u32 server:1; /**< =1 in all bus & device-related
+ u32 response_expected:1; /* =1 in all messages that expect a
+ * response (Control ignores this
+ * bit) */
+ u32 server:1; /* =1 in all bus & device-related
* messages where the message
* receiver is to act as the bus or
* device server */
- u32 test_message:1; /**< =1 for testing use only
+ u32 test_message:1; /* =1 for testing use only
* (Control and Command ignore this
* bit) */
- u32 partial_completion:1; /**< =1 if there are forthcoming
- * responses/acks associated
- * with this message */
- u32 preserve:1; /**< =1 this is to let us know to
- * preserve channel contents
- * (for running guests)*/
- u32 writer_in_diag:1; /**< =1 the DiagWriter is active in the
- * Diagnostic Partition*/
+ u32 partial_completion:1; /* =1 if there are forthcoming
+ * responses/acks associated
+ * with this message */
+ u32 preserve:1; /* =1 this is to let us know to
+ * preserve channel contents
+ * (for running guests)*/
+ u32 writer_in_diag:1; /* =1 the DiagWriter is active in the
+ * Diagnostic Partition*/
} flags;
u32 reserved; /* Natural alignment */
u64 message_handle; /* Identifies the particular message instance,
@@ -216,8 +220,8 @@ struct controlvm_message_header {
};
struct controlvm_packet_device_create {
- u32 bus_no; /* bus # (0..n-1) from the msg receiver's end */
- u32 dev_no; /* bus-relative (0..n-1) device number */
+ u32 bus_no; /* bus # (0..n-1) from the msg receiver's end */
+ u32 dev_no; /* bus-relative (0..n-1) device number */
u64 channel_addr; /* Guest physical address of the channel, which
* can be dereferenced by the receiver of this
* ControlVm command */
@@ -228,11 +232,10 @@ struct controlvm_packet_device_create {
}; /* for CONTROLVM_DEVICE_CREATE */
struct controlvm_packet_device_configure {
- u32 bus_no; /**< bus # (0..n-1) from the msg
+ u32 bus_no; /* bus # (0..n-1) from the msg
* receiver's perspective */
-
- /* Control uses header SegmentIndex field to access bus number... */
- u32 dev_no; /**< bus-relative (0..n-1) device number */
+ /* Control uses header SegmentIndex field to access bus number... */
+ u32 dev_no; /* bus-relative (0..n-1) device number */
} ; /* for CONTROLVM_DEVICE_CONFIGURE */
struct controlvm_message_device_create {
@@ -342,77 +345,48 @@ struct controlvm_message {
struct controlvm_message_packet cmd;
};
-struct device_map {
- GUEST_PHYSICAL_ADDRESS device_channel_address;
- u64 device_channel_size;
- u32 ca_index;
- u32 reserved; /* natural alignment */
- u64 reserved2; /* Align structure on 32-byte boundary */
-};
-
-struct guest_devices {
- struct device_map video_channel;
- struct device_map keyboard_channel;
- struct device_map network_channel;
- struct device_map storage_channel;
- struct device_map console_channel;
- u32 partition_index;
- u32 pad;
-};
-
struct spar_controlvm_channel_protocol {
- struct channel_header header;
- GUEST_PHYSICAL_ADDRESS gp_controlvm; /* guest physical address of
- * this channel */
- GUEST_PHYSICAL_ADDRESS gp_partition_tables;/* guest physical address of
- * partition tables */
- GUEST_PHYSICAL_ADDRESS gp_diag_guest; /* guest physical address of
- * diagnostic channel */
- GUEST_PHYSICAL_ADDRESS gp_boot_romdisk;/* guest phys addr of (read
- * only) Boot ROM disk */
- GUEST_PHYSICAL_ADDRESS gp_boot_ramdisk;/* guest phys addr of writable
- * Boot RAM disk */
- GUEST_PHYSICAL_ADDRESS gp_acpi_table; /* guest phys addr of acpi
- * table */
- GUEST_PHYSICAL_ADDRESS gp_control_channel;/* guest phys addr of control
- * channel */
- GUEST_PHYSICAL_ADDRESS gp_diag_romdisk;/* guest phys addr of diagnostic
- * ROM disk */
- GUEST_PHYSICAL_ADDRESS gp_nvram; /* guest phys addr of NVRAM
- * channel */
- u64 request_payload_offset; /* Offset to request payload area */
- u64 event_payload_offset; /* Offset to event payload area */
- u32 request_payload_bytes; /* Bytes available in request payload
+ struct channel_header header;
+ u64 gp_controlvm; /* guest phys addr of this channel */
+ u64 gp_partition_tables;/* guest phys addr of partition tables */
+ u64 gp_diag_guest; /* guest phys addr of diagnostic channel */
+ u64 gp_boot_romdisk;/* guest phys addr of (read* only) Boot ROM disk */
+ u64 gp_boot_ramdisk;/* guest phys addr of writable Boot RAM disk */
+ u64 gp_acpi_table; /* guest phys addr of acpi table */
+ u64 gp_control_channel;/* guest phys addr of control channel */
+ u64 gp_diag_romdisk;/* guest phys addr of diagnostic ROM disk */
+ u64 gp_nvram; /* guest phys addr of NVRAM channel */
+ u64 request_payload_offset; /* Offset to request payload area */
+ u64 event_payload_offset; /* Offset to event payload area */
+ u32 request_payload_bytes; /* Bytes available in request payload
* area */
- u32 event_payload_bytes;/* Bytes available in event payload area */
- u32 control_channel_bytes;
- u32 nvram_channel_bytes; /* Bytes in PartitionNvram segment */
- u32 message_bytes; /* sizeof(CONTROLVM_MESSAGE) */
- u32 message_count; /* CONTROLVM_MESSAGE_MAX */
- GUEST_PHYSICAL_ADDRESS gp_smbios_table;/* guest phys addr of SMBIOS
- * tables */
- GUEST_PHYSICAL_ADDRESS gp_physical_smbios_table;/* guest phys addr of
- * SMBIOS table */
- /* ULTRA_MAX_GUESTS_PER_SERVICE */
- struct guest_devices gp_obsolete_guest_devices[16];
-
- /* guest physical address of EFI firmware image base */
- GUEST_PHYSICAL_ADDRESS virtual_guest_firmware_image_base;
-
- /* guest physical address of EFI firmware entry point */
- GUEST_PHYSICAL_ADDRESS virtual_guest_firmware_entry_point;
-
- /* guest EFI firmware image size */
- u64 virtual_guest_firmware_image_size;
-
- /* GPA = 1MB where EFI firmware image is copied to */
- GUEST_PHYSICAL_ADDRESS virtual_guest_firmware_boot_base;
- GUEST_PHYSICAL_ADDRESS virtual_guest_image_base;
- GUEST_PHYSICAL_ADDRESS virtual_guest_image_size;
- u64 prototype_control_channel_offset;
- GUEST_PHYSICAL_ADDRESS virtual_guest_partition_handle;
-
- u16 restore_action; /* Restore Action field to restore the guest
+ u32 event_payload_bytes;/* Bytes available in event payload area */
+ u32 control_channel_bytes;
+ u32 nvram_channel_bytes; /* Bytes in PartitionNvram segment */
+ u32 message_bytes; /* sizeof(CONTROLVM_MESSAGE) */
+ u32 message_count; /* CONTROLVM_MESSAGE_MAX */
+ u64 gp_smbios_table; /* guest phys addr of SMBIOS tables */
+ u64 gp_physical_smbios_table; /* guest phys addr of SMBIOS table */
+ /* ULTRA_MAX_GUESTS_PER_SERVICE */
+ char gp_reserved[2688];
+
+ /* guest physical address of EFI firmware image base */
+ u64 virtual_guest_firmware_image_base;
+
+ /* guest physical address of EFI firmware entry point */
+ u64 virtual_guest_firmware_entry_point;
+
+ /* guest EFI firmware image size */
+ u64 virtual_guest_firmware_image_size;
+
+ /* GPA = 1MB where EFI firmware image is copied to */
+ u64 virtual_guest_firmware_boot_base;
+ u64 virtual_guest_image_base;
+ u64 virtual_guest_image_size;
+ u64 prototype_control_channel_offset;
+ u64 virtual_guest_partition_handle;
+
+ u16 restore_action; /* Restore Action field to restore the guest
* partition */
u16 dump_action; /* For Windows guests it shows if the visordisk
* is running in dump mode */
@@ -462,7 +436,7 @@ struct spar_controlvm_channel_protocol {
struct controlvm_message saved_crash_msg[CONTROLVM_CRASHMSG_MAX];
};
-/* Offsets for VM channel attributes... */
+/* Offsets for VM channel attributes */
#define VM_CH_REQ_QUEUE_OFFSET \
offsetof(struct spar_controlvm_channel_protocol, request_queue)
#define VM_CH_RESP_QUEUE_OFFSET \
diff --git a/drivers/staging/unisys/common-spar/include/controlvmcompletionstatus.h b/drivers/staging/unisys/visorbus/controlvmcompletionstatus.h
index f74f5d8c2..f74f5d8c2 100644
--- a/drivers/staging/unisys/common-spar/include/controlvmcompletionstatus.h
+++ b/drivers/staging/unisys/visorbus/controlvmcompletionstatus.h
diff --git a/drivers/staging/unisys/common-spar/include/iovmcall_gnuc.h b/drivers/staging/unisys/visorbus/iovmcall_gnuc.h
index 57dd93e0c..57dd93e0c 100644
--- a/drivers/staging/unisys/common-spar/include/iovmcall_gnuc.h
+++ b/drivers/staging/unisys/visorbus/iovmcall_gnuc.h
diff --git a/drivers/staging/unisys/visorutil/periodic_work.c b/drivers/staging/unisys/visorbus/periodic_work.c
index abbfb4889..5e56088cf 100644
--- a/drivers/staging/unisys/visorutil/periodic_work.c
+++ b/drivers/staging/unisys/visorbus/periodic_work.c
@@ -18,8 +18,8 @@
/*
* Helper functions to schedule periodic work in Linux kernel mode.
*/
+#include <linux/sched.h>
-#include "timskmod.h"
#include "periodic_work.h"
#define MYDRVNAME "periodic_work"
@@ -29,8 +29,8 @@ struct periodic_work {
struct delayed_work work;
void (*workfunc)(void *);
void *workfuncarg;
- BOOL is_scheduled;
- BOOL want_to_stop;
+ bool is_scheduled;
+ bool want_to_stop;
ulong jiffy_interval;
struct workqueue_struct *workqueue;
const char *devnam;
@@ -74,64 +74,64 @@ EXPORT_SYMBOL_GPL(visor_periodic_work_destroy);
/** Call this from your periodic work worker function to schedule the next
* call.
- * If this function returns FALSE, there was a failure and the
+ * If this function returns false, there was a failure and the
* periodic work is no longer scheduled
*/
-BOOL visor_periodic_work_nextperiod(struct periodic_work *pw)
+bool visor_periodic_work_nextperiod(struct periodic_work *pw)
{
- BOOL rc = FALSE;
+ bool rc = false;
write_lock(&pw->lock);
if (pw->want_to_stop) {
- pw->is_scheduled = FALSE;
- pw->want_to_stop = FALSE;
- rc = TRUE; /* yes, TRUE; see visor_periodic_work_stop() */
+ pw->is_scheduled = false;
+ pw->want_to_stop = false;
+ rc = true; /* yes, true; see visor_periodic_work_stop() */
goto unlock;
} else if (queue_delayed_work(pw->workqueue, &pw->work,
pw->jiffy_interval) < 0) {
- pw->is_scheduled = FALSE;
- rc = FALSE;
+ pw->is_scheduled = false;
+ rc = false;
goto unlock;
}
- rc = TRUE;
+ rc = true;
unlock:
write_unlock(&pw->lock);
return rc;
}
EXPORT_SYMBOL_GPL(visor_periodic_work_nextperiod);
-/** This function returns TRUE iff new periodic work was actually started.
- * If this function returns FALSE, then no work was started
+/** This function returns true iff new periodic work was actually started.
+ * If this function returns false, then no work was started
* (either because it was already started, or because of a failure).
*/
-BOOL visor_periodic_work_start(struct periodic_work *pw)
+bool visor_periodic_work_start(struct periodic_work *pw)
{
- BOOL rc = FALSE;
+ bool rc = false;
write_lock(&pw->lock);
if (pw->is_scheduled) {
- rc = FALSE;
+ rc = false;
goto unlock;
}
if (pw->want_to_stop) {
- rc = FALSE;
+ rc = false;
goto unlock;
}
INIT_DELAYED_WORK(&pw->work, &periodic_work_func);
if (queue_delayed_work(pw->workqueue, &pw->work,
pw->jiffy_interval) < 0) {
- rc = FALSE;
+ rc = false;
goto unlock;
}
- pw->is_scheduled = TRUE;
- rc = TRUE;
+ pw->is_scheduled = true;
+ rc = true;
unlock:
write_unlock(&pw->lock);
return rc;
}
EXPORT_SYMBOL_GPL(visor_periodic_work_start);
-/** This function returns TRUE iff your call actually stopped the periodic
+/** This function returns true iff your call actually stopped the periodic
* work.
*
* -- PAY ATTENTION... this is important --
@@ -165,20 +165,20 @@ EXPORT_SYMBOL_GPL(visor_periodic_work_start);
* this deadlock, you will get hung up in an infinite loop saying
* "waiting for delayed work...".
*/
-BOOL visor_periodic_work_stop(struct periodic_work *pw)
+bool visor_periodic_work_stop(struct periodic_work *pw)
{
- BOOL stopped_something = FALSE;
+ bool stopped_something = false;
write_lock(&pw->lock);
stopped_something = pw->is_scheduled && (!pw->want_to_stop);
while (pw->is_scheduled) {
- pw->want_to_stop = TRUE;
+ pw->want_to_stop = true;
if (cancel_delayed_work(&pw->work)) {
/* We get here if the delayed work was pending as
* delayed work, but was NOT run.
*/
WARN_ON(!pw->is_scheduled);
- pw->is_scheduled = FALSE;
+ pw->is_scheduled = false;
} else {
/* If we get here, either the delayed work:
* - was run, OR,
@@ -192,10 +192,10 @@ BOOL visor_periodic_work_stop(struct periodic_work *pw)
}
if (pw->is_scheduled) {
write_unlock(&pw->lock);
- SLEEPJIFFIES(10);
+ schedule_timeout_interruptible(msecs_to_jiffies(10));
write_lock(&pw->lock);
} else {
- pw->want_to_stop = FALSE;
+ pw->want_to_stop = false;
}
}
write_unlock(&pw->lock);
diff --git a/drivers/staging/unisys/common-spar/include/channels/vbuschannel.h b/drivers/staging/unisys/visorbus/vbuschannel.h
index 2c42ce16e..5ed83a3f1 100644
--- a/drivers/staging/unisys/common-spar/include/channels/vbuschannel.h
+++ b/drivers/staging/unisys/visorbus/vbuschannel.h
@@ -54,7 +54,7 @@ static const uuid_le spar_vbus_channel_protocol_uuid =
#define SPAR_VBUS_CHANNEL_OK_SERVER(actual_bytes) \
(spar_check_channel_server(spar_vbus_channel_protocol_uuid, \
"vbus", \
- sizeof(struct ultra_vbus_channel_protocol),\
+ sizeof(struct spar_vbus_channel_protocol),\
actual_bytes))
#pragma pack(push, 1) /* both GCC and VC now allow this pragma */
diff --git a/drivers/staging/unisys/common-spar/include/vbusdeviceinfo.h b/drivers/staging/unisys/visorbus/vbusdeviceinfo.h
index 9b6d3e693..9b6d3e693 100644
--- a/drivers/staging/unisys/common-spar/include/vbusdeviceinfo.h
+++ b/drivers/staging/unisys/visorbus/vbusdeviceinfo.h
diff --git a/drivers/staging/unisys/visorbus/visorbus_main.c b/drivers/staging/unisys/visorbus/visorbus_main.c
new file mode 100644
index 000000000..6db47196c
--- /dev/null
+++ b/drivers/staging/unisys/visorbus/visorbus_main.c
@@ -0,0 +1,1518 @@
+/* visorbus_main.c
+ *
+ * Copyright � 2010 - 2013 UNISYS CORPORATION
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ */
+
+#include <linux/uuid.h>
+
+#include "visorbus.h"
+#include "visorbus_private.h"
+#include "version.h"
+#include "periodic_work.h"
+#include "vbuschannel.h"
+#include "guestlinuxdebug.h"
+#include "vmcallinterface.h"
+
+#define MYDRVNAME "visorbus"
+
+/* module parameters */
+static int visorbus_debug;
+static int visorbus_forcematch;
+static int visorbus_forcenomatch;
+static int visorbus_debugref;
+#define SERIALLOOPBACKCHANADDR (100 * 1024 * 1024)
+
+#define CURRENT_FILE_PC VISOR_BUS_PC_visorbus_main_c
+#define POLLJIFFIES_TESTWORK 100
+#define POLLJIFFIES_NORMALCHANNEL 10
+
+static int visorbus_uevent(struct device *xdev, struct kobj_uevent_env *env);
+static int visorbus_match(struct device *xdev, struct device_driver *xdrv);
+static void fix_vbus_dev_info(struct visor_device *visordev);
+
+/* BUS type attributes
+ *
+ * define & implement display of bus attributes under
+ * /sys/bus/visorbus.
+ *
+ */
+
+static ssize_t version_show(struct bus_type *bus, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%s\n", VERSION);
+}
+
+static BUS_ATTR_RO(version);
+
+static struct attribute *visorbus_bus_attrs[] = {
+ &bus_attr_version.attr,
+ NULL,
+};
+
+static const struct attribute_group visorbus_bus_group = {
+ .attrs = visorbus_bus_attrs,
+};
+
+static const struct attribute_group *visorbus_bus_groups[] = {
+ &visorbus_bus_group,
+ NULL,
+};
+
+/** This describes the TYPE of bus.
+ * (Don't confuse this with an INSTANCE of the bus.)
+ */
+struct bus_type visorbus_type = {
+ .name = "visorbus",
+ .match = visorbus_match,
+ .uevent = visorbus_uevent,
+ .bus_groups = visorbus_bus_groups,
+};
+
+static struct delayed_work periodic_work;
+
+/* YES, we need 2 workqueues.
+ * The reason is, workitems on the test queue may need to cancel
+ * workitems on the other queue. You will be in for trouble if you try to
+ * do this with workitems queued on the same workqueue.
+ */
+static struct workqueue_struct *periodic_test_workqueue;
+static struct workqueue_struct *periodic_dev_workqueue;
+static long long bus_count; /** number of bus instances */
+ /** ever-increasing */
+
+static void chipset_bus_create(struct visor_device *bus_info);
+static void chipset_bus_destroy(struct visor_device *bus_info);
+static void chipset_device_create(struct visor_device *dev_info);
+static void chipset_device_destroy(struct visor_device *dev_info);
+static void chipset_device_pause(struct visor_device *dev_info);
+static void chipset_device_resume(struct visor_device *dev_info);
+
+/** These functions are implemented herein, and are called by the chipset
+ * driver to notify us about specific events.
+ */
+static struct visorchipset_busdev_notifiers chipset_notifiers = {
+ .bus_create = chipset_bus_create,
+ .bus_destroy = chipset_bus_destroy,
+ .device_create = chipset_device_create,
+ .device_destroy = chipset_device_destroy,
+ .device_pause = chipset_device_pause,
+ .device_resume = chipset_device_resume,
+};
+
+/** These functions are implemented in the chipset driver, and we call them
+ * herein when we want to acknowledge a specific event.
+ */
+static struct visorchipset_busdev_responders chipset_responders;
+
+/* filled in with info about parent chipset driver when we register with it */
+static struct ultra_vbus_deviceinfo chipset_driverinfo;
+/* filled in with info about this driver, wrt it servicing client busses */
+static struct ultra_vbus_deviceinfo clientbus_driverinfo;
+
+/** list of visor_device structs, linked via .list_all */
+static LIST_HEAD(list_all_bus_instances);
+/** list of visor_device structs, linked via .list_all */
+static LIST_HEAD(list_all_device_instances);
+
+static int
+visorbus_uevent(struct device *xdev, struct kobj_uevent_env *env)
+{
+ if (add_uevent_var(env, "VERSION=%s", VERSION))
+ return -ENOMEM;
+ return 0;
+}
+
+/* This is called automatically upon adding a visor_device (device_add), or
+ * adding a visor_driver (visorbus_register_visor_driver), and returns 1 iff the
+ * provided driver can control the specified device.
+ */
+static int
+visorbus_match(struct device *xdev, struct device_driver *xdrv)
+{
+ uuid_le channel_type;
+ int rc = 0;
+ int i;
+ struct visor_device *dev;
+ struct visor_driver *drv;
+
+ dev = to_visor_device(xdev);
+ drv = to_visor_driver(xdrv);
+ channel_type = visorchannel_get_uuid(dev->visorchannel);
+ if (visorbus_forcematch) {
+ rc = 1;
+ goto away;
+ }
+ if (visorbus_forcenomatch)
+ goto away;
+
+ if (!drv->channel_types)
+ goto away;
+ for (i = 0;
+ (uuid_le_cmp(drv->channel_types[i].guid, NULL_UUID_LE) != 0) ||
+ (drv->channel_types[i].name);
+ i++)
+ if (uuid_le_cmp(drv->channel_types[i].guid,
+ channel_type) == 0) {
+ rc = i + 1;
+ goto away;
+ }
+away:
+ return rc;
+}
+
+/** This is called when device_unregister() is called for the bus device
+ * instance, after all other tasks involved with destroying the device
+ * are complete.
+ */
+static void
+visorbus_release_busdevice(struct device *xdev)
+{
+ struct visor_device *dev = dev_get_drvdata(xdev);
+
+ dev_set_drvdata(xdev, NULL);
+ kfree(dev);
+}
+
+/** This is called when device_unregister() is called for each child
+ * device instance.
+ */
+static void
+visorbus_release_device(struct device *xdev)
+{
+ struct visor_device *dev = to_visor_device(xdev);
+
+ if (dev->periodic_work) {
+ visor_periodic_work_destroy(dev->periodic_work);
+ dev->periodic_work = NULL;
+ }
+ if (dev->visorchannel) {
+ visorchannel_destroy(dev->visorchannel);
+ dev->visorchannel = NULL;
+ }
+ kfree(dev);
+}
+
+/* Implement publishing of device node attributes under:
+ *
+ * /sys/bus/visorbus<x>/dev<y>/devmajorminor
+ *
+ */
+
+#define to_devmajorminor_attr(_attr) \
+ container_of(_attr, struct devmajorminor_attribute, attr)
+#define to_visor_device_from_kobjdevmajorminor(obj) \
+ container_of(obj, struct visor_device, kobjdevmajorminor)
+
+struct devmajorminor_attribute {
+ struct attribute attr;
+ int slot;
+ ssize_t (*show)(struct visor_device *, int slot, char *buf);
+ ssize_t (*store)(struct visor_device *, int slot, const char *buf,
+ size_t count);
+};
+
+static ssize_t DEVMAJORMINOR_ATTR(struct visor_device *dev, int slot, char *buf)
+{
+ int maxdevnodes = ARRAY_SIZE(dev->devnodes) / sizeof(dev->devnodes[0]);
+
+ if (slot < 0 || slot >= maxdevnodes)
+ return 0;
+ return snprintf(buf, PAGE_SIZE, "%d:%d\n",
+ dev->devnodes[slot].major, dev->devnodes[slot].minor);
+}
+
+static ssize_t
+devmajorminor_attr_show(struct kobject *kobj, struct attribute *attr, char *buf)
+{
+ struct devmajorminor_attribute *devmajorminor_attr =
+ to_devmajorminor_attr(attr);
+ struct visor_device *dev = to_visor_device_from_kobjdevmajorminor(kobj);
+ ssize_t ret = 0;
+
+ if (devmajorminor_attr->show)
+ ret = devmajorminor_attr->show(dev,
+ devmajorminor_attr->slot, buf);
+ return ret;
+}
+
+static ssize_t
+devmajorminor_attr_store(struct kobject *kobj,
+ struct attribute *attr, const char *buf, size_t count)
+{
+ struct devmajorminor_attribute *devmajorminor_attr =
+ to_devmajorminor_attr(attr);
+ struct visor_device *dev = to_visor_device_from_kobjdevmajorminor(kobj);
+ ssize_t ret = 0;
+
+ if (devmajorminor_attr->store)
+ ret = devmajorminor_attr->store(dev,
+ devmajorminor_attr->slot,
+ buf, count);
+ return ret;
+}
+
+static int register_devmajorminor_attributes(struct visor_device *dev);
+
+static int
+devmajorminor_create_file(struct visor_device *dev, const char *name,
+ int major, int minor)
+{
+ int maxdevnodes = ARRAY_SIZE(dev->devnodes) / sizeof(dev->devnodes[0]);
+ struct devmajorminor_attribute *myattr = NULL;
+ int x = -1, rc = 0, slot = -1;
+
+ register_devmajorminor_attributes(dev);
+ for (slot = 0; slot < maxdevnodes; slot++)
+ if (!dev->devnodes[slot].attr)
+ break;
+ if (slot == maxdevnodes) {
+ rc = -ENOMEM;
+ goto away;
+ }
+ myattr = kmalloc(sizeof(*myattr), GFP_KERNEL);
+ if (!myattr) {
+ rc = -ENOMEM;
+ goto away;
+ }
+ memset(myattr, 0, sizeof(struct devmajorminor_attribute));
+ myattr->show = DEVMAJORMINOR_ATTR;
+ myattr->store = NULL;
+ myattr->slot = slot;
+ myattr->attr.name = name;
+ myattr->attr.mode = S_IRUGO;
+ dev->devnodes[slot].attr = myattr;
+ dev->devnodes[slot].major = major;
+ dev->devnodes[slot].minor = minor;
+ x = sysfs_create_file(&dev->kobjdevmajorminor, &myattr->attr);
+ if (x < 0) {
+ rc = x;
+ goto away;
+ }
+ kobject_uevent(&dev->device.kobj, KOBJ_ONLINE);
+away:
+ if (rc < 0) {
+ kfree(myattr);
+ myattr = NULL;
+ dev->devnodes[slot].attr = NULL;
+ }
+ return rc;
+}
+
+static void
+devmajorminor_remove_file(struct visor_device *dev, int slot)
+{
+ int maxdevnodes = ARRAY_SIZE(dev->devnodes) / sizeof(dev->devnodes[0]);
+ struct devmajorminor_attribute *myattr = NULL;
+
+ if (slot < 0 || slot >= maxdevnodes)
+ return;
+ myattr = (struct devmajorminor_attribute *)(dev->devnodes[slot].attr);
+ if (!myattr)
+ return;
+ sysfs_remove_file(&dev->kobjdevmajorminor, &myattr->attr);
+ kobject_uevent(&dev->device.kobj, KOBJ_OFFLINE);
+ dev->devnodes[slot].attr = NULL;
+ kfree(myattr);
+}
+
+static void
+devmajorminor_remove_all_files(struct visor_device *dev)
+{
+ int i = 0;
+ int maxdevnodes = ARRAY_SIZE(dev->devnodes) / sizeof(dev->devnodes[0]);
+
+ for (i = 0; i < maxdevnodes; i++)
+ devmajorminor_remove_file(dev, i);
+}
+
+static const struct sysfs_ops devmajorminor_sysfs_ops = {
+ .show = devmajorminor_attr_show,
+ .store = devmajorminor_attr_store,
+};
+
+static struct kobj_type devmajorminor_kobj_type = {
+ .sysfs_ops = &devmajorminor_sysfs_ops
+};
+
+static int
+register_devmajorminor_attributes(struct visor_device *dev)
+{
+ int rc = 0, x = 0;
+
+ if (dev->kobjdevmajorminor.parent)
+ goto away; /* already registered */
+ x = kobject_init_and_add(&dev->kobjdevmajorminor,
+ &devmajorminor_kobj_type, &dev->device.kobj,
+ "devmajorminor");
+ if (x < 0) {
+ rc = x;
+ goto away;
+ }
+
+ kobject_uevent(&dev->kobjdevmajorminor, KOBJ_ADD);
+
+away:
+ return rc;
+}
+
+static void
+unregister_devmajorminor_attributes(struct visor_device *dev)
+{
+ if (!dev->kobjdevmajorminor.parent)
+ return; /* already unregistered */
+ devmajorminor_remove_all_files(dev);
+
+ kobject_del(&dev->kobjdevmajorminor);
+ kobject_put(&dev->kobjdevmajorminor);
+ dev->kobjdevmajorminor.parent = NULL;
+}
+
+/* begin implementation of specific channel attributes to appear under
+* /sys/bus/visorbus<x>/dev<y>/channel
+*/
+static ssize_t physaddr_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct visor_device *vdev = to_visor_device(dev);
+
+ if (!vdev->visorchannel)
+ return 0;
+ return snprintf(buf, PAGE_SIZE, "0x%Lx\n",
+ visorchannel_get_physaddr(vdev->visorchannel));
+}
+
+static ssize_t nbytes_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct visor_device *vdev = to_visor_device(dev);
+
+ if (!vdev->visorchannel)
+ return 0;
+ return snprintf(buf, PAGE_SIZE, "0x%lx\n",
+ visorchannel_get_nbytes(vdev->visorchannel));
+}
+
+static ssize_t clientpartition_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct visor_device *vdev = to_visor_device(dev);
+
+ if (!vdev->visorchannel)
+ return 0;
+ return snprintf(buf, PAGE_SIZE, "0x%Lx\n",
+ visorchannel_get_clientpartition(vdev->visorchannel));
+}
+
+static ssize_t typeguid_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct visor_device *vdev = to_visor_device(dev);
+ char s[99];
+
+ if (!vdev->visorchannel)
+ return 0;
+ return snprintf(buf, PAGE_SIZE, "%s\n",
+ visorchannel_id(vdev->visorchannel, s));
+}
+
+static ssize_t zoneguid_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct visor_device *vdev = to_visor_device(dev);
+ char s[99];
+
+ if (!vdev->visorchannel)
+ return 0;
+ return snprintf(buf, PAGE_SIZE, "%s\n",
+ visorchannel_zoneid(vdev->visorchannel, s));
+}
+
+static ssize_t typename_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct visor_device *vdev = to_visor_device(dev);
+ int i = 0;
+ struct bus_type *xbus = dev->bus;
+ struct device_driver *xdrv = dev->driver;
+ struct visor_driver *drv = NULL;
+
+ if (!vdev->visorchannel || !xbus || !xdrv)
+ return 0;
+ i = xbus->match(dev, xdrv);
+ if (!i)
+ return 0;
+ drv = to_visor_driver(xdrv);
+ return snprintf(buf, PAGE_SIZE, "%s\n", drv->channel_types[i - 1].name);
+}
+
+static DEVICE_ATTR_RO(physaddr);
+static DEVICE_ATTR_RO(nbytes);
+static DEVICE_ATTR_RO(clientpartition);
+static DEVICE_ATTR_RO(typeguid);
+static DEVICE_ATTR_RO(zoneguid);
+static DEVICE_ATTR_RO(typename);
+
+static struct attribute *channel_attrs[] = {
+ &dev_attr_physaddr.attr,
+ &dev_attr_nbytes.attr,
+ &dev_attr_clientpartition.attr,
+ &dev_attr_typeguid.attr,
+ &dev_attr_zoneguid.attr,
+ &dev_attr_typename.attr,
+};
+
+static struct attribute_group channel_attr_grp = {
+ .name = "channel",
+ .attrs = channel_attrs,
+};
+
+static const struct attribute_group *visorbus_dev_groups[] = {
+ &channel_attr_grp,
+ NULL
+};
+
+/* end implementation of specific channel attributes */
+
+/* BUS instance attributes
+ *
+ * define & implement display of bus attributes under
+ * /sys/bus/visorbus/busses/visorbus<n>.
+ *
+ * This is a bit hoaky because the kernel does not yet have the infrastructure
+ * to separate bus INSTANCE attributes from bus TYPE attributes...
+ * so we roll our own. See businst.c / businst.h.
+ *
+ */
+
+static ssize_t partition_handle_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf) {
+ struct visor_device *vdev = to_visor_device(dev);
+ u64 handle = visorchannel_get_clientpartition(vdev->visorchannel);
+
+ return snprintf(buf, PAGE_SIZE, "0x%Lx\n", handle);
+}
+
+static ssize_t partition_guid_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf) {
+ struct visor_device *vdev = to_visor_device(dev);
+
+ return snprintf(buf, PAGE_SIZE, "{%pUb}\n", &vdev->partition_uuid);
+}
+
+static ssize_t partition_name_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf) {
+ struct visor_device *vdev = to_visor_device(dev);
+
+ return snprintf(buf, PAGE_SIZE, "%s\n", vdev->name);
+}
+
+static ssize_t channel_addr_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf) {
+ struct visor_device *vdev = to_visor_device(dev);
+ u64 addr = visorchannel_get_physaddr(vdev->visorchannel);
+
+ return snprintf(buf, PAGE_SIZE, "0x%Lx\n", addr);
+}
+
+static ssize_t channel_bytes_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf) {
+ struct visor_device *vdev = to_visor_device(dev);
+ u64 nbytes = visorchannel_get_nbytes(vdev->visorchannel);
+
+ return snprintf(buf, PAGE_SIZE, "0x%Lx\n", nbytes);
+}
+
+static ssize_t channel_id_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf) {
+ struct visor_device *vdev = to_visor_device(dev);
+ int len = 0;
+
+ if (vdev->visorchannel) {
+ visorchannel_id(vdev->visorchannel, buf);
+ len = strlen(buf);
+ buf[len++] = '\n';
+ }
+ return len;
+}
+
+static ssize_t client_bus_info_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf) {
+ struct visor_device *vdev = to_visor_device(dev);
+ struct visorchannel *channel = vdev->visorchannel;
+
+ int i, x, remain = PAGE_SIZE;
+ unsigned long off;
+ char *p = buf;
+ u8 *partition_name;
+ struct ultra_vbus_deviceinfo dev_info;
+
+ partition_name = "";
+ if (channel) {
+ if (vdev->name)
+ partition_name = vdev->name;
+ x = snprintf(p, remain,
+ "Client device / client driver info for %s partition (vbus #%d):\n",
+ partition_name, vdev->chipset_dev_no);
+ p += x;
+ remain -= x;
+ x = visorchannel_read(channel,
+ offsetof(struct
+ spar_vbus_channel_protocol,
+ chp_info),
+ &dev_info, sizeof(dev_info));
+ if (x >= 0) {
+ x = vbuschannel_devinfo_to_string(&dev_info, p,
+ remain, -1);
+ p += x;
+ remain -= x;
+ }
+ x = visorchannel_read(channel,
+ offsetof(struct
+ spar_vbus_channel_protocol,
+ bus_info),
+ &dev_info, sizeof(dev_info));
+ if (x >= 0) {
+ x = vbuschannel_devinfo_to_string(&dev_info, p,
+ remain, -1);
+ p += x;
+ remain -= x;
+ }
+ off = offsetof(struct spar_vbus_channel_protocol, dev_info);
+ i = 0;
+ while (off + sizeof(dev_info) <=
+ visorchannel_get_nbytes(channel)) {
+ x = visorchannel_read(channel,
+ off, &dev_info, sizeof(dev_info));
+ if (x >= 0) {
+ x = vbuschannel_devinfo_to_string
+ (&dev_info, p, remain, i);
+ p += x;
+ remain -= x;
+ }
+ off += sizeof(dev_info);
+ i++;
+ }
+ }
+ return PAGE_SIZE - remain;
+}
+
+static DEVICE_ATTR_RO(partition_handle);
+static DEVICE_ATTR_RO(partition_guid);
+static DEVICE_ATTR_RO(partition_name);
+static DEVICE_ATTR_RO(channel_addr);
+static DEVICE_ATTR_RO(channel_bytes);
+static DEVICE_ATTR_RO(channel_id);
+static DEVICE_ATTR_RO(client_bus_info);
+
+static struct attribute *dev_attrs[] = {
+ &dev_attr_partition_handle.attr,
+ &dev_attr_partition_guid.attr,
+ &dev_attr_partition_name.attr,
+ &dev_attr_channel_addr.attr,
+ &dev_attr_channel_bytes.attr,
+ &dev_attr_channel_id.attr,
+ &dev_attr_client_bus_info.attr,
+ NULL
+};
+
+static struct attribute_group dev_attr_grp = {
+ .attrs = dev_attrs,
+};
+
+static const struct attribute_group *visorbus_groups[] = {
+ &dev_attr_grp,
+ NULL
+};
+
+/* DRIVER attributes
+ *
+ * define & implement display of driver attributes under
+ * /sys/bus/visorbus/drivers/<drivername>.
+ *
+ */
+
+static ssize_t
+DRIVER_ATTR_version(struct device_driver *xdrv, char *buf)
+{
+ struct visor_driver *drv = to_visor_driver(xdrv);
+
+ return snprintf(buf, PAGE_SIZE, "%s\n", drv->version);
+}
+
+static int
+register_driver_attributes(struct visor_driver *drv)
+{
+ int rc;
+ struct driver_attribute version =
+ __ATTR(version, S_IRUGO, DRIVER_ATTR_version, NULL);
+ drv->version_attr = version;
+ rc = driver_create_file(&drv->driver, &drv->version_attr);
+ return rc;
+}
+
+static void
+unregister_driver_attributes(struct visor_driver *drv)
+{
+ driver_remove_file(&drv->driver, &drv->version_attr);
+}
+
+static void
+dev_periodic_work(void *xdev)
+{
+ struct visor_device *dev = (struct visor_device *)xdev;
+ struct visor_driver *drv = to_visor_driver(dev->device.driver);
+
+ down(&dev->visordriver_callback_lock);
+ if (drv->channel_interrupt)
+ drv->channel_interrupt(dev);
+ up(&dev->visordriver_callback_lock);
+ if (!visor_periodic_work_nextperiod(dev->periodic_work))
+ put_device(&dev->device);
+}
+
+static void
+dev_start_periodic_work(struct visor_device *dev)
+{
+ if (dev->being_removed)
+ return;
+ /* now up by at least 2 */
+ get_device(&dev->device);
+ if (!visor_periodic_work_start(dev->periodic_work))
+ put_device(&dev->device);
+}
+
+static void
+dev_stop_periodic_work(struct visor_device *dev)
+{
+ if (visor_periodic_work_stop(dev->periodic_work))
+ put_device(&dev->device);
+}
+
+/** This is called automatically upon adding a visor_device (device_add), or
+ * adding a visor_driver (visorbus_register_visor_driver), but only after
+ * visorbus_match has returned 1 to indicate a successful match between
+ * driver and device.
+ */
+static int
+visordriver_probe_device(struct device *xdev)
+{
+ int rc;
+ struct visor_driver *drv;
+ struct visor_device *dev;
+
+ drv = to_visor_driver(xdev->driver);
+ dev = to_visor_device(xdev);
+ down(&dev->visordriver_callback_lock);
+ dev->being_removed = false;
+ /*
+ * ensure that the dev->being_removed flag is cleared before
+ * we start the probe
+ */
+ wmb();
+ get_device(&dev->device);
+ if (!drv->probe) {
+ up(&dev->visordriver_callback_lock);
+ rc = -1;
+ goto away;
+ }
+ rc = drv->probe(dev);
+ if (rc < 0)
+ goto away;
+
+ fix_vbus_dev_info(dev);
+ up(&dev->visordriver_callback_lock);
+ rc = 0;
+away:
+ if (rc != 0)
+ put_device(&dev->device);
+ return rc;
+}
+
+/** This is called when device_unregister() is called for each child device
+ * instance, to notify the appropriate visorbus_driver that the device is
+ * going away, and to decrease the reference count of the device.
+ */
+static int
+visordriver_remove_device(struct device *xdev)
+{
+ struct visor_device *dev;
+ struct visor_driver *drv;
+
+ dev = to_visor_device(xdev);
+ drv = to_visor_driver(xdev->driver);
+ down(&dev->visordriver_callback_lock);
+ dev->being_removed = true;
+ /*
+ * ensure that the dev->being_removed flag is set before we start the
+ * actual removal
+ */
+ wmb();
+ if (drv) {
+ if (drv->remove)
+ drv->remove(dev);
+ }
+ up(&dev->visordriver_callback_lock);
+ dev_stop_periodic_work(dev);
+ devmajorminor_remove_all_files(dev);
+
+ put_device(&dev->device);
+
+ return 0;
+}
+
+/** A particular type of visor driver calls this function to register
+ * the driver. The caller MUST fill in the following fields within the
+ * #drv structure:
+ * name, version, owner, channel_types, probe, remove
+ *
+ * Here's how the whole Linux bus / driver / device model works.
+ *
+ * At system start-up, the visorbus kernel module is loaded, which registers
+ * visorbus_type as a bus type, using bus_register().
+ *
+ * All kernel modules that support particular device types on a
+ * visorbus bus are loaded. Each of these kernel modules calls
+ * visorbus_register_visor_driver() in their init functions, passing a
+ * visor_driver struct. visorbus_register_visor_driver() in turn calls
+ * register_driver(&visor_driver.driver). This .driver member is
+ * initialized with generic methods (like probe), whose sole responsibility
+ * is to act as a broker for the real methods, which are within the
+ * visor_driver struct. (This is the way the subclass behavior is
+ * implemented, since visor_driver is essentially a subclass of the
+ * generic driver.) Whenever a driver_register() happens, core bus code in
+ * the kernel does (see device_attach() in drivers/base/dd.c):
+ *
+ * for each dev associated with the bus (the bus that driver is on) that
+ * does not yet have a driver
+ * if bus.match(dev,newdriver) == yes_matched ** .match specified
+ * ** during bus_register().
+ * newdriver.probe(dev) ** for visor drivers, this will call
+ * ** the generic driver.probe implemented in visorbus.c,
+ * ** which in turn calls the probe specified within the
+ * ** struct visor_driver (which was specified by the
+ * ** actual device driver as part of
+ * ** visorbus_register_visor_driver()).
+ *
+ * The above dance also happens when a new device appears.
+ * So the question is, how are devices created within the system?
+ * Basically, just call device_add(dev). See pci_bus_add_devices().
+ * pci_scan_device() shows an example of how to build a device struct. It
+ * returns the newly-created struct to pci_scan_single_device(), who adds it
+ * to the list of devices at PCIBUS.devices. That list of devices is what
+ * is traversed by pci_bus_add_devices().
+ *
+ */
+int visorbus_register_visor_driver(struct visor_driver *drv)
+{
+ int rc = 0;
+
+ drv->driver.name = drv->name;
+ drv->driver.bus = &visorbus_type;
+ drv->driver.probe = visordriver_probe_device;
+ drv->driver.remove = visordriver_remove_device;
+ drv->driver.owner = drv->owner;
+
+ /* driver_register does this:
+ * bus_add_driver(drv)
+ * ->if (drv.bus) ** (bus_type) **
+ * driver_attach(drv)
+ * for each dev with bus type of drv.bus
+ * if (!dev.drv) ** no driver assigned yet **
+ * if (bus.match(dev,drv)) [visorbus_match]
+ * dev.drv = drv
+ * if (!drv.probe(dev)) [visordriver_probe_device]
+ * dev.drv = NULL
+ */
+
+ rc = driver_register(&drv->driver);
+ if (rc < 0)
+ return rc;
+ rc = register_driver_attributes(drv);
+ return rc;
+}
+EXPORT_SYMBOL_GPL(visorbus_register_visor_driver);
+
+/** A particular type of visor driver calls this function to unregister
+ * the driver, i.e., within its module_exit function.
+ */
+void
+visorbus_unregister_visor_driver(struct visor_driver *drv)
+{
+ unregister_driver_attributes(drv);
+ driver_unregister(&drv->driver);
+}
+EXPORT_SYMBOL_GPL(visorbus_unregister_visor_driver);
+
+int
+visorbus_read_channel(struct visor_device *dev, unsigned long offset,
+ void *dest, unsigned long nbytes)
+{
+ return visorchannel_read(dev->visorchannel, offset, dest, nbytes);
+}
+EXPORT_SYMBOL_GPL(visorbus_read_channel);
+
+int
+visorbus_write_channel(struct visor_device *dev, unsigned long offset,
+ void *src, unsigned long nbytes)
+{
+ return visorchannel_write(dev->visorchannel, offset, src, nbytes);
+}
+EXPORT_SYMBOL_GPL(visorbus_write_channel);
+
+int
+visorbus_clear_channel(struct visor_device *dev, unsigned long offset, u8 ch,
+ unsigned long nbytes)
+{
+ return visorchannel_clear(dev->visorchannel, offset, ch, nbytes);
+}
+EXPORT_SYMBOL_GPL(visorbus_clear_channel);
+
+int
+visorbus_registerdevnode(struct visor_device *dev,
+ const char *name, int major, int minor)
+{
+ return devmajorminor_create_file(dev, name, major, minor);
+}
+EXPORT_SYMBOL_GPL(visorbus_registerdevnode);
+
+/** We don't really have a real interrupt, so for now we just call the
+ * interrupt function periodically...
+ */
+void
+visorbus_enable_channel_interrupts(struct visor_device *dev)
+{
+ dev_start_periodic_work(dev);
+}
+EXPORT_SYMBOL_GPL(visorbus_enable_channel_interrupts);
+
+void
+visorbus_disable_channel_interrupts(struct visor_device *dev)
+{
+ dev_stop_periodic_work(dev);
+}
+EXPORT_SYMBOL_GPL(visorbus_disable_channel_interrupts);
+
+/** This is how everything starts from the device end.
+ * This function is called when a channel first appears via a ControlVM
+ * message. In response, this function allocates a visor_device to
+ * correspond to the new channel, and attempts to connect it the appropriate
+ * driver. If the appropriate driver is found, the visor_driver.probe()
+ * function for that driver will be called, and will be passed the new
+ * visor_device that we just created.
+ *
+ * It's ok if the appropriate driver is not yet loaded, because in that case
+ * the new device struct will just stick around in the bus' list of devices.
+ * When the appropriate driver calls visorbus_register_visor_driver(), the
+ * visor_driver.probe() for the new driver will be called with the new
+ * device.
+ */
+static int
+create_visor_device(struct visor_device *dev)
+{
+ int rc = -1;
+ u32 chipset_bus_no = dev->chipset_bus_no;
+ u32 chipset_dev_no = dev->chipset_dev_no;
+
+ POSTCODE_LINUX_4(DEVICE_CREATE_ENTRY_PC, chipset_dev_no, chipset_bus_no,
+ POSTCODE_SEVERITY_INFO);
+
+ sema_init(&dev->visordriver_callback_lock, 1); /* unlocked */
+ dev->device.bus = &visorbus_type;
+ dev->device.groups = visorbus_dev_groups;
+ device_initialize(&dev->device);
+ dev->device.release = visorbus_release_device;
+ /* keep a reference just for us (now 2) */
+ get_device(&dev->device);
+ dev->periodic_work =
+ visor_periodic_work_create(POLLJIFFIES_NORMALCHANNEL,
+ periodic_dev_workqueue,
+ dev_periodic_work,
+ dev, dev_name(&dev->device));
+ if (!dev->periodic_work) {
+ POSTCODE_LINUX_3(DEVICE_CREATE_FAILURE_PC, chipset_dev_no,
+ DIAG_SEVERITY_ERR);
+ goto away;
+ }
+
+ /* bus_id must be a unique name with respect to this bus TYPE
+ * (NOT bus instance). That's why we need to include the bus
+ * number within the name.
+ */
+ dev_set_name(&dev->device, "vbus%u:dev%u",
+ chipset_bus_no, chipset_dev_no);
+
+ /* device_add does this:
+ * bus_add_device(dev)
+ * ->device_attach(dev)
+ * ->for each driver drv registered on the bus that dev is on
+ * if (dev.drv) ** device already has a driver **
+ * ** not sure we could ever get here... **
+ * else
+ * if (bus.match(dev,drv)) [visorbus_match]
+ * dev.drv = drv
+ * if (!drv.probe(dev)) [visordriver_probe_device]
+ * dev.drv = NULL
+ *
+ * Note that device_add does NOT fail if no driver failed to
+ * claim the device. The device will be linked onto
+ * bus_type.klist_devices regardless (use bus_for_each_dev).
+ */
+ rc = device_add(&dev->device);
+ if (rc < 0) {
+ POSTCODE_LINUX_3(DEVICE_ADD_PC, chipset_bus_no,
+ DIAG_SEVERITY_ERR);
+ goto away;
+ }
+
+ rc = register_devmajorminor_attributes(dev);
+ if (rc < 0) {
+ POSTCODE_LINUX_3(DEVICE_REGISTER_FAILURE_PC, chipset_dev_no,
+ DIAG_SEVERITY_ERR);
+ goto away_register;
+ }
+
+ list_add_tail(&dev->list_all, &list_all_device_instances);
+ return 0;
+
+away_register:
+ device_unregister(&dev->device);
+away:
+ put_device(&dev->device);
+ return rc;
+}
+
+static void
+remove_visor_device(struct visor_device *dev)
+{
+ list_del(&dev->list_all);
+ unregister_devmajorminor_attributes(dev);
+ put_device(&dev->device);
+ device_unregister(&dev->device);
+}
+
+static int
+get_vbus_header_info(struct visorchannel *chan,
+ struct spar_vbus_headerinfo *hdr_info)
+{
+ int rc = -1;
+
+ if (!SPAR_VBUS_CHANNEL_OK_CLIENT(visorchannel_get_header(chan)))
+ goto away;
+ if (visorchannel_read(chan, sizeof(struct channel_header), hdr_info,
+ sizeof(*hdr_info)) < 0) {
+ goto away;
+ }
+ if (hdr_info->struct_bytes < sizeof(struct spar_vbus_headerinfo))
+ goto away;
+ if (hdr_info->device_info_struct_bytes <
+ sizeof(struct ultra_vbus_deviceinfo)) {
+ goto away;
+ }
+ rc = 0;
+away:
+ return rc;
+}
+
+/* Write the contents of <info> to the struct
+ * spar_vbus_channel_protocol.chp_info. */
+
+static int
+write_vbus_chp_info(struct visorchannel *chan,
+ struct spar_vbus_headerinfo *hdr_info,
+ struct ultra_vbus_deviceinfo *info)
+{
+ int off = sizeof(struct channel_header) + hdr_info->chp_info_offset;
+
+ if (hdr_info->chp_info_offset == 0)
+ return -1;
+
+ if (visorchannel_write(chan, off, info, sizeof(*info)) < 0)
+ return -1;
+ return 0;
+}
+
+/* Write the contents of <info> to the struct
+ * spar_vbus_channel_protocol.bus_info. */
+
+static int
+write_vbus_bus_info(struct visorchannel *chan,
+ struct spar_vbus_headerinfo *hdr_info,
+ struct ultra_vbus_deviceinfo *info)
+{
+ int off = sizeof(struct channel_header) + hdr_info->bus_info_offset;
+
+ if (hdr_info->bus_info_offset == 0)
+ return -1;
+
+ if (visorchannel_write(chan, off, info, sizeof(*info)) < 0)
+ return -1;
+ return 0;
+}
+
+/* Write the contents of <info> to the
+ * struct spar_vbus_channel_protocol.dev_info[<devix>].
+ */
+static int
+write_vbus_dev_info(struct visorchannel *chan,
+ struct spar_vbus_headerinfo *hdr_info,
+ struct ultra_vbus_deviceinfo *info, int devix)
+{
+ int off =
+ (sizeof(struct channel_header) + hdr_info->dev_info_offset) +
+ (hdr_info->device_info_struct_bytes * devix);
+
+ if (hdr_info->dev_info_offset == 0)
+ return -1;
+
+ if (visorchannel_write(chan, off, info, sizeof(*info)) < 0)
+ return -1;
+ return 0;
+}
+
+/* For a child device just created on a client bus, fill in
+ * information about the driver that is controlling this device into
+ * the the appropriate slot within the vbus channel of the bus
+ * instance.
+ */
+static void
+fix_vbus_dev_info(struct visor_device *visordev)
+{
+ int i;
+ struct visor_device *bdev;
+ struct visor_driver *visordrv;
+ int bus_no = visordev->chipset_bus_no;
+ int dev_no = visordev->chipset_dev_no;
+ struct ultra_vbus_deviceinfo dev_info;
+ const char *chan_type_name = NULL;
+ struct spar_vbus_headerinfo *hdr_info;
+
+ if (!visordev->device.driver)
+ return;
+
+ hdr_info = (struct spar_vbus_headerinfo *)visordev->vbus_hdr_info;
+ if (!hdr_info)
+ return;
+
+ bdev = visorbus_get_device_by_id(bus_no, BUS_ROOT_DEVICE, NULL);
+ if (!bdev)
+ return;
+
+ visordrv = to_visor_driver(visordev->device.driver);
+
+ /* Within the list of device types (by GUID) that the driver
+ * says it supports, find out which one of those types matches
+ * the type of this device, so that we can include the device
+ * type name
+ */
+ for (i = 0; visordrv->channel_types[i].name; i++) {
+ if (memcmp(&visordrv->channel_types[i].guid,
+ &visordev->channel_type_guid,
+ sizeof(visordrv->channel_types[i].guid)) == 0) {
+ chan_type_name = visordrv->channel_types[i].name;
+ break;
+ }
+ }
+
+ bus_device_info_init(&dev_info, chan_type_name,
+ visordrv->name, visordrv->version,
+ visordrv->vertag);
+ write_vbus_dev_info(bdev->visorchannel, hdr_info, &dev_info, dev_no);
+
+ /* Re-write bus+chipset info, because it is possible that this
+ * was previously written by our evil counterpart, virtpci.
+ */
+ write_vbus_chp_info(bdev->visorchannel, hdr_info, &chipset_driverinfo);
+ write_vbus_bus_info(bdev->visorchannel, hdr_info,
+ &clientbus_driverinfo);
+}
+
+/** Create a device instance for the visor bus itself.
+ */
+static int
+create_bus_instance(struct visor_device *dev)
+{
+ int rc;
+ int id = dev->chipset_bus_no;
+ struct spar_vbus_headerinfo *hdr_info;
+
+ POSTCODE_LINUX_2(BUS_CREATE_ENTRY_PC, POSTCODE_SEVERITY_INFO);
+
+ hdr_info = kzalloc(sizeof(*hdr_info), GFP_KERNEL);
+ if (!hdr_info) {
+ rc = -1;
+ goto away;
+ }
+
+ dev_set_name(&dev->device, "visorbus%d", id);
+ dev->device.bus = &visorbus_type;
+ dev->device.groups = visorbus_groups;
+ dev->device.release = visorbus_release_busdevice;
+
+ if (device_register(&dev->device) < 0) {
+ POSTCODE_LINUX_3(DEVICE_CREATE_FAILURE_PC, id,
+ POSTCODE_SEVERITY_ERR);
+ rc = -1;
+ goto away_mem;
+ }
+
+ if (get_vbus_header_info(dev->visorchannel, hdr_info) >= 0) {
+ dev->vbus_hdr_info = (void *)hdr_info;
+ write_vbus_chp_info(dev->visorchannel, hdr_info,
+ &chipset_driverinfo);
+ write_vbus_bus_info(dev->visorchannel, hdr_info,
+ &clientbus_driverinfo);
+ } else {
+ kfree(hdr_info);
+ }
+ bus_count++;
+ list_add_tail(&dev->list_all, &list_all_bus_instances);
+ dev_set_drvdata(&dev->device, dev);
+ return 0;
+
+away_mem:
+ kfree(hdr_info);
+away:
+ return rc;
+}
+
+/** Remove a device instance for the visor bus itself.
+ */
+static void
+remove_bus_instance(struct visor_device *dev)
+{
+ /* Note that this will result in the release method for
+ * dev->dev being called, which will call
+ * visorbus_release_busdevice(). This has something to do with
+ * the put_device() done in device_unregister(), but I have never
+ * successfully been able to trace thru the code to see where/how
+ * release() gets called. But I know it does.
+ */
+ bus_count--;
+ if (dev->visorchannel) {
+ visorchannel_destroy(dev->visorchannel);
+ dev->visorchannel = NULL;
+ }
+ kfree(dev->vbus_hdr_info);
+ list_del(&dev->list_all);
+ device_unregister(&dev->device);
+}
+
+/** Create and register the one-and-only one instance of
+ * the visor bus type (visorbus_type).
+ */
+static int
+create_bus_type(void)
+{
+ int rc = 0;
+
+ rc = bus_register(&visorbus_type);
+ return rc;
+}
+
+/** Remove the one-and-only one instance of the visor bus type (visorbus_type).
+ */
+static void
+remove_bus_type(void)
+{
+ bus_unregister(&visorbus_type);
+}
+
+/** Remove all child visor bus device instances.
+ */
+static void
+remove_all_visor_devices(void)
+{
+ struct list_head *listentry, *listtmp;
+
+ list_for_each_safe(listentry, listtmp, &list_all_device_instances) {
+ struct visor_device *dev = list_entry(listentry,
+ struct visor_device,
+ list_all);
+ remove_visor_device(dev);
+ }
+}
+
+static void
+chipset_bus_create(struct visor_device *dev)
+{
+ int rc;
+ u32 bus_no = dev->chipset_bus_no;
+
+ POSTCODE_LINUX_3(BUS_CREATE_ENTRY_PC, bus_no, POSTCODE_SEVERITY_INFO);
+ rc = create_bus_instance(dev);
+ POSTCODE_LINUX_3(BUS_CREATE_EXIT_PC, bus_no, POSTCODE_SEVERITY_INFO);
+
+ if (rc < 0)
+ POSTCODE_LINUX_3(BUS_CREATE_FAILURE_PC, bus_no,
+ POSTCODE_SEVERITY_ERR);
+ else
+ POSTCODE_LINUX_3(CHIPSET_INIT_SUCCESS_PC, bus_no,
+ POSTCODE_SEVERITY_INFO);
+
+ if (chipset_responders.bus_create)
+ (*chipset_responders.bus_create) (dev, rc);
+}
+
+static void
+chipset_bus_destroy(struct visor_device *dev)
+{
+ remove_bus_instance(dev);
+ if (chipset_responders.bus_destroy)
+ (*chipset_responders.bus_destroy)(dev, 0);
+}
+
+static void
+chipset_device_create(struct visor_device *dev_info)
+{
+ int rc = -1;
+ u32 bus_no = dev_info->chipset_bus_no;
+ u32 dev_no = dev_info->chipset_dev_no;
+
+ POSTCODE_LINUX_4(DEVICE_CREATE_ENTRY_PC, dev_no, bus_no,
+ POSTCODE_SEVERITY_INFO);
+
+ rc = create_visor_device(dev_info);
+ if (chipset_responders.device_create)
+ chipset_responders.device_create(dev_info, rc);
+
+ if (rc < 0)
+ POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC, dev_no, bus_no,
+ POSTCODE_SEVERITY_ERR);
+ else
+ POSTCODE_LINUX_4(DEVICE_CREATE_SUCCESS_PC, dev_no, bus_no,
+ POSTCODE_SEVERITY_INFO);
+}
+
+static void
+chipset_device_destroy(struct visor_device *dev_info)
+{
+ remove_visor_device(dev_info);
+
+ if (chipset_responders.device_destroy)
+ (*chipset_responders.device_destroy) (dev_info, 0);
+}
+
+/* This is the callback function specified for a function driver, to
+ * be called when a pending "pause device" operation has been
+ * completed.
+ */
+static void
+pause_state_change_complete(struct visor_device *dev, int status)
+{
+ if (!dev->pausing)
+ return;
+
+ dev->pausing = false;
+ if (!chipset_responders.device_pause) /* this can never happen! */
+ return;
+
+ /* Notify the chipset driver that the pause is complete, which
+ * will presumably want to send some sort of response to the
+ * initiator. */
+ (*chipset_responders.device_pause) (dev, status);
+}
+
+/* This is the callback function specified for a function driver, to
+ * be called when a pending "resume device" operation has been
+ * completed.
+ */
+static void
+resume_state_change_complete(struct visor_device *dev, int status)
+{
+ if (!dev->resuming)
+ return;
+
+ dev->resuming = false;
+ if (!chipset_responders.device_resume) /* this can never happen! */
+ return;
+
+ /* Notify the chipset driver that the resume is complete,
+ * which will presumably want to send some sort of response to
+ * the initiator. */
+ (*chipset_responders.device_resume) (dev, status);
+}
+
+/* Tell the subordinate function driver for a specific device to pause
+ * or resume that device. Result is returned asynchronously via a
+ * callback function.
+ */
+static void
+initiate_chipset_device_pause_resume(struct visor_device *dev, bool is_pause)
+{
+ int rc = -1, x;
+ struct visor_driver *drv = NULL;
+ void (*notify_func)(struct visor_device *dev, int response) = NULL;
+
+ if (is_pause)
+ notify_func = chipset_responders.device_pause;
+ else
+ notify_func = chipset_responders.device_resume;
+ if (!notify_func)
+ goto away;
+
+ drv = to_visor_driver(dev->device.driver);
+ if (!drv)
+ goto away;
+
+ if (dev->pausing || dev->resuming)
+ goto away;
+
+ /* Note that even though both drv->pause() and drv->resume
+ * specify a callback function, it is NOT necessary for us to
+ * increment our local module usage count. Reason is, there
+ * is already a linkage dependency between child function
+ * drivers and visorbus, so it is already IMPOSSIBLE to unload
+ * visorbus while child function drivers are still running.
+ */
+ if (is_pause) {
+ if (!drv->pause)
+ goto away;
+
+ dev->pausing = true;
+ x = drv->pause(dev, pause_state_change_complete);
+ } else {
+ /* This should be done at BUS resume time, but an
+ * existing problem prevents us from ever getting a bus
+ * resume... This hack would fail to work should we
+ * ever have a bus that contains NO devices, since we
+ * would never even get here in that case. */
+ fix_vbus_dev_info(dev);
+ if (!drv->resume)
+ goto away;
+
+ dev->resuming = true;
+ x = drv->resume(dev, resume_state_change_complete);
+ }
+ if (x < 0) {
+ if (is_pause)
+ dev->pausing = false;
+ else
+ dev->resuming = false;
+ goto away;
+ }
+ rc = 0;
+away:
+ if (rc < 0) {
+ if (notify_func)
+ (*notify_func)(dev, rc);
+ }
+}
+
+static void
+chipset_device_pause(struct visor_device *dev_info)
+{
+ initiate_chipset_device_pause_resume(dev_info, true);
+}
+
+static void
+chipset_device_resume(struct visor_device *dev_info)
+{
+ initiate_chipset_device_pause_resume(dev_info, false);
+}
+
+struct channel_size_info {
+ uuid_le guid;
+ unsigned long min_size;
+ unsigned long max_size;
+};
+
+int
+visorbus_init(void)
+{
+ int rc = 0;
+
+ POSTCODE_LINUX_3(DRIVER_ENTRY_PC, rc, POSTCODE_SEVERITY_INFO);
+ bus_device_info_init(&clientbus_driverinfo,
+ "clientbus", "visorbus",
+ VERSION, NULL);
+
+ rc = create_bus_type();
+ if (rc < 0) {
+ POSTCODE_LINUX_2(BUS_CREATE_ENTRY_PC, DIAG_SEVERITY_ERR);
+ goto away;
+ }
+
+ periodic_dev_workqueue = create_singlethread_workqueue("visorbus_dev");
+ if (!periodic_dev_workqueue) {
+ POSTCODE_LINUX_2(CREATE_WORKQUEUE_PC, DIAG_SEVERITY_ERR);
+ rc = -ENOMEM;
+ goto away;
+ }
+
+ /* This enables us to receive notifications when devices appear for
+ * which this service partition is to be a server for.
+ */
+ visorchipset_register_busdev(&chipset_notifiers,
+ &chipset_responders,
+ &chipset_driverinfo);
+
+ rc = 0;
+
+away:
+ if (rc)
+ POSTCODE_LINUX_3(CHIPSET_INIT_FAILURE_PC, rc,
+ POSTCODE_SEVERITY_ERR);
+ return rc;
+}
+
+void
+visorbus_exit(void)
+{
+ struct list_head *listentry, *listtmp;
+
+ visorchipset_register_busdev(NULL, NULL, NULL);
+ remove_all_visor_devices();
+
+ flush_workqueue(periodic_dev_workqueue); /* better not be any work! */
+ destroy_workqueue(periodic_dev_workqueue);
+ periodic_dev_workqueue = NULL;
+
+ if (periodic_test_workqueue) {
+ cancel_delayed_work(&periodic_work);
+ flush_workqueue(periodic_test_workqueue);
+ destroy_workqueue(periodic_test_workqueue);
+ periodic_test_workqueue = NULL;
+ }
+
+ list_for_each_safe(listentry, listtmp, &list_all_bus_instances) {
+ struct visor_device *dev = list_entry(listentry,
+ struct
+ visor_device,
+ list_all);
+ remove_bus_instance(dev);
+ }
+ remove_bus_type();
+}
+
+module_param_named(debug, visorbus_debug, int, S_IRUGO);
+MODULE_PARM_DESC(visorbus_debug, "1 to debug");
+
+module_param_named(forcematch, visorbus_forcematch, int, S_IRUGO);
+MODULE_PARM_DESC(visorbus_forcematch,
+ "1 to force a successful dev <--> drv match");
+
+module_param_named(forcenomatch, visorbus_forcenomatch, int, S_IRUGO);
+MODULE_PARM_DESC(visorbus_forcenomatch,
+ "1 to force an UNsuccessful dev <--> drv match");
+
+module_param_named(debugref, visorbus_debugref, int, S_IRUGO);
+MODULE_PARM_DESC(visorbus_debugref, "1 to debug reference counting");
diff --git a/drivers/staging/unisys/visorbus/visorbus_private.h b/drivers/staging/unisys/visorbus/visorbus_private.h
new file mode 100644
index 000000000..2f12483e3
--- /dev/null
+++ b/drivers/staging/unisys/visorbus/visorbus_private.h
@@ -0,0 +1,69 @@
+/* visorchipset.h
+ *
+ * Copyright (C) 2010 - 2013 UNISYS CORPORATION
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ */
+
+#ifndef __VISORCHIPSET_H__
+#define __VISORCHIPSET_H__
+
+#include <linux/uuid.h>
+
+#include "controlvmchannel.h"
+#include "vbusdeviceinfo.h"
+#include "vbushelper.h"
+
+/* These functions will be called from within visorchipset when certain
+ * events happen. (The implementation of these functions is outside of
+ * visorchipset.)
+ */
+struct visorchipset_busdev_notifiers {
+ void (*bus_create)(struct visor_device *bus_info);
+ void (*bus_destroy)(struct visor_device *bus_info);
+ void (*device_create)(struct visor_device *bus_info);
+ void (*device_destroy)(struct visor_device *bus_info);
+ void (*device_pause)(struct visor_device *bus_info);
+ void (*device_resume)(struct visor_device *bus_info);
+};
+
+/* These functions live inside visorchipset, and will be called to indicate
+ * responses to specific events (by code outside of visorchipset).
+ * For now, the value for each response is simply either:
+ * 0 = it worked
+ * -1 = it failed
+ */
+struct visorchipset_busdev_responders {
+ void (*bus_create)(struct visor_device *p, int response);
+ void (*bus_destroy)(struct visor_device *p, int response);
+ void (*device_create)(struct visor_device *p, int response);
+ void (*device_destroy)(struct visor_device *p, int response);
+ void (*device_pause)(struct visor_device *p, int response);
+ void (*device_resume)(struct visor_device *p, int response);
+};
+
+/** Register functions (in the bus driver) to get called by visorchipset
+ * whenever a bus or device appears for which this guest is to be the
+ * client for. visorchipset will fill in <responders>, to indicate
+ * functions the bus driver should call to indicate message responses.
+ */
+void
+visorchipset_register_busdev(
+ struct visorchipset_busdev_notifiers *notifiers,
+ struct visorchipset_busdev_responders *responders,
+ struct ultra_vbus_deviceinfo *driver_info);
+
+/* visorbus init and exit functions */
+int visorbus_init(void);
+void visorbus_exit(void);
+#endif
diff --git a/drivers/staging/unisys/visorchannel/visorchannel_funcs.c b/drivers/staging/unisys/visorbus/visorchannel.c
index 7a9a7242f..20b63496e 100644
--- a/drivers/staging/unisys/visorchannel/visorchannel_funcs.c
+++ b/drivers/staging/unisys/visorbus/visorchannel.c
@@ -17,23 +17,31 @@
/*
* This provides Supervisor channel communication primitives, which are
- * independent of the mechanism used to access the channel data. All channel
- * data is accessed using the memregion abstraction. (memregion has both
- * a CM2 implementation and a direct memory implementation.)
+ * independent of the mechanism used to access the channel data.
*/
-#include "globals.h"
-#include "visorchannel.h"
#include <linux/uuid.h>
+#include "version.h"
+#include "visorbus.h"
+#include "controlvmchannel.h"
+
#define MYDRVNAME "visorchannel"
+#define SPAR_CONSOLEVIDEO_CHANNEL_PROTOCOL_GUID \
+ UUID_LE(0x3cd6e705, 0xd6a2, 0x4aa5, \
+ 0xad, 0x5c, 0x7b, 0x8, 0x88, 0x9d, 0xff, 0xe2)
+static const uuid_le spar_video_guid = SPAR_CONSOLEVIDEO_CHANNEL_PROTOCOL_GUID;
+
struct visorchannel {
- struct memregion *memregion; /* from visor_memregion_create() */
+ u64 physaddr;
+ ulong nbytes;
+ void __iomem *mapped;
+ bool requested;
struct channel_header chan_hdr;
uuid_le guid;
ulong size;
- BOOL needs_lock; /* channel creator knows if more than one
+ bool needs_lock; /* channel creator knows if more than one
* thread will be inserting or removing */
spinlock_t insert_lock; /* protect head writes in chan_hdr */
spinlock_t remove_lock; /* protect tail writes in chan_hdr */
@@ -44,126 +52,133 @@ struct visorchannel {
struct signal_queue_header event_queue;
struct signal_queue_header ack_queue;
} safe_uis_queue;
+ uuid_le type;
+ uuid_le inst;
};
/* Creates the struct visorchannel abstraction for a data area in memory,
* but does NOT modify this data area.
*/
static struct visorchannel *
-visorchannel_create_guts(HOSTADDRESS physaddr, ulong channel_bytes,
- struct visorchannel *parent, ulong off, uuid_le guid,
- BOOL needs_lock)
+visorchannel_create_guts(u64 physaddr, unsigned long channel_bytes,
+ gfp_t gfp, unsigned long off,
+ uuid_le guid, bool needs_lock)
{
- struct visorchannel *p = NULL;
- void *rc = NULL;
+ struct visorchannel *channel;
+ int err;
+ size_t size = sizeof(struct channel_header);
+
+ if (physaddr == 0)
+ return NULL;
- p = kmalloc(sizeof(*p), GFP_KERNEL|__GFP_NORETRY);
- if (!p) {
- rc = NULL;
+ channel = kzalloc(sizeof(*channel), gfp);
+ if (!channel)
goto cleanup;
+
+ channel->needs_lock = needs_lock;
+ spin_lock_init(&channel->insert_lock);
+ spin_lock_init(&channel->remove_lock);
+
+ /* Video driver constains the efi framebuffer so it will get a
+ * conflict resource when requesting its full mem region. Since
+ * we are only using the efi framebuffer for video we can ignore
+ * this. Remember that we haven't requested it so we don't try to
+ * release later on.
+ */
+ channel->requested = request_mem_region(physaddr, size, MYDRVNAME);
+ if (!channel->requested) {
+ if (uuid_le_cmp(guid, spar_video_guid)) {
+ /* Not the video channel we care about this */
+ goto cleanup;
+ }
}
- p->memregion = NULL;
- p->needs_lock = needs_lock;
- spin_lock_init(&p->insert_lock);
- spin_lock_init(&p->remove_lock);
-
- /* prepare chan_hdr (abstraction to read/write channel memory) */
- if (!parent)
- p->memregion =
- visor_memregion_create(physaddr,
- sizeof(struct channel_header));
- else
- p->memregion =
- visor_memregion_create_overlapped(parent->memregion,
- off, sizeof(struct channel_header));
- if (!p->memregion) {
- rc = NULL;
+
+ channel->mapped = ioremap_cache(physaddr, size);
+ if (!channel->mapped) {
+ release_mem_region(physaddr, size);
goto cleanup;
}
- if (visor_memregion_read(p->memregion, 0, &p->chan_hdr,
- sizeof(struct channel_header)) < 0) {
- rc = NULL;
+
+ channel->physaddr = physaddr;
+ channel->nbytes = size;
+
+ err = visorchannel_read(channel, 0, &channel->chan_hdr,
+ sizeof(struct channel_header));
+ if (err)
goto cleanup;
- }
+
+ /* we had better be a CLIENT of this channel */
if (channel_bytes == 0)
- /* we had better be a CLIENT of this channel */
- channel_bytes = (ulong)p->chan_hdr.size;
+ channel_bytes = (ulong)channel->chan_hdr.size;
if (uuid_le_cmp(guid, NULL_UUID_LE) == 0)
- /* we had better be a CLIENT of this channel */
- guid = p->chan_hdr.chtype;
- if (visor_memregion_resize(p->memregion, channel_bytes) < 0) {
- rc = NULL;
+ guid = channel->chan_hdr.chtype;
+
+ iounmap(channel->mapped);
+ if (channel->requested)
+ release_mem_region(channel->physaddr, channel->nbytes);
+ channel->mapped = NULL;
+ channel->requested = request_mem_region(channel->physaddr,
+ channel_bytes, MYDRVNAME);
+ if (!channel->requested) {
+ if (uuid_le_cmp(guid, spar_video_guid)) {
+ /* Different we care about this */
+ goto cleanup;
+ }
+ }
+
+ channel->mapped = ioremap_cache(channel->physaddr, channel_bytes);
+ if (!channel->mapped) {
+ release_mem_region(channel->physaddr, channel_bytes);
goto cleanup;
}
- p->size = channel_bytes;
- p->guid = guid;
- rc = p;
-cleanup:
+ channel->nbytes = channel_bytes;
- if (!rc) {
- if (!p) {
- visorchannel_destroy(p);
- p = NULL;
- }
- }
- return rc;
+ channel->size = channel_bytes;
+ channel->guid = guid;
+ return channel;
+
+cleanup:
+ visorchannel_destroy(channel);
+ return NULL;
}
struct visorchannel *
-visorchannel_create(HOSTADDRESS physaddr, ulong channel_bytes, uuid_le guid)
+visorchannel_create(u64 physaddr, unsigned long channel_bytes,
+ gfp_t gfp, uuid_le guid)
{
- return visorchannel_create_guts(physaddr, channel_bytes, NULL, 0, guid,
- FALSE);
+ return visorchannel_create_guts(physaddr, channel_bytes, gfp, 0, guid,
+ false);
}
EXPORT_SYMBOL_GPL(visorchannel_create);
struct visorchannel *
-visorchannel_create_with_lock(HOSTADDRESS physaddr, ulong channel_bytes,
- uuid_le guid)
+visorchannel_create_with_lock(u64 physaddr, unsigned long channel_bytes,
+ gfp_t gfp, uuid_le guid)
{
- return visorchannel_create_guts(physaddr, channel_bytes, NULL, 0, guid,
- TRUE);
+ return visorchannel_create_guts(physaddr, channel_bytes, gfp, 0, guid,
+ true);
}
EXPORT_SYMBOL_GPL(visorchannel_create_with_lock);
-struct visorchannel *
-visorchannel_create_overlapped(ulong channel_bytes,
- struct visorchannel *parent, ulong off,
- uuid_le guid)
-{
- return visorchannel_create_guts(0, channel_bytes, parent, off, guid,
- FALSE);
-}
-EXPORT_SYMBOL_GPL(visorchannel_create_overlapped);
-
-struct visorchannel *
-visorchannel_create_overlapped_with_lock(ulong channel_bytes,
- struct visorchannel *parent, ulong off,
- uuid_le guid)
-{
- return visorchannel_create_guts(0, channel_bytes, parent, off, guid,
- TRUE);
-}
-EXPORT_SYMBOL_GPL(visorchannel_create_overlapped_with_lock);
-
void
visorchannel_destroy(struct visorchannel *channel)
{
if (!channel)
return;
- if (channel->memregion) {
- visor_memregion_destroy(channel->memregion);
- channel->memregion = NULL;
+ if (channel->mapped) {
+ iounmap(channel->mapped);
+ if (channel->requested)
+ release_mem_region(channel->physaddr, channel->nbytes);
}
kfree(channel);
}
EXPORT_SYMBOL_GPL(visorchannel_destroy);
-HOSTADDRESS
+u64
visorchannel_get_physaddr(struct visorchannel *channel)
{
- return visor_memregion_get_physaddr(channel->memregion);
+ return channel->physaddr;
}
EXPORT_SYMBOL_GPL(visorchannel_get_physaddr);
@@ -196,13 +211,22 @@ visorchannel_zoneid(struct visorchannel *channel, char *s)
}
EXPORT_SYMBOL_GPL(visorchannel_zoneid);
-HOSTADDRESS
+u64
visorchannel_get_clientpartition(struct visorchannel *channel)
{
return channel->chan_hdr.partition_handle;
}
EXPORT_SYMBOL_GPL(visorchannel_get_clientpartition);
+int
+visorchannel_set_clientpartition(struct visorchannel *channel,
+ u64 partition_handle)
+{
+ channel->chan_hdr.partition_handle = partition_handle;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(visorchannel_set_clientpartition);
+
uuid_le
visorchannel_get_uuid(struct visorchannel *channel)
{
@@ -210,25 +234,16 @@ visorchannel_get_uuid(struct visorchannel *channel)
}
EXPORT_SYMBOL_GPL(visorchannel_get_uuid);
-struct memregion *
-visorchannel_get_memregion(struct visorchannel *channel)
-{
- return channel->memregion;
-}
-EXPORT_SYMBOL_GPL(visorchannel_get_memregion);
-
int
visorchannel_read(struct visorchannel *channel, ulong offset,
void *local, ulong nbytes)
{
- int rc = visor_memregion_read(channel->memregion, offset,
- local, nbytes);
- if ((rc >= 0) && (offset == 0) &&
- (nbytes >= sizeof(struct channel_header))) {
- memcpy(&channel->chan_hdr, local,
- sizeof(struct channel_header));
- }
- return rc;
+ if (offset + nbytes > channel->nbytes)
+ return -EIO;
+
+ memcpy_fromio(local, channel->mapped + offset, nbytes);
+
+ return 0;
}
EXPORT_SYMBOL_GPL(visorchannel_read);
@@ -236,10 +251,20 @@ int
visorchannel_write(struct visorchannel *channel, ulong offset,
void *local, ulong nbytes)
{
- if (offset == 0 && nbytes >= sizeof(struct channel_header))
- memcpy(&channel->chan_hdr, local,
- sizeof(struct channel_header));
- return visor_memregion_write(channel->memregion, offset, local, nbytes);
+ size_t chdr_size = sizeof(struct channel_header);
+ size_t copy_size;
+
+ if (offset + nbytes > channel->nbytes)
+ return -EIO;
+
+ if (offset < chdr_size) {
+ copy_size = min(chdr_size - offset, nbytes);
+ memcpy(&channel->chan_hdr + offset, local, copy_size);
+ }
+
+ memcpy_toio(channel->mapped + offset, local, nbytes);
+
+ return 0;
}
EXPORT_SYMBOL_GPL(visorchannel_write);
@@ -247,38 +272,35 @@ int
visorchannel_clear(struct visorchannel *channel, ulong offset, u8 ch,
ulong nbytes)
{
- int rc = -1;
- int bufsize = 65536;
+ int err;
+ int bufsize = PAGE_SIZE;
int written = 0;
- u8 *buf = vmalloc(bufsize);
+ u8 *buf;
+ buf = (u8 *) __get_free_page(GFP_KERNEL);
if (!buf)
- goto cleanup;
+ return -ENOMEM;
memset(buf, ch, bufsize);
+
while (nbytes > 0) {
- ulong thisbytes = bufsize;
- int x = -1;
+ int thisbytes = bufsize;
if (nbytes < thisbytes)
thisbytes = nbytes;
- x = visor_memregion_write(channel->memregion, offset + written,
- buf, thisbytes);
- if (x < 0) {
- rc = x;
+ err = visorchannel_write(channel, offset + written,
+ buf, thisbytes);
+ if (err)
goto cleanup;
- }
+
written += thisbytes;
nbytes -= thisbytes;
}
- rc = 0;
+ err = 0;
cleanup:
- if (buf) {
- vfree(buf);
- buf = NULL;
- }
- return rc;
+ free_page((unsigned long) buf);
+ return err;
}
EXPORT_SYMBOL_GPL(visorchannel_clear);
@@ -306,108 +328,77 @@ EXPORT_SYMBOL_GPL(visorchannel_get_header);
/** Write the contents of a specific field within a SIGNAL_QUEUE_HEADER back
* into host memory
*/
-#define SIG_WRITE_FIELD(channel, queue, sig_hdr, FIELD) \
- (visor_memregion_write(channel->memregion, \
- SIG_QUEUE_OFFSET(&channel->chan_hdr, queue)+ \
- offsetof(struct signal_queue_header, FIELD),\
- &((sig_hdr)->FIELD), \
- sizeof((sig_hdr)->FIELD)) >= 0)
-
-static BOOL
+#define SIG_WRITE_FIELD(channel, queue, sig_hdr, FIELD) \
+ (visorchannel_write(channel, \
+ SIG_QUEUE_OFFSET(&channel->chan_hdr, queue)+ \
+ offsetof(struct signal_queue_header, FIELD), \
+ &((sig_hdr)->FIELD), \
+ sizeof((sig_hdr)->FIELD)) >= 0)
+
+static bool
sig_read_header(struct visorchannel *channel, u32 queue,
struct signal_queue_header *sig_hdr)
{
- BOOL rc = FALSE;
+ int err;
if (channel->chan_hdr.ch_space_offset < sizeof(struct channel_header))
- goto cleanup;
+ return false;
/* Read the appropriate SIGNAL_QUEUE_HEADER into local memory. */
+ err = visorchannel_read(channel,
+ SIG_QUEUE_OFFSET(&channel->chan_hdr, queue),
+ sig_hdr, sizeof(struct signal_queue_header));
+ if (err)
+ return false;
- if (visor_memregion_read(channel->memregion,
- SIG_QUEUE_OFFSET(&channel->chan_hdr, queue),
- sig_hdr,
- sizeof(struct signal_queue_header)) < 0) {
- goto cleanup;
- }
- rc = TRUE;
-cleanup:
- return rc;
+ return true;
}
-static BOOL
-sig_do_data(struct visorchannel *channel, u32 queue,
- struct signal_queue_header *sig_hdr, u32 slot, void *data,
- BOOL is_write)
+static inline bool
+sig_read_data(struct visorchannel *channel, u32 queue,
+ struct signal_queue_header *sig_hdr, u32 slot, void *data)
{
- BOOL rc = FALSE;
+ int err;
int signal_data_offset = SIG_DATA_OFFSET(&channel->chan_hdr, queue,
sig_hdr, slot);
- if (is_write) {
- if (visor_memregion_write(channel->memregion,
- signal_data_offset,
- data, sig_hdr->signal_size) < 0) {
- goto cleanup;
- }
- } else {
- if (visor_memregion_read(channel->memregion, signal_data_offset,
- data, sig_hdr->signal_size) < 0) {
- goto cleanup;
- }
- }
- rc = TRUE;
-cleanup:
- return rc;
-}
-static inline BOOL
-sig_read_data(struct visorchannel *channel, u32 queue,
- struct signal_queue_header *sig_hdr, u32 slot, void *data)
-{
- return sig_do_data(channel, queue, sig_hdr, slot, data, FALSE);
+ err = visorchannel_read(channel, signal_data_offset,
+ data, sig_hdr->signal_size);
+ if (err)
+ return false;
+
+ return true;
}
-static inline BOOL
+static inline bool
sig_write_data(struct visorchannel *channel, u32 queue,
struct signal_queue_header *sig_hdr, u32 slot, void *data)
{
- return sig_do_data(channel, queue, sig_hdr, slot, data, TRUE);
-}
-
-static inline unsigned char
-safe_sig_queue_validate(struct signal_queue_header *psafe_sqh,
- struct signal_queue_header *punsafe_sqh,
- u32 *phead, u32 *ptail)
-{
- if ((*phead >= psafe_sqh->max_slots) ||
- (*ptail >= psafe_sqh->max_slots)) {
- /* Choose 0 or max, maybe based on current tail value */
- *phead = 0;
- *ptail = 0;
+ int err;
+ int signal_data_offset = SIG_DATA_OFFSET(&channel->chan_hdr, queue,
+ sig_hdr, slot);
- /* Sync with client as necessary */
- punsafe_sqh->head = *phead;
- punsafe_sqh->tail = *ptail;
+ err = visorchannel_write(channel, signal_data_offset,
+ data, sig_hdr->signal_size);
+ if (err)
+ return false;
- return 0;
- }
- return 1;
-} /* end safe_sig_queue_validate */
+ return true;
+}
-static BOOL
+static bool
signalremove_inner(struct visorchannel *channel, u32 queue, void *msg)
{
struct signal_queue_header sig_hdr;
if (!sig_read_header(channel, queue, &sig_hdr))
- return FALSE;
+ return false;
if (sig_hdr.head == sig_hdr.tail)
- return FALSE; /* no signals to remove */
+ return false; /* no signals to remove */
sig_hdr.tail = (sig_hdr.tail + 1) % sig_hdr.max_slots;
- if (!sig_read_data(channel, queue, &sig_hdr, sig_hdr.tail, msg)) {
- return FALSE;
- }
+ if (!sig_read_data(channel, queue, &sig_hdr, sig_hdr.tail, msg))
+ return false;
sig_hdr.num_received++;
/* For each data field in SIGNAL_QUEUE_HEADER that was modified,
@@ -415,16 +406,16 @@ signalremove_inner(struct visorchannel *channel, u32 queue, void *msg)
*/
mb(); /* required for channel synch */
if (!SIG_WRITE_FIELD(channel, queue, &sig_hdr, tail))
- return FALSE;
+ return false;
if (!SIG_WRITE_FIELD(channel, queue, &sig_hdr, num_received))
- return FALSE;
- return TRUE;
+ return false;
+ return true;
}
-BOOL
+bool
visorchannel_signalremove(struct visorchannel *channel, u32 queue, void *msg)
{
- BOOL rc;
+ bool rc;
if (channel->needs_lock) {
spin_lock(&channel->remove_lock);
@@ -438,29 +429,28 @@ visorchannel_signalremove(struct visorchannel *channel, u32 queue, void *msg)
}
EXPORT_SYMBOL_GPL(visorchannel_signalremove);
-static BOOL
+static bool
signalinsert_inner(struct visorchannel *channel, u32 queue, void *msg)
{
struct signal_queue_header sig_hdr;
if (!sig_read_header(channel, queue, &sig_hdr))
- return FALSE;
+ return false;
sig_hdr.head = ((sig_hdr.head + 1) % sig_hdr.max_slots);
if (sig_hdr.head == sig_hdr.tail) {
sig_hdr.num_overflows++;
- visor_memregion_write(channel->memregion,
- SIG_QUEUE_OFFSET(&channel->chan_hdr,
- queue) +
- offsetof(struct signal_queue_header,
- num_overflows),
- &(sig_hdr.num_overflows),
- sizeof(sig_hdr.num_overflows));
- return FALSE;
+ visorchannel_write(channel,
+ SIG_QUEUE_OFFSET(&channel->chan_hdr, queue) +
+ offsetof(struct signal_queue_header,
+ num_overflows),
+ &(sig_hdr.num_overflows),
+ sizeof(sig_hdr.num_overflows));
+ return false;
}
if (!sig_write_data(channel, queue, &sig_hdr, sig_hdr.head, msg))
- return FALSE;
+ return false;
sig_hdr.num_sent++;
@@ -469,18 +459,17 @@ signalinsert_inner(struct visorchannel *channel, u32 queue, void *msg)
*/
mb(); /* required for channel synch */
if (!SIG_WRITE_FIELD(channel, queue, &sig_hdr, head))
- return FALSE;
- if (!SIG_WRITE_FIELD(channel, queue, &sig_hdr, num_sent)) {
- return FALSE;
- }
+ return false;
+ if (!SIG_WRITE_FIELD(channel, queue, &sig_hdr, num_sent))
+ return false;
- return TRUE;
+ return true;
}
-BOOL
+bool
visorchannel_signalinsert(struct visorchannel *channel, u32 queue, void *msg)
{
- BOOL rc;
+ bool rc;
if (channel->needs_lock) {
spin_lock(&channel->insert_lock);
@@ -552,9 +541,8 @@ void
visorchannel_debug(struct visorchannel *channel, int num_queues,
struct seq_file *seq, u32 off)
{
- HOSTADDRESS addr = 0;
+ u64 addr = 0;
ulong nbytes = 0, nbytes_region = 0;
- struct memregion *memregion = NULL;
struct channel_header hdr;
struct channel_header *phdr = &hdr;
int i = 0;
@@ -562,12 +550,9 @@ visorchannel_debug(struct visorchannel *channel, int num_queues,
if (!channel)
return;
- memregion = channel->memregion;
- if (!memregion)
- return;
- addr = visor_memregion_get_physaddr(memregion);
- nbytes_region = visor_memregion_get_nbytes(memregion);
+ addr = visorchannel_get_physaddr(channel);
+ nbytes_region = visorchannel_get_nbytes(channel);
errcode = visorchannel_read(channel, off,
phdr, sizeof(struct channel_header));
if (errcode < 0) {
@@ -626,40 +611,3 @@ visorchannel_debug(struct visorchannel *channel, int num_queues,
addr + off, nbytes);
}
EXPORT_SYMBOL_GPL(visorchannel_debug);
-
-void
-visorchannel_dump_section(struct visorchannel *chan, char *s,
- int off, int len, struct seq_file *seq)
-{
- char *buf, *tbuf, *fmtbuf;
- int fmtbufsize = 0;
- int i;
- int errcode = 0;
-
- fmtbufsize = 100 * COVQ(len, 16);
- buf = kmalloc(len, GFP_KERNEL|__GFP_NORETRY);
- if (!buf)
- return;
- fmtbuf = kmalloc(fmtbufsize, GFP_KERNEL|__GFP_NORETRY);
- if (!fmtbuf)
- goto fmt_failed;
-
- errcode = visorchannel_read(chan, off, buf, len);
- if (errcode < 0)
- goto read_failed;
- seq_printf(seq, "channel %s:\n", s);
- tbuf = buf;
- while (len > 0) {
- i = (len < 16) ? len : 16;
- hex_dump_to_buffer(tbuf, i, 16, 1, fmtbuf, fmtbufsize, TRUE);
- seq_printf(seq, "%s\n", fmtbuf);
- tbuf += 16;
- len -= 16;
- }
-
-read_failed:
- kfree(fmtbuf);
-fmt_failed:
- kfree(buf);
-}
-EXPORT_SYMBOL_GPL(visorchannel_dump_section);
diff --git a/drivers/staging/unisys/visorchipset/visorchipset_main.c b/drivers/staging/unisys/visorbus/visorchipset.c
index f2663d2c7..bb8087e70 100644
--- a/drivers/staging/unisys/visorchipset/visorchipset_main.c
+++ b/drivers/staging/unisys/visorbus/visorchipset.c
@@ -15,27 +15,28 @@
* details.
*/
-#include "globals.h"
-#include "visorchipset.h"
-#include "procobjecttree.h"
-#include "visorchannel.h"
-#include "periodic_work.h"
-#include "file.h"
-#include "parser.h"
-#include "uisutils.h"
-#include "controlvmcompletionstatus.h"
-#include "guestlinuxdebug.h"
-
+#include <linux/acpi.h>
+#include <linux/cdev.h>
+#include <linux/ctype.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
#include <linux/nls.h>
#include <linux/netdevice.h>
#include <linux/platform_device.h>
#include <linux/uuid.h>
+#include <linux/crash_dump.h>
+
+#include "channel_guid.h"
+#include "controlvmchannel.h"
+#include "controlvmcompletionstatus.h"
+#include "guestlinuxdebug.h"
+#include "periodic_work.h"
+#include "version.h"
+#include "visorbus.h"
+#include "visorbus_private.h"
+#include "vmcallinterface.h"
#define CURRENT_FILE_PC VISOR_CHIPSET_PC_visorchipset_main_c
-#define TEST_VNIC_PHYSITF "eth0" /* physical network itf for
- * vnic loopback test */
-#define TEST_VNIC_SWITCHNO 1
-#define TEST_VNIC_BUSNO 9
#define MAX_NAME_SIZE 128
#define MAX_IP_SIZE 50
@@ -43,82 +44,88 @@
#define POLLJIFFIES_CONTROLVMCHANNEL_FAST 1
#define POLLJIFFIES_CONTROLVMCHANNEL_SLOW 100
+#define MAX_CONTROLVM_PAYLOAD_BYTES (1024*128)
+
+#define VISORCHIPSET_MMAP_CONTROLCHANOFFSET 0x00000000
+
+
+#define UNISYS_SPAR_LEAF_ID 0x40000000
+
+/* The s-Par leaf ID returns "UnisysSpar64" encoded across ebx, ecx, edx */
+#define UNISYS_SPAR_ID_EBX 0x73696e55
+#define UNISYS_SPAR_ID_ECX 0x70537379
+#define UNISYS_SPAR_ID_EDX 0x34367261
+
+/*
+ * Module parameters
+ */
+static int visorchipset_major;
+static int visorchipset_visorbusregwait = 1; /* default is on */
+static int visorchipset_holdchipsetready;
+static unsigned long controlvm_payload_bytes_buffered;
+
+static int
+visorchipset_open(struct inode *inode, struct file *file)
+{
+ unsigned minor_number = iminor(inode);
+
+ if (minor_number)
+ return -ENODEV;
+ file->private_data = NULL;
+ return 0;
+}
+
+static int
+visorchipset_release(struct inode *inode, struct file *file)
+{
+ return 0;
+}
+
/* When the controlvm channel is idle for at least MIN_IDLE_SECONDS,
* we switch to slow polling mode. As soon as we get a controlvm
* message, we switch back to fast polling mode.
*/
#define MIN_IDLE_SECONDS 10
-static ulong poll_jiffies = POLLJIFFIES_CONTROLVMCHANNEL_FAST;
-static ulong most_recent_message_jiffies; /* when we got our last
+static unsigned long poll_jiffies = POLLJIFFIES_CONTROLVMCHANNEL_FAST;
+static unsigned long most_recent_message_jiffies; /* when we got our last
* controlvm message */
-static inline char *
-NONULLSTR(char *s)
-{
- if (s)
- return s;
- return "";
-}
-
-static int serverregistered;
-static int clientregistered;
+static int visorbusregistered;
#define MAX_CHIPSET_EVENTS 2
static u8 chipset_events[MAX_CHIPSET_EVENTS] = { 0, 0 };
+struct parser_context {
+ unsigned long allocbytes;
+ unsigned long param_bytes;
+ u8 *curr;
+ unsigned long bytes_remaining;
+ bool byte_stream;
+ char data[0];
+};
+
static struct delayed_work periodic_controlvm_work;
static struct workqueue_struct *periodic_controlvm_workqueue;
static DEFINE_SEMAPHORE(notifier_lock);
-static struct controlvm_message_header g_diag_msg_hdr;
+static struct cdev file_cdev;
+static struct visorchannel **file_controlvm_channel;
static struct controlvm_message_header g_chipset_msg_hdr;
-static struct controlvm_message_header g_del_dump_msg_hdr;
-static const uuid_le spar_diag_pool_channel_protocol_uuid =
- SPAR_DIAG_POOL_CHANNEL_PROTOCOL_UUID;
-/* 0xffffff is an invalid Bus/Device number */
-static ulong g_diagpool_bus_no = 0xffffff;
-static ulong g_diagpool_dev_no = 0xffffff;
static struct controlvm_message_packet g_devicechangestate_packet;
-/* Only VNIC and VHBA channels are sent to visorclientbus (aka
- * "visorhackbus")
- */
-#define FOR_VISORHACKBUS(channel_type_guid) \
- (((uuid_le_cmp(channel_type_guid,\
- spar_vnic_channel_protocol_uuid) == 0) ||\
- (uuid_le_cmp(channel_type_guid,\
- spar_vhba_channel_protocol_uuid) == 0)))
-#define FOR_VISORBUS(channel_type_guid) (!(FOR_VISORHACKBUS(channel_type_guid)))
-
-#define is_diagpool_channel(channel_type_guid) \
- (uuid_le_cmp(channel_type_guid,\
- spar_diag_pool_channel_protocol_uuid) == 0)
-
static LIST_HEAD(bus_info_list);
static LIST_HEAD(dev_info_list);
static struct visorchannel *controlvm_channel;
/* Manages the request payload in the controlvm channel */
-static struct controlvm_payload_info {
+struct visor_controlvm_payload_info {
u8 __iomem *ptr; /* pointer to base address of payload pool */
u64 offset; /* offset from beginning of controlvm
* channel to beginning of payload * pool */
u32 bytes; /* number of bytes in payload pool */
-} controlvm_payload_info;
+};
-/* Manages the info for a CONTROLVM_DUMP_CAPTURESTATE /
- * CONTROLVM_DUMP_GETTEXTDUMP / CONTROLVM_DUMP_COMPLETE conversation.
- */
-static struct livedump_info {
- struct controlvm_message_header dumpcapture_header;
- struct controlvm_message_header gettextdump_header;
- struct controlvm_message_header dumpcomplete_header;
- BOOL gettextdump_outstanding;
- u32 crc32;
- ulong length;
- atomic_t buffers_in_use;
- ulong destination;
-} livedump_info;
+static struct visor_controlvm_payload_info controlvm_payload_info;
/* The following globals are used to handle the scenario where we are unable to
* offload the payload from a controlvm message due to memory requirements. In
@@ -126,14 +133,7 @@ static struct livedump_info {
* process it again the next time controlvm_periodic_work() runs.
*/
static struct controlvm_message controlvm_pending_msg;
-static BOOL controlvm_pending_msg_valid = FALSE;
-
-/* Pool of struct putfile_buffer_entry, for keeping track of pending (incoming)
- * TRANSMIT_FILE PutFile payloads.
- */
-static struct kmem_cache *putfile_buffer_list_pool;
-static const char putfile_buffer_list_pool_name[] =
- "controlvm_putfile_buffer_list_pool";
+static bool controlvm_pending_msg_valid;
/* This identifies a data buffer that has been received via a controlvm messages
* in a remote --> local CONTROLVM_TRANSMIT_FILE conversation.
@@ -203,8 +203,6 @@ struct putfile_request {
int completion_status;
};
-static atomic_t visorchipset_cache_buffers_in_use = ATOMIC_INIT(0);
-
struct parahotplug_request {
struct list_head list;
int id;
@@ -219,14 +217,16 @@ static void parahotplug_process_list(void);
/* Manages the info for a CONTROLVM_DUMP_CAPTURESTATE /
* CONTROLVM_REPORTEVENT.
*/
-static struct visorchipset_busdev_notifiers busdev_server_notifiers;
-static struct visorchipset_busdev_notifiers busdev_client_notifiers;
+static struct visorchipset_busdev_notifiers busdev_notifiers;
-static void bus_create_response(ulong bus_no, int response);
-static void bus_destroy_response(ulong bus_no, int response);
-static void device_create_response(ulong bus_no, ulong dev_no, int response);
-static void device_destroy_response(ulong bus_no, ulong dev_no, int response);
-static void device_resume_response(ulong bus_no, ulong dev_no, int response);
+static void bus_create_response(struct visor_device *p, int response);
+static void bus_destroy_response(struct visor_device *p, int response);
+static void device_create_response(struct visor_device *p, int response);
+static void device_destroy_response(struct visor_device *p, int response);
+static void device_resume_response(struct visor_device *p, int response);
+
+static void visorchipset_device_pause_response(struct visor_device *p,
+ int response);
static struct visorchipset_busdev_responders busdev_responders = {
.bus_create = bus_create_response,
@@ -331,11 +331,16 @@ static const struct attribute_group *visorchipset_dev_groups[] = {
NULL
};
+static void visorchipset_dev_release(struct device *dev)
+{
+}
+
/* /sys/devices/platform/visorchipset */
static struct platform_device visorchipset_platform_device = {
.name = "visorchipset",
.id = -1,
.dev.groups = visorchipset_dev_groups,
+ .dev.release = visorchipset_dev_release,
};
/* Function prototypes */
@@ -348,6 +353,183 @@ static void controlvm_respond_physdev_changestate(
struct controlvm_message_header *msg_hdr, int response,
struct spar_segment_state state);
+
+static void parser_done(struct parser_context *ctx);
+
+static struct parser_context *
+parser_init_byte_stream(u64 addr, u32 bytes, bool local, bool *retry)
+{
+ int allocbytes = sizeof(struct parser_context) + bytes;
+ struct parser_context *rc = NULL;
+ struct parser_context *ctx = NULL;
+
+ if (retry)
+ *retry = false;
+
+ /*
+ * alloc an 0 extra byte to ensure payload is
+ * '\0'-terminated
+ */
+ allocbytes++;
+ if ((controlvm_payload_bytes_buffered + bytes)
+ > MAX_CONTROLVM_PAYLOAD_BYTES) {
+ if (retry)
+ *retry = true;
+ rc = NULL;
+ goto cleanup;
+ }
+ ctx = kzalloc(allocbytes, GFP_KERNEL|__GFP_NORETRY);
+ if (!ctx) {
+ if (retry)
+ *retry = true;
+ rc = NULL;
+ goto cleanup;
+ }
+
+ ctx->allocbytes = allocbytes;
+ ctx->param_bytes = bytes;
+ ctx->curr = NULL;
+ ctx->bytes_remaining = 0;
+ ctx->byte_stream = false;
+ if (local) {
+ void *p;
+
+ if (addr > virt_to_phys(high_memory - 1)) {
+ rc = NULL;
+ goto cleanup;
+ }
+ p = __va((unsigned long) (addr));
+ memcpy(ctx->data, p, bytes);
+ } else {
+ void __iomem *mapping;
+
+ if (!request_mem_region(addr, bytes, "visorchipset")) {
+ rc = NULL;
+ goto cleanup;
+ }
+
+ mapping = ioremap_cache(addr, bytes);
+ if (!mapping) {
+ release_mem_region(addr, bytes);
+ rc = NULL;
+ goto cleanup;
+ }
+ memcpy_fromio(ctx->data, mapping, bytes);
+ release_mem_region(addr, bytes);
+ }
+
+ ctx->byte_stream = true;
+ rc = ctx;
+cleanup:
+ if (rc) {
+ controlvm_payload_bytes_buffered += ctx->param_bytes;
+ } else {
+ if (ctx) {
+ parser_done(ctx);
+ ctx = NULL;
+ }
+ }
+ return rc;
+}
+
+static uuid_le
+parser_id_get(struct parser_context *ctx)
+{
+ struct spar_controlvm_parameters_header *phdr = NULL;
+
+ if (ctx == NULL)
+ return NULL_UUID_LE;
+ phdr = (struct spar_controlvm_parameters_header *)(ctx->data);
+ return phdr->id;
+}
+
+/** Describes the state from the perspective of which controlvm messages have
+ * been received for a bus or device.
+ */
+
+enum PARSER_WHICH_STRING {
+ PARSERSTRING_INITIATOR,
+ PARSERSTRING_TARGET,
+ PARSERSTRING_CONNECTION,
+ PARSERSTRING_NAME, /* TODO: only PARSERSTRING_NAME is used ? */
+};
+
+static void
+parser_param_start(struct parser_context *ctx,
+ enum PARSER_WHICH_STRING which_string)
+{
+ struct spar_controlvm_parameters_header *phdr = NULL;
+
+ if (ctx == NULL)
+ goto Away;
+ phdr = (struct spar_controlvm_parameters_header *)(ctx->data);
+ switch (which_string) {
+ case PARSERSTRING_INITIATOR:
+ ctx->curr = ctx->data + phdr->initiator_offset;
+ ctx->bytes_remaining = phdr->initiator_length;
+ break;
+ case PARSERSTRING_TARGET:
+ ctx->curr = ctx->data + phdr->target_offset;
+ ctx->bytes_remaining = phdr->target_length;
+ break;
+ case PARSERSTRING_CONNECTION:
+ ctx->curr = ctx->data + phdr->connection_offset;
+ ctx->bytes_remaining = phdr->connection_length;
+ break;
+ case PARSERSTRING_NAME:
+ ctx->curr = ctx->data + phdr->name_offset;
+ ctx->bytes_remaining = phdr->name_length;
+ break;
+ default:
+ break;
+ }
+
+Away:
+ return;
+}
+
+static void parser_done(struct parser_context *ctx)
+{
+ if (!ctx)
+ return;
+ controlvm_payload_bytes_buffered -= ctx->param_bytes;
+ kfree(ctx);
+}
+
+static void *
+parser_string_get(struct parser_context *ctx)
+{
+ u8 *pscan;
+ unsigned long nscan;
+ int value_length = -1;
+ void *value = NULL;
+ int i;
+
+ if (!ctx)
+ return NULL;
+ pscan = ctx->curr;
+ nscan = ctx->bytes_remaining;
+ if (nscan == 0)
+ return NULL;
+ if (!pscan)
+ return NULL;
+ for (i = 0, value_length = -1; i < nscan; i++)
+ if (pscan[i] == '\0') {
+ value_length = i;
+ break;
+ }
+ if (value_length < 0) /* '\0' was not included in the length */
+ value_length = nscan;
+ value = kmalloc(value_length + 1, GFP_KERNEL|__GFP_NORETRY);
+ if (value == NULL)
+ return NULL;
+ if (value_length > 0)
+ memcpy(value, pscan, value_length);
+ ((u8 *) (value))[value_length] = '\0';
+ return value;
+}
+
+
static ssize_t toolaction_show(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -367,7 +549,7 @@ static ssize_t toolaction_store(struct device *dev,
u8 tool_action;
int ret;
- if (kstrtou8(buf, 10, &tool_action) != 0)
+ if (kstrtou8(buf, 10, &tool_action))
return -EINVAL;
ret = visorchannel_write(controlvm_channel,
@@ -401,7 +583,7 @@ static ssize_t boottotool_store(struct device *dev,
int val, ret;
struct efi_spar_indication efi_spar_indication;
- if (kstrtoint(buf, 10, &val) != 0)
+ if (kstrtoint(buf, 10, &val))
return -EINVAL;
efi_spar_indication.boot_to_tool = val;
@@ -433,7 +615,7 @@ static ssize_t error_store(struct device *dev, struct device_attribute *attr,
u32 error;
int ret;
- if (kstrtou32(buf, 10, &error) != 0)
+ if (kstrtou32(buf, 10, &error))
return -EINVAL;
ret = visorchannel_write(controlvm_channel,
@@ -463,7 +645,7 @@ static ssize_t textid_store(struct device *dev, struct device_attribute *attr,
u32 text_id;
int ret;
- if (kstrtou32(buf, 10, &text_id) != 0)
+ if (kstrtou32(buf, 10, &text_id))
return -EINVAL;
ret = visorchannel_write(controlvm_channel,
@@ -494,7 +676,7 @@ static ssize_t remaining_steps_store(struct device *dev,
u16 remaining_steps;
int ret;
- if (kstrtou16(buf, 10, &remaining_steps) != 0)
+ if (kstrtou16(buf, 10, &remaining_steps))
return -EINVAL;
ret = visorchannel_write(controlvm_channel,
@@ -506,30 +688,44 @@ static ssize_t remaining_steps_store(struct device *dev,
return count;
}
-static void
-bus_info_clear(void *v)
-{
- struct visorchipset_bus_info *p = (struct visorchipset_bus_info *) (v);
+struct visor_busdev {
+ u32 bus_no;
+ u32 dev_no;
+};
- kfree(p->name);
- p->name = NULL;
+static int match_visorbus_dev_by_id(struct device *dev, void *data)
+{
+ struct visor_device *vdev = to_visor_device(dev);
+ struct visor_busdev *id = (struct visor_busdev *)data;
+ u32 bus_no = id->bus_no;
+ u32 dev_no = id->dev_no;
- kfree(p->description);
- p->description = NULL;
+ if ((vdev->chipset_bus_no == bus_no) &&
+ (vdev->chipset_dev_no == dev_no))
+ return 1;
- p->state.created = 0;
- memset(p, 0, sizeof(struct visorchipset_bus_info));
+ return 0;
}
-
-static void
-dev_info_clear(void *v)
+struct visor_device *visorbus_get_device_by_id(u32 bus_no, u32 dev_no,
+ struct visor_device *from)
{
- struct visorchipset_device_info *p =
- (struct visorchipset_device_info *)(v);
+ struct device *dev;
+ struct device *dev_start = NULL;
+ struct visor_device *vdev = NULL;
+ struct visor_busdev id = {
+ .bus_no = bus_no,
+ .dev_no = dev_no
+ };
- p->state.created = 0;
- memset(p, 0, sizeof(struct visorchipset_device_info));
+ if (from)
+ dev_start = &from->device;
+ dev = bus_find_device(&visorbus_type, dev_start, (void *)&id,
+ match_visorbus_dev_by_id);
+ if (dev)
+ vdev = to_visor_device(dev);
+ return vdev;
}
+EXPORT_SYMBOL(visorbus_get_device_by_id);
static u8
check_chipset_events(void)
@@ -552,19 +748,19 @@ clear_chipset_events(void)
}
void
-visorchipset_register_busdev_server(
+visorchipset_register_busdev(
struct visorchipset_busdev_notifiers *notifiers,
struct visorchipset_busdev_responders *responders,
struct ultra_vbus_deviceinfo *driver_info)
{
down(&notifier_lock);
if (!notifiers) {
- memset(&busdev_server_notifiers, 0,
- sizeof(busdev_server_notifiers));
- serverregistered = 0; /* clear flag */
+ memset(&busdev_notifiers, 0,
+ sizeof(busdev_notifiers));
+ visorbusregistered = 0; /* clear flag */
} else {
- busdev_server_notifiers = *notifiers;
- serverregistered = 1; /* set flag */
+ busdev_notifiers = *notifiers;
+ visorbusregistered = 1; /* set flag */
}
if (responders)
*responders = busdev_responders;
@@ -574,50 +770,7 @@ visorchipset_register_busdev_server(
up(&notifier_lock);
}
-EXPORT_SYMBOL_GPL(visorchipset_register_busdev_server);
-
-void
-visorchipset_register_busdev_client(
- struct visorchipset_busdev_notifiers *notifiers,
- struct visorchipset_busdev_responders *responders,
- struct ultra_vbus_deviceinfo *driver_info)
-{
- down(&notifier_lock);
- if (!notifiers) {
- memset(&busdev_client_notifiers, 0,
- sizeof(busdev_client_notifiers));
- clientregistered = 0; /* clear flag */
- } else {
- busdev_client_notifiers = *notifiers;
- clientregistered = 1; /* set flag */
- }
- if (responders)
- *responders = busdev_responders;
- if (driver_info)
- bus_device_info_init(driver_info, "chipset(bolts)",
- "visorchipset", VERSION, NULL);
- up(&notifier_lock);
-}
-EXPORT_SYMBOL_GPL(visorchipset_register_busdev_client);
-
-static void
-cleanup_controlvm_structures(void)
-{
- struct visorchipset_bus_info *bi, *tmp_bi;
- struct visorchipset_device_info *di, *tmp_di;
-
- list_for_each_entry_safe(bi, tmp_bi, &bus_info_list, entry) {
- bus_info_clear(bi);
- list_del(&bi->entry);
- kfree(bi);
- }
-
- list_for_each_entry_safe(di, tmp_di, &dev_info_list, entry) {
- dev_info_clear(di);
- list_del(&di->entry);
- kfree(di);
- }
-}
+EXPORT_SYMBOL_GPL(visorchipset_register_busdev);
static void
chipset_init(struct controlvm_message *inmsg)
@@ -645,8 +798,6 @@ chipset_init(struct controlvm_message *inmsg)
features |= ULTRA_CHIPSET_FEATURE_REPLY;
cleanup:
- if (rc < 0)
- cleanup_controlvm_structures();
if (inmsg->hdr.flags.response_expected)
controlvm_respond_chipset_init(&inmsg->hdr, rc, features);
}
@@ -672,14 +823,6 @@ controlvm_respond(struct controlvm_message_header *msg_hdr, int response)
struct controlvm_message outmsg;
controlvm_init_response(&outmsg, msg_hdr, response);
- /* For DiagPool channel DEVICE_CHANGESTATE, we need to send
- * back the deviceChangeState structure in the packet. */
- if (msg_hdr->id == CONTROLVM_DEVICE_CHANGESTATE &&
- g_devicechangestate_packet.device_change_state.bus_no ==
- g_diagpool_bus_no &&
- g_devicechangestate_packet.device_change_state.dev_no ==
- g_diagpool_dev_no)
- outmsg.cmd = g_devicechangestate_packet;
if (outmsg.hdr.flags.test_message == 1)
return;
@@ -719,113 +862,40 @@ static void controlvm_respond_physdev_changestate(
}
}
-void
-visorchipset_save_message(struct controlvm_message *msg,
- enum crash_obj_type type)
-{
- u32 crash_msg_offset;
- u16 crash_msg_count;
-
- /* get saved message count */
- if (visorchannel_read(controlvm_channel,
- offsetof(struct spar_controlvm_channel_protocol,
- saved_crash_message_count),
- &crash_msg_count, sizeof(u16)) < 0) {
- POSTCODE_LINUX_2(CRASH_DEV_CTRL_RD_FAILURE_PC,
- POSTCODE_SEVERITY_ERR);
- return;
- }
-
- if (crash_msg_count != CONTROLVM_CRASHMSG_MAX) {
- POSTCODE_LINUX_3(CRASH_DEV_COUNT_FAILURE_PC,
- crash_msg_count,
- POSTCODE_SEVERITY_ERR);
- return;
- }
-
- /* get saved crash message offset */
- if (visorchannel_read(controlvm_channel,
- offsetof(struct spar_controlvm_channel_protocol,
- saved_crash_message_offset),
- &crash_msg_offset, sizeof(u32)) < 0) {
- POSTCODE_LINUX_2(CRASH_DEV_CTRL_RD_FAILURE_PC,
- POSTCODE_SEVERITY_ERR);
- return;
- }
-
- if (type == CRASH_BUS) {
- if (visorchannel_write(controlvm_channel,
- crash_msg_offset,
- msg,
- sizeof(struct controlvm_message)) < 0) {
- POSTCODE_LINUX_2(SAVE_MSG_BUS_FAILURE_PC,
- POSTCODE_SEVERITY_ERR);
- return;
- }
- } else {
- if (visorchannel_write(controlvm_channel,
- crash_msg_offset +
- sizeof(struct controlvm_message), msg,
- sizeof(struct controlvm_message)) < 0) {
- POSTCODE_LINUX_2(SAVE_MSG_DEV_FAILURE_PC,
- POSTCODE_SEVERITY_ERR);
- return;
- }
- }
-}
-EXPORT_SYMBOL_GPL(visorchipset_save_message);
+enum crash_obj_type {
+ CRASH_DEV,
+ CRASH_BUS,
+};
static void
-bus_responder(enum controlvm_id cmd_id, ulong bus_no, int response)
+bus_responder(enum controlvm_id cmd_id,
+ struct controlvm_message_header *pending_msg_hdr,
+ int response)
{
- struct visorchipset_bus_info *p = NULL;
- BOOL need_clear = FALSE;
+ if (pending_msg_hdr == NULL)
+ return; /* no controlvm response needed */
- p = findbus(&bus_info_list, bus_no);
- if (!p)
+ if (pending_msg_hdr->id != (u32)cmd_id)
return;
- if (response < 0) {
- if ((cmd_id == CONTROLVM_BUS_CREATE) &&
- (response != (-CONTROLVM_RESP_ERROR_ALREADY_DONE)))
- /* undo the row we just created... */
- delbusdevices(&dev_info_list, bus_no);
- } else {
- if (cmd_id == CONTROLVM_BUS_CREATE)
- p->state.created = 1;
- if (cmd_id == CONTROLVM_BUS_DESTROY)
- need_clear = TRUE;
- }
-
- if (p->pending_msg_hdr.id == CONTROLVM_INVALID)
- return; /* no controlvm response needed */
- if (p->pending_msg_hdr.id != (u32)cmd_id)
- return;
- controlvm_respond(&p->pending_msg_hdr, response);
- p->pending_msg_hdr.id = CONTROLVM_INVALID;
- if (need_clear) {
- bus_info_clear(p);
- delbusdevices(&dev_info_list, bus_no);
- }
+ controlvm_respond(pending_msg_hdr, response);
}
static void
device_changestate_responder(enum controlvm_id cmd_id,
- ulong bus_no, ulong dev_no, int response,
+ struct visor_device *p, int response,
struct spar_segment_state response_state)
{
- struct visorchipset_device_info *p = NULL;
struct controlvm_message outmsg;
+ u32 bus_no = p->chipset_bus_no;
+ u32 dev_no = p->chipset_dev_no;
- p = finddevice(&dev_info_list, bus_no, dev_no);
- if (!p)
- return;
- if (p->pending_msg_hdr.id == CONTROLVM_INVALID)
+ if (p->pending_msg_hdr == NULL)
return; /* no controlvm response needed */
- if (p->pending_msg_hdr.id != cmd_id)
+ if (p->pending_msg_hdr->id != cmd_id)
return;
- controlvm_init_response(&outmsg, &p->pending_msg_hdr, response);
+ controlvm_init_response(&outmsg, p->pending_msg_hdr, response);
outmsg.cmd.device_change_state.bus_no = bus_no;
outmsg.cmd.device_change_state.dev_no = dev_no;
@@ -834,96 +904,74 @@ device_changestate_responder(enum controlvm_id cmd_id,
if (!visorchannel_signalinsert(controlvm_channel,
CONTROLVM_QUEUE_REQUEST, &outmsg))
return;
-
- p->pending_msg_hdr.id = CONTROLVM_INVALID;
}
static void
-device_responder(enum controlvm_id cmd_id, ulong bus_no, ulong dev_no,
+device_responder(enum controlvm_id cmd_id,
+ struct controlvm_message_header *pending_msg_hdr,
int response)
{
- struct visorchipset_device_info *p = NULL;
- BOOL need_clear = FALSE;
-
- p = finddevice(&dev_info_list, bus_no, dev_no);
- if (!p)
- return;
- if (response >= 0) {
- if (cmd_id == CONTROLVM_DEVICE_CREATE)
- p->state.created = 1;
- if (cmd_id == CONTROLVM_DEVICE_DESTROY)
- need_clear = TRUE;
- }
-
- if (p->pending_msg_hdr.id == CONTROLVM_INVALID)
+ if (pending_msg_hdr == NULL)
return; /* no controlvm response needed */
- if (p->pending_msg_hdr.id != (u32)cmd_id)
+ if (pending_msg_hdr->id != (u32)cmd_id)
return;
- controlvm_respond(&p->pending_msg_hdr, response);
- p->pending_msg_hdr.id = CONTROLVM_INVALID;
- if (need_clear)
- dev_info_clear(p);
+ controlvm_respond(pending_msg_hdr, response);
}
static void
-bus_epilog(u32 bus_no,
+bus_epilog(struct visor_device *bus_info,
u32 cmd, struct controlvm_message_header *msg_hdr,
- int response, BOOL need_response)
+ int response, bool need_response)
{
- BOOL notified = FALSE;
+ bool notified = false;
+ struct controlvm_message_header *pmsg_hdr = NULL;
- struct visorchipset_bus_info *bus_info = findbus(&bus_info_list,
- bus_no);
+ if (!bus_info) {
+ /* relying on a valid passed in response code */
+ /* be lazy and re-use msg_hdr for this failure, is this ok?? */
+ pmsg_hdr = msg_hdr;
+ goto away;
+ }
- if (!bus_info)
- return;
+ if (bus_info->pending_msg_hdr) {
+ /* only non-NULL if dev is still waiting on a response */
+ response = -CONTROLVM_RESP_ERROR_MESSAGE_ID_INVALID_FOR_CLIENT;
+ pmsg_hdr = bus_info->pending_msg_hdr;
+ goto away;
+ }
if (need_response) {
- memcpy(&bus_info->pending_msg_hdr, msg_hdr,
+ pmsg_hdr = kzalloc(sizeof(*pmsg_hdr), GFP_KERNEL);
+ if (!pmsg_hdr) {
+ response = -CONTROLVM_RESP_ERROR_KMALLOC_FAILED;
+ goto away;
+ }
+
+ memcpy(pmsg_hdr, msg_hdr,
sizeof(struct controlvm_message_header));
- } else {
- bus_info->pending_msg_hdr.id = CONTROLVM_INVALID;
+ bus_info->pending_msg_hdr = pmsg_hdr;
}
down(&notifier_lock);
if (response == CONTROLVM_RESP_SUCCESS) {
switch (cmd) {
case CONTROLVM_BUS_CREATE:
- /* We can't tell from the bus_create
- * information which of our 2 bus flavors the
- * devices on this bus will ultimately end up.
- * FORTUNATELY, it turns out it is harmless to
- * send the bus_create to both of them. We can
- * narrow things down a little bit, though,
- * because we know: - BusDev_Server can handle
- * either server or client devices
- * - BusDev_Client can handle ONLY client
- * devices */
- if (busdev_server_notifiers.bus_create) {
- (*busdev_server_notifiers.bus_create) (bus_no);
- notified = TRUE;
- }
- if ((!bus_info->flags.server) /*client */ &&
- busdev_client_notifiers.bus_create) {
- (*busdev_client_notifiers.bus_create) (bus_no);
- notified = TRUE;
+ if (busdev_notifiers.bus_create) {
+ (*busdev_notifiers.bus_create) (bus_info);
+ notified = true;
}
break;
case CONTROLVM_BUS_DESTROY:
- if (busdev_server_notifiers.bus_destroy) {
- (*busdev_server_notifiers.bus_destroy) (bus_no);
- notified = TRUE;
- }
- if ((!bus_info->flags.server) /*client */ &&
- busdev_client_notifiers.bus_destroy) {
- (*busdev_client_notifiers.bus_destroy) (bus_no);
- notified = TRUE;
+ if (busdev_notifiers.bus_destroy) {
+ (*busdev_notifiers.bus_destroy) (bus_info);
+ notified = true;
}
break;
}
}
+away:
if (notified)
/* The callback function just called above is responsible
* for calling the appropriate visorchipset_busdev_responders
@@ -931,37 +979,51 @@ bus_epilog(u32 bus_no,
*/
;
else
- bus_responder(cmd, bus_no, response);
+ /*
+ * Do not kfree(pmsg_hdr) as this is the failure path.
+ * The success path ('notified') will call the responder
+ * directly and kfree() there.
+ */
+ bus_responder(cmd, pmsg_hdr, response);
up(&notifier_lock);
}
static void
-device_epilog(u32 bus_no, u32 dev_no, struct spar_segment_state state, u32 cmd,
+device_epilog(struct visor_device *dev_info,
+ struct spar_segment_state state, u32 cmd,
struct controlvm_message_header *msg_hdr, int response,
- BOOL need_response, BOOL for_visorbus)
+ bool need_response, bool for_visorbus)
{
- struct visorchipset_busdev_notifiers *notifiers = NULL;
- BOOL notified = FALSE;
+ struct visorchipset_busdev_notifiers *notifiers;
+ bool notified = false;
+ struct controlvm_message_header *pmsg_hdr = NULL;
- struct visorchipset_device_info *dev_info =
- finddevice(&dev_info_list, bus_no, dev_no);
- char *envp[] = {
- "SPARSP_DIAGPOOL_PAUSED_STATE = 1",
- NULL
- };
+ notifiers = &busdev_notifiers;
- if (!dev_info)
- return;
+ if (!dev_info) {
+ /* relying on a valid passed in response code */
+ /* be lazy and re-use msg_hdr for this failure, is this ok?? */
+ pmsg_hdr = msg_hdr;
+ goto away;
+ }
+
+ if (dev_info->pending_msg_hdr) {
+ /* only non-NULL if dev is still waiting on a response */
+ response = -CONTROLVM_RESP_ERROR_MESSAGE_ID_INVALID_FOR_CLIENT;
+ pmsg_hdr = dev_info->pending_msg_hdr;
+ goto away;
+ }
- if (for_visorbus)
- notifiers = &busdev_server_notifiers;
- else
- notifiers = &busdev_client_notifiers;
if (need_response) {
- memcpy(&dev_info->pending_msg_hdr, msg_hdr,
+ pmsg_hdr = kzalloc(sizeof(*pmsg_hdr), GFP_KERNEL);
+ if (!pmsg_hdr) {
+ response = -CONTROLVM_RESP_ERROR_KMALLOC_FAILED;
+ goto away;
+ }
+
+ memcpy(pmsg_hdr, msg_hdr,
sizeof(struct controlvm_message_header));
- } else {
- dev_info->pending_msg_hdr.id = CONTROLVM_INVALID;
+ dev_info->pending_msg_hdr = pmsg_hdr;
}
down(&notifier_lock);
@@ -969,8 +1031,8 @@ device_epilog(u32 bus_no, u32 dev_no, struct spar_segment_state state, u32 cmd,
switch (cmd) {
case CONTROLVM_DEVICE_CREATE:
if (notifiers->device_create) {
- (*notifiers->device_create) (bus_no, dev_no);
- notified = TRUE;
+ (*notifiers->device_create) (dev_info);
+ notified = true;
}
break;
case CONTROLVM_DEVICE_CHANGESTATE:
@@ -979,9 +1041,8 @@ device_epilog(u32 bus_no, u32 dev_no, struct spar_segment_state state, u32 cmd,
state.operating ==
segment_state_running.operating) {
if (notifiers->device_resume) {
- (*notifiers->device_resume) (bus_no,
- dev_no);
- notified = TRUE;
+ (*notifiers->device_resume) (dev_info);
+ notified = true;
}
}
/* ServerNotReady / ServerLost / SegmentStateStandby */
@@ -992,35 +1053,20 @@ device_epilog(u32 bus_no, u32 dev_no, struct spar_segment_state state, u32 cmd,
* where server is lost
*/
if (notifiers->device_pause) {
- (*notifiers->device_pause) (bus_no,
- dev_no);
- notified = TRUE;
- }
- } else if (state.alive == segment_state_paused.alive &&
- state.operating ==
- segment_state_paused.operating) {
- /* this is lite pause where channel is
- * still valid just 'pause' of it
- */
- if (bus_no == g_diagpool_bus_no &&
- dev_no == g_diagpool_dev_no) {
- /* this will trigger the
- * diag_shutdown.sh script in
- * the visorchipset hotplug */
- kobject_uevent_env
- (&visorchipset_platform_device.dev.
- kobj, KOBJ_ONLINE, envp);
+ (*notifiers->device_pause) (dev_info);
+ notified = true;
}
}
break;
case CONTROLVM_DEVICE_DESTROY:
if (notifiers->device_destroy) {
- (*notifiers->device_destroy) (bus_no, dev_no);
- notified = TRUE;
+ (*notifiers->device_destroy) (dev_info);
+ notified = true;
}
break;
}
}
+away:
if (notified)
/* The callback function just called above is responsible
* for calling the appropriate visorchipset_busdev_responders
@@ -1028,7 +1074,12 @@ device_epilog(u32 bus_no, u32 dev_no, struct spar_segment_state state, u32 cmd,
*/
;
else
- device_responder(cmd, bus_no, dev_no, response);
+ /*
+ * Do not kfree(pmsg_hdr) as this is the failure path.
+ * The success path ('notified') will call the responder
+ * directly and kfree() there.
+ */
+ device_responder(cmd, pmsg_hdr, response);
up(&notifier_lock);
}
@@ -1036,11 +1087,12 @@ static void
bus_create(struct controlvm_message *inmsg)
{
struct controlvm_message_packet *cmd = &inmsg->cmd;
- ulong bus_no = cmd->create_bus.bus_no;
+ u32 bus_no = cmd->create_bus.bus_no;
int rc = CONTROLVM_RESP_SUCCESS;
- struct visorchipset_bus_info *bus_info = NULL;
+ struct visor_device *bus_info;
+ struct visorchannel *visorchannel;
- bus_info = findbus(&bus_info_list, bus_no);
+ bus_info = visorbus_get_device_by_id(bus_no, BUS_ROOT_DEVICE, NULL);
if (bus_info && (bus_info->state.created == 1)) {
POSTCODE_LINUX_3(BUS_CREATE_FAILURE_PC, bus_no,
POSTCODE_SEVERITY_ERR);
@@ -1055,30 +1107,31 @@ bus_create(struct controlvm_message *inmsg)
goto cleanup;
}
- INIT_LIST_HEAD(&bus_info->entry);
- bus_info->bus_no = bus_no;
- bus_info->dev_no = cmd->create_bus.dev_count;
+ INIT_LIST_HEAD(&bus_info->list_all);
+ bus_info->chipset_bus_no = bus_no;
+ bus_info->chipset_dev_no = BUS_ROOT_DEVICE;
POSTCODE_LINUX_3(BUS_CREATE_ENTRY_PC, bus_no, POSTCODE_SEVERITY_INFO);
- if (inmsg->hdr.flags.test_message == 1)
- bus_info->chan_info.addr_type = ADDRTYPE_LOCALTEST;
- else
- bus_info->chan_info.addr_type = ADDRTYPE_LOCALPHYSICAL;
-
- bus_info->flags.server = inmsg->hdr.flags.server;
- bus_info->chan_info.channel_addr = cmd->create_bus.channel_addr;
- bus_info->chan_info.n_channel_bytes = cmd->create_bus.channel_bytes;
- bus_info->chan_info.channel_type_uuid =
- cmd->create_bus.bus_data_type_uuid;
- bus_info->chan_info.channel_inst_uuid = cmd->create_bus.bus_inst_uuid;
+ visorchannel = visorchannel_create(cmd->create_bus.channel_addr,
+ cmd->create_bus.channel_bytes,
+ GFP_KERNEL,
+ cmd->create_bus.bus_data_type_uuid);
- list_add(&bus_info->entry, &bus_info_list);
+ if (!visorchannel) {
+ POSTCODE_LINUX_3(BUS_CREATE_FAILURE_PC, bus_no,
+ POSTCODE_SEVERITY_ERR);
+ rc = -CONTROLVM_RESP_ERROR_KMALLOC_FAILED;
+ kfree(bus_info);
+ bus_info = NULL;
+ goto cleanup;
+ }
+ bus_info->visorchannel = visorchannel;
POSTCODE_LINUX_3(BUS_CREATE_EXIT_PC, bus_no, POSTCODE_SEVERITY_INFO);
cleanup:
- bus_epilog(bus_no, CONTROLVM_BUS_CREATE, &inmsg->hdr,
+ bus_epilog(bus_info, CONTROLVM_BUS_CREATE, &inmsg->hdr,
rc, inmsg->hdr.flags.response_expected == 1);
}
@@ -1086,18 +1139,20 @@ static void
bus_destroy(struct controlvm_message *inmsg)
{
struct controlvm_message_packet *cmd = &inmsg->cmd;
- ulong bus_no = cmd->destroy_bus.bus_no;
- struct visorchipset_bus_info *bus_info;
+ u32 bus_no = cmd->destroy_bus.bus_no;
+ struct visor_device *bus_info;
int rc = CONTROLVM_RESP_SUCCESS;
- bus_info = findbus(&bus_info_list, bus_no);
+ bus_info = visorbus_get_device_by_id(bus_no, BUS_ROOT_DEVICE, NULL);
if (!bus_info)
rc = -CONTROLVM_RESP_ERROR_BUS_INVALID;
else if (bus_info->state.created == 0)
rc = -CONTROLVM_RESP_ERROR_ALREADY_DONE;
- bus_epilog(bus_no, CONTROLVM_BUS_DESTROY, &inmsg->hdr,
+ bus_epilog(bus_info, CONTROLVM_BUS_DESTROY, &inmsg->hdr,
rc, inmsg->hdr.flags.response_expected == 1);
+
+ /* bus_info is freed as part of the busdevice_release function */
}
static void
@@ -1105,16 +1160,15 @@ bus_configure(struct controlvm_message *inmsg,
struct parser_context *parser_ctx)
{
struct controlvm_message_packet *cmd = &inmsg->cmd;
- ulong bus_no = cmd->configure_bus.bus_no;
- struct visorchipset_bus_info *bus_info = NULL;
+ u32 bus_no;
+ struct visor_device *bus_info;
int rc = CONTROLVM_RESP_SUCCESS;
- char s[99];
bus_no = cmd->configure_bus.bus_no;
POSTCODE_LINUX_3(BUS_CONFIGURE_ENTRY_PC, bus_no,
POSTCODE_SEVERITY_INFO);
- bus_info = findbus(&bus_info_list, bus_no);
+ bus_info = visorbus_get_device_by_id(bus_no, BUS_ROOT_DEVICE, NULL);
if (!bus_info) {
POSTCODE_LINUX_3(BUS_CONFIGURE_FAILURE_PC, bus_no,
POSTCODE_SEVERITY_ERR);
@@ -1123,21 +1177,21 @@ bus_configure(struct controlvm_message *inmsg,
POSTCODE_LINUX_3(BUS_CONFIGURE_FAILURE_PC, bus_no,
POSTCODE_SEVERITY_ERR);
rc = -CONTROLVM_RESP_ERROR_BUS_INVALID;
- } else if (bus_info->pending_msg_hdr.id != CONTROLVM_INVALID) {
+ } else if (bus_info->pending_msg_hdr != NULL) {
POSTCODE_LINUX_3(BUS_CONFIGURE_FAILURE_PC, bus_no,
POSTCODE_SEVERITY_ERR);
rc = -CONTROLVM_RESP_ERROR_MESSAGE_ID_INVALID_FOR_CLIENT;
} else {
- bus_info->partition_handle = cmd->configure_bus.guest_handle;
+ visorchannel_set_clientpartition(bus_info->visorchannel,
+ cmd->configure_bus.guest_handle);
bus_info->partition_uuid = parser_id_get(parser_ctx);
parser_param_start(parser_ctx, PARSERSTRING_NAME);
bus_info->name = parser_string_get(parser_ctx);
- visorchannel_uuid_id(&bus_info->partition_uuid, s);
POSTCODE_LINUX_3(BUS_CONFIGURE_EXIT_PC, bus_no,
POSTCODE_SEVERITY_INFO);
}
- bus_epilog(bus_no, CONTROLVM_BUS_CONFIGURE, &inmsg->hdr,
+ bus_epilog(bus_info, CONTROLVM_BUS_CONFIGURE, &inmsg->hdr,
rc, inmsg->hdr.flags.response_expected == 1);
}
@@ -1145,32 +1199,36 @@ static void
my_device_create(struct controlvm_message *inmsg)
{
struct controlvm_message_packet *cmd = &inmsg->cmd;
- ulong bus_no = cmd->create_device.bus_no;
- ulong dev_no = cmd->create_device.dev_no;
- struct visorchipset_device_info *dev_info = NULL;
- struct visorchipset_bus_info *bus_info = NULL;
+ u32 bus_no = cmd->create_device.bus_no;
+ u32 dev_no = cmd->create_device.dev_no;
+ struct visor_device *dev_info = NULL;
+ struct visor_device *bus_info;
+ struct visorchannel *visorchannel;
int rc = CONTROLVM_RESP_SUCCESS;
- dev_info = finddevice(&dev_info_list, bus_no, dev_no);
- if (dev_info && (dev_info->state.created == 1)) {
+ bus_info = visorbus_get_device_by_id(bus_no, BUS_ROOT_DEVICE, NULL);
+ if (!bus_info) {
POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC, dev_no, bus_no,
POSTCODE_SEVERITY_ERR);
- rc = -CONTROLVM_RESP_ERROR_ALREADY_DONE;
+ rc = -CONTROLVM_RESP_ERROR_BUS_INVALID;
goto cleanup;
}
- bus_info = findbus(&bus_info_list, bus_no);
- if (!bus_info) {
+
+ if (bus_info->state.created == 0) {
POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC, dev_no, bus_no,
POSTCODE_SEVERITY_ERR);
rc = -CONTROLVM_RESP_ERROR_BUS_INVALID;
goto cleanup;
}
- if (bus_info->state.created == 0) {
+
+ dev_info = visorbus_get_device_by_id(bus_no, dev_no, NULL);
+ if (dev_info && (dev_info->state.created == 1)) {
POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC, dev_no, bus_no,
POSTCODE_SEVERITY_ERR);
- rc = -CONTROLVM_RESP_ERROR_BUS_INVALID;
+ rc = -CONTROLVM_RESP_ERROR_ALREADY_DONE;
goto cleanup;
}
+
dev_info = kzalloc(sizeof(*dev_info), GFP_KERNEL);
if (!dev_info) {
POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC, dev_no, bus_no,
@@ -1179,49 +1237,50 @@ my_device_create(struct controlvm_message *inmsg)
goto cleanup;
}
- INIT_LIST_HEAD(&dev_info->entry);
- dev_info->bus_no = bus_no;
- dev_info->dev_no = dev_no;
- dev_info->dev_inst_uuid = cmd->create_device.dev_inst_uuid;
+ dev_info->chipset_bus_no = bus_no;
+ dev_info->chipset_dev_no = dev_no;
+ dev_info->inst = cmd->create_device.dev_inst_uuid;
+
+ /* not sure where the best place to set the 'parent' */
+ dev_info->device.parent = &bus_info->device;
+
POSTCODE_LINUX_4(DEVICE_CREATE_ENTRY_PC, dev_no, bus_no,
POSTCODE_SEVERITY_INFO);
- if (inmsg->hdr.flags.test_message == 1)
- dev_info->chan_info.addr_type = ADDRTYPE_LOCALTEST;
- else
- dev_info->chan_info.addr_type = ADDRTYPE_LOCALPHYSICAL;
- dev_info->chan_info.channel_addr = cmd->create_device.channel_addr;
- dev_info->chan_info.n_channel_bytes = cmd->create_device.channel_bytes;
- dev_info->chan_info.channel_type_uuid =
- cmd->create_device.data_type_uuid;
- dev_info->chan_info.intr = cmd->create_device.intr;
- list_add(&dev_info->entry, &dev_info_list);
+ visorchannel = visorchannel_create(cmd->create_device.channel_addr,
+ cmd->create_device.channel_bytes,
+ GFP_KERNEL,
+ cmd->create_device.data_type_uuid);
+
+ if (!visorchannel) {
+ POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC, dev_no, bus_no,
+ POSTCODE_SEVERITY_ERR);
+ rc = -CONTROLVM_RESP_ERROR_KMALLOC_FAILED;
+ kfree(dev_info);
+ dev_info = NULL;
+ goto cleanup;
+ }
+ dev_info->visorchannel = visorchannel;
+ dev_info->channel_type_guid = cmd->create_device.data_type_uuid;
POSTCODE_LINUX_4(DEVICE_CREATE_EXIT_PC, dev_no, bus_no,
POSTCODE_SEVERITY_INFO);
cleanup:
- /* get the bus and devNo for DiagPool channel */
- if (dev_info &&
- is_diagpool_channel(dev_info->chan_info.channel_type_uuid)) {
- g_diagpool_bus_no = bus_no;
- g_diagpool_dev_no = dev_no;
- }
- device_epilog(bus_no, dev_no, segment_state_running,
+ device_epilog(dev_info, segment_state_running,
CONTROLVM_DEVICE_CREATE, &inmsg->hdr, rc,
- inmsg->hdr.flags.response_expected == 1,
- FOR_VISORBUS(dev_info->chan_info.channel_type_uuid));
+ inmsg->hdr.flags.response_expected == 1, 1);
}
static void
my_device_changestate(struct controlvm_message *inmsg)
{
struct controlvm_message_packet *cmd = &inmsg->cmd;
- ulong bus_no = cmd->device_change_state.bus_no;
- ulong dev_no = cmd->device_change_state.dev_no;
+ u32 bus_no = cmd->device_change_state.bus_no;
+ u32 dev_no = cmd->device_change_state.dev_no;
struct spar_segment_state state = cmd->device_change_state.state;
- struct visorchipset_device_info *dev_info = NULL;
+ struct visor_device *dev_info;
int rc = CONTROLVM_RESP_SUCCESS;
- dev_info = finddevice(&dev_info_list, bus_no, dev_no);
+ dev_info = visorbus_get_device_by_id(bus_no, dev_no, NULL);
if (!dev_info) {
POSTCODE_LINUX_4(DEVICE_CHANGESTATE_FAILURE_PC, dev_no, bus_no,
POSTCODE_SEVERITY_ERR);
@@ -1232,45 +1291,41 @@ my_device_changestate(struct controlvm_message *inmsg)
rc = -CONTROLVM_RESP_ERROR_DEVICE_INVALID;
}
if ((rc >= CONTROLVM_RESP_SUCCESS) && dev_info)
- device_epilog(bus_no, dev_no, state,
+ device_epilog(dev_info, state,
CONTROLVM_DEVICE_CHANGESTATE, &inmsg->hdr, rc,
- inmsg->hdr.flags.response_expected == 1,
- FOR_VISORBUS(
- dev_info->chan_info.channel_type_uuid));
+ inmsg->hdr.flags.response_expected == 1, 1);
}
static void
my_device_destroy(struct controlvm_message *inmsg)
{
struct controlvm_message_packet *cmd = &inmsg->cmd;
- ulong bus_no = cmd->destroy_device.bus_no;
- ulong dev_no = cmd->destroy_device.dev_no;
- struct visorchipset_device_info *dev_info = NULL;
+ u32 bus_no = cmd->destroy_device.bus_no;
+ u32 dev_no = cmd->destroy_device.dev_no;
+ struct visor_device *dev_info;
int rc = CONTROLVM_RESP_SUCCESS;
- dev_info = finddevice(&dev_info_list, bus_no, dev_no);
+ dev_info = visorbus_get_device_by_id(bus_no, dev_no, NULL);
if (!dev_info)
rc = -CONTROLVM_RESP_ERROR_DEVICE_INVALID;
else if (dev_info->state.created == 0)
rc = -CONTROLVM_RESP_ERROR_ALREADY_DONE;
if ((rc >= CONTROLVM_RESP_SUCCESS) && dev_info)
- device_epilog(bus_no, dev_no, segment_state_running,
+ device_epilog(dev_info, segment_state_running,
CONTROLVM_DEVICE_DESTROY, &inmsg->hdr, rc,
- inmsg->hdr.flags.response_expected == 1,
- FOR_VISORBUS(
- dev_info->chan_info.channel_type_uuid));
+ inmsg->hdr.flags.response_expected == 1, 1);
}
/* When provided with the physical address of the controlvm channel
* (phys_addr), the offset to the payload area we need to manage
* (offset), and the size of this payload area (bytes), fills in the
- * controlvm_payload_info struct. Returns TRUE for success or FALSE
+ * controlvm_payload_info struct. Returns true for success or false
* for failure.
*/
static int
-initialize_controlvm_payload_info(HOSTADDRESS phys_addr, u64 offset, u32 bytes,
- struct controlvm_payload_info *info)
+initialize_controlvm_payload_info(u64 phys_addr, u64 offset, u32 bytes,
+ struct visor_controlvm_payload_info *info)
{
u8 __iomem *payload = NULL;
int rc = CONTROLVM_RESP_SUCCESS;
@@ -1279,7 +1334,7 @@ initialize_controlvm_payload_info(HOSTADDRESS phys_addr, u64 offset, u32 bytes,
rc = -CONTROLVM_RESP_ERROR_PAYLOAD_INVALID;
goto cleanup;
}
- memset(info, 0, sizeof(struct controlvm_payload_info));
+ memset(info, 0, sizeof(struct visor_controlvm_payload_info));
if ((offset == 0) || (bytes == 0)) {
rc = -CONTROLVM_RESP_ERROR_PAYLOAD_INVALID;
goto cleanup;
@@ -1305,19 +1360,19 @@ cleanup:
}
static void
-destroy_controlvm_payload_info(struct controlvm_payload_info *info)
+destroy_controlvm_payload_info(struct visor_controlvm_payload_info *info)
{
if (info->ptr) {
iounmap(info->ptr);
info->ptr = NULL;
}
- memset(info, 0, sizeof(struct controlvm_payload_info));
+ memset(info, 0, sizeof(struct visor_controlvm_payload_info));
}
static void
initialize_controlvm_payload(void)
{
- HOSTADDRESS phys_addr = visorchannel_get_physaddr(controlvm_channel);
+ u64 phys_addr = visorchannel_get_physaddr(controlvm_channel);
u64 payload_offset = 0;
u32 payload_bytes = 0;
@@ -1345,15 +1400,14 @@ initialize_controlvm_payload(void)
/* Send ACTION=online for DEVPATH=/sys/devices/platform/visorchipset.
* Returns CONTROLVM_RESP_xxx code.
*/
-int
+static int
visorchipset_chipset_ready(void)
{
kobject_uevent(&visorchipset_platform_device.dev.kobj, KOBJ_ONLINE);
return CONTROLVM_RESP_SUCCESS;
}
-EXPORT_SYMBOL_GPL(visorchipset_chipset_ready);
-int
+static int
visorchipset_chipset_selftest(void)
{
char env_selftest[20];
@@ -1364,18 +1418,16 @@ visorchipset_chipset_selftest(void)
envp);
return CONTROLVM_RESP_SUCCESS;
}
-EXPORT_SYMBOL_GPL(visorchipset_chipset_selftest);
/* Send ACTION=offline for DEVPATH=/sys/devices/platform/visorchipset.
* Returns CONTROLVM_RESP_xxx code.
*/
-int
+static int
visorchipset_chipset_notready(void)
{
kobject_uevent(&visorchipset_platform_device.dev.kobj, KOBJ_OFFLINE);
return CONTROLVM_RESP_SUCCESS;
}
-EXPORT_SYMBOL_GPL(visorchipset_chipset_notready);
static void
chipset_ready(struct controlvm_message_header *msg_hdr)
@@ -1419,17 +1471,17 @@ chipset_notready(struct controlvm_message_header *msg_hdr)
/* This is your "one-stop" shop for grabbing the next message from the
* CONTROLVM_QUEUE_EVENT queue in the controlvm channel.
*/
-static BOOL
+static bool
read_controlvm_event(struct controlvm_message *msg)
{
if (visorchannel_signalremove(controlvm_channel,
CONTROLVM_QUEUE_EVENT, msg)) {
/* got a message */
if (msg->hdr.flags.test_message == 1)
- return FALSE;
- return TRUE;
+ return false;
+ return true;
}
- return FALSE;
+ return false;
}
/*
@@ -1535,8 +1587,8 @@ parahotplug_request_kickoff(struct parahotplug_request *req)
static void
parahotplug_process_list(void)
{
- struct list_head *pos = NULL;
- struct list_head *tmp = NULL;
+ struct list_head *pos;
+ struct list_head *tmp;
spin_lock(&parahotplug_request_list_lock);
@@ -1567,8 +1619,8 @@ parahotplug_process_list(void)
static int
parahotplug_request_complete(int id, u16 active)
{
- struct list_head *pos = NULL;
- struct list_head *tmp = NULL;
+ struct list_head *pos;
+ struct list_head *tmp;
spin_lock(&parahotplug_request_list_lock);
@@ -1640,29 +1692,29 @@ parahotplug_process_message(struct controlvm_message *inmsg)
/* Process a controlvm message.
* Return result:
- * FALSE - this function will return FALSE only in the case where the
+ * false - this function will return false only in the case where the
* controlvm message was NOT processed, but processing must be
* retried before reading the next controlvm message; a
* scenario where this can occur is when we need to throttle
* the allocation of memory in which to copy out controlvm
* payload data
- * TRUE - processing of the controlvm message completed,
+ * true - processing of the controlvm message completed,
* either successfully or with an error.
*/
-static BOOL
-handle_command(struct controlvm_message inmsg, HOSTADDRESS channel_addr)
+static bool
+handle_command(struct controlvm_message inmsg, u64 channel_addr)
{
struct controlvm_message_packet *cmd = &inmsg.cmd;
- u64 parm_addr = 0;
- u32 parm_bytes = 0;
+ u64 parm_addr;
+ u32 parm_bytes;
struct parser_context *parser_ctx = NULL;
- bool local_addr = false;
+ bool local_addr;
struct controlvm_message ackmsg;
/* create parsing context if necessary */
local_addr = (inmsg.hdr.flags.test_message == 1);
if (channel_addr == 0)
- return TRUE;
+ return true;
parm_addr = channel_addr + inmsg.hdr.payload_vm_offset;
parm_bytes = inmsg.hdr.payload_bytes;
@@ -1670,14 +1722,14 @@ handle_command(struct controlvm_message inmsg, HOSTADDRESS channel_addr)
* within our OS-controlled memory. We need to know that, because it
* makes a difference in how we compute the virtual address.
*/
- if (parm_addr != 0 && parm_bytes != 0) {
- BOOL retry = FALSE;
+ if (parm_addr && parm_bytes) {
+ bool retry = false;
parser_ctx =
parser_init_byte_stream(parm_addr, parm_bytes,
local_addr, &retry);
if (!parser_ctx && retry)
- return FALSE;
+ return false;
}
if (!local_addr) {
@@ -1711,7 +1763,6 @@ handle_command(struct controlvm_message inmsg, HOSTADDRESS channel_addr)
/* save the hdr and cmd structures for later use */
/* when sending back the response to Command */
my_device_changestate(&inmsg);
- g_diag_msg_hdr = inmsg.hdr;
g_devicechangestate_packet = inmsg.cmd;
break;
}
@@ -1744,10 +1795,26 @@ handle_command(struct controlvm_message inmsg, HOSTADDRESS channel_addr)
parser_done(parser_ctx);
parser_ctx = NULL;
}
- return TRUE;
+ return true;
}
-static HOSTADDRESS controlvm_get_channel_address(void)
+static inline unsigned int
+issue_vmcall_io_controlvm_addr(u64 *control_addr, u32 *control_bytes)
+{
+ struct vmcall_io_controlvm_addr_params params;
+ int result = VMCALL_SUCCESS;
+ u64 physaddr;
+
+ physaddr = virt_to_phys(&params);
+ ISSUE_IO_VMCALL(VMCALL_IO_CONTROLVM_ADDR, physaddr, result);
+ if (VMCALL_SUCCESSFUL(result)) {
+ *control_addr = params.address;
+ *control_bytes = params.channel_bytes;
+ }
+ return result;
+}
+
+static u64 controlvm_get_channel_address(void)
{
u64 addr = 0;
u32 size = 0;
@@ -1762,17 +1829,12 @@ static void
controlvm_periodic_work(struct work_struct *work)
{
struct controlvm_message inmsg;
- BOOL got_command = FALSE;
- BOOL handle_command_failed = FALSE;
+ bool got_command = false;
+ bool handle_command_failed = false;
static u64 poll_count;
/* make sure visorbus server is registered for controlvm callbacks */
- if (visorchipset_serverregwait && !serverregistered)
- goto cleanup;
- /* make sure visorclientbus server is regsitered for controlvm
- * callbacks
- */
- if (visorchipset_clientregwait && !clientregistered)
+ if (visorchipset_visorbusregwait && !visorbusregistered)
goto cleanup;
poll_count++;
@@ -1805,14 +1867,14 @@ controlvm_periodic_work(struct work_struct *work)
* rather than reading a new one
*/
inmsg = controlvm_pending_msg;
- controlvm_pending_msg_valid = FALSE;
+ controlvm_pending_msg_valid = false;
got_command = true;
} else {
got_command = read_controlvm_event(&inmsg);
}
}
- handle_command_failed = FALSE;
+ handle_command_failed = false;
while (got_command && (!handle_command_failed)) {
most_recent_message_jiffies = jiffies;
if (handle_command(inmsg,
@@ -1826,9 +1888,9 @@ controlvm_periodic_work(struct work_struct *work)
* controlvm msg so we will attempt to
* reprocess it on our next loop
*/
- handle_command_failed = TRUE;
+ handle_command_failed = true;
controlvm_pending_msg = inmsg;
- controlvm_pending_msg_valid = TRUE;
+ controlvm_pending_msg_valid = true;
}
}
@@ -1863,14 +1925,8 @@ setup_crash_devices_work_queue(struct work_struct *work)
u32 local_crash_msg_offset;
u16 local_crash_msg_count;
- /* make sure visorbus server is registered for controlvm callbacks */
- if (visorchipset_serverregwait && !serverregistered)
- goto cleanup;
-
- /* make sure visorclientbus server is regsitered for controlvm
- * callbacks
- */
- if (visorchipset_clientregwait && !clientregistered)
+ /* make sure visorbus is registered for controlvm callbacks */
+ if (visorchipset_visorbusregwait && !visorbusregistered)
goto cleanup;
POSTCODE_LINUX_2(CRASH_DEV_ENTRY_PC, POSTCODE_SEVERITY_INFO);
@@ -1931,7 +1987,7 @@ setup_crash_devices_work_queue(struct work_struct *work)
}
/* reuse IOVM create bus message */
- if (local_crash_bus_msg.cmd.create_bus.channel_addr != 0) {
+ if (local_crash_bus_msg.cmd.create_bus.channel_addr) {
bus_create(&local_crash_bus_msg);
} else {
POSTCODE_LINUX_2(CRASH_DEV_BUS_NULL_FAILURE_PC,
@@ -1940,7 +1996,7 @@ setup_crash_devices_work_queue(struct work_struct *work)
}
/* reuse create device message for storage device */
- if (local_crash_dev_msg.cmd.create_device.channel_addr != 0) {
+ if (local_crash_dev_msg.cmd.create_device.channel_addr) {
my_device_create(&local_crash_dev_msg);
} else {
POSTCODE_LINUX_2(CRASH_DEV_DEV_NULL_FAILURE_PC,
@@ -1959,135 +2015,71 @@ cleanup:
}
static void
-bus_create_response(ulong bus_no, int response)
+bus_create_response(struct visor_device *bus_info, int response)
{
- bus_responder(CONTROLVM_BUS_CREATE, bus_no, response);
-}
+ if (response >= 0)
+ bus_info->state.created = 1;
-static void
-bus_destroy_response(ulong bus_no, int response)
-{
- bus_responder(CONTROLVM_BUS_DESTROY, bus_no, response);
-}
+ bus_responder(CONTROLVM_BUS_CREATE, bus_info->pending_msg_hdr,
+ response);
-static void
-device_create_response(ulong bus_no, ulong dev_no, int response)
-{
- device_responder(CONTROLVM_DEVICE_CREATE, bus_no, dev_no, response);
+ kfree(bus_info->pending_msg_hdr);
+ bus_info->pending_msg_hdr = NULL;
}
static void
-device_destroy_response(ulong bus_no, ulong dev_no, int response)
+bus_destroy_response(struct visor_device *bus_info, int response)
{
- device_responder(CONTROLVM_DEVICE_DESTROY, bus_no, dev_no, response);
-}
+ bus_responder(CONTROLVM_BUS_DESTROY, bus_info->pending_msg_hdr,
+ response);
-void
-visorchipset_device_pause_response(ulong bus_no, ulong dev_no, int response)
-{
- device_changestate_responder(CONTROLVM_DEVICE_CHANGESTATE,
- bus_no, dev_no, response,
- segment_state_standby);
+ kfree(bus_info->pending_msg_hdr);
+ bus_info->pending_msg_hdr = NULL;
}
-EXPORT_SYMBOL_GPL(visorchipset_device_pause_response);
static void
-device_resume_response(ulong bus_no, ulong dev_no, int response)
-{
- device_changestate_responder(CONTROLVM_DEVICE_CHANGESTATE,
- bus_no, dev_no, response,
- segment_state_running);
-}
-
-BOOL
-visorchipset_get_bus_info(ulong bus_no, struct visorchipset_bus_info *bus_info)
-{
- void *p = findbus(&bus_info_list, bus_no);
-
- if (!p)
- return FALSE;
- memcpy(bus_info, p, sizeof(struct visorchipset_bus_info));
- return TRUE;
-}
-EXPORT_SYMBOL_GPL(visorchipset_get_bus_info);
-
-BOOL
-visorchipset_set_bus_context(ulong bus_no, void *context)
+device_create_response(struct visor_device *dev_info, int response)
{
- struct visorchipset_bus_info *p = findbus(&bus_info_list, bus_no);
-
- if (!p)
- return FALSE;
- p->bus_driver_context = context;
- return TRUE;
-}
-EXPORT_SYMBOL_GPL(visorchipset_set_bus_context);
+ if (response >= 0)
+ dev_info->state.created = 1;
-BOOL
-visorchipset_get_device_info(ulong bus_no, ulong dev_no,
- struct visorchipset_device_info *dev_info)
-{
- void *p = finddevice(&dev_info_list, bus_no, dev_no);
+ device_responder(CONTROLVM_DEVICE_CREATE, dev_info->pending_msg_hdr,
+ response);
- if (!p)
- return FALSE;
- memcpy(dev_info, p, sizeof(struct visorchipset_device_info));
- return TRUE;
+ kfree(dev_info->pending_msg_hdr);
}
-EXPORT_SYMBOL_GPL(visorchipset_get_device_info);
-BOOL
-visorchipset_set_device_context(ulong bus_no, ulong dev_no, void *context)
+static void
+device_destroy_response(struct visor_device *dev_info, int response)
{
- struct visorchipset_device_info *p =
- finddevice(&dev_info_list, bus_no, dev_no);
+ device_responder(CONTROLVM_DEVICE_DESTROY, dev_info->pending_msg_hdr,
+ response);
- if (!p)
- return FALSE;
- p->bus_driver_context = context;
- return TRUE;
+ kfree(dev_info->pending_msg_hdr);
+ dev_info->pending_msg_hdr = NULL;
}
-EXPORT_SYMBOL_GPL(visorchipset_set_device_context);
-/* Generic wrapper function for allocating memory from a kmem_cache pool.
- */
-void *
-visorchipset_cache_alloc(struct kmem_cache *pool, BOOL ok_to_block,
- char *fn, int ln)
+static void
+visorchipset_device_pause_response(struct visor_device *dev_info,
+ int response)
{
- gfp_t gfp;
- void *p;
-
- if (ok_to_block)
- gfp = GFP_KERNEL;
- else
- gfp = GFP_ATOMIC;
- /* __GFP_NORETRY means "ok to fail", meaning
- * kmem_cache_alloc() can return NULL, implying the caller CAN
- * cope with failure. If you do NOT specify __GFP_NORETRY,
- * Linux will go to extreme measures to get memory for you
- * (like, invoke oom killer), which will probably cripple the
- * system.
- */
- gfp |= __GFP_NORETRY;
- p = kmem_cache_alloc(pool, gfp);
- if (!p)
- return NULL;
+ device_changestate_responder(CONTROLVM_DEVICE_CHANGESTATE,
+ dev_info, response,
+ segment_state_standby);
- atomic_inc(&visorchipset_cache_buffers_in_use);
- return p;
+ kfree(dev_info->pending_msg_hdr);
+ dev_info->pending_msg_hdr = NULL;
}
-/* Generic wrapper function for freeing memory from a kmem_cache pool.
- */
-void
-visorchipset_cache_free(struct kmem_cache *pool, void *p, char *fn, int ln)
+static void
+device_resume_response(struct visor_device *dev_info, int response)
{
- if (!p)
- return;
+ device_changestate_responder(CONTROLVM_DEVICE_CHANGESTATE,
+ dev_info, response,
+ segment_state_running);
- atomic_dec(&visorchipset_cache_buffers_in_use);
- kmem_cache_free(pool, p);
+ kfree(dev_info->pending_msg_hdr);
+ dev_info->pending_msg_hdr = NULL;
}
static ssize_t chipsetready_store(struct device *dev,
@@ -2099,10 +2091,10 @@ static ssize_t chipsetready_store(struct device *dev,
if (sscanf(buf, "%63s", msgtype) != 1)
return -EINVAL;
- if (strcmp(msgtype, "CALLHOMEDISK_MOUNTED") == 0) {
+ if (!strcmp(msgtype, "CALLHOMEDISK_MOUNTED")) {
chipset_events[0] = 1;
return count;
- } else if (strcmp(msgtype, "MODULES_LOADED") == 0) {
+ } else if (!strcmp(msgtype, "MODULES_LOADED")) {
chipset_events[1] = 1;
return count;
}
@@ -2117,9 +2109,9 @@ static ssize_t devicedisabled_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
- uint id;
+ unsigned int id;
- if (kstrtouint(buf, 10, &id) != 0)
+ if (kstrtouint(buf, 10, &id))
return -EINVAL;
parahotplug_request_complete(id, 0);
@@ -2134,52 +2126,158 @@ static ssize_t deviceenabled_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
- uint id;
+ unsigned int id;
- if (kstrtouint(buf, 10, &id) != 0)
+ if (kstrtouint(buf, 10, &id))
return -EINVAL;
parahotplug_request_complete(id, 1);
return count;
}
-static int __init
-visorchipset_init(void)
+static int
+visorchipset_mmap(struct file *file, struct vm_area_struct *vma)
{
- int rc = 0, x = 0;
- HOSTADDRESS addr;
+ unsigned long physaddr = 0;
+ unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+ u64 addr = 0;
- if (!unisys_spar_platform)
- return -ENODEV;
+ /* sv_enable_dfp(); */
+ if (offset & (PAGE_SIZE - 1))
+ return -ENXIO; /* need aligned offsets */
- memset(&busdev_server_notifiers, 0, sizeof(busdev_server_notifiers));
- memset(&busdev_client_notifiers, 0, sizeof(busdev_client_notifiers));
- memset(&controlvm_payload_info, 0, sizeof(controlvm_payload_info));
- memset(&livedump_info, 0, sizeof(livedump_info));
- atomic_set(&livedump_info.buffers_in_use, 0);
+ switch (offset) {
+ case VISORCHIPSET_MMAP_CONTROLCHANOFFSET:
+ vma->vm_flags |= VM_IO;
+ if (!*file_controlvm_channel)
+ return -ENXIO;
- if (visorchipset_testvnic) {
- POSTCODE_LINUX_3(CHIPSET_INIT_FAILURE_PC, x, DIAG_SEVERITY_ERR);
- rc = x;
- goto cleanup;
+ visorchannel_read(*file_controlvm_channel,
+ offsetof(struct spar_controlvm_channel_protocol,
+ gp_control_channel),
+ &addr, sizeof(addr));
+ if (!addr)
+ return -ENXIO;
+
+ physaddr = (unsigned long)addr;
+ if (remap_pfn_range(vma, vma->vm_start,
+ physaddr >> PAGE_SHIFT,
+ vma->vm_end - vma->vm_start,
+ /*pgprot_noncached */
+ (vma->vm_page_prot))) {
+ return -EAGAIN;
+ }
+ break;
+ default:
+ return -ENXIO;
}
+ return 0;
+}
- addr = controlvm_get_channel_address();
- if (addr != 0) {
- controlvm_channel =
- visorchannel_create_with_lock
- (addr,
- sizeof(struct spar_controlvm_channel_protocol),
- spar_controlvm_channel_protocol_uuid);
- if (SPAR_CONTROLVM_CHANNEL_OK_CLIENT(
- visorchannel_get_header(controlvm_channel))) {
- initialize_controlvm_payload();
- } else {
- visorchannel_destroy(controlvm_channel);
- controlvm_channel = NULL;
- return -ENODEV;
+static inline s64 issue_vmcall_query_guest_virtual_time_offset(void)
+{
+ u64 result = VMCALL_SUCCESS;
+ u64 physaddr = 0;
+
+ ISSUE_IO_VMCALL(VMCALL_QUERY_GUEST_VIRTUAL_TIME_OFFSET, physaddr,
+ result);
+ return result;
+}
+
+static inline int issue_vmcall_update_physical_time(u64 adjustment)
+{
+ int result = VMCALL_SUCCESS;
+
+ ISSUE_IO_VMCALL(VMCALL_UPDATE_PHYSICAL_TIME, adjustment, result);
+ return result;
+}
+
+static long visorchipset_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ s64 adjustment;
+ s64 vrtc_offset;
+
+ switch (cmd) {
+ case VMCALL_QUERY_GUEST_VIRTUAL_TIME_OFFSET:
+ /* get the physical rtc offset */
+ vrtc_offset = issue_vmcall_query_guest_virtual_time_offset();
+ if (copy_to_user((void __user *)arg, &vrtc_offset,
+ sizeof(vrtc_offset))) {
+ return -EFAULT;
+ }
+ return 0;
+ case VMCALL_UPDATE_PHYSICAL_TIME:
+ if (copy_from_user(&adjustment, (void __user *)arg,
+ sizeof(adjustment))) {
+ return -EFAULT;
}
+ return issue_vmcall_update_physical_time(adjustment);
+ default:
+ return -EFAULT;
+ }
+}
+
+static const struct file_operations visorchipset_fops = {
+ .owner = THIS_MODULE,
+ .open = visorchipset_open,
+ .read = NULL,
+ .write = NULL,
+ .unlocked_ioctl = visorchipset_ioctl,
+ .release = visorchipset_release,
+ .mmap = visorchipset_mmap,
+};
+
+static int
+visorchipset_file_init(dev_t major_dev, struct visorchannel **controlvm_channel)
+{
+ int rc = 0;
+
+ file_controlvm_channel = controlvm_channel;
+ cdev_init(&file_cdev, &visorchipset_fops);
+ file_cdev.owner = THIS_MODULE;
+ if (MAJOR(major_dev) == 0) {
+ rc = alloc_chrdev_region(&major_dev, 0, 1, "visorchipset");
+ /* dynamic major device number registration required */
+ if (rc < 0)
+ return rc;
+ } else {
+ /* static major device number registration required */
+ rc = register_chrdev_region(major_dev, 1, "visorchipset");
+ if (rc < 0)
+ return rc;
+ }
+ rc = cdev_add(&file_cdev, MKDEV(MAJOR(major_dev), 0), 1);
+ if (rc < 0) {
+ unregister_chrdev_region(major_dev, 1);
+ return rc;
+ }
+ return 0;
+}
+
+static int
+visorchipset_init(struct acpi_device *acpi_device)
+{
+ int rc = 0;
+ u64 addr;
+ int tmp_sz = sizeof(struct spar_controlvm_channel_protocol);
+ uuid_le uuid = SPAR_CONTROLVM_CHANNEL_PROTOCOL_UUID;
+
+ addr = controlvm_get_channel_address();
+ if (!addr)
+ return -ENODEV;
+
+ memset(&busdev_notifiers, 0, sizeof(busdev_notifiers));
+ memset(&controlvm_payload_info, 0, sizeof(controlvm_payload_info));
+
+ controlvm_channel = visorchannel_create_with_lock(addr, tmp_sz,
+ GFP_KERNEL, uuid);
+ if (SPAR_CONTROLVM_CHANNEL_OK_CLIENT(
+ visorchannel_get_header(controlvm_channel))) {
+ initialize_controlvm_payload();
} else {
+ visorchannel_destroy(controlvm_channel);
+ controlvm_channel = NULL;
return -ENODEV;
}
@@ -2190,47 +2288,32 @@ visorchipset_init(void)
goto cleanup;
}
- memset(&g_diag_msg_hdr, 0, sizeof(struct controlvm_message_header));
-
memset(&g_chipset_msg_hdr, 0, sizeof(struct controlvm_message_header));
- memset(&g_del_dump_msg_hdr, 0, sizeof(struct controlvm_message_header));
-
- putfile_buffer_list_pool =
- kmem_cache_create(putfile_buffer_list_pool_name,
- sizeof(struct putfile_buffer_entry),
- 0, SLAB_HWCACHE_ALIGN, NULL);
- if (!putfile_buffer_list_pool) {
- POSTCODE_LINUX_2(CHIPSET_INIT_FAILURE_PC, DIAG_SEVERITY_ERR);
- rc = -1;
+ /* if booting in a crash kernel */
+ if (is_kdump_kernel())
+ INIT_DELAYED_WORK(&periodic_controlvm_work,
+ setup_crash_devices_work_queue);
+ else
+ INIT_DELAYED_WORK(&periodic_controlvm_work,
+ controlvm_periodic_work);
+ periodic_controlvm_workqueue =
+ create_singlethread_workqueue("visorchipset_controlvm");
+
+ if (!periodic_controlvm_workqueue) {
+ POSTCODE_LINUX_2(CREATE_WORKQUEUE_FAILED_PC,
+ DIAG_SEVERITY_ERR);
+ rc = -ENOMEM;
goto cleanup;
}
- if (!visorchipset_disable_controlvm) {
- /* if booting in a crash kernel */
- if (visorchipset_crash_kernel)
- INIT_DELAYED_WORK(&periodic_controlvm_work,
- setup_crash_devices_work_queue);
- else
- INIT_DELAYED_WORK(&periodic_controlvm_work,
- controlvm_periodic_work);
- periodic_controlvm_workqueue =
- create_singlethread_workqueue("visorchipset_controlvm");
-
- if (!periodic_controlvm_workqueue) {
- POSTCODE_LINUX_2(CREATE_WORKQUEUE_FAILED_PC,
- DIAG_SEVERITY_ERR);
- rc = -ENOMEM;
- goto cleanup;
- }
- most_recent_message_jiffies = jiffies;
- poll_jiffies = POLLJIFFIES_CONTROLVMCHANNEL_FAST;
- rc = queue_delayed_work(periodic_controlvm_workqueue,
- &periodic_controlvm_work, poll_jiffies);
- if (rc < 0) {
- POSTCODE_LINUX_2(QUEUE_DELAYED_WORK_PC,
- DIAG_SEVERITY_ERR);
- goto cleanup;
- }
+ most_recent_message_jiffies = jiffies;
+ poll_jiffies = POLLJIFFIES_CONTROLVMCHANNEL_FAST;
+ rc = queue_delayed_work(periodic_controlvm_workqueue,
+ &periodic_controlvm_work, poll_jiffies);
+ if (rc < 0) {
+ POSTCODE_LINUX_2(QUEUE_DELAYED_WORK_PC,
+ DIAG_SEVERITY_ERR);
+ goto cleanup;
}
visorchipset_platform_device.dev.devt = major_dev;
@@ -2240,7 +2323,8 @@ visorchipset_init(void)
goto cleanup;
}
POSTCODE_LINUX_2(CHIPSET_INIT_SUCCESS_PC, POSTCODE_SEVERITY_INFO);
- rc = 0;
+
+ rc = visorbus_init();
cleanup:
if (rc) {
POSTCODE_LINUX_3(CHIPSET_INIT_FAILURE_PC, rc,
@@ -2250,83 +2334,101 @@ cleanup:
}
static void
-visorchipset_exit(void)
+visorchipset_file_cleanup(dev_t major_dev)
{
- POSTCODE_LINUX_2(DRIVER_EXIT_PC, POSTCODE_SEVERITY_INFO);
+ if (file_cdev.ops)
+ cdev_del(&file_cdev);
+ file_cdev.ops = NULL;
+ unregister_chrdev_region(major_dev, 1);
+}
- if (visorchipset_disable_controlvm) {
- ;
- } else {
- cancel_delayed_work(&periodic_controlvm_work);
- flush_workqueue(periodic_controlvm_workqueue);
- destroy_workqueue(periodic_controlvm_workqueue);
- periodic_controlvm_workqueue = NULL;
- destroy_controlvm_payload_info(&controlvm_payload_info);
- }
- if (putfile_buffer_list_pool) {
- kmem_cache_destroy(putfile_buffer_list_pool);
- putfile_buffer_list_pool = NULL;
- }
+static int
+visorchipset_exit(struct acpi_device *acpi_device)
+{
+ POSTCODE_LINUX_2(DRIVER_EXIT_PC, POSTCODE_SEVERITY_INFO);
- cleanup_controlvm_structures();
+ visorbus_exit();
- memset(&g_diag_msg_hdr, 0, sizeof(struct controlvm_message_header));
+ cancel_delayed_work(&periodic_controlvm_work);
+ flush_workqueue(periodic_controlvm_workqueue);
+ destroy_workqueue(periodic_controlvm_workqueue);
+ periodic_controlvm_workqueue = NULL;
+ destroy_controlvm_payload_info(&controlvm_payload_info);
memset(&g_chipset_msg_hdr, 0, sizeof(struct controlvm_message_header));
- memset(&g_del_dump_msg_hdr, 0, sizeof(struct controlvm_message_header));
-
visorchannel_destroy(controlvm_channel);
visorchipset_file_cleanup(visorchipset_platform_device.dev.devt);
+ platform_device_unregister(&visorchipset_platform_device);
POSTCODE_LINUX_2(DRIVER_EXIT_PC, POSTCODE_SEVERITY_INFO);
+
+ return 0;
}
-module_param_named(testvnic, visorchipset_testvnic, int, S_IRUGO);
-MODULE_PARM_DESC(visorchipset_testvnic, "1 to test vnic, using dummy VNIC connected via a loopback to a physical ethernet");
-int visorchipset_testvnic = 0;
+static const struct acpi_device_id unisys_device_ids[] = {
+ {"PNP0A07", 0},
+ {"", 0},
+};
-module_param_named(testvnicclient, visorchipset_testvnicclient, int, S_IRUGO);
-MODULE_PARM_DESC(visorchipset_testvnicclient, "1 to test vnic, using real VNIC channel attached to a separate IOVM guest");
-int visorchipset_testvnicclient = 0;
+static struct acpi_driver unisys_acpi_driver = {
+ .name = "unisys_acpi",
+ .class = "unisys_acpi_class",
+ .owner = THIS_MODULE,
+ .ids = unisys_device_ids,
+ .ops = {
+ .add = visorchipset_init,
+ .remove = visorchipset_exit,
+ },
+};
+static __init uint32_t visorutil_spar_detect(void)
+{
+ unsigned int eax, ebx, ecx, edx;
-module_param_named(testmsg, visorchipset_testmsg, int, S_IRUGO);
-MODULE_PARM_DESC(visorchipset_testmsg,
- "1 to manufacture the chipset, bus, and switch messages");
-int visorchipset_testmsg = 0;
+ if (cpu_has_hypervisor) {
+ /* check the ID */
+ cpuid(UNISYS_SPAR_LEAF_ID, &eax, &ebx, &ecx, &edx);
+ return (ebx == UNISYS_SPAR_ID_EBX) &&
+ (ecx == UNISYS_SPAR_ID_ECX) &&
+ (edx == UNISYS_SPAR_ID_EDX);
+ } else {
+ return 0;
+ }
+}
-module_param_named(major, visorchipset_major, int, S_IRUGO);
-MODULE_PARM_DESC(visorchipset_major, "major device number to use for the device node");
-int visorchipset_major = 0;
+static int init_unisys(void)
+{
+ int result;
+
+ if (!visorutil_spar_detect())
+ return -ENODEV;
+
+ result = acpi_bus_register_driver(&unisys_acpi_driver);
+ if (result)
+ return -ENODEV;
+
+ pr_info("Unisys Visorchipset Driver Loaded.\n");
+ return 0;
+};
+
+static void exit_unisys(void)
+{
+ acpi_bus_unregister_driver(&unisys_acpi_driver);
+}
-module_param_named(serverregwait, visorchipset_serverregwait, int, S_IRUGO);
-MODULE_PARM_DESC(visorchipset_serverreqwait,
+module_param_named(major, visorchipset_major, int, S_IRUGO);
+MODULE_PARM_DESC(visorchipset_major,
+ "major device number to use for the device node");
+module_param_named(visorbusregwait, visorchipset_visorbusregwait, int, S_IRUGO);
+MODULE_PARM_DESC(visorchipset_visorbusreqwait,
"1 to have the module wait for the visor bus to register");
-int visorchipset_serverregwait = 0; /* default is off */
-module_param_named(clientregwait, visorchipset_clientregwait, int, S_IRUGO);
-MODULE_PARM_DESC(visorchipset_clientregwait, "1 to have the module wait for the visorclientbus to register");
-int visorchipset_clientregwait = 1; /* default is on */
-module_param_named(testteardown, visorchipset_testteardown, int, S_IRUGO);
-MODULE_PARM_DESC(visorchipset_testteardown,
- "1 to test teardown of the chipset, bus, and switch");
-int visorchipset_testteardown = 0; /* default is off */
-module_param_named(disable_controlvm, visorchipset_disable_controlvm, int,
- S_IRUGO);
-MODULE_PARM_DESC(visorchipset_disable_controlvm,
- "1 to disable polling of controlVm channel");
-int visorchipset_disable_controlvm = 0; /* default is off */
-module_param_named(crash_kernel, visorchipset_crash_kernel, int, S_IRUGO);
-MODULE_PARM_DESC(visorchipset_crash_kernel,
- "1 means we are running in crash kernel");
-int visorchipset_crash_kernel = 0; /* default is running in non-crash kernel */
module_param_named(holdchipsetready, visorchipset_holdchipsetready,
int, S_IRUGO);
MODULE_PARM_DESC(visorchipset_holdchipsetready,
"1 to hold response to CHIPSET_READY");
-int visorchipset_holdchipsetready = 0; /* default is to send CHIPSET_READY
- * response immediately */
-module_init(visorchipset_init);
-module_exit(visorchipset_exit);
+
+module_init(init_unisys);
+module_exit(exit_unisys);
MODULE_AUTHOR("Unisys");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/unisys/common-spar/include/vmcallinterface.h b/drivers/staging/unisys/visorbus/vmcallinterface.h
index 59a7459eb..7a53df007 100644
--- a/drivers/staging/unisys/common-spar/include/vmcallinterface.h
+++ b/drivers/staging/unisys/visorbus/vmcallinterface.h
@@ -85,10 +85,8 @@ enum vmcall_monitor_interface_method_tuple { /* VMCALL identification tuples */
/* The following uses VMCALL_POST_CODE_LOGEVENT interface but is currently
* not used much */
#define ISSUE_IO_VMCALL_POSTCODE_SEVERITY(postcode, severity) \
-do { \
ISSUE_IO_EXTENDED_VMCALL(VMCALL_POST_CODE_LOGEVENT, severity, \
- MDS_APPOS, postcode); \
-} while (0)
+ MDS_APPOS, postcode)
#endif
/* Structures for IO VMCALLs */
@@ -96,18 +94,6 @@ do { \
/* ///////////// BEGIN PRAGMA PACK PUSH 1 ///////////////////////// */
/* ///////////// ONLY STRUCT TYPE SHOULD BE BELOW */
#pragma pack(push, 1)
-struct phys_info {
- u64 pi_pfn;
- u16 pi_off;
- u16 pi_len;
-};
-
-#pragma pack(pop)
-/* ///////////// END PRAGMA PACK PUSH 1 /////////////////////////// */
-
-/* ///////////// BEGIN PRAGMA PACK PUSH 1 ///////////////////////// */
-/* ///////////// ONLY STRUCT TYPE SHOULD BE BELOW */
-#pragma pack(push, 1)
/* Parameters to VMCALL_IO_CONTROLVM_ADDR interface */
struct vmcall_io_controlvm_addr_params {
/* The Guest-relative physical address of the ControlVm channel.
diff --git a/drivers/staging/unisys/visorchannel/Kconfig b/drivers/staging/unisys/visorchannel/Kconfig
deleted file mode 100644
index 8d31bebf0..000000000
--- a/drivers/staging/unisys/visorchannel/Kconfig
+++ /dev/null
@@ -1,10 +0,0 @@
-#
-# Unisys visorchannel configuration
-#
-
-config UNISYS_VISORCHANNEL
- tristate "Unisys visorchannel driver"
- select UNISYS_VISORUTIL
- ---help---
- If you say Y here, you will enable the Unisys visorchannel driver.
-
diff --git a/drivers/staging/unisys/visorchannel/Makefile b/drivers/staging/unisys/visorchannel/Makefile
deleted file mode 100644
index e079c96b1..000000000
--- a/drivers/staging/unisys/visorchannel/Makefile
+++ /dev/null
@@ -1,12 +0,0 @@
-#
-# Makefile for Unisys visorchannel
-#
-
-obj-$(CONFIG_UNISYS_VISORCHANNEL) += visorchannel.o
-
-visorchannel-y := visorchannel_main.o visorchannel_funcs.o
-
-ccflags-y += -Idrivers/staging/unisys/include
-ccflags-y += -Idrivers/staging/unisys/common-spar/include
-ccflags-y += -Idrivers/staging/unisys/common-spar/include/channels
-ccflags-y += -Idrivers/staging/unisys/visorutil
diff --git a/drivers/staging/unisys/visorchannel/globals.h b/drivers/staging/unisys/visorchannel/globals.h
deleted file mode 100644
index 0ed8e1d80..000000000
--- a/drivers/staging/unisys/visorchannel/globals.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/* globals.h
- *
- * Copyright (C) 2010 - 2013 UNISYS CORPORATION
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
- * NON INFRINGEMENT. See the GNU General Public License for more
- * details.
- */
-
-#ifndef __VISORCHANNEL_GLOBALS_H__
-#define __VISORCHANNEL_GLOBALS_H__
-
-#include "timskmod.h"
-#include "memregion.h"
-#include "version.h"
-
-#define MYDRVNAME "visorchannel"
-
-#endif
diff --git a/drivers/staging/unisys/visorchannel/visorchannel.h b/drivers/staging/unisys/visorchannel/visorchannel.h
deleted file mode 100644
index 63f1b9760..000000000
--- a/drivers/staging/unisys/visorchannel/visorchannel.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/* visorchannel.h
- *
- * Copyright (C) 2010 - 2013 UNISYS CORPORATION
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
- * NON INFRINGEMENT. See the GNU General Public License for more
- * details.
- */
-
-#ifndef __VISORCHANNEL_H__
-#define __VISORCHANNEL_H__
-
-#include <linux/uuid.h>
-
-#include "memregion.h"
-#include "channel.h"
-#ifndef HOSTADDRESS
-#define HOSTADDRESS u64
-#endif
-#ifndef BOOL
-#define BOOL int
-#endif
-
-/* Note that for visorchannel_create() and visorchannel_create_overlapped(),
- * <channel_bytes> and <guid> arguments may be 0 if we are a channel CLIENT.
- * In this case, the values can simply be read from the channel header.
- */
-struct visorchannel *visorchannel_create(HOSTADDRESS physaddr,
- ulong channel_bytes, uuid_le guid);
-struct visorchannel *visorchannel_create_overlapped(ulong channel_bytes,
- struct visorchannel *parent,
- ulong off, uuid_le guid);
-struct visorchannel *visorchannel_create_with_lock(HOSTADDRESS physaddr,
- ulong channel_bytes,
- uuid_le guid);
-struct visorchannel *visorchannel_create_overlapped_with_lock(
- ulong channel_bytes,
- struct visorchannel *parent,
- ulong off, uuid_le guid);
-void visorchannel_destroy(struct visorchannel *channel);
-int visorchannel_read(struct visorchannel *channel, ulong offset,
- void *local, ulong nbytes);
-int visorchannel_write(struct visorchannel *channel, ulong offset,
- void *local, ulong nbytes);
-int visorchannel_clear(struct visorchannel *channel, ulong offset,
- u8 ch, ulong nbytes);
-BOOL visorchannel_signalremove(struct visorchannel *channel, u32 queue,
- void *msg);
-BOOL visorchannel_signalinsert(struct visorchannel *channel, u32 queue,
- void *msg);
-int visorchannel_signalqueue_slots_avail(struct visorchannel *channel,
- u32 queue);
-int visorchannel_signalqueue_max_slots(struct visorchannel *channel, u32 queue);
-HOSTADDRESS visorchannel_get_physaddr(struct visorchannel *channel);
-ulong visorchannel_get_nbytes(struct visorchannel *channel);
-char *visorchannel_id(struct visorchannel *channel, char *s);
-char *visorchannel_zoneid(struct visorchannel *channel, char *s);
-u64 visorchannel_get_clientpartition(struct visorchannel *channel);
-uuid_le visorchannel_get_uuid(struct visorchannel *channel);
-struct memregion *visorchannel_get_memregion(struct visorchannel *channel);
-char *visorchannel_uuid_id(uuid_le *guid, char *s);
-void visorchannel_debug(struct visorchannel *channel, int num_queues,
- struct seq_file *seq, u32 off);
-void visorchannel_dump_section(struct visorchannel *chan, char *s,
- int off, int len, struct seq_file *seq);
-void __iomem *visorchannel_get_header(struct visorchannel *channel);
-
-#endif
diff --git a/drivers/staging/unisys/visorchannel/visorchannel_main.c b/drivers/staging/unisys/visorchannel/visorchannel_main.c
deleted file mode 100644
index 787d4774b..000000000
--- a/drivers/staging/unisys/visorchannel/visorchannel_main.c
+++ /dev/null
@@ -1,50 +0,0 @@
-/* visorchannel_main.c
- *
- * Copyright (C) 2010 - 2013 UNISYS CORPORATION
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
- * NON INFRINGEMENT. See the GNU General Public License for more
- * details.
- */
-
-/*
- * This is a module "wrapper" around visorchannel_funcs.
- */
-
-#include "globals.h"
-#include "channel.h"
-#include "visorchannel.h"
-#include <linux/uuid.h>
-
-#define MYDRVNAME "visorchannel"
-
-static int __init
-visorchannel_init(void)
-{
- if (!unisys_spar_platform)
- return -ENODEV;
-
- return 0;
-}
-
-static void
-visorchannel_exit(void)
-{
-}
-
-module_init(visorchannel_init);
-module_exit(visorchannel_exit);
-
-MODULE_AUTHOR("Unisys");
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Supervisor channel driver for service partition: ver "
- VERSION);
-MODULE_VERSION(VERSION);
diff --git a/drivers/staging/unisys/visorchipset/Kconfig b/drivers/staging/unisys/visorchipset/Kconfig
deleted file mode 100644
index b03bfc5c3..000000000
--- a/drivers/staging/unisys/visorchipset/Kconfig
+++ /dev/null
@@ -1,11 +0,0 @@
-#
-# Unisys visorchipset configuration
-#
-
-config UNISYS_VISORCHIPSET
- tristate "Unisys visorchipset driver"
- select UNISYS_VISORUTIL
- select UNISYS_VISORCHANNEL
- ---help---
- If you say Y here, you will enable the Unisys visorchipset driver.
-
diff --git a/drivers/staging/unisys/visorchipset/Makefile b/drivers/staging/unisys/visorchipset/Makefile
deleted file mode 100644
index 12686906b..000000000
--- a/drivers/staging/unisys/visorchipset/Makefile
+++ /dev/null
@@ -1,15 +0,0 @@
-#
-# Makefile for Unisys visorchipset
-#
-
-obj-$(CONFIG_UNISYS_VISORCHIPSET) += visorchipset.o
-
-visorchipset-y := visorchipset_main.o file.o parser.o
-
-ccflags-y += -Idrivers/staging/unisys/include
-ccflags-y += -Idrivers/staging/unisys/uislib
-ccflags-y += -Idrivers/staging/unisys/visorchannel
-ccflags-y += -Idrivers/staging/unisys/common-spar/include
-ccflags-y += -Idrivers/staging/unisys/common-spar/include/channels
-ccflags-y += -Idrivers/staging/unisys/visorutil
-ccflags-y += -Iinclude/generated
diff --git a/drivers/staging/unisys/visorchipset/file.c b/drivers/staging/unisys/visorchipset/file.c
deleted file mode 100644
index 203de0b5f..000000000
--- a/drivers/staging/unisys/visorchipset/file.c
+++ /dev/null
@@ -1,160 +0,0 @@
-/* file.c
- *
- * Copyright (C) 2010 - 2013 UNISYS CORPORATION
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
- * NON INFRINGEMENT. See the GNU General Public License for more
- * details.
- */
-
-/* This contains the implementation that allows a usermode program to
- * communicate with the visorchipset driver using a device/file interface.
- */
-
-#include "globals.h"
-#include "visorchannel.h"
-#include <linux/mm.h>
-#include <linux/fs.h>
-#include "uisutils.h"
-#include "file.h"
-
-#define CURRENT_FILE_PC VISOR_CHIPSET_PC_file_c
-
-static struct cdev file_cdev;
-static struct visorchannel **file_controlvm_channel;
-
-void
-visorchipset_file_cleanup(dev_t major_dev)
-{
- if (file_cdev.ops != NULL)
- cdev_del(&file_cdev);
- file_cdev.ops = NULL;
- unregister_chrdev_region(major_dev, 1);
-}
-
-static int
-visorchipset_open(struct inode *inode, struct file *file)
-{
- unsigned minor_number = iminor(inode);
-
- if (minor_number != 0)
- return -ENODEV;
- file->private_data = NULL;
- return 0;
-}
-
-static int
-visorchipset_release(struct inode *inode, struct file *file)
-{
- return 0;
-}
-
-static int
-visorchipset_mmap(struct file *file, struct vm_area_struct *vma)
-{
- ulong physaddr = 0;
- ulong offset = vma->vm_pgoff << PAGE_SHIFT;
- GUEST_PHYSICAL_ADDRESS addr = 0;
-
- /* sv_enable_dfp(); */
- if (offset & (PAGE_SIZE - 1))
- return -ENXIO; /* need aligned offsets */
-
- switch (offset) {
- case VISORCHIPSET_MMAP_CONTROLCHANOFFSET:
- vma->vm_flags |= VM_IO;
- if (*file_controlvm_channel == NULL) {
- return -ENXIO;
- }
- visorchannel_read(*file_controlvm_channel,
- offsetof(struct spar_controlvm_channel_protocol,
- gp_control_channel),
- &addr, sizeof(addr));
- if (addr == 0) {
- return -ENXIO;
- }
- physaddr = (ulong)addr;
- if (remap_pfn_range(vma, vma->vm_start,
- physaddr >> PAGE_SHIFT,
- vma->vm_end - vma->vm_start,
- /*pgprot_noncached */
- (vma->vm_page_prot))) {
- return -EAGAIN;
- }
- break;
- default:
- return -ENOSYS;
- }
- return 0;
-}
-
-static long visorchipset_ioctl(struct file *file, unsigned int cmd,
- unsigned long arg)
-{
- s64 adjustment;
- s64 vrtc_offset;
-
- switch (cmd) {
- case VMCALL_QUERY_GUEST_VIRTUAL_TIME_OFFSET:
- /* get the physical rtc offset */
- vrtc_offset = issue_vmcall_query_guest_virtual_time_offset();
- if (copy_to_user
- ((void __user *)arg, &vrtc_offset, sizeof(vrtc_offset))) {
- return -EFAULT;
- }
- return SUCCESS;
- case VMCALL_UPDATE_PHYSICAL_TIME:
- if (copy_from_user
- (&adjustment, (void __user *)arg, sizeof(adjustment))) {
- return -EFAULT;
- }
- return issue_vmcall_update_physical_time(adjustment);
- default:
- return -EFAULT;
- }
-}
-
-static const struct file_operations visorchipset_fops = {
- .owner = THIS_MODULE,
- .open = visorchipset_open,
- .read = NULL,
- .write = NULL,
- .unlocked_ioctl = visorchipset_ioctl,
- .release = visorchipset_release,
- .mmap = visorchipset_mmap,
-};
-
-int
-visorchipset_file_init(dev_t major_dev, struct visorchannel **controlvm_channel)
-{
- int rc = 0;
-
- file_controlvm_channel = controlvm_channel;
- cdev_init(&file_cdev, &visorchipset_fops);
- file_cdev.owner = THIS_MODULE;
- if (MAJOR(major_dev) == 0) {
- rc = alloc_chrdev_region(&major_dev, 0, 1, MYDRVNAME);
- /* dynamic major device number registration required */
- if (rc < 0)
- return rc;
- } else {
- /* static major device number registration required */
- rc = register_chrdev_region(major_dev, 1, MYDRVNAME);
- if (rc < 0)
- return rc;
- }
- rc = cdev_add(&file_cdev, MKDEV(MAJOR(major_dev), 0), 1);
- if (rc < 0) {
- unregister_chrdev_region(major_dev, 1);
- return rc;
- }
- return 0;
-}
diff --git a/drivers/staging/unisys/visorchipset/file.h b/drivers/staging/unisys/visorchipset/file.h
deleted file mode 100644
index 51f7699b7..000000000
--- a/drivers/staging/unisys/visorchipset/file.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/* file.h
- *
- * Copyright (C) 2010 - 2013 UNISYS CORPORATION
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
- * NON INFRINGEMENT. See the GNU General Public License for more
- * details.
- */
-
-#ifndef __FILE_H__
-#define __FILE_H__
-
-#include "globals.h"
-
-int visorchipset_file_init(dev_t majorDev,
- struct visorchannel **pControlVm_channel);
-void visorchipset_file_cleanup(dev_t major_dev);
-
-#endif
diff --git a/drivers/staging/unisys/visorchipset/globals.h b/drivers/staging/unisys/visorchipset/globals.h
deleted file mode 100644
index f76e498a3..000000000
--- a/drivers/staging/unisys/visorchipset/globals.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/* globals.h
- *
- * Copyright (C) 2010 - 2013 UNISYS CORPORATION
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
- * NON INFRINGEMENT. See the GNU General Public License for more
- * details.
- */
-
-#ifndef __VISORCHIPSET_GLOBALS_H__
-#define __VISORCHIPSET_GLOBALS_H__
-
-#include "diagnostics/appos_subsystems.h"
-#include "timskmod.h"
-#include "visorchipset.h"
-#include "visorchipset_umode.h"
-#include "version.h"
-
-#define MYDRVNAME "visorchipset"
-
-/* module parameters */
-
-extern int visorchipset_testvnic;
-extern int visorchipset_testvnicclient;
-extern int visorchipset_testmsg;
-extern int visorchipset_major;
-extern int visorchipset_serverregwait;
-extern int visorchipset_clientregwait;
-extern int visorchipset_testteardown;
-extern int visorchipset_disable_controlvm;
-extern int visorchipset_crash_kernel;
-extern int visorchipset_holdchipsetready;
-
-#endif
diff --git a/drivers/staging/unisys/visorchipset/parser.c b/drivers/staging/unisys/visorchipset/parser.c
deleted file mode 100644
index d8a2d6f5a..000000000
--- a/drivers/staging/unisys/visorchipset/parser.c
+++ /dev/null
@@ -1,430 +0,0 @@
-/* parser.c
- *
- * Copyright (C) 2010 - 2013 UNISYS CORPORATION
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
- * NON INFRINGEMENT. See the GNU General Public License for more
- * details.
- */
-
-#include "parser.h"
-#include "memregion.h"
-#include "controlvmchannel.h"
-#include <linux/ctype.h>
-#include <linux/mm.h>
-#include <linux/uuid.h>
-
-#define MYDRVNAME "visorchipset_parser"
-#define CURRENT_FILE_PC VISOR_CHIPSET_PC_parser_c
-
-/* We will refuse to allocate more than this many bytes to copy data from
- * incoming payloads. This serves as a throttling mechanism.
- */
-#define MAX_CONTROLVM_PAYLOAD_BYTES (1024*128)
-static ulong controlvm_payload_bytes_buffered;
-
-struct parser_context {
- ulong allocbytes;
- ulong param_bytes;
- u8 *curr;
- ulong bytes_remaining;
- BOOL byte_stream;
- char data[0];
-};
-
-static struct parser_context *
-parser_init_guts(u64 addr, u32 bytes, BOOL local,
- BOOL standard_payload_header, BOOL *retry)
-{
- int allocbytes = sizeof(struct parser_context) + bytes;
- struct parser_context *rc = NULL;
- struct parser_context *ctx = NULL;
- struct memregion *rgn = NULL;
- struct spar_controlvm_parameters_header *phdr = NULL;
-
- if (retry)
- *retry = FALSE;
- if (!standard_payload_header)
- /* alloc and 0 extra byte to ensure payload is
- * '\0'-terminated
- */
- allocbytes++;
- if ((controlvm_payload_bytes_buffered + bytes)
- > MAX_CONTROLVM_PAYLOAD_BYTES) {
- if (retry)
- *retry = TRUE;
- rc = NULL;
- goto cleanup;
- }
- ctx = kzalloc(allocbytes, GFP_KERNEL|__GFP_NORETRY);
- if (!ctx) {
- if (retry)
- *retry = TRUE;
- rc = NULL;
- goto cleanup;
- }
-
- ctx->allocbytes = allocbytes;
- ctx->param_bytes = bytes;
- ctx->curr = NULL;
- ctx->bytes_remaining = 0;
- ctx->byte_stream = FALSE;
- if (local) {
- void *p;
-
- if (addr > virt_to_phys(high_memory - 1)) {
- rc = NULL;
- goto cleanup;
- }
- p = __va((ulong) (addr));
- memcpy(ctx->data, p, bytes);
- } else {
- rgn = visor_memregion_create(addr, bytes);
- if (!rgn) {
- rc = NULL;
- goto cleanup;
- }
- if (visor_memregion_read(rgn, 0, ctx->data, bytes) < 0) {
- rc = NULL;
- goto cleanup;
- }
- }
- if (!standard_payload_header) {
- ctx->byte_stream = TRUE;
- rc = ctx;
- goto cleanup;
- }
- phdr = (struct spar_controlvm_parameters_header *)(ctx->data);
- if (phdr->total_length != bytes) {
- rc = NULL;
- goto cleanup;
- }
- if (phdr->total_length < phdr->header_length) {
- rc = NULL;
- goto cleanup;
- }
- if (phdr->header_length <
- sizeof(struct spar_controlvm_parameters_header)) {
- rc = NULL;
- goto cleanup;
- }
-
- rc = ctx;
-cleanup:
- if (rgn) {
- visor_memregion_destroy(rgn);
- rgn = NULL;
- }
- if (rc) {
- controlvm_payload_bytes_buffered += ctx->param_bytes;
- } else {
- if (ctx) {
- parser_done(ctx);
- ctx = NULL;
- }
- }
- return rc;
-}
-
-struct parser_context *
-parser_init(u64 addr, u32 bytes, BOOL local, BOOL *retry)
-{
- return parser_init_guts(addr, bytes, local, TRUE, retry);
-}
-
-/* Call this instead of parser_init() if the payload area consists of just
- * a sequence of bytes, rather than a struct spar_controlvm_parameters_header
- * structures. Afterwards, you can call parser_simpleString_get() or
- * parser_byteStream_get() to obtain the data.
- */
-struct parser_context *
-parser_init_byte_stream(u64 addr, u32 bytes, BOOL local, BOOL *retry)
-{
- return parser_init_guts(addr, bytes, local, FALSE, retry);
-}
-
-/* Obtain '\0'-terminated copy of string in payload area.
- */
-char *
-parser_simpleString_get(struct parser_context *ctx)
-{
- if (!ctx->byte_stream)
- return NULL;
- return ctx->data; /* note this IS '\0'-terminated, because of
- * the num of bytes we alloc+clear in
- * parser_init_byteStream() */
-}
-
-/* Obtain a copy of the buffer in the payload area.
- */
-void *parser_byte_stream_get(struct parser_context *ctx, ulong *nbytes)
-{
- if (!ctx->byte_stream)
- return NULL;
- if (nbytes)
- *nbytes = ctx->param_bytes;
- return (void *)ctx->data;
-}
-
-uuid_le
-parser_id_get(struct parser_context *ctx)
-{
- struct spar_controlvm_parameters_header *phdr = NULL;
-
- if (ctx == NULL)
- return NULL_UUID_LE;
- phdr = (struct spar_controlvm_parameters_header *)(ctx->data);
- return phdr->id;
-}
-
-void
-parser_param_start(struct parser_context *ctx, PARSER_WHICH_STRING which_string)
-{
- struct spar_controlvm_parameters_header *phdr = NULL;
-
- if (ctx == NULL)
- goto Away;
- phdr = (struct spar_controlvm_parameters_header *)(ctx->data);
- switch (which_string) {
- case PARSERSTRING_INITIATOR:
- ctx->curr = ctx->data + phdr->initiator_offset;
- ctx->bytes_remaining = phdr->initiator_length;
- break;
- case PARSERSTRING_TARGET:
- ctx->curr = ctx->data + phdr->target_offset;
- ctx->bytes_remaining = phdr->target_length;
- break;
- case PARSERSTRING_CONNECTION:
- ctx->curr = ctx->data + phdr->connection_offset;
- ctx->bytes_remaining = phdr->connection_length;
- break;
- case PARSERSTRING_NAME:
- ctx->curr = ctx->data + phdr->name_offset;
- ctx->bytes_remaining = phdr->name_length;
- break;
- default:
- break;
- }
-
-Away:
- return;
-}
-
-void
-parser_done(struct parser_context *ctx)
-{
- if (!ctx)
- return;
- controlvm_payload_bytes_buffered -= ctx->param_bytes;
- kfree(ctx);
-}
-
-/** Return length of string not counting trailing spaces. */
-static int
-string_length_no_trail(char *s, int len)
-{
- int i = len - 1;
-
- while (i >= 0) {
- if (!isspace(s[i]))
- return i + 1;
- i--;
- }
- return 0;
-}
-
-/** Grab the next name and value out of the parameter buffer.
- * The entire parameter buffer looks like this:
- * <name>=<value>\0
- * <name>=<value>\0
- * ...
- * \0
- * If successful, the next <name> value is returned within the supplied
- * <nam> buffer (the value is always upper-cased), and the corresponding
- * <value> is returned within a kmalloc()ed buffer, whose pointer is
- * provided as the return value of this function.
- * (The total number of bytes allocated is strlen(<value>)+1.)
- *
- * NULL is returned to indicate failure, which can occur for several reasons:
- * - all <name>=<value> pairs have already been processed
- * - bad parameter
- * - parameter buffer ends prematurely (couldn't find an '=' or '\0' within
- * the confines of the parameter buffer)
- * - the <nam> buffer is not large enough to hold the <name> of the next
- * parameter
- */
-void *
-parser_param_get(struct parser_context *ctx, char *nam, int namesize)
-{
- u8 *pscan, *pnam = nam;
- ulong nscan;
- int value_length = -1, orig_value_length = -1;
- void *value = NULL;
- int i;
- int closing_quote = 0;
-
- if (!ctx)
- return NULL;
- pscan = ctx->curr;
- nscan = ctx->bytes_remaining;
- if (nscan == 0)
- return NULL;
- if (*pscan == '\0')
- /* This is the normal return point after you have processed
- * all of the <name>=<value> pairs in a syntactically-valid
- * parameter buffer.
- */
- return NULL;
-
- /* skip whitespace */
- while (isspace(*pscan)) {
- pscan++;
- nscan--;
- if (nscan == 0)
- return NULL;
- }
-
- while (*pscan != ':') {
- if (namesize <= 0)
- return NULL;
- *pnam = toupper(*pscan);
- pnam++;
- namesize--;
- pscan++;
- nscan--;
- if (nscan == 0)
- return NULL;
- }
- if (namesize <= 0)
- return NULL;
- *pnam = '\0';
- nam[string_length_no_trail(nam, strlen(nam))] = '\0';
-
- /* point to char immediately after ":" in "<name>:<value>" */
- pscan++;
- nscan--;
- /* skip whitespace */
- while (isspace(*pscan)) {
- pscan++;
- nscan--;
- if (nscan == 0)
- return NULL;
- }
- if (nscan == 0)
- return NULL;
- if (*pscan == '\'' || *pscan == '"') {
- closing_quote = *pscan;
- pscan++;
- nscan--;
- if (nscan == 0)
- return NULL;
- }
-
- /* look for a separator character, terminator character, or
- * end of data
- */
- for (i = 0, value_length = -1; i < nscan; i++) {
- if (closing_quote) {
- if (pscan[i] == '\0')
- return NULL;
- if (pscan[i] == closing_quote) {
- value_length = i;
- break;
- }
- } else
- if (pscan[i] == ',' || pscan[i] == ';'
- || pscan[i] == '\0') {
- value_length = i;
- break;
- }
- }
- if (value_length < 0) {
- if (closing_quote)
- return NULL;
- value_length = nscan;
- }
- orig_value_length = value_length;
- if (closing_quote == 0)
- value_length = string_length_no_trail(pscan, orig_value_length);
- value = kmalloc(value_length + 1, GFP_KERNEL|__GFP_NORETRY);
- if (value == NULL)
- return NULL;
- memcpy(value, pscan, value_length);
- ((u8 *) (value))[value_length] = '\0';
-
- pscan += orig_value_length;
- nscan -= orig_value_length;
-
- /* skip past separator or closing quote */
- if (nscan > 0) {
- if (*pscan != '\0') {
- pscan++;
- nscan--;
- }
- }
-
- if (closing_quote && (nscan > 0)) {
- /* we still need to skip around the real separator if present */
- /* first, skip whitespace */
- while (isspace(*pscan)) {
- pscan++;
- nscan--;
- if (nscan == 0)
- break;
- }
- if (nscan > 0) {
- if (*pscan == ',' || *pscan == ';') {
- pscan++;
- nscan--;
- } else if (*pscan != '\0') {
- kfree(value);
- value = NULL;
- return NULL;
- }
- }
- }
- ctx->curr = pscan;
- ctx->bytes_remaining = nscan;
- return value;
-}
-
-void *
-parser_string_get(struct parser_context *ctx)
-{
- u8 *pscan;
- ulong nscan;
- int value_length = -1;
- void *value = NULL;
- int i;
-
- if (!ctx)
- return NULL;
- pscan = ctx->curr;
- nscan = ctx->bytes_remaining;
- if (nscan == 0)
- return NULL;
- if (!pscan)
- return NULL;
- for (i = 0, value_length = -1; i < nscan; i++)
- if (pscan[i] == '\0') {
- value_length = i;
- break;
- }
- if (value_length < 0) /* '\0' was not included in the length */
- value_length = nscan;
- value = kmalloc(value_length + 1, GFP_KERNEL|__GFP_NORETRY);
- if (value == NULL)
- return NULL;
- if (value_length > 0)
- memcpy(value, pscan, value_length);
- ((u8 *) (value))[value_length] = '\0';
- return value;
-}
diff --git a/drivers/staging/unisys/visorchipset/parser.h b/drivers/staging/unisys/visorchipset/parser.h
deleted file mode 100644
index 2b903f1be..000000000
--- a/drivers/staging/unisys/visorchipset/parser.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/* parser.h
- *
- * Copyright (C) 2010 - 2013 UNISYS CORPORATION
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
- * NON INFRINGEMENT. See the GNU General Public License for more
- * details.
- */
-
-#ifndef __PARSER_H__
-#define __PARSER_H__
-
-#include <linux/uuid.h>
-
-#include "timskmod.h"
-#include "channel.h"
-
-typedef enum {
- PARSERSTRING_INITIATOR,
- PARSERSTRING_TARGET,
- PARSERSTRING_CONNECTION,
- PARSERSTRING_NAME,
-} PARSER_WHICH_STRING;
-
-struct parser_context *parser_init(u64 addr, u32 bytes, BOOL isLocal,
- BOOL *tryAgain);
-struct parser_context *parser_init_byte_stream(u64 addr, u32 bytes, BOOL local,
- BOOL *retry);
-void parser_param_start(struct parser_context *ctx,
- PARSER_WHICH_STRING which_string);
-void *parser_param_get(struct parser_context *ctx, char *nam, int namesize);
-void *parser_string_get(struct parser_context *ctx);
-uuid_le parser_id_get(struct parser_context *ctx);
-char *parser_simpleString_get(struct parser_context *ctx);
-void *parser_byte_stream_get(struct parser_context *ctx, ulong *nbytes);
-void parser_done(struct parser_context *ctx);
-
-#endif
diff --git a/drivers/staging/unisys/visorchipset/visorchipset.h b/drivers/staging/unisys/visorchipset/visorchipset.h
deleted file mode 100644
index bd46df9ef..000000000
--- a/drivers/staging/unisys/visorchipset/visorchipset.h
+++ /dev/null
@@ -1,236 +0,0 @@
-/* visorchipset.h
- *
- * Copyright (C) 2010 - 2013 UNISYS CORPORATION
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
- * NON INFRINGEMENT. See the GNU General Public License for more
- * details.
- */
-
-#ifndef __VISORCHIPSET_H__
-#define __VISORCHIPSET_H__
-
-#include <linux/uuid.h>
-
-#include "timskmod.h"
-#include "channel.h"
-#include "controlvmchannel.h"
-#include "parser.h"
-#include "procobjecttree.h"
-#include "vbusdeviceinfo.h"
-#include "vbushelper.h"
-
-/** Describes the state from the perspective of which controlvm messages have
- * been received for a bus or device.
- */
-struct visorchipset_state {
- u32 created:1;
- u32 attached:1;
- u32 configured:1;
- u32 running:1;
- /* Add new fields above. */
- /* Remaining bits in this 32-bit word are unused. */
-};
-
-enum visorchipset_addresstype {
- /** address is guest physical, but outside of the physical memory
- * region that is controlled by the running OS (this is the normal
- * address type for Supervisor channels)
- */
- ADDRTYPE_LOCALPHYSICAL,
-
- /** address is guest physical, and withIN the confines of the
- * physical memory controlled by the running OS.
- */
- ADDRTYPE_LOCALTEST,
-};
-
-enum crash_obj_type {
- CRASH_DEV,
- CRASH_BUS,
-};
-
-/** Attributes for a particular Supervisor channel.
- */
-struct visorchipset_channel_info {
- enum visorchipset_addresstype addr_type;
- HOSTADDRESS channel_addr;
- struct irq_info intr;
- u64 n_channel_bytes;
- uuid_le channel_type_uuid;
- uuid_le channel_inst_uuid;
-
-};
-
-/** Attributes for a particular Supervisor device.
- * Any visorchipset client can query these attributes using
- * visorchipset_get_client_device_info() or
- * visorchipset_get_server_device_info().
- */
-struct visorchipset_device_info {
- struct list_head entry;
- u32 bus_no;
- u32 dev_no;
- uuid_le dev_inst_uuid;
- struct visorchipset_state state;
- struct visorchipset_channel_info chan_info;
- u32 reserved1; /* control_vm_id */
- u64 reserved2;
- u32 switch_no; /* when devState.attached==1 */
- u32 internal_port_no; /* when devState.attached==1 */
- struct controlvm_message_header pending_msg_hdr;/* CONTROLVM_MESSAGE */
- /** For private use by the bus driver */
- void *bus_driver_context;
-
-};
-
-static inline struct visorchipset_device_info *finddevice(
- struct list_head *list, u32 bus_no, u32 dev_no)
-{
- struct visorchipset_device_info *p;
-
- list_for_each_entry(p, list, entry) {
- if (p->bus_no == bus_no && p->dev_no == dev_no)
- return p;
- }
- return NULL;
-}
-
-static inline void delbusdevices(struct list_head *list, u32 bus_no)
-{
- struct visorchipset_device_info *p, *tmp;
-
- list_for_each_entry_safe(p, tmp, list, entry) {
- if (p->bus_no == bus_no) {
- list_del(&p->entry);
- kfree(p);
- }
- }
-}
-
-/** Attributes for a particular Supervisor bus.
- * (For a service partition acting as the server for buses/devices, there
- * is a 1-to-1 relationship between busses and guest partitions.)
- * Any visorchipset client can query these attributes using
- * visorchipset_get_client_bus_info() or visorchipset_get_bus_info().
- */
-struct visorchipset_bus_info {
- struct list_head entry;
- u32 bus_no;
- struct visorchipset_state state;
- struct visorchipset_channel_info chan_info;
- uuid_le partition_uuid;
- u64 partition_handle;
- u8 *name; /* UTF8 */
- u8 *description; /* UTF8 */
- u64 reserved1;
- u32 reserved2;
- struct {
- u32 server:1;
- /* Add new fields above. */
- /* Remaining bits in this 32-bit word are unused. */
- } flags;
- struct controlvm_message_header pending_msg_hdr;/* CONTROLVM MsgHdr */
- /** For private use by the bus driver */
- void *bus_driver_context;
- u64 dev_no;
-
-};
-
-static inline struct visorchipset_bus_info *
-findbus(struct list_head *list, u32 bus_no)
-{
- struct visorchipset_bus_info *p;
-
- list_for_each_entry(p, list, entry) {
- if (p->bus_no == bus_no)
- return p;
- }
- return NULL;
-}
-
-/* These functions will be called from within visorchipset when certain
- * events happen. (The implementation of these functions is outside of
- * visorchipset.)
- */
-struct visorchipset_busdev_notifiers {
- void (*bus_create)(ulong bus_no);
- void (*bus_destroy)(ulong bus_no);
- void (*device_create)(ulong bus_no, ulong dev_no);
- void (*device_destroy)(ulong bus_no, ulong dev_no);
- void (*device_pause)(ulong bus_no, ulong dev_no);
- void (*device_resume)(ulong bus_no, ulong dev_no);
- int (*get_channel_info)(uuid_le type_uuid, ulong *min_size,
- ulong *max_size);
-};
-
-/* These functions live inside visorchipset, and will be called to indicate
- * responses to specific events (by code outside of visorchipset).
- * For now, the value for each response is simply either:
- * 0 = it worked
- * -1 = it failed
- */
-struct visorchipset_busdev_responders {
- void (*bus_create)(ulong bus_no, int response);
- void (*bus_destroy)(ulong bus_no, int response);
- void (*device_create)(ulong bus_no, ulong dev_no, int response);
- void (*device_destroy)(ulong bus_no, ulong dev_no, int response);
- void (*device_pause)(ulong bus_no, ulong dev_no, int response);
- void (*device_resume)(ulong bus_no, ulong dev_no, int response);
-};
-
-/** Register functions (in the bus driver) to get called by visorchipset
- * whenever a bus or device appears for which this service partition is
- * to be the server for. visorchipset will fill in <responders>, to
- * indicate functions the bus driver should call to indicate message
- * responses.
- */
-void
-visorchipset_register_busdev_client(
- struct visorchipset_busdev_notifiers *notifiers,
- struct visorchipset_busdev_responders *responders,
- struct ultra_vbus_deviceinfo *driver_info);
-
-/** Register functions (in the bus driver) to get called by visorchipset
- * whenever a bus or device appears for which this service partition is
- * to be the client for. visorchipset will fill in <responders>, to
- * indicate functions the bus driver should call to indicate message
- * responses.
- */
-void
-visorchipset_register_busdev_server(
- struct visorchipset_busdev_notifiers *notifiers,
- struct visorchipset_busdev_responders *responders,
- struct ultra_vbus_deviceinfo *driver_info);
-
-typedef void (*SPARREPORTEVENT_COMPLETE_FUNC) (struct controlvm_message *msg,
- int status);
-
-void visorchipset_device_pause_response(ulong bus_no, ulong dev_no,
- int response);
-
-BOOL visorchipset_get_bus_info(ulong bus_no,
- struct visorchipset_bus_info *bus_info);
-BOOL visorchipset_get_device_info(ulong bus_no, ulong dev_no,
- struct visorchipset_device_info *dev_info);
-BOOL visorchipset_set_bus_context(ulong bus_no, void *context);
-BOOL visorchipset_set_device_context(ulong bus_no, ulong dev_no, void *context);
-int visorchipset_chipset_ready(void);
-int visorchipset_chipset_selftest(void);
-int visorchipset_chipset_notready(void);
-void visorchipset_save_message(struct controlvm_message *msg,
- enum crash_obj_type type);
-void *visorchipset_cache_alloc(struct kmem_cache *pool,
- BOOL ok_to_block, char *fn, int ln);
-void visorchipset_cache_free(struct kmem_cache *pool, void *p,
- char *fn, int ln);
-
-#endif
diff --git a/drivers/staging/unisys/visorchipset/visorchipset_umode.h b/drivers/staging/unisys/visorchipset/visorchipset_umode.h
deleted file mode 100644
index 6cf6eccb3..000000000
--- a/drivers/staging/unisys/visorchipset/visorchipset_umode.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/* visorchipset_umode.h
- *
- * Copyright (C) 2010 - 2013 UNISYS CORPORATION
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
- * NON INFRINGEMENT. See the GNU General Public License for more
- * details.
- */
-
-/** @file *********************************************************************
- *
- * This describes structures needed for the interface between the
- * visorchipset driver and a user-mode component that opens the device.
- *
- ******************************************************************************
- */
-
-#ifndef __VISORCHIPSET_UMODE_H
-#define __VISORCHIPSET_UMODE_H
-
-/** The user-mode program can access the control channel buffer directly
- * via this memory map.
- */
-#define VISORCHIPSET_MMAP_CONTROLCHANOFFSET (0x00000000)
-#define VISORCHIPSET_MMAP_CONTROLCHANSIZE (0x00400000) /* 4MB */
-
-#endif /* __VISORCHIPSET_UMODE_H */
diff --git a/drivers/staging/unisys/visornic/Kconfig b/drivers/staging/unisys/visornic/Kconfig
new file mode 100644
index 000000000..1676dc707
--- /dev/null
+++ b/drivers/staging/unisys/visornic/Kconfig
@@ -0,0 +1,15 @@
+#
+# Unisys visornic configuration
+#
+
+config UNISYS_VISORNIC
+ tristate "Unisys visornic driver"
+ depends on UNISYSSPAR && UNISYS_VISORBUS && NET
+ ---help---
+ The Unisys Visornic driver provides support for s-Par network
+ devices exposed on the s-Par visorbus. When a message is sent
+ to visorbus to create a network device, the probe function of
+ visornic is called to create the netdev device. Networking on
+ s-Par switches will not work if this driver is not selected.
+ If you say Y here, you will enable the Unisys visornic driver.
+
diff --git a/drivers/staging/unisys/visornic/Makefile b/drivers/staging/unisys/visornic/Makefile
new file mode 100644
index 000000000..439e95e03
--- /dev/null
+++ b/drivers/staging/unisys/visornic/Makefile
@@ -0,0 +1,10 @@
+#
+# Makefile for Unisys channel
+#
+
+obj-$(CONFIG_UNISYS_VISORNIC) += visornic.o
+
+visornic-y := visornic_main.o
+
+ccflags-y += -Idrivers/staging/unisys/include
+
diff --git a/drivers/staging/unisys/visornic/visornic_main.c b/drivers/staging/unisys/visornic/visornic_main.c
new file mode 100644
index 000000000..710074437
--- /dev/null
+++ b/drivers/staging/unisys/visornic/visornic_main.c
@@ -0,0 +1,2140 @@
+/* Copyright (c) 2012 - 2015 UNISYS CORPORATION
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ */
+
+/* This driver lives in a spar partition, and registers to ethernet io
+ * channels from the visorbus driver. It creates netdev devices and
+ * forwards transmit to the IO channel and accepts rcvs from the IO
+ * Partition via the IO channel.
+ */
+
+#include <linux/debugfs.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/kthread.h>
+
+#include "visorbus.h"
+#include "iochannel.h"
+
+#define VISORNIC_INFINITE_RESPONSE_WAIT 0
+#define VISORNICSOPENMAX 32
+#define MAXDEVICES 16384
+
+/* MAX_BUF = 64 lines x 32 MAXVNIC x 80 characters
+ * = 163840 bytes
+ */
+#define MAX_BUF 163840
+
+static spinlock_t dev_num_pool_lock;
+static void *dev_num_pool; /**< pool to grab device numbers from */
+
+static int visornic_probe(struct visor_device *dev);
+static void visornic_remove(struct visor_device *dev);
+static int visornic_pause(struct visor_device *dev,
+ visorbus_state_complete_func complete_func);
+static int visornic_resume(struct visor_device *dev,
+ visorbus_state_complete_func complete_func);
+
+/* DEBUGFS declarations */
+static ssize_t info_debugfs_read(struct file *file, char __user *buf,
+ size_t len, loff_t *offset);
+static ssize_t enable_ints_write(struct file *file, const char __user *buf,
+ size_t len, loff_t *ppos);
+static struct dentry *visornic_debugfs_dir;
+static const struct file_operations debugfs_info_fops = {
+ .read = info_debugfs_read,
+};
+
+static const struct file_operations debugfs_enable_ints_fops = {
+ .write = enable_ints_write,
+};
+
+static struct workqueue_struct *visornic_serverdown_workqueue;
+static struct workqueue_struct *visornic_timeout_reset_workqueue;
+
+/* GUIDS for director channel type supported by this driver. */
+static struct visor_channeltype_descriptor visornic_channel_types[] = {
+ /* Note that the only channel type we expect to be reported by the
+ * bus driver is the SPAR_VNIC channel.
+ */
+ { SPAR_VNIC_CHANNEL_PROTOCOL_UUID, "ultravnic" },
+ { NULL_UUID_LE, NULL }
+};
+
+/* This is used to tell the visor bus driver which types of visor devices
+ * we support, and what functions to call when a visor device that we support
+ * is attached or removed.
+ */
+static struct visor_driver visornic_driver = {
+ .name = "visornic",
+ .version = "1.0.0.0",
+ .vertag = NULL,
+ .owner = THIS_MODULE,
+ .channel_types = visornic_channel_types,
+ .probe = visornic_probe,
+ .remove = visornic_remove,
+ .pause = visornic_pause,
+ .resume = visornic_resume,
+ .channel_interrupt = NULL,
+};
+
+struct visor_thread_info {
+ struct task_struct *task;
+ struct completion has_stopped;
+ int id;
+};
+
+struct chanstat {
+ unsigned long got_rcv;
+ unsigned long got_enbdisack;
+ unsigned long got_xmit_done;
+ unsigned long xmit_fail;
+ unsigned long sent_enbdis;
+ unsigned long sent_promisc;
+ unsigned long sent_post;
+ unsigned long sent_xmit;
+ unsigned long reject_count;
+ unsigned long extra_rcvbufs_sent;
+};
+
+struct visornic_devdata {
+ int devnum;
+ int thread_wait_ms;
+ unsigned short enabled; /* 0 disabled 1 enabled to receive */
+ unsigned short enab_dis_acked; /* NET_RCV_ENABLE/DISABLE acked by
+ * IOPART
+ */
+ struct visor_device *dev;
+ char name[99];
+ struct list_head list_all; /* < link within list_all_devices list */
+ struct kref kref;
+ struct net_device *netdev;
+ struct net_device_stats net_stats;
+ atomic_t interrupt_rcvd;
+ wait_queue_head_t rsp_queue;
+ struct sk_buff **rcvbuf;
+ u64 uniquenum; /* TODO figure out why not used */
+ unsigned short old_flags; /* flags as they were prior to
+ * set_multicast_list
+ */
+ atomic_t usage; /* count of users */
+ int num_rcv_bufs; /* indicates how many rcv buffers
+ * the vnic will post
+ */
+ int num_rcv_bufs_could_not_alloc;
+ atomic_t num_rcvbuf_in_iovm;
+ unsigned long alloc_failed_in_if_needed_cnt;
+ unsigned long alloc_failed_in_repost_rtn_cnt;
+ int max_outstanding_net_xmits; /* absolute max number of outstanding
+ * xmits - should never hit this
+ */
+ int upper_threshold_net_xmits; /* high water mark for calling
+ * netif_stop_queue()
+ */
+ int lower_threshold_net_xmits; /* high water mark for calling
+ * netif_wake_queue()
+ */
+ struct sk_buff_head xmitbufhead; /* xmitbufhead is the head of the
+ * xmit buffer list that have been
+ * sent to the IOPART end
+ */
+ struct work_struct serverdown_completion;
+ struct work_struct timeout_reset;
+ struct uiscmdrsp *cmdrsp_rcv; /* cmdrsp_rcv is used for
+ * posting/unposting rcv buffers
+ */
+ struct uiscmdrsp *xmit_cmdrsp; /* used to issue NET_XMIT - there is
+ * never more that one xmit in
+ * progress at a time
+ */
+ bool server_down; /* IOPART is down */
+ bool server_change_state; /* Processing SERVER_CHANGESTATE msg */
+ struct dentry *eth_debugfs_dir;
+ struct visor_thread_info threadinfo;
+ u64 interrupts_rcvd;
+ u64 interrupts_notme;
+ u64 interrupts_disabled;
+ u64 busy_cnt;
+ spinlock_t priv_lock; /* spinlock to access devdata structures */
+
+ /* flow control counter */
+ u64 flow_control_upper_hits;
+ u64 flow_control_lower_hits;
+
+ /* debug counters */
+ unsigned long n_rcv0; /* # rcvs of 0 buffers */
+ unsigned long n_rcv1; /* # rcvs of 1 buffers */
+ unsigned long n_rcv2; /* # rcvs of 2 buffers */
+ unsigned long n_rcvx; /* # rcvs of >2 buffers */
+ unsigned long found_repost_rcvbuf_cnt; /* # times we called
+ * repost_rcvbuf_cnt
+ */
+ unsigned long repost_found_skb_cnt; /* # times found the skb */
+ unsigned long n_repost_deficit; /* # times we couldn't find
+ * all of the rcv buffers
+ */
+ unsigned long bad_rcv_buf; /* # times we negleted to
+ * free the rcv skb because
+ * we didn't know where it
+ * came from
+ */
+ unsigned long n_rcv_packets_not_accepted;/* # bogs rcv packets */
+
+ int queuefullmsg_logged;
+ struct chanstat chstat;
+};
+
+/* array of open devices maintained by open() and close() */
+static struct net_device *num_visornic_open[VISORNICSOPENMAX];
+
+/* List of all visornic_devdata structs,
+ * linked via the list_all member
+ */
+static LIST_HEAD(list_all_devices);
+static DEFINE_SPINLOCK(lock_all_devices);
+
+/**
+ * visor_copy_fragsinfo_from_skb(
+ * @skb_in: skbuff that we are pulling the frags from
+ * @firstfraglen: length of first fragment in skb
+ * @frags_max: max len of frags array
+ * @frags: frags array filled in on output
+ *
+ * Copy the fragment list in the SKB to a phys_info
+ * array that the IOPART understands.
+ * Return value indicates number of entries filled in frags
+ * Negative values indicate an error.
+ */
+static unsigned int
+visor_copy_fragsinfo_from_skb(struct sk_buff *skb, unsigned int firstfraglen,
+ unsigned int frags_max,
+ struct phys_info frags[])
+{
+ unsigned int count = 0, ii, size, offset = 0, numfrags;
+
+ numfrags = skb_shinfo(skb)->nr_frags;
+
+ while (firstfraglen) {
+ if (count == frags_max)
+ return -EINVAL;
+
+ frags[count].pi_pfn =
+ page_to_pfn(virt_to_page(skb->data + offset));
+ frags[count].pi_off =
+ (unsigned long)(skb->data + offset) & PI_PAGE_MASK;
+ size = min_t(unsigned int, firstfraglen,
+ PI_PAGE_SIZE - frags[count].pi_off);
+
+ /* can take smallest of firstfraglen (what's left) OR
+ * bytes left in the page
+ */
+ frags[count].pi_len = size;
+ firstfraglen -= size;
+ offset += size;
+ count++;
+ }
+ if (numfrags) {
+ if ((count + numfrags) > frags_max)
+ return -EINVAL;
+
+ for (ii = 0; ii < numfrags; ii++) {
+ count = add_physinfo_entries(page_to_pfn(
+ skb_frag_page(&skb_shinfo(skb)->frags[ii])),
+ skb_shinfo(skb)->frags[ii].
+ page_offset,
+ skb_shinfo(skb)->frags[ii].
+ size, count, frags_max, frags);
+ if (!count)
+ return -EIO;
+ }
+ }
+ if (skb_shinfo(skb)->frag_list) {
+ struct sk_buff *skbinlist;
+ int c;
+
+ for (skbinlist = skb_shinfo(skb)->frag_list; skbinlist;
+ skbinlist = skbinlist->next) {
+ c = visor_copy_fragsinfo_from_skb(skbinlist,
+ skbinlist->len -
+ skbinlist->data_len,
+ frags_max - count,
+ &frags[count]);
+ if (c < 0)
+ return c;
+ count += c;
+ }
+ }
+ return count;
+}
+
+/**
+ * visort_thread_start - starts thread for the device
+ * @thrinfo: The thread to start
+ * @threadfn: Function the thread starts
+ * @thrcontext: Context to pass to the thread, i.e. devdata
+ * @name: string describing name of thread
+ *
+ * Starts a thread for the device, currently only thread is
+ * process_incoming_rsps
+ * Returns 0 on success;
+ */
+static int visor_thread_start(struct visor_thread_info *thrinfo,
+ int (*threadfn)(void *),
+ void *thrcontext, char *name)
+{
+ /* used to stop the thread */
+ init_completion(&thrinfo->has_stopped);
+ thrinfo->task = kthread_run(threadfn, thrcontext, name);
+ if (IS_ERR(thrinfo->task)) {
+ thrinfo->id = 0;
+ return -EINVAL;
+ }
+ thrinfo->id = thrinfo->task->pid;
+ return 0;
+}
+
+/**
+ * visor_thread_stop - stop a thread for the device
+ * @thrinfo: The thread to stop
+ *
+ * Stop the thread and wait for completion for a minute
+ * Returns void.
+ */
+static void visor_thread_stop(struct visor_thread_info *thrinfo)
+{
+ if (!thrinfo->id)
+ return; /* thread not running */
+
+ kthread_stop(thrinfo->task);
+ /* give up if the thread has NOT died in 1 minute */
+ if (wait_for_completion_timeout(&thrinfo->has_stopped, 60 * HZ))
+ thrinfo->id = 0;
+}
+
+/* DebugFS code */
+static ssize_t info_debugfs_read(struct file *file, char __user *buf,
+ size_t len, loff_t *offset)
+{
+ int i;
+ ssize_t bytes_read = 0;
+ int str_pos = 0;
+ struct visornic_devdata *devdata;
+ char *vbuf;
+
+ if (len > MAX_BUF)
+ len = MAX_BUF;
+ vbuf = kzalloc(len, GFP_KERNEL);
+ if (!vbuf)
+ return -ENOMEM;
+
+ /* for each vnic channel
+ * dump out channel specific data
+ */
+ for (i = 0; i < VISORNICSOPENMAX; i++) {
+ if (!num_visornic_open[i])
+ continue;
+
+ devdata = netdev_priv(num_visornic_open[i]);
+ str_pos += scnprintf(vbuf + str_pos, len - str_pos,
+ "Vnic i = %d\n", i);
+ str_pos += scnprintf(vbuf + str_pos, len - str_pos,
+ "netdev = %s (0x%p), MAC Addr %pM\n",
+ num_visornic_open[i]->name,
+ num_visornic_open[i],
+ num_visornic_open[i]->dev_addr);
+ str_pos += scnprintf(vbuf + str_pos, len - str_pos,
+ "VisorNic Dev Info = 0x%p\n", devdata);
+ str_pos += scnprintf(vbuf + str_pos, len - str_pos,
+ " num_rcv_bufs = %d\n",
+ devdata->num_rcv_bufs);
+ str_pos += scnprintf(vbuf + str_pos, len - str_pos,
+ " max_oustanding_next_xmits = %d\n",
+ devdata->max_outstanding_net_xmits);
+ str_pos += scnprintf(vbuf + str_pos, len - str_pos,
+ " upper_threshold_net_xmits = %d\n",
+ devdata->upper_threshold_net_xmits);
+ str_pos += scnprintf(vbuf + str_pos, len - str_pos,
+ " lower_threshold_net_xmits = %d\n",
+ devdata->lower_threshold_net_xmits);
+ str_pos += scnprintf(vbuf + str_pos, len - str_pos,
+ " queuefullmsg_logged = %d\n",
+ devdata->queuefullmsg_logged);
+ str_pos += scnprintf(vbuf + str_pos, len - str_pos,
+ " chstat.got_rcv = %lu\n",
+ devdata->chstat.got_rcv);
+ str_pos += scnprintf(vbuf + str_pos, len - str_pos,
+ " chstat.got_enbdisack = %lu\n",
+ devdata->chstat.got_enbdisack);
+ str_pos += scnprintf(vbuf + str_pos, len - str_pos,
+ " chstat.got_xmit_done = %lu\n",
+ devdata->chstat.got_xmit_done);
+ str_pos += scnprintf(vbuf + str_pos, len - str_pos,
+ " chstat.xmit_fail = %lu\n",
+ devdata->chstat.xmit_fail);
+ str_pos += scnprintf(vbuf + str_pos, len - str_pos,
+ " chstat.sent_enbdis = %lu\n",
+ devdata->chstat.sent_enbdis);
+ str_pos += scnprintf(vbuf + str_pos, len - str_pos,
+ " chstat.sent_promisc = %lu\n",
+ devdata->chstat.sent_promisc);
+ str_pos += scnprintf(vbuf + str_pos, len - str_pos,
+ " chstat.sent_post = %lu\n",
+ devdata->chstat.sent_post);
+ str_pos += scnprintf(vbuf + str_pos, len - str_pos,
+ " chstat.sent_xmit = %lu\n",
+ devdata->chstat.sent_xmit);
+ str_pos += scnprintf(vbuf + str_pos, len - str_pos,
+ " chstat.reject_count = %lu\n",
+ devdata->chstat.reject_count);
+ str_pos += scnprintf(vbuf + str_pos, len - str_pos,
+ " chstat.extra_rcvbufs_sent = %lu\n",
+ devdata->chstat.extra_rcvbufs_sent);
+ str_pos += scnprintf(vbuf + str_pos, len - str_pos,
+ " n_rcv0 = %lu\n", devdata->n_rcv0);
+ str_pos += scnprintf(vbuf + str_pos, len - str_pos,
+ " n_rcv1 = %lu\n", devdata->n_rcv1);
+ str_pos += scnprintf(vbuf + str_pos, len - str_pos,
+ " n_rcv2 = %lu\n", devdata->n_rcv2);
+ str_pos += scnprintf(vbuf + str_pos, len - str_pos,
+ " n_rcvx = %lu\n", devdata->n_rcvx);
+ str_pos += scnprintf(vbuf + str_pos, len - str_pos,
+ " num_rcvbuf_in_iovm = %d\n",
+ atomic_read(&devdata->num_rcvbuf_in_iovm));
+ str_pos += scnprintf(vbuf + str_pos, len - str_pos,
+ " alloc_failed_in_if_needed_cnt = %lu\n",
+ devdata->alloc_failed_in_if_needed_cnt);
+ str_pos += scnprintf(vbuf + str_pos, len - str_pos,
+ " alloc_failed_in_repost_rtn_cnt = %lu\n",
+ devdata->alloc_failed_in_repost_rtn_cnt);
+ /* str_pos += scnprintf(vbuf + str_pos, len - str_pos,
+ * " inner_loop_limit_reached_cnt = %lu\n",
+ * devdata->inner_loop_limit_reached_cnt);
+ */
+ str_pos += scnprintf(vbuf + str_pos, len - str_pos,
+ " found_repost_rcvbuf_cnt = %lu\n",
+ devdata->found_repost_rcvbuf_cnt);
+ str_pos += scnprintf(vbuf + str_pos, len - str_pos,
+ " repost_found_skb_cnt = %lu\n",
+ devdata->repost_found_skb_cnt);
+ str_pos += scnprintf(vbuf + str_pos, len - str_pos,
+ " n_repost_deficit = %lu\n",
+ devdata->n_repost_deficit);
+ str_pos += scnprintf(vbuf + str_pos, len - str_pos,
+ " bad_rcv_buf = %lu\n",
+ devdata->bad_rcv_buf);
+ str_pos += scnprintf(vbuf + str_pos, len - str_pos,
+ " n_rcv_packets_not_accepted = %lu\n",
+ devdata->n_rcv_packets_not_accepted);
+ str_pos += scnprintf(vbuf + str_pos, len - str_pos,
+ " interrupts_rcvd = %llu\n",
+ devdata->interrupts_rcvd);
+ str_pos += scnprintf(vbuf + str_pos, len - str_pos,
+ " interrupts_notme = %llu\n",
+ devdata->interrupts_notme);
+ str_pos += scnprintf(vbuf + str_pos, len - str_pos,
+ " interrupts_disabled = %llu\n",
+ devdata->interrupts_disabled);
+ str_pos += scnprintf(vbuf + str_pos, len - str_pos,
+ " busy_cnt = %llu\n",
+ devdata->busy_cnt);
+ str_pos += scnprintf(vbuf + str_pos, len - str_pos,
+ " flow_control_upper_hits = %llu\n",
+ devdata->flow_control_upper_hits);
+ str_pos += scnprintf(vbuf + str_pos, len - str_pos,
+ " flow_control_lower_hits = %llu\n",
+ devdata->flow_control_lower_hits);
+ str_pos += scnprintf(vbuf + str_pos, len - str_pos,
+ " thread_wait_ms = %d\n",
+ devdata->thread_wait_ms);
+ str_pos += scnprintf(vbuf + str_pos, len - str_pos,
+ " netif_queue = %s\n",
+ netif_queue_stopped(devdata->netdev) ?
+ "stopped" : "running");
+ }
+ bytes_read = simple_read_from_buffer(buf, len, offset, vbuf, str_pos);
+ kfree(vbuf);
+ return bytes_read;
+}
+
+static ssize_t enable_ints_write(struct file *file,
+ const char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ char buf[4];
+ int i, new_value;
+ struct visornic_devdata *devdata;
+
+ if (count >= ARRAY_SIZE(buf))
+ return -EINVAL;
+
+ buf[count] = '\0';
+ if (copy_from_user(buf, buffer, count))
+ return -EFAULT;
+
+ i = kstrtoint(buf, 10, &new_value);
+ if (i != 0)
+ return -EFAULT;
+
+ /* set all counts to new_value usually 0 */
+ for (i = 0; i < VISORNICSOPENMAX; i++) {
+ if (num_visornic_open[i]) {
+ devdata = netdev_priv(num_visornic_open[i]);
+ /* TODO update features bit in channel */
+ }
+ }
+
+ return count;
+}
+
+/**
+ * visornic_serverdown_complete - IOPART went down, need to pause
+ * device
+ * @work: Work queue it was scheduled on
+ *
+ * The IO partition has gone down and we need to do some cleanup
+ * for when it comes back. Treat the IO partition as the link
+ * being down.
+ * Returns void.
+ */
+static void
+visornic_serverdown_complete(struct work_struct *work)
+{
+ struct visornic_devdata *devdata;
+ struct net_device *netdev;
+ unsigned long flags;
+ int i = 0, count = 0;
+
+ devdata = container_of(work, struct visornic_devdata,
+ serverdown_completion);
+ netdev = devdata->netdev;
+
+ /* Stop using datachan */
+ visor_thread_stop(&devdata->threadinfo);
+
+ /* Inform Linux that the link is down */
+ netif_carrier_off(netdev);
+ netif_stop_queue(netdev);
+
+ /* Free the skb for XMITs that haven't been serviced by the server
+ * We shouldn't have to inform Linux about these IOs because they
+ * are "lost in the ethernet"
+ */
+ skb_queue_purge(&devdata->xmitbufhead);
+
+ spin_lock_irqsave(&devdata->priv_lock, flags);
+ /* free rcv buffers */
+ for (i = 0; i < devdata->num_rcv_bufs; i++) {
+ if (devdata->rcvbuf[i]) {
+ kfree_skb(devdata->rcvbuf[i]);
+ devdata->rcvbuf[i] = NULL;
+ count++;
+ }
+ }
+ atomic_set(&devdata->num_rcvbuf_in_iovm, 0);
+ spin_unlock_irqrestore(&devdata->priv_lock, flags);
+
+ devdata->server_down = true;
+ devdata->server_change_state = false;
+}
+
+/**
+ * visornic_serverdown - Command has notified us that IOPARt is down
+ * @devdata: device that is being managed by IOPART
+ *
+ * Schedule the work needed to handle the server down request. Make
+ * sure we haven't already handled the server change state event.
+ * Returns 0 if we scheduled the work, -EINVAL on error.
+ */
+static int
+visornic_serverdown(struct visornic_devdata *devdata)
+{
+ if (!devdata->server_down && !devdata->server_change_state) {
+ devdata->server_change_state = true;
+ queue_work(visornic_serverdown_workqueue,
+ &devdata->serverdown_completion);
+ } else if (devdata->server_change_state) {
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/**
+ * alloc_rcv_buf - alloc rcv buffer to be given to the IO Partition.
+ * @netdev: network adapter the rcv bufs are attached too.
+ *
+ * Create an sk_buff (rcv_buf) that will be passed to the IO Partition
+ * so that it can write rcv data into our memory space.
+ * Return pointer to sk_buff
+ */
+static struct sk_buff *
+alloc_rcv_buf(struct net_device *netdev)
+{
+ struct sk_buff *skb;
+
+ /* NOTE: the first fragment in each rcv buffer is pointed to by
+ * rcvskb->data. For now all rcv buffers will be RCVPOST_BUF_SIZE
+ * in length, so the firstfrag is large enough to hold 1514.
+ */
+ skb = alloc_skb(RCVPOST_BUF_SIZE, GFP_ATOMIC);
+ if (!skb)
+ return NULL;
+ skb->dev = netdev;
+ skb->len = RCVPOST_BUF_SIZE;
+ /* current value of mtu doesn't come into play here; large
+ * packets will just end up using multiple rcv buffers all of
+ * same size
+ */
+ skb->data_len = 0; /* dev_alloc_skb already zeroes it out
+ * for clarification.
+ */
+ return skb;
+}
+
+/**
+ * post_skb - post a skb to the IO Partition.
+ * @cmdrsp: cmdrsp packet to be send to the IO Partition
+ * @devdata: visornic_devdata to post the skb too
+ * @skb: skb to give to the IO partition
+ *
+ * Send the skb to the IO Partition.
+ * Returns void
+ */
+static inline void
+post_skb(struct uiscmdrsp *cmdrsp,
+ struct visornic_devdata *devdata, struct sk_buff *skb)
+{
+ cmdrsp->net.buf = skb;
+ cmdrsp->net.rcvpost.frag.pi_pfn = page_to_pfn(virt_to_page(skb->data));
+ cmdrsp->net.rcvpost.frag.pi_off =
+ (unsigned long)skb->data & PI_PAGE_MASK;
+ cmdrsp->net.rcvpost.frag.pi_len = skb->len;
+ cmdrsp->net.rcvpost.unique_num = devdata->uniquenum;
+
+ if ((cmdrsp->net.rcvpost.frag.pi_off + skb->len) <= PI_PAGE_SIZE) {
+ cmdrsp->net.type = NET_RCV_POST;
+ cmdrsp->cmdtype = CMD_NET_TYPE;
+ visorchannel_signalinsert(devdata->dev->visorchannel,
+ IOCHAN_TO_IOPART,
+ cmdrsp);
+ atomic_inc(&devdata->num_rcvbuf_in_iovm);
+ devdata->chstat.sent_post++;
+ }
+}
+
+/**
+ * send_enbdis - send NET_RCV_ENBDIS to IO Partition
+ * @netdev: netdevice we are enable/disable, used as context
+ * return value
+ * @state: enable = 1/disable = 0
+ * @devdata: visornic device we are enabling/disabling
+ *
+ * Send the enable/disable message to the IO Partition.
+ * Returns void
+ */
+static void
+send_enbdis(struct net_device *netdev, int state,
+ struct visornic_devdata *devdata)
+{
+ devdata->cmdrsp_rcv->net.enbdis.enable = state;
+ devdata->cmdrsp_rcv->net.enbdis.context = netdev;
+ devdata->cmdrsp_rcv->net.type = NET_RCV_ENBDIS;
+ devdata->cmdrsp_rcv->cmdtype = CMD_NET_TYPE;
+ visorchannel_signalinsert(devdata->dev->visorchannel,
+ IOCHAN_TO_IOPART,
+ devdata->cmdrsp_rcv);
+ devdata->chstat.sent_enbdis++;
+}
+
+/**
+ * visornic_disable_with_timeout - Disable network adapter
+ * @netdev: netdevice to disale
+ * @timeout: timeout to wait for disable
+ *
+ * Disable the network adapter and inform the IO Partition that we
+ * are disabled, reclaim memory from rcv bufs.
+ * Returns 0 on success, negative for failure of IO Partition
+ * responding.
+ *
+ */
+static int
+visornic_disable_with_timeout(struct net_device *netdev, const int timeout)
+{
+ struct visornic_devdata *devdata = netdev_priv(netdev);
+ int i;
+ unsigned long flags;
+ int wait = 0;
+
+ /* stop the transmit queue so nothing more can be transmitted */
+ netif_stop_queue(netdev);
+
+ /* send a msg telling the other end we are stopping incoming pkts */
+ spin_lock_irqsave(&devdata->priv_lock, flags);
+ devdata->enabled = 0;
+ devdata->enab_dis_acked = 0; /* must wait for ack */
+ spin_unlock_irqrestore(&devdata->priv_lock, flags);
+
+ /* send disable and wait for ack -- don't hold lock when sending
+ * disable because if the queue is full, insert might sleep.
+ */
+ send_enbdis(netdev, 0, devdata);
+
+ /* wait for ack to arrive before we try to free rcv buffers
+ * NOTE: the other end automatically unposts the rcv buffers when
+ * when it gets a disable.
+ */
+ spin_lock_irqsave(&devdata->priv_lock, flags);
+ while ((timeout == VISORNIC_INFINITE_RESPONSE_WAIT) ||
+ (wait < timeout)) {
+ if (devdata->enab_dis_acked)
+ break;
+ if (devdata->server_down || devdata->server_change_state) {
+ spin_unlock_irqrestore(&devdata->priv_lock, flags);
+ return -EIO;
+ }
+ set_current_state(TASK_INTERRUPTIBLE);
+ spin_unlock_irqrestore(&devdata->priv_lock, flags);
+ wait += schedule_timeout(msecs_to_jiffies(10));
+ spin_lock_irqsave(&devdata->priv_lock, flags);
+ }
+
+ /* Wait for usage to go to 1 (no other users) before freeing
+ * rcv buffers
+ */
+ if (atomic_read(&devdata->usage) > 1) {
+ while (1) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ spin_unlock_irqrestore(&devdata->priv_lock, flags);
+ schedule_timeout(msecs_to_jiffies(10));
+ spin_lock_irqsave(&devdata->priv_lock, flags);
+ if (atomic_read(&devdata->usage))
+ break;
+ }
+ }
+
+ /* we've set enabled to 0, so we can give up the lock. */
+ spin_unlock_irqrestore(&devdata->priv_lock, flags);
+
+ /* Free rcv buffers - other end has automatically unposed them on
+ * disable
+ */
+ for (i = 0; i < devdata->num_rcv_bufs; i++) {
+ if (devdata->rcvbuf[i]) {
+ kfree_skb(devdata->rcvbuf[i]);
+ devdata->rcvbuf[i] = NULL;
+ }
+ }
+
+ /* remove references from array */
+ for (i = 0; i < VISORNICSOPENMAX; i++)
+ if (num_visornic_open[i] == netdev) {
+ num_visornic_open[i] = NULL;
+ break;
+ }
+
+ return 0;
+}
+
+/**
+ * init_rcv_bufs -- initialize receive bufs and send them to the IO Part
+ * @netdev: struct netdevice
+ * @devdata: visornic_devdata
+ *
+ * Allocate rcv buffers and post them to the IO Partition.
+ * Return 0 for success, and negative for failure.
+ */
+static int
+init_rcv_bufs(struct net_device *netdev, struct visornic_devdata *devdata)
+{
+ int i, count;
+
+ /* allocate fixed number of receive buffers to post to uisnic
+ * post receive buffers after we've allocated a required amount
+ */
+ for (i = 0; i < devdata->num_rcv_bufs; i++) {
+ devdata->rcvbuf[i] = alloc_rcv_buf(netdev);
+ if (!devdata->rcvbuf[i])
+ break; /* if we failed to allocate one let us stop */
+ }
+ if (i == 0) /* couldn't even allocate one -- bail out */
+ return -ENOMEM;
+ count = i;
+
+ /* Ensure we can alloc 2/3rd of the requeested number of buffers.
+ * 2/3 is an arbitrary choice; used also in ndis init.c
+ */
+ if (count < ((2 * devdata->num_rcv_bufs) / 3)) {
+ /* free receive buffers we did alloc and then bail out */
+ for (i = 0; i < count; i++) {
+ kfree_skb(devdata->rcvbuf[i]);
+ devdata->rcvbuf[i] = NULL;
+ }
+ return -ENOMEM;
+ }
+
+ /* post receive buffers to receive incoming input - without holding
+ * lock - we've not enabled nor started the queue so there shouldn't
+ * be any rcv or xmit activity
+ */
+ for (i = 0; i < count; i++)
+ post_skb(devdata->cmdrsp_rcv, devdata, devdata->rcvbuf[i]);
+
+ return 0;
+}
+
+/**
+ * visornic_enable_with_timeout - send enable to IO Part
+ * @netdev: struct net_device
+ * @timeout: Time to wait for the ACK from the enable
+ *
+ * Sends enable to IOVM, inits, and posts receive buffers to IOVM
+ * timeout is defined in msecs (timeout of 0 specifies infinite wait)
+ * Return 0 for success, negavite for failure.
+ */
+static int
+visornic_enable_with_timeout(struct net_device *netdev, const int timeout)
+{
+ int i;
+ struct visornic_devdata *devdata = netdev_priv(netdev);
+ unsigned long flags;
+ int wait = 0;
+
+ /* NOTE: the other end automatically unposts the rcv buffers when it
+ * gets a disable.
+ */
+ i = init_rcv_bufs(netdev, devdata);
+ if (i < 0)
+ return i;
+
+ spin_lock_irqsave(&devdata->priv_lock, flags);
+ devdata->enabled = 1;
+
+ /* now we're ready, let's send an ENB to uisnic but until we get
+ * an ACK back from uisnic, we'll drop the packets
+ */
+ devdata->n_rcv_packets_not_accepted = 0;
+ spin_unlock_irqrestore(&devdata->priv_lock, flags);
+
+ /* send enable and wait for ack -- don't hold lock when sending enable
+ * because if the queue is full, insert might sleep.
+ */
+ send_enbdis(netdev, 1, devdata);
+
+ spin_lock_irqsave(&devdata->priv_lock, flags);
+ while ((timeout == VISORNIC_INFINITE_RESPONSE_WAIT) ||
+ (wait < timeout)) {
+ if (devdata->enab_dis_acked)
+ break;
+ if (devdata->server_down || devdata->server_change_state) {
+ spin_unlock_irqrestore(&devdata->priv_lock, flags);
+ return -EIO;
+ }
+ set_current_state(TASK_INTERRUPTIBLE);
+ spin_unlock_irqrestore(&devdata->priv_lock, flags);
+ wait += schedule_timeout(msecs_to_jiffies(10));
+ spin_lock_irqsave(&devdata->priv_lock, flags);
+ }
+
+ spin_unlock_irqrestore(&devdata->priv_lock, flags);
+
+ if (!devdata->enab_dis_acked)
+ return -EIO;
+
+ /* find an open slot in the array to save off VisorNic references
+ * for debug
+ */
+ for (i = 0; i < VISORNICSOPENMAX; i++) {
+ if (!num_visornic_open[i]) {
+ num_visornic_open[i] = netdev;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * visornic_timeout_reset - handle xmit timeout resets
+ * @work work item that scheduled the work
+ *
+ * Transmit Timeouts are typically handled by resetting the
+ * device for our virtual NIC we will send a Disable and Enable
+ * to the IOVM. If it doesn't respond we will trigger a serverdown.
+ */
+static void
+visornic_timeout_reset(struct work_struct *work)
+{
+ struct visornic_devdata *devdata;
+ struct net_device *netdev;
+ int response = 0;
+
+ devdata = container_of(work, struct visornic_devdata, timeout_reset);
+ netdev = devdata->netdev;
+
+ netif_stop_queue(netdev);
+ response = visornic_disable_with_timeout(netdev, 100);
+ if (response)
+ goto call_serverdown;
+
+ response = visornic_enable_with_timeout(netdev, 100);
+ if (response)
+ goto call_serverdown;
+ netif_wake_queue(netdev);
+
+ return;
+
+call_serverdown:
+ visornic_serverdown(devdata);
+}
+
+/**
+ * visornic_open - Enable the visornic device and mark the queue started
+ * @netdev: netdevice to start
+ *
+ * Enable the device and start the transmit queue.
+ * Return 0 for success
+ */
+static int
+visornic_open(struct net_device *netdev)
+{
+ visornic_enable_with_timeout(netdev, VISORNIC_INFINITE_RESPONSE_WAIT);
+
+ /* start the interface's transmit queue, allowing it to accept
+ * packets for transmission
+ */
+ netif_start_queue(netdev);
+
+ return 0;
+}
+
+/**
+ * visornic_close - Disables the visornic device and stops the queues
+ * @netdev: netdevice to start
+ *
+ * Disable the device and stop the transmit queue.
+ * Return 0 for success
+ */
+static int
+visornic_close(struct net_device *netdev)
+{
+ netif_stop_queue(netdev);
+ visornic_disable_with_timeout(netdev, VISORNIC_INFINITE_RESPONSE_WAIT);
+
+ return 0;
+}
+
+/**
+ * visornic_xmit - send a packet to the IO Partition
+ * @skb: Packet to be sent
+ * @netdev: net device the packet is being sent from
+ *
+ * Convert the skb to a cmdrsp so the IO Partition can undersand it.
+ * Send the XMIT command to the IO Partition for processing. This
+ * function is protected from concurrent calls by a spinlock xmit_lock
+ * in the net_device struct, but as soon as the function returns it
+ * can be called again.
+ * Returns NETDEV_TX_OK for success, NETDEV_TX_BUSY for error.
+ */
+static int
+visornic_xmit(struct sk_buff *skb, struct net_device *netdev)
+{
+ struct visornic_devdata *devdata;
+ int len, firstfraglen, padlen;
+ struct uiscmdrsp *cmdrsp = NULL;
+ unsigned long flags;
+
+ devdata = netdev_priv(netdev);
+ spin_lock_irqsave(&devdata->priv_lock, flags);
+
+ if (netif_queue_stopped(netdev) || devdata->server_down ||
+ devdata->server_change_state) {
+ spin_unlock_irqrestore(&devdata->priv_lock, flags);
+ devdata->busy_cnt++;
+ return NETDEV_TX_BUSY;
+ }
+
+ /* sk_buff struct is used to host network data throughout all the
+ * linux network subsystems
+ */
+ len = skb->len;
+
+ /* skb->len is the FULL length of data (including fragmentary portion)
+ * skb->data_len is the length of the fragment portion in frags
+ * skb->len - skb->data_len is size of the 1st fragment in skb->data
+ * calculate the length of the first fragment that skb->data is
+ * pointing to
+ */
+ firstfraglen = skb->len - skb->data_len;
+ if (firstfraglen < ETH_HEADER_SIZE) {
+ spin_unlock_irqrestore(&devdata->priv_lock, flags);
+ devdata->busy_cnt++;
+ return NETDEV_TX_BUSY;
+ }
+
+ if ((len < ETH_MIN_PACKET_SIZE) &&
+ ((skb_end_pointer(skb) - skb->data) >= ETH_MIN_PACKET_SIZE)) {
+ /* pad the packet out to minimum size */
+ padlen = ETH_MIN_PACKET_SIZE - len;
+ memset(&skb->data[len], 0, padlen);
+ skb->tail += padlen;
+ skb->len += padlen;
+ len += padlen;
+ firstfraglen += padlen;
+ }
+
+ cmdrsp = devdata->xmit_cmdrsp;
+ /* clear cmdrsp */
+ memset(cmdrsp, 0, SIZEOF_CMDRSP);
+ cmdrsp->net.type = NET_XMIT;
+ cmdrsp->cmdtype = CMD_NET_TYPE;
+
+ /* save the pointer to skb -- we'll need it for completion */
+ cmdrsp->net.buf = skb;
+
+ if (((devdata->chstat.sent_xmit >= devdata->chstat.got_xmit_done) &&
+ (devdata->chstat.sent_xmit - devdata->chstat.got_xmit_done >=
+ devdata->max_outstanding_net_xmits)) ||
+ ((devdata->chstat.sent_xmit < devdata->chstat.got_xmit_done) &&
+ (ULONG_MAX - devdata->chstat.got_xmit_done +
+ devdata->chstat.sent_xmit >=
+ devdata->max_outstanding_net_xmits))) {
+ /* too many NET_XMITs queued over to IOVM - need to wait
+ */
+ devdata->chstat.reject_count++;
+ if (!devdata->queuefullmsg_logged &&
+ ((devdata->chstat.reject_count & 0x3ff) == 1))
+ devdata->queuefullmsg_logged = 1;
+ netif_stop_queue(netdev);
+ spin_unlock_irqrestore(&devdata->priv_lock, flags);
+ devdata->busy_cnt++;
+ return NETDEV_TX_BUSY;
+ }
+ if (devdata->queuefullmsg_logged)
+ devdata->queuefullmsg_logged = 0;
+
+ if (skb->ip_summed == CHECKSUM_UNNECESSARY) {
+ cmdrsp->net.xmt.lincsum.valid = 1;
+ cmdrsp->net.xmt.lincsum.protocol = skb->protocol;
+ if (skb_transport_header(skb) > skb->data) {
+ cmdrsp->net.xmt.lincsum.hrawoff =
+ skb_transport_header(skb) - skb->data;
+ cmdrsp->net.xmt.lincsum.hrawoff = 1;
+ }
+ if (skb_network_header(skb) > skb->data) {
+ cmdrsp->net.xmt.lincsum.nhrawoff =
+ skb_network_header(skb) - skb->data;
+ cmdrsp->net.xmt.lincsum.nhrawoffv = 1;
+ }
+ cmdrsp->net.xmt.lincsum.csum = skb->csum;
+ } else {
+ cmdrsp->net.xmt.lincsum.valid = 0;
+ }
+
+ /* save off the length of the entire data packet */
+ cmdrsp->net.xmt.len = len;
+
+ /* copy ethernet header from first frag into ocmdrsp
+ * - everything else will be pass in frags & DMA'ed
+ */
+ memcpy(cmdrsp->net.xmt.ethhdr, skb->data, ETH_HEADER_SIZE);
+ /* copy frags info - from skb->data we need to only provide access
+ * beyond eth header
+ */
+ cmdrsp->net.xmt.num_frags =
+ visor_copy_fragsinfo_from_skb(skb, firstfraglen,
+ MAX_PHYS_INFO,
+ cmdrsp->net.xmt.frags);
+ if (cmdrsp->net.xmt.num_frags == -1) {
+ spin_unlock_irqrestore(&devdata->priv_lock, flags);
+ devdata->busy_cnt++;
+ return NETDEV_TX_BUSY;
+ }
+
+ if (!visorchannel_signalinsert(devdata->dev->visorchannel,
+ IOCHAN_TO_IOPART, cmdrsp)) {
+ netif_stop_queue(netdev);
+ spin_unlock_irqrestore(&devdata->priv_lock, flags);
+ devdata->busy_cnt++;
+ return NETDEV_TX_BUSY;
+ }
+
+ /* Track the skbs that have been sent to the IOVM for XMIT */
+ skb_queue_head(&devdata->xmitbufhead, skb);
+
+ /* set the last transmission start time
+ * linux doc says: Do not forget to update netdev->trans_start to
+ * jiffies after each new tx packet is given to the hardware.
+ */
+ netdev->trans_start = jiffies;
+
+ /* update xmt stats */
+ devdata->net_stats.tx_packets++;
+ devdata->net_stats.tx_bytes += skb->len;
+ devdata->chstat.sent_xmit++;
+
+ /* check to see if we have hit the high watermark for
+ * netif_stop_queue()
+ */
+ if (((devdata->chstat.sent_xmit >= devdata->chstat.got_xmit_done) &&
+ (devdata->chstat.sent_xmit - devdata->chstat.got_xmit_done >=
+ devdata->upper_threshold_net_xmits)) ||
+ ((devdata->chstat.sent_xmit < devdata->chstat.got_xmit_done) &&
+ (ULONG_MAX - devdata->chstat.got_xmit_done +
+ devdata->chstat.sent_xmit >=
+ devdata->upper_threshold_net_xmits))) {
+ /* too many NET_XMITs queued over to IOVM - need to wait */
+ netif_stop_queue(netdev); /* calling stop queue - call
+ * netif_wake_queue() after lower
+ * threshold
+ */
+ devdata->flow_control_upper_hits++;
+ }
+ spin_unlock_irqrestore(&devdata->priv_lock, flags);
+
+ /* skb will be freed when we get back NET_XMIT_DONE */
+ return NETDEV_TX_OK;
+}
+
+/**
+ * visornic_get_stats - returns net_stats of the visornic device
+ * @netdev: netdevice
+ *
+ * Returns the net_device_stats for the device
+ */
+static struct net_device_stats *
+visornic_get_stats(struct net_device *netdev)
+{
+ struct visornic_devdata *devdata = netdev_priv(netdev);
+
+ return &devdata->net_stats;
+}
+
+/**
+ * visornic_ioctl - ioctl function for netdevice.
+ * @netdev: netdevice
+ * @ifr: ignored
+ * @cmd: ignored
+ *
+ * Currently not supported.
+ * Returns EOPNOTSUPP
+ */
+static int
+visornic_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
+{
+ return -EOPNOTSUPP;
+}
+
+/**
+ * visornic_change_mtu - changes mtu of device.
+ * @netdev: netdevice
+ * @new_mtu: value of new mtu
+ *
+ * MTU cannot be changed by system, must be changed via
+ * CONTROLVM message. All vnics and pnics in a switch have
+ * to have the same MTU for everything to work.
+ * Currently not supported.
+ * Returns EINVAL
+ */
+static int
+visornic_change_mtu(struct net_device *netdev, int new_mtu)
+{
+ return -EINVAL;
+}
+
+/**
+ * visornic_set_multi - changes mtu of device.
+ * @netdev: netdevice
+ *
+ * Only flag we support currently is IFF_PROMISC
+ * Returns void
+ */
+static void
+visornic_set_multi(struct net_device *netdev)
+{
+ struct uiscmdrsp *cmdrsp;
+ struct visornic_devdata *devdata = netdev_priv(netdev);
+
+ /* any filtering changes */
+ if (devdata->old_flags != netdev->flags) {
+ if ((netdev->flags & IFF_PROMISC) !=
+ (devdata->old_flags & IFF_PROMISC)) {
+ cmdrsp = kmalloc(SIZEOF_CMDRSP, GFP_ATOMIC);
+ if (!cmdrsp)
+ return;
+ cmdrsp->cmdtype = CMD_NET_TYPE;
+ cmdrsp->net.type = NET_RCV_PROMISC;
+ cmdrsp->net.enbdis.context = netdev;
+ cmdrsp->net.enbdis.enable =
+ (netdev->flags & IFF_PROMISC);
+ visorchannel_signalinsert(devdata->dev->visorchannel,
+ IOCHAN_TO_IOPART,
+ cmdrsp);
+ kfree(cmdrsp);
+ }
+ devdata->old_flags = netdev->flags;
+ }
+}
+
+/**
+ * visornic_xmit_timeout - request to timeout the xmit
+ * @netdev
+ *
+ * Queue the work and return. Make sure we have not already
+ * been informed the IO Partition is gone, if it is gone
+ * we will already timeout the xmits.
+ */
+static void
+visornic_xmit_timeout(struct net_device *netdev)
+{
+ struct visornic_devdata *devdata = netdev_priv(netdev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&devdata->priv_lock, flags);
+ /* Ensure that a ServerDown message hasn't been received */
+ if (!devdata->enabled ||
+ (devdata->server_down && !devdata->server_change_state)) {
+ spin_unlock_irqrestore(&devdata->priv_lock, flags);
+ return;
+ }
+ spin_unlock_irqrestore(&devdata->priv_lock, flags);
+
+ queue_work(visornic_timeout_reset_workqueue, &devdata->timeout_reset);
+}
+
+/**
+ * repost_return - repost rcv bufs that have come back
+ * @cmdrsp: io channel command struct to post
+ * @devdata: visornic devdata for the device
+ * @skb: skb
+ * @netdev: netdevice
+ *
+ * Repost rcv buffers that have been returned to us when
+ * we are finished with them.
+ * Returns 0 for success, -1 for error.
+ */
+static inline int
+repost_return(struct uiscmdrsp *cmdrsp, struct visornic_devdata *devdata,
+ struct sk_buff *skb, struct net_device *netdev)
+{
+ struct net_pkt_rcv copy;
+ int i = 0, cc, numreposted;
+ int found_skb = 0;
+ int status = 0;
+
+ copy = cmdrsp->net.rcv;
+ switch (copy.numrcvbufs) {
+ case 0:
+ devdata->n_rcv0++;
+ break;
+ case 1:
+ devdata->n_rcv1++;
+ break;
+ case 2:
+ devdata->n_rcv2++;
+ break;
+ default:
+ devdata->n_rcvx++;
+ break;
+ }
+ for (cc = 0, numreposted = 0; cc < copy.numrcvbufs; cc++) {
+ for (i = 0; i < devdata->num_rcv_bufs; i++) {
+ if (devdata->rcvbuf[i] != copy.rcvbuf[cc])
+ continue;
+
+ if ((skb) && devdata->rcvbuf[i] == skb) {
+ devdata->found_repost_rcvbuf_cnt++;
+ found_skb = 1;
+ devdata->repost_found_skb_cnt++;
+ }
+ devdata->rcvbuf[i] = alloc_rcv_buf(netdev);
+ if (!devdata->rcvbuf[i]) {
+ devdata->num_rcv_bufs_could_not_alloc++;
+ devdata->alloc_failed_in_repost_rtn_cnt++;
+ status = -ENOMEM;
+ break;
+ }
+ post_skb(cmdrsp, devdata, devdata->rcvbuf[i]);
+ numreposted++;
+ break;
+ }
+ }
+ if (numreposted != copy.numrcvbufs) {
+ devdata->n_repost_deficit++;
+ status = -EINVAL;
+ }
+ if (skb) {
+ if (found_skb) {
+ kfree_skb(skb);
+ } else {
+ status = -EINVAL;
+ devdata->bad_rcv_buf++;
+ }
+ }
+ atomic_dec(&devdata->usage);
+ return status;
+}
+
+/**
+ * visornic_rx - Handle receive packets coming back from IO Part
+ * @cmdrsp: Receive packet returned from IO Part
+ *
+ * Got a receive packet back from the IO Part, handle it and send
+ * it up the stack.
+ * Returns void
+ */
+static void
+visornic_rx(struct uiscmdrsp *cmdrsp)
+{
+ struct visornic_devdata *devdata;
+ struct sk_buff *skb, *prev, *curr;
+ struct net_device *netdev;
+ int cc, currsize, off, status;
+ struct ethhdr *eth;
+ unsigned long flags;
+#ifdef DEBUG
+ struct phys_info testfrags[MAX_PHYS_INFO];
+#endif
+
+ /* post new rcv buf to the other end using the cmdrsp we have at hand
+ * post it without holding lock - but we'll use the signal lock to
+ * synchronize the queue insert the cmdrsp that contains the net.rcv
+ * is the one we are using to repost, so copy the info we need from it.
+ */
+ skb = cmdrsp->net.buf;
+ netdev = skb->dev;
+
+ if (!netdev) {
+ /* We must have previously downed this network device and
+ * this skb and device is no longer valid. This also means
+ * the skb reference was removed from devdata->rcvbuf so no
+ * need to search for it.
+ * All we can do is free the skb and return.
+ * Note: We crash if we try to log this here.
+ */
+ kfree_skb(skb);
+ return;
+ }
+
+ devdata = netdev_priv(netdev);
+
+ spin_lock_irqsave(&devdata->priv_lock, flags);
+ atomic_dec(&devdata->num_rcvbuf_in_iovm);
+
+ /* update rcv stats - call it with priv_lock held */
+ devdata->net_stats.rx_packets++;
+ devdata->net_stats.rx_bytes = skb->len;
+
+ atomic_inc(&devdata->usage); /* don't want a close to happen before
+ * we're done here
+ */
+
+ /* set length to how much was ACTUALLY received -
+ * NOTE: rcv_done_len includes actual length of data rcvd
+ * including ethhdr
+ */
+ skb->len = cmdrsp->net.rcv.rcv_done_len;
+
+ /* test enabled while holding lock */
+ if (!(devdata->enabled && devdata->enab_dis_acked)) {
+ /* don't process it unless we're in enable mode and until
+ * we've gotten an ACK saying the other end got our RCV enable
+ */
+ spin_unlock_irqrestore(&devdata->priv_lock, flags);
+ repost_return(cmdrsp, devdata, skb, netdev);
+ return;
+ }
+
+ spin_unlock_irqrestore(&devdata->priv_lock, flags);
+
+ /* when skb was allocated, skb->dev, skb->data, skb->len and
+ * skb->data_len were setup. AND, data has already put into the
+ * skb (both first frag and in frags pages)
+ * NOTE: firstfragslen is the amount of data in skb->data and that
+ * which is not in nr_frags or frag_list. This is now simply
+ * RCVPOST_BUF_SIZE. bump tail to show how much data is in
+ * firstfrag & set data_len to show rest see if we have to chain
+ * frag_list.
+ */
+ if (skb->len > RCVPOST_BUF_SIZE) { /* do PRECAUTIONARY check */
+ if (cmdrsp->net.rcv.numrcvbufs < 2) {
+ if (repost_return(cmdrsp, devdata, skb, netdev) < 0)
+ dev_err(&devdata->netdev->dev,
+ "repost_return failed");
+ return;
+ }
+ /* length rcvd is greater than firstfrag in this skb rcv buf */
+ skb->tail += RCVPOST_BUF_SIZE; /* amount in skb->data */
+ skb->data_len = skb->len - RCVPOST_BUF_SIZE; /* amount that
+ will be in
+ frag_list */
+ } else {
+ /* data fits in this skb - no chaining - do
+ * PRECAUTIONARY check
+ */
+ if (cmdrsp->net.rcv.numrcvbufs != 1) { /* should be 1 */
+ if (repost_return(cmdrsp, devdata, skb, netdev) < 0)
+ dev_err(&devdata->netdev->dev,
+ "repost_return failed");
+ return;
+ }
+ skb->tail += skb->len;
+ skb->data_len = 0; /* nothing rcvd in frag_list */
+ }
+ off = skb_tail_pointer(skb) - skb->data;
+
+ /* amount we bumped tail by in the head skb
+ * it is used to calculate the size of each chained skb below
+ * it is also used to index into bufline to continue the copy
+ * (for chansocktwopc)
+ * if necessary chain the rcv skbs together.
+ * NOTE: index 0 has the same as cmdrsp->net.rcv.skb; we need to
+ * chain the rest to that one.
+ * - do PRECAUTIONARY check
+ */
+ if (cmdrsp->net.rcv.rcvbuf[0] != skb) {
+ if (repost_return(cmdrsp, devdata, skb, netdev) < 0)
+ dev_err(&devdata->netdev->dev, "repost_return failed");
+ return;
+ }
+
+ if (cmdrsp->net.rcv.numrcvbufs > 1) {
+ /* chain the various rcv buffers into the skb's frag_list. */
+ /* Note: off was initialized above */
+ for (cc = 1, prev = NULL;
+ cc < cmdrsp->net.rcv.numrcvbufs; cc++) {
+ curr = (struct sk_buff *)cmdrsp->net.rcv.rcvbuf[cc];
+ curr->next = NULL;
+ if (!prev) /* start of list- set head */
+ skb_shinfo(skb)->frag_list = curr;
+ else
+ prev->next = curr;
+ prev = curr;
+
+ /* should we set skb->len and skb->data_len for each
+ * buffer being chained??? can't hurt!
+ */
+ currsize = min(skb->len - off,
+ (unsigned int)RCVPOST_BUF_SIZE);
+ curr->len = currsize;
+ curr->tail += currsize;
+ curr->data_len = 0;
+ off += currsize;
+ }
+#ifdef DEBUG
+ /* assert skb->len == off */
+ if (skb->len != off) {
+ dev_err(&devdata->netdev->dev,
+ "%s something wrong; skb->len:%d != off:%d\n",
+ netdev->name, skb->len, off);
+ }
+ /* test code */
+ cc = util_copy_fragsinfo_from_skb("rcvchaintest", skb,
+ RCVPOST_BUF_SIZE,
+ MAX_PHYS_INFO, testfrags);
+ if (cc != cmdrsp->net.rcv.numrcvbufs) {
+ dev_err(&devdata->netdev->dev,
+ "**** %s Something wrong; rcvd chain length %d different from one we calculated %d\n",
+ netdev->name, cmdrsp->net.rcv.numrcvbufs, cc);
+ }
+ for (i = 0; i < cc; i++) {
+ dev_inf(&devdata->netdev->dev,
+ "test:RCVPOST_BUF_SIZE:%d[%d] pfn:%llu off:0x%x len:%d\n",
+ RCVPOST_BUF_SIZE, i, testfrags[i].pi_pfn,
+ testfrags[i].pi_off, testfrags[i].pi_len);
+ }
+#endif
+ }
+
+ /* set up packet's protocl type using ethernet header - this
+ * sets up skb->pkt_type & it also PULLS out the eth header
+ */
+ skb->protocol = eth_type_trans(skb, netdev);
+
+ eth = eth_hdr(skb);
+
+ skb->csum = 0;
+ skb->ip_summed = CHECKSUM_NONE;
+
+ do {
+ if (netdev->flags & IFF_PROMISC)
+ break; /* accept all packets */
+ if (skb->pkt_type == PACKET_BROADCAST) {
+ if (netdev->flags & IFF_BROADCAST)
+ break; /* accept all broadcast packets */
+ } else if (skb->pkt_type == PACKET_MULTICAST) {
+ if ((netdev->flags & IFF_MULTICAST) &&
+ (netdev_mc_count(netdev))) {
+ struct netdev_hw_addr *ha;
+ int found_mc = 0;
+
+ /* only accept multicast packets that we can
+ * find in our multicast address list
+ */
+ netdev_for_each_mc_addr(ha, netdev) {
+ if (ether_addr_equal(eth->h_dest,
+ ha->addr)) {
+ found_mc = 1;
+ break;
+ }
+ }
+ if (found_mc)
+ break; /* accept packet, dest
+ matches a multicast
+ address */
+ }
+ } else if (skb->pkt_type == PACKET_HOST) {
+ break; /* accept packet, h_dest must match vnic
+ mac address */
+ } else if (skb->pkt_type == PACKET_OTHERHOST) {
+ /* something is not right */
+ dev_err(&devdata->netdev->dev,
+ "**** FAILED to deliver rcv packet to OS; name:%s Dest:%pM VNIC:%pM\n",
+ netdev->name, eth->h_dest, netdev->dev_addr);
+ }
+ /* drop packet - don't forward it up to OS */
+ devdata->n_rcv_packets_not_accepted++;
+ repost_return(cmdrsp, devdata, skb, netdev);
+ return;
+ } while (0);
+
+ status = netif_rx(skb);
+ /* netif_rx returns various values, but "in practice most drivers
+ * ignore the return value
+ */
+
+ skb = NULL;
+ /*
+ * whether the packet got dropped or handled, the skb is freed by
+ * kernel code, so we shouldn't free it. but we should repost a
+ * new rcv buffer.
+ */
+ repost_return(cmdrsp, devdata, skb, netdev);
+}
+
+/**
+ * devdata_initialize - Initialize devdata structure
+ * @devdata: visornic_devdata structure to initialize
+ * #dev: visorbus_deviced it belongs to
+ *
+ * Setup initial values for the visornic based on channel and default
+ * values.
+ * Returns a pointer to the devdata if successful, else NULL
+ */
+static struct visornic_devdata *
+devdata_initialize(struct visornic_devdata *devdata, struct visor_device *dev)
+{
+ int devnum = -1;
+
+ if (!devdata)
+ return NULL;
+ memset(devdata, '\0', sizeof(struct visornic_devdata));
+ spin_lock(&dev_num_pool_lock);
+ devnum = find_first_zero_bit(dev_num_pool, MAXDEVICES);
+ set_bit(devnum, dev_num_pool);
+ spin_unlock(&dev_num_pool_lock);
+ if (devnum == MAXDEVICES)
+ devnum = -1;
+ if (devnum < 0) {
+ kfree(devdata);
+ return NULL;
+ }
+ devdata->devnum = devnum;
+ devdata->dev = dev;
+ strncpy(devdata->name, dev_name(&dev->device), sizeof(devdata->name));
+ kref_init(&devdata->kref);
+ spin_lock(&lock_all_devices);
+ list_add_tail(&devdata->list_all, &list_all_devices);
+ spin_unlock(&lock_all_devices);
+ return devdata;
+}
+
+/**
+ * devdata_release - Frees up a devdata
+ * @mykref: kref to the devdata
+ *
+ * Frees up a devdata.
+ * Returns void
+ */
+static void devdata_release(struct kref *mykref)
+{
+ struct visornic_devdata *devdata =
+ container_of(mykref, struct visornic_devdata, kref);
+
+ spin_lock(&dev_num_pool_lock);
+ clear_bit(devdata->devnum, dev_num_pool);
+ spin_unlock(&dev_num_pool_lock);
+ spin_lock(&lock_all_devices);
+ list_del(&devdata->list_all);
+ spin_unlock(&lock_all_devices);
+ kfree(devdata);
+}
+
+static const struct net_device_ops visornic_dev_ops = {
+ .ndo_open = visornic_open,
+ .ndo_stop = visornic_close,
+ .ndo_start_xmit = visornic_xmit,
+ .ndo_get_stats = visornic_get_stats,
+ .ndo_do_ioctl = visornic_ioctl,
+ .ndo_change_mtu = visornic_change_mtu,
+ .ndo_tx_timeout = visornic_xmit_timeout,
+ .ndo_set_rx_mode = visornic_set_multi,
+};
+
+/**
+ * send_rcv_posts_if_needed
+ * @devdata: visornic device
+ *
+ * Send receive buffers to the IO Partition.
+ * Returns void
+ */
+static void
+send_rcv_posts_if_needed(struct visornic_devdata *devdata)
+{
+ int i;
+ struct net_device *netdev;
+ struct uiscmdrsp *cmdrsp = devdata->cmdrsp_rcv;
+ int cur_num_rcv_bufs_to_alloc, rcv_bufs_allocated;
+
+ /* don't do this until vnic is marked ready */
+ if (!(devdata->enabled && devdata->enab_dis_acked))
+ return;
+
+ netdev = devdata->netdev;
+ rcv_bufs_allocated = 0;
+ /* this code is trying to prevent getting stuck here forever,
+ * but still retry it if you cant allocate them all this time.
+ */
+ cur_num_rcv_bufs_to_alloc = devdata->num_rcv_bufs_could_not_alloc;
+ while (cur_num_rcv_bufs_to_alloc > 0) {
+ cur_num_rcv_bufs_to_alloc--;
+ for (i = 0; i < devdata->num_rcv_bufs; i++) {
+ if (devdata->rcvbuf[i])
+ continue;
+ devdata->rcvbuf[i] = alloc_rcv_buf(netdev);
+ if (!devdata->rcvbuf[i]) {
+ devdata->alloc_failed_in_if_needed_cnt++;
+ break;
+ }
+ rcv_bufs_allocated++;
+ post_skb(cmdrsp, devdata, devdata->rcvbuf[i]);
+ devdata->chstat.extra_rcvbufs_sent++;
+ }
+ }
+ devdata->num_rcv_bufs_could_not_alloc -= rcv_bufs_allocated;
+}
+
+/**
+ * draing_queue - drains the response queue
+ * @cmdrsp: io channel command response message
+ * @devdata: visornic device to drain
+ *
+ * Drain the respones queue of any responses from the IO partition.
+ * Process the responses as we get them.
+ * Returns when response queue is empty or when the threadd stops.
+ */
+static void
+drain_queue(struct uiscmdrsp *cmdrsp, struct visornic_devdata *devdata)
+{
+ unsigned long flags;
+ struct net_device *netdev;
+
+ /* drain queue */
+ while (1) {
+ /* TODO: CLIENT ACQUIRE -- Don't really need this at the
+ * moment */
+ if (!visorchannel_signalremove(devdata->dev->visorchannel,
+ IOCHAN_FROM_IOPART,
+ cmdrsp))
+ break; /* queue empty */
+
+ switch (cmdrsp->net.type) {
+ case NET_RCV:
+ devdata->chstat.got_rcv++;
+ /* process incoming packet */
+ visornic_rx(cmdrsp);
+ break;
+ case NET_XMIT_DONE:
+ spin_lock_irqsave(&devdata->priv_lock, flags);
+ devdata->chstat.got_xmit_done++;
+ if (cmdrsp->net.xmtdone.xmt_done_result)
+ devdata->chstat.xmit_fail++;
+ /* only call queue wake if we stopped it */
+ netdev = ((struct sk_buff *)cmdrsp->net.buf)->dev;
+ /* ASSERT netdev == vnicinfo->netdev; */
+ if ((netdev == devdata->netdev) &&
+ netif_queue_stopped(netdev)) {
+ /* check to see if we have crossed
+ * the lower watermark for
+ * netif_wake_queue()
+ */
+ if (((devdata->chstat.sent_xmit >=
+ devdata->chstat.got_xmit_done) &&
+ (devdata->chstat.sent_xmit -
+ devdata->chstat.got_xmit_done <=
+ devdata->lower_threshold_net_xmits)) ||
+ ((devdata->chstat.sent_xmit <
+ devdata->chstat.got_xmit_done) &&
+ (ULONG_MAX - devdata->chstat.got_xmit_done
+ + devdata->chstat.sent_xmit <=
+ devdata->lower_threshold_net_xmits))) {
+ /* enough NET_XMITs completed
+ * so can restart netif queue
+ */
+ netif_wake_queue(netdev);
+ devdata->flow_control_lower_hits++;
+ }
+ }
+ skb_unlink(cmdrsp->net.buf, &devdata->xmitbufhead);
+ spin_unlock_irqrestore(&devdata->priv_lock, flags);
+ kfree_skb(cmdrsp->net.buf);
+ break;
+ case NET_RCV_ENBDIS_ACK:
+ devdata->chstat.got_enbdisack++;
+ netdev = (struct net_device *)
+ cmdrsp->net.enbdis.context;
+ spin_lock_irqsave(&devdata->priv_lock, flags);
+ devdata->enab_dis_acked = 1;
+ spin_unlock_irqrestore(&devdata->priv_lock, flags);
+
+ if (devdata->server_down &&
+ devdata->server_change_state) {
+ /* Inform Linux that the link is up */
+ devdata->server_down = false;
+ devdata->server_change_state = false;
+ netif_wake_queue(netdev);
+ netif_carrier_on(netdev);
+ }
+ break;
+ case NET_CONNECT_STATUS:
+ netdev = devdata->netdev;
+ if (cmdrsp->net.enbdis.enable == 1) {
+ spin_lock_irqsave(&devdata->priv_lock, flags);
+ devdata->enabled = cmdrsp->net.enbdis.enable;
+ spin_unlock_irqrestore(&devdata->priv_lock,
+ flags);
+ netif_wake_queue(netdev);
+ netif_carrier_on(netdev);
+ } else {
+ netif_stop_queue(netdev);
+ netif_carrier_off(netdev);
+ spin_lock_irqsave(&devdata->priv_lock, flags);
+ devdata->enabled = cmdrsp->net.enbdis.enable;
+ spin_unlock_irqrestore(&devdata->priv_lock,
+ flags);
+ }
+ break;
+ default:
+ break;
+ }
+ /* cmdrsp is now available for reuse */
+
+ if (kthread_should_stop())
+ break;
+ }
+}
+
+/**
+ * process_incoming_rsps - Checks the status of the response queue.
+ * @v: void pointer to the visronic devdata
+ *
+ * Main function of the vnic_incoming thread. Peridocially check the
+ * response queue and drain it if needed.
+ * Returns when thread has stopped.
+ */
+static int
+process_incoming_rsps(void *v)
+{
+ struct visornic_devdata *devdata = v;
+ struct uiscmdrsp *cmdrsp = NULL;
+ const int SZ = SIZEOF_CMDRSP;
+
+ cmdrsp = kmalloc(SZ, GFP_ATOMIC);
+ if (!cmdrsp)
+ complete_and_exit(&devdata->threadinfo.has_stopped, 0);
+
+ while (1) {
+ wait_event_interruptible_timeout(
+ devdata->rsp_queue, (atomic_read(
+ &devdata->interrupt_rcvd) == 1),
+ msecs_to_jiffies(devdata->thread_wait_ms));
+
+ /* periodically check to see if there are any rcf bufs which
+ * need to get sent to the IOSP. This can only happen if
+ * we run out of memory when trying to allocate skbs.
+ */
+ atomic_set(&devdata->interrupt_rcvd, 0);
+ send_rcv_posts_if_needed(devdata);
+ drain_queue(cmdrsp, devdata);
+ if (kthread_should_stop())
+ break;
+ }
+
+ kfree(cmdrsp);
+ complete_and_exit(&devdata->threadinfo.has_stopped, 0);
+}
+
+/**
+ * visornic_probe - probe function for visornic devices
+ * @dev: The visor device discovered
+ *
+ * Called when visorbus discovers a visornic device on its
+ * bus. It creates a new visornic ethernet adapter.
+ * Returns 0 or negative for error.
+ */
+static int visornic_probe(struct visor_device *dev)
+{
+ struct visornic_devdata *devdata = NULL;
+ struct net_device *netdev = NULL;
+ int err;
+ int channel_offset = 0;
+ u64 features;
+
+ netdev = alloc_etherdev(sizeof(struct visornic_devdata));
+ if (!netdev)
+ return -ENOMEM;
+
+ netdev->netdev_ops = &visornic_dev_ops;
+ netdev->watchdog_timeo = (5 * HZ);
+ netdev->dev.parent = &dev->device;
+
+ /* Get MAC adddress from channel and read it into the device. */
+ netdev->addr_len = ETH_ALEN;
+ channel_offset = offsetof(struct spar_io_channel_protocol,
+ vnic.macaddr);
+ err = visorbus_read_channel(dev, channel_offset, netdev->dev_addr,
+ ETH_ALEN);
+ if (err < 0)
+ goto cleanup_netdev;
+
+ devdata = devdata_initialize(netdev_priv(netdev), dev);
+ if (!devdata) {
+ err = -ENOMEM;
+ goto cleanup_netdev;
+ }
+
+ devdata->netdev = netdev;
+ init_waitqueue_head(&devdata->rsp_queue);
+ spin_lock_init(&devdata->priv_lock);
+ devdata->enabled = 0; /* not yet */
+ atomic_set(&devdata->usage, 1);
+
+ /* Setup rcv bufs */
+ channel_offset = offsetof(struct spar_io_channel_protocol,
+ vnic.num_rcv_bufs);
+ err = visorbus_read_channel(dev, channel_offset,
+ &devdata->num_rcv_bufs, 4);
+ if (err)
+ goto cleanup_netdev;
+
+ devdata->rcvbuf = kmalloc(sizeof(struct sk_buff *) *
+ devdata->num_rcv_bufs, GFP_KERNEL);
+ if (!devdata->rcvbuf) {
+ err = -ENOMEM;
+ goto cleanup_rcvbuf;
+ }
+
+ /* set the net_xmit outstanding threshold */
+ /* always leave two slots open but you should have 3 at a minimum */
+ devdata->max_outstanding_net_xmits =
+ max(3, ((devdata->num_rcv_bufs / 3) - 2));
+ devdata->upper_threshold_net_xmits =
+ max(2, devdata->max_outstanding_net_xmits - 1);
+ devdata->lower_threshold_net_xmits =
+ max(1, devdata->max_outstanding_net_xmits / 2);
+
+ skb_queue_head_init(&devdata->xmitbufhead);
+
+ /* create a cmdrsp we can use to post and unpost rcv buffers */
+ devdata->cmdrsp_rcv = kmalloc(SIZEOF_CMDRSP, GFP_ATOMIC);
+ if (!devdata->cmdrsp_rcv) {
+ err = -ENOMEM;
+ goto cleanup_cmdrsp_rcv;
+ }
+ devdata->xmit_cmdrsp = kmalloc(SIZEOF_CMDRSP, GFP_ATOMIC);
+ if (!devdata->xmit_cmdrsp) {
+ err = -ENOMEM;
+ goto cleanup_xmit_cmdrsp;
+ }
+ INIT_WORK(&devdata->serverdown_completion,
+ visornic_serverdown_complete);
+ INIT_WORK(&devdata->timeout_reset, visornic_timeout_reset);
+ devdata->server_down = false;
+ devdata->server_change_state = false;
+
+ /*set the default mtu */
+ channel_offset = offsetof(struct spar_io_channel_protocol,
+ vnic.mtu);
+ err = visorbus_read_channel(dev, channel_offset, &netdev->mtu, 4);
+ if (err)
+ goto cleanup_xmit_cmdrsp;
+
+ /* TODO: Setup Interrupt information */
+ /* Let's start our threads to get responses */
+ channel_offset = offsetof(struct spar_io_channel_protocol,
+ channel_header.features);
+ err = visorbus_read_channel(dev, channel_offset, &features, 8);
+ if (err)
+ goto cleanup_xmit_cmdrsp;
+
+ features |= ULTRA_IO_CHANNEL_IS_POLLING;
+ err = visorbus_write_channel(dev, channel_offset, &features, 8);
+ if (err)
+ goto cleanup_xmit_cmdrsp;
+
+ devdata->thread_wait_ms = 2;
+ visor_thread_start(&devdata->threadinfo, process_incoming_rsps,
+ devdata, "vnic_incoming");
+
+ err = register_netdev(netdev);
+ if (err)
+ goto cleanup_thread_stop;
+
+ /* create debgug/sysfs directories */
+ devdata->eth_debugfs_dir = debugfs_create_dir(netdev->name,
+ visornic_debugfs_dir);
+ if (!devdata->eth_debugfs_dir) {
+ err = -ENOMEM;
+ goto cleanup_thread_stop;
+ }
+
+ return 0;
+
+cleanup_thread_stop:
+ visor_thread_stop(&devdata->threadinfo);
+
+cleanup_xmit_cmdrsp:
+ kfree(devdata->xmit_cmdrsp);
+
+cleanup_cmdrsp_rcv:
+ kfree(devdata->cmdrsp_rcv);
+
+cleanup_rcvbuf:
+ kfree(devdata->rcvbuf);
+
+cleanup_netdev:
+ free_netdev(netdev);
+ return err;
+}
+
+/**
+ * host_side_disappeared - IO part is gone.
+ * @devdata: device object
+ *
+ * IO partition servicing this device is gone, do cleanup
+ * Returns void.
+ */
+static void host_side_disappeared(struct visornic_devdata *devdata)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&devdata->priv_lock, flags);
+ sprintf(devdata->name, "<dev#%d-history>", devdata->devnum);
+ devdata->dev = NULL; /* indicate device destroyed */
+ spin_unlock_irqrestore(&devdata->priv_lock, flags);
+}
+
+/**
+ * visornic_remove - Called when visornic dev goes away
+ * @dev: visornic device that is being removed
+ *
+ * Called when DEVICE_DESTROY gets called to remove device.
+ * Returns void
+ */
+static void visornic_remove(struct visor_device *dev)
+{
+ struct visornic_devdata *devdata = dev_get_drvdata(&dev->device);
+
+ if (!devdata)
+ return;
+ dev_set_drvdata(&dev->device, NULL);
+ host_side_disappeared(devdata);
+ kref_put(&devdata->kref, devdata_release);
+}
+
+/**
+ * visornic_pause - Called when IO Part disappears
+ * @dev: visornic device that is being serviced
+ * @complete_func: call when finished.
+ *
+ * Called when the IO Partition has gone down. Need to free
+ * up resources and wait for IO partition to come back. Mark
+ * link as down and don't attempt any DMA. When we have freed
+ * memory call the complete_func so that Command knows we are
+ * done. If we don't call complete_func, IO part will never
+ * come back.
+ * Returns 0 for success.
+ */
+static int visornic_pause(struct visor_device *dev,
+ visorbus_state_complete_func complete_func)
+{
+ struct visornic_devdata *devdata = dev_get_drvdata(&dev->device);
+
+ visornic_serverdown(devdata);
+ complete_func(dev, 0);
+ return 0;
+}
+
+/**
+ * visornic_resume - Called when IO part has recovered
+ * @dev: visornic device that is being serviced
+ * @compelte_func: call when finished
+ *
+ * Called when the IO partition has recovered. Reestablish
+ * connection to the IO part and set the link up. Okay to do
+ * DMA again.
+ * Returns 0 for success.
+ */
+static int visornic_resume(struct visor_device *dev,
+ visorbus_state_complete_func complete_func)
+{
+ struct visornic_devdata *devdata;
+ struct net_device *netdev;
+ unsigned long flags;
+
+ devdata = dev_get_drvdata(&dev->device);
+ if (!devdata)
+ return -EINVAL;
+
+ netdev = devdata->netdev;
+
+ if (devdata->server_down && !devdata->server_change_state) {
+ devdata->server_change_state = true;
+ /* Must transition channel to ATTACHED state BEFORE
+ * we can start using the device again.
+ * TODO: State transitions
+ */
+ visor_thread_start(&devdata->threadinfo, process_incoming_rsps,
+ devdata, "vnic_incoming");
+ init_rcv_bufs(netdev, devdata);
+ spin_lock_irqsave(&devdata->priv_lock, flags);
+ devdata->enabled = 1;
+
+ /* Now we're ready, let's send an ENB to uisnic but until
+ * we get an ACK back from uisnic, we'll drop the packets
+ */
+ devdata->enab_dis_acked = 0;
+ spin_unlock_irqrestore(&devdata->priv_lock, flags);
+
+ /* send enable and wait for ack - don't hold lock when
+ * sending enable because if the queue if sull, insert
+ * might sleep.
+ */
+ send_enbdis(netdev, 1, devdata);
+ } else if (devdata->server_change_state) {
+ return -EIO;
+ }
+
+ complete_func(dev, 0);
+ return 0;
+}
+
+/**
+ * visornic_init - Init function
+ *
+ * Init function for the visornic driver. Do initial driver setup
+ * and wait for devices.
+ * Returns 0 for success, negative for error.
+ */
+static int visornic_init(void)
+{
+ struct dentry *ret;
+ int err = -ENOMEM;
+
+ /* create workqueue for serverdown completion */
+ visornic_serverdown_workqueue =
+ create_singlethread_workqueue("visornic_serverdown");
+ if (!visornic_serverdown_workqueue)
+ return -ENOMEM;
+
+ /* create workqueue for tx timeout reset */
+ visornic_timeout_reset_workqueue =
+ create_singlethread_workqueue("visornic_timeout_reset");
+ if (!visornic_timeout_reset_workqueue)
+ return -ENOMEM;
+
+ visornic_debugfs_dir = debugfs_create_dir("visornic", NULL);
+ if (!visornic_debugfs_dir)
+ return err;
+
+ ret = debugfs_create_file("info", S_IRUSR, visornic_debugfs_dir, NULL,
+ &debugfs_info_fops);
+ if (!ret)
+ goto cleanup_debugfs;
+ ret = debugfs_create_file("enable_ints", S_IWUSR, visornic_debugfs_dir,
+ NULL, &debugfs_enable_ints_fops);
+ if (!ret)
+ goto cleanup_debugfs;
+
+ /* create workqueue for serverdown completion */
+ visornic_serverdown_workqueue =
+ create_singlethread_workqueue("visornic_serverdown");
+ if (!visornic_serverdown_workqueue)
+ goto cleanup_debugfs;
+
+ /* create workqueue for tx timeout reset */
+ visornic_timeout_reset_workqueue =
+ create_singlethread_workqueue("visornic_timeout_reset");
+ if (!visornic_timeout_reset_workqueue)
+ goto cleanup_workqueue;
+
+ spin_lock_init(&dev_num_pool_lock);
+ dev_num_pool = kzalloc(BITS_TO_LONGS(MAXDEVICES), GFP_KERNEL);
+ if (!dev_num_pool)
+ goto cleanup_workqueue;
+
+ visorbus_register_visor_driver(&visornic_driver);
+ return 0;
+
+cleanup_workqueue:
+ flush_workqueue(visornic_serverdown_workqueue);
+ destroy_workqueue(visornic_serverdown_workqueue);
+ if (visornic_timeout_reset_workqueue) {
+ flush_workqueue(visornic_timeout_reset_workqueue);
+ destroy_workqueue(visornic_timeout_reset_workqueue);
+ }
+cleanup_debugfs:
+ debugfs_remove_recursive(visornic_debugfs_dir);
+
+ return err;
+}
+
+/**
+ * visornic_cleanup - driver exit routine
+ *
+ * Unregister driver from the bus and free up memory.
+ */
+static void visornic_cleanup(void)
+{
+ if (visornic_serverdown_workqueue) {
+ flush_workqueue(visornic_serverdown_workqueue);
+ destroy_workqueue(visornic_serverdown_workqueue);
+ }
+ if (visornic_timeout_reset_workqueue) {
+ flush_workqueue(visornic_timeout_reset_workqueue);
+ destroy_workqueue(visornic_timeout_reset_workqueue);
+ }
+ debugfs_remove_recursive(visornic_debugfs_dir);
+
+ visorbus_unregister_visor_driver(&visornic_driver);
+ kfree(dev_num_pool);
+ dev_num_pool = NULL;
+}
+
+module_init(visornic_init);
+module_exit(visornic_cleanup);
+
+MODULE_AUTHOR("Unisys");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("sPAR nic driver for sparlinux: ver 1.0.0.0");
+MODULE_VERSION("1.0.0.0");
diff --git a/drivers/staging/unisys/visorutil/Kconfig b/drivers/staging/unisys/visorutil/Kconfig
deleted file mode 100644
index be9c2cf89..000000000
--- a/drivers/staging/unisys/visorutil/Kconfig
+++ /dev/null
@@ -1,9 +0,0 @@
-#
-# Unisys timskmod configuration
-#
-
-config UNISYS_VISORUTIL
- tristate "Unisys visorutil driver"
- ---help---
- If you say Y here, you will enable the Unisys visorutil driver.
-
diff --git a/drivers/staging/unisys/visorutil/Makefile b/drivers/staging/unisys/visorutil/Makefile
deleted file mode 100644
index d9ab5a36e..000000000
--- a/drivers/staging/unisys/visorutil/Makefile
+++ /dev/null
@@ -1,9 +0,0 @@
-#
-# Makefile for Unisys timskmod
-#
-
-obj-$(CONFIG_UNISYS_VISORUTIL) += visorutil.o
-
-visorutil-y := charqueue.o periodic_work.o memregion_direct.o visorkmodutils.o
-
-ccflags-y += -Idrivers/staging/unisys/include
diff --git a/drivers/staging/unisys/visorutil/charqueue.c b/drivers/staging/unisys/visorutil/charqueue.c
deleted file mode 100644
index c91752a2d..000000000
--- a/drivers/staging/unisys/visorutil/charqueue.c
+++ /dev/null
@@ -1,127 +0,0 @@
-/* charqueue.c
- *
- * Copyright (C) 2010 - 2013 UNISYS CORPORATION
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
- * NON INFRINGEMENT. See the GNU General Public License for more
- * details.
- */
-
-/*
- * Simple character queue implementation for Linux kernel mode.
- */
-
-#include "charqueue.h"
-
-#define MYDRVNAME "charqueue"
-
-#define IS_EMPTY(charqueue) (charqueue->head == charqueue->tail)
-
-struct charqueue {
- int alloc_size;
- int nslots;
- spinlock_t lock; /* read/write lock for this structure */
- int head, tail;
- unsigned char buf[0];
-};
-
-struct charqueue *visor_charqueue_create(ulong nslots)
-{
- int alloc_size = sizeof(struct charqueue) + nslots + 1;
- struct charqueue *cq;
-
- cq = kmalloc(alloc_size, GFP_KERNEL|__GFP_NORETRY);
- if (cq == NULL)
- return NULL;
- cq->alloc_size = alloc_size;
- cq->nslots = nslots;
- cq->head = 0;
- cq->tail = 0;
- spin_lock_init(&cq->lock);
- return cq;
-}
-EXPORT_SYMBOL_GPL(visor_charqueue_create);
-
-void visor_charqueue_enqueue(struct charqueue *charqueue, unsigned char c)
-{
- int alloc_slots = charqueue->nslots+1; /* 1 slot is always empty */
-
- spin_lock(&charqueue->lock);
- charqueue->head = (charqueue->head+1) % alloc_slots;
- if (charqueue->head == charqueue->tail)
- /* overflow; overwrite the oldest entry */
- charqueue->tail = (charqueue->tail+1) % alloc_slots;
- charqueue->buf[charqueue->head] = c;
- spin_unlock(&charqueue->lock);
-}
-EXPORT_SYMBOL_GPL(visor_charqueue_enqueue);
-
-BOOL visor_charqueue_is_empty(struct charqueue *charqueue)
-{
- BOOL b;
-
- spin_lock(&charqueue->lock);
- b = IS_EMPTY(charqueue);
- spin_unlock(&charqueue->lock);
- return b;
-}
-EXPORT_SYMBOL_GPL(visor_charqueue_is_empty);
-
-static int charqueue_dequeue_1(struct charqueue *charqueue)
-{
- int alloc_slots = charqueue->nslots + 1; /* 1 slot is always empty */
-
- if (IS_EMPTY(charqueue))
- return -1;
- charqueue->tail = (charqueue->tail+1) % alloc_slots;
- return charqueue->buf[charqueue->tail];
-}
-
-int charqueue_dequeue(struct charqueue *charqueue)
-{
- int rc;
-
- spin_lock(&charqueue->lock);
- rc = charqueue_dequeue_1(charqueue);
- spin_unlock(&charqueue->lock);
- return rc;
-}
-
-int visor_charqueue_dequeue_n(struct charqueue *charqueue, unsigned char *buf,
- int n)
-{
- int rc, counter = 0, c;
-
- spin_lock(&charqueue->lock);
- for (;;) {
- if (n <= 0)
- break; /* no more buffer space */
- c = charqueue_dequeue_1(charqueue);
- if (c < 0)
- break; /* no more input */
- *buf = (unsigned char)(c);
- buf++;
- n--;
- counter++;
- }
- rc = counter;
- spin_unlock(&charqueue->lock);
- return rc;
-}
-EXPORT_SYMBOL_GPL(visor_charqueue_dequeue_n);
-
-void visor_charqueue_destroy(struct charqueue *charqueue)
-{
- if (charqueue == NULL)
- return;
- kfree(charqueue);
-}
-EXPORT_SYMBOL_GPL(visor_charqueue_destroy);
diff --git a/drivers/staging/unisys/visorutil/charqueue.h b/drivers/staging/unisys/visorutil/charqueue.h
deleted file mode 100644
index f46a776b9..000000000
--- a/drivers/staging/unisys/visorutil/charqueue.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/* charqueue.h
- *
- * Copyright (C) 2010 - 2013 UNISYS CORPORATION
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
- * NON INFRINGEMENT. See the GNU General Public License for more
- * details.
- */
-
-#ifndef __CHARQUEUE_H__
-#define __CHARQUEUE_H__
-
-#include "timskmod.h"
-
-/* struct charqueue is an opaque structure to users.
- * Fields are declared only in the implementation .c files.
- */
-struct charqueue;
-
-struct charqueue *visor_charqueue_create(ulong nslots);
-void visor_charqueue_enqueue(struct charqueue *charqueue, unsigned char c);
-int charqueue_dequeue(struct charqueue *charqueue);
-int visor_charqueue_dequeue_n(struct charqueue *charqueue, unsigned char *buf,
- int n);
-BOOL visor_charqueue_is_empty(struct charqueue *charqueue);
-void visor_charqueue_destroy(struct charqueue *charqueue);
-
-#endif
-
diff --git a/drivers/staging/unisys/visorutil/memregion.h b/drivers/staging/unisys/visorutil/memregion.h
deleted file mode 100644
index 0c3eebcf6..000000000
--- a/drivers/staging/unisys/visorutil/memregion.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/* memregion.h
- *
- * Copyright (C) 2010 - 2013 UNISYS CORPORATION
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
- * NON INFRINGEMENT. See the GNU General Public License for more
- * details.
- */
-
-#ifndef __MEMREGION_H__
-#define __MEMREGION_H__
-
-#include "timskmod.h"
-
-/* struct memregion is an opaque structure to users.
- * Fields are declared only in the implementation .c files.
- */
-struct memregion;
-
-struct memregion *visor_memregion_create(HOSTADDRESS physaddr, ulong nbytes);
-struct memregion *visor_memregion_create_overlapped(struct memregion *parent,
- ulong offset, ulong nbytes);
-int visor_memregion_resize(struct memregion *memregion, ulong newsize);
-int visor_memregion_read(struct memregion *memregion,
- ulong offset, void *dest, ulong nbytes);
-int visor_memregion_write(struct memregion *memregion,
- ulong offset, void *src, ulong nbytes);
-void visor_memregion_destroy(struct memregion *memregion);
-HOSTADDRESS visor_memregion_get_physaddr(struct memregion *memregion);
-ulong visor_memregion_get_nbytes(struct memregion *memregion);
-void memregion_dump(struct memregion *memregion, char *s,
- ulong off, ulong len, struct seq_file *seq);
-void __iomem *visor_memregion_get_pointer(struct memregion *memregion);
-
-#endif
diff --git a/drivers/staging/unisys/visorutil/memregion_direct.c b/drivers/staging/unisys/visorutil/memregion_direct.c
deleted file mode 100644
index eb7422fbe..000000000
--- a/drivers/staging/unisys/visorutil/memregion_direct.c
+++ /dev/null
@@ -1,207 +0,0 @@
-/* memregion_direct.c
- *
- * Copyright (C) 2010 - 2013 UNISYS CORPORATION
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
- * NON INFRINGEMENT. See the GNU General Public License for more
- * details.
- */
-
-/*
- * This is an implementation of memory regions that can be used to read/write
- * channel memory (in main memory of the host system) from code running in
- * a virtual partition.
- */
-#include "timskmod.h"
-#include "memregion.h"
-
-#define MYDRVNAME "memregion"
-
-struct memregion {
- HOSTADDRESS physaddr;
- ulong nbytes;
- void __iomem *mapped;
- BOOL requested;
- BOOL overlapped;
-};
-
-static BOOL mapit(struct memregion *memregion);
-static void unmapit(struct memregion *memregion);
-
-struct memregion *
-visor_memregion_create(HOSTADDRESS physaddr, ulong nbytes)
-{
- struct memregion *rc = NULL;
- struct memregion *memregion;
-
- memregion = kzalloc(sizeof(*memregion), GFP_KERNEL | __GFP_NORETRY);
- if (memregion == NULL)
- return NULL;
-
- memregion->physaddr = physaddr;
- memregion->nbytes = nbytes;
- memregion->overlapped = FALSE;
- if (!mapit(memregion)) {
- rc = NULL;
- goto cleanup;
- }
- rc = memregion;
-cleanup:
- if (rc == NULL) {
- visor_memregion_destroy(memregion);
- memregion = NULL;
- }
- return rc;
-}
-EXPORT_SYMBOL_GPL(visor_memregion_create);
-
-struct memregion *
-visor_memregion_create_overlapped(struct memregion *parent, ulong offset,
- ulong nbytes)
-{
- struct memregion *memregion = NULL;
-
- if (parent == NULL)
- return NULL;
-
- if (parent->mapped == NULL)
- return NULL;
-
- if ((offset >= parent->nbytes) ||
- ((offset + nbytes) >= parent->nbytes))
- return NULL;
-
- memregion = kzalloc(sizeof(*memregion), GFP_KERNEL|__GFP_NORETRY);
- if (memregion == NULL)
- return NULL;
-
- memregion->physaddr = parent->physaddr + offset;
- memregion->nbytes = nbytes;
- memregion->mapped = ((u8 __iomem *)(parent->mapped)) + offset;
- memregion->requested = FALSE;
- memregion->overlapped = TRUE;
- return memregion;
-}
-EXPORT_SYMBOL_GPL(visor_memregion_create_overlapped);
-
-static BOOL
-mapit(struct memregion *memregion)
-{
- ulong physaddr = (ulong)(memregion->physaddr);
- ulong nbytes = memregion->nbytes;
-
- memregion->requested = FALSE;
- if (request_mem_region(physaddr, nbytes, MYDRVNAME))
- memregion->requested = TRUE;
- memregion->mapped = ioremap_cache(physaddr, nbytes);
- if (!memregion->mapped)
- return FALSE;
- return TRUE;
-}
-
-static void
-unmapit(struct memregion *memregion)
-{
- if (memregion->mapped != NULL) {
- iounmap(memregion->mapped);
- memregion->mapped = NULL;
- }
- if (memregion->requested) {
- release_mem_region((ulong)(memregion->physaddr),
- memregion->nbytes);
- memregion->requested = FALSE;
- }
-}
-
-HOSTADDRESS
-visor_memregion_get_physaddr(struct memregion *memregion)
-{
- return memregion->physaddr;
-}
-EXPORT_SYMBOL_GPL(visor_memregion_get_physaddr);
-
-ulong
-visor_memregion_get_nbytes(struct memregion *memregion)
-{
- return memregion->nbytes;
-}
-EXPORT_SYMBOL_GPL(visor_memregion_get_nbytes);
-
-void __iomem *
-visor_memregion_get_pointer(struct memregion *memregion)
-{
- return memregion->mapped;
-}
-EXPORT_SYMBOL_GPL(visor_memregion_get_pointer);
-
-int
-visor_memregion_resize(struct memregion *memregion, ulong newsize)
-{
- if (newsize == memregion->nbytes)
- return 0;
- if (memregion->overlapped)
- /* no error check here - we no longer know the
- * parent's range!
- */
- memregion->nbytes = newsize;
- else {
- unmapit(memregion);
- memregion->nbytes = newsize;
- if (!mapit(memregion))
- return -1;
- }
- return 0;
-}
-EXPORT_SYMBOL_GPL(visor_memregion_resize);
-
-static int
-memregion_readwrite(BOOL is_write,
- struct memregion *memregion, ulong offset,
- void *local, ulong nbytes)
-{
- if (offset + nbytes > memregion->nbytes)
- return -EIO;
-
- if (is_write)
- memcpy_toio(memregion->mapped + offset, local, nbytes);
- else
- memcpy_fromio(local, memregion->mapped + offset, nbytes);
-
- return 0;
-}
-
-int
-visor_memregion_read(struct memregion *memregion, ulong offset, void *dest,
- ulong nbytes)
-{
- return memregion_readwrite(FALSE, memregion, offset, dest, nbytes);
-}
-EXPORT_SYMBOL_GPL(visor_memregion_read);
-
-int
-visor_memregion_write(struct memregion *memregion, ulong offset, void *src,
- ulong nbytes)
-{
- return memregion_readwrite(TRUE, memregion, offset, src, nbytes);
-}
-EXPORT_SYMBOL_GPL(visor_memregion_write);
-
-void
-visor_memregion_destroy(struct memregion *memregion)
-{
- if (memregion == NULL)
- return;
- if (!memregion->overlapped)
- unmapit(memregion);
- kfree(memregion);
-}
-EXPORT_SYMBOL_GPL(visor_memregion_destroy);
-
diff --git a/drivers/staging/unisys/visorutil/visorkmodutils.c b/drivers/staging/unisys/visorutil/visorkmodutils.c
deleted file mode 100644
index 62f0f7046..000000000
--- a/drivers/staging/unisys/visorutil/visorkmodutils.c
+++ /dev/null
@@ -1,71 +0,0 @@
-/* timskmodutils.c
- *
- * Copyright (C) 2010 - 2013 UNISYS CORPORATION
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
- * NON INFRINGEMENT. See the GNU General Public License for more
- * details.
- */
-
-#include "timskmod.h"
-
-#define MYDRVNAME "timskmodutils"
-
-/* s-Par uses the Intel processor's VT-X features to separate groups of
- * processors into partitions. The firmware sets the hypervisor bit and
- * reports an ID in the HV capabilities leaf so that the partition's OS
- * knows s-Par is present and managing the processors.
- */
-
-#define UNISYS_SPAR_LEAF_ID 0x40000000
-
-/* The s-Par leaf ID returns "UnisysSpar64" encoded across ebx, ecx, edx */
-#define UNISYS_SPAR_ID_EBX 0x73696e55
-#define UNISYS_SPAR_ID_ECX 0x70537379
-#define UNISYS_SPAR_ID_EDX 0x34367261
-
-int unisys_spar_platform;
-EXPORT_SYMBOL_GPL(unisys_spar_platform);
-
-static __init uint32_t visorutil_spar_detect(void)
-{
- unsigned int eax, ebx, ecx, edx;
-
- if (cpu_has_hypervisor) {
- /* check the ID */
- cpuid(UNISYS_SPAR_LEAF_ID, &eax, &ebx, &ecx, &edx);
- return (ebx == UNISYS_SPAR_ID_EBX) &&
- (ecx == UNISYS_SPAR_ID_ECX) &&
- (edx == UNISYS_SPAR_ID_EDX);
- } else {
- return 0;
- }
-}
-
-static __init int visorutil_mod_init(void)
-{
- if (visorutil_spar_detect()) {
- unisys_spar_platform = TRUE;
- return 0;
- } else {
- return -ENODEV;
- }
-}
-
-static __exit void
-visorutil_mod_exit(void)
-{
-}
-
-module_init(visorutil_mod_init);
-module_exit(visorutil_mod_exit);
-
-MODULE_LICENSE("GPL");