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 { 176 struct leapraid_adapter *adapter; 177 struct Scsi_Host *shost; 178 179 spin_lock(&leapraid_adapter_lock); 180 list_for_each_entry(adapter, &leapraid_adapter_list, list) { 181 if (adapter->adapter_attr.id == adapter_id) { 182 if (READ_ONCE(adapter->access_ctrl.host_removing)) 183 break; 184 shost = adapter->shost; 185 if (!shost || !scsi_host_get(shost)) 186 break; 187 spin_unlock(&leapraid_adapter_lock); 188 return adapter; 189 } 190 } 191 spin_unlock(&leapraid_adapter_lock); 192 193 return NULL; 194 } 195 196 static void leapraid_ctl_put_adapter(struct leapraid_adapter *adapter) 197 { 198 if (adapter && adapter->shost) 199 scsi_host_put(adapter->shost); 200 } 201 202 static void leapraid_ctl_scsiio_cmd(struct leapraid_adapter *adapter, 203 void *ctl_sp_mpi_req, 204 u16 taskid, 205 dma_addr_t h2c_dma_addr, size_t h2c_size, 206 dma_addr_t c2h_dma_addr, size_t c2h_size, 207 u16 dev_hdl, void *psge) 208 { 209 struct leapraid_mpi_scsiio_req *scsiio_request = ctl_sp_mpi_req; 210 211 scsiio_request->sense_buffer_len = SCSI_SENSE_BUFFERSIZE; 212 scsiio_request->sense_buffer_low_add = 213 leapraid_get_sense_buffer_dma(adapter, taskid); 214 memset(&adapter->driver_cmds.ctl_cmd.sense, 215 0, SCSI_SENSE_BUFFERSIZE); 216 leapraid_build_ieee_sg(adapter, psge, h2c_dma_addr, 217 h2c_size, c2h_dma_addr, c2h_size); 218 if (scsiio_request->func == LEAPRAID_FUNC_SCSIIO) 219 leapraid_fire_scsi_io(adapter, taskid, dev_hdl); 220 else 221 leapraid_fire_task(adapter, taskid); 222 } 223 224 static int leapraid_ctl_smp_passthrough_cmd(struct leapraid_adapter *adapter, 225 void *ctl_sp_req, 226 u16 taskid, 227 dma_addr_t h2c_dma_addr, 228 size_t h2c_size, 229 dma_addr_t c2h_dma_addr, 230 size_t c2h_size, 231 void *psge, void *h2c) 232 { 233 struct leapraid_smp_passthrough_req *smp_pt_req = ctl_sp_req; 234 u8 *data; 235 236 if (!adapter->adapter_attr.enable_mp) 237 smp_pt_req->physical_port = LEAPRAID_DISABLE_MP_PORT_ID; 238 if (smp_pt_req->passthrough_flg & LEAPRAID_SMP_PT_FLAG_SGL_PTR) 239 data = (u8 *)&smp_pt_req->sgl; 240 else 241 data = h2c; 242 243 if (!(smp_pt_req->passthrough_flg & LEAPRAID_SMP_PT_FLAG_SGL_PTR) && 244 h2c_size <= 10) { 245 dev_err(&adapter->pdev->dev, 246 "%s: Invalid request size=%zu\n", 247 __func__, h2c_size); 248 return -EINVAL; 249 } 250 251 if (data[1] == SMP_PHY_CONTROL && 252 (data[10] == SMP_PHY_CONTROL_LINK_RESET || 253 data[10] == SMP_PHY_CONTROL_HARD_RESET)) 254 adapter->reset_desc.adapter_link_resetting = 1; 255 256 leapraid_build_ieee_sg(adapter, psge, h2c_dma_addr, 257 h2c_size, c2h_dma_addr, c2h_size); 258 leapraid_fire_task(adapter, taskid); 259 return 0; 260 } 261 262 static void leapraid_ctl_sas_io_unit_ctrl_cmd(struct leapraid_adapter *adapter, 263 void *ctl_sp_req, 264 dma_addr_t h2c_dma_addr, 265 size_t h2c_size, 266 dma_addr_t c2h_dma_addr, 267 size_t c2h_size, 268 void *psge, u16 taskid) 269 { 270 struct leapraid_sas_io_unit_ctrl_req *sas_io_unit_ctl_req = ctl_sp_req; 271 272 if (sas_io_unit_ctl_req->op == LEAPRAID_SAS_OP_PHY_HARD_RESET || 273 sas_io_unit_ctl_req->op == LEAPRAID_SAS_OP_PHY_LINK_RESET) 274 adapter->reset_desc.adapter_link_resetting = 1; 275 leapraid_build_mpi_sg(adapter, psge, h2c_dma_addr, 276 h2c_size, c2h_dma_addr, c2h_size); 277 leapraid_fire_task(adapter, taskid); 278 } 279 280 static int leapraid_ctl_do_command(struct leapraid_adapter *adapter, 281 struct leapraid_ioctl_command *karg, 282 void __user *mf) 283 { 284 struct leapraid_req *leap_mpi_req; 285 struct leapraid_req *ctl_sp_mpi_req; 286 u16 taskid; 287 void *h2c = NULL; 288 size_t h2c_size = 0; 289 dma_addr_t h2c_dma_addr = 0; 290 void *c2h = NULL; 291 size_t c2h_size = 0; 292 dma_addr_t c2h_dma_addr = 0; 293 void *psge; 294 unsigned long timeout; 295 u16 dev_hdl = LEAPRAID_INVALID_DEV_HANDLE; 296 bool issue_reset = false; 297 u32 data_sge_offset_bytes; 298 u32 sz; 299 int rc; 300 301 rc = leapraid_check_adapter_is_op(adapter, LEAPRAID_DB_WAIT_OP_SHORT, 302 __func__); 303 if (rc) 304 return rc; 305 306 leap_mpi_req = kzalloc(LEAPRAID_REQUEST_SIZE, GFP_KERNEL); 307 if (!leap_mpi_req) 308 return -ENOMEM; 309 310 if (karg->data_sge_offset > (UINT_MAX / LEAPRAID_SGE_OFFSET_SIZE)) { 311 dev_err(&adapter->pdev->dev, 312 "%s: Invalid data_sge_offset=%u\n", 313 __func__, karg->data_sge_offset); 314 rc = -EINVAL; 315 goto out_cleanup; 316 } 317 318 data_sge_offset_bytes = karg->data_sge_offset * 319 LEAPRAID_SGE_OFFSET_SIZE; 320 if (data_sge_offset_bytes > LEAPRAID_REQUEST_SIZE) { 321 dev_err(&adapter->pdev->dev, 322 "%s: Invalid data_sge_offset=%u\n", 323 __func__, karg->data_sge_offset); 324 rc = -EINVAL; 325 goto out_cleanup; 326 } 327 328 if (copy_from_user(leap_mpi_req, mf, data_sge_offset_bytes)) { 329 dev_err(&adapter->pdev->dev, 330 "%s: Failed to copy request message from user\n", 331 __func__); 332 rc = -EFAULT; 333 goto out_cleanup; 334 } 335 336 h2c_size = karg->h2c_size; 337 c2h_size = karg->c2h_size; 338 rc = leapraid_ctl_validate_sge_offset(adapter, leap_mpi_req, 339 data_sge_offset_bytes, 340 h2c_size, c2h_size); 341 if (rc) 342 goto out_cleanup; 343 344 taskid = adapter->driver_cmds.ctl_cmd.taskid; 345 346 adapter->driver_cmds.ctl_cmd.status = LEAPRAID_CMD_PENDING; 347 memset(&adapter->driver_cmds.ctl_cmd.reply, 0, LEAPRAID_REPLY_SIZE); 348 ctl_sp_mpi_req = leapraid_get_task_desc(adapter, taskid); 349 memset(ctl_sp_mpi_req, 0, LEAPRAID_REQUEST_SIZE); 350 memcpy(ctl_sp_mpi_req, leap_mpi_req, data_sge_offset_bytes); 351 352 if (ctl_sp_mpi_req->func == LEAPRAID_FUNC_SCSIIO || 353 ctl_sp_mpi_req->func == LEAPRAID_FUNC_SCSIIO_RAID_PASSTHROUGH || 354 ctl_sp_mpi_req->func == LEAPRAID_FUNC_SCSIIO_SATA_PASSTHROUGH) { 355 dev_hdl = le16_to_cpu(ctl_sp_mpi_req->func_dep1); 356 if (!dev_hdl || 357 dev_hdl > adapter->adapter_attr.features.max_dev_handle) { 358 dev_err(&adapter->pdev->dev, 359 "%s: Invalid device handle\n", __func__); 360 rc = -EINVAL; 361 goto out_cleanup; 362 } 363 } 364 365 if (WARN_ON(ctl_sp_mpi_req->func == LEAPRAID_FUNC_SCSI_TMF)) { 366 rc = -EINVAL; 367 goto out_cleanup; 368 } 369 370 if (h2c_size) { 371 h2c = dma_alloc_coherent(&adapter->pdev->dev, h2c_size, 372 &h2c_dma_addr, GFP_KERNEL); 373 if (!h2c) { 374 rc = -ENOMEM; 375 goto out_cleanup; 376 } 377 if (copy_from_user(h2c, karg->h2c_buf_ptr, h2c_size)) { 378 dev_err(&adapter->pdev->dev, 379 "%s: Failed to copy h2c from user\n", 380 __func__); 381 rc = -EFAULT; 382 goto out_cleanup; 383 } 384 } 385 if (c2h_size) { 386 c2h = dma_alloc_coherent(&adapter->pdev->dev, c2h_size, 387 &c2h_dma_addr, GFP_KERNEL); 388 if (!c2h) { 389 rc = -ENOMEM; 390 goto out_cleanup; 391 } 392 } 393 394 psge = (void *)ctl_sp_mpi_req + data_sge_offset_bytes; 395 init_completion(&adapter->driver_cmds.ctl_cmd.done); 396 397 switch (ctl_sp_mpi_req->func) { 398 case LEAPRAID_FUNC_SCSIIO: 399 case LEAPRAID_FUNC_SCSIIO_RAID_PASSTHROUGH: 400 leapraid_ctl_scsiio_cmd(adapter, ctl_sp_mpi_req, taskid, 401 h2c_dma_addr, h2c_size, 402 c2h_dma_addr, c2h_size, 403 dev_hdl, psge); 404 break; 405 case LEAPRAID_FUNC_SMP_PASSTHROUGH: 406 if (!h2c) { 407 rc = -EINVAL; 408 goto out_cleanup; 409 } 410 rc = leapraid_ctl_smp_passthrough_cmd(adapter, 411 ctl_sp_mpi_req, taskid, 412 h2c_dma_addr, h2c_size, 413 c2h_dma_addr, c2h_size, 414 psge, h2c); 415 if (rc) 416 goto out_cleanup; 417 break; 418 case LEAPRAID_FUNC_SCSIIO_SATA_PASSTHROUGH: 419 leapraid_build_ieee_sg(adapter, psge, h2c_dma_addr, h2c_size, 420 c2h_dma_addr, c2h_size); 421 leapraid_fire_task(adapter, taskid); 422 break; 423 case LEAPRAID_FUNC_FW_DOWNLOAD: 424 case LEAPRAID_FUNC_FW_UPLOAD: 425 leapraid_build_ieee_sg(adapter, psge, h2c_dma_addr, h2c_size, 426 c2h_dma_addr, c2h_size); 427 leapraid_fire_task(adapter, taskid); 428 break; 429 case LEAPRAID_FUNC_SAS_IO_UNIT_CTRL: 430 leapraid_ctl_sas_io_unit_ctrl_cmd(adapter, ctl_sp_mpi_req, 431 h2c_dma_addr, h2c_size, 432 c2h_dma_addr, c2h_size, 433 psge, taskid); 434 break; 435 default: 436 leapraid_build_mpi_sg(adapter, psge, h2c_dma_addr, 437 h2c_size, c2h_dma_addr, c2h_size); 438 leapraid_fire_task(adapter, taskid); 439 break; 440 } 441 442 timeout = karg->timeout; 443 if (timeout < LEAPRAID_CTL_CMD_TIMEOUT) 444 timeout = LEAPRAID_CTL_CMD_TIMEOUT; 445 if (!wait_for_completion_timeout(&adapter->driver_cmds.ctl_cmd.done, 446 timeout * HZ)) { 447 dev_err(&adapter->pdev->dev, 448 "%s: ctl_cmd timeout, status=0x%x\n", 449 __func__, adapter->driver_cmds.ctl_cmd.status); 450 leapraid_log_req_context(adapter, taskid, ctl_sp_mpi_req); 451 } 452 453 if ((leap_mpi_req->func == LEAPRAID_FUNC_SMP_PASSTHROUGH || 454 leap_mpi_req->func == LEAPRAID_FUNC_SAS_IO_UNIT_CTRL) && 455 adapter->reset_desc.adapter_link_resetting) 456 adapter->reset_desc.adapter_link_resetting = 0; 457 458 if (!(adapter->driver_cmds.ctl_cmd.status & LEAPRAID_CMD_DONE)) { 459 issue_reset = 460 leapraid_check_reset( 461 adapter->driver_cmds.ctl_cmd.status); 462 goto reset; 463 } 464 465 if (c2h_size && copy_to_user(karg->c2h_buf_ptr, c2h, c2h_size)) { 466 dev_err(&adapter->pdev->dev, 467 "%s: Failed to copy c2h to user\n", __func__); 468 rc = -ENODATA; 469 goto out_cleanup; 470 } 471 if (karg->max_rep_bytes) { 472 sz = min_t(u32, karg->max_rep_bytes, LEAPRAID_REPLY_SIZE); 473 if (copy_to_user(karg->rep_msg_buf_ptr, 474 &adapter->driver_cmds.ctl_cmd.reply, 475 sz)) { 476 dev_err(&adapter->pdev->dev, 477 "%s: Failed to copy reply to user\n", 478 __func__); 479 rc = -ENODATA; 480 goto out_cleanup; 481 } 482 } 483 484 if (karg->max_sense_bytes && 485 (leap_mpi_req->func == LEAPRAID_FUNC_SCSIIO || 486 leap_mpi_req->func == LEAPRAID_FUNC_SCSIIO_RAID_PASSTHROUGH)) { 487 if (!karg->sense_data_ptr) 488 goto out_cleanup; 489 490 sz = min_t(u32, karg->max_sense_bytes, SCSI_SENSE_BUFFERSIZE); 491 if (copy_to_user(karg->sense_data_ptr, 492 &adapter->driver_cmds.ctl_cmd.sense, 493 sz)) { 494 dev_err(&adapter->pdev->dev, 495 "%s: Failed to copy sense data to user\n", 496 __func__); 497 rc = -ENODATA; 498 goto out_cleanup; 499 } 500 } 501 reset: 502 if (issue_reset) { 503 rc = -ENODATA; 504 if (leap_mpi_req->func == LEAPRAID_FUNC_SCSIIO || 505 leap_mpi_req->func == 506 LEAPRAID_FUNC_SCSIIO_RAID_PASSTHROUGH || 507 leap_mpi_req->func == 508 LEAPRAID_FUNC_SCSIIO_SATA_PASSTHROUGH) { 509 dev_err(&adapter->pdev->dev, 510 "Fire tgt reset, hdl=0x%04x\n", 511 le16_to_cpu(leap_mpi_req->func_dep1)); 512 leapraid_issue_locked_tm( 513 adapter, 514 le16_to_cpu(leap_mpi_req->func_dep1), 0, 0, 0, 515 LEAPRAID_TM_TASKTYPE_TARGET_RESET, taskid, 516 LEAPRAID_TM_MSGFLAGS_LINK_RESET); 517 } else { 518 dev_info(&adapter->pdev->dev, 519 "%s:%d: call hard_reset\n", 520 __func__, __LINE__); 521 leapraid_hard_reset_handler(adapter, FULL_RESET); 522 } 523 } 524 out_cleanup: 525 if (c2h) 526 dma_free_coherent(&adapter->pdev->dev, c2h_size, 527 c2h, c2h_dma_addr); 528 if (h2c) 529 dma_free_coherent(&adapter->pdev->dev, h2c_size, 530 h2c, h2c_dma_addr); 531 kfree(leap_mpi_req); 532 adapter->driver_cmds.ctl_cmd.status = LEAPRAID_CMD_NOT_USED; 533 return rc; 534 } 535 536 static int leapraid_ctl_get_adapter_info(struct leapraid_adapter *adapter, 537 void __user *arg) 538 { 539 struct leapraid_ioctl_adapter_info *karg; 540 u8 revision; 541 int rc = 0; 542 543 karg = kzalloc_obj(*karg); 544 if (!karg) 545 return -ENOMEM; 546 547 pci_read_config_byte(adapter->pdev, PCI_CLASS_REVISION, &revision); 548 karg->revision = revision; 549 karg->pci_id = adapter->pdev->device; 550 karg->sub_dev = adapter->pdev->subsystem_device; 551 karg->sub_vendor = adapter->pdev->subsystem_vendor; 552 karg->pci_info.u.bits.bus = adapter->pdev->bus->number; 553 karg->pci_info.u.bits.dev = PCI_SLOT(adapter->pdev->devfn); 554 karg->pci_info.u.bits.func = PCI_FUNC(adapter->pdev->devfn); 555 karg->pci_info.seg_id = pci_domain_nr(adapter->pdev->bus); 556 karg->fw_ver = adapter->adapter_attr.features.fw_version; 557 558 snprintf(karg->driver_ver, sizeof(karg->driver_ver), "%s-%s", 559 LEAPRAID_DRIVER_NAME, LEAPRAID_DRIVER_VERSION); 560 561 karg->adapter_type = LEAPRAID_IOCTL_VERSION; 562 karg->bios_ver = adapter->adapter_attr.bios_version; 563 if (copy_to_user(arg, karg, 564 sizeof(struct leapraid_ioctl_adapter_info))) { 565 dev_err(&adapter->pdev->dev, 566 "%s: Failed to copy info to user\n", __func__); 567 rc = -EFAULT; 568 goto free_buf; 569 } 570 571 free_buf: 572 kfree(karg); 573 return rc; 574 } 575 576 static int leapraid_ctl_ioctl_main(struct file *file, unsigned int cmd, 577 void __user *arg) 578 { 579 struct leapraid_ioctl_header ioctl_header; 580 struct leapraid_adapter *adapter = NULL; 581 struct leapraid_ioctl_command __user *uarg; 582 struct leapraid_ioctl_command karg; 583 int rc = -ENOIOCTLCMD; 584 585 if (copy_from_user(&ioctl_header, arg, 586 sizeof(struct leapraid_ioctl_header))) { 587 pr_err("%s:%s: Failed to copy header from user\n", 588 LEAPRAID_DRIVER_NAME, __func__); 589 return -EFAULT; 590 } 591 592 adapter = leapraid_ctl_lookup_adapter(ioctl_header.adapter_id); 593 if (!adapter) 594 return -EFAULT; 595 596 if (atomic_read(&adapter->overheat_desc.thermal_alert)) { 597 dev_warn(&adapter->pdev->dev, 598 "%s: Failed, thermal_alert=%d\n", 599 __func__, 600 atomic_read(&adapter->overheat_desc.thermal_alert)); 601 rc = -EFAULT; 602 goto out_put; 603 } 604 605 mutex_lock(&adapter->access_ctrl.pci_access_lock); 606 607 rc = leapraid_check_adapter_is_op(adapter, LEAPRAID_DB_WAIT_OP_LONG, 608 __func__); 609 if (rc) 610 goto unlock; 611 612 if (!wait_event_timeout(adapter->access_ctrl.shost_recover_wq, 613 !adapter->access_ctrl.shost_recover_async, 614 LEAPRAID_WAIT_SHOST_RECOVERY * HZ)) { 615 dev_warn(&adapter->pdev->dev, 616 "Timeout waiting for shost recovery async\n"); 617 rc = -EAGAIN; 618 goto unlock; 619 } 620 621 if (adapter->access_ctrl.pcie_recovering || 622 adapter->scan_dev_desc.driver_loading || 623 adapter->access_ctrl.host_removing) { 624 rc = -EAGAIN; 625 goto unlock; 626 } 627 628 if (file->f_flags & O_NONBLOCK) { 629 if (!mutex_trylock(&adapter->driver_cmds.ctl_cmd.mutex)) { 630 rc = -EAGAIN; 631 goto unlock; 632 } 633 } else if (mutex_lock_interruptible(&adapter->driver_cmds 634 .ctl_cmd.mutex)) { 635 rc = -ERESTARTSYS; 636 goto unlock; 637 } 638 639 switch (_IOC_NR(cmd)) { 640 case LEAPRAID_ADAPTER_INFO: 641 if (_IOC_SIZE(cmd) == 642 sizeof(struct leapraid_ioctl_adapter_info)) 643 rc = leapraid_ctl_get_adapter_info(adapter, arg); 644 break; 645 case LEAPRAID_COMMAND: 646 if (copy_from_user(&karg, arg, sizeof(karg))) { 647 dev_err(&adapter->pdev->dev, 648 "%s: Failed to copy data from user\n", 649 __func__); 650 rc = -EFAULT; 651 break; 652 } 653 654 if (karg.hdr.adapter_id != ioctl_header.adapter_id) { 655 rc = -EINVAL; 656 break; 657 } 658 659 if (_IOC_SIZE(cmd) == sizeof(struct leapraid_ioctl_command)) { 660 uarg = arg; 661 rc = leapraid_ctl_do_command(adapter, &karg, 662 &uarg->mf); 663 if (rc) 664 dev_warn(&adapter->pdev->dev, 665 "%s: IOCTL cmd failed rc=%d\n", 666 __func__, rc); 667 } 668 break; 669 case LEAPRAID_EVENTQUERY: 670 case LEAPRAID_EVENTREPORT: 671 rc = 0; 672 break; 673 default: 674 dev_err(&adapter->pdev->dev, 675 "Unknown IOCTL opcode=0x%08x\n", cmd); 676 break; 677 } 678 mutex_unlock(&adapter->driver_cmds.ctl_cmd.mutex); 679 680 unlock: 681 mutex_unlock(&adapter->access_ctrl.pci_access_lock); 682 out_put: 683 leapraid_ctl_put_adapter(adapter); 684 return rc; 685 } 686 687 static long leapraid_ctl_ioctl(struct file *file, unsigned int cmd, 688 unsigned long arg) 689 { 690 return leapraid_ctl_ioctl_main(file, cmd, (void __user *)arg); 691 } 692 693 static void leapraid_fw_mmap_open(struct vm_area_struct *vma) 694 { 695 struct leapraid_adapter *adapter = vma->vm_private_data; 696 697 if (!adapter) 698 return; 699 700 get_device(&adapter->shost->shost_gendev); 701 atomic_inc(&adapter->fw_log_desc.mmap_refcnt); 702 } 703 704 static void leapraid_fw_mmap_close(struct vm_area_struct *vma) 705 { 706 struct leapraid_adapter *adapter = vma->vm_private_data; 707 708 if (!adapter) 709 return; 710 711 if (atomic_dec_and_test(&adapter->fw_log_desc.mmap_refcnt)) 712 wake_up(&adapter->fw_log_desc.mmap_waitq); 713 leapraid_ctl_put_adapter(adapter); 714 } 715 716 static const struct vm_operations_struct leapraid_fw_mmap_vm_ops = { 717 .open = leapraid_fw_mmap_open, 718 .close = leapraid_fw_mmap_close, 719 }; 720 721 static int leapraid_fw_mmap(struct file *filp, struct vm_area_struct *vma) 722 { 723 struct leapraid_adapter *adapter = NULL; 724 /* Userspace passes the adapter ID via vma->vm_pgoff. */ 725 u32 adapter_id = vma->vm_pgoff; 726 unsigned long length; 727 int rc = -EINVAL; 728 729 length = vma->vm_end - vma->vm_start; 730 731 adapter = leapraid_ctl_lookup_adapter(adapter_id); 732 if (!adapter) { 733 pr_err("%s: No adapter found!\n", __func__); 734 return -EINVAL; 735 } 736 737 if (READ_ONCE(adapter->access_ctrl.host_removing)) { 738 rc = -EAGAIN; 739 goto out_put; 740 } 741 742 if (length > (LEAPRAID_SYS_LOG_BUF_SIZE + 743 LEAPRAID_SYS_LOG_BUF_RESERVE)) { 744 dev_err(&adapter->pdev->dev, 745 "Requested mapping size is too large!\n"); 746 rc = -EINVAL; 747 goto out_put; 748 } 749 750 if (!adapter->fw_log_desc.fw_log_buffer) { 751 dev_err(&adapter->pdev->dev, "No log buffer!\n"); 752 rc = -EINVAL; 753 goto out_put; 754 } 755 756 vma->vm_pgoff = 0; 757 758 rc = dma_mmap_coherent(&adapter->pdev->dev, vma, 759 adapter->fw_log_desc.fw_log_buffer, 760 adapter->fw_log_desc.fw_log_buffer_dma, 761 length); 762 if (rc) { 763 dev_err(&adapter->pdev->dev, 764 "Failed to map memory to user space!\n"); 765 goto out_put; 766 } 767 768 vma->vm_private_data = adapter; 769 vma->vm_ops = &leapraid_fw_mmap_vm_ops; 770 leapraid_fw_mmap_open(vma); 771 772 rc = 0; 773 out_put: 774 leapraid_ctl_put_adapter(adapter); 775 return rc; 776 } 777 778 static const struct file_operations leapraid_ctl_fops = { 779 .owner = THIS_MODULE, 780 .unlocked_ioctl = leapraid_ctl_ioctl, 781 .mmap = leapraid_fw_mmap, 782 }; 783 784 static struct miscdevice leapraid_ctl_dev = { 785 .minor = MISC_DYNAMIC_MINOR, 786 .name = LEAPRAID_DEV_NAME, 787 .fops = &leapraid_ctl_fops, 788 }; 789 790 int leapraid_ctl_init(void) 791 { 792 if (misc_register(&leapraid_ctl_dev) < 0) { 793 pr_err("%s Can't register misc device\n", 794 LEAPRAID_DRIVER_NAME); 795 return -ENODEV; 796 } 797 return 0; 798 } 799 800 void leapraid_ctl_exit(void) 801 { 802 misc_deregister(&leapraid_ctl_dev); 803 } 804