diff options
author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2008-02-26 10:48:27 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2008-02-26 10:48:27 -0500 |
commit | 98c1fc934c097d84dc30c639e9bdb0b992ef53e2 (patch) | |
tree | 69150e7ca6b4a0eb842d5135164ee1d40a4dabbe | |
parent | 7c811e4b6af424c295e3c6438fdc9b647fe6595f (diff) | |
parent | fae603121428ba83b7343c88e68a7144525ab3eb (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394-2.6:
firewire: fix NULL pointer deref. and resource leak
Documentation: correction to debugging-via-ohci1394
ieee1394: sbp2: fix rescan-scsi-bus
firewire: fw-sbp2: fix NULL pointer deref. in scsi_remove_device
firewire: fw-sbp2: fix NULL pointer deref. in slave_alloc
firewire: fw-sbp2: (try to) avoid I/O errors during reconnect
firewire: fw-sbp2: enforce a retry of __scsi_add_device if bus generation changed
firewire: fw-sbp2: sort includes
firewire: fw-sbp2: logout and login after failed reconnect
firewire: fw-sbp2: don't add scsi_device twice
firewire: fw-sbp2: log bus_id at management request failures
firewire: fw-sbp2: wait for completion of fetch agent reset
ieee1394: sbp2: add INQUIRY delay workaround
firewire: fw-sbp2: add INQUIRY delay workaround
firewire: log GUID of new devices
firewire: fw-sbp2: don't retry login or reconnect after unplug
firewire: fix "kobject_add failed for fw* with -EEXIST"
firewire: fw-sbp2: fix logout before login retry
firewire: fw-sbp2: unsigned int vs. unsigned
-rw-r--r-- | Documentation/debugging-via-ohci1394.txt | 17 | ||||
-rw-r--r-- | drivers/firewire/fw-cdev.c | 17 | ||||
-rw-r--r-- | drivers/firewire/fw-device.c | 48 | ||||
-rw-r--r-- | drivers/firewire/fw-device.h | 2 | ||||
-rw-r--r-- | drivers/firewire/fw-sbp2.c | 358 | ||||
-rw-r--r-- | drivers/ieee1394/sbp2.c | 15 | ||||
-rw-r--r-- | drivers/ieee1394/sbp2.h | 2 |
7 files changed, 350 insertions, 109 deletions
diff --git a/Documentation/debugging-via-ohci1394.txt b/Documentation/debugging-via-ohci1394.txt index de4804e8b396..c360d4e91b48 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). | |||
36 | Drivers | 36 | Drivers |
37 | ------- | 37 | ------- |
38 | 38 | ||
39 | The OHCI-1394 drivers in drivers/firewire and drivers/ieee1394 initialize | 39 | The ohci1394 driver in drivers/ieee1394 initializes the OHCI-1394 controllers |
40 | the OHCI-1394 controllers to a working state and can be used to enable | 40 | to a working state and enables physical DMA by default for all remote nodes. |
41 | physical DMA. By default you only have to load the driver, and physical | 41 | This can be turned off by ohci1394's module parameter phys_dma=0. |
42 | DMA access will be granted to all remote nodes, but it can be turned off | 42 | |
43 | when using the ohci1394 driver. | 43 | The alternative firewire-ohci driver in drivers/firewire uses filtered physical |
44 | 44 | DMA, hence is not yet suitable for remote debugging. | |
45 | Because these drivers depend on the PCI enumeration to be completed, an | 45 | |
46 | initialization routine which can runs pretty early (long before console_init(), | 46 | Because ohci1394 depends on the PCI enumeration to be completed, an |
47 | initialization routine which runs pretty early (long before console_init() | ||
47 | which makes the printk buffer appear on the console can be called) was written. | 48 | which makes the printk buffer appear on the console can be called) was written. |
48 | 49 | ||
49 | To activate it, enable CONFIG_PROVIDE_OHCI1394_DMA_INIT (Kernel hacking menu: | 50 | 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 7e73cbaa4121..46bc197a047f 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) | |||
109 | struct client *client; | 109 | struct client *client; |
110 | unsigned long flags; | 110 | unsigned long flags; |
111 | 111 | ||
112 | device = fw_device_from_devt(inode->i_rdev); | 112 | device = fw_device_get_by_devt(inode->i_rdev); |
113 | if (device == NULL) | 113 | if (device == NULL) |
114 | return -ENODEV; | 114 | return -ENODEV; |
115 | 115 | ||
116 | client = kzalloc(sizeof(*client), GFP_KERNEL); | 116 | client = kzalloc(sizeof(*client), GFP_KERNEL); |
117 | if (client == NULL) | 117 | if (client == NULL) { |
118 | fw_device_put(device); | ||
118 | return -ENOMEM; | 119 | return -ENOMEM; |
120 | } | ||
119 | 121 | ||
120 | client->device = fw_device_get(device); | 122 | client->device = device; |
121 | INIT_LIST_HEAD(&client->event_list); | 123 | INIT_LIST_HEAD(&client->event_list); |
122 | INIT_LIST_HEAD(&client->resource_list); | 124 | INIT_LIST_HEAD(&client->resource_list); |
123 | spin_lock_init(&client->lock); | 125 | spin_lock_init(&client->lock); |
@@ -644,6 +646,10 @@ static int ioctl_create_iso_context(struct client *client, void *buffer) | |||
644 | struct fw_cdev_create_iso_context *request = buffer; | 646 | struct fw_cdev_create_iso_context *request = buffer; |
645 | struct fw_iso_context *context; | 647 | struct fw_iso_context *context; |
646 | 648 | ||
649 | /* We only support one context at this time. */ | ||
650 | if (client->iso_context != NULL) | ||
651 | return -EBUSY; | ||
652 | |||
647 | if (request->channel > 63) | 653 | if (request->channel > 63) |
648 | return -EINVAL; | 654 | return -EINVAL; |
649 | 655 | ||
@@ -790,8 +796,9 @@ static int ioctl_start_iso(struct client *client, void *buffer) | |||
790 | { | 796 | { |
791 | struct fw_cdev_start_iso *request = buffer; | 797 | struct fw_cdev_start_iso *request = buffer; |
792 | 798 | ||
793 | if (request->handle != 0) | 799 | if (client->iso_context == NULL || request->handle != 0) |
794 | return -EINVAL; | 800 | return -EINVAL; |
801 | |||
795 | if (client->iso_context->type == FW_ISO_CONTEXT_RECEIVE) { | 802 | if (client->iso_context->type == FW_ISO_CONTEXT_RECEIVE) { |
796 | if (request->tags == 0 || request->tags > 15) | 803 | if (request->tags == 0 || request->tags > 15) |
797 | return -EINVAL; | 804 | return -EINVAL; |
@@ -808,7 +815,7 @@ static int ioctl_stop_iso(struct client *client, void *buffer) | |||
808 | { | 815 | { |
809 | struct fw_cdev_stop_iso *request = buffer; | 816 | struct fw_cdev_stop_iso *request = buffer; |
810 | 817 | ||
811 | if (request->handle != 0) | 818 | if (client->iso_context == NULL || request->handle != 0) |
812 | return -EINVAL; | 819 | return -EINVAL; |
813 | 820 | ||
814 | return fw_iso_context_stop(client->iso_context); | 821 | return fw_iso_context_stop(client->iso_context); |
diff --git a/drivers/firewire/fw-device.c b/drivers/firewire/fw-device.c index de9066e69adf..2ab13e0f3469 100644 --- a/drivers/firewire/fw-device.c +++ b/drivers/firewire/fw-device.c | |||
@@ -358,12 +358,9 @@ static ssize_t | |||
358 | guid_show(struct device *dev, struct device_attribute *attr, char *buf) | 358 | guid_show(struct device *dev, struct device_attribute *attr, char *buf) |
359 | { | 359 | { |
360 | struct fw_device *device = fw_device(dev); | 360 | struct fw_device *device = fw_device(dev); |
361 | u64 guid; | ||
362 | 361 | ||
363 | guid = ((u64)device->config_rom[3] << 32) | device->config_rom[4]; | 362 | return snprintf(buf, PAGE_SIZE, "0x%08x%08x\n", |
364 | 363 | device->config_rom[3], device->config_rom[4]); | |
365 | return snprintf(buf, PAGE_SIZE, "0x%016llx\n", | ||
366 | (unsigned long long)guid); | ||
367 | } | 364 | } |
368 | 365 | ||
369 | static struct device_attribute fw_device_attributes[] = { | 366 | static struct device_attribute fw_device_attributes[] = { |
@@ -610,12 +607,14 @@ static DECLARE_RWSEM(idr_rwsem); | |||
610 | static DEFINE_IDR(fw_device_idr); | 607 | static DEFINE_IDR(fw_device_idr); |
611 | int fw_cdev_major; | 608 | int fw_cdev_major; |
612 | 609 | ||
613 | struct fw_device *fw_device_from_devt(dev_t devt) | 610 | struct fw_device *fw_device_get_by_devt(dev_t devt) |
614 | { | 611 | { |
615 | struct fw_device *device; | 612 | struct fw_device *device; |
616 | 613 | ||
617 | down_read(&idr_rwsem); | 614 | down_read(&idr_rwsem); |
618 | device = idr_find(&fw_device_idr, MINOR(devt)); | 615 | device = idr_find(&fw_device_idr, MINOR(devt)); |
616 | if (device) | ||
617 | fw_device_get(device); | ||
619 | up_read(&idr_rwsem); | 618 | up_read(&idr_rwsem); |
620 | 619 | ||
621 | return device; | 620 | return device; |
@@ -627,13 +626,14 @@ static void fw_device_shutdown(struct work_struct *work) | |||
627 | container_of(work, struct fw_device, work.work); | 626 | container_of(work, struct fw_device, work.work); |
628 | int minor = MINOR(device->device.devt); | 627 | int minor = MINOR(device->device.devt); |
629 | 628 | ||
630 | down_write(&idr_rwsem); | ||
631 | idr_remove(&fw_device_idr, minor); | ||
632 | up_write(&idr_rwsem); | ||
633 | |||
634 | fw_device_cdev_remove(device); | 629 | fw_device_cdev_remove(device); |
635 | device_for_each_child(&device->device, NULL, shutdown_unit); | 630 | device_for_each_child(&device->device, NULL, shutdown_unit); |
636 | device_unregister(&device->device); | 631 | device_unregister(&device->device); |
632 | |||
633 | down_write(&idr_rwsem); | ||
634 | idr_remove(&fw_device_idr, minor); | ||
635 | up_write(&idr_rwsem); | ||
636 | fw_device_put(device); | ||
637 | } | 637 | } |
638 | 638 | ||
639 | static struct device_type fw_device_type = { | 639 | static struct device_type fw_device_type = { |
@@ -682,10 +682,13 @@ static void fw_device_init(struct work_struct *work) | |||
682 | } | 682 | } |
683 | 683 | ||
684 | err = -ENOMEM; | 684 | err = -ENOMEM; |
685 | |||
686 | fw_device_get(device); | ||
685 | down_write(&idr_rwsem); | 687 | down_write(&idr_rwsem); |
686 | if (idr_pre_get(&fw_device_idr, GFP_KERNEL)) | 688 | if (idr_pre_get(&fw_device_idr, GFP_KERNEL)) |
687 | err = idr_get_new(&fw_device_idr, device, &minor); | 689 | err = idr_get_new(&fw_device_idr, device, &minor); |
688 | up_write(&idr_rwsem); | 690 | up_write(&idr_rwsem); |
691 | |||
689 | if (err < 0) | 692 | if (err < 0) |
690 | goto error; | 693 | goto error; |
691 | 694 | ||
@@ -717,13 +720,22 @@ static void fw_device_init(struct work_struct *work) | |||
717 | */ | 720 | */ |
718 | if (atomic_cmpxchg(&device->state, | 721 | if (atomic_cmpxchg(&device->state, |
719 | FW_DEVICE_INITIALIZING, | 722 | FW_DEVICE_INITIALIZING, |
720 | FW_DEVICE_RUNNING) == FW_DEVICE_SHUTDOWN) | 723 | FW_DEVICE_RUNNING) == FW_DEVICE_SHUTDOWN) { |
721 | fw_device_shutdown(&device->work.work); | 724 | fw_device_shutdown(&device->work.work); |
722 | else | 725 | } else { |
723 | fw_notify("created new fw device %s " | 726 | if (device->config_rom_retries) |
724 | "(%d config rom retries, S%d00)\n", | 727 | fw_notify("created device %s: GUID %08x%08x, S%d00, " |
725 | device->device.bus_id, device->config_rom_retries, | 728 | "%d config ROM retries\n", |
726 | 1 << device->max_speed); | 729 | device->device.bus_id, |
730 | device->config_rom[3], device->config_rom[4], | ||
731 | 1 << device->max_speed, | ||
732 | device->config_rom_retries); | ||
733 | else | ||
734 | fw_notify("created device %s: GUID %08x%08x, S%d00\n", | ||
735 | device->device.bus_id, | ||
736 | device->config_rom[3], device->config_rom[4], | ||
737 | 1 << device->max_speed); | ||
738 | } | ||
727 | 739 | ||
728 | /* | 740 | /* |
729 | * Reschedule the IRM work if we just finished reading the | 741 | * Reschedule the IRM work if we just finished reading the |
@@ -741,7 +753,9 @@ static void fw_device_init(struct work_struct *work) | |||
741 | idr_remove(&fw_device_idr, minor); | 753 | idr_remove(&fw_device_idr, minor); |
742 | up_write(&idr_rwsem); | 754 | up_write(&idr_rwsem); |
743 | error: | 755 | error: |
744 | put_device(&device->device); | 756 | fw_device_put(device); /* fw_device_idr's reference */ |
757 | |||
758 | put_device(&device->device); /* our reference */ | ||
745 | } | 759 | } |
746 | 760 | ||
747 | static int update_unit(struct device *dev, void *data) | 761 | static int update_unit(struct device *dev, void *data) |
diff --git a/drivers/firewire/fw-device.h b/drivers/firewire/fw-device.h index 0854fe2bc110..43808c02793e 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) | |||
77 | } | 77 | } |
78 | 78 | ||
79 | struct fw_device *fw_device_get(struct fw_device *device); | 79 | struct fw_device *fw_device_get(struct fw_device *device); |
80 | struct fw_device *fw_device_get_by_devt(dev_t devt); | ||
80 | void fw_device_put(struct fw_device *device); | 81 | void fw_device_put(struct fw_device *device); |
81 | int fw_device_enable_phys_dma(struct fw_device *device); | 82 | int fw_device_enable_phys_dma(struct fw_device *device); |
82 | 83 | ||
83 | void fw_device_cdev_update(struct fw_device *device); | 84 | void fw_device_cdev_update(struct fw_device *device); |
84 | void fw_device_cdev_remove(struct fw_device *device); | 85 | void fw_device_cdev_remove(struct fw_device *device); |
85 | 86 | ||
86 | struct fw_device *fw_device_from_devt(dev_t devt); | ||
87 | extern int fw_cdev_major; | 87 | extern int fw_cdev_major; |
88 | 88 | ||
89 | struct fw_unit { | 89 | struct fw_unit { |
diff --git a/drivers/firewire/fw-sbp2.c b/drivers/firewire/fw-sbp2.c index 19ece9b6d742..5259491580fc 100644 --- a/drivers/firewire/fw-sbp2.c +++ b/drivers/firewire/fw-sbp2.c | |||
@@ -28,14 +28,15 @@ | |||
28 | * and many others. | 28 | * and many others. |
29 | */ | 29 | */ |
30 | 30 | ||
31 | #include <linux/blkdev.h> | ||
32 | #include <linux/delay.h> | ||
33 | #include <linux/device.h> | ||
34 | #include <linux/dma-mapping.h> | ||
31 | #include <linux/kernel.h> | 35 | #include <linux/kernel.h> |
36 | #include <linux/mod_devicetable.h> | ||
32 | #include <linux/module.h> | 37 | #include <linux/module.h> |
33 | #include <linux/moduleparam.h> | 38 | #include <linux/moduleparam.h> |
34 | #include <linux/mod_devicetable.h> | ||
35 | #include <linux/device.h> | ||
36 | #include <linux/scatterlist.h> | 39 | #include <linux/scatterlist.h> |
37 | #include <linux/dma-mapping.h> | ||
38 | #include <linux/blkdev.h> | ||
39 | #include <linux/string.h> | 40 | #include <linux/string.h> |
40 | #include <linux/stringify.h> | 41 | #include <linux/stringify.h> |
41 | #include <linux/timer.h> | 42 | #include <linux/timer.h> |
@@ -47,9 +48,9 @@ | |||
47 | #include <scsi/scsi_device.h> | 48 | #include <scsi/scsi_device.h> |
48 | #include <scsi/scsi_host.h> | 49 | #include <scsi/scsi_host.h> |
49 | 50 | ||
50 | #include "fw-transaction.h" | ||
51 | #include "fw-topology.h" | ||
52 | #include "fw-device.h" | 51 | #include "fw-device.h" |
52 | #include "fw-topology.h" | ||
53 | #include "fw-transaction.h" | ||
53 | 54 | ||
54 | /* | 55 | /* |
55 | * So far only bridges from Oxford Semiconductor are known to support | 56 | * 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 " | |||
82 | * Avoids access beyond actual disk limits on devices with an off-by-one bug. | 83 | * Avoids access beyond actual disk limits on devices with an off-by-one bug. |
83 | * Don't use this with devices which don't have this bug. | 84 | * Don't use this with devices which don't have this bug. |
84 | * | 85 | * |
86 | * - delay inquiry | ||
87 | * Wait extra SBP2_INQUIRY_DELAY seconds after login before SCSI inquiry. | ||
88 | * | ||
85 | * - override internal blacklist | 89 | * - override internal blacklist |
86 | * Instead of adding to the built-in blacklist, use only the workarounds | 90 | * Instead of adding to the built-in blacklist, use only the workarounds |
87 | * specified in the module load parameter. | 91 | * specified in the module load parameter. |
@@ -91,6 +95,8 @@ MODULE_PARM_DESC(exclusive_login, "Exclusive login to sbp2 device " | |||
91 | #define SBP2_WORKAROUND_INQUIRY_36 0x2 | 95 | #define SBP2_WORKAROUND_INQUIRY_36 0x2 |
92 | #define SBP2_WORKAROUND_MODE_SENSE_8 0x4 | 96 | #define SBP2_WORKAROUND_MODE_SENSE_8 0x4 |
93 | #define SBP2_WORKAROUND_FIX_CAPACITY 0x8 | 97 | #define SBP2_WORKAROUND_FIX_CAPACITY 0x8 |
98 | #define SBP2_WORKAROUND_DELAY_INQUIRY 0x10 | ||
99 | #define SBP2_INQUIRY_DELAY 12 | ||
94 | #define SBP2_WORKAROUND_OVERRIDE 0x100 | 100 | #define SBP2_WORKAROUND_OVERRIDE 0x100 |
95 | 101 | ||
96 | static int sbp2_param_workarounds; | 102 | static int sbp2_param_workarounds; |
@@ -100,6 +106,7 @@ MODULE_PARM_DESC(workarounds, "Work around device bugs (default = 0" | |||
100 | ", 36 byte inquiry = " __stringify(SBP2_WORKAROUND_INQUIRY_36) | 106 | ", 36 byte inquiry = " __stringify(SBP2_WORKAROUND_INQUIRY_36) |
101 | ", skip mode page 8 = " __stringify(SBP2_WORKAROUND_MODE_SENSE_8) | 107 | ", skip mode page 8 = " __stringify(SBP2_WORKAROUND_MODE_SENSE_8) |
102 | ", fix capacity = " __stringify(SBP2_WORKAROUND_FIX_CAPACITY) | 108 | ", fix capacity = " __stringify(SBP2_WORKAROUND_FIX_CAPACITY) |
109 | ", delay inquiry = " __stringify(SBP2_WORKAROUND_DELAY_INQUIRY) | ||
103 | ", override internal blacklist = " __stringify(SBP2_WORKAROUND_OVERRIDE) | 110 | ", override internal blacklist = " __stringify(SBP2_WORKAROUND_OVERRIDE) |
104 | ", or a combination)"); | 111 | ", or a combination)"); |
105 | 112 | ||
@@ -132,6 +139,7 @@ struct sbp2_logical_unit { | |||
132 | int generation; | 139 | int generation; |
133 | int retries; | 140 | int retries; |
134 | struct delayed_work work; | 141 | struct delayed_work work; |
142 | bool blocked; | ||
135 | }; | 143 | }; |
136 | 144 | ||
137 | /* | 145 | /* |
@@ -141,16 +149,18 @@ struct sbp2_logical_unit { | |||
141 | struct sbp2_target { | 149 | struct sbp2_target { |
142 | struct kref kref; | 150 | struct kref kref; |
143 | struct fw_unit *unit; | 151 | struct fw_unit *unit; |
152 | const char *bus_id; | ||
153 | struct list_head lu_list; | ||
144 | 154 | ||
145 | u64 management_agent_address; | 155 | u64 management_agent_address; |
146 | int directory_id; | 156 | int directory_id; |
147 | int node_id; | 157 | int node_id; |
148 | int address_high; | 158 | int address_high; |
149 | 159 | unsigned int workarounds; | |
150 | unsigned workarounds; | ||
151 | struct list_head lu_list; | ||
152 | |||
153 | unsigned int mgt_orb_timeout; | 160 | unsigned int mgt_orb_timeout; |
161 | |||
162 | int dont_block; /* counter for each logical unit */ | ||
163 | int blocked; /* ditto */ | ||
154 | }; | 164 | }; |
155 | 165 | ||
156 | /* | 166 | /* |
@@ -160,7 +170,7 @@ struct sbp2_target { | |||
160 | */ | 170 | */ |
161 | #define SBP2_MIN_LOGIN_ORB_TIMEOUT 5000U /* Timeout in ms */ | 171 | #define SBP2_MIN_LOGIN_ORB_TIMEOUT 5000U /* Timeout in ms */ |
162 | #define SBP2_MAX_LOGIN_ORB_TIMEOUT 40000U /* Timeout in ms */ | 172 | #define SBP2_MAX_LOGIN_ORB_TIMEOUT 40000U /* Timeout in ms */ |
163 | #define SBP2_ORB_TIMEOUT 2000 /* Timeout in ms */ | 173 | #define SBP2_ORB_TIMEOUT 2000U /* Timeout in ms */ |
164 | #define SBP2_ORB_NULL 0x80000000 | 174 | #define SBP2_ORB_NULL 0x80000000 |
165 | #define SBP2_MAX_SG_ELEMENT_LENGTH 0xf000 | 175 | #define SBP2_MAX_SG_ELEMENT_LENGTH 0xf000 |
166 | 176 | ||
@@ -297,7 +307,7 @@ struct sbp2_command_orb { | |||
297 | static const struct { | 307 | static const struct { |
298 | u32 firmware_revision; | 308 | u32 firmware_revision; |
299 | u32 model; | 309 | u32 model; |
300 | unsigned workarounds; | 310 | unsigned int workarounds; |
301 | } sbp2_workarounds_table[] = { | 311 | } sbp2_workarounds_table[] = { |
302 | /* DViCO Momobay CX-1 with TSB42AA9 bridge */ { | 312 | /* DViCO Momobay CX-1 with TSB42AA9 bridge */ { |
303 | .firmware_revision = 0x002800, | 313 | .firmware_revision = 0x002800, |
@@ -305,6 +315,11 @@ static const struct { | |||
305 | .workarounds = SBP2_WORKAROUND_INQUIRY_36 | | 315 | .workarounds = SBP2_WORKAROUND_INQUIRY_36 | |
306 | SBP2_WORKAROUND_MODE_SENSE_8, | 316 | SBP2_WORKAROUND_MODE_SENSE_8, |
307 | }, | 317 | }, |
318 | /* DViCO Momobay FX-3A with TSB42AA9A bridge */ { | ||
319 | .firmware_revision = 0x002800, | ||
320 | .model = 0x000000, | ||
321 | .workarounds = SBP2_WORKAROUND_DELAY_INQUIRY, | ||
322 | }, | ||
308 | /* Initio bridges, actually only needed for some older ones */ { | 323 | /* Initio bridges, actually only needed for some older ones */ { |
309 | .firmware_revision = 0x000200, | 324 | .firmware_revision = 0x000200, |
310 | .model = ~0, | 325 | .model = ~0, |
@@ -501,6 +516,9 @@ sbp2_send_management_orb(struct sbp2_logical_unit *lu, int node_id, | |||
501 | unsigned int timeout; | 516 | unsigned int timeout; |
502 | int retval = -ENOMEM; | 517 | int retval = -ENOMEM; |
503 | 518 | ||
519 | if (function == SBP2_LOGOUT_REQUEST && fw_device_is_shutdown(device)) | ||
520 | return 0; | ||
521 | |||
504 | orb = kzalloc(sizeof(*orb), GFP_ATOMIC); | 522 | orb = kzalloc(sizeof(*orb), GFP_ATOMIC); |
505 | if (orb == NULL) | 523 | if (orb == NULL) |
506 | return -ENOMEM; | 524 | return -ENOMEM; |
@@ -553,20 +571,20 @@ sbp2_send_management_orb(struct sbp2_logical_unit *lu, int node_id, | |||
553 | 571 | ||
554 | retval = -EIO; | 572 | retval = -EIO; |
555 | if (sbp2_cancel_orbs(lu) == 0) { | 573 | if (sbp2_cancel_orbs(lu) == 0) { |
556 | fw_error("orb reply timed out, rcode=0x%02x\n", | 574 | fw_error("%s: orb reply timed out, rcode=0x%02x\n", |
557 | orb->base.rcode); | 575 | lu->tgt->bus_id, orb->base.rcode); |
558 | goto out; | 576 | goto out; |
559 | } | 577 | } |
560 | 578 | ||
561 | if (orb->base.rcode != RCODE_COMPLETE) { | 579 | if (orb->base.rcode != RCODE_COMPLETE) { |
562 | fw_error("management write failed, rcode 0x%02x\n", | 580 | fw_error("%s: management write failed, rcode 0x%02x\n", |
563 | orb->base.rcode); | 581 | lu->tgt->bus_id, orb->base.rcode); |
564 | goto out; | 582 | goto out; |
565 | } | 583 | } |
566 | 584 | ||
567 | if (STATUS_GET_RESPONSE(orb->status) != 0 || | 585 | if (STATUS_GET_RESPONSE(orb->status) != 0 || |
568 | STATUS_GET_SBP_STATUS(orb->status) != 0) { | 586 | STATUS_GET_SBP_STATUS(orb->status) != 0) { |
569 | fw_error("error status: %d:%d\n", | 587 | fw_error("%s: error status: %d:%d\n", lu->tgt->bus_id, |
570 | STATUS_GET_RESPONSE(orb->status), | 588 | STATUS_GET_RESPONSE(orb->status), |
571 | STATUS_GET_SBP_STATUS(orb->status)); | 589 | STATUS_GET_SBP_STATUS(orb->status)); |
572 | goto out; | 590 | goto out; |
@@ -590,29 +608,147 @@ sbp2_send_management_orb(struct sbp2_logical_unit *lu, int node_id, | |||
590 | 608 | ||
591 | static void | 609 | static void |
592 | complete_agent_reset_write(struct fw_card *card, int rcode, | 610 | complete_agent_reset_write(struct fw_card *card, int rcode, |
593 | void *payload, size_t length, void *data) | 611 | void *payload, size_t length, void *done) |
612 | { | ||
613 | complete(done); | ||
614 | } | ||
615 | |||
616 | static void sbp2_agent_reset(struct sbp2_logical_unit *lu) | ||
594 | { | 617 | { |
595 | struct fw_transaction *t = data; | 618 | struct fw_device *device = fw_device(lu->tgt->unit->device.parent); |
619 | DECLARE_COMPLETION_ONSTACK(done); | ||
620 | struct fw_transaction t; | ||
621 | static u32 z; | ||
622 | |||
623 | fw_send_request(device->card, &t, TCODE_WRITE_QUADLET_REQUEST, | ||
624 | lu->tgt->node_id, lu->generation, device->max_speed, | ||
625 | lu->command_block_agent_address + SBP2_AGENT_RESET, | ||
626 | &z, sizeof(z), complete_agent_reset_write, &done); | ||
627 | wait_for_completion(&done); | ||
628 | } | ||
596 | 629 | ||
597 | kfree(t); | 630 | static void |
631 | complete_agent_reset_write_no_wait(struct fw_card *card, int rcode, | ||
632 | void *payload, size_t length, void *data) | ||
633 | { | ||
634 | kfree(data); | ||
598 | } | 635 | } |
599 | 636 | ||
600 | static int sbp2_agent_reset(struct sbp2_logical_unit *lu) | 637 | static void sbp2_agent_reset_no_wait(struct sbp2_logical_unit *lu) |
601 | { | 638 | { |
602 | struct fw_device *device = fw_device(lu->tgt->unit->device.parent); | 639 | struct fw_device *device = fw_device(lu->tgt->unit->device.parent); |
603 | struct fw_transaction *t; | 640 | struct fw_transaction *t; |
604 | static u32 zero; | 641 | static u32 z; |
605 | 642 | ||
606 | t = kzalloc(sizeof(*t), GFP_ATOMIC); | 643 | t = kmalloc(sizeof(*t), GFP_ATOMIC); |
607 | if (t == NULL) | 644 | if (t == NULL) |
608 | return -ENOMEM; | 645 | return; |
609 | 646 | ||
610 | fw_send_request(device->card, t, TCODE_WRITE_QUADLET_REQUEST, | 647 | fw_send_request(device->card, t, TCODE_WRITE_QUADLET_REQUEST, |
611 | lu->tgt->node_id, lu->generation, device->max_speed, | 648 | lu->tgt->node_id, lu->generation, device->max_speed, |
612 | lu->command_block_agent_address + SBP2_AGENT_RESET, | 649 | lu->command_block_agent_address + SBP2_AGENT_RESET, |
613 | &zero, sizeof(zero), complete_agent_reset_write, t); | 650 | &z, sizeof(z), complete_agent_reset_write_no_wait, t); |
651 | } | ||
614 | 652 | ||
615 | return 0; | 653 | static void sbp2_set_generation(struct sbp2_logical_unit *lu, int generation) |
654 | { | ||
655 | struct fw_card *card = fw_device(lu->tgt->unit->device.parent)->card; | ||
656 | unsigned long flags; | ||
657 | |||
658 | /* serialize with comparisons of lu->generation and card->generation */ | ||
659 | spin_lock_irqsave(&card->lock, flags); | ||
660 | lu->generation = generation; | ||
661 | spin_unlock_irqrestore(&card->lock, flags); | ||
662 | } | ||
663 | |||
664 | static inline void sbp2_allow_block(struct sbp2_logical_unit *lu) | ||
665 | { | ||
666 | /* | ||
667 | * We may access dont_block without taking card->lock here: | ||
668 | * All callers of sbp2_allow_block() and all callers of sbp2_unblock() | ||
669 | * are currently serialized against each other. | ||
670 | * And a wrong result in sbp2_conditionally_block()'s access of | ||
671 | * dont_block is rather harmless, it simply misses its first chance. | ||
672 | */ | ||
673 | --lu->tgt->dont_block; | ||
674 | } | ||
675 | |||
676 | /* | ||
677 | * Blocks lu->tgt if all of the following conditions are met: | ||
678 | * - Login, INQUIRY, and high-level SCSI setup of all of the target's | ||
679 | * logical units have been finished (indicated by dont_block == 0). | ||
680 | * - lu->generation is stale. | ||
681 | * | ||
682 | * Note, scsi_block_requests() must be called while holding card->lock, | ||
683 | * otherwise it might foil sbp2_[conditionally_]unblock()'s attempt to | ||
684 | * unblock the target. | ||
685 | */ | ||
686 | static void sbp2_conditionally_block(struct sbp2_logical_unit *lu) | ||
687 | { | ||
688 | struct sbp2_target *tgt = lu->tgt; | ||
689 | struct fw_card *card = fw_device(tgt->unit->device.parent)->card; | ||
690 | struct Scsi_Host *shost = | ||
691 | container_of((void *)tgt, struct Scsi_Host, hostdata[0]); | ||
692 | unsigned long flags; | ||
693 | |||
694 | spin_lock_irqsave(&card->lock, flags); | ||
695 | if (!tgt->dont_block && !lu->blocked && | ||
696 | lu->generation != card->generation) { | ||
697 | lu->blocked = true; | ||
698 | if (++tgt->blocked == 1) { | ||
699 | scsi_block_requests(shost); | ||
700 | fw_notify("blocked %s\n", lu->tgt->bus_id); | ||
701 | } | ||
702 | } | ||
703 | spin_unlock_irqrestore(&card->lock, flags); | ||
704 | } | ||
705 | |||
706 | /* | ||
707 | * Unblocks lu->tgt as soon as all its logical units can be unblocked. | ||
708 | * Note, it is harmless to run scsi_unblock_requests() outside the | ||
709 | * card->lock protected section. On the other hand, running it inside | ||
710 | * the section might clash with shost->host_lock. | ||
711 | */ | ||
712 | static void sbp2_conditionally_unblock(struct sbp2_logical_unit *lu) | ||
713 | { | ||
714 | struct sbp2_target *tgt = lu->tgt; | ||
715 | struct fw_card *card = fw_device(tgt->unit->device.parent)->card; | ||
716 | struct Scsi_Host *shost = | ||
717 | container_of((void *)tgt, struct Scsi_Host, hostdata[0]); | ||
718 | unsigned long flags; | ||
719 | bool unblock = false; | ||
720 | |||
721 | spin_lock_irqsave(&card->lock, flags); | ||
722 | if (lu->blocked && lu->generation == card->generation) { | ||
723 | lu->blocked = false; | ||
724 | unblock = --tgt->blocked == 0; | ||
725 | } | ||
726 | spin_unlock_irqrestore(&card->lock, flags); | ||
727 | |||
728 | if (unblock) { | ||
729 | scsi_unblock_requests(shost); | ||
730 | fw_notify("unblocked %s\n", lu->tgt->bus_id); | ||
731 | } | ||
732 | } | ||
733 | |||
734 | /* | ||
735 | * Prevents future blocking of tgt and unblocks it. | ||
736 | * Note, it is harmless to run scsi_unblock_requests() outside the | ||
737 | * card->lock protected section. On the other hand, running it inside | ||
738 | * the section might clash with shost->host_lock. | ||
739 | */ | ||
740 | static void sbp2_unblock(struct sbp2_target *tgt) | ||
741 | { | ||
742 | struct fw_card *card = fw_device(tgt->unit->device.parent)->card; | ||
743 | struct Scsi_Host *shost = | ||
744 | container_of((void *)tgt, struct Scsi_Host, hostdata[0]); | ||
745 | unsigned long flags; | ||
746 | |||
747 | spin_lock_irqsave(&card->lock, flags); | ||
748 | ++tgt->dont_block; | ||
749 | spin_unlock_irqrestore(&card->lock, flags); | ||
750 | |||
751 | scsi_unblock_requests(shost); | ||
616 | } | 752 | } |
617 | 753 | ||
618 | static void sbp2_release_target(struct kref *kref) | 754 | static void sbp2_release_target(struct kref *kref) |
@@ -621,23 +757,24 @@ static void sbp2_release_target(struct kref *kref) | |||
621 | struct sbp2_logical_unit *lu, *next; | 757 | struct sbp2_logical_unit *lu, *next; |
622 | struct Scsi_Host *shost = | 758 | struct Scsi_Host *shost = |
623 | container_of((void *)tgt, struct Scsi_Host, hostdata[0]); | 759 | container_of((void *)tgt, struct Scsi_Host, hostdata[0]); |
624 | struct fw_device *device = fw_device(tgt->unit->device.parent); | 760 | |
761 | /* prevent deadlocks */ | ||
762 | sbp2_unblock(tgt); | ||
625 | 763 | ||
626 | list_for_each_entry_safe(lu, next, &tgt->lu_list, link) { | 764 | list_for_each_entry_safe(lu, next, &tgt->lu_list, link) { |
627 | if (lu->sdev) | 765 | if (lu->sdev) { |
628 | scsi_remove_device(lu->sdev); | 766 | scsi_remove_device(lu->sdev); |
629 | 767 | scsi_device_put(lu->sdev); | |
630 | if (!fw_device_is_shutdown(device)) | 768 | } |
631 | sbp2_send_management_orb(lu, tgt->node_id, | 769 | sbp2_send_management_orb(lu, tgt->node_id, lu->generation, |
632 | lu->generation, SBP2_LOGOUT_REQUEST, | 770 | SBP2_LOGOUT_REQUEST, lu->login_id, NULL); |
633 | lu->login_id, NULL); | ||
634 | 771 | ||
635 | fw_core_remove_address_handler(&lu->address_handler); | 772 | fw_core_remove_address_handler(&lu->address_handler); |
636 | list_del(&lu->link); | 773 | list_del(&lu->link); |
637 | kfree(lu); | 774 | kfree(lu); |
638 | } | 775 | } |
639 | scsi_remove_host(shost); | 776 | scsi_remove_host(shost); |
640 | fw_notify("released %s\n", tgt->unit->device.bus_id); | 777 | fw_notify("released %s\n", tgt->bus_id); |
641 | 778 | ||
642 | put_device(&tgt->unit->device); | 779 | put_device(&tgt->unit->device); |
643 | scsi_host_put(shost); | 780 | scsi_host_put(shost); |
@@ -666,33 +803,43 @@ static void sbp2_login(struct work_struct *work) | |||
666 | { | 803 | { |
667 | struct sbp2_logical_unit *lu = | 804 | struct sbp2_logical_unit *lu = |
668 | container_of(work, struct sbp2_logical_unit, work.work); | 805 | container_of(work, struct sbp2_logical_unit, work.work); |
669 | struct Scsi_Host *shost = | 806 | struct sbp2_target *tgt = lu->tgt; |
670 | container_of((void *)lu->tgt, struct Scsi_Host, hostdata[0]); | 807 | struct fw_device *device = fw_device(tgt->unit->device.parent); |
808 | struct Scsi_Host *shost; | ||
671 | struct scsi_device *sdev; | 809 | struct scsi_device *sdev; |
672 | struct scsi_lun eight_bytes_lun; | 810 | struct scsi_lun eight_bytes_lun; |
673 | struct fw_unit *unit = lu->tgt->unit; | ||
674 | struct fw_device *device = fw_device(unit->device.parent); | ||
675 | struct sbp2_login_response response; | 811 | struct sbp2_login_response response; |
676 | int generation, node_id, local_node_id; | 812 | int generation, node_id, local_node_id; |
677 | 813 | ||
814 | if (fw_device_is_shutdown(device)) | ||
815 | goto out; | ||
816 | |||
678 | generation = device->generation; | 817 | generation = device->generation; |
679 | smp_rmb(); /* node_id must not be older than generation */ | 818 | smp_rmb(); /* node_id must not be older than generation */ |
680 | node_id = device->node_id; | 819 | node_id = device->node_id; |
681 | local_node_id = device->card->node_id; | 820 | local_node_id = device->card->node_id; |
682 | 821 | ||
822 | /* If this is a re-login attempt, log out, or we might be rejected. */ | ||
823 | if (lu->sdev) | ||
824 | sbp2_send_management_orb(lu, device->node_id, generation, | ||
825 | SBP2_LOGOUT_REQUEST, lu->login_id, NULL); | ||
826 | |||
683 | if (sbp2_send_management_orb(lu, node_id, generation, | 827 | if (sbp2_send_management_orb(lu, node_id, generation, |
684 | SBP2_LOGIN_REQUEST, lu->lun, &response) < 0) { | 828 | SBP2_LOGIN_REQUEST, lu->lun, &response) < 0) { |
685 | if (lu->retries++ < 5) | 829 | if (lu->retries++ < 5) { |
686 | sbp2_queue_work(lu, DIV_ROUND_UP(HZ, 5)); | 830 | sbp2_queue_work(lu, DIV_ROUND_UP(HZ, 5)); |
687 | else | 831 | } else { |
688 | fw_error("failed to login to %s LUN %04x\n", | 832 | fw_error("%s: failed to login to LUN %04x\n", |
689 | unit->device.bus_id, lu->lun); | 833 | tgt->bus_id, lu->lun); |
834 | /* Let any waiting I/O fail from now on. */ | ||
835 | sbp2_unblock(lu->tgt); | ||
836 | } | ||
690 | goto out; | 837 | goto out; |
691 | } | 838 | } |
692 | 839 | ||
693 | lu->generation = generation; | 840 | tgt->node_id = node_id; |
694 | lu->tgt->node_id = node_id; | 841 | tgt->address_high = local_node_id << 16; |
695 | lu->tgt->address_high = local_node_id << 16; | 842 | sbp2_set_generation(lu, generation); |
696 | 843 | ||
697 | /* Get command block agent offset and login id. */ | 844 | /* Get command block agent offset and login id. */ |
698 | lu->command_block_agent_address = | 845 | lu->command_block_agent_address = |
@@ -700,8 +847,8 @@ static void sbp2_login(struct work_struct *work) | |||
700 | response.command_block_agent.low; | 847 | response.command_block_agent.low; |
701 | lu->login_id = LOGIN_RESPONSE_GET_LOGIN_ID(response); | 848 | lu->login_id = LOGIN_RESPONSE_GET_LOGIN_ID(response); |
702 | 849 | ||
703 | fw_notify("logged in to %s LUN %04x (%d retries)\n", | 850 | fw_notify("%s: logged in to LUN %04x (%d retries)\n", |
704 | unit->device.bus_id, lu->lun, lu->retries); | 851 | tgt->bus_id, lu->lun, lu->retries); |
705 | 852 | ||
706 | #if 0 | 853 | #if 0 |
707 | /* FIXME: The linux1394 sbp2 does this last step. */ | 854 | /* FIXME: The linux1394 sbp2 does this last step. */ |
@@ -711,26 +858,62 @@ static void sbp2_login(struct work_struct *work) | |||
711 | PREPARE_DELAYED_WORK(&lu->work, sbp2_reconnect); | 858 | PREPARE_DELAYED_WORK(&lu->work, sbp2_reconnect); |
712 | sbp2_agent_reset(lu); | 859 | sbp2_agent_reset(lu); |
713 | 860 | ||
861 | /* This was a re-login. */ | ||
862 | if (lu->sdev) { | ||
863 | sbp2_cancel_orbs(lu); | ||
864 | sbp2_conditionally_unblock(lu); | ||
865 | goto out; | ||
866 | } | ||
867 | |||
868 | if (lu->tgt->workarounds & SBP2_WORKAROUND_DELAY_INQUIRY) | ||
869 | ssleep(SBP2_INQUIRY_DELAY); | ||
870 | |||
714 | memset(&eight_bytes_lun, 0, sizeof(eight_bytes_lun)); | 871 | memset(&eight_bytes_lun, 0, sizeof(eight_bytes_lun)); |
715 | eight_bytes_lun.scsi_lun[0] = (lu->lun >> 8) & 0xff; | 872 | eight_bytes_lun.scsi_lun[0] = (lu->lun >> 8) & 0xff; |
716 | eight_bytes_lun.scsi_lun[1] = lu->lun & 0xff; | 873 | eight_bytes_lun.scsi_lun[1] = lu->lun & 0xff; |
874 | shost = container_of((void *)tgt, struct Scsi_Host, hostdata[0]); | ||
717 | 875 | ||
718 | sdev = __scsi_add_device(shost, 0, 0, | 876 | sdev = __scsi_add_device(shost, 0, 0, |
719 | scsilun_to_int(&eight_bytes_lun), lu); | 877 | scsilun_to_int(&eight_bytes_lun), lu); |
720 | if (IS_ERR(sdev)) { | 878 | /* |
721 | sbp2_send_management_orb(lu, node_id, generation, | 879 | * FIXME: We are unable to perform reconnects while in sbp2_login(). |
722 | SBP2_LOGOUT_REQUEST, lu->login_id, NULL); | 880 | * Therefore __scsi_add_device() will get into trouble if a bus reset |
723 | /* | 881 | * happens in parallel. It will either fail or leave us with an |
724 | * Set this back to sbp2_login so we fall back and | 882 | * unusable sdev. As a workaround we check for this and retry the |
725 | * retry login on bus reset. | 883 | * whole login and SCSI probing. |
726 | */ | 884 | */ |
727 | PREPARE_DELAYED_WORK(&lu->work, sbp2_login); | 885 | |
728 | } else { | 886 | /* Reported error during __scsi_add_device() */ |
729 | lu->sdev = sdev; | 887 | if (IS_ERR(sdev)) |
888 | goto out_logout_login; | ||
889 | |||
890 | /* Unreported error during __scsi_add_device() */ | ||
891 | smp_rmb(); /* get current card generation */ | ||
892 | if (generation != device->card->generation) { | ||
893 | scsi_remove_device(sdev); | ||
730 | scsi_device_put(sdev); | 894 | scsi_device_put(sdev); |
895 | goto out_logout_login; | ||
731 | } | 896 | } |
897 | |||
898 | /* No error during __scsi_add_device() */ | ||
899 | lu->sdev = sdev; | ||
900 | sbp2_allow_block(lu); | ||
901 | goto out; | ||
902 | |||
903 | out_logout_login: | ||
904 | smp_rmb(); /* generation may have changed */ | ||
905 | generation = device->generation; | ||
906 | smp_rmb(); /* node_id must not be older than generation */ | ||
907 | |||
908 | sbp2_send_management_orb(lu, device->node_id, generation, | ||
909 | SBP2_LOGOUT_REQUEST, lu->login_id, NULL); | ||
910 | /* | ||
911 | * If a bus reset happened, sbp2_update will have requeued | ||
912 | * lu->work already. Reset the work from reconnect to login. | ||
913 | */ | ||
914 | PREPARE_DELAYED_WORK(&lu->work, sbp2_login); | ||
732 | out: | 915 | out: |
733 | sbp2_target_put(lu->tgt); | 916 | sbp2_target_put(tgt); |
734 | } | 917 | } |
735 | 918 | ||
736 | static int sbp2_add_logical_unit(struct sbp2_target *tgt, int lun_entry) | 919 | 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) | |||
755 | lu->sdev = NULL; | 938 | lu->sdev = NULL; |
756 | lu->lun = lun_entry & 0xffff; | 939 | lu->lun = lun_entry & 0xffff; |
757 | lu->retries = 0; | 940 | lu->retries = 0; |
941 | lu->blocked = false; | ||
942 | ++tgt->dont_block; | ||
758 | INIT_LIST_HEAD(&lu->orb_list); | 943 | INIT_LIST_HEAD(&lu->orb_list); |
759 | INIT_DELAYED_WORK(&lu->work, sbp2_login); | 944 | INIT_DELAYED_WORK(&lu->work, sbp2_login); |
760 | 945 | ||
@@ -813,7 +998,7 @@ static int sbp2_scan_unit_dir(struct sbp2_target *tgt, u32 *directory, | |||
813 | if (timeout > tgt->mgt_orb_timeout) | 998 | if (timeout > tgt->mgt_orb_timeout) |
814 | fw_notify("%s: config rom contains %ds " | 999 | fw_notify("%s: config rom contains %ds " |
815 | "management ORB timeout, limiting " | 1000 | "management ORB timeout, limiting " |
816 | "to %ds\n", tgt->unit->device.bus_id, | 1001 | "to %ds\n", tgt->bus_id, |
817 | timeout / 1000, | 1002 | timeout / 1000, |
818 | tgt->mgt_orb_timeout / 1000); | 1003 | tgt->mgt_orb_timeout / 1000); |
819 | break; | 1004 | break; |
@@ -836,12 +1021,12 @@ static void sbp2_init_workarounds(struct sbp2_target *tgt, u32 model, | |||
836 | u32 firmware_revision) | 1021 | u32 firmware_revision) |
837 | { | 1022 | { |
838 | int i; | 1023 | int i; |
839 | unsigned w = sbp2_param_workarounds; | 1024 | unsigned int w = sbp2_param_workarounds; |
840 | 1025 | ||
841 | if (w) | 1026 | if (w) |
842 | fw_notify("Please notify linux1394-devel@lists.sourceforge.net " | 1027 | fw_notify("Please notify linux1394-devel@lists.sourceforge.net " |
843 | "if you need the workarounds parameter for %s\n", | 1028 | "if you need the workarounds parameter for %s\n", |
844 | tgt->unit->device.bus_id); | 1029 | tgt->bus_id); |
845 | 1030 | ||
846 | if (w & SBP2_WORKAROUND_OVERRIDE) | 1031 | if (w & SBP2_WORKAROUND_OVERRIDE) |
847 | goto out; | 1032 | goto out; |
@@ -863,8 +1048,7 @@ static void sbp2_init_workarounds(struct sbp2_target *tgt, u32 model, | |||
863 | if (w) | 1048 | if (w) |
864 | fw_notify("Workarounds for %s: 0x%x " | 1049 | fw_notify("Workarounds for %s: 0x%x " |
865 | "(firmware_revision 0x%06x, model_id 0x%06x)\n", | 1050 | "(firmware_revision 0x%06x, model_id 0x%06x)\n", |
866 | tgt->unit->device.bus_id, | 1051 | tgt->bus_id, w, firmware_revision, model); |
867 | w, firmware_revision, model); | ||
868 | tgt->workarounds = w; | 1052 | tgt->workarounds = w; |
869 | } | 1053 | } |
870 | 1054 | ||
@@ -888,6 +1072,7 @@ static int sbp2_probe(struct device *dev) | |||
888 | tgt->unit = unit; | 1072 | tgt->unit = unit; |
889 | kref_init(&tgt->kref); | 1073 | kref_init(&tgt->kref); |
890 | INIT_LIST_HEAD(&tgt->lu_list); | 1074 | INIT_LIST_HEAD(&tgt->lu_list); |
1075 | tgt->bus_id = unit->device.bus_id; | ||
891 | 1076 | ||
892 | if (fw_device_enable_phys_dma(device) < 0) | 1077 | if (fw_device_enable_phys_dma(device) < 0) |
893 | goto fail_shost_put; | 1078 | goto fail_shost_put; |
@@ -938,10 +1123,13 @@ static void sbp2_reconnect(struct work_struct *work) | |||
938 | { | 1123 | { |
939 | struct sbp2_logical_unit *lu = | 1124 | struct sbp2_logical_unit *lu = |
940 | container_of(work, struct sbp2_logical_unit, work.work); | 1125 | container_of(work, struct sbp2_logical_unit, work.work); |
941 | struct fw_unit *unit = lu->tgt->unit; | 1126 | struct sbp2_target *tgt = lu->tgt; |
942 | struct fw_device *device = fw_device(unit->device.parent); | 1127 | struct fw_device *device = fw_device(tgt->unit->device.parent); |
943 | int generation, node_id, local_node_id; | 1128 | int generation, node_id, local_node_id; |
944 | 1129 | ||
1130 | if (fw_device_is_shutdown(device)) | ||
1131 | goto out; | ||
1132 | |||
945 | generation = device->generation; | 1133 | generation = device->generation; |
946 | smp_rmb(); /* node_id must not be older than generation */ | 1134 | smp_rmb(); /* node_id must not be older than generation */ |
947 | node_id = device->node_id; | 1135 | node_id = device->node_id; |
@@ -950,10 +1138,17 @@ static void sbp2_reconnect(struct work_struct *work) | |||
950 | if (sbp2_send_management_orb(lu, node_id, generation, | 1138 | if (sbp2_send_management_orb(lu, node_id, generation, |
951 | SBP2_RECONNECT_REQUEST, | 1139 | SBP2_RECONNECT_REQUEST, |
952 | lu->login_id, NULL) < 0) { | 1140 | lu->login_id, NULL) < 0) { |
953 | if (lu->retries++ >= 5) { | 1141 | /* |
954 | fw_error("failed to reconnect to %s\n", | 1142 | * If reconnect was impossible even though we are in the |
955 | unit->device.bus_id); | 1143 | * current generation, fall back and try to log in again. |
956 | /* Fall back and try to log in again. */ | 1144 | * |
1145 | * We could check for "Function rejected" status, but | ||
1146 | * looking at the bus generation as simpler and more general. | ||
1147 | */ | ||
1148 | smp_rmb(); /* get current card generation */ | ||
1149 | if (generation == device->card->generation || | ||
1150 | lu->retries++ >= 5) { | ||
1151 | fw_error("%s: failed to reconnect\n", tgt->bus_id); | ||
957 | lu->retries = 0; | 1152 | lu->retries = 0; |
958 | PREPARE_DELAYED_WORK(&lu->work, sbp2_login); | 1153 | PREPARE_DELAYED_WORK(&lu->work, sbp2_login); |
959 | } | 1154 | } |
@@ -961,17 +1156,18 @@ static void sbp2_reconnect(struct work_struct *work) | |||
961 | goto out; | 1156 | goto out; |
962 | } | 1157 | } |
963 | 1158 | ||
964 | lu->generation = generation; | 1159 | tgt->node_id = node_id; |
965 | lu->tgt->node_id = node_id; | 1160 | tgt->address_high = local_node_id << 16; |
966 | lu->tgt->address_high = local_node_id << 16; | 1161 | sbp2_set_generation(lu, generation); |
967 | 1162 | ||
968 | fw_notify("reconnected to %s LUN %04x (%d retries)\n", | 1163 | fw_notify("%s: reconnected to LUN %04x (%d retries)\n", |
969 | unit->device.bus_id, lu->lun, lu->retries); | 1164 | tgt->bus_id, lu->lun, lu->retries); |
970 | 1165 | ||
971 | sbp2_agent_reset(lu); | 1166 | sbp2_agent_reset(lu); |
972 | sbp2_cancel_orbs(lu); | 1167 | sbp2_cancel_orbs(lu); |
1168 | sbp2_conditionally_unblock(lu); | ||
973 | out: | 1169 | out: |
974 | sbp2_target_put(lu->tgt); | 1170 | sbp2_target_put(tgt); |
975 | } | 1171 | } |
976 | 1172 | ||
977 | static void sbp2_update(struct fw_unit *unit) | 1173 | static void sbp2_update(struct fw_unit *unit) |
@@ -986,6 +1182,7 @@ static void sbp2_update(struct fw_unit *unit) | |||
986 | * Iteration over tgt->lu_list is therefore safe here. | 1182 | * Iteration over tgt->lu_list is therefore safe here. |
987 | */ | 1183 | */ |
988 | list_for_each_entry(lu, &tgt->lu_list, link) { | 1184 | list_for_each_entry(lu, &tgt->lu_list, link) { |
1185 | sbp2_conditionally_block(lu); | ||
989 | lu->retries = 0; | 1186 | lu->retries = 0; |
990 | sbp2_queue_work(lu, 0); | 1187 | sbp2_queue_work(lu, 0); |
991 | } | 1188 | } |
@@ -1063,7 +1260,7 @@ complete_command_orb(struct sbp2_orb *base_orb, struct sbp2_status *status) | |||
1063 | 1260 | ||
1064 | if (status != NULL) { | 1261 | if (status != NULL) { |
1065 | if (STATUS_GET_DEAD(*status)) | 1262 | if (STATUS_GET_DEAD(*status)) |
1066 | sbp2_agent_reset(orb->lu); | 1263 | sbp2_agent_reset_no_wait(orb->lu); |
1067 | 1264 | ||
1068 | switch (STATUS_GET_RESPONSE(*status)) { | 1265 | switch (STATUS_GET_RESPONSE(*status)) { |
1069 | case SBP2_STATUS_REQUEST_COMPLETE: | 1266 | case SBP2_STATUS_REQUEST_COMPLETE: |
@@ -1089,6 +1286,7 @@ complete_command_orb(struct sbp2_orb *base_orb, struct sbp2_status *status) | |||
1089 | * or when sending the write (less likely). | 1286 | * or when sending the write (less likely). |
1090 | */ | 1287 | */ |
1091 | result = DID_BUS_BUSY << 16; | 1288 | result = DID_BUS_BUSY << 16; |
1289 | sbp2_conditionally_block(orb->lu); | ||
1092 | } | 1290 | } |
1093 | 1291 | ||
1094 | dma_unmap_single(device->card->device, orb->base.request_bus, | 1292 | 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) | |||
1197 | struct sbp2_logical_unit *lu = cmd->device->hostdata; | 1395 | struct sbp2_logical_unit *lu = cmd->device->hostdata; |
1198 | struct fw_device *device = fw_device(lu->tgt->unit->device.parent); | 1396 | struct fw_device *device = fw_device(lu->tgt->unit->device.parent); |
1199 | struct sbp2_command_orb *orb; | 1397 | struct sbp2_command_orb *orb; |
1200 | unsigned max_payload; | 1398 | unsigned int max_payload; |
1201 | int retval = SCSI_MLQUEUE_HOST_BUSY; | 1399 | int retval = SCSI_MLQUEUE_HOST_BUSY; |
1202 | 1400 | ||
1203 | /* | 1401 | /* |
@@ -1275,6 +1473,10 @@ static int sbp2_scsi_slave_alloc(struct scsi_device *sdev) | |||
1275 | { | 1473 | { |
1276 | struct sbp2_logical_unit *lu = sdev->hostdata; | 1474 | struct sbp2_logical_unit *lu = sdev->hostdata; |
1277 | 1475 | ||
1476 | /* (Re-)Adding logical units via the SCSI stack is not supported. */ | ||
1477 | if (!lu) | ||
1478 | return -ENOSYS; | ||
1479 | |||
1278 | sdev->allow_restart = 1; | 1480 | sdev->allow_restart = 1; |
1279 | 1481 | ||
1280 | /* | 1482 | /* |
@@ -1319,7 +1521,7 @@ static int sbp2_scsi_abort(struct scsi_cmnd *cmd) | |||
1319 | { | 1521 | { |
1320 | struct sbp2_logical_unit *lu = cmd->device->hostdata; | 1522 | struct sbp2_logical_unit *lu = cmd->device->hostdata; |
1321 | 1523 | ||
1322 | fw_notify("sbp2_scsi_abort\n"); | 1524 | fw_notify("%s: sbp2_scsi_abort\n", lu->tgt->bus_id); |
1323 | sbp2_agent_reset(lu); | 1525 | sbp2_agent_reset(lu); |
1324 | sbp2_cancel_orbs(lu); | 1526 | sbp2_cancel_orbs(lu); |
1325 | 1527 | ||
diff --git a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c index 28e155a9e2a5..9e2b1964d71a 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 " | |||
183 | * Avoids access beyond actual disk limits on devices with an off-by-one bug. | 183 | * Avoids access beyond actual disk limits on devices with an off-by-one bug. |
184 | * Don't use this with devices which don't have this bug. | 184 | * Don't use this with devices which don't have this bug. |
185 | * | 185 | * |
186 | * - delay inquiry | ||
187 | * Wait extra SBP2_INQUIRY_DELAY seconds after login before SCSI inquiry. | ||
188 | * | ||
186 | * - override internal blacklist | 189 | * - override internal blacklist |
187 | * Instead of adding to the built-in blacklist, use only the workarounds | 190 | * Instead of adding to the built-in blacklist, use only the workarounds |
188 | * specified in the module load parameter. | 191 | * specified in the module load parameter. |
@@ -195,6 +198,7 @@ MODULE_PARM_DESC(workarounds, "Work around device bugs (default = 0" | |||
195 | ", 36 byte inquiry = " __stringify(SBP2_WORKAROUND_INQUIRY_36) | 198 | ", 36 byte inquiry = " __stringify(SBP2_WORKAROUND_INQUIRY_36) |
196 | ", skip mode page 8 = " __stringify(SBP2_WORKAROUND_MODE_SENSE_8) | 199 | ", skip mode page 8 = " __stringify(SBP2_WORKAROUND_MODE_SENSE_8) |
197 | ", fix capacity = " __stringify(SBP2_WORKAROUND_FIX_CAPACITY) | 200 | ", fix capacity = " __stringify(SBP2_WORKAROUND_FIX_CAPACITY) |
201 | ", delay inquiry = " __stringify(SBP2_WORKAROUND_DELAY_INQUIRY) | ||
198 | ", override internal blacklist = " __stringify(SBP2_WORKAROUND_OVERRIDE) | 202 | ", override internal blacklist = " __stringify(SBP2_WORKAROUND_OVERRIDE) |
199 | ", or a combination)"); | 203 | ", or a combination)"); |
200 | 204 | ||
@@ -357,6 +361,11 @@ static const struct { | |||
357 | .workarounds = SBP2_WORKAROUND_INQUIRY_36 | | 361 | .workarounds = SBP2_WORKAROUND_INQUIRY_36 | |
358 | SBP2_WORKAROUND_MODE_SENSE_8, | 362 | SBP2_WORKAROUND_MODE_SENSE_8, |
359 | }, | 363 | }, |
364 | /* DViCO Momobay FX-3A with TSB42AA9A bridge */ { | ||
365 | .firmware_revision = 0x002800, | ||
366 | .model_id = 0x000000, | ||
367 | .workarounds = SBP2_WORKAROUND_DELAY_INQUIRY, | ||
368 | }, | ||
360 | /* Initio bridges, actually only needed for some older ones */ { | 369 | /* Initio bridges, actually only needed for some older ones */ { |
361 | .firmware_revision = 0x000200, | 370 | .firmware_revision = 0x000200, |
362 | .model_id = SBP2_ROM_VALUE_WILDCARD, | 371 | .model_id = SBP2_ROM_VALUE_WILDCARD, |
@@ -914,6 +923,9 @@ static int sbp2_start_device(struct sbp2_lu *lu) | |||
914 | sbp2_agent_reset(lu, 1); | 923 | sbp2_agent_reset(lu, 1); |
915 | sbp2_max_speed_and_size(lu); | 924 | sbp2_max_speed_and_size(lu); |
916 | 925 | ||
926 | if (lu->workarounds & SBP2_WORKAROUND_DELAY_INQUIRY) | ||
927 | ssleep(SBP2_INQUIRY_DELAY); | ||
928 | |||
917 | error = scsi_add_device(lu->shost, 0, lu->ud->id, 0); | 929 | error = scsi_add_device(lu->shost, 0, lu->ud->id, 0); |
918 | if (error) { | 930 | if (error) { |
919 | SBP2_ERR("scsi_add_device failed"); | 931 | SBP2_ERR("scsi_add_device failed"); |
@@ -1962,6 +1974,9 @@ static int sbp2scsi_slave_alloc(struct scsi_device *sdev) | |||
1962 | { | 1974 | { |
1963 | struct sbp2_lu *lu = (struct sbp2_lu *)sdev->host->hostdata[0]; | 1975 | struct sbp2_lu *lu = (struct sbp2_lu *)sdev->host->hostdata[0]; |
1964 | 1976 | ||
1977 | if (sdev->lun != 0 || sdev->id != lu->ud->id || sdev->channel != 0) | ||
1978 | return -ENODEV; | ||
1979 | |||
1965 | lu->sdev = sdev; | 1980 | lu->sdev = sdev; |
1966 | sdev->allow_restart = 1; | 1981 | sdev->allow_restart = 1; |
1967 | 1982 | ||
diff --git a/drivers/ieee1394/sbp2.h b/drivers/ieee1394/sbp2.h index d2ecb0d8a1bb..80d8e097b065 100644 --- a/drivers/ieee1394/sbp2.h +++ b/drivers/ieee1394/sbp2.h | |||
@@ -343,6 +343,8 @@ enum sbp2lu_state_types { | |||
343 | #define SBP2_WORKAROUND_INQUIRY_36 0x2 | 343 | #define SBP2_WORKAROUND_INQUIRY_36 0x2 |
344 | #define SBP2_WORKAROUND_MODE_SENSE_8 0x4 | 344 | #define SBP2_WORKAROUND_MODE_SENSE_8 0x4 |
345 | #define SBP2_WORKAROUND_FIX_CAPACITY 0x8 | 345 | #define SBP2_WORKAROUND_FIX_CAPACITY 0x8 |
346 | #define SBP2_WORKAROUND_DELAY_INQUIRY 0x10 | ||
347 | #define SBP2_INQUIRY_DELAY 12 | ||
346 | #define SBP2_WORKAROUND_OVERRIDE 0x100 | 348 | #define SBP2_WORKAROUND_OVERRIDE 0x100 |
347 | 349 | ||
348 | #endif /* SBP2_H */ | 350 | #endif /* SBP2_H */ |