firewire: fw-sbp2: wait for completion of fetch agent reset
authorStefan Richter <stefanr@s5r6.in-berlin.de>
Sun, 3 Feb 2008 22:08:58 +0000 (23:08 +0100)
committerStefan Richter <stefanr@s5r6.in-berlin.de>
Sat, 16 Feb 2008 14:40:34 +0000 (15:40 +0100)
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@s5r6.in-berlin.de>
drivers/firewire/fw-sbp2.c

index 4a118fb..32b50f1 100644 (file)
@@ -603,29 +603,46 @@ 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)
 {
-       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)
@@ -1086,7 +1103,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: