18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (c) 2009, Microsoft Corporation.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Authors:
68c2ecf20Sopenharmony_ci *   Haiyang Zhang <haiyangz@microsoft.com>
78c2ecf20Sopenharmony_ci *   Hank Janssen  <hjanssen@microsoft.com>
88c2ecf20Sopenharmony_ci *   K. Y. Srinivasan <kys@microsoft.com>
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <linux/kernel.h>
128c2ecf20Sopenharmony_ci#include <linux/wait.h>
138c2ecf20Sopenharmony_ci#include <linux/sched.h>
148c2ecf20Sopenharmony_ci#include <linux/completion.h>
158c2ecf20Sopenharmony_ci#include <linux/string.h>
168c2ecf20Sopenharmony_ci#include <linux/mm.h>
178c2ecf20Sopenharmony_ci#include <linux/delay.h>
188c2ecf20Sopenharmony_ci#include <linux/init.h>
198c2ecf20Sopenharmony_ci#include <linux/slab.h>
208c2ecf20Sopenharmony_ci#include <linux/module.h>
218c2ecf20Sopenharmony_ci#include <linux/device.h>
228c2ecf20Sopenharmony_ci#include <linux/hyperv.h>
238c2ecf20Sopenharmony_ci#include <linux/blkdev.h>
248c2ecf20Sopenharmony_ci#include <scsi/scsi.h>
258c2ecf20Sopenharmony_ci#include <scsi/scsi_cmnd.h>
268c2ecf20Sopenharmony_ci#include <scsi/scsi_host.h>
278c2ecf20Sopenharmony_ci#include <scsi/scsi_device.h>
288c2ecf20Sopenharmony_ci#include <scsi/scsi_tcq.h>
298c2ecf20Sopenharmony_ci#include <scsi/scsi_eh.h>
308c2ecf20Sopenharmony_ci#include <scsi/scsi_devinfo.h>
318c2ecf20Sopenharmony_ci#include <scsi/scsi_dbg.h>
328c2ecf20Sopenharmony_ci#include <scsi/scsi_transport_fc.h>
338c2ecf20Sopenharmony_ci#include <scsi/scsi_transport.h>
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci/*
368c2ecf20Sopenharmony_ci * All wire protocol details (storage protocol between the guest and the host)
378c2ecf20Sopenharmony_ci * are consolidated here.
388c2ecf20Sopenharmony_ci *
398c2ecf20Sopenharmony_ci * Begin protocol definitions.
408c2ecf20Sopenharmony_ci */
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci/*
438c2ecf20Sopenharmony_ci * Version history:
448c2ecf20Sopenharmony_ci * V1 Beta: 0.1
458c2ecf20Sopenharmony_ci * V1 RC < 2008/1/31: 1.0
468c2ecf20Sopenharmony_ci * V1 RC > 2008/1/31:  2.0
478c2ecf20Sopenharmony_ci * Win7: 4.2
488c2ecf20Sopenharmony_ci * Win8: 5.1
498c2ecf20Sopenharmony_ci * Win8.1: 6.0
508c2ecf20Sopenharmony_ci * Win10: 6.2
518c2ecf20Sopenharmony_ci */
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci#define VMSTOR_PROTO_VERSION(MAJOR_, MINOR_)	((((MAJOR_) & 0xff) << 8) | \
548c2ecf20Sopenharmony_ci						(((MINOR_) & 0xff)))
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci#define VMSTOR_PROTO_VERSION_WIN6	VMSTOR_PROTO_VERSION(2, 0)
578c2ecf20Sopenharmony_ci#define VMSTOR_PROTO_VERSION_WIN7	VMSTOR_PROTO_VERSION(4, 2)
588c2ecf20Sopenharmony_ci#define VMSTOR_PROTO_VERSION_WIN8	VMSTOR_PROTO_VERSION(5, 1)
598c2ecf20Sopenharmony_ci#define VMSTOR_PROTO_VERSION_WIN8_1	VMSTOR_PROTO_VERSION(6, 0)
608c2ecf20Sopenharmony_ci#define VMSTOR_PROTO_VERSION_WIN10	VMSTOR_PROTO_VERSION(6, 2)
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci/*  Packet structure describing virtual storage requests. */
638c2ecf20Sopenharmony_cienum vstor_packet_operation {
648c2ecf20Sopenharmony_ci	VSTOR_OPERATION_COMPLETE_IO		= 1,
658c2ecf20Sopenharmony_ci	VSTOR_OPERATION_REMOVE_DEVICE		= 2,
668c2ecf20Sopenharmony_ci	VSTOR_OPERATION_EXECUTE_SRB		= 3,
678c2ecf20Sopenharmony_ci	VSTOR_OPERATION_RESET_LUN		= 4,
688c2ecf20Sopenharmony_ci	VSTOR_OPERATION_RESET_ADAPTER		= 5,
698c2ecf20Sopenharmony_ci	VSTOR_OPERATION_RESET_BUS		= 6,
708c2ecf20Sopenharmony_ci	VSTOR_OPERATION_BEGIN_INITIALIZATION	= 7,
718c2ecf20Sopenharmony_ci	VSTOR_OPERATION_END_INITIALIZATION	= 8,
728c2ecf20Sopenharmony_ci	VSTOR_OPERATION_QUERY_PROTOCOL_VERSION	= 9,
738c2ecf20Sopenharmony_ci	VSTOR_OPERATION_QUERY_PROPERTIES	= 10,
748c2ecf20Sopenharmony_ci	VSTOR_OPERATION_ENUMERATE_BUS		= 11,
758c2ecf20Sopenharmony_ci	VSTOR_OPERATION_FCHBA_DATA              = 12,
768c2ecf20Sopenharmony_ci	VSTOR_OPERATION_CREATE_SUB_CHANNELS     = 13,
778c2ecf20Sopenharmony_ci	VSTOR_OPERATION_MAXIMUM                 = 13
788c2ecf20Sopenharmony_ci};
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci/*
818c2ecf20Sopenharmony_ci * WWN packet for Fibre Channel HBA
828c2ecf20Sopenharmony_ci */
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_cistruct hv_fc_wwn_packet {
858c2ecf20Sopenharmony_ci	u8	primary_active;
868c2ecf20Sopenharmony_ci	u8	reserved1[3];
878c2ecf20Sopenharmony_ci	u8	primary_port_wwn[8];
888c2ecf20Sopenharmony_ci	u8	primary_node_wwn[8];
898c2ecf20Sopenharmony_ci	u8	secondary_port_wwn[8];
908c2ecf20Sopenharmony_ci	u8	secondary_node_wwn[8];
918c2ecf20Sopenharmony_ci};
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci/*
968c2ecf20Sopenharmony_ci * SRB Flag Bits
978c2ecf20Sopenharmony_ci */
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci#define SRB_FLAGS_QUEUE_ACTION_ENABLE		0x00000002
1008c2ecf20Sopenharmony_ci#define SRB_FLAGS_DISABLE_DISCONNECT		0x00000004
1018c2ecf20Sopenharmony_ci#define SRB_FLAGS_DISABLE_SYNCH_TRANSFER	0x00000008
1028c2ecf20Sopenharmony_ci#define SRB_FLAGS_BYPASS_FROZEN_QUEUE		0x00000010
1038c2ecf20Sopenharmony_ci#define SRB_FLAGS_DISABLE_AUTOSENSE		0x00000020
1048c2ecf20Sopenharmony_ci#define SRB_FLAGS_DATA_IN			0x00000040
1058c2ecf20Sopenharmony_ci#define SRB_FLAGS_DATA_OUT			0x00000080
1068c2ecf20Sopenharmony_ci#define SRB_FLAGS_NO_DATA_TRANSFER		0x00000000
1078c2ecf20Sopenharmony_ci#define SRB_FLAGS_UNSPECIFIED_DIRECTION	(SRB_FLAGS_DATA_IN | SRB_FLAGS_DATA_OUT)
1088c2ecf20Sopenharmony_ci#define SRB_FLAGS_NO_QUEUE_FREEZE		0x00000100
1098c2ecf20Sopenharmony_ci#define SRB_FLAGS_ADAPTER_CACHE_ENABLE		0x00000200
1108c2ecf20Sopenharmony_ci#define SRB_FLAGS_FREE_SENSE_BUFFER		0x00000400
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci/*
1138c2ecf20Sopenharmony_ci * This flag indicates the request is part of the workflow for processing a D3.
1148c2ecf20Sopenharmony_ci */
1158c2ecf20Sopenharmony_ci#define SRB_FLAGS_D3_PROCESSING			0x00000800
1168c2ecf20Sopenharmony_ci#define SRB_FLAGS_IS_ACTIVE			0x00010000
1178c2ecf20Sopenharmony_ci#define SRB_FLAGS_ALLOCATED_FROM_ZONE		0x00020000
1188c2ecf20Sopenharmony_ci#define SRB_FLAGS_SGLIST_FROM_POOL		0x00040000
1198c2ecf20Sopenharmony_ci#define SRB_FLAGS_BYPASS_LOCKED_QUEUE		0x00080000
1208c2ecf20Sopenharmony_ci#define SRB_FLAGS_NO_KEEP_AWAKE			0x00100000
1218c2ecf20Sopenharmony_ci#define SRB_FLAGS_PORT_DRIVER_ALLOCSENSE	0x00200000
1228c2ecf20Sopenharmony_ci#define SRB_FLAGS_PORT_DRIVER_SENSEHASPORT	0x00400000
1238c2ecf20Sopenharmony_ci#define SRB_FLAGS_DONT_START_NEXT_PACKET	0x00800000
1248c2ecf20Sopenharmony_ci#define SRB_FLAGS_PORT_DRIVER_RESERVED		0x0F000000
1258c2ecf20Sopenharmony_ci#define SRB_FLAGS_CLASS_DRIVER_RESERVED		0xF0000000
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci#define SP_UNTAGGED			((unsigned char) ~0)
1288c2ecf20Sopenharmony_ci#define SRB_SIMPLE_TAG_REQUEST		0x20
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci/*
1318c2ecf20Sopenharmony_ci * Platform neutral description of a scsi request -
1328c2ecf20Sopenharmony_ci * this remains the same across the write regardless of 32/64 bit
1338c2ecf20Sopenharmony_ci * note: it's patterned off the SCSI_PASS_THROUGH structure
1348c2ecf20Sopenharmony_ci */
1358c2ecf20Sopenharmony_ci#define STORVSC_MAX_CMD_LEN			0x10
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci#define POST_WIN7_STORVSC_SENSE_BUFFER_SIZE	0x14
1388c2ecf20Sopenharmony_ci#define PRE_WIN8_STORVSC_SENSE_BUFFER_SIZE	0x12
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci#define STORVSC_SENSE_BUFFER_SIZE		0x14
1418c2ecf20Sopenharmony_ci#define STORVSC_MAX_BUF_LEN_WITH_PADDING	0x14
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci/*
1448c2ecf20Sopenharmony_ci * Sense buffer size changed in win8; have a run-time
1458c2ecf20Sopenharmony_ci * variable to track the size we should use.  This value will
1468c2ecf20Sopenharmony_ci * likely change during protocol negotiation but it is valid
1478c2ecf20Sopenharmony_ci * to start by assuming pre-Win8.
1488c2ecf20Sopenharmony_ci */
1498c2ecf20Sopenharmony_cistatic int sense_buffer_size = PRE_WIN8_STORVSC_SENSE_BUFFER_SIZE;
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci/*
1528c2ecf20Sopenharmony_ci * The storage protocol version is determined during the
1538c2ecf20Sopenharmony_ci * initial exchange with the host.  It will indicate which
1548c2ecf20Sopenharmony_ci * storage functionality is available in the host.
1558c2ecf20Sopenharmony_ci*/
1568c2ecf20Sopenharmony_cistatic int vmstor_proto_version;
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci#define STORVSC_LOGGING_NONE	0
1598c2ecf20Sopenharmony_ci#define STORVSC_LOGGING_ERROR	1
1608c2ecf20Sopenharmony_ci#define STORVSC_LOGGING_WARN	2
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_cistatic int logging_level = STORVSC_LOGGING_ERROR;
1638c2ecf20Sopenharmony_cimodule_param(logging_level, int, S_IRUGO|S_IWUSR);
1648c2ecf20Sopenharmony_ciMODULE_PARM_DESC(logging_level,
1658c2ecf20Sopenharmony_ci	"Logging level, 0 - None, 1 - Error (default), 2 - Warning.");
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_cistatic inline bool do_logging(int level)
1688c2ecf20Sopenharmony_ci{
1698c2ecf20Sopenharmony_ci	return logging_level >= level;
1708c2ecf20Sopenharmony_ci}
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci#define storvsc_log(dev, level, fmt, ...)			\
1738c2ecf20Sopenharmony_cido {								\
1748c2ecf20Sopenharmony_ci	if (do_logging(level))					\
1758c2ecf20Sopenharmony_ci		dev_warn(&(dev)->device, fmt, ##__VA_ARGS__);	\
1768c2ecf20Sopenharmony_ci} while (0)
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_cistruct vmscsi_win8_extension {
1798c2ecf20Sopenharmony_ci	/*
1808c2ecf20Sopenharmony_ci	 * The following were added in Windows 8
1818c2ecf20Sopenharmony_ci	 */
1828c2ecf20Sopenharmony_ci	u16 reserve;
1838c2ecf20Sopenharmony_ci	u8  queue_tag;
1848c2ecf20Sopenharmony_ci	u8  queue_action;
1858c2ecf20Sopenharmony_ci	u32 srb_flags;
1868c2ecf20Sopenharmony_ci	u32 time_out_value;
1878c2ecf20Sopenharmony_ci	u32 queue_sort_ey;
1888c2ecf20Sopenharmony_ci} __packed;
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_cistruct vmscsi_request {
1918c2ecf20Sopenharmony_ci	u16 length;
1928c2ecf20Sopenharmony_ci	u8 srb_status;
1938c2ecf20Sopenharmony_ci	u8 scsi_status;
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	u8  port_number;
1968c2ecf20Sopenharmony_ci	u8  path_id;
1978c2ecf20Sopenharmony_ci	u8  target_id;
1988c2ecf20Sopenharmony_ci	u8  lun;
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	u8  cdb_length;
2018c2ecf20Sopenharmony_ci	u8  sense_info_length;
2028c2ecf20Sopenharmony_ci	u8  data_in;
2038c2ecf20Sopenharmony_ci	u8  reserved;
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	u32 data_transfer_length;
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	union {
2088c2ecf20Sopenharmony_ci		u8 cdb[STORVSC_MAX_CMD_LEN];
2098c2ecf20Sopenharmony_ci		u8 sense_data[STORVSC_SENSE_BUFFER_SIZE];
2108c2ecf20Sopenharmony_ci		u8 reserved_array[STORVSC_MAX_BUF_LEN_WITH_PADDING];
2118c2ecf20Sopenharmony_ci	};
2128c2ecf20Sopenharmony_ci	/*
2138c2ecf20Sopenharmony_ci	 * The following was added in win8.
2148c2ecf20Sopenharmony_ci	 */
2158c2ecf20Sopenharmony_ci	struct vmscsi_win8_extension win8_extension;
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci} __attribute((packed));
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci/*
2218c2ecf20Sopenharmony_ci * The size of the vmscsi_request has changed in win8. The
2228c2ecf20Sopenharmony_ci * additional size is because of new elements added to the
2238c2ecf20Sopenharmony_ci * structure. These elements are valid only when we are talking
2248c2ecf20Sopenharmony_ci * to a win8 host.
2258c2ecf20Sopenharmony_ci * Track the correction to size we need to apply. This value
2268c2ecf20Sopenharmony_ci * will likely change during protocol negotiation but it is
2278c2ecf20Sopenharmony_ci * valid to start by assuming pre-Win8.
2288c2ecf20Sopenharmony_ci */
2298c2ecf20Sopenharmony_cistatic int vmscsi_size_delta = sizeof(struct vmscsi_win8_extension);
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci/*
2328c2ecf20Sopenharmony_ci * The list of storage protocols in order of preference.
2338c2ecf20Sopenharmony_ci */
2348c2ecf20Sopenharmony_cistruct vmstor_protocol {
2358c2ecf20Sopenharmony_ci	int protocol_version;
2368c2ecf20Sopenharmony_ci	int sense_buffer_size;
2378c2ecf20Sopenharmony_ci	int vmscsi_size_delta;
2388c2ecf20Sopenharmony_ci};
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_cistatic const struct vmstor_protocol vmstor_protocols[] = {
2428c2ecf20Sopenharmony_ci	{
2438c2ecf20Sopenharmony_ci		VMSTOR_PROTO_VERSION_WIN10,
2448c2ecf20Sopenharmony_ci		POST_WIN7_STORVSC_SENSE_BUFFER_SIZE,
2458c2ecf20Sopenharmony_ci		0
2468c2ecf20Sopenharmony_ci	},
2478c2ecf20Sopenharmony_ci	{
2488c2ecf20Sopenharmony_ci		VMSTOR_PROTO_VERSION_WIN8_1,
2498c2ecf20Sopenharmony_ci		POST_WIN7_STORVSC_SENSE_BUFFER_SIZE,
2508c2ecf20Sopenharmony_ci		0
2518c2ecf20Sopenharmony_ci	},
2528c2ecf20Sopenharmony_ci	{
2538c2ecf20Sopenharmony_ci		VMSTOR_PROTO_VERSION_WIN8,
2548c2ecf20Sopenharmony_ci		POST_WIN7_STORVSC_SENSE_BUFFER_SIZE,
2558c2ecf20Sopenharmony_ci		0
2568c2ecf20Sopenharmony_ci	},
2578c2ecf20Sopenharmony_ci	{
2588c2ecf20Sopenharmony_ci		VMSTOR_PROTO_VERSION_WIN7,
2598c2ecf20Sopenharmony_ci		PRE_WIN8_STORVSC_SENSE_BUFFER_SIZE,
2608c2ecf20Sopenharmony_ci		sizeof(struct vmscsi_win8_extension),
2618c2ecf20Sopenharmony_ci	},
2628c2ecf20Sopenharmony_ci	{
2638c2ecf20Sopenharmony_ci		VMSTOR_PROTO_VERSION_WIN6,
2648c2ecf20Sopenharmony_ci		PRE_WIN8_STORVSC_SENSE_BUFFER_SIZE,
2658c2ecf20Sopenharmony_ci		sizeof(struct vmscsi_win8_extension),
2668c2ecf20Sopenharmony_ci	}
2678c2ecf20Sopenharmony_ci};
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci/*
2718c2ecf20Sopenharmony_ci * This structure is sent during the initialization phase to get the different
2728c2ecf20Sopenharmony_ci * properties of the channel.
2738c2ecf20Sopenharmony_ci */
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci#define STORAGE_CHANNEL_SUPPORTS_MULTI_CHANNEL		0x1
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_cistruct vmstorage_channel_properties {
2788c2ecf20Sopenharmony_ci	u32 reserved;
2798c2ecf20Sopenharmony_ci	u16 max_channel_cnt;
2808c2ecf20Sopenharmony_ci	u16 reserved1;
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	u32 flags;
2838c2ecf20Sopenharmony_ci	u32   max_transfer_bytes;
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci	u64  reserved2;
2868c2ecf20Sopenharmony_ci} __packed;
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci/*  This structure is sent during the storage protocol negotiations. */
2898c2ecf20Sopenharmony_cistruct vmstorage_protocol_version {
2908c2ecf20Sopenharmony_ci	/* Major (MSW) and minor (LSW) version numbers. */
2918c2ecf20Sopenharmony_ci	u16 major_minor;
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci	/*
2948c2ecf20Sopenharmony_ci	 * Revision number is auto-incremented whenever this file is changed
2958c2ecf20Sopenharmony_ci	 * (See FILL_VMSTOR_REVISION macro above).  Mismatch does not
2968c2ecf20Sopenharmony_ci	 * definitely indicate incompatibility--but it does indicate mismatched
2978c2ecf20Sopenharmony_ci	 * builds.
2988c2ecf20Sopenharmony_ci	 * This is only used on the windows side. Just set it to 0.
2998c2ecf20Sopenharmony_ci	 */
3008c2ecf20Sopenharmony_ci	u16 revision;
3018c2ecf20Sopenharmony_ci} __packed;
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci/* Channel Property Flags */
3048c2ecf20Sopenharmony_ci#define STORAGE_CHANNEL_REMOVABLE_FLAG		0x1
3058c2ecf20Sopenharmony_ci#define STORAGE_CHANNEL_EMULATED_IDE_FLAG	0x2
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_cistruct vstor_packet {
3088c2ecf20Sopenharmony_ci	/* Requested operation type */
3098c2ecf20Sopenharmony_ci	enum vstor_packet_operation operation;
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci	/*  Flags - see below for values */
3128c2ecf20Sopenharmony_ci	u32 flags;
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	/* Status of the request returned from the server side. */
3158c2ecf20Sopenharmony_ci	u32 status;
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	/* Data payload area */
3188c2ecf20Sopenharmony_ci	union {
3198c2ecf20Sopenharmony_ci		/*
3208c2ecf20Sopenharmony_ci		 * Structure used to forward SCSI commands from the
3218c2ecf20Sopenharmony_ci		 * client to the server.
3228c2ecf20Sopenharmony_ci		 */
3238c2ecf20Sopenharmony_ci		struct vmscsi_request vm_srb;
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci		/* Structure used to query channel properties. */
3268c2ecf20Sopenharmony_ci		struct vmstorage_channel_properties storage_channel_properties;
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci		/* Used during version negotiations. */
3298c2ecf20Sopenharmony_ci		struct vmstorage_protocol_version version;
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci		/* Fibre channel address packet */
3328c2ecf20Sopenharmony_ci		struct hv_fc_wwn_packet wwn_packet;
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci		/* Number of sub-channels to create */
3358c2ecf20Sopenharmony_ci		u16 sub_channel_count;
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci		/* This will be the maximum of the union members */
3388c2ecf20Sopenharmony_ci		u8  buffer[0x34];
3398c2ecf20Sopenharmony_ci	};
3408c2ecf20Sopenharmony_ci} __packed;
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci/*
3438c2ecf20Sopenharmony_ci * Packet Flags:
3448c2ecf20Sopenharmony_ci *
3458c2ecf20Sopenharmony_ci * This flag indicates that the server should send back a completion for this
3468c2ecf20Sopenharmony_ci * packet.
3478c2ecf20Sopenharmony_ci */
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci#define REQUEST_COMPLETION_FLAG	0x1
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci/* Matches Windows-end */
3528c2ecf20Sopenharmony_cienum storvsc_request_type {
3538c2ecf20Sopenharmony_ci	WRITE_TYPE = 0,
3548c2ecf20Sopenharmony_ci	READ_TYPE,
3558c2ecf20Sopenharmony_ci	UNKNOWN_TYPE,
3568c2ecf20Sopenharmony_ci};
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci/*
3598c2ecf20Sopenharmony_ci * SRB status codes and masks. In the 8-bit field, the two high order bits
3608c2ecf20Sopenharmony_ci * are flags, while the remaining 6 bits are an integer status code.  The
3618c2ecf20Sopenharmony_ci * definitions here include only the subset of the integer status codes that
3628c2ecf20Sopenharmony_ci * are tested for in this driver.
3638c2ecf20Sopenharmony_ci */
3648c2ecf20Sopenharmony_ci#define SRB_STATUS_AUTOSENSE_VALID	0x80
3658c2ecf20Sopenharmony_ci#define SRB_STATUS_QUEUE_FROZEN		0x40
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci/* SRB status integer codes */
3688c2ecf20Sopenharmony_ci#define SRB_STATUS_SUCCESS		0x01
3698c2ecf20Sopenharmony_ci#define SRB_STATUS_ABORTED		0x02
3708c2ecf20Sopenharmony_ci#define SRB_STATUS_ERROR		0x04
3718c2ecf20Sopenharmony_ci#define SRB_STATUS_INVALID_REQUEST	0x06
3728c2ecf20Sopenharmony_ci#define SRB_STATUS_DATA_OVERRUN		0x12
3738c2ecf20Sopenharmony_ci#define SRB_STATUS_INVALID_LUN		0x20
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci#define SRB_STATUS(status) \
3768c2ecf20Sopenharmony_ci	(status & ~(SRB_STATUS_AUTOSENSE_VALID | SRB_STATUS_QUEUE_FROZEN))
3778c2ecf20Sopenharmony_ci/*
3788c2ecf20Sopenharmony_ci * This is the end of Protocol specific defines.
3798c2ecf20Sopenharmony_ci */
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_cistatic int storvsc_ringbuffer_size = (128 * 1024);
3828c2ecf20Sopenharmony_cistatic u32 max_outstanding_req_per_channel;
3838c2ecf20Sopenharmony_cistatic int storvsc_change_queue_depth(struct scsi_device *sdev, int queue_depth);
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_cistatic int storvsc_vcpus_per_sub_channel = 4;
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_cimodule_param(storvsc_ringbuffer_size, int, S_IRUGO);
3888c2ecf20Sopenharmony_ciMODULE_PARM_DESC(storvsc_ringbuffer_size, "Ring buffer size (bytes)");
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_cimodule_param(storvsc_vcpus_per_sub_channel, int, S_IRUGO);
3918c2ecf20Sopenharmony_ciMODULE_PARM_DESC(storvsc_vcpus_per_sub_channel, "Ratio of VCPUs to subchannels");
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_cistatic int ring_avail_percent_lowater = 10;
3948c2ecf20Sopenharmony_cimodule_param(ring_avail_percent_lowater, int, S_IRUGO);
3958c2ecf20Sopenharmony_ciMODULE_PARM_DESC(ring_avail_percent_lowater,
3968c2ecf20Sopenharmony_ci		"Select a channel if available ring size > this in percent");
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ci/*
3998c2ecf20Sopenharmony_ci * Timeout in seconds for all devices managed by this driver.
4008c2ecf20Sopenharmony_ci */
4018c2ecf20Sopenharmony_cistatic int storvsc_timeout = 180;
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_SCSI_FC_ATTRS)
4048c2ecf20Sopenharmony_cistatic struct scsi_transport_template *fc_transport_template;
4058c2ecf20Sopenharmony_ci#endif
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_cistatic void storvsc_on_channel_callback(void *context);
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci#define STORVSC_MAX_LUNS_PER_TARGET			255
4108c2ecf20Sopenharmony_ci#define STORVSC_MAX_TARGETS				2
4118c2ecf20Sopenharmony_ci#define STORVSC_MAX_CHANNELS				8
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci#define STORVSC_FC_MAX_LUNS_PER_TARGET			255
4148c2ecf20Sopenharmony_ci#define STORVSC_FC_MAX_TARGETS				128
4158c2ecf20Sopenharmony_ci#define STORVSC_FC_MAX_CHANNELS				8
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci#define STORVSC_IDE_MAX_LUNS_PER_TARGET			64
4188c2ecf20Sopenharmony_ci#define STORVSC_IDE_MAX_TARGETS				1
4198c2ecf20Sopenharmony_ci#define STORVSC_IDE_MAX_CHANNELS			1
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_cistruct storvsc_cmd_request {
4228c2ecf20Sopenharmony_ci	struct scsi_cmnd *cmd;
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci	struct hv_device *device;
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_ci	/* Synchronize the request/response if needed */
4278c2ecf20Sopenharmony_ci	struct completion wait_event;
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci	struct vmbus_channel_packet_multipage_buffer mpb;
4308c2ecf20Sopenharmony_ci	struct vmbus_packet_mpb_array *payload;
4318c2ecf20Sopenharmony_ci	u32 payload_sz;
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci	struct vstor_packet vstor_packet;
4348c2ecf20Sopenharmony_ci};
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci/* A storvsc device is a device object that contains a vmbus channel */
4388c2ecf20Sopenharmony_cistruct storvsc_device {
4398c2ecf20Sopenharmony_ci	struct hv_device *device;
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci	bool	 destroy;
4428c2ecf20Sopenharmony_ci	bool	 drain_notify;
4438c2ecf20Sopenharmony_ci	atomic_t num_outstanding_req;
4448c2ecf20Sopenharmony_ci	struct Scsi_Host *host;
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci	wait_queue_head_t waiting_to_drain;
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci	/*
4498c2ecf20Sopenharmony_ci	 * Each unique Port/Path/Target represents 1 channel ie scsi
4508c2ecf20Sopenharmony_ci	 * controller. In reality, the pathid, targetid is always 0
4518c2ecf20Sopenharmony_ci	 * and the port is set by us
4528c2ecf20Sopenharmony_ci	 */
4538c2ecf20Sopenharmony_ci	unsigned int port_number;
4548c2ecf20Sopenharmony_ci	unsigned char path_id;
4558c2ecf20Sopenharmony_ci	unsigned char target_id;
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci	/*
4588c2ecf20Sopenharmony_ci	 * Max I/O, the device can support.
4598c2ecf20Sopenharmony_ci	 */
4608c2ecf20Sopenharmony_ci	u32   max_transfer_bytes;
4618c2ecf20Sopenharmony_ci	/*
4628c2ecf20Sopenharmony_ci	 * Number of sub-channels we will open.
4638c2ecf20Sopenharmony_ci	 */
4648c2ecf20Sopenharmony_ci	u16 num_sc;
4658c2ecf20Sopenharmony_ci	struct vmbus_channel **stor_chns;
4668c2ecf20Sopenharmony_ci	/*
4678c2ecf20Sopenharmony_ci	 * Mask of CPUs bound to subchannels.
4688c2ecf20Sopenharmony_ci	 */
4698c2ecf20Sopenharmony_ci	struct cpumask alloced_cpus;
4708c2ecf20Sopenharmony_ci	/*
4718c2ecf20Sopenharmony_ci	 * Serializes modifications of stor_chns[] from storvsc_do_io()
4728c2ecf20Sopenharmony_ci	 * and storvsc_change_target_cpu().
4738c2ecf20Sopenharmony_ci	 */
4748c2ecf20Sopenharmony_ci	spinlock_t lock;
4758c2ecf20Sopenharmony_ci	/* Used for vsc/vsp channel reset process */
4768c2ecf20Sopenharmony_ci	struct storvsc_cmd_request init_request;
4778c2ecf20Sopenharmony_ci	struct storvsc_cmd_request reset_request;
4788c2ecf20Sopenharmony_ci	/*
4798c2ecf20Sopenharmony_ci	 * Currently active port and node names for FC devices.
4808c2ecf20Sopenharmony_ci	 */
4818c2ecf20Sopenharmony_ci	u64 node_name;
4828c2ecf20Sopenharmony_ci	u64 port_name;
4838c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_SCSI_FC_ATTRS)
4848c2ecf20Sopenharmony_ci	struct fc_rport *rport;
4858c2ecf20Sopenharmony_ci#endif
4868c2ecf20Sopenharmony_ci};
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_cistruct hv_host_device {
4898c2ecf20Sopenharmony_ci	struct hv_device *dev;
4908c2ecf20Sopenharmony_ci	unsigned int port;
4918c2ecf20Sopenharmony_ci	unsigned char path;
4928c2ecf20Sopenharmony_ci	unsigned char target;
4938c2ecf20Sopenharmony_ci	struct workqueue_struct *handle_error_wq;
4948c2ecf20Sopenharmony_ci	struct work_struct host_scan_work;
4958c2ecf20Sopenharmony_ci	struct Scsi_Host *host;
4968c2ecf20Sopenharmony_ci};
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_cistruct storvsc_scan_work {
4998c2ecf20Sopenharmony_ci	struct work_struct work;
5008c2ecf20Sopenharmony_ci	struct Scsi_Host *host;
5018c2ecf20Sopenharmony_ci	u8 lun;
5028c2ecf20Sopenharmony_ci	u8 tgt_id;
5038c2ecf20Sopenharmony_ci};
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_cistatic void storvsc_device_scan(struct work_struct *work)
5068c2ecf20Sopenharmony_ci{
5078c2ecf20Sopenharmony_ci	struct storvsc_scan_work *wrk;
5088c2ecf20Sopenharmony_ci	struct scsi_device *sdev;
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_ci	wrk = container_of(work, struct storvsc_scan_work, work);
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_ci	sdev = scsi_device_lookup(wrk->host, 0, wrk->tgt_id, wrk->lun);
5138c2ecf20Sopenharmony_ci	if (!sdev)
5148c2ecf20Sopenharmony_ci		goto done;
5158c2ecf20Sopenharmony_ci	scsi_rescan_device(&sdev->sdev_gendev);
5168c2ecf20Sopenharmony_ci	scsi_device_put(sdev);
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_cidone:
5198c2ecf20Sopenharmony_ci	kfree(wrk);
5208c2ecf20Sopenharmony_ci}
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_cistatic void storvsc_host_scan(struct work_struct *work)
5238c2ecf20Sopenharmony_ci{
5248c2ecf20Sopenharmony_ci	struct Scsi_Host *host;
5258c2ecf20Sopenharmony_ci	struct scsi_device *sdev;
5268c2ecf20Sopenharmony_ci	struct hv_host_device *host_device =
5278c2ecf20Sopenharmony_ci		container_of(work, struct hv_host_device, host_scan_work);
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci	host = host_device->host;
5308c2ecf20Sopenharmony_ci	/*
5318c2ecf20Sopenharmony_ci	 * Before scanning the host, first check to see if any of the
5328c2ecf20Sopenharmony_ci	 * currrently known devices have been hot removed. We issue a
5338c2ecf20Sopenharmony_ci	 * "unit ready" command against all currently known devices.
5348c2ecf20Sopenharmony_ci	 * This I/O will result in an error for devices that have been
5358c2ecf20Sopenharmony_ci	 * removed. As part of handling the I/O error, we remove the device.
5368c2ecf20Sopenharmony_ci	 *
5378c2ecf20Sopenharmony_ci	 * When a LUN is added or removed, the host sends us a signal to
5388c2ecf20Sopenharmony_ci	 * scan the host. Thus we are forced to discover the LUNs that
5398c2ecf20Sopenharmony_ci	 * may have been removed this way.
5408c2ecf20Sopenharmony_ci	 */
5418c2ecf20Sopenharmony_ci	mutex_lock(&host->scan_mutex);
5428c2ecf20Sopenharmony_ci	shost_for_each_device(sdev, host)
5438c2ecf20Sopenharmony_ci		scsi_test_unit_ready(sdev, 1, 1, NULL);
5448c2ecf20Sopenharmony_ci	mutex_unlock(&host->scan_mutex);
5458c2ecf20Sopenharmony_ci	/*
5468c2ecf20Sopenharmony_ci	 * Now scan the host to discover LUNs that may have been added.
5478c2ecf20Sopenharmony_ci	 */
5488c2ecf20Sopenharmony_ci	scsi_scan_host(host);
5498c2ecf20Sopenharmony_ci}
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_cistatic void storvsc_remove_lun(struct work_struct *work)
5528c2ecf20Sopenharmony_ci{
5538c2ecf20Sopenharmony_ci	struct storvsc_scan_work *wrk;
5548c2ecf20Sopenharmony_ci	struct scsi_device *sdev;
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_ci	wrk = container_of(work, struct storvsc_scan_work, work);
5578c2ecf20Sopenharmony_ci	if (!scsi_host_get(wrk->host))
5588c2ecf20Sopenharmony_ci		goto done;
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_ci	sdev = scsi_device_lookup(wrk->host, 0, wrk->tgt_id, wrk->lun);
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_ci	if (sdev) {
5638c2ecf20Sopenharmony_ci		scsi_remove_device(sdev);
5648c2ecf20Sopenharmony_ci		scsi_device_put(sdev);
5658c2ecf20Sopenharmony_ci	}
5668c2ecf20Sopenharmony_ci	scsi_host_put(wrk->host);
5678c2ecf20Sopenharmony_ci
5688c2ecf20Sopenharmony_cidone:
5698c2ecf20Sopenharmony_ci	kfree(wrk);
5708c2ecf20Sopenharmony_ci}
5718c2ecf20Sopenharmony_ci
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_ci/*
5748c2ecf20Sopenharmony_ci * We can get incoming messages from the host that are not in response to
5758c2ecf20Sopenharmony_ci * messages that we have sent out. An example of this would be messages
5768c2ecf20Sopenharmony_ci * received by the guest to notify dynamic addition/removal of LUNs. To
5778c2ecf20Sopenharmony_ci * deal with potential race conditions where the driver may be in the
5788c2ecf20Sopenharmony_ci * midst of being unloaded when we might receive an unsolicited message
5798c2ecf20Sopenharmony_ci * from the host, we have implemented a mechanism to gurantee sequential
5808c2ecf20Sopenharmony_ci * consistency:
5818c2ecf20Sopenharmony_ci *
5828c2ecf20Sopenharmony_ci * 1) Once the device is marked as being destroyed, we will fail all
5838c2ecf20Sopenharmony_ci *    outgoing messages.
5848c2ecf20Sopenharmony_ci * 2) We permit incoming messages when the device is being destroyed,
5858c2ecf20Sopenharmony_ci *    only to properly account for messages already sent out.
5868c2ecf20Sopenharmony_ci */
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_cistatic inline struct storvsc_device *get_out_stor_device(
5898c2ecf20Sopenharmony_ci					struct hv_device *device)
5908c2ecf20Sopenharmony_ci{
5918c2ecf20Sopenharmony_ci	struct storvsc_device *stor_device;
5928c2ecf20Sopenharmony_ci
5938c2ecf20Sopenharmony_ci	stor_device = hv_get_drvdata(device);
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_ci	if (stor_device && stor_device->destroy)
5968c2ecf20Sopenharmony_ci		stor_device = NULL;
5978c2ecf20Sopenharmony_ci
5988c2ecf20Sopenharmony_ci	return stor_device;
5998c2ecf20Sopenharmony_ci}
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_ci
6028c2ecf20Sopenharmony_cistatic inline void storvsc_wait_to_drain(struct storvsc_device *dev)
6038c2ecf20Sopenharmony_ci{
6048c2ecf20Sopenharmony_ci	dev->drain_notify = true;
6058c2ecf20Sopenharmony_ci	wait_event(dev->waiting_to_drain,
6068c2ecf20Sopenharmony_ci		   atomic_read(&dev->num_outstanding_req) == 0);
6078c2ecf20Sopenharmony_ci	dev->drain_notify = false;
6088c2ecf20Sopenharmony_ci}
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_cistatic inline struct storvsc_device *get_in_stor_device(
6118c2ecf20Sopenharmony_ci					struct hv_device *device)
6128c2ecf20Sopenharmony_ci{
6138c2ecf20Sopenharmony_ci	struct storvsc_device *stor_device;
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_ci	stor_device = hv_get_drvdata(device);
6168c2ecf20Sopenharmony_ci
6178c2ecf20Sopenharmony_ci	if (!stor_device)
6188c2ecf20Sopenharmony_ci		goto get_in_err;
6198c2ecf20Sopenharmony_ci
6208c2ecf20Sopenharmony_ci	/*
6218c2ecf20Sopenharmony_ci	 * If the device is being destroyed; allow incoming
6228c2ecf20Sopenharmony_ci	 * traffic only to cleanup outstanding requests.
6238c2ecf20Sopenharmony_ci	 */
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_ci	if (stor_device->destroy  &&
6268c2ecf20Sopenharmony_ci		(atomic_read(&stor_device->num_outstanding_req) == 0))
6278c2ecf20Sopenharmony_ci		stor_device = NULL;
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_ciget_in_err:
6308c2ecf20Sopenharmony_ci	return stor_device;
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ci}
6338c2ecf20Sopenharmony_ci
6348c2ecf20Sopenharmony_cistatic void storvsc_change_target_cpu(struct vmbus_channel *channel, u32 old,
6358c2ecf20Sopenharmony_ci				      u32 new)
6368c2ecf20Sopenharmony_ci{
6378c2ecf20Sopenharmony_ci	struct storvsc_device *stor_device;
6388c2ecf20Sopenharmony_ci	struct vmbus_channel *cur_chn;
6398c2ecf20Sopenharmony_ci	bool old_is_alloced = false;
6408c2ecf20Sopenharmony_ci	struct hv_device *device;
6418c2ecf20Sopenharmony_ci	unsigned long flags;
6428c2ecf20Sopenharmony_ci	int cpu;
6438c2ecf20Sopenharmony_ci
6448c2ecf20Sopenharmony_ci	device = channel->primary_channel ?
6458c2ecf20Sopenharmony_ci			channel->primary_channel->device_obj
6468c2ecf20Sopenharmony_ci				: channel->device_obj;
6478c2ecf20Sopenharmony_ci	stor_device = get_out_stor_device(device);
6488c2ecf20Sopenharmony_ci	if (!stor_device)
6498c2ecf20Sopenharmony_ci		return;
6508c2ecf20Sopenharmony_ci
6518c2ecf20Sopenharmony_ci	/* See storvsc_do_io() -> get_og_chn(). */
6528c2ecf20Sopenharmony_ci	spin_lock_irqsave(&stor_device->lock, flags);
6538c2ecf20Sopenharmony_ci
6548c2ecf20Sopenharmony_ci	/*
6558c2ecf20Sopenharmony_ci	 * Determines if the storvsc device has other channels assigned to
6568c2ecf20Sopenharmony_ci	 * the "old" CPU to update the alloced_cpus mask and the stor_chns
6578c2ecf20Sopenharmony_ci	 * array.
6588c2ecf20Sopenharmony_ci	 */
6598c2ecf20Sopenharmony_ci	if (device->channel != channel && device->channel->target_cpu == old) {
6608c2ecf20Sopenharmony_ci		cur_chn = device->channel;
6618c2ecf20Sopenharmony_ci		old_is_alloced = true;
6628c2ecf20Sopenharmony_ci		goto old_is_alloced;
6638c2ecf20Sopenharmony_ci	}
6648c2ecf20Sopenharmony_ci	list_for_each_entry(cur_chn, &device->channel->sc_list, sc_list) {
6658c2ecf20Sopenharmony_ci		if (cur_chn == channel)
6668c2ecf20Sopenharmony_ci			continue;
6678c2ecf20Sopenharmony_ci		if (cur_chn->target_cpu == old) {
6688c2ecf20Sopenharmony_ci			old_is_alloced = true;
6698c2ecf20Sopenharmony_ci			goto old_is_alloced;
6708c2ecf20Sopenharmony_ci		}
6718c2ecf20Sopenharmony_ci	}
6728c2ecf20Sopenharmony_ci
6738c2ecf20Sopenharmony_ciold_is_alloced:
6748c2ecf20Sopenharmony_ci	if (old_is_alloced)
6758c2ecf20Sopenharmony_ci		WRITE_ONCE(stor_device->stor_chns[old], cur_chn);
6768c2ecf20Sopenharmony_ci	else
6778c2ecf20Sopenharmony_ci		cpumask_clear_cpu(old, &stor_device->alloced_cpus);
6788c2ecf20Sopenharmony_ci
6798c2ecf20Sopenharmony_ci	/* "Flush" the stor_chns array. */
6808c2ecf20Sopenharmony_ci	for_each_possible_cpu(cpu) {
6818c2ecf20Sopenharmony_ci		if (stor_device->stor_chns[cpu] && !cpumask_test_cpu(
6828c2ecf20Sopenharmony_ci					cpu, &stor_device->alloced_cpus))
6838c2ecf20Sopenharmony_ci			WRITE_ONCE(stor_device->stor_chns[cpu], NULL);
6848c2ecf20Sopenharmony_ci	}
6858c2ecf20Sopenharmony_ci
6868c2ecf20Sopenharmony_ci	WRITE_ONCE(stor_device->stor_chns[new], channel);
6878c2ecf20Sopenharmony_ci	cpumask_set_cpu(new, &stor_device->alloced_cpus);
6888c2ecf20Sopenharmony_ci
6898c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&stor_device->lock, flags);
6908c2ecf20Sopenharmony_ci}
6918c2ecf20Sopenharmony_ci
6928c2ecf20Sopenharmony_cistatic void handle_sc_creation(struct vmbus_channel *new_sc)
6938c2ecf20Sopenharmony_ci{
6948c2ecf20Sopenharmony_ci	struct hv_device *device = new_sc->primary_channel->device_obj;
6958c2ecf20Sopenharmony_ci	struct device *dev = &device->device;
6968c2ecf20Sopenharmony_ci	struct storvsc_device *stor_device;
6978c2ecf20Sopenharmony_ci	struct vmstorage_channel_properties props;
6988c2ecf20Sopenharmony_ci	int ret;
6998c2ecf20Sopenharmony_ci
7008c2ecf20Sopenharmony_ci	stor_device = get_out_stor_device(device);
7018c2ecf20Sopenharmony_ci	if (!stor_device)
7028c2ecf20Sopenharmony_ci		return;
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_ci	memset(&props, 0, sizeof(struct vmstorage_channel_properties));
7058c2ecf20Sopenharmony_ci
7068c2ecf20Sopenharmony_ci	ret = vmbus_open(new_sc,
7078c2ecf20Sopenharmony_ci			 storvsc_ringbuffer_size,
7088c2ecf20Sopenharmony_ci			 storvsc_ringbuffer_size,
7098c2ecf20Sopenharmony_ci			 (void *)&props,
7108c2ecf20Sopenharmony_ci			 sizeof(struct vmstorage_channel_properties),
7118c2ecf20Sopenharmony_ci			 storvsc_on_channel_callback, new_sc);
7128c2ecf20Sopenharmony_ci
7138c2ecf20Sopenharmony_ci	/* In case vmbus_open() fails, we don't use the sub-channel. */
7148c2ecf20Sopenharmony_ci	if (ret != 0) {
7158c2ecf20Sopenharmony_ci		dev_err(dev, "Failed to open sub-channel: err=%d\n", ret);
7168c2ecf20Sopenharmony_ci		return;
7178c2ecf20Sopenharmony_ci	}
7188c2ecf20Sopenharmony_ci
7198c2ecf20Sopenharmony_ci	new_sc->change_target_cpu_callback = storvsc_change_target_cpu;
7208c2ecf20Sopenharmony_ci
7218c2ecf20Sopenharmony_ci	/* Add the sub-channel to the array of available channels. */
7228c2ecf20Sopenharmony_ci	stor_device->stor_chns[new_sc->target_cpu] = new_sc;
7238c2ecf20Sopenharmony_ci	cpumask_set_cpu(new_sc->target_cpu, &stor_device->alloced_cpus);
7248c2ecf20Sopenharmony_ci}
7258c2ecf20Sopenharmony_ci
7268c2ecf20Sopenharmony_cistatic void  handle_multichannel_storage(struct hv_device *device, int max_chns)
7278c2ecf20Sopenharmony_ci{
7288c2ecf20Sopenharmony_ci	struct device *dev = &device->device;
7298c2ecf20Sopenharmony_ci	struct storvsc_device *stor_device;
7308c2ecf20Sopenharmony_ci	int num_sc;
7318c2ecf20Sopenharmony_ci	struct storvsc_cmd_request *request;
7328c2ecf20Sopenharmony_ci	struct vstor_packet *vstor_packet;
7338c2ecf20Sopenharmony_ci	int ret, t;
7348c2ecf20Sopenharmony_ci
7358c2ecf20Sopenharmony_ci	/*
7368c2ecf20Sopenharmony_ci	 * If the number of CPUs is artificially restricted, such as
7378c2ecf20Sopenharmony_ci	 * with maxcpus=1 on the kernel boot line, Hyper-V could offer
7388c2ecf20Sopenharmony_ci	 * sub-channels >= the number of CPUs. These sub-channels
7398c2ecf20Sopenharmony_ci	 * should not be created. The primary channel is already created
7408c2ecf20Sopenharmony_ci	 * and assigned to one CPU, so check against # CPUs - 1.
7418c2ecf20Sopenharmony_ci	 */
7428c2ecf20Sopenharmony_ci	num_sc = min((int)(num_online_cpus() - 1), max_chns);
7438c2ecf20Sopenharmony_ci	if (!num_sc)
7448c2ecf20Sopenharmony_ci		return;
7458c2ecf20Sopenharmony_ci
7468c2ecf20Sopenharmony_ci	stor_device = get_out_stor_device(device);
7478c2ecf20Sopenharmony_ci	if (!stor_device)
7488c2ecf20Sopenharmony_ci		return;
7498c2ecf20Sopenharmony_ci
7508c2ecf20Sopenharmony_ci	stor_device->num_sc = num_sc;
7518c2ecf20Sopenharmony_ci	request = &stor_device->init_request;
7528c2ecf20Sopenharmony_ci	vstor_packet = &request->vstor_packet;
7538c2ecf20Sopenharmony_ci
7548c2ecf20Sopenharmony_ci	/*
7558c2ecf20Sopenharmony_ci	 * Establish a handler for dealing with subchannels.
7568c2ecf20Sopenharmony_ci	 */
7578c2ecf20Sopenharmony_ci	vmbus_set_sc_create_callback(device->channel, handle_sc_creation);
7588c2ecf20Sopenharmony_ci
7598c2ecf20Sopenharmony_ci	/*
7608c2ecf20Sopenharmony_ci	 * Request the host to create sub-channels.
7618c2ecf20Sopenharmony_ci	 */
7628c2ecf20Sopenharmony_ci	memset(request, 0, sizeof(struct storvsc_cmd_request));
7638c2ecf20Sopenharmony_ci	init_completion(&request->wait_event);
7648c2ecf20Sopenharmony_ci	vstor_packet->operation = VSTOR_OPERATION_CREATE_SUB_CHANNELS;
7658c2ecf20Sopenharmony_ci	vstor_packet->flags = REQUEST_COMPLETION_FLAG;
7668c2ecf20Sopenharmony_ci	vstor_packet->sub_channel_count = num_sc;
7678c2ecf20Sopenharmony_ci
7688c2ecf20Sopenharmony_ci	ret = vmbus_sendpacket(device->channel, vstor_packet,
7698c2ecf20Sopenharmony_ci			       (sizeof(struct vstor_packet) -
7708c2ecf20Sopenharmony_ci			       vmscsi_size_delta),
7718c2ecf20Sopenharmony_ci			       (unsigned long)request,
7728c2ecf20Sopenharmony_ci			       VM_PKT_DATA_INBAND,
7738c2ecf20Sopenharmony_ci			       VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
7748c2ecf20Sopenharmony_ci
7758c2ecf20Sopenharmony_ci	if (ret != 0) {
7768c2ecf20Sopenharmony_ci		dev_err(dev, "Failed to create sub-channel: err=%d\n", ret);
7778c2ecf20Sopenharmony_ci		return;
7788c2ecf20Sopenharmony_ci	}
7798c2ecf20Sopenharmony_ci
7808c2ecf20Sopenharmony_ci	t = wait_for_completion_timeout(&request->wait_event, 10*HZ);
7818c2ecf20Sopenharmony_ci	if (t == 0) {
7828c2ecf20Sopenharmony_ci		dev_err(dev, "Failed to create sub-channel: timed out\n");
7838c2ecf20Sopenharmony_ci		return;
7848c2ecf20Sopenharmony_ci	}
7858c2ecf20Sopenharmony_ci
7868c2ecf20Sopenharmony_ci	if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO ||
7878c2ecf20Sopenharmony_ci	    vstor_packet->status != 0) {
7888c2ecf20Sopenharmony_ci		dev_err(dev, "Failed to create sub-channel: op=%d, sts=%d\n",
7898c2ecf20Sopenharmony_ci			vstor_packet->operation, vstor_packet->status);
7908c2ecf20Sopenharmony_ci		return;
7918c2ecf20Sopenharmony_ci	}
7928c2ecf20Sopenharmony_ci
7938c2ecf20Sopenharmony_ci	/*
7948c2ecf20Sopenharmony_ci	 * We need to do nothing here, because vmbus_process_offer()
7958c2ecf20Sopenharmony_ci	 * invokes channel->sc_creation_callback, which will open and use
7968c2ecf20Sopenharmony_ci	 * the sub-channel(s).
7978c2ecf20Sopenharmony_ci	 */
7988c2ecf20Sopenharmony_ci}
7998c2ecf20Sopenharmony_ci
8008c2ecf20Sopenharmony_cistatic void cache_wwn(struct storvsc_device *stor_device,
8018c2ecf20Sopenharmony_ci		      struct vstor_packet *vstor_packet)
8028c2ecf20Sopenharmony_ci{
8038c2ecf20Sopenharmony_ci	/*
8048c2ecf20Sopenharmony_ci	 * Cache the currently active port and node ww names.
8058c2ecf20Sopenharmony_ci	 */
8068c2ecf20Sopenharmony_ci	if (vstor_packet->wwn_packet.primary_active) {
8078c2ecf20Sopenharmony_ci		stor_device->node_name =
8088c2ecf20Sopenharmony_ci			wwn_to_u64(vstor_packet->wwn_packet.primary_node_wwn);
8098c2ecf20Sopenharmony_ci		stor_device->port_name =
8108c2ecf20Sopenharmony_ci			wwn_to_u64(vstor_packet->wwn_packet.primary_port_wwn);
8118c2ecf20Sopenharmony_ci	} else {
8128c2ecf20Sopenharmony_ci		stor_device->node_name =
8138c2ecf20Sopenharmony_ci			wwn_to_u64(vstor_packet->wwn_packet.secondary_node_wwn);
8148c2ecf20Sopenharmony_ci		stor_device->port_name =
8158c2ecf20Sopenharmony_ci			wwn_to_u64(vstor_packet->wwn_packet.secondary_port_wwn);
8168c2ecf20Sopenharmony_ci	}
8178c2ecf20Sopenharmony_ci}
8188c2ecf20Sopenharmony_ci
8198c2ecf20Sopenharmony_ci
8208c2ecf20Sopenharmony_cistatic int storvsc_execute_vstor_op(struct hv_device *device,
8218c2ecf20Sopenharmony_ci				    struct storvsc_cmd_request *request,
8228c2ecf20Sopenharmony_ci				    bool status_check)
8238c2ecf20Sopenharmony_ci{
8248c2ecf20Sopenharmony_ci	struct vstor_packet *vstor_packet;
8258c2ecf20Sopenharmony_ci	int ret, t;
8268c2ecf20Sopenharmony_ci
8278c2ecf20Sopenharmony_ci	vstor_packet = &request->vstor_packet;
8288c2ecf20Sopenharmony_ci
8298c2ecf20Sopenharmony_ci	init_completion(&request->wait_event);
8308c2ecf20Sopenharmony_ci	vstor_packet->flags = REQUEST_COMPLETION_FLAG;
8318c2ecf20Sopenharmony_ci
8328c2ecf20Sopenharmony_ci	ret = vmbus_sendpacket(device->channel, vstor_packet,
8338c2ecf20Sopenharmony_ci			       (sizeof(struct vstor_packet) -
8348c2ecf20Sopenharmony_ci			       vmscsi_size_delta),
8358c2ecf20Sopenharmony_ci			       (unsigned long)request,
8368c2ecf20Sopenharmony_ci			       VM_PKT_DATA_INBAND,
8378c2ecf20Sopenharmony_ci			       VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
8388c2ecf20Sopenharmony_ci	if (ret != 0)
8398c2ecf20Sopenharmony_ci		return ret;
8408c2ecf20Sopenharmony_ci
8418c2ecf20Sopenharmony_ci	t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
8428c2ecf20Sopenharmony_ci	if (t == 0)
8438c2ecf20Sopenharmony_ci		return -ETIMEDOUT;
8448c2ecf20Sopenharmony_ci
8458c2ecf20Sopenharmony_ci	if (!status_check)
8468c2ecf20Sopenharmony_ci		return ret;
8478c2ecf20Sopenharmony_ci
8488c2ecf20Sopenharmony_ci	if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO ||
8498c2ecf20Sopenharmony_ci	    vstor_packet->status != 0)
8508c2ecf20Sopenharmony_ci		return -EINVAL;
8518c2ecf20Sopenharmony_ci
8528c2ecf20Sopenharmony_ci	return ret;
8538c2ecf20Sopenharmony_ci}
8548c2ecf20Sopenharmony_ci
8558c2ecf20Sopenharmony_cistatic int storvsc_channel_init(struct hv_device *device, bool is_fc)
8568c2ecf20Sopenharmony_ci{
8578c2ecf20Sopenharmony_ci	struct storvsc_device *stor_device;
8588c2ecf20Sopenharmony_ci	struct storvsc_cmd_request *request;
8598c2ecf20Sopenharmony_ci	struct vstor_packet *vstor_packet;
8608c2ecf20Sopenharmony_ci	int ret, i;
8618c2ecf20Sopenharmony_ci	int max_chns;
8628c2ecf20Sopenharmony_ci	bool process_sub_channels = false;
8638c2ecf20Sopenharmony_ci
8648c2ecf20Sopenharmony_ci	stor_device = get_out_stor_device(device);
8658c2ecf20Sopenharmony_ci	if (!stor_device)
8668c2ecf20Sopenharmony_ci		return -ENODEV;
8678c2ecf20Sopenharmony_ci
8688c2ecf20Sopenharmony_ci	request = &stor_device->init_request;
8698c2ecf20Sopenharmony_ci	vstor_packet = &request->vstor_packet;
8708c2ecf20Sopenharmony_ci
8718c2ecf20Sopenharmony_ci	/*
8728c2ecf20Sopenharmony_ci	 * Now, initiate the vsc/vsp initialization protocol on the open
8738c2ecf20Sopenharmony_ci	 * channel
8748c2ecf20Sopenharmony_ci	 */
8758c2ecf20Sopenharmony_ci	memset(request, 0, sizeof(struct storvsc_cmd_request));
8768c2ecf20Sopenharmony_ci	vstor_packet->operation = VSTOR_OPERATION_BEGIN_INITIALIZATION;
8778c2ecf20Sopenharmony_ci	ret = storvsc_execute_vstor_op(device, request, true);
8788c2ecf20Sopenharmony_ci	if (ret)
8798c2ecf20Sopenharmony_ci		return ret;
8808c2ecf20Sopenharmony_ci	/*
8818c2ecf20Sopenharmony_ci	 * Query host supported protocol version.
8828c2ecf20Sopenharmony_ci	 */
8838c2ecf20Sopenharmony_ci
8848c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(vmstor_protocols); i++) {
8858c2ecf20Sopenharmony_ci		/* reuse the packet for version range supported */
8868c2ecf20Sopenharmony_ci		memset(vstor_packet, 0, sizeof(struct vstor_packet));
8878c2ecf20Sopenharmony_ci		vstor_packet->operation =
8888c2ecf20Sopenharmony_ci			VSTOR_OPERATION_QUERY_PROTOCOL_VERSION;
8898c2ecf20Sopenharmony_ci
8908c2ecf20Sopenharmony_ci		vstor_packet->version.major_minor =
8918c2ecf20Sopenharmony_ci			vmstor_protocols[i].protocol_version;
8928c2ecf20Sopenharmony_ci
8938c2ecf20Sopenharmony_ci		/*
8948c2ecf20Sopenharmony_ci		 * The revision number is only used in Windows; set it to 0.
8958c2ecf20Sopenharmony_ci		 */
8968c2ecf20Sopenharmony_ci		vstor_packet->version.revision = 0;
8978c2ecf20Sopenharmony_ci		ret = storvsc_execute_vstor_op(device, request, false);
8988c2ecf20Sopenharmony_ci		if (ret != 0)
8998c2ecf20Sopenharmony_ci			return ret;
9008c2ecf20Sopenharmony_ci
9018c2ecf20Sopenharmony_ci		if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO)
9028c2ecf20Sopenharmony_ci			return -EINVAL;
9038c2ecf20Sopenharmony_ci
9048c2ecf20Sopenharmony_ci		if (vstor_packet->status == 0) {
9058c2ecf20Sopenharmony_ci			vmstor_proto_version =
9068c2ecf20Sopenharmony_ci				vmstor_protocols[i].protocol_version;
9078c2ecf20Sopenharmony_ci
9088c2ecf20Sopenharmony_ci			sense_buffer_size =
9098c2ecf20Sopenharmony_ci				vmstor_protocols[i].sense_buffer_size;
9108c2ecf20Sopenharmony_ci
9118c2ecf20Sopenharmony_ci			vmscsi_size_delta =
9128c2ecf20Sopenharmony_ci				vmstor_protocols[i].vmscsi_size_delta;
9138c2ecf20Sopenharmony_ci
9148c2ecf20Sopenharmony_ci			break;
9158c2ecf20Sopenharmony_ci		}
9168c2ecf20Sopenharmony_ci	}
9178c2ecf20Sopenharmony_ci
9188c2ecf20Sopenharmony_ci	if (vstor_packet->status != 0)
9198c2ecf20Sopenharmony_ci		return -EINVAL;
9208c2ecf20Sopenharmony_ci
9218c2ecf20Sopenharmony_ci
9228c2ecf20Sopenharmony_ci	memset(vstor_packet, 0, sizeof(struct vstor_packet));
9238c2ecf20Sopenharmony_ci	vstor_packet->operation = VSTOR_OPERATION_QUERY_PROPERTIES;
9248c2ecf20Sopenharmony_ci	ret = storvsc_execute_vstor_op(device, request, true);
9258c2ecf20Sopenharmony_ci	if (ret != 0)
9268c2ecf20Sopenharmony_ci		return ret;
9278c2ecf20Sopenharmony_ci
9288c2ecf20Sopenharmony_ci	/*
9298c2ecf20Sopenharmony_ci	 * Check to see if multi-channel support is there.
9308c2ecf20Sopenharmony_ci	 * Hosts that implement protocol version of 5.1 and above
9318c2ecf20Sopenharmony_ci	 * support multi-channel.
9328c2ecf20Sopenharmony_ci	 */
9338c2ecf20Sopenharmony_ci	max_chns = vstor_packet->storage_channel_properties.max_channel_cnt;
9348c2ecf20Sopenharmony_ci
9358c2ecf20Sopenharmony_ci	/*
9368c2ecf20Sopenharmony_ci	 * Allocate state to manage the sub-channels.
9378c2ecf20Sopenharmony_ci	 * We allocate an array based on the numbers of possible CPUs
9388c2ecf20Sopenharmony_ci	 * (Hyper-V does not support cpu online/offline).
9398c2ecf20Sopenharmony_ci	 * This Array will be sparseley populated with unique
9408c2ecf20Sopenharmony_ci	 * channels - primary + sub-channels.
9418c2ecf20Sopenharmony_ci	 * We will however populate all the slots to evenly distribute
9428c2ecf20Sopenharmony_ci	 * the load.
9438c2ecf20Sopenharmony_ci	 */
9448c2ecf20Sopenharmony_ci	stor_device->stor_chns = kcalloc(num_possible_cpus(), sizeof(void *),
9458c2ecf20Sopenharmony_ci					 GFP_KERNEL);
9468c2ecf20Sopenharmony_ci	if (stor_device->stor_chns == NULL)
9478c2ecf20Sopenharmony_ci		return -ENOMEM;
9488c2ecf20Sopenharmony_ci
9498c2ecf20Sopenharmony_ci	device->channel->change_target_cpu_callback = storvsc_change_target_cpu;
9508c2ecf20Sopenharmony_ci
9518c2ecf20Sopenharmony_ci	stor_device->stor_chns[device->channel->target_cpu] = device->channel;
9528c2ecf20Sopenharmony_ci	cpumask_set_cpu(device->channel->target_cpu,
9538c2ecf20Sopenharmony_ci			&stor_device->alloced_cpus);
9548c2ecf20Sopenharmony_ci
9558c2ecf20Sopenharmony_ci	if (vmstor_proto_version >= VMSTOR_PROTO_VERSION_WIN8) {
9568c2ecf20Sopenharmony_ci		if (vstor_packet->storage_channel_properties.flags &
9578c2ecf20Sopenharmony_ci		    STORAGE_CHANNEL_SUPPORTS_MULTI_CHANNEL)
9588c2ecf20Sopenharmony_ci			process_sub_channels = true;
9598c2ecf20Sopenharmony_ci	}
9608c2ecf20Sopenharmony_ci	stor_device->max_transfer_bytes =
9618c2ecf20Sopenharmony_ci		vstor_packet->storage_channel_properties.max_transfer_bytes;
9628c2ecf20Sopenharmony_ci
9638c2ecf20Sopenharmony_ci	if (!is_fc)
9648c2ecf20Sopenharmony_ci		goto done;
9658c2ecf20Sopenharmony_ci
9668c2ecf20Sopenharmony_ci	/*
9678c2ecf20Sopenharmony_ci	 * For FC devices retrieve FC HBA data.
9688c2ecf20Sopenharmony_ci	 */
9698c2ecf20Sopenharmony_ci	memset(vstor_packet, 0, sizeof(struct vstor_packet));
9708c2ecf20Sopenharmony_ci	vstor_packet->operation = VSTOR_OPERATION_FCHBA_DATA;
9718c2ecf20Sopenharmony_ci	ret = storvsc_execute_vstor_op(device, request, true);
9728c2ecf20Sopenharmony_ci	if (ret != 0)
9738c2ecf20Sopenharmony_ci		return ret;
9748c2ecf20Sopenharmony_ci
9758c2ecf20Sopenharmony_ci	/*
9768c2ecf20Sopenharmony_ci	 * Cache the currently active port and node ww names.
9778c2ecf20Sopenharmony_ci	 */
9788c2ecf20Sopenharmony_ci	cache_wwn(stor_device, vstor_packet);
9798c2ecf20Sopenharmony_ci
9808c2ecf20Sopenharmony_cidone:
9818c2ecf20Sopenharmony_ci
9828c2ecf20Sopenharmony_ci	memset(vstor_packet, 0, sizeof(struct vstor_packet));
9838c2ecf20Sopenharmony_ci	vstor_packet->operation = VSTOR_OPERATION_END_INITIALIZATION;
9848c2ecf20Sopenharmony_ci	ret = storvsc_execute_vstor_op(device, request, true);
9858c2ecf20Sopenharmony_ci	if (ret != 0)
9868c2ecf20Sopenharmony_ci		return ret;
9878c2ecf20Sopenharmony_ci
9888c2ecf20Sopenharmony_ci	if (process_sub_channels)
9898c2ecf20Sopenharmony_ci		handle_multichannel_storage(device, max_chns);
9908c2ecf20Sopenharmony_ci
9918c2ecf20Sopenharmony_ci	return ret;
9928c2ecf20Sopenharmony_ci}
9938c2ecf20Sopenharmony_ci
9948c2ecf20Sopenharmony_cistatic void storvsc_handle_error(struct vmscsi_request *vm_srb,
9958c2ecf20Sopenharmony_ci				struct scsi_cmnd *scmnd,
9968c2ecf20Sopenharmony_ci				struct Scsi_Host *host,
9978c2ecf20Sopenharmony_ci				u8 asc, u8 ascq)
9988c2ecf20Sopenharmony_ci{
9998c2ecf20Sopenharmony_ci	struct storvsc_scan_work *wrk;
10008c2ecf20Sopenharmony_ci	void (*process_err_fn)(struct work_struct *work);
10018c2ecf20Sopenharmony_ci	struct hv_host_device *host_dev = shost_priv(host);
10028c2ecf20Sopenharmony_ci
10038c2ecf20Sopenharmony_ci	switch (SRB_STATUS(vm_srb->srb_status)) {
10048c2ecf20Sopenharmony_ci	case SRB_STATUS_ERROR:
10058c2ecf20Sopenharmony_ci	case SRB_STATUS_ABORTED:
10068c2ecf20Sopenharmony_ci	case SRB_STATUS_INVALID_REQUEST:
10078c2ecf20Sopenharmony_ci		if (vm_srb->srb_status & SRB_STATUS_AUTOSENSE_VALID) {
10088c2ecf20Sopenharmony_ci			/* Check for capacity change */
10098c2ecf20Sopenharmony_ci			if ((asc == 0x2a) && (ascq == 0x9)) {
10108c2ecf20Sopenharmony_ci				process_err_fn = storvsc_device_scan;
10118c2ecf20Sopenharmony_ci				/* Retry the I/O that triggered this. */
10128c2ecf20Sopenharmony_ci				set_host_byte(scmnd, DID_REQUEUE);
10138c2ecf20Sopenharmony_ci				goto do_work;
10148c2ecf20Sopenharmony_ci			}
10158c2ecf20Sopenharmony_ci
10168c2ecf20Sopenharmony_ci			/*
10178c2ecf20Sopenharmony_ci			 * Check for "Operating parameters have changed"
10188c2ecf20Sopenharmony_ci			 * due to Hyper-V changing the VHD/VHDX BlockSize
10198c2ecf20Sopenharmony_ci			 * when adding/removing a differencing disk. This
10208c2ecf20Sopenharmony_ci			 * causes discard_granularity to change, so do a
10218c2ecf20Sopenharmony_ci			 * rescan to pick up the new granularity. We don't
10228c2ecf20Sopenharmony_ci			 * want scsi_report_sense() to output a message
10238c2ecf20Sopenharmony_ci			 * that a sysadmin wouldn't know what to do with.
10248c2ecf20Sopenharmony_ci			 */
10258c2ecf20Sopenharmony_ci			if ((asc == 0x3f) && (ascq != 0x03) &&
10268c2ecf20Sopenharmony_ci					(ascq != 0x0e)) {
10278c2ecf20Sopenharmony_ci				process_err_fn = storvsc_device_scan;
10288c2ecf20Sopenharmony_ci				set_host_byte(scmnd, DID_REQUEUE);
10298c2ecf20Sopenharmony_ci				goto do_work;
10308c2ecf20Sopenharmony_ci			}
10318c2ecf20Sopenharmony_ci
10328c2ecf20Sopenharmony_ci			/*
10338c2ecf20Sopenharmony_ci			 * Otherwise, let upper layer deal with the
10348c2ecf20Sopenharmony_ci			 * error when sense message is present
10358c2ecf20Sopenharmony_ci			 */
10368c2ecf20Sopenharmony_ci			return;
10378c2ecf20Sopenharmony_ci		}
10388c2ecf20Sopenharmony_ci
10398c2ecf20Sopenharmony_ci		/*
10408c2ecf20Sopenharmony_ci		 * If there is an error; offline the device since all
10418c2ecf20Sopenharmony_ci		 * error recovery strategies would have already been
10428c2ecf20Sopenharmony_ci		 * deployed on the host side. However, if the command
10438c2ecf20Sopenharmony_ci		 * were a pass-through command deal with it appropriately.
10448c2ecf20Sopenharmony_ci		 */
10458c2ecf20Sopenharmony_ci		switch (scmnd->cmnd[0]) {
10468c2ecf20Sopenharmony_ci		case ATA_16:
10478c2ecf20Sopenharmony_ci		case ATA_12:
10488c2ecf20Sopenharmony_ci			set_host_byte(scmnd, DID_PASSTHROUGH);
10498c2ecf20Sopenharmony_ci			break;
10508c2ecf20Sopenharmony_ci		/*
10518c2ecf20Sopenharmony_ci		 * On some Hyper-V hosts TEST_UNIT_READY command can
10528c2ecf20Sopenharmony_ci		 * return SRB_STATUS_ERROR. Let the upper level code
10538c2ecf20Sopenharmony_ci		 * deal with it based on the sense information.
10548c2ecf20Sopenharmony_ci		 */
10558c2ecf20Sopenharmony_ci		case TEST_UNIT_READY:
10568c2ecf20Sopenharmony_ci			break;
10578c2ecf20Sopenharmony_ci		default:
10588c2ecf20Sopenharmony_ci			set_host_byte(scmnd, DID_ERROR);
10598c2ecf20Sopenharmony_ci		}
10608c2ecf20Sopenharmony_ci		return;
10618c2ecf20Sopenharmony_ci
10628c2ecf20Sopenharmony_ci	case SRB_STATUS_INVALID_LUN:
10638c2ecf20Sopenharmony_ci		set_host_byte(scmnd, DID_NO_CONNECT);
10648c2ecf20Sopenharmony_ci		process_err_fn = storvsc_remove_lun;
10658c2ecf20Sopenharmony_ci		goto do_work;
10668c2ecf20Sopenharmony_ci
10678c2ecf20Sopenharmony_ci	}
10688c2ecf20Sopenharmony_ci	return;
10698c2ecf20Sopenharmony_ci
10708c2ecf20Sopenharmony_cido_work:
10718c2ecf20Sopenharmony_ci	/*
10728c2ecf20Sopenharmony_ci	 * We need to schedule work to process this error; schedule it.
10738c2ecf20Sopenharmony_ci	 */
10748c2ecf20Sopenharmony_ci	wrk = kmalloc(sizeof(struct storvsc_scan_work), GFP_ATOMIC);
10758c2ecf20Sopenharmony_ci	if (!wrk) {
10768c2ecf20Sopenharmony_ci		set_host_byte(scmnd, DID_TARGET_FAILURE);
10778c2ecf20Sopenharmony_ci		return;
10788c2ecf20Sopenharmony_ci	}
10798c2ecf20Sopenharmony_ci
10808c2ecf20Sopenharmony_ci	wrk->host = host;
10818c2ecf20Sopenharmony_ci	wrk->lun = vm_srb->lun;
10828c2ecf20Sopenharmony_ci	wrk->tgt_id = vm_srb->target_id;
10838c2ecf20Sopenharmony_ci	INIT_WORK(&wrk->work, process_err_fn);
10848c2ecf20Sopenharmony_ci	queue_work(host_dev->handle_error_wq, &wrk->work);
10858c2ecf20Sopenharmony_ci}
10868c2ecf20Sopenharmony_ci
10878c2ecf20Sopenharmony_ci
10888c2ecf20Sopenharmony_cistatic void storvsc_command_completion(struct storvsc_cmd_request *cmd_request,
10898c2ecf20Sopenharmony_ci				       struct storvsc_device *stor_dev)
10908c2ecf20Sopenharmony_ci{
10918c2ecf20Sopenharmony_ci	struct scsi_cmnd *scmnd = cmd_request->cmd;
10928c2ecf20Sopenharmony_ci	struct scsi_sense_hdr sense_hdr;
10938c2ecf20Sopenharmony_ci	struct vmscsi_request *vm_srb;
10948c2ecf20Sopenharmony_ci	u32 data_transfer_length;
10958c2ecf20Sopenharmony_ci	struct Scsi_Host *host;
10968c2ecf20Sopenharmony_ci	u32 payload_sz = cmd_request->payload_sz;
10978c2ecf20Sopenharmony_ci	void *payload = cmd_request->payload;
10988c2ecf20Sopenharmony_ci
10998c2ecf20Sopenharmony_ci	host = stor_dev->host;
11008c2ecf20Sopenharmony_ci
11018c2ecf20Sopenharmony_ci	vm_srb = &cmd_request->vstor_packet.vm_srb;
11028c2ecf20Sopenharmony_ci	data_transfer_length = vm_srb->data_transfer_length;
11038c2ecf20Sopenharmony_ci
11048c2ecf20Sopenharmony_ci	scmnd->result = vm_srb->scsi_status;
11058c2ecf20Sopenharmony_ci
11068c2ecf20Sopenharmony_ci	if (scmnd->result) {
11078c2ecf20Sopenharmony_ci		if (scsi_normalize_sense(scmnd->sense_buffer,
11088c2ecf20Sopenharmony_ci				SCSI_SENSE_BUFFERSIZE, &sense_hdr) &&
11098c2ecf20Sopenharmony_ci		    !(sense_hdr.sense_key == NOT_READY &&
11108c2ecf20Sopenharmony_ci				 sense_hdr.asc == 0x03A) &&
11118c2ecf20Sopenharmony_ci		    do_logging(STORVSC_LOGGING_ERROR))
11128c2ecf20Sopenharmony_ci			scsi_print_sense_hdr(scmnd->device, "storvsc",
11138c2ecf20Sopenharmony_ci					     &sense_hdr);
11148c2ecf20Sopenharmony_ci	}
11158c2ecf20Sopenharmony_ci
11168c2ecf20Sopenharmony_ci	if (vm_srb->srb_status != SRB_STATUS_SUCCESS) {
11178c2ecf20Sopenharmony_ci		storvsc_handle_error(vm_srb, scmnd, host, sense_hdr.asc,
11188c2ecf20Sopenharmony_ci					 sense_hdr.ascq);
11198c2ecf20Sopenharmony_ci		/*
11208c2ecf20Sopenharmony_ci		 * The Windows driver set data_transfer_length on
11218c2ecf20Sopenharmony_ci		 * SRB_STATUS_DATA_OVERRUN. On other errors, this value
11228c2ecf20Sopenharmony_ci		 * is untouched.  In these cases we set it to 0.
11238c2ecf20Sopenharmony_ci		 */
11248c2ecf20Sopenharmony_ci		if (vm_srb->srb_status != SRB_STATUS_DATA_OVERRUN)
11258c2ecf20Sopenharmony_ci			data_transfer_length = 0;
11268c2ecf20Sopenharmony_ci	}
11278c2ecf20Sopenharmony_ci
11288c2ecf20Sopenharmony_ci	/* Validate data_transfer_length (from Hyper-V) */
11298c2ecf20Sopenharmony_ci	if (data_transfer_length > cmd_request->payload->range.len)
11308c2ecf20Sopenharmony_ci		data_transfer_length = cmd_request->payload->range.len;
11318c2ecf20Sopenharmony_ci
11328c2ecf20Sopenharmony_ci	scsi_set_resid(scmnd,
11338c2ecf20Sopenharmony_ci		cmd_request->payload->range.len - data_transfer_length);
11348c2ecf20Sopenharmony_ci
11358c2ecf20Sopenharmony_ci	scmnd->scsi_done(scmnd);
11368c2ecf20Sopenharmony_ci
11378c2ecf20Sopenharmony_ci	if (payload_sz >
11388c2ecf20Sopenharmony_ci		sizeof(struct vmbus_channel_packet_multipage_buffer))
11398c2ecf20Sopenharmony_ci		kfree(payload);
11408c2ecf20Sopenharmony_ci}
11418c2ecf20Sopenharmony_ci
11428c2ecf20Sopenharmony_cistatic void storvsc_on_io_completion(struct storvsc_device *stor_device,
11438c2ecf20Sopenharmony_ci				  struct vstor_packet *vstor_packet,
11448c2ecf20Sopenharmony_ci				  struct storvsc_cmd_request *request)
11458c2ecf20Sopenharmony_ci{
11468c2ecf20Sopenharmony_ci	struct vstor_packet *stor_pkt;
11478c2ecf20Sopenharmony_ci	struct hv_device *device = stor_device->device;
11488c2ecf20Sopenharmony_ci
11498c2ecf20Sopenharmony_ci	stor_pkt = &request->vstor_packet;
11508c2ecf20Sopenharmony_ci
11518c2ecf20Sopenharmony_ci	/*
11528c2ecf20Sopenharmony_ci	 * The current SCSI handling on the host side does
11538c2ecf20Sopenharmony_ci	 * not correctly handle:
11548c2ecf20Sopenharmony_ci	 * INQUIRY command with page code parameter set to 0x80
11558c2ecf20Sopenharmony_ci	 * MODE_SENSE command with cmd[2] == 0x1c
11568c2ecf20Sopenharmony_ci	 *
11578c2ecf20Sopenharmony_ci	 * Setup srb and scsi status so this won't be fatal.
11588c2ecf20Sopenharmony_ci	 * We do this so we can distinguish truly fatal failues
11598c2ecf20Sopenharmony_ci	 * (srb status == 0x4) and off-line the device in that case.
11608c2ecf20Sopenharmony_ci	 */
11618c2ecf20Sopenharmony_ci
11628c2ecf20Sopenharmony_ci	if ((stor_pkt->vm_srb.cdb[0] == INQUIRY) ||
11638c2ecf20Sopenharmony_ci	   (stor_pkt->vm_srb.cdb[0] == MODE_SENSE)) {
11648c2ecf20Sopenharmony_ci		vstor_packet->vm_srb.scsi_status = 0;
11658c2ecf20Sopenharmony_ci		vstor_packet->vm_srb.srb_status = SRB_STATUS_SUCCESS;
11668c2ecf20Sopenharmony_ci	}
11678c2ecf20Sopenharmony_ci
11688c2ecf20Sopenharmony_ci
11698c2ecf20Sopenharmony_ci	/* Copy over the status...etc */
11708c2ecf20Sopenharmony_ci	stor_pkt->vm_srb.scsi_status = vstor_packet->vm_srb.scsi_status;
11718c2ecf20Sopenharmony_ci	stor_pkt->vm_srb.srb_status = vstor_packet->vm_srb.srb_status;
11728c2ecf20Sopenharmony_ci
11738c2ecf20Sopenharmony_ci	/* Validate sense_info_length (from Hyper-V) */
11748c2ecf20Sopenharmony_ci	if (vstor_packet->vm_srb.sense_info_length > sense_buffer_size)
11758c2ecf20Sopenharmony_ci		vstor_packet->vm_srb.sense_info_length = sense_buffer_size;
11768c2ecf20Sopenharmony_ci
11778c2ecf20Sopenharmony_ci	stor_pkt->vm_srb.sense_info_length =
11788c2ecf20Sopenharmony_ci	vstor_packet->vm_srb.sense_info_length;
11798c2ecf20Sopenharmony_ci
11808c2ecf20Sopenharmony_ci	if (vstor_packet->vm_srb.scsi_status != 0 ||
11818c2ecf20Sopenharmony_ci	    vstor_packet->vm_srb.srb_status != SRB_STATUS_SUCCESS)
11828c2ecf20Sopenharmony_ci		storvsc_log(device, STORVSC_LOGGING_WARN,
11838c2ecf20Sopenharmony_ci			"cmd 0x%x scsi status 0x%x srb status 0x%x\n",
11848c2ecf20Sopenharmony_ci			stor_pkt->vm_srb.cdb[0],
11858c2ecf20Sopenharmony_ci			vstor_packet->vm_srb.scsi_status,
11868c2ecf20Sopenharmony_ci			vstor_packet->vm_srb.srb_status);
11878c2ecf20Sopenharmony_ci
11888c2ecf20Sopenharmony_ci	if ((vstor_packet->vm_srb.scsi_status & 0xFF) == 0x02) {
11898c2ecf20Sopenharmony_ci		/* CHECK_CONDITION */
11908c2ecf20Sopenharmony_ci		if (vstor_packet->vm_srb.srb_status &
11918c2ecf20Sopenharmony_ci			SRB_STATUS_AUTOSENSE_VALID) {
11928c2ecf20Sopenharmony_ci			/* autosense data available */
11938c2ecf20Sopenharmony_ci
11948c2ecf20Sopenharmony_ci			storvsc_log(device, STORVSC_LOGGING_WARN,
11958c2ecf20Sopenharmony_ci				"stor pkt %p autosense data valid - len %d\n",
11968c2ecf20Sopenharmony_ci				request, vstor_packet->vm_srb.sense_info_length);
11978c2ecf20Sopenharmony_ci
11988c2ecf20Sopenharmony_ci			memcpy(request->cmd->sense_buffer,
11998c2ecf20Sopenharmony_ci			       vstor_packet->vm_srb.sense_data,
12008c2ecf20Sopenharmony_ci			       vstor_packet->vm_srb.sense_info_length);
12018c2ecf20Sopenharmony_ci
12028c2ecf20Sopenharmony_ci		}
12038c2ecf20Sopenharmony_ci	}
12048c2ecf20Sopenharmony_ci
12058c2ecf20Sopenharmony_ci	stor_pkt->vm_srb.data_transfer_length =
12068c2ecf20Sopenharmony_ci	vstor_packet->vm_srb.data_transfer_length;
12078c2ecf20Sopenharmony_ci
12088c2ecf20Sopenharmony_ci	storvsc_command_completion(request, stor_device);
12098c2ecf20Sopenharmony_ci
12108c2ecf20Sopenharmony_ci	if (atomic_dec_and_test(&stor_device->num_outstanding_req) &&
12118c2ecf20Sopenharmony_ci		stor_device->drain_notify)
12128c2ecf20Sopenharmony_ci		wake_up(&stor_device->waiting_to_drain);
12138c2ecf20Sopenharmony_ci
12148c2ecf20Sopenharmony_ci
12158c2ecf20Sopenharmony_ci}
12168c2ecf20Sopenharmony_ci
12178c2ecf20Sopenharmony_cistatic void storvsc_on_receive(struct storvsc_device *stor_device,
12188c2ecf20Sopenharmony_ci			     struct vstor_packet *vstor_packet,
12198c2ecf20Sopenharmony_ci			     struct storvsc_cmd_request *request)
12208c2ecf20Sopenharmony_ci{
12218c2ecf20Sopenharmony_ci	struct hv_host_device *host_dev;
12228c2ecf20Sopenharmony_ci	switch (vstor_packet->operation) {
12238c2ecf20Sopenharmony_ci	case VSTOR_OPERATION_COMPLETE_IO:
12248c2ecf20Sopenharmony_ci		storvsc_on_io_completion(stor_device, vstor_packet, request);
12258c2ecf20Sopenharmony_ci		break;
12268c2ecf20Sopenharmony_ci
12278c2ecf20Sopenharmony_ci	case VSTOR_OPERATION_REMOVE_DEVICE:
12288c2ecf20Sopenharmony_ci	case VSTOR_OPERATION_ENUMERATE_BUS:
12298c2ecf20Sopenharmony_ci		host_dev = shost_priv(stor_device->host);
12308c2ecf20Sopenharmony_ci		queue_work(
12318c2ecf20Sopenharmony_ci			host_dev->handle_error_wq, &host_dev->host_scan_work);
12328c2ecf20Sopenharmony_ci		break;
12338c2ecf20Sopenharmony_ci
12348c2ecf20Sopenharmony_ci	case VSTOR_OPERATION_FCHBA_DATA:
12358c2ecf20Sopenharmony_ci		cache_wwn(stor_device, vstor_packet);
12368c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_SCSI_FC_ATTRS)
12378c2ecf20Sopenharmony_ci		fc_host_node_name(stor_device->host) = stor_device->node_name;
12388c2ecf20Sopenharmony_ci		fc_host_port_name(stor_device->host) = stor_device->port_name;
12398c2ecf20Sopenharmony_ci#endif
12408c2ecf20Sopenharmony_ci		break;
12418c2ecf20Sopenharmony_ci	default:
12428c2ecf20Sopenharmony_ci		break;
12438c2ecf20Sopenharmony_ci	}
12448c2ecf20Sopenharmony_ci}
12458c2ecf20Sopenharmony_ci
12468c2ecf20Sopenharmony_cistatic void storvsc_on_channel_callback(void *context)
12478c2ecf20Sopenharmony_ci{
12488c2ecf20Sopenharmony_ci	struct vmbus_channel *channel = (struct vmbus_channel *)context;
12498c2ecf20Sopenharmony_ci	const struct vmpacket_descriptor *desc;
12508c2ecf20Sopenharmony_ci	struct hv_device *device;
12518c2ecf20Sopenharmony_ci	struct storvsc_device *stor_device;
12528c2ecf20Sopenharmony_ci
12538c2ecf20Sopenharmony_ci	if (channel->primary_channel != NULL)
12548c2ecf20Sopenharmony_ci		device = channel->primary_channel->device_obj;
12558c2ecf20Sopenharmony_ci	else
12568c2ecf20Sopenharmony_ci		device = channel->device_obj;
12578c2ecf20Sopenharmony_ci
12588c2ecf20Sopenharmony_ci	stor_device = get_in_stor_device(device);
12598c2ecf20Sopenharmony_ci	if (!stor_device)
12608c2ecf20Sopenharmony_ci		return;
12618c2ecf20Sopenharmony_ci
12628c2ecf20Sopenharmony_ci	foreach_vmbus_pkt(desc, channel) {
12638c2ecf20Sopenharmony_ci		void *packet = hv_pkt_data(desc);
12648c2ecf20Sopenharmony_ci		struct storvsc_cmd_request *request;
12658c2ecf20Sopenharmony_ci
12668c2ecf20Sopenharmony_ci		request = (struct storvsc_cmd_request *)
12678c2ecf20Sopenharmony_ci			((unsigned long)desc->trans_id);
12688c2ecf20Sopenharmony_ci
12698c2ecf20Sopenharmony_ci		if (request == &stor_device->init_request ||
12708c2ecf20Sopenharmony_ci		    request == &stor_device->reset_request) {
12718c2ecf20Sopenharmony_ci			memcpy(&request->vstor_packet, packet,
12728c2ecf20Sopenharmony_ci			       (sizeof(struct vstor_packet) - vmscsi_size_delta));
12738c2ecf20Sopenharmony_ci			complete(&request->wait_event);
12748c2ecf20Sopenharmony_ci		} else {
12758c2ecf20Sopenharmony_ci			storvsc_on_receive(stor_device, packet, request);
12768c2ecf20Sopenharmony_ci		}
12778c2ecf20Sopenharmony_ci	}
12788c2ecf20Sopenharmony_ci}
12798c2ecf20Sopenharmony_ci
12808c2ecf20Sopenharmony_cistatic int storvsc_connect_to_vsp(struct hv_device *device, u32 ring_size,
12818c2ecf20Sopenharmony_ci				  bool is_fc)
12828c2ecf20Sopenharmony_ci{
12838c2ecf20Sopenharmony_ci	struct vmstorage_channel_properties props;
12848c2ecf20Sopenharmony_ci	int ret;
12858c2ecf20Sopenharmony_ci
12868c2ecf20Sopenharmony_ci	memset(&props, 0, sizeof(struct vmstorage_channel_properties));
12878c2ecf20Sopenharmony_ci
12888c2ecf20Sopenharmony_ci	ret = vmbus_open(device->channel,
12898c2ecf20Sopenharmony_ci			 ring_size,
12908c2ecf20Sopenharmony_ci			 ring_size,
12918c2ecf20Sopenharmony_ci			 (void *)&props,
12928c2ecf20Sopenharmony_ci			 sizeof(struct vmstorage_channel_properties),
12938c2ecf20Sopenharmony_ci			 storvsc_on_channel_callback, device->channel);
12948c2ecf20Sopenharmony_ci
12958c2ecf20Sopenharmony_ci	if (ret != 0)
12968c2ecf20Sopenharmony_ci		return ret;
12978c2ecf20Sopenharmony_ci
12988c2ecf20Sopenharmony_ci	ret = storvsc_channel_init(device, is_fc);
12998c2ecf20Sopenharmony_ci
13008c2ecf20Sopenharmony_ci	return ret;
13018c2ecf20Sopenharmony_ci}
13028c2ecf20Sopenharmony_ci
13038c2ecf20Sopenharmony_cistatic int storvsc_dev_remove(struct hv_device *device)
13048c2ecf20Sopenharmony_ci{
13058c2ecf20Sopenharmony_ci	struct storvsc_device *stor_device;
13068c2ecf20Sopenharmony_ci
13078c2ecf20Sopenharmony_ci	stor_device = hv_get_drvdata(device);
13088c2ecf20Sopenharmony_ci
13098c2ecf20Sopenharmony_ci	stor_device->destroy = true;
13108c2ecf20Sopenharmony_ci
13118c2ecf20Sopenharmony_ci	/* Make sure flag is set before waiting */
13128c2ecf20Sopenharmony_ci	wmb();
13138c2ecf20Sopenharmony_ci
13148c2ecf20Sopenharmony_ci	/*
13158c2ecf20Sopenharmony_ci	 * At this point, all outbound traffic should be disable. We
13168c2ecf20Sopenharmony_ci	 * only allow inbound traffic (responses) to proceed so that
13178c2ecf20Sopenharmony_ci	 * outstanding requests can be completed.
13188c2ecf20Sopenharmony_ci	 */
13198c2ecf20Sopenharmony_ci
13208c2ecf20Sopenharmony_ci	storvsc_wait_to_drain(stor_device);
13218c2ecf20Sopenharmony_ci
13228c2ecf20Sopenharmony_ci	/*
13238c2ecf20Sopenharmony_ci	 * Since we have already drained, we don't need to busy wait
13248c2ecf20Sopenharmony_ci	 * as was done in final_release_stor_device()
13258c2ecf20Sopenharmony_ci	 * Note that we cannot set the ext pointer to NULL until
13268c2ecf20Sopenharmony_ci	 * we have drained - to drain the outgoing packets, we need to
13278c2ecf20Sopenharmony_ci	 * allow incoming packets.
13288c2ecf20Sopenharmony_ci	 */
13298c2ecf20Sopenharmony_ci	hv_set_drvdata(device, NULL);
13308c2ecf20Sopenharmony_ci
13318c2ecf20Sopenharmony_ci	/* Close the channel */
13328c2ecf20Sopenharmony_ci	vmbus_close(device->channel);
13338c2ecf20Sopenharmony_ci
13348c2ecf20Sopenharmony_ci	kfree(stor_device->stor_chns);
13358c2ecf20Sopenharmony_ci	kfree(stor_device);
13368c2ecf20Sopenharmony_ci	return 0;
13378c2ecf20Sopenharmony_ci}
13388c2ecf20Sopenharmony_ci
13398c2ecf20Sopenharmony_cistatic struct vmbus_channel *get_og_chn(struct storvsc_device *stor_device,
13408c2ecf20Sopenharmony_ci					u16 q_num)
13418c2ecf20Sopenharmony_ci{
13428c2ecf20Sopenharmony_ci	u16 slot = 0;
13438c2ecf20Sopenharmony_ci	u16 hash_qnum;
13448c2ecf20Sopenharmony_ci	const struct cpumask *node_mask;
13458c2ecf20Sopenharmony_ci	int num_channels, tgt_cpu;
13468c2ecf20Sopenharmony_ci
13478c2ecf20Sopenharmony_ci	if (stor_device->num_sc == 0) {
13488c2ecf20Sopenharmony_ci		stor_device->stor_chns[q_num] = stor_device->device->channel;
13498c2ecf20Sopenharmony_ci		return stor_device->device->channel;
13508c2ecf20Sopenharmony_ci	}
13518c2ecf20Sopenharmony_ci
13528c2ecf20Sopenharmony_ci	/*
13538c2ecf20Sopenharmony_ci	 * Our channel array is sparsley populated and we
13548c2ecf20Sopenharmony_ci	 * initiated I/O on a processor/hw-q that does not
13558c2ecf20Sopenharmony_ci	 * currently have a designated channel. Fix this.
13568c2ecf20Sopenharmony_ci	 * The strategy is simple:
13578c2ecf20Sopenharmony_ci	 * I. Ensure NUMA locality
13588c2ecf20Sopenharmony_ci	 * II. Distribute evenly (best effort)
13598c2ecf20Sopenharmony_ci	 */
13608c2ecf20Sopenharmony_ci
13618c2ecf20Sopenharmony_ci	node_mask = cpumask_of_node(cpu_to_node(q_num));
13628c2ecf20Sopenharmony_ci
13638c2ecf20Sopenharmony_ci	num_channels = 0;
13648c2ecf20Sopenharmony_ci	for_each_cpu(tgt_cpu, &stor_device->alloced_cpus) {
13658c2ecf20Sopenharmony_ci		if (cpumask_test_cpu(tgt_cpu, node_mask))
13668c2ecf20Sopenharmony_ci			num_channels++;
13678c2ecf20Sopenharmony_ci	}
13688c2ecf20Sopenharmony_ci	if (num_channels == 0) {
13698c2ecf20Sopenharmony_ci		stor_device->stor_chns[q_num] = stor_device->device->channel;
13708c2ecf20Sopenharmony_ci		return stor_device->device->channel;
13718c2ecf20Sopenharmony_ci	}
13728c2ecf20Sopenharmony_ci
13738c2ecf20Sopenharmony_ci	hash_qnum = q_num;
13748c2ecf20Sopenharmony_ci	while (hash_qnum >= num_channels)
13758c2ecf20Sopenharmony_ci		hash_qnum -= num_channels;
13768c2ecf20Sopenharmony_ci
13778c2ecf20Sopenharmony_ci	for_each_cpu(tgt_cpu, &stor_device->alloced_cpus) {
13788c2ecf20Sopenharmony_ci		if (!cpumask_test_cpu(tgt_cpu, node_mask))
13798c2ecf20Sopenharmony_ci			continue;
13808c2ecf20Sopenharmony_ci		if (slot == hash_qnum)
13818c2ecf20Sopenharmony_ci			break;
13828c2ecf20Sopenharmony_ci		slot++;
13838c2ecf20Sopenharmony_ci	}
13848c2ecf20Sopenharmony_ci
13858c2ecf20Sopenharmony_ci	stor_device->stor_chns[q_num] = stor_device->stor_chns[tgt_cpu];
13868c2ecf20Sopenharmony_ci
13878c2ecf20Sopenharmony_ci	return stor_device->stor_chns[q_num];
13888c2ecf20Sopenharmony_ci}
13898c2ecf20Sopenharmony_ci
13908c2ecf20Sopenharmony_ci
13918c2ecf20Sopenharmony_cistatic int storvsc_do_io(struct hv_device *device,
13928c2ecf20Sopenharmony_ci			 struct storvsc_cmd_request *request, u16 q_num)
13938c2ecf20Sopenharmony_ci{
13948c2ecf20Sopenharmony_ci	struct storvsc_device *stor_device;
13958c2ecf20Sopenharmony_ci	struct vstor_packet *vstor_packet;
13968c2ecf20Sopenharmony_ci	struct vmbus_channel *outgoing_channel, *channel;
13978c2ecf20Sopenharmony_ci	unsigned long flags;
13988c2ecf20Sopenharmony_ci	int ret = 0;
13998c2ecf20Sopenharmony_ci	const struct cpumask *node_mask;
14008c2ecf20Sopenharmony_ci	int tgt_cpu;
14018c2ecf20Sopenharmony_ci
14028c2ecf20Sopenharmony_ci	vstor_packet = &request->vstor_packet;
14038c2ecf20Sopenharmony_ci	stor_device = get_out_stor_device(device);
14048c2ecf20Sopenharmony_ci
14058c2ecf20Sopenharmony_ci	if (!stor_device)
14068c2ecf20Sopenharmony_ci		return -ENODEV;
14078c2ecf20Sopenharmony_ci
14088c2ecf20Sopenharmony_ci
14098c2ecf20Sopenharmony_ci	request->device  = device;
14108c2ecf20Sopenharmony_ci	/*
14118c2ecf20Sopenharmony_ci	 * Select an appropriate channel to send the request out.
14128c2ecf20Sopenharmony_ci	 */
14138c2ecf20Sopenharmony_ci	/* See storvsc_change_target_cpu(). */
14148c2ecf20Sopenharmony_ci	outgoing_channel = READ_ONCE(stor_device->stor_chns[q_num]);
14158c2ecf20Sopenharmony_ci	if (outgoing_channel != NULL) {
14168c2ecf20Sopenharmony_ci		if (outgoing_channel->target_cpu == q_num) {
14178c2ecf20Sopenharmony_ci			/*
14188c2ecf20Sopenharmony_ci			 * Ideally, we want to pick a different channel if
14198c2ecf20Sopenharmony_ci			 * available on the same NUMA node.
14208c2ecf20Sopenharmony_ci			 */
14218c2ecf20Sopenharmony_ci			node_mask = cpumask_of_node(cpu_to_node(q_num));
14228c2ecf20Sopenharmony_ci			for_each_cpu_wrap(tgt_cpu,
14238c2ecf20Sopenharmony_ci				 &stor_device->alloced_cpus, q_num + 1) {
14248c2ecf20Sopenharmony_ci				if (!cpumask_test_cpu(tgt_cpu, node_mask))
14258c2ecf20Sopenharmony_ci					continue;
14268c2ecf20Sopenharmony_ci				if (tgt_cpu == q_num)
14278c2ecf20Sopenharmony_ci					continue;
14288c2ecf20Sopenharmony_ci				channel = READ_ONCE(
14298c2ecf20Sopenharmony_ci					stor_device->stor_chns[tgt_cpu]);
14308c2ecf20Sopenharmony_ci				if (channel == NULL)
14318c2ecf20Sopenharmony_ci					continue;
14328c2ecf20Sopenharmony_ci				if (hv_get_avail_to_write_percent(
14338c2ecf20Sopenharmony_ci							&channel->outbound)
14348c2ecf20Sopenharmony_ci						> ring_avail_percent_lowater) {
14358c2ecf20Sopenharmony_ci					outgoing_channel = channel;
14368c2ecf20Sopenharmony_ci					goto found_channel;
14378c2ecf20Sopenharmony_ci				}
14388c2ecf20Sopenharmony_ci			}
14398c2ecf20Sopenharmony_ci
14408c2ecf20Sopenharmony_ci			/*
14418c2ecf20Sopenharmony_ci			 * All the other channels on the same NUMA node are
14428c2ecf20Sopenharmony_ci			 * busy. Try to use the channel on the current CPU
14438c2ecf20Sopenharmony_ci			 */
14448c2ecf20Sopenharmony_ci			if (hv_get_avail_to_write_percent(
14458c2ecf20Sopenharmony_ci						&outgoing_channel->outbound)
14468c2ecf20Sopenharmony_ci					> ring_avail_percent_lowater)
14478c2ecf20Sopenharmony_ci				goto found_channel;
14488c2ecf20Sopenharmony_ci
14498c2ecf20Sopenharmony_ci			/*
14508c2ecf20Sopenharmony_ci			 * If we reach here, all the channels on the current
14518c2ecf20Sopenharmony_ci			 * NUMA node are busy. Try to find a channel in
14528c2ecf20Sopenharmony_ci			 * other NUMA nodes
14538c2ecf20Sopenharmony_ci			 */
14548c2ecf20Sopenharmony_ci			for_each_cpu(tgt_cpu, &stor_device->alloced_cpus) {
14558c2ecf20Sopenharmony_ci				if (cpumask_test_cpu(tgt_cpu, node_mask))
14568c2ecf20Sopenharmony_ci					continue;
14578c2ecf20Sopenharmony_ci				channel = READ_ONCE(
14588c2ecf20Sopenharmony_ci					stor_device->stor_chns[tgt_cpu]);
14598c2ecf20Sopenharmony_ci				if (channel == NULL)
14608c2ecf20Sopenharmony_ci					continue;
14618c2ecf20Sopenharmony_ci				if (hv_get_avail_to_write_percent(
14628c2ecf20Sopenharmony_ci							&channel->outbound)
14638c2ecf20Sopenharmony_ci						> ring_avail_percent_lowater) {
14648c2ecf20Sopenharmony_ci					outgoing_channel = channel;
14658c2ecf20Sopenharmony_ci					goto found_channel;
14668c2ecf20Sopenharmony_ci				}
14678c2ecf20Sopenharmony_ci			}
14688c2ecf20Sopenharmony_ci		}
14698c2ecf20Sopenharmony_ci	} else {
14708c2ecf20Sopenharmony_ci		spin_lock_irqsave(&stor_device->lock, flags);
14718c2ecf20Sopenharmony_ci		outgoing_channel = stor_device->stor_chns[q_num];
14728c2ecf20Sopenharmony_ci		if (outgoing_channel != NULL) {
14738c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(&stor_device->lock, flags);
14748c2ecf20Sopenharmony_ci			goto found_channel;
14758c2ecf20Sopenharmony_ci		}
14768c2ecf20Sopenharmony_ci		outgoing_channel = get_og_chn(stor_device, q_num);
14778c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&stor_device->lock, flags);
14788c2ecf20Sopenharmony_ci	}
14798c2ecf20Sopenharmony_ci
14808c2ecf20Sopenharmony_cifound_channel:
14818c2ecf20Sopenharmony_ci	vstor_packet->flags |= REQUEST_COMPLETION_FLAG;
14828c2ecf20Sopenharmony_ci
14838c2ecf20Sopenharmony_ci	vstor_packet->vm_srb.length = (sizeof(struct vmscsi_request) -
14848c2ecf20Sopenharmony_ci					vmscsi_size_delta);
14858c2ecf20Sopenharmony_ci
14868c2ecf20Sopenharmony_ci
14878c2ecf20Sopenharmony_ci	vstor_packet->vm_srb.sense_info_length = sense_buffer_size;
14888c2ecf20Sopenharmony_ci
14898c2ecf20Sopenharmony_ci
14908c2ecf20Sopenharmony_ci	vstor_packet->vm_srb.data_transfer_length =
14918c2ecf20Sopenharmony_ci	request->payload->range.len;
14928c2ecf20Sopenharmony_ci
14938c2ecf20Sopenharmony_ci	vstor_packet->operation = VSTOR_OPERATION_EXECUTE_SRB;
14948c2ecf20Sopenharmony_ci
14958c2ecf20Sopenharmony_ci	if (request->payload->range.len) {
14968c2ecf20Sopenharmony_ci
14978c2ecf20Sopenharmony_ci		ret = vmbus_sendpacket_mpb_desc(outgoing_channel,
14988c2ecf20Sopenharmony_ci				request->payload, request->payload_sz,
14998c2ecf20Sopenharmony_ci				vstor_packet,
15008c2ecf20Sopenharmony_ci				(sizeof(struct vstor_packet) -
15018c2ecf20Sopenharmony_ci				vmscsi_size_delta),
15028c2ecf20Sopenharmony_ci				(unsigned long)request);
15038c2ecf20Sopenharmony_ci	} else {
15048c2ecf20Sopenharmony_ci		ret = vmbus_sendpacket(outgoing_channel, vstor_packet,
15058c2ecf20Sopenharmony_ci			       (sizeof(struct vstor_packet) -
15068c2ecf20Sopenharmony_ci				vmscsi_size_delta),
15078c2ecf20Sopenharmony_ci			       (unsigned long)request,
15088c2ecf20Sopenharmony_ci			       VM_PKT_DATA_INBAND,
15098c2ecf20Sopenharmony_ci			       VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
15108c2ecf20Sopenharmony_ci	}
15118c2ecf20Sopenharmony_ci
15128c2ecf20Sopenharmony_ci	if (ret != 0)
15138c2ecf20Sopenharmony_ci		return ret;
15148c2ecf20Sopenharmony_ci
15158c2ecf20Sopenharmony_ci	atomic_inc(&stor_device->num_outstanding_req);
15168c2ecf20Sopenharmony_ci
15178c2ecf20Sopenharmony_ci	return ret;
15188c2ecf20Sopenharmony_ci}
15198c2ecf20Sopenharmony_ci
15208c2ecf20Sopenharmony_cistatic int storvsc_device_alloc(struct scsi_device *sdevice)
15218c2ecf20Sopenharmony_ci{
15228c2ecf20Sopenharmony_ci	/*
15238c2ecf20Sopenharmony_ci	 * Set blist flag to permit the reading of the VPD pages even when
15248c2ecf20Sopenharmony_ci	 * the target may claim SPC-2 compliance. MSFT targets currently
15258c2ecf20Sopenharmony_ci	 * claim SPC-2 compliance while they implement post SPC-2 features.
15268c2ecf20Sopenharmony_ci	 * With this flag we can correctly handle WRITE_SAME_16 issues.
15278c2ecf20Sopenharmony_ci	 *
15288c2ecf20Sopenharmony_ci	 * Hypervisor reports SCSI_UNKNOWN type for DVD ROM device but
15298c2ecf20Sopenharmony_ci	 * still supports REPORT LUN.
15308c2ecf20Sopenharmony_ci	 */
15318c2ecf20Sopenharmony_ci	sdevice->sdev_bflags = BLIST_REPORTLUN2 | BLIST_TRY_VPD_PAGES;
15328c2ecf20Sopenharmony_ci
15338c2ecf20Sopenharmony_ci	return 0;
15348c2ecf20Sopenharmony_ci}
15358c2ecf20Sopenharmony_ci
15368c2ecf20Sopenharmony_cistatic int storvsc_device_configure(struct scsi_device *sdevice)
15378c2ecf20Sopenharmony_ci{
15388c2ecf20Sopenharmony_ci	blk_queue_rq_timeout(sdevice->request_queue, (storvsc_timeout * HZ));
15398c2ecf20Sopenharmony_ci
15408c2ecf20Sopenharmony_ci	/* storvsc devices don't support MAINTENANCE_IN SCSI cmd */
15418c2ecf20Sopenharmony_ci	sdevice->no_report_opcodes = 1;
15428c2ecf20Sopenharmony_ci	sdevice->no_write_same = 1;
15438c2ecf20Sopenharmony_ci
15448c2ecf20Sopenharmony_ci	/*
15458c2ecf20Sopenharmony_ci	 * If the host is WIN8 or WIN8 R2, claim conformance to SPC-3
15468c2ecf20Sopenharmony_ci	 * if the device is a MSFT virtual device.  If the host is
15478c2ecf20Sopenharmony_ci	 * WIN10 or newer, allow write_same.
15488c2ecf20Sopenharmony_ci	 */
15498c2ecf20Sopenharmony_ci	if (!strncmp(sdevice->vendor, "Msft", 4)) {
15508c2ecf20Sopenharmony_ci		switch (vmstor_proto_version) {
15518c2ecf20Sopenharmony_ci		case VMSTOR_PROTO_VERSION_WIN8:
15528c2ecf20Sopenharmony_ci		case VMSTOR_PROTO_VERSION_WIN8_1:
15538c2ecf20Sopenharmony_ci			sdevice->scsi_level = SCSI_SPC_3;
15548c2ecf20Sopenharmony_ci			break;
15558c2ecf20Sopenharmony_ci		}
15568c2ecf20Sopenharmony_ci
15578c2ecf20Sopenharmony_ci		if (vmstor_proto_version >= VMSTOR_PROTO_VERSION_WIN10)
15588c2ecf20Sopenharmony_ci			sdevice->no_write_same = 0;
15598c2ecf20Sopenharmony_ci	}
15608c2ecf20Sopenharmony_ci
15618c2ecf20Sopenharmony_ci	return 0;
15628c2ecf20Sopenharmony_ci}
15638c2ecf20Sopenharmony_ci
15648c2ecf20Sopenharmony_cistatic int storvsc_get_chs(struct scsi_device *sdev, struct block_device * bdev,
15658c2ecf20Sopenharmony_ci			   sector_t capacity, int *info)
15668c2ecf20Sopenharmony_ci{
15678c2ecf20Sopenharmony_ci	sector_t nsect = capacity;
15688c2ecf20Sopenharmony_ci	sector_t cylinders = nsect;
15698c2ecf20Sopenharmony_ci	int heads, sectors_pt;
15708c2ecf20Sopenharmony_ci
15718c2ecf20Sopenharmony_ci	/*
15728c2ecf20Sopenharmony_ci	 * We are making up these values; let us keep it simple.
15738c2ecf20Sopenharmony_ci	 */
15748c2ecf20Sopenharmony_ci	heads = 0xff;
15758c2ecf20Sopenharmony_ci	sectors_pt = 0x3f;      /* Sectors per track */
15768c2ecf20Sopenharmony_ci	sector_div(cylinders, heads * sectors_pt);
15778c2ecf20Sopenharmony_ci	if ((sector_t)(cylinders + 1) * heads * sectors_pt < nsect)
15788c2ecf20Sopenharmony_ci		cylinders = 0xffff;
15798c2ecf20Sopenharmony_ci
15808c2ecf20Sopenharmony_ci	info[0] = heads;
15818c2ecf20Sopenharmony_ci	info[1] = sectors_pt;
15828c2ecf20Sopenharmony_ci	info[2] = (int)cylinders;
15838c2ecf20Sopenharmony_ci
15848c2ecf20Sopenharmony_ci	return 0;
15858c2ecf20Sopenharmony_ci}
15868c2ecf20Sopenharmony_ci
15878c2ecf20Sopenharmony_cistatic int storvsc_host_reset_handler(struct scsi_cmnd *scmnd)
15888c2ecf20Sopenharmony_ci{
15898c2ecf20Sopenharmony_ci	struct hv_host_device *host_dev = shost_priv(scmnd->device->host);
15908c2ecf20Sopenharmony_ci	struct hv_device *device = host_dev->dev;
15918c2ecf20Sopenharmony_ci
15928c2ecf20Sopenharmony_ci	struct storvsc_device *stor_device;
15938c2ecf20Sopenharmony_ci	struct storvsc_cmd_request *request;
15948c2ecf20Sopenharmony_ci	struct vstor_packet *vstor_packet;
15958c2ecf20Sopenharmony_ci	int ret, t;
15968c2ecf20Sopenharmony_ci
15978c2ecf20Sopenharmony_ci
15988c2ecf20Sopenharmony_ci	stor_device = get_out_stor_device(device);
15998c2ecf20Sopenharmony_ci	if (!stor_device)
16008c2ecf20Sopenharmony_ci		return FAILED;
16018c2ecf20Sopenharmony_ci
16028c2ecf20Sopenharmony_ci	request = &stor_device->reset_request;
16038c2ecf20Sopenharmony_ci	vstor_packet = &request->vstor_packet;
16048c2ecf20Sopenharmony_ci	memset(vstor_packet, 0, sizeof(struct vstor_packet));
16058c2ecf20Sopenharmony_ci
16068c2ecf20Sopenharmony_ci	init_completion(&request->wait_event);
16078c2ecf20Sopenharmony_ci
16088c2ecf20Sopenharmony_ci	vstor_packet->operation = VSTOR_OPERATION_RESET_BUS;
16098c2ecf20Sopenharmony_ci	vstor_packet->flags = REQUEST_COMPLETION_FLAG;
16108c2ecf20Sopenharmony_ci	vstor_packet->vm_srb.path_id = stor_device->path_id;
16118c2ecf20Sopenharmony_ci
16128c2ecf20Sopenharmony_ci	ret = vmbus_sendpacket(device->channel, vstor_packet,
16138c2ecf20Sopenharmony_ci			       (sizeof(struct vstor_packet) -
16148c2ecf20Sopenharmony_ci				vmscsi_size_delta),
16158c2ecf20Sopenharmony_ci			       (unsigned long)&stor_device->reset_request,
16168c2ecf20Sopenharmony_ci			       VM_PKT_DATA_INBAND,
16178c2ecf20Sopenharmony_ci			       VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
16188c2ecf20Sopenharmony_ci	if (ret != 0)
16198c2ecf20Sopenharmony_ci		return FAILED;
16208c2ecf20Sopenharmony_ci
16218c2ecf20Sopenharmony_ci	t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
16228c2ecf20Sopenharmony_ci	if (t == 0)
16238c2ecf20Sopenharmony_ci		return TIMEOUT_ERROR;
16248c2ecf20Sopenharmony_ci
16258c2ecf20Sopenharmony_ci
16268c2ecf20Sopenharmony_ci	/*
16278c2ecf20Sopenharmony_ci	 * At this point, all outstanding requests in the adapter
16288c2ecf20Sopenharmony_ci	 * should have been flushed out and return to us
16298c2ecf20Sopenharmony_ci	 * There is a potential race here where the host may be in
16308c2ecf20Sopenharmony_ci	 * the process of responding when we return from here.
16318c2ecf20Sopenharmony_ci	 * Just wait for all in-transit packets to be accounted for
16328c2ecf20Sopenharmony_ci	 * before we return from here.
16338c2ecf20Sopenharmony_ci	 */
16348c2ecf20Sopenharmony_ci	storvsc_wait_to_drain(stor_device);
16358c2ecf20Sopenharmony_ci
16368c2ecf20Sopenharmony_ci	return SUCCESS;
16378c2ecf20Sopenharmony_ci}
16388c2ecf20Sopenharmony_ci
16398c2ecf20Sopenharmony_ci/*
16408c2ecf20Sopenharmony_ci * The host guarantees to respond to each command, although I/O latencies might
16418c2ecf20Sopenharmony_ci * be unbounded on Azure.  Reset the timer unconditionally to give the host a
16428c2ecf20Sopenharmony_ci * chance to perform EH.
16438c2ecf20Sopenharmony_ci */
16448c2ecf20Sopenharmony_cistatic enum blk_eh_timer_return storvsc_eh_timed_out(struct scsi_cmnd *scmnd)
16458c2ecf20Sopenharmony_ci{
16468c2ecf20Sopenharmony_ci	return BLK_EH_RESET_TIMER;
16478c2ecf20Sopenharmony_ci}
16488c2ecf20Sopenharmony_ci
16498c2ecf20Sopenharmony_cistatic bool storvsc_scsi_cmd_ok(struct scsi_cmnd *scmnd)
16508c2ecf20Sopenharmony_ci{
16518c2ecf20Sopenharmony_ci	bool allowed = true;
16528c2ecf20Sopenharmony_ci	u8 scsi_op = scmnd->cmnd[0];
16538c2ecf20Sopenharmony_ci
16548c2ecf20Sopenharmony_ci	switch (scsi_op) {
16558c2ecf20Sopenharmony_ci	/* the host does not handle WRITE_SAME, log accident usage */
16568c2ecf20Sopenharmony_ci	case WRITE_SAME:
16578c2ecf20Sopenharmony_ci	/*
16588c2ecf20Sopenharmony_ci	 * smartd sends this command and the host does not handle
16598c2ecf20Sopenharmony_ci	 * this. So, don't send it.
16608c2ecf20Sopenharmony_ci	 */
16618c2ecf20Sopenharmony_ci	case SET_WINDOW:
16628c2ecf20Sopenharmony_ci		scmnd->result = ILLEGAL_REQUEST << 16;
16638c2ecf20Sopenharmony_ci		allowed = false;
16648c2ecf20Sopenharmony_ci		break;
16658c2ecf20Sopenharmony_ci	default:
16668c2ecf20Sopenharmony_ci		break;
16678c2ecf20Sopenharmony_ci	}
16688c2ecf20Sopenharmony_ci	return allowed;
16698c2ecf20Sopenharmony_ci}
16708c2ecf20Sopenharmony_ci
16718c2ecf20Sopenharmony_cistatic int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd)
16728c2ecf20Sopenharmony_ci{
16738c2ecf20Sopenharmony_ci	int ret;
16748c2ecf20Sopenharmony_ci	struct hv_host_device *host_dev = shost_priv(host);
16758c2ecf20Sopenharmony_ci	struct hv_device *dev = host_dev->dev;
16768c2ecf20Sopenharmony_ci	struct storvsc_cmd_request *cmd_request = scsi_cmd_priv(scmnd);
16778c2ecf20Sopenharmony_ci	int i;
16788c2ecf20Sopenharmony_ci	struct scatterlist *sgl;
16798c2ecf20Sopenharmony_ci	unsigned int sg_count = 0;
16808c2ecf20Sopenharmony_ci	struct vmscsi_request *vm_srb;
16818c2ecf20Sopenharmony_ci	struct scatterlist *cur_sgl;
16828c2ecf20Sopenharmony_ci	struct vmbus_packet_mpb_array  *payload;
16838c2ecf20Sopenharmony_ci	u32 payload_sz;
16848c2ecf20Sopenharmony_ci	u32 length;
16858c2ecf20Sopenharmony_ci
16868c2ecf20Sopenharmony_ci	if (vmstor_proto_version <= VMSTOR_PROTO_VERSION_WIN8) {
16878c2ecf20Sopenharmony_ci		/*
16888c2ecf20Sopenharmony_ci		 * On legacy hosts filter unimplemented commands.
16898c2ecf20Sopenharmony_ci		 * Future hosts are expected to correctly handle
16908c2ecf20Sopenharmony_ci		 * unsupported commands. Furthermore, it is
16918c2ecf20Sopenharmony_ci		 * possible that some of the currently
16928c2ecf20Sopenharmony_ci		 * unsupported commands maybe supported in
16938c2ecf20Sopenharmony_ci		 * future versions of the host.
16948c2ecf20Sopenharmony_ci		 */
16958c2ecf20Sopenharmony_ci		if (!storvsc_scsi_cmd_ok(scmnd)) {
16968c2ecf20Sopenharmony_ci			scmnd->scsi_done(scmnd);
16978c2ecf20Sopenharmony_ci			return 0;
16988c2ecf20Sopenharmony_ci		}
16998c2ecf20Sopenharmony_ci	}
17008c2ecf20Sopenharmony_ci
17018c2ecf20Sopenharmony_ci	/* Setup the cmd request */
17028c2ecf20Sopenharmony_ci	cmd_request->cmd = scmnd;
17038c2ecf20Sopenharmony_ci
17048c2ecf20Sopenharmony_ci	memset(&cmd_request->vstor_packet, 0, sizeof(struct vstor_packet));
17058c2ecf20Sopenharmony_ci	vm_srb = &cmd_request->vstor_packet.vm_srb;
17068c2ecf20Sopenharmony_ci	vm_srb->win8_extension.time_out_value = 60;
17078c2ecf20Sopenharmony_ci
17088c2ecf20Sopenharmony_ci	vm_srb->win8_extension.srb_flags |=
17098c2ecf20Sopenharmony_ci		SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
17108c2ecf20Sopenharmony_ci
17118c2ecf20Sopenharmony_ci	if (scmnd->device->tagged_supported) {
17128c2ecf20Sopenharmony_ci		vm_srb->win8_extension.srb_flags |=
17138c2ecf20Sopenharmony_ci		(SRB_FLAGS_QUEUE_ACTION_ENABLE | SRB_FLAGS_NO_QUEUE_FREEZE);
17148c2ecf20Sopenharmony_ci		vm_srb->win8_extension.queue_tag = SP_UNTAGGED;
17158c2ecf20Sopenharmony_ci		vm_srb->win8_extension.queue_action = SRB_SIMPLE_TAG_REQUEST;
17168c2ecf20Sopenharmony_ci	}
17178c2ecf20Sopenharmony_ci
17188c2ecf20Sopenharmony_ci	/* Build the SRB */
17198c2ecf20Sopenharmony_ci	switch (scmnd->sc_data_direction) {
17208c2ecf20Sopenharmony_ci	case DMA_TO_DEVICE:
17218c2ecf20Sopenharmony_ci		vm_srb->data_in = WRITE_TYPE;
17228c2ecf20Sopenharmony_ci		vm_srb->win8_extension.srb_flags |= SRB_FLAGS_DATA_OUT;
17238c2ecf20Sopenharmony_ci		break;
17248c2ecf20Sopenharmony_ci	case DMA_FROM_DEVICE:
17258c2ecf20Sopenharmony_ci		vm_srb->data_in = READ_TYPE;
17268c2ecf20Sopenharmony_ci		vm_srb->win8_extension.srb_flags |= SRB_FLAGS_DATA_IN;
17278c2ecf20Sopenharmony_ci		break;
17288c2ecf20Sopenharmony_ci	case DMA_NONE:
17298c2ecf20Sopenharmony_ci		vm_srb->data_in = UNKNOWN_TYPE;
17308c2ecf20Sopenharmony_ci		vm_srb->win8_extension.srb_flags |= SRB_FLAGS_NO_DATA_TRANSFER;
17318c2ecf20Sopenharmony_ci		break;
17328c2ecf20Sopenharmony_ci	default:
17338c2ecf20Sopenharmony_ci		/*
17348c2ecf20Sopenharmony_ci		 * This is DMA_BIDIRECTIONAL or something else we are never
17358c2ecf20Sopenharmony_ci		 * supposed to see here.
17368c2ecf20Sopenharmony_ci		 */
17378c2ecf20Sopenharmony_ci		WARN(1, "Unexpected data direction: %d\n",
17388c2ecf20Sopenharmony_ci		     scmnd->sc_data_direction);
17398c2ecf20Sopenharmony_ci		return -EINVAL;
17408c2ecf20Sopenharmony_ci	}
17418c2ecf20Sopenharmony_ci
17428c2ecf20Sopenharmony_ci
17438c2ecf20Sopenharmony_ci	vm_srb->port_number = host_dev->port;
17448c2ecf20Sopenharmony_ci	vm_srb->path_id = scmnd->device->channel;
17458c2ecf20Sopenharmony_ci	vm_srb->target_id = scmnd->device->id;
17468c2ecf20Sopenharmony_ci	vm_srb->lun = scmnd->device->lun;
17478c2ecf20Sopenharmony_ci
17488c2ecf20Sopenharmony_ci	vm_srb->cdb_length = scmnd->cmd_len;
17498c2ecf20Sopenharmony_ci
17508c2ecf20Sopenharmony_ci	memcpy(vm_srb->cdb, scmnd->cmnd, vm_srb->cdb_length);
17518c2ecf20Sopenharmony_ci
17528c2ecf20Sopenharmony_ci	sgl = (struct scatterlist *)scsi_sglist(scmnd);
17538c2ecf20Sopenharmony_ci	sg_count = scsi_sg_count(scmnd);
17548c2ecf20Sopenharmony_ci
17558c2ecf20Sopenharmony_ci	length = scsi_bufflen(scmnd);
17568c2ecf20Sopenharmony_ci	payload = (struct vmbus_packet_mpb_array *)&cmd_request->mpb;
17578c2ecf20Sopenharmony_ci	payload_sz = 0;
17588c2ecf20Sopenharmony_ci
17598c2ecf20Sopenharmony_ci	if (sg_count) {
17608c2ecf20Sopenharmony_ci		unsigned int hvpgoff = 0;
17618c2ecf20Sopenharmony_ci		unsigned long offset_in_hvpg = sgl->offset & ~HV_HYP_PAGE_MASK;
17628c2ecf20Sopenharmony_ci		unsigned int hvpg_count = HVPFN_UP(offset_in_hvpg + length);
17638c2ecf20Sopenharmony_ci		u64 hvpfn;
17648c2ecf20Sopenharmony_ci
17658c2ecf20Sopenharmony_ci		payload_sz = (hvpg_count * sizeof(u64) +
17668c2ecf20Sopenharmony_ci			      sizeof(struct vmbus_packet_mpb_array));
17678c2ecf20Sopenharmony_ci
17688c2ecf20Sopenharmony_ci		if (hvpg_count > MAX_PAGE_BUFFER_COUNT) {
17698c2ecf20Sopenharmony_ci			payload = kzalloc(payload_sz, GFP_ATOMIC);
17708c2ecf20Sopenharmony_ci			if (!payload)
17718c2ecf20Sopenharmony_ci				return SCSI_MLQUEUE_DEVICE_BUSY;
17728c2ecf20Sopenharmony_ci		}
17738c2ecf20Sopenharmony_ci
17748c2ecf20Sopenharmony_ci		/*
17758c2ecf20Sopenharmony_ci		 * sgl is a list of PAGEs, and payload->range.pfn_array
17768c2ecf20Sopenharmony_ci		 * expects the page number in the unit of HV_HYP_PAGE_SIZE (the
17778c2ecf20Sopenharmony_ci		 * page size that Hyper-V uses, so here we need to divide PAGEs
17788c2ecf20Sopenharmony_ci		 * into HV_HYP_PAGE in case that PAGE_SIZE > HV_HYP_PAGE_SIZE.
17798c2ecf20Sopenharmony_ci		 * Besides, payload->range.offset should be the offset in one
17808c2ecf20Sopenharmony_ci		 * HV_HYP_PAGE.
17818c2ecf20Sopenharmony_ci		 */
17828c2ecf20Sopenharmony_ci		payload->range.len = length;
17838c2ecf20Sopenharmony_ci		payload->range.offset = offset_in_hvpg;
17848c2ecf20Sopenharmony_ci		hvpgoff = sgl->offset >> HV_HYP_PAGE_SHIFT;
17858c2ecf20Sopenharmony_ci
17868c2ecf20Sopenharmony_ci		cur_sgl = sgl;
17878c2ecf20Sopenharmony_ci		for (i = 0; i < hvpg_count; i++) {
17888c2ecf20Sopenharmony_ci			/*
17898c2ecf20Sopenharmony_ci			 * 'i' is the index of hv pages in the payload and
17908c2ecf20Sopenharmony_ci			 * 'hvpgoff' is the offset (in hv pages) of the first
17918c2ecf20Sopenharmony_ci			 * hv page in the the first page. The relationship
17928c2ecf20Sopenharmony_ci			 * between the sum of 'i' and 'hvpgoff' and the offset
17938c2ecf20Sopenharmony_ci			 * (in hv pages) in a payload page ('hvpgoff_in_page')
17948c2ecf20Sopenharmony_ci			 * is as follow:
17958c2ecf20Sopenharmony_ci			 *
17968c2ecf20Sopenharmony_ci			 * |------------------ PAGE -------------------|
17978c2ecf20Sopenharmony_ci			 * |   NR_HV_HYP_PAGES_IN_PAGE hvpgs in total  |
17988c2ecf20Sopenharmony_ci			 * |hvpg|hvpg| ...              |hvpg|... |hvpg|
17998c2ecf20Sopenharmony_ci			 * ^         ^                                 ^                 ^
18008c2ecf20Sopenharmony_ci			 * +-hvpgoff-+                                 +-hvpgoff_in_page-+
18018c2ecf20Sopenharmony_ci			 *           ^                                                   |
18028c2ecf20Sopenharmony_ci			 *           +--------------------- i ---------------------------+
18038c2ecf20Sopenharmony_ci			 */
18048c2ecf20Sopenharmony_ci			unsigned int hvpgoff_in_page =
18058c2ecf20Sopenharmony_ci				(i + hvpgoff) % NR_HV_HYP_PAGES_IN_PAGE;
18068c2ecf20Sopenharmony_ci
18078c2ecf20Sopenharmony_ci			/*
18088c2ecf20Sopenharmony_ci			 * Two cases that we need to fetch a page:
18098c2ecf20Sopenharmony_ci			 * 1) i == 0, the first step or
18108c2ecf20Sopenharmony_ci			 * 2) hvpgoff_in_page == 0, when we reach the boundary
18118c2ecf20Sopenharmony_ci			 *    of a page.
18128c2ecf20Sopenharmony_ci			 */
18138c2ecf20Sopenharmony_ci			if (hvpgoff_in_page == 0 || i == 0) {
18148c2ecf20Sopenharmony_ci				hvpfn = page_to_hvpfn(sg_page(cur_sgl));
18158c2ecf20Sopenharmony_ci				cur_sgl = sg_next(cur_sgl);
18168c2ecf20Sopenharmony_ci			}
18178c2ecf20Sopenharmony_ci
18188c2ecf20Sopenharmony_ci			payload->range.pfn_array[i] = hvpfn + hvpgoff_in_page;
18198c2ecf20Sopenharmony_ci		}
18208c2ecf20Sopenharmony_ci	}
18218c2ecf20Sopenharmony_ci
18228c2ecf20Sopenharmony_ci	cmd_request->payload = payload;
18238c2ecf20Sopenharmony_ci	cmd_request->payload_sz = payload_sz;
18248c2ecf20Sopenharmony_ci
18258c2ecf20Sopenharmony_ci	/* Invokes the vsc to start an IO */
18268c2ecf20Sopenharmony_ci	ret = storvsc_do_io(dev, cmd_request, get_cpu());
18278c2ecf20Sopenharmony_ci	put_cpu();
18288c2ecf20Sopenharmony_ci
18298c2ecf20Sopenharmony_ci	if (ret == -EAGAIN) {
18308c2ecf20Sopenharmony_ci		if (payload_sz > sizeof(cmd_request->mpb))
18318c2ecf20Sopenharmony_ci			kfree(payload);
18328c2ecf20Sopenharmony_ci		/* no more space */
18338c2ecf20Sopenharmony_ci		return SCSI_MLQUEUE_DEVICE_BUSY;
18348c2ecf20Sopenharmony_ci	}
18358c2ecf20Sopenharmony_ci
18368c2ecf20Sopenharmony_ci	return 0;
18378c2ecf20Sopenharmony_ci}
18388c2ecf20Sopenharmony_ci
18398c2ecf20Sopenharmony_cistatic struct scsi_host_template scsi_driver = {
18408c2ecf20Sopenharmony_ci	.module	=		THIS_MODULE,
18418c2ecf20Sopenharmony_ci	.name =			"storvsc_host_t",
18428c2ecf20Sopenharmony_ci	.cmd_size =             sizeof(struct storvsc_cmd_request),
18438c2ecf20Sopenharmony_ci	.bios_param =		storvsc_get_chs,
18448c2ecf20Sopenharmony_ci	.queuecommand =		storvsc_queuecommand,
18458c2ecf20Sopenharmony_ci	.eh_host_reset_handler =	storvsc_host_reset_handler,
18468c2ecf20Sopenharmony_ci	.proc_name =		"storvsc_host",
18478c2ecf20Sopenharmony_ci	.eh_timed_out =		storvsc_eh_timed_out,
18488c2ecf20Sopenharmony_ci	.slave_alloc =		storvsc_device_alloc,
18498c2ecf20Sopenharmony_ci	.slave_configure =	storvsc_device_configure,
18508c2ecf20Sopenharmony_ci	.cmd_per_lun =		2048,
18518c2ecf20Sopenharmony_ci	.this_id =		-1,
18528c2ecf20Sopenharmony_ci	/* Make sure we dont get a sg segment crosses a page boundary */
18538c2ecf20Sopenharmony_ci	.dma_boundary =		PAGE_SIZE-1,
18548c2ecf20Sopenharmony_ci	/* Ensure there are no gaps in presented sgls */
18558c2ecf20Sopenharmony_ci	.virt_boundary_mask =	PAGE_SIZE-1,
18568c2ecf20Sopenharmony_ci	.no_write_same =	1,
18578c2ecf20Sopenharmony_ci	.track_queue_depth =	1,
18588c2ecf20Sopenharmony_ci	.change_queue_depth =	storvsc_change_queue_depth,
18598c2ecf20Sopenharmony_ci};
18608c2ecf20Sopenharmony_ci
18618c2ecf20Sopenharmony_cienum {
18628c2ecf20Sopenharmony_ci	SCSI_GUID,
18638c2ecf20Sopenharmony_ci	IDE_GUID,
18648c2ecf20Sopenharmony_ci	SFC_GUID,
18658c2ecf20Sopenharmony_ci};
18668c2ecf20Sopenharmony_ci
18678c2ecf20Sopenharmony_cistatic const struct hv_vmbus_device_id id_table[] = {
18688c2ecf20Sopenharmony_ci	/* SCSI guid */
18698c2ecf20Sopenharmony_ci	{ HV_SCSI_GUID,
18708c2ecf20Sopenharmony_ci	  .driver_data = SCSI_GUID
18718c2ecf20Sopenharmony_ci	},
18728c2ecf20Sopenharmony_ci	/* IDE guid */
18738c2ecf20Sopenharmony_ci	{ HV_IDE_GUID,
18748c2ecf20Sopenharmony_ci	  .driver_data = IDE_GUID
18758c2ecf20Sopenharmony_ci	},
18768c2ecf20Sopenharmony_ci	/* Fibre Channel GUID */
18778c2ecf20Sopenharmony_ci	{
18788c2ecf20Sopenharmony_ci	  HV_SYNTHFC_GUID,
18798c2ecf20Sopenharmony_ci	  .driver_data = SFC_GUID
18808c2ecf20Sopenharmony_ci	},
18818c2ecf20Sopenharmony_ci	{ },
18828c2ecf20Sopenharmony_ci};
18838c2ecf20Sopenharmony_ci
18848c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(vmbus, id_table);
18858c2ecf20Sopenharmony_ci
18868c2ecf20Sopenharmony_cistatic const struct { guid_t guid; } fc_guid = { HV_SYNTHFC_GUID };
18878c2ecf20Sopenharmony_ci
18888c2ecf20Sopenharmony_cistatic bool hv_dev_is_fc(struct hv_device *hv_dev)
18898c2ecf20Sopenharmony_ci{
18908c2ecf20Sopenharmony_ci	return guid_equal(&fc_guid.guid, &hv_dev->dev_type);
18918c2ecf20Sopenharmony_ci}
18928c2ecf20Sopenharmony_ci
18938c2ecf20Sopenharmony_cistatic int storvsc_probe(struct hv_device *device,
18948c2ecf20Sopenharmony_ci			const struct hv_vmbus_device_id *dev_id)
18958c2ecf20Sopenharmony_ci{
18968c2ecf20Sopenharmony_ci	int ret;
18978c2ecf20Sopenharmony_ci	int num_cpus = num_online_cpus();
18988c2ecf20Sopenharmony_ci	struct Scsi_Host *host;
18998c2ecf20Sopenharmony_ci	struct hv_host_device *host_dev;
19008c2ecf20Sopenharmony_ci	bool dev_is_ide = ((dev_id->driver_data == IDE_GUID) ? true : false);
19018c2ecf20Sopenharmony_ci	bool is_fc = ((dev_id->driver_data == SFC_GUID) ? true : false);
19028c2ecf20Sopenharmony_ci	int target = 0;
19038c2ecf20Sopenharmony_ci	struct storvsc_device *stor_device;
19048c2ecf20Sopenharmony_ci	int max_luns_per_target;
19058c2ecf20Sopenharmony_ci	int max_targets;
19068c2ecf20Sopenharmony_ci	int max_channels;
19078c2ecf20Sopenharmony_ci	int max_sub_channels = 0;
19088c2ecf20Sopenharmony_ci
19098c2ecf20Sopenharmony_ci	/*
19108c2ecf20Sopenharmony_ci	 * Based on the windows host we are running on,
19118c2ecf20Sopenharmony_ci	 * set state to properly communicate with the host.
19128c2ecf20Sopenharmony_ci	 */
19138c2ecf20Sopenharmony_ci
19148c2ecf20Sopenharmony_ci	if (vmbus_proto_version < VERSION_WIN8) {
19158c2ecf20Sopenharmony_ci		max_luns_per_target = STORVSC_IDE_MAX_LUNS_PER_TARGET;
19168c2ecf20Sopenharmony_ci		max_targets = STORVSC_IDE_MAX_TARGETS;
19178c2ecf20Sopenharmony_ci		max_channels = STORVSC_IDE_MAX_CHANNELS;
19188c2ecf20Sopenharmony_ci	} else {
19198c2ecf20Sopenharmony_ci		max_luns_per_target = STORVSC_MAX_LUNS_PER_TARGET;
19208c2ecf20Sopenharmony_ci		max_targets = STORVSC_MAX_TARGETS;
19218c2ecf20Sopenharmony_ci		max_channels = STORVSC_MAX_CHANNELS;
19228c2ecf20Sopenharmony_ci		/*
19238c2ecf20Sopenharmony_ci		 * On Windows8 and above, we support sub-channels for storage
19248c2ecf20Sopenharmony_ci		 * on SCSI and FC controllers.
19258c2ecf20Sopenharmony_ci		 * The number of sub-channels offerred is based on the number of
19268c2ecf20Sopenharmony_ci		 * VCPUs in the guest.
19278c2ecf20Sopenharmony_ci		 */
19288c2ecf20Sopenharmony_ci		if (!dev_is_ide)
19298c2ecf20Sopenharmony_ci			max_sub_channels =
19308c2ecf20Sopenharmony_ci				(num_cpus - 1) / storvsc_vcpus_per_sub_channel;
19318c2ecf20Sopenharmony_ci	}
19328c2ecf20Sopenharmony_ci
19338c2ecf20Sopenharmony_ci	scsi_driver.can_queue = max_outstanding_req_per_channel *
19348c2ecf20Sopenharmony_ci				(max_sub_channels + 1) *
19358c2ecf20Sopenharmony_ci				(100 - ring_avail_percent_lowater) / 100;
19368c2ecf20Sopenharmony_ci
19378c2ecf20Sopenharmony_ci	host = scsi_host_alloc(&scsi_driver,
19388c2ecf20Sopenharmony_ci			       sizeof(struct hv_host_device));
19398c2ecf20Sopenharmony_ci	if (!host)
19408c2ecf20Sopenharmony_ci		return -ENOMEM;
19418c2ecf20Sopenharmony_ci
19428c2ecf20Sopenharmony_ci	host_dev = shost_priv(host);
19438c2ecf20Sopenharmony_ci	memset(host_dev, 0, sizeof(struct hv_host_device));
19448c2ecf20Sopenharmony_ci
19458c2ecf20Sopenharmony_ci	host_dev->port = host->host_no;
19468c2ecf20Sopenharmony_ci	host_dev->dev = device;
19478c2ecf20Sopenharmony_ci	host_dev->host = host;
19488c2ecf20Sopenharmony_ci
19498c2ecf20Sopenharmony_ci
19508c2ecf20Sopenharmony_ci	stor_device = kzalloc(sizeof(struct storvsc_device), GFP_KERNEL);
19518c2ecf20Sopenharmony_ci	if (!stor_device) {
19528c2ecf20Sopenharmony_ci		ret = -ENOMEM;
19538c2ecf20Sopenharmony_ci		goto err_out0;
19548c2ecf20Sopenharmony_ci	}
19558c2ecf20Sopenharmony_ci
19568c2ecf20Sopenharmony_ci	stor_device->destroy = false;
19578c2ecf20Sopenharmony_ci	init_waitqueue_head(&stor_device->waiting_to_drain);
19588c2ecf20Sopenharmony_ci	stor_device->device = device;
19598c2ecf20Sopenharmony_ci	stor_device->host = host;
19608c2ecf20Sopenharmony_ci	spin_lock_init(&stor_device->lock);
19618c2ecf20Sopenharmony_ci	hv_set_drvdata(device, stor_device);
19628c2ecf20Sopenharmony_ci
19638c2ecf20Sopenharmony_ci	stor_device->port_number = host->host_no;
19648c2ecf20Sopenharmony_ci	ret = storvsc_connect_to_vsp(device, storvsc_ringbuffer_size, is_fc);
19658c2ecf20Sopenharmony_ci	if (ret)
19668c2ecf20Sopenharmony_ci		goto err_out1;
19678c2ecf20Sopenharmony_ci
19688c2ecf20Sopenharmony_ci	host_dev->path = stor_device->path_id;
19698c2ecf20Sopenharmony_ci	host_dev->target = stor_device->target_id;
19708c2ecf20Sopenharmony_ci
19718c2ecf20Sopenharmony_ci	switch (dev_id->driver_data) {
19728c2ecf20Sopenharmony_ci	case SFC_GUID:
19738c2ecf20Sopenharmony_ci		host->max_lun = STORVSC_FC_MAX_LUNS_PER_TARGET;
19748c2ecf20Sopenharmony_ci		host->max_id = STORVSC_FC_MAX_TARGETS;
19758c2ecf20Sopenharmony_ci		host->max_channel = STORVSC_FC_MAX_CHANNELS - 1;
19768c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_SCSI_FC_ATTRS)
19778c2ecf20Sopenharmony_ci		host->transportt = fc_transport_template;
19788c2ecf20Sopenharmony_ci#endif
19798c2ecf20Sopenharmony_ci		break;
19808c2ecf20Sopenharmony_ci
19818c2ecf20Sopenharmony_ci	case SCSI_GUID:
19828c2ecf20Sopenharmony_ci		host->max_lun = max_luns_per_target;
19838c2ecf20Sopenharmony_ci		host->max_id = max_targets;
19848c2ecf20Sopenharmony_ci		host->max_channel = max_channels - 1;
19858c2ecf20Sopenharmony_ci		break;
19868c2ecf20Sopenharmony_ci
19878c2ecf20Sopenharmony_ci	default:
19888c2ecf20Sopenharmony_ci		host->max_lun = STORVSC_IDE_MAX_LUNS_PER_TARGET;
19898c2ecf20Sopenharmony_ci		host->max_id = STORVSC_IDE_MAX_TARGETS;
19908c2ecf20Sopenharmony_ci		host->max_channel = STORVSC_IDE_MAX_CHANNELS - 1;
19918c2ecf20Sopenharmony_ci		break;
19928c2ecf20Sopenharmony_ci	}
19938c2ecf20Sopenharmony_ci	/* max cmd length */
19948c2ecf20Sopenharmony_ci	host->max_cmd_len = STORVSC_MAX_CMD_LEN;
19958c2ecf20Sopenharmony_ci
19968c2ecf20Sopenharmony_ci	/*
19978c2ecf20Sopenharmony_ci	 * set the table size based on the info we got
19988c2ecf20Sopenharmony_ci	 * from the host.
19998c2ecf20Sopenharmony_ci	 */
20008c2ecf20Sopenharmony_ci	host->sg_tablesize = (stor_device->max_transfer_bytes >> PAGE_SHIFT);
20018c2ecf20Sopenharmony_ci	/*
20028c2ecf20Sopenharmony_ci	 * For non-IDE disks, the host supports multiple channels.
20038c2ecf20Sopenharmony_ci	 * Set the number of HW queues we are supporting.
20048c2ecf20Sopenharmony_ci	 */
20058c2ecf20Sopenharmony_ci	if (!dev_is_ide)
20068c2ecf20Sopenharmony_ci		host->nr_hw_queues = num_present_cpus();
20078c2ecf20Sopenharmony_ci
20088c2ecf20Sopenharmony_ci	/*
20098c2ecf20Sopenharmony_ci	 * Set the error handler work queue.
20108c2ecf20Sopenharmony_ci	 */
20118c2ecf20Sopenharmony_ci	host_dev->handle_error_wq =
20128c2ecf20Sopenharmony_ci			alloc_ordered_workqueue("storvsc_error_wq_%d",
20138c2ecf20Sopenharmony_ci						0,
20148c2ecf20Sopenharmony_ci						host->host_no);
20158c2ecf20Sopenharmony_ci	if (!host_dev->handle_error_wq) {
20168c2ecf20Sopenharmony_ci		ret = -ENOMEM;
20178c2ecf20Sopenharmony_ci		goto err_out2;
20188c2ecf20Sopenharmony_ci	}
20198c2ecf20Sopenharmony_ci	INIT_WORK(&host_dev->host_scan_work, storvsc_host_scan);
20208c2ecf20Sopenharmony_ci	/* Register the HBA and start the scsi bus scan */
20218c2ecf20Sopenharmony_ci	ret = scsi_add_host(host, &device->device);
20228c2ecf20Sopenharmony_ci	if (ret != 0)
20238c2ecf20Sopenharmony_ci		goto err_out3;
20248c2ecf20Sopenharmony_ci
20258c2ecf20Sopenharmony_ci	if (!dev_is_ide) {
20268c2ecf20Sopenharmony_ci		scsi_scan_host(host);
20278c2ecf20Sopenharmony_ci	} else {
20288c2ecf20Sopenharmony_ci		target = (device->dev_instance.b[5] << 8 |
20298c2ecf20Sopenharmony_ci			 device->dev_instance.b[4]);
20308c2ecf20Sopenharmony_ci		ret = scsi_add_device(host, 0, target, 0);
20318c2ecf20Sopenharmony_ci		if (ret)
20328c2ecf20Sopenharmony_ci			goto err_out4;
20338c2ecf20Sopenharmony_ci	}
20348c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_SCSI_FC_ATTRS)
20358c2ecf20Sopenharmony_ci	if (host->transportt == fc_transport_template) {
20368c2ecf20Sopenharmony_ci		struct fc_rport_identifiers ids = {
20378c2ecf20Sopenharmony_ci			.roles = FC_PORT_ROLE_FCP_DUMMY_INITIATOR,
20388c2ecf20Sopenharmony_ci		};
20398c2ecf20Sopenharmony_ci
20408c2ecf20Sopenharmony_ci		fc_host_node_name(host) = stor_device->node_name;
20418c2ecf20Sopenharmony_ci		fc_host_port_name(host) = stor_device->port_name;
20428c2ecf20Sopenharmony_ci		stor_device->rport = fc_remote_port_add(host, 0, &ids);
20438c2ecf20Sopenharmony_ci		if (!stor_device->rport) {
20448c2ecf20Sopenharmony_ci			ret = -ENOMEM;
20458c2ecf20Sopenharmony_ci			goto err_out4;
20468c2ecf20Sopenharmony_ci		}
20478c2ecf20Sopenharmony_ci	}
20488c2ecf20Sopenharmony_ci#endif
20498c2ecf20Sopenharmony_ci	return 0;
20508c2ecf20Sopenharmony_ci
20518c2ecf20Sopenharmony_cierr_out4:
20528c2ecf20Sopenharmony_ci	scsi_remove_host(host);
20538c2ecf20Sopenharmony_ci
20548c2ecf20Sopenharmony_cierr_out3:
20558c2ecf20Sopenharmony_ci	destroy_workqueue(host_dev->handle_error_wq);
20568c2ecf20Sopenharmony_ci
20578c2ecf20Sopenharmony_cierr_out2:
20588c2ecf20Sopenharmony_ci	/*
20598c2ecf20Sopenharmony_ci	 * Once we have connected with the host, we would need to
20608c2ecf20Sopenharmony_ci	 * to invoke storvsc_dev_remove() to rollback this state and
20618c2ecf20Sopenharmony_ci	 * this call also frees up the stor_device; hence the jump around
20628c2ecf20Sopenharmony_ci	 * err_out1 label.
20638c2ecf20Sopenharmony_ci	 */
20648c2ecf20Sopenharmony_ci	storvsc_dev_remove(device);
20658c2ecf20Sopenharmony_ci	goto err_out0;
20668c2ecf20Sopenharmony_ci
20678c2ecf20Sopenharmony_cierr_out1:
20688c2ecf20Sopenharmony_ci	kfree(stor_device->stor_chns);
20698c2ecf20Sopenharmony_ci	kfree(stor_device);
20708c2ecf20Sopenharmony_ci
20718c2ecf20Sopenharmony_cierr_out0:
20728c2ecf20Sopenharmony_ci	scsi_host_put(host);
20738c2ecf20Sopenharmony_ci	return ret;
20748c2ecf20Sopenharmony_ci}
20758c2ecf20Sopenharmony_ci
20768c2ecf20Sopenharmony_ci/* Change a scsi target's queue depth */
20778c2ecf20Sopenharmony_cistatic int storvsc_change_queue_depth(struct scsi_device *sdev, int queue_depth)
20788c2ecf20Sopenharmony_ci{
20798c2ecf20Sopenharmony_ci	if (queue_depth > scsi_driver.can_queue)
20808c2ecf20Sopenharmony_ci		queue_depth = scsi_driver.can_queue;
20818c2ecf20Sopenharmony_ci
20828c2ecf20Sopenharmony_ci	return scsi_change_queue_depth(sdev, queue_depth);
20838c2ecf20Sopenharmony_ci}
20848c2ecf20Sopenharmony_ci
20858c2ecf20Sopenharmony_cistatic int storvsc_remove(struct hv_device *dev)
20868c2ecf20Sopenharmony_ci{
20878c2ecf20Sopenharmony_ci	struct storvsc_device *stor_device = hv_get_drvdata(dev);
20888c2ecf20Sopenharmony_ci	struct Scsi_Host *host = stor_device->host;
20898c2ecf20Sopenharmony_ci	struct hv_host_device *host_dev = shost_priv(host);
20908c2ecf20Sopenharmony_ci
20918c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_SCSI_FC_ATTRS)
20928c2ecf20Sopenharmony_ci	if (host->transportt == fc_transport_template) {
20938c2ecf20Sopenharmony_ci		fc_remote_port_delete(stor_device->rport);
20948c2ecf20Sopenharmony_ci		fc_remove_host(host);
20958c2ecf20Sopenharmony_ci	}
20968c2ecf20Sopenharmony_ci#endif
20978c2ecf20Sopenharmony_ci	destroy_workqueue(host_dev->handle_error_wq);
20988c2ecf20Sopenharmony_ci	scsi_remove_host(host);
20998c2ecf20Sopenharmony_ci	storvsc_dev_remove(dev);
21008c2ecf20Sopenharmony_ci	scsi_host_put(host);
21018c2ecf20Sopenharmony_ci
21028c2ecf20Sopenharmony_ci	return 0;
21038c2ecf20Sopenharmony_ci}
21048c2ecf20Sopenharmony_ci
21058c2ecf20Sopenharmony_cistatic int storvsc_suspend(struct hv_device *hv_dev)
21068c2ecf20Sopenharmony_ci{
21078c2ecf20Sopenharmony_ci	struct storvsc_device *stor_device = hv_get_drvdata(hv_dev);
21088c2ecf20Sopenharmony_ci	struct Scsi_Host *host = stor_device->host;
21098c2ecf20Sopenharmony_ci	struct hv_host_device *host_dev = shost_priv(host);
21108c2ecf20Sopenharmony_ci
21118c2ecf20Sopenharmony_ci	storvsc_wait_to_drain(stor_device);
21128c2ecf20Sopenharmony_ci
21138c2ecf20Sopenharmony_ci	drain_workqueue(host_dev->handle_error_wq);
21148c2ecf20Sopenharmony_ci
21158c2ecf20Sopenharmony_ci	vmbus_close(hv_dev->channel);
21168c2ecf20Sopenharmony_ci
21178c2ecf20Sopenharmony_ci	kfree(stor_device->stor_chns);
21188c2ecf20Sopenharmony_ci	stor_device->stor_chns = NULL;
21198c2ecf20Sopenharmony_ci
21208c2ecf20Sopenharmony_ci	cpumask_clear(&stor_device->alloced_cpus);
21218c2ecf20Sopenharmony_ci
21228c2ecf20Sopenharmony_ci	return 0;
21238c2ecf20Sopenharmony_ci}
21248c2ecf20Sopenharmony_ci
21258c2ecf20Sopenharmony_cistatic int storvsc_resume(struct hv_device *hv_dev)
21268c2ecf20Sopenharmony_ci{
21278c2ecf20Sopenharmony_ci	int ret;
21288c2ecf20Sopenharmony_ci
21298c2ecf20Sopenharmony_ci	ret = storvsc_connect_to_vsp(hv_dev, storvsc_ringbuffer_size,
21308c2ecf20Sopenharmony_ci				     hv_dev_is_fc(hv_dev));
21318c2ecf20Sopenharmony_ci	return ret;
21328c2ecf20Sopenharmony_ci}
21338c2ecf20Sopenharmony_ci
21348c2ecf20Sopenharmony_cistatic struct hv_driver storvsc_drv = {
21358c2ecf20Sopenharmony_ci	.name = KBUILD_MODNAME,
21368c2ecf20Sopenharmony_ci	.id_table = id_table,
21378c2ecf20Sopenharmony_ci	.probe = storvsc_probe,
21388c2ecf20Sopenharmony_ci	.remove = storvsc_remove,
21398c2ecf20Sopenharmony_ci	.suspend = storvsc_suspend,
21408c2ecf20Sopenharmony_ci	.resume = storvsc_resume,
21418c2ecf20Sopenharmony_ci	.driver = {
21428c2ecf20Sopenharmony_ci		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
21438c2ecf20Sopenharmony_ci	},
21448c2ecf20Sopenharmony_ci};
21458c2ecf20Sopenharmony_ci
21468c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_SCSI_FC_ATTRS)
21478c2ecf20Sopenharmony_cistatic struct fc_function_template fc_transport_functions = {
21488c2ecf20Sopenharmony_ci	.show_host_node_name = 1,
21498c2ecf20Sopenharmony_ci	.show_host_port_name = 1,
21508c2ecf20Sopenharmony_ci};
21518c2ecf20Sopenharmony_ci#endif
21528c2ecf20Sopenharmony_ci
21538c2ecf20Sopenharmony_cistatic int __init storvsc_drv_init(void)
21548c2ecf20Sopenharmony_ci{
21558c2ecf20Sopenharmony_ci	int ret;
21568c2ecf20Sopenharmony_ci
21578c2ecf20Sopenharmony_ci	/*
21588c2ecf20Sopenharmony_ci	 * Divide the ring buffer data size (which is 1 page less
21598c2ecf20Sopenharmony_ci	 * than the ring buffer size since that page is reserved for
21608c2ecf20Sopenharmony_ci	 * the ring buffer indices) by the max request size (which is
21618c2ecf20Sopenharmony_ci	 * vmbus_channel_packet_multipage_buffer + struct vstor_packet + u64)
21628c2ecf20Sopenharmony_ci	 */
21638c2ecf20Sopenharmony_ci	max_outstanding_req_per_channel =
21648c2ecf20Sopenharmony_ci		((storvsc_ringbuffer_size - PAGE_SIZE) /
21658c2ecf20Sopenharmony_ci		ALIGN(MAX_MULTIPAGE_BUFFER_PACKET +
21668c2ecf20Sopenharmony_ci		sizeof(struct vstor_packet) + sizeof(u64) -
21678c2ecf20Sopenharmony_ci		vmscsi_size_delta,
21688c2ecf20Sopenharmony_ci		sizeof(u64)));
21698c2ecf20Sopenharmony_ci
21708c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_SCSI_FC_ATTRS)
21718c2ecf20Sopenharmony_ci	fc_transport_template = fc_attach_transport(&fc_transport_functions);
21728c2ecf20Sopenharmony_ci	if (!fc_transport_template)
21738c2ecf20Sopenharmony_ci		return -ENODEV;
21748c2ecf20Sopenharmony_ci#endif
21758c2ecf20Sopenharmony_ci
21768c2ecf20Sopenharmony_ci	ret = vmbus_driver_register(&storvsc_drv);
21778c2ecf20Sopenharmony_ci
21788c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_SCSI_FC_ATTRS)
21798c2ecf20Sopenharmony_ci	if (ret)
21808c2ecf20Sopenharmony_ci		fc_release_transport(fc_transport_template);
21818c2ecf20Sopenharmony_ci#endif
21828c2ecf20Sopenharmony_ci
21838c2ecf20Sopenharmony_ci	return ret;
21848c2ecf20Sopenharmony_ci}
21858c2ecf20Sopenharmony_ci
21868c2ecf20Sopenharmony_cistatic void __exit storvsc_drv_exit(void)
21878c2ecf20Sopenharmony_ci{
21888c2ecf20Sopenharmony_ci	vmbus_driver_unregister(&storvsc_drv);
21898c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_SCSI_FC_ATTRS)
21908c2ecf20Sopenharmony_ci	fc_release_transport(fc_transport_template);
21918c2ecf20Sopenharmony_ci#endif
21928c2ecf20Sopenharmony_ci}
21938c2ecf20Sopenharmony_ci
21948c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
21958c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Microsoft Hyper-V virtual storage driver");
21968c2ecf20Sopenharmony_cimodule_init(storvsc_drv_init);
21978c2ecf20Sopenharmony_cimodule_exit(storvsc_drv_exit);
2198