1/* $NetBSD: hvs.c,v 1.7 2021/08/07 16:19:11 thorpej Exp $ */ 2/* $OpenBSD: hvs.c,v 1.17 2017/08/10 17:22:48 mikeb Exp $ */ 3 4/*- 5 * Copyright (c) 2009-2012,2016 Microsoft Corp. 6 * Copyright (c) 2012 NetApp Inc. 7 * Copyright (c) 2012 Citrix Inc. 8 * Copyright (c) 2017 Mike Belopuhov <mike@esdenera.com> 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice unmodified, this list of conditions, and the following 16 * disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33/* 34 * The OpenBSD port was done under funding by Esdenera Networks GmbH. 35 */ 36 37/* #define HVS_DEBUG_IO */ 38 39#include <sys/cdefs.h> 40__KERNEL_RCSID(0, "$NetBSD: hvs.c,v 1.7 2021/08/07 16:19:11 thorpej Exp $"); 41 42#include <sys/param.h> 43#include <sys/systm.h> 44#include <sys/kernel.h> 45#include <sys/device.h> 46#include <sys/buf.h> 47#include <sys/bus.h> 48#include <sys/kmem.h> 49#include <sys/mutex.h> 50 51#include <uvm/uvm_extern.h> 52 53#include <dev/hyperv/vmbusvar.h> 54 55#include <dev/scsipi/scsi_all.h> 56#include <dev/scsipi/scsiconf.h> 57#include <dev/scsipi/scsipi_all.h> 58 59#define HVS_PROTO_VERSION_WIN6 0x200 60#define HVS_PROTO_VERSION_WIN7 0x402 61#define HVS_PROTO_VERSION_WIN8 0x501 62#define HVS_PROTO_VERSION_WIN8_1 0x600 63#define HVS_PROTO_VERSION_WIN10 0x602 64 65#define HVS_MSG_IODONE 0x01 66#define HVS_MSG_DEVGONE 0x02 67#define HVS_MSG_ENUMERATE 0x0b 68 69#define HVS_REQ_SCSIIO 0x03 70#define HVS_REQ_STARTINIT 0x07 71#define HVS_REQ_FINISHINIT 0x08 72#define HVS_REQ_QUERYPROTO 0x09 73#define HVS_REQ_QUERYPROPS 0x0a 74#define HVS_REQ_CREATEMULTICHANNELS 0x0d 75 76struct hvs_cmd_hdr { 77 uint32_t hdr_op; 78 uint32_t hdr_flags; 79 uint32_t hdr_status; 80#define cmd_op cmd_hdr.hdr_op 81#define cmd_flags cmd_hdr.hdr_flags 82#define cmd_status cmd_hdr.hdr_status 83} __packed; 84 85/* Negotiate version */ 86struct hvs_cmd_ver { 87 struct hvs_cmd_hdr cmd_hdr; 88 uint16_t cmd_ver; 89 uint16_t cmd_rev; 90} __packed; 91 92/* Query channel properties */ 93struct hvs_chp { 94 uint16_t chp_proto; 95 uint8_t chp_path; 96 uint8_t chp_target; 97 uint16_t chp_maxchan; 98 uint16_t chp_port; 99 uint32_t chp_chflags; 100#define CHP_CHFLAGS_MULTI_CHANNEL 0x1 101 uint32_t chp_maxfer; 102 uint64_t chp_chanid; 103} __packed; 104 105struct hvs_cmd_chp { 106 struct hvs_cmd_hdr cmd_hdr; 107 struct hvs_chp cmd_chp; 108} __packed; 109 110#define SENSE_DATA_LEN_WIN7 18 111#define SENSE_DATA_LEN 20 112#define MAX_SRB_DATA 20 113 114/* SCSI Request Block */ 115struct hvs_srb { 116 uint16_t srb_reqlen; 117 uint8_t srb_iostatus; 118 uint8_t srb_scsistatus; 119 120 uint8_t srb_initiator; 121 uint8_t srb_bus; 122 uint8_t srb_target; 123 uint8_t srb_lun; 124 125 uint8_t srb_cdblen; 126 uint8_t srb_senselen; 127 uint8_t srb_direction; 128 uint8_t _reserved; 129 130 uint32_t srb_datalen; 131 uint8_t srb_data[MAX_SRB_DATA]; 132} __packed; 133 134#define SRB_DATA_WRITE 0 135#define SRB_DATA_READ 1 136#define SRB_DATA_NONE 2 137 138#define SRB_STATUS_PENDING 0x00 139#define SRB_STATUS_SUCCESS 0x01 140#define SRB_STATUS_ABORTED 0x02 141#define SRB_STATUS_ERROR 0x04 142#define SRB_STATUS_INVALID_LUN 0x20 143#define SRB_STATUS_QUEUE_FROZEN 0x40 144#define SRB_STATUS_AUTOSENSE_VALID 0x80 145 146#define SRB_FLAGS_QUEUE_ACTION_ENABLE 0x00000002 147#define SRB_FLAGS_DISABLE_DISCONNECT 0x00000004 148#define SRB_FLAGS_DISABLE_SYNCH_TRANSFER 0x00000008 149#define SRB_FLAGS_BYPASS_FROZEN_QUEUE 0x00000010 150#define SRB_FLAGS_DISABLE_AUTOSENSE 0x00000020 151#define SRB_FLAGS_DATA_IN 0x00000040 152#define SRB_FLAGS_DATA_OUT 0x00000080 153#define SRB_FLAGS_NO_DATA_TRANSFER 0x00000000 154#define SRB_FLAGS_NO_QUEUE_FREEZE 0x00000100 155#define SRB_FLAGS_ADAPTER_CACHE_ENABLE 0x00000200 156#define SRB_FLAGS_FREE_SENSE_BUFFER 0x00000400 157 158struct hvs_cmd_io { 159 struct hvs_cmd_hdr cmd_hdr; 160 struct hvs_srb cmd_srb; 161 /* Win8 extensions */ 162 uint16_t _reserved; 163 uint8_t cmd_qtag; 164 uint8_t cmd_qaction; 165 uint32_t cmd_srbflags; 166 uint32_t cmd_timeout; 167 uint32_t cmd_qsortkey; 168} __packed; 169 170#define HVS_CMD_SIZE 64 171 172union hvs_cmd { 173 struct hvs_cmd_hdr cmd_hdr; 174 struct hvs_cmd_ver ver; 175 struct hvs_cmd_chp chp; 176 struct hvs_cmd_io io; 177 uint16_t multi_chans_cnt; 178 uint8_t pad[HVS_CMD_SIZE]; 179} __packed; 180 181#define HVS_RING_SIZE (20 * PAGE_SIZE) 182#define HVS_MAX_CCB 128 183#define HVS_MAX_SGE (howmany(MAXPHYS, PAGE_SIZE) + 1) 184 185struct hvs_softc; 186 187struct hvs_ccb { 188 struct scsipi_xfer *ccb_xfer; /* associated transfer */ 189 union hvs_cmd *ccb_cmd; /* associated command */ 190 union hvs_cmd ccb_rsp; /* response */ 191 bus_dmamap_t ccb_dmap; /* transfer map */ 192 uint64_t ccb_rid; /* request id */ 193 struct vmbus_gpa_range *ccb_sgl; 194 int ccb_nsge; 195 void (*ccb_done)(struct hvs_ccb *); 196 void *ccb_cookie; 197 SIMPLEQ_ENTRY(hvs_ccb) ccb_link; 198}; 199SIMPLEQ_HEAD(hvs_ccb_queue, hvs_ccb); 200 201struct hvs_config; 202 203struct hvs_softc { 204 device_t sc_dev; 205 bus_dma_tag_t sc_dmat; 206 207 struct vmbus_channel *sc_chan; 208 209 const struct hvs_config *sc_config; 210 211 struct hvs_chp sc_props; 212 213 /* CCBs */ 214 int sc_nccb; 215 struct hvs_ccb *sc_ccbs; 216 struct hvs_ccb_queue sc_ccb_fq; /* free queue */ 217 kmutex_t sc_ccb_fqlck; 218 219 int sc_bus; 220 221 struct scsipi_adapter sc_adapter; 222 struct scsipi_channel sc_channel; 223 device_t sc_scsibus; 224#if notyet /* XXX subchannel */ 225 u_int sc_nchan; 226 struct vmbus_channel *sc_sel_chan[MAXCPUS]; 227#endif 228}; 229 230static int hvs_match(device_t, cfdata_t, void *); 231static void hvs_attach(device_t, device_t, void *); 232static int hvs_detach(device_t, int); 233 234CFATTACH_DECL_NEW(hvs, sizeof(struct hvs_softc), 235 hvs_match, hvs_attach, hvs_detach, NULL); 236 237static void hvs_scsipi_request(struct scsipi_channel *, 238 scsipi_adapter_req_t, void *); 239static void hvs_scsi_cmd_done(struct hvs_ccb *); 240static int hvs_start(struct hvs_softc *, struct vmbus_channel *, 241 struct hvs_ccb *); 242static int hvs_poll(struct hvs_softc *, struct vmbus_channel *, 243 struct hvs_ccb *); 244static void hvs_poll_done(struct hvs_ccb *); 245static void hvs_intr(void *); 246static void hvs_scsi_probe(void *arg); 247static void hvs_scsi_done(struct scsipi_xfer *, int); 248 249static int hvs_connect(struct hvs_softc *); 250static void hvs_empty_done(struct hvs_ccb *); 251 252static int hvs_alloc_ccbs(struct hvs_softc *); 253static void hvs_free_ccbs(struct hvs_softc *); 254static struct hvs_ccb * 255 hvs_get_ccb(struct hvs_softc *); 256static void hvs_put_ccb(struct hvs_softc *, struct hvs_ccb *); 257 258static const struct hvs_config { 259 uint32_t proto_version; 260 uint16_t reqlen; 261 uint8_t senselen; 262 bool fixup_wrong_response; 263 bool upgrade_spc2_to_spc3; 264 bool use_win8ext_flags; 265} hvs_config_list[] = { 266 { 267 .proto_version = HVS_PROTO_VERSION_WIN10, 268 .reqlen = sizeof(struct hvs_cmd_io), 269 .senselen = SENSE_DATA_LEN, 270 .fixup_wrong_response = false, 271 .upgrade_spc2_to_spc3 = false, 272 .use_win8ext_flags = true, 273 }, 274 { 275 .proto_version = HVS_PROTO_VERSION_WIN8_1, 276 .reqlen = sizeof(struct hvs_cmd_io), 277 .senselen = SENSE_DATA_LEN, 278 .fixup_wrong_response = true, 279 .upgrade_spc2_to_spc3 = true, 280 .use_win8ext_flags = true, 281 }, 282 { 283 .proto_version = HVS_PROTO_VERSION_WIN8, 284 .reqlen = sizeof(struct hvs_cmd_io), 285 .senselen = SENSE_DATA_LEN, 286 .fixup_wrong_response = true, 287 .upgrade_spc2_to_spc3 = true, 288 .use_win8ext_flags = true, 289 }, 290 { 291 .proto_version = HVS_PROTO_VERSION_WIN7, 292 .reqlen = offsetof(struct hvs_cmd_io, _reserved), 293 .senselen = SENSE_DATA_LEN_WIN7, 294 .fixup_wrong_response = true, 295 .upgrade_spc2_to_spc3 = false, 296 .use_win8ext_flags = false, 297 }, 298 { 299 .proto_version = HVS_PROTO_VERSION_WIN6, 300 .reqlen = offsetof(struct hvs_cmd_io, _reserved), 301 .senselen = SENSE_DATA_LEN_WIN7, 302 .fixup_wrong_response = false, 303 .upgrade_spc2_to_spc3 = false, 304 .use_win8ext_flags = false, 305 }, 306}; 307 308#if notyet /* XXX subchannel */ 309static int hvs_chan_cnt; 310#endif 311 312static int 313hvs_match(device_t parent, cfdata_t cf, void *aux) 314{ 315 struct vmbus_attach_args *aa = aux; 316 317 if (memcmp(aa->aa_type, &hyperv_guid_ide, sizeof(*aa->aa_type)) != 0 && 318 memcmp(aa->aa_type, &hyperv_guid_scsi, sizeof(*aa->aa_type)) != 0) 319 return 0; 320 return 1; 321} 322 323static void 324hvs_attach(device_t parent, device_t self, void *aux) 325{ 326 extern struct cfdata cfdata[]; 327 struct hvs_softc *sc = device_private(self); 328 struct vmbus_attach_args *aa = aux; 329 struct scsipi_adapter *adapt = &sc->sc_adapter; 330 struct scsipi_channel *chan = &sc->sc_channel; 331 const char *bus; 332 bool is_scsi; 333 334 sc->sc_dev = self; 335 sc->sc_chan = aa->aa_chan; 336 sc->sc_dmat = sc->sc_chan->ch_sc->sc_dmat; 337#if notyet /* XXX subchannel */ 338 sc->sc_nchan = 1; 339 sc->sc_sel_chan[0] = sc->sc_chan; 340#endif 341 342 if (memcmp(aa->aa_type, &hyperv_guid_scsi, sizeof(*aa->aa_type)) == 0) { 343 is_scsi = true; 344 bus = "SCSI"; 345 } else { 346 is_scsi = false; 347 bus = "IDE"; 348 } 349 350 aprint_naive("\n"); 351 aprint_normal(": Hyper-V StorVSC %s\n", bus); 352 353 if (vmbus_channel_setdeferred(sc->sc_chan, device_xname(self))) { 354 aprint_error_dev(self, 355 "failed to create the interrupt thread\n"); 356 return; 357 } 358 359 if (vmbus_channel_open(sc->sc_chan, HVS_RING_SIZE, &sc->sc_props, 360 sizeof(sc->sc_props), hvs_intr, sc)) { 361 aprint_error_dev(self, "failed to open channel\n"); 362 return; 363 } 364 365 if (hvs_alloc_ccbs(sc)) 366 return; 367 368 if (hvs_connect(sc)) 369 return; 370 371 aprint_normal_dev(self, "protocol %u.%u\n", 372 (sc->sc_config->proto_version >> 8) & 0xff, 373 sc->sc_config->proto_version & 0xff); 374 375 adapt = &sc->sc_adapter; 376 adapt->adapt_dev = self; 377 adapt->adapt_nchannels = 1; 378 adapt->adapt_openings = sc->sc_nccb; 379 adapt->adapt_max_periph = adapt->adapt_openings; 380 adapt->adapt_request = hvs_scsipi_request; 381 adapt->adapt_minphys = minphys; 382 adapt->adapt_flags = SCSIPI_ADAPT_MPSAFE; 383 384 chan = &sc->sc_channel; 385 chan->chan_adapter = adapt; 386 chan->chan_bustype = &scsi_bustype; /* XXX IDE/ATAPI */ 387 chan->chan_channel = 0; 388 chan->chan_ntargets = 2; 389 chan->chan_nluns = is_scsi ? 64 : 1; 390 chan->chan_id = 0; 391 chan->chan_flags = SCSIPI_CHAN_NOSETTLE; 392 chan->chan_defquirks |= PQUIRK_ONLYBIG; 393 394 sc->sc_scsibus = config_found(self, &sc->sc_channel, scsiprint, 395 CFARGS_NONE); 396 397 /* 398 * If the driver has successfully attached to an IDE device, 399 * we need to make sure that the same disk is not available to 400 * the system via pciide(4) or piixide(4) causing DUID conflicts 401 * and preventing system from booting. 402 */ 403 if (!is_scsi && sc->sc_scsibus != NULL) { 404 static const char *disable_devices[] = { 405 "wd", 406 }; 407 size_t j; 408 409 for (j = 0; j < __arraycount(disable_devices); j++) { 410 const char *dev = disable_devices[j]; 411 size_t len = strlen(dev); 412 int devno; 413 414 for (devno = 0; cfdata[devno].cf_name != NULL; devno++) { 415 cfdata_t cf = &cfdata[devno]; 416 417 if (strlen(cf->cf_name) != len || 418 strncasecmp(dev, cf->cf_name, len) != 0 || 419 cf->cf_fstate != FSTATE_STAR) 420 continue; 421 422 cf->cf_fstate = FSTATE_DSTAR; 423 } 424 } 425 } 426} 427 428static int 429hvs_detach(device_t self, int flags) 430{ 431 432 /* XXX detach */ 433 434 return 0; 435} 436 437#define XS2DMA(xs) \ 438 ((((xs)->xs_control & XS_CTL_DATA_IN) ? BUS_DMA_READ : BUS_DMA_WRITE) | \ 439 (((xs)->xs_control & XS_CTL_NOSLEEP) ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK) | \ 440 BUS_DMA_STREAMING) 441 442#define XS2DMAPRE(xs) (((xs)->xs_control & XS_CTL_DATA_IN) ? \ 443 BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE) 444 445#define XS2DMAPOST(xs) (((xs)->xs_control & XS_CTL_DATA_IN) ? \ 446 BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE) 447 448static void 449hvs_scsipi_request(struct scsipi_channel *chan, scsipi_adapter_req_t request, 450 void *arg) 451{ 452 struct scsipi_adapter *adapt = chan->chan_adapter; 453 struct hvs_softc *sc = device_private(adapt->adapt_dev); 454 struct scsipi_xfer *xs; 455 struct scsipi_xfer_mode *xm; 456 struct scsipi_periph *periph; 457 struct hvs_ccb *ccb; 458 union hvs_cmd cmd; 459 struct hvs_cmd_io *io = &cmd.io; 460 struct hvs_srb *srb = &io->cmd_srb; 461 int i, error; 462 463 switch (request) { 464 default: 465 device_printf(sc->sc_dev, 466 "%s: unhandled request %u\n", __func__, request); 467 return; 468 469 case ADAPTER_REQ_GROW_RESOURCES: 470 /* Not supported. */ 471 return; 472 473 case ADAPTER_REQ_SET_XFER_MODE: 474 xm = arg; 475 xm->xm_mode = PERIPH_CAP_TQING; 476 xm->xm_period = 0; 477 xm->xm_offset = 0; 478 scsipi_async_event(chan, ASYNC_EVENT_XFER_MODE, xm); 479 return; 480 481 case ADAPTER_REQ_RUN_XFER: 482 break; 483 } 484 485 xs = arg; 486 487 if (xs->cmdlen > MAX_SRB_DATA) { 488 device_printf(sc->sc_dev, "CDB is too big: %d\n", 489 xs->cmdlen); 490 memset(&xs->sense, 0, sizeof(xs->sense)); 491 xs->sense.scsi_sense.response_code = 492 SSD_RCODE_VALID | SSD_RCODE_CURRENT; 493 xs->sense.scsi_sense.flags = SSD_ILI; 494 xs->sense.scsi_sense.asc = 0x20; 495 hvs_scsi_done(xs, XS_SENSE); 496 return; 497 } 498 499 ccb = hvs_get_ccb(sc); 500 if (ccb == NULL) { 501 device_printf(sc->sc_dev, "failed to allocate ccb\n"); 502 hvs_scsi_done(xs, XS_RESOURCE_SHORTAGE); 503 return; 504 } 505 506 periph = xs->xs_periph; 507 508 memset(&cmd, 0, sizeof(cmd)); 509 510 srb->srb_initiator = chan->chan_id; 511 srb->srb_bus = sc->sc_bus; 512 srb->srb_target = periph->periph_target - 1; 513 srb->srb_lun = periph->periph_lun; 514 srb->srb_cdblen = xs->cmdlen; 515 memcpy(srb->srb_data, xs->cmd, xs->cmdlen); 516 517 if (sc->sc_config->use_win8ext_flags) { 518 io->cmd_timeout = 60; 519 SET(io->cmd_srbflags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER); 520 } 521 522 switch (xs->xs_control & (XS_CTL_DATA_IN | XS_CTL_DATA_OUT)) { 523 case XS_CTL_DATA_IN: 524 srb->srb_direction = SRB_DATA_READ; 525 if (sc->sc_config->use_win8ext_flags) 526 SET(io->cmd_srbflags, SRB_FLAGS_DATA_IN); 527 break; 528 case XS_CTL_DATA_OUT: 529 srb->srb_direction = SRB_DATA_WRITE; 530 if (sc->sc_config->use_win8ext_flags) 531 SET(io->cmd_srbflags, SRB_FLAGS_DATA_OUT); 532 break; 533 default: 534 srb->srb_direction = SRB_DATA_NONE; 535 if (sc->sc_config->use_win8ext_flags) 536 SET(io->cmd_srbflags, SRB_FLAGS_NO_DATA_TRANSFER); 537 break; 538 } 539 540 srb->srb_datalen = xs->datalen; 541 srb->srb_reqlen = sc->sc_config->reqlen; 542 srb->srb_senselen = sc->sc_config->senselen; 543 544 cmd.cmd_op = HVS_REQ_SCSIIO; 545 cmd.cmd_flags = VMBUS_CHANPKT_FLAG_RC; 546 547 if (xs->datalen > 0) { 548 error = bus_dmamap_load(sc->sc_dmat, ccb->ccb_dmap, xs->data, 549 xs->datalen, NULL, XS2DMA(xs)); 550 if (error) { 551 device_printf(sc->sc_dev, 552 "failed to load %d bytes (%d)\n", xs->datalen, 553 error); 554 hvs_put_ccb(sc, ccb); 555 hvs_scsi_done(xs, (error == ENOMEM || error == EAGAIN) ? 556 XS_RESOURCE_SHORTAGE : XS_DRIVER_STUFFUP); 557 return; 558 } 559 bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmap, 0, xs->datalen, 560 XS2DMAPRE(xs)); 561 562 ccb->ccb_sgl->gpa_len = xs->datalen; 563 ccb->ccb_sgl->gpa_ofs = (vaddr_t)xs->data & PAGE_MASK; 564 for (i = 0; i < ccb->ccb_dmap->dm_nsegs; i++) 565 ccb->ccb_sgl->gpa_page[i] = 566 atop(ccb->ccb_dmap->dm_segs[i].ds_addr); 567 ccb->ccb_nsge = ccb->ccb_dmap->dm_nsegs; 568 } else 569 ccb->ccb_nsge = 0; 570 571 ccb->ccb_xfer = xs; 572 ccb->ccb_cmd = &cmd; 573 ccb->ccb_done = hvs_scsi_cmd_done; 574 575#ifdef HVS_DEBUG_IO 576 printf("%s: %u.%u: rid %"PRIu64" opcode %#x control %#x datalen %d\n", 577 device_xname(sc->sc_dev), periph->periph_target, periph->periph_lun, 578 ccb->ccb_rid, xs->cmd->opcode, xs->xs_control, xs->datalen); 579#endif 580 581 if (xs->xs_control & XS_CTL_POLL) 582 error = hvs_poll(sc, sc->sc_chan, ccb); 583 else 584 error = hvs_start(sc, sc->sc_chan, ccb); 585 if (error) { 586 hvs_put_ccb(sc, ccb); 587 hvs_scsi_done(xs, (error == ENOMEM || error == EAGAIN) ? 588 XS_RESOURCE_SHORTAGE : XS_DRIVER_STUFFUP); 589 } 590} 591 592static int 593hvs_start(struct hvs_softc *sc, struct vmbus_channel *chan, struct hvs_ccb *ccb) 594{ 595 union hvs_cmd *cmd = ccb->ccb_cmd; 596 int error; 597 598 ccb->ccb_cmd = NULL; 599 600 if (ccb->ccb_nsge > 0) { 601 error = vmbus_channel_send_prpl(chan, ccb->ccb_sgl, 602 ccb->ccb_nsge, cmd, HVS_CMD_SIZE, ccb->ccb_rid); 603 if (error) { 604 device_printf(sc->sc_dev, 605 "failed to submit operation %x via prpl\n", 606 cmd->cmd_op); 607 bus_dmamap_unload(sc->sc_dmat, ccb->ccb_dmap); 608 } 609 } else { 610 error = vmbus_channel_send(chan, cmd, HVS_CMD_SIZE, 611 ccb->ccb_rid, VMBUS_CHANPKT_TYPE_INBAND, 612 VMBUS_CHANPKT_FLAG_RC); 613 if (error) 614 device_printf(sc->sc_dev, 615 "failed to submit operation %x\n", cmd->cmd_op); 616 } 617 618 return error; 619} 620 621static void 622hvs_poll_done(struct hvs_ccb *ccb) 623{ 624 int *rv = ccb->ccb_cookie; 625 626 if (ccb->ccb_cmd) { 627 memcpy(&ccb->ccb_rsp, ccb->ccb_cmd, HVS_CMD_SIZE); 628 ccb->ccb_cmd = &ccb->ccb_rsp; 629 } else 630 memset(&ccb->ccb_rsp, 0, HVS_CMD_SIZE); 631 632 *rv = 0; 633} 634 635static int 636hvs_poll(struct hvs_softc *sc, struct vmbus_channel *chan, struct hvs_ccb *ccb) 637{ 638 void (*done)(struct hvs_ccb *); 639 void *cookie; 640 int s, rv = 1; 641 642 done = ccb->ccb_done; 643 cookie = ccb->ccb_cookie; 644 645 ccb->ccb_done = hvs_poll_done; 646 ccb->ccb_cookie = &rv; 647 648 if (hvs_start(sc, chan, ccb)) { 649 ccb->ccb_cookie = cookie; 650 ccb->ccb_done = done; 651 return -1; 652 } 653 654 while (rv == 1) { 655 delay(10); 656 s = splbio(); 657 hvs_intr(sc); 658 splx(s); 659 } 660 661 ccb->ccb_cookie = cookie; 662 ccb->ccb_done = done; 663 ccb->ccb_done(ccb); 664 665 return 0; 666} 667 668static void 669hvs_intr(void *xsc) 670{ 671 struct hvs_softc *sc = xsc; 672 struct hvs_ccb *ccb; 673 union hvs_cmd cmd; 674 uint64_t rid; 675 uint32_t rlen; 676 int error; 677 678 for (;;) { 679 error = vmbus_channel_recv(sc->sc_chan, &cmd, sizeof(cmd), 680 &rlen, &rid, 0); 681 switch (error) { 682 case 0: 683 break; 684 case EAGAIN: 685 /* No more messages to process */ 686 return; 687 default: 688 device_printf(sc->sc_dev, 689 "error %d while receiving a reply\n", error); 690 return; 691 } 692 if (rlen != sizeof(cmd)) { 693 device_printf(sc->sc_dev, "short read: %u\n", rlen); 694 return; 695 } 696 697#ifdef HVS_DEBUG_IO 698 printf("%s: rid %"PRIu64" operation %u flags %#x status %#x\n", 699 device_xname(sc->sc_dev), rid, cmd.cmd_op, cmd.cmd_flags, 700 cmd.cmd_status); 701#endif 702 703 switch (cmd.cmd_op) { 704 case HVS_MSG_IODONE: 705 if (rid >= sc->sc_nccb) { 706 device_printf(sc->sc_dev, 707 "invalid response %#"PRIx64"\n", rid); 708 continue; 709 } 710 ccb = &sc->sc_ccbs[rid]; 711 ccb->ccb_cmd = &cmd; 712 ccb->ccb_done(ccb); 713 break; 714 case HVS_MSG_ENUMERATE: 715 hvs_scsi_probe(sc); 716 break; 717 default: 718 device_printf(sc->sc_dev, 719 "operation %u is not implemented\n", cmd.cmd_op); 720 break; 721 } 722 } 723} 724 725static int 726is_inquiry_valid(struct scsipi_inquiry_data *inq) 727{ 728 729 if ((inq->device & SID_TYPE) == T_NODEVICE) 730 return 0; 731 if ((inq->device & SID_QUAL) == SID_QUAL_LU_NOT_SUPP) 732 return 0; 733 return 1; 734} 735 736static void 737fixup_inquiry(struct scsipi_xfer *xs, struct hvs_srb *srb) 738{ 739 struct scsipi_periph *periph = xs->xs_periph; 740 struct scsipi_channel *chan = periph->periph_channel; 741 struct scsipi_adapter *adapt = chan->chan_adapter; 742 struct hvs_softc *sc = device_private(adapt->adapt_dev); 743 struct scsipi_inquiry_data *inq = (void *)xs->data; 744 int datalen, resplen; 745 char vendor[8]; 746 747 resplen = srb->srb_datalen >= 5 ? inq->additional_length + 5 : 0; 748 datalen = MIN(resplen, srb->srb_datalen); 749 750 /* Fixup wrong response from WS2012 */ 751 if (sc->sc_config->fixup_wrong_response && 752 !is_inquiry_valid(inq) && datalen >= 4 && 753 (inq->version == 0 || inq->response_format == 0)) { 754 inq->version = 0x05; /* SPC-3 */ 755 inq->response_format = SID_FORMAT_ISO; 756 } else if (datalen >= SCSIPI_INQUIRY_LENGTH_SCSI2) { 757 /* 758 * Upgrade SPC2 to SPC3 if host is Win8 or WS2012 R2 759 * to support UNMAP feature. 760 */ 761 strnvisx(vendor, sizeof(vendor), inq->vendor, sizeof(vendor), 762 VIS_TRIM|VIS_SAFE|VIS_OCTAL); 763 if (sc->sc_config->upgrade_spc2_to_spc3 && 764 (inq->version & SID_ANSII) == 0x04 /* SPC-2 */ && 765 !strncmp(vendor, "Msft", 4)) 766 inq->version = 0x05; /* SPC-3 */ 767 } 768} 769 770static void 771hvs_scsi_cmd_done(struct hvs_ccb *ccb) 772{ 773 struct scsipi_xfer *xs = ccb->ccb_xfer; 774 struct scsipi_periph *periph = xs->xs_periph; 775 struct scsipi_channel *chan = periph->periph_channel; 776 struct scsipi_adapter *adapt = chan->chan_adapter; 777 struct hvs_softc *sc = device_private(adapt->adapt_dev); 778 union hvs_cmd *cmd = ccb->ccb_cmd; 779 struct hvs_srb *srb; 780 bus_dmamap_t map; 781 int error; 782 783 map = ccb->ccb_dmap; 784 bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize, XS2DMAPOST(xs)); 785 bus_dmamap_unload(sc->sc_dmat, map); 786 787 xs = ccb->ccb_xfer; 788 srb = &cmd->io.cmd_srb; 789 790 xs->status = srb->srb_scsistatus & 0xff; 791 792 switch (xs->status) { 793 case SCSI_OK: 794 if ((srb->srb_iostatus & ~(SRB_STATUS_AUTOSENSE_VALID | 795 SRB_STATUS_QUEUE_FROZEN)) != SRB_STATUS_SUCCESS) 796 error = XS_SELTIMEOUT; 797 else 798 error = XS_NOERROR; 799 break; 800 case SCSI_BUSY: 801 case SCSI_QUEUE_FULL: 802 device_printf(sc->sc_dev, "status %#x iostatus %#x (busy)\n", 803 srb->srb_scsistatus, srb->srb_iostatus); 804 error = XS_BUSY; 805 break; 806 case SCSI_CHECK: 807 if (srb->srb_iostatus & SRB_STATUS_AUTOSENSE_VALID) { 808 memcpy(&xs->sense, srb->srb_data, 809 MIN(sizeof(xs->sense), srb->srb_senselen)); 810 error = XS_SENSE; 811 break; 812 } 813 /* FALLTHROUGH */ 814 default: 815 error = XS_DRIVER_STUFFUP; 816 break; 817 } 818 819 if (error == XS_NOERROR) { 820 if (xs->cmd->opcode == INQUIRY) 821 fixup_inquiry(xs, srb); 822 else if (srb->srb_direction != SRB_DATA_NONE) 823 xs->resid = xs->datalen - srb->srb_datalen; 824 } 825 826 hvs_put_ccb(sc, ccb); 827 hvs_scsi_done(xs, error); 828} 829 830static void 831hvs_scsi_probe(void *arg) 832{ 833 struct hvs_softc *sc = arg; 834 835 if (sc->sc_scsibus != NULL) 836 scsi_probe_bus(device_private(sc->sc_scsibus), -1, -1); 837} 838 839static void 840hvs_scsi_done(struct scsipi_xfer *xs, int error) 841{ 842 843 xs->error = error; 844 scsipi_done(xs); 845} 846 847static int 848hvs_connect(struct hvs_softc *sc) 849{ 850 union hvs_cmd ucmd; 851 struct hvs_cmd_ver *cmd; 852 struct hvs_chp *chp; 853 struct hvs_ccb *ccb; 854#if notyet /* XXX subchannel */ 855 struct vmbus_softc *vsc; 856 struct vmbus_channel **subchan; 857 uint32_t version; 858 uint16_t max_subch, req_subch; 859 bool support_multichannel = false; 860#endif 861 int i; 862 863 ccb = hvs_get_ccb(sc); 864 if (ccb == NULL) { 865 aprint_error_dev(sc->sc_dev, "failed to allocate ccb\n"); 866 return -1; 867 } 868 869 ccb->ccb_done = hvs_empty_done; 870 871 cmd = (struct hvs_cmd_ver *)&ucmd; 872 873 /* 874 * Begin initialization 875 */ 876 877 memset(&ucmd, 0, sizeof(ucmd)); 878 879 cmd->cmd_op = HVS_REQ_STARTINIT; 880 cmd->cmd_flags = VMBUS_CHANPKT_FLAG_RC; 881 882 ccb->ccb_cmd = &ucmd; 883 if (hvs_poll(sc, sc->sc_chan, ccb)) { 884 aprint_error_dev(sc->sc_dev, 885 "failed to send initialization command\n"); 886 goto error; 887 } 888 if (ccb->ccb_rsp.cmd_status != 0) { 889 aprint_error_dev(sc->sc_dev, 890 "failed to initialize, status %#x\n", 891 ccb->ccb_rsp.cmd_status); 892 goto error; 893 } 894 895 /* 896 * Negotiate protocol version 897 */ 898 899 memset(&ucmd, 0, sizeof(ucmd)); 900 901 cmd->cmd_op = HVS_REQ_QUERYPROTO; 902 cmd->cmd_flags = VMBUS_CHANPKT_FLAG_RC; 903 904 for (i = 0; i < __arraycount(hvs_config_list); i++) { 905 cmd->cmd_ver = hvs_config_list[i].proto_version; 906 907 ccb->ccb_cmd = &ucmd; 908 if (hvs_poll(sc, sc->sc_chan, ccb)) { 909 aprint_error_dev(sc->sc_dev, 910 "failed to send protocol query\n"); 911 goto error; 912 } 913 if (ccb->ccb_rsp.cmd_status == 0) { 914 sc->sc_config = &hvs_config_list[i]; 915 break; 916 } 917 } 918 if (sc->sc_config == NULL) { 919 aprint_error_dev(sc->sc_dev, 920 "failed to negotiate protocol version\n"); 921 goto error; 922 } 923 924 /* 925 * Query channel properties 926 */ 927 928 memset(&ucmd, 0, sizeof(ucmd)); 929 930 cmd->cmd_op = HVS_REQ_QUERYPROPS; 931 cmd->cmd_flags = VMBUS_CHANPKT_FLAG_RC; 932 933 ccb->ccb_cmd = &ucmd; 934 if (hvs_poll(sc, sc->sc_chan, ccb)) { 935 aprint_error_dev(sc->sc_dev, 936 "failed to send channel properties query\n"); 937 goto error; 938 } 939 if (ccb->ccb_rsp.cmd_op != HVS_MSG_IODONE || 940 ccb->ccb_rsp.cmd_status != 0) { 941 aprint_error_dev(sc->sc_dev, 942 "failed to obtain channel properties, status %#x\n", 943 ccb->ccb_rsp.cmd_status); 944 goto error; 945 } 946 chp = &ccb->ccb_rsp.chp.cmd_chp; 947 948 DPRINTF("%s: proto %#x path %u target %u maxchan %u port %u " 949 "chflags %#x maxfer %u chanid %#"PRIx64"\n", 950 device_xname(sc->sc_dev), chp->chp_proto, chp->chp_path, 951 chp->chp_target, chp->chp_maxchan, chp->chp_port, 952 chp->chp_chflags, chp->chp_maxfer, chp->chp_chanid); 953 954#if notyet /* XXX subchannel */ 955 max_subch = chp->chp_maxchan; 956 if (hvs_chan_cnt > 0 && hvs_chan_cnt < (max_subch + 1)) 957 max_subch = hvs_chan_cnt - 1; 958 959 /* multi-channels feature is supported by WIN8 and above version */ 960 version = sc->sc_chan->ch_sc->sc_proto; 961 if (version != VMBUS_VERSION_WIN7 && version != VMBUS_VERSION_WS2008 && 962 ISSET(chp->chp_chflags, CHP_CHFLAGS_MULTI_CHANNEL)) 963 support_multichannel = true; 964#endif 965 966 /* XXX */ 967 sc->sc_bus = chp->chp_path; 968 sc->sc_channel.chan_id = chp->chp_target; 969 970 /* 971 * Finish initialization 972 */ 973 974 memset(&ucmd, 0, sizeof(ucmd)); 975 976 cmd->cmd_op = HVS_REQ_FINISHINIT; 977 cmd->cmd_flags = VMBUS_CHANPKT_FLAG_RC; 978 979 ccb->ccb_cmd = &ucmd; 980 if (hvs_poll(sc, sc->sc_chan, ccb)) { 981 aprint_error_dev(sc->sc_dev, 982 "failed to send initialization finish\n"); 983 goto error; 984 } 985 if (ccb->ccb_rsp.cmd_op != HVS_MSG_IODONE || 986 ccb->ccb_rsp.cmd_status != 0) { 987 aprint_error_dev(sc->sc_dev, 988 "failed to finish initialization, status %#x\n", 989 ccb->ccb_rsp.cmd_status); 990 goto error; 991 } 992 993#if notyet /* XXX subchannel */ 994 if (support_multichannel && max_subch > 0 && ncpu > 1) { 995 req_subch = MIN(max_subch, ncpu - 1); 996 997 memset(&ucmd, 0, sizeof(ucmd)); 998 999 cmd->cmd_op = HVS_REQ_CREATEMULTICHANNELS; 1000 cmd->cmd_flags = VMBUS_CHANPKT_FLAG_RC; 1001 cmd->u.multi_chans_cnt = req_subch; 1002 1003 ccb->ccb_cmd = &ucmd; 1004 if (hvs_poll(sc, sc->sc_chan, ccb)) { 1005 aprint_error_dev(sc->sc_dev, 1006 "failed to send create multi-channel\n"); 1007 goto out; 1008 } 1009 if (ccb->ccb_rsp.cmd_op != HVS_MSG_IODONE || 1010 ccb->ccb_rsp.cmd_status != 0) { 1011 aprint_error_dev(sc->sc_dev, 1012 "failed to create multi-channel, status %#x\n", 1013 ccb->ccb_rsp.cmd_status); 1014 goto out; 1015 } 1016 1017 sc->sc_nchan = req_subch + 1; 1018 subchan = vmbus_subchan_get(sc->sc_chan, req_subch); 1019 for (i = 0; i < req_subch; i++) 1020 hsv_subchan_attach(sc, subchan[i]); 1021 vmbus_subchan_rel(subchan, req_subch); 1022 aprint_normal_dev(sc->sc_dev, "using %u channels\n", 1023 sc->sc_nchan); 1024 } 1025out: 1026#endif 1027 hvs_put_ccb(sc, ccb); 1028 return 0; 1029 1030error: 1031 hvs_put_ccb(sc, ccb); 1032 return -1; 1033} 1034 1035static void 1036hvs_empty_done(struct hvs_ccb *ccb) 1037{ 1038 /* nothing */ 1039} 1040 1041static int 1042hvs_alloc_ccbs(struct hvs_softc *sc) 1043{ 1044 const int dmaflags = cold ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK; 1045 int i, error; 1046 1047 SIMPLEQ_INIT(&sc->sc_ccb_fq); 1048 mutex_init(&sc->sc_ccb_fqlck, MUTEX_DEFAULT, IPL_BIO); 1049 1050 sc->sc_nccb = HVS_MAX_CCB; 1051 sc->sc_ccbs = kmem_zalloc(sc->sc_nccb * sizeof(struct hvs_ccb), 1052 KM_SLEEP); 1053 1054 for (i = 0; i < sc->sc_nccb; i++) { 1055 error = bus_dmamap_create(sc->sc_dmat, MAXPHYS, HVS_MAX_SGE, 1056 PAGE_SIZE, PAGE_SIZE, dmaflags, &sc->sc_ccbs[i].ccb_dmap); 1057 if (error) { 1058 aprint_error_dev(sc->sc_dev, 1059 "failed to create a CCB memory map (%d)\n", error); 1060 goto errout; 1061 } 1062 1063 sc->sc_ccbs[i].ccb_sgl = kmem_zalloc( 1064 sizeof(struct vmbus_gpa_range) * (HVS_MAX_SGE + 1), 1065 KM_SLEEP); 1066 sc->sc_ccbs[i].ccb_rid = i; 1067 hvs_put_ccb(sc, &sc->sc_ccbs[i]); 1068 } 1069 1070 return 0; 1071 1072 errout: 1073 hvs_free_ccbs(sc); 1074 return -1; 1075} 1076 1077static void 1078hvs_free_ccbs(struct hvs_softc *sc) 1079{ 1080 struct hvs_ccb *ccb; 1081 int i; 1082 1083 for (i = 0; i < sc->sc_nccb; i++) { 1084 ccb = &sc->sc_ccbs[i]; 1085 if (ccb->ccb_dmap == NULL) 1086 continue; 1087 1088 bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmap, 1089 0, ccb->ccb_dmap->dm_mapsize, 1090 BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 1091 bus_dmamap_unload(sc->sc_dmat, ccb->ccb_dmap); 1092 bus_dmamap_destroy(sc->sc_dmat, ccb->ccb_dmap); 1093 1094 kmem_free(ccb->ccb_sgl, 1095 sizeof(struct vmbus_gpa_range) * (HVS_MAX_SGE + 1)); 1096 } 1097 1098 kmem_free(sc->sc_ccbs, sc->sc_nccb * sizeof(struct hvs_ccb)); 1099 sc->sc_ccbs = NULL; 1100 sc->sc_nccb = 0; 1101} 1102 1103static struct hvs_ccb * 1104hvs_get_ccb(struct hvs_softc *sc) 1105{ 1106 struct hvs_ccb *ccb; 1107 1108 mutex_enter(&sc->sc_ccb_fqlck); 1109 ccb = SIMPLEQ_FIRST(&sc->sc_ccb_fq); 1110 if (ccb != NULL) 1111 SIMPLEQ_REMOVE_HEAD(&sc->sc_ccb_fq, ccb_link); 1112 mutex_exit(&sc->sc_ccb_fqlck); 1113 1114 return ccb; 1115} 1116 1117static void 1118hvs_put_ccb(struct hvs_softc *sc, struct hvs_ccb *ccb) 1119{ 1120 1121 ccb->ccb_cmd = NULL; 1122 ccb->ccb_xfer = NULL; 1123 ccb->ccb_done = NULL; 1124 ccb->ccb_cookie = NULL; 1125 ccb->ccb_nsge = 0; 1126 1127 mutex_enter(&sc->sc_ccb_fqlck); 1128 SIMPLEQ_INSERT_HEAD(&sc->sc_ccb_fq, ccb, ccb_link); 1129 mutex_exit(&sc->sc_ccb_fqlck); 1130} 1131