| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * 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 | 4 | * |
|---|
| 17 | 5 | * Authors: |
|---|
| 18 | 6 | * Haiyang Zhang <haiyangz@microsoft.com> |
|---|
| .. | .. |
|---|
| 368 | 356 | }; |
|---|
| 369 | 357 | |
|---|
| 370 | 358 | /* |
|---|
| 371 | | - * SRB status codes and masks; a subset of the codes used here. |
|---|
| 359 | + * SRB status codes and masks. In the 8-bit field, the two high order bits |
|---|
| 360 | + * are flags, while the remaining 6 bits are an integer status code. The |
|---|
| 361 | + * definitions here include only the subset of the integer status codes that |
|---|
| 362 | + * are tested for in this driver. |
|---|
| 372 | 363 | */ |
|---|
| 373 | | - |
|---|
| 374 | 364 | #define SRB_STATUS_AUTOSENSE_VALID 0x80 |
|---|
| 375 | 365 | #define SRB_STATUS_QUEUE_FROZEN 0x40 |
|---|
| 376 | | -#define SRB_STATUS_INVALID_LUN 0x20 |
|---|
| 377 | | -#define SRB_STATUS_SUCCESS 0x01 |
|---|
| 378 | | -#define SRB_STATUS_ABORTED 0x02 |
|---|
| 379 | | -#define SRB_STATUS_ERROR 0x04 |
|---|
| 380 | | -#define SRB_STATUS_DATA_OVERRUN 0x12 |
|---|
| 366 | + |
|---|
| 367 | +/* SRB status integer codes */ |
|---|
| 368 | +#define SRB_STATUS_SUCCESS 0x01 |
|---|
| 369 | +#define SRB_STATUS_ABORTED 0x02 |
|---|
| 370 | +#define SRB_STATUS_ERROR 0x04 |
|---|
| 371 | +#define SRB_STATUS_INVALID_REQUEST 0x06 |
|---|
| 372 | +#define SRB_STATUS_DATA_OVERRUN 0x12 |
|---|
| 373 | +#define SRB_STATUS_INVALID_LUN 0x20 |
|---|
| 381 | 374 | |
|---|
| 382 | 375 | #define SRB_STATUS(status) \ |
|---|
| 383 | 376 | (status & ~(SRB_STATUS_AUTOSENSE_VALID | SRB_STATUS_QUEUE_FROZEN)) |
|---|
| .. | .. |
|---|
| 385 | 378 | * This is the end of Protocol specific defines. |
|---|
| 386 | 379 | */ |
|---|
| 387 | 380 | |
|---|
| 388 | | -static int storvsc_ringbuffer_size = (256 * PAGE_SIZE); |
|---|
| 381 | +static int storvsc_ringbuffer_size = (128 * 1024); |
|---|
| 389 | 382 | static u32 max_outstanding_req_per_channel; |
|---|
| 383 | +static int storvsc_change_queue_depth(struct scsi_device *sdev, int queue_depth); |
|---|
| 390 | 384 | |
|---|
| 391 | 385 | static int storvsc_vcpus_per_sub_channel = 4; |
|---|
| 392 | 386 | |
|---|
| .. | .. |
|---|
| 446 | 440 | |
|---|
| 447 | 441 | bool destroy; |
|---|
| 448 | 442 | bool drain_notify; |
|---|
| 449 | | - bool open_sub_channel; |
|---|
| 450 | 443 | atomic_t num_outstanding_req; |
|---|
| 451 | 444 | struct Scsi_Host *host; |
|---|
| 452 | 445 | |
|---|
| .. | .. |
|---|
| 474 | 467 | * Mask of CPUs bound to subchannels. |
|---|
| 475 | 468 | */ |
|---|
| 476 | 469 | struct cpumask alloced_cpus; |
|---|
| 470 | + /* |
|---|
| 471 | + * Serializes modifications of stor_chns[] from storvsc_do_io() |
|---|
| 472 | + * and storvsc_change_target_cpu(). |
|---|
| 473 | + */ |
|---|
| 474 | + spinlock_t lock; |
|---|
| 477 | 475 | /* Used for vsc/vsp channel reset process */ |
|---|
| 478 | 476 | struct storvsc_cmd_request init_request; |
|---|
| 479 | 477 | struct storvsc_cmd_request reset_request; |
|---|
| .. | .. |
|---|
| 633 | 631 | |
|---|
| 634 | 632 | } |
|---|
| 635 | 633 | |
|---|
| 634 | +static void storvsc_change_target_cpu(struct vmbus_channel *channel, u32 old, |
|---|
| 635 | + u32 new) |
|---|
| 636 | +{ |
|---|
| 637 | + struct storvsc_device *stor_device; |
|---|
| 638 | + struct vmbus_channel *cur_chn; |
|---|
| 639 | + bool old_is_alloced = false; |
|---|
| 640 | + struct hv_device *device; |
|---|
| 641 | + unsigned long flags; |
|---|
| 642 | + int cpu; |
|---|
| 643 | + |
|---|
| 644 | + device = channel->primary_channel ? |
|---|
| 645 | + channel->primary_channel->device_obj |
|---|
| 646 | + : channel->device_obj; |
|---|
| 647 | + stor_device = get_out_stor_device(device); |
|---|
| 648 | + if (!stor_device) |
|---|
| 649 | + return; |
|---|
| 650 | + |
|---|
| 651 | + /* See storvsc_do_io() -> get_og_chn(). */ |
|---|
| 652 | + spin_lock_irqsave(&stor_device->lock, flags); |
|---|
| 653 | + |
|---|
| 654 | + /* |
|---|
| 655 | + * Determines if the storvsc device has other channels assigned to |
|---|
| 656 | + * the "old" CPU to update the alloced_cpus mask and the stor_chns |
|---|
| 657 | + * array. |
|---|
| 658 | + */ |
|---|
| 659 | + if (device->channel != channel && device->channel->target_cpu == old) { |
|---|
| 660 | + cur_chn = device->channel; |
|---|
| 661 | + old_is_alloced = true; |
|---|
| 662 | + goto old_is_alloced; |
|---|
| 663 | + } |
|---|
| 664 | + list_for_each_entry(cur_chn, &device->channel->sc_list, sc_list) { |
|---|
| 665 | + if (cur_chn == channel) |
|---|
| 666 | + continue; |
|---|
| 667 | + if (cur_chn->target_cpu == old) { |
|---|
| 668 | + old_is_alloced = true; |
|---|
| 669 | + goto old_is_alloced; |
|---|
| 670 | + } |
|---|
| 671 | + } |
|---|
| 672 | + |
|---|
| 673 | +old_is_alloced: |
|---|
| 674 | + if (old_is_alloced) |
|---|
| 675 | + WRITE_ONCE(stor_device->stor_chns[old], cur_chn); |
|---|
| 676 | + else |
|---|
| 677 | + cpumask_clear_cpu(old, &stor_device->alloced_cpus); |
|---|
| 678 | + |
|---|
| 679 | + /* "Flush" the stor_chns array. */ |
|---|
| 680 | + for_each_possible_cpu(cpu) { |
|---|
| 681 | + if (stor_device->stor_chns[cpu] && !cpumask_test_cpu( |
|---|
| 682 | + cpu, &stor_device->alloced_cpus)) |
|---|
| 683 | + WRITE_ONCE(stor_device->stor_chns[cpu], NULL); |
|---|
| 684 | + } |
|---|
| 685 | + |
|---|
| 686 | + WRITE_ONCE(stor_device->stor_chns[new], channel); |
|---|
| 687 | + cpumask_set_cpu(new, &stor_device->alloced_cpus); |
|---|
| 688 | + |
|---|
| 689 | + spin_unlock_irqrestore(&stor_device->lock, flags); |
|---|
| 690 | +} |
|---|
| 691 | + |
|---|
| 636 | 692 | static void handle_sc_creation(struct vmbus_channel *new_sc) |
|---|
| 637 | 693 | { |
|---|
| 638 | 694 | struct hv_device *device = new_sc->primary_channel->device_obj; |
|---|
| 695 | + struct device *dev = &device->device; |
|---|
| 639 | 696 | struct storvsc_device *stor_device; |
|---|
| 640 | 697 | struct vmstorage_channel_properties props; |
|---|
| 698 | + int ret; |
|---|
| 641 | 699 | |
|---|
| 642 | 700 | stor_device = get_out_stor_device(device); |
|---|
| 643 | 701 | if (!stor_device) |
|---|
| 644 | 702 | return; |
|---|
| 645 | 703 | |
|---|
| 646 | | - if (stor_device->open_sub_channel == false) |
|---|
| 647 | | - return; |
|---|
| 648 | | - |
|---|
| 649 | 704 | memset(&props, 0, sizeof(struct vmstorage_channel_properties)); |
|---|
| 650 | 705 | |
|---|
| 651 | | - vmbus_open(new_sc, |
|---|
| 652 | | - storvsc_ringbuffer_size, |
|---|
| 653 | | - storvsc_ringbuffer_size, |
|---|
| 654 | | - (void *)&props, |
|---|
| 655 | | - sizeof(struct vmstorage_channel_properties), |
|---|
| 656 | | - storvsc_on_channel_callback, new_sc); |
|---|
| 706 | + ret = vmbus_open(new_sc, |
|---|
| 707 | + storvsc_ringbuffer_size, |
|---|
| 708 | + storvsc_ringbuffer_size, |
|---|
| 709 | + (void *)&props, |
|---|
| 710 | + sizeof(struct vmstorage_channel_properties), |
|---|
| 711 | + storvsc_on_channel_callback, new_sc); |
|---|
| 657 | 712 | |
|---|
| 658 | | - if (new_sc->state == CHANNEL_OPENED_STATE) { |
|---|
| 659 | | - stor_device->stor_chns[new_sc->target_cpu] = new_sc; |
|---|
| 660 | | - cpumask_set_cpu(new_sc->target_cpu, &stor_device->alloced_cpus); |
|---|
| 713 | + /* In case vmbus_open() fails, we don't use the sub-channel. */ |
|---|
| 714 | + if (ret != 0) { |
|---|
| 715 | + dev_err(dev, "Failed to open sub-channel: err=%d\n", ret); |
|---|
| 716 | + return; |
|---|
| 661 | 717 | } |
|---|
| 718 | + |
|---|
| 719 | + new_sc->change_target_cpu_callback = storvsc_change_target_cpu; |
|---|
| 720 | + |
|---|
| 721 | + /* Add the sub-channel to the array of available channels. */ |
|---|
| 722 | + stor_device->stor_chns[new_sc->target_cpu] = new_sc; |
|---|
| 723 | + cpumask_set_cpu(new_sc->target_cpu, &stor_device->alloced_cpus); |
|---|
| 662 | 724 | } |
|---|
| 663 | 725 | |
|---|
| 664 | 726 | static void handle_multichannel_storage(struct hv_device *device, int max_chns) |
|---|
| 665 | 727 | { |
|---|
| 728 | + struct device *dev = &device->device; |
|---|
| 666 | 729 | struct storvsc_device *stor_device; |
|---|
| 667 | 730 | int num_sc; |
|---|
| 668 | 731 | struct storvsc_cmd_request *request; |
|---|
| .. | .. |
|---|
| 688 | 751 | request = &stor_device->init_request; |
|---|
| 689 | 752 | vstor_packet = &request->vstor_packet; |
|---|
| 690 | 753 | |
|---|
| 691 | | - stor_device->open_sub_channel = true; |
|---|
| 692 | 754 | /* |
|---|
| 693 | 755 | * Establish a handler for dealing with subchannels. |
|---|
| 694 | 756 | */ |
|---|
| 695 | 757 | vmbus_set_sc_create_callback(device->channel, handle_sc_creation); |
|---|
| 696 | 758 | |
|---|
| 697 | | - /* |
|---|
| 698 | | - * Check to see if sub-channels have already been created. This |
|---|
| 699 | | - * can happen when this driver is re-loaded after unloading. |
|---|
| 700 | | - */ |
|---|
| 701 | | - |
|---|
| 702 | | - if (vmbus_are_subchannels_present(device->channel)) |
|---|
| 703 | | - return; |
|---|
| 704 | | - |
|---|
| 705 | | - stor_device->open_sub_channel = false; |
|---|
| 706 | 759 | /* |
|---|
| 707 | 760 | * Request the host to create sub-channels. |
|---|
| 708 | 761 | */ |
|---|
| .. | .. |
|---|
| 719 | 772 | VM_PKT_DATA_INBAND, |
|---|
| 720 | 773 | VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); |
|---|
| 721 | 774 | |
|---|
| 722 | | - if (ret != 0) |
|---|
| 775 | + if (ret != 0) { |
|---|
| 776 | + dev_err(dev, "Failed to create sub-channel: err=%d\n", ret); |
|---|
| 723 | 777 | return; |
|---|
| 778 | + } |
|---|
| 724 | 779 | |
|---|
| 725 | 780 | t = wait_for_completion_timeout(&request->wait_event, 10*HZ); |
|---|
| 726 | | - if (t == 0) |
|---|
| 781 | + if (t == 0) { |
|---|
| 782 | + dev_err(dev, "Failed to create sub-channel: timed out\n"); |
|---|
| 727 | 783 | return; |
|---|
| 784 | + } |
|---|
| 728 | 785 | |
|---|
| 729 | 786 | if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO || |
|---|
| 730 | | - vstor_packet->status != 0) |
|---|
| 787 | + vstor_packet->status != 0) { |
|---|
| 788 | + dev_err(dev, "Failed to create sub-channel: op=%d, sts=%d\n", |
|---|
| 789 | + vstor_packet->operation, vstor_packet->status); |
|---|
| 731 | 790 | return; |
|---|
| 791 | + } |
|---|
| 732 | 792 | |
|---|
| 733 | 793 | /* |
|---|
| 734 | | - * Now that we created the sub-channels, invoke the check; this |
|---|
| 735 | | - * may trigger the callback. |
|---|
| 794 | + * We need to do nothing here, because vmbus_process_offer() |
|---|
| 795 | + * invokes channel->sc_creation_callback, which will open and use |
|---|
| 796 | + * the sub-channel(s). |
|---|
| 736 | 797 | */ |
|---|
| 737 | | - stor_device->open_sub_channel = true; |
|---|
| 738 | | - vmbus_are_subchannels_present(device->channel); |
|---|
| 739 | 798 | } |
|---|
| 740 | 799 | |
|---|
| 741 | 800 | static void cache_wwn(struct storvsc_device *stor_device, |
|---|
| .. | .. |
|---|
| 887 | 946 | if (stor_device->stor_chns == NULL) |
|---|
| 888 | 947 | return -ENOMEM; |
|---|
| 889 | 948 | |
|---|
| 949 | + device->channel->change_target_cpu_callback = storvsc_change_target_cpu; |
|---|
| 950 | + |
|---|
| 890 | 951 | stor_device->stor_chns[device->channel->target_cpu] = device->channel; |
|---|
| 891 | 952 | cpumask_set_cpu(device->channel->target_cpu, |
|---|
| 892 | 953 | &stor_device->alloced_cpus); |
|---|
| .. | .. |
|---|
| 938 | 999 | struct storvsc_scan_work *wrk; |
|---|
| 939 | 1000 | void (*process_err_fn)(struct work_struct *work); |
|---|
| 940 | 1001 | struct hv_host_device *host_dev = shost_priv(host); |
|---|
| 941 | | - bool do_work = false; |
|---|
| 942 | 1002 | |
|---|
| 943 | 1003 | switch (SRB_STATUS(vm_srb->srb_status)) { |
|---|
| 944 | 1004 | case SRB_STATUS_ERROR: |
|---|
| 945 | | - /* |
|---|
| 946 | | - * Let upper layer deal with error when |
|---|
| 947 | | - * sense message is present. |
|---|
| 948 | | - */ |
|---|
| 1005 | + case SRB_STATUS_ABORTED: |
|---|
| 1006 | + case SRB_STATUS_INVALID_REQUEST: |
|---|
| 1007 | + if (vm_srb->srb_status & SRB_STATUS_AUTOSENSE_VALID) { |
|---|
| 1008 | + /* Check for capacity change */ |
|---|
| 1009 | + if ((asc == 0x2a) && (ascq == 0x9)) { |
|---|
| 1010 | + process_err_fn = storvsc_device_scan; |
|---|
| 1011 | + /* Retry the I/O that triggered this. */ |
|---|
| 1012 | + set_host_byte(scmnd, DID_REQUEUE); |
|---|
| 1013 | + goto do_work; |
|---|
| 1014 | + } |
|---|
| 949 | 1015 | |
|---|
| 950 | | - if (vm_srb->srb_status & SRB_STATUS_AUTOSENSE_VALID) |
|---|
| 951 | | - break; |
|---|
| 1016 | + /* |
|---|
| 1017 | + * Otherwise, let upper layer deal with the |
|---|
| 1018 | + * error when sense message is present |
|---|
| 1019 | + */ |
|---|
| 1020 | + return; |
|---|
| 1021 | + } |
|---|
| 1022 | + |
|---|
| 952 | 1023 | /* |
|---|
| 953 | 1024 | * If there is an error; offline the device since all |
|---|
| 954 | 1025 | * error recovery strategies would have already been |
|---|
| .. | .. |
|---|
| 961 | 1032 | set_host_byte(scmnd, DID_PASSTHROUGH); |
|---|
| 962 | 1033 | break; |
|---|
| 963 | 1034 | /* |
|---|
| 964 | | - * On Some Windows hosts TEST_UNIT_READY command can return |
|---|
| 965 | | - * SRB_STATUS_ERROR, let the upper level code deal with it |
|---|
| 966 | | - * based on the sense information. |
|---|
| 1035 | + * On some Hyper-V hosts TEST_UNIT_READY command can |
|---|
| 1036 | + * return SRB_STATUS_ERROR. Let the upper level code |
|---|
| 1037 | + * deal with it based on the sense information. |
|---|
| 967 | 1038 | */ |
|---|
| 968 | 1039 | case TEST_UNIT_READY: |
|---|
| 969 | 1040 | break; |
|---|
| 970 | 1041 | default: |
|---|
| 971 | 1042 | set_host_byte(scmnd, DID_ERROR); |
|---|
| 972 | 1043 | } |
|---|
| 973 | | - break; |
|---|
| 974 | | - case SRB_STATUS_INVALID_LUN: |
|---|
| 975 | | - set_host_byte(scmnd, DID_NO_CONNECT); |
|---|
| 976 | | - do_work = true; |
|---|
| 977 | | - process_err_fn = storvsc_remove_lun; |
|---|
| 978 | | - break; |
|---|
| 979 | | - case SRB_STATUS_ABORTED: |
|---|
| 980 | | - if (vm_srb->srb_status & SRB_STATUS_AUTOSENSE_VALID && |
|---|
| 981 | | - (asc == 0x2a) && (ascq == 0x9)) { |
|---|
| 982 | | - do_work = true; |
|---|
| 983 | | - process_err_fn = storvsc_device_scan; |
|---|
| 984 | | - /* |
|---|
| 985 | | - * Retry the I/O that trigerred this. |
|---|
| 986 | | - */ |
|---|
| 987 | | - set_host_byte(scmnd, DID_REQUEUE); |
|---|
| 988 | | - } |
|---|
| 989 | | - break; |
|---|
| 990 | | - } |
|---|
| 991 | | - |
|---|
| 992 | | - if (!do_work) |
|---|
| 993 | 1044 | return; |
|---|
| 994 | 1045 | |
|---|
| 1046 | + case SRB_STATUS_INVALID_LUN: |
|---|
| 1047 | + set_host_byte(scmnd, DID_NO_CONNECT); |
|---|
| 1048 | + process_err_fn = storvsc_remove_lun; |
|---|
| 1049 | + goto do_work; |
|---|
| 1050 | + |
|---|
| 1051 | + } |
|---|
| 1052 | + return; |
|---|
| 1053 | + |
|---|
| 1054 | +do_work: |
|---|
| 995 | 1055 | /* |
|---|
| 996 | 1056 | * We need to schedule work to process this error; schedule it. |
|---|
| 997 | 1057 | */ |
|---|
| .. | .. |
|---|
| 1049 | 1109 | data_transfer_length = 0; |
|---|
| 1050 | 1110 | } |
|---|
| 1051 | 1111 | |
|---|
| 1112 | + /* Validate data_transfer_length (from Hyper-V) */ |
|---|
| 1113 | + if (data_transfer_length > cmd_request->payload->range.len) |
|---|
| 1114 | + data_transfer_length = cmd_request->payload->range.len; |
|---|
| 1115 | + |
|---|
| 1052 | 1116 | scsi_set_resid(scmnd, |
|---|
| 1053 | 1117 | cmd_request->payload->range.len - data_transfer_length); |
|---|
| 1054 | 1118 | |
|---|
| .. | .. |
|---|
| 1089 | 1153 | /* Copy over the status...etc */ |
|---|
| 1090 | 1154 | stor_pkt->vm_srb.scsi_status = vstor_packet->vm_srb.scsi_status; |
|---|
| 1091 | 1155 | stor_pkt->vm_srb.srb_status = vstor_packet->vm_srb.srb_status; |
|---|
| 1156 | + |
|---|
| 1157 | + /* Validate sense_info_length (from Hyper-V) */ |
|---|
| 1158 | + if (vstor_packet->vm_srb.sense_info_length > sense_buffer_size) |
|---|
| 1159 | + vstor_packet->vm_srb.sense_info_length = sense_buffer_size; |
|---|
| 1160 | + |
|---|
| 1092 | 1161 | stor_pkt->vm_srb.sense_info_length = |
|---|
| 1093 | 1162 | vstor_packet->vm_srb.sense_info_length; |
|---|
| 1094 | 1163 | |
|---|
| .. | .. |
|---|
| 1259 | 1328 | const struct cpumask *node_mask; |
|---|
| 1260 | 1329 | int num_channels, tgt_cpu; |
|---|
| 1261 | 1330 | |
|---|
| 1262 | | - if (stor_device->num_sc == 0) |
|---|
| 1331 | + if (stor_device->num_sc == 0) { |
|---|
| 1332 | + stor_device->stor_chns[q_num] = stor_device->device->channel; |
|---|
| 1263 | 1333 | return stor_device->device->channel; |
|---|
| 1334 | + } |
|---|
| 1264 | 1335 | |
|---|
| 1265 | 1336 | /* |
|---|
| 1266 | 1337 | * Our channel array is sparsley populated and we |
|---|
| .. | .. |
|---|
| 1269 | 1340 | * The strategy is simple: |
|---|
| 1270 | 1341 | * I. Ensure NUMA locality |
|---|
| 1271 | 1342 | * II. Distribute evenly (best effort) |
|---|
| 1272 | | - * III. Mapping is persistent. |
|---|
| 1273 | 1343 | */ |
|---|
| 1274 | 1344 | |
|---|
| 1275 | 1345 | node_mask = cpumask_of_node(cpu_to_node(q_num)); |
|---|
| .. | .. |
|---|
| 1279 | 1349 | if (cpumask_test_cpu(tgt_cpu, node_mask)) |
|---|
| 1280 | 1350 | num_channels++; |
|---|
| 1281 | 1351 | } |
|---|
| 1282 | | - if (num_channels == 0) |
|---|
| 1352 | + if (num_channels == 0) { |
|---|
| 1353 | + stor_device->stor_chns[q_num] = stor_device->device->channel; |
|---|
| 1283 | 1354 | return stor_device->device->channel; |
|---|
| 1355 | + } |
|---|
| 1284 | 1356 | |
|---|
| 1285 | 1357 | hash_qnum = q_num; |
|---|
| 1286 | 1358 | while (hash_qnum >= num_channels) |
|---|
| .. | .. |
|---|
| 1306 | 1378 | struct storvsc_device *stor_device; |
|---|
| 1307 | 1379 | struct vstor_packet *vstor_packet; |
|---|
| 1308 | 1380 | struct vmbus_channel *outgoing_channel, *channel; |
|---|
| 1381 | + unsigned long flags; |
|---|
| 1309 | 1382 | int ret = 0; |
|---|
| 1310 | 1383 | const struct cpumask *node_mask; |
|---|
| 1311 | 1384 | int tgt_cpu; |
|---|
| .. | .. |
|---|
| 1319 | 1392 | |
|---|
| 1320 | 1393 | request->device = device; |
|---|
| 1321 | 1394 | /* |
|---|
| 1322 | | - * Select an an appropriate channel to send the request out. |
|---|
| 1395 | + * Select an appropriate channel to send the request out. |
|---|
| 1323 | 1396 | */ |
|---|
| 1324 | | - if (stor_device->stor_chns[q_num] != NULL) { |
|---|
| 1325 | | - outgoing_channel = stor_device->stor_chns[q_num]; |
|---|
| 1397 | + /* See storvsc_change_target_cpu(). */ |
|---|
| 1398 | + outgoing_channel = READ_ONCE(stor_device->stor_chns[q_num]); |
|---|
| 1399 | + if (outgoing_channel != NULL) { |
|---|
| 1326 | 1400 | if (outgoing_channel->target_cpu == q_num) { |
|---|
| 1327 | 1401 | /* |
|---|
| 1328 | 1402 | * Ideally, we want to pick a different channel if |
|---|
| .. | .. |
|---|
| 1335 | 1409 | continue; |
|---|
| 1336 | 1410 | if (tgt_cpu == q_num) |
|---|
| 1337 | 1411 | continue; |
|---|
| 1338 | | - channel = stor_device->stor_chns[tgt_cpu]; |
|---|
| 1412 | + channel = READ_ONCE( |
|---|
| 1413 | + stor_device->stor_chns[tgt_cpu]); |
|---|
| 1414 | + if (channel == NULL) |
|---|
| 1415 | + continue; |
|---|
| 1339 | 1416 | if (hv_get_avail_to_write_percent( |
|---|
| 1340 | 1417 | &channel->outbound) |
|---|
| 1341 | 1418 | > ring_avail_percent_lowater) { |
|---|
| .. | .. |
|---|
| 1361 | 1438 | for_each_cpu(tgt_cpu, &stor_device->alloced_cpus) { |
|---|
| 1362 | 1439 | if (cpumask_test_cpu(tgt_cpu, node_mask)) |
|---|
| 1363 | 1440 | continue; |
|---|
| 1364 | | - channel = stor_device->stor_chns[tgt_cpu]; |
|---|
| 1441 | + channel = READ_ONCE( |
|---|
| 1442 | + stor_device->stor_chns[tgt_cpu]); |
|---|
| 1443 | + if (channel == NULL) |
|---|
| 1444 | + continue; |
|---|
| 1365 | 1445 | if (hv_get_avail_to_write_percent( |
|---|
| 1366 | 1446 | &channel->outbound) |
|---|
| 1367 | 1447 | > ring_avail_percent_lowater) { |
|---|
| .. | .. |
|---|
| 1371 | 1451 | } |
|---|
| 1372 | 1452 | } |
|---|
| 1373 | 1453 | } else { |
|---|
| 1454 | + spin_lock_irqsave(&stor_device->lock, flags); |
|---|
| 1455 | + outgoing_channel = stor_device->stor_chns[q_num]; |
|---|
| 1456 | + if (outgoing_channel != NULL) { |
|---|
| 1457 | + spin_unlock_irqrestore(&stor_device->lock, flags); |
|---|
| 1458 | + goto found_channel; |
|---|
| 1459 | + } |
|---|
| 1374 | 1460 | outgoing_channel = get_og_chn(stor_device, q_num); |
|---|
| 1461 | + spin_unlock_irqrestore(&stor_device->lock, flags); |
|---|
| 1375 | 1462 | } |
|---|
| 1376 | 1463 | |
|---|
| 1377 | 1464 | found_channel: |
|---|
| .. | .. |
|---|
| 1433 | 1520 | static int storvsc_device_configure(struct scsi_device *sdevice) |
|---|
| 1434 | 1521 | { |
|---|
| 1435 | 1522 | blk_queue_rq_timeout(sdevice->request_queue, (storvsc_timeout * HZ)); |
|---|
| 1436 | | - |
|---|
| 1437 | | - /* Ensure there are no gaps in presented sgls */ |
|---|
| 1438 | | - blk_queue_virt_boundary(sdevice->request_queue, PAGE_SIZE - 1); |
|---|
| 1439 | 1523 | |
|---|
| 1440 | 1524 | sdevice->no_write_same = 1; |
|---|
| 1441 | 1525 | |
|---|
| .. | .. |
|---|
| 1499 | 1583 | |
|---|
| 1500 | 1584 | request = &stor_device->reset_request; |
|---|
| 1501 | 1585 | vstor_packet = &request->vstor_packet; |
|---|
| 1586 | + memset(vstor_packet, 0, sizeof(struct vstor_packet)); |
|---|
| 1502 | 1587 | |
|---|
| 1503 | 1588 | init_completion(&request->wait_event); |
|---|
| 1504 | 1589 | |
|---|
| .. | .. |
|---|
| 1602 | 1687 | /* Setup the cmd request */ |
|---|
| 1603 | 1688 | cmd_request->cmd = scmnd; |
|---|
| 1604 | 1689 | |
|---|
| 1690 | + memset(&cmd_request->vstor_packet, 0, sizeof(struct vstor_packet)); |
|---|
| 1605 | 1691 | vm_srb = &cmd_request->vstor_packet.vm_srb; |
|---|
| 1606 | 1692 | vm_srb->win8_extension.time_out_value = 60; |
|---|
| 1607 | 1693 | |
|---|
| .. | .. |
|---|
| 1657 | 1743 | payload_sz = sizeof(cmd_request->mpb); |
|---|
| 1658 | 1744 | |
|---|
| 1659 | 1745 | if (sg_count) { |
|---|
| 1660 | | - if (sg_count > MAX_PAGE_BUFFER_COUNT) { |
|---|
| 1746 | + unsigned int hvpgoff = 0; |
|---|
| 1747 | + unsigned long offset_in_hvpg = sgl->offset & ~HV_HYP_PAGE_MASK; |
|---|
| 1748 | + unsigned int hvpg_count = HVPFN_UP(offset_in_hvpg + length); |
|---|
| 1749 | + u64 hvpfn; |
|---|
| 1661 | 1750 | |
|---|
| 1662 | | - payload_sz = (sg_count * sizeof(u64) + |
|---|
| 1751 | + if (hvpg_count > MAX_PAGE_BUFFER_COUNT) { |
|---|
| 1752 | + |
|---|
| 1753 | + payload_sz = (hvpg_count * sizeof(u64) + |
|---|
| 1663 | 1754 | sizeof(struct vmbus_packet_mpb_array)); |
|---|
| 1664 | 1755 | payload = kzalloc(payload_sz, GFP_ATOMIC); |
|---|
| 1665 | 1756 | if (!payload) |
|---|
| 1666 | 1757 | return SCSI_MLQUEUE_DEVICE_BUSY; |
|---|
| 1667 | 1758 | } |
|---|
| 1668 | 1759 | |
|---|
| 1760 | + /* |
|---|
| 1761 | + * sgl is a list of PAGEs, and payload->range.pfn_array |
|---|
| 1762 | + * expects the page number in the unit of HV_HYP_PAGE_SIZE (the |
|---|
| 1763 | + * page size that Hyper-V uses, so here we need to divide PAGEs |
|---|
| 1764 | + * into HV_HYP_PAGE in case that PAGE_SIZE > HV_HYP_PAGE_SIZE. |
|---|
| 1765 | + * Besides, payload->range.offset should be the offset in one |
|---|
| 1766 | + * HV_HYP_PAGE. |
|---|
| 1767 | + */ |
|---|
| 1669 | 1768 | payload->range.len = length; |
|---|
| 1670 | | - payload->range.offset = sgl[0].offset; |
|---|
| 1769 | + payload->range.offset = offset_in_hvpg; |
|---|
| 1770 | + hvpgoff = sgl->offset >> HV_HYP_PAGE_SHIFT; |
|---|
| 1671 | 1771 | |
|---|
| 1672 | 1772 | cur_sgl = sgl; |
|---|
| 1673 | | - for (i = 0; i < sg_count; i++) { |
|---|
| 1674 | | - payload->range.pfn_array[i] = |
|---|
| 1675 | | - page_to_pfn(sg_page((cur_sgl))); |
|---|
| 1676 | | - cur_sgl = sg_next(cur_sgl); |
|---|
| 1773 | + for (i = 0; i < hvpg_count; i++) { |
|---|
| 1774 | + /* |
|---|
| 1775 | + * 'i' is the index of hv pages in the payload and |
|---|
| 1776 | + * 'hvpgoff' is the offset (in hv pages) of the first |
|---|
| 1777 | + * hv page in the the first page. The relationship |
|---|
| 1778 | + * between the sum of 'i' and 'hvpgoff' and the offset |
|---|
| 1779 | + * (in hv pages) in a payload page ('hvpgoff_in_page') |
|---|
| 1780 | + * is as follow: |
|---|
| 1781 | + * |
|---|
| 1782 | + * |------------------ PAGE -------------------| |
|---|
| 1783 | + * | NR_HV_HYP_PAGES_IN_PAGE hvpgs in total | |
|---|
| 1784 | + * |hvpg|hvpg| ... |hvpg|... |hvpg| |
|---|
| 1785 | + * ^ ^ ^ ^ |
|---|
| 1786 | + * +-hvpgoff-+ +-hvpgoff_in_page-+ |
|---|
| 1787 | + * ^ | |
|---|
| 1788 | + * +--------------------- i ---------------------------+ |
|---|
| 1789 | + */ |
|---|
| 1790 | + unsigned int hvpgoff_in_page = |
|---|
| 1791 | + (i + hvpgoff) % NR_HV_HYP_PAGES_IN_PAGE; |
|---|
| 1792 | + |
|---|
| 1793 | + /* |
|---|
| 1794 | + * Two cases that we need to fetch a page: |
|---|
| 1795 | + * 1) i == 0, the first step or |
|---|
| 1796 | + * 2) hvpgoff_in_page == 0, when we reach the boundary |
|---|
| 1797 | + * of a page. |
|---|
| 1798 | + */ |
|---|
| 1799 | + if (hvpgoff_in_page == 0 || i == 0) { |
|---|
| 1800 | + hvpfn = page_to_hvpfn(sg_page(cur_sgl)); |
|---|
| 1801 | + cur_sgl = sg_next(cur_sgl); |
|---|
| 1802 | + } |
|---|
| 1803 | + |
|---|
| 1804 | + payload->range.pfn_array[i] = hvpfn + hvpgoff_in_page; |
|---|
| 1677 | 1805 | } |
|---|
| 1678 | 1806 | } |
|---|
| 1679 | 1807 | |
|---|
| .. | .. |
|---|
| 1707 | 1835 | .slave_configure = storvsc_device_configure, |
|---|
| 1708 | 1836 | .cmd_per_lun = 2048, |
|---|
| 1709 | 1837 | .this_id = -1, |
|---|
| 1710 | | - .use_clustering = ENABLE_CLUSTERING, |
|---|
| 1711 | 1838 | /* Make sure we dont get a sg segment crosses a page boundary */ |
|---|
| 1712 | 1839 | .dma_boundary = PAGE_SIZE-1, |
|---|
| 1840 | + /* Ensure there are no gaps in presented sgls */ |
|---|
| 1841 | + .virt_boundary_mask = PAGE_SIZE-1, |
|---|
| 1713 | 1842 | .no_write_same = 1, |
|---|
| 1714 | 1843 | .track_queue_depth = 1, |
|---|
| 1844 | + .change_queue_depth = storvsc_change_queue_depth, |
|---|
| 1715 | 1845 | }; |
|---|
| 1716 | 1846 | |
|---|
| 1717 | 1847 | enum { |
|---|
| .. | .. |
|---|
| 1738 | 1868 | }; |
|---|
| 1739 | 1869 | |
|---|
| 1740 | 1870 | MODULE_DEVICE_TABLE(vmbus, id_table); |
|---|
| 1871 | + |
|---|
| 1872 | +static const struct { guid_t guid; } fc_guid = { HV_SYNTHFC_GUID }; |
|---|
| 1873 | + |
|---|
| 1874 | +static bool hv_dev_is_fc(struct hv_device *hv_dev) |
|---|
| 1875 | +{ |
|---|
| 1876 | + return guid_equal(&fc_guid.guid, &hv_dev->dev_type); |
|---|
| 1877 | +} |
|---|
| 1741 | 1878 | |
|---|
| 1742 | 1879 | static int storvsc_probe(struct hv_device *device, |
|---|
| 1743 | 1880 | const struct hv_vmbus_device_id *dev_id) |
|---|
| .. | .. |
|---|
| 1803 | 1940 | } |
|---|
| 1804 | 1941 | |
|---|
| 1805 | 1942 | stor_device->destroy = false; |
|---|
| 1806 | | - stor_device->open_sub_channel = false; |
|---|
| 1807 | 1943 | init_waitqueue_head(&stor_device->waiting_to_drain); |
|---|
| 1808 | 1944 | stor_device->device = device; |
|---|
| 1809 | 1945 | stor_device->host = host; |
|---|
| 1946 | + spin_lock_init(&stor_device->lock); |
|---|
| 1810 | 1947 | hv_set_drvdata(device, stor_device); |
|---|
| 1811 | 1948 | |
|---|
| 1812 | 1949 | stor_device->port_number = host->host_no; |
|---|
| .. | .. |
|---|
| 1848 | 1985 | */ |
|---|
| 1849 | 1986 | host->sg_tablesize = (stor_device->max_transfer_bytes >> PAGE_SHIFT); |
|---|
| 1850 | 1987 | /* |
|---|
| 1988 | + * For non-IDE disks, the host supports multiple channels. |
|---|
| 1851 | 1989 | * Set the number of HW queues we are supporting. |
|---|
| 1852 | 1990 | */ |
|---|
| 1853 | | - if (stor_device->num_sc != 0) |
|---|
| 1854 | | - host->nr_hw_queues = stor_device->num_sc + 1; |
|---|
| 1991 | + if (!dev_is_ide) |
|---|
| 1992 | + host->nr_hw_queues = num_present_cpus(); |
|---|
| 1855 | 1993 | |
|---|
| 1856 | 1994 | /* |
|---|
| 1857 | 1995 | * Set the error handler work queue. |
|---|
| 1858 | 1996 | */ |
|---|
| 1859 | 1997 | host_dev->handle_error_wq = |
|---|
| 1860 | 1998 | alloc_ordered_workqueue("storvsc_error_wq_%d", |
|---|
| 1861 | | - WQ_MEM_RECLAIM, |
|---|
| 1999 | + 0, |
|---|
| 1862 | 2000 | host->host_no); |
|---|
| 1863 | | - if (!host_dev->handle_error_wq) |
|---|
| 2001 | + if (!host_dev->handle_error_wq) { |
|---|
| 2002 | + ret = -ENOMEM; |
|---|
| 1864 | 2003 | goto err_out2; |
|---|
| 2004 | + } |
|---|
| 1865 | 2005 | INIT_WORK(&host_dev->host_scan_work, storvsc_host_scan); |
|---|
| 1866 | 2006 | /* Register the HBA and start the scsi bus scan */ |
|---|
| 1867 | 2007 | ret = scsi_add_host(host, &device->device); |
|---|
| .. | .. |
|---|
| 1919 | 2059 | return ret; |
|---|
| 1920 | 2060 | } |
|---|
| 1921 | 2061 | |
|---|
| 2062 | +/* Change a scsi target's queue depth */ |
|---|
| 2063 | +static int storvsc_change_queue_depth(struct scsi_device *sdev, int queue_depth) |
|---|
| 2064 | +{ |
|---|
| 2065 | + if (queue_depth > scsi_driver.can_queue) |
|---|
| 2066 | + queue_depth = scsi_driver.can_queue; |
|---|
| 2067 | + |
|---|
| 2068 | + return scsi_change_queue_depth(sdev, queue_depth); |
|---|
| 2069 | +} |
|---|
| 2070 | + |
|---|
| 1922 | 2071 | static int storvsc_remove(struct hv_device *dev) |
|---|
| 1923 | 2072 | { |
|---|
| 1924 | 2073 | struct storvsc_device *stor_device = hv_get_drvdata(dev); |
|---|
| .. | .. |
|---|
| 1939 | 2088 | return 0; |
|---|
| 1940 | 2089 | } |
|---|
| 1941 | 2090 | |
|---|
| 2091 | +static int storvsc_suspend(struct hv_device *hv_dev) |
|---|
| 2092 | +{ |
|---|
| 2093 | + struct storvsc_device *stor_device = hv_get_drvdata(hv_dev); |
|---|
| 2094 | + struct Scsi_Host *host = stor_device->host; |
|---|
| 2095 | + struct hv_host_device *host_dev = shost_priv(host); |
|---|
| 2096 | + |
|---|
| 2097 | + storvsc_wait_to_drain(stor_device); |
|---|
| 2098 | + |
|---|
| 2099 | + drain_workqueue(host_dev->handle_error_wq); |
|---|
| 2100 | + |
|---|
| 2101 | + vmbus_close(hv_dev->channel); |
|---|
| 2102 | + |
|---|
| 2103 | + kfree(stor_device->stor_chns); |
|---|
| 2104 | + stor_device->stor_chns = NULL; |
|---|
| 2105 | + |
|---|
| 2106 | + cpumask_clear(&stor_device->alloced_cpus); |
|---|
| 2107 | + |
|---|
| 2108 | + return 0; |
|---|
| 2109 | +} |
|---|
| 2110 | + |
|---|
| 2111 | +static int storvsc_resume(struct hv_device *hv_dev) |
|---|
| 2112 | +{ |
|---|
| 2113 | + int ret; |
|---|
| 2114 | + |
|---|
| 2115 | + ret = storvsc_connect_to_vsp(hv_dev, storvsc_ringbuffer_size, |
|---|
| 2116 | + hv_dev_is_fc(hv_dev)); |
|---|
| 2117 | + return ret; |
|---|
| 2118 | +} |
|---|
| 2119 | + |
|---|
| 1942 | 2120 | static struct hv_driver storvsc_drv = { |
|---|
| 1943 | 2121 | .name = KBUILD_MODNAME, |
|---|
| 1944 | 2122 | .id_table = id_table, |
|---|
| 1945 | 2123 | .probe = storvsc_probe, |
|---|
| 1946 | 2124 | .remove = storvsc_remove, |
|---|
| 2125 | + .suspend = storvsc_suspend, |
|---|
| 2126 | + .resume = storvsc_resume, |
|---|
| 1947 | 2127 | .driver = { |
|---|
| 1948 | 2128 | .probe_type = PROBE_PREFER_ASYNCHRONOUS, |
|---|
| 1949 | 2129 | }, |
|---|