mpi_reply = mpt3sas_base_get_reply_virt_addr(ioc, reply);
        if (mpi_reply && mpi_reply->Function == MPI2_FUNCTION_EVENT_ACK)
-               return 1;
+               return mpt3sas_check_for_pending_internal_cmds(ioc, smid);
 
        if (ioc->base_cmds.status == MPT3_CMD_NOT_USED)
                return 1;
        Mpi2EventNotificationReply_t *mpi_reply;
        Mpi2EventAckRequest_t *ack_request;
        u16 smid;
+       struct _event_ack_list *delayed_event_ack;
 
        mpi_reply = mpt3sas_base_get_reply_virt_addr(ioc, reply);
        if (!mpi_reply)
                goto out;
        smid = mpt3sas_base_get_smid(ioc, ioc->base_cb_idx);
        if (!smid) {
-               pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n",
-                   ioc->name, __func__);
+               delayed_event_ack = kzalloc(sizeof(*delayed_event_ack),
+                                       GFP_ATOMIC);
+               if (!delayed_event_ack)
+                       goto out;
+               INIT_LIST_HEAD(&delayed_event_ack->list);
+               delayed_event_ack->Event = mpi_reply->Event;
+               delayed_event_ack->EventContext = mpi_reply->EventContext;
+               list_add_tail(&delayed_event_ack->list,
+                               &ioc->delayed_event_ack_list);
+               dewtprintk(ioc, pr_info(MPT3SAS_FMT
+                               "DELAYED: EVENT ACK: event (0x%04x)\n",
+                               ioc->name, le16_to_cpu(mpi_reply->Event)));
                goto out;
        }
 
        }
        ioc->shost->sg_tablesize = sg_tablesize;
 
-       ioc->hi_priority_depth = facts->HighPriorityCredit;
-       ioc->internal_depth = ioc->hi_priority_depth + (5);
+       ioc->internal_depth = min_t(int, (facts->HighPriorityCredit + (5)),
+               (facts->RequestCredit / 4));
+       if (ioc->internal_depth < INTERNAL_CMDS_COUNT) {
+               if (facts->RequestCredit <= (INTERNAL_CMDS_COUNT +
+                               INTERNAL_SCSIIO_CMDS_COUNT)) {
+                       pr_err(MPT3SAS_FMT "IOC doesn't have enough Request \
+                           Credits, it has just %d number of credits\n",
+                           ioc->name, facts->RequestCredit);
+                       return -ENOMEM;
+               }
+               ioc->internal_depth = 10;
+       }
+
+       ioc->hi_priority_depth = ioc->internal_depth - (5);
        /* command line tunables  for max controller queue depth */
        if (max_queue_depth != -1 && max_queue_depth != 0) {
                max_request_credit = min_t(u16, max_queue_depth +
-                   ioc->hi_priority_depth + ioc->internal_depth,
-                   facts->RequestCredit);
+                       ioc->internal_depth, facts->RequestCredit);
                if (max_request_credit > MAX_HBA_QUEUE_DEPTH)
                        max_request_credit =  MAX_HBA_QUEUE_DEPTH;
        } else
                max_request_credit = min_t(u16, facts->RequestCredit,
                    MAX_HBA_QUEUE_DEPTH);
 
-       ioc->hba_queue_depth = max_request_credit;
+       /* Firmware maintains additional facts->HighPriorityCredit number of
+        * credits for HiPriprity Request messages, so hba queue depth will be
+        * sum of max_request_credit and high priority queue depth.
+        */
+       ioc->hba_queue_depth = max_request_credit + ioc->hi_priority_depth;
 
        /* request frame size */
        ioc->request_sz = facts->IOCRequestFrameSize * 4;
                ioc->reply_post_queue_depth += 16 -
                (ioc->reply_post_queue_depth % 16);
 
-
        if (ioc->reply_post_queue_depth >
            facts->MaxReplyDescriptorPostQueueDepth) {
                ioc->reply_post_queue_depth =
        /* set the scsi host can_queue depth
         * with some internal commands that could be outstanding
         */
-       ioc->shost->can_queue = ioc->scsiio_depth;
+       ioc->shost->can_queue = ioc->scsiio_depth - INTERNAL_SCSIIO_CMDS_COUNT;
        dinitprintk(ioc, pr_info(MPT3SAS_FMT
                "scsi host: can_queue depth (%d)\n",
                ioc->name, ioc->shost->can_queue));
                    ioc->chains_needed_per_io, ioc->request_sz, sz/1024);
                if (ioc->scsiio_depth < MPT3SAS_SAS_QUEUE_DEPTH)
                        goto out;
-               retry_sz += 64;
-               ioc->hba_queue_depth = max_request_credit - retry_sz;
+               retry_sz = 64;
+               ioc->hba_queue_depth -= retry_sz;
                goto retry_allocation;
        }
 
        u32 reply_address;
        u16 smid;
        struct _tr_list *delayed_tr, *delayed_tr_next;
+       struct _sc_list *delayed_sc, *delayed_sc_next;
+       struct _event_ack_list *delayed_event_ack, *delayed_event_ack_next;
        u8 hide_flag;
        struct adapter_reply_queue *reply_q;
        long reply_post_free;
                kfree(delayed_tr);
        }
 
+       list_for_each_entry_safe(delayed_sc, delayed_sc_next,
+           &ioc->delayed_sc_list, list) {
+               list_del(&delayed_sc->list);
+               kfree(delayed_sc);
+       }
+
+       list_for_each_entry_safe(delayed_event_ack, delayed_event_ack_next,
+           &ioc->delayed_event_ack_list, list) {
+               list_del(&delayed_event_ack->list);
+               kfree(delayed_event_ack);
+       }
+
        /* initialize the scsi lookup free list */
        spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
        INIT_LIST_HEAD(&ioc->free_list);
 
 #define  NO_SLEEP                      0
 
 #define INTERNAL_CMDS_COUNT            10      /* reserved cmds */
+/* reserved for issuing internally framed scsi io cmds */
+#define INTERNAL_SCSIIO_CMDS_COUNT     3
 
 #define MPI3_HIM_MASK                  0xFFFFFFFF /* mask every bit*/
 
        u16     state;
 };
 
+/**
+ * struct _sc_list - delayed SAS_IO_UNIT_CONTROL message list
+ * @handle: device handle
+ */
+struct _sc_list {
+       struct list_head list;
+       u16     handle;
+};
+
+/**
+ * struct _event_ack_list - delayed event acknowledgment list
+ * @Event: Event ID
+ * @EventContext: used to track the event uniquely
+ */
+struct _event_ack_list {
+       struct list_head list;
+       u16     Event;
+       u32     EventContext;
+};
 
 /**
  * struct adapter_reply_queue - the reply queue struct
  * @replyPostRegisterIndex: index of next position in Reply Desc Post Queue
  * @delayed_tr_list: target reset link list
  * @delayed_tr_volume_list: volume target reset link list
+ * @delayed_sc_list:
+ * @delayed_event_ack_list:
  * @temp_sensors_count: flag to carry the number of temperature sensors
  * @pci_access_mutex: Mutex to synchronize ioctl,sysfs show path and
  *     pci resource handling. PCI resource freeing will lead to free
 
        struct list_head delayed_tr_list;
        struct list_head delayed_tr_volume_list;
+       struct list_head delayed_sc_list;
+       struct list_head delayed_event_ack_list;
        u8              temp_sensors_count;
        struct mutex pci_access_mutex;
 
 void mpt3sas_expander_remove(struct MPT3SAS_ADAPTER *ioc, u64 sas_address);
 void mpt3sas_device_remove_by_sas_address(struct MPT3SAS_ADAPTER *ioc,
        u64 sas_address);
+u8 mpt3sas_check_for_pending_internal_cmds(struct MPT3SAS_ADAPTER *ioc,
+       u16 smid);
 
 struct _sas_node *mpt3sas_scsih_expander_find_by_handle(
        struct MPT3SAS_ADAPTER *ioc, u16 handle);
 
        Mpi2SasIoUnitControlRequest_t *mpi_request;
        u16 smid_sas_ctrl;
        u32 ioc_state;
+       struct _sc_list *delayed_sc;
 
        if (ioc->remove_host) {
                dewtprintk(ioc, pr_info(MPT3SAS_FMT
 
        smid_sas_ctrl = mpt3sas_base_get_smid(ioc, ioc->tm_sas_control_cb_idx);
        if (!smid_sas_ctrl) {
-               pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n",
-                   ioc->name, __func__);
-               return 1;
+               delayed_sc = kzalloc(sizeof(*delayed_sc), GFP_ATOMIC);
+               if (!delayed_sc)
+                       return _scsih_check_for_pending_tm(ioc, smid);
+               INIT_LIST_HEAD(&delayed_sc->list);
+               delayed_sc->handle = mpi_request_tm->DevHandle;
+               list_add_tail(&delayed_sc->list, &ioc->delayed_sc_list);
+               dewtprintk(ioc, pr_info(MPT3SAS_FMT
+                   "DELAYED:sc:handle(0x%04x), (open)\n",
+                   ioc->name, handle));
+               return _scsih_check_for_pending_tm(ioc, smid);
        }
 
        dewtprintk(ioc, pr_info(MPT3SAS_FMT
                pr_err(MPT3SAS_FMT "mpi_reply not valid at %s:%d/%s()!\n",
                    ioc->name, __FILE__, __LINE__, __func__);
        }
-       return 1;
+       return mpt3sas_check_for_pending_internal_cmds(ioc, smid);
 }
 
 /**
        return _scsih_check_for_pending_tm(ioc, smid);
 }
 
+/**
+ * _scsih_issue_delayed_event_ack - issue delayed Event ACK messages
+ * @ioc: per adapter object
+ * @smid: system request message index
+ * @event: Event ID
+ * @event_context: used to track events uniquely
+ *
+ * Context - processed in interrupt context.
+ */
+void
+_scsih_issue_delayed_event_ack(struct MPT3SAS_ADAPTER *ioc, u16 smid, u16 event,
+                               u32 event_context)
+{
+       Mpi2EventAckRequest_t *ack_request;
+       int i = smid - ioc->internal_smid;
+       unsigned long flags;
+
+       /* Without releasing the smid just update the
+        * call back index and reuse the same smid for
+        * processing this delayed request
+        */
+       spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
+       ioc->internal_lookup[i].cb_idx = ioc->base_cb_idx;
+       spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
+
+       dewtprintk(ioc, pr_info(MPT3SAS_FMT
+               "EVENT ACK: event(0x%04x), smid(%d), cb(%d)\n",
+               ioc->name, le16_to_cpu(event), smid,
+               ioc->base_cb_idx));
+       ack_request = mpt3sas_base_get_msg_frame(ioc, smid);
+       memset(ack_request, 0, sizeof(Mpi2EventAckRequest_t));
+       ack_request->Function = MPI2_FUNCTION_EVENT_ACK;
+       ack_request->Event = event;
+       ack_request->EventContext = event_context;
+       ack_request->VF_ID = 0;  /* TODO */
+       ack_request->VP_ID = 0;
+       mpt3sas_base_put_smid_default(ioc, smid);
+}
+
+/**
+ * _scsih_issue_delayed_sas_io_unit_ctrl - issue delayed
+ *                             sas_io_unit_ctrl messages
+ * @ioc: per adapter object
+ * @smid: system request message index
+ * @handle: device handle
+ *
+ * Context - processed in interrupt context.
+ */
+void
+_scsih_issue_delayed_sas_io_unit_ctrl(struct MPT3SAS_ADAPTER *ioc,
+                                       u16 smid, u16 handle)
+       {
+               Mpi2SasIoUnitControlRequest_t *mpi_request;
+               u32 ioc_state;
+               int i = smid - ioc->internal_smid;
+               unsigned long flags;
+
+               if (ioc->remove_host) {
+                       dewtprintk(ioc, pr_info(MPT3SAS_FMT
+                           "%s: host has been removed\n",
+                            __func__, ioc->name));
+                       return;
+               } else if (ioc->pci_error_recovery) {
+                       dewtprintk(ioc, pr_info(MPT3SAS_FMT
+                           "%s: host in pci error recovery\n",
+                           __func__, ioc->name));
+               return;
+       }
+       ioc_state = mpt3sas_base_get_iocstate(ioc, 1);
+       if (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
+               dewtprintk(ioc, pr_info(MPT3SAS_FMT
+                   "%s: host is not operational\n",
+                   __func__, ioc->name));
+               return;
+       }
+
+       /* Without releasing the smid just update the
+        * call back index and reuse the same smid for
+        * processing this delayed request
+        */
+       spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
+       ioc->internal_lookup[i].cb_idx = ioc->tm_sas_control_cb_idx;
+       spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
+
+       dewtprintk(ioc, pr_info(MPT3SAS_FMT
+           "sc_send:handle(0x%04x), (open), smid(%d), cb(%d)\n",
+           ioc->name, le16_to_cpu(handle), smid,
+           ioc->tm_sas_control_cb_idx));
+       mpi_request = mpt3sas_base_get_msg_frame(ioc, smid);
+       memset(mpi_request, 0, sizeof(Mpi2SasIoUnitControlRequest_t));
+       mpi_request->Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL;
+       mpi_request->Operation = MPI2_SAS_OP_REMOVE_DEVICE;
+       mpi_request->DevHandle = handle;
+       mpt3sas_base_put_smid_default(ioc, smid);
+}
+
+/**
+ * _scsih_check_for_pending_internal_cmds - check for pending internal messages
+ * @ioc: per adapter object
+ * @smid: system request message index
+ *
+ * Context: Executed in interrupt context
+ *
+ * This will check delayed internal messages list, and process the
+ * next request.
+ *
+ * Return 1 meaning mf should be freed from _base_interrupt
+ *        0 means the mf is freed from this function.
+ */
+u8
+mpt3sas_check_for_pending_internal_cmds(struct MPT3SAS_ADAPTER *ioc, u16 smid)
+{
+       struct _sc_list *delayed_sc;
+       struct _event_ack_list *delayed_event_ack;
+
+       if (!list_empty(&ioc->delayed_event_ack_list)) {
+               delayed_event_ack = list_entry(ioc->delayed_event_ack_list.next,
+                                               struct _event_ack_list, list);
+               _scsih_issue_delayed_event_ack(ioc, smid,
+                 delayed_event_ack->Event, delayed_event_ack->EventContext);
+               list_del(&delayed_event_ack->list);
+               kfree(delayed_event_ack);
+               return 0;
+       }
+
+       if (!list_empty(&ioc->delayed_sc_list)) {
+               delayed_sc = list_entry(ioc->delayed_sc_list.next,
+                                               struct _sc_list, list);
+               _scsih_issue_delayed_sas_io_unit_ctrl(ioc, smid,
+                                                delayed_sc->handle);
+               list_del(&delayed_sc->list);
+               kfree(delayed_sc);
+               return 0;
+       }
+       return 1;
+}
 
 /**
  * _scsih_check_for_pending_tm - check for pending task management
        INIT_LIST_HEAD(&ioc->raid_device_list);
        INIT_LIST_HEAD(&ioc->sas_hba.sas_port_list);
        INIT_LIST_HEAD(&ioc->delayed_tr_list);
+       INIT_LIST_HEAD(&ioc->delayed_sc_list);
+       INIT_LIST_HEAD(&ioc->delayed_event_ack_list);
        INIT_LIST_HEAD(&ioc->delayed_tr_volume_list);
        INIT_LIST_HEAD(&ioc->reply_queue_list);