From 008c25ebb9af3085b497eaa487de27d83b88ea45 Mon Sep 17 00:00:00 2001 From: Sepherosa Ziehau Date: Thu, 12 May 2016 03:29:29 +0000 Subject: [PATCH] hyperv/stor: Enable INQUIRY result check only on WIN10 like host systems On WIN8 like host systems, when rescan happens, the already installed disks seem to return random invalid results for INQUIRY. More investigation is under way to figure out why random invalid INQUIRY results are delivered to VM on WIN8 like host systems. Submitted by: Hongjiang Zhang Reviewed by: sephe MFC after: 1 week Sponsored by: Microsoft OSTC Differential Revision: https://reviews.freebsd.org/D6316 --- .../hyperv/storvsc/hv_storvsc_drv_freebsd.c | 130 ++++++++++++------ sys/dev/hyperv/storvsc/hv_vstorage.h | 5 + 2 files changed, 90 insertions(+), 45 deletions(-) diff --git a/sys/dev/hyperv/storvsc/hv_storvsc_drv_freebsd.c b/sys/dev/hyperv/storvsc/hv_storvsc_drv_freebsd.c index 04574867e686..f0f07332592c 100644 --- a/sys/dev/hyperv/storvsc/hv_storvsc_drv_freebsd.c +++ b/sys/dev/hyperv/storvsc/hv_storvsc_drv_freebsd.c @@ -81,12 +81,6 @@ __FBSDID("$FreeBSD$"); #define BLKVSC_MAX_IO_REQUESTS STORVSC_MAX_IO_REQUESTS #define STORVSC_MAX_TARGETS (2) -#define STORVSC_WIN7_MAJOR 4 -#define STORVSC_WIN7_MINOR 2 - -#define STORVSC_WIN8_MAJOR 5 -#define STORVSC_WIN8_MINOR 1 - #define VSTOR_PKT_SIZE (sizeof(struct vstor_packet) - vmscsi_size_delta) #define HV_ALIGN(x, a) roundup2(x, a) @@ -207,7 +201,7 @@ static struct storvsc_driver_props g_drv_props_table[] = { * Sense buffer size changed in win8; have a run-time * variable to track the size we should use. */ -static int sense_buffer_size; +static int sense_buffer_size = PRE_WIN8_STORVSC_SENSE_BUFFER_SIZE; /* * The size of the vmscsi_request has changed in win8. The @@ -217,9 +211,46 @@ static int sense_buffer_size; * Track the correct size we need to apply. */ static int vmscsi_size_delta; +/* + * The storage protocol version is determined during the + * initial exchange with the host. It will indicate which + * storage functionality is available in the host. +*/ +static int vmstor_proto_version; -static int storvsc_current_major; -static int storvsc_current_minor; +struct vmstor_proto { + int proto_version; + int sense_buffer_size; + int vmscsi_size_delta; +}; + +static const struct vmstor_proto vmstor_proto_list[] = { + { + VMSTOR_PROTOCOL_VERSION_WIN10, + POST_WIN7_STORVSC_SENSE_BUFFER_SIZE, + 0 + }, + { + VMSTOR_PROTOCOL_VERSION_WIN8_1, + POST_WIN7_STORVSC_SENSE_BUFFER_SIZE, + 0 + }, + { + VMSTOR_PROTOCOL_VERSION_WIN8, + POST_WIN7_STORVSC_SENSE_BUFFER_SIZE, + 0 + }, + { + VMSTOR_PROTOCOL_VERSION_WIN7, + PRE_WIN8_STORVSC_SENSE_BUFFER_SIZE, + sizeof(struct vmscsi_win8_extension), + }, + { + VMSTOR_PROTOCOL_VERSION_WIN6, + PRE_WIN8_STORVSC_SENSE_BUFFER_SIZE, + sizeof(struct vmscsi_win8_extension), + } +}; /* static functions */ static int storvsc_probe(device_t dev); @@ -427,7 +458,7 @@ storvsc_send_multichannel_request(struct hv_device *dev, int max_chans) static int hv_storvsc_channel_init(struct hv_device *dev) { - int ret = 0; + int ret = 0, i; struct hv_storvsc_request *request; struct vstor_packet *vstor_packet; struct storvsc_softc *sc; @@ -476,19 +507,20 @@ hv_storvsc_channel_init(struct hv_device *dev) goto cleanup; } - /* reuse the packet for version range supported */ + for (i = 0; i < nitems(vmstor_proto_list); i++) { + /* reuse the packet for version range supported */ - memset(vstor_packet, 0, sizeof(struct vstor_packet)); - vstor_packet->operation = VSTOR_OPERATION_QUERYPROTOCOLVERSION; - vstor_packet->flags = REQUEST_COMPLETION_FLAG; + memset(vstor_packet, 0, sizeof(struct vstor_packet)); + vstor_packet->operation = VSTOR_OPERATION_QUERYPROTOCOLVERSION; + vstor_packet->flags = REQUEST_COMPLETION_FLAG; - vstor_packet->u.version.major_minor = - VMSTOR_PROTOCOL_VERSION(storvsc_current_major, storvsc_current_minor); + vstor_packet->u.version.major_minor = + vmstor_proto_list[i].proto_version; - /* revision is only significant for Windows guests */ - vstor_packet->u.version.revision = 0; + /* revision is only significant for Windows guests */ + vstor_packet->u.version.revision = 0; - ret = hv_vmbus_channel_send_packet( + ret = hv_vmbus_channel_send_packet( dev->channel, vstor_packet, VSTOR_PKT_SIZE, @@ -496,20 +528,34 @@ hv_storvsc_channel_init(struct hv_device *dev) HV_VMBUS_PACKET_TYPE_DATA_IN_BAND, HV_VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); - if (ret != 0) + if (ret != 0) + goto cleanup; + + /* wait 5 seconds */ + ret = sema_timedwait(&request->synch_sema, 5 * hz); + + if (ret) + goto cleanup; + + if (vstor_packet->operation != VSTOR_OPERATION_COMPLETEIO) { + ret = EINVAL; + goto cleanup; + } + if (vstor_packet->status == 0) { + vmstor_proto_version = + vmstor_proto_list[i].proto_version; + sense_buffer_size = + vmstor_proto_list[i].sense_buffer_size; + vmscsi_size_delta = + vmstor_proto_list[i].vmscsi_size_delta; + break; + } + } + + if (vstor_packet->status != 0) { + ret = EINVAL; goto cleanup; - - /* wait 5 seconds */ - ret = sema_timedwait(&request->synch_sema, 5 * hz); - - if (ret) - goto cleanup; - - /* TODO: Check returned version */ - if (vstor_packet->operation != VSTOR_OPERATION_COMPLETEIO || - vstor_packet->status != 0) - goto cleanup; - + } /** * Query channel properties */ @@ -903,19 +949,6 @@ storvsc_probe(device_t dev) int ata_disk_enable = 0; int ret = ENXIO; - if (hv_vmbus_protocal_version == HV_VMBUS_VERSION_WS2008 || - hv_vmbus_protocal_version == HV_VMBUS_VERSION_WIN7) { - sense_buffer_size = PRE_WIN8_STORVSC_SENSE_BUFFER_SIZE; - vmscsi_size_delta = sizeof(struct vmscsi_win8_extension); - storvsc_current_major = STORVSC_WIN7_MAJOR; - storvsc_current_minor = STORVSC_WIN7_MINOR; - } else { - sense_buffer_size = POST_WIN7_STORVSC_SENSE_BUFFER_SIZE; - vmscsi_size_delta = 0; - storvsc_current_major = STORVSC_WIN8_MAJOR; - storvsc_current_minor = STORVSC_WIN8_MINOR; - } - switch (storvsc_get_storage_type(dev)) { case DRIVER_BLKVSC: if(bootverbose) @@ -2048,6 +2081,13 @@ storvsc_io_done(struct hv_storvsc_request *reqp) ((ccb->ccb_h.flags & CAM_CDB_POINTER) ? csio->cdb_io.cdb_ptr : csio->cdb_io.cdb_bytes); if (cmd->opcode == INQUIRY && + /* + * XXX: Temporary work around disk hot plugin on win2k12r2, + * only filtering the invalid disk on win10 or 2016 server. + * So, the hot plugin on win10 and 2016 server needs + * to be fixed. + */ + vmstor_proto_version == VMSTOR_PROTOCOL_VERSION_WIN10 && is_inquiry_valid( (const struct scsi_inquiry_data *)csio->data_ptr) == 0) { ccb->ccb_h.status |= CAM_DEV_NOT_THERE; diff --git a/sys/dev/hyperv/storvsc/hv_vstorage.h b/sys/dev/hyperv/storvsc/hv_vstorage.h index 026189c9ae47..f2b948046361 100644 --- a/sys/dev/hyperv/storvsc/hv_vstorage.h +++ b/sys/dev/hyperv/storvsc/hv_vstorage.h @@ -41,6 +41,11 @@ #define VMSTOR_PROTOCOL_VERSION(MAJOR_, MINOR_) ((((MAJOR_) & 0xff) << 8) | \ (((MINOR_) & 0xff) )) +#define VMSTOR_PROTOCOL_VERSION_WIN6 VMSTOR_PROTOCOL_VERSION(2, 0) +#define VMSTOR_PROTOCOL_VERSION_WIN7 VMSTOR_PROTOCOL_VERSION(4, 2) +#define VMSTOR_PROTOCOL_VERSION_WIN8 VMSTOR_PROTOCOL_VERSION(5, 1) +#define VMSTOR_PROTOCOL_VERSION_WIN8_1 VMSTOR_PROTOCOL_VERSION(6, 0) +#define VMSTOR_PROTOCOL_VERSION_WIN10 VMSTOR_PROTOCOL_VERSION(6, 2) /* * Invalid version. */