From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:40977) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ZyKu1-000638-PW for qemu-devel@nongnu.org; Mon, 16 Nov 2015 09:37:07 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1ZyKtx-0003es-O9 for qemu-devel@nongnu.org; Mon, 16 Nov 2015 09:37:05 -0500 Received: from mx2.suse.de ([195.135.220.15]:58461) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ZyKtx-0003eT-Fm for qemu-devel@nongnu.org; Mon, 16 Nov 2015 09:37:01 -0500 From: Hannes Reinecke Date: Mon, 16 Nov 2015 15:36:57 +0100 Message-Id: <1447684618-17794-3-git-send-email-hare@suse.de> In-Reply-To: <1447684618-17794-1-git-send-email-hare@suse.de> References: <1447684618-17794-1-git-send-email-hare@suse.de> Subject: [Qemu-devel] [PATCH 2/3] scsi-disk: Add 'alua_state' property List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: Paolo Bonzini Cc: Johannes Thumshirn , qemu-devel@nongnu.org, Alexander Graf , Hannes Reinecke To support asymmetric logical unit access (ALUA) we need to store the ALUA state in the device structure. Signed-off-by: Hannes Reinecke --- hw/scsi/scsi-bus.c | 15 +++++++++++ hw/scsi/scsi-disk.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++ include/block/scsi.h | 13 +++++++++ include/hw/scsi/scsi.h | 6 +++++ 4 files changed, 106 insertions(+) diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c index fd1171e..2096f4c 100644 --- a/hw/scsi/scsi-bus.c +++ b/hw/scsi/scsi-bus.c @@ -1294,6 +1294,21 @@ const struct SCSISense sense_code_LUN_NOT_READY = { .key = NOT_READY, .asc = 0x04, .ascq = 0x03 }; +/* LUN not ready, asymmetric access state transition */ +const struct SCSISense sense_code_STATE_TRANSITION = { + .key = NOT_READY, .asc = 0x04, .ascq = 0x0a +}; + +/* LUN not ready, target port in standby state */ +const struct SCSISense sense_code_STATE_STANDBY = { + .key = NOT_READY, .asc = 0x04, .ascq = 0x0b +}; + +/* LUN not ready, target port in unavailable state */ +const struct SCSISense sense_code_STATE_UNAVAILABLE = { + .key = NOT_READY, .asc = 0x04, .ascq = 0x0c +}; + /* LUN not ready, Medium not present */ const struct SCSISense sense_code_NO_MEDIUM = { .key = NOT_READY, .asc = 0x3a, .ascq = 0x00 diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c index f544f43..fbd30f3 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c @@ -80,6 +80,7 @@ struct SCSIDiskState uint64_t port_wwn; uint16_t port_index; uint16_t port_group; + uint8_t alua_state; uint64_t max_unmap_size; uint64_t max_io_size; QEMUBH *bh; @@ -1890,6 +1891,60 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf) break; } + if (s->alua_state != ALUA_STATE_ACTIVE_OPTIMIZED && + s->alua_state != ALUA_STATE_ACTIVE_NON_OPTIMIZED) { + bool standby_allowed = true; + bool unavailable_allowed = true; + bool transition_allowed = true; + + switch(req->cmd.buf[0]) { + case MAINTENANCE_IN: + if ((req->cmd.buf[1] & 31) != MI_REPORT_TARGET_PORT_GROUPS) { + transition_allowed = false; + unavailable_allowed = false; + standby_allowed = false; + } + /* Fallthrough */ + case INQUIRY: + case REPORT_LUNS: + case REQUEST_SENSE: + break; + case MAINTENANCE_OUT: + transition_allowed = false; + break; + case PERSISTENT_RESERVE_IN: + case PERSISTENT_RESERVE_OUT: + case LOG_SENSE: + case LOG_SELECT: + case MODE_SENSE: + case MODE_SENSE_10: + case MODE_SELECT: + case MODE_SELECT_10: + case RECEIVE_DIAGNOSTIC: + case SEND_DIAGNOSTIC: + transition_allowed = false; + unavailable_allowed = false; + break; + default: + transition_allowed = false; + unavailable_allowed = false; + standby_allowed = false; + break; + } + if (s->alua_state == ALUA_STATE_STANDBY && !standby_allowed) { + scsi_check_condition(r, SENSE_CODE(STATE_STANDBY)); + return 0; + } + if (s->alua_state == ALUA_STATE_UNAVAILABLE && !unavailable_allowed) { + scsi_check_condition(r, SENSE_CODE(STATE_UNAVAILABLE)); + return 0; + } + if (s->alua_state == ALUA_STATE_TRANSITION && !transition_allowed) { + scsi_check_condition(r, SENSE_CODE(STATE_TRANSITION)); + return 0; + } + } + /* * FIXME: we shouldn't return anything bigger than 4k, but the code * requires the buffer to be as big as req->cmd.xfer in several @@ -2156,6 +2211,21 @@ static int32_t scsi_disk_dma_command(SCSIRequest *req, uint8_t *buf) return 0; } + switch (s->alua_state) { + case ALUA_STATE_ACTIVE_OPTIMIZED: + case ALUA_STATE_ACTIVE_NON_OPTIMIZED: + break; + case ALUA_STATE_STANDBY: + scsi_check_condition(r, SENSE_CODE(STATE_STANDBY)); + return 0; + case ALUA_STATE_UNAVAILABLE: + scsi_check_condition(r, SENSE_CODE(STATE_UNAVAILABLE)); + return 0; + case ALUA_STATE_TRANSITION: + scsi_check_condition(r, SENSE_CODE(STATE_TRANSITION)); + return 0; + } + len = scsi_data_cdb_xfer(r->req.cmd.buf); switch (command) { case READ_6: @@ -2680,6 +2750,7 @@ static Property scsi_hd_properties[] = { DEFINE_PROP_UINT64("port_wwn", SCSIDiskState, port_wwn, 0), DEFINE_PROP_UINT16("port_index", SCSIDiskState, port_index, 0), DEFINE_PROP_UINT16("port_group", SCSIDiskState, port_group, 0), + DEFINE_PROP_UINT8("alua_state", SCSIDiskState, alua_state, 0), DEFINE_PROP_UINT64("max_unmap_size", SCSIDiskState, max_unmap_size, DEFAULT_MAX_UNMAP_SIZE), DEFINE_PROP_UINT64("max_io_size", SCSIDiskState, max_io_size, @@ -2797,6 +2868,7 @@ static Property scsi_disk_properties[] = { DEFINE_PROP_UINT64("port_wwn", SCSIDiskState, port_wwn, 0), DEFINE_PROP_UINT16("port_index", SCSIDiskState, port_index, 0), DEFINE_PROP_UINT16("port_group", SCSIDiskState, port_group, 0), + DEFINE_PROP_UINT8("alua_state", SCSIDiskState, alua_state, 0), DEFINE_PROP_UINT64("max_unmap_size", SCSIDiskState, max_unmap_size, DEFAULT_MAX_UNMAP_SIZE), DEFINE_PROP_UINT64("max_io_size", SCSIDiskState, max_io_size, diff --git a/include/block/scsi.h b/include/block/scsi.h index a311341..a9d0f64 100644 --- a/include/block/scsi.h +++ b/include/block/scsi.h @@ -151,6 +151,11 @@ const char *scsi_command_name(uint8_t cmd); #define SAI_READ_CAPACITY_16 0x10 /* + * MAINTENANCE IN subcodes + */ +#define MI_REPORT_TARGET_PORT_GROUPS 0xa + +/* * READ POSITION service action codes */ #define SHORT_FORM_BLOCK_ID 0x00 @@ -306,4 +311,12 @@ const char *scsi_command_name(uint8_t cmd); #define MMC_PROFILE_HDDVD_RW_DL 0x005A #define MMC_PROFILE_INVALID 0xFFFF +#define ALUA_STATE_ACTIVE_OPTIMIZED 0x0 +#define ALUA_STATE_ACTIVE_NON_OPTIMIZED 0x1 +#define ALUA_STATE_STANDBY 0x2 +#define ALUA_STATE_UNAVAILABLE 0x3 +#define ALUA_STATE_LBA_DEPENDENT 0x4 +#define ALUA_STATE_OFFLINE 0xE +#define ALUA_STATE_TRANSITION 0xF + #endif diff --git a/include/hw/scsi/scsi.h b/include/hw/scsi/scsi.h index cdaf0f8..1574862 100644 --- a/include/hw/scsi/scsi.h +++ b/include/hw/scsi/scsi.h @@ -185,6 +185,12 @@ void scsi_bus_legacy_handle_cmdline(SCSIBus *bus, Error **errp); extern const struct SCSISense sense_code_NO_SENSE; /* LUN not ready, Manual intervention required */ extern const struct SCSISense sense_code_LUN_NOT_READY; +/* LUN not ready, asymmetric access state transition */ +extern const struct SCSISense sense_code_STATE_TRANSITION; +/* LUN not ready, Target Port in standby state */ +extern const struct SCSISense sense_code_STATE_STANDBY; +/* LUN not ready, Target Port in unavailable state */ +extern const struct SCSISense sense_code_STATE_UNAVAILABLE; /* LUN not ready, Medium not present */ extern const struct SCSISense sense_code_NO_MEDIUM; /* LUN not ready, medium removal prevented */ -- 1.8.4.5