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