xref: /OK3568_Linux_fs/kernel/drivers/scsi/libsas/sas_event.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Serial Attached SCSI (SAS) Event processing
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 2005 Adaptec, Inc.  All rights reserved.
6*4882a593Smuzhiyun  * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
7*4882a593Smuzhiyun  */
8*4882a593Smuzhiyun 
9*4882a593Smuzhiyun #include <linux/export.h>
10*4882a593Smuzhiyun #include <scsi/scsi_host.h>
11*4882a593Smuzhiyun #include "sas_internal.h"
12*4882a593Smuzhiyun 
sas_queue_work(struct sas_ha_struct * ha,struct sas_work * sw)13*4882a593Smuzhiyun int sas_queue_work(struct sas_ha_struct *ha, struct sas_work *sw)
14*4882a593Smuzhiyun {
15*4882a593Smuzhiyun 	/* it's added to the defer_q when draining so return succeed */
16*4882a593Smuzhiyun 	int rc = 1;
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun 	if (!test_bit(SAS_HA_REGISTERED, &ha->state))
19*4882a593Smuzhiyun 		return 0;
20*4882a593Smuzhiyun 
21*4882a593Smuzhiyun 	if (test_bit(SAS_HA_DRAINING, &ha->state)) {
22*4882a593Smuzhiyun 		/* add it to the defer list, if not already pending */
23*4882a593Smuzhiyun 		if (list_empty(&sw->drain_node))
24*4882a593Smuzhiyun 			list_add_tail(&sw->drain_node, &ha->defer_q);
25*4882a593Smuzhiyun 	} else
26*4882a593Smuzhiyun 		rc = queue_work(ha->event_q, &sw->work);
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun 	return rc;
29*4882a593Smuzhiyun }
30*4882a593Smuzhiyun 
sas_queue_event(int event,struct sas_work * work,struct sas_ha_struct * ha)31*4882a593Smuzhiyun static int sas_queue_event(int event, struct sas_work *work,
32*4882a593Smuzhiyun 			    struct sas_ha_struct *ha)
33*4882a593Smuzhiyun {
34*4882a593Smuzhiyun 	unsigned long flags;
35*4882a593Smuzhiyun 	int rc;
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun 	spin_lock_irqsave(&ha->lock, flags);
38*4882a593Smuzhiyun 	rc = sas_queue_work(ha, work);
39*4882a593Smuzhiyun 	spin_unlock_irqrestore(&ha->lock, flags);
40*4882a593Smuzhiyun 
41*4882a593Smuzhiyun 	return rc;
42*4882a593Smuzhiyun }
43*4882a593Smuzhiyun 
44*4882a593Smuzhiyun 
__sas_drain_work(struct sas_ha_struct * ha)45*4882a593Smuzhiyun void __sas_drain_work(struct sas_ha_struct *ha)
46*4882a593Smuzhiyun {
47*4882a593Smuzhiyun 	struct sas_work *sw, *_sw;
48*4882a593Smuzhiyun 	int ret;
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun 	set_bit(SAS_HA_DRAINING, &ha->state);
51*4882a593Smuzhiyun 	/* flush submitters */
52*4882a593Smuzhiyun 	spin_lock_irq(&ha->lock);
53*4882a593Smuzhiyun 	spin_unlock_irq(&ha->lock);
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun 	drain_workqueue(ha->event_q);
56*4882a593Smuzhiyun 	drain_workqueue(ha->disco_q);
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun 	spin_lock_irq(&ha->lock);
59*4882a593Smuzhiyun 	clear_bit(SAS_HA_DRAINING, &ha->state);
60*4882a593Smuzhiyun 	list_for_each_entry_safe(sw, _sw, &ha->defer_q, drain_node) {
61*4882a593Smuzhiyun 		list_del_init(&sw->drain_node);
62*4882a593Smuzhiyun 		ret = sas_queue_work(ha, sw);
63*4882a593Smuzhiyun 		if (ret != 1)
64*4882a593Smuzhiyun 			sas_free_event(to_asd_sas_event(&sw->work));
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun 	}
67*4882a593Smuzhiyun 	spin_unlock_irq(&ha->lock);
68*4882a593Smuzhiyun }
69*4882a593Smuzhiyun 
sas_drain_work(struct sas_ha_struct * ha)70*4882a593Smuzhiyun int sas_drain_work(struct sas_ha_struct *ha)
71*4882a593Smuzhiyun {
72*4882a593Smuzhiyun 	int err;
73*4882a593Smuzhiyun 
74*4882a593Smuzhiyun 	err = mutex_lock_interruptible(&ha->drain_mutex);
75*4882a593Smuzhiyun 	if (err)
76*4882a593Smuzhiyun 		return err;
77*4882a593Smuzhiyun 	if (test_bit(SAS_HA_REGISTERED, &ha->state))
78*4882a593Smuzhiyun 		__sas_drain_work(ha);
79*4882a593Smuzhiyun 	mutex_unlock(&ha->drain_mutex);
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun 	return 0;
82*4882a593Smuzhiyun }
83*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(sas_drain_work);
84*4882a593Smuzhiyun 
sas_disable_revalidation(struct sas_ha_struct * ha)85*4882a593Smuzhiyun void sas_disable_revalidation(struct sas_ha_struct *ha)
86*4882a593Smuzhiyun {
87*4882a593Smuzhiyun 	mutex_lock(&ha->disco_mutex);
88*4882a593Smuzhiyun 	set_bit(SAS_HA_ATA_EH_ACTIVE, &ha->state);
89*4882a593Smuzhiyun 	mutex_unlock(&ha->disco_mutex);
90*4882a593Smuzhiyun }
91*4882a593Smuzhiyun 
sas_enable_revalidation(struct sas_ha_struct * ha)92*4882a593Smuzhiyun void sas_enable_revalidation(struct sas_ha_struct *ha)
93*4882a593Smuzhiyun {
94*4882a593Smuzhiyun 	int i;
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun 	mutex_lock(&ha->disco_mutex);
97*4882a593Smuzhiyun 	clear_bit(SAS_HA_ATA_EH_ACTIVE, &ha->state);
98*4882a593Smuzhiyun 	for (i = 0; i < ha->num_phys; i++) {
99*4882a593Smuzhiyun 		struct asd_sas_port *port = ha->sas_port[i];
100*4882a593Smuzhiyun 		const int ev = DISCE_REVALIDATE_DOMAIN;
101*4882a593Smuzhiyun 		struct sas_discovery *d = &port->disc;
102*4882a593Smuzhiyun 		struct asd_sas_phy *sas_phy;
103*4882a593Smuzhiyun 
104*4882a593Smuzhiyun 		if (!test_and_clear_bit(ev, &d->pending))
105*4882a593Smuzhiyun 			continue;
106*4882a593Smuzhiyun 
107*4882a593Smuzhiyun 		if (list_empty(&port->phy_list))
108*4882a593Smuzhiyun 			continue;
109*4882a593Smuzhiyun 
110*4882a593Smuzhiyun 		sas_phy = container_of(port->phy_list.next, struct asd_sas_phy,
111*4882a593Smuzhiyun 				port_phy_el);
112*4882a593Smuzhiyun 		sas_notify_port_event(sas_phy, PORTE_BROADCAST_RCVD);
113*4882a593Smuzhiyun 	}
114*4882a593Smuzhiyun 	mutex_unlock(&ha->disco_mutex);
115*4882a593Smuzhiyun }
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun 
sas_port_event_worker(struct work_struct * work)118*4882a593Smuzhiyun static void sas_port_event_worker(struct work_struct *work)
119*4882a593Smuzhiyun {
120*4882a593Smuzhiyun 	struct asd_sas_event *ev = to_asd_sas_event(work);
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun 	sas_port_event_fns[ev->event](work);
123*4882a593Smuzhiyun 	sas_free_event(ev);
124*4882a593Smuzhiyun }
125*4882a593Smuzhiyun 
sas_phy_event_worker(struct work_struct * work)126*4882a593Smuzhiyun static void sas_phy_event_worker(struct work_struct *work)
127*4882a593Smuzhiyun {
128*4882a593Smuzhiyun 	struct asd_sas_event *ev = to_asd_sas_event(work);
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun 	sas_phy_event_fns[ev->event](work);
131*4882a593Smuzhiyun 	sas_free_event(ev);
132*4882a593Smuzhiyun }
133*4882a593Smuzhiyun 
__sas_notify_port_event(struct asd_sas_phy * phy,enum port_event event,struct asd_sas_event * ev)134*4882a593Smuzhiyun static int __sas_notify_port_event(struct asd_sas_phy *phy,
135*4882a593Smuzhiyun 				   enum port_event event,
136*4882a593Smuzhiyun 				   struct asd_sas_event *ev)
137*4882a593Smuzhiyun {
138*4882a593Smuzhiyun 	struct sas_ha_struct *ha = phy->ha;
139*4882a593Smuzhiyun 	int ret;
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun 	BUG_ON(event >= PORT_NUM_EVENTS);
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun 	INIT_SAS_EVENT(ev, sas_port_event_worker, phy, event);
144*4882a593Smuzhiyun 
145*4882a593Smuzhiyun 	ret = sas_queue_event(event, &ev->work, ha);
146*4882a593Smuzhiyun 	if (ret != 1)
147*4882a593Smuzhiyun 		sas_free_event(ev);
148*4882a593Smuzhiyun 
149*4882a593Smuzhiyun 	return ret;
150*4882a593Smuzhiyun }
151*4882a593Smuzhiyun 
sas_notify_port_event_gfp(struct asd_sas_phy * phy,enum port_event event,gfp_t gfp_flags)152*4882a593Smuzhiyun int sas_notify_port_event_gfp(struct asd_sas_phy *phy, enum port_event event,
153*4882a593Smuzhiyun 			      gfp_t gfp_flags)
154*4882a593Smuzhiyun {
155*4882a593Smuzhiyun 	struct asd_sas_event *ev;
156*4882a593Smuzhiyun 
157*4882a593Smuzhiyun 	ev = sas_alloc_event_gfp(phy, gfp_flags);
158*4882a593Smuzhiyun 	if (!ev)
159*4882a593Smuzhiyun 		return -ENOMEM;
160*4882a593Smuzhiyun 
161*4882a593Smuzhiyun 	return __sas_notify_port_event(phy, event, ev);
162*4882a593Smuzhiyun }
163*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(sas_notify_port_event_gfp);
164*4882a593Smuzhiyun 
sas_notify_port_event(struct asd_sas_phy * phy,enum port_event event)165*4882a593Smuzhiyun int sas_notify_port_event(struct asd_sas_phy *phy, enum port_event event)
166*4882a593Smuzhiyun {
167*4882a593Smuzhiyun 	struct asd_sas_event *ev;
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun 	ev = sas_alloc_event(phy);
170*4882a593Smuzhiyun 	if (!ev)
171*4882a593Smuzhiyun 		return -ENOMEM;
172*4882a593Smuzhiyun 
173*4882a593Smuzhiyun 	return __sas_notify_port_event(phy, event, ev);
174*4882a593Smuzhiyun }
175*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(sas_notify_port_event);
176*4882a593Smuzhiyun 
__sas_notify_phy_event(struct asd_sas_phy * phy,enum phy_event event,struct asd_sas_event * ev)177*4882a593Smuzhiyun static inline int __sas_notify_phy_event(struct asd_sas_phy *phy,
178*4882a593Smuzhiyun 					 enum phy_event event,
179*4882a593Smuzhiyun 					 struct asd_sas_event *ev)
180*4882a593Smuzhiyun {
181*4882a593Smuzhiyun 	struct sas_ha_struct *ha = phy->ha;
182*4882a593Smuzhiyun 	int ret;
183*4882a593Smuzhiyun 
184*4882a593Smuzhiyun 	BUG_ON(event >= PHY_NUM_EVENTS);
185*4882a593Smuzhiyun 
186*4882a593Smuzhiyun 	INIT_SAS_EVENT(ev, sas_phy_event_worker, phy, event);
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun 	ret = sas_queue_event(event, &ev->work, ha);
189*4882a593Smuzhiyun 	if (ret != 1)
190*4882a593Smuzhiyun 		sas_free_event(ev);
191*4882a593Smuzhiyun 
192*4882a593Smuzhiyun 	return ret;
193*4882a593Smuzhiyun }
194*4882a593Smuzhiyun 
sas_notify_phy_event_gfp(struct asd_sas_phy * phy,enum phy_event event,gfp_t gfp_flags)195*4882a593Smuzhiyun int sas_notify_phy_event_gfp(struct asd_sas_phy *phy, enum phy_event event,
196*4882a593Smuzhiyun 			     gfp_t gfp_flags)
197*4882a593Smuzhiyun {
198*4882a593Smuzhiyun 	struct asd_sas_event *ev;
199*4882a593Smuzhiyun 
200*4882a593Smuzhiyun 	ev = sas_alloc_event_gfp(phy, gfp_flags);
201*4882a593Smuzhiyun 	if (!ev)
202*4882a593Smuzhiyun 		return -ENOMEM;
203*4882a593Smuzhiyun 
204*4882a593Smuzhiyun 	return __sas_notify_phy_event(phy, event, ev);
205*4882a593Smuzhiyun }
206*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(sas_notify_phy_event_gfp);
207*4882a593Smuzhiyun 
sas_notify_phy_event(struct asd_sas_phy * phy,enum phy_event event)208*4882a593Smuzhiyun int sas_notify_phy_event(struct asd_sas_phy *phy, enum phy_event event)
209*4882a593Smuzhiyun {
210*4882a593Smuzhiyun 	struct asd_sas_event *ev;
211*4882a593Smuzhiyun 
212*4882a593Smuzhiyun 	ev = sas_alloc_event(phy);
213*4882a593Smuzhiyun 	if (!ev)
214*4882a593Smuzhiyun 		return -ENOMEM;
215*4882a593Smuzhiyun 
216*4882a593Smuzhiyun 	return __sas_notify_phy_event(phy, event, ev);
217*4882a593Smuzhiyun }
218*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(sas_notify_phy_event);
219