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