Commit a68db9cb authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'firewire-updates' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394

Pull firewire updates from Stefan Richter:
 "IEEE 1394 subsystem updates:
   - clean up firewire-ohci's longlived vm-mapping
   - use target instance lock instead of core lock in firewire-sbp2"

* tag 'firewire-updates' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394:
  firewire: sbp2: replace card lock by target lock
  firewire: sbp2: replace some spin_lock_irqsave by spin_lock_irq
  firewire: sbp2: protect a reference counter properly
  firewire: core: document fw_csr_string's truncation of long strings
  firewire: ohci: replace vm_map_ram() with vmap()
parents 7051d8e6 d737d7da
...@@ -115,6 +115,9 @@ static int textual_leaf_to_string(const u32 *block, char *buf, size_t size) ...@@ -115,6 +115,9 @@ static int textual_leaf_to_string(const u32 *block, char *buf, size_t size)
* *
* The string is taken from a minimal ASCII text descriptor leaf after * The string is taken from a minimal ASCII text descriptor leaf after
* the immediate entry with @key. The string is zero-terminated. * the immediate entry with @key. The string is zero-terminated.
* An overlong string is silently truncated such that it and the
* zero byte fit into @size.
*
* Returns strlen(buf) or a negative error code. * Returns strlen(buf) or a negative error code.
*/ */
int fw_csr_string(const u32 *directory, int key, char *buf, size_t size) int fw_csr_string(const u32 *directory, int key, char *buf, size_t size)
......
...@@ -689,8 +689,7 @@ static void ar_context_release(struct ar_context *ctx) ...@@ -689,8 +689,7 @@ static void ar_context_release(struct ar_context *ctx)
{ {
unsigned int i; unsigned int i;
if (ctx->buffer) vunmap(ctx->buffer);
vm_unmap_ram(ctx->buffer, AR_BUFFERS + AR_WRAPAROUND_PAGES);
for (i = 0; i < AR_BUFFERS; i++) for (i = 0; i < AR_BUFFERS; i++)
if (ctx->pages[i]) { if (ctx->pages[i]) {
...@@ -1018,8 +1017,7 @@ static int ar_context_init(struct ar_context *ctx, struct fw_ohci *ohci, ...@@ -1018,8 +1017,7 @@ static int ar_context_init(struct ar_context *ctx, struct fw_ohci *ohci,
pages[i] = ctx->pages[i]; pages[i] = ctx->pages[i];
for (i = 0; i < AR_WRAPAROUND_PAGES; i++) for (i = 0; i < AR_WRAPAROUND_PAGES; i++)
pages[AR_BUFFERS + i] = ctx->pages[i]; pages[AR_BUFFERS + i] = ctx->pages[i];
ctx->buffer = vm_map_ram(pages, AR_BUFFERS + AR_WRAPAROUND_PAGES, ctx->buffer = vmap(pages, ARRAY_SIZE(pages), VM_MAP, PAGE_KERNEL);
-1, PAGE_KERNEL);
if (!ctx->buffer) if (!ctx->buffer)
goto out_of_memory; goto out_of_memory;
......
...@@ -174,6 +174,7 @@ struct sbp2_target { ...@@ -174,6 +174,7 @@ struct sbp2_target {
unsigned int mgt_orb_timeout; unsigned int mgt_orb_timeout;
unsigned int max_payload; unsigned int max_payload;
spinlock_t lock;
int dont_block; /* counter for each logical unit */ int dont_block; /* counter for each logical unit */
int blocked; /* ditto */ int blocked; /* ditto */
}; };
...@@ -270,6 +271,7 @@ struct sbp2_orb { ...@@ -270,6 +271,7 @@ struct sbp2_orb {
dma_addr_t request_bus; dma_addr_t request_bus;
int rcode; int rcode;
void (*callback)(struct sbp2_orb * orb, struct sbp2_status * status); void (*callback)(struct sbp2_orb * orb, struct sbp2_status * status);
struct sbp2_logical_unit *lu;
struct list_head link; struct list_head link;
}; };
...@@ -321,7 +323,6 @@ struct sbp2_command_orb { ...@@ -321,7 +323,6 @@ struct sbp2_command_orb {
u8 command_block[SBP2_MAX_CDB_SIZE]; u8 command_block[SBP2_MAX_CDB_SIZE];
} request; } request;
struct scsi_cmnd *cmd; struct scsi_cmnd *cmd;
struct sbp2_logical_unit *lu;
struct sbp2_pointer page_table[SG_ALL] __attribute__((aligned(8))); struct sbp2_pointer page_table[SG_ALL] __attribute__((aligned(8)));
dma_addr_t page_table_bus; dma_addr_t page_table_bus;
...@@ -444,7 +445,7 @@ static void sbp2_status_write(struct fw_card *card, struct fw_request *request, ...@@ -444,7 +445,7 @@ static void sbp2_status_write(struct fw_card *card, struct fw_request *request,
} }
/* Lookup the orb corresponding to this status write. */ /* Lookup the orb corresponding to this status write. */
spin_lock_irqsave(&card->lock, flags); spin_lock_irqsave(&lu->tgt->lock, flags);
list_for_each_entry(orb, &lu->orb_list, link) { list_for_each_entry(orb, &lu->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) {
...@@ -453,7 +454,7 @@ static void sbp2_status_write(struct fw_card *card, struct fw_request *request, ...@@ -453,7 +454,7 @@ static void sbp2_status_write(struct fw_card *card, struct fw_request *request,
break; break;
} }
} }
spin_unlock_irqrestore(&card->lock, flags); spin_unlock_irqrestore(&lu->tgt->lock, flags);
if (&orb->link != &lu->orb_list) { if (&orb->link != &lu->orb_list) {
orb->callback(orb, &status); orb->callback(orb, &status);
...@@ -480,18 +481,18 @@ static void complete_transaction(struct fw_card *card, int rcode, ...@@ -480,18 +481,18 @@ static void complete_transaction(struct fw_card *card, int rcode,
* been set and only does the cleanup if the transaction * been set and only does the cleanup if the transaction
* failed and we didn't already get a status write. * failed and we didn't already get a status write.
*/ */
spin_lock_irqsave(&card->lock, flags); spin_lock_irqsave(&orb->lu->tgt->lock, flags);
if (orb->rcode == -1) if (orb->rcode == -1)
orb->rcode = rcode; orb->rcode = rcode;
if (orb->rcode != RCODE_COMPLETE) { if (orb->rcode != RCODE_COMPLETE) {
list_del(&orb->link); list_del(&orb->link);
spin_unlock_irqrestore(&card->lock, flags); spin_unlock_irqrestore(&orb->lu->tgt->lock, flags);
orb->callback(orb, NULL); orb->callback(orb, NULL);
kref_put(&orb->kref, free_orb); /* orb callback reference */ kref_put(&orb->kref, free_orb); /* orb callback reference */
} else { } else {
spin_unlock_irqrestore(&card->lock, flags); spin_unlock_irqrestore(&orb->lu->tgt->lock, flags);
} }
kref_put(&orb->kref, free_orb); /* transaction callback reference */ kref_put(&orb->kref, free_orb); /* transaction callback reference */
...@@ -507,9 +508,10 @@ static void sbp2_send_orb(struct sbp2_orb *orb, struct sbp2_logical_unit *lu, ...@@ -507,9 +508,10 @@ static void sbp2_send_orb(struct sbp2_orb *orb, struct sbp2_logical_unit *lu,
orb_pointer.high = 0; orb_pointer.high = 0;
orb_pointer.low = cpu_to_be32(orb->request_bus); orb_pointer.low = cpu_to_be32(orb->request_bus);
spin_lock_irqsave(&device->card->lock, flags); orb->lu = lu;
spin_lock_irqsave(&lu->tgt->lock, flags);
list_add_tail(&orb->link, &lu->orb_list); list_add_tail(&orb->link, &lu->orb_list);
spin_unlock_irqrestore(&device->card->lock, flags); spin_unlock_irqrestore(&lu->tgt->lock, flags);
kref_get(&orb->kref); /* transaction callback reference */ kref_get(&orb->kref); /* transaction callback reference */
kref_get(&orb->kref); /* orb callback reference */ kref_get(&orb->kref); /* orb callback reference */
...@@ -524,13 +526,12 @@ static int sbp2_cancel_orbs(struct sbp2_logical_unit *lu) ...@@ -524,13 +526,12 @@ static int sbp2_cancel_orbs(struct sbp2_logical_unit *lu)
struct fw_device *device = target_parent_device(lu->tgt); struct fw_device *device = target_parent_device(lu->tgt);
struct sbp2_orb *orb, *next; struct sbp2_orb *orb, *next;
struct list_head list; struct list_head list;
unsigned long flags;
int retval = -ENOENT; int retval = -ENOENT;
INIT_LIST_HEAD(&list); INIT_LIST_HEAD(&list);
spin_lock_irqsave(&device->card->lock, flags); spin_lock_irq(&lu->tgt->lock);
list_splice_init(&lu->orb_list, &list); list_splice_init(&lu->orb_list, &list);
spin_unlock_irqrestore(&device->card->lock, flags); spin_unlock_irq(&lu->tgt->lock);
list_for_each_entry_safe(orb, next, &list, link) { list_for_each_entry_safe(orb, next, &list, link) {
retval = 0; retval = 0;
...@@ -687,16 +688,11 @@ static void sbp2_agent_reset_no_wait(struct sbp2_logical_unit *lu) ...@@ -687,16 +688,11 @@ static void sbp2_agent_reset_no_wait(struct sbp2_logical_unit *lu)
&d, 4, complete_agent_reset_write_no_wait, t); &d, 4, complete_agent_reset_write_no_wait, t);
} }
static inline void sbp2_allow_block(struct sbp2_logical_unit *lu) static inline void sbp2_allow_block(struct sbp2_target *tgt)
{ {
/* spin_lock_irq(&tgt->lock);
* We may access dont_block without taking card->lock here: --tgt->dont_block;
* All callers of sbp2_allow_block() and all callers of sbp2_unblock() spin_unlock_irq(&tgt->lock);
* are currently serialized against each other.
* And a wrong result in sbp2_conditionally_block()'s access of
* dont_block is rather harmless, it simply misses its first chance.
*/
--lu->tgt->dont_block;
} }
/* /*
...@@ -705,7 +701,7 @@ static inline void sbp2_allow_block(struct sbp2_logical_unit *lu) ...@@ -705,7 +701,7 @@ static inline void sbp2_allow_block(struct sbp2_logical_unit *lu)
* logical units have been finished (indicated by dont_block == 0). * logical units have been finished (indicated by dont_block == 0).
* - lu->generation is stale. * - lu->generation is stale.
* *
* Note, scsi_block_requests() must be called while holding card->lock, * Note, scsi_block_requests() must be called while holding tgt->lock,
* otherwise it might foil sbp2_[conditionally_]unblock()'s attempt to * otherwise it might foil sbp2_[conditionally_]unblock()'s attempt to
* unblock the target. * unblock the target.
*/ */
...@@ -717,20 +713,20 @@ static void sbp2_conditionally_block(struct sbp2_logical_unit *lu) ...@@ -717,20 +713,20 @@ static void sbp2_conditionally_block(struct sbp2_logical_unit *lu)
container_of((void *)tgt, struct Scsi_Host, hostdata[0]); container_of((void *)tgt, struct Scsi_Host, hostdata[0]);
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&card->lock, flags); spin_lock_irqsave(&tgt->lock, flags);
if (!tgt->dont_block && !lu->blocked && if (!tgt->dont_block && !lu->blocked &&
lu->generation != card->generation) { lu->generation != card->generation) {
lu->blocked = true; lu->blocked = true;
if (++tgt->blocked == 1) if (++tgt->blocked == 1)
scsi_block_requests(shost); scsi_block_requests(shost);
} }
spin_unlock_irqrestore(&card->lock, flags); spin_unlock_irqrestore(&tgt->lock, flags);
} }
/* /*
* Unblocks lu->tgt as soon as all its logical units can be unblocked. * Unblocks lu->tgt as soon as all its logical units can be unblocked.
* Note, it is harmless to run scsi_unblock_requests() outside the * Note, it is harmless to run scsi_unblock_requests() outside the
* card->lock protected section. On the other hand, running it inside * tgt->lock protected section. On the other hand, running it inside
* the section might clash with shost->host_lock. * the section might clash with shost->host_lock.
*/ */
static void sbp2_conditionally_unblock(struct sbp2_logical_unit *lu) static void sbp2_conditionally_unblock(struct sbp2_logical_unit *lu)
...@@ -739,15 +735,14 @@ static void sbp2_conditionally_unblock(struct sbp2_logical_unit *lu) ...@@ -739,15 +735,14 @@ static void sbp2_conditionally_unblock(struct sbp2_logical_unit *lu)
struct fw_card *card = target_parent_device(tgt)->card; struct fw_card *card = target_parent_device(tgt)->card;
struct Scsi_Host *shost = struct Scsi_Host *shost =
container_of((void *)tgt, struct Scsi_Host, hostdata[0]); container_of((void *)tgt, struct Scsi_Host, hostdata[0]);
unsigned long flags;
bool unblock = false; bool unblock = false;
spin_lock_irqsave(&card->lock, flags); spin_lock_irq(&tgt->lock);
if (lu->blocked && lu->generation == card->generation) { if (lu->blocked && lu->generation == card->generation) {
lu->blocked = false; lu->blocked = false;
unblock = --tgt->blocked == 0; unblock = --tgt->blocked == 0;
} }
spin_unlock_irqrestore(&card->lock, flags); spin_unlock_irq(&tgt->lock);
if (unblock) if (unblock)
scsi_unblock_requests(shost); scsi_unblock_requests(shost);
...@@ -756,19 +751,17 @@ static void sbp2_conditionally_unblock(struct sbp2_logical_unit *lu) ...@@ -756,19 +751,17 @@ static void sbp2_conditionally_unblock(struct sbp2_logical_unit *lu)
/* /*
* Prevents future blocking of tgt and unblocks it. * Prevents future blocking of tgt and unblocks it.
* Note, it is harmless to run scsi_unblock_requests() outside the * Note, it is harmless to run scsi_unblock_requests() outside the
* card->lock protected section. On the other hand, running it inside * tgt->lock protected section. On the other hand, running it inside
* the section might clash with shost->host_lock. * the section might clash with shost->host_lock.
*/ */
static void sbp2_unblock(struct sbp2_target *tgt) static void sbp2_unblock(struct sbp2_target *tgt)
{ {
struct fw_card *card = target_parent_device(tgt)->card;
struct Scsi_Host *shost = struct Scsi_Host *shost =
container_of((void *)tgt, struct Scsi_Host, hostdata[0]); container_of((void *)tgt, struct Scsi_Host, hostdata[0]);
unsigned long flags;
spin_lock_irqsave(&card->lock, flags); spin_lock_irq(&tgt->lock);
++tgt->dont_block; ++tgt->dont_block;
spin_unlock_irqrestore(&card->lock, flags); spin_unlock_irq(&tgt->lock);
scsi_unblock_requests(shost); scsi_unblock_requests(shost);
} }
...@@ -904,7 +897,7 @@ static void sbp2_login(struct work_struct *work) ...@@ -904,7 +897,7 @@ static void sbp2_login(struct work_struct *work)
/* No error during __scsi_add_device() */ /* No error during __scsi_add_device() */
lu->has_sdev = true; lu->has_sdev = true;
scsi_device_put(sdev); scsi_device_put(sdev);
sbp2_allow_block(lu); sbp2_allow_block(tgt);
return; return;
...@@ -1163,6 +1156,7 @@ static int sbp2_probe(struct fw_unit *unit, const struct ieee1394_device_id *id) ...@@ -1163,6 +1156,7 @@ static int sbp2_probe(struct fw_unit *unit, const struct ieee1394_device_id *id)
dev_set_drvdata(&unit->device, tgt); dev_set_drvdata(&unit->device, tgt);
tgt->unit = unit; tgt->unit = unit;
INIT_LIST_HEAD(&tgt->lu_list); INIT_LIST_HEAD(&tgt->lu_list);
spin_lock_init(&tgt->lock);
tgt->guid = (u64)device->config_rom[3] << 32 | device->config_rom[4]; tgt->guid = (u64)device->config_rom[3] << 32 | device->config_rom[4];
if (fw_device_enable_phys_dma(device) < 0) if (fw_device_enable_phys_dma(device) < 0)
...@@ -1359,12 +1353,12 @@ static void complete_command_orb(struct sbp2_orb *base_orb, ...@@ -1359,12 +1353,12 @@ static void complete_command_orb(struct sbp2_orb *base_orb,
{ {
struct sbp2_command_orb *orb = struct sbp2_command_orb *orb =
container_of(base_orb, struct sbp2_command_orb, base); container_of(base_orb, struct sbp2_command_orb, base);
struct fw_device *device = target_parent_device(orb->lu->tgt); struct fw_device *device = target_parent_device(base_orb->lu->tgt);
int result; int result;
if (status != NULL) { if (status != NULL) {
if (STATUS_GET_DEAD(*status)) if (STATUS_GET_DEAD(*status))
sbp2_agent_reset_no_wait(orb->lu); sbp2_agent_reset_no_wait(base_orb->lu);
switch (STATUS_GET_RESPONSE(*status)) { switch (STATUS_GET_RESPONSE(*status)) {
case SBP2_STATUS_REQUEST_COMPLETE: case SBP2_STATUS_REQUEST_COMPLETE:
...@@ -1390,7 +1384,7 @@ static void complete_command_orb(struct sbp2_orb *base_orb, ...@@ -1390,7 +1384,7 @@ static void complete_command_orb(struct sbp2_orb *base_orb,
* or when sending the write (less likely). * or when sending the write (less likely).
*/ */
result = DID_BUS_BUSY << 16; result = DID_BUS_BUSY << 16;
sbp2_conditionally_block(orb->lu); sbp2_conditionally_block(base_orb->lu);
} }
dma_unmap_single(device->card->device, orb->base.request_bus, dma_unmap_single(device->card->device, orb->base.request_bus,
...@@ -1487,7 +1481,6 @@ static int sbp2_scsi_queuecommand(struct Scsi_Host *shost, ...@@ -1487,7 +1481,6 @@ static int sbp2_scsi_queuecommand(struct Scsi_Host *shost,
/* 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); kref_init(&orb->base.kref);
orb->lu = lu;
orb->cmd = cmd; orb->cmd = cmd;
orb->request.next.high = cpu_to_be32(SBP2_ORB_NULL); orb->request.next.high = cpu_to_be32(SBP2_ORB_NULL);
orb->request.misc = cpu_to_be32( orb->request.misc = cpu_to_be32(
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment