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.14.15
  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		sas_notify_port_event(sas_phy,
113				PORTE_BROADCAST_RCVD, GFP_KERNEL);
114	}
115	mutex_unlock(&ha->disco_mutex);
116}
117
118
119static void sas_port_event_worker(struct work_struct *work)
120{
121	struct asd_sas_event *ev = to_asd_sas_event(work);
122
123	sas_port_event_fns[ev->event](work);
124	sas_free_event(ev);
125}
126
127static void sas_phy_event_worker(struct work_struct *work)
128{
129	struct asd_sas_event *ev = to_asd_sas_event(work);
130
131	sas_phy_event_fns[ev->event](work);
132	sas_free_event(ev);
 
 
133}
134
135int sas_notify_port_event(struct asd_sas_phy *phy, enum port_event event,
136			  gfp_t gfp_flags)
137{
138	struct sas_ha_struct *ha = phy->ha;
139	struct asd_sas_event *ev;
140	int ret;
141
142	BUG_ON(event >= PORT_NUM_EVENTS);
143
144	ev = sas_alloc_event(phy, gfp_flags);
145	if (!ev)
146		return -ENOMEM;
147
148	INIT_SAS_EVENT(ev, sas_port_event_worker, phy, event);
149
150	ret = sas_queue_event(event, &ev->work, ha);
151	if (ret != 1)
152		sas_free_event(ev);
153
154	return ret;
 
155}
156EXPORT_SYMBOL_GPL(sas_notify_port_event);
157
158int sas_notify_phy_event(struct asd_sas_phy *phy, enum phy_event event,
159			 gfp_t gfp_flags)
160{
161	struct sas_ha_struct *ha = phy->ha;
162	struct asd_sas_event *ev;
163	int ret;
164
165	BUG_ON(event >= PHY_NUM_EVENTS);
166
167	ev = sas_alloc_event(phy, gfp_flags);
168	if (!ev)
169		return -ENOMEM;
 
170
171	INIT_SAS_EVENT(ev, sas_phy_event_worker, phy, event);
 
 
172
173	ret = sas_queue_event(event, &ev->work, ha);
174	if (ret != 1)
175		sas_free_event(ev);
176
177	return ret;
178}
179EXPORT_SYMBOL_GPL(sas_notify_phy_event);