Index: sys/dev/hyperv/include/hyperv.h =================================================================== --- sys/dev/hyperv/include/hyperv.h +++ sys/dev/hyperv/include/hyperv.h @@ -82,18 +82,6 @@ #define VMBUS_VERSION_MAJOR(ver) (((uint32_t)(ver)) >> 16) #define VMBUS_VERSION_MINOR(ver) (((uint32_t)(ver)) & 0xffff) -#define HV_MAX_MULTIPAGE_BUFFER_COUNT 32 - -#define HV_ALIGN_UP(value, align) \ - (((value) & (align-1)) ? \ - (((value) + (align-1)) & ~(align-1) ) : (value)) - -#define HV_ALIGN_DOWN(value, align) ( (value) & ~(align-1) ) - -#define HV_NUM_PAGES_SPANNED(addr, len) \ - ((HV_ALIGN_UP(addr+len, PAGE_SIZE) - \ - HV_ALIGN_DOWN(addr, PAGE_SIZE)) >> PAGE_SHIFT ) - struct hyperv_guid { uint8_t hv_guid[16]; } __packed; @@ -224,12 +212,6 @@ } __packed hv_vmbus_ring_buffer; typedef struct { - int length; - int offset; - uint64_t pfn_array[HV_MAX_MULTIPAGE_BUFFER_COUNT]; -} __packed hv_vmbus_multipage_buffer; - -typedef struct { hv_vmbus_ring_buffer* ring_buffer; struct mtx ring_lock; uint32_t ring_data_size; /* ring_size */ @@ -368,13 +350,6 @@ hv_vmbus_packet_type type, uint32_t flags); -int hv_vmbus_channel_send_packet_multipagebuffer( - hv_vmbus_channel* channel, - hv_vmbus_multipage_buffer* multi_page_buffer, - void* buffer, - uint32_t buffer_len, - uint64_t request_id); - int hv_vmbus_channel_establish_gpadl( hv_vmbus_channel* channel, /* must be phys and virt contiguous */ Index: sys/dev/hyperv/include/vmbus.h =================================================================== --- sys/dev/hyperv/include/vmbus.h +++ sys/dev/hyperv/include/vmbus.h @@ -31,6 +31,15 @@ #include +/* + * GPA stuffs. + */ +struct vmbus_gpa_range { + uint32_t gpa_len; + uint32_t gpa_ofs; + uint64_t gpa_page[0]; +} __packed; + /* This is actually vmbus_gpa_range.gpa_page[1] */ struct vmbus_gpa { uint32_t gpa_len; @@ -39,11 +48,15 @@ } __packed; #define VMBUS_CHAN_SGLIST_MAX 32 +#define VMBUS_CHAN_PRPLIST_MAX 32 struct hv_vmbus_channel; int vmbus_chan_send_sglist(struct hv_vmbus_channel *chan, struct vmbus_gpa sg[], int sglen, void *data, int dlen, uint64_t xactid); +int vmbus_chan_send_prplist(struct hv_vmbus_channel *chan, + struct vmbus_gpa_range *prp, int prp_cnt, void *data, int dlen, + uint64_t xactid); #endif /* !_VMBUS_H_ */ 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 @@ -72,6 +72,7 @@ #include #include +#include #include "hv_vstorage.h" #include "vmbus_if.h" @@ -100,7 +101,7 @@ boolean_t is_init; } g_hv_sgl_page_pool; -#define STORVSC_MAX_SG_PAGE_CNT STORVSC_MAX_IO_REQUESTS * HV_MAX_MULTIPAGE_BUFFER_COUNT +#define STORVSC_MAX_SG_PAGE_CNT STORVSC_MAX_IO_REQUESTS * VMBUS_CHAN_PRPLIST_MAX enum storvsc_request_type { WRITE_TYPE, @@ -108,10 +109,16 @@ UNKNOWN_TYPE }; +struct hvs_gpa_range { + struct vmbus_gpa_range gpa_range; + uint64_t gpa_page[VMBUS_CHAN_PRPLIST_MAX]; +} __packed; + struct hv_storvsc_request { LIST_ENTRY(hv_storvsc_request) link; struct vstor_packet vstor_packet; - hv_vmbus_multipage_buffer data_buf; + int prp_cnt; + struct hvs_gpa_range prp_list; void *sense_data; uint8_t sense_info_len; uint8_t retries; @@ -674,21 +681,18 @@ vstor_packet->u.vm_srb.sense_info_len = sense_buffer_size; - vstor_packet->u.vm_srb.transfer_len = request->data_buf.length; + vstor_packet->u.vm_srb.transfer_len = + request->prp_list.gpa_range.gpa_len; vstor_packet->operation = VSTOR_OPERATION_EXECUTESRB; outgoing_channel = vmbus_select_outgoing_channel(sc->hs_chan); mtx_unlock(&request->softc->hs_lock); - if (request->data_buf.length) { - ret = hv_vmbus_channel_send_packet_multipagebuffer( - outgoing_channel, - &request->data_buf, - vstor_packet, - VSTOR_PKT_SIZE, - (uint64_t)(uintptr_t)request); - + if (request->prp_list.gpa_range.gpa_len) { + ret = vmbus_chan_send_prplist(outgoing_channel, + &request->prp_list.gpa_range, request->prp_cnt, + vstor_packet, VSTOR_PKT_SIZE, (uint64_t)(uintptr_t)request); } else { ret = hv_vmbus_channel_send_packet( outgoing_channel, @@ -947,7 +951,7 @@ /* * Pre-create SG list, each SG list with - * HV_MAX_MULTIPAGE_BUFFER_COUNT segments, each + * VMBUS_CHAN_PRPLIST_MAX segments, each * segment has one page buffer */ for (i = 0; i < STORVSC_MAX_IO_REQUESTS; i++) { @@ -955,10 +959,10 @@ M_DEVBUF, M_WAITOK|M_ZERO); sgl_node->sgl_data = - sglist_alloc(HV_MAX_MULTIPAGE_BUFFER_COUNT, + sglist_alloc(VMBUS_CHAN_PRPLIST_MAX, M_WAITOK|M_ZERO); - for (j = 0; j < HV_MAX_MULTIPAGE_BUFFER_COUNT; j++) { + for (j = 0; j < VMBUS_CHAN_PRPLIST_MAX; j++) { tmp_buff = malloc(PAGE_SIZE, M_DEVBUF, M_WAITOK|M_ZERO); @@ -1045,7 +1049,7 @@ while (!LIST_EMPTY(&g_hv_sgl_page_pool.free_sgl_list)) { sgl_node = LIST_FIRST(&g_hv_sgl_page_pool.free_sgl_list); LIST_REMOVE(sgl_node, link); - for (j = 0; j < HV_MAX_MULTIPAGE_BUFFER_COUNT; j++) { + for (j = 0; j < VMBUS_CHAN_PRPLIST_MAX; j++) { if (NULL != (void*)sgl_node->sgl_data->sg_segs[j].ss_paddr) { free((void*)sgl_node->sgl_data->sg_segs[j].ss_paddr, M_DEVBUF); @@ -1108,7 +1112,7 @@ while (!LIST_EMPTY(&g_hv_sgl_page_pool.free_sgl_list)) { sgl_node = LIST_FIRST(&g_hv_sgl_page_pool.free_sgl_list); LIST_REMOVE(sgl_node, link); - for (j = 0; j < HV_MAX_MULTIPAGE_BUFFER_COUNT; j++){ + for (j = 0; j < VMBUS_CHAN_PRPLIST_MAX; j++){ if (NULL != (void*)sgl_node->sgl_data->sg_segs[j].ss_paddr) { free((void*)sgl_node->sgl_data->sg_segs[j].ss_paddr, M_DEVBUF); @@ -1659,6 +1663,7 @@ uint32_t pfn_num = 0; uint32_t pfn; uint64_t not_aligned_seg_bits = 0; + struct hvs_gpa_range *prplist; /* refer to struct vmscsi_req for meanings of these two fields */ reqp->vstor_packet.u.vm_srb.port = @@ -1702,22 +1707,23 @@ return (0); } - reqp->data_buf.length = csio->dxfer_len; + prplist = &reqp->prp_list; + prplist->gpa_range.gpa_len = csio->dxfer_len; switch (ccb->ccb_h.flags & CAM_DATA_MASK) { case CAM_DATA_VADDR: { bytes_to_copy = csio->dxfer_len; phys_addr = vtophys(csio->data_ptr); - reqp->data_buf.offset = phys_addr & PAGE_MASK; + prplist->gpa_range.gpa_ofs = phys_addr & PAGE_MASK; while (bytes_to_copy != 0) { int bytes, page_offset; phys_addr = - vtophys(&csio->data_ptr[reqp->data_buf.length - + vtophys(&csio->data_ptr[prplist->gpa_range.gpa_len - bytes_to_copy]); pfn = phys_addr >> PAGE_SHIFT; - reqp->data_buf.pfn_array[pfn_num] = pfn; + prplist->gpa_page[pfn_num] = pfn; page_offset = phys_addr & PAGE_MASK; bytes = min(PAGE_SIZE - page_offset, bytes_to_copy); @@ -1725,6 +1731,7 @@ bytes_to_copy -= bytes; pfn_num++; } + reqp->prp_cnt = pfn_num; break; } @@ -1741,10 +1748,10 @@ printf("Storvsc: get SG I/O operation, %d\n", reqp->vstor_packet.u.vm_srb.data_in); - if (storvsc_sg_count > HV_MAX_MULTIPAGE_BUFFER_COUNT){ + if (storvsc_sg_count > VMBUS_CHAN_PRPLIST_MAX){ printf("Storvsc: %d segments is too much, " "only support %d segments\n", - storvsc_sg_count, HV_MAX_MULTIPAGE_BUFFER_COUNT); + storvsc_sg_count, VMBUS_CHAN_PRPLIST_MAX); return (EINVAL); } @@ -1797,10 +1804,10 @@ phys_addr = vtophys(storvsc_sglist[0].ds_addr); } - reqp->data_buf.offset = phys_addr & PAGE_MASK; + prplist->gpa_range.gpa_ofs = phys_addr & PAGE_MASK; pfn = phys_addr >> PAGE_SHIFT; - reqp->data_buf.pfn_array[0] = pfn; + prplist->gpa_page[0] = pfn; for (i = 1; i < storvsc_sg_count; i++) { if (reqp->not_aligned_seg_bits & (1 << i)) { @@ -1812,27 +1819,31 @@ } pfn = phys_addr >> PAGE_SHIFT; - reqp->data_buf.pfn_array[i] = pfn; + prplist->gpa_page[i] = pfn; } + reqp->prp_cnt = i; } else { phys_addr = vtophys(storvsc_sglist[0].ds_addr); - reqp->data_buf.offset = phys_addr & PAGE_MASK; + prplist->gpa_range.gpa_ofs = phys_addr & PAGE_MASK; for (i = 0; i < storvsc_sg_count; i++) { phys_addr = vtophys(storvsc_sglist[i].ds_addr); pfn = phys_addr >> PAGE_SHIFT; - reqp->data_buf.pfn_array[i] = pfn; + prplist->gpa_page[i] = pfn; } + reqp->prp_cnt = i; /* check the last segment cross boundary or not */ offset = phys_addr & PAGE_MASK; if (offset) { + /* Add one more PRP entry */ phys_addr = vtophys(storvsc_sglist[i-1].ds_addr + PAGE_SIZE - offset); pfn = phys_addr >> PAGE_SHIFT; - reqp->data_buf.pfn_array[i] = pfn; + prplist->gpa_page[i] = pfn; + reqp->prp_cnt++; } reqp->bounce_sgl_count = 0; Index: sys/dev/hyperv/vmbus/hv_channel.c =================================================================== --- sys/dev/hyperv/vmbus/hv_channel.c +++ sys/dev/hyperv/vmbus/hv_channel.c @@ -712,78 +712,46 @@ return error; } -/** - * @brief Send a multi-page buffer packet using a GPADL Direct packet type - */ int -hv_vmbus_channel_send_packet_multipagebuffer( - hv_vmbus_channel* channel, - hv_vmbus_multipage_buffer* multi_page_buffer, - void* buffer, - uint32_t buffer_len, - uint64_t request_id) +vmbus_chan_send_prplist(struct hv_vmbus_channel *chan, + struct vmbus_gpa_range *prp, int prp_cnt, void *data, int dlen, + uint64_t xactid) { + struct vmbus_chanpkt_prplist pkt; + int pktlen, pad_pktlen, hlen, error; + struct iovec iov[4]; + boolean_t send_evt; + uint64_t pad = 0; - int ret = 0; - uint32_t desc_size; - boolean_t need_sig; - uint32_t packet_len; - uint32_t packet_len_aligned; - uint32_t pfn_count; - uint64_t aligned_data = 0; - struct iovec iov[3]; - hv_vmbus_channel_packet_multipage_buffer desc; - - pfn_count = - HV_NUM_PAGES_SPANNED( - multi_page_buffer->offset, - multi_page_buffer->length); - - if ((pfn_count == 0) || (pfn_count > HV_MAX_MULTIPAGE_BUFFER_COUNT)) - return (EINVAL); - /* - * Adjust the size down since hv_vmbus_channel_packet_multipage_buffer - * is the largest size we support - */ - desc_size = - sizeof(hv_vmbus_channel_packet_multipage_buffer) - - ((HV_MAX_MULTIPAGE_BUFFER_COUNT - pfn_count) * - sizeof(uint64_t)); - packet_len = desc_size + buffer_len; - packet_len_aligned = HV_ALIGN_UP(packet_len, sizeof(uint64_t)); - - /* - * Setup the descriptor - */ - desc.type = HV_VMBUS_PACKET_TYPE_DATA_USING_GPA_DIRECT; - desc.flags = HV_VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED; - desc.data_offset8 = desc_size >> 3; /* in 8-bytes granularity */ - desc.length8 = (uint16_t) (packet_len_aligned >> 3); - desc.transaction_id = request_id; - desc.range_count = 1; - - desc.range.length = multi_page_buffer->length; - desc.range.offset = multi_page_buffer->offset; - - memcpy(desc.range.pfn_array, multi_page_buffer->pfn_array, - pfn_count * sizeof(uint64_t)); - - iov[0].iov_base = &desc; - iov[0].iov_len = desc_size; - - iov[1].iov_base = buffer; - iov[1].iov_len = buffer_len; + KASSERT(prp_cnt < VMBUS_CHAN_PRPLIST_MAX, + ("invalid prplist entry count %d", prp_cnt)); - iov[2].iov_base = &aligned_data; - iov[2].iov_len = packet_len_aligned - packet_len; + hlen = __offsetof(struct vmbus_chanpkt_prplist, + cp_range[0].gpa_page[prp_cnt]); + pktlen = hlen + dlen; + pad_pktlen = roundup2(pktlen, VMBUS_CHANPKT_SIZE_ALIGN); - ret = hv_ring_buffer_write(&channel->outbound, iov, 3, &need_sig); + pkt.cp_hdr.cph_type = HV_VMBUS_PACKET_TYPE_DATA_USING_GPA_DIRECT; + pkt.cp_hdr.cph_flags = HV_VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED; + pkt.cp_hdr.cph_data_ofs = hlen >> VMBUS_CHANPKT_SIZE_SHIFT; + pkt.cp_hdr.cph_len = pad_pktlen >> VMBUS_CHANPKT_SIZE_SHIFT; + pkt.cp_hdr.cph_xactid = xactid; + pkt.cp_rsvd = 0; + pkt.cp_range_cnt = 1; - /* TODO: We should determine if this is optional */ - if (ret == 0 && need_sig) - vmbus_chan_send_event(channel); + iov[0].iov_base = &pkt; + iov[0].iov_len = sizeof(pkt); + iov[1].iov_base = prp; + iov[1].iov_len = __offsetof(struct vmbus_gpa_range, gpa_page[prp_cnt]); + iov[2].iov_base = data; + iov[2].iov_len = dlen; + iov[3].iov_base = &pad; + iov[3].iov_len = pad_pktlen - pktlen; - return (ret); + error = hv_ring_buffer_write(&chan->outbound, iov, 4, &send_evt); + if (!error && send_evt) + vmbus_chan_send_event(chan); + return error; } /** Index: sys/dev/hyperv/vmbus/hv_vmbus_priv.h =================================================================== --- sys/dev/hyperv/vmbus/hv_vmbus_priv.h +++ sys/dev/hyperv/vmbus/hv_vmbus_priv.h @@ -42,20 +42,6 @@ struct vmbus_softc; /* - * The format must be the same as hv_vm_data_gpa_direct - */ -typedef struct hv_vmbus_channel_packet_multipage_buffer { - uint16_t type; - uint16_t data_offset8; - uint16_t length8; - uint16_t flags; - uint64_t transaction_id; - uint32_t reserved; - uint32_t range_count; /* Always 1 in this case */ - hv_vmbus_multipage_buffer range; -} __packed hv_vmbus_channel_packet_multipage_buffer; - -/* * Private, VM Bus functions */ struct sysctl_ctx_list; Index: sys/dev/hyperv/vmbus/vmbus_reg.h =================================================================== --- sys/dev/hyperv/vmbus/vmbus_reg.h +++ sys/dev/hyperv/vmbus/vmbus_reg.h @@ -109,15 +109,6 @@ #define VMBUS_CHAN_MAX (VMBUS_EVTFLAG_LEN * VMBUS_EVTFLAGS_MAX) /* - * GPA range. - */ -struct vmbus_gpa_range { - uint32_t gpa_len; - uint32_t gpa_ofs; - uint64_t gpa_page[]; -} __packed; - -/* * Channel packets */ @@ -143,6 +134,13 @@ struct vmbus_gpa cp_gpa[]; } __packed; +struct vmbus_chanpkt_prplist { + struct vmbus_chanpkt_hdr cp_hdr; + uint32_t cp_rsvd; + uint32_t cp_range_cnt; + struct vmbus_gpa_range cp_range[]; +} __packed; + /* * Channel messages * - Embedded in vmbus_message.msg_data, e.g. response and notification.