Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * This module provides common API to set Diagnostic trigger for MPT
0003  * (Message Passing Technology) based controllers
0004  *
0005  * This code is based on drivers/scsi/mpt3sas/mpt3sas_trigger_diag.c
0006  * Copyright (C) 2012-2014  LSI Corporation
0007  * Copyright (C) 2013-2014 Avago Technologies
0008  *  (mailto: MPT-FusionLinux.pdl@avagotech.com)
0009  *
0010  * This program is free software; you can redistribute it and/or
0011  * modify it under the terms of the GNU General Public License
0012  * as published by the Free Software Foundation; either version 2
0013  * of the License, or (at your option) any later version.
0014  *
0015  * This program is distributed in the hope that it will be useful,
0016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0018  * GNU General Public License for more details.
0019  *
0020  * NO WARRANTY
0021  * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
0022  * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
0023  * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
0024  * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
0025  * solely responsible for determining the appropriateness of using and
0026  * distributing the Program and assumes all risks associated with its
0027  * exercise of rights under this Agreement, including but not limited to
0028  * the risks and costs of program errors, damage to or loss of data,
0029  * programs or equipment, and unavailability or interruption of operations.
0030 
0031  * DISCLAIMER OF LIABILITY
0032  * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
0033  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
0034  * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
0035  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
0036  * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
0037  * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
0038  * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
0039 
0040  * You should have received a copy of the GNU General Public License
0041  * along with this program; if not, write to the Free Software
0042  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
0043  * USA.
0044  */
0045 
0046 #include <linux/kernel.h>
0047 #include <linux/module.h>
0048 #include <linux/errno.h>
0049 #include <linux/init.h>
0050 #include <linux/slab.h>
0051 #include <linux/types.h>
0052 #include <linux/pci.h>
0053 #include <linux/delay.h>
0054 #include <linux/compat.h>
0055 #include <linux/poll.h>
0056 
0057 #include <linux/io.h>
0058 #include <linux/uaccess.h>
0059 
0060 #include "mpt3sas_base.h"
0061 
0062 /**
0063  * _mpt3sas_raise_sigio - notifiy app
0064  * @ioc: per adapter object
0065  * @event_data: ?
0066  */
0067 static void
0068 _mpt3sas_raise_sigio(struct MPT3SAS_ADAPTER *ioc,
0069     struct SL_WH_TRIGGERS_EVENT_DATA_T *event_data)
0070 {
0071     Mpi2EventNotificationReply_t *mpi_reply;
0072     u16 sz, event_data_sz;
0073     unsigned long flags;
0074 
0075     dTriggerDiagPrintk(ioc, ioc_info(ioc, "%s: enter\n", __func__));
0076 
0077     sz = offsetof(Mpi2EventNotificationReply_t, EventData) +
0078         sizeof(struct SL_WH_TRIGGERS_EVENT_DATA_T) + 4;
0079     mpi_reply = kzalloc(sz, GFP_KERNEL);
0080     if (!mpi_reply)
0081         goto out;
0082     mpi_reply->Event = cpu_to_le16(MPI3_EVENT_DIAGNOSTIC_TRIGGER_FIRED);
0083     event_data_sz = (sizeof(struct SL_WH_TRIGGERS_EVENT_DATA_T) + 4) / 4;
0084     mpi_reply->EventDataLength = cpu_to_le16(event_data_sz);
0085     memcpy(&mpi_reply->EventData, event_data,
0086         sizeof(struct SL_WH_TRIGGERS_EVENT_DATA_T));
0087     dTriggerDiagPrintk(ioc,
0088                ioc_info(ioc, "%s: add to driver event log\n",
0089                     __func__));
0090     mpt3sas_ctl_add_to_event_log(ioc, mpi_reply);
0091     kfree(mpi_reply);
0092  out:
0093 
0094     /* clearing the diag_trigger_active flag */
0095     spin_lock_irqsave(&ioc->diag_trigger_lock, flags);
0096     dTriggerDiagPrintk(ioc,
0097                ioc_info(ioc, "%s: clearing diag_trigger_active flag\n",
0098                     __func__));
0099     ioc->diag_trigger_active = 0;
0100     spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags);
0101 
0102     dTriggerDiagPrintk(ioc, ioc_info(ioc, "%s: exit\n",
0103                      __func__));
0104 }
0105 
0106 /**
0107  * mpt3sas_process_trigger_data - process the event data for the trigger
0108  * @ioc: per adapter object
0109  * @event_data: ?
0110  */
0111 void
0112 mpt3sas_process_trigger_data(struct MPT3SAS_ADAPTER *ioc,
0113     struct SL_WH_TRIGGERS_EVENT_DATA_T *event_data)
0114 {
0115     u8 issue_reset = 0;
0116     u32 *trig_data = (u32 *)&event_data->u.master;
0117 
0118     dTriggerDiagPrintk(ioc, ioc_info(ioc, "%s: enter\n", __func__));
0119 
0120     /* release the diag buffer trace */
0121     if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
0122         MPT3_DIAG_BUFFER_IS_RELEASED) == 0) {
0123         /*
0124          * add a log message so that user knows which event caused
0125          * the release
0126          */
0127         ioc_info(ioc,
0128             "%s: Releasing the trace buffer. Trigger_Type 0x%08x, Data[0] 0x%08x, Data[1] 0x%08x\n",
0129             __func__, event_data->trigger_type,
0130             trig_data[0], trig_data[1]);
0131         mpt3sas_send_diag_release(ioc, MPI2_DIAG_BUF_TYPE_TRACE,
0132             &issue_reset);
0133     }
0134 
0135     ioc->htb_rel.buffer_rel_condition = MPT3_DIAG_BUFFER_REL_TRIGGER;
0136     if (event_data) {
0137         ioc->htb_rel.trigger_type = event_data->trigger_type;
0138         switch (event_data->trigger_type) {
0139         case MPT3SAS_TRIGGER_SCSI:
0140             memcpy(&ioc->htb_rel.trigger_info_dwords,
0141                 &event_data->u.scsi,
0142                 sizeof(struct SL_WH_SCSI_TRIGGER_T));
0143             break;
0144         case MPT3SAS_TRIGGER_MPI:
0145             memcpy(&ioc->htb_rel.trigger_info_dwords,
0146                 &event_data->u.mpi,
0147                 sizeof(struct SL_WH_MPI_TRIGGER_T));
0148             break;
0149         case MPT3SAS_TRIGGER_MASTER:
0150             ioc->htb_rel.trigger_info_dwords[0] =
0151                 event_data->u.master.MasterData;
0152             break;
0153         case MPT3SAS_TRIGGER_EVENT:
0154             memcpy(&ioc->htb_rel.trigger_info_dwords,
0155                 &event_data->u.event,
0156                 sizeof(struct SL_WH_EVENT_TRIGGER_T));
0157             break;
0158         default:
0159             ioc_err(ioc, "%d - Is not a valid Trigger type\n",
0160                 event_data->trigger_type);
0161             break;
0162         }
0163     }
0164     _mpt3sas_raise_sigio(ioc, event_data);
0165 
0166     dTriggerDiagPrintk(ioc, ioc_info(ioc, "%s: exit\n",
0167                      __func__));
0168 }
0169 
0170 /**
0171  * mpt3sas_trigger_master - Master trigger handler
0172  * @ioc: per adapter object
0173  * @trigger_bitmask:
0174  *
0175  */
0176 void
0177 mpt3sas_trigger_master(struct MPT3SAS_ADAPTER *ioc, u32 trigger_bitmask)
0178 {
0179     struct SL_WH_TRIGGERS_EVENT_DATA_T event_data;
0180     unsigned long flags;
0181     u8 found_match = 0;
0182 
0183     spin_lock_irqsave(&ioc->diag_trigger_lock, flags);
0184 
0185     if (trigger_bitmask & MASTER_TRIGGER_FW_FAULT ||
0186         trigger_bitmask & MASTER_TRIGGER_ADAPTER_RESET)
0187         goto by_pass_checks;
0188 
0189     /* check to see if trace buffers are currently registered */
0190     if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
0191         MPT3_DIAG_BUFFER_IS_REGISTERED) == 0) {
0192         spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags);
0193         return;
0194     }
0195 
0196     /* check to see if trace buffers are currently released */
0197     if (ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
0198         MPT3_DIAG_BUFFER_IS_RELEASED) {
0199         spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags);
0200         return;
0201     }
0202 
0203  by_pass_checks:
0204 
0205     dTriggerDiagPrintk(ioc,
0206                ioc_info(ioc, "%s: enter - trigger_bitmask = 0x%08x\n",
0207                     __func__, trigger_bitmask));
0208 
0209     /* don't send trigger if an trigger is currently active */
0210     if (ioc->diag_trigger_active) {
0211         spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags);
0212         goto out;
0213     }
0214 
0215     /* check for the trigger condition */
0216     if (ioc->diag_trigger_master.MasterData & trigger_bitmask) {
0217         found_match = 1;
0218         ioc->diag_trigger_active = 1;
0219         dTriggerDiagPrintk(ioc,
0220                    ioc_info(ioc, "%s: setting diag_trigger_active flag\n",
0221                         __func__));
0222     }
0223     spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags);
0224 
0225     if (!found_match)
0226         goto out;
0227 
0228     memset(&event_data, 0, sizeof(struct SL_WH_TRIGGERS_EVENT_DATA_T));
0229     event_data.trigger_type = MPT3SAS_TRIGGER_MASTER;
0230     event_data.u.master.MasterData = trigger_bitmask;
0231 
0232     if (trigger_bitmask & MASTER_TRIGGER_FW_FAULT ||
0233         trigger_bitmask & MASTER_TRIGGER_ADAPTER_RESET) {
0234         ioc->htb_rel.trigger_type = MPT3SAS_TRIGGER_MASTER;
0235         ioc->htb_rel.trigger_info_dwords[0] = trigger_bitmask;
0236         if (ioc->reset_from_user)
0237             ioc->htb_rel.trigger_info_dwords[1] =
0238                 MPT_DIAG_RESET_ISSUED_BY_USER;
0239         _mpt3sas_raise_sigio(ioc, &event_data);
0240     } else
0241         mpt3sas_send_trigger_data_event(ioc, &event_data);
0242 
0243  out:
0244     dTriggerDiagPrintk(ioc, ioc_info(ioc, "%s: exit\n",
0245                      __func__));
0246 }
0247 
0248 /**
0249  * mpt3sas_trigger_event - Event trigger handler
0250  * @ioc: per adapter object
0251  * @event: ?
0252  * @log_entry_qualifier: ?
0253  *
0254  */
0255 void
0256 mpt3sas_trigger_event(struct MPT3SAS_ADAPTER *ioc, u16 event,
0257     u16 log_entry_qualifier)
0258 {
0259     struct SL_WH_TRIGGERS_EVENT_DATA_T event_data;
0260     struct SL_WH_EVENT_TRIGGER_T *event_trigger;
0261     int i;
0262     unsigned long flags;
0263     u8 found_match;
0264 
0265     spin_lock_irqsave(&ioc->diag_trigger_lock, flags);
0266 
0267     /* check to see if trace buffers are currently registered */
0268     if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
0269         MPT3_DIAG_BUFFER_IS_REGISTERED) == 0) {
0270         spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags);
0271         return;
0272     }
0273 
0274     /* check to see if trace buffers are currently released */
0275     if (ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
0276         MPT3_DIAG_BUFFER_IS_RELEASED) {
0277         spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags);
0278         return;
0279     }
0280 
0281     dTriggerDiagPrintk(ioc,
0282                ioc_info(ioc, "%s: enter - event = 0x%04x, log_entry_qualifier = 0x%04x\n",
0283                     __func__, event, log_entry_qualifier));
0284 
0285     /* don't send trigger if an trigger is currently active */
0286     if (ioc->diag_trigger_active) {
0287         spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags);
0288         goto out;
0289     }
0290 
0291     /* check for the trigger condition */
0292     event_trigger = ioc->diag_trigger_event.EventTriggerEntry;
0293     for (i = 0 , found_match = 0; i < ioc->diag_trigger_event.ValidEntries
0294         && !found_match; i++, event_trigger++) {
0295         if (event_trigger->EventValue != event)
0296             continue;
0297         if (event == MPI2_EVENT_LOG_ENTRY_ADDED) {
0298             if (event_trigger->LogEntryQualifier ==
0299                 log_entry_qualifier)
0300                 found_match = 1;
0301             continue;
0302         }
0303         found_match = 1;
0304         ioc->diag_trigger_active = 1;
0305         dTriggerDiagPrintk(ioc,
0306                    ioc_info(ioc, "%s: setting diag_trigger_active flag\n",
0307                         __func__));
0308     }
0309     spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags);
0310 
0311     if (!found_match)
0312         goto out;
0313 
0314     dTriggerDiagPrintk(ioc,
0315                ioc_info(ioc, "%s: setting diag_trigger_active flag\n",
0316                     __func__));
0317     memset(&event_data, 0, sizeof(struct SL_WH_TRIGGERS_EVENT_DATA_T));
0318     event_data.trigger_type = MPT3SAS_TRIGGER_EVENT;
0319     event_data.u.event.EventValue = event;
0320     event_data.u.event.LogEntryQualifier = log_entry_qualifier;
0321     mpt3sas_send_trigger_data_event(ioc, &event_data);
0322  out:
0323     dTriggerDiagPrintk(ioc, ioc_info(ioc, "%s: exit\n",
0324                      __func__));
0325 }
0326 
0327 /**
0328  * mpt3sas_trigger_scsi - SCSI trigger handler
0329  * @ioc: per adapter object
0330  * @sense_key: ?
0331  * @asc: ?
0332  * @ascq: ?
0333  *
0334  */
0335 void
0336 mpt3sas_trigger_scsi(struct MPT3SAS_ADAPTER *ioc, u8 sense_key, u8 asc,
0337     u8 ascq)
0338 {
0339     struct SL_WH_TRIGGERS_EVENT_DATA_T event_data;
0340     struct SL_WH_SCSI_TRIGGER_T *scsi_trigger;
0341     int i;
0342     unsigned long flags;
0343     u8 found_match;
0344 
0345     spin_lock_irqsave(&ioc->diag_trigger_lock, flags);
0346 
0347     /* check to see if trace buffers are currently registered */
0348     if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
0349         MPT3_DIAG_BUFFER_IS_REGISTERED) == 0) {
0350         spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags);
0351         return;
0352     }
0353 
0354     /* check to see if trace buffers are currently released */
0355     if (ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
0356         MPT3_DIAG_BUFFER_IS_RELEASED) {
0357         spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags);
0358         return;
0359     }
0360 
0361     dTriggerDiagPrintk(ioc,
0362                ioc_info(ioc, "%s: enter - sense_key = 0x%02x, asc = 0x%02x, ascq = 0x%02x\n",
0363                     __func__, sense_key, asc, ascq));
0364 
0365     /* don't send trigger if an trigger is currently active */
0366     if (ioc->diag_trigger_active) {
0367         spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags);
0368         goto out;
0369     }
0370 
0371     /* check for the trigger condition */
0372     scsi_trigger = ioc->diag_trigger_scsi.SCSITriggerEntry;
0373     for (i = 0 , found_match = 0; i < ioc->diag_trigger_scsi.ValidEntries
0374         && !found_match; i++, scsi_trigger++) {
0375         if (scsi_trigger->SenseKey != sense_key)
0376             continue;
0377         if (!(scsi_trigger->ASC == 0xFF || scsi_trigger->ASC == asc))
0378             continue;
0379         if (!(scsi_trigger->ASCQ == 0xFF || scsi_trigger->ASCQ == ascq))
0380             continue;
0381         found_match = 1;
0382         ioc->diag_trigger_active = 1;
0383     }
0384     spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags);
0385 
0386     if (!found_match)
0387         goto out;
0388 
0389     dTriggerDiagPrintk(ioc,
0390                ioc_info(ioc, "%s: setting diag_trigger_active flag\n",
0391                     __func__));
0392     memset(&event_data, 0, sizeof(struct SL_WH_TRIGGERS_EVENT_DATA_T));
0393     event_data.trigger_type = MPT3SAS_TRIGGER_SCSI;
0394     event_data.u.scsi.SenseKey = sense_key;
0395     event_data.u.scsi.ASC = asc;
0396     event_data.u.scsi.ASCQ = ascq;
0397     mpt3sas_send_trigger_data_event(ioc, &event_data);
0398  out:
0399     dTriggerDiagPrintk(ioc, ioc_info(ioc, "%s: exit\n",
0400                      __func__));
0401 }
0402 
0403 /**
0404  * mpt3sas_trigger_mpi - MPI trigger handler
0405  * @ioc: per adapter object
0406  * @ioc_status: ?
0407  * @loginfo: ?
0408  *
0409  */
0410 void
0411 mpt3sas_trigger_mpi(struct MPT3SAS_ADAPTER *ioc, u16 ioc_status, u32 loginfo)
0412 {
0413     struct SL_WH_TRIGGERS_EVENT_DATA_T event_data;
0414     struct SL_WH_MPI_TRIGGER_T *mpi_trigger;
0415     int i;
0416     unsigned long flags;
0417     u8 found_match;
0418 
0419     spin_lock_irqsave(&ioc->diag_trigger_lock, flags);
0420 
0421     /* check to see if trace buffers are currently registered */
0422     if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
0423         MPT3_DIAG_BUFFER_IS_REGISTERED) == 0) {
0424         spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags);
0425         return;
0426     }
0427 
0428     /* check to see if trace buffers are currently released */
0429     if (ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
0430         MPT3_DIAG_BUFFER_IS_RELEASED) {
0431         spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags);
0432         return;
0433     }
0434 
0435     dTriggerDiagPrintk(ioc,
0436                ioc_info(ioc, "%s: enter - ioc_status = 0x%04x, loginfo = 0x%08x\n",
0437                     __func__, ioc_status, loginfo));
0438 
0439     /* don't send trigger if an trigger is currently active */
0440     if (ioc->diag_trigger_active) {
0441         spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags);
0442         goto out;
0443     }
0444 
0445     /* check for the trigger condition */
0446     mpi_trigger = ioc->diag_trigger_mpi.MPITriggerEntry;
0447     for (i = 0 , found_match = 0; i < ioc->diag_trigger_mpi.ValidEntries
0448         && !found_match; i++, mpi_trigger++) {
0449         if (mpi_trigger->IOCStatus != ioc_status)
0450             continue;
0451         if (!(mpi_trigger->IocLogInfo == 0xFFFFFFFF ||
0452             mpi_trigger->IocLogInfo == loginfo))
0453             continue;
0454         found_match = 1;
0455         ioc->diag_trigger_active = 1;
0456     }
0457     spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags);
0458 
0459     if (!found_match)
0460         goto out;
0461 
0462     dTriggerDiagPrintk(ioc,
0463                ioc_info(ioc, "%s: setting diag_trigger_active flag\n",
0464                     __func__));
0465     memset(&event_data, 0, sizeof(struct SL_WH_TRIGGERS_EVENT_DATA_T));
0466     event_data.trigger_type = MPT3SAS_TRIGGER_MPI;
0467     event_data.u.mpi.IOCStatus = ioc_status;
0468     event_data.u.mpi.IocLogInfo = loginfo;
0469     mpt3sas_send_trigger_data_event(ioc, &event_data);
0470  out:
0471     dTriggerDiagPrintk(ioc, ioc_info(ioc, "%s: exit\n",
0472                      __func__));
0473 }