diff options
author | Christoph Hellwig <hch@infradead.org> | 2012-10-07 10:55:51 -0400 |
---|---|---|
committer | Nicholas Bellinger <nab@linux-iscsi.org> | 2012-11-06 20:55:44 -0800 |
commit | d1b1f8053401aaf1dfe636afa6d361301e3ae8b7 (patch) | |
tree | 52a04af8a2383ce291105b4b5d01bb869802f33c /drivers/target/target_core_spc.c | |
parent | 9e999a6c51fe74a41a76038c64ce038ff9243bfb (diff) | |
download | linux-next-d1b1f8053401aaf1dfe636afa6d361301e3ae8b7.tar.gz |
target: move REPORT LUNS emulation to target_core_spc.c
Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
Diffstat (limited to 'drivers/target/target_core_spc.c')
-rw-r--r-- | drivers/target/target_core_spc.c | 65 |
1 files changed, 64 insertions, 1 deletions
diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c index 0af45ae32f8c..07b82700dcd8 100644 --- a/drivers/target/target_core_spc.c +++ b/drivers/target/target_core_spc.c @@ -908,6 +908,69 @@ static int spc_emulate_request_sense(struct se_cmd *cmd) return 0; } +static int spc_emulate_report_luns(struct se_cmd *cmd) +{ + struct se_dev_entry *deve; + struct se_session *sess = cmd->se_sess; + unsigned char *buf; + u32 lun_count = 0, offset = 8, i; + + if (cmd->data_length < 16) { + pr_warn("REPORT LUNS allocation length %u too small\n", + cmd->data_length); + cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; + return -EINVAL; + } + + buf = transport_kmap_data_sg(cmd); + if (!buf) + return -ENOMEM; + + /* + * If no struct se_session pointer is present, this struct se_cmd is + * coming via a target_core_mod PASSTHROUGH op, and not through + * a $FABRIC_MOD. In that case, report LUN=0 only. + */ + if (!sess) { + int_to_scsilun(0, (struct scsi_lun *)&buf[offset]); + lun_count = 1; + goto done; + } + + spin_lock_irq(&sess->se_node_acl->device_list_lock); + for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) { + deve = sess->se_node_acl->device_list[i]; + if (!(deve->lun_flags & TRANSPORT_LUNFLAGS_INITIATOR_ACCESS)) + continue; + /* + * We determine the correct LUN LIST LENGTH even once we + * have reached the initial allocation length. + * See SPC2-R20 7.19. + */ + lun_count++; + if ((offset + 8) > cmd->data_length) + continue; + + int_to_scsilun(deve->mapped_lun, (struct scsi_lun *)&buf[offset]); + offset += 8; + } + spin_unlock_irq(&sess->se_node_acl->device_list_lock); + + /* + * See SPC3 r07, page 159. + */ +done: + lun_count *= 8; + buf[0] = ((lun_count >> 24) & 0xff); + buf[1] = ((lun_count >> 16) & 0xff); + buf[2] = ((lun_count >> 8) & 0xff); + buf[3] = (lun_count & 0xff); + transport_kunmap_data_sg(cmd); + + target_complete_cmd(cmd, GOOD); + return 0; +} + static int spc_emulate_testunitready(struct se_cmd *cmd) { target_complete_cmd(cmd, GOOD); @@ -1013,7 +1076,7 @@ int spc_parse_cdb(struct se_cmd *cmd, unsigned int *size) *size = (cdb[6] << 16) + (cdb[7] << 8) + cdb[8]; break; case REPORT_LUNS: - cmd->execute_cmd = target_report_luns; + cmd->execute_cmd = spc_emulate_report_luns; *size = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; /* * Do implict HEAD_OF_QUEUE processing for REPORT_LUNS |