|
@@ -1203,17 +1203,13 @@ sense_reason_t spc_emulate_report_luns(struct se_cmd *cmd)
|
|
|
struct se_dev_entry *deve;
|
|
|
struct se_session *sess = cmd->se_sess;
|
|
|
struct se_node_acl *nacl;
|
|
|
+ struct scsi_lun slun;
|
|
|
unsigned char *buf;
|
|
|
u32 lun_count = 0, offset = 8;
|
|
|
-
|
|
|
- if (cmd->data_length < 16) {
|
|
|
- pr_warn("REPORT LUNS allocation length %u too small\n",
|
|
|
- cmd->data_length);
|
|
|
- return TCM_INVALID_CDB_FIELD;
|
|
|
- }
|
|
|
+ __be32 len;
|
|
|
|
|
|
buf = transport_kmap_data_sg(cmd);
|
|
|
- if (!buf)
|
|
|
+ if (cmd->data_length && !buf)
|
|
|
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
|
|
|
|
|
|
/*
|
|
@@ -1234,10 +1230,12 @@ sense_reason_t spc_emulate_report_luns(struct se_cmd *cmd)
|
|
|
* See SPC2-R20 7.19.
|
|
|
*/
|
|
|
lun_count++;
|
|
|
- if ((offset + 8) > cmd->data_length)
|
|
|
+ if (offset >= cmd->data_length)
|
|
|
continue;
|
|
|
|
|
|
- int_to_scsilun(deve->mapped_lun, (struct scsi_lun *)&buf[offset]);
|
|
|
+ int_to_scsilun(deve->mapped_lun, &slun);
|
|
|
+ memcpy(buf + offset, &slun,
|
|
|
+ min(8u, cmd->data_length - offset));
|
|
|
offset += 8;
|
|
|
}
|
|
|
rcu_read_unlock();
|
|
@@ -1250,16 +1248,18 @@ done:
|
|
|
* If no LUNs are accessible, report virtual LUN 0.
|
|
|
*/
|
|
|
if (lun_count == 0) {
|
|
|
- int_to_scsilun(0, (struct scsi_lun *)&buf[offset]);
|
|
|
+ int_to_scsilun(0, &slun);
|
|
|
+ if (cmd->data_length > 8)
|
|
|
+ memcpy(buf + offset, &slun,
|
|
|
+ min(8u, cmd->data_length - offset));
|
|
|
lun_count = 1;
|
|
|
}
|
|
|
|
|
|
- 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);
|
|
|
+ if (buf) {
|
|
|
+ len = cpu_to_be32(lun_count * 8);
|
|
|
+ memcpy(buf, &len, min_t(int, sizeof len, cmd->data_length));
|
|
|
+ transport_kunmap_data_sg(cmd);
|
|
|
+ }
|
|
|
|
|
|
target_complete_cmd_with_length(cmd, GOOD, 8 + lun_count * 8);
|
|
|
return 0;
|