-
Notifications
You must be signed in to change notification settings - Fork 107
scsi: leapraid: supports LeapRaid controller #1470
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: linux-6.18.y
Are you sure you want to change the base?
Conversation
The LeapRAID driver provides support for LeapRAID PCIe RAID controllers, enabling communication between the host operating system, firmware, and hardware for efficient storage management. The main source files are organized as follows: leapraid_os.c: Implements the scsi_host_template functions, PCIe device probing, and initialization routines, integrating the driver with the Linux SCSI subsystem. leapraid_func.c: Provides the core functional routines that handle low-level interactions with the controller firmware and hardware, including interrupt handling, topology management, and reset sequence processing, and other related operations. leapraid_app.c: Implements the ioctl interface, providing user-space tools access to device management and diagnostic operations. leapraid_transport.c: Interacts with the Linux SCSI transport layer to add SAS phys and ports. leapraid_func.h: Declares common data structures, constants, and function prototypes shared across the driver. leapraid.h: Provides global constants, register mappings, and interface definitions that facilitate communication between the driver and the controller firmware. The leapraid_probe function is called when the driver detects a supported LeapRAID PCIe device. It allocates and initializes the Scsi_Host structure, configures hardware and firmware interfaces, and registers the host adapter with the Linux SCSI mid-layer. After registration, the driver invokes scsi_scan_host() to initiate device discovery. The firmware then reports discovered logical and physical devices to the host through interrupt-driven events and synchronizes their operational states. leapraid_adapter is the core data structure that encapsulates all resources and runtime state information maintained during driver operation, described as follows: /** * struct leapraid_adapter - Main LeapRaid adapter structure * @list: List head for adapter management * @shost: SCSI host structure * @pdev: PCI device structure * @iomem_base: I/O memory mapped base address * @rep_msg_host_idx: Host index for reply messages * @mask_int: Interrupt masking flag * @timestamp_sync_cnt: Timestamp synchronization counter * @adapter_attr: Adapter attributes * @mem_desc: Memory descriptor * @driver_cmds: Driver commands * @dynamic_task_desc: Dynamic task descriptor * @fw_evt_s: Firmware event structure * @notification_desc: Notification descriptor * @reset_desc: Reset descriptor * @scan_dev_desc: Device scan descriptor * @access_ctrl: Access control * @fw_log_desc: Firmware log descriptor * @dev_topo: Device topology * @boot_devs: Boot devices * @smart_poll_desc: SMART polling descriptor */ struct leapraid_adapter { struct list_head list; struct Scsi_Host *shost; struct pci_dev *pdev; struct leapraid_reg_base __iomem *iomem_base; u32 rep_msg_host_idx; bool mask_int; u32 timestamp_sync_cnt; struct leapraid_adapter_attr adapter_attr; struct leapraid_mem_desc mem_desc; struct leapraid_driver_cmds driver_cmds; struct leapraid_dynamic_task_desc dynamic_task_desc; struct leapraid_fw_evt_struct fw_evt_s; struct leapraid_notification_desc notification_desc; struct leapraid_reset_desc reset_desc; struct leapraid_scan_dev_desc scan_dev_desc; struct leapraid_access_ctrl access_ctrl; struct leapraid_fw_log_desc fw_log_desc; struct leapraid_dev_topo dev_topo; struct leapraid_boot_devs boot_devs; struct leapraid_smart_poll_desc smart_poll_desc; }; Signed-off-by: Hao Dongdong <doubled@leap-io-kernel.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry @leap-io, your pull request is larger than the review limit of 150000 diff characters
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Introduces a new in-kernel SCSI driver to support LeapRAID controllers, integrating it into the Linux SCSI subsystem and enabling it in select Deepin desktop defconfigs.
Changes:
- Adds the LeapRAID driver implementation (core logic, OS glue, SAS transport integration, and user ioctl/mmap interface).
- Wires the new driver into
drivers/scsiKconfig/Makefile infrastructure. - Enables
CONFIG_SCSI_LEAPRAID=min Deepin desktop defconfigs (x86, arm64, loongarch).
Reviewed changes
Copilot reviewed 12 out of 13 changed files in this pull request and generated 14 comments.
Show a summary per file
| File | Description |
|---|---|
| drivers/scsi/leapraid/leapraid_func.c | Core driver logic (device management, firmware interaction, command paths). |
| drivers/scsi/leapraid/leapraid_os.c | OS/SCSI midlayer integration glue for the driver. |
| drivers/scsi/leapraid/leapraid_transport.c | SAS transport integration (ports/phys/rphy management, SMP handling). |
| drivers/scsi/leapraid/leapraid_app.c | User-facing misc device ioctl/mmap interface. |
| drivers/scsi/leapraid/leapraid_func.h | Driver internal API/types/constants shared across compilation units. |
| drivers/scsi/leapraid/leapraid.h | HW/firmware interface structures, constants, and message formats. |
| drivers/scsi/leapraid/Makefile | Builds LeapRAID objects into leapraid.ko. |
| drivers/scsi/leapraid/Kconfig | Adds CONFIG_SCSI_LEAPRAID configuration option. |
| drivers/scsi/Makefile | Adds LeapRAID subdirectory to SCSI build. |
| drivers/scsi/Kconfig | Sources LeapRAID Kconfig. |
| arch/x86/configs/deepin_x86_desktop_defconfig | Enables LeapRAID module by default for Deepin x86 desktop. |
| arch/arm64/configs/deepin_arm64_desktop_defconfig | Enables LeapRAID module by default for Deepin arm64 desktop. |
| arch/loongarch/configs/deepin_loongarch_desktop_defconfig | Enables LeapRAID module by default for Deepin loongarch desktop. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if (sas_port->remote_identify.device_type == | ||
| LEAPRAID_DEVTYP_EDGE_EXPANDER || | ||
| sas_port->remote_identify.device_type == | ||
| LEAPRAID_DEVTYP_FANOUT_EXPANDER) | ||
| leapraid_transport_exp_report_manu(adapter, | ||
| sas_port->remote_identify.sas_address, | ||
| rphy_to_expander_device(rphy), | ||
| card_port->port_id); |
Copilot
AI
Feb 2, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sas_port->remote_identify.device_type is a SAS transport enum (e.g., SAS_EDGE_EXPANDER_DEVICE), but it’s being compared against LEAPRAID_DEVTYP_* constants (device-info bitfield values). This condition will never be true, so expander manufacturer info is never queried. Compare against the SAS_*_EXPANDER_DEVICE values instead.
| dev_err(&adapter->pdev->dev, | ||
| "%s set phy attached hdl identify failed!\n", | ||
| __func__); | ||
| sas_phy_free(phy); |
Copilot
AI
Feb 2, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On attached-handle identify failure, the code frees phy but then continues and later calls leapraid_init_sas_or_exp_phy() / sas_phy_add(phy) on a freed pointer. Return an error (or goto a common cleanup path) immediately after sas_phy_free(phy) here.
| sas_phy_free(phy); | |
| sas_phy_free(phy); | |
| return -EFAULT; |
| if (sas_port->remote_identify.device_type == SAS_END_DEVICE) { | ||
| sas_dev = leapraid_get_sas_dev_by_addr(adapter, | ||
| sas_port->remote_identify.sas_address, | ||
| card_port); | ||
| if (!sas_dev) | ||
| return NULL; |
Copilot
AI
Feb 2, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If leapraid_get_sas_dev_by_addr() fails, this returns NULL after the SAS port has already been added and PHYs have been attached/marked assigned. This leaves the SAS transport objects and phy_is_assigned state inconsistent and leaks the sas_port. Refactor to a single error path that detaches PHYs, resets phy_is_assigned, and deletes/frees the port as needed.
| data_out = dma_alloc_coherent(&adapter->pdev->dev, | ||
| h2c_size + c2h_size, | ||
| &h2c_dma_addr, | ||
| GFP_ATOMIC); |
Copilot
AI
Feb 2, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
dma_alloc_coherent(..., GFP_ATOMIC) is used while holding transport_cmd.mutex. This path can sleep, so use GFP_KERNEL (or release the mutex before allocating) to avoid unnecessary allocation failures under memory pressure.
| GFP_ATOMIC); | |
| GFP_KERNEL); |
| ret = strscpy(karg->driver_ver, LEAPRAID_DRIVER_NAME, | ||
| sizeof(karg->driver_ver)); | ||
| strcat(karg->driver_ver, "-"); | ||
| strcat(karg->driver_ver, LEAPRAID_DRIVER_VERSION); | ||
| karg->adapter_type = LEAPRAID_IOCTL_VERSION; | ||
| karg->bios_ver = adapter->adapter_attr.bios_version; | ||
| if (copy_to_user(arg, karg, |
Copilot
AI
Feb 2, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Avoid strcat() here; it’s easy to regress into a buffer overflow if the constants change. Use strlcat()/strscpy() with bounds (or scnprintf() into driver_ver) instead.
| ret = strscpy(karg->driver_ver, LEAPRAID_DRIVER_NAME, | |
| sizeof(karg->driver_ver)); | |
| strcat(karg->driver_ver, "-"); | |
| strcat(karg->driver_ver, LEAPRAID_DRIVER_VERSION); | |
| karg->adapter_type = LEAPRAID_IOCTL_VERSION; | |
| karg->bios_ver = adapter->adapter_attr.bios_version; | |
| if (copy_to_user(arg, karg, | |
| ret = scnprintf(karg->driver_ver, sizeof(karg->driver_ver), | |
| "%s-%s", LEAPRAID_DRIVER_NAME, LEAPRAID_DRIVER_VERSION); | |
| karg->adapter_type = LEAPRAID_IOCTL_VERSION; | |
| karg->bios_ver = adapter->adapter_attr.bios_version; | |
| if (copy_to_user(arg, karg, | |
| karg->bios_ver = adapter->adapter_attr.bios_version; | |
| if (copy_to_user(arg, karg, |
|
|
||
| if (topo_node->hdl <= adapter->dev_topo.card.phys_num) { | ||
| if (!topo_node->card_phy[i].vphy) { | ||
| card_port->phy_mask |= BIT(i); |
Copilot
AI
Feb 2, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
card_port->phy_mask is a u32, but BIT(i) is used with i iterating up to topo_node->phys_num (a runtime u8 from firmware/config). If phys_num >= 32, BIT(i) becomes undefined and the mask cannot represent all PHYs. Add an explicit bounds check (like other SAS drivers) or switch phy_mask/vphys_mask to a real bitmap sized by phys_num.
| card_port->phy_mask |= BIT(i); | |
| if (i < sizeof(card_port->phy_mask) * 8U) | |
| card_port->phy_mask |= BIT(i); |
| if (WARN_ON(ctl_sp_mpi_req->func == LEAPRAID_FUNC_SCSI_TMF)) | ||
| return -EINVAL; |
Copilot
AI
Feb 2, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This WARN_ON() path returns directly, bypassing the common out: cleanup. That leaks leap_mpi_req (and potentially DMA buffers) and leaves ctl_cmd.status set to LEAPRAID_CMD_PENDING. Convert this to rc = -EINVAL; goto out; (or similar) so all resources and state are cleaned up consistently.
| if (WARN_ON(ctl_sp_mpi_req->func == LEAPRAID_FUNC_SCSI_TMF)) | |
| return -EINVAL; | |
| if (WARN_ON(ctl_sp_mpi_req->func == LEAPRAID_FUNC_SCSI_TMF)) { | |
| rc = -EINVAL; | |
| goto out; | |
| } |
| h2c = dma_alloc_coherent(&adapter->pdev->dev, h2c_size, | ||
| &h2c_dma_addr, GFP_ATOMIC); | ||
| if (!h2c) { | ||
| rc = -ENOMEM; | ||
| goto out; | ||
| } | ||
| if (copy_from_user(h2c, karg->h2c_buf_ptr, h2c_size)) { | ||
| rc = -EFAULT; | ||
| goto out; | ||
| } | ||
| } | ||
| if (c2h_size) { | ||
| c2h = dma_alloc_coherent(&adapter->pdev->dev, | ||
| c2h_size, &c2h_dma_addr, GFP_ATOMIC); | ||
| if (!c2h) { |
Copilot
AI
Feb 2, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These dma_alloc_coherent(..., GFP_ATOMIC) allocations are performed in an ioctl context (process context) and after taking mutexes, so GFP_ATOMIC is unnecessarily restrictive. Use GFP_KERNEL to reduce the chance of spurious -ENOMEM failures.
| pfn = virt_to_phys(adapter->fw_log_desc.fw_log_buffer) >> PAGE_SHIFT; | ||
|
|
||
| if (remap_pfn_range(vma, vma->vm_start, pfn, length, | ||
| vma->vm_page_prot)) { |
Copilot
AI
Feb 2, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fw_log_buffer is allocated with dma_alloc_coherent(), but mmap uses virt_to_phys() + remap_pfn_range(). This is not portable for DMA memory and can map the wrong pages / wrong cache attributes on some architectures. Use dma_mmap_coherent() with fw_log_buffer_dma instead.
|
|
||
| /* some requset and reply buffer size */ | ||
| #define LEAPRAID_REQUEST_SIZE 128 | ||
| #define LEAPRAID_REPLY_SIEZ 128 |
Copilot
AI
Feb 2, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo in constant name: LEAPRAID_REPLY_SIEZ should be LEAPRAID_REPLY_SIZE for clarity/consistency. Since this is a new driver, it’s best to fix the name now and update all references.
| #define LEAPRAID_REPLY_SIEZ 128 | |
| #define LEAPRAID_REPLY_SIZE 128 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo in constant name:
LEAPRAID_REPLY_SIEZshould beLEAPRAID_REPLY_SIZEfor clarity/consistency. Since this is a new driver, it’s best to fix the name now and update all references.
......How did this even compile
This commit is to support LeapRAID controllers.
RAID controllers support RAID 0/1/5/6/10/50/60 modes;
RAID support SAS/SATA HDD/SSD.