io_heci.c revision 617e2443dfc17fe44fd44c0675d6aad2ffc9df42
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Part of Intel(R) Manageability Engine Interface Linux driver
*
* Copyright (c) 2003 - 2008 Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions, and the following disclaimer,
* without modification.
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
* substantially similar to the "NO WARRANTY" disclaimer below
* ("Disclaimer") and any redistribution must be conditioned upon
* including a substantially similar Disclaimer requirement for further
* binary redistribution.
* 3. Neither the names of the above-listed copyright holders nor the names
* of any contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*
* NO WARRANTY
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGES.
*
*/
#include <sys/ddi_impldefs.h>
#include <sys/instance.h>
#include "heci_data_structures.h"
#include "heci.h"
#include "heci_interface.h"
#include "version.h"
struct heci_file_private *fe2);
/*
* heci_ioctl_get_version - the get driver version IOCTL function
*
* @dev: Device object for our driver
* @if_num: minor number
* @*u_msg: pointer to user data struct in user space
* @k_msg: data in kernel on the stack
* @file_ext: private data of the file object
*
* @return 0 on success, <0 on failure.
*/
int
struct heci_message_data *u_msg,
struct heci_message_data k_msg,
{
int rets = 0;
struct heci_driver_version *version;
struct heci_message_data res_msg;
(!file_ext))
return (-ENODEV);
DBG("user buffer less than heci_driver_version.\n");
return (-EMSGSIZE);
}
KM_SLEEP);
DBG("failed allocation response buffer size = %d.\n",
(int)sizeof (struct heci_driver_version));
return (-ENOMEM);
}
/* now copy the data to user space */
goto end;
}
goto end;
}
end:
return (rets);
}
/*
* heci_ioctl_connect_client - the connect to fw client IOCTL function
*
* @dev: Device object for our driver
* @if_num: minor number
* @*u_msg: pointer to user data struct in user space
* @k_msg: data in kernel on the stack
* @file_ext: private data of the file object
*
* @return 0 on success, <0 on failure.
*/
int
struct heci_message_data *u_msg,
struct heci_message_data k_msg,
{
int rets = 0;
struct heci_client *client;
struct heci_file_private *file_ext;
uint8_t i;
int err = 0;
return (-ENODEV);
if (!file_ext)
return (-ENODEV);
DBG("user buffer size is not equal to size of struct "
"guid(16).\n");
return (-EMSGSIZE);
}
return (-EIO);
DBG("failed allocation response buffer size = %d.\n",
(int)sizeof (struct heci_client));
return (-ENOMEM);
}
DBG("failed allocation request buffer size = %d.\n",
(int)sizeof (struct guid));
goto fail;
}
fail:
return (-ENOMEM);
}
/*
* copy the message to kernel space -
* use a pointer already copied into kernel space
*/
goto end;
}
/* buffered ioctl cb */
if (!priv_cb) {
goto end;
}
goto end;
}
goto end;
}
/* find ME client we're trying to connect to */
for (i = 0; i < dev->num_heci_me_clients; i++) {
DBG("guid:%x, me_client_id:%d\n",
sizeof (struct guid)) == 0) {
}
break;
}
}
/*
* if we're connecting to PTHI client so we will use the exist
* connection
*/
sizeof (struct guid)) == 0) {
goto end;
}
struct heci_file_private) {
DBG("remove file private data node host"
" client = %d, ME client = %d.\n",
}
}
DBG("free file private data memory.\n");
/* now copy the data to user space */
goto end;
}
goto end;
}
goto end;
}
goto end;
}
/* prepare the output buffer */
if (dev->host_buffer_is_empty &&
dev->host_buffer_is_empty = 0;
goto end;
} else {
cb_list);
}
} else {
DBG("add connect cb to control write list.\n");
}
err = 0;
tm = ddi_get_lbolt();
}
DBG("successfully connected to FW client."
" me_client_id:%d, host_client_id:%d\n",
/* now copy the data to user space */
goto end;
}
goto end;
}
goto end;
} else {
DBG("failed to connect to FW client.file_ext->state = %d,"
" me_client_id:%d, host_client_id:%d\n",
if (!err) {
DBG("wait_event_interruptible_timeout failed on client"
" connect message fw response message.\n");
}
goto remove_list;
}
if (priv_cb) {
}
end:
DBG("free connect cb memory.");
if (priv_cb) {
}
return (rets);
}
/*
* heci_ioctl_wd - the wd IOCTL function
*
* @dev: Device object for our driver
* @if_num: minor number
* @k_msg: data in kernel on the stack
* @file_ext: private data of the file object
*
* @return 0 on success, <0 on failure.
*/
int
struct heci_message_data k_msg,
{
int rets = 0;
if (if_num < HECI_MINOR_NUMBER)
return (-ENODEV);
DBG("user buffer has invalid size.\n");
return (-EMSGSIZE);
}
DBG("failed allocation request buffer size = %d.\n",
return (-ENOMEM);
}
/*
* copy the message to kernel space - use a pointer already
* copied into kernel space
*/
goto end;
}
goto end;
}
goto end;
}
goto end;
}
dev->wd_pending = 0;
if (dev->wd_timeout == 0) {
} else {
}
end:
return (rets);
}
/*
* heci_ioctl_bypass_wd - the bypass_wd IOCTL function
*
* @dev: Device object for our driver
* @if_num: minor number
* @k_msg: data in kernel on the stack
* @file_ext: private data of the file object
*
* @return 0 on success, <0 on failure.
*/
int
struct heci_message_data k_msg,
{
int rets = 0;
if (if_num < HECI_MINOR_NUMBER)
return (-ENODEV);
DBG("user buffer less than HECI_WATCHDOG_DATA_SIZE.\n");
return (-EMSGSIZE);
}
goto end;
}
end:
return (rets);
}
/*
* find_pthi_read_list_entry - finds a PTHIlist entry for current file
*
* @dev: Device object for our driver
* @file: pointer to file object
*
* @return returned a list entry on success, NULL on failure.
*/
struct heci_cb_private *
struct iamt_heci_device *dev,
{
struct heci_file_private *file_ext_temp;
struct heci_cb_private) {
file_ext_temp = (struct heci_file_private *)
if ((file_ext_temp != NULL) &&
return (priv_cb_pos);
}
}
return (NULL);
}
/*
* pthi_read - read data from pthi client
*
* @dev: Device object for our driver
* @if_num: minor number
* @file: pointer to file object
* @*ubuf: pointer to user data in user space
* @length: data length to read
* @offset: data read offset
*
* @return
* returned data length on success,
* zero if no data to read,
* negative on failure.
*/
int
{
int rets = 0;
uint8_t i;
unsigned long currtime = ddi_get_time();
return (-ENODEV);
return (-ENODEV);
for (i = 0; i < dev->num_heci_me_clients; i++) {
break;
}
if ((i == dev->num_heci_me_clients) ||
DBG("PTHI client not found.\n");
return (-ENODEV);
}
if (!priv_cb) {
return (0); /* No more data to read */
} else {
if (priv_cb &&
/* 15 sec for the message has expired */
goto free;
}
/* if the whole message will fit remove it from the list */
(UIO_LENGTH(uio_p) >=
} else if ((priv_cb->information > 0) &&
/* end of the message has been reached */
rets = 0;
goto free;
}
/*
* else means that not full buffer will be read and do not
* remove message from deletion list
*/
}
DBG("pthi priv_cb->response_buffer size - %d\n",
DBG("pthi priv_cb->information - %lu\n",
free:
DBG("free pthi cb memory.\n");
return (rets);
}
/*
* heci_start_read - the start read client message function.
*
* @dev: Device object for our driver
* @if_num: minor number
* @file_ext: private data of the file object
*
* @return 0 on success, <0 on failure.
*/
int
struct heci_file_private *file_ext)
{
int rets = 0;
uint8_t i;
DBG("received wrong function input param.\n");
return (-ENODEV);
}
return (-ENODEV);
return (-ENODEV);
}
DBG("check if read is pending.\n");
DBG("read is pending.\n");
return (-EBUSY);
}
if (!priv_cb)
return (-ENOMEM);
DBG("allocation call back success\n"
"host client = %d, ME client = %d\n",
for (i = 0; i < dev->num_heci_me_clients; i++) {
break;
}
if (i == dev->num_heci_me_clients) {
goto unlock;
}
goto fail;
}
DBG("allocation call back data success.\n");
/* make sure information is zero before we start */
priv_cb->information = 0;
if (dev->host_buffer_is_empty) {
dev->host_buffer_is_empty = 0;
goto unlock;
} else {
}
} else {
}
return (rets);
fail:
return (rets);
}
/*
* pthi_write: write iamthif data to pthi client
*
* @dev: Device object for our driver
* @priv_cb: heci call back struct
*
* @return 0 on success, <0 on failure.
*/
int
struct heci_cb_private *priv_cb)
{
int rets = 0;
struct heci_msg_hdr heci_hdr;
return (-ENODEV);
DBG("write data to pthi client.\n");
dev->iamthif_canceled = 0;
dev->host_buffer_is_empty = 0;
sizeof (uint32_t)) - sizeof (struct heci_msg_hdr)) {
sizeof (uint32_t)) - sizeof (struct heci_msg_hdr);
heci_hdr.msg_complete = 0;
} else {
}
(unsigned char *)(dev->iamthif_msg_buf),
return (-ENODEV);
if (heci_hdr.msg_complete) {
DBG("add pthi cb to write waiting list\n");
} else {
DBG("message does not complete, "
"so add pthi cb to write list.\n");
}
} else {
if (!(dev->host_buffer_is_empty))
DBG("host buffer is not empty");
DBG("No flow control credentials, "
"so add iamthif cb to write list.\n");
}
return (rets);
}
/*
* iamthif_ioctl_send_msg - send cmd data to pthi client
*
* @dev: Device object for our driver
*
* @return 0 on success, <0 on failure.
*/
void
{
struct heci_file_private *file_ext_tmp;
int status = 0;
if (!dev)
return;
dev->iamthif_msg_buf_size = 0;
dev->iamthif_msg_buf_index = 0;
dev->iamthif_canceled = 0;
dev->iamthif_timer = 0;
DBG("complete pthi cmd_list cb.\n");
struct heci_cb_private) {
file_ext_tmp = (struct heci_file_private *)
if ((file_ext_tmp != NULL) &&
if (status != 0) {
DBG("pthi write failed status = %d\n",
status);
return;
}
break;
}
}
}
}
/*
* heci_free_cb_private - free heci_cb_private related memory
*
* @priv_cb: heci callback struct
*/
void
{
return;
}
/*
* heci_fe_same_id - tell if file private data have same id
*
* @fe1: private data of 1. file object
* @fe2: private data of 2. file object
*
* @return !=0 - if ids are the same, 0 - if differ.
*/
struct heci_file_private *fe2)
{
}