This commit was manufactured by cvs2svn to create branch 'vserver'.
[linux-2.6.git] / drivers / infiniband / hw / ehca / ehca_hca.c
diff --git a/drivers/infiniband/hw/ehca/ehca_hca.c b/drivers/infiniband/hw/ehca/ehca_hca.c
new file mode 100644 (file)
index 0000000..b7be950
--- /dev/null
@@ -0,0 +1,242 @@
+/*
+ *  IBM eServer eHCA Infiniband device driver for Linux on POWER
+ *
+ *  HCA query functions
+ *
+ *  Authors: Heiko J Schick <schickhj@de.ibm.com>
+ *           Christoph Raisch <raisch@de.ibm.com>
+ *
+ *  Copyright (c) 2005 IBM Corporation
+ *
+ *  All rights reserved.
+ *
+ *  This source code is distributed under a dual license of GPL v2.0 and OpenIB
+ *  BSD.
+ *
+ * OpenIB BSD License
+ *
+ * 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.
+ *
+ * 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 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 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 DAMAGE.
+ */
+
+#include "ehca_tools.h"
+#include "ehca_iverbs.h"
+#include "hcp_if.h"
+
+int ehca_query_device(struct ib_device *ibdev, struct ib_device_attr *props)
+{
+       int ret = 0;
+       struct ehca_shca *shca = container_of(ibdev, struct ehca_shca,
+                                             ib_device);
+       struct hipz_query_hca *rblock;
+
+       rblock = ehca_alloc_fw_ctrlblock(GFP_KERNEL);
+       if (!rblock) {
+               ehca_err(&shca->ib_device, "Can't allocate rblock memory.");
+               return -ENOMEM;
+       }
+
+       if (hipz_h_query_hca(shca->ipz_hca_handle, rblock) != H_SUCCESS) {
+               ehca_err(&shca->ib_device, "Can't query device properties");
+               ret = -EINVAL;
+               goto query_device1;
+       }
+
+       memset(props, 0, sizeof(struct ib_device_attr));
+       props->fw_ver          = rblock->hw_ver;
+       props->max_mr_size     = rblock->max_mr_size;
+       props->vendor_id       = rblock->vendor_id >> 8;
+       props->vendor_part_id  = rblock->vendor_part_id >> 16;
+       props->hw_ver          = rblock->hw_ver;
+       props->max_qp          = min_t(int, rblock->max_qp, INT_MAX);
+       props->max_qp_wr       = min_t(int, rblock->max_wqes_wq, INT_MAX);
+       props->max_sge         = min_t(int, rblock->max_sge, INT_MAX);
+       props->max_sge_rd      = min_t(int, rblock->max_sge_rd, INT_MAX);
+       props->max_cq          = min_t(int, rblock->max_cq, INT_MAX);
+       props->max_cqe         = min_t(int, rblock->max_cqe, INT_MAX);
+       props->max_mr          = min_t(int, rblock->max_mr, INT_MAX);
+       props->max_mw          = min_t(int, rblock->max_mw, INT_MAX);
+       props->max_pd          = min_t(int, rblock->max_pd, INT_MAX);
+       props->max_ah          = min_t(int, rblock->max_ah, INT_MAX);
+       props->max_fmr         = min_t(int, rblock->max_mr, INT_MAX);
+       props->max_srq         = 0;
+       props->max_srq_wr      = 0;
+       props->max_srq_sge     = 0;
+       props->max_pkeys       = 16;
+       props->local_ca_ack_delay
+               = rblock->local_ca_ack_delay;
+       props->max_raw_ipv6_qp
+               = min_t(int, rblock->max_raw_ipv6_qp, INT_MAX);
+       props->max_raw_ethy_qp
+               = min_t(int, rblock->max_raw_ethy_qp, INT_MAX);
+       props->max_mcast_grp
+               = min_t(int, rblock->max_mcast_grp, INT_MAX);
+       props->max_mcast_qp_attach
+               = min_t(int, rblock->max_mcast_qp_attach, INT_MAX);
+       props->max_total_mcast_qp_attach
+               = min_t(int, rblock->max_total_mcast_qp_attach, INT_MAX);
+
+query_device1:
+       ehca_free_fw_ctrlblock(rblock);
+
+       return ret;
+}
+
+int ehca_query_port(struct ib_device *ibdev,
+                   u8 port, struct ib_port_attr *props)
+{
+       int ret = 0;
+       struct ehca_shca *shca = container_of(ibdev, struct ehca_shca,
+                                             ib_device);
+       struct hipz_query_port *rblock;
+
+       rblock = ehca_alloc_fw_ctrlblock(GFP_KERNEL);
+       if (!rblock) {
+               ehca_err(&shca->ib_device, "Can't allocate rblock memory.");
+               return -ENOMEM;
+       }
+
+       if (hipz_h_query_port(shca->ipz_hca_handle, port, rblock) != H_SUCCESS) {
+               ehca_err(&shca->ib_device, "Can't query port properties");
+               ret = -EINVAL;
+               goto query_port1;
+       }
+
+       memset(props, 0, sizeof(struct ib_port_attr));
+       props->state = rblock->state;
+
+       switch (rblock->max_mtu) {
+       case 0x1:
+               props->active_mtu = props->max_mtu = IB_MTU_256;
+               break;
+       case 0x2:
+               props->active_mtu = props->max_mtu = IB_MTU_512;
+               break;
+       case 0x3:
+               props->active_mtu = props->max_mtu = IB_MTU_1024;
+               break;
+       case 0x4:
+               props->active_mtu = props->max_mtu = IB_MTU_2048;
+               break;
+       case 0x5:
+               props->active_mtu = props->max_mtu = IB_MTU_4096;
+               break;
+       default:
+               ehca_err(&shca->ib_device, "Unknown MTU size: %x.",
+                        rblock->max_mtu);
+               break;
+       }
+
+       props->gid_tbl_len     = rblock->gid_tbl_len;
+       props->max_msg_sz      = rblock->max_msg_sz;
+       props->bad_pkey_cntr   = rblock->bad_pkey_cntr;
+       props->qkey_viol_cntr  = rblock->qkey_viol_cntr;
+       props->pkey_tbl_len    = rblock->pkey_tbl_len;
+       props->lid             = rblock->lid;
+       props->sm_lid          = rblock->sm_lid;
+       props->lmc             = rblock->lmc;
+       props->sm_sl           = rblock->sm_sl;
+       props->subnet_timeout  = rblock->subnet_timeout;
+       props->init_type_reply = rblock->init_type_reply;
+
+       props->active_width    = IB_WIDTH_12X;
+       props->active_speed    = 0x1;
+
+query_port1:
+       ehca_free_fw_ctrlblock(rblock);
+
+       return ret;
+}
+
+int ehca_query_pkey(struct ib_device *ibdev, u8 port, u16 index, u16 *pkey)
+{
+       int ret = 0;
+       struct ehca_shca *shca = container_of(ibdev, struct ehca_shca, ib_device);
+       struct hipz_query_port *rblock;
+
+       if (index > 16) {
+               ehca_err(&shca->ib_device, "Invalid index: %x.", index);
+               return -EINVAL;
+       }
+
+       rblock = ehca_alloc_fw_ctrlblock(GFP_KERNEL);
+       if (!rblock) {
+               ehca_err(&shca->ib_device,  "Can't allocate rblock memory.");
+               return -ENOMEM;
+       }
+
+       if (hipz_h_query_port(shca->ipz_hca_handle, port, rblock) != H_SUCCESS) {
+               ehca_err(&shca->ib_device, "Can't query port properties");
+               ret = -EINVAL;
+               goto query_pkey1;
+       }
+
+       memcpy(pkey, &rblock->pkey_entries + index, sizeof(u16));
+
+query_pkey1:
+       ehca_free_fw_ctrlblock(rblock);
+
+       return ret;
+}
+
+int ehca_query_gid(struct ib_device *ibdev, u8 port,
+                  int index, union ib_gid *gid)
+{
+       int ret = 0;
+       struct ehca_shca *shca = container_of(ibdev, struct ehca_shca,
+                                             ib_device);
+       struct hipz_query_port *rblock;
+
+       if (index > 255) {
+               ehca_err(&shca->ib_device, "Invalid index: %x.", index);
+               return -EINVAL;
+       }
+
+       rblock = ehca_alloc_fw_ctrlblock(GFP_KERNEL);
+       if (!rblock) {
+               ehca_err(&shca->ib_device, "Can't allocate rblock memory.");
+               return -ENOMEM;
+       }
+
+       if (hipz_h_query_port(shca->ipz_hca_handle, port, rblock) != H_SUCCESS) {
+               ehca_err(&shca->ib_device, "Can't query port properties");
+               ret = -EINVAL;
+               goto query_gid1;
+       }
+
+       memcpy(&gid->raw[0], &rblock->gid_prefix, sizeof(u64));
+       memcpy(&gid->raw[8], &rblock->guid_entries[index], sizeof(u64));
+
+query_gid1:
+       ehca_free_fw_ctrlblock(rblock);
+
+       return ret;
+}
+
+int ehca_modify_port(struct ib_device *ibdev,
+                    u8 port, int port_modify_mask,
+                    struct ib_port_modify *props)
+{
+       /* Not implemented yet */
+       return -EFAULT;
+}