[openib-general] [PATCH 4/10] Implementation of Control path of the communication protocol
Ramachandra K
rkuchimanchi at silverstorm.com
Mon Oct 2 13:06:02 PDT 2006
Adds the files that implement the various control messages that are exchanged
as part of the communication protocol with the VEx.
Signed-off-by: Ramachandra K <rkuchimanchi at silverstorm.com>
---
drivers/infiniband/ulp/vnic/vnic_control.c | 1875 ++++++++++++++++++++++++
drivers/infiniband/ulp/vnic/vnic_control.h | 145 ++
drivers/infiniband/ulp/vnic/vnic_control_pkt.h | 278 ++++
3 files changed, 2298 insertions(+), 0 deletions(-)
diff --git a/drivers/infiniband/ulp/vnic/vnic_control.c b/drivers/infiniband/ulp/vnic/vnic_control.c
new file mode 100644
index 0000000..9e71bc7
--- /dev/null
+++ b/drivers/infiniband/ulp/vnic/vnic_control.c
@@ -0,0 +1,1875 @@
+/*
+ * Copyright (c) 2006 SilverStorm Technologies Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/netdevice.h>
+#include <linux/list.h>
+
+#include "vnic_util.h"
+#include "vnic_main.h"
+#include "vnic_viport.h"
+#include "vnic_control.h"
+#include "vnic_config.h"
+#include "vnic_control_pkt.h"
+
+static void control_log_control_packet(struct vnic_control_packet *pkt);
+
+static inline char *control_ifcfg_name(struct control *control)
+{
+ if (!control)
+ return "nctl";
+ if (!control->parent)
+ return "np";
+ if (!control->parent->parent)
+ return "npp";
+ if (!control->parent->parent->parent)
+ return "nppp";
+ if (!control->parent->parent->parent->config)
+ return "npppc";
+ return (control->parent->parent->parent->config->name);
+}
+
+static void control_recv(struct control *control, struct recv_io *recv_io)
+{
+ if (!vnic_ib_post_recv(&control->ib_conn, &recv_io->io)) {
+ viport_failure(control->parent);
+ }
+ return;
+}
+
+static void control_recv_complete(struct io *io)
+{
+ struct recv_io *recv_io = (struct recv_io *)io;
+ struct recv_io *last_recv_io;
+ struct control *control = &io->viport->control;
+ struct vnic_control_packet *pkt = control_packet(recv_io);
+ struct vnic_control_header *c_hdr = &pkt->hdr;
+ unsigned long flags;
+
+#ifdef CONFIG_INFINIBAND_VNIC_STATS
+ cycles_t response_time;
+#endif /* CONFIG_INFINIBAND_VNIC_STATS */
+
+ CONTROL_FUNCTION("%s: control_recv_complete()\n",
+ control_ifcfg_name(control));
+
+ dma_sync_single_for_cpu(control->parent->config->ibdev->dma_device,
+ control->recv_dma, control->recv_len,
+ DMA_FROM_DEVICE);
+
+#ifdef CONFIG_INFINIBAND_VNIC_STATS
+ response_time = get_cycles();
+#endif /* CONFIG_INFINIBAND_VNIC_STATS */
+
+ CONTROL_PACKET(pkt);
+ spin_lock_irqsave(&control->io_lock, flags);
+ if (c_hdr->pkt_type == TYPE_INFO) {
+ last_recv_io = control->info;
+ control->info = recv_io;
+ spin_unlock_irqrestore(&control->io_lock, flags);
+ viport_kick(control->parent);
+ if (last_recv_io)
+ control_recv(control, last_recv_io);
+ } else if (c_hdr->pkt_type == TYPE_RSP) {
+ if (control->rsp_expected
+ && (c_hdr->pkt_seq_num == control->seq_num)) {
+ control->response = recv_io;
+ control->rsp_expected = FALSE;
+ spin_unlock_irqrestore(&control->io_lock, flags);
+#ifdef CONFIG_INFINIBAND_VNIC_STATS
+ response_time -= control->statistics.request_time;
+ control->statistics.response_time += response_time;
+ control->statistics.response_num++;
+ if (control->statistics.response_max < response_time)
+ control->statistics.response_max =
+ response_time;
+ if ((control->statistics.response_min == 0)
+ || (control->statistics.response_min >
+ response_time))
+ control->statistics.response_min =
+ response_time;
+#endif /* CONFIG_INFINIBAND_VNIC_STATS */
+ viport_kick(control->parent);
+ } else {
+ spin_unlock_irqrestore(&control->io_lock, flags);
+ control_recv(control, recv_io);
+ }
+ } else {
+ list_add_tail(&recv_io->io.list_ptrs, &control->failure_list);
+ spin_unlock_irqrestore(&control->io_lock, flags);
+ viport_kick(control->parent);
+ }
+ dma_sync_single_for_device(control->parent->config->ibdev->dma_device,
+ control->recv_dma, control->recv_len,
+ DMA_FROM_DEVICE);
+
+ return;
+}
+
+static void control_timeout(unsigned long data)
+{
+ struct control *control;
+
+ control = (struct control *)PTR(data);
+ CONTROL_FUNCTION("%s: control_timeout()\n",
+ control_ifcfg_name(control));
+ control->timer_state = TIMER_EXPIRED;
+ control->rsp_expected = FALSE;
+ viport_kick(control->parent);
+ return;
+}
+
+static void control_timer(struct control *control, int timeout)
+{
+ CONTROL_FUNCTION("%s: control_timer()\n",
+ control_ifcfg_name(control));
+ if (control->timer_state == TIMER_ACTIVE) {
+ mod_timer(&control->timer, jiffies + timeout);
+ } else {
+ init_timer(&control->timer);
+ control->timer.expires = jiffies + timeout;
+ control->timer.data = (unsigned long)control;
+ control->timer.function = control_timeout;
+ control->timer_state = TIMER_ACTIVE;
+ add_timer(&control->timer);
+ }
+ return;
+}
+
+static void control_timer_stop(struct control *control)
+{
+ CONTROL_FUNCTION("%s: control_timer_stop()\n",
+ control_ifcfg_name(control));
+ if (control->timer_state == TIMER_ACTIVE) {
+ del_timer_sync(&control->timer);
+ }
+ control->timer_state = TIMER_IDLE;
+ return;
+}
+
+static BOOLEAN control_send(struct control *control, struct send_io *send_io)
+{
+ CONTROL_FUNCTION("%s: control_send()\n", control_ifcfg_name(control));
+ if (control->req_outstanding) {
+ CONTROL_ERROR("%s: IB send never completed\n",
+ control_ifcfg_name(control));
+ viport_failure(control->parent);
+ return FALSE;
+ }
+ control->req_outstanding = TRUE;
+
+ control_timer(control, control->config->rsp_timeout);
+
+#ifdef CONFIG_INFINIBAND_VNIC_STATS
+ control->statistics.request_time = get_cycles();
+#endif /* CONFIG_INFINIBAND_VNIC_STATS */
+
+ if (!vnic_ib_post_send(&control->ib_conn, &control->send_io.io)) {
+ CONTROL_ERROR("failed to post send\n");
+ viport_failure(control->parent);
+ control->req_outstanding = FALSE;
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static void control_send_complete(struct io *io)
+{
+ struct control *control = &io->viport->control;
+
+ CONTROL_FUNCTION("%s: control_send_complete()\n",
+ control_ifcfg_name(control));
+ control->req_outstanding = FALSE;
+
+ return;
+}
+
+void control_process_async(struct control *control)
+{
+ struct recv_io *recv_io;
+ struct vnic_control_packet *pkt;
+ unsigned long flags;
+
+ CONTROL_FUNCTION("%s: control_process_async()\n",
+ control_ifcfg_name(control));
+ dma_sync_single_for_cpu(control->parent->config->ibdev->dma_device,
+ control->recv_dma, control->recv_len,
+ DMA_FROM_DEVICE);
+
+ spin_lock_irqsave(&control->io_lock, flags);
+ if ((recv_io = control->info) != NULL) {
+ CONTROL_INFO("%s: processing info packet\n",
+ control_ifcfg_name(control));
+ control->info = NULL;
+ spin_unlock_irqrestore(&control->io_lock, flags);
+ pkt = control_packet(recv_io);
+ if (ntoh8(pkt->hdr.pkt_cmd) == CMD_REPORT_STATUS) {
+ switch (ntoh32(pkt->cmd.report_status.status_number)) {
+ case VNIC_STATUS_LINK_UP:
+ CONTROL_INFO("%s: link up\n",
+ control_ifcfg_name(control));
+ viport_link_up(control->parent);
+ break;
+ case VNIC_STATUS_LINK_DOWN:
+ CONTROL_INFO("%s: link down\n",
+ control_ifcfg_name(control));
+ viport_link_down(control->parent);
+ break;
+ default:
+ CONTROL_ERROR("%s: asynchronous status"
+ " received from EIOC\n",
+ control_ifcfg_name(control));
+ control_log_control_packet(pkt);
+ break;
+ }
+ }
+ if ((ntoh8(pkt->hdr.pkt_cmd) != CMD_REPORT_STATUS)
+ || ntoh8(pkt->cmd.report_status.is_fatal)) {
+ viport_failure(control->parent);
+ }
+ control_recv(control, recv_io);
+ spin_lock_irqsave(&control->io_lock, flags);
+ }
+
+ while (!list_empty(&control->failure_list)) {
+ CONTROL_INFO("%s: processing error packet\n",
+ control_ifcfg_name(control));
+ recv_io = (struct recv_io *)
+ list_entry(control->failure_list.next, struct io,
+ list_ptrs);
+ list_del(&recv_io->io.list_ptrs);
+ spin_unlock_irqrestore(&control->io_lock, flags);
+ pkt = control_packet(recv_io);
+ CONTROL_ERROR("%s: asynchronous error received from EIOC\n",
+ control_ifcfg_name(control));
+ control_log_control_packet(pkt);
+ if ((ntoh8(pkt->hdr.pkt_type) != TYPE_ERR)
+ || (ntoh8(pkt->hdr.pkt_cmd) != CMD_REPORT_STATUS)
+ || ntoh8(pkt->cmd.report_status.is_fatal)) {
+ viport_failure(control->parent);
+ }
+ control_recv(control, recv_io);
+ spin_lock_irqsave(&control->io_lock, flags);
+ }
+ spin_unlock_irqrestore(&control->io_lock, flags);
+ dma_sync_single_for_device(control->parent->config->ibdev->dma_device,
+ control->recv_dma, control->recv_len,
+ DMA_FROM_DEVICE);
+
+ CONTROL_INFO("%s: done control_process_async\n",
+ control_ifcfg_name(control));
+}
+
+static struct send_io *control_init_hdr(struct control *control, u8 cmd)
+{
+ struct control_config *config;
+ struct vnic_control_packet *pkt;
+ struct vnic_control_header *hdr;
+
+ CONTROL_FUNCTION("control_init_hdr()\n");
+ config = control->config;
+
+ pkt = control_packet(&control->send_io);
+ hdr = &pkt->hdr;
+
+ hdr->pkt_type = hton8(TYPE_REQ);
+ hdr->pkt_cmd = hton8(cmd);
+ control->seq_num++;
+ hdr->pkt_seq_num = hton8(control->seq_num);
+ control->req_retry_counter = 0;
+ hdr->pkt_retry_count = hton8(control->req_retry_counter);
+
+ return &control->send_io;
+}
+
+static struct recv_io *control_get_rsp(struct control *control)
+{
+ struct recv_io *recv_io;
+ unsigned long flags;
+
+ CONTROL_FUNCTION("%s: control_get_rsp()\n",
+ control_ifcfg_name(control));
+ spin_lock_irqsave(&control->io_lock, flags);
+ if ((recv_io = control->response) != NULL) {
+ control_timer_stop(control);
+ control->response = NULL;
+ spin_unlock_irqrestore(&control->io_lock, flags);
+ return recv_io;
+ }
+ spin_unlock_irqrestore(&control->io_lock, flags);
+ if (control->timer_state == TIMER_EXPIRED) {
+ struct vnic_control_packet *pkt =
+ control_packet(&control->send_io);
+ struct vnic_control_header *hdr = &pkt->hdr;
+
+ control->timer_state = TIMER_IDLE;
+ CONTROL_ERROR("%s: no response received from EIOC\n",
+ control_ifcfg_name(control));
+#ifdef CONFIG_INFINIBAND_VNIC_STATS
+ control->statistics.timeout_num++;
+#endif /* CONFIG_INFINIBAND_VNIC_STATS */
+ control->req_retry_counter++;
+ if (control->req_retry_counter >=
+ control->config->req_retry_count) {
+ CONTROL_ERROR("%s: control packet retry exceeded\n",
+ control_ifcfg_name(control));
+ viport_failure(control->parent);
+ } else {
+ hdr->pkt_retry_count =
+ hton8(control->req_retry_counter);
+ control_send(control, &control->send_io);
+ }
+ }
+ return NULL;
+}
+
+BOOLEAN control_init_vnic_req(struct control *control)
+{
+ struct send_io *send_io;
+ struct control_config *config = control->config;
+ struct vnic_control_packet *pkt;
+ struct vnic_cmd_init_vnic_req *init_vnic_req;
+
+ dma_sync_single_for_cpu(control->parent->config->ibdev->dma_device,
+ control->send_dma, control->send_len,
+ DMA_TO_DEVICE);
+
+ send_io = control_init_hdr(control, CMD_INIT_VNIC);
+ if (!send_io) {
+ dma_sync_single_for_device(control->parent->config->ibdev->
+ dma_device, control->send_dma,
+ control->send_len, DMA_TO_DEVICE);
+ return FALSE;
+ }
+
+ pkt = control_packet(send_io);
+ init_vnic_req = &pkt->cmd.init_vnic_req;
+ init_vnic_req->vnic_major_version = hton16(VNIC_MAJORVERSION);
+ init_vnic_req->vnic_minor_version = hton16(VNIC_MINORVERSION);
+ init_vnic_req->vnic_instance = hton8(config->vnic_instance);
+ init_vnic_req->num_data_paths = 1;
+ init_vnic_req->num_address_entries =
+ hton16(config->max_address_entries);
+
+ CONTROL_PACKET(pkt);
+
+ control->rsp_expected = pkt->hdr.pkt_cmd;
+
+ dma_sync_single_for_device(control->parent->config->ibdev->dma_device,
+ control->send_dma, control->send_len,
+ DMA_TO_DEVICE);
+
+ return control_send(control, send_io);
+}
+
+BOOLEAN control_init_vnic_rsp(struct control * control, u32 * features,
+ u8 * mac_address, u16 * num_addrs, u16 * vlan)
+{
+ struct recv_io *recv_io;
+ struct control_config *config = control->config;
+ struct vnic_control_packet *pkt;
+ struct vnic_cmd_init_vnic_rsp *init_vnic_rsp;
+ u8 num_data_paths, num_lan_switches;
+
+ CONTROL_FUNCTION("%s: control_init_vnic_rsp()\n",
+ control_ifcfg_name(control));
+ dma_sync_single_for_cpu(control->parent->config->ibdev->dma_device,
+ control->recv_dma, control->recv_len,
+ DMA_FROM_DEVICE);
+
+ recv_io = control_get_rsp(control);
+ if (!recv_io)
+ return FALSE;
+
+ pkt = control_packet(recv_io);
+ if (pkt->hdr.pkt_cmd != CMD_INIT_VNIC) {
+ CONTROL_ERROR("%s: sent control request:\n",
+ control_ifcfg_name(control));
+ control_log_control_packet(control_last_req(control));
+ CONTROL_ERROR("%s: received control response:\n",
+ control_ifcfg_name(control));
+ control_log_control_packet(pkt);
+ goto failure;
+ }
+ init_vnic_rsp = &pkt->cmd.init_vnic_rsp;
+ control->maj_ver = ntoh16(init_vnic_rsp->vnic_major_version);
+ control->min_ver = ntoh16(init_vnic_rsp->vnic_minor_version);
+ num_data_paths = ntoh8(init_vnic_rsp->num_data_paths);
+ num_lan_switches = ntoh8(init_vnic_rsp->num_lan_switches);
+ *features = ntoh32(init_vnic_rsp->features_supported);
+ *num_addrs = ntoh16(init_vnic_rsp->num_address_entries);
+
+ if ((control->maj_ver > VNIC_MAJORVERSION)
+ || ((control->maj_ver == VNIC_MAJORVERSION)
+ && (control->min_ver > VNIC_MINORVERSION))) {
+ CONTROL_ERROR("%s: unsupported version\n",
+ control_ifcfg_name(control));
+ goto failure;
+ }
+ if (num_data_paths != 1) {
+ CONTROL_ERROR("%s: EIOC returned too many datapaths\n",
+ control_ifcfg_name(control));
+ goto failure;
+ }
+ if (*num_addrs > config->max_address_entries) {
+ CONTROL_ERROR
+ ("%s: EIOC returned more address entries than requested\n",
+ control_ifcfg_name(control));
+ goto failure;
+ }
+ if (*num_addrs < config->min_address_entries) {
+ CONTROL_ERROR("%s: not enough address entries\n",
+ control_ifcfg_name(control));
+ goto failure;
+ }
+ if (num_lan_switches < 1) {
+ CONTROL_ERROR("%s: EIOC returned no lan switches\n",
+ control_ifcfg_name(control));
+ goto failure;
+ }
+ if (num_lan_switches > 1) {
+ CONTROL_ERROR("%s: EIOC returned multiple lan switches\n",
+ control_ifcfg_name(control));
+ goto failure;
+ }
+
+ control->lan_switch.lan_switch_num =
+ ntoh8(init_vnic_rsp->lan_switch[0].lan_switch_num);
+ control->lan_switch.num_enet_ports =
+ ntoh8(init_vnic_rsp->lan_switch[0].num_enet_ports);
+ control->lan_switch.default_vlan =
+ ntoh16(init_vnic_rsp->lan_switch[0].default_vlan);
+ *vlan = control->lan_switch.default_vlan;
+ memcpy(control->lan_switch.hw_mac_address,
+ init_vnic_rsp->lan_switch[0].hw_mac_address, MAC_ADDR_LEN);
+ memcpy(mac_address, init_vnic_rsp->lan_switch[0].hw_mac_address,
+ MAC_ADDR_LEN);
+
+ control_recv(control, recv_io);
+ dma_sync_single_for_device(control->parent->config->ibdev->dma_device,
+ control->recv_dma, control->recv_len,
+ DMA_FROM_DEVICE);
+
+ return TRUE;
+failure:
+ viport_failure(control->parent);
+ dma_sync_single_for_device(control->parent->config->ibdev->dma_device,
+ control->recv_dma, control->recv_len,
+ DMA_FROM_DEVICE);
+ return FALSE;
+}
+
+static void copy_recv_pool_config(struct vnic_recv_pool_config *src,
+ struct vnic_recv_pool_config *dst)
+{
+ dst->size_recv_pool_entry = hton32(src->size_recv_pool_entry);
+ dst->num_recv_pool_entries = hton32(src->num_recv_pool_entries);
+ dst->timeout_before_kick = hton32(src->timeout_before_kick);
+ dst->num_recv_pool_entries_before_kick =
+ hton32(src->num_recv_pool_entries_before_kick);
+ dst->num_recv_pool_bytes_before_kick =
+ hton32(src->num_recv_pool_bytes_before_kick);
+ dst->free_recv_pool_entries_per_update =
+ hton32(src->free_recv_pool_entries_per_update);
+ return;
+}
+
+static BOOLEAN check_recv_pool_config_value(u32 *src, u32 *dst,
+ u32 *max, u32 *min, char *name)
+{
+ u32 value;
+
+ value = ntoh32(*src);
+ if (value > *max) {
+ CONTROL_ERROR("value %s too large\n", name);
+ return FALSE;
+ } else if (value < *min) {
+ CONTROL_ERROR("value %s too small\n", name);
+ return FALSE;
+ }
+ *dst = value;
+ return TRUE;
+}
+
+static BOOLEAN check_recv_pool_config(struct vnic_recv_pool_config *src,
+ struct vnic_recv_pool_config *dst,
+ struct vnic_recv_pool_config *max,
+ struct vnic_recv_pool_config *min)
+{
+ if (!check_recv_pool_config_value
+ (&src->size_recv_pool_entry, &dst->size_recv_pool_entry,
+ &max->size_recv_pool_entry, &min->size_recv_pool_entry,
+ "size_recv_pool_entry")
+ || !check_recv_pool_config_value(&src->num_recv_pool_entries,
+ &dst->num_recv_pool_entries,
+ &max->num_recv_pool_entries,
+ &min->num_recv_pool_entries,
+ "num_recv_pool_entries")
+ || !check_recv_pool_config_value(&src->timeout_before_kick,
+ &dst->timeout_before_kick,
+ &max->timeout_before_kick,
+ &min->timeout_before_kick,
+ "timeout_before_kick")
+ || !check_recv_pool_config_value(&src->
+ num_recv_pool_entries_before_kick,
+ &dst->
+ num_recv_pool_entries_before_kick,
+ &max->
+ num_recv_pool_entries_before_kick,
+ &min->
+ num_recv_pool_entries_before_kick,
+ "num_recv_pool_entries_before_kick")
+ || !check_recv_pool_config_value(&src->
+ num_recv_pool_bytes_before_kick,
+ &dst->
+ num_recv_pool_bytes_before_kick,
+ &max->
+ num_recv_pool_bytes_before_kick,
+ &min->
+ num_recv_pool_bytes_before_kick,
+ "num_recv_pool_bytes_before_kick")
+ || !check_recv_pool_config_value(&src->
+ free_recv_pool_entries_per_update,
+ &dst->
+ free_recv_pool_entries_per_update,
+ &max->
+ free_recv_pool_entries_per_update,
+ &min->
+ free_recv_pool_entries_per_update,
+ "free_recv_pool_entries_per_update"))
+ return FALSE;
+
+ if (!is_power_of2(dst->num_recv_pool_entries)) {
+ CONTROL_ERROR("num_recv_pool_entries (%d)"
+ " must be power of 2\n",
+ dst->num_recv_pool_entries);
+ return FALSE;
+ }
+ if (!is_power_of2(dst->free_recv_pool_entries_per_update)) {
+ CONTROL_ERROR("free_recv_pool_entries_per_update (%d)"
+ " must be power of 2\n",
+ dst->free_recv_pool_entries_per_update);
+ return FALSE;
+ }
+ if (dst->free_recv_pool_entries_per_update >=
+ dst->num_recv_pool_entries) {
+ CONTROL_ERROR("free_recv_pool_entries_per_update (%d) must be"
+ " less than num_recv_pool_entries (%d)\n",
+ dst->free_recv_pool_entries_per_update,
+ dst->num_recv_pool_entries);
+ return FALSE;
+ }
+ if (dst->num_recv_pool_entries_before_kick >=
+ dst->num_recv_pool_entries) {
+ CONTROL_ERROR("num_recv_pool_entries_before_kick (%d) must be"
+ " less than num_recv_pool_entries (%d)\n",
+ dst->num_recv_pool_entries_before_kick,
+ dst->num_recv_pool_entries);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+BOOLEAN control_config_data_path_req(struct control * control, u64 path_id,
+ struct vnic_recv_pool_config * host,
+ struct vnic_recv_pool_config * eioc)
+{
+ struct send_io *send_io;
+ struct vnic_control_packet *pkt;
+ struct vnic_cmd_config_data_path *config_data_path;
+
+ CONTROL_FUNCTION("%s: control_config_data_path_req()\n",
+ control_ifcfg_name(control));
+ dma_sync_single_for_cpu(control->parent->config->ibdev->dma_device,
+ control->send_dma, control->send_len,
+ DMA_TO_DEVICE);
+
+ send_io = control_init_hdr(control, CMD_CONFIG_DATA_PATH);
+ if (!send_io)
+ return FALSE;
+
+ pkt = control_packet(send_io);
+ config_data_path = &pkt->cmd.config_data_path_req;
+ config_data_path->data_path = hton8(0);
+ config_data_path->path_identifier = path_id;
+ copy_recv_pool_config(host, &config_data_path->host_recv_pool_config);
+ copy_recv_pool_config(eioc, &config_data_path->eioc_recv_pool_config);
+ CONTROL_PACKET(pkt);
+
+ control->rsp_expected = pkt->hdr.pkt_cmd;
+
+ dma_sync_single_for_device(control->parent->config->ibdev->dma_device,
+ control->send_dma, control->send_len,
+ DMA_TO_DEVICE);
+
+ return control_send(control, send_io);
+}
+
+BOOLEAN control_config_data_path_rsp(struct control * control,
+ struct vnic_recv_pool_config * host,
+ struct vnic_recv_pool_config * eioc,
+ struct vnic_recv_pool_config * max_host,
+ struct vnic_recv_pool_config * max_eioc,
+ struct vnic_recv_pool_config * min_host,
+ struct vnic_recv_pool_config * min_eioc)
+{
+ struct recv_io *recv_io;
+ struct vnic_control_packet *pkt;
+ struct vnic_cmd_config_data_path *config_data_path;
+
+ CONTROL_FUNCTION("%s: control_config_data_path_rsp()\n",
+ control_ifcfg_name(control));
+ dma_sync_single_for_cpu(control->parent->config->ibdev->dma_device,
+ control->recv_dma, control->recv_len,
+ DMA_FROM_DEVICE);
+
+ recv_io = control_get_rsp(control);
+ if (!recv_io)
+ return FALSE;
+
+ pkt = control_packet(recv_io);
+ if (pkt->hdr.pkt_cmd != CMD_CONFIG_DATA_PATH) {
+ CONTROL_ERROR("%s: sent control request:\n",
+ control_ifcfg_name(control));
+ control_log_control_packet(control_last_req(control));
+ CONTROL_ERROR("%s: received control response:\n",
+ control_ifcfg_name(control));
+ control_log_control_packet(pkt);
+ goto failure;
+ }
+ config_data_path = &pkt->cmd.config_data_path_rsp;
+ if (ntoh8(config_data_path->data_path) != 0) {
+ CONTROL_ERROR("%s: received CMD_CONFIG_DATA_PATH response"
+ " for wrong data path: %u\n",
+ control_ifcfg_name(control),
+ config_data_path->data_path);
+ goto failure;
+ }
+ if (!check_recv_pool_config(&config_data_path->host_recv_pool_config,
+ host, max_host, min_host)
+ || !check_recv_pool_config(&config_data_path->eioc_recv_pool_config,
+ eioc, max_eioc, min_eioc)) {
+ goto failure;
+ }
+
+ control_recv(control, recv_io);
+ dma_sync_single_for_device(control->parent->config->ibdev->dma_device,
+ control->recv_dma, control->recv_len,
+ DMA_FROM_DEVICE);
+
+ return TRUE;
+failure:
+ viport_failure(control->parent);
+ dma_sync_single_for_device(control->parent->config->ibdev->dma_device,
+ control->recv_dma, control->recv_len,
+ DMA_FROM_DEVICE);
+
+ return FALSE;
+}
+
+BOOLEAN control_exchange_pools_req(struct control * control, u64 addr, u32 rkey)
+{
+ struct send_io *send_io;
+ struct vnic_cmd_exchange_pools *exchange_pools;
+ struct vnic_control_packet *pkt;
+
+ CONTROL_FUNCTION("%s: control_exchange_pools_req()\n",
+ control_ifcfg_name(control));
+ dma_sync_single_for_cpu(control->parent->config->ibdev->dma_device,
+ control->send_dma, control->send_len,
+ DMA_TO_DEVICE);
+
+ send_io = control_init_hdr(control, CMD_EXCHANGE_POOLS);
+ if (!send_io)
+ return FALSE;
+
+ pkt = control_packet(send_io);
+ exchange_pools = &pkt->cmd.exchange_pools_req;
+ exchange_pools->data_path = hton32(0);
+ exchange_pools->pool_rkey = hton32(rkey);
+ exchange_pools->pool_addr = hton64(addr);
+
+ control->rsp_expected = pkt->hdr.pkt_cmd;
+
+ dma_sync_single_for_device(control->parent->config->ibdev->dma_device,
+ control->send_dma, control->send_len,
+ DMA_TO_DEVICE);
+
+ return control_send(control, send_io);
+}
+
+BOOLEAN control_exchange_pools_rsp(struct control * control, u64 * addr,
+ u32 * rkey)
+{
+ struct recv_io *recv_io;
+ struct vnic_control_packet *pkt;
+ struct vnic_cmd_exchange_pools *exchange_pools;
+
+ CONTROL_FUNCTION("%s: control_exchange_pools_rsp()\n",
+ control_ifcfg_name(control));
+ dma_sync_single_for_cpu(control->parent->config->ibdev->dma_device,
+ control->recv_dma, control->recv_len,
+ DMA_FROM_DEVICE);
+
+ recv_io = control_get_rsp(control);
+ if (!recv_io)
+ return FALSE;
+
+ pkt = control_packet(recv_io);
+ if (pkt->hdr.pkt_cmd != CMD_EXCHANGE_POOLS) {
+ CONTROL_ERROR("%s: sent control request:\n",
+ control_ifcfg_name(control));
+ control_log_control_packet(control_last_req(control));
+ CONTROL_ERROR("%s: received control response:\n",
+ control_ifcfg_name(control));
+ control_log_control_packet(pkt);
+ goto failure;
+ }
+ exchange_pools = &pkt->cmd.exchange_pools_rsp;
+ *rkey = hton32(exchange_pools->pool_rkey);
+ *addr = hton64(exchange_pools->pool_addr);
+ if (hton32(exchange_pools->data_path) != 0) {
+ CONTROL_ERROR("%s: received CMD_EXCHANGE_POOLS response"
+ " for wrong data path: %u\n",
+ control_ifcfg_name(control),
+ exchange_pools->data_path);
+ goto failure;
+ }
+
+ control_recv(control, recv_io);
+ dma_sync_single_for_device(control->parent->config->ibdev->dma_device,
+ control->recv_dma, control->recv_len,
+ DMA_FROM_DEVICE);
+
+ return TRUE;
+failure:
+ viport_failure(control->parent);
+ dma_sync_single_for_device(control->parent->config->ibdev->dma_device,
+ control->recv_dma, control->recv_len,
+ DMA_FROM_DEVICE);
+ return FALSE;
+}
+
+BOOLEAN control_config_link_req(struct control * control, u16 flags, u16 mtu)
+{
+ struct send_io *send_io;
+ struct vnic_cmd_config_link *config_link_req;
+ struct vnic_control_packet *pkt;
+
+ CONTROL_FUNCTION("%s: control_config_link_req()\n",
+ control_ifcfg_name(control));
+ dma_sync_single_for_cpu(control->parent->config->ibdev->dma_device,
+ control->send_dma, control->send_len,
+ DMA_TO_DEVICE);
+
+ send_io = control_init_hdr(control, CMD_CONFIG_LINK);
+ if (!send_io)
+ return FALSE;
+
+ pkt = control_packet(send_io);
+ config_link_req = &pkt->cmd.config_link_req;
+ config_link_req->lan_switch_num =
+ hton8(control->lan_switch.lan_switch_num);
+ config_link_req->cmd_flags = VNIC_FLAG_SET_MTU;
+ if (flags & IFF_UP) {
+ config_link_req->cmd_flags |= VNIC_FLAG_ENABLE_NIC;
+ } else {
+ config_link_req->cmd_flags |= VNIC_FLAG_DISABLE_NIC;
+ }
+ if (flags & IFF_ALLMULTI) {
+ config_link_req->cmd_flags |= VNIC_FLAG_ENABLE_MCAST_ALL;
+ } else {
+ config_link_req->cmd_flags |= VNIC_FLAG_DISABLE_MCAST_ALL;
+ }
+ if (flags & IFF_PROMISC) {
+ config_link_req->cmd_flags |= VNIC_FLAG_ENABLE_PROMISC;
+ /* the EIOU doesn't really do PROMISC mode.
+ * if PROMISC is set, it only receives unicast packets
+ * I also have to set MCAST_ALL if I want real
+ * PROMISC mode.
+ */
+ config_link_req->cmd_flags &= ~VNIC_FLAG_DISABLE_MCAST_ALL;
+ config_link_req->cmd_flags |= VNIC_FLAG_ENABLE_MCAST_ALL;
+ } else {
+ config_link_req->cmd_flags |= VNIC_FLAG_DISABLE_PROMISC;
+ }
+ config_link_req->mtu_size = hton16(mtu);
+
+ control->rsp_expected = pkt->hdr.pkt_cmd;
+ dma_sync_single_for_device(control->parent->config->ibdev->dma_device,
+ control->send_dma, control->send_len,
+ DMA_TO_DEVICE);
+
+ return control_send(control, send_io);
+}
+
+BOOLEAN control_config_link_rsp(struct control * control, u16 * flags,
+ u16 * mtu)
+{
+ struct recv_io *recv_io;
+ struct vnic_control_packet *pkt;
+ struct vnic_cmd_config_link *config_link_rsp;
+
+ CONTROL_FUNCTION("%s: control_config_link_rsp()\n",
+ control_ifcfg_name(control));
+ dma_sync_single_for_cpu(control->parent->config->ibdev->dma_device,
+ control->recv_dma, control->recv_len,
+ DMA_FROM_DEVICE);
+
+ recv_io = control_get_rsp(control);
+ if (!recv_io)
+ return FALSE;
+
+ pkt = control_packet(recv_io);
+ if (pkt->hdr.pkt_cmd != CMD_CONFIG_LINK) {
+ CONTROL_ERROR("%s: sent control request:\n",
+ control_ifcfg_name(control));
+ control_log_control_packet(control_last_req(control));
+ CONTROL_ERROR("%s: received control response:\n",
+ control_ifcfg_name(control));
+ control_log_control_packet(pkt);
+ goto failure;
+ }
+ config_link_rsp = &pkt->cmd.config_link_rsp;
+ if (config_link_rsp->cmd_flags & VNIC_FLAG_ENABLE_NIC) {
+ *flags |= IFF_UP;
+ }
+ if (config_link_rsp->cmd_flags & VNIC_FLAG_ENABLE_MCAST_ALL) {
+ *flags |= IFF_ALLMULTI;
+ }
+ if (config_link_rsp->cmd_flags & VNIC_FLAG_ENABLE_PROMISC) {
+ *flags |= IFF_PROMISC;
+ }
+ *mtu = ntoh16(config_link_rsp->mtu_size);
+
+ control_recv(control, recv_io);
+ dma_sync_single_for_device(control->parent->config->ibdev->dma_device,
+ control->recv_dma, control->recv_len,
+ DMA_FROM_DEVICE);
+
+ return TRUE;
+failure:
+ viport_failure(control->parent);
+ dma_sync_single_for_device(control->parent->config->ibdev->dma_device,
+ control->recv_dma, control->recv_len,
+ DMA_FROM_DEVICE);
+
+ return FALSE;
+}
+
+/* control_config_addrs_req:
+ * return values:
+ * -1: failure
+ * 0: incomplete (successful operation, but more address
+ * table entries to be updated)
+ * 1: complete
+ */
+int control_config_addrs_req(struct control *control,
+ struct vnic_address_op *addrs, u16 num)
+{
+ struct send_io *send_io;
+ struct vnic_cmd_config_addresses *config_addrs_req;
+ struct vnic_control_packet *pkt;
+ u16 i;
+ u8 j;
+ int ret = 1;
+
+ CONTROL_FUNCTION("%s: control_config_addrs_req()\n",
+ control_ifcfg_name(control));
+ dma_sync_single_for_cpu(control->parent->config->ibdev->dma_device,
+ control->send_dma, control->send_len,
+ DMA_TO_DEVICE);
+
+ send_io = control_init_hdr(control, CMD_CONFIG_ADDRESSES);
+ if (!send_io)
+ return -1;
+
+ pkt = control_packet(send_io);
+ config_addrs_req = &pkt->cmd.config_addresses_req;
+ config_addrs_req->lan_switch_num =
+ hton8(control->lan_switch.lan_switch_num);
+ for (i = 0, j = 0; (i < num) && (j < 16); i++) {
+ if (!addrs[i].operation)
+ continue;
+ config_addrs_req->list_address_ops[j].index = hton16(i);
+ config_addrs_req->list_address_ops[j].operation =
+ VNIC_OP_SET_ENTRY;
+ config_addrs_req->list_address_ops[j].valid = addrs[i].valid;
+ memcpy(config_addrs_req->list_address_ops[j].address,
+ addrs[i].address, MAC_ADDR_LEN);
+ config_addrs_req->list_address_ops[j].vlan =
+ hton16(addrs[i].vlan);
+ addrs[i].operation = 0;
+ j++;
+ }
+ for (; i < num; i++) {
+ if (addrs[i].operation) {
+ ret = 0;
+ break;
+ }
+ }
+ config_addrs_req->num_address_ops = hton8(j);
+
+ control->rsp_expected = pkt->hdr.pkt_cmd;
+ dma_sync_single_for_device(control->parent->config->ibdev->dma_device,
+ control->send_dma, control->send_len,
+ DMA_TO_DEVICE);
+
+ if (!control_send(control, send_io))
+ return -1;
+ return ret;
+}
+
+BOOLEAN control_config_addrs_rsp(struct control * control)
+{
+ struct recv_io *recv_io;
+ struct vnic_control_packet *pkt;
+ struct vnic_cmd_config_addresses *config_addrs_rsp;
+
+ CONTROL_FUNCTION("%s: control_config_addrs_rsp()\n",
+ control_ifcfg_name(control));
+ dma_sync_single_for_cpu(control->parent->config->ibdev->dma_device,
+ control->recv_dma, control->recv_len,
+ DMA_FROM_DEVICE);
+
+ recv_io = control_get_rsp(control);
+ if (!recv_io)
+ return FALSE;
+
+ pkt = control_packet(recv_io);
+ if (pkt->hdr.pkt_cmd != CMD_CONFIG_ADDRESSES) {
+ CONTROL_ERROR("%s: sent control request:\n",
+ control_ifcfg_name(control));
+ control_log_control_packet(control_last_req(control));
+ CONTROL_ERROR("%s: received control response:\n",
+ control_ifcfg_name(control));
+ control_log_control_packet(pkt);
+ goto failure;
+ }
+ config_addrs_rsp = &pkt->cmd.config_addresses_rsp;
+
+ control_recv(control, recv_io);
+ dma_sync_single_for_device(control->parent->config->ibdev->dma_device,
+ control->recv_dma, control->recv_len,
+ DMA_FROM_DEVICE);
+ return TRUE;
+failure:
+ viport_failure(control->parent);
+ dma_sync_single_for_device(control->parent->config->ibdev->dma_device,
+ control->recv_dma, control->recv_len,
+ DMA_FROM_DEVICE);
+ return FALSE;
+}
+
+BOOLEAN control_report_statistics_req(struct control * control)
+{
+ struct send_io *send_io;
+ struct vnic_control_packet *pkt;
+ struct vnic_cmd_report_stats_req *report_statistics_req;
+
+ CONTROL_FUNCTION("%s: control_report_statistics_req()\n",
+ control_ifcfg_name(control));
+ dma_sync_single_for_cpu(control->parent->config->ibdev->dma_device,
+ control->send_dma, control->send_len,
+ DMA_TO_DEVICE);
+
+ send_io = control_init_hdr(control, CMD_REPORT_STATISTICS);
+ if (!send_io)
+ return FALSE;
+
+ pkt = control_packet(send_io);
+ report_statistics_req = &pkt->cmd.report_statistics_req;
+ report_statistics_req->lan_switch_num =
+ hton8(control->lan_switch.lan_switch_num);
+
+ control->rsp_expected = pkt->hdr.pkt_cmd;
+ dma_sync_single_for_device(control->parent->config->ibdev->dma_device,
+ control->send_dma, control->send_len,
+ DMA_TO_DEVICE);
+
+ return control_send(control, send_io);
+}
+
+BOOLEAN control_report_statistics_rsp(struct control * control,
+ struct vnic_cmd_report_stats_rsp *
+ stats)
+{
+ struct recv_io *recv_io;
+ struct vnic_control_packet *pkt;
+ struct vnic_cmd_report_stats_rsp *rep_stat_rsp;
+
+ CONTROL_FUNCTION("%s: control_report_statistics_rsp()\n",
+ control_ifcfg_name(control));
+ dma_sync_single_for_cpu(control->parent->config->ibdev->dma_device,
+ control->recv_dma, control->recv_len,
+ DMA_FROM_DEVICE);
+
+ recv_io = control_get_rsp(control);
+ if (!recv_io)
+ return FALSE;
+
+ pkt = control_packet(recv_io);
+ if (pkt->hdr.pkt_cmd != CMD_REPORT_STATISTICS) {
+ CONTROL_ERROR("%s: sent control request:\n",
+ control_ifcfg_name(control));
+ control_log_control_packet(control_last_req(control));
+ CONTROL_ERROR("%s: received control response:\n",
+ control_ifcfg_name(control));
+ control_log_control_packet(pkt);
+ goto failure;
+ }
+ rep_stat_rsp = &pkt->cmd.report_statistics_rsp;
+ stats->if_in_broadcast_pkts =
+ ntoh64(rep_stat_rsp->if_in_broadcast_pkts);
+ stats->if_in_multicast_pkts =
+ ntoh64(rep_stat_rsp->if_in_multicast_pkts);
+ stats->if_in_octets = ntoh64(rep_stat_rsp->if_in_octets);
+ stats->if_in_ucast_pkts = ntoh64(rep_stat_rsp->if_in_ucast_pkts);
+ stats->if_in_nucast_pkts = ntoh64(rep_stat_rsp->if_in_nucast_pkts);
+ stats->if_in_underrun = ntoh64(rep_stat_rsp->if_in_underrun);
+ stats->if_in_errors = ntoh64(rep_stat_rsp->if_in_errors);
+ stats->if_out_errors = ntoh64(rep_stat_rsp->if_out_errors);
+ stats->if_out_octets = ntoh64(rep_stat_rsp->if_out_octets);
+ stats->if_out_ucast_pkts = ntoh64(rep_stat_rsp->if_out_ucast_pkts);
+ stats->if_out_multicast_pkts =
+ ntoh64(rep_stat_rsp->if_out_multicast_pkts);
+ stats->if_out_broadcast_pkts =
+ ntoh64(rep_stat_rsp->if_out_broadcast_pkts);
+ stats->if_out_nucast_pkts = ntoh64(rep_stat_rsp->if_out_nucast_pkts);
+ stats->if_out_ok = ntoh64(rep_stat_rsp->if_out_ok);
+ stats->if_in_ok = ntoh64(rep_stat_rsp->if_in_ok);
+ stats->if_out_ucast_bytes = ntoh64(rep_stat_rsp->if_out_ucast_bytes);
+ stats->if_out_multicast_bytes =
+ ntoh64(rep_stat_rsp->if_out_multicast_bytes);
+ stats->if_out_broadcast_bytes =
+ ntoh64(rep_stat_rsp->if_out_broadcast_bytes);
+ stats->if_in_ucast_bytes = ntoh64(rep_stat_rsp->if_in_ucast_bytes);
+ stats->if_in_multicast_bytes =
+ ntoh64(rep_stat_rsp->if_in_multicast_bytes);
+ stats->if_in_broadcast_bytes =
+ ntoh64(rep_stat_rsp->if_in_broadcast_bytes);
+ stats->ethernet_status = ntoh64(rep_stat_rsp->ethernet_status);
+
+ control_recv(control, recv_io);
+ dma_sync_single_for_device(control->parent->config->ibdev->dma_device,
+ control->recv_dma, control->recv_len,
+ DMA_FROM_DEVICE);
+
+ return TRUE;
+failure:
+ viport_failure(control->parent);
+ dma_sync_single_for_device(control->parent->config->ibdev->dma_device,
+ control->recv_dma, control->recv_len,
+ DMA_FROM_DEVICE);
+
+ return FALSE;
+}
+
+BOOLEAN control_reset_req(struct control * control)
+{
+ struct send_io *send_io;
+ struct vnic_control_packet *pkt;
+
+ CONTROL_FUNCTION("%s: control_reset_req()\n",
+ control_ifcfg_name(control));
+ dma_sync_single_for_cpu(control->parent->config->ibdev->dma_device,
+ control->send_dma, control->send_len,
+ DMA_TO_DEVICE);
+
+ send_io = control_init_hdr(control, CMD_RESET);
+ if (!send_io)
+ return FALSE;
+
+ pkt = control_packet(send_io);
+
+ control->rsp_expected = pkt->hdr.pkt_cmd;
+ dma_sync_single_for_device(control->parent->config->ibdev->dma_device,
+ control->send_dma, control->send_len,
+ DMA_TO_DEVICE);
+
+ return control_send(control, send_io);
+}
+
+BOOLEAN control_reset_rsp(struct control * control)
+{
+ struct recv_io *recv_io;
+ struct vnic_control_packet *pkt;
+
+ CONTROL_FUNCTION("%s: control_reset_rsp()\n",
+ control_ifcfg_name(control));
+ dma_sync_single_for_cpu(control->parent->config->ibdev->dma_device,
+ control->recv_dma, control->recv_len,
+ DMA_FROM_DEVICE);
+
+ recv_io = control_get_rsp(control);
+ if (!recv_io)
+ return FALSE;
+
+ pkt = control_packet(recv_io);
+ if (pkt->hdr.pkt_cmd != CMD_RESET) {
+ CONTROL_ERROR("%s: sent control request:\n",
+ control_ifcfg_name(control));
+ control_log_control_packet(control_last_req(control));
+ CONTROL_ERROR("%s: received control response:\n",
+ control_ifcfg_name(control));
+ control_log_control_packet(pkt);
+ goto failure;
+ }
+
+ control_recv(control, recv_io);
+ dma_sync_single_for_device(control->parent->config->ibdev->dma_device,
+ control->recv_dma, control->recv_len,
+ DMA_FROM_DEVICE);
+
+ return TRUE;
+ failure:
+ viport_failure(control->parent);
+ dma_sync_single_for_device(control->parent->config->ibdev->dma_device,
+ control->recv_dma, control->recv_len,
+ DMA_FROM_DEVICE);
+
+ return FALSE;
+}
+
+BOOLEAN control_heartbeat_req(struct control * control, u32 hb_interval)
+{
+ struct send_io *send_io;
+ struct vnic_control_packet *pkt;
+ struct vnic_cmd_heartbeat *heartbeat_req;
+
+ CONTROL_FUNCTION("%s: control_heartbeat_req()\n",
+ control_ifcfg_name(control));
+ dma_sync_single_for_cpu(control->parent->config->ibdev->dma_device,
+ control->send_dma, control->send_len,
+ DMA_TO_DEVICE);
+
+ send_io = control_init_hdr(control, CMD_HEARTBEAT);
+ if (!send_io)
+ return FALSE;
+
+ pkt = control_packet(send_io);
+ heartbeat_req = &pkt->cmd.heartbeat_req;
+ heartbeat_req->hb_interval = hton32(hb_interval);
+
+ control->rsp_expected = pkt->hdr.pkt_cmd;
+ dma_sync_single_for_device(control->parent->config->ibdev->dma_device,
+ control->send_dma, control->send_len,
+ DMA_TO_DEVICE);
+
+ return control_send(control, send_io);
+}
+
+BOOLEAN control_heartbeat_rsp(struct control * control)
+{
+ struct recv_io *recv_io;
+ struct vnic_control_packet *pkt;
+ struct vnic_cmd_heartbeat *heartbeat_rsp;
+
+ CONTROL_FUNCTION("%s: control_heartbeat_rsp()\n",
+ control_ifcfg_name(control));
+ dma_sync_single_for_cpu(control->parent->config->ibdev->dma_device,
+ control->recv_dma, control->recv_len,
+ DMA_FROM_DEVICE);
+
+ recv_io = control_get_rsp(control);
+ if (!recv_io)
+ return FALSE;
+
+ pkt = control_packet(recv_io);
+ if (pkt->hdr.pkt_cmd != CMD_HEARTBEAT) {
+ CONTROL_ERROR("%s: sent control request:\n",
+ control_ifcfg_name(control));
+ control_log_control_packet(control_last_req(control));
+ CONTROL_ERROR("%s: received control response:\n",
+ control_ifcfg_name(control));
+ control_log_control_packet(pkt);
+ goto failure;
+ }
+
+ heartbeat_rsp = &pkt->cmd.heartbeat_rsp;
+
+ control_recv(control, recv_io);
+ dma_sync_single_for_device(control->parent->config->ibdev->dma_device,
+ control->recv_dma, control->recv_len,
+ DMA_FROM_DEVICE);
+
+ return TRUE;
+ failure:
+ viport_failure(control->parent);
+ dma_sync_single_for_device(control->parent->config->ibdev->dma_device,
+ control->recv_dma, control->recv_len,
+ DMA_FROM_DEVICE);
+
+ return FALSE;
+}
+
+static void control_log_control_packet(struct vnic_control_packet *pkt)
+{
+ char *type;
+ int i;
+
+ switch (ntoh8(pkt->hdr.pkt_type)) {
+ case TYPE_INFO:
+ type = "TYPE_INFO";
+ break;
+ case TYPE_REQ:
+ type = "TYPE_REQ";
+ break;
+ case TYPE_RSP:
+ type = "TYPE_RSP";
+ break;
+ case TYPE_ERR:
+ type = "TYPE_ERR";
+ break;
+ default:
+ type = "UNKNOWN";
+ }
+ switch (ntoh8(pkt->hdr.pkt_cmd)) {
+ case CMD_INIT_VNIC:
+ printk(KERN_INFO
+ "control_packet: pkt_type = %s,"
+ " pkt_cmd = CMD_INIT_VNIC\n",
+ type);
+ printk(KERN_INFO
+ " pkt_seq_num = %u,"
+ " pkt_retry_count = %u\n",
+ ntoh8(pkt->hdr.pkt_seq_num),
+ ntoh8(pkt->hdr.pkt_retry_count));
+ printk(KERN_INFO
+ " vnic_major_version = %u,"
+ " vnic_minor_version = %u\n",
+ ntoh16(pkt->cmd.init_vnic_req.vnic_major_version),
+ ntoh16(pkt->cmd.init_vnic_req.vnic_minor_version));
+ if (pkt->hdr.pkt_type == TYPE_REQ) {
+ printk(KERN_INFO
+ " vnic_instance = %u,"
+ " num_data_paths = %u\n",
+ ntoh8(pkt->cmd.init_vnic_req.vnic_instance),
+ ntoh8(pkt->cmd.init_vnic_req.num_data_paths));
+ printk(KERN_INFO
+ " num_address_entries = %u\n",
+ ntoh16(pkt->cmd.init_vnic_req.
+ num_address_entries));
+ } else {
+ printk(KERN_INFO
+ " num_lan_switches = %u,"
+ " num_data_paths = %u\n",
+ ntoh8(pkt->cmd.init_vnic_rsp.num_lan_switches),
+ ntoh8(pkt->cmd.init_vnic_rsp.num_data_paths));
+ printk(KERN_INFO
+ " num_address_entries = %u,"
+ " features_supported = %08x\n",
+ ntoh16(pkt->cmd.init_vnic_rsp.
+ num_address_entries),
+ ntoh32(pkt->cmd.init_vnic_rsp.
+ features_supported));
+ if (pkt->cmd.init_vnic_rsp.num_lan_switches != 0) {
+ printk(KERN_INFO
+ "lan_switch[0] lan_switch_num = %u,"
+ " num_enet_ports = %08x\n",
+ ntoh8(pkt->cmd.init_vnic_rsp.
+ lan_switch[0].lan_switch_num),
+ ntoh8(pkt->cmd.init_vnic_rsp.
+ lan_switch[0].num_enet_ports));
+ printk(KERN_INFO
+ " default_vlan = %u,"
+ " hw_mac_address ="
+ " %02x:%02x:%02x:%02x:%02x:%02x\n",
+ ntoh16(pkt->cmd.init_vnic_rsp.
+ lan_switch[0].default_vlan),
+ pkt->cmd.init_vnic_rsp.lan_switch[0].
+ hw_mac_address[0],
+ pkt->cmd.init_vnic_rsp.lan_switch[0].
+ hw_mac_address[1],
+ pkt->cmd.init_vnic_rsp.lan_switch[0].
+ hw_mac_address[2],
+ pkt->cmd.init_vnic_rsp.lan_switch[0].
+ hw_mac_address[3],
+ pkt->cmd.init_vnic_rsp.lan_switch[0].
+ hw_mac_address[4],
+ pkt->cmd.init_vnic_rsp.lan_switch[0].
+ hw_mac_address[5]);
+ }
+ }
+ break;
+ case CMD_CONFIG_DATA_PATH:
+ printk(KERN_INFO
+ "control_packet: pkt_type = %s,"
+ " pkt_cmd = CMD_CONFIG_DATA_PATH\n",
+ type);
+ printk(KERN_INFO
+ " pkt_seq_num = %u,"
+ " pkt_retry_count = %u\n",
+ ntoh8(pkt->hdr.pkt_seq_num),
+ ntoh8(pkt->hdr.pkt_retry_count));
+ printk(KERN_INFO " path_identifier = %" PRIx64
+ ", data_path = %u\n",
+ pkt->cmd.config_data_path_req.path_identifier,
+ ntoh8(pkt->cmd.config_data_path_req.data_path));
+ printk(KERN_INFO
+ "host config size_recv_pool_entry = %u,"
+ " num_recv_pool_entries = %u\n",
+ ntoh32(pkt->cmd.config_data_path_req.
+ host_recv_pool_config.size_recv_pool_entry),
+ ntoh32(pkt->cmd.config_data_path_req.
+ host_recv_pool_config.num_recv_pool_entries));
+ printk(KERN_INFO
+ " timeout_before_kick = %u,"
+ " num_recv_pool_entries_before_kick = %u\n",
+ ntoh32(pkt->cmd.config_data_path_req.
+ host_recv_pool_config.timeout_before_kick),
+ ntoh32(pkt->cmd.config_data_path_req.
+ host_recv_pool_config.
+ num_recv_pool_entries_before_kick));
+ printk(KERN_INFO
+ " num_recv_pool_bytes_before_kick = %u,"
+ " free_recv_pool_entries_per_update = %u\n",
+ ntoh32(pkt->cmd.config_data_path_req.
+ host_recv_pool_config.
+ num_recv_pool_bytes_before_kick),
+ ntoh32(pkt->cmd.config_data_path_req.
+ host_recv_pool_config.
+ free_recv_pool_entries_per_update));
+ printk(KERN_INFO
+ "eioc config size_recv_pool_entry = %u,"
+ " num_recv_pool_entries = %u\n",
+ ntoh32(pkt->cmd.config_data_path_req.
+ eioc_recv_pool_config.size_recv_pool_entry),
+ ntoh32(pkt->cmd.config_data_path_req.
+ eioc_recv_pool_config.num_recv_pool_entries));
+ printk(KERN_INFO
+ " timeout_before_kick = %u,"
+ " num_recv_pool_entries_before_kick = %u\n",
+ ntoh32(pkt->cmd.config_data_path_req.
+ eioc_recv_pool_config.timeout_before_kick),
+ ntoh32(pkt->cmd.config_data_path_req.
+ eioc_recv_pool_config.
+ num_recv_pool_entries_before_kick));
+ printk(KERN_INFO
+ " num_recv_pool_bytes_before_kick = %u,"
+ " free_recv_pool_entries_per_update = %u\n",
+ ntoh32(pkt->cmd.config_data_path_req.
+ eioc_recv_pool_config.
+ num_recv_pool_bytes_before_kick),
+ ntoh32(pkt->cmd.config_data_path_req.
+ eioc_recv_pool_config.
+ free_recv_pool_entries_per_update));
+ break;
+ case CMD_EXCHANGE_POOLS:
+ printk(KERN_INFO
+ "control_packet: pkt_type = %s,"
+ " pkt_cmd = CMD_EXCHANGE_POOLS\n",
+ type);
+ printk(KERN_INFO
+ " pkt_seq_num = %u,"
+ " pkt_retry_count = %u\n",
+ ntoh8(pkt->hdr.pkt_seq_num),
+ ntoh8(pkt->hdr.pkt_retry_count));
+ printk(KERN_INFO " datapath = %u\n",
+ pkt->cmd.exchange_pools_req.data_path);
+ printk(KERN_INFO " pool_rkey = %08x"
+ " pool_addr = %"
+ PRIx64 "\n",
+ ntoh32(pkt->cmd.exchange_pools_req.pool_rkey),
+ ntoh64(pkt->cmd.exchange_pools_req.pool_addr));
+ break;
+ case CMD_CONFIG_ADDRESSES:
+ printk(KERN_INFO
+ "control_packet: pkt_type = %s,"
+ " pkt_cmd = CMD_CONFIG_ADDRESSES\n",
+ type);
+ printk(KERN_INFO
+ " pkt_seq_num = %u,"
+ " pkt_retry_count = %u\n",
+ ntoh8(pkt->hdr.pkt_seq_num),
+ ntoh8(pkt->hdr.pkt_retry_count));
+ printk(KERN_INFO
+ " num_address_ops = %x,"
+ " lan_switch_num = %d\n",
+ ntoh8(pkt->cmd.config_addresses_req.num_address_ops),
+ ntoh8(pkt->cmd.config_addresses_req.lan_switch_num));
+ for (i = 0; (i < pkt->cmd.config_addresses_req.num_address_ops)
+ && (i < 16); i++) {
+ printk(KERN_INFO
+ " list_address_ops[%u].index"
+ " = %u\n",
+ i,
+ ntoh16(pkt->cmd.config_addresses_req.
+ list_address_ops[i].index));
+ switch (ntoh8
+ (pkt->cmd.config_addresses_req.
+ list_address_ops[i].operation)) {
+ case VNIC_OP_GET_ENTRY:
+ printk(KERN_INFO
+ " list_address_ops[%u]."
+ "operation = VNIC_OP_GET_ENTRY\n",
+ i);
+ break;
+ case VNIC_OP_SET_ENTRY:
+ printk(KERN_INFO
+ " list_address_ops[%u]."
+ "operation = VNIC_OP_SET_ENTRY\n",
+ i);
+ break;
+ default:
+ printk(KERN_INFO
+ " list_address_ops[%u]."
+ "operation = UNKNOWN(%d)\n",
+ i,
+ ntoh8(pkt->cmd.config_addresses_req.
+ list_address_ops[i].operation));
+ break;
+ }
+ printk(KERN_INFO
+ " list_address_ops[%u].valid"
+ " = %u\n",
+ i,
+ ntoh8(pkt->cmd.config_addresses_req.
+ list_address_ops[i].valid));
+ printk(KERN_INFO
+ " list_address_ops[%u].address"
+ " = %02x:%02x:%02x:%02x:%02x:%02x\n",
+ i,
+ pkt->cmd.config_addresses_req.
+ list_address_ops[i].address[0],
+ pkt->cmd.config_addresses_req.
+ list_address_ops[i].address[1],
+ pkt->cmd.config_addresses_req.
+ list_address_ops[i].address[2],
+ pkt->cmd.config_addresses_req.
+ list_address_ops[i].address[3],
+ pkt->cmd.config_addresses_req.
+ list_address_ops[i].address[4],
+ pkt->cmd.config_addresses_req.
+ list_address_ops[i].address[5]);
+ printk(KERN_INFO
+ " list_address_ops[%u].vlan"
+ " = %u\n",
+ i,
+ ntoh16(pkt->cmd.config_addresses_req.
+ list_address_ops[i].vlan));
+ }
+ break;
+ case CMD_CONFIG_LINK:
+ printk(KERN_INFO
+ "control_packet: pkt_type = %s,"
+ " pkt_cmd = CMD_CONFIG_LINK\n",
+ type);
+ printk(KERN_INFO
+ " pkt_seq_num = %u,"
+ " pkt_retry_count = %u\n",
+ ntoh8(pkt->hdr.pkt_seq_num),
+ ntoh8(pkt->hdr.pkt_retry_count));
+ printk(KERN_INFO " cmd_flags = %x\n",
+ ntoh8(pkt->cmd.config_link_req.cmd_flags));
+ if (pkt->cmd.config_link_req.cmd_flags & VNIC_FLAG_ENABLE_NIC)
+ printk(KERN_INFO
+ " VNIC_FLAG_ENABLE_NIC\n");
+ if (pkt->cmd.config_link_req.cmd_flags & VNIC_FLAG_DISABLE_NIC)
+ printk(KERN_INFO
+ " VNIC_FLAG_DISABLE_NIC\n");
+ if (pkt->cmd.config_link_req.
+ cmd_flags & VNIC_FLAG_ENABLE_MCAST_ALL)
+ printk(KERN_INFO
+ " VNIC_FLAG_ENABLE_"
+ "MCAST_ALL\n");
+ if (pkt->cmd.config_link_req.
+ cmd_flags & VNIC_FLAG_DISABLE_MCAST_ALL)
+ printk(KERN_INFO
+ " VNIC_FLAG_DISABLE_"
+ "MCAST_ALL\n");
+ if (pkt->cmd.config_link_req.
+ cmd_flags & VNIC_FLAG_ENABLE_PROMISC)
+ printk(KERN_INFO
+ " VNIC_FLAG_ENABLE_"
+ "PROMISC\n");
+ if (pkt->cmd.config_link_req.
+ cmd_flags & VNIC_FLAG_DISABLE_PROMISC)
+ printk(KERN_INFO
+ " VNIC_FLAG_DISABLE_"
+ "PROMISC\n");
+ if (pkt->cmd.config_link_req.cmd_flags & VNIC_FLAG_SET_MTU)
+ printk(KERN_INFO
+ " VNIC_FLAG_SET_MTU\n");
+ printk(KERN_INFO
+ " lan_switch_num = %x, mtu_size = %d\n",
+ ntoh8(pkt->cmd.config_link_req.lan_switch_num),
+ ntoh16(pkt->cmd.config_link_req.mtu_size));
+ if (pkt->hdr.pkt_type == TYPE_RSP) {
+ printk(KERN_INFO
+ " default_vlan = %u,"
+ " hw_mac_address ="
+ " %02x:%02x:%02x:%02x:%02x:%02x\n",
+ ntoh16(pkt->cmd.config_link_req.default_vlan),
+ pkt->cmd.config_link_req.hw_mac_address[0],
+ pkt->cmd.config_link_req.hw_mac_address[1],
+ pkt->cmd.config_link_req.hw_mac_address[2],
+ pkt->cmd.config_link_req.hw_mac_address[3],
+ pkt->cmd.config_link_req.hw_mac_address[4],
+ pkt->cmd.config_link_req.hw_mac_address[5]);
+ }
+ break;
+ case CMD_REPORT_STATISTICS:
+ printk(KERN_INFO
+ "control_packet: pkt_type = %s,"
+ " pkt_cmd = CMD_REPORT_STATISTICS\n",
+ type);
+ printk(KERN_INFO
+ " pkt_seq_num = %u,"
+ " pkt_retry_count = %u\n",
+ ntoh8(pkt->hdr.pkt_seq_num),
+ ntoh8(pkt->hdr.pkt_retry_count));
+ printk(KERN_INFO " lan_switch_num = %u\n",
+ ntoh8(pkt->cmd.report_statistics_req.lan_switch_num));
+ if (pkt->hdr.pkt_type == TYPE_REQ)
+ break;
+ printk(KERN_INFO " if_in_broadcast_pkts = %"
+ PRIu64,
+ ntoh64(pkt->cmd.report_statistics_rsp.
+ if_in_broadcast_pkts));
+ printk(" if_in_multicast_pkts = %" PRIu64 "\n",
+ ntoh64(pkt->cmd.report_statistics_rsp.
+ if_in_multicast_pkts));
+ printk(KERN_INFO " if_in_octets = %" PRIu64,
+ ntoh64(pkt->cmd.report_statistics_rsp.if_in_octets));
+ printk(" if_in_ucast_pkts = %" PRIu64 "\n",
+ ntoh64(pkt->cmd.report_statistics_rsp.if_in_ucast_pkts));
+ printk(KERN_INFO " if_in_nucast_pkts = %" PRIu64,
+ ntoh64(pkt->cmd.report_statistics_rsp.
+ if_in_nucast_pkts));
+ printk(" if_in_underrun = %" PRIu64 "\n",
+ ntoh64(pkt->cmd.report_statistics_rsp.if_in_underrun));
+ printk(KERN_INFO " if_in_errors = %" PRIu64,
+ ntoh64(pkt->cmd.report_statistics_rsp.if_in_errors));
+ printk(" if_out_errors = %" PRIu64 "\n",
+ ntoh64(pkt->cmd.report_statistics_rsp.if_out_errors));
+ printk(KERN_INFO " if_out_octets = %" PRIu64,
+ ntoh64(pkt->cmd.report_statistics_rsp.if_out_octets));
+ printk(" if_out_ucast_pkts = %" PRIu64 "\n",
+ ntoh64(pkt->cmd.report_statistics_rsp.
+ if_out_ucast_pkts));
+ printk(KERN_INFO " if_out_multicast_pkts = %"
+ PRIu64,
+ ntoh64(pkt->cmd.report_statistics_rsp.
+ if_out_multicast_pkts));
+ printk(" if_out_broadcast_pkts = %" PRIu64 "\n",
+ ntoh64(pkt->cmd.report_statistics_rsp.
+ if_out_broadcast_pkts));
+ printk(KERN_INFO " if_out_nucast_pkts"
+ " = %" PRIu64,
+ ntoh64(pkt->cmd.report_statistics_rsp.
+ if_out_nucast_pkts));
+ printk(" if_out_ok = %" PRIu64 "\n",
+ ntoh64(pkt->cmd.report_statistics_rsp.if_out_ok));
+ printk(KERN_INFO " if_in_ok = %" PRIu64,
+ ntoh64(pkt->cmd.report_statistics_rsp.if_in_ok));
+ printk(" if_out_ucast_bytes = %" PRIu64 "\n",
+ ntoh64(pkt->cmd.report_statistics_rsp.
+ if_out_ucast_bytes));
+ printk(KERN_INFO " if_out_multicast_bytes = %"
+ PRIu64,
+ ntoh64(pkt->cmd.report_statistics_rsp.
+ if_out_multicast_bytes));
+ printk(" if_out_broadcast_bytes = %" PRIu64 "\n",
+ ntoh64(pkt->cmd.report_statistics_rsp.
+ if_out_broadcast_bytes));
+ printk(KERN_INFO " if_in_ucast_bytes = %" PRIu64,
+ ntoh64(pkt->cmd.report_statistics_rsp.
+ if_in_ucast_bytes));
+ printk(" if_in_multicast_bytes = %" PRIu64 "\n",
+ ntoh64(pkt->cmd.report_statistics_rsp.
+ if_in_multicast_bytes));
+ printk(KERN_INFO " if_in_broadcast_bytes = %"
+ PRIu64,
+ ntoh64(pkt->cmd.report_statistics_rsp.
+ if_in_broadcast_bytes));
+ printk(" ethernet_status = %" PRIu64 "\n",
+ ntoh64(pkt->cmd.report_statistics_rsp.ethernet_status));
+ break;
+ case CMD_CLEAR_STATISTICS:
+ printk(KERN_INFO
+ "control_packet: pkt_type = %s,"
+ " pkt_cmd = CMD_CLEAR_STATISTICS\n",
+ type);
+ printk(KERN_INFO
+ " pkt_seq_num = %u,"
+ " pkt_retry_count = %u\n",
+ ntoh8(pkt->hdr.pkt_seq_num),
+ ntoh8(pkt->hdr.pkt_retry_count));
+ break;
+ case CMD_REPORT_STATUS:
+ printk(KERN_INFO
+ "control_packet: pkt_type = %s,"
+ " pkt_cmd = CMD_REPORT_STATUS\n",
+ type);
+ printk(KERN_INFO
+ " pkt_seq_num = %u,"
+ " pkt_retry_count = %u\n",
+ ntoh8(pkt->hdr.pkt_seq_num),
+ ntoh8(pkt->hdr.pkt_retry_count));
+ printk(KERN_INFO
+ " lan_switch_num = %u, is_fatal = %u\n",
+ ntoh8(pkt->cmd.report_status.lan_switch_num),
+ ntoh8(pkt->cmd.report_status.is_fatal));
+ printk(KERN_INFO
+ " status_number = %u, status_info = %u\n",
+ ntoh32(pkt->cmd.report_status.status_number),
+ ntoh32(pkt->cmd.report_status.status_info));
+ pkt->cmd.report_status.file_name[31] = '\0';
+ pkt->cmd.report_status.routine[31] = '\0';
+ printk(KERN_INFO " filename = %s, routine = %s\n",
+ pkt->cmd.report_status.file_name,
+ pkt->cmd.report_status.routine);
+ printk(KERN_INFO
+ " line_num = %u, error_parameter = %u\n",
+ ntoh32(pkt->cmd.report_status.line_num),
+ ntoh32(pkt->cmd.report_status.error_parameter));
+ pkt->cmd.report_status.desc_text[127] = '\0';
+ printk(KERN_INFO " desc_text = %s\n",
+ pkt->cmd.report_status.desc_text);
+ break;
+ case CMD_RESET:
+ printk(KERN_INFO
+ "control_packet: pkt_type = %s, pkt_cmd = CMD_RESET\n",
+ type);
+ printk(KERN_INFO
+ " pkt_seq_num = %u,"
+ " pkt_retry_count = %u\n",
+ ntoh8(pkt->hdr.pkt_seq_num),
+ ntoh8(pkt->hdr.pkt_retry_count));
+ break;
+ case CMD_HEARTBEAT:
+ printk(KERN_INFO
+ "control_packet: pkt_type = %s,"
+ " pkt_cmd = CMD_HEARTBEAT\n",
+ type);
+ printk(KERN_INFO
+ " pkt_seq_num = %u,"
+ " pkt_retry_count = %u\n",
+ ntoh8(pkt->hdr.pkt_seq_num),
+ ntoh8(pkt->hdr.pkt_retry_count));
+ printk(KERN_INFO " hb_interval = %d\n",
+ ntoh32(pkt->cmd.heartbeat_req.hb_interval));
+ break;
+ default:
+ printk(KERN_INFO
+ "control_packet: pkt_type = %s,"
+ " pkt_cmd = UNKNOWN (%u)\n",
+ type, pkt->hdr.pkt_cmd);
+ printk(KERN_INFO
+ " pkt_seq_num = %u,"
+ " pkt_retry_count = %u\n",
+ ntoh8(pkt->hdr.pkt_seq_num),
+ ntoh8(pkt->hdr.pkt_retry_count));
+ break;
+ }
+ return;
+}
+
+BOOLEAN control_init(struct control * control, struct viport * viport,
+ struct control_config * config, struct ib_pd * pd,
+ u64 guid)
+{
+ struct vnic_control_packet *pkt;
+ struct io *io;
+ int sz;
+ unsigned int i;
+ struct ib_device *ibdev;
+ dma_addr_t recv_dma;
+
+ CONTROL_FUNCTION("%s: control_init()\n", control_ifcfg_name(control));
+ memset(control, 0, sizeof(struct control));
+
+ control->parent = viport;
+ control->config = config;
+ control->ib_conn.viport = viport;
+ control->ib_conn.ib_config = &config->ib_config;
+ control->ib_conn.state = IB_CONN_UNINITTED;
+
+ control->req_outstanding = FALSE;
+ control->seq_num = 0;
+
+ control->response = NULL;
+ control->info = NULL;
+ INIT_LIST_HEAD(&control->failure_list);
+ spin_lock_init(&control->io_lock);
+
+ if (!vnic_ib_conn_init(&control->ib_conn, viport, pd, guid,
+ &config->ib_config)) {
+ CONTROL_ERROR("IB connection initialization failed\n");
+ goto failure;
+ }
+
+ control->mr = ib_get_dma_mr(pd, IB_ACCESS_LOCAL_WRITE);
+ if (IS_ERR(control->mr)) {
+ CONTROL_ERROR("%s: failed to register memory"
+ " for control connection\n",
+ control_ifcfg_name(control));
+ goto destroy_conn;
+ }
+
+ control->ib_conn.cm_id = ib_create_cm_id(viport->config->ibdev,
+ vnic_ib_cm_handler,
+ &control->ib_conn);
+
+ if (IS_ERR(control->ib_conn.cm_id)) {
+ CONTROL_ERROR("creating control CM ID failed\n");
+ return FALSE;
+ }
+
+ sz = (sizeof(struct recv_io) * config->num_recvs) +
+ (sizeof(struct vnic_control_packet) * (config->num_recvs + 1));
+
+ control->local_storage = kmalloc(sz, GFP_KERNEL);
+ if (control->local_storage == NULL) {
+ CONTROL_ERROR("%s: failed allocating space for local storage\n",
+ control_ifcfg_name(control));
+ goto destroy_conn;
+ }
+ memset(control->local_storage, '\0', sz);
+
+ control->recv_ios = (struct recv_io *)control->local_storage;
+
+ ibdev = viport->config->ibdev;
+ sz = sizeof(struct recv_io) * config->num_recvs;
+
+ pkt = (struct vnic_control_packet *)(control->local_storage +
+ sizeof(struct recv_io) *
+ config->num_recvs);
+
+ control->send_io.virtual_addr = control->local_storage +
+ sizeof(struct send_io) * config->num_recvs;
+ control->send_len = sizeof(struct vnic_control_packet);
+
+ /*NOTE: using one send buffer and num_recvs recv buffers */
+
+ control->send_dma =
+ dma_map_single(ibdev->dma_device, pkt, control->send_len,
+ DMA_TO_DEVICE);
+
+ if (dma_mapping_error(control->send_dma)) {
+ CONTROL_ERROR("control send dma map error\n");
+ goto destroy_conn;
+ }
+
+ io = &control->send_io.io;
+ io->viport = viport;
+ io->routine = control_send_complete;
+
+ control->send_io.list.addr = control->send_dma;
+ control->send_io.list.length = sizeof(struct vnic_control_packet);
+ control->send_io.list.lkey = control->mr->lkey;
+
+ io->swr.wr_id = PTR64(io);
+ io->swr.sg_list = &control->send_io.list;
+ io->swr.num_sge = 1;
+ io->swr.opcode = IB_WR_SEND;
+ io->swr.send_flags = IB_SEND_SIGNALED;
+ io->type = SEND;
+
+ pkt++;
+
+ sz = sizeof(struct vnic_control_packet) * (config->num_recvs);
+ control->recv_dma = dma_map_single(ibdev->dma_device,
+ pkt, sz, DMA_FROM_DEVICE);
+ control->recv_len = sz;
+
+ if (dma_mapping_error(control->recv_dma)) {
+ CONTROL_ERROR("control recv dma map error\n");
+ goto destroy_conn;
+ }
+
+ recv_dma = control->recv_dma;
+
+ for (i = 0; i < config->num_recvs; i++) {
+ io = &control->recv_ios[i].io;
+ io->viport = viport;
+ io->routine = control_recv_complete;
+
+ io->type = RECV;
+
+ control->recv_ios[i].virtual_addr = (u8 *) pkt;
+ control->recv_ios[i].list.addr = recv_dma;
+ control->recv_ios[i].list.length =
+ sizeof(struct vnic_control_packet);
+ control->recv_ios[i].list.lkey = control->mr->lkey;
+
+ recv_dma = recv_dma + sizeof(struct vnic_control_packet);
+ pkt++;
+
+ io->rwr.wr_id = PTR64(io);
+ io->rwr.sg_list = &control->recv_ios[i].list;
+ io->rwr.num_sge = 1;
+ if (!vnic_ib_post_recv(&control->ib_conn, io)) {
+ kfree(control->local_storage);
+ goto destroy_conn;
+ }
+ }
+ return TRUE;
+destroy_conn:
+ ib_destroy_qp(control->ib_conn.qp);
+ ib_destroy_cq(control->ib_conn.cq);
+failure:
+ return FALSE;
+
+}
+
+void control_cleanup(struct control *control)
+{
+ CONTROL_FUNCTION("%s: control_disconnect()\n",
+ control_ifcfg_name(control));
+
+ init_completion(&control->ib_conn.done);
+
+ if (ib_send_cm_dreq(control->ib_conn.cm_id, NULL, 0)) {
+ printk(KERN_DEBUG "control CM DREQ sending failed\n");
+ } else
+ wait_for_completion(&control->ib_conn.done);
+
+ control_timer_stop(control);
+
+ ib_destroy_cm_id(control->ib_conn.cm_id);
+
+ ib_destroy_qp(control->ib_conn.qp);
+
+ ib_destroy_cq(control->ib_conn.cq);
+
+ ib_dereg_mr(control->mr);
+
+ dma_unmap_single(control->parent->config->ibdev->dma_device,
+ control->send_dma, control->send_len, DMA_TO_DEVICE);
+ dma_unmap_single(control->parent->config->ibdev->dma_device,
+ control->recv_dma, control->send_len, DMA_FROM_DEVICE);
+
+ kfree(control->local_storage);
+ return;
+}
diff --git a/drivers/infiniband/ulp/vnic/vnic_control.h b/drivers/infiniband/ulp/vnic/vnic_control.h
new file mode 100644
index 0000000..2124bea
--- /dev/null
+++ b/drivers/infiniband/ulp/vnic/vnic_control.h
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2006 SilverStorm Technologies Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef VNIC_CONTROL_H_INCLUDED
+#define VNIC_CONTROL_H_INCLUDED
+
+#ifdef CONFIG_INFINIBAND_VNIC_STATS
+#include <linux/timex.h>
+#include <linux/completion.h>
+#endif /* CONFIG_INFINIBAND_VNIC_STATS */
+
+#include "vnic_ib.h"
+#include "vnic_control_pkt.h"
+
+enum control_timer_state {
+ TIMER_IDLE,
+ TIMER_ACTIVE,
+ TIMER_EXPIRED
+};
+
+struct control {
+ struct viport *parent;
+ struct control_config *config;
+ struct ib_mr *mr;
+ struct vnic_ib_conn ib_conn;
+ u8 *local_storage;
+ int send_len;
+ int recv_len;
+ u16 maj_ver;
+ u16 min_ver;
+ struct vnic_lan_switch_attribs lan_switch;
+ struct send_io send_io;
+ struct recv_io *recv_ios;
+ dma_addr_t send_dma;
+ dma_addr_t recv_dma;
+ enum control_timer_state timer_state;
+ struct timer_list timer;
+ u8 req_retry_counter;
+ u8 req_outstanding;
+ u8 seq_num;
+ u8 rsp_expected;
+ struct recv_io *response;
+ struct recv_io *info;
+ struct list_head failure_list;
+ spinlock_t io_lock;
+ struct completion done;
+#ifdef CONFIG_INFINIBAND_VNIC_STATS
+ struct {
+ cycles_t request_time; /* intermediate value */
+ cycles_t response_time;
+ u32 response_num;
+ cycles_t response_max;
+ cycles_t response_min;
+ u32 timeout_num;
+ } statistics;
+#endif /* CONFIG_INFINIBAND_VNIC_STATS */
+};
+
+BOOLEAN control_init(struct control *control, struct viport *viport,
+ struct control_config *config, struct ib_pd *pd,
+ u64 guid);
+
+BOOLEAN control_connect(struct control *control);
+void control_cleanup(struct control *control);
+
+void control_process_async(struct control *control);
+
+BOOLEAN control_init_vnic_req(struct control *control);
+BOOLEAN control_init_vnic_rsp(struct control *control, u32 * features,
+ u8 * mac_address, u16 * num_addrs, u16 * vlan);
+
+BOOLEAN control_config_data_path_req(struct control *control, u64 path_id,
+ struct vnic_recv_pool_config *host,
+ struct vnic_recv_pool_config *eioc);
+BOOLEAN control_config_data_path_rsp(struct control *control,
+ struct vnic_recv_pool_config *host,
+ struct vnic_recv_pool_config *eioc,
+ struct vnic_recv_pool_config *max_host,
+ struct vnic_recv_pool_config *max_eioc,
+ struct vnic_recv_pool_config *min_host,
+ struct vnic_recv_pool_config *min_eioc);
+
+BOOLEAN control_exchange_pools_req(struct control *control, u64 addr, u32 rkey);
+BOOLEAN control_exchange_pools_rsp(struct control *control, u64 * addr,
+ u32 * rkey);
+
+BOOLEAN control_config_link_req(struct control *control, u16 flags, u16 mtu);
+BOOLEAN control_config_link_rsp(struct control *control, u16 * flags,
+ u16 * mtu);
+
+int control_config_addrs_req(struct control *control,
+ struct vnic_address_op *addrs, u16 num);
+BOOLEAN control_config_addrs_rsp(struct control *control);
+
+BOOLEAN control_report_statistics_req(struct control *control);
+BOOLEAN control_report_statistics_rsp(struct control *control,
+ struct vnic_cmd_report_stats_rsp *stats);
+
+BOOLEAN control_reset_req(struct control *control);
+BOOLEAN control_reset_rsp(struct control *control);
+
+BOOLEAN control_heartbeat_req(struct control *control, u32 hb_interval);
+BOOLEAN control_heartbeat_rsp(struct control *control);
+
+#define control_packet(io) \
+ (struct vnic_control_packet *)PTR((io)->virtual_addr)
+#define control_is_connected(control) \
+ (ib_conn_connected(&((control)->ib_conn)))
+
+#define control_last_req(control) control_packet(&(control)->send_io)
+#define control_features(control) (control)->features_supported
+
+#define control_get_mac_address(control,addr) \
+ memcpy(addr,(control)->lan_switch.hw_mac_address,MAC_ADDR_LEN)
+
+#endif /* VNIC_CONTROL_H_INCLUDED */
diff --git a/drivers/infiniband/ulp/vnic/vnic_control_pkt.h b/drivers/infiniband/ulp/vnic/vnic_control_pkt.h
new file mode 100644
index 0000000..33dcf8d
--- /dev/null
+++ b/drivers/infiniband/ulp/vnic/vnic_control_pkt.h
@@ -0,0 +1,278 @@
+/*
+ * Copyright (c) 2006 SilverStorm Technologies Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef VNIC_CONTROL_PKT_H_INCLUDED
+#define VNIC_CONTROL_PKT_H_INCLUDED
+
+struct vnic_connection_data {
+ u64 path_id;
+ u8 vnic_instance;
+ u8 path_num;
+ u8 nodename[65];
+};
+
+struct vnic_control_header {
+ u8 pkt_type;
+ u8 pkt_cmd;
+ u8 pkt_seq_num;
+ u8 pkt_retry_count;
+ u32 reserved; /* for 64-bit alignmnet */
+};
+
+/* ptk_type values */
+#define TYPE_INFO 0
+#define TYPE_REQ 1
+#define TYPE_RSP 2
+#define TYPE_ERR 3
+
+/* ptk_cmd values */
+#define CMD_INIT_VNIC 1
+#define CMD_CONFIG_DATA_PATH 2
+#define CMD_EXCHANGE_POOLS 3
+#define CMD_CONFIG_ADDRESSES 4
+#define CMD_CONFIG_LINK 5
+#define CMD_REPORT_STATISTICS 6
+#define CMD_CLEAR_STATISTICS 7
+#define CMD_REPORT_STATUS 8
+#define CMD_RESET 9
+#define CMD_HEARTBEAT 10
+
+#define MAC_ADDR_LEN 6
+
+/* pkt_cmd CMD_INIT_VNIC, pkt_type TYPE_REQ data format */
+struct vnic_cmd_init_vnic_req {
+ u16 vnic_major_version;
+ u16 vnic_minor_version;
+ u8 vnic_instance;
+ u8 num_data_paths;
+ u16 num_address_entries;
+};
+
+/* pkt_cmd CMD_INIT_VNIC, pkt_type TYPE_RSP subdata format */
+struct vnic_lan_switch_attribs {
+ u8 lan_switch_num;
+ u8 num_enet_ports;
+ u16 default_vlan;
+ u8 hw_mac_address[MAC_ADDR_LEN];
+};
+
+/* pkt_cmd CMD_INIT_VNIC, pkt_type TYPE_RSP data format */
+struct vnic_cmd_init_vnic_rsp {
+ u16 vnic_major_version;
+ u16 vnic_minor_version;
+ u8 num_lan_switches;
+ u8 num_data_paths;
+ u16 num_address_entries;
+ u32 features_supported;
+ struct vnic_lan_switch_attribs lan_switch[1];
+};
+
+/* features_supported values */
+#define VNIC_FEAT_IPV4_HEADERS 0x0001
+#define VNIC_FEAT_IPV6_HEADERS 0x0002
+#define VNIC_FEAT_IPV4_CSUM_RX 0x0004
+#define VNIC_FEAT_IPV4_CSUM_TX 0x0008
+#define VNIC_FEAT_TCP_CSUM_RX 0x0010
+#define VNIC_FEAT_TCP_CSUM_TX 0x0020
+#define VNIC_FEAT_UDP_CSUM_RX 0x0040
+#define VNIC_FEAT_UDP_CSUM_TX 0x0080
+#define VNIC_FEAT_TCP_SEGMENT 0x0100
+#define VNIC_FEAT_IPV4_IPSEC_OFFLOAD 0x0200
+#define VNIC_FEAT_IPV6_IPSEC_OFFLOAD 0x0400
+#define VNIC_FEAT_FCS_PROPAGATE 0x0800
+#define VNIC_FEAT_PF_KICK 0x1000
+#define VNIC_FEAT_PF_FORCE_ROUTE 0x2000
+#define VNIC_FEAT_CHASH_OFFLOAD 0x4000
+
+/* pkt_cmd CMD_CONFIG_DATA_PATH subdata format */
+struct vnic_recv_pool_config {
+ u32 size_recv_pool_entry;
+ u32 num_recv_pool_entries;
+ u32 timeout_before_kick;
+ u32 num_recv_pool_entries_before_kick;
+ u32 num_recv_pool_bytes_before_kick;
+ u32 free_recv_pool_entries_per_update;
+};
+
+/* pkt_cmd CMD_CONFIG_DATA_PATH data format */
+struct vnic_cmd_config_data_path {
+ u64 path_identifier;
+ u8 data_path;
+ u8 reserved[3];
+ struct vnic_recv_pool_config host_recv_pool_config;
+ struct vnic_recv_pool_config eioc_recv_pool_config;
+};
+
+/* pkt_cmd CMD_EXCHANGE_POOLS data format */
+struct vnic_cmd_exchange_pools {
+ u8 data_path;
+ u8 reserved[3];
+ u32 pool_rkey;
+ u64 pool_addr;
+};
+
+/* pkt_cmd CMD_CONFIG_ADDRESSES subdata format */
+struct vnic_address_op {
+ u16 index;
+ u8 operation;
+ u8 valid;
+ u8 address[6];
+ u16 vlan;
+};
+
+/* operation values */
+#define VNIC_OP_SET_ENTRY 0x01
+#define VNIC_OP_GET_ENTRY 0x02
+
+/* pkt_cmd CMD_CONFIG_ADDRESSES data format */
+struct vnic_cmd_config_addresses {
+ u8 num_address_ops;
+ u8 lan_switch_num;
+ struct vnic_address_op list_address_ops[1];
+};
+
+/* CMD_CONFIG_LINK data format */
+struct vnic_cmd_config_link {
+ u8 cmd_flags;
+ u8 lan_switch_num;
+ u16 mtu_size;
+ u16 default_vlan;
+ u8 hw_mac_address[6];
+};
+
+/* cmd_flags values */
+#define VNIC_FLAG_ENABLE_NIC 0x01
+#define VNIC_FLAG_DISABLE_NIC 0x02
+#define VNIC_FLAG_ENABLE_MCAST_ALL 0x04
+#define VNIC_FLAG_DISABLE_MCAST_ALL 0x08
+#define VNIC_FLAG_ENABLE_PROMISC 0x10
+#define VNIC_FLAG_DISABLE_PROMISC 0x20
+#define VNIC_FLAG_SET_MTU 0x40
+
+/* pkt_cmd CMD_REPORT_STATISTICS, pkt_type TYPE_REQ data format */
+struct vnic_cmd_report_stats_req {
+ u8 lan_switch_num;
+};
+
+/* pkt_cmd CMD_REPORT_STATISTICS, pkt_type TYPE_RSP data format */
+struct vnic_cmd_report_stats_rsp {
+ u8 lan_switch_num;
+ u8 reserved[7]; /* for 64-bit alignment */
+ u64 if_in_broadcast_pkts;
+ u64 if_in_multicast_pkts;
+ u64 if_in_octets;
+ u64 if_in_ucast_pkts;
+ u64 if_in_nucast_pkts; /* if_in_broadcast_pkts
+ + if_in_multicast_pkts */
+ u64 if_in_underrun; /* (OID_GEN_RCV_NO_BUFFER) */
+ u64 if_in_errors; /* (OID_GEN_RCV_ERROR) */
+ u64 if_out_errors; /* (OID_GEN_XMIT_ERROR) */
+ u64 if_out_octets;
+ u64 if_out_ucast_pkts;
+ u64 if_out_multicast_pkts;
+ u64 if_out_broadcast_pkts;
+ u64 if_out_nucast_pkts; /* if_out_broadcast_pkts
+ + if_out_multicast_pkts */
+ u64 if_out_ok; /* if_out_nucast_pkts
+ + if_out_ucast_pkts(OID_GEN_XMIT_OK) */
+ u64 if_in_ok; /* if_in_nucast_pkts
+ + if_in_ucast_pkts(OID_GEN_RCV_OK) */
+ u64 if_out_ucast_bytes; /* (OID_GEN_DIRECTED_BYTES_XMT) */
+ u64 if_out_multicast_bytes; /* (OID_GEN_MULTICAST_BYTES_XMT) */
+ u64 if_out_broadcast_bytes; /* (OID_GEN_BROADCAST_BYTES_XMT) */
+ u64 if_in_ucast_bytes; /* (OID_GEN_DIRECTED_BYTES_RCV) */
+ u64 if_in_multicast_bytes; /* (OID_GEN_MULTICAST_BYTES_RCV) */
+ u64 if_in_broadcast_bytes; /* (OID_GEN_BROADCAST_BYTES_RCV) */
+ u64 ethernet_status; /* OID_GEN_MEDIA_CONNECT_STATUS) */
+};
+
+/* pkt_cmd CMD_CLEAR_STATISTICS data format */
+struct vnic_cmd_clear_statistics {
+ u8 lan_switch_num;
+};
+
+/* pkt_cmd CMD_REPORT_STATUS data format */
+struct vnic_cmd_report_status {
+ u8 lan_switch_num;
+ u8 is_fatal;
+ u8 reserved[2]; /* for 32-bit alignment */
+ u32 status_number;
+ u32 status_info;
+ u8 file_name[32];
+ u8 routine[32];
+ u32 line_num;
+ u32 error_parameter;
+ u8 desc_text[128];
+};
+
+/* pkt_cmd CMD_HEARTBEAT data format */
+struct vnic_cmd_heartbeat {
+ u32 hb_interval;
+};
+
+#define VNIC_STATUS_LINK_UP 1
+#define VNIC_STATUS_LINK_DOWN 2
+#define VNIC_STATUS_ENET_AGGREGATION_CHANGE 3
+#define VNIC_STATUS_EIOC_SHUTDOWN 4
+#define VNIC_STATUS_CONTROL_ERROR 5
+#define VNIC_STATUS_EIOC_ERROR 6
+
+#define VNIC_MAX_CONTROLPKTSZ 256
+#define VNIC_MAX_CONTROLDATASZ \
+ (VNIC_MAX_CONTROLPKTSZ - sizeof(struct vnic_control_header))
+
+struct vnic_control_packet {
+ struct vnic_control_header hdr;
+ union {
+ struct vnic_cmd_init_vnic_req init_vnic_req;
+ struct vnic_cmd_init_vnic_rsp init_vnic_rsp;
+ struct vnic_cmd_config_data_path config_data_path_req;
+ struct vnic_cmd_config_data_path config_data_path_rsp;
+ struct vnic_cmd_exchange_pools exchange_pools_req;
+ struct vnic_cmd_exchange_pools exchange_pools_rsp;
+ struct vnic_cmd_config_addresses config_addresses_req;
+ struct vnic_cmd_config_addresses config_addresses_rsp;
+ struct vnic_cmd_config_link config_link_req;
+ struct vnic_cmd_config_link config_link_rsp;
+ struct vnic_cmd_report_stats_req report_statistics_req;
+ struct vnic_cmd_report_stats_rsp report_statistics_rsp;
+ struct vnic_cmd_clear_statistics clear_statistics_req;
+ struct vnic_cmd_clear_statistics clear_statistics_rsp;
+ struct vnic_cmd_report_status report_status;
+ struct vnic_cmd_heartbeat heartbeat_req;
+ struct vnic_cmd_heartbeat heartbeat_rsp;
+
+ char cmd_data[VNIC_MAX_CONTROLDATASZ];
+ } cmd;
+};
+
+#endif /* VNIC_CONTROL_PKT_H_INCLUDED */
More information about the general
mailing list