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