diff options
Diffstat (limited to 'drivers/firewire/fw-sbp2.c')
-rw-r--r-- | drivers/firewire/fw-sbp2.c | 49 |
1 files changed, 40 insertions, 9 deletions
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 | } |