From 52a83e91afb2d8e63f02c838c12edcafc6c57e3c Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Sat, 20 Jul 2013 15:35:38 -0700 Subject: [PATCH] Add POWER_CONDITION modepage marshalling/unmarshalling --- examples/iscsiclient.c | 4 +- include/scsi-lowlevel.h | 51 ++++++++++--- lib/scsi-lowlevel.c | 100 +++++++++++++++++++++++--- src/iscsi-swp.c | 4 +- test-tool/0300_readonly.c | 4 +- test-tool/iscsi-support.c | 8 +-- test-tool/iscsi-test-cu.c | 2 +- test-tool/test_modesense6_all_pages.c | 2 +- test-tool/test_modesense6_residuals.c | 4 +- 9 files changed, 149 insertions(+), 30 deletions(-) diff --git a/examples/iscsiclient.c b/examples/iscsiclient.c index caf2002..34838d9 100644 --- a/examples/iscsiclient.c +++ b/examples/iscsiclient.c @@ -342,7 +342,7 @@ void modesense6_cb(struct iscsi_context *iscsi, int status, void *command_data, full_size = scsi_datain_getfullsize(task); if (full_size > task->datain.size) { printf("did not get enough data for mode sense, sening modesense again asking for bigger buffer\n"); - if (iscsi_modesense6_task(iscsi, clnt->lun, 0, SCSI_MODESENSE_PC_CURRENT, SCSI_MODESENSE_PAGECODE_RETURN_ALL_PAGES, 0, full_size, modesense6_cb, private_data) == NULL) { + if (iscsi_modesense6_task(iscsi, clnt->lun, 0, SCSI_MODESENSE_PC_CURRENT, SCSI_MODEPAGE_RETURN_ALL_PAGES, 0, full_size, modesense6_cb, private_data) == NULL) { printf("failed to send modesense6 command\n"); scsi_free_scsi_task(task); exit(10); @@ -391,7 +391,7 @@ void inquiry_cb(struct iscsi_context *iscsi, int status, void *command_data, voi printf("Device Type is %d. VendorId:%s ProductId:%s\n", inq->device_type, inq->vendor_identification, inq->product_identification); printf("Send MODESENSE6\n"); - if (iscsi_modesense6_task(iscsi, clnt->lun, 0, SCSI_MODESENSE_PC_CURRENT, SCSI_MODESENSE_PAGECODE_RETURN_ALL_PAGES, 0, 4, modesense6_cb, private_data) == NULL) { + if (iscsi_modesense6_task(iscsi, clnt->lun, 0, SCSI_MODESENSE_PC_CURRENT, SCSI_MODEPAGE_RETURN_ALL_PAGES, 0, 4, modesense6_cb, private_data) == NULL) { printf("failed to send modesense6 command\n"); scsi_free_scsi_task(task); exit(10); diff --git a/include/scsi-lowlevel.h b/include/scsi-lowlevel.h index 4655443..cdc7057 100644 --- a/include/scsi-lowlevel.h +++ b/include/scsi-lowlevel.h @@ -664,6 +664,26 @@ struct scsi_mode_page_caching { int cache_segment_size; }; +struct scsi_mode_page_power_condition { + int pm_bg_precedence; + int standby_y; + + int idle_c; + int idle_b; + int idle_a; + int standby_z; + + uint32_t idle_a_condition_timer; + uint32_t standby_z_condition_timer; + uint32_t idle_b_condition_timer; + uint32_t idle_c_condition_timer; + uint32_t standby_y_condition_timer; + + int ccf_idle; + int ccf_standby; + int ccf_stopped; +}; + struct scsi_mode_page_control { int tst; int tmf_only; @@ -719,16 +739,30 @@ struct scsi_mode_page_informational_exceptions_control { }; enum scsi_modesense_page_code { - 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_CONTROL = 0x0a, - SCSI_MODESENSE_PAGECODE_INFORMATIONAL_EXCEPTIONS_CONTROL = 0x1c, - SCSI_MODESENSE_PAGECODE_RETURN_ALL_PAGES = 0x3f + SCSI_MODEPAGE_READ_WRITE_ERROR_RECOVERY = 0x01, + SCSI_MODEPAGE_DISCONNECT_RECONNECT = 0x02, + SCSI_MODEPAGE_VERIFY_ERROR_RECOVERY = 0x07, + SCSI_MODEPAGE_CACHING = 0x08, + SCSI_MODEPAGE_XOR_CONTROL = 0x10, + SCSI_MODEPAGE_CONTROL = 0x0a, + SCSI_MODEPAGE_POWER_CONDITION = 0x1a, + SCSI_MODEPAGE_INFORMATIONAL_EXCEPTIONS_CONTROL = 0x1c, + SCSI_MODEPAGE_RETURN_ALL_PAGES = 0x3f }; + +/* Do not use in new code. + * Backward compatibility macros + */ +#define SCSI_MODESENSE_PAGECODE_READ_WRITE_ERROR_RECOVERY SCSI_MODEPAGE_READ_WRITE_ERROR_RECOVERY +#define SCSI_MODESENSE_PAGECODE_DISCONNECT_RECONNECT SCSI_MODEPAGE_DISCONNECT_RECONNECT +#define SCSI_MODESENSE_PAGECODE_VERIFY_ERROR_RECOVERY SCSI_MODEPAGE_VERIFY_ERROR_RECOVERY +#define SCSI_MODESENSE_PAGECODE_CACHING SCSI_MODEPAGE_CACHING +#define SCSI_MODESENSE_PAGECODE_XOR_CONTROL SCSI_MODEPAGE_XOR_CONTROL +#define SCSI_MODESENSE_PAGECODE_CONTROL SCSI_MODEPAGE_CONTROL +#define SCSI_MODESENSE_PAGECODE_INFORMATIONAL_EXCEPTIONS_CONTROL SCSI_MODEPAGE_INFORMATIONAL_EXCEPTIONS_CONTROL +#define SCSI_MODESENSE_PAGECODE_RETURN_ALL_PAGES SCSI_MODEPAGE_RETURN_ALL_PAGES + struct scsi_mode_page { struct scsi_mode_page *next; int ps; @@ -741,6 +775,7 @@ struct scsi_mode_page { struct scsi_mode_page_control control; struct scsi_mode_page_disconnect_reconnect disconnect_reconnect; struct scsi_mode_page_informational_exceptions_control iec; + struct scsi_mode_page_power_condition power_condition; }; }; diff --git a/lib/scsi-lowlevel.c b/lib/scsi-lowlevel.c index 32aa6c0..ac63c14 100644 --- a/lib/scsi-lowlevel.c +++ b/lib/scsi-lowlevel.c @@ -2392,6 +2392,42 @@ scsi_parse_mode_control(struct scsi_task *task, int pos, struct scsi_mode_page * task_get_uint16(task, pos + 8); } +static void +scsi_parse_mode_power_condition(struct scsi_task *task, int pos, struct scsi_mode_page *mp) +{ + mp->power_condition.pm_bg_precedence = + (task_get_uint8(task, pos) >> 6) & 0x03; + mp->power_condition.standby_y = + !!(task_get_uint8(task, pos) & 0x01); + + mp->power_condition.idle_c = + !!(task_get_uint8(task, pos + 1) & 0x08); + mp->power_condition.idle_b = + !!(task_get_uint8(task, pos + 1) & 0x04); + mp->power_condition.idle_a = + !!(task_get_uint8(task, pos + 1) & 0x02); + mp->power_condition.standby_z = + !!(task_get_uint8(task, pos + 1) & 0x01); + + mp->power_condition.idle_a_condition_timer = + task_get_uint32(task, pos + 2); + mp->power_condition.standby_z_condition_timer = + task_get_uint32(task, pos + 6); + mp->power_condition.idle_b_condition_timer = + task_get_uint32(task, pos + 10); + mp->power_condition.idle_c_condition_timer = + task_get_uint32(task, pos + 14); + mp->power_condition.standby_y_condition_timer = + task_get_uint32(task, pos + 18); + + mp->power_condition.ccf_idle = + (task_get_uint8(task, pos + 37) >> 6) & 0x03; + mp->power_condition.ccf_standby = + (task_get_uint8(task, pos + 37) >> 4) & 0x03; + mp->power_condition.ccf_stopped = + (task_get_uint8(task, pos + 37) >> 2) & 0x03; +} + static void scsi_parse_mode_disconnect_reconnect(struct scsi_task *task, int pos, struct scsi_mode_page *mp) { @@ -2503,18 +2539,21 @@ scsi_modesense_datain_unmarshall(struct scsi_task *task, int is_modesense6) } switch (mp->page_code) { - case SCSI_MODESENSE_PAGECODE_CACHING: + case SCSI_MODEPAGE_CACHING: scsi_parse_mode_caching(task, pos, mp); break; - case SCSI_MODESENSE_PAGECODE_CONTROL: + case SCSI_MODEPAGE_CONTROL: scsi_parse_mode_control(task, pos, mp); break; - case SCSI_MODESENSE_PAGECODE_DISCONNECT_RECONNECT: + case SCSI_MODEPAGE_DISCONNECT_RECONNECT: scsi_parse_mode_disconnect_reconnect(task, pos, mp); break; - case SCSI_MODESENSE_PAGECODE_INFORMATIONAL_EXCEPTIONS_CONTROL: + case SCSI_MODEPAGE_INFORMATIONAL_EXCEPTIONS_CONTROL: scsi_parse_mode_informational_exceptions_control(task, pos, mp); break; + case SCSI_MODEPAGE_POWER_CONDITION: + scsi_parse_mode_power_condition(task, pos, mp); + break; default: /* TODO: process other pages, or add raw data to struct * scsi_mode_page. */ @@ -2611,6 +2650,48 @@ scsi_modesense_marshall_control(struct scsi_task *task, return data; } +static struct scsi_data * +scsi_modesense_marshall_power_condition(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 = 40 + hdr_size; + data->data = scsi_malloc(task, data->size); + + data->data[hdr_size + 2] |= + (mp->power_condition.pm_bg_precedence << 6) & 0xc0; + if (mp->power_condition.standby_y) data->data[hdr_size + 2] |= 0x01; + + if (mp->power_condition.idle_c) data->data[hdr_size + 3] |= 0x08; + if (mp->power_condition.idle_b) data->data[hdr_size + 3] |= 0x04; + if (mp->power_condition.idle_a) data->data[hdr_size + 3] |= 0x02; + if (mp->power_condition.standby_z) data->data[hdr_size + 3] |= 0x01; + + scsi_set_uint32(&data->data[hdr_size + 4], + mp->power_condition.idle_a_condition_timer); + scsi_set_uint32(&data->data[hdr_size + 8], + mp->power_condition.standby_z_condition_timer); + scsi_set_uint32(&data->data[hdr_size + 12], + mp->power_condition.idle_b_condition_timer); + scsi_set_uint32(&data->data[hdr_size + 16], + mp->power_condition.idle_c_condition_timer); + scsi_set_uint32(&data->data[hdr_size + 20], + mp->power_condition.standby_y_condition_timer); + + data->data[hdr_size + 39] |= + (mp->power_condition.ccf_idle << 6) & 0xc0; + data->data[hdr_size + 39] |= + (mp->power_condition.ccf_standby << 4) & 0x30; + data->data[hdr_size + 39] |= + (mp->power_condition.ccf_stopped << 2) & 0x0c; + + return data; +} + static struct scsi_data * scsi_modesense_marshall_disconnect_reconnect(struct scsi_task *task, struct scsi_mode_page *mp, @@ -2680,18 +2761,21 @@ scsi_modesense_dataout_marshall(struct scsi_task *task, int hdr_size = is_modeselect6 ? 4 : 8; switch (mp->page_code) { - case SCSI_MODESENSE_PAGECODE_CACHING: + case SCSI_MODEPAGE_CACHING: data = scsi_modesense_marshall_caching(task, mp, hdr_size); break; - case SCSI_MODESENSE_PAGECODE_CONTROL: + case SCSI_MODEPAGE_CONTROL: data = scsi_modesense_marshall_control(task, mp, hdr_size); break; - case SCSI_MODESENSE_PAGECODE_DISCONNECT_RECONNECT: + case SCSI_MODEPAGE_DISCONNECT_RECONNECT: data = scsi_modesense_marshall_disconnect_reconnect(task, mp, hdr_size); break; - case SCSI_MODESENSE_PAGECODE_INFORMATIONAL_EXCEPTIONS_CONTROL: + case SCSI_MODEPAGE_INFORMATIONAL_EXCEPTIONS_CONTROL: data = scsi_modesense_marshall_informational_exceptions_control(task, mp, hdr_size); break; + case SCSI_MODEPAGE_POWER_CONDITION: + data = scsi_modesense_marshall_power_condition(task, mp, hdr_size); + break; default: /* TODO error reporting ? */ return NULL; diff --git a/src/iscsi-swp.c b/src/iscsi-swp.c index c98ee6c..0a47bb3 100644 --- a/src/iscsi-swp.c +++ b/src/iscsi-swp.c @@ -179,7 +179,7 @@ int main(int argc, char *argv[]) sense_task = iscsi_modesense10_sync(iscsi, iscsi_url->lun, 0, 1, SCSI_MODESENSE_PC_CURRENT, - SCSI_MODESENSE_PAGECODE_CONTROL, + SCSI_MODEPAGE_CONTROL, 0, 255); if (sense_task == NULL) { printf("Failed to send MODE_SENSE10 command: %s\n", @@ -199,7 +199,7 @@ int main(int argc, char *argv[]) ret = 10; goto finished; } - mp = scsi_modesense_get_page(ms, SCSI_MODESENSE_PAGECODE_CONTROL, 0); + mp = scsi_modesense_get_page(ms, SCSI_MODEPAGE_CONTROL, 0); if (mp == NULL) { printf("failed to read control mode page\n"); ret = 10; diff --git a/test-tool/0300_readonly.c b/test-tool/0300_readonly.c index e2b0bb3..f21f001 100644 --- a/test-tool/0300_readonly.c +++ b/test-tool/0300_readonly.c @@ -72,7 +72,7 @@ int T0300_readonly(const char *initiator, const char *url) /* verify the device is readonly */ task = iscsi_modesense6_sync(iscsi, lun, 0, SCSI_MODESENSE_PC_CURRENT, - SCSI_MODESENSE_PAGECODE_RETURN_ALL_PAGES, 0, + SCSI_MODEPAGE_RETURN_ALL_PAGES, 0, 4); if (task == NULL) { printf("Failed to send modesense6 command: %s\n", iscsi_get_error(iscsi)); @@ -82,7 +82,7 @@ int T0300_readonly(const char *initiator, const char *url) if (full_size > task->datain.size) { scsi_free_scsi_task(task); task = iscsi_modesense6_sync(iscsi, lun, 0, SCSI_MODESENSE_PC_CURRENT, - SCSI_MODESENSE_PAGECODE_RETURN_ALL_PAGES, 0, + SCSI_MODEPAGE_RETURN_ALL_PAGES, 0, full_size); if (task == NULL) { printf("Failed to send modesense6 command: %s\n", iscsi_get_error(iscsi)); diff --git a/test-tool/iscsi-support.c b/test-tool/iscsi-support.c index ec33929..d837fce 100644 --- a/test-tool/iscsi-support.c +++ b/test-tool/iscsi-support.c @@ -6028,7 +6028,7 @@ int set_swp(struct iscsi_context *iscsi, int lun) logging(LOG_VERBOSE, "Read CONTROL page"); sense_task = iscsi_modesense6_sync(iscsi, lun, 1, SCSI_MODESENSE_PC_CURRENT, - SCSI_MODESENSE_PAGECODE_CONTROL, + SCSI_MODEPAGE_CONTROL, 0, 255); if (sense_task == NULL) { logging(LOG_NORMAL, "Failed to send MODE_SENSE6 command: %s", @@ -6049,7 +6049,7 @@ int set_swp(struct iscsi_context *iscsi, int lun) ret = -1; goto finished; } - mp = scsi_modesense_get_page(ms, SCSI_MODESENSE_PAGECODE_CONTROL, 0); + mp = scsi_modesense_get_page(ms, SCSI_MODEPAGE_CONTROL, 0); if (mp == NULL) { logging(LOG_NORMAL, "failed to read control mode page"); ret = -1; @@ -6095,7 +6095,7 @@ int clear_swp(struct iscsi_context *iscsi, int lun) logging(LOG_VERBOSE, "Read CONTROL page"); sense_task = iscsi_modesense6_sync(iscsi, lun, 1, SCSI_MODESENSE_PC_CURRENT, - SCSI_MODESENSE_PAGECODE_CONTROL, + SCSI_MODEPAGE_CONTROL, 0, 255); if (sense_task == NULL) { logging(LOG_NORMAL, "Failed to send MODE_SENSE6 command: %s", @@ -6116,7 +6116,7 @@ int clear_swp(struct iscsi_context *iscsi, int lun) ret = -1; goto finished; } - mp = scsi_modesense_get_page(ms, SCSI_MODESENSE_PAGECODE_CONTROL, 0); + mp = scsi_modesense_get_page(ms, SCSI_MODEPAGE_CONTROL, 0); if (mp == NULL) { logging(LOG_NORMAL, "failed to read control mode page"); ret = -1; diff --git a/test-tool/iscsi-test-cu.c b/test-tool/iscsi-test-cu.c index 868c258..25ec827 100644 --- a/test-tool/iscsi-test-cu.c +++ b/test-tool/iscsi-test-cu.c @@ -1185,7 +1185,7 @@ main(int argc, char *argv[]) /* check if the device is write protected or not */ task = iscsi_modesense6_sync(iscsic, lun, 0, SCSI_MODESENSE_PC_CURRENT, - SCSI_MODESENSE_PAGECODE_RETURN_ALL_PAGES, + SCSI_MODEPAGE_RETURN_ALL_PAGES, 0, 255); if (task == NULL) { printf("Failed to send MODE_SENSE6 command: %s\n", diff --git a/test-tool/test_modesense6_all_pages.c b/test-tool/test_modesense6_all_pages.c index 9e0e1d8..7c96141 100644 --- a/test-tool/test_modesense6_all_pages.c +++ b/test-tool/test_modesense6_all_pages.c @@ -41,7 +41,7 @@ test_modesense6_all_pages(void) logging(LOG_VERBOSE, "Send MODESENSE6 command to fetch AllPages"); task = iscsi_modesense6_sync(iscsic, tgt_lun, 0, SCSI_MODESENSE_PC_CURRENT, - SCSI_MODESENSE_PAGECODE_RETURN_ALL_PAGES, + SCSI_MODEPAGE_RETURN_ALL_PAGES, 0, 255); if (task == NULL || task->status != SCSI_STATUS_GOOD) { logging(LOG_VERBOSE, "[FAILED] Failed to send MODE_SENSE6 " diff --git a/test-tool/test_modesense6_residuals.c b/test-tool/test_modesense6_residuals.c index 57fda6c..8124082 100644 --- a/test-tool/test_modesense6_residuals.c +++ b/test-tool/test_modesense6_residuals.c @@ -42,7 +42,7 @@ test_modesense6_residuals(void) } task = iscsi_modesense6_sync(iscsic, tgt_lun, 0, SCSI_MODESENSE_PC_CURRENT, - SCSI_MODESENSE_PAGECODE_RETURN_ALL_PAGES, + SCSI_MODEPAGE_RETURN_ALL_PAGES, 0, 4); if (task == NULL || task->status != SCSI_STATUS_GOOD) { logging(LOG_VERBOSE, "[FAILED] Failed to send MODE_SENSE6 " @@ -82,7 +82,7 @@ test_modesense6_residuals(void) } task = iscsi_modesense6_sync(iscsic, tgt_lun, 0, SCSI_MODESENSE_PC_CURRENT, - SCSI_MODESENSE_PAGECODE_RETURN_ALL_PAGES, + SCSI_MODEPAGE_RETURN_ALL_PAGES, 0, 255); if (task == NULL || task->status != SCSI_STATUS_GOOD) { logging(LOG_VERBOSE, "[FAILED] Failed to send MODE_SENSE6 "