vsw_hio.c revision da14cebe459d3275048785f25bd869cb09b5307f
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <sys/sysmacros.h>
#include <sys/ethernet.h>
#include <sys/machsystm.h>
#include <sys/mac_provider.h>
#include <sys/mac_ether.h>
#include <sys/mach_descrip.h>
#include <sys/vio_mailbox.h>
#include <sys/vnet_mailbox.h>
#include <sys/vnet_common.h>
#include <sys/vio_util.h>
extern int vsw_hio_max_cleanup_retries;
extern int vsw_hio_cleanup_delay;
/* Functions imported from other files */
/* Functions exported to other files */
/* Support functions */
/*
* Locking strategy for HybridIO is followed as below:
*
* - As the Shares are associated with a network device, the
* the global lock('vswp>mac_lock') is used for all Shares
* related operations.
* - The 'port->maccl_rwlock' is used to synchronize only the
* the operations that operate on that port's mac client. That
* is, the share_bind and unbind operations only.
*
* - The locking hierarchy follows that the global mac_lock is
* acquired first and then the ports mac client lock(maccl_rwlock)
*/
/*
* vsw_hio_init -- Initialize the HybridIO related info.
* - Query SHARES and RINGS capability. Both capabilities
* need to be supported by the physical-device.
*/
void
{
int num_shares;
int i;
if (vsw_hio_enabled == B_FALSE) {
return;
}
if (num_shares == 0) {
return;
}
for (i = 0; i < hiop->vh_num_shares; i++) {
}
/*
* Register to get reboot and panic events so that
* we can cleanup HybridIO resources gracefully.
*/
/* setup kstats for hybrid resources */
}
}
/*
* vsw_hio_alloc_share -- Allocate and setup the share for a guest domain.
* - Allocate a free share.
* - Bind the Guest's MAC address.
*/
static vsw_share_t *
{
int rv;
/* No free shares available */
return (NULL);
}
if (rv != 0) {
return (NULL);
}
/* Cache some useful info */
return (vsharep);
}
/*
* vsw_hio_find_free_share -- Find a free Share.
*/
static vsw_share_t *
{
int i;
for (i = 0; i < hiop->vh_num_shares; i++) {
return (vsharep);
}
}
return (NULL);
}
/*
* vsw_hio_find_vshare_ldcid -- Given ldc_id, find the corresponding
* share structure.
*/
static vsw_share_t *
{
int i;
for (i = 0; i < hiop->vh_num_shares; i++) {
continue;
}
return (vsharep);
}
}
return (NULL);
}
/*
* vsw_hio_find_vshare_port -- Given portp, find the corresponding
* share structure.
*/
static vsw_share_t *
{
int i;
for (i = 0; i < hiop->vh_num_shares; i++) {
continue;
}
return (vsharep);
}
}
return (NULL);
}
/*
* vsw_hio_free_share -- Unbind the MAC address and free share.
*/
static void
{
vsharep->vs_macaddr = 0;
/* DERR only for printing by default */
}
/*
* vsw_hio_cleanup -- Cleanup the HybridIO. It unregisters the callbs
* and frees all shares.
*/
void
{
/* Unregister reboot and panic callbs. */
if (vswp->hio_reboot_cb_id) {
vswp->hio_reboot_cb_id = 0;
}
if (vswp->hio_panic_cb_id) {
vswp->hio_panic_cb_id = 0;
}
}
/*
* vsw_hio_free_all_shares -- A routine to free all shares gracefully.
* The following are the steps followed to accomplish this:
*
* - First clear 'hio_capable' to avoid further share allocations.
* - If a share is in accepted(ACKD) state, that means the guest
* has HybridIO setup etc. If so, send a DEL_SHARE message and
* give some time(delay) for the guest to ACK.
* - If the Share is another state, give some time to transition to
* ACKD state, then try the above.
* - After max retries, reset the ports to brute force the shares
* to be freed. Give a little delay for the LDC reset code to
* free the Share.
*/
static void
{
int free_shares = 0;
int i;
/*
* Acquire plist->lockrw to make the locking a bit easier
* and keep the ports in a stable state while we are cleaningup
* HybridIO.
*/
/*
* first clear the hio_capable flag so that no more
* HybridIO operations are initiated.
*/
do {
free_shares = 0;
for (i = 0; i < hiop->vh_num_shares; i++) {
free_shares++;
continue;
}
/*
* If the share is in DDS_ACKD state, then
* send DEL_SHARE message so that guest can
* release its Hybrid resource.
*/
int rv;
/* send DDS_DEL_SHARE */
if (rv != 0) {
/*
* No alternative, reset the port
* to force the release of Hybrid
* resources.
*/
B_FALSE);
}
}
if (max_retries == 1) {
/*
* Last retry, reset the port.
* If it is reboot case, issue an immediate
* reset.
*/
" cause a reset to trigger cleanup for "
}
}
/* Clean up is done */
break;
}
/*
* Release the lock so that reply for DEL_SHARE
* messages come and get processed, that is, shares
* get freed.
* This delay is also needed for the port reset to
* release the Hybrid resource.
*/
max_retries--;
/* By now, all shares should be freed */
}
}
hiop->vh_num_shares = 0;
}
/*
* vsw_hio_start_ports -- Start HybridIO for ports that have
* already established connection before HybridIO is intialized.
*/
void
{
return;
}
continue;
}
}
/* Cause a rest to trigger HybridIO setup */
}
}
}
/*
* vsw_hio_start -- Start HybridIO for a guest(given LDC)
*/
void
{
int rv;
return;
}
/* Verify if a share was already allocated */
return;
}
return;
}
if (rv != 0) {
/*
* Failed to send a DDS message, so cleanup now.
*/
return;
}
/* DERR only to print by default */
}
/*
*/
void
{
return;
}
}
/*
* vsw_hio_send_delshare_msg -- Send a DEL_SHARE message to the guest.
*/
static int
{
int rv;
return (0);
}
return (0);
}
if (rv == 0) {
}
return (rv);
}
/*
* vsw_send_dds_msg -- Send a DDS message.
*/
static int
{
int rv;
return (rv);
}
/*
* vsw_process_dds_msg -- Process a DDS message received from a guest.
*/
void
{
/* discard */
return;
}
/*
* We expect to receive DDS messages only from guests that
* have HybridIO started.
*/
return;
}
switch (dmsg->dds_subclass) {
case DDS_VNET_ADD_SHARE:
/* A response for ADD_SHARE message. */
break;
}
" message req_id=0x%X share's req_id=0x%X",
break;
}
/* cleanup for NACK */
} else {
}
break;
case DDS_VNET_DEL_SHARE:
/* A response for DEL_SHARE message */
break;
}
" message share req_id=0x%X share's req_id=0x%X",
break;
}
__func__);
}
/* There is nothing we can do, free share now */
break;
case DDS_VNET_REL_SHARE:
/* Guest has released Share voluntarily, so free it now */
/* send ACK */
break;
default:
break;
}
}
/*
* vsw_send_dds_resp_msg -- Send a DDS response message.
*/
static int
{
int rv;
} else {
}
return (rv);
}
/*
* vsw_hio_port_update -- update Hybrid mode change for a port.
*/
void
{
/* Verify if the mode really changed */
return;
}
if (hio_enabled == B_FALSE) {
/* Hybrid Mode is disabled, so stop HybridIO */
} else {
/* reset the port to initiate HybridIO setup */
}
}
/*
* vsw_hio_stop_port -- Stop HybridIO for a given port. Sequence
* followed is similar to vsw_hio_free_all_shares().
*
*/
void
{
return;
}
return;
}
do {
int rv;
/* send DDS_DEL_SHARE */
if (rv != 0) {
/*
* Cause a port reset to trigger
* cleanup.
*/
}
}
if (max_retries == 1) {
/* last retry */
" cause a reset to trigger cleanup for "
}
/* Check if the share still assigned to this port */
break;
}
/*
* Release the lock so that reply for DEL_SHARE
* messages come and get processed, that is, shares
* get freed.
*/
/* Check if the share still assigned to this port */
break;
}
max_retries--;
}
/*
* vsw_hio_rest_all -- Resets all ports that have shares allocated.
* It is called only in the panic code path, so the LDC channels
* are reset immediately.
*/
static void
{
int i;
return;
for (i = 0; i < hiop->vh_num_shares; i++) {
continue;
}
/*
* Reset the port with immediate flag enabled,
* to cause LDC reset immediately.
*/
}
}
/*
* vsw_hio_reboot_callb -- Called for reboot event. It tries to
* free all currently allocated shares.
*/
/* ARGSUSED */
static boolean_t
{
return (B_TRUE);
}
/*
* vsw_hio_panic_callb -- Called from panic event. It resets all
* the ports that have shares allocated. This is done to
* trigger the cleanup in the guest ahead of HV reset.
*/
/* ARGSUSED */
static boolean_t
{
return (B_TRUE);
}
/*
* Setup kstats for hio statistics.
*/
static kstat_t *
{
char share_assigned_info[MAXNAMELEN];
int i;
/*
* vsw_hio_stats_t structure is variable size structure
* having fields defined only for one share. So, we need
* allocate additional space for the rest of the shares.
*/
return (NULL);
}
for (i = 0; i < hiop->vh_num_shares; i++) {
"hio_share_", i, "_state");
}
return (ksp);
}
/*
* Destroy hio kstats.
*/
static void
{
}
}
/*
* Update hio kstats.
*/
static int
{
int i;
if (rw == KSTAT_READ) {
if (vswp->hio_capable) {
} else {
/* not hio capable, just return */
return (0);
}
for (i = 0; i < hiop->vh_num_shares; i++) {
}
} else {
return (EACCES);
}
return (0);
}