1 // SPDX-License-Identifier: GPL-2.0
3 * Serial Attached SCSI (SAS) Event processing
5 * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
6 * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
9 #include <linux/export.h>
10 #include <scsi/scsi_host.h>
11 #include "sas_internal.h"
13 int sas_queue_work(struct sas_ha_struct
*ha
, struct sas_work
*sw
)
15 /* it's added to the defer_q when draining so return succeed */
18 if (!test_bit(SAS_HA_REGISTERED
, &ha
->state
))
21 if (test_bit(SAS_HA_DRAINING
, &ha
->state
)) {
22 /* add it to the defer list, if not already pending */
23 if (list_empty(&sw
->drain_node
))
24 list_add_tail(&sw
->drain_node
, &ha
->defer_q
);
26 rc
= queue_work(ha
->event_q
, &sw
->work
);
31 static int sas_queue_event(int event
, struct sas_work
*work
,
32 struct sas_ha_struct
*ha
)
37 spin_lock_irqsave(&ha
->lock
, flags
);
38 rc
= sas_queue_work(ha
, work
);
39 spin_unlock_irqrestore(&ha
->lock
, flags
);
45 void __sas_drain_work(struct sas_ha_struct
*ha
)
47 struct sas_work
*sw
, *_sw
;
50 set_bit(SAS_HA_DRAINING
, &ha
->state
);
51 /* flush submitters */
52 spin_lock_irq(&ha
->lock
);
53 spin_unlock_irq(&ha
->lock
);
55 drain_workqueue(ha
->event_q
);
56 drain_workqueue(ha
->disco_q
);
58 spin_lock_irq(&ha
->lock
);
59 clear_bit(SAS_HA_DRAINING
, &ha
->state
);
60 list_for_each_entry_safe(sw
, _sw
, &ha
->defer_q
, drain_node
) {
61 list_del_init(&sw
->drain_node
);
62 ret
= sas_queue_work(ha
, sw
);
64 sas_free_event(to_asd_sas_event(&sw
->work
));
67 spin_unlock_irq(&ha
->lock
);
70 int sas_drain_work(struct sas_ha_struct
*ha
)
74 err
= mutex_lock_interruptible(&ha
->drain_mutex
);
77 if (test_bit(SAS_HA_REGISTERED
, &ha
->state
))
79 mutex_unlock(&ha
->drain_mutex
);
83 EXPORT_SYMBOL_GPL(sas_drain_work
);
85 void sas_disable_revalidation(struct sas_ha_struct
*ha
)
87 mutex_lock(&ha
->disco_mutex
);
88 set_bit(SAS_HA_ATA_EH_ACTIVE
, &ha
->state
);
89 mutex_unlock(&ha
->disco_mutex
);
92 void sas_enable_revalidation(struct sas_ha_struct
*ha
)
96 mutex_lock(&ha
->disco_mutex
);
97 clear_bit(SAS_HA_ATA_EH_ACTIVE
, &ha
->state
);
98 for (i
= 0; i
< ha
->num_phys
; i
++) {
99 struct asd_sas_port
*port
= ha
->sas_port
[i
];
100 const int ev
= DISCE_REVALIDATE_DOMAIN
;
101 struct sas_discovery
*d
= &port
->disc
;
102 struct asd_sas_phy
*sas_phy
;
104 if (!test_and_clear_bit(ev
, &d
->pending
))
107 if (list_empty(&port
->phy_list
))
110 sas_phy
= container_of(port
->phy_list
.next
, struct asd_sas_phy
,
112 ha
->notify_port_event(sas_phy
, PORTE_BROADCAST_RCVD
);
114 mutex_unlock(&ha
->disco_mutex
);
118 static void sas_port_event_worker(struct work_struct
*work
)
120 struct asd_sas_event
*ev
= to_asd_sas_event(work
);
122 sas_port_event_fns
[ev
->event
](work
);
126 static void sas_phy_event_worker(struct work_struct
*work
)
128 struct asd_sas_event
*ev
= to_asd_sas_event(work
);
130 sas_phy_event_fns
[ev
->event
](work
);
134 static int sas_notify_port_event(struct asd_sas_phy
*phy
, enum port_event event
)
136 struct asd_sas_event
*ev
;
137 struct sas_ha_struct
*ha
= phy
->ha
;
140 BUG_ON(event
>= PORT_NUM_EVENTS
);
142 ev
= sas_alloc_event(phy
);
146 INIT_SAS_EVENT(ev
, sas_port_event_worker
, phy
, event
);
148 ret
= sas_queue_event(event
, &ev
->work
, ha
);
155 int sas_notify_phy_event(struct asd_sas_phy
*phy
, enum phy_event event
)
157 struct asd_sas_event
*ev
;
158 struct sas_ha_struct
*ha
= phy
->ha
;
161 BUG_ON(event
>= PHY_NUM_EVENTS
);
163 ev
= sas_alloc_event(phy
);
167 INIT_SAS_EVENT(ev
, sas_phy_event_worker
, phy
, event
);
169 ret
= sas_queue_event(event
, &ev
->work
, ha
);
176 int sas_init_events(struct sas_ha_struct
*sas_ha
)
178 sas_ha
->notify_port_event
= sas_notify_port_event
;
179 sas_ha
->notify_phy_event
= sas_notify_phy_event
;