diff mbox series

[1/6] scsi: target: core: add support of RSOC command

Message ID 20220718120117.4435-2-d.bogdanov@yadro.com
State Superseded
Headers show
Series add support of RSOC command | expand

Commit Message

Dmitry Bogdanov July 18, 2022, 12:01 p.m. UTC
Add support of REPORT SUPPORTED OPERATION CODES command according
to SPC4.

Reviewed-by: Roman Bolshakov <r.bolshakov@yadro.com>
Signed-off-by: Dmitry Bogdanov <d.bogdanov@yadro.com>
---
 drivers/target/target_core_spc.c  | 200 ++++++++++++++++++++++++++++++
 include/scsi/scsi_proto.h         |   7 ++
 include/target/target_core_base.h |  12 ++
 3 files changed, 219 insertions(+)

Comments

kernel test robot July 19, 2022, 10:08 a.m. UTC | #1
Hi Dmitry,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on mkp-scsi/for-next]
[also build test WARNING on jejb-scsi/for-next linus/master v5.19-rc7 next-20220718]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Dmitry-Bogdanov/add-support-of-RSOC-command/20220718-200622
base:   https://git.kernel.org/pub/scm/linux/kernel/git/mkp/scsi.git for-next
config: nios2-randconfig-s042-20220718 (https://download.01.org/0day-ci/archive/20220719/202207191727.tSUku1lU-lkp@intel.com/config)
compiler: nios2-linux-gcc (GCC) 12.1.0
reproduce:
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # apt-get install sparse
        # sparse version: v0.6.4-39-gce1a6720-dirty
        # https://github.com/intel-lab-lkp/linux/commit/dd5367ced3f2a2d631776343184cca65d8cfbed8
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review Dmitry-Bogdanov/add-support-of-RSOC-command/20220718-200622
        git checkout dd5367ced3f2a2d631776343184cca65d8cfbed8
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__' O=build_dir ARCH=nios2 SHELL=/bin/bash drivers/target/

If you fix the issue, kindly add following tag where applicable
Reported-by: kernel test robot <lkp@intel.com>


sparse warnings: (new ones prefixed by >>)
>> drivers/target/target_core_spc.c:1459:21: sparse: sparse: incorrect type in assignment (different base types) @@     expected int ret @@     got restricted sense_reason_t @@
   drivers/target/target_core_spc.c:1459:21: sparse:     expected int ret
   drivers/target/target_core_spc.c:1459:21: sparse:     got restricted sense_reason_t
   drivers/target/target_core_spc.c:1466:21: sparse: sparse: incorrect type in assignment (different base types) @@     expected int ret @@     got restricted sense_reason_t @@
   drivers/target/target_core_spc.c:1466:21: sparse:     expected int ret
   drivers/target/target_core_spc.c:1466:21: sparse:     got restricted sense_reason_t
   drivers/target/target_core_spc.c:1478:21: sparse: sparse: incorrect type in assignment (different base types) @@     expected int ret @@     got restricted sense_reason_t @@
   drivers/target/target_core_spc.c:1478:21: sparse:     expected int ret
   drivers/target/target_core_spc.c:1478:21: sparse:     got restricted sense_reason_t
>> drivers/target/target_core_spc.c:1504:16: sparse: sparse: incorrect type in return expression (different base types) @@     expected restricted sense_reason_t @@     got int ret @@
   drivers/target/target_core_spc.c:1504:16: sparse:     expected restricted sense_reason_t
   drivers/target/target_core_spc.c:1504:16: sparse:     got int ret

vim +1459 drivers/target/target_core_spc.c

  1442	
  1443	static sense_reason_t
  1444	spc_emulate_report_supp_op_codes(struct se_cmd *cmd)
  1445	{
  1446		int descr_num = ARRAY_SIZE(tcm_supported_opcodes);
  1447		struct target_opcode_descriptor *descr = NULL;
  1448		unsigned char *cdb = cmd->t_task_cdb;
  1449		u8 rctd = (cdb[2] >> 7) & 0x1;
  1450		unsigned char *buf = NULL;
  1451		int response_length = 0;
  1452		u8 opts = cdb[2] & 0x3;
  1453		unsigned char *rbuf;
  1454		int ret = 0;
  1455		int i;
  1456	
  1457		rbuf = transport_kmap_data_sg(cmd);
  1458		if (cmd->data_length && !rbuf) {
> 1459			ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
  1460			goto out;
  1461		}
  1462	
  1463		if (opts == 0)
  1464			response_length = 4 + (8 + rctd * 12) * descr_num;
  1465		else {
  1466			ret = spc_rsoc_get_descr(cmd, &descr);
  1467			if (ret)
  1468				goto out;
  1469	
  1470			if (descr)
  1471				response_length = 4 + descr->cdb_size + rctd * 12;
  1472			else
  1473				response_length = 2;
  1474		}
  1475	
  1476		buf = kzalloc(response_length, GFP_KERNEL);
  1477		if (!buf) {
  1478			ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
  1479			goto out;
  1480		}
  1481		response_length = 0;
  1482	
  1483		if (opts == 0) {
  1484			response_length += 4;
  1485	
  1486			for (i = 0; i < ARRAY_SIZE(tcm_supported_opcodes); i++) {
  1487				descr = tcm_supported_opcodes[i];
  1488				response_length += spc_rsoc_encode_command_descriptor(
  1489						&buf[response_length], rctd, descr);
  1490			}
  1491			put_unaligned_be32(response_length - 3, buf);
  1492		} else {
  1493			response_length = spc_rsoc_encode_one_command_descriptor(
  1494					&buf[response_length], rctd, descr);
  1495		}
  1496	
  1497		memcpy(rbuf, buf, min_t(u32, response_length, cmd->data_length));
  1498	out:
  1499		kfree(buf);
  1500		transport_kunmap_data_sg(cmd);
  1501	
  1502		if (!ret)
  1503			target_complete_cmd_with_length(cmd, SAM_STAT_GOOD, response_length);
> 1504		return ret;
  1505	}
  1506
diff mbox series

Patch

diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c
index c14441c89bed..4157f73977cf 100644
--- a/drivers/target/target_core_spc.c
+++ b/drivers/target/target_core_spc.c
@@ -1308,6 +1308,202 @@  spc_emulate_testunitready(struct se_cmd *cmd)
 	return 0;
 }
 
+
+static struct target_opcode_descriptor *tcm_supported_opcodes[] = {
+};
+
+static int
+spc_rsoc_encode_command_timeouts_descriptor(unsigned char *buf, u8 ctdp,
+				struct target_opcode_descriptor *descr)
+{
+	if (!ctdp)
+		return 0;
+
+	put_unaligned_be16(0xa, buf);
+	buf[3] = descr->specific_timeout;
+	put_unaligned_be32(descr->nominal_timeout, &buf[4]);
+	put_unaligned_be32(descr->recommended_timeout, &buf[8]);
+
+	return 12;
+}
+
+static int
+spc_rsoc_encode_command_descriptor(unsigned char *buf, u8 ctdp,
+				   struct target_opcode_descriptor *descr)
+{
+	int td_size = 0;
+
+	buf[0] = descr->opcode;
+
+	put_unaligned_be16(descr->service_action, &buf[2]);
+
+	buf[5] = (ctdp << 1) | descr->serv_action_valid;
+	put_unaligned_be16(descr->cdb_size, &buf[6]);
+
+	td_size = spc_rsoc_encode_command_timeouts_descriptor(&buf[8], ctdp,
+							      descr);
+
+	return 8 + td_size;
+}
+
+static int
+spc_rsoc_encode_one_command_descriptor(unsigned char *buf, u8 ctdp,
+				       struct target_opcode_descriptor *descr)
+{
+	int td_size = 0;
+
+	if (!descr) {
+		buf[1] = (ctdp << 7) | SCSI_SUPPORT_NOT_SUPPORTED;
+		return 2;
+	}
+
+	buf[1] = (ctdp << 7) | SCSI_SUPPORT_FULL;
+	put_unaligned_be16(descr->cdb_size, &buf[2]);
+	memcpy(&buf[4], descr->usage_bits, descr->cdb_size);
+
+	td_size = spc_rsoc_encode_command_timeouts_descriptor(
+			&buf[4 + descr->cdb_size], ctdp, descr);
+
+	return 4 + descr->cdb_size + td_size;
+}
+
+static sense_reason_t
+spc_rsoc_get_descr(struct se_cmd *cmd, struct target_opcode_descriptor **opcode)
+{
+	struct target_opcode_descriptor *descr;
+	struct se_session *sess = cmd->se_sess;
+	unsigned char *cdb = cmd->t_task_cdb;
+	u8 opts = cdb[2] & 0x3;
+	u8 requested_opcode;
+	u16 requested_sa;
+	int i;
+
+	requested_opcode = cdb[3];
+	requested_sa = ((u16)cdb[4]) << 8 | cdb[5];
+	*opcode = NULL;
+
+	if (opts > 3) {
+		pr_debug("TARGET_CORE[%s]: Invalid REPORT SUPPORTED OPERATION CODES"
+			" with unsupported REPORTING OPTIONS %#x for 0x%08llx from %s\n",
+			cmd->se_tfo->fabric_name, opts,
+			cmd->se_lun->unpacked_lun,
+			sess->se_node_acl->initiatorname);
+		return TCM_INVALID_CDB_FIELD;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(tcm_supported_opcodes); i++) {
+		descr = tcm_supported_opcodes[i];
+		if (descr->opcode != requested_opcode)
+			continue;
+
+		switch (opts) {
+		case 0x1:
+			/*
+			 * If the REQUESTED OPERATION CODE field specifies an
+			 * operation code for which the device server implements
+			 * service actions, then the device server shall
+			 * terminate the command with CHECK CONDITION status,
+			 * with the sense key set to ILLEGAL REQUEST, and the
+			 * additional sense code set to INVALID FIELD IN CDB
+			 */
+			if (descr->serv_action_valid)
+				return TCM_INVALID_CDB_FIELD;
+			*opcode = descr;
+			break;
+		case 0x2:
+			/*
+			 * If the REQUESTED OPERATION CODE field specifies an
+			 * operation code for which the device server does not
+			 * implement service actions, then the device server
+			 * shall terminate the command with CHECK CONDITION
+			 * status, with the sense key set to ILLEGAL REQUEST,
+			 * and the additional sense code set to INVALID FIELD IN CDB.
+			 */
+			if (descr->serv_action_valid &&
+			    descr->service_action == requested_sa)
+				*opcode = descr;
+			else if (!descr->serv_action_valid)
+				return TCM_INVALID_CDB_FIELD;
+			break;
+		case 0x3:
+			/*
+			 * The command support data for the operation code and
+			 * service action a specified in the REQUESTED OPERATION
+			 * CODE field and REQUESTED SERVICE ACTION field shall
+			 * be returned in the one_command parameter data format.
+			 */
+			if (descr->service_action == requested_sa)
+				*opcode = descr;
+			break;
+		}
+	}
+	return 0;
+}
+
+static sense_reason_t
+spc_emulate_report_supp_op_codes(struct se_cmd *cmd)
+{
+	int descr_num = ARRAY_SIZE(tcm_supported_opcodes);
+	struct target_opcode_descriptor *descr = NULL;
+	unsigned char *cdb = cmd->t_task_cdb;
+	u8 rctd = (cdb[2] >> 7) & 0x1;
+	unsigned char *buf = NULL;
+	int response_length = 0;
+	u8 opts = cdb[2] & 0x3;
+	unsigned char *rbuf;
+	int ret = 0;
+	int i;
+
+	rbuf = transport_kmap_data_sg(cmd);
+	if (cmd->data_length && !rbuf) {
+		ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+		goto out;
+	}
+
+	if (opts == 0)
+		response_length = 4 + (8 + rctd * 12) * descr_num;
+	else {
+		ret = spc_rsoc_get_descr(cmd, &descr);
+		if (ret)
+			goto out;
+
+		if (descr)
+			response_length = 4 + descr->cdb_size + rctd * 12;
+		else
+			response_length = 2;
+	}
+
+	buf = kzalloc(response_length, GFP_KERNEL);
+	if (!buf) {
+		ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+		goto out;
+	}
+	response_length = 0;
+
+	if (opts == 0) {
+		response_length += 4;
+
+		for (i = 0; i < ARRAY_SIZE(tcm_supported_opcodes); i++) {
+			descr = tcm_supported_opcodes[i];
+			response_length += spc_rsoc_encode_command_descriptor(
+					&buf[response_length], rctd, descr);
+		}
+		put_unaligned_be32(response_length - 3, buf);
+	} else {
+		response_length = spc_rsoc_encode_one_command_descriptor(
+				&buf[response_length], rctd, descr);
+	}
+
+	memcpy(rbuf, buf, min_t(u32, response_length, cmd->data_length));
+out:
+	kfree(buf);
+	transport_kunmap_data_sg(cmd);
+
+	if (!ret)
+		target_complete_cmd_with_length(cmd, SAM_STAT_GOOD, response_length);
+	return ret;
+}
+
 sense_reason_t
 spc_parse_cdb(struct se_cmd *cmd, unsigned int *size)
 {
@@ -1433,6 +1629,10 @@  spc_parse_cdb(struct se_cmd *cmd, unsigned int *size)
 				cmd->execute_cmd =
 					target_emulate_report_target_port_groups;
 			}
+			if ((cdb[1] & 0x1f) ==
+			    MI_REPORT_SUPPORTED_OPERATION_CODES)
+				cmd->execute_cmd =
+					spc_emulate_report_supp_op_codes;
 			*size = get_unaligned_be32(&cdb[6]);
 		} else {
 			/*
diff --git a/include/scsi/scsi_proto.h b/include/scsi/scsi_proto.h
index c03e35fc382c..651b5183451c 100644
--- a/include/scsi/scsi_proto.h
+++ b/include/scsi/scsi_proto.h
@@ -342,4 +342,11 @@  enum scsi_version_descriptor {
 	SCSI_VERSION_DESCRIPTOR_SRP	= 0x0940
 };
 
+enum scsi_support_opcode {
+	SCSI_SUPPORT_NO_INFO		= 0,
+	SCSI_SUPPORT_NOT_SUPPORTED	= 1,
+	SCSI_SUPPORT_FULL		= 3,
+	SCSI_SUPPORT_VENDOR		= 5,
+};
+
 #endif /* _SCSI_PROTO_H_ */
diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h
index c2b36f7d917d..d93c65bcbc11 100644
--- a/include/target/target_core_base.h
+++ b/include/target/target_core_base.h
@@ -867,6 +867,18 @@  struct se_device {
 	struct se_device_queue	*queues;
 };
 
+struct target_opcode_descriptor {
+	u8			support:3;
+	u8			serv_action_valid:1;
+	u8			opcode;
+	u16			service_action;
+	u32			cdb_size;
+	u8			specific_timeout;
+	u16			nominal_timeout;
+	u16			recommended_timeout;
+	u8			usage_bits[];
+};
+
 struct se_hba {
 	u16			hba_tpgt;
 	u32			hba_id;