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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 806 void leapraid_ctl_exit(void) 807 { 808 misc_deregister(&leapraid_ctl_dev); 809 } 810