LCOV - code coverage report
Current view: top level - dev/pv - hvs.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 398 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 18 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-
       2             :  * Copyright (c) 2009-2012,2016 Microsoft Corp.
       3             :  * Copyright (c) 2012 NetApp Inc.
       4             :  * Copyright (c) 2012 Citrix Inc.
       5             :  * Copyright (c) 2017 Mike Belopuhov <mike@esdenera.com>
       6             :  * All rights reserved.
       7             :  *
       8             :  * Redistribution and use in source and binary forms, with or without
       9             :  * modification, are permitted provided that the following conditions
      10             :  * are met:
      11             :  * 1. Redistributions of source code must retain the above copyright
      12             :  *    notice unmodified, this list of conditions, and the following
      13             :  *    disclaimer.
      14             :  * 2. Redistributions in binary form must reproduce the above copyright
      15             :  *    notice, this list of conditions and the following disclaimer in the
      16             :  *    documentation and/or other materials provided with the distribution.
      17             :  *
      18             :  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
      19             :  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
      20             :  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
      21             :  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
      22             :  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
      23             :  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
      24             :  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      25             :  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
      26             :  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
      27             :  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      28             :  */
      29             : 
      30             : /*
      31             :  * The OpenBSD port was done under funding by Esdenera Networks GmbH.
      32             :  */
      33             : 
      34             : /* #define HVS_DEBUG_IO */
      35             : 
      36             : #include <sys/param.h>
      37             : #include <sys/systm.h>
      38             : #include <sys/atomic.h>
      39             : #include <sys/device.h>
      40             : #include <sys/kernel.h>
      41             : #include <sys/buf.h>
      42             : #include <sys/malloc.h>
      43             : #include <sys/task.h>
      44             : 
      45             : #include <machine/bus.h>
      46             : 
      47             : #include <uvm/uvm_extern.h>
      48             : 
      49             : #include <dev/pv/hypervreg.h>
      50             : #include <dev/pv/hypervvar.h>
      51             : 
      52             : #include <scsi/scsi_all.h>
      53             : #include <scsi/cd.h>
      54             : #include <scsi/scsi_disk.h>
      55             : #include <scsi/scsiconf.h>
      56             : 
      57             : #define HVS_PROTO_VERSION_WIN6           0x200
      58             : #define HVS_PROTO_VERSION_WIN7           0x402
      59             : #define HVS_PROTO_VERSION_WIN8           0x501
      60             : #define HVS_PROTO_VERSION_WIN8_1         0x600
      61             : #define HVS_PROTO_VERSION_WIN10          0x602
      62             : 
      63             : #define HVS_MSG_IODONE                   0x01
      64             : #define HVS_MSG_DEVGONE                  0x02
      65             : #define HVS_MSG_ENUMERATE                0x0b
      66             : 
      67             : #define HVS_REQ_SCSIIO                   0x03
      68             : #define HVS_REQ_STARTINIT                0x07
      69             : #define HVS_REQ_FINISHINIT               0x08
      70             : #define HVS_REQ_QUERYPROTO               0x09
      71             : #define HVS_REQ_QUERYPROPS               0x0a
      72             : 
      73             : struct hvs_cmd_hdr {
      74             :         uint32_t                 hdr_op;
      75             :         uint32_t                 hdr_flags;
      76             :         uint32_t                 hdr_status;
      77             : #define cmd_op                   cmd_hdr.hdr_op
      78             : #define cmd_flags                cmd_hdr.hdr_flags
      79             : #define cmd_status               cmd_hdr.hdr_status
      80             : } __packed;
      81             : 
      82             : /* Negotiate version */
      83             : struct hvs_cmd_ver {
      84             :         struct hvs_cmd_hdr       cmd_hdr;
      85             :         uint16_t                 cmd_ver;
      86             :         uint16_t                 cmd_rev;
      87             : } __packed;
      88             : 
      89             : /* Query channel properties */
      90             : struct hvs_chp {
      91             :         uint16_t                 chp_proto;
      92             :         uint8_t                  chp_path;
      93             :         uint8_t                  chp_target;
      94             :         uint16_t                 chp_maxchan;
      95             :         uint16_t                 chp_port;
      96             :         uint32_t                 chp_chflags;
      97             :         uint32_t                 chp_maxfer;
      98             :         uint64_t                 chp_chanid;
      99             : } __packed;
     100             : 
     101             : struct hvs_cmd_chp {
     102             :         struct hvs_cmd_hdr       cmd_hdr;
     103             :         struct hvs_chp           cmd_chp;
     104             : } __packed;
     105             : 
     106             : #define SENSE_DATA_LEN_WIN7              18
     107             : #define SENSE_DATA_LEN                   20
     108             : #define MAX_SRB_DATA                     20
     109             : 
     110             : /* SCSI Request Block */
     111             : struct hvs_srb {
     112             :         uint16_t                 srb_reqlen;
     113             :         uint8_t                  srb_iostatus;
     114             :         uint8_t                  srb_scsistatus;
     115             : 
     116             :         uint8_t                  srb_initiator;
     117             :         uint8_t                  srb_bus;
     118             :         uint8_t                  srb_target;
     119             :         uint8_t                  srb_lun;
     120             : 
     121             :         uint8_t                  srb_cdblen;
     122             :         uint8_t                  srb_senselen;
     123             :         uint8_t                  srb_direction;
     124             :         uint8_t                  _reserved;
     125             : 
     126             :         uint32_t                 srb_datalen;
     127             :         uint8_t                  srb_data[MAX_SRB_DATA];
     128             : } __packed;
     129             : 
     130             : #define SRB_DATA_WRITE                   0
     131             : #define SRB_DATA_READ                    1
     132             : #define SRB_DATA_NONE                    2
     133             : 
     134             : #define SRB_STATUS_PENDING               0x00
     135             : #define SRB_STATUS_SUCCESS               0x01
     136             : #define SRB_STATUS_ABORTED               0x02
     137             : #define SRB_STATUS_ERROR                 0x04
     138             : #define SRB_STATUS_INVALID_LUN           0x20
     139             : #define SRB_STATUS_QUEUE_FROZEN          0x40
     140             : #define SRB_STATUS_AUTOSENSE_VALID       0x80
     141             : 
     142             : #define SRB_FLAGS_QUEUE_ACTION_ENABLE    0x00000002
     143             : #define SRB_FLAGS_DISABLE_DISCONNECT     0x00000004
     144             : #define SRB_FLAGS_DISABLE_SYNCH_TRANSFER 0x00000008
     145             : #define SRB_FLAGS_BYPASS_FROZEN_QUEUE    0x00000010
     146             : #define SRB_FLAGS_DISABLE_AUTOSENSE      0x00000020
     147             : #define SRB_FLAGS_DATA_IN                0x00000040
     148             : #define SRB_FLAGS_DATA_OUT               0x00000080
     149             : #define SRB_FLAGS_NO_DATA_TRANSFER       0x00000000
     150             : #define SRB_FLAGS_NO_QUEUE_FREEZE        0x00000100
     151             : #define SRB_FLAGS_ADAPTER_CACHE_ENABLE   0x00000200
     152             : #define SRB_FLAGS_FREE_SENSE_BUFFER      0x00000400
     153             : 
     154             : struct hvs_cmd_io {
     155             :         struct hvs_cmd_hdr       cmd_hdr;
     156             :         struct hvs_srb           cmd_srb;
     157             :         /* Win8 extensions */
     158             :         uint16_t                 _reserved;
     159             :         uint8_t                  cmd_qtag;
     160             :         uint8_t                  cmd_qaction;
     161             :         uint32_t                 cmd_srbflags;
     162             :         uint32_t                 cmd_timeout;
     163             :         uint32_t                 cmd_qsortkey;
     164             : } __packed;
     165             : 
     166             : #define HVS_CMD_SIZE                     64
     167             : 
     168             : union hvs_cmd {
     169             :         struct hvs_cmd_hdr       cmd_hdr;
     170             :         struct hvs_cmd_ver       ver;
     171             :         struct hvs_cmd_chp       chp;
     172             :         struct hvs_cmd_io        io;
     173             :         uint8_t                  pad[HVS_CMD_SIZE];
     174             : } __packed;
     175             : 
     176             : #define HVS_RING_SIZE                    (20 * PAGE_SIZE)
     177             : #define HVS_MAX_CCB                      128
     178             : #define HVS_MAX_SGE                      (MAXPHYS / PAGE_SIZE + 1)
     179             : 
     180             : struct hvs_softc;
     181             : 
     182             : struct hvs_ccb {
     183             :         struct scsi_xfer        *ccb_xfer;  /* associated transfer */
     184             :         union hvs_cmd           *ccb_cmd;   /* associated command */
     185             :         union hvs_cmd            ccb_rsp;   /* response */
     186             :         bus_dmamap_t             ccb_dmap;  /* transfer map */
     187             :         uint64_t                 ccb_rid;   /* request id */
     188             :         struct vmbus_gpa_range  *ccb_sgl;
     189             :         int                      ccb_nsge;
     190             :         void                    (*ccb_done)(struct hvs_ccb *);
     191             :         void                    *ccb_cookie;
     192             :         SIMPLEQ_ENTRY(hvs_ccb)   ccb_link;
     193             : };
     194             : SIMPLEQ_HEAD(hvs_ccb_queue, hvs_ccb);
     195             : 
     196             : struct hvs_softc {
     197             :         struct device            sc_dev;
     198             :         struct hv_softc         *sc_hvsc;
     199             :         struct hv_channel       *sc_chan;
     200             :         bus_dma_tag_t            sc_dmat;
     201             : 
     202             :         int                      sc_proto;
     203             :         int                      sc_flags;
     204             : #define  HVSF_SCSI                0x0001
     205             : #define  HVSF_W8PLUS              0x0002
     206             :         struct hvs_chp           sc_props;
     207             : 
     208             :         /* CCBs */
     209             :         int                      sc_nccb;
     210             :         struct hvs_ccb          *sc_ccbs;
     211             :         struct hvs_ccb_queue     sc_ccb_fq; /* free queue */
     212             :         struct mutex             sc_ccb_fqlck;
     213             : 
     214             :         int                      sc_bus;
     215             :         int                      sc_initiator;
     216             : 
     217             :         struct scsi_iopool       sc_iopool;
     218             :         struct scsi_adapter      sc_switch;
     219             :         struct scsi_link         sc_link;
     220             :         struct device           *sc_scsibus;
     221             :         struct task              sc_probetask;
     222             : };
     223             : 
     224             : int     hvs_match(struct device *, void *, void *);
     225             : void    hvs_attach(struct device *, struct device *, void *);
     226             : 
     227             : void    hvs_scsi_cmd(struct scsi_xfer *);
     228             : void    hvs_scsi_cmd_done(struct hvs_ccb *);
     229             : int     hvs_start(struct hvs_softc *, struct hvs_ccb *);
     230             : int     hvs_poll(struct hvs_softc *, struct hvs_ccb *);
     231             : void    hvs_poll_done(struct hvs_ccb *);
     232             : void    hvs_intr(void *);
     233             : void    hvs_scsi_probe(void *arg);
     234             : void    hvs_scsi_done(struct scsi_xfer *, int);
     235             : 
     236             : int     hvs_connect(struct hvs_softc *);
     237             : void    hvs_empty_done(struct hvs_ccb *);
     238             : 
     239             : int     hvs_alloc_ccbs(struct hvs_softc *);
     240             : void    hvs_free_ccbs(struct hvs_softc *);
     241             : void    *hvs_get_ccb(void *);
     242             : void    hvs_put_ccb(void *, void *);
     243             : 
     244             : struct cfdriver hvs_cd = {
     245             :         NULL, "hvs", DV_DULL
     246             : };
     247             : 
     248             : const struct cfattach hvs_ca = {
     249             :         sizeof(struct hvs_softc), hvs_match, hvs_attach
     250             : };
     251             : 
     252             : int
     253           0 : hvs_match(struct device *parent, void *match, void *aux)
     254             : {
     255           0 :         struct hv_attach_args *aa = aux;
     256             : 
     257           0 :         if (strcmp("ide", aa->aa_ident) &&
     258           0 :             strcmp("scsi", aa->aa_ident))
     259           0 :                 return (0);
     260             : 
     261           0 :         return (1);
     262           0 : }
     263             : 
     264             : void
     265           0 : hvs_attach(struct device *parent, struct device *self, void *aux)
     266             : {
     267           0 :         struct hv_attach_args *aa = aux;
     268           0 :         struct hvs_softc *sc = (struct hvs_softc *)self;
     269           0 :         struct scsibus_attach_args saa;
     270             :         extern int pciide_skip_ata;
     271             : 
     272           0 :         sc->sc_hvsc = (struct hv_softc *)parent;
     273           0 :         sc->sc_chan = aa->aa_chan;
     274           0 :         sc->sc_dmat = aa->aa_dmat;
     275             : 
     276           0 :         printf(" channel %u: %s", sc->sc_chan->ch_id, aa->aa_ident);
     277             : 
     278           0 :         if (strcmp("scsi", aa->aa_ident) == 0)
     279           0 :                 sc->sc_flags |= HVSF_SCSI;
     280             : 
     281           0 :         if (hv_channel_setdeferred(sc->sc_chan, sc->sc_dev.dv_xname)) {
     282           0 :                 printf(": failed to create the interrupt thread\n");
     283           0 :                 return;
     284             :         }
     285             : 
     286           0 :         if (hv_channel_open(sc->sc_chan, HVS_RING_SIZE, &sc->sc_props,
     287           0 :             sizeof(sc->sc_props), hvs_intr, sc)) {
     288           0 :                 printf(": failed to open channel\n");
     289           0 :                 return;
     290             :         }
     291             : 
     292           0 :         hv_evcount_attach(sc->sc_chan, sc->sc_dev.dv_xname);
     293             : 
     294           0 :         if (hvs_alloc_ccbs(sc))
     295           0 :                 return;
     296             : 
     297           0 :         if (hvs_connect(sc))
     298           0 :                 return;
     299             : 
     300           0 :         printf(", protocol %u.%u\n", (sc->sc_proto >> 8) & 0xff,
     301           0 :             sc->sc_proto & 0xff);
     302             : 
     303           0 :         if (sc->sc_proto >= HVS_PROTO_VERSION_WIN8)
     304           0 :                 sc->sc_flags |= HVSF_W8PLUS;
     305             : 
     306           0 :         task_set(&sc->sc_probetask, hvs_scsi_probe, sc);
     307             : 
     308           0 :         sc->sc_switch.scsi_cmd = hvs_scsi_cmd;
     309           0 :         sc->sc_switch.scsi_minphys = scsi_minphys;
     310             : 
     311           0 :         sc->sc_link.adapter = &sc->sc_switch;
     312           0 :         sc->sc_link.adapter_softc = self;
     313           0 :         sc->sc_link.luns = sc->sc_flags & HVSF_SCSI ? 64 : 1;
     314           0 :         sc->sc_link.adapter_buswidth = 2;
     315           0 :         sc->sc_link.adapter_target = 2;
     316           0 :         sc->sc_link.openings = sc->sc_nccb;
     317           0 :         sc->sc_link.pool = &sc->sc_iopool;
     318             : 
     319           0 :         memset(&saa, 0, sizeof(saa));
     320           0 :         saa.saa_sc_link = &sc->sc_link;
     321           0 :         sc->sc_scsibus = config_found(self, &saa, scsiprint);
     322             : 
     323             :         /*
     324             :          * If the driver has successfully attached to an IDE
     325             :          * device, we need to make sure that the same disk is
     326             :          * not available to the system via pciide(4) causing
     327             :          * DUID conflicts and preventing system from booting.
     328             :          */
     329           0 :         if (!(sc->sc_flags & HVSF_SCSI) && sc->sc_scsibus)
     330           0 :                 pciide_skip_ata = 1;
     331           0 : }
     332             : 
     333             : void
     334           0 : hvs_scsi_cmd(struct scsi_xfer *xs)
     335             : {
     336           0 :         struct scsi_link *link = xs->sc_link;
     337           0 :         struct hvs_softc *sc = link->adapter_softc;
     338           0 :         struct hvs_ccb *ccb = xs->io;
     339           0 :         union hvs_cmd cmd;
     340           0 :         struct hvs_cmd_io *io = &cmd.io;
     341           0 :         struct hvs_srb *srb = &io->cmd_srb;
     342             :         int i, rv, flags = BUS_DMA_NOWAIT;
     343             : 
     344           0 :         if (xs->cmdlen > MAX_SRB_DATA) {
     345           0 :                 printf("%s: CDB is too big: %d\n", sc->sc_dev.dv_xname,
     346             :                     xs->cmdlen);
     347           0 :                 memset(&xs->sense, 0, sizeof(xs->sense));
     348           0 :                 xs->sense.error_code = SSD_ERRCODE_VALID | 0x70;
     349           0 :                 xs->sense.flags = SKEY_ILLEGAL_REQUEST;
     350           0 :                 xs->sense.add_sense_code = 0x20;
     351           0 :                 hvs_scsi_done(xs, XS_SENSE);
     352           0 :                 return;
     353             :         }
     354             : 
     355           0 :         KERNEL_UNLOCK();
     356             : 
     357           0 :         memset(&cmd, 0, sizeof(cmd));
     358             : 
     359           0 :         srb->srb_initiator = sc->sc_initiator;
     360           0 :         srb->srb_bus = sc->sc_bus;
     361           0 :         srb->srb_target = link->target;
     362           0 :         srb->srb_lun = link->lun;
     363             : 
     364           0 :         srb->srb_cdblen = xs->cmdlen;
     365           0 :         memcpy(srb->srb_data, xs->cmd, xs->cmdlen);
     366             : 
     367           0 :         switch (xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) {
     368             :         case SCSI_DATA_IN:
     369           0 :                 srb->srb_direction = SRB_DATA_READ;
     370           0 :                 if (sc->sc_flags & HVSF_W8PLUS)
     371           0 :                         io->cmd_srbflags |= SRB_FLAGS_DATA_IN;
     372             :                 flags |= BUS_DMA_WRITE;
     373           0 :                 break;
     374             :         case SCSI_DATA_OUT:
     375           0 :                 srb->srb_direction = SRB_DATA_WRITE;
     376           0 :                 if (sc->sc_flags & HVSF_W8PLUS)
     377           0 :                         io->cmd_srbflags |= SRB_FLAGS_DATA_OUT;
     378             :                 flags |= BUS_DMA_READ;
     379           0 :                 break;
     380             :         default:
     381           0 :                 srb->srb_direction = SRB_DATA_NONE;
     382           0 :                 if (sc->sc_flags & HVSF_W8PLUS)
     383           0 :                         io->cmd_srbflags |= SRB_FLAGS_NO_DATA_TRANSFER;
     384             :                 break;
     385             :         }
     386             : 
     387           0 :         srb->srb_datalen = xs->datalen;
     388             : 
     389           0 :         if (sc->sc_flags & HVSF_W8PLUS) {
     390           0 :                 srb->srb_reqlen = sizeof(*io);
     391           0 :                 srb->srb_senselen = SENSE_DATA_LEN;
     392           0 :         } else {
     393           0 :                 srb->srb_reqlen = sizeof(struct hvs_cmd_hdr) +
     394             :                     sizeof(struct hvs_srb);
     395           0 :                 srb->srb_senselen = SENSE_DATA_LEN_WIN7;
     396             :         }
     397             : 
     398           0 :         cmd.cmd_op = HVS_REQ_SCSIIO;
     399           0 :         cmd.cmd_flags = VMBUS_CHANPKT_FLAG_RC;
     400             : 
     401           0 :         if (xs->datalen > 0) {
     402           0 :                 rv = bus_dmamap_load(sc->sc_dmat, ccb->ccb_dmap, xs->data,
     403             :                     xs->datalen, NULL, flags);
     404           0 :                 if (rv) {
     405           0 :                         printf("%s: failed to load %d bytes (%d)\n",
     406           0 :                             sc->sc_dev.dv_xname, xs->datalen, rv);
     407           0 :                         KERNEL_LOCK();
     408           0 :                         hvs_scsi_done(xs, XS_DRIVER_STUFFUP);
     409           0 :                         return;
     410             :                 }
     411             : 
     412           0 :                 ccb->ccb_sgl->gpa_len = xs->datalen;
     413           0 :                 ccb->ccb_sgl->gpa_ofs = (vaddr_t)xs->data & PAGE_MASK;
     414           0 :                 for (i = 0; i < ccb->ccb_dmap->dm_nsegs; i++)
     415           0 :                         ccb->ccb_sgl->gpa_page[i] =
     416           0 :                             atop(ccb->ccb_dmap->dm_segs[i].ds_addr);
     417           0 :                 ccb->ccb_nsge = ccb->ccb_dmap->dm_nsegs;
     418           0 :         } else
     419           0 :                 ccb->ccb_nsge = 0;
     420             : 
     421           0 :         ccb->ccb_xfer = xs;
     422           0 :         ccb->ccb_cmd = &cmd;
     423           0 :         ccb->ccb_done = hvs_scsi_cmd_done;
     424             : 
     425             : #ifdef HVS_DEBUG_IO
     426             :         DPRINTF("%s: %u.%u: rid %llu opcode %#x flags %#x datalen %d\n",
     427             :             sc->sc_dev.dv_xname, link->target, link->lun, ccb->ccb_rid,
     428             :             xs->cmd->opcode, xs->flags, xs->datalen);
     429             : #endif
     430             : 
     431           0 :         if (xs->flags & SCSI_POLL)
     432           0 :                 rv = hvs_poll(sc, ccb);
     433             :         else
     434           0 :                 rv = hvs_start(sc, ccb);
     435           0 :         if (rv) {
     436           0 :                 KERNEL_LOCK();
     437           0 :                 hvs_scsi_done(xs, XS_DRIVER_STUFFUP);
     438           0 :                 return;
     439             :         }
     440             : 
     441           0 :         KERNEL_LOCK();
     442           0 : }
     443             : 
     444             : int
     445           0 : hvs_start(struct hvs_softc *sc, struct hvs_ccb *ccb)
     446             : {
     447           0 :         union hvs_cmd *cmd = ccb->ccb_cmd;
     448             :         int rv;
     449             : 
     450           0 :         ccb->ccb_cmd = NULL;
     451             : 
     452           0 :         if (ccb->ccb_nsge > 0) {
     453           0 :                 rv = hv_channel_send_prpl(sc->sc_chan, ccb->ccb_sgl,
     454           0 :                     ccb->ccb_nsge, cmd, HVS_CMD_SIZE, ccb->ccb_rid);
     455           0 :                 if (rv) {
     456           0 :                         printf("%s: failed to submit operation %x via prpl\n",
     457           0 :                             sc->sc_dev.dv_xname, cmd->cmd_op);
     458           0 :                         bus_dmamap_unload(sc->sc_dmat, ccb->ccb_dmap);
     459           0 :                 }
     460             :         } else {
     461           0 :                 rv = hv_channel_send(sc->sc_chan, cmd, HVS_CMD_SIZE,
     462           0 :                     ccb->ccb_rid, VMBUS_CHANPKT_TYPE_INBAND,
     463             :                     VMBUS_CHANPKT_FLAG_RC);
     464           0 :                 if (rv)
     465           0 :                         printf("%s: failed to submit operation %x\n",
     466           0 :                             sc->sc_dev.dv_xname, cmd->cmd_op);
     467             :         }
     468             : 
     469           0 :         return (rv);
     470             : }
     471             : 
     472             : void
     473           0 : hvs_poll_done(struct hvs_ccb *ccb)
     474             : {
     475           0 :         int *rv = ccb->ccb_cookie;
     476             : 
     477           0 :         if (ccb->ccb_cmd) {
     478           0 :                 memcpy(&ccb->ccb_rsp, ccb->ccb_cmd, HVS_CMD_SIZE);
     479           0 :                 ccb->ccb_cmd = &ccb->ccb_rsp;
     480           0 :         } else
     481           0 :                 memset(&ccb->ccb_rsp, 0, HVS_CMD_SIZE);
     482             : 
     483           0 :         *rv = 0;
     484           0 : }
     485             : 
     486             : int
     487           0 : hvs_poll(struct hvs_softc *sc, struct hvs_ccb *ccb)
     488             : {
     489             :         void (*done)(struct hvs_ccb *);
     490             :         void *cookie;
     491           0 :         int s, rv = 1;
     492             : 
     493           0 :         done = ccb->ccb_done;
     494           0 :         cookie = ccb->ccb_cookie;
     495             : 
     496           0 :         ccb->ccb_done = hvs_poll_done;
     497           0 :         ccb->ccb_cookie = &rv;
     498             : 
     499           0 :         if (hvs_start(sc, ccb)) {
     500           0 :                 ccb->ccb_cookie = cookie;
     501           0 :                 ccb->ccb_done = done;
     502           0 :                 return (-1);
     503             :         }
     504             : 
     505           0 :         while (rv == 1) {
     506           0 :                 delay(10);
     507           0 :                 s = splbio();
     508           0 :                 hvs_intr(sc);
     509           0 :                 splx(s);
     510             :         }
     511             : 
     512           0 :         ccb->ccb_cookie = cookie;
     513           0 :         ccb->ccb_done = done;
     514           0 :         ccb->ccb_done(ccb);
     515             : 
     516           0 :         return (0);
     517           0 : }
     518             : 
     519             : void
     520           0 : hvs_intr(void *xsc)
     521             : {
     522           0 :         struct hvs_softc *sc = xsc;
     523             :         struct hvs_ccb *ccb;
     524           0 :         union hvs_cmd cmd;
     525           0 :         uint64_t rid;
     526           0 :         uint32_t rlen;
     527             :         int rv;
     528             : 
     529           0 :         for (;;) {
     530           0 :                 rv = hv_channel_recv(sc->sc_chan, &cmd, sizeof(cmd), &rlen,
     531             :                     &rid, 0);
     532           0 :                 switch (rv) {
     533             :                 case 0:
     534             :                         break;
     535             :                 case EAGAIN:
     536             :                         /* No more messages to process */
     537           0 :                         return;
     538             :                 default:
     539           0 :                         printf("%s: error %d while receiving a reply\n",
     540           0 :                             sc->sc_dev.dv_xname, rv);
     541           0 :                         return;
     542             :                 }
     543           0 :                 if (rlen != sizeof(cmd)) {
     544           0 :                         printf("%s: short read: %u\n", sc->sc_dev.dv_xname,
     545             :                             rlen);
     546           0 :                         return;
     547             :                 }
     548             : 
     549             : #ifdef HVS_DEBUG_IO
     550             :                 DPRINTF("%s: rid %llu opertaion %u flags %#x status %#x\n",
     551             :                     sc->sc_dev.dv_xname, rid, cmd.cmd_op, cmd.cmd_flags,
     552             :                     cmd.cmd_status);
     553             : #endif
     554             : 
     555           0 :                 switch (cmd.cmd_op) {
     556             :                 case HVS_MSG_IODONE:
     557           0 :                         if (rid >= sc->sc_nccb) {
     558           0 :                                 printf("%s: invalid response %#llx\n",
     559           0 :                                     sc->sc_dev.dv_xname, rid);
     560           0 :                                 continue;
     561             :                         }
     562           0 :                         ccb = &sc->sc_ccbs[rid];
     563           0 :                         ccb->ccb_cmd = &cmd;
     564           0 :                         ccb->ccb_done(ccb);
     565           0 :                         break;
     566             :                 case HVS_MSG_ENUMERATE:
     567           0 :                         task_add(systq, &sc->sc_probetask);
     568           0 :                         break;
     569             :                 default:
     570           0 :                         printf("%s: operation %u is not implemented\n",
     571           0 :                             sc->sc_dev.dv_xname, cmd.cmd_op);
     572           0 :                 }
     573             :         }
     574           0 : }
     575             : 
     576             : static inline int
     577           0 : is_inquiry_valid(struct scsi_inquiry_data *inq)
     578             : {
     579           0 :         if ((inq->device & SID_TYPE) == T_NODEVICE)
     580           0 :                 return (0);
     581           0 :         if ((inq->device & SID_QUAL) == SID_QUAL_BAD_LU)
     582           0 :                 return (0);
     583           0 :         return (1);
     584           0 : }
     585             : 
     586             : static inline void
     587           0 : fixup_inquiry(struct scsi_xfer *xs, struct hvs_srb *srb)
     588             : {
     589           0 :         struct hvs_softc *sc = xs->sc_link->adapter_softc;
     590           0 :         struct scsi_inquiry_data *inq = (struct scsi_inquiry_data *)xs->data;
     591             :         int datalen, resplen;
     592           0 :         char vendor[8];
     593             : 
     594           0 :         resplen = srb->srb_datalen >= 5 ? inq->additional_length + 5 : 0;
     595           0 :         datalen = MIN(resplen, srb->srb_datalen);
     596             : 
     597             :         /* Fixup wrong response from WS2012 */
     598           0 :         if ((sc->sc_proto == HVS_PROTO_VERSION_WIN8_1 ||
     599           0 :             sc->sc_proto == HVS_PROTO_VERSION_WIN8 ||
     600           0 :             sc->sc_proto == HVS_PROTO_VERSION_WIN7) &&
     601           0 :             !is_inquiry_valid(inq) && datalen >= 4 &&
     602           0 :             (inq->version == 0 || inq->response_format == 0)) {
     603           0 :                 inq->version = 0x05; /* SPC-3 */
     604           0 :                 inq->response_format = 2;
     605           0 :         } else if (datalen >= SID_INQUIRY_HDR + SID_SCSI2_ALEN) {
     606             :                 /*
     607             :                  * Upgrade SPC2 to SPC3 if host is Win8 or WS2012 R2
     608             :                  * to support UNMAP feature.
     609             :                  */
     610           0 :                 scsi_strvis(vendor, inq->vendor, sizeof(vendor));
     611           0 :                 if ((sc->sc_proto == HVS_PROTO_VERSION_WIN8_1 ||
     612           0 :                     sc->sc_proto == HVS_PROTO_VERSION_WIN8) &&
     613           0 :                     SCSISPC(inq->version) == 2 &&
     614           0 :                     !strncmp(vendor, "Msft", 4))
     615           0 :                         inq->version = 0x05; /* SPC-3 */
     616             :         }
     617           0 : }
     618             : 
     619             : void
     620           0 : hvs_scsi_cmd_done(struct hvs_ccb *ccb)
     621             : {
     622           0 :         struct scsi_xfer *xs = ccb->ccb_xfer;
     623           0 :         struct hvs_softc *sc = xs->sc_link->adapter_softc;
     624           0 :         union hvs_cmd *cmd = ccb->ccb_cmd;
     625             :         struct hvs_srb *srb;
     626             :         bus_dmamap_t map;
     627             :         int error;
     628             : 
     629           0 :         map = ccb->ccb_dmap;
     630           0 :         bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
     631             :             BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
     632           0 :         bus_dmamap_unload(sc->sc_dmat, map);
     633             : 
     634           0 :         xs = ccb->ccb_xfer;
     635           0 :         srb = &cmd->io.cmd_srb;
     636             : 
     637           0 :         xs->status = srb->srb_scsistatus & 0xff;
     638             : 
     639           0 :         switch (xs->status) {
     640             :         case SCSI_OK:
     641           0 :                 if ((srb->srb_iostatus & ~(SRB_STATUS_AUTOSENSE_VALID |
     642           0 :                     SRB_STATUS_QUEUE_FROZEN)) != SRB_STATUS_SUCCESS)
     643           0 :                         error = XS_SELTIMEOUT;
     644             :                 else
     645             :                         error = XS_NOERROR;
     646             :                 break;
     647             :         case SCSI_BUSY:
     648             :         case SCSI_QUEUE_FULL:
     649           0 :                 printf("%s: status %#x iostatus %#x (busy)\n",
     650           0 :                     sc->sc_dev.dv_xname, srb->srb_scsistatus,
     651           0 :                     srb->srb_iostatus);
     652             :                 error = XS_BUSY;
     653           0 :                 break;
     654             :         case SCSI_CHECK:
     655           0 :                 if (srb->srb_iostatus & SRB_STATUS_AUTOSENSE_VALID) {
     656           0 :                         memcpy(&xs->sense, srb->srb_data,
     657             :                             MIN(sizeof(xs->sense), srb->srb_senselen));
     658             :                         error = XS_SENSE;
     659           0 :                         break;
     660             :                 }
     661             :                 /* FALLTHROUGH */
     662             :         default:
     663             :                 error = XS_DRIVER_STUFFUP;
     664           0 :         }
     665             : 
     666           0 :         if (error == XS_NOERROR) {
     667           0 :                 if (xs->cmd->opcode == INQUIRY)
     668           0 :                         fixup_inquiry(xs, srb);
     669           0 :                 else if (srb->srb_direction != SRB_DATA_NONE)
     670           0 :                         xs->resid = xs->datalen - srb->srb_datalen;
     671             :         }
     672             : 
     673           0 :         KERNEL_LOCK();
     674           0 :         hvs_scsi_done(xs, error);
     675           0 :         KERNEL_UNLOCK();
     676           0 : }
     677             : 
     678             : void
     679           0 : hvs_scsi_probe(void *arg)
     680             : {
     681           0 :         struct hvs_softc *sc = arg;
     682             : 
     683           0 :         if (sc->sc_scsibus)
     684           0 :                 scsi_probe_bus((void *)sc->sc_scsibus);
     685           0 : }
     686             : 
     687             : void
     688           0 : hvs_scsi_done(struct scsi_xfer *xs, int error)
     689             : {
     690             :         int s;
     691             : 
     692           0 :         KERNEL_ASSERT_LOCKED();
     693             : 
     694           0 :         xs->error = error;
     695             : 
     696           0 :         s = splbio();
     697           0 :         scsi_done(xs);
     698           0 :         splx(s);
     699           0 : }
     700             : 
     701             : int
     702           0 : hvs_connect(struct hvs_softc *sc)
     703             : {
     704             :         const uint32_t protos[] = {
     705             :                 HVS_PROTO_VERSION_WIN10,
     706             :                 HVS_PROTO_VERSION_WIN8_1,
     707             :                 HVS_PROTO_VERSION_WIN8,
     708             :                 HVS_PROTO_VERSION_WIN7,
     709             :                 HVS_PROTO_VERSION_WIN6
     710             :         };
     711           0 :         union hvs_cmd ucmd;
     712             :         struct hvs_cmd_ver *cmd;
     713             :         struct hvs_chp *chp;
     714             :         struct hvs_ccb *ccb;
     715             :         int i;
     716             : 
     717           0 :         ccb = scsi_io_get(&sc->sc_iopool, SCSI_POLL);
     718           0 :         if (ccb == NULL) {
     719           0 :                 printf(": failed to allocate ccb\n");
     720           0 :                 return (-1);
     721             :         }
     722             : 
     723           0 :         ccb->ccb_done = hvs_empty_done;
     724             : 
     725           0 :         cmd = (struct hvs_cmd_ver *)&ucmd;
     726             : 
     727             :         /*
     728             :          * Begin initialization
     729             :          */
     730             : 
     731           0 :         memset(&ucmd, 0, sizeof(ucmd));
     732             : 
     733           0 :         cmd->cmd_op = HVS_REQ_STARTINIT;
     734           0 :         cmd->cmd_flags = VMBUS_CHANPKT_FLAG_RC;
     735             : 
     736           0 :         ccb->ccb_cmd = &ucmd;
     737           0 :         if (hvs_poll(sc, ccb)) {
     738           0 :                 printf(": failed to send initialization command\n");
     739           0 :                 scsi_io_put(&sc->sc_iopool, ccb);
     740           0 :                 return (-1);
     741             :         }
     742           0 :         if (ccb->ccb_rsp.cmd_status != 0) {
     743           0 :                 printf(": failed to initialize, status %#x\n",
     744             :                     ccb->ccb_rsp.cmd_status);
     745           0 :                 scsi_io_put(&sc->sc_iopool, ccb);
     746           0 :                 return (-1);
     747             :         }
     748             : 
     749             :         /*
     750             :          * Negotiate protocol version
     751             :          */
     752             : 
     753           0 :         memset(&ucmd, 0, sizeof(ucmd));
     754             : 
     755           0 :         cmd->cmd_op = HVS_REQ_QUERYPROTO;
     756           0 :         cmd->cmd_flags = VMBUS_CHANPKT_FLAG_RC;
     757             : 
     758           0 :         for (i = 0; i < nitems(protos); i++) {
     759           0 :                 cmd->cmd_ver = protos[i];
     760             : 
     761           0 :                 ccb->ccb_cmd = &ucmd;
     762           0 :                 if (hvs_poll(sc, ccb)) {
     763           0 :                         printf(": failed to send protocol query\n");
     764           0 :                         scsi_io_put(&sc->sc_iopool, ccb);
     765           0 :                         return (-1);
     766             :                 }
     767           0 :                 if (ccb->ccb_rsp.cmd_status == 0) {
     768           0 :                         sc->sc_proto = protos[i];
     769           0 :                         break;
     770             :                 }
     771             :         }
     772           0 :         if (!sc->sc_proto) {
     773           0 :                 printf(": failed to negotiate protocol version\n");
     774           0 :                 scsi_io_put(&sc->sc_iopool, ccb);
     775           0 :                 return (-1);
     776             :         }
     777             : 
     778             :         /*
     779             :          * Query channel properties
     780             :          */
     781             : 
     782           0 :         memset(&ucmd, 0, sizeof(ucmd));
     783             : 
     784           0 :         cmd->cmd_op = HVS_REQ_QUERYPROPS;
     785           0 :         cmd->cmd_flags = VMBUS_CHANPKT_FLAG_RC;
     786             : 
     787           0 :         ccb->ccb_cmd = &ucmd;
     788           0 :         if (hvs_poll(sc, ccb)) {
     789           0 :                 printf(": failed to send channel properties query\n");
     790           0 :                 scsi_io_put(&sc->sc_iopool, ccb);
     791           0 :                 return (-1);
     792             :         }
     793           0 :         if (ccb->ccb_rsp.cmd_op != HVS_MSG_IODONE ||
     794           0 :             ccb->ccb_rsp.cmd_status != 0) {
     795           0 :                 printf(": failed to obtain channel properties, status %#x\n",
     796           0 :                     ccb->ccb_rsp.cmd_status);
     797           0 :                 scsi_io_put(&sc->sc_iopool, ccb);
     798           0 :                 return (-1);
     799             :         }
     800           0 :         chp = &ccb->ccb_rsp.chp.cmd_chp;
     801             : 
     802             :         DPRINTF(": proto %#x path %u target %u maxchan %u",
     803             :             chp->chp_proto, chp->chp_path, chp->chp_target,
     804             :             chp->chp_maxchan);
     805             :         DPRINTF(" port %u chflags %#x maxfer %u chanid %#llx",
     806             :             chp->chp_port, chp->chp_chflags, chp->chp_maxfer,
     807             :             chp->chp_chanid);
     808             : 
     809             :         /* XXX */
     810           0 :         sc->sc_bus = chp->chp_path;
     811           0 :         sc->sc_initiator = chp->chp_target;
     812             : 
     813             :         /*
     814             :          * Finish initialization
     815             :          */
     816             : 
     817           0 :         memset(&ucmd, 0, sizeof(ucmd));
     818             : 
     819           0 :         cmd->cmd_op = HVS_REQ_FINISHINIT;
     820           0 :         cmd->cmd_flags = VMBUS_CHANPKT_FLAG_RC;
     821             : 
     822           0 :         ccb->ccb_cmd = &ucmd;
     823           0 :         if (hvs_poll(sc, ccb)) {
     824           0 :                 printf(": failed to send initialization finish\n");
     825           0 :                 scsi_io_put(&sc->sc_iopool, ccb);
     826           0 :                 return (-1);
     827             :         }
     828           0 :         if (ccb->ccb_rsp.cmd_op != HVS_MSG_IODONE ||
     829           0 :             ccb->ccb_rsp.cmd_status != 0) {
     830           0 :                 printf(": failed to finish initialization, status %#x\n",
     831           0 :                     ccb->ccb_rsp.cmd_status);
     832           0 :                 scsi_io_put(&sc->sc_iopool, ccb);
     833           0 :                 return (-1);
     834             :         }
     835             : 
     836           0 :         scsi_io_put(&sc->sc_iopool, ccb);
     837             : 
     838           0 :         return (0);
     839           0 : }
     840             : 
     841             : void
     842           0 : hvs_empty_done(struct hvs_ccb *ccb)
     843             : {
     844             :         /* nothing */
     845           0 : }
     846             : 
     847             : int
     848           0 : hvs_alloc_ccbs(struct hvs_softc *sc)
     849             : {
     850             :         int i, error;
     851             : 
     852           0 :         SIMPLEQ_INIT(&sc->sc_ccb_fq);
     853           0 :         mtx_init(&sc->sc_ccb_fqlck, IPL_BIO);
     854             : 
     855           0 :         sc->sc_nccb = HVS_MAX_CCB;
     856             : 
     857           0 :         sc->sc_ccbs = mallocarray(sc->sc_nccb, sizeof(struct hvs_ccb),
     858             :             M_DEVBUF, M_ZERO | M_NOWAIT);
     859           0 :         if (sc->sc_ccbs == NULL) {
     860           0 :                 printf(": failed to allocate CCBs\n");
     861           0 :                 return (-1);
     862             :         }
     863             : 
     864           0 :         for (i = 0; i < sc->sc_nccb; i++) {
     865           0 :                 error = bus_dmamap_create(sc->sc_dmat, MAXPHYS, HVS_MAX_SGE,
     866             :                     PAGE_SIZE, PAGE_SIZE, BUS_DMA_NOWAIT,
     867             :                     &sc->sc_ccbs[i].ccb_dmap);
     868           0 :                 if (error) {
     869           0 :                         printf(": failed to create a CCB memory map (%d)\n",
     870             :                             error);
     871           0 :                         goto errout;
     872             :                 }
     873             : 
     874           0 :                 sc->sc_ccbs[i].ccb_sgl = malloc(sizeof(struct vmbus_gpa_range) *
     875             :                     (HVS_MAX_SGE + 1), M_DEVBUF, M_ZERO | M_NOWAIT);
     876           0 :                 if (sc->sc_ccbs[i].ccb_sgl == NULL) {
     877           0 :                         printf(": failed to allocate SGL array\n");
     878           0 :                         goto errout;
     879             :                 }
     880             : 
     881           0 :                 sc->sc_ccbs[i].ccb_rid = i;
     882           0 :                 hvs_put_ccb(sc, &sc->sc_ccbs[i]);
     883             :         }
     884             : 
     885           0 :         scsi_iopool_init(&sc->sc_iopool, sc, hvs_get_ccb, hvs_put_ccb);
     886             : 
     887           0 :         return (0);
     888             : 
     889             :  errout:
     890           0 :         hvs_free_ccbs(sc);
     891           0 :         return (-1);
     892           0 : }
     893             : 
     894             : void
     895           0 : hvs_free_ccbs(struct hvs_softc *sc)
     896             : {
     897             :         struct hvs_ccb *ccb;
     898             :         int i;
     899             : 
     900           0 :         for (i = 0; i < sc->sc_nccb; i++) {
     901           0 :                 ccb = &sc->sc_ccbs[i];
     902           0 :                 if (ccb->ccb_dmap == NULL)
     903             :                         continue;
     904           0 :                 bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmap, 0, 0,
     905             :                     BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
     906           0 :                 bus_dmamap_unload(sc->sc_dmat, ccb->ccb_dmap);
     907           0 :                 bus_dmamap_destroy(sc->sc_dmat, ccb->ccb_dmap);
     908             : 
     909           0 :                 free(ccb->ccb_sgl, M_DEVBUF, sizeof(struct vmbus_gpa_range) *
     910             :                     (HVS_MAX_SGE + 1));
     911           0 :         }
     912             : 
     913           0 :         free(sc->sc_ccbs, M_DEVBUF, sc->sc_nccb * sizeof(struct hvs_ccb));
     914           0 :         sc->sc_ccbs = NULL;
     915           0 :         sc->sc_nccb = 0;
     916           0 : }
     917             : 
     918             : void *
     919           0 : hvs_get_ccb(void *xsc)
     920             : {
     921           0 :         struct hvs_softc *sc = xsc;
     922             :         struct hvs_ccb *ccb;
     923             : 
     924           0 :         mtx_enter(&sc->sc_ccb_fqlck);
     925           0 :         ccb = SIMPLEQ_FIRST(&sc->sc_ccb_fq);
     926           0 :         if (ccb != NULL)
     927           0 :                 SIMPLEQ_REMOVE_HEAD(&sc->sc_ccb_fq, ccb_link);
     928           0 :         mtx_leave(&sc->sc_ccb_fqlck);
     929             : 
     930           0 :         return (ccb);
     931             : }
     932             : 
     933             : void
     934           0 : hvs_put_ccb(void *xsc, void *io)
     935             : {
     936           0 :         struct hvs_softc *sc = xsc;
     937           0 :         struct hvs_ccb *ccb = io;
     938             : 
     939           0 :         ccb->ccb_cmd = NULL;
     940           0 :         ccb->ccb_xfer = NULL;
     941           0 :         ccb->ccb_done = NULL;
     942           0 :         ccb->ccb_cookie = NULL;
     943           0 :         ccb->ccb_nsge = 0;
     944             : 
     945           0 :         mtx_enter(&sc->sc_ccb_fqlck);
     946           0 :         SIMPLEQ_INSERT_HEAD(&sc->sc_ccb_fq, ccb, ccb_link);
     947           0 :         mtx_leave(&sc->sc_ccb_fqlck);
     948           0 : }

Generated by: LCOV version 1.13