VERIFY10: Add support for VERIFY10. Also add a simple test for verify10

This commit is contained in:
Ronnie Sahlberg
2012-01-26 15:47:14 +11:00
parent b9bae6f4a7
commit cff996a96d
11 changed files with 256 additions and 4 deletions

View File

@@ -58,7 +58,8 @@ bin_iscsi_test_SOURCES = test-tool/iscsi-test.c \
test-tool/0104_read10_flags.c test-tool/0105_read10_invalid.c \
test-tool/0110_readcapacity10_simple.c \
test-tool/0111_readcapacity10_pmi.c test-tool/0120_read6_simple.c \
test-tool/0121_read6_beyond_eol.c test-tool/0122_read6_invalid.c
test-tool/0121_read6_beyond_eol.c test-tool/0122_read6_invalid.c \
test-tool/0130_verify10_simple.c
endif
# LD_PRELOAD library.

View File

@@ -256,6 +256,7 @@ void iscsi_set_error(struct iscsi_context *iscsi, const char *error_string,
unsigned char *iscsi_get_user_in_buffer(struct iscsi_context *iscsi, struct iscsi_in_pdu *in, uint32_t pos, ssize_t *count);
unsigned char *scsi_task_get_data_in_buffer(struct scsi_task *task, uint32_t pos, ssize_t *count);
unsigned long crc32c(char *buf, int len);
#endif /* __iscsi_private_h__ */

View File

@@ -593,6 +593,12 @@ iscsi_write10_task(struct iscsi_context *iscsi, int lun,
int fuanv, int blocksize, iscsi_command_cb cb,
void *private_data);
EXTERN struct scsi_task *
iscsi_verify10_task(struct iscsi_context *iscsi, int lun,
unsigned char *data, uint32_t datalen, uint32_t lba,
int vprotect, int dpo, int bytchk,
int blocksize, iscsi_command_cb cb,
void *private_data);
EXTERN struct scsi_task *
iscsi_modesense6_task(struct iscsi_context *iscsi, int lun, int dbd,
int pc, int page_code, int sub_page_code,
unsigned char alloc_len, iscsi_command_cb cb,
@@ -638,6 +644,11 @@ iscsi_write10_sync(struct iscsi_context *iscsi, int lun,
unsigned char *data, uint32_t datalen, uint32_t lba, int fua,
int fuanv, int blocksize);
EXTERN struct scsi_task *
iscsi_verify10_sync(struct iscsi_context *iscsi, int lun,
unsigned char *data, uint32_t datalen, uint32_t lba,
int vprotect, int dpo, int bytchk,
int blocksize);
/*
* This function is used when the application wants to specify its own buffers to read the data

View File

@@ -27,6 +27,7 @@ enum scsi_opcode {
SCSI_OPCODE_READCAPACITY10 = 0x25,
SCSI_OPCODE_READ10 = 0x28,
SCSI_OPCODE_WRITE10 = 0x2A,
SCSI_OPCODE_VERIFY10 = 0x2F,
SCSI_OPCODE_SYNCHRONIZECACHE10 = 0x35,
SCSI_OPCODE_REPORTLUNS = 0xA0
};
@@ -83,6 +84,13 @@ struct scsi_write10_params {
uint32_t lba;
uint32_t num_blocks;
};
struct scsi_verify10_params {
uint32_t lba;
uint32_t num_blocks;
int vprotect;
int dpo;
int bytchk;
};
struct scsi_readcapacity10_params {
int lba;
int pmi;
@@ -131,6 +139,7 @@ struct scsi_task {
struct scsi_read6_params read6;
struct scsi_read10_params read10;
struct scsi_write10_params write10;
struct scsi_verify10_params verify10;
struct scsi_readcapacity10_params readcapacity10;
struct scsi_reportluns_params reportluns;
struct scsi_inquiry_params inquiry;
@@ -481,9 +490,11 @@ EXTERN struct scsi_task *scsi_cdb_read6(uint32_t lba, uint32_t xferlen, int bloc
EXTERN struct scsi_task *scsi_cdb_read10(uint32_t lba, uint32_t xferlen, int blocksize);
EXTERN struct scsi_task *scsi_cdb_write10(uint32_t lba, uint32_t xferlen, int fua, int fuanv,
int blocksize);
EXTERN struct scsi_task *scsi_cdb_verify10(uint32_t lba, uint32_t xferlen, int vprotect, int dpo, int bytchk, int blocksize);
EXTERN struct scsi_task *scsi_cdb_synchronizecache10(int lba, int num_blocks,
int syncnv, int immed);
#endif /* __scsi_lowlevel_h__ */

View File

@@ -46,6 +46,7 @@ iscsi_readcapacity10_task
iscsi_synchronizecache10_task
iscsi_read6_task
iscsi_read10_task
iscsi_verify10_task
iscsi_write10_task
iscsi_modesense6_task
iscsi_scsi_command_sync
@@ -56,6 +57,7 @@ iscsi_readcapacity10_sync
iscsi_synchronizecache10_sync
iscsi_read6_sync
iscsi_read10_sync
iscsi_verify10_sync
iscsi_write10_sync
iscsi_task_cancel
poll
@@ -81,6 +83,7 @@ scsi_datain_getfullsize
scsi_datain_unmarshall
scsi_cdb_read6
scsi_cdb_read10
scsi_cdb_verify10
scsi_cdb_write10
scsi_cdb_synchronizecache10

View File

@@ -677,7 +677,40 @@ iscsi_write10_task(struct iscsi_context *iscsi, int lun, unsigned char *data,
task = scsi_cdb_write10(lba, datalen, fua, fuanv, blocksize);
if (task == NULL) {
iscsi_set_error(iscsi, "Out-of-memory: Failed to create "
"read10 cdb.");
"write10 cdb.");
return NULL;
}
outdata.data = data;
outdata.size = datalen;
if (iscsi_scsi_command_async(iscsi, lun, task, cb, &outdata,
private_data) != 0) {
scsi_free_scsi_task(task);
return NULL;
}
return task;
}
struct scsi_task *
iscsi_verify10_task(struct iscsi_context *iscsi, int lun, unsigned char *data,
uint32_t datalen, uint32_t lba, int vprotect, int dpo, int bytchk, int blocksize,
iscsi_command_cb cb, void *private_data)
{
struct scsi_task *task;
struct iscsi_data outdata;
if (datalen % blocksize != 0) {
iscsi_set_error(iscsi, "Datalen:%d is not a multiple of the "
"blocksize:%d.", datalen, blocksize);
return NULL;
}
task = scsi_cdb_verify10(lba, datalen, vprotect, dpo, bytchk, blocksize);
if (task == NULL) {
iscsi_set_error(iscsi, "Out-of-memory: Failed to create "
"verify10 cdb.");
return NULL;
}

View File

@@ -632,6 +632,52 @@ scsi_cdb_write10(uint32_t lba, uint32_t xferlen, int fua, int fuanv, int blocksi
}
/*
* VERIFY10
*/
struct scsi_task *
scsi_cdb_verify10(uint32_t lba, uint32_t xferlen, int vprotect, int dpo, int bytchk, int blocksize)
{
struct scsi_task *task;
task = malloc(sizeof(struct scsi_task));
if (task == NULL) {
return NULL;
}
memset(task, 0, sizeof(struct scsi_task));
task->cdb[0] = SCSI_OPCODE_VERIFY10;
if (vprotect) {
task->cdb[1] |= ((vprotect << 5) & 0xe0);
}
if (dpo) {
task->cdb[1] |= 0x10;
}
if (bytchk) {
task->cdb[1] |= 0x02;
}
*(uint32_t *)&task->cdb[2] = htonl(lba);
*(uint16_t *)&task->cdb[7] = htons(xferlen/blocksize);
task->cdb_size = 10;
if (xferlen != 0) {
task->xfer_dir = SCSI_XFER_WRITE;
} else {
task->xfer_dir = SCSI_XFER_NONE;
}
task->expxferlen = xferlen;
task->params.verify10.lba = lba;
task->params.verify10.num_blocks = xferlen/blocksize;
task->params.verify10.vprotect = vprotect;
task->params.verify10.dpo = dpo;
task->params.verify10.bytchk = bytchk;
return task;
}
/*
* MODESENSE6

View File

@@ -322,6 +322,26 @@ iscsi_write10_sync(struct iscsi_context *iscsi, int lun, unsigned char *data, ui
return state.task;
}
struct scsi_task *
iscsi_verify10_sync(struct iscsi_context *iscsi, int lun, unsigned char *data, uint32_t datalen, uint32_t lba,
int vprotect, int dpo, int bytchk, int blocksize)
{
struct iscsi_sync_state state;
memset(&state, 0, sizeof(state));
if (iscsi_verify10_task(iscsi, lun, data, datalen, lba, vprotect, dpo, bytchk, blocksize,
scsi_sync_cb, &state) == NULL) {
iscsi_set_error(iscsi,
"Failed to send Verify10 command");
return NULL;
}
event_loop(iscsi, &state);
return state.task;
}
struct scsi_task *
iscsi_scsi_command_sync(struct iscsi_context *iscsi, int lun,
struct scsi_task *task, struct iscsi_data *data)

View File

@@ -0,0 +1,121 @@
/*
Copyright (C) 2010 by Ronnie Sahlberg <ronniesahlberg@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include "iscsi.h"
#include "scsi-lowlevel.h"
#include "iscsi-test.h"
int T0130_verify10_simple(const char *initiator, const char *url)
{
struct iscsi_context *iscsi;
struct scsi_task *task;
struct scsi_task *vtask;
struct scsi_readcapacity10 *rc10;
int ret, i, lun;
uint32_t block_size, num_blocks;
iscsi = iscsi_context_login(initiator, url, &lun);
if (iscsi == NULL) {
printf("Failed to login to target\n");
return -1;
}
/* find the size of the LUN */
task = iscsi_readcapacity10_sync(iscsi, lun, 0, 0);
if (task == NULL) {
printf("Failed to send readcapacity10 command: %s\n", iscsi_get_error(iscsi));
ret = -1;
goto finished;
}
if (task->status != SCSI_STATUS_GOOD) {
printf("Readcapacity command: failed with sense. %s\n", iscsi_get_error(iscsi));
ret = -1;
scsi_free_scsi_task(task);
goto finished;
}
rc10 = scsi_datain_unmarshall(task);
if (rc10 == NULL) {
printf("failed to unmarshall readcapacity10 data. %s\n", iscsi_get_error(iscsi));
ret = -1;
scsi_free_scsi_task(task);
goto finished;
}
block_size = rc10->block_size;
num_blocks = rc10->lba;
scsi_free_scsi_task(task);
ret = 0;
/* read and verify the first 1 - 256 blocks at the start of the LUN */
printf("Read+verify first 1-256 blocks ... ");
for (i = 1; i <= 256; i++) {
char *buf;
task = iscsi_read10_sync(iscsi, lun, 0, i * block_size, block_size);
if (task == NULL) {
printf("[FAILED]\n");
printf("Failed to send read10 command: %s\n", iscsi_get_error(iscsi));
ret = -1;
goto finished;
}
if (task->status != SCSI_STATUS_GOOD) {
printf("[FAILED]\n");
printf("Read10 command: failed with sense. %s\n", iscsi_get_error(iscsi));
ret = -1;
scsi_free_scsi_task(task);
goto finished;
}
buf = task->datain.data;
if (buf == NULL) {
printf("[FAILED]\n");
printf("Failed to access DATA-IN buffer %s\n", iscsi_get_error(iscsi));
ret = -1;
scsi_free_scsi_task(task);
goto finished;
}
vtask = iscsi_verify10_sync(iscsi, lun, buf, i * block_size, 0, 0, 1, 1, block_size);
if (vtask == NULL) {
printf("[FAILED]\n");
printf("Failed to send verify10 command: %s\n", iscsi_get_error(iscsi));
ret = -1;
scsi_free_scsi_task(task);
goto finished;
}
if (vtask->status != SCSI_STATUS_GOOD) {
printf("[FAILED]\n");
printf("Verify10 command: failed with sense. %s\n", iscsi_get_error(iscsi));
ret = -1;
scsi_free_scsi_task(task);
scsi_free_scsi_task(vtask);
goto finished;
}
scsi_free_scsi_task(task);
scsi_free_scsi_task(vtask);
}
printf("[OK]\n");
finished:
iscsi_logout_sync(iscsi);
iscsi_destroy_context(iscsi);
return ret;
}

View File

@@ -28,10 +28,10 @@
#include "iscsi.h"
#include "iscsi-test.h"
char *initiator = "iqn.2010-11.iscsi-test";
const char *initiator = "iqn.2010-11.iscsi-test";
struct scsi_test {
char *name;
const char *name;
int (*test)(const char *initiator, const char *url);
};
@@ -53,6 +53,9 @@ struct scsi_test tests[] = {
{ "T0121_read6_beyond_eol", T0121_read6_beyond_eol },
{ "T0122_read6_invalid", T0122_read6_invalid },
/* verify10*/
{ "T0130_verify10_simple", T0130_verify10_simple },
{ NULL, NULL }
};

View File

@@ -33,3 +33,5 @@ int T0111_readcapacity10_pmi(const char *initiator, const char *url);
int T0120_read6_simple(const char *initiator, const char *url);
int T0121_read6_beyond_eol(const char *initiator, const char *url);
int T0122_read6_invalid(const char *initiator, const char *url);
int T0130_verify10_simple(const char *initiator, const char *url);