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
This commit is contained in:
commit
f2154eef2a
3 changed files with 51 additions and 18 deletions
|
@ -510,9 +510,11 @@ fw_core_remove_card(struct fw_card *card)
|
||||||
/* Set up the dummy driver. */
|
/* Set up the dummy driver. */
|
||||||
card->driver = &dummy_driver;
|
card->driver = &dummy_driver;
|
||||||
|
|
||||||
fw_flush_transactions(card);
|
|
||||||
|
|
||||||
fw_destroy_nodes(card);
|
fw_destroy_nodes(card);
|
||||||
|
flush_scheduled_work();
|
||||||
|
|
||||||
|
fw_flush_transactions(card);
|
||||||
|
del_timer_sync(&card->flush_timer);
|
||||||
|
|
||||||
fw_card_put(card);
|
fw_card_put(card);
|
||||||
}
|
}
|
||||||
|
|
|
@ -159,6 +159,7 @@ struct sbp2_pointer {
|
||||||
|
|
||||||
struct sbp2_orb {
|
struct sbp2_orb {
|
||||||
struct fw_transaction t;
|
struct fw_transaction t;
|
||||||
|
struct kref kref;
|
||||||
dma_addr_t request_bus;
|
dma_addr_t request_bus;
|
||||||
int rcode;
|
int rcode;
|
||||||
struct sbp2_pointer pointer;
|
struct sbp2_pointer pointer;
|
||||||
|
@ -279,6 +280,14 @@ static const struct {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
free_orb(struct kref *kref)
|
||||||
|
{
|
||||||
|
struct sbp2_orb *orb = container_of(kref, struct sbp2_orb, kref);
|
||||||
|
|
||||||
|
kfree(orb);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
sbp2_status_write(struct fw_card *card, struct fw_request *request,
|
sbp2_status_write(struct fw_card *card, struct fw_request *request,
|
||||||
int tcode, int destination, int source,
|
int tcode, int destination, int source,
|
||||||
|
@ -312,8 +321,8 @@ sbp2_status_write(struct fw_card *card, struct fw_request *request,
|
||||||
spin_lock_irqsave(&card->lock, flags);
|
spin_lock_irqsave(&card->lock, flags);
|
||||||
list_for_each_entry(orb, &sd->orb_list, link) {
|
list_for_each_entry(orb, &sd->orb_list, link) {
|
||||||
if (STATUS_GET_ORB_HIGH(status) == 0 &&
|
if (STATUS_GET_ORB_HIGH(status) == 0 &&
|
||||||
STATUS_GET_ORB_LOW(status) == orb->request_bus &&
|
STATUS_GET_ORB_LOW(status) == orb->request_bus) {
|
||||||
orb->rcode == RCODE_COMPLETE) {
|
orb->rcode = RCODE_COMPLETE;
|
||||||
list_del(&orb->link);
|
list_del(&orb->link);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -325,6 +334,8 @@ sbp2_status_write(struct fw_card *card, struct fw_request *request,
|
||||||
else
|
else
|
||||||
fw_error("status write for unknown orb\n");
|
fw_error("status write for unknown orb\n");
|
||||||
|
|
||||||
|
kref_put(&orb->kref, free_orb);
|
||||||
|
|
||||||
fw_send_response(card, request, RCODE_COMPLETE);
|
fw_send_response(card, request, RCODE_COMPLETE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -335,13 +346,27 @@ complete_transaction(struct fw_card *card, int rcode,
|
||||||
struct sbp2_orb *orb = data;
|
struct sbp2_orb *orb = data;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
orb->rcode = rcode;
|
/*
|
||||||
if (rcode != RCODE_COMPLETE) {
|
* This is a little tricky. We can get the status write for
|
||||||
spin_lock_irqsave(&card->lock, flags);
|
* the orb before we get this callback. The status write
|
||||||
|
* handler above will assume the orb pointer transaction was
|
||||||
|
* successful and set the rcode to RCODE_COMPLETE for the orb.
|
||||||
|
* So this callback only sets the rcode if it hasn't already
|
||||||
|
* been set and only does the cleanup if the transaction
|
||||||
|
* failed and we didn't already get a status write.
|
||||||
|
*/
|
||||||
|
spin_lock_irqsave(&card->lock, flags);
|
||||||
|
|
||||||
|
if (orb->rcode == -1)
|
||||||
|
orb->rcode = rcode;
|
||||||
|
if (orb->rcode != RCODE_COMPLETE) {
|
||||||
list_del(&orb->link);
|
list_del(&orb->link);
|
||||||
spin_unlock_irqrestore(&card->lock, flags);
|
|
||||||
orb->callback(orb, NULL);
|
orb->callback(orb, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
spin_unlock_irqrestore(&card->lock, flags);
|
||||||
|
|
||||||
|
kref_put(&orb->kref, free_orb);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -360,6 +385,10 @@ sbp2_send_orb(struct sbp2_orb *orb, struct fw_unit *unit,
|
||||||
list_add_tail(&orb->link, &sd->orb_list);
|
list_add_tail(&orb->link, &sd->orb_list);
|
||||||
spin_unlock_irqrestore(&device->card->lock, flags);
|
spin_unlock_irqrestore(&device->card->lock, flags);
|
||||||
|
|
||||||
|
/* Take a ref for the orb list and for the transaction callback. */
|
||||||
|
kref_get(&orb->kref);
|
||||||
|
kref_get(&orb->kref);
|
||||||
|
|
||||||
fw_send_request(device->card, &orb->t, TCODE_WRITE_BLOCK_REQUEST,
|
fw_send_request(device->card, &orb->t, TCODE_WRITE_BLOCK_REQUEST,
|
||||||
node_id, generation, device->max_speed, offset,
|
node_id, generation, device->max_speed, offset,
|
||||||
&orb->pointer, sizeof(orb->pointer),
|
&orb->pointer, sizeof(orb->pointer),
|
||||||
|
@ -416,6 +445,7 @@ sbp2_send_management_orb(struct fw_unit *unit, int node_id, int generation,
|
||||||
if (orb == NULL)
|
if (orb == NULL)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
kref_init(&orb->base.kref);
|
||||||
orb->response_bus =
|
orb->response_bus =
|
||||||
dma_map_single(device->card->device, &orb->response,
|
dma_map_single(device->card->device, &orb->response,
|
||||||
sizeof(orb->response), DMA_FROM_DEVICE);
|
sizeof(orb->response), DMA_FROM_DEVICE);
|
||||||
|
@ -490,7 +520,7 @@ sbp2_send_management_orb(struct fw_unit *unit, int node_id, int generation,
|
||||||
if (response)
|
if (response)
|
||||||
fw_memcpy_from_be32(response,
|
fw_memcpy_from_be32(response,
|
||||||
orb->response, sizeof(orb->response));
|
orb->response, sizeof(orb->response));
|
||||||
kfree(orb);
|
kref_put(&orb->base.kref, free_orb);
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
@ -886,7 +916,6 @@ complete_command_orb(struct sbp2_orb *base_orb, struct sbp2_status *status)
|
||||||
|
|
||||||
orb->cmd->result = result;
|
orb->cmd->result = result;
|
||||||
orb->done(orb->cmd);
|
orb->done(orb->cmd);
|
||||||
kfree(orb);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sbp2_command_orb_map_scatterlist(struct sbp2_command_orb *orb)
|
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)
|
||||||
|
|
||||||
/* Initialize rcode to something not RCODE_COMPLETE. */
|
/* Initialize rcode to something not RCODE_COMPLETE. */
|
||||||
orb->base.rcode = -1;
|
orb->base.rcode = -1;
|
||||||
|
kref_init(&orb->base.kref);
|
||||||
|
|
||||||
orb->unit = unit;
|
orb->unit = unit;
|
||||||
orb->done = done;
|
orb->done = done;
|
||||||
|
@ -1051,10 +1081,11 @@ static int sbp2_scsi_queuecommand(struct scsi_cmnd *cmd, scsi_done_fn_t done)
|
||||||
sbp2_send_orb(&orb->base, unit, sd->node_id, sd->generation,
|
sbp2_send_orb(&orb->base, unit, sd->node_id, sd->generation,
|
||||||
sd->command_block_agent_address + SBP2_ORB_POINTER);
|
sd->command_block_agent_address + SBP2_ORB_POINTER);
|
||||||
|
|
||||||
|
kref_put(&orb->base.kref, free_orb);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
fail_mapping:
|
fail_mapping:
|
||||||
kfree(orb);
|
kref_put(&orb->base.kref, free_orb);
|
||||||
fail_alloc:
|
fail_alloc:
|
||||||
return SCSI_MLQUEUE_HOST_BUSY;
|
return SCSI_MLQUEUE_HOST_BUSY;
|
||||||
}
|
}
|
||||||
|
|
|
@ -513,9 +513,9 @@ static int sbp2util_create_command_orb_pool(struct sbp2_lu *lu)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sbp2util_remove_command_orb_pool(struct sbp2_lu *lu)
|
static void sbp2util_remove_command_orb_pool(struct sbp2_lu *lu,
|
||||||
|
struct hpsb_host *host)
|
||||||
{
|
{
|
||||||
struct hpsb_host *host = lu->hi->host;
|
|
||||||
struct list_head *lh, *next;
|
struct list_head *lh, *next;
|
||||||
struct sbp2_command_info *cmd;
|
struct sbp2_command_info *cmd;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
@ -922,15 +922,16 @@ static void sbp2_remove_device(struct sbp2_lu *lu)
|
||||||
|
|
||||||
if (!lu)
|
if (!lu)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
hi = lu->hi;
|
hi = lu->hi;
|
||||||
|
if (!hi)
|
||||||
|
goto no_hi;
|
||||||
|
|
||||||
if (lu->shost) {
|
if (lu->shost) {
|
||||||
scsi_remove_host(lu->shost);
|
scsi_remove_host(lu->shost);
|
||||||
scsi_host_put(lu->shost);
|
scsi_host_put(lu->shost);
|
||||||
}
|
}
|
||||||
flush_scheduled_work();
|
flush_scheduled_work();
|
||||||
sbp2util_remove_command_orb_pool(lu);
|
sbp2util_remove_command_orb_pool(lu, hi->host);
|
||||||
|
|
||||||
list_del(&lu->lu_list);
|
list_del(&lu->lu_list);
|
||||||
|
|
||||||
|
@ -971,9 +972,8 @@ static void sbp2_remove_device(struct sbp2_lu *lu)
|
||||||
|
|
||||||
lu->ud->device.driver_data = NULL;
|
lu->ud->device.driver_data = NULL;
|
||||||
|
|
||||||
if (hi)
|
module_put(hi->host->driver->owner);
|
||||||
module_put(hi->host->driver->owner);
|
no_hi:
|
||||||
|
|
||||||
kfree(lu);
|
kfree(lu);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue