Add MODESELECT6 support
Add support for MODESELECT6 and add marshalling functions for the mode pages we support so far.
This commit is contained in:
@@ -635,6 +635,8 @@ EXTERN int
|
||||
iscsi_set_isid_reserved(struct iscsi_context *iscsi);
|
||||
|
||||
|
||||
struct scsi_mode_page;
|
||||
|
||||
|
||||
|
||||
/*
|
||||
@@ -818,6 +820,10 @@ iscsi_writesame16_task(struct iscsi_context *iscsi, int lun, uint64_t lba,
|
||||
int anchor, int unmap, int wrprotect, int group,
|
||||
iscsi_command_cb cb, void *private_data);
|
||||
EXTERN struct scsi_task *
|
||||
iscsi_modeselect6_task(struct iscsi_context *iscsi, int lun,
|
||||
int pf, int sp, struct scsi_mode_page *mp,
|
||||
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,
|
||||
@@ -870,6 +876,10 @@ EXTERN struct scsi_task *
|
||||
iscsi_scsi_command_sync(struct iscsi_context *iscsi, int lun,
|
||||
struct scsi_task *task, struct iscsi_data *data);
|
||||
|
||||
EXTERN struct scsi_task *
|
||||
iscsi_modeselect6_sync(struct iscsi_context *iscsi, int lun,
|
||||
int pf, int sp, struct scsi_mode_page *mp);
|
||||
|
||||
EXTERN struct scsi_task *
|
||||
iscsi_modesense6_sync(struct iscsi_context *iscsi, int lun, int dbd,
|
||||
int pc, int page_code, int sub_page_code,
|
||||
|
||||
@@ -33,6 +33,7 @@ enum scsi_opcode {
|
||||
SCSI_OPCODE_TESTUNITREADY = 0x00,
|
||||
SCSI_OPCODE_READ6 = 0x08,
|
||||
SCSI_OPCODE_INQUIRY = 0x12,
|
||||
SCSI_OPCODE_MODESELECT6 = 0x15,
|
||||
SCSI_OPCODE_RESERVE6 = 0x16,
|
||||
SCSI_OPCODE_RELEASE6 = 0x17,
|
||||
SCSI_OPCODE_MODESENSE6 = 0x1a,
|
||||
@@ -747,6 +748,11 @@ struct scsi_mode_sense {
|
||||
struct scsi_mode_page *pages;
|
||||
};
|
||||
|
||||
EXTERN struct scsi_mode_page *
|
||||
scsi_modesense_get_page(struct scsi_mode_sense *ms,
|
||||
enum scsi_modesense_page_code page_code,
|
||||
int subpage_code);
|
||||
|
||||
EXTERN struct scsi_task *scsi_cdb_modesense6(int dbd,
|
||||
enum scsi_modesense_page_control pc,
|
||||
enum scsi_modesense_page_code page_code,
|
||||
@@ -754,6 +760,12 @@ EXTERN struct scsi_task *scsi_cdb_modesense6(int dbd,
|
||||
unsigned char alloc_len);
|
||||
|
||||
|
||||
EXTERN struct scsi_task *scsi_cdb_modeselect6(int pf, int sp, int param_len);
|
||||
|
||||
EXTERN struct scsi_data *
|
||||
scsi_modesense_dataout_marshall(struct scsi_task *task,
|
||||
struct scsi_mode_page *mp,
|
||||
int is_modeselect6);
|
||||
|
||||
|
||||
struct scsi_readcapacity16 {
|
||||
|
||||
@@ -1204,6 +1204,43 @@ iscsi_verify16_task(struct iscsi_context *iscsi, int lun, unsigned char *data,
|
||||
return task;
|
||||
}
|
||||
|
||||
struct scsi_task *
|
||||
iscsi_modeselect6_task(struct iscsi_context *iscsi, int lun,
|
||||
int pf, int sp, struct scsi_mode_page *mp,
|
||||
iscsi_command_cb cb, void *private_data)
|
||||
{
|
||||
struct scsi_task *task;
|
||||
struct scsi_data *data;
|
||||
struct iscsi_data d;
|
||||
|
||||
task = scsi_cdb_modeselect6(pf, sp, 255);
|
||||
if (task == NULL) {
|
||||
iscsi_set_error(iscsi, "Out-of-memory: Failed to create "
|
||||
"modeselect6 cdb.");
|
||||
return NULL;
|
||||
}
|
||||
data = scsi_modesense_dataout_marshall(task, mp, 1);
|
||||
if (data == NULL) {
|
||||
iscsi_set_error(iscsi, "Error: Failed to marshall "
|
||||
"modesense dataout buffer.");
|
||||
scsi_free_scsi_task(task);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
d.data = data->data;
|
||||
d.size = data->size;
|
||||
task->cdb[4] = data->size;
|
||||
task->expxferlen = data->size;
|
||||
|
||||
if (iscsi_scsi_command_async(iscsi, lun, task, cb,
|
||||
&d, private_data) != 0) {
|
||||
scsi_free_scsi_task(task);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return task;
|
||||
}
|
||||
|
||||
struct scsi_task *
|
||||
iscsi_modesense6_task(struct iscsi_context *iscsi, int lun, int dbd, int pc,
|
||||
int page_code, int sub_page_code,
|
||||
|
||||
@@ -23,6 +23,8 @@ iscsi_login_async
|
||||
iscsi_login_sync
|
||||
iscsi_logout_async
|
||||
iscsi_logout_sync
|
||||
iscsi_modeselect6_sync
|
||||
iscsi_modeselect6_task
|
||||
iscsi_modesense6_sync
|
||||
iscsi_modesense6_task
|
||||
iscsi_nop_out_async
|
||||
@@ -151,6 +153,7 @@ iscsi_writesame16_task
|
||||
scsi_association_to_str
|
||||
scsi_cdb_inquiry
|
||||
scsi_cdb_get_lba_status
|
||||
scsi_cdb_modeselect6
|
||||
scsi_cdb_modesense6
|
||||
scsi_cdb_persistent_reserve_in
|
||||
scsi_cdb_persistent_reserve_out
|
||||
@@ -196,6 +199,8 @@ scsi_devtype_to_str
|
||||
scsi_free_scsi_task
|
||||
scsi_get_task_private_ptr
|
||||
scsi_inquiry_pagecode_to_str
|
||||
scsi_modesense_dataout_marshall
|
||||
scsi_modesense_get_page
|
||||
scsi_protocol_identifier_to_str
|
||||
scsi_reportluns_cdb
|
||||
scsi_sense_ascq_str
|
||||
|
||||
@@ -21,6 +21,8 @@ iscsi_login_async
|
||||
iscsi_login_sync
|
||||
iscsi_logout_async
|
||||
iscsi_logout_sync
|
||||
iscsi_modeselect6_sync
|
||||
iscsi_modeselect6_task
|
||||
iscsi_modesense6_sync
|
||||
iscsi_modesense6_task
|
||||
iscsi_nop_out_async
|
||||
@@ -149,6 +151,7 @@ iscsi_writesame16_task
|
||||
scsi_association_to_str
|
||||
scsi_cdb_inquiry
|
||||
scsi_cdb_get_lba_status
|
||||
scsi_cdb_modeselect6
|
||||
scsi_cdb_modesense6
|
||||
scsi_cdb_persistent_reserve_in
|
||||
scsi_cdb_persistent_reserve_out
|
||||
@@ -194,6 +197,8 @@ scsi_devtype_to_str
|
||||
scsi_free_scsi_task
|
||||
scsi_get_task_private_ptr
|
||||
scsi_inquiry_pagecode_to_str
|
||||
scsi_modesense_dataout_marshall
|
||||
scsi_modesense_get_page
|
||||
scsi_protocol_identifier_to_str
|
||||
scsi_reportluns_cdb
|
||||
scsi_sense_ascq_str
|
||||
|
||||
@@ -2177,6 +2177,58 @@ scsi_cdb_modesense6(int dbd, enum scsi_modesense_page_control pc,
|
||||
return task;
|
||||
}
|
||||
|
||||
/*
|
||||
* MODESELECT6
|
||||
*/
|
||||
struct scsi_task *
|
||||
scsi_cdb_modeselect6(int pf, int sp, int param_len)
|
||||
{
|
||||
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_MODESELECT6;
|
||||
|
||||
if (pf) {
|
||||
task->cdb[1] |= 0x10;
|
||||
}
|
||||
if (sp) {
|
||||
task->cdb[1] |= 0x01;
|
||||
}
|
||||
task->cdb[4] = param_len;
|
||||
|
||||
task->cdb_size = 6;
|
||||
if (param_len != 0) {
|
||||
task->xfer_dir = SCSI_XFER_WRITE;
|
||||
} else {
|
||||
task->xfer_dir = SCSI_XFER_NONE;
|
||||
}
|
||||
task->expxferlen = param_len;
|
||||
|
||||
return task;
|
||||
}
|
||||
|
||||
struct scsi_mode_page *
|
||||
scsi_modesense_get_page(struct scsi_mode_sense *ms,
|
||||
enum scsi_modesense_page_code page_code,
|
||||
int subpage_code)
|
||||
{
|
||||
struct scsi_mode_page *mp;
|
||||
|
||||
for (mp = ms->pages; mp; mp = mp->next) {
|
||||
if (mp->page_code == page_code
|
||||
&& mp->subpage_code == subpage_code) {
|
||||
return mp;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* parse the data in blob and calculate the size of a full
|
||||
* modesense6 datain structure
|
||||
@@ -2377,6 +2429,201 @@ scsi_modesense_datain_unmarshall(struct scsi_task *task)
|
||||
return ms;
|
||||
}
|
||||
|
||||
static struct scsi_data *
|
||||
scsi_modesense_marshall_caching(struct scsi_task *task,
|
||||
struct scsi_mode_page *mp,
|
||||
int hdr_size)
|
||||
{
|
||||
struct scsi_data *data;
|
||||
|
||||
data = scsi_malloc(task, sizeof(struct scsi_data));
|
||||
|
||||
data->size = 20 + hdr_size;
|
||||
data->data = scsi_malloc(task, data->size);
|
||||
|
||||
if (mp->caching.ic) data->data[hdr_size + 2] |= 0x80;
|
||||
if (mp->caching.abpf) data->data[hdr_size + 2] |= 0x40;
|
||||
if (mp->caching.cap) data->data[hdr_size + 2] |= 0x20;
|
||||
if (mp->caching.disc) data->data[hdr_size + 2] |= 0x10;
|
||||
if (mp->caching.size) data->data[hdr_size + 2] |= 0x08;
|
||||
if (mp->caching.wce) data->data[hdr_size + 2] |= 0x04;
|
||||
if (mp->caching.mf) data->data[hdr_size + 2] |= 0x02;
|
||||
if (mp->caching.rcd) data->data[hdr_size + 2] |= 0x01;
|
||||
|
||||
data->data[hdr_size + 3] |= (mp->caching.demand_read_retention_priority << 4) & 0xf0;
|
||||
data->data[hdr_size + 3] |= mp->caching.write_retention_priority & 0x0f;
|
||||
|
||||
scsi_set_uint16(&data->data[hdr_size + 4], mp->caching.disable_prefetch_transfer_length);
|
||||
scsi_set_uint16(&data->data[hdr_size + 6], mp->caching.minimum_prefetch);
|
||||
scsi_set_uint16(&data->data[hdr_size + 8], mp->caching.maximum_prefetch);
|
||||
scsi_set_uint16(&data->data[hdr_size + 10], mp->caching.maximum_prefetch_ceiling);
|
||||
|
||||
if (mp->caching.fsw) data->data[hdr_size + 12] |= 0x80;
|
||||
if (mp->caching.lbcss) data->data[hdr_size + 12] |= 0x40;
|
||||
if (mp->caching.dra) data->data[hdr_size + 12] |= 0x20;
|
||||
if (mp->caching.nv_dis) data->data[hdr_size + 12] |= 0x01;
|
||||
|
||||
data->data[hdr_size + 13] = mp->caching.number_of_cache_segments;
|
||||
|
||||
scsi_set_uint16(&data->data[hdr_size + 14], mp->caching.cache_segment_size);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
static struct scsi_data *
|
||||
scsi_modesense_marshall_control(struct scsi_task *task,
|
||||
struct scsi_mode_page *mp,
|
||||
int hdr_size)
|
||||
{
|
||||
struct scsi_data *data;
|
||||
|
||||
data = scsi_malloc(task, sizeof(struct scsi_data));
|
||||
|
||||
data->size = 12 + hdr_size;
|
||||
data->data = scsi_malloc(task, data->size);
|
||||
|
||||
data->data[hdr_size + 2] |= (mp->control.tst << 5) & 0xe0;
|
||||
if (mp->control.tmf_only) data->data[hdr_size + 2] |= 0x10;
|
||||
if (mp->control.dpicz) data->data[hdr_size + 2] |= 0x08;
|
||||
if (mp->control.d_sense) data->data[hdr_size + 2] |= 0x04;
|
||||
if (mp->control.gltsd) data->data[hdr_size + 2] |= 0x02;
|
||||
if (mp->control.rlec) data->data[hdr_size + 2] |= 0x01;
|
||||
|
||||
data->data[hdr_size + 3] |= (mp->control.queue_algorithm_modifier << 4) & 0xf0;
|
||||
if (mp->control.nuar) data->data[hdr_size + 3] |= 0x08;
|
||||
data->data[hdr_size + 3] |= (mp->control.qerr << 1) & 0x06;
|
||||
|
||||
if (mp->control.vs) data->data[hdr_size + 4] |= 0x80;
|
||||
if (mp->control.rac) data->data[hdr_size + 4] |= 0x40;
|
||||
data->data[hdr_size + 4] |= (mp->control.ua_intlck_ctrl << 4) & 0x30;
|
||||
if (mp->control.swp) data->data[hdr_size + 4] |= 0x08;
|
||||
|
||||
if (mp->control.ato) data->data[hdr_size + 5] |= 0x80;
|
||||
if (mp->control.tas) data->data[hdr_size + 5] |= 0x40;
|
||||
if (mp->control.atmpe) data->data[hdr_size + 5] |= 0x20;
|
||||
if (mp->control.rwwp) data->data[hdr_size + 5] |= 0x10;
|
||||
data->data[hdr_size + 5] |= mp->control.autoload_mode & 0x07;
|
||||
|
||||
scsi_set_uint16(&data->data[hdr_size + 8], mp->control.busy_timeout_period);
|
||||
scsi_set_uint16(&data->data[hdr_size + 10], mp->control.extended_selftest_completion_time);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
static struct scsi_data *
|
||||
scsi_modesense_marshall_disconnect_reconnect(struct scsi_task *task,
|
||||
struct scsi_mode_page *mp,
|
||||
int hdr_size)
|
||||
{
|
||||
struct scsi_data *data;
|
||||
|
||||
data = scsi_malloc(task, sizeof(struct scsi_data));
|
||||
|
||||
data->size = 16 + hdr_size;
|
||||
data->data = scsi_malloc(task, data->size);
|
||||
|
||||
data->data[hdr_size + 2] = mp->disconnect_reconnect.buffer_full_ratio;
|
||||
data->data[hdr_size + 3] = mp->disconnect_reconnect.buffer_empty_ratio;
|
||||
scsi_set_uint16(&data->data[hdr_size + 4], mp->disconnect_reconnect.bus_inactivity_limit);
|
||||
scsi_set_uint16(&data->data[hdr_size + 6], mp->disconnect_reconnect.disconnect_time_limit);
|
||||
scsi_set_uint16(&data->data[hdr_size + 8], mp->disconnect_reconnect.connect_time_limit);
|
||||
scsi_set_uint16(&data->data[hdr_size + 10], mp->disconnect_reconnect.maximum_burst_size);
|
||||
|
||||
if (mp->disconnect_reconnect.emdp) data->data[hdr_size + 12] |= 0x80;
|
||||
data->data[hdr_size + 12] |= (mp->disconnect_reconnect.fair_arbitration << 4) & 0x70;
|
||||
if (mp->disconnect_reconnect.dimm) data->data[hdr_size + 12] |= 0x08;
|
||||
data->data[hdr_size + 12] |= mp->disconnect_reconnect.dtdc & 0x07;
|
||||
|
||||
scsi_set_uint16(&data->data[hdr_size + 14], mp->disconnect_reconnect.first_burst_size);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
static struct scsi_data *
|
||||
scsi_modesense_marshall_informational_exceptions_control(struct scsi_task *task,
|
||||
struct scsi_mode_page *mp,
|
||||
int hdr_size)
|
||||
{
|
||||
struct scsi_data *data;
|
||||
|
||||
data = scsi_malloc(task, sizeof(struct scsi_data));
|
||||
|
||||
data->size = 12 + hdr_size;
|
||||
data->data = scsi_malloc(task, data->size);
|
||||
|
||||
if (mp->iec.perf) data->data[hdr_size + 2] |= 0x80;
|
||||
if (mp->iec.ebf) data->data[hdr_size + 2] |= 0x20;
|
||||
if (mp->iec.ewasc) data->data[hdr_size + 2] |= 0x10;
|
||||
if (mp->iec.dexcpt) data->data[hdr_size + 2] |= 0x08;
|
||||
if (mp->iec.test) data->data[hdr_size + 2] |= 0x04;
|
||||
if (mp->iec.ebackerr) data->data[hdr_size + 2] |= 0x02;
|
||||
if (mp->iec.logerr) data->data[hdr_size + 2] |= 0x01;
|
||||
|
||||
data->data[hdr_size + 3] |= mp->iec.mrie & 0x0f;
|
||||
|
||||
scsi_set_uint32(&data->data[hdr_size + 4], mp->iec.interval_timer);
|
||||
scsi_set_uint32(&data->data[hdr_size + 8], mp->iec.report_count);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/*
|
||||
* marshall the mode sense data out buffer
|
||||
*/
|
||||
struct scsi_data *
|
||||
scsi_modesense_dataout_marshall(struct scsi_task *task,
|
||||
struct scsi_mode_page *mp,
|
||||
int is_modeselect6)
|
||||
{
|
||||
struct scsi_data *data;
|
||||
int hdr_size = is_modeselect6 ? 4 : 8;
|
||||
|
||||
switch (mp->page_code) {
|
||||
case SCSI_MODESENSE_PAGECODE_CACHING:
|
||||
data = scsi_modesense_marshall_caching(task, mp, hdr_size);
|
||||
break;
|
||||
case SCSI_MODESENSE_PAGECODE_CONTROL:
|
||||
data = scsi_modesense_marshall_control(task, mp, hdr_size);
|
||||
break;
|
||||
case SCSI_MODESENSE_PAGECODE_DISCONNECT_RECONNECT:
|
||||
data = scsi_modesense_marshall_disconnect_reconnect(task, mp, hdr_size);
|
||||
break;
|
||||
case SCSI_MODESENSE_PAGECODE_INFORMATIONAL_EXCEPTIONS_CONTROL:
|
||||
data = scsi_modesense_marshall_informational_exceptions_control(task, mp, hdr_size);
|
||||
break;
|
||||
default:
|
||||
/* TODO error reporting ? */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (data == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (is_modeselect6) {
|
||||
data->data[0] = data->size - 1;
|
||||
} else {
|
||||
data->data[0] = (data->size - 2) >> 8;
|
||||
data->data[1] = (data->size - 2) & 0xff;
|
||||
}
|
||||
|
||||
|
||||
data->data[hdr_size + 0] = mp->page_code & 0x3f;
|
||||
if (mp->ps) {
|
||||
data->data[hdr_size + 0] |= 0x80;
|
||||
}
|
||||
if (mp->spf) {
|
||||
data->data[hdr_size + 0] |= 0x40;
|
||||
data->data[hdr_size + 1] = mp->subpage_code;
|
||||
scsi_set_uint16(&data->data[hdr_size + 2], data->size -hdr_size - 4);
|
||||
} else {
|
||||
data->data[hdr_size + 1] = (data->size - hdr_size - 2) & 0xff;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* STARTSTOPUNIT
|
||||
*/
|
||||
|
||||
20
lib/sync.c
20
lib/sync.c
@@ -1156,6 +1156,26 @@ iscsi_scsi_command_sync(struct iscsi_context *iscsi, int lun,
|
||||
}
|
||||
|
||||
|
||||
struct scsi_task *
|
||||
iscsi_modeselect6_sync(struct iscsi_context *iscsi, int lun,
|
||||
int pf, int sp, struct scsi_mode_page *mp)
|
||||
{
|
||||
struct iscsi_sync_state state;
|
||||
|
||||
memset(&state, 0, sizeof(state));
|
||||
|
||||
if (iscsi_modeselect6_task(iscsi, lun, pf, sp, mp,
|
||||
scsi_sync_cb, &state) == NULL) {
|
||||
iscsi_set_error(iscsi,
|
||||
"Failed to send MODE_SELECT6 command");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
event_loop(iscsi, &state);
|
||||
|
||||
return state.task;
|
||||
}
|
||||
|
||||
struct scsi_task *
|
||||
iscsi_modesense6_sync(struct iscsi_context *iscsi, int lun, int dbd,
|
||||
int pc, int page_code, int sub_page_code,
|
||||
|
||||
Reference in New Issue
Block a user