aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/target
diff options
context:
space:
mode:
authorAndy Grover <agrover@redhat.com>2015-04-14 20:30:04 -0400
committerNicholas Bellinger <nab@linux-iscsi.org>2015-04-20 01:40:26 -0400
commit0ad46af8a618fc38e0cdc3927cfa9f7b42cc9423 (patch)
tree92ff9184b1c24d7886403f6f2bbb25115022e16f /drivers/target
parent65204c84d7666a78e965da0dd8696bdb007606dd (diff)
target: Version 2 of TCMU ABI
The initial version of TCMU (in 3.18) does not properly handle bidirectional SCSI commands -- those with both an in and out buffer. In looking to fix this it also became clear that TCMU's support for adding new types of entries (opcodes) to the command ring was broken. We need to fix this now, so that future issues can be handled properly by adding new opcodes. We make the most of this ABI break by enabling bidi cmd handling within TCMP_OP_CMD opcode. Add an iov_bidi_cnt field to tcmu_cmd_entry.req. This enables TCMU to describe bidi commands, but further kernel work is needed for full bidi support. Enlarge tcmu_cmd_entry_hdr by 32 bits by pulling in cmd_id and __pad1. Turn __pad1 into two 8 bit flags fields, for kernel-set and userspace-set flags, "kflags" and "uflags" respectively. Update version fields so userspace can tell the interface is changed. Update tcmu-design.txt with details of how new stuff works: - Specify an additional requirement for userspace to set UNKNOWN_OP (bit 0) in hdr.uflags for unknown/unhandled opcodes. - Define how Data-In and Data-Out fields are described in req.iov[] Changed in v2: - Change name of SKIPPED bit to UNKNOWN bit - PAD op does not set the bit any more - Change len_op helper functions to take just len_op, not the whole struct - Change version to 2 in missed spots, and use defines - Add 16 unused bytes to cmd_entry.req, in case additional SAM cmd parameters need to be included - Add iov_dif_cnt field to specify buffers used for DIF info in iov[] - Rearrange fields to naturally align cdb_off - Handle if userspace sets UNKNOWN_OP by indicating failure of the cmd - Wrap some overly long UPDATE_HEAD lines (Add missing req.iov_bidi_cnt + req.iov_dif_cnt zeroing - Ilias) Signed-off-by: Andy Grover <agrover@redhat.com> Reviewed-by: Ilias Tsitsimpis <iliastsi@arrikto.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
Diffstat (limited to 'drivers/target')
-rw-r--r--drivers/target/target_core_user.c46
1 files changed, 34 insertions, 12 deletions
diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c
index 1fbf304a9491..dbc872a6c981 100644
--- a/drivers/target/target_core_user.c
+++ b/drivers/target/target_core_user.c
@@ -344,8 +344,11 @@ static int tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd)
344 344
345 entry = (void *) mb + CMDR_OFF + cmd_head; 345 entry = (void *) mb + CMDR_OFF + cmd_head;
346 tcmu_flush_dcache_range(entry, sizeof(*entry)); 346 tcmu_flush_dcache_range(entry, sizeof(*entry));
347 tcmu_hdr_set_op(&entry->hdr, TCMU_OP_PAD); 347 tcmu_hdr_set_op(&entry->hdr.len_op, TCMU_OP_PAD);
348 tcmu_hdr_set_len(&entry->hdr, pad_size); 348 tcmu_hdr_set_len(&entry->hdr.len_op, pad_size);
349 entry->hdr.cmd_id = 0; /* not used for PAD */
350 entry->hdr.kflags = 0;
351 entry->hdr.uflags = 0;
349 352
350 UPDATE_HEAD(mb->cmd_head, pad_size, udev->cmdr_size); 353 UPDATE_HEAD(mb->cmd_head, pad_size, udev->cmdr_size);
351 354
@@ -355,9 +358,11 @@ static int tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd)
355 358
356 entry = (void *) mb + CMDR_OFF + cmd_head; 359 entry = (void *) mb + CMDR_OFF + cmd_head;
357 tcmu_flush_dcache_range(entry, sizeof(*entry)); 360 tcmu_flush_dcache_range(entry, sizeof(*entry));
358 tcmu_hdr_set_op(&entry->hdr, TCMU_OP_CMD); 361 tcmu_hdr_set_op(&entry->hdr.len_op, TCMU_OP_CMD);
359 tcmu_hdr_set_len(&entry->hdr, command_size); 362 tcmu_hdr_set_len(&entry->hdr.len_op, command_size);
360 entry->cmd_id = tcmu_cmd->cmd_id; 363 entry->hdr.cmd_id = tcmu_cmd->cmd_id;
364 entry->hdr.kflags = 0;
365 entry->hdr.uflags = 0;
361 366
362 /* 367 /*
363 * Fix up iovecs, and handle if allocation in data ring wrapped. 368 * Fix up iovecs, and handle if allocation in data ring wrapped.
@@ -407,6 +412,8 @@ static int tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd)
407 kunmap_atomic(from); 412 kunmap_atomic(from);
408 } 413 }
409 entry->req.iov_cnt = iov_cnt; 414 entry->req.iov_cnt = iov_cnt;
415 entry->req.iov_bidi_cnt = 0;
416 entry->req.iov_dif_cnt = 0;
410 417
411 /* All offsets relative to mb_addr, not start of entry! */ 418 /* All offsets relative to mb_addr, not start of entry! */
412 cdb_off = CMDR_OFF + cmd_head + base_command_size; 419 cdb_off = CMDR_OFF + cmd_head + base_command_size;
@@ -464,6 +471,17 @@ static void tcmu_handle_completion(struct tcmu_cmd *cmd, struct tcmu_cmd_entry *
464 return; 471 return;
465 } 472 }
466 473
474 if (entry->hdr.uflags & TCMU_UFLAG_UNKNOWN_OP) {
475 UPDATE_HEAD(udev->data_tail, cmd->data_length, udev->data_size);
476 pr_warn("TCMU: Userspace set UNKNOWN_OP flag on se_cmd %p\n",
477 cmd->se_cmd);
478 transport_generic_request_failure(cmd->se_cmd,
479 TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE);
480 cmd->se_cmd = NULL;
481 kmem_cache_free(tcmu_cmd_cache, cmd);
482 return;
483 }
484
467 if (entry->rsp.scsi_status == SAM_STAT_CHECK_CONDITION) { 485 if (entry->rsp.scsi_status == SAM_STAT_CHECK_CONDITION) {
468 memcpy(se_cmd->sense_buffer, entry->rsp.sense_buffer, 486 memcpy(se_cmd->sense_buffer, entry->rsp.sense_buffer,
469 se_cmd->scsi_sense_length); 487 se_cmd->scsi_sense_length);
@@ -542,14 +560,16 @@ static unsigned int tcmu_handle_completions(struct tcmu_dev *udev)
542 560
543 tcmu_flush_dcache_range(entry, sizeof(*entry)); 561 tcmu_flush_dcache_range(entry, sizeof(*entry));
544 562
545 if (tcmu_hdr_get_op(&entry->hdr) == TCMU_OP_PAD) { 563 if (tcmu_hdr_get_op(entry->hdr.len_op) == TCMU_OP_PAD) {
546 UPDATE_HEAD(udev->cmdr_last_cleaned, tcmu_hdr_get_len(&entry->hdr), udev->cmdr_size); 564 UPDATE_HEAD(udev->cmdr_last_cleaned,
565 tcmu_hdr_get_len(entry->hdr.len_op),
566 udev->cmdr_size);
547 continue; 567 continue;
548 } 568 }
549 WARN_ON(tcmu_hdr_get_op(&entry->hdr) != TCMU_OP_CMD); 569 WARN_ON(tcmu_hdr_get_op(entry->hdr.len_op) != TCMU_OP_CMD);
550 570
551 spin_lock(&udev->commands_lock); 571 spin_lock(&udev->commands_lock);
552 cmd = idr_find(&udev->commands, entry->cmd_id); 572 cmd = idr_find(&udev->commands, entry->hdr.cmd_id);
553 if (cmd) 573 if (cmd)
554 idr_remove(&udev->commands, cmd->cmd_id); 574 idr_remove(&udev->commands, cmd->cmd_id);
555 spin_unlock(&udev->commands_lock); 575 spin_unlock(&udev->commands_lock);
@@ -562,7 +582,9 @@ static unsigned int tcmu_handle_completions(struct tcmu_dev *udev)
562 582
563 tcmu_handle_completion(cmd, entry); 583 tcmu_handle_completion(cmd, entry);
564 584
565 UPDATE_HEAD(udev->cmdr_last_cleaned, tcmu_hdr_get_len(&entry->hdr), udev->cmdr_size); 585 UPDATE_HEAD(udev->cmdr_last_cleaned,
586 tcmu_hdr_get_len(entry->hdr.len_op),
587 udev->cmdr_size);
566 588
567 handled++; 589 handled++;
568 } 590 }
@@ -840,14 +862,14 @@ static int tcmu_configure_device(struct se_device *dev)
840 udev->data_size = TCMU_RING_SIZE - CMDR_SIZE; 862 udev->data_size = TCMU_RING_SIZE - CMDR_SIZE;
841 863
842 mb = udev->mb_addr; 864 mb = udev->mb_addr;
843 mb->version = 1; 865 mb->version = TCMU_MAILBOX_VERSION;
844 mb->cmdr_off = CMDR_OFF; 866 mb->cmdr_off = CMDR_OFF;
845 mb->cmdr_size = udev->cmdr_size; 867 mb->cmdr_size = udev->cmdr_size;
846 868
847 WARN_ON(!PAGE_ALIGNED(udev->data_off)); 869 WARN_ON(!PAGE_ALIGNED(udev->data_off));
848 WARN_ON(udev->data_size % PAGE_SIZE); 870 WARN_ON(udev->data_size % PAGE_SIZE);
849 871
850 info->version = "1"; 872 info->version = xstr(TCMU_MAILBOX_VERSION);
851 873
852 info->mem[0].name = "tcm-user command & data buffer"; 874 info->mem[0].name = "tcm-user command & data buffer";
853 info->mem[0].addr = (phys_addr_t) udev->mb_addr; 875 info->mem[0].addr = (phys_addr_t) udev->mb_addr;