18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * This module provides common API to set Diagnostic trigger for MPT
38c2ecf20Sopenharmony_ci * (Message Passing Technology) based controllers
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * This code is based on drivers/scsi/mpt3sas/mpt3sas_trigger_diag.c
68c2ecf20Sopenharmony_ci * Copyright (C) 2012-2014  LSI Corporation
78c2ecf20Sopenharmony_ci * Copyright (C) 2013-2014 Avago Technologies
88c2ecf20Sopenharmony_ci *  (mailto: MPT-FusionLinux.pdl@avagotech.com)
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or
118c2ecf20Sopenharmony_ci * modify it under the terms of the GNU General Public License
128c2ecf20Sopenharmony_ci * as published by the Free Software Foundation; either version 2
138c2ecf20Sopenharmony_ci * of the License, or (at your option) any later version.
148c2ecf20Sopenharmony_ci *
158c2ecf20Sopenharmony_ci * This program is distributed in the hope that it will be useful,
168c2ecf20Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
178c2ecf20Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
188c2ecf20Sopenharmony_ci * GNU General Public License for more details.
198c2ecf20Sopenharmony_ci *
208c2ecf20Sopenharmony_ci * NO WARRANTY
218c2ecf20Sopenharmony_ci * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
228c2ecf20Sopenharmony_ci * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
238c2ecf20Sopenharmony_ci * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
248c2ecf20Sopenharmony_ci * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
258c2ecf20Sopenharmony_ci * solely responsible for determining the appropriateness of using and
268c2ecf20Sopenharmony_ci * distributing the Program and assumes all risks associated with its
278c2ecf20Sopenharmony_ci * exercise of rights under this Agreement, including but not limited to
288c2ecf20Sopenharmony_ci * the risks and costs of program errors, damage to or loss of data,
298c2ecf20Sopenharmony_ci * programs or equipment, and unavailability or interruption of operations.
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci * DISCLAIMER OF LIABILITY
328c2ecf20Sopenharmony_ci * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
338c2ecf20Sopenharmony_ci * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
348c2ecf20Sopenharmony_ci * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
358c2ecf20Sopenharmony_ci * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
368c2ecf20Sopenharmony_ci * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
378c2ecf20Sopenharmony_ci * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
388c2ecf20Sopenharmony_ci * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci * You should have received a copy of the GNU General Public License
418c2ecf20Sopenharmony_ci * along with this program; if not, write to the Free Software
428c2ecf20Sopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
438c2ecf20Sopenharmony_ci * USA.
448c2ecf20Sopenharmony_ci */
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci#include <linux/kernel.h>
478c2ecf20Sopenharmony_ci#include <linux/module.h>
488c2ecf20Sopenharmony_ci#include <linux/errno.h>
498c2ecf20Sopenharmony_ci#include <linux/init.h>
508c2ecf20Sopenharmony_ci#include <linux/slab.h>
518c2ecf20Sopenharmony_ci#include <linux/types.h>
528c2ecf20Sopenharmony_ci#include <linux/pci.h>
538c2ecf20Sopenharmony_ci#include <linux/delay.h>
548c2ecf20Sopenharmony_ci#include <linux/compat.h>
558c2ecf20Sopenharmony_ci#include <linux/poll.h>
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci#include <linux/io.h>
588c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci#include "mpt3sas_base.h"
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci/**
638c2ecf20Sopenharmony_ci * _mpt3sas_raise_sigio - notifiy app
648c2ecf20Sopenharmony_ci * @ioc: per adapter object
658c2ecf20Sopenharmony_ci * @event_data: ?
668c2ecf20Sopenharmony_ci */
678c2ecf20Sopenharmony_cistatic void
688c2ecf20Sopenharmony_ci_mpt3sas_raise_sigio(struct MPT3SAS_ADAPTER *ioc,
698c2ecf20Sopenharmony_ci	struct SL_WH_TRIGGERS_EVENT_DATA_T *event_data)
708c2ecf20Sopenharmony_ci{
718c2ecf20Sopenharmony_ci	Mpi2EventNotificationReply_t *mpi_reply;
728c2ecf20Sopenharmony_ci	u16 sz, event_data_sz;
738c2ecf20Sopenharmony_ci	unsigned long flags;
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	dTriggerDiagPrintk(ioc, ioc_info(ioc, "%s: enter\n", __func__));
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	sz = offsetof(Mpi2EventNotificationReply_t, EventData) +
788c2ecf20Sopenharmony_ci	    sizeof(struct SL_WH_TRIGGERS_EVENT_DATA_T) + 4;
798c2ecf20Sopenharmony_ci	mpi_reply = kzalloc(sz, GFP_KERNEL);
808c2ecf20Sopenharmony_ci	if (!mpi_reply)
818c2ecf20Sopenharmony_ci		goto out;
828c2ecf20Sopenharmony_ci	mpi_reply->Event = cpu_to_le16(MPI3_EVENT_DIAGNOSTIC_TRIGGER_FIRED);
838c2ecf20Sopenharmony_ci	event_data_sz = (sizeof(struct SL_WH_TRIGGERS_EVENT_DATA_T) + 4) / 4;
848c2ecf20Sopenharmony_ci	mpi_reply->EventDataLength = cpu_to_le16(event_data_sz);
858c2ecf20Sopenharmony_ci	memcpy(&mpi_reply->EventData, event_data,
868c2ecf20Sopenharmony_ci	    sizeof(struct SL_WH_TRIGGERS_EVENT_DATA_T));
878c2ecf20Sopenharmony_ci	dTriggerDiagPrintk(ioc,
888c2ecf20Sopenharmony_ci			   ioc_info(ioc, "%s: add to driver event log\n",
898c2ecf20Sopenharmony_ci				    __func__));
908c2ecf20Sopenharmony_ci	mpt3sas_ctl_add_to_event_log(ioc, mpi_reply);
918c2ecf20Sopenharmony_ci	kfree(mpi_reply);
928c2ecf20Sopenharmony_ci out:
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	/* clearing the diag_trigger_active flag */
958c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ioc->diag_trigger_lock, flags);
968c2ecf20Sopenharmony_ci	dTriggerDiagPrintk(ioc,
978c2ecf20Sopenharmony_ci			   ioc_info(ioc, "%s: clearing diag_trigger_active flag\n",
988c2ecf20Sopenharmony_ci				    __func__));
998c2ecf20Sopenharmony_ci	ioc->diag_trigger_active = 0;
1008c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags);
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci	dTriggerDiagPrintk(ioc, ioc_info(ioc, "%s: exit\n",
1038c2ecf20Sopenharmony_ci					 __func__));
1048c2ecf20Sopenharmony_ci}
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci/**
1078c2ecf20Sopenharmony_ci * mpt3sas_process_trigger_data - process the event data for the trigger
1088c2ecf20Sopenharmony_ci * @ioc: per adapter object
1098c2ecf20Sopenharmony_ci * @event_data: ?
1108c2ecf20Sopenharmony_ci */
1118c2ecf20Sopenharmony_civoid
1128c2ecf20Sopenharmony_cimpt3sas_process_trigger_data(struct MPT3SAS_ADAPTER *ioc,
1138c2ecf20Sopenharmony_ci	struct SL_WH_TRIGGERS_EVENT_DATA_T *event_data)
1148c2ecf20Sopenharmony_ci{
1158c2ecf20Sopenharmony_ci	u8 issue_reset = 0;
1168c2ecf20Sopenharmony_ci	u32 *trig_data = (u32 *)&event_data->u.master;
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	dTriggerDiagPrintk(ioc, ioc_info(ioc, "%s: enter\n", __func__));
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	/* release the diag buffer trace */
1218c2ecf20Sopenharmony_ci	if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
1228c2ecf20Sopenharmony_ci	    MPT3_DIAG_BUFFER_IS_RELEASED) == 0) {
1238c2ecf20Sopenharmony_ci		/*
1248c2ecf20Sopenharmony_ci		 * add a log message so that user knows which event caused
1258c2ecf20Sopenharmony_ci		 * the release
1268c2ecf20Sopenharmony_ci		 */
1278c2ecf20Sopenharmony_ci		ioc_info(ioc,
1288c2ecf20Sopenharmony_ci		    "%s: Releasing the trace buffer. Trigger_Type 0x%08x, Data[0] 0x%08x, Data[1] 0x%08x\n",
1298c2ecf20Sopenharmony_ci		    __func__, event_data->trigger_type,
1308c2ecf20Sopenharmony_ci		    trig_data[0], trig_data[1]);
1318c2ecf20Sopenharmony_ci		mpt3sas_send_diag_release(ioc, MPI2_DIAG_BUF_TYPE_TRACE,
1328c2ecf20Sopenharmony_ci		    &issue_reset);
1338c2ecf20Sopenharmony_ci	}
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	_mpt3sas_raise_sigio(ioc, event_data);
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	dTriggerDiagPrintk(ioc, ioc_info(ioc, "%s: exit\n",
1388c2ecf20Sopenharmony_ci					 __func__));
1398c2ecf20Sopenharmony_ci}
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci/**
1428c2ecf20Sopenharmony_ci * mpt3sas_trigger_master - Master trigger handler
1438c2ecf20Sopenharmony_ci * @ioc: per adapter object
1448c2ecf20Sopenharmony_ci * @trigger_bitmask:
1458c2ecf20Sopenharmony_ci *
1468c2ecf20Sopenharmony_ci */
1478c2ecf20Sopenharmony_civoid
1488c2ecf20Sopenharmony_cimpt3sas_trigger_master(struct MPT3SAS_ADAPTER *ioc, u32 trigger_bitmask)
1498c2ecf20Sopenharmony_ci{
1508c2ecf20Sopenharmony_ci	struct SL_WH_TRIGGERS_EVENT_DATA_T event_data;
1518c2ecf20Sopenharmony_ci	unsigned long flags;
1528c2ecf20Sopenharmony_ci	u8 found_match = 0;
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ioc->diag_trigger_lock, flags);
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci	if (trigger_bitmask & MASTER_TRIGGER_FW_FAULT ||
1578c2ecf20Sopenharmony_ci	    trigger_bitmask & MASTER_TRIGGER_ADAPTER_RESET)
1588c2ecf20Sopenharmony_ci		goto by_pass_checks;
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	/* check to see if trace buffers are currently registered */
1618c2ecf20Sopenharmony_ci	if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
1628c2ecf20Sopenharmony_ci	    MPT3_DIAG_BUFFER_IS_REGISTERED) == 0) {
1638c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags);
1648c2ecf20Sopenharmony_ci		return;
1658c2ecf20Sopenharmony_ci	}
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci	/* check to see if trace buffers are currently released */
1688c2ecf20Sopenharmony_ci	if (ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
1698c2ecf20Sopenharmony_ci	    MPT3_DIAG_BUFFER_IS_RELEASED) {
1708c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags);
1718c2ecf20Sopenharmony_ci		return;
1728c2ecf20Sopenharmony_ci	}
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci by_pass_checks:
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci	dTriggerDiagPrintk(ioc,
1778c2ecf20Sopenharmony_ci			   ioc_info(ioc, "%s: enter - trigger_bitmask = 0x%08x\n",
1788c2ecf20Sopenharmony_ci				    __func__, trigger_bitmask));
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci	/* don't send trigger if an trigger is currently active */
1818c2ecf20Sopenharmony_ci	if (ioc->diag_trigger_active) {
1828c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags);
1838c2ecf20Sopenharmony_ci		goto out;
1848c2ecf20Sopenharmony_ci	}
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	/* check for the trigger condition */
1878c2ecf20Sopenharmony_ci	if (ioc->diag_trigger_master.MasterData & trigger_bitmask) {
1888c2ecf20Sopenharmony_ci		found_match = 1;
1898c2ecf20Sopenharmony_ci		ioc->diag_trigger_active = 1;
1908c2ecf20Sopenharmony_ci		dTriggerDiagPrintk(ioc,
1918c2ecf20Sopenharmony_ci				   ioc_info(ioc, "%s: setting diag_trigger_active flag\n",
1928c2ecf20Sopenharmony_ci					    __func__));
1938c2ecf20Sopenharmony_ci	}
1948c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags);
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	if (!found_match)
1978c2ecf20Sopenharmony_ci		goto out;
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	memset(&event_data, 0, sizeof(struct SL_WH_TRIGGERS_EVENT_DATA_T));
2008c2ecf20Sopenharmony_ci	event_data.trigger_type = MPT3SAS_TRIGGER_MASTER;
2018c2ecf20Sopenharmony_ci	event_data.u.master.MasterData = trigger_bitmask;
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	if (trigger_bitmask & MASTER_TRIGGER_FW_FAULT ||
2048c2ecf20Sopenharmony_ci	    trigger_bitmask & MASTER_TRIGGER_ADAPTER_RESET)
2058c2ecf20Sopenharmony_ci		_mpt3sas_raise_sigio(ioc, &event_data);
2068c2ecf20Sopenharmony_ci	else
2078c2ecf20Sopenharmony_ci		mpt3sas_send_trigger_data_event(ioc, &event_data);
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci out:
2108c2ecf20Sopenharmony_ci	dTriggerDiagPrintk(ioc, ioc_info(ioc, "%s: exit\n",
2118c2ecf20Sopenharmony_ci					 __func__));
2128c2ecf20Sopenharmony_ci}
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci/**
2158c2ecf20Sopenharmony_ci * mpt3sas_trigger_event - Event trigger handler
2168c2ecf20Sopenharmony_ci * @ioc: per adapter object
2178c2ecf20Sopenharmony_ci * @event: ?
2188c2ecf20Sopenharmony_ci * @log_entry_qualifier: ?
2198c2ecf20Sopenharmony_ci *
2208c2ecf20Sopenharmony_ci */
2218c2ecf20Sopenharmony_civoid
2228c2ecf20Sopenharmony_cimpt3sas_trigger_event(struct MPT3SAS_ADAPTER *ioc, u16 event,
2238c2ecf20Sopenharmony_ci	u16 log_entry_qualifier)
2248c2ecf20Sopenharmony_ci{
2258c2ecf20Sopenharmony_ci	struct SL_WH_TRIGGERS_EVENT_DATA_T event_data;
2268c2ecf20Sopenharmony_ci	struct SL_WH_EVENT_TRIGGER_T *event_trigger;
2278c2ecf20Sopenharmony_ci	int i;
2288c2ecf20Sopenharmony_ci	unsigned long flags;
2298c2ecf20Sopenharmony_ci	u8 found_match;
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ioc->diag_trigger_lock, flags);
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	/* check to see if trace buffers are currently registered */
2348c2ecf20Sopenharmony_ci	if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
2358c2ecf20Sopenharmony_ci	    MPT3_DIAG_BUFFER_IS_REGISTERED) == 0) {
2368c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags);
2378c2ecf20Sopenharmony_ci		return;
2388c2ecf20Sopenharmony_ci	}
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	/* check to see if trace buffers are currently released */
2418c2ecf20Sopenharmony_ci	if (ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
2428c2ecf20Sopenharmony_ci	    MPT3_DIAG_BUFFER_IS_RELEASED) {
2438c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags);
2448c2ecf20Sopenharmony_ci		return;
2458c2ecf20Sopenharmony_ci	}
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	dTriggerDiagPrintk(ioc,
2488c2ecf20Sopenharmony_ci			   ioc_info(ioc, "%s: enter - event = 0x%04x, log_entry_qualifier = 0x%04x\n",
2498c2ecf20Sopenharmony_ci				    __func__, event, log_entry_qualifier));
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	/* don't send trigger if an trigger is currently active */
2528c2ecf20Sopenharmony_ci	if (ioc->diag_trigger_active) {
2538c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags);
2548c2ecf20Sopenharmony_ci		goto out;
2558c2ecf20Sopenharmony_ci	}
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	/* check for the trigger condition */
2588c2ecf20Sopenharmony_ci	event_trigger = ioc->diag_trigger_event.EventTriggerEntry;
2598c2ecf20Sopenharmony_ci	for (i = 0 , found_match = 0; i < ioc->diag_trigger_event.ValidEntries
2608c2ecf20Sopenharmony_ci	    && !found_match; i++, event_trigger++) {
2618c2ecf20Sopenharmony_ci		if (event_trigger->EventValue != event)
2628c2ecf20Sopenharmony_ci			continue;
2638c2ecf20Sopenharmony_ci		if (event == MPI2_EVENT_LOG_ENTRY_ADDED) {
2648c2ecf20Sopenharmony_ci			if (event_trigger->LogEntryQualifier ==
2658c2ecf20Sopenharmony_ci			    log_entry_qualifier)
2668c2ecf20Sopenharmony_ci				found_match = 1;
2678c2ecf20Sopenharmony_ci			continue;
2688c2ecf20Sopenharmony_ci		}
2698c2ecf20Sopenharmony_ci		found_match = 1;
2708c2ecf20Sopenharmony_ci		ioc->diag_trigger_active = 1;
2718c2ecf20Sopenharmony_ci		dTriggerDiagPrintk(ioc,
2728c2ecf20Sopenharmony_ci				   ioc_info(ioc, "%s: setting diag_trigger_active flag\n",
2738c2ecf20Sopenharmony_ci					    __func__));
2748c2ecf20Sopenharmony_ci	}
2758c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags);
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	if (!found_match)
2788c2ecf20Sopenharmony_ci		goto out;
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	dTriggerDiagPrintk(ioc,
2818c2ecf20Sopenharmony_ci			   ioc_info(ioc, "%s: setting diag_trigger_active flag\n",
2828c2ecf20Sopenharmony_ci				    __func__));
2838c2ecf20Sopenharmony_ci	memset(&event_data, 0, sizeof(struct SL_WH_TRIGGERS_EVENT_DATA_T));
2848c2ecf20Sopenharmony_ci	event_data.trigger_type = MPT3SAS_TRIGGER_EVENT;
2858c2ecf20Sopenharmony_ci	event_data.u.event.EventValue = event;
2868c2ecf20Sopenharmony_ci	event_data.u.event.LogEntryQualifier = log_entry_qualifier;
2878c2ecf20Sopenharmony_ci	mpt3sas_send_trigger_data_event(ioc, &event_data);
2888c2ecf20Sopenharmony_ci out:
2898c2ecf20Sopenharmony_ci	dTriggerDiagPrintk(ioc, ioc_info(ioc, "%s: exit\n",
2908c2ecf20Sopenharmony_ci					 __func__));
2918c2ecf20Sopenharmony_ci}
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci/**
2948c2ecf20Sopenharmony_ci * mpt3sas_trigger_scsi - SCSI trigger handler
2958c2ecf20Sopenharmony_ci * @ioc: per adapter object
2968c2ecf20Sopenharmony_ci * @sense_key: ?
2978c2ecf20Sopenharmony_ci * @asc: ?
2988c2ecf20Sopenharmony_ci * @ascq: ?
2998c2ecf20Sopenharmony_ci *
3008c2ecf20Sopenharmony_ci */
3018c2ecf20Sopenharmony_civoid
3028c2ecf20Sopenharmony_cimpt3sas_trigger_scsi(struct MPT3SAS_ADAPTER *ioc, u8 sense_key, u8 asc,
3038c2ecf20Sopenharmony_ci	u8 ascq)
3048c2ecf20Sopenharmony_ci{
3058c2ecf20Sopenharmony_ci	struct SL_WH_TRIGGERS_EVENT_DATA_T event_data;
3068c2ecf20Sopenharmony_ci	struct SL_WH_SCSI_TRIGGER_T *scsi_trigger;
3078c2ecf20Sopenharmony_ci	int i;
3088c2ecf20Sopenharmony_ci	unsigned long flags;
3098c2ecf20Sopenharmony_ci	u8 found_match;
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ioc->diag_trigger_lock, flags);
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	/* check to see if trace buffers are currently registered */
3148c2ecf20Sopenharmony_ci	if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
3158c2ecf20Sopenharmony_ci	    MPT3_DIAG_BUFFER_IS_REGISTERED) == 0) {
3168c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags);
3178c2ecf20Sopenharmony_ci		return;
3188c2ecf20Sopenharmony_ci	}
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci	/* check to see if trace buffers are currently released */
3218c2ecf20Sopenharmony_ci	if (ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
3228c2ecf20Sopenharmony_ci	    MPT3_DIAG_BUFFER_IS_RELEASED) {
3238c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags);
3248c2ecf20Sopenharmony_ci		return;
3258c2ecf20Sopenharmony_ci	}
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	dTriggerDiagPrintk(ioc,
3288c2ecf20Sopenharmony_ci			   ioc_info(ioc, "%s: enter - sense_key = 0x%02x, asc = 0x%02x, ascq = 0x%02x\n",
3298c2ecf20Sopenharmony_ci				    __func__, sense_key, asc, ascq));
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	/* don't send trigger if an trigger is currently active */
3328c2ecf20Sopenharmony_ci	if (ioc->diag_trigger_active) {
3338c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags);
3348c2ecf20Sopenharmony_ci		goto out;
3358c2ecf20Sopenharmony_ci	}
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	/* check for the trigger condition */
3388c2ecf20Sopenharmony_ci	scsi_trigger = ioc->diag_trigger_scsi.SCSITriggerEntry;
3398c2ecf20Sopenharmony_ci	for (i = 0 , found_match = 0; i < ioc->diag_trigger_scsi.ValidEntries
3408c2ecf20Sopenharmony_ci	    && !found_match; i++, scsi_trigger++) {
3418c2ecf20Sopenharmony_ci		if (scsi_trigger->SenseKey != sense_key)
3428c2ecf20Sopenharmony_ci			continue;
3438c2ecf20Sopenharmony_ci		if (!(scsi_trigger->ASC == 0xFF || scsi_trigger->ASC == asc))
3448c2ecf20Sopenharmony_ci			continue;
3458c2ecf20Sopenharmony_ci		if (!(scsi_trigger->ASCQ == 0xFF || scsi_trigger->ASCQ == ascq))
3468c2ecf20Sopenharmony_ci			continue;
3478c2ecf20Sopenharmony_ci		found_match = 1;
3488c2ecf20Sopenharmony_ci		ioc->diag_trigger_active = 1;
3498c2ecf20Sopenharmony_ci	}
3508c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags);
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	if (!found_match)
3538c2ecf20Sopenharmony_ci		goto out;
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci	dTriggerDiagPrintk(ioc,
3568c2ecf20Sopenharmony_ci			   ioc_info(ioc, "%s: setting diag_trigger_active flag\n",
3578c2ecf20Sopenharmony_ci				    __func__));
3588c2ecf20Sopenharmony_ci	memset(&event_data, 0, sizeof(struct SL_WH_TRIGGERS_EVENT_DATA_T));
3598c2ecf20Sopenharmony_ci	event_data.trigger_type = MPT3SAS_TRIGGER_SCSI;
3608c2ecf20Sopenharmony_ci	event_data.u.scsi.SenseKey = sense_key;
3618c2ecf20Sopenharmony_ci	event_data.u.scsi.ASC = asc;
3628c2ecf20Sopenharmony_ci	event_data.u.scsi.ASCQ = ascq;
3638c2ecf20Sopenharmony_ci	mpt3sas_send_trigger_data_event(ioc, &event_data);
3648c2ecf20Sopenharmony_ci out:
3658c2ecf20Sopenharmony_ci	dTriggerDiagPrintk(ioc, ioc_info(ioc, "%s: exit\n",
3668c2ecf20Sopenharmony_ci					 __func__));
3678c2ecf20Sopenharmony_ci}
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci/**
3708c2ecf20Sopenharmony_ci * mpt3sas_trigger_mpi - MPI trigger handler
3718c2ecf20Sopenharmony_ci * @ioc: per adapter object
3728c2ecf20Sopenharmony_ci * @ioc_status: ?
3738c2ecf20Sopenharmony_ci * @loginfo: ?
3748c2ecf20Sopenharmony_ci *
3758c2ecf20Sopenharmony_ci */
3768c2ecf20Sopenharmony_civoid
3778c2ecf20Sopenharmony_cimpt3sas_trigger_mpi(struct MPT3SAS_ADAPTER *ioc, u16 ioc_status, u32 loginfo)
3788c2ecf20Sopenharmony_ci{
3798c2ecf20Sopenharmony_ci	struct SL_WH_TRIGGERS_EVENT_DATA_T event_data;
3808c2ecf20Sopenharmony_ci	struct SL_WH_MPI_TRIGGER_T *mpi_trigger;
3818c2ecf20Sopenharmony_ci	int i;
3828c2ecf20Sopenharmony_ci	unsigned long flags;
3838c2ecf20Sopenharmony_ci	u8 found_match;
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ioc->diag_trigger_lock, flags);
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci	/* check to see if trace buffers are currently registered */
3888c2ecf20Sopenharmony_ci	if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
3898c2ecf20Sopenharmony_ci	    MPT3_DIAG_BUFFER_IS_REGISTERED) == 0) {
3908c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags);
3918c2ecf20Sopenharmony_ci		return;
3928c2ecf20Sopenharmony_ci	}
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci	/* check to see if trace buffers are currently released */
3958c2ecf20Sopenharmony_ci	if (ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
3968c2ecf20Sopenharmony_ci	    MPT3_DIAG_BUFFER_IS_RELEASED) {
3978c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags);
3988c2ecf20Sopenharmony_ci		return;
3998c2ecf20Sopenharmony_ci	}
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci	dTriggerDiagPrintk(ioc,
4028c2ecf20Sopenharmony_ci			   ioc_info(ioc, "%s: enter - ioc_status = 0x%04x, loginfo = 0x%08x\n",
4038c2ecf20Sopenharmony_ci				    __func__, ioc_status, loginfo));
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci	/* don't send trigger if an trigger is currently active */
4068c2ecf20Sopenharmony_ci	if (ioc->diag_trigger_active) {
4078c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags);
4088c2ecf20Sopenharmony_ci		goto out;
4098c2ecf20Sopenharmony_ci	}
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ci	/* check for the trigger condition */
4128c2ecf20Sopenharmony_ci	mpi_trigger = ioc->diag_trigger_mpi.MPITriggerEntry;
4138c2ecf20Sopenharmony_ci	for (i = 0 , found_match = 0; i < ioc->diag_trigger_mpi.ValidEntries
4148c2ecf20Sopenharmony_ci	    && !found_match; i++, mpi_trigger++) {
4158c2ecf20Sopenharmony_ci		if (mpi_trigger->IOCStatus != ioc_status)
4168c2ecf20Sopenharmony_ci			continue;
4178c2ecf20Sopenharmony_ci		if (!(mpi_trigger->IocLogInfo == 0xFFFFFFFF ||
4188c2ecf20Sopenharmony_ci		    mpi_trigger->IocLogInfo == loginfo))
4198c2ecf20Sopenharmony_ci			continue;
4208c2ecf20Sopenharmony_ci		found_match = 1;
4218c2ecf20Sopenharmony_ci		ioc->diag_trigger_active = 1;
4228c2ecf20Sopenharmony_ci	}
4238c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags);
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_ci	if (!found_match)
4268c2ecf20Sopenharmony_ci		goto out;
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci	dTriggerDiagPrintk(ioc,
4298c2ecf20Sopenharmony_ci			   ioc_info(ioc, "%s: setting diag_trigger_active flag\n",
4308c2ecf20Sopenharmony_ci				    __func__));
4318c2ecf20Sopenharmony_ci	memset(&event_data, 0, sizeof(struct SL_WH_TRIGGERS_EVENT_DATA_T));
4328c2ecf20Sopenharmony_ci	event_data.trigger_type = MPT3SAS_TRIGGER_MPI;
4338c2ecf20Sopenharmony_ci	event_data.u.mpi.IOCStatus = ioc_status;
4348c2ecf20Sopenharmony_ci	event_data.u.mpi.IocLogInfo = loginfo;
4358c2ecf20Sopenharmony_ci	mpt3sas_send_trigger_data_event(ioc, &event_data);
4368c2ecf20Sopenharmony_ci out:
4378c2ecf20Sopenharmony_ci	dTriggerDiagPrintk(ioc, ioc_info(ioc, "%s: exit\n",
4388c2ecf20Sopenharmony_ci					 __func__));
4398c2ecf20Sopenharmony_ci}
440