K. Y. Srinivasan | cdee150 | 2011-05-12 19:34:34 -0700 | [diff] [blame] | 1 | /* |
| 2 | * |
| 3 | * Copyright (c) 2011, Microsoft Corporation. |
| 4 | * |
| 5 | * This program is free software; you can redistribute it and/or modify it |
| 6 | * under the terms and conditions of the GNU General Public License, |
| 7 | * version 2, as published by the Free Software Foundation. |
| 8 | * |
| 9 | * This program is distributed in the hope it will be useful, but WITHOUT |
| 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
| 12 | * more details. |
| 13 | * |
| 14 | * You should have received a copy of the GNU General Public License along with |
| 15 | * this program; if not, write to the Free Software Foundation, Inc., 59 Temple |
| 16 | * Place - Suite 330, Boston, MA 02111-1307 USA. |
| 17 | * |
| 18 | * Authors: |
| 19 | * Haiyang Zhang <haiyangz@microsoft.com> |
| 20 | * Hank Janssen <hjanssen@microsoft.com> |
| 21 | * K. Y. Srinivasan <kys@microsoft.com> |
| 22 | * |
| 23 | */ |
| 24 | |
| 25 | #ifndef _HYPERV_STORAGE_H |
| 26 | #define _HYPERV_STORAGE_H |
| 27 | |
| 28 | |
K. Y. Srinivasan | e6572b0 | 2011-05-12 19:34:35 -0700 | [diff] [blame] | 29 | /* vstorage.w revision number. This is used in the case of a version match, */ |
| 30 | /* to alert the user that structure sizes may be mismatched even though the */ |
| 31 | /* protocol versions match. */ |
| 32 | |
| 33 | |
| 34 | #define REVISION_STRING(REVISION_) #REVISION_ |
| 35 | #define FILL_VMSTOR_REVISION(RESULT_LVALUE_) \ |
| 36 | do { \ |
| 37 | char *revision_string \ |
| 38 | = REVISION_STRING($Rev : 6 $) + 6; \ |
| 39 | RESULT_LVALUE_ = 0; \ |
| 40 | while (*revision_string >= '0' \ |
| 41 | && *revision_string <= '9') { \ |
| 42 | RESULT_LVALUE_ *= 10; \ |
| 43 | RESULT_LVALUE_ += *revision_string - '0'; \ |
| 44 | revision_string++; \ |
| 45 | } \ |
| 46 | } while (0) |
| 47 | |
| 48 | /* Major/minor macros. Minor version is in LSB, meaning that earlier flat */ |
| 49 | /* version numbers will be interpreted as "0.x" (i.e., 1 becomes 0.1). */ |
| 50 | #define VMSTOR_PROTOCOL_MAJOR(VERSION_) (((VERSION_) >> 8) & 0xff) |
| 51 | #define VMSTOR_PROTOCOL_MINOR(VERSION_) (((VERSION_)) & 0xff) |
| 52 | #define VMSTOR_PROTOCOL_VERSION(MAJOR_, MINOR_) ((((MAJOR_) & 0xff) << 8) | \ |
| 53 | (((MINOR_) & 0xff))) |
| 54 | #define VMSTOR_INVALID_PROTOCOL_VERSION (-1) |
| 55 | |
| 56 | /* Version history: */ |
| 57 | /* V1 Beta 0.1 */ |
| 58 | /* V1 RC < 2008/1/31 1.0 */ |
| 59 | /* V1 RC > 2008/1/31 2.0 */ |
| 60 | #define VMSTOR_PROTOCOL_VERSION_CURRENT VMSTOR_PROTOCOL_VERSION(2, 0) |
| 61 | |
| 62 | |
| 63 | |
| 64 | |
| 65 | /* This will get replaced with the max transfer length that is possible on */ |
| 66 | /* the host adapter. */ |
| 67 | /* The max transfer length will be published when we offer a vmbus channel. */ |
| 68 | #define MAX_TRANSFER_LENGTH 0x40000 |
| 69 | #define DEFAULT_PACKET_SIZE (sizeof(struct vmdata_gpa_direct) + \ |
| 70 | sizeof(struct vstor_packet) + \ |
| 71 | sizesizeof(u64) * (MAX_TRANSFER_LENGTH / PAGE_SIZE))) |
| 72 | |
| 73 | |
| 74 | /* Packet structure describing virtual storage requests. */ |
| 75 | enum vstor_packet_operation { |
| 76 | VSTOR_OPERATION_COMPLETE_IO = 1, |
| 77 | VSTOR_OPERATION_REMOVE_DEVICE = 2, |
| 78 | VSTOR_OPERATION_EXECUTE_SRB = 3, |
| 79 | VSTOR_OPERATION_RESET_LUN = 4, |
| 80 | VSTOR_OPERATION_RESET_ADAPTER = 5, |
| 81 | VSTOR_OPERATION_RESET_BUS = 6, |
| 82 | VSTOR_OPERATION_BEGIN_INITIALIZATION = 7, |
| 83 | VSTOR_OPERATION_END_INITIALIZATION = 8, |
| 84 | VSTOR_OPERATION_QUERY_PROTOCOL_VERSION = 9, |
| 85 | VSTOR_OPERATION_QUERY_PROPERTIES = 10, |
| 86 | VSTOR_OPERATION_MAXIMUM = 10 |
| 87 | }; |
| 88 | |
| 89 | /* |
| 90 | * Platform neutral description of a scsi request - |
| 91 | * this remains the same across the write regardless of 32/64 bit |
| 92 | * note: it's patterned off the SCSI_PASS_THROUGH structure |
| 93 | */ |
| 94 | #define CDB16GENERIC_LENGTH 0x10 |
| 95 | |
| 96 | #ifndef SENSE_BUFFER_SIZE |
| 97 | #define SENSE_BUFFER_SIZE 0x12 |
| 98 | #endif |
| 99 | |
| 100 | #define MAX_DATA_BUF_LEN_WITH_PADDING 0x14 |
| 101 | |
| 102 | struct vmscsi_request { |
| 103 | unsigned short length; |
| 104 | unsigned char srb_status; |
| 105 | unsigned char scsi_status; |
| 106 | |
| 107 | unsigned char port_number; |
| 108 | unsigned char path_id; |
| 109 | unsigned char target_id; |
| 110 | unsigned char lun; |
| 111 | |
| 112 | unsigned char cdb_length; |
| 113 | unsigned char sense_info_length; |
| 114 | unsigned char data_in; |
| 115 | unsigned char reserved; |
| 116 | |
| 117 | unsigned int data_transfer_length; |
| 118 | |
| 119 | union { |
| 120 | unsigned char cdb[CDB16GENERIC_LENGTH]; |
| 121 | unsigned char sense_data[SENSE_BUFFER_SIZE]; |
| 122 | unsigned char reserved_array[MAX_DATA_BUF_LEN_WITH_PADDING]; |
| 123 | }; |
| 124 | } __attribute((packed)); |
| 125 | |
| 126 | |
| 127 | /* |
| 128 | * This structure is sent during the intialization phase to get the different |
| 129 | * properties of the channel. |
| 130 | */ |
| 131 | struct vmstorage_channel_properties { |
| 132 | unsigned short protocol_version; |
| 133 | unsigned char path_id; |
| 134 | unsigned char target_id; |
| 135 | |
| 136 | /* Note: port number is only really known on the client side */ |
| 137 | unsigned int port_number; |
| 138 | unsigned int flags; |
| 139 | unsigned int max_transfer_bytes; |
| 140 | |
| 141 | /* This id is unique for each channel and will correspond with */ |
| 142 | /* vendor specific data in the inquirydata */ |
| 143 | unsigned long long unique_id; |
| 144 | } __packed; |
| 145 | |
| 146 | /* This structure is sent during the storage protocol negotiations. */ |
| 147 | struct vmstorage_protocol_version { |
| 148 | /* Major (MSW) and minor (LSW) version numbers. */ |
| 149 | unsigned short major_minor; |
| 150 | |
| 151 | /* |
| 152 | * Revision number is auto-incremented whenever this file is changed |
| 153 | * (See FILL_VMSTOR_REVISION macro above). Mismatch does not |
| 154 | * definitely indicate incompatibility--but it does indicate mismatched |
| 155 | * builds. |
| 156 | */ |
| 157 | unsigned short revision; |
| 158 | } __packed; |
| 159 | |
| 160 | /* Channel Property Flags */ |
| 161 | #define STORAGE_CHANNEL_REMOVABLE_FLAG 0x1 |
| 162 | #define STORAGE_CHANNEL_EMULATED_IDE_FLAG 0x2 |
| 163 | |
| 164 | struct vstor_packet { |
| 165 | /* Requested operation type */ |
| 166 | enum vstor_packet_operation operation; |
| 167 | |
| 168 | /* Flags - see below for values */ |
| 169 | unsigned int flags; |
| 170 | |
| 171 | /* Status of the request returned from the server side. */ |
| 172 | unsigned int status; |
| 173 | |
| 174 | /* Data payload area */ |
| 175 | union { |
| 176 | /* |
| 177 | * Structure used to forward SCSI commands from the |
| 178 | * client to the server. |
| 179 | */ |
| 180 | struct vmscsi_request vm_srb; |
| 181 | |
| 182 | /* Structure used to query channel properties. */ |
| 183 | struct vmstorage_channel_properties storage_channel_properties; |
| 184 | |
| 185 | /* Used during version negotiations. */ |
| 186 | struct vmstorage_protocol_version version; |
| 187 | }; |
| 188 | } __packed; |
| 189 | |
| 190 | /* Packet flags */ |
| 191 | /* |
| 192 | * This flag indicates that the server should send back a completion for this |
| 193 | * packet. |
| 194 | */ |
| 195 | #define REQUEST_COMPLETION_FLAG 0x1 |
| 196 | |
| 197 | /* This is the set of flags that the vsc can set in any packets it sends */ |
| 198 | #define VSC_LEGAL_FLAGS (REQUEST_COMPLETION_FLAG) |
| 199 | |
K. Y. Srinivasan | 5041e71 | 2011-05-12 19:34:36 -0700 | [diff] [blame] | 200 | |
| 201 | #include <linux/kernel.h> |
| 202 | #include <linux/wait.h> |
| 203 | #include "hyperv_storage.h" |
| 204 | #include "hyperv.h" |
| 205 | |
| 206 | /* Defines */ |
| 207 | #define STORVSC_RING_BUFFER_SIZE (20*PAGE_SIZE) |
| 208 | #define BLKVSC_RING_BUFFER_SIZE (20*PAGE_SIZE) |
| 209 | |
| 210 | #define STORVSC_MAX_IO_REQUESTS 128 |
| 211 | |
| 212 | /* |
| 213 | * In Hyper-V, each port/path/target maps to 1 scsi host adapter. In |
| 214 | * reality, the path/target is not used (ie always set to 0) so our |
| 215 | * scsi host adapter essentially has 1 bus with 1 target that contains |
| 216 | * up to 256 luns. |
| 217 | */ |
| 218 | #define STORVSC_MAX_LUNS_PER_TARGET 64 |
| 219 | #define STORVSC_MAX_TARGETS 1 |
| 220 | #define STORVSC_MAX_CHANNELS 1 |
| 221 | |
| 222 | struct hv_storvsc_request; |
| 223 | |
| 224 | /* Matches Windows-end */ |
| 225 | enum storvsc_request_type { |
| 226 | WRITE_TYPE, |
| 227 | READ_TYPE, |
| 228 | UNKNOWN_TYPE, |
| 229 | }; |
| 230 | |
| 231 | |
| 232 | struct hv_storvsc_request { |
| 233 | struct hv_storvsc_request *request; |
| 234 | struct hv_device *device; |
| 235 | |
| 236 | /* Synchronize the request/response if needed */ |
| 237 | struct completion wait_event; |
| 238 | |
| 239 | unsigned char *sense_buffer; |
| 240 | void *context; |
| 241 | void (*on_io_completion)(struct hv_storvsc_request *request); |
| 242 | struct hv_multipage_buffer data_buffer; |
| 243 | |
| 244 | struct vstor_packet vstor_packet; |
| 245 | }; |
| 246 | |
| 247 | |
| 248 | struct storvsc_device_info { |
| 249 | u32 ring_buffer_size; |
| 250 | unsigned int port_number; |
| 251 | unsigned char path_id; |
| 252 | unsigned char target_id; |
| 253 | }; |
| 254 | |
| 255 | struct storvsc_major_info { |
| 256 | int major; |
| 257 | int index; |
| 258 | bool do_register; |
| 259 | char *devname; |
| 260 | char *diskname; |
| 261 | }; |
| 262 | |
| 263 | /* A storvsc device is a device object that contains a vmbus channel */ |
| 264 | struct storvsc_device { |
| 265 | struct hv_device *device; |
| 266 | |
| 267 | /* 0 indicates the device is being destroyed */ |
| 268 | atomic_t ref_count; |
| 269 | |
| 270 | bool drain_notify; |
| 271 | atomic_t num_outstanding_req; |
| 272 | |
| 273 | wait_queue_head_t waiting_to_drain; |
| 274 | |
| 275 | /* |
| 276 | * Each unique Port/Path/Target represents 1 channel ie scsi |
| 277 | * controller. In reality, the pathid, targetid is always 0 |
| 278 | * and the port is set by us |
| 279 | */ |
| 280 | unsigned int port_number; |
| 281 | unsigned char path_id; |
| 282 | unsigned char target_id; |
| 283 | |
| 284 | /* Used for vsc/vsp channel reset process */ |
| 285 | struct hv_storvsc_request init_request; |
| 286 | struct hv_storvsc_request reset_request; |
| 287 | }; |
| 288 | |
| 289 | |
| 290 | /* Get the stordevice object iff exists and its refcount > 1 */ |
| 291 | static inline struct storvsc_device *get_stor_device(struct hv_device *device) |
| 292 | { |
| 293 | struct storvsc_device *stor_device; |
| 294 | |
| 295 | stor_device = (struct storvsc_device *)device->ext; |
| 296 | if (stor_device && atomic_read(&stor_device->ref_count) > 1) |
| 297 | atomic_inc(&stor_device->ref_count); |
| 298 | else |
| 299 | stor_device = NULL; |
| 300 | |
| 301 | return stor_device; |
| 302 | } |
| 303 | |
| 304 | |
| 305 | static inline void put_stor_device(struct hv_device *device) |
| 306 | { |
| 307 | struct storvsc_device *stor_device; |
| 308 | |
| 309 | stor_device = (struct storvsc_device *)device->ext; |
| 310 | |
| 311 | atomic_dec(&stor_device->ref_count); |
| 312 | } |
| 313 | |
| 314 | static inline void storvsc_wait_to_drain(struct storvsc_device *dev) |
| 315 | { |
| 316 | dev->drain_notify = true; |
| 317 | wait_event(dev->waiting_to_drain, |
| 318 | atomic_read(&dev->num_outstanding_req) == 0); |
| 319 | dev->drain_notify = false; |
| 320 | } |
| 321 | |
| 322 | /* Interface */ |
| 323 | |
| 324 | int storvsc_dev_add(struct hv_device *device, |
| 325 | void *additional_info); |
| 326 | int storvsc_dev_remove(struct hv_device *device); |
| 327 | |
| 328 | int storvsc_do_io(struct hv_device *device, |
| 329 | struct hv_storvsc_request *request); |
| 330 | |
| 331 | int storvsc_get_major_info(struct storvsc_device_info *device_info, |
| 332 | struct storvsc_major_info *major_info); |
| 333 | |
K. Y. Srinivasan | cdee150 | 2011-05-12 19:34:34 -0700 | [diff] [blame] | 334 | #endif /* _HYPERV_STORAGE_H */ |