18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Management Module Support for MPT (Message Passing Technology) based 38c2ecf20Sopenharmony_ci * controllers 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * This code is based on drivers/scsi/mpt3sas/mpt3sas_ctl.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#include "mpt3sas_ctl.h" 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cistatic struct fasync_struct *async_queue; 658c2ecf20Sopenharmony_cistatic DECLARE_WAIT_QUEUE_HEAD(ctl_poll_wait); 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci/** 698c2ecf20Sopenharmony_ci * enum block_state - blocking state 708c2ecf20Sopenharmony_ci * @NON_BLOCKING: non blocking 718c2ecf20Sopenharmony_ci * @BLOCKING: blocking 728c2ecf20Sopenharmony_ci * 738c2ecf20Sopenharmony_ci * These states are for ioctls that need to wait for a response 748c2ecf20Sopenharmony_ci * from firmware, so they probably require sleep. 758c2ecf20Sopenharmony_ci */ 768c2ecf20Sopenharmony_cienum block_state { 778c2ecf20Sopenharmony_ci NON_BLOCKING, 788c2ecf20Sopenharmony_ci BLOCKING, 798c2ecf20Sopenharmony_ci}; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci/** 828c2ecf20Sopenharmony_ci * _ctl_display_some_debug - debug routine 838c2ecf20Sopenharmony_ci * @ioc: per adapter object 848c2ecf20Sopenharmony_ci * @smid: system request message index 858c2ecf20Sopenharmony_ci * @calling_function_name: string pass from calling function 868c2ecf20Sopenharmony_ci * @mpi_reply: reply message frame 878c2ecf20Sopenharmony_ci * Context: none. 888c2ecf20Sopenharmony_ci * 898c2ecf20Sopenharmony_ci * Function for displaying debug info helpful when debugging issues 908c2ecf20Sopenharmony_ci * in this module. 918c2ecf20Sopenharmony_ci */ 928c2ecf20Sopenharmony_cistatic void 938c2ecf20Sopenharmony_ci_ctl_display_some_debug(struct MPT3SAS_ADAPTER *ioc, u16 smid, 948c2ecf20Sopenharmony_ci char *calling_function_name, MPI2DefaultReply_t *mpi_reply) 958c2ecf20Sopenharmony_ci{ 968c2ecf20Sopenharmony_ci Mpi2ConfigRequest_t *mpi_request; 978c2ecf20Sopenharmony_ci char *desc = NULL; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci if (!(ioc->logging_level & MPT_DEBUG_IOCTL)) 1008c2ecf20Sopenharmony_ci return; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci mpi_request = mpt3sas_base_get_msg_frame(ioc, smid); 1038c2ecf20Sopenharmony_ci switch (mpi_request->Function) { 1048c2ecf20Sopenharmony_ci case MPI2_FUNCTION_SCSI_IO_REQUEST: 1058c2ecf20Sopenharmony_ci { 1068c2ecf20Sopenharmony_ci Mpi2SCSIIORequest_t *scsi_request = 1078c2ecf20Sopenharmony_ci (Mpi2SCSIIORequest_t *)mpi_request; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci snprintf(ioc->tmp_string, MPT_STRING_LENGTH, 1108c2ecf20Sopenharmony_ci "scsi_io, cmd(0x%02x), cdb_len(%d)", 1118c2ecf20Sopenharmony_ci scsi_request->CDB.CDB32[0], 1128c2ecf20Sopenharmony_ci le16_to_cpu(scsi_request->IoFlags) & 0xF); 1138c2ecf20Sopenharmony_ci desc = ioc->tmp_string; 1148c2ecf20Sopenharmony_ci break; 1158c2ecf20Sopenharmony_ci } 1168c2ecf20Sopenharmony_ci case MPI2_FUNCTION_SCSI_TASK_MGMT: 1178c2ecf20Sopenharmony_ci desc = "task_mgmt"; 1188c2ecf20Sopenharmony_ci break; 1198c2ecf20Sopenharmony_ci case MPI2_FUNCTION_IOC_INIT: 1208c2ecf20Sopenharmony_ci desc = "ioc_init"; 1218c2ecf20Sopenharmony_ci break; 1228c2ecf20Sopenharmony_ci case MPI2_FUNCTION_IOC_FACTS: 1238c2ecf20Sopenharmony_ci desc = "ioc_facts"; 1248c2ecf20Sopenharmony_ci break; 1258c2ecf20Sopenharmony_ci case MPI2_FUNCTION_CONFIG: 1268c2ecf20Sopenharmony_ci { 1278c2ecf20Sopenharmony_ci Mpi2ConfigRequest_t *config_request = 1288c2ecf20Sopenharmony_ci (Mpi2ConfigRequest_t *)mpi_request; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci snprintf(ioc->tmp_string, MPT_STRING_LENGTH, 1318c2ecf20Sopenharmony_ci "config, type(0x%02x), ext_type(0x%02x), number(%d)", 1328c2ecf20Sopenharmony_ci (config_request->Header.PageType & 1338c2ecf20Sopenharmony_ci MPI2_CONFIG_PAGETYPE_MASK), config_request->ExtPageType, 1348c2ecf20Sopenharmony_ci config_request->Header.PageNumber); 1358c2ecf20Sopenharmony_ci desc = ioc->tmp_string; 1368c2ecf20Sopenharmony_ci break; 1378c2ecf20Sopenharmony_ci } 1388c2ecf20Sopenharmony_ci case MPI2_FUNCTION_PORT_FACTS: 1398c2ecf20Sopenharmony_ci desc = "port_facts"; 1408c2ecf20Sopenharmony_ci break; 1418c2ecf20Sopenharmony_ci case MPI2_FUNCTION_PORT_ENABLE: 1428c2ecf20Sopenharmony_ci desc = "port_enable"; 1438c2ecf20Sopenharmony_ci break; 1448c2ecf20Sopenharmony_ci case MPI2_FUNCTION_EVENT_NOTIFICATION: 1458c2ecf20Sopenharmony_ci desc = "event_notification"; 1468c2ecf20Sopenharmony_ci break; 1478c2ecf20Sopenharmony_ci case MPI2_FUNCTION_FW_DOWNLOAD: 1488c2ecf20Sopenharmony_ci desc = "fw_download"; 1498c2ecf20Sopenharmony_ci break; 1508c2ecf20Sopenharmony_ci case MPI2_FUNCTION_FW_UPLOAD: 1518c2ecf20Sopenharmony_ci desc = "fw_upload"; 1528c2ecf20Sopenharmony_ci break; 1538c2ecf20Sopenharmony_ci case MPI2_FUNCTION_RAID_ACTION: 1548c2ecf20Sopenharmony_ci desc = "raid_action"; 1558c2ecf20Sopenharmony_ci break; 1568c2ecf20Sopenharmony_ci case MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH: 1578c2ecf20Sopenharmony_ci { 1588c2ecf20Sopenharmony_ci Mpi2SCSIIORequest_t *scsi_request = 1598c2ecf20Sopenharmony_ci (Mpi2SCSIIORequest_t *)mpi_request; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci snprintf(ioc->tmp_string, MPT_STRING_LENGTH, 1628c2ecf20Sopenharmony_ci "raid_pass, cmd(0x%02x), cdb_len(%d)", 1638c2ecf20Sopenharmony_ci scsi_request->CDB.CDB32[0], 1648c2ecf20Sopenharmony_ci le16_to_cpu(scsi_request->IoFlags) & 0xF); 1658c2ecf20Sopenharmony_ci desc = ioc->tmp_string; 1668c2ecf20Sopenharmony_ci break; 1678c2ecf20Sopenharmony_ci } 1688c2ecf20Sopenharmony_ci case MPI2_FUNCTION_SAS_IO_UNIT_CONTROL: 1698c2ecf20Sopenharmony_ci desc = "sas_iounit_cntl"; 1708c2ecf20Sopenharmony_ci break; 1718c2ecf20Sopenharmony_ci case MPI2_FUNCTION_SATA_PASSTHROUGH: 1728c2ecf20Sopenharmony_ci desc = "sata_pass"; 1738c2ecf20Sopenharmony_ci break; 1748c2ecf20Sopenharmony_ci case MPI2_FUNCTION_DIAG_BUFFER_POST: 1758c2ecf20Sopenharmony_ci desc = "diag_buffer_post"; 1768c2ecf20Sopenharmony_ci break; 1778c2ecf20Sopenharmony_ci case MPI2_FUNCTION_DIAG_RELEASE: 1788c2ecf20Sopenharmony_ci desc = "diag_release"; 1798c2ecf20Sopenharmony_ci break; 1808c2ecf20Sopenharmony_ci case MPI2_FUNCTION_SMP_PASSTHROUGH: 1818c2ecf20Sopenharmony_ci desc = "smp_passthrough"; 1828c2ecf20Sopenharmony_ci break; 1838c2ecf20Sopenharmony_ci case MPI2_FUNCTION_TOOLBOX: 1848c2ecf20Sopenharmony_ci desc = "toolbox"; 1858c2ecf20Sopenharmony_ci break; 1868c2ecf20Sopenharmony_ci case MPI2_FUNCTION_NVME_ENCAPSULATED: 1878c2ecf20Sopenharmony_ci desc = "nvme_encapsulated"; 1888c2ecf20Sopenharmony_ci break; 1898c2ecf20Sopenharmony_ci } 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci if (!desc) 1928c2ecf20Sopenharmony_ci return; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci ioc_info(ioc, "%s: %s, smid(%d)\n", calling_function_name, desc, smid); 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci if (!mpi_reply) 1978c2ecf20Sopenharmony_ci return; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci if (mpi_reply->IOCStatus || mpi_reply->IOCLogInfo) 2008c2ecf20Sopenharmony_ci ioc_info(ioc, "\tiocstatus(0x%04x), loginfo(0x%08x)\n", 2018c2ecf20Sopenharmony_ci le16_to_cpu(mpi_reply->IOCStatus), 2028c2ecf20Sopenharmony_ci le32_to_cpu(mpi_reply->IOCLogInfo)); 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci if (mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST || 2058c2ecf20Sopenharmony_ci mpi_request->Function == 2068c2ecf20Sopenharmony_ci MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH) { 2078c2ecf20Sopenharmony_ci Mpi2SCSIIOReply_t *scsi_reply = 2088c2ecf20Sopenharmony_ci (Mpi2SCSIIOReply_t *)mpi_reply; 2098c2ecf20Sopenharmony_ci struct _sas_device *sas_device = NULL; 2108c2ecf20Sopenharmony_ci struct _pcie_device *pcie_device = NULL; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci sas_device = mpt3sas_get_sdev_by_handle(ioc, 2138c2ecf20Sopenharmony_ci le16_to_cpu(scsi_reply->DevHandle)); 2148c2ecf20Sopenharmony_ci if (sas_device) { 2158c2ecf20Sopenharmony_ci ioc_warn(ioc, "\tsas_address(0x%016llx), phy(%d)\n", 2168c2ecf20Sopenharmony_ci (u64)sas_device->sas_address, 2178c2ecf20Sopenharmony_ci sas_device->phy); 2188c2ecf20Sopenharmony_ci ioc_warn(ioc, "\tenclosure_logical_id(0x%016llx), slot(%d)\n", 2198c2ecf20Sopenharmony_ci (u64)sas_device->enclosure_logical_id, 2208c2ecf20Sopenharmony_ci sas_device->slot); 2218c2ecf20Sopenharmony_ci sas_device_put(sas_device); 2228c2ecf20Sopenharmony_ci } 2238c2ecf20Sopenharmony_ci if (!sas_device) { 2248c2ecf20Sopenharmony_ci pcie_device = mpt3sas_get_pdev_by_handle(ioc, 2258c2ecf20Sopenharmony_ci le16_to_cpu(scsi_reply->DevHandle)); 2268c2ecf20Sopenharmony_ci if (pcie_device) { 2278c2ecf20Sopenharmony_ci ioc_warn(ioc, "\tWWID(0x%016llx), port(%d)\n", 2288c2ecf20Sopenharmony_ci (unsigned long long)pcie_device->wwid, 2298c2ecf20Sopenharmony_ci pcie_device->port_num); 2308c2ecf20Sopenharmony_ci if (pcie_device->enclosure_handle != 0) 2318c2ecf20Sopenharmony_ci ioc_warn(ioc, "\tenclosure_logical_id(0x%016llx), slot(%d)\n", 2328c2ecf20Sopenharmony_ci (u64)pcie_device->enclosure_logical_id, 2338c2ecf20Sopenharmony_ci pcie_device->slot); 2348c2ecf20Sopenharmony_ci pcie_device_put(pcie_device); 2358c2ecf20Sopenharmony_ci } 2368c2ecf20Sopenharmony_ci } 2378c2ecf20Sopenharmony_ci if (scsi_reply->SCSIState || scsi_reply->SCSIStatus) 2388c2ecf20Sopenharmony_ci ioc_info(ioc, "\tscsi_state(0x%02x), scsi_status(0x%02x)\n", 2398c2ecf20Sopenharmony_ci scsi_reply->SCSIState, 2408c2ecf20Sopenharmony_ci scsi_reply->SCSIStatus); 2418c2ecf20Sopenharmony_ci } 2428c2ecf20Sopenharmony_ci} 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci/** 2458c2ecf20Sopenharmony_ci * mpt3sas_ctl_done - ctl module completion routine 2468c2ecf20Sopenharmony_ci * @ioc: per adapter object 2478c2ecf20Sopenharmony_ci * @smid: system request message index 2488c2ecf20Sopenharmony_ci * @msix_index: MSIX table index supplied by the OS 2498c2ecf20Sopenharmony_ci * @reply: reply message frame(lower 32bit addr) 2508c2ecf20Sopenharmony_ci * Context: none. 2518c2ecf20Sopenharmony_ci * 2528c2ecf20Sopenharmony_ci * The callback handler when using ioc->ctl_cb_idx. 2538c2ecf20Sopenharmony_ci * 2548c2ecf20Sopenharmony_ci * Return: 1 meaning mf should be freed from _base_interrupt 2558c2ecf20Sopenharmony_ci * 0 means the mf is freed from this function. 2568c2ecf20Sopenharmony_ci */ 2578c2ecf20Sopenharmony_ciu8 2588c2ecf20Sopenharmony_cimpt3sas_ctl_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, 2598c2ecf20Sopenharmony_ci u32 reply) 2608c2ecf20Sopenharmony_ci{ 2618c2ecf20Sopenharmony_ci MPI2DefaultReply_t *mpi_reply; 2628c2ecf20Sopenharmony_ci Mpi2SCSIIOReply_t *scsiio_reply; 2638c2ecf20Sopenharmony_ci Mpi26NVMeEncapsulatedErrorReply_t *nvme_error_reply; 2648c2ecf20Sopenharmony_ci const void *sense_data; 2658c2ecf20Sopenharmony_ci u32 sz; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci if (ioc->ctl_cmds.status == MPT3_CMD_NOT_USED) 2688c2ecf20Sopenharmony_ci return 1; 2698c2ecf20Sopenharmony_ci if (ioc->ctl_cmds.smid != smid) 2708c2ecf20Sopenharmony_ci return 1; 2718c2ecf20Sopenharmony_ci ioc->ctl_cmds.status |= MPT3_CMD_COMPLETE; 2728c2ecf20Sopenharmony_ci mpi_reply = mpt3sas_base_get_reply_virt_addr(ioc, reply); 2738c2ecf20Sopenharmony_ci if (mpi_reply) { 2748c2ecf20Sopenharmony_ci memcpy(ioc->ctl_cmds.reply, mpi_reply, mpi_reply->MsgLength*4); 2758c2ecf20Sopenharmony_ci ioc->ctl_cmds.status |= MPT3_CMD_REPLY_VALID; 2768c2ecf20Sopenharmony_ci /* get sense data */ 2778c2ecf20Sopenharmony_ci if (mpi_reply->Function == MPI2_FUNCTION_SCSI_IO_REQUEST || 2788c2ecf20Sopenharmony_ci mpi_reply->Function == 2798c2ecf20Sopenharmony_ci MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH) { 2808c2ecf20Sopenharmony_ci scsiio_reply = (Mpi2SCSIIOReply_t *)mpi_reply; 2818c2ecf20Sopenharmony_ci if (scsiio_reply->SCSIState & 2828c2ecf20Sopenharmony_ci MPI2_SCSI_STATE_AUTOSENSE_VALID) { 2838c2ecf20Sopenharmony_ci sz = min_t(u32, SCSI_SENSE_BUFFERSIZE, 2848c2ecf20Sopenharmony_ci le32_to_cpu(scsiio_reply->SenseCount)); 2858c2ecf20Sopenharmony_ci sense_data = mpt3sas_base_get_sense_buffer(ioc, 2868c2ecf20Sopenharmony_ci smid); 2878c2ecf20Sopenharmony_ci memcpy(ioc->ctl_cmds.sense, sense_data, sz); 2888c2ecf20Sopenharmony_ci } 2898c2ecf20Sopenharmony_ci } 2908c2ecf20Sopenharmony_ci /* 2918c2ecf20Sopenharmony_ci * Get Error Response data for NVMe device. The ctl_cmds.sense 2928c2ecf20Sopenharmony_ci * buffer is used to store the Error Response data. 2938c2ecf20Sopenharmony_ci */ 2948c2ecf20Sopenharmony_ci if (mpi_reply->Function == MPI2_FUNCTION_NVME_ENCAPSULATED) { 2958c2ecf20Sopenharmony_ci nvme_error_reply = 2968c2ecf20Sopenharmony_ci (Mpi26NVMeEncapsulatedErrorReply_t *)mpi_reply; 2978c2ecf20Sopenharmony_ci sz = min_t(u32, NVME_ERROR_RESPONSE_SIZE, 2988c2ecf20Sopenharmony_ci le16_to_cpu(nvme_error_reply->ErrorResponseCount)); 2998c2ecf20Sopenharmony_ci sense_data = mpt3sas_base_get_sense_buffer(ioc, smid); 3008c2ecf20Sopenharmony_ci memcpy(ioc->ctl_cmds.sense, sense_data, sz); 3018c2ecf20Sopenharmony_ci } 3028c2ecf20Sopenharmony_ci } 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci _ctl_display_some_debug(ioc, smid, "ctl_done", mpi_reply); 3058c2ecf20Sopenharmony_ci ioc->ctl_cmds.status &= ~MPT3_CMD_PENDING; 3068c2ecf20Sopenharmony_ci complete(&ioc->ctl_cmds.done); 3078c2ecf20Sopenharmony_ci return 1; 3088c2ecf20Sopenharmony_ci} 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci/** 3118c2ecf20Sopenharmony_ci * _ctl_check_event_type - determines when an event needs logging 3128c2ecf20Sopenharmony_ci * @ioc: per adapter object 3138c2ecf20Sopenharmony_ci * @event: firmware event 3148c2ecf20Sopenharmony_ci * 3158c2ecf20Sopenharmony_ci * The bitmask in ioc->event_type[] indicates which events should be 3168c2ecf20Sopenharmony_ci * be saved in the driver event_log. This bitmask is set by application. 3178c2ecf20Sopenharmony_ci * 3188c2ecf20Sopenharmony_ci * Return: 1 when event should be captured, or zero means no match. 3198c2ecf20Sopenharmony_ci */ 3208c2ecf20Sopenharmony_cistatic int 3218c2ecf20Sopenharmony_ci_ctl_check_event_type(struct MPT3SAS_ADAPTER *ioc, u16 event) 3228c2ecf20Sopenharmony_ci{ 3238c2ecf20Sopenharmony_ci u16 i; 3248c2ecf20Sopenharmony_ci u32 desired_event; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci if (event >= 128 || !event || !ioc->event_log) 3278c2ecf20Sopenharmony_ci return 0; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci desired_event = (1 << (event % 32)); 3308c2ecf20Sopenharmony_ci if (!desired_event) 3318c2ecf20Sopenharmony_ci desired_event = 1; 3328c2ecf20Sopenharmony_ci i = event / 32; 3338c2ecf20Sopenharmony_ci return desired_event & ioc->event_type[i]; 3348c2ecf20Sopenharmony_ci} 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci/** 3378c2ecf20Sopenharmony_ci * mpt3sas_ctl_add_to_event_log - add event 3388c2ecf20Sopenharmony_ci * @ioc: per adapter object 3398c2ecf20Sopenharmony_ci * @mpi_reply: reply message frame 3408c2ecf20Sopenharmony_ci */ 3418c2ecf20Sopenharmony_civoid 3428c2ecf20Sopenharmony_cimpt3sas_ctl_add_to_event_log(struct MPT3SAS_ADAPTER *ioc, 3438c2ecf20Sopenharmony_ci Mpi2EventNotificationReply_t *mpi_reply) 3448c2ecf20Sopenharmony_ci{ 3458c2ecf20Sopenharmony_ci struct MPT3_IOCTL_EVENTS *event_log; 3468c2ecf20Sopenharmony_ci u16 event; 3478c2ecf20Sopenharmony_ci int i; 3488c2ecf20Sopenharmony_ci u32 sz, event_data_sz; 3498c2ecf20Sopenharmony_ci u8 send_aen = 0; 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci if (!ioc->event_log) 3528c2ecf20Sopenharmony_ci return; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci event = le16_to_cpu(mpi_reply->Event); 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci if (_ctl_check_event_type(ioc, event)) { 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci /* insert entry into circular event_log */ 3598c2ecf20Sopenharmony_ci i = ioc->event_context % MPT3SAS_CTL_EVENT_LOG_SIZE; 3608c2ecf20Sopenharmony_ci event_log = ioc->event_log; 3618c2ecf20Sopenharmony_ci event_log[i].event = event; 3628c2ecf20Sopenharmony_ci event_log[i].context = ioc->event_context++; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci event_data_sz = le16_to_cpu(mpi_reply->EventDataLength)*4; 3658c2ecf20Sopenharmony_ci sz = min_t(u32, event_data_sz, MPT3_EVENT_DATA_SIZE); 3668c2ecf20Sopenharmony_ci memset(event_log[i].data, 0, MPT3_EVENT_DATA_SIZE); 3678c2ecf20Sopenharmony_ci memcpy(event_log[i].data, mpi_reply->EventData, sz); 3688c2ecf20Sopenharmony_ci send_aen = 1; 3698c2ecf20Sopenharmony_ci } 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci /* This aen_event_read_flag flag is set until the 3728c2ecf20Sopenharmony_ci * application has read the event log. 3738c2ecf20Sopenharmony_ci * For MPI2_EVENT_LOG_ENTRY_ADDED, we always notify. 3748c2ecf20Sopenharmony_ci */ 3758c2ecf20Sopenharmony_ci if (event == MPI2_EVENT_LOG_ENTRY_ADDED || 3768c2ecf20Sopenharmony_ci (send_aen && !ioc->aen_event_read_flag)) { 3778c2ecf20Sopenharmony_ci ioc->aen_event_read_flag = 1; 3788c2ecf20Sopenharmony_ci wake_up_interruptible(&ctl_poll_wait); 3798c2ecf20Sopenharmony_ci if (async_queue) 3808c2ecf20Sopenharmony_ci kill_fasync(&async_queue, SIGIO, POLL_IN); 3818c2ecf20Sopenharmony_ci } 3828c2ecf20Sopenharmony_ci} 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci/** 3858c2ecf20Sopenharmony_ci * mpt3sas_ctl_event_callback - firmware event handler (called at ISR time) 3868c2ecf20Sopenharmony_ci * @ioc: per adapter object 3878c2ecf20Sopenharmony_ci * @msix_index: MSIX table index supplied by the OS 3888c2ecf20Sopenharmony_ci * @reply: reply message frame(lower 32bit addr) 3898c2ecf20Sopenharmony_ci * Context: interrupt. 3908c2ecf20Sopenharmony_ci * 3918c2ecf20Sopenharmony_ci * This function merely adds a new work task into ioc->firmware_event_thread. 3928c2ecf20Sopenharmony_ci * The tasks are worked from _firmware_event_work in user context. 3938c2ecf20Sopenharmony_ci * 3948c2ecf20Sopenharmony_ci * Return: 1 meaning mf should be freed from _base_interrupt 3958c2ecf20Sopenharmony_ci * 0 means the mf is freed from this function. 3968c2ecf20Sopenharmony_ci */ 3978c2ecf20Sopenharmony_ciu8 3988c2ecf20Sopenharmony_cimpt3sas_ctl_event_callback(struct MPT3SAS_ADAPTER *ioc, u8 msix_index, 3998c2ecf20Sopenharmony_ci u32 reply) 4008c2ecf20Sopenharmony_ci{ 4018c2ecf20Sopenharmony_ci Mpi2EventNotificationReply_t *mpi_reply; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci mpi_reply = mpt3sas_base_get_reply_virt_addr(ioc, reply); 4048c2ecf20Sopenharmony_ci if (mpi_reply) 4058c2ecf20Sopenharmony_ci mpt3sas_ctl_add_to_event_log(ioc, mpi_reply); 4068c2ecf20Sopenharmony_ci return 1; 4078c2ecf20Sopenharmony_ci} 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci/** 4108c2ecf20Sopenharmony_ci * _ctl_verify_adapter - validates ioc_number passed from application 4118c2ecf20Sopenharmony_ci * @ioc_number: ? 4128c2ecf20Sopenharmony_ci * @iocpp: The ioc pointer is returned in this. 4138c2ecf20Sopenharmony_ci * @mpi_version: will be MPI2_VERSION for mpt2ctl ioctl device & 4148c2ecf20Sopenharmony_ci * MPI25_VERSION | MPI26_VERSION for mpt3ctl ioctl device. 4158c2ecf20Sopenharmony_ci * 4168c2ecf20Sopenharmony_ci * Return: (-1) means error, else ioc_number. 4178c2ecf20Sopenharmony_ci */ 4188c2ecf20Sopenharmony_cistatic int 4198c2ecf20Sopenharmony_ci_ctl_verify_adapter(int ioc_number, struct MPT3SAS_ADAPTER **iocpp, 4208c2ecf20Sopenharmony_ci int mpi_version) 4218c2ecf20Sopenharmony_ci{ 4228c2ecf20Sopenharmony_ci struct MPT3SAS_ADAPTER *ioc; 4238c2ecf20Sopenharmony_ci int version = 0; 4248c2ecf20Sopenharmony_ci /* global ioc lock to protect controller on list operations */ 4258c2ecf20Sopenharmony_ci spin_lock(&gioc_lock); 4268c2ecf20Sopenharmony_ci list_for_each_entry(ioc, &mpt3sas_ioc_list, list) { 4278c2ecf20Sopenharmony_ci if (ioc->id != ioc_number) 4288c2ecf20Sopenharmony_ci continue; 4298c2ecf20Sopenharmony_ci /* Check whether this ioctl command is from right 4308c2ecf20Sopenharmony_ci * ioctl device or not, if not continue the search. 4318c2ecf20Sopenharmony_ci */ 4328c2ecf20Sopenharmony_ci version = ioc->hba_mpi_version_belonged; 4338c2ecf20Sopenharmony_ci /* MPI25_VERSION and MPI26_VERSION uses same ioctl 4348c2ecf20Sopenharmony_ci * device. 4358c2ecf20Sopenharmony_ci */ 4368c2ecf20Sopenharmony_ci if (mpi_version == (MPI25_VERSION | MPI26_VERSION)) { 4378c2ecf20Sopenharmony_ci if ((version == MPI25_VERSION) || 4388c2ecf20Sopenharmony_ci (version == MPI26_VERSION)) 4398c2ecf20Sopenharmony_ci goto out; 4408c2ecf20Sopenharmony_ci else 4418c2ecf20Sopenharmony_ci continue; 4428c2ecf20Sopenharmony_ci } else { 4438c2ecf20Sopenharmony_ci if (version != mpi_version) 4448c2ecf20Sopenharmony_ci continue; 4458c2ecf20Sopenharmony_ci } 4468c2ecf20Sopenharmony_ciout: 4478c2ecf20Sopenharmony_ci spin_unlock(&gioc_lock); 4488c2ecf20Sopenharmony_ci *iocpp = ioc; 4498c2ecf20Sopenharmony_ci return ioc_number; 4508c2ecf20Sopenharmony_ci } 4518c2ecf20Sopenharmony_ci spin_unlock(&gioc_lock); 4528c2ecf20Sopenharmony_ci *iocpp = NULL; 4538c2ecf20Sopenharmony_ci return -1; 4548c2ecf20Sopenharmony_ci} 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci/** 4578c2ecf20Sopenharmony_ci * mpt3sas_ctl_reset_handler - reset callback handler (for ctl) 4588c2ecf20Sopenharmony_ci * @ioc: per adapter object 4598c2ecf20Sopenharmony_ci * 4608c2ecf20Sopenharmony_ci * The handler for doing any required cleanup or initialization. 4618c2ecf20Sopenharmony_ci */ 4628c2ecf20Sopenharmony_civoid mpt3sas_ctl_pre_reset_handler(struct MPT3SAS_ADAPTER *ioc) 4638c2ecf20Sopenharmony_ci{ 4648c2ecf20Sopenharmony_ci int i; 4658c2ecf20Sopenharmony_ci u8 issue_reset; 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci dtmprintk(ioc, ioc_info(ioc, "%s: MPT3_IOC_PRE_RESET\n", __func__)); 4688c2ecf20Sopenharmony_ci for (i = 0; i < MPI2_DIAG_BUF_TYPE_COUNT; i++) { 4698c2ecf20Sopenharmony_ci if (!(ioc->diag_buffer_status[i] & 4708c2ecf20Sopenharmony_ci MPT3_DIAG_BUFFER_IS_REGISTERED)) 4718c2ecf20Sopenharmony_ci continue; 4728c2ecf20Sopenharmony_ci if ((ioc->diag_buffer_status[i] & 4738c2ecf20Sopenharmony_ci MPT3_DIAG_BUFFER_IS_RELEASED)) 4748c2ecf20Sopenharmony_ci continue; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci /* 4778c2ecf20Sopenharmony_ci * add a log message to indicate the release 4788c2ecf20Sopenharmony_ci */ 4798c2ecf20Sopenharmony_ci ioc_info(ioc, 4808c2ecf20Sopenharmony_ci "%s: Releasing the trace buffer due to adapter reset.", 4818c2ecf20Sopenharmony_ci __func__); 4828c2ecf20Sopenharmony_ci mpt3sas_send_diag_release(ioc, i, &issue_reset); 4838c2ecf20Sopenharmony_ci } 4848c2ecf20Sopenharmony_ci} 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci/** 4878c2ecf20Sopenharmony_ci * mpt3sas_ctl_reset_handler - clears outstanding ioctl cmd. 4888c2ecf20Sopenharmony_ci * @ioc: per adapter object 4898c2ecf20Sopenharmony_ci * 4908c2ecf20Sopenharmony_ci * The handler for doing any required cleanup or initialization. 4918c2ecf20Sopenharmony_ci */ 4928c2ecf20Sopenharmony_civoid mpt3sas_ctl_clear_outstanding_ioctls(struct MPT3SAS_ADAPTER *ioc) 4938c2ecf20Sopenharmony_ci{ 4948c2ecf20Sopenharmony_ci dtmprintk(ioc, 4958c2ecf20Sopenharmony_ci ioc_info(ioc, "%s: clear outstanding ioctl cmd\n", __func__)); 4968c2ecf20Sopenharmony_ci if (ioc->ctl_cmds.status & MPT3_CMD_PENDING) { 4978c2ecf20Sopenharmony_ci ioc->ctl_cmds.status |= MPT3_CMD_RESET; 4988c2ecf20Sopenharmony_ci mpt3sas_base_free_smid(ioc, ioc->ctl_cmds.smid); 4998c2ecf20Sopenharmony_ci complete(&ioc->ctl_cmds.done); 5008c2ecf20Sopenharmony_ci } 5018c2ecf20Sopenharmony_ci} 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci/** 5048c2ecf20Sopenharmony_ci * mpt3sas_ctl_reset_handler - reset callback handler (for ctl) 5058c2ecf20Sopenharmony_ci * @ioc: per adapter object 5068c2ecf20Sopenharmony_ci * 5078c2ecf20Sopenharmony_ci * The handler for doing any required cleanup or initialization. 5088c2ecf20Sopenharmony_ci */ 5098c2ecf20Sopenharmony_civoid mpt3sas_ctl_reset_done_handler(struct MPT3SAS_ADAPTER *ioc) 5108c2ecf20Sopenharmony_ci{ 5118c2ecf20Sopenharmony_ci int i; 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci dtmprintk(ioc, ioc_info(ioc, "%s: MPT3_IOC_DONE_RESET\n", __func__)); 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci for (i = 0; i < MPI2_DIAG_BUF_TYPE_COUNT; i++) { 5168c2ecf20Sopenharmony_ci if (!(ioc->diag_buffer_status[i] & 5178c2ecf20Sopenharmony_ci MPT3_DIAG_BUFFER_IS_REGISTERED)) 5188c2ecf20Sopenharmony_ci continue; 5198c2ecf20Sopenharmony_ci if ((ioc->diag_buffer_status[i] & 5208c2ecf20Sopenharmony_ci MPT3_DIAG_BUFFER_IS_RELEASED)) 5218c2ecf20Sopenharmony_ci continue; 5228c2ecf20Sopenharmony_ci ioc->diag_buffer_status[i] |= 5238c2ecf20Sopenharmony_ci MPT3_DIAG_BUFFER_IS_DIAG_RESET; 5248c2ecf20Sopenharmony_ci } 5258c2ecf20Sopenharmony_ci} 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci/** 5288c2ecf20Sopenharmony_ci * _ctl_fasync - 5298c2ecf20Sopenharmony_ci * @fd: ? 5308c2ecf20Sopenharmony_ci * @filep: ? 5318c2ecf20Sopenharmony_ci * @mode: ? 5328c2ecf20Sopenharmony_ci * 5338c2ecf20Sopenharmony_ci * Called when application request fasyn callback handler. 5348c2ecf20Sopenharmony_ci */ 5358c2ecf20Sopenharmony_cistatic int 5368c2ecf20Sopenharmony_ci_ctl_fasync(int fd, struct file *filep, int mode) 5378c2ecf20Sopenharmony_ci{ 5388c2ecf20Sopenharmony_ci return fasync_helper(fd, filep, mode, &async_queue); 5398c2ecf20Sopenharmony_ci} 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci/** 5428c2ecf20Sopenharmony_ci * _ctl_poll - 5438c2ecf20Sopenharmony_ci * @filep: ? 5448c2ecf20Sopenharmony_ci * @wait: ? 5458c2ecf20Sopenharmony_ci * 5468c2ecf20Sopenharmony_ci */ 5478c2ecf20Sopenharmony_cistatic __poll_t 5488c2ecf20Sopenharmony_ci_ctl_poll(struct file *filep, poll_table *wait) 5498c2ecf20Sopenharmony_ci{ 5508c2ecf20Sopenharmony_ci struct MPT3SAS_ADAPTER *ioc; 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci poll_wait(filep, &ctl_poll_wait, wait); 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci /* global ioc lock to protect controller on list operations */ 5558c2ecf20Sopenharmony_ci spin_lock(&gioc_lock); 5568c2ecf20Sopenharmony_ci list_for_each_entry(ioc, &mpt3sas_ioc_list, list) { 5578c2ecf20Sopenharmony_ci if (ioc->aen_event_read_flag) { 5588c2ecf20Sopenharmony_ci spin_unlock(&gioc_lock); 5598c2ecf20Sopenharmony_ci return EPOLLIN | EPOLLRDNORM; 5608c2ecf20Sopenharmony_ci } 5618c2ecf20Sopenharmony_ci } 5628c2ecf20Sopenharmony_ci spin_unlock(&gioc_lock); 5638c2ecf20Sopenharmony_ci return 0; 5648c2ecf20Sopenharmony_ci} 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci/** 5678c2ecf20Sopenharmony_ci * _ctl_set_task_mid - assign an active smid to tm request 5688c2ecf20Sopenharmony_ci * @ioc: per adapter object 5698c2ecf20Sopenharmony_ci * @karg: (struct mpt3_ioctl_command) 5708c2ecf20Sopenharmony_ci * @tm_request: pointer to mf from user space 5718c2ecf20Sopenharmony_ci * 5728c2ecf20Sopenharmony_ci * Return: 0 when an smid if found, else fail. 5738c2ecf20Sopenharmony_ci * during failure, the reply frame is filled. 5748c2ecf20Sopenharmony_ci */ 5758c2ecf20Sopenharmony_cistatic int 5768c2ecf20Sopenharmony_ci_ctl_set_task_mid(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command *karg, 5778c2ecf20Sopenharmony_ci Mpi2SCSITaskManagementRequest_t *tm_request) 5788c2ecf20Sopenharmony_ci{ 5798c2ecf20Sopenharmony_ci u8 found = 0; 5808c2ecf20Sopenharmony_ci u16 smid; 5818c2ecf20Sopenharmony_ci u16 handle; 5828c2ecf20Sopenharmony_ci struct scsi_cmnd *scmd; 5838c2ecf20Sopenharmony_ci struct MPT3SAS_DEVICE *priv_data; 5848c2ecf20Sopenharmony_ci Mpi2SCSITaskManagementReply_t *tm_reply; 5858c2ecf20Sopenharmony_ci u32 sz; 5868c2ecf20Sopenharmony_ci u32 lun; 5878c2ecf20Sopenharmony_ci char *desc = NULL; 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci if (tm_request->TaskType == MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK) 5908c2ecf20Sopenharmony_ci desc = "abort_task"; 5918c2ecf20Sopenharmony_ci else if (tm_request->TaskType == MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK) 5928c2ecf20Sopenharmony_ci desc = "query_task"; 5938c2ecf20Sopenharmony_ci else 5948c2ecf20Sopenharmony_ci return 0; 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci lun = scsilun_to_int((struct scsi_lun *)tm_request->LUN); 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci handle = le16_to_cpu(tm_request->DevHandle); 5998c2ecf20Sopenharmony_ci for (smid = ioc->scsiio_depth; smid && !found; smid--) { 6008c2ecf20Sopenharmony_ci struct scsiio_tracker *st; 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci scmd = mpt3sas_scsih_scsi_lookup_get(ioc, smid); 6038c2ecf20Sopenharmony_ci if (!scmd) 6048c2ecf20Sopenharmony_ci continue; 6058c2ecf20Sopenharmony_ci if (lun != scmd->device->lun) 6068c2ecf20Sopenharmony_ci continue; 6078c2ecf20Sopenharmony_ci priv_data = scmd->device->hostdata; 6088c2ecf20Sopenharmony_ci if (priv_data->sas_target == NULL) 6098c2ecf20Sopenharmony_ci continue; 6108c2ecf20Sopenharmony_ci if (priv_data->sas_target->handle != handle) 6118c2ecf20Sopenharmony_ci continue; 6128c2ecf20Sopenharmony_ci st = scsi_cmd_priv(scmd); 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci /* 6158c2ecf20Sopenharmony_ci * If the given TaskMID from the user space is zero, then the 6168c2ecf20Sopenharmony_ci * first outstanding smid will be picked up. Otherwise, 6178c2ecf20Sopenharmony_ci * targeted smid will be the one. 6188c2ecf20Sopenharmony_ci */ 6198c2ecf20Sopenharmony_ci if (!tm_request->TaskMID || tm_request->TaskMID == st->smid) { 6208c2ecf20Sopenharmony_ci tm_request->TaskMID = cpu_to_le16(st->smid); 6218c2ecf20Sopenharmony_ci found = 1; 6228c2ecf20Sopenharmony_ci } 6238c2ecf20Sopenharmony_ci } 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci if (!found) { 6268c2ecf20Sopenharmony_ci dctlprintk(ioc, 6278c2ecf20Sopenharmony_ci ioc_info(ioc, "%s: handle(0x%04x), lun(%d), no active mid!!\n", 6288c2ecf20Sopenharmony_ci desc, le16_to_cpu(tm_request->DevHandle), 6298c2ecf20Sopenharmony_ci lun)); 6308c2ecf20Sopenharmony_ci tm_reply = ioc->ctl_cmds.reply; 6318c2ecf20Sopenharmony_ci tm_reply->DevHandle = tm_request->DevHandle; 6328c2ecf20Sopenharmony_ci tm_reply->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; 6338c2ecf20Sopenharmony_ci tm_reply->TaskType = tm_request->TaskType; 6348c2ecf20Sopenharmony_ci tm_reply->MsgLength = sizeof(Mpi2SCSITaskManagementReply_t)/4; 6358c2ecf20Sopenharmony_ci tm_reply->VP_ID = tm_request->VP_ID; 6368c2ecf20Sopenharmony_ci tm_reply->VF_ID = tm_request->VF_ID; 6378c2ecf20Sopenharmony_ci sz = min_t(u32, karg->max_reply_bytes, ioc->reply_sz); 6388c2ecf20Sopenharmony_ci if (copy_to_user(karg->reply_frame_buf_ptr, ioc->ctl_cmds.reply, 6398c2ecf20Sopenharmony_ci sz)) 6408c2ecf20Sopenharmony_ci pr_err("failure at %s:%d/%s()!\n", __FILE__, 6418c2ecf20Sopenharmony_ci __LINE__, __func__); 6428c2ecf20Sopenharmony_ci return 1; 6438c2ecf20Sopenharmony_ci } 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci dctlprintk(ioc, 6468c2ecf20Sopenharmony_ci ioc_info(ioc, "%s: handle(0x%04x), lun(%d), task_mid(%d)\n", 6478c2ecf20Sopenharmony_ci desc, le16_to_cpu(tm_request->DevHandle), lun, 6488c2ecf20Sopenharmony_ci le16_to_cpu(tm_request->TaskMID))); 6498c2ecf20Sopenharmony_ci return 0; 6508c2ecf20Sopenharmony_ci} 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci/** 6538c2ecf20Sopenharmony_ci * _ctl_do_mpt_command - main handler for MPT3COMMAND opcode 6548c2ecf20Sopenharmony_ci * @ioc: per adapter object 6558c2ecf20Sopenharmony_ci * @karg: (struct mpt3_ioctl_command) 6568c2ecf20Sopenharmony_ci * @mf: pointer to mf in user space 6578c2ecf20Sopenharmony_ci */ 6588c2ecf20Sopenharmony_cistatic long 6598c2ecf20Sopenharmony_ci_ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg, 6608c2ecf20Sopenharmony_ci void __user *mf) 6618c2ecf20Sopenharmony_ci{ 6628c2ecf20Sopenharmony_ci MPI2RequestHeader_t *mpi_request = NULL, *request; 6638c2ecf20Sopenharmony_ci MPI2DefaultReply_t *mpi_reply; 6648c2ecf20Sopenharmony_ci Mpi26NVMeEncapsulatedRequest_t *nvme_encap_request = NULL; 6658c2ecf20Sopenharmony_ci struct _pcie_device *pcie_device = NULL; 6668c2ecf20Sopenharmony_ci u16 smid; 6678c2ecf20Sopenharmony_ci unsigned long timeout; 6688c2ecf20Sopenharmony_ci u8 issue_reset; 6698c2ecf20Sopenharmony_ci u32 sz, sz_arg; 6708c2ecf20Sopenharmony_ci void *psge; 6718c2ecf20Sopenharmony_ci void *data_out = NULL; 6728c2ecf20Sopenharmony_ci dma_addr_t data_out_dma = 0; 6738c2ecf20Sopenharmony_ci size_t data_out_sz = 0; 6748c2ecf20Sopenharmony_ci void *data_in = NULL; 6758c2ecf20Sopenharmony_ci dma_addr_t data_in_dma = 0; 6768c2ecf20Sopenharmony_ci size_t data_in_sz = 0; 6778c2ecf20Sopenharmony_ci long ret; 6788c2ecf20Sopenharmony_ci u16 device_handle = MPT3SAS_INVALID_DEVICE_HANDLE; 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci issue_reset = 0; 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci if (ioc->ctl_cmds.status != MPT3_CMD_NOT_USED) { 6838c2ecf20Sopenharmony_ci ioc_err(ioc, "%s: ctl_cmd in use\n", __func__); 6848c2ecf20Sopenharmony_ci ret = -EAGAIN; 6858c2ecf20Sopenharmony_ci goto out; 6868c2ecf20Sopenharmony_ci } 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci ret = mpt3sas_wait_for_ioc(ioc, IOC_OPERATIONAL_WAIT_COUNT); 6898c2ecf20Sopenharmony_ci if (ret) 6908c2ecf20Sopenharmony_ci goto out; 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci mpi_request = kzalloc(ioc->request_sz, GFP_KERNEL); 6938c2ecf20Sopenharmony_ci if (!mpi_request) { 6948c2ecf20Sopenharmony_ci ioc_err(ioc, "%s: failed obtaining a memory for mpi_request\n", 6958c2ecf20Sopenharmony_ci __func__); 6968c2ecf20Sopenharmony_ci ret = -ENOMEM; 6978c2ecf20Sopenharmony_ci goto out; 6988c2ecf20Sopenharmony_ci } 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci /* Check for overflow and wraparound */ 7018c2ecf20Sopenharmony_ci if (karg.data_sge_offset * 4 > ioc->request_sz || 7028c2ecf20Sopenharmony_ci karg.data_sge_offset > (UINT_MAX / 4)) { 7038c2ecf20Sopenharmony_ci ret = -EINVAL; 7048c2ecf20Sopenharmony_ci goto out; 7058c2ecf20Sopenharmony_ci } 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci /* copy in request message frame from user */ 7088c2ecf20Sopenharmony_ci if (copy_from_user(mpi_request, mf, karg.data_sge_offset*4)) { 7098c2ecf20Sopenharmony_ci pr_err("failure at %s:%d/%s()!\n", __FILE__, __LINE__, 7108c2ecf20Sopenharmony_ci __func__); 7118c2ecf20Sopenharmony_ci ret = -EFAULT; 7128c2ecf20Sopenharmony_ci goto out; 7138c2ecf20Sopenharmony_ci } 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci if (mpi_request->Function == MPI2_FUNCTION_SCSI_TASK_MGMT) { 7168c2ecf20Sopenharmony_ci smid = mpt3sas_base_get_smid_hpr(ioc, ioc->ctl_cb_idx); 7178c2ecf20Sopenharmony_ci if (!smid) { 7188c2ecf20Sopenharmony_ci ioc_err(ioc, "%s: failed obtaining a smid\n", __func__); 7198c2ecf20Sopenharmony_ci ret = -EAGAIN; 7208c2ecf20Sopenharmony_ci goto out; 7218c2ecf20Sopenharmony_ci } 7228c2ecf20Sopenharmony_ci } else { 7238c2ecf20Sopenharmony_ci /* Use first reserved smid for passthrough ioctls */ 7248c2ecf20Sopenharmony_ci smid = ioc->scsiio_depth - INTERNAL_SCSIIO_CMDS_COUNT + 1; 7258c2ecf20Sopenharmony_ci } 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci ret = 0; 7288c2ecf20Sopenharmony_ci ioc->ctl_cmds.status = MPT3_CMD_PENDING; 7298c2ecf20Sopenharmony_ci memset(ioc->ctl_cmds.reply, 0, ioc->reply_sz); 7308c2ecf20Sopenharmony_ci request = mpt3sas_base_get_msg_frame(ioc, smid); 7318c2ecf20Sopenharmony_ci memset(request, 0, ioc->request_sz); 7328c2ecf20Sopenharmony_ci memcpy(request, mpi_request, karg.data_sge_offset*4); 7338c2ecf20Sopenharmony_ci ioc->ctl_cmds.smid = smid; 7348c2ecf20Sopenharmony_ci data_out_sz = karg.data_out_size; 7358c2ecf20Sopenharmony_ci data_in_sz = karg.data_in_size; 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci if (mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST || 7388c2ecf20Sopenharmony_ci mpi_request->Function == MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH || 7398c2ecf20Sopenharmony_ci mpi_request->Function == MPI2_FUNCTION_SCSI_TASK_MGMT || 7408c2ecf20Sopenharmony_ci mpi_request->Function == MPI2_FUNCTION_SATA_PASSTHROUGH || 7418c2ecf20Sopenharmony_ci mpi_request->Function == MPI2_FUNCTION_NVME_ENCAPSULATED) { 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci device_handle = le16_to_cpu(mpi_request->FunctionDependent1); 7448c2ecf20Sopenharmony_ci if (!device_handle || (device_handle > 7458c2ecf20Sopenharmony_ci ioc->facts.MaxDevHandle)) { 7468c2ecf20Sopenharmony_ci ret = -EINVAL; 7478c2ecf20Sopenharmony_ci mpt3sas_base_free_smid(ioc, smid); 7488c2ecf20Sopenharmony_ci goto out; 7498c2ecf20Sopenharmony_ci } 7508c2ecf20Sopenharmony_ci } 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci /* obtain dma-able memory for data transfer */ 7538c2ecf20Sopenharmony_ci if (data_out_sz) /* WRITE */ { 7548c2ecf20Sopenharmony_ci data_out = dma_alloc_coherent(&ioc->pdev->dev, data_out_sz, 7558c2ecf20Sopenharmony_ci &data_out_dma, GFP_KERNEL); 7568c2ecf20Sopenharmony_ci if (!data_out) { 7578c2ecf20Sopenharmony_ci pr_err("failure at %s:%d/%s()!\n", __FILE__, 7588c2ecf20Sopenharmony_ci __LINE__, __func__); 7598c2ecf20Sopenharmony_ci ret = -ENOMEM; 7608c2ecf20Sopenharmony_ci mpt3sas_base_free_smid(ioc, smid); 7618c2ecf20Sopenharmony_ci goto out; 7628c2ecf20Sopenharmony_ci } 7638c2ecf20Sopenharmony_ci if (copy_from_user(data_out, karg.data_out_buf_ptr, 7648c2ecf20Sopenharmony_ci data_out_sz)) { 7658c2ecf20Sopenharmony_ci pr_err("failure at %s:%d/%s()!\n", __FILE__, 7668c2ecf20Sopenharmony_ci __LINE__, __func__); 7678c2ecf20Sopenharmony_ci ret = -EFAULT; 7688c2ecf20Sopenharmony_ci mpt3sas_base_free_smid(ioc, smid); 7698c2ecf20Sopenharmony_ci goto out; 7708c2ecf20Sopenharmony_ci } 7718c2ecf20Sopenharmony_ci } 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci if (data_in_sz) /* READ */ { 7748c2ecf20Sopenharmony_ci data_in = dma_alloc_coherent(&ioc->pdev->dev, data_in_sz, 7758c2ecf20Sopenharmony_ci &data_in_dma, GFP_KERNEL); 7768c2ecf20Sopenharmony_ci if (!data_in) { 7778c2ecf20Sopenharmony_ci pr_err("failure at %s:%d/%s()!\n", __FILE__, 7788c2ecf20Sopenharmony_ci __LINE__, __func__); 7798c2ecf20Sopenharmony_ci ret = -ENOMEM; 7808c2ecf20Sopenharmony_ci mpt3sas_base_free_smid(ioc, smid); 7818c2ecf20Sopenharmony_ci goto out; 7828c2ecf20Sopenharmony_ci } 7838c2ecf20Sopenharmony_ci } 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci psge = (void *)request + (karg.data_sge_offset*4); 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci /* send command to firmware */ 7888c2ecf20Sopenharmony_ci _ctl_display_some_debug(ioc, smid, "ctl_request", NULL); 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci init_completion(&ioc->ctl_cmds.done); 7918c2ecf20Sopenharmony_ci switch (mpi_request->Function) { 7928c2ecf20Sopenharmony_ci case MPI2_FUNCTION_NVME_ENCAPSULATED: 7938c2ecf20Sopenharmony_ci { 7948c2ecf20Sopenharmony_ci nvme_encap_request = (Mpi26NVMeEncapsulatedRequest_t *)request; 7958c2ecf20Sopenharmony_ci if (!ioc->pcie_sg_lookup) { 7968c2ecf20Sopenharmony_ci dtmprintk(ioc, ioc_info(ioc, 7978c2ecf20Sopenharmony_ci "HBA doesn't support NVMe. Rejecting NVMe Encapsulated request.\n" 7988c2ecf20Sopenharmony_ci )); 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci if (ioc->logging_level & MPT_DEBUG_TM) 8018c2ecf20Sopenharmony_ci _debug_dump_mf(nvme_encap_request, 8028c2ecf20Sopenharmony_ci ioc->request_sz/4); 8038c2ecf20Sopenharmony_ci mpt3sas_base_free_smid(ioc, smid); 8048c2ecf20Sopenharmony_ci ret = -EINVAL; 8058c2ecf20Sopenharmony_ci goto out; 8068c2ecf20Sopenharmony_ci } 8078c2ecf20Sopenharmony_ci /* 8088c2ecf20Sopenharmony_ci * Get the Physical Address of the sense buffer. 8098c2ecf20Sopenharmony_ci * Use Error Response buffer address field to hold the sense 8108c2ecf20Sopenharmony_ci * buffer address. 8118c2ecf20Sopenharmony_ci * Clear the internal sense buffer, which will potentially hold 8128c2ecf20Sopenharmony_ci * the Completion Queue Entry on return, or 0 if no Entry. 8138c2ecf20Sopenharmony_ci * Build the PRPs and set direction bits. 8148c2ecf20Sopenharmony_ci * Send the request. 8158c2ecf20Sopenharmony_ci */ 8168c2ecf20Sopenharmony_ci nvme_encap_request->ErrorResponseBaseAddress = 8178c2ecf20Sopenharmony_ci cpu_to_le64(ioc->sense_dma & 0xFFFFFFFF00000000UL); 8188c2ecf20Sopenharmony_ci nvme_encap_request->ErrorResponseBaseAddress |= 8198c2ecf20Sopenharmony_ci cpu_to_le64(le32_to_cpu( 8208c2ecf20Sopenharmony_ci mpt3sas_base_get_sense_buffer_dma(ioc, smid))); 8218c2ecf20Sopenharmony_ci nvme_encap_request->ErrorResponseAllocationLength = 8228c2ecf20Sopenharmony_ci cpu_to_le16(NVME_ERROR_RESPONSE_SIZE); 8238c2ecf20Sopenharmony_ci memset(ioc->ctl_cmds.sense, 0, NVME_ERROR_RESPONSE_SIZE); 8248c2ecf20Sopenharmony_ci ioc->build_nvme_prp(ioc, smid, nvme_encap_request, 8258c2ecf20Sopenharmony_ci data_out_dma, data_out_sz, data_in_dma, data_in_sz); 8268c2ecf20Sopenharmony_ci if (test_bit(device_handle, ioc->device_remove_in_progress)) { 8278c2ecf20Sopenharmony_ci dtmprintk(ioc, 8288c2ecf20Sopenharmony_ci ioc_info(ioc, "handle(0x%04x): ioctl failed due to device removal in progress\n", 8298c2ecf20Sopenharmony_ci device_handle)); 8308c2ecf20Sopenharmony_ci mpt3sas_base_free_smid(ioc, smid); 8318c2ecf20Sopenharmony_ci ret = -EINVAL; 8328c2ecf20Sopenharmony_ci goto out; 8338c2ecf20Sopenharmony_ci } 8348c2ecf20Sopenharmony_ci mpt3sas_base_put_smid_nvme_encap(ioc, smid); 8358c2ecf20Sopenharmony_ci break; 8368c2ecf20Sopenharmony_ci } 8378c2ecf20Sopenharmony_ci case MPI2_FUNCTION_SCSI_IO_REQUEST: 8388c2ecf20Sopenharmony_ci case MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH: 8398c2ecf20Sopenharmony_ci { 8408c2ecf20Sopenharmony_ci Mpi2SCSIIORequest_t *scsiio_request = 8418c2ecf20Sopenharmony_ci (Mpi2SCSIIORequest_t *)request; 8428c2ecf20Sopenharmony_ci scsiio_request->SenseBufferLength = SCSI_SENSE_BUFFERSIZE; 8438c2ecf20Sopenharmony_ci scsiio_request->SenseBufferLowAddress = 8448c2ecf20Sopenharmony_ci mpt3sas_base_get_sense_buffer_dma(ioc, smid); 8458c2ecf20Sopenharmony_ci memset(ioc->ctl_cmds.sense, 0, SCSI_SENSE_BUFFERSIZE); 8468c2ecf20Sopenharmony_ci if (test_bit(device_handle, ioc->device_remove_in_progress)) { 8478c2ecf20Sopenharmony_ci dtmprintk(ioc, 8488c2ecf20Sopenharmony_ci ioc_info(ioc, "handle(0x%04x) :ioctl failed due to device removal in progress\n", 8498c2ecf20Sopenharmony_ci device_handle)); 8508c2ecf20Sopenharmony_ci mpt3sas_base_free_smid(ioc, smid); 8518c2ecf20Sopenharmony_ci ret = -EINVAL; 8528c2ecf20Sopenharmony_ci goto out; 8538c2ecf20Sopenharmony_ci } 8548c2ecf20Sopenharmony_ci ioc->build_sg(ioc, psge, data_out_dma, data_out_sz, 8558c2ecf20Sopenharmony_ci data_in_dma, data_in_sz); 8568c2ecf20Sopenharmony_ci if (mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST) 8578c2ecf20Sopenharmony_ci ioc->put_smid_scsi_io(ioc, smid, device_handle); 8588c2ecf20Sopenharmony_ci else 8598c2ecf20Sopenharmony_ci ioc->put_smid_default(ioc, smid); 8608c2ecf20Sopenharmony_ci break; 8618c2ecf20Sopenharmony_ci } 8628c2ecf20Sopenharmony_ci case MPI2_FUNCTION_SCSI_TASK_MGMT: 8638c2ecf20Sopenharmony_ci { 8648c2ecf20Sopenharmony_ci Mpi2SCSITaskManagementRequest_t *tm_request = 8658c2ecf20Sopenharmony_ci (Mpi2SCSITaskManagementRequest_t *)request; 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_ci dtmprintk(ioc, 8688c2ecf20Sopenharmony_ci ioc_info(ioc, "TASK_MGMT: handle(0x%04x), task_type(0x%02x)\n", 8698c2ecf20Sopenharmony_ci le16_to_cpu(tm_request->DevHandle), 8708c2ecf20Sopenharmony_ci tm_request->TaskType)); 8718c2ecf20Sopenharmony_ci ioc->got_task_abort_from_ioctl = 1; 8728c2ecf20Sopenharmony_ci if (tm_request->TaskType == 8738c2ecf20Sopenharmony_ci MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK || 8748c2ecf20Sopenharmony_ci tm_request->TaskType == 8758c2ecf20Sopenharmony_ci MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK) { 8768c2ecf20Sopenharmony_ci if (_ctl_set_task_mid(ioc, &karg, tm_request)) { 8778c2ecf20Sopenharmony_ci mpt3sas_base_free_smid(ioc, smid); 8788c2ecf20Sopenharmony_ci ioc->got_task_abort_from_ioctl = 0; 8798c2ecf20Sopenharmony_ci goto out; 8808c2ecf20Sopenharmony_ci } 8818c2ecf20Sopenharmony_ci } 8828c2ecf20Sopenharmony_ci ioc->got_task_abort_from_ioctl = 0; 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci if (test_bit(device_handle, ioc->device_remove_in_progress)) { 8858c2ecf20Sopenharmony_ci dtmprintk(ioc, 8868c2ecf20Sopenharmony_ci ioc_info(ioc, "handle(0x%04x) :ioctl failed due to device removal in progress\n", 8878c2ecf20Sopenharmony_ci device_handle)); 8888c2ecf20Sopenharmony_ci mpt3sas_base_free_smid(ioc, smid); 8898c2ecf20Sopenharmony_ci ret = -EINVAL; 8908c2ecf20Sopenharmony_ci goto out; 8918c2ecf20Sopenharmony_ci } 8928c2ecf20Sopenharmony_ci mpt3sas_scsih_set_tm_flag(ioc, le16_to_cpu( 8938c2ecf20Sopenharmony_ci tm_request->DevHandle)); 8948c2ecf20Sopenharmony_ci ioc->build_sg_mpi(ioc, psge, data_out_dma, data_out_sz, 8958c2ecf20Sopenharmony_ci data_in_dma, data_in_sz); 8968c2ecf20Sopenharmony_ci ioc->put_smid_hi_priority(ioc, smid, 0); 8978c2ecf20Sopenharmony_ci break; 8988c2ecf20Sopenharmony_ci } 8998c2ecf20Sopenharmony_ci case MPI2_FUNCTION_SMP_PASSTHROUGH: 9008c2ecf20Sopenharmony_ci { 9018c2ecf20Sopenharmony_ci Mpi2SmpPassthroughRequest_t *smp_request = 9028c2ecf20Sopenharmony_ci (Mpi2SmpPassthroughRequest_t *)mpi_request; 9038c2ecf20Sopenharmony_ci u8 *data; 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci /* ioc determines which port to use */ 9068c2ecf20Sopenharmony_ci smp_request->PhysicalPort = 0xFF; 9078c2ecf20Sopenharmony_ci if (smp_request->PassthroughFlags & 9088c2ecf20Sopenharmony_ci MPI2_SMP_PT_REQ_PT_FLAGS_IMMEDIATE) 9098c2ecf20Sopenharmony_ci data = (u8 *)&smp_request->SGL; 9108c2ecf20Sopenharmony_ci else { 9118c2ecf20Sopenharmony_ci if (unlikely(data_out == NULL)) { 9128c2ecf20Sopenharmony_ci pr_err("failure at %s:%d/%s()!\n", 9138c2ecf20Sopenharmony_ci __FILE__, __LINE__, __func__); 9148c2ecf20Sopenharmony_ci mpt3sas_base_free_smid(ioc, smid); 9158c2ecf20Sopenharmony_ci ret = -EINVAL; 9168c2ecf20Sopenharmony_ci goto out; 9178c2ecf20Sopenharmony_ci } 9188c2ecf20Sopenharmony_ci data = data_out; 9198c2ecf20Sopenharmony_ci } 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ci if (data[1] == 0x91 && (data[10] == 1 || data[10] == 2)) { 9228c2ecf20Sopenharmony_ci ioc->ioc_link_reset_in_progress = 1; 9238c2ecf20Sopenharmony_ci ioc->ignore_loginfos = 1; 9248c2ecf20Sopenharmony_ci } 9258c2ecf20Sopenharmony_ci ioc->build_sg(ioc, psge, data_out_dma, data_out_sz, data_in_dma, 9268c2ecf20Sopenharmony_ci data_in_sz); 9278c2ecf20Sopenharmony_ci ioc->put_smid_default(ioc, smid); 9288c2ecf20Sopenharmony_ci break; 9298c2ecf20Sopenharmony_ci } 9308c2ecf20Sopenharmony_ci case MPI2_FUNCTION_SATA_PASSTHROUGH: 9318c2ecf20Sopenharmony_ci { 9328c2ecf20Sopenharmony_ci if (test_bit(device_handle, ioc->device_remove_in_progress)) { 9338c2ecf20Sopenharmony_ci dtmprintk(ioc, 9348c2ecf20Sopenharmony_ci ioc_info(ioc, "handle(0x%04x) :ioctl failed due to device removal in progress\n", 9358c2ecf20Sopenharmony_ci device_handle)); 9368c2ecf20Sopenharmony_ci mpt3sas_base_free_smid(ioc, smid); 9378c2ecf20Sopenharmony_ci ret = -EINVAL; 9388c2ecf20Sopenharmony_ci goto out; 9398c2ecf20Sopenharmony_ci } 9408c2ecf20Sopenharmony_ci ioc->build_sg(ioc, psge, data_out_dma, data_out_sz, data_in_dma, 9418c2ecf20Sopenharmony_ci data_in_sz); 9428c2ecf20Sopenharmony_ci ioc->put_smid_default(ioc, smid); 9438c2ecf20Sopenharmony_ci break; 9448c2ecf20Sopenharmony_ci } 9458c2ecf20Sopenharmony_ci case MPI2_FUNCTION_FW_DOWNLOAD: 9468c2ecf20Sopenharmony_ci case MPI2_FUNCTION_FW_UPLOAD: 9478c2ecf20Sopenharmony_ci { 9488c2ecf20Sopenharmony_ci ioc->build_sg(ioc, psge, data_out_dma, data_out_sz, data_in_dma, 9498c2ecf20Sopenharmony_ci data_in_sz); 9508c2ecf20Sopenharmony_ci ioc->put_smid_default(ioc, smid); 9518c2ecf20Sopenharmony_ci break; 9528c2ecf20Sopenharmony_ci } 9538c2ecf20Sopenharmony_ci case MPI2_FUNCTION_TOOLBOX: 9548c2ecf20Sopenharmony_ci { 9558c2ecf20Sopenharmony_ci Mpi2ToolboxCleanRequest_t *toolbox_request = 9568c2ecf20Sopenharmony_ci (Mpi2ToolboxCleanRequest_t *)mpi_request; 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_ci if ((toolbox_request->Tool == MPI2_TOOLBOX_DIAGNOSTIC_CLI_TOOL) 9598c2ecf20Sopenharmony_ci || (toolbox_request->Tool == 9608c2ecf20Sopenharmony_ci MPI26_TOOLBOX_BACKEND_PCIE_LANE_MARGIN)) 9618c2ecf20Sopenharmony_ci ioc->build_sg(ioc, psge, data_out_dma, data_out_sz, 9628c2ecf20Sopenharmony_ci data_in_dma, data_in_sz); 9638c2ecf20Sopenharmony_ci else if (toolbox_request->Tool == 9648c2ecf20Sopenharmony_ci MPI2_TOOLBOX_MEMORY_MOVE_TOOL) { 9658c2ecf20Sopenharmony_ci Mpi2ToolboxMemMoveRequest_t *mem_move_request = 9668c2ecf20Sopenharmony_ci (Mpi2ToolboxMemMoveRequest_t *)request; 9678c2ecf20Sopenharmony_ci Mpi2SGESimple64_t tmp, *src = NULL, *dst = NULL; 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_ci ioc->build_sg_mpi(ioc, psge, data_out_dma, 9708c2ecf20Sopenharmony_ci data_out_sz, data_in_dma, data_in_sz); 9718c2ecf20Sopenharmony_ci if (data_out_sz && !data_in_sz) { 9728c2ecf20Sopenharmony_ci dst = 9738c2ecf20Sopenharmony_ci (Mpi2SGESimple64_t *)&mem_move_request->SGL; 9748c2ecf20Sopenharmony_ci src = (void *)dst + ioc->sge_size; 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ci memcpy(&tmp, src, ioc->sge_size); 9778c2ecf20Sopenharmony_ci memcpy(src, dst, ioc->sge_size); 9788c2ecf20Sopenharmony_ci memcpy(dst, &tmp, ioc->sge_size); 9798c2ecf20Sopenharmony_ci } 9808c2ecf20Sopenharmony_ci if (ioc->logging_level & MPT_DEBUG_TM) { 9818c2ecf20Sopenharmony_ci ioc_info(ioc, 9828c2ecf20Sopenharmony_ci "Mpi2ToolboxMemMoveRequest_t request msg\n"); 9838c2ecf20Sopenharmony_ci _debug_dump_mf(mem_move_request, 9848c2ecf20Sopenharmony_ci ioc->request_sz/4); 9858c2ecf20Sopenharmony_ci } 9868c2ecf20Sopenharmony_ci } else 9878c2ecf20Sopenharmony_ci ioc->build_sg_mpi(ioc, psge, data_out_dma, data_out_sz, 9888c2ecf20Sopenharmony_ci data_in_dma, data_in_sz); 9898c2ecf20Sopenharmony_ci ioc->put_smid_default(ioc, smid); 9908c2ecf20Sopenharmony_ci break; 9918c2ecf20Sopenharmony_ci } 9928c2ecf20Sopenharmony_ci case MPI2_FUNCTION_SAS_IO_UNIT_CONTROL: 9938c2ecf20Sopenharmony_ci { 9948c2ecf20Sopenharmony_ci Mpi2SasIoUnitControlRequest_t *sasiounit_request = 9958c2ecf20Sopenharmony_ci (Mpi2SasIoUnitControlRequest_t *)mpi_request; 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_ci if (sasiounit_request->Operation == MPI2_SAS_OP_PHY_HARD_RESET 9988c2ecf20Sopenharmony_ci || sasiounit_request->Operation == 9998c2ecf20Sopenharmony_ci MPI2_SAS_OP_PHY_LINK_RESET) { 10008c2ecf20Sopenharmony_ci ioc->ioc_link_reset_in_progress = 1; 10018c2ecf20Sopenharmony_ci ioc->ignore_loginfos = 1; 10028c2ecf20Sopenharmony_ci } 10038c2ecf20Sopenharmony_ci /* drop to default case for posting the request */ 10048c2ecf20Sopenharmony_ci } 10058c2ecf20Sopenharmony_ci fallthrough; 10068c2ecf20Sopenharmony_ci default: 10078c2ecf20Sopenharmony_ci ioc->build_sg_mpi(ioc, psge, data_out_dma, data_out_sz, 10088c2ecf20Sopenharmony_ci data_in_dma, data_in_sz); 10098c2ecf20Sopenharmony_ci ioc->put_smid_default(ioc, smid); 10108c2ecf20Sopenharmony_ci break; 10118c2ecf20Sopenharmony_ci } 10128c2ecf20Sopenharmony_ci 10138c2ecf20Sopenharmony_ci if (karg.timeout < MPT3_IOCTL_DEFAULT_TIMEOUT) 10148c2ecf20Sopenharmony_ci timeout = MPT3_IOCTL_DEFAULT_TIMEOUT; 10158c2ecf20Sopenharmony_ci else 10168c2ecf20Sopenharmony_ci timeout = karg.timeout; 10178c2ecf20Sopenharmony_ci wait_for_completion_timeout(&ioc->ctl_cmds.done, timeout*HZ); 10188c2ecf20Sopenharmony_ci if (mpi_request->Function == MPI2_FUNCTION_SCSI_TASK_MGMT) { 10198c2ecf20Sopenharmony_ci Mpi2SCSITaskManagementRequest_t *tm_request = 10208c2ecf20Sopenharmony_ci (Mpi2SCSITaskManagementRequest_t *)mpi_request; 10218c2ecf20Sopenharmony_ci mpt3sas_scsih_clear_tm_flag(ioc, le16_to_cpu( 10228c2ecf20Sopenharmony_ci tm_request->DevHandle)); 10238c2ecf20Sopenharmony_ci mpt3sas_trigger_master(ioc, MASTER_TRIGGER_TASK_MANAGMENT); 10248c2ecf20Sopenharmony_ci } else if ((mpi_request->Function == MPI2_FUNCTION_SMP_PASSTHROUGH || 10258c2ecf20Sopenharmony_ci mpi_request->Function == MPI2_FUNCTION_SAS_IO_UNIT_CONTROL) && 10268c2ecf20Sopenharmony_ci ioc->ioc_link_reset_in_progress) { 10278c2ecf20Sopenharmony_ci ioc->ioc_link_reset_in_progress = 0; 10288c2ecf20Sopenharmony_ci ioc->ignore_loginfos = 0; 10298c2ecf20Sopenharmony_ci } 10308c2ecf20Sopenharmony_ci if (!(ioc->ctl_cmds.status & MPT3_CMD_COMPLETE)) { 10318c2ecf20Sopenharmony_ci mpt3sas_check_cmd_timeout(ioc, 10328c2ecf20Sopenharmony_ci ioc->ctl_cmds.status, mpi_request, 10338c2ecf20Sopenharmony_ci karg.data_sge_offset, issue_reset); 10348c2ecf20Sopenharmony_ci goto issue_host_reset; 10358c2ecf20Sopenharmony_ci } 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci mpi_reply = ioc->ctl_cmds.reply; 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_ci if (mpi_reply->Function == MPI2_FUNCTION_SCSI_TASK_MGMT && 10408c2ecf20Sopenharmony_ci (ioc->logging_level & MPT_DEBUG_TM)) { 10418c2ecf20Sopenharmony_ci Mpi2SCSITaskManagementReply_t *tm_reply = 10428c2ecf20Sopenharmony_ci (Mpi2SCSITaskManagementReply_t *)mpi_reply; 10438c2ecf20Sopenharmony_ci 10448c2ecf20Sopenharmony_ci ioc_info(ioc, "TASK_MGMT: IOCStatus(0x%04x), IOCLogInfo(0x%08x), TerminationCount(0x%08x)\n", 10458c2ecf20Sopenharmony_ci le16_to_cpu(tm_reply->IOCStatus), 10468c2ecf20Sopenharmony_ci le32_to_cpu(tm_reply->IOCLogInfo), 10478c2ecf20Sopenharmony_ci le32_to_cpu(tm_reply->TerminationCount)); 10488c2ecf20Sopenharmony_ci } 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_ci /* copy out xdata to user */ 10518c2ecf20Sopenharmony_ci if (data_in_sz) { 10528c2ecf20Sopenharmony_ci if (copy_to_user(karg.data_in_buf_ptr, data_in, 10538c2ecf20Sopenharmony_ci data_in_sz)) { 10548c2ecf20Sopenharmony_ci pr_err("failure at %s:%d/%s()!\n", __FILE__, 10558c2ecf20Sopenharmony_ci __LINE__, __func__); 10568c2ecf20Sopenharmony_ci ret = -ENODATA; 10578c2ecf20Sopenharmony_ci goto out; 10588c2ecf20Sopenharmony_ci } 10598c2ecf20Sopenharmony_ci } 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_ci /* copy out reply message frame to user */ 10628c2ecf20Sopenharmony_ci if (karg.max_reply_bytes) { 10638c2ecf20Sopenharmony_ci sz = min_t(u32, karg.max_reply_bytes, ioc->reply_sz); 10648c2ecf20Sopenharmony_ci if (copy_to_user(karg.reply_frame_buf_ptr, ioc->ctl_cmds.reply, 10658c2ecf20Sopenharmony_ci sz)) { 10668c2ecf20Sopenharmony_ci pr_err("failure at %s:%d/%s()!\n", __FILE__, 10678c2ecf20Sopenharmony_ci __LINE__, __func__); 10688c2ecf20Sopenharmony_ci ret = -ENODATA; 10698c2ecf20Sopenharmony_ci goto out; 10708c2ecf20Sopenharmony_ci } 10718c2ecf20Sopenharmony_ci } 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci /* copy out sense/NVMe Error Response to user */ 10748c2ecf20Sopenharmony_ci if (karg.max_sense_bytes && (mpi_request->Function == 10758c2ecf20Sopenharmony_ci MPI2_FUNCTION_SCSI_IO_REQUEST || mpi_request->Function == 10768c2ecf20Sopenharmony_ci MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH || mpi_request->Function == 10778c2ecf20Sopenharmony_ci MPI2_FUNCTION_NVME_ENCAPSULATED)) { 10788c2ecf20Sopenharmony_ci if (karg.sense_data_ptr == NULL) { 10798c2ecf20Sopenharmony_ci ioc_info(ioc, "Response buffer provided by application is NULL; Response data will not be returned\n"); 10808c2ecf20Sopenharmony_ci goto out; 10818c2ecf20Sopenharmony_ci } 10828c2ecf20Sopenharmony_ci sz_arg = (mpi_request->Function == 10838c2ecf20Sopenharmony_ci MPI2_FUNCTION_NVME_ENCAPSULATED) ? NVME_ERROR_RESPONSE_SIZE : 10848c2ecf20Sopenharmony_ci SCSI_SENSE_BUFFERSIZE; 10858c2ecf20Sopenharmony_ci sz = min_t(u32, karg.max_sense_bytes, sz_arg); 10868c2ecf20Sopenharmony_ci if (copy_to_user(karg.sense_data_ptr, ioc->ctl_cmds.sense, 10878c2ecf20Sopenharmony_ci sz)) { 10888c2ecf20Sopenharmony_ci pr_err("failure at %s:%d/%s()!\n", __FILE__, 10898c2ecf20Sopenharmony_ci __LINE__, __func__); 10908c2ecf20Sopenharmony_ci ret = -ENODATA; 10918c2ecf20Sopenharmony_ci goto out; 10928c2ecf20Sopenharmony_ci } 10938c2ecf20Sopenharmony_ci } 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_ci issue_host_reset: 10968c2ecf20Sopenharmony_ci if (issue_reset) { 10978c2ecf20Sopenharmony_ci ret = -ENODATA; 10988c2ecf20Sopenharmony_ci if ((mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST || 10998c2ecf20Sopenharmony_ci mpi_request->Function == 11008c2ecf20Sopenharmony_ci MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH || 11018c2ecf20Sopenharmony_ci mpi_request->Function == MPI2_FUNCTION_SATA_PASSTHROUGH)) { 11028c2ecf20Sopenharmony_ci ioc_info(ioc, "issue target reset: handle = (0x%04x)\n", 11038c2ecf20Sopenharmony_ci le16_to_cpu(mpi_request->FunctionDependent1)); 11048c2ecf20Sopenharmony_ci mpt3sas_halt_firmware(ioc); 11058c2ecf20Sopenharmony_ci pcie_device = mpt3sas_get_pdev_by_handle(ioc, 11068c2ecf20Sopenharmony_ci le16_to_cpu(mpi_request->FunctionDependent1)); 11078c2ecf20Sopenharmony_ci if (pcie_device && (!ioc->tm_custom_handling) && 11088c2ecf20Sopenharmony_ci (!(mpt3sas_scsih_is_pcie_scsi_device( 11098c2ecf20Sopenharmony_ci pcie_device->device_info)))) 11108c2ecf20Sopenharmony_ci mpt3sas_scsih_issue_locked_tm(ioc, 11118c2ecf20Sopenharmony_ci le16_to_cpu(mpi_request->FunctionDependent1), 11128c2ecf20Sopenharmony_ci 0, 0, 0, 11138c2ecf20Sopenharmony_ci MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 11148c2ecf20Sopenharmony_ci 0, pcie_device->reset_timeout, 11158c2ecf20Sopenharmony_ci MPI26_SCSITASKMGMT_MSGFLAGS_PROTOCOL_LVL_RST_PCIE); 11168c2ecf20Sopenharmony_ci else 11178c2ecf20Sopenharmony_ci mpt3sas_scsih_issue_locked_tm(ioc, 11188c2ecf20Sopenharmony_ci le16_to_cpu(mpi_request->FunctionDependent1), 11198c2ecf20Sopenharmony_ci 0, 0, 0, 11208c2ecf20Sopenharmony_ci MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 11218c2ecf20Sopenharmony_ci 0, 30, MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET); 11228c2ecf20Sopenharmony_ci } else 11238c2ecf20Sopenharmony_ci mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER); 11248c2ecf20Sopenharmony_ci } 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_ci out: 11278c2ecf20Sopenharmony_ci if (pcie_device) 11288c2ecf20Sopenharmony_ci pcie_device_put(pcie_device); 11298c2ecf20Sopenharmony_ci 11308c2ecf20Sopenharmony_ci /* free memory associated with sg buffers */ 11318c2ecf20Sopenharmony_ci if (data_in) 11328c2ecf20Sopenharmony_ci dma_free_coherent(&ioc->pdev->dev, data_in_sz, data_in, 11338c2ecf20Sopenharmony_ci data_in_dma); 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_ci if (data_out) 11368c2ecf20Sopenharmony_ci dma_free_coherent(&ioc->pdev->dev, data_out_sz, data_out, 11378c2ecf20Sopenharmony_ci data_out_dma); 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_ci kfree(mpi_request); 11408c2ecf20Sopenharmony_ci ioc->ctl_cmds.status = MPT3_CMD_NOT_USED; 11418c2ecf20Sopenharmony_ci return ret; 11428c2ecf20Sopenharmony_ci} 11438c2ecf20Sopenharmony_ci 11448c2ecf20Sopenharmony_ci/** 11458c2ecf20Sopenharmony_ci * _ctl_getiocinfo - main handler for MPT3IOCINFO opcode 11468c2ecf20Sopenharmony_ci * @ioc: per adapter object 11478c2ecf20Sopenharmony_ci * @arg: user space buffer containing ioctl content 11488c2ecf20Sopenharmony_ci */ 11498c2ecf20Sopenharmony_cistatic long 11508c2ecf20Sopenharmony_ci_ctl_getiocinfo(struct MPT3SAS_ADAPTER *ioc, void __user *arg) 11518c2ecf20Sopenharmony_ci{ 11528c2ecf20Sopenharmony_ci struct mpt3_ioctl_iocinfo karg; 11538c2ecf20Sopenharmony_ci 11548c2ecf20Sopenharmony_ci dctlprintk(ioc, ioc_info(ioc, "%s: enter\n", 11558c2ecf20Sopenharmony_ci __func__)); 11568c2ecf20Sopenharmony_ci 11578c2ecf20Sopenharmony_ci memset(&karg, 0 , sizeof(karg)); 11588c2ecf20Sopenharmony_ci if (ioc->pfacts) 11598c2ecf20Sopenharmony_ci karg.port_number = ioc->pfacts[0].PortNumber; 11608c2ecf20Sopenharmony_ci karg.hw_rev = ioc->pdev->revision; 11618c2ecf20Sopenharmony_ci karg.pci_id = ioc->pdev->device; 11628c2ecf20Sopenharmony_ci karg.subsystem_device = ioc->pdev->subsystem_device; 11638c2ecf20Sopenharmony_ci karg.subsystem_vendor = ioc->pdev->subsystem_vendor; 11648c2ecf20Sopenharmony_ci karg.pci_information.u.bits.bus = ioc->pdev->bus->number; 11658c2ecf20Sopenharmony_ci karg.pci_information.u.bits.device = PCI_SLOT(ioc->pdev->devfn); 11668c2ecf20Sopenharmony_ci karg.pci_information.u.bits.function = PCI_FUNC(ioc->pdev->devfn); 11678c2ecf20Sopenharmony_ci karg.pci_information.segment_id = pci_domain_nr(ioc->pdev->bus); 11688c2ecf20Sopenharmony_ci karg.firmware_version = ioc->facts.FWVersion.Word; 11698c2ecf20Sopenharmony_ci strcpy(karg.driver_version, ioc->driver_name); 11708c2ecf20Sopenharmony_ci strcat(karg.driver_version, "-"); 11718c2ecf20Sopenharmony_ci switch (ioc->hba_mpi_version_belonged) { 11728c2ecf20Sopenharmony_ci case MPI2_VERSION: 11738c2ecf20Sopenharmony_ci if (ioc->is_warpdrive) 11748c2ecf20Sopenharmony_ci karg.adapter_type = MPT2_IOCTL_INTERFACE_SAS2_SSS6200; 11758c2ecf20Sopenharmony_ci else 11768c2ecf20Sopenharmony_ci karg.adapter_type = MPT2_IOCTL_INTERFACE_SAS2; 11778c2ecf20Sopenharmony_ci strcat(karg.driver_version, MPT2SAS_DRIVER_VERSION); 11788c2ecf20Sopenharmony_ci break; 11798c2ecf20Sopenharmony_ci case MPI25_VERSION: 11808c2ecf20Sopenharmony_ci case MPI26_VERSION: 11818c2ecf20Sopenharmony_ci if (ioc->is_gen35_ioc) 11828c2ecf20Sopenharmony_ci karg.adapter_type = MPT3_IOCTL_INTERFACE_SAS35; 11838c2ecf20Sopenharmony_ci else 11848c2ecf20Sopenharmony_ci karg.adapter_type = MPT3_IOCTL_INTERFACE_SAS3; 11858c2ecf20Sopenharmony_ci strcat(karg.driver_version, MPT3SAS_DRIVER_VERSION); 11868c2ecf20Sopenharmony_ci break; 11878c2ecf20Sopenharmony_ci } 11888c2ecf20Sopenharmony_ci karg.bios_version = le32_to_cpu(ioc->bios_pg3.BiosVersion); 11898c2ecf20Sopenharmony_ci 11908c2ecf20Sopenharmony_ci if (copy_to_user(arg, &karg, sizeof(karg))) { 11918c2ecf20Sopenharmony_ci pr_err("failure at %s:%d/%s()!\n", 11928c2ecf20Sopenharmony_ci __FILE__, __LINE__, __func__); 11938c2ecf20Sopenharmony_ci return -EFAULT; 11948c2ecf20Sopenharmony_ci } 11958c2ecf20Sopenharmony_ci return 0; 11968c2ecf20Sopenharmony_ci} 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_ci/** 11998c2ecf20Sopenharmony_ci * _ctl_eventquery - main handler for MPT3EVENTQUERY opcode 12008c2ecf20Sopenharmony_ci * @ioc: per adapter object 12018c2ecf20Sopenharmony_ci * @arg: user space buffer containing ioctl content 12028c2ecf20Sopenharmony_ci */ 12038c2ecf20Sopenharmony_cistatic long 12048c2ecf20Sopenharmony_ci_ctl_eventquery(struct MPT3SAS_ADAPTER *ioc, void __user *arg) 12058c2ecf20Sopenharmony_ci{ 12068c2ecf20Sopenharmony_ci struct mpt3_ioctl_eventquery karg; 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_ci if (copy_from_user(&karg, arg, sizeof(karg))) { 12098c2ecf20Sopenharmony_ci pr_err("failure at %s:%d/%s()!\n", 12108c2ecf20Sopenharmony_ci __FILE__, __LINE__, __func__); 12118c2ecf20Sopenharmony_ci return -EFAULT; 12128c2ecf20Sopenharmony_ci } 12138c2ecf20Sopenharmony_ci 12148c2ecf20Sopenharmony_ci dctlprintk(ioc, ioc_info(ioc, "%s: enter\n", 12158c2ecf20Sopenharmony_ci __func__)); 12168c2ecf20Sopenharmony_ci 12178c2ecf20Sopenharmony_ci karg.event_entries = MPT3SAS_CTL_EVENT_LOG_SIZE; 12188c2ecf20Sopenharmony_ci memcpy(karg.event_types, ioc->event_type, 12198c2ecf20Sopenharmony_ci MPI2_EVENT_NOTIFY_EVENTMASK_WORDS * sizeof(u32)); 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_ci if (copy_to_user(arg, &karg, sizeof(karg))) { 12228c2ecf20Sopenharmony_ci pr_err("failure at %s:%d/%s()!\n", 12238c2ecf20Sopenharmony_ci __FILE__, __LINE__, __func__); 12248c2ecf20Sopenharmony_ci return -EFAULT; 12258c2ecf20Sopenharmony_ci } 12268c2ecf20Sopenharmony_ci return 0; 12278c2ecf20Sopenharmony_ci} 12288c2ecf20Sopenharmony_ci 12298c2ecf20Sopenharmony_ci/** 12308c2ecf20Sopenharmony_ci * _ctl_eventenable - main handler for MPT3EVENTENABLE opcode 12318c2ecf20Sopenharmony_ci * @ioc: per adapter object 12328c2ecf20Sopenharmony_ci * @arg: user space buffer containing ioctl content 12338c2ecf20Sopenharmony_ci */ 12348c2ecf20Sopenharmony_cistatic long 12358c2ecf20Sopenharmony_ci_ctl_eventenable(struct MPT3SAS_ADAPTER *ioc, void __user *arg) 12368c2ecf20Sopenharmony_ci{ 12378c2ecf20Sopenharmony_ci struct mpt3_ioctl_eventenable karg; 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_ci if (copy_from_user(&karg, arg, sizeof(karg))) { 12408c2ecf20Sopenharmony_ci pr_err("failure at %s:%d/%s()!\n", 12418c2ecf20Sopenharmony_ci __FILE__, __LINE__, __func__); 12428c2ecf20Sopenharmony_ci return -EFAULT; 12438c2ecf20Sopenharmony_ci } 12448c2ecf20Sopenharmony_ci 12458c2ecf20Sopenharmony_ci dctlprintk(ioc, ioc_info(ioc, "%s: enter\n", 12468c2ecf20Sopenharmony_ci __func__)); 12478c2ecf20Sopenharmony_ci 12488c2ecf20Sopenharmony_ci memcpy(ioc->event_type, karg.event_types, 12498c2ecf20Sopenharmony_ci MPI2_EVENT_NOTIFY_EVENTMASK_WORDS * sizeof(u32)); 12508c2ecf20Sopenharmony_ci mpt3sas_base_validate_event_type(ioc, ioc->event_type); 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_ci if (ioc->event_log) 12538c2ecf20Sopenharmony_ci return 0; 12548c2ecf20Sopenharmony_ci /* initialize event_log */ 12558c2ecf20Sopenharmony_ci ioc->event_context = 0; 12568c2ecf20Sopenharmony_ci ioc->aen_event_read_flag = 0; 12578c2ecf20Sopenharmony_ci ioc->event_log = kcalloc(MPT3SAS_CTL_EVENT_LOG_SIZE, 12588c2ecf20Sopenharmony_ci sizeof(struct MPT3_IOCTL_EVENTS), GFP_KERNEL); 12598c2ecf20Sopenharmony_ci if (!ioc->event_log) { 12608c2ecf20Sopenharmony_ci pr_err("failure at %s:%d/%s()!\n", 12618c2ecf20Sopenharmony_ci __FILE__, __LINE__, __func__); 12628c2ecf20Sopenharmony_ci return -ENOMEM; 12638c2ecf20Sopenharmony_ci } 12648c2ecf20Sopenharmony_ci return 0; 12658c2ecf20Sopenharmony_ci} 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_ci/** 12688c2ecf20Sopenharmony_ci * _ctl_eventreport - main handler for MPT3EVENTREPORT opcode 12698c2ecf20Sopenharmony_ci * @ioc: per adapter object 12708c2ecf20Sopenharmony_ci * @arg: user space buffer containing ioctl content 12718c2ecf20Sopenharmony_ci */ 12728c2ecf20Sopenharmony_cistatic long 12738c2ecf20Sopenharmony_ci_ctl_eventreport(struct MPT3SAS_ADAPTER *ioc, void __user *arg) 12748c2ecf20Sopenharmony_ci{ 12758c2ecf20Sopenharmony_ci struct mpt3_ioctl_eventreport karg; 12768c2ecf20Sopenharmony_ci u32 number_bytes, max_events, max; 12778c2ecf20Sopenharmony_ci struct mpt3_ioctl_eventreport __user *uarg = arg; 12788c2ecf20Sopenharmony_ci 12798c2ecf20Sopenharmony_ci if (copy_from_user(&karg, arg, sizeof(karg))) { 12808c2ecf20Sopenharmony_ci pr_err("failure at %s:%d/%s()!\n", 12818c2ecf20Sopenharmony_ci __FILE__, __LINE__, __func__); 12828c2ecf20Sopenharmony_ci return -EFAULT; 12838c2ecf20Sopenharmony_ci } 12848c2ecf20Sopenharmony_ci 12858c2ecf20Sopenharmony_ci dctlprintk(ioc, ioc_info(ioc, "%s: enter\n", 12868c2ecf20Sopenharmony_ci __func__)); 12878c2ecf20Sopenharmony_ci 12888c2ecf20Sopenharmony_ci number_bytes = karg.hdr.max_data_size - 12898c2ecf20Sopenharmony_ci sizeof(struct mpt3_ioctl_header); 12908c2ecf20Sopenharmony_ci max_events = number_bytes/sizeof(struct MPT3_IOCTL_EVENTS); 12918c2ecf20Sopenharmony_ci max = min_t(u32, MPT3SAS_CTL_EVENT_LOG_SIZE, max_events); 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_ci /* If fewer than 1 event is requested, there must have 12948c2ecf20Sopenharmony_ci * been some type of error. 12958c2ecf20Sopenharmony_ci */ 12968c2ecf20Sopenharmony_ci if (!max || !ioc->event_log) 12978c2ecf20Sopenharmony_ci return -ENODATA; 12988c2ecf20Sopenharmony_ci 12998c2ecf20Sopenharmony_ci number_bytes = max * sizeof(struct MPT3_IOCTL_EVENTS); 13008c2ecf20Sopenharmony_ci if (copy_to_user(uarg->event_data, ioc->event_log, number_bytes)) { 13018c2ecf20Sopenharmony_ci pr_err("failure at %s:%d/%s()!\n", 13028c2ecf20Sopenharmony_ci __FILE__, __LINE__, __func__); 13038c2ecf20Sopenharmony_ci return -EFAULT; 13048c2ecf20Sopenharmony_ci } 13058c2ecf20Sopenharmony_ci 13068c2ecf20Sopenharmony_ci /* reset flag so SIGIO can restart */ 13078c2ecf20Sopenharmony_ci ioc->aen_event_read_flag = 0; 13088c2ecf20Sopenharmony_ci return 0; 13098c2ecf20Sopenharmony_ci} 13108c2ecf20Sopenharmony_ci 13118c2ecf20Sopenharmony_ci/** 13128c2ecf20Sopenharmony_ci * _ctl_do_reset - main handler for MPT3HARDRESET opcode 13138c2ecf20Sopenharmony_ci * @ioc: per adapter object 13148c2ecf20Sopenharmony_ci * @arg: user space buffer containing ioctl content 13158c2ecf20Sopenharmony_ci */ 13168c2ecf20Sopenharmony_cistatic long 13178c2ecf20Sopenharmony_ci_ctl_do_reset(struct MPT3SAS_ADAPTER *ioc, void __user *arg) 13188c2ecf20Sopenharmony_ci{ 13198c2ecf20Sopenharmony_ci struct mpt3_ioctl_diag_reset karg; 13208c2ecf20Sopenharmony_ci int retval; 13218c2ecf20Sopenharmony_ci 13228c2ecf20Sopenharmony_ci if (copy_from_user(&karg, arg, sizeof(karg))) { 13238c2ecf20Sopenharmony_ci pr_err("failure at %s:%d/%s()!\n", 13248c2ecf20Sopenharmony_ci __FILE__, __LINE__, __func__); 13258c2ecf20Sopenharmony_ci return -EFAULT; 13268c2ecf20Sopenharmony_ci } 13278c2ecf20Sopenharmony_ci 13288c2ecf20Sopenharmony_ci if (ioc->shost_recovery || ioc->pci_error_recovery || 13298c2ecf20Sopenharmony_ci ioc->is_driver_loading) 13308c2ecf20Sopenharmony_ci return -EAGAIN; 13318c2ecf20Sopenharmony_ci 13328c2ecf20Sopenharmony_ci dctlprintk(ioc, ioc_info(ioc, "%s: enter\n", 13338c2ecf20Sopenharmony_ci __func__)); 13348c2ecf20Sopenharmony_ci 13358c2ecf20Sopenharmony_ci retval = mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER); 13368c2ecf20Sopenharmony_ci ioc_info(ioc, 13378c2ecf20Sopenharmony_ci "Ioctl: host reset: %s\n", ((!retval) ? "SUCCESS" : "FAILED")); 13388c2ecf20Sopenharmony_ci return 0; 13398c2ecf20Sopenharmony_ci} 13408c2ecf20Sopenharmony_ci 13418c2ecf20Sopenharmony_ci/** 13428c2ecf20Sopenharmony_ci * _ctl_btdh_search_sas_device - searching for sas device 13438c2ecf20Sopenharmony_ci * @ioc: per adapter object 13448c2ecf20Sopenharmony_ci * @btdh: btdh ioctl payload 13458c2ecf20Sopenharmony_ci */ 13468c2ecf20Sopenharmony_cistatic int 13478c2ecf20Sopenharmony_ci_ctl_btdh_search_sas_device(struct MPT3SAS_ADAPTER *ioc, 13488c2ecf20Sopenharmony_ci struct mpt3_ioctl_btdh_mapping *btdh) 13498c2ecf20Sopenharmony_ci{ 13508c2ecf20Sopenharmony_ci struct _sas_device *sas_device; 13518c2ecf20Sopenharmony_ci unsigned long flags; 13528c2ecf20Sopenharmony_ci int rc = 0; 13538c2ecf20Sopenharmony_ci 13548c2ecf20Sopenharmony_ci if (list_empty(&ioc->sas_device_list)) 13558c2ecf20Sopenharmony_ci return rc; 13568c2ecf20Sopenharmony_ci 13578c2ecf20Sopenharmony_ci spin_lock_irqsave(&ioc->sas_device_lock, flags); 13588c2ecf20Sopenharmony_ci list_for_each_entry(sas_device, &ioc->sas_device_list, list) { 13598c2ecf20Sopenharmony_ci if (btdh->bus == 0xFFFFFFFF && btdh->id == 0xFFFFFFFF && 13608c2ecf20Sopenharmony_ci btdh->handle == sas_device->handle) { 13618c2ecf20Sopenharmony_ci btdh->bus = sas_device->channel; 13628c2ecf20Sopenharmony_ci btdh->id = sas_device->id; 13638c2ecf20Sopenharmony_ci rc = 1; 13648c2ecf20Sopenharmony_ci goto out; 13658c2ecf20Sopenharmony_ci } else if (btdh->bus == sas_device->channel && btdh->id == 13668c2ecf20Sopenharmony_ci sas_device->id && btdh->handle == 0xFFFF) { 13678c2ecf20Sopenharmony_ci btdh->handle = sas_device->handle; 13688c2ecf20Sopenharmony_ci rc = 1; 13698c2ecf20Sopenharmony_ci goto out; 13708c2ecf20Sopenharmony_ci } 13718c2ecf20Sopenharmony_ci } 13728c2ecf20Sopenharmony_ci out: 13738c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ioc->sas_device_lock, flags); 13748c2ecf20Sopenharmony_ci return rc; 13758c2ecf20Sopenharmony_ci} 13768c2ecf20Sopenharmony_ci 13778c2ecf20Sopenharmony_ci/** 13788c2ecf20Sopenharmony_ci * _ctl_btdh_search_pcie_device - searching for pcie device 13798c2ecf20Sopenharmony_ci * @ioc: per adapter object 13808c2ecf20Sopenharmony_ci * @btdh: btdh ioctl payload 13818c2ecf20Sopenharmony_ci */ 13828c2ecf20Sopenharmony_cistatic int 13838c2ecf20Sopenharmony_ci_ctl_btdh_search_pcie_device(struct MPT3SAS_ADAPTER *ioc, 13848c2ecf20Sopenharmony_ci struct mpt3_ioctl_btdh_mapping *btdh) 13858c2ecf20Sopenharmony_ci{ 13868c2ecf20Sopenharmony_ci struct _pcie_device *pcie_device; 13878c2ecf20Sopenharmony_ci unsigned long flags; 13888c2ecf20Sopenharmony_ci int rc = 0; 13898c2ecf20Sopenharmony_ci 13908c2ecf20Sopenharmony_ci if (list_empty(&ioc->pcie_device_list)) 13918c2ecf20Sopenharmony_ci return rc; 13928c2ecf20Sopenharmony_ci 13938c2ecf20Sopenharmony_ci spin_lock_irqsave(&ioc->pcie_device_lock, flags); 13948c2ecf20Sopenharmony_ci list_for_each_entry(pcie_device, &ioc->pcie_device_list, list) { 13958c2ecf20Sopenharmony_ci if (btdh->bus == 0xFFFFFFFF && btdh->id == 0xFFFFFFFF && 13968c2ecf20Sopenharmony_ci btdh->handle == pcie_device->handle) { 13978c2ecf20Sopenharmony_ci btdh->bus = pcie_device->channel; 13988c2ecf20Sopenharmony_ci btdh->id = pcie_device->id; 13998c2ecf20Sopenharmony_ci rc = 1; 14008c2ecf20Sopenharmony_ci goto out; 14018c2ecf20Sopenharmony_ci } else if (btdh->bus == pcie_device->channel && btdh->id == 14028c2ecf20Sopenharmony_ci pcie_device->id && btdh->handle == 0xFFFF) { 14038c2ecf20Sopenharmony_ci btdh->handle = pcie_device->handle; 14048c2ecf20Sopenharmony_ci rc = 1; 14058c2ecf20Sopenharmony_ci goto out; 14068c2ecf20Sopenharmony_ci } 14078c2ecf20Sopenharmony_ci } 14088c2ecf20Sopenharmony_ci out: 14098c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ioc->pcie_device_lock, flags); 14108c2ecf20Sopenharmony_ci return rc; 14118c2ecf20Sopenharmony_ci} 14128c2ecf20Sopenharmony_ci 14138c2ecf20Sopenharmony_ci/** 14148c2ecf20Sopenharmony_ci * _ctl_btdh_search_raid_device - searching for raid device 14158c2ecf20Sopenharmony_ci * @ioc: per adapter object 14168c2ecf20Sopenharmony_ci * @btdh: btdh ioctl payload 14178c2ecf20Sopenharmony_ci */ 14188c2ecf20Sopenharmony_cistatic int 14198c2ecf20Sopenharmony_ci_ctl_btdh_search_raid_device(struct MPT3SAS_ADAPTER *ioc, 14208c2ecf20Sopenharmony_ci struct mpt3_ioctl_btdh_mapping *btdh) 14218c2ecf20Sopenharmony_ci{ 14228c2ecf20Sopenharmony_ci struct _raid_device *raid_device; 14238c2ecf20Sopenharmony_ci unsigned long flags; 14248c2ecf20Sopenharmony_ci int rc = 0; 14258c2ecf20Sopenharmony_ci 14268c2ecf20Sopenharmony_ci if (list_empty(&ioc->raid_device_list)) 14278c2ecf20Sopenharmony_ci return rc; 14288c2ecf20Sopenharmony_ci 14298c2ecf20Sopenharmony_ci spin_lock_irqsave(&ioc->raid_device_lock, flags); 14308c2ecf20Sopenharmony_ci list_for_each_entry(raid_device, &ioc->raid_device_list, list) { 14318c2ecf20Sopenharmony_ci if (btdh->bus == 0xFFFFFFFF && btdh->id == 0xFFFFFFFF && 14328c2ecf20Sopenharmony_ci btdh->handle == raid_device->handle) { 14338c2ecf20Sopenharmony_ci btdh->bus = raid_device->channel; 14348c2ecf20Sopenharmony_ci btdh->id = raid_device->id; 14358c2ecf20Sopenharmony_ci rc = 1; 14368c2ecf20Sopenharmony_ci goto out; 14378c2ecf20Sopenharmony_ci } else if (btdh->bus == raid_device->channel && btdh->id == 14388c2ecf20Sopenharmony_ci raid_device->id && btdh->handle == 0xFFFF) { 14398c2ecf20Sopenharmony_ci btdh->handle = raid_device->handle; 14408c2ecf20Sopenharmony_ci rc = 1; 14418c2ecf20Sopenharmony_ci goto out; 14428c2ecf20Sopenharmony_ci } 14438c2ecf20Sopenharmony_ci } 14448c2ecf20Sopenharmony_ci out: 14458c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ioc->raid_device_lock, flags); 14468c2ecf20Sopenharmony_ci return rc; 14478c2ecf20Sopenharmony_ci} 14488c2ecf20Sopenharmony_ci 14498c2ecf20Sopenharmony_ci/** 14508c2ecf20Sopenharmony_ci * _ctl_btdh_mapping - main handler for MPT3BTDHMAPPING opcode 14518c2ecf20Sopenharmony_ci * @ioc: per adapter object 14528c2ecf20Sopenharmony_ci * @arg: user space buffer containing ioctl content 14538c2ecf20Sopenharmony_ci */ 14548c2ecf20Sopenharmony_cistatic long 14558c2ecf20Sopenharmony_ci_ctl_btdh_mapping(struct MPT3SAS_ADAPTER *ioc, void __user *arg) 14568c2ecf20Sopenharmony_ci{ 14578c2ecf20Sopenharmony_ci struct mpt3_ioctl_btdh_mapping karg; 14588c2ecf20Sopenharmony_ci int rc; 14598c2ecf20Sopenharmony_ci 14608c2ecf20Sopenharmony_ci if (copy_from_user(&karg, arg, sizeof(karg))) { 14618c2ecf20Sopenharmony_ci pr_err("failure at %s:%d/%s()!\n", 14628c2ecf20Sopenharmony_ci __FILE__, __LINE__, __func__); 14638c2ecf20Sopenharmony_ci return -EFAULT; 14648c2ecf20Sopenharmony_ci } 14658c2ecf20Sopenharmony_ci 14668c2ecf20Sopenharmony_ci dctlprintk(ioc, ioc_info(ioc, "%s\n", 14678c2ecf20Sopenharmony_ci __func__)); 14688c2ecf20Sopenharmony_ci 14698c2ecf20Sopenharmony_ci rc = _ctl_btdh_search_sas_device(ioc, &karg); 14708c2ecf20Sopenharmony_ci if (!rc) 14718c2ecf20Sopenharmony_ci rc = _ctl_btdh_search_pcie_device(ioc, &karg); 14728c2ecf20Sopenharmony_ci if (!rc) 14738c2ecf20Sopenharmony_ci _ctl_btdh_search_raid_device(ioc, &karg); 14748c2ecf20Sopenharmony_ci 14758c2ecf20Sopenharmony_ci if (copy_to_user(arg, &karg, sizeof(karg))) { 14768c2ecf20Sopenharmony_ci pr_err("failure at %s:%d/%s()!\n", 14778c2ecf20Sopenharmony_ci __FILE__, __LINE__, __func__); 14788c2ecf20Sopenharmony_ci return -EFAULT; 14798c2ecf20Sopenharmony_ci } 14808c2ecf20Sopenharmony_ci return 0; 14818c2ecf20Sopenharmony_ci} 14828c2ecf20Sopenharmony_ci 14838c2ecf20Sopenharmony_ci/** 14848c2ecf20Sopenharmony_ci * _ctl_diag_capability - return diag buffer capability 14858c2ecf20Sopenharmony_ci * @ioc: per adapter object 14868c2ecf20Sopenharmony_ci * @buffer_type: specifies either TRACE, SNAPSHOT, or EXTENDED 14878c2ecf20Sopenharmony_ci * 14888c2ecf20Sopenharmony_ci * returns 1 when diag buffer support is enabled in firmware 14898c2ecf20Sopenharmony_ci */ 14908c2ecf20Sopenharmony_cistatic u8 14918c2ecf20Sopenharmony_ci_ctl_diag_capability(struct MPT3SAS_ADAPTER *ioc, u8 buffer_type) 14928c2ecf20Sopenharmony_ci{ 14938c2ecf20Sopenharmony_ci u8 rc = 0; 14948c2ecf20Sopenharmony_ci 14958c2ecf20Sopenharmony_ci switch (buffer_type) { 14968c2ecf20Sopenharmony_ci case MPI2_DIAG_BUF_TYPE_TRACE: 14978c2ecf20Sopenharmony_ci if (ioc->facts.IOCCapabilities & 14988c2ecf20Sopenharmony_ci MPI2_IOCFACTS_CAPABILITY_DIAG_TRACE_BUFFER) 14998c2ecf20Sopenharmony_ci rc = 1; 15008c2ecf20Sopenharmony_ci break; 15018c2ecf20Sopenharmony_ci case MPI2_DIAG_BUF_TYPE_SNAPSHOT: 15028c2ecf20Sopenharmony_ci if (ioc->facts.IOCCapabilities & 15038c2ecf20Sopenharmony_ci MPI2_IOCFACTS_CAPABILITY_SNAPSHOT_BUFFER) 15048c2ecf20Sopenharmony_ci rc = 1; 15058c2ecf20Sopenharmony_ci break; 15068c2ecf20Sopenharmony_ci case MPI2_DIAG_BUF_TYPE_EXTENDED: 15078c2ecf20Sopenharmony_ci if (ioc->facts.IOCCapabilities & 15088c2ecf20Sopenharmony_ci MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER) 15098c2ecf20Sopenharmony_ci rc = 1; 15108c2ecf20Sopenharmony_ci } 15118c2ecf20Sopenharmony_ci 15128c2ecf20Sopenharmony_ci return rc; 15138c2ecf20Sopenharmony_ci} 15148c2ecf20Sopenharmony_ci 15158c2ecf20Sopenharmony_ci/** 15168c2ecf20Sopenharmony_ci * _ctl_diag_get_bufftype - return diag buffer type 15178c2ecf20Sopenharmony_ci * either TRACE, SNAPSHOT, or EXTENDED 15188c2ecf20Sopenharmony_ci * @ioc: per adapter object 15198c2ecf20Sopenharmony_ci * @unique_id: specifies the unique_id for the buffer 15208c2ecf20Sopenharmony_ci * 15218c2ecf20Sopenharmony_ci * returns MPT3_DIAG_UID_NOT_FOUND if the id not found 15228c2ecf20Sopenharmony_ci */ 15238c2ecf20Sopenharmony_cistatic u8 15248c2ecf20Sopenharmony_ci_ctl_diag_get_bufftype(struct MPT3SAS_ADAPTER *ioc, u32 unique_id) 15258c2ecf20Sopenharmony_ci{ 15268c2ecf20Sopenharmony_ci u8 index; 15278c2ecf20Sopenharmony_ci 15288c2ecf20Sopenharmony_ci for (index = 0; index < MPI2_DIAG_BUF_TYPE_COUNT; index++) { 15298c2ecf20Sopenharmony_ci if (ioc->unique_id[index] == unique_id) 15308c2ecf20Sopenharmony_ci return index; 15318c2ecf20Sopenharmony_ci } 15328c2ecf20Sopenharmony_ci 15338c2ecf20Sopenharmony_ci return MPT3_DIAG_UID_NOT_FOUND; 15348c2ecf20Sopenharmony_ci} 15358c2ecf20Sopenharmony_ci 15368c2ecf20Sopenharmony_ci/** 15378c2ecf20Sopenharmony_ci * _ctl_diag_register_2 - wrapper for registering diag buffer support 15388c2ecf20Sopenharmony_ci * @ioc: per adapter object 15398c2ecf20Sopenharmony_ci * @diag_register: the diag_register struct passed in from user space 15408c2ecf20Sopenharmony_ci * 15418c2ecf20Sopenharmony_ci */ 15428c2ecf20Sopenharmony_cistatic long 15438c2ecf20Sopenharmony_ci_ctl_diag_register_2(struct MPT3SAS_ADAPTER *ioc, 15448c2ecf20Sopenharmony_ci struct mpt3_diag_register *diag_register) 15458c2ecf20Sopenharmony_ci{ 15468c2ecf20Sopenharmony_ci int rc, i; 15478c2ecf20Sopenharmony_ci void *request_data = NULL; 15488c2ecf20Sopenharmony_ci dma_addr_t request_data_dma; 15498c2ecf20Sopenharmony_ci u32 request_data_sz = 0; 15508c2ecf20Sopenharmony_ci Mpi2DiagBufferPostRequest_t *mpi_request; 15518c2ecf20Sopenharmony_ci Mpi2DiagBufferPostReply_t *mpi_reply; 15528c2ecf20Sopenharmony_ci u8 buffer_type; 15538c2ecf20Sopenharmony_ci u16 smid; 15548c2ecf20Sopenharmony_ci u16 ioc_status; 15558c2ecf20Sopenharmony_ci u32 ioc_state; 15568c2ecf20Sopenharmony_ci u8 issue_reset = 0; 15578c2ecf20Sopenharmony_ci 15588c2ecf20Sopenharmony_ci dctlprintk(ioc, ioc_info(ioc, "%s\n", 15598c2ecf20Sopenharmony_ci __func__)); 15608c2ecf20Sopenharmony_ci 15618c2ecf20Sopenharmony_ci ioc_state = mpt3sas_base_get_iocstate(ioc, 1); 15628c2ecf20Sopenharmony_ci if (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { 15638c2ecf20Sopenharmony_ci ioc_err(ioc, "%s: failed due to ioc not operational\n", 15648c2ecf20Sopenharmony_ci __func__); 15658c2ecf20Sopenharmony_ci rc = -EAGAIN; 15668c2ecf20Sopenharmony_ci goto out; 15678c2ecf20Sopenharmony_ci } 15688c2ecf20Sopenharmony_ci 15698c2ecf20Sopenharmony_ci if (ioc->ctl_cmds.status != MPT3_CMD_NOT_USED) { 15708c2ecf20Sopenharmony_ci ioc_err(ioc, "%s: ctl_cmd in use\n", __func__); 15718c2ecf20Sopenharmony_ci rc = -EAGAIN; 15728c2ecf20Sopenharmony_ci goto out; 15738c2ecf20Sopenharmony_ci } 15748c2ecf20Sopenharmony_ci 15758c2ecf20Sopenharmony_ci buffer_type = diag_register->buffer_type; 15768c2ecf20Sopenharmony_ci if (!_ctl_diag_capability(ioc, buffer_type)) { 15778c2ecf20Sopenharmony_ci ioc_err(ioc, "%s: doesn't have capability for buffer_type(0x%02x)\n", 15788c2ecf20Sopenharmony_ci __func__, buffer_type); 15798c2ecf20Sopenharmony_ci return -EPERM; 15808c2ecf20Sopenharmony_ci } 15818c2ecf20Sopenharmony_ci 15828c2ecf20Sopenharmony_ci if (diag_register->unique_id == 0) { 15838c2ecf20Sopenharmony_ci ioc_err(ioc, 15848c2ecf20Sopenharmony_ci "%s: Invalid UID(0x%08x), buffer_type(0x%02x)\n", __func__, 15858c2ecf20Sopenharmony_ci diag_register->unique_id, buffer_type); 15868c2ecf20Sopenharmony_ci return -EINVAL; 15878c2ecf20Sopenharmony_ci } 15888c2ecf20Sopenharmony_ci 15898c2ecf20Sopenharmony_ci if ((ioc->diag_buffer_status[buffer_type] & 15908c2ecf20Sopenharmony_ci MPT3_DIAG_BUFFER_IS_APP_OWNED) && 15918c2ecf20Sopenharmony_ci !(ioc->diag_buffer_status[buffer_type] & 15928c2ecf20Sopenharmony_ci MPT3_DIAG_BUFFER_IS_RELEASED)) { 15938c2ecf20Sopenharmony_ci ioc_err(ioc, 15948c2ecf20Sopenharmony_ci "%s: buffer_type(0x%02x) is already registered by application with UID(0x%08x)\n", 15958c2ecf20Sopenharmony_ci __func__, buffer_type, ioc->unique_id[buffer_type]); 15968c2ecf20Sopenharmony_ci return -EINVAL; 15978c2ecf20Sopenharmony_ci } 15988c2ecf20Sopenharmony_ci 15998c2ecf20Sopenharmony_ci if (ioc->diag_buffer_status[buffer_type] & 16008c2ecf20Sopenharmony_ci MPT3_DIAG_BUFFER_IS_REGISTERED) { 16018c2ecf20Sopenharmony_ci /* 16028c2ecf20Sopenharmony_ci * If driver posts buffer initially, then an application wants 16038c2ecf20Sopenharmony_ci * to Register that buffer (own it) without Releasing first, 16048c2ecf20Sopenharmony_ci * the application Register command MUST have the same buffer 16058c2ecf20Sopenharmony_ci * type and size in the Register command (obtained from the 16068c2ecf20Sopenharmony_ci * Query command). Otherwise that Register command will be 16078c2ecf20Sopenharmony_ci * failed. If the application has released the buffer but wants 16088c2ecf20Sopenharmony_ci * to re-register it, it should be allowed as long as the 16098c2ecf20Sopenharmony_ci * Unique-Id/Size match. 16108c2ecf20Sopenharmony_ci */ 16118c2ecf20Sopenharmony_ci 16128c2ecf20Sopenharmony_ci if (ioc->unique_id[buffer_type] == MPT3DIAGBUFFUNIQUEID && 16138c2ecf20Sopenharmony_ci ioc->diag_buffer_sz[buffer_type] == 16148c2ecf20Sopenharmony_ci diag_register->requested_buffer_size) { 16158c2ecf20Sopenharmony_ci 16168c2ecf20Sopenharmony_ci if (!(ioc->diag_buffer_status[buffer_type] & 16178c2ecf20Sopenharmony_ci MPT3_DIAG_BUFFER_IS_RELEASED)) { 16188c2ecf20Sopenharmony_ci dctlprintk(ioc, ioc_info(ioc, 16198c2ecf20Sopenharmony_ci "%s: diag_buffer (%d) ownership changed. old-ID(0x%08x), new-ID(0x%08x)\n", 16208c2ecf20Sopenharmony_ci __func__, buffer_type, 16218c2ecf20Sopenharmony_ci ioc->unique_id[buffer_type], 16228c2ecf20Sopenharmony_ci diag_register->unique_id)); 16238c2ecf20Sopenharmony_ci 16248c2ecf20Sopenharmony_ci /* 16258c2ecf20Sopenharmony_ci * Application wants to own the buffer with 16268c2ecf20Sopenharmony_ci * the same size. 16278c2ecf20Sopenharmony_ci */ 16288c2ecf20Sopenharmony_ci ioc->unique_id[buffer_type] = 16298c2ecf20Sopenharmony_ci diag_register->unique_id; 16308c2ecf20Sopenharmony_ci rc = 0; /* success */ 16318c2ecf20Sopenharmony_ci goto out; 16328c2ecf20Sopenharmony_ci } 16338c2ecf20Sopenharmony_ci } else if (ioc->unique_id[buffer_type] != 16348c2ecf20Sopenharmony_ci MPT3DIAGBUFFUNIQUEID) { 16358c2ecf20Sopenharmony_ci if (ioc->unique_id[buffer_type] != 16368c2ecf20Sopenharmony_ci diag_register->unique_id || 16378c2ecf20Sopenharmony_ci ioc->diag_buffer_sz[buffer_type] != 16388c2ecf20Sopenharmony_ci diag_register->requested_buffer_size || 16398c2ecf20Sopenharmony_ci !(ioc->diag_buffer_status[buffer_type] & 16408c2ecf20Sopenharmony_ci MPT3_DIAG_BUFFER_IS_RELEASED)) { 16418c2ecf20Sopenharmony_ci ioc_err(ioc, 16428c2ecf20Sopenharmony_ci "%s: already has a registered buffer for buffer_type(0x%02x)\n", 16438c2ecf20Sopenharmony_ci __func__, buffer_type); 16448c2ecf20Sopenharmony_ci return -EINVAL; 16458c2ecf20Sopenharmony_ci } 16468c2ecf20Sopenharmony_ci } else { 16478c2ecf20Sopenharmony_ci ioc_err(ioc, "%s: already has a registered buffer for buffer_type(0x%02x)\n", 16488c2ecf20Sopenharmony_ci __func__, buffer_type); 16498c2ecf20Sopenharmony_ci return -EINVAL; 16508c2ecf20Sopenharmony_ci } 16518c2ecf20Sopenharmony_ci } else if (ioc->diag_buffer_status[buffer_type] & 16528c2ecf20Sopenharmony_ci MPT3_DIAG_BUFFER_IS_DRIVER_ALLOCATED) { 16538c2ecf20Sopenharmony_ci 16548c2ecf20Sopenharmony_ci if (ioc->unique_id[buffer_type] != MPT3DIAGBUFFUNIQUEID || 16558c2ecf20Sopenharmony_ci ioc->diag_buffer_sz[buffer_type] != 16568c2ecf20Sopenharmony_ci diag_register->requested_buffer_size) { 16578c2ecf20Sopenharmony_ci 16588c2ecf20Sopenharmony_ci ioc_err(ioc, 16598c2ecf20Sopenharmony_ci "%s: already a buffer is allocated for buffer_type(0x%02x) of size %d bytes, so please try registering again with same size\n", 16608c2ecf20Sopenharmony_ci __func__, buffer_type, 16618c2ecf20Sopenharmony_ci ioc->diag_buffer_sz[buffer_type]); 16628c2ecf20Sopenharmony_ci return -EINVAL; 16638c2ecf20Sopenharmony_ci } 16648c2ecf20Sopenharmony_ci } 16658c2ecf20Sopenharmony_ci 16668c2ecf20Sopenharmony_ci if (diag_register->requested_buffer_size % 4) { 16678c2ecf20Sopenharmony_ci ioc_err(ioc, "%s: the requested_buffer_size is not 4 byte aligned\n", 16688c2ecf20Sopenharmony_ci __func__); 16698c2ecf20Sopenharmony_ci return -EINVAL; 16708c2ecf20Sopenharmony_ci } 16718c2ecf20Sopenharmony_ci 16728c2ecf20Sopenharmony_ci smid = mpt3sas_base_get_smid(ioc, ioc->ctl_cb_idx); 16738c2ecf20Sopenharmony_ci if (!smid) { 16748c2ecf20Sopenharmony_ci ioc_err(ioc, "%s: failed obtaining a smid\n", __func__); 16758c2ecf20Sopenharmony_ci rc = -EAGAIN; 16768c2ecf20Sopenharmony_ci goto out; 16778c2ecf20Sopenharmony_ci } 16788c2ecf20Sopenharmony_ci 16798c2ecf20Sopenharmony_ci rc = 0; 16808c2ecf20Sopenharmony_ci ioc->ctl_cmds.status = MPT3_CMD_PENDING; 16818c2ecf20Sopenharmony_ci memset(ioc->ctl_cmds.reply, 0, ioc->reply_sz); 16828c2ecf20Sopenharmony_ci mpi_request = mpt3sas_base_get_msg_frame(ioc, smid); 16838c2ecf20Sopenharmony_ci ioc->ctl_cmds.smid = smid; 16848c2ecf20Sopenharmony_ci 16858c2ecf20Sopenharmony_ci request_data = ioc->diag_buffer[buffer_type]; 16868c2ecf20Sopenharmony_ci request_data_sz = diag_register->requested_buffer_size; 16878c2ecf20Sopenharmony_ci ioc->unique_id[buffer_type] = diag_register->unique_id; 16888c2ecf20Sopenharmony_ci ioc->diag_buffer_status[buffer_type] &= 16898c2ecf20Sopenharmony_ci MPT3_DIAG_BUFFER_IS_DRIVER_ALLOCATED; 16908c2ecf20Sopenharmony_ci memcpy(ioc->product_specific[buffer_type], 16918c2ecf20Sopenharmony_ci diag_register->product_specific, MPT3_PRODUCT_SPECIFIC_DWORDS); 16928c2ecf20Sopenharmony_ci ioc->diagnostic_flags[buffer_type] = diag_register->diagnostic_flags; 16938c2ecf20Sopenharmony_ci 16948c2ecf20Sopenharmony_ci if (request_data) { 16958c2ecf20Sopenharmony_ci request_data_dma = ioc->diag_buffer_dma[buffer_type]; 16968c2ecf20Sopenharmony_ci if (request_data_sz != ioc->diag_buffer_sz[buffer_type]) { 16978c2ecf20Sopenharmony_ci dma_free_coherent(&ioc->pdev->dev, 16988c2ecf20Sopenharmony_ci ioc->diag_buffer_sz[buffer_type], 16998c2ecf20Sopenharmony_ci request_data, request_data_dma); 17008c2ecf20Sopenharmony_ci request_data = NULL; 17018c2ecf20Sopenharmony_ci } 17028c2ecf20Sopenharmony_ci } 17038c2ecf20Sopenharmony_ci 17048c2ecf20Sopenharmony_ci if (request_data == NULL) { 17058c2ecf20Sopenharmony_ci ioc->diag_buffer_sz[buffer_type] = 0; 17068c2ecf20Sopenharmony_ci ioc->diag_buffer_dma[buffer_type] = 0; 17078c2ecf20Sopenharmony_ci request_data = dma_alloc_coherent(&ioc->pdev->dev, 17088c2ecf20Sopenharmony_ci request_data_sz, &request_data_dma, GFP_KERNEL); 17098c2ecf20Sopenharmony_ci if (request_data == NULL) { 17108c2ecf20Sopenharmony_ci ioc_err(ioc, "%s: failed allocating memory for diag buffers, requested size(%d)\n", 17118c2ecf20Sopenharmony_ci __func__, request_data_sz); 17128c2ecf20Sopenharmony_ci mpt3sas_base_free_smid(ioc, smid); 17138c2ecf20Sopenharmony_ci rc = -ENOMEM; 17148c2ecf20Sopenharmony_ci goto out; 17158c2ecf20Sopenharmony_ci } 17168c2ecf20Sopenharmony_ci ioc->diag_buffer[buffer_type] = request_data; 17178c2ecf20Sopenharmony_ci ioc->diag_buffer_sz[buffer_type] = request_data_sz; 17188c2ecf20Sopenharmony_ci ioc->diag_buffer_dma[buffer_type] = request_data_dma; 17198c2ecf20Sopenharmony_ci } 17208c2ecf20Sopenharmony_ci 17218c2ecf20Sopenharmony_ci mpi_request->Function = MPI2_FUNCTION_DIAG_BUFFER_POST; 17228c2ecf20Sopenharmony_ci mpi_request->BufferType = diag_register->buffer_type; 17238c2ecf20Sopenharmony_ci mpi_request->Flags = cpu_to_le32(diag_register->diagnostic_flags); 17248c2ecf20Sopenharmony_ci mpi_request->BufferAddress = cpu_to_le64(request_data_dma); 17258c2ecf20Sopenharmony_ci mpi_request->BufferLength = cpu_to_le32(request_data_sz); 17268c2ecf20Sopenharmony_ci mpi_request->VF_ID = 0; /* TODO */ 17278c2ecf20Sopenharmony_ci mpi_request->VP_ID = 0; 17288c2ecf20Sopenharmony_ci 17298c2ecf20Sopenharmony_ci dctlprintk(ioc, 17308c2ecf20Sopenharmony_ci ioc_info(ioc, "%s: diag_buffer(0x%p), dma(0x%llx), sz(%d)\n", 17318c2ecf20Sopenharmony_ci __func__, request_data, 17328c2ecf20Sopenharmony_ci (unsigned long long)request_data_dma, 17338c2ecf20Sopenharmony_ci le32_to_cpu(mpi_request->BufferLength))); 17348c2ecf20Sopenharmony_ci 17358c2ecf20Sopenharmony_ci for (i = 0; i < MPT3_PRODUCT_SPECIFIC_DWORDS; i++) 17368c2ecf20Sopenharmony_ci mpi_request->ProductSpecific[i] = 17378c2ecf20Sopenharmony_ci cpu_to_le32(ioc->product_specific[buffer_type][i]); 17388c2ecf20Sopenharmony_ci 17398c2ecf20Sopenharmony_ci init_completion(&ioc->ctl_cmds.done); 17408c2ecf20Sopenharmony_ci ioc->put_smid_default(ioc, smid); 17418c2ecf20Sopenharmony_ci wait_for_completion_timeout(&ioc->ctl_cmds.done, 17428c2ecf20Sopenharmony_ci MPT3_IOCTL_DEFAULT_TIMEOUT*HZ); 17438c2ecf20Sopenharmony_ci 17448c2ecf20Sopenharmony_ci if (!(ioc->ctl_cmds.status & MPT3_CMD_COMPLETE)) { 17458c2ecf20Sopenharmony_ci mpt3sas_check_cmd_timeout(ioc, 17468c2ecf20Sopenharmony_ci ioc->ctl_cmds.status, mpi_request, 17478c2ecf20Sopenharmony_ci sizeof(Mpi2DiagBufferPostRequest_t)/4, issue_reset); 17488c2ecf20Sopenharmony_ci goto issue_host_reset; 17498c2ecf20Sopenharmony_ci } 17508c2ecf20Sopenharmony_ci 17518c2ecf20Sopenharmony_ci /* process the completed Reply Message Frame */ 17528c2ecf20Sopenharmony_ci if ((ioc->ctl_cmds.status & MPT3_CMD_REPLY_VALID) == 0) { 17538c2ecf20Sopenharmony_ci ioc_err(ioc, "%s: no reply message\n", __func__); 17548c2ecf20Sopenharmony_ci rc = -EFAULT; 17558c2ecf20Sopenharmony_ci goto out; 17568c2ecf20Sopenharmony_ci } 17578c2ecf20Sopenharmony_ci 17588c2ecf20Sopenharmony_ci mpi_reply = ioc->ctl_cmds.reply; 17598c2ecf20Sopenharmony_ci ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & MPI2_IOCSTATUS_MASK; 17608c2ecf20Sopenharmony_ci 17618c2ecf20Sopenharmony_ci if (ioc_status == MPI2_IOCSTATUS_SUCCESS) { 17628c2ecf20Sopenharmony_ci ioc->diag_buffer_status[buffer_type] |= 17638c2ecf20Sopenharmony_ci MPT3_DIAG_BUFFER_IS_REGISTERED; 17648c2ecf20Sopenharmony_ci dctlprintk(ioc, ioc_info(ioc, "%s: success\n", __func__)); 17658c2ecf20Sopenharmony_ci } else { 17668c2ecf20Sopenharmony_ci ioc_info(ioc, "%s: ioc_status(0x%04x) log_info(0x%08x)\n", 17678c2ecf20Sopenharmony_ci __func__, 17688c2ecf20Sopenharmony_ci ioc_status, le32_to_cpu(mpi_reply->IOCLogInfo)); 17698c2ecf20Sopenharmony_ci rc = -EFAULT; 17708c2ecf20Sopenharmony_ci } 17718c2ecf20Sopenharmony_ci 17728c2ecf20Sopenharmony_ci issue_host_reset: 17738c2ecf20Sopenharmony_ci if (issue_reset) 17748c2ecf20Sopenharmony_ci mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER); 17758c2ecf20Sopenharmony_ci 17768c2ecf20Sopenharmony_ci out: 17778c2ecf20Sopenharmony_ci 17788c2ecf20Sopenharmony_ci if (rc && request_data) { 17798c2ecf20Sopenharmony_ci dma_free_coherent(&ioc->pdev->dev, request_data_sz, 17808c2ecf20Sopenharmony_ci request_data, request_data_dma); 17818c2ecf20Sopenharmony_ci ioc->diag_buffer_status[buffer_type] &= 17828c2ecf20Sopenharmony_ci ~MPT3_DIAG_BUFFER_IS_DRIVER_ALLOCATED; 17838c2ecf20Sopenharmony_ci } 17848c2ecf20Sopenharmony_ci 17858c2ecf20Sopenharmony_ci ioc->ctl_cmds.status = MPT3_CMD_NOT_USED; 17868c2ecf20Sopenharmony_ci return rc; 17878c2ecf20Sopenharmony_ci} 17888c2ecf20Sopenharmony_ci 17898c2ecf20Sopenharmony_ci/** 17908c2ecf20Sopenharmony_ci * mpt3sas_enable_diag_buffer - enabling diag_buffers support driver load time 17918c2ecf20Sopenharmony_ci * @ioc: per adapter object 17928c2ecf20Sopenharmony_ci * @bits_to_register: bitwise field where trace is bit 0, and snapshot is bit 1 17938c2ecf20Sopenharmony_ci * 17948c2ecf20Sopenharmony_ci * This is called when command line option diag_buffer_enable is enabled 17958c2ecf20Sopenharmony_ci * at driver load time. 17968c2ecf20Sopenharmony_ci */ 17978c2ecf20Sopenharmony_civoid 17988c2ecf20Sopenharmony_cimpt3sas_enable_diag_buffer(struct MPT3SAS_ADAPTER *ioc, u8 bits_to_register) 17998c2ecf20Sopenharmony_ci{ 18008c2ecf20Sopenharmony_ci struct mpt3_diag_register diag_register; 18018c2ecf20Sopenharmony_ci u32 ret_val; 18028c2ecf20Sopenharmony_ci u32 trace_buff_size = ioc->manu_pg11.HostTraceBufferMaxSizeKB<<10; 18038c2ecf20Sopenharmony_ci u32 min_trace_buff_size = 0; 18048c2ecf20Sopenharmony_ci u32 decr_trace_buff_size = 0; 18058c2ecf20Sopenharmony_ci 18068c2ecf20Sopenharmony_ci memset(&diag_register, 0, sizeof(struct mpt3_diag_register)); 18078c2ecf20Sopenharmony_ci 18088c2ecf20Sopenharmony_ci if (bits_to_register & 1) { 18098c2ecf20Sopenharmony_ci ioc_info(ioc, "registering trace buffer support\n"); 18108c2ecf20Sopenharmony_ci ioc->diag_trigger_master.MasterData = 18118c2ecf20Sopenharmony_ci (MASTER_TRIGGER_FW_FAULT + MASTER_TRIGGER_ADAPTER_RESET); 18128c2ecf20Sopenharmony_ci diag_register.buffer_type = MPI2_DIAG_BUF_TYPE_TRACE; 18138c2ecf20Sopenharmony_ci diag_register.unique_id = 18148c2ecf20Sopenharmony_ci (ioc->hba_mpi_version_belonged == MPI2_VERSION) ? 18158c2ecf20Sopenharmony_ci (MPT2DIAGBUFFUNIQUEID):(MPT3DIAGBUFFUNIQUEID); 18168c2ecf20Sopenharmony_ci 18178c2ecf20Sopenharmony_ci if (trace_buff_size != 0) { 18188c2ecf20Sopenharmony_ci diag_register.requested_buffer_size = trace_buff_size; 18198c2ecf20Sopenharmony_ci min_trace_buff_size = 18208c2ecf20Sopenharmony_ci ioc->manu_pg11.HostTraceBufferMinSizeKB<<10; 18218c2ecf20Sopenharmony_ci decr_trace_buff_size = 18228c2ecf20Sopenharmony_ci ioc->manu_pg11.HostTraceBufferDecrementSizeKB<<10; 18238c2ecf20Sopenharmony_ci 18248c2ecf20Sopenharmony_ci if (min_trace_buff_size > trace_buff_size) { 18258c2ecf20Sopenharmony_ci /* The buff size is not set correctly */ 18268c2ecf20Sopenharmony_ci ioc_err(ioc, 18278c2ecf20Sopenharmony_ci "Min Trace Buff size (%d KB) greater than Max Trace Buff size (%d KB)\n", 18288c2ecf20Sopenharmony_ci min_trace_buff_size>>10, 18298c2ecf20Sopenharmony_ci trace_buff_size>>10); 18308c2ecf20Sopenharmony_ci ioc_err(ioc, 18318c2ecf20Sopenharmony_ci "Using zero Min Trace Buff Size\n"); 18328c2ecf20Sopenharmony_ci min_trace_buff_size = 0; 18338c2ecf20Sopenharmony_ci } 18348c2ecf20Sopenharmony_ci 18358c2ecf20Sopenharmony_ci if (decr_trace_buff_size == 0) { 18368c2ecf20Sopenharmony_ci /* 18378c2ecf20Sopenharmony_ci * retry the min size if decrement 18388c2ecf20Sopenharmony_ci * is not available. 18398c2ecf20Sopenharmony_ci */ 18408c2ecf20Sopenharmony_ci decr_trace_buff_size = 18418c2ecf20Sopenharmony_ci trace_buff_size - min_trace_buff_size; 18428c2ecf20Sopenharmony_ci } 18438c2ecf20Sopenharmony_ci } else { 18448c2ecf20Sopenharmony_ci /* register for 2MB buffers */ 18458c2ecf20Sopenharmony_ci diag_register.requested_buffer_size = 2 * (1024 * 1024); 18468c2ecf20Sopenharmony_ci } 18478c2ecf20Sopenharmony_ci 18488c2ecf20Sopenharmony_ci do { 18498c2ecf20Sopenharmony_ci ret_val = _ctl_diag_register_2(ioc, &diag_register); 18508c2ecf20Sopenharmony_ci 18518c2ecf20Sopenharmony_ci if (ret_val == -ENOMEM && min_trace_buff_size && 18528c2ecf20Sopenharmony_ci (trace_buff_size - decr_trace_buff_size) >= 18538c2ecf20Sopenharmony_ci min_trace_buff_size) { 18548c2ecf20Sopenharmony_ci /* adjust the buffer size */ 18558c2ecf20Sopenharmony_ci trace_buff_size -= decr_trace_buff_size; 18568c2ecf20Sopenharmony_ci diag_register.requested_buffer_size = 18578c2ecf20Sopenharmony_ci trace_buff_size; 18588c2ecf20Sopenharmony_ci } else 18598c2ecf20Sopenharmony_ci break; 18608c2ecf20Sopenharmony_ci } while (true); 18618c2ecf20Sopenharmony_ci 18628c2ecf20Sopenharmony_ci if (ret_val == -ENOMEM) 18638c2ecf20Sopenharmony_ci ioc_err(ioc, 18648c2ecf20Sopenharmony_ci "Cannot allocate trace buffer memory. Last memory tried = %d KB\n", 18658c2ecf20Sopenharmony_ci diag_register.requested_buffer_size>>10); 18668c2ecf20Sopenharmony_ci else if (ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] 18678c2ecf20Sopenharmony_ci & MPT3_DIAG_BUFFER_IS_REGISTERED) { 18688c2ecf20Sopenharmony_ci ioc_err(ioc, "Trace buffer memory %d KB allocated\n", 18698c2ecf20Sopenharmony_ci diag_register.requested_buffer_size>>10); 18708c2ecf20Sopenharmony_ci if (ioc->hba_mpi_version_belonged != MPI2_VERSION) 18718c2ecf20Sopenharmony_ci ioc->diag_buffer_status[ 18728c2ecf20Sopenharmony_ci MPI2_DIAG_BUF_TYPE_TRACE] |= 18738c2ecf20Sopenharmony_ci MPT3_DIAG_BUFFER_IS_DRIVER_ALLOCATED; 18748c2ecf20Sopenharmony_ci } 18758c2ecf20Sopenharmony_ci } 18768c2ecf20Sopenharmony_ci 18778c2ecf20Sopenharmony_ci if (bits_to_register & 2) { 18788c2ecf20Sopenharmony_ci ioc_info(ioc, "registering snapshot buffer support\n"); 18798c2ecf20Sopenharmony_ci diag_register.buffer_type = MPI2_DIAG_BUF_TYPE_SNAPSHOT; 18808c2ecf20Sopenharmony_ci /* register for 2MB buffers */ 18818c2ecf20Sopenharmony_ci diag_register.requested_buffer_size = 2 * (1024 * 1024); 18828c2ecf20Sopenharmony_ci diag_register.unique_id = 0x7075901; 18838c2ecf20Sopenharmony_ci _ctl_diag_register_2(ioc, &diag_register); 18848c2ecf20Sopenharmony_ci } 18858c2ecf20Sopenharmony_ci 18868c2ecf20Sopenharmony_ci if (bits_to_register & 4) { 18878c2ecf20Sopenharmony_ci ioc_info(ioc, "registering extended buffer support\n"); 18888c2ecf20Sopenharmony_ci diag_register.buffer_type = MPI2_DIAG_BUF_TYPE_EXTENDED; 18898c2ecf20Sopenharmony_ci /* register for 2MB buffers */ 18908c2ecf20Sopenharmony_ci diag_register.requested_buffer_size = 2 * (1024 * 1024); 18918c2ecf20Sopenharmony_ci diag_register.unique_id = 0x7075901; 18928c2ecf20Sopenharmony_ci _ctl_diag_register_2(ioc, &diag_register); 18938c2ecf20Sopenharmony_ci } 18948c2ecf20Sopenharmony_ci} 18958c2ecf20Sopenharmony_ci 18968c2ecf20Sopenharmony_ci/** 18978c2ecf20Sopenharmony_ci * _ctl_diag_register - application register with driver 18988c2ecf20Sopenharmony_ci * @ioc: per adapter object 18998c2ecf20Sopenharmony_ci * @arg: user space buffer containing ioctl content 19008c2ecf20Sopenharmony_ci * 19018c2ecf20Sopenharmony_ci * This will allow the driver to setup any required buffers that will be 19028c2ecf20Sopenharmony_ci * needed by firmware to communicate with the driver. 19038c2ecf20Sopenharmony_ci */ 19048c2ecf20Sopenharmony_cistatic long 19058c2ecf20Sopenharmony_ci_ctl_diag_register(struct MPT3SAS_ADAPTER *ioc, void __user *arg) 19068c2ecf20Sopenharmony_ci{ 19078c2ecf20Sopenharmony_ci struct mpt3_diag_register karg; 19088c2ecf20Sopenharmony_ci long rc; 19098c2ecf20Sopenharmony_ci 19108c2ecf20Sopenharmony_ci if (copy_from_user(&karg, arg, sizeof(karg))) { 19118c2ecf20Sopenharmony_ci pr_err("failure at %s:%d/%s()!\n", 19128c2ecf20Sopenharmony_ci __FILE__, __LINE__, __func__); 19138c2ecf20Sopenharmony_ci return -EFAULT; 19148c2ecf20Sopenharmony_ci } 19158c2ecf20Sopenharmony_ci 19168c2ecf20Sopenharmony_ci rc = _ctl_diag_register_2(ioc, &karg); 19178c2ecf20Sopenharmony_ci 19188c2ecf20Sopenharmony_ci if (!rc && (ioc->diag_buffer_status[karg.buffer_type] & 19198c2ecf20Sopenharmony_ci MPT3_DIAG_BUFFER_IS_REGISTERED)) 19208c2ecf20Sopenharmony_ci ioc->diag_buffer_status[karg.buffer_type] |= 19218c2ecf20Sopenharmony_ci MPT3_DIAG_BUFFER_IS_APP_OWNED; 19228c2ecf20Sopenharmony_ci 19238c2ecf20Sopenharmony_ci return rc; 19248c2ecf20Sopenharmony_ci} 19258c2ecf20Sopenharmony_ci 19268c2ecf20Sopenharmony_ci/** 19278c2ecf20Sopenharmony_ci * _ctl_diag_unregister - application unregister with driver 19288c2ecf20Sopenharmony_ci * @ioc: per adapter object 19298c2ecf20Sopenharmony_ci * @arg: user space buffer containing ioctl content 19308c2ecf20Sopenharmony_ci * 19318c2ecf20Sopenharmony_ci * This will allow the driver to cleanup any memory allocated for diag 19328c2ecf20Sopenharmony_ci * messages and to free up any resources. 19338c2ecf20Sopenharmony_ci */ 19348c2ecf20Sopenharmony_cistatic long 19358c2ecf20Sopenharmony_ci_ctl_diag_unregister(struct MPT3SAS_ADAPTER *ioc, void __user *arg) 19368c2ecf20Sopenharmony_ci{ 19378c2ecf20Sopenharmony_ci struct mpt3_diag_unregister karg; 19388c2ecf20Sopenharmony_ci void *request_data; 19398c2ecf20Sopenharmony_ci dma_addr_t request_data_dma; 19408c2ecf20Sopenharmony_ci u32 request_data_sz; 19418c2ecf20Sopenharmony_ci u8 buffer_type; 19428c2ecf20Sopenharmony_ci 19438c2ecf20Sopenharmony_ci if (copy_from_user(&karg, arg, sizeof(karg))) { 19448c2ecf20Sopenharmony_ci pr_err("failure at %s:%d/%s()!\n", 19458c2ecf20Sopenharmony_ci __FILE__, __LINE__, __func__); 19468c2ecf20Sopenharmony_ci return -EFAULT; 19478c2ecf20Sopenharmony_ci } 19488c2ecf20Sopenharmony_ci 19498c2ecf20Sopenharmony_ci dctlprintk(ioc, ioc_info(ioc, "%s\n", 19508c2ecf20Sopenharmony_ci __func__)); 19518c2ecf20Sopenharmony_ci 19528c2ecf20Sopenharmony_ci buffer_type = _ctl_diag_get_bufftype(ioc, karg.unique_id); 19538c2ecf20Sopenharmony_ci if (buffer_type == MPT3_DIAG_UID_NOT_FOUND) { 19548c2ecf20Sopenharmony_ci ioc_err(ioc, "%s: buffer with unique_id(0x%08x) not found\n", 19558c2ecf20Sopenharmony_ci __func__, karg.unique_id); 19568c2ecf20Sopenharmony_ci return -EINVAL; 19578c2ecf20Sopenharmony_ci } 19588c2ecf20Sopenharmony_ci 19598c2ecf20Sopenharmony_ci if (!_ctl_diag_capability(ioc, buffer_type)) { 19608c2ecf20Sopenharmony_ci ioc_err(ioc, "%s: doesn't have capability for buffer_type(0x%02x)\n", 19618c2ecf20Sopenharmony_ci __func__, buffer_type); 19628c2ecf20Sopenharmony_ci return -EPERM; 19638c2ecf20Sopenharmony_ci } 19648c2ecf20Sopenharmony_ci 19658c2ecf20Sopenharmony_ci if ((ioc->diag_buffer_status[buffer_type] & 19668c2ecf20Sopenharmony_ci MPT3_DIAG_BUFFER_IS_REGISTERED) == 0) { 19678c2ecf20Sopenharmony_ci ioc_err(ioc, "%s: buffer_type(0x%02x) is not registered\n", 19688c2ecf20Sopenharmony_ci __func__, buffer_type); 19698c2ecf20Sopenharmony_ci return -EINVAL; 19708c2ecf20Sopenharmony_ci } 19718c2ecf20Sopenharmony_ci if ((ioc->diag_buffer_status[buffer_type] & 19728c2ecf20Sopenharmony_ci MPT3_DIAG_BUFFER_IS_RELEASED) == 0) { 19738c2ecf20Sopenharmony_ci ioc_err(ioc, "%s: buffer_type(0x%02x) has not been released\n", 19748c2ecf20Sopenharmony_ci __func__, buffer_type); 19758c2ecf20Sopenharmony_ci return -EINVAL; 19768c2ecf20Sopenharmony_ci } 19778c2ecf20Sopenharmony_ci 19788c2ecf20Sopenharmony_ci if (karg.unique_id != ioc->unique_id[buffer_type]) { 19798c2ecf20Sopenharmony_ci ioc_err(ioc, "%s: unique_id(0x%08x) is not registered\n", 19808c2ecf20Sopenharmony_ci __func__, karg.unique_id); 19818c2ecf20Sopenharmony_ci return -EINVAL; 19828c2ecf20Sopenharmony_ci } 19838c2ecf20Sopenharmony_ci 19848c2ecf20Sopenharmony_ci request_data = ioc->diag_buffer[buffer_type]; 19858c2ecf20Sopenharmony_ci if (!request_data) { 19868c2ecf20Sopenharmony_ci ioc_err(ioc, "%s: doesn't have memory allocated for buffer_type(0x%02x)\n", 19878c2ecf20Sopenharmony_ci __func__, buffer_type); 19888c2ecf20Sopenharmony_ci return -ENOMEM; 19898c2ecf20Sopenharmony_ci } 19908c2ecf20Sopenharmony_ci 19918c2ecf20Sopenharmony_ci if (ioc->diag_buffer_status[buffer_type] & 19928c2ecf20Sopenharmony_ci MPT3_DIAG_BUFFER_IS_DRIVER_ALLOCATED) { 19938c2ecf20Sopenharmony_ci ioc->unique_id[buffer_type] = MPT3DIAGBUFFUNIQUEID; 19948c2ecf20Sopenharmony_ci ioc->diag_buffer_status[buffer_type] &= 19958c2ecf20Sopenharmony_ci ~MPT3_DIAG_BUFFER_IS_APP_OWNED; 19968c2ecf20Sopenharmony_ci ioc->diag_buffer_status[buffer_type] &= 19978c2ecf20Sopenharmony_ci ~MPT3_DIAG_BUFFER_IS_REGISTERED; 19988c2ecf20Sopenharmony_ci } else { 19998c2ecf20Sopenharmony_ci request_data_sz = ioc->diag_buffer_sz[buffer_type]; 20008c2ecf20Sopenharmony_ci request_data_dma = ioc->diag_buffer_dma[buffer_type]; 20018c2ecf20Sopenharmony_ci dma_free_coherent(&ioc->pdev->dev, request_data_sz, 20028c2ecf20Sopenharmony_ci request_data, request_data_dma); 20038c2ecf20Sopenharmony_ci ioc->diag_buffer[buffer_type] = NULL; 20048c2ecf20Sopenharmony_ci ioc->diag_buffer_status[buffer_type] = 0; 20058c2ecf20Sopenharmony_ci } 20068c2ecf20Sopenharmony_ci return 0; 20078c2ecf20Sopenharmony_ci} 20088c2ecf20Sopenharmony_ci 20098c2ecf20Sopenharmony_ci/** 20108c2ecf20Sopenharmony_ci * _ctl_diag_query - query relevant info associated with diag buffers 20118c2ecf20Sopenharmony_ci * @ioc: per adapter object 20128c2ecf20Sopenharmony_ci * @arg: user space buffer containing ioctl content 20138c2ecf20Sopenharmony_ci * 20148c2ecf20Sopenharmony_ci * The application will send only buffer_type and unique_id. Driver will 20158c2ecf20Sopenharmony_ci * inspect unique_id first, if valid, fill in all the info. If unique_id is 20168c2ecf20Sopenharmony_ci * 0x00, the driver will return info specified by Buffer Type. 20178c2ecf20Sopenharmony_ci */ 20188c2ecf20Sopenharmony_cistatic long 20198c2ecf20Sopenharmony_ci_ctl_diag_query(struct MPT3SAS_ADAPTER *ioc, void __user *arg) 20208c2ecf20Sopenharmony_ci{ 20218c2ecf20Sopenharmony_ci struct mpt3_diag_query karg; 20228c2ecf20Sopenharmony_ci void *request_data; 20238c2ecf20Sopenharmony_ci int i; 20248c2ecf20Sopenharmony_ci u8 buffer_type; 20258c2ecf20Sopenharmony_ci 20268c2ecf20Sopenharmony_ci if (copy_from_user(&karg, arg, sizeof(karg))) { 20278c2ecf20Sopenharmony_ci pr_err("failure at %s:%d/%s()!\n", 20288c2ecf20Sopenharmony_ci __FILE__, __LINE__, __func__); 20298c2ecf20Sopenharmony_ci return -EFAULT; 20308c2ecf20Sopenharmony_ci } 20318c2ecf20Sopenharmony_ci 20328c2ecf20Sopenharmony_ci dctlprintk(ioc, ioc_info(ioc, "%s\n", 20338c2ecf20Sopenharmony_ci __func__)); 20348c2ecf20Sopenharmony_ci 20358c2ecf20Sopenharmony_ci karg.application_flags = 0; 20368c2ecf20Sopenharmony_ci buffer_type = karg.buffer_type; 20378c2ecf20Sopenharmony_ci 20388c2ecf20Sopenharmony_ci if (!_ctl_diag_capability(ioc, buffer_type)) { 20398c2ecf20Sopenharmony_ci ioc_err(ioc, "%s: doesn't have capability for buffer_type(0x%02x)\n", 20408c2ecf20Sopenharmony_ci __func__, buffer_type); 20418c2ecf20Sopenharmony_ci return -EPERM; 20428c2ecf20Sopenharmony_ci } 20438c2ecf20Sopenharmony_ci 20448c2ecf20Sopenharmony_ci if (!(ioc->diag_buffer_status[buffer_type] & 20458c2ecf20Sopenharmony_ci MPT3_DIAG_BUFFER_IS_DRIVER_ALLOCATED)) { 20468c2ecf20Sopenharmony_ci if ((ioc->diag_buffer_status[buffer_type] & 20478c2ecf20Sopenharmony_ci MPT3_DIAG_BUFFER_IS_REGISTERED) == 0) { 20488c2ecf20Sopenharmony_ci ioc_err(ioc, "%s: buffer_type(0x%02x) is not registered\n", 20498c2ecf20Sopenharmony_ci __func__, buffer_type); 20508c2ecf20Sopenharmony_ci return -EINVAL; 20518c2ecf20Sopenharmony_ci } 20528c2ecf20Sopenharmony_ci } 20538c2ecf20Sopenharmony_ci 20548c2ecf20Sopenharmony_ci if (karg.unique_id) { 20558c2ecf20Sopenharmony_ci if (karg.unique_id != ioc->unique_id[buffer_type]) { 20568c2ecf20Sopenharmony_ci ioc_err(ioc, "%s: unique_id(0x%08x) is not registered\n", 20578c2ecf20Sopenharmony_ci __func__, karg.unique_id); 20588c2ecf20Sopenharmony_ci return -EINVAL; 20598c2ecf20Sopenharmony_ci } 20608c2ecf20Sopenharmony_ci } 20618c2ecf20Sopenharmony_ci 20628c2ecf20Sopenharmony_ci request_data = ioc->diag_buffer[buffer_type]; 20638c2ecf20Sopenharmony_ci if (!request_data) { 20648c2ecf20Sopenharmony_ci ioc_err(ioc, "%s: doesn't have buffer for buffer_type(0x%02x)\n", 20658c2ecf20Sopenharmony_ci __func__, buffer_type); 20668c2ecf20Sopenharmony_ci return -ENOMEM; 20678c2ecf20Sopenharmony_ci } 20688c2ecf20Sopenharmony_ci 20698c2ecf20Sopenharmony_ci if ((ioc->diag_buffer_status[buffer_type] & 20708c2ecf20Sopenharmony_ci MPT3_DIAG_BUFFER_IS_REGISTERED)) 20718c2ecf20Sopenharmony_ci karg.application_flags |= MPT3_APP_FLAGS_BUFFER_VALID; 20728c2ecf20Sopenharmony_ci 20738c2ecf20Sopenharmony_ci if (!(ioc->diag_buffer_status[buffer_type] & 20748c2ecf20Sopenharmony_ci MPT3_DIAG_BUFFER_IS_RELEASED)) 20758c2ecf20Sopenharmony_ci karg.application_flags |= MPT3_APP_FLAGS_FW_BUFFER_ACCESS; 20768c2ecf20Sopenharmony_ci 20778c2ecf20Sopenharmony_ci if (!(ioc->diag_buffer_status[buffer_type] & 20788c2ecf20Sopenharmony_ci MPT3_DIAG_BUFFER_IS_DRIVER_ALLOCATED)) 20798c2ecf20Sopenharmony_ci karg.application_flags |= MPT3_APP_FLAGS_DYNAMIC_BUFFER_ALLOC; 20808c2ecf20Sopenharmony_ci 20818c2ecf20Sopenharmony_ci if ((ioc->diag_buffer_status[buffer_type] & 20828c2ecf20Sopenharmony_ci MPT3_DIAG_BUFFER_IS_APP_OWNED)) 20838c2ecf20Sopenharmony_ci karg.application_flags |= MPT3_APP_FLAGS_APP_OWNED; 20848c2ecf20Sopenharmony_ci 20858c2ecf20Sopenharmony_ci for (i = 0; i < MPT3_PRODUCT_SPECIFIC_DWORDS; i++) 20868c2ecf20Sopenharmony_ci karg.product_specific[i] = 20878c2ecf20Sopenharmony_ci ioc->product_specific[buffer_type][i]; 20888c2ecf20Sopenharmony_ci 20898c2ecf20Sopenharmony_ci karg.total_buffer_size = ioc->diag_buffer_sz[buffer_type]; 20908c2ecf20Sopenharmony_ci karg.driver_added_buffer_size = 0; 20918c2ecf20Sopenharmony_ci karg.unique_id = ioc->unique_id[buffer_type]; 20928c2ecf20Sopenharmony_ci karg.diagnostic_flags = ioc->diagnostic_flags[buffer_type]; 20938c2ecf20Sopenharmony_ci 20948c2ecf20Sopenharmony_ci if (copy_to_user(arg, &karg, sizeof(struct mpt3_diag_query))) { 20958c2ecf20Sopenharmony_ci ioc_err(ioc, "%s: unable to write mpt3_diag_query data @ %p\n", 20968c2ecf20Sopenharmony_ci __func__, arg); 20978c2ecf20Sopenharmony_ci return -EFAULT; 20988c2ecf20Sopenharmony_ci } 20998c2ecf20Sopenharmony_ci return 0; 21008c2ecf20Sopenharmony_ci} 21018c2ecf20Sopenharmony_ci 21028c2ecf20Sopenharmony_ci/** 21038c2ecf20Sopenharmony_ci * mpt3sas_send_diag_release - Diag Release Message 21048c2ecf20Sopenharmony_ci * @ioc: per adapter object 21058c2ecf20Sopenharmony_ci * @buffer_type: specifies either TRACE, SNAPSHOT, or EXTENDED 21068c2ecf20Sopenharmony_ci * @issue_reset: specifies whether host reset is required. 21078c2ecf20Sopenharmony_ci * 21088c2ecf20Sopenharmony_ci */ 21098c2ecf20Sopenharmony_ciint 21108c2ecf20Sopenharmony_cimpt3sas_send_diag_release(struct MPT3SAS_ADAPTER *ioc, u8 buffer_type, 21118c2ecf20Sopenharmony_ci u8 *issue_reset) 21128c2ecf20Sopenharmony_ci{ 21138c2ecf20Sopenharmony_ci Mpi2DiagReleaseRequest_t *mpi_request; 21148c2ecf20Sopenharmony_ci Mpi2DiagReleaseReply_t *mpi_reply; 21158c2ecf20Sopenharmony_ci u16 smid; 21168c2ecf20Sopenharmony_ci u16 ioc_status; 21178c2ecf20Sopenharmony_ci u32 ioc_state; 21188c2ecf20Sopenharmony_ci int rc; 21198c2ecf20Sopenharmony_ci u8 reset_needed = 0; 21208c2ecf20Sopenharmony_ci 21218c2ecf20Sopenharmony_ci dctlprintk(ioc, ioc_info(ioc, "%s\n", 21228c2ecf20Sopenharmony_ci __func__)); 21238c2ecf20Sopenharmony_ci 21248c2ecf20Sopenharmony_ci rc = 0; 21258c2ecf20Sopenharmony_ci *issue_reset = 0; 21268c2ecf20Sopenharmony_ci 21278c2ecf20Sopenharmony_ci 21288c2ecf20Sopenharmony_ci ioc_state = mpt3sas_base_get_iocstate(ioc, 1); 21298c2ecf20Sopenharmony_ci if (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { 21308c2ecf20Sopenharmony_ci if (ioc->diag_buffer_status[buffer_type] & 21318c2ecf20Sopenharmony_ci MPT3_DIAG_BUFFER_IS_REGISTERED) 21328c2ecf20Sopenharmony_ci ioc->diag_buffer_status[buffer_type] |= 21338c2ecf20Sopenharmony_ci MPT3_DIAG_BUFFER_IS_RELEASED; 21348c2ecf20Sopenharmony_ci dctlprintk(ioc, 21358c2ecf20Sopenharmony_ci ioc_info(ioc, "%s: skipping due to FAULT state\n", 21368c2ecf20Sopenharmony_ci __func__)); 21378c2ecf20Sopenharmony_ci rc = -EAGAIN; 21388c2ecf20Sopenharmony_ci goto out; 21398c2ecf20Sopenharmony_ci } 21408c2ecf20Sopenharmony_ci 21418c2ecf20Sopenharmony_ci if (ioc->ctl_cmds.status != MPT3_CMD_NOT_USED) { 21428c2ecf20Sopenharmony_ci ioc_err(ioc, "%s: ctl_cmd in use\n", __func__); 21438c2ecf20Sopenharmony_ci rc = -EAGAIN; 21448c2ecf20Sopenharmony_ci goto out; 21458c2ecf20Sopenharmony_ci } 21468c2ecf20Sopenharmony_ci 21478c2ecf20Sopenharmony_ci smid = mpt3sas_base_get_smid(ioc, ioc->ctl_cb_idx); 21488c2ecf20Sopenharmony_ci if (!smid) { 21498c2ecf20Sopenharmony_ci ioc_err(ioc, "%s: failed obtaining a smid\n", __func__); 21508c2ecf20Sopenharmony_ci rc = -EAGAIN; 21518c2ecf20Sopenharmony_ci goto out; 21528c2ecf20Sopenharmony_ci } 21538c2ecf20Sopenharmony_ci 21548c2ecf20Sopenharmony_ci ioc->ctl_cmds.status = MPT3_CMD_PENDING; 21558c2ecf20Sopenharmony_ci memset(ioc->ctl_cmds.reply, 0, ioc->reply_sz); 21568c2ecf20Sopenharmony_ci mpi_request = mpt3sas_base_get_msg_frame(ioc, smid); 21578c2ecf20Sopenharmony_ci ioc->ctl_cmds.smid = smid; 21588c2ecf20Sopenharmony_ci 21598c2ecf20Sopenharmony_ci mpi_request->Function = MPI2_FUNCTION_DIAG_RELEASE; 21608c2ecf20Sopenharmony_ci mpi_request->BufferType = buffer_type; 21618c2ecf20Sopenharmony_ci mpi_request->VF_ID = 0; /* TODO */ 21628c2ecf20Sopenharmony_ci mpi_request->VP_ID = 0; 21638c2ecf20Sopenharmony_ci 21648c2ecf20Sopenharmony_ci init_completion(&ioc->ctl_cmds.done); 21658c2ecf20Sopenharmony_ci ioc->put_smid_default(ioc, smid); 21668c2ecf20Sopenharmony_ci wait_for_completion_timeout(&ioc->ctl_cmds.done, 21678c2ecf20Sopenharmony_ci MPT3_IOCTL_DEFAULT_TIMEOUT*HZ); 21688c2ecf20Sopenharmony_ci 21698c2ecf20Sopenharmony_ci if (!(ioc->ctl_cmds.status & MPT3_CMD_COMPLETE)) { 21708c2ecf20Sopenharmony_ci mpt3sas_check_cmd_timeout(ioc, 21718c2ecf20Sopenharmony_ci ioc->ctl_cmds.status, mpi_request, 21728c2ecf20Sopenharmony_ci sizeof(Mpi2DiagReleaseRequest_t)/4, reset_needed); 21738c2ecf20Sopenharmony_ci *issue_reset = reset_needed; 21748c2ecf20Sopenharmony_ci rc = -EFAULT; 21758c2ecf20Sopenharmony_ci goto out; 21768c2ecf20Sopenharmony_ci } 21778c2ecf20Sopenharmony_ci 21788c2ecf20Sopenharmony_ci /* process the completed Reply Message Frame */ 21798c2ecf20Sopenharmony_ci if ((ioc->ctl_cmds.status & MPT3_CMD_REPLY_VALID) == 0) { 21808c2ecf20Sopenharmony_ci ioc_err(ioc, "%s: no reply message\n", __func__); 21818c2ecf20Sopenharmony_ci rc = -EFAULT; 21828c2ecf20Sopenharmony_ci goto out; 21838c2ecf20Sopenharmony_ci } 21848c2ecf20Sopenharmony_ci 21858c2ecf20Sopenharmony_ci mpi_reply = ioc->ctl_cmds.reply; 21868c2ecf20Sopenharmony_ci ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & MPI2_IOCSTATUS_MASK; 21878c2ecf20Sopenharmony_ci 21888c2ecf20Sopenharmony_ci if (ioc_status == MPI2_IOCSTATUS_SUCCESS) { 21898c2ecf20Sopenharmony_ci ioc->diag_buffer_status[buffer_type] |= 21908c2ecf20Sopenharmony_ci MPT3_DIAG_BUFFER_IS_RELEASED; 21918c2ecf20Sopenharmony_ci dctlprintk(ioc, ioc_info(ioc, "%s: success\n", __func__)); 21928c2ecf20Sopenharmony_ci } else { 21938c2ecf20Sopenharmony_ci ioc_info(ioc, "%s: ioc_status(0x%04x) log_info(0x%08x)\n", 21948c2ecf20Sopenharmony_ci __func__, 21958c2ecf20Sopenharmony_ci ioc_status, le32_to_cpu(mpi_reply->IOCLogInfo)); 21968c2ecf20Sopenharmony_ci rc = -EFAULT; 21978c2ecf20Sopenharmony_ci } 21988c2ecf20Sopenharmony_ci 21998c2ecf20Sopenharmony_ci out: 22008c2ecf20Sopenharmony_ci ioc->ctl_cmds.status = MPT3_CMD_NOT_USED; 22018c2ecf20Sopenharmony_ci return rc; 22028c2ecf20Sopenharmony_ci} 22038c2ecf20Sopenharmony_ci 22048c2ecf20Sopenharmony_ci/** 22058c2ecf20Sopenharmony_ci * _ctl_diag_release - request to send Diag Release Message to firmware 22068c2ecf20Sopenharmony_ci * @ioc: ? 22078c2ecf20Sopenharmony_ci * @arg: user space buffer containing ioctl content 22088c2ecf20Sopenharmony_ci * 22098c2ecf20Sopenharmony_ci * This allows ownership of the specified buffer to returned to the driver, 22108c2ecf20Sopenharmony_ci * allowing an application to read the buffer without fear that firmware is 22118c2ecf20Sopenharmony_ci * overwriting information in the buffer. 22128c2ecf20Sopenharmony_ci */ 22138c2ecf20Sopenharmony_cistatic long 22148c2ecf20Sopenharmony_ci_ctl_diag_release(struct MPT3SAS_ADAPTER *ioc, void __user *arg) 22158c2ecf20Sopenharmony_ci{ 22168c2ecf20Sopenharmony_ci struct mpt3_diag_release karg; 22178c2ecf20Sopenharmony_ci void *request_data; 22188c2ecf20Sopenharmony_ci int rc; 22198c2ecf20Sopenharmony_ci u8 buffer_type; 22208c2ecf20Sopenharmony_ci u8 issue_reset = 0; 22218c2ecf20Sopenharmony_ci 22228c2ecf20Sopenharmony_ci if (copy_from_user(&karg, arg, sizeof(karg))) { 22238c2ecf20Sopenharmony_ci pr_err("failure at %s:%d/%s()!\n", 22248c2ecf20Sopenharmony_ci __FILE__, __LINE__, __func__); 22258c2ecf20Sopenharmony_ci return -EFAULT; 22268c2ecf20Sopenharmony_ci } 22278c2ecf20Sopenharmony_ci 22288c2ecf20Sopenharmony_ci dctlprintk(ioc, ioc_info(ioc, "%s\n", 22298c2ecf20Sopenharmony_ci __func__)); 22308c2ecf20Sopenharmony_ci 22318c2ecf20Sopenharmony_ci buffer_type = _ctl_diag_get_bufftype(ioc, karg.unique_id); 22328c2ecf20Sopenharmony_ci if (buffer_type == MPT3_DIAG_UID_NOT_FOUND) { 22338c2ecf20Sopenharmony_ci ioc_err(ioc, "%s: buffer with unique_id(0x%08x) not found\n", 22348c2ecf20Sopenharmony_ci __func__, karg.unique_id); 22358c2ecf20Sopenharmony_ci return -EINVAL; 22368c2ecf20Sopenharmony_ci } 22378c2ecf20Sopenharmony_ci 22388c2ecf20Sopenharmony_ci if (!_ctl_diag_capability(ioc, buffer_type)) { 22398c2ecf20Sopenharmony_ci ioc_err(ioc, "%s: doesn't have capability for buffer_type(0x%02x)\n", 22408c2ecf20Sopenharmony_ci __func__, buffer_type); 22418c2ecf20Sopenharmony_ci return -EPERM; 22428c2ecf20Sopenharmony_ci } 22438c2ecf20Sopenharmony_ci 22448c2ecf20Sopenharmony_ci if ((ioc->diag_buffer_status[buffer_type] & 22458c2ecf20Sopenharmony_ci MPT3_DIAG_BUFFER_IS_REGISTERED) == 0) { 22468c2ecf20Sopenharmony_ci ioc_err(ioc, "%s: buffer_type(0x%02x) is not registered\n", 22478c2ecf20Sopenharmony_ci __func__, buffer_type); 22488c2ecf20Sopenharmony_ci return -EINVAL; 22498c2ecf20Sopenharmony_ci } 22508c2ecf20Sopenharmony_ci 22518c2ecf20Sopenharmony_ci if (karg.unique_id != ioc->unique_id[buffer_type]) { 22528c2ecf20Sopenharmony_ci ioc_err(ioc, "%s: unique_id(0x%08x) is not registered\n", 22538c2ecf20Sopenharmony_ci __func__, karg.unique_id); 22548c2ecf20Sopenharmony_ci return -EINVAL; 22558c2ecf20Sopenharmony_ci } 22568c2ecf20Sopenharmony_ci 22578c2ecf20Sopenharmony_ci if (ioc->diag_buffer_status[buffer_type] & 22588c2ecf20Sopenharmony_ci MPT3_DIAG_BUFFER_IS_RELEASED) { 22598c2ecf20Sopenharmony_ci ioc_err(ioc, "%s: buffer_type(0x%02x) is already released\n", 22608c2ecf20Sopenharmony_ci __func__, buffer_type); 22618c2ecf20Sopenharmony_ci return -EINVAL; 22628c2ecf20Sopenharmony_ci } 22638c2ecf20Sopenharmony_ci 22648c2ecf20Sopenharmony_ci request_data = ioc->diag_buffer[buffer_type]; 22658c2ecf20Sopenharmony_ci 22668c2ecf20Sopenharmony_ci if (!request_data) { 22678c2ecf20Sopenharmony_ci ioc_err(ioc, "%s: doesn't have memory allocated for buffer_type(0x%02x)\n", 22688c2ecf20Sopenharmony_ci __func__, buffer_type); 22698c2ecf20Sopenharmony_ci return -ENOMEM; 22708c2ecf20Sopenharmony_ci } 22718c2ecf20Sopenharmony_ci 22728c2ecf20Sopenharmony_ci /* buffers were released by due to host reset */ 22738c2ecf20Sopenharmony_ci if ((ioc->diag_buffer_status[buffer_type] & 22748c2ecf20Sopenharmony_ci MPT3_DIAG_BUFFER_IS_DIAG_RESET)) { 22758c2ecf20Sopenharmony_ci ioc->diag_buffer_status[buffer_type] |= 22768c2ecf20Sopenharmony_ci MPT3_DIAG_BUFFER_IS_RELEASED; 22778c2ecf20Sopenharmony_ci ioc->diag_buffer_status[buffer_type] &= 22788c2ecf20Sopenharmony_ci ~MPT3_DIAG_BUFFER_IS_DIAG_RESET; 22798c2ecf20Sopenharmony_ci ioc_err(ioc, "%s: buffer_type(0x%02x) was released due to host reset\n", 22808c2ecf20Sopenharmony_ci __func__, buffer_type); 22818c2ecf20Sopenharmony_ci return 0; 22828c2ecf20Sopenharmony_ci } 22838c2ecf20Sopenharmony_ci 22848c2ecf20Sopenharmony_ci rc = mpt3sas_send_diag_release(ioc, buffer_type, &issue_reset); 22858c2ecf20Sopenharmony_ci 22868c2ecf20Sopenharmony_ci if (issue_reset) 22878c2ecf20Sopenharmony_ci mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER); 22888c2ecf20Sopenharmony_ci 22898c2ecf20Sopenharmony_ci return rc; 22908c2ecf20Sopenharmony_ci} 22918c2ecf20Sopenharmony_ci 22928c2ecf20Sopenharmony_ci/** 22938c2ecf20Sopenharmony_ci * _ctl_diag_read_buffer - request for copy of the diag buffer 22948c2ecf20Sopenharmony_ci * @ioc: per adapter object 22958c2ecf20Sopenharmony_ci * @arg: user space buffer containing ioctl content 22968c2ecf20Sopenharmony_ci */ 22978c2ecf20Sopenharmony_cistatic long 22988c2ecf20Sopenharmony_ci_ctl_diag_read_buffer(struct MPT3SAS_ADAPTER *ioc, void __user *arg) 22998c2ecf20Sopenharmony_ci{ 23008c2ecf20Sopenharmony_ci struct mpt3_diag_read_buffer karg; 23018c2ecf20Sopenharmony_ci struct mpt3_diag_read_buffer __user *uarg = arg; 23028c2ecf20Sopenharmony_ci void *request_data, *diag_data; 23038c2ecf20Sopenharmony_ci Mpi2DiagBufferPostRequest_t *mpi_request; 23048c2ecf20Sopenharmony_ci Mpi2DiagBufferPostReply_t *mpi_reply; 23058c2ecf20Sopenharmony_ci int rc, i; 23068c2ecf20Sopenharmony_ci u8 buffer_type; 23078c2ecf20Sopenharmony_ci unsigned long request_size, copy_size; 23088c2ecf20Sopenharmony_ci u16 smid; 23098c2ecf20Sopenharmony_ci u16 ioc_status; 23108c2ecf20Sopenharmony_ci u8 issue_reset = 0; 23118c2ecf20Sopenharmony_ci 23128c2ecf20Sopenharmony_ci if (copy_from_user(&karg, arg, sizeof(karg))) { 23138c2ecf20Sopenharmony_ci pr_err("failure at %s:%d/%s()!\n", 23148c2ecf20Sopenharmony_ci __FILE__, __LINE__, __func__); 23158c2ecf20Sopenharmony_ci return -EFAULT; 23168c2ecf20Sopenharmony_ci } 23178c2ecf20Sopenharmony_ci 23188c2ecf20Sopenharmony_ci dctlprintk(ioc, ioc_info(ioc, "%s\n", 23198c2ecf20Sopenharmony_ci __func__)); 23208c2ecf20Sopenharmony_ci 23218c2ecf20Sopenharmony_ci buffer_type = _ctl_diag_get_bufftype(ioc, karg.unique_id); 23228c2ecf20Sopenharmony_ci if (buffer_type == MPT3_DIAG_UID_NOT_FOUND) { 23238c2ecf20Sopenharmony_ci ioc_err(ioc, "%s: buffer with unique_id(0x%08x) not found\n", 23248c2ecf20Sopenharmony_ci __func__, karg.unique_id); 23258c2ecf20Sopenharmony_ci return -EINVAL; 23268c2ecf20Sopenharmony_ci } 23278c2ecf20Sopenharmony_ci 23288c2ecf20Sopenharmony_ci if (!_ctl_diag_capability(ioc, buffer_type)) { 23298c2ecf20Sopenharmony_ci ioc_err(ioc, "%s: doesn't have capability for buffer_type(0x%02x)\n", 23308c2ecf20Sopenharmony_ci __func__, buffer_type); 23318c2ecf20Sopenharmony_ci return -EPERM; 23328c2ecf20Sopenharmony_ci } 23338c2ecf20Sopenharmony_ci 23348c2ecf20Sopenharmony_ci if (karg.unique_id != ioc->unique_id[buffer_type]) { 23358c2ecf20Sopenharmony_ci ioc_err(ioc, "%s: unique_id(0x%08x) is not registered\n", 23368c2ecf20Sopenharmony_ci __func__, karg.unique_id); 23378c2ecf20Sopenharmony_ci return -EINVAL; 23388c2ecf20Sopenharmony_ci } 23398c2ecf20Sopenharmony_ci 23408c2ecf20Sopenharmony_ci request_data = ioc->diag_buffer[buffer_type]; 23418c2ecf20Sopenharmony_ci if (!request_data) { 23428c2ecf20Sopenharmony_ci ioc_err(ioc, "%s: doesn't have buffer for buffer_type(0x%02x)\n", 23438c2ecf20Sopenharmony_ci __func__, buffer_type); 23448c2ecf20Sopenharmony_ci return -ENOMEM; 23458c2ecf20Sopenharmony_ci } 23468c2ecf20Sopenharmony_ci 23478c2ecf20Sopenharmony_ci request_size = ioc->diag_buffer_sz[buffer_type]; 23488c2ecf20Sopenharmony_ci 23498c2ecf20Sopenharmony_ci if ((karg.starting_offset % 4) || (karg.bytes_to_read % 4)) { 23508c2ecf20Sopenharmony_ci ioc_err(ioc, "%s: either the starting_offset or bytes_to_read are not 4 byte aligned\n", 23518c2ecf20Sopenharmony_ci __func__); 23528c2ecf20Sopenharmony_ci return -EINVAL; 23538c2ecf20Sopenharmony_ci } 23548c2ecf20Sopenharmony_ci 23558c2ecf20Sopenharmony_ci if (karg.starting_offset > request_size) 23568c2ecf20Sopenharmony_ci return -EINVAL; 23578c2ecf20Sopenharmony_ci 23588c2ecf20Sopenharmony_ci diag_data = (void *)(request_data + karg.starting_offset); 23598c2ecf20Sopenharmony_ci dctlprintk(ioc, 23608c2ecf20Sopenharmony_ci ioc_info(ioc, "%s: diag_buffer(%p), offset(%d), sz(%d)\n", 23618c2ecf20Sopenharmony_ci __func__, diag_data, karg.starting_offset, 23628c2ecf20Sopenharmony_ci karg.bytes_to_read)); 23638c2ecf20Sopenharmony_ci 23648c2ecf20Sopenharmony_ci /* Truncate data on requests that are too large */ 23658c2ecf20Sopenharmony_ci if ((diag_data + karg.bytes_to_read < diag_data) || 23668c2ecf20Sopenharmony_ci (diag_data + karg.bytes_to_read > request_data + request_size)) 23678c2ecf20Sopenharmony_ci copy_size = request_size - karg.starting_offset; 23688c2ecf20Sopenharmony_ci else 23698c2ecf20Sopenharmony_ci copy_size = karg.bytes_to_read; 23708c2ecf20Sopenharmony_ci 23718c2ecf20Sopenharmony_ci if (copy_to_user((void __user *)uarg->diagnostic_data, 23728c2ecf20Sopenharmony_ci diag_data, copy_size)) { 23738c2ecf20Sopenharmony_ci ioc_err(ioc, "%s: Unable to write mpt_diag_read_buffer_t data @ %p\n", 23748c2ecf20Sopenharmony_ci __func__, diag_data); 23758c2ecf20Sopenharmony_ci return -EFAULT; 23768c2ecf20Sopenharmony_ci } 23778c2ecf20Sopenharmony_ci 23788c2ecf20Sopenharmony_ci if ((karg.flags & MPT3_FLAGS_REREGISTER) == 0) 23798c2ecf20Sopenharmony_ci return 0; 23808c2ecf20Sopenharmony_ci 23818c2ecf20Sopenharmony_ci dctlprintk(ioc, 23828c2ecf20Sopenharmony_ci ioc_info(ioc, "%s: Reregister buffer_type(0x%02x)\n", 23838c2ecf20Sopenharmony_ci __func__, buffer_type)); 23848c2ecf20Sopenharmony_ci if ((ioc->diag_buffer_status[buffer_type] & 23858c2ecf20Sopenharmony_ci MPT3_DIAG_BUFFER_IS_RELEASED) == 0) { 23868c2ecf20Sopenharmony_ci dctlprintk(ioc, 23878c2ecf20Sopenharmony_ci ioc_info(ioc, "%s: buffer_type(0x%02x) is still registered\n", 23888c2ecf20Sopenharmony_ci __func__, buffer_type)); 23898c2ecf20Sopenharmony_ci return 0; 23908c2ecf20Sopenharmony_ci } 23918c2ecf20Sopenharmony_ci /* Get a free request frame and save the message context. 23928c2ecf20Sopenharmony_ci */ 23938c2ecf20Sopenharmony_ci 23948c2ecf20Sopenharmony_ci if (ioc->ctl_cmds.status != MPT3_CMD_NOT_USED) { 23958c2ecf20Sopenharmony_ci ioc_err(ioc, "%s: ctl_cmd in use\n", __func__); 23968c2ecf20Sopenharmony_ci rc = -EAGAIN; 23978c2ecf20Sopenharmony_ci goto out; 23988c2ecf20Sopenharmony_ci } 23998c2ecf20Sopenharmony_ci 24008c2ecf20Sopenharmony_ci smid = mpt3sas_base_get_smid(ioc, ioc->ctl_cb_idx); 24018c2ecf20Sopenharmony_ci if (!smid) { 24028c2ecf20Sopenharmony_ci ioc_err(ioc, "%s: failed obtaining a smid\n", __func__); 24038c2ecf20Sopenharmony_ci rc = -EAGAIN; 24048c2ecf20Sopenharmony_ci goto out; 24058c2ecf20Sopenharmony_ci } 24068c2ecf20Sopenharmony_ci 24078c2ecf20Sopenharmony_ci rc = 0; 24088c2ecf20Sopenharmony_ci ioc->ctl_cmds.status = MPT3_CMD_PENDING; 24098c2ecf20Sopenharmony_ci memset(ioc->ctl_cmds.reply, 0, ioc->reply_sz); 24108c2ecf20Sopenharmony_ci mpi_request = mpt3sas_base_get_msg_frame(ioc, smid); 24118c2ecf20Sopenharmony_ci ioc->ctl_cmds.smid = smid; 24128c2ecf20Sopenharmony_ci 24138c2ecf20Sopenharmony_ci mpi_request->Function = MPI2_FUNCTION_DIAG_BUFFER_POST; 24148c2ecf20Sopenharmony_ci mpi_request->BufferType = buffer_type; 24158c2ecf20Sopenharmony_ci mpi_request->BufferLength = 24168c2ecf20Sopenharmony_ci cpu_to_le32(ioc->diag_buffer_sz[buffer_type]); 24178c2ecf20Sopenharmony_ci mpi_request->BufferAddress = 24188c2ecf20Sopenharmony_ci cpu_to_le64(ioc->diag_buffer_dma[buffer_type]); 24198c2ecf20Sopenharmony_ci for (i = 0; i < MPT3_PRODUCT_SPECIFIC_DWORDS; i++) 24208c2ecf20Sopenharmony_ci mpi_request->ProductSpecific[i] = 24218c2ecf20Sopenharmony_ci cpu_to_le32(ioc->product_specific[buffer_type][i]); 24228c2ecf20Sopenharmony_ci mpi_request->VF_ID = 0; /* TODO */ 24238c2ecf20Sopenharmony_ci mpi_request->VP_ID = 0; 24248c2ecf20Sopenharmony_ci 24258c2ecf20Sopenharmony_ci init_completion(&ioc->ctl_cmds.done); 24268c2ecf20Sopenharmony_ci ioc->put_smid_default(ioc, smid); 24278c2ecf20Sopenharmony_ci wait_for_completion_timeout(&ioc->ctl_cmds.done, 24288c2ecf20Sopenharmony_ci MPT3_IOCTL_DEFAULT_TIMEOUT*HZ); 24298c2ecf20Sopenharmony_ci 24308c2ecf20Sopenharmony_ci if (!(ioc->ctl_cmds.status & MPT3_CMD_COMPLETE)) { 24318c2ecf20Sopenharmony_ci mpt3sas_check_cmd_timeout(ioc, 24328c2ecf20Sopenharmony_ci ioc->ctl_cmds.status, mpi_request, 24338c2ecf20Sopenharmony_ci sizeof(Mpi2DiagBufferPostRequest_t)/4, issue_reset); 24348c2ecf20Sopenharmony_ci goto issue_host_reset; 24358c2ecf20Sopenharmony_ci } 24368c2ecf20Sopenharmony_ci 24378c2ecf20Sopenharmony_ci /* process the completed Reply Message Frame */ 24388c2ecf20Sopenharmony_ci if ((ioc->ctl_cmds.status & MPT3_CMD_REPLY_VALID) == 0) { 24398c2ecf20Sopenharmony_ci ioc_err(ioc, "%s: no reply message\n", __func__); 24408c2ecf20Sopenharmony_ci rc = -EFAULT; 24418c2ecf20Sopenharmony_ci goto out; 24428c2ecf20Sopenharmony_ci } 24438c2ecf20Sopenharmony_ci 24448c2ecf20Sopenharmony_ci mpi_reply = ioc->ctl_cmds.reply; 24458c2ecf20Sopenharmony_ci ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & MPI2_IOCSTATUS_MASK; 24468c2ecf20Sopenharmony_ci 24478c2ecf20Sopenharmony_ci if (ioc_status == MPI2_IOCSTATUS_SUCCESS) { 24488c2ecf20Sopenharmony_ci ioc->diag_buffer_status[buffer_type] |= 24498c2ecf20Sopenharmony_ci MPT3_DIAG_BUFFER_IS_REGISTERED; 24508c2ecf20Sopenharmony_ci ioc->diag_buffer_status[buffer_type] &= 24518c2ecf20Sopenharmony_ci ~MPT3_DIAG_BUFFER_IS_RELEASED; 24528c2ecf20Sopenharmony_ci dctlprintk(ioc, ioc_info(ioc, "%s: success\n", __func__)); 24538c2ecf20Sopenharmony_ci } else { 24548c2ecf20Sopenharmony_ci ioc_info(ioc, "%s: ioc_status(0x%04x) log_info(0x%08x)\n", 24558c2ecf20Sopenharmony_ci __func__, ioc_status, 24568c2ecf20Sopenharmony_ci le32_to_cpu(mpi_reply->IOCLogInfo)); 24578c2ecf20Sopenharmony_ci rc = -EFAULT; 24588c2ecf20Sopenharmony_ci } 24598c2ecf20Sopenharmony_ci 24608c2ecf20Sopenharmony_ci issue_host_reset: 24618c2ecf20Sopenharmony_ci if (issue_reset) 24628c2ecf20Sopenharmony_ci mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER); 24638c2ecf20Sopenharmony_ci 24648c2ecf20Sopenharmony_ci out: 24658c2ecf20Sopenharmony_ci 24668c2ecf20Sopenharmony_ci ioc->ctl_cmds.status = MPT3_CMD_NOT_USED; 24678c2ecf20Sopenharmony_ci return rc; 24688c2ecf20Sopenharmony_ci} 24698c2ecf20Sopenharmony_ci 24708c2ecf20Sopenharmony_ci 24718c2ecf20Sopenharmony_ci 24728c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT 24738c2ecf20Sopenharmony_ci/** 24748c2ecf20Sopenharmony_ci * _ctl_compat_mpt_command - convert 32bit pointers to 64bit. 24758c2ecf20Sopenharmony_ci * @ioc: per adapter object 24768c2ecf20Sopenharmony_ci * @cmd: ioctl opcode 24778c2ecf20Sopenharmony_ci * @arg: (struct mpt3_ioctl_command32) 24788c2ecf20Sopenharmony_ci * 24798c2ecf20Sopenharmony_ci * MPT3COMMAND32 - Handle 32bit applications running on 64bit os. 24808c2ecf20Sopenharmony_ci */ 24818c2ecf20Sopenharmony_cistatic long 24828c2ecf20Sopenharmony_ci_ctl_compat_mpt_command(struct MPT3SAS_ADAPTER *ioc, unsigned cmd, 24838c2ecf20Sopenharmony_ci void __user *arg) 24848c2ecf20Sopenharmony_ci{ 24858c2ecf20Sopenharmony_ci struct mpt3_ioctl_command32 karg32; 24868c2ecf20Sopenharmony_ci struct mpt3_ioctl_command32 __user *uarg; 24878c2ecf20Sopenharmony_ci struct mpt3_ioctl_command karg; 24888c2ecf20Sopenharmony_ci 24898c2ecf20Sopenharmony_ci if (_IOC_SIZE(cmd) != sizeof(struct mpt3_ioctl_command32)) 24908c2ecf20Sopenharmony_ci return -EINVAL; 24918c2ecf20Sopenharmony_ci 24928c2ecf20Sopenharmony_ci uarg = (struct mpt3_ioctl_command32 __user *) arg; 24938c2ecf20Sopenharmony_ci 24948c2ecf20Sopenharmony_ci if (copy_from_user(&karg32, (char __user *)arg, sizeof(karg32))) { 24958c2ecf20Sopenharmony_ci pr_err("failure at %s:%d/%s()!\n", 24968c2ecf20Sopenharmony_ci __FILE__, __LINE__, __func__); 24978c2ecf20Sopenharmony_ci return -EFAULT; 24988c2ecf20Sopenharmony_ci } 24998c2ecf20Sopenharmony_ci 25008c2ecf20Sopenharmony_ci memset(&karg, 0, sizeof(struct mpt3_ioctl_command)); 25018c2ecf20Sopenharmony_ci karg.hdr.ioc_number = karg32.hdr.ioc_number; 25028c2ecf20Sopenharmony_ci karg.hdr.port_number = karg32.hdr.port_number; 25038c2ecf20Sopenharmony_ci karg.hdr.max_data_size = karg32.hdr.max_data_size; 25048c2ecf20Sopenharmony_ci karg.timeout = karg32.timeout; 25058c2ecf20Sopenharmony_ci karg.max_reply_bytes = karg32.max_reply_bytes; 25068c2ecf20Sopenharmony_ci karg.data_in_size = karg32.data_in_size; 25078c2ecf20Sopenharmony_ci karg.data_out_size = karg32.data_out_size; 25088c2ecf20Sopenharmony_ci karg.max_sense_bytes = karg32.max_sense_bytes; 25098c2ecf20Sopenharmony_ci karg.data_sge_offset = karg32.data_sge_offset; 25108c2ecf20Sopenharmony_ci karg.reply_frame_buf_ptr = compat_ptr(karg32.reply_frame_buf_ptr); 25118c2ecf20Sopenharmony_ci karg.data_in_buf_ptr = compat_ptr(karg32.data_in_buf_ptr); 25128c2ecf20Sopenharmony_ci karg.data_out_buf_ptr = compat_ptr(karg32.data_out_buf_ptr); 25138c2ecf20Sopenharmony_ci karg.sense_data_ptr = compat_ptr(karg32.sense_data_ptr); 25148c2ecf20Sopenharmony_ci return _ctl_do_mpt_command(ioc, karg, &uarg->mf); 25158c2ecf20Sopenharmony_ci} 25168c2ecf20Sopenharmony_ci#endif 25178c2ecf20Sopenharmony_ci 25188c2ecf20Sopenharmony_ci/** 25198c2ecf20Sopenharmony_ci * _ctl_ioctl_main - main ioctl entry point 25208c2ecf20Sopenharmony_ci * @file: (struct file) 25218c2ecf20Sopenharmony_ci * @cmd: ioctl opcode 25228c2ecf20Sopenharmony_ci * @arg: user space data buffer 25238c2ecf20Sopenharmony_ci * @compat: handles 32 bit applications in 64bit os 25248c2ecf20Sopenharmony_ci * @mpi_version: will be MPI2_VERSION for mpt2ctl ioctl device & 25258c2ecf20Sopenharmony_ci * MPI25_VERSION | MPI26_VERSION for mpt3ctl ioctl device. 25268c2ecf20Sopenharmony_ci */ 25278c2ecf20Sopenharmony_cistatic long 25288c2ecf20Sopenharmony_ci_ctl_ioctl_main(struct file *file, unsigned int cmd, void __user *arg, 25298c2ecf20Sopenharmony_ci u8 compat, u16 mpi_version) 25308c2ecf20Sopenharmony_ci{ 25318c2ecf20Sopenharmony_ci struct MPT3SAS_ADAPTER *ioc; 25328c2ecf20Sopenharmony_ci struct mpt3_ioctl_header ioctl_header; 25338c2ecf20Sopenharmony_ci enum block_state state; 25348c2ecf20Sopenharmony_ci long ret = -EINVAL; 25358c2ecf20Sopenharmony_ci 25368c2ecf20Sopenharmony_ci /* get IOCTL header */ 25378c2ecf20Sopenharmony_ci if (copy_from_user(&ioctl_header, (char __user *)arg, 25388c2ecf20Sopenharmony_ci sizeof(struct mpt3_ioctl_header))) { 25398c2ecf20Sopenharmony_ci pr_err("failure at %s:%d/%s()!\n", 25408c2ecf20Sopenharmony_ci __FILE__, __LINE__, __func__); 25418c2ecf20Sopenharmony_ci return -EFAULT; 25428c2ecf20Sopenharmony_ci } 25438c2ecf20Sopenharmony_ci 25448c2ecf20Sopenharmony_ci if (_ctl_verify_adapter(ioctl_header.ioc_number, 25458c2ecf20Sopenharmony_ci &ioc, mpi_version) == -1 || !ioc) 25468c2ecf20Sopenharmony_ci return -ENODEV; 25478c2ecf20Sopenharmony_ci 25488c2ecf20Sopenharmony_ci /* pci_access_mutex lock acquired by ioctl path */ 25498c2ecf20Sopenharmony_ci mutex_lock(&ioc->pci_access_mutex); 25508c2ecf20Sopenharmony_ci 25518c2ecf20Sopenharmony_ci if (ioc->shost_recovery || ioc->pci_error_recovery || 25528c2ecf20Sopenharmony_ci ioc->is_driver_loading || ioc->remove_host) { 25538c2ecf20Sopenharmony_ci ret = -EAGAIN; 25548c2ecf20Sopenharmony_ci goto out_unlock_pciaccess; 25558c2ecf20Sopenharmony_ci } 25568c2ecf20Sopenharmony_ci 25578c2ecf20Sopenharmony_ci state = (file->f_flags & O_NONBLOCK) ? NON_BLOCKING : BLOCKING; 25588c2ecf20Sopenharmony_ci if (state == NON_BLOCKING) { 25598c2ecf20Sopenharmony_ci if (!mutex_trylock(&ioc->ctl_cmds.mutex)) { 25608c2ecf20Sopenharmony_ci ret = -EAGAIN; 25618c2ecf20Sopenharmony_ci goto out_unlock_pciaccess; 25628c2ecf20Sopenharmony_ci } 25638c2ecf20Sopenharmony_ci } else if (mutex_lock_interruptible(&ioc->ctl_cmds.mutex)) { 25648c2ecf20Sopenharmony_ci ret = -ERESTARTSYS; 25658c2ecf20Sopenharmony_ci goto out_unlock_pciaccess; 25668c2ecf20Sopenharmony_ci } 25678c2ecf20Sopenharmony_ci 25688c2ecf20Sopenharmony_ci 25698c2ecf20Sopenharmony_ci switch (cmd) { 25708c2ecf20Sopenharmony_ci case MPT3IOCINFO: 25718c2ecf20Sopenharmony_ci if (_IOC_SIZE(cmd) == sizeof(struct mpt3_ioctl_iocinfo)) 25728c2ecf20Sopenharmony_ci ret = _ctl_getiocinfo(ioc, arg); 25738c2ecf20Sopenharmony_ci break; 25748c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT 25758c2ecf20Sopenharmony_ci case MPT3COMMAND32: 25768c2ecf20Sopenharmony_ci#endif 25778c2ecf20Sopenharmony_ci case MPT3COMMAND: 25788c2ecf20Sopenharmony_ci { 25798c2ecf20Sopenharmony_ci struct mpt3_ioctl_command __user *uarg; 25808c2ecf20Sopenharmony_ci struct mpt3_ioctl_command karg; 25818c2ecf20Sopenharmony_ci 25828c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT 25838c2ecf20Sopenharmony_ci if (compat) { 25848c2ecf20Sopenharmony_ci ret = _ctl_compat_mpt_command(ioc, cmd, arg); 25858c2ecf20Sopenharmony_ci break; 25868c2ecf20Sopenharmony_ci } 25878c2ecf20Sopenharmony_ci#endif 25888c2ecf20Sopenharmony_ci if (copy_from_user(&karg, arg, sizeof(karg))) { 25898c2ecf20Sopenharmony_ci pr_err("failure at %s:%d/%s()!\n", 25908c2ecf20Sopenharmony_ci __FILE__, __LINE__, __func__); 25918c2ecf20Sopenharmony_ci ret = -EFAULT; 25928c2ecf20Sopenharmony_ci break; 25938c2ecf20Sopenharmony_ci } 25948c2ecf20Sopenharmony_ci 25958c2ecf20Sopenharmony_ci if (karg.hdr.ioc_number != ioctl_header.ioc_number) { 25968c2ecf20Sopenharmony_ci ret = -EINVAL; 25978c2ecf20Sopenharmony_ci break; 25988c2ecf20Sopenharmony_ci } 25998c2ecf20Sopenharmony_ci if (_IOC_SIZE(cmd) == sizeof(struct mpt3_ioctl_command)) { 26008c2ecf20Sopenharmony_ci uarg = arg; 26018c2ecf20Sopenharmony_ci ret = _ctl_do_mpt_command(ioc, karg, &uarg->mf); 26028c2ecf20Sopenharmony_ci } 26038c2ecf20Sopenharmony_ci break; 26048c2ecf20Sopenharmony_ci } 26058c2ecf20Sopenharmony_ci case MPT3EVENTQUERY: 26068c2ecf20Sopenharmony_ci if (_IOC_SIZE(cmd) == sizeof(struct mpt3_ioctl_eventquery)) 26078c2ecf20Sopenharmony_ci ret = _ctl_eventquery(ioc, arg); 26088c2ecf20Sopenharmony_ci break; 26098c2ecf20Sopenharmony_ci case MPT3EVENTENABLE: 26108c2ecf20Sopenharmony_ci if (_IOC_SIZE(cmd) == sizeof(struct mpt3_ioctl_eventenable)) 26118c2ecf20Sopenharmony_ci ret = _ctl_eventenable(ioc, arg); 26128c2ecf20Sopenharmony_ci break; 26138c2ecf20Sopenharmony_ci case MPT3EVENTREPORT: 26148c2ecf20Sopenharmony_ci ret = _ctl_eventreport(ioc, arg); 26158c2ecf20Sopenharmony_ci break; 26168c2ecf20Sopenharmony_ci case MPT3HARDRESET: 26178c2ecf20Sopenharmony_ci if (_IOC_SIZE(cmd) == sizeof(struct mpt3_ioctl_diag_reset)) 26188c2ecf20Sopenharmony_ci ret = _ctl_do_reset(ioc, arg); 26198c2ecf20Sopenharmony_ci break; 26208c2ecf20Sopenharmony_ci case MPT3BTDHMAPPING: 26218c2ecf20Sopenharmony_ci if (_IOC_SIZE(cmd) == sizeof(struct mpt3_ioctl_btdh_mapping)) 26228c2ecf20Sopenharmony_ci ret = _ctl_btdh_mapping(ioc, arg); 26238c2ecf20Sopenharmony_ci break; 26248c2ecf20Sopenharmony_ci case MPT3DIAGREGISTER: 26258c2ecf20Sopenharmony_ci if (_IOC_SIZE(cmd) == sizeof(struct mpt3_diag_register)) 26268c2ecf20Sopenharmony_ci ret = _ctl_diag_register(ioc, arg); 26278c2ecf20Sopenharmony_ci break; 26288c2ecf20Sopenharmony_ci case MPT3DIAGUNREGISTER: 26298c2ecf20Sopenharmony_ci if (_IOC_SIZE(cmd) == sizeof(struct mpt3_diag_unregister)) 26308c2ecf20Sopenharmony_ci ret = _ctl_diag_unregister(ioc, arg); 26318c2ecf20Sopenharmony_ci break; 26328c2ecf20Sopenharmony_ci case MPT3DIAGQUERY: 26338c2ecf20Sopenharmony_ci if (_IOC_SIZE(cmd) == sizeof(struct mpt3_diag_query)) 26348c2ecf20Sopenharmony_ci ret = _ctl_diag_query(ioc, arg); 26358c2ecf20Sopenharmony_ci break; 26368c2ecf20Sopenharmony_ci case MPT3DIAGRELEASE: 26378c2ecf20Sopenharmony_ci if (_IOC_SIZE(cmd) == sizeof(struct mpt3_diag_release)) 26388c2ecf20Sopenharmony_ci ret = _ctl_diag_release(ioc, arg); 26398c2ecf20Sopenharmony_ci break; 26408c2ecf20Sopenharmony_ci case MPT3DIAGREADBUFFER: 26418c2ecf20Sopenharmony_ci if (_IOC_SIZE(cmd) == sizeof(struct mpt3_diag_read_buffer)) 26428c2ecf20Sopenharmony_ci ret = _ctl_diag_read_buffer(ioc, arg); 26438c2ecf20Sopenharmony_ci break; 26448c2ecf20Sopenharmony_ci default: 26458c2ecf20Sopenharmony_ci dctlprintk(ioc, 26468c2ecf20Sopenharmony_ci ioc_info(ioc, "unsupported ioctl opcode(0x%08x)\n", 26478c2ecf20Sopenharmony_ci cmd)); 26488c2ecf20Sopenharmony_ci break; 26498c2ecf20Sopenharmony_ci } 26508c2ecf20Sopenharmony_ci 26518c2ecf20Sopenharmony_ci mutex_unlock(&ioc->ctl_cmds.mutex); 26528c2ecf20Sopenharmony_ciout_unlock_pciaccess: 26538c2ecf20Sopenharmony_ci mutex_unlock(&ioc->pci_access_mutex); 26548c2ecf20Sopenharmony_ci return ret; 26558c2ecf20Sopenharmony_ci} 26568c2ecf20Sopenharmony_ci 26578c2ecf20Sopenharmony_ci/** 26588c2ecf20Sopenharmony_ci * _ctl_ioctl - mpt3ctl main ioctl entry point (unlocked) 26598c2ecf20Sopenharmony_ci * @file: (struct file) 26608c2ecf20Sopenharmony_ci * @cmd: ioctl opcode 26618c2ecf20Sopenharmony_ci * @arg: ? 26628c2ecf20Sopenharmony_ci */ 26638c2ecf20Sopenharmony_cistatic long 26648c2ecf20Sopenharmony_ci_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 26658c2ecf20Sopenharmony_ci{ 26668c2ecf20Sopenharmony_ci long ret; 26678c2ecf20Sopenharmony_ci 26688c2ecf20Sopenharmony_ci /* pass MPI25_VERSION | MPI26_VERSION value, 26698c2ecf20Sopenharmony_ci * to indicate that this ioctl cmd 26708c2ecf20Sopenharmony_ci * came from mpt3ctl ioctl device. 26718c2ecf20Sopenharmony_ci */ 26728c2ecf20Sopenharmony_ci ret = _ctl_ioctl_main(file, cmd, (void __user *)arg, 0, 26738c2ecf20Sopenharmony_ci MPI25_VERSION | MPI26_VERSION); 26748c2ecf20Sopenharmony_ci return ret; 26758c2ecf20Sopenharmony_ci} 26768c2ecf20Sopenharmony_ci 26778c2ecf20Sopenharmony_ci/** 26788c2ecf20Sopenharmony_ci * _ctl_mpt2_ioctl - mpt2ctl main ioctl entry point (unlocked) 26798c2ecf20Sopenharmony_ci * @file: (struct file) 26808c2ecf20Sopenharmony_ci * @cmd: ioctl opcode 26818c2ecf20Sopenharmony_ci * @arg: ? 26828c2ecf20Sopenharmony_ci */ 26838c2ecf20Sopenharmony_cistatic long 26848c2ecf20Sopenharmony_ci_ctl_mpt2_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 26858c2ecf20Sopenharmony_ci{ 26868c2ecf20Sopenharmony_ci long ret; 26878c2ecf20Sopenharmony_ci 26888c2ecf20Sopenharmony_ci /* pass MPI2_VERSION value, to indicate that this ioctl cmd 26898c2ecf20Sopenharmony_ci * came from mpt2ctl ioctl device. 26908c2ecf20Sopenharmony_ci */ 26918c2ecf20Sopenharmony_ci ret = _ctl_ioctl_main(file, cmd, (void __user *)arg, 0, MPI2_VERSION); 26928c2ecf20Sopenharmony_ci return ret; 26938c2ecf20Sopenharmony_ci} 26948c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT 26958c2ecf20Sopenharmony_ci/** 26968c2ecf20Sopenharmony_ci *_ ctl_ioctl_compat - main ioctl entry point (compat) 26978c2ecf20Sopenharmony_ci * @file: ? 26988c2ecf20Sopenharmony_ci * @cmd: ? 26998c2ecf20Sopenharmony_ci * @arg: ? 27008c2ecf20Sopenharmony_ci * 27018c2ecf20Sopenharmony_ci * This routine handles 32 bit applications in 64bit os. 27028c2ecf20Sopenharmony_ci */ 27038c2ecf20Sopenharmony_cistatic long 27048c2ecf20Sopenharmony_ci_ctl_ioctl_compat(struct file *file, unsigned cmd, unsigned long arg) 27058c2ecf20Sopenharmony_ci{ 27068c2ecf20Sopenharmony_ci long ret; 27078c2ecf20Sopenharmony_ci 27088c2ecf20Sopenharmony_ci ret = _ctl_ioctl_main(file, cmd, (void __user *)arg, 1, 27098c2ecf20Sopenharmony_ci MPI25_VERSION | MPI26_VERSION); 27108c2ecf20Sopenharmony_ci return ret; 27118c2ecf20Sopenharmony_ci} 27128c2ecf20Sopenharmony_ci 27138c2ecf20Sopenharmony_ci/** 27148c2ecf20Sopenharmony_ci *_ ctl_mpt2_ioctl_compat - main ioctl entry point (compat) 27158c2ecf20Sopenharmony_ci * @file: ? 27168c2ecf20Sopenharmony_ci * @cmd: ? 27178c2ecf20Sopenharmony_ci * @arg: ? 27188c2ecf20Sopenharmony_ci * 27198c2ecf20Sopenharmony_ci * This routine handles 32 bit applications in 64bit os. 27208c2ecf20Sopenharmony_ci */ 27218c2ecf20Sopenharmony_cistatic long 27228c2ecf20Sopenharmony_ci_ctl_mpt2_ioctl_compat(struct file *file, unsigned cmd, unsigned long arg) 27238c2ecf20Sopenharmony_ci{ 27248c2ecf20Sopenharmony_ci long ret; 27258c2ecf20Sopenharmony_ci 27268c2ecf20Sopenharmony_ci ret = _ctl_ioctl_main(file, cmd, (void __user *)arg, 1, MPI2_VERSION); 27278c2ecf20Sopenharmony_ci return ret; 27288c2ecf20Sopenharmony_ci} 27298c2ecf20Sopenharmony_ci#endif 27308c2ecf20Sopenharmony_ci 27318c2ecf20Sopenharmony_ci/* scsi host attributes */ 27328c2ecf20Sopenharmony_ci/** 27338c2ecf20Sopenharmony_ci * version_fw_show - firmware version 27348c2ecf20Sopenharmony_ci * @cdev: pointer to embedded class device 27358c2ecf20Sopenharmony_ci * @attr: ? 27368c2ecf20Sopenharmony_ci * @buf: the buffer returned 27378c2ecf20Sopenharmony_ci * 27388c2ecf20Sopenharmony_ci * A sysfs 'read-only' shost attribute. 27398c2ecf20Sopenharmony_ci */ 27408c2ecf20Sopenharmony_cistatic ssize_t 27418c2ecf20Sopenharmony_civersion_fw_show(struct device *cdev, struct device_attribute *attr, 27428c2ecf20Sopenharmony_ci char *buf) 27438c2ecf20Sopenharmony_ci{ 27448c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(cdev); 27458c2ecf20Sopenharmony_ci struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); 27468c2ecf20Sopenharmony_ci 27478c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "%02d.%02d.%02d.%02d\n", 27488c2ecf20Sopenharmony_ci (ioc->facts.FWVersion.Word & 0xFF000000) >> 24, 27498c2ecf20Sopenharmony_ci (ioc->facts.FWVersion.Word & 0x00FF0000) >> 16, 27508c2ecf20Sopenharmony_ci (ioc->facts.FWVersion.Word & 0x0000FF00) >> 8, 27518c2ecf20Sopenharmony_ci ioc->facts.FWVersion.Word & 0x000000FF); 27528c2ecf20Sopenharmony_ci} 27538c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(version_fw); 27548c2ecf20Sopenharmony_ci 27558c2ecf20Sopenharmony_ci/** 27568c2ecf20Sopenharmony_ci * version_bios_show - bios version 27578c2ecf20Sopenharmony_ci * @cdev: pointer to embedded class device 27588c2ecf20Sopenharmony_ci * @attr: ? 27598c2ecf20Sopenharmony_ci * @buf: the buffer returned 27608c2ecf20Sopenharmony_ci * 27618c2ecf20Sopenharmony_ci * A sysfs 'read-only' shost attribute. 27628c2ecf20Sopenharmony_ci */ 27638c2ecf20Sopenharmony_cistatic ssize_t 27648c2ecf20Sopenharmony_civersion_bios_show(struct device *cdev, struct device_attribute *attr, 27658c2ecf20Sopenharmony_ci char *buf) 27668c2ecf20Sopenharmony_ci{ 27678c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(cdev); 27688c2ecf20Sopenharmony_ci struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); 27698c2ecf20Sopenharmony_ci 27708c2ecf20Sopenharmony_ci u32 version = le32_to_cpu(ioc->bios_pg3.BiosVersion); 27718c2ecf20Sopenharmony_ci 27728c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "%02d.%02d.%02d.%02d\n", 27738c2ecf20Sopenharmony_ci (version & 0xFF000000) >> 24, 27748c2ecf20Sopenharmony_ci (version & 0x00FF0000) >> 16, 27758c2ecf20Sopenharmony_ci (version & 0x0000FF00) >> 8, 27768c2ecf20Sopenharmony_ci version & 0x000000FF); 27778c2ecf20Sopenharmony_ci} 27788c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(version_bios); 27798c2ecf20Sopenharmony_ci 27808c2ecf20Sopenharmony_ci/** 27818c2ecf20Sopenharmony_ci * version_mpi_show - MPI (message passing interface) version 27828c2ecf20Sopenharmony_ci * @cdev: pointer to embedded class device 27838c2ecf20Sopenharmony_ci * @attr: ? 27848c2ecf20Sopenharmony_ci * @buf: the buffer returned 27858c2ecf20Sopenharmony_ci * 27868c2ecf20Sopenharmony_ci * A sysfs 'read-only' shost attribute. 27878c2ecf20Sopenharmony_ci */ 27888c2ecf20Sopenharmony_cistatic ssize_t 27898c2ecf20Sopenharmony_civersion_mpi_show(struct device *cdev, struct device_attribute *attr, 27908c2ecf20Sopenharmony_ci char *buf) 27918c2ecf20Sopenharmony_ci{ 27928c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(cdev); 27938c2ecf20Sopenharmony_ci struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); 27948c2ecf20Sopenharmony_ci 27958c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "%03x.%02x\n", 27968c2ecf20Sopenharmony_ci ioc->facts.MsgVersion, ioc->facts.HeaderVersion >> 8); 27978c2ecf20Sopenharmony_ci} 27988c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(version_mpi); 27998c2ecf20Sopenharmony_ci 28008c2ecf20Sopenharmony_ci/** 28018c2ecf20Sopenharmony_ci * version_product_show - product name 28028c2ecf20Sopenharmony_ci * @cdev: pointer to embedded class device 28038c2ecf20Sopenharmony_ci * @attr: ? 28048c2ecf20Sopenharmony_ci * @buf: the buffer returned 28058c2ecf20Sopenharmony_ci * 28068c2ecf20Sopenharmony_ci * A sysfs 'read-only' shost attribute. 28078c2ecf20Sopenharmony_ci */ 28088c2ecf20Sopenharmony_cistatic ssize_t 28098c2ecf20Sopenharmony_civersion_product_show(struct device *cdev, struct device_attribute *attr, 28108c2ecf20Sopenharmony_ci char *buf) 28118c2ecf20Sopenharmony_ci{ 28128c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(cdev); 28138c2ecf20Sopenharmony_ci struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); 28148c2ecf20Sopenharmony_ci 28158c2ecf20Sopenharmony_ci return snprintf(buf, 16, "%s\n", ioc->manu_pg0.ChipName); 28168c2ecf20Sopenharmony_ci} 28178c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(version_product); 28188c2ecf20Sopenharmony_ci 28198c2ecf20Sopenharmony_ci/** 28208c2ecf20Sopenharmony_ci * version_nvdata_persistent_show - ndvata persistent version 28218c2ecf20Sopenharmony_ci * @cdev: pointer to embedded class device 28228c2ecf20Sopenharmony_ci * @attr: ? 28238c2ecf20Sopenharmony_ci * @buf: the buffer returned 28248c2ecf20Sopenharmony_ci * 28258c2ecf20Sopenharmony_ci * A sysfs 'read-only' shost attribute. 28268c2ecf20Sopenharmony_ci */ 28278c2ecf20Sopenharmony_cistatic ssize_t 28288c2ecf20Sopenharmony_civersion_nvdata_persistent_show(struct device *cdev, 28298c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 28308c2ecf20Sopenharmony_ci{ 28318c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(cdev); 28328c2ecf20Sopenharmony_ci struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); 28338c2ecf20Sopenharmony_ci 28348c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "%08xh\n", 28358c2ecf20Sopenharmony_ci le32_to_cpu(ioc->iounit_pg0.NvdataVersionPersistent.Word)); 28368c2ecf20Sopenharmony_ci} 28378c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(version_nvdata_persistent); 28388c2ecf20Sopenharmony_ci 28398c2ecf20Sopenharmony_ci/** 28408c2ecf20Sopenharmony_ci * version_nvdata_default_show - nvdata default version 28418c2ecf20Sopenharmony_ci * @cdev: pointer to embedded class device 28428c2ecf20Sopenharmony_ci * @attr: ? 28438c2ecf20Sopenharmony_ci * @buf: the buffer returned 28448c2ecf20Sopenharmony_ci * 28458c2ecf20Sopenharmony_ci * A sysfs 'read-only' shost attribute. 28468c2ecf20Sopenharmony_ci */ 28478c2ecf20Sopenharmony_cistatic ssize_t 28488c2ecf20Sopenharmony_civersion_nvdata_default_show(struct device *cdev, struct device_attribute 28498c2ecf20Sopenharmony_ci *attr, char *buf) 28508c2ecf20Sopenharmony_ci{ 28518c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(cdev); 28528c2ecf20Sopenharmony_ci struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); 28538c2ecf20Sopenharmony_ci 28548c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "%08xh\n", 28558c2ecf20Sopenharmony_ci le32_to_cpu(ioc->iounit_pg0.NvdataVersionDefault.Word)); 28568c2ecf20Sopenharmony_ci} 28578c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(version_nvdata_default); 28588c2ecf20Sopenharmony_ci 28598c2ecf20Sopenharmony_ci/** 28608c2ecf20Sopenharmony_ci * board_name_show - board name 28618c2ecf20Sopenharmony_ci * @cdev: pointer to embedded class device 28628c2ecf20Sopenharmony_ci * @attr: ? 28638c2ecf20Sopenharmony_ci * @buf: the buffer returned 28648c2ecf20Sopenharmony_ci * 28658c2ecf20Sopenharmony_ci * A sysfs 'read-only' shost attribute. 28668c2ecf20Sopenharmony_ci */ 28678c2ecf20Sopenharmony_cistatic ssize_t 28688c2ecf20Sopenharmony_ciboard_name_show(struct device *cdev, struct device_attribute *attr, 28698c2ecf20Sopenharmony_ci char *buf) 28708c2ecf20Sopenharmony_ci{ 28718c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(cdev); 28728c2ecf20Sopenharmony_ci struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); 28738c2ecf20Sopenharmony_ci 28748c2ecf20Sopenharmony_ci return snprintf(buf, 16, "%s\n", ioc->manu_pg0.BoardName); 28758c2ecf20Sopenharmony_ci} 28768c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(board_name); 28778c2ecf20Sopenharmony_ci 28788c2ecf20Sopenharmony_ci/** 28798c2ecf20Sopenharmony_ci * board_assembly_show - board assembly name 28808c2ecf20Sopenharmony_ci * @cdev: pointer to embedded class device 28818c2ecf20Sopenharmony_ci * @attr: ? 28828c2ecf20Sopenharmony_ci * @buf: the buffer returned 28838c2ecf20Sopenharmony_ci * 28848c2ecf20Sopenharmony_ci * A sysfs 'read-only' shost attribute. 28858c2ecf20Sopenharmony_ci */ 28868c2ecf20Sopenharmony_cistatic ssize_t 28878c2ecf20Sopenharmony_ciboard_assembly_show(struct device *cdev, struct device_attribute *attr, 28888c2ecf20Sopenharmony_ci char *buf) 28898c2ecf20Sopenharmony_ci{ 28908c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(cdev); 28918c2ecf20Sopenharmony_ci struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); 28928c2ecf20Sopenharmony_ci 28938c2ecf20Sopenharmony_ci return snprintf(buf, 16, "%s\n", ioc->manu_pg0.BoardAssembly); 28948c2ecf20Sopenharmony_ci} 28958c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(board_assembly); 28968c2ecf20Sopenharmony_ci 28978c2ecf20Sopenharmony_ci/** 28988c2ecf20Sopenharmony_ci * board_tracer_show - board tracer number 28998c2ecf20Sopenharmony_ci * @cdev: pointer to embedded class device 29008c2ecf20Sopenharmony_ci * @attr: ? 29018c2ecf20Sopenharmony_ci * @buf: the buffer returned 29028c2ecf20Sopenharmony_ci * 29038c2ecf20Sopenharmony_ci * A sysfs 'read-only' shost attribute. 29048c2ecf20Sopenharmony_ci */ 29058c2ecf20Sopenharmony_cistatic ssize_t 29068c2ecf20Sopenharmony_ciboard_tracer_show(struct device *cdev, struct device_attribute *attr, 29078c2ecf20Sopenharmony_ci char *buf) 29088c2ecf20Sopenharmony_ci{ 29098c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(cdev); 29108c2ecf20Sopenharmony_ci struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); 29118c2ecf20Sopenharmony_ci 29128c2ecf20Sopenharmony_ci return snprintf(buf, 16, "%s\n", ioc->manu_pg0.BoardTracerNumber); 29138c2ecf20Sopenharmony_ci} 29148c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(board_tracer); 29158c2ecf20Sopenharmony_ci 29168c2ecf20Sopenharmony_ci/** 29178c2ecf20Sopenharmony_ci * io_delay_show - io missing delay 29188c2ecf20Sopenharmony_ci * @cdev: pointer to embedded class device 29198c2ecf20Sopenharmony_ci * @attr: ? 29208c2ecf20Sopenharmony_ci * @buf: the buffer returned 29218c2ecf20Sopenharmony_ci * 29228c2ecf20Sopenharmony_ci * This is for firmware implemention for deboucing device 29238c2ecf20Sopenharmony_ci * removal events. 29248c2ecf20Sopenharmony_ci * 29258c2ecf20Sopenharmony_ci * A sysfs 'read-only' shost attribute. 29268c2ecf20Sopenharmony_ci */ 29278c2ecf20Sopenharmony_cistatic ssize_t 29288c2ecf20Sopenharmony_ciio_delay_show(struct device *cdev, struct device_attribute *attr, 29298c2ecf20Sopenharmony_ci char *buf) 29308c2ecf20Sopenharmony_ci{ 29318c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(cdev); 29328c2ecf20Sopenharmony_ci struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); 29338c2ecf20Sopenharmony_ci 29348c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->io_missing_delay); 29358c2ecf20Sopenharmony_ci} 29368c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(io_delay); 29378c2ecf20Sopenharmony_ci 29388c2ecf20Sopenharmony_ci/** 29398c2ecf20Sopenharmony_ci * device_delay_show - device missing delay 29408c2ecf20Sopenharmony_ci * @cdev: pointer to embedded class device 29418c2ecf20Sopenharmony_ci * @attr: ? 29428c2ecf20Sopenharmony_ci * @buf: the buffer returned 29438c2ecf20Sopenharmony_ci * 29448c2ecf20Sopenharmony_ci * This is for firmware implemention for deboucing device 29458c2ecf20Sopenharmony_ci * removal events. 29468c2ecf20Sopenharmony_ci * 29478c2ecf20Sopenharmony_ci * A sysfs 'read-only' shost attribute. 29488c2ecf20Sopenharmony_ci */ 29498c2ecf20Sopenharmony_cistatic ssize_t 29508c2ecf20Sopenharmony_cidevice_delay_show(struct device *cdev, struct device_attribute *attr, 29518c2ecf20Sopenharmony_ci char *buf) 29528c2ecf20Sopenharmony_ci{ 29538c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(cdev); 29548c2ecf20Sopenharmony_ci struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); 29558c2ecf20Sopenharmony_ci 29568c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->device_missing_delay); 29578c2ecf20Sopenharmony_ci} 29588c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(device_delay); 29598c2ecf20Sopenharmony_ci 29608c2ecf20Sopenharmony_ci/** 29618c2ecf20Sopenharmony_ci * fw_queue_depth_show - global credits 29628c2ecf20Sopenharmony_ci * @cdev: pointer to embedded class device 29638c2ecf20Sopenharmony_ci * @attr: ? 29648c2ecf20Sopenharmony_ci * @buf: the buffer returned 29658c2ecf20Sopenharmony_ci * 29668c2ecf20Sopenharmony_ci * This is firmware queue depth limit 29678c2ecf20Sopenharmony_ci * 29688c2ecf20Sopenharmony_ci * A sysfs 'read-only' shost attribute. 29698c2ecf20Sopenharmony_ci */ 29708c2ecf20Sopenharmony_cistatic ssize_t 29718c2ecf20Sopenharmony_cifw_queue_depth_show(struct device *cdev, struct device_attribute *attr, 29728c2ecf20Sopenharmony_ci char *buf) 29738c2ecf20Sopenharmony_ci{ 29748c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(cdev); 29758c2ecf20Sopenharmony_ci struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); 29768c2ecf20Sopenharmony_ci 29778c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->facts.RequestCredit); 29788c2ecf20Sopenharmony_ci} 29798c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(fw_queue_depth); 29808c2ecf20Sopenharmony_ci 29818c2ecf20Sopenharmony_ci/** 29828c2ecf20Sopenharmony_ci * sas_address_show - sas address 29838c2ecf20Sopenharmony_ci * @cdev: pointer to embedded class device 29848c2ecf20Sopenharmony_ci * @attr: ? 29858c2ecf20Sopenharmony_ci * @buf: the buffer returned 29868c2ecf20Sopenharmony_ci * 29878c2ecf20Sopenharmony_ci * This is the controller sas address 29888c2ecf20Sopenharmony_ci * 29898c2ecf20Sopenharmony_ci * A sysfs 'read-only' shost attribute. 29908c2ecf20Sopenharmony_ci */ 29918c2ecf20Sopenharmony_cistatic ssize_t 29928c2ecf20Sopenharmony_cihost_sas_address_show(struct device *cdev, struct device_attribute *attr, 29938c2ecf20Sopenharmony_ci char *buf) 29948c2ecf20Sopenharmony_ci 29958c2ecf20Sopenharmony_ci{ 29968c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(cdev); 29978c2ecf20Sopenharmony_ci struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); 29988c2ecf20Sopenharmony_ci 29998c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "0x%016llx\n", 30008c2ecf20Sopenharmony_ci (unsigned long long)ioc->sas_hba.sas_address); 30018c2ecf20Sopenharmony_ci} 30028c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(host_sas_address); 30038c2ecf20Sopenharmony_ci 30048c2ecf20Sopenharmony_ci/** 30058c2ecf20Sopenharmony_ci * logging_level_show - logging level 30068c2ecf20Sopenharmony_ci * @cdev: pointer to embedded class device 30078c2ecf20Sopenharmony_ci * @attr: ? 30088c2ecf20Sopenharmony_ci * @buf: the buffer returned 30098c2ecf20Sopenharmony_ci * 30108c2ecf20Sopenharmony_ci * A sysfs 'read/write' shost attribute. 30118c2ecf20Sopenharmony_ci */ 30128c2ecf20Sopenharmony_cistatic ssize_t 30138c2ecf20Sopenharmony_cilogging_level_show(struct device *cdev, struct device_attribute *attr, 30148c2ecf20Sopenharmony_ci char *buf) 30158c2ecf20Sopenharmony_ci{ 30168c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(cdev); 30178c2ecf20Sopenharmony_ci struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); 30188c2ecf20Sopenharmony_ci 30198c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "%08xh\n", ioc->logging_level); 30208c2ecf20Sopenharmony_ci} 30218c2ecf20Sopenharmony_cistatic ssize_t 30228c2ecf20Sopenharmony_cilogging_level_store(struct device *cdev, struct device_attribute *attr, 30238c2ecf20Sopenharmony_ci const char *buf, size_t count) 30248c2ecf20Sopenharmony_ci{ 30258c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(cdev); 30268c2ecf20Sopenharmony_ci struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); 30278c2ecf20Sopenharmony_ci int val = 0; 30288c2ecf20Sopenharmony_ci 30298c2ecf20Sopenharmony_ci if (sscanf(buf, "%x", &val) != 1) 30308c2ecf20Sopenharmony_ci return -EINVAL; 30318c2ecf20Sopenharmony_ci 30328c2ecf20Sopenharmony_ci ioc->logging_level = val; 30338c2ecf20Sopenharmony_ci ioc_info(ioc, "logging_level=%08xh\n", 30348c2ecf20Sopenharmony_ci ioc->logging_level); 30358c2ecf20Sopenharmony_ci return strlen(buf); 30368c2ecf20Sopenharmony_ci} 30378c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(logging_level); 30388c2ecf20Sopenharmony_ci 30398c2ecf20Sopenharmony_ci/** 30408c2ecf20Sopenharmony_ci * fwfault_debug_show - show/store fwfault_debug 30418c2ecf20Sopenharmony_ci * @cdev: pointer to embedded class device 30428c2ecf20Sopenharmony_ci * @attr: ? 30438c2ecf20Sopenharmony_ci * @buf: the buffer returned 30448c2ecf20Sopenharmony_ci * 30458c2ecf20Sopenharmony_ci * mpt3sas_fwfault_debug is command line option 30468c2ecf20Sopenharmony_ci * A sysfs 'read/write' shost attribute. 30478c2ecf20Sopenharmony_ci */ 30488c2ecf20Sopenharmony_cistatic ssize_t 30498c2ecf20Sopenharmony_cifwfault_debug_show(struct device *cdev, struct device_attribute *attr, 30508c2ecf20Sopenharmony_ci char *buf) 30518c2ecf20Sopenharmony_ci{ 30528c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(cdev); 30538c2ecf20Sopenharmony_ci struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); 30548c2ecf20Sopenharmony_ci 30558c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "%d\n", ioc->fwfault_debug); 30568c2ecf20Sopenharmony_ci} 30578c2ecf20Sopenharmony_cistatic ssize_t 30588c2ecf20Sopenharmony_cifwfault_debug_store(struct device *cdev, struct device_attribute *attr, 30598c2ecf20Sopenharmony_ci const char *buf, size_t count) 30608c2ecf20Sopenharmony_ci{ 30618c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(cdev); 30628c2ecf20Sopenharmony_ci struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); 30638c2ecf20Sopenharmony_ci int val = 0; 30648c2ecf20Sopenharmony_ci 30658c2ecf20Sopenharmony_ci if (sscanf(buf, "%d", &val) != 1) 30668c2ecf20Sopenharmony_ci return -EINVAL; 30678c2ecf20Sopenharmony_ci 30688c2ecf20Sopenharmony_ci ioc->fwfault_debug = val; 30698c2ecf20Sopenharmony_ci ioc_info(ioc, "fwfault_debug=%d\n", 30708c2ecf20Sopenharmony_ci ioc->fwfault_debug); 30718c2ecf20Sopenharmony_ci return strlen(buf); 30728c2ecf20Sopenharmony_ci} 30738c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(fwfault_debug); 30748c2ecf20Sopenharmony_ci 30758c2ecf20Sopenharmony_ci/** 30768c2ecf20Sopenharmony_ci * ioc_reset_count_show - ioc reset count 30778c2ecf20Sopenharmony_ci * @cdev: pointer to embedded class device 30788c2ecf20Sopenharmony_ci * @attr: ? 30798c2ecf20Sopenharmony_ci * @buf: the buffer returned 30808c2ecf20Sopenharmony_ci * 30818c2ecf20Sopenharmony_ci * This is firmware queue depth limit 30828c2ecf20Sopenharmony_ci * 30838c2ecf20Sopenharmony_ci * A sysfs 'read-only' shost attribute. 30848c2ecf20Sopenharmony_ci */ 30858c2ecf20Sopenharmony_cistatic ssize_t 30868c2ecf20Sopenharmony_ciioc_reset_count_show(struct device *cdev, struct device_attribute *attr, 30878c2ecf20Sopenharmony_ci char *buf) 30888c2ecf20Sopenharmony_ci{ 30898c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(cdev); 30908c2ecf20Sopenharmony_ci struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); 30918c2ecf20Sopenharmony_ci 30928c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "%d\n", ioc->ioc_reset_count); 30938c2ecf20Sopenharmony_ci} 30948c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(ioc_reset_count); 30958c2ecf20Sopenharmony_ci 30968c2ecf20Sopenharmony_ci/** 30978c2ecf20Sopenharmony_ci * reply_queue_count_show - number of reply queues 30988c2ecf20Sopenharmony_ci * @cdev: pointer to embedded class device 30998c2ecf20Sopenharmony_ci * @attr: ? 31008c2ecf20Sopenharmony_ci * @buf: the buffer returned 31018c2ecf20Sopenharmony_ci * 31028c2ecf20Sopenharmony_ci * This is number of reply queues 31038c2ecf20Sopenharmony_ci * 31048c2ecf20Sopenharmony_ci * A sysfs 'read-only' shost attribute. 31058c2ecf20Sopenharmony_ci */ 31068c2ecf20Sopenharmony_cistatic ssize_t 31078c2ecf20Sopenharmony_cireply_queue_count_show(struct device *cdev, 31088c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 31098c2ecf20Sopenharmony_ci{ 31108c2ecf20Sopenharmony_ci u8 reply_queue_count; 31118c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(cdev); 31128c2ecf20Sopenharmony_ci struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); 31138c2ecf20Sopenharmony_ci 31148c2ecf20Sopenharmony_ci if ((ioc->facts.IOCCapabilities & 31158c2ecf20Sopenharmony_ci MPI2_IOCFACTS_CAPABILITY_MSI_X_INDEX) && ioc->msix_enable) 31168c2ecf20Sopenharmony_ci reply_queue_count = ioc->reply_queue_count; 31178c2ecf20Sopenharmony_ci else 31188c2ecf20Sopenharmony_ci reply_queue_count = 1; 31198c2ecf20Sopenharmony_ci 31208c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "%d\n", reply_queue_count); 31218c2ecf20Sopenharmony_ci} 31228c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(reply_queue_count); 31238c2ecf20Sopenharmony_ci 31248c2ecf20Sopenharmony_ci/** 31258c2ecf20Sopenharmony_ci * BRM_status_show - Backup Rail Monitor Status 31268c2ecf20Sopenharmony_ci * @cdev: pointer to embedded class device 31278c2ecf20Sopenharmony_ci * @attr: ? 31288c2ecf20Sopenharmony_ci * @buf: the buffer returned 31298c2ecf20Sopenharmony_ci * 31308c2ecf20Sopenharmony_ci * This is number of reply queues 31318c2ecf20Sopenharmony_ci * 31328c2ecf20Sopenharmony_ci * A sysfs 'read-only' shost attribute. 31338c2ecf20Sopenharmony_ci */ 31348c2ecf20Sopenharmony_cistatic ssize_t 31358c2ecf20Sopenharmony_ciBRM_status_show(struct device *cdev, struct device_attribute *attr, 31368c2ecf20Sopenharmony_ci char *buf) 31378c2ecf20Sopenharmony_ci{ 31388c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(cdev); 31398c2ecf20Sopenharmony_ci struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); 31408c2ecf20Sopenharmony_ci Mpi2IOUnitPage3_t *io_unit_pg3 = NULL; 31418c2ecf20Sopenharmony_ci Mpi2ConfigReply_t mpi_reply; 31428c2ecf20Sopenharmony_ci u16 backup_rail_monitor_status = 0; 31438c2ecf20Sopenharmony_ci u16 ioc_status; 31448c2ecf20Sopenharmony_ci int sz; 31458c2ecf20Sopenharmony_ci ssize_t rc = 0; 31468c2ecf20Sopenharmony_ci 31478c2ecf20Sopenharmony_ci if (!ioc->is_warpdrive) { 31488c2ecf20Sopenharmony_ci ioc_err(ioc, "%s: BRM attribute is only for warpdrive\n", 31498c2ecf20Sopenharmony_ci __func__); 31508c2ecf20Sopenharmony_ci return 0; 31518c2ecf20Sopenharmony_ci } 31528c2ecf20Sopenharmony_ci /* pci_access_mutex lock acquired by sysfs show path */ 31538c2ecf20Sopenharmony_ci mutex_lock(&ioc->pci_access_mutex); 31548c2ecf20Sopenharmony_ci if (ioc->pci_error_recovery || ioc->remove_host) 31558c2ecf20Sopenharmony_ci goto out; 31568c2ecf20Sopenharmony_ci 31578c2ecf20Sopenharmony_ci /* allocate upto GPIOVal 36 entries */ 31588c2ecf20Sopenharmony_ci sz = offsetof(Mpi2IOUnitPage3_t, GPIOVal) + (sizeof(u16) * 36); 31598c2ecf20Sopenharmony_ci io_unit_pg3 = kzalloc(sz, GFP_KERNEL); 31608c2ecf20Sopenharmony_ci if (!io_unit_pg3) { 31618c2ecf20Sopenharmony_ci rc = -ENOMEM; 31628c2ecf20Sopenharmony_ci ioc_err(ioc, "%s: failed allocating memory for iounit_pg3: (%d) bytes\n", 31638c2ecf20Sopenharmony_ci __func__, sz); 31648c2ecf20Sopenharmony_ci goto out; 31658c2ecf20Sopenharmony_ci } 31668c2ecf20Sopenharmony_ci 31678c2ecf20Sopenharmony_ci if (mpt3sas_config_get_iounit_pg3(ioc, &mpi_reply, io_unit_pg3, sz) != 31688c2ecf20Sopenharmony_ci 0) { 31698c2ecf20Sopenharmony_ci ioc_err(ioc, "%s: failed reading iounit_pg3\n", 31708c2ecf20Sopenharmony_ci __func__); 31718c2ecf20Sopenharmony_ci rc = -EINVAL; 31728c2ecf20Sopenharmony_ci goto out; 31738c2ecf20Sopenharmony_ci } 31748c2ecf20Sopenharmony_ci 31758c2ecf20Sopenharmony_ci ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; 31768c2ecf20Sopenharmony_ci if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { 31778c2ecf20Sopenharmony_ci ioc_err(ioc, "%s: iounit_pg3 failed with ioc_status(0x%04x)\n", 31788c2ecf20Sopenharmony_ci __func__, ioc_status); 31798c2ecf20Sopenharmony_ci rc = -EINVAL; 31808c2ecf20Sopenharmony_ci goto out; 31818c2ecf20Sopenharmony_ci } 31828c2ecf20Sopenharmony_ci 31838c2ecf20Sopenharmony_ci if (io_unit_pg3->GPIOCount < 25) { 31848c2ecf20Sopenharmony_ci ioc_err(ioc, "%s: iounit_pg3->GPIOCount less than 25 entries, detected (%d) entries\n", 31858c2ecf20Sopenharmony_ci __func__, io_unit_pg3->GPIOCount); 31868c2ecf20Sopenharmony_ci rc = -EINVAL; 31878c2ecf20Sopenharmony_ci goto out; 31888c2ecf20Sopenharmony_ci } 31898c2ecf20Sopenharmony_ci 31908c2ecf20Sopenharmony_ci /* BRM status is in bit zero of GPIOVal[24] */ 31918c2ecf20Sopenharmony_ci backup_rail_monitor_status = le16_to_cpu(io_unit_pg3->GPIOVal[24]); 31928c2ecf20Sopenharmony_ci rc = snprintf(buf, PAGE_SIZE, "%d\n", (backup_rail_monitor_status & 1)); 31938c2ecf20Sopenharmony_ci 31948c2ecf20Sopenharmony_ci out: 31958c2ecf20Sopenharmony_ci kfree(io_unit_pg3); 31968c2ecf20Sopenharmony_ci mutex_unlock(&ioc->pci_access_mutex); 31978c2ecf20Sopenharmony_ci return rc; 31988c2ecf20Sopenharmony_ci} 31998c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(BRM_status); 32008c2ecf20Sopenharmony_ci 32018c2ecf20Sopenharmony_cistruct DIAG_BUFFER_START { 32028c2ecf20Sopenharmony_ci __le32 Size; 32038c2ecf20Sopenharmony_ci __le32 DiagVersion; 32048c2ecf20Sopenharmony_ci u8 BufferType; 32058c2ecf20Sopenharmony_ci u8 Reserved[3]; 32068c2ecf20Sopenharmony_ci __le32 Reserved1; 32078c2ecf20Sopenharmony_ci __le32 Reserved2; 32088c2ecf20Sopenharmony_ci __le32 Reserved3; 32098c2ecf20Sopenharmony_ci}; 32108c2ecf20Sopenharmony_ci 32118c2ecf20Sopenharmony_ci/** 32128c2ecf20Sopenharmony_ci * host_trace_buffer_size_show - host buffer size (trace only) 32138c2ecf20Sopenharmony_ci * @cdev: pointer to embedded class device 32148c2ecf20Sopenharmony_ci * @attr: ? 32158c2ecf20Sopenharmony_ci * @buf: the buffer returned 32168c2ecf20Sopenharmony_ci * 32178c2ecf20Sopenharmony_ci * A sysfs 'read-only' shost attribute. 32188c2ecf20Sopenharmony_ci */ 32198c2ecf20Sopenharmony_cistatic ssize_t 32208c2ecf20Sopenharmony_cihost_trace_buffer_size_show(struct device *cdev, 32218c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 32228c2ecf20Sopenharmony_ci{ 32238c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(cdev); 32248c2ecf20Sopenharmony_ci struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); 32258c2ecf20Sopenharmony_ci u32 size = 0; 32268c2ecf20Sopenharmony_ci struct DIAG_BUFFER_START *request_data; 32278c2ecf20Sopenharmony_ci 32288c2ecf20Sopenharmony_ci if (!ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) { 32298c2ecf20Sopenharmony_ci ioc_err(ioc, "%s: host_trace_buffer is not registered\n", 32308c2ecf20Sopenharmony_ci __func__); 32318c2ecf20Sopenharmony_ci return 0; 32328c2ecf20Sopenharmony_ci } 32338c2ecf20Sopenharmony_ci 32348c2ecf20Sopenharmony_ci if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & 32358c2ecf20Sopenharmony_ci MPT3_DIAG_BUFFER_IS_REGISTERED) == 0) { 32368c2ecf20Sopenharmony_ci ioc_err(ioc, "%s: host_trace_buffer is not registered\n", 32378c2ecf20Sopenharmony_ci __func__); 32388c2ecf20Sopenharmony_ci return 0; 32398c2ecf20Sopenharmony_ci } 32408c2ecf20Sopenharmony_ci 32418c2ecf20Sopenharmony_ci request_data = (struct DIAG_BUFFER_START *) 32428c2ecf20Sopenharmony_ci ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]; 32438c2ecf20Sopenharmony_ci if ((le32_to_cpu(request_data->DiagVersion) == 0x00000000 || 32448c2ecf20Sopenharmony_ci le32_to_cpu(request_data->DiagVersion) == 0x01000000 || 32458c2ecf20Sopenharmony_ci le32_to_cpu(request_data->DiagVersion) == 0x01010000) && 32468c2ecf20Sopenharmony_ci le32_to_cpu(request_data->Reserved3) == 0x4742444c) 32478c2ecf20Sopenharmony_ci size = le32_to_cpu(request_data->Size); 32488c2ecf20Sopenharmony_ci 32498c2ecf20Sopenharmony_ci ioc->ring_buffer_sz = size; 32508c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "%d\n", size); 32518c2ecf20Sopenharmony_ci} 32528c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(host_trace_buffer_size); 32538c2ecf20Sopenharmony_ci 32548c2ecf20Sopenharmony_ci/** 32558c2ecf20Sopenharmony_ci * host_trace_buffer_show - firmware ring buffer (trace only) 32568c2ecf20Sopenharmony_ci * @cdev: pointer to embedded class device 32578c2ecf20Sopenharmony_ci * @attr: ? 32588c2ecf20Sopenharmony_ci * @buf: the buffer returned 32598c2ecf20Sopenharmony_ci * 32608c2ecf20Sopenharmony_ci * A sysfs 'read/write' shost attribute. 32618c2ecf20Sopenharmony_ci * 32628c2ecf20Sopenharmony_ci * You will only be able to read 4k bytes of ring buffer at a time. 32638c2ecf20Sopenharmony_ci * In order to read beyond 4k bytes, you will have to write out the 32648c2ecf20Sopenharmony_ci * offset to the same attribute, it will move the pointer. 32658c2ecf20Sopenharmony_ci */ 32668c2ecf20Sopenharmony_cistatic ssize_t 32678c2ecf20Sopenharmony_cihost_trace_buffer_show(struct device *cdev, struct device_attribute *attr, 32688c2ecf20Sopenharmony_ci char *buf) 32698c2ecf20Sopenharmony_ci{ 32708c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(cdev); 32718c2ecf20Sopenharmony_ci struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); 32728c2ecf20Sopenharmony_ci void *request_data; 32738c2ecf20Sopenharmony_ci u32 size; 32748c2ecf20Sopenharmony_ci 32758c2ecf20Sopenharmony_ci if (!ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) { 32768c2ecf20Sopenharmony_ci ioc_err(ioc, "%s: host_trace_buffer is not registered\n", 32778c2ecf20Sopenharmony_ci __func__); 32788c2ecf20Sopenharmony_ci return 0; 32798c2ecf20Sopenharmony_ci } 32808c2ecf20Sopenharmony_ci 32818c2ecf20Sopenharmony_ci if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & 32828c2ecf20Sopenharmony_ci MPT3_DIAG_BUFFER_IS_REGISTERED) == 0) { 32838c2ecf20Sopenharmony_ci ioc_err(ioc, "%s: host_trace_buffer is not registered\n", 32848c2ecf20Sopenharmony_ci __func__); 32858c2ecf20Sopenharmony_ci return 0; 32868c2ecf20Sopenharmony_ci } 32878c2ecf20Sopenharmony_ci 32888c2ecf20Sopenharmony_ci if (ioc->ring_buffer_offset > ioc->ring_buffer_sz) 32898c2ecf20Sopenharmony_ci return 0; 32908c2ecf20Sopenharmony_ci 32918c2ecf20Sopenharmony_ci size = ioc->ring_buffer_sz - ioc->ring_buffer_offset; 32928c2ecf20Sopenharmony_ci size = (size >= PAGE_SIZE) ? (PAGE_SIZE - 1) : size; 32938c2ecf20Sopenharmony_ci request_data = ioc->diag_buffer[0] + ioc->ring_buffer_offset; 32948c2ecf20Sopenharmony_ci memcpy(buf, request_data, size); 32958c2ecf20Sopenharmony_ci return size; 32968c2ecf20Sopenharmony_ci} 32978c2ecf20Sopenharmony_ci 32988c2ecf20Sopenharmony_cistatic ssize_t 32998c2ecf20Sopenharmony_cihost_trace_buffer_store(struct device *cdev, struct device_attribute *attr, 33008c2ecf20Sopenharmony_ci const char *buf, size_t count) 33018c2ecf20Sopenharmony_ci{ 33028c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(cdev); 33038c2ecf20Sopenharmony_ci struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); 33048c2ecf20Sopenharmony_ci int val = 0; 33058c2ecf20Sopenharmony_ci 33068c2ecf20Sopenharmony_ci if (sscanf(buf, "%d", &val) != 1) 33078c2ecf20Sopenharmony_ci return -EINVAL; 33088c2ecf20Sopenharmony_ci 33098c2ecf20Sopenharmony_ci ioc->ring_buffer_offset = val; 33108c2ecf20Sopenharmony_ci return strlen(buf); 33118c2ecf20Sopenharmony_ci} 33128c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(host_trace_buffer); 33138c2ecf20Sopenharmony_ci 33148c2ecf20Sopenharmony_ci 33158c2ecf20Sopenharmony_ci/*****************************************/ 33168c2ecf20Sopenharmony_ci 33178c2ecf20Sopenharmony_ci/** 33188c2ecf20Sopenharmony_ci * host_trace_buffer_enable_show - firmware ring buffer (trace only) 33198c2ecf20Sopenharmony_ci * @cdev: pointer to embedded class device 33208c2ecf20Sopenharmony_ci * @attr: ? 33218c2ecf20Sopenharmony_ci * @buf: the buffer returned 33228c2ecf20Sopenharmony_ci * 33238c2ecf20Sopenharmony_ci * A sysfs 'read/write' shost attribute. 33248c2ecf20Sopenharmony_ci * 33258c2ecf20Sopenharmony_ci * This is a mechnism to post/release host_trace_buffers 33268c2ecf20Sopenharmony_ci */ 33278c2ecf20Sopenharmony_cistatic ssize_t 33288c2ecf20Sopenharmony_cihost_trace_buffer_enable_show(struct device *cdev, 33298c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 33308c2ecf20Sopenharmony_ci{ 33318c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(cdev); 33328c2ecf20Sopenharmony_ci struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); 33338c2ecf20Sopenharmony_ci 33348c2ecf20Sopenharmony_ci if ((!ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) || 33358c2ecf20Sopenharmony_ci ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & 33368c2ecf20Sopenharmony_ci MPT3_DIAG_BUFFER_IS_REGISTERED) == 0)) 33378c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "off\n"); 33388c2ecf20Sopenharmony_ci else if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & 33398c2ecf20Sopenharmony_ci MPT3_DIAG_BUFFER_IS_RELEASED)) 33408c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "release\n"); 33418c2ecf20Sopenharmony_ci else 33428c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "post\n"); 33438c2ecf20Sopenharmony_ci} 33448c2ecf20Sopenharmony_ci 33458c2ecf20Sopenharmony_cistatic ssize_t 33468c2ecf20Sopenharmony_cihost_trace_buffer_enable_store(struct device *cdev, 33478c2ecf20Sopenharmony_ci struct device_attribute *attr, const char *buf, size_t count) 33488c2ecf20Sopenharmony_ci{ 33498c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(cdev); 33508c2ecf20Sopenharmony_ci struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); 33518c2ecf20Sopenharmony_ci char str[10] = ""; 33528c2ecf20Sopenharmony_ci struct mpt3_diag_register diag_register; 33538c2ecf20Sopenharmony_ci u8 issue_reset = 0; 33548c2ecf20Sopenharmony_ci 33558c2ecf20Sopenharmony_ci /* don't allow post/release occurr while recovery is active */ 33568c2ecf20Sopenharmony_ci if (ioc->shost_recovery || ioc->remove_host || 33578c2ecf20Sopenharmony_ci ioc->pci_error_recovery || ioc->is_driver_loading) 33588c2ecf20Sopenharmony_ci return -EBUSY; 33598c2ecf20Sopenharmony_ci 33608c2ecf20Sopenharmony_ci if (sscanf(buf, "%9s", str) != 1) 33618c2ecf20Sopenharmony_ci return -EINVAL; 33628c2ecf20Sopenharmony_ci 33638c2ecf20Sopenharmony_ci if (!strcmp(str, "post")) { 33648c2ecf20Sopenharmony_ci /* exit out if host buffers are already posted */ 33658c2ecf20Sopenharmony_ci if ((ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) && 33668c2ecf20Sopenharmony_ci (ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & 33678c2ecf20Sopenharmony_ci MPT3_DIAG_BUFFER_IS_REGISTERED) && 33688c2ecf20Sopenharmony_ci ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & 33698c2ecf20Sopenharmony_ci MPT3_DIAG_BUFFER_IS_RELEASED) == 0)) 33708c2ecf20Sopenharmony_ci goto out; 33718c2ecf20Sopenharmony_ci memset(&diag_register, 0, sizeof(struct mpt3_diag_register)); 33728c2ecf20Sopenharmony_ci ioc_info(ioc, "posting host trace buffers\n"); 33738c2ecf20Sopenharmony_ci diag_register.buffer_type = MPI2_DIAG_BUF_TYPE_TRACE; 33748c2ecf20Sopenharmony_ci 33758c2ecf20Sopenharmony_ci if (ioc->manu_pg11.HostTraceBufferMaxSizeKB != 0 && 33768c2ecf20Sopenharmony_ci ioc->diag_buffer_sz[MPI2_DIAG_BUF_TYPE_TRACE] != 0) { 33778c2ecf20Sopenharmony_ci /* post the same buffer allocated previously */ 33788c2ecf20Sopenharmony_ci diag_register.requested_buffer_size = 33798c2ecf20Sopenharmony_ci ioc->diag_buffer_sz[MPI2_DIAG_BUF_TYPE_TRACE]; 33808c2ecf20Sopenharmony_ci } else { 33818c2ecf20Sopenharmony_ci /* 33828c2ecf20Sopenharmony_ci * Free the diag buffer memory which was previously 33838c2ecf20Sopenharmony_ci * allocated by an application. 33848c2ecf20Sopenharmony_ci */ 33858c2ecf20Sopenharmony_ci if ((ioc->diag_buffer_sz[MPI2_DIAG_BUF_TYPE_TRACE] != 0) 33868c2ecf20Sopenharmony_ci && 33878c2ecf20Sopenharmony_ci (ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & 33888c2ecf20Sopenharmony_ci MPT3_DIAG_BUFFER_IS_APP_OWNED)) { 33898c2ecf20Sopenharmony_ci dma_free_coherent(&ioc->pdev->dev, 33908c2ecf20Sopenharmony_ci ioc->diag_buffer_sz[MPI2_DIAG_BUF_TYPE_TRACE], 33918c2ecf20Sopenharmony_ci ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE], 33928c2ecf20Sopenharmony_ci ioc->diag_buffer_dma[MPI2_DIAG_BUF_TYPE_TRACE]); 33938c2ecf20Sopenharmony_ci ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE] = 33948c2ecf20Sopenharmony_ci NULL; 33958c2ecf20Sopenharmony_ci } 33968c2ecf20Sopenharmony_ci 33978c2ecf20Sopenharmony_ci diag_register.requested_buffer_size = (1024 * 1024); 33988c2ecf20Sopenharmony_ci } 33998c2ecf20Sopenharmony_ci 34008c2ecf20Sopenharmony_ci diag_register.unique_id = 34018c2ecf20Sopenharmony_ci (ioc->hba_mpi_version_belonged == MPI2_VERSION) ? 34028c2ecf20Sopenharmony_ci (MPT2DIAGBUFFUNIQUEID):(MPT3DIAGBUFFUNIQUEID); 34038c2ecf20Sopenharmony_ci ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] = 0; 34048c2ecf20Sopenharmony_ci _ctl_diag_register_2(ioc, &diag_register); 34058c2ecf20Sopenharmony_ci if (ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & 34068c2ecf20Sopenharmony_ci MPT3_DIAG_BUFFER_IS_REGISTERED) { 34078c2ecf20Sopenharmony_ci ioc_info(ioc, 34088c2ecf20Sopenharmony_ci "Trace buffer %d KB allocated through sysfs\n", 34098c2ecf20Sopenharmony_ci diag_register.requested_buffer_size>>10); 34108c2ecf20Sopenharmony_ci if (ioc->hba_mpi_version_belonged != MPI2_VERSION) 34118c2ecf20Sopenharmony_ci ioc->diag_buffer_status[ 34128c2ecf20Sopenharmony_ci MPI2_DIAG_BUF_TYPE_TRACE] |= 34138c2ecf20Sopenharmony_ci MPT3_DIAG_BUFFER_IS_DRIVER_ALLOCATED; 34148c2ecf20Sopenharmony_ci } 34158c2ecf20Sopenharmony_ci } else if (!strcmp(str, "release")) { 34168c2ecf20Sopenharmony_ci /* exit out if host buffers are already released */ 34178c2ecf20Sopenharmony_ci if (!ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) 34188c2ecf20Sopenharmony_ci goto out; 34198c2ecf20Sopenharmony_ci if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & 34208c2ecf20Sopenharmony_ci MPT3_DIAG_BUFFER_IS_REGISTERED) == 0) 34218c2ecf20Sopenharmony_ci goto out; 34228c2ecf20Sopenharmony_ci if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & 34238c2ecf20Sopenharmony_ci MPT3_DIAG_BUFFER_IS_RELEASED)) 34248c2ecf20Sopenharmony_ci goto out; 34258c2ecf20Sopenharmony_ci ioc_info(ioc, "releasing host trace buffer\n"); 34268c2ecf20Sopenharmony_ci mpt3sas_send_diag_release(ioc, MPI2_DIAG_BUF_TYPE_TRACE, 34278c2ecf20Sopenharmony_ci &issue_reset); 34288c2ecf20Sopenharmony_ci } 34298c2ecf20Sopenharmony_ci 34308c2ecf20Sopenharmony_ci out: 34318c2ecf20Sopenharmony_ci return strlen(buf); 34328c2ecf20Sopenharmony_ci} 34338c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(host_trace_buffer_enable); 34348c2ecf20Sopenharmony_ci 34358c2ecf20Sopenharmony_ci/*********** diagnostic trigger suppport *********************************/ 34368c2ecf20Sopenharmony_ci 34378c2ecf20Sopenharmony_ci/** 34388c2ecf20Sopenharmony_ci * diag_trigger_master_show - show the diag_trigger_master attribute 34398c2ecf20Sopenharmony_ci * @cdev: pointer to embedded class device 34408c2ecf20Sopenharmony_ci * @attr: ? 34418c2ecf20Sopenharmony_ci * @buf: the buffer returned 34428c2ecf20Sopenharmony_ci * 34438c2ecf20Sopenharmony_ci * A sysfs 'read/write' shost attribute. 34448c2ecf20Sopenharmony_ci */ 34458c2ecf20Sopenharmony_cistatic ssize_t 34468c2ecf20Sopenharmony_cidiag_trigger_master_show(struct device *cdev, 34478c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 34488c2ecf20Sopenharmony_ci 34498c2ecf20Sopenharmony_ci{ 34508c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(cdev); 34518c2ecf20Sopenharmony_ci struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); 34528c2ecf20Sopenharmony_ci unsigned long flags; 34538c2ecf20Sopenharmony_ci ssize_t rc; 34548c2ecf20Sopenharmony_ci 34558c2ecf20Sopenharmony_ci spin_lock_irqsave(&ioc->diag_trigger_lock, flags); 34568c2ecf20Sopenharmony_ci rc = sizeof(struct SL_WH_MASTER_TRIGGER_T); 34578c2ecf20Sopenharmony_ci memcpy(buf, &ioc->diag_trigger_master, rc); 34588c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags); 34598c2ecf20Sopenharmony_ci return rc; 34608c2ecf20Sopenharmony_ci} 34618c2ecf20Sopenharmony_ci 34628c2ecf20Sopenharmony_ci/** 34638c2ecf20Sopenharmony_ci * diag_trigger_master_store - store the diag_trigger_master attribute 34648c2ecf20Sopenharmony_ci * @cdev: pointer to embedded class device 34658c2ecf20Sopenharmony_ci * @attr: ? 34668c2ecf20Sopenharmony_ci * @buf: the buffer returned 34678c2ecf20Sopenharmony_ci * @count: ? 34688c2ecf20Sopenharmony_ci * 34698c2ecf20Sopenharmony_ci * A sysfs 'read/write' shost attribute. 34708c2ecf20Sopenharmony_ci */ 34718c2ecf20Sopenharmony_cistatic ssize_t 34728c2ecf20Sopenharmony_cidiag_trigger_master_store(struct device *cdev, 34738c2ecf20Sopenharmony_ci struct device_attribute *attr, const char *buf, size_t count) 34748c2ecf20Sopenharmony_ci 34758c2ecf20Sopenharmony_ci{ 34768c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(cdev); 34778c2ecf20Sopenharmony_ci struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); 34788c2ecf20Sopenharmony_ci unsigned long flags; 34798c2ecf20Sopenharmony_ci ssize_t rc; 34808c2ecf20Sopenharmony_ci 34818c2ecf20Sopenharmony_ci spin_lock_irqsave(&ioc->diag_trigger_lock, flags); 34828c2ecf20Sopenharmony_ci rc = min(sizeof(struct SL_WH_MASTER_TRIGGER_T), count); 34838c2ecf20Sopenharmony_ci memset(&ioc->diag_trigger_master, 0, 34848c2ecf20Sopenharmony_ci sizeof(struct SL_WH_MASTER_TRIGGER_T)); 34858c2ecf20Sopenharmony_ci memcpy(&ioc->diag_trigger_master, buf, rc); 34868c2ecf20Sopenharmony_ci ioc->diag_trigger_master.MasterData |= 34878c2ecf20Sopenharmony_ci (MASTER_TRIGGER_FW_FAULT + MASTER_TRIGGER_ADAPTER_RESET); 34888c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags); 34898c2ecf20Sopenharmony_ci return rc; 34908c2ecf20Sopenharmony_ci} 34918c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(diag_trigger_master); 34928c2ecf20Sopenharmony_ci 34938c2ecf20Sopenharmony_ci 34948c2ecf20Sopenharmony_ci/** 34958c2ecf20Sopenharmony_ci * diag_trigger_event_show - show the diag_trigger_event attribute 34968c2ecf20Sopenharmony_ci * @cdev: pointer to embedded class device 34978c2ecf20Sopenharmony_ci * @attr: ? 34988c2ecf20Sopenharmony_ci * @buf: the buffer returned 34998c2ecf20Sopenharmony_ci * 35008c2ecf20Sopenharmony_ci * A sysfs 'read/write' shost attribute. 35018c2ecf20Sopenharmony_ci */ 35028c2ecf20Sopenharmony_cistatic ssize_t 35038c2ecf20Sopenharmony_cidiag_trigger_event_show(struct device *cdev, 35048c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 35058c2ecf20Sopenharmony_ci{ 35068c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(cdev); 35078c2ecf20Sopenharmony_ci struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); 35088c2ecf20Sopenharmony_ci unsigned long flags; 35098c2ecf20Sopenharmony_ci ssize_t rc; 35108c2ecf20Sopenharmony_ci 35118c2ecf20Sopenharmony_ci spin_lock_irqsave(&ioc->diag_trigger_lock, flags); 35128c2ecf20Sopenharmony_ci rc = sizeof(struct SL_WH_EVENT_TRIGGERS_T); 35138c2ecf20Sopenharmony_ci memcpy(buf, &ioc->diag_trigger_event, rc); 35148c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags); 35158c2ecf20Sopenharmony_ci return rc; 35168c2ecf20Sopenharmony_ci} 35178c2ecf20Sopenharmony_ci 35188c2ecf20Sopenharmony_ci/** 35198c2ecf20Sopenharmony_ci * diag_trigger_event_store - store the diag_trigger_event attribute 35208c2ecf20Sopenharmony_ci * @cdev: pointer to embedded class device 35218c2ecf20Sopenharmony_ci * @attr: ? 35228c2ecf20Sopenharmony_ci * @buf: the buffer returned 35238c2ecf20Sopenharmony_ci * @count: ? 35248c2ecf20Sopenharmony_ci * 35258c2ecf20Sopenharmony_ci * A sysfs 'read/write' shost attribute. 35268c2ecf20Sopenharmony_ci */ 35278c2ecf20Sopenharmony_cistatic ssize_t 35288c2ecf20Sopenharmony_cidiag_trigger_event_store(struct device *cdev, 35298c2ecf20Sopenharmony_ci struct device_attribute *attr, const char *buf, size_t count) 35308c2ecf20Sopenharmony_ci 35318c2ecf20Sopenharmony_ci{ 35328c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(cdev); 35338c2ecf20Sopenharmony_ci struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); 35348c2ecf20Sopenharmony_ci unsigned long flags; 35358c2ecf20Sopenharmony_ci ssize_t sz; 35368c2ecf20Sopenharmony_ci 35378c2ecf20Sopenharmony_ci spin_lock_irqsave(&ioc->diag_trigger_lock, flags); 35388c2ecf20Sopenharmony_ci sz = min(sizeof(struct SL_WH_EVENT_TRIGGERS_T), count); 35398c2ecf20Sopenharmony_ci memset(&ioc->diag_trigger_event, 0, 35408c2ecf20Sopenharmony_ci sizeof(struct SL_WH_EVENT_TRIGGERS_T)); 35418c2ecf20Sopenharmony_ci memcpy(&ioc->diag_trigger_event, buf, sz); 35428c2ecf20Sopenharmony_ci if (ioc->diag_trigger_event.ValidEntries > NUM_VALID_ENTRIES) 35438c2ecf20Sopenharmony_ci ioc->diag_trigger_event.ValidEntries = NUM_VALID_ENTRIES; 35448c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags); 35458c2ecf20Sopenharmony_ci return sz; 35468c2ecf20Sopenharmony_ci} 35478c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(diag_trigger_event); 35488c2ecf20Sopenharmony_ci 35498c2ecf20Sopenharmony_ci 35508c2ecf20Sopenharmony_ci/** 35518c2ecf20Sopenharmony_ci * diag_trigger_scsi_show - show the diag_trigger_scsi attribute 35528c2ecf20Sopenharmony_ci * @cdev: pointer to embedded class device 35538c2ecf20Sopenharmony_ci * @attr: ? 35548c2ecf20Sopenharmony_ci * @buf: the buffer returned 35558c2ecf20Sopenharmony_ci * 35568c2ecf20Sopenharmony_ci * A sysfs 'read/write' shost attribute. 35578c2ecf20Sopenharmony_ci */ 35588c2ecf20Sopenharmony_cistatic ssize_t 35598c2ecf20Sopenharmony_cidiag_trigger_scsi_show(struct device *cdev, 35608c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 35618c2ecf20Sopenharmony_ci{ 35628c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(cdev); 35638c2ecf20Sopenharmony_ci struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); 35648c2ecf20Sopenharmony_ci unsigned long flags; 35658c2ecf20Sopenharmony_ci ssize_t rc; 35668c2ecf20Sopenharmony_ci 35678c2ecf20Sopenharmony_ci spin_lock_irqsave(&ioc->diag_trigger_lock, flags); 35688c2ecf20Sopenharmony_ci rc = sizeof(struct SL_WH_SCSI_TRIGGERS_T); 35698c2ecf20Sopenharmony_ci memcpy(buf, &ioc->diag_trigger_scsi, rc); 35708c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags); 35718c2ecf20Sopenharmony_ci return rc; 35728c2ecf20Sopenharmony_ci} 35738c2ecf20Sopenharmony_ci 35748c2ecf20Sopenharmony_ci/** 35758c2ecf20Sopenharmony_ci * diag_trigger_scsi_store - store the diag_trigger_scsi attribute 35768c2ecf20Sopenharmony_ci * @cdev: pointer to embedded class device 35778c2ecf20Sopenharmony_ci * @attr: ? 35788c2ecf20Sopenharmony_ci * @buf: the buffer returned 35798c2ecf20Sopenharmony_ci * @count: ? 35808c2ecf20Sopenharmony_ci * 35818c2ecf20Sopenharmony_ci * A sysfs 'read/write' shost attribute. 35828c2ecf20Sopenharmony_ci */ 35838c2ecf20Sopenharmony_cistatic ssize_t 35848c2ecf20Sopenharmony_cidiag_trigger_scsi_store(struct device *cdev, 35858c2ecf20Sopenharmony_ci struct device_attribute *attr, const char *buf, size_t count) 35868c2ecf20Sopenharmony_ci{ 35878c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(cdev); 35888c2ecf20Sopenharmony_ci struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); 35898c2ecf20Sopenharmony_ci unsigned long flags; 35908c2ecf20Sopenharmony_ci ssize_t sz; 35918c2ecf20Sopenharmony_ci 35928c2ecf20Sopenharmony_ci spin_lock_irqsave(&ioc->diag_trigger_lock, flags); 35938c2ecf20Sopenharmony_ci sz = min(sizeof(ioc->diag_trigger_scsi), count); 35948c2ecf20Sopenharmony_ci memset(&ioc->diag_trigger_scsi, 0, sizeof(ioc->diag_trigger_scsi)); 35958c2ecf20Sopenharmony_ci memcpy(&ioc->diag_trigger_scsi, buf, sz); 35968c2ecf20Sopenharmony_ci if (ioc->diag_trigger_scsi.ValidEntries > NUM_VALID_ENTRIES) 35978c2ecf20Sopenharmony_ci ioc->diag_trigger_scsi.ValidEntries = NUM_VALID_ENTRIES; 35988c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags); 35998c2ecf20Sopenharmony_ci return sz; 36008c2ecf20Sopenharmony_ci} 36018c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(diag_trigger_scsi); 36028c2ecf20Sopenharmony_ci 36038c2ecf20Sopenharmony_ci 36048c2ecf20Sopenharmony_ci/** 36058c2ecf20Sopenharmony_ci * diag_trigger_scsi_show - show the diag_trigger_mpi attribute 36068c2ecf20Sopenharmony_ci * @cdev: pointer to embedded class device 36078c2ecf20Sopenharmony_ci * @attr: ? 36088c2ecf20Sopenharmony_ci * @buf: the buffer returned 36098c2ecf20Sopenharmony_ci * 36108c2ecf20Sopenharmony_ci * A sysfs 'read/write' shost attribute. 36118c2ecf20Sopenharmony_ci */ 36128c2ecf20Sopenharmony_cistatic ssize_t 36138c2ecf20Sopenharmony_cidiag_trigger_mpi_show(struct device *cdev, 36148c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 36158c2ecf20Sopenharmony_ci{ 36168c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(cdev); 36178c2ecf20Sopenharmony_ci struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); 36188c2ecf20Sopenharmony_ci unsigned long flags; 36198c2ecf20Sopenharmony_ci ssize_t rc; 36208c2ecf20Sopenharmony_ci 36218c2ecf20Sopenharmony_ci spin_lock_irqsave(&ioc->diag_trigger_lock, flags); 36228c2ecf20Sopenharmony_ci rc = sizeof(struct SL_WH_MPI_TRIGGERS_T); 36238c2ecf20Sopenharmony_ci memcpy(buf, &ioc->diag_trigger_mpi, rc); 36248c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags); 36258c2ecf20Sopenharmony_ci return rc; 36268c2ecf20Sopenharmony_ci} 36278c2ecf20Sopenharmony_ci 36288c2ecf20Sopenharmony_ci/** 36298c2ecf20Sopenharmony_ci * diag_trigger_mpi_store - store the diag_trigger_mpi attribute 36308c2ecf20Sopenharmony_ci * @cdev: pointer to embedded class device 36318c2ecf20Sopenharmony_ci * @attr: ? 36328c2ecf20Sopenharmony_ci * @buf: the buffer returned 36338c2ecf20Sopenharmony_ci * @count: ? 36348c2ecf20Sopenharmony_ci * 36358c2ecf20Sopenharmony_ci * A sysfs 'read/write' shost attribute. 36368c2ecf20Sopenharmony_ci */ 36378c2ecf20Sopenharmony_cistatic ssize_t 36388c2ecf20Sopenharmony_cidiag_trigger_mpi_store(struct device *cdev, 36398c2ecf20Sopenharmony_ci struct device_attribute *attr, const char *buf, size_t count) 36408c2ecf20Sopenharmony_ci{ 36418c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(cdev); 36428c2ecf20Sopenharmony_ci struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); 36438c2ecf20Sopenharmony_ci unsigned long flags; 36448c2ecf20Sopenharmony_ci ssize_t sz; 36458c2ecf20Sopenharmony_ci 36468c2ecf20Sopenharmony_ci spin_lock_irqsave(&ioc->diag_trigger_lock, flags); 36478c2ecf20Sopenharmony_ci sz = min(sizeof(struct SL_WH_MPI_TRIGGERS_T), count); 36488c2ecf20Sopenharmony_ci memset(&ioc->diag_trigger_mpi, 0, 36498c2ecf20Sopenharmony_ci sizeof(ioc->diag_trigger_mpi)); 36508c2ecf20Sopenharmony_ci memcpy(&ioc->diag_trigger_mpi, buf, sz); 36518c2ecf20Sopenharmony_ci if (ioc->diag_trigger_mpi.ValidEntries > NUM_VALID_ENTRIES) 36528c2ecf20Sopenharmony_ci ioc->diag_trigger_mpi.ValidEntries = NUM_VALID_ENTRIES; 36538c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags); 36548c2ecf20Sopenharmony_ci return sz; 36558c2ecf20Sopenharmony_ci} 36568c2ecf20Sopenharmony_ci 36578c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(diag_trigger_mpi); 36588c2ecf20Sopenharmony_ci 36598c2ecf20Sopenharmony_ci/*********** diagnostic trigger suppport *** END ****************************/ 36608c2ecf20Sopenharmony_ci 36618c2ecf20Sopenharmony_ci/*****************************************/ 36628c2ecf20Sopenharmony_ci 36638c2ecf20Sopenharmony_ci/** 36648c2ecf20Sopenharmony_ci * drv_support_bitmap_show - driver supported feature bitmap 36658c2ecf20Sopenharmony_ci * @cdev: pointer to embedded class device 36668c2ecf20Sopenharmony_ci * @attr: unused 36678c2ecf20Sopenharmony_ci * @buf: the buffer returned 36688c2ecf20Sopenharmony_ci * 36698c2ecf20Sopenharmony_ci * A sysfs 'read-only' shost attribute. 36708c2ecf20Sopenharmony_ci */ 36718c2ecf20Sopenharmony_cistatic ssize_t 36728c2ecf20Sopenharmony_cidrv_support_bitmap_show(struct device *cdev, 36738c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 36748c2ecf20Sopenharmony_ci{ 36758c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(cdev); 36768c2ecf20Sopenharmony_ci struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); 36778c2ecf20Sopenharmony_ci 36788c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "0x%08x\n", ioc->drv_support_bitmap); 36798c2ecf20Sopenharmony_ci} 36808c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(drv_support_bitmap); 36818c2ecf20Sopenharmony_ci 36828c2ecf20Sopenharmony_ci/** 36838c2ecf20Sopenharmony_ci * enable_sdev_max_qd_show - display whether sdev max qd is enabled/disabled 36848c2ecf20Sopenharmony_ci * @cdev: pointer to embedded class device 36858c2ecf20Sopenharmony_ci * @attr: unused 36868c2ecf20Sopenharmony_ci * @buf: the buffer returned 36878c2ecf20Sopenharmony_ci * 36888c2ecf20Sopenharmony_ci * A sysfs read/write shost attribute. This attribute is used to set the 36898c2ecf20Sopenharmony_ci * targets queue depth to HBA IO queue depth if this attribute is enabled. 36908c2ecf20Sopenharmony_ci */ 36918c2ecf20Sopenharmony_cistatic ssize_t 36928c2ecf20Sopenharmony_cienable_sdev_max_qd_show(struct device *cdev, 36938c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 36948c2ecf20Sopenharmony_ci{ 36958c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(cdev); 36968c2ecf20Sopenharmony_ci struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); 36978c2ecf20Sopenharmony_ci 36988c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "%d\n", ioc->enable_sdev_max_qd); 36998c2ecf20Sopenharmony_ci} 37008c2ecf20Sopenharmony_ci 37018c2ecf20Sopenharmony_ci/** 37028c2ecf20Sopenharmony_ci * enable_sdev_max_qd_store - Enable/disable sdev max qd 37038c2ecf20Sopenharmony_ci * @cdev: pointer to embedded class device 37048c2ecf20Sopenharmony_ci * @attr: unused 37058c2ecf20Sopenharmony_ci * @buf: the buffer returned 37068c2ecf20Sopenharmony_ci * @count: unused 37078c2ecf20Sopenharmony_ci * 37088c2ecf20Sopenharmony_ci * A sysfs read/write shost attribute. This attribute is used to set the 37098c2ecf20Sopenharmony_ci * targets queue depth to HBA IO queue depth if this attribute is enabled. 37108c2ecf20Sopenharmony_ci * If this attribute is disabled then targets will have corresponding default 37118c2ecf20Sopenharmony_ci * queue depth. 37128c2ecf20Sopenharmony_ci */ 37138c2ecf20Sopenharmony_cistatic ssize_t 37148c2ecf20Sopenharmony_cienable_sdev_max_qd_store(struct device *cdev, 37158c2ecf20Sopenharmony_ci struct device_attribute *attr, const char *buf, size_t count) 37168c2ecf20Sopenharmony_ci{ 37178c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(cdev); 37188c2ecf20Sopenharmony_ci struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); 37198c2ecf20Sopenharmony_ci struct MPT3SAS_DEVICE *sas_device_priv_data; 37208c2ecf20Sopenharmony_ci struct MPT3SAS_TARGET *sas_target_priv_data; 37218c2ecf20Sopenharmony_ci int val = 0; 37228c2ecf20Sopenharmony_ci struct scsi_device *sdev; 37238c2ecf20Sopenharmony_ci struct _raid_device *raid_device; 37248c2ecf20Sopenharmony_ci int qdepth; 37258c2ecf20Sopenharmony_ci 37268c2ecf20Sopenharmony_ci if (kstrtoint(buf, 0, &val) != 0) 37278c2ecf20Sopenharmony_ci return -EINVAL; 37288c2ecf20Sopenharmony_ci 37298c2ecf20Sopenharmony_ci switch (val) { 37308c2ecf20Sopenharmony_ci case 0: 37318c2ecf20Sopenharmony_ci ioc->enable_sdev_max_qd = 0; 37328c2ecf20Sopenharmony_ci shost_for_each_device(sdev, ioc->shost) { 37338c2ecf20Sopenharmony_ci sas_device_priv_data = sdev->hostdata; 37348c2ecf20Sopenharmony_ci if (!sas_device_priv_data) 37358c2ecf20Sopenharmony_ci continue; 37368c2ecf20Sopenharmony_ci sas_target_priv_data = sas_device_priv_data->sas_target; 37378c2ecf20Sopenharmony_ci if (!sas_target_priv_data) 37388c2ecf20Sopenharmony_ci continue; 37398c2ecf20Sopenharmony_ci 37408c2ecf20Sopenharmony_ci if (sas_target_priv_data->flags & 37418c2ecf20Sopenharmony_ci MPT_TARGET_FLAGS_VOLUME) { 37428c2ecf20Sopenharmony_ci raid_device = 37438c2ecf20Sopenharmony_ci mpt3sas_raid_device_find_by_handle(ioc, 37448c2ecf20Sopenharmony_ci sas_target_priv_data->handle); 37458c2ecf20Sopenharmony_ci 37468c2ecf20Sopenharmony_ci switch (raid_device->volume_type) { 37478c2ecf20Sopenharmony_ci case MPI2_RAID_VOL_TYPE_RAID0: 37488c2ecf20Sopenharmony_ci if (raid_device->device_info & 37498c2ecf20Sopenharmony_ci MPI2_SAS_DEVICE_INFO_SSP_TARGET) 37508c2ecf20Sopenharmony_ci qdepth = 37518c2ecf20Sopenharmony_ci MPT3SAS_SAS_QUEUE_DEPTH; 37528c2ecf20Sopenharmony_ci else 37538c2ecf20Sopenharmony_ci qdepth = 37548c2ecf20Sopenharmony_ci MPT3SAS_SATA_QUEUE_DEPTH; 37558c2ecf20Sopenharmony_ci break; 37568c2ecf20Sopenharmony_ci case MPI2_RAID_VOL_TYPE_RAID1E: 37578c2ecf20Sopenharmony_ci case MPI2_RAID_VOL_TYPE_RAID1: 37588c2ecf20Sopenharmony_ci case MPI2_RAID_VOL_TYPE_RAID10: 37598c2ecf20Sopenharmony_ci case MPI2_RAID_VOL_TYPE_UNKNOWN: 37608c2ecf20Sopenharmony_ci default: 37618c2ecf20Sopenharmony_ci qdepth = MPT3SAS_RAID_QUEUE_DEPTH; 37628c2ecf20Sopenharmony_ci } 37638c2ecf20Sopenharmony_ci } else if (sas_target_priv_data->flags & 37648c2ecf20Sopenharmony_ci MPT_TARGET_FLAGS_PCIE_DEVICE) 37658c2ecf20Sopenharmony_ci qdepth = MPT3SAS_NVME_QUEUE_DEPTH; 37668c2ecf20Sopenharmony_ci else 37678c2ecf20Sopenharmony_ci qdepth = MPT3SAS_SAS_QUEUE_DEPTH; 37688c2ecf20Sopenharmony_ci 37698c2ecf20Sopenharmony_ci mpt3sas_scsih_change_queue_depth(sdev, qdepth); 37708c2ecf20Sopenharmony_ci } 37718c2ecf20Sopenharmony_ci break; 37728c2ecf20Sopenharmony_ci case 1: 37738c2ecf20Sopenharmony_ci ioc->enable_sdev_max_qd = 1; 37748c2ecf20Sopenharmony_ci shost_for_each_device(sdev, ioc->shost) 37758c2ecf20Sopenharmony_ci mpt3sas_scsih_change_queue_depth(sdev, 37768c2ecf20Sopenharmony_ci shost->can_queue); 37778c2ecf20Sopenharmony_ci break; 37788c2ecf20Sopenharmony_ci default: 37798c2ecf20Sopenharmony_ci return -EINVAL; 37808c2ecf20Sopenharmony_ci } 37818c2ecf20Sopenharmony_ci 37828c2ecf20Sopenharmony_ci return strlen(buf); 37838c2ecf20Sopenharmony_ci} 37848c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(enable_sdev_max_qd); 37858c2ecf20Sopenharmony_ci 37868c2ecf20Sopenharmony_cistruct device_attribute *mpt3sas_host_attrs[] = { 37878c2ecf20Sopenharmony_ci &dev_attr_version_fw, 37888c2ecf20Sopenharmony_ci &dev_attr_version_bios, 37898c2ecf20Sopenharmony_ci &dev_attr_version_mpi, 37908c2ecf20Sopenharmony_ci &dev_attr_version_product, 37918c2ecf20Sopenharmony_ci &dev_attr_version_nvdata_persistent, 37928c2ecf20Sopenharmony_ci &dev_attr_version_nvdata_default, 37938c2ecf20Sopenharmony_ci &dev_attr_board_name, 37948c2ecf20Sopenharmony_ci &dev_attr_board_assembly, 37958c2ecf20Sopenharmony_ci &dev_attr_board_tracer, 37968c2ecf20Sopenharmony_ci &dev_attr_io_delay, 37978c2ecf20Sopenharmony_ci &dev_attr_device_delay, 37988c2ecf20Sopenharmony_ci &dev_attr_logging_level, 37998c2ecf20Sopenharmony_ci &dev_attr_fwfault_debug, 38008c2ecf20Sopenharmony_ci &dev_attr_fw_queue_depth, 38018c2ecf20Sopenharmony_ci &dev_attr_host_sas_address, 38028c2ecf20Sopenharmony_ci &dev_attr_ioc_reset_count, 38038c2ecf20Sopenharmony_ci &dev_attr_host_trace_buffer_size, 38048c2ecf20Sopenharmony_ci &dev_attr_host_trace_buffer, 38058c2ecf20Sopenharmony_ci &dev_attr_host_trace_buffer_enable, 38068c2ecf20Sopenharmony_ci &dev_attr_reply_queue_count, 38078c2ecf20Sopenharmony_ci &dev_attr_diag_trigger_master, 38088c2ecf20Sopenharmony_ci &dev_attr_diag_trigger_event, 38098c2ecf20Sopenharmony_ci &dev_attr_diag_trigger_scsi, 38108c2ecf20Sopenharmony_ci &dev_attr_diag_trigger_mpi, 38118c2ecf20Sopenharmony_ci &dev_attr_drv_support_bitmap, 38128c2ecf20Sopenharmony_ci &dev_attr_BRM_status, 38138c2ecf20Sopenharmony_ci &dev_attr_enable_sdev_max_qd, 38148c2ecf20Sopenharmony_ci NULL, 38158c2ecf20Sopenharmony_ci}; 38168c2ecf20Sopenharmony_ci 38178c2ecf20Sopenharmony_ci/* device attributes */ 38188c2ecf20Sopenharmony_ci 38198c2ecf20Sopenharmony_ci/** 38208c2ecf20Sopenharmony_ci * sas_address_show - sas address 38218c2ecf20Sopenharmony_ci * @dev: pointer to embedded class device 38228c2ecf20Sopenharmony_ci * @attr: ? 38238c2ecf20Sopenharmony_ci * @buf: the buffer returned 38248c2ecf20Sopenharmony_ci * 38258c2ecf20Sopenharmony_ci * This is the sas address for the target 38268c2ecf20Sopenharmony_ci * 38278c2ecf20Sopenharmony_ci * A sysfs 'read-only' shost attribute. 38288c2ecf20Sopenharmony_ci */ 38298c2ecf20Sopenharmony_cistatic ssize_t 38308c2ecf20Sopenharmony_cisas_address_show(struct device *dev, struct device_attribute *attr, 38318c2ecf20Sopenharmony_ci char *buf) 38328c2ecf20Sopenharmony_ci{ 38338c2ecf20Sopenharmony_ci struct scsi_device *sdev = to_scsi_device(dev); 38348c2ecf20Sopenharmony_ci struct MPT3SAS_DEVICE *sas_device_priv_data = sdev->hostdata; 38358c2ecf20Sopenharmony_ci 38368c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "0x%016llx\n", 38378c2ecf20Sopenharmony_ci (unsigned long long)sas_device_priv_data->sas_target->sas_address); 38388c2ecf20Sopenharmony_ci} 38398c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(sas_address); 38408c2ecf20Sopenharmony_ci 38418c2ecf20Sopenharmony_ci/** 38428c2ecf20Sopenharmony_ci * sas_device_handle_show - device handle 38438c2ecf20Sopenharmony_ci * @dev: pointer to embedded class device 38448c2ecf20Sopenharmony_ci * @attr: ? 38458c2ecf20Sopenharmony_ci * @buf: the buffer returned 38468c2ecf20Sopenharmony_ci * 38478c2ecf20Sopenharmony_ci * This is the firmware assigned device handle 38488c2ecf20Sopenharmony_ci * 38498c2ecf20Sopenharmony_ci * A sysfs 'read-only' shost attribute. 38508c2ecf20Sopenharmony_ci */ 38518c2ecf20Sopenharmony_cistatic ssize_t 38528c2ecf20Sopenharmony_cisas_device_handle_show(struct device *dev, struct device_attribute *attr, 38538c2ecf20Sopenharmony_ci char *buf) 38548c2ecf20Sopenharmony_ci{ 38558c2ecf20Sopenharmony_ci struct scsi_device *sdev = to_scsi_device(dev); 38568c2ecf20Sopenharmony_ci struct MPT3SAS_DEVICE *sas_device_priv_data = sdev->hostdata; 38578c2ecf20Sopenharmony_ci 38588c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "0x%04x\n", 38598c2ecf20Sopenharmony_ci sas_device_priv_data->sas_target->handle); 38608c2ecf20Sopenharmony_ci} 38618c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(sas_device_handle); 38628c2ecf20Sopenharmony_ci 38638c2ecf20Sopenharmony_ci/** 38648c2ecf20Sopenharmony_ci * sas_ncq_io_prio_show - send prioritized io commands to device 38658c2ecf20Sopenharmony_ci * @dev: pointer to embedded device 38668c2ecf20Sopenharmony_ci * @attr: ? 38678c2ecf20Sopenharmony_ci * @buf: the buffer returned 38688c2ecf20Sopenharmony_ci * 38698c2ecf20Sopenharmony_ci * A sysfs 'read/write' sdev attribute, only works with SATA 38708c2ecf20Sopenharmony_ci */ 38718c2ecf20Sopenharmony_cistatic ssize_t 38728c2ecf20Sopenharmony_cisas_ncq_prio_enable_show(struct device *dev, 38738c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 38748c2ecf20Sopenharmony_ci{ 38758c2ecf20Sopenharmony_ci struct scsi_device *sdev = to_scsi_device(dev); 38768c2ecf20Sopenharmony_ci struct MPT3SAS_DEVICE *sas_device_priv_data = sdev->hostdata; 38778c2ecf20Sopenharmony_ci 38788c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "%d\n", 38798c2ecf20Sopenharmony_ci sas_device_priv_data->ncq_prio_enable); 38808c2ecf20Sopenharmony_ci} 38818c2ecf20Sopenharmony_ci 38828c2ecf20Sopenharmony_cistatic ssize_t 38838c2ecf20Sopenharmony_cisas_ncq_prio_enable_store(struct device *dev, 38848c2ecf20Sopenharmony_ci struct device_attribute *attr, 38858c2ecf20Sopenharmony_ci const char *buf, size_t count) 38868c2ecf20Sopenharmony_ci{ 38878c2ecf20Sopenharmony_ci struct scsi_device *sdev = to_scsi_device(dev); 38888c2ecf20Sopenharmony_ci struct MPT3SAS_DEVICE *sas_device_priv_data = sdev->hostdata; 38898c2ecf20Sopenharmony_ci bool ncq_prio_enable = 0; 38908c2ecf20Sopenharmony_ci 38918c2ecf20Sopenharmony_ci if (kstrtobool(buf, &ncq_prio_enable)) 38928c2ecf20Sopenharmony_ci return -EINVAL; 38938c2ecf20Sopenharmony_ci 38948c2ecf20Sopenharmony_ci if (!scsih_ncq_prio_supp(sdev)) 38958c2ecf20Sopenharmony_ci return -EINVAL; 38968c2ecf20Sopenharmony_ci 38978c2ecf20Sopenharmony_ci sas_device_priv_data->ncq_prio_enable = ncq_prio_enable; 38988c2ecf20Sopenharmony_ci return strlen(buf); 38998c2ecf20Sopenharmony_ci} 39008c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(sas_ncq_prio_enable); 39018c2ecf20Sopenharmony_ci 39028c2ecf20Sopenharmony_cistruct device_attribute *mpt3sas_dev_attrs[] = { 39038c2ecf20Sopenharmony_ci &dev_attr_sas_address, 39048c2ecf20Sopenharmony_ci &dev_attr_sas_device_handle, 39058c2ecf20Sopenharmony_ci &dev_attr_sas_ncq_prio_enable, 39068c2ecf20Sopenharmony_ci NULL, 39078c2ecf20Sopenharmony_ci}; 39088c2ecf20Sopenharmony_ci 39098c2ecf20Sopenharmony_ci/* file operations table for mpt3ctl device */ 39108c2ecf20Sopenharmony_cistatic const struct file_operations ctl_fops = { 39118c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 39128c2ecf20Sopenharmony_ci .unlocked_ioctl = _ctl_ioctl, 39138c2ecf20Sopenharmony_ci .poll = _ctl_poll, 39148c2ecf20Sopenharmony_ci .fasync = _ctl_fasync, 39158c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT 39168c2ecf20Sopenharmony_ci .compat_ioctl = _ctl_ioctl_compat, 39178c2ecf20Sopenharmony_ci#endif 39188c2ecf20Sopenharmony_ci}; 39198c2ecf20Sopenharmony_ci 39208c2ecf20Sopenharmony_ci/* file operations table for mpt2ctl device */ 39218c2ecf20Sopenharmony_cistatic const struct file_operations ctl_gen2_fops = { 39228c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 39238c2ecf20Sopenharmony_ci .unlocked_ioctl = _ctl_mpt2_ioctl, 39248c2ecf20Sopenharmony_ci .poll = _ctl_poll, 39258c2ecf20Sopenharmony_ci .fasync = _ctl_fasync, 39268c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT 39278c2ecf20Sopenharmony_ci .compat_ioctl = _ctl_mpt2_ioctl_compat, 39288c2ecf20Sopenharmony_ci#endif 39298c2ecf20Sopenharmony_ci}; 39308c2ecf20Sopenharmony_ci 39318c2ecf20Sopenharmony_cistatic struct miscdevice ctl_dev = { 39328c2ecf20Sopenharmony_ci .minor = MPT3SAS_MINOR, 39338c2ecf20Sopenharmony_ci .name = MPT3SAS_DEV_NAME, 39348c2ecf20Sopenharmony_ci .fops = &ctl_fops, 39358c2ecf20Sopenharmony_ci}; 39368c2ecf20Sopenharmony_ci 39378c2ecf20Sopenharmony_cistatic struct miscdevice gen2_ctl_dev = { 39388c2ecf20Sopenharmony_ci .minor = MPT2SAS_MINOR, 39398c2ecf20Sopenharmony_ci .name = MPT2SAS_DEV_NAME, 39408c2ecf20Sopenharmony_ci .fops = &ctl_gen2_fops, 39418c2ecf20Sopenharmony_ci}; 39428c2ecf20Sopenharmony_ci 39438c2ecf20Sopenharmony_ci/** 39448c2ecf20Sopenharmony_ci * mpt3sas_ctl_init - main entry point for ctl. 39458c2ecf20Sopenharmony_ci * @hbas_to_enumerate: ? 39468c2ecf20Sopenharmony_ci */ 39478c2ecf20Sopenharmony_civoid 39488c2ecf20Sopenharmony_cimpt3sas_ctl_init(ushort hbas_to_enumerate) 39498c2ecf20Sopenharmony_ci{ 39508c2ecf20Sopenharmony_ci async_queue = NULL; 39518c2ecf20Sopenharmony_ci 39528c2ecf20Sopenharmony_ci /* Don't register mpt3ctl ioctl device if 39538c2ecf20Sopenharmony_ci * hbas_to_enumarate is one. 39548c2ecf20Sopenharmony_ci */ 39558c2ecf20Sopenharmony_ci if (hbas_to_enumerate != 1) 39568c2ecf20Sopenharmony_ci if (misc_register(&ctl_dev) < 0) 39578c2ecf20Sopenharmony_ci pr_err("%s can't register misc device [minor=%d]\n", 39588c2ecf20Sopenharmony_ci MPT3SAS_DRIVER_NAME, MPT3SAS_MINOR); 39598c2ecf20Sopenharmony_ci 39608c2ecf20Sopenharmony_ci /* Don't register mpt3ctl ioctl device if 39618c2ecf20Sopenharmony_ci * hbas_to_enumarate is two. 39628c2ecf20Sopenharmony_ci */ 39638c2ecf20Sopenharmony_ci if (hbas_to_enumerate != 2) 39648c2ecf20Sopenharmony_ci if (misc_register(&gen2_ctl_dev) < 0) 39658c2ecf20Sopenharmony_ci pr_err("%s can't register misc device [minor=%d]\n", 39668c2ecf20Sopenharmony_ci MPT2SAS_DRIVER_NAME, MPT2SAS_MINOR); 39678c2ecf20Sopenharmony_ci 39688c2ecf20Sopenharmony_ci init_waitqueue_head(&ctl_poll_wait); 39698c2ecf20Sopenharmony_ci} 39708c2ecf20Sopenharmony_ci 39718c2ecf20Sopenharmony_ci/** 39728c2ecf20Sopenharmony_ci * mpt3sas_ctl_exit - exit point for ctl 39738c2ecf20Sopenharmony_ci * @hbas_to_enumerate: ? 39748c2ecf20Sopenharmony_ci */ 39758c2ecf20Sopenharmony_civoid 39768c2ecf20Sopenharmony_cimpt3sas_ctl_exit(ushort hbas_to_enumerate) 39778c2ecf20Sopenharmony_ci{ 39788c2ecf20Sopenharmony_ci struct MPT3SAS_ADAPTER *ioc; 39798c2ecf20Sopenharmony_ci int i; 39808c2ecf20Sopenharmony_ci 39818c2ecf20Sopenharmony_ci list_for_each_entry(ioc, &mpt3sas_ioc_list, list) { 39828c2ecf20Sopenharmony_ci 39838c2ecf20Sopenharmony_ci /* free memory associated to diag buffers */ 39848c2ecf20Sopenharmony_ci for (i = 0; i < MPI2_DIAG_BUF_TYPE_COUNT; i++) { 39858c2ecf20Sopenharmony_ci if (!ioc->diag_buffer[i]) 39868c2ecf20Sopenharmony_ci continue; 39878c2ecf20Sopenharmony_ci dma_free_coherent(&ioc->pdev->dev, 39888c2ecf20Sopenharmony_ci ioc->diag_buffer_sz[i], 39898c2ecf20Sopenharmony_ci ioc->diag_buffer[i], 39908c2ecf20Sopenharmony_ci ioc->diag_buffer_dma[i]); 39918c2ecf20Sopenharmony_ci ioc->diag_buffer[i] = NULL; 39928c2ecf20Sopenharmony_ci ioc->diag_buffer_status[i] = 0; 39938c2ecf20Sopenharmony_ci } 39948c2ecf20Sopenharmony_ci 39958c2ecf20Sopenharmony_ci kfree(ioc->event_log); 39968c2ecf20Sopenharmony_ci } 39978c2ecf20Sopenharmony_ci if (hbas_to_enumerate != 1) 39988c2ecf20Sopenharmony_ci misc_deregister(&ctl_dev); 39998c2ecf20Sopenharmony_ci if (hbas_to_enumerate != 2) 40008c2ecf20Sopenharmony_ci misc_deregister(&gen2_ctl_dev); 40018c2ecf20Sopenharmony_ci} 4002