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