[SCSI] storvsc: Implement multi-channel support
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com> Reviewed-by: Haiyang Zhang <haiyangz@microsoft.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
This commit is contained in:
parent
c8a2ba3f50
commit
6f94d5de09
|
@ -328,6 +328,8 @@ static int storvsc_timeout = 180;
|
||||||
|
|
||||||
#define STORVSC_MAX_IO_REQUESTS 128
|
#define STORVSC_MAX_IO_REQUESTS 128
|
||||||
|
|
||||||
|
static void storvsc_on_channel_callback(void *context);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* In Hyper-V, each port/path/target maps to 1 scsi host adapter. In
|
* In Hyper-V, each port/path/target maps to 1 scsi host adapter. In
|
||||||
* reality, the path/target is not used (ie always set to 0) so our
|
* reality, the path/target is not used (ie always set to 0) so our
|
||||||
|
@ -364,6 +366,7 @@ struct storvsc_device {
|
||||||
|
|
||||||
bool destroy;
|
bool destroy;
|
||||||
bool drain_notify;
|
bool drain_notify;
|
||||||
|
bool open_sub_channel;
|
||||||
atomic_t num_outstanding_req;
|
atomic_t num_outstanding_req;
|
||||||
struct Scsi_Host *host;
|
struct Scsi_Host *host;
|
||||||
|
|
||||||
|
@ -755,12 +758,104 @@ static unsigned int copy_to_bounce_buffer(struct scatterlist *orig_sgl,
|
||||||
return total_copied;
|
return total_copied;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void handle_sc_creation(struct vmbus_channel *new_sc)
|
||||||
|
{
|
||||||
|
struct hv_device *device = new_sc->primary_channel->device_obj;
|
||||||
|
struct storvsc_device *stor_device;
|
||||||
|
struct vmstorage_channel_properties props;
|
||||||
|
|
||||||
|
stor_device = get_out_stor_device(device);
|
||||||
|
if (!stor_device)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (stor_device->open_sub_channel == false)
|
||||||
|
return;
|
||||||
|
|
||||||
|
memset(&props, 0, sizeof(struct vmstorage_channel_properties));
|
||||||
|
|
||||||
|
vmbus_open(new_sc,
|
||||||
|
storvsc_ringbuffer_size,
|
||||||
|
storvsc_ringbuffer_size,
|
||||||
|
(void *)&props,
|
||||||
|
sizeof(struct vmstorage_channel_properties),
|
||||||
|
storvsc_on_channel_callback, new_sc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_multichannel_storage(struct hv_device *device, int max_chns)
|
||||||
|
{
|
||||||
|
struct storvsc_device *stor_device;
|
||||||
|
int num_cpus = num_online_cpus();
|
||||||
|
int num_sc;
|
||||||
|
struct storvsc_cmd_request *request;
|
||||||
|
struct vstor_packet *vstor_packet;
|
||||||
|
int ret, t;
|
||||||
|
|
||||||
|
num_sc = ((max_chns > num_cpus) ? num_cpus : max_chns);
|
||||||
|
stor_device = get_out_stor_device(device);
|
||||||
|
if (!stor_device)
|
||||||
|
return;
|
||||||
|
|
||||||
|
request = &stor_device->init_request;
|
||||||
|
vstor_packet = &request->vstor_packet;
|
||||||
|
|
||||||
|
stor_device->open_sub_channel = true;
|
||||||
|
/*
|
||||||
|
* Establish a handler for dealing with subchannels.
|
||||||
|
*/
|
||||||
|
vmbus_set_sc_create_callback(device->channel, handle_sc_creation);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check to see if sub-channels have already been created. This
|
||||||
|
* can happen when this driver is re-loaded after unloading.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (vmbus_are_subchannels_present(device->channel))
|
||||||
|
return;
|
||||||
|
|
||||||
|
stor_device->open_sub_channel = false;
|
||||||
|
/*
|
||||||
|
* Request the host to create sub-channels.
|
||||||
|
*/
|
||||||
|
memset(request, 0, sizeof(struct storvsc_cmd_request));
|
||||||
|
init_completion(&request->wait_event);
|
||||||
|
vstor_packet->operation = VSTOR_OPERATION_CREATE_SUB_CHANNELS;
|
||||||
|
vstor_packet->flags = REQUEST_COMPLETION_FLAG;
|
||||||
|
vstor_packet->sub_channel_count = num_sc;
|
||||||
|
|
||||||
|
ret = vmbus_sendpacket(device->channel, vstor_packet,
|
||||||
|
(sizeof(struct vstor_packet) -
|
||||||
|
vmscsi_size_delta),
|
||||||
|
(unsigned long)request,
|
||||||
|
VM_PKT_DATA_INBAND,
|
||||||
|
VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
|
||||||
|
|
||||||
|
if (ret != 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
t = wait_for_completion_timeout(&request->wait_event, 10*HZ);
|
||||||
|
if (t == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO ||
|
||||||
|
vstor_packet->status != 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now that we created the sub-channels, invoke the check; this
|
||||||
|
* may trigger the callback.
|
||||||
|
*/
|
||||||
|
stor_device->open_sub_channel = true;
|
||||||
|
vmbus_are_subchannels_present(device->channel);
|
||||||
|
}
|
||||||
|
|
||||||
static int storvsc_channel_init(struct hv_device *device)
|
static int storvsc_channel_init(struct hv_device *device)
|
||||||
{
|
{
|
||||||
struct storvsc_device *stor_device;
|
struct storvsc_device *stor_device;
|
||||||
struct storvsc_cmd_request *request;
|
struct storvsc_cmd_request *request;
|
||||||
struct vstor_packet *vstor_packet;
|
struct vstor_packet *vstor_packet;
|
||||||
int ret, t;
|
int ret, t;
|
||||||
|
int max_chns;
|
||||||
|
bool process_sub_channels = false;
|
||||||
|
|
||||||
stor_device = get_out_stor_device(device);
|
stor_device = get_out_stor_device(device);
|
||||||
if (!stor_device)
|
if (!stor_device)
|
||||||
|
@ -855,6 +950,19 @@ static int storvsc_channel_init(struct hv_device *device)
|
||||||
vstor_packet->status != 0)
|
vstor_packet->status != 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check to see if multi-channel support is there.
|
||||||
|
* Hosts that implement protocol version of 5.1 and above
|
||||||
|
* support multi-channel.
|
||||||
|
*/
|
||||||
|
max_chns = vstor_packet->storage_channel_properties.max_channel_cnt;
|
||||||
|
if ((vmbus_proto_version != VERSION_WIN7) &&
|
||||||
|
(vmbus_proto_version != VERSION_WS2008)) {
|
||||||
|
if (vstor_packet->storage_channel_properties.flags &
|
||||||
|
STORAGE_CHANNEL_SUPPORTS_MULTI_CHANNEL)
|
||||||
|
process_sub_channels = true;
|
||||||
|
}
|
||||||
|
|
||||||
memset(vstor_packet, 0, sizeof(struct vstor_packet));
|
memset(vstor_packet, 0, sizeof(struct vstor_packet));
|
||||||
vstor_packet->operation = VSTOR_OPERATION_END_INITIALIZATION;
|
vstor_packet->operation = VSTOR_OPERATION_END_INITIALIZATION;
|
||||||
vstor_packet->flags = REQUEST_COMPLETION_FLAG;
|
vstor_packet->flags = REQUEST_COMPLETION_FLAG;
|
||||||
|
@ -879,6 +987,9 @@ static int storvsc_channel_init(struct hv_device *device)
|
||||||
vstor_packet->status != 0)
|
vstor_packet->status != 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
|
if (process_sub_channels)
|
||||||
|
handle_multichannel_storage(device, max_chns);
|
||||||
|
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -1100,7 +1211,8 @@ static void storvsc_on_receive(struct hv_device *device,
|
||||||
|
|
||||||
static void storvsc_on_channel_callback(void *context)
|
static void storvsc_on_channel_callback(void *context)
|
||||||
{
|
{
|
||||||
struct hv_device *device = (struct hv_device *)context;
|
struct vmbus_channel *channel = (struct vmbus_channel *)context;
|
||||||
|
struct hv_device *device;
|
||||||
struct storvsc_device *stor_device;
|
struct storvsc_device *stor_device;
|
||||||
u32 bytes_recvd;
|
u32 bytes_recvd;
|
||||||
u64 request_id;
|
u64 request_id;
|
||||||
|
@ -1108,13 +1220,17 @@ static void storvsc_on_channel_callback(void *context)
|
||||||
struct storvsc_cmd_request *request;
|
struct storvsc_cmd_request *request;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
if (channel->primary_channel != NULL)
|
||||||
|
device = channel->primary_channel->device_obj;
|
||||||
|
else
|
||||||
|
device = channel->device_obj;
|
||||||
|
|
||||||
stor_device = get_in_stor_device(device);
|
stor_device = get_in_stor_device(device);
|
||||||
if (!stor_device)
|
if (!stor_device)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
ret = vmbus_recvpacket(device->channel, packet,
|
ret = vmbus_recvpacket(channel, packet,
|
||||||
ALIGN((sizeof(struct vstor_packet) -
|
ALIGN((sizeof(struct vstor_packet) -
|
||||||
vmscsi_size_delta), 8),
|
vmscsi_size_delta), 8),
|
||||||
&bytes_recvd, &request_id);
|
&bytes_recvd, &request_id);
|
||||||
|
@ -1155,7 +1271,7 @@ static int storvsc_connect_to_vsp(struct hv_device *device, u32 ring_size)
|
||||||
ring_size,
|
ring_size,
|
||||||
(void *)&props,
|
(void *)&props,
|
||||||
sizeof(struct vmstorage_channel_properties),
|
sizeof(struct vmstorage_channel_properties),
|
||||||
storvsc_on_channel_callback, device);
|
storvsc_on_channel_callback, device->channel);
|
||||||
|
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -1207,6 +1323,7 @@ static int storvsc_do_io(struct hv_device *device,
|
||||||
{
|
{
|
||||||
struct storvsc_device *stor_device;
|
struct storvsc_device *stor_device;
|
||||||
struct vstor_packet *vstor_packet;
|
struct vstor_packet *vstor_packet;
|
||||||
|
struct vmbus_channel *outgoing_channel;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
vstor_packet = &request->vstor_packet;
|
vstor_packet = &request->vstor_packet;
|
||||||
|
@ -1217,6 +1334,11 @@ static int storvsc_do_io(struct hv_device *device,
|
||||||
|
|
||||||
|
|
||||||
request->device = device;
|
request->device = device;
|
||||||
|
/*
|
||||||
|
* Select an an appropriate channel to send the request out.
|
||||||
|
*/
|
||||||
|
|
||||||
|
outgoing_channel = vmbus_get_outgoing_channel(device->channel);
|
||||||
|
|
||||||
|
|
||||||
vstor_packet->flags |= REQUEST_COMPLETION_FLAG;
|
vstor_packet->flags |= REQUEST_COMPLETION_FLAG;
|
||||||
|
@ -1234,7 +1356,7 @@ static int storvsc_do_io(struct hv_device *device,
|
||||||
vstor_packet->operation = VSTOR_OPERATION_EXECUTE_SRB;
|
vstor_packet->operation = VSTOR_OPERATION_EXECUTE_SRB;
|
||||||
|
|
||||||
if (request->data_buffer.len) {
|
if (request->data_buffer.len) {
|
||||||
ret = vmbus_sendpacket_multipagebuffer(device->channel,
|
ret = vmbus_sendpacket_multipagebuffer(outgoing_channel,
|
||||||
&request->data_buffer,
|
&request->data_buffer,
|
||||||
vstor_packet,
|
vstor_packet,
|
||||||
(sizeof(struct vstor_packet) -
|
(sizeof(struct vstor_packet) -
|
||||||
|
@ -1643,6 +1765,7 @@ static int storvsc_probe(struct hv_device *device,
|
||||||
}
|
}
|
||||||
|
|
||||||
stor_device->destroy = false;
|
stor_device->destroy = false;
|
||||||
|
stor_device->open_sub_channel = false;
|
||||||
init_waitqueue_head(&stor_device->waiting_to_drain);
|
init_waitqueue_head(&stor_device->waiting_to_drain);
|
||||||
stor_device->device = device;
|
stor_device->device = device;
|
||||||
stor_device->host = host;
|
stor_device->host = host;
|
||||||
|
|
Loading…
Reference in New Issue