From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753432AbcEQHfY (ORCPT ); Tue, 17 May 2016 03:35:24 -0400 Received: from mail1.bemta8.messagelabs.com ([216.82.243.206]:53360 "EHLO mail1.bemta8.messagelabs.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752688AbcEQHfR (ORCPT ); Tue, 17 May 2016 03:35:17 -0400 X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFrrJIsWRWlGSWpSXmKPExsVywNY2Q1fphFW 4wZcduhYL25awWFzeNYfNgcnj8ya5AMYo1sy8pPyKBNaMXTf62Avm9rBUXD94i7WBsWM9cxcj F4eQwG5GidZFs1khnMOMEtdaTjDDOe+/LmODcC4zSpxvPw7lrGOUuHh7PyOEs4VRYv+Ef0xdj JwcbAIGEjPv3GUHsUUEzrNIPL2VC2ILC4RJrPs1nRXEZhFQlfh/YyEbiM0r4ClxbME1MFtCQE 7i5LHJYDWcAl4SN349A4sLAdVc//ScEcJWkzh89hFUfbDEkQ3XmCDmCEqcnPmEBcRmFpCQOPj iBfMERqFZSFKzkKQWMDKtYtQoTi0qSy3SNbTUSyrKTM8oyU3MzNE1NLDQy00tLk5MT81JTCrW S87P3cQIDOZ6BgbGHYzTdrsfYpTkYFIS5bU8aBUuxJeUn1KZkVicEV9UmpNafIhRhoNDSYL34 jGgnGBRanpqRVpmDjCuYNISHDxKIrx/QNK8xQWJucWZ6RCpU4y6HEt2PVjLJMSSl5+XKiUOMU MApCijNA9uBCzGLzHKSgnzMjIwMAjxFKQW5WaWoMq/YhTnYFQS5n0MMoUnM68EbtMroCOYgI6 YYGYBckRJIkJKqoGRZUPiGwP772fyr7UKnWHdtrQidEewkoeWte3j8tz7lT38i2UkWed2yR1O 2RSXyHD9i0gww8EVV+v0YgWrLVllTu3s/rW5fOX/yBzTqiLh5pMm1bqT5z8wU7ncmS759o2Q6 gbtRIczN3dnrjksU3u7vTEm8q9/Uy/jVmfxTf6rNr+ujl18/L0SS3FGoqEWc1FxIgBJlsNJ7A IAAA== X-Env-Sender: David.Kershner@unisys.com X-Msg-Ref: server-10.tower-99.messagelabs.com!1463470109!20004999!15 X-Originating-IP: [192.61.61.104] X-StarScan-Received: X-StarScan-Version: 8.34; banners=-,-,- X-VirusChecked: Checked From: David Kershner To: , , , , , , , , , , , , , , , , , , , , , Subject: [PATCH 2/5] include: linux: visorbus: Add visorbus to include/linux directory Date: Tue, 17 May 2016 03:27:58 -0400 Message-ID: <1463470081-24223-3-git-send-email-david.kershner@unisys.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1463470081-24223-1-git-send-email-david.kershner@unisys.com> References: <1463470081-24223-1-git-send-email-david.kershner@unisys.com> X-OriginalArrivalTime: 17 May 2016 07:28:28.0900 (UTC) FILETIME=[B50C4A40:01D1B00D] MIME-Version: 1.0 Content-Type: text/plain Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Update include/linux to include the s-Par associated common include header files needed for the s-Par visorbus. Signed-off-by: David Kershner --- include/linux/visorbus/channel.h | 572 +++++++++++++++++++++++++++++++ include/linux/visorbus/channel_guid.h | 55 +++ include/linux/visorbus/diagchannel.h | 38 ++ include/linux/visorbus/guestlinuxdebug.h | 180 ++++++++++ include/linux/visorbus/iochannel.h | 571 ++++++++++++++++++++++++++++++ include/linux/visorbus/periodic_work.h | 40 +++ include/linux/visorbus/vbushelper.h | 46 +++ include/linux/visorbus/version.h | 45 +++ include/linux/visorbus/visorbus.h | 234 +++++++++++++ 9 files changed, 1781 insertions(+) create mode 100644 include/linux/visorbus/channel.h create mode 100644 include/linux/visorbus/channel_guid.h create mode 100644 include/linux/visorbus/diagchannel.h create mode 100644 include/linux/visorbus/guestlinuxdebug.h create mode 100644 include/linux/visorbus/iochannel.h create mode 100644 include/linux/visorbus/periodic_work.h create mode 100644 include/linux/visorbus/vbushelper.h create mode 100644 include/linux/visorbus/version.h create mode 100644 include/linux/visorbus/visorbus.h diff --git a/include/linux/visorbus/channel.h b/include/linux/visorbus/channel.h new file mode 100644 index 0000000..db4e6b2 --- /dev/null +++ b/include/linux/visorbus/channel.h @@ -0,0 +1,572 @@ +/* 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 __CHANNEL_H__ +#define __CHANNEL_H__ + +#include +#include +#include + +/* +* Whenever this file is changed a corresponding change must be made in +* the Console/ServicePart/visordiag_early/supervisor_channel.h file +* which is needed for Linux kernel compiles. These two files must be +* in sync. +*/ + +/* define the following to prevent include nesting in kernel header + * files of similar abbreviated content + */ +#define __SUPERVISOR_CHANNEL_H__ + +#define SIGNATURE_16(A, B) ((A) | (B << 8)) +#define SIGNATURE_32(A, B, C, D) \ + (SIGNATURE_16(A, B) | (SIGNATURE_16(C, D) << 16)) +#define SIGNATURE_64(A, B, C, D, E, F, G, H) \ + (SIGNATURE_32(A, B, C, D) | ((u64)(SIGNATURE_32(E, F, G, H)) << 32)) + +#ifndef lengthof +#define lengthof(TYPE, MEMBER) (sizeof(((TYPE *)0)->MEMBER)) +#endif +#ifndef COVERQ +#define COVERQ(v, d) (((v) + (d) - 1) / (d)) +#endif +#ifndef COVER +#define COVER(v, d) ((d) * COVERQ(v, d)) +#endif + +#define ULTRA_CHANNEL_PROTOCOL_SIGNATURE SIGNATURE_32('E', 'C', 'N', 'L') + +enum channel_serverstate { + CHANNELSRV_UNINITIALIZED = 0, /* channel is in an undefined state */ + CHANNELSRV_READY = 1 /* channel has been initialized by server */ +}; + +enum channel_clientstate { + CHANNELCLI_DETACHED = 0, + CHANNELCLI_DISABLED = 1, /* client can see channel but is NOT + * allowed to use it unless given TBD + * explicit request (should actually be + * < DETACHED) + */ + CHANNELCLI_ATTACHING = 2, /* legacy EFI client request + * for EFI server to attach + */ + CHANNELCLI_ATTACHED = 3, /* idle, but client may want + * to use channel any time + */ + CHANNELCLI_BUSY = 4, /* client either wants to use or is + * using channel + */ + CHANNELCLI_OWNED = 5 /* "no worries" state - client can */ + /* access channel anytime */ +}; + +static inline const u8 * +ULTRA_CHANNELCLI_STRING(u32 state) +{ + switch (state) { + case CHANNELCLI_DETACHED: + return (const u8 *)("DETACHED"); + case CHANNELCLI_DISABLED: + return (const u8 *)("DISABLED"); + case CHANNELCLI_ATTACHING: + return (const u8 *)("ATTACHING"); + case CHANNELCLI_ATTACHED: + return (const u8 *)("ATTACHED"); + case CHANNELCLI_BUSY: + return (const u8 *)("BUSY"); + case CHANNELCLI_OWNED: + return (const u8 *)("OWNED"); + default: + break; + } + return (const u8 *)("?"); +} + +#define SPAR_CHANNEL_SERVER_READY(ch) \ + (readl(&(ch)->srv_state) == CHANNELSRV_READY) + +#define ULTRA_VALID_CHANNELCLI_TRANSITION(o, n) \ + (((((o) == CHANNELCLI_DETACHED) && ((n) == CHANNELCLI_DISABLED)) || \ + (((o) == CHANNELCLI_ATTACHING) && ((n) == CHANNELCLI_DISABLED)) || \ + (((o) == CHANNELCLI_ATTACHED) && ((n) == CHANNELCLI_DISABLED)) || \ + (((o) == CHANNELCLI_ATTACHING) && ((n) == CHANNELCLI_DETACHED)) || \ + (((o) == CHANNELCLI_ATTACHED) && ((n) == CHANNELCLI_DETACHED)) || \ + (((o) == CHANNELCLI_DETACHED) && ((n) == CHANNELCLI_ATTACHING)) || \ + (((o) == CHANNELCLI_ATTACHING) && ((n) == CHANNELCLI_ATTACHED)) || \ + (((o) == CHANNELCLI_DETACHED) && ((n) == CHANNELCLI_ATTACHED)) || \ + (((o) == CHANNELCLI_BUSY) && ((n) == CHANNELCLI_ATTACHED)) || \ + (((o) == CHANNELCLI_ATTACHED) && ((n) == CHANNELCLI_BUSY)) || \ + (((o) == CHANNELCLI_DETACHED) && ((n) == CHANNELCLI_OWNED)) || \ + (((o) == CHANNELCLI_DISABLED) && ((n) == CHANNELCLI_OWNED)) || \ + (((o) == CHANNELCLI_ATTACHING) && ((n) == CHANNELCLI_OWNED)) || \ + (((o) == CHANNELCLI_ATTACHED) && ((n) == CHANNELCLI_OWNED)) || \ + (((o) == CHANNELCLI_BUSY) && ((n) == CHANNELCLI_OWNED)) || (0)) \ + ? (1) : (0)) + +/* Values for ULTRA_CHANNEL_PROTOCOL.CliErrorBoot: */ +/* throttling invalid boot channel statetransition error due to client + * disabled + */ +#define ULTRA_CLIERRORBOOT_THROTTLEMSG_DISABLED 0x01 + +/* throttling invalid boot channel statetransition error due to client + * not attached + */ +#define ULTRA_CLIERRORBOOT_THROTTLEMSG_NOTATTACHED 0x02 + +/* throttling invalid boot channel statetransition error due to busy channel */ +#define ULTRA_CLIERRORBOOT_THROTTLEMSG_BUSY 0x04 + +/* Values for ULTRA_CHANNEL_PROTOCOL.CliErrorOS: */ +/* throttling invalid guest OS channel statetransition error due to + * client disabled + */ +#define ULTRA_CLIERROROS_THROTTLEMSG_DISABLED 0x01 + +/* throttling invalid guest OS channel statetransition error due to + * client not attached + */ +#define ULTRA_CLIERROROS_THROTTLEMSG_NOTATTACHED 0x02 + +/* throttling invalid guest OS channel statetransition error due to + * busy channel + */ +#define ULTRA_CLIERROROS_THROTTLEMSG_BUSY 0x04 + +/* Values for ULTRA_CHANNEL_PROTOCOL.Features: This define exists so + * that windows guest can look at the FeatureFlags in the io channel, + * and configure the windows driver to use interrupts or not based on + * this setting. This flag is set in uislib after the + * ULTRA_VHBA_init_channel is called. All feature bits for all + * channels should be defined here. The io channel feature bits are + * defined right here + */ +#define ULTRA_IO_DRIVER_ENABLES_INTS (0x1ULL << 1) +#define ULTRA_IO_CHANNEL_IS_POLLING (0x1ULL << 3) +#define ULTRA_IO_IOVM_IS_OK_WITH_DRIVER_DISABLING_INTS (0x1ULL << 4) +#define ULTRA_IO_DRIVER_DISABLES_INTS (0x1ULL << 5) +#define ULTRA_IO_DRIVER_SUPPORTS_ENHANCED_RCVBUF_CHECKING (0x1ULL << 6) + +/* Common Channel Header */ +struct channel_header { + u64 signature; /* Signature */ + u32 legacy_state; /* DEPRECATED - being replaced by */ + /* SrvState, CliStateBoot, and CliStateOS below */ + u32 header_size; /* sizeof(struct channel_header) */ + u64 size; /* Total size of this channel in bytes */ + u64 features; /* Flags to modify behavior */ + uuid_le chtype; /* Channel type: data, bus, control, etc. */ + u64 partition_handle; /* ID of guest partition */ + u64 handle; /* Device number of this channel in client */ + u64 ch_space_offset; /* Offset in bytes to channel specific area */ + u32 version_id; /* struct channel_header Version ID */ + u32 partition_index; /* Index of guest partition */ + uuid_le zone_uuid; /* Guid of Channel's zone */ + u32 cli_str_offset; /* offset from channel header to + * nul-terminated ClientString (0 if + * ClientString not present) + */ + u32 cli_state_boot; /* CHANNEL_CLIENTSTATE of pre-boot + * EFI client of this channel + */ + u32 cmd_state_cli; /* CHANNEL_COMMANDSTATE (overloaded in + * Windows drivers, see ServerStateUp, + * ServerStateDown, etc) + */ + u32 cli_state_os; /* CHANNEL_CLIENTSTATE of Guest OS + * client of this channel + */ + u32 ch_characteristic; /* CHANNEL_CHARACTERISTIC_ */ + u32 cmd_state_srv; /* CHANNEL_COMMANDSTATE (overloaded in + * Windows drivers, see ServerStateUp, + * ServerStateDown, etc) + */ + u32 srv_state; /* CHANNEL_SERVERSTATE */ + u8 cli_error_boot; /* bits to indicate err states for + * boot clients, so err messages can + * be throttled + */ + u8 cli_error_os; /* bits to indicate err states for OS + * clients, so err messages can be + * throttled + */ + u8 filler[1]; /* Pad out to 128 byte cacheline */ + /* Please add all new single-byte values below here */ + u8 recover_channel; +} __packed; + +#define ULTRA_CHANNEL_ENABLE_INTS (0x1ULL << 0) + +/* Subheader for the Signal Type variation of the Common Channel */ +struct signal_queue_header { + /* 1st cache line */ + u32 version; /* SIGNAL_QUEUE_HEADER Version ID */ + u32 chtype; /* Queue type: storage, network */ + u64 size; /* Total size of this queue in bytes */ + u64 sig_base_offset; /* Offset to signal queue area */ + u64 features; /* Flags to modify behavior */ + u64 num_sent; /* Total # of signals placed in this queue */ + u64 num_overflows; /* Total # of inserts failed due to + * full queue + */ + u32 signal_size; /* Total size of a signal for this queue */ + u32 max_slots; /* Max # of slots in queue, 1 slot is + * always empty + */ + u32 max_signals; /* Max # of signals in queue + * (MaxSignalSlots-1) + */ + u32 head; /* Queue head signal # */ + /* 2nd cache line */ + u64 num_received; /* Total # of signals removed from this queue */ + u32 tail; /* Queue tail signal */ + u32 reserved1; /* Reserved field */ + u64 reserved2; /* Reserved field */ + u64 client_queue; + u64 num_irq_received; /* Total # of Interrupts received. This + * is incremented by the ISR in the + * guest windows driver + */ + u64 num_empty; /* Number of times that visor_signal_remove + * is called and returned Empty Status. + */ + u32 errorflags; /* Error bits set during SignalReinit + * to denote trouble with client's + * fields + */ + u8 filler[12]; /* Pad out to 64 byte cacheline */ +} __packed; + +#define spar_signal_init(chan, QHDRFLD, QDATAFLD, QDATATYPE, ver, typ) \ + do { \ + memset(&chan->QHDRFLD, 0, sizeof(chan->QHDRFLD)); \ + chan->QHDRFLD.version = ver; \ + chan->QHDRFLD.chtype = typ; \ + chan->QHDRFLD.size = sizeof(chan->QDATAFLD); \ + chan->QHDRFLD.signal_size = sizeof(QDATATYPE); \ + chan->QHDRFLD.sig_base_offset = (u64)(chan->QDATAFLD) - \ + (u64)(&chan->QHDRFLD); \ + chan->QHDRFLD.max_slots = \ + sizeof(chan->QDATAFLD) / sizeof(QDATATYPE); \ + chan->QHDRFLD.max_signals = chan->QHDRFLD.max_slots - 1;\ + } while (0) + +/* Generic function useful for validating any type of channel when it is + * received by the client that will be accessing the channel. + * Note that is only needed for callers in the EFI environment, and + * is used to pass the EFI_DIAG_CAPTURE_PROTOCOL needed to log messages. + */ +static inline int +spar_check_channel_client(void __iomem *ch, + uuid_le expected_uuid, + char *chname, + u64 expected_min_bytes, + u32 expected_version, + u64 expected_signature) +{ + if (uuid_le_cmp(expected_uuid, NULL_UUID_LE) != 0) { + uuid_le guid; + + memcpy_fromio(&guid, + &((struct channel_header __iomem *)(ch))->chtype, + sizeof(guid)); + /* caller wants us to verify type GUID */ + if (uuid_le_cmp(guid, expected_uuid) != 0) { + pr_err("Channel mismatch on channel=%s(%pUL) field=type expected=%pUL actual=%pUL\n", + chname, &expected_uuid, + &expected_uuid, &guid); + return 0; + } + } + if (expected_min_bytes > 0) { /* verify channel size */ + unsigned long long bytes = + readq(&((struct channel_header __iomem *) + (ch))->size); + if (bytes < expected_min_bytes) { + pr_err("Channel mismatch on channel=%s(%pUL) field=size expected=0x%-8.8Lx actual=0x%-8.8Lx\n", + chname, &expected_uuid, + (unsigned long long)expected_min_bytes, bytes); + return 0; + } + } + if (expected_version > 0) { /* verify channel version */ + unsigned long ver = readl(&((struct channel_header __iomem *) + (ch))->version_id); + if (ver != expected_version) { + pr_err("Channel mismatch on channel=%s(%pUL) field=version expected=0x%-8.8lx actual=0x%-8.8lx\n", + chname, &expected_uuid, + (unsigned long)expected_version, ver); + return 0; + } + } + if (expected_signature > 0) { /* verify channel signature */ + unsigned long long sig = + readq(&((struct channel_header __iomem *) + (ch))->signature); + if (sig != expected_signature) { + pr_err("Channel mismatch on channel=%s(%pUL) field=signature expected=0x%-8.8llx actual=0x%-8.8llx\n", + chname, &expected_uuid, + expected_signature, sig); + return 0; + } + } + return 1; +} + +/* Generic function useful for validating any type of channel when it is about + * to be initialized by the server of the channel. + * Note that is only needed for callers in the EFI environment, and + * is used to pass the EFI_DIAG_CAPTURE_PROTOCOL needed to log messages. + */ +static inline int spar_check_channel_server(uuid_le typeuuid, char *name, + u64 expected_min_bytes, + u64 actual_bytes) +{ + if (expected_min_bytes > 0) /* verify channel size */ + if (actual_bytes < expected_min_bytes) { + pr_err("Channel mismatch on channel=%s(%pUL) field=size expected=0x%-8.8llx actual=0x%-8.8llx\n", + name, &typeuuid, expected_min_bytes, + actual_bytes); + return 0; + } + return 1; +} + +/* Given a file pathname (with '/' or '\' separating directory nodes), + * returns a pointer to the beginning of a node within that pathname such + * that the number of nodes from that pointer to the end of the string is + * NOT more than . Note that if the pathname has less than nodes + * in it, the return pointer will be to the beginning of the string. + */ +static inline u8 * +pathname_last_n_nodes(u8 *s, unsigned int n) +{ + u8 *p = s; + unsigned int node_count = 0; + + while (*p != '\0') { + if ((*p == '/') || (*p == '\\')) + node_count++; + p++; + } + if (node_count <= n) + return s; + while (n > 0) { + p--; + if (p == s) + break; /* should never happen, unless someone + * is changing the string while we are + * looking at it!! + */ + if ((*p == '/') || (*p == '\\')) + n--; + } + return p + 1; +} + +static inline int +spar_channel_client_acquire_os(void __iomem *ch, u8 *id) +{ + struct channel_header __iomem *hdr = ch; + + if (readl(&hdr->cli_state_os) == CHANNELCLI_DISABLED) { + if ((readb(&hdr->cli_error_os) + & ULTRA_CLIERROROS_THROTTLEMSG_DISABLED) == 0) { + /* we are NOT throttling this message */ + writeb(readb(&hdr->cli_error_os) | + ULTRA_CLIERROROS_THROTTLEMSG_DISABLED, + &hdr->cli_error_os); + /* throttle until acquire successful */ + + pr_info("%s Channel StateTransition INVALID! - acquire failed because OS client DISABLED\n", + id); + } + return 0; + } + if ((readl(&hdr->cli_state_os) != CHANNELCLI_OWNED) && + (readl(&hdr->cli_state_boot) == CHANNELCLI_DISABLED)) { + /* Our competitor is DISABLED, so we can transition to OWNED */ + pr_info("%s Channel StateTransition (%s) %s(%d)-->%s(%d)\n", + id, "cli_state_os", + ULTRA_CHANNELCLI_STRING(readl(&hdr->cli_state_os)), + readl(&hdr->cli_state_os), + ULTRA_CHANNELCLI_STRING(CHANNELCLI_OWNED), + CHANNELCLI_OWNED); + writel(CHANNELCLI_OWNED, &hdr->cli_state_os); + mb(); /* required for channel synch */ + } + if (readl(&hdr->cli_state_os) == CHANNELCLI_OWNED) { + if (readb(&hdr->cli_error_os)) { + /* we are in an error msg throttling state; + * come out of it + */ + pr_info("%s Channel OS client acquire now successful\n", + id); + writeb(0, &hdr->cli_error_os); + } + return 1; + } + + /* We have to do it the "hard way". We transition to BUSY, + * and can use the channel iff our competitor has not also + * transitioned to BUSY. + */ + if (readl(&hdr->cli_state_os) != CHANNELCLI_ATTACHED) { + if ((readb(&hdr->cli_error_os) + & ULTRA_CLIERROROS_THROTTLEMSG_NOTATTACHED) == 0) { + /* we are NOT throttling this message */ + writeb(readb(&hdr->cli_error_os) | + ULTRA_CLIERROROS_THROTTLEMSG_NOTATTACHED, + &hdr->cli_error_os); + /* throttle until acquire successful */ + pr_info("%s Channel StateTransition INVALID! - acquire failed because OS client NOT ATTACHED (state=%s(%d))\n", + id, ULTRA_CHANNELCLI_STRING( + readl(&hdr->cli_state_os)), + readl(&hdr->cli_state_os)); + } + return 0; + } + writel(CHANNELCLI_BUSY, &hdr->cli_state_os); + mb(); /* required for channel synch */ + if (readl(&hdr->cli_state_boot) == CHANNELCLI_BUSY) { + if ((readb(&hdr->cli_error_os) + & ULTRA_CLIERROROS_THROTTLEMSG_BUSY) == 0) { + /* we are NOT throttling this message */ + writeb(readb(&hdr->cli_error_os) | + ULTRA_CLIERROROS_THROTTLEMSG_BUSY, + &hdr->cli_error_os); + /* throttle until acquire successful */ + pr_info("%s Channel StateTransition failed - host OS acquire failed because boot BUSY\n", + id); + } + /* reset busy */ + writel(CHANNELCLI_ATTACHED, &hdr->cli_state_os); + mb(); /* required for channel synch */ + return 0; + } + if (readb(&hdr->cli_error_os)) { + /* we are in an error msg throttling state; come out of it */ + pr_info("%s Channel OS client acquire now successful\n", id); + writeb(0, &hdr->cli_error_os); + } + return 1; +} + +static inline void +spar_channel_client_release_os(void __iomem *ch, u8 *id) +{ + struct channel_header __iomem *hdr = ch; + + if (readb(&hdr->cli_error_os)) { + /* we are in an error msg throttling state; come out of it */ + pr_info("%s Channel OS client error state cleared\n", id); + writeb(0, &hdr->cli_error_os); + } + if (readl(&hdr->cli_state_os) == CHANNELCLI_OWNED) + return; + if (readl(&hdr->cli_state_os) != CHANNELCLI_BUSY) { + pr_info("%s Channel StateTransition INVALID! - release failed because OS client NOT BUSY (state=%s(%d))\n", + id, ULTRA_CHANNELCLI_STRING( + readl(&hdr->cli_state_os)), + readl(&hdr->cli_state_os)); + /* return; */ + } + writel(CHANNELCLI_ATTACHED, &hdr->cli_state_os); /* release busy */ +} + +/* +* 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); + +/* +* 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); + +/* +* 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); + +/* +* 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); + +#endif diff --git a/include/linux/visorbus/channel_guid.h b/include/linux/visorbus/channel_guid.h new file mode 100644 index 0000000..17cb499 --- /dev/null +++ b/include/linux/visorbus/channel_guid.h @@ -0,0 +1,55 @@ +/* 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. + */ + +/* + * CHANNEL Guids + */ + +/* {414815ed-c58c-11da-95a9-00e08161165f} */ +#define SPAR_VHBA_CHANNEL_PROTOCOL_UUID \ + UUID_LE(0x414815ed, 0xc58c, 0x11da, \ + 0x95, 0xa9, 0x0, 0xe0, 0x81, 0x61, 0x16, 0x5f) +static const uuid_le spar_vhba_channel_protocol_uuid = + SPAR_VHBA_CHANNEL_PROTOCOL_UUID; +#define SPAR_VHBA_CHANNEL_PROTOCOL_UUID_STR \ + "414815ed-c58c-11da-95a9-00e08161165f" + +/* {8cd5994d-c58e-11da-95a9-00e08161165f} */ +#define SPAR_VNIC_CHANNEL_PROTOCOL_UUID \ + UUID_LE(0x8cd5994d, 0xc58e, 0x11da, \ + 0x95, 0xa9, 0x0, 0xe0, 0x81, 0x61, 0x16, 0x5f) +static const uuid_le spar_vnic_channel_protocol_uuid = + SPAR_VNIC_CHANNEL_PROTOCOL_UUID; +#define SPAR_VNIC_CHANNEL_PROTOCOL_UUID_STR \ + "8cd5994d-c58e-11da-95a9-00e08161165f" + +/* {72120008-4AAB-11DC-8530-444553544200} */ +#define SPAR_SIOVM_UUID \ + UUID_LE(0x72120008, 0x4AAB, 0x11DC, \ + 0x85, 0x30, 0x44, 0x45, 0x53, 0x54, 0x42, 0x00) +static const uuid_le spar_siovm_uuid = SPAR_SIOVM_UUID; + +/* {5b52c5ac-e5f5-4d42-8dff-429eaecd221f} */ +#define SPAR_CONTROLDIRECTOR_CHANNEL_PROTOCOL_UUID \ + UUID_LE(0x5b52c5ac, 0xe5f5, 0x4d42, \ + 0x8d, 0xff, 0x42, 0x9e, 0xae, 0xcd, 0x22, 0x1f) + +static const uuid_le spar_controldirector_channel_protocol_uuid = + SPAR_CONTROLDIRECTOR_CHANNEL_PROTOCOL_UUID; + +/* {b4e79625-aede-4eAA-9e11-D3eddcd4504c} */ +#define SPAR_DIAG_POOL_CHANNEL_PROTOCOL_UUID \ + UUID_LE(0xb4e79625, 0xaede, 0x4eaa, \ + 0x9e, 0x11, 0xd3, 0xed, 0xdc, 0xd4, 0x50, 0x4c) diff --git a/include/linux/visorbus/diagchannel.h b/include/linux/visorbus/diagchannel.h new file mode 100644 index 0000000..6e813c7 --- /dev/null +++ b/include/linux/visorbus/diagchannel.h @@ -0,0 +1,38 @@ +/* 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_ + +/* 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/include/linux/visorbus/guestlinuxdebug.h b/include/linux/visorbus/guestlinuxdebug.h new file mode 100644 index 0000000..b81287f --- /dev/null +++ b/include/linux/visorbus/guestlinuxdebug.h @@ -0,0 +1,180 @@ +/* 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 __GUESTLINUXDEBUG_H__ +#define __GUESTLINUXDEBUG_H__ + +/* + * This file contains supporting interface for "vmcallinterface.h", particularly + * regarding adding additional structure and functionality to linux + * ISSUE_IO_VMCALL_POSTCODE_SEVERITY + */ + +/******* INFO ON ISSUE_POSTCODE_LINUX() BELOW *******/ +enum driver_pc { /* POSTCODE driver identifier tuples */ + /* visorchipset driver files */ + VISOR_CHIPSET_PC = 0xA0, + VISOR_CHIPSET_PC_controlvm_c = 0xA1, + VISOR_CHIPSET_PC_controlvm_cm2 = 0xA2, + VISOR_CHIPSET_PC_controlvm_direct_c = 0xA3, + VISOR_CHIPSET_PC_file_c = 0xA4, + VISOR_CHIPSET_PC_parser_c = 0xA5, + VISOR_CHIPSET_PC_testing_c = 0xA6, + VISOR_CHIPSET_PC_visorchipset_main_c = 0xA7, + VISOR_CHIPSET_PC_visorswitchbus_c = 0xA8, + /* visorbus driver files */ + VISOR_BUS_PC = 0xB0, + VISOR_BUS_PC_businst_attr_c = 0xB1, + VISOR_BUS_PC_channel_attr_c = 0xB2, + VISOR_BUS_PC_devmajorminor_attr_c = 0xB3, + VISOR_BUS_PC_visorbus_main_c = 0xB4, + /* visorclientbus driver files */ + VISOR_CLIENT_BUS_PC = 0xC0, + VISOR_CLIENT_BUS_PC_visorclientbus_main_c = 0xC1, + /* virt hba driver files */ + VIRT_HBA_PC = 0xC2, + VIRT_HBA_PC_virthba_c = 0xC3, + /* virtpci driver files */ + VIRT_PCI_PC = 0xC4, + VIRT_PCI_PC_virtpci_c = 0xC5, + /* virtnic driver files */ + VIRT_NIC_PC = 0xC6, + VIRT_NIC_P_virtnic_c = 0xC7, + /* uislib driver files */ + UISLIB_PC = 0xD0, + UISLIB_PC_uislib_c = 0xD1, + UISLIB_PC_uisqueue_c = 0xD2, + UISLIB_PC_uisthread_c = 0xD3, + UISLIB_PC_uisutils_c = 0xD4, +}; + +enum event_pc { /* POSTCODE event identifier tuples */ + ATTACH_PORT_ENTRY_PC = 0x001, + ATTACH_PORT_FAILURE_PC = 0x002, + ATTACH_PORT_SUCCESS_PC = 0x003, + BUS_FAILURE_PC = 0x004, + BUS_CREATE_ENTRY_PC = 0x005, + BUS_CREATE_FAILURE_PC = 0x006, + BUS_CREATE_EXIT_PC = 0x007, + BUS_CONFIGURE_ENTRY_PC = 0x008, + BUS_CONFIGURE_FAILURE_PC = 0x009, + BUS_CONFIGURE_EXIT_PC = 0x00A, + CHIPSET_INIT_ENTRY_PC = 0x00B, + CHIPSET_INIT_SUCCESS_PC = 0x00C, + CHIPSET_INIT_FAILURE_PC = 0x00D, + CHIPSET_INIT_EXIT_PC = 0x00E, + CREATE_WORKQUEUE_PC = 0x00F, + CREATE_WORKQUEUE_FAILED_PC = 0x0A0, + CONTROLVM_INIT_FAILURE_PC = 0x0A1, + DEVICE_CREATE_ENTRY_PC = 0x0A2, + DEVICE_CREATE_FAILURE_PC = 0x0A3, + DEVICE_CREATE_SUCCESS_PC = 0x0A4, + DEVICE_CREATE_EXIT_PC = 0x0A5, + DEVICE_ADD_PC = 0x0A6, + DEVICE_REGISTER_FAILURE_PC = 0x0A7, + DEVICE_CHANGESTATE_ENTRY_PC = 0x0A8, + DEVICE_CHANGESTATE_FAILURE_PC = 0x0A9, + DEVICE_CHANGESTATE_EXIT_PC = 0x0AA, + DRIVER_ENTRY_PC = 0x0AB, + DRIVER_EXIT_PC = 0x0AC, + MALLOC_FAILURE_PC = 0x0AD, + QUEUE_DELAYED_WORK_PC = 0x0AE, + UISLIB_THREAD_FAILURE_PC = 0x0B7, + VBUS_CHANNEL_ENTRY_PC = 0x0B8, + VBUS_CHANNEL_FAILURE_PC = 0x0B9, + VBUS_CHANNEL_EXIT_PC = 0x0BA, + VHBA_CREATE_ENTRY_PC = 0x0BB, + VHBA_CREATE_FAILURE_PC = 0x0BC, + VHBA_CREATE_EXIT_PC = 0x0BD, + VHBA_CREATE_SUCCESS_PC = 0x0BE, + VHBA_COMMAND_HANDLER_PC = 0x0BF, + VHBA_PROBE_ENTRY_PC = 0x0C0, + VHBA_PROBE_FAILURE_PC = 0x0C1, + VHBA_PROBE_EXIT_PC = 0x0C2, + VNIC_CREATE_ENTRY_PC = 0x0C3, + VNIC_CREATE_FAILURE_PC = 0x0C4, + VNIC_CREATE_SUCCESS_PC = 0x0C5, + VNIC_PROBE_ENTRY_PC = 0x0C6, + VNIC_PROBE_FAILURE_PC = 0x0C7, + VNIC_PROBE_EXIT_PC = 0x0C8, + VPCI_CREATE_ENTRY_PC = 0x0C9, + VPCI_CREATE_FAILURE_PC = 0x0CA, + VPCI_CREATE_EXIT_PC = 0x0CB, + VPCI_PROBE_ENTRY_PC = 0x0CC, + VPCI_PROBE_FAILURE_PC = 0x0CD, + VPCI_PROBE_EXIT_PC = 0x0CE, + CRASH_DEV_ENTRY_PC = 0x0CF, + CRASH_DEV_EXIT_PC = 0x0D0, + CRASH_DEV_HADDR_NULL = 0x0D1, + CRASH_DEV_CONTROLVM_NULL = 0x0D2, + CRASH_DEV_RD_BUS_FAIULRE_PC = 0x0D3, + CRASH_DEV_RD_DEV_FAIULRE_PC = 0x0D4, + CRASH_DEV_BUS_NULL_FAILURE_PC = 0x0D5, + CRASH_DEV_DEV_NULL_FAILURE_PC = 0x0D6, + CRASH_DEV_CTRL_RD_FAILURE_PC = 0x0D7, + CRASH_DEV_COUNT_FAILURE_PC = 0x0D8, + SAVE_MSG_BUS_FAILURE_PC = 0x0D9, + SAVE_MSG_DEV_FAILURE_PC = 0x0DA, + CALLHOME_INIT_FAILURE_PC = 0x0DB +}; + +#ifdef __GNUC__ + +#define POSTCODE_SEVERITY_ERR DIAG_SEVERITY_ERR +#define POSTCODE_SEVERITY_WARNING DIAG_SEVERITY_WARNING +/* TODO-> Info currently doesn't show, so we set info=warning */ +#define POSTCODE_SEVERITY_INFO DIAG_SEVERITY_PRINT + +/* 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 + * searching for the __LINE__ number, convert it first to decimal. The line + * number combined with driver and type of call, will allow you to track down + * exactly what line an error occurred on, or where the last driver + * entered/exited from. + */ + +/* BASE FUNCTIONS */ +#define POSTCODE_LINUX_A(DRIVER_PC, EVENT_PC, pc32bit, severity) \ +do { \ + unsigned long long post_code_temp; \ + post_code_temp = (((u64)DRIVER_PC) << 56) | (((u64)EVENT_PC) << 44) | \ + ((((u64)__LINE__) & 0xFFF) << 32) | \ + (((u64)pc32bit) & 0xFFFFFFFF); \ + ISSUE_IO_VMCALL_POSTCODE_SEVERITY(post_code_temp, severity); \ +} while (0) + +#define POSTCODE_LINUX_B(DRIVER_PC, EVENT_PC, pc16bit1, pc16bit2, severity) \ +do { \ + unsigned long long post_code_temp; \ + post_code_temp = (((u64)DRIVER_PC) << 56) | (((u64)EVENT_PC) << 44) | \ + ((((u64)__LINE__) & 0xFFF) << 32) | \ + ((((u64)pc16bit1) & 0xFFFF) << 16) | \ + (((u64)pc16bit2) & 0xFFFF); \ + ISSUE_IO_VMCALL_POSTCODE_SEVERITY(post_code_temp, severity); \ +} while (0) + +/* MOST COMMON */ +#define POSTCODE_LINUX_2(EVENT_PC, severity) \ + POSTCODE_LINUX_A(CURRENT_FILE_PC, EVENT_PC, 0x0000, severity) + +#define POSTCODE_LINUX_3(EVENT_PC, pc32bit, severity) \ + POSTCODE_LINUX_A(CURRENT_FILE_PC, EVENT_PC, pc32bit, severity) + +#define POSTCODE_LINUX_4(EVENT_PC, pc16bit1, pc16bit2, severity) \ + POSTCODE_LINUX_B(CURRENT_FILE_PC, EVENT_PC, pc16bit1, \ + pc16bit2, severity) + +#endif +#endif diff --git a/include/linux/visorbus/iochannel.h b/include/linux/visorbus/iochannel.h new file mode 100644 index 0000000..5ccf814 --- /dev/null +++ b/include/linux/visorbus/iochannel.h @@ -0,0 +1,571 @@ +/* Copyright (C) 2010 - 2013 UNISYS CORPORATION */ +/* All rights reserved. */ +#ifndef __IOCHANNEL_H__ +#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. + */ + +/* + * 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 + +#include +#include "channel.h" +#include "channel_guid.h" + +#define ULTRA_VHBA_CHANNEL_PROTOCOL_SIGNATURE ULTRA_CHANNEL_PROTOCOL_SIGNATURE +#define ULTRA_VNIC_CHANNEL_PROTOCOL_SIGNATURE ULTRA_CHANNEL_PROTOCOL_SIGNATURE +#define ULTRA_VSWITCH_CHANNEL_PROTOCOL_SIGNATURE \ + 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. + */ +#define ULTRA_VHBA_CHANNEL_PROTOCOL_VERSIONID 2 +#define ULTRA_VNIC_CHANNEL_PROTOCOL_VERSIONID 2 +#define ULTRA_VSWITCH_CHANNEL_PROTOCOL_VERSIONID 1 + +#define SPAR_VHBA_CHANNEL_OK_CLIENT(ch) \ + (spar_check_channel_client(ch, spar_vhba_channel_protocol_uuid, \ + "vhba", MIN_IO_CHANNEL_SIZE, \ + ULTRA_VHBA_CHANNEL_PROTOCOL_VERSIONID, \ + ULTRA_VHBA_CHANNEL_PROTOCOL_SIGNATURE)) + +#define SPAR_VNIC_CHANNEL_OK_CLIENT(ch) \ + (spar_check_channel_client(ch, spar_vnic_channel_protocol_uuid, \ + "vnic", MIN_IO_CHANNEL_SIZE, \ + ULTRA_VNIC_CHANNEL_PROTOCOL_VERSIONID, \ + ULTRA_VNIC_CHANNEL_PROTOCOL_SIGNATURE)) + +/* + * Everything necessary to handle SCSI & NIC traffic between Guest Partition and + * IO Partition is defined below. + */ + +/* Defines and enums. */ +#define MINNUM(a, b) (((a) < (b)) ? (a) : (b)) +#define MAXNUM(a, b) (((a) > (b)) ? (a) : (b)) + +/* define the two queues per data channel between iopart and ioguestparts */ +/* used by ioguestpart to 'insert' signals to iopart */ +#define IOCHAN_TO_IOPART 0 +/* used by ioguestpart to 'remove' signals from iopart, same previous queue */ +#define IOCHAN_FROM_IOPART 1 + +/* size of cdb - i.e., scsi cmnd */ +#define MAX_CMND_SIZE 16 + +#define MAX_SENSE_SIZE 64 + +#define MAX_PHYS_INFO 64 + +/* various types of network packets that can be sent in cmdrsp */ +enum net_types { + NET_RCV_POST = 0, /* submit buffer to hold receiving + * incoming packet + */ + /* virtnic -> uisnic */ + NET_RCV, /* incoming packet received */ + /* uisnic -> virtpci */ + NET_XMIT, /* for outgoing net packets */ + /* virtnic -> uisnic */ + NET_XMIT_DONE, /* outgoing packet xmitted */ + /* uisnic -> virtpci */ + NET_RCV_ENBDIS, /* enable/disable packet reception */ + /* virtnic -> uisnic */ + NET_RCV_ENBDIS_ACK, /* acknowledge enable/disable packet */ + /* reception */ + /* uisnic -> virtnic */ + NET_RCV_PROMISC, /* enable/disable promiscuous mode */ + /* virtnic -> uisnic */ + NET_CONNECT_STATUS, /* indicate the loss or restoration of a network + * connection + */ + /* uisnic -> virtnic */ + NET_MACADDR, /* indicates the client has requested to update + * its MAC addr + */ + NET_MACADDR_ACK, /* MAC address */ + +}; + +#define ETH_HEADER_SIZE 14 /* size of ethernet header */ + +#define ETH_MIN_DATA_SIZE 46 /* minimum eth data size */ +#define ETH_MIN_PACKET_SIZE (ETH_HEADER_SIZE + ETH_MIN_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 */ + +/* various types of scsi task mgmt commands */ +enum task_mgmt_types { + TASK_MGMT_ABORT_TASK = 1, + TASK_MGMT_BUS_RESET, + TASK_MGMT_LUN_RESET, + TASK_MGMT_TARGET_RESET, +}; + +/* various types of vdisk mgmt commands */ +enum vdisk_mgmt_types { + VDISK_MGMT_ACQUIRE = 1, + VDISK_MGMT_RELEASE, +}; + +struct phys_info { + u64 pi_pfn; + u16 pi_off; + u16 pi_len; +} __packed; + +#define MIN_NUMSIGNALS 64 + +/* structs with pragma pack */ + +struct guest_phys_info { + u64 address; + u64 length; +} __packed; + +#define GPI_ENTRIES_PER_PAGE (PAGE_SIZE / sizeof(struct guest_phys_info)) + +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). + */ +struct vhba_config_max {/* 20 bytes */ + u32 max_channel;/* maximum channel for devices attached to this bus */ + u32 max_id; /* maximum SCSI ID for devices attached to bus */ + u32 max_lun; /* maximum SCSI LUN for devices attached to bus */ + u32 cmd_per_lun;/* maximum number of outstanding commands per LUN */ + u32 max_io_size;/* maximum io size for devices attached to this 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 { + u64 handle; /* the handle to the cmd that was received */ + /* send it back as is in the rsp packet. */ + u8 cmnd[MAX_CMND_SIZE]; /* the cdb for the command */ + u32 bufflen; /* length of data to be transferred out or in */ + u16 guest_phys_entries; /* Number of entries in scatter-gather list */ + struct guest_phys_info gpi_list[MAX_PHYS_INFO]; /* physical address + * information for each + * fragment + */ + enum dma_data_direction data_dir; /* direction of the data, if any */ + struct uisscsi_dest vdest; /* identifies the virtual hba, id, */ + /* channel, lun to which cmd was sent */ + + /* Needed to queue the rsp back to cmd originator */ + int linuxstat; /* original Linux status used by linux vdisk */ + u8 scsistat; /* the scsi status */ + u8 addlstat; /* non-scsi status */ +#define ADDL_SEL_TIMEOUT 4 + + /* the following fields are need to determine the result of command */ + u8 sensebuf[MAX_SENSE_SIZE]; /* sense info in case cmd failed; */ + /* it holds the sense_data struct; */ + /* see that struct for details. */ + void *vdisk; /* pointer to the vdisk to clean up when 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. + */ +} __packed; + +/* Defines to support sending correct inquiry result when no disk is + * configured. + */ + +/* From SCSI SPC2 - + * + * If the target is not capable of supporting a device on this logical unit, the + * device server shall set this field to 7Fh (PERIPHERAL QUALIFIER set to 011b + * and PERIPHERAL DEVICE TYPE set to 1Fh). + * + *The device server is capable of supporting the specified peripheral device + *type on this logical unit. However, the physical device is not currently + *connected to this logical unit. + */ + +#define DEV_NOT_CAPABLE 0x7f /* peripheral qualifier of 0x3 */ + /* 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_HISUPPORT 0x10 /* HiSup = 1; shows support for report luns */ + /* 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. + */ +#define NO_DISK_INQUIRY_RESULT_LEN 36 + +#define MIN_INQUIRY_RESULT_LEN 5 /* 5 bytes minimum for inquiry result */ + +/* SCSI device version for no disk inquiry result */ +#define SCSI_SPC2_VER 4 /* indicates SCSI SPC2 (SPC3 is 5) */ + +/* 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. + */ +struct sense_data { + u8 errorcode:7; + u8 valid:1; + u8 segment_number; + u8 sense_key:4; + u8 reserved:1; + u8 incorrect_length:1; + u8 end_of_media:1; + u8 file_mark:1; + u8 information[4]; + u8 additional_sense_length; + u8 command_specific_information[4]; + u8 additional_sense_code; + u8 additional_sense_code_qualifier; + u8 fru_code; + u8 sense_key_specific[3]; +} __packed; + +struct net_pkt_xmt { + int len; /* full length of data in the packet */ + int num_frags; /* number of fragments in frags containing data */ + struct phys_info frags[MAX_PHYS_INFO]; /* physical page information */ + char ethhdr[ETH_HEADER_SIZE]; /* the ethernet header */ + struct { + /* these are needed for csum at uisnic end */ + u8 valid; /* 1 = struct is valid - else ignore */ + u8 hrawoffv; /* 1 = hwrafoff is valid */ + u8 nhrawoffv; /* 1 = nhwrafoff is valid */ + u16 protocol; /* specifies packet protocol */ + u32 csum; /* value used to set skb->csum at IOPart */ + u32 hrawoff; /* value used to set skb->h.raw at IOPart */ + /* hrawoff points to the start of the TRANSPORT LAYER HEADER */ + u32 nhrawoff; /* value used to set skb->nh.raw at IOPart */ + /* nhrawoff points to the start of the NETWORK LAYER HEADER */ + } lincsum; + + /* **** NOTE **** + * The full packet is described in frags but the ethernet header is + * separately kept in ethhdr so that uisnic doesn't have "MAP" the + * 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 */ +} __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. + */ +#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 + */ + struct phys_info frag; /* physical page information for the */ + /* single fragment 2K rcv buf */ + u64 unique_num; + /* unique_num ensure that receive posts are returned to */ + /* the Adapter which we sent them originally. */ +} __packed; + +struct net_pkt_rcv { + /* the number of receive buffers that can be chained */ + /* is based on max mtu and size of each rcv buf */ + u32 rcv_done_len; /* length of received data */ + u8 numrcvbufs; /* number of receive buffers that contain the */ + /* incoming data; guest end MUST chain these together. */ + void *rcvbuf[MAX_NET_RCV_CHAIN]; /* list of chained rcvbufs */ + /* each entry is a receive buffer provided by NET_RCV_POST. */ + /* 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_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_enbdis enbdis; /* used for NET_RCV_ENBDIS, */ + /* 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; + + /* the type of task */ + struct uisscsi_dest vdest; + + /* the vdisk for which this task mgmt is generated */ + u64 handle; + + /* This is a 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. + */ + u64 notify_handle; + + /* 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. + * 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. + */ + u64 notifyresult_handle; + + /* 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. + */ + char result; + + /* result of taskmgmt command - set by IOPart - values are: */ +#define TASK_MGMT_FAILED 0 +} __packed; + +/* 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 */ + void *v_hba; /* 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. + */ +struct uiscmdrsp_vdiskmgmt { + enum vdisk_mgmt_types vdisktype; + + /* the type of task */ + struct uisscsi_dest vdest; + + /* the vdisk for which this task mgmt is generated */ + u64 handle; + + /* This is a 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. + */ + u64 notify_handle; + + /* For linux guests, this is a pointer to wait_queue_head that a + * thread is waiting on to see if the tskmgmt 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. + */ + u64 notifyresult_handle; + + /* 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. + */ + char result; + + /* result of taskmgmt command - set by IOPart - values are: */ +#define VDISK_MGMT_FAILED 0 +} __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 */ +#define CMD_SCSI_TYPE 1 +#define CMD_NET_TYPE 2 +#define CMD_SCSITASKMGMT_TYPE 3 +#define CMD_NOTIFYGUEST_TYPE 4 +#define CMD_VDISKMGMT_TYPE 5 + union { + struct uiscmdrsp_scsi scsi; + struct uiscmdrsp_net net; + struct uiscmdrsp_scsitaskmgmt scsitaskmgmt; + struct uiscmdrsp_disknotify disknotify; + struct uiscmdrsp_vdiskmgmt vdiskmgmt; + }; + void *private_data; /* send the response when the cmd is */ + /* 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 */ +} __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. + */ +struct spar_io_channel_protocol { + struct channel_header channel_header; + struct signal_queue_header cmd_q; + struct signal_queue_header rsp_q; + union { + struct iochannel_vhba vhba; + struct iochannel_vnic vnic; + } __packed; + +#define MAX_CLIENTSTRING_LEN 1024 + /* client_string is NULL termimated so holds max -1 bytes */ + u8 client_string[MAX_CLIENTSTRING_LEN]; +} __packed; + +/* 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)) + +#define MIN_IO_CHANNEL_SIZE COVER(SIZEOF_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. + */ + +/* use 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 + +/* returns next non-zero index on success or zero on failure (i.e. out of + * room) + */ +static inline u16 +add_physinfo_entries(u64 inp_pfn, u16 inp_off, u32 inp_len, u16 index, + u16 max_pi_arr_entries, struct phys_info pi_arr[]) +{ + u32 len; + u16 i, firstlen; + + firstlen = PI_PAGE_SIZE - inp_off; + if (inp_len <= firstlen) { + /* the input entry spans only one page - add as is */ + if (index >= max_pi_arr_entries) + return 0; + pi_arr[index].pi_pfn = inp_pfn; + pi_arr[index].pi_off = (u16)inp_off; + pi_arr[index].pi_len = (u16)inp_len; + return index + 1; + } + + /* this entry spans multiple pages */ + for (len = inp_len, i = 0; len; + len -= pi_arr[index + i].pi_len, i++) { + if (index + i >= max_pi_arr_entries) + return 0; + pi_arr[index + i].pi_pfn = inp_pfn + i; + if (i == 0) { + pi_arr[index].pi_off = inp_off; + pi_arr[index].pi_len = firstlen; + } else { + pi_arr[index + i].pi_off = 0; + pi_arr[index + i].pi_len = + (u16)MINNUM(len, (u32)PI_PAGE_SIZE); + } + } + return index + i; +} + +#endif /* __IOCHANNEL_H__ */ diff --git a/include/linux/visorbus/periodic_work.h b/include/linux/visorbus/periodic_work.h new file mode 100644 index 0000000..0b3335a --- /dev/null +++ b/include/linux/visorbus/periodic_work.h @@ -0,0 +1,40 @@ +/* periodic_work.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 __PERIODIC_WORK_H__ +#define __PERIODIC_WORK_H__ + +#include +#include + +/* PERIODIC_WORK an opaque structure to users. + * Fields are declared only in the implementation .c files. + */ +struct periodic_work; + +struct periodic_work * +visor_periodic_work_create(ulong jiffy_interval, + struct workqueue_struct *workqueue, + void (*workfunc)(void *), + 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); + +#endif diff --git a/include/linux/visorbus/vbushelper.h b/include/linux/visorbus/vbushelper.h new file mode 100644 index 0000000..f1b6aac --- /dev/null +++ b/include/linux/visorbus/vbushelper.h @@ -0,0 +1,46 @@ +/* vbushelper.h + * + * Copyright (C) 2011 - 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 __VBUSHELPER_H__ +#define __VBUSHELPER_H__ + +/* TARGET_HOSTNAME specified as -DTARGET_HOSTNAME=\"thename\" on the + * command line + */ + +#define TARGET_HOSTNAME "linuxguest" + +static inline void bus_device_info_init( + struct ultra_vbus_deviceinfo *bus_device_info_ptr, + const char *dev_type, const char *drv_name, + const char *ver, const char *ver_tag) +{ + memset(bus_device_info_ptr, 0, sizeof(struct ultra_vbus_deviceinfo)); + snprintf(bus_device_info_ptr->devtype, + sizeof(bus_device_info_ptr->devtype), + "%s", (dev_type) ? dev_type : "unknownType"); + snprintf(bus_device_info_ptr->drvname, + sizeof(bus_device_info_ptr->drvname), + "%s", (drv_name) ? drv_name : "unknownDriver"); + snprintf(bus_device_info_ptr->infostrs, + sizeof(bus_device_info_ptr->infostrs), "%s\t%s\t%s", + (ver) ? ver : "unknownVer", + (ver_tag) ? ver_tag : "unknownVerTag", + TARGET_HOSTNAME); +} + +#endif diff --git a/include/linux/visorbus/version.h b/include/linux/visorbus/version.h new file mode 100644 index 0000000..83d1da7 --- /dev/null +++ b/include/linux/visorbus/version.h @@ -0,0 +1,45 @@ +/* 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. + */ + +/* version.h */ + +/* Common version/release info needed by all components goes here. + * (This file must compile cleanly in all environments.) + * Ultimately, this will be combined with defines generated dynamically as + * part of the sysgen, and some of the defines below may in fact end up + * being replaced with dynamically generated ones. + */ +#ifndef __VERSION_H__ +#define __VERSION_H__ + +#define SPARVER1 "1" +#define SPARVER2 "0" +#define SPARVER3 "0" +#define SPARVER4 "0" + +#define VERSION SPARVER1 "." SPARVER2 "." SPARVER3 "." SPARVER4 + +/* Here are various version forms needed in Windows environments. + */ +#define VISOR_PRODUCTVERSION SPARVERCOMMA +#define VISOR_PRODUCTVERSION_STR SPARVER1 "." SPARVER2 "." SPARVER3 "." \ + SPARVER4 +#define VISOR_OBJECTVERSION_STR SPARVER1 "," SPARVER2 "," SPARVER3 "," \ + SPARVER4 + +#define COPYRIGHT "Unisys Corporation" +#define COPYRIGHTDATE "2010 - 2013" + +#endif diff --git a/include/linux/visorbus/visorbus.h b/include/linux/visorbus/visorbus.h new file mode 100644 index 0000000..9baf1ec --- /dev/null +++ b/include/linux/visorbus/visorbus.h @@ -0,0 +1,234 @@ +/* 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 +#include +#include +#include +#include + +#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; +}; + +/** + * struct visor_driver - Information provided by each visor driver when it + * registers with the visorbus driver. + * @name: Name of the visor driver. + * @version: The numbered version of the driver (x.x.xxx). + * @vertag: A human readable version string. + * @owner: The module owner. + * @channel_types: Types of channels handled by this driver, ending with + * a zero 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. + * @probe: 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(), or driver_attach()). + * @remove: Called when a new device is removed, by our remove() + * function specified by driver.remove() (triggered + * ultimately by some call to device_release_driver()). + * @channel_interrupt: Called periodically, whenever there is a possiblity + * that "something interesting" may have happened to the + * channel. + * @pause: 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. + * @resume: Behaves similar to pause. + * @driver: Private reference to the device driver. For use by bus + * driver only. + * @version_attr: Private version field. For use by bus driver only. + */ +struct visor_driver { + const char *name; + const char *version; + const char *vertag; + struct module *owner; + struct visor_channeltype_descriptor *channel_types; + int (*probe)(struct visor_device *dev); + void (*remove)(struct visor_device *dev); + void (*channel_interrupt)(struct visor_device *dev); + 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) ((x) ? \ + (container_of(x, struct visor_driver, driver)) : (NULL)) + +/** + * struct visor_device - A device type for things "plugged" into the visorbus + * bus + * visorchannel: Points to the channel that the device is + * associated with. + * channel_type_guid: Identifies the channel type to the bus driver. + * device: Device struct meant for use by the bus driver + * only. + * list_all: Used by the bus driver to enumerate devices. + * periodic_work: Device work queue. Private use by bus driver + * only. + * being_removed: Indicates that the device is being removed from + * the bus. Private bus driver use only. + * visordriver_callback_lock: Used by the bus driver to lock when handling + * channel events. + * pausing: Indicates that a change towards a paused state. + * is in progress. Only modified by the bus driver. + * resuming: Indicates that a change towards a running state + * is in progress. Only modified by the bus driver. + * chipset_bus_no: Private field used by the bus driver. + * chipset_dev_no: Private field used the bus driver. + * state: Used to indicate the current state of the + * device. + * inst: Unique GUID for this instance of the device. + * name: Name of the device. + * pending_msg_hdr: For private use by bus driver to respond to + * hypervisor requests. + * vbus_hdr_info: A pointer to header info. Private use by bus + * driver. + * partition_uuid: Indicates client partion id. This should be the + * same across all visor_devices in the current + * guest. Private use by bus driver only. + */ + +struct visor_device { + struct visorchannel *visorchannel; + uuid_le channel_type_guid; + /* These fields are for private use by the bus driver only. */ + struct device device; + struct list_head list_all; + struct periodic_work *periodic_work; + bool being_removed; + struct semaphore visordriver_callback_lock; + bool pausing; + bool resuming; + u32 chipset_bus_no; + u32 chipset_dev_no; + struct visorchipset_state state; + uuid_le inst; + u8 *name; + struct controlvm_message_header *pending_msg_hdr; + void *vbus_hdr_info; + 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); +void visorbus_enable_channel_interrupts(struct visor_device *dev); +void visorbus_disable_channel_interrupts(struct visor_device *dev); +#endif + +/* Note that for visorchannel_create() + * and 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); +bool visorchannel_signalempty(struct visorchannel *channel, u32 queue); + +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 -- 1.9.1