linux 2.6.16.38 w/ vs2.0.3-rc1
[linux-2.6.git] / drivers / infiniband / hw / mthca / mthca_cmd.c
index deabc14..2825615 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
  * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
- * Copyright (c) 2005, 2006 Cisco Systems.  All rights reserved.
+ * Copyright (c) 2005 Cisco Systems. 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
@@ -174,6 +174,7 @@ enum {
 
 struct mthca_cmd_context {
        struct completion done;
+       struct timer_list timer;
        int               result;
        int               next;
        u64               out_param;
@@ -181,58 +182,25 @@ struct mthca_cmd_context {
        u8                status;
 };
 
-static int fw_cmd_doorbell = 0;
-module_param(fw_cmd_doorbell, int, 0644);
-MODULE_PARM_DESC(fw_cmd_doorbell, "post FW commands through doorbell page if nonzero "
-                "(and supported by FW)");
-
 static inline int go_bit(struct mthca_dev *dev)
 {
        return readl(dev->hcr + HCR_STATUS_OFFSET) &
                swab32(1 << HCR_GO_BIT);
 }
 
-static void mthca_cmd_post_dbell(struct mthca_dev *dev,
-                                u64 in_param,
-                                u64 out_param,
-                                u32 in_modifier,
-                                u8 op_modifier,
-                                u16 op,
-                                u16 token)
+static int mthca_cmd_post(struct mthca_dev *dev,
+                         u64 in_param,
+                         u64 out_param,
+                         u32 in_modifier,
+                         u8 op_modifier,
+                         u16 op,
+                         u16 token,
+                         int event)
 {
-       void __iomem *ptr = dev->cmd.dbell_map;
-       u16 *offs = dev->cmd.dbell_offsets;
+       int err = 0;
 
-       __raw_writel((__force u32) cpu_to_be32(in_param >> 32),           ptr + offs[0]);
-       wmb();
-       __raw_writel((__force u32) cpu_to_be32(in_param & 0xfffffffful),  ptr + offs[1]);
-       wmb();
-       __raw_writel((__force u32) cpu_to_be32(in_modifier),              ptr + offs[2]);
-       wmb();
-       __raw_writel((__force u32) cpu_to_be32(out_param >> 32),          ptr + offs[3]);
-       wmb();
-       __raw_writel((__force u32) cpu_to_be32(out_param & 0xfffffffful), ptr + offs[4]);
-       wmb();
-       __raw_writel((__force u32) cpu_to_be32(token << 16),              ptr + offs[5]);
-       wmb();
-       __raw_writel((__force u32) cpu_to_be32((1 << HCR_GO_BIT)                |
-                                              (1 << HCA_E_BIT)                 |
-                                              (op_modifier << HCR_OPMOD_SHIFT) |
-                                               op),                      ptr + offs[6]);
-       wmb();
-       __raw_writel((__force u32) 0,                                     ptr + offs[7]);
-       wmb();
-}
+       mutex_lock(&dev->cmd.hcr_mutex);
 
-static int mthca_cmd_post_hcr(struct mthca_dev *dev,
-                             u64 in_param,
-                             u64 out_param,
-                             u32 in_modifier,
-                             u8 op_modifier,
-                             u16 op,
-                             u16 token,
-                             int event)
-{
        if (event) {
                unsigned long end = jiffies + GO_BIT_TIMEOUT;
 
@@ -242,8 +210,10 @@ static int mthca_cmd_post_hcr(struct mthca_dev *dev,
                }
        }
 
-       if (go_bit(dev))
-               return -EAGAIN;
+       if (go_bit(dev)) {
+               err = -EAGAIN;
+               goto out;
+       }
 
        /*
         * We use writel (instead of something like memcpy_toio)
@@ -266,29 +236,7 @@ static int mthca_cmd_post_hcr(struct mthca_dev *dev,
                                               (op_modifier << HCR_OPMOD_SHIFT) |
                                               op),                       dev->hcr + 6 * 4);
 
-       return 0;
-}
-
-static int mthca_cmd_post(struct mthca_dev *dev,
-                         u64 in_param,
-                         u64 out_param,
-                         u32 in_modifier,
-                         u8 op_modifier,
-                         u16 op,
-                         u16 token,
-                         int event)
-{
-       int err = 0;
-
-       mutex_lock(&dev->cmd.hcr_mutex);
-
-       if (event && dev->cmd.flags & MTHCA_CMD_POST_DOORBELLS && fw_cmd_doorbell)
-               mthca_cmd_post_dbell(dev, in_param, out_param, in_modifier,
-                                          op_modifier, op, token);
-       else
-               err = mthca_cmd_post_hcr(dev, in_param, out_param, in_modifier,
-                                        op_modifier, op, token, event);
-
+out:
        mutex_unlock(&dev->cmd.hcr_mutex);
        return err;
 }
@@ -327,7 +275,7 @@ static int mthca_cmd_poll(struct mthca_dev *dev,
        }
 
        if (out_is_imm)
-               *out_param =
+               *out_param = 
                        (u64) be32_to_cpu((__force __be32)
                                          __raw_readl(dev->hcr + HCR_OUT_PARAM_OFFSET)) << 32 |
                        (u64) be32_to_cpu((__force __be32)
@@ -361,6 +309,15 @@ void mthca_cmd_event(struct mthca_dev *dev,
        complete(&context->done);
 }
 
+static void event_timeout(unsigned long context_ptr)
+{
+       struct mthca_cmd_context *context =
+               (struct mthca_cmd_context *) context_ptr;
+
+       context->result = -EBUSY;
+       complete(&context->done);
+}
+
 static int mthca_cmd_wait(struct mthca_dev *dev,
                          u64 in_param,
                          u64 *out_param,
@@ -391,10 +348,11 @@ static int mthca_cmd_wait(struct mthca_dev *dev,
        if (err)
                goto out;
 
-       if (!wait_for_completion_timeout(&context->done, timeout)) {
-               err = -EBUSY;
-               goto out;
-       }
+       context->timer.expires  = jiffies + timeout;
+       add_timer(&context->timer);
+
+       wait_for_completion(&context->done);
+       del_timer_sync(&context->timer);
 
        err = context->result;
        if (err)
@@ -428,7 +386,7 @@ static int mthca_cmd_box(struct mthca_dev *dev,
                         unsigned long timeout,
                         u8 *status)
 {
-       if (dev->cmd.flags & MTHCA_CMD_USE_EVENTS)
+       if (dev->cmd.use_events)
                return mthca_cmd_wait(dev, in_param, &out_param, 0,
                                      in_modifier, op_modifier, op,
                                      timeout, status);
@@ -465,7 +423,7 @@ static int mthca_cmd_imm(struct mthca_dev *dev,
                         unsigned long timeout,
                         u8 *status)
 {
-       if (dev->cmd.flags & MTHCA_CMD_USE_EVENTS)
+       if (dev->cmd.use_events)
                return mthca_cmd_wait(dev, in_param, out_param, 1,
                                      in_modifier, op_modifier, op,
                                      timeout, status);
@@ -479,7 +437,7 @@ int mthca_cmd_init(struct mthca_dev *dev)
 {
        mutex_init(&dev->cmd.hcr_mutex);
        sema_init(&dev->cmd.poll_sem, 1);
-       dev->cmd.flags = 0;
+       dev->cmd.use_events = 0;
 
        dev->hcr = ioremap(pci_resource_start(dev->pdev, 0) + MTHCA_HCR_BASE,
                           MTHCA_HCR_SIZE);
@@ -503,8 +461,6 @@ void mthca_cmd_cleanup(struct mthca_dev *dev)
 {
        pci_pool_destroy(dev->cmd.pool);
        iounmap(dev->hcr);
-       if (dev->cmd.flags & MTHCA_CMD_POST_DOORBELLS)
-               iounmap(dev->cmd.dbell_map);
 }
 
 /*
@@ -524,6 +480,10 @@ int mthca_cmd_use_events(struct mthca_dev *dev)
        for (i = 0; i < dev->cmd.max_cmds; ++i) {
                dev->cmd.context[i].token = i;
                dev->cmd.context[i].next = i + 1;
+               init_timer(&dev->cmd.context[i].timer);
+               dev->cmd.context[i].timer.data     =
+                       (unsigned long) &dev->cmd.context[i];
+               dev->cmd.context[i].timer.function = event_timeout;
        }
 
        dev->cmd.context[dev->cmd.max_cmds - 1].next = -1;
@@ -538,8 +498,7 @@ int mthca_cmd_use_events(struct mthca_dev *dev)
                ; /* nothing */
        --dev->cmd.token_mask;
 
-       dev->cmd.flags |= MTHCA_CMD_USE_EVENTS;
-
+       dev->cmd.use_events = 1;
        down(&dev->cmd.poll_sem);
 
        return 0;
@@ -552,7 +511,7 @@ void mthca_cmd_use_polling(struct mthca_dev *dev)
 {
        int i;
 
-       dev->cmd.flags &= ~MTHCA_CMD_USE_EVENTS;
+       dev->cmd.use_events = 0;
 
        for (i = 0; i < dev->cmd.max_cmds; ++i)
                down(&dev->cmd.event_sem);
@@ -637,9 +596,8 @@ static int mthca_map_cmd(struct mthca_dev *dev, u16 op, struct mthca_icm *icm,
                 * address or size and use that as our log2 size.
                 */
                lg = ffs(mthca_icm_addr(&iter) | mthca_icm_size(&iter)) - 1;
-               if (lg < MTHCA_ICM_PAGE_SHIFT) {
-                       mthca_warn(dev, "Got FW area not aligned to %d (%llx/%lx).\n",
-                                  MTHCA_ICM_PAGE_SIZE,
+               if (lg < 12) {
+                       mthca_warn(dev, "Got FW area not aligned to 4K (%llx/%lx).\n",
                                   (unsigned long long) mthca_icm_addr(&iter),
                                   mthca_icm_size(&iter));
                        err = -EINVAL;
@@ -651,9 +609,8 @@ static int mthca_map_cmd(struct mthca_dev *dev, u16 op, struct mthca_icm *icm,
                                virt += 1 << lg;
                        }
 
-                       pages[nent * 2 + 1] =
-                               cpu_to_be64((mthca_icm_addr(&iter) + (i << lg)) |
-                                           (lg - MTHCA_ICM_PAGE_SHIFT));
+                       pages[nent * 2 + 1] = cpu_to_be64((mthca_icm_addr(&iter) +
+                                                          (i << lg)) | (lg - 12));
                        ts += 1 << (lg - 10);
                        ++tc;
 
@@ -704,41 +661,12 @@ int mthca_RUN_FW(struct mthca_dev *dev, u8 *status)
        return mthca_cmd(dev, 0, 0, 0, CMD_RUN_FW, CMD_TIME_CLASS_A, status);
 }
 
-static void mthca_setup_cmd_doorbells(struct mthca_dev *dev, u64 base)
-{
-       unsigned long addr;
-       u16 max_off = 0;
-       int i;
-
-       for (i = 0; i < 8; ++i)
-               max_off = max(max_off, dev->cmd.dbell_offsets[i]);
-
-       if ((base & PAGE_MASK) != ((base + max_off) & PAGE_MASK)) {
-               mthca_warn(dev, "Firmware doorbell region at 0x%016llx, "
-                          "length 0x%x crosses a page boundary\n",
-                          (unsigned long long) base, max_off);
-               return;
-       }
-
-       addr = pci_resource_start(dev->pdev, 2) +
-               ((pci_resource_len(dev->pdev, 2) - 1) & base);
-       dev->cmd.dbell_map = ioremap(addr, max_off + sizeof(u32));
-       if (!dev->cmd.dbell_map)
-               return;
-
-       dev->cmd.flags |= MTHCA_CMD_POST_DOORBELLS;
-       mthca_dbg(dev, "Mapped doorbell page for posting FW commands\n");
-}
-
 int mthca_QUERY_FW(struct mthca_dev *dev, u8 *status)
 {
        struct mthca_mailbox *mailbox;
        u32 *outbox;
-       u64 base;
-       u32 tmp;
        int err = 0;
        u8 lg;
-       int i;
 
 #define QUERY_FW_OUT_SIZE             0x100
 #define QUERY_FW_VER_OFFSET            0x00
@@ -746,10 +674,6 @@ int mthca_QUERY_FW(struct mthca_dev *dev, u8 *status)
 #define QUERY_FW_ERR_START_OFFSET      0x30
 #define QUERY_FW_ERR_SIZE_OFFSET       0x38
 
-#define QUERY_FW_CMD_DB_EN_OFFSET      0x10
-#define QUERY_FW_CMD_DB_OFFSET         0x50
-#define QUERY_FW_CMD_DB_BASE           0x60
-
 #define QUERY_FW_START_OFFSET          0x20
 #define QUERY_FW_END_OFFSET            0x28
 
@@ -780,28 +704,14 @@ int mthca_QUERY_FW(struct mthca_dev *dev, u8 *status)
 
        MTHCA_GET(lg, outbox, QUERY_FW_MAX_CMD_OFFSET);
        dev->cmd.max_cmds = 1 << lg;
-
-       mthca_dbg(dev, "FW version %012llx, max commands %d\n",
-                 (unsigned long long) dev->fw_ver, dev->cmd.max_cmds);
-
        MTHCA_GET(dev->catas_err.addr, outbox, QUERY_FW_ERR_START_OFFSET);
        MTHCA_GET(dev->catas_err.size, outbox, QUERY_FW_ERR_SIZE_OFFSET);
 
+       mthca_dbg(dev, "FW version %012llx, max commands %d\n",
+                 (unsigned long long) dev->fw_ver, dev->cmd.max_cmds);
        mthca_dbg(dev, "Catastrophic error buffer at 0x%llx, size 0x%x\n",
                  (unsigned long long) dev->catas_err.addr, dev->catas_err.size);
 
-       MTHCA_GET(tmp, outbox, QUERY_FW_CMD_DB_EN_OFFSET);
-       if (tmp & 0x1) {
-               mthca_dbg(dev, "FW supports commands through doorbells\n");
-
-               MTHCA_GET(base, outbox, QUERY_FW_CMD_DB_BASE);
-               for (i = 0; i < MTHCA_CMD_NUM_DBELL_DWORDS; ++i)
-                       MTHCA_GET(dev->cmd.dbell_offsets[i], outbox,
-                                 QUERY_FW_CMD_DB_OFFSET + (i << 1));
-
-               mthca_setup_cmd_doorbells(dev, base);
-       }
-
        if (mthca_is_memfree(dev)) {
                MTHCA_GET(dev->fw.arbel.fw_pages,       outbox, QUERY_FW_SIZE_OFFSET);
                MTHCA_GET(dev->fw.arbel.clr_int_base,   outbox, QUERY_FW_CLR_INT_BASE_OFFSET);
@@ -810,12 +720,12 @@ int mthca_QUERY_FW(struct mthca_dev *dev, u8 *status)
                mthca_dbg(dev, "FW size %d KB\n", dev->fw.arbel.fw_pages << 2);
 
                /*
-                * Round up number of system pages needed in case
-                * MTHCA_ICM_PAGE_SIZE < PAGE_SIZE.
+                * Arbel page size is always 4 KB; round up number of
+                * system pages needed.
                 */
                dev->fw.arbel.fw_pages =
-                       ALIGN(dev->fw.arbel.fw_pages, PAGE_SIZE / MTHCA_ICM_PAGE_SIZE) >>
-                               (PAGE_SHIFT - MTHCA_ICM_PAGE_SHIFT);
+                       ALIGN(dev->fw.arbel.fw_pages, PAGE_SIZE >> 12) >>
+                               (PAGE_SHIFT - 12);
 
                mthca_dbg(dev, "Clear int @ %llx, EQ arm @ %llx, EQ set CI @ %llx\n",
                          (unsigned long long) dev->fw.arbel.clr_int_base,
@@ -951,7 +861,6 @@ int mthca_QUERY_DEV_LIM(struct mthca_dev *dev,
        u32 *outbox;
        u8 field;
        u16 size;
-       u16 stat_rate;
        int err;
 
 #define QUERY_DEV_LIM_OUT_SIZE             0x100
@@ -982,7 +891,6 @@ int mthca_QUERY_DEV_LIM(struct mthca_dev *dev,
 #define QUERY_DEV_LIM_MTU_WIDTH_OFFSET      0x36
 #define QUERY_DEV_LIM_VL_PORT_OFFSET        0x37
 #define QUERY_DEV_LIM_MAX_GID_OFFSET        0x3b
-#define QUERY_DEV_LIM_RATE_SUPPORT_OFFSET   0x3c
 #define QUERY_DEV_LIM_MAX_PKEY_OFFSET       0x3f
 #define QUERY_DEV_LIM_FLAGS_OFFSET          0x44
 #define QUERY_DEV_LIM_RSVD_UAR_OFFSET       0x48
@@ -1074,8 +982,6 @@ int mthca_QUERY_DEV_LIM(struct mthca_dev *dev,
        dev_lim->num_ports = field & 0xf;
        MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_GID_OFFSET);
        dev_lim->max_gids = 1 << (field & 0xf);
-       MTHCA_GET(stat_rate, outbox, QUERY_DEV_LIM_RATE_SUPPORT_OFFSET);
-       dev_lim->stat_rate_support = stat_rate;
        MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_PKEY_OFFSET);
        dev_lim->max_pkeys = 1 << (field & 0xf);
        MTHCA_GET(dev_lim->flags, outbox, QUERY_DEV_LIM_FLAGS_OFFSET);
@@ -1267,8 +1173,7 @@ int mthca_INIT_HCA(struct mthca_dev *dev,
        int err;
 
 #define INIT_HCA_IN_SIZE                0x200
-#define INIT_HCA_FLAGS1_OFFSET           0x00c
-#define INIT_HCA_FLAGS2_OFFSET           0x014
+#define INIT_HCA_FLAGS_OFFSET           0x014
 #define INIT_HCA_QPC_OFFSET             0x020
 #define  INIT_HCA_QPC_BASE_OFFSET       (INIT_HCA_QPC_OFFSET + 0x10)
 #define  INIT_HCA_LOG_QP_OFFSET         (INIT_HCA_QPC_OFFSET + 0x17)
@@ -1311,18 +1216,15 @@ int mthca_INIT_HCA(struct mthca_dev *dev,
 
        memset(inbox, 0, INIT_HCA_IN_SIZE);
 
-       if (dev->mthca_flags & MTHCA_FLAG_SINAI_OPT)
-               MTHCA_PUT(inbox, 0x1, INIT_HCA_FLAGS1_OFFSET);
-
 #if defined(__LITTLE_ENDIAN)
-       *(inbox + INIT_HCA_FLAGS2_OFFSET / 4) &= ~cpu_to_be32(1 << 1);
+       *(inbox + INIT_HCA_FLAGS_OFFSET / 4) &= ~cpu_to_be32(1 << 1);
 #elif defined(__BIG_ENDIAN)
-       *(inbox + INIT_HCA_FLAGS2_OFFSET / 4) |= cpu_to_be32(1 << 1);
+       *(inbox + INIT_HCA_FLAGS_OFFSET / 4) |= cpu_to_be32(1 << 1);
 #else
 #error Host endianness not defined
 #endif
        /* Check port for UD address vector: */
-       *(inbox + INIT_HCA_FLAGS2_OFFSET / 4) |= cpu_to_be32(1);
+       *(inbox + INIT_HCA_FLAGS_OFFSET / 4) |= cpu_to_be32(1);
 
        /* We leave wqe_quota, responder_exu, etc as 0 (default) */
 
@@ -1536,11 +1438,11 @@ int mthca_SET_ICM_SIZE(struct mthca_dev *dev, u64 icm_size, u64 *aux_pages,
                return ret;
 
        /*
-        * Round up number of system pages needed in case
-        * MTHCA_ICM_PAGE_SIZE < PAGE_SIZE.
+        * Arbel page size is always 4 KB; round up number of system
+        * pages needed.
         */
-       *aux_pages = ALIGN(*aux_pages, PAGE_SIZE / MTHCA_ICM_PAGE_SIZE) >>
-               (PAGE_SHIFT - MTHCA_ICM_PAGE_SHIFT);
+       *aux_pages = (*aux_pages + (1 << (PAGE_SHIFT - 12)) - 1) >> (PAGE_SHIFT - 12);
+       *aux_pages = ALIGN(*aux_pages, PAGE_SIZE >> 12) >> (PAGE_SHIFT - 12);
 
        return 0;
 }
@@ -1612,37 +1514,6 @@ int mthca_HW2SW_CQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
                             CMD_TIME_CLASS_A, status);
 }
 
-int mthca_RESIZE_CQ(struct mthca_dev *dev, int cq_num, u32 lkey, u8 log_size,
-                   u8 *status)
-{
-       struct mthca_mailbox *mailbox;
-       __be32 *inbox;
-       int err;
-
-#define RESIZE_CQ_IN_SIZE              0x40
-#define RESIZE_CQ_LOG_SIZE_OFFSET      0x0c
-#define RESIZE_CQ_LKEY_OFFSET          0x1c
-
-       mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
-       if (IS_ERR(mailbox))
-               return PTR_ERR(mailbox);
-       inbox = mailbox->buf;
-
-       memset(inbox, 0, RESIZE_CQ_IN_SIZE);
-       /*
-        * Leave start address fields zeroed out -- mthca assumes that
-        * MRs for CQs always start at virtual address 0.
-        */
-       MTHCA_PUT(inbox, log_size, RESIZE_CQ_LOG_SIZE_OFFSET);
-       MTHCA_PUT(inbox, lkey,     RESIZE_CQ_LKEY_OFFSET);
-
-       err = mthca_cmd(dev, mailbox->dma, cq_num, 1, CMD_RESIZE_CQ,
-                       CMD_TIME_CLASS_B, status);
-
-       mthca_free_mailbox(dev, mailbox);
-       return err;
-}
-
 int mthca_SW2HW_SRQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
                    int srq_num, u8 *status)
 {
@@ -1658,69 +1529,37 @@ int mthca_HW2SW_SRQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
                             CMD_TIME_CLASS_A, status);
 }
 
-int mthca_QUERY_SRQ(struct mthca_dev *dev, u32 num,
-                   struct mthca_mailbox *mailbox, u8 *status)
-{
-       return mthca_cmd_box(dev, 0, mailbox->dma, num, 0,
-                            CMD_QUERY_SRQ, CMD_TIME_CLASS_A, status);
-}
-
 int mthca_ARM_SRQ(struct mthca_dev *dev, int srq_num, int limit, u8 *status)
 {
        return mthca_cmd(dev, limit, srq_num, 0, CMD_ARM_SRQ,
                         CMD_TIME_CLASS_B, status);
 }
 
-int mthca_MODIFY_QP(struct mthca_dev *dev, enum ib_qp_state cur,
-                   enum ib_qp_state next, u32 num, int is_ee,
-                   struct mthca_mailbox *mailbox, u32 optmask,
+int mthca_MODIFY_QP(struct mthca_dev *dev, int trans, u32 num,
+                   int is_ee, struct mthca_mailbox *mailbox, u32 optmask,
                    u8 *status)
 {
-       static const u16 op[IB_QPS_ERR + 1][IB_QPS_ERR + 1] = {
-               [IB_QPS_RESET] = {
-                       [IB_QPS_RESET]  = CMD_ERR2RST_QPEE,
-                       [IB_QPS_ERR]    = CMD_2ERR_QPEE,
-                       [IB_QPS_INIT]   = CMD_RST2INIT_QPEE,
-               },
-               [IB_QPS_INIT]  = {
-                       [IB_QPS_RESET]  = CMD_ERR2RST_QPEE,
-                       [IB_QPS_ERR]    = CMD_2ERR_QPEE,
-                       [IB_QPS_INIT]   = CMD_INIT2INIT_QPEE,
-                       [IB_QPS_RTR]    = CMD_INIT2RTR_QPEE,
-               },
-               [IB_QPS_RTR]   = {
-                       [IB_QPS_RESET]  = CMD_ERR2RST_QPEE,
-                       [IB_QPS_ERR]    = CMD_2ERR_QPEE,
-                       [IB_QPS_RTS]    = CMD_RTR2RTS_QPEE,
-               },
-               [IB_QPS_RTS]   = {
-                       [IB_QPS_RESET]  = CMD_ERR2RST_QPEE,
-                       [IB_QPS_ERR]    = CMD_2ERR_QPEE,
-                       [IB_QPS_RTS]    = CMD_RTS2RTS_QPEE,
-                       [IB_QPS_SQD]    = CMD_RTS2SQD_QPEE,
-               },
-               [IB_QPS_SQD] = {
-                       [IB_QPS_RESET]  = CMD_ERR2RST_QPEE,
-                       [IB_QPS_ERR]    = CMD_2ERR_QPEE,
-                       [IB_QPS_RTS]    = CMD_SQD2RTS_QPEE,
-                       [IB_QPS_SQD]    = CMD_SQD2SQD_QPEE,
-               },
-               [IB_QPS_SQE] = {
-                       [IB_QPS_RESET]  = CMD_ERR2RST_QPEE,
-                       [IB_QPS_ERR]    = CMD_2ERR_QPEE,
-                       [IB_QPS_RTS]    = CMD_SQERR2RTS_QPEE,
-               },
-               [IB_QPS_ERR] = {
-                       [IB_QPS_RESET]  = CMD_ERR2RST_QPEE,
-                       [IB_QPS_ERR]    = CMD_2ERR_QPEE,
-               }
+       static const u16 op[] = {
+               [MTHCA_TRANS_RST2INIT]  = CMD_RST2INIT_QPEE,
+               [MTHCA_TRANS_INIT2INIT] = CMD_INIT2INIT_QPEE,
+               [MTHCA_TRANS_INIT2RTR]  = CMD_INIT2RTR_QPEE,
+               [MTHCA_TRANS_RTR2RTS]   = CMD_RTR2RTS_QPEE,
+               [MTHCA_TRANS_RTS2RTS]   = CMD_RTS2RTS_QPEE,
+               [MTHCA_TRANS_SQERR2RTS] = CMD_SQERR2RTS_QPEE,
+               [MTHCA_TRANS_ANY2ERR]   = CMD_2ERR_QPEE,
+               [MTHCA_TRANS_RTS2SQD]   = CMD_RTS2SQD_QPEE,
+               [MTHCA_TRANS_SQD2SQD]   = CMD_SQD2SQD_QPEE,
+               [MTHCA_TRANS_SQD2RTS]   = CMD_SQD2RTS_QPEE,
+               [MTHCA_TRANS_ANY2RST]   = CMD_ERR2RST_QPEE
        };
-
        u8 op_mod = 0;
        int my_mailbox = 0;
        int err;
 
-       if (op[cur][next] == CMD_ERR2RST_QPEE) {
+       if (trans < 0 || trans >= ARRAY_SIZE(op))
+               return -EINVAL;
+
+       if (trans == MTHCA_TRANS_ANY2RST) {
                op_mod = 3;     /* don't write outbox, any->reset */
 
                /* For debugging */
@@ -1732,35 +1571,34 @@ int mthca_MODIFY_QP(struct mthca_dev *dev, enum ib_qp_state cur,
                        } else
                                mailbox = NULL;
                }
-
-               err = mthca_cmd_box(dev, 0, mailbox ? mailbox->dma : 0,
-                                   (!!is_ee << 24) | num, op_mod,
-                                   op[cur][next], CMD_TIME_CLASS_C, status);
-
-               if (0 && mailbox) {
+       } else {
+               if (0) {
                        int i;
                        mthca_dbg(dev, "Dumping QP context:\n");
-                       printk(" %08x\n", be32_to_cpup(mailbox->buf));
+                       printk("  opt param mask: %08x\n", be32_to_cpup(mailbox->buf));
                        for (i = 0; i < 0x100 / 4; ++i) {
                                if (i % 8 == 0)
-                                       printk("[%02x] ", i * 4);
+                                       printk("  [%02x] ", i * 4);
                                printk(" %08x",
                                       be32_to_cpu(((__be32 *) mailbox->buf)[i + 2]));
                                if ((i + 1) % 8 == 0)
                                        printk("\n");
                        }
                }
+       }
 
-               if (my_mailbox)
-                       mthca_free_mailbox(dev, mailbox);
-       } else {
-               if (0) {
+       if (trans == MTHCA_TRANS_ANY2RST) {
+               err = mthca_cmd_box(dev, 0, mailbox ? mailbox->dma : 0,
+                                   (!!is_ee << 24) | num, op_mod,
+                                   op[trans], CMD_TIME_CLASS_C, status);
+
+               if (0 && mailbox) {
                        int i;
                        mthca_dbg(dev, "Dumping QP context:\n");
-                       printk("  opt param mask: %08x\n", be32_to_cpup(mailbox->buf));
+                       printk(" %08x\n", be32_to_cpup(mailbox->buf));
                        for (i = 0; i < 0x100 / 4; ++i) {
                                if (i % 8 == 0)
-                                       printk("  [%02x] ", i * 4);
+                                       printk("[%02x] ", i * 4);
                                printk(" %08x",
                                       be32_to_cpu(((__be32 *) mailbox->buf)[i + 2]));
                                if ((i + 1) % 8 == 0)
@@ -1768,9 +1606,12 @@ int mthca_MODIFY_QP(struct mthca_dev *dev, enum ib_qp_state cur,
                        }
                }
 
-               err = mthca_cmd(dev, mailbox->dma, optmask | (!!is_ee << 24) | num,
-                               op_mod, op[cur][next], CMD_TIME_CLASS_C, status);
-       }
+       } else
+               err = mthca_cmd(dev, mailbox->dma, (!!is_ee << 24) | num,
+                               op_mod, op[trans], CMD_TIME_CLASS_C, status);
+
+       if (my_mailbox)
+               mthca_free_mailbox(dev, mailbox);
 
        return err;
 }