diff options
author | Kristian Høgsberg <krh@redhat.com> | 2007-02-06 14:49:33 -0500 |
---|---|---|
committer | Stefan Richter <stefanr@s5r6.in-berlin.de> | 2007-03-09 16:02:52 -0500 |
commit | 1d3d52c5367e0ca352aff6d6986533787bcf36d0 (patch) | |
tree | e151460d410ba18aeffb2d87d4c7d9ecf04dfe7b /drivers/firewire/fw-sbp2.c | |
parent | 730c32f58ba81b3a4fe6d19c7d9e9829dd96d363 (diff) |
firewire: fw-sbp2: Do ORB timeout right.
When a management ORB times out, either because the fw_transaction
times out or when we don't get the status write, we need to properly
cancel the entire operation.
Signed-off-by: Kristian Høgsberg <krh@redhat.com>
Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
Diffstat (limited to 'drivers/firewire/fw-sbp2.c')
-rw-r--r-- | drivers/firewire/fw-sbp2.c | 24 |
1 files changed, 21 insertions, 3 deletions
diff --git a/drivers/firewire/fw-sbp2.c b/drivers/firewire/fw-sbp2.c index bb133398feec..c196333e1de9 100644 --- a/drivers/firewire/fw-sbp2.c +++ b/drivers/firewire/fw-sbp2.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/device.h> | 24 | #include <linux/device.h> |
25 | #include <linux/scatterlist.h> | 25 | #include <linux/scatterlist.h> |
26 | #include <linux/dma-mapping.h> | 26 | #include <linux/dma-mapping.h> |
27 | #include <linux/timer.h> | ||
27 | 28 | ||
28 | #include <scsi/scsi.h> | 29 | #include <scsi/scsi.h> |
29 | #include <scsi/scsi_cmnd.h> | 30 | #include <scsi/scsi_cmnd.h> |
@@ -58,12 +59,16 @@ struct sbp2_device { | |||
58 | int address_high; | 59 | int address_high; |
59 | int generation; | 60 | int generation; |
60 | 61 | ||
62 | /* Timer for flushing ORBs. */ | ||
63 | struct timer_list orb_timer; | ||
64 | |||
61 | struct work_struct work; | 65 | struct work_struct work; |
62 | struct Scsi_Host *scsi_host; | 66 | struct Scsi_Host *scsi_host; |
63 | }; | 67 | }; |
64 | 68 | ||
65 | #define SBP2_MAX_SG_ELEMENT_LENGTH 0xf000 | 69 | #define SBP2_MAX_SG_ELEMENT_LENGTH 0xf000 |
66 | #define SBP2_MAX_SECTORS 255 /* Max sectors supported */ | 70 | #define SBP2_MAX_SECTORS 255 /* Max sectors supported */ |
71 | #define SBP2_ORB_TIMEOUT 2000 /* Timeout in ms */ | ||
67 | 72 | ||
68 | #define SBP2_ORB_NULL 0x80000000 | 73 | #define SBP2_ORB_NULL 0x80000000 |
69 | 74 | ||
@@ -327,6 +332,9 @@ sbp2_send_orb(struct sbp2_orb *orb, struct fw_unit *unit, | |||
327 | list_add_tail(&orb->link, &sd->orb_list); | 332 | list_add_tail(&orb->link, &sd->orb_list); |
328 | spin_unlock_irqrestore(&device->card->lock, flags); | 333 | spin_unlock_irqrestore(&device->card->lock, flags); |
329 | 334 | ||
335 | mod_timer(&sd->orb_timer, | ||
336 | jiffies + DIV_ROUND_UP(SBP2_ORB_TIMEOUT * HZ, 1000)); | ||
337 | |||
330 | fw_send_request(device->card, &orb->t, TCODE_WRITE_BLOCK_REQUEST, | 338 | fw_send_request(device->card, &orb->t, TCODE_WRITE_BLOCK_REQUEST, |
331 | node_id, generation, | 339 | node_id, generation, |
332 | device->node->max_speed, offset, | 340 | device->node->max_speed, offset, |
@@ -356,6 +364,13 @@ static void sbp2_cancel_orbs(struct fw_unit *unit) | |||
356 | } | 364 | } |
357 | } | 365 | } |
358 | 366 | ||
367 | static void orb_timer_callback(unsigned long data) | ||
368 | { | ||
369 | struct sbp2_device *sd = (struct sbp2_device *)data; | ||
370 | |||
371 | sbp2_cancel_orbs(sd->unit); | ||
372 | } | ||
373 | |||
359 | static void | 374 | static void |
360 | complete_management_orb(struct sbp2_orb *base_orb, struct sbp2_status *status) | 375 | complete_management_orb(struct sbp2_orb *base_orb, struct sbp2_status *status) |
361 | { | 376 | { |
@@ -374,7 +389,6 @@ sbp2_send_management_orb(struct fw_unit *unit, int node_id, int generation, | |||
374 | struct fw_device *device = fw_device(unit->device.parent); | 389 | struct fw_device *device = fw_device(unit->device.parent); |
375 | struct sbp2_device *sd = unit->device.driver_data; | 390 | struct sbp2_device *sd = unit->device.driver_data; |
376 | struct sbp2_management_orb *orb; | 391 | struct sbp2_management_orb *orb; |
377 | unsigned long timeout; | ||
378 | int retval = -ENOMEM; | 392 | int retval = -ENOMEM; |
379 | 393 | ||
380 | orb = kzalloc(sizeof *orb, GFP_ATOMIC); | 394 | orb = kzalloc(sizeof *orb, GFP_ATOMIC); |
@@ -426,7 +440,7 @@ sbp2_send_management_orb(struct fw_unit *unit, int node_id, int generation, | |||
426 | sbp2_send_orb(&orb->base, unit, | 440 | sbp2_send_orb(&orb->base, unit, |
427 | node_id, generation, sd->management_agent_address); | 441 | node_id, generation, sd->management_agent_address); |
428 | 442 | ||
429 | timeout = wait_for_completion_timeout(&orb->done, 10 * HZ); | 443 | wait_for_completion(&orb->done); |
430 | 444 | ||
431 | /* FIXME: Handle bus reset race here. */ | 445 | /* FIXME: Handle bus reset race here. */ |
432 | 446 | ||
@@ -437,7 +451,7 @@ sbp2_send_management_orb(struct fw_unit *unit, int node_id, int generation, | |||
437 | goto out; | 451 | goto out; |
438 | } | 452 | } |
439 | 453 | ||
440 | if (timeout == 0) { | 454 | if (orb->base.rcode == RCODE_CANCELLED) { |
441 | fw_error("orb reply timed out, rcode=0x%02x\n", | 455 | fw_error("orb reply timed out, rcode=0x%02x\n", |
442 | orb->base.rcode); | 456 | orb->base.rcode); |
443 | goto out; | 457 | goto out; |
@@ -516,6 +530,7 @@ static int sbp2_probe(struct device *dev) | |||
516 | unit->device.driver_data = sd; | 530 | unit->device.driver_data = sd; |
517 | sd->unit = unit; | 531 | sd->unit = unit; |
518 | INIT_LIST_HEAD(&sd->orb_list); | 532 | INIT_LIST_HEAD(&sd->orb_list); |
533 | setup_timer(&sd->orb_timer, orb_timer_callback, (unsigned long)sd); | ||
519 | 534 | ||
520 | sd->address_handler.length = 0x100; | 535 | sd->address_handler.length = 0x100; |
521 | sd->address_handler.address_callback = sbp2_status_write; | 536 | sd->address_handler.address_callback = sbp2_status_write; |
@@ -583,6 +598,7 @@ static int sbp2_probe(struct device *dev) | |||
583 | if (sbp2_send_management_orb(unit, node_id, generation, | 598 | if (sbp2_send_management_orb(unit, node_id, generation, |
584 | SBP2_LOGIN_REQUEST, lun, &response) < 0) { | 599 | SBP2_LOGIN_REQUEST, lun, &response) < 0) { |
585 | fw_core_remove_address_handler(&sd->address_handler); | 600 | fw_core_remove_address_handler(&sd->address_handler); |
601 | del_timer_sync(&sd->orb_timer); | ||
586 | kfree(sd); | 602 | kfree(sd); |
587 | return -EBUSY; | 603 | return -EBUSY; |
588 | } | 604 | } |
@@ -618,6 +634,7 @@ static int sbp2_probe(struct device *dev) | |||
618 | SBP2_LOGOUT_REQUEST, sd->login_id, | 634 | SBP2_LOGOUT_REQUEST, sd->login_id, |
619 | NULL); | 635 | NULL); |
620 | fw_core_remove_address_handler(&sd->address_handler); | 636 | fw_core_remove_address_handler(&sd->address_handler); |
637 | del_timer_sync(&sd->orb_timer); | ||
621 | kfree(sd); | 638 | kfree(sd); |
622 | return retval; | 639 | return retval; |
623 | } | 640 | } |
@@ -634,6 +651,7 @@ static int sbp2_remove(struct device *dev) | |||
634 | SBP2_LOGOUT_REQUEST, sd->login_id, NULL); | 651 | SBP2_LOGOUT_REQUEST, sd->login_id, NULL); |
635 | 652 | ||
636 | remove_scsi_devices(unit); | 653 | remove_scsi_devices(unit); |
654 | del_timer_sync(&sd->orb_timer); | ||
637 | 655 | ||
638 | fw_core_remove_address_handler(&sd->address_handler); | 656 | fw_core_remove_address_handler(&sd->address_handler); |
639 | kfree(sd); | 657 | kfree(sd); |