Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8b612fa2 authored by K. Y. Srinivasan's avatar K. Y. Srinivasan Committed by James Bottomley
Browse files

[SCSI] storvsc: Update the storage protocol to win8 level

parent 893def38
Loading
Loading
Loading
Loading
+168 −35
Original line number Original line Diff line number Diff line
@@ -55,10 +55,15 @@
 * V1 RC < 2008/1/31: 1.0
 * V1 RC < 2008/1/31: 1.0
 * V1 RC > 2008/1/31:  2.0
 * V1 RC > 2008/1/31:  2.0
 * Win7: 4.2
 * 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. */
/*  Packet structure describing virtual storage requests. */
@@ -74,18 +79,103 @@ enum vstor_packet_operation {
	VSTOR_OPERATION_QUERY_PROTOCOL_VERSION	= 9,
	VSTOR_OPERATION_QUERY_PROTOCOL_VERSION	= 9,
	VSTOR_OPERATION_QUERY_PROPERTIES	= 10,
	VSTOR_OPERATION_QUERY_PROPERTIES	= 10,
	VSTOR_OPERATION_ENUMERATE_BUS		= 11,
	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 -
 * Platform neutral description of a scsi request -
 * this remains the same across the write regardless of 32/64 bit
 * this remains the same across the write regardless of 32/64 bit
 * note: it's patterned off the SCSI_PASS_THROUGH structure
 * note: it's patterned off the SCSI_PASS_THROUGH structure
 */
 */
#define STORVSC_MAX_CMD_LEN			0x10
#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
#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 {
struct vmscsi_request {
	u16 length;
	u16 length;
	u8 srb_status;
	u8 srb_status;
@@ -108,6 +198,11 @@ struct vmscsi_request {
		u8 sense_data[STORVSC_SENSE_BUFFER_SIZE];
		u8 sense_data[STORVSC_SENSE_BUFFER_SIZE];
		u8 reserved_array[STORVSC_MAX_BUF_LEN_WITH_PADDING];
		u8 reserved_array[STORVSC_MAX_BUF_LEN_WITH_PADDING];
	};
	};
	/*
	 * The following was added in win8.
	 */
	struct vmscsi_win8_extension win8_extension;

} __attribute((packed));
} __attribute((packed));




@@ -115,22 +210,18 @@ struct vmscsi_request {
 * This structure is sent during the intialization phase to get the different
 * This structure is sent during the intialization phase to get the different
 * properties of the channel.
 * properties of the channel.
 */
 */

#define STORAGE_CHANNEL_SUPPORTS_MULTI_CHANNEL		0x1

struct vmstorage_channel_properties {
struct vmstorage_channel_properties {
	u16 protocol_version;
	u32 reserved;
	u8  path_id;
	u16 max_channel_cnt;
	u8 target_id;
	u16 reserved1;


	/* Note: port number is only really known on the client side */
	u32  port_number;
	u32 flags;
	u32 flags;
	u32   max_transfer_bytes;
	u32   max_transfer_bytes;


	/*
	u64  reserved2;
	 * This id is unique for each channel and will correspond with
	 * vendor specific data in the inquiry data.
	 */

	u64  unique_id;
} __packed;
} __packed;


/*  This structure is sent during the storage protocol negotiations. */
/*  This structure is sent during the storage protocol negotiations. */
@@ -175,6 +266,15 @@ struct vstor_packet {


		/* Used during version negotiations. */
		/* Used during version negotiations. */
		struct vmstorage_protocol_version version;
		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;
} __packed;


@@ -679,7 +779,8 @@ static int storvsc_channel_init(struct hv_device *device)
	vstor_packet->flags = REQUEST_COMPLETION_FLAG;
	vstor_packet->flags = REQUEST_COMPLETION_FLAG;


	ret = vmbus_sendpacket(device->channel, vstor_packet,
	ret = vmbus_sendpacket(device->channel, vstor_packet,
			       sizeof(struct vstor_packet),
			       (sizeof(struct vstor_packet) -
			       vmscsi_size_delta),
			       (unsigned long)request,
			       (unsigned long)request,
			       VM_PKT_DATA_INBAND,
			       VM_PKT_DATA_INBAND,
			       VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
			       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->flags = REQUEST_COMPLETION_FLAG;


	vstor_packet->version.major_minor =
	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.
	 * 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;
	vstor_packet->version.revision = 0;


	ret = vmbus_sendpacket(device->channel, vstor_packet,
	ret = vmbus_sendpacket(device->channel, vstor_packet,
			       sizeof(struct vstor_packet),
			       (sizeof(struct vstor_packet) -
				vmscsi_size_delta),
			       (unsigned long)request,
			       (unsigned long)request,
			       VM_PKT_DATA_INBAND,
			       VM_PKT_DATA_INBAND,
			       VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
			       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));
	memset(vstor_packet, 0, sizeof(struct vstor_packet));
	vstor_packet->operation = VSTOR_OPERATION_QUERY_PROPERTIES;
	vstor_packet->operation = VSTOR_OPERATION_QUERY_PROPERTIES;
	vstor_packet->flags = REQUEST_COMPLETION_FLAG;
	vstor_packet->flags = REQUEST_COMPLETION_FLAG;
	vstor_packet->storage_channel_properties.port_number =
					stor_device->port_number;


	ret = vmbus_sendpacket(device->channel, vstor_packet,
	ret = vmbus_sendpacket(device->channel, vstor_packet,
			       sizeof(struct vstor_packet),
			       (sizeof(struct vstor_packet) -
				vmscsi_size_delta),
			       (unsigned long)request,
			       (unsigned long)request,
			       VM_PKT_DATA_INBAND,
			       VM_PKT_DATA_INBAND,
			       VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
			       VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
@@ -754,16 +855,13 @@ static int storvsc_channel_init(struct hv_device *device)
	    vstor_packet->status != 0)
	    vstor_packet->status != 0)
		goto cleanup;
		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));
	memset(vstor_packet, 0, sizeof(struct vstor_packet));
	vstor_packet->operation = VSTOR_OPERATION_END_INITIALIZATION;
	vstor_packet->operation = VSTOR_OPERATION_END_INITIALIZATION;
	vstor_packet->flags = REQUEST_COMPLETION_FLAG;
	vstor_packet->flags = REQUEST_COMPLETION_FLAG;


	ret = vmbus_sendpacket(device->channel, vstor_packet,
	ret = vmbus_sendpacket(device->channel, vstor_packet,
			       sizeof(struct vstor_packet),
			       (sizeof(struct vstor_packet) -
				vmscsi_size_delta),
			       (unsigned long)request,
			       (unsigned long)request,
			       VM_PKT_DATA_INBAND,
			       VM_PKT_DATA_INBAND,
			       VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
			       VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
@@ -1017,7 +1115,8 @@ static void storvsc_on_channel_callback(void *context)


	do {
	do {
		ret = vmbus_recvpacket(device->channel, packet,
		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);
				       &bytes_recvd, &request_id);
		if (ret == 0 && bytes_recvd > 0) {
		if (ret == 0 && bytes_recvd > 0) {


@@ -1028,7 +1127,8 @@ static void storvsc_on_channel_callback(void *context)
			    (request == &stor_device->reset_request)) {
			    (request == &stor_device->reset_request)) {


				memcpy(&request->vstor_packet, packet,
				memcpy(&request->vstor_packet, packet,
				       sizeof(struct vstor_packet));
				       (sizeof(struct vstor_packet) -
					vmscsi_size_delta));
				complete(&request->wait_event);
				complete(&request->wait_event);
			} else {
			} else {
				storvsc_on_receive(device,
				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->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 =
	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,
		ret = vmbus_sendpacket_multipagebuffer(device->channel,
				&request->data_buffer,
				&request->data_buffer,
				vstor_packet,
				vstor_packet,
				sizeof(struct vstor_packet),
				(sizeof(struct vstor_packet) -
				vmscsi_size_delta),
				(unsigned long)request);
				(unsigned long)request);
	} else {
	} else {
		ret = vmbus_sendpacket(device->channel, vstor_packet,
		ret = vmbus_sendpacket(device->channel, vstor_packet,
			       sizeof(struct vstor_packet),
			       (sizeof(struct vstor_packet) -
				vmscsi_size_delta),
			       (unsigned long)request,
			       (unsigned long)request,
			       VM_PKT_DATA_INBAND,
			       VM_PKT_DATA_INBAND,
			       VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
			       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;
	vstor_packet->vm_srb.path_id = stor_device->path_id;


	ret = vmbus_sendpacket(device->channel, vstor_packet,
	ret = vmbus_sendpacket(device->channel, vstor_packet,
			       sizeof(struct vstor_packet),
			       (sizeof(struct vstor_packet) -
				vmscsi_size_delta),
			       (unsigned long)&stor_device->reset_request,
			       (unsigned long)&stor_device->reset_request,
			       VM_PKT_DATA_INBAND,
			       VM_PKT_DATA_INBAND,
			       VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
			       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;
	scmnd->host_scribble = (unsigned char *)cmd_request;


	vm_srb = &cmd_request->vstor_packet.vm_srb;
	vm_srb = &cmd_request->vstor_packet.vm_srb;
	vm_srb->win8_extension.time_out_value = 60;




	/* Build the SRB */
	/* Build the SRB */
	switch (scmnd->sc_data_direction) {
	switch (scmnd->sc_data_direction) {
	case DMA_TO_DEVICE:
	case DMA_TO_DEVICE:
		vm_srb->data_in = WRITE_TYPE;
		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;
		break;
	case DMA_FROM_DEVICE:
	case DMA_FROM_DEVICE:
		vm_srb->data_in = READ_TYPE;
		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;
		break;
	default:
	default:
		vm_srb->data_in = UNKNOWN_TYPE;
		vm_srb->data_in = UNKNOWN_TYPE;
		vm_srb->win8_extension.srb_flags = 0;
		break;
		break;
	}
	}


@@ -1492,6 +1606,24 @@ static int storvsc_probe(struct hv_device *device,
	int target = 0;
	int target = 0;
	struct storvsc_device *stor_device;
	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,
	host = scsi_host_alloc(&scsi_driver,
			       sizeof(struct hv_host_device));
			       sizeof(struct hv_host_device));
	if (!host)
	if (!host)
@@ -1601,7 +1733,8 @@ static int __init storvsc_drv_init(void)
	max_outstanding_req_per_channel =
	max_outstanding_req_per_channel =
		((storvsc_ringbuffer_size - PAGE_SIZE) /
		((storvsc_ringbuffer_size - PAGE_SIZE) /
		ALIGN(MAX_MULTIPAGE_BUFFER_PACKET +
		ALIGN(MAX_MULTIPAGE_BUFFER_PACKET +
		sizeof(struct vstor_packet) + sizeof(u64),
		sizeof(struct vstor_packet) + sizeof(u64) -
		vmscsi_size_delta,
		sizeof(u64)));
		sizeof(u64)));


	if (max_outstanding_req_per_channel <
	if (max_outstanding_req_per_channel <