events: support multiple event handlers
authorshefty <shefty@ad392aa1-c5ef-ae45-8dd8-e69d62a5ef86>
Wed, 23 Jul 2008 21:33:56 +0000 (21:33 +0000)
committershefty <shefty@ad392aa1-c5ef-ae45-8dd8-e69d62a5ef86>
Wed, 23 Jul 2008 21:33:56 +0000 (21:33 +0000)
Modify the channel interface to allow clients to register different
event handlers.  This is in addition to the event handler specified when
opening the channel adapter.  The latter can be replaced in a subsequent
patch, but is left as is to minimize changes.

This change allows the channel interface to support multiple direct
call clients, such as winverbs and ibal.

Signed-off-by: Sean Hefty <sean.hefty@intel.com>
git-svn-id: svn://openib.tc.cornell.edu/gen1/trunk@1443 ad392aa1-c5ef-ae45-8dd8-e69d62a5ef86

hw/mlx4/kernel/hca/ca.c
hw/mlx4/kernel/hca/data.c
hw/mlx4/kernel/hca/data.h
hw/mlx4/kernel/hca/drv.c
hw/mthca/kernel/hca_data.c
hw/mthca/kernel/hca_data.h
hw/mthca/kernel/hca_verbs.c
hw/mthca/kernel/mthca_main.c
inc/iba/ib_ci.h
inc/iba/ib_types.h

index 7e40a89..3b77659 100644 (file)
@@ -99,6 +99,32 @@ err_set_cb:
        return status;\r
 }\r
 \r
+static void\r
+mlnx_register_event_handler (\r
+       IN              const   ib_ca_handle_t                          h_ca,\r
+       IN                              ci_event_handler_t*                     p_reg)\r
+{\r
+       mlnx_hca_t *p_hca = (mlnx_hca_t *) h_ca;\r
+       KIRQL irql;\r
+\r
+       KeAcquireSpinLock(&p_hca->event_list_lock, &irql);\r
+       InsertTailList(&p_hca->event_list, &p_reg->entry);\r
+       KeReleaseSpinLock(&p_hca->event_list_lock, irql);\r
+}\r
+\r
+static void\r
+mlnx_unregister_event_handler (\r
+       IN              const   ib_ca_handle_t                          h_ca,\r
+       IN                              ci_event_handler_t*                     p_reg)\r
+{\r
+       mlnx_hca_t *p_hca = (mlnx_hca_t *) h_ca;\r
+       KIRQL irql;\r
+\r
+       KeAcquireSpinLock(&p_hca->event_list_lock, &irql);\r
+       RemoveEntryList(&p_reg->entry);\r
+       KeReleaseSpinLock(&p_hca->event_list_lock, irql);\r
+}\r
+\r
 ib_api_status_t\r
 mlnx_query_ca (\r
        IN              const   ib_ca_handle_t                          h_ca,\r
@@ -408,6 +434,8 @@ mlnx_ca_if(
        p_interface->modify_ca = mlnx_modify_ca; \r
        p_interface->query_ca = mlnx_query_ca;\r
        p_interface->close_ca = mlnx_close_ca;\r
+       p_interface->register_event_handler = mlnx_register_event_handler;\r
+       p_interface->unregister_event_handler = mlnx_unregister_event_handler;\r
 }\r
 \r
 void\r
index b068434..9a51a6f 100644 (file)
@@ -299,10 +299,12 @@ void ca_event_handler(struct ib_event *ev, void *context)
 {\r
        mlnx_hca_t *p_hca = (mlnx_hca_t *)context;\r
        ib_event_rec_t event_rec;\r
+       LIST_ENTRY *entry;\r
+       ci_event_handler_t *event_handler;\r
 \r
        // prepare parameters\r
-       event_rec.context = (void *)p_hca->ca_context;\r
        event_rec.type = ev->event;\r
+       event_rec.port_number = ev->element.port_num;\r
        if (event_rec.type > IB_AE_UNKNOWN) {\r
                // CL_ASSERT(0); // This shouldn't happen\r
                HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_SHIM,("Unmapped E_EV_CA event of type 0x%x. Replaced by 0x%x (IB_AE_LOCAL_FATAL)\n", \r
@@ -311,9 +313,20 @@ void ca_event_handler(struct ib_event *ev, void *context)
        }\r
 \r
        // call the user callback\r
-       if (p_hca && p_hca->async_cb_p)\r
+       KeAcquireSpinLockAtDpcLevel(&p_hca->event_list_lock);\r
+       for (entry = p_hca->event_list.Flink; entry != &p_hca->event_list;\r
+                entry = entry->Flink) {\r
+\r
+               event_handler = CONTAINING_RECORD(entry, ci_event_handler_t, entry);\r
+               event_rec.context = (void *) event_handler;\r
+               event_handler->pfn_async_event_cb(&event_rec);\r
+       }\r
+       KeReleaseSpinLockFromDpcLevel(&p_hca->event_list_lock);\r
+\r
+       if (p_hca && p_hca->async_cb_p) {\r
+               event_rec.context = (void *)p_hca->ca_context;\r
                (p_hca->async_cb_p)(&event_rec);\r
-       else {\r
+       else {\r
                HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_SHIM ,("Incorrect context. Async callback was not invoked\n"));\r
        }\r
 }\r
index 65f752d..2d0aabe 100644 (file)
@@ -156,6 +156,8 @@ typedef struct _mlnx_hca_t {
        net64_t                 guid;                                   // HCA node Guid\r
        uint32_t                        hw_ver;                         // HCA HW version\r
        // HOB\r
+       KSPIN_LOCK                      event_list_lock;\r
+       LIST_ENTRY                      event_list;\r
        ci_async_event_cb_t async_cb_p;\r
        const void          *ca_context;\r
        void                *cl_device_h;\r
index 6b14ece..fb1209b 100644 (file)
@@ -35,8 +35,8 @@
 #include <wdmguid.h>\r
 \r
 #if defined(EVENT_TRACING)\r
-#ifdef offsetof
-#undef offsetof
+#ifdef offsetof\r
+#undef offsetof\r
 #endif\r
 #include "drv.tmh"\r
 #endif \r
@@ -651,7 +651,9 @@ EvtDevicePrepareHardware(
        }\r
        p_fdo->bus_ib_ifc_taken = TRUE;\r
        p_fdo->bus_ib_ifc.p_ibdev->x.p_fdo = p_fdo;\r
-       \r
+\r
+       InitializeListHead(&p_fdo->hca.event_list);\r
+       KeInitializeSpinLock(&p_fdo->hca.event_list_lock);\r
 \r
        /* get node GUID */\r
        err = __get_dev_info( p_fdo, &p_fdo->hca.guid, &p_fdo->hca.hw_ver );\r
index dbaa885..99b1c65 100644 (file)
@@ -335,10 +335,12 @@ void ca_event_handler(struct ib_event *ev, void *context)
 {\r
        mlnx_hob_t *hob_p = (mlnx_hob_t *)context;\r
        ib_event_rec_t event_rec;\r
+       LIST_ENTRY *entry;\r
+       ci_event_handler_t *event_handler;\r
 \r
        // prepare parameters\r
-       event_rec.context = (void *)hob_p->ca_context;\r
        event_rec.type = ev->event;\r
+       event_rec.port_number = ev->element.port_num;\r
        if (event_rec.type > IB_AE_UNKNOWN) {\r
                // CL_ASSERT(0); // This shouldn't happen\r
                HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_SHIM,("Unmapped E_EV_CA event of type 0x%x. Replaced by 0x%x (IB_AE_LOCAL_FATAL)\n", \r
@@ -347,9 +349,20 @@ void ca_event_handler(struct ib_event *ev, void *context)
        }\r
 \r
        // call the user callback\r
-       if (hob_p && hob_p->async_cb_p)\r
+       KeAcquireSpinLockAtDpcLevel(&hob_p->event_list_lock);\r
+       for (entry = hob_p->event_list.Flink; entry != &hob_p->event_list;\r
+                entry = entry->Flink) {\r
+\r
+               event_handler = CONTAINING_RECORD(entry, ci_event_handler_t, entry);\r
+               event_rec.context = (void *) event_handler;\r
+               event_handler->pfn_async_event_cb(&event_rec);\r
+       }\r
+       KeReleaseSpinLockFromDpcLevel(&hob_p->event_list_lock);\r
+\r
+       if (hob_p && hob_p->async_cb_p) {\r
+               event_rec.context = (void *)hob_p->ca_context;\r
                (hob_p->async_cb_p)(&event_rec);\r
-       else {\r
+       else {\r
                HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_SHIM ,("Incorrect context. Async callback was not invoked\n"));\r
        }\r
 }\r
index 99b8e0a..bb3bfa1 100644 (file)
@@ -172,6 +172,8 @@ typedef struct _attr_cache
 \r
 typedef struct _ib_ca {\r
        ENUM_MARK           mark;\r
+       KSPIN_LOCK                      event_list_lock;\r
+       LIST_ENTRY                      event_list;\r
        ci_async_event_cb_t async_cb_p;\r
        const void          *ca_context;\r
        void                *cl_device_h;\r
index 569462d..38c7ff2 100644 (file)
@@ -116,6 +116,32 @@ err_set_cb:
        return status;\r
 }\r
 \r
+static void\r
+mlnx_register_event_handler (\r
+       IN              const   ib_ca_handle_t                          h_ca,\r
+       IN                              ci_event_handler_t*                     p_reg)\r
+{\r
+       mlnx_hob_t *hob_p = (mlnx_hob_t *) h_ca;\r
+       KIRQL irql;\r
+\r
+       KeAcquireSpinLock(&hob_p->event_list_lock, &irql);\r
+       InsertTailList(&hob_p->event_list, &p_reg->entry);\r
+       KeReleaseSpinLock(&hob_p->event_list_lock, irql);\r
+}\r
+\r
+static void\r
+mlnx_unregister_event_handler (\r
+       IN              const   ib_ca_handle_t                          h_ca,\r
+       IN                              ci_event_handler_t*                     p_reg)\r
+{\r
+       mlnx_hob_t *hob_p = (mlnx_hob_t *) h_ca;\r
+       KIRQL irql;\r
+\r
+       KeAcquireSpinLock(&hob_p->event_list_lock, &irql);\r
+       RemoveEntryList(&p_reg->entry);\r
+       KeReleaseSpinLock(&hob_p->event_list_lock, irql);\r
+}\r
+\r
 ib_api_status_t\r
 mlnx_query_ca (\r
        IN              const   ib_ca_handle_t                          h_ca,\r
@@ -1656,6 +1682,8 @@ setup_ci_interface(
        p_interface->close_ca = mlnx_close_ca;\r
        p_interface->um_open_ca = mlnx_um_open;\r
        p_interface->um_close_ca = mlnx_um_close;\r
+       p_interface->register_event_handler = mlnx_register_event_handler;\r
+       p_interface->unregister_event_handler = mlnx_unregister_event_handler;\r
 \r
        p_interface->allocate_pd = mlnx_allocate_pd;\r
        p_interface->deallocate_pd = mlnx_deallocate_pd;\r
index c23478a..f6c5264 100644 (file)
-/*
- * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
- * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
- * Copyright (c) 2005 Mellanox Technologies. 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.
- *
- * $Id$
- */
-
-#include "mthca_dev.h"
-#if defined(EVENT_TRACING)
-#ifdef offsetof
-#undef offsetof
-#endif
-#include "mthca_main.tmh"
-#endif
-#include "mthca_config_reg.h"
-#include "mthca_cmd.h"
-#include "mthca_profile.h"
-#include "mthca_memfree.h"
-
-static const char mthca_version[] =
-       DRV_NAME ": HCA Driver v"
-       DRV_VERSION " (" DRV_RELDATE ")";
-
-static struct mthca_profile default_profile = {
-       1 << 16,                // num_qp
-       4,                                      // rdb_per_qp
-       0,                              // num_srq
-       1 << 16,                // num_cq
-       1 << 13,                // num_mcg
-       1 << 17,                // num_mpt
-       1 << 20,                // num_mtt
-       1 << 15,                // num_udav (Tavor only)
-       0,                                      // num_uar
-       1 << 18,                // uarc_size (Arbel only)
-       1 << 18,                // fmr_reserved_mtts (Tavor only)
-};
-
-/* Types of supported HCA */
-enum __hca_type {
-       TAVOR,                  /* MT23108                        */
-       ARBEL_COMPAT,           /* MT25208 in Tavor compat mode   */
-       ARBEL_NATIVE,           /* MT25218 with extended features */
-       SINAI,                  /* MT25204 */
-       LIVEFISH                /* a burning device */
-};
-
-#define MTHCA_FW_VER(major, minor, subminor) \
-       (((u64) (major) << 32) | ((u64) (minor) << 16) | (u64) (subminor))
-
-static struct {
-       u64 max_unsupported_fw;
-       u64 min_supported_fw;
-       int is_memfree;
-       int is_pcie;
-} mthca_hca_table[] = {
-       { MTHCA_FW_VER(3, 3, 2), MTHCA_FW_VER(3, 4, 0), 0, 0 }, /* TAVOR */
-       { MTHCA_FW_VER(4, 7, 0), MTHCA_FW_VER(4, 7, 400), 0, 1 },       /* ARBEL_COMPAT */
-       { MTHCA_FW_VER(5, 1, 0), MTHCA_FW_VER(5, 1, 400), 1, 1 },       /* ARBEL_NATIVE */
-       { MTHCA_FW_VER(1, 0, 800), MTHCA_FW_VER(1, 1, 0), 1, 1 },       /* SINAI */
-       { MTHCA_FW_VER(0, 0, 0), MTHCA_FW_VER(0, 0, 0), 0, 0 }          /* LIVEFISH */
-};
-
-
-#define HCA(v, d, t) \
-       { PCI_VENDOR_ID_##v,    PCI_DEVICE_ID_MELLANOX_##d, t }
-
-static struct pci_device_id {
-       unsigned                vendor;
-       unsigned                device;
-       enum __hca_type driver_data;
-} mthca_pci_table[] = {
-       HCA(MELLANOX, TAVOR,        TAVOR),
-       HCA(MELLANOX, ARBEL_COMPAT, ARBEL_COMPAT),
-       HCA(MELLANOX, ARBEL,        ARBEL_NATIVE),
-       HCA(MELLANOX, SINAI_OLD,    SINAI),
-       HCA(MELLANOX, SINAI,        SINAI),
-       HCA(TOPSPIN,  TAVOR,        TAVOR),
-       HCA(TOPSPIN,  ARBEL_COMPAT, TAVOR),
-       HCA(TOPSPIN,  ARBEL,        ARBEL_NATIVE),
-       HCA(TOPSPIN,  SINAI_OLD,    SINAI),
-       HCA(TOPSPIN,  SINAI,        SINAI),
-       // live fishes
-       HCA(MELLANOX, TAVOR_BD, LIVEFISH),
-       HCA(MELLANOX, ARBEL_BD,         LIVEFISH),
-       HCA(MELLANOX, SINAI_OLD_BD,     LIVEFISH),
-       HCA(MELLANOX, SINAI_BD,         LIVEFISH),
-       HCA(TOPSPIN, TAVOR_BD,          LIVEFISH),
-       HCA(TOPSPIN, ARBEL_BD,          LIVEFISH),
-       HCA(TOPSPIN, SINAI_OLD_BD,      LIVEFISH),
-       HCA(TOPSPIN, SINAI_BD,          LIVEFISH),
-};
-#define MTHCA_PCI_TABLE_SIZE (sizeof(mthca_pci_table)/sizeof(struct pci_device_id))
-
-// wrapper to driver's hca_tune_pci
-static NTSTATUS mthca_tune_pci(struct mthca_dev *mdev)
-{
-       PDEVICE_OBJECT pdo = mdev->ext->cl_ext.p_self_do;
-       return hca_tune_pci(pdo, &mdev->uplink_info);
-}
-
-int mthca_get_dev_info(struct mthca_dev *mdev, __be64 *node_guid, u32 *hw_id)
-{
-       struct ib_device_attr props;
-       struct ib_device *ib_dev = &mdev->ib_dev;
-       int err = (ib_dev->query_device )(ib_dev, &props );
-
-       if (err) {
-               HCA_PRINT_EV(TRACE_LEVEL_ERROR   ,HCA_DBG_LOW   ,("can't get guid - mthca_query_port() failed (%08X)\n", err ));
-               return err;
-       }
-
-       //TODO: do we need to convert GUID to LE by cl_ntoh64(x) ?
-       *node_guid = ib_dev->node_guid;
-       *hw_id = props.hw_ver;
-       return 0;
-}
-
-static struct pci_device_id * mthca_find_pci_dev(unsigned ven_id, unsigned dev_id)
-{
-       struct pci_device_id *p_id = mthca_pci_table;
-       int i;
-
-       // find p_id (appropriate line in mthca_pci_table)
-       for (i = 0; i < MTHCA_PCI_TABLE_SIZE; ++i, ++p_id) {
-               if (p_id->device == dev_id && p_id->vendor ==  ven_id)
-                       return p_id;
-       }
-       return NULL;
-}
-
-
-static int  mthca_dev_lim(struct mthca_dev *mdev, struct mthca_dev_lim *dev_lim)
-{
-       int err;
-       u8 status;
-
-       err = mthca_QUERY_DEV_LIM(mdev, dev_lim, &status);
-       if (err) {
-               HCA_PRINT_EV(TRACE_LEVEL_ERROR   ,HCA_DBG_LOW   ,("QUERY_DEV_LIM command failed, aborting.\n"));
-               return err;
-       }
-       if (status) {
-               HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("QUERY_DEV_LIM returned status 0x%02x, "
-                         "aborting.\n", status));
-               return -EINVAL;
-       }
-       if (dev_lim->min_page_sz > PAGE_SIZE) {
-               HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("HCA minimum page size of %d bigger than "
-                         "kernel PAGE_SIZE of %ld, aborting.\n",
-                         dev_lim->min_page_sz, PAGE_SIZE));
-               return -ENODEV;
-       }
-       if (dev_lim->num_ports > MTHCA_MAX_PORTS) {
-               HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("HCA has %d ports, but we only support %d, "
-                         "aborting.\n",
-                         dev_lim->num_ports, MTHCA_MAX_PORTS));
-               return -ENODEV;
-       }
-
-       if (dev_lim->uar_size > (int)pci_resource_len(mdev, HCA_BAR_TYPE_UAR)) {
-               HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW , ("HCA reported UAR size of 0x%x bigger than "
-                         "Bar%d size of 0x%lx, aborting.\n",
-                         dev_lim->uar_size, HCA_BAR_TYPE_UAR, 
-                         (unsigned long)pci_resource_len(mdev, HCA_BAR_TYPE_UAR)));
-               return -ENODEV;
-       }
-       
-
-       mdev->limits.num_ports          = dev_lim->num_ports;
-       mdev->limits.vl_cap             = dev_lim->max_vl;
-       mdev->limits.mtu_cap            = dev_lim->max_mtu;
-       mdev->limits.gid_table_len      = dev_lim->max_gids;
-       mdev->limits.pkey_table_len     = dev_lim->max_pkeys;
-       mdev->limits.local_ca_ack_delay = dev_lim->local_ca_ack_delay;
-       mdev->limits.max_sg             = dev_lim->max_sg;
-       mdev->limits.max_wqes           = dev_lim->max_qp_sz;
-       mdev->limits.max_qp_init_rdma   = dev_lim->max_requester_per_qp;
-       mdev->limits.reserved_qps       = dev_lim->reserved_qps;
-       mdev->limits.max_srq_wqes       = dev_lim->max_srq_sz;
-       mdev->limits.reserved_srqs      = dev_lim->reserved_srqs;
-       mdev->limits.reserved_eecs      = dev_lim->reserved_eecs;
-       mdev->limits.max_desc_sz      = dev_lim->max_desc_sz;
-       mdev->limits.max_srq_sge        = mthca_max_srq_sge(mdev);
-       /*
-        * Subtract 1 from the limit because we need to allocate a
-        * spare CQE so the HCA HW can tell the difference between an
-        * empty CQ and a full CQ.
-        */
-       mdev->limits.max_cqes           = dev_lim->max_cq_sz - 1;
-       mdev->limits.reserved_cqs       = dev_lim->reserved_cqs;
-       mdev->limits.reserved_eqs       = dev_lim->reserved_eqs;
-       mdev->limits.reserved_mtts      = dev_lim->reserved_mtts;
-       mdev->limits.reserved_mrws      = dev_lim->reserved_mrws;
-       mdev->limits.reserved_uars      = dev_lim->reserved_uars;
-       mdev->limits.reserved_pds       = dev_lim->reserved_pds;
-       mdev->limits.port_width_cap     = (u8)dev_lim->max_port_width;
-       mdev->limits.page_size_cap      = !(u32)(dev_lim->min_page_sz - 1);
-       mdev->limits.flags                              = dev_lim->flags;
-       mdev->limits.num_avs = mthca_is_memfree(mdev) ? 0 : dev_lim->hca.tavor.max_avs;
-
-       /* IB_DEVICE_RESIZE_MAX_WR not supported by driver.
-          May be doable since hardware supports it for SRQ.
-
-          IB_DEVICE_N_NOTIFY_CQ is supported by hardware but not by driver.
-
-          IB_DEVICE_SRQ_RESIZE is supported by hardware but SRQ is not
-          supported by driver. */
-       mdev->device_cap_flags = IB_DEVICE_CHANGE_PHY_PORT |
-               IB_DEVICE_PORT_ACTIVE_EVENT |
-               IB_DEVICE_SYS_IMAGE_GUID |
-               IB_DEVICE_RC_RNR_NAK_GEN;
-
-       if (dev_lim->flags & DEV_LIM_FLAG_BAD_PKEY_CNTR)
-               mdev->device_cap_flags |= IB_DEVICE_BAD_PKEY_CNTR;
-
-       if (dev_lim->flags & DEV_LIM_FLAG_BAD_QKEY_CNTR)
-               mdev->device_cap_flags |= IB_DEVICE_BAD_QKEY_CNTR;
-
-       if (dev_lim->flags & DEV_LIM_FLAG_RAW_MULTI)
-               mdev->device_cap_flags |= IB_DEVICE_RAW_MULTI;
-
-       if (dev_lim->flags & DEV_LIM_FLAG_AUTO_PATH_MIG)
-               mdev->device_cap_flags |= IB_DEVICE_AUTO_PATH_MIG;
-
-       if (dev_lim->flags & DEV_LIM_FLAG_UD_AV_PORT_ENFORCE)
-               mdev->device_cap_flags |= IB_DEVICE_UD_AV_PORT_ENFORCE;
-
-       if (dev_lim->flags & DEV_LIM_FLAG_SRQ)
-               mdev->mthca_flags |= MTHCA_FLAG_SRQ;
-
-       return 0;
-}
-
-static int  mthca_init_tavor(struct mthca_dev *mdev)
-{
-       u8 status;
-       int err;
-       struct mthca_dev_lim        dev_lim;
-       struct mthca_profile        profile;
-       struct mthca_init_hca_param init_hca;
-
-       err = mthca_SYS_EN(mdev, &status);
-       if (err) {
-               HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("SYS_EN command failed, aborting.\n"));
-               return err;
-       }
-       if (status) {
-               HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("SYS_EN returned status 0x%02x, "
-                         "aborting.\n", status));
-               return -EINVAL;
-       }
-
-       err = mthca_QUERY_FW(mdev, &status);
-       if (err) {
-               HCA_PRINT_EV(TRACE_LEVEL_ERROR   ,HCA_DBG_LOW   ,("QUERY_FW command failed, aborting.\n"));
-               goto err_disable;
-       }
-       if (status) {
-               HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("QUERY_FW returned status 0x%02x, "
-                         "aborting.\n", status));
-               err = -EINVAL;
-               goto err_disable;
-       }
-       err = mthca_QUERY_DDR(mdev, &status);
-       if (err) {
-               HCA_PRINT_EV(TRACE_LEVEL_ERROR   ,HCA_DBG_LOW   ,("QUERY_DDR command failed, aborting.\n"));
-               goto err_disable;
-       }
-       if (status) {
-               HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,( "QUERY_DDR returned status 0x%02x, "
-                         "aborting.\n", status));
-               err = -EINVAL;
-               goto err_disable;
-       }
-
-       err = mthca_dev_lim(mdev, &dev_lim);
-       if (err) {
-               HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,( "QUERY_DEV_LIM command failed, aborting.\n"));
-               goto err_disable;
-       }
-
-       profile = default_profile;
-       profile.num_uar   = dev_lim.uar_size / PAGE_SIZE;
-       profile.uarc_size = 0;
-
-       /* correct default profile */
-       if ( g_profile_qp_num != 0 ) 
-               profile.num_qp = g_profile_qp_num;
-               
-       if ( g_profile_rd_out != 0xffffffff )
-               profile.rdb_per_qp = g_profile_rd_out;
-
-       if (mdev->mthca_flags & MTHCA_FLAG_SRQ)
-               profile.num_srq = dev_lim.max_srqs;
-
-       err = (int)mthca_make_profile(mdev, &profile, &dev_lim, &init_hca);
-       if (err < 0)
-               goto err_disable;
-
-       err = (int)mthca_INIT_HCA(mdev, &init_hca, &status);
-       if (err) {
-               HCA_PRINT_EV(TRACE_LEVEL_ERROR   ,HCA_DBG_LOW   ,("INIT_HCA command failed, aborting.\n"));
-               goto err_disable;
-       }
-       if (status) {
-               HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("INIT_HCA returned status 0x%02x, "
-                         "aborting.\n", status));
-               err = -EINVAL;
-               goto err_disable;
-       }
-
-       return 0;
-
-err_disable:
-       mthca_SYS_DIS(mdev, &status);
-
-       return err;
-}
-
-static int  mthca_load_fw(struct mthca_dev *mdev)
-{
-       u8 status;
-       int err;
-
-       /* FIXME: use HCA-attached memory for FW if present */
-
-       mdev->fw.arbel.fw_icm =
-               mthca_alloc_icm(mdev, mdev->fw.arbel.fw_pages,
-                               GFP_HIGHUSER | __GFP_NOWARN);
-       if (!mdev->fw.arbel.fw_icm) {
-               HCA_PRINT_EV(TRACE_LEVEL_ERROR   ,HCA_DBG_LOW   ,("Couldn't allocate FW area, aborting.\n"));
-               return -ENOMEM;
-       }
-
-       err = mthca_MAP_FA(mdev, mdev->fw.arbel.fw_icm, &status);
-       if (err) {
-               HCA_PRINT_EV(TRACE_LEVEL_ERROR   ,HCA_DBG_LOW   ,("MAP_FA command failed, aborting.\n"));
-               goto err_free;
-       }
-       if (status) {
-               HCA_PRINT_EV(TRACE_LEVEL_ERROR   ,HCA_DBG_LOW   ,("MAP_FA returned status 0x%02x, aborting.\n", status));
-               err = -EINVAL;
-               goto err_free;
-       }
-       err = mthca_RUN_FW(mdev, &status);
-       if (err) {
-               HCA_PRINT_EV(TRACE_LEVEL_ERROR   ,HCA_DBG_LOW   ,("RUN_FW command failed, aborting.\n"));
-               goto err_unmap_fa;
-       }
-       if (status) {
-               HCA_PRINT_EV(TRACE_LEVEL_ERROR   ,HCA_DBG_LOW   ,("RUN_FW returned status 0x%02x, aborting.\n", status));
-               err = -EINVAL;
-               goto err_unmap_fa;
-       }
-
-       return 0;
-
-err_unmap_fa:
-       mthca_UNMAP_FA(mdev, &status);
-
-err_free:
-       mthca_free_icm(mdev, mdev->fw.arbel.fw_icm);
-       return err;
-}
-
-static int  mthca_init_icm(struct mthca_dev *mdev,
-                                   struct mthca_dev_lim *dev_lim,
-                                   struct mthca_init_hca_param *init_hca,
-                                   u64 icm_size)
-{
-       u64 aux_pages;
-       u8 status;
-       int err;
-
-       err = mthca_SET_ICM_SIZE(mdev, icm_size, &aux_pages, &status);
-       if (err) {
-               HCA_PRINT_EV(TRACE_LEVEL_ERROR   ,HCA_DBG_LOW   ,("SET_ICM_SIZE command failed, aborting.\n"));
-               return err;
-       }
-       if (status) {
-               HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("SET_ICM_SIZE returned status 0x%02x, "
-                         "aborting.\n", status));
-               return -EINVAL;
-       }
-
-       HCA_PRINT(TRACE_LEVEL_INFORMATION ,HCA_DBG_LOW , ("%I64d KB of HCA context requires %I64d KB aux memory.\n",
-                 (u64) icm_size >> 10,
-                 (u64) aux_pages << 2));
-
-       mdev->fw.arbel.aux_icm = mthca_alloc_icm(mdev, (int)aux_pages,
-                                                GFP_HIGHUSER | __GFP_NOWARN);
-       if (!mdev->fw.arbel.aux_icm) {
-               HCA_PRINT_EV(TRACE_LEVEL_ERROR   ,HCA_DBG_LOW   ,("Couldn't allocate aux memory, aborting.\n"));
-               return -ENOMEM;
-       }
-
-       err = mthca_MAP_ICM_AUX(mdev, mdev->fw.arbel.aux_icm, &status);
-       if (err) {
-               HCA_PRINT_EV(TRACE_LEVEL_ERROR   ,HCA_DBG_LOW   ,("MAP_ICM_AUX command failed, aborting.\n"));
-               goto err_free_aux;
-       }
-       if (status) {
-               HCA_PRINT_EV(TRACE_LEVEL_ERROR   ,HCA_DBG_LOW   ,("MAP_ICM_AUX returned status 0x%02x, aborting.\n", status));
-               err = -EINVAL;
-               goto err_free_aux;
-       }
-
-       err = mthca_map_eq_icm(mdev, init_hca->eqc_base);
-       if (err) {
-               HCA_PRINT_EV(TRACE_LEVEL_ERROR   ,HCA_DBG_LOW   ,("Failed to map EQ context memory, aborting.\n"));
-               goto err_unmap_aux;
-       }
-
-       mdev->mr_table.mtt_table = mthca_alloc_icm_table(mdev, init_hca->mtt_base,
-                                                        MTHCA_MTT_SEG_SIZE,
-                                                        mdev->limits.num_mtt_segs,
-                                                        mdev->limits.reserved_mtts, 1);
-       if (!mdev->mr_table.mtt_table) {
-               HCA_PRINT_EV(TRACE_LEVEL_ERROR   ,HCA_DBG_LOW   ,("Failed to map MTT context memory, aborting.\n"));
-               err = -ENOMEM;
-               goto err_unmap_eq;
-       }
-
-       mdev->mr_table.mpt_table = mthca_alloc_icm_table(mdev, init_hca->mpt_base,
-                                                        dev_lim->mpt_entry_sz,
-                                                        mdev->limits.num_mpts,
-                                                        mdev->limits.reserved_mrws, 1);
-       if (!mdev->mr_table.mpt_table) {
-               HCA_PRINT_EV(TRACE_LEVEL_ERROR   ,HCA_DBG_LOW   ,("Failed to map MPT context memory, aborting.\n"));
-               err = -ENOMEM;
-               goto err_unmap_mtt;
-       }
-
-       mdev->qp_table.qp_table = mthca_alloc_icm_table(mdev, init_hca->qpc_base,
-                                                       dev_lim->qpc_entry_sz,
-                                                       mdev->limits.num_qps,
-                                                       mdev->limits.reserved_qps, 0);
-       if (!mdev->qp_table.qp_table) {
-               HCA_PRINT_EV(TRACE_LEVEL_ERROR   ,HCA_DBG_LOW   ,("Failed to map QP context memory, aborting.\n"));
-               err = -ENOMEM;
-               goto err_unmap_mpt;
-       }
-
-       mdev->qp_table.eqp_table = mthca_alloc_icm_table(mdev, init_hca->eqpc_base,
-                                                        dev_lim->eqpc_entry_sz,
-                                                        mdev->limits.num_qps,
-                                                        mdev->limits.reserved_qps, 0);
-       if (!mdev->qp_table.eqp_table) {
-               HCA_PRINT_EV(TRACE_LEVEL_ERROR   ,HCA_DBG_LOW   ,("Failed to map EQP context memory, aborting.\n"));
-               err = -ENOMEM;
-               goto err_unmap_qp;
-       }
-
-       mdev->qp_table.rdb_table = mthca_alloc_icm_table(mdev, init_hca->rdb_base,
-                                                        MTHCA_RDB_ENTRY_SIZE,
-                                                        mdev->limits.num_qps <<
-                                                        mdev->qp_table.rdb_shift,
-                                                        0, 0);
-       if (!mdev->qp_table.rdb_table) {
-               HCA_PRINT_EV(TRACE_LEVEL_ERROR   ,HCA_DBG_LOW   ,("Failed to map RDB context memory, aborting\n"));
-               err = -ENOMEM;
-               goto err_unmap_eqp;
-       }
-
-       mdev->cq_table.table = mthca_alloc_icm_table(mdev, init_hca->cqc_base,
-                                                   dev_lim->cqc_entry_sz,
-                                                   mdev->limits.num_cqs,
-                                                   mdev->limits.reserved_cqs, 0);
-       if (!mdev->cq_table.table) {
-               HCA_PRINT_EV(TRACE_LEVEL_ERROR   ,HCA_DBG_LOW   ,("Failed to map CQ context memory, aborting.\n"));
-               err = -ENOMEM;
-               goto err_unmap_rdb;
-       }
-
-       if (mdev->mthca_flags & MTHCA_FLAG_SRQ) {
-               mdev->srq_table.table =
-                       mthca_alloc_icm_table(mdev, init_hca->srqc_base,
-                                             dev_lim->srq_entry_sz,
-                                             mdev->limits.num_srqs,
-                                             mdev->limits.reserved_srqs, 0);
-               if (!mdev->srq_table.table) {
-                       HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("Failed to map SRQ context memory, "
-                                 "aborting.\n"));
-                       err = -ENOMEM;
-                       goto err_unmap_cq;
-               }
-       }
-
-       /*
-        * It's not strictly required, but for simplicity just map the
-        * whole multicast group table now.  The table isn't very big
-        * and it's a lot easier than trying to track ref counts.
-        */
-       mdev->mcg_table.table = mthca_alloc_icm_table(mdev, init_hca->mc_base,
-                                                     MTHCA_MGM_ENTRY_SIZE,
-                                                     mdev->limits.num_mgms +
-                                                     mdev->limits.num_amgms,
-                                                     mdev->limits.num_mgms +
-                                                     mdev->limits.num_amgms,
-                                                     0);
-       if (!mdev->mcg_table.table) {
-               HCA_PRINT_EV(TRACE_LEVEL_ERROR   ,HCA_DBG_LOW   ,("Failed to map MCG context memory, aborting.\n"));
-               err = -ENOMEM;
-               goto err_unmap_srq;
-       }
-
-       return 0;
-
-err_unmap_srq:
-       if (mdev->mthca_flags & MTHCA_FLAG_SRQ)
-               mthca_free_icm_table(mdev, mdev->srq_table.table);
-
-err_unmap_cq:
-       mthca_free_icm_table(mdev, mdev->cq_table.table);
-
-err_unmap_rdb:
-       mthca_free_icm_table(mdev, mdev->qp_table.rdb_table);
-
-err_unmap_eqp:
-       mthca_free_icm_table(mdev, mdev->qp_table.eqp_table);
-
-err_unmap_qp:
-       mthca_free_icm_table(mdev, mdev->qp_table.qp_table);
-
-err_unmap_mpt:
-       mthca_free_icm_table(mdev, mdev->mr_table.mpt_table);
-
-err_unmap_mtt:
-       mthca_free_icm_table(mdev, mdev->mr_table.mtt_table);
-
-err_unmap_eq:
-       mthca_unmap_eq_icm(mdev);
-
-err_unmap_aux:
-       mthca_UNMAP_ICM_AUX(mdev, &status);
-
-err_free_aux:
-       mthca_free_icm(mdev, mdev->fw.arbel.aux_icm);
-
-       return err;
-}
-
-static int  mthca_init_arbel(struct mthca_dev *mdev)
-{
-       struct mthca_dev_lim        dev_lim;
-       struct mthca_profile        profile;
-       struct mthca_init_hca_param init_hca;
-       u64 icm_size;
-       u8 status;
-       int err;
-
-       err = mthca_QUERY_FW(mdev, &status);
-       if (err) {
-               HCA_PRINT_EV(TRACE_LEVEL_ERROR   ,HCA_DBG_LOW   ,("QUERY_FW command failed, aborting.\n"));
-               return err;
-       }
-       if (status) {
-               HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("QUERY_FW returned status 0x%02x, "
-                         "aborting.\n", status));
-               return -EINVAL;
-       }
-
-       err = mthca_ENABLE_LAM(mdev, &status);
-       if (err) {
-               HCA_PRINT_EV(TRACE_LEVEL_ERROR   ,HCA_DBG_LOW   ,("ENABLE_LAM command failed, aborting.\n"));
-               return err;
-       }
-       if (status == MTHCA_CMD_STAT_LAM_NOT_PRE) {
-               HCA_PRINT(TRACE_LEVEL_INFORMATION   ,HCA_DBG_LOW   ,("No HCA-attached memory (running in MemFree mode)\n"));
-               mdev->mthca_flags |= MTHCA_FLAG_NO_LAM;
-       } else if (status) {
-               HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("ENABLE_LAM returned status 0x%02x, "
-                         "aborting.\n", status));
-               return -EINVAL;
-       }
-
-       err = mthca_load_fw(mdev);
-       if (err) {
-               HCA_PRINT_EV(TRACE_LEVEL_ERROR   ,HCA_DBG_LOW   ,("Failed to start FW, aborting.\n"));
-               goto err_disable;
-       }
-
-       err = mthca_dev_lim(mdev, &dev_lim);
-       if (err) {
-               HCA_PRINT_EV(TRACE_LEVEL_ERROR   ,HCA_DBG_LOW   ,("QUERY_DEV_LIM command failed, aborting.\n"));
-               goto err_stop_fw;
-       }
-
-       profile = default_profile;
-       profile.num_uar  = dev_lim.uar_size / PAGE_SIZE;
-       profile.num_udav = 0;
-       if (mdev->mthca_flags & MTHCA_FLAG_SRQ)
-               profile.num_srq = dev_lim.max_srqs;
-
-       /* correct default profile */
-       if ( g_profile_qp_num != 0 ) 
-               profile.num_qp = g_profile_qp_num;
-               
-       if ( g_profile_rd_out != 0xffffffff )
-               profile.rdb_per_qp = g_profile_rd_out;
-
-       RtlZeroMemory( &init_hca, sizeof(init_hca));
-       icm_size = mthca_make_profile(mdev, &profile, &dev_lim, &init_hca);
-       if ((int) icm_size < 0) {
-               err = (int)icm_size;
-               goto err_stop_fw;
-       }
-
-       err = mthca_init_icm(mdev, &dev_lim, &init_hca, icm_size);
-       if (err)
-               goto err_stop_fw;
-
-       err = mthca_INIT_HCA(mdev, &init_hca, &status);
-       if (err) {
-               HCA_PRINT_EV(TRACE_LEVEL_ERROR   ,HCA_DBG_LOW   ,("INIT_HCA command failed, aborting.\n"));
-               goto err_free_icm;
-       }
-       if (status) {
-               HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("INIT_HCA returned status 0x%02x, "
-                         "aborting.\n", status));
-               err = -EINVAL;
-               goto err_free_icm;
-       }
-
-       return 0;
-
-err_free_icm:
-       if (mdev->mthca_flags & MTHCA_FLAG_SRQ)
-               mthca_free_icm_table(mdev, mdev->srq_table.table);
-       mthca_free_icm_table(mdev, mdev->cq_table.table);
-       mthca_free_icm_table(mdev, mdev->qp_table.rdb_table);
-       mthca_free_icm_table(mdev, mdev->qp_table.eqp_table);
-       mthca_free_icm_table(mdev, mdev->qp_table.qp_table);
-       mthca_free_icm_table(mdev, mdev->mr_table.mpt_table);
-       mthca_free_icm_table(mdev, mdev->mr_table.mtt_table);
-       mthca_unmap_eq_icm(mdev);
-
-       mthca_UNMAP_ICM_AUX(mdev, &status);
-       mthca_free_icm(mdev, mdev->fw.arbel.aux_icm);
-
-err_stop_fw:
-       mthca_UNMAP_FA(mdev, &status);
-       mthca_free_icm(mdev, mdev->fw.arbel.fw_icm);
-
-err_disable:
-       if (!(mdev->mthca_flags & MTHCA_FLAG_NO_LAM))
-               mthca_DISABLE_LAM(mdev, &status);
-
-       return err;
-}
-
-static void mthca_close_hca(struct mthca_dev *mdev)
-{
-       u8 status;
-
-       mthca_CLOSE_HCA(mdev, 0, &status);
-
-       if (mthca_is_memfree(mdev)) {
-               if (mdev->mthca_flags & MTHCA_FLAG_SRQ)
-                       mthca_free_icm_table(mdev, mdev->srq_table.table);
-               mthca_free_icm_table(mdev, mdev->cq_table.table);
-               mthca_free_icm_table(mdev, mdev->qp_table.rdb_table);
-               mthca_free_icm_table(mdev, mdev->qp_table.eqp_table);
-               mthca_free_icm_table(mdev, mdev->qp_table.qp_table);
-               mthca_free_icm_table(mdev, mdev->mr_table.mpt_table);
-               mthca_free_icm_table(mdev, mdev->mr_table.mtt_table);
-               mthca_free_icm_table(mdev, mdev->mcg_table.table);
-               mthca_unmap_eq_icm(mdev);
-
-               mthca_UNMAP_ICM_AUX(mdev, &status);
-               mthca_free_icm(mdev, mdev->fw.arbel.aux_icm);
-
-               mthca_UNMAP_FA(mdev, &status);
-               mthca_free_icm(mdev, mdev->fw.arbel.fw_icm);
-
-               if (!(mdev->mthca_flags & MTHCA_FLAG_NO_LAM))
-                       mthca_DISABLE_LAM(mdev, &status);
-       } else
-               mthca_SYS_DIS(mdev, &status);
-}
-
-static int  mthca_init_hca(struct mthca_dev *mdev)
-{
-       u8 status;
-       int err;
-       struct mthca_adapter adapter;
-
-       if (mthca_is_memfree(mdev))
-               err = mthca_init_arbel(mdev);
-       else
-               err = mthca_init_tavor(mdev);
-
-       if (err)
-               return err;
-
-       err = mthca_QUERY_ADAPTER(mdev, &adapter, &status);
-       if (err) {
-               HCA_PRINT_EV(TRACE_LEVEL_ERROR   ,HCA_DBG_LOW   ,("QUERY_ADAPTER command failed, aborting.\n"));
-               goto err_close;
-       }
-       if (status) {
-               HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("QUERY_ADAPTER returned status 0x%02x, "
-                         "aborting.\n", status));
-               err = -EINVAL;
-               goto err_close;
-       }
-
-       mdev->eq_table.inta_pin = adapter.inta_pin;
-       mdev->rev_id            = adapter.revision_id;
-       memcpy(mdev->board_id, adapter.board_id, sizeof mdev->board_id);
-
-       return 0;
-
-err_close:
-       mthca_close_hca(mdev);
-       return err;
-}
-
-static int  mthca_setup_hca(struct mthca_dev *mdev)
-{
-       int err;
-       u8 status;
-
-       MTHCA_INIT_DOORBELL_LOCK(&mdev->doorbell_lock);
-
-       err = mthca_init_uar_table(mdev);
-       if (err) {
-               HCA_PRINT_EV(TRACE_LEVEL_ERROR,HCA_DBG_LOW,("Failed to initialize "
-                         "user access region table, aborting.\n"));
-               return err;
-       }
-
-       err = mthca_uar_alloc(mdev, &mdev->driver_uar);
-       if (err) {
-               HCA_PRINT_EV(TRACE_LEVEL_ERROR,HCA_DBG_LOW,("Failed to allocate driver access region, "
-                         "aborting.\n"));
-               goto err_uar_table_free;
-       }
-
-       mdev->kar = ioremap((io_addr_t)mdev->driver_uar.pfn << PAGE_SHIFT, PAGE_SIZE,&mdev->kar_size);
-       if (!mdev->kar) {
-               HCA_PRINT_EV(TRACE_LEVEL_ERROR,HCA_DBG_LOW,("Couldn't map kernel access region, "
-                         "aborting.\n"));
-               err = -ENOMEM;
-               goto err_uar_free;
-       }
-
-       err = mthca_init_pd_table(mdev);
-       if (err) {
-               HCA_PRINT_EV(TRACE_LEVEL_ERROR,HCA_DBG_LOW,("Failed to initialize "
-                         "protection domain table, aborting.\n"));
-               goto err_kar_unmap;
-       }
-
-       err = mthca_init_mr_table(mdev);
-       if (err) {
-               HCA_PRINT_EV(TRACE_LEVEL_ERROR,HCA_DBG_LOW,("Failed to initialize "
-                         "memory region table, aborting.\n"));
-               goto err_pd_table_free;
-       }
-
-       err = mthca_pd_alloc(mdev, 1, &mdev->driver_pd);
-       if (err) {
-               HCA_PRINT_EV(TRACE_LEVEL_ERROR,HCA_DBG_LOW,("Failed to create driver PD, "
-                         "aborting.\n"));
-               goto err_mr_table_free;
-       }
-
-       err = mthca_init_eq_table(mdev);
-       if (err) {
-               HCA_PRINT_EV(TRACE_LEVEL_ERROR,HCA_DBG_LOW, ("Failed to initialize "
-                         "event queue table, aborting.\n"));
-               goto err_pd_free;
-       }
-
-       err = mthca_cmd_use_events(mdev);
-       if (err) {
-               HCA_PRINT_EV(TRACE_LEVEL_ERROR,HCA_DBG_LOW,("Failed to switch to event-driven "
-                         "firmware commands, aborting.\n"));
-               goto err_eq_table_free;
-       }
-
-       err = mthca_NOP(mdev, &status);
-       if (err || status) {
-               HCA_PRINT_EV(TRACE_LEVEL_ERROR  ,HCA_DBG_LOW  ,("NOP command failed to generate interrupt, aborting.\n"));
-               if (mdev->mthca_flags & (MTHCA_FLAG_MSI | MTHCA_FLAG_MSI_X)){
-                       HCA_PRINT_EV(TRACE_LEVEL_ERROR  ,HCA_DBG_LOW  ,("Try again with MSI/MSI-X disabled.\n"));
-               }else{
-                       HCA_PRINT_EV(TRACE_LEVEL_ERROR  ,HCA_DBG_LOW  ,("BIOS or ACPI interrupt routing problem?\n"));
-               }
-
-               goto err_cmd_poll;
-       }
-
-       HCA_PRINT(TRACE_LEVEL_VERBOSE  ,HCA_DBG_LOW  ,("NOP command IRQ test passed\n"));
-
-       err = mthca_init_cq_table(mdev);
-       if (err) {
-               HCA_PRINT_EV(TRACE_LEVEL_ERROR,HCA_DBG_LOW,("Failed to initialize "
-                         "completion queue table, aborting.\n"));
-               goto err_cmd_poll;
-       }
-
-       err = mthca_init_srq_table(mdev);
-       if (err) {
-               HCA_PRINT_EV(TRACE_LEVEL_ERROR,HCA_DBG_LOW,("Failed to initialize "
-                         "shared receive queue table, aborting.\n"));
-               goto err_cq_table_free;
-       }
-
-       err = mthca_init_qp_table(mdev);
-       if (err) {
-               HCA_PRINT_EV(TRACE_LEVEL_ERROR,HCA_DBG_LOW, ("Failed to initialize "
-                         "queue pair table, aborting.\n"));
-               goto err_srq_table_free;
-       }
-
-       err = mthca_init_av_table(mdev);
-       if (err) {
-               HCA_PRINT_EV(TRACE_LEVEL_ERROR,HCA_DBG_LOW,("Failed to initialize "
-                         "address vector table, aborting.\n"));
-               goto err_qp_table_free;
-       }
-
-       err = mthca_init_mcg_table(mdev);
-       if (err) {
-               HCA_PRINT_EV(TRACE_LEVEL_ERROR,HCA_DBG_LOW,("Failed to initialize "
-                         "multicast group table, aborting.\n"));
-               goto err_av_table_free;
-       }
-
-       return 0;
-
-err_av_table_free:
-       mthca_cleanup_av_table(mdev);
-
-err_qp_table_free:
-       mthca_cleanup_qp_table(mdev);
-
-err_srq_table_free:
-       mthca_cleanup_srq_table(mdev);
-
-err_cq_table_free:
-       mthca_cleanup_cq_table(mdev);
-
-err_cmd_poll:
-       mthca_cmd_use_polling(mdev);
-
-err_eq_table_free:
-       mthca_cleanup_eq_table(mdev);
-
-err_pd_free:
-       mthca_pd_free(mdev, &mdev->driver_pd);
-
-err_mr_table_free:
-       mthca_cleanup_mr_table(mdev);
-
-err_pd_table_free:
-       mthca_cleanup_pd_table(mdev);
-
-err_kar_unmap:
-       iounmap(mdev->kar, mdev->kar_size);
-
-err_uar_free:
-       mthca_uar_free(mdev, &mdev->driver_uar);
-
-err_uar_table_free:
-       mthca_cleanup_uar_table(mdev);
-       return err;
-}
-
-
-static int     mthca_check_fw(struct mthca_dev *mdev, struct pci_device_id *p_id)
-{
-       int err = 0;
-       
-       if (mdev->fw_ver < mthca_hca_table[p_id->driver_data].max_unsupported_fw) {
-               HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("HCA FW version %d.%d.%d is not supported. Use %d.%d.%d or higher.\n",
-                          (int) (mdev->fw_ver >> 32), (int) (mdev->fw_ver >> 16) & 0xffff,
-                          (int) (mdev->fw_ver & 0xffff),
-                          (int) (mthca_hca_table[p_id->driver_data].min_supported_fw >> 32),
-                          (int) (mthca_hca_table[p_id->driver_data].min_supported_fw >> 16) & 0xffff,
-                          (int) (mthca_hca_table[p_id->driver_data].min_supported_fw & 0xffff)));
-               err = -EINVAL;
-       }
-       else 
-       if (mdev->fw_ver < mthca_hca_table[p_id->driver_data].min_supported_fw) {
-               HCA_PRINT_EV(TRACE_LEVEL_WARNING ,HCA_DBG_LOW ,
-                       ("The HCA FW version is %d.%d.%d, which is not the latest one. \n"
-                       "If you meet any issues with the HCA please first try to upgrade the FW to version %d.%d.%d or higher.\n",
-                                (int) (mdev->fw_ver >> 32), (int) (mdev->fw_ver >> 16) & 0xffff,
-                                (int) (mdev->fw_ver & 0xffff),
-                                (int) (mthca_hca_table[p_id->driver_data].min_supported_fw >> 32),
-                                (int) (mthca_hca_table[p_id->driver_data].min_supported_fw >> 16) & 0xffff,
-                                (int) (mthca_hca_table[p_id->driver_data].min_supported_fw & 0xffff)));
-       }
-       else {
-               HCA_PRINT(TRACE_LEVEL_INFORMATION ,HCA_DBG_LOW ,("Current HCA FW version is %d.%d.%d. \n",
-                                (int) (mdev->fw_ver >> 32), (int) (mdev->fw_ver >> 16) & 0xffff,
-                                (int) (mdev->fw_ver & 0xffff)));
-       }
-
-       return err;
-}
-
-NTSTATUS mthca_init_one(hca_dev_ext_t *ext)
-{
-       static int mthca_version_printed = 0;
-       int err;
-       NTSTATUS status;
-       struct mthca_dev *mdev;
-       struct pci_device_id *p_id;
-
-       /* print version */
-       if (!mthca_version_printed) {
-               HCA_PRINT(TRACE_LEVEL_INFORMATION ,HCA_DBG_LOW ,("%s\n", mthca_version));
-               ++mthca_version_printed;
-       }
-
-       /* find the type of device */
-       p_id = mthca_find_pci_dev(
-               (unsigned)ext->hcaConfig.VendorID,
-               (unsigned)ext->hcaConfig.DeviceID);
-       if (p_id == NULL) {
-               status = STATUS_NO_SUCH_DEVICE;
-               goto end;
-       }
-
-run_as_livefish:
-       /* allocate mdev structure */
-       mdev = kzalloc(sizeof *mdev, GFP_KERNEL);
-       if (!mdev) {
-               // can't use HCA_PRINT_EV here !
-               HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("Device struct alloc failed, "
-                       "aborting.\n"));
-               status = STATUS_INSUFFICIENT_RESOURCES;
-               goto end;
-       }
-        
-       /* set some fields */
-       mdev->ext = ext;                /* pointer to DEVICE OBJECT extension */
-       mdev->hca_type = p_id->driver_data;
-       mdev->ib_dev.mdev = mdev;
-       if (p_id->driver_data == LIVEFISH)
-               mdev->mthca_flags |= MTHCA_FLAG_LIVEFISH;
-       if (mthca_is_livefish(mdev))
-               goto done;
-       if (ext->hca_hidden)
-               mdev->mthca_flags |= MTHCA_FLAG_DDR_HIDDEN;
-       if (mthca_hca_table[p_id->driver_data].is_memfree)
-               mdev->mthca_flags |= MTHCA_FLAG_MEMFREE;
-       if (mthca_hca_table[p_id->driver_data].is_pcie)
-               mdev->mthca_flags |= MTHCA_FLAG_PCIE;
-       
-//TODO: after we have a FW, capable of reset, 
-// write a routine, that only presses the button
-
-       /*
-        * Now reset the HCA before we touch the PCI capabilities or
-        * attempt a firmware command, since a boot ROM may have left
-        * the HCA in an undefined state.
-        */
-       status = hca_reset( mdev->ext->cl_ext.p_self_do, p_id->driver_data == TAVOR );
-       if ( !NT_SUCCESS( status ) ) {
-               HCA_PRINT_EV(TRACE_LEVEL_ERROR   ,HCA_DBG_LOW   ,("Failed to reset HCA, aborting.\n"));
-               goto err_free_dev;
-       }
-
-       if (mthca_cmd_init(mdev)) {
-               HCA_PRINT_EV(TRACE_LEVEL_ERROR   ,HCA_DBG_LOW   ,("Failed to init command interface, aborting.\n"));
-               status = STATUS_DEVICE_DATA_ERROR;
-               goto err_free_dev;
-       }
-
-       status = mthca_tune_pci(mdev);
-       if ( !NT_SUCCESS( status ) ) {
-               goto err_cmd;
-       }
-
-       err = mthca_init_hca(mdev); 
-       if (err) {
-               status = STATUS_UNSUCCESSFUL;
-               goto err_cmd;
-       }
-
-       err = mthca_check_fw(mdev, p_id);
-       if (err) {
-               status = STATUS_UNSUCCESSFUL;
-               goto err_close;
-       }
-
-       err = mthca_setup_hca(mdev);
-       if (err) {
-               status = STATUS_UNSUCCESSFUL;
-               goto err_close;
-       }
-
-       err = mthca_register_device(mdev);
-       if (err) {
-               status = STATUS_UNSUCCESSFUL;
-               goto err_cleanup;
-       }
-
-       done:
-       ext->hca.mdev = mdev;
-       mdev->state = MTHCA_DEV_INITIALIZED;
-       return 0;
-
-err_cleanup:
-       mthca_cleanup_mcg_table(mdev);
-       mthca_cleanup_av_table(mdev);
-       mthca_cleanup_qp_table(mdev);
-       mthca_cleanup_srq_table(mdev);
-       mthca_cleanup_cq_table(mdev);
-       mthca_cmd_use_polling(mdev);
-       mthca_cleanup_eq_table(mdev);
-
-       mthca_pd_free(mdev, &mdev->driver_pd);
-
-       mthca_cleanup_mr_table(mdev);
-       mthca_cleanup_pd_table(mdev);
-       mthca_cleanup_uar_table(mdev);
-
-err_close:
-       mthca_close_hca(mdev);
-
-err_cmd:
-       mthca_cmd_cleanup(mdev);
-
-err_free_dev:
-       kfree(mdev);
-
-       /* we failed device initialization - try to simulate "livefish" device to facilitate using FW burning tools */
-       {
-               USHORT dev_id = ext->hcaConfig.DeviceID;
-               
-               if (dev_id == PCI_DEVICE_ID_MELLANOX_ARBEL)
-                       dev_id = PCI_DEVICE_ID_MELLANOX_ARBEL_COMPAT;
-               p_id = mthca_find_pci_dev( (unsigned)ext->hcaConfig.VendorID, dev_id + 1 );
-               if (p_id == NULL) {
-                       status = STATUS_NO_SUCH_DEVICE;
-                       goto end;
-               }
-               goto run_as_livefish;
-       }
-       
-end:
-       return status;
-}
-
-void mthca_remove_one(hca_dev_ext_t *ext)
-{
-       struct mthca_dev *mdev = ext->hca.mdev;
-       u8 status;
-       int p;
-
-       ext->hca.mdev = NULL;
-       if (mdev) {
-               mdev->state = MTHCA_DEV_UNINITIALIZED;
-               if (mthca_is_livefish(mdev))
-                       goto done;
-               mthca_unregister_device(mdev);
-
-               for (p = 1; p <= mdev->limits.num_ports; ++p)
-                       mthca_CLOSE_IB(mdev, p, &status);
-
-               mthca_cleanup_mcg_table(mdev);
-               mthca_cleanup_av_table(mdev);
-               mthca_cleanup_qp_table(mdev);
-               mthca_cleanup_srq_table(mdev);
-               mthca_cleanup_cq_table(mdev);
-               mthca_cmd_use_polling(mdev);
-               mthca_cleanup_eq_table(mdev);
-               mthca_pd_free(mdev, &mdev->driver_pd);
-               mthca_cleanup_mr_table(mdev);
-               mthca_cleanup_pd_table(mdev);
-               iounmap(mdev->kar, mdev->kar_size);
-               mthca_uar_free(mdev, &mdev->driver_uar);
-               mthca_cleanup_uar_table(mdev);
-               mthca_close_hca(mdev);
-               mthca_cmd_cleanup(mdev);
-done:
-               kfree(mdev);
-       }
-}
-
-
-
+/*\r
+ * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.\r
+ * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.\r
+ * Copyright (c) 2005 Mellanox Technologies. All rights reserved.\r
+ *\r
+ * This software is available to you under a choice of one of two\r
+ * licenses.  You may choose to be licensed under the terms of the GNU\r
+ * General Public License (GPL) Version 2, available from the file\r
+ * COPYING in the main directory of this source tree, or the\r
+ * OpenIB.org BSD license below:\r
+ *\r
+ *     Redistribution and use in source and binary forms, with or\r
+ *     without modification, are permitted provided that the following\r
+ *     conditions are met:\r
+ *\r
+ *      - Redistributions of source code must retain the above\r
+ *        copyright notice, this list of conditions and the following\r
+ *        disclaimer.\r
+ *\r
+ *      - Redistributions in binary form must reproduce the above\r
+ *        copyright notice, this list of conditions and the following\r
+ *        disclaimer in the documentation and/or other materials\r
+ *        provided with the distribution.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ *\r
+ * $Id$\r
+ */\r
+\r
+#include "mthca_dev.h"\r
+#if defined(EVENT_TRACING)\r
+#ifdef offsetof\r
+#undef offsetof\r
+#endif\r
+#include "mthca_main.tmh"\r
+#endif\r
+#include "mthca_config_reg.h"\r
+#include "mthca_cmd.h"\r
+#include "mthca_profile.h"\r
+#include "mthca_memfree.h"\r
+\r
+static const char mthca_version[] =\r
+       DRV_NAME ": HCA Driver v"\r
+       DRV_VERSION " (" DRV_RELDATE ")";\r
+\r
+static struct mthca_profile default_profile = {\r
+       1 << 16,                // num_qp\r
+       4,                                      // rdb_per_qp\r
+       0,                              // num_srq\r
+       1 << 16,                // num_cq\r
+       1 << 13,                // num_mcg\r
+       1 << 17,                // num_mpt\r
+       1 << 20,                // num_mtt\r
+       1 << 15,                // num_udav (Tavor only)\r
+       0,                                      // num_uar\r
+       1 << 18,                // uarc_size (Arbel only)\r
+       1 << 18,                // fmr_reserved_mtts (Tavor only)\r
+};\r
+\r
+/* Types of supported HCA */\r
+enum __hca_type {\r
+       TAVOR,                  /* MT23108                        */\r
+       ARBEL_COMPAT,           /* MT25208 in Tavor compat mode   */\r
+       ARBEL_NATIVE,           /* MT25218 with extended features */\r
+       SINAI,                  /* MT25204 */\r
+       LIVEFISH                /* a burning device */\r
+};\r
+\r
+#define MTHCA_FW_VER(major, minor, subminor) \\r
+       (((u64) (major) << 32) | ((u64) (minor) << 16) | (u64) (subminor))\r
+\r
+static struct {\r
+       u64 max_unsupported_fw;\r
+       u64 min_supported_fw;\r
+       int is_memfree;\r
+       int is_pcie;\r
+} mthca_hca_table[] = {\r
+       { MTHCA_FW_VER(3, 3, 2), MTHCA_FW_VER(3, 4, 0), 0, 0 }, /* TAVOR */\r
+       { MTHCA_FW_VER(4, 7, 0), MTHCA_FW_VER(4, 7, 400), 0, 1 },       /* ARBEL_COMPAT */\r
+       { MTHCA_FW_VER(5, 1, 0), MTHCA_FW_VER(5, 1, 400), 1, 1 },       /* ARBEL_NATIVE */\r
+       { MTHCA_FW_VER(1, 0, 800), MTHCA_FW_VER(1, 1, 0), 1, 1 },       /* SINAI */\r
+       { MTHCA_FW_VER(0, 0, 0), MTHCA_FW_VER(0, 0, 0), 0, 0 }          /* LIVEFISH */\r
+};\r
+\r
+\r
+#define HCA(v, d, t) \\r
+       { PCI_VENDOR_ID_##v,    PCI_DEVICE_ID_MELLANOX_##d, t }\r
+\r
+static struct pci_device_id {\r
+       unsigned                vendor;\r
+       unsigned                device;\r
+       enum __hca_type driver_data;\r
+} mthca_pci_table[] = {\r
+       HCA(MELLANOX, TAVOR,        TAVOR),\r
+       HCA(MELLANOX, ARBEL_COMPAT, ARBEL_COMPAT),\r
+       HCA(MELLANOX, ARBEL,        ARBEL_NATIVE),\r
+       HCA(MELLANOX, SINAI_OLD,    SINAI),\r
+       HCA(MELLANOX, SINAI,        SINAI),\r
+       HCA(TOPSPIN,  TAVOR,        TAVOR),\r
+       HCA(TOPSPIN,  ARBEL_COMPAT, TAVOR),\r
+       HCA(TOPSPIN,  ARBEL,        ARBEL_NATIVE),\r
+       HCA(TOPSPIN,  SINAI_OLD,    SINAI),\r
+       HCA(TOPSPIN,  SINAI,        SINAI),\r
+       // live fishes\r
+       HCA(MELLANOX, TAVOR_BD, LIVEFISH),\r
+       HCA(MELLANOX, ARBEL_BD,         LIVEFISH),\r
+       HCA(MELLANOX, SINAI_OLD_BD,     LIVEFISH),\r
+       HCA(MELLANOX, SINAI_BD,         LIVEFISH),\r
+       HCA(TOPSPIN, TAVOR_BD,          LIVEFISH),\r
+       HCA(TOPSPIN, ARBEL_BD,          LIVEFISH),\r
+       HCA(TOPSPIN, SINAI_OLD_BD,      LIVEFISH),\r
+       HCA(TOPSPIN, SINAI_BD,          LIVEFISH),\r
+};\r
+#define MTHCA_PCI_TABLE_SIZE (sizeof(mthca_pci_table)/sizeof(struct pci_device_id))\r
+\r
+// wrapper to driver's hca_tune_pci\r
+static NTSTATUS mthca_tune_pci(struct mthca_dev *mdev)\r
+{\r
+       PDEVICE_OBJECT pdo = mdev->ext->cl_ext.p_self_do;\r
+       return hca_tune_pci(pdo, &mdev->uplink_info);\r
+}\r
+\r
+int mthca_get_dev_info(struct mthca_dev *mdev, __be64 *node_guid, u32 *hw_id)\r
+{\r
+       struct ib_device_attr props;\r
+       struct ib_device *ib_dev = &mdev->ib_dev;\r
+       int err = (ib_dev->query_device )(ib_dev, &props );\r
+\r
+       if (err) {\r
+               HCA_PRINT_EV(TRACE_LEVEL_ERROR   ,HCA_DBG_LOW   ,("can't get guid - mthca_query_port() failed (%08X)\n", err ));\r
+               return err;\r
+       }\r
+\r
+       //TODO: do we need to convert GUID to LE by cl_ntoh64(x) ?\r
+       *node_guid = ib_dev->node_guid;\r
+       *hw_id = props.hw_ver;\r
+       return 0;\r
+}\r
+\r
+static struct pci_device_id * mthca_find_pci_dev(unsigned ven_id, unsigned dev_id)\r
+{\r
+       struct pci_device_id *p_id = mthca_pci_table;\r
+       int i;\r
+\r
+       // find p_id (appropriate line in mthca_pci_table)\r
+       for (i = 0; i < MTHCA_PCI_TABLE_SIZE; ++i, ++p_id) {\r
+               if (p_id->device == dev_id && p_id->vendor ==  ven_id)\r
+                       return p_id;\r
+       }\r
+       return NULL;\r
+}\r
+\r
+\r
+static int  mthca_dev_lim(struct mthca_dev *mdev, struct mthca_dev_lim *dev_lim)\r
+{\r
+       int err;\r
+       u8 status;\r
+\r
+       err = mthca_QUERY_DEV_LIM(mdev, dev_lim, &status);\r
+       if (err) {\r
+               HCA_PRINT_EV(TRACE_LEVEL_ERROR   ,HCA_DBG_LOW   ,("QUERY_DEV_LIM command failed, aborting.\n"));\r
+               return err;\r
+       }\r
+       if (status) {\r
+               HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("QUERY_DEV_LIM returned status 0x%02x, "\r
+                         "aborting.\n", status));\r
+               return -EINVAL;\r
+       }\r
+       if (dev_lim->min_page_sz > PAGE_SIZE) {\r
+               HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("HCA minimum page size of %d bigger than "\r
+                         "kernel PAGE_SIZE of %ld, aborting.\n",\r
+                         dev_lim->min_page_sz, PAGE_SIZE));\r
+               return -ENODEV;\r
+       }\r
+       if (dev_lim->num_ports > MTHCA_MAX_PORTS) {\r
+               HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("HCA has %d ports, but we only support %d, "\r
+                         "aborting.\n",\r
+                         dev_lim->num_ports, MTHCA_MAX_PORTS));\r
+               return -ENODEV;\r
+       }\r
+\r
+       if (dev_lim->uar_size > (int)pci_resource_len(mdev, HCA_BAR_TYPE_UAR)) {\r
+               HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW , ("HCA reported UAR size of 0x%x bigger than "\r
+                         "Bar%d size of 0x%lx, aborting.\n",\r
+                         dev_lim->uar_size, HCA_BAR_TYPE_UAR, \r
+                         (unsigned long)pci_resource_len(mdev, HCA_BAR_TYPE_UAR)));\r
+               return -ENODEV;\r
+       }\r
+       \r
+\r
+       mdev->limits.num_ports          = dev_lim->num_ports;\r
+       mdev->limits.vl_cap             = dev_lim->max_vl;\r
+       mdev->limits.mtu_cap            = dev_lim->max_mtu;\r
+       mdev->limits.gid_table_len      = dev_lim->max_gids;\r
+       mdev->limits.pkey_table_len     = dev_lim->max_pkeys;\r
+       mdev->limits.local_ca_ack_delay = dev_lim->local_ca_ack_delay;\r
+       mdev->limits.max_sg             = dev_lim->max_sg;\r
+       mdev->limits.max_wqes           = dev_lim->max_qp_sz;\r
+       mdev->limits.max_qp_init_rdma   = dev_lim->max_requester_per_qp;\r
+       mdev->limits.reserved_qps       = dev_lim->reserved_qps;\r
+       mdev->limits.max_srq_wqes       = dev_lim->max_srq_sz;\r
+       mdev->limits.reserved_srqs      = dev_lim->reserved_srqs;\r
+       mdev->limits.reserved_eecs      = dev_lim->reserved_eecs;\r
+       mdev->limits.max_desc_sz      = dev_lim->max_desc_sz;\r
+       mdev->limits.max_srq_sge        = mthca_max_srq_sge(mdev);\r
+       /*\r
+        * Subtract 1 from the limit because we need to allocate a\r
+        * spare CQE so the HCA HW can tell the difference between an\r
+        * empty CQ and a full CQ.\r
+        */\r
+       mdev->limits.max_cqes           = dev_lim->max_cq_sz - 1;\r
+       mdev->limits.reserved_cqs       = dev_lim->reserved_cqs;\r
+       mdev->limits.reserved_eqs       = dev_lim->reserved_eqs;\r
+       mdev->limits.reserved_mtts      = dev_lim->reserved_mtts;\r
+       mdev->limits.reserved_mrws      = dev_lim->reserved_mrws;\r
+       mdev->limits.reserved_uars      = dev_lim->reserved_uars;\r
+       mdev->limits.reserved_pds       = dev_lim->reserved_pds;\r
+       mdev->limits.port_width_cap     = (u8)dev_lim->max_port_width;\r
+       mdev->limits.page_size_cap      = !(u32)(dev_lim->min_page_sz - 1);\r
+       mdev->limits.flags                              = dev_lim->flags;\r
+       mdev->limits.num_avs = mthca_is_memfree(mdev) ? 0 : dev_lim->hca.tavor.max_avs;\r
+\r
+       /* IB_DEVICE_RESIZE_MAX_WR not supported by driver.\r
+          May be doable since hardware supports it for SRQ.\r
+\r
+          IB_DEVICE_N_NOTIFY_CQ is supported by hardware but not by driver.\r
+\r
+          IB_DEVICE_SRQ_RESIZE is supported by hardware but SRQ is not\r
+          supported by driver. */\r
+       mdev->device_cap_flags = IB_DEVICE_CHANGE_PHY_PORT |\r
+               IB_DEVICE_PORT_ACTIVE_EVENT |\r
+               IB_DEVICE_SYS_IMAGE_GUID |\r
+               IB_DEVICE_RC_RNR_NAK_GEN;\r
+\r
+       if (dev_lim->flags & DEV_LIM_FLAG_BAD_PKEY_CNTR)\r
+               mdev->device_cap_flags |= IB_DEVICE_BAD_PKEY_CNTR;\r
+\r
+       if (dev_lim->flags & DEV_LIM_FLAG_BAD_QKEY_CNTR)\r
+               mdev->device_cap_flags |= IB_DEVICE_BAD_QKEY_CNTR;\r
+\r
+       if (dev_lim->flags & DEV_LIM_FLAG_RAW_MULTI)\r
+               mdev->device_cap_flags |= IB_DEVICE_RAW_MULTI;\r
+\r
+       if (dev_lim->flags & DEV_LIM_FLAG_AUTO_PATH_MIG)\r
+               mdev->device_cap_flags |= IB_DEVICE_AUTO_PATH_MIG;\r
+\r
+       if (dev_lim->flags & DEV_LIM_FLAG_UD_AV_PORT_ENFORCE)\r
+               mdev->device_cap_flags |= IB_DEVICE_UD_AV_PORT_ENFORCE;\r
+\r
+       if (dev_lim->flags & DEV_LIM_FLAG_SRQ)\r
+               mdev->mthca_flags |= MTHCA_FLAG_SRQ;\r
+\r
+       return 0;\r
+}\r
+\r
+static int  mthca_init_tavor(struct mthca_dev *mdev)\r
+{\r
+       u8 status;\r
+       int err;\r
+       struct mthca_dev_lim        dev_lim;\r
+       struct mthca_profile        profile;\r
+       struct mthca_init_hca_param init_hca;\r
+\r
+       err = mthca_SYS_EN(mdev, &status);\r
+       if (err) {\r
+               HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("SYS_EN command failed, aborting.\n"));\r
+               return err;\r
+       }\r
+       if (status) {\r
+               HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("SYS_EN returned status 0x%02x, "\r
+                         "aborting.\n", status));\r
+               return -EINVAL;\r
+       }\r
+\r
+       err = mthca_QUERY_FW(mdev, &status);\r
+       if (err) {\r
+               HCA_PRINT_EV(TRACE_LEVEL_ERROR   ,HCA_DBG_LOW   ,("QUERY_FW command failed, aborting.\n"));\r
+               goto err_disable;\r
+       }\r
+       if (status) {\r
+               HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("QUERY_FW returned status 0x%02x, "\r
+                         "aborting.\n", status));\r
+               err = -EINVAL;\r
+               goto err_disable;\r
+       }\r
+       err = mthca_QUERY_DDR(mdev, &status);\r
+       if (err) {\r
+               HCA_PRINT_EV(TRACE_LEVEL_ERROR   ,HCA_DBG_LOW   ,("QUERY_DDR command failed, aborting.\n"));\r
+               goto err_disable;\r
+       }\r
+       if (status) {\r
+               HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,( "QUERY_DDR returned status 0x%02x, "\r
+                         "aborting.\n", status));\r
+               err = -EINVAL;\r
+               goto err_disable;\r
+       }\r
+\r
+       err = mthca_dev_lim(mdev, &dev_lim);\r
+       if (err) {\r
+               HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,( "QUERY_DEV_LIM command failed, aborting.\n"));\r
+               goto err_disable;\r
+       }\r
+\r
+       profile = default_profile;\r
+       profile.num_uar   = dev_lim.uar_size / PAGE_SIZE;\r
+       profile.uarc_size = 0;\r
+\r
+       /* correct default profile */\r
+       if ( g_profile_qp_num != 0 ) \r
+               profile.num_qp = g_profile_qp_num;\r
+               \r
+       if ( g_profile_rd_out != 0xffffffff )\r
+               profile.rdb_per_qp = g_profile_rd_out;\r
+\r
+       if (mdev->mthca_flags & MTHCA_FLAG_SRQ)\r
+               profile.num_srq = dev_lim.max_srqs;\r
+\r
+       err = (int)mthca_make_profile(mdev, &profile, &dev_lim, &init_hca);\r
+       if (err < 0)\r
+               goto err_disable;\r
+\r
+       err = (int)mthca_INIT_HCA(mdev, &init_hca, &status);\r
+       if (err) {\r
+               HCA_PRINT_EV(TRACE_LEVEL_ERROR   ,HCA_DBG_LOW   ,("INIT_HCA command failed, aborting.\n"));\r
+               goto err_disable;\r
+       }\r
+       if (status) {\r
+               HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("INIT_HCA returned status 0x%02x, "\r
+                         "aborting.\n", status));\r
+               err = -EINVAL;\r
+               goto err_disable;\r
+       }\r
+\r
+       return 0;\r
+\r
+err_disable:\r
+       mthca_SYS_DIS(mdev, &status);\r
+\r
+       return err;\r
+}\r
+\r
+static int  mthca_load_fw(struct mthca_dev *mdev)\r
+{\r
+       u8 status;\r
+       int err;\r
+\r
+       /* FIXME: use HCA-attached memory for FW if present */\r
+\r
+       mdev->fw.arbel.fw_icm =\r
+               mthca_alloc_icm(mdev, mdev->fw.arbel.fw_pages,\r
+                               GFP_HIGHUSER | __GFP_NOWARN);\r
+       if (!mdev->fw.arbel.fw_icm) {\r
+               HCA_PRINT_EV(TRACE_LEVEL_ERROR   ,HCA_DBG_LOW   ,("Couldn't allocate FW area, aborting.\n"));\r
+               return -ENOMEM;\r
+       }\r
+\r
+       err = mthca_MAP_FA(mdev, mdev->fw.arbel.fw_icm, &status);\r
+       if (err) {\r
+               HCA_PRINT_EV(TRACE_LEVEL_ERROR   ,HCA_DBG_LOW   ,("MAP_FA command failed, aborting.\n"));\r
+               goto err_free;\r
+       }\r
+       if (status) {\r
+               HCA_PRINT_EV(TRACE_LEVEL_ERROR   ,HCA_DBG_LOW   ,("MAP_FA returned status 0x%02x, aborting.\n", status));\r
+               err = -EINVAL;\r
+               goto err_free;\r
+       }\r
+       err = mthca_RUN_FW(mdev, &status);\r
+       if (err) {\r
+               HCA_PRINT_EV(TRACE_LEVEL_ERROR   ,HCA_DBG_LOW   ,("RUN_FW command failed, aborting.\n"));\r
+               goto err_unmap_fa;\r
+       }\r
+       if (status) {\r
+               HCA_PRINT_EV(TRACE_LEVEL_ERROR   ,HCA_DBG_LOW   ,("RUN_FW returned status 0x%02x, aborting.\n", status));\r
+               err = -EINVAL;\r
+               goto err_unmap_fa;\r
+       }\r
+\r
+       return 0;\r
+\r
+err_unmap_fa:\r
+       mthca_UNMAP_FA(mdev, &status);\r
+\r
+err_free:\r
+       mthca_free_icm(mdev, mdev->fw.arbel.fw_icm);\r
+       return err;\r
+}\r
+\r
+static int  mthca_init_icm(struct mthca_dev *mdev,\r
+                                   struct mthca_dev_lim *dev_lim,\r
+                                   struct mthca_init_hca_param *init_hca,\r
+                                   u64 icm_size)\r
+{\r
+       u64 aux_pages;\r
+       u8 status;\r
+       int err;\r
+\r
+       err = mthca_SET_ICM_SIZE(mdev, icm_size, &aux_pages, &status);\r
+       if (err) {\r
+               HCA_PRINT_EV(TRACE_LEVEL_ERROR   ,HCA_DBG_LOW   ,("SET_ICM_SIZE command failed, aborting.\n"));\r
+               return err;\r
+       }\r
+       if (status) {\r
+               HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("SET_ICM_SIZE returned status 0x%02x, "\r
+                         "aborting.\n", status));\r
+               return -EINVAL;\r
+       }\r
+\r
+       HCA_PRINT(TRACE_LEVEL_INFORMATION ,HCA_DBG_LOW , ("%I64d KB of HCA context requires %I64d KB aux memory.\n",\r
+                 (u64) icm_size >> 10,\r
+                 (u64) aux_pages << 2));\r
+\r
+       mdev->fw.arbel.aux_icm = mthca_alloc_icm(mdev, (int)aux_pages,\r
+                                                GFP_HIGHUSER | __GFP_NOWARN);\r
+       if (!mdev->fw.arbel.aux_icm) {\r
+               HCA_PRINT_EV(TRACE_LEVEL_ERROR   ,HCA_DBG_LOW   ,("Couldn't allocate aux memory, aborting.\n"));\r
+               return -ENOMEM;\r
+       }\r
+\r
+       err = mthca_MAP_ICM_AUX(mdev, mdev->fw.arbel.aux_icm, &status);\r
+       if (err) {\r
+               HCA_PRINT_EV(TRACE_LEVEL_ERROR   ,HCA_DBG_LOW   ,("MAP_ICM_AUX command failed, aborting.\n"));\r
+               goto err_free_aux;\r
+       }\r
+       if (status) {\r
+               HCA_PRINT_EV(TRACE_LEVEL_ERROR   ,HCA_DBG_LOW   ,("MAP_ICM_AUX returned status 0x%02x, aborting.\n", status));\r
+               err = -EINVAL;\r
+               goto err_free_aux;\r
+       }\r
+\r
+       err = mthca_map_eq_icm(mdev, init_hca->eqc_base);\r
+       if (err) {\r
+               HCA_PRINT_EV(TRACE_LEVEL_ERROR   ,HCA_DBG_LOW   ,("Failed to map EQ context memory, aborting.\n"));\r
+               goto err_unmap_aux;\r
+       }\r
+\r
+       mdev->mr_table.mtt_table = mthca_alloc_icm_table(mdev, init_hca->mtt_base,\r
+                                                        MTHCA_MTT_SEG_SIZE,\r
+                                                        mdev->limits.num_mtt_segs,\r
+                                                        mdev->limits.reserved_mtts, 1);\r
+       if (!mdev->mr_table.mtt_table) {\r
+               HCA_PRINT_EV(TRACE_LEVEL_ERROR   ,HCA_DBG_LOW   ,("Failed to map MTT context memory, aborting.\n"));\r
+               err = -ENOMEM;\r
+               goto err_unmap_eq;\r
+       }\r
+\r
+       mdev->mr_table.mpt_table = mthca_alloc_icm_table(mdev, init_hca->mpt_base,\r
+                                                        dev_lim->mpt_entry_sz,\r
+                                                        mdev->limits.num_mpts,\r
+                                                        mdev->limits.reserved_mrws, 1);\r
+       if (!mdev->mr_table.mpt_table) {\r
+               HCA_PRINT_EV(TRACE_LEVEL_ERROR   ,HCA_DBG_LOW   ,("Failed to map MPT context memory, aborting.\n"));\r
+               err = -ENOMEM;\r
+               goto err_unmap_mtt;\r
+       }\r
+\r
+       mdev->qp_table.qp_table = mthca_alloc_icm_table(mdev, init_hca->qpc_base,\r
+                                                       dev_lim->qpc_entry_sz,\r
+                                                       mdev->limits.num_qps,\r
+                                                       mdev->limits.reserved_qps, 0);\r
+       if (!mdev->qp_table.qp_table) {\r
+               HCA_PRINT_EV(TRACE_LEVEL_ERROR   ,HCA_DBG_LOW   ,("Failed to map QP context memory, aborting.\n"));\r
+               err = -ENOMEM;\r
+               goto err_unmap_mpt;\r
+       }\r
+\r
+       mdev->qp_table.eqp_table = mthca_alloc_icm_table(mdev, init_hca->eqpc_base,\r
+                                                        dev_lim->eqpc_entry_sz,\r
+                                                        mdev->limits.num_qps,\r
+                                                        mdev->limits.reserved_qps, 0);\r
+       if (!mdev->qp_table.eqp_table) {\r
+               HCA_PRINT_EV(TRACE_LEVEL_ERROR   ,HCA_DBG_LOW   ,("Failed to map EQP context memory, aborting.\n"));\r
+               err = -ENOMEM;\r
+               goto err_unmap_qp;\r
+       }\r
+\r
+       mdev->qp_table.rdb_table = mthca_alloc_icm_table(mdev, init_hca->rdb_base,\r
+                                                        MTHCA_RDB_ENTRY_SIZE,\r
+                                                        mdev->limits.num_qps <<\r
+                                                        mdev->qp_table.rdb_shift,\r
+                                                        0, 0);\r
+       if (!mdev->qp_table.rdb_table) {\r
+               HCA_PRINT_EV(TRACE_LEVEL_ERROR   ,HCA_DBG_LOW   ,("Failed to map RDB context memory, aborting\n"));\r
+               err = -ENOMEM;\r
+               goto err_unmap_eqp;\r
+       }\r
+\r
+       mdev->cq_table.table = mthca_alloc_icm_table(mdev, init_hca->cqc_base,\r
+                                                   dev_lim->cqc_entry_sz,\r
+                                                   mdev->limits.num_cqs,\r
+                                                   mdev->limits.reserved_cqs, 0);\r
+       if (!mdev->cq_table.table) {\r
+               HCA_PRINT_EV(TRACE_LEVEL_ERROR   ,HCA_DBG_LOW   ,("Failed to map CQ context memory, aborting.\n"));\r
+               err = -ENOMEM;\r
+               goto err_unmap_rdb;\r
+       }\r
+\r
+       if (mdev->mthca_flags & MTHCA_FLAG_SRQ) {\r
+               mdev->srq_table.table =\r
+                       mthca_alloc_icm_table(mdev, init_hca->srqc_base,\r
+                                             dev_lim->srq_entry_sz,\r
+                                             mdev->limits.num_srqs,\r
+                                             mdev->limits.reserved_srqs, 0);\r
+               if (!mdev->srq_table.table) {\r
+                       HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("Failed to map SRQ context memory, "\r
+                                 "aborting.\n"));\r
+                       err = -ENOMEM;\r
+                       goto err_unmap_cq;\r
+               }\r
+       }\r
+\r
+       /*\r
+        * It's not strictly required, but for simplicity just map the\r
+        * whole multicast group table now.  The table isn't very big\r
+        * and it's a lot easier than trying to track ref counts.\r
+        */\r
+       mdev->mcg_table.table = mthca_alloc_icm_table(mdev, init_hca->mc_base,\r
+                                                     MTHCA_MGM_ENTRY_SIZE,\r
+                                                     mdev->limits.num_mgms +\r
+                                                     mdev->limits.num_amgms,\r
+                                                     mdev->limits.num_mgms +\r
+                                                     mdev->limits.num_amgms,\r
+                                                     0);\r
+       if (!mdev->mcg_table.table) {\r
+               HCA_PRINT_EV(TRACE_LEVEL_ERROR   ,HCA_DBG_LOW   ,("Failed to map MCG context memory, aborting.\n"));\r
+               err = -ENOMEM;\r
+               goto err_unmap_srq;\r
+       }\r
+\r
+       return 0;\r
+\r
+err_unmap_srq:\r
+       if (mdev->mthca_flags & MTHCA_FLAG_SRQ)\r
+               mthca_free_icm_table(mdev, mdev->srq_table.table);\r
+\r
+err_unmap_cq:\r
+       mthca_free_icm_table(mdev, mdev->cq_table.table);\r
+\r
+err_unmap_rdb:\r
+       mthca_free_icm_table(mdev, mdev->qp_table.rdb_table);\r
+\r
+err_unmap_eqp:\r
+       mthca_free_icm_table(mdev, mdev->qp_table.eqp_table);\r
+\r
+err_unmap_qp:\r
+       mthca_free_icm_table(mdev, mdev->qp_table.qp_table);\r
+\r
+err_unmap_mpt:\r
+       mthca_free_icm_table(mdev, mdev->mr_table.mpt_table);\r
+\r
+err_unmap_mtt:\r
+       mthca_free_icm_table(mdev, mdev->mr_table.mtt_table);\r
+\r
+err_unmap_eq:\r
+       mthca_unmap_eq_icm(mdev);\r
+\r
+err_unmap_aux:\r
+       mthca_UNMAP_ICM_AUX(mdev, &status);\r
+\r
+err_free_aux:\r
+       mthca_free_icm(mdev, mdev->fw.arbel.aux_icm);\r
+\r
+       return err;\r
+}\r
+\r
+static int  mthca_init_arbel(struct mthca_dev *mdev)\r
+{\r
+       struct mthca_dev_lim        dev_lim;\r
+       struct mthca_profile        profile;\r
+       struct mthca_init_hca_param init_hca;\r
+       u64 icm_size;\r
+       u8 status;\r
+       int err;\r
+\r
+       err = mthca_QUERY_FW(mdev, &status);\r
+       if (err) {\r
+               HCA_PRINT_EV(TRACE_LEVEL_ERROR   ,HCA_DBG_LOW   ,("QUERY_FW command failed, aborting.\n"));\r
+               return err;\r
+       }\r
+       if (status) {\r
+               HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("QUERY_FW returned status 0x%02x, "\r
+                         "aborting.\n", status));\r
+               return -EINVAL;\r
+       }\r
+\r
+       err = mthca_ENABLE_LAM(mdev, &status);\r
+       if (err) {\r
+               HCA_PRINT_EV(TRACE_LEVEL_ERROR   ,HCA_DBG_LOW   ,("ENABLE_LAM command failed, aborting.\n"));\r
+               return err;\r
+       }\r
+       if (status == MTHCA_CMD_STAT_LAM_NOT_PRE) {\r
+               HCA_PRINT(TRACE_LEVEL_INFORMATION   ,HCA_DBG_LOW   ,("No HCA-attached memory (running in MemFree mode)\n"));\r
+               mdev->mthca_flags |= MTHCA_FLAG_NO_LAM;\r
+       } else if (status) {\r
+               HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("ENABLE_LAM returned status 0x%02x, "\r
+                         "aborting.\n", status));\r
+               return -EINVAL;\r
+       }\r
+\r
+       err = mthca_load_fw(mdev);\r
+       if (err) {\r
+               HCA_PRINT_EV(TRACE_LEVEL_ERROR   ,HCA_DBG_LOW   ,("Failed to start FW, aborting.\n"));\r
+               goto err_disable;\r
+       }\r
+\r
+       err = mthca_dev_lim(mdev, &dev_lim);\r
+       if (err) {\r
+               HCA_PRINT_EV(TRACE_LEVEL_ERROR   ,HCA_DBG_LOW   ,("QUERY_DEV_LIM command failed, aborting.\n"));\r
+               goto err_stop_fw;\r
+       }\r
+\r
+       profile = default_profile;\r
+       profile.num_uar  = dev_lim.uar_size / PAGE_SIZE;\r
+       profile.num_udav = 0;\r
+       if (mdev->mthca_flags & MTHCA_FLAG_SRQ)\r
+               profile.num_srq = dev_lim.max_srqs;\r
+\r
+       /* correct default profile */\r
+       if ( g_profile_qp_num != 0 ) \r
+               profile.num_qp = g_profile_qp_num;\r
+               \r
+       if ( g_profile_rd_out != 0xffffffff )\r
+               profile.rdb_per_qp = g_profile_rd_out;\r
+\r
+       RtlZeroMemory( &init_hca, sizeof(init_hca));\r
+       icm_size = mthca_make_profile(mdev, &profile, &dev_lim, &init_hca);\r
+       if ((int) icm_size < 0) {\r
+               err = (int)icm_size;\r
+               goto err_stop_fw;\r
+       }\r
+\r
+       err = mthca_init_icm(mdev, &dev_lim, &init_hca, icm_size);\r
+       if (err)\r
+               goto err_stop_fw;\r
+\r
+       err = mthca_INIT_HCA(mdev, &init_hca, &status);\r
+       if (err) {\r
+               HCA_PRINT_EV(TRACE_LEVEL_ERROR   ,HCA_DBG_LOW   ,("INIT_HCA command failed, aborting.\n"));\r
+               goto err_free_icm;\r
+       }\r
+       if (status) {\r
+               HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("INIT_HCA returned status 0x%02x, "\r
+                         "aborting.\n", status));\r
+               err = -EINVAL;\r
+               goto err_free_icm;\r
+       }\r
+\r
+       return 0;\r
+\r
+err_free_icm:\r
+       if (mdev->mthca_flags & MTHCA_FLAG_SRQ)\r
+               mthca_free_icm_table(mdev, mdev->srq_table.table);\r
+       mthca_free_icm_table(mdev, mdev->cq_table.table);\r
+       mthca_free_icm_table(mdev, mdev->qp_table.rdb_table);\r
+       mthca_free_icm_table(mdev, mdev->qp_table.eqp_table);\r
+       mthca_free_icm_table(mdev, mdev->qp_table.qp_table);\r
+       mthca_free_icm_table(mdev, mdev->mr_table.mpt_table);\r
+       mthca_free_icm_table(mdev, mdev->mr_table.mtt_table);\r
+       mthca_unmap_eq_icm(mdev);\r
+\r
+       mthca_UNMAP_ICM_AUX(mdev, &status);\r
+       mthca_free_icm(mdev, mdev->fw.arbel.aux_icm);\r
+\r
+err_stop_fw:\r
+       mthca_UNMAP_FA(mdev, &status);\r
+       mthca_free_icm(mdev, mdev->fw.arbel.fw_icm);\r
+\r
+err_disable:\r
+       if (!(mdev->mthca_flags & MTHCA_FLAG_NO_LAM))\r
+               mthca_DISABLE_LAM(mdev, &status);\r
+\r
+       return err;\r
+}\r
+\r
+static void mthca_close_hca(struct mthca_dev *mdev)\r
+{\r
+       u8 status;\r
+\r
+       mthca_CLOSE_HCA(mdev, 0, &status);\r
+\r
+       if (mthca_is_memfree(mdev)) {\r
+               if (mdev->mthca_flags & MTHCA_FLAG_SRQ)\r
+                       mthca_free_icm_table(mdev, mdev->srq_table.table);\r
+               mthca_free_icm_table(mdev, mdev->cq_table.table);\r
+               mthca_free_icm_table(mdev, mdev->qp_table.rdb_table);\r
+               mthca_free_icm_table(mdev, mdev->qp_table.eqp_table);\r
+               mthca_free_icm_table(mdev, mdev->qp_table.qp_table);\r
+               mthca_free_icm_table(mdev, mdev->mr_table.mpt_table);\r
+               mthca_free_icm_table(mdev, mdev->mr_table.mtt_table);\r
+               mthca_free_icm_table(mdev, mdev->mcg_table.table);\r
+               mthca_unmap_eq_icm(mdev);\r
+\r
+               mthca_UNMAP_ICM_AUX(mdev, &status);\r
+               mthca_free_icm(mdev, mdev->fw.arbel.aux_icm);\r
+\r
+               mthca_UNMAP_FA(mdev, &status);\r
+               mthca_free_icm(mdev, mdev->fw.arbel.fw_icm);\r
+\r
+               if (!(mdev->mthca_flags & MTHCA_FLAG_NO_LAM))\r
+                       mthca_DISABLE_LAM(mdev, &status);\r
+       } else\r
+               mthca_SYS_DIS(mdev, &status);\r
+}\r
+\r
+static int  mthca_init_hca(struct mthca_dev *mdev)\r
+{\r
+       u8 status;\r
+       int err;\r
+       struct mthca_adapter adapter;\r
+\r
+       if (mthca_is_memfree(mdev))\r
+               err = mthca_init_arbel(mdev);\r
+       else\r
+               err = mthca_init_tavor(mdev);\r
+\r
+       if (err)\r
+               return err;\r
+\r
+       err = mthca_QUERY_ADAPTER(mdev, &adapter, &status);\r
+       if (err) {\r
+               HCA_PRINT_EV(TRACE_LEVEL_ERROR   ,HCA_DBG_LOW   ,("QUERY_ADAPTER command failed, aborting.\n"));\r
+               goto err_close;\r
+       }\r
+       if (status) {\r
+               HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("QUERY_ADAPTER returned status 0x%02x, "\r
+                         "aborting.\n", status));\r
+               err = -EINVAL;\r
+               goto err_close;\r
+       }\r
+\r
+       mdev->eq_table.inta_pin = adapter.inta_pin;\r
+       mdev->rev_id            = adapter.revision_id;\r
+       memcpy(mdev->board_id, adapter.board_id, sizeof mdev->board_id);\r
+\r
+       return 0;\r
+\r
+err_close:\r
+       mthca_close_hca(mdev);\r
+       return err;\r
+}\r
+\r
+static int  mthca_setup_hca(struct mthca_dev *mdev)\r
+{\r
+       int err;\r
+       u8 status;\r
+\r
+       MTHCA_INIT_DOORBELL_LOCK(&mdev->doorbell_lock);\r
+\r
+       err = mthca_init_uar_table(mdev);\r
+       if (err) {\r
+               HCA_PRINT_EV(TRACE_LEVEL_ERROR,HCA_DBG_LOW,("Failed to initialize "\r
+                         "user access region table, aborting.\n"));\r
+               return err;\r
+       }\r
+\r
+       err = mthca_uar_alloc(mdev, &mdev->driver_uar);\r
+       if (err) {\r
+               HCA_PRINT_EV(TRACE_LEVEL_ERROR,HCA_DBG_LOW,("Failed to allocate driver access region, "\r
+                         "aborting.\n"));\r
+               goto err_uar_table_free;\r
+       }\r
+\r
+       mdev->kar = ioremap((io_addr_t)mdev->driver_uar.pfn << PAGE_SHIFT, PAGE_SIZE,&mdev->kar_size);\r
+       if (!mdev->kar) {\r
+               HCA_PRINT_EV(TRACE_LEVEL_ERROR,HCA_DBG_LOW,("Couldn't map kernel access region, "\r
+                         "aborting.\n"));\r
+               err = -ENOMEM;\r
+               goto err_uar_free;\r
+       }\r
+\r
+       err = mthca_init_pd_table(mdev);\r
+       if (err) {\r
+               HCA_PRINT_EV(TRACE_LEVEL_ERROR,HCA_DBG_LOW,("Failed to initialize "\r
+                         "protection domain table, aborting.\n"));\r
+               goto err_kar_unmap;\r
+       }\r
+\r
+       err = mthca_init_mr_table(mdev);\r
+       if (err) {\r
+               HCA_PRINT_EV(TRACE_LEVEL_ERROR,HCA_DBG_LOW,("Failed to initialize "\r
+                         "memory region table, aborting.\n"));\r
+               goto err_pd_table_free;\r
+       }\r
+\r
+       err = mthca_pd_alloc(mdev, 1, &mdev->driver_pd);\r
+       if (err) {\r
+               HCA_PRINT_EV(TRACE_LEVEL_ERROR,HCA_DBG_LOW,("Failed to create driver PD, "\r
+                         "aborting.\n"));\r
+               goto err_mr_table_free;\r
+       }\r
+\r
+       err = mthca_init_eq_table(mdev);\r
+       if (err) {\r
+               HCA_PRINT_EV(TRACE_LEVEL_ERROR,HCA_DBG_LOW, ("Failed to initialize "\r
+                         "event queue table, aborting.\n"));\r
+               goto err_pd_free;\r
+       }\r
+\r
+       err = mthca_cmd_use_events(mdev);\r
+       if (err) {\r
+               HCA_PRINT_EV(TRACE_LEVEL_ERROR,HCA_DBG_LOW,("Failed to switch to event-driven "\r
+                         "firmware commands, aborting.\n"));\r
+               goto err_eq_table_free;\r
+       }\r
+\r
+       err = mthca_NOP(mdev, &status);\r
+       if (err || status) {\r
+               HCA_PRINT_EV(TRACE_LEVEL_ERROR  ,HCA_DBG_LOW  ,("NOP command failed to generate interrupt, aborting.\n"));\r
+               if (mdev->mthca_flags & (MTHCA_FLAG_MSI | MTHCA_FLAG_MSI_X)){\r
+                       HCA_PRINT_EV(TRACE_LEVEL_ERROR  ,HCA_DBG_LOW  ,("Try again with MSI/MSI-X disabled.\n"));\r
+               }else{\r
+                       HCA_PRINT_EV(TRACE_LEVEL_ERROR  ,HCA_DBG_LOW  ,("BIOS or ACPI interrupt routing problem?\n"));\r
+               }\r
+\r
+               goto err_cmd_poll;\r
+       }\r
+\r
+       HCA_PRINT(TRACE_LEVEL_VERBOSE  ,HCA_DBG_LOW  ,("NOP command IRQ test passed\n"));\r
+\r
+       err = mthca_init_cq_table(mdev);\r
+       if (err) {\r
+               HCA_PRINT_EV(TRACE_LEVEL_ERROR,HCA_DBG_LOW,("Failed to initialize "\r
+                         "completion queue table, aborting.\n"));\r
+               goto err_cmd_poll;\r
+       }\r
+\r
+       err = mthca_init_srq_table(mdev);\r
+       if (err) {\r
+               HCA_PRINT_EV(TRACE_LEVEL_ERROR,HCA_DBG_LOW,("Failed to initialize "\r
+                         "shared receive queue table, aborting.\n"));\r
+               goto err_cq_table_free;\r
+       }\r
+\r
+       err = mthca_init_qp_table(mdev);\r
+       if (err) {\r
+               HCA_PRINT_EV(TRACE_LEVEL_ERROR,HCA_DBG_LOW, ("Failed to initialize "\r
+                         "queue pair table, aborting.\n"));\r
+               goto err_srq_table_free;\r
+       }\r
+\r
+       err = mthca_init_av_table(mdev);\r
+       if (err) {\r
+               HCA_PRINT_EV(TRACE_LEVEL_ERROR,HCA_DBG_LOW,("Failed to initialize "\r
+                         "address vector table, aborting.\n"));\r
+               goto err_qp_table_free;\r
+       }\r
+\r
+       err = mthca_init_mcg_table(mdev);\r
+       if (err) {\r
+               HCA_PRINT_EV(TRACE_LEVEL_ERROR,HCA_DBG_LOW,("Failed to initialize "\r
+                         "multicast group table, aborting.\n"));\r
+               goto err_av_table_free;\r
+       }\r
+\r
+       return 0;\r
+\r
+err_av_table_free:\r
+       mthca_cleanup_av_table(mdev);\r
+\r
+err_qp_table_free:\r
+       mthca_cleanup_qp_table(mdev);\r
+\r
+err_srq_table_free:\r
+       mthca_cleanup_srq_table(mdev);\r
+\r
+err_cq_table_free:\r
+       mthca_cleanup_cq_table(mdev);\r
+\r
+err_cmd_poll:\r
+       mthca_cmd_use_polling(mdev);\r
+\r
+err_eq_table_free:\r
+       mthca_cleanup_eq_table(mdev);\r
+\r
+err_pd_free:\r
+       mthca_pd_free(mdev, &mdev->driver_pd);\r
+\r
+err_mr_table_free:\r
+       mthca_cleanup_mr_table(mdev);\r
+\r
+err_pd_table_free:\r
+       mthca_cleanup_pd_table(mdev);\r
+\r
+err_kar_unmap:\r
+       iounmap(mdev->kar, mdev->kar_size);\r
+\r
+err_uar_free:\r
+       mthca_uar_free(mdev, &mdev->driver_uar);\r
+\r
+err_uar_table_free:\r
+       mthca_cleanup_uar_table(mdev);\r
+       return err;\r
+}\r
+\r
+\r
+static int     mthca_check_fw(struct mthca_dev *mdev, struct pci_device_id *p_id)\r
+{\r
+       int err = 0;\r
+       \r
+       if (mdev->fw_ver < mthca_hca_table[p_id->driver_data].max_unsupported_fw) {\r
+               HCA_PRINT_EV(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("HCA FW version %d.%d.%d is not supported. Use %d.%d.%d or higher.\n",\r
+                          (int) (mdev->fw_ver >> 32), (int) (mdev->fw_ver >> 16) & 0xffff,\r
+                          (int) (mdev->fw_ver & 0xffff),\r
+                          (int) (mthca_hca_table[p_id->driver_data].min_supported_fw >> 32),\r
+                          (int) (mthca_hca_table[p_id->driver_data].min_supported_fw >> 16) & 0xffff,\r
+                          (int) (mthca_hca_table[p_id->driver_data].min_supported_fw & 0xffff)));\r
+               err = -EINVAL;\r
+       }\r
+       else \r
+       if (mdev->fw_ver < mthca_hca_table[p_id->driver_data].min_supported_fw) {\r
+               HCA_PRINT_EV(TRACE_LEVEL_WARNING ,HCA_DBG_LOW ,\r
+                       ("The HCA FW version is %d.%d.%d, which is not the latest one. \n"\r
+                       "If you meet any issues with the HCA please first try to upgrade the FW to version %d.%d.%d or higher.\n",\r
+                                (int) (mdev->fw_ver >> 32), (int) (mdev->fw_ver >> 16) & 0xffff,\r
+                                (int) (mdev->fw_ver & 0xffff),\r
+                                (int) (mthca_hca_table[p_id->driver_data].min_supported_fw >> 32),\r
+                                (int) (mthca_hca_table[p_id->driver_data].min_supported_fw >> 16) & 0xffff,\r
+                                (int) (mthca_hca_table[p_id->driver_data].min_supported_fw & 0xffff)));\r
+       }\r
+       else {\r
+               HCA_PRINT(TRACE_LEVEL_INFORMATION ,HCA_DBG_LOW ,("Current HCA FW version is %d.%d.%d. \n",\r
+                                (int) (mdev->fw_ver >> 32), (int) (mdev->fw_ver >> 16) & 0xffff,\r
+                                (int) (mdev->fw_ver & 0xffff)));\r
+       }\r
+\r
+       return err;\r
+}\r
+\r
+NTSTATUS mthca_init_one(hca_dev_ext_t *ext)\r
+{\r
+       static int mthca_version_printed = 0;\r
+       int err;\r
+       NTSTATUS status;\r
+       struct mthca_dev *mdev;\r
+       struct pci_device_id *p_id;\r
+\r
+       /* print version */\r
+       if (!mthca_version_printed) {\r
+               HCA_PRINT(TRACE_LEVEL_INFORMATION ,HCA_DBG_LOW ,("%s\n", mthca_version));\r
+               ++mthca_version_printed;\r
+       }\r
+\r
+       /* find the type of device */\r
+       p_id = mthca_find_pci_dev(\r
+               (unsigned)ext->hcaConfig.VendorID,\r
+               (unsigned)ext->hcaConfig.DeviceID);\r
+       if (p_id == NULL) {\r
+               status = STATUS_NO_SUCH_DEVICE;\r
+               goto end;\r
+       }\r
+\r
+       InitializeListHead(&ext->hca.hob.event_list);\r
+       KeInitializeSpinLock(&ext->hca.hob.event_list_lock);\r
+\r
+run_as_livefish:\r
+       /* allocate mdev structure */\r
+       mdev = kzalloc(sizeof *mdev, GFP_KERNEL);\r
+       if (!mdev) {\r
+               // can't use HCA_PRINT_EV here !\r
+               HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_LOW ,("Device struct alloc failed, "\r
+                       "aborting.\n"));\r
+               status = STATUS_INSUFFICIENT_RESOURCES;\r
+               goto end;\r
+       }\r
+        \r
+       /* set some fields */\r
+       mdev->ext = ext;                /* pointer to DEVICE OBJECT extension */\r
+       mdev->hca_type = p_id->driver_data;\r
+       mdev->ib_dev.mdev = mdev;\r
+       if (p_id->driver_data == LIVEFISH)\r
+               mdev->mthca_flags |= MTHCA_FLAG_LIVEFISH;\r
+       if (mthca_is_livefish(mdev))\r
+               goto done;\r
+       if (ext->hca_hidden)\r
+               mdev->mthca_flags |= MTHCA_FLAG_DDR_HIDDEN;\r
+       if (mthca_hca_table[p_id->driver_data].is_memfree)\r
+               mdev->mthca_flags |= MTHCA_FLAG_MEMFREE;\r
+       if (mthca_hca_table[p_id->driver_data].is_pcie)\r
+               mdev->mthca_flags |= MTHCA_FLAG_PCIE;\r
+       \r
+//TODO: after we have a FW, capable of reset, \r
+// write a routine, that only presses the button\r
+\r
+       /*\r
+        * Now reset the HCA before we touch the PCI capabilities or\r
+        * attempt a firmware command, since a boot ROM may have left\r
+        * the HCA in an undefined state.\r
+        */\r
+       status = hca_reset( mdev->ext->cl_ext.p_self_do, p_id->driver_data == TAVOR );\r
+       if ( !NT_SUCCESS( status ) ) {\r
+               HCA_PRINT_EV(TRACE_LEVEL_ERROR   ,HCA_DBG_LOW   ,("Failed to reset HCA, aborting.\n"));\r
+               goto err_free_dev;\r
+       }\r
+\r
+       if (mthca_cmd_init(mdev)) {\r
+               HCA_PRINT_EV(TRACE_LEVEL_ERROR   ,HCA_DBG_LOW   ,("Failed to init command interface, aborting.\n"));\r
+               status = STATUS_DEVICE_DATA_ERROR;\r
+               goto err_free_dev;\r
+       }\r
+\r
+       status = mthca_tune_pci(mdev);\r
+       if ( !NT_SUCCESS( status ) ) {\r
+               goto err_cmd;\r
+       }\r
+\r
+       err = mthca_init_hca(mdev); \r
+       if (err) {\r
+               status = STATUS_UNSUCCESSFUL;\r
+               goto err_cmd;\r
+       }\r
+\r
+       err = mthca_check_fw(mdev, p_id);\r
+       if (err) {\r
+               status = STATUS_UNSUCCESSFUL;\r
+               goto err_close;\r
+       }\r
+\r
+       err = mthca_setup_hca(mdev);\r
+       if (err) {\r
+               status = STATUS_UNSUCCESSFUL;\r
+               goto err_close;\r
+       }\r
+\r
+       err = mthca_register_device(mdev);\r
+       if (err) {\r
+               status = STATUS_UNSUCCESSFUL;\r
+               goto err_cleanup;\r
+       }\r
+\r
+       done:\r
+       ext->hca.mdev = mdev;\r
+       mdev->state = MTHCA_DEV_INITIALIZED;\r
+       return 0;\r
+\r
+err_cleanup:\r
+       mthca_cleanup_mcg_table(mdev);\r
+       mthca_cleanup_av_table(mdev);\r
+       mthca_cleanup_qp_table(mdev);\r
+       mthca_cleanup_srq_table(mdev);\r
+       mthca_cleanup_cq_table(mdev);\r
+       mthca_cmd_use_polling(mdev);\r
+       mthca_cleanup_eq_table(mdev);\r
+\r
+       mthca_pd_free(mdev, &mdev->driver_pd);\r
+\r
+       mthca_cleanup_mr_table(mdev);\r
+       mthca_cleanup_pd_table(mdev);\r
+       mthca_cleanup_uar_table(mdev);\r
+\r
+err_close:\r
+       mthca_close_hca(mdev);\r
+\r
+err_cmd:\r
+       mthca_cmd_cleanup(mdev);\r
+\r
+err_free_dev:\r
+       kfree(mdev);\r
+\r
+       /* we failed device initialization - try to simulate "livefish" device to facilitate using FW burning tools */\r
+       {\r
+               USHORT dev_id = ext->hcaConfig.DeviceID;\r
+               \r
+               if (dev_id == PCI_DEVICE_ID_MELLANOX_ARBEL)\r
+                       dev_id = PCI_DEVICE_ID_MELLANOX_ARBEL_COMPAT;\r
+               p_id = mthca_find_pci_dev( (unsigned)ext->hcaConfig.VendorID, dev_id + 1 );\r
+               if (p_id == NULL) {\r
+                       status = STATUS_NO_SUCH_DEVICE;\r
+                       goto end;\r
+               }\r
+               goto run_as_livefish;\r
+       }\r
+       \r
+end:\r
+       return status;\r
+}\r
+\r
+void mthca_remove_one(hca_dev_ext_t *ext)\r
+{\r
+       struct mthca_dev *mdev = ext->hca.mdev;\r
+       u8 status;\r
+       int p;\r
+\r
+       ext->hca.mdev = NULL;\r
+       if (mdev) {\r
+               mdev->state = MTHCA_DEV_UNINITIALIZED;\r
+               if (mthca_is_livefish(mdev))\r
+                       goto done;\r
+               mthca_unregister_device(mdev);\r
+\r
+               for (p = 1; p <= mdev->limits.num_ports; ++p)\r
+                       mthca_CLOSE_IB(mdev, p, &status);\r
+\r
+               mthca_cleanup_mcg_table(mdev);\r
+               mthca_cleanup_av_table(mdev);\r
+               mthca_cleanup_qp_table(mdev);\r
+               mthca_cleanup_srq_table(mdev);\r
+               mthca_cleanup_cq_table(mdev);\r
+               mthca_cmd_use_polling(mdev);\r
+               mthca_cleanup_eq_table(mdev);\r
+               mthca_pd_free(mdev, &mdev->driver_pd);\r
+               mthca_cleanup_mr_table(mdev);\r
+               mthca_cleanup_pd_table(mdev);\r
+               iounmap(mdev->kar, mdev->kar_size);\r
+               mthca_uar_free(mdev, &mdev->driver_uar);\r
+               mthca_cleanup_uar_table(mdev);\r
+               mthca_close_hca(mdev);\r
+               mthca_cmd_cleanup(mdev);\r
+done:\r
+               kfree(mdev);\r
+       }\r
+}\r
+\r
+\r
+\r
index 6b3b797..0dc108e 100644 (file)
@@ -193,6 +193,8 @@ typedef void
 *      channel adapter.  The event notification record passed has relevant\r
 *      information on the type of the event, the source that caused the event,\r
 *      and the context associated.\r
+*\r
+*   This routine is called at DISPATCH.\r
 *****/\r
 \r
 \r
@@ -249,6 +251,28 @@ typedef ib_api_status_t
 *********/\r
 \r
 \r
+/*\r
+ * Structure is provided by caller, and must be valid while registered.\r
+ * Callback context for CA events references structure.\r
+ */\r
+typedef struct _ci_event_handler\r
+{\r
+       LIST_ENTRY                              entry;\r
+       ci_async_event_cb_t             pfn_async_event_cb;\r
+\r
+}      ci_event_handler_t;\r
+\r
+typedef void\r
+(*ci_register_event_handler_t) (\r
+       IN              const   ib_ca_handle_t                          h_ca,\r
+       IN                              ci_event_handler_t*                     p_reg);\r
+\r
+typedef void\r
+(*ci_unregister_event_handler_t) (\r
+       IN              const   ib_ca_handle_t                          h_ca,\r
+       IN                              ci_event_handler_t*                     p_reg);\r
+\r
+\r
 /****f* Verbs/ci_um_open_ca\r
 * NAME\r
 *      ci_um_open_ca -- Create a CA context for use by user-mode processes.\r
@@ -2798,6 +2822,9 @@ typedef struct _ci_interface
        ci_modify_ca            modify_ca;\r
        ci_close_ca                     close_ca;\r
        ci_um_close_ca_t        um_close_ca;\r
+       ci_register_event_handler_t             register_event_handler;\r
+       ci_unregister_event_handler_t   unregister_event_handler;\r
+\r
 \r
        ci_vendor_call          vendor_call;\r
 \r
index 827cac3..16bed5d 100644 (file)
@@ -8903,7 +8903,6 @@ typedef enum _ib_async_event_t
 *****/\r
 \r
 \r
-\r
 /****f* IBA Base: Types/ib_get_async_event_str\r
 * NAME\r
 *      ib_get_async_event_str\r
@@ -8953,6 +8952,7 @@ typedef struct _ib_event_rec
 \r
        /* HCA vendor specific event information. */\r
        uint64_t                                vendor_specific;\r
+       uint8_t                                 port_number;\r
 \r
 }      ib_event_rec_t;\r
 /*******/\r