Commit | Line | Data |
---|---|---|
bef4a34a | 1 | /* |
bef4a34a HJ |
2 | * Copyright (c) 2009, Microsoft Corporation. |
3 | * | |
4 | * This program is free software; you can redistribute it and/or modify it | |
5 | * under the terms and conditions of the GNU General Public License, | |
6 | * version 2, as published by the Free Software Foundation. | |
7 | * | |
8 | * This program is distributed in the hope it will be useful, but WITHOUT | |
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
11 | * more details. | |
12 | * | |
13 | * You should have received a copy of the GNU General Public License along with | |
14 | * this program; if not, write to the Free Software Foundation, Inc., 59 Temple | |
15 | * Place - Suite 330, Boston, MA 02111-1307 USA. | |
16 | * | |
17 | * Authors: | |
18 | * Haiyang Zhang <haiyangz@microsoft.com> | |
19 | * Hank Janssen <hjanssen@microsoft.com> | |
bef4a34a | 20 | */ |
5654e932 | 21 | #include <linux/kernel.h> |
0c3b7b2f S |
22 | #include <linux/sched.h> |
23 | #include <linux/wait.h> | |
0ffa63b0 | 24 | #include <linux/string.h> |
5a0e3ad6 | 25 | #include <linux/slab.h> |
0ffa63b0 | 26 | #include <linux/mm.h> |
b4362c9c | 27 | #include <linux/delay.h> |
4983b39a | 28 | #include "osd.h" |
645954c5 | 29 | #include "logging.h" |
bb969793 | 30 | #include "storvsc_api.h" |
f8e5add2 | 31 | #include "vmbus_packet_format.h" |
2dd88b51 | 32 | #include "vstorage.h" |
50ea95df | 33 | #include "channel.h" |
bef4a34a HJ |
34 | |
35 | ||
7dd03fc4 | 36 | struct storvsc_request_extension { |
068c5df2 | 37 | /* LIST_ENTRY ListEntry; */ |
bef4a34a | 38 | |
3d8cdf22 HJ |
39 | struct hv_storvsc_request *request; |
40 | struct hv_device *device; | |
bef4a34a | 41 | |
454f18a9 | 42 | /* Synchronize the request/response if needed */ |
0c3b7b2f S |
43 | int wait_condition; |
44 | wait_queue_head_t wait_event; | |
bef4a34a | 45 | |
3d8cdf22 | 46 | struct vstor_packet vstor_packet; |
7dd03fc4 | 47 | }; |
bef4a34a | 48 | |
454f18a9 | 49 | /* A storvsc device is a device object that contains a vmbus channel */ |
7dd03fc4 | 50 | struct storvsc_device { |
3d8cdf22 | 51 | struct hv_device *device; |
bef4a34a | 52 | |
068c5df2 | 53 | /* 0 indicates the device is being destroyed */ |
3d8cdf22 | 54 | atomic_t ref_count; |
bef4a34a | 55 | |
f638859e | 56 | atomic_t num_outstanding_req; |
bef4a34a | 57 | |
454f18a9 BP |
58 | /* |
59 | * Each unique Port/Path/Target represents 1 channel ie scsi | |
60 | * controller. In reality, the pathid, targetid is always 0 | |
61 | * and the port is set by us | |
62 | */ | |
3d8cdf22 HJ |
63 | unsigned int port_number; |
64 | unsigned char path_id; | |
65 | unsigned char target_id; | |
bef4a34a | 66 | |
068c5df2 GKH |
67 | /* LIST_ENTRY OutstandingRequestList; */ |
68 | /* HANDLE OutstandingRequestLock; */ | |
bef4a34a | 69 | |
454f18a9 | 70 | /* Used for vsc/vsp channel reset process */ |
3d8cdf22 HJ |
71 | struct storvsc_request_extension init_request; |
72 | struct storvsc_request_extension reset_request; | |
7dd03fc4 | 73 | }; |
bef4a34a HJ |
74 | |
75 | ||
3d8cdf22 | 76 | static const char *g_driver_name = "storvsc"; |
bef4a34a | 77 | |
454f18a9 | 78 | /* {ba6163d9-04a1-4d29-b605-72e2ffb1dc7f} */ |
caf26a31 GKH |
79 | static const struct hv_guid gStorVscDeviceType = { |
80 | .data = { | |
81 | 0xd9, 0x63, 0x61, 0xba, 0xa1, 0x04, 0x29, 0x4d, | |
82 | 0xb6, 0x05, 0x72, 0xe2, 0xff, 0xb1, 0xdc, 0x7f | |
83 | } | |
bef4a34a HJ |
84 | }; |
85 | ||
454f18a9 | 86 | |
f638859e | 87 | static inline struct storvsc_device *alloc_stor_device(struct hv_device *device) |
bef4a34a | 88 | { |
f638859e | 89 | struct storvsc_device *stor_device; |
bef4a34a | 90 | |
f638859e HJ |
91 | stor_device = kzalloc(sizeof(struct storvsc_device), GFP_KERNEL); |
92 | if (!stor_device) | |
bef4a34a HJ |
93 | return NULL; |
94 | ||
454f18a9 | 95 | /* Set to 2 to allow both inbound and outbound traffics */ |
3d8cdf22 | 96 | /* (ie get_stor_device() and must_get_stor_device()) to proceed. */ |
f638859e | 97 | atomic_cmpxchg(&stor_device->ref_count, 0, 2); |
bef4a34a | 98 | |
f638859e | 99 | stor_device->device = device; |
ca623ad3 | 100 | device->ext = stor_device; |
bef4a34a | 101 | |
f638859e | 102 | return stor_device; |
bef4a34a HJ |
103 | } |
104 | ||
f638859e | 105 | static inline void free_stor_device(struct storvsc_device *device) |
bef4a34a | 106 | { |
f638859e HJ |
107 | /* ASSERT(atomic_read(&device->ref_count) == 0); */ |
108 | kfree(device); | |
bef4a34a HJ |
109 | } |
110 | ||
454f18a9 | 111 | /* Get the stordevice object iff exists and its refcount > 1 */ |
f638859e | 112 | static inline struct storvsc_device *get_stor_device(struct hv_device *device) |
bef4a34a | 113 | { |
f638859e | 114 | struct storvsc_device *stor_device; |
bef4a34a | 115 | |
ca623ad3 | 116 | stor_device = (struct storvsc_device *)device->ext; |
f638859e HJ |
117 | if (stor_device && atomic_read(&stor_device->ref_count) > 1) |
118 | atomic_inc(&stor_device->ref_count); | |
bef4a34a | 119 | else |
f638859e | 120 | stor_device = NULL; |
bef4a34a | 121 | |
f638859e | 122 | return stor_device; |
bef4a34a HJ |
123 | } |
124 | ||
454f18a9 | 125 | /* Get the stordevice object iff exists and its refcount > 0 */ |
02e37db7 | 126 | static inline struct storvsc_device *must_get_stor_device( |
f638859e | 127 | struct hv_device *device) |
bef4a34a | 128 | { |
f638859e | 129 | struct storvsc_device *stor_device; |
bef4a34a | 130 | |
ca623ad3 | 131 | stor_device = (struct storvsc_device *)device->ext; |
f638859e HJ |
132 | if (stor_device && atomic_read(&stor_device->ref_count)) |
133 | atomic_inc(&stor_device->ref_count); | |
bef4a34a | 134 | else |
f638859e | 135 | stor_device = NULL; |
bef4a34a | 136 | |
f638859e | 137 | return stor_device; |
bef4a34a HJ |
138 | } |
139 | ||
f638859e | 140 | static inline void put_stor_device(struct hv_device *device) |
bef4a34a | 141 | { |
f638859e | 142 | struct storvsc_device *stor_device; |
bef4a34a | 143 | |
ca623ad3 | 144 | stor_device = (struct storvsc_device *)device->ext; |
f638859e | 145 | /* ASSERT(stor_device); */ |
bef4a34a | 146 | |
f638859e HJ |
147 | atomic_dec(&stor_device->ref_count); |
148 | /* ASSERT(atomic_read(&stor_device->ref_count)); */ | |
bef4a34a HJ |
149 | } |
150 | ||
02e37db7 HJ |
151 | /* Drop ref count to 1 to effectively disable get_stor_device() */ |
152 | static inline struct storvsc_device *release_stor_device( | |
f638859e | 153 | struct hv_device *device) |
bef4a34a | 154 | { |
f638859e | 155 | struct storvsc_device *stor_device; |
bef4a34a | 156 | |
ca623ad3 | 157 | stor_device = (struct storvsc_device *)device->ext; |
f638859e | 158 | /* ASSERT(stor_device); */ |
bef4a34a | 159 | |
454f18a9 | 160 | /* Busy wait until the ref drop to 2, then set it to 1 */ |
f638859e | 161 | while (atomic_cmpxchg(&stor_device->ref_count, 2, 1) != 2) |
b4362c9c | 162 | udelay(100); |
bef4a34a | 163 | |
f638859e | 164 | return stor_device; |
bef4a34a HJ |
165 | } |
166 | ||
f638859e | 167 | /* Drop ref count to 0. No one can use stor_device object. */ |
02e37db7 | 168 | static inline struct storvsc_device *final_release_stor_device( |
f638859e | 169 | struct hv_device *device) |
bef4a34a | 170 | { |
f638859e | 171 | struct storvsc_device *stor_device; |
bef4a34a | 172 | |
ca623ad3 | 173 | stor_device = (struct storvsc_device *)device->ext; |
f638859e | 174 | /* ASSERT(stor_device); */ |
bef4a34a | 175 | |
454f18a9 | 176 | /* Busy wait until the ref drop to 1, then set it to 0 */ |
f638859e | 177 | while (atomic_cmpxchg(&stor_device->ref_count, 1, 0) != 1) |
b4362c9c | 178 | udelay(100); |
bef4a34a | 179 | |
ca623ad3 | 180 | device->ext = NULL; |
f638859e | 181 | return stor_device; |
bef4a34a HJ |
182 | } |
183 | ||
f638859e | 184 | static int stor_vsc_channel_init(struct hv_device *device) |
bef4a34a | 185 | { |
f638859e | 186 | struct storvsc_device *stor_device; |
7dd03fc4 | 187 | struct storvsc_request_extension *request; |
f638859e | 188 | struct vstor_packet *vstor_packet; |
068c5df2 | 189 | int ret; |
bef4a34a | 190 | |
f638859e HJ |
191 | stor_device = get_stor_device(device); |
192 | if (!stor_device) { | |
068c5df2 GKH |
193 | DPRINT_ERR(STORVSC, "unable to get stor device..." |
194 | "device being destroyed?"); | |
bef4a34a HJ |
195 | return -1; |
196 | } | |
197 | ||
f638859e HJ |
198 | request = &stor_device->init_request; |
199 | vstor_packet = &request->vstor_packet; | |
bef4a34a | 200 | |
068c5df2 GKH |
201 | /* |
202 | * Now, initiate the vsc/vsp initialization protocol on the open | |
203 | * channel | |
204 | */ | |
8c960e49 | 205 | memset(request, 0, sizeof(struct storvsc_request_extension)); |
0c3b7b2f | 206 | init_waitqueue_head(&request->wait_event); |
f638859e HJ |
207 | vstor_packet->operation = VSTOR_OPERATION_BEGIN_INITIALIZATION; |
208 | vstor_packet->flags = REQUEST_COMPLETION_FLAG; | |
bef4a34a | 209 | |
bef4a34a HJ |
210 | DPRINT_INFO(STORVSC, "BEGIN_INITIALIZATION_OPERATION..."); |
211 | ||
0c3b7b2f | 212 | request->wait_condition = 0; |
f638859e | 213 | ret = vmbus_sendpacket(device->channel, vstor_packet, |
b60d71e2 GKH |
214 | sizeof(struct vstor_packet), |
215 | (unsigned long)request, | |
415f2287 | 216 | VM_PKT_DATA_INBAND, |
b60d71e2 | 217 | VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); |
068c5df2 GKH |
218 | if (ret != 0) { |
219 | DPRINT_ERR(STORVSC, | |
220 | "unable to send BEGIN_INITIALIZATION_OPERATION"); | |
0c3b7b2f S |
221 | goto cleanup; |
222 | } | |
223 | ||
224 | wait_event_timeout(request->wait_event, request->wait_condition, | |
225 | msecs_to_jiffies(1000)); | |
226 | if (request->wait_condition == 0) { | |
227 | ret = -ETIMEDOUT; | |
228 | goto cleanup; | |
bef4a34a HJ |
229 | } |
230 | ||
bef4a34a | 231 | |
f638859e HJ |
232 | if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO || |
233 | vstor_packet->status != 0) { | |
068c5df2 GKH |
234 | DPRINT_ERR(STORVSC, "BEGIN_INITIALIZATION_OPERATION failed " |
235 | "(op %d status 0x%x)", | |
f638859e | 236 | vstor_packet->operation, vstor_packet->status); |
0c3b7b2f | 237 | goto cleanup; |
bef4a34a HJ |
238 | } |
239 | ||
240 | DPRINT_INFO(STORVSC, "QUERY_PROTOCOL_VERSION_OPERATION..."); | |
241 | ||
454f18a9 | 242 | /* reuse the packet for version range supported */ |
f638859e HJ |
243 | memset(vstor_packet, 0, sizeof(struct vstor_packet)); |
244 | vstor_packet->operation = VSTOR_OPERATION_QUERY_PROTOCOL_VERSION; | |
245 | vstor_packet->flags = REQUEST_COMPLETION_FLAG; | |
bef4a34a | 246 | |
f638859e HJ |
247 | vstor_packet->version.major_minor = VMSTOR_PROTOCOL_VERSION_CURRENT; |
248 | FILL_VMSTOR_REVISION(vstor_packet->version.revision); | |
bef4a34a | 249 | |
0c3b7b2f | 250 | request->wait_condition = 0; |
f638859e | 251 | ret = vmbus_sendpacket(device->channel, vstor_packet, |
b60d71e2 GKH |
252 | sizeof(struct vstor_packet), |
253 | (unsigned long)request, | |
415f2287 | 254 | VM_PKT_DATA_INBAND, |
b60d71e2 | 255 | VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); |
068c5df2 GKH |
256 | if (ret != 0) { |
257 | DPRINT_ERR(STORVSC, | |
258 | "unable to send BEGIN_INITIALIZATION_OPERATION"); | |
0c3b7b2f | 259 | goto cleanup; |
bef4a34a HJ |
260 | } |
261 | ||
0c3b7b2f S |
262 | wait_event_timeout(request->wait_event, request->wait_condition, |
263 | msecs_to_jiffies(1000)); | |
264 | if (request->wait_condition == 0) { | |
265 | ret = -ETIMEDOUT; | |
266 | goto cleanup; | |
267 | } | |
bef4a34a | 268 | |
454f18a9 | 269 | /* TODO: Check returned version */ |
f638859e HJ |
270 | if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO || |
271 | vstor_packet->status != 0) { | |
068c5df2 GKH |
272 | DPRINT_ERR(STORVSC, "QUERY_PROTOCOL_VERSION_OPERATION failed " |
273 | "(op %d status 0x%x)", | |
f638859e | 274 | vstor_packet->operation, vstor_packet->status); |
0c3b7b2f | 275 | goto cleanup; |
bef4a34a HJ |
276 | } |
277 | ||
454f18a9 | 278 | /* Query channel properties */ |
bef4a34a HJ |
279 | DPRINT_INFO(STORVSC, "QUERY_PROPERTIES_OPERATION..."); |
280 | ||
f638859e HJ |
281 | memset(vstor_packet, 0, sizeof(struct vstor_packet)); |
282 | vstor_packet->operation = VSTOR_OPERATION_QUERY_PROPERTIES; | |
283 | vstor_packet->flags = REQUEST_COMPLETION_FLAG; | |
284 | vstor_packet->storage_channel_properties.port_number = | |
285 | stor_device->port_number; | |
bef4a34a | 286 | |
0c3b7b2f | 287 | request->wait_condition = 0; |
f638859e | 288 | ret = vmbus_sendpacket(device->channel, vstor_packet, |
b60d71e2 GKH |
289 | sizeof(struct vstor_packet), |
290 | (unsigned long)request, | |
415f2287 | 291 | VM_PKT_DATA_INBAND, |
b60d71e2 | 292 | VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); |
068c5df2 GKH |
293 | |
294 | if (ret != 0) { | |
295 | DPRINT_ERR(STORVSC, | |
296 | "unable to send QUERY_PROPERTIES_OPERATION"); | |
0c3b7b2f | 297 | goto cleanup; |
bef4a34a HJ |
298 | } |
299 | ||
0c3b7b2f S |
300 | wait_event_timeout(request->wait_event, request->wait_condition, |
301 | msecs_to_jiffies(1000)); | |
302 | if (request->wait_condition == 0) { | |
303 | ret = -ETIMEDOUT; | |
304 | goto cleanup; | |
305 | } | |
bef4a34a | 306 | |
454f18a9 | 307 | /* TODO: Check returned version */ |
f638859e HJ |
308 | if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO || |
309 | vstor_packet->status != 0) { | |
068c5df2 GKH |
310 | DPRINT_ERR(STORVSC, "QUERY_PROPERTIES_OPERATION failed " |
311 | "(op %d status 0x%x)", | |
f638859e | 312 | vstor_packet->operation, vstor_packet->status); |
0c3b7b2f | 313 | goto cleanup; |
bef4a34a HJ |
314 | } |
315 | ||
f638859e HJ |
316 | stor_device->path_id = vstor_packet->storage_channel_properties.path_id; |
317 | stor_device->target_id | |
318 | = vstor_packet->storage_channel_properties.target_id; | |
bef4a34a | 319 | |
068c5df2 | 320 | DPRINT_DBG(STORVSC, "channel flag 0x%x, max xfer len 0x%x", |
f638859e HJ |
321 | vstor_packet->storage_channel_properties.flags, |
322 | vstor_packet->storage_channel_properties.max_transfer_bytes); | |
bef4a34a HJ |
323 | |
324 | DPRINT_INFO(STORVSC, "END_INITIALIZATION_OPERATION..."); | |
325 | ||
f638859e HJ |
326 | memset(vstor_packet, 0, sizeof(struct vstor_packet)); |
327 | vstor_packet->operation = VSTOR_OPERATION_END_INITIALIZATION; | |
328 | vstor_packet->flags = REQUEST_COMPLETION_FLAG; | |
bef4a34a | 329 | |
0c3b7b2f | 330 | request->wait_condition = 0; |
f638859e | 331 | ret = vmbus_sendpacket(device->channel, vstor_packet, |
b60d71e2 GKH |
332 | sizeof(struct vstor_packet), |
333 | (unsigned long)request, | |
415f2287 | 334 | VM_PKT_DATA_INBAND, |
b60d71e2 | 335 | VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); |
068c5df2 GKH |
336 | |
337 | if (ret != 0) { | |
338 | DPRINT_ERR(STORVSC, | |
339 | "unable to send END_INITIALIZATION_OPERATION"); | |
0c3b7b2f | 340 | goto cleanup; |
bef4a34a HJ |
341 | } |
342 | ||
0c3b7b2f S |
343 | wait_event_timeout(request->wait_event, request->wait_condition, |
344 | msecs_to_jiffies(1000)); | |
345 | if (request->wait_condition == 0) { | |
346 | ret = -ETIMEDOUT; | |
347 | goto cleanup; | |
348 | } | |
bef4a34a | 349 | |
f638859e HJ |
350 | if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO || |
351 | vstor_packet->status != 0) { | |
068c5df2 GKH |
352 | DPRINT_ERR(STORVSC, "END_INITIALIZATION_OPERATION failed " |
353 | "(op %d status 0x%x)", | |
f638859e | 354 | vstor_packet->operation, vstor_packet->status); |
0c3b7b2f | 355 | goto cleanup; |
bef4a34a HJ |
356 | } |
357 | ||
358 | DPRINT_INFO(STORVSC, "**** storage channel up and running!! ****"); | |
359 | ||
0c3b7b2f | 360 | cleanup: |
f638859e | 361 | put_stor_device(device); |
bef4a34a HJ |
362 | return ret; |
363 | } | |
364 | ||
f638859e HJ |
365 | static void stor_vsc_on_io_completion(struct hv_device *device, |
366 | struct vstor_packet *vstor_packet, | |
367 | struct storvsc_request_extension *request_ext) | |
163680b4 GKH |
368 | { |
369 | struct hv_storvsc_request *request; | |
f638859e | 370 | struct storvsc_device *stor_device; |
163680b4 | 371 | |
f638859e HJ |
372 | stor_device = must_get_stor_device(device); |
373 | if (!stor_device) { | |
163680b4 GKH |
374 | DPRINT_ERR(STORVSC, "unable to get stor device..." |
375 | "device being destroyed?"); | |
163680b4 GKH |
376 | return; |
377 | } | |
378 | ||
379 | DPRINT_DBG(STORVSC, "IO_COMPLETE_OPERATION - request extension %p " | |
f638859e HJ |
380 | "completed bytes xfer %u", request_ext, |
381 | vstor_packet->vm_srb.data_transfer_length); | |
163680b4 | 382 | |
f638859e HJ |
383 | /* ASSERT(request_ext != NULL); */ |
384 | /* ASSERT(request_ext->request != NULL); */ | |
163680b4 | 385 | |
f638859e | 386 | request = request_ext->request; |
163680b4 | 387 | |
e2e64432 | 388 | /* ASSERT(request->OnIOCompletion != NULL); */ |
163680b4 GKH |
389 | |
390 | /* Copy over the status...etc */ | |
f638859e | 391 | request->status = vstor_packet->vm_srb.scsi_status; |
163680b4 | 392 | |
f638859e | 393 | if (request->status != 0 || vstor_packet->vm_srb.srb_status != 1) { |
163680b4 GKH |
394 | DPRINT_WARN(STORVSC, |
395 | "cmd 0x%x scsi status 0x%x srb status 0x%x\n", | |
f638859e HJ |
396 | request->cdb[0], vstor_packet->vm_srb.scsi_status, |
397 | vstor_packet->vm_srb.srb_status); | |
163680b4 GKH |
398 | } |
399 | ||
8a046024 | 400 | if ((request->status & 0xFF) == 0x02) { |
163680b4 | 401 | /* CHECK_CONDITION */ |
f638859e | 402 | if (vstor_packet->vm_srb.srb_status & 0x80) { |
163680b4 GKH |
403 | /* autosense data available */ |
404 | DPRINT_WARN(STORVSC, "storvsc pkt %p autosense data " | |
f638859e HJ |
405 | "valid - len %d\n", request_ext, |
406 | vstor_packet->vm_srb.sense_info_length); | |
163680b4 | 407 | |
f638859e | 408 | /* ASSERT(vstor_packet->vm_srb.sense_info_length <= */ |
e2e64432 | 409 | /* request->SenseBufferSize); */ |
8a046024 | 410 | memcpy(request->sense_buffer, |
f638859e HJ |
411 | vstor_packet->vm_srb.sense_data, |
412 | vstor_packet->vm_srb.sense_info_length); | |
163680b4 | 413 | |
8a046024 | 414 | request->sense_buffer_size = |
f638859e | 415 | vstor_packet->vm_srb.sense_info_length; |
163680b4 GKH |
416 | } |
417 | } | |
418 | ||
419 | /* TODO: */ | |
f638859e | 420 | request->bytes_xfer = vstor_packet->vm_srb.data_transfer_length; |
163680b4 | 421 | |
8a046024 | 422 | request->on_io_completion(request); |
163680b4 | 423 | |
f638859e | 424 | atomic_dec(&stor_device->num_outstanding_req); |
163680b4 | 425 | |
f638859e | 426 | put_stor_device(device); |
163680b4 GKH |
427 | } |
428 | ||
f638859e HJ |
429 | static void stor_vsc_on_receive(struct hv_device *device, |
430 | struct vstor_packet *vstor_packet, | |
431 | struct storvsc_request_extension *request_ext) | |
163680b4 | 432 | { |
f638859e | 433 | switch (vstor_packet->operation) { |
d2aaba45 | 434 | case VSTOR_OPERATION_COMPLETE_IO: |
163680b4 | 435 | DPRINT_DBG(STORVSC, "IO_COMPLETE_OPERATION"); |
f638859e | 436 | stor_vsc_on_io_completion(device, vstor_packet, request_ext); |
163680b4 | 437 | break; |
d2aaba45 | 438 | case VSTOR_OPERATION_REMOVE_DEVICE: |
163680b4 GKH |
439 | DPRINT_INFO(STORVSC, "REMOVE_DEVICE_OPERATION"); |
440 | /* TODO: */ | |
441 | break; | |
442 | ||
443 | default: | |
444 | DPRINT_INFO(STORVSC, "Unknown operation received - %d", | |
f638859e | 445 | vstor_packet->operation); |
163680b4 GKH |
446 | break; |
447 | } | |
448 | } | |
449 | ||
02e37db7 | 450 | static void stor_vsc_on_channel_callback(void *context) |
163680b4 GKH |
451 | { |
452 | struct hv_device *device = (struct hv_device *)context; | |
f638859e HJ |
453 | struct storvsc_device *stor_device; |
454 | u32 bytes_recvd; | |
455 | u64 request_id; | |
73509681 | 456 | unsigned char packet[ALIGN(sizeof(struct vstor_packet), 8)]; |
163680b4 GKH |
457 | struct storvsc_request_extension *request; |
458 | int ret; | |
459 | ||
e2e64432 | 460 | /* ASSERT(device); */ |
163680b4 | 461 | |
f638859e HJ |
462 | stor_device = must_get_stor_device(device); |
463 | if (!stor_device) { | |
163680b4 GKH |
464 | DPRINT_ERR(STORVSC, "unable to get stor device..." |
465 | "device being destroyed?"); | |
163680b4 GKH |
466 | return; |
467 | } | |
468 | ||
469 | do { | |
50ea95df | 470 | ret = vmbus_recvpacket(device->channel, packet, |
73509681 | 471 | ALIGN(sizeof(struct vstor_packet), 8), |
f638859e HJ |
472 | &bytes_recvd, &request_id); |
473 | if (ret == 0 && bytes_recvd > 0) { | |
163680b4 | 474 | DPRINT_DBG(STORVSC, "receive %d bytes - tid %llx", |
f638859e | 475 | bytes_recvd, request_id); |
163680b4 | 476 | |
f638859e HJ |
477 | /* ASSERT(bytes_recvd == |
478 | sizeof(struct vstor_packet)); */ | |
163680b4 GKH |
479 | |
480 | request = (struct storvsc_request_extension *) | |
f638859e | 481 | (unsigned long)request_id; |
e2e64432 | 482 | /* ASSERT(request);c */ |
163680b4 | 483 | |
f638859e HJ |
484 | /* if (vstor_packet.Flags & SYNTHETIC_FLAG) */ |
485 | if ((request == &stor_device->init_request) || | |
486 | (request == &stor_device->reset_request)) { | |
163680b4 GKH |
487 | /* DPRINT_INFO(STORVSC, |
488 | * "reset completion - operation " | |
489 | * "%u status %u", | |
f638859e HJ |
490 | * vstor_packet.Operation, |
491 | * vstor_packet.Status); */ | |
163680b4 | 492 | |
3d8cdf22 | 493 | memcpy(&request->vstor_packet, packet, |
163680b4 | 494 | sizeof(struct vstor_packet)); |
0c3b7b2f S |
495 | request->wait_condition = 1; |
496 | wake_up(&request->wait_event); | |
163680b4 | 497 | } else { |
02e37db7 | 498 | stor_vsc_on_receive(device, |
163680b4 GKH |
499 | (struct vstor_packet *)packet, |
500 | request); | |
501 | } | |
502 | } else { | |
503 | /* DPRINT_DBG(STORVSC, "nothing else to read..."); */ | |
504 | break; | |
505 | } | |
506 | } while (1); | |
507 | ||
02e37db7 | 508 | put_stor_device(device); |
163680b4 GKH |
509 | return; |
510 | } | |
511 | ||
f638859e | 512 | static int stor_vsc_connect_to_vsp(struct hv_device *device) |
bef4a34a | 513 | { |
b3715ee4 | 514 | struct vmstorage_channel_properties props; |
f638859e | 515 | struct storvsc_driver_object *stor_driver; |
068c5df2 | 516 | int ret; |
bef4a34a | 517 | |
ca623ad3 | 518 | stor_driver = (struct storvsc_driver_object *)device->drv; |
8c960e49 | 519 | memset(&props, 0, sizeof(struct vmstorage_channel_properties)); |
bef4a34a | 520 | |
454f18a9 | 521 | /* Open the channel */ |
f638859e HJ |
522 | ret = vmbus_open(device->channel, |
523 | stor_driver->ring_buffer_size, | |
524 | stor_driver->ring_buffer_size, | |
60f841ac GKH |
525 | (void *)&props, |
526 | sizeof(struct vmstorage_channel_properties), | |
f638859e | 527 | stor_vsc_on_channel_callback, device); |
068c5df2 GKH |
528 | |
529 | DPRINT_DBG(STORVSC, "storage props: path id %d, tgt id %d, max xfer %d", | |
d2aaba45 | 530 | props.path_id, props.target_id, props.max_transfer_bytes); |
068c5df2 GKH |
531 | |
532 | if (ret != 0) { | |
bef4a34a HJ |
533 | DPRINT_ERR(STORVSC, "unable to open channel: %d", ret); |
534 | return -1; | |
535 | } | |
536 | ||
f638859e | 537 | ret = stor_vsc_channel_init(device); |
bef4a34a HJ |
538 | |
539 | return ret; | |
540 | } | |
541 | ||
3e189519 | 542 | /* |
02e37db7 | 543 | * stor_vsc_on_device_add - Callback when the device belonging to this driver |
3d8cdf22 | 544 | * is added |
163680b4 | 545 | */ |
f638859e HJ |
546 | static int stor_vsc_on_device_add(struct hv_device *device, |
547 | void *additional_info) | |
163680b4 | 548 | { |
f638859e | 549 | struct storvsc_device *stor_device; |
163680b4 | 550 | /* struct vmstorage_channel_properties *props; */ |
f638859e | 551 | struct storvsc_device_info *device_info; |
163680b4 GKH |
552 | int ret = 0; |
553 | ||
f638859e HJ |
554 | device_info = (struct storvsc_device_info *)additional_info; |
555 | stor_device = alloc_stor_device(device); | |
556 | if (!stor_device) { | |
163680b4 | 557 | ret = -1; |
0c3b7b2f | 558 | goto cleanup; |
163680b4 GKH |
559 | } |
560 | ||
561 | /* Save the channel properties to our storvsc channel */ | |
562 | /* props = (struct vmstorage_channel_properties *) | |
0686e4f4 | 563 | * channel->offerMsg.Offer.u.Standard.UserDefined; */ |
163680b4 GKH |
564 | |
565 | /* FIXME: */ | |
566 | /* | |
567 | * If we support more than 1 scsi channel, we need to set the | |
568 | * port number here to the scsi channel but how do we get the | |
569 | * scsi channel prior to the bus scan | |
570 | */ | |
571 | ||
572 | /* storChannel->PortNumber = 0; | |
573 | storChannel->PathId = props->PathId; | |
574 | storChannel->TargetId = props->TargetId; */ | |
575 | ||
f638859e | 576 | stor_device->port_number = device_info->port_number; |
163680b4 | 577 | /* Send it back up */ |
f638859e | 578 | ret = stor_vsc_connect_to_vsp(device); |
163680b4 | 579 | |
f638859e HJ |
580 | /* device_info->PortNumber = stor_device->PortNumber; */ |
581 | device_info->path_id = stor_device->path_id; | |
582 | device_info->target_id = stor_device->target_id; | |
163680b4 GKH |
583 | |
584 | DPRINT_DBG(STORVSC, "assigned port %u, path %u target %u\n", | |
f638859e HJ |
585 | stor_device->port_number, stor_device->path_id, |
586 | stor_device->target_id); | |
163680b4 | 587 | |
0c3b7b2f | 588 | cleanup: |
163680b4 GKH |
589 | return ret; |
590 | } | |
bef4a34a | 591 | |
3e189519 | 592 | /* |
02e37db7 | 593 | * stor_vsc_on_device_remove - Callback when the our device is being removed |
068c5df2 | 594 | */ |
f638859e | 595 | static int stor_vsc_on_device_remove(struct hv_device *device) |
bef4a34a | 596 | { |
f638859e | 597 | struct storvsc_device *stor_device; |
bef4a34a | 598 | |
068c5df2 | 599 | DPRINT_INFO(STORVSC, "disabling storage device (%p)...", |
ca623ad3 | 600 | device->ext); |
bef4a34a | 601 | |
f638859e | 602 | stor_device = release_stor_device(device); |
bef4a34a | 603 | |
454f18a9 BP |
604 | /* |
605 | * At this point, all outbound traffic should be disable. We | |
606 | * only allow inbound traffic (responses) to proceed so that | |
607 | * outstanding requests can be completed. | |
608 | */ | |
f638859e | 609 | while (atomic_read(&stor_device->num_outstanding_req)) { |
068c5df2 | 610 | DPRINT_INFO(STORVSC, "waiting for %d requests to complete...", |
f638859e | 611 | atomic_read(&stor_device->num_outstanding_req)); |
b4362c9c | 612 | udelay(100); |
bef4a34a HJ |
613 | } |
614 | ||
068c5df2 | 615 | DPRINT_INFO(STORVSC, "removing storage device (%p)...", |
ca623ad3 | 616 | device->ext); |
bef4a34a | 617 | |
f638859e | 618 | stor_device = final_release_stor_device(device); |
bef4a34a | 619 | |
f638859e | 620 | DPRINT_INFO(STORVSC, "storage device (%p) safe to remove", stor_device); |
bef4a34a | 621 | |
454f18a9 | 622 | /* Close the channel */ |
f638859e | 623 | vmbus_close(device->channel); |
bef4a34a | 624 | |
f638859e | 625 | free_stor_device(stor_device); |
068c5df2 | 626 | return 0; |
454f18a9 | 627 | } |
bef4a34a | 628 | |
f638859e | 629 | int stor_vsc_on_host_reset(struct hv_device *device) |
bef4a34a | 630 | { |
f638859e | 631 | struct storvsc_device *stor_device; |
7dd03fc4 | 632 | struct storvsc_request_extension *request; |
f638859e | 633 | struct vstor_packet *vstor_packet; |
068c5df2 | 634 | int ret; |
bef4a34a | 635 | |
bef4a34a HJ |
636 | DPRINT_INFO(STORVSC, "resetting host adapter..."); |
637 | ||
f638859e HJ |
638 | stor_device = get_stor_device(device); |
639 | if (!stor_device) { | |
068c5df2 GKH |
640 | DPRINT_ERR(STORVSC, "unable to get stor device..." |
641 | "device being destroyed?"); | |
bef4a34a HJ |
642 | return -1; |
643 | } | |
644 | ||
f638859e HJ |
645 | request = &stor_device->reset_request; |
646 | vstor_packet = &request->vstor_packet; | |
bef4a34a | 647 | |
0c3b7b2f | 648 | init_waitqueue_head(&request->wait_event); |
bef4a34a | 649 | |
f638859e HJ |
650 | vstor_packet->operation = VSTOR_OPERATION_RESET_BUS; |
651 | vstor_packet->flags = REQUEST_COMPLETION_FLAG; | |
652 | vstor_packet->vm_srb.path_id = stor_device->path_id; | |
bef4a34a | 653 | |
0c3b7b2f | 654 | request->wait_condition = 0; |
f638859e | 655 | ret = vmbus_sendpacket(device->channel, vstor_packet, |
b60d71e2 | 656 | sizeof(struct vstor_packet), |
f638859e | 657 | (unsigned long)&stor_device->reset_request, |
415f2287 | 658 | VM_PKT_DATA_INBAND, |
b60d71e2 | 659 | VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); |
068c5df2 GKH |
660 | if (ret != 0) { |
661 | DPRINT_ERR(STORVSC, "Unable to send reset packet %p ret %d", | |
f638859e | 662 | vstor_packet, ret); |
0c3b7b2f | 663 | goto cleanup; |
bef4a34a HJ |
664 | } |
665 | ||
0c3b7b2f S |
666 | wait_event_timeout(request->wait_event, request->wait_condition, |
667 | msecs_to_jiffies(1000)); | |
668 | if (request->wait_condition == 0) { | |
669 | ret = -ETIMEDOUT; | |
670 | goto cleanup; | |
671 | } | |
bef4a34a | 672 | |
bef4a34a HJ |
673 | DPRINT_INFO(STORVSC, "host adapter reset completed"); |
674 | ||
454f18a9 BP |
675 | /* |
676 | * At this point, all outstanding requests in the adapter | |
677 | * should have been flushed out and return to us | |
678 | */ | |
bef4a34a | 679 | |
0c3b7b2f | 680 | cleanup: |
f638859e | 681 | put_stor_device(device); |
bef4a34a HJ |
682 | return ret; |
683 | } | |
684 | ||
3e189519 | 685 | /* |
02e37db7 | 686 | * stor_vsc_on_io_request - Callback to initiate an I/O request |
068c5df2 | 687 | */ |
f638859e HJ |
688 | static int stor_vsc_on_io_request(struct hv_device *device, |
689 | struct hv_storvsc_request *request) | |
bef4a34a | 690 | { |
f638859e HJ |
691 | struct storvsc_device *stor_device; |
692 | struct storvsc_request_extension *request_extension; | |
693 | struct vstor_packet *vstor_packet; | |
068c5df2 | 694 | int ret = 0; |
bef4a34a | 695 | |
f638859e HJ |
696 | request_extension = |
697 | (struct storvsc_request_extension *)request->extension; | |
698 | vstor_packet = &request_extension->vstor_packet; | |
699 | stor_device = get_stor_device(device); | |
bef4a34a | 700 | |
068c5df2 | 701 | DPRINT_DBG(STORVSC, "enter - Device %p, DeviceExt %p, Request %p, " |
f638859e HJ |
702 | "Extension %p", device, stor_device, request, |
703 | request_extension); | |
bef4a34a HJ |
704 | |
705 | DPRINT_DBG(STORVSC, "req %p len %d bus %d, target %d, lun %d cdblen %d", | |
ca623ad3 | 706 | request, request->data_buffer.len, request->bus, |
f638859e | 707 | request->target_id, request->lun_id, request->cdb_len); |
bef4a34a | 708 | |
f638859e | 709 | if (!stor_device) { |
068c5df2 GKH |
710 | DPRINT_ERR(STORVSC, "unable to get stor device..." |
711 | "device being destroyed?"); | |
bef4a34a HJ |
712 | return -2; |
713 | } | |
714 | ||
f638859e HJ |
715 | /* print_hex_dump_bytes("", DUMP_PREFIX_NONE, request->Cdb, |
716 | * request->CdbLen); */ | |
bef4a34a | 717 | |
f638859e HJ |
718 | request_extension->request = request; |
719 | request_extension->device = device; | |
bef4a34a | 720 | |
f638859e | 721 | memset(vstor_packet, 0 , sizeof(struct vstor_packet)); |
bef4a34a | 722 | |
f638859e | 723 | vstor_packet->flags |= REQUEST_COMPLETION_FLAG; |
bef4a34a | 724 | |
f638859e | 725 | vstor_packet->vm_srb.length = sizeof(struct vmscsi_request); |
bef4a34a | 726 | |
f638859e HJ |
727 | vstor_packet->vm_srb.port_number = request->host; |
728 | vstor_packet->vm_srb.path_id = request->bus; | |
729 | vstor_packet->vm_srb.target_id = request->target_id; | |
730 | vstor_packet->vm_srb.lun = request->lun_id; | |
bef4a34a | 731 | |
f638859e | 732 | vstor_packet->vm_srb.sense_info_length = SENSE_BUFFER_SIZE; |
bef4a34a | 733 | |
454f18a9 | 734 | /* Copy over the scsi command descriptor block */ |
f638859e HJ |
735 | vstor_packet->vm_srb.cdb_length = request->cdb_len; |
736 | memcpy(&vstor_packet->vm_srb.cdb, request->cdb, request->cdb_len); | |
bef4a34a | 737 | |
f638859e | 738 | vstor_packet->vm_srb.data_in = request->type; |
ca623ad3 | 739 | vstor_packet->vm_srb.data_transfer_length = request->data_buffer.len; |
bef4a34a | 740 | |
f638859e | 741 | vstor_packet->operation = VSTOR_OPERATION_EXECUTE_SRB; |
bef4a34a | 742 | |
068c5df2 GKH |
743 | DPRINT_DBG(STORVSC, "srb - len %d port %d, path %d, target %d, " |
744 | "lun %d senselen %d cdblen %d", | |
f638859e HJ |
745 | vstor_packet->vm_srb.length, |
746 | vstor_packet->vm_srb.port_number, | |
747 | vstor_packet->vm_srb.path_id, | |
748 | vstor_packet->vm_srb.target_id, | |
749 | vstor_packet->vm_srb.lun, | |
750 | vstor_packet->vm_srb.sense_info_length, | |
751 | vstor_packet->vm_srb.cdb_length); | |
752 | ||
ca623ad3 | 753 | if (request_extension->request->data_buffer.len) { |
f638859e HJ |
754 | ret = vmbus_sendpacket_multipagebuffer(device->channel, |
755 | &request_extension->request->data_buffer, | |
756 | vstor_packet, | |
b3715ee4 | 757 | sizeof(struct vstor_packet), |
f638859e | 758 | (unsigned long)request_extension); |
068c5df2 | 759 | } else { |
f638859e | 760 | ret = vmbus_sendpacket(device->channel, vstor_packet, |
b60d71e2 | 761 | sizeof(struct vstor_packet), |
f638859e | 762 | (unsigned long)request_extension, |
415f2287 | 763 | VM_PKT_DATA_INBAND, |
b60d71e2 | 764 | VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); |
bef4a34a HJ |
765 | } |
766 | ||
068c5df2 GKH |
767 | if (ret != 0) { |
768 | DPRINT_DBG(STORVSC, "Unable to send packet %p ret %d", | |
f638859e | 769 | vstor_packet, ret); |
bef4a34a HJ |
770 | } |
771 | ||
f638859e | 772 | atomic_inc(&stor_device->num_outstanding_req); |
bef4a34a | 773 | |
f638859e | 774 | put_stor_device(device); |
bef4a34a HJ |
775 | return ret; |
776 | } | |
777 | ||
3e189519 | 778 | /* |
02e37db7 | 779 | * stor_vsc_on_cleanup - Perform any cleanup when the driver is removed |
068c5df2 | 780 | */ |
f638859e | 781 | static void stor_vsc_on_cleanup(struct hv_driver *driver) |
bef4a34a | 782 | { |
bef4a34a HJ |
783 | } |
784 | ||
3e189519 | 785 | /* |
eb4f3e0a | 786 | * stor_vsc_initialize - Main entry point |
163680b4 | 787 | */ |
f638859e | 788 | int stor_vsc_initialize(struct hv_driver *driver) |
bef4a34a | 789 | { |
f638859e | 790 | struct storvsc_driver_object *stor_driver; |
bef4a34a | 791 | |
f638859e | 792 | stor_driver = (struct storvsc_driver_object *)driver; |
bef4a34a | 793 | |
163680b4 GKH |
794 | DPRINT_DBG(STORVSC, "sizeof(STORVSC_REQUEST)=%zd " |
795 | "sizeof(struct storvsc_request_extension)=%zd " | |
796 | "sizeof(struct vstor_packet)=%zd, " | |
797 | "sizeof(struct vmscsi_request)=%zd", | |
798 | sizeof(struct hv_storvsc_request), | |
799 | sizeof(struct storvsc_request_extension), | |
800 | sizeof(struct vstor_packet), | |
801 | sizeof(struct vmscsi_request)); | |
bef4a34a | 802 | |
163680b4 | 803 | /* Make sure we are at least 2 pages since 1 page is used for control */ |
f638859e | 804 | /* ASSERT(stor_driver->RingBufferSize >= (PAGE_SIZE << 1)); */ |
bef4a34a | 805 | |
f638859e | 806 | driver->name = g_driver_name; |
ca623ad3 | 807 | memcpy(&driver->dev_type, &gStorVscDeviceType, |
163680b4 | 808 | sizeof(struct hv_guid)); |
bef4a34a | 809 | |
f638859e HJ |
810 | stor_driver->request_ext_size = |
811 | sizeof(struct storvsc_request_extension); | |
bef4a34a | 812 | |
163680b4 GKH |
813 | /* |
814 | * Divide the ring buffer data size (which is 1 page less | |
815 | * than the ring buffer size since that page is reserved for | |
816 | * the ring buffer indices) by the max request size (which is | |
430a8e9a | 817 | * vmbus_channel_packet_multipage_buffer + struct vstor_packet + u64) |
163680b4 | 818 | */ |
f638859e HJ |
819 | stor_driver->max_outstanding_req_per_channel = |
820 | ((stor_driver->ring_buffer_size - PAGE_SIZE) / | |
73509681 | 821 | ALIGN(MAX_MULTIPAGE_BUFFER_PACKET + |
163680b4 GKH |
822 | sizeof(struct vstor_packet) + sizeof(u64), |
823 | sizeof(u64))); | |
bef4a34a | 824 | |
163680b4 | 825 | DPRINT_INFO(STORVSC, "max io %u, currently %u\n", |
f638859e | 826 | stor_driver->max_outstanding_req_per_channel, |
163680b4 | 827 | STORVSC_MAX_IO_REQUESTS); |
bef4a34a | 828 | |
163680b4 | 829 | /* Setup the dispatch table */ |
ca623ad3 HZ |
830 | stor_driver->base.dev_add = stor_vsc_on_device_add; |
831 | stor_driver->base.dev_rm = stor_vsc_on_device_remove; | |
832 | stor_driver->base.cleanup = stor_vsc_on_cleanup; | |
bef4a34a | 833 | |
f638859e | 834 | stor_driver->on_io_request = stor_vsc_on_io_request; |
bef4a34a | 835 | |
163680b4 | 836 | return 0; |
bef4a34a | 837 | } |