Index: sys/dev/hyperv/include/vmbus.h =================================================================== --- sys/dev/hyperv/include/vmbus.h +++ sys/dev/hyperv/include/vmbus.h @@ -134,6 +134,8 @@ struct vmbus_channel * vmbus_chan_cpu2chan(struct vmbus_channel *chan, int cpu); void vmbus_chan_set_readbatch(struct vmbus_channel *chan, bool on); +int vmbus_chan_array(struct vmbus_channel *pri_chan, + struct vmbus_channel **chan_array, int array_max_len); struct vmbus_channel ** vmbus_subchan_get(struct vmbus_channel *pri_chan, Index: sys/dev/hyperv/storvsc/hv_storvsc_drv_freebsd.c =================================================================== --- sys/dev/hyperv/storvsc/hv_storvsc_drv_freebsd.c +++ sys/dev/hyperv/storvsc/hv_storvsc_drv_freebsd.c @@ -75,11 +75,10 @@ #include #include - +#include #include "hv_vstorage.h" #include "vmbus_if.h" -#define STORVSC_RINGBUFFER_SIZE (20*PAGE_SIZE) #define STORVSC_MAX_LUNS_PER_TARGET (64) #define STORVSC_MAX_IO_REQUESTS (STORVSC_MAX_LUNS_PER_TARGET * 2) #define BLKVSC_MAX_IDE_DISKS_PER_TARGET (1) @@ -121,8 +120,6 @@ boolean_t is_init; } g_hv_sgl_page_pool; -#define STORVSC_MAX_SG_PAGE_CNT STORVSC_MAX_IO_REQUESTS * STORVSC_DATA_SEGCNT_MAX - enum storvsc_request_type { WRITE_TYPE, READ_TYPE, @@ -132,11 +129,28 @@ SYSCTL_NODE(_hw, OID_AUTO, storvsc, CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "Hyper-V storage interface"); +static u_int hv_storvsc_use_win8ext_flags = 1; +SYSCTL_INT(_hw_storvsc, OID_AUTO, use_win8ext_flags, CTLFLAG_RW, + &hv_storvsc_use_win8ext_flags, 0, + "Use win8 extension flags or not"); + static u_int hv_storvsc_use_pim_unmapped = 1; SYSCTL_INT(_hw_storvsc, OID_AUTO, use_pim_unmapped, CTLFLAG_RDTUN, &hv_storvsc_use_pim_unmapped, 0, "Optimize storvsc by using unmapped I/O"); +static u_int hv_storvsc_ringbuffer_size = (64 * PAGE_SIZE); +SYSCTL_INT(_hw_storvsc, OID_AUTO, ringbuffer_size, CTLFLAG_RDTUN, + &hv_storvsc_ringbuffer_size, 0, "Hyper-V storage ringbuffer size"); + +static u_int hv_storvsc_max_io = 512; +SYSCTL_INT(_hw_storvsc, OID_AUTO, max_io, CTLFLAG_RDTUN, + &hv_storvsc_max_io, 0, "Hyper-V storage max io limit"); + +#define STORVSC_MAX_IO \ + (hv_storvsc_ringbuffer_size - PAGE_SIZE) / \ + MAX_SIZE_BUFRING_ITEM(STORVSC_DATA_SEGCNT_MAX, \ + VSTOR_PKT_SIZE) struct hv_storvsc_sysctl { u_long data_bio_cnt; u_long data_vaddr_cnt; @@ -184,10 +198,18 @@ device_t hs_dev; bus_dma_tag_t storvsc_req_dtag; struct hv_storvsc_sysctl sysctl_data; - - struct vmbus_channel *hs_cpu2chan[MAXCPU]; + uint32_t hs_nchan; + struct vmbus_channel *hs_lun2chan[MAXCPU]; }; +/* + * The size of the vmscsi_request has changed in win8. The + * additional size is for the newly added elements in the + * structure. These elements are valid only when we are talking + * to a win8 host. + * Track the correct size we need to apply. + */ +static int vmscsi_size_delta = sizeof(struct vmscsi_win8_extension); /** * HyperV storvsc timeout testing cases: @@ -211,7 +233,7 @@ char *drv_name; char *drv_desc; uint8_t drv_max_luns_per_target; - uint8_t drv_max_ios_per_target; + uint32_t drv_max_ios_per_target; uint32_t drv_ringbuffer_size; }; @@ -240,10 +262,10 @@ static struct storvsc_driver_props g_drv_props_table[] = { {"blkvsc", "Hyper-V IDE Storage Interface", BLKVSC_MAX_IDE_DISKS_PER_TARGET, BLKVSC_MAX_IO_REQUESTS, - STORVSC_RINGBUFFER_SIZE}, + 20*PAGE_SIZE}, {"storvsc", "Hyper-V SCSI Storage Interface", STORVSC_MAX_LUNS_PER_TARGET, STORVSC_MAX_IO_REQUESTS, - STORVSC_RINGBUFFER_SIZE} + 20*PAGE_SIZE} }; /* @@ -253,14 +275,6 @@ static int sense_buffer_size = PRE_WIN8_STORVSC_SENSE_BUFFER_SIZE; /* - * The size of the vmscsi_request has changed in win8. The - * additional size is for the newly added elements in the - * structure. These elements are valid only when we are talking - * to a win8 host. - * Track the correct size we need to apply. - */ -static int vmscsi_size_delta; -/* * The storage protocol version is determined during the * initial exchange with the host. It will indicate which * storage functionality is available in the host. @@ -687,6 +701,7 @@ struct vstor_packet *vstor_packet = &request->vstor_packet; struct vmbus_channel* outgoing_channel = NULL; int ret = 0; + int ch_sel; vstor_packet->flags |= REQUEST_COMPLETION_FLAG; @@ -699,7 +714,8 @@ vstor_packet->operation = VSTOR_OPERATION_EXECUTESRB; - outgoing_channel = sc->hs_cpu2chan[curcpu]; + ch_sel = vstor_packet->u.vm_srb.lun + curcpu; + outgoing_channel = sc->hs_lun2chan[ch_sel % sc->hs_nchan]; mtx_unlock(&request->softc->hs_lock); if (request->prp_list.gpa_range.gpa_len) { @@ -906,17 +922,10 @@ } static void -storvsc_create_cpu2chan(struct storvsc_softc *sc) +storvsc_create_lun2chan(struct storvsc_softc *sc) { - int cpu; - - CPU_FOREACH(cpu) { - sc->hs_cpu2chan[cpu] = vmbus_chan_cpu2chan(sc->hs_chan, cpu); - if (bootverbose) { - device_printf(sc->hs_dev, "cpu%d -> chan%u\n", - cpu, vmbus_chan_id(sc->hs_cpu2chan[cpu])); - } - } + int nchan = vmbus_chan_array(sc->hs_chan, sc->hs_lun2chan, MAXCPU); + sc->hs_nchan = nchan; } static int @@ -1029,7 +1038,15 @@ /* fill in driver specific properties */ sc->hs_drv_props = &g_drv_props_table[stor_type]; - + sc->hs_drv_props->drv_ringbuffer_size = hv_storvsc_ringbuffer_size; + sc->hs_drv_props->drv_max_ios_per_target = + STORVSC_MAX_IO > hv_storvsc_max_io ? + hv_storvsc_max_io : STORVSC_MAX_IO; + if (bootverbose) { + printf("storvsc ringbuffer size: %d, max_io: %d\n", + sc->hs_drv_props->drv_ringbuffer_size, + sc->hs_drv_props->drv_max_ios_per_target); + } /* fill in device specific properties */ sc->hs_unit = device_get_unit(dev); sc->hs_dev = dev; @@ -1051,7 +1068,7 @@ * STORVSC_DATA_SEGCNT_MAX segments, each * segment has one page buffer */ - for (i = 0; i < STORVSC_MAX_IO_REQUESTS; i++) { + for (i = 0; i < sc->hs_drv_props->drv_max_ios_per_target; i++) { sgl_node = malloc(sizeof(struct hv_sgl_node), M_DEVBUF, M_WAITOK|M_ZERO); @@ -1082,7 +1099,7 @@ } /* Construct cpu to channel mapping */ - storvsc_create_cpu2chan(sc); + storvsc_create_lun2chan(sc); /* * Create the device queue. @@ -1839,18 +1856,39 @@ csio->cdb_len); } + if (hv_storvsc_use_win8ext_flags) { + reqp->vstor_packet.u.vm_srb.win8_extension.time_out_value = 60; + reqp->vstor_packet.u.vm_srb.win8_extension.srb_flags |= + SRB_FLAGS_DISABLE_SYNCH_TRANSFER; + } switch (ccb->ccb_h.flags & CAM_DIR_MASK) { case CAM_DIR_OUT: - reqp->vstor_packet.u.vm_srb.data_in = WRITE_TYPE; + reqp->vstor_packet.u.vm_srb.data_in = WRITE_TYPE; + if (hv_storvsc_use_win8ext_flags) { + reqp->vstor_packet.u.vm_srb.win8_extension.srb_flags |= + SRB_FLAGS_DATA_OUT; + } break; case CAM_DIR_IN: reqp->vstor_packet.u.vm_srb.data_in = READ_TYPE; + if (hv_storvsc_use_win8ext_flags) { + reqp->vstor_packet.u.vm_srb.win8_extension.srb_flags |= + SRB_FLAGS_DATA_IN; + } break; case CAM_DIR_NONE: reqp->vstor_packet.u.vm_srb.data_in = UNKNOWN_TYPE; + if (hv_storvsc_use_win8ext_flags) { + reqp->vstor_packet.u.vm_srb.win8_extension.srb_flags |= + SRB_FLAGS_DATA_IN; + } break; default: reqp->vstor_packet.u.vm_srb.data_in = UNKNOWN_TYPE; + if (hv_storvsc_use_win8ext_flags) { + reqp->vstor_packet.u.vm_srb.win8_extension.srb_flags |= + SRB_FLAGS_DATA_IN; + } break; } Index: sys/dev/hyperv/storvsc/hv_vstorage.h =================================================================== --- sys/dev/hyperv/storvsc/hv_vstorage.h +++ sys/dev/hyperv/storvsc/hv_vstorage.h @@ -253,6 +253,22 @@ #define SRB_STATUS_AUTOSENSE_VALID 0x80 #define SRB_STATUS_INVALID_LUN 0X20 +/* + * SRB Flag Bits + */ + +#define SRB_FLAGS_QUEUE_ACTION_ENABLE 0x00000002 +#define SRB_FLAGS_DISABLE_DISCONNECT 0x00000004 +#define SRB_FLAGS_DISABLE_SYNCH_TRANSFER 0x00000008 +#define SRB_FLAGS_BYPASS_FROZEN_QUEUE 0x00000010 +#define SRB_FLAGS_DISABLE_AUTOSENSE 0x00000020 +#define SRB_FLAGS_DATA_IN 0x00000040 +#define SRB_FLAGS_DATA_OUT 0x00000080 +#define SRB_FLAGS_NO_DATA_TRANSFER 0x00000000 +#define SRB_FLAGS_UNSPECIFIED_DIRECTION (SRB_FLAGS_DATA_IN | SRB_FLAGS_DATA_OUT) +#define SRB_FLAGS_NO_QUEUE_FREEZE 0x00000100 +#define SRB_FLAGS_ADAPTER_CACHE_ENABLE 0x00000200 +#define SRB_FLAGS_FREE_SENSE_BUFFER 0x00000400 /** * Packet flags */ Index: sys/dev/hyperv/vmbus/vmbus_chan.c =================================================================== --- sys/dev/hyperv/vmbus/vmbus_chan.c +++ sys/dev/hyperv/vmbus/vmbus_chan.c @@ -173,6 +173,9 @@ SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(chid_tree), OID_AUTO, "cpu", CTLFLAG_RD, &chan->ch_cpuid, 0, "owner CPU id"); + SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(chid_tree), OID_AUTO, + "send", CTLFLAG_RD, &chan->ch_stat_send_nreq, 0, + "requests sent from this channel"); SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(chid_tree), OID_AUTO, "mnf", CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, chan, 0, vmbus_chan_sysctl_mnf, "I", @@ -629,6 +632,10 @@ error = vmbus_txbr_write(&chan->ch_txbr, iov, 3, &send_evt); if (!error && send_evt) vmbus_chan_signal_tx(chan); + // statistc for this channel + if (!error) { + chan->ch_stat_send_nreq++; + } return error; } @@ -668,6 +675,10 @@ error = vmbus_txbr_write(&chan->ch_txbr, iov, 4, &send_evt); if (!error && send_evt) vmbus_chan_signal_tx(chan); + // statistc for this channel + if (!error) { + chan->ch_stat_send_nreq++; + } return error; } @@ -709,6 +720,10 @@ error = vmbus_txbr_write(&chan->ch_txbr, iov, 4, &send_evt); if (!error && send_evt) vmbus_chan_signal_tx(chan); + // statistc for this channel + if (!error) { + chan->ch_stat_send_nreq++; + } return error; } @@ -1314,6 +1329,30 @@ return sel; } +int +vmbus_chan_array(struct vmbus_channel *pri_chan, + struct vmbus_channel **chan_array, int array_max_len) +{ + struct vmbus_channel *chan; + int nchan = 0; + chan_array[nchan++] = pri_chan; + + if (TAILQ_EMPTY(&pri_chan->ch_subchans)) { + return nchan; + } + mtx_lock(&pri_chan->ch_subchan_lock); + TAILQ_FOREACH(chan, &pri_chan->ch_subchans, ch_sublink) { + KASSERT(chan->ch_stflags & VMBUS_CHAN_ST_OPENED, + ("chan%u is not opened", chan->ch_id)); + KASSERT(nchan + 1 < array_max_len, + ("channel array's capacity %d is reached\n", + array_max_len)); + chan_array[nchan++] = chan; + } + mtx_unlock(&pri_chan->ch_subchan_lock); + return nchan; +} + struct vmbus_channel ** vmbus_subchan_get(struct vmbus_channel *pri_chan, int subchan_cnt) { Index: sys/dev/hyperv/vmbus/vmbus_chanvar.h =================================================================== --- sys/dev/hyperv/vmbus/vmbus_chanvar.h +++ sys/dev/hyperv/vmbus/vmbus_chanvar.h @@ -89,7 +89,7 @@ volatile u_long *ch_evtflag; /* event flag loc. */ /* - * Rarely used fields. + * Rarepy used fields. */ struct hyperv_mon_param *ch_monprm; @@ -133,6 +133,7 @@ struct hyperv_guid ch_guid_inst; struct sysctl_ctx_list ch_sysctl_ctx; + u_int ch_stat_send_nreq; } __aligned(CACHE_LINE_SIZE); #define VMBUS_CHAN_ISPRIMARY(chan) ((chan)->ch_subidx == 0) Index: sys/dev/hyperv/vmbus/vmbus_reg.h =================================================================== --- sys/dev/hyperv/vmbus/vmbus_reg.h +++ sys/dev/hyperv/vmbus/vmbus_reg.h @@ -171,6 +171,10 @@ struct vmbus_gpa_range cp_range[]; } __packed; +#define MAX_SIZE_BUFRING_ITEM(GPA_PAGE_CNT, SRB_SIZE) \ + (roundup2(__offsetof(struct vmbus_chanpkt_prplist, \ + cp_range[0].gpa_page[GPA_PAGE_CNT]) + SRB_SIZE, \ + VMBUS_CHANPKT_SIZE_ALIGN) + sizeof(uint64_t)) /* * Channel messages * - Embedded in vmbus_message.msg_data, e.g. response and notification.