isci: replace isci_timer list with proper embedded timers

Rather than preallocating a list of timers and doling them out at runtime,
embed a struct timerlist in each object that needs one.  A struct sci_timer
interface is introduced to manage the timer cancellation semantics which
currently need to guarantee the timer is cancelled while holding
spin_lock(ihost->scic_lock).  Since the timeout functions also need to acquire
the lock it currently prevents the driver from using del_timer_sync() for
runtime cancellations.

del_timer_sync() is used however before the objects go out of scope.

Signed-off-by: Edmund Nadolski <edmund.nadolski@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
diff --git a/drivers/scsi/isci/isci.h b/drivers/scsi/isci/isci.h
index 69826ea..2fe5557 100644
--- a/drivers/scsi/isci/isci.h
+++ b/drivers/scsi/isci/isci.h
@@ -551,4 +551,37 @@
 irqreturn_t isci_msix_isr(int vec, void *data);
 irqreturn_t isci_intx_isr(int vec, void *data);
 irqreturn_t isci_error_isr(int vec, void *data);
+
+/*
+ * Each timer is associated with a cancellation flag that is set when
+ * del_timer() is called and checked in the timer callback function. This
+ * is needed since del_timer_sync() cannot be called with scic_lock held.
+ * For deinit however, del_timer_sync() is used without holding the lock.
+ */
+struct sci_timer {
+	struct timer_list	timer;
+	bool			cancel;
+};
+
+static inline
+void sci_init_timer(struct sci_timer *tmr, void (*fn)(unsigned long))
+{
+	tmr->timer.function = fn;
+	tmr->timer.data = (unsigned long) tmr;
+	tmr->cancel = 0;
+	init_timer(&tmr->timer);
+}
+
+static inline void sci_mod_timer(struct sci_timer *tmr, unsigned long msec)
+{
+	tmr->cancel = 0;
+	mod_timer(&tmr->timer, jiffies + msecs_to_jiffies(msec));
+}
+
+static inline void sci_del_timer(struct sci_timer *tmr)
+{
+	tmr->cancel = 1;
+	del_timer(&tmr->timer);
+}
+
 #endif  /* __ISCI_H__ */