test tool: Detect unsupported opcodes correctly

There is no agreement among the T10 committee whether a SCSI target should
report "invalid opcode", "invalid field in CDB" or "invalid field in
parameter list" if the opcode consists of two bytes. Hence accept all three
sense codes for two-byte opcodes. For more information see also Frederick
Knight, RE: INVALID COMMAND OPERATION CODE, T10 Reflector, 16 May 2008
(http://t10.org/ftp/t10/t10r/2008/r0805167.htm).

Signed-off-by: Bart Van Assche <bvanassche@acm.org>
This commit is contained in:
Bart Van Assche
2014-10-14 11:49:23 +02:00
committed by Ronnie Sahlberg
parent 30355f8cc0
commit fe9620092c

View File

@@ -115,6 +115,40 @@ static const char *scsi_status_str(int status)
return "UNKNOWN";
}
static int status_is_invalid_field_in_cdb(struct scsi_task *task)
{
return task->status == SCSI_STATUS_CHECK_CONDITION
&& task->sense.key == SCSI_SENSE_ILLEGAL_REQUEST
&& task->sense.ascq == SCSI_SENSE_ASCQ_INVALID_FIELD_IN_CDB;
}
/*
* There is no agreement among the T10 committee whether a SCSI target should
* report "invalid opcode", "invalid field in CDB" or "invalid field in
* parameter list" if the opcode consists of two bytes. Hence accept all three
* sense codes for two-byte opcodes. For more information see also Frederick
* Knight, RE: INVALID COMMAND OPERATION CODE, T10 Reflector, 16 May 2008
* (http://t10.org/ftp/t10/t10r/2008/r0805167.htm).
*/
static int status_is_invalid_opcode(struct scsi_task *task)
{
if (task->status == SCSI_STATUS_CHECK_CONDITION
&& task->sense.key == SCSI_SENSE_ILLEGAL_REQUEST) {
if (task->sense.ascq == SCSI_SENSE_ASCQ_INVALID_OPERATION_CODE)
return 1;
switch (task->cdb[0]) {
case SCSI_OPCODE_MAINTENANCE_IN:
case SCSI_OPCODE_SERVICE_ACTION_IN:
switch (task->sense.ascq) {
case SCSI_SENSE_ASCQ_INVALID_FIELD_IN_CDB:
case SCSI_SENSE_ASCQ_INVALID_FIELD_IN_PARAMETER_LIST:
return 1;
}
}
}
return 0;
}
static int check_result(const char *opcode, struct scsi_device *sdev,
struct scsi_task *task,
int status, enum scsi_sense_key key,
@@ -127,9 +161,7 @@ static int check_result(const char *opcode, struct scsi_device *sdev,
"%s", opcode, sdev->error_str);
return -1;
}
if (task->status == SCSI_STATUS_CHECK_CONDITION
&& task->sense.key == SCSI_SENSE_ILLEGAL_REQUEST
&& task->sense.ascq == SCSI_SENSE_ASCQ_INVALID_OPERATION_CODE) {
if (status_is_invalid_opcode(task)) {
logging(LOG_NORMAL, "[SKIPPED] %s is not implemented.",
opcode);
return -2;
@@ -493,9 +525,7 @@ prin_task(struct scsi_device *sdev, int service_action,
iscsi_get_error(sdev->iscsi_ctx));
return -1;
}
if (task->status == SCSI_STATUS_CHECK_CONDITION
&& task->sense.key == SCSI_SENSE_ILLEGAL_REQUEST
&& task->sense.ascq == SCSI_SENSE_ASCQ_INVALID_OPERATION_CODE) {
if (status_is_invalid_opcode(task)) {
scsi_free_scsi_task(task);
logging(LOG_NORMAL, "[SKIPPED] PERSISTENT RESERVE IN is not implemented.");
return -2;
@@ -541,9 +571,7 @@ prin_read_keys(struct scsi_device *sdev, struct scsi_task **tp,
iscsi_get_error(sdev->iscsi_ctx));
return -1;
}
if ((*tp)->status == SCSI_STATUS_CHECK_CONDITION
&& (*tp)->sense.key == SCSI_SENSE_ILLEGAL_REQUEST
&& (*tp)->sense.ascq == SCSI_SENSE_ASCQ_INVALID_OPERATION_CODE) {
if (status_is_invalid_opcode(*tp)) {
logging(LOG_NORMAL, "[SKIPPED] PERSISTENT RESERVE IN is not implemented.");
return -2;
}
@@ -597,9 +625,7 @@ prout_register_and_ignore(struct scsi_device *sdev,
iscsi_get_error(sdev->iscsi_ctx));
return -1;
}
if (task->status == SCSI_STATUS_CHECK_CONDITION &&
task->sense.key == SCSI_SENSE_ILLEGAL_REQUEST &&
task->sense.ascq == SCSI_SENSE_ASCQ_INVALID_OPERATION_CODE) {
if (status_is_invalid_opcode(task)) {
logging(LOG_NORMAL, "[SKIPPED] PROUT Not Supported");
ret = -2;
goto dun;
@@ -648,9 +674,7 @@ prout_register_key(struct scsi_device *sdev,
iscsi_get_error(sdev->iscsi_ctx));
return -1;
}
if (task->status == SCSI_STATUS_CHECK_CONDITION
&& task->sense.key == SCSI_SENSE_ILLEGAL_REQUEST
&& task->sense.ascq == SCSI_SENSE_ASCQ_INVALID_OPERATION_CODE) {
if (status_is_invalid_opcode(task)) {
scsi_free_scsi_task(task);
logging(LOG_NORMAL, "[SKIPPED] PERSISTENT RESERVE OUT is not implemented.");
return -2;
@@ -692,9 +716,7 @@ prin_verify_key_presence(struct scsi_device *sdev,
iscsi_get_error(sdev->iscsi_ctx));
return -1;
}
if (task->status == SCSI_STATUS_CHECK_CONDITION
&& task->sense.key == SCSI_SENSE_ILLEGAL_REQUEST
&& task->sense.ascq == SCSI_SENSE_ASCQ_INVALID_OPERATION_CODE) {
if (status_is_invalid_opcode(task)) {
scsi_free_scsi_task(task);
logging(LOG_NORMAL, "[SKIPPED] PERSISTENT RESERVE IN is not implemented.");
return -2;
@@ -767,9 +789,7 @@ prout_reregister_key_fails(struct scsi_device *sdev,
iscsi_get_error(sdev->iscsi_ctx));
return -1;
}
if (task->status == SCSI_STATUS_CHECK_CONDITION
&& task->sense.key == SCSI_SENSE_ILLEGAL_REQUEST
&& task->sense.ascq == SCSI_SENSE_ASCQ_INVALID_OPERATION_CODE) {
if (status_is_invalid_opcode(task)) {
scsi_free_scsi_task(task);
logging(LOG_NORMAL, "[SKIPPED] PERSISTENT RESERVE OUT is not implemented.");
return -2;
@@ -817,9 +837,7 @@ prout_reserve(struct scsi_device *sdev,
iscsi_get_error(sdev->iscsi_ctx));
return -1;
}
if (task->status == SCSI_STATUS_CHECK_CONDITION
&& task->sense.key == SCSI_SENSE_ILLEGAL_REQUEST
&& task->sense.ascq == SCSI_SENSE_ASCQ_INVALID_OPERATION_CODE) {
if (status_is_invalid_opcode(task)) {
scsi_free_scsi_task(task);
logging(LOG_NORMAL, "[SKIPPED] PERSISTENT RESERVE OUT is not implemented.");
return -2;
@@ -866,9 +884,7 @@ prout_release(struct scsi_device *sdev,
iscsi_get_error(sdev->iscsi_ctx));
return -1;
}
if (task->status == SCSI_STATUS_CHECK_CONDITION
&& task->sense.key == SCSI_SENSE_ILLEGAL_REQUEST
&& task->sense.ascq == SCSI_SENSE_ASCQ_INVALID_OPERATION_CODE) {
if (status_is_invalid_opcode(task)) {
scsi_free_scsi_task(task);
logging(LOG_NORMAL, "[SKIPPED] PERSISTENT RESERVE OUT is not implemented.");
return -2;
@@ -907,9 +923,7 @@ prin_verify_reserved_as(struct scsi_device *sdev,
iscsi_get_error(sdev->iscsi_ctx));
return -1;
}
if (task->status == SCSI_STATUS_CHECK_CONDITION
&& task->sense.key == SCSI_SENSE_ILLEGAL_REQUEST
&& task->sense.ascq == SCSI_SENSE_ASCQ_INVALID_OPERATION_CODE) {
if (status_is_invalid_opcode(task)) {
scsi_free_scsi_task(task);
logging(LOG_NORMAL, "[SKIPPED] PERSISTENT RESERVE IN is not implemented.");
return -2;
@@ -980,9 +994,7 @@ prin_verify_not_reserved(struct scsi_device *sdev)
iscsi_get_error(sdev->iscsi_ctx));
return -1;
}
if (task->status == SCSI_STATUS_CHECK_CONDITION
&& task->sense.key == SCSI_SENSE_ILLEGAL_REQUEST
&& task->sense.ascq == SCSI_SENSE_ASCQ_INVALID_OPERATION_CODE) {
if (status_is_invalid_opcode(task)) {
scsi_free_scsi_task(task);
logging(LOG_NORMAL, "[SKIPPED] PERSISTENT RESERVE IN is not implemented.");
return -2;
@@ -1240,9 +1252,7 @@ int sanitize(struct scsi_device *sdev, int immed, int ause, int sa, int param_le
iscsi_get_error(sdev->iscsi_ctx));
return -1;
}
if (task->status == SCSI_STATUS_CHECK_CONDITION
&& task->sense.key == SCSI_SENSE_ILLEGAL_REQUEST
&& task->sense.ascq == SCSI_SENSE_ASCQ_INVALID_OPERATION_CODE) {
if (status_is_invalid_opcode(task)) {
logging(LOG_NORMAL, "[SKIPPED] SANITIZE is not "
"implemented on target");
scsi_free_scsi_task(task);
@@ -1277,9 +1287,7 @@ int sanitize_invalidfieldincdb(struct scsi_device *sdev, int immed, int ause, in
iscsi_get_error(sdev->iscsi_ctx));
return -1;
}
if (task->status == SCSI_STATUS_CHECK_CONDITION
&& task->sense.key == SCSI_SENSE_ILLEGAL_REQUEST
&& task->sense.ascq == SCSI_SENSE_ASCQ_INVALID_OPERATION_CODE) {
if (status_is_invalid_opcode(task)) {
logging(LOG_NORMAL, "[SKIPPED] SANITIZE is not "
"implemented on target");
scsi_free_scsi_task(task);
@@ -1291,9 +1299,7 @@ int sanitize_invalidfieldincdb(struct scsi_device *sdev, int immed, int ause, in
scsi_free_scsi_task(task);
return -1;
}
if (task->status != SCSI_STATUS_CHECK_CONDITION
|| task->sense.key != SCSI_SENSE_ILLEGAL_REQUEST
|| task->sense.ascq != SCSI_SENSE_ASCQ_INVALID_FIELD_IN_CDB) {
if (!status_is_invalid_field_in_cdb(task)) {
logging(LOG_NORMAL, "[FAILED] SANITIZE failed with wrong "
"sense. Should have failed with ILLEGAL_REQUEST/"
"INVALID_FIELD_IN_CDB. Sense:%s\n",
@@ -1635,9 +1641,7 @@ preventallow(struct scsi_device *sdev, int prevent)
"command: %s", iscsi_get_error(sdev->iscsi_ctx));
return -1;
}
if (task->status == SCSI_STATUS_CHECK_CONDITION
&& task->sense.key == SCSI_SENSE_ILLEGAL_REQUEST
&& task->sense.ascq == SCSI_SENSE_ASCQ_INVALID_OPERATION_CODE) {
if (status_is_invalid_opcode(task)) {
logging(LOG_NORMAL, "[SKIPPED] PREVENTALLOW is not implemented on target");
scsi_free_scsi_task(task);
return -2;
@@ -1907,9 +1911,7 @@ reserve6(struct scsi_device *sdev)
res = -1;
break;
}
if (task->status == SCSI_STATUS_CHECK_CONDITION
&& task->sense.key == SCSI_SENSE_ILLEGAL_REQUEST
&& task->sense.ascq == SCSI_SENSE_ASCQ_INVALID_OPERATION_CODE) {
if (status_is_invalid_opcode(task)) {
logging(LOG_NORMAL, "[SKIPPED] RESERVE6 is not "
"implemented on target");
res = -2;
@@ -1947,9 +1949,7 @@ reserve6_conflict(struct scsi_device *sdev)
res = -1;
break;
}
if (task->status == SCSI_STATUS_CHECK_CONDITION
&& task->sense.key == SCSI_SENSE_ILLEGAL_REQUEST
&& task->sense.ascq == SCSI_SENSE_ASCQ_INVALID_OPERATION_CODE) {
if (status_is_invalid_opcode(task)) {
logging(LOG_NORMAL, "[SKIPPED] RESERVE6 is not"
" implemented on target");
res = -2;