1 /*- 2 * Copyright (c) 2009-2012,2016 Microsoft Corp. 3 * Copyright (c) 2010-2012 Citrix Inc. 4 * Copyright (c) 2012 NetApp Inc. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice unmodified, this list of conditions, and the following 12 * disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 /* 30 * Network Virtualization Service. 31 */ 32 33 #include <sys/cdefs.h> 34 __FBSDID("$FreeBSD$"); 35 36 #include "opt_inet6.h" 37 #include "opt_inet.h" 38 39 #include <sys/param.h> 40 #include <sys/kernel.h> 41 #include <sys/limits.h> 42 #include <sys/socket.h> 43 #include <sys/systm.h> 44 #include <sys/taskqueue.h> 45 46 #include <net/if.h> 47 #include <net/if_var.h> 48 #include <net/if_media.h> 49 50 #include <netinet/in.h> 51 #include <netinet/tcp_lro.h> 52 53 #include <dev/hyperv/include/hyperv.h> 54 #include <dev/hyperv/include/hyperv_busdma.h> 55 #include <dev/hyperv/include/vmbus.h> 56 #include <dev/hyperv/include/vmbus_xact.h> 57 58 #include <dev/hyperv/netvsc/ndis.h> 59 #include <dev/hyperv/netvsc/if_hnreg.h> 60 #include <dev/hyperv/netvsc/if_hnvar.h> 61 #include <dev/hyperv/netvsc/hn_nvs.h> 62 63 static int hn_nvs_conn_chim(struct hn_softc *); 64 static int hn_nvs_conn_rxbuf(struct hn_softc *); 65 static int hn_nvs_disconn_chim(struct hn_softc *); 66 static int hn_nvs_disconn_rxbuf(struct hn_softc *); 67 static int hn_nvs_conf_ndis(struct hn_softc *, int); 68 static int hn_nvs_init_ndis(struct hn_softc *); 69 static int hn_nvs_doinit(struct hn_softc *, uint32_t); 70 static int hn_nvs_init(struct hn_softc *); 71 static const void *hn_nvs_xact_execute(struct hn_softc *, 72 struct vmbus_xact *, void *, int, 73 size_t *, uint32_t); 74 static void hn_nvs_sent_none(struct hn_nvs_sendctx *, 75 struct hn_softc *, struct vmbus_channel *, 76 const void *, int); 77 78 struct hn_nvs_sendctx hn_nvs_sendctx_none = 79 HN_NVS_SENDCTX_INITIALIZER(hn_nvs_sent_none, NULL); 80 81 static const uint32_t hn_nvs_version[] = { 82 HN_NVS_VERSION_5, 83 HN_NVS_VERSION_4, 84 HN_NVS_VERSION_2, 85 HN_NVS_VERSION_1 86 }; 87 88 static const void * 89 hn_nvs_xact_execute(struct hn_softc *sc, struct vmbus_xact *xact, 90 void *req, int reqlen, size_t *resplen0, uint32_t type) 91 { 92 struct hn_nvs_sendctx sndc; 93 size_t resplen, min_resplen = *resplen0; 94 const struct hn_nvs_hdr *hdr; 95 int error; 96 97 KASSERT(min_resplen >= sizeof(*hdr), 98 ("invalid minimum response len %zu", min_resplen)); 99 100 /* 101 * Execute the xact setup by the caller. 102 */ 103 hn_nvs_sendctx_init(&sndc, hn_nvs_sent_xact, xact); 104 105 vmbus_xact_activate(xact); 106 error = hn_nvs_send(sc->hn_prichan, VMBUS_CHANPKT_FLAG_RC, 107 req, reqlen, &sndc); 108 if (error) { 109 vmbus_xact_deactivate(xact); 110 return (NULL); 111 } 112 hdr = vmbus_xact_wait(xact, &resplen); 113 114 /* 115 * Check this NVS response message. 116 */ 117 if (resplen < min_resplen) { 118 if_printf(sc->hn_ifp, "invalid NVS resp len %zu\n", resplen); 119 return (NULL); 120 } 121 if (hdr->nvs_type != type) { 122 if_printf(sc->hn_ifp, "unexpected NVS resp 0x%08x, " 123 "expect 0x%08x\n", hdr->nvs_type, type); 124 return (NULL); 125 } 126 /* All pass! */ 127 *resplen0 = resplen; 128 return (hdr); 129 } 130 131 static __inline int 132 hn_nvs_req_send(struct hn_softc *sc, void *req, int reqlen) 133 { 134 135 return (hn_nvs_send(sc->hn_prichan, VMBUS_CHANPKT_FLAG_NONE, 136 req, reqlen, &hn_nvs_sendctx_none)); 137 } 138 139 static int 140 hn_nvs_conn_rxbuf(struct hn_softc *sc) 141 { 142 struct vmbus_xact *xact = NULL; 143 struct hn_nvs_rxbuf_conn *conn; 144 const struct hn_nvs_rxbuf_connresp *resp; 145 size_t resp_len; 146 uint32_t status; 147 int error, rxbuf_size; 148 149 /* 150 * Limit RXBUF size for old NVS. 151 */ 152 if (sc->hn_nvs_ver <= HN_NVS_VERSION_2) 153 rxbuf_size = HN_RXBUF_SIZE_COMPAT; 154 else 155 rxbuf_size = HN_RXBUF_SIZE; 156 157 /* 158 * Connect the RXBUF GPADL to the primary channel. 159 * 160 * NOTE: 161 * Only primary channel has RXBUF connected to it. Sub-channels 162 * just share this RXBUF. 163 */ 164 error = vmbus_chan_gpadl_connect(sc->hn_prichan, 165 sc->hn_rxbuf_dma.hv_paddr, rxbuf_size, &sc->hn_rxbuf_gpadl); 166 if (error) { 167 if_printf(sc->hn_ifp, "rxbuf gpadl conn failed: %d\n", 168 error); 169 goto cleanup; 170 } 171 172 /* 173 * Connect RXBUF to NVS. 174 */ 175 176 xact = vmbus_xact_get(sc->hn_xact, sizeof(*conn)); 177 if (xact == NULL) { 178 if_printf(sc->hn_ifp, "no xact for nvs rxbuf conn\n"); 179 error = ENXIO; 180 goto cleanup; 181 } 182 conn = vmbus_xact_req_data(xact); 183 conn->nvs_type = HN_NVS_TYPE_RXBUF_CONN; 184 conn->nvs_gpadl = sc->hn_rxbuf_gpadl; 185 conn->nvs_sig = HN_NVS_RXBUF_SIG; 186 187 resp_len = sizeof(*resp); 188 resp = hn_nvs_xact_execute(sc, xact, conn, sizeof(*conn), &resp_len, 189 HN_NVS_TYPE_RXBUF_CONNRESP); 190 if (resp == NULL) { 191 if_printf(sc->hn_ifp, "exec nvs rxbuf conn failed\n"); 192 error = EIO; 193 goto cleanup; 194 } 195 196 status = resp->nvs_status; 197 vmbus_xact_put(xact); 198 xact = NULL; 199 200 if (status != HN_NVS_STATUS_OK) { 201 if_printf(sc->hn_ifp, "nvs rxbuf conn failed: %x\n", status); 202 error = EIO; 203 goto cleanup; 204 } 205 sc->hn_flags |= HN_FLAG_RXBUF_CONNECTED; 206 207 return (0); 208 209 cleanup: 210 if (xact != NULL) 211 vmbus_xact_put(xact); 212 hn_nvs_disconn_rxbuf(sc); 213 return (error); 214 } 215 216 static int 217 hn_nvs_conn_chim(struct hn_softc *sc) 218 { 219 struct vmbus_xact *xact = NULL; 220 struct hn_nvs_chim_conn *chim; 221 const struct hn_nvs_chim_connresp *resp; 222 size_t resp_len; 223 uint32_t status, sectsz; 224 int error; 225 226 /* 227 * Connect chimney sending buffer GPADL to the primary channel. 228 * 229 * NOTE: 230 * Only primary channel has chimney sending buffer connected to it. 231 * Sub-channels just share this chimney sending buffer. 232 */ 233 error = vmbus_chan_gpadl_connect(sc->hn_prichan, 234 sc->hn_chim_dma.hv_paddr, HN_CHIM_SIZE, &sc->hn_chim_gpadl); 235 if (error) { 236 if_printf(sc->hn_ifp, "chim gpadl conn failed: %d\n", error); 237 goto cleanup; 238 } 239 240 /* 241 * Connect chimney sending buffer to NVS 242 */ 243 244 xact = vmbus_xact_get(sc->hn_xact, sizeof(*chim)); 245 if (xact == NULL) { 246 if_printf(sc->hn_ifp, "no xact for nvs chim conn\n"); 247 error = ENXIO; 248 goto cleanup; 249 } 250 chim = vmbus_xact_req_data(xact); 251 chim->nvs_type = HN_NVS_TYPE_CHIM_CONN; 252 chim->nvs_gpadl = sc->hn_chim_gpadl; 253 chim->nvs_sig = HN_NVS_CHIM_SIG; 254 255 resp_len = sizeof(*resp); 256 resp = hn_nvs_xact_execute(sc, xact, chim, sizeof(*chim), &resp_len, 257 HN_NVS_TYPE_CHIM_CONNRESP); 258 if (resp == NULL) { 259 if_printf(sc->hn_ifp, "exec nvs chim conn failed\n"); 260 error = EIO; 261 goto cleanup; 262 } 263 264 status = resp->nvs_status; 265 sectsz = resp->nvs_sectsz; 266 vmbus_xact_put(xact); 267 xact = NULL; 268 269 if (status != HN_NVS_STATUS_OK) { 270 if_printf(sc->hn_ifp, "nvs chim conn failed: %x\n", status); 271 error = EIO; 272 goto cleanup; 273 } 274 if (sectsz == 0) { 275 if_printf(sc->hn_ifp, "zero chimney sending buffer " 276 "section size\n"); 277 return (0); 278 } 279 280 sc->hn_chim_szmax = sectsz; 281 sc->hn_chim_cnt = HN_CHIM_SIZE / sc->hn_chim_szmax; 282 if (HN_CHIM_SIZE % sc->hn_chim_szmax != 0) { 283 if_printf(sc->hn_ifp, "chimney sending sections are " 284 "not properly aligned\n"); 285 } 286 if (sc->hn_chim_cnt % LONG_BIT != 0) { 287 if_printf(sc->hn_ifp, "discard %d chimney sending sections\n", 288 sc->hn_chim_cnt % LONG_BIT); 289 } 290 291 sc->hn_chim_bmap_cnt = sc->hn_chim_cnt / LONG_BIT; 292 sc->hn_chim_bmap = malloc(sc->hn_chim_bmap_cnt * sizeof(u_long), 293 M_DEVBUF, M_WAITOK | M_ZERO); 294 295 /* Done! */ 296 sc->hn_flags |= HN_FLAG_CHIM_CONNECTED; 297 if (bootverbose) { 298 if_printf(sc->hn_ifp, "chimney sending buffer %d/%d\n", 299 sc->hn_chim_szmax, sc->hn_chim_cnt); 300 } 301 return (0); 302 303 cleanup: 304 if (xact != NULL) 305 vmbus_xact_put(xact); 306 hn_nvs_disconn_chim(sc); 307 return (error); 308 } 309 310 static int 311 hn_nvs_disconn_rxbuf(struct hn_softc *sc) 312 { 313 int error; 314 315 if (sc->hn_flags & HN_FLAG_RXBUF_CONNECTED) { 316 struct hn_nvs_rxbuf_disconn disconn; 317 318 /* 319 * Disconnect RXBUF from NVS. 320 */ 321 memset(&disconn, 0, sizeof(disconn)); 322 disconn.nvs_type = HN_NVS_TYPE_RXBUF_DISCONN; 323 disconn.nvs_sig = HN_NVS_RXBUF_SIG; 324 325 /* NOTE: No response. */ 326 error = hn_nvs_req_send(sc, &disconn, sizeof(disconn)); 327 if (error) { 328 if_printf(sc->hn_ifp, 329 "send nvs rxbuf disconn failed: %d\n", error); 330 return (error); 331 } 332 sc->hn_flags &= ~HN_FLAG_RXBUF_CONNECTED; 333 334 /* 335 * Wait for the hypervisor to receive this NVS request. 336 */ 337 while (!vmbus_chan_tx_empty(sc->hn_prichan)) 338 pause("waittx", 1); 339 /* 340 * Linger long enough for NVS to disconnect RXBUF. 341 */ 342 pause("lingtx", (200 * hz) / 1000); 343 } 344 345 if (sc->hn_rxbuf_gpadl != 0) { 346 /* 347 * Disconnect RXBUF from primary channel. 348 */ 349 error = vmbus_chan_gpadl_disconnect(sc->hn_prichan, 350 sc->hn_rxbuf_gpadl); 351 if (error) { 352 if_printf(sc->hn_ifp, 353 "rxbuf gpadl disconn failed: %d\n", error); 354 return (error); 355 } 356 sc->hn_rxbuf_gpadl = 0; 357 } 358 return (0); 359 } 360 361 static int 362 hn_nvs_disconn_chim(struct hn_softc *sc) 363 { 364 int error; 365 366 if (sc->hn_flags & HN_FLAG_CHIM_CONNECTED) { 367 struct hn_nvs_chim_disconn disconn; 368 369 /* 370 * Disconnect chimney sending buffer from NVS. 371 */ 372 memset(&disconn, 0, sizeof(disconn)); 373 disconn.nvs_type = HN_NVS_TYPE_CHIM_DISCONN; 374 disconn.nvs_sig = HN_NVS_CHIM_SIG; 375 376 /* NOTE: No response. */ 377 error = hn_nvs_req_send(sc, &disconn, sizeof(disconn)); 378 if (error) { 379 if_printf(sc->hn_ifp, 380 "send nvs chim disconn failed: %d\n", error); 381 return (error); 382 } 383 sc->hn_flags &= ~HN_FLAG_CHIM_CONNECTED; 384 385 /* 386 * Wait for the hypervisor to receive this NVS request. 387 */ 388 while (!vmbus_chan_tx_empty(sc->hn_prichan)) 389 pause("waittx", 1); 390 /* 391 * Linger long enough for NVS to disconnect chimney 392 * sending buffer. 393 */ 394 pause("lingtx", (200 * hz) / 1000); 395 } 396 397 if (sc->hn_chim_gpadl != 0) { 398 /* 399 * Disconnect chimney sending buffer from primary channel. 400 */ 401 error = vmbus_chan_gpadl_disconnect(sc->hn_prichan, 402 sc->hn_chim_gpadl); 403 if (error) { 404 if_printf(sc->hn_ifp, 405 "chim gpadl disconn failed: %d\n", error); 406 return (error); 407 } 408 sc->hn_chim_gpadl = 0; 409 } 410 411 if (sc->hn_chim_bmap != NULL) { 412 free(sc->hn_chim_bmap, M_DEVBUF); 413 sc->hn_chim_bmap = NULL; 414 } 415 return (0); 416 } 417 418 static int 419 hn_nvs_doinit(struct hn_softc *sc, uint32_t nvs_ver) 420 { 421 struct vmbus_xact *xact; 422 struct hn_nvs_init *init; 423 const struct hn_nvs_init_resp *resp; 424 size_t resp_len; 425 uint32_t status; 426 427 xact = vmbus_xact_get(sc->hn_xact, sizeof(*init)); 428 if (xact == NULL) { 429 if_printf(sc->hn_ifp, "no xact for nvs init\n"); 430 return (ENXIO); 431 } 432 init = vmbus_xact_req_data(xact); 433 init->nvs_type = HN_NVS_TYPE_INIT; 434 init->nvs_ver_min = nvs_ver; 435 init->nvs_ver_max = nvs_ver; 436 437 resp_len = sizeof(*resp); 438 resp = hn_nvs_xact_execute(sc, xact, init, sizeof(*init), &resp_len, 439 HN_NVS_TYPE_INIT_RESP); 440 if (resp == NULL) { 441 if_printf(sc->hn_ifp, "exec init failed\n"); 442 vmbus_xact_put(xact); 443 return (EIO); 444 } 445 446 status = resp->nvs_status; 447 vmbus_xact_put(xact); 448 449 if (status != HN_NVS_STATUS_OK) { 450 if (bootverbose) { 451 /* 452 * Caller may try another NVS version, and will log 453 * error if there are no more NVS versions to try, 454 * so don't bark out loud here. 455 */ 456 if_printf(sc->hn_ifp, "nvs init failed for ver 0x%x\n", 457 nvs_ver); 458 } 459 return (EINVAL); 460 } 461 return (0); 462 } 463 464 /* 465 * Configure MTU and enable VLAN. 466 */ 467 static int 468 hn_nvs_conf_ndis(struct hn_softc *sc, int mtu) 469 { 470 struct hn_nvs_ndis_conf conf; 471 int error; 472 473 memset(&conf, 0, sizeof(conf)); 474 conf.nvs_type = HN_NVS_TYPE_NDIS_CONF; 475 conf.nvs_mtu = mtu; 476 conf.nvs_caps = HN_NVS_NDIS_CONF_VLAN; 477 478 /* NOTE: No response. */ 479 error = hn_nvs_req_send(sc, &conf, sizeof(conf)); 480 if (error) { 481 if_printf(sc->hn_ifp, "send nvs ndis conf failed: %d\n", error); 482 return (error); 483 } 484 485 if (bootverbose) 486 if_printf(sc->hn_ifp, "nvs ndis conf done\n"); 487 sc->hn_caps |= HN_CAP_MTU | HN_CAP_VLAN; 488 return (0); 489 } 490 491 static int 492 hn_nvs_init_ndis(struct hn_softc *sc) 493 { 494 struct hn_nvs_ndis_init ndis; 495 int error; 496 497 memset(&ndis, 0, sizeof(ndis)); 498 ndis.nvs_type = HN_NVS_TYPE_NDIS_INIT; 499 ndis.nvs_ndis_major = HN_NDIS_VERSION_MAJOR(sc->hn_ndis_ver); 500 ndis.nvs_ndis_minor = HN_NDIS_VERSION_MINOR(sc->hn_ndis_ver); 501 502 /* NOTE: No response. */ 503 error = hn_nvs_req_send(sc, &ndis, sizeof(ndis)); 504 if (error) 505 if_printf(sc->hn_ifp, "send nvs ndis init failed: %d\n", error); 506 return (error); 507 } 508 509 static int 510 hn_nvs_init(struct hn_softc *sc) 511 { 512 int i, error; 513 514 if (device_is_attached(sc->hn_dev)) { 515 /* 516 * NVS version and NDIS version MUST NOT be changed. 517 */ 518 if (bootverbose) { 519 if_printf(sc->hn_ifp, "reinit NVS version 0x%x, " 520 "NDIS version %u.%u\n", sc->hn_nvs_ver, 521 HN_NDIS_VERSION_MAJOR(sc->hn_ndis_ver), 522 HN_NDIS_VERSION_MINOR(sc->hn_ndis_ver)); 523 } 524 525 error = hn_nvs_doinit(sc, sc->hn_nvs_ver); 526 if (error) { 527 if_printf(sc->hn_ifp, "reinit NVS version 0x%x " 528 "failed: %d\n", sc->hn_nvs_ver, error); 529 return (error); 530 } 531 goto done; 532 } 533 534 /* 535 * Find the supported NVS version and set NDIS version accordingly. 536 */ 537 for (i = 0; i < nitems(hn_nvs_version); ++i) { 538 error = hn_nvs_doinit(sc, hn_nvs_version[i]); 539 if (!error) { 540 sc->hn_nvs_ver = hn_nvs_version[i]; 541 542 /* Set NDIS version according to NVS version. */ 543 sc->hn_ndis_ver = HN_NDIS_VERSION_6_30; 544 if (sc->hn_nvs_ver <= HN_NVS_VERSION_4) 545 sc->hn_ndis_ver = HN_NDIS_VERSION_6_1; 546 547 if (bootverbose) { 548 if_printf(sc->hn_ifp, "NVS version 0x%x, " 549 "NDIS version %u.%u\n", sc->hn_nvs_ver, 550 HN_NDIS_VERSION_MAJOR(sc->hn_ndis_ver), 551 HN_NDIS_VERSION_MINOR(sc->hn_ndis_ver)); 552 } 553 goto done; 554 } 555 } 556 if_printf(sc->hn_ifp, "no NVS available\n"); 557 return (ENXIO); 558 559 done: 560 if (sc->hn_nvs_ver >= HN_NVS_VERSION_5) 561 sc->hn_caps |= HN_CAP_HASHVAL; 562 return (0); 563 } 564 565 int 566 hn_nvs_attach(struct hn_softc *sc, int mtu) 567 { 568 int error; 569 570 /* 571 * Initialize NVS. 572 */ 573 error = hn_nvs_init(sc); 574 if (error) 575 return (error); 576 577 if (sc->hn_nvs_ver >= HN_NVS_VERSION_2) { 578 /* 579 * Configure NDIS before initializing it. 580 */ 581 error = hn_nvs_conf_ndis(sc, mtu); 582 if (error) 583 return (error); 584 } 585 586 /* 587 * Initialize NDIS. 588 */ 589 error = hn_nvs_init_ndis(sc); 590 if (error) 591 return (error); 592 593 /* 594 * Connect RXBUF. 595 */ 596 error = hn_nvs_conn_rxbuf(sc); 597 if (error) 598 return (error); 599 600 /* 601 * Connect chimney sending buffer. 602 */ 603 error = hn_nvs_conn_chim(sc); 604 if (error) 605 return (error); 606 return (0); 607 } 608 609 void 610 hn_nvs_detach(struct hn_softc *sc) 611 { 612 613 /* NOTE: there are no requests to stop the NVS. */ 614 hn_nvs_disconn_rxbuf(sc); 615 hn_nvs_disconn_chim(sc); 616 } 617 618 void 619 hn_nvs_sent_xact(struct hn_nvs_sendctx *sndc, 620 struct hn_softc *sc __unused, struct vmbus_channel *chan __unused, 621 const void *data, int dlen) 622 { 623 624 vmbus_xact_wakeup(sndc->hn_cbarg, data, dlen); 625 } 626 627 static void 628 hn_nvs_sent_none(struct hn_nvs_sendctx *sndc __unused, 629 struct hn_softc *sc __unused, struct vmbus_channel *chan __unused, 630 const void *data __unused, int dlen __unused) 631 { 632 /* EMPTY */ 633 } 634 635 int 636 hn_nvs_alloc_subchans(struct hn_softc *sc, int *nsubch0) 637 { 638 struct vmbus_xact *xact; 639 struct hn_nvs_subch_req *req; 640 const struct hn_nvs_subch_resp *resp; 641 int error, nsubch_req; 642 uint32_t nsubch; 643 size_t resp_len; 644 645 nsubch_req = *nsubch0; 646 KASSERT(nsubch_req > 0, ("invalid # of sub-channels %d", nsubch_req)); 647 648 xact = vmbus_xact_get(sc->hn_xact, sizeof(*req)); 649 if (xact == NULL) { 650 if_printf(sc->hn_ifp, "no xact for nvs subch alloc\n"); 651 return (ENXIO); 652 } 653 req = vmbus_xact_req_data(xact); 654 req->nvs_type = HN_NVS_TYPE_SUBCH_REQ; 655 req->nvs_op = HN_NVS_SUBCH_OP_ALLOC; 656 req->nvs_nsubch = nsubch_req; 657 658 resp_len = sizeof(*resp); 659 resp = hn_nvs_xact_execute(sc, xact, req, sizeof(*req), &resp_len, 660 HN_NVS_TYPE_SUBCH_RESP); 661 if (resp == NULL) { 662 if_printf(sc->hn_ifp, "exec nvs subch alloc failed\n"); 663 error = EIO; 664 goto done; 665 } 666 if (resp->nvs_status != HN_NVS_STATUS_OK) { 667 if_printf(sc->hn_ifp, "nvs subch alloc failed: %x\n", 668 resp->nvs_status); 669 error = EIO; 670 goto done; 671 } 672 673 nsubch = resp->nvs_nsubch; 674 if (nsubch > nsubch_req) { 675 if_printf(sc->hn_ifp, "%u subchans are allocated, " 676 "requested %d\n", nsubch, nsubch_req); 677 nsubch = nsubch_req; 678 } 679 *nsubch0 = nsubch; 680 error = 0; 681 done: 682 vmbus_xact_put(xact); 683 return (error); 684 } 685 686 int 687 hn_nvs_send_rndis_ctrl(struct vmbus_channel *chan, 688 struct hn_nvs_sendctx *sndc, struct vmbus_gpa *gpa, int gpa_cnt) 689 { 690 691 return hn_nvs_send_rndis_sglist(chan, HN_NVS_RNDIS_MTYPE_CTRL, 692 sndc, gpa, gpa_cnt); 693 } 694