diff options
author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-08-25 14:24:53 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-08-25 14:24:53 -0400 |
commit | f2154eef2a926435cdf79156cd361092d6cba91e (patch) | |
tree | bc92864fd906158d65f8792af2e166dd68fa4a50 | |
parent | 6ae26fa468533c86aaa6936fd366142fcf01386f (diff) | |
parent | e57d2011a6276d55a87f26653a0395f302ce0d51 (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: Add ref-counting for sbp2 orbs (fix command abortion)
firewire: fix unloading of fw-ohci while devices are attached
ieee1394: sbp2: fix sbp2_remove_device for error cases
-rw-r--r-- | drivers/firewire/fw-card.c | 6 | ||||
-rw-r--r-- | drivers/firewire/fw-sbp2.c | 49 | ||||
-rw-r--r-- | drivers/ieee1394/sbp2.c | 14 |
3 files changed, 51 insertions, 18 deletions
diff --git a/drivers/firewire/fw-card.c b/drivers/firewire/fw-card.c index 0aeab3218bb6..3e9719948a8e 100644 --- a/drivers/firewire/fw-card.c +++ b/drivers/firewire/fw-card.c | |||
@@ -510,9 +510,11 @@ fw_core_remove_card(struct fw_card *card) | |||
510 | /* Set up the dummy driver. */ | 510 | /* Set up the dummy driver. */ |
511 | card->driver = &dummy_driver; | 511 | card->driver = &dummy_driver; |
512 | 512 | ||
513 | fw_flush_transactions(card); | ||
514 | |||
515 | fw_destroy_nodes(card); | 513 | fw_destroy_nodes(card); |
514 | flush_scheduled_work(); | ||
515 | |||
516 | fw_flush_transactions(card); | ||
517 | del_timer_sync(&card->flush_timer); | ||
516 | 518 | ||
517 | fw_card_put(card); | 519 | fw_card_put(card); |
518 | } | 520 | } |
diff --git a/drivers/firewire/fw-sbp2.c b/drivers/firewire/fw-sbp2.c index ba816ef6def1..238730f75db1 100644 --- a/drivers/firewire/fw-sbp2.c +++ b/drivers/firewire/fw-sbp2.c | |||
@@ -159,6 +159,7 @@ struct sbp2_pointer { | |||
159 | 159 | ||
160 | struct sbp2_orb { | 160 | struct sbp2_orb { |
161 | struct fw_transaction t; | 161 | struct fw_transaction t; |
162 | struct kref kref; | ||
162 | dma_addr_t request_bus; | 163 | dma_addr_t request_bus; |
163 | int rcode; | 164 | int rcode; |
164 | struct sbp2_pointer pointer; | 165 | struct sbp2_pointer pointer; |
@@ -280,6 +281,14 @@ static const struct { | |||
280 | }; | 281 | }; |
281 | 282 | ||
282 | static void | 283 | static void |
284 | free_orb(struct kref *kref) | ||
285 | { | ||
286 | struct sbp2_orb *orb = container_of(kref, struct sbp2_orb, kref); | ||
287 | |||
288 | kfree(orb); | ||
289 | } | ||
290 | |||
291 | static void | ||
283 | sbp2_status_write(struct fw_card *card, struct fw_request *request, | 292 | sbp2_status_write(struct fw_card *card, struct fw_request *request, |
284 | int tcode, int destination, int source, | 293 | int tcode, int destination, int source, |
285 | int generation, int speed, | 294 | int generation, int speed, |
@@ -312,8 +321,8 @@ sbp2_status_write(struct fw_card *card, struct fw_request *request, | |||
312 | spin_lock_irqsave(&card->lock, flags); | 321 | spin_lock_irqsave(&card->lock, flags); |
313 | list_for_each_entry(orb, &sd->orb_list, link) { | 322 | list_for_each_entry(orb, &sd->orb_list, link) { |
314 | if (STATUS_GET_ORB_HIGH(status) == 0 && | 323 | if (STATUS_GET_ORB_HIGH(status) == 0 && |
315 | STATUS_GET_ORB_LOW(status) == orb->request_bus && | 324 | STATUS_GET_ORB_LOW(status) == orb->request_bus) { |
316 | orb->rcode == RCODE_COMPLETE) { | 325 | orb->rcode = RCODE_COMPLETE; |
317 | list_del(&orb->link); | 326 | list_del(&orb->link); |
318 | break; | 327 | break; |
319 | } | 328 | } |
@@ -325,6 +334,8 @@ sbp2_status_write(struct fw_card *card, struct fw_request *request, | |||
325 | else | 334 | else |
326 | fw_error("status write for unknown orb\n"); | 335 | fw_error("status write for unknown orb\n"); |
327 | 336 | ||
337 | kref_put(&orb->kref, free_orb); | ||
338 | |||
328 | fw_send_response(card, request, RCODE_COMPLETE); | 339 | fw_send_response(card, request, RCODE_COMPLETE); |
329 | } | 340 | } |
330 | 341 | ||
@@ -335,13 +346,27 @@ complete_transaction(struct fw_card *card, int rcode, | |||
335 | struct sbp2_orb *orb = data; | 346 | struct sbp2_orb *orb = data; |
336 | unsigned long flags; | 347 | unsigned long flags; |
337 | 348 | ||
338 | orb->rcode = rcode; | 349 | /* |
339 | if (rcode != RCODE_COMPLETE) { | 350 | * This is a little tricky. We can get the status write for |
340 | spin_lock_irqsave(&card->lock, flags); | 351 | * the orb before we get this callback. The status write |
352 | * handler above will assume the orb pointer transaction was | ||
353 | * successful and set the rcode to RCODE_COMPLETE for the orb. | ||
354 | * So this callback only sets the rcode if it hasn't already | ||
355 | * been set and only does the cleanup if the transaction | ||
356 | * failed and we didn't already get a status write. | ||
357 | */ | ||
358 | spin_lock_irqsave(&card->lock, flags); | ||
359 | |||
360 | if (orb->rcode == -1) | ||
361 | orb->rcode = rcode; | ||
362 | if (orb->rcode != RCODE_COMPLETE) { | ||
341 | list_del(&orb->link); | 363 | list_del(&orb->link); |
342 | spin_unlock_irqrestore(&card->lock, flags); | ||
343 | orb->callback(orb, NULL); | 364 | orb->callback(orb, NULL); |
344 | } | 365 | } |
366 | |||
367 | spin_unlock_irqrestore(&card->lock, flags); | ||
368 | |||
369 | kref_put(&orb->kref, free_orb); | ||
345 | } | 370 | } |
346 | 371 | ||
347 | static void | 372 | static void |
@@ -360,6 +385,10 @@ sbp2_send_orb(struct sbp2_orb *orb, struct fw_unit *unit, | |||
360 | list_add_tail(&orb->link, &sd->orb_list); | 385 | list_add_tail(&orb->link, &sd->orb_list); |
361 | spin_unlock_irqrestore(&device->card->lock, flags); | 386 | spin_unlock_irqrestore(&device->card->lock, flags); |
362 | 387 | ||
388 | /* Take a ref for the orb list and for the transaction callback. */ | ||
389 | kref_get(&orb->kref); | ||
390 | kref_get(&orb->kref); | ||
391 | |||
363 | fw_send_request(device->card, &orb->t, TCODE_WRITE_BLOCK_REQUEST, | 392 | fw_send_request(device->card, &orb->t, TCODE_WRITE_BLOCK_REQUEST, |
364 | node_id, generation, device->max_speed, offset, | 393 | node_id, generation, device->max_speed, offset, |
365 | &orb->pointer, sizeof(orb->pointer), | 394 | &orb->pointer, sizeof(orb->pointer), |
@@ -416,6 +445,7 @@ sbp2_send_management_orb(struct fw_unit *unit, int node_id, int generation, | |||
416 | if (orb == NULL) | 445 | if (orb == NULL) |
417 | return -ENOMEM; | 446 | return -ENOMEM; |
418 | 447 | ||
448 | kref_init(&orb->base.kref); | ||
419 | orb->response_bus = | 449 | orb->response_bus = |
420 | dma_map_single(device->card->device, &orb->response, | 450 | dma_map_single(device->card->device, &orb->response, |
421 | sizeof(orb->response), DMA_FROM_DEVICE); | 451 | sizeof(orb->response), DMA_FROM_DEVICE); |
@@ -490,7 +520,7 @@ sbp2_send_management_orb(struct fw_unit *unit, int node_id, int generation, | |||
490 | if (response) | 520 | if (response) |
491 | fw_memcpy_from_be32(response, | 521 | fw_memcpy_from_be32(response, |
492 | orb->response, sizeof(orb->response)); | 522 | orb->response, sizeof(orb->response)); |
493 | kfree(orb); | 523 | kref_put(&orb->base.kref, free_orb); |
494 | 524 | ||
495 | return retval; | 525 | return retval; |
496 | } | 526 | } |
@@ -886,7 +916,6 @@ complete_command_orb(struct sbp2_orb *base_orb, struct sbp2_status *status) | |||
886 | 916 | ||
887 | orb->cmd->result = result; | 917 | orb->cmd->result = result; |
888 | orb->done(orb->cmd); | 918 | orb->done(orb->cmd); |
889 | kfree(orb); | ||
890 | } | 919 | } |
891 | 920 | ||
892 | static int sbp2_command_orb_map_scatterlist(struct sbp2_command_orb *orb) | 921 | static int sbp2_command_orb_map_scatterlist(struct sbp2_command_orb *orb) |
@@ -1005,6 +1034,7 @@ static int sbp2_scsi_queuecommand(struct scsi_cmnd *cmd, scsi_done_fn_t done) | |||
1005 | 1034 | ||
1006 | /* Initialize rcode to something not RCODE_COMPLETE. */ | 1035 | /* Initialize rcode to something not RCODE_COMPLETE. */ |
1007 | orb->base.rcode = -1; | 1036 | orb->base.rcode = -1; |
1037 | kref_init(&orb->base.kref); | ||
1008 | 1038 | ||
1009 | orb->unit = unit; | 1039 | orb->unit = unit; |
1010 | orb->done = done; | 1040 | orb->done = done; |
@@ -1051,10 +1081,11 @@ static int sbp2_scsi_queuecommand(struct scsi_cmnd *cmd, scsi_done_fn_t done) | |||
1051 | sbp2_send_orb(&orb->base, unit, sd->node_id, sd->generation, | 1081 | sbp2_send_orb(&orb->base, unit, sd->node_id, sd->generation, |
1052 | sd->command_block_agent_address + SBP2_ORB_POINTER); | 1082 | sd->command_block_agent_address + SBP2_ORB_POINTER); |
1053 | 1083 | ||
1084 | kref_put(&orb->base.kref, free_orb); | ||
1054 | return 0; | 1085 | return 0; |
1055 | 1086 | ||
1056 | fail_mapping: | 1087 | fail_mapping: |
1057 | kfree(orb); | 1088 | kref_put(&orb->base.kref, free_orb); |
1058 | fail_alloc: | 1089 | fail_alloc: |
1059 | return SCSI_MLQUEUE_HOST_BUSY; | 1090 | return SCSI_MLQUEUE_HOST_BUSY; |
1060 | } | 1091 | } |
diff --git a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c index 47dbe8f17e82..a81ba8fca0db 100644 --- a/drivers/ieee1394/sbp2.c +++ b/drivers/ieee1394/sbp2.c | |||
@@ -513,9 +513,9 @@ static int sbp2util_create_command_orb_pool(struct sbp2_lu *lu) | |||
513 | return 0; | 513 | return 0; |
514 | } | 514 | } |
515 | 515 | ||
516 | static void sbp2util_remove_command_orb_pool(struct sbp2_lu *lu) | 516 | static void sbp2util_remove_command_orb_pool(struct sbp2_lu *lu, |
517 | struct hpsb_host *host) | ||
517 | { | 518 | { |
518 | struct hpsb_host *host = lu->hi->host; | ||
519 | struct list_head *lh, *next; | 519 | struct list_head *lh, *next; |
520 | struct sbp2_command_info *cmd; | 520 | struct sbp2_command_info *cmd; |
521 | unsigned long flags; | 521 | unsigned long flags; |
@@ -922,15 +922,16 @@ static void sbp2_remove_device(struct sbp2_lu *lu) | |||
922 | 922 | ||
923 | if (!lu) | 923 | if (!lu) |
924 | return; | 924 | return; |
925 | |||
926 | hi = lu->hi; | 925 | hi = lu->hi; |
926 | if (!hi) | ||
927 | goto no_hi; | ||
927 | 928 | ||
928 | if (lu->shost) { | 929 | if (lu->shost) { |
929 | scsi_remove_host(lu->shost); | 930 | scsi_remove_host(lu->shost); |
930 | scsi_host_put(lu->shost); | 931 | scsi_host_put(lu->shost); |
931 | } | 932 | } |
932 | flush_scheduled_work(); | 933 | flush_scheduled_work(); |
933 | sbp2util_remove_command_orb_pool(lu); | 934 | sbp2util_remove_command_orb_pool(lu, hi->host); |
934 | 935 | ||
935 | list_del(&lu->lu_list); | 936 | list_del(&lu->lu_list); |
936 | 937 | ||
@@ -971,9 +972,8 @@ static void sbp2_remove_device(struct sbp2_lu *lu) | |||
971 | 972 | ||
972 | lu->ud->device.driver_data = NULL; | 973 | lu->ud->device.driver_data = NULL; |
973 | 974 | ||
974 | if (hi) | 975 | module_put(hi->host->driver->owner); |
975 | module_put(hi->host->driver->owner); | 976 | no_hi: |
976 | |||
977 | kfree(lu); | 977 | kfree(lu); |
978 | } | 978 | } |
979 | 979 | ||