From: Sasha Levin Date: Sun, 20 Apr 2025 14:59:56 +0000 (-0400) Subject: Fixes for 5.15 X-Git-Tag: v6.1.135~143 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=24241cb4284b59260dafb3327fc2a4bdc7094659;p=thirdparty%2Fkernel%2Fstable-queue.git Fixes for 5.15 Signed-off-by: Sasha Levin --- diff --git a/queue-5.15/bluetooth-btrtl-prevent-potential-null-dereference.patch b/queue-5.15/bluetooth-btrtl-prevent-potential-null-dereference.patch new file mode 100644 index 0000000000..dfa6dda7a9 --- /dev/null +++ b/queue-5.15/bluetooth-btrtl-prevent-potential-null-dereference.patch @@ -0,0 +1,42 @@ +From 6c2dfb35b5d46c6cc96deb74cc07aa435a4fc27d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 2 Apr 2025 14:01:41 +0300 +Subject: Bluetooth: btrtl: Prevent potential NULL dereference + +From: Dan Carpenter + +[ Upstream commit 324dddea321078a6eeb535c2bff5257be74c9799 ] + +The btrtl_initialize() function checks that rtl_load_file() either +had an error or it loaded a zero length file. However, if it loaded +a zero length file then the error code is not set correctly. It +results in an error pointer vs NULL bug, followed by a NULL pointer +dereference. This was detected by Smatch: + +drivers/bluetooth/btrtl.c:592 btrtl_initialize() warn: passing zero to 'ERR_PTR' + +Fixes: 26503ad25de8 ("Bluetooth: btrtl: split the device initialization into smaller parts") +Signed-off-by: Dan Carpenter +Reviewed-by: Hans de Goede +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + drivers/bluetooth/btrtl.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/bluetooth/btrtl.c b/drivers/bluetooth/btrtl.c +index 1f8afa0244d85..1918e60caa91e 100644 +--- a/drivers/bluetooth/btrtl.c ++++ b/drivers/bluetooth/btrtl.c +@@ -677,6 +677,8 @@ struct btrtl_device_info *btrtl_initialize(struct hci_dev *hdev, + rtl_dev_err(hdev, "mandatory config file %s not found", + btrtl_dev->ic_info->cfg_name); + ret = btrtl_dev->cfg_len; ++ if (!ret) ++ ret = -EINVAL; + goto err_free; + } + } +-- +2.39.5 + diff --git a/queue-5.15/bluetooth-hci_event-fix-sending-mgmt_ev_device_found.patch b/queue-5.15/bluetooth-hci_event-fix-sending-mgmt_ev_device_found.patch new file mode 100644 index 0000000000..4f422a17b1 --- /dev/null +++ b/queue-5.15/bluetooth-hci_event-fix-sending-mgmt_ev_device_found.patch @@ -0,0 +1,50 @@ +From 36eb3d1c0483f34668ad3b3450dde65ef83d658c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 1 Apr 2025 13:02:08 -0400 +Subject: Bluetooth: hci_event: Fix sending MGMT_EV_DEVICE_FOUND for invalid + address + +From: Luiz Augusto von Dentz + +[ Upstream commit eb73b5a9157221f405b4fe32751da84ee46b7a25 ] + +This fixes sending MGMT_EV_DEVICE_FOUND for invalid address +(00:00:00:00:00:00) which is a regression introduced by +a2ec905d1e16 ("Bluetooth: fix kernel oops in store_pending_adv_report") +since in the attempt to skip storing data for extended advertisement it +actually made the code to skip the entire if statement supposed to send +MGMT_EV_DEVICE_FOUND without attempting to use the last_addr_adv which +is garanteed to be invalid for extended advertisement since we never +store anything on it. + +Link: https://github.com/bluez/bluez/issues/1157 +Link: https://github.com/bluez/bluez/issues/1149#issuecomment-2767215658 +Fixes: a2ec905d1e16 ("Bluetooth: fix kernel oops in store_pending_adv_report") +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/hci_event.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c +index 83af50c3838a9..84b07b27b3cf4 100644 +--- a/net/bluetooth/hci_event.c ++++ b/net/bluetooth/hci_event.c +@@ -5777,11 +5777,12 @@ static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr, + * event or send an immediate device found event if the data + * should not be stored for later. + */ +- if (!ext_adv && !has_pending_adv_report(hdev)) { ++ if (!has_pending_adv_report(hdev)) { + /* If the report will trigger a SCAN_REQ store it for + * later merging. + */ +- if (type == LE_ADV_IND || type == LE_ADV_SCAN_IND) { ++ if (!ext_adv && (type == LE_ADV_IND || ++ type == LE_ADV_SCAN_IND)) { + store_pending_adv_report(hdev, bdaddr, bdaddr_type, + rssi, flags, data, len); + return; +-- +2.39.5 + diff --git a/queue-5.15/bluetooth-l2cap-check-encryption-key-size-on-incomin.patch b/queue-5.15/bluetooth-l2cap-check-encryption-key-size-on-incomin.patch new file mode 100644 index 0000000000..3b3e200b12 --- /dev/null +++ b/queue-5.15/bluetooth-l2cap-check-encryption-key-size-on-incomin.patch @@ -0,0 +1,81 @@ +From 4ea91eddd8f855dfb54d2a869788d039c1dab0ca Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 9 Apr 2025 10:53:06 +0200 +Subject: Bluetooth: l2cap: Check encryption key size on incoming connection +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Frédéric Danis + +[ Upstream commit 522e9ed157e3c21b4dd623c79967f72c21e45b78 ] + +This is required for passing GAP/SEC/SEM/BI-04-C PTS test case: + Security Mode 4 Level 4, Responder - Invalid Encryption Key Size + - 128 bit + +This tests the security key with size from 1 to 15 bytes while the +Security Mode 4 Level 4 requests 16 bytes key size. + +Currently PTS fails with the following logs: +- expected:Connection Response: + Code: [3 (0x03)] Code + Identifier: (lt)WildCard: Exists(gt) + Length: [8 (0x0008)] + Destination CID: (lt)WildCard: Exists(gt) + Source CID: [64 (0x0040)] + Result: [3 (0x0003)] Connection refused - Security block + Status: (lt)WildCard: Exists(gt), +but received:Connection Response: + Code: [3 (0x03)] Code + Identifier: [1 (0x01)] + Length: [8 (0x0008)] + Destination CID: [64 (0x0040)] + Source CID: [64 (0x0040)] + Result: [0 (0x0000)] Connection Successful + Status: [0 (0x0000)] No further information available + +And HCI logs: +< HCI Command: Read Encrypti.. (0x05|0x0008) plen 2 + Handle: 14 Address: 00:1B:DC:F2:24:10 (Vencer Co., Ltd.) +> HCI Event: Command Complete (0x0e) plen 7 + Read Encryption Key Size (0x05|0x0008) ncmd 1 + Status: Success (0x00) + Handle: 14 Address: 00:1B:DC:F2:24:10 (Vencer Co., Ltd.) + Key size: 7 +> ACL Data RX: Handle 14 flags 0x02 dlen 12 + L2CAP: Connection Request (0x02) ident 1 len 4 + PSM: 4097 (0x1001) + Source CID: 64 +< ACL Data TX: Handle 14 flags 0x00 dlen 16 + L2CAP: Connection Response (0x03) ident 1 len 8 + Destination CID: 64 + Source CID: 64 + Result: Connection successful (0x0000) + Status: No further information available (0x0000) + +Fixes: 288c06973daa ("Bluetooth: Enforce key size of 16 bytes on FIPS level") +Signed-off-by: Frédéric Danis +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Sasha Levin +--- + net/bluetooth/l2cap_core.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c +index 2d451009a6477..d34e161a30b37 100644 +--- a/net/bluetooth/l2cap_core.c ++++ b/net/bluetooth/l2cap_core.c +@@ -4162,7 +4162,8 @@ static struct l2cap_chan *l2cap_connect(struct l2cap_conn *conn, + + /* Check if the ACL is secure enough (if not SDP) */ + if (psm != cpu_to_le16(L2CAP_PSM_SDP) && +- !hci_conn_check_link_mode(conn->hcon)) { ++ (!hci_conn_check_link_mode(conn->hcon) || ++ !l2cap_check_enc_key_size(conn->hcon))) { + conn->disc_reason = HCI_ERROR_AUTH_FAILURE; + result = L2CAP_CR_SEC_BLOCK; + goto response; +-- +2.39.5 + diff --git a/queue-5.15/cpufreq-sched-fix-the-usage-of-cpufreq_need_update_l.patch b/queue-5.15/cpufreq-sched-fix-the-usage-of-cpufreq_need_update_l.patch new file mode 100644 index 0000000000..b476b20f21 --- /dev/null +++ b/queue-5.15/cpufreq-sched-fix-the-usage-of-cpufreq_need_update_l.patch @@ -0,0 +1,78 @@ +From d9ebb2e363d7be6aeee0f597e87e1aba8d6bab07 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 15 Apr 2025 11:58:08 +0200 +Subject: cpufreq/sched: Fix the usage of CPUFREQ_NEED_UPDATE_LIMITS + +From: Rafael J. Wysocki + +[ Upstream commit cfde542df7dd51d26cf667f4af497878ddffd85a ] + +Commit 8e461a1cb43d ("cpufreq: schedutil: Fix superfluous updates caused +by need_freq_update") modified sugov_should_update_freq() to set the +need_freq_update flag only for drivers with CPUFREQ_NEED_UPDATE_LIMITS +set, but that flag generally needs to be set when the policy limits +change because the driver callback may need to be invoked for the new +limits to take effect. + +However, if the return value of cpufreq_driver_resolve_freq() after +applying the new limits is still equal to the previously selected +frequency, the driver callback needs to be invoked only in the case +when CPUFREQ_NEED_UPDATE_LIMITS is set (which means that the driver +specifically wants its callback to be invoked every time the policy +limits change). + +Update the code accordingly to avoid missing policy limits changes for +drivers without CPUFREQ_NEED_UPDATE_LIMITS. + +Fixes: 8e461a1cb43d ("cpufreq: schedutil: Fix superfluous updates caused by need_freq_update") +Closes: https://lore.kernel.org/lkml/Z_Tlc6Qs-tYpxWYb@linaro.org/ +Reported-by: Stephan Gerhold +Signed-off-by: Rafael J. Wysocki +Reviewed-by: Christian Loehle +Link: https://patch.msgid.link/3010358.e9J7NaK4W3@rjwysocki.net +Signed-off-by: Sasha Levin +--- + kernel/sched/cpufreq_schedutil.c | 18 +++++++++++++++--- + 1 file changed, 15 insertions(+), 3 deletions(-) + +diff --git a/kernel/sched/cpufreq_schedutil.c b/kernel/sched/cpufreq_schedutil.c +index e23a0fc96a7d2..519f742d44f48 100644 +--- a/kernel/sched/cpufreq_schedutil.c ++++ b/kernel/sched/cpufreq_schedutil.c +@@ -91,7 +91,7 @@ static bool sugov_should_update_freq(struct sugov_policy *sg_policy, u64 time) + + if (unlikely(sg_policy->limits_changed)) { + sg_policy->limits_changed = false; +- sg_policy->need_freq_update = cpufreq_driver_test_flags(CPUFREQ_NEED_UPDATE_LIMITS); ++ sg_policy->need_freq_update = true; + return true; + } + +@@ -103,10 +103,22 @@ static bool sugov_should_update_freq(struct sugov_policy *sg_policy, u64 time) + static bool sugov_update_next_freq(struct sugov_policy *sg_policy, u64 time, + unsigned int next_freq) + { +- if (sg_policy->need_freq_update) ++ if (sg_policy->need_freq_update) { + sg_policy->need_freq_update = false; +- else if (sg_policy->next_freq == next_freq) ++ /* ++ * The policy limits have changed, but if the return value of ++ * cpufreq_driver_resolve_freq() after applying the new limits ++ * is still equal to the previously selected frequency, the ++ * driver callback need not be invoked unless the driver ++ * specifically wants that to happen on every update of the ++ * policy limits. ++ */ ++ if (sg_policy->next_freq == next_freq && ++ !cpufreq_driver_test_flags(CPUFREQ_NEED_UPDATE_LIMITS)) ++ return false; ++ } else if (sg_policy->next_freq == next_freq) { + return false; ++ } + + sg_policy->next_freq = next_freq; + sg_policy->last_freq_update_time = time; +-- +2.39.5 + diff --git a/queue-5.15/cxgb4-fix-memory-leak-in-cxgb4_init_ethtool_filters-.patch b/queue-5.15/cxgb4-fix-memory-leak-in-cxgb4_init_ethtool_filters-.patch new file mode 100644 index 0000000000..615daacecc --- /dev/null +++ b/queue-5.15/cxgb4-fix-memory-leak-in-cxgb4_init_ethtool_filters-.patch @@ -0,0 +1,43 @@ +From 0032af7670c4b2fe3ce53282b0904df2360887bb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 14 Apr 2025 22:36:46 +0530 +Subject: cxgb4: fix memory leak in cxgb4_init_ethtool_filters() error path + +From: Abdun Nihaal + +[ Upstream commit 00ffb3724ce743578163f5ade2884374554ca021 ] + +In the for loop used to allocate the loc_array and bmap for each port, a +memory leak is possible when the allocation for loc_array succeeds, +but the allocation for bmap fails. This is because when the control flow +goes to the label free_eth_finfo, only the allocations starting from +(i-1)th iteration are freed. + +Fix that by freeing the loc_array in the bmap allocation error path. + +Fixes: d915c299f1da ("cxgb4: add skeleton for ethtool n-tuple filters") +Signed-off-by: Abdun Nihaal +Reviewed-by: Simon Horman +Reviewed-by: Jacob Keller +Link: https://patch.msgid.link/20250414170649.89156-1-abdun.nihaal@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c +index 129352bbe1143..f1e09a8dfc5c7 100644 +--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c ++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c +@@ -2262,6 +2262,7 @@ int cxgb4_init_ethtool_filters(struct adapter *adap) + GFP_KERNEL); + if (!eth_filter->port[i].bmap) { + ret = -ENOMEM; ++ kvfree(eth_filter->port[i].loc_array); + goto free_eth_finfo; + } + } +-- +2.39.5 + diff --git a/queue-5.15/igc-cleanup-ptp-module-if-probe-fails.patch b/queue-5.15/igc-cleanup-ptp-module-if-probe-fails.patch new file mode 100644 index 0000000000..5215614e96 --- /dev/null +++ b/queue-5.15/igc-cleanup-ptp-module-if-probe-fails.patch @@ -0,0 +1,39 @@ +From 0f381b7a8c3213ac931c1b6148538b59772d4b10 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 1 Apr 2025 16:35:33 -0700 +Subject: igc: cleanup PTP module if probe fails + +From: Christopher S M Hall + +[ Upstream commit 1f025759ba394dd53e434d2668cb0597886d9b69 ] + +Make sure that the PTP module is cleaned up if the igc_probe() fails by +calling igc_ptp_stop() on exit. + +Fixes: d89f88419f99 ("igc: Add skeletal frame for Intel(R) 2.5G Ethernet Controller support") +Signed-off-by: Christopher S M Hall +Reviewed-by: Corinna Vinschen +Signed-off-by: Jacob Keller +Tested-by: Mor Bar-Gabay +Acked-by: Vinicius Costa Gomes +Signed-off-by: Tony Nguyen +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/igc/igc_main.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c +index 27c24bfc2dbeb..4186e5732f972 100644 +--- a/drivers/net/ethernet/intel/igc/igc_main.c ++++ b/drivers/net/ethernet/intel/igc/igc_main.c +@@ -6722,6 +6722,7 @@ static int igc_probe(struct pci_dev *pdev, + + err_register: + igc_release_hw_control(adapter); ++ igc_ptp_stop(adapter); + err_eeprom: + if (!igc_check_reset_block(hw)) + igc_reset_phy(hw); +-- +2.39.5 + diff --git a/queue-5.15/igc-fix-ptm-cycle-trigger-logic.patch b/queue-5.15/igc-fix-ptm-cycle-trigger-logic.patch new file mode 100644 index 0000000000..48eba5e265 --- /dev/null +++ b/queue-5.15/igc-fix-ptm-cycle-trigger-logic.patch @@ -0,0 +1,198 @@ +From d346e8c8e077a6eb739ea1c154d93f13ff536ada Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 1 Apr 2025 16:35:29 -0700 +Subject: igc: fix PTM cycle trigger logic + +From: Christopher S M Hall + +[ Upstream commit 8e404ad95d2c10c261e2ef6992c7c12dde03df0e ] + +Writing to clear the PTM status 'valid' bit while the PTM cycle is +triggered results in unreliable PTM operation. To fix this, clear the +PTM 'trigger' and status after each PTM transaction. + +The issue can be reproduced with the following: + +$ sudo phc2sys -R 1000 -O 0 -i tsn0 -m + +Note: 1000 Hz (-R 1000) is unrealistically large, but provides a way to +quickly reproduce the issue. + +PHC2SYS exits with: + +"ioctl PTP_OFFSET_PRECISE: Connection timed out" when the PTM transaction + fails + +This patch also fixes a hang in igc_probe() when loading the igc +driver in the kdump kernel on systems supporting PTM. + +The igc driver running in the base kernel enables PTM trigger in +igc_probe(). Therefore the driver is always in PTM trigger mode, +except in brief periods when manually triggering a PTM cycle. + +When a crash occurs, the NIC is reset while PTM trigger is enabled. +Due to a hardware problem, the NIC is subsequently in a bad busmaster +state and doesn't handle register reads/writes. When running +igc_probe() in the kdump kernel, the first register access to a NIC +register hangs driver probing and ultimately breaks kdump. + +With this patch, igc has PTM trigger disabled most of the time, +and the trigger is only enabled for very brief (10 - 100 us) periods +when manually triggering a PTM cycle. Chances that a crash occurs +during a PTM trigger are not 0, but extremely reduced. + +Fixes: a90ec8483732 ("igc: Add support for PTP getcrosststamp()") +Reviewed-by: Michal Swiatkowski +Tested-by: Mor Bar-Gabay +Tested-by: Avigail Dahan +Signed-off-by: Christopher S M Hall +Reviewed-by: Corinna Vinschen +Signed-off-by: Jacob Keller +Tested-by: Corinna Vinschen +Acked-by: Vinicius Costa Gomes +Signed-off-by: Tony Nguyen +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/igc/igc_defines.h | 1 + + drivers/net/ethernet/intel/igc/igc_ptp.c | 70 ++++++++++++-------- + 2 files changed, 42 insertions(+), 29 deletions(-) + +diff --git a/drivers/net/ethernet/intel/igc/igc_defines.h b/drivers/net/ethernet/intel/igc/igc_defines.h +index d5acee27894e5..9f99a6ed7008d 100644 +--- a/drivers/net/ethernet/intel/igc/igc_defines.h ++++ b/drivers/net/ethernet/intel/igc/igc_defines.h +@@ -577,6 +577,7 @@ + #define IGC_PTM_STAT_T4M1_OVFL BIT(3) /* T4 minus T1 overflow */ + #define IGC_PTM_STAT_ADJUST_1ST BIT(4) /* 1588 timer adjusted during 1st PTM cycle */ + #define IGC_PTM_STAT_ADJUST_CYC BIT(5) /* 1588 timer adjusted during non-1st PTM cycle */ ++#define IGC_PTM_STAT_ALL GENMASK(5, 0) /* Used to clear all status */ + + /* PCIe PTM Cycle Control */ + #define IGC_PTM_CYCLE_CTRL_CYC_TIME(msec) ((msec) & 0x3ff) /* PTM Cycle Time (msec) */ +diff --git a/drivers/net/ethernet/intel/igc/igc_ptp.c b/drivers/net/ethernet/intel/igc/igc_ptp.c +index 556750b61c98f..d0363bd68e5ed 100644 +--- a/drivers/net/ethernet/intel/igc/igc_ptp.c ++++ b/drivers/net/ethernet/intel/igc/igc_ptp.c +@@ -849,13 +849,40 @@ static void igc_ptm_log_error(struct igc_adapter *adapter, u32 ptm_stat) + } + } + ++static void igc_ptm_trigger(struct igc_hw *hw) ++{ ++ u32 ctrl; ++ ++ /* To "manually" start the PTM cycle we need to set the ++ * trigger (TRIG) bit ++ */ ++ ctrl = rd32(IGC_PTM_CTRL); ++ ctrl |= IGC_PTM_CTRL_TRIG; ++ wr32(IGC_PTM_CTRL, ctrl); ++ /* Perform flush after write to CTRL register otherwise ++ * transaction may not start ++ */ ++ wrfl(); ++} ++ ++static void igc_ptm_reset(struct igc_hw *hw) ++{ ++ u32 ctrl; ++ ++ ctrl = rd32(IGC_PTM_CTRL); ++ ctrl &= ~IGC_PTM_CTRL_TRIG; ++ wr32(IGC_PTM_CTRL, ctrl); ++ /* Write to clear all status */ ++ wr32(IGC_PTM_STAT, IGC_PTM_STAT_ALL); ++} ++ + static int igc_phc_get_syncdevicetime(ktime_t *device, + struct system_counterval_t *system, + void *ctx) + { +- u32 stat, t2_curr_h, t2_curr_l, ctrl; + struct igc_adapter *adapter = ctx; + struct igc_hw *hw = &adapter->hw; ++ u32 stat, t2_curr_h, t2_curr_l; + int err, count = 100; + ktime_t t1, t2_curr; + +@@ -869,25 +896,13 @@ static int igc_phc_get_syncdevicetime(ktime_t *device, + * are transitory. Repeating the process returns valid + * data eventually. + */ +- +- /* To "manually" start the PTM cycle we need to clear and +- * then set again the TRIG bit. +- */ +- ctrl = rd32(IGC_PTM_CTRL); +- ctrl &= ~IGC_PTM_CTRL_TRIG; +- wr32(IGC_PTM_CTRL, ctrl); +- ctrl |= IGC_PTM_CTRL_TRIG; +- wr32(IGC_PTM_CTRL, ctrl); +- +- /* The cycle only starts "for real" when software notifies +- * that it has read the registers, this is done by setting +- * VALID bit. +- */ +- wr32(IGC_PTM_STAT, IGC_PTM_STAT_VALID); ++ igc_ptm_trigger(hw); + + err = readx_poll_timeout(rd32, IGC_PTM_STAT, stat, + stat, IGC_PTM_STAT_SLEEP, + IGC_PTM_STAT_TIMEOUT); ++ igc_ptm_reset(hw); ++ + if (err < 0) { + netdev_err(adapter->netdev, "Timeout reading IGC_PTM_STAT register\n"); + return err; +@@ -896,15 +911,7 @@ static int igc_phc_get_syncdevicetime(ktime_t *device, + if ((stat & IGC_PTM_STAT_VALID) == IGC_PTM_STAT_VALID) + break; + +- if (stat & ~IGC_PTM_STAT_VALID) { +- /* An error occurred, log it. */ +- igc_ptm_log_error(adapter, stat); +- /* The STAT register is write-1-to-clear (W1C), +- * so write the previous error status to clear it. +- */ +- wr32(IGC_PTM_STAT, stat); +- continue; +- } ++ igc_ptm_log_error(adapter, stat); + } while (--count); + + if (!count) { +@@ -1086,7 +1093,7 @@ void igc_ptp_stop(struct igc_adapter *adapter) + void igc_ptp_reset(struct igc_adapter *adapter) + { + struct igc_hw *hw = &adapter->hw; +- u32 cycle_ctrl, ctrl; ++ u32 cycle_ctrl, ctrl, stat; + unsigned long flags; + u32 timadj; + +@@ -1121,14 +1128,19 @@ void igc_ptp_reset(struct igc_adapter *adapter) + ctrl = IGC_PTM_CTRL_EN | + IGC_PTM_CTRL_START_NOW | + IGC_PTM_CTRL_SHRT_CYC(IGC_PTM_SHORT_CYC_DEFAULT) | +- IGC_PTM_CTRL_PTM_TO(IGC_PTM_TIMEOUT_DEFAULT) | +- IGC_PTM_CTRL_TRIG; ++ IGC_PTM_CTRL_PTM_TO(IGC_PTM_TIMEOUT_DEFAULT); + + wr32(IGC_PTM_CTRL, ctrl); + + /* Force the first cycle to run. */ +- wr32(IGC_PTM_STAT, IGC_PTM_STAT_VALID); ++ igc_ptm_trigger(hw); ++ ++ if (readx_poll_timeout_atomic(rd32, IGC_PTM_STAT, stat, ++ stat, IGC_PTM_STAT_SLEEP, ++ IGC_PTM_STAT_TIMEOUT)) ++ netdev_err(adapter->netdev, "Timeout reading IGC_PTM_STAT register\n"); + ++ igc_ptm_reset(hw); + break; + default: + /* No work to do. */ +-- +2.39.5 + diff --git a/queue-5.15/igc-handle-the-igc_ptp_enabled-flag-correctly.patch b/queue-5.15/igc-handle-the-igc_ptp_enabled-flag-correctly.patch new file mode 100644 index 0000000000..0aa80192ec --- /dev/null +++ b/queue-5.15/igc-handle-the-igc_ptp_enabled-flag-correctly.patch @@ -0,0 +1,55 @@ +From 558397cb7dcb9b7a9d1bc538e0a5d48775305146 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 1 Apr 2025 16:35:32 -0700 +Subject: igc: handle the IGC_PTP_ENABLED flag correctly + +From: Christopher S M Hall + +[ Upstream commit 26a3910afd111f7c1a96dace6dc02f3225063896 ] + +All functions in igc_ptp.c called from igc_main.c should check the +IGC_PTP_ENABLED flag. Adding check for this flag to stop and reset +functions. + +Fixes: 5f2958052c58 ("igc: Add basic skeleton for PTP") +Signed-off-by: Christopher S M Hall +Reviewed-by: Corinna Vinschen +Signed-off-by: Jacob Keller +Tested-by: Mor Bar-Gabay +Acked-by: Vinicius Costa Gomes +Signed-off-by: Tony Nguyen +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/igc/igc_ptp.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/net/ethernet/intel/igc/igc_ptp.c b/drivers/net/ethernet/intel/igc/igc_ptp.c +index 863669192301e..49f8b0b0e6586 100644 +--- a/drivers/net/ethernet/intel/igc/igc_ptp.c ++++ b/drivers/net/ethernet/intel/igc/igc_ptp.c +@@ -1075,8 +1075,12 @@ void igc_ptp_suspend(struct igc_adapter *adapter) + **/ + void igc_ptp_stop(struct igc_adapter *adapter) + { ++ if (!(adapter->ptp_flags & IGC_PTP_ENABLED)) ++ return; ++ + igc_ptp_suspend(adapter); + ++ adapter->ptp_flags &= ~IGC_PTP_ENABLED; + if (adapter->ptp_clock) { + ptp_clock_unregister(adapter->ptp_clock); + netdev_info(adapter->netdev, "PHC removed\n"); +@@ -1097,6 +1101,9 @@ void igc_ptp_reset(struct igc_adapter *adapter) + unsigned long flags; + u32 timadj; + ++ if (!(adapter->ptp_flags & IGC_PTP_ENABLED)) ++ return; ++ + /* reset the tstamp_config */ + igc_ptp_set_timestamp_mode(adapter, &adapter->tstamp_config); + +-- +2.39.5 + diff --git a/queue-5.15/igc-move-ktime-snapshot-into-ptm-retry-loop.patch b/queue-5.15/igc-move-ktime-snapshot-into-ptm-retry-loop.patch new file mode 100644 index 0000000000..5543627501 --- /dev/null +++ b/queue-5.15/igc-move-ktime-snapshot-into-ptm-retry-loop.patch @@ -0,0 +1,59 @@ +From bc85d4c42e4a40628d0e915d4131c01a03abd623 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 1 Apr 2025 16:35:31 -0700 +Subject: igc: move ktime snapshot into PTM retry loop + +From: Christopher S M Hall + +[ Upstream commit cd7f7328d691937102732f39f97ead35b15bf803 ] + +Move ktime_get_snapshot() into the loop. If a retry does occur, a more +recent snapshot will result in a more accurate cross-timestamp. + +Fixes: a90ec8483732 ("igc: Add support for PTP getcrosststamp()") +Reviewed-by: Michal Swiatkowski +Tested-by: Mor Bar-Gabay +Tested-by: Avigail Dahan +Signed-off-by: Christopher S M Hall +Reviewed-by: Corinna Vinschen +Signed-off-by: Jacob Keller +Acked-by: Vinicius Costa Gomes +Signed-off-by: Tony Nguyen +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/intel/igc/igc_ptp.c | 18 +++++++++--------- + 1 file changed, 9 insertions(+), 9 deletions(-) + +diff --git a/drivers/net/ethernet/intel/igc/igc_ptp.c b/drivers/net/ethernet/intel/igc/igc_ptp.c +index d0363bd68e5ed..863669192301e 100644 +--- a/drivers/net/ethernet/intel/igc/igc_ptp.c ++++ b/drivers/net/ethernet/intel/igc/igc_ptp.c +@@ -886,16 +886,16 @@ static int igc_phc_get_syncdevicetime(ktime_t *device, + int err, count = 100; + ktime_t t1, t2_curr; + +- /* Get a snapshot of system clocks to use as historic value. */ +- ktime_get_snapshot(&adapter->snapshot); +- ++ /* Doing this in a loop because in the event of a ++ * badly timed (ha!) system clock adjustment, we may ++ * get PTM errors from the PCI root, but these errors ++ * are transitory. Repeating the process returns valid ++ * data eventually. ++ */ + do { +- /* Doing this in a loop because in the event of a +- * badly timed (ha!) system clock adjustment, we may +- * get PTM errors from the PCI root, but these errors +- * are transitory. Repeating the process returns valid +- * data eventually. +- */ ++ /* Get a snapshot of system clocks to use as historic value. */ ++ ktime_get_snapshot(&adapter->snapshot); ++ + igc_ptm_trigger(hw); + + err = readx_poll_timeout(rd32, IGC_PTM_STAT, stat, +-- +2.39.5 + diff --git a/queue-5.15/md-raid10-fix-missing-discard-io-accounting.patch b/queue-5.15/md-raid10-fix-missing-discard-io-accounting.patch new file mode 100644 index 0000000000..5b6fab24b4 --- /dev/null +++ b/queue-5.15/md-raid10-fix-missing-discard-io-accounting.patch @@ -0,0 +1,47 @@ +From 1369e974267e013f2ddf50c712477e43e4c82ccf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 25 Mar 2025 09:57:46 +0800 +Subject: md/raid10: fix missing discard IO accounting + +From: Yu Kuai + +[ Upstream commit d05af90d6218e9c8f1c2026990c3f53c1b41bfb0 ] + +md_account_bio() is not called from raid10_handle_discard(), now that we +handle bitmap inside md_account_bio(), also fix missing +bitmap_startwrite for discard. + +Test whole disk discard for 20G raid10: + +Before: +Device d/s dMB/s drqm/s %drqm d_await dareq-sz +md0 48.00 16.00 0.00 0.00 5.42 341.33 + +After: +Device d/s dMB/s drqm/s %drqm d_await dareq-sz +md0 68.00 20462.00 0.00 0.00 2.65 308133.65 + +Link: https://lore.kernel.org/linux-raid/20250325015746.3195035-1-yukuai1@huaweicloud.com +Fixes: 528bc2cf2fcc ("md/raid10: enable io accounting") +Signed-off-by: Yu Kuai +Acked-by: Coly Li +Signed-off-by: Sasha Levin +--- + drivers/md/raid10.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c +index bdd5a564e3191..e6c0e24cb9ae2 100644 +--- a/drivers/md/raid10.c ++++ b/drivers/md/raid10.c +@@ -1771,6 +1771,7 @@ static int raid10_handle_discard(struct mddev *mddev, struct bio *bio) + * The discard bio returns only first r10bio finishes + */ + if (first_copy) { ++ md_account_bio(mddev, &bio); + r10_bio->master_bio = bio; + set_bit(R10BIO_Discard, &r10_bio->state); + first_copy = false; +-- +2.39.5 + diff --git a/queue-5.15/net-b53-enable-bpdu-reception-for-management-port.patch b/queue-5.15/net-b53-enable-bpdu-reception-for-management-port.patch new file mode 100644 index 0000000000..0f60f4ec5e --- /dev/null +++ b/queue-5.15/net-b53-enable-bpdu-reception-for-management-port.patch @@ -0,0 +1,53 @@ +From c40aa1f679853a3d2a8a8abfdd5e1c9deef0f5e9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 14 Apr 2025 22:04:34 +0200 +Subject: net: b53: enable BPDU reception for management port + +From: Jonas Gorski + +[ Upstream commit 36355ddfe8955f226a88a543ed354b9f6b84cd70 ] + +For STP to work, receiving BPDUs is essential, but the appropriate bit +was never set. Without GC_RX_BPDU_EN, the switch chip will filter all +BPDUs, even if an appropriate PVID VLAN was setup. + +Fixes: ff39c2d68679 ("net: dsa: b53: Add bridge support") +Signed-off-by: Jonas Gorski +Link: https://patch.msgid.link/20250414200434.194422-1-jonas.gorski@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/dsa/b53/b53_common.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c +index df67262c30924..27025ca5a7598 100644 +--- a/drivers/net/dsa/b53/b53_common.c ++++ b/drivers/net/dsa/b53/b53_common.c +@@ -724,6 +724,15 @@ static void b53_enable_mib(struct b53_device *dev) + b53_write8(dev, B53_MGMT_PAGE, B53_GLOBAL_CONFIG, gc); + } + ++static void b53_enable_stp(struct b53_device *dev) ++{ ++ u8 gc; ++ ++ b53_read8(dev, B53_MGMT_PAGE, B53_GLOBAL_CONFIG, &gc); ++ gc |= GC_RX_BPDU_EN; ++ b53_write8(dev, B53_MGMT_PAGE, B53_GLOBAL_CONFIG, gc); ++} ++ + static u16 b53_default_pvid(struct b53_device *dev) + { + if (is5325(dev) || is5365(dev)) +@@ -863,6 +872,7 @@ static int b53_switch_reset(struct b53_device *dev) + } + + b53_enable_mib(dev); ++ b53_enable_stp(dev); + + return b53_flush_arl(dev, FAST_AGE_STATIC); + } +-- +2.39.5 + diff --git a/queue-5.15/net-dsa-avoid-refcount-warnings-when-ds-ops-tag_8021.patch b/queue-5.15/net-dsa-avoid-refcount-warnings-when-ds-ops-tag_8021.patch new file mode 100644 index 0000000000..703d7ffc4f --- /dev/null +++ b/queue-5.15/net-dsa-avoid-refcount-warnings-when-ds-ops-tag_8021.patch @@ -0,0 +1,40 @@ +From f02b9dbb987c264ab3f44c1f9c1ac4625d5dfb16 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 15 Apr 2025 00:30:20 +0300 +Subject: net: dsa: avoid refcount warnings when ds->ops->tag_8021q_vlan_del() + fails + +From: Vladimir Oltean + +[ Upstream commit 514eff7b0aa1c5eb645ddbb8676ef3e2d88a8b99 ] + +This is very similar to the problem and solution from commit +232deb3f9567 ("net: dsa: avoid refcount warnings when +->port_{fdb,mdb}_del returns error"), except for the +dsa_port_do_tag_8021q_vlan_del() operation. + +Fixes: c64b9c05045a ("net: dsa: tag_8021q: add proper cross-chip notifier support") +Signed-off-by: Vladimir Oltean +Link: https://patch.msgid.link/20250414213020.2959021-1-vladimir.oltean@nxp.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/dsa/tag_8021q.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/dsa/tag_8021q.c b/net/dsa/tag_8021q.c +index e443088ab0f65..cc96afc6468de 100644 +--- a/net/dsa/tag_8021q.c ++++ b/net/dsa/tag_8021q.c +@@ -196,7 +196,7 @@ static int dsa_switch_do_tag_8021q_vlan_del(struct dsa_switch *ds, int port, + + err = ds->ops->tag_8021q_vlan_del(ds, port, vid); + if (err) { +- refcount_inc(&v->refcount); ++ refcount_set(&v->refcount, 1); + return err; + } + +-- +2.39.5 + diff --git a/queue-5.15/net-dsa-mv88e6xxx-avoid-unregistering-devlink-region.patch b/queue-5.15/net-dsa-mv88e6xxx-avoid-unregistering-devlink-region.patch new file mode 100644 index 0000000000..aad674a8c7 --- /dev/null +++ b/queue-5.15/net-dsa-mv88e6xxx-avoid-unregistering-devlink-region.patch @@ -0,0 +1,56 @@ +From c95195eebd6a3edc9a0711954e59d57020f4d752 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 15 Apr 2025 00:28:50 +0300 +Subject: net: dsa: mv88e6xxx: avoid unregistering devlink regions which were + never registered + +From: Vladimir Oltean + +[ Upstream commit c84f6ce918a9e6f4996597cbc62536bbf2247c96 ] + +Russell King reports that a system with mv88e6xxx dereferences a NULL +pointer when unbinding this driver: +https://lore.kernel.org/netdev/Z_lRkMlTJ1KQ0kVX@shell.armlinux.org.uk/ + +The crash seems to be in devlink_region_destroy(), which is not NULL +tolerant but is given a NULL devlink global region pointer. + +At least on some chips, some devlink regions are conditionally registered +since the blamed commit, see mv88e6xxx_setup_devlink_regions_global(): + + if (cond && !cond(chip)) + continue; + +These are MV88E6XXX_REGION_STU and MV88E6XXX_REGION_PVT. If the chip +does not have an STU or PVT, it should crash like this. + +To fix the issue, avoid unregistering those regions which are NULL, i.e. +were skipped at mv88e6xxx_setup_devlink_regions_global() time. + +Fixes: 836021a2d0e0 ("net: dsa: mv88e6xxx: Export cross-chip PVT as devlink region") +Tested-by: Russell King (Oracle) +Signed-off-by: Vladimir Oltean +Link: https://patch.msgid.link/20250414212850.2953957-1-vladimir.oltean@nxp.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/dsa/mv88e6xxx/devlink.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/dsa/mv88e6xxx/devlink.c b/drivers/net/dsa/mv88e6xxx/devlink.c +index 381068395c63b..e6d1801bb8f50 100644 +--- a/drivers/net/dsa/mv88e6xxx/devlink.c ++++ b/drivers/net/dsa/mv88e6xxx/devlink.c +@@ -653,7 +653,8 @@ void mv88e6xxx_teardown_devlink_regions_global(struct dsa_switch *ds) + int i; + + for (i = 0; i < ARRAY_SIZE(mv88e6xxx_regions); i++) +- dsa_devlink_region_destroy(chip->regions[i]); ++ if (chip->regions[i]) ++ dsa_devlink_region_destroy(chip->regions[i]); + } + + void mv88e6xxx_teardown_devlink_regions_port(struct dsa_switch *ds, int port) +-- +2.39.5 + diff --git a/queue-5.15/net-mctp-set-sock_rcu_free.patch b/queue-5.15/net-mctp-set-sock_rcu_free.patch new file mode 100644 index 0000000000..713737b420 --- /dev/null +++ b/queue-5.15/net-mctp-set-sock_rcu_free.patch @@ -0,0 +1,38 @@ +From 18bbf2a203f176ab4a27815b285822b287d6e14b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 10 Apr 2025 11:53:19 +0800 +Subject: net: mctp: Set SOCK_RCU_FREE + +From: Matt Johnston + +[ Upstream commit 52024cd6ec71a6ca934d0cc12452bd8d49850679 ] + +Bind lookup runs under RCU, so ensure that a socket doesn't go away in +the middle of a lookup. + +Fixes: 833ef3b91de6 ("mctp: Populate socket implementation") +Signed-off-by: Matt Johnston +Link: https://patch.msgid.link/20250410-mctp-rcu-sock-v1-1-872de9fdc877@codeconstruct.com.au +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/mctp/af_mctp.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/net/mctp/af_mctp.c b/net/mctp/af_mctp.c +index 0ca031866ce1a..53b3a294b0424 100644 +--- a/net/mctp/af_mctp.c ++++ b/net/mctp/af_mctp.c +@@ -253,6 +253,9 @@ static int mctp_sk_hash(struct sock *sk) + { + struct net *net = sock_net(sk); + ++ /* Bind lookup runs under RCU, remain live during that. */ ++ sock_set_flag(sk, SOCK_RCU_FREE); ++ + mutex_lock(&net->mctp.bind_lock); + sk_add_node_rcu(sk, &net->mctp.binds); + mutex_unlock(&net->mctp.bind_lock); +-- +2.39.5 + diff --git a/queue-5.15/net-openvswitch-fix-nested-key-length-validation-in-.patch b/queue-5.15/net-openvswitch-fix-nested-key-length-validation-in-.patch new file mode 100644 index 0000000000..07eb675d8c --- /dev/null +++ b/queue-5.15/net-openvswitch-fix-nested-key-length-validation-in-.patch @@ -0,0 +1,44 @@ +From 6f300eba77d897e4731c1b193f66c75d8a9fb182 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 12 Apr 2025 12:40:18 +0200 +Subject: net: openvswitch: fix nested key length validation in the set() + action + +From: Ilya Maximets + +[ Upstream commit 65d91192aa66f05710cfddf6a14b5a25ee554dba ] + +It's not safe to access nla_len(ovs_key) if the data is smaller than +the netlink header. Check that the attribute is OK first. + +Fixes: ccb1352e76cf ("net: Add Open vSwitch kernel components.") +Reported-by: syzbot+b07a9da40df1576b8048@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=b07a9da40df1576b8048 +Tested-by: syzbot+b07a9da40df1576b8048@syzkaller.appspotmail.com +Signed-off-by: Ilya Maximets +Reviewed-by: Eelco Chaudron +Acked-by: Aaron Conole +Link: https://patch.msgid.link/20250412104052.2073688-1-i.maximets@ovn.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/openvswitch/flow_netlink.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/net/openvswitch/flow_netlink.c b/net/openvswitch/flow_netlink.c +index d9bef3decd70c..7db0f8938c145 100644 +--- a/net/openvswitch/flow_netlink.c ++++ b/net/openvswitch/flow_netlink.c +@@ -2831,7 +2831,8 @@ static int validate_set(const struct nlattr *a, + size_t key_len; + + /* There can be only one key in a action */ +- if (nla_total_size(nla_len(ovs_key)) != nla_len(a)) ++ if (!nla_ok(ovs_key, nla_len(a)) || ++ nla_total_size(nla_len(ovs_key)) != nla_len(a)) + return -EINVAL; + + key_len = nla_len(ovs_key); +-- +2.39.5 + diff --git a/queue-5.15/rdma-core-silence-oversized-kvmalloc-warning.patch b/queue-5.15/rdma-core-silence-oversized-kvmalloc-warning.patch new file mode 100644 index 0000000000..031b8b4cc1 --- /dev/null +++ b/queue-5.15/rdma-core-silence-oversized-kvmalloc-warning.patch @@ -0,0 +1,73 @@ +From 71c3bf8217d25f77e6d4fb7883c29c221877f893 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 19 Mar 2025 14:42:21 +0200 +Subject: RDMA/core: Silence oversized kvmalloc() warning + +From: Shay Drory + +[ Upstream commit 9a0e6f15029e1a8a21e40f06fd05aa52b7f063de ] + +syzkaller triggered an oversized kvmalloc() warning. +Silence it by adding __GFP_NOWARN. + +syzkaller log: + WARNING: CPU: 7 PID: 518 at mm/util.c:665 __kvmalloc_node_noprof+0x175/0x180 + CPU: 7 UID: 0 PID: 518 Comm: c_repro Not tainted 6.11.0-rc6+ #6 + Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.13.0-0-gf21b5a4aeb02-prebuilt.qemu.org 04/01/2014 + RIP: 0010:__kvmalloc_node_noprof+0x175/0x180 + RSP: 0018:ffffc90001e67c10 EFLAGS: 00010246 + RAX: 0000000000000100 RBX: 0000000000000400 RCX: ffffffff8149d46b + RDX: 0000000000000000 RSI: ffff8881030fae80 RDI: 0000000000000002 + RBP: 000000712c800000 R08: 0000000000000100 R09: 0000000000000000 + R10: ffffc90001e67c10 R11: 0030ae0601000000 R12: 0000000000000000 + R13: 0000000000000000 R14: 00000000ffffffff R15: 0000000000000000 + FS: 00007fde79159740(0000) GS:ffff88813bdc0000(0000) knlGS:0000000000000000 + CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 + CR2: 0000000020000180 CR3: 0000000105eb4005 CR4: 00000000003706b0 + DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 + DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 + Call Trace: + + ib_umem_odp_get+0x1f6/0x390 + mlx5_ib_reg_user_mr+0x1e8/0x450 + ib_uverbs_reg_mr+0x28b/0x440 + ib_uverbs_write+0x7d3/0xa30 + vfs_write+0x1ac/0x6c0 + ksys_write+0x134/0x170 + ? __sanitizer_cov_trace_pc+0x1c/0x50 + do_syscall_64+0x50/0x110 + entry_SYSCALL_64_after_hwframe+0x76/0x7e + +Fixes: 37824952dc8f ("RDMA/odp: Use kvcalloc for the dma_list and page_list") +Signed-off-by: Shay Drory +Link: https://patch.msgid.link/c6cb92379de668be94894f49c2cfa40e73f94d56.1742388096.git.leonro@nvidia.com +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/core/umem_odp.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/infiniband/core/umem_odp.c b/drivers/infiniband/core/umem_odp.c +index b052de1b9ccb9..cbb14b0b175f6 100644 +--- a/drivers/infiniband/core/umem_odp.c ++++ b/drivers/infiniband/core/umem_odp.c +@@ -78,12 +78,14 @@ static inline int ib_init_umem_odp(struct ib_umem_odp *umem_odp, + + npfns = (end - start) >> PAGE_SHIFT; + umem_odp->pfn_list = kvcalloc( +- npfns, sizeof(*umem_odp->pfn_list), GFP_KERNEL); ++ npfns, sizeof(*umem_odp->pfn_list), ++ GFP_KERNEL | __GFP_NOWARN); + if (!umem_odp->pfn_list) + return -ENOMEM; + + umem_odp->dma_list = kvcalloc( +- ndmas, sizeof(*umem_odp->dma_list), GFP_KERNEL); ++ ndmas, sizeof(*umem_odp->dma_list), ++ GFP_KERNEL | __GFP_NOWARN); + if (!umem_odp->dma_list) { + ret = -ENOMEM; + goto out_pfn_list; +-- +2.39.5 + diff --git a/queue-5.15/rdma-hns-fix-wrong-maximum-dma-segment-size.patch b/queue-5.15/rdma-hns-fix-wrong-maximum-dma-segment-size.patch new file mode 100644 index 0000000000..39e021b66d --- /dev/null +++ b/queue-5.15/rdma-hns-fix-wrong-maximum-dma-segment-size.patch @@ -0,0 +1,37 @@ +From fd15faa75981128ceff940157e6191bce53e077f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 27 Mar 2025 19:47:24 +0800 +Subject: RDMA/hns: Fix wrong maximum DMA segment size + +From: Chengchang Tang + +[ Upstream commit 9beb2c91fb86e0be70a5833c6730441fa3c9efa8 ] + +Set maximum DMA segment size to 2G instead of UINT_MAX due to HW limit. + +Fixes: e0477b34d9d1 ("RDMA: Explicitly pass in the dma_device to ib_register_device") +Link: https://patch.msgid.link/r/20250327114724.3454268-3-huangjunxian6@hisilicon.com +Signed-off-by: Chengchang Tang +Signed-off-by: Junxian Huang +Signed-off-by: Jason Gunthorpe +Signed-off-by: Sasha Levin +--- + drivers/infiniband/hw/hns/hns_roce_main.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/infiniband/hw/hns/hns_roce_main.c b/drivers/infiniband/hw/hns/hns_roce_main.c +index 83a6b8fbe10f0..4fc8e0c8b7ab0 100644 +--- a/drivers/infiniband/hw/hns/hns_roce_main.c ++++ b/drivers/infiniband/hw/hns/hns_roce_main.c +@@ -544,7 +544,7 @@ static int hns_roce_register_device(struct hns_roce_dev *hr_dev) + if (ret) + return ret; + } +- dma_set_max_seg_size(dev, UINT_MAX); ++ dma_set_max_seg_size(dev, SZ_2G); + ret = ib_register_device(ib_dev, "hns_%d", dev); + if (ret) { + dev_err(dev, "ib_register_device failed!\n"); +-- +2.39.5 + diff --git a/queue-5.15/rdma-usnic-fix-passing-zero-to-ptr_err-in-usnic_ib_p.patch b/queue-5.15/rdma-usnic-fix-passing-zero-to-ptr_err-in-usnic_ib_p.patch new file mode 100644 index 0000000000..c8ccc731aa --- /dev/null +++ b/queue-5.15/rdma-usnic-fix-passing-zero-to-ptr_err-in-usnic_ib_p.patch @@ -0,0 +1,68 @@ +From 76abf005ddd8573b23110da3ae1be92d873e7413 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 24 Mar 2025 20:31:32 +0800 +Subject: RDMA/usnic: Fix passing zero to PTR_ERR in usnic_ib_pci_probe() + +From: Yue Haibing + +[ Upstream commit 95ba3850fed03e01b422ab5d7943aeba130c9723 ] + +drivers/infiniband/hw/usnic/usnic_ib_main.c:590 + usnic_ib_pci_probe() warn: passing zero to 'PTR_ERR' + +Make usnic_ib_device_add() return NULL on fail path, also remove +useless NULL check for usnic_ib_discover_pf() + +Fixes: e3cf00d0a87f ("IB/usnic: Add Cisco VIC low-level hardware driver") +Link: https://patch.msgid.link/r/20250324123132.2392077-1-yuehaibing@huawei.com +Signed-off-by: Yue Haibing +Reviewed-by: Zhu Yanjun +Reviewed-by: Jason Gunthorpe +Signed-off-by: Jason Gunthorpe +Signed-off-by: Sasha Levin +--- + drivers/infiniband/hw/usnic/usnic_ib_main.c | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +diff --git a/drivers/infiniband/hw/usnic/usnic_ib_main.c b/drivers/infiniband/hw/usnic/usnic_ib_main.c +index d346dd48e731b..9bb78918e52aa 100644 +--- a/drivers/infiniband/hw/usnic/usnic_ib_main.c ++++ b/drivers/infiniband/hw/usnic/usnic_ib_main.c +@@ -380,7 +380,7 @@ static void *usnic_ib_device_add(struct pci_dev *dev) + if (!us_ibdev) { + usnic_err("Device %s context alloc failed\n", + netdev_name(pci_get_drvdata(dev))); +- return ERR_PTR(-EFAULT); ++ return NULL; + } + + us_ibdev->ufdev = usnic_fwd_dev_alloc(dev); +@@ -500,8 +500,8 @@ static struct usnic_ib_dev *usnic_ib_discover_pf(struct usnic_vnic *vnic) + } + + us_ibdev = usnic_ib_device_add(parent_pci); +- if (IS_ERR_OR_NULL(us_ibdev)) { +- us_ibdev = us_ibdev ? us_ibdev : ERR_PTR(-EFAULT); ++ if (!us_ibdev) { ++ us_ibdev = ERR_PTR(-EFAULT); + goto out; + } + +@@ -564,10 +564,10 @@ static int usnic_ib_pci_probe(struct pci_dev *pdev, + } + + pf = usnic_ib_discover_pf(vf->vnic); +- if (IS_ERR_OR_NULL(pf)) { +- usnic_err("Failed to discover pf of vnic %s with err%ld\n", +- pci_name(pdev), PTR_ERR(pf)); +- err = pf ? PTR_ERR(pf) : -EFAULT; ++ if (IS_ERR(pf)) { ++ err = PTR_ERR(pf); ++ usnic_err("Failed to discover pf of vnic %s with err%d\n", ++ pci_name(pdev), err); + goto out_clean_vnic; + } + +-- +2.39.5 + diff --git a/queue-5.15/revert-wifi-mac80211-update-skb-s-control-block-key-.patch b/queue-5.15/revert-wifi-mac80211-update-skb-s-control-block-key-.patch new file mode 100644 index 0000000000..e64f2a2077 --- /dev/null +++ b/queue-5.15/revert-wifi-mac80211-update-skb-s-control-block-key-.patch @@ -0,0 +1,41 @@ +From 0bec44fe811ea2b3a1dfdd1603b98a2fedfa136b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 11 Apr 2025 16:13:34 +0200 +Subject: Revert "wifi: mac80211: Update skb's control block key in + ieee80211_tx_dequeue()" + +From: Johannes Berg + +[ Upstream commit 0937cb5f345c79d702b4d0d744e2a2529b551cb2 ] + +This reverts commit a104042e2bf6528199adb6ca901efe7b60c2c27f. + +Since the original bug seems to have been around for years, +but a new issue was report with the fix, revert the fix for +now. We have a couple of weeks to figure it out for this +release, if needed. + +Reported-by: Bert Karwatzki +Closes: https://lore.kernel.org/linux-wireless/20250410215527.3001-1-spasswolf@web.de +Fixes: a104042e2bf6 ("wifi: mac80211: Update skb's control block key in ieee80211_tx_dequeue()") +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + net/mac80211/tx.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c +index 0a658e747798b..c4e6fbe4343ee 100644 +--- a/net/mac80211/tx.c ++++ b/net/mac80211/tx.c +@@ -3704,7 +3704,6 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw, + * The key can be removed while the packet was queued, so need to call + * this here to get the current key. + */ +- info->control.hw_key = NULL; + r = ieee80211_tx_h_select_key(&tx); + if (r != TX_CONTINUE) { + ieee80211_free_txskb(&local->hw, skb); +-- +2.39.5 + diff --git a/queue-5.15/riscv-kgdb-do-not-inline-arch_kgdb_breakpoint.patch b/queue-5.15/riscv-kgdb-do-not-inline-arch_kgdb_breakpoint.patch new file mode 100644 index 0000000000..42aab91d23 --- /dev/null +++ b/queue-5.15/riscv-kgdb-do-not-inline-arch_kgdb_breakpoint.patch @@ -0,0 +1,80 @@ +From 6e0680ad34d6f0e5517a2172784d1cf9b8111a6b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 11 Apr 2025 15:32:21 +0800 +Subject: riscv: KGDB: Do not inline arch_kgdb_breakpoint() + +From: WangYuli + +[ Upstream commit 3af4bec9c1db3f003be4d5ae09b6a737e4be1612 ] + +The arch_kgdb_breakpoint() function defines the kgdb_compiled_break +symbol using inline assembly. + +There's a potential issue where the compiler might inline +arch_kgdb_breakpoint(), which would then define the kgdb_compiled_break +symbol multiple times, leading to fail to link vmlinux.o. + +This isn't merely a potential compilation problem. The intent here +is to determine the global symbol address of kgdb_compiled_break, +and if this function is inlined multiple times, it would logically +be a grave error. + +Link: https://lore.kernel.org/all/4b4187c1-77e5-44b7-885f-d6826723dd9a@sifive.com/ +Link: https://lore.kernel.org/all/5b0adf9b-2b22-43fe-ab74-68df94115b9a@ghiti.fr/ +Link: https://lore.kernel.org/all/23693e7f-4fff-40f3-a437-e06d827278a5@ghiti.fr/ +Fixes: fe89bd2be866 ("riscv: Add KGDB support") +Co-developed-by: Huacai Chen +Signed-off-by: Huacai Chen +Signed-off-by: WangYuli +Link: https://lore.kernel.org/r/F22359AFB6FF9FD8+20250411073222.56820-1-wangyuli@uniontech.com +Signed-off-by: Palmer Dabbelt +Signed-off-by: Sasha Levin +--- + arch/riscv/include/asm/kgdb.h | 9 +-------- + arch/riscv/kernel/kgdb.c | 8 ++++++++ + 2 files changed, 9 insertions(+), 8 deletions(-) + +diff --git a/arch/riscv/include/asm/kgdb.h b/arch/riscv/include/asm/kgdb.h +index 46677daf708bd..cc11c4544cffd 100644 +--- a/arch/riscv/include/asm/kgdb.h ++++ b/arch/riscv/include/asm/kgdb.h +@@ -19,16 +19,9 @@ + + #ifndef __ASSEMBLY__ + ++void arch_kgdb_breakpoint(void); + extern unsigned long kgdb_compiled_break; + +-static inline void arch_kgdb_breakpoint(void) +-{ +- asm(".global kgdb_compiled_break\n" +- ".option norvc\n" +- "kgdb_compiled_break: ebreak\n" +- ".option rvc\n"); +-} +- + #endif /* !__ASSEMBLY__ */ + + #define DBG_REG_ZERO "zero" +diff --git a/arch/riscv/kernel/kgdb.c b/arch/riscv/kernel/kgdb.c +index 963ed7edcff26..b0db3350d243b 100644 +--- a/arch/riscv/kernel/kgdb.c ++++ b/arch/riscv/kernel/kgdb.c +@@ -273,6 +273,14 @@ void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long pc) + regs->epc = pc; + } + ++noinline void arch_kgdb_breakpoint(void) ++{ ++ asm(".global kgdb_compiled_break\n" ++ ".option norvc\n" ++ "kgdb_compiled_break: ebreak\n" ++ ".option rvc\n"); ++} ++ + void kgdb_arch_handle_qxfer_pkt(char *remcom_in_buffer, + char *remcom_out_buffer) + { +-- +2.39.5 + diff --git a/queue-5.15/riscv-kgdb-remove-.option-norvc-.option-rvc-for-kgdb.patch b/queue-5.15/riscv-kgdb-remove-.option-norvc-.option-rvc-for-kgdb.patch new file mode 100644 index 0000000000..8a4b2071d5 --- /dev/null +++ b/queue-5.15/riscv-kgdb-remove-.option-norvc-.option-rvc-for-kgdb.patch @@ -0,0 +1,64 @@ +From 82b08adb4bcfd2d87eda89eeb9f0deeb34a28b0f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 11 Apr 2025 15:32:22 +0800 +Subject: riscv: KGDB: Remove ".option norvc/.option rvc" for + kgdb_compiled_break + +From: WangYuli + +[ Upstream commit 550c2aa787d1b06efcb11de1877354502a1237f2 ] + +[ Quoting Samuel Holland: ] + + This is a separate issue, but using ".option rvc" here is a bug. + It will unconditionally enable the C extension for the rest of + the file, even if the kernel is being built with CONFIG_RISCV_ISA_C=n. + +[ Quoting Palmer Dabbelt: ] + + We're just looking at the address of kgdb_compiled_break, so it's + fine if it ends up as a c.ebreak. + +[ Quoting Alexandre Ghiti: ] + + .option norvc is used to prevent the assembler from using compressed + instructions, but it's generally used when we need to ensure the + size of the instructions that are used, which is not the case here + as noted by Palmer since we only care about the address. So yes + it will work fine with C enabled :) + +So let's just remove them all. + +Link: https://lore.kernel.org/all/4b4187c1-77e5-44b7-885f-d6826723dd9a@sifive.com/ +Link: https://lore.kernel.org/all/mhng-69513841-5068-441d-be8f-2aeebdc56a08@palmer-ri-x1c9a/ +Link: https://lore.kernel.org/all/23693e7f-4fff-40f3-a437-e06d827278a5@ghiti.fr/ +Fixes: fe89bd2be866 ("riscv: Add KGDB support") +Cc: Samuel Holland +Cc: Palmer Dabbelt +Cc: Alexandre Ghiti +Signed-off-by: WangYuli +Link: https://lore.kernel.org/r/8B431C6A4626225C+20250411073222.56820-2-wangyuli@uniontech.com +Signed-off-by: Palmer Dabbelt +Signed-off-by: Sasha Levin +--- + arch/riscv/kernel/kgdb.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/arch/riscv/kernel/kgdb.c b/arch/riscv/kernel/kgdb.c +index b0db3350d243b..1d83b36967212 100644 +--- a/arch/riscv/kernel/kgdb.c ++++ b/arch/riscv/kernel/kgdb.c +@@ -276,9 +276,7 @@ void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long pc) + noinline void arch_kgdb_breakpoint(void) + { + asm(".global kgdb_compiled_break\n" +- ".option norvc\n" +- "kgdb_compiled_break: ebreak\n" +- ".option rvc\n"); ++ "kgdb_compiled_break: ebreak\n"); + } + + void kgdb_arch_handle_qxfer_pkt(char *remcom_in_buffer, +-- +2.39.5 + diff --git a/queue-5.15/riscv-properly-export-reserved-regions-in-proc-iomem.patch b/queue-5.15/riscv-properly-export-reserved-regions-in-proc-iomem.patch new file mode 100644 index 0000000000..ce398bcda8 --- /dev/null +++ b/queue-5.15/riscv-properly-export-reserved-regions-in-proc-iomem.patch @@ -0,0 +1,120 @@ +From 4f62c238dc67e2abe785877e8f84a1689d3768b3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 9 Apr 2025 20:21:27 +0200 +Subject: riscv: Properly export reserved regions in /proc/iomem +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Björn Töpel + +[ Upstream commit e94eb7ea6f206e229791761a5fdf9389f8dbd183 ] + +The /proc/iomem represents the kernel's memory map. Regions marked +with "Reserved" tells the user that the range should not be tampered +with. Kexec-tools, when using the older kexec_load syscall relies on +the "Reserved" regions to build the memory segments, that will be the +target of the new kexec'd kernel. + +The RISC-V port tries to expose all reserved regions to userland, but +some regions were not properly exposed: Regions that resided in both +the "regular" and reserved memory block, e.g. the EFI Memory Map. A +missing entry could result in reserved memory being overwritten. + +It turns out, that arm64, and loongarch had a similar issue a while +back: + + commit d91680e687f4 ("arm64: Fix /proc/iomem for reserved but not memory regions") + commit 50d7ba36b916 ("arm64: export memblock_reserve()d regions via /proc/iomem") + +Similar to the other ports, resolve the issue by splitting the regions +in an arch initcall, since we need a working allocator. + +Fixes: ffe0e5261268 ("RISC-V: Improve init_resources()") +Signed-off-by: Björn Töpel +Reviewed-by: Alexandre Ghiti +Link: https://lore.kernel.org/r/20250409182129.634415-1-bjorn@kernel.org +Signed-off-by: Alexandre Ghiti +Signed-off-by: Sasha Levin +--- + arch/riscv/kernel/setup.c | 36 +++++++++++++++++++++++++++++++++++- + 1 file changed, 35 insertions(+), 1 deletion(-) + +diff --git a/arch/riscv/kernel/setup.c b/arch/riscv/kernel/setup.c +index 8cc147491c675..0c85b9e59ec0e 100644 +--- a/arch/riscv/kernel/setup.c ++++ b/arch/riscv/kernel/setup.c +@@ -84,6 +84,9 @@ static struct resource bss_res = { .name = "Kernel bss", }; + static struct resource elfcorehdr_res = { .name = "ELF Core hdr", }; + #endif + ++static int num_standard_resources; ++static struct resource *standard_resources; ++ + static int __init add_resource(struct resource *parent, + struct resource *res) + { +@@ -157,7 +160,7 @@ static void __init init_resources(void) + struct resource *res = NULL; + struct resource *mem_res = NULL; + size_t mem_res_sz = 0; +- int num_resources = 0, res_idx = 0; ++ int num_resources = 0, res_idx = 0, non_resv_res = 0; + int ret = 0; + + /* + 1 as memblock_alloc() might increase memblock.reserved.cnt */ +@@ -221,6 +224,7 @@ static void __init init_resources(void) + /* Add /memory regions to the resource tree */ + for_each_mem_region(region) { + res = &mem_res[res_idx--]; ++ non_resv_res++; + + if (unlikely(memblock_is_nomap(region))) { + res->name = "Reserved"; +@@ -238,6 +242,9 @@ static void __init init_resources(void) + goto error; + } + ++ num_standard_resources = non_resv_res; ++ standard_resources = &mem_res[res_idx + 1]; ++ + /* Clean-up any unused pre-allocated resources */ + if (res_idx >= 0) + memblock_free(__pa(mem_res), (res_idx + 1) * sizeof(*mem_res)); +@@ -249,6 +256,33 @@ static void __init init_resources(void) + memblock_free(__pa(mem_res), mem_res_sz); + } + ++static int __init reserve_memblock_reserved_regions(void) ++{ ++ u64 i, j; ++ ++ for (i = 0; i < num_standard_resources; i++) { ++ struct resource *mem = &standard_resources[i]; ++ phys_addr_t r_start, r_end, mem_size = resource_size(mem); ++ ++ if (!memblock_is_region_reserved(mem->start, mem_size)) ++ continue; ++ ++ for_each_reserved_mem_range(j, &r_start, &r_end) { ++ resource_size_t start, end; ++ ++ start = max(PFN_PHYS(PFN_DOWN(r_start)), mem->start); ++ end = min(PFN_PHYS(PFN_UP(r_end)) - 1, mem->end); ++ ++ if (start > mem->end || end < mem->start) ++ continue; ++ ++ reserve_region_with_split(mem, start, end, "Reserved"); ++ } ++ } ++ ++ return 0; ++} ++arch_initcall(reserve_memblock_reserved_regions); + + static void __init parse_dtb(void) + { +-- +2.39.5 + diff --git a/queue-5.15/scsi-hisi_sas-enable-force-phy-when-sata-disk-direct.patch b/queue-5.15/scsi-hisi_sas-enable-force-phy-when-sata-disk-direct.patch new file mode 100644 index 0000000000..906e4f57b1 --- /dev/null +++ b/queue-5.15/scsi-hisi_sas-enable-force-phy-when-sata-disk-direct.patch @@ -0,0 +1,102 @@ +From 223511b28349c05e380602c5f3d9dedb8c226179 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 12 Mar 2025 17:51:34 +0800 +Subject: scsi: hisi_sas: Enable force phy when SATA disk directly connected + +From: Xingui Yang + +[ Upstream commit 8aa580cd92843b60d4d6331f3b0a9e8409bb70eb ] + +when a SATA disk is directly connected the SAS controller determines the +disk to which I/Os are delivered based on the port ID in the DQ entry. + +When many phys are disconnected and reconnect, the port ID of phys were +changed and used by other link, resulting in I/O being sent to incorrect +disk. Data inconsistency on the SATA disk may occur during I/O retries +using the old port ID. So enable force phy, then force the command to be +executed in a certain phy, and if the actual phy ID of the port does not +match the phy configured in the command, the chip will stop delivering the +I/O to disk. + +Fixes: ce60689e12dd ("scsi: hisi_sas: add v3 code to send ATA frame") +Signed-off-by: Xingui Yang +Link: https://lore.kernel.org/r/20250312095135.3048379-2-yangxingui@huawei.com +Reviewed-by: Yihang Li +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 9 +++++++-- + drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 14 ++++++++++++-- + 2 files changed, 19 insertions(+), 4 deletions(-) + +diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +index 9a8009fc3f206..0582737b1d30a 100644 +--- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c ++++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +@@ -2500,6 +2500,7 @@ static void prep_ata_v2_hw(struct hisi_hba *hisi_hba, + struct asd_sas_port *sas_port = device->port; + struct hisi_sas_port *port = to_hisi_sas_port(sas_port); + struct sas_tmf_task *tmf = slot->tmf; ++ int phy_id; + u8 *buf_cmd; + int has_data = 0, hdr_tag = 0; + u32 dw0, dw1 = 0, dw2 = 0; +@@ -2507,10 +2508,14 @@ static void prep_ata_v2_hw(struct hisi_hba *hisi_hba, + /* create header */ + /* dw0 */ + dw0 = port->id << CMD_HDR_PORT_OFF; +- if (parent_dev && dev_is_expander(parent_dev->dev_type)) ++ if (parent_dev && dev_is_expander(parent_dev->dev_type)) { + dw0 |= 3 << CMD_HDR_CMD_OFF; +- else ++ } else { ++ phy_id = device->phy->identify.phy_identifier; ++ dw0 |= (1U << phy_id) << CMD_HDR_PHY_ID_OFF; ++ dw0 |= CMD_HDR_FORCE_PHY_MSK; + dw0 |= 4 << CMD_HDR_CMD_OFF; ++ } + + if (tmf && tmf->force_phy) { + dw0 |= CMD_HDR_FORCE_PHY_MSK; +diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +index 2fce1c0a54635..6d467ae9d337c 100644 +--- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c ++++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +@@ -356,6 +356,10 @@ + #define CMD_HDR_RESP_REPORT_MSK (0x1 << CMD_HDR_RESP_REPORT_OFF) + #define CMD_HDR_TLR_CTRL_OFF 6 + #define CMD_HDR_TLR_CTRL_MSK (0x3 << CMD_HDR_TLR_CTRL_OFF) ++#define CMD_HDR_PHY_ID_OFF 8 ++#define CMD_HDR_PHY_ID_MSK (0x1ff << CMD_HDR_PHY_ID_OFF) ++#define CMD_HDR_FORCE_PHY_OFF 17 ++#define CMD_HDR_FORCE_PHY_MSK (0x1U << CMD_HDR_FORCE_PHY_OFF) + #define CMD_HDR_PORT_OFF 18 + #define CMD_HDR_PORT_MSK (0xf << CMD_HDR_PORT_OFF) + #define CMD_HDR_PRIORITY_OFF 27 +@@ -1384,15 +1388,21 @@ static void prep_ata_v3_hw(struct hisi_hba *hisi_hba, + struct hisi_sas_cmd_hdr *hdr = slot->cmd_hdr; + struct asd_sas_port *sas_port = device->port; + struct hisi_sas_port *port = to_hisi_sas_port(sas_port); ++ int phy_id; + u8 *buf_cmd; + int has_data = 0, hdr_tag = 0; + u32 dw1 = 0, dw2 = 0; + + hdr->dw0 = cpu_to_le32(port->id << CMD_HDR_PORT_OFF); +- if (parent_dev && dev_is_expander(parent_dev->dev_type)) ++ if (parent_dev && dev_is_expander(parent_dev->dev_type)) { + hdr->dw0 |= cpu_to_le32(3 << CMD_HDR_CMD_OFF); +- else ++ } else { ++ phy_id = device->phy->identify.phy_identifier; ++ hdr->dw0 |= cpu_to_le32((1U << phy_id) ++ << CMD_HDR_PHY_ID_OFF); ++ hdr->dw0 |= CMD_HDR_FORCE_PHY_MSK; + hdr->dw0 |= cpu_to_le32(4U << CMD_HDR_CMD_OFF); ++ } + + switch (task->data_dir) { + case DMA_TO_DEVICE: +-- +2.39.5 + diff --git a/queue-5.15/scsi-hisi_sas-factor-out-task-prep-and-delivery-code.patch b/queue-5.15/scsi-hisi_sas-factor-out-task-prep-and-delivery-code.patch new file mode 100644 index 0000000000..f30a19228e --- /dev/null +++ b/queue-5.15/scsi-hisi_sas-factor-out-task-prep-and-delivery-code.patch @@ -0,0 +1,405 @@ +From 6110e7819dbbdc9163a572696e079302c3f34627 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Dec 2021 22:37:37 +0800 +Subject: scsi: hisi_sas: Factor out task prep and delivery code + +From: John Garry + +[ Upstream commit dc313f6b125b095d3d2683d94d5f69c8dc9bdc36 ] + +The task prep code is the same between the normal path (in +hisi_sas_task_prep()) and the internal abort path, so factor is out into a +common function. + +Link: https://lore.kernel.org/r/1639579061-179473-5-git-send-email-john.garry@huawei.com +Signed-off-by: John Garry +Signed-off-by: Martin K. Petersen +Stable-dep-of: 8aa580cd9284 ("scsi: hisi_sas: Enable force phy when SATA disk directly connected") +Signed-off-by: Sasha Levin +--- + drivers/scsi/hisi_sas/hisi_sas_main.c | 281 ++++++++++++-------------- + 1 file changed, 124 insertions(+), 157 deletions(-) + +diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c +index 321e6fae03adc..b9f4f7fadfd40 100644 +--- a/drivers/scsi/hisi_sas/hisi_sas_main.c ++++ b/drivers/scsi/hisi_sas/hisi_sas_main.c +@@ -403,94 +403,20 @@ static int hisi_sas_dif_dma_map(struct hisi_hba *hisi_hba, + return rc; + } + +-static int hisi_sas_task_prep(struct sas_task *task, +- struct hisi_sas_dq **dq_pointer, +- bool is_tmf, struct hisi_sas_tmf_task *tmf) ++static ++void hisi_sas_task_deliver(struct hisi_hba *hisi_hba, ++ struct hisi_sas_slot *slot, ++ struct hisi_sas_dq *dq, ++ struct hisi_sas_device *sas_dev, ++ struct hisi_sas_internal_abort *abort, ++ struct hisi_sas_tmf_task *tmf) + { +- struct domain_device *device = task->dev; +- struct hisi_hba *hisi_hba = dev_to_hisi_hba(device); +- struct hisi_sas_device *sas_dev = device->lldd_dev; +- struct hisi_sas_port *port; +- struct hisi_sas_slot *slot; +- struct hisi_sas_cmd_hdr *cmd_hdr_base; +- struct asd_sas_port *sas_port = device->port; +- struct device *dev = hisi_hba->dev; +- int dlvry_queue_slot, dlvry_queue, rc, slot_idx; +- int n_elem = 0, n_elem_dif = 0, n_elem_req = 0; +- struct scsi_cmnd *scmd = NULL; +- struct hisi_sas_dq *dq; ++ struct hisi_sas_cmd_hdr *cmd_hdr_base; ++ int dlvry_queue_slot, dlvry_queue; ++ struct sas_task *task = slot->task; + unsigned long flags; + int wr_q_index; + +- if (DEV_IS_GONE(sas_dev)) { +- if (sas_dev) +- dev_info(dev, "task prep: device %d not ready\n", +- sas_dev->device_id); +- else +- dev_info(dev, "task prep: device %016llx not ready\n", +- SAS_ADDR(device->sas_addr)); +- +- return -ECOMM; +- } +- +- if (task->uldd_task) { +- struct ata_queued_cmd *qc; +- +- if (dev_is_sata(device)) { +- qc = task->uldd_task; +- scmd = qc->scsicmd; +- } else { +- scmd = task->uldd_task; +- } +- } +- +- if (scmd) { +- unsigned int dq_index; +- u32 blk_tag; +- +- blk_tag = blk_mq_unique_tag(scsi_cmd_to_rq(scmd)); +- dq_index = blk_mq_unique_tag_to_hwq(blk_tag); +- *dq_pointer = dq = &hisi_hba->dq[dq_index]; +- } else { +- struct Scsi_Host *shost = hisi_hba->shost; +- struct blk_mq_queue_map *qmap = &shost->tag_set.map[HCTX_TYPE_DEFAULT]; +- int queue = qmap->mq_map[raw_smp_processor_id()]; +- +- *dq_pointer = dq = &hisi_hba->dq[queue]; +- } +- +- port = to_hisi_sas_port(sas_port); +- if (port && !port->port_attached) { +- dev_info(dev, "task prep: %s port%d not attach device\n", +- (dev_is_sata(device)) ? +- "SATA/STP" : "SAS", +- device->port->id); +- +- return -ECOMM; +- } +- +- rc = hisi_sas_dma_map(hisi_hba, task, &n_elem, +- &n_elem_req); +- if (rc < 0) +- goto prep_out; +- +- if (!sas_protocol_ata(task->task_proto)) { +- rc = hisi_sas_dif_dma_map(hisi_hba, &n_elem_dif, task); +- if (rc < 0) +- goto err_out_dma_unmap; +- } +- +- if (hisi_hba->hw->slot_index_alloc) +- rc = hisi_hba->hw->slot_index_alloc(hisi_hba, device); +- else +- rc = hisi_sas_slot_index_alloc(hisi_hba, scmd); +- +- if (rc < 0) +- goto err_out_dif_dma_unmap; +- +- slot_idx = rc; +- slot = &hisi_hba->slot_info[slot_idx]; +- + spin_lock(&dq->lock); + wr_q_index = dq->wr_point; + dq->wr_point = (dq->wr_point + 1) % HISI_SAS_QUEUE_SLOTS; +@@ -504,16 +430,13 @@ static int hisi_sas_task_prep(struct sas_task *task, + dlvry_queue_slot = wr_q_index; + + slot->device_id = sas_dev->device_id; +- slot->n_elem = n_elem; +- slot->n_elem_dif = n_elem_dif; + slot->dlvry_queue = dlvry_queue; + slot->dlvry_queue_slot = dlvry_queue_slot; + cmd_hdr_base = hisi_hba->cmd_hdr[dlvry_queue]; + slot->cmd_hdr = &cmd_hdr_base[dlvry_queue_slot]; +- slot->task = task; +- slot->port = port; ++ + slot->tmf = tmf; +- slot->is_internal = is_tmf; ++ slot->is_internal = tmf; + task->lldd_task = slot; + + memset(slot->cmd_hdr, 0, sizeof(struct hisi_sas_cmd_hdr)); +@@ -533,8 +456,14 @@ static int hisi_sas_task_prep(struct sas_task *task, + case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP: + hisi_sas_task_prep_ata(hisi_hba, slot); + break; ++ case SAS_PROTOCOL_NONE: ++ if (abort) { ++ hisi_sas_task_prep_abort(hisi_hba, abort, slot, sas_dev->device_id); ++ break; ++ } ++ fallthrough; + default: +- dev_err(dev, "task prep: unknown/unsupported proto (0x%x)\n", ++ dev_err(hisi_hba->dev, "task prep: unknown/unsupported proto (0x%x)\n", + task->task_proto); + break; + } +@@ -548,29 +477,22 @@ static int hisi_sas_task_prep(struct sas_task *task, + spin_lock(&dq->lock); + hisi_hba->hw->start_delivery(dq); + spin_unlock(&dq->lock); +- +- return 0; +- +-err_out_dif_dma_unmap: +- if (!sas_protocol_ata(task->task_proto)) +- hisi_sas_dif_dma_unmap(hisi_hba, task, n_elem_dif); +-err_out_dma_unmap: +- hisi_sas_dma_unmap(hisi_hba, task, n_elem, +- n_elem_req); +-prep_out: +- dev_err(dev, "task prep: failed[%d]!\n", rc); +- return rc; + } + + static int hisi_sas_task_exec(struct sas_task *task, gfp_t gfp_flags, +- bool is_tmf, struct hisi_sas_tmf_task *tmf) ++ struct hisi_sas_tmf_task *tmf) + { +- u32 rc; +- struct hisi_hba *hisi_hba; +- struct device *dev; ++ int n_elem = 0, n_elem_dif = 0, n_elem_req = 0; + struct domain_device *device = task->dev; + struct asd_sas_port *sas_port = device->port; ++ struct hisi_sas_device *sas_dev = device->lldd_dev; ++ struct scsi_cmnd *scmd = NULL; + struct hisi_sas_dq *dq = NULL; ++ struct hisi_sas_port *port; ++ struct hisi_hba *hisi_hba; ++ struct hisi_sas_slot *slot; ++ struct device *dev; ++ int rc; + + if (!sas_port) { + struct task_status_struct *ts = &task->task_status; +@@ -597,11 +519,94 @@ static int hisi_sas_task_exec(struct sas_task *task, gfp_t gfp_flags, + up(&hisi_hba->sem); + } + ++ if (DEV_IS_GONE(sas_dev)) { ++ if (sas_dev) ++ dev_info(dev, "task prep: device %d not ready\n", ++ sas_dev->device_id); ++ else ++ dev_info(dev, "task prep: device %016llx not ready\n", ++ SAS_ADDR(device->sas_addr)); ++ ++ return -ECOMM; ++ } ++ ++ if (task->uldd_task) { ++ struct ata_queued_cmd *qc; ++ ++ if (dev_is_sata(device)) { ++ qc = task->uldd_task; ++ scmd = qc->scsicmd; ++ } else { ++ scmd = task->uldd_task; ++ } ++ } ++ ++ if (scmd) { ++ unsigned int dq_index; ++ u32 blk_tag; ++ ++ blk_tag = blk_mq_unique_tag(scsi_cmd_to_rq(scmd)); ++ dq_index = blk_mq_unique_tag_to_hwq(blk_tag); ++ dq = &hisi_hba->dq[dq_index]; ++ } else { ++ struct Scsi_Host *shost = hisi_hba->shost; ++ struct blk_mq_queue_map *qmap = &shost->tag_set.map[HCTX_TYPE_DEFAULT]; ++ int queue = qmap->mq_map[raw_smp_processor_id()]; ++ ++ dq = &hisi_hba->dq[queue]; ++ } ++ ++ port = to_hisi_sas_port(sas_port); ++ if (port && !port->port_attached) { ++ dev_info(dev, "task prep: %s port%d not attach device\n", ++ (dev_is_sata(device)) ? ++ "SATA/STP" : "SAS", ++ device->port->id); ++ ++ return -ECOMM; ++ } ++ ++ rc = hisi_sas_dma_map(hisi_hba, task, &n_elem, ++ &n_elem_req); ++ if (rc < 0) ++ goto prep_out; ++ ++ if (!sas_protocol_ata(task->task_proto)) { ++ rc = hisi_sas_dif_dma_map(hisi_hba, &n_elem_dif, task); ++ if (rc < 0) ++ goto err_out_dma_unmap; ++ } ++ ++ if (hisi_hba->hw->slot_index_alloc) ++ rc = hisi_hba->hw->slot_index_alloc(hisi_hba, device); ++ else ++ rc = hisi_sas_slot_index_alloc(hisi_hba, scmd); ++ ++ if (rc < 0) ++ goto err_out_dif_dma_unmap; ++ ++ slot = &hisi_hba->slot_info[rc]; ++ slot->n_elem = n_elem; ++ slot->n_elem_dif = n_elem_dif; ++ slot->task = task; ++ slot->port = port; ++ ++ slot->tmf = tmf; ++ slot->is_internal = tmf; ++ + /* protect task_prep and start_delivery sequence */ +- rc = hisi_sas_task_prep(task, &dq, is_tmf, tmf); +- if (rc) +- dev_err(dev, "task exec: failed[%d]!\n", rc); ++ hisi_sas_task_deliver(hisi_hba, slot, dq, sas_dev, NULL, tmf); + ++ return 0; ++ ++err_out_dif_dma_unmap: ++ if (!sas_protocol_ata(task->task_proto)) ++ hisi_sas_dif_dma_unmap(hisi_hba, task, n_elem_dif); ++err_out_dma_unmap: ++ hisi_sas_dma_unmap(hisi_hba, task, n_elem, ++ n_elem_req); ++prep_out: ++ dev_err(dev, "task exec: failed[%d]!\n", rc); + return rc; + } + +@@ -1089,7 +1094,7 @@ static void hisi_sas_dev_gone(struct domain_device *device) + + static int hisi_sas_queue_command(struct sas_task *task, gfp_t gfp_flags) + { +- return hisi_sas_task_exec(task, gfp_flags, 0, NULL); ++ return hisi_sas_task_exec(task, gfp_flags, NULL); + } + + static int hisi_sas_phy_set_linkrate(struct hisi_hba *hisi_hba, int phy_no, +@@ -1221,8 +1226,7 @@ static int hisi_sas_exec_internal_tmf_task(struct domain_device *device, + task->slow_task->timer.expires = jiffies + TASK_TIMEOUT; + add_timer(&task->slow_task->timer); + +- res = hisi_sas_task_exec(task, GFP_KERNEL, 1, tmf); +- ++ res = hisi_sas_task_exec(task, GFP_KERNEL, tmf); + if (res) { + del_timer(&task->slow_task->timer); + dev_err(dev, "abort tmf: executing internal task failed: %d\n", +@@ -1976,12 +1980,9 @@ hisi_sas_internal_abort_task_exec(struct hisi_hba *hisi_hba, int device_id, + struct hisi_sas_device *sas_dev = device->lldd_dev; + struct device *dev = hisi_hba->dev; + struct hisi_sas_port *port; +- struct hisi_sas_slot *slot; + struct asd_sas_port *sas_port = device->port; +- struct hisi_sas_cmd_hdr *cmd_hdr_base; +- int dlvry_queue_slot, dlvry_queue, n_elem = 0, rc, slot_idx; +- unsigned long flags; +- int wr_q_index; ++ struct hisi_sas_slot *slot; ++ int slot_idx; + + if (unlikely(test_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags))) + return -EINVAL; +@@ -1992,58 +1993,24 @@ hisi_sas_internal_abort_task_exec(struct hisi_hba *hisi_hba, int device_id, + port = to_hisi_sas_port(sas_port); + + /* simply get a slot and send abort command */ +- rc = hisi_sas_slot_index_alloc(hisi_hba, NULL); +- if (rc < 0) ++ slot_idx = hisi_sas_slot_index_alloc(hisi_hba, NULL); ++ if (slot_idx < 0) + goto err_out; + +- slot_idx = rc; + slot = &hisi_hba->slot_info[slot_idx]; +- +- spin_lock(&dq->lock); +- wr_q_index = dq->wr_point; +- dq->wr_point = (dq->wr_point + 1) % HISI_SAS_QUEUE_SLOTS; +- list_add_tail(&slot->delivery, &dq->list); +- spin_unlock(&dq->lock); +- spin_lock(&sas_dev->lock); +- list_add_tail(&slot->entry, &sas_dev->list); +- spin_unlock(&sas_dev->lock); +- +- dlvry_queue = dq->id; +- dlvry_queue_slot = wr_q_index; +- +- slot->device_id = sas_dev->device_id; +- slot->n_elem = n_elem; +- slot->dlvry_queue = dlvry_queue; +- slot->dlvry_queue_slot = dlvry_queue_slot; +- cmd_hdr_base = hisi_hba->cmd_hdr[dlvry_queue]; +- slot->cmd_hdr = &cmd_hdr_base[dlvry_queue_slot]; ++ slot->n_elem = 0; + slot->task = task; + slot->port = port; + slot->is_internal = true; +- task->lldd_task = slot; + +- memset(slot->cmd_hdr, 0, sizeof(struct hisi_sas_cmd_hdr)); +- memset(hisi_sas_cmd_hdr_addr_mem(slot), 0, HISI_SAS_COMMAND_TABLE_SZ); +- memset(hisi_sas_status_buf_addr_mem(slot), 0, +- sizeof(struct hisi_sas_err_record)); +- +- hisi_sas_task_prep_abort(hisi_hba, abort, slot, device_id); +- +- spin_lock_irqsave(&task->task_state_lock, flags); +- task->task_state_flags |= SAS_TASK_AT_INITIATOR; +- spin_unlock_irqrestore(&task->task_state_lock, flags); +- WRITE_ONCE(slot->ready, 1); +- /* send abort command to the chip */ +- spin_lock(&dq->lock); +- hisi_hba->hw->start_delivery(dq); +- spin_unlock(&dq->lock); ++ hisi_sas_task_deliver(hisi_hba, slot, dq, sas_dev, abort, NULL); + + return 0; + + err_out: +- dev_err(dev, "internal abort task prep: failed[%d]!\n", rc); ++ dev_err(dev, "internal abort task prep: failed[%d]!\n", slot_idx); + +- return rc; ++ return slot_idx; + } + + /** +-- +2.39.5 + diff --git a/queue-5.15/scsi-hisi_sas-fix-setting-of-hisi_sas_slot.is_intern.patch b/queue-5.15/scsi-hisi_sas-fix-setting-of-hisi_sas_slot.is_intern.patch new file mode 100644 index 0000000000..a943f30c98 --- /dev/null +++ b/queue-5.15/scsi-hisi_sas-fix-setting-of-hisi_sas_slot.is_intern.patch @@ -0,0 +1,93 @@ +From 52a4077b35ad3f3c992c4166cbfde070649f18ac Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 31 Jan 2022 19:13:27 +0800 +Subject: scsi: hisi_sas: Fix setting of hisi_sas_slot.is_internal + +From: John Garry + +[ Upstream commit c763ec4c10f78678d6d4415646237f07109a5a5f ] + +The hisi_sas_slot.is_internal member is not set properly for ATA commands +which the driver sends directly. A TMF struct pointer is normally used as a +test to set this, but it is NULL for those commands. It's not ideal, but +pass an empty TMF struct to set that member properly. + +Link: https://lore.kernel.org/r/1643627607-138785-1-git-send-email-john.garry@huawei.com +Fixes: dc313f6b125b ("scsi: hisi_sas: Factor out task prep and delivery code") +Reported-by: Xiang Chen +Signed-off-by: John Garry +Signed-off-by: Martin K. Petersen +Stable-dep-of: 8aa580cd9284 ("scsi: hisi_sas: Enable force phy when SATA disk directly connected") +Signed-off-by: Sasha Levin +--- + drivers/scsi/hisi_sas/hisi_sas_main.c | 14 ++++++-------- + 1 file changed, 6 insertions(+), 8 deletions(-) + +diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c +index b9f4f7fadfd40..9663492e566d1 100644 +--- a/drivers/scsi/hisi_sas/hisi_sas_main.c ++++ b/drivers/scsi/hisi_sas/hisi_sas_main.c +@@ -408,8 +408,7 @@ void hisi_sas_task_deliver(struct hisi_hba *hisi_hba, + struct hisi_sas_slot *slot, + struct hisi_sas_dq *dq, + struct hisi_sas_device *sas_dev, +- struct hisi_sas_internal_abort *abort, +- struct hisi_sas_tmf_task *tmf) ++ struct hisi_sas_internal_abort *abort) + { + struct hisi_sas_cmd_hdr *cmd_hdr_base; + int dlvry_queue_slot, dlvry_queue; +@@ -435,8 +434,6 @@ void hisi_sas_task_deliver(struct hisi_hba *hisi_hba, + cmd_hdr_base = hisi_hba->cmd_hdr[dlvry_queue]; + slot->cmd_hdr = &cmd_hdr_base[dlvry_queue_slot]; + +- slot->tmf = tmf; +- slot->is_internal = tmf; + task->lldd_task = slot; + + memset(slot->cmd_hdr, 0, sizeof(struct hisi_sas_cmd_hdr)); +@@ -595,7 +592,7 @@ static int hisi_sas_task_exec(struct sas_task *task, gfp_t gfp_flags, + slot->is_internal = tmf; + + /* protect task_prep and start_delivery sequence */ +- hisi_sas_task_deliver(hisi_hba, slot, dq, sas_dev, NULL, tmf); ++ hisi_sas_task_deliver(hisi_hba, slot, dq, sas_dev, NULL); + + return 0; + +@@ -1333,12 +1330,13 @@ static int hisi_sas_softreset_ata_disk(struct domain_device *device) + struct hisi_hba *hisi_hba = dev_to_hisi_hba(device); + struct device *dev = hisi_hba->dev; + int s = sizeof(struct host_to_dev_fis); ++ struct hisi_sas_tmf_task tmf = {}; + + ata_for_each_link(link, ap, EDGE) { + int pmp = sata_srst_pmp(link); + + hisi_sas_fill_ata_reset_cmd(link->device, 1, pmp, fis); +- rc = hisi_sas_exec_internal_tmf_task(device, fis, s, NULL); ++ rc = hisi_sas_exec_internal_tmf_task(device, fis, s, &tmf); + if (rc != TMF_RESP_FUNC_COMPLETE) + break; + } +@@ -1349,7 +1347,7 @@ static int hisi_sas_softreset_ata_disk(struct domain_device *device) + + hisi_sas_fill_ata_reset_cmd(link->device, 0, pmp, fis); + rc = hisi_sas_exec_internal_tmf_task(device, fis, +- s, NULL); ++ s, &tmf); + if (rc != TMF_RESP_FUNC_COMPLETE) + dev_err(dev, "ata disk %016llx de-reset failed\n", + SAS_ADDR(device->sas_addr)); +@@ -2003,7 +2001,7 @@ hisi_sas_internal_abort_task_exec(struct hisi_hba *hisi_hba, int device_id, + slot->port = port; + slot->is_internal = true; + +- hisi_sas_task_deliver(hisi_hba, slot, dq, sas_dev, abort, NULL); ++ hisi_sas_task_deliver(hisi_hba, slot, dq, sas_dev, abort); + + return 0; + +-- +2.39.5 + diff --git a/queue-5.15/scsi-hisi_sas-pass-abort-structure-for-internal-abor.patch b/queue-5.15/scsi-hisi_sas-pass-abort-structure-for-internal-abor.patch new file mode 100644 index 0000000000..f688bbea0f --- /dev/null +++ b/queue-5.15/scsi-hisi_sas-pass-abort-structure-for-internal-abor.patch @@ -0,0 +1,107 @@ +From f2750028dfd256b2a9ef10e1b6f854db8d6e39b5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Dec 2021 22:37:36 +0800 +Subject: scsi: hisi_sas: Pass abort structure for internal abort + +From: John Garry + +[ Upstream commit 08c61b5d902b70180b517e9f2616ad70b7a98dcf ] + +To help factor out code in future, it's useful to know if we're executing +an internal abort, so pass a pointer to the structure. The idea is that a +NULL pointer means not an internal abort. + +Link: https://lore.kernel.org/r/1639579061-179473-4-git-send-email-john.garry@huawei.com +Reviewed-by: Xiang Chen +Signed-off-by: John Garry +Signed-off-by: Martin K. Petersen +Stable-dep-of: 8aa580cd9284 ("scsi: hisi_sas: Enable force phy when SATA disk directly connected") +Signed-off-by: Sasha Levin +--- + drivers/scsi/hisi_sas/hisi_sas.h | 5 +++++ + drivers/scsi/hisi_sas/hisi_sas_main.c | 21 ++++++++++++--------- + 2 files changed, 17 insertions(+), 9 deletions(-) + +diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h +index 57be32ba0109f..39da9f1645135 100644 +--- a/drivers/scsi/hisi_sas/hisi_sas.h ++++ b/drivers/scsi/hisi_sas/hisi_sas.h +@@ -134,6 +134,11 @@ struct hisi_sas_rst { + bool done; + }; + ++struct hisi_sas_internal_abort { ++ unsigned int flag; ++ unsigned int tag; ++}; ++ + #define HISI_SAS_RST_WORK_INIT(r, c) \ + { .hisi_hba = hisi_hba, \ + .completion = &c, \ +diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c +index ff6b6868cd955..321e6fae03adc 100644 +--- a/drivers/scsi/hisi_sas/hisi_sas_main.c ++++ b/drivers/scsi/hisi_sas/hisi_sas_main.c +@@ -273,11 +273,11 @@ static void hisi_sas_task_prep_ata(struct hisi_hba *hisi_hba, + } + + static void hisi_sas_task_prep_abort(struct hisi_hba *hisi_hba, +- struct hisi_sas_slot *slot, +- int device_id, int abort_flag, int tag_to_abort) ++ struct hisi_sas_internal_abort *abort, ++ struct hisi_sas_slot *slot, int device_id) + { + hisi_hba->hw->prep_abort(hisi_hba, slot, +- device_id, abort_flag, tag_to_abort); ++ device_id, abort->flag, abort->tag); + } + + static void hisi_sas_dma_unmap(struct hisi_hba *hisi_hba, +@@ -1968,8 +1968,9 @@ static int hisi_sas_query_task(struct sas_task *task) + + static int + hisi_sas_internal_abort_task_exec(struct hisi_hba *hisi_hba, int device_id, +- struct sas_task *task, int abort_flag, +- int task_tag, struct hisi_sas_dq *dq) ++ struct hisi_sas_internal_abort *abort, ++ struct sas_task *task, ++ struct hisi_sas_dq *dq) + { + struct domain_device *device = task->dev; + struct hisi_sas_device *sas_dev = device->lldd_dev; +@@ -2026,8 +2027,7 @@ hisi_sas_internal_abort_task_exec(struct hisi_hba *hisi_hba, int device_id, + memset(hisi_sas_status_buf_addr_mem(slot), 0, + sizeof(struct hisi_sas_err_record)); + +- hisi_sas_task_prep_abort(hisi_hba, slot, device_id, +- abort_flag, task_tag); ++ hisi_sas_task_prep_abort(hisi_hba, abort, slot, device_id); + + spin_lock_irqsave(&task->task_state_lock, flags); + task->task_state_flags |= SAS_TASK_AT_INITIATOR; +@@ -2065,9 +2065,12 @@ _hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba, + { + struct sas_task *task; + struct hisi_sas_device *sas_dev = device->lldd_dev; ++ struct hisi_sas_internal_abort abort = { ++ .flag = abort_flag, ++ .tag = tag, ++ }; + struct device *dev = hisi_hba->dev; + int res; +- + /* + * The interface is not realized means this HW don't support internal + * abort, or don't need to do internal abort. Then here, we return +@@ -2092,7 +2095,7 @@ _hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba, + add_timer(&task->slow_task->timer); + + res = hisi_sas_internal_abort_task_exec(hisi_hba, sas_dev->device_id, +- task, abort_flag, tag, dq); ++ &abort, task, dq); + if (res) { + del_timer(&task->slow_task->timer); + dev_err(dev, "internal task abort: executing internal task failed: %d\n", +-- +2.39.5 + diff --git a/queue-5.15/scsi-hisi_sas-start-delivery-hisi_sas_task_exec-dire.patch b/queue-5.15/scsi-hisi_sas-start-delivery-hisi_sas_task_exec-dire.patch new file mode 100644 index 0000000000..f04045af08 --- /dev/null +++ b/queue-5.15/scsi-hisi_sas-start-delivery-hisi_sas_task_exec-dire.patch @@ -0,0 +1,82 @@ +From f5cf54854715f64beb2a3761a059aa6f37f39c9a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Dec 2021 22:37:34 +0800 +Subject: scsi: hisi_sas: Start delivery hisi_sas_task_exec() directly + +From: John Garry + +[ Upstream commit 0e4620856b89335426a17904933a92346ee4599d ] + +Currently we start delivery of commands to the DQ after returning from +hisi_sas_task_exec() with success. + +Let's just start delivery directly in that function without having to check +if some local variable is set. + +Link: https://lore.kernel.org/r/1639579061-179473-2-git-send-email-john.garry@huawei.com +Reviewed-by: Xiang Chen +Signed-off-by: John Garry +Signed-off-by: Martin K. Petersen +Stable-dep-of: 8aa580cd9284 ("scsi: hisi_sas: Enable force phy when SATA disk directly connected") +Signed-off-by: Sasha Levin +--- + drivers/scsi/hisi_sas/hisi_sas_main.c | 17 ++++++----------- + 1 file changed, 6 insertions(+), 11 deletions(-) + +diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c +index 530f61df109a3..ff6b6868cd955 100644 +--- a/drivers/scsi/hisi_sas/hisi_sas_main.c ++++ b/drivers/scsi/hisi_sas/hisi_sas_main.c +@@ -405,8 +405,7 @@ static int hisi_sas_dif_dma_map(struct hisi_hba *hisi_hba, + + static int hisi_sas_task_prep(struct sas_task *task, + struct hisi_sas_dq **dq_pointer, +- bool is_tmf, struct hisi_sas_tmf_task *tmf, +- int *pass) ++ bool is_tmf, struct hisi_sas_tmf_task *tmf) + { + struct domain_device *device = task->dev; + struct hisi_hba *hisi_hba = dev_to_hisi_hba(device); +@@ -544,9 +543,12 @@ static int hisi_sas_task_prep(struct sas_task *task, + task->task_state_flags |= SAS_TASK_AT_INITIATOR; + spin_unlock_irqrestore(&task->task_state_lock, flags); + +- ++(*pass); + WRITE_ONCE(slot->ready, 1); + ++ spin_lock(&dq->lock); ++ hisi_hba->hw->start_delivery(dq); ++ spin_unlock(&dq->lock); ++ + return 0; + + err_out_dif_dma_unmap: +@@ -564,7 +566,6 @@ static int hisi_sas_task_exec(struct sas_task *task, gfp_t gfp_flags, + bool is_tmf, struct hisi_sas_tmf_task *tmf) + { + u32 rc; +- u32 pass = 0; + struct hisi_hba *hisi_hba; + struct device *dev; + struct domain_device *device = task->dev; +@@ -597,16 +598,10 @@ static int hisi_sas_task_exec(struct sas_task *task, gfp_t gfp_flags, + } + + /* protect task_prep and start_delivery sequence */ +- rc = hisi_sas_task_prep(task, &dq, is_tmf, tmf, &pass); ++ rc = hisi_sas_task_prep(task, &dq, is_tmf, tmf); + if (rc) + dev_err(dev, "task exec: failed[%d]!\n", rc); + +- if (likely(pass)) { +- spin_lock(&dq->lock); +- hisi_hba->hw->start_delivery(dq); +- spin_unlock(&dq->lock); +- } +- + return rc; + } + +-- +2.39.5 + diff --git a/queue-5.15/scsi-iscsi-fix-missing-scsi_host_put-in-error-path.patch b/queue-5.15/scsi-iscsi-fix-missing-scsi_host_put-in-error-path.patch new file mode 100644 index 0000000000..a8d28070a1 --- /dev/null +++ b/queue-5.15/scsi-iscsi-fix-missing-scsi_host_put-in-error-path.patch @@ -0,0 +1,47 @@ +From df571167e937525c44c172bc876f2b202b911321 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 18 Mar 2025 17:43:43 +0800 +Subject: scsi: iscsi: Fix missing scsi_host_put() in error path + +From: Miaoqian Lin + +[ Upstream commit 72eea84a1092b50a10eeecfeba4b28ac9f1312ab ] + +Add goto to ensure scsi_host_put() is called in all error paths of +iscsi_set_host_param() function. This fixes a potential memory leak when +strlen() check fails. + +Fixes: ce51c8170084 ("scsi: iscsi: Add strlen() check in iscsi_if_set{_host}_param()") +Signed-off-by: Miaoqian Lin +Link: https://lore.kernel.org/r/20250318094344.91776-1-linmq006@gmail.com +Reviewed-by: Mike Christie +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/scsi/scsi_transport_iscsi.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c +index f839e8e497be3..8930acdff08c5 100644 +--- a/drivers/scsi/scsi_transport_iscsi.c ++++ b/drivers/scsi/scsi_transport_iscsi.c +@@ -3228,11 +3228,14 @@ iscsi_set_host_param(struct iscsi_transport *transport, + } + + /* see similar check in iscsi_if_set_param() */ +- if (strlen(data) > ev->u.set_host_param.len) +- return -EINVAL; ++ if (strlen(data) > ev->u.set_host_param.len) { ++ err = -EINVAL; ++ goto out; ++ } + + err = transport->set_host_param(shost, ev->u.set_host_param.param, + data, ev->u.set_host_param.len); ++out: + scsi_host_put(shost); + return err; + } +-- +2.39.5 + diff --git a/queue-5.15/scsi-libsas-add-struct-sas_tmf_task.patch b/queue-5.15/scsi-libsas-add-struct-sas_tmf_task.patch new file mode 100644 index 0000000000..bf0bc00e93 --- /dev/null +++ b/queue-5.15/scsi-libsas-add-struct-sas_tmf_task.patch @@ -0,0 +1,491 @@ +From c4869a3020e568cf4efd025f4191fbb2d6bc8032 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 17 Feb 2022 23:42:35 +0800 +Subject: scsi: libsas: Add struct sas_tmf_task + +From: John Garry + +[ Upstream commit bbfe82cdbaf84e6622ceb6f3447c8c4bb7dde7ab ] + +Some of the LLDDs which use libsas have their own definition of a struct +to hold TMF info, so add a common struct for libsas. + +Also add an interim force phy id field for hisi_sas driver, which will be +removed once the STP "TMF" code is factored out. + +Even though some LLDDs (pm8001) use a u32 for the tag, u16 will be adequate, +as that named driver only uses tags in range [0, 1024). + +Link: https://lore.kernel.org/r/1645112566-115804-8-git-send-email-john.garry@huawei.com +Tested-by: Yihang Li +Tested-by: Damien Le Moal +Reviewed-by: Christoph Hellwig +Signed-off-by: John Garry +Signed-off-by: Martin K. Petersen +Stable-dep-of: 8aa580cd9284 ("scsi: hisi_sas: Enable force phy when SATA disk directly connected") +Signed-off-by: Sasha Levin +--- + drivers/scsi/hisi_sas/hisi_sas.h | 9 +-------- + drivers/scsi/hisi_sas/hisi_sas_main.c | 22 +++++++++++----------- + drivers/scsi/hisi_sas/hisi_sas_v1_hw.c | 2 +- + drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 4 ++-- + drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 2 +- + drivers/scsi/mvsas/mv_defs.h | 5 ----- + drivers/scsi/mvsas/mv_sas.c | 20 ++++++++++---------- + drivers/scsi/pm8001/pm8001_hwi.c | 4 ++-- + drivers/scsi/pm8001/pm8001_sas.c | 18 +++++++++--------- + drivers/scsi/pm8001/pm8001_sas.h | 10 +++------- + include/scsi/libsas.h | 9 +++++++++ + 11 files changed, 49 insertions(+), 56 deletions(-) + +diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h +index 39da9f1645135..081b4e22a502f 100644 +--- a/drivers/scsi/hisi_sas/hisi_sas.h ++++ b/drivers/scsi/hisi_sas/hisi_sas.h +@@ -234,13 +234,6 @@ struct hisi_sas_device { + spinlock_t lock; /* For protecting slots */ + }; + +-struct hisi_sas_tmf_task { +- int force_phy; +- int phy_id; +- u8 tmf; +- u16 tag_of_task_to_be_managed; +-}; +- + struct hisi_sas_slot { + struct list_head entry; + struct list_head delivery; +@@ -259,7 +252,7 @@ struct hisi_sas_slot { + dma_addr_t cmd_hdr_dma; + struct timer_list internal_abort_timer; + bool is_internal; +- struct hisi_sas_tmf_task *tmf; ++ struct sas_tmf_task *tmf; + /* Do not reorder/change members after here */ + void *buf; + dma_addr_t buf_dma; +diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c +index bb95153bd22f0..0ca80e00835cb 100644 +--- a/drivers/scsi/hisi_sas/hisi_sas_main.c ++++ b/drivers/scsi/hisi_sas/hisi_sas_main.c +@@ -11,7 +11,7 @@ + ((!dev) || (dev->dev_type == SAS_PHY_UNUSED)) + + static int hisi_sas_debug_issue_ssp_tmf(struct domain_device *device, +- u8 *lun, struct hisi_sas_tmf_task *tmf); ++ u8 *lun, struct sas_tmf_task *tmf); + static int + hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba, + struct domain_device *device, +@@ -477,7 +477,7 @@ void hisi_sas_task_deliver(struct hisi_hba *hisi_hba, + } + + static int hisi_sas_task_exec(struct sas_task *task, gfp_t gfp_flags, +- struct hisi_sas_tmf_task *tmf) ++ struct sas_tmf_task *tmf) + { + int n_elem = 0, n_elem_dif = 0, n_elem_req = 0; + struct domain_device *device = task->dev; +@@ -691,7 +691,7 @@ static int hisi_sas_init_device(struct domain_device *device) + { + int rc = TMF_RESP_FUNC_COMPLETE; + struct scsi_lun lun; +- struct hisi_sas_tmf_task tmf_task; ++ struct sas_tmf_task tmf_task; + int retry = HISI_SAS_DISK_RECOVER_CNT; + struct hisi_hba *hisi_hba = dev_to_hisi_hba(device); + struct device *dev = hisi_hba->dev; +@@ -1195,7 +1195,7 @@ static void hisi_sas_tmf_timedout(struct timer_list *t) + #define INTERNAL_ABORT_TIMEOUT (6 * HZ) + static int hisi_sas_exec_internal_tmf_task(struct domain_device *device, + void *parameter, u32 para_len, +- struct hisi_sas_tmf_task *tmf) ++ struct sas_tmf_task *tmf) + { + struct hisi_sas_device *sas_dev = device->lldd_dev; + struct hisi_hba *hisi_hba = sas_dev->hisi_hba; +@@ -1330,7 +1330,7 @@ static int hisi_sas_softreset_ata_disk(struct domain_device *device) + struct hisi_hba *hisi_hba = dev_to_hisi_hba(device); + struct device *dev = hisi_hba->dev; + int s = sizeof(struct host_to_dev_fis); +- struct hisi_sas_tmf_task tmf = {}; ++ struct sas_tmf_task tmf = {}; + + ata_for_each_link(link, ap, EDGE) { + int pmp = sata_srst_pmp(link); +@@ -1364,7 +1364,7 @@ static int hisi_sas_softreset_ata_disk(struct domain_device *device) + } + + static int hisi_sas_debug_issue_ssp_tmf(struct domain_device *device, +- u8 *lun, struct hisi_sas_tmf_task *tmf) ++ u8 *lun, struct sas_tmf_task *tmf) + { + struct sas_ssp_task ssp_task; + +@@ -1469,7 +1469,7 @@ static void hisi_sas_send_ata_reset_each_phy(struct hisi_hba *hisi_hba, + struct asd_sas_port *sas_port, + struct domain_device *device) + { +- struct hisi_sas_tmf_task tmf_task = { .force_phy = 1 }; ++ struct sas_tmf_task tmf_task = { .force_phy = 1 }; + struct ata_port *ap = device->sata_dev.ap; + struct device *dev = hisi_hba->dev; + int s = sizeof(struct host_to_dev_fis); +@@ -1624,7 +1624,7 @@ static int hisi_sas_controller_reset(struct hisi_hba *hisi_hba) + static int hisi_sas_abort_task(struct sas_task *task) + { + struct scsi_lun lun; +- struct hisi_sas_tmf_task tmf_task; ++ struct sas_tmf_task tmf_task; + struct domain_device *device = task->dev; + struct hisi_sas_device *sas_dev = device->lldd_dev; + struct hisi_hba *hisi_hba; +@@ -1733,7 +1733,7 @@ static int hisi_sas_abort_task_set(struct domain_device *device, u8 *lun) + { + struct hisi_hba *hisi_hba = dev_to_hisi_hba(device); + struct device *dev = hisi_hba->dev; +- struct hisi_sas_tmf_task tmf_task; ++ struct sas_tmf_task tmf_task; + int rc; + + rc = hisi_sas_internal_task_abort(hisi_hba, device, +@@ -1868,7 +1868,7 @@ static int hisi_sas_lu_reset(struct domain_device *device, u8 *lun) + hisi_sas_release_task(hisi_hba, device); + sas_put_local_phy(phy); + } else { +- struct hisi_sas_tmf_task tmf_task = { .tmf = TMF_LU_RESET }; ++ struct sas_tmf_task tmf_task = { .tmf = TMF_LU_RESET }; + + rc = hisi_sas_debug_issue_ssp_tmf(device, lun, &tmf_task); + if (rc == TMF_RESP_FUNC_COMPLETE) +@@ -1926,7 +1926,7 @@ static int hisi_sas_clear_nexus_ha(struct sas_ha_struct *sas_ha) + static int hisi_sas_query_task(struct sas_task *task) + { + struct scsi_lun lun; +- struct hisi_sas_tmf_task tmf_task; ++ struct sas_tmf_task tmf_task; + int rc = TMF_RESP_FUNC_FAILED; + + if (task->lldd_task && task->task_proto & SAS_PROTOCOL_SSP) { +diff --git a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c +index 862f4e8b7eb58..76756dd318d75 100644 +--- a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c ++++ b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c +@@ -958,7 +958,7 @@ static void prep_ssp_v1_hw(struct hisi_hba *hisi_hba, + struct hisi_sas_port *port = slot->port; + struct sas_ssp_task *ssp_task = &task->ssp_task; + struct scsi_cmnd *scsi_cmnd = ssp_task->cmd; +- struct hisi_sas_tmf_task *tmf = slot->tmf; ++ struct sas_tmf_task *tmf = slot->tmf; + int has_data = 0, priority = !!tmf; + u8 *buf_cmd, fburst = 0; + u32 dw1, dw2; +diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +index a6d89a1495461..9a8009fc3f206 100644 +--- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c ++++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +@@ -1742,7 +1742,7 @@ static void prep_ssp_v2_hw(struct hisi_hba *hisi_hba, + struct hisi_sas_port *port = slot->port; + struct sas_ssp_task *ssp_task = &task->ssp_task; + struct scsi_cmnd *scsi_cmnd = ssp_task->cmd; +- struct hisi_sas_tmf_task *tmf = slot->tmf; ++ struct sas_tmf_task *tmf = slot->tmf; + int has_data = 0, priority = !!tmf; + u8 *buf_cmd; + u32 dw1 = 0, dw2 = 0; +@@ -2499,7 +2499,7 @@ static void prep_ata_v2_hw(struct hisi_hba *hisi_hba, + struct hisi_sas_cmd_hdr *hdr = slot->cmd_hdr; + struct asd_sas_port *sas_port = device->port; + struct hisi_sas_port *port = to_hisi_sas_port(sas_port); +- struct hisi_sas_tmf_task *tmf = slot->tmf; ++ struct sas_tmf_task *tmf = slot->tmf; + u8 *buf_cmd; + int has_data = 0, hdr_tag = 0; + u32 dw0, dw1 = 0, dw2 = 0; +diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +index 3f3d768548c57..2fce1c0a54635 100644 +--- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c ++++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +@@ -1223,7 +1223,7 @@ static void prep_ssp_v3_hw(struct hisi_hba *hisi_hba, + struct hisi_sas_port *port = slot->port; + struct sas_ssp_task *ssp_task = &task->ssp_task; + struct scsi_cmnd *scsi_cmnd = ssp_task->cmd; +- struct hisi_sas_tmf_task *tmf = slot->tmf; ++ struct sas_tmf_task *tmf = slot->tmf; + int has_data = 0, priority = !!tmf; + unsigned char prot_op; + u8 *buf_cmd; +diff --git a/drivers/scsi/mvsas/mv_defs.h b/drivers/scsi/mvsas/mv_defs.h +index 199ab49aa047f..7123a2efbf583 100644 +--- a/drivers/scsi/mvsas/mv_defs.h ++++ b/drivers/scsi/mvsas/mv_defs.h +@@ -486,9 +486,4 @@ enum datapres_field { + SENSE_DATA = 2, + }; + +-/* define task management IU */ +-struct mvs_tmf_task{ +- u8 tmf; +- u16 tag_of_task_to_be_managed; +-}; + #endif +diff --git a/drivers/scsi/mvsas/mv_sas.c b/drivers/scsi/mvsas/mv_sas.c +index 107f1993932bf..04d3710c683fe 100644 +--- a/drivers/scsi/mvsas/mv_sas.c ++++ b/drivers/scsi/mvsas/mv_sas.c +@@ -551,7 +551,7 @@ static int mvs_task_prep_ata(struct mvs_info *mvi, + + static int mvs_task_prep_ssp(struct mvs_info *mvi, + struct mvs_task_exec_info *tei, int is_tmf, +- struct mvs_tmf_task *tmf) ++ struct sas_tmf_task *tmf) + { + struct sas_task *task = tei->task; + struct mvs_cmd_hdr *hdr = tei->hdr; +@@ -691,7 +691,7 @@ static int mvs_task_prep_ssp(struct mvs_info *mvi, + + #define DEV_IS_GONE(mvi_dev) ((!mvi_dev || (mvi_dev->dev_type == SAS_PHY_UNUSED))) + static int mvs_task_prep(struct sas_task *task, struct mvs_info *mvi, int is_tmf, +- struct mvs_tmf_task *tmf, int *pass) ++ struct sas_tmf_task *tmf, int *pass) + { + struct domain_device *dev = task->dev; + struct mvs_device *mvi_dev = dev->lldd_dev; +@@ -837,7 +837,7 @@ static int mvs_task_prep(struct sas_task *task, struct mvs_info *mvi, int is_tmf + + static int mvs_task_exec(struct sas_task *task, gfp_t gfp_flags, + struct completion *completion, int is_tmf, +- struct mvs_tmf_task *tmf) ++ struct sas_tmf_task *tmf) + { + struct mvs_info *mvi = NULL; + u32 rc = 0; +@@ -1275,7 +1275,7 @@ static void mvs_tmf_timedout(struct timer_list *t) + + #define MVS_TASK_TIMEOUT 20 + static int mvs_exec_internal_tmf_task(struct domain_device *dev, +- void *parameter, u32 para_len, struct mvs_tmf_task *tmf) ++ void *parameter, u32 para_len, struct sas_tmf_task *tmf) + { + int res, retry; + struct sas_task *task = NULL; +@@ -1350,7 +1350,7 @@ static int mvs_exec_internal_tmf_task(struct domain_device *dev, + } + + static int mvs_debug_issue_ssp_tmf(struct domain_device *dev, +- u8 *lun, struct mvs_tmf_task *tmf) ++ u8 *lun, struct sas_tmf_task *tmf) + { + struct sas_ssp_task ssp_task; + if (!(dev->tproto & SAS_PROTOCOL_SSP)) +@@ -1382,7 +1382,7 @@ int mvs_lu_reset(struct domain_device *dev, u8 *lun) + { + unsigned long flags; + int rc = TMF_RESP_FUNC_FAILED; +- struct mvs_tmf_task tmf_task; ++ struct sas_tmf_task tmf_task; + struct mvs_device * mvi_dev = dev->lldd_dev; + struct mvs_info *mvi = mvi_dev->mvi_info; + +@@ -1426,7 +1426,7 @@ int mvs_query_task(struct sas_task *task) + { + u32 tag; + struct scsi_lun lun; +- struct mvs_tmf_task tmf_task; ++ struct sas_tmf_task tmf_task; + int rc = TMF_RESP_FUNC_FAILED; + + if (task->lldd_task && task->task_proto & SAS_PROTOCOL_SSP) { +@@ -1463,7 +1463,7 @@ int mvs_query_task(struct sas_task *task) + int mvs_abort_task(struct sas_task *task) + { + struct scsi_lun lun; +- struct mvs_tmf_task tmf_task; ++ struct sas_tmf_task tmf_task; + struct domain_device *dev = task->dev; + struct mvs_device *mvi_dev = (struct mvs_device *)dev->lldd_dev; + struct mvs_info *mvi; +@@ -1540,7 +1540,7 @@ int mvs_abort_task(struct sas_task *task) + int mvs_abort_task_set(struct domain_device *dev, u8 *lun) + { + int rc; +- struct mvs_tmf_task tmf_task; ++ struct sas_tmf_task tmf_task; + + tmf_task.tmf = TMF_ABORT_TASK_SET; + rc = mvs_debug_issue_ssp_tmf(dev, lun, &tmf_task); +@@ -1551,7 +1551,7 @@ int mvs_abort_task_set(struct domain_device *dev, u8 *lun) + int mvs_clear_task_set(struct domain_device *dev, u8 *lun) + { + int rc = TMF_RESP_FUNC_FAILED; +- struct mvs_tmf_task tmf_task; ++ struct sas_tmf_task tmf_task; + + tmf_task.tmf = TMF_CLEAR_TASK_SET; + rc = mvs_debug_issue_ssp_tmf(dev, lun, &tmf_task); +diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c +index 352705e023c83..537b762a2b834 100644 +--- a/drivers/scsi/pm8001/pm8001_hwi.c ++++ b/drivers/scsi/pm8001/pm8001_hwi.c +@@ -4624,7 +4624,7 @@ int pm8001_chip_abort_task(struct pm8001_hba_info *pm8001_ha, + * @tmf: task management function. + */ + int pm8001_chip_ssp_tm_req(struct pm8001_hba_info *pm8001_ha, +- struct pm8001_ccb_info *ccb, struct pm8001_tmf_task *tmf) ++ struct pm8001_ccb_info *ccb, struct sas_tmf_task *tmf) + { + struct sas_task *task = ccb->task; + struct domain_device *dev = task->dev; +@@ -4636,7 +4636,7 @@ int pm8001_chip_ssp_tm_req(struct pm8001_hba_info *pm8001_ha, + + memset(&sspTMCmd, 0, sizeof(sspTMCmd)); + sspTMCmd.device_id = cpu_to_le32(pm8001_dev->device_id); +- sspTMCmd.relate_tag = cpu_to_le32(tmf->tag_of_task_to_be_managed); ++ sspTMCmd.relate_tag = cpu_to_le32((u32)tmf->tag_of_task_to_be_managed); + sspTMCmd.tmf = cpu_to_le32(tmf->tmf); + memcpy(sspTMCmd.lun, task->ssp_task.LUN, 8); + sspTMCmd.tag = cpu_to_le32(ccb->ccb_tag); +diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c +index 93fe1bec25e21..2c003c17fe6aa 100644 +--- a/drivers/scsi/pm8001/pm8001_sas.c ++++ b/drivers/scsi/pm8001/pm8001_sas.c +@@ -335,7 +335,7 @@ static int pm8001_task_prep_ata(struct pm8001_hba_info *pm8001_ha, + * @tmf: the task management IU + */ + static int pm8001_task_prep_ssp_tm(struct pm8001_hba_info *pm8001_ha, +- struct pm8001_ccb_info *ccb, struct pm8001_tmf_task *tmf) ++ struct pm8001_ccb_info *ccb, struct sas_tmf_task *tmf) + { + return PM8001_CHIP_DISP->ssp_tm_req(pm8001_ha, ccb, tmf); + } +@@ -378,7 +378,7 @@ static int sas_find_local_port_id(struct domain_device *dev) + * @tmf: the task management IU + */ + static int pm8001_task_exec(struct sas_task *task, +- gfp_t gfp_flags, int is_tmf, struct pm8001_tmf_task *tmf) ++ gfp_t gfp_flags, int is_tmf, struct sas_tmf_task *tmf) + { + struct domain_device *dev = task->dev; + struct pm8001_hba_info *pm8001_ha; +@@ -715,7 +715,7 @@ static void pm8001_tmf_timedout(struct timer_list *t) + * this function, note it is also with the task execute interface. + */ + static int pm8001_exec_internal_tmf_task(struct domain_device *dev, +- void *parameter, u32 para_len, struct pm8001_tmf_task *tmf) ++ void *parameter, u32 para_len, struct sas_tmf_task *tmf) + { + int res, retry; + struct sas_task *task = NULL; +@@ -906,7 +906,7 @@ void pm8001_dev_gone(struct domain_device *dev) + } + + static int pm8001_issue_ssp_tmf(struct domain_device *dev, +- u8 *lun, struct pm8001_tmf_task *tmf) ++ u8 *lun, struct sas_tmf_task *tmf) + { + struct sas_ssp_task ssp_task; + if (!(dev->tproto & SAS_PROTOCOL_SSP)) +@@ -1108,7 +1108,7 @@ int pm8001_I_T_nexus_event_handler(struct domain_device *dev) + int pm8001_lu_reset(struct domain_device *dev, u8 *lun) + { + int rc = TMF_RESP_FUNC_FAILED; +- struct pm8001_tmf_task tmf_task; ++ struct sas_tmf_task tmf_task; + struct pm8001_device *pm8001_dev = dev->lldd_dev; + struct pm8001_hba_info *pm8001_ha = pm8001_find_ha_by_dev(dev); + DECLARE_COMPLETION_ONSTACK(completion_setstate); +@@ -1137,7 +1137,7 @@ int pm8001_query_task(struct sas_task *task) + { + u32 tag = 0xdeadbeef; + struct scsi_lun lun; +- struct pm8001_tmf_task tmf_task; ++ struct sas_tmf_task tmf_task; + int rc = TMF_RESP_FUNC_FAILED; + if (unlikely(!task || !task->lldd_task || !task->dev)) + return rc; +@@ -1186,7 +1186,7 @@ int pm8001_abort_task(struct sas_task *task) + struct pm8001_hba_info *pm8001_ha; + struct scsi_lun lun; + struct pm8001_device *pm8001_dev; +- struct pm8001_tmf_task tmf_task; ++ struct sas_tmf_task tmf_task; + int rc = TMF_RESP_FUNC_FAILED, ret; + u32 phy_id; + struct sas_task_slow slow_task; +@@ -1335,7 +1335,7 @@ int pm8001_abort_task(struct sas_task *task) + + int pm8001_abort_task_set(struct domain_device *dev, u8 *lun) + { +- struct pm8001_tmf_task tmf_task; ++ struct sas_tmf_task tmf_task; + + tmf_task.tmf = TMF_ABORT_TASK_SET; + return pm8001_issue_ssp_tmf(dev, lun, &tmf_task); +@@ -1343,7 +1343,7 @@ int pm8001_abort_task_set(struct domain_device *dev, u8 *lun) + + int pm8001_clear_task_set(struct domain_device *dev, u8 *lun) + { +- struct pm8001_tmf_task tmf_task; ++ struct sas_tmf_task tmf_task; + struct pm8001_device *pm8001_dev = dev->lldd_dev; + struct pm8001_hba_info *pm8001_ha = pm8001_find_ha_by_dev(dev); + +diff --git a/drivers/scsi/pm8001/pm8001_sas.h b/drivers/scsi/pm8001/pm8001_sas.h +index 52c62a29df18a..75864b47921aa 100644 +--- a/drivers/scsi/pm8001/pm8001_sas.h ++++ b/drivers/scsi/pm8001/pm8001_sas.h +@@ -99,11 +99,7 @@ extern const struct pm8001_dispatch pm8001_80xx_dispatch; + struct pm8001_hba_info; + struct pm8001_ccb_info; + struct pm8001_device; +-/* define task management IU */ +-struct pm8001_tmf_task { +- u8 tmf; +- u32 tag_of_task_to_be_managed; +-}; ++ + struct pm8001_ioctl_payload { + u32 signature; + u16 major_function; +@@ -203,7 +199,7 @@ struct pm8001_dispatch { + struct pm8001_device *pm8001_dev, u8 flag, u32 task_tag, + u32 cmd_tag); + int (*ssp_tm_req)(struct pm8001_hba_info *pm8001_ha, +- struct pm8001_ccb_info *ccb, struct pm8001_tmf_task *tmf); ++ struct pm8001_ccb_info *ccb, struct sas_tmf_task *tmf); + int (*get_nvmd_req)(struct pm8001_hba_info *pm8001_ha, void *payload); + int (*set_nvmd_req)(struct pm8001_hba_info *pm8001_ha, void *payload); + int (*fw_flash_update_req)(struct pm8001_hba_info *pm8001_ha, +@@ -682,7 +678,7 @@ int pm8001_chip_set_nvmd_req(struct pm8001_hba_info *pm8001_ha, void *payload); + int pm8001_chip_get_nvmd_req(struct pm8001_hba_info *pm8001_ha, void *payload); + int pm8001_chip_ssp_tm_req(struct pm8001_hba_info *pm8001_ha, + struct pm8001_ccb_info *ccb, +- struct pm8001_tmf_task *tmf); ++ struct sas_tmf_task *tmf); + int pm8001_chip_abort_task(struct pm8001_hba_info *pm8001_ha, + struct pm8001_device *pm8001_dev, + u8 flag, u32 task_tag, u32 cmd_tag); +diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h +index 22c54f21206d4..306005b3b60f3 100644 +--- a/include/scsi/libsas.h ++++ b/include/scsi/libsas.h +@@ -576,6 +576,15 @@ struct sas_ssp_task { + struct scsi_cmnd *cmd; + }; + ++struct sas_tmf_task { ++ u8 tmf; ++ u16 tag_of_task_to_be_managed; ++ ++ /* Temp */ ++ int force_phy; ++ int phy_id; ++}; ++ + struct sas_task { + struct domain_device *dev; + +-- +2.39.5 + diff --git a/queue-5.15/scsi-libsas-delete-lldd_clear_aca-callback.patch b/queue-5.15/scsi-libsas-delete-lldd_clear_aca-callback.patch new file mode 100644 index 0000000000..9e93591758 --- /dev/null +++ b/queue-5.15/scsi-libsas-delete-lldd_clear_aca-callback.patch @@ -0,0 +1,293 @@ +From 204172d6ebb2b49914d4cd8c47df57a493bed1e6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 17 Feb 2022 23:42:31 +0800 +Subject: scsi: libsas: Delete lldd_clear_aca callback + +From: John Garry + +[ Upstream commit 25882c82f850e3e972a973e0af310b3e58de38fd ] + +This callback is never called, so remove support. + +Link: https://lore.kernel.org/r/1645112566-115804-4-git-send-email-john.garry@huawei.com +Tested-by: Yihang Li +Tested-by: Damien Le Moal +Reviewed-by: Jack Wang +Reviewed-by: Christoph Hellwig +Reviewed-by: Xiang Chen +Signed-off-by: John Garry +Signed-off-by: Martin K. Petersen +Stable-dep-of: 8aa580cd9284 ("scsi: hisi_sas: Enable force phy when SATA disk directly connected") +Signed-off-by: Sasha Levin +--- + Documentation/scsi/libsas.rst | 2 -- + drivers/scsi/aic94xx/aic94xx.h | 1 - + drivers/scsi/aic94xx/aic94xx_init.c | 1 - + drivers/scsi/aic94xx/aic94xx_tmf.c | 9 --------- + drivers/scsi/hisi_sas/hisi_sas_main.c | 12 ------------ + drivers/scsi/isci/init.c | 1 - + drivers/scsi/isci/task.c | 18 ------------------ + drivers/scsi/isci/task.h | 4 ---- + drivers/scsi/mvsas/mv_init.c | 1 - + drivers/scsi/mvsas/mv_sas.c | 11 ----------- + drivers/scsi/mvsas/mv_sas.h | 1 - + drivers/scsi/pm8001/pm8001_init.c | 1 - + drivers/scsi/pm8001/pm8001_sas.c | 8 -------- + drivers/scsi/pm8001/pm8001_sas.h | 1 - + include/scsi/libsas.h | 1 - + 15 files changed, 72 deletions(-) + +diff --git a/Documentation/scsi/libsas.rst b/Documentation/scsi/libsas.rst +index 6589dfefbc02a..305a253d5c3b0 100644 +--- a/Documentation/scsi/libsas.rst ++++ b/Documentation/scsi/libsas.rst +@@ -207,7 +207,6 @@ Management Functions (TMFs) described in SAM:: + /* Task Management Functions. Must be called from process context. */ + int (*lldd_abort_task)(struct sas_task *); + int (*lldd_abort_task_set)(struct domain_device *, u8 *lun); +- int (*lldd_clear_aca)(struct domain_device *, u8 *lun); + int (*lldd_clear_task_set)(struct domain_device *, u8 *lun); + int (*lldd_I_T_nexus_reset)(struct domain_device *); + int (*lldd_lu_reset)(struct domain_device *, u8 *lun); +@@ -262,7 +261,6 @@ can look like this (called last thing from probe()) + + my_ha->sas_ha.lldd_abort_task = my_abort_task; + my_ha->sas_ha.lldd_abort_task_set = my_abort_task_set; +- my_ha->sas_ha.lldd_clear_aca = my_clear_aca; + my_ha->sas_ha.lldd_clear_task_set = my_clear_task_set; + my_ha->sas_ha.lldd_I_T_nexus_reset= NULL; (2) + my_ha->sas_ha.lldd_lu_reset = my_lu_reset; +diff --git a/drivers/scsi/aic94xx/aic94xx.h b/drivers/scsi/aic94xx/aic94xx.h +index 8f24180646c27..f595bc2ee45e7 100644 +--- a/drivers/scsi/aic94xx/aic94xx.h ++++ b/drivers/scsi/aic94xx/aic94xx.h +@@ -60,7 +60,6 @@ void asd_set_dmamode(struct domain_device *dev); + /* ---------- TMFs ---------- */ + int asd_abort_task(struct sas_task *); + int asd_abort_task_set(struct domain_device *, u8 *lun); +-int asd_clear_aca(struct domain_device *, u8 *lun); + int asd_clear_task_set(struct domain_device *, u8 *lun); + int asd_lu_reset(struct domain_device *, u8 *lun); + int asd_I_T_nexus_reset(struct domain_device *dev); +diff --git a/drivers/scsi/aic94xx/aic94xx_init.c b/drivers/scsi/aic94xx/aic94xx_init.c +index 7a78606598c4b..954d0c5ae2e28 100644 +--- a/drivers/scsi/aic94xx/aic94xx_init.c ++++ b/drivers/scsi/aic94xx/aic94xx_init.c +@@ -960,7 +960,6 @@ static struct sas_domain_function_template aic94xx_transport_functions = { + + .lldd_abort_task = asd_abort_task, + .lldd_abort_task_set = asd_abort_task_set, +- .lldd_clear_aca = asd_clear_aca, + .lldd_clear_task_set = asd_clear_task_set, + .lldd_I_T_nexus_reset = asd_I_T_nexus_reset, + .lldd_lu_reset = asd_lu_reset, +diff --git a/drivers/scsi/aic94xx/aic94xx_tmf.c b/drivers/scsi/aic94xx/aic94xx_tmf.c +index 0eb6e206a2b48..0ff0d6506ccf2 100644 +--- a/drivers/scsi/aic94xx/aic94xx_tmf.c ++++ b/drivers/scsi/aic94xx/aic94xx_tmf.c +@@ -644,15 +644,6 @@ int asd_abort_task_set(struct domain_device *dev, u8 *lun) + return res; + } + +-int asd_clear_aca(struct domain_device *dev, u8 *lun) +-{ +- int res = asd_initiate_ssp_tmf(dev, lun, TMF_CLEAR_ACA, 0); +- +- if (res == TMF_RESP_FUNC_COMPLETE) +- asd_clear_nexus_I_T_L(dev, lun); +- return res; +-} +- + int asd_clear_task_set(struct domain_device *dev, u8 *lun) + { + int res = asd_initiate_ssp_tmf(dev, lun, TMF_CLEAR_TASK_SET, 0); +diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c +index 9663492e566d1..bb95153bd22f0 100644 +--- a/drivers/scsi/hisi_sas/hisi_sas_main.c ++++ b/drivers/scsi/hisi_sas/hisi_sas_main.c +@@ -1753,17 +1753,6 @@ static int hisi_sas_abort_task_set(struct domain_device *device, u8 *lun) + return rc; + } + +-static int hisi_sas_clear_aca(struct domain_device *device, u8 *lun) +-{ +- struct hisi_sas_tmf_task tmf_task; +- int rc; +- +- tmf_task.tmf = TMF_CLEAR_ACA; +- rc = hisi_sas_debug_issue_ssp_tmf(device, lun, &tmf_task); +- +- return rc; +-} +- + #define I_T_NEXUS_RESET_PHYUP_TIMEOUT (2 * HZ) + + static int hisi_sas_debug_I_T_nexus_reset(struct domain_device *device) +@@ -2275,7 +2264,6 @@ static struct sas_domain_function_template hisi_sas_transport_ops = { + .lldd_control_phy = hisi_sas_control_phy, + .lldd_abort_task = hisi_sas_abort_task, + .lldd_abort_task_set = hisi_sas_abort_task_set, +- .lldd_clear_aca = hisi_sas_clear_aca, + .lldd_I_T_nexus_reset = hisi_sas_I_T_nexus_reset, + .lldd_lu_reset = hisi_sas_lu_reset, + .lldd_query_task = hisi_sas_query_task, +diff --git a/drivers/scsi/isci/init.c b/drivers/scsi/isci/init.c +index ffd33e5decae8..bd73f6925a9dc 100644 +--- a/drivers/scsi/isci/init.c ++++ b/drivers/scsi/isci/init.c +@@ -191,7 +191,6 @@ static struct sas_domain_function_template isci_transport_ops = { + /* Task Management Functions. Must be called from process context. */ + .lldd_abort_task = isci_task_abort_task, + .lldd_abort_task_set = isci_task_abort_task_set, +- .lldd_clear_aca = isci_task_clear_aca, + .lldd_clear_task_set = isci_task_clear_task_set, + .lldd_I_T_nexus_reset = isci_task_I_T_nexus_reset, + .lldd_lu_reset = isci_task_lu_reset, +diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c +index 3fd88d72a0c01..403bfee34d84d 100644 +--- a/drivers/scsi/isci/task.c ++++ b/drivers/scsi/isci/task.c +@@ -625,24 +625,6 @@ int isci_task_abort_task_set( + } + + +-/** +- * isci_task_clear_aca() - This function is one of the SAS Domain Template +- * functions. This is one of the Task Management functoins called by libsas. +- * @d_device: This parameter specifies the domain device associated with this +- * request. +- * @lun: This parameter specifies the lun associated with this request. +- * +- * status, zero indicates success. +- */ +-int isci_task_clear_aca( +- struct domain_device *d_device, +- u8 *lun) +-{ +- return TMF_RESP_FUNC_FAILED; +-} +- +- +- + /** + * isci_task_clear_task_set() - This function is one of the SAS Domain Template + * functions. This is one of the Task Management functoins called by libsas. +diff --git a/drivers/scsi/isci/task.h b/drivers/scsi/isci/task.h +index 8f4531f22ac29..5939cb175a20f 100644 +--- a/drivers/scsi/isci/task.h ++++ b/drivers/scsi/isci/task.h +@@ -140,10 +140,6 @@ int isci_task_abort_task_set( + struct domain_device *d_device, + u8 *lun); + +-int isci_task_clear_aca( +- struct domain_device *d_device, +- u8 *lun); +- + int isci_task_clear_task_set( + struct domain_device *d_device, + u8 *lun); +diff --git a/drivers/scsi/mvsas/mv_init.c b/drivers/scsi/mvsas/mv_init.c +index f6f8ca3c8c7f5..1c98662db080f 100644 +--- a/drivers/scsi/mvsas/mv_init.c ++++ b/drivers/scsi/mvsas/mv_init.c +@@ -64,7 +64,6 @@ static struct sas_domain_function_template mvs_transport_ops = { + + .lldd_abort_task = mvs_abort_task, + .lldd_abort_task_set = mvs_abort_task_set, +- .lldd_clear_aca = mvs_clear_aca, + .lldd_clear_task_set = mvs_clear_task_set, + .lldd_I_T_nexus_reset = mvs_I_T_nexus_reset, + .lldd_lu_reset = mvs_lu_reset, +diff --git a/drivers/scsi/mvsas/mv_sas.c b/drivers/scsi/mvsas/mv_sas.c +index 31d1ea5a5dd2b..107f1993932bf 100644 +--- a/drivers/scsi/mvsas/mv_sas.c ++++ b/drivers/scsi/mvsas/mv_sas.c +@@ -1548,17 +1548,6 @@ int mvs_abort_task_set(struct domain_device *dev, u8 *lun) + return rc; + } + +-int mvs_clear_aca(struct domain_device *dev, u8 *lun) +-{ +- int rc = TMF_RESP_FUNC_FAILED; +- struct mvs_tmf_task tmf_task; +- +- tmf_task.tmf = TMF_CLEAR_ACA; +- rc = mvs_debug_issue_ssp_tmf(dev, lun, &tmf_task); +- +- return rc; +-} +- + int mvs_clear_task_set(struct domain_device *dev, u8 *lun) + { + int rc = TMF_RESP_FUNC_FAILED; +diff --git a/drivers/scsi/mvsas/mv_sas.h b/drivers/scsi/mvsas/mv_sas.h +index 8ff976c9967e1..fa654c73beeee 100644 +--- a/drivers/scsi/mvsas/mv_sas.h ++++ b/drivers/scsi/mvsas/mv_sas.h +@@ -441,7 +441,6 @@ int mvs_scan_finished(struct Scsi_Host *shost, unsigned long time); + int mvs_queue_command(struct sas_task *task, gfp_t gfp_flags); + int mvs_abort_task(struct sas_task *task); + int mvs_abort_task_set(struct domain_device *dev, u8 *lun); +-int mvs_clear_aca(struct domain_device *dev, u8 *lun); + int mvs_clear_task_set(struct domain_device *dev, u8 * lun); + void mvs_port_formed(struct asd_sas_phy *sas_phy); + void mvs_port_deformed(struct asd_sas_phy *sas_phy); +diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c +index a54460fe86300..0659ee9aafce7 100644 +--- a/drivers/scsi/pm8001/pm8001_init.c ++++ b/drivers/scsi/pm8001/pm8001_init.c +@@ -123,7 +123,6 @@ static struct sas_domain_function_template pm8001_transport_ops = { + + .lldd_abort_task = pm8001_abort_task, + .lldd_abort_task_set = pm8001_abort_task_set, +- .lldd_clear_aca = pm8001_clear_aca, + .lldd_clear_task_set = pm8001_clear_task_set, + .lldd_I_T_nexus_reset = pm8001_I_T_nexus_reset, + .lldd_lu_reset = pm8001_lu_reset, +diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c +index 5fb08acbc0e5e..93fe1bec25e21 100644 +--- a/drivers/scsi/pm8001/pm8001_sas.c ++++ b/drivers/scsi/pm8001/pm8001_sas.c +@@ -1341,14 +1341,6 @@ int pm8001_abort_task_set(struct domain_device *dev, u8 *lun) + return pm8001_issue_ssp_tmf(dev, lun, &tmf_task); + } + +-int pm8001_clear_aca(struct domain_device *dev, u8 *lun) +-{ +- struct pm8001_tmf_task tmf_task; +- +- tmf_task.tmf = TMF_CLEAR_ACA; +- return pm8001_issue_ssp_tmf(dev, lun, &tmf_task); +-} +- + int pm8001_clear_task_set(struct domain_device *dev, u8 *lun) + { + struct pm8001_tmf_task tmf_task; +diff --git a/drivers/scsi/pm8001/pm8001_sas.h b/drivers/scsi/pm8001/pm8001_sas.h +index f40a41f450d9b..52c62a29df18a 100644 +--- a/drivers/scsi/pm8001/pm8001_sas.h ++++ b/drivers/scsi/pm8001/pm8001_sas.h +@@ -645,7 +645,6 @@ int pm8001_scan_finished(struct Scsi_Host *shost, unsigned long time); + int pm8001_queue_command(struct sas_task *task, gfp_t gfp_flags); + int pm8001_abort_task(struct sas_task *task); + int pm8001_abort_task_set(struct domain_device *dev, u8 *lun); +-int pm8001_clear_aca(struct domain_device *dev, u8 *lun); + int pm8001_clear_task_set(struct domain_device *dev, u8 *lun); + int pm8001_dev_found(struct domain_device *dev); + void pm8001_dev_gone(struct domain_device *dev); +diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h +index 6fe125a71b608..22c54f21206d4 100644 +--- a/include/scsi/libsas.h ++++ b/include/scsi/libsas.h +@@ -636,7 +636,6 @@ struct sas_domain_function_template { + /* Task Management Functions. Must be called from process context. */ + int (*lldd_abort_task)(struct sas_task *); + int (*lldd_abort_task_set)(struct domain_device *, u8 *lun); +- int (*lldd_clear_aca)(struct domain_device *, u8 *lun); + int (*lldd_clear_task_set)(struct domain_device *, u8 *lun); + int (*lldd_I_T_nexus_reset)(struct domain_device *); + int (*lldd_ata_check_ready)(struct domain_device *); +-- +2.39.5 + diff --git a/queue-5.15/series b/queue-5.15/series index 621c39f65f..01f7b6bc72 100644 --- a/queue-5.15/series +++ b/queue-5.15/series @@ -117,3 +117,37 @@ arm64-errata-add-newer-arm-cores-to-the-spectre_bhb_loop_affected-lists.patch acpi-platform-profile-fix-cfi-violation-when-accessing-sysfs-files.patch x86-e820-fix-handling-of-subpage-regions-when-calculating-nosave-ranges-in-e820__register_nosave_regions.patch bluetooth-hci_uart-fix-another-race-during-initialization.patch +scsi-hisi_sas-start-delivery-hisi_sas_task_exec-dire.patch +scsi-hisi_sas-pass-abort-structure-for-internal-abor.patch +scsi-hisi_sas-factor-out-task-prep-and-delivery-code.patch +scsi-hisi_sas-fix-setting-of-hisi_sas_slot.is_intern.patch +scsi-libsas-delete-lldd_clear_aca-callback.patch +scsi-libsas-add-struct-sas_tmf_task.patch +scsi-hisi_sas-enable-force-phy-when-sata-disk-direct.patch +wifi-at76c50x-fix-use-after-free-access-in-at76_disc.patch +wifi-mac80211-update-skb-s-control-block-key-in-ieee.patch +wifi-mac80211-purge-vif-txq-in-ieee80211_do_stop.patch +wifi-wl1251-fix-memory-leak-in-wl1251_tx_work.patch +scsi-iscsi-fix-missing-scsi_host_put-in-error-path.patch +md-raid10-fix-missing-discard-io-accounting.patch +rdma-usnic-fix-passing-zero-to-ptr_err-in-usnic_ib_p.patch +rdma-hns-fix-wrong-maximum-dma-segment-size.patch +rdma-core-silence-oversized-kvmalloc-warning.patch +bluetooth-hci_event-fix-sending-mgmt_ev_device_found.patch +bluetooth-btrtl-prevent-potential-null-dereference.patch +bluetooth-l2cap-check-encryption-key-size-on-incomin.patch +revert-wifi-mac80211-update-skb-s-control-block-key-.patch +igc-fix-ptm-cycle-trigger-logic.patch +igc-move-ktime-snapshot-into-ptm-retry-loop.patch +igc-handle-the-igc_ptp_enabled-flag-correctly.patch +igc-cleanup-ptp-module-if-probe-fails.patch +net-mctp-set-sock_rcu_free.patch +net-openvswitch-fix-nested-key-length-validation-in-.patch +cxgb4-fix-memory-leak-in-cxgb4_init_ethtool_filters-.patch +net-b53-enable-bpdu-reception-for-management-port.patch +net-dsa-mv88e6xxx-avoid-unregistering-devlink-region.patch +net-dsa-avoid-refcount-warnings-when-ds-ops-tag_8021.patch +riscv-properly-export-reserved-regions-in-proc-iomem.patch +riscv-kgdb-do-not-inline-arch_kgdb_breakpoint.patch +riscv-kgdb-remove-.option-norvc-.option-rvc-for-kgdb.patch +cpufreq-sched-fix-the-usage-of-cpufreq_need_update_l.patch diff --git a/queue-5.15/wifi-at76c50x-fix-use-after-free-access-in-at76_disc.patch b/queue-5.15/wifi-at76c50x-fix-use-after-free-access-in-at76_disc.patch new file mode 100644 index 0000000000..e64a379c15 --- /dev/null +++ b/queue-5.15/wifi-at76c50x-fix-use-after-free-access-in-at76_disc.patch @@ -0,0 +1,39 @@ +From 243ec22eb7fb3bc8439842d2fe9f41634a633776 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 30 Mar 2025 16:01:10 +0530 +Subject: wifi: at76c50x: fix use after free access in at76_disconnect + +From: Abdun Nihaal + +[ Upstream commit 27c7e63b3cb1a20bb78ed4a36c561ea4579fd7da ] + +The memory pointed to by priv is freed at the end of at76_delete_device +function (using ieee80211_free_hw). But the code then accesses the udev +field of the freed object to put the USB device. This may also lead to a +memory leak of the usb device. Fix this by using udev from interface. + +Fixes: 29e20aa6c6af ("at76c50x-usb: fix use after free on failure path in at76_probe()") +Signed-off-by: Abdun Nihaal +Link: https://patch.msgid.link/20250330103110.44080-1-abdun.nihaal@gmail.com +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/atmel/at76c50x-usb.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/wireless/atmel/at76c50x-usb.c b/drivers/net/wireless/atmel/at76c50x-usb.c +index 7582761c61e2c..26953dcffe193 100644 +--- a/drivers/net/wireless/atmel/at76c50x-usb.c ++++ b/drivers/net/wireless/atmel/at76c50x-usb.c +@@ -2553,7 +2553,7 @@ static void at76_disconnect(struct usb_interface *interface) + + wiphy_info(priv->hw->wiphy, "disconnecting\n"); + at76_delete_device(priv); +- usb_put_dev(priv->udev); ++ usb_put_dev(interface_to_usbdev(interface)); + dev_info(&interface->dev, "disconnected\n"); + } + +-- +2.39.5 + diff --git a/queue-5.15/wifi-mac80211-purge-vif-txq-in-ieee80211_do_stop.patch b/queue-5.15/wifi-mac80211-purge-vif-txq-in-ieee80211_do_stop.patch new file mode 100644 index 0000000000..15ce9a29f7 --- /dev/null +++ b/queue-5.15/wifi-mac80211-purge-vif-txq-in-ieee80211_do_stop.patch @@ -0,0 +1,117 @@ +From e16ad889922f6c211d87cee07790f5aad2a1e393 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 24 Mar 2025 17:28:21 +0100 +Subject: wifi: mac80211: Purge vif txq in ieee80211_do_stop() + +From: Remi Pommarel + +[ Upstream commit 378677eb8f44621ecc9ce659f7af61e5baa94d81 ] + +After ieee80211_do_stop() SKB from vif's txq could still be processed. +Indeed another concurrent vif schedule_and_wake_txq call could cause +those packets to be dequeued (see ieee80211_handle_wake_tx_queue()) +without checking the sdata current state. + +Because vif.drv_priv is now cleared in this function, this could lead to +driver crash. + +For example in ath12k, ahvif is store in vif.drv_priv. Thus if +ath12k_mac_op_tx() is called after ieee80211_do_stop(), ahvif->ah can be +NULL, leading the ath12k_warn(ahvif->ah,...) call in this function to +trigger the NULL deref below. + + Unable to handle kernel paging request at virtual address dfffffc000000001 + KASAN: null-ptr-deref in range [0x0000000000000008-0x000000000000000f] + batman_adv: bat0: Interface deactivated: brbh1337 + Mem abort info: + ESR = 0x0000000096000004 + EC = 0x25: DABT (current EL), IL = 32 bits + SET = 0, FnV = 0 + EA = 0, S1PTW = 0 + FSC = 0x04: level 0 translation fault + Data abort info: + ISV = 0, ISS = 0x00000004, ISS2 = 0x00000000 + CM = 0, WnR = 0, TnD = 0, TagAccess = 0 + GCS = 0, Overlay = 0, DirtyBit = 0, Xs = 0 + [dfffffc000000001] address between user and kernel address ranges + Internal error: Oops: 0000000096000004 [#1] SMP + CPU: 1 UID: 0 PID: 978 Comm: lbd Not tainted 6.13.0-g633f875b8f1e #114 + Hardware name: HW (DT) + pstate: 10000005 (nzcV daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) + pc : ath12k_mac_op_tx+0x6cc/0x29b8 [ath12k] + lr : ath12k_mac_op_tx+0x174/0x29b8 [ath12k] + sp : ffffffc086ace450 + x29: ffffffc086ace450 x28: 0000000000000000 x27: 1ffffff810d59ca4 + x26: ffffff801d05f7c0 x25: 0000000000000000 x24: 000000004000001e + x23: ffffff8009ce4926 x22: ffffff801f9c0800 x21: ffffff801d05f7f0 + x20: ffffff8034a19f40 x19: 0000000000000000 x18: ffffff801f9c0958 + x17: ffffff800bc0a504 x16: dfffffc000000000 x15: ffffffc086ace4f8 + x14: ffffff801d05f83c x13: 0000000000000000 x12: ffffffb003a0bf03 + x11: 0000000000000000 x10: ffffffb003a0bf02 x9 : ffffff8034a19f40 + x8 : ffffff801d05f818 x7 : 1ffffff0069433dc x6 : ffffff8034a19ee0 + x5 : ffffff801d05f7f0 x4 : 0000000000000000 x3 : 0000000000000001 + x2 : 0000000000000000 x1 : dfffffc000000000 x0 : 0000000000000008 + Call trace: + ath12k_mac_op_tx+0x6cc/0x29b8 [ath12k] (P) + ieee80211_handle_wake_tx_queue+0x16c/0x260 + ieee80211_queue_skb+0xeec/0x1d20 + ieee80211_tx+0x200/0x2c8 + ieee80211_xmit+0x22c/0x338 + __ieee80211_subif_start_xmit+0x7e8/0xc60 + ieee80211_subif_start_xmit+0xc4/0xee0 + __ieee80211_subif_start_xmit_8023.isra.0+0x854/0x17a0 + ieee80211_subif_start_xmit_8023+0x124/0x488 + dev_hard_start_xmit+0x160/0x5a8 + __dev_queue_xmit+0x6f8/0x3120 + br_dev_queue_push_xmit+0x120/0x4a8 + __br_forward+0xe4/0x2b0 + deliver_clone+0x5c/0xd0 + br_flood+0x398/0x580 + br_dev_xmit+0x454/0x9f8 + dev_hard_start_xmit+0x160/0x5a8 + __dev_queue_xmit+0x6f8/0x3120 + ip6_finish_output2+0xc28/0x1b60 + __ip6_finish_output+0x38c/0x638 + ip6_output+0x1b4/0x338 + ip6_local_out+0x7c/0xa8 + ip6_send_skb+0x7c/0x1b0 + ip6_push_pending_frames+0x94/0xd0 + rawv6_sendmsg+0x1a98/0x2898 + inet_sendmsg+0x94/0xe0 + __sys_sendto+0x1e4/0x308 + __arm64_sys_sendto+0xc4/0x140 + do_el0_svc+0x110/0x280 + el0_svc+0x20/0x60 + el0t_64_sync_handler+0x104/0x138 + el0t_64_sync+0x154/0x158 + +To avoid that, empty vif's txq at ieee80211_do_stop() so no packet could +be dequeued after ieee80211_do_stop() (new packets cannot be queued +because SDATA_STATE_RUNNING is cleared at this point). + +Fixes: ba8c3d6f16a1 ("mac80211: add an intermediate software queue implementation") +Signed-off-by: Remi Pommarel +Link: https://patch.msgid.link/ff7849e268562456274213c0476e09481a48f489.1742833382.git.repk@triplefau.lt +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + net/mac80211/iface.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c +index e362a08af2873..e437bcadf4a27 100644 +--- a/net/mac80211/iface.c ++++ b/net/mac80211/iface.c +@@ -585,6 +585,9 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_do + if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) + ieee80211_txq_remove_vlan(local, sdata); + ++ if (sdata->vif.txq) ++ ieee80211_txq_purge(sdata->local, to_txq_info(sdata->vif.txq)); ++ + sdata->bss = NULL; + + if (local->open_count == 0) +-- +2.39.5 + diff --git a/queue-5.15/wifi-mac80211-update-skb-s-control-block-key-in-ieee.patch b/queue-5.15/wifi-mac80211-update-skb-s-control-block-key-in-ieee.patch new file mode 100644 index 0000000000..ee3fb4b5b9 --- /dev/null +++ b/queue-5.15/wifi-mac80211-update-skb-s-control-block-key-in-ieee.patch @@ -0,0 +1,100 @@ +From 37f570d4c9b8bfb684dea58b06d5f4871cababa7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 24 Mar 2025 17:28:20 +0100 +Subject: wifi: mac80211: Update skb's control block key in + ieee80211_tx_dequeue() + +From: Remi Pommarel + +[ Upstream commit a104042e2bf6528199adb6ca901efe7b60c2c27f ] + +The ieee80211 skb control block key (set when skb was queued) could have +been removed before ieee80211_tx_dequeue() call. ieee80211_tx_dequeue() +already called ieee80211_tx_h_select_key() to get the current key, but +the latter do not update the key in skb control block in case it is +NULL. Because some drivers actually use this key in their TX callbacks +(e.g. ath1{1,2}k_mac_op_tx()) this could lead to the use after free +below: + + BUG: KASAN: slab-use-after-free in ath11k_mac_op_tx+0x590/0x61c + Read of size 4 at addr ffffff803083c248 by task kworker/u16:4/1440 + + CPU: 3 UID: 0 PID: 1440 Comm: kworker/u16:4 Not tainted 6.13.0-ge128f627f404 #2 + Hardware name: HW (DT) + Workqueue: bat_events batadv_send_outstanding_bcast_packet + Call trace: + show_stack+0x14/0x1c (C) + dump_stack_lvl+0x58/0x74 + print_report+0x164/0x4c0 + kasan_report+0xac/0xe8 + __asan_report_load4_noabort+0x1c/0x24 + ath11k_mac_op_tx+0x590/0x61c + ieee80211_handle_wake_tx_queue+0x12c/0x1c8 + ieee80211_queue_skb+0xdcc/0x1b4c + ieee80211_tx+0x1ec/0x2bc + ieee80211_xmit+0x224/0x324 + __ieee80211_subif_start_xmit+0x85c/0xcf8 + ieee80211_subif_start_xmit+0xc0/0xec4 + dev_hard_start_xmit+0xf4/0x28c + __dev_queue_xmit+0x6ac/0x318c + batadv_send_skb_packet+0x38c/0x4b0 + batadv_send_outstanding_bcast_packet+0x110/0x328 + process_one_work+0x578/0xc10 + worker_thread+0x4bc/0xc7c + kthread+0x2f8/0x380 + ret_from_fork+0x10/0x20 + + Allocated by task 1906: + kasan_save_stack+0x28/0x4c + kasan_save_track+0x1c/0x40 + kasan_save_alloc_info+0x3c/0x4c + __kasan_kmalloc+0xac/0xb0 + __kmalloc_noprof+0x1b4/0x380 + ieee80211_key_alloc+0x3c/0xb64 + ieee80211_add_key+0x1b4/0x71c + nl80211_new_key+0x2b4/0x5d8 + genl_family_rcv_msg_doit+0x198/0x240 + <...> + + Freed by task 1494: + kasan_save_stack+0x28/0x4c + kasan_save_track+0x1c/0x40 + kasan_save_free_info+0x48/0x94 + __kasan_slab_free+0x48/0x60 + kfree+0xc8/0x31c + kfree_sensitive+0x70/0x80 + ieee80211_key_free_common+0x10c/0x174 + ieee80211_free_keys+0x188/0x46c + ieee80211_stop_mesh+0x70/0x2cc + ieee80211_leave_mesh+0x1c/0x60 + cfg80211_leave_mesh+0xe0/0x280 + cfg80211_leave+0x1e0/0x244 + <...> + +Reset SKB control block key before calling ieee80211_tx_h_select_key() +to avoid that. + +Fixes: bb42f2d13ffc ("mac80211: Move reorder-sensitive TX handlers to after TXQ dequeue") +Signed-off-by: Remi Pommarel +Link: https://patch.msgid.link/06aa507b853ca385ceded81c18b0a6dd0f081bc8.1742833382.git.repk@triplefau.lt +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + net/mac80211/tx.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c +index c4e6fbe4343ee..0a658e747798b 100644 +--- a/net/mac80211/tx.c ++++ b/net/mac80211/tx.c +@@ -3704,6 +3704,7 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw, + * The key can be removed while the packet was queued, so need to call + * this here to get the current key. + */ ++ info->control.hw_key = NULL; + r = ieee80211_tx_h_select_key(&tx); + if (r != TX_CONTINUE) { + ieee80211_free_txskb(&local->hw, skb); +-- +2.39.5 + diff --git a/queue-5.15/wifi-wl1251-fix-memory-leak-in-wl1251_tx_work.patch b/queue-5.15/wifi-wl1251-fix-memory-leak-in-wl1251_tx_work.patch new file mode 100644 index 0000000000..49bc74de53 --- /dev/null +++ b/queue-5.15/wifi-wl1251-fix-memory-leak-in-wl1251_tx_work.patch @@ -0,0 +1,41 @@ +From 4c7b136ba76c7c5875fa0c1f86934e5f9772b88d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 30 Mar 2025 16:15:32 +0530 +Subject: wifi: wl1251: fix memory leak in wl1251_tx_work + +From: Abdun Nihaal + +[ Upstream commit a0f0dc96de03ffeefc2a177b7f8acde565cb77f4 ] + +The skb dequeued from tx_queue is lost when wl1251_ps_elp_wakeup fails +with a -ETIMEDOUT error. Fix that by queueing the skb back to tx_queue. + +Fixes: c5483b719363 ("wl12xx: check if elp wakeup failed") +Signed-off-by: Abdun Nihaal +Reviewed-by: Michael Nemanov +Link: https://patch.msgid.link/20250330104532.44935-1-abdun.nihaal@gmail.com +Signed-off-by: Johannes Berg +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/ti/wl1251/tx.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/wireless/ti/wl1251/tx.c b/drivers/net/wireless/ti/wl1251/tx.c +index 98cd39619d579..5771f61392efb 100644 +--- a/drivers/net/wireless/ti/wl1251/tx.c ++++ b/drivers/net/wireless/ti/wl1251/tx.c +@@ -342,8 +342,10 @@ void wl1251_tx_work(struct work_struct *work) + while ((skb = skb_dequeue(&wl->tx_queue))) { + if (!woken_up) { + ret = wl1251_ps_elp_wakeup(wl); +- if (ret < 0) ++ if (ret < 0) { ++ skb_queue_head(&wl->tx_queue, skb); + goto out; ++ } + woken_up = true; + } + +-- +2.39.5 +