Now REPORT LUNS for software device servers always reports all luns regardless of SELECT REPORT field. Add handling of that field according to SPC-4: * accept known values, * reject unknown values. Changes since v1: - unmap transport data in error handling case Reviewed-by: Roman Bolshakov <r.bolshakov@xxxxxxxxx> Signed-off-by: Dmitry Bogdanov <d.bogdanov@xxxxxxxxx> --- patch to 5.11/scsi-queue drivers/target/target_core_spc.c | 27 +++++++++++++++++++++++++++ include/scsi/scsi_proto.h | 10 ++++++++++ 2 files changed, 37 insertions(+) diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c index ca5579ebc81d..044ac45cdf47 100644 --- a/drivers/target/target_core_spc.c +++ b/drivers/target/target_core_spc.c @@ -1210,10 +1210,12 @@ sense_reason_t spc_emulate_report_luns(struct se_cmd *cmd) { struct se_dev_entry *deve; struct se_session *sess = cmd->se_sess; + unsigned char *cdb = cmd->t_task_cdb; struct se_node_acl *nacl; struct scsi_lun slun; unsigned char *buf; u32 lun_count = 0, offset = 8; + u8 sr = cdb[2]; __be32 len; buf = transport_kmap_data_sg(cmd); @@ -1230,6 +1232,28 @@ sense_reason_t spc_emulate_report_luns(struct se_cmd *cmd) nacl = sess->se_node_acl; + switch (sr) { + case SCSI_SELECT_WELLKNOWN: + case SCSI_SELECT_ADMINISTRATIVE: + case SCSI_SELECT_SUBSIDIARY: + /* report empty lun list */ + goto out; + case SCSI_SELECT_TOP_LEVEL: + if (cmd->se_lun->unpacked_lun != 0) + goto out; + fallthrough; + case SCSI_SELECT_REGULAR: + case SCSI_SELECT_ALL_ACCESSIBLE: + break; + default: + pr_debug("TARGET_CORE[%s]: Invalid REPORT LUNS with unsupported " + "SELECT REPORT %#x for 0x%08llx from %s\n", + cmd->se_tfo->fabric_name, sr, cmd->se_lun->unpacked_lun, + sess->se_node_acl->initiatorname); + transport_kunmap_data_sg(cmd); + return TCM_INVALID_CDB_FIELD; + } + rcu_read_lock(); hlist_for_each_entry_rcu(deve, &nacl->lun_entry_hlist, link) { /* @@ -1252,6 +1276,8 @@ sense_reason_t spc_emulate_report_luns(struct se_cmd *cmd) * See SPC3 r07, page 159. */ done: + if ((sr != SCSI_SELECT_REGULAR) && (sr != SCSI_SELECT_ALL_ACCESSIBLE)) + goto out; /* * If no LUNs are accessible, report virtual LUN 0. */ @@ -1263,6 +1289,7 @@ sense_reason_t spc_emulate_report_luns(struct se_cmd *cmd) lun_count = 1; } +out: if (buf) { len = cpu_to_be32(lun_count * 8); memcpy(buf, &len, min_t(int, sizeof len, cmd->data_length)); diff --git a/include/scsi/scsi_proto.h b/include/scsi/scsi_proto.h index c36860111932..280169c75d85 100644 --- a/include/scsi/scsi_proto.h +++ b/include/scsi/scsi_proto.h @@ -341,4 +341,14 @@ enum zbc_zone_cond { ZBC_ZONE_COND_OFFLINE = 0xf, }; +/* Select Report fot REPORT LUNS */ +enum scsi_select_report { + SCSI_SELECT_REGULAR = 0x0, + SCSI_SELECT_WELLKNOWN = 0x1, + SCSI_SELECT_ALL_ACCESSIBLE = 0x2, + SCSI_SELECT_ADMINISTRATIVE = 0x10, + SCSI_SELECT_TOP_LEVEL = 0x11, + SCSI_SELECT_SUBSIDIARY = 0x12, +}; + #endif /* _SCSI_PROTO_H_ */ -- 2.25.1