]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.4-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 31 Jul 2012 19:30:13 +0000 (12:30 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 31 Jul 2012 19:30:13 +0000 (12:30 -0700)
added patches:
arm-omap2-opp-fix-to-ensure-check-of-right-oppdef-after-bad-one.patch
rt2800usb-2001-3c17-is-an-rt3370-device.patch
scsi-avoid-dangling-pointer-in-scsi_requeue_command.patch
scsi-fix-device-removal-null-pointer-dereference.patch
scsi-fix-eh-wakeup-scsi_schedule_eh-vs-scsi_restart_operations.patch
scsi-fix-hot-unplug-vs-async-scan-race.patch
scsi-libsas-continue-revalidation.patch
scsi-libsas-fix-sas_discover_devices-return-code-handling.patch

queue-3.4/arm-omap2-opp-fix-to-ensure-check-of-right-oppdef-after-bad-one.patch [new file with mode: 0644]
queue-3.4/rt2800usb-2001-3c17-is-an-rt3370-device.patch [new file with mode: 0644]
queue-3.4/scsi-avoid-dangling-pointer-in-scsi_requeue_command.patch [new file with mode: 0644]
queue-3.4/scsi-fix-device-removal-null-pointer-dereference.patch [new file with mode: 0644]
queue-3.4/scsi-fix-eh-wakeup-scsi_schedule_eh-vs-scsi_restart_operations.patch [new file with mode: 0644]
queue-3.4/scsi-fix-hot-unplug-vs-async-scan-race.patch [new file with mode: 0644]
queue-3.4/scsi-libsas-continue-revalidation.patch [new file with mode: 0644]
queue-3.4/scsi-libsas-fix-sas_discover_devices-return-code-handling.patch [new file with mode: 0644]
queue-3.4/series

diff --git a/queue-3.4/arm-omap2-opp-fix-to-ensure-check-of-right-oppdef-after-bad-one.patch b/queue-3.4/arm-omap2-opp-fix-to-ensure-check-of-right-oppdef-after-bad-one.patch
new file mode 100644 (file)
index 0000000..6ccb712
--- /dev/null
@@ -0,0 +1,57 @@
+From b110547e586eb5825bc1d04aa9147bff83b57672 Mon Sep 17 00:00:00 2001
+From: Nishanth Menon <nm@ti.com>
+Date: Fri, 18 May 2012 12:26:19 -0500
+Subject: ARM: OMAP2+: OPP: Fix to ensure check of right oppdef after bad one
+
+From: Nishanth Menon <nm@ti.com>
+
+commit b110547e586eb5825bc1d04aa9147bff83b57672 upstream.
+
+Commit 9fa2df6b90786301b175e264f5fa9846aba81a65
+(ARM: OMAP2+: OPP: allow OPP enumeration to continue if device is not present)
+makes the logic:
+for (i = 0; i < opp_def_size; i++) {
+       <snip>
+       if (!oh || !oh->od) {
+               <snip>
+               continue;
+       }
+<snip>
+opp_def++;
+}
+
+In short, the moment we hit a "Bad OPP", we end up looping the list
+comparing against the bad opp definition pointer for the rest of the
+iteration count. Instead, increment opp_def in the for loop itself
+and allow continue to be used in code without much thought so that
+we check the next set of OPP definition pointers :)
+
+Cc: Steve Sakoman <steve@sakoman.com>
+Cc: Tony Lindgren <tony@atomide.com>
+Signed-off-by: Nishanth Menon <nm@ti.com>
+Signed-off-by: Kevin Hilman <khilman@ti.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ arch/arm/mach-omap2/opp.c |    3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+--- a/arch/arm/mach-omap2/opp.c
++++ b/arch/arm/mach-omap2/opp.c
+@@ -53,7 +53,7 @@ int __init omap_init_opp_table(struct om
+       omap_table_init = 1;
+       /* Lets now register with OPP library */
+-      for (i = 0; i < opp_def_size; i++) {
++      for (i = 0; i < opp_def_size; i++, opp_def++) {
+               struct omap_hwmod *oh;
+               struct device *dev;
+@@ -86,7 +86,6 @@ int __init omap_init_opp_table(struct om
+                                       __func__, opp_def->freq,
+                                       opp_def->hwmod_name, i, r);
+               }
+-              opp_def++;
+       }
+       return 0;
diff --git a/queue-3.4/rt2800usb-2001-3c17-is-an-rt3370-device.patch b/queue-3.4/rt2800usb-2001-3c17-is-an-rt3370-device.patch
new file mode 100644 (file)
index 0000000..7dcb4e1
--- /dev/null
@@ -0,0 +1,39 @@
+From 8fd9d059af12786341dec5a688e607bcdb372238 Mon Sep 17 00:00:00 2001
+From: Albert Pool <albertpool@solcon.nl>
+Date: Mon, 14 May 2012 18:08:32 +0200
+Subject: rt2800usb: 2001:3c17 is an RT3370 device
+
+From: Albert Pool <albertpool@solcon.nl>
+
+commit 8fd9d059af12786341dec5a688e607bcdb372238 upstream.
+
+D-Link DWA-123 rev A1
+
+Signed-off-by: Albert Pool<albertpool@solcon.nl>
+Acked-by: Gertjan van Wingerde <gwingerde@gmail.com>
+Signed-off-by: John W. Linville <linville@tuxdriver.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/net/wireless/rt2x00/rt2800usb.c |    3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/wireless/rt2x00/rt2800usb.c
++++ b/drivers/net/wireless/rt2x00/rt2800usb.c
+@@ -1137,6 +1137,8 @@ static struct usb_device_id rt2800usb_de
+ #ifdef CONFIG_RT2800USB_RT33XX
+       /* Belkin */
+       { USB_DEVICE(0x050d, 0x945b) },
++      /* D-Link */
++      { USB_DEVICE(0x2001, 0x3c17) },
+       /* Panasonic */
+       { USB_DEVICE(0x083a, 0xb511) },
+       /* Philips */
+@@ -1237,7 +1239,6 @@ static struct usb_device_id rt2800usb_de
+       /* D-Link */
+       { USB_DEVICE(0x07d1, 0x3c0b) },
+       { USB_DEVICE(0x07d1, 0x3c17) },
+-      { USB_DEVICE(0x2001, 0x3c17) },
+       /* Encore */
+       { USB_DEVICE(0x203d, 0x14a1) },
+       /* Gemtek */
diff --git a/queue-3.4/scsi-avoid-dangling-pointer-in-scsi_requeue_command.patch b/queue-3.4/scsi-avoid-dangling-pointer-in-scsi_requeue_command.patch
new file mode 100644 (file)
index 0000000..2739a72
--- /dev/null
@@ -0,0 +1,55 @@
+From 940f5d47e2f2e1fa00443921a0abf4822335b54d Mon Sep 17 00:00:00 2001
+From: Bart Van Assche <bvanassche@acm.org>
+Date: Fri, 29 Jun 2012 15:34:26 +0000
+Subject: SCSI: Avoid dangling pointer in scsi_requeue_command()
+
+From: Bart Van Assche <bvanassche@acm.org>
+
+commit 940f5d47e2f2e1fa00443921a0abf4822335b54d upstream.
+
+When we call scsi_unprep_request() the command associated with the request
+gets destroyed and therefore drops its reference on the device.  If this was
+the only reference, the device may get released and we end up with a NULL
+pointer deref when we call blk_requeue_request.
+
+Reported-by: Mike Christie <michaelc@cs.wisc.edu>
+Signed-off-by: Bart Van Assche <bvanassche@acm.org>
+Reviewed-by: Mike Christie <michaelc@cs.wisc.edu>
+Reviewed-by: Tejun Heo <tj@kernel.org>
+[jejb: enhance commend and add commit log for stable]
+Signed-off-by: James Bottomley <JBottomley@Parallels.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/scsi/scsi_lib.c |   11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+--- a/drivers/scsi/scsi_lib.c
++++ b/drivers/scsi/scsi_lib.c
+@@ -479,15 +479,26 @@ void scsi_requeue_run_queue(struct work_
+  */
+ static void scsi_requeue_command(struct request_queue *q, struct scsi_cmnd *cmd)
+ {
++      struct scsi_device *sdev = cmd->device;
+       struct request *req = cmd->request;
+       unsigned long flags;
++      /*
++       * We need to hold a reference on the device to avoid the queue being
++       * killed after the unlock and before scsi_run_queue is invoked which
++       * may happen because scsi_unprep_request() puts the command which
++       * releases its reference on the device.
++       */
++      get_device(&sdev->sdev_gendev);
++
+       spin_lock_irqsave(q->queue_lock, flags);
+       scsi_unprep_request(req);
+       blk_requeue_request(q, req);
+       spin_unlock_irqrestore(q->queue_lock, flags);
+       scsi_run_queue(q);
++
++      put_device(&sdev->sdev_gendev);
+ }
+ void scsi_next_command(struct scsi_cmnd *cmd)
diff --git a/queue-3.4/scsi-fix-device-removal-null-pointer-dereference.patch b/queue-3.4/scsi-fix-device-removal-null-pointer-dereference.patch
new file mode 100644 (file)
index 0000000..1c45c81
--- /dev/null
@@ -0,0 +1,155 @@
+From 67bd94130015c507011af37858989b199c52e1de Mon Sep 17 00:00:00 2001
+From: Bart Van Assche <bvanassche@acm.org>
+Date: Fri, 29 Jun 2012 15:33:22 +0000
+Subject: SCSI: Fix device removal NULL pointer dereference
+
+From: Bart Van Assche <bvanassche@acm.org>
+
+commit 67bd94130015c507011af37858989b199c52e1de upstream.
+
+Use blk_queue_dead() to test whether the queue is dead instead
+of !sdev. Since scsi_prep_fn() may be invoked concurrently with
+__scsi_remove_device(), keep the queuedata (sdev) pointer in
+__scsi_remove_device(). This patch fixes a kernel oops that
+can be triggered by USB device removal. See also
+http://www.spinics.net/lists/linux-scsi/msg56254.html.
+
+Other changes included in this patch:
+- Swap the blk_cleanup_queue() and kfree() calls in
+  scsi_host_dev_release() to make that code easier to grasp.
+- Remove the queue dead check from scsi_run_queue() since the
+  queue state can change anyway at any point in that function
+  where the queue lock is not held.
+- Remove the queue dead check from the start of scsi_request_fn()
+  since it is redundant with the scsi_device_online() check.
+
+Reported-by: Jun'ichi Nomura <j-nomura@ce.jp.nec.com>
+Signed-off-by: Bart Van Assche <bvanassche@acm.org>
+Reviewed-by: Mike Christie <michaelc@cs.wisc.edu>
+Reviewed-by: Tejun Heo <tj@kernel.org>
+Signed-off-by: James Bottomley <JBottomley@Parallels.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/scsi/hosts.c      |    7 ++++---
+ drivers/scsi/scsi_lib.c   |   32 ++++----------------------------
+ drivers/scsi/scsi_priv.h  |    1 -
+ drivers/scsi/scsi_sysfs.c |    5 +----
+ 4 files changed, 9 insertions(+), 36 deletions(-)
+
+--- a/drivers/scsi/hosts.c
++++ b/drivers/scsi/hosts.c
+@@ -290,6 +290,7 @@ static void scsi_host_dev_release(struct
+       struct Scsi_Host *shost = dev_to_shost(dev);
+       struct device *parent = dev->parent;
+       struct request_queue *q;
++      void *queuedata;
+       scsi_proc_hostdir_rm(shost->hostt);
+@@ -299,9 +300,9 @@ static void scsi_host_dev_release(struct
+               destroy_workqueue(shost->work_q);
+       q = shost->uspace_req_q;
+       if (q) {
+-              kfree(q->queuedata);
+-              q->queuedata = NULL;
+-              scsi_free_queue(q);
++              queuedata = q->queuedata;
++              blk_cleanup_queue(q);
++              kfree(queuedata);
+       }
+       scsi_destroy_command_freelist(shost);
+--- a/drivers/scsi/scsi_lib.c
++++ b/drivers/scsi/scsi_lib.c
+@@ -406,10 +406,6 @@ static void scsi_run_queue(struct reques
+       LIST_HEAD(starved_list);
+       unsigned long flags;
+-      /* if the device is dead, sdev will be NULL, so no queue to run */
+-      if (!sdev)
+-              return;
+-
+       shost = sdev->host;
+       if (scsi_target(sdev)->single_lun)
+               scsi_single_lun_run(sdev);
+@@ -1370,16 +1366,16 @@ static inline int scsi_host_queue_ready(
+  * may be changed after request stacking drivers call the function,
+  * regardless of taking lock or not.
+  *
+- * When scsi can't dispatch I/Os anymore and needs to kill I/Os
+- * (e.g. !sdev), scsi needs to return 'not busy'.
+- * Otherwise, request stacking drivers may hold requests forever.
++ * When scsi can't dispatch I/Os anymore and needs to kill I/Os scsi
++ * needs to return 'not busy'. Otherwise, request stacking drivers
++ * may hold requests forever.
+  */
+ static int scsi_lld_busy(struct request_queue *q)
+ {
+       struct scsi_device *sdev = q->queuedata;
+       struct Scsi_Host *shost;
+-      if (!sdev)
++      if (blk_queue_dead(q))
+               return 0;
+       shost = sdev->host;
+@@ -1490,12 +1486,6 @@ static void scsi_request_fn(struct reque
+       struct scsi_cmnd *cmd;
+       struct request *req;
+-      if (!sdev) {
+-              while ((req = blk_peek_request(q)) != NULL)
+-                      scsi_kill_request(req, q);
+-              return;
+-      }
+-
+       if(!get_device(&sdev->sdev_gendev))
+               /* We must be tearing the block queue down already */
+               return;
+@@ -1697,20 +1687,6 @@ struct request_queue *scsi_alloc_queue(s
+       return q;
+ }
+-void scsi_free_queue(struct request_queue *q)
+-{
+-      unsigned long flags;
+-
+-      WARN_ON(q->queuedata);
+-
+-      /* cause scsi_request_fn() to kill all non-finished requests */
+-      spin_lock_irqsave(q->queue_lock, flags);
+-      q->request_fn(q);
+-      spin_unlock_irqrestore(q->queue_lock, flags);
+-
+-      blk_cleanup_queue(q);
+-}
+-
+ /*
+  * Function:    scsi_block_requests()
+  *
+--- a/drivers/scsi/scsi_priv.h
++++ b/drivers/scsi/scsi_priv.h
+@@ -84,7 +84,6 @@ extern void scsi_next_command(struct scs
+ extern void scsi_io_completion(struct scsi_cmnd *, unsigned int);
+ extern void scsi_run_host_queues(struct Scsi_Host *shost);
+ extern struct request_queue *scsi_alloc_queue(struct scsi_device *sdev);
+-extern void scsi_free_queue(struct request_queue *q);
+ extern int scsi_init_queue(void);
+ extern void scsi_exit_queue(void);
+ struct request_queue;
+--- a/drivers/scsi/scsi_sysfs.c
++++ b/drivers/scsi/scsi_sysfs.c
+@@ -971,11 +971,8 @@ void __scsi_remove_device(struct scsi_de
+               sdev->host->hostt->slave_destroy(sdev);
+       transport_destroy_device(dev);
+-      /* cause the request function to reject all I/O requests */
+-      sdev->request_queue->queuedata = NULL;
+-
+       /* Freeing the queue signals to block that we're done */
+-      scsi_free_queue(sdev->request_queue);
++      blk_cleanup_queue(sdev->request_queue);
+       put_device(dev);
+ }
diff --git a/queue-3.4/scsi-fix-eh-wakeup-scsi_schedule_eh-vs-scsi_restart_operations.patch b/queue-3.4/scsi-fix-eh-wakeup-scsi_schedule_eh-vs-scsi_restart_operations.patch
new file mode 100644 (file)
index 0000000..b21a85c
--- /dev/null
@@ -0,0 +1,59 @@
+From 57fc2e335fd3c2f898ee73570dc81426c28dc7b4 Mon Sep 17 00:00:00 2001
+From: Dan Williams <dan.j.williams@intel.com>
+Date: Thu, 21 Jun 2012 23:25:32 -0700
+Subject: SCSI: fix eh wakeup (scsi_schedule_eh vs scsi_restart_operations)
+
+From: Dan Williams <dan.j.williams@intel.com>
+
+commit 57fc2e335fd3c2f898ee73570dc81426c28dc7b4 upstream.
+
+Rapid ata hotplug on a libsas controller results in cases where libsas
+is waiting indefinitely on eh to perform an ata probe.
+
+A race exists between scsi_schedule_eh() and scsi_restart_operations()
+in the case when scsi_restart_operations() issues i/o to other devices
+in the sas domain.  When this happens the host state transitions from
+SHOST_RECOVERY (set by scsi_schedule_eh) back to SHOST_RUNNING and
+->host_busy is non-zero so we put the eh thread to sleep even though
+->host_eh_scheduled is active.
+
+Before putting the error handler to sleep we need to check if the
+host_state needs to return to SHOST_RECOVERY for another trip through
+eh.  Since i/o that is released by scsi_restart_operations has been
+blocked for at least one eh cycle, this implementation allows those
+i/o's to run before another eh cycle starts to discourage hung task
+timeouts.
+
+Reported-by: Tom Jackson <thomas.p.jackson@intel.com>
+Tested-by: Tom Jackson <thomas.p.jackson@intel.com>
+Signed-off-by: Dan Williams <dan.j.williams@intel.com>
+Signed-off-by: James Bottomley <JBottomley@Parallels.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/scsi/scsi_error.c |   14 ++++++++++++++
+ 1 file changed, 14 insertions(+)
+
+--- a/drivers/scsi/scsi_error.c
++++ b/drivers/scsi/scsi_error.c
+@@ -1687,6 +1687,20 @@ static void scsi_restart_operations(stru
+        * requests are started.
+        */
+       scsi_run_host_queues(shost);
++
++      /*
++       * if eh is active and host_eh_scheduled is pending we need to re-run
++       * recovery.  we do this check after scsi_run_host_queues() to allow
++       * everything pent up since the last eh run a chance to make forward
++       * progress before we sync again.  Either we'll immediately re-run
++       * recovery or scsi_device_unbusy() will wake us again when these
++       * pending commands complete.
++       */
++      spin_lock_irqsave(shost->host_lock, flags);
++      if (shost->host_eh_scheduled)
++              if (scsi_host_set_state(shost, SHOST_RECOVERY))
++                      WARN_ON(scsi_host_set_state(shost, SHOST_CANCEL_RECOVERY));
++      spin_unlock_irqrestore(shost->host_lock, flags);
+ }
+ /**
diff --git a/queue-3.4/scsi-fix-hot-unplug-vs-async-scan-race.patch b/queue-3.4/scsi-fix-hot-unplug-vs-async-scan-race.patch
new file mode 100644 (file)
index 0000000..bf56f60
--- /dev/null
@@ -0,0 +1,118 @@
+From 3b661a92e869ebe2358de8f4b3230ad84f7fce51 Mon Sep 17 00:00:00 2001
+From: Dan Williams <dan.j.williams@intel.com>
+Date: Thu, 21 Jun 2012 23:47:28 -0700
+Subject: SCSI: fix hot unplug vs async scan race
+
+From: Dan Williams <dan.j.williams@intel.com>
+
+commit 3b661a92e869ebe2358de8f4b3230ad84f7fce51 upstream.
+
+The following crash results from cases where the end_device has been
+removed before scsi_sysfs_add_sdev has had a chance to run.
+
+ BUG: unable to handle kernel NULL pointer dereference at 0000000000000098
+ IP: [<ffffffff8115e100>] sysfs_create_dir+0x32/0xb6
+ ...
+ Call Trace:
+  [<ffffffff8125e4a8>] kobject_add_internal+0x120/0x1e3
+  [<ffffffff81075149>] ? trace_hardirqs_on+0xd/0xf
+  [<ffffffff8125e641>] kobject_add_varg+0x41/0x50
+  [<ffffffff8125e70b>] kobject_add+0x64/0x66
+  [<ffffffff8131122b>] device_add+0x12d/0x63a
+  [<ffffffff814b65ea>] ? _raw_spin_unlock_irqrestore+0x47/0x56
+  [<ffffffff8107de15>] ? module_refcount+0x89/0xa0
+  [<ffffffff8132f348>] scsi_sysfs_add_sdev+0x4e/0x28a
+  [<ffffffff8132dcbb>] do_scan_async+0x9c/0x145
+
+...teach scsi_sysfs_add_devices() to check for deleted devices() before
+trying to add them, and teach scsi_remove_target() how to remove targets
+that have not been added via device_add().
+
+Reported-by: Dariusz Majchrzak <dariusz.majchrzak@intel.com>
+Signed-off-by: Dan Williams <dan.j.williams@intel.com>
+Signed-off-by: James Bottomley <JBottomley@Parallels.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/scsi/scsi_scan.c  |    3 +++
+ drivers/scsi/scsi_sysfs.c |   41 ++++++++++++++++++++++++++---------------
+ 2 files changed, 29 insertions(+), 15 deletions(-)
+
+--- a/drivers/scsi/scsi_scan.c
++++ b/drivers/scsi/scsi_scan.c
+@@ -1714,6 +1714,9 @@ static void scsi_sysfs_add_devices(struc
+ {
+       struct scsi_device *sdev;
+       shost_for_each_device(sdev, shost) {
++              /* target removed before the device could be added */
++              if (sdev->sdev_state == SDEV_DEL)
++                      continue;
+               if (!scsi_host_scan_allowed(shost) ||
+                   scsi_sysfs_add_sdev(sdev) != 0)
+                       __scsi_remove_device(sdev);
+--- a/drivers/scsi/scsi_sysfs.c
++++ b/drivers/scsi/scsi_sysfs.c
+@@ -1000,7 +1000,6 @@ static void __scsi_remove_target(struct
+       struct scsi_device *sdev;
+       spin_lock_irqsave(shost->host_lock, flags);
+-      starget->reap_ref++;
+  restart:
+       list_for_each_entry(sdev, &shost->__devices, siblings) {
+               if (sdev->channel != starget->channel ||
+@@ -1014,14 +1013,6 @@ static void __scsi_remove_target(struct
+               goto restart;
+       }
+       spin_unlock_irqrestore(shost->host_lock, flags);
+-      scsi_target_reap(starget);
+-}
+-
+-static int __remove_child (struct device * dev, void * data)
+-{
+-      if (scsi_is_target_device(dev))
+-              __scsi_remove_target(to_scsi_target(dev));
+-      return 0;
+ }
+ /**
+@@ -1034,14 +1025,34 @@ static int __remove_child (struct device
+  */
+ void scsi_remove_target(struct device *dev)
+ {
+-      if (scsi_is_target_device(dev)) {
+-              __scsi_remove_target(to_scsi_target(dev));
+-              return;
++      struct Scsi_Host *shost = dev_to_shost(dev->parent);
++      struct scsi_target *starget, *found;
++      unsigned long flags;
++
++ restart:
++      found = NULL;
++      spin_lock_irqsave(shost->host_lock, flags);
++      list_for_each_entry(starget, &shost->__targets, siblings) {
++              if (starget->state == STARGET_DEL)
++                      continue;
++              if (starget->dev.parent == dev || &starget->dev == dev) {
++                      found = starget;
++                      found->reap_ref++;
++                      break;
++              }
+       }
++      spin_unlock_irqrestore(shost->host_lock, flags);
+-      get_device(dev);
+-      device_for_each_child(dev, NULL, __remove_child);
+-      put_device(dev);
++      if (found) {
++              __scsi_remove_target(found);
++              scsi_target_reap(found);
++              /* in the case where @dev has multiple starget children,
++               * continue removing.
++               *
++               * FIXME: does such a case exist?
++               */
++              goto restart;
++      }
+ }
+ EXPORT_SYMBOL(scsi_remove_target);
diff --git a/queue-3.4/scsi-libsas-continue-revalidation.patch b/queue-3.4/scsi-libsas-continue-revalidation.patch
new file mode 100644 (file)
index 0000000..22ceb7f
--- /dev/null
@@ -0,0 +1,47 @@
+From 26f2f199ff150d8876b2641c41e60d1c92d2fb81 Mon Sep 17 00:00:00 2001
+From: Dan Williams <dan.j.williams@intel.com>
+Date: Thu, 21 Jun 2012 23:36:15 -0700
+Subject: SCSI: libsas: continue revalidation
+
+From: Dan Williams <dan.j.williams@intel.com>
+
+commit 26f2f199ff150d8876b2641c41e60d1c92d2fb81 upstream.
+
+Continue running revalidation until no more broadcast devices are
+discovered.  Fixes cases where re-discovery completes too early in a
+domain with multiple expanders with pending re-discovery events.
+Servicing BCNs can get backed up behind error recovery.
+
+Signed-off-by: Dan Williams <dan.j.williams@intel.com>
+Signed-off-by: James Bottomley <JBottomley@Parallels.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/scsi/libsas/sas_expander.c |    8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+--- a/drivers/scsi/libsas/sas_expander.c
++++ b/drivers/scsi/libsas/sas_expander.c
+@@ -2109,9 +2109,7 @@ int sas_ex_revalidate_domain(struct doma
+       struct domain_device *dev = NULL;
+       res = sas_find_bcast_dev(port_dev, &dev);
+-      if (res)
+-              goto out;
+-      if (dev) {
++      while (res == 0 && dev) {
+               struct expander_device *ex = &dev->ex_dev;
+               int i = 0, phy_id;
+@@ -2123,8 +2121,10 @@ int sas_ex_revalidate_domain(struct doma
+                       res = sas_rediscover(dev, phy_id);
+                       i = phy_id + 1;
+               } while (i < ex->num_phys);
++
++              dev = NULL;
++              res = sas_find_bcast_dev(port_dev, &dev);
+       }
+-out:
+       return res;
+ }
diff --git a/queue-3.4/scsi-libsas-fix-sas_discover_devices-return-code-handling.patch b/queue-3.4/scsi-libsas-fix-sas_discover_devices-return-code-handling.patch
new file mode 100644 (file)
index 0000000..86c2ea2
--- /dev/null
@@ -0,0 +1,126 @@
+From b17caa174a7e1fd2e17b26e210d4ee91c4c28b37 Mon Sep 17 00:00:00 2001
+From: Dan Williams <dan.j.williams@intel.com>
+Date: Thu, 21 Jun 2012 23:36:20 -0700
+Subject: SCSI: libsas: fix sas_discover_devices return code handling
+
+From: Dan Williams <dan.j.williams@intel.com>
+
+commit b17caa174a7e1fd2e17b26e210d4ee91c4c28b37 upstream.
+
+commit 198439e4 [SCSI] libsas: do not set res = 0 in sas_ex_discover_dev()
+commit 19252de6 [SCSI] libsas: fix wide port hotplug issues
+
+The above commits seem to have confused the return value of
+sas_ex_discover_dev which is non-zero on failure and
+sas_ex_join_wide_port which just indicates short circuiting discovery on
+already established ports.  The result is random discovery failures
+depending on configuration.
+
+Calls to sas_ex_join_wide_port are the source of the trouble as its
+return value is errantly assigned to 'res'.  Convert it to bool and stop
+returning its result up the stack.
+
+Tested-by: Dan Melnic <dan.melnic@amd.com>
+Reported-by: Dan Melnic <dan.melnic@amd.com>
+Signed-off-by: Dan Williams <dan.j.williams@intel.com>
+Reviewed-by: Jack Wang <jack_wang@usish.com>
+Signed-off-by: James Bottomley <JBottomley@Parallels.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/scsi/libsas/sas_expander.c |   39 +++++++++++--------------------------
+ 1 file changed, 12 insertions(+), 27 deletions(-)
+
+--- a/drivers/scsi/libsas/sas_expander.c
++++ b/drivers/scsi/libsas/sas_expander.c
+@@ -868,7 +868,7 @@ static struct domain_device *sas_ex_disc
+ }
+ /* See if this phy is part of a wide port */
+-static int sas_ex_join_wide_port(struct domain_device *parent, int phy_id)
++static bool sas_ex_join_wide_port(struct domain_device *parent, int phy_id)
+ {
+       struct ex_phy *phy = &parent->ex_dev.ex_phy[phy_id];
+       int i;
+@@ -884,11 +884,11 @@ static int sas_ex_join_wide_port(struct
+                       sas_port_add_phy(ephy->port, phy->phy);
+                       phy->port = ephy->port;
+                       phy->phy_state = PHY_DEVICE_DISCOVERED;
+-                      return 0;
++                      return true;
+               }
+       }
+-      return -ENODEV;
++      return false;
+ }
+ static struct domain_device *sas_ex_discover_expander(
+@@ -1030,8 +1030,7 @@ static int sas_ex_discover_dev(struct do
+               return res;
+       }
+-      res = sas_ex_join_wide_port(dev, phy_id);
+-      if (!res) {
++      if (sas_ex_join_wide_port(dev, phy_id)) {
+               SAS_DPRINTK("Attaching ex phy%d to wide port %016llx\n",
+                           phy_id, SAS_ADDR(ex_phy->attached_sas_addr));
+               return res;
+@@ -1077,8 +1076,7 @@ static int sas_ex_discover_dev(struct do
+                       if (SAS_ADDR(ex->ex_phy[i].attached_sas_addr) ==
+                           SAS_ADDR(child->sas_addr)) {
+                               ex->ex_phy[i].phy_state= PHY_DEVICE_DISCOVERED;
+-                              res = sas_ex_join_wide_port(dev, i);
+-                              if (!res)
++                              if (sas_ex_join_wide_port(dev, i))
+                                       SAS_DPRINTK("Attaching ex phy%d to wide port %016llx\n",
+                                                   i, SAS_ADDR(ex->ex_phy[i].attached_sas_addr));
+@@ -1943,32 +1941,20 @@ static int sas_discover_new(struct domai
+ {
+       struct ex_phy *ex_phy = &dev->ex_dev.ex_phy[phy_id];
+       struct domain_device *child;
+-      bool found = false;
+-      int res, i;
++      int res;
+       SAS_DPRINTK("ex %016llx phy%d new device attached\n",
+                   SAS_ADDR(dev->sas_addr), phy_id);
+       res = sas_ex_phy_discover(dev, phy_id);
+       if (res)
+-              goto out;
+-      /* to support the wide port inserted */
+-      for (i = 0; i < dev->ex_dev.num_phys; i++) {
+-              struct ex_phy *ex_phy_temp = &dev->ex_dev.ex_phy[i];
+-              if (i == phy_id)
+-                      continue;
+-              if (SAS_ADDR(ex_phy_temp->attached_sas_addr) ==
+-                  SAS_ADDR(ex_phy->attached_sas_addr)) {
+-                      found = true;
+-                      break;
+-              }
+-      }
+-      if (found) {
+-              sas_ex_join_wide_port(dev, phy_id);
++              return res;
++
++      if (sas_ex_join_wide_port(dev, phy_id))
+               return 0;
+-      }
++
+       res = sas_ex_discover_devices(dev, phy_id);
+-      if (!res)
+-              goto out;
++      if (res)
++              return res;
+       list_for_each_entry(child, &dev->ex_dev.children, siblings) {
+               if (SAS_ADDR(child->sas_addr) ==
+                   SAS_ADDR(ex_phy->attached_sas_addr)) {
+@@ -1978,7 +1964,6 @@ static int sas_discover_new(struct domai
+                       break;
+               }
+       }
+-out:
+       return res;
+ }
index dd09fe8047e1f0f3ca23530fe746fa43e0c04149..53268a1ae2846879aa09361c0ef8a94de5971405 100644 (file)
@@ -6,3 +6,11 @@ powerpc-ftrace-fix-assembly-trampoline-register-usage.patch
 powerpc-add-memory-attribute-for-mfmsr.patch
 powerpc-eeh-check-handle_eeh_events-return-value.patch
 powerpc-85xx-use-the-brx-registers-to-enable-indirect-mode-on-the-p1022ds.patch
+scsi-libsas-continue-revalidation.patch
+scsi-libsas-fix-sas_discover_devices-return-code-handling.patch
+scsi-fix-eh-wakeup-scsi_schedule_eh-vs-scsi_restart_operations.patch
+scsi-fix-hot-unplug-vs-async-scan-race.patch
+scsi-fix-device-removal-null-pointer-dereference.patch
+scsi-avoid-dangling-pointer-in-scsi_requeue_command.patch
+rt2800usb-2001-3c17-is-an-rt3370-device.patch
+arm-omap2-opp-fix-to-ensure-check-of-right-oppdef-after-bad-one.patch