blob: 8a2dd113f401098410d80a1bbb121e9ce5a73525 [file] [log] [blame]
Sreekanth Reddyf92363d2012-11-30 07:44:21 +05301/*
2 * This module provides common API to set Diagnostic trigger for MPT
3 * (Message Passing Technology) based controllers
4 *
5 * This code is based on drivers/scsi/mpt3sas/mpt3sas_trigger_diag.c
Sreekanth Reddya4ffce02014-09-12 15:35:29 +05306 * Copyright (C) 2012-2014 LSI Corporation
Sreekanth Reddyf92363d2012-11-30 07:44:21 +05307 * (mailto:DL-MPTFusionLinux@lsi.com)
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
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * NO WARRANTY
20 * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
21 * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
22 * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
23 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
24 * solely responsible for determining the appropriateness of using and
25 * distributing the Program and assumes all risks associated with its
26 * exercise of rights under this Agreement, including but not limited to
27 * the risks and costs of program errors, damage to or loss of data,
28 * programs or equipment, and unavailability or interruption of operations.
29
30 * DISCLAIMER OF LIABILITY
31 * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
32 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
34 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
35 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
36 * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
37 * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
38
39 * You should have received a copy of the GNU General Public License
40 * along with this program; if not, write to the Free Software
41 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
42 * USA.
43 */
44
Sreekanth Reddyf92363d2012-11-30 07:44:21 +053045#include <linux/kernel.h>
46#include <linux/module.h>
47#include <linux/errno.h>
48#include <linux/init.h>
49#include <linux/slab.h>
50#include <linux/types.h>
51#include <linux/pci.h>
52#include <linux/delay.h>
53#include <linux/compat.h>
54#include <linux/poll.h>
55
56#include <linux/io.h>
57#include <linux/uaccess.h>
58
59#include "mpt3sas_base.h"
60
61/**
62 * _mpt3sas_raise_sigio - notifiy app
63 * @ioc: per adapter object
64 * @event_data:
65 */
66static void
67_mpt3sas_raise_sigio(struct MPT3SAS_ADAPTER *ioc,
68 struct SL_WH_TRIGGERS_EVENT_DATA_T *event_data)
69{
70 Mpi2EventNotificationReply_t *mpi_reply;
71 u16 sz, event_data_sz;
72 unsigned long flags;
73
74 dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT "%s: enter\n",
75 ioc->name, __func__));
76
77 sz = offsetof(Mpi2EventNotificationReply_t, EventData) +
78 sizeof(struct SL_WH_TRIGGERS_EVENT_DATA_T) + 4;
79 mpi_reply = kzalloc(sz, GFP_KERNEL);
80 if (!mpi_reply)
81 goto out;
82 mpi_reply->Event = cpu_to_le16(MPI3_EVENT_DIAGNOSTIC_TRIGGER_FIRED);
83 event_data_sz = (sizeof(struct SL_WH_TRIGGERS_EVENT_DATA_T) + 4) / 4;
84 mpi_reply->EventDataLength = cpu_to_le16(event_data_sz);
85 memcpy(&mpi_reply->EventData, event_data,
86 sizeof(struct SL_WH_TRIGGERS_EVENT_DATA_T));
87 dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT
88 "%s: add to driver event log\n",
89 ioc->name, __func__));
90 mpt3sas_ctl_add_to_event_log(ioc, mpi_reply);
91 kfree(mpi_reply);
92 out:
93
94 /* clearing the diag_trigger_active flag */
95 spin_lock_irqsave(&ioc->diag_trigger_lock, flags);
96 dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT
97 "%s: clearing diag_trigger_active flag\n",
98 ioc->name, __func__));
99 ioc->diag_trigger_active = 0;
100 spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags);
101
102 dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT "%s: exit\n", ioc->name,
103 __func__));
104}
105
106/**
107 * mpt3sas_process_trigger_data - process the event data for the trigger
108 * @ioc: per adapter object
109 * @event_data:
110 */
111void
112mpt3sas_process_trigger_data(struct MPT3SAS_ADAPTER *ioc,
113 struct SL_WH_TRIGGERS_EVENT_DATA_T *event_data)
114{
115 u8 issue_reset = 0;
116
117 dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT "%s: enter\n",
118 ioc->name, __func__));
119
120 /* release the diag buffer trace */
121 if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
122 MPT3_DIAG_BUFFER_IS_RELEASED) == 0) {
123 dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT
124 "%s: release trace diag buffer\n", ioc->name, __func__));
125 mpt3sas_send_diag_release(ioc, MPI2_DIAG_BUF_TYPE_TRACE,
126 &issue_reset);
127 }
128
129 _mpt3sas_raise_sigio(ioc, event_data);
130
131 dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT "%s: exit\n", ioc->name,
132 __func__));
133}
134
135/**
136 * mpt3sas_trigger_master - Master trigger handler
137 * @ioc: per adapter object
138 * @trigger_bitmask:
139 *
140 */
141void
142mpt3sas_trigger_master(struct MPT3SAS_ADAPTER *ioc, u32 trigger_bitmask)
143{
144 struct SL_WH_TRIGGERS_EVENT_DATA_T event_data;
145 unsigned long flags;
146 u8 found_match = 0;
147
148 spin_lock_irqsave(&ioc->diag_trigger_lock, flags);
149
150 if (trigger_bitmask & MASTER_TRIGGER_FW_FAULT ||
151 trigger_bitmask & MASTER_TRIGGER_ADAPTER_RESET)
152 goto by_pass_checks;
153
154 /* check to see if trace buffers are currently registered */
155 if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
156 MPT3_DIAG_BUFFER_IS_REGISTERED) == 0) {
157 spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags);
158 return;
159 }
160
161 /* check to see if trace buffers are currently released */
162 if (ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
163 MPT3_DIAG_BUFFER_IS_RELEASED) {
164 spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags);
165 return;
166 }
167
168 by_pass_checks:
169
170 dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT
171 "%s: enter - trigger_bitmask = 0x%08x\n",
172 ioc->name, __func__, trigger_bitmask));
173
174 /* don't send trigger if an trigger is currently active */
175 if (ioc->diag_trigger_active) {
176 spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags);
177 goto out;
178 }
179
180 /* check for the trigger condition */
181 if (ioc->diag_trigger_master.MasterData & trigger_bitmask) {
182 found_match = 1;
183 ioc->diag_trigger_active = 1;
184 dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT
185 "%s: setting diag_trigger_active flag\n",
186 ioc->name, __func__));
187 }
188 spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags);
189
190 if (!found_match)
191 goto out;
192
193 memset(&event_data, 0, sizeof(struct SL_WH_TRIGGERS_EVENT_DATA_T));
194 event_data.trigger_type = MPT3SAS_TRIGGER_MASTER;
195 event_data.u.master.MasterData = trigger_bitmask;
196
197 if (trigger_bitmask & MASTER_TRIGGER_FW_FAULT ||
198 trigger_bitmask & MASTER_TRIGGER_ADAPTER_RESET)
199 _mpt3sas_raise_sigio(ioc, &event_data);
200 else
201 mpt3sas_send_trigger_data_event(ioc, &event_data);
202
203 out:
204 dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT "%s: exit\n", ioc->name,
205 __func__));
206}
207
208/**
209 * mpt3sas_trigger_event - Event trigger handler
210 * @ioc: per adapter object
211 * @event:
212 * @log_entry_qualifier:
213 *
214 */
215void
216mpt3sas_trigger_event(struct MPT3SAS_ADAPTER *ioc, u16 event,
217 u16 log_entry_qualifier)
218{
219 struct SL_WH_TRIGGERS_EVENT_DATA_T event_data;
220 struct SL_WH_EVENT_TRIGGER_T *event_trigger;
221 int i;
222 unsigned long flags;
223 u8 found_match;
224
225 spin_lock_irqsave(&ioc->diag_trigger_lock, flags);
226
227 /* check to see if trace buffers are currently registered */
228 if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
229 MPT3_DIAG_BUFFER_IS_REGISTERED) == 0) {
230 spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags);
231 return;
232 }
233
234 /* check to see if trace buffers are currently released */
235 if (ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
236 MPT3_DIAG_BUFFER_IS_RELEASED) {
237 spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags);
238 return;
239 }
240
241 dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT
242 "%s: enter - event = 0x%04x, log_entry_qualifier = 0x%04x\n",
243 ioc->name, __func__, event, log_entry_qualifier));
244
245 /* don't send trigger if an trigger is currently active */
246 if (ioc->diag_trigger_active) {
247 spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags);
248 goto out;
249 }
250
251 /* check for the trigger condition */
252 event_trigger = ioc->diag_trigger_event.EventTriggerEntry;
253 for (i = 0 , found_match = 0; i < ioc->diag_trigger_event.ValidEntries
254 && !found_match; i++, event_trigger++) {
255 if (event_trigger->EventValue != event)
256 continue;
257 if (event == MPI2_EVENT_LOG_ENTRY_ADDED) {
258 if (event_trigger->LogEntryQualifier ==
259 log_entry_qualifier)
260 found_match = 1;
261 continue;
262 }
263 found_match = 1;
264 ioc->diag_trigger_active = 1;
265 dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT
266 "%s: setting diag_trigger_active flag\n",
267 ioc->name, __func__));
268 }
269 spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags);
270
271 if (!found_match)
272 goto out;
273
274 dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT
275 "%s: setting diag_trigger_active flag\n",
276 ioc->name, __func__));
277 memset(&event_data, 0, sizeof(struct SL_WH_TRIGGERS_EVENT_DATA_T));
278 event_data.trigger_type = MPT3SAS_TRIGGER_EVENT;
279 event_data.u.event.EventValue = event;
280 event_data.u.event.LogEntryQualifier = log_entry_qualifier;
281 mpt3sas_send_trigger_data_event(ioc, &event_data);
282 out:
283 dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT "%s: exit\n", ioc->name,
284 __func__));
285}
286
287/**
288 * mpt3sas_trigger_scsi - SCSI trigger handler
289 * @ioc: per adapter object
290 * @sense_key:
291 * @asc:
292 * @ascq:
293 *
294 */
295void
296mpt3sas_trigger_scsi(struct MPT3SAS_ADAPTER *ioc, u8 sense_key, u8 asc,
297 u8 ascq)
298{
299 struct SL_WH_TRIGGERS_EVENT_DATA_T event_data;
300 struct SL_WH_SCSI_TRIGGER_T *scsi_trigger;
301 int i;
302 unsigned long flags;
303 u8 found_match;
304
305 spin_lock_irqsave(&ioc->diag_trigger_lock, flags);
306
307 /* check to see if trace buffers are currently registered */
308 if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
309 MPT3_DIAG_BUFFER_IS_REGISTERED) == 0) {
310 spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags);
311 return;
312 }
313
314 /* check to see if trace buffers are currently released */
315 if (ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
316 MPT3_DIAG_BUFFER_IS_RELEASED) {
317 spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags);
318 return;
319 }
320
321 dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT
322 "%s: enter - sense_key = 0x%02x, asc = 0x%02x, ascq = 0x%02x\n",
323 ioc->name, __func__, sense_key, asc, ascq));
324
325 /* don't send trigger if an trigger is currently active */
326 if (ioc->diag_trigger_active) {
327 spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags);
328 goto out;
329 }
330
331 /* check for the trigger condition */
332 scsi_trigger = ioc->diag_trigger_scsi.SCSITriggerEntry;
333 for (i = 0 , found_match = 0; i < ioc->diag_trigger_scsi.ValidEntries
334 && !found_match; i++, scsi_trigger++) {
335 if (scsi_trigger->SenseKey != sense_key)
336 continue;
337 if (!(scsi_trigger->ASC == 0xFF || scsi_trigger->ASC == asc))
338 continue;
339 if (!(scsi_trigger->ASCQ == 0xFF || scsi_trigger->ASCQ == ascq))
340 continue;
341 found_match = 1;
342 ioc->diag_trigger_active = 1;
343 }
344 spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags);
345
346 if (!found_match)
347 goto out;
348
349 dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT
350 "%s: setting diag_trigger_active flag\n",
351 ioc->name, __func__));
352 memset(&event_data, 0, sizeof(struct SL_WH_TRIGGERS_EVENT_DATA_T));
353 event_data.trigger_type = MPT3SAS_TRIGGER_SCSI;
354 event_data.u.scsi.SenseKey = sense_key;
355 event_data.u.scsi.ASC = asc;
356 event_data.u.scsi.ASCQ = ascq;
357 mpt3sas_send_trigger_data_event(ioc, &event_data);
358 out:
359 dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT "%s: exit\n", ioc->name,
360 __func__));
361}
362
363/**
364 * mpt3sas_trigger_mpi - MPI trigger handler
365 * @ioc: per adapter object
366 * @ioc_status:
367 * @loginfo:
368 *
369 */
370void
371mpt3sas_trigger_mpi(struct MPT3SAS_ADAPTER *ioc, u16 ioc_status, u32 loginfo)
372{
373 struct SL_WH_TRIGGERS_EVENT_DATA_T event_data;
374 struct SL_WH_MPI_TRIGGER_T *mpi_trigger;
375 int i;
376 unsigned long flags;
377 u8 found_match;
378
379 spin_lock_irqsave(&ioc->diag_trigger_lock, flags);
380
381 /* check to see if trace buffers are currently registered */
382 if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
383 MPT3_DIAG_BUFFER_IS_REGISTERED) == 0) {
384 spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags);
385 return;
386 }
387
388 /* check to see if trace buffers are currently released */
389 if (ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
390 MPT3_DIAG_BUFFER_IS_RELEASED) {
391 spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags);
392 return;
393 }
394
395 dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT
396 "%s: enter - ioc_status = 0x%04x, loginfo = 0x%08x\n",
397 ioc->name, __func__, ioc_status, loginfo));
398
399 /* don't send trigger if an trigger is currently active */
400 if (ioc->diag_trigger_active) {
401 spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags);
402 goto out;
403 }
404
405 /* check for the trigger condition */
406 mpi_trigger = ioc->diag_trigger_mpi.MPITriggerEntry;
407 for (i = 0 , found_match = 0; i < ioc->diag_trigger_mpi.ValidEntries
408 && !found_match; i++, mpi_trigger++) {
409 if (mpi_trigger->IOCStatus != ioc_status)
410 continue;
411 if (!(mpi_trigger->IocLogInfo == 0xFFFFFFFF ||
412 mpi_trigger->IocLogInfo == loginfo))
413 continue;
414 found_match = 1;
415 ioc->diag_trigger_active = 1;
416 }
417 spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags);
418
419 if (!found_match)
420 goto out;
421
422 dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT
423 "%s: setting diag_trigger_active flag\n",
424 ioc->name, __func__));
425 memset(&event_data, 0, sizeof(struct SL_WH_TRIGGERS_EVENT_DATA_T));
426 event_data.trigger_type = MPT3SAS_TRIGGER_MPI;
427 event_data.u.mpi.IOCStatus = ioc_status;
428 event_data.u.mpi.IocLogInfo = loginfo;
429 mpt3sas_send_trigger_data_event(ioc, &event_data);
430 out:
431 dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT "%s: exit\n", ioc->name,
432 __func__));
433}