@ -55,10 +55,15 @@
* V1 RC < 2008 / 1 / 31 : 1.0
* V1 RC > 2008 / 1 / 31 : 2.0
* Win7 : 4.2
* Win8 : 5.1
*/
# define VMSTOR_CURRENT_MAJOR 4
# define VMSTOR_CURRENT_MINOR 2
# define VMSTOR_WIN7_MAJOR 4
# define VMSTOR_WIN7_MINOR 2
# define VMSTOR_WIN8_MAJOR 5
# define VMSTOR_WIN8_MINOR 1
/* Packet structure describing virtual storage requests. */
@ -74,18 +79,103 @@ enum vstor_packet_operation {
VSTOR_OPERATION_QUERY_PROTOCOL_VERSION = 9 ,
VSTOR_OPERATION_QUERY_PROPERTIES = 10 ,
VSTOR_OPERATION_ENUMERATE_BUS = 11 ,
VSTOR_OPERATION_MAXIMUM = 11
VSTOR_OPERATION_FCHBA_DATA = 12 ,
VSTOR_OPERATION_CREATE_SUB_CHANNELS = 13 ,
VSTOR_OPERATION_MAXIMUM = 13
} ;
/*
* WWN packet for Fibre Channel HBA
*/
struct hv_fc_wwn_packet {
bool primary_active ;
u8 reserved1 ;
u8 reserved2 ;
u8 primary_port_wwn [ 8 ] ;
u8 primary_node_wwn [ 8 ] ;
u8 secondary_port_wwn [ 8 ] ;
u8 secondary_node_wwn [ 8 ] ;
} ;
/*
* SRB Flag Bits
*/
# define SRB_FLAGS_QUEUE_ACTION_ENABLE 0x00000002
# define SRB_FLAGS_DISABLE_DISCONNECT 0x00000004
# define SRB_FLAGS_DISABLE_SYNCH_TRANSFER 0x00000008
# define SRB_FLAGS_BYPASS_FROZEN_QUEUE 0x00000010
# define SRB_FLAGS_DISABLE_AUTOSENSE 0x00000020
# define SRB_FLAGS_DATA_IN 0x00000040
# define SRB_FLAGS_DATA_OUT 0x00000080
# define SRB_FLAGS_NO_DATA_TRANSFER 0x00000000
# define SRB_FLAGS_UNSPECIFIED_DIRECTION (SRB_FLAGS_DATA_IN | SRB_FLAGS_DATA_OUT)
# define SRB_FLAGS_NO_QUEUE_FREEZE 0x00000100
# define SRB_FLAGS_ADAPTER_CACHE_ENABLE 0x00000200
# define SRB_FLAGS_FREE_SENSE_BUFFER 0x00000400
/*
* This flag indicates the request is part of the workflow for processing a D3 .
*/
# define SRB_FLAGS_D3_PROCESSING 0x00000800
# define SRB_FLAGS_IS_ACTIVE 0x00010000
# define SRB_FLAGS_ALLOCATED_FROM_ZONE 0x00020000
# define SRB_FLAGS_SGLIST_FROM_POOL 0x00040000
# define SRB_FLAGS_BYPASS_LOCKED_QUEUE 0x00080000
# define SRB_FLAGS_NO_KEEP_AWAKE 0x00100000
# define SRB_FLAGS_PORT_DRIVER_ALLOCSENSE 0x00200000
# define SRB_FLAGS_PORT_DRIVER_SENSEHASPORT 0x00400000
# define SRB_FLAGS_DONT_START_NEXT_PACKET 0x00800000
# define SRB_FLAGS_PORT_DRIVER_RESERVED 0x0F000000
# define SRB_FLAGS_CLASS_DRIVER_RESERVED 0xF0000000
/*
* Platform neutral description of a scsi request -
* this remains the same across the write regardless of 32 / 64 bit
* note : it ' s patterned off the SCSI_PASS_THROUGH structure
*/
# define STORVSC_MAX_CMD_LEN 0x10
# define STORVSC_SENSE_BUFFER_SIZE 0x12
# define POST_WIN7_STORVSC_SENSE_BUFFER_SIZE 0x14
# define PRE_WIN8_STORVSC_SENSE_BUFFER_SIZE 0x12
# define STORVSC_SENSE_BUFFER_SIZE 0x14
# define STORVSC_MAX_BUF_LEN_WITH_PADDING 0x14
/*
* Sense buffer size changed in win8 ; have a run - time
* variable to track the size we should use .
*/
static int sense_buffer_size ;
/*
* The size of the vmscsi_request has changed in win8 . The
* additional size is because of new elements added to the
* structure . These elements are valid only when we are talking
* to a win8 host .
* Track the correction to size we need to apply .
*/
static int vmscsi_size_delta ;
static int vmstor_current_major ;
static int vmstor_current_minor ;
struct vmscsi_win8_extension {
/*
* The following were added in Windows 8
*/
u16 reserve ;
u8 queue_tag ;
u8 queue_action ;
u32 srb_flags ;
u32 time_out_value ;
u32 queue_sort_ey ;
} __packed ;
struct vmscsi_request {
u16 length ;
u8 srb_status ;
@ -108,6 +198,11 @@ struct vmscsi_request {
u8 sense_data [ STORVSC_SENSE_BUFFER_SIZE ] ;
u8 reserved_array [ STORVSC_MAX_BUF_LEN_WITH_PADDING ] ;
} ;
/*
* The following was added in win8 .
*/
struct vmscsi_win8_extension win8_extension ;
} __attribute ( ( packed ) ) ;
@ -115,22 +210,18 @@ struct vmscsi_request {
* This structure is sent during the intialization phase to get the different
* properties of the channel .
*/
# define STORAGE_CHANNEL_SUPPORTS_MULTI_CHANNEL 0x1
struct vmstorage_channel_properties {
u16 protocol_version ;
u8 path_id ;
u8 target_id ;
u32 reserved ;
u16 max_channel_cnt ;
u16 reserved1 ;
/* Note: port number is only really known on the client side */
u32 port_number ;
u32 flags ;
u32 flags ;
u32 max_transfer_bytes ;
/*
* This id is unique for each channel and will correspond with
* vendor specific data in the inquiry data .
*/
u64 unique_id ;
u64 reserved2 ;
} __packed ;
/* This structure is sent during the storage protocol negotiations. */
@ -175,6 +266,15 @@ struct vstor_packet {
/* Used during version negotiations. */
struct vmstorage_protocol_version version ;
/* Fibre channel address packet */
struct hv_fc_wwn_packet wwn_packet ;
/* Number of sub-channels to create */
u16 sub_channel_count ;
/* This will be the maximum of the union members */
u8 buffer [ 0x34 ] ;
} ;
} __packed ;
@ -679,7 +779,8 @@ static int storvsc_channel_init(struct hv_device *device)
vstor_packet - > flags = REQUEST_COMPLETION_FLAG ;
ret = vmbus_sendpacket ( device - > channel , vstor_packet ,
sizeof ( struct vstor_packet ) ,
( sizeof ( struct vstor_packet ) -
vmscsi_size_delta ) ,
( unsigned long ) request ,
VM_PKT_DATA_INBAND ,
VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED ) ;
@ -703,7 +804,7 @@ static int storvsc_channel_init(struct hv_device *device)
vstor_packet - > flags = REQUEST_COMPLETION_FLAG ;
vstor_packet - > version . major_minor =
storvsc_get_version ( VMSTOR_CURRENT_MAJOR , VMSTOR_CURRENT_MINOR ) ;
storvsc_get_version ( vmstor_current_major , vmstor_current_minor ) ;
/*
* The revision number is only used in Windows ; set it to 0.
@ -711,7 +812,8 @@ static int storvsc_channel_init(struct hv_device *device)
vstor_packet - > version . revision = 0 ;
ret = vmbus_sendpacket ( device - > channel , vstor_packet ,
sizeof ( struct vstor_packet ) ,
( sizeof ( struct vstor_packet ) -
vmscsi_size_delta ) ,
( unsigned long ) request ,
VM_PKT_DATA_INBAND ,
VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED ) ;
@ -732,11 +834,10 @@ static int storvsc_channel_init(struct hv_device *device)
memset ( vstor_packet , 0 , sizeof ( struct vstor_packet ) ) ;
vstor_packet - > operation = VSTOR_OPERATION_QUERY_PROPERTIES ;
vstor_packet - > flags = REQUEST_COMPLETION_FLAG ;
vstor_packet - > storage_channel_properties . port_number =
stor_device - > port_number ;
ret = vmbus_sendpacket ( device - > channel , vstor_packet ,
sizeof ( struct vstor_packet ) ,
( sizeof ( struct vstor_packet ) -
vmscsi_size_delta ) ,
( unsigned long ) request ,
VM_PKT_DATA_INBAND ,
VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED ) ;
@ -754,16 +855,13 @@ static int storvsc_channel_init(struct hv_device *device)
vstor_packet - > status ! = 0 )
goto cleanup ;
stor_device - > path_id = vstor_packet - > storage_channel_properties . path_id ;
stor_device - > target_id
= vstor_packet - > storage_channel_properties . target_id ;
memset ( vstor_packet , 0 , sizeof ( struct vstor_packet ) ) ;
vstor_packet - > operation = VSTOR_OPERATION_END_INITIALIZATION ;
vstor_packet - > flags = REQUEST_COMPLETION_FLAG ;
ret = vmbus_sendpacket ( device - > channel , vstor_packet ,
sizeof ( struct vstor_packet ) ,
( sizeof ( struct vstor_packet ) -
vmscsi_size_delta ) ,
( unsigned long ) request ,
VM_PKT_DATA_INBAND ,
VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED ) ;
@ -1017,7 +1115,8 @@ static void storvsc_on_channel_callback(void *context)
do {
ret = vmbus_recvpacket ( device - > channel , packet ,
ALIGN ( sizeof ( struct vstor_packet ) , 8 ) ,
ALIGN ( ( sizeof ( struct vstor_packet ) -
vmscsi_size_delta ) , 8 ) ,
& bytes_recvd , & request_id ) ;
if ( ret = = 0 & & bytes_recvd > 0 ) {
@ -1028,7 +1127,8 @@ static void storvsc_on_channel_callback(void *context)
( request = = & stor_device - > reset_request ) ) {
memcpy ( & request - > vstor_packet , packet ,
sizeof ( struct vstor_packet ) ) ;
( sizeof ( struct vstor_packet ) -
vmscsi_size_delta ) ) ;
complete ( & request - > wait_event ) ;
} else {
storvsc_on_receive ( device ,
@ -1121,10 +1221,11 @@ static int storvsc_do_io(struct hv_device *device,
vstor_packet - > flags | = REQUEST_COMPLETION_FLAG ;
vstor_packet - > vm_srb . length = sizeof ( struct vmscsi_request ) ;
vstor_packet - > vm_srb . length = ( sizeof ( struct vmscsi_request ) -
vmscsi_size_delta ) ;
vstor_packet - > vm_srb . sense_info_length = STORVSC_SENSE_BUFFER_SIZE ;
vstor_packet - > vm_srb . sense_info_length = sense_buffer_size ;
vstor_packet - > vm_srb . data_transfer_length =
@ -1136,11 +1237,13 @@ static int storvsc_do_io(struct hv_device *device,
ret = vmbus_sendpacket_multipagebuffer ( device - > channel ,
& request - > data_buffer ,
vstor_packet ,
sizeof ( struct vstor_packet ) ,
( sizeof ( struct vstor_packet ) -
vmscsi_size_delta ) ,
( unsigned long ) request ) ;
} else {
ret = vmbus_sendpacket ( device - > channel , vstor_packet ,
sizeof ( struct vstor_packet ) ,
( sizeof ( struct vstor_packet ) -
vmscsi_size_delta ) ,
( unsigned long ) request ,
VM_PKT_DATA_INBAND ,
VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED ) ;
@ -1264,7 +1367,8 @@ static int storvsc_host_reset_handler(struct scsi_cmnd *scmnd)
vstor_packet - > vm_srb . path_id = stor_device - > path_id ;
ret = vmbus_sendpacket ( device - > channel , vstor_packet ,
sizeof ( struct vstor_packet ) ,
( sizeof ( struct vstor_packet ) -
vmscsi_size_delta ) ,
( unsigned long ) & stor_device - > reset_request ,
VM_PKT_DATA_INBAND ,
VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED ) ;
@ -1349,18 +1453,28 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd)
scmnd - > host_scribble = ( unsigned char * ) cmd_request ;
vm_srb = & cmd_request - > vstor_packet . vm_srb ;
vm_srb - > win8_extension . time_out_value = 60 ;
/* Build the SRB */
switch ( scmnd - > sc_data_direction ) {
case DMA_TO_DEVICE :
vm_srb - > data_in = WRITE_TYPE ;
vm_srb - > win8_extension . srb_flags | = SRB_FLAGS_DATA_OUT ;
vm_srb - > win8_extension . srb_flags | =
( SRB_FLAGS_QUEUE_ACTION_ENABLE |
SRB_FLAGS_DISABLE_SYNCH_TRANSFER ) ;
break ;
case DMA_FROM_DEVICE :
vm_srb - > data_in = READ_TYPE ;
vm_srb - > win8_extension . srb_flags | = SRB_FLAGS_DATA_IN ;
vm_srb - > win8_extension . srb_flags | =
( SRB_FLAGS_QUEUE_ACTION_ENABLE |
SRB_FLAGS_DISABLE_SYNCH_TRANSFER ) ;
break ;
default :
vm_srb - > data_in = UNKNOWN_TYPE ;
vm_srb - > win8_extension . srb_flags = 0 ;
break ;
}
@ -1492,6 +1606,24 @@ static int storvsc_probe(struct hv_device *device,
int target = 0 ;
struct storvsc_device * stor_device ;
/*
* Based on the windows host we are running on ,
* set state to properly communicate with the host .
*/
if ( vmbus_proto_version = = VERSION_WIN8 ) {
sense_buffer_size = POST_WIN7_STORVSC_SENSE_BUFFER_SIZE ;
vmscsi_size_delta = 0 ;
vmstor_current_major = VMSTOR_WIN8_MAJOR ;
vmstor_current_minor = VMSTOR_WIN8_MINOR ;
} else {
sense_buffer_size = PRE_WIN8_STORVSC_SENSE_BUFFER_SIZE ;
vmscsi_size_delta = sizeof ( struct vmscsi_win8_extension ) ;
vmstor_current_major = VMSTOR_WIN7_MAJOR ;
vmstor_current_minor = VMSTOR_WIN7_MINOR ;
}
host = scsi_host_alloc ( & scsi_driver ,
sizeof ( struct hv_host_device ) ) ;
if ( ! host )
@ -1601,7 +1733,8 @@ static int __init storvsc_drv_init(void)
max_outstanding_req_per_channel =
( ( storvsc_ringbuffer_size - PAGE_SIZE ) /
ALIGN ( MAX_MULTIPAGE_BUFFER_PACKET +
sizeof ( struct vstor_packet ) + sizeof ( u64 ) ,
sizeof ( struct vstor_packet ) + sizeof ( u64 ) -
vmscsi_size_delta ,
sizeof ( u64 ) ) ) ;
if ( max_outstanding_req_per_channel <