Skip to content

Conversation

@leap-io
Copy link

@leap-io leap-io commented Feb 1, 2026

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.

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>
Copy link

@sourcery-ai sourcery-ai bot left a 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

@deepin-ci-robot
Copy link

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please assign avenger-285714 for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

Copy link

Copilot AI left a 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/scsi Kconfig/Makefile infrastructure.
  • Enables CONFIG_SCSI_LEAPRAID=m in 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.

Comment on lines +697 to +704
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);
Copy link

Copilot AI Feb 2, 2026

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.

Copilot uses AI. Check for mistakes.
dev_err(&adapter->pdev->dev,
"%s set phy attached hdl identify failed!\n",
__func__);
sas_phy_free(phy);
Copy link

Copilot AI Feb 2, 2026

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.

Suggested change
sas_phy_free(phy);
sas_phy_free(phy);
return -EFAULT;

Copilot uses AI. Check for mistakes.
Comment on lines +612 to +617
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;
Copy link

Copilot AI Feb 2, 2026

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.

Copilot uses AI. Check for mistakes.
data_out = dma_alloc_coherent(&adapter->pdev->dev,
h2c_size + c2h_size,
&h2c_dma_addr,
GFP_ATOMIC);
Copy link

Copilot AI Feb 2, 2026

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.

Suggested change
GFP_ATOMIC);
GFP_KERNEL);

Copilot uses AI. Check for mistakes.
Comment on lines +507 to +513
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,
Copy link

Copilot AI Feb 2, 2026

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.

Suggested change
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,

Copilot uses AI. Check for mistakes.

if (topo_node->hdl <= adapter->dev_topo.card.phys_num) {
if (!topo_node->card_phy[i].vphy) {
card_port->phy_mask |= BIT(i);
Copy link

Copilot AI Feb 2, 2026

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.

Suggested change
card_port->phy_mask |= BIT(i);
if (i < sizeof(card_port->phy_mask) * 8U)
card_port->phy_mask |= BIT(i);

Copilot uses AI. Check for mistakes.
Comment on lines +325 to +326
if (WARN_ON(ctl_sp_mpi_req->func == LEAPRAID_FUNC_SCSI_TMF))
return -EINVAL;
Copy link

Copilot AI Feb 2, 2026

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.

Suggested change
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;
}

Copilot uses AI. Check for mistakes.
Comment on lines +331 to +345
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) {
Copy link

Copilot AI Feb 2, 2026

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.

Copilot uses AI. Check for mistakes.
Comment on lines +642 to +645
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)) {
Copy link

Copilot AI Feb 2, 2026

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.

Copilot uses AI. Check for mistakes.

/* some requset and reply buffer size */
#define LEAPRAID_REQUEST_SIZE 128
#define LEAPRAID_REPLY_SIEZ 128
Copy link

Copilot AI Feb 2, 2026

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.

Suggested change
#define LEAPRAID_REPLY_SIEZ 128
#define LEAPRAID_REPLY_SIZE 128

Copilot uses AI. Check for mistakes.
Copy link
Member

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.

......How did this even compile

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants