start implementing mode page unmarshalling
This commit is contained in:
@@ -13,7 +13,7 @@
|
||||
*/
|
||||
|
||||
/* 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 <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 scsi_task *task = command_data;
|
||||
struct scsi_mode_sense *ms;
|
||||
int full_size;
|
||||
|
||||
if (status == SCSI_STATUS_CHECK_CONDITION) {
|
||||
printf("Modesense6 failed with sense key:%d ascq:%04x\n", task->sense.key, task->sense.ascq);
|
||||
exit(10);
|
||||
} else {
|
||||
full_size = scsi_datain_getfullsize(task);
|
||||
if (full_size > task->datain.size) {
|
||||
@@ -227,7 +229,13 @@ void modesense6_cb(struct iscsi_context *iscsi, int status, void *command_data,
|
||||
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");
|
||||
|
||||
@@ -379,8 +379,90 @@ enum scsi_modesense_page_control {
|
||||
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 {
|
||||
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,
|
||||
|
||||
@@ -677,6 +677,138 @@ scsi_modesense6_datain_getfullsize(struct scsi_task *task)
|
||||
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
|
||||
@@ -740,6 +872,8 @@ scsi_datain_unmarshall(struct scsi_task *task)
|
||||
return NULL;
|
||||
case SCSI_OPCODE_INQUIRY:
|
||||
return scsi_inquiry_datain_unmarshall(task);
|
||||
case SCSI_OPCODE_MODESENSE6:
|
||||
return scsi_modesense_datain_unmarshall(task);
|
||||
case SCSI_OPCODE_READCAPACITY10:
|
||||
return scsi_readcapacity10_datain_unmarshall(task);
|
||||
case SCSI_OPCODE_SYNCHRONIZECACHE10:
|
||||
|
||||
Reference in New Issue
Block a user