ufs: fix POST_CHANGE pairing and AHIT race condition
Subsystems (6)
[email protected]
maintainerv2 cover ufs: fix POST_CHANGE pairing and AHIT race condition
From: Peter Wang <[email protected]>
Patch 1 fixes a bug where POST_CHANGE was skipped on a failed gear switch, leaving the host in an inconsistent state if resources acquired in PRE_CHANGE were never released.
Patch 2 fixes a race between the sysfs AHIT update path and the MediaTek host driver's power mode change path. A mutex and depth counter are introduced to serialize AHIT register access and ensure AHIT is correctly restored after the last disabler completes.
The two patches are related: patch 1 guarantees POST_CHANGE is always called, ensuring the depth counter introduced in patch 2 is always properly decremented.
Peter Wang (2):
ufs: always notify POST_CHANGE even on gear switch failure
ufs: serialize AHIT register access between sysfs and host driver
drivers/ufs/core/ufshcd.c | 22 +++++++++++++++++++--- drivers/ufs/host/ufs-exynos.c | 4 +++- drivers/ufs/host/ufs-mediatek.c | 16 ++++++++++++---- drivers/ufs/host/ufshcd-pci.c | 3 ++- include/ufs/ufshcd.h | 8 ++++++++ 5 files changed, 44 insertions(+), 9 deletions(-)
Signature · 1 line
2.45.2
[email protected]
maintainerPATCH v2 1/2 ufs: always notify POST_CHANGE even on gear switch failure
From: Peter Wang <[email protected]>
Previously, POST_CHANGE was only notified on a successful gear switch. This could leave the host in an inconsistent state if resources were acquired in PRE_CHANGE (e.g. disabling auto-hibern8) but never released due to a missing POST_CHANGE.
Fix this by always calling POST_CHANGE regardless of the gear switch result. On failure, pass dev_req_params = NULL to signal that there is nothing to apply; hosts that receive NULL simply skip their post work.
Update the affected vendor drivers (ufs-exynos and ufshcd-pci) to guard their POST_CHANGE logic with a NULL check so they correctly handle the failure case.
--- drivers/ufs/core/ufshcd.c | 8 ++++++-- drivers/ufs/host/ufs-exynos.c | 4 +++- drivers/ufs/host/ufshcd-pci.c | 3 ++- 3 files changed, 11 insertions(+), 4 deletions(-)
drivers/ufs/core/ufshcd.c +6 -2
@@ -4979,8 +4979,12 @@ int ufshcd_change_power_mode(struct ufs_hba *hba, ret =ufshcd_dme_change_power_mode (hba, pwr_mode, pmc_policy); -if (!ret) -ufshcd_vops_pwr_change_notify (hba,POST_CHANGE , pwr_mode); +/* +* Always notify POST_CHANGE to pair with PRE_CHANGE, even on failure. +* On failure, pass dev_req_params = NULL to indicate nothing to apply. +* POST_CHANGE return value is advisory and does not mask @ret. +*/ +ufshcd_vops_pwr_change_notify (hba,POST_CHANGE , ret ?NULL : pwr_mode);return ret; }
drivers/ufs/host/ufs-exynos.c +3 -1
@@ -1782,7 +1782,9 @@ static int exynos_ufs_pwr_change_notify(struct ufs_hba *hba, ret =exynos_ufs_pre_pwr_mode (hba, dev_req_params);break ;case POST_CHANGE : - ret =exynos_ufs_post_pwr_mode (hba, dev_req_params); +/* NULL when the gear switch failed: nothing to apply */ +if (dev_req_params) + ret =exynos_ufs_post_pwr_mode (hba, dev_req_params);break ; }
drivers/ufs/host/ufshcd-pci.c +2 -1
@@ -166,7 +166,8 @@ static int ufs_intel_lkf_pwr_change_notify(struct ufs_hba *hba,ufs_intel_set_lanes (hba,2 );break ;case POST_CHANGE : -if (ufshcd_is_hs_mode (dev_req_params)) { +/* NULL when the gear switch failed: nothing to apply */ +if (dev_req_params &&ufshcd_is_hs_mode (dev_req_params)) {u32 peer_granularity;usleep_range (1000 ,1250 );
Signature · 1 line
2.45.2
[email protected]
AI reviewRe: [PATCH v2 1/2] ufs: always notify POST_CHANGE even on gear switch failure
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [Medium] Passing `NULL` for `dev_req_params` on failure causes spurious error logs in unmodified vendor…
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] Passing NULL for dev_req_params on failure causes spurious error logs in unmodified vendor drivers (ufs-qcom, ufs-hisi) and destroys the context needed for proper resource rollback. --
commit e9e864935f979762e71567d19e93d8a30870f23b
Author: Peter Wang <[email protected]>
ufs: always notify POST_CHANGE even on gear switch failure
This commit modifies ufshcd_change_power_mode() to always notify POST_CHANGE, even if the gear switch fails. On failure, it passes NULL for dev_req_params and updates ufs-exynos and ufshcd-pci to handle the NULL argument.
Quoted 6 lines
drivers/ufs/core/ufshcd.c +0
-0@@ -5003,8 +5003,12 @@ int ufshcd_change_power_mode(struct ufs_hba *hba,
drivers/ufs/core/ufshcd.c int ufshcd_change_power_mode(struct ufs_hba *hba, · line 5011
Quoted 10 lines
drivers/ufs/core/ufshcd.c +6
-2ret =ufshcd_dme_change_power_mode (hba, pwr_mode, pmc_policy); -if (!ret) -ufshcd_vops_pwr_change_notify (hba,POST_CHANGE , pwr_mode); +/* +* Always notify POST_CHANGE to pair with PRE_CHANGE, even on failure. +* On failure, pass dev_req_params = NULL to indicate nothing to apply. +* POST_CHANGE return value is advisory and does not mask @ret. +*/ +ufshcd_vops_pwr_change_notify (hba,POST_CHANGE , ret ?NULL : pwr_mode);
[Severity: Medium]
Will passing NULL for dev_req_params on failure cause issues for unmodified vendor drivers?
Looking at ufs_qcom_pwr_change_notify() in drivers/ufs/host/ufs-qcom.c, it has an early check that will trap this NULL argument and log a spurious error before any POST_CHANGE cleanup can execute:
drivers/ufs/host/ufs-qcom.c:ufs_qcom_pwr_change_notify() {
if (!dev_req_params) {
pr_err("%s: incoming dev_req_params is NULL\n", __func__);
return -EINVAL;
}
...
}Similarly, ufs_hisi_pwr_change_notify() in drivers/ufs/host/ufs-hisi.c will also log a spurious error on every power mode change failure:
drivers/ufs/host/ufs-hisi.c:ufs_hisi_pwr_change_notify() {
if (!dev_req_params) {
dev_err(hba->dev,
"%s: incoming dev_req_params is NULL\n", __func__);
ret = -EINVAL;
goto out;
}
...
}Additionally, does passing NULL here destroy the context needed for proper resource rollback?
For instance, in ufs_qcom_pwr_change_notify(), resources are acquired in PRE_CHANGE based on the dev_req_params:
drivers/ufs/host/ufs-qcom.c:ufs_qcom_pwr_change_notify() {
...
/* enable the device ref clock before changing to HS mode */
if (!ufshcd_is_hs_mode(&hba->pwr_info) &&
ufshcd_is_hs_mode(dev_req_params))
ufs_qcom_dev_ref_clk_ctrl(host, true);
...
}By omitting the original parameters on failure, the target drivers are prevented from using the requested mode context in POST_CHANGE to safely revert their state.
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=1
Peter Wang (王信友)
maintainerRe: [PATCH v2 1/2] ufs: always notify POST_CHANGE even on gear switch failure
On Mon, 2026-09-14 at 09:02 +0000, [email protected] wrote
Quoted 25 lines
[Severity: Medium]
Will passing NULL fordev_req_paramson failure cause issues for unmodified
vendor drivers?Looking at
ufs_qcom_pwr_change_notify()indrivers/ufs/host/ufs-qcom.c, it
has an early check that will trap this NULL argument and log a spurious error
before anyPOST_CHANGEcleanup can execute:drivers/ufs/host/ufs-qcom.c:ufs_qcom_pwr_change_notify() { if (!dev_req_params) { pr_err("%s: incoming dev_req_params is NULL\n", __func__); return -EINVAL; } ... }Similarly,
ufs_hisi_pwr_change_notify()indrivers/ufs/host/ufs-hisi.cwill
also log a spurious error on every power mode change failure:
Quoted 11 lines
drivers/ufs/host/ufs-hisi.c:ufs_hisi_pwr_change_notify() {
if (!dev_req_params) {
dev_err(hba->dev,
"%s: incoming dev_req_params is NULL\n",
__func__);
ret = -EINVAL;
goto out;
}
...
}Yes, both the qcom and hisi host drivers ignore NULL and only print an error log that indicates a power‑mode‑change failure.
Quoted 8 lines
Additionally, does passing NULL here destroy the context needed for proper
resource rollback?For instance, in
ufs_qcom_pwr_change_notify(), resources are acquired inPRE_CHANGEbased on thedev_req_params:
This patch doesn't change the behavior of the qcom driver.
Thanks
Peter
[email protected]
maintainerPATCH v2 2/2 ufs: serialize AHIT register access between sysfs and host driver
In reply to [email protected]From: Peter Wang <[email protected]>
A race exists between ufshcd_auto_hibern8_update() and ufs_mtk_pwr_change_notify() when both paths concurrently access REG_AUTO_HIBERNATE_IDLE_TIMER. Additionally, the static local variable used to save/restore AHIT in the power change path is not re-entrant and may hold a stale value if a sysfs write races with a gear change.
Introduce ahit_mutex and ahit_disable_depth in struct ufs_hba to serialize AHIT register access. The depth counter tracks how many host-driver paths have forced AHIT off; sysfs writes are suppressed while it is non-zero and the register is restored from hba->ahit only when the last disabler drops it to zero.
--- drivers/ufs/core/ufshcd.c | 14 +++++++++++++- drivers/ufs/host/ufs-mediatek.c | 16 ++++++++++++---- include/ufs/ufshcd.h | 8 ++++++++ 3 files changed, 33 insertions(+), 5 deletions(-)
drivers/ufs/core/ufshcd.c +13 -1
@@ -4748,7 +4748,17 @@ void ufshcd_auto_hibern8_update(struct ufs_hba *hba, u32 ahit)if (!pm_runtime_suspended (&hba->ufs_device_wlun->sdev_gendev)) {ufshcd_rpm_get_sync (hba);ufshcd_hold (hba); -ufshcd_configure_auto_hibern8 (hba); +/* +* Serialize with the host driver's AHIT control. Skip the +* register write while the driver has AHIT forced off; the +* driver programs hba->ahit back when it re-enables it. +* Mutex is taken here (not across the rpm calls above) so it +* never blocks a resume that the driver's path may need. +*/ +mutex_lock (&hba->ahit_mutex); +if (!hba->ahit_disable_depth) +ufshcd_configure_auto_hibern8 (hba); +mutex_unlock (&hba->ahit_mutex);ufshcd_release (hba);ufshcd_rpm_put_sync (hba); }
@@ -11272,6 +11282,8 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)mutex_init (&hba->wb_mutex); +mutex_init (&hba->ahit_mutex); +init_rwsem (&hba->clk_scaling_lock);ufshcd_init_clk_gating (hba);
drivers/ufs/host/ufs-mediatek.c +12 -4
@@ -1507,19 +1507,27 @@ static int ufs_mtk_pwr_change_notify(struct ufs_hba *hba, struct ufs_pa_layer_attr *dev_req_params) {int ret =0 ; -static u32 reg;switch (stage) {case PRE_CHANGE :if (ufshcd_is_auto_hibern8_supported (hba)) { - reg =ufshcd_readl (hba,REG_AUTO_HIBERNATE_IDLE_TIMER ); +/* Block sysfs AHIT writes while we force AHIT off */ +mutex_lock (&hba->ahit_mutex); + hba->ahit_disable_depth++; +mutex_unlock (&hba->ahit_mutex);ufs_mtk_auto_hibern8_disable (hba); } ret =ufs_mtk_pre_pwr_change (hba, dev_req_params);break ;case POST_CHANGE : -if (ufshcd_is_auto_hibern8_supported (hba)) -ufshcd_writel (hba, reg,REG_AUTO_HIBERNATE_IDLE_TIMER ); +if (ufshcd_is_auto_hibern8_supported (hba)) { +mutex_lock (&hba->ahit_mutex); +/* re-enable only when the last disabler drops off */ +if (!--hba->ahit_disable_depth) +ufshcd_writel (hba, hba->ahit, +REG_AUTO_HIBERNATE_IDLE_TIMER ); +mutex_unlock (&hba->ahit_mutex); + }break ;default : ret = -EINVAL ;
include/ufs/ufshcd.h +8 -0
@@ -1132,6 +1132,14 @@ struct ufs_hba {/* Auto-Hibernate Idle Timer register value */ u32 ahit; +/* Serializes AHIT register access between sysfs and the host driver */ +struct mutex ahit_mutex; +/* +* Nesting count of host-driver paths that have AHIT forced off. +* Non-zero blocks sysfs AHIT writes; AHIT is reprogrammed only when +* the last disabler drops it back to zero. Guarded by ahit_mutex. +*/ +int ahit_disable_depth;unsigned long outstanding_tasks;spinlock_t outstanding_lock;
Signature · 1 line
2.45.2
[email protected]
AI reviewRe: [PATCH v2 2/2] ufs: serialize AHIT register access between sysfs and host driver
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
Pre-existing issues:
- [High] The ufshcd_auto_hibern8_update() function ignores the return value of ufshcd_rpm_get_sync(). If the runtime PM resume fails, it proceeds to unsafely write to the REG_AUTO_HIBERNATE_IDLE_TIMER register on a potentially suspended device.
- [High] Potential NULL pointer dereference in ufshcd_auto_hibern8_update if called via sysfs before the device WLUN is fully initialized.
- [High] The UFS core driver registers a shared IRQ (IRQF_SHARED) but calls disable_irq() during runtime suspend instead of synchronize_irq(), and fails to verify device activity in its interrupt handler. --
commit 10d014f6ed545565699c7988448c9337de308b17
Author: Peter Wang <[email protected]>
ufs: serialize AHIT register access between sysfs and host driver
This commit introduces a mutex and a depth counter to serialize AHIT register access between the host driver and sysfs writes. This prevents stale values from being programmed if a sysfs write races with a gear change.
drivers/ufs/core/ufshcd.c void ufshcd_auto_hibern8_update(struct ufs_hba *hba, u32 ahit) · line 4772
Quoted 6 lines
drivers/ufs/core/ufshcd.c +0
-0@@ -4772,7 +4772,17 @@ void ufshcd_auto_hibern8_update(struct ufs_hba *hba, u32 ahit)if (!pm_runtime_suspended (&hba->ufs_device_wlun->sdev_gendev)) {
[Severity: High]
This isn't a bug introduced by this patch, but can this dereference a NULL pointer?
Sysfs attributes are exposed in ufshcd_init() via ufs_sysfs_add_nodes() before hba->ufs_device_wlun is allocated. The initialization is deferred to the ufshcd_async_scan worker.
If a user writes to the sysfs node before ufshcd_add_lus() allocates hba->ufs_device_wlun, can auto_hibern8_store() call ufshcd_auto_hibern8_update() and locklessly dereference a NULL pointer here?
drivers/ufs/core/ufshcd.c void ufshcd_auto_hibern8_update(struct ufs_hba *hba, u32 ahit) · line 4749
Quoted 1 line
drivers/ufs/core/ufshcd.c +0
-0ufshcd_rpm_get_sync (hba);
[Severity: High]
This is a pre-existing issue, but is it safe to ignore the return value of ufshcd_rpm_get_sync() here?
If the runtime PM resume fails (e.g., due to a power domain failure or device removal), pm_runtime_get_sync() returns a negative error code.
Does ignoring this error allow the function to proceed and write to REG_AUTO_HIBERNATE_IDLE_TIMER on a potentially suspended device, causing a synchronous external abort?
Quoted 6 lines
drivers/ufs/core/ufshcd.c +4
-1ufshcd_hold (hba); -ufshcd_configure_auto_hibern8 (hba); +/* +* Serialize with the host driver's AHIT control. Skip the +* register write while the driver has AHIT forced off; the +* driver programs hba->ahit back when it re-enables it.
drivers/ufs/core/ufshcd.c void ufshcd_auto_hibern8_update(struct ufs_hba *hba, u32 ahit) · line 4764
Quoted 10 lines
drivers/ufs/core/ufshcd.c +7
-0+* Mutex is taken here (not across the rpm calls above) so it +* never blocks a resume that the driver's path may need. +*/ +mutex_lock (&hba->ahit_mutex); +if (!hba->ahit_disable_depth) +ufshcd_configure_auto_hibern8 (hba); +mutex_unlock (&hba->ahit_mutex);ufshcd_release (hba);ufshcd_rpm_put_sync (hba); }
[ ... ]
[Severity: High]
This is a pre-existing issue, but does the UFS core driver handle shared IRQs correctly?
The driver registers its IRQ with IRQF_SHARED. When the UFS controller enters runtime suspend, ufshcd_suspend() disables the interrupt line entirely:
drivers/ufs/core/ufshcd.c:ufshcd_suspend() {
...
ufshcd_disable_irq(hba);
...
}Does calling disable_irq() mask interrupts for any other devices sharing the line? Should this use synchronize_irq() instead?
Additionally, ufshcd_intr() reads the hardware register unconditionally:
drivers/ufs/core/ufshcd.c:ufshcd_intr() {
...
last_intr_status = intr_status = ufshcd_readl(hba, REG_INTERRUPT_STATUS);
...
}Can this access powered-off hardware if the interrupt belongs to another device on the same shared line? Should this verify the device is actively powered using pm_runtime_get_if_active() before accessing registers?
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=2
Peter Wang (王信友)
maintainerRe: [PATCH v2 2/2] ufs: serialize AHIT register access between sysfs and host driver
Quoted 10 lines · On Mon, 2026-09-14 at 09:13 +0000, [email protected] wrote:
[Severity: High]
This isn't a bug introduced by this patch, but can this dereference a NULL pointer?Sysfs attributes are exposed in
ufshcd_init()viaufs_sysfs_add_nodes()
beforehba->ufs_device_wlunis allocated. The initialization is deferred
to theufshcd_async_scanworker.
Quoted 5 lines
If a user writes to the sysfs node before
ufshcd_add_lus()allocateshba->ufs_device_wlun, canauto_hibern8_store()callufshcd_auto_hibern8_update()and locklessly dereference a NULL pointer here?
This patch focuses on the current issue.
The previous issue can be addressed with a separate patch, but not with this one.
Quoted 7 lines
Quoted 1 line
ufshcd_rpm_get_sync(hba);[Severity: High]
This is a pre-existing issue, but is it safe to ignore the return value
ofufshcd_rpm_get_sync()here?
Quoted 9 lines
If the runtime PM resume fails (e.g., due to a power domain failure or
device removal),pm_runtime_get_sync()returns a negative error code.Does ignoring this error allow the function to proceed and write to
REG_AUTO_HIBERNATE_IDLE_TIMERon a potentially suspended device, causing a
synchronous external abort?
Same, pre-existing issue should be addressed with a separate patch.
Quoted 24 lines
Quoted 21 lines
ufshcd_hold(hba);drivers/ufs/core/ufshcd.c +2
-1-ufshcd_configure_auto_hibern8 (hba); +/* +* Serialize with the host driver's AHIT control. Skip the
(quoted diff) +1
-0+ * register write while the driver has AHIT forcedoff; the
(quoted diff) +1
-0+ * driver programs hba->ahit back when it re-enables it.
(quoted diff) +1
-0+ * Mutex is taken here (not across the rpm callsabove) so it
(quoted diff) +1
-0+ * never blocks a resume that the driver's pathmay need.
drivers/ufs/core/ufshcd.c +5
-0+*/ +mutex_lock (&hba->ahit_mutex); +if (!hba->ahit_disable_depth) +ufshcd_configure_auto_hibern8 (hba); +mutex_unlock (&hba->ahit_mutex);
ufshcd_release(hba);
ufshcd_rpm_put_sync(hba);
}[ ... ]
Quoted 5 lines
[Severity: High]
This is a pre-existing issue, but does the UFS core driver handle shared
IRQs correctly?
Same, pre-existing issue should be addressed with a separate patch.
Quoted 31 lines
The driver registers its IRQ with
IRQF_SHARED. When the UFS controller enters
runtime suspend,ufshcd_suspend()disables the interrupt line entirely:drivers/ufs/core/ufshcd.c:ufshcd_suspend() {
...ufshcd_disable_irq(hba);...
}Does calling
disable_irq()mask interrupts for any other devices sharing the
line? Should this usesynchronize_irq()instead?Additionally,
ufshcd_intr()reads the hardware register unconditionally:drivers/ufs/core/ufshcd.c:ufshcd_intr() {
...
last_intr_status=intr_status= ufshcd_readl(hba,REG_INTERRUPT_STATUS);
...
}Can this access powered-off hardware if the interrupt belongs to another
device on the same shared line? Should this verify the device is actively
powered usingpm_runtime_get_if_active()before accessing registers?
Quoted 20 lines · On Mon, 2026-09-14 at 16:49 +0800, [email protected] wrote:
From: Peter Wang <[email protected]>
Patch 1 fixes a bug where
POST_CHANGEwas skipped on a failed gear switch, leaving the host in an inconsistent state if resources acquired
inPRE_CHANGEwere never released.Patch 2 fixes a race between the sysfs AHIT update path and the MediaTek host driver's power mode change path. A mutex and depth counter are introduced to serialize AHIT register access and ensure AHIT is correctly restored after the last disabler completes.
The two patches are related: patch 1 guarantees
POST_CHANGEis always called, ensuring the depth counter introduced in patch 2 is always properly decremented.Peter Wang (2):
ufs: always notifyPOST_CHANGEeven on gear switch failure
ufs: serialize AHIT register access between sysfs and host driver
Quoted 7 lines
drivers/ufs/core/ufshcd.c | 22 +++++++++++++++++++--- drivers/ufs/host/ufs-exynos.c | 4 +++-
drivers/ufs/host/ufs-mediatek.c| 16 ++++++++++++---- drivers/ufs/host/ufshcd-pci.c | 3 ++- include/ufs/ufshcd.h | 8 ++++++++5 files changed, 44 insertions(+), 9 deletions(-)
Quoted 9 lines
Patch 1 fixes a bug where
POST_CHANGEwas skipped on a failed gear switch, leaving the host in an inconsistent state if resources acquired inPRE_CHANGEwere never released.Patch 2 fixes a race between the sysfs AHIT update path and the MediaTek host driver's power mode change path. A mutex and depth counter are introduced to serialize AHIT register access and ensure AHIT is correctly restored after the last disabler completes.
Applied to 7.4/scsi-staging, thanks!
Signature · 1 line
Martin K. Petersen
Quoted 5 lines
Applied to 7.4/scsi-staging, thanks!
--
Martin K. Petersen
Hi Martin,
I don't see this series in in 7.4/scsi-staging at [1], or perhaps just push is missing?
Thanks,
Sandeep.
[1]: https://git.kernel.org/pub/scm/linux/kernel/git/mkp/scsi.git/log/?h=7.4/scsi-staging
Martin K. Petersen
maintainerSandeep,
Quoted 2 lines
I don't see this series in in 7.4/scsi-staging at [1], or perhaps just push is missing?
Just pushed.
Signature · 1 line
Martin K. Petersen
Quoted 10 lines · On Mon, 14 Sep 2026 16:49:23 +0800, [email protected] wrote:
Patch 1 fixes a bug where
POST_CHANGEwas skipped on a failed gear switch, leaving the host in an inconsistent state if resources acquired inPRE_CHANGEwere never released.Patch 2 fixes a race between the sysfs AHIT update path and the MediaTek host driver's power mode change path. A mutex and depth counter are introduced to serialize AHIT register access and ensure AHIT is correctly restored after the last disabler completes.
[...]
Applied to 7.4/scsi-queue, thanks!
[1/2] ufs: always notify POST_CHANGE even on gear switch failure
https://git.kernel.org/mkp/scsi/c/6efee14ca0ae [2/2] ufs: serialize AHIT register access between sysfs and host driver https://git.kernel.org/mkp/scsi/c/7dec5cedf7b2
Signature · 1 line
Martin K. Petersen