Linux Audio

Check our new training course

Loading...
v4.10.11
 
  1/*
  2 * Serial Attached SCSI (SAS) Event processing
  3 *
  4 * Copyright (C) 2005 Adaptec, Inc.  All rights reserved.
  5 * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
  6 *
  7 * This file is licensed under GPLv2.
  8 *
  9 * This program is free software; you can redistribute it and/or
 10 * modify it under the terms of the GNU General Public License as
 11 * published by the Free Software Foundation; either version 2 of the
 12 * License, or (at your option) any later version.
 13 *
 14 * This program is distributed in the hope that it will be useful, but
 15 * WITHOUT ANY WARRANTY; without even the implied warranty of
 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 17 * General Public License for more details.
 18 *
 19 * You should have received a copy of the GNU General Public License
 20 * along with this program; if not, write to the Free Software
 21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 22 *
 23 */
 24
 25#include <linux/export.h>
 26#include <scsi/scsi_host.h>
 27#include "sas_internal.h"
 28#include "sas_dump.h"
 29
 30void sas_queue_work(struct sas_ha_struct *ha, struct sas_work *sw)
 31{
 
 
 
 32	if (!test_bit(SAS_HA_REGISTERED, &ha->state))
 33		return;
 34
 35	if (test_bit(SAS_HA_DRAINING, &ha->state)) {
 36		/* add it to the defer list, if not already pending */
 37		if (list_empty(&sw->drain_node))
 38			list_add(&sw->drain_node, &ha->defer_q);
 39	} else
 40		scsi_queue_work(ha->core.shost, &sw->work);
 
 
 41}
 42
 43static void sas_queue_event(int event, unsigned long *pending,
 44			    struct sas_work *work,
 45			    struct sas_ha_struct *ha)
 46{
 47	if (!test_and_set_bit(event, pending)) {
 48		unsigned long flags;
 49
 50		spin_lock_irqsave(&ha->lock, flags);
 51		sas_queue_work(ha, work);
 52		spin_unlock_irqrestore(&ha->lock, flags);
 53	}
 
 54}
 55
 56
 57void __sas_drain_work(struct sas_ha_struct *ha)
 58{
 59	struct workqueue_struct *wq = ha->core.shost->work_q;
 60	struct sas_work *sw, *_sw;
 
 61
 62	set_bit(SAS_HA_DRAINING, &ha->state);
 63	/* flush submitters */
 64	spin_lock_irq(&ha->lock);
 65	spin_unlock_irq(&ha->lock);
 66
 67	drain_workqueue(wq);
 
 68
 69	spin_lock_irq(&ha->lock);
 70	clear_bit(SAS_HA_DRAINING, &ha->state);
 71	list_for_each_entry_safe(sw, _sw, &ha->defer_q, drain_node) {
 72		list_del_init(&sw->drain_node);
 73		sas_queue_work(ha, sw);
 
 
 
 74	}
 75	spin_unlock_irq(&ha->lock);
 76}
 77
 78int sas_drain_work(struct sas_ha_struct *ha)
 79{
 80	int err;
 81
 82	err = mutex_lock_interruptible(&ha->drain_mutex);
 83	if (err)
 84		return err;
 85	if (test_bit(SAS_HA_REGISTERED, &ha->state))
 86		__sas_drain_work(ha);
 87	mutex_unlock(&ha->drain_mutex);
 88
 89	return 0;
 90}
 91EXPORT_SYMBOL_GPL(sas_drain_work);
 92
 93void sas_disable_revalidation(struct sas_ha_struct *ha)
 94{
 95	mutex_lock(&ha->disco_mutex);
 96	set_bit(SAS_HA_ATA_EH_ACTIVE, &ha->state);
 97	mutex_unlock(&ha->disco_mutex);
 98}
 99
100void sas_enable_revalidation(struct sas_ha_struct *ha)
101{
102	int i;
103
104	mutex_lock(&ha->disco_mutex);
105	clear_bit(SAS_HA_ATA_EH_ACTIVE, &ha->state);
106	for (i = 0; i < ha->num_phys; i++) {
107		struct asd_sas_port *port = ha->sas_port[i];
108		const int ev = DISCE_REVALIDATE_DOMAIN;
109		struct sas_discovery *d = &port->disc;
 
110
111		if (!test_and_clear_bit(ev, &d->pending))
112			continue;
113
114		sas_queue_event(ev, &d->pending, &d->disc_work[ev].work, ha);
 
 
 
 
 
115	}
116	mutex_unlock(&ha->disco_mutex);
117}
118
119static void notify_ha_event(struct sas_ha_struct *sas_ha, enum ha_event event)
 
 
 
 
 
 
 
 
 
120{
121	BUG_ON(event >= HA_NUM_EVENTS);
122
123	sas_queue_event(event, &sas_ha->pending,
124			&sas_ha->ha_events[event].work, sas_ha);
125}
126
127static void notify_port_event(struct asd_sas_phy *phy, enum port_event event)
128{
 
129	struct sas_ha_struct *ha = phy->ha;
 
130
131	BUG_ON(event >= PORT_NUM_EVENTS);
132
133	sas_queue_event(event, &phy->port_events_pending,
134			&phy->port_events[event].work, ha);
 
 
 
 
 
 
 
 
 
135}
136
137void sas_notify_phy_event(struct asd_sas_phy *phy, enum phy_event event)
138{
 
139	struct sas_ha_struct *ha = phy->ha;
 
140
141	BUG_ON(event >= PHY_NUM_EVENTS);
142
143	sas_queue_event(event, &phy->phy_events_pending,
144			&phy->phy_events[event].work, ha);
145}
146
147int sas_init_events(struct sas_ha_struct *sas_ha)
148{
149	static const work_func_t sas_ha_event_fns[HA_NUM_EVENTS] = {
150		[HAE_RESET] = sas_hae_reset,
151	};
152
153	int i;
 
 
154
155	for (i = 0; i < HA_NUM_EVENTS; i++) {
156		INIT_SAS_WORK(&sas_ha->ha_events[i].work, sas_ha_event_fns[i]);
157		sas_ha->ha_events[i].ha = sas_ha;
158	}
159
160	sas_ha->notify_ha_event = notify_ha_event;
161	sas_ha->notify_port_event = notify_port_event;
 
162	sas_ha->notify_phy_event = sas_notify_phy_event;
163
164	return 0;
165}
v5.4
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Serial Attached SCSI (SAS) Event processing
  4 *
  5 * Copyright (C) 2005 Adaptec, Inc.  All rights reserved.
  6 * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
  7 */
  8
  9#include <linux/export.h>
 10#include <scsi/scsi_host.h>
 11#include "sas_internal.h"
 
 12
 13int sas_queue_work(struct sas_ha_struct *ha, struct sas_work *sw)
 14{
 15	/* it's added to the defer_q when draining so return succeed */
 16	int rc = 1;
 17
 18	if (!test_bit(SAS_HA_REGISTERED, &ha->state))
 19		return 0;
 20
 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);
 25	} else
 26		rc = queue_work(ha->event_q, &sw->work);
 27
 28	return rc;
 29}
 30
 31static int sas_queue_event(int event, struct sas_work *work,
 
 32			    struct sas_ha_struct *ha)
 33{
 34	unsigned long flags;
 35	int rc;
 36
 37	spin_lock_irqsave(&ha->lock, flags);
 38	rc = sas_queue_work(ha, work);
 39	spin_unlock_irqrestore(&ha->lock, flags);
 40
 41	return rc;
 42}
 43
 44
 45void __sas_drain_work(struct sas_ha_struct *ha)
 46{
 
 47	struct sas_work *sw, *_sw;
 48	int ret;
 49
 50	set_bit(SAS_HA_DRAINING, &ha->state);
 51	/* flush submitters */
 52	spin_lock_irq(&ha->lock);
 53	spin_unlock_irq(&ha->lock);
 54
 55	drain_workqueue(ha->event_q);
 56	drain_workqueue(ha->disco_q);
 57
 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);
 63		if (ret != 1)
 64			sas_free_event(to_asd_sas_event(&sw->work));
 65
 66	}
 67	spin_unlock_irq(&ha->lock);
 68}
 69
 70int sas_drain_work(struct sas_ha_struct *ha)
 71{
 72	int err;
 73
 74	err = mutex_lock_interruptible(&ha->drain_mutex);
 75	if (err)
 76		return err;
 77	if (test_bit(SAS_HA_REGISTERED, &ha->state))
 78		__sas_drain_work(ha);
 79	mutex_unlock(&ha->drain_mutex);
 80
 81	return 0;
 82}
 83EXPORT_SYMBOL_GPL(sas_drain_work);
 84
 85void sas_disable_revalidation(struct sas_ha_struct *ha)
 86{
 87	mutex_lock(&ha->disco_mutex);
 88	set_bit(SAS_HA_ATA_EH_ACTIVE, &ha->state);
 89	mutex_unlock(&ha->disco_mutex);
 90}
 91
 92void sas_enable_revalidation(struct sas_ha_struct *ha)
 93{
 94	int i;
 95
 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;
103
104		if (!test_and_clear_bit(ev, &d->pending))
105			continue;
106
107		if (list_empty(&port->phy_list))
108			continue;
109
110		sas_phy = container_of(port->phy_list.next, struct asd_sas_phy,
111				port_phy_el);
112		ha->notify_port_event(sas_phy, PORTE_BROADCAST_RCVD);
113	}
114	mutex_unlock(&ha->disco_mutex);
115}
116
117
118static void sas_port_event_worker(struct work_struct *work)
119{
120	struct asd_sas_event *ev = to_asd_sas_event(work);
121
122	sas_port_event_fns[ev->event](work);
123	sas_free_event(ev);
124}
125
126static void sas_phy_event_worker(struct work_struct *work)
127{
128	struct asd_sas_event *ev = to_asd_sas_event(work);
129
130	sas_phy_event_fns[ev->event](work);
131	sas_free_event(ev);
132}
133
134static int sas_notify_port_event(struct asd_sas_phy *phy, enum port_event event)
135{
136	struct asd_sas_event *ev;
137	struct sas_ha_struct *ha = phy->ha;
138	int ret;
139
140	BUG_ON(event >= PORT_NUM_EVENTS);
141
142	ev = sas_alloc_event(phy);
143	if (!ev)
144		return -ENOMEM;
145
146	INIT_SAS_EVENT(ev, sas_port_event_worker, phy, event);
147
148	ret = sas_queue_event(event, &ev->work, ha);
149	if (ret != 1)
150		sas_free_event(ev);
151
152	return ret;
153}
154
155int sas_notify_phy_event(struct asd_sas_phy *phy, enum phy_event event)
156{
157	struct asd_sas_event *ev;
158	struct sas_ha_struct *ha = phy->ha;
159	int ret;
160
161	BUG_ON(event >= PHY_NUM_EVENTS);
162
163	ev = sas_alloc_event(phy);
164	if (!ev)
165		return -ENOMEM;
166
167	INIT_SAS_EVENT(ev, sas_phy_event_worker, phy, event);
 
 
 
 
168
169	ret = sas_queue_event(event, &ev->work, ha);
170	if (ret != 1)
171		sas_free_event(ev);
172
173	return ret;
174}
 
 
175
176int sas_init_events(struct sas_ha_struct *sas_ha)
177{
178	sas_ha->notify_port_event = sas_notify_port_event;
179	sas_ha->notify_phy_event = sas_notify_phy_event;
180
181	return 0;
182}