rpms/kernel/devel kernel.spec, 1.442, 1.443 linux-2.6-firewire-git-pending.patch, 1.4, 1.5 linux-2.6-firewire-git-update.patch, 1.6, 1.7

Jarod Wilson (jwilson) fedora-extras-commits at redhat.com
Thu Feb 21 04:40:57 UTC 2008


Author: jwilson

Update of /cvs/pkgs/rpms/kernel/devel
In directory cvs-int.fedora.redhat.com:/tmp/cvs-serv4965

Modified Files:
	kernel.spec linux-2.6-firewire-git-pending.patch 
	linux-2.6-firewire-git-update.patch 
Log Message:
* Wed Feb 20 2008 Jarod Wilson <jwilson at redhat.com>
- Update to latest FireWire git bits



Index: kernel.spec
===================================================================
RCS file: /cvs/pkgs/rpms/kernel/devel/kernel.spec,v
retrieving revision 1.442
retrieving revision 1.443
diff -u -r1.442 -r1.443
--- kernel.spec	21 Feb 2008 02:22:59 -0000	1.442
+++ kernel.spec	21 Feb 2008 04:40:21 -0000	1.443
@@ -1737,6 +1737,9 @@
 %kernel_variant_files -a /%{image_install_path}/xen*-%{KVERREL} -e /etc/ld.so.conf.d/kernelcap-%{KVERREL}.conf %{with_xen} xen
 
 %changelog
+* Wed Feb 20 2008 Jarod Wilson <jwilson at redhat.com>
+- Update to latest FireWire git bits
+
 * Wed Feb 20 2008 Kyle McMartin <kmcmartin at redhat.com>
 - fix thinko in the libgcc patch
 

linux-2.6-firewire-git-pending.patch:

Index: linux-2.6-firewire-git-pending.patch
===================================================================
RCS file: /cvs/pkgs/rpms/kernel/devel/linux-2.6-firewire-git-pending.patch,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- linux-2.6-firewire-git-pending.patch	12 Feb 2008 16:41:53 -0000	1.4
+++ linux-2.6-firewire-git-pending.patch	21 Feb 2008 04:40:21 -0000	1.5
@@ -3,1119 +3,3 @@
 # tree, which we think we're going to want...
 #
 
-There is a race between shutdown and creation of devices:  fw-core may
-attempt to add a device with the same name of an already existing
-device.  http://bugzilla.kernel.org/show_bug.cgi?id=9828
-
-Impact of the bug:  Happens rarely (when shutdown of a device coincides
-with creation of another), forces the user to unplug and replug the new
-device to get it working.
-
-The fix is obvious:  Free the minor number *after* instead of *before*
-device_unregister().  This requires to take an additional reference of
-the fw_device as long as the IDR tree points to it.
-
-And while we are at it, we fix an additional race condition:
-fw_device_op_open() took its reference of the fw_device a little bit too
-late, hence was in danger to access an already invalid fw_device.
-
-Signed-off-by: Stefan Richter <stefanr at s5r6.in-berlin.de>
----
- drivers/firewire/fw-cdev.c   |    8 +++++---
- drivers/firewire/fw-device.c |   20 ++++++++++++++------
- drivers/firewire/fw-device.h |    2 +-
- 3 files changed, 20 insertions(+), 10 deletions(-)
-
-Index: linux/drivers/firewire/fw-device.c
-===================================================================
---- linux.orig/drivers/firewire/fw-device.c
-+++ linux/drivers/firewire/fw-device.c
-@@ -610,12 +610,14 @@ static DECLARE_RWSEM(idr_rwsem);
- static DEFINE_IDR(fw_device_idr);
- int fw_cdev_major;
- 
--struct fw_device *fw_device_from_devt(dev_t devt)
-+struct fw_device *fw_device_get_by_devt(dev_t devt)
- {
- 	struct fw_device *device;
- 
- 	down_read(&idr_rwsem);
- 	device = idr_find(&fw_device_idr, MINOR(devt));
-+	if (device)
-+		fw_device_get(device);
- 	up_read(&idr_rwsem);
- 
- 	return device;
-@@ -627,13 +629,14 @@ static void fw_device_shutdown(struct wo
- 		container_of(work, struct fw_device, work.work);
- 	int minor = MINOR(device->device.devt);
- 
--	down_write(&idr_rwsem);
--	idr_remove(&fw_device_idr, minor);
--	up_write(&idr_rwsem);
--
- 	fw_device_cdev_remove(device);
- 	device_for_each_child(&device->device, NULL, shutdown_unit);
- 	device_unregister(&device->device);
-+
-+	down_write(&idr_rwsem);
-+	idr_remove(&fw_device_idr, minor);
-+	up_write(&idr_rwsem);
-+	fw_device_put(device);
- }
- 
- static struct device_type fw_device_type = {
-@@ -682,10 +685,13 @@ static void fw_device_init(struct work_s
- 	}
- 
- 	err = -ENOMEM;
-+
-+	fw_device_get(device);
- 	down_write(&idr_rwsem);
- 	if (idr_pre_get(&fw_device_idr, GFP_KERNEL))
- 		err = idr_get_new(&fw_device_idr, device, &minor);
- 	up_write(&idr_rwsem);
-+
- 	if (err < 0)
- 		goto error;
- 
-@@ -741,7 +747,9 @@ static void fw_device_init(struct work_s
- 	idr_remove(&fw_device_idr, minor);
- 	up_write(&idr_rwsem);
-  error:
--	put_device(&device->device);
-+	fw_device_put(device);		/* fw_device_idr's reference */
-+
-+	put_device(&device->device);	/* our reference */
- }
- 
- static int update_unit(struct device *dev, void *data)
-Index: linux/drivers/firewire/fw-cdev.c
-===================================================================
---- linux.orig/drivers/firewire/fw-cdev.c
-+++ linux/drivers/firewire/fw-cdev.c
-@@ -109,15 +109,17 @@ static int fw_device_op_open(struct inod
- 	struct client *client;
- 	unsigned long flags;
- 
--	device = fw_device_from_devt(inode->i_rdev);
-+	device = fw_device_get_by_devt(inode->i_rdev);
- 	if (device == NULL)
- 		return -ENODEV;
- 
- 	client = kzalloc(sizeof(*client), GFP_KERNEL);
--	if (client == NULL)
-+	if (client == NULL) {
-+		fw_device_put(device);
- 		return -ENOMEM;
-+	}
- 
--	client->device = fw_device_get(device);
-+	client->device = device;
- 	INIT_LIST_HEAD(&client->event_list);
- 	INIT_LIST_HEAD(&client->resource_list);
- 	spin_lock_init(&client->lock);
-Index: linux/drivers/firewire/fw-device.h
-===================================================================
---- linux.orig/drivers/firewire/fw-device.h
-+++ linux/drivers/firewire/fw-device.h
-@@ -77,13 +77,13 @@ fw_device_is_shutdown(struct fw_device *
- }
- 
- struct fw_device *fw_device_get(struct fw_device *device);
-+struct fw_device *fw_device_get_by_devt(dev_t devt);
- void fw_device_put(struct fw_device *device);
- int fw_device_enable_phys_dma(struct fw_device *device);
- 
- void fw_device_cdev_update(struct fw_device *device);
- void fw_device_cdev_remove(struct fw_device *device);
- 
--struct fw_device *fw_device_from_devt(dev_t devt);
- extern int fw_cdev_major;
- 
- struct fw_unit {
-
--- 
-Stefan Richter
--=====-==--- --=- ---=-
-http://arcgraph.de/sr/
-
-
-This should help to interpret user reports.  E.g. one can look up the
-vendor OUI (first three bytes of the GUID) and thus tell what is what.
-
-Also simplifies the math in the GUID sysfs attribute.
-
-Signed-off-by: Stefan Richter <stefanr at s5r6.in-berlin.de>
----
- drivers/firewire/fw-device.c |   28 +++++++++++++++++-----------
- 1 file changed, 17 insertions(+), 11 deletions(-)
-
-Index: linux/drivers/firewire/fw-device.c
-===================================================================
---- linux.orig/drivers/firewire/fw-device.c
-+++ linux/drivers/firewire/fw-device.c
-@@ -358,12 +358,9 @@ static ssize_t
- guid_show(struct device *dev, struct device_attribute *attr, char *buf)
- {
- 	struct fw_device *device = fw_device(dev);
--	u64 guid;
- 
--	guid = ((u64)device->config_rom[3] << 32) | device->config_rom[4];
--
--	return snprintf(buf, PAGE_SIZE, "0x%016llx\n",
--			(unsigned long long)guid);
-+	return snprintf(buf, PAGE_SIZE, "0x%08x%08x\n",
-+			device->config_rom[3], device->config_rom[4]);
- }
- 
- static struct device_attribute fw_device_attributes[] = {
-@@ -723,13 +720,22 @@ static void fw_device_init(struct work_s
- 	 */
- 	if (atomic_cmpxchg(&device->state,
- 		    FW_DEVICE_INITIALIZING,
--		    FW_DEVICE_RUNNING) == FW_DEVICE_SHUTDOWN)
-+		    FW_DEVICE_RUNNING) == FW_DEVICE_SHUTDOWN) {
- 		fw_device_shutdown(&device->work.work);
--	else
--		fw_notify("created new fw device %s "
--			  "(%d config rom retries, S%d00)\n",
--			  device->device.bus_id, device->config_rom_retries,
--			  1 << device->max_speed);
-+	} else {
-+		if (device->config_rom_retries)
-+			fw_notify("created device %s: GUID %08x%08x, S%d00, "
-+				  "%d config ROM retries\n",
-+				  device->device.bus_id,
-+				  device->config_rom[3], device->config_rom[4],
-+				  1 << device->max_speed,
-+				  device->config_rom_retries);
-+		else
-+			fw_notify("created device %s: GUID %08x%08x, S%d00\n",
-+				  device->device.bus_id,
-+				  device->config_rom[3], device->config_rom[4],
-+				  1 << device->max_speed);
-+	}
- 
- 	/*
- 	 * Reschedule the IRM work if we just finished reading the
-
--- 
-Stefan Richter
--=====-==--- --=- ---==
-http://arcgraph.de/sr/
-
-
-Several different SBP-2 bridges accept a login early while the IDE
-device is still powering up.  They are therefore unable to respond to
-SCSI INQUIRY immediately, and the SCSI core has to retry the INQUIRY.
-One of these retries is typically successful, and all is well.
-
-But in case of Momobay FX-3A, the INQUIRY retries tend to fail entirely.
-This can usually be avoided by waiting a little while after login before
-letting the SCSI core send the INQUIRY.  The old sbp2 driver handles
-this more gracefully for as yet unknown reasons (perhaps because it
-waits for fetch agent resets to complete, unlike fw-sbp2 which quickly
-proceeds after requesting the agent reset).  Therefore the workaround is
-not as much necessary for sbp2.
-
-Signed-off-by: Stefan Richter <stefanr at s5r6.in-berlin.de>
----
- drivers/firewire/fw-sbp2.c |   15 +++++++++++++++
- 1 file changed, 15 insertions(+)
-
-Index: linux/drivers/firewire/fw-sbp2.c
-===================================================================
---- linux.orig/drivers/firewire/fw-sbp2.c
-+++ linux/drivers/firewire/fw-sbp2.c
-@@ -32,6 +32,7 @@
- #include <linux/module.h>
- #include <linux/moduleparam.h>
- #include <linux/mod_devicetable.h>
-+#include <linux/delay.h>
- #include <linux/device.h>
- #include <linux/scatterlist.h>
- #include <linux/dma-mapping.h>
-@@ -82,6 +83,9 @@ MODULE_PARM_DESC(exclusive_login, "Exclu
-  *   Avoids access beyond actual disk limits on devices with an off-by-one bug.
-  *   Don't use this with devices which don't have this bug.
-  *
-+ * - delay inquiry
-+ *   Wait extra SBP2_INQUIRY_DELAY seconds after login before SCSI inquiry.
-+ *
-  * - override internal blacklist
-  *   Instead of adding to the built-in blacklist, use only the workarounds
-  *   specified in the module load parameter.
-@@ -91,6 +95,8 @@ MODULE_PARM_DESC(exclusive_login, "Exclu
- #define SBP2_WORKAROUND_INQUIRY_36	0x2
- #define SBP2_WORKAROUND_MODE_SENSE_8	0x4
- #define SBP2_WORKAROUND_FIX_CAPACITY	0x8
-+#define SBP2_WORKAROUND_DELAY_INQUIRY	0x10
-+#define SBP2_INQUIRY_DELAY		12
- #define SBP2_WORKAROUND_OVERRIDE	0x100
- 
- static int sbp2_param_workarounds;
-@@ -100,6 +106,7 @@ MODULE_PARM_DESC(workarounds, "Work arou
- 	", 36 byte inquiry = "    __stringify(SBP2_WORKAROUND_INQUIRY_36)
- 	", skip mode page 8 = "   __stringify(SBP2_WORKAROUND_MODE_SENSE_8)
- 	", fix capacity = "       __stringify(SBP2_WORKAROUND_FIX_CAPACITY)
-+	", delay inquiry = "      __stringify(SBP2_WORKAROUND_DELAY_INQUIRY)
- 	", override internal blacklist = " __stringify(SBP2_WORKAROUND_OVERRIDE)
- 	", or a combination)");
- 
-@@ -303,6 +310,11 @@ static const struct {
- 		.workarounds		= SBP2_WORKAROUND_INQUIRY_36 |
- 					  SBP2_WORKAROUND_MODE_SENSE_8,
- 	},
-+	/* DViCO Momobay FX-3A with TSB42AA9A bridge */ {
-+		.firmware_revision	= 0x002800,
-+		.model			= 0x000000,
-+		.workarounds		= SBP2_WORKAROUND_DELAY_INQUIRY,
-+	},
- 	/* Initio bridges, actually only needed for some older ones */ {
- 		.firmware_revision	= 0x000200,
- 		.model			= ~0,
-@@ -712,6 +724,9 @@ static void sbp2_login(struct work_struc
- 	PREPARE_DELAYED_WORK(&lu->work, sbp2_reconnect);
- 	sbp2_agent_reset(lu);
- 
-+	if (lu->tgt->workarounds & SBP2_WORKAROUND_DELAY_INQUIRY)
-+		ssleep(SBP2_INQUIRY_DELAY);
-+
- 	memset(&eight_bytes_lun, 0, sizeof(eight_bytes_lun));
- 	eight_bytes_lun.scsi_lun[0] = (lu->lun >> 8) & 0xff;
- 	eight_bytes_lun.scsi_lun[1] = lu->lun & 0xff;
-
--- 
-Stefan Richter
--=====-==--- --=- ---==
-http://arcgraph.de/sr/
-
-
-Add the same workaround as found in fw-sbp2 for feature parity and
-compatibility of the workarounds module parameter.
-
-Signed-off-by: Stefan Richter <stefanr at s5r6.in-berlin.de>
----
- drivers/ieee1394/sbp2.c |   12 ++++++++++++
- drivers/ieee1394/sbp2.h |    2 ++
- 2 files changed, 14 insertions(+)
-
-Index: linux/drivers/ieee1394/sbp2.c
-===================================================================
---- linux.orig/drivers/ieee1394/sbp2.c
-+++ linux/drivers/ieee1394/sbp2.c
-@@ -183,6 +183,9 @@ MODULE_PARM_DESC(exclusive_login, "Exclu
-  *   Avoids access beyond actual disk limits on devices with an off-by-one bug.
-  *   Don't use this with devices which don't have this bug.
-  *
-+ * - delay inquiry
-+ *   Wait extra SBP2_INQUIRY_DELAY seconds after login before SCSI inquiry.
-+ *
-  * - override internal blacklist
-  *   Instead of adding to the built-in blacklist, use only the workarounds
-  *   specified in the module load parameter.
-@@ -195,6 +198,7 @@ MODULE_PARM_DESC(workarounds, "Work arou
- 	", 36 byte inquiry = "    __stringify(SBP2_WORKAROUND_INQUIRY_36)
- 	", skip mode page 8 = "   __stringify(SBP2_WORKAROUND_MODE_SENSE_8)
- 	", fix capacity = "       __stringify(SBP2_WORKAROUND_FIX_CAPACITY)
-+	", delay inquiry = "      __stringify(SBP2_WORKAROUND_DELAY_INQUIRY)
- 	", override internal blacklist = " __stringify(SBP2_WORKAROUND_OVERRIDE)
- 	", or a combination)");
- 
-@@ -357,6 +361,11 @@ static const struct {
- 		.workarounds		= SBP2_WORKAROUND_INQUIRY_36 |
- 					  SBP2_WORKAROUND_MODE_SENSE_8,
- 	},
-+	/* DViCO Momobay FX-3A with TSB42AA9A bridge */ {
-+		.firmware_revision	= 0x002800,
-+		.model_id		= 0x000000,
-+		.workarounds		= SBP2_WORKAROUND_DELAY_INQUIRY,
-+	},
- 	/* Initio bridges, actually only needed for some older ones */ {
- 		.firmware_revision	= 0x000200,
- 		.model_id		= SBP2_ROM_VALUE_WILDCARD,
-@@ -914,6 +923,9 @@ static int sbp2_start_device(struct sbp2
- 	sbp2_agent_reset(lu, 1);
- 	sbp2_max_speed_and_size(lu);
- 
-+	if (lu->workarounds & SBP2_WORKAROUND_DELAY_INQUIRY)
-+		ssleep(SBP2_INQUIRY_DELAY);
-+
- 	error = scsi_add_device(lu->shost, 0, lu->ud->id, 0);
- 	if (error) {
- 		SBP2_ERR("scsi_add_device failed");
-Index: linux/drivers/ieee1394/sbp2.h
-===================================================================
---- linux.orig/drivers/ieee1394/sbp2.h
-+++ linux/drivers/ieee1394/sbp2.h
-@@ -343,6 +343,8 @@ enum sbp2lu_state_types {
- #define SBP2_WORKAROUND_INQUIRY_36	0x2
- #define SBP2_WORKAROUND_MODE_SENSE_8	0x4
- #define SBP2_WORKAROUND_FIX_CAPACITY	0x8
-+#define SBP2_WORKAROUND_DELAY_INQUIRY	0x10
-+#define SBP2_INQUIRY_DELAY		12
- #define SBP2_WORKAROUND_OVERRIDE	0x100
- 
- #endif /* SBP2_H */
-
--- 
-Stefan Richter
--=====-==--- --=- ---==
-http://arcgraph.de/sr/
-
-
-Like the old sbp2 driver, wait for the write transaction to the
-AGENT_RESET to complete before proceeding (after login, after reconnect,
-or in SCSI error handling).
-
-There is one occasion where AGENT_RESET is written to from atomic
-context when getting DEAD status for a command ORB.  There we still
-continue without waiting for the transaction to complete because this
-is more difficult to fix...
-
-Signed-off-by: Stefan Richter <stefanr at s5r6.in-berlin.de>
----
- drivers/firewire/fw-sbp2.c |   39 ++++++++++++++++++++++++++-----------
- 1 file changed, 28 insertions(+), 11 deletions(-)
-
-Index: linux/drivers/firewire/fw-sbp2.c
-===================================================================
---- linux.orig/drivers/firewire/fw-sbp2.c
-+++ linux/drivers/firewire/fw-sbp2.c
-@@ -603,29 +603,46 @@ sbp2_send_management_orb(struct sbp2_log
- 
- static void
- complete_agent_reset_write(struct fw_card *card, int rcode,
--			   void *payload, size_t length, void *data)
-+			   void *payload, size_t length, void *done)
- {
--	struct fw_transaction *t = data;
-+	complete(done);
-+}
-+
-+static void sbp2_agent_reset(struct sbp2_logical_unit *lu)
-+{
-+	struct fw_device *device = fw_device(lu->tgt->unit->device.parent);
-+	DECLARE_COMPLETION_ONSTACK(done);
-+	struct fw_transaction t;
-+	static u32 z;
- 
--	kfree(t);
-+	fw_send_request(device->card, &t, TCODE_WRITE_QUADLET_REQUEST,
-+			lu->tgt->node_id, lu->generation, device->max_speed,
-+			lu->command_block_agent_address + SBP2_AGENT_RESET,
-+			&z, sizeof(z), complete_agent_reset_write, &done);
-+	wait_for_completion(&done);
- }
- 
--static int sbp2_agent_reset(struct sbp2_logical_unit *lu)
-+static void
-+complete_agent_reset_write_no_wait(struct fw_card *card, int rcode,
-+				   void *payload, size_t length, void *data)
-+{
-+	kfree(data);
-+}
-+
-+static void sbp2_agent_reset_no_wait(struct sbp2_logical_unit *lu)
- {
- 	struct fw_device *device = fw_device(lu->tgt->unit->device.parent);
- 	struct fw_transaction *t;
--	static u32 zero;
-+	static u32 z;
- 
--	t = kzalloc(sizeof(*t), GFP_ATOMIC);
-+	t = kmalloc(sizeof(*t), GFP_ATOMIC);
- 	if (t == NULL)
--		return -ENOMEM;
-+		return;
- 
- 	fw_send_request(device->card, t, TCODE_WRITE_QUADLET_REQUEST,
- 			lu->tgt->node_id, lu->generation, device->max_speed,
- 			lu->command_block_agent_address + SBP2_AGENT_RESET,
--			&zero, sizeof(zero), complete_agent_reset_write, t);
--
--	return 0;
-+			&z, sizeof(z), complete_agent_reset_write_no_wait, t);
- }
- 
- static void sbp2_release_target(struct kref *kref)
-@@ -1110,7 +1127,7 @@ complete_command_orb(struct sbp2_orb *ba
- 
- 	if (status != NULL) {
- 		if (STATUS_GET_DEAD(*status))
--			sbp2_agent_reset(orb->lu);
-+			sbp2_agent_reset_no_wait(orb->lu);
- 
- 		switch (STATUS_GET_RESPONSE(*status)) {
- 		case SBP2_STATUS_REQUEST_COMPLETE:
-
--- 
-Stefan Richter
--=====-==--- --=- ---==
-http://arcgraph.de/sr/
-
-
-for easier readable logs if more than one SBP-2 device is present.
-
-Signed-off-by: Stefan Richter <stefanr at s5r6.in-berlin.de>
----
- drivers/firewire/fw-sbp2.c |   66 ++++++++++++++++++-------------------
- 1 file changed, 33 insertions(+), 33 deletions(-)
-
-Index: linux/drivers/firewire/fw-sbp2.c
-===================================================================
---- linux.orig/drivers/firewire/fw-sbp2.c
-+++ linux/drivers/firewire/fw-sbp2.c
-@@ -149,6 +149,7 @@ struct sbp2_target {
- 	struct kref kref;
- 	struct fw_unit *unit;
- 	struct list_head lu_list;
-+	const char *bus_id;
- 
- 	u64 management_agent_address;
- 	int directory_id;
-@@ -566,20 +567,20 @@ sbp2_send_management_orb(struct sbp2_log
- 
- 	retval = -EIO;
- 	if (sbp2_cancel_orbs(lu) == 0) {
--		fw_error("orb reply timed out, rcode=0x%02x\n",
--			 orb->base.rcode);
-+		fw_error("%s: orb reply timed out, rcode=0x%02x\n",
-+			 lu->tgt->bus_id, orb->base.rcode);
- 		goto out;
- 	}
- 
- 	if (orb->base.rcode != RCODE_COMPLETE) {
--		fw_error("management write failed, rcode 0x%02x\n",
--			 orb->base.rcode);
-+		fw_error("%s: management write failed, rcode 0x%02x\n",
-+			 lu->tgt->bus_id, orb->base.rcode);
- 		goto out;
- 	}
- 
- 	if (STATUS_GET_RESPONSE(orb->status) != 0 ||
- 	    STATUS_GET_SBP_STATUS(orb->status) != 0) {
--		fw_error("error status: %d:%d\n",
-+		fw_error("%s: error status: %d:%d\n", lu->tgt->bus_id,
- 			 STATUS_GET_RESPONSE(orb->status),
- 			 STATUS_GET_SBP_STATUS(orb->status));
- 		goto out;
-@@ -664,7 +665,7 @@ static void sbp2_release_target(struct k
- 		kfree(lu);
- 	}
- 	scsi_remove_host(shost);
--	fw_notify("released %s\n", tgt->unit->device.bus_id);
-+	fw_notify("released %s\n", tgt->bus_id);
- 
- 	put_device(&tgt->unit->device);
- 	scsi_host_put(shost);
-@@ -693,12 +694,11 @@ static void sbp2_login(struct work_struc
- {
- 	struct sbp2_logical_unit *lu =
- 		container_of(work, struct sbp2_logical_unit, work.work);
--	struct Scsi_Host *shost =
--		container_of((void *)lu->tgt, struct Scsi_Host, hostdata[0]);
-+	struct sbp2_target *tgt = lu->tgt;
-+	struct fw_device *device = fw_device(tgt->unit->device.parent);
-+	struct Scsi_Host *shost;
- 	struct scsi_device *sdev;
- 	struct scsi_lun eight_bytes_lun;
--	struct fw_unit *unit = lu->tgt->unit;
--	struct fw_device *device = fw_device(unit->device.parent);
- 	struct sbp2_login_response response;
- 	int generation, node_id, local_node_id;
- 
-@@ -715,14 +715,14 @@ static void sbp2_login(struct work_struc
- 		if (lu->retries++ < 5)
- 			sbp2_queue_work(lu, DIV_ROUND_UP(HZ, 5));
- 		else
--			fw_error("failed to login to %s LUN %04x\n",
--				 unit->device.bus_id, lu->lun);
-+			fw_error("%s: failed to login to LUN %04x\n",
-+				 tgt->bus_id, lu->lun);
- 		goto out;
- 	}
- 
--	lu->generation        = generation;
--	lu->tgt->node_id      = node_id;
--	lu->tgt->address_high = local_node_id << 16;
-+	lu->generation    = generation;
-+	tgt->node_id	  = node_id;
-+	tgt->address_high = local_node_id << 16;
- 
- 	/* Get command block agent offset and login id. */
- 	lu->command_block_agent_address =
-@@ -730,8 +730,8 @@ static void sbp2_login(struct work_struc
- 		response.command_block_agent.low;
- 	lu->login_id = LOGIN_RESPONSE_GET_LOGIN_ID(response);
- 
--	fw_notify("logged in to %s LUN %04x (%d retries)\n",
--		  unit->device.bus_id, lu->lun, lu->retries);
-+	fw_notify("%s: logged in to LUN %04x (%d retries)\n",
-+		  tgt->bus_id, lu->lun, lu->retries);
- 
- #if 0
- 	/* FIXME: The linux1394 sbp2 does this last step. */
-@@ -747,6 +747,7 @@ static void sbp2_login(struct work_struc
- 	memset(&eight_bytes_lun, 0, sizeof(eight_bytes_lun));
- 	eight_bytes_lun.scsi_lun[0] = (lu->lun >> 8) & 0xff;
- 	eight_bytes_lun.scsi_lun[1] = lu->lun & 0xff;
-+	shost = container_of((void *)tgt, struct Scsi_Host, hostdata[0]);
- 
- 	sdev = __scsi_add_device(shost, 0, 0,
- 				 scsilun_to_int(&eight_bytes_lun), lu);
-@@ -791,7 +792,7 @@ static void sbp2_login(struct work_struc
- 	 */
- 	PREPARE_DELAYED_WORK(&lu->work, sbp2_login);
-  out:
--	sbp2_target_put(lu->tgt);
-+	sbp2_target_put(tgt);
- }
- 
- static int sbp2_add_logical_unit(struct sbp2_target *tgt, int lun_entry)
-@@ -874,7 +875,7 @@ static int sbp2_scan_unit_dir(struct sbp
- 			if (timeout > tgt->mgt_orb_timeout)
- 				fw_notify("%s: config rom contains %ds "
- 					  "management ORB timeout, limiting "
--					  "to %ds\n", tgt->unit->device.bus_id,
-+					  "to %ds\n", tgt->bus_id,
- 					  timeout / 1000,
- 					  tgt->mgt_orb_timeout / 1000);
- 			break;
-@@ -902,7 +903,7 @@ static void sbp2_init_workarounds(struct
- 	if (w)
- 		fw_notify("Please notify linux1394-devel at lists.sourceforge.net "
- 			  "if you need the workarounds parameter for %s\n",
--			  tgt->unit->device.bus_id);
-+			  tgt->bus_id);
- 
- 	if (w & SBP2_WORKAROUND_OVERRIDE)
- 		goto out;
-@@ -924,8 +925,7 @@ static void sbp2_init_workarounds(struct
- 	if (w)
- 		fw_notify("Workarounds for %s: 0x%x "
- 			  "(firmware_revision 0x%06x, model_id 0x%06x)\n",
--			  tgt->unit->device.bus_id,
--			  w, firmware_revision, model);
-+			  tgt->bus_id, w, firmware_revision, model);
- 	tgt->workarounds = w;
- }
- 
-@@ -949,6 +949,7 @@ static int sbp2_probe(struct device *dev
- 	tgt->unit = unit;
- 	kref_init(&tgt->kref);
- 	INIT_LIST_HEAD(&tgt->lu_list);
-+	tgt->bus_id = unit->device.bus_id;
- 
- 	if (fw_device_enable_phys_dma(device) < 0)
- 		goto fail_shost_put;
-@@ -999,8 +1000,8 @@ static void sbp2_reconnect(struct work_s
- {
- 	struct sbp2_logical_unit *lu =
- 		container_of(work, struct sbp2_logical_unit, work.work);
--	struct fw_unit *unit = lu->tgt->unit;
--	struct fw_device *device = fw_device(unit->device.parent);
-+	struct sbp2_target *tgt = lu->tgt;
-+	struct fw_device *device = fw_device(tgt->unit->device.parent);
- 	int generation, node_id, local_node_id;
- 
- 	if (fw_device_is_shutdown(device))
-@@ -1015,8 +1016,7 @@ static void sbp2_reconnect(struct work_s
- 				     SBP2_RECONNECT_REQUEST,
- 				     lu->login_id, NULL) < 0) {
- 		if (lu->retries++ >= 5) {
--			fw_error("failed to reconnect to %s\n",
--				 unit->device.bus_id);
-+			fw_error("%s: failed to reconnect\n", tgt->bus_id);
- 			/* Fall back and try to log in again. */
- 			lu->retries = 0;
- 			PREPARE_DELAYED_WORK(&lu->work, sbp2_login);
-@@ -1025,17 +1025,17 @@ static void sbp2_reconnect(struct work_s
- 		goto out;
- 	}
- 
--	lu->generation        = generation;
--	lu->tgt->node_id      = node_id;
--	lu->tgt->address_high = local_node_id << 16;
-+	lu->generation    = generation;
-+	tgt->node_id      = node_id;
-+	tgt->address_high = local_node_id << 16;
- 
--	fw_notify("reconnected to %s LUN %04x (%d retries)\n",
--		  unit->device.bus_id, lu->lun, lu->retries);
-+	fw_notify("%s: reconnected to LUN %04x (%d retries)\n",
-+		  tgt->bus_id, lu->lun, lu->retries);
- 
- 	sbp2_agent_reset(lu);
- 	sbp2_cancel_orbs(lu);
-  out:
--	sbp2_target_put(lu->tgt);
-+	sbp2_target_put(tgt);
- }
- 
- static void sbp2_update(struct fw_unit *unit)
-@@ -1377,7 +1377,7 @@ static int sbp2_scsi_abort(struct scsi_c
- {
- 	struct sbp2_logical_unit *lu = cmd->device->hostdata;
- 
--	fw_notify("sbp2_scsi_abort\n");
-+	fw_notify("%s: sbp2_scsi_abort\n", lu->tgt->bus_id);
- 	sbp2_agent_reset(lu);
- 	sbp2_cancel_orbs(lu);
- 
-
--- 
-Stefan Richter
--=====-==--- --=- ---==
-http://arcgraph.de/sr/
-
-
-When a reconnect failed but re-login succeeded, __scsi_add_device was
-called again.
-
-Signed-off-by: Stefan Richter <stefanr at s5r6.in-berlin.de>
----
- drivers/firewire/fw-sbp2.c |    6 ++++++
- 1 file changed, 6 insertions(+)
-
-Index: linux/drivers/firewire/fw-sbp2.c
-===================================================================
---- linux.orig/drivers/firewire/fw-sbp2.c
-+++ linux/drivers/firewire/fw-sbp2.c
-@@ -741,6 +741,12 @@ static void sbp2_login(struct work_struc
- 	PREPARE_DELAYED_WORK(&lu->work, sbp2_reconnect);
- 	sbp2_agent_reset(lu);
- 
-+	/* This was a re-login. */
-+	if (lu->sdev) {
-+		sbp2_cancel_orbs(lu);
-+		goto out;
-+	}
-+
- 	if (lu->tgt->workarounds & SBP2_WORKAROUND_DELAY_INQUIRY)
- 		ssleep(SBP2_INQUIRY_DELAY);
- 
-
--- 
-Stefan Richter
--=====-==--- --=- ---==
-http://arcgraph.de/sr/
-
-
-If fw-sbp2 was too late with requesting the reconnect, the target would
-reject this.  In this case, log out before attempting the reconnect.
-Else several firmwares will deny the re-login because they somehow
-didn't invalidate the old login.
-
-Also, don't retry reconnects in this situation.  The retries won't
-succeed either.
-
-These changes improve chances for successful re-login and shorten the
-period during which the logical unit is inaccessible.
-
-Signed-off-by: Stefan Richter <stefanr at s5r6.in-berlin.de>
----
- drivers/firewire/fw-sbp2.c |   17 +++++++++++++++--
- 1 file changed, 15 insertions(+), 2 deletions(-)
-
-Index: linux/drivers/firewire/fw-sbp2.c
-===================================================================
---- linux.orig/drivers/firewire/fw-sbp2.c
-+++ linux/drivers/firewire/fw-sbp2.c
-@@ -710,6 +710,11 @@ static void sbp2_login(struct work_struc
- 	node_id       = device->node_id;
- 	local_node_id = device->card->node_id;
- 
-+	/* If this is a re-login attempt, log out, or we might be rejected. */
-+	if (lu->sdev)
-+		sbp2_send_management_orb(lu, device->node_id, generation,
-+				SBP2_LOGOUT_REQUEST, lu->login_id, NULL);
-+
- 	if (sbp2_send_management_orb(lu, node_id, generation,
- 				SBP2_LOGIN_REQUEST, lu->lun, &response) < 0) {
- 		if (lu->retries++ < 5)
-@@ -1021,9 +1026,17 @@ static void sbp2_reconnect(struct work_s
- 	if (sbp2_send_management_orb(lu, node_id, generation,
- 				     SBP2_RECONNECT_REQUEST,
- 				     lu->login_id, NULL) < 0) {
--		if (lu->retries++ >= 5) {
-+		/*
-+		 * If reconnect was impossible even though we are in the
-+		 * current generation, fall back and try to log in again.
-+		 *
-+		 * We could check for "Function rejected" status, but
-+		 * looking at the bus generation as simpler and more general.
-+		 */
-+		smp_rmb(); /* get current card generation */
-+		if (generation == device->card->generation ||
-+		    lu->retries++ >= 5) {
- 			fw_error("%s: failed to reconnect\n", tgt->bus_id);
--			/* Fall back and try to log in again. */
- 			lu->retries = 0;
- 			PREPARE_DELAYED_WORK(&lu->work, sbp2_login);
- 		}
-
--- 
-Stefan Richter
--=====-==--- --=- ---==
-http://arcgraph.de/sr/
-
-
-Signed-off-by: Stefan Richter <stefanr at s5r6.in-berlin.de>
----
- drivers/firewire/fw-sbp2.c |   14 +++++++-------
- 1 file changed, 7 insertions(+), 7 deletions(-)
-
-Index: linux/drivers/firewire/fw-sbp2.c
-===================================================================
---- linux.orig/drivers/firewire/fw-sbp2.c
-+++ linux/drivers/firewire/fw-sbp2.c
-@@ -28,15 +28,15 @@
-  * and many others.
-  */
- 
-+#include <linux/blkdev.h>
-+#include <linux/delay.h>
-+#include <linux/device.h>
-+#include <linux/dma-mapping.h>
- #include <linux/kernel.h>
-+#include <linux/mod_devicetable.h>
- #include <linux/module.h>
- #include <linux/moduleparam.h>
--#include <linux/mod_devicetable.h>
--#include <linux/delay.h>
--#include <linux/device.h>
- #include <linux/scatterlist.h>
--#include <linux/dma-mapping.h>
--#include <linux/blkdev.h>
- #include <linux/string.h>
- #include <linux/stringify.h>
- #include <linux/timer.h>
-@@ -48,9 +48,9 @@
- #include <scsi/scsi_device.h>
- #include <scsi/scsi_host.h>
- 
--#include "fw-transaction.h"
--#include "fw-topology.h"
- #include "fw-device.h"
-+#include "fw-topology.h"
-+#include "fw-transaction.h"
- 
- /*
-  * So far only bridges from Oxford Semiconductor are known to support
-
--- 
-Stefan Richter
--=====-==--- --=- ---==
-http://arcgraph.de/sr/
-
-
-While fw-sbp2 takes the necessary time to reconnect to a logical unit
-after bus reset, the SCSI core keeps sending new commands.  They are all
-immediately completed with host busy status, and application clients or
-filesystems will break quickly.  The SCSI device might even be taken
-offline:  http://bugzilla.kernel.org/show_bug.cgi?id=9734
-
-The only remedy seems to be to block the SCSI device until reconnect.
-Alas the SCSI core has no useful API to block only one logical unit i.e.
-the scsi_device, therefore we block the entire Scsi_Host.  This
-currently corresponds to an SBP-2 target.  In case of targets with
-multiple logical units, we need to satisfy the dependencies between
-logical units by carefully tracking the blocking state of the target and
-its units.  We block all logical units of a target as soon as one of
-them needs to be blocked, and keep them blocked until all of them are
-ready to be unblocked.
-
-Furthermore, as the history of the old sbp2 driver has shown, the
-scsi_block_requests() API is a minefield with high potential of
-deadlocks.  We therefore take extra measures to keep logical units
-unblocked during __scsi_add_device() and during shutdown.
-
-Signed-off-by: Stefan Richter <stefanr at s5r6.in-berlin.de>
----
- drivers/firewire/fw-sbp2.c |   71 +++++++++++++++++++++++++++++++++++--
- 1 file changed, 69 insertions(+), 2 deletions(-)
-
-Index: linux/drivers/firewire/fw-sbp2.c
-===================================================================
---- linux.orig/drivers/firewire/fw-sbp2.c
-+++ linux/drivers/firewire/fw-sbp2.c
-@@ -41,6 +41,7 @@
- #include <linux/stringify.h>
- #include <linux/timer.h>
- #include <linux/workqueue.h>
-+#include <asm/atomic.h>
- #include <asm/system.h>
- 
- #include <scsi/scsi.h>
-@@ -139,6 +140,7 @@ struct sbp2_logical_unit {
- 	int generation;
- 	int retries;
- 	struct delayed_work work;
-+	atomic_t blocked;
- };
- 
- /*
-@@ -157,6 +159,9 @@ struct sbp2_target {
- 	int address_high;
- 	unsigned int workarounds;
- 	unsigned int mgt_orb_timeout;
-+
-+	atomic_t dont_block;
-+	atomic_t blocked;
- };
- 
- /*
-@@ -646,6 +651,53 @@ static void sbp2_agent_reset_no_wait(str
- 			&z, sizeof(z), complete_agent_reset_write_no_wait, t);
- }
- 
-+/*
-+ * Blocks lu->tgt if all of the following conditions are met:
-+ *   - Login, INQUIRY, and high-level SCSI setup of all logical units of the
-+ *     target have been successfully finished (indicated by dont_block == 0).
-+ *   - The lu->generation is stale.  sbp2_reconnect will unblock lu later.
-+ */
-+static void sbp2_conditionally_block(struct sbp2_logical_unit *lu)
-+{
-+	struct fw_card *card = fw_device(lu->tgt->unit->device.parent)->card;
-+
-+	if (!atomic_read(&lu->tgt->dont_block) &&
-+	    lu->generation != card->generation &&
-+	    atomic_cmpxchg(&lu->blocked, 0, 1) == 0) {
-+
-+		/* raise the block count of the target */
-+		if (atomic_inc_return(&lu->tgt->blocked) == 1) {
-+			scsi_block_requests(lu->sdev->host);
-+			fw_notify("blocked %s\n", lu->tgt->bus_id);
-+		}
-+	}
-+}
-+
-+/* Unblocks lu->tgt as soon as all its logical units can be unblocked. */
-+static void sbp2_conditionally_unblock(struct sbp2_logical_unit *lu)
-+{
-+	if (atomic_cmpxchg(&lu->blocked, 1, 0) == 1) {
-+
-+		/* lower the block count of the target */
-+		if (atomic_dec_and_test(&lu->tgt->blocked)) {
-+			scsi_unblock_requests(lu->sdev->host);
-+			fw_notify("unblocked %s\n", lu->tgt->bus_id);
-+		}
-+	}
-+}
-+
-+
-+/* Prevents future blocking of tgt and then unblocks it. */
-+static void sbp2_unblock(struct sbp2_target *tgt)
-+{
-+	struct Scsi_Host *shost =
-+		container_of((void *)tgt, struct Scsi_Host, hostdata[0]);
-+
-+	atomic_inc(&tgt->dont_block);
-+	smp_wmb();
-+	scsi_unblock_requests(shost);
-+}
-+
- static void sbp2_release_target(struct kref *kref)
- {
- 	struct sbp2_target *tgt = container_of(kref, struct sbp2_target, kref);
-@@ -654,6 +706,12 @@ static void sbp2_release_target(struct k
- 		container_of((void *)tgt, struct Scsi_Host, hostdata[0]);
- 	struct fw_device *device = fw_device(tgt->unit->device.parent);
- 
-+	/*
-+	 * Make sure that the target is unblocked and won't be blocked anymore
-+	 * before scsi_remove_device() is called.  Else it will deadlock.
-+	 */
-+	sbp2_unblock(tgt);
-+
- 	list_for_each_entry_safe(lu, next, &tgt->lu_list, link) {
- 		if (lu->sdev)
- 			scsi_remove_device(lu->sdev);
-@@ -717,11 +775,14 @@ static void sbp2_login(struct work_struc
- 
- 	if (sbp2_send_management_orb(lu, node_id, generation,
- 				SBP2_LOGIN_REQUEST, lu->lun, &response) < 0) {
--		if (lu->retries++ < 5)
-+		if (lu->retries++ < 5) {
- 			sbp2_queue_work(lu, DIV_ROUND_UP(HZ, 5));
--		else
-+		} else {
- 			fw_error("%s: failed to login to LUN %04x\n",
- 				 tgt->bus_id, lu->lun);
-+			/* Let any waiting I/O fail from now on. */
-+			sbp2_unblock(lu->tgt);
-+		}
- 		goto out;
- 	}
- 
-@@ -749,6 +810,7 @@ static void sbp2_login(struct work_struc
- 	/* This was a re-login. */
- 	if (lu->sdev) {
- 		sbp2_cancel_orbs(lu);
-+		sbp2_conditionally_unblock(lu);
- 		goto out;
- 	}
- 
-@@ -786,6 +848,8 @@ static void sbp2_login(struct work_struc
- 		 * Can you believe it?  Everything went well.
- 		 */
- 		lu->sdev = sdev;
-+		smp_wmb();  /* We need lu->sdev when we want to block lu. */
-+		atomic_dec(&lu->tgt->dont_block);
- 		scsi_device_put(sdev);
- 		goto out;
- 	}
-@@ -828,6 +892,7 @@ static int sbp2_add_logical_unit(struct 
- 	lu->sdev = NULL;
- 	lu->lun  = lun_entry & 0xffff;
- 	lu->retries = 0;
-+	atomic_inc(&tgt->dont_block);
- 	INIT_LIST_HEAD(&lu->orb_list);
- 	INIT_DELAYED_WORK(&lu->work, sbp2_login);
- 
-@@ -1053,6 +1118,7 @@ static void sbp2_reconnect(struct work_s
- 
- 	sbp2_agent_reset(lu);
- 	sbp2_cancel_orbs(lu);
-+	sbp2_conditionally_unblock(lu);
-  out:
- 	sbp2_target_put(tgt);
- }
-@@ -1172,6 +1238,7 @@ complete_command_orb(struct sbp2_orb *ba
- 		 * or when sending the write (less likely).
- 		 */
- 		result = DID_BUS_BUSY << 16;
-+		sbp2_conditionally_block(orb->lu);
- 	}
- 
- 	dma_unmap_single(device->card->device, orb->base.request_bus,
-
--- 
-Stefan Richter
--=====-==--- --=- ---==
-http://arcgraph.de/sr/
-
-Since "fw-sbp2: fix I/O errors during reconnect", a Scsi_Host will be
-blocked as soon as a command failed due to bus generation change.  Now
-we also block it when fw-core signalled a bus reset via sbp2_update.
-This will avoid some command failures and retries (but not all because
-commands are injected from tasklet context while sbp2_update runs from
-workqueue thread context).
-
-Signed-off-by: Stefan Richter <stefanr at s5r6.in-berlin.de>
----
- drivers/firewire/fw-sbp2.c |    1 +
- 1 file changed, 1 insertion(+)
-
-Index: linux/drivers/firewire/fw-sbp2.c
-===================================================================
---- linux.orig/drivers/firewire/fw-sbp2.c
-+++ linux/drivers/firewire/fw-sbp2.c
-@@ -1135,6 +1135,7 @@ static void sbp2_update(struct fw_unit *
- 	 * Iteration over tgt->lu_list is therefore safe here.
- 	 */
- 	list_for_each_entry(lu, &tgt->lu_list, link) {
-+		sbp2_conditionally_block(lu);
- 		lu->retries = 0;
- 		sbp2_queue_work(lu, 0);
- 	}
-
--- 
-Stefan Richter
--=====-==--- --=- --==-
-http://arcgraph.de/sr/
-
-
-fw-sbp2 is unable to reconnect while performing __scsi_add_device
-because there is only a single workqueue thread context available for
-both at the moment.  This should be fixed eventually.
-
-An actual failure of __scsi_add_device is easy to handle, but an
-incomplete execution of __scsi_add_device with an sdev returned would
-remain undetected and leave the SBP-2 target unusable.
-
-Therefore we use a workaround:  If there was a bus reset during
-__scsi_add_device (i.e. during the SCSI probe), we remove the new sdev
-immediately, log out, and attempt login and SCSI probe again.
-
-Signed-off-by: Stefan Richter <stefanr at s5r6.in-berlin.de>
-Signed-off-by: Jarod Wilson <jwilson at redhat.com>
----
-
-The previous patch "firewire: fw-sbp2: retry login if scsi_device was
-offlined early" should be folded into this one before upstream
-submission.
-
- drivers/firewire/fw-sbp2.c |   43 ++++++++++++++++---------------------
- 1 file changed, 19 insertions(+), 24 deletions(-)
-
-Index: linux/drivers/firewire/fw-sbp2.c
-===================================================================
---- linux.orig/drivers/firewire/fw-sbp2.c
-+++ linux/drivers/firewire/fw-sbp2.c
-@@ -824,36 +824,31 @@ static void sbp2_login(struct work_struc
- 
- 	sdev = __scsi_add_device(shost, 0, 0,
- 				 scsilun_to_int(&eight_bytes_lun), lu);
--	if (IS_ERR(sdev)) {
--		/*
--		 * The most frequent cause for __scsi_add_device() to fail
--		 * is a bus reset while sending the SCSI INQUIRY.  Try again.
--		 */
-+	/*
-+	 * FIXME:  We are unable to perform reconnects while in sbp2_login().
-+	 * Therefore __scsi_add_device() will get into trouble if a bus reset
-+	 * happens in parallel.  It will either fail or leave us with an
-+	 * unusable sdev.  As a workaround we check for this and retry the
-+	 * whole login and SCSI probing.
-+	 */
-+
-+	if (IS_ERR(sdev))
- 		goto out_logout_login;
- 
--	} else if (sdev->sdev_state == SDEV_OFFLINE) {
--		/*
--		 * FIXME:  We are unable to perform reconnects while in
--		 * sbp2_login().  Therefore __scsi_add_device() will get
--		 * into trouble if a bus reset happens in parallel.
--		 * It will either fail (that's OK, see above) or take sdev
--		 * offline.  Here is a crude workaround for the latter.
--		 */
--		scsi_device_put(sdev);
-+	scsi_device_put(sdev);
-+
-+	smp_rmb(); /* get current card generation */
-+	if (generation != device->card->generation) {
- 		scsi_remove_device(sdev);
- 		goto out_logout_login;
--
--	} else {
--		/*
--		 * Can you believe it?  Everything went well.
--		 */
--		lu->sdev = sdev;
--		smp_wmb();  /* We need lu->sdev when we want to block lu. */
--		atomic_dec(&lu->tgt->dont_block);
--		scsi_device_put(sdev);
--		goto out;
- 	}
- 
-+	/* Everything went well. */
-+	lu->sdev = sdev;
-+	smp_wmb();  /* We need lu->sdev when we want to block lu. */
-+	atomic_dec(&lu->tgt->dont_block);
-+	goto out;
-+
-  out_logout_login:
- 	smp_rmb(); /* generation may have changed */
- 	generation = device->generation;
-
--- 
-Stefan Richter
--=====-==--- --=- -=---
-http://arcgraph.de/sr/
-
-

linux-2.6-firewire-git-update.patch:

Index: linux-2.6-firewire-git-update.patch
===================================================================
RCS file: /cvs/pkgs/rpms/kernel/devel/linux-2.6-firewire-git-update.patch,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -r1.6 -r1.7
--- linux-2.6-firewire-git-update.patch	12 Feb 2008 16:41:53 -0000	1.6
+++ linux-2.6-firewire-git-update.patch	21 Feb 2008 04:40:21 -0000	1.7
@@ -1,10 +1,272 @@
-diff -Naurp linux-2.6-git/drivers/firewire/fw-sbp2.c firewire-git/drivers/firewire/fw-sbp2.c
---- linux-2.6-git/drivers/firewire/fw-sbp2.c	2008-02-12 10:05:41.000000000 -0500
-+++ firewire-git/drivers/firewire/fw-sbp2.c	2008-02-12 10:27:23.000000000 -0500
-@@ -141,15 +141,13 @@ struct sbp2_logical_unit {
+git diff in linux1394-git tree vs. 2.6.25-rc1, 02/20/2008
+
+ Documentation/debugging-via-ohci1394.txt |   17 +-
+ drivers/firewire/fw-cdev.c               |    8 +-
+ drivers/firewire/fw-device.c             |   48 +++--
+ drivers/firewire/fw-device.h             |    2 +-
+ drivers/firewire/fw-sbp2.c               |  358 +++++++++++++++++++++++-------
+ drivers/ieee1394/sbp2.c                  |   22 ++-
+ drivers/ieee1394/sbp2.h                  |    2 +
+ 7 files changed, 345 insertions(+), 112 deletions(-)
+
+---
+
+diff --git a/Documentation/debugging-via-ohci1394.txt b/Documentation/debugging-via-ohci1394.txt
+index de4804e..c360d4e 100644
+--- a/Documentation/debugging-via-ohci1394.txt
++++ b/Documentation/debugging-via-ohci1394.txt
+@@ -36,14 +36,15 @@ available (notebooks) or too slow for extensive debug information (like ACPI).
+ Drivers
+ -------
+ 
+-The OHCI-1394 drivers in drivers/firewire and drivers/ieee1394 initialize
+-the OHCI-1394 controllers to a working state and can be used to enable
+-physical DMA. By default you only have to load the driver, and physical
+-DMA access will be granted to all remote nodes, but it can be turned off
+-when using the ohci1394 driver.
+-
+-Because these drivers depend on the PCI enumeration to be completed, an
+-initialization routine which can runs pretty early (long before console_init(),
++The ohci1394 driver in drivers/ieee1394 initializes the OHCI-1394 controllers
++to a working state and enables physical DMA by default for all remote nodes.
++This can be turned off by ohci1394's module parameter phys_dma=0.
++
++The alternative firewire-ohci driver in drivers/firewire uses filtered physical
++DMA, hence is not yet suitable for remote debugging.
++
++Because ohci1394 depends on the PCI enumeration to be completed, an
++initialization routine which runs pretty early (long before console_init()
+ which makes the printk buffer appear on the console can be called) was written.
+ 
+ To activate it, enable CONFIG_PROVIDE_OHCI1394_DMA_INIT (Kernel hacking menu:
+diff --git a/drivers/firewire/fw-cdev.c b/drivers/firewire/fw-cdev.c
+index 7e73cba..44ccee2 100644
+--- a/drivers/firewire/fw-cdev.c
++++ b/drivers/firewire/fw-cdev.c
+@@ -109,15 +109,17 @@ static int fw_device_op_open(struct inode *inode, struct file *file)
+ 	struct client *client;
+ 	unsigned long flags;
+ 
+-	device = fw_device_from_devt(inode->i_rdev);
++	device = fw_device_get_by_devt(inode->i_rdev);
+ 	if (device == NULL)
+ 		return -ENODEV;
+ 
+ 	client = kzalloc(sizeof(*client), GFP_KERNEL);
+-	if (client == NULL)
++	if (client == NULL) {
++		fw_device_put(device);
+ 		return -ENOMEM;
++	}
+ 
+-	client->device = fw_device_get(device);
++	client->device = device;
+ 	INIT_LIST_HEAD(&client->event_list);
+ 	INIT_LIST_HEAD(&client->resource_list);
+ 	spin_lock_init(&client->lock);
+diff --git a/drivers/firewire/fw-device.c b/drivers/firewire/fw-device.c
+index de9066e..2ab13e0 100644
+--- a/drivers/firewire/fw-device.c
++++ b/drivers/firewire/fw-device.c
+@@ -358,12 +358,9 @@ static ssize_t
+ guid_show(struct device *dev, struct device_attribute *attr, char *buf)
+ {
+ 	struct fw_device *device = fw_device(dev);
+-	u64 guid;
+ 
+-	guid = ((u64)device->config_rom[3] << 32) | device->config_rom[4];
+-
+-	return snprintf(buf, PAGE_SIZE, "0x%016llx\n",
+-			(unsigned long long)guid);
++	return snprintf(buf, PAGE_SIZE, "0x%08x%08x\n",
++			device->config_rom[3], device->config_rom[4]);
+ }
+ 
+ static struct device_attribute fw_device_attributes[] = {
+@@ -610,12 +607,14 @@ static DECLARE_RWSEM(idr_rwsem);
+ static DEFINE_IDR(fw_device_idr);
+ int fw_cdev_major;
+ 
+-struct fw_device *fw_device_from_devt(dev_t devt)
++struct fw_device *fw_device_get_by_devt(dev_t devt)
+ {
+ 	struct fw_device *device;
+ 
+ 	down_read(&idr_rwsem);
+ 	device = idr_find(&fw_device_idr, MINOR(devt));
++	if (device)
++		fw_device_get(device);
+ 	up_read(&idr_rwsem);
+ 
+ 	return device;
+@@ -627,13 +626,14 @@ static void fw_device_shutdown(struct work_struct *work)
+ 		container_of(work, struct fw_device, work.work);
+ 	int minor = MINOR(device->device.devt);
+ 
+-	down_write(&idr_rwsem);
+-	idr_remove(&fw_device_idr, minor);
+-	up_write(&idr_rwsem);
+-
+ 	fw_device_cdev_remove(device);
+ 	device_for_each_child(&device->device, NULL, shutdown_unit);
+ 	device_unregister(&device->device);
++
++	down_write(&idr_rwsem);
++	idr_remove(&fw_device_idr, minor);
++	up_write(&idr_rwsem);
++	fw_device_put(device);
+ }
+ 
+ static struct device_type fw_device_type = {
+@@ -682,10 +682,13 @@ static void fw_device_init(struct work_struct *work)
+ 	}
+ 
+ 	err = -ENOMEM;
++
++	fw_device_get(device);
+ 	down_write(&idr_rwsem);
+ 	if (idr_pre_get(&fw_device_idr, GFP_KERNEL))
+ 		err = idr_get_new(&fw_device_idr, device, &minor);
+ 	up_write(&idr_rwsem);
++
+ 	if (err < 0)
+ 		goto error;
+ 
+@@ -717,13 +720,22 @@ static void fw_device_init(struct work_struct *work)
+ 	 */
+ 	if (atomic_cmpxchg(&device->state,
+ 		    FW_DEVICE_INITIALIZING,
+-		    FW_DEVICE_RUNNING) == FW_DEVICE_SHUTDOWN)
++		    FW_DEVICE_RUNNING) == FW_DEVICE_SHUTDOWN) {
+ 		fw_device_shutdown(&device->work.work);
+-	else
+-		fw_notify("created new fw device %s "
+-			  "(%d config rom retries, S%d00)\n",
+-			  device->device.bus_id, device->config_rom_retries,
+-			  1 << device->max_speed);
++	} else {
++		if (device->config_rom_retries)
++			fw_notify("created device %s: GUID %08x%08x, S%d00, "
++				  "%d config ROM retries\n",
++				  device->device.bus_id,
++				  device->config_rom[3], device->config_rom[4],
++				  1 << device->max_speed,
++				  device->config_rom_retries);
++		else
++			fw_notify("created device %s: GUID %08x%08x, S%d00\n",
++				  device->device.bus_id,
++				  device->config_rom[3], device->config_rom[4],
++				  1 << device->max_speed);
++	}
+ 
+ 	/*
+ 	 * Reschedule the IRM work if we just finished reading the
+@@ -741,7 +753,9 @@ static void fw_device_init(struct work_struct *work)
+ 	idr_remove(&fw_device_idr, minor);
+ 	up_write(&idr_rwsem);
+  error:
+-	put_device(&device->device);
++	fw_device_put(device);		/* fw_device_idr's reference */
++
++	put_device(&device->device);	/* our reference */
+ }
+ 
+ static int update_unit(struct device *dev, void *data)
+diff --git a/drivers/firewire/fw-device.h b/drivers/firewire/fw-device.h
+index 0854fe2..43808c0 100644
+--- a/drivers/firewire/fw-device.h
++++ b/drivers/firewire/fw-device.h
+@@ -77,13 +77,13 @@ fw_device_is_shutdown(struct fw_device *device)
+ }
+ 
+ struct fw_device *fw_device_get(struct fw_device *device);
++struct fw_device *fw_device_get_by_devt(dev_t devt);
+ void fw_device_put(struct fw_device *device);
+ int fw_device_enable_phys_dma(struct fw_device *device);
+ 
+ void fw_device_cdev_update(struct fw_device *device);
+ void fw_device_cdev_remove(struct fw_device *device);
+ 
+-struct fw_device *fw_device_from_devt(dev_t devt);
+ extern int fw_cdev_major;
+ 
+ struct fw_unit {
+diff --git a/drivers/firewire/fw-sbp2.c b/drivers/firewire/fw-sbp2.c
+index 19ece9b..5259491 100644
+--- a/drivers/firewire/fw-sbp2.c
++++ b/drivers/firewire/fw-sbp2.c
+@@ -28,14 +28,15 @@
+  * and many others.
+  */
+ 
++#include <linux/blkdev.h>
++#include <linux/delay.h>
++#include <linux/device.h>
++#include <linux/dma-mapping.h>
+ #include <linux/kernel.h>
++#include <linux/mod_devicetable.h>
+ #include <linux/module.h>
+ #include <linux/moduleparam.h>
+-#include <linux/mod_devicetable.h>
+-#include <linux/device.h>
+ #include <linux/scatterlist.h>
+-#include <linux/dma-mapping.h>
+-#include <linux/blkdev.h>
+ #include <linux/string.h>
+ #include <linux/stringify.h>
+ #include <linux/timer.h>
+@@ -47,9 +48,9 @@
+ #include <scsi/scsi_device.h>
+ #include <scsi/scsi_host.h>
+ 
+-#include "fw-transaction.h"
+-#include "fw-topology.h"
+ #include "fw-device.h"
++#include "fw-topology.h"
++#include "fw-transaction.h"
+ 
+ /*
+  * So far only bridges from Oxford Semiconductor are known to support
+@@ -82,6 +83,9 @@ MODULE_PARM_DESC(exclusive_login, "Exclusive login to sbp2 device "
+  *   Avoids access beyond actual disk limits on devices with an off-by-one bug.
+  *   Don't use this with devices which don't have this bug.
+  *
++ * - delay inquiry
++ *   Wait extra SBP2_INQUIRY_DELAY seconds after login before SCSI inquiry.
++ *
+  * - override internal blacklist
+  *   Instead of adding to the built-in blacklist, use only the workarounds
+  *   specified in the module load parameter.
+@@ -91,6 +95,8 @@ MODULE_PARM_DESC(exclusive_login, "Exclusive login to sbp2 device "
+ #define SBP2_WORKAROUND_INQUIRY_36	0x2
+ #define SBP2_WORKAROUND_MODE_SENSE_8	0x4
+ #define SBP2_WORKAROUND_FIX_CAPACITY	0x8
++#define SBP2_WORKAROUND_DELAY_INQUIRY	0x10
++#define SBP2_INQUIRY_DELAY		12
+ #define SBP2_WORKAROUND_OVERRIDE	0x100
+ 
+ static int sbp2_param_workarounds;
+@@ -100,6 +106,7 @@ MODULE_PARM_DESC(workarounds, "Work around device bugs (default = 0"
+ 	", 36 byte inquiry = "    __stringify(SBP2_WORKAROUND_INQUIRY_36)
+ 	", skip mode page 8 = "   __stringify(SBP2_WORKAROUND_MODE_SENSE_8)
+ 	", fix capacity = "       __stringify(SBP2_WORKAROUND_FIX_CAPACITY)
++	", delay inquiry = "      __stringify(SBP2_WORKAROUND_DELAY_INQUIRY)
+ 	", override internal blacklist = " __stringify(SBP2_WORKAROUND_OVERRIDE)
+ 	", or a combination)");
+ 
+@@ -132,6 +139,7 @@ struct sbp2_logical_unit {
+ 	int generation;
+ 	int retries;
+ 	struct delayed_work work;
++	bool blocked;
+ };
+ 
+ /*
+@@ -141,16 +149,18 @@ struct sbp2_logical_unit {
  struct sbp2_target {
  	struct kref kref;
  	struct fw_unit *unit;
++	const char *bus_id;
 +	struct list_head lu_list;
  
  	u64 management_agent_address;
@@ -17,9 +279,13 @@
 -
 +	unsigned int workarounds;
  	unsigned int mgt_orb_timeout;
++
++	int dont_block;	/* counter for each logical unit */
++	int blocked;	/* ditto */
  };
  
-@@ -160,7 +158,7 @@ struct sbp2_target {
+ /*
+@@ -160,7 +170,7 @@ struct sbp2_target {
   */
  #define SBP2_MIN_LOGIN_ORB_TIMEOUT	5000U	/* Timeout in ms */
  #define SBP2_MAX_LOGIN_ORB_TIMEOUT	40000U	/* Timeout in ms */
@@ -28,7 +294,7 @@
  #define SBP2_ORB_NULL			0x80000000
  #define SBP2_MAX_SG_ELEMENT_LENGTH	0xf000
  
-@@ -297,7 +295,7 @@ struct sbp2_command_orb {
+@@ -297,7 +307,7 @@ struct sbp2_command_orb {
  static const struct {
  	u32 firmware_revision;
  	u32 model;
@@ -37,7 +303,19 @@
  } sbp2_workarounds_table[] = {
  	/* DViCO Momobay CX-1 with TSB42AA9 bridge */ {
  		.firmware_revision	= 0x002800,
-@@ -501,6 +499,9 @@ sbp2_send_management_orb(struct sbp2_log
+@@ -305,6 +315,11 @@ static const struct {
+ 		.workarounds		= SBP2_WORKAROUND_INQUIRY_36 |
+ 					  SBP2_WORKAROUND_MODE_SENSE_8,
+ 	},
++	/* DViCO Momobay FX-3A with TSB42AA9A bridge */ {
++		.firmware_revision	= 0x002800,
++		.model			= 0x000000,
++		.workarounds		= SBP2_WORKAROUND_DELAY_INQUIRY,
++	},
+ 	/* Initio bridges, actually only needed for some older ones */ {
+ 		.firmware_revision	= 0x000200,
+ 		.model			= ~0,
+@@ -501,6 +516,9 @@ sbp2_send_management_orb(struct sbp2_logical_unit *lu, int node_id,
  	unsigned int timeout;
  	int retval = -ENOMEM;
  
@@ -47,20 +325,235 @@
  	orb = kzalloc(sizeof(*orb), GFP_ATOMIC);
  	if (orb == NULL)
  		return -ENOMEM;
-@@ -627,10 +628,8 @@ static void sbp2_release_target(struct k
- 		if (lu->sdev)
- 			scsi_remove_device(lu->sdev);
+@@ -553,20 +571,20 @@ sbp2_send_management_orb(struct sbp2_logical_unit *lu, int node_id,
+ 
+ 	retval = -EIO;
+ 	if (sbp2_cancel_orbs(lu) == 0) {
+-		fw_error("orb reply timed out, rcode=0x%02x\n",
+-			 orb->base.rcode);
++		fw_error("%s: orb reply timed out, rcode=0x%02x\n",
++			 lu->tgt->bus_id, orb->base.rcode);
+ 		goto out;
+ 	}
+ 
+ 	if (orb->base.rcode != RCODE_COMPLETE) {
+-		fw_error("management write failed, rcode 0x%02x\n",
+-			 orb->base.rcode);
++		fw_error("%s: management write failed, rcode 0x%02x\n",
++			 lu->tgt->bus_id, orb->base.rcode);
+ 		goto out;
+ 	}
+ 
+ 	if (STATUS_GET_RESPONSE(orb->status) != 0 ||
+ 	    STATUS_GET_SBP_STATUS(orb->status) != 0) {
+-		fw_error("error status: %d:%d\n",
++		fw_error("%s: error status: %d:%d\n", lu->tgt->bus_id,
+ 			 STATUS_GET_RESPONSE(orb->status),
+ 			 STATUS_GET_SBP_STATUS(orb->status));
+ 		goto out;
+@@ -590,29 +608,147 @@ sbp2_send_management_orb(struct sbp2_logical_unit *lu, int node_id,
+ 
+ static void
+ complete_agent_reset_write(struct fw_card *card, int rcode,
+-			   void *payload, size_t length, void *data)
++			   void *payload, size_t length, void *done)
++{
++	complete(done);
++}
++
++static void sbp2_agent_reset(struct sbp2_logical_unit *lu)
+ {
+-	struct fw_transaction *t = data;
++	struct fw_device *device = fw_device(lu->tgt->unit->device.parent);
++	DECLARE_COMPLETION_ONSTACK(done);
++	struct fw_transaction t;
++	static u32 z;
++
++	fw_send_request(device->card, &t, TCODE_WRITE_QUADLET_REQUEST,
++			lu->tgt->node_id, lu->generation, device->max_speed,
++			lu->command_block_agent_address + SBP2_AGENT_RESET,
++			&z, sizeof(z), complete_agent_reset_write, &done);
++	wait_for_completion(&done);
++}
+ 
+-	kfree(t);
++static void
++complete_agent_reset_write_no_wait(struct fw_card *card, int rcode,
++				   void *payload, size_t length, void *data)
++{
++	kfree(data);
+ }
+ 
+-static int sbp2_agent_reset(struct sbp2_logical_unit *lu)
++static void sbp2_agent_reset_no_wait(struct sbp2_logical_unit *lu)
+ {
+ 	struct fw_device *device = fw_device(lu->tgt->unit->device.parent);
+ 	struct fw_transaction *t;
+-	static u32 zero;
++	static u32 z;
+ 
+-	t = kzalloc(sizeof(*t), GFP_ATOMIC);
++	t = kmalloc(sizeof(*t), GFP_ATOMIC);
+ 	if (t == NULL)
+-		return -ENOMEM;
++		return;
+ 
+ 	fw_send_request(device->card, t, TCODE_WRITE_QUADLET_REQUEST,
+ 			lu->tgt->node_id, lu->generation, device->max_speed,
+ 			lu->command_block_agent_address + SBP2_AGENT_RESET,
+-			&zero, sizeof(zero), complete_agent_reset_write, t);
++			&z, sizeof(z), complete_agent_reset_write_no_wait, t);
++}
+ 
+-	return 0;
++static void sbp2_set_generation(struct sbp2_logical_unit *lu, int generation)
++{
++	struct fw_card *card = fw_device(lu->tgt->unit->device.parent)->card;
++	unsigned long flags;
++
++	/* serialize with comparisons of lu->generation and card->generation */
++	spin_lock_irqsave(&card->lock, flags);
++	lu->generation = generation;
++	spin_unlock_irqrestore(&card->lock, flags);
++}
++
++static inline void sbp2_allow_block(struct sbp2_logical_unit *lu)
++{
++	/*
++	 * We may access dont_block without taking card->lock here:
++	 * All callers of sbp2_allow_block() and all callers of sbp2_unblock()
++	 * are currently serialized against each other.
++	 * And a wrong result in sbp2_conditionally_block()'s access of
++	 * dont_block is rather harmless, it simply misses its first chance.
++	 */
++	--lu->tgt->dont_block;
++}
++
++/*
++ * Blocks lu->tgt if all of the following conditions are met:
++ *   - Login, INQUIRY, and high-level SCSI setup of all of the target's
++ *     logical units have been finished (indicated by dont_block == 0).
++ *   - lu->generation is stale.
++ *
++ * Note, scsi_block_requests() must be called while holding card->lock,
++ * otherwise it might foil sbp2_[conditionally_]unblock()'s attempt to
++ * unblock the target.
++ */
++static void sbp2_conditionally_block(struct sbp2_logical_unit *lu)
++{
++	struct sbp2_target *tgt = lu->tgt;
++	struct fw_card *card = fw_device(tgt->unit->device.parent)->card;
++	struct Scsi_Host *shost =
++		container_of((void *)tgt, struct Scsi_Host, hostdata[0]);
++	unsigned long flags;
++
++	spin_lock_irqsave(&card->lock, flags);
++	if (!tgt->dont_block && !lu->blocked &&
++	    lu->generation != card->generation) {
++		lu->blocked = true;
++		if (++tgt->blocked == 1) {
++			scsi_block_requests(shost);
++			fw_notify("blocked %s\n", lu->tgt->bus_id);
++		}
++	}
++	spin_unlock_irqrestore(&card->lock, flags);
++}
++
++/*
++ * Unblocks lu->tgt as soon as all its logical units can be unblocked.
++ * Note, it is harmless to run scsi_unblock_requests() outside the
++ * card->lock protected section.  On the other hand, running it inside
++ * the section might clash with shost->host_lock.
++ */
++static void sbp2_conditionally_unblock(struct sbp2_logical_unit *lu)
++{
++	struct sbp2_target *tgt = lu->tgt;
++	struct fw_card *card = fw_device(tgt->unit->device.parent)->card;
++	struct Scsi_Host *shost =
++		container_of((void *)tgt, struct Scsi_Host, hostdata[0]);
++	unsigned long flags;
++	bool unblock = false;
++
++	spin_lock_irqsave(&card->lock, flags);
++	if (lu->blocked && lu->generation == card->generation) {
++		lu->blocked = false;
++		unblock = --tgt->blocked == 0;
++	}
++	spin_unlock_irqrestore(&card->lock, flags);
++
++	if (unblock) {
++		scsi_unblock_requests(shost);
++		fw_notify("unblocked %s\n", lu->tgt->bus_id);
++	}
++}
++
++/*
++ * Prevents future blocking of tgt and unblocks it.
++ * Note, it is harmless to run scsi_unblock_requests() outside the
++ * card->lock protected section.  On the other hand, running it inside
++ * the section might clash with shost->host_lock.
++ */
++static void sbp2_unblock(struct sbp2_target *tgt)
++{
++	struct fw_card *card = fw_device(tgt->unit->device.parent)->card;
++	struct Scsi_Host *shost =
++		container_of((void *)tgt, struct Scsi_Host, hostdata[0]);
++	unsigned long flags;
++
++	spin_lock_irqsave(&card->lock, flags);
++	++tgt->dont_block;
++	spin_unlock_irqrestore(&card->lock, flags);
++
++	scsi_unblock_requests(shost);
+ }
  
+ static void sbp2_release_target(struct kref *kref)
+@@ -621,23 +757,24 @@ static void sbp2_release_target(struct kref *kref)
+ 	struct sbp2_logical_unit *lu, *next;
+ 	struct Scsi_Host *shost =
+ 		container_of((void *)tgt, struct Scsi_Host, hostdata[0]);
+-	struct fw_device *device = fw_device(tgt->unit->device.parent);
++
++	/* prevent deadlocks */
++	sbp2_unblock(tgt);
+ 
+ 	list_for_each_entry_safe(lu, next, &tgt->lu_list, link) {
+-		if (lu->sdev)
++		if (lu->sdev) {
+ 			scsi_remove_device(lu->sdev);
+-
 -		if (!fw_device_is_shutdown(device))
 -			sbp2_send_management_orb(lu, tgt->node_id,
 -					lu->generation, SBP2_LOGOUT_REQUEST,
 -					lu->login_id, NULL);
++			scsi_device_put(lu->sdev);
++		}
 +		sbp2_send_management_orb(lu, tgt->node_id, lu->generation,
 +				SBP2_LOGOUT_REQUEST, lu->login_id, NULL);
  
  		fw_core_remove_address_handler(&lu->address_handler);
  		list_del(&lu->link);
-@@ -675,6 +674,9 @@ static void sbp2_login(struct work_struc
+ 		kfree(lu);
+ 	}
+ 	scsi_remove_host(shost);
+-	fw_notify("released %s\n", tgt->unit->device.bus_id);
++	fw_notify("released %s\n", tgt->bus_id);
+ 
+ 	put_device(&tgt->unit->device);
+ 	scsi_host_put(shost);
+@@ -666,33 +803,43 @@ static void sbp2_login(struct work_struct *work)
+ {
+ 	struct sbp2_logical_unit *lu =
+ 		container_of(work, struct sbp2_logical_unit, work.work);
+-	struct Scsi_Host *shost =
+-		container_of((void *)lu->tgt, struct Scsi_Host, hostdata[0]);
++	struct sbp2_target *tgt = lu->tgt;
++	struct fw_device *device = fw_device(tgt->unit->device.parent);
++	struct Scsi_Host *shost;
+ 	struct scsi_device *sdev;
+ 	struct scsi_lun eight_bytes_lun;
+-	struct fw_unit *unit = lu->tgt->unit;
+-	struct fw_device *device = fw_device(unit->device.parent);
  	struct sbp2_login_response response;
  	int generation, node_id, local_node_id;
  
@@ -70,42 +563,106 @@
  	generation    = device->generation;
  	smp_rmb();    /* node_id must not be older than generation */
  	node_id       = device->node_id;
-@@ -718,17 +720,45 @@ static void sbp2_login(struct work_struc
+ 	local_node_id = device->card->node_id;
+ 
++	/* If this is a re-login attempt, log out, or we might be rejected. */
++	if (lu->sdev)
++		sbp2_send_management_orb(lu, device->node_id, generation,
++				SBP2_LOGOUT_REQUEST, lu->login_id, NULL);
++
+ 	if (sbp2_send_management_orb(lu, node_id, generation,
+ 				SBP2_LOGIN_REQUEST, lu->lun, &response) < 0) {
+-		if (lu->retries++ < 5)
++		if (lu->retries++ < 5) {
+ 			sbp2_queue_work(lu, DIV_ROUND_UP(HZ, 5));
+-		else
+-			fw_error("failed to login to %s LUN %04x\n",
+-				 unit->device.bus_id, lu->lun);
++		} else {
++			fw_error("%s: failed to login to LUN %04x\n",
++				 tgt->bus_id, lu->lun);
++			/* Let any waiting I/O fail from now on. */
++			sbp2_unblock(lu->tgt);
++		}
+ 		goto out;
+ 	}
+ 
+-	lu->generation        = generation;
+-	lu->tgt->node_id      = node_id;
+-	lu->tgt->address_high = local_node_id << 16;
++	tgt->node_id	  = node_id;
++	tgt->address_high = local_node_id << 16;
++	sbp2_set_generation(lu, generation);
+ 
+ 	/* Get command block agent offset and login id. */
+ 	lu->command_block_agent_address =
+@@ -700,8 +847,8 @@ static void sbp2_login(struct work_struct *work)
+ 		response.command_block_agent.low;
+ 	lu->login_id = LOGIN_RESPONSE_GET_LOGIN_ID(response);
+ 
+-	fw_notify("logged in to %s LUN %04x (%d retries)\n",
+-		  unit->device.bus_id, lu->lun, lu->retries);
++	fw_notify("%s: logged in to LUN %04x (%d retries)\n",
++		  tgt->bus_id, lu->lun, lu->retries);
+ 
+ #if 0
+ 	/* FIXME: The linux1394 sbp2 does this last step. */
+@@ -711,26 +858,62 @@ static void sbp2_login(struct work_struct *work)
+ 	PREPARE_DELAYED_WORK(&lu->work, sbp2_reconnect);
+ 	sbp2_agent_reset(lu);
+ 
++	/* This was a re-login. */
++	if (lu->sdev) {
++		sbp2_cancel_orbs(lu);
++		sbp2_conditionally_unblock(lu);
++		goto out;
++	}
++
++	if (lu->tgt->workarounds & SBP2_WORKAROUND_DELAY_INQUIRY)
++		ssleep(SBP2_INQUIRY_DELAY);
++
+ 	memset(&eight_bytes_lun, 0, sizeof(eight_bytes_lun));
+ 	eight_bytes_lun.scsi_lun[0] = (lu->lun >> 8) & 0xff;
+ 	eight_bytes_lun.scsi_lun[1] = lu->lun & 0xff;
++	shost = container_of((void *)tgt, struct Scsi_Host, hostdata[0]);
+ 
  	sdev = __scsi_add_device(shost, 0, 0,
  				 scsilun_to_int(&eight_bytes_lun), lu);
- 	if (IS_ERR(sdev)) {
+-	if (IS_ERR(sdev)) {
 -		sbp2_send_management_orb(lu, node_id, generation,
 -				SBP2_LOGOUT_REQUEST, lu->login_id, NULL);
- 		/*
+-		/*
 -		 * Set this back to sbp2_login so we fall back and
 -		 * retry login on bus reset.
-+		 * The most frequent cause for __scsi_add_device() to fail
-+		 * is a bus reset while sending the SCSI INQUIRY.  Try again.
-+		 */
-+		goto out_logout_login;
-+
-+	} else if (sdev->sdev_state == SDEV_OFFLINE) {
-+		/*
-+		 * FIXME:  We are unable to perform reconnects while in
-+		 * sbp2_login().  Therefore __scsi_add_device() will get
-+		 * into trouble if a bus reset happens in parallel.
-+		 * It will either fail (that's OK, see above) or take sdev
-+		 * offline.  Here is a crude workaround for the latter.
- 		 */
+-		 */
 -		PREPARE_DELAYED_WORK(&lu->work, sbp2_login);
-+		scsi_device_put(sdev);
-+		scsi_remove_device(sdev);
+-	} else {
+-		lu->sdev = sdev;
++	/*
++	 * FIXME:  We are unable to perform reconnects while in sbp2_login().
++	 * Therefore __scsi_add_device() will get into trouble if a bus reset
++	 * happens in parallel.  It will either fail or leave us with an
++	 * unusable sdev.  As a workaround we check for this and retry the
++	 * whole login and SCSI probing.
++	 */
++
++	/* Reported error during __scsi_add_device() */
++	if (IS_ERR(sdev))
 +		goto out_logout_login;
 +
- 	} else {
-+		/*
-+		 * Can you believe it?  Everything went well.
-+		 */
- 		lu->sdev = sdev;
++	/* Unreported error during __scsi_add_device() */
++	smp_rmb(); /* get current card generation */
++	if (generation != device->card->generation) {
++		scsi_remove_device(sdev);
  		scsi_device_put(sdev);
-+		goto out;
++		goto out_logout_login;
  	}
 +
++	/* No error during __scsi_add_device() */
++	lu->sdev = sdev;
++	sbp2_allow_block(lu);
++	goto out;
++
 + out_logout_login:
 +	smp_rmb(); /* generation may have changed */
 +	generation = device->generation;
@@ -119,9 +676,30 @@
 +	 */
 +	PREPARE_DELAYED_WORK(&lu->work, sbp2_login);
   out:
- 	sbp2_target_put(lu->tgt);
+-	sbp2_target_put(lu->tgt);
++	sbp2_target_put(tgt);
  }
-@@ -836,7 +866,7 @@ static void sbp2_init_workarounds(struct
+ 
+ static int sbp2_add_logical_unit(struct sbp2_target *tgt, int lun_entry)
+@@ -755,6 +938,8 @@ static int sbp2_add_logical_unit(struct sbp2_target *tgt, int lun_entry)
+ 	lu->sdev = NULL;
+ 	lu->lun  = lun_entry & 0xffff;
+ 	lu->retries = 0;
++	lu->blocked = false;
++	++tgt->dont_block;
+ 	INIT_LIST_HEAD(&lu->orb_list);
+ 	INIT_DELAYED_WORK(&lu->work, sbp2_login);
+ 
+@@ -813,7 +998,7 @@ static int sbp2_scan_unit_dir(struct sbp2_target *tgt, u32 *directory,
+ 			if (timeout > tgt->mgt_orb_timeout)
+ 				fw_notify("%s: config rom contains %ds "
+ 					  "management ORB timeout, limiting "
+-					  "to %ds\n", tgt->unit->device.bus_id,
++					  "to %ds\n", tgt->bus_id,
+ 					  timeout / 1000,
+ 					  tgt->mgt_orb_timeout / 1000);
+ 			break;
+@@ -836,12 +1021,12 @@ static void sbp2_init_workarounds(struct sbp2_target *tgt, u32 model,
  				  u32 firmware_revision)
  {
  	int i;
@@ -130,8 +708,38 @@
  
  	if (w)
  		fw_notify("Please notify linux1394-devel at lists.sourceforge.net "
-@@ -942,6 +972,9 @@ static void sbp2_reconnect(struct work_s
- 	struct fw_device *device = fw_device(unit->device.parent);
+ 			  "if you need the workarounds parameter for %s\n",
+-			  tgt->unit->device.bus_id);
++			  tgt->bus_id);
+ 
+ 	if (w & SBP2_WORKAROUND_OVERRIDE)
+ 		goto out;
+@@ -863,8 +1048,7 @@ static void sbp2_init_workarounds(struct sbp2_target *tgt, u32 model,
+ 	if (w)
+ 		fw_notify("Workarounds for %s: 0x%x "
+ 			  "(firmware_revision 0x%06x, model_id 0x%06x)\n",
+-			  tgt->unit->device.bus_id,
+-			  w, firmware_revision, model);
++			  tgt->bus_id, w, firmware_revision, model);
+ 	tgt->workarounds = w;
+ }
+ 
+@@ -888,6 +1072,7 @@ static int sbp2_probe(struct device *dev)
+ 	tgt->unit = unit;
+ 	kref_init(&tgt->kref);
+ 	INIT_LIST_HEAD(&tgt->lu_list);
++	tgt->bus_id = unit->device.bus_id;
+ 
+ 	if (fw_device_enable_phys_dma(device) < 0)
+ 		goto fail_shost_put;
+@@ -938,10 +1123,13 @@ static void sbp2_reconnect(struct work_struct *work)
+ {
+ 	struct sbp2_logical_unit *lu =
+ 		container_of(work, struct sbp2_logical_unit, work.work);
+-	struct fw_unit *unit = lu->tgt->unit;
+-	struct fw_device *device = fw_device(unit->device.parent);
++	struct sbp2_target *tgt = lu->tgt;
++	struct fw_device *device = fw_device(tgt->unit->device.parent);
  	int generation, node_id, local_node_id;
  
 +	if (fw_device_is_shutdown(device))
@@ -140,7 +748,79 @@
  	generation    = device->generation;
  	smp_rmb();    /* node_id must not be older than generation */
  	node_id       = device->node_id;
-@@ -1197,7 +1230,7 @@ static int sbp2_scsi_queuecommand(struct
+@@ -950,10 +1138,17 @@ static void sbp2_reconnect(struct work_struct *work)
+ 	if (sbp2_send_management_orb(lu, node_id, generation,
+ 				     SBP2_RECONNECT_REQUEST,
+ 				     lu->login_id, NULL) < 0) {
+-		if (lu->retries++ >= 5) {
+-			fw_error("failed to reconnect to %s\n",
+-				 unit->device.bus_id);
+-			/* Fall back and try to log in again. */
++		/*
++		 * If reconnect was impossible even though we are in the
++		 * current generation, fall back and try to log in again.
++		 *
++		 * We could check for "Function rejected" status, but
++		 * looking at the bus generation as simpler and more general.
++		 */
++		smp_rmb(); /* get current card generation */
++		if (generation == device->card->generation ||
++		    lu->retries++ >= 5) {
++			fw_error("%s: failed to reconnect\n", tgt->bus_id);
+ 			lu->retries = 0;
+ 			PREPARE_DELAYED_WORK(&lu->work, sbp2_login);
+ 		}
+@@ -961,17 +1156,18 @@ static void sbp2_reconnect(struct work_struct *work)
+ 		goto out;
+ 	}
+ 
+-	lu->generation        = generation;
+-	lu->tgt->node_id      = node_id;
+-	lu->tgt->address_high = local_node_id << 16;
++	tgt->node_id      = node_id;
++	tgt->address_high = local_node_id << 16;
++	sbp2_set_generation(lu, generation);
+ 
+-	fw_notify("reconnected to %s LUN %04x (%d retries)\n",
+-		  unit->device.bus_id, lu->lun, lu->retries);
++	fw_notify("%s: reconnected to LUN %04x (%d retries)\n",
++		  tgt->bus_id, lu->lun, lu->retries);
+ 
+ 	sbp2_agent_reset(lu);
+ 	sbp2_cancel_orbs(lu);
++	sbp2_conditionally_unblock(lu);
+  out:
+-	sbp2_target_put(lu->tgt);
++	sbp2_target_put(tgt);
+ }
+ 
+ static void sbp2_update(struct fw_unit *unit)
+@@ -986,6 +1182,7 @@ static void sbp2_update(struct fw_unit *unit)
+ 	 * Iteration over tgt->lu_list is therefore safe here.
+ 	 */
+ 	list_for_each_entry(lu, &tgt->lu_list, link) {
++		sbp2_conditionally_block(lu);
+ 		lu->retries = 0;
+ 		sbp2_queue_work(lu, 0);
+ 	}
+@@ -1063,7 +1260,7 @@ complete_command_orb(struct sbp2_orb *base_orb, struct sbp2_status *status)
+ 
+ 	if (status != NULL) {
+ 		if (STATUS_GET_DEAD(*status))
+-			sbp2_agent_reset(orb->lu);
++			sbp2_agent_reset_no_wait(orb->lu);
+ 
+ 		switch (STATUS_GET_RESPONSE(*status)) {
+ 		case SBP2_STATUS_REQUEST_COMPLETE:
+@@ -1089,6 +1286,7 @@ complete_command_orb(struct sbp2_orb *base_orb, struct sbp2_status *status)
+ 		 * or when sending the write (less likely).
+ 		 */
+ 		result = DID_BUS_BUSY << 16;
++		sbp2_conditionally_block(orb->lu);
+ 	}
+ 
+ 	dma_unmap_single(device->card->device, orb->base.request_bus,
+@@ -1197,7 +1395,7 @@ static int sbp2_scsi_queuecommand(struct scsi_cmnd *cmd, scsi_done_fn_t done)
  	struct sbp2_logical_unit *lu = cmd->device->hostdata;
  	struct fw_device *device = fw_device(lu->tgt->unit->device.parent);
  	struct sbp2_command_orb *orb;
@@ -149,8 +829,78 @@
  	int retval = SCSI_MLQUEUE_HOST_BUSY;
  
  	/*
-@@ -1277,11 +1310,8 @@ static int sbp2_scsi_slave_alloc(struct 
+@@ -1275,6 +1473,10 @@ static int sbp2_scsi_slave_alloc(struct scsi_device *sdev)
+ {
+ 	struct sbp2_logical_unit *lu = sdev->hostdata;
  
++	/* (Re-)Adding logical units via the SCSI stack is not supported. */
++	if (!lu)
++		return -ENOSYS;
++
+ 	sdev->allow_restart = 1;
+ 
+ 	/*
+@@ -1319,7 +1521,7 @@ static int sbp2_scsi_abort(struct scsi_cmnd *cmd)
+ {
+ 	struct sbp2_logical_unit *lu = cmd->device->hostdata;
+ 
+-	fw_notify("sbp2_scsi_abort\n");
++	fw_notify("%s: sbp2_scsi_abort\n", lu->tgt->bus_id);
+ 	sbp2_agent_reset(lu);
+ 	sbp2_cancel_orbs(lu);
+ 
+diff --git a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c
+index 28e155a..29e6663 100644
+--- a/drivers/ieee1394/sbp2.c
++++ b/drivers/ieee1394/sbp2.c
+@@ -183,6 +183,9 @@ MODULE_PARM_DESC(exclusive_login, "Exclusive login to sbp2 device "
+  *   Avoids access beyond actual disk limits on devices with an off-by-one bug.
+  *   Don't use this with devices which don't have this bug.
+  *
++ * - delay inquiry
++ *   Wait extra SBP2_INQUIRY_DELAY seconds after login before SCSI inquiry.
++ *
+  * - override internal blacklist
+  *   Instead of adding to the built-in blacklist, use only the workarounds
+  *   specified in the module load parameter.
+@@ -195,6 +198,7 @@ MODULE_PARM_DESC(workarounds, "Work around device bugs (default = 0"
+ 	", 36 byte inquiry = "    __stringify(SBP2_WORKAROUND_INQUIRY_36)
+ 	", skip mode page 8 = "   __stringify(SBP2_WORKAROUND_MODE_SENSE_8)
+ 	", fix capacity = "       __stringify(SBP2_WORKAROUND_FIX_CAPACITY)
++	", delay inquiry = "      __stringify(SBP2_WORKAROUND_DELAY_INQUIRY)
+ 	", override internal blacklist = " __stringify(SBP2_WORKAROUND_OVERRIDE)
+ 	", or a combination)");
+ 
+@@ -357,6 +361,11 @@ static const struct {
+ 		.workarounds		= SBP2_WORKAROUND_INQUIRY_36 |
+ 					  SBP2_WORKAROUND_MODE_SENSE_8,
+ 	},
++	/* DViCO Momobay FX-3A with TSB42AA9A bridge */ {
++		.firmware_revision	= 0x002800,
++		.model_id		= 0x000000,
++		.workarounds		= SBP2_WORKAROUND_DELAY_INQUIRY,
++	},
+ 	/* Initio bridges, actually only needed for some older ones */ {
+ 		.firmware_revision	= 0x000200,
+ 		.model_id		= SBP2_ROM_VALUE_WILDCARD,
+@@ -914,6 +923,9 @@ static int sbp2_start_device(struct sbp2_lu *lu)
+ 	sbp2_agent_reset(lu, 1);
+ 	sbp2_max_speed_and_size(lu);
+ 
++	if (lu->workarounds & SBP2_WORKAROUND_DELAY_INQUIRY)
++		ssleep(SBP2_INQUIRY_DELAY);
++
+ 	error = scsi_add_device(lu->shost, 0, lu->ud->id, 0);
+ 	if (error) {
+ 		SBP2_ERR("scsi_add_device failed");
+@@ -1962,14 +1974,14 @@ static int sbp2scsi_slave_alloc(struct scsi_device *sdev)
+ {
+ 	struct sbp2_lu *lu = (struct sbp2_lu *)sdev->host->hostdata[0];
+ 
++	if (sdev->lun != 0 || sdev->id != lu->ud->id || sdev->channel != 0)
++		return -ENODEV;
++
+ 	lu->sdev = sdev;
  	sdev->allow_restart = 1;
  
 -	/*
@@ -161,5 +911,18 @@
 +	/* SBP-2 requires quadlet alignment of the data buffers. */
 +	blk_queue_update_dma_alignment(sdev->request_queue, 4 - 1);
  
- 	if (lu->tgt->workarounds & SBP2_WORKAROUND_INQUIRY_36)
+ 	if (lu->workarounds & SBP2_WORKAROUND_INQUIRY_36)
  		sdev->inquiry_len = 36;
+diff --git a/drivers/ieee1394/sbp2.h b/drivers/ieee1394/sbp2.h
+index d2ecb0d..80d8e09 100644
+--- a/drivers/ieee1394/sbp2.h
++++ b/drivers/ieee1394/sbp2.h
+@@ -343,6 +343,8 @@ enum sbp2lu_state_types {
+ #define SBP2_WORKAROUND_INQUIRY_36	0x2
+ #define SBP2_WORKAROUND_MODE_SENSE_8	0x4
+ #define SBP2_WORKAROUND_FIX_CAPACITY	0x8
++#define SBP2_WORKAROUND_DELAY_INQUIRY	0x10
++#define SBP2_INQUIRY_DELAY		12
+ #define SBP2_WORKAROUND_OVERRIDE	0x100
+ 
+ #endif /* SBP2_H */




More information about the fedora-extras-commits mailing list