All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 1/6] xhci: fix usb3 streams
       [not found] <1379071635-30701-1-git-send-email-kraxel@redhat.com>
@ 2013-09-13 11:27 ` Gerd Hoffmann
  2013-09-13 11:27   ` Gerd Hoffmann
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 16+ messages in thread
From: Gerd Hoffmann @ 2013-09-13 11:27 UTC (permalink / raw)
  To: linux-usb; +Cc: Gerd Hoffmann, Sarah Sharp, Greg Kroah-Hartman, open list

xhci maintains a radix tree for each stream endpoint because it must
be able to map a trb address to the stream ring.  Each ring segment
must be added to the ring for this to work.  Currently xhci sticks
only the first segment of each stream ring into the radix tree.

Result is that things work initially, but as soon as the first segment
is full xhci can't map the trb address from the completion event to the
stream ring any more -> BOOM.  You'll find this message in the logs:

  ERROR Transfer event for disabled endpoint or incorrect stream ring

This patch adds a helper function to update the radix tree.  It can
both insert and remove ring segments.  It loops over the segment list
and handles all segments instead of just the first.  It is called
whenever an update is needed:  When allocating a ring, when expanding
a ring and when releasing a ring.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 drivers/usb/host/xhci-mem.c | 53 ++++++++++++++++++++++++++++++++++-----------
 drivers/usb/host/xhci.h     |  2 ++
 2 files changed, 42 insertions(+), 13 deletions(-)

diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index 6f8c2fd..de8b006 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -154,8 +154,11 @@ void xhci_ring_free(struct xhci_hcd *xhci, struct xhci_ring *ring)
 	if (!ring)
 		return;
 
-	if (ring->first_seg)
+	if (ring->first_seg) {
+		if (ring->type == TYPE_STREAM)
+			xhci_update_stream_ring(ring, false);
 		xhci_free_segments_for_ring(xhci, ring->first_seg);
+	}
 
 	kfree(ring);
 }
@@ -351,6 +354,11 @@ int xhci_ring_expansion(struct xhci_hcd *xhci, struct xhci_ring *ring,
 	xhci_dbg(xhci, "ring expansion succeed, now has %d segments\n",
 			ring->num_segs);
 
+	if (ring->type == TYPE_STREAM) {
+		ret = xhci_update_stream_ring(ring, true);
+		WARN_ON(ret); /* FIXME */
+	}
+
 	return 0;
 }
 
@@ -601,6 +609,35 @@ static int xhci_test_radix_tree(struct xhci_hcd *xhci,
  * extended systems (where the DMA address can be bigger than 32-bits),
  * if we allow the PCI dma mask to be bigger than 32-bits.  So don't do that.
  */
+
+int xhci_update_stream_ring(struct xhci_ring *ring, bool insert)
+{
+	struct xhci_segment *seg;
+	unsigned long key;
+	bool present;
+	int ret;
+
+	if (WARN_ON_ONCE(ring->trb_address_map == NULL))
+		return 0;
+
+	seg = ring->first_seg;
+	do {
+		key = (unsigned long)(seg->dma >> TRB_SEGMENT_SHIFT);
+		present = radix_tree_lookup(ring->trb_address_map, key) != NULL;
+		if (!present && insert) {
+			ret = radix_tree_insert(ring->trb_address_map,
+						key, ring);
+			if (ret)
+				return ret;
+		}
+		if (present && !insert)
+			radix_tree_delete(ring->trb_address_map, key);
+		seg = seg->next;
+	} while (seg != ring->first_seg);
+
+	return 0;
+}
+
 struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci,
 		unsigned int num_stream_ctxs,
 		unsigned int num_streams, gfp_t mem_flags)
@@ -608,7 +645,6 @@ struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci,
 	struct xhci_stream_info *stream_info;
 	u32 cur_stream;
 	struct xhci_ring *cur_ring;
-	unsigned long key;
 	u64 addr;
 	int ret;
 
@@ -663,6 +699,7 @@ struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci,
 		if (!cur_ring)
 			goto cleanup_rings;
 		cur_ring->stream_id = cur_stream;
+		cur_ring->trb_address_map = &stream_info->trb_address_map;
 		/* Set deq ptr, cycle bit, and stream context type */
 		addr = cur_ring->first_seg->dma |
 			SCT_FOR_CTX(SCT_PRI_TR) |
@@ -672,10 +709,7 @@ struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci,
 		xhci_dbg(xhci, "Setting stream %d ring ptr to 0x%08llx\n",
 				cur_stream, (unsigned long long) addr);
 
-		key = (unsigned long)
-			(cur_ring->first_seg->dma >> TRB_SEGMENT_SHIFT);
-		ret = radix_tree_insert(&stream_info->trb_address_map,
-				key, cur_ring);
+		ret = xhci_update_stream_ring(cur_ring, true);
 		if (ret) {
 			xhci_ring_free(xhci, cur_ring);
 			stream_info->stream_rings[cur_stream] = NULL;
@@ -702,9 +736,6 @@ cleanup_rings:
 	for (cur_stream = 1; cur_stream < num_streams; cur_stream++) {
 		cur_ring = stream_info->stream_rings[cur_stream];
 		if (cur_ring) {
-			addr = cur_ring->first_seg->dma;
-			radix_tree_delete(&stream_info->trb_address_map,
-					addr >> TRB_SEGMENT_SHIFT);
 			xhci_ring_free(xhci, cur_ring);
 			stream_info->stream_rings[cur_stream] = NULL;
 		}
@@ -764,7 +795,6 @@ void xhci_free_stream_info(struct xhci_hcd *xhci,
 {
 	int cur_stream;
 	struct xhci_ring *cur_ring;
-	dma_addr_t addr;
 
 	if (!stream_info)
 		return;
@@ -773,9 +803,6 @@ void xhci_free_stream_info(struct xhci_hcd *xhci,
 			cur_stream++) {
 		cur_ring = stream_info->stream_rings[cur_stream];
 		if (cur_ring) {
-			addr = cur_ring->first_seg->dma;
-			radix_tree_delete(&stream_info->trb_address_map,
-					addr >> TRB_SEGMENT_SHIFT);
 			xhci_ring_free(xhci, cur_ring);
 			stream_info->stream_rings[cur_stream] = NULL;
 		}
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index c338741..b525cfc 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1334,6 +1334,7 @@ struct xhci_ring {
 	unsigned int		num_trbs_free_temp;
 	enum xhci_ring_type	type;
 	bool			last_td_was_short;
+	struct radix_tree_root	*trb_address_map;
 };
 
 struct xhci_erst_entry {
@@ -1702,6 +1703,7 @@ int xhci_endpoint_init(struct xhci_hcd *xhci, struct xhci_virt_device *virt_dev,
 void xhci_ring_free(struct xhci_hcd *xhci, struct xhci_ring *ring);
 int xhci_ring_expansion(struct xhci_hcd *xhci, struct xhci_ring *ring,
 				unsigned int num_trbs, gfp_t flags);
+int xhci_update_stream_ring(struct xhci_ring *ring, bool insert);
 void xhci_free_or_cache_endpoint_ring(struct xhci_hcd *xhci,
 		struct xhci_virt_device *virt_dev,
 		unsigned int ep_index);
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v3 2/6] uas: properly reinitialize in uas_eh_bus_reset_handler
       [not found] <1379071635-30701-1-git-send-email-kraxel@redhat.com>
@ 2013-09-13 11:27   ` Gerd Hoffmann
  2013-09-13 11:27   ` Gerd Hoffmann
                     ` (4 subsequent siblings)
  5 siblings, 0 replies; 16+ messages in thread
From: Gerd Hoffmann @ 2013-09-13 11:27 UTC (permalink / raw)
  To: linux-usb
  Cc: Gerd Hoffmann, Matthew Wilcox, Sarah Sharp, Matthew Dharm,
	Greg Kroah-Hartman, open list:USB ATTACHED SCSI,
	open list:USB MASS STORAGE...,
	open list

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 drivers/usb/storage/uas.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c
index d966b59..fc08ee9 100644
--- a/drivers/usb/storage/uas.c
+++ b/drivers/usb/storage/uas.c
@@ -85,6 +85,8 @@ static int uas_submit_urbs(struct scsi_cmnd *cmnd,
 				struct uas_dev_info *devinfo, gfp_t gfp);
 static void uas_do_work(struct work_struct *work);
 static int uas_try_complete(struct scsi_cmnd *cmnd, const char *caller);
+static void uas_configure_endpoints(struct uas_dev_info *devinfo);
+static void uas_free_streams(struct uas_dev_info *devinfo);
 
 static DECLARE_WORK(uas_work, uas_do_work);
 static DEFINE_SPINLOCK(uas_work_lock);
@@ -800,7 +802,10 @@ static int uas_eh_bus_reset_handler(struct scsi_cmnd *cmnd)
 	usb_kill_anchored_urbs(&devinfo->cmd_urbs);
 	usb_kill_anchored_urbs(&devinfo->sense_urbs);
 	usb_kill_anchored_urbs(&devinfo->data_urbs);
+	uas_free_streams(devinfo);
 	err = usb_reset_device(udev);
+	if (!err)
+		uas_configure_endpoints(devinfo);
 	devinfo->resetting = 0;
 
 	if (err) {
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v3 2/6] uas: properly reinitialize in uas_eh_bus_reset_handler
@ 2013-09-13 11:27   ` Gerd Hoffmann
  0 siblings, 0 replies; 16+ messages in thread
From: Gerd Hoffmann @ 2013-09-13 11:27 UTC (permalink / raw)
  To: linux-usb
  Cc: Gerd Hoffmann, Matthew Wilcox, Sarah Sharp, Matthew Dharm,
	Greg Kroah-Hartman, open list:USB ATTACHED SCSI,
	open list:USB MASS STORAGE...,
	open list

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 drivers/usb/storage/uas.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c
index d966b59..fc08ee9 100644
--- a/drivers/usb/storage/uas.c
+++ b/drivers/usb/storage/uas.c
@@ -85,6 +85,8 @@ static int uas_submit_urbs(struct scsi_cmnd *cmnd,
 				struct uas_dev_info *devinfo, gfp_t gfp);
 static void uas_do_work(struct work_struct *work);
 static int uas_try_complete(struct scsi_cmnd *cmnd, const char *caller);
+static void uas_configure_endpoints(struct uas_dev_info *devinfo);
+static void uas_free_streams(struct uas_dev_info *devinfo);
 
 static DECLARE_WORK(uas_work, uas_do_work);
 static DEFINE_SPINLOCK(uas_work_lock);
@@ -800,7 +802,10 @@ static int uas_eh_bus_reset_handler(struct scsi_cmnd *cmnd)
 	usb_kill_anchored_urbs(&devinfo->cmd_urbs);
 	usb_kill_anchored_urbs(&devinfo->sense_urbs);
 	usb_kill_anchored_urbs(&devinfo->data_urbs);
+	uas_free_streams(devinfo);
 	err = usb_reset_device(udev);
+	if (!err)
+		uas_configure_endpoints(devinfo);
 	devinfo->resetting = 0;
 
 	if (err) {
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v3 3/6] uas: make work list per-device
@ 2013-09-13 11:27   ` Gerd Hoffmann
  0 siblings, 0 replies; 16+ messages in thread
From: Gerd Hoffmann @ 2013-09-13 11:27 UTC (permalink / raw)
  To: linux-usb
  Cc: Gerd Hoffmann, Matthew Wilcox, Sarah Sharp, Matthew Dharm,
	Greg Kroah-Hartman, open list:USB ATTACHED SCSI,
	open list:USB MASS STORAGE...,
	open list

Simplifies locking, we'll protect the list with the device spin lock.
Also plugs races which can happen when two devices operate on the
global list.

While being at it rename the list head from "list" to "work", preparing
for the addition of a second list.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 drivers/usb/storage/uas.c | 106 +++++++++++++++++++---------------------------
 1 file changed, 44 insertions(+), 62 deletions(-)

diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c
index fc08ee9..3cf5a5f 100644
--- a/drivers/usb/storage/uas.c
+++ b/drivers/usb/storage/uas.c
@@ -51,6 +51,8 @@ struct uas_dev_info {
 	unsigned uas_sense_old:1;
 	struct scsi_cmnd *cmnd;
 	spinlock_t lock;
+	struct work_struct work;
+	struct list_head work_list;
 };
 
 enum {
@@ -77,7 +79,7 @@ struct uas_cmd_info {
 	struct urb *cmd_urb;
 	struct urb *data_in_urb;
 	struct urb *data_out_urb;
-	struct list_head list;
+	struct list_head work;
 };
 
 /* I hate forward declarations, but I actually have a loop */
@@ -88,10 +90,6 @@ static int uas_try_complete(struct scsi_cmnd *cmnd, const char *caller);
 static void uas_configure_endpoints(struct uas_dev_info *devinfo);
 static void uas_free_streams(struct uas_dev_info *devinfo);
 
-static DECLARE_WORK(uas_work, uas_do_work);
-static DEFINE_SPINLOCK(uas_work_lock);
-static LIST_HEAD(uas_work_list);
-
 static void uas_unlink_data_urbs(struct uas_dev_info *devinfo,
 				 struct uas_cmd_info *cmdinfo)
 {
@@ -118,75 +116,66 @@ static void uas_unlink_data_urbs(struct uas_dev_info *devinfo,
 
 static void uas_do_work(struct work_struct *work)
 {
+	struct uas_dev_info *devinfo =
+		container_of(work, struct uas_dev_info, work);
 	struct uas_cmd_info *cmdinfo;
 	struct uas_cmd_info *temp;
-	struct list_head list;
 	unsigned long flags;
 	int err;
 
-	spin_lock_irq(&uas_work_lock);
-	list_replace_init(&uas_work_list, &list);
-	spin_unlock_irq(&uas_work_lock);
-
-	list_for_each_entry_safe(cmdinfo, temp, &list, list) {
+	spin_lock_irqsave(&devinfo->lock, flags);
+	list_for_each_entry_safe(cmdinfo, temp, &devinfo->work_list, work) {
 		struct scsi_pointer *scp = (void *)cmdinfo;
-		struct scsi_cmnd *cmnd = container_of(scp,
-							struct scsi_cmnd, SCp);
-		struct uas_dev_info *devinfo = (void *)cmnd->device->hostdata;
-		spin_lock_irqsave(&devinfo->lock, flags);
+		struct scsi_cmnd *cmnd = container_of(scp, struct scsi_cmnd,
+						      SCp);
 		err = uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_ATOMIC);
-		if (!err)
+		if (!err) {
 			cmdinfo->state &= ~IS_IN_WORK_LIST;
-		spin_unlock_irqrestore(&devinfo->lock, flags);
-		if (err) {
-			list_del(&cmdinfo->list);
-			spin_lock_irq(&uas_work_lock);
-			list_add_tail(&cmdinfo->list, &uas_work_list);
-			spin_unlock_irq(&uas_work_lock);
-			schedule_work(&uas_work);
+			list_del(&cmdinfo->work);
+		} else {
+			schedule_work(&devinfo->work);
 		}
 	}
+	spin_unlock_irqrestore(&devinfo->lock, flags);
 }
 
 static void uas_abort_work(struct uas_dev_info *devinfo)
 {
 	struct uas_cmd_info *cmdinfo;
 	struct uas_cmd_info *temp;
-	struct list_head list;
 	unsigned long flags;
 
-	spin_lock_irq(&uas_work_lock);
-	list_replace_init(&uas_work_list, &list);
-	spin_unlock_irq(&uas_work_lock);
-
 	spin_lock_irqsave(&devinfo->lock, flags);
-	list_for_each_entry_safe(cmdinfo, temp, &list, list) {
+	list_for_each_entry_safe(cmdinfo, temp, &devinfo->work_list, work) {
 		struct scsi_pointer *scp = (void *)cmdinfo;
-		struct scsi_cmnd *cmnd = container_of(scp,
-							struct scsi_cmnd, SCp);
-		struct uas_dev_info *di = (void *)cmnd->device->hostdata;
-
-		if (di == devinfo) {
-			cmdinfo->state |= COMMAND_ABORTED;
-			cmdinfo->state &= ~IS_IN_WORK_LIST;
-			if (devinfo->resetting) {
-				/* uas_stat_cmplt() will not do that
-				 * when a device reset is in
-				 * progress */
-				cmdinfo->state &= ~COMMAND_INFLIGHT;
-			}
-			uas_try_complete(cmnd, __func__);
-		} else {
-			/* not our uas device, relink into list */
-			list_del(&cmdinfo->list);
-			spin_lock_irq(&uas_work_lock);
-			list_add_tail(&cmdinfo->list, &uas_work_list);
-			spin_unlock_irq(&uas_work_lock);
+		struct scsi_cmnd *cmnd = container_of(scp, struct scsi_cmnd,
+						      SCp);
+		cmdinfo->state |= COMMAND_ABORTED;
+		cmdinfo->state &= ~IS_IN_WORK_LIST;
+		if (devinfo->resetting) {
+			/* uas_stat_cmplt() will not do that
+			 * when a device reset is in
+			 * progress */
+			cmdinfo->state &= ~COMMAND_INFLIGHT;
 		}
+		uas_try_complete(cmnd, __func__);
+		list_del(&cmdinfo->work);
 	}
 	spin_unlock_irqrestore(&devinfo->lock, flags);
 }
 
+static void uas_add_work(struct uas_cmd_info *cmdinfo)
+{
+	struct scsi_pointer *scp = (void *)cmdinfo;
+	struct scsi_cmnd *cmnd = container_of(scp, struct scsi_cmnd, SCp);
+	struct uas_dev_info *devinfo = cmnd->device->hostdata;
+
+	WARN_ON(!spin_is_locked(&devinfo->lock));
+	list_add_tail(&cmdinfo->work, &devinfo->work_list);
+	cmdinfo->state |= IS_IN_WORK_LIST;
+	schedule_work(&devinfo->work);
+}
+
 static void uas_sense(struct urb *urb, struct scsi_cmnd *cmnd)
 {
 	struct sense_iu *sense_iu = urb->transfer_buffer;
@@ -288,11 +277,7 @@ static void uas_xfer_data(struct urb *urb, struct scsi_cmnd *cmnd,
 	cmdinfo->state |= direction | SUBMIT_STATUS_URB;
 	err = uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_ATOMIC);
 	if (err) {
-		spin_lock(&uas_work_lock);
-		list_add_tail(&cmdinfo->list, &uas_work_list);
-		cmdinfo->state |= IS_IN_WORK_LIST;
-		spin_unlock(&uas_work_lock);
-		schedule_work(&uas_work);
+		uas_add_work(cmdinfo);
 	}
 }
 
@@ -694,11 +679,7 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd,
 			spin_unlock_irqrestore(&devinfo->lock, flags);
 			return SCSI_MLQUEUE_DEVICE_BUSY;
 		}
-		spin_lock(&uas_work_lock);
-		list_add_tail(&cmdinfo->list, &uas_work_list);
-		cmdinfo->state |= IS_IN_WORK_LIST;
-		spin_unlock(&uas_work_lock);
-		schedule_work(&uas_work);
+		uas_add_work(cmdinfo);
 	}
 
 	spin_unlock_irqrestore(&devinfo->lock, flags);
@@ -764,10 +745,8 @@ static int uas_eh_abort_handler(struct scsi_cmnd *cmnd)
 	spin_lock_irqsave(&devinfo->lock, flags);
 	cmdinfo->state |= COMMAND_ABORTED;
 	if (cmdinfo->state & IS_IN_WORK_LIST) {
-		spin_lock(&uas_work_lock);
-		list_del(&cmdinfo->list);
+		list_del(&cmdinfo->work);
 		cmdinfo->state &= ~IS_IN_WORK_LIST;
-		spin_unlock(&uas_work_lock);
 	}
 	if (cmdinfo->state & COMMAND_INFLIGHT) {
 		spin_unlock_irqrestore(&devinfo->lock, flags);
@@ -1007,6 +986,8 @@ static int uas_probe(struct usb_interface *intf, const struct usb_device_id *id)
 	init_usb_anchor(&devinfo->sense_urbs);
 	init_usb_anchor(&devinfo->data_urbs);
 	spin_lock_init(&devinfo->lock);
+	INIT_WORK(&devinfo->work, uas_do_work);
+	INIT_LIST_HEAD(&devinfo->work_list);
 	uas_configure_endpoints(devinfo);
 
 	result = scsi_init_shared_tag_map(shost, devinfo->qdepth - 3);
@@ -1050,6 +1031,7 @@ static void uas_disconnect(struct usb_interface *intf)
 	struct uas_dev_info *devinfo = (void *)shost->hostdata[0];
 
 	devinfo->resetting = 1;
+	cancel_work_sync(&devinfo->work);
 	uas_abort_work(devinfo);
 	usb_kill_anchored_urbs(&devinfo->cmd_urbs);
 	usb_kill_anchored_urbs(&devinfo->sense_urbs);
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v3 3/6] uas: make work list per-device
@ 2013-09-13 11:27   ` Gerd Hoffmann
  0 siblings, 0 replies; 16+ messages in thread
From: Gerd Hoffmann @ 2013-09-13 11:27 UTC (permalink / raw)
  To: linux-usb-u79uwXL29TY76Z2rM5mHXA
  Cc: Gerd Hoffmann, Matthew Wilcox, Sarah Sharp, Matthew Dharm,
	Greg Kroah-Hartman, open list:USB ATTACHED SCSI,
	open list:USB MASS STORAGE...,
	open list

Simplifies locking, we'll protect the list with the device spin lock.
Also plugs races which can happen when two devices operate on the
global list.

While being at it rename the list head from "list" to "work", preparing
for the addition of a second list.

Signed-off-by: Gerd Hoffmann <kraxel-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
---
 drivers/usb/storage/uas.c | 106 +++++++++++++++++++---------------------------
 1 file changed, 44 insertions(+), 62 deletions(-)

diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c
index fc08ee9..3cf5a5f 100644
--- a/drivers/usb/storage/uas.c
+++ b/drivers/usb/storage/uas.c
@@ -51,6 +51,8 @@ struct uas_dev_info {
 	unsigned uas_sense_old:1;
 	struct scsi_cmnd *cmnd;
 	spinlock_t lock;
+	struct work_struct work;
+	struct list_head work_list;
 };
 
 enum {
@@ -77,7 +79,7 @@ struct uas_cmd_info {
 	struct urb *cmd_urb;
 	struct urb *data_in_urb;
 	struct urb *data_out_urb;
-	struct list_head list;
+	struct list_head work;
 };
 
 /* I hate forward declarations, but I actually have a loop */
@@ -88,10 +90,6 @@ static int uas_try_complete(struct scsi_cmnd *cmnd, const char *caller);
 static void uas_configure_endpoints(struct uas_dev_info *devinfo);
 static void uas_free_streams(struct uas_dev_info *devinfo);
 
-static DECLARE_WORK(uas_work, uas_do_work);
-static DEFINE_SPINLOCK(uas_work_lock);
-static LIST_HEAD(uas_work_list);
-
 static void uas_unlink_data_urbs(struct uas_dev_info *devinfo,
 				 struct uas_cmd_info *cmdinfo)
 {
@@ -118,75 +116,66 @@ static void uas_unlink_data_urbs(struct uas_dev_info *devinfo,
 
 static void uas_do_work(struct work_struct *work)
 {
+	struct uas_dev_info *devinfo =
+		container_of(work, struct uas_dev_info, work);
 	struct uas_cmd_info *cmdinfo;
 	struct uas_cmd_info *temp;
-	struct list_head list;
 	unsigned long flags;
 	int err;
 
-	spin_lock_irq(&uas_work_lock);
-	list_replace_init(&uas_work_list, &list);
-	spin_unlock_irq(&uas_work_lock);
-
-	list_for_each_entry_safe(cmdinfo, temp, &list, list) {
+	spin_lock_irqsave(&devinfo->lock, flags);
+	list_for_each_entry_safe(cmdinfo, temp, &devinfo->work_list, work) {
 		struct scsi_pointer *scp = (void *)cmdinfo;
-		struct scsi_cmnd *cmnd = container_of(scp,
-							struct scsi_cmnd, SCp);
-		struct uas_dev_info *devinfo = (void *)cmnd->device->hostdata;
-		spin_lock_irqsave(&devinfo->lock, flags);
+		struct scsi_cmnd *cmnd = container_of(scp, struct scsi_cmnd,
+						      SCp);
 		err = uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_ATOMIC);
-		if (!err)
+		if (!err) {
 			cmdinfo->state &= ~IS_IN_WORK_LIST;
-		spin_unlock_irqrestore(&devinfo->lock, flags);
-		if (err) {
-			list_del(&cmdinfo->list);
-			spin_lock_irq(&uas_work_lock);
-			list_add_tail(&cmdinfo->list, &uas_work_list);
-			spin_unlock_irq(&uas_work_lock);
-			schedule_work(&uas_work);
+			list_del(&cmdinfo->work);
+		} else {
+			schedule_work(&devinfo->work);
 		}
 	}
+	spin_unlock_irqrestore(&devinfo->lock, flags);
 }
 
 static void uas_abort_work(struct uas_dev_info *devinfo)
 {
 	struct uas_cmd_info *cmdinfo;
 	struct uas_cmd_info *temp;
-	struct list_head list;
 	unsigned long flags;
 
-	spin_lock_irq(&uas_work_lock);
-	list_replace_init(&uas_work_list, &list);
-	spin_unlock_irq(&uas_work_lock);
-
 	spin_lock_irqsave(&devinfo->lock, flags);
-	list_for_each_entry_safe(cmdinfo, temp, &list, list) {
+	list_for_each_entry_safe(cmdinfo, temp, &devinfo->work_list, work) {
 		struct scsi_pointer *scp = (void *)cmdinfo;
-		struct scsi_cmnd *cmnd = container_of(scp,
-							struct scsi_cmnd, SCp);
-		struct uas_dev_info *di = (void *)cmnd->device->hostdata;
-
-		if (di == devinfo) {
-			cmdinfo->state |= COMMAND_ABORTED;
-			cmdinfo->state &= ~IS_IN_WORK_LIST;
-			if (devinfo->resetting) {
-				/* uas_stat_cmplt() will not do that
-				 * when a device reset is in
-				 * progress */
-				cmdinfo->state &= ~COMMAND_INFLIGHT;
-			}
-			uas_try_complete(cmnd, __func__);
-		} else {
-			/* not our uas device, relink into list */
-			list_del(&cmdinfo->list);
-			spin_lock_irq(&uas_work_lock);
-			list_add_tail(&cmdinfo->list, &uas_work_list);
-			spin_unlock_irq(&uas_work_lock);
+		struct scsi_cmnd *cmnd = container_of(scp, struct scsi_cmnd,
+						      SCp);
+		cmdinfo->state |= COMMAND_ABORTED;
+		cmdinfo->state &= ~IS_IN_WORK_LIST;
+		if (devinfo->resetting) {
+			/* uas_stat_cmplt() will not do that
+			 * when a device reset is in
+			 * progress */
+			cmdinfo->state &= ~COMMAND_INFLIGHT;
 		}
+		uas_try_complete(cmnd, __func__);
+		list_del(&cmdinfo->work);
 	}
 	spin_unlock_irqrestore(&devinfo->lock, flags);
 }
 
+static void uas_add_work(struct uas_cmd_info *cmdinfo)
+{
+	struct scsi_pointer *scp = (void *)cmdinfo;
+	struct scsi_cmnd *cmnd = container_of(scp, struct scsi_cmnd, SCp);
+	struct uas_dev_info *devinfo = cmnd->device->hostdata;
+
+	WARN_ON(!spin_is_locked(&devinfo->lock));
+	list_add_tail(&cmdinfo->work, &devinfo->work_list);
+	cmdinfo->state |= IS_IN_WORK_LIST;
+	schedule_work(&devinfo->work);
+}
+
 static void uas_sense(struct urb *urb, struct scsi_cmnd *cmnd)
 {
 	struct sense_iu *sense_iu = urb->transfer_buffer;
@@ -288,11 +277,7 @@ static void uas_xfer_data(struct urb *urb, struct scsi_cmnd *cmnd,
 	cmdinfo->state |= direction | SUBMIT_STATUS_URB;
 	err = uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_ATOMIC);
 	if (err) {
-		spin_lock(&uas_work_lock);
-		list_add_tail(&cmdinfo->list, &uas_work_list);
-		cmdinfo->state |= IS_IN_WORK_LIST;
-		spin_unlock(&uas_work_lock);
-		schedule_work(&uas_work);
+		uas_add_work(cmdinfo);
 	}
 }
 
@@ -694,11 +679,7 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd,
 			spin_unlock_irqrestore(&devinfo->lock, flags);
 			return SCSI_MLQUEUE_DEVICE_BUSY;
 		}
-		spin_lock(&uas_work_lock);
-		list_add_tail(&cmdinfo->list, &uas_work_list);
-		cmdinfo->state |= IS_IN_WORK_LIST;
-		spin_unlock(&uas_work_lock);
-		schedule_work(&uas_work);
+		uas_add_work(cmdinfo);
 	}
 
 	spin_unlock_irqrestore(&devinfo->lock, flags);
@@ -764,10 +745,8 @@ static int uas_eh_abort_handler(struct scsi_cmnd *cmnd)
 	spin_lock_irqsave(&devinfo->lock, flags);
 	cmdinfo->state |= COMMAND_ABORTED;
 	if (cmdinfo->state & IS_IN_WORK_LIST) {
-		spin_lock(&uas_work_lock);
-		list_del(&cmdinfo->list);
+		list_del(&cmdinfo->work);
 		cmdinfo->state &= ~IS_IN_WORK_LIST;
-		spin_unlock(&uas_work_lock);
 	}
 	if (cmdinfo->state & COMMAND_INFLIGHT) {
 		spin_unlock_irqrestore(&devinfo->lock, flags);
@@ -1007,6 +986,8 @@ static int uas_probe(struct usb_interface *intf, const struct usb_device_id *id)
 	init_usb_anchor(&devinfo->sense_urbs);
 	init_usb_anchor(&devinfo->data_urbs);
 	spin_lock_init(&devinfo->lock);
+	INIT_WORK(&devinfo->work, uas_do_work);
+	INIT_LIST_HEAD(&devinfo->work_list);
 	uas_configure_endpoints(devinfo);
 
 	result = scsi_init_shared_tag_map(shost, devinfo->qdepth - 3);
@@ -1050,6 +1031,7 @@ static void uas_disconnect(struct usb_interface *intf)
 	struct uas_dev_info *devinfo = (void *)shost->hostdata[0];
 
 	devinfo->resetting = 1;
+	cancel_work_sync(&devinfo->work);
 	uas_abort_work(devinfo);
 	usb_kill_anchored_urbs(&devinfo->cmd_urbs);
 	usb_kill_anchored_urbs(&devinfo->sense_urbs);
-- 
1.8.3.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v3 4/6] uas: add dead request list
       [not found] <1379071635-30701-1-git-send-email-kraxel@redhat.com>
@ 2013-09-13 11:27   ` Gerd Hoffmann
  2013-09-13 11:27   ` Gerd Hoffmann
                     ` (4 subsequent siblings)
  5 siblings, 0 replies; 16+ messages in thread
From: Gerd Hoffmann @ 2013-09-13 11:27 UTC (permalink / raw)
  To: linux-usb
  Cc: Gerd Hoffmann, Matthew Wilcox, Sarah Sharp, Matthew Dharm,
	Greg Kroah-Hartman, open list:USB ATTACHED SCSI,
	open list:USB MASS STORAGE...,
	open list

This patch adds a new list where all requests which are canceled are
added to, so we don't loose them.  Then, after killing all inflight
urbs on bus reset (and disconnect) we'll walk over the list and clean
them up.

Without this we can end up with aborted requests lingering around in
case of status pipe transfer errors.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 drivers/usb/storage/uas.c | 50 +++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 42 insertions(+), 8 deletions(-)

diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c
index 3cf5a5f..f049038 100644
--- a/drivers/usb/storage/uas.c
+++ b/drivers/usb/storage/uas.c
@@ -53,6 +53,7 @@ struct uas_dev_info {
 	spinlock_t lock;
 	struct work_struct work;
 	struct list_head work_list;
+	struct list_head dead_list;
 };
 
 enum {
@@ -80,6 +81,7 @@ struct uas_cmd_info {
 	struct urb *data_in_urb;
 	struct urb *data_out_urb;
 	struct list_head work;
+	struct list_head dead;
 };
 
 /* I hate forward declarations, but I actually have a loop */
@@ -89,6 +91,7 @@ static void uas_do_work(struct work_struct *work);
 static int uas_try_complete(struct scsi_cmnd *cmnd, const char *caller);
 static void uas_configure_endpoints(struct uas_dev_info *devinfo);
 static void uas_free_streams(struct uas_dev_info *devinfo);
+static void uas_log_cmd_state(struct scsi_cmnd *cmnd, const char *caller);
 
 static void uas_unlink_data_urbs(struct uas_dev_info *devinfo,
 				 struct uas_cmd_info *cmdinfo)
@@ -150,16 +153,12 @@ static void uas_abort_work(struct uas_dev_info *devinfo)
 		struct scsi_pointer *scp = (void *)cmdinfo;
 		struct scsi_cmnd *cmnd = container_of(scp, struct scsi_cmnd,
 						      SCp);
+		uas_log_cmd_state(cmnd, __func__);
+		WARN_ON(cmdinfo->state & COMMAND_ABORTED);
 		cmdinfo->state |= COMMAND_ABORTED;
 		cmdinfo->state &= ~IS_IN_WORK_LIST;
-		if (devinfo->resetting) {
-			/* uas_stat_cmplt() will not do that
-			 * when a device reset is in
-			 * progress */
-			cmdinfo->state &= ~COMMAND_INFLIGHT;
-		}
-		uas_try_complete(cmnd, __func__);
 		list_del(&cmdinfo->work);
+		list_add_tail(&cmdinfo->dead, &devinfo->dead_list);
 	}
 	spin_unlock_irqrestore(&devinfo->lock, flags);
 }
@@ -176,6 +175,28 @@ static void uas_add_work(struct uas_cmd_info *cmdinfo)
 	schedule_work(&devinfo->work);
 }
 
+static void uas_zap_dead(struct uas_dev_info *devinfo)
+{
+	struct uas_cmd_info *cmdinfo;
+	struct uas_cmd_info *temp;
+	unsigned long flags;
+
+	spin_lock_irqsave(&devinfo->lock, flags);
+	list_for_each_entry_safe(cmdinfo, temp, &devinfo->dead_list, dead) {
+		struct scsi_pointer *scp = (void *)cmdinfo;
+		struct scsi_cmnd *cmnd = container_of(scp, struct scsi_cmnd,
+						      SCp);
+		uas_log_cmd_state(cmnd, __func__);
+		WARN_ON(!(cmdinfo->state & COMMAND_ABORTED));
+		/* all urbs are killed, clear inflight bits */
+		cmdinfo->state &= ~(COMMAND_INFLIGHT |
+				    DATA_IN_URB_INFLIGHT |
+				    DATA_OUT_URB_INFLIGHT);
+		uas_try_complete(cmnd, __func__);
+	}
+	spin_unlock_irqrestore(&devinfo->lock, flags);
+}
+
 static void uas_sense(struct urb *urb, struct scsi_cmnd *cmnd)
 {
 	struct sense_iu *sense_iu = urb->transfer_buffer;
@@ -263,6 +284,7 @@ static int uas_try_complete(struct scsi_cmnd *cmnd, const char *caller)
 	if (cmdinfo->state & COMMAND_ABORTED) {
 		scmd_printk(KERN_INFO, cmnd, "abort completed\n");
 		cmnd->result = DID_ABORT << 16;
+		list_del(&cmdinfo->dead);
 	}
 	cmnd->scsi_done(cmnd);
 	return 0;
@@ -292,7 +314,13 @@ static void uas_stat_cmplt(struct urb *urb)
 	u16 tag;
 
 	if (urb->status) {
-		dev_err(&urb->dev->dev, "URB BAD STATUS %d\n", urb->status);
+		if (urb->status == -ENOENT) {
+			dev_err(&urb->dev->dev, "stat urb: killed, stream %d\n",
+				urb->stream_id);
+		} else {
+			dev_err(&urb->dev->dev, "stat urb: status %d\n",
+				urb->status);
+		}
 		usb_free_urb(urb);
 		return;
 	}
@@ -743,7 +771,9 @@ static int uas_eh_abort_handler(struct scsi_cmnd *cmnd)
 
 	uas_log_cmd_state(cmnd, __func__);
 	spin_lock_irqsave(&devinfo->lock, flags);
+	WARN_ON(cmdinfo->state & COMMAND_ABORTED);
 	cmdinfo->state |= COMMAND_ABORTED;
+	list_add_tail(&cmdinfo->dead, &devinfo->dead_list);
 	if (cmdinfo->state & IS_IN_WORK_LIST) {
 		list_del(&cmdinfo->work);
 		cmdinfo->state &= ~IS_IN_WORK_LIST;
@@ -776,11 +806,13 @@ static int uas_eh_bus_reset_handler(struct scsi_cmnd *cmnd)
 	struct usb_device *udev = devinfo->udev;
 	int err;
 
+	shost_printk(KERN_INFO, sdev->host, "%s start\n", __func__);
 	devinfo->resetting = 1;
 	uas_abort_work(devinfo);
 	usb_kill_anchored_urbs(&devinfo->cmd_urbs);
 	usb_kill_anchored_urbs(&devinfo->sense_urbs);
 	usb_kill_anchored_urbs(&devinfo->data_urbs);
+	uas_zap_dead(devinfo);
 	uas_free_streams(devinfo);
 	err = usb_reset_device(udev);
 	if (!err)
@@ -988,6 +1020,7 @@ static int uas_probe(struct usb_interface *intf, const struct usb_device_id *id)
 	spin_lock_init(&devinfo->lock);
 	INIT_WORK(&devinfo->work, uas_do_work);
 	INIT_LIST_HEAD(&devinfo->work_list);
+	INIT_LIST_HEAD(&devinfo->dead_list);
 	uas_configure_endpoints(devinfo);
 
 	result = scsi_init_shared_tag_map(shost, devinfo->qdepth - 3);
@@ -1036,6 +1069,7 @@ static void uas_disconnect(struct usb_interface *intf)
 	usb_kill_anchored_urbs(&devinfo->cmd_urbs);
 	usb_kill_anchored_urbs(&devinfo->sense_urbs);
 	usb_kill_anchored_urbs(&devinfo->data_urbs);
+	uas_zap_dead(devinfo);
 	scsi_remove_host(shost);
 	uas_free_streams(devinfo);
 	kfree(devinfo);
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v3 4/6] uas: add dead request list
@ 2013-09-13 11:27   ` Gerd Hoffmann
  0 siblings, 0 replies; 16+ messages in thread
From: Gerd Hoffmann @ 2013-09-13 11:27 UTC (permalink / raw)
  To: linux-usb
  Cc: Gerd Hoffmann, Matthew Wilcox, Sarah Sharp, Matthew Dharm,
	Greg Kroah-Hartman, open list:USB ATTACHED SCSI,
	open list:USB MASS STORAGE...,
	open list

This patch adds a new list where all requests which are canceled are
added to, so we don't loose them.  Then, after killing all inflight
urbs on bus reset (and disconnect) we'll walk over the list and clean
them up.

Without this we can end up with aborted requests lingering around in
case of status pipe transfer errors.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 drivers/usb/storage/uas.c | 50 +++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 42 insertions(+), 8 deletions(-)

diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c
index 3cf5a5f..f049038 100644
--- a/drivers/usb/storage/uas.c
+++ b/drivers/usb/storage/uas.c
@@ -53,6 +53,7 @@ struct uas_dev_info {
 	spinlock_t lock;
 	struct work_struct work;
 	struct list_head work_list;
+	struct list_head dead_list;
 };
 
 enum {
@@ -80,6 +81,7 @@ struct uas_cmd_info {
 	struct urb *data_in_urb;
 	struct urb *data_out_urb;
 	struct list_head work;
+	struct list_head dead;
 };
 
 /* I hate forward declarations, but I actually have a loop */
@@ -89,6 +91,7 @@ static void uas_do_work(struct work_struct *work);
 static int uas_try_complete(struct scsi_cmnd *cmnd, const char *caller);
 static void uas_configure_endpoints(struct uas_dev_info *devinfo);
 static void uas_free_streams(struct uas_dev_info *devinfo);
+static void uas_log_cmd_state(struct scsi_cmnd *cmnd, const char *caller);
 
 static void uas_unlink_data_urbs(struct uas_dev_info *devinfo,
 				 struct uas_cmd_info *cmdinfo)
@@ -150,16 +153,12 @@ static void uas_abort_work(struct uas_dev_info *devinfo)
 		struct scsi_pointer *scp = (void *)cmdinfo;
 		struct scsi_cmnd *cmnd = container_of(scp, struct scsi_cmnd,
 						      SCp);
+		uas_log_cmd_state(cmnd, __func__);
+		WARN_ON(cmdinfo->state & COMMAND_ABORTED);
 		cmdinfo->state |= COMMAND_ABORTED;
 		cmdinfo->state &= ~IS_IN_WORK_LIST;
-		if (devinfo->resetting) {
-			/* uas_stat_cmplt() will not do that
-			 * when a device reset is in
-			 * progress */
-			cmdinfo->state &= ~COMMAND_INFLIGHT;
-		}
-		uas_try_complete(cmnd, __func__);
 		list_del(&cmdinfo->work);
+		list_add_tail(&cmdinfo->dead, &devinfo->dead_list);
 	}
 	spin_unlock_irqrestore(&devinfo->lock, flags);
 }
@@ -176,6 +175,28 @@ static void uas_add_work(struct uas_cmd_info *cmdinfo)
 	schedule_work(&devinfo->work);
 }
 
+static void uas_zap_dead(struct uas_dev_info *devinfo)
+{
+	struct uas_cmd_info *cmdinfo;
+	struct uas_cmd_info *temp;
+	unsigned long flags;
+
+	spin_lock_irqsave(&devinfo->lock, flags);
+	list_for_each_entry_safe(cmdinfo, temp, &devinfo->dead_list, dead) {
+		struct scsi_pointer *scp = (void *)cmdinfo;
+		struct scsi_cmnd *cmnd = container_of(scp, struct scsi_cmnd,
+						      SCp);
+		uas_log_cmd_state(cmnd, __func__);
+		WARN_ON(!(cmdinfo->state & COMMAND_ABORTED));
+		/* all urbs are killed, clear inflight bits */
+		cmdinfo->state &= ~(COMMAND_INFLIGHT |
+				    DATA_IN_URB_INFLIGHT |
+				    DATA_OUT_URB_INFLIGHT);
+		uas_try_complete(cmnd, __func__);
+	}
+	spin_unlock_irqrestore(&devinfo->lock, flags);
+}
+
 static void uas_sense(struct urb *urb, struct scsi_cmnd *cmnd)
 {
 	struct sense_iu *sense_iu = urb->transfer_buffer;
@@ -263,6 +284,7 @@ static int uas_try_complete(struct scsi_cmnd *cmnd, const char *caller)
 	if (cmdinfo->state & COMMAND_ABORTED) {
 		scmd_printk(KERN_INFO, cmnd, "abort completed\n");
 		cmnd->result = DID_ABORT << 16;
+		list_del(&cmdinfo->dead);
 	}
 	cmnd->scsi_done(cmnd);
 	return 0;
@@ -292,7 +314,13 @@ static void uas_stat_cmplt(struct urb *urb)
 	u16 tag;
 
 	if (urb->status) {
-		dev_err(&urb->dev->dev, "URB BAD STATUS %d\n", urb->status);
+		if (urb->status == -ENOENT) {
+			dev_err(&urb->dev->dev, "stat urb: killed, stream %d\n",
+				urb->stream_id);
+		} else {
+			dev_err(&urb->dev->dev, "stat urb: status %d\n",
+				urb->status);
+		}
 		usb_free_urb(urb);
 		return;
 	}
@@ -743,7 +771,9 @@ static int uas_eh_abort_handler(struct scsi_cmnd *cmnd)
 
 	uas_log_cmd_state(cmnd, __func__);
 	spin_lock_irqsave(&devinfo->lock, flags);
+	WARN_ON(cmdinfo->state & COMMAND_ABORTED);
 	cmdinfo->state |= COMMAND_ABORTED;
+	list_add_tail(&cmdinfo->dead, &devinfo->dead_list);
 	if (cmdinfo->state & IS_IN_WORK_LIST) {
 		list_del(&cmdinfo->work);
 		cmdinfo->state &= ~IS_IN_WORK_LIST;
@@ -776,11 +806,13 @@ static int uas_eh_bus_reset_handler(struct scsi_cmnd *cmnd)
 	struct usb_device *udev = devinfo->udev;
 	int err;
 
+	shost_printk(KERN_INFO, sdev->host, "%s start\n", __func__);
 	devinfo->resetting = 1;
 	uas_abort_work(devinfo);
 	usb_kill_anchored_urbs(&devinfo->cmd_urbs);
 	usb_kill_anchored_urbs(&devinfo->sense_urbs);
 	usb_kill_anchored_urbs(&devinfo->data_urbs);
+	uas_zap_dead(devinfo);
 	uas_free_streams(devinfo);
 	err = usb_reset_device(udev);
 	if (!err)
@@ -988,6 +1020,7 @@ static int uas_probe(struct usb_interface *intf, const struct usb_device_id *id)
 	spin_lock_init(&devinfo->lock);
 	INIT_WORK(&devinfo->work, uas_do_work);
 	INIT_LIST_HEAD(&devinfo->work_list);
+	INIT_LIST_HEAD(&devinfo->dead_list);
 	uas_configure_endpoints(devinfo);
 
 	result = scsi_init_shared_tag_map(shost, devinfo->qdepth - 3);
@@ -1036,6 +1069,7 @@ static void uas_disconnect(struct usb_interface *intf)
 	usb_kill_anchored_urbs(&devinfo->cmd_urbs);
 	usb_kill_anchored_urbs(&devinfo->sense_urbs);
 	usb_kill_anchored_urbs(&devinfo->data_urbs);
+	uas_zap_dead(devinfo);
 	scsi_remove_host(shost);
 	uas_free_streams(devinfo);
 	kfree(devinfo);
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v3 5/6] uas: replace BUG_ON() + WARN_ON() with WARN_ON_ONCE()
       [not found] <1379071635-30701-1-git-send-email-kraxel@redhat.com>
@ 2013-09-13 11:27   ` Gerd Hoffmann
  2013-09-13 11:27   ` Gerd Hoffmann
                     ` (4 subsequent siblings)
  5 siblings, 0 replies; 16+ messages in thread
From: Gerd Hoffmann @ 2013-09-13 11:27 UTC (permalink / raw)
  To: linux-usb
  Cc: Gerd Hoffmann, Matthew Wilcox, Sarah Sharp, Matthew Dharm,
	Greg Kroah-Hartman, open list:USB ATTACHED SCSI,
	open list:USB MASS STORAGE...,
	open list

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 drivers/usb/storage/uas.c | 19 ++++++++++---------
 1 file changed, 10 insertions(+), 9 deletions(-)

diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c
index f049038..046eedf 100644
--- a/drivers/usb/storage/uas.c
+++ b/drivers/usb/storage/uas.c
@@ -154,7 +154,7 @@ static void uas_abort_work(struct uas_dev_info *devinfo)
 		struct scsi_cmnd *cmnd = container_of(scp, struct scsi_cmnd,
 						      SCp);
 		uas_log_cmd_state(cmnd, __func__);
-		WARN_ON(cmdinfo->state & COMMAND_ABORTED);
+		WARN_ON_ONCE(cmdinfo->state & COMMAND_ABORTED);
 		cmdinfo->state |= COMMAND_ABORTED;
 		cmdinfo->state &= ~IS_IN_WORK_LIST;
 		list_del(&cmdinfo->work);
@@ -169,7 +169,7 @@ static void uas_add_work(struct uas_cmd_info *cmdinfo)
 	struct scsi_cmnd *cmnd = container_of(scp, struct scsi_cmnd, SCp);
 	struct uas_dev_info *devinfo = cmnd->device->hostdata;
 
-	WARN_ON(!spin_is_locked(&devinfo->lock));
+	WARN_ON_ONCE(!spin_is_locked(&devinfo->lock));
 	list_add_tail(&cmdinfo->work, &devinfo->work_list);
 	cmdinfo->state |= IS_IN_WORK_LIST;
 	schedule_work(&devinfo->work);
@@ -187,7 +187,7 @@ static void uas_zap_dead(struct uas_dev_info *devinfo)
 		struct scsi_cmnd *cmnd = container_of(scp, struct scsi_cmnd,
 						      SCp);
 		uas_log_cmd_state(cmnd, __func__);
-		WARN_ON(!(cmdinfo->state & COMMAND_ABORTED));
+		WARN_ON_ONCE(!(cmdinfo->state & COMMAND_ABORTED));
 		/* all urbs are killed, clear inflight bits */
 		cmdinfo->state &= ~(COMMAND_INFLIGHT |
 				    DATA_IN_URB_INFLIGHT |
@@ -271,13 +271,13 @@ static int uas_try_complete(struct scsi_cmnd *cmnd, const char *caller)
 	struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
 	struct uas_dev_info *devinfo = (void *)cmnd->device->hostdata;
 
-	WARN_ON(!spin_is_locked(&devinfo->lock));
+	WARN_ON_ONCE(!spin_is_locked(&devinfo->lock));
 	if (cmdinfo->state & (COMMAND_INFLIGHT |
 			      DATA_IN_URB_INFLIGHT |
 			      DATA_OUT_URB_INFLIGHT |
 			      UNLINK_DATA_URBS))
 		return -EBUSY;
-	BUG_ON(cmdinfo->state & COMMAND_COMPLETED);
+	WARN_ON_ONCE(cmdinfo->state & COMMAND_COMPLETED);
 	cmdinfo->state |= COMMAND_COMPLETED;
 	usb_free_urb(cmdinfo->data_in_urb);
 	usb_free_urb(cmdinfo->data_out_urb);
@@ -398,8 +398,9 @@ static void uas_data_cmplt(struct urb *urb)
 		sdb = scsi_out(cmnd);
 		cmdinfo->state &= ~DATA_OUT_URB_INFLIGHT;
 	}
-	BUG_ON(sdb == NULL);
-	if (urb->status) {
+	if (sdb == NULL) {
+		WARN_ON_ONCE(1);
+	} else if (urb->status) {
 		/* error: no data transfered */
 		sdb->resid = sdb->length;
 	} else {
@@ -573,7 +574,7 @@ static int uas_submit_urbs(struct scsi_cmnd *cmnd,
 	struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
 	int err;
 
-	WARN_ON(!spin_is_locked(&devinfo->lock));
+	WARN_ON_ONCE(!spin_is_locked(&devinfo->lock));
 	if (cmdinfo->state & SUBMIT_STATUS_URB) {
 		err = uas_submit_sense_urb(cmnd->device->host, gfp,
 					   cmdinfo->stream);
@@ -771,7 +772,7 @@ static int uas_eh_abort_handler(struct scsi_cmnd *cmnd)
 
 	uas_log_cmd_state(cmnd, __func__);
 	spin_lock_irqsave(&devinfo->lock, flags);
-	WARN_ON(cmdinfo->state & COMMAND_ABORTED);
+	WARN_ON_ONCE(cmdinfo->state & COMMAND_ABORTED);
 	cmdinfo->state |= COMMAND_ABORTED;
 	list_add_tail(&cmdinfo->dead, &devinfo->dead_list);
 	if (cmdinfo->state & IS_IN_WORK_LIST) {
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v3 5/6] uas: replace BUG_ON() + WARN_ON() with WARN_ON_ONCE()
@ 2013-09-13 11:27   ` Gerd Hoffmann
  0 siblings, 0 replies; 16+ messages in thread
From: Gerd Hoffmann @ 2013-09-13 11:27 UTC (permalink / raw)
  To: linux-usb
  Cc: Gerd Hoffmann, Matthew Wilcox, Sarah Sharp, Matthew Dharm,
	Greg Kroah-Hartman, open list:USB ATTACHED SCSI,
	open list:USB MASS STORAGE...,
	open list

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 drivers/usb/storage/uas.c | 19 ++++++++++---------
 1 file changed, 10 insertions(+), 9 deletions(-)

diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c
index f049038..046eedf 100644
--- a/drivers/usb/storage/uas.c
+++ b/drivers/usb/storage/uas.c
@@ -154,7 +154,7 @@ static void uas_abort_work(struct uas_dev_info *devinfo)
 		struct scsi_cmnd *cmnd = container_of(scp, struct scsi_cmnd,
 						      SCp);
 		uas_log_cmd_state(cmnd, __func__);
-		WARN_ON(cmdinfo->state & COMMAND_ABORTED);
+		WARN_ON_ONCE(cmdinfo->state & COMMAND_ABORTED);
 		cmdinfo->state |= COMMAND_ABORTED;
 		cmdinfo->state &= ~IS_IN_WORK_LIST;
 		list_del(&cmdinfo->work);
@@ -169,7 +169,7 @@ static void uas_add_work(struct uas_cmd_info *cmdinfo)
 	struct scsi_cmnd *cmnd = container_of(scp, struct scsi_cmnd, SCp);
 	struct uas_dev_info *devinfo = cmnd->device->hostdata;
 
-	WARN_ON(!spin_is_locked(&devinfo->lock));
+	WARN_ON_ONCE(!spin_is_locked(&devinfo->lock));
 	list_add_tail(&cmdinfo->work, &devinfo->work_list);
 	cmdinfo->state |= IS_IN_WORK_LIST;
 	schedule_work(&devinfo->work);
@@ -187,7 +187,7 @@ static void uas_zap_dead(struct uas_dev_info *devinfo)
 		struct scsi_cmnd *cmnd = container_of(scp, struct scsi_cmnd,
 						      SCp);
 		uas_log_cmd_state(cmnd, __func__);
-		WARN_ON(!(cmdinfo->state & COMMAND_ABORTED));
+		WARN_ON_ONCE(!(cmdinfo->state & COMMAND_ABORTED));
 		/* all urbs are killed, clear inflight bits */
 		cmdinfo->state &= ~(COMMAND_INFLIGHT |
 				    DATA_IN_URB_INFLIGHT |
@@ -271,13 +271,13 @@ static int uas_try_complete(struct scsi_cmnd *cmnd, const char *caller)
 	struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
 	struct uas_dev_info *devinfo = (void *)cmnd->device->hostdata;
 
-	WARN_ON(!spin_is_locked(&devinfo->lock));
+	WARN_ON_ONCE(!spin_is_locked(&devinfo->lock));
 	if (cmdinfo->state & (COMMAND_INFLIGHT |
 			      DATA_IN_URB_INFLIGHT |
 			      DATA_OUT_URB_INFLIGHT |
 			      UNLINK_DATA_URBS))
 		return -EBUSY;
-	BUG_ON(cmdinfo->state & COMMAND_COMPLETED);
+	WARN_ON_ONCE(cmdinfo->state & COMMAND_COMPLETED);
 	cmdinfo->state |= COMMAND_COMPLETED;
 	usb_free_urb(cmdinfo->data_in_urb);
 	usb_free_urb(cmdinfo->data_out_urb);
@@ -398,8 +398,9 @@ static void uas_data_cmplt(struct urb *urb)
 		sdb = scsi_out(cmnd);
 		cmdinfo->state &= ~DATA_OUT_URB_INFLIGHT;
 	}
-	BUG_ON(sdb == NULL);
-	if (urb->status) {
+	if (sdb == NULL) {
+		WARN_ON_ONCE(1);
+	} else if (urb->status) {
 		/* error: no data transfered */
 		sdb->resid = sdb->length;
 	} else {
@@ -573,7 +574,7 @@ static int uas_submit_urbs(struct scsi_cmnd *cmnd,
 	struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
 	int err;
 
-	WARN_ON(!spin_is_locked(&devinfo->lock));
+	WARN_ON_ONCE(!spin_is_locked(&devinfo->lock));
 	if (cmdinfo->state & SUBMIT_STATUS_URB) {
 		err = uas_submit_sense_urb(cmnd->device->host, gfp,
 					   cmdinfo->stream);
@@ -771,7 +772,7 @@ static int uas_eh_abort_handler(struct scsi_cmnd *cmnd)
 
 	uas_log_cmd_state(cmnd, __func__);
 	spin_lock_irqsave(&devinfo->lock, flags);
-	WARN_ON(cmdinfo->state & COMMAND_ABORTED);
+	WARN_ON_ONCE(cmdinfo->state & COMMAND_ABORTED);
 	cmdinfo->state |= COMMAND_ABORTED;
 	list_add_tail(&cmdinfo->dead, &devinfo->dead_list);
 	if (cmdinfo->state & IS_IN_WORK_LIST) {
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v3 6/6] uas: remove BROKEN
       [not found] <1379071635-30701-1-git-send-email-kraxel@redhat.com>
                   ` (4 preceding siblings ...)
  2013-09-13 11:27   ` Gerd Hoffmann
@ 2013-09-13 11:27 ` Gerd Hoffmann
  5 siblings, 0 replies; 16+ messages in thread
From: Gerd Hoffmann @ 2013-09-13 11:27 UTC (permalink / raw)
  To: linux-usb
  Cc: Gerd Hoffmann, Matthew Dharm, Greg Kroah-Hartman,
	open list:USB MASS STORAGE...,
	open list

xhci streams support is fixed, unblock usb attached scsi.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 drivers/usb/storage/Kconfig | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/usb/storage/Kconfig b/drivers/usb/storage/Kconfig
index 8470e1b..4761a28 100644
--- a/drivers/usb/storage/Kconfig
+++ b/drivers/usb/storage/Kconfig
@@ -202,7 +202,7 @@ config USB_STORAGE_ENE_UB6250
 
 config USB_UAS
 	tristate "USB Attached SCSI"
-	depends on SCSI && BROKEN
+	depends on SCSI
 	help
 	  The USB Attached SCSI protocol is supported by some USB
 	  storage devices.  It permits higher performance by supporting
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* Re: [PATCH v3 3/6] uas: make work list per-device
  2013-09-13 11:27   ` Gerd Hoffmann
@ 2013-09-17 20:30     ` Christoph Hellwig
  -1 siblings, 0 replies; 16+ messages in thread
From: Christoph Hellwig @ 2013-09-17 20:30 UTC (permalink / raw)
  To: Gerd Hoffmann
  Cc: linux-usb, Matthew Wilcox, Sarah Sharp, Matthew Dharm,
	Greg Kroah-Hartman, open list:USB ATTACHED SCSI,
	open list:USB MASS STORAGE...,
	open list

On Fri, Sep 13, 2013 at 01:27:12PM +0200, Gerd Hoffmann wrote:
> Simplifies locking, we'll protect the list with the device spin lock.
> Also plugs races which can happen when two devices operate on the
> global list.
> 
> While being at it rename the list head from "list" to "work", preparing
> for the addition of a second list.

Why do you even the list?  What would a ordered per-device workqueue not
provide?


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v3 3/6] uas: make work list per-device
@ 2013-09-17 20:30     ` Christoph Hellwig
  0 siblings, 0 replies; 16+ messages in thread
From: Christoph Hellwig @ 2013-09-17 20:30 UTC (permalink / raw)
  To: Gerd Hoffmann
  Cc: linux-usb, Matthew Wilcox, Sarah Sharp, Matthew Dharm,
	Greg Kroah-Hartman, open list:USB ATTACHED SCSI,
	open list:USB MASS STORAGE...,
	open list

On Fri, Sep 13, 2013 at 01:27:12PM +0200, Gerd Hoffmann wrote:
> Simplifies locking, we'll protect the list with the device spin lock.
> Also plugs races which can happen when two devices operate on the
> global list.
> 
> While being at it rename the list head from "list" to "work", preparing
> for the addition of a second list.

Why do you even the list?  What would a ordered per-device workqueue not
provide?

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v3 3/6] uas: make work list per-device
  2013-09-17 20:30     ` Christoph Hellwig
@ 2013-09-18  7:33       ` Gerd Hoffmann
  -1 siblings, 0 replies; 16+ messages in thread
From: Gerd Hoffmann @ 2013-09-18  7:33 UTC (permalink / raw)
  To: Christoph Hellwig
  Cc: linux-usb, Matthew Wilcox, Sarah Sharp, Matthew Dharm,
	Greg Kroah-Hartman, open list:USB ATTACHED SCSI,
	open list:USB MASS STORAGE...,
	open list

On Di, 2013-09-17 at 13:30 -0700, Christoph Hellwig wrote:
> On Fri, Sep 13, 2013 at 01:27:12PM +0200, Gerd Hoffmann wrote:
> > Simplifies locking, we'll protect the list with the device spin lock.
> > Also plugs races which can happen when two devices operate on the
> > global list.
> > 
> > While being at it rename the list head from "list" to "work", preparing
> > for the addition of a second list.
> 
> Why do you even the list?

The list was already there when I took over maintainance ...

> What would a ordered per-device workqueue not
> provide?

Had no reason to look into replacing the list with something else so
far.  Why do you suggest using a workqueue instead?

Note that the list is not used in a typical request workflow.  Only in
case queuing an usb urb failed the request is linked into the list and
the worker will try to submit the usb urb again.

cheers,
  Gerd



^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v3 3/6] uas: make work list per-device
@ 2013-09-18  7:33       ` Gerd Hoffmann
  0 siblings, 0 replies; 16+ messages in thread
From: Gerd Hoffmann @ 2013-09-18  7:33 UTC (permalink / raw)
  To: Christoph Hellwig
  Cc: linux-usb, Matthew Wilcox, Sarah Sharp, Matthew Dharm,
	Greg Kroah-Hartman, open list:USB ATTACHED SCSI,
	open list:USB MASS STORAGE...,
	open list

On Di, 2013-09-17 at 13:30 -0700, Christoph Hellwig wrote:
> On Fri, Sep 13, 2013 at 01:27:12PM +0200, Gerd Hoffmann wrote:
> > Simplifies locking, we'll protect the list with the device spin lock.
> > Also plugs races which can happen when two devices operate on the
> > global list.
> > 
> > While being at it rename the list head from "list" to "work", preparing
> > for the addition of a second list.
> 
> Why do you even the list?

The list was already there when I took over maintainance ...

> What would a ordered per-device workqueue not
> provide?

Had no reason to look into replacing the list with something else so
far.  Why do you suggest using a workqueue instead?

Note that the list is not used in a typical request workflow.  Only in
case queuing an usb urb failed the request is linked into the list and
the worker will try to submit the usb urb again.

cheers,
  Gerd

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v3 3/6] uas: make work list per-device
  2013-09-18  7:33       ` Gerd Hoffmann
@ 2013-09-24  8:52         ` Christoph Hellwig
  -1 siblings, 0 replies; 16+ messages in thread
From: Christoph Hellwig @ 2013-09-24  8:52 UTC (permalink / raw)
  To: Gerd Hoffmann
  Cc: Christoph Hellwig, linux-usb, Matthew Wilcox, Sarah Sharp,
	Matthew Dharm, Greg Kroah-Hartman, open list:USB ATTACHED SCSI,
	open list:USB MASS STORAGE...,
	open list

On Wed, Sep 18, 2013 at 09:33:04AM +0200, Gerd Hoffmann wrote:
> > > While being at it rename the list head from "list" to "work", preparing
> > > for the addition of a second list.
> > 
> > Why do you even the list?
> 
> The list was already there when I took over maintainance ...
> 
> > What would a ordered per-device workqueue not
> > provide?
> 
> Had no reason to look into replacing the list with something else so
> far.  Why do you suggest using a workqueue instead?
> 
> Note that the list is not used in a typical request workflow.  Only in
> case queuing an usb urb failed the request is linked into the list and
> the worker will try to submit the usb urb again.

The driver is only using the list to queue up things into workqueue
context as far as I can see.  Which means it's far easier to leave that
to the workqueue.


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v3 3/6] uas: make work list per-device
@ 2013-09-24  8:52         ` Christoph Hellwig
  0 siblings, 0 replies; 16+ messages in thread
From: Christoph Hellwig @ 2013-09-24  8:52 UTC (permalink / raw)
  To: Gerd Hoffmann
  Cc: Christoph Hellwig, linux-usb, Matthew Wilcox, Sarah Sharp,
	Matthew Dharm, Greg Kroah-Hartman, open list:USB ATTACHED SCSI,
	open list:USB MASS STORAGE...,
	open list

On Wed, Sep 18, 2013 at 09:33:04AM +0200, Gerd Hoffmann wrote:
> > > While being at it rename the list head from "list" to "work", preparing
> > > for the addition of a second list.
> > 
> > Why do you even the list?
> 
> The list was already there when I took over maintainance ...
> 
> > What would a ordered per-device workqueue not
> > provide?
> 
> Had no reason to look into replacing the list with something else so
> far.  Why do you suggest using a workqueue instead?
> 
> Note that the list is not used in a typical request workflow.  Only in
> case queuing an usb urb failed the request is linked into the list and
> the worker will try to submit the usb urb again.

The driver is only using the list to queue up things into workqueue
context as far as I can see.  Which means it's far easier to leave that
to the workqueue.

^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2013-09-24  8:52 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <1379071635-30701-1-git-send-email-kraxel@redhat.com>
2013-09-13 11:27 ` [PATCH v3 1/6] xhci: fix usb3 streams Gerd Hoffmann
2013-09-13 11:27 ` [PATCH v3 2/6] uas: properly reinitialize in uas_eh_bus_reset_handler Gerd Hoffmann
2013-09-13 11:27   ` Gerd Hoffmann
2013-09-13 11:27 ` [PATCH v3 3/6] uas: make work list per-device Gerd Hoffmann
2013-09-13 11:27   ` Gerd Hoffmann
2013-09-17 20:30   ` Christoph Hellwig
2013-09-17 20:30     ` Christoph Hellwig
2013-09-18  7:33     ` Gerd Hoffmann
2013-09-18  7:33       ` Gerd Hoffmann
2013-09-24  8:52       ` Christoph Hellwig
2013-09-24  8:52         ` Christoph Hellwig
2013-09-13 11:27 ` [PATCH v3 4/6] uas: add dead request list Gerd Hoffmann
2013-09-13 11:27   ` Gerd Hoffmann
2013-09-13 11:27 ` [PATCH v3 5/6] uas: replace BUG_ON() + WARN_ON() with WARN_ON_ONCE() Gerd Hoffmann
2013-09-13 11:27   ` Gerd Hoffmann
2013-09-13 11:27 ` [PATCH v3 6/6] uas: remove BROKEN Gerd Hoffmann

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.