unsigned long flags;
        struct vio_dev *vdev = to_vio_dev(vhost->dev);
        struct ibmvfc_queue *crq = &vhost->crq;
+       struct ibmvfc_queue *scrq;
+       int i;
 
        /* Close the CRQ */
        do {
        memset(crq->msgs.crq, 0, PAGE_SIZE);
        crq->cur = 0;
 
+       if (vhost->scsi_scrqs.scrqs) {
+               for (i = 0; i < IBMVFC_SCSI_HW_QUEUES; i++) {
+                       scrq = &vhost->scsi_scrqs.scrqs[i];
+                       spin_lock(scrq->q_lock);
+                       memset(scrq->msgs.scrq, 0, PAGE_SIZE);
+                       scrq->cur = 0;
+                       spin_unlock(scrq->q_lock);
+               }
+       }
+
        /* And re-open it again */
        rc = plpar_hcall_norets(H_REG_CRQ, vdev->unit_address,
                                crq->msg_token, PAGE_SIZE);
        case IBMVFC_ASYNC_FMT:
                fmt_size = sizeof(*queue->msgs.async);
                break;
+       case IBMVFC_SUB_CRQ_FMT:
+               fmt_size = sizeof(*queue->msgs.scrq);
+               /* We need one extra event for Cancel Commands */
+               pool_size = max_requests + 1;
+               break;
        default:
                dev_warn(dev, "Unknown command/response queue message format: %d\n", fmt);
                return -EINVAL;
        return retrc;
 }
 
+static int ibmvfc_register_scsi_channel(struct ibmvfc_host *vhost,
+                                 int index)
+{
+       struct device *dev = vhost->dev;
+       struct vio_dev *vdev = to_vio_dev(dev);
+       struct ibmvfc_queue *scrq = &vhost->scsi_scrqs.scrqs[index];
+       int rc = -ENOMEM;
+
+       ENTER;
+
+       if (ibmvfc_alloc_queue(vhost, scrq, IBMVFC_SUB_CRQ_FMT))
+               return -ENOMEM;
+
+       rc = h_reg_sub_crq(vdev->unit_address, scrq->msg_token, PAGE_SIZE,
+                          &scrq->cookie, &scrq->hw_irq);
+
+       if (rc) {
+               dev_warn(dev, "Error registering sub-crq: %d\n", rc);
+               if (rc == H_PARAMETER)
+                       dev_warn_once(dev, "Firmware may not support MQ\n");
+               goto reg_failed;
+       }
+
+       scrq->hwq_id = index;
+       scrq->vhost = vhost;
+
+       LEAVE;
+       return 0;
+
+reg_failed:
+       ibmvfc_free_queue(vhost, scrq);
+       LEAVE;
+       return rc;
+}
+
+static void ibmvfc_deregister_scsi_channel(struct ibmvfc_host *vhost, int index)
+{
+       struct device *dev = vhost->dev;
+       struct vio_dev *vdev = to_vio_dev(dev);
+       struct ibmvfc_queue *scrq = &vhost->scsi_scrqs.scrqs[index];
+       long rc;
+
+       ENTER;
+
+       do {
+               rc = plpar_hcall_norets(H_FREE_SUB_CRQ, vdev->unit_address,
+                                       scrq->cookie);
+       } while (rc == H_BUSY || H_IS_LONG_BUSY(rc));
+
+       if (rc)
+               dev_err(dev, "Failed to free sub-crq[%d]: rc=%ld\n", index, rc);
+
+       ibmvfc_free_queue(vhost, scrq);
+       LEAVE;
+}
+
+static int ibmvfc_init_sub_crqs(struct ibmvfc_host *vhost)
+{
+       int i, j;
+
+       ENTER;
+
+       vhost->scsi_scrqs.scrqs = kcalloc(IBMVFC_SCSI_HW_QUEUES,
+                                         sizeof(*vhost->scsi_scrqs.scrqs),
+                                         GFP_KERNEL);
+       if (!vhost->scsi_scrqs.scrqs)
+               return -1;
+
+       for (i = 0; i < IBMVFC_SCSI_HW_QUEUES; i++) {
+               if (ibmvfc_register_scsi_channel(vhost, i)) {
+                       for (j = i; j > 0; j--)
+                               ibmvfc_deregister_scsi_channel(vhost, j - 1);
+                       kfree(vhost->scsi_scrqs.scrqs);
+                       vhost->scsi_scrqs.scrqs = NULL;
+                       vhost->scsi_scrqs.active_queues = 0;
+                       LEAVE;
+                       return -1;
+               }
+       }
+
+       LEAVE;
+       return 0;
+}
+
+static void ibmvfc_release_sub_crqs(struct ibmvfc_host *vhost)
+{
+       int i;
+
+       ENTER;
+       if (!vhost->scsi_scrqs.scrqs)
+               return;
+
+       for (i = 0; i < IBMVFC_SCSI_HW_QUEUES; i++)
+               ibmvfc_deregister_scsi_channel(vhost, i);
+
+       kfree(vhost->scsi_scrqs.scrqs);
+       vhost->scsi_scrqs.scrqs = NULL;
+       vhost->scsi_scrqs.active_queues = 0;
+       LEAVE;
+}
+
 /**
  * ibmvfc_free_mem - Free memory for vhost
  * @vhost:     ibmvfc host struct
                goto remove_shost;
        }
 
+       if (vhost->mq_enabled) {
+               rc = ibmvfc_init_sub_crqs(vhost);
+               if (rc)
+                       dev_warn(dev, "Failed to allocate Sub-CRQs. rc=%d\n", rc);
+       }
+
        if (shost_to_fc_host(shost)->rqst_q)
                blk_queue_max_segments(shost_to_fc_host(shost)->rqst_q, 1);
        dev_set_drvdata(dev, vhost);
        list_splice_init(&vhost->purge, &purge);
        spin_unlock_irqrestore(vhost->host->host_lock, flags);
        ibmvfc_complete_purge(&purge);
+       ibmvfc_release_sub_crqs(vhost);
        ibmvfc_release_crq_queue(vhost);
 
        ibmvfc_free_mem(vhost);