start implementing mode page unmarshalling
This commit is contained in:
@@ -13,7 +13,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* This is the host/port we connect to.*/
|
/* This is the host/port we connect to.*/
|
||||||
#define TARGET "10.1.1.27:3260"
|
#define TARGET "127.0.0.1:3260"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@@ -210,10 +210,12 @@ void modesense6_cb(struct iscsi_context *iscsi, int status, void *command_data,
|
|||||||
{
|
{
|
||||||
struct client_state *clnt = (struct client_state *)private_data;
|
struct client_state *clnt = (struct client_state *)private_data;
|
||||||
struct scsi_task *task = command_data;
|
struct scsi_task *task = command_data;
|
||||||
|
struct scsi_mode_sense *ms;
|
||||||
int full_size;
|
int full_size;
|
||||||
|
|
||||||
if (status == SCSI_STATUS_CHECK_CONDITION) {
|
if (status == SCSI_STATUS_CHECK_CONDITION) {
|
||||||
printf("Modesense6 failed with sense key:%d ascq:%04x\n", task->sense.key, task->sense.ascq);
|
printf("Modesense6 failed with sense key:%d ascq:%04x\n", task->sense.key, task->sense.ascq);
|
||||||
|
exit(10);
|
||||||
} else {
|
} else {
|
||||||
full_size = scsi_datain_getfullsize(task);
|
full_size = scsi_datain_getfullsize(task);
|
||||||
if (full_size > task->datain.size) {
|
if (full_size > task->datain.size) {
|
||||||
@@ -227,7 +229,13 @@ void modesense6_cb(struct iscsi_context *iscsi, int status, void *command_data,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("MODESENSE6 successful.\n");
|
}
|
||||||
|
printf("MODESENSE6 successful.\n");
|
||||||
|
ms = scsi_datain_unmarshall(task);
|
||||||
|
if (ms == NULL) {
|
||||||
|
printf("failed to unmarshall mode sense datain blob\n");
|
||||||
|
scsi_free_scsi_task(task);
|
||||||
|
exit(10);
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("Send READCAPACITY10\n");
|
printf("Send READCAPACITY10\n");
|
||||||
|
|||||||
@@ -379,8 +379,90 @@ enum scsi_modesense_page_control {
|
|||||||
SCSI_MODESENSE_PC_SAVED = 0x03
|
SCSI_MODESENSE_PC_SAVED = 0x03
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct scsi_mode_page_caching {
|
||||||
|
int ic;
|
||||||
|
int abpf;
|
||||||
|
int cap;
|
||||||
|
int disc;
|
||||||
|
int size;
|
||||||
|
int wce;
|
||||||
|
int mf;
|
||||||
|
int rcd;
|
||||||
|
|
||||||
|
int demand_read_retention_priority;
|
||||||
|
int write_retention_priority;
|
||||||
|
|
||||||
|
int disable_prefetch_transfer_length;
|
||||||
|
int minimum_prefetch;
|
||||||
|
int maximum_prefetch;
|
||||||
|
int maximum_prefetch_ceiling;
|
||||||
|
|
||||||
|
int fsw;
|
||||||
|
int lbcss;
|
||||||
|
int dra;
|
||||||
|
int nv_dis;
|
||||||
|
|
||||||
|
int number_of_cache_segments;
|
||||||
|
int cache_segment_size;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct scsi_mode_page_disconnect_reconnect {
|
||||||
|
int buffer_full_ratio;
|
||||||
|
int buffer_empty_ratio;
|
||||||
|
int bus_inactivity_limit;
|
||||||
|
int disconnect_time_limit;
|
||||||
|
int connect_time_limit;
|
||||||
|
int maximum_burst_size;
|
||||||
|
int emdp;
|
||||||
|
int fair_arbitration;
|
||||||
|
int dimm;
|
||||||
|
int dtdc;
|
||||||
|
int first_burst_size;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct scsi_mode_page_informational_exceptions_control {
|
||||||
|
int perf;
|
||||||
|
int ebf;
|
||||||
|
int ewasc;
|
||||||
|
int dexcpt;
|
||||||
|
int test;
|
||||||
|
int ebackerr;
|
||||||
|
int logerr;
|
||||||
|
int mrie;
|
||||||
|
int interval_timer;
|
||||||
|
int report_count;
|
||||||
|
};
|
||||||
|
|
||||||
enum scsi_modesense_page_code {
|
enum scsi_modesense_page_code {
|
||||||
SCSI_MODESENSE_PAGECODE_RETURN_ALL_PAGES = 0x3f
|
SCSI_MODESENSE_PAGECODE_READ_WRITE_ERROR_RECOVERY = 0x01,
|
||||||
|
SCSI_MODESENSE_PAGECODE_DISCONNECT_RECONNECT = 0x02,
|
||||||
|
SCSI_MODESENSE_PAGECODE_VERIFY_ERROR_RECOVERY = 0x07,
|
||||||
|
SCSI_MODESENSE_PAGECODE_CACHING = 0x08,
|
||||||
|
SCSI_MODESENSE_PAGECODE_XOR_CONTROL = 0x10,
|
||||||
|
SCSI_MODESENSE_PAGECODE_INFORMATIONAL_EXCEPTIONS_CONTROL = 0x1c,
|
||||||
|
SCSI_MODESENSE_PAGECODE_RETURN_ALL_PAGES = 0x3f
|
||||||
|
};
|
||||||
|
|
||||||
|
struct scsi_mode_page {
|
||||||
|
struct scsi_mode_page *next;
|
||||||
|
int ps;
|
||||||
|
int spf;
|
||||||
|
enum scsi_modesense_page_code page_code;
|
||||||
|
int subpage_code;
|
||||||
|
int len;
|
||||||
|
union {
|
||||||
|
struct scsi_mode_page_caching caching;
|
||||||
|
struct scsi_mode_page_disconnect_reconnect disconnect_reconnect;
|
||||||
|
struct scsi_mode_page_informational_exceptions_control iec;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct scsi_mode_sense {
|
||||||
|
uint8_t mode_data_length;
|
||||||
|
uint8_t medium_type;
|
||||||
|
uint8_t device_specific_parameter;
|
||||||
|
uint8_t block_descriptor_length;
|
||||||
|
struct scsi_mode_page *pages;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct scsi_task *scsi_cdb_modesense6(int dbd,
|
struct scsi_task *scsi_cdb_modesense6(int dbd,
|
||||||
|
|||||||
@@ -677,6 +677,138 @@ scsi_modesense6_datain_getfullsize(struct scsi_task *task)
|
|||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
scsi_parse_mode_caching(struct scsi_task *task, int pos, struct scsi_mode_page *mp)
|
||||||
|
{
|
||||||
|
mp->caching.ic = task->datain.data[pos] & 0x80;
|
||||||
|
mp->caching.abpf = task->datain.data[pos] & 0x40;
|
||||||
|
mp->caching.cap = task->datain.data[pos] & 0x20;
|
||||||
|
mp->caching.disc = task->datain.data[pos] & 0x10;
|
||||||
|
mp->caching.size = task->datain.data[pos] & 0x08;
|
||||||
|
mp->caching.wce = task->datain.data[pos] & 0x04;
|
||||||
|
mp->caching.mf = task->datain.data[pos] & 0x02;
|
||||||
|
mp->caching.rcd = task->datain.data[pos] & 0x01;
|
||||||
|
|
||||||
|
mp->caching.demand_read_retention_priority = (task->datain.data[pos+1] >> 4) & 0x0f;
|
||||||
|
mp->caching.write_retention_priority = task->datain.data[pos+1] & 0x0f;
|
||||||
|
|
||||||
|
mp->caching.disable_prefetch_transfer_length = htons(*(uint16_t *)&(task->datain.data[pos+2]));
|
||||||
|
mp->caching.minimum_prefetch = htons(*(uint16_t *)&(task->datain.data[pos+4]));
|
||||||
|
mp->caching.maximum_prefetch = htons(*(uint16_t *)&(task->datain.data[pos+6]));
|
||||||
|
mp->caching.maximum_prefetch_ceiling = htons(*(uint16_t *)&(task->datain.data[pos+8]));
|
||||||
|
|
||||||
|
mp->caching.fsw = task->datain.data[pos+10] & 0x80;
|
||||||
|
mp->caching.lbcss = task->datain.data[pos+10] & 0x40;
|
||||||
|
mp->caching.dra = task->datain.data[pos+10] & 0x20;
|
||||||
|
mp->caching.nv_dis = task->datain.data[pos+10] & 0x01;
|
||||||
|
|
||||||
|
mp->caching.number_of_cache_segments = task->datain.data[pos+11];
|
||||||
|
mp->caching.cache_segment_size = htons(*(uint16_t *)&(task->datain.data[pos+12]));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
scsi_parse_mode_disconnect_reconnect(struct scsi_task *task, int pos, struct scsi_mode_page *mp)
|
||||||
|
{
|
||||||
|
mp->disconnect_reconnect.buffer_full_ratio = task->datain.data[pos];
|
||||||
|
mp->disconnect_reconnect.buffer_empty_ratio = task->datain.data[pos+1];
|
||||||
|
mp->disconnect_reconnect.bus_inactivity_limit = htons(*(uint16_t *)&(task->datain.data[pos+2]));
|
||||||
|
mp->disconnect_reconnect.disconnect_time_limit = htons(*(uint16_t *)&(task->datain.data[pos+4]));
|
||||||
|
mp->disconnect_reconnect.connect_time_limit = htons(*(uint16_t *)&(task->datain.data[pos+6]));
|
||||||
|
mp->disconnect_reconnect.maximum_burst_size = htons(*(uint16_t *)&(task->datain.data[pos+8]));
|
||||||
|
mp->disconnect_reconnect.emdp = task->datain.data[pos+10] & 0x80;
|
||||||
|
mp->disconnect_reconnect.fair_arbitration = (task->datain.data[pos+10]>>4) & 0x0f;
|
||||||
|
mp->disconnect_reconnect.dimm = task->datain.data[pos+10] & 0x08;
|
||||||
|
mp->disconnect_reconnect.dtdc = task->datain.data[pos+10] & 0x07;
|
||||||
|
mp->disconnect_reconnect.first_burst_size = htons(*(uint16_t *)&(task->datain.data[pos+12]));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
scsi_parse_mode_informational_exceptions_control(struct scsi_task *task, int pos, struct scsi_mode_page *mp)
|
||||||
|
{
|
||||||
|
mp->iec.perf = task->datain.data[pos] & 0x80;
|
||||||
|
mp->iec.ebf = task->datain.data[pos] & 0x20;
|
||||||
|
mp->iec.ewasc = task->datain.data[pos] & 0x10;
|
||||||
|
mp->iec.dexcpt = task->datain.data[pos] & 0x08;
|
||||||
|
mp->iec.test = task->datain.data[pos] & 0x04;
|
||||||
|
mp->iec.ebackerr = task->datain.data[pos] & 0x02;
|
||||||
|
mp->iec.logerr = task->datain.data[pos] & 0x01;
|
||||||
|
mp->iec.mrie = task->datain.data[pos+1] & 0x0f;
|
||||||
|
mp->iec.interval_timer = htonl(*(uint32_t *)&(task->datain.data[pos+2]));
|
||||||
|
mp->iec.report_count = htonl(*(uint32_t *)&(task->datain.data[pos+6]));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* parse and unmarshall the mode sense data in buffer
|
||||||
|
*/
|
||||||
|
static struct scsi_mode_sense *
|
||||||
|
scsi_modesense_datain_unmarshall(struct scsi_task *task)
|
||||||
|
{
|
||||||
|
struct scsi_mode_sense *ms;
|
||||||
|
int pos;
|
||||||
|
|
||||||
|
if (task->datain.size < 4) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ms = scsi_malloc(task, sizeof(struct scsi_mode_sense));
|
||||||
|
if (ms == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ms->mode_data_length = task->datain.data[0];
|
||||||
|
ms->medium_type = task->datain.data[1];
|
||||||
|
ms->device_specific_parameter = task->datain.data[2];
|
||||||
|
ms->block_descriptor_length = task->datain.data[3];
|
||||||
|
ms->pages = NULL;
|
||||||
|
|
||||||
|
if (ms->mode_data_length + 1 > task->datain.size) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
pos = 4 + ms->block_descriptor_length;
|
||||||
|
while (pos < task->datain.size) {
|
||||||
|
struct scsi_mode_page *mp;
|
||||||
|
|
||||||
|
mp = scsi_malloc(task, sizeof(struct scsi_mode_page));
|
||||||
|
if (mp == NULL) {
|
||||||
|
return ms;
|
||||||
|
}
|
||||||
|
mp->ps = task->datain.data[pos] & 0x80;
|
||||||
|
mp->spf = task->datain.data[pos] & 0x40;
|
||||||
|
mp->page_code = task->datain.data[pos] & 0x3f;
|
||||||
|
pos++;
|
||||||
|
|
||||||
|
if (mp->spf) {
|
||||||
|
mp->subpage_code = task->datain.data[pos++];
|
||||||
|
mp->len = ntohs(*(uint16_t *)&task->datain.data[pos]);
|
||||||
|
pos += 2;
|
||||||
|
} else {
|
||||||
|
mp->subpage_code = 0;
|
||||||
|
mp->len = task->datain.data[pos++];
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (mp->page_code) {
|
||||||
|
case SCSI_MODESENSE_PAGECODE_CACHING:
|
||||||
|
scsi_parse_mode_caching(task, pos, mp);
|
||||||
|
break;
|
||||||
|
case SCSI_MODESENSE_PAGECODE_DISCONNECT_RECONNECT:
|
||||||
|
scsi_parse_mode_disconnect_reconnect(task, pos, mp);
|
||||||
|
break;
|
||||||
|
case SCSI_MODESENSE_PAGECODE_INFORMATIONAL_EXCEPTIONS_CONTROL:
|
||||||
|
scsi_parse_mode_informational_exceptions_control(task, pos, mp);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
mp->next = ms->pages;
|
||||||
|
ms->pages = mp;
|
||||||
|
|
||||||
|
pos += mp->len;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SYNCHRONIZECACHE10
|
* SYNCHRONIZECACHE10
|
||||||
@@ -740,6 +872,8 @@ scsi_datain_unmarshall(struct scsi_task *task)
|
|||||||
return NULL;
|
return NULL;
|
||||||
case SCSI_OPCODE_INQUIRY:
|
case SCSI_OPCODE_INQUIRY:
|
||||||
return scsi_inquiry_datain_unmarshall(task);
|
return scsi_inquiry_datain_unmarshall(task);
|
||||||
|
case SCSI_OPCODE_MODESENSE6:
|
||||||
|
return scsi_modesense_datain_unmarshall(task);
|
||||||
case SCSI_OPCODE_READCAPACITY10:
|
case SCSI_OPCODE_READCAPACITY10:
|
||||||
return scsi_readcapacity10_datain_unmarshall(task);
|
return scsi_readcapacity10_datain_unmarshall(task);
|
||||||
case SCSI_OPCODE_SYNCHRONIZECACHE10:
|
case SCSI_OPCODE_SYNCHRONIZECACHE10:
|
||||||
|
|||||||
Reference in New Issue
Block a user