[REGRESSION] Setting the LED status via attention stopped working.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi all,

We discovered regression with setting LED state through "attention" for
VMD slot. e.g /sys/bus/pci/slots/2-1/attention.

Expected behavior:
write status into "attention" will set the LED status correctly.

Actual behavior:
write the status causes undefined behavior, "attention" contains a
different value than the one entered, the requested LED status is not
set

After bisection kernel, it turned out that the issue appeared between
kernel v6.6..v6.7-rc1. Tested kernel:
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git

I found a patch that causes issue:
PCI: hotplug: Use FIELD_GET/PREP()
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?h=v6.7-rc1&id=abaaac4845a0d6f39f83cbaba4c3b46ba5f93170 
I confirmed this by reverting this patch from kernel 6.10.

Issue was discovered by using ledmon utility (ledctl is a part of ledmon
software) https://github.com/intel/ledmon, 
example command: ledctl locate={/dev/nvme6n1 }, should set locate
status on nvme6n1

The values that ledmon writes into "attention"

#define ATTENTION_OFF        0xF  /* (1111) Attention Off, Power Off */
#define ATTENTION_LOCATE     0x7  /* (0111) Attention Off, Power On */
#define ATTENTION_REBUILD    0x5  /* (0101) Attention On, Power On */
#define ATTENTION_FAILURE    0xD  /* (1101) Attention On, Power Off */

Without mentioned patch, writing these values will set the LEDs
correctly.

I was able to determine that the change in behavior was caused by this
change @@ -484,7 +485,7 @@ int pciehp_set_raw_indicator_status(struct
hotplug_slot *hotplug_slot, struct pci_dev *pdev = ctrl_dev(ctrl);
 
 	pci_config_pm_runtime_get(pdev);
-	pcie_write_cmd_nowait(ctrl, status << 6,
+	pcie_write_cmd_nowait(ctrl, FIELD_PREP(PCI_EXP_SLTCTL_AIC,
status), PCI_EXP_SLTCTL_AIC | PCI_EXP_SLTCTL_PIC);
 	pci_config_pm_runtime_put(pdev)
	
I added logging of bit shift values and there is a significant
difference in the operation of this method

int pciehp_set_raw_indicator_status(struct hotplug_slot *hotplug_slot,
                                    u8 status)
{
        struct controller *ctrl = to_ctrl(hotplug_slot);
        struct pci_dev *pdev = ctrl_dev(ctrl);

        pr_err("SET_INDICATOR_ST START");

        pr_err("SET_INDICATOR_ST_INPUT: STATUS: %d %u", status, status);
        pr_err("SET_INDICATOR_ST_OLD d %d, u %u", status << 6, status
        << 6);

        u8 test = FIELD_PREP(PCI_EXP_SLTCTL_AIC, status);
        pr_err("SET_INDICATOR_ST_NEW d %d, u %u", test, test);

        pr_err("SET_INDICATOR_ST END");

        pci_config_pm_runtime_get(pdev);
        pcie_write_cmd_nowait(ctrl, status << 6,
                              PCI_EXP_SLTCTL_AIC | PCI_EXP_SLTCTL_PIC);
        pci_config_pm_runtime_put(pdev);
        return 0;
}
LOGS:

[   75.814893] SET_INDICATOR_ST START
[   75.814895] SET_INDICATOR_ST_INPUT: STATUS: 15 15
[   75.818362] SET_INDICATOR_ST_OLD d 960, u 960
[   75.823143] SET_INDICATOR_ST_NEW d 192, u 192
[   75.827634] SET_INDICATOR_ST END
[   75.832880] SET_INDICATOR_ST START
[   75.836167] SET_INDICATOR_ST_INPUT: STATUS: 15 15
[   75.839626] SET_INDICATOR_ST_OLD d 960, u 960
[   75.844408] SET_INDICATOR_ST_NEW d 192, u 192
[   75.848834] SET_INDICATOR_ST END
[   76.225732] SET_INDICATOR_ST START
[   76.229022] SET_INDICATOR_ST_INPUT: STATUS: 15 15
[   76.232481] SET_INDICATOR_ST_OLD d 960, u 960
[   76.237259] SET_INDICATOR_ST_NEW d 192, u 192
[   76.241691] SET_INDICATOR_ST END
[   76.250247] SET_INDICATOR_ST START
[   76.253530] SET_INDICATOR_ST_INPUT: STATUS: 15 15
[   76.256990] SET_INDICATOR_ST_OLD d 960, u 960
[   76.261766] SET_INDICATOR_ST_NEW d 192, u 192
[   76.266189] SET_INDICATOR_ST END
[   77.223562] SET_INDICATOR_ST START
[   77.226852] SET_INDICATOR_ST_INPUT: STATUS: 15 15
[   77.230312] SET_INDICATOR_ST_OLD d 960, u 960
[   77.235091] SET_INDICATOR_ST_NEW d 192, u 192
[   77.239521] SET_INDICATOR_ST END
[   77.244765] SET_INDICATOR_ST START
[   77.248051] SET_INDICATOR_ST_INPUT: STATUS: 15 15
[   77.251510] SET_INDICATOR_ST_OLD d 960, u 960
[   77.256288] SET_INDICATOR_ST_NEW d 192, u 192
[   77.260725] SET_INDICATOR_ST END
[   77.267606] SET_INDICATOR_ST START

# ATTENTION_LOCATE
[   77.270895] SET_INDICATOR_ST_INPUT: STATUS: 7 7
[   77.274356] SET_INDICATOR_ST_OLD d 448, u 448
[   77.278959] SET_INDICATOR_ST_NEW d 192, u 192
[   77.283379] SET_INDICATOR_ST END

With patch PCI: hotplug: Use FIELD_GET/PREP():
after trying to set ATTENTION_LOCATE, file "attention" contains value
0x3 instead expected 0x7.

[  862.150910] SET_INDICATOR_ST START
[  862.150912] SET_INDICATOR_ST_INPUT: STATUS: 15 15
[  862.154375] SET_INDICATOR_ST_OLD d 960, u 960
[  862.159159] SET_INDICATOR_ST_NEW d 192, u 192
[  862.163591] SET_INDICATOR_ST END
[  862.169235] SET_INDICATOR_ST START
[  862.172524] SET_INDICATOR_ST_INPUT: STATUS: 15 15
[  862.175984] SET_INDICATOR_ST_OLD d 960, u 960
[  862.182933] SET_INDICATOR_ST_NEW d 192, u 192
[  862.189190] SET_INDICATOR_ST END
[  862.198302] SET_INDICATOR_ST START
[  862.203290] SET_INDICATOR_ST_INPUT: STATUS: 15 15
[  862.208398] SET_INDICATOR_ST_OLD d 960, u 960
[  862.214780] SET_INDICATOR_ST_NEW d 192, u 192
[  862.220817] SET_INDICATOR_ST END
[  862.231044] SET_INDICATOR_ST START
[  862.235931] SET_INDICATOR_ST_INPUT: STATUS: 15 15
[  862.240994] SET_INDICATOR_ST_OLD d 960, u 960
[  862.247376] SET_INDICATOR_ST_NEW d 192, u 192
[  862.253411] SET_INDICATOR_ST END
[  862.262574] SET_INDICATOR_ST START
[  862.267471] SET_INDICATOR_ST_INPUT: STATUS: 15 15
[  862.272537] SET_INDICATOR_ST_OLD d 960, u 960
[  862.278918] SET_INDICATOR_ST_NEW d 192, u 192
[  862.284945] SET_INDICATOR_ST END
[  862.291705] SET_INDICATOR_ST START
[  862.296596] SET_INDICATOR_ST_INPUT: STATUS: 15 15
[  862.301656] SET_INDICATOR_ST_OLD d 960, u 960
[  862.308039] SET_INDICATOR_ST_NEW d 192, u 192
[  862.314064] SET_INDICATOR_ST END

# ATTENTION_REBUILD
[  862.322480] SET_INDICATOR_ST START
[  862.327388] SET_INDICATOR_ST_INPUT: STATUS: 5 5
[  862.332454] SET_INDICATOR_ST_OLD d 320, u 320
[  862.338662] SET_INDICATOR_ST_NEW d 64, u 64
[  862.344704] SET_INDICATOR_ST END

With patch PCI: hotplug: Use FIELD_GET/PREP():
After trying to set ATTENTION_REBUILD, file "attention" contains value
0x1 instead expected 0x5.

This topic is quite important for us, because this change has been
included in RHEL9.5 kernel and causes LED setting for VMD drives to not
work.

Looking at the above logs, I don't know if it always worked wrong,
because the input status is u8 and the bit shift did not cut off some
of higher bits e.g. for ATTENTION_LOCATE 0x7 (0111),
currently macro FIELD_PREP it does this through "AND" with mask.

Regards,
Blazej





[Index of Archives]     [DMA Engine]     [Linux Coverity]     [Linux USB]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Greybus]

  Powered by Linux