From: Greg Kroah-Hartman Date: Tue, 16 May 2017 10:37:33 +0000 (+0200) Subject: 4.4-stable patches X-Git-Tag: v3.18.54~38 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=c59303d98958827fee286c7d5c34e9e1a5dad1a3;p=thirdparty%2Fkernel%2Fstable-queue.git 4.4-stable patches added patches: iscsi-target-set-session_fall_back_to_erl0-when-forcing-reinstatement.patch staging-comedi-jr3_pci-cope-with-jiffies-wraparound.patch staging-comedi-jr3_pci-fix-possible-null-pointer-dereference.patch staging-gdm724x-gdm_mux-fix-use-after-free-on-module-unload.patch staging-vt6656-use-off-stack-for-in-buffer-usb-transfers.patch staging-vt6656-use-off-stack-for-out-buffer-usb-transfers.patch target-convert-acl-change-queue_depth-se_session-reference-usage.patch target-fileio-fix-zero-length-read-and-write-handling.patch target-fix-compare_and_write_callback-handling-for-non-good-status.patch usb-host-xhci-print-correct-command-ring-address.patch usb-hub-do-not-attempt-to-autosuspend-disconnected-devices.patch usb-hub-fix-error-loop-seen-after-hub-communication-errors.patch usb-make-sure-usb-phy-of-gets-built-in.patch usb-misc-add-missing-continue-in-switch.patch usb-misc-legousbtower-fix-buffers-on-stack.patch usb-proper-handling-of-race-condition-when-two-usb-class-drivers-try-to-call-init_usb_class-simultaneously.patch usb-serial-ftdi_sio-add-device-id-for-microsemi-arrow-sf2plus-dev-kit.patch --- diff --git a/queue-4.4/iscsi-target-set-session_fall_back_to_erl0-when-forcing-reinstatement.patch b/queue-4.4/iscsi-target-set-session_fall_back_to_erl0-when-forcing-reinstatement.patch new file mode 100644 index 00000000000..a3f914853a9 --- /dev/null +++ b/queue-4.4/iscsi-target-set-session_fall_back_to_erl0-when-forcing-reinstatement.patch @@ -0,0 +1,75 @@ +From 197b806ae5db60c6f609d74da04ddb62ea5e1b00 Mon Sep 17 00:00:00 2001 +From: Nicholas Bellinger +Date: Tue, 25 Apr 2017 10:55:12 -0700 +Subject: iscsi-target: Set session_fall_back_to_erl0 when forcing reinstatement + +From: Nicholas Bellinger + +commit 197b806ae5db60c6f609d74da04ddb62ea5e1b00 upstream. + +While testing modification of per se_node_acl queue_depth forcing +session reinstatement via lio_target_nacl_cmdsn_depth_store() -> +core_tpg_set_initiator_node_queue_depth(), a hung task bug triggered +when changing cmdsn_depth invoked session reinstatement while an iscsi +login was already waiting for session reinstatement to complete. + +This can happen when an outstanding se_cmd descriptor is taking a +long time to complete, and session reinstatement from iscsi login +or cmdsn_depth change occurs concurrently. + +To address this bug, explicitly set session_fall_back_to_erl0 = 1 +when forcing session reinstatement, so session reinstatement is +not attempted if an active session is already being shutdown. + +This patch has been tested with two scenarios. The first when +iscsi login is blocked waiting for iscsi session reinstatement +to complete followed by queue_depth change via configfs, and +second when queue_depth change via configfs us blocked followed +by a iscsi login driven session reinstatement. + +Note this patch depends on commit d36ad77f702 to handle multiple +sessions per se_node_acl when changing cmdsn_depth, and for +pre v4.5 kernels will need to be included for stable as well. + +Reported-by: Gary Guo +Tested-by: Gary Guo +Cc: Gary Guo +Signed-off-by: Nicholas Bellinger +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/target/iscsi/iscsi_target.c | 1 + + drivers/target/iscsi/iscsi_target_configfs.c | 1 + + drivers/target/iscsi/iscsi_target_login.c | 1 + + 3 files changed, 3 insertions(+) + +--- a/drivers/target/iscsi/iscsi_target.c ++++ b/drivers/target/iscsi/iscsi_target.c +@@ -4821,6 +4821,7 @@ int iscsit_release_sessions_for_tpg(stru + continue; + } + atomic_set(&sess->session_reinstatement, 1); ++ atomic_set(&sess->session_fall_back_to_erl0, 1); + spin_unlock(&sess->conn_lock); + + list_move_tail(&se_sess->sess_list, &free_list); +--- a/drivers/target/iscsi/iscsi_target_configfs.c ++++ b/drivers/target/iscsi/iscsi_target_configfs.c +@@ -1608,6 +1608,7 @@ static int lio_tpg_shutdown_session(stru + return 0; + } + atomic_set(&sess->session_reinstatement, 1); ++ atomic_set(&sess->session_fall_back_to_erl0, 1); + spin_unlock(&sess->conn_lock); + + iscsit_stop_time2retain_timer(sess); +--- a/drivers/target/iscsi/iscsi_target_login.c ++++ b/drivers/target/iscsi/iscsi_target_login.c +@@ -195,6 +195,7 @@ int iscsi_check_for_session_reinstatemen + initiatorname_param->value) && + (sess_p->sess_ops->SessionType == sessiontype))) { + atomic_set(&sess_p->session_reinstatement, 1); ++ atomic_set(&sess_p->session_fall_back_to_erl0, 1); + spin_unlock(&sess_p->conn_lock); + iscsit_inc_session_usage_count(sess_p); + iscsit_stop_time2retain_timer(sess_p); diff --git a/queue-4.4/series b/queue-4.4/series index ca0ac415f0b..37b8dadea6c 100644 --- a/queue-4.4/series +++ b/queue-4.4/series @@ -1 +1,18 @@ xen-adjust-early-dom0-p2m-handling-to-xen-hypervisor-behavior.patch +target-fix-compare_and_write_callback-handling-for-non-good-status.patch +target-fileio-fix-zero-length-read-and-write-handling.patch +target-convert-acl-change-queue_depth-se_session-reference-usage.patch +iscsi-target-set-session_fall_back_to_erl0-when-forcing-reinstatement.patch +usb-host-xhci-print-correct-command-ring-address.patch +usb-serial-ftdi_sio-add-device-id-for-microsemi-arrow-sf2plus-dev-kit.patch +usb-proper-handling-of-race-condition-when-two-usb-class-drivers-try-to-call-init_usb_class-simultaneously.patch +staging-vt6656-use-off-stack-for-in-buffer-usb-transfers.patch +staging-vt6656-use-off-stack-for-out-buffer-usb-transfers.patch +staging-gdm724x-gdm_mux-fix-use-after-free-on-module-unload.patch +staging-comedi-jr3_pci-fix-possible-null-pointer-dereference.patch +staging-comedi-jr3_pci-cope-with-jiffies-wraparound.patch +usb-misc-add-missing-continue-in-switch.patch +usb-make-sure-usb-phy-of-gets-built-in.patch +usb-hub-fix-error-loop-seen-after-hub-communication-errors.patch +usb-hub-do-not-attempt-to-autosuspend-disconnected-devices.patch +usb-misc-legousbtower-fix-buffers-on-stack.patch diff --git a/queue-4.4/staging-comedi-jr3_pci-cope-with-jiffies-wraparound.patch b/queue-4.4/staging-comedi-jr3_pci-cope-with-jiffies-wraparound.patch new file mode 100644 index 00000000000..e2a24fbf386 --- /dev/null +++ b/queue-4.4/staging-comedi-jr3_pci-cope-with-jiffies-wraparound.patch @@ -0,0 +1,34 @@ +From 8ec04a491825e08068e92bed0bba7821893b6433 Mon Sep 17 00:00:00 2001 +From: Ian Abbott +Date: Fri, 17 Feb 2017 11:09:09 +0000 +Subject: staging: comedi: jr3_pci: cope with jiffies wraparound + +From: Ian Abbott + +commit 8ec04a491825e08068e92bed0bba7821893b6433 upstream. + +The timer expiry routine `jr3_pci_poll_dev()` checks for expiry by +checking whether the absolute value of `jiffies` (stored in local +variable `now`) is greater than the expected expiry time in jiffy units. +This will fail when `jiffies` wraps around. Also, it seems to make +sense to handle the expiry one jiffy earlier than the current test. Use +`time_after_eq()` to check for expiry. + +Signed-off-by: Ian Abbott +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/staging/comedi/drivers/jr3_pci.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/staging/comedi/drivers/jr3_pci.c ++++ b/drivers/staging/comedi/drivers/jr3_pci.c +@@ -610,7 +610,7 @@ static void jr3_pci_poll_dev(unsigned lo + s = &dev->subdevices[i]; + spriv = s->private; + +- if (now > spriv->next_time_min) { ++ if (time_after_eq(now, spriv->next_time_min)) { + struct jr3_pci_poll_delay sub_delay; + + sub_delay = jr3_pci_poll_subdevice(s); diff --git a/queue-4.4/staging-comedi-jr3_pci-fix-possible-null-pointer-dereference.patch b/queue-4.4/staging-comedi-jr3_pci-fix-possible-null-pointer-dereference.patch new file mode 100644 index 00000000000..e687943932f --- /dev/null +++ b/queue-4.4/staging-comedi-jr3_pci-fix-possible-null-pointer-dereference.patch @@ -0,0 +1,51 @@ +From 45292be0b3db0b7f8286683b376e2d9f949d11f9 Mon Sep 17 00:00:00 2001 +From: Ian Abbott +Date: Fri, 17 Feb 2017 11:09:08 +0000 +Subject: staging: comedi: jr3_pci: fix possible null pointer dereference + +From: Ian Abbott + +commit 45292be0b3db0b7f8286683b376e2d9f949d11f9 upstream. + +For some reason, the driver does not consider allocation of the +subdevice private data to be a fatal error when attaching the COMEDI +device. It tests the subdevice private data pointer for validity at +certain points, but omits some crucial tests. In particular, +`jr3_pci_auto_attach()` calls `jr3_pci_alloc_spriv()` to allocate and +initialize the subdevice private data, but the same function +subsequently dereferences the pointer to access the `next_time_min` and +`next_time_max` members without checking it first. The other missing +test is in the timer expiry routine `jr3_pci_poll_dev()`, but it will +crash before it gets that far. + +Fix the bug by returning `-ENOMEM` from `jr3_pci_auto_attach()` as soon +as one of the calls to `jr3_pci_alloc_spriv()` returns `NULL`. The +COMEDI core will subsequently call `jr3_pci_detach()` to clean up. + +Signed-off-by: Ian Abbott +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/staging/comedi/drivers/jr3_pci.c | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +--- a/drivers/staging/comedi/drivers/jr3_pci.c ++++ b/drivers/staging/comedi/drivers/jr3_pci.c +@@ -726,11 +726,12 @@ static int jr3_pci_auto_attach(struct co + s->insn_read = jr3_pci_ai_insn_read; + + spriv = jr3_pci_alloc_spriv(dev, s); +- if (spriv) { +- /* Channel specific range and maxdata */ +- s->range_table_list = spriv->range_table_list; +- s->maxdata_list = spriv->maxdata_list; +- } ++ if (!spriv) ++ return -ENOMEM; ++ ++ /* Channel specific range and maxdata */ ++ s->range_table_list = spriv->range_table_list; ++ s->maxdata_list = spriv->maxdata_list; + } + + /* Reset DSP card */ diff --git a/queue-4.4/staging-gdm724x-gdm_mux-fix-use-after-free-on-module-unload.patch b/queue-4.4/staging-gdm724x-gdm_mux-fix-use-after-free-on-module-unload.patch new file mode 100644 index 00000000000..ce985538b81 --- /dev/null +++ b/queue-4.4/staging-gdm724x-gdm_mux-fix-use-after-free-on-module-unload.patch @@ -0,0 +1,41 @@ +From b58f45c8fc301fe83ee28cad3e64686c19e78f1c Mon Sep 17 00:00:00 2001 +From: Johan Hovold +Date: Wed, 26 Apr 2017 12:23:04 +0200 +Subject: staging: gdm724x: gdm_mux: fix use-after-free on module unload + +From: Johan Hovold + +commit b58f45c8fc301fe83ee28cad3e64686c19e78f1c upstream. + +Make sure to deregister the USB driver before releasing the tty driver +to avoid use-after-free in the USB disconnect callback where the tty +devices are deregistered. + +Fixes: 61e121047645 ("staging: gdm7240: adding LTE USB driver") +Cc: Won Kang +Signed-off-by: Johan Hovold +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/staging/gdm724x/gdm_mux.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/staging/gdm724x/gdm_mux.c ++++ b/drivers/staging/gdm724x/gdm_mux.c +@@ -670,14 +670,14 @@ static int __init gdm_usb_mux_init(void) + + static void __exit gdm_usb_mux_exit(void) + { +- unregister_lte_tty_driver(); +- + if (mux_rx_wq) { + flush_workqueue(mux_rx_wq); + destroy_workqueue(mux_rx_wq); + } + + usb_deregister(&gdm_mux_driver); ++ unregister_lte_tty_driver(); ++ + } + + module_init(gdm_usb_mux_init); diff --git a/queue-4.4/staging-vt6656-use-off-stack-for-in-buffer-usb-transfers.patch b/queue-4.4/staging-vt6656-use-off-stack-for-in-buffer-usb-transfers.patch new file mode 100644 index 00000000000..016e0364d56 --- /dev/null +++ b/queue-4.4/staging-vt6656-use-off-stack-for-in-buffer-usb-transfers.patch @@ -0,0 +1,54 @@ +From 05c0cf88bec588a7cb34de569acd871ceef26760 Mon Sep 17 00:00:00 2001 +From: Malcolm Priestley +Date: Sat, 22 Apr 2017 11:14:58 +0100 +Subject: staging: vt6656: use off stack for in buffer USB transfers. + +From: Malcolm Priestley + +commit 05c0cf88bec588a7cb34de569acd871ceef26760 upstream. + +Since 4.9 mandated USB buffers to be heap allocated. This causes +the driver to fail. + +Create buffer for USB transfers. + +Signed-off-by: Malcolm Priestley +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/staging/vt6656/usbpipe.c | 17 +++++++++++++++-- + 1 file changed, 15 insertions(+), 2 deletions(-) + +--- a/drivers/staging/vt6656/usbpipe.c ++++ b/drivers/staging/vt6656/usbpipe.c +@@ -78,15 +78,28 @@ int vnt_control_in(struct vnt_private *p + u16 index, u16 length, u8 *buffer) + { + int status; ++ u8 *usb_buffer; + + if (test_bit(DEVICE_FLAGS_DISCONNECTED, &priv->flags)) + return STATUS_FAILURE; + + mutex_lock(&priv->usb_lock); + ++ usb_buffer = kmalloc(length, GFP_KERNEL); ++ if (!usb_buffer) { ++ mutex_unlock(&priv->usb_lock); ++ return -ENOMEM; ++ } ++ + status = usb_control_msg(priv->usb, +- usb_rcvctrlpipe(priv->usb, 0), request, 0xc0, value, +- index, buffer, length, USB_CTL_WAIT); ++ usb_rcvctrlpipe(priv->usb, 0), ++ request, 0xc0, value, ++ index, usb_buffer, length, USB_CTL_WAIT); ++ ++ if (status == length) ++ memcpy(buffer, usb_buffer, length); ++ ++ kfree(usb_buffer); + + mutex_unlock(&priv->usb_lock); + diff --git a/queue-4.4/staging-vt6656-use-off-stack-for-out-buffer-usb-transfers.patch b/queue-4.4/staging-vt6656-use-off-stack-for-out-buffer-usb-transfers.patch new file mode 100644 index 00000000000..dce28658354 --- /dev/null +++ b/queue-4.4/staging-vt6656-use-off-stack-for-out-buffer-usb-transfers.patch @@ -0,0 +1,52 @@ +From 12ecd24ef93277e4e5feaf27b0b18f2d3828bc5e Mon Sep 17 00:00:00 2001 +From: Malcolm Priestley +Date: Sat, 22 Apr 2017 11:14:57 +0100 +Subject: staging: vt6656: use off stack for out buffer USB transfers. + +From: Malcolm Priestley + +commit 12ecd24ef93277e4e5feaf27b0b18f2d3828bc5e upstream. + +Since 4.9 mandated USB buffers be heap allocated this causes the driver +to fail. + +Since there is a wide range of buffer sizes use kmemdup to create +allocated buffer. + +Signed-off-by: Malcolm Priestley +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/staging/vt6656/usbpipe.c | 14 ++++++++++++-- + 1 file changed, 12 insertions(+), 2 deletions(-) + +--- a/drivers/staging/vt6656/usbpipe.c ++++ b/drivers/staging/vt6656/usbpipe.c +@@ -50,15 +50,25 @@ int vnt_control_out(struct vnt_private * + u16 index, u16 length, u8 *buffer) + { + int status = 0; ++ u8 *usb_buffer; + + if (test_bit(DEVICE_FLAGS_DISCONNECTED, &priv->flags)) + return STATUS_FAILURE; + + mutex_lock(&priv->usb_lock); + ++ usb_buffer = kmemdup(buffer, length, GFP_KERNEL); ++ if (!usb_buffer) { ++ mutex_unlock(&priv->usb_lock); ++ return -ENOMEM; ++ } ++ + status = usb_control_msg(priv->usb, +- usb_sndctrlpipe(priv->usb, 0), request, 0x40, value, +- index, buffer, length, USB_CTL_WAIT); ++ usb_sndctrlpipe(priv->usb, 0), ++ request, 0x40, value, ++ index, usb_buffer, length, USB_CTL_WAIT); ++ ++ kfree(usb_buffer); + + mutex_unlock(&priv->usb_lock); + diff --git a/queue-4.4/target-convert-acl-change-queue_depth-se_session-reference-usage.patch b/queue-4.4/target-convert-acl-change-queue_depth-se_session-reference-usage.patch new file mode 100644 index 00000000000..5ed62e2870d --- /dev/null +++ b/queue-4.4/target-convert-acl-change-queue_depth-se_session-reference-usage.patch @@ -0,0 +1,397 @@ +From d36ad77f702356afb1009d2987b0ab55da4c7d57 Mon Sep 17 00:00:00 2001 +From: Nicholas Bellinger +Date: Thu, 7 Jan 2016 22:15:06 -0800 +Subject: target: Convert ACL change queue_depth se_session reference usage + +From: Nicholas Bellinger + +commit d36ad77f702356afb1009d2987b0ab55da4c7d57 upstream. + +This patch converts core_tpg_set_initiator_node_queue_depth() +to use struct se_node_acl->acl_sess_list when performing +explicit se_tpg_tfo->shutdown_session() for active sessions, +in order for new se_node_acl->queue_depth to take effect. + +This follows how core_tpg_del_initiator_node_acl() currently +works when invoking se_tpg_tfo->shutdown-session(), and ahead +of the next patch to take se_node_acl->acl_kref during lookup, +the extra get_initiator_node_acl() can go away. In order to +achieve this, go ahead and change target_get_session() to use +kref_get_unless_zero() and propigate up the return value +to know when a session is already being released. + +This is because se_node_acl->acl_group is already protecting +se_node_acl->acl_group reference via configfs, and shutdown +within core_tpg_del_initiator_node_acl() won't occur until +sys_write() to core_tpg_set_initiator_node_queue_depth() +attribute returns back to user-space. + +Also, drop the left-over iscsi-target hack, and obtain +se_portal_group->session_lock in lio_tpg_shutdown_session() +internally. Remove iscsi-target wrapper and unused se_tpg + +force parameters and associated code. + +Reported-by: Christoph Hellwig +Cc: Sagi Grimberg +Cc: Hannes Reinecke +Cc: Andy Grover +Cc: Mike Christie +Signed-off-by: Nicholas Bellinger +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/target/iscsi/iscsi_target_configfs.c | 29 +---- + drivers/target/iscsi/iscsi_target_tpg.c | 10 - + drivers/target/iscsi/iscsi_target_tpg.h | 2 + drivers/target/target_core_tpg.c | 152 +++++++-------------------- + drivers/target/target_core_transport.c | 4 + include/target/target_core_fabric.h | 5 + 6 files changed, 56 insertions(+), 146 deletions(-) + +--- a/drivers/target/iscsi/iscsi_target_configfs.c ++++ b/drivers/target/iscsi/iscsi_target_configfs.c +@@ -725,11 +725,8 @@ static ssize_t lio_target_nacl_cmdsn_dep + + if (iscsit_get_tpg(tpg) < 0) + return -EINVAL; +- /* +- * iscsit_tpg_set_initiator_node_queue_depth() assumes force=1 +- */ +- ret = iscsit_tpg_set_initiator_node_queue_depth(tpg, +- config_item_name(acl_ci), cmdsn_depth, 1); ++ ++ ret = core_tpg_set_initiator_node_queue_depth(se_nacl, cmdsn_depth); + + pr_debug("LIO_Target_ConfigFS: %s/%s Set CmdSN Window: %u for" + "InitiatorName: %s\n", config_item_name(wwn_ci), +@@ -1593,42 +1590,30 @@ static int lio_tpg_check_prot_fabric_onl + } + + /* +- * Called with spin_lock_irq(struct se_portal_group->session_lock) held +- * or not held. +- * +- * Also, this function calls iscsit_inc_session_usage_count() on the ++ * This function calls iscsit_inc_session_usage_count() on the + * struct iscsi_session in question. + */ + static int lio_tpg_shutdown_session(struct se_session *se_sess) + { + struct iscsi_session *sess = se_sess->fabric_sess_ptr; +- struct se_portal_group *se_tpg = se_sess->se_tpg; +- bool local_lock = false; +- +- if (!spin_is_locked(&se_tpg->session_lock)) { +- spin_lock_irq(&se_tpg->session_lock); +- local_lock = true; +- } ++ struct se_portal_group *se_tpg = &sess->tpg->tpg_se_tpg; + ++ spin_lock_bh(&se_tpg->session_lock); + spin_lock(&sess->conn_lock); + if (atomic_read(&sess->session_fall_back_to_erl0) || + atomic_read(&sess->session_logout) || + (sess->time2retain_timer_flags & ISCSI_TF_EXPIRED)) { + spin_unlock(&sess->conn_lock); +- if (local_lock) +- spin_unlock_irq(&sess->conn_lock); ++ spin_unlock_bh(&se_tpg->session_lock); + return 0; + } + atomic_set(&sess->session_reinstatement, 1); + spin_unlock(&sess->conn_lock); + + iscsit_stop_time2retain_timer(sess); +- spin_unlock_irq(&se_tpg->session_lock); ++ spin_unlock_bh(&se_tpg->session_lock); + + iscsit_stop_session(sess, 1, 1); +- if (!local_lock) +- spin_lock_irq(&se_tpg->session_lock); +- + return 1; + } + +--- a/drivers/target/iscsi/iscsi_target_tpg.c ++++ b/drivers/target/iscsi/iscsi_target_tpg.c +@@ -589,16 +589,6 @@ int iscsit_tpg_del_network_portal( + return iscsit_tpg_release_np(tpg_np, tpg, np); + } + +-int iscsit_tpg_set_initiator_node_queue_depth( +- struct iscsi_portal_group *tpg, +- unsigned char *initiatorname, +- u32 queue_depth, +- int force) +-{ +- return core_tpg_set_initiator_node_queue_depth(&tpg->tpg_se_tpg, +- initiatorname, queue_depth, force); +-} +- + int iscsit_ta_authentication(struct iscsi_portal_group *tpg, u32 authentication) + { + unsigned char buf1[256], buf2[256], *none = NULL; +--- a/drivers/target/iscsi/iscsi_target_tpg.h ++++ b/drivers/target/iscsi/iscsi_target_tpg.h +@@ -26,8 +26,6 @@ extern struct iscsi_tpg_np *iscsit_tpg_a + int); + extern int iscsit_tpg_del_network_portal(struct iscsi_portal_group *, + struct iscsi_tpg_np *); +-extern int iscsit_tpg_set_initiator_node_queue_depth(struct iscsi_portal_group *, +- unsigned char *, u32, int); + extern int iscsit_ta_authentication(struct iscsi_portal_group *, u32); + extern int iscsit_ta_login_timeout(struct iscsi_portal_group *, u32); + extern int iscsit_ta_netif_timeout(struct iscsi_portal_group *, u32); +--- a/drivers/target/target_core_tpg.c ++++ b/drivers/target/target_core_tpg.c +@@ -169,28 +169,25 @@ void core_tpg_add_node_to_devs( + mutex_unlock(&tpg->tpg_lun_mutex); + } + +-/* core_set_queue_depth_for_node(): +- * +- * +- */ +-static int core_set_queue_depth_for_node( +- struct se_portal_group *tpg, +- struct se_node_acl *acl) ++static void ++target_set_nacl_queue_depth(struct se_portal_group *tpg, ++ struct se_node_acl *acl, u32 queue_depth) + { ++ acl->queue_depth = queue_depth; ++ + if (!acl->queue_depth) { +- pr_err("Queue depth for %s Initiator Node: %s is 0," ++ pr_warn("Queue depth for %s Initiator Node: %s is 0," + "defaulting to 1.\n", tpg->se_tpg_tfo->get_fabric_name(), + acl->initiatorname); + acl->queue_depth = 1; + } +- +- return 0; + } + + static struct se_node_acl *target_alloc_node_acl(struct se_portal_group *tpg, + const unsigned char *initiatorname) + { + struct se_node_acl *acl; ++ u32 queue_depth; + + acl = kzalloc(max(sizeof(*acl), tpg->se_tpg_tfo->node_acl_size), + GFP_KERNEL); +@@ -205,24 +202,20 @@ static struct se_node_acl *target_alloc_ + spin_lock_init(&acl->nacl_sess_lock); + mutex_init(&acl->lun_entry_mutex); + atomic_set(&acl->acl_pr_ref_count, 0); ++ + if (tpg->se_tpg_tfo->tpg_get_default_depth) +- acl->queue_depth = tpg->se_tpg_tfo->tpg_get_default_depth(tpg); ++ queue_depth = tpg->se_tpg_tfo->tpg_get_default_depth(tpg); + else +- acl->queue_depth = 1; ++ queue_depth = 1; ++ target_set_nacl_queue_depth(tpg, acl, queue_depth); ++ + snprintf(acl->initiatorname, TRANSPORT_IQN_LEN, "%s", initiatorname); + acl->se_tpg = tpg; + acl->acl_index = scsi_get_new_index(SCSI_AUTH_INTR_INDEX); + + tpg->se_tpg_tfo->set_default_node_attributes(acl); + +- if (core_set_queue_depth_for_node(tpg, acl) < 0) +- goto out_free_acl; +- + return acl; +- +-out_free_acl: +- kfree(acl); +- return NULL; + } + + static void target_add_node_acl(struct se_node_acl *acl) +@@ -369,7 +362,8 @@ void core_tpg_del_initiator_node_acl(str + if (sess->sess_tearing_down != 0) + continue; + +- target_get_session(sess); ++ if (!target_get_session(sess)) ++ continue; + list_move(&sess->sess_acl_list, &sess_list); + } + spin_unlock_irqrestore(&acl->nacl_sess_lock, flags); +@@ -406,108 +400,52 @@ void core_tpg_del_initiator_node_acl(str + * + */ + int core_tpg_set_initiator_node_queue_depth( +- struct se_portal_group *tpg, +- unsigned char *initiatorname, +- u32 queue_depth, +- int force) ++ struct se_node_acl *acl, ++ u32 queue_depth) + { +- struct se_session *sess, *init_sess = NULL; +- struct se_node_acl *acl; ++ LIST_HEAD(sess_list); ++ struct se_portal_group *tpg = acl->se_tpg; ++ struct se_session *sess, *sess_tmp; + unsigned long flags; +- int dynamic_acl = 0; +- +- mutex_lock(&tpg->acl_node_mutex); +- acl = __core_tpg_get_initiator_node_acl(tpg, initiatorname); +- if (!acl) { +- pr_err("Access Control List entry for %s Initiator" +- " Node %s does not exists for TPG %hu, ignoring" +- " request.\n", tpg->se_tpg_tfo->get_fabric_name(), +- initiatorname, tpg->se_tpg_tfo->tpg_get_tag(tpg)); +- mutex_unlock(&tpg->acl_node_mutex); +- return -ENODEV; +- } +- if (acl->dynamic_node_acl) { +- acl->dynamic_node_acl = 0; +- dynamic_acl = 1; +- } +- mutex_unlock(&tpg->acl_node_mutex); +- +- spin_lock_irqsave(&tpg->session_lock, flags); +- list_for_each_entry(sess, &tpg->tpg_sess_list, sess_list) { +- if (sess->se_node_acl != acl) +- continue; +- +- if (!force) { +- pr_err("Unable to change queue depth for %s" +- " Initiator Node: %s while session is" +- " operational. To forcefully change the queue" +- " depth and force session reinstatement" +- " use the \"force=1\" parameter.\n", +- tpg->se_tpg_tfo->get_fabric_name(), initiatorname); +- spin_unlock_irqrestore(&tpg->session_lock, flags); +- +- mutex_lock(&tpg->acl_node_mutex); +- if (dynamic_acl) +- acl->dynamic_node_acl = 1; +- mutex_unlock(&tpg->acl_node_mutex); +- return -EEXIST; +- } +- /* +- * Determine if the session needs to be closed by our context. +- */ +- if (!tpg->se_tpg_tfo->shutdown_session(sess)) +- continue; +- +- init_sess = sess; +- break; +- } ++ int rc; + + /* + * User has requested to change the queue depth for a Initiator Node. + * Change the value in the Node's struct se_node_acl, and call +- * core_set_queue_depth_for_node() to add the requested queue depth. +- * +- * Finally call tpg->se_tpg_tfo->close_session() to force session +- * reinstatement to occur if there is an active session for the +- * $FABRIC_MOD Initiator Node in question. ++ * target_set_nacl_queue_depth() to set the new queue depth. + */ +- acl->queue_depth = queue_depth; ++ target_set_nacl_queue_depth(tpg, acl, queue_depth); ++ ++ spin_lock_irqsave(&acl->nacl_sess_lock, flags); ++ list_for_each_entry_safe(sess, sess_tmp, &acl->acl_sess_list, ++ sess_acl_list) { ++ if (sess->sess_tearing_down != 0) ++ continue; ++ if (!target_get_session(sess)) ++ continue; ++ spin_unlock_irqrestore(&acl->nacl_sess_lock, flags); + +- if (core_set_queue_depth_for_node(tpg, acl) < 0) { +- spin_unlock_irqrestore(&tpg->session_lock, flags); + /* +- * Force session reinstatement if +- * core_set_queue_depth_for_node() failed, because we assume +- * the $FABRIC_MOD has already the set session reinstatement +- * bit from tpg->se_tpg_tfo->shutdown_session() called above. ++ * Finally call tpg->se_tpg_tfo->close_session() to force session ++ * reinstatement to occur if there is an active session for the ++ * $FABRIC_MOD Initiator Node in question. + */ +- if (init_sess) +- tpg->se_tpg_tfo->close_session(init_sess); +- +- mutex_lock(&tpg->acl_node_mutex); +- if (dynamic_acl) +- acl->dynamic_node_acl = 1; +- mutex_unlock(&tpg->acl_node_mutex); +- return -EINVAL; ++ rc = tpg->se_tpg_tfo->shutdown_session(sess); ++ target_put_session(sess); ++ if (!rc) { ++ spin_lock_irqsave(&acl->nacl_sess_lock, flags); ++ continue; ++ } ++ target_put_session(sess); ++ spin_lock_irqsave(&acl->nacl_sess_lock, flags); + } +- spin_unlock_irqrestore(&tpg->session_lock, flags); +- /* +- * If the $FABRIC_MOD session for the Initiator Node ACL exists, +- * forcefully shutdown the $FABRIC_MOD session/nexus. +- */ +- if (init_sess) +- tpg->se_tpg_tfo->close_session(init_sess); ++ spin_unlock_irqrestore(&acl->nacl_sess_lock, flags); + + pr_debug("Successfully changed queue depth to: %d for Initiator" +- " Node: %s on %s Target Portal Group: %u\n", queue_depth, +- initiatorname, tpg->se_tpg_tfo->get_fabric_name(), ++ " Node: %s on %s Target Portal Group: %u\n", acl->queue_depth, ++ acl->initiatorname, tpg->se_tpg_tfo->get_fabric_name(), + tpg->se_tpg_tfo->tpg_get_tag(tpg)); + +- mutex_lock(&tpg->acl_node_mutex); +- if (dynamic_acl) +- acl->dynamic_node_acl = 1; +- mutex_unlock(&tpg->acl_node_mutex); +- + return 0; + } + EXPORT_SYMBOL(core_tpg_set_initiator_node_queue_depth); +--- a/drivers/target/target_core_transport.c ++++ b/drivers/target/target_core_transport.c +@@ -383,9 +383,9 @@ static void target_release_session(struc + se_tpg->se_tpg_tfo->close_session(se_sess); + } + +-void target_get_session(struct se_session *se_sess) ++int target_get_session(struct se_session *se_sess) + { +- kref_get(&se_sess->sess_kref); ++ return kref_get_unless_zero(&se_sess->sess_kref); + } + EXPORT_SYMBOL(target_get_session); + +--- a/include/target/target_core_fabric.h ++++ b/include/target/target_core_fabric.h +@@ -117,7 +117,7 @@ void __transport_register_session(struct + struct se_node_acl *, struct se_session *, void *); + void transport_register_session(struct se_portal_group *, + struct se_node_acl *, struct se_session *, void *); +-void target_get_session(struct se_session *); ++int target_get_session(struct se_session *); + void target_put_session(struct se_session *); + ssize_t target_show_dynamic_sessions(struct se_portal_group *, char *); + void transport_free_session(struct se_session *); +@@ -172,8 +172,7 @@ bool target_tpg_has_node_acl(struct se_p + const char *); + struct se_node_acl *core_tpg_check_initiator_node_acl(struct se_portal_group *, + unsigned char *); +-int core_tpg_set_initiator_node_queue_depth(struct se_portal_group *, +- unsigned char *, u32, int); ++int core_tpg_set_initiator_node_queue_depth(struct se_node_acl *, u32); + int core_tpg_set_initiator_node_tag(struct se_portal_group *, + struct se_node_acl *, const char *); + int core_tpg_register(struct se_wwn *, struct se_portal_group *, int); diff --git a/queue-4.4/target-fileio-fix-zero-length-read-and-write-handling.patch b/queue-4.4/target-fileio-fix-zero-length-read-and-write-handling.patch new file mode 100644 index 00000000000..e5e6eab9a7d --- /dev/null +++ b/queue-4.4/target-fileio-fix-zero-length-read-and-write-handling.patch @@ -0,0 +1,50 @@ +From 59ac9c078141b8fd0186c0b18660a1b2c24e724e Mon Sep 17 00:00:00 2001 +From: Bart Van Assche +Date: Thu, 4 May 2017 15:50:47 -0700 +Subject: target/fileio: Fix zero-length READ and WRITE handling + +From: Bart Van Assche + +commit 59ac9c078141b8fd0186c0b18660a1b2c24e724e upstream. + +This patch fixes zero-length READ and WRITE handling in target/FILEIO, +which was broken a long time back by: + +Since: + + commit d81cb44726f050d7cf1be4afd9cb45d153b52066 + Author: Paolo Bonzini + Date: Mon Sep 17 16:36:11 2012 -0700 + + target: go through normal processing for all zero-length commands + +which moved zero-length READ and WRITE completion out of target-core, +to doing submission into backend driver code. + +To address this, go ahead and invoke target_complete_cmd() for any +non negative return value in fd_do_rw(). + +Signed-off-by: Bart Van Assche +Reviewed-by: Hannes Reinecke +Reviewed-by: Christoph Hellwig +Cc: Andy Grover +Cc: David Disseldorp +Signed-off-by: Nicholas Bellinger +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/target/target_core_file.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +--- a/drivers/target/target_core_file.c ++++ b/drivers/target/target_core_file.c +@@ -594,8 +594,7 @@ fd_execute_rw(struct se_cmd *cmd, struct + if (ret < 0) + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + +- if (ret) +- target_complete_cmd(cmd, SAM_STAT_GOOD); ++ target_complete_cmd(cmd, SAM_STAT_GOOD); + return 0; + } + diff --git a/queue-4.4/target-fix-compare_and_write_callback-handling-for-non-good-status.patch b/queue-4.4/target-fix-compare_and_write_callback-handling-for-non-good-status.patch new file mode 100644 index 00000000000..35731b71015 --- /dev/null +++ b/queue-4.4/target-fix-compare_and_write_callback-handling-for-non-good-status.patch @@ -0,0 +1,48 @@ +From a71a5dc7f833943998e97ca8fa6a4c708a0ed1a9 Mon Sep 17 00:00:00 2001 +From: Nicholas Bellinger +Date: Tue, 11 Apr 2017 16:24:16 -0700 +Subject: target: Fix compare_and_write_callback handling for non GOOD status + +From: Nicholas Bellinger + +commit a71a5dc7f833943998e97ca8fa6a4c708a0ed1a9 upstream. + +Following the bugfix for handling non SAM_STAT_GOOD COMPARE_AND_WRITE +status during COMMIT phase in commit 9b2792c3da1, the same bug exists +for the READ phase as well. + +This would manifest first as a lost SCSI response, and eventual +hung task during fabric driver logout or re-login, as existing +shutdown logic waited for the COMPARE_AND_WRITE se_cmd->cmd_kref +to reach zero. + +To address this bug, compare_and_write_callback() has been changed +to set post_ret = 1 and return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE +as necessary to signal failure status. + +Reported-by: Bill Borsari +Cc: Bill Borsari +Tested-by: Gary Guo +Cc: Gary Guo +Signed-off-by: Nicholas Bellinger +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/target/target_core_sbc.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +--- a/drivers/target/target_core_sbc.c ++++ b/drivers/target/target_core_sbc.c +@@ -498,8 +498,11 @@ static sense_reason_t compare_and_write_ + * been failed with a non-zero SCSI status. + */ + if (cmd->scsi_status) { +- pr_err("compare_and_write_callback: non zero scsi_status:" ++ pr_debug("compare_and_write_callback: non zero scsi_status:" + " 0x%02x\n", cmd->scsi_status); ++ *post_ret = 1; ++ if (cmd->scsi_status == SAM_STAT_CHECK_CONDITION) ++ ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + goto out; + } + diff --git a/queue-4.4/usb-host-xhci-print-correct-command-ring-address.patch b/queue-4.4/usb-host-xhci-print-correct-command-ring-address.patch new file mode 100644 index 00000000000..004a1dbbad3 --- /dev/null +++ b/queue-4.4/usb-host-xhci-print-correct-command-ring-address.patch @@ -0,0 +1,30 @@ +From 6fc091fb0459ade939a795bfdcaf645385b951d4 Mon Sep 17 00:00:00 2001 +From: Peter Chen +Date: Wed, 19 Apr 2017 16:55:52 +0300 +Subject: usb: host: xhci: print correct command ring address + +From: Peter Chen + +commit 6fc091fb0459ade939a795bfdcaf645385b951d4 upstream. + +Print correct command ring address using 'val_64'. + +Signed-off-by: Peter Chen +Signed-off-by: Mathias Nyman +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/host/xhci-mem.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/usb/host/xhci-mem.c ++++ b/drivers/usb/host/xhci-mem.c +@@ -2493,7 +2493,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, + (xhci->cmd_ring->first_seg->dma & (u64) ~CMD_RING_RSVD_BITS) | + xhci->cmd_ring->cycle_state; + xhci_dbg_trace(xhci, trace_xhci_dbg_init, +- "// Setting command ring address to 0x%x", val); ++ "// Setting command ring address to 0x%016llx", val_64); + xhci_write_64(xhci, val_64, &xhci->op_regs->cmd_ring); + xhci_dbg_cmd_ptrs(xhci); + diff --git a/queue-4.4/usb-hub-do-not-attempt-to-autosuspend-disconnected-devices.patch b/queue-4.4/usb-hub-do-not-attempt-to-autosuspend-disconnected-devices.patch new file mode 100644 index 00000000000..c54236b1357 --- /dev/null +++ b/queue-4.4/usb-hub-do-not-attempt-to-autosuspend-disconnected-devices.patch @@ -0,0 +1,103 @@ +From f5cccf49428447dfbc9edb7a04bb8fc316269781 Mon Sep 17 00:00:00 2001 +From: Guenter Roeck +Date: Mon, 20 Mar 2017 14:30:50 -0700 +Subject: usb: hub: Do not attempt to autosuspend disconnected devices + +From: Guenter Roeck + +commit f5cccf49428447dfbc9edb7a04bb8fc316269781 upstream. + +While running a bind/unbind stress test with the dwc3 usb driver on rk3399, +the following crash was observed. + +Unable to handle kernel NULL pointer dereference at virtual address 00000218 +pgd = ffffffc00165f000 +[00000218] *pgd=000000000174f003, *pud=000000000174f003, + *pmd=0000000001750003, *pte=00e8000001751713 +Internal error: Oops: 96000005 [#1] PREEMPT SMP +Modules linked in: uinput uvcvideo videobuf2_vmalloc cmac +ipt_MASQUERADE nf_nat_masquerade_ipv4 iptable_nat nf_nat_ipv4 nf_nat rfcomm +xt_mark fuse bridge stp llc zram btusb btrtl btbcm btintel bluetooth +ip6table_filter mwifiex_pcie mwifiex cfg80211 cdc_ether usbnet r8152 mii joydev +snd_seq_midi snd_seq_midi_event snd_rawmidi snd_seq snd_seq_device ppp_async +ppp_generic slhc tun +CPU: 1 PID: 29814 Comm: kworker/1:1 Not tainted 4.4.52 #507 +Hardware name: Google Kevin (DT) +Workqueue: pm pm_runtime_work +task: ffffffc0ac540000 ti: ffffffc0af4d4000 task.ti: ffffffc0af4d4000 +PC is at autosuspend_check+0x74/0x174 +LR is at autosuspend_check+0x70/0x174 +... +Call trace: +[] autosuspend_check+0x74/0x174 +[] usb_runtime_idle+0x20/0x40 +[] __rpm_callback+0x48/0x7c +[] rpm_idle+0x1e8/0x498 +[] pm_runtime_work+0x88/0xcc +[] process_one_work+0x390/0x6b8 +[] worker_thread+0x480/0x610 +[] kthread+0x164/0x178 +[] ret_from_fork+0x10/0x40 + +Source: + +(gdb) l *0xffffffc00080dcc0 +0xffffffc00080dcc0 is in autosuspend_check +(drivers/usb/core/driver.c:1778). +1773 /* We don't need to check interfaces that are +1774 * disabled for runtime PM. Either they are unbound +1775 * or else their drivers don't support autosuspend +1776 * and so they are permanently active. +1777 */ +1778 if (intf->dev.power.disable_depth) +1779 continue; +1780 if (atomic_read(&intf->dev.power.usage_count) > 0) +1781 return -EBUSY; +1782 w |= intf->needs_remote_wakeup; + +Code analysis shows that intf is set to NULL in usb_disable_device() prior +to setting actconfig to NULL. At the same time, usb_runtime_idle() does not +lock the usb device, and neither does any of the functions in the +traceback. This means that there is no protection against a race condition +where usb_disable_device() is removing dev->actconfig->interface[] pointers +while those are being accessed from autosuspend_check(). + +To solve the problem, synchronize and validate device state between +autosuspend_check() and usb_disconnect(). + +Acked-by: Alan Stern +Signed-off-by: Guenter Roeck +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/core/driver.c | 3 +++ + drivers/usb/core/hub.c | 6 ++++++ + 2 files changed, 9 insertions(+) + +--- a/drivers/usb/core/driver.c ++++ b/drivers/usb/core/driver.c +@@ -1778,6 +1778,9 @@ static int autosuspend_check(struct usb_ + int w, i; + struct usb_interface *intf; + ++ if (udev->state == USB_STATE_NOTATTACHED) ++ return -ENODEV; ++ + /* Fail if autosuspend is disabled, or any interfaces are in use, or + * any interface drivers require remote wakeup but it isn't available. + */ +--- a/drivers/usb/core/hub.c ++++ b/drivers/usb/core/hub.c +@@ -2071,6 +2071,12 @@ void usb_disconnect(struct usb_device ** + dev_info(&udev->dev, "USB disconnect, device number %d\n", + udev->devnum); + ++ /* ++ * Ensure that the pm runtime code knows that the USB device ++ * is in the process of being disconnected. ++ */ ++ pm_runtime_barrier(&udev->dev); ++ + usb_lock_device(udev); + + hub_disconnect_children(udev); diff --git a/queue-4.4/usb-hub-fix-error-loop-seen-after-hub-communication-errors.patch b/queue-4.4/usb-hub-fix-error-loop-seen-after-hub-communication-errors.patch new file mode 100644 index 00000000000..e8e3cab6903 --- /dev/null +++ b/queue-4.4/usb-hub-fix-error-loop-seen-after-hub-communication-errors.patch @@ -0,0 +1,137 @@ +From 245b2eecee2aac6fdc77dcafaa73c33f9644c3c7 Mon Sep 17 00:00:00 2001 +From: Guenter Roeck +Date: Mon, 20 Mar 2017 11:16:11 -0700 +Subject: usb: hub: Fix error loop seen after hub communication errors + +From: Guenter Roeck + +commit 245b2eecee2aac6fdc77dcafaa73c33f9644c3c7 upstream. + +While stress testing a usb controller using a bind/unbind looop, the +following error loop was observed. + +usb 7-1.2: new low-speed USB device number 3 using xhci-hcd +usb 7-1.2: hub failed to enable device, error -108 +usb 7-1-port2: cannot disable (err = -22) +usb 7-1-port2: couldn't allocate usb_device +usb 7-1-port2: cannot disable (err = -22) +hub 7-1:1.0: hub_ext_port_status failed (err = -22) +hub 7-1:1.0: hub_ext_port_status failed (err = -22) +hub 7-1:1.0: activate --> -22 +hub 7-1:1.0: hub_ext_port_status failed (err = -22) +hub 7-1:1.0: hub_ext_port_status failed (err = -22) +hub 7-1:1.0: activate --> -22 +hub 7-1:1.0: hub_ext_port_status failed (err = -22) +hub 7-1:1.0: hub_ext_port_status failed (err = -22) +hub 7-1:1.0: activate --> -22 +hub 7-1:1.0: hub_ext_port_status failed (err = -22) +hub 7-1:1.0: hub_ext_port_status failed (err = -22) +hub 7-1:1.0: activate --> -22 +hub 7-1:1.0: hub_ext_port_status failed (err = -22) +hub 7-1:1.0: hub_ext_port_status failed (err = -22) +hub 7-1:1.0: activate --> -22 +hub 7-1:1.0: hub_ext_port_status failed (err = -22) +hub 7-1:1.0: hub_ext_port_status failed (err = -22) +hub 7-1:1.0: activate --> -22 +hub 7-1:1.0: hub_ext_port_status failed (err = -22) +hub 7-1:1.0: hub_ext_port_status failed (err = -22) +hub 7-1:1.0: activate --> -22 +hub 7-1:1.0: hub_ext_port_status failed (err = -22) +hub 7-1:1.0: hub_ext_port_status failed (err = -22) +hub 7-1:1.0: activate --> -22 +hub 7-1:1.0: hub_ext_port_status failed (err = -22) +hub 7-1:1.0: hub_ext_port_status failed (err = -22) +** 57 printk messages dropped ** hub 7-1:1.0: activate --> -22 +** 82 printk messages dropped ** hub 7-1:1.0: hub_ext_port_status failed (err = -22) + +This continues forever. After adding tracebacks into the code, +the call sequence leading to this is found to be as follows. + +[] hub_activate+0x368/0x7b8 +[] hub_resume+0x2c/0x3c +[] usb_resume_interface.isra.6+0x128/0x158 +[] usb_suspend_both+0x1e8/0x288 +[] usb_runtime_suspend+0x3c/0x98 +[] __rpm_callback+0x48/0x7c +[] rpm_callback+0xa8/0xd4 +[] rpm_suspend+0x84/0x758 +[] rpm_idle+0x2c8/0x498 +[] __pm_runtime_idle+0x60/0xac +[] usb_autopm_put_interface+0x6c/0x7c +[] hub_event+0x10ac/0x12ac +[] process_one_work+0x390/0x6b8 +[] worker_thread+0x480/0x610 +[] kthread+0x164/0x178 +[] ret_from_fork+0x10/0x40 + +kick_hub_wq() is called from hub_activate() even after failures to +communicate with the hub. This results in an endless sequence of +hub event -> hub activate -> wq trigger -> hub event -> ... + +Provide two solutions for the problem. + +- Only trigger the hub event queue if communication with the hub + is successful. +- After a suspend failure, only resume already suspended interfaces + if the communication with the device is still possible. + +Each of the changes fixes the observed problem. Use both to improve +robustness. + +Acked-by: Alan Stern +Signed-off-by: Guenter Roeck +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/core/driver.c | 18 ++++++++++++++++++ + drivers/usb/core/hub.c | 5 ++++- + 2 files changed, 22 insertions(+), 1 deletion(-) + +--- a/drivers/usb/core/driver.c ++++ b/drivers/usb/core/driver.c +@@ -1328,6 +1328,24 @@ static int usb_suspend_both(struct usb_d + */ + if (udev->parent && !PMSG_IS_AUTO(msg)) + status = 0; ++ ++ /* ++ * If the device is inaccessible, don't try to resume ++ * suspended interfaces and just return the error. ++ */ ++ if (status && status != -EBUSY) { ++ int err; ++ u16 devstat; ++ ++ err = usb_get_status(udev, USB_RECIP_DEVICE, 0, ++ &devstat); ++ if (err) { ++ dev_err(&udev->dev, ++ "Failed to suspend device, error %d\n", ++ status); ++ goto done; ++ } ++ } + } + + /* If the suspend failed, resume interfaces that did get suspended */ +--- a/drivers/usb/core/hub.c ++++ b/drivers/usb/core/hub.c +@@ -1048,6 +1048,9 @@ static void hub_activate(struct usb_hub + + portstatus = portchange = 0; + status = hub_port_status(hub, port1, &portstatus, &portchange); ++ if (status) ++ goto abort; ++ + if (udev || (portstatus & USB_PORT_STAT_CONNECTION)) + dev_dbg(&port_dev->dev, "status %04x change %04x\n", + portstatus, portchange); +@@ -1180,7 +1183,7 @@ static void hub_activate(struct usb_hub + + /* Scan all ports that need attention */ + kick_hub_wq(hub); +- ++ abort: + if (type == HUB_INIT2 || type == HUB_INIT3) { + /* Allow autosuspend if it was suppressed */ + disconnected: diff --git a/queue-4.4/usb-make-sure-usb-phy-of-gets-built-in.patch b/queue-4.4/usb-make-sure-usb-phy-of-gets-built-in.patch new file mode 100644 index 00000000000..1232d571922 --- /dev/null +++ b/queue-4.4/usb-make-sure-usb-phy-of-gets-built-in.patch @@ -0,0 +1,54 @@ +From 3d6159640da9c9175d1ca42f151fc1a14caded59 Mon Sep 17 00:00:00 2001 +From: Alexey Brodkin +Date: Thu, 13 Apr 2017 15:33:34 +0300 +Subject: usb: Make sure usb/phy/of gets built-in + +From: Alexey Brodkin + +commit 3d6159640da9c9175d1ca42f151fc1a14caded59 upstream. + +DWC3 driver uses of_usb_get_phy_mode() which is +implemented in drivers/usb/phy/of.c and in bare minimal +configuration it might not be pulled in kernel binary. + +In case of ARC or ARM this could be easily reproduced with +"allnodefconfig" +CONFIG_USB=m +CONFIG_USB_DWC3=m. + +On building all ends-up with: +---------------------->8------------------ + Kernel: arch/arm/boot/Image is ready + Kernel: arch/arm/boot/zImage is ready + Building modules, stage 2. + MODPOST 5 modules +ERROR: "of_usb_get_phy_mode" [drivers/usb/dwc3/dwc3.ko] undefined! +make[1]: *** [__modpost] Error 1 +make: *** [modules] Error 2 +---------------------->8------------------ + +Signed-off-by: Alexey Brodkin +Cc: Greg Kroah-Hartman +Cc: Masahiro Yamada +Cc: Geert Uytterhoeven +Cc: Nicolas Pitre +Cc: Thomas Gleixner +Cc: Felipe Balbi +Cc: Felix Fietkau +Cc: Jeremy Kerr +Cc: linux-snps-arc@lists.infradead.org +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/Makefile | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/Makefile ++++ b/drivers/Makefile +@@ -98,6 +98,7 @@ obj-$(CONFIG_USB_PHY) += usb/ + obj-$(CONFIG_USB) += usb/ + obj-$(CONFIG_PCI) += usb/ + obj-$(CONFIG_USB_GADGET) += usb/ ++obj-$(CONFIG_OF) += usb/ + obj-$(CONFIG_SERIO) += input/serio/ + obj-$(CONFIG_GAMEPORT) += input/gameport/ + obj-$(CONFIG_INPUT) += input/ diff --git a/queue-4.4/usb-misc-add-missing-continue-in-switch.patch b/queue-4.4/usb-misc-add-missing-continue-in-switch.patch new file mode 100644 index 00000000000..73c64e65181 --- /dev/null +++ b/queue-4.4/usb-misc-add-missing-continue-in-switch.patch @@ -0,0 +1,30 @@ +From 2c930e3d0aed1505e86e0928d323df5027817740 Mon Sep 17 00:00:00 2001 +From: "Gustavo A. R. Silva" +Date: Mon, 3 Apr 2017 22:48:40 -0500 +Subject: usb: misc: add missing continue in switch + +From: Gustavo A. R. Silva + +commit 2c930e3d0aed1505e86e0928d323df5027817740 upstream. + +Add missing continue in switch. + +Addresses-Coverity-ID: 1248733 +Signed-off-by: Gustavo A. R. Silva +Acked-by: Alan Stern +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/misc/usbtest.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/usb/misc/usbtest.c ++++ b/drivers/usb/misc/usbtest.c +@@ -135,6 +135,7 @@ get_endpoints(struct usbtest_dev *dev, s + case USB_ENDPOINT_XFER_INT: + if (dev->info->intr) + goto try_intr; ++ continue; + case USB_ENDPOINT_XFER_ISOC: + if (dev->info->iso) + goto try_iso; diff --git a/queue-4.4/usb-misc-legousbtower-fix-buffers-on-stack.patch b/queue-4.4/usb-misc-legousbtower-fix-buffers-on-stack.patch new file mode 100644 index 00000000000..7c2402c93ce --- /dev/null +++ b/queue-4.4/usb-misc-legousbtower-fix-buffers-on-stack.patch @@ -0,0 +1,116 @@ +From 942a48730faf149ccbf3e12ac718aee120bb3529 Mon Sep 17 00:00:00 2001 +From: Maksim Salau +Date: Tue, 25 Apr 2017 22:49:21 +0300 +Subject: usb: misc: legousbtower: Fix buffers on stack + +From: Maksim Salau + +commit 942a48730faf149ccbf3e12ac718aee120bb3529 upstream. + +Allocate buffers on HEAP instead of STACK for local structures +that are to be received using usb_control_msg(). + +Signed-off-by: Maksim Salau +Tested-by: Alfredo Rafael Vicente Boix ; +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/misc/legousbtower.c | 37 +++++++++++++++++++++++++++---------- + 1 file changed, 27 insertions(+), 10 deletions(-) + +--- a/drivers/usb/misc/legousbtower.c ++++ b/drivers/usb/misc/legousbtower.c +@@ -317,9 +317,16 @@ static int tower_open (struct inode *ino + int subminor; + int retval = 0; + struct usb_interface *interface; +- struct tower_reset_reply reset_reply; ++ struct tower_reset_reply *reset_reply; + int result; + ++ reset_reply = kmalloc(sizeof(*reset_reply), GFP_KERNEL); ++ ++ if (!reset_reply) { ++ retval = -ENOMEM; ++ goto exit; ++ } ++ + nonseekable_open(inode, file); + subminor = iminor(inode); + +@@ -364,8 +371,8 @@ static int tower_open (struct inode *ino + USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_DEVICE, + 0, + 0, +- &reset_reply, +- sizeof(reset_reply), ++ reset_reply, ++ sizeof(*reset_reply), + 1000); + if (result < 0) { + dev_err(&dev->udev->dev, +@@ -406,6 +413,7 @@ unlock_exit: + mutex_unlock(&dev->lock); + + exit: ++ kfree(reset_reply); + return retval; + } + +@@ -808,7 +816,7 @@ static int tower_probe (struct usb_inter + struct lego_usb_tower *dev = NULL; + struct usb_host_interface *iface_desc; + struct usb_endpoint_descriptor* endpoint; +- struct tower_get_version_reply get_version_reply; ++ struct tower_get_version_reply *get_version_reply = NULL; + int i; + int retval = -ENOMEM; + int result; +@@ -898,6 +906,13 @@ static int tower_probe (struct usb_inter + dev->interrupt_in_interval = interrupt_in_interval ? interrupt_in_interval : dev->interrupt_in_endpoint->bInterval; + dev->interrupt_out_interval = interrupt_out_interval ? interrupt_out_interval : dev->interrupt_out_endpoint->bInterval; + ++ get_version_reply = kmalloc(sizeof(*get_version_reply), GFP_KERNEL); ++ ++ if (!get_version_reply) { ++ retval = -ENOMEM; ++ goto error; ++ } ++ + /* get the firmware version and log it */ + result = usb_control_msg (udev, + usb_rcvctrlpipe(udev, 0), +@@ -905,18 +920,19 @@ static int tower_probe (struct usb_inter + USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_DEVICE, + 0, + 0, +- &get_version_reply, +- sizeof(get_version_reply), ++ get_version_reply, ++ sizeof(*get_version_reply), + 1000); + if (result < 0) { + dev_err(idev, "LEGO USB Tower get version control request failed\n"); + retval = result; + goto error; + } +- dev_info(&interface->dev, "LEGO USB Tower firmware version is %d.%d " +- "build %d\n", get_version_reply.major, +- get_version_reply.minor, +- le16_to_cpu(get_version_reply.build_no)); ++ dev_info(&interface->dev, ++ "LEGO USB Tower firmware version is %d.%d build %d\n", ++ get_version_reply->major, ++ get_version_reply->minor, ++ le16_to_cpu(get_version_reply->build_no)); + + /* we can register the device now, as it is ready */ + usb_set_intfdata (interface, dev); +@@ -940,6 +956,7 @@ exit: + return retval; + + error: ++ kfree(get_version_reply); + tower_delete(dev); + return retval; + } diff --git a/queue-4.4/usb-proper-handling-of-race-condition-when-two-usb-class-drivers-try-to-call-init_usb_class-simultaneously.patch b/queue-4.4/usb-proper-handling-of-race-condition-when-two-usb-class-drivers-try-to-call-init_usb_class-simultaneously.patch new file mode 100644 index 00000000000..f3d5881bfb4 --- /dev/null +++ b/queue-4.4/usb-proper-handling-of-race-condition-when-two-usb-class-drivers-try-to-call-init_usb_class-simultaneously.patch @@ -0,0 +1,60 @@ +From 2f86a96be0ccb1302b7eee7855dbee5ce4dc5dfb Mon Sep 17 00:00:00 2001 +From: Ajay Kaher +Date: Tue, 28 Mar 2017 08:09:32 -0400 +Subject: USB: Proper handling of Race Condition when two USB class drivers try to call init_usb_class simultaneously + +From: Ajay Kaher + +commit 2f86a96be0ccb1302b7eee7855dbee5ce4dc5dfb upstream. + +There is race condition when two USB class drivers try to call +init_usb_class at the same time and leads to crash. +code path: probe->usb_register_dev->init_usb_class + +To solve this, mutex locking has been added in init_usb_class() and +destroy_usb_class(). + +As pointed by Alan, removed "if (usb_class)" test from destroy_usb_class() +because usb_class can never be NULL there. + +Signed-off-by: Ajay Kaher +Acked-by: Alan Stern +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/core/file.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +--- a/drivers/usb/core/file.c ++++ b/drivers/usb/core/file.c +@@ -26,6 +26,7 @@ + #define MAX_USB_MINORS 256 + static const struct file_operations *usb_minors[MAX_USB_MINORS]; + static DECLARE_RWSEM(minor_rwsem); ++static DEFINE_MUTEX(init_usb_class_mutex); + + static int usb_open(struct inode *inode, struct file *file) + { +@@ -108,8 +109,9 @@ static void release_usb_class(struct kre + + static void destroy_usb_class(void) + { +- if (usb_class) +- kref_put(&usb_class->kref, release_usb_class); ++ mutex_lock(&init_usb_class_mutex); ++ kref_put(&usb_class->kref, release_usb_class); ++ mutex_unlock(&init_usb_class_mutex); + } + + int usb_major_init(void) +@@ -171,7 +173,10 @@ int usb_register_dev(struct usb_interfac + if (intf->minor >= 0) + return -EADDRINUSE; + ++ mutex_lock(&init_usb_class_mutex); + retval = init_usb_class(); ++ mutex_unlock(&init_usb_class_mutex); ++ + if (retval) + return retval; + diff --git a/queue-4.4/usb-serial-ftdi_sio-add-device-id-for-microsemi-arrow-sf2plus-dev-kit.patch b/queue-4.4/usb-serial-ftdi_sio-add-device-id-for-microsemi-arrow-sf2plus-dev-kit.patch new file mode 100644 index 00000000000..3962563329a --- /dev/null +++ b/queue-4.4/usb-serial-ftdi_sio-add-device-id-for-microsemi-arrow-sf2plus-dev-kit.patch @@ -0,0 +1,51 @@ +From 31c5d1922b90ddc1da6a6ddecef7cd31f17aa32b Mon Sep 17 00:00:00 2001 +From: Marek Vasut +Date: Tue, 18 Apr 2017 20:07:56 +0200 +Subject: USB: serial: ftdi_sio: add device ID for Microsemi/Arrow SF2PLUS Dev Kit + +From: Marek Vasut + +commit 31c5d1922b90ddc1da6a6ddecef7cd31f17aa32b upstream. + +This development kit has an FT4232 on it with a custom USB VID/PID. +The FT4232 provides four UARTs, but only two are used. The UART 0 +is used by the FlashPro5 programmer and UART 2 is connected to the +SmartFusion2 CortexM3 SoC UART port. + +Note that the USB VID is registered to Actel according to Linux USB +VID database, but that was acquired by Microsemi. + +Signed-off-by: Marek Vasut +Signed-off-by: Johan Hovold +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/serial/ftdi_sio.c | 1 + + drivers/usb/serial/ftdi_sio_ids.h | 6 ++++++ + 2 files changed, 7 insertions(+) + +--- a/drivers/usb/serial/ftdi_sio.c ++++ b/drivers/usb/serial/ftdi_sio.c +@@ -873,6 +873,7 @@ static const struct usb_device_id id_tab + { USB_DEVICE_AND_INTERFACE_INFO(MICROCHIP_VID, MICROCHIP_USB_BOARD_PID, + USB_CLASS_VENDOR_SPEC, + USB_SUBCLASS_VENDOR_SPEC, 0x00) }, ++ { USB_DEVICE_INTERFACE_NUMBER(ACTEL_VID, MICROSEMI_ARROW_SF2PLUS_BOARD_PID, 2) }, + { USB_DEVICE(JETI_VID, JETI_SPC1201_PID) }, + { USB_DEVICE(MARVELL_VID, MARVELL_SHEEVAPLUG_PID), + .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, +--- a/drivers/usb/serial/ftdi_sio_ids.h ++++ b/drivers/usb/serial/ftdi_sio_ids.h +@@ -873,6 +873,12 @@ + #define FIC_VID 0x1457 + #define FIC_NEO1973_DEBUG_PID 0x5118 + ++/* ++ * Actel / Microsemi ++ */ ++#define ACTEL_VID 0x1514 ++#define MICROSEMI_ARROW_SF2PLUS_BOARD_PID 0x2008 ++ + /* Olimex */ + #define OLIMEX_VID 0x15BA + #define OLIMEX_ARM_USB_OCD_PID 0x0003