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