162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2009, Microsoft Corporation. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Authors: 662306a36Sopenharmony_ci * Haiyang Zhang <haiyangz@microsoft.com> 762306a36Sopenharmony_ci * Hank Janssen <hjanssen@microsoft.com> 862306a36Sopenharmony_ci * K. Y. Srinivasan <kys@microsoft.com> 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/kernel.h> 1262306a36Sopenharmony_ci#include <linux/wait.h> 1362306a36Sopenharmony_ci#include <linux/sched.h> 1462306a36Sopenharmony_ci#include <linux/completion.h> 1562306a36Sopenharmony_ci#include <linux/string.h> 1662306a36Sopenharmony_ci#include <linux/mm.h> 1762306a36Sopenharmony_ci#include <linux/delay.h> 1862306a36Sopenharmony_ci#include <linux/init.h> 1962306a36Sopenharmony_ci#include <linux/slab.h> 2062306a36Sopenharmony_ci#include <linux/module.h> 2162306a36Sopenharmony_ci#include <linux/device.h> 2262306a36Sopenharmony_ci#include <linux/hyperv.h> 2362306a36Sopenharmony_ci#include <linux/blkdev.h> 2462306a36Sopenharmony_ci#include <linux/dma-mapping.h> 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#include <scsi/scsi.h> 2762306a36Sopenharmony_ci#include <scsi/scsi_cmnd.h> 2862306a36Sopenharmony_ci#include <scsi/scsi_host.h> 2962306a36Sopenharmony_ci#include <scsi/scsi_device.h> 3062306a36Sopenharmony_ci#include <scsi/scsi_tcq.h> 3162306a36Sopenharmony_ci#include <scsi/scsi_eh.h> 3262306a36Sopenharmony_ci#include <scsi/scsi_devinfo.h> 3362306a36Sopenharmony_ci#include <scsi/scsi_dbg.h> 3462306a36Sopenharmony_ci#include <scsi/scsi_transport_fc.h> 3562306a36Sopenharmony_ci#include <scsi/scsi_transport.h> 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci/* 3862306a36Sopenharmony_ci * All wire protocol details (storage protocol between the guest and the host) 3962306a36Sopenharmony_ci * are consolidated here. 4062306a36Sopenharmony_ci * 4162306a36Sopenharmony_ci * Begin protocol definitions. 4262306a36Sopenharmony_ci */ 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci/* 4562306a36Sopenharmony_ci * Version history: 4662306a36Sopenharmony_ci * V1 Beta: 0.1 4762306a36Sopenharmony_ci * V1 RC < 2008/1/31: 1.0 4862306a36Sopenharmony_ci * V1 RC > 2008/1/31: 2.0 4962306a36Sopenharmony_ci * Win7: 4.2 5062306a36Sopenharmony_ci * Win8: 5.1 5162306a36Sopenharmony_ci * Win8.1: 6.0 5262306a36Sopenharmony_ci * Win10: 6.2 5362306a36Sopenharmony_ci */ 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci#define VMSTOR_PROTO_VERSION(MAJOR_, MINOR_) ((((MAJOR_) & 0xff) << 8) | \ 5662306a36Sopenharmony_ci (((MINOR_) & 0xff))) 5762306a36Sopenharmony_ci#define VMSTOR_PROTO_VERSION_WIN6 VMSTOR_PROTO_VERSION(2, 0) 5862306a36Sopenharmony_ci#define VMSTOR_PROTO_VERSION_WIN7 VMSTOR_PROTO_VERSION(4, 2) 5962306a36Sopenharmony_ci#define VMSTOR_PROTO_VERSION_WIN8 VMSTOR_PROTO_VERSION(5, 1) 6062306a36Sopenharmony_ci#define VMSTOR_PROTO_VERSION_WIN8_1 VMSTOR_PROTO_VERSION(6, 0) 6162306a36Sopenharmony_ci#define VMSTOR_PROTO_VERSION_WIN10 VMSTOR_PROTO_VERSION(6, 2) 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci/* channel callback timeout in ms */ 6462306a36Sopenharmony_ci#define CALLBACK_TIMEOUT 2 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci/* Packet structure describing virtual storage requests. */ 6762306a36Sopenharmony_cienum vstor_packet_operation { 6862306a36Sopenharmony_ci VSTOR_OPERATION_COMPLETE_IO = 1, 6962306a36Sopenharmony_ci VSTOR_OPERATION_REMOVE_DEVICE = 2, 7062306a36Sopenharmony_ci VSTOR_OPERATION_EXECUTE_SRB = 3, 7162306a36Sopenharmony_ci VSTOR_OPERATION_RESET_LUN = 4, 7262306a36Sopenharmony_ci VSTOR_OPERATION_RESET_ADAPTER = 5, 7362306a36Sopenharmony_ci VSTOR_OPERATION_RESET_BUS = 6, 7462306a36Sopenharmony_ci VSTOR_OPERATION_BEGIN_INITIALIZATION = 7, 7562306a36Sopenharmony_ci VSTOR_OPERATION_END_INITIALIZATION = 8, 7662306a36Sopenharmony_ci VSTOR_OPERATION_QUERY_PROTOCOL_VERSION = 9, 7762306a36Sopenharmony_ci VSTOR_OPERATION_QUERY_PROPERTIES = 10, 7862306a36Sopenharmony_ci VSTOR_OPERATION_ENUMERATE_BUS = 11, 7962306a36Sopenharmony_ci VSTOR_OPERATION_FCHBA_DATA = 12, 8062306a36Sopenharmony_ci VSTOR_OPERATION_CREATE_SUB_CHANNELS = 13, 8162306a36Sopenharmony_ci VSTOR_OPERATION_MAXIMUM = 13 8262306a36Sopenharmony_ci}; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci/* 8562306a36Sopenharmony_ci * WWN packet for Fibre Channel HBA 8662306a36Sopenharmony_ci */ 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_cistruct hv_fc_wwn_packet { 8962306a36Sopenharmony_ci u8 primary_active; 9062306a36Sopenharmony_ci u8 reserved1[3]; 9162306a36Sopenharmony_ci u8 primary_port_wwn[8]; 9262306a36Sopenharmony_ci u8 primary_node_wwn[8]; 9362306a36Sopenharmony_ci u8 secondary_port_wwn[8]; 9462306a36Sopenharmony_ci u8 secondary_node_wwn[8]; 9562306a36Sopenharmony_ci}; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci/* 10062306a36Sopenharmony_ci * SRB Flag Bits 10162306a36Sopenharmony_ci */ 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci#define SRB_FLAGS_QUEUE_ACTION_ENABLE 0x00000002 10462306a36Sopenharmony_ci#define SRB_FLAGS_DISABLE_DISCONNECT 0x00000004 10562306a36Sopenharmony_ci#define SRB_FLAGS_DISABLE_SYNCH_TRANSFER 0x00000008 10662306a36Sopenharmony_ci#define SRB_FLAGS_BYPASS_FROZEN_QUEUE 0x00000010 10762306a36Sopenharmony_ci#define SRB_FLAGS_DISABLE_AUTOSENSE 0x00000020 10862306a36Sopenharmony_ci#define SRB_FLAGS_DATA_IN 0x00000040 10962306a36Sopenharmony_ci#define SRB_FLAGS_DATA_OUT 0x00000080 11062306a36Sopenharmony_ci#define SRB_FLAGS_NO_DATA_TRANSFER 0x00000000 11162306a36Sopenharmony_ci#define SRB_FLAGS_UNSPECIFIED_DIRECTION (SRB_FLAGS_DATA_IN | SRB_FLAGS_DATA_OUT) 11262306a36Sopenharmony_ci#define SRB_FLAGS_NO_QUEUE_FREEZE 0x00000100 11362306a36Sopenharmony_ci#define SRB_FLAGS_ADAPTER_CACHE_ENABLE 0x00000200 11462306a36Sopenharmony_ci#define SRB_FLAGS_FREE_SENSE_BUFFER 0x00000400 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci/* 11762306a36Sopenharmony_ci * This flag indicates the request is part of the workflow for processing a D3. 11862306a36Sopenharmony_ci */ 11962306a36Sopenharmony_ci#define SRB_FLAGS_D3_PROCESSING 0x00000800 12062306a36Sopenharmony_ci#define SRB_FLAGS_IS_ACTIVE 0x00010000 12162306a36Sopenharmony_ci#define SRB_FLAGS_ALLOCATED_FROM_ZONE 0x00020000 12262306a36Sopenharmony_ci#define SRB_FLAGS_SGLIST_FROM_POOL 0x00040000 12362306a36Sopenharmony_ci#define SRB_FLAGS_BYPASS_LOCKED_QUEUE 0x00080000 12462306a36Sopenharmony_ci#define SRB_FLAGS_NO_KEEP_AWAKE 0x00100000 12562306a36Sopenharmony_ci#define SRB_FLAGS_PORT_DRIVER_ALLOCSENSE 0x00200000 12662306a36Sopenharmony_ci#define SRB_FLAGS_PORT_DRIVER_SENSEHASPORT 0x00400000 12762306a36Sopenharmony_ci#define SRB_FLAGS_DONT_START_NEXT_PACKET 0x00800000 12862306a36Sopenharmony_ci#define SRB_FLAGS_PORT_DRIVER_RESERVED 0x0F000000 12962306a36Sopenharmony_ci#define SRB_FLAGS_CLASS_DRIVER_RESERVED 0xF0000000 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci#define SP_UNTAGGED ((unsigned char) ~0) 13262306a36Sopenharmony_ci#define SRB_SIMPLE_TAG_REQUEST 0x20 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci/* 13562306a36Sopenharmony_ci * Platform neutral description of a scsi request - 13662306a36Sopenharmony_ci * this remains the same across the write regardless of 32/64 bit 13762306a36Sopenharmony_ci * note: it's patterned off the SCSI_PASS_THROUGH structure 13862306a36Sopenharmony_ci */ 13962306a36Sopenharmony_ci#define STORVSC_MAX_CMD_LEN 0x10 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci/* Sense buffer size is the same for all versions since Windows 8 */ 14262306a36Sopenharmony_ci#define STORVSC_SENSE_BUFFER_SIZE 0x14 14362306a36Sopenharmony_ci#define STORVSC_MAX_BUF_LEN_WITH_PADDING 0x14 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci/* 14662306a36Sopenharmony_ci * The storage protocol version is determined during the 14762306a36Sopenharmony_ci * initial exchange with the host. It will indicate which 14862306a36Sopenharmony_ci * storage functionality is available in the host. 14962306a36Sopenharmony_ci*/ 15062306a36Sopenharmony_cistatic int vmstor_proto_version; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci#define STORVSC_LOGGING_NONE 0 15362306a36Sopenharmony_ci#define STORVSC_LOGGING_ERROR 1 15462306a36Sopenharmony_ci#define STORVSC_LOGGING_WARN 2 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_cistatic int logging_level = STORVSC_LOGGING_ERROR; 15762306a36Sopenharmony_cimodule_param(logging_level, int, S_IRUGO|S_IWUSR); 15862306a36Sopenharmony_ciMODULE_PARM_DESC(logging_level, 15962306a36Sopenharmony_ci "Logging level, 0 - None, 1 - Error (default), 2 - Warning."); 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_cistatic inline bool do_logging(int level) 16262306a36Sopenharmony_ci{ 16362306a36Sopenharmony_ci return logging_level >= level; 16462306a36Sopenharmony_ci} 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci#define storvsc_log(dev, level, fmt, ...) \ 16762306a36Sopenharmony_cido { \ 16862306a36Sopenharmony_ci if (do_logging(level)) \ 16962306a36Sopenharmony_ci dev_warn(&(dev)->device, fmt, ##__VA_ARGS__); \ 17062306a36Sopenharmony_ci} while (0) 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_cistruct vmscsi_request { 17362306a36Sopenharmony_ci u16 length; 17462306a36Sopenharmony_ci u8 srb_status; 17562306a36Sopenharmony_ci u8 scsi_status; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci u8 port_number; 17862306a36Sopenharmony_ci u8 path_id; 17962306a36Sopenharmony_ci u8 target_id; 18062306a36Sopenharmony_ci u8 lun; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci u8 cdb_length; 18362306a36Sopenharmony_ci u8 sense_info_length; 18462306a36Sopenharmony_ci u8 data_in; 18562306a36Sopenharmony_ci u8 reserved; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci u32 data_transfer_length; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci union { 19062306a36Sopenharmony_ci u8 cdb[STORVSC_MAX_CMD_LEN]; 19162306a36Sopenharmony_ci u8 sense_data[STORVSC_SENSE_BUFFER_SIZE]; 19262306a36Sopenharmony_ci u8 reserved_array[STORVSC_MAX_BUF_LEN_WITH_PADDING]; 19362306a36Sopenharmony_ci }; 19462306a36Sopenharmony_ci /* 19562306a36Sopenharmony_ci * The following was added in win8. 19662306a36Sopenharmony_ci */ 19762306a36Sopenharmony_ci u16 reserve; 19862306a36Sopenharmony_ci u8 queue_tag; 19962306a36Sopenharmony_ci u8 queue_action; 20062306a36Sopenharmony_ci u32 srb_flags; 20162306a36Sopenharmony_ci u32 time_out_value; 20262306a36Sopenharmony_ci u32 queue_sort_ey; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci} __attribute((packed)); 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci/* 20762306a36Sopenharmony_ci * The list of windows version in order of preference. 20862306a36Sopenharmony_ci */ 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_cistatic const int protocol_version[] = { 21162306a36Sopenharmony_ci VMSTOR_PROTO_VERSION_WIN10, 21262306a36Sopenharmony_ci VMSTOR_PROTO_VERSION_WIN8_1, 21362306a36Sopenharmony_ci VMSTOR_PROTO_VERSION_WIN8, 21462306a36Sopenharmony_ci}; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci/* 21862306a36Sopenharmony_ci * This structure is sent during the initialization phase to get the different 21962306a36Sopenharmony_ci * properties of the channel. 22062306a36Sopenharmony_ci */ 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci#define STORAGE_CHANNEL_SUPPORTS_MULTI_CHANNEL 0x1 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_cistruct vmstorage_channel_properties { 22562306a36Sopenharmony_ci u32 reserved; 22662306a36Sopenharmony_ci u16 max_channel_cnt; 22762306a36Sopenharmony_ci u16 reserved1; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci u32 flags; 23062306a36Sopenharmony_ci u32 max_transfer_bytes; 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci u64 reserved2; 23362306a36Sopenharmony_ci} __packed; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci/* This structure is sent during the storage protocol negotiations. */ 23662306a36Sopenharmony_cistruct vmstorage_protocol_version { 23762306a36Sopenharmony_ci /* Major (MSW) and minor (LSW) version numbers. */ 23862306a36Sopenharmony_ci u16 major_minor; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci /* 24162306a36Sopenharmony_ci * Revision number is auto-incremented whenever this file is changed 24262306a36Sopenharmony_ci * (See FILL_VMSTOR_REVISION macro above). Mismatch does not 24362306a36Sopenharmony_ci * definitely indicate incompatibility--but it does indicate mismatched 24462306a36Sopenharmony_ci * builds. 24562306a36Sopenharmony_ci * This is only used on the windows side. Just set it to 0. 24662306a36Sopenharmony_ci */ 24762306a36Sopenharmony_ci u16 revision; 24862306a36Sopenharmony_ci} __packed; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci/* Channel Property Flags */ 25162306a36Sopenharmony_ci#define STORAGE_CHANNEL_REMOVABLE_FLAG 0x1 25262306a36Sopenharmony_ci#define STORAGE_CHANNEL_EMULATED_IDE_FLAG 0x2 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_cistruct vstor_packet { 25562306a36Sopenharmony_ci /* Requested operation type */ 25662306a36Sopenharmony_ci enum vstor_packet_operation operation; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci /* Flags - see below for values */ 25962306a36Sopenharmony_ci u32 flags; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci /* Status of the request returned from the server side. */ 26262306a36Sopenharmony_ci u32 status; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci /* Data payload area */ 26562306a36Sopenharmony_ci union { 26662306a36Sopenharmony_ci /* 26762306a36Sopenharmony_ci * Structure used to forward SCSI commands from the 26862306a36Sopenharmony_ci * client to the server. 26962306a36Sopenharmony_ci */ 27062306a36Sopenharmony_ci struct vmscsi_request vm_srb; 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci /* Structure used to query channel properties. */ 27362306a36Sopenharmony_ci struct vmstorage_channel_properties storage_channel_properties; 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci /* Used during version negotiations. */ 27662306a36Sopenharmony_ci struct vmstorage_protocol_version version; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci /* Fibre channel address packet */ 27962306a36Sopenharmony_ci struct hv_fc_wwn_packet wwn_packet; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci /* Number of sub-channels to create */ 28262306a36Sopenharmony_ci u16 sub_channel_count; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci /* This will be the maximum of the union members */ 28562306a36Sopenharmony_ci u8 buffer[0x34]; 28662306a36Sopenharmony_ci }; 28762306a36Sopenharmony_ci} __packed; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci/* 29062306a36Sopenharmony_ci * Packet Flags: 29162306a36Sopenharmony_ci * 29262306a36Sopenharmony_ci * This flag indicates that the server should send back a completion for this 29362306a36Sopenharmony_ci * packet. 29462306a36Sopenharmony_ci */ 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci#define REQUEST_COMPLETION_FLAG 0x1 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci/* Matches Windows-end */ 29962306a36Sopenharmony_cienum storvsc_request_type { 30062306a36Sopenharmony_ci WRITE_TYPE = 0, 30162306a36Sopenharmony_ci READ_TYPE, 30262306a36Sopenharmony_ci UNKNOWN_TYPE, 30362306a36Sopenharmony_ci}; 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci/* 30662306a36Sopenharmony_ci * SRB status codes and masks. In the 8-bit field, the two high order bits 30762306a36Sopenharmony_ci * are flags, while the remaining 6 bits are an integer status code. The 30862306a36Sopenharmony_ci * definitions here include only the subset of the integer status codes that 30962306a36Sopenharmony_ci * are tested for in this driver. 31062306a36Sopenharmony_ci */ 31162306a36Sopenharmony_ci#define SRB_STATUS_AUTOSENSE_VALID 0x80 31262306a36Sopenharmony_ci#define SRB_STATUS_QUEUE_FROZEN 0x40 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci/* SRB status integer codes */ 31562306a36Sopenharmony_ci#define SRB_STATUS_SUCCESS 0x01 31662306a36Sopenharmony_ci#define SRB_STATUS_ABORTED 0x02 31762306a36Sopenharmony_ci#define SRB_STATUS_ERROR 0x04 31862306a36Sopenharmony_ci#define SRB_STATUS_INVALID_REQUEST 0x06 31962306a36Sopenharmony_ci#define SRB_STATUS_TIMEOUT 0x09 32062306a36Sopenharmony_ci#define SRB_STATUS_SELECTION_TIMEOUT 0x0A 32162306a36Sopenharmony_ci#define SRB_STATUS_BUS_RESET 0x0E 32262306a36Sopenharmony_ci#define SRB_STATUS_DATA_OVERRUN 0x12 32362306a36Sopenharmony_ci#define SRB_STATUS_INVALID_LUN 0x20 32462306a36Sopenharmony_ci#define SRB_STATUS_INTERNAL_ERROR 0x30 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci#define SRB_STATUS(status) \ 32762306a36Sopenharmony_ci (status & ~(SRB_STATUS_AUTOSENSE_VALID | SRB_STATUS_QUEUE_FROZEN)) 32862306a36Sopenharmony_ci/* 32962306a36Sopenharmony_ci * This is the end of Protocol specific defines. 33062306a36Sopenharmony_ci */ 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_cistatic int storvsc_ringbuffer_size = (128 * 1024); 33362306a36Sopenharmony_cistatic int aligned_ringbuffer_size; 33462306a36Sopenharmony_cistatic u32 max_outstanding_req_per_channel; 33562306a36Sopenharmony_cistatic int storvsc_change_queue_depth(struct scsi_device *sdev, int queue_depth); 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_cistatic int storvsc_vcpus_per_sub_channel = 4; 33862306a36Sopenharmony_cistatic unsigned int storvsc_max_hw_queues; 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_cimodule_param(storvsc_ringbuffer_size, int, S_IRUGO); 34162306a36Sopenharmony_ciMODULE_PARM_DESC(storvsc_ringbuffer_size, "Ring buffer size (bytes)"); 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_cimodule_param(storvsc_max_hw_queues, uint, 0644); 34462306a36Sopenharmony_ciMODULE_PARM_DESC(storvsc_max_hw_queues, "Maximum number of hardware queues"); 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_cimodule_param(storvsc_vcpus_per_sub_channel, int, S_IRUGO); 34762306a36Sopenharmony_ciMODULE_PARM_DESC(storvsc_vcpus_per_sub_channel, "Ratio of VCPUs to subchannels"); 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_cistatic int ring_avail_percent_lowater = 10; 35062306a36Sopenharmony_cimodule_param(ring_avail_percent_lowater, int, S_IRUGO); 35162306a36Sopenharmony_ciMODULE_PARM_DESC(ring_avail_percent_lowater, 35262306a36Sopenharmony_ci "Select a channel if available ring size > this in percent"); 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci/* 35562306a36Sopenharmony_ci * Timeout in seconds for all devices managed by this driver. 35662306a36Sopenharmony_ci */ 35762306a36Sopenharmony_cistatic int storvsc_timeout = 180; 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_SCSI_FC_ATTRS) 36062306a36Sopenharmony_cistatic struct scsi_transport_template *fc_transport_template; 36162306a36Sopenharmony_ci#endif 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_cistatic struct scsi_host_template scsi_driver; 36462306a36Sopenharmony_cistatic void storvsc_on_channel_callback(void *context); 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci#define STORVSC_MAX_LUNS_PER_TARGET 255 36762306a36Sopenharmony_ci#define STORVSC_MAX_TARGETS 2 36862306a36Sopenharmony_ci#define STORVSC_MAX_CHANNELS 8 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci#define STORVSC_FC_MAX_LUNS_PER_TARGET 255 37162306a36Sopenharmony_ci#define STORVSC_FC_MAX_TARGETS 128 37262306a36Sopenharmony_ci#define STORVSC_FC_MAX_CHANNELS 8 37362306a36Sopenharmony_ci#define STORVSC_FC_MAX_XFER_SIZE ((u32)(512 * 1024)) 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci#define STORVSC_IDE_MAX_LUNS_PER_TARGET 64 37662306a36Sopenharmony_ci#define STORVSC_IDE_MAX_TARGETS 1 37762306a36Sopenharmony_ci#define STORVSC_IDE_MAX_CHANNELS 1 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci/* 38062306a36Sopenharmony_ci * Upper bound on the size of a storvsc packet. 38162306a36Sopenharmony_ci */ 38262306a36Sopenharmony_ci#define STORVSC_MAX_PKT_SIZE (sizeof(struct vmpacket_descriptor) +\ 38362306a36Sopenharmony_ci sizeof(struct vstor_packet)) 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_cistruct storvsc_cmd_request { 38662306a36Sopenharmony_ci struct scsi_cmnd *cmd; 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci struct hv_device *device; 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci /* Synchronize the request/response if needed */ 39162306a36Sopenharmony_ci struct completion wait_event; 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci struct vmbus_channel_packet_multipage_buffer mpb; 39462306a36Sopenharmony_ci struct vmbus_packet_mpb_array *payload; 39562306a36Sopenharmony_ci u32 payload_sz; 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci struct vstor_packet vstor_packet; 39862306a36Sopenharmony_ci}; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci/* A storvsc device is a device object that contains a vmbus channel */ 40262306a36Sopenharmony_cistruct storvsc_device { 40362306a36Sopenharmony_ci struct hv_device *device; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci bool destroy; 40662306a36Sopenharmony_ci bool drain_notify; 40762306a36Sopenharmony_ci atomic_t num_outstanding_req; 40862306a36Sopenharmony_ci struct Scsi_Host *host; 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci wait_queue_head_t waiting_to_drain; 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci /* 41362306a36Sopenharmony_ci * Each unique Port/Path/Target represents 1 channel ie scsi 41462306a36Sopenharmony_ci * controller. In reality, the pathid, targetid is always 0 41562306a36Sopenharmony_ci * and the port is set by us 41662306a36Sopenharmony_ci */ 41762306a36Sopenharmony_ci unsigned int port_number; 41862306a36Sopenharmony_ci unsigned char path_id; 41962306a36Sopenharmony_ci unsigned char target_id; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci /* 42262306a36Sopenharmony_ci * Max I/O, the device can support. 42362306a36Sopenharmony_ci */ 42462306a36Sopenharmony_ci u32 max_transfer_bytes; 42562306a36Sopenharmony_ci /* 42662306a36Sopenharmony_ci * Number of sub-channels we will open. 42762306a36Sopenharmony_ci */ 42862306a36Sopenharmony_ci u16 num_sc; 42962306a36Sopenharmony_ci struct vmbus_channel **stor_chns; 43062306a36Sopenharmony_ci /* 43162306a36Sopenharmony_ci * Mask of CPUs bound to subchannels. 43262306a36Sopenharmony_ci */ 43362306a36Sopenharmony_ci struct cpumask alloced_cpus; 43462306a36Sopenharmony_ci /* 43562306a36Sopenharmony_ci * Serializes modifications of stor_chns[] from storvsc_do_io() 43662306a36Sopenharmony_ci * and storvsc_change_target_cpu(). 43762306a36Sopenharmony_ci */ 43862306a36Sopenharmony_ci spinlock_t lock; 43962306a36Sopenharmony_ci /* Used for vsc/vsp channel reset process */ 44062306a36Sopenharmony_ci struct storvsc_cmd_request init_request; 44162306a36Sopenharmony_ci struct storvsc_cmd_request reset_request; 44262306a36Sopenharmony_ci /* 44362306a36Sopenharmony_ci * Currently active port and node names for FC devices. 44462306a36Sopenharmony_ci */ 44562306a36Sopenharmony_ci u64 node_name; 44662306a36Sopenharmony_ci u64 port_name; 44762306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_SCSI_FC_ATTRS) 44862306a36Sopenharmony_ci struct fc_rport *rport; 44962306a36Sopenharmony_ci#endif 45062306a36Sopenharmony_ci}; 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_cistruct hv_host_device { 45362306a36Sopenharmony_ci struct hv_device *dev; 45462306a36Sopenharmony_ci unsigned int port; 45562306a36Sopenharmony_ci unsigned char path; 45662306a36Sopenharmony_ci unsigned char target; 45762306a36Sopenharmony_ci struct workqueue_struct *handle_error_wq; 45862306a36Sopenharmony_ci struct work_struct host_scan_work; 45962306a36Sopenharmony_ci struct Scsi_Host *host; 46062306a36Sopenharmony_ci}; 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_cistruct storvsc_scan_work { 46362306a36Sopenharmony_ci struct work_struct work; 46462306a36Sopenharmony_ci struct Scsi_Host *host; 46562306a36Sopenharmony_ci u8 lun; 46662306a36Sopenharmony_ci u8 tgt_id; 46762306a36Sopenharmony_ci}; 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_cistatic void storvsc_device_scan(struct work_struct *work) 47062306a36Sopenharmony_ci{ 47162306a36Sopenharmony_ci struct storvsc_scan_work *wrk; 47262306a36Sopenharmony_ci struct scsi_device *sdev; 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci wrk = container_of(work, struct storvsc_scan_work, work); 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci sdev = scsi_device_lookup(wrk->host, 0, wrk->tgt_id, wrk->lun); 47762306a36Sopenharmony_ci if (!sdev) 47862306a36Sopenharmony_ci goto done; 47962306a36Sopenharmony_ci scsi_rescan_device(sdev); 48062306a36Sopenharmony_ci scsi_device_put(sdev); 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_cidone: 48362306a36Sopenharmony_ci kfree(wrk); 48462306a36Sopenharmony_ci} 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_cistatic void storvsc_host_scan(struct work_struct *work) 48762306a36Sopenharmony_ci{ 48862306a36Sopenharmony_ci struct Scsi_Host *host; 48962306a36Sopenharmony_ci struct scsi_device *sdev; 49062306a36Sopenharmony_ci struct hv_host_device *host_device = 49162306a36Sopenharmony_ci container_of(work, struct hv_host_device, host_scan_work); 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci host = host_device->host; 49462306a36Sopenharmony_ci /* 49562306a36Sopenharmony_ci * Before scanning the host, first check to see if any of the 49662306a36Sopenharmony_ci * currently known devices have been hot removed. We issue a 49762306a36Sopenharmony_ci * "unit ready" command against all currently known devices. 49862306a36Sopenharmony_ci * This I/O will result in an error for devices that have been 49962306a36Sopenharmony_ci * removed. As part of handling the I/O error, we remove the device. 50062306a36Sopenharmony_ci * 50162306a36Sopenharmony_ci * When a LUN is added or removed, the host sends us a signal to 50262306a36Sopenharmony_ci * scan the host. Thus we are forced to discover the LUNs that 50362306a36Sopenharmony_ci * may have been removed this way. 50462306a36Sopenharmony_ci */ 50562306a36Sopenharmony_ci mutex_lock(&host->scan_mutex); 50662306a36Sopenharmony_ci shost_for_each_device(sdev, host) 50762306a36Sopenharmony_ci scsi_test_unit_ready(sdev, 1, 1, NULL); 50862306a36Sopenharmony_ci mutex_unlock(&host->scan_mutex); 50962306a36Sopenharmony_ci /* 51062306a36Sopenharmony_ci * Now scan the host to discover LUNs that may have been added. 51162306a36Sopenharmony_ci */ 51262306a36Sopenharmony_ci scsi_scan_host(host); 51362306a36Sopenharmony_ci} 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_cistatic void storvsc_remove_lun(struct work_struct *work) 51662306a36Sopenharmony_ci{ 51762306a36Sopenharmony_ci struct storvsc_scan_work *wrk; 51862306a36Sopenharmony_ci struct scsi_device *sdev; 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci wrk = container_of(work, struct storvsc_scan_work, work); 52162306a36Sopenharmony_ci if (!scsi_host_get(wrk->host)) 52262306a36Sopenharmony_ci goto done; 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci sdev = scsi_device_lookup(wrk->host, 0, wrk->tgt_id, wrk->lun); 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci if (sdev) { 52762306a36Sopenharmony_ci scsi_remove_device(sdev); 52862306a36Sopenharmony_ci scsi_device_put(sdev); 52962306a36Sopenharmony_ci } 53062306a36Sopenharmony_ci scsi_host_put(wrk->host); 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_cidone: 53362306a36Sopenharmony_ci kfree(wrk); 53462306a36Sopenharmony_ci} 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci/* 53862306a36Sopenharmony_ci * We can get incoming messages from the host that are not in response to 53962306a36Sopenharmony_ci * messages that we have sent out. An example of this would be messages 54062306a36Sopenharmony_ci * received by the guest to notify dynamic addition/removal of LUNs. To 54162306a36Sopenharmony_ci * deal with potential race conditions where the driver may be in the 54262306a36Sopenharmony_ci * midst of being unloaded when we might receive an unsolicited message 54362306a36Sopenharmony_ci * from the host, we have implemented a mechanism to gurantee sequential 54462306a36Sopenharmony_ci * consistency: 54562306a36Sopenharmony_ci * 54662306a36Sopenharmony_ci * 1) Once the device is marked as being destroyed, we will fail all 54762306a36Sopenharmony_ci * outgoing messages. 54862306a36Sopenharmony_ci * 2) We permit incoming messages when the device is being destroyed, 54962306a36Sopenharmony_ci * only to properly account for messages already sent out. 55062306a36Sopenharmony_ci */ 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_cistatic inline struct storvsc_device *get_out_stor_device( 55362306a36Sopenharmony_ci struct hv_device *device) 55462306a36Sopenharmony_ci{ 55562306a36Sopenharmony_ci struct storvsc_device *stor_device; 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci stor_device = hv_get_drvdata(device); 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci if (stor_device && stor_device->destroy) 56062306a36Sopenharmony_ci stor_device = NULL; 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci return stor_device; 56362306a36Sopenharmony_ci} 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_cistatic inline void storvsc_wait_to_drain(struct storvsc_device *dev) 56762306a36Sopenharmony_ci{ 56862306a36Sopenharmony_ci dev->drain_notify = true; 56962306a36Sopenharmony_ci wait_event(dev->waiting_to_drain, 57062306a36Sopenharmony_ci atomic_read(&dev->num_outstanding_req) == 0); 57162306a36Sopenharmony_ci dev->drain_notify = false; 57262306a36Sopenharmony_ci} 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_cistatic inline struct storvsc_device *get_in_stor_device( 57562306a36Sopenharmony_ci struct hv_device *device) 57662306a36Sopenharmony_ci{ 57762306a36Sopenharmony_ci struct storvsc_device *stor_device; 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci stor_device = hv_get_drvdata(device); 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci if (!stor_device) 58262306a36Sopenharmony_ci goto get_in_err; 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci /* 58562306a36Sopenharmony_ci * If the device is being destroyed; allow incoming 58662306a36Sopenharmony_ci * traffic only to cleanup outstanding requests. 58762306a36Sopenharmony_ci */ 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci if (stor_device->destroy && 59062306a36Sopenharmony_ci (atomic_read(&stor_device->num_outstanding_req) == 0)) 59162306a36Sopenharmony_ci stor_device = NULL; 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ciget_in_err: 59462306a36Sopenharmony_ci return stor_device; 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci} 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_cistatic void storvsc_change_target_cpu(struct vmbus_channel *channel, u32 old, 59962306a36Sopenharmony_ci u32 new) 60062306a36Sopenharmony_ci{ 60162306a36Sopenharmony_ci struct storvsc_device *stor_device; 60262306a36Sopenharmony_ci struct vmbus_channel *cur_chn; 60362306a36Sopenharmony_ci bool old_is_alloced = false; 60462306a36Sopenharmony_ci struct hv_device *device; 60562306a36Sopenharmony_ci unsigned long flags; 60662306a36Sopenharmony_ci int cpu; 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci device = channel->primary_channel ? 60962306a36Sopenharmony_ci channel->primary_channel->device_obj 61062306a36Sopenharmony_ci : channel->device_obj; 61162306a36Sopenharmony_ci stor_device = get_out_stor_device(device); 61262306a36Sopenharmony_ci if (!stor_device) 61362306a36Sopenharmony_ci return; 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci /* See storvsc_do_io() -> get_og_chn(). */ 61662306a36Sopenharmony_ci spin_lock_irqsave(&stor_device->lock, flags); 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci /* 61962306a36Sopenharmony_ci * Determines if the storvsc device has other channels assigned to 62062306a36Sopenharmony_ci * the "old" CPU to update the alloced_cpus mask and the stor_chns 62162306a36Sopenharmony_ci * array. 62262306a36Sopenharmony_ci */ 62362306a36Sopenharmony_ci if (device->channel != channel && device->channel->target_cpu == old) { 62462306a36Sopenharmony_ci cur_chn = device->channel; 62562306a36Sopenharmony_ci old_is_alloced = true; 62662306a36Sopenharmony_ci goto old_is_alloced; 62762306a36Sopenharmony_ci } 62862306a36Sopenharmony_ci list_for_each_entry(cur_chn, &device->channel->sc_list, sc_list) { 62962306a36Sopenharmony_ci if (cur_chn == channel) 63062306a36Sopenharmony_ci continue; 63162306a36Sopenharmony_ci if (cur_chn->target_cpu == old) { 63262306a36Sopenharmony_ci old_is_alloced = true; 63362306a36Sopenharmony_ci goto old_is_alloced; 63462306a36Sopenharmony_ci } 63562306a36Sopenharmony_ci } 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ciold_is_alloced: 63862306a36Sopenharmony_ci if (old_is_alloced) 63962306a36Sopenharmony_ci WRITE_ONCE(stor_device->stor_chns[old], cur_chn); 64062306a36Sopenharmony_ci else 64162306a36Sopenharmony_ci cpumask_clear_cpu(old, &stor_device->alloced_cpus); 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci /* "Flush" the stor_chns array. */ 64462306a36Sopenharmony_ci for_each_possible_cpu(cpu) { 64562306a36Sopenharmony_ci if (stor_device->stor_chns[cpu] && !cpumask_test_cpu( 64662306a36Sopenharmony_ci cpu, &stor_device->alloced_cpus)) 64762306a36Sopenharmony_ci WRITE_ONCE(stor_device->stor_chns[cpu], NULL); 64862306a36Sopenharmony_ci } 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci WRITE_ONCE(stor_device->stor_chns[new], channel); 65162306a36Sopenharmony_ci cpumask_set_cpu(new, &stor_device->alloced_cpus); 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci spin_unlock_irqrestore(&stor_device->lock, flags); 65462306a36Sopenharmony_ci} 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_cistatic u64 storvsc_next_request_id(struct vmbus_channel *channel, u64 rqst_addr) 65762306a36Sopenharmony_ci{ 65862306a36Sopenharmony_ci struct storvsc_cmd_request *request = 65962306a36Sopenharmony_ci (struct storvsc_cmd_request *)(unsigned long)rqst_addr; 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci if (rqst_addr == VMBUS_RQST_INIT) 66262306a36Sopenharmony_ci return VMBUS_RQST_INIT; 66362306a36Sopenharmony_ci if (rqst_addr == VMBUS_RQST_RESET) 66462306a36Sopenharmony_ci return VMBUS_RQST_RESET; 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci /* 66762306a36Sopenharmony_ci * Cannot return an ID of 0, which is reserved for an unsolicited 66862306a36Sopenharmony_ci * message from Hyper-V. 66962306a36Sopenharmony_ci */ 67062306a36Sopenharmony_ci return (u64)blk_mq_unique_tag(scsi_cmd_to_rq(request->cmd)) + 1; 67162306a36Sopenharmony_ci} 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_cistatic void handle_sc_creation(struct vmbus_channel *new_sc) 67462306a36Sopenharmony_ci{ 67562306a36Sopenharmony_ci struct hv_device *device = new_sc->primary_channel->device_obj; 67662306a36Sopenharmony_ci struct device *dev = &device->device; 67762306a36Sopenharmony_ci struct storvsc_device *stor_device; 67862306a36Sopenharmony_ci struct vmstorage_channel_properties props; 67962306a36Sopenharmony_ci int ret; 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci stor_device = get_out_stor_device(device); 68262306a36Sopenharmony_ci if (!stor_device) 68362306a36Sopenharmony_ci return; 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci memset(&props, 0, sizeof(struct vmstorage_channel_properties)); 68662306a36Sopenharmony_ci new_sc->max_pkt_size = STORVSC_MAX_PKT_SIZE; 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci new_sc->next_request_id_callback = storvsc_next_request_id; 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci ret = vmbus_open(new_sc, 69162306a36Sopenharmony_ci aligned_ringbuffer_size, 69262306a36Sopenharmony_ci aligned_ringbuffer_size, 69362306a36Sopenharmony_ci (void *)&props, 69462306a36Sopenharmony_ci sizeof(struct vmstorage_channel_properties), 69562306a36Sopenharmony_ci storvsc_on_channel_callback, new_sc); 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci /* In case vmbus_open() fails, we don't use the sub-channel. */ 69862306a36Sopenharmony_ci if (ret != 0) { 69962306a36Sopenharmony_ci dev_err(dev, "Failed to open sub-channel: err=%d\n", ret); 70062306a36Sopenharmony_ci return; 70162306a36Sopenharmony_ci } 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci new_sc->change_target_cpu_callback = storvsc_change_target_cpu; 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci /* Add the sub-channel to the array of available channels. */ 70662306a36Sopenharmony_ci stor_device->stor_chns[new_sc->target_cpu] = new_sc; 70762306a36Sopenharmony_ci cpumask_set_cpu(new_sc->target_cpu, &stor_device->alloced_cpus); 70862306a36Sopenharmony_ci} 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_cistatic void handle_multichannel_storage(struct hv_device *device, int max_chns) 71162306a36Sopenharmony_ci{ 71262306a36Sopenharmony_ci struct device *dev = &device->device; 71362306a36Sopenharmony_ci struct storvsc_device *stor_device; 71462306a36Sopenharmony_ci int num_sc; 71562306a36Sopenharmony_ci struct storvsc_cmd_request *request; 71662306a36Sopenharmony_ci struct vstor_packet *vstor_packet; 71762306a36Sopenharmony_ci int ret, t; 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci /* 72062306a36Sopenharmony_ci * If the number of CPUs is artificially restricted, such as 72162306a36Sopenharmony_ci * with maxcpus=1 on the kernel boot line, Hyper-V could offer 72262306a36Sopenharmony_ci * sub-channels >= the number of CPUs. These sub-channels 72362306a36Sopenharmony_ci * should not be created. The primary channel is already created 72462306a36Sopenharmony_ci * and assigned to one CPU, so check against # CPUs - 1. 72562306a36Sopenharmony_ci */ 72662306a36Sopenharmony_ci num_sc = min((int)(num_online_cpus() - 1), max_chns); 72762306a36Sopenharmony_ci if (!num_sc) 72862306a36Sopenharmony_ci return; 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci stor_device = get_out_stor_device(device); 73162306a36Sopenharmony_ci if (!stor_device) 73262306a36Sopenharmony_ci return; 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci stor_device->num_sc = num_sc; 73562306a36Sopenharmony_ci request = &stor_device->init_request; 73662306a36Sopenharmony_ci vstor_packet = &request->vstor_packet; 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci /* 73962306a36Sopenharmony_ci * Establish a handler for dealing with subchannels. 74062306a36Sopenharmony_ci */ 74162306a36Sopenharmony_ci vmbus_set_sc_create_callback(device->channel, handle_sc_creation); 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci /* 74462306a36Sopenharmony_ci * Request the host to create sub-channels. 74562306a36Sopenharmony_ci */ 74662306a36Sopenharmony_ci memset(request, 0, sizeof(struct storvsc_cmd_request)); 74762306a36Sopenharmony_ci init_completion(&request->wait_event); 74862306a36Sopenharmony_ci vstor_packet->operation = VSTOR_OPERATION_CREATE_SUB_CHANNELS; 74962306a36Sopenharmony_ci vstor_packet->flags = REQUEST_COMPLETION_FLAG; 75062306a36Sopenharmony_ci vstor_packet->sub_channel_count = num_sc; 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci ret = vmbus_sendpacket(device->channel, vstor_packet, 75362306a36Sopenharmony_ci sizeof(struct vstor_packet), 75462306a36Sopenharmony_ci VMBUS_RQST_INIT, 75562306a36Sopenharmony_ci VM_PKT_DATA_INBAND, 75662306a36Sopenharmony_ci VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci if (ret != 0) { 75962306a36Sopenharmony_ci dev_err(dev, "Failed to create sub-channel: err=%d\n", ret); 76062306a36Sopenharmony_ci return; 76162306a36Sopenharmony_ci } 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci t = wait_for_completion_timeout(&request->wait_event, 10*HZ); 76462306a36Sopenharmony_ci if (t == 0) { 76562306a36Sopenharmony_ci dev_err(dev, "Failed to create sub-channel: timed out\n"); 76662306a36Sopenharmony_ci return; 76762306a36Sopenharmony_ci } 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO || 77062306a36Sopenharmony_ci vstor_packet->status != 0) { 77162306a36Sopenharmony_ci dev_err(dev, "Failed to create sub-channel: op=%d, sts=%d\n", 77262306a36Sopenharmony_ci vstor_packet->operation, vstor_packet->status); 77362306a36Sopenharmony_ci return; 77462306a36Sopenharmony_ci } 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci /* 77762306a36Sopenharmony_ci * We need to do nothing here, because vmbus_process_offer() 77862306a36Sopenharmony_ci * invokes channel->sc_creation_callback, which will open and use 77962306a36Sopenharmony_ci * the sub-channel(s). 78062306a36Sopenharmony_ci */ 78162306a36Sopenharmony_ci} 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_cistatic void cache_wwn(struct storvsc_device *stor_device, 78462306a36Sopenharmony_ci struct vstor_packet *vstor_packet) 78562306a36Sopenharmony_ci{ 78662306a36Sopenharmony_ci /* 78762306a36Sopenharmony_ci * Cache the currently active port and node ww names. 78862306a36Sopenharmony_ci */ 78962306a36Sopenharmony_ci if (vstor_packet->wwn_packet.primary_active) { 79062306a36Sopenharmony_ci stor_device->node_name = 79162306a36Sopenharmony_ci wwn_to_u64(vstor_packet->wwn_packet.primary_node_wwn); 79262306a36Sopenharmony_ci stor_device->port_name = 79362306a36Sopenharmony_ci wwn_to_u64(vstor_packet->wwn_packet.primary_port_wwn); 79462306a36Sopenharmony_ci } else { 79562306a36Sopenharmony_ci stor_device->node_name = 79662306a36Sopenharmony_ci wwn_to_u64(vstor_packet->wwn_packet.secondary_node_wwn); 79762306a36Sopenharmony_ci stor_device->port_name = 79862306a36Sopenharmony_ci wwn_to_u64(vstor_packet->wwn_packet.secondary_port_wwn); 79962306a36Sopenharmony_ci } 80062306a36Sopenharmony_ci} 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_cistatic int storvsc_execute_vstor_op(struct hv_device *device, 80462306a36Sopenharmony_ci struct storvsc_cmd_request *request, 80562306a36Sopenharmony_ci bool status_check) 80662306a36Sopenharmony_ci{ 80762306a36Sopenharmony_ci struct storvsc_device *stor_device; 80862306a36Sopenharmony_ci struct vstor_packet *vstor_packet; 80962306a36Sopenharmony_ci int ret, t; 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci stor_device = get_out_stor_device(device); 81262306a36Sopenharmony_ci if (!stor_device) 81362306a36Sopenharmony_ci return -ENODEV; 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci vstor_packet = &request->vstor_packet; 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci init_completion(&request->wait_event); 81862306a36Sopenharmony_ci vstor_packet->flags = REQUEST_COMPLETION_FLAG; 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci ret = vmbus_sendpacket(device->channel, vstor_packet, 82162306a36Sopenharmony_ci sizeof(struct vstor_packet), 82262306a36Sopenharmony_ci VMBUS_RQST_INIT, 82362306a36Sopenharmony_ci VM_PKT_DATA_INBAND, 82462306a36Sopenharmony_ci VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); 82562306a36Sopenharmony_ci if (ret != 0) 82662306a36Sopenharmony_ci return ret; 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci t = wait_for_completion_timeout(&request->wait_event, 5*HZ); 82962306a36Sopenharmony_ci if (t == 0) 83062306a36Sopenharmony_ci return -ETIMEDOUT; 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci if (!status_check) 83362306a36Sopenharmony_ci return ret; 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_ci if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO || 83662306a36Sopenharmony_ci vstor_packet->status != 0) 83762306a36Sopenharmony_ci return -EINVAL; 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ci return ret; 84062306a36Sopenharmony_ci} 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_cistatic int storvsc_channel_init(struct hv_device *device, bool is_fc) 84362306a36Sopenharmony_ci{ 84462306a36Sopenharmony_ci struct storvsc_device *stor_device; 84562306a36Sopenharmony_ci struct storvsc_cmd_request *request; 84662306a36Sopenharmony_ci struct vstor_packet *vstor_packet; 84762306a36Sopenharmony_ci int ret, i; 84862306a36Sopenharmony_ci int max_chns; 84962306a36Sopenharmony_ci bool process_sub_channels = false; 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_ci stor_device = get_out_stor_device(device); 85262306a36Sopenharmony_ci if (!stor_device) 85362306a36Sopenharmony_ci return -ENODEV; 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci request = &stor_device->init_request; 85662306a36Sopenharmony_ci vstor_packet = &request->vstor_packet; 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_ci /* 85962306a36Sopenharmony_ci * Now, initiate the vsc/vsp initialization protocol on the open 86062306a36Sopenharmony_ci * channel 86162306a36Sopenharmony_ci */ 86262306a36Sopenharmony_ci memset(request, 0, sizeof(struct storvsc_cmd_request)); 86362306a36Sopenharmony_ci vstor_packet->operation = VSTOR_OPERATION_BEGIN_INITIALIZATION; 86462306a36Sopenharmony_ci ret = storvsc_execute_vstor_op(device, request, true); 86562306a36Sopenharmony_ci if (ret) 86662306a36Sopenharmony_ci return ret; 86762306a36Sopenharmony_ci /* 86862306a36Sopenharmony_ci * Query host supported protocol version. 86962306a36Sopenharmony_ci */ 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(protocol_version); i++) { 87262306a36Sopenharmony_ci /* reuse the packet for version range supported */ 87362306a36Sopenharmony_ci memset(vstor_packet, 0, sizeof(struct vstor_packet)); 87462306a36Sopenharmony_ci vstor_packet->operation = 87562306a36Sopenharmony_ci VSTOR_OPERATION_QUERY_PROTOCOL_VERSION; 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci vstor_packet->version.major_minor = protocol_version[i]; 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ci /* 88062306a36Sopenharmony_ci * The revision number is only used in Windows; set it to 0. 88162306a36Sopenharmony_ci */ 88262306a36Sopenharmony_ci vstor_packet->version.revision = 0; 88362306a36Sopenharmony_ci ret = storvsc_execute_vstor_op(device, request, false); 88462306a36Sopenharmony_ci if (ret != 0) 88562306a36Sopenharmony_ci return ret; 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO) 88862306a36Sopenharmony_ci return -EINVAL; 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci if (vstor_packet->status == 0) { 89162306a36Sopenharmony_ci vmstor_proto_version = protocol_version[i]; 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci break; 89462306a36Sopenharmony_ci } 89562306a36Sopenharmony_ci } 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci if (vstor_packet->status != 0) { 89862306a36Sopenharmony_ci dev_err(&device->device, "Obsolete Hyper-V version\n"); 89962306a36Sopenharmony_ci return -EINVAL; 90062306a36Sopenharmony_ci } 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci memset(vstor_packet, 0, sizeof(struct vstor_packet)); 90462306a36Sopenharmony_ci vstor_packet->operation = VSTOR_OPERATION_QUERY_PROPERTIES; 90562306a36Sopenharmony_ci ret = storvsc_execute_vstor_op(device, request, true); 90662306a36Sopenharmony_ci if (ret != 0) 90762306a36Sopenharmony_ci return ret; 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci /* 91062306a36Sopenharmony_ci * Check to see if multi-channel support is there. 91162306a36Sopenharmony_ci * Hosts that implement protocol version of 5.1 and above 91262306a36Sopenharmony_ci * support multi-channel. 91362306a36Sopenharmony_ci */ 91462306a36Sopenharmony_ci max_chns = vstor_packet->storage_channel_properties.max_channel_cnt; 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci /* 91762306a36Sopenharmony_ci * Allocate state to manage the sub-channels. 91862306a36Sopenharmony_ci * We allocate an array based on the numbers of possible CPUs 91962306a36Sopenharmony_ci * (Hyper-V does not support cpu online/offline). 92062306a36Sopenharmony_ci * This Array will be sparseley populated with unique 92162306a36Sopenharmony_ci * channels - primary + sub-channels. 92262306a36Sopenharmony_ci * We will however populate all the slots to evenly distribute 92362306a36Sopenharmony_ci * the load. 92462306a36Sopenharmony_ci */ 92562306a36Sopenharmony_ci stor_device->stor_chns = kcalloc(num_possible_cpus(), sizeof(void *), 92662306a36Sopenharmony_ci GFP_KERNEL); 92762306a36Sopenharmony_ci if (stor_device->stor_chns == NULL) 92862306a36Sopenharmony_ci return -ENOMEM; 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci device->channel->change_target_cpu_callback = storvsc_change_target_cpu; 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ci stor_device->stor_chns[device->channel->target_cpu] = device->channel; 93362306a36Sopenharmony_ci cpumask_set_cpu(device->channel->target_cpu, 93462306a36Sopenharmony_ci &stor_device->alloced_cpus); 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci if (vstor_packet->storage_channel_properties.flags & 93762306a36Sopenharmony_ci STORAGE_CHANNEL_SUPPORTS_MULTI_CHANNEL) 93862306a36Sopenharmony_ci process_sub_channels = true; 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_ci stor_device->max_transfer_bytes = 94162306a36Sopenharmony_ci vstor_packet->storage_channel_properties.max_transfer_bytes; 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ci if (!is_fc) 94462306a36Sopenharmony_ci goto done; 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_ci /* 94762306a36Sopenharmony_ci * For FC devices retrieve FC HBA data. 94862306a36Sopenharmony_ci */ 94962306a36Sopenharmony_ci memset(vstor_packet, 0, sizeof(struct vstor_packet)); 95062306a36Sopenharmony_ci vstor_packet->operation = VSTOR_OPERATION_FCHBA_DATA; 95162306a36Sopenharmony_ci ret = storvsc_execute_vstor_op(device, request, true); 95262306a36Sopenharmony_ci if (ret != 0) 95362306a36Sopenharmony_ci return ret; 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_ci /* 95662306a36Sopenharmony_ci * Cache the currently active port and node ww names. 95762306a36Sopenharmony_ci */ 95862306a36Sopenharmony_ci cache_wwn(stor_device, vstor_packet); 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_cidone: 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci memset(vstor_packet, 0, sizeof(struct vstor_packet)); 96362306a36Sopenharmony_ci vstor_packet->operation = VSTOR_OPERATION_END_INITIALIZATION; 96462306a36Sopenharmony_ci ret = storvsc_execute_vstor_op(device, request, true); 96562306a36Sopenharmony_ci if (ret != 0) 96662306a36Sopenharmony_ci return ret; 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci if (process_sub_channels) 96962306a36Sopenharmony_ci handle_multichannel_storage(device, max_chns); 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ci return ret; 97262306a36Sopenharmony_ci} 97362306a36Sopenharmony_ci 97462306a36Sopenharmony_cistatic void storvsc_handle_error(struct vmscsi_request *vm_srb, 97562306a36Sopenharmony_ci struct scsi_cmnd *scmnd, 97662306a36Sopenharmony_ci struct Scsi_Host *host, 97762306a36Sopenharmony_ci u8 asc, u8 ascq) 97862306a36Sopenharmony_ci{ 97962306a36Sopenharmony_ci struct storvsc_scan_work *wrk; 98062306a36Sopenharmony_ci void (*process_err_fn)(struct work_struct *work); 98162306a36Sopenharmony_ci struct hv_host_device *host_dev = shost_priv(host); 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci switch (SRB_STATUS(vm_srb->srb_status)) { 98462306a36Sopenharmony_ci case SRB_STATUS_ERROR: 98562306a36Sopenharmony_ci case SRB_STATUS_ABORTED: 98662306a36Sopenharmony_ci case SRB_STATUS_INVALID_REQUEST: 98762306a36Sopenharmony_ci case SRB_STATUS_INTERNAL_ERROR: 98862306a36Sopenharmony_ci case SRB_STATUS_TIMEOUT: 98962306a36Sopenharmony_ci case SRB_STATUS_SELECTION_TIMEOUT: 99062306a36Sopenharmony_ci case SRB_STATUS_BUS_RESET: 99162306a36Sopenharmony_ci case SRB_STATUS_DATA_OVERRUN: 99262306a36Sopenharmony_ci if (vm_srb->srb_status & SRB_STATUS_AUTOSENSE_VALID) { 99362306a36Sopenharmony_ci /* Check for capacity change */ 99462306a36Sopenharmony_ci if ((asc == 0x2a) && (ascq == 0x9)) { 99562306a36Sopenharmony_ci process_err_fn = storvsc_device_scan; 99662306a36Sopenharmony_ci /* Retry the I/O that triggered this. */ 99762306a36Sopenharmony_ci set_host_byte(scmnd, DID_REQUEUE); 99862306a36Sopenharmony_ci goto do_work; 99962306a36Sopenharmony_ci } 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_ci /* 100262306a36Sopenharmony_ci * Check for "Operating parameters have changed" 100362306a36Sopenharmony_ci * due to Hyper-V changing the VHD/VHDX BlockSize 100462306a36Sopenharmony_ci * when adding/removing a differencing disk. This 100562306a36Sopenharmony_ci * causes discard_granularity to change, so do a 100662306a36Sopenharmony_ci * rescan to pick up the new granularity. We don't 100762306a36Sopenharmony_ci * want scsi_report_sense() to output a message 100862306a36Sopenharmony_ci * that a sysadmin wouldn't know what to do with. 100962306a36Sopenharmony_ci */ 101062306a36Sopenharmony_ci if ((asc == 0x3f) && (ascq != 0x03) && 101162306a36Sopenharmony_ci (ascq != 0x0e)) { 101262306a36Sopenharmony_ci process_err_fn = storvsc_device_scan; 101362306a36Sopenharmony_ci set_host_byte(scmnd, DID_REQUEUE); 101462306a36Sopenharmony_ci goto do_work; 101562306a36Sopenharmony_ci } 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_ci /* 101862306a36Sopenharmony_ci * Otherwise, let upper layer deal with the 101962306a36Sopenharmony_ci * error when sense message is present 102062306a36Sopenharmony_ci */ 102162306a36Sopenharmony_ci return; 102262306a36Sopenharmony_ci } 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_ci /* 102562306a36Sopenharmony_ci * If there is an error; offline the device since all 102662306a36Sopenharmony_ci * error recovery strategies would have already been 102762306a36Sopenharmony_ci * deployed on the host side. However, if the command 102862306a36Sopenharmony_ci * were a pass-through command deal with it appropriately. 102962306a36Sopenharmony_ci */ 103062306a36Sopenharmony_ci switch (scmnd->cmnd[0]) { 103162306a36Sopenharmony_ci case ATA_16: 103262306a36Sopenharmony_ci case ATA_12: 103362306a36Sopenharmony_ci set_host_byte(scmnd, DID_PASSTHROUGH); 103462306a36Sopenharmony_ci break; 103562306a36Sopenharmony_ci /* 103662306a36Sopenharmony_ci * On some Hyper-V hosts TEST_UNIT_READY command can 103762306a36Sopenharmony_ci * return SRB_STATUS_ERROR. Let the upper level code 103862306a36Sopenharmony_ci * deal with it based on the sense information. 103962306a36Sopenharmony_ci */ 104062306a36Sopenharmony_ci case TEST_UNIT_READY: 104162306a36Sopenharmony_ci break; 104262306a36Sopenharmony_ci default: 104362306a36Sopenharmony_ci set_host_byte(scmnd, DID_ERROR); 104462306a36Sopenharmony_ci } 104562306a36Sopenharmony_ci return; 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_ci case SRB_STATUS_INVALID_LUN: 104862306a36Sopenharmony_ci set_host_byte(scmnd, DID_NO_CONNECT); 104962306a36Sopenharmony_ci process_err_fn = storvsc_remove_lun; 105062306a36Sopenharmony_ci goto do_work; 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_ci } 105362306a36Sopenharmony_ci return; 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_cido_work: 105662306a36Sopenharmony_ci /* 105762306a36Sopenharmony_ci * We need to schedule work to process this error; schedule it. 105862306a36Sopenharmony_ci */ 105962306a36Sopenharmony_ci wrk = kmalloc(sizeof(struct storvsc_scan_work), GFP_ATOMIC); 106062306a36Sopenharmony_ci if (!wrk) { 106162306a36Sopenharmony_ci set_host_byte(scmnd, DID_BAD_TARGET); 106262306a36Sopenharmony_ci return; 106362306a36Sopenharmony_ci } 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_ci wrk->host = host; 106662306a36Sopenharmony_ci wrk->lun = vm_srb->lun; 106762306a36Sopenharmony_ci wrk->tgt_id = vm_srb->target_id; 106862306a36Sopenharmony_ci INIT_WORK(&wrk->work, process_err_fn); 106962306a36Sopenharmony_ci queue_work(host_dev->handle_error_wq, &wrk->work); 107062306a36Sopenharmony_ci} 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_cistatic void storvsc_command_completion(struct storvsc_cmd_request *cmd_request, 107462306a36Sopenharmony_ci struct storvsc_device *stor_dev) 107562306a36Sopenharmony_ci{ 107662306a36Sopenharmony_ci struct scsi_cmnd *scmnd = cmd_request->cmd; 107762306a36Sopenharmony_ci struct scsi_sense_hdr sense_hdr; 107862306a36Sopenharmony_ci struct vmscsi_request *vm_srb; 107962306a36Sopenharmony_ci u32 data_transfer_length; 108062306a36Sopenharmony_ci struct Scsi_Host *host; 108162306a36Sopenharmony_ci u32 payload_sz = cmd_request->payload_sz; 108262306a36Sopenharmony_ci void *payload = cmd_request->payload; 108362306a36Sopenharmony_ci bool sense_ok; 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_ci host = stor_dev->host; 108662306a36Sopenharmony_ci 108762306a36Sopenharmony_ci vm_srb = &cmd_request->vstor_packet.vm_srb; 108862306a36Sopenharmony_ci data_transfer_length = vm_srb->data_transfer_length; 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci scmnd->result = vm_srb->scsi_status; 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_ci if (scmnd->result) { 109362306a36Sopenharmony_ci sense_ok = scsi_normalize_sense(scmnd->sense_buffer, 109462306a36Sopenharmony_ci SCSI_SENSE_BUFFERSIZE, &sense_hdr); 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_ci if (sense_ok && do_logging(STORVSC_LOGGING_WARN)) 109762306a36Sopenharmony_ci scsi_print_sense_hdr(scmnd->device, "storvsc", 109862306a36Sopenharmony_ci &sense_hdr); 109962306a36Sopenharmony_ci } 110062306a36Sopenharmony_ci 110162306a36Sopenharmony_ci if (vm_srb->srb_status != SRB_STATUS_SUCCESS) { 110262306a36Sopenharmony_ci storvsc_handle_error(vm_srb, scmnd, host, sense_hdr.asc, 110362306a36Sopenharmony_ci sense_hdr.ascq); 110462306a36Sopenharmony_ci /* 110562306a36Sopenharmony_ci * The Windows driver set data_transfer_length on 110662306a36Sopenharmony_ci * SRB_STATUS_DATA_OVERRUN. On other errors, this value 110762306a36Sopenharmony_ci * is untouched. In these cases we set it to 0. 110862306a36Sopenharmony_ci */ 110962306a36Sopenharmony_ci if (vm_srb->srb_status != SRB_STATUS_DATA_OVERRUN) 111062306a36Sopenharmony_ci data_transfer_length = 0; 111162306a36Sopenharmony_ci } 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_ci /* Validate data_transfer_length (from Hyper-V) */ 111462306a36Sopenharmony_ci if (data_transfer_length > cmd_request->payload->range.len) 111562306a36Sopenharmony_ci data_transfer_length = cmd_request->payload->range.len; 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_ci scsi_set_resid(scmnd, 111862306a36Sopenharmony_ci cmd_request->payload->range.len - data_transfer_length); 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_ci scsi_done(scmnd); 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_ci if (payload_sz > 112362306a36Sopenharmony_ci sizeof(struct vmbus_channel_packet_multipage_buffer)) 112462306a36Sopenharmony_ci kfree(payload); 112562306a36Sopenharmony_ci} 112662306a36Sopenharmony_ci 112762306a36Sopenharmony_cistatic void storvsc_on_io_completion(struct storvsc_device *stor_device, 112862306a36Sopenharmony_ci struct vstor_packet *vstor_packet, 112962306a36Sopenharmony_ci struct storvsc_cmd_request *request) 113062306a36Sopenharmony_ci{ 113162306a36Sopenharmony_ci struct vstor_packet *stor_pkt; 113262306a36Sopenharmony_ci struct hv_device *device = stor_device->device; 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_ci stor_pkt = &request->vstor_packet; 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_ci /* 113762306a36Sopenharmony_ci * The current SCSI handling on the host side does 113862306a36Sopenharmony_ci * not correctly handle: 113962306a36Sopenharmony_ci * INQUIRY command with page code parameter set to 0x80 114062306a36Sopenharmony_ci * MODE_SENSE command with cmd[2] == 0x1c 114162306a36Sopenharmony_ci * 114262306a36Sopenharmony_ci * Setup srb and scsi status so this won't be fatal. 114362306a36Sopenharmony_ci * We do this so we can distinguish truly fatal failues 114462306a36Sopenharmony_ci * (srb status == 0x4) and off-line the device in that case. 114562306a36Sopenharmony_ci */ 114662306a36Sopenharmony_ci 114762306a36Sopenharmony_ci if ((stor_pkt->vm_srb.cdb[0] == INQUIRY) || 114862306a36Sopenharmony_ci (stor_pkt->vm_srb.cdb[0] == MODE_SENSE)) { 114962306a36Sopenharmony_ci vstor_packet->vm_srb.scsi_status = 0; 115062306a36Sopenharmony_ci vstor_packet->vm_srb.srb_status = SRB_STATUS_SUCCESS; 115162306a36Sopenharmony_ci } 115262306a36Sopenharmony_ci 115362306a36Sopenharmony_ci /* Copy over the status...etc */ 115462306a36Sopenharmony_ci stor_pkt->vm_srb.scsi_status = vstor_packet->vm_srb.scsi_status; 115562306a36Sopenharmony_ci stor_pkt->vm_srb.srb_status = vstor_packet->vm_srb.srb_status; 115662306a36Sopenharmony_ci 115762306a36Sopenharmony_ci /* 115862306a36Sopenharmony_ci * Copy over the sense_info_length, but limit to the known max 115962306a36Sopenharmony_ci * size if Hyper-V returns a bad value. 116062306a36Sopenharmony_ci */ 116162306a36Sopenharmony_ci stor_pkt->vm_srb.sense_info_length = min_t(u8, STORVSC_SENSE_BUFFER_SIZE, 116262306a36Sopenharmony_ci vstor_packet->vm_srb.sense_info_length); 116362306a36Sopenharmony_ci 116462306a36Sopenharmony_ci if (vstor_packet->vm_srb.scsi_status != 0 || 116562306a36Sopenharmony_ci vstor_packet->vm_srb.srb_status != SRB_STATUS_SUCCESS) { 116662306a36Sopenharmony_ci 116762306a36Sopenharmony_ci /* 116862306a36Sopenharmony_ci * Log TEST_UNIT_READY errors only as warnings. Hyper-V can 116962306a36Sopenharmony_ci * return errors when detecting devices using TEST_UNIT_READY, 117062306a36Sopenharmony_ci * and logging these as errors produces unhelpful noise. 117162306a36Sopenharmony_ci */ 117262306a36Sopenharmony_ci int loglevel = (stor_pkt->vm_srb.cdb[0] == TEST_UNIT_READY) ? 117362306a36Sopenharmony_ci STORVSC_LOGGING_WARN : STORVSC_LOGGING_ERROR; 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_ci storvsc_log(device, loglevel, 117662306a36Sopenharmony_ci "tag#%d cmd 0x%x status: scsi 0x%x srb 0x%x hv 0x%x\n", 117762306a36Sopenharmony_ci scsi_cmd_to_rq(request->cmd)->tag, 117862306a36Sopenharmony_ci stor_pkt->vm_srb.cdb[0], 117962306a36Sopenharmony_ci vstor_packet->vm_srb.scsi_status, 118062306a36Sopenharmony_ci vstor_packet->vm_srb.srb_status, 118162306a36Sopenharmony_ci vstor_packet->status); 118262306a36Sopenharmony_ci } 118362306a36Sopenharmony_ci 118462306a36Sopenharmony_ci if (vstor_packet->vm_srb.scsi_status == SAM_STAT_CHECK_CONDITION && 118562306a36Sopenharmony_ci (vstor_packet->vm_srb.srb_status & SRB_STATUS_AUTOSENSE_VALID)) 118662306a36Sopenharmony_ci memcpy(request->cmd->sense_buffer, 118762306a36Sopenharmony_ci vstor_packet->vm_srb.sense_data, 118862306a36Sopenharmony_ci stor_pkt->vm_srb.sense_info_length); 118962306a36Sopenharmony_ci 119062306a36Sopenharmony_ci stor_pkt->vm_srb.data_transfer_length = 119162306a36Sopenharmony_ci vstor_packet->vm_srb.data_transfer_length; 119262306a36Sopenharmony_ci 119362306a36Sopenharmony_ci storvsc_command_completion(request, stor_device); 119462306a36Sopenharmony_ci 119562306a36Sopenharmony_ci if (atomic_dec_and_test(&stor_device->num_outstanding_req) && 119662306a36Sopenharmony_ci stor_device->drain_notify) 119762306a36Sopenharmony_ci wake_up(&stor_device->waiting_to_drain); 119862306a36Sopenharmony_ci} 119962306a36Sopenharmony_ci 120062306a36Sopenharmony_cistatic void storvsc_on_receive(struct storvsc_device *stor_device, 120162306a36Sopenharmony_ci struct vstor_packet *vstor_packet, 120262306a36Sopenharmony_ci struct storvsc_cmd_request *request) 120362306a36Sopenharmony_ci{ 120462306a36Sopenharmony_ci struct hv_host_device *host_dev; 120562306a36Sopenharmony_ci switch (vstor_packet->operation) { 120662306a36Sopenharmony_ci case VSTOR_OPERATION_COMPLETE_IO: 120762306a36Sopenharmony_ci storvsc_on_io_completion(stor_device, vstor_packet, request); 120862306a36Sopenharmony_ci break; 120962306a36Sopenharmony_ci 121062306a36Sopenharmony_ci case VSTOR_OPERATION_REMOVE_DEVICE: 121162306a36Sopenharmony_ci case VSTOR_OPERATION_ENUMERATE_BUS: 121262306a36Sopenharmony_ci host_dev = shost_priv(stor_device->host); 121362306a36Sopenharmony_ci queue_work( 121462306a36Sopenharmony_ci host_dev->handle_error_wq, &host_dev->host_scan_work); 121562306a36Sopenharmony_ci break; 121662306a36Sopenharmony_ci 121762306a36Sopenharmony_ci case VSTOR_OPERATION_FCHBA_DATA: 121862306a36Sopenharmony_ci cache_wwn(stor_device, vstor_packet); 121962306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_SCSI_FC_ATTRS) 122062306a36Sopenharmony_ci fc_host_node_name(stor_device->host) = stor_device->node_name; 122162306a36Sopenharmony_ci fc_host_port_name(stor_device->host) = stor_device->port_name; 122262306a36Sopenharmony_ci#endif 122362306a36Sopenharmony_ci break; 122462306a36Sopenharmony_ci default: 122562306a36Sopenharmony_ci break; 122662306a36Sopenharmony_ci } 122762306a36Sopenharmony_ci} 122862306a36Sopenharmony_ci 122962306a36Sopenharmony_cistatic void storvsc_on_channel_callback(void *context) 123062306a36Sopenharmony_ci{ 123162306a36Sopenharmony_ci struct vmbus_channel *channel = (struct vmbus_channel *)context; 123262306a36Sopenharmony_ci const struct vmpacket_descriptor *desc; 123362306a36Sopenharmony_ci struct hv_device *device; 123462306a36Sopenharmony_ci struct storvsc_device *stor_device; 123562306a36Sopenharmony_ci struct Scsi_Host *shost; 123662306a36Sopenharmony_ci unsigned long time_limit = jiffies + msecs_to_jiffies(CALLBACK_TIMEOUT); 123762306a36Sopenharmony_ci 123862306a36Sopenharmony_ci if (channel->primary_channel != NULL) 123962306a36Sopenharmony_ci device = channel->primary_channel->device_obj; 124062306a36Sopenharmony_ci else 124162306a36Sopenharmony_ci device = channel->device_obj; 124262306a36Sopenharmony_ci 124362306a36Sopenharmony_ci stor_device = get_in_stor_device(device); 124462306a36Sopenharmony_ci if (!stor_device) 124562306a36Sopenharmony_ci return; 124662306a36Sopenharmony_ci 124762306a36Sopenharmony_ci shost = stor_device->host; 124862306a36Sopenharmony_ci 124962306a36Sopenharmony_ci foreach_vmbus_pkt(desc, channel) { 125062306a36Sopenharmony_ci struct vstor_packet *packet = hv_pkt_data(desc); 125162306a36Sopenharmony_ci struct storvsc_cmd_request *request = NULL; 125262306a36Sopenharmony_ci u32 pktlen = hv_pkt_datalen(desc); 125362306a36Sopenharmony_ci u64 rqst_id = desc->trans_id; 125462306a36Sopenharmony_ci u32 minlen = rqst_id ? sizeof(struct vstor_packet) : 125562306a36Sopenharmony_ci sizeof(enum vstor_packet_operation); 125662306a36Sopenharmony_ci 125762306a36Sopenharmony_ci if (unlikely(time_after(jiffies, time_limit))) { 125862306a36Sopenharmony_ci hv_pkt_iter_close(channel); 125962306a36Sopenharmony_ci return; 126062306a36Sopenharmony_ci } 126162306a36Sopenharmony_ci 126262306a36Sopenharmony_ci if (pktlen < minlen) { 126362306a36Sopenharmony_ci dev_err(&device->device, 126462306a36Sopenharmony_ci "Invalid pkt: id=%llu, len=%u, minlen=%u\n", 126562306a36Sopenharmony_ci rqst_id, pktlen, minlen); 126662306a36Sopenharmony_ci continue; 126762306a36Sopenharmony_ci } 126862306a36Sopenharmony_ci 126962306a36Sopenharmony_ci if (rqst_id == VMBUS_RQST_INIT) { 127062306a36Sopenharmony_ci request = &stor_device->init_request; 127162306a36Sopenharmony_ci } else if (rqst_id == VMBUS_RQST_RESET) { 127262306a36Sopenharmony_ci request = &stor_device->reset_request; 127362306a36Sopenharmony_ci } else { 127462306a36Sopenharmony_ci /* Hyper-V can send an unsolicited message with ID of 0 */ 127562306a36Sopenharmony_ci if (rqst_id == 0) { 127662306a36Sopenharmony_ci /* 127762306a36Sopenharmony_ci * storvsc_on_receive() looks at the vstor_packet in the message 127862306a36Sopenharmony_ci * from the ring buffer. 127962306a36Sopenharmony_ci * 128062306a36Sopenharmony_ci * - If the operation in the vstor_packet is COMPLETE_IO, then 128162306a36Sopenharmony_ci * we call storvsc_on_io_completion(), and dereference the 128262306a36Sopenharmony_ci * guest memory address. Make sure we don't call 128362306a36Sopenharmony_ci * storvsc_on_io_completion() with a guest memory address 128462306a36Sopenharmony_ci * that is zero if Hyper-V were to construct and send such 128562306a36Sopenharmony_ci * a bogus packet. 128662306a36Sopenharmony_ci * 128762306a36Sopenharmony_ci * - If the operation in the vstor_packet is FCHBA_DATA, then 128862306a36Sopenharmony_ci * we call cache_wwn(), and access the data payload area of 128962306a36Sopenharmony_ci * the packet (wwn_packet); however, there is no guarantee 129062306a36Sopenharmony_ci * that the packet is big enough to contain such area. 129162306a36Sopenharmony_ci * Future-proof the code by rejecting such a bogus packet. 129262306a36Sopenharmony_ci */ 129362306a36Sopenharmony_ci if (packet->operation == VSTOR_OPERATION_COMPLETE_IO || 129462306a36Sopenharmony_ci packet->operation == VSTOR_OPERATION_FCHBA_DATA) { 129562306a36Sopenharmony_ci dev_err(&device->device, "Invalid packet with ID of 0\n"); 129662306a36Sopenharmony_ci continue; 129762306a36Sopenharmony_ci } 129862306a36Sopenharmony_ci } else { 129962306a36Sopenharmony_ci struct scsi_cmnd *scmnd; 130062306a36Sopenharmony_ci 130162306a36Sopenharmony_ci /* Transaction 'rqst_id' corresponds to tag 'rqst_id - 1' */ 130262306a36Sopenharmony_ci scmnd = scsi_host_find_tag(shost, rqst_id - 1); 130362306a36Sopenharmony_ci if (scmnd == NULL) { 130462306a36Sopenharmony_ci dev_err(&device->device, "Incorrect transaction ID\n"); 130562306a36Sopenharmony_ci continue; 130662306a36Sopenharmony_ci } 130762306a36Sopenharmony_ci request = (struct storvsc_cmd_request *)scsi_cmd_priv(scmnd); 130862306a36Sopenharmony_ci scsi_dma_unmap(scmnd); 130962306a36Sopenharmony_ci } 131062306a36Sopenharmony_ci 131162306a36Sopenharmony_ci storvsc_on_receive(stor_device, packet, request); 131262306a36Sopenharmony_ci continue; 131362306a36Sopenharmony_ci } 131462306a36Sopenharmony_ci 131562306a36Sopenharmony_ci memcpy(&request->vstor_packet, packet, 131662306a36Sopenharmony_ci sizeof(struct vstor_packet)); 131762306a36Sopenharmony_ci complete(&request->wait_event); 131862306a36Sopenharmony_ci } 131962306a36Sopenharmony_ci} 132062306a36Sopenharmony_ci 132162306a36Sopenharmony_cistatic int storvsc_connect_to_vsp(struct hv_device *device, u32 ring_size, 132262306a36Sopenharmony_ci bool is_fc) 132362306a36Sopenharmony_ci{ 132462306a36Sopenharmony_ci struct vmstorage_channel_properties props; 132562306a36Sopenharmony_ci int ret; 132662306a36Sopenharmony_ci 132762306a36Sopenharmony_ci memset(&props, 0, sizeof(struct vmstorage_channel_properties)); 132862306a36Sopenharmony_ci 132962306a36Sopenharmony_ci device->channel->max_pkt_size = STORVSC_MAX_PKT_SIZE; 133062306a36Sopenharmony_ci device->channel->next_request_id_callback = storvsc_next_request_id; 133162306a36Sopenharmony_ci 133262306a36Sopenharmony_ci ret = vmbus_open(device->channel, 133362306a36Sopenharmony_ci ring_size, 133462306a36Sopenharmony_ci ring_size, 133562306a36Sopenharmony_ci (void *)&props, 133662306a36Sopenharmony_ci sizeof(struct vmstorage_channel_properties), 133762306a36Sopenharmony_ci storvsc_on_channel_callback, device->channel); 133862306a36Sopenharmony_ci 133962306a36Sopenharmony_ci if (ret != 0) 134062306a36Sopenharmony_ci return ret; 134162306a36Sopenharmony_ci 134262306a36Sopenharmony_ci ret = storvsc_channel_init(device, is_fc); 134362306a36Sopenharmony_ci 134462306a36Sopenharmony_ci return ret; 134562306a36Sopenharmony_ci} 134662306a36Sopenharmony_ci 134762306a36Sopenharmony_cistatic int storvsc_dev_remove(struct hv_device *device) 134862306a36Sopenharmony_ci{ 134962306a36Sopenharmony_ci struct storvsc_device *stor_device; 135062306a36Sopenharmony_ci 135162306a36Sopenharmony_ci stor_device = hv_get_drvdata(device); 135262306a36Sopenharmony_ci 135362306a36Sopenharmony_ci stor_device->destroy = true; 135462306a36Sopenharmony_ci 135562306a36Sopenharmony_ci /* Make sure flag is set before waiting */ 135662306a36Sopenharmony_ci wmb(); 135762306a36Sopenharmony_ci 135862306a36Sopenharmony_ci /* 135962306a36Sopenharmony_ci * At this point, all outbound traffic should be disable. We 136062306a36Sopenharmony_ci * only allow inbound traffic (responses) to proceed so that 136162306a36Sopenharmony_ci * outstanding requests can be completed. 136262306a36Sopenharmony_ci */ 136362306a36Sopenharmony_ci 136462306a36Sopenharmony_ci storvsc_wait_to_drain(stor_device); 136562306a36Sopenharmony_ci 136662306a36Sopenharmony_ci /* 136762306a36Sopenharmony_ci * Since we have already drained, we don't need to busy wait 136862306a36Sopenharmony_ci * as was done in final_release_stor_device() 136962306a36Sopenharmony_ci * Note that we cannot set the ext pointer to NULL until 137062306a36Sopenharmony_ci * we have drained - to drain the outgoing packets, we need to 137162306a36Sopenharmony_ci * allow incoming packets. 137262306a36Sopenharmony_ci */ 137362306a36Sopenharmony_ci hv_set_drvdata(device, NULL); 137462306a36Sopenharmony_ci 137562306a36Sopenharmony_ci /* Close the channel */ 137662306a36Sopenharmony_ci vmbus_close(device->channel); 137762306a36Sopenharmony_ci 137862306a36Sopenharmony_ci kfree(stor_device->stor_chns); 137962306a36Sopenharmony_ci kfree(stor_device); 138062306a36Sopenharmony_ci return 0; 138162306a36Sopenharmony_ci} 138262306a36Sopenharmony_ci 138362306a36Sopenharmony_cistatic struct vmbus_channel *get_og_chn(struct storvsc_device *stor_device, 138462306a36Sopenharmony_ci u16 q_num) 138562306a36Sopenharmony_ci{ 138662306a36Sopenharmony_ci u16 slot = 0; 138762306a36Sopenharmony_ci u16 hash_qnum; 138862306a36Sopenharmony_ci const struct cpumask *node_mask; 138962306a36Sopenharmony_ci int num_channels, tgt_cpu; 139062306a36Sopenharmony_ci 139162306a36Sopenharmony_ci if (stor_device->num_sc == 0) { 139262306a36Sopenharmony_ci stor_device->stor_chns[q_num] = stor_device->device->channel; 139362306a36Sopenharmony_ci return stor_device->device->channel; 139462306a36Sopenharmony_ci } 139562306a36Sopenharmony_ci 139662306a36Sopenharmony_ci /* 139762306a36Sopenharmony_ci * Our channel array is sparsley populated and we 139862306a36Sopenharmony_ci * initiated I/O on a processor/hw-q that does not 139962306a36Sopenharmony_ci * currently have a designated channel. Fix this. 140062306a36Sopenharmony_ci * The strategy is simple: 140162306a36Sopenharmony_ci * I. Ensure NUMA locality 140262306a36Sopenharmony_ci * II. Distribute evenly (best effort) 140362306a36Sopenharmony_ci */ 140462306a36Sopenharmony_ci 140562306a36Sopenharmony_ci node_mask = cpumask_of_node(cpu_to_node(q_num)); 140662306a36Sopenharmony_ci 140762306a36Sopenharmony_ci num_channels = 0; 140862306a36Sopenharmony_ci for_each_cpu(tgt_cpu, &stor_device->alloced_cpus) { 140962306a36Sopenharmony_ci if (cpumask_test_cpu(tgt_cpu, node_mask)) 141062306a36Sopenharmony_ci num_channels++; 141162306a36Sopenharmony_ci } 141262306a36Sopenharmony_ci if (num_channels == 0) { 141362306a36Sopenharmony_ci stor_device->stor_chns[q_num] = stor_device->device->channel; 141462306a36Sopenharmony_ci return stor_device->device->channel; 141562306a36Sopenharmony_ci } 141662306a36Sopenharmony_ci 141762306a36Sopenharmony_ci hash_qnum = q_num; 141862306a36Sopenharmony_ci while (hash_qnum >= num_channels) 141962306a36Sopenharmony_ci hash_qnum -= num_channels; 142062306a36Sopenharmony_ci 142162306a36Sopenharmony_ci for_each_cpu(tgt_cpu, &stor_device->alloced_cpus) { 142262306a36Sopenharmony_ci if (!cpumask_test_cpu(tgt_cpu, node_mask)) 142362306a36Sopenharmony_ci continue; 142462306a36Sopenharmony_ci if (slot == hash_qnum) 142562306a36Sopenharmony_ci break; 142662306a36Sopenharmony_ci slot++; 142762306a36Sopenharmony_ci } 142862306a36Sopenharmony_ci 142962306a36Sopenharmony_ci stor_device->stor_chns[q_num] = stor_device->stor_chns[tgt_cpu]; 143062306a36Sopenharmony_ci 143162306a36Sopenharmony_ci return stor_device->stor_chns[q_num]; 143262306a36Sopenharmony_ci} 143362306a36Sopenharmony_ci 143462306a36Sopenharmony_ci 143562306a36Sopenharmony_cistatic int storvsc_do_io(struct hv_device *device, 143662306a36Sopenharmony_ci struct storvsc_cmd_request *request, u16 q_num) 143762306a36Sopenharmony_ci{ 143862306a36Sopenharmony_ci struct storvsc_device *stor_device; 143962306a36Sopenharmony_ci struct vstor_packet *vstor_packet; 144062306a36Sopenharmony_ci struct vmbus_channel *outgoing_channel, *channel; 144162306a36Sopenharmony_ci unsigned long flags; 144262306a36Sopenharmony_ci int ret = 0; 144362306a36Sopenharmony_ci const struct cpumask *node_mask; 144462306a36Sopenharmony_ci int tgt_cpu; 144562306a36Sopenharmony_ci 144662306a36Sopenharmony_ci vstor_packet = &request->vstor_packet; 144762306a36Sopenharmony_ci stor_device = get_out_stor_device(device); 144862306a36Sopenharmony_ci 144962306a36Sopenharmony_ci if (!stor_device) 145062306a36Sopenharmony_ci return -ENODEV; 145162306a36Sopenharmony_ci 145262306a36Sopenharmony_ci 145362306a36Sopenharmony_ci request->device = device; 145462306a36Sopenharmony_ci /* 145562306a36Sopenharmony_ci * Select an appropriate channel to send the request out. 145662306a36Sopenharmony_ci */ 145762306a36Sopenharmony_ci /* See storvsc_change_target_cpu(). */ 145862306a36Sopenharmony_ci outgoing_channel = READ_ONCE(stor_device->stor_chns[q_num]); 145962306a36Sopenharmony_ci if (outgoing_channel != NULL) { 146062306a36Sopenharmony_ci if (outgoing_channel->target_cpu == q_num) { 146162306a36Sopenharmony_ci /* 146262306a36Sopenharmony_ci * Ideally, we want to pick a different channel if 146362306a36Sopenharmony_ci * available on the same NUMA node. 146462306a36Sopenharmony_ci */ 146562306a36Sopenharmony_ci node_mask = cpumask_of_node(cpu_to_node(q_num)); 146662306a36Sopenharmony_ci for_each_cpu_wrap(tgt_cpu, 146762306a36Sopenharmony_ci &stor_device->alloced_cpus, q_num + 1) { 146862306a36Sopenharmony_ci if (!cpumask_test_cpu(tgt_cpu, node_mask)) 146962306a36Sopenharmony_ci continue; 147062306a36Sopenharmony_ci if (tgt_cpu == q_num) 147162306a36Sopenharmony_ci continue; 147262306a36Sopenharmony_ci channel = READ_ONCE( 147362306a36Sopenharmony_ci stor_device->stor_chns[tgt_cpu]); 147462306a36Sopenharmony_ci if (channel == NULL) 147562306a36Sopenharmony_ci continue; 147662306a36Sopenharmony_ci if (hv_get_avail_to_write_percent( 147762306a36Sopenharmony_ci &channel->outbound) 147862306a36Sopenharmony_ci > ring_avail_percent_lowater) { 147962306a36Sopenharmony_ci outgoing_channel = channel; 148062306a36Sopenharmony_ci goto found_channel; 148162306a36Sopenharmony_ci } 148262306a36Sopenharmony_ci } 148362306a36Sopenharmony_ci 148462306a36Sopenharmony_ci /* 148562306a36Sopenharmony_ci * All the other channels on the same NUMA node are 148662306a36Sopenharmony_ci * busy. Try to use the channel on the current CPU 148762306a36Sopenharmony_ci */ 148862306a36Sopenharmony_ci if (hv_get_avail_to_write_percent( 148962306a36Sopenharmony_ci &outgoing_channel->outbound) 149062306a36Sopenharmony_ci > ring_avail_percent_lowater) 149162306a36Sopenharmony_ci goto found_channel; 149262306a36Sopenharmony_ci 149362306a36Sopenharmony_ci /* 149462306a36Sopenharmony_ci * If we reach here, all the channels on the current 149562306a36Sopenharmony_ci * NUMA node are busy. Try to find a channel in 149662306a36Sopenharmony_ci * other NUMA nodes 149762306a36Sopenharmony_ci */ 149862306a36Sopenharmony_ci for_each_cpu(tgt_cpu, &stor_device->alloced_cpus) { 149962306a36Sopenharmony_ci if (cpumask_test_cpu(tgt_cpu, node_mask)) 150062306a36Sopenharmony_ci continue; 150162306a36Sopenharmony_ci channel = READ_ONCE( 150262306a36Sopenharmony_ci stor_device->stor_chns[tgt_cpu]); 150362306a36Sopenharmony_ci if (channel == NULL) 150462306a36Sopenharmony_ci continue; 150562306a36Sopenharmony_ci if (hv_get_avail_to_write_percent( 150662306a36Sopenharmony_ci &channel->outbound) 150762306a36Sopenharmony_ci > ring_avail_percent_lowater) { 150862306a36Sopenharmony_ci outgoing_channel = channel; 150962306a36Sopenharmony_ci goto found_channel; 151062306a36Sopenharmony_ci } 151162306a36Sopenharmony_ci } 151262306a36Sopenharmony_ci } 151362306a36Sopenharmony_ci } else { 151462306a36Sopenharmony_ci spin_lock_irqsave(&stor_device->lock, flags); 151562306a36Sopenharmony_ci outgoing_channel = stor_device->stor_chns[q_num]; 151662306a36Sopenharmony_ci if (outgoing_channel != NULL) { 151762306a36Sopenharmony_ci spin_unlock_irqrestore(&stor_device->lock, flags); 151862306a36Sopenharmony_ci goto found_channel; 151962306a36Sopenharmony_ci } 152062306a36Sopenharmony_ci outgoing_channel = get_og_chn(stor_device, q_num); 152162306a36Sopenharmony_ci spin_unlock_irqrestore(&stor_device->lock, flags); 152262306a36Sopenharmony_ci } 152362306a36Sopenharmony_ci 152462306a36Sopenharmony_cifound_channel: 152562306a36Sopenharmony_ci vstor_packet->flags |= REQUEST_COMPLETION_FLAG; 152662306a36Sopenharmony_ci 152762306a36Sopenharmony_ci vstor_packet->vm_srb.length = sizeof(struct vmscsi_request); 152862306a36Sopenharmony_ci 152962306a36Sopenharmony_ci 153062306a36Sopenharmony_ci vstor_packet->vm_srb.sense_info_length = STORVSC_SENSE_BUFFER_SIZE; 153162306a36Sopenharmony_ci 153262306a36Sopenharmony_ci 153362306a36Sopenharmony_ci vstor_packet->vm_srb.data_transfer_length = 153462306a36Sopenharmony_ci request->payload->range.len; 153562306a36Sopenharmony_ci 153662306a36Sopenharmony_ci vstor_packet->operation = VSTOR_OPERATION_EXECUTE_SRB; 153762306a36Sopenharmony_ci 153862306a36Sopenharmony_ci if (request->payload->range.len) { 153962306a36Sopenharmony_ci 154062306a36Sopenharmony_ci ret = vmbus_sendpacket_mpb_desc(outgoing_channel, 154162306a36Sopenharmony_ci request->payload, request->payload_sz, 154262306a36Sopenharmony_ci vstor_packet, 154362306a36Sopenharmony_ci sizeof(struct vstor_packet), 154462306a36Sopenharmony_ci (unsigned long)request); 154562306a36Sopenharmony_ci } else { 154662306a36Sopenharmony_ci ret = vmbus_sendpacket(outgoing_channel, vstor_packet, 154762306a36Sopenharmony_ci sizeof(struct vstor_packet), 154862306a36Sopenharmony_ci (unsigned long)request, 154962306a36Sopenharmony_ci VM_PKT_DATA_INBAND, 155062306a36Sopenharmony_ci VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); 155162306a36Sopenharmony_ci } 155262306a36Sopenharmony_ci 155362306a36Sopenharmony_ci if (ret != 0) 155462306a36Sopenharmony_ci return ret; 155562306a36Sopenharmony_ci 155662306a36Sopenharmony_ci atomic_inc(&stor_device->num_outstanding_req); 155762306a36Sopenharmony_ci 155862306a36Sopenharmony_ci return ret; 155962306a36Sopenharmony_ci} 156062306a36Sopenharmony_ci 156162306a36Sopenharmony_cistatic int storvsc_device_alloc(struct scsi_device *sdevice) 156262306a36Sopenharmony_ci{ 156362306a36Sopenharmony_ci /* 156462306a36Sopenharmony_ci * Set blist flag to permit the reading of the VPD pages even when 156562306a36Sopenharmony_ci * the target may claim SPC-2 compliance. MSFT targets currently 156662306a36Sopenharmony_ci * claim SPC-2 compliance while they implement post SPC-2 features. 156762306a36Sopenharmony_ci * With this flag we can correctly handle WRITE_SAME_16 issues. 156862306a36Sopenharmony_ci * 156962306a36Sopenharmony_ci * Hypervisor reports SCSI_UNKNOWN type for DVD ROM device but 157062306a36Sopenharmony_ci * still supports REPORT LUN. 157162306a36Sopenharmony_ci */ 157262306a36Sopenharmony_ci sdevice->sdev_bflags = BLIST_REPORTLUN2 | BLIST_TRY_VPD_PAGES; 157362306a36Sopenharmony_ci 157462306a36Sopenharmony_ci return 0; 157562306a36Sopenharmony_ci} 157662306a36Sopenharmony_ci 157762306a36Sopenharmony_cistatic int storvsc_device_configure(struct scsi_device *sdevice) 157862306a36Sopenharmony_ci{ 157962306a36Sopenharmony_ci blk_queue_rq_timeout(sdevice->request_queue, (storvsc_timeout * HZ)); 158062306a36Sopenharmony_ci 158162306a36Sopenharmony_ci /* storvsc devices don't support MAINTENANCE_IN SCSI cmd */ 158262306a36Sopenharmony_ci sdevice->no_report_opcodes = 1; 158362306a36Sopenharmony_ci sdevice->no_write_same = 1; 158462306a36Sopenharmony_ci 158562306a36Sopenharmony_ci /* 158662306a36Sopenharmony_ci * If the host is WIN8 or WIN8 R2, claim conformance to SPC-3 158762306a36Sopenharmony_ci * if the device is a MSFT virtual device. If the host is 158862306a36Sopenharmony_ci * WIN10 or newer, allow write_same. 158962306a36Sopenharmony_ci */ 159062306a36Sopenharmony_ci if (!strncmp(sdevice->vendor, "Msft", 4)) { 159162306a36Sopenharmony_ci switch (vmstor_proto_version) { 159262306a36Sopenharmony_ci case VMSTOR_PROTO_VERSION_WIN8: 159362306a36Sopenharmony_ci case VMSTOR_PROTO_VERSION_WIN8_1: 159462306a36Sopenharmony_ci sdevice->scsi_level = SCSI_SPC_3; 159562306a36Sopenharmony_ci break; 159662306a36Sopenharmony_ci } 159762306a36Sopenharmony_ci 159862306a36Sopenharmony_ci if (vmstor_proto_version >= VMSTOR_PROTO_VERSION_WIN10) 159962306a36Sopenharmony_ci sdevice->no_write_same = 0; 160062306a36Sopenharmony_ci } 160162306a36Sopenharmony_ci 160262306a36Sopenharmony_ci return 0; 160362306a36Sopenharmony_ci} 160462306a36Sopenharmony_ci 160562306a36Sopenharmony_cistatic int storvsc_get_chs(struct scsi_device *sdev, struct block_device * bdev, 160662306a36Sopenharmony_ci sector_t capacity, int *info) 160762306a36Sopenharmony_ci{ 160862306a36Sopenharmony_ci sector_t nsect = capacity; 160962306a36Sopenharmony_ci sector_t cylinders = nsect; 161062306a36Sopenharmony_ci int heads, sectors_pt; 161162306a36Sopenharmony_ci 161262306a36Sopenharmony_ci /* 161362306a36Sopenharmony_ci * We are making up these values; let us keep it simple. 161462306a36Sopenharmony_ci */ 161562306a36Sopenharmony_ci heads = 0xff; 161662306a36Sopenharmony_ci sectors_pt = 0x3f; /* Sectors per track */ 161762306a36Sopenharmony_ci sector_div(cylinders, heads * sectors_pt); 161862306a36Sopenharmony_ci if ((sector_t)(cylinders + 1) * heads * sectors_pt < nsect) 161962306a36Sopenharmony_ci cylinders = 0xffff; 162062306a36Sopenharmony_ci 162162306a36Sopenharmony_ci info[0] = heads; 162262306a36Sopenharmony_ci info[1] = sectors_pt; 162362306a36Sopenharmony_ci info[2] = (int)cylinders; 162462306a36Sopenharmony_ci 162562306a36Sopenharmony_ci return 0; 162662306a36Sopenharmony_ci} 162762306a36Sopenharmony_ci 162862306a36Sopenharmony_cistatic int storvsc_host_reset_handler(struct scsi_cmnd *scmnd) 162962306a36Sopenharmony_ci{ 163062306a36Sopenharmony_ci struct hv_host_device *host_dev = shost_priv(scmnd->device->host); 163162306a36Sopenharmony_ci struct hv_device *device = host_dev->dev; 163262306a36Sopenharmony_ci 163362306a36Sopenharmony_ci struct storvsc_device *stor_device; 163462306a36Sopenharmony_ci struct storvsc_cmd_request *request; 163562306a36Sopenharmony_ci struct vstor_packet *vstor_packet; 163662306a36Sopenharmony_ci int ret, t; 163762306a36Sopenharmony_ci 163862306a36Sopenharmony_ci stor_device = get_out_stor_device(device); 163962306a36Sopenharmony_ci if (!stor_device) 164062306a36Sopenharmony_ci return FAILED; 164162306a36Sopenharmony_ci 164262306a36Sopenharmony_ci request = &stor_device->reset_request; 164362306a36Sopenharmony_ci vstor_packet = &request->vstor_packet; 164462306a36Sopenharmony_ci memset(vstor_packet, 0, sizeof(struct vstor_packet)); 164562306a36Sopenharmony_ci 164662306a36Sopenharmony_ci init_completion(&request->wait_event); 164762306a36Sopenharmony_ci 164862306a36Sopenharmony_ci vstor_packet->operation = VSTOR_OPERATION_RESET_BUS; 164962306a36Sopenharmony_ci vstor_packet->flags = REQUEST_COMPLETION_FLAG; 165062306a36Sopenharmony_ci vstor_packet->vm_srb.path_id = stor_device->path_id; 165162306a36Sopenharmony_ci 165262306a36Sopenharmony_ci ret = vmbus_sendpacket(device->channel, vstor_packet, 165362306a36Sopenharmony_ci sizeof(struct vstor_packet), 165462306a36Sopenharmony_ci VMBUS_RQST_RESET, 165562306a36Sopenharmony_ci VM_PKT_DATA_INBAND, 165662306a36Sopenharmony_ci VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); 165762306a36Sopenharmony_ci if (ret != 0) 165862306a36Sopenharmony_ci return FAILED; 165962306a36Sopenharmony_ci 166062306a36Sopenharmony_ci t = wait_for_completion_timeout(&request->wait_event, 5*HZ); 166162306a36Sopenharmony_ci if (t == 0) 166262306a36Sopenharmony_ci return TIMEOUT_ERROR; 166362306a36Sopenharmony_ci 166462306a36Sopenharmony_ci 166562306a36Sopenharmony_ci /* 166662306a36Sopenharmony_ci * At this point, all outstanding requests in the adapter 166762306a36Sopenharmony_ci * should have been flushed out and return to us 166862306a36Sopenharmony_ci * There is a potential race here where the host may be in 166962306a36Sopenharmony_ci * the process of responding when we return from here. 167062306a36Sopenharmony_ci * Just wait for all in-transit packets to be accounted for 167162306a36Sopenharmony_ci * before we return from here. 167262306a36Sopenharmony_ci */ 167362306a36Sopenharmony_ci storvsc_wait_to_drain(stor_device); 167462306a36Sopenharmony_ci 167562306a36Sopenharmony_ci return SUCCESS; 167662306a36Sopenharmony_ci} 167762306a36Sopenharmony_ci 167862306a36Sopenharmony_ci/* 167962306a36Sopenharmony_ci * The host guarantees to respond to each command, although I/O latencies might 168062306a36Sopenharmony_ci * be unbounded on Azure. Reset the timer unconditionally to give the host a 168162306a36Sopenharmony_ci * chance to perform EH. 168262306a36Sopenharmony_ci */ 168362306a36Sopenharmony_cistatic enum scsi_timeout_action storvsc_eh_timed_out(struct scsi_cmnd *scmnd) 168462306a36Sopenharmony_ci{ 168562306a36Sopenharmony_ci return SCSI_EH_RESET_TIMER; 168662306a36Sopenharmony_ci} 168762306a36Sopenharmony_ci 168862306a36Sopenharmony_cistatic bool storvsc_scsi_cmd_ok(struct scsi_cmnd *scmnd) 168962306a36Sopenharmony_ci{ 169062306a36Sopenharmony_ci bool allowed = true; 169162306a36Sopenharmony_ci u8 scsi_op = scmnd->cmnd[0]; 169262306a36Sopenharmony_ci 169362306a36Sopenharmony_ci switch (scsi_op) { 169462306a36Sopenharmony_ci /* the host does not handle WRITE_SAME, log accident usage */ 169562306a36Sopenharmony_ci case WRITE_SAME: 169662306a36Sopenharmony_ci /* 169762306a36Sopenharmony_ci * smartd sends this command and the host does not handle 169862306a36Sopenharmony_ci * this. So, don't send it. 169962306a36Sopenharmony_ci */ 170062306a36Sopenharmony_ci case SET_WINDOW: 170162306a36Sopenharmony_ci set_host_byte(scmnd, DID_ERROR); 170262306a36Sopenharmony_ci allowed = false; 170362306a36Sopenharmony_ci break; 170462306a36Sopenharmony_ci default: 170562306a36Sopenharmony_ci break; 170662306a36Sopenharmony_ci } 170762306a36Sopenharmony_ci return allowed; 170862306a36Sopenharmony_ci} 170962306a36Sopenharmony_ci 171062306a36Sopenharmony_cistatic int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd) 171162306a36Sopenharmony_ci{ 171262306a36Sopenharmony_ci int ret; 171362306a36Sopenharmony_ci struct hv_host_device *host_dev = shost_priv(host); 171462306a36Sopenharmony_ci struct hv_device *dev = host_dev->dev; 171562306a36Sopenharmony_ci struct storvsc_cmd_request *cmd_request = scsi_cmd_priv(scmnd); 171662306a36Sopenharmony_ci struct scatterlist *sgl; 171762306a36Sopenharmony_ci struct vmscsi_request *vm_srb; 171862306a36Sopenharmony_ci struct vmbus_packet_mpb_array *payload; 171962306a36Sopenharmony_ci u32 payload_sz; 172062306a36Sopenharmony_ci u32 length; 172162306a36Sopenharmony_ci 172262306a36Sopenharmony_ci if (vmstor_proto_version <= VMSTOR_PROTO_VERSION_WIN8) { 172362306a36Sopenharmony_ci /* 172462306a36Sopenharmony_ci * On legacy hosts filter unimplemented commands. 172562306a36Sopenharmony_ci * Future hosts are expected to correctly handle 172662306a36Sopenharmony_ci * unsupported commands. Furthermore, it is 172762306a36Sopenharmony_ci * possible that some of the currently 172862306a36Sopenharmony_ci * unsupported commands maybe supported in 172962306a36Sopenharmony_ci * future versions of the host. 173062306a36Sopenharmony_ci */ 173162306a36Sopenharmony_ci if (!storvsc_scsi_cmd_ok(scmnd)) { 173262306a36Sopenharmony_ci scsi_done(scmnd); 173362306a36Sopenharmony_ci return 0; 173462306a36Sopenharmony_ci } 173562306a36Sopenharmony_ci } 173662306a36Sopenharmony_ci 173762306a36Sopenharmony_ci /* Setup the cmd request */ 173862306a36Sopenharmony_ci cmd_request->cmd = scmnd; 173962306a36Sopenharmony_ci 174062306a36Sopenharmony_ci memset(&cmd_request->vstor_packet, 0, sizeof(struct vstor_packet)); 174162306a36Sopenharmony_ci vm_srb = &cmd_request->vstor_packet.vm_srb; 174262306a36Sopenharmony_ci vm_srb->time_out_value = 60; 174362306a36Sopenharmony_ci 174462306a36Sopenharmony_ci vm_srb->srb_flags |= 174562306a36Sopenharmony_ci SRB_FLAGS_DISABLE_SYNCH_TRANSFER; 174662306a36Sopenharmony_ci 174762306a36Sopenharmony_ci if (scmnd->device->tagged_supported) { 174862306a36Sopenharmony_ci vm_srb->srb_flags |= 174962306a36Sopenharmony_ci (SRB_FLAGS_QUEUE_ACTION_ENABLE | SRB_FLAGS_NO_QUEUE_FREEZE); 175062306a36Sopenharmony_ci vm_srb->queue_tag = SP_UNTAGGED; 175162306a36Sopenharmony_ci vm_srb->queue_action = SRB_SIMPLE_TAG_REQUEST; 175262306a36Sopenharmony_ci } 175362306a36Sopenharmony_ci 175462306a36Sopenharmony_ci /* Build the SRB */ 175562306a36Sopenharmony_ci switch (scmnd->sc_data_direction) { 175662306a36Sopenharmony_ci case DMA_TO_DEVICE: 175762306a36Sopenharmony_ci vm_srb->data_in = WRITE_TYPE; 175862306a36Sopenharmony_ci vm_srb->srb_flags |= SRB_FLAGS_DATA_OUT; 175962306a36Sopenharmony_ci break; 176062306a36Sopenharmony_ci case DMA_FROM_DEVICE: 176162306a36Sopenharmony_ci vm_srb->data_in = READ_TYPE; 176262306a36Sopenharmony_ci vm_srb->srb_flags |= SRB_FLAGS_DATA_IN; 176362306a36Sopenharmony_ci break; 176462306a36Sopenharmony_ci case DMA_NONE: 176562306a36Sopenharmony_ci vm_srb->data_in = UNKNOWN_TYPE; 176662306a36Sopenharmony_ci vm_srb->srb_flags |= SRB_FLAGS_NO_DATA_TRANSFER; 176762306a36Sopenharmony_ci break; 176862306a36Sopenharmony_ci default: 176962306a36Sopenharmony_ci /* 177062306a36Sopenharmony_ci * This is DMA_BIDIRECTIONAL or something else we are never 177162306a36Sopenharmony_ci * supposed to see here. 177262306a36Sopenharmony_ci */ 177362306a36Sopenharmony_ci WARN(1, "Unexpected data direction: %d\n", 177462306a36Sopenharmony_ci scmnd->sc_data_direction); 177562306a36Sopenharmony_ci return -EINVAL; 177662306a36Sopenharmony_ci } 177762306a36Sopenharmony_ci 177862306a36Sopenharmony_ci 177962306a36Sopenharmony_ci vm_srb->port_number = host_dev->port; 178062306a36Sopenharmony_ci vm_srb->path_id = scmnd->device->channel; 178162306a36Sopenharmony_ci vm_srb->target_id = scmnd->device->id; 178262306a36Sopenharmony_ci vm_srb->lun = scmnd->device->lun; 178362306a36Sopenharmony_ci 178462306a36Sopenharmony_ci vm_srb->cdb_length = scmnd->cmd_len; 178562306a36Sopenharmony_ci 178662306a36Sopenharmony_ci memcpy(vm_srb->cdb, scmnd->cmnd, vm_srb->cdb_length); 178762306a36Sopenharmony_ci 178862306a36Sopenharmony_ci sgl = (struct scatterlist *)scsi_sglist(scmnd); 178962306a36Sopenharmony_ci 179062306a36Sopenharmony_ci length = scsi_bufflen(scmnd); 179162306a36Sopenharmony_ci payload = (struct vmbus_packet_mpb_array *)&cmd_request->mpb; 179262306a36Sopenharmony_ci payload_sz = 0; 179362306a36Sopenharmony_ci 179462306a36Sopenharmony_ci if (scsi_sg_count(scmnd)) { 179562306a36Sopenharmony_ci unsigned long offset_in_hvpg = offset_in_hvpage(sgl->offset); 179662306a36Sopenharmony_ci unsigned int hvpg_count = HVPFN_UP(offset_in_hvpg + length); 179762306a36Sopenharmony_ci struct scatterlist *sg; 179862306a36Sopenharmony_ci unsigned long hvpfn, hvpfns_to_add; 179962306a36Sopenharmony_ci int j, i = 0, sg_count; 180062306a36Sopenharmony_ci 180162306a36Sopenharmony_ci payload_sz = (hvpg_count * sizeof(u64) + 180262306a36Sopenharmony_ci sizeof(struct vmbus_packet_mpb_array)); 180362306a36Sopenharmony_ci 180462306a36Sopenharmony_ci if (hvpg_count > MAX_PAGE_BUFFER_COUNT) { 180562306a36Sopenharmony_ci payload = kzalloc(payload_sz, GFP_ATOMIC); 180662306a36Sopenharmony_ci if (!payload) 180762306a36Sopenharmony_ci return SCSI_MLQUEUE_DEVICE_BUSY; 180862306a36Sopenharmony_ci } 180962306a36Sopenharmony_ci 181062306a36Sopenharmony_ci payload->range.len = length; 181162306a36Sopenharmony_ci payload->range.offset = offset_in_hvpg; 181262306a36Sopenharmony_ci 181362306a36Sopenharmony_ci sg_count = scsi_dma_map(scmnd); 181462306a36Sopenharmony_ci if (sg_count < 0) { 181562306a36Sopenharmony_ci ret = SCSI_MLQUEUE_DEVICE_BUSY; 181662306a36Sopenharmony_ci goto err_free_payload; 181762306a36Sopenharmony_ci } 181862306a36Sopenharmony_ci 181962306a36Sopenharmony_ci for_each_sg(sgl, sg, sg_count, j) { 182062306a36Sopenharmony_ci /* 182162306a36Sopenharmony_ci * Init values for the current sgl entry. hvpfns_to_add 182262306a36Sopenharmony_ci * is in units of Hyper-V size pages. Handling the 182362306a36Sopenharmony_ci * PAGE_SIZE != HV_HYP_PAGE_SIZE case also handles 182462306a36Sopenharmony_ci * values of sgl->offset that are larger than PAGE_SIZE. 182562306a36Sopenharmony_ci * Such offsets are handled even on other than the first 182662306a36Sopenharmony_ci * sgl entry, provided they are a multiple of PAGE_SIZE. 182762306a36Sopenharmony_ci */ 182862306a36Sopenharmony_ci hvpfn = HVPFN_DOWN(sg_dma_address(sg)); 182962306a36Sopenharmony_ci hvpfns_to_add = HVPFN_UP(sg_dma_address(sg) + 183062306a36Sopenharmony_ci sg_dma_len(sg)) - hvpfn; 183162306a36Sopenharmony_ci 183262306a36Sopenharmony_ci /* 183362306a36Sopenharmony_ci * Fill the next portion of the PFN array with 183462306a36Sopenharmony_ci * sequential Hyper-V PFNs for the continguous physical 183562306a36Sopenharmony_ci * memory described by the sgl entry. The end of the 183662306a36Sopenharmony_ci * last sgl should be reached at the same time that 183762306a36Sopenharmony_ci * the PFN array is filled. 183862306a36Sopenharmony_ci */ 183962306a36Sopenharmony_ci while (hvpfns_to_add--) 184062306a36Sopenharmony_ci payload->range.pfn_array[i++] = hvpfn++; 184162306a36Sopenharmony_ci } 184262306a36Sopenharmony_ci } 184362306a36Sopenharmony_ci 184462306a36Sopenharmony_ci cmd_request->payload = payload; 184562306a36Sopenharmony_ci cmd_request->payload_sz = payload_sz; 184662306a36Sopenharmony_ci 184762306a36Sopenharmony_ci /* Invokes the vsc to start an IO */ 184862306a36Sopenharmony_ci ret = storvsc_do_io(dev, cmd_request, get_cpu()); 184962306a36Sopenharmony_ci put_cpu(); 185062306a36Sopenharmony_ci 185162306a36Sopenharmony_ci if (ret) 185262306a36Sopenharmony_ci scsi_dma_unmap(scmnd); 185362306a36Sopenharmony_ci 185462306a36Sopenharmony_ci if (ret == -EAGAIN) { 185562306a36Sopenharmony_ci /* no more space */ 185662306a36Sopenharmony_ci ret = SCSI_MLQUEUE_DEVICE_BUSY; 185762306a36Sopenharmony_ci goto err_free_payload; 185862306a36Sopenharmony_ci } 185962306a36Sopenharmony_ci 186062306a36Sopenharmony_ci return 0; 186162306a36Sopenharmony_ci 186262306a36Sopenharmony_cierr_free_payload: 186362306a36Sopenharmony_ci if (payload_sz > sizeof(cmd_request->mpb)) 186462306a36Sopenharmony_ci kfree(payload); 186562306a36Sopenharmony_ci 186662306a36Sopenharmony_ci return ret; 186762306a36Sopenharmony_ci} 186862306a36Sopenharmony_ci 186962306a36Sopenharmony_cistatic struct scsi_host_template scsi_driver = { 187062306a36Sopenharmony_ci .module = THIS_MODULE, 187162306a36Sopenharmony_ci .name = "storvsc_host_t", 187262306a36Sopenharmony_ci .cmd_size = sizeof(struct storvsc_cmd_request), 187362306a36Sopenharmony_ci .bios_param = storvsc_get_chs, 187462306a36Sopenharmony_ci .queuecommand = storvsc_queuecommand, 187562306a36Sopenharmony_ci .eh_host_reset_handler = storvsc_host_reset_handler, 187662306a36Sopenharmony_ci .proc_name = "storvsc_host", 187762306a36Sopenharmony_ci .eh_timed_out = storvsc_eh_timed_out, 187862306a36Sopenharmony_ci .slave_alloc = storvsc_device_alloc, 187962306a36Sopenharmony_ci .slave_configure = storvsc_device_configure, 188062306a36Sopenharmony_ci .cmd_per_lun = 2048, 188162306a36Sopenharmony_ci .this_id = -1, 188262306a36Sopenharmony_ci /* Ensure there are no gaps in presented sgls */ 188362306a36Sopenharmony_ci .virt_boundary_mask = HV_HYP_PAGE_SIZE - 1, 188462306a36Sopenharmony_ci .no_write_same = 1, 188562306a36Sopenharmony_ci .track_queue_depth = 1, 188662306a36Sopenharmony_ci .change_queue_depth = storvsc_change_queue_depth, 188762306a36Sopenharmony_ci}; 188862306a36Sopenharmony_ci 188962306a36Sopenharmony_cienum { 189062306a36Sopenharmony_ci SCSI_GUID, 189162306a36Sopenharmony_ci IDE_GUID, 189262306a36Sopenharmony_ci SFC_GUID, 189362306a36Sopenharmony_ci}; 189462306a36Sopenharmony_ci 189562306a36Sopenharmony_cistatic const struct hv_vmbus_device_id id_table[] = { 189662306a36Sopenharmony_ci /* SCSI guid */ 189762306a36Sopenharmony_ci { HV_SCSI_GUID, 189862306a36Sopenharmony_ci .driver_data = SCSI_GUID 189962306a36Sopenharmony_ci }, 190062306a36Sopenharmony_ci /* IDE guid */ 190162306a36Sopenharmony_ci { HV_IDE_GUID, 190262306a36Sopenharmony_ci .driver_data = IDE_GUID 190362306a36Sopenharmony_ci }, 190462306a36Sopenharmony_ci /* Fibre Channel GUID */ 190562306a36Sopenharmony_ci { 190662306a36Sopenharmony_ci HV_SYNTHFC_GUID, 190762306a36Sopenharmony_ci .driver_data = SFC_GUID 190862306a36Sopenharmony_ci }, 190962306a36Sopenharmony_ci { }, 191062306a36Sopenharmony_ci}; 191162306a36Sopenharmony_ci 191262306a36Sopenharmony_ciMODULE_DEVICE_TABLE(vmbus, id_table); 191362306a36Sopenharmony_ci 191462306a36Sopenharmony_cistatic const struct { guid_t guid; } fc_guid = { HV_SYNTHFC_GUID }; 191562306a36Sopenharmony_ci 191662306a36Sopenharmony_cistatic bool hv_dev_is_fc(struct hv_device *hv_dev) 191762306a36Sopenharmony_ci{ 191862306a36Sopenharmony_ci return guid_equal(&fc_guid.guid, &hv_dev->dev_type); 191962306a36Sopenharmony_ci} 192062306a36Sopenharmony_ci 192162306a36Sopenharmony_cistatic int storvsc_probe(struct hv_device *device, 192262306a36Sopenharmony_ci const struct hv_vmbus_device_id *dev_id) 192362306a36Sopenharmony_ci{ 192462306a36Sopenharmony_ci int ret; 192562306a36Sopenharmony_ci int num_cpus = num_online_cpus(); 192662306a36Sopenharmony_ci int num_present_cpus = num_present_cpus(); 192762306a36Sopenharmony_ci struct Scsi_Host *host; 192862306a36Sopenharmony_ci struct hv_host_device *host_dev; 192962306a36Sopenharmony_ci bool dev_is_ide = ((dev_id->driver_data == IDE_GUID) ? true : false); 193062306a36Sopenharmony_ci bool is_fc = ((dev_id->driver_data == SFC_GUID) ? true : false); 193162306a36Sopenharmony_ci int target = 0; 193262306a36Sopenharmony_ci struct storvsc_device *stor_device; 193362306a36Sopenharmony_ci int max_sub_channels = 0; 193462306a36Sopenharmony_ci u32 max_xfer_bytes; 193562306a36Sopenharmony_ci 193662306a36Sopenharmony_ci /* 193762306a36Sopenharmony_ci * We support sub-channels for storage on SCSI and FC controllers. 193862306a36Sopenharmony_ci * The number of sub-channels offerred is based on the number of 193962306a36Sopenharmony_ci * VCPUs in the guest. 194062306a36Sopenharmony_ci */ 194162306a36Sopenharmony_ci if (!dev_is_ide) 194262306a36Sopenharmony_ci max_sub_channels = 194362306a36Sopenharmony_ci (num_cpus - 1) / storvsc_vcpus_per_sub_channel; 194462306a36Sopenharmony_ci 194562306a36Sopenharmony_ci scsi_driver.can_queue = max_outstanding_req_per_channel * 194662306a36Sopenharmony_ci (max_sub_channels + 1) * 194762306a36Sopenharmony_ci (100 - ring_avail_percent_lowater) / 100; 194862306a36Sopenharmony_ci 194962306a36Sopenharmony_ci host = scsi_host_alloc(&scsi_driver, 195062306a36Sopenharmony_ci sizeof(struct hv_host_device)); 195162306a36Sopenharmony_ci if (!host) 195262306a36Sopenharmony_ci return -ENOMEM; 195362306a36Sopenharmony_ci 195462306a36Sopenharmony_ci host_dev = shost_priv(host); 195562306a36Sopenharmony_ci memset(host_dev, 0, sizeof(struct hv_host_device)); 195662306a36Sopenharmony_ci 195762306a36Sopenharmony_ci host_dev->port = host->host_no; 195862306a36Sopenharmony_ci host_dev->dev = device; 195962306a36Sopenharmony_ci host_dev->host = host; 196062306a36Sopenharmony_ci 196162306a36Sopenharmony_ci 196262306a36Sopenharmony_ci stor_device = kzalloc(sizeof(struct storvsc_device), GFP_KERNEL); 196362306a36Sopenharmony_ci if (!stor_device) { 196462306a36Sopenharmony_ci ret = -ENOMEM; 196562306a36Sopenharmony_ci goto err_out0; 196662306a36Sopenharmony_ci } 196762306a36Sopenharmony_ci 196862306a36Sopenharmony_ci stor_device->destroy = false; 196962306a36Sopenharmony_ci init_waitqueue_head(&stor_device->waiting_to_drain); 197062306a36Sopenharmony_ci stor_device->device = device; 197162306a36Sopenharmony_ci stor_device->host = host; 197262306a36Sopenharmony_ci spin_lock_init(&stor_device->lock); 197362306a36Sopenharmony_ci hv_set_drvdata(device, stor_device); 197462306a36Sopenharmony_ci dma_set_min_align_mask(&device->device, HV_HYP_PAGE_SIZE - 1); 197562306a36Sopenharmony_ci 197662306a36Sopenharmony_ci stor_device->port_number = host->host_no; 197762306a36Sopenharmony_ci ret = storvsc_connect_to_vsp(device, aligned_ringbuffer_size, is_fc); 197862306a36Sopenharmony_ci if (ret) 197962306a36Sopenharmony_ci goto err_out1; 198062306a36Sopenharmony_ci 198162306a36Sopenharmony_ci host_dev->path = stor_device->path_id; 198262306a36Sopenharmony_ci host_dev->target = stor_device->target_id; 198362306a36Sopenharmony_ci 198462306a36Sopenharmony_ci switch (dev_id->driver_data) { 198562306a36Sopenharmony_ci case SFC_GUID: 198662306a36Sopenharmony_ci host->max_lun = STORVSC_FC_MAX_LUNS_PER_TARGET; 198762306a36Sopenharmony_ci host->max_id = STORVSC_FC_MAX_TARGETS; 198862306a36Sopenharmony_ci host->max_channel = STORVSC_FC_MAX_CHANNELS - 1; 198962306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_SCSI_FC_ATTRS) 199062306a36Sopenharmony_ci host->transportt = fc_transport_template; 199162306a36Sopenharmony_ci#endif 199262306a36Sopenharmony_ci break; 199362306a36Sopenharmony_ci 199462306a36Sopenharmony_ci case SCSI_GUID: 199562306a36Sopenharmony_ci host->max_lun = STORVSC_MAX_LUNS_PER_TARGET; 199662306a36Sopenharmony_ci host->max_id = STORVSC_MAX_TARGETS; 199762306a36Sopenharmony_ci host->max_channel = STORVSC_MAX_CHANNELS - 1; 199862306a36Sopenharmony_ci break; 199962306a36Sopenharmony_ci 200062306a36Sopenharmony_ci default: 200162306a36Sopenharmony_ci host->max_lun = STORVSC_IDE_MAX_LUNS_PER_TARGET; 200262306a36Sopenharmony_ci host->max_id = STORVSC_IDE_MAX_TARGETS; 200362306a36Sopenharmony_ci host->max_channel = STORVSC_IDE_MAX_CHANNELS - 1; 200462306a36Sopenharmony_ci break; 200562306a36Sopenharmony_ci } 200662306a36Sopenharmony_ci /* max cmd length */ 200762306a36Sopenharmony_ci host->max_cmd_len = STORVSC_MAX_CMD_LEN; 200862306a36Sopenharmony_ci /* 200962306a36Sopenharmony_ci * Any reasonable Hyper-V configuration should provide 201062306a36Sopenharmony_ci * max_transfer_bytes value aligning to HV_HYP_PAGE_SIZE, 201162306a36Sopenharmony_ci * protecting it from any weird value. 201262306a36Sopenharmony_ci */ 201362306a36Sopenharmony_ci max_xfer_bytes = round_down(stor_device->max_transfer_bytes, HV_HYP_PAGE_SIZE); 201462306a36Sopenharmony_ci if (is_fc) 201562306a36Sopenharmony_ci max_xfer_bytes = min(max_xfer_bytes, STORVSC_FC_MAX_XFER_SIZE); 201662306a36Sopenharmony_ci 201762306a36Sopenharmony_ci /* max_hw_sectors_kb */ 201862306a36Sopenharmony_ci host->max_sectors = max_xfer_bytes >> 9; 201962306a36Sopenharmony_ci /* 202062306a36Sopenharmony_ci * There are 2 requirements for Hyper-V storvsc sgl segments, 202162306a36Sopenharmony_ci * based on which the below calculation for max segments is 202262306a36Sopenharmony_ci * done: 202362306a36Sopenharmony_ci * 202462306a36Sopenharmony_ci * 1. Except for the first and last sgl segment, all sgl segments 202562306a36Sopenharmony_ci * should be align to HV_HYP_PAGE_SIZE, that also means the 202662306a36Sopenharmony_ci * maximum number of segments in a sgl can be calculated by 202762306a36Sopenharmony_ci * dividing the total max transfer length by HV_HYP_PAGE_SIZE. 202862306a36Sopenharmony_ci * 202962306a36Sopenharmony_ci * 2. Except for the first and last, each entry in the SGL must 203062306a36Sopenharmony_ci * have an offset that is a multiple of HV_HYP_PAGE_SIZE. 203162306a36Sopenharmony_ci */ 203262306a36Sopenharmony_ci host->sg_tablesize = (max_xfer_bytes >> HV_HYP_PAGE_SHIFT) + 1; 203362306a36Sopenharmony_ci /* 203462306a36Sopenharmony_ci * For non-IDE disks, the host supports multiple channels. 203562306a36Sopenharmony_ci * Set the number of HW queues we are supporting. 203662306a36Sopenharmony_ci */ 203762306a36Sopenharmony_ci if (!dev_is_ide) { 203862306a36Sopenharmony_ci if (storvsc_max_hw_queues > num_present_cpus) { 203962306a36Sopenharmony_ci storvsc_max_hw_queues = 0; 204062306a36Sopenharmony_ci storvsc_log(device, STORVSC_LOGGING_WARN, 204162306a36Sopenharmony_ci "Resetting invalid storvsc_max_hw_queues value to default.\n"); 204262306a36Sopenharmony_ci } 204362306a36Sopenharmony_ci if (storvsc_max_hw_queues) 204462306a36Sopenharmony_ci host->nr_hw_queues = storvsc_max_hw_queues; 204562306a36Sopenharmony_ci else 204662306a36Sopenharmony_ci host->nr_hw_queues = num_present_cpus; 204762306a36Sopenharmony_ci } 204862306a36Sopenharmony_ci 204962306a36Sopenharmony_ci /* 205062306a36Sopenharmony_ci * Set the error handler work queue. 205162306a36Sopenharmony_ci */ 205262306a36Sopenharmony_ci host_dev->handle_error_wq = 205362306a36Sopenharmony_ci alloc_ordered_workqueue("storvsc_error_wq_%d", 205462306a36Sopenharmony_ci 0, 205562306a36Sopenharmony_ci host->host_no); 205662306a36Sopenharmony_ci if (!host_dev->handle_error_wq) { 205762306a36Sopenharmony_ci ret = -ENOMEM; 205862306a36Sopenharmony_ci goto err_out2; 205962306a36Sopenharmony_ci } 206062306a36Sopenharmony_ci INIT_WORK(&host_dev->host_scan_work, storvsc_host_scan); 206162306a36Sopenharmony_ci /* Register the HBA and start the scsi bus scan */ 206262306a36Sopenharmony_ci ret = scsi_add_host(host, &device->device); 206362306a36Sopenharmony_ci if (ret != 0) 206462306a36Sopenharmony_ci goto err_out3; 206562306a36Sopenharmony_ci 206662306a36Sopenharmony_ci if (!dev_is_ide) { 206762306a36Sopenharmony_ci scsi_scan_host(host); 206862306a36Sopenharmony_ci } else { 206962306a36Sopenharmony_ci target = (device->dev_instance.b[5] << 8 | 207062306a36Sopenharmony_ci device->dev_instance.b[4]); 207162306a36Sopenharmony_ci ret = scsi_add_device(host, 0, target, 0); 207262306a36Sopenharmony_ci if (ret) 207362306a36Sopenharmony_ci goto err_out4; 207462306a36Sopenharmony_ci } 207562306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_SCSI_FC_ATTRS) 207662306a36Sopenharmony_ci if (host->transportt == fc_transport_template) { 207762306a36Sopenharmony_ci struct fc_rport_identifiers ids = { 207862306a36Sopenharmony_ci .roles = FC_PORT_ROLE_FCP_DUMMY_INITIATOR, 207962306a36Sopenharmony_ci }; 208062306a36Sopenharmony_ci 208162306a36Sopenharmony_ci fc_host_node_name(host) = stor_device->node_name; 208262306a36Sopenharmony_ci fc_host_port_name(host) = stor_device->port_name; 208362306a36Sopenharmony_ci stor_device->rport = fc_remote_port_add(host, 0, &ids); 208462306a36Sopenharmony_ci if (!stor_device->rport) { 208562306a36Sopenharmony_ci ret = -ENOMEM; 208662306a36Sopenharmony_ci goto err_out4; 208762306a36Sopenharmony_ci } 208862306a36Sopenharmony_ci } 208962306a36Sopenharmony_ci#endif 209062306a36Sopenharmony_ci return 0; 209162306a36Sopenharmony_ci 209262306a36Sopenharmony_cierr_out4: 209362306a36Sopenharmony_ci scsi_remove_host(host); 209462306a36Sopenharmony_ci 209562306a36Sopenharmony_cierr_out3: 209662306a36Sopenharmony_ci destroy_workqueue(host_dev->handle_error_wq); 209762306a36Sopenharmony_ci 209862306a36Sopenharmony_cierr_out2: 209962306a36Sopenharmony_ci /* 210062306a36Sopenharmony_ci * Once we have connected with the host, we would need to 210162306a36Sopenharmony_ci * invoke storvsc_dev_remove() to rollback this state and 210262306a36Sopenharmony_ci * this call also frees up the stor_device; hence the jump around 210362306a36Sopenharmony_ci * err_out1 label. 210462306a36Sopenharmony_ci */ 210562306a36Sopenharmony_ci storvsc_dev_remove(device); 210662306a36Sopenharmony_ci goto err_out0; 210762306a36Sopenharmony_ci 210862306a36Sopenharmony_cierr_out1: 210962306a36Sopenharmony_ci kfree(stor_device->stor_chns); 211062306a36Sopenharmony_ci kfree(stor_device); 211162306a36Sopenharmony_ci 211262306a36Sopenharmony_cierr_out0: 211362306a36Sopenharmony_ci scsi_host_put(host); 211462306a36Sopenharmony_ci return ret; 211562306a36Sopenharmony_ci} 211662306a36Sopenharmony_ci 211762306a36Sopenharmony_ci/* Change a scsi target's queue depth */ 211862306a36Sopenharmony_cistatic int storvsc_change_queue_depth(struct scsi_device *sdev, int queue_depth) 211962306a36Sopenharmony_ci{ 212062306a36Sopenharmony_ci if (queue_depth > scsi_driver.can_queue) 212162306a36Sopenharmony_ci queue_depth = scsi_driver.can_queue; 212262306a36Sopenharmony_ci 212362306a36Sopenharmony_ci return scsi_change_queue_depth(sdev, queue_depth); 212462306a36Sopenharmony_ci} 212562306a36Sopenharmony_ci 212662306a36Sopenharmony_cistatic void storvsc_remove(struct hv_device *dev) 212762306a36Sopenharmony_ci{ 212862306a36Sopenharmony_ci struct storvsc_device *stor_device = hv_get_drvdata(dev); 212962306a36Sopenharmony_ci struct Scsi_Host *host = stor_device->host; 213062306a36Sopenharmony_ci struct hv_host_device *host_dev = shost_priv(host); 213162306a36Sopenharmony_ci 213262306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_SCSI_FC_ATTRS) 213362306a36Sopenharmony_ci if (host->transportt == fc_transport_template) { 213462306a36Sopenharmony_ci fc_remote_port_delete(stor_device->rport); 213562306a36Sopenharmony_ci fc_remove_host(host); 213662306a36Sopenharmony_ci } 213762306a36Sopenharmony_ci#endif 213862306a36Sopenharmony_ci destroy_workqueue(host_dev->handle_error_wq); 213962306a36Sopenharmony_ci scsi_remove_host(host); 214062306a36Sopenharmony_ci storvsc_dev_remove(dev); 214162306a36Sopenharmony_ci scsi_host_put(host); 214262306a36Sopenharmony_ci} 214362306a36Sopenharmony_ci 214462306a36Sopenharmony_cistatic int storvsc_suspend(struct hv_device *hv_dev) 214562306a36Sopenharmony_ci{ 214662306a36Sopenharmony_ci struct storvsc_device *stor_device = hv_get_drvdata(hv_dev); 214762306a36Sopenharmony_ci struct Scsi_Host *host = stor_device->host; 214862306a36Sopenharmony_ci struct hv_host_device *host_dev = shost_priv(host); 214962306a36Sopenharmony_ci 215062306a36Sopenharmony_ci storvsc_wait_to_drain(stor_device); 215162306a36Sopenharmony_ci 215262306a36Sopenharmony_ci drain_workqueue(host_dev->handle_error_wq); 215362306a36Sopenharmony_ci 215462306a36Sopenharmony_ci vmbus_close(hv_dev->channel); 215562306a36Sopenharmony_ci 215662306a36Sopenharmony_ci kfree(stor_device->stor_chns); 215762306a36Sopenharmony_ci stor_device->stor_chns = NULL; 215862306a36Sopenharmony_ci 215962306a36Sopenharmony_ci cpumask_clear(&stor_device->alloced_cpus); 216062306a36Sopenharmony_ci 216162306a36Sopenharmony_ci return 0; 216262306a36Sopenharmony_ci} 216362306a36Sopenharmony_ci 216462306a36Sopenharmony_cistatic int storvsc_resume(struct hv_device *hv_dev) 216562306a36Sopenharmony_ci{ 216662306a36Sopenharmony_ci int ret; 216762306a36Sopenharmony_ci 216862306a36Sopenharmony_ci ret = storvsc_connect_to_vsp(hv_dev, aligned_ringbuffer_size, 216962306a36Sopenharmony_ci hv_dev_is_fc(hv_dev)); 217062306a36Sopenharmony_ci return ret; 217162306a36Sopenharmony_ci} 217262306a36Sopenharmony_ci 217362306a36Sopenharmony_cistatic struct hv_driver storvsc_drv = { 217462306a36Sopenharmony_ci .name = KBUILD_MODNAME, 217562306a36Sopenharmony_ci .id_table = id_table, 217662306a36Sopenharmony_ci .probe = storvsc_probe, 217762306a36Sopenharmony_ci .remove = storvsc_remove, 217862306a36Sopenharmony_ci .suspend = storvsc_suspend, 217962306a36Sopenharmony_ci .resume = storvsc_resume, 218062306a36Sopenharmony_ci .driver = { 218162306a36Sopenharmony_ci .probe_type = PROBE_PREFER_ASYNCHRONOUS, 218262306a36Sopenharmony_ci }, 218362306a36Sopenharmony_ci}; 218462306a36Sopenharmony_ci 218562306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_SCSI_FC_ATTRS) 218662306a36Sopenharmony_cistatic struct fc_function_template fc_transport_functions = { 218762306a36Sopenharmony_ci .show_host_node_name = 1, 218862306a36Sopenharmony_ci .show_host_port_name = 1, 218962306a36Sopenharmony_ci}; 219062306a36Sopenharmony_ci#endif 219162306a36Sopenharmony_ci 219262306a36Sopenharmony_cistatic int __init storvsc_drv_init(void) 219362306a36Sopenharmony_ci{ 219462306a36Sopenharmony_ci int ret; 219562306a36Sopenharmony_ci 219662306a36Sopenharmony_ci /* 219762306a36Sopenharmony_ci * Divide the ring buffer data size (which is 1 page less 219862306a36Sopenharmony_ci * than the ring buffer size since that page is reserved for 219962306a36Sopenharmony_ci * the ring buffer indices) by the max request size (which is 220062306a36Sopenharmony_ci * vmbus_channel_packet_multipage_buffer + struct vstor_packet + u64) 220162306a36Sopenharmony_ci */ 220262306a36Sopenharmony_ci aligned_ringbuffer_size = VMBUS_RING_SIZE(storvsc_ringbuffer_size); 220362306a36Sopenharmony_ci max_outstanding_req_per_channel = 220462306a36Sopenharmony_ci ((aligned_ringbuffer_size - PAGE_SIZE) / 220562306a36Sopenharmony_ci ALIGN(MAX_MULTIPAGE_BUFFER_PACKET + 220662306a36Sopenharmony_ci sizeof(struct vstor_packet) + sizeof(u64), 220762306a36Sopenharmony_ci sizeof(u64))); 220862306a36Sopenharmony_ci 220962306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_SCSI_FC_ATTRS) 221062306a36Sopenharmony_ci fc_transport_template = fc_attach_transport(&fc_transport_functions); 221162306a36Sopenharmony_ci if (!fc_transport_template) 221262306a36Sopenharmony_ci return -ENODEV; 221362306a36Sopenharmony_ci#endif 221462306a36Sopenharmony_ci 221562306a36Sopenharmony_ci ret = vmbus_driver_register(&storvsc_drv); 221662306a36Sopenharmony_ci 221762306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_SCSI_FC_ATTRS) 221862306a36Sopenharmony_ci if (ret) 221962306a36Sopenharmony_ci fc_release_transport(fc_transport_template); 222062306a36Sopenharmony_ci#endif 222162306a36Sopenharmony_ci 222262306a36Sopenharmony_ci return ret; 222362306a36Sopenharmony_ci} 222462306a36Sopenharmony_ci 222562306a36Sopenharmony_cistatic void __exit storvsc_drv_exit(void) 222662306a36Sopenharmony_ci{ 222762306a36Sopenharmony_ci vmbus_driver_unregister(&storvsc_drv); 222862306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_SCSI_FC_ATTRS) 222962306a36Sopenharmony_ci fc_release_transport(fc_transport_template); 223062306a36Sopenharmony_ci#endif 223162306a36Sopenharmony_ci} 223262306a36Sopenharmony_ci 223362306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 223462306a36Sopenharmony_ciMODULE_DESCRIPTION("Microsoft Hyper-V virtual storage driver"); 223562306a36Sopenharmony_cimodule_init(storvsc_drv_init); 223662306a36Sopenharmony_cimodule_exit(storvsc_drv_exit); 2237