Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2426bd45 authored by Roland Dreier's avatar Roland Dreier Committed by Nicholas Bellinger
Browse files

target: Report correct response length for some commands

When an initiator sends an allocation length bigger than what its
command consumes, the target should only return the actual response data
and set the residual length to the unused part of the allocation length.

Add a helper function that command handlers (INQUIRY, READ CAPACITY,
etc) can use to do this correctly, and use this code to get the correct
residual for commands that don't use the full initiator allocation in the
handlers for READ CAPACITY, READ CAPACITY(16), INQUIRY, MODE SENSE and
REPORT LUNS.

This addresses a handful of failures as reported by Christophe with
the Windows Certification Kit:

  http://permalink.gmane.org/gmane.linux.scsi.target.devel/6515



Signed-off-by: default avatarRoland Dreier <roland@purestorage.com>
Tested-by: default avatarChristophe Vu-Brugier <cvubrugier@yahoo.fr>
Cc: stable@vger.kernel.org # 3.10+
Signed-off-by: default avatarNicholas Bellinger <nab@linux-iscsi.org>
parent c52716de
Loading
Loading
Loading
Loading
+2 −2
Original line number Original line Diff line number Diff line
@@ -81,7 +81,7 @@ sbc_emulate_readcapacity(struct se_cmd *cmd)
		transport_kunmap_data_sg(cmd);
		transport_kunmap_data_sg(cmd);
	}
	}


	target_complete_cmd(cmd, GOOD);
	target_complete_cmd_with_length(cmd, GOOD, 8);
	return 0;
	return 0;
}
}


@@ -137,7 +137,7 @@ sbc_emulate_readcapacity_16(struct se_cmd *cmd)
		transport_kunmap_data_sg(cmd);
		transport_kunmap_data_sg(cmd);
	}
	}


	target_complete_cmd(cmd, GOOD);
	target_complete_cmd_with_length(cmd, GOOD, 32);
	return 0;
	return 0;
}
}


+6 −3
Original line number Original line Diff line number Diff line
@@ -716,6 +716,7 @@ spc_emulate_inquiry(struct se_cmd *cmd)
	unsigned char *buf;
	unsigned char *buf;
	sense_reason_t ret;
	sense_reason_t ret;
	int p;
	int p;
	int len = 0;


	buf = kzalloc(SE_INQUIRY_BUF, GFP_KERNEL);
	buf = kzalloc(SE_INQUIRY_BUF, GFP_KERNEL);
	if (!buf) {
	if (!buf) {
@@ -737,6 +738,7 @@ spc_emulate_inquiry(struct se_cmd *cmd)
		}
		}


		ret = spc_emulate_inquiry_std(cmd, buf);
		ret = spc_emulate_inquiry_std(cmd, buf);
		len = buf[4] + 5;
		goto out;
		goto out;
	}
	}


@@ -744,6 +746,7 @@ spc_emulate_inquiry(struct se_cmd *cmd)
		if (cdb[2] == evpd_handlers[p].page) {
		if (cdb[2] == evpd_handlers[p].page) {
			buf[1] = cdb[2];
			buf[1] = cdb[2];
			ret = evpd_handlers[p].emulate(cmd, buf);
			ret = evpd_handlers[p].emulate(cmd, buf);
			len = get_unaligned_be16(&buf[2]) + 4;
			goto out;
			goto out;
		}
		}
	}
	}
@@ -760,7 +763,7 @@ spc_emulate_inquiry(struct se_cmd *cmd)
	kfree(buf);
	kfree(buf);


	if (!ret)
	if (!ret)
		target_complete_cmd(cmd, GOOD);
		target_complete_cmd_with_length(cmd, GOOD, len);
	return ret;
	return ret;
}
}


@@ -1098,7 +1101,7 @@ static sense_reason_t spc_emulate_modesense(struct se_cmd *cmd)
		transport_kunmap_data_sg(cmd);
		transport_kunmap_data_sg(cmd);
	}
	}


	target_complete_cmd(cmd, GOOD);
	target_complete_cmd_with_length(cmd, GOOD, length);
	return 0;
	return 0;
}
}


@@ -1274,7 +1277,7 @@ sense_reason_t spc_emulate_report_luns(struct se_cmd *cmd)
	buf[3] = (lun_count & 0xff);
	buf[3] = (lun_count & 0xff);
	transport_kunmap_data_sg(cmd);
	transport_kunmap_data_sg(cmd);


	target_complete_cmd(cmd, GOOD);
	target_complete_cmd_with_length(cmd, GOOD, 8 + lun_count * 8);
	return 0;
	return 0;
}
}
EXPORT_SYMBOL(spc_emulate_report_luns);
EXPORT_SYMBOL(spc_emulate_report_luns);
+17 −0
Original line number Original line Diff line number Diff line
@@ -703,6 +703,23 @@ void target_complete_cmd(struct se_cmd *cmd, u8 scsi_status)
}
}
EXPORT_SYMBOL(target_complete_cmd);
EXPORT_SYMBOL(target_complete_cmd);


void target_complete_cmd_with_length(struct se_cmd *cmd, u8 scsi_status, int length)
{
	if (scsi_status == SAM_STAT_GOOD && length < cmd->data_length) {
		if (cmd->se_cmd_flags & SCF_UNDERFLOW_BIT) {
			cmd->residual_count += cmd->data_length - length;
		} else {
			cmd->se_cmd_flags |= SCF_UNDERFLOW_BIT;
			cmd->residual_count = cmd->data_length - length;
		}

		cmd->data_length = length;
	}

	target_complete_cmd(cmd, scsi_status);
}
EXPORT_SYMBOL(target_complete_cmd_with_length);

static void target_add_to_state_list(struct se_cmd *cmd)
static void target_add_to_state_list(struct se_cmd *cmd)
{
{
	struct se_device *dev = cmd->se_dev;
	struct se_device *dev = cmd->se_dev;
+1 −0
Original line number Original line Diff line number Diff line
@@ -59,6 +59,7 @@ int transport_subsystem_register(struct se_subsystem_api *);
void	transport_subsystem_release(struct se_subsystem_api *);
void	transport_subsystem_release(struct se_subsystem_api *);


void	target_complete_cmd(struct se_cmd *, u8);
void	target_complete_cmd(struct se_cmd *, u8);
void	target_complete_cmd_with_length(struct se_cmd *, u8, int);


sense_reason_t	spc_parse_cdb(struct se_cmd *cmd, unsigned int *size);
sense_reason_t	spc_parse_cdb(struct se_cmd *cmd, unsigned int *size);
sense_reason_t	spc_emulate_report_luns(struct se_cmd *cmd);
sense_reason_t	spc_emulate_report_luns(struct se_cmd *cmd);