[PATCH 28/32] elx: efct: IO timeout handling routines

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This patch continues the efct driver population.

This patch adds driver definitions for:
Add support for a WQE timer to handle the wqe and IO timeouts.

Signed-off-by: Ram Vegesna <ram.vegesna@xxxxxxxxxxxx>
Signed-off-by: James Smart <jsmart2021@xxxxxxxxx>
---
 drivers/scsi/elx/efct/efct_hw.c | 209 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 209 insertions(+)

diff --git a/drivers/scsi/elx/efct/efct_hw.c b/drivers/scsi/elx/efct/efct_hw.c
index 48cdbeebd058..751edbd2ddf9 100644
--- a/drivers/scsi/elx/efct/efct_hw.c
+++ b/drivers/scsi/elx/efct/efct_hw.c
@@ -5716,3 +5716,212 @@ efct_hw_get_num_eq(struct efct_hw_s *hw)
 {
 	return hw->eq_count;
 }
+
+/**
+ * @brief HW async call context structure.
+ */
+struct efct_hw_async_call_ctx_s {
+	efct_hw_async_cb_t callback;
+	void *arg;
+	u8 cmd[SLI4_BMBX_SIZE];
+};
+
+/**
+ * @brief HW async callback handler
+ *
+ * @par Description
+ * This function is called when the NOP mbox cmd completes.  The callback stored
+ * in the requesting context is invoked.
+ *
+ * @param hw Pointer to HW object.
+ * @param status Completion status.
+ * @param mqe Pointer to mailbox completion queue entry.
+ * @param arg Caller-provided argument.
+ *
+ * @return None.
+ */
+static void
+efct_hw_async_cb(struct efct_hw_s *hw, int status, u8 *mqe, void *arg)
+{
+	struct efct_hw_async_call_ctx_s *ctx = arg;
+
+	if (ctx) {
+		if (ctx->callback)
+			(*ctx->callback)(hw, status, mqe, ctx->arg);
+
+		kfree(ctx);
+	}
+}
+
+/**
+ * @brief Make an async callback using NOP mailbox command
+ *
+ * @par Description
+ * Post a NOP mbox cmd; the callback with argument is invoked upon completion
+ * while in the event processing context.
+ *
+ * @param hw Pointer to HW object.
+ * @param callback Pointer to callback function.
+ * @param arg Caller-provided callback.
+ *
+ * @return Returns 0 on success, or a negative error code value on failure.
+ */
+int
+efct_hw_async_call(struct efct_hw_s *hw,
+		   efct_hw_async_cb_t callback, void *arg)
+{
+	int rc = 0;
+	struct efct_hw_async_call_ctx_s *ctx;
+
+	/*
+	 * Allocate a callback context (which includes the mbox cmd buffer),
+	 * we need this to be persistent as the mbox cmd submission may be
+	 * queued and executed later execution.
+	 */
+	ctx = kmalloc(sizeof(*ctx), GFP_ATOMIC);
+	if (!ctx)
+		return EFCT_HW_RTN_NO_MEMORY;
+
+	memset(ctx, 0, sizeof(*ctx));
+	ctx->callback = callback;
+	ctx->arg = arg;
+
+	/* Build and send a NOP mailbox command */
+	if (!sli_cmd_common_nop(&hw->sli, ctx->cmd,
+			       sizeof(ctx->cmd), 0) == 0) {
+		efc_log_err(hw->os, "COMMON_NOP format failure\n");
+		kfree(ctx);
+		rc = -1;
+	}
+
+	if (efct_hw_command(hw, ctx->cmd, EFCT_CMD_NOWAIT, efct_hw_async_cb,
+			    ctx)) {
+		efc_log_err(hw->os, "COMMON_NOP command failure\n");
+		kfree(ctx);
+		rc = -1;
+	}
+	return rc;
+}
+
+static int
+target_wqe_timer_nop_cb(struct efct_hw_s *hw, int status,
+			u8 *mqe, void *arg)
+{
+	struct efct_hw_io_s *io = NULL;
+	struct efct_hw_io_s *io_next = NULL;
+	u64 ticks_current = jiffies_64;
+	u32 sec_elapsed;
+	struct sli4_mbox_command_header_s *hdr =
+				(struct sli4_mbox_command_header_s *)mqe;
+	unsigned long flags = 0;
+
+	if (status || le16_to_cpu(hdr->status)) {
+		efc_log_debug(hw->os, "bad status st=%x hdr=%x\n",
+			       status,
+			       le16_to_cpu(hdr->status));
+		/* go ahead and proceed with wqe timer checks... */
+	}
+
+	/* loop through active WQE list and check for timeouts */
+	spin_lock_irqsave(&hw->io_lock, flags);
+	list_for_each_entry_safe(io, io_next, &hw->io_timed_wqe, wqe_link) {
+		sec_elapsed = ((u32)(ticks_current - io->submit_ticks) / HZ);
+
+		/*
+		 * If elapsed time > timeout, abort it. No need to check type
+		 * since it wouldn't be on this list unless it was a target WQE
+		 */
+		if (sec_elapsed > io->tgt_wqe_timeout) {
+			efc_log_test(hw->os,
+				      "IO timeout xri=0x%x tag=0x%x type=%d\n",
+				     io->indicator, io->reqtag, io->type);
+
+			/*
+			 * remove from active_wqe list so won't try to abort
+			 * again
+			 */
+			list_del(&io->list_entry);
+
+			/* save status of timed_out for when abort completes */
+			io->status_saved = true;
+			io->saved_status =
+					 SLI4_FC_WCQE_STATUS_TARGET_WQE_TIMEOUT;
+			io->saved_ext = 0;
+			io->saved_len = 0;
+
+			/* now abort outstanding IO */
+			efct_hw_io_abort(hw, io, false, NULL, NULL);
+		}
+		/*
+		 * need to go through entire list since each IO could have a
+		 * different timeout value
+		 */
+	}
+	spin_unlock_irqrestore(&hw->io_lock, flags);
+
+	/* if we're not in the middle of shutting down, schedule next timer */
+	if (!hw->active_wqe_timer_shutdown) {
+		timer_setup(&hw->wqe_timer,
+			    &target_wqe_timer_cb, 0);
+
+		mod_timer(&hw->wqe_timer,
+			  jiffies +
+			  msecs_to_jiffies(EFCT_HW_WQ_TIMER_PERIOD_MS));
+	}
+	hw->in_active_wqe_timer = false;
+	return 0;
+}
+
+static void
+target_wqe_timer_cb(struct timer_list *t)
+{
+	struct efct_hw_s *hw = from_timer(hw, t, wqe_timer);
+
+	/*
+	 * delete existing timer; will kick off new timer after checking wqe
+	 * timeouts
+	 */
+	hw->in_active_wqe_timer = true;
+	del_timer(&hw->wqe_timer);
+
+	/*
+	 * Forward timer callback to execute in the mailbox completion
+	 * processing context
+	 */
+	if (efct_hw_async_call(hw, target_wqe_timer_nop_cb, hw))
+		efc_log_test(hw->os, "efct_hw_async_call failed\n");
+}
+
+static void
+shutdown_target_wqe_timer(struct efct_hw_s *hw)
+{
+	u32	iters = 100;
+
+	if (hw->config.emulate_tgt_wqe_timeout) {
+		/*
+		 * request active wqe timer shutdown, then wait for it to
+		 * complete
+		 */
+		hw->active_wqe_timer_shutdown = true;
+
+		/*
+		 * delete WQE timer and wait for timer handler to complete
+		 * (if necessary)
+		 */
+		del_timer(&hw->wqe_timer);
+
+		/* now wait for timer handler to complete (if necessary) */
+		while (hw->in_active_wqe_timer && iters) {
+			/*
+			 * if we happen to have just sent NOP mbox cmn, make
+			 * sure completions are being processed
+			 */
+			efct_hw_flush(hw);
+			iters--;
+		}
+
+		if (iters == 0)
+			efc_log_test(hw->os,
+				      "Failed to shutdown active wqe timer\n");
+	}
+}
-- 
2.13.7





[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [SCSI Target Devel]     [Linux SCSI Target Infrastructure]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Linux IIO]     [Samba]     [Device Mapper]

  Powered by Linux