Staging: hv: storvsc: Rename get_stor_device()
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / drivers / staging / hv / storvsc.c
blob313a3f8cfaf31b2de2994c824fcd263908a44f8b
1 /*
2 * Copyright (c) 2009, Microsoft Corporation.
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.
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.
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.
17 * Authors:
18 * Haiyang Zhang <haiyangz@microsoft.com>
19 * Hank Janssen <hjanssen@microsoft.com>
20 * K. Y. Srinivasan <kys@microsoft.com>
23 #include <linux/kernel.h>
24 #include <linux/sched.h>
25 #include <linux/completion.h>
26 #include <linux/string.h>
27 #include <linux/slab.h>
28 #include <linux/mm.h>
29 #include <linux/delay.h>
31 #include "hyperv.h"
32 #include "hyperv_storage.h"
35 static inline struct storvsc_device *alloc_stor_device(struct hv_device *device)
37 struct storvsc_device *stor_device;
39 stor_device = kzalloc(sizeof(struct storvsc_device), GFP_KERNEL);
40 if (!stor_device)
41 return NULL;
43 /* Set to 2 to allow both inbound and outbound traffics */
44 /* (ie get_out_stor_device() and get_in_stor_device()) to proceed. */
45 atomic_cmpxchg(&stor_device->ref_count, 0, 2);
47 init_waitqueue_head(&stor_device->waiting_to_drain);
48 stor_device->device = device;
49 device->ext = stor_device;
51 return stor_device;
55 /* Get the stordevice object iff exists and its refcount > 0 */
56 static inline struct storvsc_device *get_in_stor_device(
57 struct hv_device *device)
59 struct storvsc_device *stor_device;
61 stor_device = (struct storvsc_device *)device->ext;
62 if (stor_device && atomic_read(&stor_device->ref_count))
63 atomic_inc(&stor_device->ref_count);
64 else
65 stor_device = NULL;
67 return stor_device;
70 /* Drop ref count to 1 to effectively disable get_out_stor_device() */
71 static inline struct storvsc_device *release_stor_device(
72 struct hv_device *device)
74 struct storvsc_device *stor_device;
76 stor_device = (struct storvsc_device *)device->ext;
78 /* Busy wait until the ref drop to 2, then set it to 1 */
79 while (atomic_cmpxchg(&stor_device->ref_count, 2, 1) != 2)
80 udelay(100);
82 return stor_device;
85 /* Drop ref count to 0. No one can use stor_device object. */
86 static inline struct storvsc_device *final_release_stor_device(
87 struct hv_device *device)
89 struct storvsc_device *stor_device;
91 stor_device = (struct storvsc_device *)device->ext;
93 /* Busy wait until the ref drop to 1, then set it to 0 */
94 while (atomic_cmpxchg(&stor_device->ref_count, 1, 0) != 1)
95 udelay(100);
97 device->ext = NULL;
98 return stor_device;
101 static int storvsc_channel_init(struct hv_device *device)
103 struct storvsc_device *stor_device;
104 struct hv_storvsc_request *request;
105 struct vstor_packet *vstor_packet;
106 int ret, t;
108 stor_device = get_out_stor_device(device);
109 if (!stor_device)
110 return -ENODEV;
112 request = &stor_device->init_request;
113 vstor_packet = &request->vstor_packet;
116 * Now, initiate the vsc/vsp initialization protocol on the open
117 * channel
119 memset(request, 0, sizeof(struct hv_storvsc_request));
120 init_completion(&request->wait_event);
121 vstor_packet->operation = VSTOR_OPERATION_BEGIN_INITIALIZATION;
122 vstor_packet->flags = REQUEST_COMPLETION_FLAG;
124 ret = vmbus_sendpacket(device->channel, vstor_packet,
125 sizeof(struct vstor_packet),
126 (unsigned long)request,
127 VM_PKT_DATA_INBAND,
128 VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
129 if (ret != 0)
130 goto cleanup;
132 t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
133 if (t == 0) {
134 ret = -ETIMEDOUT;
135 goto cleanup;
138 if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO ||
139 vstor_packet->status != 0)
140 goto cleanup;
143 /* reuse the packet for version range supported */
144 memset(vstor_packet, 0, sizeof(struct vstor_packet));
145 vstor_packet->operation = VSTOR_OPERATION_QUERY_PROTOCOL_VERSION;
146 vstor_packet->flags = REQUEST_COMPLETION_FLAG;
148 vstor_packet->version.major_minor = VMSTOR_PROTOCOL_VERSION_CURRENT;
149 FILL_VMSTOR_REVISION(vstor_packet->version.revision);
151 ret = vmbus_sendpacket(device->channel, vstor_packet,
152 sizeof(struct vstor_packet),
153 (unsigned long)request,
154 VM_PKT_DATA_INBAND,
155 VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
156 if (ret != 0)
157 goto cleanup;
159 t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
160 if (t == 0) {
161 ret = -ETIMEDOUT;
162 goto cleanup;
165 if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO ||
166 vstor_packet->status != 0)
167 goto cleanup;
170 memset(vstor_packet, 0, sizeof(struct vstor_packet));
171 vstor_packet->operation = VSTOR_OPERATION_QUERY_PROPERTIES;
172 vstor_packet->flags = REQUEST_COMPLETION_FLAG;
173 vstor_packet->storage_channel_properties.port_number =
174 stor_device->port_number;
176 ret = vmbus_sendpacket(device->channel, vstor_packet,
177 sizeof(struct vstor_packet),
178 (unsigned long)request,
179 VM_PKT_DATA_INBAND,
180 VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
182 if (ret != 0)
183 goto cleanup;
185 t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
186 if (t == 0) {
187 ret = -ETIMEDOUT;
188 goto cleanup;
191 if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO ||
192 vstor_packet->status != 0)
193 goto cleanup;
195 stor_device->path_id = vstor_packet->storage_channel_properties.path_id;
196 stor_device->target_id
197 = vstor_packet->storage_channel_properties.target_id;
199 memset(vstor_packet, 0, sizeof(struct vstor_packet));
200 vstor_packet->operation = VSTOR_OPERATION_END_INITIALIZATION;
201 vstor_packet->flags = REQUEST_COMPLETION_FLAG;
203 ret = vmbus_sendpacket(device->channel, vstor_packet,
204 sizeof(struct vstor_packet),
205 (unsigned long)request,
206 VM_PKT_DATA_INBAND,
207 VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
209 if (ret != 0)
210 goto cleanup;
212 t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
213 if (t == 0) {
214 ret = -ETIMEDOUT;
215 goto cleanup;
218 if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO ||
219 vstor_packet->status != 0)
220 goto cleanup;
223 cleanup:
224 put_stor_device(device);
225 return ret;
228 static void storvsc_on_io_completion(struct hv_device *device,
229 struct vstor_packet *vstor_packet,
230 struct hv_storvsc_request *request)
232 struct storvsc_device *stor_device;
233 struct vstor_packet *stor_pkt;
235 stor_device = (struct storvsc_device *)device->ext;
237 stor_pkt = &request->vstor_packet;
240 /* Copy over the status...etc */
241 stor_pkt->vm_srb.scsi_status = vstor_packet->vm_srb.scsi_status;
242 stor_pkt->vm_srb.srb_status = vstor_packet->vm_srb.srb_status;
243 stor_pkt->vm_srb.sense_info_length =
244 vstor_packet->vm_srb.sense_info_length;
246 if (vstor_packet->vm_srb.scsi_status != 0 ||
247 vstor_packet->vm_srb.srb_status != 1){
248 DPRINT_WARN(STORVSC,
249 "cmd 0x%x scsi status 0x%x srb status 0x%x\n",
250 stor_pkt->vm_srb.cdb[0],
251 vstor_packet->vm_srb.scsi_status,
252 vstor_packet->vm_srb.srb_status);
255 if ((vstor_packet->vm_srb.scsi_status & 0xFF) == 0x02) {
256 /* CHECK_CONDITION */
257 if (vstor_packet->vm_srb.srb_status & 0x80) {
258 /* autosense data available */
259 DPRINT_WARN(STORVSC, "storvsc pkt %p autosense data "
260 "valid - len %d\n", request,
261 vstor_packet->vm_srb.sense_info_length);
263 memcpy(request->sense_buffer,
264 vstor_packet->vm_srb.sense_data,
265 vstor_packet->vm_srb.sense_info_length);
270 stor_pkt->vm_srb.data_transfer_length =
271 vstor_packet->vm_srb.data_transfer_length;
273 request->on_io_completion(request);
275 if (atomic_dec_and_test(&stor_device->num_outstanding_req) &&
276 stor_device->drain_notify)
277 wake_up(&stor_device->waiting_to_drain);
282 static void storvsc_on_receive(struct hv_device *device,
283 struct vstor_packet *vstor_packet,
284 struct hv_storvsc_request *request)
286 switch (vstor_packet->operation) {
287 case VSTOR_OPERATION_COMPLETE_IO:
288 storvsc_on_io_completion(device, vstor_packet, request);
289 break;
290 case VSTOR_OPERATION_REMOVE_DEVICE:
292 default:
293 break;
297 static void storvsc_on_channel_callback(void *context)
299 struct hv_device *device = (struct hv_device *)context;
300 struct storvsc_device *stor_device;
301 u32 bytes_recvd;
302 u64 request_id;
303 unsigned char packet[ALIGN(sizeof(struct vstor_packet), 8)];
304 struct hv_storvsc_request *request;
305 int ret;
308 stor_device = get_in_stor_device(device);
309 if (!stor_device)
310 return;
312 do {
313 ret = vmbus_recvpacket(device->channel, packet,
314 ALIGN(sizeof(struct vstor_packet), 8),
315 &bytes_recvd, &request_id);
316 if (ret == 0 && bytes_recvd > 0) {
318 request = (struct hv_storvsc_request *)
319 (unsigned long)request_id;
321 if ((request == &stor_device->init_request) ||
322 (request == &stor_device->reset_request)) {
324 memcpy(&request->vstor_packet, packet,
325 sizeof(struct vstor_packet));
326 complete(&request->wait_event);
327 } else {
328 storvsc_on_receive(device,
329 (struct vstor_packet *)packet,
330 request);
332 } else {
333 break;
335 } while (1);
337 put_stor_device(device);
338 return;
341 static int storvsc_connect_to_vsp(struct hv_device *device, u32 ring_size)
343 struct vmstorage_channel_properties props;
344 int ret;
346 memset(&props, 0, sizeof(struct vmstorage_channel_properties));
348 /* Open the channel */
349 ret = vmbus_open(device->channel,
350 ring_size,
351 ring_size,
352 (void *)&props,
353 sizeof(struct vmstorage_channel_properties),
354 storvsc_on_channel_callback, device);
356 if (ret != 0)
357 return ret;
359 ret = storvsc_channel_init(device);
361 return ret;
364 int storvsc_dev_add(struct hv_device *device,
365 void *additional_info)
367 struct storvsc_device *stor_device;
368 struct storvsc_device_info *device_info;
369 int ret = 0;
371 device_info = (struct storvsc_device_info *)additional_info;
372 stor_device = alloc_stor_device(device);
373 if (!stor_device)
374 return -ENOMEM;
376 /* Save the channel properties to our storvsc channel */
379 * If we support more than 1 scsi channel, we need to set the
380 * port number here to the scsi channel but how do we get the
381 * scsi channel prior to the bus scan.
383 * The host does not support this.
386 stor_device->port_number = device_info->port_number;
387 /* Send it back up */
388 ret = storvsc_connect_to_vsp(device, device_info->ring_buffer_size);
389 if (ret) {
390 kfree(stor_device);
391 return ret;
393 device_info->path_id = stor_device->path_id;
394 device_info->target_id = stor_device->target_id;
396 return ret;
399 int storvsc_dev_remove(struct hv_device *device)
401 struct storvsc_device *stor_device;
403 stor_device = release_stor_device(device);
406 * At this point, all outbound traffic should be disable. We
407 * only allow inbound traffic (responses) to proceed so that
408 * outstanding requests can be completed.
411 storvsc_wait_to_drain(stor_device);
413 stor_device = final_release_stor_device(device);
415 /* Close the channel */
416 vmbus_close(device->channel);
418 kfree(stor_device);
419 return 0;
422 int storvsc_do_io(struct hv_device *device,
423 struct hv_storvsc_request *request)
425 struct storvsc_device *stor_device;
426 struct vstor_packet *vstor_packet;
427 int ret = 0;
429 vstor_packet = &request->vstor_packet;
430 stor_device = get_out_stor_device(device);
432 if (!stor_device)
433 return -ENODEV;
436 request->device = device;
439 vstor_packet->flags |= REQUEST_COMPLETION_FLAG;
441 vstor_packet->vm_srb.length = sizeof(struct vmscsi_request);
444 vstor_packet->vm_srb.sense_info_length = SENSE_BUFFER_SIZE;
447 vstor_packet->vm_srb.data_transfer_length =
448 request->data_buffer.len;
450 vstor_packet->operation = VSTOR_OPERATION_EXECUTE_SRB;
452 if (request->data_buffer.len) {
453 ret = vmbus_sendpacket_multipagebuffer(device->channel,
454 &request->data_buffer,
455 vstor_packet,
456 sizeof(struct vstor_packet),
457 (unsigned long)request);
458 } else {
459 ret = vmbus_sendpacket(device->channel, vstor_packet,
460 sizeof(struct vstor_packet),
461 (unsigned long)request,
462 VM_PKT_DATA_INBAND,
463 VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
466 if (ret != 0)
467 return ret;
469 atomic_inc(&stor_device->num_outstanding_req);
471 put_stor_device(device);
472 return ret;
476 * The channel properties uniquely specify how the device is to be
477 * presented to the guest. Map this information for use by the block
478 * driver. For Linux guests on Hyper-V, we emulate a scsi HBA in the guest
479 * (storvsc_drv) and so scsi devices in the guest are handled by
480 * native upper level Linux drivers. Consequently, Hyper-V
481 * block driver, while being a generic block driver, presently does not
482 * deal with anything other than devices that would need to be presented
483 * to the guest as an IDE disk.
485 * This function maps the channel properties as embedded in the input
486 * parameter device_info onto information necessary to register the
487 * corresponding block device.
489 * Currently, there is no way to stop the emulation of the block device
490 * on the host side. And so, to prevent the native IDE drivers in Linux
491 * from taking over these devices (to be managedby Hyper-V block
492 * driver), we will take over if need be the major of the IDE controllers.
496 int storvsc_get_major_info(struct storvsc_device_info *device_info,
497 struct storvsc_major_info *major_info)
499 static bool ide0_registered;
500 static bool ide1_registered;
503 * For now we only support IDE disks.
505 major_info->devname = "ide";
506 major_info->diskname = "hd";
508 if (device_info->path_id) {
509 major_info->major = 22;
510 if (!ide1_registered) {
511 major_info->do_register = true;
512 ide1_registered = true;
513 } else
514 major_info->do_register = false;
516 if (device_info->target_id)
517 major_info->index = 3;
518 else
519 major_info->index = 2;
521 return 0;
522 } else {
523 major_info->major = 3;
524 if (!ide0_registered) {
525 major_info->do_register = true;
526 ide0_registered = true;
527 } else
528 major_info->do_register = false;
530 if (device_info->target_id)
531 major_info->index = 1;
532 else
533 major_info->index = 0;
535 return 0;
538 return -ENODEV;