xref: /linux/drivers/scsi/mpt3sas/mpt3sas_ctl.c (revision 77fd4f2c88bf83205a21f9ca49fdcc0c7868dba9)
1f92363d1SSreekanth Reddy /*
2f92363d1SSreekanth Reddy  * Management Module Support for MPT (Message Passing Technology) based
3f92363d1SSreekanth Reddy  * controllers
4f92363d1SSreekanth Reddy  *
5f92363d1SSreekanth Reddy  * This code is based on drivers/scsi/mpt3sas/mpt3sas_ctl.c
6a4ffce0dSSreekanth Reddy  * Copyright (C) 2012-2014  LSI Corporation
7a03bd153SSreekanth Reddy  * Copyright (C) 2013-2014 Avago Technologies
8a03bd153SSreekanth Reddy  *  (mailto: MPT-FusionLinux.pdl@avagotech.com)
9f92363d1SSreekanth Reddy  *
10f92363d1SSreekanth Reddy  * This program is free software; you can redistribute it and/or
11f92363d1SSreekanth Reddy  * modify it under the terms of the GNU General Public License
12f92363d1SSreekanth Reddy  * as published by the Free Software Foundation; either version 2
13f92363d1SSreekanth Reddy  * of the License, or (at your option) any later version.
14f92363d1SSreekanth Reddy  *
15f92363d1SSreekanth Reddy  * This program is distributed in the hope that it will be useful,
16f92363d1SSreekanth Reddy  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17f92363d1SSreekanth Reddy  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18f92363d1SSreekanth Reddy  * GNU General Public License for more details.
19f92363d1SSreekanth Reddy  *
20f92363d1SSreekanth Reddy  * NO WARRANTY
21f92363d1SSreekanth Reddy  * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
22f92363d1SSreekanth Reddy  * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
23f92363d1SSreekanth Reddy  * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
24f92363d1SSreekanth Reddy  * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
25f92363d1SSreekanth Reddy  * solely responsible for determining the appropriateness of using and
26f92363d1SSreekanth Reddy  * distributing the Program and assumes all risks associated with its
27f92363d1SSreekanth Reddy  * exercise of rights under this Agreement, including but not limited to
28f92363d1SSreekanth Reddy  * the risks and costs of program errors, damage to or loss of data,
29f92363d1SSreekanth Reddy  * programs or equipment, and unavailability or interruption of operations.
30f92363d1SSreekanth Reddy 
31f92363d1SSreekanth Reddy  * DISCLAIMER OF LIABILITY
32f92363d1SSreekanth Reddy  * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
33f92363d1SSreekanth Reddy  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34f92363d1SSreekanth Reddy  * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
35f92363d1SSreekanth Reddy  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
36f92363d1SSreekanth Reddy  * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
37f92363d1SSreekanth Reddy  * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
38f92363d1SSreekanth Reddy  * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
39f92363d1SSreekanth Reddy 
40f92363d1SSreekanth Reddy  * You should have received a copy of the GNU General Public License
41f92363d1SSreekanth Reddy  * along with this program; if not, write to the Free Software
42f92363d1SSreekanth Reddy  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
43f92363d1SSreekanth Reddy  * USA.
44f92363d1SSreekanth Reddy  */
45f92363d1SSreekanth Reddy 
46f92363d1SSreekanth Reddy #include <linux/kernel.h>
47f92363d1SSreekanth Reddy #include <linux/module.h>
48f92363d1SSreekanth Reddy #include <linux/errno.h>
49f92363d1SSreekanth Reddy #include <linux/init.h>
50f92363d1SSreekanth Reddy #include <linux/slab.h>
51f92363d1SSreekanth Reddy #include <linux/types.h>
52f92363d1SSreekanth Reddy #include <linux/pci.h>
53f92363d1SSreekanth Reddy #include <linux/delay.h>
54f92363d1SSreekanth Reddy #include <linux/compat.h>
55f92363d1SSreekanth Reddy #include <linux/poll.h>
56f92363d1SSreekanth Reddy 
57f92363d1SSreekanth Reddy #include <linux/io.h>
58f92363d1SSreekanth Reddy #include <linux/uaccess.h>
59f92363d1SSreekanth Reddy 
60f92363d1SSreekanth Reddy #include "mpt3sas_base.h"
61f92363d1SSreekanth Reddy #include "mpt3sas_ctl.h"
62f92363d1SSreekanth Reddy 
63f92363d1SSreekanth Reddy 
64f92363d1SSreekanth Reddy static struct fasync_struct *async_queue;
65f92363d1SSreekanth Reddy static DECLARE_WAIT_QUEUE_HEAD(ctl_poll_wait);
66f92363d1SSreekanth Reddy 
67f92363d1SSreekanth Reddy 
68f92363d1SSreekanth Reddy /**
69f92363d1SSreekanth Reddy  * enum block_state - blocking state
70f92363d1SSreekanth Reddy  * @NON_BLOCKING: non blocking
71f92363d1SSreekanth Reddy  * @BLOCKING: blocking
72f92363d1SSreekanth Reddy  *
73f92363d1SSreekanth Reddy  * These states are for ioctls that need to wait for a response
74f92363d1SSreekanth Reddy  * from firmware, so they probably require sleep.
75f92363d1SSreekanth Reddy  */
76f92363d1SSreekanth Reddy enum block_state {
77f92363d1SSreekanth Reddy 	NON_BLOCKING,
78f92363d1SSreekanth Reddy 	BLOCKING,
79f92363d1SSreekanth Reddy };
80f92363d1SSreekanth Reddy 
81f92363d1SSreekanth Reddy /**
82f92363d1SSreekanth Reddy  * _ctl_display_some_debug - debug routine
83f92363d1SSreekanth Reddy  * @ioc: per adapter object
84f92363d1SSreekanth Reddy  * @smid: system request message index
85f92363d1SSreekanth Reddy  * @calling_function_name: string pass from calling function
86f92363d1SSreekanth Reddy  * @mpi_reply: reply message frame
87f92363d1SSreekanth Reddy  * Context: none.
88f92363d1SSreekanth Reddy  *
89f92363d1SSreekanth Reddy  * Function for displaying debug info helpful when debugging issues
90f92363d1SSreekanth Reddy  * in this module.
91f92363d1SSreekanth Reddy  */
92f92363d1SSreekanth Reddy static void
93f92363d1SSreekanth Reddy _ctl_display_some_debug(struct MPT3SAS_ADAPTER *ioc, u16 smid,
94f92363d1SSreekanth Reddy 	char *calling_function_name, MPI2DefaultReply_t *mpi_reply)
95f92363d1SSreekanth Reddy {
96f92363d1SSreekanth Reddy 	Mpi2ConfigRequest_t *mpi_request;
97f92363d1SSreekanth Reddy 	char *desc = NULL;
98f92363d1SSreekanth Reddy 
99f92363d1SSreekanth Reddy 	if (!(ioc->logging_level & MPT_DEBUG_IOCTL))
100f92363d1SSreekanth Reddy 		return;
101f92363d1SSreekanth Reddy 
102f92363d1SSreekanth Reddy 	mpi_request = mpt3sas_base_get_msg_frame(ioc, smid);
103f92363d1SSreekanth Reddy 	switch (mpi_request->Function) {
104f92363d1SSreekanth Reddy 	case MPI2_FUNCTION_SCSI_IO_REQUEST:
105f92363d1SSreekanth Reddy 	{
106f92363d1SSreekanth Reddy 		Mpi2SCSIIORequest_t *scsi_request =
107f92363d1SSreekanth Reddy 		    (Mpi2SCSIIORequest_t *)mpi_request;
108f92363d1SSreekanth Reddy 
109f92363d1SSreekanth Reddy 		snprintf(ioc->tmp_string, MPT_STRING_LENGTH,
110f92363d1SSreekanth Reddy 		    "scsi_io, cmd(0x%02x), cdb_len(%d)",
111f92363d1SSreekanth Reddy 		    scsi_request->CDB.CDB32[0],
112f92363d1SSreekanth Reddy 		    le16_to_cpu(scsi_request->IoFlags) & 0xF);
113f92363d1SSreekanth Reddy 		desc = ioc->tmp_string;
114f92363d1SSreekanth Reddy 		break;
115f92363d1SSreekanth Reddy 	}
116f92363d1SSreekanth Reddy 	case MPI2_FUNCTION_SCSI_TASK_MGMT:
117f92363d1SSreekanth Reddy 		desc = "task_mgmt";
118f92363d1SSreekanth Reddy 		break;
119f92363d1SSreekanth Reddy 	case MPI2_FUNCTION_IOC_INIT:
120f92363d1SSreekanth Reddy 		desc = "ioc_init";
121f92363d1SSreekanth Reddy 		break;
122f92363d1SSreekanth Reddy 	case MPI2_FUNCTION_IOC_FACTS:
123f92363d1SSreekanth Reddy 		desc = "ioc_facts";
124f92363d1SSreekanth Reddy 		break;
125f92363d1SSreekanth Reddy 	case MPI2_FUNCTION_CONFIG:
126f92363d1SSreekanth Reddy 	{
127f92363d1SSreekanth Reddy 		Mpi2ConfigRequest_t *config_request =
128f92363d1SSreekanth Reddy 		    (Mpi2ConfigRequest_t *)mpi_request;
129f92363d1SSreekanth Reddy 
130f92363d1SSreekanth Reddy 		snprintf(ioc->tmp_string, MPT_STRING_LENGTH,
131f92363d1SSreekanth Reddy 		    "config, type(0x%02x), ext_type(0x%02x), number(%d)",
132f92363d1SSreekanth Reddy 		    (config_request->Header.PageType &
133f92363d1SSreekanth Reddy 		     MPI2_CONFIG_PAGETYPE_MASK), config_request->ExtPageType,
134f92363d1SSreekanth Reddy 		    config_request->Header.PageNumber);
135f92363d1SSreekanth Reddy 		desc = ioc->tmp_string;
136f92363d1SSreekanth Reddy 		break;
137f92363d1SSreekanth Reddy 	}
138f92363d1SSreekanth Reddy 	case MPI2_FUNCTION_PORT_FACTS:
139f92363d1SSreekanth Reddy 		desc = "port_facts";
140f92363d1SSreekanth Reddy 		break;
141f92363d1SSreekanth Reddy 	case MPI2_FUNCTION_PORT_ENABLE:
142f92363d1SSreekanth Reddy 		desc = "port_enable";
143f92363d1SSreekanth Reddy 		break;
144f92363d1SSreekanth Reddy 	case MPI2_FUNCTION_EVENT_NOTIFICATION:
145f92363d1SSreekanth Reddy 		desc = "event_notification";
146f92363d1SSreekanth Reddy 		break;
147f92363d1SSreekanth Reddy 	case MPI2_FUNCTION_FW_DOWNLOAD:
148f92363d1SSreekanth Reddy 		desc = "fw_download";
149f92363d1SSreekanth Reddy 		break;
150f92363d1SSreekanth Reddy 	case MPI2_FUNCTION_FW_UPLOAD:
151f92363d1SSreekanth Reddy 		desc = "fw_upload";
152f92363d1SSreekanth Reddy 		break;
153f92363d1SSreekanth Reddy 	case MPI2_FUNCTION_RAID_ACTION:
154f92363d1SSreekanth Reddy 		desc = "raid_action";
155f92363d1SSreekanth Reddy 		break;
156f92363d1SSreekanth Reddy 	case MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH:
157f92363d1SSreekanth Reddy 	{
158f92363d1SSreekanth Reddy 		Mpi2SCSIIORequest_t *scsi_request =
159f92363d1SSreekanth Reddy 		    (Mpi2SCSIIORequest_t *)mpi_request;
160f92363d1SSreekanth Reddy 
161f92363d1SSreekanth Reddy 		snprintf(ioc->tmp_string, MPT_STRING_LENGTH,
162f92363d1SSreekanth Reddy 		    "raid_pass, cmd(0x%02x), cdb_len(%d)",
163f92363d1SSreekanth Reddy 		    scsi_request->CDB.CDB32[0],
164f92363d1SSreekanth Reddy 		    le16_to_cpu(scsi_request->IoFlags) & 0xF);
165f92363d1SSreekanth Reddy 		desc = ioc->tmp_string;
166f92363d1SSreekanth Reddy 		break;
167f92363d1SSreekanth Reddy 	}
168f92363d1SSreekanth Reddy 	case MPI2_FUNCTION_SAS_IO_UNIT_CONTROL:
169f92363d1SSreekanth Reddy 		desc = "sas_iounit_cntl";
170f92363d1SSreekanth Reddy 		break;
171f92363d1SSreekanth Reddy 	case MPI2_FUNCTION_SATA_PASSTHROUGH:
172f92363d1SSreekanth Reddy 		desc = "sata_pass";
173f92363d1SSreekanth Reddy 		break;
174f92363d1SSreekanth Reddy 	case MPI2_FUNCTION_DIAG_BUFFER_POST:
175f92363d1SSreekanth Reddy 		desc = "diag_buffer_post";
176f92363d1SSreekanth Reddy 		break;
177f92363d1SSreekanth Reddy 	case MPI2_FUNCTION_DIAG_RELEASE:
178f92363d1SSreekanth Reddy 		desc = "diag_release";
179f92363d1SSreekanth Reddy 		break;
180f92363d1SSreekanth Reddy 	case MPI2_FUNCTION_SMP_PASSTHROUGH:
181f92363d1SSreekanth Reddy 		desc = "smp_passthrough";
182f92363d1SSreekanth Reddy 		break;
183f92363d1SSreekanth Reddy 	}
184f92363d1SSreekanth Reddy 
185f92363d1SSreekanth Reddy 	if (!desc)
186f92363d1SSreekanth Reddy 		return;
187f92363d1SSreekanth Reddy 
188919d8a3fSJoe Perches 	ioc_info(ioc, "%s: %s, smid(%d)\n", calling_function_name, desc, smid);
189f92363d1SSreekanth Reddy 
190f92363d1SSreekanth Reddy 	if (!mpi_reply)
191f92363d1SSreekanth Reddy 		return;
192f92363d1SSreekanth Reddy 
193f92363d1SSreekanth Reddy 	if (mpi_reply->IOCStatus || mpi_reply->IOCLogInfo)
194919d8a3fSJoe Perches 		ioc_info(ioc, "\tiocstatus(0x%04x), loginfo(0x%08x)\n",
195919d8a3fSJoe Perches 			 le16_to_cpu(mpi_reply->IOCStatus),
196f92363d1SSreekanth Reddy 			 le32_to_cpu(mpi_reply->IOCLogInfo));
197f92363d1SSreekanth Reddy 
198f92363d1SSreekanth Reddy 	if (mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST ||
199f92363d1SSreekanth Reddy 	    mpi_request->Function ==
200f92363d1SSreekanth Reddy 	    MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH) {
201f92363d1SSreekanth Reddy 		Mpi2SCSIIOReply_t *scsi_reply =
202f92363d1SSreekanth Reddy 		    (Mpi2SCSIIOReply_t *)mpi_reply;
203f92363d1SSreekanth Reddy 		struct _sas_device *sas_device = NULL;
20445aa6a1aSSuganath Prabu Subramani 		struct _pcie_device *pcie_device = NULL;
205f92363d1SSreekanth Reddy 
20645aa6a1aSSuganath Prabu Subramani 		sas_device = mpt3sas_get_sdev_by_handle(ioc,
207f92363d1SSreekanth Reddy 		    le16_to_cpu(scsi_reply->DevHandle));
208f92363d1SSreekanth Reddy 		if (sas_device) {
209919d8a3fSJoe Perches 			ioc_warn(ioc, "\tsas_address(0x%016llx), phy(%d)\n",
210919d8a3fSJoe Perches 				 (u64)sas_device->sas_address,
211919d8a3fSJoe Perches 				 sas_device->phy);
212919d8a3fSJoe Perches 			ioc_warn(ioc, "\tenclosure_logical_id(0x%016llx), slot(%d)\n",
213919d8a3fSJoe Perches 				 (u64)sas_device->enclosure_logical_id,
214919d8a3fSJoe Perches 				 sas_device->slot);
21545aa6a1aSSuganath Prabu Subramani 			sas_device_put(sas_device);
216f92363d1SSreekanth Reddy 		}
21745aa6a1aSSuganath Prabu Subramani 		if (!sas_device) {
21845aa6a1aSSuganath Prabu Subramani 			pcie_device = mpt3sas_get_pdev_by_handle(ioc,
21945aa6a1aSSuganath Prabu Subramani 				le16_to_cpu(scsi_reply->DevHandle));
22045aa6a1aSSuganath Prabu Subramani 			if (pcie_device) {
221919d8a3fSJoe Perches 				ioc_warn(ioc, "\tWWID(0x%016llx), port(%d)\n",
22245aa6a1aSSuganath Prabu Subramani 					 (unsigned long long)pcie_device->wwid,
22345aa6a1aSSuganath Prabu Subramani 					 pcie_device->port_num);
22445aa6a1aSSuganath Prabu Subramani 				if (pcie_device->enclosure_handle != 0)
225919d8a3fSJoe Perches 					ioc_warn(ioc, "\tenclosure_logical_id(0x%016llx), slot(%d)\n",
226919d8a3fSJoe Perches 						 (u64)pcie_device->enclosure_logical_id,
22745aa6a1aSSuganath Prabu Subramani 						 pcie_device->slot);
22845aa6a1aSSuganath Prabu Subramani 				pcie_device_put(pcie_device);
22945aa6a1aSSuganath Prabu Subramani 			}
23045aa6a1aSSuganath Prabu Subramani 		}
231f92363d1SSreekanth Reddy 		if (scsi_reply->SCSIState || scsi_reply->SCSIStatus)
232919d8a3fSJoe Perches 			ioc_info(ioc, "\tscsi_state(0x%02x), scsi_status(0x%02x)\n",
233f92363d1SSreekanth Reddy 				 scsi_reply->SCSIState,
234f92363d1SSreekanth Reddy 				 scsi_reply->SCSIStatus);
235f92363d1SSreekanth Reddy 	}
236f92363d1SSreekanth Reddy }
237f92363d1SSreekanth Reddy 
238f92363d1SSreekanth Reddy /**
239f92363d1SSreekanth Reddy  * mpt3sas_ctl_done - ctl module completion routine
240f92363d1SSreekanth Reddy  * @ioc: per adapter object
241f92363d1SSreekanth Reddy  * @smid: system request message index
242f92363d1SSreekanth Reddy  * @msix_index: MSIX table index supplied by the OS
243f92363d1SSreekanth Reddy  * @reply: reply message frame(lower 32bit addr)
244f92363d1SSreekanth Reddy  * Context: none.
245f92363d1SSreekanth Reddy  *
246f92363d1SSreekanth Reddy  * The callback handler when using ioc->ctl_cb_idx.
247f92363d1SSreekanth Reddy  *
2484beb4867SBart Van Assche  * Return: 1 meaning mf should be freed from _base_interrupt
249f92363d1SSreekanth Reddy  *         0 means the mf is freed from this function.
250f92363d1SSreekanth Reddy  */
251f92363d1SSreekanth Reddy u8
252f92363d1SSreekanth Reddy mpt3sas_ctl_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
253f92363d1SSreekanth Reddy 	u32 reply)
254f92363d1SSreekanth Reddy {
255f92363d1SSreekanth Reddy 	MPI2DefaultReply_t *mpi_reply;
256f92363d1SSreekanth Reddy 	Mpi2SCSIIOReply_t *scsiio_reply;
257aff39e61SSuganath Prabu Subramani 	Mpi26NVMeEncapsulatedErrorReply_t *nvme_error_reply;
258f92363d1SSreekanth Reddy 	const void *sense_data;
259f92363d1SSreekanth Reddy 	u32 sz;
260f92363d1SSreekanth Reddy 
261f92363d1SSreekanth Reddy 	if (ioc->ctl_cmds.status == MPT3_CMD_NOT_USED)
262f92363d1SSreekanth Reddy 		return 1;
263f92363d1SSreekanth Reddy 	if (ioc->ctl_cmds.smid != smid)
264f92363d1SSreekanth Reddy 		return 1;
265f92363d1SSreekanth Reddy 	ioc->ctl_cmds.status |= MPT3_CMD_COMPLETE;
266f92363d1SSreekanth Reddy 	mpi_reply = mpt3sas_base_get_reply_virt_addr(ioc, reply);
267f92363d1SSreekanth Reddy 	if (mpi_reply) {
268f92363d1SSreekanth Reddy 		memcpy(ioc->ctl_cmds.reply, mpi_reply, mpi_reply->MsgLength*4);
269f92363d1SSreekanth Reddy 		ioc->ctl_cmds.status |= MPT3_CMD_REPLY_VALID;
270f92363d1SSreekanth Reddy 		/* get sense data */
271f92363d1SSreekanth Reddy 		if (mpi_reply->Function == MPI2_FUNCTION_SCSI_IO_REQUEST ||
272f92363d1SSreekanth Reddy 		    mpi_reply->Function ==
273f92363d1SSreekanth Reddy 		    MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH) {
274f92363d1SSreekanth Reddy 			scsiio_reply = (Mpi2SCSIIOReply_t *)mpi_reply;
275f92363d1SSreekanth Reddy 			if (scsiio_reply->SCSIState &
276f92363d1SSreekanth Reddy 			    MPI2_SCSI_STATE_AUTOSENSE_VALID) {
277f92363d1SSreekanth Reddy 				sz = min_t(u32, SCSI_SENSE_BUFFERSIZE,
278f92363d1SSreekanth Reddy 				    le32_to_cpu(scsiio_reply->SenseCount));
279f92363d1SSreekanth Reddy 				sense_data = mpt3sas_base_get_sense_buffer(ioc,
280f92363d1SSreekanth Reddy 				    smid);
281f92363d1SSreekanth Reddy 				memcpy(ioc->ctl_cmds.sense, sense_data, sz);
282f92363d1SSreekanth Reddy 			}
283f92363d1SSreekanth Reddy 		}
284aff39e61SSuganath Prabu Subramani 		/*
285aff39e61SSuganath Prabu Subramani 		 * Get Error Response data for NVMe device. The ctl_cmds.sense
286aff39e61SSuganath Prabu Subramani 		 * buffer is used to store the Error Response data.
287aff39e61SSuganath Prabu Subramani 		 */
288aff39e61SSuganath Prabu Subramani 		if (mpi_reply->Function == MPI2_FUNCTION_NVME_ENCAPSULATED) {
289aff39e61SSuganath Prabu Subramani 			nvme_error_reply =
290aff39e61SSuganath Prabu Subramani 			    (Mpi26NVMeEncapsulatedErrorReply_t *)mpi_reply;
291aff39e61SSuganath Prabu Subramani 			sz = min_t(u32, NVME_ERROR_RESPONSE_SIZE,
292cf6bf971SChaitra P B 			    le16_to_cpu(nvme_error_reply->ErrorResponseCount));
293aff39e61SSuganath Prabu Subramani 			sense_data = mpt3sas_base_get_sense_buffer(ioc, smid);
294aff39e61SSuganath Prabu Subramani 			memcpy(ioc->ctl_cmds.sense, sense_data, sz);
295aff39e61SSuganath Prabu Subramani 		}
296f92363d1SSreekanth Reddy 	}
297016d5c35SSuganath Prabu Subramani 
298f92363d1SSreekanth Reddy 	_ctl_display_some_debug(ioc, smid, "ctl_done", mpi_reply);
299f92363d1SSreekanth Reddy 	ioc->ctl_cmds.status &= ~MPT3_CMD_PENDING;
300f92363d1SSreekanth Reddy 	complete(&ioc->ctl_cmds.done);
301f92363d1SSreekanth Reddy 	return 1;
302f92363d1SSreekanth Reddy }
303f92363d1SSreekanth Reddy 
304f92363d1SSreekanth Reddy /**
305f92363d1SSreekanth Reddy  * _ctl_check_event_type - determines when an event needs logging
306f92363d1SSreekanth Reddy  * @ioc: per adapter object
307f92363d1SSreekanth Reddy  * @event: firmware event
308f92363d1SSreekanth Reddy  *
309f92363d1SSreekanth Reddy  * The bitmask in ioc->event_type[] indicates which events should be
310f92363d1SSreekanth Reddy  * be saved in the driver event_log.  This bitmask is set by application.
311f92363d1SSreekanth Reddy  *
3124beb4867SBart Van Assche  * Return: 1 when event should be captured, or zero means no match.
313f92363d1SSreekanth Reddy  */
314f92363d1SSreekanth Reddy static int
315f92363d1SSreekanth Reddy _ctl_check_event_type(struct MPT3SAS_ADAPTER *ioc, u16 event)
316f92363d1SSreekanth Reddy {
317f92363d1SSreekanth Reddy 	u16 i;
318f92363d1SSreekanth Reddy 	u32 desired_event;
319f92363d1SSreekanth Reddy 
320f92363d1SSreekanth Reddy 	if (event >= 128 || !event || !ioc->event_log)
321f92363d1SSreekanth Reddy 		return 0;
322f92363d1SSreekanth Reddy 
323f92363d1SSreekanth Reddy 	desired_event = (1 << (event % 32));
324f92363d1SSreekanth Reddy 	if (!desired_event)
325f92363d1SSreekanth Reddy 		desired_event = 1;
326f92363d1SSreekanth Reddy 	i = event / 32;
327f92363d1SSreekanth Reddy 	return desired_event & ioc->event_type[i];
328f92363d1SSreekanth Reddy }
329f92363d1SSreekanth Reddy 
330f92363d1SSreekanth Reddy /**
331f92363d1SSreekanth Reddy  * mpt3sas_ctl_add_to_event_log - add event
332f92363d1SSreekanth Reddy  * @ioc: per adapter object
333f92363d1SSreekanth Reddy  * @mpi_reply: reply message frame
334f92363d1SSreekanth Reddy  */
335f92363d1SSreekanth Reddy void
336f92363d1SSreekanth Reddy mpt3sas_ctl_add_to_event_log(struct MPT3SAS_ADAPTER *ioc,
337f92363d1SSreekanth Reddy 	Mpi2EventNotificationReply_t *mpi_reply)
338f92363d1SSreekanth Reddy {
339f92363d1SSreekanth Reddy 	struct MPT3_IOCTL_EVENTS *event_log;
340f92363d1SSreekanth Reddy 	u16 event;
341f92363d1SSreekanth Reddy 	int i;
342f92363d1SSreekanth Reddy 	u32 sz, event_data_sz;
343f92363d1SSreekanth Reddy 	u8 send_aen = 0;
344f92363d1SSreekanth Reddy 
345f92363d1SSreekanth Reddy 	if (!ioc->event_log)
346f92363d1SSreekanth Reddy 		return;
347f92363d1SSreekanth Reddy 
348f92363d1SSreekanth Reddy 	event = le16_to_cpu(mpi_reply->Event);
349f92363d1SSreekanth Reddy 
350f92363d1SSreekanth Reddy 	if (_ctl_check_event_type(ioc, event)) {
351f92363d1SSreekanth Reddy 
352f92363d1SSreekanth Reddy 		/* insert entry into circular event_log */
353f92363d1SSreekanth Reddy 		i = ioc->event_context % MPT3SAS_CTL_EVENT_LOG_SIZE;
354f92363d1SSreekanth Reddy 		event_log = ioc->event_log;
355f92363d1SSreekanth Reddy 		event_log[i].event = event;
356f92363d1SSreekanth Reddy 		event_log[i].context = ioc->event_context++;
357f92363d1SSreekanth Reddy 
358f92363d1SSreekanth Reddy 		event_data_sz = le16_to_cpu(mpi_reply->EventDataLength)*4;
359f92363d1SSreekanth Reddy 		sz = min_t(u32, event_data_sz, MPT3_EVENT_DATA_SIZE);
360f92363d1SSreekanth Reddy 		memset(event_log[i].data, 0, MPT3_EVENT_DATA_SIZE);
361f92363d1SSreekanth Reddy 		memcpy(event_log[i].data, mpi_reply->EventData, sz);
362f92363d1SSreekanth Reddy 		send_aen = 1;
363f92363d1SSreekanth Reddy 	}
364f92363d1SSreekanth Reddy 
365f92363d1SSreekanth Reddy 	/* This aen_event_read_flag flag is set until the
366f92363d1SSreekanth Reddy 	 * application has read the event log.
367f92363d1SSreekanth Reddy 	 * For MPI2_EVENT_LOG_ENTRY_ADDED, we always notify.
368f92363d1SSreekanth Reddy 	 */
369f92363d1SSreekanth Reddy 	if (event == MPI2_EVENT_LOG_ENTRY_ADDED ||
370f92363d1SSreekanth Reddy 	    (send_aen && !ioc->aen_event_read_flag)) {
371f92363d1SSreekanth Reddy 		ioc->aen_event_read_flag = 1;
372f92363d1SSreekanth Reddy 		wake_up_interruptible(&ctl_poll_wait);
373f92363d1SSreekanth Reddy 		if (async_queue)
374f92363d1SSreekanth Reddy 			kill_fasync(&async_queue, SIGIO, POLL_IN);
375f92363d1SSreekanth Reddy 	}
376f92363d1SSreekanth Reddy }
377f92363d1SSreekanth Reddy 
378f92363d1SSreekanth Reddy /**
379f92363d1SSreekanth Reddy  * mpt3sas_ctl_event_callback - firmware event handler (called at ISR time)
380f92363d1SSreekanth Reddy  * @ioc: per adapter object
381f92363d1SSreekanth Reddy  * @msix_index: MSIX table index supplied by the OS
382f92363d1SSreekanth Reddy  * @reply: reply message frame(lower 32bit addr)
383f92363d1SSreekanth Reddy  * Context: interrupt.
384f92363d1SSreekanth Reddy  *
385f92363d1SSreekanth Reddy  * This function merely adds a new work task into ioc->firmware_event_thread.
386f92363d1SSreekanth Reddy  * The tasks are worked from _firmware_event_work in user context.
387f92363d1SSreekanth Reddy  *
3884beb4867SBart Van Assche  * Return: 1 meaning mf should be freed from _base_interrupt
389f92363d1SSreekanth Reddy  *         0 means the mf is freed from this function.
390f92363d1SSreekanth Reddy  */
391f92363d1SSreekanth Reddy u8
392f92363d1SSreekanth Reddy mpt3sas_ctl_event_callback(struct MPT3SAS_ADAPTER *ioc, u8 msix_index,
393f92363d1SSreekanth Reddy 	u32 reply)
394f92363d1SSreekanth Reddy {
395f92363d1SSreekanth Reddy 	Mpi2EventNotificationReply_t *mpi_reply;
396f92363d1SSreekanth Reddy 
397f92363d1SSreekanth Reddy 	mpi_reply = mpt3sas_base_get_reply_virt_addr(ioc, reply);
398869817f9SSuganath prabu Subramani 	if (mpi_reply)
399f92363d1SSreekanth Reddy 		mpt3sas_ctl_add_to_event_log(ioc, mpi_reply);
400f92363d1SSreekanth Reddy 	return 1;
401f92363d1SSreekanth Reddy }
402f92363d1SSreekanth Reddy 
403f92363d1SSreekanth Reddy /**
404f92363d1SSreekanth Reddy  * _ctl_verify_adapter - validates ioc_number passed from application
4054beb4867SBart Van Assche  * @ioc_number: ?
406f92363d1SSreekanth Reddy  * @iocpp: The ioc pointer is returned in this.
407c84b06a4SSreekanth Reddy  * @mpi_version: will be MPI2_VERSION for mpt2ctl ioctl device &
408b130b0d5SSuganath prabu Subramani  * MPI25_VERSION | MPI26_VERSION for mpt3ctl ioctl device.
409f92363d1SSreekanth Reddy  *
4104beb4867SBart Van Assche  * Return: (-1) means error, else ioc_number.
411f92363d1SSreekanth Reddy  */
412f92363d1SSreekanth Reddy static int
413c84b06a4SSreekanth Reddy _ctl_verify_adapter(int ioc_number, struct MPT3SAS_ADAPTER **iocpp,
414c84b06a4SSreekanth Reddy 							int mpi_version)
415f92363d1SSreekanth Reddy {
416f92363d1SSreekanth Reddy 	struct MPT3SAS_ADAPTER *ioc;
417b130b0d5SSuganath prabu Subramani 	int version = 0;
41808c4d550SSreekanth Reddy 	/* global ioc lock to protect controller on list operations */
41908c4d550SSreekanth Reddy 	spin_lock(&gioc_lock);
420f92363d1SSreekanth Reddy 	list_for_each_entry(ioc, &mpt3sas_ioc_list, list) {
421f92363d1SSreekanth Reddy 		if (ioc->id != ioc_number)
422f92363d1SSreekanth Reddy 			continue;
423c84b06a4SSreekanth Reddy 		/* Check whether this ioctl command is from right
424c84b06a4SSreekanth Reddy 		 * ioctl device or not, if not continue the search.
425c84b06a4SSreekanth Reddy 		 */
426b130b0d5SSuganath prabu Subramani 		version = ioc->hba_mpi_version_belonged;
427b130b0d5SSuganath prabu Subramani 		/* MPI25_VERSION and MPI26_VERSION uses same ioctl
428b130b0d5SSuganath prabu Subramani 		 * device.
429b130b0d5SSuganath prabu Subramani 		 */
430b130b0d5SSuganath prabu Subramani 		if (mpi_version == (MPI25_VERSION | MPI26_VERSION)) {
431b130b0d5SSuganath prabu Subramani 			if ((version == MPI25_VERSION) ||
432b130b0d5SSuganath prabu Subramani 				(version == MPI26_VERSION))
433b130b0d5SSuganath prabu Subramani 				goto out;
434b130b0d5SSuganath prabu Subramani 			else
435c84b06a4SSreekanth Reddy 				continue;
436b130b0d5SSuganath prabu Subramani 		} else {
437b130b0d5SSuganath prabu Subramani 			if (version != mpi_version)
438b130b0d5SSuganath prabu Subramani 				continue;
439b130b0d5SSuganath prabu Subramani 		}
440b130b0d5SSuganath prabu Subramani out:
44108c4d550SSreekanth Reddy 		spin_unlock(&gioc_lock);
442f92363d1SSreekanth Reddy 		*iocpp = ioc;
443f92363d1SSreekanth Reddy 		return ioc_number;
444f92363d1SSreekanth Reddy 	}
44508c4d550SSreekanth Reddy 	spin_unlock(&gioc_lock);
446f92363d1SSreekanth Reddy 	*iocpp = NULL;
447f92363d1SSreekanth Reddy 	return -1;
448f92363d1SSreekanth Reddy }
449f92363d1SSreekanth Reddy 
450f92363d1SSreekanth Reddy /**
451f92363d1SSreekanth Reddy  * mpt3sas_ctl_reset_handler - reset callback handler (for ctl)
452f92363d1SSreekanth Reddy  * @ioc: per adapter object
453f92363d1SSreekanth Reddy  *
454f92363d1SSreekanth Reddy  * The handler for doing any required cleanup or initialization.
455f92363d1SSreekanth Reddy  */
456c7a35705SBart Van Assche void mpt3sas_ctl_pre_reset_handler(struct MPT3SAS_ADAPTER *ioc)
457f92363d1SSreekanth Reddy {
458f92363d1SSreekanth Reddy 	int i;
459f92363d1SSreekanth Reddy 	u8 issue_reset;
460f92363d1SSreekanth Reddy 
461919d8a3fSJoe Perches 	dtmprintk(ioc, ioc_info(ioc, "%s: MPT3_IOC_PRE_RESET\n", __func__));
462f92363d1SSreekanth Reddy 	for (i = 0; i < MPI2_DIAG_BUF_TYPE_COUNT; i++) {
463f92363d1SSreekanth Reddy 		if (!(ioc->diag_buffer_status[i] &
464f92363d1SSreekanth Reddy 		      MPT3_DIAG_BUFFER_IS_REGISTERED))
465f92363d1SSreekanth Reddy 			continue;
466f92363d1SSreekanth Reddy 		if ((ioc->diag_buffer_status[i] &
467f92363d1SSreekanth Reddy 		     MPT3_DIAG_BUFFER_IS_RELEASED))
468f92363d1SSreekanth Reddy 			continue;
4694bc50dc1SSreekanth Reddy 
4704bc50dc1SSreekanth Reddy 		/*
4714bc50dc1SSreekanth Reddy 		 * add a log message to indicate the release
4724bc50dc1SSreekanth Reddy 		 */
4734bc50dc1SSreekanth Reddy 		ioc_info(ioc,
4744bc50dc1SSreekanth Reddy 		    "%s: Releasing the trace buffer due to adapter reset.",
4754bc50dc1SSreekanth Reddy 		    __func__);
476f92363d1SSreekanth Reddy 		mpt3sas_send_diag_release(ioc, i, &issue_reset);
477f92363d1SSreekanth Reddy 	}
478c7a35705SBart Van Assche }
479c7a35705SBart Van Assche 
480c7a35705SBart Van Assche /**
481c7a35705SBart Van Assche  * mpt3sas_ctl_reset_handler - reset callback handler (for ctl)
482c7a35705SBart Van Assche  * @ioc: per adapter object
483c7a35705SBart Van Assche  *
484c7a35705SBart Van Assche  * The handler for doing any required cleanup or initialization.
485c7a35705SBart Van Assche  */
486c7a35705SBart Van Assche void mpt3sas_ctl_after_reset_handler(struct MPT3SAS_ADAPTER *ioc)
487c7a35705SBart Van Assche {
488919d8a3fSJoe Perches 	dtmprintk(ioc, ioc_info(ioc, "%s: MPT3_IOC_AFTER_RESET\n", __func__));
489f92363d1SSreekanth Reddy 	if (ioc->ctl_cmds.status & MPT3_CMD_PENDING) {
490f92363d1SSreekanth Reddy 		ioc->ctl_cmds.status |= MPT3_CMD_RESET;
491f92363d1SSreekanth Reddy 		mpt3sas_base_free_smid(ioc, ioc->ctl_cmds.smid);
492f92363d1SSreekanth Reddy 		complete(&ioc->ctl_cmds.done);
493f92363d1SSreekanth Reddy 	}
494c7a35705SBart Van Assche }
495c7a35705SBart Van Assche 
496c7a35705SBart Van Assche /**
497c7a35705SBart Van Assche  * mpt3sas_ctl_reset_handler - reset callback handler (for ctl)
498c7a35705SBart Van Assche  * @ioc: per adapter object
499c7a35705SBart Van Assche  *
500c7a35705SBart Van Assche  * The handler for doing any required cleanup or initialization.
501c7a35705SBart Van Assche  */
502c7a35705SBart Van Assche void mpt3sas_ctl_reset_done_handler(struct MPT3SAS_ADAPTER *ioc)
503c7a35705SBart Van Assche {
504c7a35705SBart Van Assche 	int i;
505c7a35705SBart Van Assche 
506919d8a3fSJoe Perches 	dtmprintk(ioc, ioc_info(ioc, "%s: MPT3_IOC_DONE_RESET\n", __func__));
507f92363d1SSreekanth Reddy 
508f92363d1SSreekanth Reddy 	for (i = 0; i < MPI2_DIAG_BUF_TYPE_COUNT; i++) {
509f92363d1SSreekanth Reddy 		if (!(ioc->diag_buffer_status[i] &
510f92363d1SSreekanth Reddy 		      MPT3_DIAG_BUFFER_IS_REGISTERED))
511f92363d1SSreekanth Reddy 			continue;
512f92363d1SSreekanth Reddy 		if ((ioc->diag_buffer_status[i] &
513f92363d1SSreekanth Reddy 		     MPT3_DIAG_BUFFER_IS_RELEASED))
514f92363d1SSreekanth Reddy 			continue;
515f92363d1SSreekanth Reddy 		ioc->diag_buffer_status[i] |=
516f92363d1SSreekanth Reddy 			MPT3_DIAG_BUFFER_IS_DIAG_RESET;
517f92363d1SSreekanth Reddy 	}
518f92363d1SSreekanth Reddy }
519f92363d1SSreekanth Reddy 
520f92363d1SSreekanth Reddy /**
521c84b06a4SSreekanth Reddy  * _ctl_fasync -
5224beb4867SBart Van Assche  * @fd: ?
5234beb4867SBart Van Assche  * @filep: ?
5244beb4867SBart Van Assche  * @mode: ?
525f92363d1SSreekanth Reddy  *
526f92363d1SSreekanth Reddy  * Called when application request fasyn callback handler.
527f92363d1SSreekanth Reddy  */
5288bbb1cf6SCalvin Owens static int
529c84b06a4SSreekanth Reddy _ctl_fasync(int fd, struct file *filep, int mode)
530f92363d1SSreekanth Reddy {
531f92363d1SSreekanth Reddy 	return fasync_helper(fd, filep, mode, &async_queue);
532f92363d1SSreekanth Reddy }
533f92363d1SSreekanth Reddy 
534f92363d1SSreekanth Reddy /**
535c84b06a4SSreekanth Reddy  * _ctl_poll -
5364beb4867SBart Van Assche  * @filep: ?
5374beb4867SBart Van Assche  * @wait: ?
538f92363d1SSreekanth Reddy  *
539f92363d1SSreekanth Reddy  */
540afc9a42bSAl Viro static __poll_t
541c84b06a4SSreekanth Reddy _ctl_poll(struct file *filep, poll_table *wait)
542f92363d1SSreekanth Reddy {
543f92363d1SSreekanth Reddy 	struct MPT3SAS_ADAPTER *ioc;
544f92363d1SSreekanth Reddy 
545f92363d1SSreekanth Reddy 	poll_wait(filep, &ctl_poll_wait, wait);
546f92363d1SSreekanth Reddy 
54708c4d550SSreekanth Reddy 	/* global ioc lock to protect controller on list operations */
54808c4d550SSreekanth Reddy 	spin_lock(&gioc_lock);
549f92363d1SSreekanth Reddy 	list_for_each_entry(ioc, &mpt3sas_ioc_list, list) {
55008c4d550SSreekanth Reddy 		if (ioc->aen_event_read_flag) {
55108c4d550SSreekanth Reddy 			spin_unlock(&gioc_lock);
552a9a08845SLinus Torvalds 			return EPOLLIN | EPOLLRDNORM;
553f92363d1SSreekanth Reddy 		}
55408c4d550SSreekanth Reddy 	}
55508c4d550SSreekanth Reddy 	spin_unlock(&gioc_lock);
556f92363d1SSreekanth Reddy 	return 0;
557f92363d1SSreekanth Reddy }
558f92363d1SSreekanth Reddy 
559f92363d1SSreekanth Reddy /**
560f92363d1SSreekanth Reddy  * _ctl_set_task_mid - assign an active smid to tm request
561f92363d1SSreekanth Reddy  * @ioc: per adapter object
5624beb4867SBart Van Assche  * @karg: (struct mpt3_ioctl_command)
5634beb4867SBart Van Assche  * @tm_request: pointer to mf from user space
564f92363d1SSreekanth Reddy  *
5654beb4867SBart Van Assche  * Return: 0 when an smid if found, else fail.
566f92363d1SSreekanth Reddy  * during failure, the reply frame is filled.
567f92363d1SSreekanth Reddy  */
568f92363d1SSreekanth Reddy static int
569f92363d1SSreekanth Reddy _ctl_set_task_mid(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command *karg,
570f92363d1SSreekanth Reddy 	Mpi2SCSITaskManagementRequest_t *tm_request)
571f92363d1SSreekanth Reddy {
572f92363d1SSreekanth Reddy 	u8 found = 0;
573dbec4c90SSuganath Prabu Subramani 	u16 smid;
574f92363d1SSreekanth Reddy 	u16 handle;
575f92363d1SSreekanth Reddy 	struct scsi_cmnd *scmd;
576f92363d1SSreekanth Reddy 	struct MPT3SAS_DEVICE *priv_data;
577f92363d1SSreekanth Reddy 	Mpi2SCSITaskManagementReply_t *tm_reply;
578f92363d1SSreekanth Reddy 	u32 sz;
579f92363d1SSreekanth Reddy 	u32 lun;
580f92363d1SSreekanth Reddy 	char *desc = NULL;
581f92363d1SSreekanth Reddy 
582f92363d1SSreekanth Reddy 	if (tm_request->TaskType == MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK)
583f92363d1SSreekanth Reddy 		desc = "abort_task";
584f92363d1SSreekanth Reddy 	else if (tm_request->TaskType == MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK)
585f92363d1SSreekanth Reddy 		desc = "query_task";
586f92363d1SSreekanth Reddy 	else
587f92363d1SSreekanth Reddy 		return 0;
588f92363d1SSreekanth Reddy 
589f92363d1SSreekanth Reddy 	lun = scsilun_to_int((struct scsi_lun *)tm_request->LUN);
590f92363d1SSreekanth Reddy 
591f92363d1SSreekanth Reddy 	handle = le16_to_cpu(tm_request->DevHandle);
592dbec4c90SSuganath Prabu Subramani 	for (smid = ioc->scsiio_depth; smid && !found; smid--) {
593dbec4c90SSuganath Prabu Subramani 		struct scsiio_tracker *st;
594dbec4c90SSuganath Prabu Subramani 
595dbec4c90SSuganath Prabu Subramani 		scmd = mpt3sas_scsih_scsi_lookup_get(ioc, smid);
596dbec4c90SSuganath Prabu Subramani 		if (!scmd)
597f92363d1SSreekanth Reddy 			continue;
598f92363d1SSreekanth Reddy 		if (lun != scmd->device->lun)
599f92363d1SSreekanth Reddy 			continue;
600f92363d1SSreekanth Reddy 		priv_data = scmd->device->hostdata;
601f92363d1SSreekanth Reddy 		if (priv_data->sas_target == NULL)
602f92363d1SSreekanth Reddy 			continue;
603f92363d1SSreekanth Reddy 		if (priv_data->sas_target->handle != handle)
604f92363d1SSreekanth Reddy 			continue;
605dbec4c90SSuganath Prabu Subramani 		st = scsi_cmd_priv(scmd);
6068f55c307SMinwoo Im 
6078f55c307SMinwoo Im 		/*
6088f55c307SMinwoo Im 		 * If the given TaskMID from the user space is zero, then the
6098f55c307SMinwoo Im 		 * first outstanding smid will be picked up.  Otherwise,
6108f55c307SMinwoo Im 		 * targeted smid will be the one.
6118f55c307SMinwoo Im 		 */
6128f55c307SMinwoo Im 		if (!tm_request->TaskMID || tm_request->TaskMID == st->smid) {
613dbec4c90SSuganath Prabu Subramani 			tm_request->TaskMID = cpu_to_le16(st->smid);
614f92363d1SSreekanth Reddy 			found = 1;
615f92363d1SSreekanth Reddy 		}
6168f55c307SMinwoo Im 	}
617f92363d1SSreekanth Reddy 
618f92363d1SSreekanth Reddy 	if (!found) {
619919d8a3fSJoe Perches 		dctlprintk(ioc,
620919d8a3fSJoe Perches 			   ioc_info(ioc, "%s: handle(0x%04x), lun(%d), no active mid!!\n",
621919d8a3fSJoe Perches 				    desc, le16_to_cpu(tm_request->DevHandle),
622919d8a3fSJoe Perches 				    lun));
623f92363d1SSreekanth Reddy 		tm_reply = ioc->ctl_cmds.reply;
624f92363d1SSreekanth Reddy 		tm_reply->DevHandle = tm_request->DevHandle;
625f92363d1SSreekanth Reddy 		tm_reply->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
626f92363d1SSreekanth Reddy 		tm_reply->TaskType = tm_request->TaskType;
627f92363d1SSreekanth Reddy 		tm_reply->MsgLength = sizeof(Mpi2SCSITaskManagementReply_t)/4;
628f92363d1SSreekanth Reddy 		tm_reply->VP_ID = tm_request->VP_ID;
629f92363d1SSreekanth Reddy 		tm_reply->VF_ID = tm_request->VF_ID;
630f92363d1SSreekanth Reddy 		sz = min_t(u32, karg->max_reply_bytes, ioc->reply_sz);
631f92363d1SSreekanth Reddy 		if (copy_to_user(karg->reply_frame_buf_ptr, ioc->ctl_cmds.reply,
632f92363d1SSreekanth Reddy 		    sz))
633f92363d1SSreekanth Reddy 			pr_err("failure at %s:%d/%s()!\n", __FILE__,
634f92363d1SSreekanth Reddy 			    __LINE__, __func__);
635f92363d1SSreekanth Reddy 		return 1;
636f92363d1SSreekanth Reddy 	}
637f92363d1SSreekanth Reddy 
638919d8a3fSJoe Perches 	dctlprintk(ioc,
639919d8a3fSJoe Perches 		   ioc_info(ioc, "%s: handle(0x%04x), lun(%d), task_mid(%d)\n",
640f92363d1SSreekanth Reddy 			    desc, le16_to_cpu(tm_request->DevHandle), lun,
641f92363d1SSreekanth Reddy 			    le16_to_cpu(tm_request->TaskMID)));
642f92363d1SSreekanth Reddy 	return 0;
643f92363d1SSreekanth Reddy }
644f92363d1SSreekanth Reddy 
645f92363d1SSreekanth Reddy /**
646f92363d1SSreekanth Reddy  * _ctl_do_mpt_command - main handler for MPT3COMMAND opcode
647f92363d1SSreekanth Reddy  * @ioc: per adapter object
6484beb4867SBart Van Assche  * @karg: (struct mpt3_ioctl_command)
6494beb4867SBart Van Assche  * @mf: pointer to mf in user space
650f92363d1SSreekanth Reddy  */
651f92363d1SSreekanth Reddy static long
652f92363d1SSreekanth Reddy _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg,
653f92363d1SSreekanth Reddy 	void __user *mf)
654f92363d1SSreekanth Reddy {
655f92363d1SSreekanth Reddy 	MPI2RequestHeader_t *mpi_request = NULL, *request;
656f92363d1SSreekanth Reddy 	MPI2DefaultReply_t *mpi_reply;
657aff39e61SSuganath Prabu Subramani 	Mpi26NVMeEncapsulatedRequest_t *nvme_encap_request = NULL;
658c1a6c5acSChaitra P B 	struct _pcie_device *pcie_device = NULL;
659f92363d1SSreekanth Reddy 	u16 smid;
660c1a6c5acSChaitra P B 	u8 timeout;
661f92363d1SSreekanth Reddy 	u8 issue_reset;
662aff39e61SSuganath Prabu Subramani 	u32 sz, sz_arg;
663f92363d1SSreekanth Reddy 	void *psge;
664f92363d1SSreekanth Reddy 	void *data_out = NULL;
665f92363d1SSreekanth Reddy 	dma_addr_t data_out_dma = 0;
666f92363d1SSreekanth Reddy 	size_t data_out_sz = 0;
667f92363d1SSreekanth Reddy 	void *data_in = NULL;
668f92363d1SSreekanth Reddy 	dma_addr_t data_in_dma = 0;
669f92363d1SSreekanth Reddy 	size_t data_in_sz = 0;
670f92363d1SSreekanth Reddy 	long ret;
671c696f7b8SSuganath Prabu Subramani 	u16 device_handle = MPT3SAS_INVALID_DEVICE_HANDLE;
672f92363d1SSreekanth Reddy 
673f92363d1SSreekanth Reddy 	issue_reset = 0;
674f92363d1SSreekanth Reddy 
675f92363d1SSreekanth Reddy 	if (ioc->ctl_cmds.status != MPT3_CMD_NOT_USED) {
676919d8a3fSJoe Perches 		ioc_err(ioc, "%s: ctl_cmd in use\n", __func__);
677f92363d1SSreekanth Reddy 		ret = -EAGAIN;
678f92363d1SSreekanth Reddy 		goto out;
679f92363d1SSreekanth Reddy 	}
680f92363d1SSreekanth Reddy 
681f4305749SSuganath Prabu 	ret = mpt3sas_wait_for_ioc(ioc,	IOC_OPERATIONAL_WAIT_COUNT);
682f4305749SSuganath Prabu 	if (ret)
683f92363d1SSreekanth Reddy 		goto out;
684f92363d1SSreekanth Reddy 
685f92363d1SSreekanth Reddy 	mpi_request = kzalloc(ioc->request_sz, GFP_KERNEL);
686f92363d1SSreekanth Reddy 	if (!mpi_request) {
687919d8a3fSJoe Perches 		ioc_err(ioc, "%s: failed obtaining a memory for mpi_request\n",
688919d8a3fSJoe Perches 			__func__);
689f92363d1SSreekanth Reddy 		ret = -ENOMEM;
690f92363d1SSreekanth Reddy 		goto out;
691f92363d1SSreekanth Reddy 	}
692f92363d1SSreekanth Reddy 
693f92363d1SSreekanth Reddy 	/* Check for overflow and wraparound */
694f92363d1SSreekanth Reddy 	if (karg.data_sge_offset * 4 > ioc->request_sz ||
695f92363d1SSreekanth Reddy 	    karg.data_sge_offset > (UINT_MAX / 4)) {
696f92363d1SSreekanth Reddy 		ret = -EINVAL;
697f92363d1SSreekanth Reddy 		goto out;
698f92363d1SSreekanth Reddy 	}
699f92363d1SSreekanth Reddy 
700f92363d1SSreekanth Reddy 	/* copy in request message frame from user */
701f92363d1SSreekanth Reddy 	if (copy_from_user(mpi_request, mf, karg.data_sge_offset*4)) {
702f92363d1SSreekanth Reddy 		pr_err("failure at %s:%d/%s()!\n", __FILE__, __LINE__,
703f92363d1SSreekanth Reddy 		    __func__);
704f92363d1SSreekanth Reddy 		ret = -EFAULT;
705f92363d1SSreekanth Reddy 		goto out;
706f92363d1SSreekanth Reddy 	}
707f92363d1SSreekanth Reddy 
708f92363d1SSreekanth Reddy 	if (mpi_request->Function == MPI2_FUNCTION_SCSI_TASK_MGMT) {
709f92363d1SSreekanth Reddy 		smid = mpt3sas_base_get_smid_hpr(ioc, ioc->ctl_cb_idx);
710f92363d1SSreekanth Reddy 		if (!smid) {
711919d8a3fSJoe Perches 			ioc_err(ioc, "%s: failed obtaining a smid\n", __func__);
712f92363d1SSreekanth Reddy 			ret = -EAGAIN;
713f92363d1SSreekanth Reddy 			goto out;
714f92363d1SSreekanth Reddy 		}
715f92363d1SSreekanth Reddy 	} else {
716b0cd285eSHannes Reinecke 		/* Use first reserved smid for passthrough ioctls */
717b0cd285eSHannes Reinecke 		smid = ioc->scsiio_depth - INTERNAL_SCSIIO_CMDS_COUNT + 1;
718f92363d1SSreekanth Reddy 	}
719f92363d1SSreekanth Reddy 
720f92363d1SSreekanth Reddy 	ret = 0;
721f92363d1SSreekanth Reddy 	ioc->ctl_cmds.status = MPT3_CMD_PENDING;
722f92363d1SSreekanth Reddy 	memset(ioc->ctl_cmds.reply, 0, ioc->reply_sz);
723f92363d1SSreekanth Reddy 	request = mpt3sas_base_get_msg_frame(ioc, smid);
724e224e03bSSuganath Prabu 	memset(request, 0, ioc->request_sz);
725f92363d1SSreekanth Reddy 	memcpy(request, mpi_request, karg.data_sge_offset*4);
726f92363d1SSreekanth Reddy 	ioc->ctl_cmds.smid = smid;
727f92363d1SSreekanth Reddy 	data_out_sz = karg.data_out_size;
728f92363d1SSreekanth Reddy 	data_in_sz = karg.data_in_size;
729f92363d1SSreekanth Reddy 
730f92363d1SSreekanth Reddy 	if (mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST ||
731c696f7b8SSuganath Prabu Subramani 	    mpi_request->Function == MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH ||
732c696f7b8SSuganath Prabu Subramani 	    mpi_request->Function == MPI2_FUNCTION_SCSI_TASK_MGMT ||
733aff39e61SSuganath Prabu Subramani 	    mpi_request->Function == MPI2_FUNCTION_SATA_PASSTHROUGH ||
734aff39e61SSuganath Prabu Subramani 	    mpi_request->Function == MPI2_FUNCTION_NVME_ENCAPSULATED) {
735c696f7b8SSuganath Prabu Subramani 
736c696f7b8SSuganath Prabu Subramani 		device_handle = le16_to_cpu(mpi_request->FunctionDependent1);
737c696f7b8SSuganath Prabu Subramani 		if (!device_handle || (device_handle >
738c696f7b8SSuganath Prabu Subramani 		    ioc->facts.MaxDevHandle)) {
739f92363d1SSreekanth Reddy 			ret = -EINVAL;
740f92363d1SSreekanth Reddy 			mpt3sas_base_free_smid(ioc, smid);
741f92363d1SSreekanth Reddy 			goto out;
742f92363d1SSreekanth Reddy 		}
743f92363d1SSreekanth Reddy 	}
744f92363d1SSreekanth Reddy 
745f92363d1SSreekanth Reddy 	/* obtain dma-able memory for data transfer */
746f92363d1SSreekanth Reddy 	if (data_out_sz) /* WRITE */ {
7471c2048bdSChristoph Hellwig 		data_out = dma_alloc_coherent(&ioc->pdev->dev, data_out_sz,
7481c2048bdSChristoph Hellwig 				&data_out_dma, GFP_KERNEL);
749f92363d1SSreekanth Reddy 		if (!data_out) {
750f92363d1SSreekanth Reddy 			pr_err("failure at %s:%d/%s()!\n", __FILE__,
751f92363d1SSreekanth Reddy 			    __LINE__, __func__);
752f92363d1SSreekanth Reddy 			ret = -ENOMEM;
753f92363d1SSreekanth Reddy 			mpt3sas_base_free_smid(ioc, smid);
754f92363d1SSreekanth Reddy 			goto out;
755f92363d1SSreekanth Reddy 		}
756f92363d1SSreekanth Reddy 		if (copy_from_user(data_out, karg.data_out_buf_ptr,
757f92363d1SSreekanth Reddy 			data_out_sz)) {
758f92363d1SSreekanth Reddy 			pr_err("failure at %s:%d/%s()!\n", __FILE__,
759f92363d1SSreekanth Reddy 			    __LINE__, __func__);
760f92363d1SSreekanth Reddy 			ret =  -EFAULT;
761f92363d1SSreekanth Reddy 			mpt3sas_base_free_smid(ioc, smid);
762f92363d1SSreekanth Reddy 			goto out;
763f92363d1SSreekanth Reddy 		}
764f92363d1SSreekanth Reddy 	}
765f92363d1SSreekanth Reddy 
766f92363d1SSreekanth Reddy 	if (data_in_sz) /* READ */ {
7671c2048bdSChristoph Hellwig 		data_in = dma_alloc_coherent(&ioc->pdev->dev, data_in_sz,
7681c2048bdSChristoph Hellwig 				&data_in_dma, GFP_KERNEL);
769f92363d1SSreekanth Reddy 		if (!data_in) {
770f92363d1SSreekanth Reddy 			pr_err("failure at %s:%d/%s()!\n", __FILE__,
771f92363d1SSreekanth Reddy 			    __LINE__, __func__);
772f92363d1SSreekanth Reddy 			ret = -ENOMEM;
773f92363d1SSreekanth Reddy 			mpt3sas_base_free_smid(ioc, smid);
774f92363d1SSreekanth Reddy 			goto out;
775f92363d1SSreekanth Reddy 		}
776f92363d1SSreekanth Reddy 	}
777f92363d1SSreekanth Reddy 
778f92363d1SSreekanth Reddy 	psge = (void *)request + (karg.data_sge_offset*4);
779f92363d1SSreekanth Reddy 
780f92363d1SSreekanth Reddy 	/* send command to firmware */
781f92363d1SSreekanth Reddy 	_ctl_display_some_debug(ioc, smid, "ctl_request", NULL);
782f92363d1SSreekanth Reddy 
783f92363d1SSreekanth Reddy 	init_completion(&ioc->ctl_cmds.done);
784f92363d1SSreekanth Reddy 	switch (mpi_request->Function) {
785aff39e61SSuganath Prabu Subramani 	case MPI2_FUNCTION_NVME_ENCAPSULATED:
786aff39e61SSuganath Prabu Subramani 	{
787aff39e61SSuganath Prabu Subramani 		nvme_encap_request = (Mpi26NVMeEncapsulatedRequest_t *)request;
788*77fd4f2cSSreekanth Reddy 		if (!ioc->pcie_sg_lookup) {
789*77fd4f2cSSreekanth Reddy 			dtmprintk(ioc, ioc_info(ioc,
790*77fd4f2cSSreekanth Reddy 			    "HBA doesn't support NVMe. Rejecting NVMe Encapsulated request.\n"
791*77fd4f2cSSreekanth Reddy 			    ));
792*77fd4f2cSSreekanth Reddy 
793*77fd4f2cSSreekanth Reddy 			if (ioc->logging_level & MPT_DEBUG_TM)
794*77fd4f2cSSreekanth Reddy 				_debug_dump_mf(nvme_encap_request,
795*77fd4f2cSSreekanth Reddy 				    ioc->request_sz/4);
796*77fd4f2cSSreekanth Reddy 			mpt3sas_base_free_smid(ioc, smid);
797*77fd4f2cSSreekanth Reddy 			ret = -EINVAL;
798*77fd4f2cSSreekanth Reddy 			goto out;
799*77fd4f2cSSreekanth Reddy 		}
800aff39e61SSuganath Prabu Subramani 		/*
801aff39e61SSuganath Prabu Subramani 		 * Get the Physical Address of the sense buffer.
802aff39e61SSuganath Prabu Subramani 		 * Use Error Response buffer address field to hold the sense
803aff39e61SSuganath Prabu Subramani 		 * buffer address.
804aff39e61SSuganath Prabu Subramani 		 * Clear the internal sense buffer, which will potentially hold
805aff39e61SSuganath Prabu Subramani 		 * the Completion Queue Entry on return, or 0 if no Entry.
806aff39e61SSuganath Prabu Subramani 		 * Build the PRPs and set direction bits.
807aff39e61SSuganath Prabu Subramani 		 * Send the request.
808aff39e61SSuganath Prabu Subramani 		 */
809cf6bf971SChaitra P B 		nvme_encap_request->ErrorResponseBaseAddress =
810cf6bf971SChaitra P B 		    cpu_to_le64(ioc->sense_dma & 0xFFFFFFFF00000000UL);
811aff39e61SSuganath Prabu Subramani 		nvme_encap_request->ErrorResponseBaseAddress |=
812cf6bf971SChaitra P B 		   cpu_to_le64(le32_to_cpu(
813cf6bf971SChaitra P B 		   mpt3sas_base_get_sense_buffer_dma(ioc, smid)));
814aff39e61SSuganath Prabu Subramani 		nvme_encap_request->ErrorResponseAllocationLength =
815cf6bf971SChaitra P B 					cpu_to_le16(NVME_ERROR_RESPONSE_SIZE);
816aff39e61SSuganath Prabu Subramani 		memset(ioc->ctl_cmds.sense, 0, NVME_ERROR_RESPONSE_SIZE);
817aff39e61SSuganath Prabu Subramani 		ioc->build_nvme_prp(ioc, smid, nvme_encap_request,
818aff39e61SSuganath Prabu Subramani 		    data_out_dma, data_out_sz, data_in_dma, data_in_sz);
819aff39e61SSuganath Prabu Subramani 		if (test_bit(device_handle, ioc->device_remove_in_progress)) {
820919d8a3fSJoe Perches 			dtmprintk(ioc,
821919d8a3fSJoe Perches 				  ioc_info(ioc, "handle(0x%04x): ioctl failed due to device removal in progress\n",
822919d8a3fSJoe Perches 					   device_handle));
823aff39e61SSuganath Prabu Subramani 			mpt3sas_base_free_smid(ioc, smid);
824aff39e61SSuganath Prabu Subramani 			ret = -EINVAL;
825aff39e61SSuganath Prabu Subramani 			goto out;
826aff39e61SSuganath Prabu Subramani 		}
82740114bdeSSuganath Prabu S 		mpt3sas_base_put_smid_nvme_encap(ioc, smid);
828aff39e61SSuganath Prabu Subramani 		break;
829aff39e61SSuganath Prabu Subramani 	}
830f92363d1SSreekanth Reddy 	case MPI2_FUNCTION_SCSI_IO_REQUEST:
831f92363d1SSreekanth Reddy 	case MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH:
832f92363d1SSreekanth Reddy 	{
833f92363d1SSreekanth Reddy 		Mpi2SCSIIORequest_t *scsiio_request =
834f92363d1SSreekanth Reddy 		    (Mpi2SCSIIORequest_t *)request;
835f92363d1SSreekanth Reddy 		scsiio_request->SenseBufferLength = SCSI_SENSE_BUFFERSIZE;
836f92363d1SSreekanth Reddy 		scsiio_request->SenseBufferLowAddress =
837f92363d1SSreekanth Reddy 		    mpt3sas_base_get_sense_buffer_dma(ioc, smid);
838f92363d1SSreekanth Reddy 		memset(ioc->ctl_cmds.sense, 0, SCSI_SENSE_BUFFERSIZE);
839c696f7b8SSuganath Prabu Subramani 		if (test_bit(device_handle, ioc->device_remove_in_progress)) {
840919d8a3fSJoe Perches 			dtmprintk(ioc,
841919d8a3fSJoe Perches 				  ioc_info(ioc, "handle(0x%04x) :ioctl failed due to device removal in progress\n",
842919d8a3fSJoe Perches 					   device_handle));
843c696f7b8SSuganath Prabu Subramani 			mpt3sas_base_free_smid(ioc, smid);
844c696f7b8SSuganath Prabu Subramani 			ret = -EINVAL;
845c696f7b8SSuganath Prabu Subramani 			goto out;
846c696f7b8SSuganath Prabu Subramani 		}
847f92363d1SSreekanth Reddy 		ioc->build_sg(ioc, psge, data_out_dma, data_out_sz,
848f92363d1SSreekanth Reddy 		    data_in_dma, data_in_sz);
849f92363d1SSreekanth Reddy 		if (mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST)
85081c16f83SSuganath Prabu Subramani 			ioc->put_smid_scsi_io(ioc, smid, device_handle);
851f92363d1SSreekanth Reddy 		else
852078a4cc1SSuganath Prabu S 			ioc->put_smid_default(ioc, smid);
853f92363d1SSreekanth Reddy 		break;
854f92363d1SSreekanth Reddy 	}
855f92363d1SSreekanth Reddy 	case MPI2_FUNCTION_SCSI_TASK_MGMT:
856f92363d1SSreekanth Reddy 	{
857f92363d1SSreekanth Reddy 		Mpi2SCSITaskManagementRequest_t *tm_request =
858f92363d1SSreekanth Reddy 		    (Mpi2SCSITaskManagementRequest_t *)request;
859f92363d1SSreekanth Reddy 
860919d8a3fSJoe Perches 		dtmprintk(ioc,
861919d8a3fSJoe Perches 			  ioc_info(ioc, "TASK_MGMT: handle(0x%04x), task_type(0x%02x)\n",
862919d8a3fSJoe Perches 				   le16_to_cpu(tm_request->DevHandle),
863919d8a3fSJoe Perches 				   tm_request->TaskType));
864459325c4SChaitra P B 		ioc->got_task_abort_from_ioctl = 1;
865f92363d1SSreekanth Reddy 		if (tm_request->TaskType ==
866f92363d1SSreekanth Reddy 		    MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK ||
867f92363d1SSreekanth Reddy 		    tm_request->TaskType ==
868f92363d1SSreekanth Reddy 		    MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK) {
869f92363d1SSreekanth Reddy 			if (_ctl_set_task_mid(ioc, &karg, tm_request)) {
870f92363d1SSreekanth Reddy 				mpt3sas_base_free_smid(ioc, smid);
871459325c4SChaitra P B 				ioc->got_task_abort_from_ioctl = 0;
872f92363d1SSreekanth Reddy 				goto out;
873f92363d1SSreekanth Reddy 			}
874f92363d1SSreekanth Reddy 		}
875459325c4SChaitra P B 		ioc->got_task_abort_from_ioctl = 0;
876f92363d1SSreekanth Reddy 
877c696f7b8SSuganath Prabu Subramani 		if (test_bit(device_handle, ioc->device_remove_in_progress)) {
878919d8a3fSJoe Perches 			dtmprintk(ioc,
879919d8a3fSJoe Perches 				  ioc_info(ioc, "handle(0x%04x) :ioctl failed due to device removal in progress\n",
880919d8a3fSJoe Perches 					   device_handle));
881c696f7b8SSuganath Prabu Subramani 			mpt3sas_base_free_smid(ioc, smid);
882c696f7b8SSuganath Prabu Subramani 			ret = -EINVAL;
883c696f7b8SSuganath Prabu Subramani 			goto out;
884c696f7b8SSuganath Prabu Subramani 		}
885f92363d1SSreekanth Reddy 		mpt3sas_scsih_set_tm_flag(ioc, le16_to_cpu(
886f92363d1SSreekanth Reddy 		    tm_request->DevHandle));
887f92363d1SSreekanth Reddy 		ioc->build_sg_mpi(ioc, psge, data_out_dma, data_out_sz,
888f92363d1SSreekanth Reddy 		    data_in_dma, data_in_sz);
889078a4cc1SSuganath Prabu S 		ioc->put_smid_hi_priority(ioc, smid, 0);
890f92363d1SSreekanth Reddy 		break;
891f92363d1SSreekanth Reddy 	}
892f92363d1SSreekanth Reddy 	case MPI2_FUNCTION_SMP_PASSTHROUGH:
893f92363d1SSreekanth Reddy 	{
894f92363d1SSreekanth Reddy 		Mpi2SmpPassthroughRequest_t *smp_request =
895f92363d1SSreekanth Reddy 		    (Mpi2SmpPassthroughRequest_t *)mpi_request;
896f92363d1SSreekanth Reddy 		u8 *data;
897f92363d1SSreekanth Reddy 
898f92363d1SSreekanth Reddy 		/* ioc determines which port to use */
899f92363d1SSreekanth Reddy 		smp_request->PhysicalPort = 0xFF;
900f92363d1SSreekanth Reddy 		if (smp_request->PassthroughFlags &
901f92363d1SSreekanth Reddy 		    MPI2_SMP_PT_REQ_PT_FLAGS_IMMEDIATE)
902f92363d1SSreekanth Reddy 			data = (u8 *)&smp_request->SGL;
903f92363d1SSreekanth Reddy 		else {
904f92363d1SSreekanth Reddy 			if (unlikely(data_out == NULL)) {
905f92363d1SSreekanth Reddy 				pr_err("failure at %s:%d/%s()!\n",
906f92363d1SSreekanth Reddy 				    __FILE__, __LINE__, __func__);
907f92363d1SSreekanth Reddy 				mpt3sas_base_free_smid(ioc, smid);
908f92363d1SSreekanth Reddy 				ret = -EINVAL;
909f92363d1SSreekanth Reddy 				goto out;
910f92363d1SSreekanth Reddy 			}
911f92363d1SSreekanth Reddy 			data = data_out;
912f92363d1SSreekanth Reddy 		}
913f92363d1SSreekanth Reddy 
914f92363d1SSreekanth Reddy 		if (data[1] == 0x91 && (data[10] == 1 || data[10] == 2)) {
915f92363d1SSreekanth Reddy 			ioc->ioc_link_reset_in_progress = 1;
916f92363d1SSreekanth Reddy 			ioc->ignore_loginfos = 1;
917f92363d1SSreekanth Reddy 		}
918f92363d1SSreekanth Reddy 		ioc->build_sg(ioc, psge, data_out_dma, data_out_sz, data_in_dma,
919f92363d1SSreekanth Reddy 		    data_in_sz);
920078a4cc1SSuganath Prabu S 		ioc->put_smid_default(ioc, smid);
921f92363d1SSreekanth Reddy 		break;
922f92363d1SSreekanth Reddy 	}
923f92363d1SSreekanth Reddy 	case MPI2_FUNCTION_SATA_PASSTHROUGH:
924c696f7b8SSuganath Prabu Subramani 	{
925c696f7b8SSuganath Prabu Subramani 		if (test_bit(device_handle, ioc->device_remove_in_progress)) {
926919d8a3fSJoe Perches 			dtmprintk(ioc,
927919d8a3fSJoe Perches 				  ioc_info(ioc, "handle(0x%04x) :ioctl failed due to device removal in progress\n",
928919d8a3fSJoe Perches 					   device_handle));
929c696f7b8SSuganath Prabu Subramani 			mpt3sas_base_free_smid(ioc, smid);
930c696f7b8SSuganath Prabu Subramani 			ret = -EINVAL;
931c696f7b8SSuganath Prabu Subramani 			goto out;
932c696f7b8SSuganath Prabu Subramani 		}
933c696f7b8SSuganath Prabu Subramani 		ioc->build_sg(ioc, psge, data_out_dma, data_out_sz, data_in_dma,
934c696f7b8SSuganath Prabu Subramani 		    data_in_sz);
935078a4cc1SSuganath Prabu S 		ioc->put_smid_default(ioc, smid);
936c696f7b8SSuganath Prabu Subramani 		break;
937c696f7b8SSuganath Prabu Subramani 	}
938f92363d1SSreekanth Reddy 	case MPI2_FUNCTION_FW_DOWNLOAD:
939f92363d1SSreekanth Reddy 	case MPI2_FUNCTION_FW_UPLOAD:
940f92363d1SSreekanth Reddy 	{
941f92363d1SSreekanth Reddy 		ioc->build_sg(ioc, psge, data_out_dma, data_out_sz, data_in_dma,
942f92363d1SSreekanth Reddy 		    data_in_sz);
943078a4cc1SSuganath Prabu S 		ioc->put_smid_default(ioc, smid);
944f92363d1SSreekanth Reddy 		break;
945f92363d1SSreekanth Reddy 	}
946f92363d1SSreekanth Reddy 	case MPI2_FUNCTION_TOOLBOX:
947f92363d1SSreekanth Reddy 	{
948f92363d1SSreekanth Reddy 		Mpi2ToolboxCleanRequest_t *toolbox_request =
949f92363d1SSreekanth Reddy 			(Mpi2ToolboxCleanRequest_t *)mpi_request;
950f92363d1SSreekanth Reddy 
951f23ca2cbSSuganath Prabu 		if ((toolbox_request->Tool == MPI2_TOOLBOX_DIAGNOSTIC_CLI_TOOL)
952f23ca2cbSSuganath Prabu 		    || (toolbox_request->Tool ==
953f23ca2cbSSuganath Prabu 		    MPI26_TOOLBOX_BACKEND_PCIE_LANE_MARGIN))
954f92363d1SSreekanth Reddy 			ioc->build_sg(ioc, psge, data_out_dma, data_out_sz,
955f92363d1SSreekanth Reddy 				data_in_dma, data_in_sz);
956ba630ea0SSuganath Prabu 		else if (toolbox_request->Tool ==
957ba630ea0SSuganath Prabu 				MPI2_TOOLBOX_MEMORY_MOVE_TOOL) {
958ba630ea0SSuganath Prabu 			Mpi2ToolboxMemMoveRequest_t *mem_move_request =
959ba630ea0SSuganath Prabu 					(Mpi2ToolboxMemMoveRequest_t *)request;
960ba630ea0SSuganath Prabu 			Mpi2SGESimple64_t tmp, *src = NULL, *dst = NULL;
961ba630ea0SSuganath Prabu 
962ba630ea0SSuganath Prabu 			ioc->build_sg_mpi(ioc, psge, data_out_dma,
963ba630ea0SSuganath Prabu 					data_out_sz, data_in_dma, data_in_sz);
964ba630ea0SSuganath Prabu 			if (data_out_sz && !data_in_sz) {
965ba630ea0SSuganath Prabu 				dst =
966ba630ea0SSuganath Prabu 				    (Mpi2SGESimple64_t *)&mem_move_request->SGL;
967ba630ea0SSuganath Prabu 				src = (void *)dst + ioc->sge_size;
968ba630ea0SSuganath Prabu 
969ba630ea0SSuganath Prabu 				memcpy(&tmp, src, ioc->sge_size);
970ba630ea0SSuganath Prabu 				memcpy(src, dst, ioc->sge_size);
971ba630ea0SSuganath Prabu 				memcpy(dst, &tmp, ioc->sge_size);
972ba630ea0SSuganath Prabu 			}
973ba630ea0SSuganath Prabu 			if (ioc->logging_level & MPT_DEBUG_TM) {
974ba630ea0SSuganath Prabu 				ioc_info(ioc,
975ba630ea0SSuganath Prabu 				  "Mpi2ToolboxMemMoveRequest_t request msg\n");
976ba630ea0SSuganath Prabu 				_debug_dump_mf(mem_move_request,
977ba630ea0SSuganath Prabu 							ioc->request_sz/4);
978ba630ea0SSuganath Prabu 			}
979ba630ea0SSuganath Prabu 		} else
980f92363d1SSreekanth Reddy 			ioc->build_sg_mpi(ioc, psge, data_out_dma, data_out_sz,
981f92363d1SSreekanth Reddy 			    data_in_dma, data_in_sz);
982078a4cc1SSuganath Prabu S 		ioc->put_smid_default(ioc, smid);
983f92363d1SSreekanth Reddy 		break;
984f92363d1SSreekanth Reddy 	}
985f92363d1SSreekanth Reddy 	case MPI2_FUNCTION_SAS_IO_UNIT_CONTROL:
986f92363d1SSreekanth Reddy 	{
987f92363d1SSreekanth Reddy 		Mpi2SasIoUnitControlRequest_t *sasiounit_request =
988f92363d1SSreekanth Reddy 		    (Mpi2SasIoUnitControlRequest_t *)mpi_request;
989f92363d1SSreekanth Reddy 
990f92363d1SSreekanth Reddy 		if (sasiounit_request->Operation == MPI2_SAS_OP_PHY_HARD_RESET
991f92363d1SSreekanth Reddy 		    || sasiounit_request->Operation ==
992f92363d1SSreekanth Reddy 		    MPI2_SAS_OP_PHY_LINK_RESET) {
993f92363d1SSreekanth Reddy 			ioc->ioc_link_reset_in_progress = 1;
994f92363d1SSreekanth Reddy 			ioc->ignore_loginfos = 1;
995f92363d1SSreekanth Reddy 		}
996f92363d1SSreekanth Reddy 		/* drop to default case for posting the request */
997f92363d1SSreekanth Reddy 	}
998eb0c7af2SBart Van Assche 		/* fall through */
999f92363d1SSreekanth Reddy 	default:
1000f92363d1SSreekanth Reddy 		ioc->build_sg_mpi(ioc, psge, data_out_dma, data_out_sz,
1001f92363d1SSreekanth Reddy 		    data_in_dma, data_in_sz);
1002078a4cc1SSuganath Prabu S 		ioc->put_smid_default(ioc, smid);
1003f92363d1SSreekanth Reddy 		break;
1004f92363d1SSreekanth Reddy 	}
1005f92363d1SSreekanth Reddy 
1006f92363d1SSreekanth Reddy 	if (karg.timeout < MPT3_IOCTL_DEFAULT_TIMEOUT)
1007f92363d1SSreekanth Reddy 		timeout = MPT3_IOCTL_DEFAULT_TIMEOUT;
1008f92363d1SSreekanth Reddy 	else
1009f92363d1SSreekanth Reddy 		timeout = karg.timeout;
10108bbb1cf6SCalvin Owens 	wait_for_completion_timeout(&ioc->ctl_cmds.done, timeout*HZ);
1011f92363d1SSreekanth Reddy 	if (mpi_request->Function == MPI2_FUNCTION_SCSI_TASK_MGMT) {
1012f92363d1SSreekanth Reddy 		Mpi2SCSITaskManagementRequest_t *tm_request =
1013f92363d1SSreekanth Reddy 		    (Mpi2SCSITaskManagementRequest_t *)mpi_request;
1014f92363d1SSreekanth Reddy 		mpt3sas_scsih_clear_tm_flag(ioc, le16_to_cpu(
1015f92363d1SSreekanth Reddy 		    tm_request->DevHandle));
1016f92363d1SSreekanth Reddy 		mpt3sas_trigger_master(ioc, MASTER_TRIGGER_TASK_MANAGMENT);
1017f92363d1SSreekanth Reddy 	} else if ((mpi_request->Function == MPI2_FUNCTION_SMP_PASSTHROUGH ||
1018f92363d1SSreekanth Reddy 	    mpi_request->Function == MPI2_FUNCTION_SAS_IO_UNIT_CONTROL) &&
1019f92363d1SSreekanth Reddy 		ioc->ioc_link_reset_in_progress) {
1020f92363d1SSreekanth Reddy 		ioc->ioc_link_reset_in_progress = 0;
1021f92363d1SSreekanth Reddy 		ioc->ignore_loginfos = 0;
1022f92363d1SSreekanth Reddy 	}
1023f92363d1SSreekanth Reddy 	if (!(ioc->ctl_cmds.status & MPT3_CMD_COMPLETE)) {
1024d37306caSChaitra P B 		issue_reset =
1025d37306caSChaitra P B 			mpt3sas_base_check_cmd_timeout(ioc,
1026d37306caSChaitra P B 				ioc->ctl_cmds.status, mpi_request,
1027d37306caSChaitra P B 				karg.data_sge_offset);
1028f92363d1SSreekanth Reddy 		goto issue_host_reset;
1029f92363d1SSreekanth Reddy 	}
1030f92363d1SSreekanth Reddy 
1031f92363d1SSreekanth Reddy 	mpi_reply = ioc->ctl_cmds.reply;
1032f92363d1SSreekanth Reddy 
1033f92363d1SSreekanth Reddy 	if (mpi_reply->Function == MPI2_FUNCTION_SCSI_TASK_MGMT &&
1034f92363d1SSreekanth Reddy 	    (ioc->logging_level & MPT_DEBUG_TM)) {
1035f92363d1SSreekanth Reddy 		Mpi2SCSITaskManagementReply_t *tm_reply =
1036f92363d1SSreekanth Reddy 		    (Mpi2SCSITaskManagementReply_t *)mpi_reply;
1037f92363d1SSreekanth Reddy 
1038919d8a3fSJoe Perches 		ioc_info(ioc, "TASK_MGMT: IOCStatus(0x%04x), IOCLogInfo(0x%08x), TerminationCount(0x%08x)\n",
1039f92363d1SSreekanth Reddy 			 le16_to_cpu(tm_reply->IOCStatus),
1040f92363d1SSreekanth Reddy 			 le32_to_cpu(tm_reply->IOCLogInfo),
1041f92363d1SSreekanth Reddy 			 le32_to_cpu(tm_reply->TerminationCount));
1042f92363d1SSreekanth Reddy 	}
1043af009411SSreekanth Reddy 
1044f92363d1SSreekanth Reddy 	/* copy out xdata to user */
1045f92363d1SSreekanth Reddy 	if (data_in_sz) {
1046f92363d1SSreekanth Reddy 		if (copy_to_user(karg.data_in_buf_ptr, data_in,
1047f92363d1SSreekanth Reddy 		    data_in_sz)) {
1048f92363d1SSreekanth Reddy 			pr_err("failure at %s:%d/%s()!\n", __FILE__,
1049f92363d1SSreekanth Reddy 			    __LINE__, __func__);
1050f92363d1SSreekanth Reddy 			ret = -ENODATA;
1051f92363d1SSreekanth Reddy 			goto out;
1052f92363d1SSreekanth Reddy 		}
1053f92363d1SSreekanth Reddy 	}
1054f92363d1SSreekanth Reddy 
1055f92363d1SSreekanth Reddy 	/* copy out reply message frame to user */
1056f92363d1SSreekanth Reddy 	if (karg.max_reply_bytes) {
1057f92363d1SSreekanth Reddy 		sz = min_t(u32, karg.max_reply_bytes, ioc->reply_sz);
1058f92363d1SSreekanth Reddy 		if (copy_to_user(karg.reply_frame_buf_ptr, ioc->ctl_cmds.reply,
1059f92363d1SSreekanth Reddy 		    sz)) {
1060f92363d1SSreekanth Reddy 			pr_err("failure at %s:%d/%s()!\n", __FILE__,
1061f92363d1SSreekanth Reddy 			    __LINE__, __func__);
1062f92363d1SSreekanth Reddy 			ret = -ENODATA;
1063f92363d1SSreekanth Reddy 			goto out;
1064f92363d1SSreekanth Reddy 		}
1065f92363d1SSreekanth Reddy 	}
1066f92363d1SSreekanth Reddy 
1067aff39e61SSuganath Prabu Subramani 	/* copy out sense/NVMe Error Response to user */
1068f92363d1SSreekanth Reddy 	if (karg.max_sense_bytes && (mpi_request->Function ==
1069f92363d1SSreekanth Reddy 	    MPI2_FUNCTION_SCSI_IO_REQUEST || mpi_request->Function ==
1070aff39e61SSuganath Prabu Subramani 	    MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH || mpi_request->Function ==
1071aff39e61SSuganath Prabu Subramani 	    MPI2_FUNCTION_NVME_ENCAPSULATED)) {
1072aff39e61SSuganath Prabu Subramani 		if (karg.sense_data_ptr == NULL) {
1073919d8a3fSJoe Perches 			ioc_info(ioc, "Response buffer provided by application is NULL; Response data will not be returned\n");
1074aff39e61SSuganath Prabu Subramani 			goto out;
1075aff39e61SSuganath Prabu Subramani 		}
1076aff39e61SSuganath Prabu Subramani 		sz_arg = (mpi_request->Function ==
1077aff39e61SSuganath Prabu Subramani 		MPI2_FUNCTION_NVME_ENCAPSULATED) ? NVME_ERROR_RESPONSE_SIZE :
1078aff39e61SSuganath Prabu Subramani 							SCSI_SENSE_BUFFERSIZE;
1079aff39e61SSuganath Prabu Subramani 		sz = min_t(u32, karg.max_sense_bytes, sz_arg);
1080f92363d1SSreekanth Reddy 		if (copy_to_user(karg.sense_data_ptr, ioc->ctl_cmds.sense,
1081f92363d1SSreekanth Reddy 		    sz)) {
1082f92363d1SSreekanth Reddy 			pr_err("failure at %s:%d/%s()!\n", __FILE__,
1083f92363d1SSreekanth Reddy 				__LINE__, __func__);
1084f92363d1SSreekanth Reddy 			ret = -ENODATA;
1085f92363d1SSreekanth Reddy 			goto out;
1086f92363d1SSreekanth Reddy 		}
1087f92363d1SSreekanth Reddy 	}
1088f92363d1SSreekanth Reddy 
1089f92363d1SSreekanth Reddy  issue_host_reset:
1090f92363d1SSreekanth Reddy 	if (issue_reset) {
1091f92363d1SSreekanth Reddy 		ret = -ENODATA;
1092f92363d1SSreekanth Reddy 		if ((mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST ||
1093f92363d1SSreekanth Reddy 		    mpi_request->Function ==
1094f92363d1SSreekanth Reddy 		    MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH ||
1095f92363d1SSreekanth Reddy 		    mpi_request->Function == MPI2_FUNCTION_SATA_PASSTHROUGH)) {
1096919d8a3fSJoe Perches 			ioc_info(ioc, "issue target reset: handle = (0x%04x)\n",
1097f92363d1SSreekanth Reddy 				 le16_to_cpu(mpi_request->FunctionDependent1));
1098f92363d1SSreekanth Reddy 			mpt3sas_halt_firmware(ioc);
1099c1a6c5acSChaitra P B 			pcie_device = mpt3sas_get_pdev_by_handle(ioc,
1100c1a6c5acSChaitra P B 				le16_to_cpu(mpi_request->FunctionDependent1));
11015bb309dbSSuganath Prabu 			if (pcie_device && (!ioc->tm_custom_handling) &&
11025bb309dbSSuganath Prabu 			    (!(mpt3sas_scsih_is_pcie_scsi_device(
11035bb309dbSSuganath Prabu 			    pcie_device->device_info))))
110496902835SCalvin Owens 				mpt3sas_scsih_issue_locked_tm(ioc,
1105c1a6c5acSChaitra P B 				  le16_to_cpu(mpi_request->FunctionDependent1),
1106c1a6c5acSChaitra P B 				  0, MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0,
1107c1a6c5acSChaitra P B 				  0, pcie_device->reset_timeout,
11085bb309dbSSuganath Prabu 			MPI26_SCSITASKMGMT_MSGFLAGS_PROTOCOL_LVL_RST_PCIE);
1109c1a6c5acSChaitra P B 			else
1110c1a6c5acSChaitra P B 				mpt3sas_scsih_issue_locked_tm(ioc,
1111c1a6c5acSChaitra P B 				  le16_to_cpu(mpi_request->FunctionDependent1),
1112c1a6c5acSChaitra P B 				  0, MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0,
1113c1a6c5acSChaitra P B 				  0, 30, MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET);
1114f92363d1SSreekanth Reddy 		} else
111598c56ad3SCalvin Owens 			mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER);
1116f92363d1SSreekanth Reddy 	}
1117f92363d1SSreekanth Reddy 
1118f92363d1SSreekanth Reddy  out:
1119c1a6c5acSChaitra P B 	if (pcie_device)
1120c1a6c5acSChaitra P B 		pcie_device_put(pcie_device);
1121f92363d1SSreekanth Reddy 
1122f92363d1SSreekanth Reddy 	/* free memory associated with sg buffers */
1123f92363d1SSreekanth Reddy 	if (data_in)
11241c2048bdSChristoph Hellwig 		dma_free_coherent(&ioc->pdev->dev, data_in_sz, data_in,
1125f92363d1SSreekanth Reddy 		    data_in_dma);
1126f92363d1SSreekanth Reddy 
1127f92363d1SSreekanth Reddy 	if (data_out)
11281c2048bdSChristoph Hellwig 		dma_free_coherent(&ioc->pdev->dev, data_out_sz, data_out,
1129f92363d1SSreekanth Reddy 		    data_out_dma);
1130f92363d1SSreekanth Reddy 
1131f92363d1SSreekanth Reddy 	kfree(mpi_request);
1132f92363d1SSreekanth Reddy 	ioc->ctl_cmds.status = MPT3_CMD_NOT_USED;
1133f92363d1SSreekanth Reddy 	return ret;
1134f92363d1SSreekanth Reddy }
1135f92363d1SSreekanth Reddy 
1136f92363d1SSreekanth Reddy /**
1137f92363d1SSreekanth Reddy  * _ctl_getiocinfo - main handler for MPT3IOCINFO opcode
1138f92363d1SSreekanth Reddy  * @ioc: per adapter object
11394beb4867SBart Van Assche  * @arg: user space buffer containing ioctl content
1140f92363d1SSreekanth Reddy  */
1141f92363d1SSreekanth Reddy static long
1142f92363d1SSreekanth Reddy _ctl_getiocinfo(struct MPT3SAS_ADAPTER *ioc, void __user *arg)
1143f92363d1SSreekanth Reddy {
1144f92363d1SSreekanth Reddy 	struct mpt3_ioctl_iocinfo karg;
1145f92363d1SSreekanth Reddy 
1146919d8a3fSJoe Perches 	dctlprintk(ioc, ioc_info(ioc, "%s: enter\n",
1147f92363d1SSreekanth Reddy 				 __func__));
1148f92363d1SSreekanth Reddy 
1149f92363d1SSreekanth Reddy 	memset(&karg, 0 , sizeof(karg));
1150f92363d1SSreekanth Reddy 	if (ioc->pfacts)
1151f92363d1SSreekanth Reddy 		karg.port_number = ioc->pfacts[0].PortNumber;
1152f92363d1SSreekanth Reddy 	karg.hw_rev = ioc->pdev->revision;
1153f92363d1SSreekanth Reddy 	karg.pci_id = ioc->pdev->device;
1154f92363d1SSreekanth Reddy 	karg.subsystem_device = ioc->pdev->subsystem_device;
1155f92363d1SSreekanth Reddy 	karg.subsystem_vendor = ioc->pdev->subsystem_vendor;
1156f92363d1SSreekanth Reddy 	karg.pci_information.u.bits.bus = ioc->pdev->bus->number;
1157f92363d1SSreekanth Reddy 	karg.pci_information.u.bits.device = PCI_SLOT(ioc->pdev->devfn);
1158f92363d1SSreekanth Reddy 	karg.pci_information.u.bits.function = PCI_FUNC(ioc->pdev->devfn);
1159f92363d1SSreekanth Reddy 	karg.pci_information.segment_id = pci_domain_nr(ioc->pdev->bus);
1160f92363d1SSreekanth Reddy 	karg.firmware_version = ioc->facts.FWVersion.Word;
1161c84b06a4SSreekanth Reddy 	strcpy(karg.driver_version, ioc->driver_name);
1162f92363d1SSreekanth Reddy 	strcat(karg.driver_version, "-");
1163d357e84dSSreekanth Reddy 	switch  (ioc->hba_mpi_version_belonged) {
1164d357e84dSSreekanth Reddy 	case MPI2_VERSION:
11657786ab6aSSreekanth Reddy 		if (ioc->is_warpdrive)
11667786ab6aSSreekanth Reddy 			karg.adapter_type = MPT2_IOCTL_INTERFACE_SAS2_SSS6200;
11677786ab6aSSreekanth Reddy 		else
1168d357e84dSSreekanth Reddy 			karg.adapter_type = MPT2_IOCTL_INTERFACE_SAS2;
1169d357e84dSSreekanth Reddy 		strcat(karg.driver_version, MPT2SAS_DRIVER_VERSION);
1170d357e84dSSreekanth Reddy 		break;
1171d357e84dSSreekanth Reddy 	case MPI25_VERSION:
1172b130b0d5SSuganath prabu Subramani 	case MPI26_VERSION:
1173998f26aeSSuganath Prabu Subramani 		if (ioc->is_gen35_ioc)
1174998f26aeSSuganath Prabu Subramani 			karg.adapter_type = MPT3_IOCTL_INTERFACE_SAS35;
1175998f26aeSSuganath Prabu Subramani 		else
1176d357e84dSSreekanth Reddy 			karg.adapter_type = MPT3_IOCTL_INTERFACE_SAS3;
1177d357e84dSSreekanth Reddy 		strcat(karg.driver_version, MPT3SAS_DRIVER_VERSION);
1178d357e84dSSreekanth Reddy 		break;
1179d357e84dSSreekanth Reddy 	}
1180f92363d1SSreekanth Reddy 	karg.bios_version = le32_to_cpu(ioc->bios_pg3.BiosVersion);
1181f92363d1SSreekanth Reddy 
1182f92363d1SSreekanth Reddy 	if (copy_to_user(arg, &karg, sizeof(karg))) {
1183f92363d1SSreekanth Reddy 		pr_err("failure at %s:%d/%s()!\n",
1184f92363d1SSreekanth Reddy 		    __FILE__, __LINE__, __func__);
1185f92363d1SSreekanth Reddy 		return -EFAULT;
1186f92363d1SSreekanth Reddy 	}
1187f92363d1SSreekanth Reddy 	return 0;
1188f92363d1SSreekanth Reddy }
1189f92363d1SSreekanth Reddy 
1190f92363d1SSreekanth Reddy /**
1191f92363d1SSreekanth Reddy  * _ctl_eventquery - main handler for MPT3EVENTQUERY opcode
1192f92363d1SSreekanth Reddy  * @ioc: per adapter object
11934beb4867SBart Van Assche  * @arg: user space buffer containing ioctl content
1194f92363d1SSreekanth Reddy  */
1195f92363d1SSreekanth Reddy static long
1196f92363d1SSreekanth Reddy _ctl_eventquery(struct MPT3SAS_ADAPTER *ioc, void __user *arg)
1197f92363d1SSreekanth Reddy {
1198f92363d1SSreekanth Reddy 	struct mpt3_ioctl_eventquery karg;
1199f92363d1SSreekanth Reddy 
1200f92363d1SSreekanth Reddy 	if (copy_from_user(&karg, arg, sizeof(karg))) {
1201f92363d1SSreekanth Reddy 		pr_err("failure at %s:%d/%s()!\n",
1202f92363d1SSreekanth Reddy 		    __FILE__, __LINE__, __func__);
1203f92363d1SSreekanth Reddy 		return -EFAULT;
1204f92363d1SSreekanth Reddy 	}
1205f92363d1SSreekanth Reddy 
1206919d8a3fSJoe Perches 	dctlprintk(ioc, ioc_info(ioc, "%s: enter\n",
1207f92363d1SSreekanth Reddy 				 __func__));
1208f92363d1SSreekanth Reddy 
1209f92363d1SSreekanth Reddy 	karg.event_entries = MPT3SAS_CTL_EVENT_LOG_SIZE;
1210f92363d1SSreekanth Reddy 	memcpy(karg.event_types, ioc->event_type,
1211f92363d1SSreekanth Reddy 	    MPI2_EVENT_NOTIFY_EVENTMASK_WORDS * sizeof(u32));
1212f92363d1SSreekanth Reddy 
1213f92363d1SSreekanth Reddy 	if (copy_to_user(arg, &karg, sizeof(karg))) {
1214f92363d1SSreekanth Reddy 		pr_err("failure at %s:%d/%s()!\n",
1215f92363d1SSreekanth Reddy 		    __FILE__, __LINE__, __func__);
1216f92363d1SSreekanth Reddy 		return -EFAULT;
1217f92363d1SSreekanth Reddy 	}
1218f92363d1SSreekanth Reddy 	return 0;
1219f92363d1SSreekanth Reddy }
1220f92363d1SSreekanth Reddy 
1221f92363d1SSreekanth Reddy /**
1222f92363d1SSreekanth Reddy  * _ctl_eventenable - main handler for MPT3EVENTENABLE opcode
1223f92363d1SSreekanth Reddy  * @ioc: per adapter object
12244beb4867SBart Van Assche  * @arg: user space buffer containing ioctl content
1225f92363d1SSreekanth Reddy  */
1226f92363d1SSreekanth Reddy static long
1227f92363d1SSreekanth Reddy _ctl_eventenable(struct MPT3SAS_ADAPTER *ioc, void __user *arg)
1228f92363d1SSreekanth Reddy {
1229f92363d1SSreekanth Reddy 	struct mpt3_ioctl_eventenable karg;
1230f92363d1SSreekanth Reddy 
1231f92363d1SSreekanth Reddy 	if (copy_from_user(&karg, arg, sizeof(karg))) {
1232f92363d1SSreekanth Reddy 		pr_err("failure at %s:%d/%s()!\n",
1233f92363d1SSreekanth Reddy 		    __FILE__, __LINE__, __func__);
1234f92363d1SSreekanth Reddy 		return -EFAULT;
1235f92363d1SSreekanth Reddy 	}
1236f92363d1SSreekanth Reddy 
1237919d8a3fSJoe Perches 	dctlprintk(ioc, ioc_info(ioc, "%s: enter\n",
1238f92363d1SSreekanth Reddy 				 __func__));
1239f92363d1SSreekanth Reddy 
1240f92363d1SSreekanth Reddy 	memcpy(ioc->event_type, karg.event_types,
1241f92363d1SSreekanth Reddy 	    MPI2_EVENT_NOTIFY_EVENTMASK_WORDS * sizeof(u32));
1242f92363d1SSreekanth Reddy 	mpt3sas_base_validate_event_type(ioc, ioc->event_type);
1243f92363d1SSreekanth Reddy 
1244f92363d1SSreekanth Reddy 	if (ioc->event_log)
1245f92363d1SSreekanth Reddy 		return 0;
1246f92363d1SSreekanth Reddy 	/* initialize event_log */
1247f92363d1SSreekanth Reddy 	ioc->event_context = 0;
1248f92363d1SSreekanth Reddy 	ioc->aen_event_read_flag = 0;
1249f92363d1SSreekanth Reddy 	ioc->event_log = kcalloc(MPT3SAS_CTL_EVENT_LOG_SIZE,
1250f92363d1SSreekanth Reddy 	    sizeof(struct MPT3_IOCTL_EVENTS), GFP_KERNEL);
1251f92363d1SSreekanth Reddy 	if (!ioc->event_log) {
1252f92363d1SSreekanth Reddy 		pr_err("failure at %s:%d/%s()!\n",
1253f92363d1SSreekanth Reddy 		    __FILE__, __LINE__, __func__);
1254f92363d1SSreekanth Reddy 		return -ENOMEM;
1255f92363d1SSreekanth Reddy 	}
1256f92363d1SSreekanth Reddy 	return 0;
1257f92363d1SSreekanth Reddy }
1258f92363d1SSreekanth Reddy 
1259f92363d1SSreekanth Reddy /**
1260f92363d1SSreekanth Reddy  * _ctl_eventreport - main handler for MPT3EVENTREPORT opcode
1261f92363d1SSreekanth Reddy  * @ioc: per adapter object
12624beb4867SBart Van Assche  * @arg: user space buffer containing ioctl content
1263f92363d1SSreekanth Reddy  */
1264f92363d1SSreekanth Reddy static long
1265f92363d1SSreekanth Reddy _ctl_eventreport(struct MPT3SAS_ADAPTER *ioc, void __user *arg)
1266f92363d1SSreekanth Reddy {
1267f92363d1SSreekanth Reddy 	struct mpt3_ioctl_eventreport karg;
1268f92363d1SSreekanth Reddy 	u32 number_bytes, max_events, max;
1269f92363d1SSreekanth Reddy 	struct mpt3_ioctl_eventreport __user *uarg = arg;
1270f92363d1SSreekanth Reddy 
1271f92363d1SSreekanth Reddy 	if (copy_from_user(&karg, arg, sizeof(karg))) {
1272f92363d1SSreekanth Reddy 		pr_err("failure at %s:%d/%s()!\n",
1273f92363d1SSreekanth Reddy 		    __FILE__, __LINE__, __func__);
1274f92363d1SSreekanth Reddy 		return -EFAULT;
1275f92363d1SSreekanth Reddy 	}
1276f92363d1SSreekanth Reddy 
1277919d8a3fSJoe Perches 	dctlprintk(ioc, ioc_info(ioc, "%s: enter\n",
1278f92363d1SSreekanth Reddy 				 __func__));
1279f92363d1SSreekanth Reddy 
1280f92363d1SSreekanth Reddy 	number_bytes = karg.hdr.max_data_size -
1281f92363d1SSreekanth Reddy 	    sizeof(struct mpt3_ioctl_header);
1282f92363d1SSreekanth Reddy 	max_events = number_bytes/sizeof(struct MPT3_IOCTL_EVENTS);
1283f92363d1SSreekanth Reddy 	max = min_t(u32, MPT3SAS_CTL_EVENT_LOG_SIZE, max_events);
1284f92363d1SSreekanth Reddy 
1285f92363d1SSreekanth Reddy 	/* If fewer than 1 event is requested, there must have
1286f92363d1SSreekanth Reddy 	 * been some type of error.
1287f92363d1SSreekanth Reddy 	 */
1288f92363d1SSreekanth Reddy 	if (!max || !ioc->event_log)
1289f92363d1SSreekanth Reddy 		return -ENODATA;
1290f92363d1SSreekanth Reddy 
1291f92363d1SSreekanth Reddy 	number_bytes = max * sizeof(struct MPT3_IOCTL_EVENTS);
1292f92363d1SSreekanth Reddy 	if (copy_to_user(uarg->event_data, ioc->event_log, number_bytes)) {
1293f92363d1SSreekanth Reddy 		pr_err("failure at %s:%d/%s()!\n",
1294f92363d1SSreekanth Reddy 		    __FILE__, __LINE__, __func__);
1295f92363d1SSreekanth Reddy 		return -EFAULT;
1296f92363d1SSreekanth Reddy 	}
1297f92363d1SSreekanth Reddy 
1298f92363d1SSreekanth Reddy 	/* reset flag so SIGIO can restart */
1299f92363d1SSreekanth Reddy 	ioc->aen_event_read_flag = 0;
1300f92363d1SSreekanth Reddy 	return 0;
1301f92363d1SSreekanth Reddy }
1302f92363d1SSreekanth Reddy 
1303f92363d1SSreekanth Reddy /**
1304f92363d1SSreekanth Reddy  * _ctl_do_reset - main handler for MPT3HARDRESET opcode
1305f92363d1SSreekanth Reddy  * @ioc: per adapter object
13064beb4867SBart Van Assche  * @arg: user space buffer containing ioctl content
1307f92363d1SSreekanth Reddy  */
1308f92363d1SSreekanth Reddy static long
1309f92363d1SSreekanth Reddy _ctl_do_reset(struct MPT3SAS_ADAPTER *ioc, void __user *arg)
1310f92363d1SSreekanth Reddy {
1311f92363d1SSreekanth Reddy 	struct mpt3_ioctl_diag_reset karg;
1312f92363d1SSreekanth Reddy 	int retval;
1313f92363d1SSreekanth Reddy 
1314f92363d1SSreekanth Reddy 	if (copy_from_user(&karg, arg, sizeof(karg))) {
1315f92363d1SSreekanth Reddy 		pr_err("failure at %s:%d/%s()!\n",
1316f92363d1SSreekanth Reddy 		    __FILE__, __LINE__, __func__);
1317f92363d1SSreekanth Reddy 		return -EFAULT;
1318f92363d1SSreekanth Reddy 	}
1319f92363d1SSreekanth Reddy 
1320f92363d1SSreekanth Reddy 	if (ioc->shost_recovery || ioc->pci_error_recovery ||
1321f92363d1SSreekanth Reddy 	    ioc->is_driver_loading)
1322f92363d1SSreekanth Reddy 		return -EAGAIN;
1323f92363d1SSreekanth Reddy 
1324919d8a3fSJoe Perches 	dctlprintk(ioc, ioc_info(ioc, "%s: enter\n",
1325f92363d1SSreekanth Reddy 				 __func__));
1326f92363d1SSreekanth Reddy 
132798c56ad3SCalvin Owens 	retval = mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER);
1328919d8a3fSJoe Perches 	ioc_info(ioc, "host reset: %s\n", ((!retval) ? "SUCCESS" : "FAILED"));
1329f92363d1SSreekanth Reddy 	return 0;
1330f92363d1SSreekanth Reddy }
1331f92363d1SSreekanth Reddy 
1332f92363d1SSreekanth Reddy /**
1333f92363d1SSreekanth Reddy  * _ctl_btdh_search_sas_device - searching for sas device
1334f92363d1SSreekanth Reddy  * @ioc: per adapter object
1335f92363d1SSreekanth Reddy  * @btdh: btdh ioctl payload
1336f92363d1SSreekanth Reddy  */
1337f92363d1SSreekanth Reddy static int
1338f92363d1SSreekanth Reddy _ctl_btdh_search_sas_device(struct MPT3SAS_ADAPTER *ioc,
1339f92363d1SSreekanth Reddy 	struct mpt3_ioctl_btdh_mapping *btdh)
1340f92363d1SSreekanth Reddy {
1341f92363d1SSreekanth Reddy 	struct _sas_device *sas_device;
1342f92363d1SSreekanth Reddy 	unsigned long flags;
1343f92363d1SSreekanth Reddy 	int rc = 0;
1344f92363d1SSreekanth Reddy 
1345f92363d1SSreekanth Reddy 	if (list_empty(&ioc->sas_device_list))
1346f92363d1SSreekanth Reddy 		return rc;
1347f92363d1SSreekanth Reddy 
1348f92363d1SSreekanth Reddy 	spin_lock_irqsave(&ioc->sas_device_lock, flags);
1349f92363d1SSreekanth Reddy 	list_for_each_entry(sas_device, &ioc->sas_device_list, list) {
1350f92363d1SSreekanth Reddy 		if (btdh->bus == 0xFFFFFFFF && btdh->id == 0xFFFFFFFF &&
1351f92363d1SSreekanth Reddy 		    btdh->handle == sas_device->handle) {
1352f92363d1SSreekanth Reddy 			btdh->bus = sas_device->channel;
1353f92363d1SSreekanth Reddy 			btdh->id = sas_device->id;
1354f92363d1SSreekanth Reddy 			rc = 1;
1355f92363d1SSreekanth Reddy 			goto out;
1356f92363d1SSreekanth Reddy 		} else if (btdh->bus == sas_device->channel && btdh->id ==
1357f92363d1SSreekanth Reddy 		    sas_device->id && btdh->handle == 0xFFFF) {
1358f92363d1SSreekanth Reddy 			btdh->handle = sas_device->handle;
1359f92363d1SSreekanth Reddy 			rc = 1;
1360f92363d1SSreekanth Reddy 			goto out;
1361f92363d1SSreekanth Reddy 		}
1362f92363d1SSreekanth Reddy 	}
1363f92363d1SSreekanth Reddy  out:
1364f92363d1SSreekanth Reddy 	spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
1365f92363d1SSreekanth Reddy 	return rc;
1366f92363d1SSreekanth Reddy }
1367f92363d1SSreekanth Reddy 
1368f92363d1SSreekanth Reddy /**
136945aa6a1aSSuganath Prabu Subramani  * _ctl_btdh_search_pcie_device - searching for pcie device
137045aa6a1aSSuganath Prabu Subramani  * @ioc: per adapter object
137145aa6a1aSSuganath Prabu Subramani  * @btdh: btdh ioctl payload
137245aa6a1aSSuganath Prabu Subramani  */
137345aa6a1aSSuganath Prabu Subramani static int
137445aa6a1aSSuganath Prabu Subramani _ctl_btdh_search_pcie_device(struct MPT3SAS_ADAPTER *ioc,
137545aa6a1aSSuganath Prabu Subramani 	struct mpt3_ioctl_btdh_mapping *btdh)
137645aa6a1aSSuganath Prabu Subramani {
137745aa6a1aSSuganath Prabu Subramani 	struct _pcie_device *pcie_device;
137845aa6a1aSSuganath Prabu Subramani 	unsigned long flags;
137945aa6a1aSSuganath Prabu Subramani 	int rc = 0;
138045aa6a1aSSuganath Prabu Subramani 
138145aa6a1aSSuganath Prabu Subramani 	if (list_empty(&ioc->pcie_device_list))
138245aa6a1aSSuganath Prabu Subramani 		return rc;
138345aa6a1aSSuganath Prabu Subramani 
138445aa6a1aSSuganath Prabu Subramani 	spin_lock_irqsave(&ioc->pcie_device_lock, flags);
138545aa6a1aSSuganath Prabu Subramani 	list_for_each_entry(pcie_device, &ioc->pcie_device_list, list) {
138645aa6a1aSSuganath Prabu Subramani 		if (btdh->bus == 0xFFFFFFFF && btdh->id == 0xFFFFFFFF &&
138745aa6a1aSSuganath Prabu Subramani 			   btdh->handle == pcie_device->handle) {
138845aa6a1aSSuganath Prabu Subramani 			btdh->bus = pcie_device->channel;
138945aa6a1aSSuganath Prabu Subramani 			btdh->id = pcie_device->id;
139045aa6a1aSSuganath Prabu Subramani 			rc = 1;
139145aa6a1aSSuganath Prabu Subramani 			goto out;
139245aa6a1aSSuganath Prabu Subramani 		} else if (btdh->bus == pcie_device->channel && btdh->id ==
139345aa6a1aSSuganath Prabu Subramani 			   pcie_device->id && btdh->handle == 0xFFFF) {
139445aa6a1aSSuganath Prabu Subramani 			btdh->handle = pcie_device->handle;
139545aa6a1aSSuganath Prabu Subramani 			rc = 1;
139645aa6a1aSSuganath Prabu Subramani 			goto out;
139745aa6a1aSSuganath Prabu Subramani 		}
139845aa6a1aSSuganath Prabu Subramani 	}
139945aa6a1aSSuganath Prabu Subramani  out:
140045aa6a1aSSuganath Prabu Subramani 	spin_unlock_irqrestore(&ioc->pcie_device_lock, flags);
140145aa6a1aSSuganath Prabu Subramani 	return rc;
140245aa6a1aSSuganath Prabu Subramani }
140345aa6a1aSSuganath Prabu Subramani 
140445aa6a1aSSuganath Prabu Subramani /**
1405f92363d1SSreekanth Reddy  * _ctl_btdh_search_raid_device - searching for raid device
1406f92363d1SSreekanth Reddy  * @ioc: per adapter object
1407f92363d1SSreekanth Reddy  * @btdh: btdh ioctl payload
1408f92363d1SSreekanth Reddy  */
1409f92363d1SSreekanth Reddy static int
1410f92363d1SSreekanth Reddy _ctl_btdh_search_raid_device(struct MPT3SAS_ADAPTER *ioc,
1411f92363d1SSreekanth Reddy 	struct mpt3_ioctl_btdh_mapping *btdh)
1412f92363d1SSreekanth Reddy {
1413f92363d1SSreekanth Reddy 	struct _raid_device *raid_device;
1414f92363d1SSreekanth Reddy 	unsigned long flags;
1415f92363d1SSreekanth Reddy 	int rc = 0;
1416f92363d1SSreekanth Reddy 
1417f92363d1SSreekanth Reddy 	if (list_empty(&ioc->raid_device_list))
1418f92363d1SSreekanth Reddy 		return rc;
1419f92363d1SSreekanth Reddy 
1420f92363d1SSreekanth Reddy 	spin_lock_irqsave(&ioc->raid_device_lock, flags);
1421f92363d1SSreekanth Reddy 	list_for_each_entry(raid_device, &ioc->raid_device_list, list) {
1422f92363d1SSreekanth Reddy 		if (btdh->bus == 0xFFFFFFFF && btdh->id == 0xFFFFFFFF &&
1423f92363d1SSreekanth Reddy 		    btdh->handle == raid_device->handle) {
1424f92363d1SSreekanth Reddy 			btdh->bus = raid_device->channel;
1425f92363d1SSreekanth Reddy 			btdh->id = raid_device->id;
1426f92363d1SSreekanth Reddy 			rc = 1;
1427f92363d1SSreekanth Reddy 			goto out;
1428f92363d1SSreekanth Reddy 		} else if (btdh->bus == raid_device->channel && btdh->id ==
1429f92363d1SSreekanth Reddy 		    raid_device->id && btdh->handle == 0xFFFF) {
1430f92363d1SSreekanth Reddy 			btdh->handle = raid_device->handle;
1431f92363d1SSreekanth Reddy 			rc = 1;
1432f92363d1SSreekanth Reddy 			goto out;
1433f92363d1SSreekanth Reddy 		}
1434f92363d1SSreekanth Reddy 	}
1435f92363d1SSreekanth Reddy  out:
1436f92363d1SSreekanth Reddy 	spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
1437f92363d1SSreekanth Reddy 	return rc;
1438f92363d1SSreekanth Reddy }
1439f92363d1SSreekanth Reddy 
1440f92363d1SSreekanth Reddy /**
1441f92363d1SSreekanth Reddy  * _ctl_btdh_mapping - main handler for MPT3BTDHMAPPING opcode
1442f92363d1SSreekanth Reddy  * @ioc: per adapter object
14434beb4867SBart Van Assche  * @arg: user space buffer containing ioctl content
1444f92363d1SSreekanth Reddy  */
1445f92363d1SSreekanth Reddy static long
1446f92363d1SSreekanth Reddy _ctl_btdh_mapping(struct MPT3SAS_ADAPTER *ioc, void __user *arg)
1447f92363d1SSreekanth Reddy {
1448f92363d1SSreekanth Reddy 	struct mpt3_ioctl_btdh_mapping karg;
1449f92363d1SSreekanth Reddy 	int rc;
1450f92363d1SSreekanth Reddy 
1451f92363d1SSreekanth Reddy 	if (copy_from_user(&karg, arg, sizeof(karg))) {
1452f92363d1SSreekanth Reddy 		pr_err("failure at %s:%d/%s()!\n",
1453f92363d1SSreekanth Reddy 		    __FILE__, __LINE__, __func__);
1454f92363d1SSreekanth Reddy 		return -EFAULT;
1455f92363d1SSreekanth Reddy 	}
1456f92363d1SSreekanth Reddy 
1457919d8a3fSJoe Perches 	dctlprintk(ioc, ioc_info(ioc, "%s\n",
1458f92363d1SSreekanth Reddy 				 __func__));
1459f92363d1SSreekanth Reddy 
1460f92363d1SSreekanth Reddy 	rc = _ctl_btdh_search_sas_device(ioc, &karg);
1461f92363d1SSreekanth Reddy 	if (!rc)
146245aa6a1aSSuganath Prabu Subramani 		rc = _ctl_btdh_search_pcie_device(ioc, &karg);
146345aa6a1aSSuganath Prabu Subramani 	if (!rc)
1464f92363d1SSreekanth Reddy 		_ctl_btdh_search_raid_device(ioc, &karg);
1465f92363d1SSreekanth Reddy 
1466f92363d1SSreekanth Reddy 	if (copy_to_user(arg, &karg, sizeof(karg))) {
1467f92363d1SSreekanth Reddy 		pr_err("failure at %s:%d/%s()!\n",
1468f92363d1SSreekanth Reddy 		    __FILE__, __LINE__, __func__);
1469f92363d1SSreekanth Reddy 		return -EFAULT;
1470f92363d1SSreekanth Reddy 	}
1471f92363d1SSreekanth Reddy 	return 0;
1472f92363d1SSreekanth Reddy }
1473f92363d1SSreekanth Reddy 
1474f92363d1SSreekanth Reddy /**
1475f92363d1SSreekanth Reddy  * _ctl_diag_capability - return diag buffer capability
1476f92363d1SSreekanth Reddy  * @ioc: per adapter object
1477f92363d1SSreekanth Reddy  * @buffer_type: specifies either TRACE, SNAPSHOT, or EXTENDED
1478f92363d1SSreekanth Reddy  *
1479f92363d1SSreekanth Reddy  * returns 1 when diag buffer support is enabled in firmware
1480f92363d1SSreekanth Reddy  */
1481f92363d1SSreekanth Reddy static u8
1482f92363d1SSreekanth Reddy _ctl_diag_capability(struct MPT3SAS_ADAPTER *ioc, u8 buffer_type)
1483f92363d1SSreekanth Reddy {
1484f92363d1SSreekanth Reddy 	u8 rc = 0;
1485f92363d1SSreekanth Reddy 
1486f92363d1SSreekanth Reddy 	switch (buffer_type) {
1487f92363d1SSreekanth Reddy 	case MPI2_DIAG_BUF_TYPE_TRACE:
1488f92363d1SSreekanth Reddy 		if (ioc->facts.IOCCapabilities &
1489f92363d1SSreekanth Reddy 		    MPI2_IOCFACTS_CAPABILITY_DIAG_TRACE_BUFFER)
1490f92363d1SSreekanth Reddy 			rc = 1;
1491f92363d1SSreekanth Reddy 		break;
1492f92363d1SSreekanth Reddy 	case MPI2_DIAG_BUF_TYPE_SNAPSHOT:
1493f92363d1SSreekanth Reddy 		if (ioc->facts.IOCCapabilities &
1494f92363d1SSreekanth Reddy 		    MPI2_IOCFACTS_CAPABILITY_SNAPSHOT_BUFFER)
1495f92363d1SSreekanth Reddy 			rc = 1;
1496f92363d1SSreekanth Reddy 		break;
1497f92363d1SSreekanth Reddy 	case MPI2_DIAG_BUF_TYPE_EXTENDED:
1498f92363d1SSreekanth Reddy 		if (ioc->facts.IOCCapabilities &
1499f92363d1SSreekanth Reddy 		    MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER)
1500f92363d1SSreekanth Reddy 			rc = 1;
1501f92363d1SSreekanth Reddy 	}
1502f92363d1SSreekanth Reddy 
1503f92363d1SSreekanth Reddy 	return rc;
1504f92363d1SSreekanth Reddy }
1505f92363d1SSreekanth Reddy 
150608e7378eSSreekanth Reddy /**
150708e7378eSSreekanth Reddy  * _ctl_diag_get_bufftype - return diag buffer type
150808e7378eSSreekanth Reddy  *              either TRACE, SNAPSHOT, or EXTENDED
150908e7378eSSreekanth Reddy  * @ioc: per adapter object
151008e7378eSSreekanth Reddy  * @unique_id: specifies the unique_id for the buffer
151108e7378eSSreekanth Reddy  *
151208e7378eSSreekanth Reddy  * returns MPT3_DIAG_UID_NOT_FOUND if the id not found
151308e7378eSSreekanth Reddy  */
151408e7378eSSreekanth Reddy static u8
151508e7378eSSreekanth Reddy _ctl_diag_get_bufftype(struct MPT3SAS_ADAPTER *ioc, u32 unique_id)
151608e7378eSSreekanth Reddy {
151708e7378eSSreekanth Reddy 	u8  index;
151808e7378eSSreekanth Reddy 
151908e7378eSSreekanth Reddy 	for (index = 0; index < MPI2_DIAG_BUF_TYPE_COUNT; index++) {
152008e7378eSSreekanth Reddy 		if (ioc->unique_id[index] == unique_id)
152108e7378eSSreekanth Reddy 			return index;
152208e7378eSSreekanth Reddy 	}
152308e7378eSSreekanth Reddy 
152408e7378eSSreekanth Reddy 	return MPT3_DIAG_UID_NOT_FOUND;
152508e7378eSSreekanth Reddy }
1526f92363d1SSreekanth Reddy 
1527f92363d1SSreekanth Reddy /**
1528f92363d1SSreekanth Reddy  * _ctl_diag_register_2 - wrapper for registering diag buffer support
1529f92363d1SSreekanth Reddy  * @ioc: per adapter object
1530f92363d1SSreekanth Reddy  * @diag_register: the diag_register struct passed in from user space
1531f92363d1SSreekanth Reddy  *
1532f92363d1SSreekanth Reddy  */
1533f92363d1SSreekanth Reddy static long
1534f92363d1SSreekanth Reddy _ctl_diag_register_2(struct MPT3SAS_ADAPTER *ioc,
1535f92363d1SSreekanth Reddy 	struct mpt3_diag_register *diag_register)
1536f92363d1SSreekanth Reddy {
1537f92363d1SSreekanth Reddy 	int rc, i;
1538f92363d1SSreekanth Reddy 	void *request_data = NULL;
1539f92363d1SSreekanth Reddy 	dma_addr_t request_data_dma;
1540f92363d1SSreekanth Reddy 	u32 request_data_sz = 0;
1541f92363d1SSreekanth Reddy 	Mpi2DiagBufferPostRequest_t *mpi_request;
1542f92363d1SSreekanth Reddy 	Mpi2DiagBufferPostReply_t *mpi_reply;
1543f92363d1SSreekanth Reddy 	u8 buffer_type;
1544f92363d1SSreekanth Reddy 	u16 smid;
1545f92363d1SSreekanth Reddy 	u16 ioc_status;
1546f92363d1SSreekanth Reddy 	u32 ioc_state;
1547f92363d1SSreekanth Reddy 	u8 issue_reset = 0;
1548f92363d1SSreekanth Reddy 
1549919d8a3fSJoe Perches 	dctlprintk(ioc, ioc_info(ioc, "%s\n",
1550f92363d1SSreekanth Reddy 				 __func__));
1551f92363d1SSreekanth Reddy 
1552f92363d1SSreekanth Reddy 	ioc_state = mpt3sas_base_get_iocstate(ioc, 1);
1553f92363d1SSreekanth Reddy 	if (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
1554919d8a3fSJoe Perches 		ioc_err(ioc, "%s: failed due to ioc not operational\n",
1555919d8a3fSJoe Perches 			__func__);
1556f92363d1SSreekanth Reddy 		rc = -EAGAIN;
1557f92363d1SSreekanth Reddy 		goto out;
1558f92363d1SSreekanth Reddy 	}
1559f92363d1SSreekanth Reddy 
1560f92363d1SSreekanth Reddy 	if (ioc->ctl_cmds.status != MPT3_CMD_NOT_USED) {
1561919d8a3fSJoe Perches 		ioc_err(ioc, "%s: ctl_cmd in use\n", __func__);
1562f92363d1SSreekanth Reddy 		rc = -EAGAIN;
1563f92363d1SSreekanth Reddy 		goto out;
1564f92363d1SSreekanth Reddy 	}
1565f92363d1SSreekanth Reddy 
1566f92363d1SSreekanth Reddy 	buffer_type = diag_register->buffer_type;
1567f92363d1SSreekanth Reddy 	if (!_ctl_diag_capability(ioc, buffer_type)) {
1568919d8a3fSJoe Perches 		ioc_err(ioc, "%s: doesn't have capability for buffer_type(0x%02x)\n",
1569919d8a3fSJoe Perches 			__func__, buffer_type);
1570f92363d1SSreekanth Reddy 		return -EPERM;
1571f92363d1SSreekanth Reddy 	}
1572f92363d1SSreekanth Reddy 
157308e7378eSSreekanth Reddy 	if (diag_register->unique_id == 0) {
157408e7378eSSreekanth Reddy 		ioc_err(ioc,
157508e7378eSSreekanth Reddy 		    "%s: Invalid UID(0x%08x), buffer_type(0x%02x)\n", __func__,
157608e7378eSSreekanth Reddy 		    diag_register->unique_id, buffer_type);
157708e7378eSSreekanth Reddy 		return -EINVAL;
157808e7378eSSreekanth Reddy 	}
157908e7378eSSreekanth Reddy 
1580a8a6cbcdSSreekanth Reddy 	if ((ioc->diag_buffer_status[buffer_type] &
1581a8a6cbcdSSreekanth Reddy 	    MPT3_DIAG_BUFFER_IS_APP_OWNED) &&
1582a8a6cbcdSSreekanth Reddy 	    !(ioc->diag_buffer_status[buffer_type] &
1583a8a6cbcdSSreekanth Reddy 	    MPT3_DIAG_BUFFER_IS_RELEASED)) {
1584a8a6cbcdSSreekanth Reddy 		ioc_err(ioc,
1585a8a6cbcdSSreekanth Reddy 		    "%s: buffer_type(0x%02x) is already registered by application with UID(0x%08x)\n",
1586a8a6cbcdSSreekanth Reddy 		    __func__, buffer_type, ioc->unique_id[buffer_type]);
1587a8a6cbcdSSreekanth Reddy 		return -EINVAL;
1588a8a6cbcdSSreekanth Reddy 	}
1589a8a6cbcdSSreekanth Reddy 
1590f92363d1SSreekanth Reddy 	if (ioc->diag_buffer_status[buffer_type] &
1591f92363d1SSreekanth Reddy 	    MPT3_DIAG_BUFFER_IS_REGISTERED) {
159208e7378eSSreekanth Reddy 		/*
159308e7378eSSreekanth Reddy 		 * If driver posts buffer initially, then an application wants
159408e7378eSSreekanth Reddy 		 * to Register that buffer (own it) without Releasing first,
159508e7378eSSreekanth Reddy 		 * the application Register command MUST have the same buffer
159608e7378eSSreekanth Reddy 		 * type and size in the Register command (obtained from the
159708e7378eSSreekanth Reddy 		 * Query command). Otherwise that Register command will be
159808e7378eSSreekanth Reddy 		 * failed. If the application has released the buffer but wants
159908e7378eSSreekanth Reddy 		 * to re-register it, it should be allowed as long as the
160008e7378eSSreekanth Reddy 		 * Unique-Id/Size match.
160108e7378eSSreekanth Reddy 		 */
160208e7378eSSreekanth Reddy 
160308e7378eSSreekanth Reddy 		if (ioc->unique_id[buffer_type] == MPT3DIAGBUFFUNIQUEID &&
160408e7378eSSreekanth Reddy 		    ioc->diag_buffer_sz[buffer_type] ==
160508e7378eSSreekanth Reddy 		    diag_register->requested_buffer_size) {
160608e7378eSSreekanth Reddy 
160708e7378eSSreekanth Reddy 			if (!(ioc->diag_buffer_status[buffer_type] &
160808e7378eSSreekanth Reddy 			     MPT3_DIAG_BUFFER_IS_RELEASED)) {
160908e7378eSSreekanth Reddy 				dctlprintk(ioc, ioc_info(ioc,
161008e7378eSSreekanth Reddy 				    "%s: diag_buffer (%d) ownership changed. old-ID(0x%08x), new-ID(0x%08x)\n",
161108e7378eSSreekanth Reddy 				    __func__, buffer_type,
161208e7378eSSreekanth Reddy 				    ioc->unique_id[buffer_type],
161308e7378eSSreekanth Reddy 				    diag_register->unique_id));
161408e7378eSSreekanth Reddy 
161508e7378eSSreekanth Reddy 				/*
161608e7378eSSreekanth Reddy 				 * Application wants to own the buffer with
161708e7378eSSreekanth Reddy 				 * the same size.
161808e7378eSSreekanth Reddy 				 */
161908e7378eSSreekanth Reddy 				ioc->unique_id[buffer_type] =
162008e7378eSSreekanth Reddy 				    diag_register->unique_id;
162108e7378eSSreekanth Reddy 				rc = 0; /* success */
162208e7378eSSreekanth Reddy 				goto out;
162308e7378eSSreekanth Reddy 			}
162408e7378eSSreekanth Reddy 		} else if (ioc->unique_id[buffer_type] !=
162508e7378eSSreekanth Reddy 		    MPT3DIAGBUFFUNIQUEID) {
162608e7378eSSreekanth Reddy 			if (ioc->unique_id[buffer_type] !=
162708e7378eSSreekanth Reddy 			    diag_register->unique_id ||
162808e7378eSSreekanth Reddy 			    ioc->diag_buffer_sz[buffer_type] !=
162908e7378eSSreekanth Reddy 			    diag_register->requested_buffer_size ||
163008e7378eSSreekanth Reddy 			    !(ioc->diag_buffer_status[buffer_type] &
163108e7378eSSreekanth Reddy 			    MPT3_DIAG_BUFFER_IS_RELEASED)) {
163208e7378eSSreekanth Reddy 				ioc_err(ioc,
163308e7378eSSreekanth Reddy 				    "%s: already has a registered buffer for buffer_type(0x%02x)\n",
163408e7378eSSreekanth Reddy 				    __func__, buffer_type);
163508e7378eSSreekanth Reddy 				return -EINVAL;
163608e7378eSSreekanth Reddy 			}
163708e7378eSSreekanth Reddy 		} else {
1638919d8a3fSJoe Perches 			ioc_err(ioc, "%s: already has a registered buffer for buffer_type(0x%02x)\n",
1639919d8a3fSJoe Perches 			    __func__, buffer_type);
1640f92363d1SSreekanth Reddy 			return -EINVAL;
1641f92363d1SSreekanth Reddy 		}
1642a066f4c3SSreekanth Reddy 	} else if (ioc->diag_buffer_status[buffer_type] &
1643a066f4c3SSreekanth Reddy 	    MPT3_DIAG_BUFFER_IS_DRIVER_ALLOCATED) {
1644a066f4c3SSreekanth Reddy 
1645a066f4c3SSreekanth Reddy 		if (ioc->unique_id[buffer_type] != MPT3DIAGBUFFUNIQUEID ||
1646a066f4c3SSreekanth Reddy 		    ioc->diag_buffer_sz[buffer_type] !=
1647a066f4c3SSreekanth Reddy 		    diag_register->requested_buffer_size) {
1648a066f4c3SSreekanth Reddy 
1649a066f4c3SSreekanth Reddy 			ioc_err(ioc,
1650a066f4c3SSreekanth Reddy 			    "%s: already a buffer is allocated for buffer_type(0x%02x) of size %d bytes, so please try registering again with same size\n",
1651a066f4c3SSreekanth Reddy 			     __func__, buffer_type,
1652a066f4c3SSreekanth Reddy 			    ioc->diag_buffer_sz[buffer_type]);
1653a066f4c3SSreekanth Reddy 			return -EINVAL;
1654a066f4c3SSreekanth Reddy 		}
165508e7378eSSreekanth Reddy 	}
1656f92363d1SSreekanth Reddy 
1657f92363d1SSreekanth Reddy 	if (diag_register->requested_buffer_size % 4)  {
1658919d8a3fSJoe Perches 		ioc_err(ioc, "%s: the requested_buffer_size is not 4 byte aligned\n",
1659919d8a3fSJoe Perches 			__func__);
1660f92363d1SSreekanth Reddy 		return -EINVAL;
1661f92363d1SSreekanth Reddy 	}
1662f92363d1SSreekanth Reddy 
1663f92363d1SSreekanth Reddy 	smid = mpt3sas_base_get_smid(ioc, ioc->ctl_cb_idx);
1664f92363d1SSreekanth Reddy 	if (!smid) {
1665919d8a3fSJoe Perches 		ioc_err(ioc, "%s: failed obtaining a smid\n", __func__);
1666f92363d1SSreekanth Reddy 		rc = -EAGAIN;
1667f92363d1SSreekanth Reddy 		goto out;
1668f92363d1SSreekanth Reddy 	}
1669f92363d1SSreekanth Reddy 
1670f92363d1SSreekanth Reddy 	rc = 0;
1671f92363d1SSreekanth Reddy 	ioc->ctl_cmds.status = MPT3_CMD_PENDING;
1672f92363d1SSreekanth Reddy 	memset(ioc->ctl_cmds.reply, 0, ioc->reply_sz);
1673f92363d1SSreekanth Reddy 	mpi_request = mpt3sas_base_get_msg_frame(ioc, smid);
1674f92363d1SSreekanth Reddy 	ioc->ctl_cmds.smid = smid;
1675f92363d1SSreekanth Reddy 
1676f92363d1SSreekanth Reddy 	request_data = ioc->diag_buffer[buffer_type];
1677f92363d1SSreekanth Reddy 	request_data_sz = diag_register->requested_buffer_size;
1678f92363d1SSreekanth Reddy 	ioc->unique_id[buffer_type] = diag_register->unique_id;
1679a066f4c3SSreekanth Reddy 	ioc->diag_buffer_status[buffer_type] &=
1680a066f4c3SSreekanth Reddy 	    MPT3_DIAG_BUFFER_IS_DRIVER_ALLOCATED;
1681f92363d1SSreekanth Reddy 	memcpy(ioc->product_specific[buffer_type],
1682f92363d1SSreekanth Reddy 	    diag_register->product_specific, MPT3_PRODUCT_SPECIFIC_DWORDS);
1683f92363d1SSreekanth Reddy 	ioc->diagnostic_flags[buffer_type] = diag_register->diagnostic_flags;
1684f92363d1SSreekanth Reddy 
1685f92363d1SSreekanth Reddy 	if (request_data) {
1686f92363d1SSreekanth Reddy 		request_data_dma = ioc->diag_buffer_dma[buffer_type];
1687f92363d1SSreekanth Reddy 		if (request_data_sz != ioc->diag_buffer_sz[buffer_type]) {
16881c2048bdSChristoph Hellwig 			dma_free_coherent(&ioc->pdev->dev,
1689f92363d1SSreekanth Reddy 					ioc->diag_buffer_sz[buffer_type],
1690f92363d1SSreekanth Reddy 					request_data, request_data_dma);
1691f92363d1SSreekanth Reddy 			request_data = NULL;
1692f92363d1SSreekanth Reddy 		}
1693f92363d1SSreekanth Reddy 	}
1694f92363d1SSreekanth Reddy 
1695f92363d1SSreekanth Reddy 	if (request_data == NULL) {
1696f92363d1SSreekanth Reddy 		ioc->diag_buffer_sz[buffer_type] = 0;
1697f92363d1SSreekanth Reddy 		ioc->diag_buffer_dma[buffer_type] = 0;
16981c2048bdSChristoph Hellwig 		request_data = dma_alloc_coherent(&ioc->pdev->dev,
16991c2048bdSChristoph Hellwig 				request_data_sz, &request_data_dma, GFP_KERNEL);
1700f92363d1SSreekanth Reddy 		if (request_data == NULL) {
1701919d8a3fSJoe Perches 			ioc_err(ioc, "%s: failed allocating memory for diag buffers, requested size(%d)\n",
1702919d8a3fSJoe Perches 				__func__, request_data_sz);
1703f92363d1SSreekanth Reddy 			mpt3sas_base_free_smid(ioc, smid);
1704782b2818SSreekanth Reddy 			rc = -ENOMEM;
1705782b2818SSreekanth Reddy 			goto out;
1706f92363d1SSreekanth Reddy 		}
1707f92363d1SSreekanth Reddy 		ioc->diag_buffer[buffer_type] = request_data;
1708f92363d1SSreekanth Reddy 		ioc->diag_buffer_sz[buffer_type] = request_data_sz;
1709f92363d1SSreekanth Reddy 		ioc->diag_buffer_dma[buffer_type] = request_data_dma;
1710f92363d1SSreekanth Reddy 	}
1711f92363d1SSreekanth Reddy 
1712f92363d1SSreekanth Reddy 	mpi_request->Function = MPI2_FUNCTION_DIAG_BUFFER_POST;
1713f92363d1SSreekanth Reddy 	mpi_request->BufferType = diag_register->buffer_type;
1714f92363d1SSreekanth Reddy 	mpi_request->Flags = cpu_to_le32(diag_register->diagnostic_flags);
1715f92363d1SSreekanth Reddy 	mpi_request->BufferAddress = cpu_to_le64(request_data_dma);
1716f92363d1SSreekanth Reddy 	mpi_request->BufferLength = cpu_to_le32(request_data_sz);
1717f92363d1SSreekanth Reddy 	mpi_request->VF_ID = 0; /* TODO */
1718f92363d1SSreekanth Reddy 	mpi_request->VP_ID = 0;
1719f92363d1SSreekanth Reddy 
1720919d8a3fSJoe Perches 	dctlprintk(ioc,
1721919d8a3fSJoe Perches 		   ioc_info(ioc, "%s: diag_buffer(0x%p), dma(0x%llx), sz(%d)\n",
1722919d8a3fSJoe Perches 			    __func__, request_data,
1723f92363d1SSreekanth Reddy 			    (unsigned long long)request_data_dma,
1724f92363d1SSreekanth Reddy 			    le32_to_cpu(mpi_request->BufferLength)));
1725f92363d1SSreekanth Reddy 
1726f92363d1SSreekanth Reddy 	for (i = 0; i < MPT3_PRODUCT_SPECIFIC_DWORDS; i++)
1727f92363d1SSreekanth Reddy 		mpi_request->ProductSpecific[i] =
1728f92363d1SSreekanth Reddy 			cpu_to_le32(ioc->product_specific[buffer_type][i]);
1729f92363d1SSreekanth Reddy 
1730f92363d1SSreekanth Reddy 	init_completion(&ioc->ctl_cmds.done);
1731078a4cc1SSuganath Prabu S 	ioc->put_smid_default(ioc, smid);
17328bbb1cf6SCalvin Owens 	wait_for_completion_timeout(&ioc->ctl_cmds.done,
1733f92363d1SSreekanth Reddy 	    MPT3_IOCTL_DEFAULT_TIMEOUT*HZ);
1734f92363d1SSreekanth Reddy 
1735f92363d1SSreekanth Reddy 	if (!(ioc->ctl_cmds.status & MPT3_CMD_COMPLETE)) {
1736d37306caSChaitra P B 		issue_reset =
1737d37306caSChaitra P B 			mpt3sas_base_check_cmd_timeout(ioc,
1738d37306caSChaitra P B 				ioc->ctl_cmds.status, mpi_request,
1739f92363d1SSreekanth Reddy 				sizeof(Mpi2DiagBufferPostRequest_t)/4);
1740f92363d1SSreekanth Reddy 		goto issue_host_reset;
1741f92363d1SSreekanth Reddy 	}
1742f92363d1SSreekanth Reddy 
1743f92363d1SSreekanth Reddy 	/* process the completed Reply Message Frame */
1744f92363d1SSreekanth Reddy 	if ((ioc->ctl_cmds.status & MPT3_CMD_REPLY_VALID) == 0) {
1745919d8a3fSJoe Perches 		ioc_err(ioc, "%s: no reply message\n", __func__);
1746f92363d1SSreekanth Reddy 		rc = -EFAULT;
1747f92363d1SSreekanth Reddy 		goto out;
1748f92363d1SSreekanth Reddy 	}
1749f92363d1SSreekanth Reddy 
1750f92363d1SSreekanth Reddy 	mpi_reply = ioc->ctl_cmds.reply;
1751f92363d1SSreekanth Reddy 	ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
1752f92363d1SSreekanth Reddy 
1753f92363d1SSreekanth Reddy 	if (ioc_status == MPI2_IOCSTATUS_SUCCESS) {
1754f92363d1SSreekanth Reddy 		ioc->diag_buffer_status[buffer_type] |=
1755f92363d1SSreekanth Reddy 			MPT3_DIAG_BUFFER_IS_REGISTERED;
1756919d8a3fSJoe Perches 		dctlprintk(ioc, ioc_info(ioc, "%s: success\n", __func__));
1757f92363d1SSreekanth Reddy 	} else {
1758919d8a3fSJoe Perches 		ioc_info(ioc, "%s: ioc_status(0x%04x) log_info(0x%08x)\n",
1759919d8a3fSJoe Perches 			 __func__,
1760f92363d1SSreekanth Reddy 			 ioc_status, le32_to_cpu(mpi_reply->IOCLogInfo));
1761f92363d1SSreekanth Reddy 		rc = -EFAULT;
1762f92363d1SSreekanth Reddy 	}
1763f92363d1SSreekanth Reddy 
1764f92363d1SSreekanth Reddy  issue_host_reset:
1765f92363d1SSreekanth Reddy 	if (issue_reset)
176698c56ad3SCalvin Owens 		mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER);
1767f92363d1SSreekanth Reddy 
1768f92363d1SSreekanth Reddy  out:
1769f92363d1SSreekanth Reddy 
1770a066f4c3SSreekanth Reddy 	if (rc && request_data) {
17711c2048bdSChristoph Hellwig 		dma_free_coherent(&ioc->pdev->dev, request_data_sz,
1772f92363d1SSreekanth Reddy 		    request_data, request_data_dma);
1773a066f4c3SSreekanth Reddy 		ioc->diag_buffer_status[buffer_type] &=
1774a066f4c3SSreekanth Reddy 		    ~MPT3_DIAG_BUFFER_IS_DRIVER_ALLOCATED;
1775a066f4c3SSreekanth Reddy 	}
1776f92363d1SSreekanth Reddy 
1777f92363d1SSreekanth Reddy 	ioc->ctl_cmds.status = MPT3_CMD_NOT_USED;
1778f92363d1SSreekanth Reddy 	return rc;
1779f92363d1SSreekanth Reddy }
1780f92363d1SSreekanth Reddy 
1781f92363d1SSreekanth Reddy /**
1782f92363d1SSreekanth Reddy  * mpt3sas_enable_diag_buffer - enabling diag_buffers support driver load time
1783f92363d1SSreekanth Reddy  * @ioc: per adapter object
1784f92363d1SSreekanth Reddy  * @bits_to_register: bitwise field where trace is bit 0, and snapshot is bit 1
1785f92363d1SSreekanth Reddy  *
1786f92363d1SSreekanth Reddy  * This is called when command line option diag_buffer_enable is enabled
1787f92363d1SSreekanth Reddy  * at driver load time.
1788f92363d1SSreekanth Reddy  */
1789f92363d1SSreekanth Reddy void
1790f92363d1SSreekanth Reddy mpt3sas_enable_diag_buffer(struct MPT3SAS_ADAPTER *ioc, u8 bits_to_register)
1791f92363d1SSreekanth Reddy {
1792f92363d1SSreekanth Reddy 	struct mpt3_diag_register diag_register;
1793d04a6edfSSreekanth Reddy 	u32 ret_val;
1794d04a6edfSSreekanth Reddy 	u32 trace_buff_size = ioc->manu_pg11.HostTraceBufferMaxSizeKB<<10;
1795d04a6edfSSreekanth Reddy 	u32 min_trace_buff_size = 0;
1796d04a6edfSSreekanth Reddy 	u32 decr_trace_buff_size = 0;
1797f92363d1SSreekanth Reddy 
1798f92363d1SSreekanth Reddy 	memset(&diag_register, 0, sizeof(struct mpt3_diag_register));
1799f92363d1SSreekanth Reddy 
1800f92363d1SSreekanth Reddy 	if (bits_to_register & 1) {
1801919d8a3fSJoe Perches 		ioc_info(ioc, "registering trace buffer support\n");
1802f92363d1SSreekanth Reddy 		ioc->diag_trigger_master.MasterData =
1803f92363d1SSreekanth Reddy 		    (MASTER_TRIGGER_FW_FAULT + MASTER_TRIGGER_ADAPTER_RESET);
1804f92363d1SSreekanth Reddy 		diag_register.buffer_type = MPI2_DIAG_BUF_TYPE_TRACE;
180508e7378eSSreekanth Reddy 		diag_register.unique_id =
180608e7378eSSreekanth Reddy 		    (ioc->hba_mpi_version_belonged == MPI2_VERSION) ?
180708e7378eSSreekanth Reddy 		    (MPT2DIAGBUFFUNIQUEID):(MPT3DIAGBUFFUNIQUEID);
1808d04a6edfSSreekanth Reddy 
1809d04a6edfSSreekanth Reddy 		if (trace_buff_size != 0) {
1810d04a6edfSSreekanth Reddy 			diag_register.requested_buffer_size = trace_buff_size;
1811d04a6edfSSreekanth Reddy 			min_trace_buff_size =
1812d04a6edfSSreekanth Reddy 			    ioc->manu_pg11.HostTraceBufferMinSizeKB<<10;
1813d04a6edfSSreekanth Reddy 			decr_trace_buff_size =
1814d04a6edfSSreekanth Reddy 			    ioc->manu_pg11.HostTraceBufferDecrementSizeKB<<10;
1815d04a6edfSSreekanth Reddy 
1816d04a6edfSSreekanth Reddy 			if (min_trace_buff_size > trace_buff_size) {
1817d04a6edfSSreekanth Reddy 				/* The buff size is not set correctly */
1818d04a6edfSSreekanth Reddy 				ioc_err(ioc,
1819d04a6edfSSreekanth Reddy 				    "Min Trace Buff size (%d KB) greater than Max Trace Buff size (%d KB)\n",
1820d04a6edfSSreekanth Reddy 				     min_trace_buff_size>>10,
1821d04a6edfSSreekanth Reddy 				     trace_buff_size>>10);
1822d04a6edfSSreekanth Reddy 				ioc_err(ioc,
1823d04a6edfSSreekanth Reddy 				    "Using zero Min Trace Buff Size\n");
1824d04a6edfSSreekanth Reddy 				    min_trace_buff_size = 0;
1825d04a6edfSSreekanth Reddy 			}
1826d04a6edfSSreekanth Reddy 
1827d04a6edfSSreekanth Reddy 			if (decr_trace_buff_size == 0) {
1828d04a6edfSSreekanth Reddy 				/*
1829d04a6edfSSreekanth Reddy 				 * retry the min size if decrement
1830d04a6edfSSreekanth Reddy 				 * is not available.
1831d04a6edfSSreekanth Reddy 				 */
1832d04a6edfSSreekanth Reddy 				decr_trace_buff_size =
1833d04a6edfSSreekanth Reddy 				    trace_buff_size - min_trace_buff_size;
1834d04a6edfSSreekanth Reddy 			}
1835d04a6edfSSreekanth Reddy 		} else {
1836f92363d1SSreekanth Reddy 			/* register for 2MB buffers  */
1837f92363d1SSreekanth Reddy 			diag_register.requested_buffer_size = 2 * (1024 * 1024);
1838d04a6edfSSreekanth Reddy 		}
1839d04a6edfSSreekanth Reddy 
1840d04a6edfSSreekanth Reddy 		do {
1841d04a6edfSSreekanth Reddy 			ret_val = _ctl_diag_register_2(ioc,  &diag_register);
1842d04a6edfSSreekanth Reddy 
1843d04a6edfSSreekanth Reddy 			if (ret_val == -ENOMEM && min_trace_buff_size &&
1844d04a6edfSSreekanth Reddy 			    (trace_buff_size - decr_trace_buff_size) >=
1845d04a6edfSSreekanth Reddy 			    min_trace_buff_size) {
1846d04a6edfSSreekanth Reddy 				/* adjust the buffer size */
1847d04a6edfSSreekanth Reddy 				trace_buff_size -= decr_trace_buff_size;
1848d04a6edfSSreekanth Reddy 				diag_register.requested_buffer_size =
1849d04a6edfSSreekanth Reddy 				    trace_buff_size;
1850d04a6edfSSreekanth Reddy 			} else
1851d04a6edfSSreekanth Reddy 				break;
1852d04a6edfSSreekanth Reddy 		} while (true);
1853d04a6edfSSreekanth Reddy 
1854d04a6edfSSreekanth Reddy 		if (ret_val == -ENOMEM)
1855d04a6edfSSreekanth Reddy 			ioc_err(ioc,
1856d04a6edfSSreekanth Reddy 			    "Cannot allocate trace buffer memory. Last memory tried = %d KB\n",
1857d04a6edfSSreekanth Reddy 			    diag_register.requested_buffer_size>>10);
1858d04a6edfSSreekanth Reddy 		else if (ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE]
1859a066f4c3SSreekanth Reddy 		    & MPT3_DIAG_BUFFER_IS_REGISTERED) {
1860d04a6edfSSreekanth Reddy 			ioc_err(ioc, "Trace buffer memory %d KB allocated\n",
1861d04a6edfSSreekanth Reddy 			    diag_register.requested_buffer_size>>10);
1862a066f4c3SSreekanth Reddy 			if (ioc->hba_mpi_version_belonged != MPI2_VERSION)
1863a066f4c3SSreekanth Reddy 				ioc->diag_buffer_status[
1864a066f4c3SSreekanth Reddy 				    MPI2_DIAG_BUF_TYPE_TRACE] |=
1865a066f4c3SSreekanth Reddy 				    MPT3_DIAG_BUFFER_IS_DRIVER_ALLOCATED;
1866a066f4c3SSreekanth Reddy 		}
1867f92363d1SSreekanth Reddy 	}
1868f92363d1SSreekanth Reddy 
1869f92363d1SSreekanth Reddy 	if (bits_to_register & 2) {
1870919d8a3fSJoe Perches 		ioc_info(ioc, "registering snapshot buffer support\n");
1871f92363d1SSreekanth Reddy 		diag_register.buffer_type = MPI2_DIAG_BUF_TYPE_SNAPSHOT;
1872f92363d1SSreekanth Reddy 		/* register for 2MB buffers  */
1873f92363d1SSreekanth Reddy 		diag_register.requested_buffer_size = 2 * (1024 * 1024);
1874f92363d1SSreekanth Reddy 		diag_register.unique_id = 0x7075901;
1875f92363d1SSreekanth Reddy 		_ctl_diag_register_2(ioc,  &diag_register);
1876f92363d1SSreekanth Reddy 	}
1877f92363d1SSreekanth Reddy 
1878f92363d1SSreekanth Reddy 	if (bits_to_register & 4) {
1879919d8a3fSJoe Perches 		ioc_info(ioc, "registering extended buffer support\n");
1880f92363d1SSreekanth Reddy 		diag_register.buffer_type = MPI2_DIAG_BUF_TYPE_EXTENDED;
1881f92363d1SSreekanth Reddy 		/* register for 2MB buffers  */
1882f92363d1SSreekanth Reddy 		diag_register.requested_buffer_size = 2 * (1024 * 1024);
1883f92363d1SSreekanth Reddy 		diag_register.unique_id = 0x7075901;
1884f92363d1SSreekanth Reddy 		_ctl_diag_register_2(ioc,  &diag_register);
1885f92363d1SSreekanth Reddy 	}
1886f92363d1SSreekanth Reddy }
1887f92363d1SSreekanth Reddy 
1888f92363d1SSreekanth Reddy /**
1889f92363d1SSreekanth Reddy  * _ctl_diag_register - application register with driver
1890f92363d1SSreekanth Reddy  * @ioc: per adapter object
18914beb4867SBart Van Assche  * @arg: user space buffer containing ioctl content
1892f92363d1SSreekanth Reddy  *
1893f92363d1SSreekanth Reddy  * This will allow the driver to setup any required buffers that will be
1894f92363d1SSreekanth Reddy  * needed by firmware to communicate with the driver.
1895f92363d1SSreekanth Reddy  */
1896f92363d1SSreekanth Reddy static long
1897f92363d1SSreekanth Reddy _ctl_diag_register(struct MPT3SAS_ADAPTER *ioc, void __user *arg)
1898f92363d1SSreekanth Reddy {
1899f92363d1SSreekanth Reddy 	struct mpt3_diag_register karg;
1900f92363d1SSreekanth Reddy 	long rc;
1901f92363d1SSreekanth Reddy 
1902f92363d1SSreekanth Reddy 	if (copy_from_user(&karg, arg, sizeof(karg))) {
1903f92363d1SSreekanth Reddy 		pr_err("failure at %s:%d/%s()!\n",
1904f92363d1SSreekanth Reddy 		    __FILE__, __LINE__, __func__);
1905f92363d1SSreekanth Reddy 		return -EFAULT;
1906f92363d1SSreekanth Reddy 	}
1907f92363d1SSreekanth Reddy 
1908f92363d1SSreekanth Reddy 	rc = _ctl_diag_register_2(ioc, &karg);
1909a8a6cbcdSSreekanth Reddy 
1910a8a6cbcdSSreekanth Reddy 	if (!rc && (ioc->diag_buffer_status[karg.buffer_type] &
1911a8a6cbcdSSreekanth Reddy 	    MPT3_DIAG_BUFFER_IS_REGISTERED))
1912a8a6cbcdSSreekanth Reddy 		ioc->diag_buffer_status[karg.buffer_type] |=
1913a8a6cbcdSSreekanth Reddy 		    MPT3_DIAG_BUFFER_IS_APP_OWNED;
1914a8a6cbcdSSreekanth Reddy 
1915f92363d1SSreekanth Reddy 	return rc;
1916f92363d1SSreekanth Reddy }
1917f92363d1SSreekanth Reddy 
1918f92363d1SSreekanth Reddy /**
1919f92363d1SSreekanth Reddy  * _ctl_diag_unregister - application unregister with driver
1920f92363d1SSreekanth Reddy  * @ioc: per adapter object
19214beb4867SBart Van Assche  * @arg: user space buffer containing ioctl content
1922f92363d1SSreekanth Reddy  *
1923f92363d1SSreekanth Reddy  * This will allow the driver to cleanup any memory allocated for diag
1924f92363d1SSreekanth Reddy  * messages and to free up any resources.
1925f92363d1SSreekanth Reddy  */
1926f92363d1SSreekanth Reddy static long
1927f92363d1SSreekanth Reddy _ctl_diag_unregister(struct MPT3SAS_ADAPTER *ioc, void __user *arg)
1928f92363d1SSreekanth Reddy {
1929f92363d1SSreekanth Reddy 	struct mpt3_diag_unregister karg;
1930f92363d1SSreekanth Reddy 	void *request_data;
1931f92363d1SSreekanth Reddy 	dma_addr_t request_data_dma;
1932f92363d1SSreekanth Reddy 	u32 request_data_sz;
1933f92363d1SSreekanth Reddy 	u8 buffer_type;
1934f92363d1SSreekanth Reddy 
1935f92363d1SSreekanth Reddy 	if (copy_from_user(&karg, arg, sizeof(karg))) {
1936f92363d1SSreekanth Reddy 		pr_err("failure at %s:%d/%s()!\n",
1937f92363d1SSreekanth Reddy 		    __FILE__, __LINE__, __func__);
1938f92363d1SSreekanth Reddy 		return -EFAULT;
1939f92363d1SSreekanth Reddy 	}
1940f92363d1SSreekanth Reddy 
1941919d8a3fSJoe Perches 	dctlprintk(ioc, ioc_info(ioc, "%s\n",
1942f92363d1SSreekanth Reddy 				 __func__));
1943f92363d1SSreekanth Reddy 
194408e7378eSSreekanth Reddy 	buffer_type = _ctl_diag_get_bufftype(ioc, karg.unique_id);
194508e7378eSSreekanth Reddy 	if (buffer_type == MPT3_DIAG_UID_NOT_FOUND) {
194608e7378eSSreekanth Reddy 		ioc_err(ioc, "%s: buffer with unique_id(0x%08x) not found\n",
194708e7378eSSreekanth Reddy 		    __func__, karg.unique_id);
194808e7378eSSreekanth Reddy 		return -EINVAL;
194908e7378eSSreekanth Reddy 	}
195008e7378eSSreekanth Reddy 
1951f92363d1SSreekanth Reddy 	if (!_ctl_diag_capability(ioc, buffer_type)) {
1952919d8a3fSJoe Perches 		ioc_err(ioc, "%s: doesn't have capability for buffer_type(0x%02x)\n",
1953919d8a3fSJoe Perches 			__func__, buffer_type);
1954f92363d1SSreekanth Reddy 		return -EPERM;
1955f92363d1SSreekanth Reddy 	}
1956f92363d1SSreekanth Reddy 
1957f92363d1SSreekanth Reddy 	if ((ioc->diag_buffer_status[buffer_type] &
1958f92363d1SSreekanth Reddy 	    MPT3_DIAG_BUFFER_IS_REGISTERED) == 0) {
1959919d8a3fSJoe Perches 		ioc_err(ioc, "%s: buffer_type(0x%02x) is not registered\n",
1960919d8a3fSJoe Perches 			__func__, buffer_type);
1961f92363d1SSreekanth Reddy 		return -EINVAL;
1962f92363d1SSreekanth Reddy 	}
1963f92363d1SSreekanth Reddy 	if ((ioc->diag_buffer_status[buffer_type] &
1964f92363d1SSreekanth Reddy 	    MPT3_DIAG_BUFFER_IS_RELEASED) == 0) {
1965919d8a3fSJoe Perches 		ioc_err(ioc, "%s: buffer_type(0x%02x) has not been released\n",
1966919d8a3fSJoe Perches 			__func__, buffer_type);
1967f92363d1SSreekanth Reddy 		return -EINVAL;
1968f92363d1SSreekanth Reddy 	}
1969f92363d1SSreekanth Reddy 
1970f92363d1SSreekanth Reddy 	if (karg.unique_id != ioc->unique_id[buffer_type]) {
1971919d8a3fSJoe Perches 		ioc_err(ioc, "%s: unique_id(0x%08x) is not registered\n",
1972919d8a3fSJoe Perches 			__func__, karg.unique_id);
1973f92363d1SSreekanth Reddy 		return -EINVAL;
1974f92363d1SSreekanth Reddy 	}
1975f92363d1SSreekanth Reddy 
1976f92363d1SSreekanth Reddy 	request_data = ioc->diag_buffer[buffer_type];
1977f92363d1SSreekanth Reddy 	if (!request_data) {
1978919d8a3fSJoe Perches 		ioc_err(ioc, "%s: doesn't have memory allocated for buffer_type(0x%02x)\n",
1979919d8a3fSJoe Perches 			__func__, buffer_type);
1980f92363d1SSreekanth Reddy 		return -ENOMEM;
1981f92363d1SSreekanth Reddy 	}
1982f92363d1SSreekanth Reddy 
1983a066f4c3SSreekanth Reddy 	if (ioc->diag_buffer_status[buffer_type] &
1984a066f4c3SSreekanth Reddy 	    MPT3_DIAG_BUFFER_IS_DRIVER_ALLOCATED) {
1985a066f4c3SSreekanth Reddy 		ioc->unique_id[buffer_type] = MPT3DIAGBUFFUNIQUEID;
1986a066f4c3SSreekanth Reddy 		ioc->diag_buffer_status[buffer_type] &=
1987a8a6cbcdSSreekanth Reddy 		    ~MPT3_DIAG_BUFFER_IS_APP_OWNED;
1988a8a6cbcdSSreekanth Reddy 		ioc->diag_buffer_status[buffer_type] &=
1989a066f4c3SSreekanth Reddy 		    ~MPT3_DIAG_BUFFER_IS_REGISTERED;
1990a066f4c3SSreekanth Reddy 	} else {
1991f92363d1SSreekanth Reddy 		request_data_sz = ioc->diag_buffer_sz[buffer_type];
1992f92363d1SSreekanth Reddy 		request_data_dma = ioc->diag_buffer_dma[buffer_type];
19931c2048bdSChristoph Hellwig 		dma_free_coherent(&ioc->pdev->dev, request_data_sz,
1994f92363d1SSreekanth Reddy 				request_data, request_data_dma);
1995f92363d1SSreekanth Reddy 		ioc->diag_buffer[buffer_type] = NULL;
1996f92363d1SSreekanth Reddy 		ioc->diag_buffer_status[buffer_type] = 0;
1997a066f4c3SSreekanth Reddy 	}
1998f92363d1SSreekanth Reddy 	return 0;
1999f92363d1SSreekanth Reddy }
2000f92363d1SSreekanth Reddy 
2001f92363d1SSreekanth Reddy /**
2002f92363d1SSreekanth Reddy  * _ctl_diag_query - query relevant info associated with diag buffers
2003f92363d1SSreekanth Reddy  * @ioc: per adapter object
20044beb4867SBart Van Assche  * @arg: user space buffer containing ioctl content
2005f92363d1SSreekanth Reddy  *
2006f92363d1SSreekanth Reddy  * The application will send only buffer_type and unique_id.  Driver will
2007f92363d1SSreekanth Reddy  * inspect unique_id first, if valid, fill in all the info.  If unique_id is
2008f92363d1SSreekanth Reddy  * 0x00, the driver will return info specified by Buffer Type.
2009f92363d1SSreekanth Reddy  */
2010f92363d1SSreekanth Reddy static long
2011f92363d1SSreekanth Reddy _ctl_diag_query(struct MPT3SAS_ADAPTER *ioc, void __user *arg)
2012f92363d1SSreekanth Reddy {
2013f92363d1SSreekanth Reddy 	struct mpt3_diag_query karg;
2014f92363d1SSreekanth Reddy 	void *request_data;
2015f92363d1SSreekanth Reddy 	int i;
2016f92363d1SSreekanth Reddy 	u8 buffer_type;
2017f92363d1SSreekanth Reddy 
2018f92363d1SSreekanth Reddy 	if (copy_from_user(&karg, arg, sizeof(karg))) {
2019f92363d1SSreekanth Reddy 		pr_err("failure at %s:%d/%s()!\n",
2020f92363d1SSreekanth Reddy 		    __FILE__, __LINE__, __func__);
2021f92363d1SSreekanth Reddy 		return -EFAULT;
2022f92363d1SSreekanth Reddy 	}
2023f92363d1SSreekanth Reddy 
2024919d8a3fSJoe Perches 	dctlprintk(ioc, ioc_info(ioc, "%s\n",
2025f92363d1SSreekanth Reddy 				 __func__));
2026f92363d1SSreekanth Reddy 
2027f92363d1SSreekanth Reddy 	karg.application_flags = 0;
2028f92363d1SSreekanth Reddy 	buffer_type = karg.buffer_type;
2029f92363d1SSreekanth Reddy 
2030f92363d1SSreekanth Reddy 	if (!_ctl_diag_capability(ioc, buffer_type)) {
2031919d8a3fSJoe Perches 		ioc_err(ioc, "%s: doesn't have capability for buffer_type(0x%02x)\n",
2032919d8a3fSJoe Perches 			__func__, buffer_type);
2033f92363d1SSreekanth Reddy 		return -EPERM;
2034f92363d1SSreekanth Reddy 	}
2035f92363d1SSreekanth Reddy 
2036a066f4c3SSreekanth Reddy 	if (!(ioc->diag_buffer_status[buffer_type] &
2037a066f4c3SSreekanth Reddy 	    MPT3_DIAG_BUFFER_IS_DRIVER_ALLOCATED)) {
2038f92363d1SSreekanth Reddy 		if ((ioc->diag_buffer_status[buffer_type] &
2039f92363d1SSreekanth Reddy 		    MPT3_DIAG_BUFFER_IS_REGISTERED) == 0) {
2040919d8a3fSJoe Perches 			ioc_err(ioc, "%s: buffer_type(0x%02x) is not registered\n",
2041919d8a3fSJoe Perches 				__func__, buffer_type);
2042f92363d1SSreekanth Reddy 			return -EINVAL;
2043f92363d1SSreekanth Reddy 		}
2044a066f4c3SSreekanth Reddy 	}
2045f92363d1SSreekanth Reddy 
204608e7378eSSreekanth Reddy 	if (karg.unique_id) {
2047f92363d1SSreekanth Reddy 		if (karg.unique_id != ioc->unique_id[buffer_type]) {
2048919d8a3fSJoe Perches 			ioc_err(ioc, "%s: unique_id(0x%08x) is not registered\n",
2049919d8a3fSJoe Perches 				__func__, karg.unique_id);
2050f92363d1SSreekanth Reddy 			return -EINVAL;
2051f92363d1SSreekanth Reddy 		}
2052f92363d1SSreekanth Reddy 	}
2053f92363d1SSreekanth Reddy 
2054f92363d1SSreekanth Reddy 	request_data = ioc->diag_buffer[buffer_type];
2055f92363d1SSreekanth Reddy 	if (!request_data) {
2056919d8a3fSJoe Perches 		ioc_err(ioc, "%s: doesn't have buffer for buffer_type(0x%02x)\n",
2057919d8a3fSJoe Perches 			__func__, buffer_type);
2058f92363d1SSreekanth Reddy 		return -ENOMEM;
2059f92363d1SSreekanth Reddy 	}
2060f92363d1SSreekanth Reddy 
2061a066f4c3SSreekanth Reddy 	if ((ioc->diag_buffer_status[buffer_type] &
2062a066f4c3SSreekanth Reddy 	    MPT3_DIAG_BUFFER_IS_REGISTERED))
2063a066f4c3SSreekanth Reddy 		karg.application_flags |= MPT3_APP_FLAGS_BUFFER_VALID;
2064a066f4c3SSreekanth Reddy 
2065a066f4c3SSreekanth Reddy 	if (!(ioc->diag_buffer_status[buffer_type] &
2066a066f4c3SSreekanth Reddy 	     MPT3_DIAG_BUFFER_IS_RELEASED))
2067a066f4c3SSreekanth Reddy 		karg.application_flags |= MPT3_APP_FLAGS_FW_BUFFER_ACCESS;
2068a066f4c3SSreekanth Reddy 
2069a066f4c3SSreekanth Reddy 	if (!(ioc->diag_buffer_status[buffer_type] &
2070a066f4c3SSreekanth Reddy 	    MPT3_DIAG_BUFFER_IS_DRIVER_ALLOCATED))
2071a066f4c3SSreekanth Reddy 		karg.application_flags |= MPT3_APP_FLAGS_DYNAMIC_BUFFER_ALLOC;
2072f92363d1SSreekanth Reddy 
2073a8a6cbcdSSreekanth Reddy 	if ((ioc->diag_buffer_status[buffer_type] &
2074a8a6cbcdSSreekanth Reddy 	    MPT3_DIAG_BUFFER_IS_APP_OWNED))
2075a8a6cbcdSSreekanth Reddy 		karg.application_flags |= MPT3_APP_FLAGS_APP_OWNED;
2076a8a6cbcdSSreekanth Reddy 
2077f92363d1SSreekanth Reddy 	for (i = 0; i < MPT3_PRODUCT_SPECIFIC_DWORDS; i++)
2078f92363d1SSreekanth Reddy 		karg.product_specific[i] =
2079f92363d1SSreekanth Reddy 		    ioc->product_specific[buffer_type][i];
2080f92363d1SSreekanth Reddy 
2081f92363d1SSreekanth Reddy 	karg.total_buffer_size = ioc->diag_buffer_sz[buffer_type];
2082f92363d1SSreekanth Reddy 	karg.driver_added_buffer_size = 0;
2083f92363d1SSreekanth Reddy 	karg.unique_id = ioc->unique_id[buffer_type];
2084f92363d1SSreekanth Reddy 	karg.diagnostic_flags = ioc->diagnostic_flags[buffer_type];
2085f92363d1SSreekanth Reddy 
2086f92363d1SSreekanth Reddy 	if (copy_to_user(arg, &karg, sizeof(struct mpt3_diag_query))) {
2087919d8a3fSJoe Perches 		ioc_err(ioc, "%s: unable to write mpt3_diag_query data @ %p\n",
2088919d8a3fSJoe Perches 			__func__, arg);
2089f92363d1SSreekanth Reddy 		return -EFAULT;
2090f92363d1SSreekanth Reddy 	}
2091f92363d1SSreekanth Reddy 	return 0;
2092f92363d1SSreekanth Reddy }
2093f92363d1SSreekanth Reddy 
2094f92363d1SSreekanth Reddy /**
2095f92363d1SSreekanth Reddy  * mpt3sas_send_diag_release - Diag Release Message
2096f92363d1SSreekanth Reddy  * @ioc: per adapter object
20974beb4867SBart Van Assche  * @buffer_type: specifies either TRACE, SNAPSHOT, or EXTENDED
20984beb4867SBart Van Assche  * @issue_reset: specifies whether host reset is required.
2099f92363d1SSreekanth Reddy  *
2100f92363d1SSreekanth Reddy  */
2101f92363d1SSreekanth Reddy int
2102f92363d1SSreekanth Reddy mpt3sas_send_diag_release(struct MPT3SAS_ADAPTER *ioc, u8 buffer_type,
2103f92363d1SSreekanth Reddy 	u8 *issue_reset)
2104f92363d1SSreekanth Reddy {
2105f92363d1SSreekanth Reddy 	Mpi2DiagReleaseRequest_t *mpi_request;
2106f92363d1SSreekanth Reddy 	Mpi2DiagReleaseReply_t *mpi_reply;
2107f92363d1SSreekanth Reddy 	u16 smid;
2108f92363d1SSreekanth Reddy 	u16 ioc_status;
2109f92363d1SSreekanth Reddy 	u32 ioc_state;
2110f92363d1SSreekanth Reddy 	int rc;
2111f92363d1SSreekanth Reddy 
2112919d8a3fSJoe Perches 	dctlprintk(ioc, ioc_info(ioc, "%s\n",
2113f92363d1SSreekanth Reddy 				 __func__));
2114f92363d1SSreekanth Reddy 
2115f92363d1SSreekanth Reddy 	rc = 0;
2116f92363d1SSreekanth Reddy 	*issue_reset = 0;
2117f92363d1SSreekanth Reddy 
2118f92363d1SSreekanth Reddy 	ioc_state = mpt3sas_base_get_iocstate(ioc, 1);
2119f92363d1SSreekanth Reddy 	if (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
2120f92363d1SSreekanth Reddy 		if (ioc->diag_buffer_status[buffer_type] &
2121f92363d1SSreekanth Reddy 		    MPT3_DIAG_BUFFER_IS_REGISTERED)
2122f92363d1SSreekanth Reddy 			ioc->diag_buffer_status[buffer_type] |=
2123f92363d1SSreekanth Reddy 			    MPT3_DIAG_BUFFER_IS_RELEASED;
2124919d8a3fSJoe Perches 		dctlprintk(ioc,
2125919d8a3fSJoe Perches 			   ioc_info(ioc, "%s: skipping due to FAULT state\n",
2126f92363d1SSreekanth Reddy 				    __func__));
2127f92363d1SSreekanth Reddy 		rc = -EAGAIN;
2128f92363d1SSreekanth Reddy 		goto out;
2129f92363d1SSreekanth Reddy 	}
2130f92363d1SSreekanth Reddy 
2131f92363d1SSreekanth Reddy 	if (ioc->ctl_cmds.status != MPT3_CMD_NOT_USED) {
2132919d8a3fSJoe Perches 		ioc_err(ioc, "%s: ctl_cmd in use\n", __func__);
2133f92363d1SSreekanth Reddy 		rc = -EAGAIN;
2134f92363d1SSreekanth Reddy 		goto out;
2135f92363d1SSreekanth Reddy 	}
2136f92363d1SSreekanth Reddy 
2137f92363d1SSreekanth Reddy 	smid = mpt3sas_base_get_smid(ioc, ioc->ctl_cb_idx);
2138f92363d1SSreekanth Reddy 	if (!smid) {
2139919d8a3fSJoe Perches 		ioc_err(ioc, "%s: failed obtaining a smid\n", __func__);
2140f92363d1SSreekanth Reddy 		rc = -EAGAIN;
2141f92363d1SSreekanth Reddy 		goto out;
2142f92363d1SSreekanth Reddy 	}
2143f92363d1SSreekanth Reddy 
2144f92363d1SSreekanth Reddy 	ioc->ctl_cmds.status = MPT3_CMD_PENDING;
2145f92363d1SSreekanth Reddy 	memset(ioc->ctl_cmds.reply, 0, ioc->reply_sz);
2146f92363d1SSreekanth Reddy 	mpi_request = mpt3sas_base_get_msg_frame(ioc, smid);
2147f92363d1SSreekanth Reddy 	ioc->ctl_cmds.smid = smid;
2148f92363d1SSreekanth Reddy 
2149f92363d1SSreekanth Reddy 	mpi_request->Function = MPI2_FUNCTION_DIAG_RELEASE;
2150f92363d1SSreekanth Reddy 	mpi_request->BufferType = buffer_type;
2151f92363d1SSreekanth Reddy 	mpi_request->VF_ID = 0; /* TODO */
2152f92363d1SSreekanth Reddy 	mpi_request->VP_ID = 0;
2153f92363d1SSreekanth Reddy 
2154f92363d1SSreekanth Reddy 	init_completion(&ioc->ctl_cmds.done);
2155078a4cc1SSuganath Prabu S 	ioc->put_smid_default(ioc, smid);
21568bbb1cf6SCalvin Owens 	wait_for_completion_timeout(&ioc->ctl_cmds.done,
2157f92363d1SSreekanth Reddy 	    MPT3_IOCTL_DEFAULT_TIMEOUT*HZ);
2158f92363d1SSreekanth Reddy 
2159f92363d1SSreekanth Reddy 	if (!(ioc->ctl_cmds.status & MPT3_CMD_COMPLETE)) {
2160d37306caSChaitra P B 		*issue_reset = mpt3sas_base_check_cmd_timeout(ioc,
2161d37306caSChaitra P B 				ioc->ctl_cmds.status, mpi_request,
2162f92363d1SSreekanth Reddy 				sizeof(Mpi2DiagReleaseRequest_t)/4);
2163f92363d1SSreekanth Reddy 		rc = -EFAULT;
2164f92363d1SSreekanth Reddy 		goto out;
2165f92363d1SSreekanth Reddy 	}
2166f92363d1SSreekanth Reddy 
2167f92363d1SSreekanth Reddy 	/* process the completed Reply Message Frame */
2168f92363d1SSreekanth Reddy 	if ((ioc->ctl_cmds.status & MPT3_CMD_REPLY_VALID) == 0) {
2169919d8a3fSJoe Perches 		ioc_err(ioc, "%s: no reply message\n", __func__);
2170f92363d1SSreekanth Reddy 		rc = -EFAULT;
2171f92363d1SSreekanth Reddy 		goto out;
2172f92363d1SSreekanth Reddy 	}
2173f92363d1SSreekanth Reddy 
2174f92363d1SSreekanth Reddy 	mpi_reply = ioc->ctl_cmds.reply;
2175f92363d1SSreekanth Reddy 	ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
2176f92363d1SSreekanth Reddy 
2177f92363d1SSreekanth Reddy 	if (ioc_status == MPI2_IOCSTATUS_SUCCESS) {
2178f92363d1SSreekanth Reddy 		ioc->diag_buffer_status[buffer_type] |=
2179f92363d1SSreekanth Reddy 		    MPT3_DIAG_BUFFER_IS_RELEASED;
2180919d8a3fSJoe Perches 		dctlprintk(ioc, ioc_info(ioc, "%s: success\n", __func__));
2181f92363d1SSreekanth Reddy 	} else {
2182919d8a3fSJoe Perches 		ioc_info(ioc, "%s: ioc_status(0x%04x) log_info(0x%08x)\n",
2183919d8a3fSJoe Perches 			 __func__,
2184f92363d1SSreekanth Reddy 			 ioc_status, le32_to_cpu(mpi_reply->IOCLogInfo));
2185f92363d1SSreekanth Reddy 		rc = -EFAULT;
2186f92363d1SSreekanth Reddy 	}
2187f92363d1SSreekanth Reddy 
2188f92363d1SSreekanth Reddy  out:
2189f92363d1SSreekanth Reddy 	ioc->ctl_cmds.status = MPT3_CMD_NOT_USED;
2190f92363d1SSreekanth Reddy 	return rc;
2191f92363d1SSreekanth Reddy }
2192f92363d1SSreekanth Reddy 
2193f92363d1SSreekanth Reddy /**
2194f92363d1SSreekanth Reddy  * _ctl_diag_release - request to send Diag Release Message to firmware
21954beb4867SBart Van Assche  * @ioc: ?
21964beb4867SBart Van Assche  * @arg: user space buffer containing ioctl content
2197f92363d1SSreekanth Reddy  *
2198f92363d1SSreekanth Reddy  * This allows ownership of the specified buffer to returned to the driver,
2199f92363d1SSreekanth Reddy  * allowing an application to read the buffer without fear that firmware is
22009a284e5cSMasahiro Yamada  * overwriting information in the buffer.
2201f92363d1SSreekanth Reddy  */
2202f92363d1SSreekanth Reddy static long
2203f92363d1SSreekanth Reddy _ctl_diag_release(struct MPT3SAS_ADAPTER *ioc, void __user *arg)
2204f92363d1SSreekanth Reddy {
2205f92363d1SSreekanth Reddy 	struct mpt3_diag_release karg;
2206f92363d1SSreekanth Reddy 	void *request_data;
2207f92363d1SSreekanth Reddy 	int rc;
2208f92363d1SSreekanth Reddy 	u8 buffer_type;
2209f92363d1SSreekanth Reddy 	u8 issue_reset = 0;
2210f92363d1SSreekanth Reddy 
2211f92363d1SSreekanth Reddy 	if (copy_from_user(&karg, arg, sizeof(karg))) {
2212f92363d1SSreekanth Reddy 		pr_err("failure at %s:%d/%s()!\n",
2213f92363d1SSreekanth Reddy 		    __FILE__, __LINE__, __func__);
2214f92363d1SSreekanth Reddy 		return -EFAULT;
2215f92363d1SSreekanth Reddy 	}
2216f92363d1SSreekanth Reddy 
2217919d8a3fSJoe Perches 	dctlprintk(ioc, ioc_info(ioc, "%s\n",
2218f92363d1SSreekanth Reddy 				 __func__));
2219f92363d1SSreekanth Reddy 
222008e7378eSSreekanth Reddy 	buffer_type = _ctl_diag_get_bufftype(ioc, karg.unique_id);
222108e7378eSSreekanth Reddy 	if (buffer_type == MPT3_DIAG_UID_NOT_FOUND) {
222208e7378eSSreekanth Reddy 		ioc_err(ioc, "%s: buffer with unique_id(0x%08x) not found\n",
222308e7378eSSreekanth Reddy 		    __func__, karg.unique_id);
222408e7378eSSreekanth Reddy 		return -EINVAL;
222508e7378eSSreekanth Reddy 	}
222608e7378eSSreekanth Reddy 
2227f92363d1SSreekanth Reddy 	if (!_ctl_diag_capability(ioc, buffer_type)) {
2228919d8a3fSJoe Perches 		ioc_err(ioc, "%s: doesn't have capability for buffer_type(0x%02x)\n",
2229919d8a3fSJoe Perches 			__func__, buffer_type);
2230f92363d1SSreekanth Reddy 		return -EPERM;
2231f92363d1SSreekanth Reddy 	}
2232f92363d1SSreekanth Reddy 
2233f92363d1SSreekanth Reddy 	if ((ioc->diag_buffer_status[buffer_type] &
2234f92363d1SSreekanth Reddy 	    MPT3_DIAG_BUFFER_IS_REGISTERED) == 0) {
2235919d8a3fSJoe Perches 		ioc_err(ioc, "%s: buffer_type(0x%02x) is not registered\n",
2236919d8a3fSJoe Perches 			__func__, buffer_type);
2237f92363d1SSreekanth Reddy 		return -EINVAL;
2238f92363d1SSreekanth Reddy 	}
2239f92363d1SSreekanth Reddy 
2240f92363d1SSreekanth Reddy 	if (karg.unique_id != ioc->unique_id[buffer_type]) {
2241919d8a3fSJoe Perches 		ioc_err(ioc, "%s: unique_id(0x%08x) is not registered\n",
2242919d8a3fSJoe Perches 			__func__, karg.unique_id);
2243f92363d1SSreekanth Reddy 		return -EINVAL;
2244f92363d1SSreekanth Reddy 	}
2245f92363d1SSreekanth Reddy 
2246f92363d1SSreekanth Reddy 	if (ioc->diag_buffer_status[buffer_type] &
2247f92363d1SSreekanth Reddy 	    MPT3_DIAG_BUFFER_IS_RELEASED) {
2248919d8a3fSJoe Perches 		ioc_err(ioc, "%s: buffer_type(0x%02x) is already released\n",
2249919d8a3fSJoe Perches 			__func__, buffer_type);
225029f571f8SSreekanth Reddy 		return -EINVAL;
2251f92363d1SSreekanth Reddy 	}
2252f92363d1SSreekanth Reddy 
2253f92363d1SSreekanth Reddy 	request_data = ioc->diag_buffer[buffer_type];
2254f92363d1SSreekanth Reddy 
2255f92363d1SSreekanth Reddy 	if (!request_data) {
2256919d8a3fSJoe Perches 		ioc_err(ioc, "%s: doesn't have memory allocated for buffer_type(0x%02x)\n",
2257919d8a3fSJoe Perches 			__func__, buffer_type);
2258f92363d1SSreekanth Reddy 		return -ENOMEM;
2259f92363d1SSreekanth Reddy 	}
2260f92363d1SSreekanth Reddy 
2261f92363d1SSreekanth Reddy 	/* buffers were released by due to host reset */
2262f92363d1SSreekanth Reddy 	if ((ioc->diag_buffer_status[buffer_type] &
2263f92363d1SSreekanth Reddy 	    MPT3_DIAG_BUFFER_IS_DIAG_RESET)) {
2264f92363d1SSreekanth Reddy 		ioc->diag_buffer_status[buffer_type] |=
2265f92363d1SSreekanth Reddy 		    MPT3_DIAG_BUFFER_IS_RELEASED;
2266f92363d1SSreekanth Reddy 		ioc->diag_buffer_status[buffer_type] &=
2267f92363d1SSreekanth Reddy 		    ~MPT3_DIAG_BUFFER_IS_DIAG_RESET;
2268919d8a3fSJoe Perches 		ioc_err(ioc, "%s: buffer_type(0x%02x) was released due to host reset\n",
2269919d8a3fSJoe Perches 			__func__, buffer_type);
2270f92363d1SSreekanth Reddy 		return 0;
2271f92363d1SSreekanth Reddy 	}
2272f92363d1SSreekanth Reddy 
2273f92363d1SSreekanth Reddy 	rc = mpt3sas_send_diag_release(ioc, buffer_type, &issue_reset);
2274f92363d1SSreekanth Reddy 
2275f92363d1SSreekanth Reddy 	if (issue_reset)
227698c56ad3SCalvin Owens 		mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER);
2277f92363d1SSreekanth Reddy 
2278f92363d1SSreekanth Reddy 	return rc;
2279f92363d1SSreekanth Reddy }
2280f92363d1SSreekanth Reddy 
2281f92363d1SSreekanth Reddy /**
2282f92363d1SSreekanth Reddy  * _ctl_diag_read_buffer - request for copy of the diag buffer
2283f92363d1SSreekanth Reddy  * @ioc: per adapter object
22844beb4867SBart Van Assche  * @arg: user space buffer containing ioctl content
2285f92363d1SSreekanth Reddy  */
2286f92363d1SSreekanth Reddy static long
2287f92363d1SSreekanth Reddy _ctl_diag_read_buffer(struct MPT3SAS_ADAPTER *ioc, void __user *arg)
2288f92363d1SSreekanth Reddy {
2289f92363d1SSreekanth Reddy 	struct mpt3_diag_read_buffer karg;
2290f92363d1SSreekanth Reddy 	struct mpt3_diag_read_buffer __user *uarg = arg;
2291f92363d1SSreekanth Reddy 	void *request_data, *diag_data;
2292f92363d1SSreekanth Reddy 	Mpi2DiagBufferPostRequest_t *mpi_request;
2293f92363d1SSreekanth Reddy 	Mpi2DiagBufferPostReply_t *mpi_reply;
2294f92363d1SSreekanth Reddy 	int rc, i;
2295f92363d1SSreekanth Reddy 	u8 buffer_type;
22968bbb1cf6SCalvin Owens 	unsigned long request_size, copy_size;
2297f92363d1SSreekanth Reddy 	u16 smid;
2298f92363d1SSreekanth Reddy 	u16 ioc_status;
2299f92363d1SSreekanth Reddy 	u8 issue_reset = 0;
2300f92363d1SSreekanth Reddy 
2301f92363d1SSreekanth Reddy 	if (copy_from_user(&karg, arg, sizeof(karg))) {
2302f92363d1SSreekanth Reddy 		pr_err("failure at %s:%d/%s()!\n",
2303f92363d1SSreekanth Reddy 		    __FILE__, __LINE__, __func__);
2304f92363d1SSreekanth Reddy 		return -EFAULT;
2305f92363d1SSreekanth Reddy 	}
2306f92363d1SSreekanth Reddy 
2307919d8a3fSJoe Perches 	dctlprintk(ioc, ioc_info(ioc, "%s\n",
2308f92363d1SSreekanth Reddy 				 __func__));
2309f92363d1SSreekanth Reddy 
231008e7378eSSreekanth Reddy 	buffer_type = _ctl_diag_get_bufftype(ioc, karg.unique_id);
231108e7378eSSreekanth Reddy 	if (buffer_type == MPT3_DIAG_UID_NOT_FOUND) {
231208e7378eSSreekanth Reddy 		ioc_err(ioc, "%s: buffer with unique_id(0x%08x) not found\n",
231308e7378eSSreekanth Reddy 		    __func__, karg.unique_id);
231408e7378eSSreekanth Reddy 		return -EINVAL;
231508e7378eSSreekanth Reddy 	}
231608e7378eSSreekanth Reddy 
2317f92363d1SSreekanth Reddy 	if (!_ctl_diag_capability(ioc, buffer_type)) {
2318919d8a3fSJoe Perches 		ioc_err(ioc, "%s: doesn't have capability for buffer_type(0x%02x)\n",
2319919d8a3fSJoe Perches 			__func__, buffer_type);
2320f92363d1SSreekanth Reddy 		return -EPERM;
2321f92363d1SSreekanth Reddy 	}
2322f92363d1SSreekanth Reddy 
2323f92363d1SSreekanth Reddy 	if (karg.unique_id != ioc->unique_id[buffer_type]) {
2324919d8a3fSJoe Perches 		ioc_err(ioc, "%s: unique_id(0x%08x) is not registered\n",
2325919d8a3fSJoe Perches 			__func__, karg.unique_id);
2326f92363d1SSreekanth Reddy 		return -EINVAL;
2327f92363d1SSreekanth Reddy 	}
2328f92363d1SSreekanth Reddy 
2329f92363d1SSreekanth Reddy 	request_data = ioc->diag_buffer[buffer_type];
2330f92363d1SSreekanth Reddy 	if (!request_data) {
2331919d8a3fSJoe Perches 		ioc_err(ioc, "%s: doesn't have buffer for buffer_type(0x%02x)\n",
2332919d8a3fSJoe Perches 			__func__, buffer_type);
2333f92363d1SSreekanth Reddy 		return -ENOMEM;
2334f92363d1SSreekanth Reddy 	}
2335f92363d1SSreekanth Reddy 
2336f92363d1SSreekanth Reddy 	request_size = ioc->diag_buffer_sz[buffer_type];
2337f92363d1SSreekanth Reddy 
2338f92363d1SSreekanth Reddy 	if ((karg.starting_offset % 4) || (karg.bytes_to_read % 4)) {
2339919d8a3fSJoe Perches 		ioc_err(ioc, "%s: either the starting_offset or bytes_to_read are not 4 byte aligned\n",
2340f92363d1SSreekanth Reddy 			__func__);
2341f92363d1SSreekanth Reddy 		return -EINVAL;
2342f92363d1SSreekanth Reddy 	}
2343f92363d1SSreekanth Reddy 
2344f92363d1SSreekanth Reddy 	if (karg.starting_offset > request_size)
2345f92363d1SSreekanth Reddy 		return -EINVAL;
2346f92363d1SSreekanth Reddy 
2347f92363d1SSreekanth Reddy 	diag_data = (void *)(request_data + karg.starting_offset);
2348919d8a3fSJoe Perches 	dctlprintk(ioc,
2349919d8a3fSJoe Perches 		   ioc_info(ioc, "%s: diag_buffer(%p), offset(%d), sz(%d)\n",
2350919d8a3fSJoe Perches 			    __func__, diag_data, karg.starting_offset,
2351919d8a3fSJoe Perches 			    karg.bytes_to_read));
2352f92363d1SSreekanth Reddy 
2353f92363d1SSreekanth Reddy 	/* Truncate data on requests that are too large */
2354f92363d1SSreekanth Reddy 	if ((diag_data + karg.bytes_to_read < diag_data) ||
2355f92363d1SSreekanth Reddy 	    (diag_data + karg.bytes_to_read > request_data + request_size))
2356f92363d1SSreekanth Reddy 		copy_size = request_size - karg.starting_offset;
2357f92363d1SSreekanth Reddy 	else
2358f92363d1SSreekanth Reddy 		copy_size = karg.bytes_to_read;
2359f92363d1SSreekanth Reddy 
2360f92363d1SSreekanth Reddy 	if (copy_to_user((void __user *)uarg->diagnostic_data,
2361f92363d1SSreekanth Reddy 	    diag_data, copy_size)) {
2362919d8a3fSJoe Perches 		ioc_err(ioc, "%s: Unable to write mpt_diag_read_buffer_t data @ %p\n",
2363919d8a3fSJoe Perches 			__func__, diag_data);
2364f92363d1SSreekanth Reddy 		return -EFAULT;
2365f92363d1SSreekanth Reddy 	}
2366f92363d1SSreekanth Reddy 
2367f92363d1SSreekanth Reddy 	if ((karg.flags & MPT3_FLAGS_REREGISTER) == 0)
2368f92363d1SSreekanth Reddy 		return 0;
2369f92363d1SSreekanth Reddy 
2370919d8a3fSJoe Perches 	dctlprintk(ioc,
2371919d8a3fSJoe Perches 		   ioc_info(ioc, "%s: Reregister buffer_type(0x%02x)\n",
2372919d8a3fSJoe Perches 			    __func__, buffer_type));
2373f92363d1SSreekanth Reddy 	if ((ioc->diag_buffer_status[buffer_type] &
2374f92363d1SSreekanth Reddy 	    MPT3_DIAG_BUFFER_IS_RELEASED) == 0) {
2375919d8a3fSJoe Perches 		dctlprintk(ioc,
2376919d8a3fSJoe Perches 			   ioc_info(ioc, "%s: buffer_type(0x%02x) is still registered\n",
2377919d8a3fSJoe Perches 				    __func__, buffer_type));
2378f92363d1SSreekanth Reddy 		return 0;
2379f92363d1SSreekanth Reddy 	}
2380f92363d1SSreekanth Reddy 	/* Get a free request frame and save the message context.
2381f92363d1SSreekanth Reddy 	*/
2382f92363d1SSreekanth Reddy 
2383f92363d1SSreekanth Reddy 	if (ioc->ctl_cmds.status != MPT3_CMD_NOT_USED) {
2384919d8a3fSJoe Perches 		ioc_err(ioc, "%s: ctl_cmd in use\n", __func__);
2385f92363d1SSreekanth Reddy 		rc = -EAGAIN;
2386f92363d1SSreekanth Reddy 		goto out;
2387f92363d1SSreekanth Reddy 	}
2388f92363d1SSreekanth Reddy 
2389f92363d1SSreekanth Reddy 	smid = mpt3sas_base_get_smid(ioc, ioc->ctl_cb_idx);
2390f92363d1SSreekanth Reddy 	if (!smid) {
2391919d8a3fSJoe Perches 		ioc_err(ioc, "%s: failed obtaining a smid\n", __func__);
2392f92363d1SSreekanth Reddy 		rc = -EAGAIN;
2393f92363d1SSreekanth Reddy 		goto out;
2394f92363d1SSreekanth Reddy 	}
2395f92363d1SSreekanth Reddy 
2396f92363d1SSreekanth Reddy 	rc = 0;
2397f92363d1SSreekanth Reddy 	ioc->ctl_cmds.status = MPT3_CMD_PENDING;
2398f92363d1SSreekanth Reddy 	memset(ioc->ctl_cmds.reply, 0, ioc->reply_sz);
2399f92363d1SSreekanth Reddy 	mpi_request = mpt3sas_base_get_msg_frame(ioc, smid);
2400f92363d1SSreekanth Reddy 	ioc->ctl_cmds.smid = smid;
2401f92363d1SSreekanth Reddy 
2402f92363d1SSreekanth Reddy 	mpi_request->Function = MPI2_FUNCTION_DIAG_BUFFER_POST;
2403f92363d1SSreekanth Reddy 	mpi_request->BufferType = buffer_type;
2404f92363d1SSreekanth Reddy 	mpi_request->BufferLength =
2405f92363d1SSreekanth Reddy 	    cpu_to_le32(ioc->diag_buffer_sz[buffer_type]);
2406f92363d1SSreekanth Reddy 	mpi_request->BufferAddress =
2407f92363d1SSreekanth Reddy 	    cpu_to_le64(ioc->diag_buffer_dma[buffer_type]);
2408f92363d1SSreekanth Reddy 	for (i = 0; i < MPT3_PRODUCT_SPECIFIC_DWORDS; i++)
2409f92363d1SSreekanth Reddy 		mpi_request->ProductSpecific[i] =
2410f92363d1SSreekanth Reddy 			cpu_to_le32(ioc->product_specific[buffer_type][i]);
2411f92363d1SSreekanth Reddy 	mpi_request->VF_ID = 0; /* TODO */
2412f92363d1SSreekanth Reddy 	mpi_request->VP_ID = 0;
2413f92363d1SSreekanth Reddy 
2414f92363d1SSreekanth Reddy 	init_completion(&ioc->ctl_cmds.done);
2415078a4cc1SSuganath Prabu S 	ioc->put_smid_default(ioc, smid);
24168bbb1cf6SCalvin Owens 	wait_for_completion_timeout(&ioc->ctl_cmds.done,
2417f92363d1SSreekanth Reddy 	    MPT3_IOCTL_DEFAULT_TIMEOUT*HZ);
2418f92363d1SSreekanth Reddy 
2419f92363d1SSreekanth Reddy 	if (!(ioc->ctl_cmds.status & MPT3_CMD_COMPLETE)) {
2420d37306caSChaitra P B 		issue_reset =
2421d37306caSChaitra P B 			mpt3sas_base_check_cmd_timeout(ioc,
2422d37306caSChaitra P B 				ioc->ctl_cmds.status, mpi_request,
2423f92363d1SSreekanth Reddy 				sizeof(Mpi2DiagBufferPostRequest_t)/4);
2424f92363d1SSreekanth Reddy 		goto issue_host_reset;
2425f92363d1SSreekanth Reddy 	}
2426f92363d1SSreekanth Reddy 
2427f92363d1SSreekanth Reddy 	/* process the completed Reply Message Frame */
2428f92363d1SSreekanth Reddy 	if ((ioc->ctl_cmds.status & MPT3_CMD_REPLY_VALID) == 0) {
2429919d8a3fSJoe Perches 		ioc_err(ioc, "%s: no reply message\n", __func__);
2430f92363d1SSreekanth Reddy 		rc = -EFAULT;
2431f92363d1SSreekanth Reddy 		goto out;
2432f92363d1SSreekanth Reddy 	}
2433f92363d1SSreekanth Reddy 
2434f92363d1SSreekanth Reddy 	mpi_reply = ioc->ctl_cmds.reply;
2435f92363d1SSreekanth Reddy 	ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
2436f92363d1SSreekanth Reddy 
2437f92363d1SSreekanth Reddy 	if (ioc_status == MPI2_IOCSTATUS_SUCCESS) {
2438f92363d1SSreekanth Reddy 		ioc->diag_buffer_status[buffer_type] |=
2439f92363d1SSreekanth Reddy 		    MPT3_DIAG_BUFFER_IS_REGISTERED;
2440dd180e4eSSreekanth Reddy 		ioc->diag_buffer_status[buffer_type] &=
2441dd180e4eSSreekanth Reddy 		    ~MPT3_DIAG_BUFFER_IS_RELEASED;
2442919d8a3fSJoe Perches 		dctlprintk(ioc, ioc_info(ioc, "%s: success\n", __func__));
2443f92363d1SSreekanth Reddy 	} else {
2444919d8a3fSJoe Perches 		ioc_info(ioc, "%s: ioc_status(0x%04x) log_info(0x%08x)\n",
2445919d8a3fSJoe Perches 			 __func__, ioc_status,
2446919d8a3fSJoe Perches 			 le32_to_cpu(mpi_reply->IOCLogInfo));
2447f92363d1SSreekanth Reddy 		rc = -EFAULT;
2448f92363d1SSreekanth Reddy 	}
2449f92363d1SSreekanth Reddy 
2450f92363d1SSreekanth Reddy  issue_host_reset:
2451f92363d1SSreekanth Reddy 	if (issue_reset)
245298c56ad3SCalvin Owens 		mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER);
2453f92363d1SSreekanth Reddy 
2454f92363d1SSreekanth Reddy  out:
2455f92363d1SSreekanth Reddy 
2456f92363d1SSreekanth Reddy 	ioc->ctl_cmds.status = MPT3_CMD_NOT_USED;
2457f92363d1SSreekanth Reddy 	return rc;
2458f92363d1SSreekanth Reddy }
2459f92363d1SSreekanth Reddy 
2460f92363d1SSreekanth Reddy 
2461f92363d1SSreekanth Reddy 
2462f92363d1SSreekanth Reddy #ifdef CONFIG_COMPAT
2463f92363d1SSreekanth Reddy /**
2464f92363d1SSreekanth Reddy  * _ctl_compat_mpt_command - convert 32bit pointers to 64bit.
2465f92363d1SSreekanth Reddy  * @ioc: per adapter object
24664beb4867SBart Van Assche  * @cmd: ioctl opcode
24674beb4867SBart Van Assche  * @arg: (struct mpt3_ioctl_command32)
2468f92363d1SSreekanth Reddy  *
2469f92363d1SSreekanth Reddy  * MPT3COMMAND32 - Handle 32bit applications running on 64bit os.
2470f92363d1SSreekanth Reddy  */
2471f92363d1SSreekanth Reddy static long
2472f92363d1SSreekanth Reddy _ctl_compat_mpt_command(struct MPT3SAS_ADAPTER *ioc, unsigned cmd,
2473f92363d1SSreekanth Reddy 	void __user *arg)
2474f92363d1SSreekanth Reddy {
2475f92363d1SSreekanth Reddy 	struct mpt3_ioctl_command32 karg32;
2476f92363d1SSreekanth Reddy 	struct mpt3_ioctl_command32 __user *uarg;
2477f92363d1SSreekanth Reddy 	struct mpt3_ioctl_command karg;
2478f92363d1SSreekanth Reddy 
2479f92363d1SSreekanth Reddy 	if (_IOC_SIZE(cmd) != sizeof(struct mpt3_ioctl_command32))
2480f92363d1SSreekanth Reddy 		return -EINVAL;
2481f92363d1SSreekanth Reddy 
2482f92363d1SSreekanth Reddy 	uarg = (struct mpt3_ioctl_command32 __user *) arg;
2483f92363d1SSreekanth Reddy 
2484f92363d1SSreekanth Reddy 	if (copy_from_user(&karg32, (char __user *)arg, sizeof(karg32))) {
2485f92363d1SSreekanth Reddy 		pr_err("failure at %s:%d/%s()!\n",
2486f92363d1SSreekanth Reddy 		    __FILE__, __LINE__, __func__);
2487f92363d1SSreekanth Reddy 		return -EFAULT;
2488f92363d1SSreekanth Reddy 	}
2489f92363d1SSreekanth Reddy 
2490f92363d1SSreekanth Reddy 	memset(&karg, 0, sizeof(struct mpt3_ioctl_command));
2491f92363d1SSreekanth Reddy 	karg.hdr.ioc_number = karg32.hdr.ioc_number;
2492f92363d1SSreekanth Reddy 	karg.hdr.port_number = karg32.hdr.port_number;
2493f92363d1SSreekanth Reddy 	karg.hdr.max_data_size = karg32.hdr.max_data_size;
2494f92363d1SSreekanth Reddy 	karg.timeout = karg32.timeout;
2495f92363d1SSreekanth Reddy 	karg.max_reply_bytes = karg32.max_reply_bytes;
2496f92363d1SSreekanth Reddy 	karg.data_in_size = karg32.data_in_size;
2497f92363d1SSreekanth Reddy 	karg.data_out_size = karg32.data_out_size;
2498f92363d1SSreekanth Reddy 	karg.max_sense_bytes = karg32.max_sense_bytes;
2499f92363d1SSreekanth Reddy 	karg.data_sge_offset = karg32.data_sge_offset;
2500f92363d1SSreekanth Reddy 	karg.reply_frame_buf_ptr = compat_ptr(karg32.reply_frame_buf_ptr);
2501f92363d1SSreekanth Reddy 	karg.data_in_buf_ptr = compat_ptr(karg32.data_in_buf_ptr);
2502f92363d1SSreekanth Reddy 	karg.data_out_buf_ptr = compat_ptr(karg32.data_out_buf_ptr);
2503f92363d1SSreekanth Reddy 	karg.sense_data_ptr = compat_ptr(karg32.sense_data_ptr);
2504f92363d1SSreekanth Reddy 	return _ctl_do_mpt_command(ioc, karg, &uarg->mf);
2505f92363d1SSreekanth Reddy }
2506f92363d1SSreekanth Reddy #endif
2507f92363d1SSreekanth Reddy 
2508f92363d1SSreekanth Reddy /**
2509f92363d1SSreekanth Reddy  * _ctl_ioctl_main - main ioctl entry point
25104beb4867SBart Van Assche  * @file:  (struct file)
25114beb4867SBart Van Assche  * @cmd:  ioctl opcode
25124beb4867SBart Van Assche  * @arg:  user space data buffer
25134beb4867SBart Van Assche  * @compat:  handles 32 bit applications in 64bit os
2514c84b06a4SSreekanth Reddy  * @mpi_version: will be MPI2_VERSION for mpt2ctl ioctl device &
2515b130b0d5SSuganath prabu Subramani  * MPI25_VERSION | MPI26_VERSION for mpt3ctl ioctl device.
2516f92363d1SSreekanth Reddy  */
2517f92363d1SSreekanth Reddy static long
2518f92363d1SSreekanth Reddy _ctl_ioctl_main(struct file *file, unsigned int cmd, void __user *arg,
2519c84b06a4SSreekanth Reddy 	u8 compat, u16 mpi_version)
2520f92363d1SSreekanth Reddy {
2521f92363d1SSreekanth Reddy 	struct MPT3SAS_ADAPTER *ioc;
2522f92363d1SSreekanth Reddy 	struct mpt3_ioctl_header ioctl_header;
2523f92363d1SSreekanth Reddy 	enum block_state state;
2524f92363d1SSreekanth Reddy 	long ret = -EINVAL;
2525f92363d1SSreekanth Reddy 
2526f92363d1SSreekanth Reddy 	/* get IOCTL header */
2527f92363d1SSreekanth Reddy 	if (copy_from_user(&ioctl_header, (char __user *)arg,
2528f92363d1SSreekanth Reddy 	    sizeof(struct mpt3_ioctl_header))) {
2529f92363d1SSreekanth Reddy 		pr_err("failure at %s:%d/%s()!\n",
2530f92363d1SSreekanth Reddy 		    __FILE__, __LINE__, __func__);
2531f92363d1SSreekanth Reddy 		return -EFAULT;
2532f92363d1SSreekanth Reddy 	}
2533f92363d1SSreekanth Reddy 
2534c84b06a4SSreekanth Reddy 	if (_ctl_verify_adapter(ioctl_header.ioc_number,
2535c84b06a4SSreekanth Reddy 				&ioc, mpi_version) == -1 || !ioc)
2536f92363d1SSreekanth Reddy 		return -ENODEV;
2537f92363d1SSreekanth Reddy 
253808c4d550SSreekanth Reddy 	/* pci_access_mutex lock acquired by ioctl path */
253908c4d550SSreekanth Reddy 	mutex_lock(&ioc->pci_access_mutex);
254008c4d550SSreekanth Reddy 
2541f92363d1SSreekanth Reddy 	if (ioc->shost_recovery || ioc->pci_error_recovery ||
254208c4d550SSreekanth Reddy 	    ioc->is_driver_loading || ioc->remove_host) {
254308c4d550SSreekanth Reddy 		ret = -EAGAIN;
254408c4d550SSreekanth Reddy 		goto out_unlock_pciaccess;
254508c4d550SSreekanth Reddy 	}
2546f92363d1SSreekanth Reddy 
2547f92363d1SSreekanth Reddy 	state = (file->f_flags & O_NONBLOCK) ? NON_BLOCKING : BLOCKING;
2548f92363d1SSreekanth Reddy 	if (state == NON_BLOCKING) {
254908c4d550SSreekanth Reddy 		if (!mutex_trylock(&ioc->ctl_cmds.mutex)) {
255008c4d550SSreekanth Reddy 			ret = -EAGAIN;
255108c4d550SSreekanth Reddy 			goto out_unlock_pciaccess;
255208c4d550SSreekanth Reddy 		}
255308c4d550SSreekanth Reddy 	} else if (mutex_lock_interruptible(&ioc->ctl_cmds.mutex)) {
255408c4d550SSreekanth Reddy 		ret = -ERESTARTSYS;
255508c4d550SSreekanth Reddy 		goto out_unlock_pciaccess;
255608c4d550SSreekanth Reddy 	}
2557f92363d1SSreekanth Reddy 
2558f92363d1SSreekanth Reddy 
2559f92363d1SSreekanth Reddy 	switch (cmd) {
2560f92363d1SSreekanth Reddy 	case MPT3IOCINFO:
2561f92363d1SSreekanth Reddy 		if (_IOC_SIZE(cmd) == sizeof(struct mpt3_ioctl_iocinfo))
2562f92363d1SSreekanth Reddy 			ret = _ctl_getiocinfo(ioc, arg);
2563f92363d1SSreekanth Reddy 		break;
2564f92363d1SSreekanth Reddy #ifdef CONFIG_COMPAT
2565f92363d1SSreekanth Reddy 	case MPT3COMMAND32:
2566f92363d1SSreekanth Reddy #endif
2567f92363d1SSreekanth Reddy 	case MPT3COMMAND:
2568f92363d1SSreekanth Reddy 	{
2569f92363d1SSreekanth Reddy 		struct mpt3_ioctl_command __user *uarg;
2570f92363d1SSreekanth Reddy 		struct mpt3_ioctl_command karg;
2571f92363d1SSreekanth Reddy 
2572f92363d1SSreekanth Reddy #ifdef CONFIG_COMPAT
2573f92363d1SSreekanth Reddy 		if (compat) {
2574f92363d1SSreekanth Reddy 			ret = _ctl_compat_mpt_command(ioc, cmd, arg);
2575f92363d1SSreekanth Reddy 			break;
2576f92363d1SSreekanth Reddy 		}
2577f92363d1SSreekanth Reddy #endif
2578f92363d1SSreekanth Reddy 		if (copy_from_user(&karg, arg, sizeof(karg))) {
2579f92363d1SSreekanth Reddy 			pr_err("failure at %s:%d/%s()!\n",
2580f92363d1SSreekanth Reddy 			    __FILE__, __LINE__, __func__);
2581f92363d1SSreekanth Reddy 			ret = -EFAULT;
2582f92363d1SSreekanth Reddy 			break;
2583f92363d1SSreekanth Reddy 		}
2584f92363d1SSreekanth Reddy 
2585f9e3ebeeSGen Zhang 		if (karg.hdr.ioc_number != ioctl_header.ioc_number) {
2586f9e3ebeeSGen Zhang 			ret = -EINVAL;
2587f9e3ebeeSGen Zhang 			break;
2588f9e3ebeeSGen Zhang 		}
2589f92363d1SSreekanth Reddy 		if (_IOC_SIZE(cmd) == sizeof(struct mpt3_ioctl_command)) {
2590f92363d1SSreekanth Reddy 			uarg = arg;
2591f92363d1SSreekanth Reddy 			ret = _ctl_do_mpt_command(ioc, karg, &uarg->mf);
2592f92363d1SSreekanth Reddy 		}
2593f92363d1SSreekanth Reddy 		break;
2594f92363d1SSreekanth Reddy 	}
2595f92363d1SSreekanth Reddy 	case MPT3EVENTQUERY:
2596f92363d1SSreekanth Reddy 		if (_IOC_SIZE(cmd) == sizeof(struct mpt3_ioctl_eventquery))
2597f92363d1SSreekanth Reddy 			ret = _ctl_eventquery(ioc, arg);
2598f92363d1SSreekanth Reddy 		break;
2599f92363d1SSreekanth Reddy 	case MPT3EVENTENABLE:
2600f92363d1SSreekanth Reddy 		if (_IOC_SIZE(cmd) == sizeof(struct mpt3_ioctl_eventenable))
2601f92363d1SSreekanth Reddy 			ret = _ctl_eventenable(ioc, arg);
2602f92363d1SSreekanth Reddy 		break;
2603f92363d1SSreekanth Reddy 	case MPT3EVENTREPORT:
2604f92363d1SSreekanth Reddy 		ret = _ctl_eventreport(ioc, arg);
2605f92363d1SSreekanth Reddy 		break;
2606f92363d1SSreekanth Reddy 	case MPT3HARDRESET:
2607f92363d1SSreekanth Reddy 		if (_IOC_SIZE(cmd) == sizeof(struct mpt3_ioctl_diag_reset))
2608f92363d1SSreekanth Reddy 			ret = _ctl_do_reset(ioc, arg);
2609f92363d1SSreekanth Reddy 		break;
2610f92363d1SSreekanth Reddy 	case MPT3BTDHMAPPING:
2611f92363d1SSreekanth Reddy 		if (_IOC_SIZE(cmd) == sizeof(struct mpt3_ioctl_btdh_mapping))
2612f92363d1SSreekanth Reddy 			ret = _ctl_btdh_mapping(ioc, arg);
2613f92363d1SSreekanth Reddy 		break;
2614f92363d1SSreekanth Reddy 	case MPT3DIAGREGISTER:
2615f92363d1SSreekanth Reddy 		if (_IOC_SIZE(cmd) == sizeof(struct mpt3_diag_register))
2616f92363d1SSreekanth Reddy 			ret = _ctl_diag_register(ioc, arg);
2617f92363d1SSreekanth Reddy 		break;
2618f92363d1SSreekanth Reddy 	case MPT3DIAGUNREGISTER:
2619f92363d1SSreekanth Reddy 		if (_IOC_SIZE(cmd) == sizeof(struct mpt3_diag_unregister))
2620f92363d1SSreekanth Reddy 			ret = _ctl_diag_unregister(ioc, arg);
2621f92363d1SSreekanth Reddy 		break;
2622f92363d1SSreekanth Reddy 	case MPT3DIAGQUERY:
2623f92363d1SSreekanth Reddy 		if (_IOC_SIZE(cmd) == sizeof(struct mpt3_diag_query))
2624f92363d1SSreekanth Reddy 			ret = _ctl_diag_query(ioc, arg);
2625f92363d1SSreekanth Reddy 		break;
2626f92363d1SSreekanth Reddy 	case MPT3DIAGRELEASE:
2627f92363d1SSreekanth Reddy 		if (_IOC_SIZE(cmd) == sizeof(struct mpt3_diag_release))
2628f92363d1SSreekanth Reddy 			ret = _ctl_diag_release(ioc, arg);
2629f92363d1SSreekanth Reddy 		break;
2630f92363d1SSreekanth Reddy 	case MPT3DIAGREADBUFFER:
2631f92363d1SSreekanth Reddy 		if (_IOC_SIZE(cmd) == sizeof(struct mpt3_diag_read_buffer))
2632f92363d1SSreekanth Reddy 			ret = _ctl_diag_read_buffer(ioc, arg);
2633f92363d1SSreekanth Reddy 		break;
2634f92363d1SSreekanth Reddy 	default:
2635919d8a3fSJoe Perches 		dctlprintk(ioc,
2636919d8a3fSJoe Perches 			   ioc_info(ioc, "unsupported ioctl opcode(0x%08x)\n",
2637919d8a3fSJoe Perches 				    cmd));
2638f92363d1SSreekanth Reddy 		break;
2639f92363d1SSreekanth Reddy 	}
2640f92363d1SSreekanth Reddy 
2641f92363d1SSreekanth Reddy 	mutex_unlock(&ioc->ctl_cmds.mutex);
264208c4d550SSreekanth Reddy out_unlock_pciaccess:
264308c4d550SSreekanth Reddy 	mutex_unlock(&ioc->pci_access_mutex);
2644f92363d1SSreekanth Reddy 	return ret;
2645f92363d1SSreekanth Reddy }
2646f92363d1SSreekanth Reddy 
2647f92363d1SSreekanth Reddy /**
2648c84b06a4SSreekanth Reddy  * _ctl_ioctl - mpt3ctl main ioctl entry point (unlocked)
26494beb4867SBart Van Assche  * @file: (struct file)
26504beb4867SBart Van Assche  * @cmd: ioctl opcode
26514beb4867SBart Van Assche  * @arg: ?
2652f92363d1SSreekanth Reddy  */
26538bbb1cf6SCalvin Owens static long
2654c84b06a4SSreekanth Reddy _ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
2655f92363d1SSreekanth Reddy {
2656f92363d1SSreekanth Reddy 	long ret;
2657f92363d1SSreekanth Reddy 
2658b130b0d5SSuganath prabu Subramani 	/* pass MPI25_VERSION | MPI26_VERSION value,
2659b130b0d5SSuganath prabu Subramani 	 * to indicate that this ioctl cmd
2660c84b06a4SSreekanth Reddy 	 * came from mpt3ctl ioctl device.
2661c84b06a4SSreekanth Reddy 	 */
2662b130b0d5SSuganath prabu Subramani 	ret = _ctl_ioctl_main(file, cmd, (void __user *)arg, 0,
2663b130b0d5SSuganath prabu Subramani 		MPI25_VERSION | MPI26_VERSION);
2664f92363d1SSreekanth Reddy 	return ret;
2665f92363d1SSreekanth Reddy }
2666f92363d1SSreekanth Reddy 
2667c84b06a4SSreekanth Reddy /**
2668c84b06a4SSreekanth Reddy  * _ctl_mpt2_ioctl - mpt2ctl main ioctl entry point (unlocked)
26694beb4867SBart Van Assche  * @file: (struct file)
26704beb4867SBart Van Assche  * @cmd: ioctl opcode
26714beb4867SBart Van Assche  * @arg: ?
2672c84b06a4SSreekanth Reddy  */
26738bbb1cf6SCalvin Owens static long
2674c84b06a4SSreekanth Reddy _ctl_mpt2_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
2675c84b06a4SSreekanth Reddy {
2676c84b06a4SSreekanth Reddy 	long ret;
2677c84b06a4SSreekanth Reddy 
2678c84b06a4SSreekanth Reddy 	/* pass MPI2_VERSION value, to indicate that this ioctl cmd
2679c84b06a4SSreekanth Reddy 	 * came from mpt2ctl ioctl device.
2680c84b06a4SSreekanth Reddy 	 */
2681c84b06a4SSreekanth Reddy 	ret = _ctl_ioctl_main(file, cmd, (void __user *)arg, 0, MPI2_VERSION);
2682c84b06a4SSreekanth Reddy 	return ret;
2683c84b06a4SSreekanth Reddy }
2684f92363d1SSreekanth Reddy #ifdef CONFIG_COMPAT
2685f92363d1SSreekanth Reddy /**
2686c84b06a4SSreekanth Reddy  *_ ctl_ioctl_compat - main ioctl entry point (compat)
26874beb4867SBart Van Assche  * @file: ?
26884beb4867SBart Van Assche  * @cmd: ?
26894beb4867SBart Van Assche  * @arg: ?
2690f92363d1SSreekanth Reddy  *
2691f92363d1SSreekanth Reddy  * This routine handles 32 bit applications in 64bit os.
2692f92363d1SSreekanth Reddy  */
26938bbb1cf6SCalvin Owens static long
2694c84b06a4SSreekanth Reddy _ctl_ioctl_compat(struct file *file, unsigned cmd, unsigned long arg)
2695f92363d1SSreekanth Reddy {
2696f92363d1SSreekanth Reddy 	long ret;
2697f92363d1SSreekanth Reddy 
2698b130b0d5SSuganath prabu Subramani 	ret = _ctl_ioctl_main(file, cmd, (void __user *)arg, 1,
2699b130b0d5SSuganath prabu Subramani 		MPI25_VERSION | MPI26_VERSION);
2700c84b06a4SSreekanth Reddy 	return ret;
2701c84b06a4SSreekanth Reddy }
2702c84b06a4SSreekanth Reddy 
2703c84b06a4SSreekanth Reddy /**
2704c84b06a4SSreekanth Reddy  *_ ctl_mpt2_ioctl_compat - main ioctl entry point (compat)
27054beb4867SBart Van Assche  * @file: ?
27064beb4867SBart Van Assche  * @cmd: ?
27074beb4867SBart Van Assche  * @arg: ?
2708c84b06a4SSreekanth Reddy  *
2709c84b06a4SSreekanth Reddy  * This routine handles 32 bit applications in 64bit os.
2710c84b06a4SSreekanth Reddy  */
27118bbb1cf6SCalvin Owens static long
2712c84b06a4SSreekanth Reddy _ctl_mpt2_ioctl_compat(struct file *file, unsigned cmd, unsigned long arg)
2713c84b06a4SSreekanth Reddy {
2714c84b06a4SSreekanth Reddy 	long ret;
2715c84b06a4SSreekanth Reddy 
2716c84b06a4SSreekanth Reddy 	ret = _ctl_ioctl_main(file, cmd, (void __user *)arg, 1, MPI2_VERSION);
2717f92363d1SSreekanth Reddy 	return ret;
2718f92363d1SSreekanth Reddy }
2719f92363d1SSreekanth Reddy #endif
2720f92363d1SSreekanth Reddy 
2721f92363d1SSreekanth Reddy /* scsi host attributes */
2722f92363d1SSreekanth Reddy /**
2723c9df1442STomas Henzl  * version_fw_show - firmware version
27244beb4867SBart Van Assche  * @cdev: pointer to embedded class device
27254beb4867SBart Van Assche  * @attr: ?
27264beb4867SBart Van Assche  * @buf: the buffer returned
2727f92363d1SSreekanth Reddy  *
2728f92363d1SSreekanth Reddy  * A sysfs 'read-only' shost attribute.
2729f92363d1SSreekanth Reddy  */
2730f92363d1SSreekanth Reddy static ssize_t
2731c9df1442STomas Henzl version_fw_show(struct device *cdev, struct device_attribute *attr,
2732f92363d1SSreekanth Reddy 	char *buf)
2733f92363d1SSreekanth Reddy {
2734f92363d1SSreekanth Reddy 	struct Scsi_Host *shost = class_to_shost(cdev);
2735f92363d1SSreekanth Reddy 	struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
2736f92363d1SSreekanth Reddy 
2737f92363d1SSreekanth Reddy 	return snprintf(buf, PAGE_SIZE, "%02d.%02d.%02d.%02d\n",
2738f92363d1SSreekanth Reddy 	    (ioc->facts.FWVersion.Word & 0xFF000000) >> 24,
2739f92363d1SSreekanth Reddy 	    (ioc->facts.FWVersion.Word & 0x00FF0000) >> 16,
2740f92363d1SSreekanth Reddy 	    (ioc->facts.FWVersion.Word & 0x0000FF00) >> 8,
2741f92363d1SSreekanth Reddy 	    ioc->facts.FWVersion.Word & 0x000000FF);
2742f92363d1SSreekanth Reddy }
2743c9df1442STomas Henzl static DEVICE_ATTR_RO(version_fw);
2744f92363d1SSreekanth Reddy 
2745f92363d1SSreekanth Reddy /**
2746c9df1442STomas Henzl  * version_bios_show - bios version
27474beb4867SBart Van Assche  * @cdev: pointer to embedded class device
27484beb4867SBart Van Assche  * @attr: ?
27494beb4867SBart Van Assche  * @buf: the buffer returned
2750f92363d1SSreekanth Reddy  *
2751f92363d1SSreekanth Reddy  * A sysfs 'read-only' shost attribute.
2752f92363d1SSreekanth Reddy  */
2753f92363d1SSreekanth Reddy static ssize_t
2754c9df1442STomas Henzl version_bios_show(struct device *cdev, struct device_attribute *attr,
2755f92363d1SSreekanth Reddy 	char *buf)
2756f92363d1SSreekanth Reddy {
2757f92363d1SSreekanth Reddy 	struct Scsi_Host *shost = class_to_shost(cdev);
2758f92363d1SSreekanth Reddy 	struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
2759f92363d1SSreekanth Reddy 
2760f92363d1SSreekanth Reddy 	u32 version = le32_to_cpu(ioc->bios_pg3.BiosVersion);
2761f92363d1SSreekanth Reddy 
2762f92363d1SSreekanth Reddy 	return snprintf(buf, PAGE_SIZE, "%02d.%02d.%02d.%02d\n",
2763f92363d1SSreekanth Reddy 	    (version & 0xFF000000) >> 24,
2764f92363d1SSreekanth Reddy 	    (version & 0x00FF0000) >> 16,
2765f92363d1SSreekanth Reddy 	    (version & 0x0000FF00) >> 8,
2766f92363d1SSreekanth Reddy 	    version & 0x000000FF);
2767f92363d1SSreekanth Reddy }
2768c9df1442STomas Henzl static DEVICE_ATTR_RO(version_bios);
2769f92363d1SSreekanth Reddy 
2770f92363d1SSreekanth Reddy /**
2771c9df1442STomas Henzl  * version_mpi_show - MPI (message passing interface) version
27724beb4867SBart Van Assche  * @cdev: pointer to embedded class device
27734beb4867SBart Van Assche  * @attr: ?
27744beb4867SBart Van Assche  * @buf: the buffer returned
2775f92363d1SSreekanth Reddy  *
2776f92363d1SSreekanth Reddy  * A sysfs 'read-only' shost attribute.
2777f92363d1SSreekanth Reddy  */
2778f92363d1SSreekanth Reddy static ssize_t
2779c9df1442STomas Henzl version_mpi_show(struct device *cdev, struct device_attribute *attr,
2780f92363d1SSreekanth Reddy 	char *buf)
2781f92363d1SSreekanth Reddy {
2782f92363d1SSreekanth Reddy 	struct Scsi_Host *shost = class_to_shost(cdev);
2783f92363d1SSreekanth Reddy 	struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
2784f92363d1SSreekanth Reddy 
2785f92363d1SSreekanth Reddy 	return snprintf(buf, PAGE_SIZE, "%03x.%02x\n",
2786f92363d1SSreekanth Reddy 	    ioc->facts.MsgVersion, ioc->facts.HeaderVersion >> 8);
2787f92363d1SSreekanth Reddy }
2788c9df1442STomas Henzl static DEVICE_ATTR_RO(version_mpi);
2789f92363d1SSreekanth Reddy 
2790f92363d1SSreekanth Reddy /**
2791c9df1442STomas Henzl  * version_product_show - product name
27924beb4867SBart Van Assche  * @cdev: pointer to embedded class device
27934beb4867SBart Van Assche  * @attr: ?
27944beb4867SBart Van Assche  * @buf: the buffer returned
2795f92363d1SSreekanth Reddy  *
2796f92363d1SSreekanth Reddy  * A sysfs 'read-only' shost attribute.
2797f92363d1SSreekanth Reddy  */
2798f92363d1SSreekanth Reddy static ssize_t
2799c9df1442STomas Henzl version_product_show(struct device *cdev, struct device_attribute *attr,
2800f92363d1SSreekanth Reddy 	char *buf)
2801f92363d1SSreekanth Reddy {
2802f92363d1SSreekanth Reddy 	struct Scsi_Host *shost = class_to_shost(cdev);
2803f92363d1SSreekanth Reddy 	struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
2804f92363d1SSreekanth Reddy 
2805f92363d1SSreekanth Reddy 	return snprintf(buf, 16, "%s\n", ioc->manu_pg0.ChipName);
2806f92363d1SSreekanth Reddy }
2807c9df1442STomas Henzl static DEVICE_ATTR_RO(version_product);
2808f92363d1SSreekanth Reddy 
2809f92363d1SSreekanth Reddy /**
2810c9df1442STomas Henzl  * version_nvdata_persistent_show - ndvata persistent version
28114beb4867SBart Van Assche  * @cdev: pointer to embedded class device
28124beb4867SBart Van Assche  * @attr: ?
28134beb4867SBart Van Assche  * @buf: the buffer returned
2814f92363d1SSreekanth Reddy  *
2815f92363d1SSreekanth Reddy  * A sysfs 'read-only' shost attribute.
2816f92363d1SSreekanth Reddy  */
2817f92363d1SSreekanth Reddy static ssize_t
2818c9df1442STomas Henzl version_nvdata_persistent_show(struct device *cdev,
2819f92363d1SSreekanth Reddy 	struct device_attribute *attr, char *buf)
2820f92363d1SSreekanth Reddy {
2821f92363d1SSreekanth Reddy 	struct Scsi_Host *shost = class_to_shost(cdev);
2822f92363d1SSreekanth Reddy 	struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
2823f92363d1SSreekanth Reddy 
2824f92363d1SSreekanth Reddy 	return snprintf(buf, PAGE_SIZE, "%08xh\n",
2825f92363d1SSreekanth Reddy 	    le32_to_cpu(ioc->iounit_pg0.NvdataVersionPersistent.Word));
2826f92363d1SSreekanth Reddy }
2827c9df1442STomas Henzl static DEVICE_ATTR_RO(version_nvdata_persistent);
2828f92363d1SSreekanth Reddy 
2829f92363d1SSreekanth Reddy /**
2830c9df1442STomas Henzl  * version_nvdata_default_show - nvdata default version
28314beb4867SBart Van Assche  * @cdev: pointer to embedded class device
28324beb4867SBart Van Assche  * @attr: ?
28334beb4867SBart Van Assche  * @buf: the buffer returned
2834f92363d1SSreekanth Reddy  *
2835f92363d1SSreekanth Reddy  * A sysfs 'read-only' shost attribute.
2836f92363d1SSreekanth Reddy  */
2837f92363d1SSreekanth Reddy static ssize_t
2838c9df1442STomas Henzl version_nvdata_default_show(struct device *cdev, struct device_attribute
2839f92363d1SSreekanth Reddy 	*attr, char *buf)
2840f92363d1SSreekanth Reddy {
2841f92363d1SSreekanth Reddy 	struct Scsi_Host *shost = class_to_shost(cdev);
2842f92363d1SSreekanth Reddy 	struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
2843f92363d1SSreekanth Reddy 
2844f92363d1SSreekanth Reddy 	return snprintf(buf, PAGE_SIZE, "%08xh\n",
2845f92363d1SSreekanth Reddy 	    le32_to_cpu(ioc->iounit_pg0.NvdataVersionDefault.Word));
2846f92363d1SSreekanth Reddy }
2847c9df1442STomas Henzl static DEVICE_ATTR_RO(version_nvdata_default);
2848f92363d1SSreekanth Reddy 
2849f92363d1SSreekanth Reddy /**
2850c9df1442STomas Henzl  * board_name_show - board name
28514beb4867SBart Van Assche  * @cdev: pointer to embedded class device
28524beb4867SBart Van Assche  * @attr: ?
28534beb4867SBart Van Assche  * @buf: the buffer returned
2854f92363d1SSreekanth Reddy  *
2855f92363d1SSreekanth Reddy  * A sysfs 'read-only' shost attribute.
2856f92363d1SSreekanth Reddy  */
2857f92363d1SSreekanth Reddy static ssize_t
2858c9df1442STomas Henzl board_name_show(struct device *cdev, struct device_attribute *attr,
2859f92363d1SSreekanth Reddy 	char *buf)
2860f92363d1SSreekanth Reddy {
2861f92363d1SSreekanth Reddy 	struct Scsi_Host *shost = class_to_shost(cdev);
2862f92363d1SSreekanth Reddy 	struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
2863f92363d1SSreekanth Reddy 
2864f92363d1SSreekanth Reddy 	return snprintf(buf, 16, "%s\n", ioc->manu_pg0.BoardName);
2865f92363d1SSreekanth Reddy }
2866c9df1442STomas Henzl static DEVICE_ATTR_RO(board_name);
2867f92363d1SSreekanth Reddy 
2868f92363d1SSreekanth Reddy /**
2869c9df1442STomas Henzl  * board_assembly_show - board assembly name
28704beb4867SBart Van Assche  * @cdev: pointer to embedded class device
28714beb4867SBart Van Assche  * @attr: ?
28724beb4867SBart Van Assche  * @buf: the buffer returned
2873f92363d1SSreekanth Reddy  *
2874f92363d1SSreekanth Reddy  * A sysfs 'read-only' shost attribute.
2875f92363d1SSreekanth Reddy  */
2876f92363d1SSreekanth Reddy static ssize_t
2877c9df1442STomas Henzl board_assembly_show(struct device *cdev, struct device_attribute *attr,
2878f92363d1SSreekanth Reddy 	char *buf)
2879f92363d1SSreekanth Reddy {
2880f92363d1SSreekanth Reddy 	struct Scsi_Host *shost = class_to_shost(cdev);
2881f92363d1SSreekanth Reddy 	struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
2882f92363d1SSreekanth Reddy 
2883f92363d1SSreekanth Reddy 	return snprintf(buf, 16, "%s\n", ioc->manu_pg0.BoardAssembly);
2884f92363d1SSreekanth Reddy }
2885c9df1442STomas Henzl static DEVICE_ATTR_RO(board_assembly);
2886f92363d1SSreekanth Reddy 
2887f92363d1SSreekanth Reddy /**
2888c9df1442STomas Henzl  * board_tracer_show - board tracer number
28894beb4867SBart Van Assche  * @cdev: pointer to embedded class device
28904beb4867SBart Van Assche  * @attr: ?
28914beb4867SBart Van Assche  * @buf: the buffer returned
2892f92363d1SSreekanth Reddy  *
2893f92363d1SSreekanth Reddy  * A sysfs 'read-only' shost attribute.
2894f92363d1SSreekanth Reddy  */
2895f92363d1SSreekanth Reddy static ssize_t
2896c9df1442STomas Henzl board_tracer_show(struct device *cdev, struct device_attribute *attr,
2897f92363d1SSreekanth Reddy 	char *buf)
2898f92363d1SSreekanth Reddy {
2899f92363d1SSreekanth Reddy 	struct Scsi_Host *shost = class_to_shost(cdev);
2900f92363d1SSreekanth Reddy 	struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
2901f92363d1SSreekanth Reddy 
2902f92363d1SSreekanth Reddy 	return snprintf(buf, 16, "%s\n", ioc->manu_pg0.BoardTracerNumber);
2903f92363d1SSreekanth Reddy }
2904c9df1442STomas Henzl static DEVICE_ATTR_RO(board_tracer);
2905f92363d1SSreekanth Reddy 
2906f92363d1SSreekanth Reddy /**
2907c9df1442STomas Henzl  * io_delay_show - io missing delay
29084beb4867SBart Van Assche  * @cdev: pointer to embedded class device
29094beb4867SBart Van Assche  * @attr: ?
29104beb4867SBart Van Assche  * @buf: the buffer returned
2911f92363d1SSreekanth Reddy  *
2912f92363d1SSreekanth Reddy  * This is for firmware implemention for deboucing device
2913f92363d1SSreekanth Reddy  * removal events.
2914f92363d1SSreekanth Reddy  *
2915f92363d1SSreekanth Reddy  * A sysfs 'read-only' shost attribute.
2916f92363d1SSreekanth Reddy  */
2917f92363d1SSreekanth Reddy static ssize_t
2918c9df1442STomas Henzl io_delay_show(struct device *cdev, struct device_attribute *attr,
2919f92363d1SSreekanth Reddy 	char *buf)
2920f92363d1SSreekanth Reddy {
2921f92363d1SSreekanth Reddy 	struct Scsi_Host *shost = class_to_shost(cdev);
2922f92363d1SSreekanth Reddy 	struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
2923f92363d1SSreekanth Reddy 
2924f92363d1SSreekanth Reddy 	return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->io_missing_delay);
2925f92363d1SSreekanth Reddy }
2926c9df1442STomas Henzl static DEVICE_ATTR_RO(io_delay);
2927f92363d1SSreekanth Reddy 
2928f92363d1SSreekanth Reddy /**
2929c9df1442STomas Henzl  * device_delay_show - device missing delay
29304beb4867SBart Van Assche  * @cdev: pointer to embedded class device
29314beb4867SBart Van Assche  * @attr: ?
29324beb4867SBart Van Assche  * @buf: the buffer returned
2933f92363d1SSreekanth Reddy  *
2934f92363d1SSreekanth Reddy  * This is for firmware implemention for deboucing device
2935f92363d1SSreekanth Reddy  * removal events.
2936f92363d1SSreekanth Reddy  *
2937f92363d1SSreekanth Reddy  * A sysfs 'read-only' shost attribute.
2938f92363d1SSreekanth Reddy  */
2939f92363d1SSreekanth Reddy static ssize_t
2940c9df1442STomas Henzl device_delay_show(struct device *cdev, struct device_attribute *attr,
2941f92363d1SSreekanth Reddy 	char *buf)
2942f92363d1SSreekanth Reddy {
2943f92363d1SSreekanth Reddy 	struct Scsi_Host *shost = class_to_shost(cdev);
2944f92363d1SSreekanth Reddy 	struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
2945f92363d1SSreekanth Reddy 
2946f92363d1SSreekanth Reddy 	return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->device_missing_delay);
2947f92363d1SSreekanth Reddy }
2948c9df1442STomas Henzl static DEVICE_ATTR_RO(device_delay);
2949f92363d1SSreekanth Reddy 
2950f92363d1SSreekanth Reddy /**
2951c9df1442STomas Henzl  * fw_queue_depth_show - global credits
29524beb4867SBart Van Assche  * @cdev: pointer to embedded class device
29534beb4867SBart Van Assche  * @attr: ?
29544beb4867SBart Van Assche  * @buf: the buffer returned
2955f92363d1SSreekanth Reddy  *
2956f92363d1SSreekanth Reddy  * This is firmware queue depth limit
2957f92363d1SSreekanth Reddy  *
2958f92363d1SSreekanth Reddy  * A sysfs 'read-only' shost attribute.
2959f92363d1SSreekanth Reddy  */
2960f92363d1SSreekanth Reddy static ssize_t
2961c9df1442STomas Henzl fw_queue_depth_show(struct device *cdev, struct device_attribute *attr,
2962f92363d1SSreekanth Reddy 	char *buf)
2963f92363d1SSreekanth Reddy {
2964f92363d1SSreekanth Reddy 	struct Scsi_Host *shost = class_to_shost(cdev);
2965f92363d1SSreekanth Reddy 	struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
2966f92363d1SSreekanth Reddy 
2967f92363d1SSreekanth Reddy 	return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->facts.RequestCredit);
2968f92363d1SSreekanth Reddy }
2969c9df1442STomas Henzl static DEVICE_ATTR_RO(fw_queue_depth);
2970f92363d1SSreekanth Reddy 
2971f92363d1SSreekanth Reddy /**
2972c9df1442STomas Henzl  * sas_address_show - sas address
29734beb4867SBart Van Assche  * @cdev: pointer to embedded class device
29744beb4867SBart Van Assche  * @attr: ?
29754beb4867SBart Van Assche  * @buf: the buffer returned
2976f92363d1SSreekanth Reddy  *
2977f92363d1SSreekanth Reddy  * This is the controller sas address
2978f92363d1SSreekanth Reddy  *
2979f92363d1SSreekanth Reddy  * A sysfs 'read-only' shost attribute.
2980f92363d1SSreekanth Reddy  */
2981f92363d1SSreekanth Reddy static ssize_t
2982c9df1442STomas Henzl host_sas_address_show(struct device *cdev, struct device_attribute *attr,
2983f92363d1SSreekanth Reddy 	char *buf)
2984f92363d1SSreekanth Reddy 
2985f92363d1SSreekanth Reddy {
2986f92363d1SSreekanth Reddy 	struct Scsi_Host *shost = class_to_shost(cdev);
2987f92363d1SSreekanth Reddy 	struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
2988f92363d1SSreekanth Reddy 
2989f92363d1SSreekanth Reddy 	return snprintf(buf, PAGE_SIZE, "0x%016llx\n",
2990f92363d1SSreekanth Reddy 	    (unsigned long long)ioc->sas_hba.sas_address);
2991f92363d1SSreekanth Reddy }
2992c9df1442STomas Henzl static DEVICE_ATTR_RO(host_sas_address);
2993f92363d1SSreekanth Reddy 
2994f92363d1SSreekanth Reddy /**
2995c9df1442STomas Henzl  * logging_level_show - logging level
29964beb4867SBart Van Assche  * @cdev: pointer to embedded class device
29974beb4867SBart Van Assche  * @attr: ?
29984beb4867SBart Van Assche  * @buf: the buffer returned
2999f92363d1SSreekanth Reddy  *
3000f92363d1SSreekanth Reddy  * A sysfs 'read/write' shost attribute.
3001f92363d1SSreekanth Reddy  */
3002f92363d1SSreekanth Reddy static ssize_t
3003c9df1442STomas Henzl logging_level_show(struct device *cdev, struct device_attribute *attr,
3004f92363d1SSreekanth Reddy 	char *buf)
3005f92363d1SSreekanth Reddy {
3006f92363d1SSreekanth Reddy 	struct Scsi_Host *shost = class_to_shost(cdev);
3007f92363d1SSreekanth Reddy 	struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
3008f92363d1SSreekanth Reddy 
3009f92363d1SSreekanth Reddy 	return snprintf(buf, PAGE_SIZE, "%08xh\n", ioc->logging_level);
3010f92363d1SSreekanth Reddy }
3011f92363d1SSreekanth Reddy static ssize_t
3012c9df1442STomas Henzl logging_level_store(struct device *cdev, struct device_attribute *attr,
3013f92363d1SSreekanth Reddy 	const char *buf, size_t count)
3014f92363d1SSreekanth Reddy {
3015f92363d1SSreekanth Reddy 	struct Scsi_Host *shost = class_to_shost(cdev);
3016f92363d1SSreekanth Reddy 	struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
3017f92363d1SSreekanth Reddy 	int val = 0;
3018f92363d1SSreekanth Reddy 
3019f92363d1SSreekanth Reddy 	if (sscanf(buf, "%x", &val) != 1)
3020f92363d1SSreekanth Reddy 		return -EINVAL;
3021f92363d1SSreekanth Reddy 
3022f92363d1SSreekanth Reddy 	ioc->logging_level = val;
3023919d8a3fSJoe Perches 	ioc_info(ioc, "logging_level=%08xh\n",
3024f92363d1SSreekanth Reddy 		 ioc->logging_level);
3025f92363d1SSreekanth Reddy 	return strlen(buf);
3026f92363d1SSreekanth Reddy }
3027c9df1442STomas Henzl static DEVICE_ATTR_RW(logging_level);
3028f92363d1SSreekanth Reddy 
3029f92363d1SSreekanth Reddy /**
3030c9df1442STomas Henzl  * fwfault_debug_show - show/store fwfault_debug
30314beb4867SBart Van Assche  * @cdev: pointer to embedded class device
30324beb4867SBart Van Assche  * @attr: ?
30334beb4867SBart Van Assche  * @buf: the buffer returned
3034f92363d1SSreekanth Reddy  *
3035f92363d1SSreekanth Reddy  * mpt3sas_fwfault_debug is command line option
3036f92363d1SSreekanth Reddy  * A sysfs 'read/write' shost attribute.
3037f92363d1SSreekanth Reddy  */
3038f92363d1SSreekanth Reddy static ssize_t
3039c9df1442STomas Henzl fwfault_debug_show(struct device *cdev, struct device_attribute *attr,
3040f92363d1SSreekanth Reddy 	char *buf)
3041f92363d1SSreekanth Reddy {
3042f92363d1SSreekanth Reddy 	struct Scsi_Host *shost = class_to_shost(cdev);
3043f92363d1SSreekanth Reddy 	struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
3044f92363d1SSreekanth Reddy 
3045f92363d1SSreekanth Reddy 	return snprintf(buf, PAGE_SIZE, "%d\n", ioc->fwfault_debug);
3046f92363d1SSreekanth Reddy }
3047f92363d1SSreekanth Reddy static ssize_t
3048c9df1442STomas Henzl fwfault_debug_store(struct device *cdev, struct device_attribute *attr,
3049f92363d1SSreekanth Reddy 	const char *buf, size_t count)
3050f92363d1SSreekanth Reddy {
3051f92363d1SSreekanth Reddy 	struct Scsi_Host *shost = class_to_shost(cdev);
3052f92363d1SSreekanth Reddy 	struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
3053f92363d1SSreekanth Reddy 	int val = 0;
3054f92363d1SSreekanth Reddy 
3055f92363d1SSreekanth Reddy 	if (sscanf(buf, "%d", &val) != 1)
3056f92363d1SSreekanth Reddy 		return -EINVAL;
3057f92363d1SSreekanth Reddy 
3058f92363d1SSreekanth Reddy 	ioc->fwfault_debug = val;
3059919d8a3fSJoe Perches 	ioc_info(ioc, "fwfault_debug=%d\n",
3060f92363d1SSreekanth Reddy 		 ioc->fwfault_debug);
3061f92363d1SSreekanth Reddy 	return strlen(buf);
3062f92363d1SSreekanth Reddy }
3063c9df1442STomas Henzl static DEVICE_ATTR_RW(fwfault_debug);
3064f92363d1SSreekanth Reddy 
3065f92363d1SSreekanth Reddy /**
3066c9df1442STomas Henzl  * ioc_reset_count_show - ioc reset count
30674beb4867SBart Van Assche  * @cdev: pointer to embedded class device
30684beb4867SBart Van Assche  * @attr: ?
30694beb4867SBart Van Assche  * @buf: the buffer returned
3070f92363d1SSreekanth Reddy  *
3071f92363d1SSreekanth Reddy  * This is firmware queue depth limit
3072f92363d1SSreekanth Reddy  *
3073f92363d1SSreekanth Reddy  * A sysfs 'read-only' shost attribute.
3074f92363d1SSreekanth Reddy  */
3075f92363d1SSreekanth Reddy static ssize_t
3076c9df1442STomas Henzl ioc_reset_count_show(struct device *cdev, struct device_attribute *attr,
3077f92363d1SSreekanth Reddy 	char *buf)
3078f92363d1SSreekanth Reddy {
3079f92363d1SSreekanth Reddy 	struct Scsi_Host *shost = class_to_shost(cdev);
3080f92363d1SSreekanth Reddy 	struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
3081f92363d1SSreekanth Reddy 
3082f92363d1SSreekanth Reddy 	return snprintf(buf, PAGE_SIZE, "%d\n", ioc->ioc_reset_count);
3083f92363d1SSreekanth Reddy }
3084c9df1442STomas Henzl static DEVICE_ATTR_RO(ioc_reset_count);
3085f92363d1SSreekanth Reddy 
3086f92363d1SSreekanth Reddy /**
3087c9df1442STomas Henzl  * reply_queue_count_show - number of reply queues
30884beb4867SBart Van Assche  * @cdev: pointer to embedded class device
30894beb4867SBart Van Assche  * @attr: ?
30904beb4867SBart Van Assche  * @buf: the buffer returned
3091f92363d1SSreekanth Reddy  *
3092f92363d1SSreekanth Reddy  * This is number of reply queues
3093f92363d1SSreekanth Reddy  *
3094f92363d1SSreekanth Reddy  * A sysfs 'read-only' shost attribute.
3095f92363d1SSreekanth Reddy  */
3096f92363d1SSreekanth Reddy static ssize_t
3097c9df1442STomas Henzl reply_queue_count_show(struct device *cdev,
3098f92363d1SSreekanth Reddy 	struct device_attribute *attr, char *buf)
3099f92363d1SSreekanth Reddy {
3100f92363d1SSreekanth Reddy 	u8 reply_queue_count;
3101f92363d1SSreekanth Reddy 	struct Scsi_Host *shost = class_to_shost(cdev);
3102f92363d1SSreekanth Reddy 	struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
3103f92363d1SSreekanth Reddy 
3104f92363d1SSreekanth Reddy 	if ((ioc->facts.IOCCapabilities &
3105f92363d1SSreekanth Reddy 	    MPI2_IOCFACTS_CAPABILITY_MSI_X_INDEX) && ioc->msix_enable)
3106f92363d1SSreekanth Reddy 		reply_queue_count = ioc->reply_queue_count;
3107f92363d1SSreekanth Reddy 	else
3108f92363d1SSreekanth Reddy 		reply_queue_count = 1;
3109f92363d1SSreekanth Reddy 
3110f92363d1SSreekanth Reddy 	return snprintf(buf, PAGE_SIZE, "%d\n", reply_queue_count);
3111f92363d1SSreekanth Reddy }
3112c9df1442STomas Henzl static DEVICE_ATTR_RO(reply_queue_count);
3113f92363d1SSreekanth Reddy 
311442263095SSreekanth Reddy /**
3115c9df1442STomas Henzl  * BRM_status_show - Backup Rail Monitor Status
31164beb4867SBart Van Assche  * @cdev: pointer to embedded class device
31174beb4867SBart Van Assche  * @attr: ?
31184beb4867SBart Van Assche  * @buf: the buffer returned
311942263095SSreekanth Reddy  *
312042263095SSreekanth Reddy  * This is number of reply queues
312142263095SSreekanth Reddy  *
312242263095SSreekanth Reddy  * A sysfs 'read-only' shost attribute.
312342263095SSreekanth Reddy  */
312442263095SSreekanth Reddy static ssize_t
3125c9df1442STomas Henzl BRM_status_show(struct device *cdev, struct device_attribute *attr,
312642263095SSreekanth Reddy 	char *buf)
312742263095SSreekanth Reddy {
312842263095SSreekanth Reddy 	struct Scsi_Host *shost = class_to_shost(cdev);
312942263095SSreekanth Reddy 	struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
313042263095SSreekanth Reddy 	Mpi2IOUnitPage3_t *io_unit_pg3 = NULL;
313142263095SSreekanth Reddy 	Mpi2ConfigReply_t mpi_reply;
313242263095SSreekanth Reddy 	u16 backup_rail_monitor_status = 0;
313342263095SSreekanth Reddy 	u16 ioc_status;
313442263095SSreekanth Reddy 	int sz;
313542263095SSreekanth Reddy 	ssize_t rc = 0;
313642263095SSreekanth Reddy 
313742263095SSreekanth Reddy 	if (!ioc->is_warpdrive) {
3138919d8a3fSJoe Perches 		ioc_err(ioc, "%s: BRM attribute is only for warpdrive\n",
3139919d8a3fSJoe Perches 			__func__);
314042263095SSreekanth Reddy 		goto out;
314142263095SSreekanth Reddy 	}
314208c4d550SSreekanth Reddy 	/* pci_access_mutex lock acquired by sysfs show path */
314308c4d550SSreekanth Reddy 	mutex_lock(&ioc->pci_access_mutex);
314408c4d550SSreekanth Reddy 	if (ioc->pci_error_recovery || ioc->remove_host) {
314508c4d550SSreekanth Reddy 		mutex_unlock(&ioc->pci_access_mutex);
314608c4d550SSreekanth Reddy 		return 0;
314708c4d550SSreekanth Reddy 	}
314842263095SSreekanth Reddy 
314942263095SSreekanth Reddy 	/* allocate upto GPIOVal 36 entries */
315042263095SSreekanth Reddy 	sz = offsetof(Mpi2IOUnitPage3_t, GPIOVal) + (sizeof(u16) * 36);
315142263095SSreekanth Reddy 	io_unit_pg3 = kzalloc(sz, GFP_KERNEL);
315242263095SSreekanth Reddy 	if (!io_unit_pg3) {
3153919d8a3fSJoe Perches 		ioc_err(ioc, "%s: failed allocating memory for iounit_pg3: (%d) bytes\n",
3154919d8a3fSJoe Perches 			__func__, sz);
315542263095SSreekanth Reddy 		goto out;
315642263095SSreekanth Reddy 	}
315742263095SSreekanth Reddy 
315842263095SSreekanth Reddy 	if (mpt3sas_config_get_iounit_pg3(ioc, &mpi_reply, io_unit_pg3, sz) !=
315942263095SSreekanth Reddy 	    0) {
3160919d8a3fSJoe Perches 		ioc_err(ioc, "%s: failed reading iounit_pg3\n",
316142263095SSreekanth Reddy 			__func__);
316242263095SSreekanth Reddy 		goto out;
316342263095SSreekanth Reddy 	}
316442263095SSreekanth Reddy 
316542263095SSreekanth Reddy 	ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK;
316642263095SSreekanth Reddy 	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
3167919d8a3fSJoe Perches 		ioc_err(ioc, "%s: iounit_pg3 failed with ioc_status(0x%04x)\n",
3168919d8a3fSJoe Perches 			__func__, ioc_status);
316942263095SSreekanth Reddy 		goto out;
317042263095SSreekanth Reddy 	}
317142263095SSreekanth Reddy 
317242263095SSreekanth Reddy 	if (io_unit_pg3->GPIOCount < 25) {
3173919d8a3fSJoe Perches 		ioc_err(ioc, "%s: iounit_pg3->GPIOCount less than 25 entries, detected (%d) entries\n",
3174919d8a3fSJoe Perches 			__func__, io_unit_pg3->GPIOCount);
317542263095SSreekanth Reddy 		goto out;
317642263095SSreekanth Reddy 	}
317742263095SSreekanth Reddy 
317842263095SSreekanth Reddy 	/* BRM status is in bit zero of GPIOVal[24] */
317942263095SSreekanth Reddy 	backup_rail_monitor_status = le16_to_cpu(io_unit_pg3->GPIOVal[24]);
318042263095SSreekanth Reddy 	rc = snprintf(buf, PAGE_SIZE, "%d\n", (backup_rail_monitor_status & 1));
318142263095SSreekanth Reddy 
318242263095SSreekanth Reddy  out:
318342263095SSreekanth Reddy 	kfree(io_unit_pg3);
318408c4d550SSreekanth Reddy 	mutex_unlock(&ioc->pci_access_mutex);
318542263095SSreekanth Reddy 	return rc;
318642263095SSreekanth Reddy }
3187c9df1442STomas Henzl static DEVICE_ATTR_RO(BRM_status);
318842263095SSreekanth Reddy 
3189f92363d1SSreekanth Reddy struct DIAG_BUFFER_START {
3190f92363d1SSreekanth Reddy 	__le32	Size;
3191f92363d1SSreekanth Reddy 	__le32	DiagVersion;
3192f92363d1SSreekanth Reddy 	u8	BufferType;
3193f92363d1SSreekanth Reddy 	u8	Reserved[3];
3194f92363d1SSreekanth Reddy 	__le32	Reserved1;
3195f92363d1SSreekanth Reddy 	__le32	Reserved2;
3196f92363d1SSreekanth Reddy 	__le32	Reserved3;
3197f92363d1SSreekanth Reddy };
3198f92363d1SSreekanth Reddy 
3199f92363d1SSreekanth Reddy /**
3200c9df1442STomas Henzl  * host_trace_buffer_size_show - host buffer size (trace only)
32014beb4867SBart Van Assche  * @cdev: pointer to embedded class device
32024beb4867SBart Van Assche  * @attr: ?
32034beb4867SBart Van Assche  * @buf: the buffer returned
3204f92363d1SSreekanth Reddy  *
3205f92363d1SSreekanth Reddy  * A sysfs 'read-only' shost attribute.
3206f92363d1SSreekanth Reddy  */
3207f92363d1SSreekanth Reddy static ssize_t
3208c9df1442STomas Henzl host_trace_buffer_size_show(struct device *cdev,
3209f92363d1SSreekanth Reddy 	struct device_attribute *attr, char *buf)
3210f92363d1SSreekanth Reddy {
3211f92363d1SSreekanth Reddy 	struct Scsi_Host *shost = class_to_shost(cdev);
3212f92363d1SSreekanth Reddy 	struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
3213f92363d1SSreekanth Reddy 	u32 size = 0;
3214f92363d1SSreekanth Reddy 	struct DIAG_BUFFER_START *request_data;
3215f92363d1SSreekanth Reddy 
3216f92363d1SSreekanth Reddy 	if (!ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) {
3217919d8a3fSJoe Perches 		ioc_err(ioc, "%s: host_trace_buffer is not registered\n",
3218919d8a3fSJoe Perches 			__func__);
3219f92363d1SSreekanth Reddy 		return 0;
3220f92363d1SSreekanth Reddy 	}
3221f92363d1SSreekanth Reddy 
3222f92363d1SSreekanth Reddy 	if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
3223f92363d1SSreekanth Reddy 	    MPT3_DIAG_BUFFER_IS_REGISTERED) == 0) {
3224919d8a3fSJoe Perches 		ioc_err(ioc, "%s: host_trace_buffer is not registered\n",
3225919d8a3fSJoe Perches 			__func__);
3226f92363d1SSreekanth Reddy 		return 0;
3227f92363d1SSreekanth Reddy 	}
3228f92363d1SSreekanth Reddy 
3229f92363d1SSreekanth Reddy 	request_data = (struct DIAG_BUFFER_START *)
3230f92363d1SSreekanth Reddy 	    ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE];
3231f92363d1SSreekanth Reddy 	if ((le32_to_cpu(request_data->DiagVersion) == 0x00000000 ||
3232f92363d1SSreekanth Reddy 	    le32_to_cpu(request_data->DiagVersion) == 0x01000000 ||
3233f92363d1SSreekanth Reddy 	    le32_to_cpu(request_data->DiagVersion) == 0x01010000) &&
3234f92363d1SSreekanth Reddy 	    le32_to_cpu(request_data->Reserved3) == 0x4742444c)
3235f92363d1SSreekanth Reddy 		size = le32_to_cpu(request_data->Size);
3236f92363d1SSreekanth Reddy 
3237f92363d1SSreekanth Reddy 	ioc->ring_buffer_sz = size;
3238f92363d1SSreekanth Reddy 	return snprintf(buf, PAGE_SIZE, "%d\n", size);
3239f92363d1SSreekanth Reddy }
3240c9df1442STomas Henzl static DEVICE_ATTR_RO(host_trace_buffer_size);
3241f92363d1SSreekanth Reddy 
3242f92363d1SSreekanth Reddy /**
3243c9df1442STomas Henzl  * host_trace_buffer_show - firmware ring buffer (trace only)
32444beb4867SBart Van Assche  * @cdev: pointer to embedded class device
32454beb4867SBart Van Assche  * @attr: ?
32464beb4867SBart Van Assche  * @buf: the buffer returned
3247f92363d1SSreekanth Reddy  *
3248f92363d1SSreekanth Reddy  * A sysfs 'read/write' shost attribute.
3249f92363d1SSreekanth Reddy  *
3250f92363d1SSreekanth Reddy  * You will only be able to read 4k bytes of ring buffer at a time.
3251f92363d1SSreekanth Reddy  * In order to read beyond 4k bytes, you will have to write out the
3252f92363d1SSreekanth Reddy  * offset to the same attribute, it will move the pointer.
3253f92363d1SSreekanth Reddy  */
3254f92363d1SSreekanth Reddy static ssize_t
3255c9df1442STomas Henzl host_trace_buffer_show(struct device *cdev, struct device_attribute *attr,
3256f92363d1SSreekanth Reddy 	char *buf)
3257f92363d1SSreekanth Reddy {
3258f92363d1SSreekanth Reddy 	struct Scsi_Host *shost = class_to_shost(cdev);
3259f92363d1SSreekanth Reddy 	struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
3260f92363d1SSreekanth Reddy 	void *request_data;
3261f92363d1SSreekanth Reddy 	u32 size;
3262f92363d1SSreekanth Reddy 
3263f92363d1SSreekanth Reddy 	if (!ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) {
3264919d8a3fSJoe Perches 		ioc_err(ioc, "%s: host_trace_buffer is not registered\n",
3265919d8a3fSJoe Perches 			__func__);
3266f92363d1SSreekanth Reddy 		return 0;
3267f92363d1SSreekanth Reddy 	}
3268f92363d1SSreekanth Reddy 
3269f92363d1SSreekanth Reddy 	if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
3270f92363d1SSreekanth Reddy 	    MPT3_DIAG_BUFFER_IS_REGISTERED) == 0) {
3271919d8a3fSJoe Perches 		ioc_err(ioc, "%s: host_trace_buffer is not registered\n",
3272919d8a3fSJoe Perches 			__func__);
3273f92363d1SSreekanth Reddy 		return 0;
3274f92363d1SSreekanth Reddy 	}
3275f92363d1SSreekanth Reddy 
3276f92363d1SSreekanth Reddy 	if (ioc->ring_buffer_offset > ioc->ring_buffer_sz)
3277f92363d1SSreekanth Reddy 		return 0;
3278f92363d1SSreekanth Reddy 
3279f92363d1SSreekanth Reddy 	size = ioc->ring_buffer_sz - ioc->ring_buffer_offset;
3280f92363d1SSreekanth Reddy 	size = (size >= PAGE_SIZE) ? (PAGE_SIZE - 1) : size;
3281f92363d1SSreekanth Reddy 	request_data = ioc->diag_buffer[0] + ioc->ring_buffer_offset;
3282f92363d1SSreekanth Reddy 	memcpy(buf, request_data, size);
3283f92363d1SSreekanth Reddy 	return size;
3284f92363d1SSreekanth Reddy }
3285f92363d1SSreekanth Reddy 
3286f92363d1SSreekanth Reddy static ssize_t
3287c9df1442STomas Henzl host_trace_buffer_store(struct device *cdev, struct device_attribute *attr,
3288f92363d1SSreekanth Reddy 	const char *buf, size_t count)
3289f92363d1SSreekanth Reddy {
3290f92363d1SSreekanth Reddy 	struct Scsi_Host *shost = class_to_shost(cdev);
3291f92363d1SSreekanth Reddy 	struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
3292f92363d1SSreekanth Reddy 	int val = 0;
3293f92363d1SSreekanth Reddy 
3294f92363d1SSreekanth Reddy 	if (sscanf(buf, "%d", &val) != 1)
3295f92363d1SSreekanth Reddy 		return -EINVAL;
3296f92363d1SSreekanth Reddy 
3297f92363d1SSreekanth Reddy 	ioc->ring_buffer_offset = val;
3298f92363d1SSreekanth Reddy 	return strlen(buf);
3299f92363d1SSreekanth Reddy }
3300c9df1442STomas Henzl static DEVICE_ATTR_RW(host_trace_buffer);
3301f92363d1SSreekanth Reddy 
3302f92363d1SSreekanth Reddy 
3303f92363d1SSreekanth Reddy /*****************************************/
3304f92363d1SSreekanth Reddy 
3305f92363d1SSreekanth Reddy /**
3306c9df1442STomas Henzl  * host_trace_buffer_enable_show - firmware ring buffer (trace only)
33074beb4867SBart Van Assche  * @cdev: pointer to embedded class device
33084beb4867SBart Van Assche  * @attr: ?
33094beb4867SBart Van Assche  * @buf: the buffer returned
3310f92363d1SSreekanth Reddy  *
3311f92363d1SSreekanth Reddy  * A sysfs 'read/write' shost attribute.
3312f92363d1SSreekanth Reddy  *
3313f92363d1SSreekanth Reddy  * This is a mechnism to post/release host_trace_buffers
3314f92363d1SSreekanth Reddy  */
3315f92363d1SSreekanth Reddy static ssize_t
3316c9df1442STomas Henzl host_trace_buffer_enable_show(struct device *cdev,
3317f92363d1SSreekanth Reddy 	struct device_attribute *attr, char *buf)
3318f92363d1SSreekanth Reddy {
3319f92363d1SSreekanth Reddy 	struct Scsi_Host *shost = class_to_shost(cdev);
3320f92363d1SSreekanth Reddy 	struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
3321f92363d1SSreekanth Reddy 
3322f92363d1SSreekanth Reddy 	if ((!ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) ||
3323f92363d1SSreekanth Reddy 	   ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
3324f92363d1SSreekanth Reddy 	    MPT3_DIAG_BUFFER_IS_REGISTERED) == 0))
3325f92363d1SSreekanth Reddy 		return snprintf(buf, PAGE_SIZE, "off\n");
3326f92363d1SSreekanth Reddy 	else if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
3327f92363d1SSreekanth Reddy 	    MPT3_DIAG_BUFFER_IS_RELEASED))
3328f92363d1SSreekanth Reddy 		return snprintf(buf, PAGE_SIZE, "release\n");
3329f92363d1SSreekanth Reddy 	else
3330f92363d1SSreekanth Reddy 		return snprintf(buf, PAGE_SIZE, "post\n");
3331f92363d1SSreekanth Reddy }
3332f92363d1SSreekanth Reddy 
3333f92363d1SSreekanth Reddy static ssize_t
3334c9df1442STomas Henzl host_trace_buffer_enable_store(struct device *cdev,
3335f92363d1SSreekanth Reddy 	struct device_attribute *attr, const char *buf, size_t count)
3336f92363d1SSreekanth Reddy {
3337f92363d1SSreekanth Reddy 	struct Scsi_Host *shost = class_to_shost(cdev);
3338f92363d1SSreekanth Reddy 	struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
3339f92363d1SSreekanth Reddy 	char str[10] = "";
3340f92363d1SSreekanth Reddy 	struct mpt3_diag_register diag_register;
3341f92363d1SSreekanth Reddy 	u8 issue_reset = 0;
3342f92363d1SSreekanth Reddy 
3343f92363d1SSreekanth Reddy 	/* don't allow post/release occurr while recovery is active */
3344f92363d1SSreekanth Reddy 	if (ioc->shost_recovery || ioc->remove_host ||
3345f92363d1SSreekanth Reddy 	    ioc->pci_error_recovery || ioc->is_driver_loading)
3346f92363d1SSreekanth Reddy 		return -EBUSY;
3347f92363d1SSreekanth Reddy 
3348f92363d1SSreekanth Reddy 	if (sscanf(buf, "%9s", str) != 1)
3349f92363d1SSreekanth Reddy 		return -EINVAL;
3350f92363d1SSreekanth Reddy 
3351f92363d1SSreekanth Reddy 	if (!strcmp(str, "post")) {
3352f92363d1SSreekanth Reddy 		/* exit out if host buffers are already posted */
3353f92363d1SSreekanth Reddy 		if ((ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) &&
3354f92363d1SSreekanth Reddy 		    (ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
3355f92363d1SSreekanth Reddy 		    MPT3_DIAG_BUFFER_IS_REGISTERED) &&
3356f92363d1SSreekanth Reddy 		    ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
3357f92363d1SSreekanth Reddy 		    MPT3_DIAG_BUFFER_IS_RELEASED) == 0))
3358f92363d1SSreekanth Reddy 			goto out;
3359f92363d1SSreekanth Reddy 		memset(&diag_register, 0, sizeof(struct mpt3_diag_register));
3360919d8a3fSJoe Perches 		ioc_info(ioc, "posting host trace buffers\n");
3361f92363d1SSreekanth Reddy 		diag_register.buffer_type = MPI2_DIAG_BUF_TYPE_TRACE;
3362d04a6edfSSreekanth Reddy 
3363d04a6edfSSreekanth Reddy 		if (ioc->manu_pg11.HostTraceBufferMaxSizeKB != 0 &&
3364d04a6edfSSreekanth Reddy 		    ioc->diag_buffer_sz[MPI2_DIAG_BUF_TYPE_TRACE] != 0) {
3365d04a6edfSSreekanth Reddy 			/* post the same buffer allocated previously */
3366d04a6edfSSreekanth Reddy 			diag_register.requested_buffer_size =
3367d04a6edfSSreekanth Reddy 			    ioc->diag_buffer_sz[MPI2_DIAG_BUF_TYPE_TRACE];
3368a8a6cbcdSSreekanth Reddy 		} else {
3369a8a6cbcdSSreekanth Reddy 			/*
3370a8a6cbcdSSreekanth Reddy 			 * Free the diag buffer memory which was previously
3371a8a6cbcdSSreekanth Reddy 			 * allocated by an application.
3372a8a6cbcdSSreekanth Reddy 			 */
3373a8a6cbcdSSreekanth Reddy 			if ((ioc->diag_buffer_sz[MPI2_DIAG_BUF_TYPE_TRACE] != 0)
3374a8a6cbcdSSreekanth Reddy 			    &&
3375a8a6cbcdSSreekanth Reddy 			    (ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
3376a8a6cbcdSSreekanth Reddy 			    MPT3_DIAG_BUFFER_IS_APP_OWNED)) {
3377a8a6cbcdSSreekanth Reddy 				pci_free_consistent(ioc->pdev,
3378a8a6cbcdSSreekanth Reddy 				    ioc->diag_buffer_sz[
3379a8a6cbcdSSreekanth Reddy 				    MPI2_DIAG_BUF_TYPE_TRACE],
3380a8a6cbcdSSreekanth Reddy 				    ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE],
3381a8a6cbcdSSreekanth Reddy 				    ioc->diag_buffer_dma[
3382a8a6cbcdSSreekanth Reddy 				    MPI2_DIAG_BUF_TYPE_TRACE]);
3383a8a6cbcdSSreekanth Reddy 				ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE] =
3384a8a6cbcdSSreekanth Reddy 				    NULL;
3385a8a6cbcdSSreekanth Reddy 			}
3386a8a6cbcdSSreekanth Reddy 
3387f92363d1SSreekanth Reddy 			diag_register.requested_buffer_size = (1024 * 1024);
3388a8a6cbcdSSreekanth Reddy 		}
3389d04a6edfSSreekanth Reddy 
339008e7378eSSreekanth Reddy 		diag_register.unique_id =
339108e7378eSSreekanth Reddy 		    (ioc->hba_mpi_version_belonged == MPI2_VERSION) ?
339208e7378eSSreekanth Reddy 		    (MPT2DIAGBUFFUNIQUEID):(MPT3DIAGBUFFUNIQUEID);
3393f92363d1SSreekanth Reddy 		ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] = 0;
3394f92363d1SSreekanth Reddy 		_ctl_diag_register_2(ioc,  &diag_register);
3395a066f4c3SSreekanth Reddy 		if (ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
3396a066f4c3SSreekanth Reddy 		    MPT3_DIAG_BUFFER_IS_REGISTERED) {
3397a066f4c3SSreekanth Reddy 			ioc_info(ioc,
3398a066f4c3SSreekanth Reddy 			    "Trace buffer %d KB allocated through sysfs\n",
3399a066f4c3SSreekanth Reddy 			    diag_register.requested_buffer_size>>10);
3400a066f4c3SSreekanth Reddy 			if (ioc->hba_mpi_version_belonged != MPI2_VERSION)
3401a066f4c3SSreekanth Reddy 				ioc->diag_buffer_status[
3402a066f4c3SSreekanth Reddy 				    MPI2_DIAG_BUF_TYPE_TRACE] |=
3403a066f4c3SSreekanth Reddy 				    MPT3_DIAG_BUFFER_IS_DRIVER_ALLOCATED;
3404a066f4c3SSreekanth Reddy 		}
3405f92363d1SSreekanth Reddy 	} else if (!strcmp(str, "release")) {
3406f92363d1SSreekanth Reddy 		/* exit out if host buffers are already released */
3407f92363d1SSreekanth Reddy 		if (!ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE])
3408f92363d1SSreekanth Reddy 			goto out;
3409f92363d1SSreekanth Reddy 		if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
3410f92363d1SSreekanth Reddy 		    MPT3_DIAG_BUFFER_IS_REGISTERED) == 0)
3411f92363d1SSreekanth Reddy 			goto out;
3412f92363d1SSreekanth Reddy 		if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
3413f92363d1SSreekanth Reddy 		    MPT3_DIAG_BUFFER_IS_RELEASED))
3414f92363d1SSreekanth Reddy 			goto out;
3415919d8a3fSJoe Perches 		ioc_info(ioc, "releasing host trace buffer\n");
3416f92363d1SSreekanth Reddy 		mpt3sas_send_diag_release(ioc, MPI2_DIAG_BUF_TYPE_TRACE,
3417f92363d1SSreekanth Reddy 		    &issue_reset);
3418f92363d1SSreekanth Reddy 	}
3419f92363d1SSreekanth Reddy 
3420f92363d1SSreekanth Reddy  out:
3421f92363d1SSreekanth Reddy 	return strlen(buf);
3422f92363d1SSreekanth Reddy }
3423c9df1442STomas Henzl static DEVICE_ATTR_RW(host_trace_buffer_enable);
3424f92363d1SSreekanth Reddy 
3425f92363d1SSreekanth Reddy /*********** diagnostic trigger suppport *********************************/
3426f92363d1SSreekanth Reddy 
3427f92363d1SSreekanth Reddy /**
3428c9df1442STomas Henzl  * diag_trigger_master_show - show the diag_trigger_master attribute
34294beb4867SBart Van Assche  * @cdev: pointer to embedded class device
34304beb4867SBart Van Assche  * @attr: ?
34314beb4867SBart Van Assche  * @buf: the buffer returned
3432f92363d1SSreekanth Reddy  *
3433f92363d1SSreekanth Reddy  * A sysfs 'read/write' shost attribute.
3434f92363d1SSreekanth Reddy  */
3435f92363d1SSreekanth Reddy static ssize_t
3436c9df1442STomas Henzl diag_trigger_master_show(struct device *cdev,
3437f92363d1SSreekanth Reddy 	struct device_attribute *attr, char *buf)
3438f92363d1SSreekanth Reddy 
3439f92363d1SSreekanth Reddy {
3440f92363d1SSreekanth Reddy 	struct Scsi_Host *shost = class_to_shost(cdev);
3441f92363d1SSreekanth Reddy 	struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
3442f92363d1SSreekanth Reddy 	unsigned long flags;
3443f92363d1SSreekanth Reddy 	ssize_t rc;
3444f92363d1SSreekanth Reddy 
3445f92363d1SSreekanth Reddy 	spin_lock_irqsave(&ioc->diag_trigger_lock, flags);
3446f92363d1SSreekanth Reddy 	rc = sizeof(struct SL_WH_MASTER_TRIGGER_T);
3447f92363d1SSreekanth Reddy 	memcpy(buf, &ioc->diag_trigger_master, rc);
3448f92363d1SSreekanth Reddy 	spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags);
3449f92363d1SSreekanth Reddy 	return rc;
3450f92363d1SSreekanth Reddy }
3451f92363d1SSreekanth Reddy 
3452f92363d1SSreekanth Reddy /**
3453c9df1442STomas Henzl  * diag_trigger_master_store - store the diag_trigger_master attribute
34544beb4867SBart Van Assche  * @cdev: pointer to embedded class device
34554beb4867SBart Van Assche  * @attr: ?
34564beb4867SBart Van Assche  * @buf: the buffer returned
34574beb4867SBart Van Assche  * @count: ?
3458f92363d1SSreekanth Reddy  *
3459f92363d1SSreekanth Reddy  * A sysfs 'read/write' shost attribute.
3460f92363d1SSreekanth Reddy  */
3461f92363d1SSreekanth Reddy static ssize_t
3462c9df1442STomas Henzl diag_trigger_master_store(struct device *cdev,
3463f92363d1SSreekanth Reddy 	struct device_attribute *attr, const char *buf, size_t count)
3464f92363d1SSreekanth Reddy 
3465f92363d1SSreekanth Reddy {
3466f92363d1SSreekanth Reddy 	struct Scsi_Host *shost = class_to_shost(cdev);
3467f92363d1SSreekanth Reddy 	struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
3468f92363d1SSreekanth Reddy 	unsigned long flags;
3469f92363d1SSreekanth Reddy 	ssize_t rc;
3470f92363d1SSreekanth Reddy 
3471f92363d1SSreekanth Reddy 	spin_lock_irqsave(&ioc->diag_trigger_lock, flags);
3472f92363d1SSreekanth Reddy 	rc = min(sizeof(struct SL_WH_MASTER_TRIGGER_T), count);
3473f92363d1SSreekanth Reddy 	memset(&ioc->diag_trigger_master, 0,
3474f92363d1SSreekanth Reddy 	    sizeof(struct SL_WH_MASTER_TRIGGER_T));
3475f92363d1SSreekanth Reddy 	memcpy(&ioc->diag_trigger_master, buf, rc);
3476f92363d1SSreekanth Reddy 	ioc->diag_trigger_master.MasterData |=
3477f92363d1SSreekanth Reddy 	    (MASTER_TRIGGER_FW_FAULT + MASTER_TRIGGER_ADAPTER_RESET);
3478f92363d1SSreekanth Reddy 	spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags);
3479f92363d1SSreekanth Reddy 	return rc;
3480f92363d1SSreekanth Reddy }
3481c9df1442STomas Henzl static DEVICE_ATTR_RW(diag_trigger_master);
3482f92363d1SSreekanth Reddy 
3483f92363d1SSreekanth Reddy 
3484f92363d1SSreekanth Reddy /**
3485c9df1442STomas Henzl  * diag_trigger_event_show - show the diag_trigger_event attribute
34864beb4867SBart Van Assche  * @cdev: pointer to embedded class device
34874beb4867SBart Van Assche  * @attr: ?
34884beb4867SBart Van Assche  * @buf: the buffer returned
3489f92363d1SSreekanth Reddy  *
3490f92363d1SSreekanth Reddy  * A sysfs 'read/write' shost attribute.
3491f92363d1SSreekanth Reddy  */
3492f92363d1SSreekanth Reddy static ssize_t
3493c9df1442STomas Henzl diag_trigger_event_show(struct device *cdev,
3494f92363d1SSreekanth Reddy 	struct device_attribute *attr, char *buf)
3495f92363d1SSreekanth Reddy {
3496f92363d1SSreekanth Reddy 	struct Scsi_Host *shost = class_to_shost(cdev);
3497f92363d1SSreekanth Reddy 	struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
3498f92363d1SSreekanth Reddy 	unsigned long flags;
3499f92363d1SSreekanth Reddy 	ssize_t rc;
3500f92363d1SSreekanth Reddy 
3501f92363d1SSreekanth Reddy 	spin_lock_irqsave(&ioc->diag_trigger_lock, flags);
3502f92363d1SSreekanth Reddy 	rc = sizeof(struct SL_WH_EVENT_TRIGGERS_T);
3503f92363d1SSreekanth Reddy 	memcpy(buf, &ioc->diag_trigger_event, rc);
3504f92363d1SSreekanth Reddy 	spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags);
3505f92363d1SSreekanth Reddy 	return rc;
3506f92363d1SSreekanth Reddy }
3507f92363d1SSreekanth Reddy 
3508f92363d1SSreekanth Reddy /**
3509c9df1442STomas Henzl  * diag_trigger_event_store - store the diag_trigger_event attribute
35104beb4867SBart Van Assche  * @cdev: pointer to embedded class device
35114beb4867SBart Van Assche  * @attr: ?
35124beb4867SBart Van Assche  * @buf: the buffer returned
35134beb4867SBart Van Assche  * @count: ?
3514f92363d1SSreekanth Reddy  *
3515f92363d1SSreekanth Reddy  * A sysfs 'read/write' shost attribute.
3516f92363d1SSreekanth Reddy  */
3517f92363d1SSreekanth Reddy static ssize_t
3518c9df1442STomas Henzl diag_trigger_event_store(struct device *cdev,
3519f92363d1SSreekanth Reddy 	struct device_attribute *attr, const char *buf, size_t count)
3520f92363d1SSreekanth Reddy 
3521f92363d1SSreekanth Reddy {
3522f92363d1SSreekanth Reddy 	struct Scsi_Host *shost = class_to_shost(cdev);
3523f92363d1SSreekanth Reddy 	struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
3524f92363d1SSreekanth Reddy 	unsigned long flags;
3525f92363d1SSreekanth Reddy 	ssize_t sz;
3526f92363d1SSreekanth Reddy 
3527f92363d1SSreekanth Reddy 	spin_lock_irqsave(&ioc->diag_trigger_lock, flags);
3528f92363d1SSreekanth Reddy 	sz = min(sizeof(struct SL_WH_EVENT_TRIGGERS_T), count);
3529f92363d1SSreekanth Reddy 	memset(&ioc->diag_trigger_event, 0,
3530f92363d1SSreekanth Reddy 	    sizeof(struct SL_WH_EVENT_TRIGGERS_T));
3531f92363d1SSreekanth Reddy 	memcpy(&ioc->diag_trigger_event, buf, sz);
3532f92363d1SSreekanth Reddy 	if (ioc->diag_trigger_event.ValidEntries > NUM_VALID_ENTRIES)
3533f92363d1SSreekanth Reddy 		ioc->diag_trigger_event.ValidEntries = NUM_VALID_ENTRIES;
3534f92363d1SSreekanth Reddy 	spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags);
3535f92363d1SSreekanth Reddy 	return sz;
3536f92363d1SSreekanth Reddy }
3537c9df1442STomas Henzl static DEVICE_ATTR_RW(diag_trigger_event);
3538f92363d1SSreekanth Reddy 
3539f92363d1SSreekanth Reddy 
3540f92363d1SSreekanth Reddy /**
3541c9df1442STomas Henzl  * diag_trigger_scsi_show - show the diag_trigger_scsi attribute
35424beb4867SBart Van Assche  * @cdev: pointer to embedded class device
35434beb4867SBart Van Assche  * @attr: ?
35444beb4867SBart Van Assche  * @buf: the buffer returned
3545f92363d1SSreekanth Reddy  *
3546f92363d1SSreekanth Reddy  * A sysfs 'read/write' shost attribute.
3547f92363d1SSreekanth Reddy  */
3548f92363d1SSreekanth Reddy static ssize_t
3549c9df1442STomas Henzl diag_trigger_scsi_show(struct device *cdev,
3550f92363d1SSreekanth Reddy 	struct device_attribute *attr, char *buf)
3551f92363d1SSreekanth Reddy {
3552f92363d1SSreekanth Reddy 	struct Scsi_Host *shost = class_to_shost(cdev);
3553f92363d1SSreekanth Reddy 	struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
3554f92363d1SSreekanth Reddy 	unsigned long flags;
3555f92363d1SSreekanth Reddy 	ssize_t rc;
3556f92363d1SSreekanth Reddy 
3557f92363d1SSreekanth Reddy 	spin_lock_irqsave(&ioc->diag_trigger_lock, flags);
3558f92363d1SSreekanth Reddy 	rc = sizeof(struct SL_WH_SCSI_TRIGGERS_T);
3559f92363d1SSreekanth Reddy 	memcpy(buf, &ioc->diag_trigger_scsi, rc);
3560f92363d1SSreekanth Reddy 	spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags);
3561f92363d1SSreekanth Reddy 	return rc;
3562f92363d1SSreekanth Reddy }
3563f92363d1SSreekanth Reddy 
3564f92363d1SSreekanth Reddy /**
3565c9df1442STomas Henzl  * diag_trigger_scsi_store - store the diag_trigger_scsi attribute
35664beb4867SBart Van Assche  * @cdev: pointer to embedded class device
35674beb4867SBart Van Assche  * @attr: ?
35684beb4867SBart Van Assche  * @buf: the buffer returned
35694beb4867SBart Van Assche  * @count: ?
3570f92363d1SSreekanth Reddy  *
3571f92363d1SSreekanth Reddy  * A sysfs 'read/write' shost attribute.
3572f92363d1SSreekanth Reddy  */
3573f92363d1SSreekanth Reddy static ssize_t
3574c9df1442STomas Henzl diag_trigger_scsi_store(struct device *cdev,
3575f92363d1SSreekanth Reddy 	struct device_attribute *attr, const char *buf, size_t count)
3576f92363d1SSreekanth Reddy {
3577f92363d1SSreekanth Reddy 	struct Scsi_Host *shost = class_to_shost(cdev);
3578f92363d1SSreekanth Reddy 	struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
3579f92363d1SSreekanth Reddy 	unsigned long flags;
3580f92363d1SSreekanth Reddy 	ssize_t sz;
3581f92363d1SSreekanth Reddy 
3582f92363d1SSreekanth Reddy 	spin_lock_irqsave(&ioc->diag_trigger_lock, flags);
35831de540a9SDan Carpenter 	sz = min(sizeof(ioc->diag_trigger_scsi), count);
35841de540a9SDan Carpenter 	memset(&ioc->diag_trigger_scsi, 0, sizeof(ioc->diag_trigger_scsi));
3585f92363d1SSreekanth Reddy 	memcpy(&ioc->diag_trigger_scsi, buf, sz);
3586f92363d1SSreekanth Reddy 	if (ioc->diag_trigger_scsi.ValidEntries > NUM_VALID_ENTRIES)
3587f92363d1SSreekanth Reddy 		ioc->diag_trigger_scsi.ValidEntries = NUM_VALID_ENTRIES;
3588f92363d1SSreekanth Reddy 	spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags);
3589f92363d1SSreekanth Reddy 	return sz;
3590f92363d1SSreekanth Reddy }
3591c9df1442STomas Henzl static DEVICE_ATTR_RW(diag_trigger_scsi);
3592f92363d1SSreekanth Reddy 
3593f92363d1SSreekanth Reddy 
3594f92363d1SSreekanth Reddy /**
3595c9df1442STomas Henzl  * diag_trigger_scsi_show - show the diag_trigger_mpi attribute
35964beb4867SBart Van Assche  * @cdev: pointer to embedded class device
35974beb4867SBart Van Assche  * @attr: ?
35984beb4867SBart Van Assche  * @buf: the buffer returned
3599f92363d1SSreekanth Reddy  *
3600f92363d1SSreekanth Reddy  * A sysfs 'read/write' shost attribute.
3601f92363d1SSreekanth Reddy  */
3602f92363d1SSreekanth Reddy static ssize_t
3603c9df1442STomas Henzl diag_trigger_mpi_show(struct device *cdev,
3604f92363d1SSreekanth Reddy 	struct device_attribute *attr, char *buf)
3605f92363d1SSreekanth Reddy {
3606f92363d1SSreekanth Reddy 	struct Scsi_Host *shost = class_to_shost(cdev);
3607f92363d1SSreekanth Reddy 	struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
3608f92363d1SSreekanth Reddy 	unsigned long flags;
3609f92363d1SSreekanth Reddy 	ssize_t rc;
3610f92363d1SSreekanth Reddy 
3611f92363d1SSreekanth Reddy 	spin_lock_irqsave(&ioc->diag_trigger_lock, flags);
3612f92363d1SSreekanth Reddy 	rc = sizeof(struct SL_WH_MPI_TRIGGERS_T);
3613f92363d1SSreekanth Reddy 	memcpy(buf, &ioc->diag_trigger_mpi, rc);
3614f92363d1SSreekanth Reddy 	spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags);
3615f92363d1SSreekanth Reddy 	return rc;
3616f92363d1SSreekanth Reddy }
3617f92363d1SSreekanth Reddy 
3618f92363d1SSreekanth Reddy /**
3619c9df1442STomas Henzl  * diag_trigger_mpi_store - store the diag_trigger_mpi attribute
36204beb4867SBart Van Assche  * @cdev: pointer to embedded class device
36214beb4867SBart Van Assche  * @attr: ?
36224beb4867SBart Van Assche  * @buf: the buffer returned
36234beb4867SBart Van Assche  * @count: ?
3624f92363d1SSreekanth Reddy  *
3625f92363d1SSreekanth Reddy  * A sysfs 'read/write' shost attribute.
3626f92363d1SSreekanth Reddy  */
3627f92363d1SSreekanth Reddy static ssize_t
3628c9df1442STomas Henzl diag_trigger_mpi_store(struct device *cdev,
3629f92363d1SSreekanth Reddy 	struct device_attribute *attr, const char *buf, size_t count)
3630f92363d1SSreekanth Reddy {
3631f92363d1SSreekanth Reddy 	struct Scsi_Host *shost = class_to_shost(cdev);
3632f92363d1SSreekanth Reddy 	struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
3633f92363d1SSreekanth Reddy 	unsigned long flags;
3634f92363d1SSreekanth Reddy 	ssize_t sz;
3635f92363d1SSreekanth Reddy 
3636f92363d1SSreekanth Reddy 	spin_lock_irqsave(&ioc->diag_trigger_lock, flags);
3637f92363d1SSreekanth Reddy 	sz = min(sizeof(struct SL_WH_MPI_TRIGGERS_T), count);
3638f92363d1SSreekanth Reddy 	memset(&ioc->diag_trigger_mpi, 0,
363966331e8cSDan Carpenter 	    sizeof(ioc->diag_trigger_mpi));
3640f92363d1SSreekanth Reddy 	memcpy(&ioc->diag_trigger_mpi, buf, sz);
3641f92363d1SSreekanth Reddy 	if (ioc->diag_trigger_mpi.ValidEntries > NUM_VALID_ENTRIES)
3642f92363d1SSreekanth Reddy 		ioc->diag_trigger_mpi.ValidEntries = NUM_VALID_ENTRIES;
3643f92363d1SSreekanth Reddy 	spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags);
3644f92363d1SSreekanth Reddy 	return sz;
3645f92363d1SSreekanth Reddy }
3646f92363d1SSreekanth Reddy 
3647c9df1442STomas Henzl static DEVICE_ATTR_RW(diag_trigger_mpi);
3648f92363d1SSreekanth Reddy 
3649f92363d1SSreekanth Reddy /*********** diagnostic trigger suppport *** END ****************************/
3650f92363d1SSreekanth Reddy 
3651f92363d1SSreekanth Reddy /*****************************************/
3652f92363d1SSreekanth Reddy 
36533ac8e47bSSuganath Prabu /**
36543ac8e47bSSuganath Prabu  * drv_support_bitmap_show - driver supported feature bitmap
36553ac8e47bSSuganath Prabu  * @cdev - pointer to embedded class device
36563ac8e47bSSuganath Prabu  * @buf - the buffer returned
36573ac8e47bSSuganath Prabu  *
36583ac8e47bSSuganath Prabu  * A sysfs 'read-only' shost attribute.
36593ac8e47bSSuganath Prabu  */
36603ac8e47bSSuganath Prabu static ssize_t
36613ac8e47bSSuganath Prabu drv_support_bitmap_show(struct device *cdev,
36623ac8e47bSSuganath Prabu 	struct device_attribute *attr, char *buf)
36633ac8e47bSSuganath Prabu {
36643ac8e47bSSuganath Prabu 	struct Scsi_Host *shost = class_to_shost(cdev);
36653ac8e47bSSuganath Prabu 	struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
36663ac8e47bSSuganath Prabu 
36673ac8e47bSSuganath Prabu 	return snprintf(buf, PAGE_SIZE, "0x%08x\n", ioc->drv_support_bitmap);
36683ac8e47bSSuganath Prabu }
36693ac8e47bSSuganath Prabu static DEVICE_ATTR_RO(drv_support_bitmap);
36703ac8e47bSSuganath Prabu 
36718dc8d29aSSreekanth Reddy /**
36728dc8d29aSSreekanth Reddy  * enable_sdev_max_qd_show - display whether sdev max qd is enabled/disabled
36738dc8d29aSSreekanth Reddy  * @cdev - pointer to embedded class device
36748dc8d29aSSreekanth Reddy  * @buf - the buffer returned
36758dc8d29aSSreekanth Reddy  *
36768dc8d29aSSreekanth Reddy  * A sysfs read/write shost attribute. This attribute is used to set the
36778dc8d29aSSreekanth Reddy  * targets queue depth to HBA IO queue depth if this attribute is enabled.
36788dc8d29aSSreekanth Reddy  */
36798dc8d29aSSreekanth Reddy static ssize_t
36808dc8d29aSSreekanth Reddy enable_sdev_max_qd_show(struct device *cdev,
36818dc8d29aSSreekanth Reddy 	struct device_attribute *attr, char *buf)
36828dc8d29aSSreekanth Reddy {
36838dc8d29aSSreekanth Reddy 	struct Scsi_Host *shost = class_to_shost(cdev);
36848dc8d29aSSreekanth Reddy 	struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
36858dc8d29aSSreekanth Reddy 
36868dc8d29aSSreekanth Reddy 	return snprintf(buf, PAGE_SIZE, "%d\n", ioc->enable_sdev_max_qd);
36878dc8d29aSSreekanth Reddy }
36888dc8d29aSSreekanth Reddy 
36898dc8d29aSSreekanth Reddy /**
36908dc8d29aSSreekanth Reddy  * enable_sdev_max_qd_store - Enable/disable sdev max qd
36918dc8d29aSSreekanth Reddy  * @cdev - pointer to embedded class device
36928dc8d29aSSreekanth Reddy  * @buf - the buffer returned
36938dc8d29aSSreekanth Reddy  *
36948dc8d29aSSreekanth Reddy  * A sysfs read/write shost attribute. This attribute is used to set the
36958dc8d29aSSreekanth Reddy  * targets queue depth to HBA IO queue depth if this attribute is enabled.
36968dc8d29aSSreekanth Reddy  * If this attribute is disabled then targets will have corresponding default
36978dc8d29aSSreekanth Reddy  * queue depth.
36988dc8d29aSSreekanth Reddy  */
36998dc8d29aSSreekanth Reddy static ssize_t
37008dc8d29aSSreekanth Reddy enable_sdev_max_qd_store(struct device *cdev,
37018dc8d29aSSreekanth Reddy 	struct device_attribute *attr, const char *buf, size_t count)
37028dc8d29aSSreekanth Reddy {
37038dc8d29aSSreekanth Reddy 	struct Scsi_Host *shost = class_to_shost(cdev);
37048dc8d29aSSreekanth Reddy 	struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
37058dc8d29aSSreekanth Reddy 	struct MPT3SAS_DEVICE *sas_device_priv_data;
37068dc8d29aSSreekanth Reddy 	struct MPT3SAS_TARGET *sas_target_priv_data;
37078dc8d29aSSreekanth Reddy 	int val = 0;
37088dc8d29aSSreekanth Reddy 	struct scsi_device *sdev;
37098dc8d29aSSreekanth Reddy 	struct _raid_device *raid_device;
37108dc8d29aSSreekanth Reddy 	int qdepth;
37118dc8d29aSSreekanth Reddy 
37128dc8d29aSSreekanth Reddy 	if (kstrtoint(buf, 0, &val) != 0)
37138dc8d29aSSreekanth Reddy 		return -EINVAL;
37148dc8d29aSSreekanth Reddy 
37158dc8d29aSSreekanth Reddy 	switch (val) {
37168dc8d29aSSreekanth Reddy 	case 0:
37178dc8d29aSSreekanth Reddy 		ioc->enable_sdev_max_qd = 0;
37188dc8d29aSSreekanth Reddy 		shost_for_each_device(sdev, ioc->shost) {
37198dc8d29aSSreekanth Reddy 			sas_device_priv_data = sdev->hostdata;
37208dc8d29aSSreekanth Reddy 			if (!sas_device_priv_data)
37218dc8d29aSSreekanth Reddy 				continue;
37228dc8d29aSSreekanth Reddy 			sas_target_priv_data = sas_device_priv_data->sas_target;
37238dc8d29aSSreekanth Reddy 			if (!sas_target_priv_data)
37248dc8d29aSSreekanth Reddy 				continue;
37258dc8d29aSSreekanth Reddy 
37268dc8d29aSSreekanth Reddy 			if (sas_target_priv_data->flags &
37278dc8d29aSSreekanth Reddy 			    MPT_TARGET_FLAGS_VOLUME) {
37288dc8d29aSSreekanth Reddy 				raid_device =
37298dc8d29aSSreekanth Reddy 				    mpt3sas_raid_device_find_by_handle(ioc,
37308dc8d29aSSreekanth Reddy 				    sas_target_priv_data->handle);
37318dc8d29aSSreekanth Reddy 
37328dc8d29aSSreekanth Reddy 				switch (raid_device->volume_type) {
37338dc8d29aSSreekanth Reddy 				case MPI2_RAID_VOL_TYPE_RAID0:
37348dc8d29aSSreekanth Reddy 					if (raid_device->device_info &
37358dc8d29aSSreekanth Reddy 					    MPI2_SAS_DEVICE_INFO_SSP_TARGET)
37368dc8d29aSSreekanth Reddy 						qdepth =
37378dc8d29aSSreekanth Reddy 						    MPT3SAS_SAS_QUEUE_DEPTH;
37388dc8d29aSSreekanth Reddy 					else
37398dc8d29aSSreekanth Reddy 						qdepth =
37408dc8d29aSSreekanth Reddy 						    MPT3SAS_SATA_QUEUE_DEPTH;
37418dc8d29aSSreekanth Reddy 					break;
37428dc8d29aSSreekanth Reddy 				case MPI2_RAID_VOL_TYPE_RAID1E:
37438dc8d29aSSreekanth Reddy 				case MPI2_RAID_VOL_TYPE_RAID1:
37448dc8d29aSSreekanth Reddy 				case MPI2_RAID_VOL_TYPE_RAID10:
37458dc8d29aSSreekanth Reddy 				case MPI2_RAID_VOL_TYPE_UNKNOWN:
37468dc8d29aSSreekanth Reddy 				default:
37478dc8d29aSSreekanth Reddy 					qdepth = MPT3SAS_RAID_QUEUE_DEPTH;
37488dc8d29aSSreekanth Reddy 				}
37498dc8d29aSSreekanth Reddy 			} else if (sas_target_priv_data->flags &
37508dc8d29aSSreekanth Reddy 			    MPT_TARGET_FLAGS_PCIE_DEVICE)
37518dc8d29aSSreekanth Reddy 				qdepth = MPT3SAS_NVME_QUEUE_DEPTH;
37528dc8d29aSSreekanth Reddy 			else
37538dc8d29aSSreekanth Reddy 				qdepth = MPT3SAS_SAS_QUEUE_DEPTH;
37548dc8d29aSSreekanth Reddy 
37558dc8d29aSSreekanth Reddy 			mpt3sas_scsih_change_queue_depth(sdev, qdepth);
37568dc8d29aSSreekanth Reddy 		}
37578dc8d29aSSreekanth Reddy 		break;
37588dc8d29aSSreekanth Reddy 	case 1:
37598dc8d29aSSreekanth Reddy 		ioc->enable_sdev_max_qd = 1;
37608dc8d29aSSreekanth Reddy 		shost_for_each_device(sdev, ioc->shost)
37618dc8d29aSSreekanth Reddy 			mpt3sas_scsih_change_queue_depth(sdev,
37628dc8d29aSSreekanth Reddy 			    shost->can_queue);
37638dc8d29aSSreekanth Reddy 		break;
37648dc8d29aSSreekanth Reddy 	default:
37658dc8d29aSSreekanth Reddy 		return -EINVAL;
37668dc8d29aSSreekanth Reddy 	}
37678dc8d29aSSreekanth Reddy 
37688dc8d29aSSreekanth Reddy 	return strlen(buf);
37698dc8d29aSSreekanth Reddy }
37708dc8d29aSSreekanth Reddy static DEVICE_ATTR_RW(enable_sdev_max_qd);
37718dc8d29aSSreekanth Reddy 
3772f92363d1SSreekanth Reddy struct device_attribute *mpt3sas_host_attrs[] = {
3773f92363d1SSreekanth Reddy 	&dev_attr_version_fw,
3774f92363d1SSreekanth Reddy 	&dev_attr_version_bios,
3775f92363d1SSreekanth Reddy 	&dev_attr_version_mpi,
3776f92363d1SSreekanth Reddy 	&dev_attr_version_product,
3777f92363d1SSreekanth Reddy 	&dev_attr_version_nvdata_persistent,
3778f92363d1SSreekanth Reddy 	&dev_attr_version_nvdata_default,
3779f92363d1SSreekanth Reddy 	&dev_attr_board_name,
3780f92363d1SSreekanth Reddy 	&dev_attr_board_assembly,
3781f92363d1SSreekanth Reddy 	&dev_attr_board_tracer,
3782f92363d1SSreekanth Reddy 	&dev_attr_io_delay,
3783f92363d1SSreekanth Reddy 	&dev_attr_device_delay,
3784f92363d1SSreekanth Reddy 	&dev_attr_logging_level,
3785f92363d1SSreekanth Reddy 	&dev_attr_fwfault_debug,
3786f92363d1SSreekanth Reddy 	&dev_attr_fw_queue_depth,
3787f92363d1SSreekanth Reddy 	&dev_attr_host_sas_address,
3788f92363d1SSreekanth Reddy 	&dev_attr_ioc_reset_count,
3789f92363d1SSreekanth Reddy 	&dev_attr_host_trace_buffer_size,
3790f92363d1SSreekanth Reddy 	&dev_attr_host_trace_buffer,
3791f92363d1SSreekanth Reddy 	&dev_attr_host_trace_buffer_enable,
3792f92363d1SSreekanth Reddy 	&dev_attr_reply_queue_count,
3793f92363d1SSreekanth Reddy 	&dev_attr_diag_trigger_master,
3794f92363d1SSreekanth Reddy 	&dev_attr_diag_trigger_event,
3795f92363d1SSreekanth Reddy 	&dev_attr_diag_trigger_scsi,
3796f92363d1SSreekanth Reddy 	&dev_attr_diag_trigger_mpi,
37973ac8e47bSSuganath Prabu 	&dev_attr_drv_support_bitmap,
379842263095SSreekanth Reddy 	&dev_attr_BRM_status,
37998dc8d29aSSreekanth Reddy 	&dev_attr_enable_sdev_max_qd,
3800f92363d1SSreekanth Reddy 	NULL,
3801f92363d1SSreekanth Reddy };
3802f92363d1SSreekanth Reddy 
3803f92363d1SSreekanth Reddy /* device attributes */
3804f92363d1SSreekanth Reddy 
3805f92363d1SSreekanth Reddy /**
3806c9df1442STomas Henzl  * sas_address_show - sas address
38074beb4867SBart Van Assche  * @dev: pointer to embedded class device
38084beb4867SBart Van Assche  * @attr: ?
38094beb4867SBart Van Assche  * @buf: the buffer returned
3810f92363d1SSreekanth Reddy  *
3811f92363d1SSreekanth Reddy  * This is the sas address for the target
3812f92363d1SSreekanth Reddy  *
3813f92363d1SSreekanth Reddy  * A sysfs 'read-only' shost attribute.
3814f92363d1SSreekanth Reddy  */
3815f92363d1SSreekanth Reddy static ssize_t
3816c9df1442STomas Henzl sas_address_show(struct device *dev, struct device_attribute *attr,
3817f92363d1SSreekanth Reddy 	char *buf)
3818f92363d1SSreekanth Reddy {
3819f92363d1SSreekanth Reddy 	struct scsi_device *sdev = to_scsi_device(dev);
3820f92363d1SSreekanth Reddy 	struct MPT3SAS_DEVICE *sas_device_priv_data = sdev->hostdata;
3821f92363d1SSreekanth Reddy 
3822f92363d1SSreekanth Reddy 	return snprintf(buf, PAGE_SIZE, "0x%016llx\n",
3823f92363d1SSreekanth Reddy 	    (unsigned long long)sas_device_priv_data->sas_target->sas_address);
3824f92363d1SSreekanth Reddy }
3825c9df1442STomas Henzl static DEVICE_ATTR_RO(sas_address);
3826f92363d1SSreekanth Reddy 
3827f92363d1SSreekanth Reddy /**
3828c9df1442STomas Henzl  * sas_device_handle_show - device handle
38294beb4867SBart Van Assche  * @dev: pointer to embedded class device
38304beb4867SBart Van Assche  * @attr: ?
38314beb4867SBart Van Assche  * @buf: the buffer returned
3832f92363d1SSreekanth Reddy  *
3833f92363d1SSreekanth Reddy  * This is the firmware assigned device handle
3834f92363d1SSreekanth Reddy  *
3835f92363d1SSreekanth Reddy  * A sysfs 'read-only' shost attribute.
3836f92363d1SSreekanth Reddy  */
3837f92363d1SSreekanth Reddy static ssize_t
3838c9df1442STomas Henzl sas_device_handle_show(struct device *dev, struct device_attribute *attr,
3839f92363d1SSreekanth Reddy 	char *buf)
3840f92363d1SSreekanth Reddy {
3841f92363d1SSreekanth Reddy 	struct scsi_device *sdev = to_scsi_device(dev);
3842f92363d1SSreekanth Reddy 	struct MPT3SAS_DEVICE *sas_device_priv_data = sdev->hostdata;
3843f92363d1SSreekanth Reddy 
3844f92363d1SSreekanth Reddy 	return snprintf(buf, PAGE_SIZE, "0x%04x\n",
3845f92363d1SSreekanth Reddy 	    sas_device_priv_data->sas_target->handle);
3846f92363d1SSreekanth Reddy }
3847c9df1442STomas Henzl static DEVICE_ATTR_RO(sas_device_handle);
3848f92363d1SSreekanth Reddy 
3849307d9075SAdam Manzanares /**
3850c9df1442STomas Henzl  * sas_ncq_io_prio_show - send prioritized io commands to device
38514beb4867SBart Van Assche  * @dev: pointer to embedded device
38524beb4867SBart Van Assche  * @attr: ?
38534beb4867SBart Van Assche  * @buf: the buffer returned
3854307d9075SAdam Manzanares  *
3855307d9075SAdam Manzanares  * A sysfs 'read/write' sdev attribute, only works with SATA
3856307d9075SAdam Manzanares  */
3857307d9075SAdam Manzanares static ssize_t
3858c9df1442STomas Henzl sas_ncq_prio_enable_show(struct device *dev,
3859307d9075SAdam Manzanares 				 struct device_attribute *attr, char *buf)
3860307d9075SAdam Manzanares {
3861307d9075SAdam Manzanares 	struct scsi_device *sdev = to_scsi_device(dev);
3862307d9075SAdam Manzanares 	struct MPT3SAS_DEVICE *sas_device_priv_data = sdev->hostdata;
3863307d9075SAdam Manzanares 
3864307d9075SAdam Manzanares 	return snprintf(buf, PAGE_SIZE, "%d\n",
3865307d9075SAdam Manzanares 			sas_device_priv_data->ncq_prio_enable);
3866307d9075SAdam Manzanares }
3867307d9075SAdam Manzanares 
3868307d9075SAdam Manzanares static ssize_t
3869c9df1442STomas Henzl sas_ncq_prio_enable_store(struct device *dev,
3870307d9075SAdam Manzanares 				  struct device_attribute *attr,
3871307d9075SAdam Manzanares 				  const char *buf, size_t count)
3872307d9075SAdam Manzanares {
3873307d9075SAdam Manzanares 	struct scsi_device *sdev = to_scsi_device(dev);
3874307d9075SAdam Manzanares 	struct MPT3SAS_DEVICE *sas_device_priv_data = sdev->hostdata;
3875307d9075SAdam Manzanares 	bool ncq_prio_enable = 0;
3876307d9075SAdam Manzanares 
3877307d9075SAdam Manzanares 	if (kstrtobool(buf, &ncq_prio_enable))
3878307d9075SAdam Manzanares 		return -EINVAL;
3879307d9075SAdam Manzanares 
3880307d9075SAdam Manzanares 	if (!scsih_ncq_prio_supp(sdev))
3881307d9075SAdam Manzanares 		return -EINVAL;
3882307d9075SAdam Manzanares 
3883307d9075SAdam Manzanares 	sas_device_priv_data->ncq_prio_enable = ncq_prio_enable;
3884307d9075SAdam Manzanares 	return strlen(buf);
3885307d9075SAdam Manzanares }
3886c9df1442STomas Henzl static DEVICE_ATTR_RW(sas_ncq_prio_enable);
3887307d9075SAdam Manzanares 
3888f92363d1SSreekanth Reddy struct device_attribute *mpt3sas_dev_attrs[] = {
3889f92363d1SSreekanth Reddy 	&dev_attr_sas_address,
3890f92363d1SSreekanth Reddy 	&dev_attr_sas_device_handle,
3891307d9075SAdam Manzanares 	&dev_attr_sas_ncq_prio_enable,
3892f92363d1SSreekanth Reddy 	NULL,
3893f92363d1SSreekanth Reddy };
3894f92363d1SSreekanth Reddy 
3895c84b06a4SSreekanth Reddy /* file operations table for mpt3ctl device */
3896c84b06a4SSreekanth Reddy static const struct file_operations ctl_fops = {
3897c84b06a4SSreekanth Reddy 	.owner = THIS_MODULE,
3898c84b06a4SSreekanth Reddy 	.unlocked_ioctl = _ctl_ioctl,
3899c84b06a4SSreekanth Reddy 	.poll = _ctl_poll,
3900c84b06a4SSreekanth Reddy 	.fasync = _ctl_fasync,
3901c84b06a4SSreekanth Reddy #ifdef CONFIG_COMPAT
3902c84b06a4SSreekanth Reddy 	.compat_ioctl = _ctl_ioctl_compat,
3903c84b06a4SSreekanth Reddy #endif
3904c84b06a4SSreekanth Reddy };
3905c84b06a4SSreekanth Reddy 
3906c84b06a4SSreekanth Reddy /* file operations table for mpt2ctl device */
3907c84b06a4SSreekanth Reddy static const struct file_operations ctl_gen2_fops = {
3908c84b06a4SSreekanth Reddy 	.owner = THIS_MODULE,
3909c84b06a4SSreekanth Reddy 	.unlocked_ioctl = _ctl_mpt2_ioctl,
3910c84b06a4SSreekanth Reddy 	.poll = _ctl_poll,
3911c84b06a4SSreekanth Reddy 	.fasync = _ctl_fasync,
3912c84b06a4SSreekanth Reddy #ifdef CONFIG_COMPAT
3913c84b06a4SSreekanth Reddy 	.compat_ioctl = _ctl_mpt2_ioctl_compat,
3914c84b06a4SSreekanth Reddy #endif
3915c84b06a4SSreekanth Reddy };
3916c84b06a4SSreekanth Reddy 
3917c84b06a4SSreekanth Reddy static struct miscdevice ctl_dev = {
3918c84b06a4SSreekanth Reddy 	.minor  = MPT3SAS_MINOR,
3919c84b06a4SSreekanth Reddy 	.name   = MPT3SAS_DEV_NAME,
3920c84b06a4SSreekanth Reddy 	.fops   = &ctl_fops,
3921c84b06a4SSreekanth Reddy };
3922c84b06a4SSreekanth Reddy 
3923c84b06a4SSreekanth Reddy static struct miscdevice gen2_ctl_dev = {
3924c84b06a4SSreekanth Reddy 	.minor  = MPT2SAS_MINOR,
3925c84b06a4SSreekanth Reddy 	.name   = MPT2SAS_DEV_NAME,
3926c84b06a4SSreekanth Reddy 	.fops   = &ctl_gen2_fops,
3927c84b06a4SSreekanth Reddy };
3928c84b06a4SSreekanth Reddy 
3929f92363d1SSreekanth Reddy /**
3930c84b06a4SSreekanth Reddy  * mpt3sas_ctl_init - main entry point for ctl.
39314beb4867SBart Van Assche  * @hbas_to_enumerate: ?
3932f92363d1SSreekanth Reddy  */
3933f92363d1SSreekanth Reddy void
3934c84b06a4SSreekanth Reddy mpt3sas_ctl_init(ushort hbas_to_enumerate)
3935f92363d1SSreekanth Reddy {
3936f92363d1SSreekanth Reddy 	async_queue = NULL;
3937c84b06a4SSreekanth Reddy 
3938c84b06a4SSreekanth Reddy 	/* Don't register mpt3ctl ioctl device if
3939c84b06a4SSreekanth Reddy 	 * hbas_to_enumarate is one.
3940c84b06a4SSreekanth Reddy 	 */
3941c84b06a4SSreekanth Reddy 	if (hbas_to_enumerate != 1)
3942c84b06a4SSreekanth Reddy 		if (misc_register(&ctl_dev) < 0)
3943c84b06a4SSreekanth Reddy 			pr_err("%s can't register misc device [minor=%d]\n",
3944c84b06a4SSreekanth Reddy 			    MPT3SAS_DRIVER_NAME, MPT3SAS_MINOR);
3945c84b06a4SSreekanth Reddy 
3946c84b06a4SSreekanth Reddy 	/* Don't register mpt3ctl ioctl device if
3947c84b06a4SSreekanth Reddy 	 * hbas_to_enumarate is two.
3948c84b06a4SSreekanth Reddy 	 */
3949c84b06a4SSreekanth Reddy 	if (hbas_to_enumerate != 2)
3950c84b06a4SSreekanth Reddy 		if (misc_register(&gen2_ctl_dev) < 0)
3951c84b06a4SSreekanth Reddy 			pr_err("%s can't register misc device [minor=%d]\n",
3952c84b06a4SSreekanth Reddy 			    MPT2SAS_DRIVER_NAME, MPT2SAS_MINOR);
3953c84b06a4SSreekanth Reddy 
3954f92363d1SSreekanth Reddy 	init_waitqueue_head(&ctl_poll_wait);
3955f92363d1SSreekanth Reddy }
3956f92363d1SSreekanth Reddy 
3957f92363d1SSreekanth Reddy /**
3958c84b06a4SSreekanth Reddy  * mpt3sas_ctl_exit - exit point for ctl
39594beb4867SBart Van Assche  * @hbas_to_enumerate: ?
3960f92363d1SSreekanth Reddy  */
3961f92363d1SSreekanth Reddy void
3962c84b06a4SSreekanth Reddy mpt3sas_ctl_exit(ushort hbas_to_enumerate)
3963f92363d1SSreekanth Reddy {
3964f92363d1SSreekanth Reddy 	struct MPT3SAS_ADAPTER *ioc;
3965f92363d1SSreekanth Reddy 	int i;
3966f92363d1SSreekanth Reddy 
3967f92363d1SSreekanth Reddy 	list_for_each_entry(ioc, &mpt3sas_ioc_list, list) {
3968f92363d1SSreekanth Reddy 
3969f92363d1SSreekanth Reddy 		/* free memory associated to diag buffers */
3970f92363d1SSreekanth Reddy 		for (i = 0; i < MPI2_DIAG_BUF_TYPE_COUNT; i++) {
3971f92363d1SSreekanth Reddy 			if (!ioc->diag_buffer[i])
3972f92363d1SSreekanth Reddy 				continue;
39731c2048bdSChristoph Hellwig 			dma_free_coherent(&ioc->pdev->dev,
39741c2048bdSChristoph Hellwig 					  ioc->diag_buffer_sz[i],
39751c2048bdSChristoph Hellwig 					  ioc->diag_buffer[i],
39761c2048bdSChristoph Hellwig 					  ioc->diag_buffer_dma[i]);
3977f92363d1SSreekanth Reddy 			ioc->diag_buffer[i] = NULL;
3978f92363d1SSreekanth Reddy 			ioc->diag_buffer_status[i] = 0;
3979f92363d1SSreekanth Reddy 		}
3980f92363d1SSreekanth Reddy 
3981f92363d1SSreekanth Reddy 		kfree(ioc->event_log);
3982f92363d1SSreekanth Reddy 	}
3983c84b06a4SSreekanth Reddy 	if (hbas_to_enumerate != 1)
3984c84b06a4SSreekanth Reddy 		misc_deregister(&ctl_dev);
3985c84b06a4SSreekanth Reddy 	if (hbas_to_enumerate != 2)
3986c84b06a4SSreekanth Reddy 		misc_deregister(&gen2_ctl_dev);
3987f92363d1SSreekanth Reddy }
3988