xref: /linux/drivers/scsi/leapraid/leapraid_app.c (revision 08dbfad3f5040f5bdb6c529da20d6d4e81fefd72)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2026 LeapIO Tech Inc.
4  *
5  * LeapRAID storage and RAID controller driver.
6  */
7 #include <linux/compat.h>
8 #include <linux/module.h>
9 #include <linux/miscdevice.h>
10 
11 #include "leapraid_func.h"
12 
13 /* IOCTL device file name. */
14 #define LEAPRAID_DEV_NAME       "leapraid_ctl"
15 
16 /* IOCTL version. */
17 #define LEAPRAID_IOCTL_VERSION  0x07
18 
19 /* IOCTL commands. */
20 #define LEAPRAID_ADAPTER_INFO   17
21 #define LEAPRAID_COMMAND        20
22 #define LEAPRAID_EVENTQUERY     21
23 #define LEAPRAID_EVENTREPORT    23
24 
25 /**
26  * struct leapraid_ioctl_header - IOCTL command header
27  *
28  * @adapter_id : Adapter identifier.
29  * @port_number: Port identifier.
30  * @max_data_size: Maximum data size for transfer.
31  */
32 struct leapraid_ioctl_header {
33 	u32 adapter_id;
34 	u32 port_number;
35 	u32 max_data_size;
36 };
37 
38 /**
39  * struct leapraid_ioctl_diag_reset - Diagnostic reset request
40  *
41  * @hdr: Common IOCTL header.
42  */
43 struct leapraid_ioctl_diag_reset {
44 	struct leapraid_ioctl_header hdr;
45 };
46 
47 /**
48  * struct leapraid_ioctl_pci_info - PCI device information
49  *
50  * @u: Union holding PCI bus/device/function information.
51  * @u.bits.dev: PCI device number.
52  * @u.bits.func: PCI function number.
53  * @u.bits.bus: PCI bus number.
54  * @u.word: Combined representation of PCI BDF.
55  * @seg_id: PCI segment identifier.
56  */
57 struct leapraid_ioctl_pci_info {
58 	union {
59 		struct {
60 			u32 dev:5;
61 			u32 func:3;
62 			u32 bus:24;
63 		} bits;
64 		u32 word;
65 	} u;
66 	u32 seg_id;
67 };
68 
69 /**
70  * struct leapraid_ioctl_adapter_info - Adapter information for IOCTL
71  *
72  * @hdr: IOCTL header.
73  * @adapter_type: Adapter type identifier.
74  * @port_number: Port number.
75  * @pci_id: PCI device ID.
76  * @revision: Revision number.
77  * @sub_dev: Subsystem device ID.
78  * @sub_vendor: Subsystem vendor ID.
79  * @r0: Reserved.
80  * @fw_ver: Firmware version.
81  * @bios_ver: BIOS version.
82  * @driver_ver: Driver version.
83  * @r1: Reserved.
84  * @scsi_id: SCSI ID.
85  * @r2: Reserved.
86  * @pci_info: PCI information structure.
87  */
88 struct leapraid_ioctl_adapter_info {
89 	struct leapraid_ioctl_header hdr;
90 	u32 adapter_type;
91 	u32 port_number;
92 	u32 pci_id;
93 	u32 revision;
94 	u32 sub_dev;
95 	u32 sub_vendor;
96 	u32 r0;
97 	u32 fw_ver;
98 	u32 bios_ver;
99 	u8 driver_ver[32];
100 	u8 r1;
101 	u8 scsi_id;
102 	u16 r2;
103 	struct leapraid_ioctl_pci_info pci_info;
104 };
105 
106 /**
107  * struct leapraid_ioctl_command - IOCTL command structure
108  *
109  * @hdr: IOCTL header.
110  * @timeout: Command timeout.
111  * @rep_msg_buf_ptr: User pointer to reply message buffer.
112  * @c2h_buf_ptr: User pointer to card-to-host data buffer.
113  * @h2c_buf_ptr: User pointer to host-to-card data buffer.
114  * @sense_data_ptr: User pointer to sense data buffer.
115  * @max_rep_bytes: Maximum reply bytes.
116  * @c2h_size: Card-to-host data size.
117  * @h2c_size: Host-to-card data size.
118  * @max_sense_bytes: Maximum sense data bytes.
119  * @data_sge_offset: Data SGE offset.
120  * @mf: Message frame data (flexible array).
121  */
122 struct leapraid_ioctl_command {
123 	struct leapraid_ioctl_header hdr;
124 	u32 timeout;
125 	void __user *rep_msg_buf_ptr;
126 	void __user *c2h_buf_ptr;
127 	void __user *h2c_buf_ptr;
128 	void __user *sense_data_ptr;
129 	u32 max_rep_bytes;
130 	u32 c2h_size;
131 	u32 h2c_size;
132 	u32 max_sense_bytes;
133 	u32 data_sge_offset;
134 	u8 mf[];
135 };
136 
leapraid_ctl_validate_sge_offset(struct leapraid_adapter * adapter,const struct leapraid_req * req,u32 offset_bytes,size_t h2c_size,size_t c2h_size)137 static int leapraid_ctl_validate_sge_offset(struct leapraid_adapter *adapter,
138 					    const struct leapraid_req *req,
139 					    u32 offset_bytes,
140 					    size_t h2c_size,
141 					    size_t c2h_size)
142 {
143 	size_t sge_bytes;
144 
145 	switch (req->func) {
146 	case LEAPRAID_FUNC_SCSIIO:
147 	case LEAPRAID_FUNC_SCSIIO_RAID_PASSTHROUGH:
148 	case LEAPRAID_FUNC_SMP_PASSTHROUGH:
149 	case LEAPRAID_FUNC_SCSIIO_SATA_PASSTHROUGH:
150 	case LEAPRAID_FUNC_FW_DOWNLOAD:
151 	case LEAPRAID_FUNC_FW_UPLOAD:
152 		sge_bytes = LEAPRAID_IEEE_SGE64_ENTRY_SIZE;
153 		break;
154 	default:
155 		sge_bytes = adapter->adapter_attr.use_32_dma_mask ?
156 			sizeof(struct leapraid_sge_simple32) :
157 			sizeof(struct leapraid_sge_simple64);
158 		break;
159 	}
160 
161 	if (h2c_size && c2h_size)
162 		sge_bytes *= 2;
163 
164 	if (offset_bytes > LEAPRAID_REQUEST_SIZE - sge_bytes) {
165 		dev_err(&adapter->pdev->dev,
166 			"%s: Invalid offset_bytes=%u for func=0x%x\n",
167 			__func__, offset_bytes, req->func);
168 		return -EINVAL;
169 	}
170 
171 	return 0;
172 }
173 
leapraid_ctl_lookup_adapter(int adapter_id,bool track_mmap)174 static struct leapraid_adapter *leapraid_ctl_lookup_adapter(int adapter_id,
175 							    bool track_mmap)
176 {
177 	struct leapraid_adapter *adapter;
178 	struct Scsi_Host *shost;
179 
180 	spin_lock(&leapraid_adapter_lock);
181 	list_for_each_entry(adapter, &leapraid_adapter_list, list) {
182 		if (adapter->adapter_attr.id == adapter_id) {
183 			if (READ_ONCE(adapter->access_ctrl.host_removing))
184 				break;
185 			shost = adapter->shost;
186 			if (!shost || !scsi_host_get(shost))
187 				break;
188 			if (track_mmap)
189 				atomic_inc(&adapter->fw_log_desc.mmap_refcnt);
190 			spin_unlock(&leapraid_adapter_lock);
191 			return adapter;
192 		}
193 	}
194 	spin_unlock(&leapraid_adapter_lock);
195 
196 	return NULL;
197 }
198 
leapraid_ctl_put_adapter(struct leapraid_adapter * adapter)199 static void leapraid_ctl_put_adapter(struct leapraid_adapter *adapter)
200 {
201 	if (adapter && adapter->shost)
202 		scsi_host_put(adapter->shost);
203 }
204 
leapraid_ctl_scsiio_cmd(struct leapraid_adapter * adapter,void * ctl_sp_mpi_req,u16 taskid,dma_addr_t h2c_dma_addr,size_t h2c_size,dma_addr_t c2h_dma_addr,size_t c2h_size,u16 dev_hdl,void * psge)205 static void leapraid_ctl_scsiio_cmd(struct leapraid_adapter *adapter,
206 				    void *ctl_sp_mpi_req,
207 				    u16 taskid,
208 				    dma_addr_t h2c_dma_addr, size_t h2c_size,
209 				    dma_addr_t c2h_dma_addr, size_t c2h_size,
210 				    u16 dev_hdl, void *psge)
211 {
212 	struct leapraid_mpi_scsiio_req *scsiio_request = ctl_sp_mpi_req;
213 
214 	scsiio_request->sense_buffer_len = SCSI_SENSE_BUFFERSIZE;
215 	scsiio_request->sense_buffer_low_add =
216 		leapraid_get_sense_buffer_dma(adapter, taskid);
217 	memset(&adapter->driver_cmds.ctl_cmd.sense,
218 	       0, SCSI_SENSE_BUFFERSIZE);
219 	leapraid_build_ieee_sg(adapter, psge, h2c_dma_addr,
220 			       h2c_size, c2h_dma_addr, c2h_size);
221 	if (scsiio_request->func == LEAPRAID_FUNC_SCSIIO)
222 		leapraid_fire_scsi_io(adapter, taskid, dev_hdl);
223 	else
224 		leapraid_fire_task(adapter, taskid);
225 }
226 
leapraid_ctl_smp_passthrough_cmd(struct leapraid_adapter * adapter,void * ctl_sp_req,u16 taskid,dma_addr_t h2c_dma_addr,size_t h2c_size,dma_addr_t c2h_dma_addr,size_t c2h_size,void * psge,void * h2c)227 static int leapraid_ctl_smp_passthrough_cmd(struct leapraid_adapter *adapter,
228 					    void *ctl_sp_req,
229 					    u16 taskid,
230 					    dma_addr_t h2c_dma_addr,
231 					    size_t h2c_size,
232 					    dma_addr_t c2h_dma_addr,
233 					    size_t c2h_size,
234 					    void *psge, void *h2c)
235 {
236 	struct leapraid_smp_passthrough_req *smp_pt_req = ctl_sp_req;
237 	u8 *data;
238 
239 	if (!adapter->adapter_attr.enable_mp)
240 		smp_pt_req->physical_port = LEAPRAID_DISABLE_MP_PORT_ID;
241 	if (smp_pt_req->passthrough_flg & LEAPRAID_SMP_PT_FLAG_SGL_PTR)
242 		data = (u8 *)&smp_pt_req->sgl;
243 	else
244 		data = h2c;
245 
246 	if (!(smp_pt_req->passthrough_flg & LEAPRAID_SMP_PT_FLAG_SGL_PTR) &&
247 	    h2c_size <= 10) {
248 		dev_err(&adapter->pdev->dev,
249 			"%s: Invalid request size=%zu\n",
250 			__func__, h2c_size);
251 		return -EINVAL;
252 	}
253 
254 	if (data[1] == SMP_PHY_CONTROL &&
255 	    (data[10] == SMP_PHY_CONTROL_LINK_RESET ||
256 	     data[10] == SMP_PHY_CONTROL_HARD_RESET))
257 		adapter->reset_desc.adapter_link_resetting = 1;
258 
259 	leapraid_build_ieee_sg(adapter, psge, h2c_dma_addr,
260 			       h2c_size, c2h_dma_addr, c2h_size);
261 	leapraid_fire_task(adapter, taskid);
262 	return 0;
263 }
264 
leapraid_ctl_sas_io_unit_ctrl_cmd(struct leapraid_adapter * adapter,void * ctl_sp_req,dma_addr_t h2c_dma_addr,size_t h2c_size,dma_addr_t c2h_dma_addr,size_t c2h_size,void * psge,u16 taskid)265 static void leapraid_ctl_sas_io_unit_ctrl_cmd(struct leapraid_adapter *adapter,
266 					      void *ctl_sp_req,
267 					      dma_addr_t h2c_dma_addr,
268 					      size_t h2c_size,
269 					      dma_addr_t c2h_dma_addr,
270 					      size_t c2h_size,
271 					      void *psge, u16 taskid)
272 {
273 	struct leapraid_sas_io_unit_ctrl_req *sas_io_unit_ctl_req = ctl_sp_req;
274 
275 	if (sas_io_unit_ctl_req->op == LEAPRAID_SAS_OP_PHY_HARD_RESET ||
276 	    sas_io_unit_ctl_req->op == LEAPRAID_SAS_OP_PHY_LINK_RESET)
277 		adapter->reset_desc.adapter_link_resetting = 1;
278 	leapraid_build_mpi_sg(adapter, psge, h2c_dma_addr,
279 			      h2c_size, c2h_dma_addr, c2h_size);
280 	leapraid_fire_task(adapter, taskid);
281 }
282 
leapraid_ctl_do_command(struct leapraid_adapter * adapter,struct leapraid_ioctl_command * karg,void __user * mf)283 static int leapraid_ctl_do_command(struct leapraid_adapter *adapter,
284 				   struct leapraid_ioctl_command *karg,
285 				   void __user *mf)
286 {
287 	struct leapraid_req *leap_mpi_req;
288 	struct leapraid_req *ctl_sp_mpi_req;
289 	u16 taskid;
290 	void *h2c = NULL;
291 	size_t h2c_size = 0;
292 	dma_addr_t h2c_dma_addr = 0;
293 	void *c2h = NULL;
294 	size_t c2h_size = 0;
295 	dma_addr_t c2h_dma_addr = 0;
296 	void *psge;
297 	unsigned long timeout;
298 	u16 dev_hdl = LEAPRAID_INVALID_DEV_HANDLE;
299 	bool issue_reset = false;
300 	u32 data_sge_offset_bytes;
301 	u32 sz;
302 	int rc;
303 
304 	rc = leapraid_check_adapter_is_op(adapter, LEAPRAID_DB_WAIT_OP_SHORT,
305 					  __func__);
306 	if (rc)
307 		return rc;
308 
309 	leap_mpi_req = kzalloc(LEAPRAID_REQUEST_SIZE, GFP_KERNEL);
310 	if (!leap_mpi_req)
311 		return -ENOMEM;
312 
313 	if (karg->data_sge_offset > (UINT_MAX / LEAPRAID_SGE_OFFSET_SIZE)) {
314 		dev_err(&adapter->pdev->dev,
315 			"%s: Invalid data_sge_offset=%u\n",
316 			__func__, karg->data_sge_offset);
317 		rc = -EINVAL;
318 		goto out_cleanup;
319 	}
320 
321 	data_sge_offset_bytes = karg->data_sge_offset *
322 				LEAPRAID_SGE_OFFSET_SIZE;
323 	if (data_sge_offset_bytes > LEAPRAID_REQUEST_SIZE) {
324 		dev_err(&adapter->pdev->dev,
325 			"%s: Invalid data_sge_offset=%u\n",
326 			__func__, karg->data_sge_offset);
327 		rc = -EINVAL;
328 		goto out_cleanup;
329 	}
330 
331 	if (copy_from_user(leap_mpi_req, mf, data_sge_offset_bytes)) {
332 		dev_err(&adapter->pdev->dev,
333 			"%s: Failed to copy request message from user\n",
334 			__func__);
335 		rc = -EFAULT;
336 		goto out_cleanup;
337 	}
338 
339 	h2c_size = karg->h2c_size;
340 	c2h_size = karg->c2h_size;
341 	rc = leapraid_ctl_validate_sge_offset(adapter, leap_mpi_req,
342 					      data_sge_offset_bytes,
343 					      h2c_size, c2h_size);
344 	if (rc)
345 		goto out_cleanup;
346 
347 	taskid = adapter->driver_cmds.ctl_cmd.taskid;
348 
349 	adapter->driver_cmds.ctl_cmd.status = LEAPRAID_CMD_PENDING;
350 	memset(&adapter->driver_cmds.ctl_cmd.reply, 0, LEAPRAID_REPLY_SIZE);
351 	ctl_sp_mpi_req = leapraid_get_task_desc(adapter, taskid);
352 	memset(ctl_sp_mpi_req, 0, LEAPRAID_REQUEST_SIZE);
353 	memcpy(ctl_sp_mpi_req, leap_mpi_req, data_sge_offset_bytes);
354 
355 	if (ctl_sp_mpi_req->func == LEAPRAID_FUNC_SCSIIO ||
356 	    ctl_sp_mpi_req->func == LEAPRAID_FUNC_SCSIIO_RAID_PASSTHROUGH ||
357 	    ctl_sp_mpi_req->func == LEAPRAID_FUNC_SCSIIO_SATA_PASSTHROUGH) {
358 		dev_hdl = le16_to_cpu(ctl_sp_mpi_req->func_dep1);
359 		if (!dev_hdl ||
360 		    dev_hdl > adapter->adapter_attr.features.max_dev_handle) {
361 			dev_err(&adapter->pdev->dev,
362 				"%s: Invalid device handle\n", __func__);
363 			rc = -EINVAL;
364 			goto out_cleanup;
365 		}
366 	}
367 
368 	if (WARN_ON(ctl_sp_mpi_req->func == LEAPRAID_FUNC_SCSI_TMF)) {
369 		rc = -EINVAL;
370 		goto out_cleanup;
371 	}
372 
373 	if (h2c_size) {
374 		h2c = dma_alloc_coherent(&adapter->pdev->dev, h2c_size,
375 					 &h2c_dma_addr, GFP_KERNEL);
376 		if (!h2c) {
377 			rc = -ENOMEM;
378 			goto out_cleanup;
379 		}
380 		if (copy_from_user(h2c, karg->h2c_buf_ptr, h2c_size)) {
381 			dev_err(&adapter->pdev->dev,
382 				"%s: Failed to copy h2c from user\n",
383 				__func__);
384 			rc = -EFAULT;
385 			goto out_cleanup;
386 		}
387 	}
388 	if (c2h_size) {
389 		c2h = dma_alloc_coherent(&adapter->pdev->dev, c2h_size,
390 					 &c2h_dma_addr, GFP_KERNEL);
391 		if (!c2h) {
392 			rc = -ENOMEM;
393 			goto out_cleanup;
394 		}
395 	}
396 
397 	psge = (void *)ctl_sp_mpi_req + data_sge_offset_bytes;
398 	init_completion(&adapter->driver_cmds.ctl_cmd.done);
399 
400 	switch (ctl_sp_mpi_req->func) {
401 	case LEAPRAID_FUNC_SCSIIO:
402 	case LEAPRAID_FUNC_SCSIIO_RAID_PASSTHROUGH:
403 		leapraid_ctl_scsiio_cmd(adapter, ctl_sp_mpi_req, taskid,
404 					h2c_dma_addr, h2c_size,
405 					c2h_dma_addr, c2h_size,
406 					dev_hdl, psge);
407 		break;
408 	case LEAPRAID_FUNC_SMP_PASSTHROUGH:
409 		if (!h2c) {
410 			rc = -EINVAL;
411 			goto out_cleanup;
412 		}
413 		rc = leapraid_ctl_smp_passthrough_cmd(adapter,
414 						      ctl_sp_mpi_req, taskid,
415 						      h2c_dma_addr, h2c_size,
416 						      c2h_dma_addr, c2h_size,
417 						      psge, h2c);
418 		if (rc)
419 			goto out_cleanup;
420 		break;
421 	case LEAPRAID_FUNC_SCSIIO_SATA_PASSTHROUGH:
422 		leapraid_build_ieee_sg(adapter, psge, h2c_dma_addr, h2c_size,
423 				       c2h_dma_addr, c2h_size);
424 		leapraid_fire_task(adapter, taskid);
425 		break;
426 	case LEAPRAID_FUNC_FW_DOWNLOAD:
427 	case LEAPRAID_FUNC_FW_UPLOAD:
428 		leapraid_build_ieee_sg(adapter, psge, h2c_dma_addr, h2c_size,
429 				       c2h_dma_addr, c2h_size);
430 		leapraid_fire_task(adapter, taskid);
431 		break;
432 	case LEAPRAID_FUNC_SAS_IO_UNIT_CTRL:
433 		leapraid_ctl_sas_io_unit_ctrl_cmd(adapter, ctl_sp_mpi_req,
434 						  h2c_dma_addr, h2c_size,
435 						  c2h_dma_addr, c2h_size,
436 						  psge, taskid);
437 		break;
438 	default:
439 		leapraid_build_mpi_sg(adapter, psge, h2c_dma_addr,
440 				      h2c_size, c2h_dma_addr, c2h_size);
441 		leapraid_fire_task(adapter, taskid);
442 		break;
443 	}
444 
445 	timeout = karg->timeout;
446 	if (timeout < LEAPRAID_CTL_CMD_TIMEOUT)
447 		timeout = LEAPRAID_CTL_CMD_TIMEOUT;
448 	if (!wait_for_completion_timeout(&adapter->driver_cmds.ctl_cmd.done,
449 					 timeout * HZ)) {
450 		dev_err(&adapter->pdev->dev,
451 			"%s: ctl_cmd timeout, status=0x%x\n",
452 			__func__, adapter->driver_cmds.ctl_cmd.status);
453 		leapraid_log_req_context(adapter, taskid, ctl_sp_mpi_req);
454 	}
455 
456 	if ((leap_mpi_req->func == LEAPRAID_FUNC_SMP_PASSTHROUGH ||
457 	     leap_mpi_req->func == LEAPRAID_FUNC_SAS_IO_UNIT_CTRL) &&
458 	    adapter->reset_desc.adapter_link_resetting)
459 		adapter->reset_desc.adapter_link_resetting = 0;
460 
461 	if (!(adapter->driver_cmds.ctl_cmd.status & LEAPRAID_CMD_DONE)) {
462 		issue_reset =
463 			leapraid_check_reset(
464 				adapter->driver_cmds.ctl_cmd.status);
465 		goto reset;
466 	}
467 
468 	if (c2h_size && copy_to_user(karg->c2h_buf_ptr, c2h, c2h_size)) {
469 		dev_err(&adapter->pdev->dev,
470 			"%s: Failed to copy c2h to user\n", __func__);
471 		rc = -ENODATA;
472 		goto out_cleanup;
473 	}
474 	if (karg->max_rep_bytes) {
475 		sz = min_t(u32, karg->max_rep_bytes, LEAPRAID_REPLY_SIZE);
476 		if (copy_to_user(karg->rep_msg_buf_ptr,
477 				 &adapter->driver_cmds.ctl_cmd.reply,
478 				 sz)) {
479 			dev_err(&adapter->pdev->dev,
480 				"%s: Failed to copy reply to user\n",
481 				__func__);
482 			rc = -ENODATA;
483 			goto out_cleanup;
484 		}
485 	}
486 
487 	if (karg->max_sense_bytes &&
488 	    (leap_mpi_req->func == LEAPRAID_FUNC_SCSIIO ||
489 	     leap_mpi_req->func == LEAPRAID_FUNC_SCSIIO_RAID_PASSTHROUGH)) {
490 		if (!karg->sense_data_ptr)
491 			goto out_cleanup;
492 
493 		sz = min_t(u32, karg->max_sense_bytes, SCSI_SENSE_BUFFERSIZE);
494 		if (copy_to_user(karg->sense_data_ptr,
495 				 &adapter->driver_cmds.ctl_cmd.sense,
496 				 sz)) {
497 			dev_err(&adapter->pdev->dev,
498 				"%s: Failed to copy sense data to user\n",
499 				__func__);
500 			rc = -ENODATA;
501 			goto out_cleanup;
502 		}
503 	}
504 reset:
505 	if (issue_reset) {
506 		rc = -ENODATA;
507 		if (leap_mpi_req->func == LEAPRAID_FUNC_SCSIIO ||
508 		    leap_mpi_req->func ==
509 		    LEAPRAID_FUNC_SCSIIO_RAID_PASSTHROUGH ||
510 		    leap_mpi_req->func ==
511 		    LEAPRAID_FUNC_SCSIIO_SATA_PASSTHROUGH) {
512 			dev_err(&adapter->pdev->dev,
513 				"Fire tgt reset, hdl=0x%04x\n",
514 				le16_to_cpu(leap_mpi_req->func_dep1));
515 			leapraid_issue_locked_tm(
516 				adapter,
517 				le16_to_cpu(leap_mpi_req->func_dep1), 0, 0, 0,
518 				LEAPRAID_TM_TASKTYPE_TARGET_RESET, taskid,
519 				LEAPRAID_TM_MSGFLAGS_LINK_RESET);
520 		} else {
521 			dev_info(&adapter->pdev->dev,
522 				 "%s:%d: call hard_reset\n",
523 				 __func__, __LINE__);
524 			leapraid_hard_reset_handler(adapter, FULL_RESET);
525 		}
526 	}
527 out_cleanup:
528 	if (c2h)
529 		dma_free_coherent(&adapter->pdev->dev, c2h_size,
530 				  c2h, c2h_dma_addr);
531 	if (h2c)
532 		dma_free_coherent(&adapter->pdev->dev, h2c_size,
533 				  h2c, h2c_dma_addr);
534 	kfree(leap_mpi_req);
535 	adapter->driver_cmds.ctl_cmd.status = LEAPRAID_CMD_NOT_USED;
536 	return rc;
537 }
538 
leapraid_ctl_get_adapter_info(struct leapraid_adapter * adapter,void __user * arg)539 static int leapraid_ctl_get_adapter_info(struct leapraid_adapter *adapter,
540 					 void __user *arg)
541 {
542 	struct leapraid_ioctl_adapter_info *karg;
543 	u8 revision;
544 	int rc = 0;
545 
546 	karg = kzalloc_obj(*karg);
547 	if (!karg)
548 		return -ENOMEM;
549 
550 	pci_read_config_byte(adapter->pdev, PCI_CLASS_REVISION, &revision);
551 	karg->revision = revision;
552 	karg->pci_id = adapter->pdev->device;
553 	karg->sub_dev = adapter->pdev->subsystem_device;
554 	karg->sub_vendor = adapter->pdev->subsystem_vendor;
555 	karg->pci_info.u.bits.bus = adapter->pdev->bus->number;
556 	karg->pci_info.u.bits.dev = PCI_SLOT(adapter->pdev->devfn);
557 	karg->pci_info.u.bits.func = PCI_FUNC(adapter->pdev->devfn);
558 	karg->pci_info.seg_id = pci_domain_nr(adapter->pdev->bus);
559 	karg->fw_ver = adapter->adapter_attr.features.fw_version;
560 
561 	snprintf(karg->driver_ver, sizeof(karg->driver_ver), "%s-%s",
562 		 LEAPRAID_DRIVER_NAME, LEAPRAID_DRIVER_VERSION);
563 
564 	karg->adapter_type = LEAPRAID_IOCTL_VERSION;
565 	karg->bios_ver = adapter->adapter_attr.bios_version;
566 	if (copy_to_user(arg, karg,
567 			 sizeof(struct leapraid_ioctl_adapter_info))) {
568 		dev_err(&adapter->pdev->dev,
569 			"%s: Failed to copy info to user\n", __func__);
570 		rc = -EFAULT;
571 		goto free_buf;
572 	}
573 
574 free_buf:
575 	kfree(karg);
576 	return rc;
577 }
578 
leapraid_ctl_ioctl_main(struct file * file,unsigned int cmd,void __user * arg)579 static int leapraid_ctl_ioctl_main(struct file *file, unsigned int cmd,
580 				   void __user *arg)
581 {
582 	struct leapraid_ioctl_header ioctl_header;
583 	struct leapraid_adapter *adapter = NULL;
584 	struct leapraid_ioctl_command __user *uarg;
585 	struct leapraid_ioctl_command karg;
586 	int rc = -ENOIOCTLCMD;
587 
588 	if (copy_from_user(&ioctl_header, arg,
589 			   sizeof(struct leapraid_ioctl_header))) {
590 		pr_err("%s:%s: Failed to copy header from user\n",
591 		       LEAPRAID_DRIVER_NAME, __func__);
592 		return -EFAULT;
593 	}
594 
595 	adapter = leapraid_ctl_lookup_adapter(ioctl_header.adapter_id, false);
596 	if (!adapter)
597 		return -EFAULT;
598 
599 	if (atomic_read(&adapter->overheat_desc.thermal_alert)) {
600 		dev_warn(&adapter->pdev->dev,
601 			 "%s: Failed, thermal_alert=%d\n",
602 			 __func__,
603 			 atomic_read(&adapter->overheat_desc.thermal_alert));
604 		rc = -EFAULT;
605 		goto out_put;
606 	}
607 
608 	mutex_lock(&adapter->access_ctrl.pci_access_lock);
609 
610 	rc = leapraid_check_adapter_is_op(adapter, LEAPRAID_DB_WAIT_OP_LONG,
611 					  __func__);
612 	if (rc)
613 		goto unlock;
614 
615 	if (!wait_event_timeout(adapter->access_ctrl.shost_recover_wq,
616 				!adapter->access_ctrl.shost_recover_async,
617 				LEAPRAID_WAIT_SHOST_RECOVERY * HZ)) {
618 		dev_warn(&adapter->pdev->dev,
619 			 "Timeout waiting for shost recovery async\n");
620 		rc = -EAGAIN;
621 		goto unlock;
622 	}
623 
624 	if (adapter->access_ctrl.pcie_recovering ||
625 	    adapter->scan_dev_desc.driver_loading ||
626 	    adapter->access_ctrl.host_removing) {
627 		rc = -EAGAIN;
628 		goto unlock;
629 	}
630 
631 	if (file->f_flags & O_NONBLOCK) {
632 		if (!mutex_trylock(&adapter->driver_cmds.ctl_cmd.mutex)) {
633 			rc = -EAGAIN;
634 			goto unlock;
635 		}
636 	} else if (mutex_lock_interruptible(&adapter->driver_cmds
637 					    .ctl_cmd.mutex)) {
638 		rc = -ERESTARTSYS;
639 		goto unlock;
640 	}
641 
642 	switch (_IOC_NR(cmd)) {
643 	case LEAPRAID_ADAPTER_INFO:
644 		if (_IOC_SIZE(cmd) ==
645 		    sizeof(struct leapraid_ioctl_adapter_info))
646 			rc = leapraid_ctl_get_adapter_info(adapter, arg);
647 		break;
648 	case LEAPRAID_COMMAND:
649 		if (copy_from_user(&karg, arg, sizeof(karg))) {
650 			dev_err(&adapter->pdev->dev,
651 				"%s: Failed to copy data from user\n",
652 				__func__);
653 			rc = -EFAULT;
654 			break;
655 		}
656 
657 		if (karg.hdr.adapter_id != ioctl_header.adapter_id) {
658 			rc = -EINVAL;
659 			break;
660 		}
661 
662 		if (_IOC_SIZE(cmd) == sizeof(struct leapraid_ioctl_command)) {
663 			uarg = arg;
664 			rc = leapraid_ctl_do_command(adapter, &karg,
665 						     &uarg->mf);
666 			if (rc)
667 				dev_warn(&adapter->pdev->dev,
668 					 "%s: IOCTL cmd failed rc=%d\n",
669 					 __func__, rc);
670 		}
671 		break;
672 	case LEAPRAID_EVENTQUERY:
673 	case LEAPRAID_EVENTREPORT:
674 		rc = 0;
675 		break;
676 	default:
677 		dev_err(&adapter->pdev->dev,
678 			"Unknown IOCTL opcode=0x%08x\n", cmd);
679 		break;
680 	}
681 	mutex_unlock(&adapter->driver_cmds.ctl_cmd.mutex);
682 
683 unlock:
684 	mutex_unlock(&adapter->access_ctrl.pci_access_lock);
685 out_put:
686 	leapraid_ctl_put_adapter(adapter);
687 	return rc;
688 }
689 
leapraid_ctl_ioctl(struct file * file,unsigned int cmd,unsigned long arg)690 static long leapraid_ctl_ioctl(struct file *file, unsigned int cmd,
691 			       unsigned long arg)
692 {
693 	return leapraid_ctl_ioctl_main(file, cmd, (void __user *)arg);
694 }
695 
leapraid_fw_mmap_open(struct vm_area_struct * vma)696 static void leapraid_fw_mmap_open(struct vm_area_struct *vma)
697 {
698 	struct leapraid_adapter *adapter = vma->vm_private_data;
699 
700 	if (!adapter)
701 		return;
702 
703 	get_device(&adapter->shost->shost_gendev);
704 	atomic_inc(&adapter->fw_log_desc.mmap_refcnt);
705 }
706 
leapraid_fw_mmap_close(struct vm_area_struct * vma)707 static void leapraid_fw_mmap_close(struct vm_area_struct *vma)
708 {
709 	struct leapraid_adapter *adapter = vma->vm_private_data;
710 
711 	if (!adapter)
712 		return;
713 
714 	if (atomic_dec_and_test(&adapter->fw_log_desc.mmap_refcnt))
715 		wake_up(&adapter->fw_log_desc.mmap_waitq);
716 	leapraid_ctl_put_adapter(adapter);
717 }
718 
719 static const struct vm_operations_struct leapraid_fw_mmap_vm_ops = {
720 	.open = leapraid_fw_mmap_open,
721 	.close = leapraid_fw_mmap_close,
722 };
723 
leapraid_fw_mmap(struct file * filp,struct vm_area_struct * vma)724 static int leapraid_fw_mmap(struct file *filp, struct vm_area_struct *vma)
725 {
726 	struct leapraid_adapter *adapter = NULL;
727 	/* Userspace passes the adapter ID via vma->vm_pgoff. */
728 	u32 adapter_id = vma->vm_pgoff;
729 	unsigned long length;
730 	int rc = -EINVAL;
731 
732 	length = vma->vm_end - vma->vm_start;
733 
734 	adapter = leapraid_ctl_lookup_adapter(adapter_id, true);
735 	if (!adapter) {
736 		pr_err("%s: No adapter found!\n", __func__);
737 		return -EINVAL;
738 	}
739 
740 	if (READ_ONCE(adapter->access_ctrl.host_removing)) {
741 		rc = -EAGAIN;
742 		goto out_put;
743 	}
744 
745 	if (length > (LEAPRAID_SYS_LOG_BUF_SIZE +
746 		      LEAPRAID_SYS_LOG_BUF_RESERVE)) {
747 		dev_err(&adapter->pdev->dev,
748 			"Requested mapping size is too large!\n");
749 		rc = -EINVAL;
750 		goto out_put;
751 	}
752 
753 	if (!adapter->fw_log_desc.fw_log_buffer) {
754 		dev_err(&adapter->pdev->dev, "No log buffer!\n");
755 		rc = -EINVAL;
756 		goto out_put;
757 	}
758 
759 	vma->vm_pgoff = 0;
760 
761 	rc = dma_mmap_coherent(&adapter->pdev->dev, vma,
762 			       adapter->fw_log_desc.fw_log_buffer,
763 			       adapter->fw_log_desc.fw_log_buffer_dma,
764 			       length);
765 	if (rc) {
766 		dev_err(&adapter->pdev->dev,
767 			"Failed to map memory to user space!\n");
768 		goto out_put;
769 	}
770 
771 	vma->vm_private_data = adapter;
772 	vma->vm_ops = &leapraid_fw_mmap_vm_ops;
773 	leapraid_fw_mmap_open(vma);
774 
775 	rc = 0;
776 out_put:
777 	if (adapter &&
778 	    atomic_dec_and_test(&adapter->fw_log_desc.mmap_refcnt))
779 		wake_up(&adapter->fw_log_desc.mmap_waitq);
780 	leapraid_ctl_put_adapter(adapter);
781 	return rc;
782 }
783 
784 static const struct file_operations leapraid_ctl_fops = {
785 	.owner = THIS_MODULE,
786 	.unlocked_ioctl = leapraid_ctl_ioctl,
787 	.mmap = leapraid_fw_mmap,
788 };
789 
790 static struct miscdevice leapraid_ctl_dev = {
791 	.minor = MISC_DYNAMIC_MINOR,
792 	.name = LEAPRAID_DEV_NAME,
793 	.fops = &leapraid_ctl_fops,
794 };
795 
leapraid_ctl_init(void)796 int leapraid_ctl_init(void)
797 {
798 	if (misc_register(&leapraid_ctl_dev) < 0) {
799 		pr_err("%s Can't register misc device\n",
800 		       LEAPRAID_DRIVER_NAME);
801 		return -ENODEV;
802 	}
803 	return 0;
804 }
805 
leapraid_ctl_exit(void)806 void leapraid_ctl_exit(void)
807 {
808 	misc_deregister(&leapraid_ctl_dev);
809 }
810