start implementing mode page unmarshalling

This commit is contained in:
Ronnie Sahlberg
2011-04-23 14:02:59 +10:00
parent 8bc4150e31
commit de97dbdde8
3 changed files with 227 additions and 3 deletions

View File

@@ -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");

View File

@@ -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,

View File

@@ -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: