public inbox for linux-scsi@vger.kernel.org
 help / color / mirror / Atom feed
* [SCSI] aic94xx: remove event thread
@ 2006-03-12 16:06 James Bottomley
  2006-03-12 16:29 ` James Bottomley
  2006-03-14 18:00 ` Alexis Bruemmer
  0 siblings, 2 replies; 3+ messages in thread
From: James Bottomley @ 2006-03-12 16:06 UTC (permalink / raw)
  To: linux-scsi

This patch moves the discovery and event processing entirely over to
being workqueue based.  Additionally, it tries to ensure discovery gets
time to proceed before finishing the module load.  There's still a
non-determinism in there since it starts with a port interrupt for a
connected phy after phys are enabled, so there's a ssleep(1) in there to
capture this before the scsi_flush_work() waits for it to complete.

James

diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h
index 7b6534a..f716c1d 100644
--- a/drivers/scsi/lpfc/lpfc_crtn.h
+++ b/drivers/scsi/lpfc/lpfc_crtn.h
@@ -84,6 +84,7 @@ int lpfc_els_rsp_adisc_acc(struct lpfc_h
 			   struct lpfc_nodelist *);
 int lpfc_els_rsp_prli_acc(struct lpfc_hba *, struct lpfc_iocbq *,
 			  struct lpfc_nodelist *);
+void lpfc_cancel_retry_delay_tmo(struct lpfc_hba *, struct lpfc_nodelist *);
 void lpfc_els_retry_delay(unsigned long);
 void lpfc_els_retry_delay_handler(struct lpfc_nodelist *);
 void lpfc_els_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *,
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c
index efba875..6d12cd0 100644
--- a/drivers/scsi/lpfc/lpfc_els.c
+++ b/drivers/scsi/lpfc/lpfc_els.c
@@ -1435,6 +1435,46 @@ lpfc_issue_els_farpr(struct lpfc_hba * p
 }
 
 void
+lpfc_cancel_retry_delay_tmo(struct lpfc_hba *phba, struct lpfc_nodelist * nlp)
+{
+	nlp->nlp_flag &= ~NLP_DELAY_TMO;
+	del_timer_sync(&nlp->nlp_delayfunc);
+	nlp->nlp_last_elscmd = 0;
+
+	if (!list_empty(&nlp->els_retry_evt.evt_listp))
+		list_del_init(&nlp->els_retry_evt.evt_listp);
+
+	if (nlp->nlp_flag & NLP_NPR_2B_DISC) {
+		nlp->nlp_flag &= ~NLP_NPR_2B_DISC;
+		if (phba->num_disc_nodes) {
+			/* Check to see if there are more
+			 * PLOGIs to be sent
+			 */
+			lpfc_more_plogi(phba);
+		}
+
+		if (phba->num_disc_nodes == 0) {
+			phba->fc_flag &= ~FC_NDISC_ACTIVE;
+			lpfc_can_disctmo(phba);
+			if (phba->fc_flag & FC_RSCN_MODE) {
+				/* Check to see if more RSCNs
+				 * came in while we were
+				 * processing this one.
+				 */
+				if((phba->fc_rscn_id_cnt==0) &&
+				   (!(phba->fc_flag & FC_RSCN_DISCOVERY))) {
+					phba->fc_flag &= ~FC_RSCN_MODE;
+				}
+				else {
+					lpfc_els_handle_rscn(phba);
+				}
+			}
+		}
+	}
+	return;
+}
+
+void
 lpfc_els_retry_delay(unsigned long ptr)
 {
 	struct lpfc_nodelist *ndlp;
@@ -2415,15 +2455,8 @@ lpfc_rscn_recovery_check(struct lpfc_hba
 			/* Make sure NLP_DELAY_TMO is NOT running
 			 * after a device recovery event.
 			 */
-			if (ndlp->nlp_flag & NLP_DELAY_TMO) {
-				ndlp->nlp_flag &= ~NLP_DELAY_TMO;
-				ndlp->nlp_last_elscmd = 0;
-				del_timer_sync(&ndlp->nlp_delayfunc);
-				if (!list_empty(&ndlp->
-						els_retry_evt.evt_listp))
-					list_del_init(&ndlp->
-						els_retry_evt.evt_listp);
-			}
+			if (ndlp->nlp_flag & NLP_DELAY_TMO)
+				lpfc_cancel_retry_delay_tmo(phba, ndlp);
 		}
 	}
 	return 0;
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
index 2b227b3..e15120d 100644
--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
@@ -1152,13 +1152,9 @@ lpfc_nlp_list(struct lpfc_hba * phba, st
 		/* Stop delay tmo if taking node off NPR list */
 		if ((nlp->nlp_flag & NLP_DELAY_TMO) &&
 		   (list != NLP_NPR_LIST)) {
-			nlp->nlp_flag &= ~NLP_DELAY_TMO;
-			nlp->nlp_last_elscmd = 0;
 			spin_unlock_irq(phba->host->host_lock);
-			del_timer_sync(&nlp->nlp_delayfunc);
+			lpfc_cancel_retry_delay_tmo(phba, nlp);
 			spin_lock_irq(phba->host->host_lock);
-			if (!list_empty(&nlp->els_retry_evt.evt_listp))
-				list_del_init(&nlp->els_retry_evt.evt_listp);
 		}
 		break;
 	}
@@ -1598,13 +1594,7 @@ lpfc_nlp_remove(struct lpfc_hba * phba, 
 
 
 	if (ndlp->nlp_flag & NLP_DELAY_TMO) {
-		spin_lock_irq(phba->host->host_lock);
-		ndlp->nlp_flag &= ~NLP_DELAY_TMO;
-		spin_unlock_irq(phba->host->host_lock);
-		ndlp->nlp_last_elscmd = 0;
-		del_timer_sync(&ndlp->nlp_delayfunc);
-		if (!list_empty(&ndlp->els_retry_evt.evt_listp))
-			list_del_init(&ndlp->els_retry_evt.evt_listp);
+		lpfc_cancel_retry_delay_tmo(phba, ndlp);
 	}
 
 	if (ndlp->nlp_disc_refcnt) {
@@ -1896,14 +1886,8 @@ lpfc_setup_disc_node(struct lpfc_hba * p
 			/* Since this node is marked for discovery,
 			 * delay timeout is not needed.
 			 */
-			if (ndlp->nlp_flag & NLP_DELAY_TMO) {
-				ndlp->nlp_flag &= ~NLP_DELAY_TMO;
-				del_timer_sync(&ndlp->nlp_delayfunc);
-				if (!list_empty(&ndlp->els_retry_evt.
-								evt_listp))
-					list_del_init(&ndlp->els_retry_evt.
-						      		evt_listp);
-			}
+			if (ndlp->nlp_flag & NLP_DELAY_TMO)
+				lpfc_cancel_retry_delay_tmo(phba, ndlp);
 		} else {
 			ndlp->nlp_flag &= ~NLP_NPR_2B_DISC;
 			ndlp = NULL;
diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c
index 8affc15..3d77bd9 100644
--- a/drivers/scsi/lpfc/lpfc_nportdisc.c
+++ b/drivers/scsi/lpfc/lpfc_nportdisc.c
@@ -259,13 +259,8 @@ lpfc_els_abort(struct lpfc_hba * phba, s
 	} while(found);
 
 	/* If we are delaying issuing an ELS command, cancel it */
-	if (ndlp->nlp_flag & NLP_DELAY_TMO) {
-		ndlp->nlp_flag &= ~NLP_DELAY_TMO;
-		ndlp->nlp_last_elscmd = 0;
-		del_timer_sync(&ndlp->nlp_delayfunc);
-		if (!list_empty(&ndlp->els_retry_evt.evt_listp))
-			list_del_init(&ndlp->els_retry_evt.evt_listp);
-	}
+	if (ndlp->nlp_flag & NLP_DELAY_TMO)
+		lpfc_cancel_retry_delay_tmo(phba, ndlp);
 	return 0;
 }
 
@@ -1496,7 +1491,7 @@ lpfc_rcv_plogi_npr_node(struct lpfc_hba 
 
 	if (lpfc_rcv_plogi(phba, ndlp, cmdiocb)) {
 		spin_lock_irq(phba->host->host_lock);
-		ndlp->nlp_flag &= ~(NLP_NPR_ADISC | NLP_NPR_2B_DISC);
+		ndlp->nlp_flag &= ~NLP_NPR_ADISC;
 		spin_unlock_irq(phba->host->host_lock);
 		return ndlp->nlp_state;
 	}
@@ -1693,16 +1688,10 @@ lpfc_device_recov_npr_node(struct lpfc_h
 {
 	spin_lock_irq(phba->host->host_lock);
 	ndlp->nlp_flag &= ~NLP_NPR_2B_DISC;
+	spin_unlock_irq(phba->host->host_lock);
 	if (ndlp->nlp_flag & NLP_DELAY_TMO) {
-		ndlp->nlp_flag &= ~NLP_DELAY_TMO;
-		if (!list_empty(&ndlp->els_retry_evt.evt_listp))
-			list_del_init(&ndlp->els_retry_evt.evt_listp);
-		spin_unlock_irq(phba->host->host_lock);
-		ndlp->nlp_last_elscmd = 0;
-		del_timer_sync(&ndlp->nlp_delayfunc);
-		return ndlp->nlp_state;
+		lpfc_cancel_retry_delay_tmo(phba, ndlp);
 	}
-	spin_unlock_irq(phba->host->host_lock);
 	return ndlp->nlp_state;
 }
 



^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [SCSI] aic94xx: remove event thread
  2006-03-12 16:06 [SCSI] aic94xx: remove event thread James Bottomley
@ 2006-03-12 16:29 ` James Bottomley
  2006-03-14 18:00 ` Alexis Bruemmer
  1 sibling, 0 replies; 3+ messages in thread
From: James Bottomley @ 2006-03-12 16:29 UTC (permalink / raw)
  To: linux-scsi

On Sun, 2006-03-12 at 10:06 -0600, James Bottomley wrote:
> This patch moves the discovery and event processing entirely over to
> being workqueue based.  Additionally, it tries to ensure discovery gets
> time to proceed before finishing the module load.  There's still a
> non-determinism in there since it starts with a port interrupt for a
> connected phy after phys are enabled, so there's a ssleep(1) in there to
> capture this before the scsi_flush_work() waits for it to complete.

Er, OK, this time with the actual correct patch.

James

diff --git a/drivers/scsi/aic94xx/aic94xx_init.c b/drivers/scsi/aic94xx/aic94xx_init.c
index 924075d..161106e 100644
--- a/drivers/scsi/aic94xx/aic94xx_init.c
+++ b/drivers/scsi/aic94xx/aic94xx_init.c
@@ -30,6 +30,7 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
+#include <linux/delay.h>
 
 #include <scsi/scsi_host.h>
 
@@ -632,6 +633,11 @@ static int __devinit asd_pci_probe(struc
 		goto Err_en_phys;
 	}
 	ASD_DPRINTK("enabled phys\n");
+	/* give the phy enabling interrupt event time to come in (1s
+	 * is empirically about all it takes) */
+	ssleep(1);
+	/* Wait for discovery to finish */
+	scsi_flush_work(asd_ha->sas_ha.core.shost);
 
 	return 0;
 Err_en_phys:
diff --git a/drivers/scsi/sas/sas_discover.c b/drivers/scsi/sas/sas_discover.c
index 05ff2ed..c10b453 100644
--- a/drivers/scsi/sas/sas_discover.c
+++ b/drivers/scsi/sas/sas_discover.c
@@ -567,9 +567,13 @@ void sas_unregister_dev(struct domain_de
 	sas_rphy_delete(dev->rphy);
 }
 
-static void sas_unregister_domain_devices(struct sas_port *port)
+static void sas_unregister_domain_devices(void *data)
 {
 	struct domain_device *dev, *n;
+	struct sas_port *port = data;
+
+	sas_begin_event(DISCE_PORT_GONE, &port->disc.disc_event_lock,
+			&port->disc.pending);
 
 	list_for_each_entry_reverse_safe(dev,n,&port->dev_list,dev_list_node)
 		sas_unregister_dev(dev);
@@ -586,16 +590,20 @@ static void sas_unregister_domain_device
  * Discover process only interrogates devices in order to discover the
  * domain.
  */
-static int sas_discover_domain(struct sas_port *port)
+static void sas_discover_domain(void *data)
 {
 	int error = 0;
+	struct sas_port *port = data;
+
+	sas_begin_event(DISCE_DISCOVER_DOMAIN, &port->disc.disc_event_lock,
+			&port->disc.pending);
 
 	if (port->port_dev)
-		return 0;
+		return ;
 	else {
 		error = sas_get_port_device(port);
 		if (error)
-			return error;
+			return;
 	}
 
 	SAS_DPRINTK("DOING DISCOVERY on port %d, pid:%d\n", port->id,
@@ -625,13 +633,15 @@ static int sas_discover_domain(struct sa
 
 	SAS_DPRINTK("DONE DISCOVERY on port %d, pid:%d, result:%d\n", port->id,
 		    current->pid, error);
-
-	return error;
 }
 
-static int sas_revalidate_domain(struct sas_port *port)
+static void sas_revalidate_domain(void *data)
 {
 	int res = 0;
+	struct sas_port *port = data;
+
+	sas_begin_event(DISCE_REVALIDATE_DOMAIN, &port->disc.disc_event_lock,
+			&port->disc.pending);
 
 	SAS_DPRINTK("REVALIDATING DOMAIN on port %d, pid:%d\n", port->id,
 		    current->pid);
@@ -640,81 +650,20 @@ static int sas_revalidate_domain(struct 
 
 	SAS_DPRINTK("done REVALIDATING DOMAIN on port %d, pid:%d, res 0x%x\n",
 		    port->id, current->pid, res);
-	return res;
 }
 
-/* ---------- Threads and events ---------- */
-
-static void sas_discover_work_fn(void *_sas_port)
-{
-	struct sas_port *port = _sas_port;
-	struct sas_discovery *disc = &port->disc;
-
-	spin_lock(&disc->disc_event_lock);
-	disc->disc_thread = 1;
-	while (!disc->disc_thread_quit && !list_empty(&disc->disc_event_list)){
-		struct list_head *head = disc->disc_event_list.next;
-		enum discover_event disc_ev = container_of(head,
-							   struct sas_event,
-							   el)->event;
-		list_del_init(head);
-		spin_unlock(&disc->disc_event_lock);
-
-		switch (disc_ev) {
-		case DISCE_DISCOVER_DOMAIN:
-			sas_discover_domain(port);
-			break;
-		case DISCE_REVALIDATE_DOMAIN:
-			sas_revalidate_domain(port);
-			break;
-		case DISCE_PORT_GONE:
-			sas_unregister_domain_devices(port);
-			complete(&port->port_gone_completion);
-			break;
-		}
-		spin_lock(&disc->disc_event_lock);
-	}
-	INIT_LIST_HEAD(&disc->disc_event_list);
-	disc->disc_thread = 0;
-	spin_unlock(&disc->disc_event_lock);
-	up(&disc->disc_sema);
-}
+/* ---------- Events ---------- */
 
 int sas_discover_event(struct sas_port *port, enum discover_event ev)
 {
 	struct sas_discovery *disc = &port->disc;
 
-	spin_lock(&disc->disc_event_lock);
-	list_move_tail(&disc->disc_events[ev].el,
-		       &disc->disc_event_list);
-	if (disc->disc_thread) {
-		spin_unlock(&disc->disc_event_lock);
-		return 0;
-	}
-	down_interruptible(&disc->disc_sema);
-	disc->disc_thread_quit = 0;
-	spin_unlock(&disc->disc_event_lock);
-
-	/* The event thread (caller) is single threaded so this is safe. */
-	INIT_WORK(&port->work, sas_discover_work_fn, port);
-	scsi_queue_work(port->ha->core.shost, &port->work);
+	BUG_ON(ev >= DISC_NUM_EVENTS);
 
-	return 0;
-}
-
-void sas_kill_disc_thread(struct sas_port *port)
-{
-	struct sas_discovery *disc = &port->disc;
+	sas_queue_event(ev, &disc->disc_event_lock, &disc->pending,
+			&disc->disc_work[ev], port->ha->core.shost);
 
-	spin_lock(&disc->disc_event_lock);
-	disc->disc_thread_quit = 1;
-	if (disc->disc_thread) {
-		spin_unlock(&disc->disc_event_lock);
-		scsi_flush_work(port->ha->core.shost);
-		down_interruptible(&disc->disc_sema);
-		return;
-	}
-	spin_unlock(&disc->disc_event_lock);
+	return 0;
 }
 
 /**
@@ -727,17 +676,16 @@ void sas_init_disc(struct sas_discovery 
 {
 	int i;
 
+	static void (*sas_event_fns[DISC_NUM_EVENTS])(void *) = {
+		[DISCE_DISCOVER_DOMAIN] = sas_discover_domain,
+		[DISCE_REVALIDATE_DOMAIN] = sas_revalidate_domain,
+		[DISCE_PORT_GONE] = sas_unregister_domain_devices,
+	};
+
 	spin_lock_init(&disc->disc_event_lock);
-	INIT_LIST_HEAD(&disc->disc_event_list);
-	init_MUTEX(&disc->disc_sema);
-	disc->disc_thread = 0;
-	disc->disc_thread_quit = 0;
-
-	for (i = 0; i < DISC_NUM_EVENTS; i++) {
-		struct sas_event *ev = &disc->disc_events[i];
-		ev->event = i;
-		INIT_LIST_HEAD(&ev->el);
-	}
+	disc->pending = 0;
+	for (i = 0; i < DISC_NUM_EVENTS; i++)
+		INIT_WORK(&disc->disc_work[i], sas_event_fns[i], port);
 }
 
 void sas_unregister_devices(struct sas_ha_struct *sas_ha)
diff --git a/drivers/scsi/sas/sas_event.c b/drivers/scsi/sas/sas_event.c
index f06f4a3..587368b 100644
--- a/drivers/scsi/sas/sas_event.c
+++ b/drivers/scsi/sas/sas_event.c
@@ -68,227 +68,50 @@
 #include "sas_dump.h"
 #include <scsi/sas/sas_discover.h>
 
-static void sas_process_phy_event(struct asd_sas_phy *phy)
-{
-	unsigned long flags;
-	struct sas_ha_struct *sas_ha = phy->ha;
-	enum phy_event phy_event;
-
-	spin_lock_irqsave(&sas_ha->event_lock, flags);
-	while (!list_empty(&phy->phy_event_list)) {
-		struct list_head *head = phy->phy_event_list.next;
-		phy_event = container_of(head, struct sas_event, el)->event;
-		list_del_init(head);
-		spin_unlock_irqrestore(&sas_ha->event_lock, flags);
-
-		sas_dprint_phye(phy->id, phy_event);
-
-		switch(phy_event) {
-		case PHYE_LOSS_OF_SIGNAL:
-			sas_phye_loss_of_signal(phy);
-			break;
-		case PHYE_OOB_DONE:
-			sas_phye_oob_done(phy);
-			break;
-		case PHYE_OOB_ERROR:
-			sas_phye_oob_error(phy);
-			break;
-		case PHYE_SPINUP_HOLD:
-			sas_phye_spinup_hold(phy);
-			break;
-		}
-		spin_lock_irqsave(&sas_ha->event_lock, flags);
-	}
-	/* Clear the bit in case we received events in due time. */
-	sas_ha->phye_mask &= ~(1 << phy->id);
-	spin_unlock_irqrestore(&sas_ha->event_lock, flags);
-}
-
-static void sas_process_port_event(struct asd_sas_phy *phy)
-{
-	unsigned long flags;
-	struct sas_ha_struct *sas_ha = phy->ha;
-	enum port_event port_event;
-
-	spin_lock_irqsave(&sas_ha->event_lock, flags);
-	while (!list_empty(&phy->port_event_list)) {
-		struct list_head *head = phy->port_event_list.next;
-		port_event = container_of(head, struct sas_event, el)->event;
-		list_del_init(head);
-		spin_unlock_irqrestore(&sas_ha->event_lock, flags);
-
-		sas_dprint_porte(phy->id, port_event);
-
-		switch (port_event) {
-		case PORTE_BYTES_DMAED:
-			sas_porte_bytes_dmaed(phy);
-			break;
-		case PORTE_BROADCAST_RCVD:
-			sas_porte_broadcast_rcvd(phy);
-			break;
-		case PORTE_LINK_RESET_ERR:
-			sas_porte_link_reset_err(phy);
-			break;
-		case PORTE_TIMER_EVENT:
-			sas_porte_timer_event(phy);
-			break;
-		case PORTE_HARD_RESET:
-			sas_porte_hard_reset(phy);
-			break;
-		}
-		spin_lock_irqsave(&sas_ha->event_lock, flags);
-	}
-	/* Clear the bit in case we received events in due time. */
-	sas_ha->porte_mask &= ~(1 << phy->id);
-	spin_unlock_irqrestore(&sas_ha->event_lock, flags);
-}
-
-static void sas_process_ha_event(struct sas_ha_struct *sas_ha)
-{
-	unsigned long flags;
-	enum ha_event ha_event;
-
-	spin_lock_irqsave(&sas_ha->event_lock, flags);
-	while (!list_empty(&sas_ha->ha_event_list)) {
-		struct list_head *head = sas_ha->ha_event_list.next;
-		ha_event = container_of(head, struct sas_event, el)->event;
-		list_del_init(head);
-		spin_unlock_irqrestore(&sas_ha->event_lock, flags);
-
-		sas_dprint_hae(sas_ha, ha_event);
-
-		switch (ha_event) {
-		case HAE_RESET:
-			sas_hae_reset(sas_ha);
-			break;
-		}
-		spin_lock_irqsave(&sas_ha->event_lock, flags);
-	}
-	spin_unlock_irqrestore(&sas_ha->event_lock, flags);
-}
-
-static void sas_process_events(struct sas_ha_struct *sas_ha)
-{
-	unsigned long flags;
-	u32 porte_mask, phye_mask;
-	int p;
-
-	spin_lock_irqsave(&sas_ha->event_lock, flags);
-	phye_mask = sas_ha->phye_mask;
-	sas_ha->phye_mask = 0;
-	spin_unlock_irqrestore(&sas_ha->event_lock, flags);
-
-	for (p = 0; phye_mask != 0; phye_mask >>= 1, p++)
-		if (phye_mask & 01)
-			sas_process_phy_event(sas_ha->sas_phy[p]);
-
-	spin_lock_irqsave(&sas_ha->event_lock, flags);
-	porte_mask = sas_ha->porte_mask;
-	sas_ha->porte_mask = 0;
-	spin_unlock_irqrestore(&sas_ha->event_lock, flags);
-
-	for (p = 0; porte_mask != 0; porte_mask >>= 1, p++)
-		if (porte_mask & 01)
-			sas_process_port_event(sas_ha->sas_phy[p]);
-
-	sas_process_ha_event(sas_ha);
-}
-
 static void notify_ha_event(struct sas_ha_struct *sas_ha, enum ha_event event)
 {
-	unsigned long flags;
+	BUG_ON(event >= HA_NUM_EVENTS);
 
-	spin_lock_irqsave(&sas_ha->event_lock, flags);
-	list_move_tail(&sas_ha->ha_events[event].el, &sas_ha->ha_event_list);
-	up(&sas_ha->event_sema);
-	spin_unlock_irqrestore(&sas_ha->event_lock, flags);
+	sas_queue_event(event, &sas_ha->event_lock, &sas_ha->pending,
+			&sas_ha->ha_events[event], sas_ha->core.shost);
 }
 
 static void notify_port_event(struct asd_sas_phy *phy, enum port_event event)
 {
 	struct sas_ha_struct *ha = phy->ha;
-	unsigned long flags;
 
-	spin_lock_irqsave(&ha->event_lock, flags);
-	list_move_tail(&phy->port_events[event].el, &phy->port_event_list);
-	ha->porte_mask |= (1 << phy->id);
-	up(&ha->event_sema);
-	spin_unlock_irqrestore(&ha->event_lock, flags);
+	BUG_ON(event >= PORT_NUM_EVENTS);
+
+	sas_queue_event(event, &ha->event_lock, &phy->port_events_pending,
+			&phy->port_events[event], ha->core.shost);
 }
 
 static void notify_phy_event(struct asd_sas_phy *phy, enum phy_event event)
 {
 	struct sas_ha_struct *ha = phy->ha;
-	unsigned long flags;
-
-	spin_lock_irqsave(&ha->event_lock, flags);
-	list_move_tail(&phy->phy_events[event].el, &phy->phy_event_list);
-	ha->phye_mask |= (1 << phy->id);
-	up(&ha->event_sema);
-	spin_unlock_irqrestore(&ha->event_lock, flags);
-}
 
-static DECLARE_COMPLETION(event_th_comp);
+	BUG_ON(event >= PHY_NUM_EVENTS);
 
-static int sas_event_thread(void *_sas_ha)
-{
-	struct sas_ha_struct *sas_ha = _sas_ha;
-
-	daemonize("sas_event_%d", sas_ha->core.shost->host_no);
-	current->flags |= PF_NOFREEZE;
-
-	complete(&event_th_comp);
-
-	while (1) {
-		down_interruptible(&sas_ha->event_sema);
-		if (sas_ha->event_thread_kill)
-			break;
-		sas_process_events(sas_ha);
-	}
-
-	complete(&event_th_comp);
-
-	return 0;
+	sas_queue_event(event, &ha->event_lock, &phy->phy_events_pending,
+			&phy->phy_events[event], ha->core.shost);
 }
 
-int sas_start_event_thread(struct sas_ha_struct *sas_ha)
+int sas_init_events(struct sas_ha_struct *sas_ha)
 {
-	int i;
+	static void (*sas_ha_event_fns[HA_NUM_EVENTS])(void *) = {
+		[HAE_RESET] = sas_hae_reset,
+	};
 
-	init_MUTEX_LOCKED(&sas_ha->event_sema);
-	sas_ha->event_thread_kill = 0;
+	int i;
 
 	spin_lock_init(&sas_ha->event_lock);
-	INIT_LIST_HEAD(&sas_ha->ha_event_list);
-	sas_ha->porte_mask = 0;
-	sas_ha->phye_mask = 0;
-
-	for (i = 0; i < HA_NUM_EVENTS; i++) {
-		struct sas_event *ev = &sas_ha->ha_events[i];
-		ev->event = i;
-		INIT_LIST_HEAD(&ev->el);
-	}
+
+	for (i = 0; i < HA_NUM_EVENTS; i++)
+		INIT_WORK(&sas_ha->ha_events[i], sas_ha_event_fns[i], sas_ha);
 
 	sas_ha->notify_ha_event = notify_ha_event;
 	sas_ha->notify_port_event = notify_port_event;
 	sas_ha->notify_phy_event = notify_phy_event;
 
-	i = kernel_thread(sas_event_thread, sas_ha, 0);
-	if (i >= 0)
-		wait_for_completion(&event_th_comp);
-
-	return i < 0 ? i : 0;
-}
-
-void sas_kill_event_thread(struct sas_ha_struct *sas_ha)
-{
-	int i;
-
-	init_completion(&event_th_comp);
-	sas_ha->event_thread_kill = 1;
-	up(&sas_ha->event_sema);
-	wait_for_completion(&event_th_comp);
-
-	for (i = 0; i < sas_ha->num_phys; i++)
-		sas_kill_disc_thread(sas_ha->sas_port[i]);
+	return 0;
 }
diff --git a/drivers/scsi/sas/sas_init.c b/drivers/scsi/sas/sas_init.c
index 4f89cf5..39d4f99 100644
--- a/drivers/scsi/sas/sas_init.c
+++ b/drivers/scsi/sas/sas_init.c
@@ -40,9 +40,12 @@ kmem_cache_t *sas_task_cache;
 
 /* ---------- HA events ---------- */
 
-void sas_hae_reset(struct sas_ha_struct *sas_ha)
+void sas_hae_reset(void *data)
 {
-	;
+	struct sas_ha_struct *ha = data;
+
+	sas_begin_event(HAE_RESET, &ha->event_lock,
+			&ha->pending);
 }
 
 int sas_register_ha(struct sas_ha_struct *sas_ha,
@@ -77,7 +80,7 @@ int sas_register_ha(struct sas_ha_struct
 		goto Undo_phys;
 	}
 
-	error = sas_start_event_thread(sas_ha);
+	error = sas_init_events(sas_ha);
 	if (error) {
 		printk(KERN_NOTICE "couldn't start event thread:%d\n", error);
 		goto Undo_ports;
@@ -92,8 +95,6 @@ int sas_register_ha(struct sas_ha_struct
 		}
 	}
 
-	/* wait for discovery to finish */
-	scsi_flush_work(sas_ha->core.shost);
 	return 0;
 
 Undo_ports:
@@ -113,8 +114,6 @@ int sas_unregister_ha(struct sas_ha_stru
 		sas_shutdown_queue(sas_ha);
 	}
 
-	sas_kill_event_thread(sas_ha);
-
 	sas_unregister_ports(sas_ha);
 
 	sas_unregister_scsi_host(sas_ha);
diff --git a/drivers/scsi/sas/sas_internal.h b/drivers/scsi/sas/sas_internal.h
index bc9c1cb..90d772e 100644
--- a/drivers/scsi/sas/sas_internal.h
+++ b/drivers/scsi/sas/sas_internal.h
@@ -28,6 +28,7 @@
 #define _SAS_INTERNAL_H_
 
 #include <scsi/sas/sas_class.h>
+#include <scsi/scsi_host.h>
 
 #define sas_printk(fmt, ...) printk(KERN_NOTICE "sas: " fmt, ## __VA_ARGS__)
 
@@ -53,29 +54,43 @@ extern int  sas_register_scsi_host(struc
 				   struct scsi_transport_template *);
 void sas_unregister_scsi_host(struct sas_ha_struct *sas_ha);
 
-int  sas_start_event_thread(struct sas_ha_struct *sas_ha);
-void sas_kill_event_thread(struct sas_ha_struct *sas_ha);
-
 int  sas_init_queue(struct sas_ha_struct *sas_ha);
+int  sas_init_events(struct sas_ha_struct *sas_ha);
 void sas_shutdown_queue(struct sas_ha_struct *sas_ha);
 
-void sas_phye_loss_of_signal(struct asd_sas_phy *phy);
-void sas_phye_oob_done(struct asd_sas_phy *phy);
-void sas_phye_oob_error(struct asd_sas_phy *phy);
-void sas_phye_spinup_hold(struct asd_sas_phy *phy);
-
 void sas_deform_port(struct asd_sas_phy *phy);
 
-void sas_porte_bytes_dmaed(struct asd_sas_phy *phy);
-void sas_porte_broadcast_rcvd(struct asd_sas_phy *phy);
-void sas_porte_link_reset_err(struct asd_sas_phy *phy);
-void sas_porte_timer_event(struct asd_sas_phy *phy);
-void sas_porte_hard_reset(struct asd_sas_phy *phy);
-
-int  sas_reserve_free_id(struct sas_port *port);
-void sas_reserve_scsi_id(struct sas_port *port, int id);
-void sas_release_scsi_id(struct sas_port *port, int id);
-
-void sas_hae_reset(struct sas_ha_struct *sas_ha);
+void sas_porte_bytes_dmaed(void *);
+void sas_porte_broadcast_rcvd(void *);
+void sas_porte_link_reset_err(void *);
+void sas_porte_timer_event(void *);
+void sas_porte_hard_reset(void *);
+
+void sas_hae_reset(void *);
+
+static inline void sas_queue_event(int event, spinlock_t *lock, u32 *pending,
+				   struct work_struct *work,
+				   struct Scsi_Host *shost)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(lock, flags);
+	if (*pending & (1 << event)) {
+		spin_unlock_irqrestore(lock, flags);
+		return;
+	}
+	*pending |= (1 << event);
+	spin_unlock_irqrestore(lock, flags);
+	scsi_queue_work(shost, work);
+}
+
+static inline void sas_begin_event(int event, spinlock_t *lock, u32 *pending)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(lock, flags);
+	*pending &= ~(1 << event);
+	spin_unlock_irqrestore(lock, flags);
+}
 
 #endif /* _SAS_INTERNAL_H_ */
diff --git a/drivers/scsi/sas/sas_phy.c b/drivers/scsi/sas/sas_phy.c
index 6014351..bc2834c 100644
--- a/drivers/scsi/sas/sas_phy.c
+++ b/drivers/scsi/sas/sas_phy.c
@@ -29,22 +29,34 @@
 
 /* ---------- Phy events ---------- */
 
-void sas_phye_loss_of_signal(struct asd_sas_phy *phy)
+static void sas_phye_loss_of_signal(void *data)
 {
+	struct asd_sas_phy *phy = data;
+
+	sas_begin_event(PHYE_LOSS_OF_SIGNAL, &phy->ha->event_lock,
+			&phy->phy_events_pending);
 	phy->error = 0;
 	sas_deform_port(phy);
 }
 
-void sas_phye_oob_done(struct asd_sas_phy *phy)
+static void sas_phye_oob_done(void *data)
 {
+	struct asd_sas_phy *phy = data;
+
+	sas_begin_event(PHYE_OOB_DONE, &phy->ha->event_lock,
+			&phy->phy_events_pending);
 	phy->error = 0;
 }
 
-void sas_phye_oob_error(struct asd_sas_phy *phy)
+static void sas_phye_oob_error(void *data)
 {
+	struct asd_sas_phy *phy = data;
 	struct sas_ha_struct *sas_ha = phy->ha;
 	struct sas_port *port = phy->port;
 
+	sas_begin_event(PHYE_OOB_ERROR, &phy->ha->event_lock,
+			&phy->phy_events_pending);
+
 	sas_deform_port(phy);
 
 	if (!port && phy->enabled && sas_ha->lldd_control_phy) {
@@ -64,10 +76,14 @@ void sas_phye_oob_error(struct asd_sas_p
 	}
 }
 
-void sas_phye_spinup_hold(struct asd_sas_phy *phy)
+static void sas_phye_spinup_hold(void *data)
 {
+	struct asd_sas_phy *phy = data;
 	struct sas_ha_struct *sas_ha = phy->ha;
 
+	sas_begin_event(PHYE_SPINUP_HOLD, &phy->ha->event_lock,
+			&phy->phy_events_pending);
+
 	phy->error = 0;
 	sas_ha->lldd_control_phy(phy, PHY_FUNC_RELEASE_SPINUP_HOLD);
 }
@@ -78,6 +94,21 @@ int sas_register_phys(struct sas_ha_stru
 {
 	int i;
 
+	static void (*sas_phy_event_fns[PHY_NUM_EVENTS])(void *) = {
+		[PHYE_LOSS_OF_SIGNAL] = sas_phye_loss_of_signal,
+		[PHYE_OOB_DONE] = sas_phye_oob_done,
+		[PHYE_OOB_ERROR] = sas_phye_oob_error,
+		[PHYE_SPINUP_HOLD] = sas_phye_spinup_hold,
+	};
+
+	static void (*sas_port_event_fns[PORT_NUM_EVENTS])(void *) = {
+		[PORTE_BYTES_DMAED] = sas_porte_bytes_dmaed,
+		[PORTE_BROADCAST_RCVD] = sas_porte_broadcast_rcvd,
+		[PORTE_LINK_RESET_ERR] = sas_porte_link_reset_err,
+		[PORTE_TIMER_EVENT] = sas_porte_timer_event,
+		[PORTE_HARD_RESET] = sas_porte_hard_reset,
+	};
+
 	/* Now register the phys. */
 	for (i = 0; i < sas_ha->num_phys; i++) {
 		int k;
@@ -85,18 +116,13 @@ int sas_register_phys(struct sas_ha_stru
 
 		phy->error = 0;
 		INIT_LIST_HEAD(&phy->port_phy_el);
-		INIT_LIST_HEAD(&phy->port_event_list);
-		INIT_LIST_HEAD(&phy->phy_event_list);
-		for (k = 0; k < PORT_NUM_EVENTS; k++) {
-			struct sas_event *ev = &phy->port_events[k];
-			ev->event = k;
-			INIT_LIST_HEAD(&ev->el);
-		}
-		for (k = 0; k < PHY_NUM_EVENTS; k++) {
-			struct sas_event *ev = &phy->phy_events[k];
-			ev->event = k;
-			INIT_LIST_HEAD(&ev->el);
-		}
+		for (k = 0; k < PORT_NUM_EVENTS; k++)
+			INIT_WORK(&phy->port_events[k], sas_port_event_fns[k],
+				  phy);
+
+		for (k = 0; k < PHY_NUM_EVENTS; k++)
+			INIT_WORK(&phy->phy_events[k], sas_phy_event_fns[k],
+				  phy);
 		phy->port = NULL;
 		phy->ha = sas_ha;
 		spin_lock_init(&phy->frame_rcvd_lock);
diff --git a/drivers/scsi/sas/sas_port.c b/drivers/scsi/sas/sas_port.c
index 53117e4..6177423 100644
--- a/drivers/scsi/sas/sas_port.c
+++ b/drivers/scsi/sas/sas_port.c
@@ -167,15 +167,24 @@ void sas_deform_port(struct asd_sas_phy 
 
 /* ---------- SAS port events ---------- */
 
-void sas_porte_bytes_dmaed(struct asd_sas_phy *phy)
+void sas_porte_bytes_dmaed(void *data)
 {
+	struct asd_sas_phy *phy = data;
+
+	sas_begin_event(PORTE_BYTES_DMAED, &phy->ha->event_lock,
+			&phy->port_events_pending);
+
 	sas_form_port(phy);
 }
 
-void sas_porte_broadcast_rcvd(struct asd_sas_phy *phy)
+void sas_porte_broadcast_rcvd(void *data)
 {
 	unsigned long flags;
 	u32 prim;
+	struct asd_sas_phy *phy = data;
+
+	sas_begin_event(PORTE_BROADCAST_RCVD, &phy->ha->event_lock,
+			&phy->port_events_pending);
 
 	spin_lock_irqsave(&phy->sas_prim_lock, flags);
 	prim = phy->sas_prim;
@@ -185,18 +194,33 @@ void sas_porte_broadcast_rcvd(struct asd
 	sas_discover_event(phy->port, DISCE_REVALIDATE_DOMAIN);
 }
 
-void sas_porte_link_reset_err(struct asd_sas_phy *phy)
+void sas_porte_link_reset_err(void *data)
 {
+	struct asd_sas_phy *phy = data;
+
+	sas_begin_event(PORTE_LINK_RESET_ERR, &phy->ha->event_lock,
+			&phy->port_events_pending);
+
 	sas_deform_port(phy);
 }
 
-void sas_porte_timer_event(struct asd_sas_phy *phy)
+void sas_porte_timer_event(void *data)
 {
+	struct asd_sas_phy *phy = data;
+
+	sas_begin_event(PORTE_TIMER_EVENT, &phy->ha->event_lock,
+			&phy->port_events_pending);
+
 	sas_deform_port(phy);
 }
 
-void sas_porte_hard_reset(struct asd_sas_phy *phy)
+void sas_porte_hard_reset(void *data)
 {
+	struct asd_sas_phy *phy = data;
+
+	sas_begin_event(PORTE_HARD_RESET, &phy->ha->event_lock,
+			&phy->port_events_pending);
+
 	sas_deform_port(phy);
 }
 
diff --git a/include/scsi/sas/sas_class.h b/include/scsi/sas/sas_class.h
index f7b8a26..e275fb6 100644
--- a/include/scsi/sas/sas_class.h
+++ b/include/scsi/sas/sas_class.h
@@ -86,21 +86,17 @@ enum discover_event {
 };
 #define DISC_NUM_EVENTS 3
 
-struct sas_event {
-	int    event;
-	struct list_head el;
-};
-
 /* The phy pretty much is controlled by the LLDD.
  * The class only reads those fields.
  */
 struct asd_sas_phy {
 /* private: */
 	/* protected by ha->event_lock */
-	struct list_head   port_event_list;
-	struct list_head   phy_event_list;
-	struct sas_event   port_events[PORT_NUM_EVENTS];
-	struct sas_event   phy_events[PHY_NUM_EVENTS];
+	struct work_struct   port_events[PORT_NUM_EVENTS];
+	struct work_struct   phy_events[PHY_NUM_EVENTS];
+
+	u32 port_events_pending;
+	u32 phy_events_pending;
 
 	int error;
 
@@ -142,12 +138,8 @@ struct sas_port;
 
 struct sas_discovery {
 	spinlock_t disc_event_lock;
-	unsigned        disc_thread_quit:1;
-	unsigned	disc_thread:1;
-	struct list_head disc_event_list;
-	struct sas_event disc_events[DISC_NUM_EVENTS];
-	struct semaphore  disc_sema;
-
+	struct work_struct disc_work[DISC_NUM_EVENTS];
+	u32    pending;
 	u8     fanout_sas_addr[8];
 	u8     eeds_a[8];
 	u8     eeds_b[8];
@@ -207,14 +199,9 @@ struct scsi_core {
 
 struct sas_ha_struct {
 /* private: */
-	struct semaphore event_sema;
-	int              event_thread_kill;
-
 	spinlock_t       event_lock;
-	struct list_head ha_event_list;
-	struct sas_event ha_events[HA_NUM_EVENTS];
-	u32              porte_mask; /* mask of phys for port events */
-	u32              phye_mask; /* mask of phys for phy events */
+	struct work_struct ha_events[HA_NUM_EVENTS];
+	u32		 pending;
 
 	struct scsi_core core;
 
diff --git a/include/scsi/sas/sas_discover.h b/include/scsi/sas/sas_discover.h
index 2aa56f3..df0cdcb 100644
--- a/include/scsi/sas/sas_discover.h
+++ b/include/scsi/sas/sas_discover.h
@@ -171,7 +171,6 @@ static inline void sas_init_dev(struct d
 }
 
 void sas_init_disc(struct sas_discovery *disc, struct sas_port *port);
-void sas_kill_disc_thread(struct sas_port *port);
 int  sas_discover_event(struct sas_port *sas_port, enum discover_event ev);
 
 int  sas_discover_sata(struct domain_device *dev);



^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [SCSI] aic94xx: remove event thread
  2006-03-12 16:06 [SCSI] aic94xx: remove event thread James Bottomley
  2006-03-12 16:29 ` James Bottomley
@ 2006-03-14 18:00 ` Alexis Bruemmer
  1 sibling, 0 replies; 3+ messages in thread
From: Alexis Bruemmer @ 2006-03-14 18:00 UTC (permalink / raw)
  To: James Bottomley; +Cc: linux-scsi

On Sun, 2006-03-12 at 10:06 -0600, James Bottomley wrote:
> This patch moves the discovery and event processing entirely over to
> being workqueue based.  Additionally, it tries to ensure discovery gets
> time to proceed before finishing the module load.  There's still a
> non-determinism in there since it starts with a port interrupt for a
> connected phy after phys are enabled, so there's a ssleep(1) in there to
> capture this before the scsi_flush_work() waits for it to complete.

Just wanted to let you know that this patch has passed an overnight
reboot test on a x366.  The ssleep(1) seems to allow for enough time in
order to verify that sas_process_events has been called before waiting
on discovery.

> 
> James
> 

Regards,

Alexis

>  
> 
> 
> -
> To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2006-03-14 18:00 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-03-12 16:06 [SCSI] aic94xx: remove event thread James Bottomley
2006-03-12 16:29 ` James Bottomley
2006-03-14 18:00 ` Alexis Bruemmer

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox