1250199Sgrehan/*-
2250199Sgrehan * Copyright (c) 2009-2012 Microsoft Corp.
3250199Sgrehan * Copyright (c) 2012 NetApp Inc.
4250199Sgrehan * Copyright (c) 2012 Citrix Inc.
5250199Sgrehan * All rights reserved.
6250199Sgrehan *
7250199Sgrehan * Redistribution and use in source and binary forms, with or without
8250199Sgrehan * modification, are permitted provided that the following conditions
9250199Sgrehan * are met:
10250199Sgrehan * 1. Redistributions of source code must retain the above copyright
11250199Sgrehan *    notice unmodified, this list of conditions, and the following
12250199Sgrehan *    disclaimer.
13250199Sgrehan * 2. Redistributions in binary form must reproduce the above copyright
14250199Sgrehan *    notice, this list of conditions and the following disclaimer in the
15250199Sgrehan *    documentation and/or other materials provided with the distribution.
16250199Sgrehan *
17250199Sgrehan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18250199Sgrehan * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19250199Sgrehan * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20250199Sgrehan * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21250199Sgrehan * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22250199Sgrehan * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23250199Sgrehan * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24250199Sgrehan * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25250199Sgrehan * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26250199Sgrehan * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27250199Sgrehan */
28250199Sgrehan
29250199Sgrehan/**
30250199Sgrehan * StorVSC driver for Hyper-V.  This driver presents a SCSI HBA interface
31250199Sgrehan * to the Comman Access Method (CAM) layer.  CAM control blocks (CCBs) are
32250199Sgrehan * converted into VSCSI protocol messages which are delivered to the parent
33250199Sgrehan * partition StorVSP driver over the Hyper-V VMBUS.
34250199Sgrehan */
35256276Sdim#include <sys/cdefs.h>
36256276Sdim__FBSDID("$FreeBSD: releng/10.2/sys/dev/hyperv/storvsc/hv_storvsc_drv_freebsd.c 283644 2015-05-28 09:20:35Z whu $");
37250199Sgrehan
38250199Sgrehan#include <sys/param.h>
39250199Sgrehan#include <sys/proc.h>
40250199Sgrehan#include <sys/condvar.h>
41283280Swhu#include <sys/time.h>
42250199Sgrehan#include <sys/systm.h>
43250199Sgrehan#include <sys/sockio.h>
44250199Sgrehan#include <sys/mbuf.h>
45250199Sgrehan#include <sys/malloc.h>
46250199Sgrehan#include <sys/module.h>
47250199Sgrehan#include <sys/kernel.h>
48250199Sgrehan#include <sys/queue.h>
49250199Sgrehan#include <sys/lock.h>
50250199Sgrehan#include <sys/sx.h>
51250199Sgrehan#include <sys/taskqueue.h>
52250199Sgrehan#include <sys/bus.h>
53250199Sgrehan#include <sys/mutex.h>
54250199Sgrehan#include <sys/callout.h>
55250199Sgrehan#include <vm/vm.h>
56250199Sgrehan#include <vm/pmap.h>
57283280Swhu#include <vm/uma.h>
58250199Sgrehan#include <sys/lock.h>
59250199Sgrehan#include <sys/sema.h>
60283280Swhu#include <sys/sglist.h>
61283280Swhu#include <machine/bus.h>
62283280Swhu#include <sys/bus_dma.h>
63250199Sgrehan
64250199Sgrehan#include <cam/cam.h>
65250199Sgrehan#include <cam/cam_ccb.h>
66250199Sgrehan#include <cam/cam_periph.h>
67250199Sgrehan#include <cam/cam_sim.h>
68250199Sgrehan#include <cam/cam_xpt_sim.h>
69250199Sgrehan#include <cam/cam_xpt_internal.h>
70250199Sgrehan#include <cam/cam_debug.h>
71250199Sgrehan#include <cam/scsi/scsi_all.h>
72250199Sgrehan#include <cam/scsi/scsi_message.h>
73250199Sgrehan
74250199Sgrehan#include <dev/hyperv/include/hyperv.h>
75250199Sgrehan#include "hv_vstorage.h"
76250199Sgrehan
77250199Sgrehan#define STORVSC_RINGBUFFER_SIZE		(20*PAGE_SIZE)
78250199Sgrehan#define STORVSC_MAX_LUNS_PER_TARGET	(64)
79250199Sgrehan#define STORVSC_MAX_IO_REQUESTS		(STORVSC_MAX_LUNS_PER_TARGET * 2)
80250199Sgrehan#define BLKVSC_MAX_IDE_DISKS_PER_TARGET	(1)
81250199Sgrehan#define BLKVSC_MAX_IO_REQUESTS		STORVSC_MAX_IO_REQUESTS
82273429Sgjb#define STORVSC_MAX_TARGETS		(2)
83250199Sgrehan
84283280Swhu#define STORVSC_WIN7_MAJOR 4
85283280Swhu#define STORVSC_WIN7_MINOR 2
86283280Swhu
87283280Swhu#define STORVSC_WIN8_MAJOR 5
88283280Swhu#define STORVSC_WIN8_MINOR 1
89283280Swhu
90283644Swhu#define VSTOR_PKT_SIZE	(sizeof(struct vstor_packet) - vmscsi_size_delta)
91283644Swhu
92283280Swhu#define HV_ALIGN(x, a) roundup2(x, a)
93283280Swhu
94250199Sgrehanstruct storvsc_softc;
95250199Sgrehan
96283280Swhustruct hv_sgl_node {
97283280Swhu	LIST_ENTRY(hv_sgl_node) link;
98283280Swhu	struct sglist *sgl_data;
99283280Swhu};
100283280Swhu
101283280Swhustruct hv_sgl_page_pool{
102283280Swhu	LIST_HEAD(, hv_sgl_node) in_use_sgl_list;
103283280Swhu	LIST_HEAD(, hv_sgl_node) free_sgl_list;
104283280Swhu	boolean_t                is_init;
105283280Swhu} g_hv_sgl_page_pool;
106283280Swhu
107283280Swhu#define STORVSC_MAX_SG_PAGE_CNT STORVSC_MAX_IO_REQUESTS * HV_MAX_MULTIPAGE_BUFFER_COUNT
108283280Swhu
109250199Sgrehanenum storvsc_request_type {
110250199Sgrehan	WRITE_TYPE,
111250199Sgrehan	READ_TYPE,
112250199Sgrehan	UNKNOWN_TYPE
113250199Sgrehan};
114250199Sgrehan
115250199Sgrehanstruct hv_storvsc_request {
116250199Sgrehan	LIST_ENTRY(hv_storvsc_request) link;
117250199Sgrehan	struct vstor_packet	vstor_packet;
118250199Sgrehan	hv_vmbus_multipage_buffer data_buf;
119250199Sgrehan	void *sense_data;
120250199Sgrehan	uint8_t sense_info_len;
121250199Sgrehan	uint8_t retries;
122250199Sgrehan	union ccb *ccb;
123250199Sgrehan	struct storvsc_softc *softc;
124250199Sgrehan	struct callout callout;
125250199Sgrehan	struct sema synch_sema; /*Synchronize the request/response if needed */
126283280Swhu	struct sglist *bounce_sgl;
127283280Swhu	unsigned int bounce_sgl_count;
128283280Swhu	uint64_t not_aligned_seg_bits;
129250199Sgrehan};
130250199Sgrehan
131250199Sgrehanstruct storvsc_softc {
132250199Sgrehan	struct hv_device		*hs_dev;
133283280Swhu	LIST_HEAD(, hv_storvsc_request)	hs_free_list;
134283280Swhu	struct mtx			hs_lock;
135283280Swhu	struct storvsc_driver_props	*hs_drv_props;
136283280Swhu	int 				hs_unit;
137283280Swhu	uint32_t			hs_frozen;
138283280Swhu	struct cam_sim			*hs_sim;
139283280Swhu	struct cam_path 		*hs_path;
140250199Sgrehan	uint32_t			hs_num_out_reqs;
141250199Sgrehan	boolean_t			hs_destroy;
142250199Sgrehan	boolean_t			hs_drain_notify;
143283280Swhu	boolean_t			hs_open_multi_channel;
144250199Sgrehan	struct sema 			hs_drain_sema;
145250199Sgrehan	struct hv_storvsc_request	hs_init_req;
146250199Sgrehan	struct hv_storvsc_request	hs_reset_req;
147250199Sgrehan};
148250199Sgrehan
149250199Sgrehan
150250199Sgrehan/**
151250199Sgrehan * HyperV storvsc timeout testing cases:
152250199Sgrehan * a. IO returned after first timeout;
153250199Sgrehan * b. IO returned after second timeout and queue freeze;
154250199Sgrehan * c. IO returned while timer handler is running
155250199Sgrehan * The first can be tested by "sg_senddiag -vv /dev/daX",
156250199Sgrehan * and the second and third can be done by
157250199Sgrehan * "sg_wr_mode -v -p 08 -c 0,1a -m 0,ff /dev/daX".
158283280Swhu */
159250199Sgrehan#define HVS_TIMEOUT_TEST 0
160250199Sgrehan
161250199Sgrehan/*
162250199Sgrehan * Bus/adapter reset functionality on the Hyper-V host is
163250199Sgrehan * buggy and it will be disabled until
164250199Sgrehan * it can be further tested.
165250199Sgrehan */
166250199Sgrehan#define HVS_HOST_RESET 0
167250199Sgrehan
168250199Sgrehanstruct storvsc_driver_props {
169250199Sgrehan	char		*drv_name;
170250199Sgrehan	char		*drv_desc;
171250199Sgrehan	uint8_t		drv_max_luns_per_target;
172283280Swhu	uint8_t		drv_max_ios_per_target;
173250199Sgrehan	uint32_t	drv_ringbuffer_size;
174250199Sgrehan};
175250199Sgrehan
176250199Sgrehanenum hv_storage_type {
177250199Sgrehan	DRIVER_BLKVSC,
178250199Sgrehan	DRIVER_STORVSC,
179250199Sgrehan	DRIVER_UNKNOWN
180250199Sgrehan};
181250199Sgrehan
182250199Sgrehan#define HS_MAX_ADAPTERS 10
183250199Sgrehan
184283280Swhu#define HV_STORAGE_SUPPORTS_MULTI_CHANNEL 0x1
185283280Swhu
186250199Sgrehan/* {ba6163d9-04a1-4d29-b605-72e2ffb1dc7f} */
187250199Sgrehanstatic const hv_guid gStorVscDeviceType={
188250199Sgrehan	.data = {0xd9, 0x63, 0x61, 0xba, 0xa1, 0x04, 0x29, 0x4d,
189250199Sgrehan		 0xb6, 0x05, 0x72, 0xe2, 0xff, 0xb1, 0xdc, 0x7f}
190250199Sgrehan};
191250199Sgrehan
192250199Sgrehan/* {32412632-86cb-44a2-9b5c-50d1417354f5} */
193250199Sgrehanstatic const hv_guid gBlkVscDeviceType={
194250199Sgrehan	.data = {0x32, 0x26, 0x41, 0x32, 0xcb, 0x86, 0xa2, 0x44,
195250199Sgrehan		 0x9b, 0x5c, 0x50, 0xd1, 0x41, 0x73, 0x54, 0xf5}
196250199Sgrehan};
197250199Sgrehan
198250199Sgrehanstatic struct storvsc_driver_props g_drv_props_table[] = {
199250199Sgrehan	{"blkvsc", "Hyper-V IDE Storage Interface",
200250199Sgrehan	 BLKVSC_MAX_IDE_DISKS_PER_TARGET, BLKVSC_MAX_IO_REQUESTS,
201250199Sgrehan	 STORVSC_RINGBUFFER_SIZE},
202250199Sgrehan	{"storvsc", "Hyper-V SCSI Storage Interface",
203250199Sgrehan	 STORVSC_MAX_LUNS_PER_TARGET, STORVSC_MAX_IO_REQUESTS,
204250199Sgrehan	 STORVSC_RINGBUFFER_SIZE}
205250199Sgrehan};
206250199Sgrehan
207283644Swhu/*
208283644Swhu * Sense buffer size changed in win8; have a run-time
209283644Swhu * variable to track the size we should use.
210283644Swhu */
211283644Swhustatic int sense_buffer_size;
212283644Swhu
213283644Swhu/*
214283644Swhu * The size of the vmscsi_request has changed in win8. The
215283644Swhu * additional size is for the newly added elements in the
216283644Swhu * structure. These elements are valid only when we are talking
217283644Swhu * to a win8 host.
218283644Swhu * Track the correct size we need to apply.
219283644Swhu */
220283644Swhustatic int vmscsi_size_delta;
221283644Swhu
222283280Swhustatic int storvsc_current_major;
223283280Swhustatic int storvsc_current_minor;
224283280Swhu
225250199Sgrehan/* static functions */
226250199Sgrehanstatic int storvsc_probe(device_t dev);
227250199Sgrehanstatic int storvsc_attach(device_t dev);
228250199Sgrehanstatic int storvsc_detach(device_t dev);
229250199Sgrehanstatic void storvsc_poll(struct cam_sim * sim);
230250199Sgrehanstatic void storvsc_action(struct cam_sim * sim, union ccb * ccb);
231283280Swhustatic int create_storvsc_request(union ccb *ccb, struct hv_storvsc_request *reqp);
232250199Sgrehanstatic void storvsc_free_request(struct storvsc_softc *sc, struct hv_storvsc_request *reqp);
233250199Sgrehanstatic enum hv_storage_type storvsc_get_storage_type(device_t dev);
234283644Swhustatic void hv_storvsc_rescan_target(struct storvsc_softc *sc);
235250199Sgrehanstatic void hv_storvsc_on_channel_callback(void *context);
236250199Sgrehanstatic void hv_storvsc_on_iocompletion( struct storvsc_softc *sc,
237250199Sgrehan					struct vstor_packet *vstor_packet,
238250199Sgrehan					struct hv_storvsc_request *request);
239250199Sgrehanstatic int hv_storvsc_connect_vsp(struct hv_device *device);
240250199Sgrehanstatic void storvsc_io_done(struct hv_storvsc_request *reqp);
241283280Swhustatic void storvsc_copy_sgl_to_bounce_buf(struct sglist *bounce_sgl,
242283280Swhu				bus_dma_segment_t *orig_sgl,
243283280Swhu				unsigned int orig_sgl_count,
244283280Swhu				uint64_t seg_bits);
245283280Swhuvoid storvsc_copy_from_bounce_buf_to_sgl(bus_dma_segment_t *dest_sgl,
246283280Swhu				unsigned int dest_sgl_count,
247283280Swhu				struct sglist* src_sgl,
248283280Swhu				uint64_t seg_bits);
249250199Sgrehan
250250199Sgrehanstatic device_method_t storvsc_methods[] = {
251250199Sgrehan	/* Device interface */
252250199Sgrehan	DEVMETHOD(device_probe,		storvsc_probe),
253250199Sgrehan	DEVMETHOD(device_attach,	storvsc_attach),
254250199Sgrehan	DEVMETHOD(device_detach,	storvsc_detach),
255250199Sgrehan	DEVMETHOD(device_shutdown,      bus_generic_shutdown),
256252645Sgrehan	DEVMETHOD_END
257250199Sgrehan};
258250199Sgrehan
259250199Sgrehanstatic driver_t storvsc_driver = {
260250199Sgrehan	"storvsc", storvsc_methods, sizeof(struct storvsc_softc),
261250199Sgrehan};
262250199Sgrehan
263250199Sgrehanstatic devclass_t storvsc_devclass;
264250199SgrehanDRIVER_MODULE(storvsc, vmbus, storvsc_driver, storvsc_devclass, 0, 0);
265252645SgrehanMODULE_VERSION(storvsc, 1);
266250199SgrehanMODULE_DEPEND(storvsc, vmbus, 1, 1, 1);
267250199Sgrehan
268250199Sgrehan
269250199Sgrehan/**
270283280Swhu * The host is capable of sending messages to us that are
271250199Sgrehan * completely unsolicited. So, we need to address the race
272250199Sgrehan * condition where we may be in the process of unloading the
273250199Sgrehan * driver when the host may send us an unsolicited message.
274250199Sgrehan * We address this issue by implementing a sequentially
275250199Sgrehan * consistent protocol:
276250199Sgrehan *
277250199Sgrehan * 1. Channel callback is invoked while holding the the channel lock
278250199Sgrehan *    and an unloading driver will reset the channel callback under
279250199Sgrehan *    the protection of this channel lock.
280250199Sgrehan *
281250199Sgrehan * 2. To ensure bounded wait time for unloading a driver, we don't
282250199Sgrehan *    permit outgoing traffic once the device is marked as being
283250199Sgrehan *    destroyed.
284250199Sgrehan *
285250199Sgrehan * 3. Once the device is marked as being destroyed, we only
286283280Swhu *    permit incoming traffic to properly account for
287250199Sgrehan *    packets already sent out.
288250199Sgrehan */
289250199Sgrehanstatic inline struct storvsc_softc *
290250199Sgrehanget_stor_device(struct hv_device *device,
291250199Sgrehan				boolean_t outbound)
292250199Sgrehan{
293250199Sgrehan	struct storvsc_softc *sc;
294250199Sgrehan
295250199Sgrehan	sc = device_get_softc(device->device);
296250199Sgrehan	if (sc == NULL) {
297250199Sgrehan		return NULL;
298250199Sgrehan	}
299250199Sgrehan
300250199Sgrehan	if (outbound) {
301250199Sgrehan		/*
302250199Sgrehan		 * Here we permit outgoing I/O only
303250199Sgrehan		 * if the device is not being destroyed.
304250199Sgrehan		 */
305250199Sgrehan
306250199Sgrehan		if (sc->hs_destroy) {
307250199Sgrehan			sc = NULL;
308250199Sgrehan		}
309250199Sgrehan	} else {
310250199Sgrehan		/*
311250199Sgrehan		 * inbound case; if being destroyed
312250199Sgrehan		 * only permit to account for
313250199Sgrehan		 * messages already sent out.
314250199Sgrehan		 */
315250199Sgrehan		if (sc->hs_destroy && (sc->hs_num_out_reqs == 0)) {
316250199Sgrehan			sc = NULL;
317250199Sgrehan		}
318250199Sgrehan	}
319250199Sgrehan	return sc;
320250199Sgrehan}
321250199Sgrehan
322250199Sgrehan/**
323283280Swhu * @brief Callback handler, will be invoked when receive mutil-channel offer
324283280Swhu *
325283280Swhu * @param context  new multi-channel
326283280Swhu */
327283280Swhustatic void
328283280Swhustorvsc_handle_sc_creation(void *context)
329283280Swhu{
330283280Swhu	hv_vmbus_channel *new_channel;
331283280Swhu	struct hv_device *device;
332283280Swhu	struct storvsc_softc *sc;
333283280Swhu	struct vmstor_chan_props props;
334283280Swhu	int ret = 0;
335283280Swhu
336283280Swhu	new_channel = (hv_vmbus_channel *)context;
337283280Swhu	device = new_channel->primary_channel->device;
338283280Swhu	sc = get_stor_device(device, TRUE);
339283280Swhu	if (sc == NULL)
340283280Swhu		return;
341283280Swhu
342283280Swhu	if (FALSE == sc->hs_open_multi_channel)
343283280Swhu		return;
344283280Swhu
345283280Swhu	memset(&props, 0, sizeof(props));
346283280Swhu
347283280Swhu	ret = hv_vmbus_channel_open(new_channel,
348283280Swhu	    sc->hs_drv_props->drv_ringbuffer_size,
349283280Swhu  	    sc->hs_drv_props->drv_ringbuffer_size,
350283280Swhu	    (void *)&props,
351283280Swhu	    sizeof(struct vmstor_chan_props),
352283280Swhu	    hv_storvsc_on_channel_callback,
353283280Swhu	    new_channel);
354283280Swhu
355283280Swhu	return;
356283280Swhu}
357283280Swhu
358283280Swhu/**
359283280Swhu * @brief Send multi-channel creation request to host
360283280Swhu *
361283280Swhu * @param device  a Hyper-V device pointer
362283280Swhu * @param max_chans  the max channels supported by vmbus
363283280Swhu */
364283280Swhustatic void
365283280Swhustorvsc_send_multichannel_request(struct hv_device *dev, int max_chans)
366283280Swhu{
367283280Swhu	struct storvsc_softc *sc;
368283280Swhu	struct hv_storvsc_request *request;
369283280Swhu	struct vstor_packet *vstor_packet;
370283280Swhu	int request_channels_cnt = 0;
371283280Swhu	int ret;
372283280Swhu
373283280Swhu	/* get multichannels count that need to create */
374283280Swhu	request_channels_cnt = MIN(max_chans, mp_ncpus);
375283280Swhu
376283280Swhu	sc = get_stor_device(dev, TRUE);
377283280Swhu	if (sc == NULL) {
378283280Swhu		printf("Storvsc_error: get sc failed while send mutilchannel "
379283280Swhu		    "request\n");
380283280Swhu		return;
381283280Swhu	}
382283280Swhu
383283280Swhu	request = &sc->hs_init_req;
384283280Swhu
385283280Swhu	/* Establish a handler for multi-channel */
386283280Swhu	dev->channel->sc_creation_callback = storvsc_handle_sc_creation;
387283280Swhu
388283280Swhu	/* request the host to create multi-channel */
389283280Swhu	memset(request, 0, sizeof(struct hv_storvsc_request));
390283280Swhu
391283280Swhu	sema_init(&request->synch_sema, 0, ("stor_synch_sema"));
392283280Swhu
393283280Swhu	vstor_packet = &request->vstor_packet;
394283280Swhu
395283280Swhu	vstor_packet->operation = VSTOR_OPERATION_CREATE_MULTI_CHANNELS;
396283280Swhu	vstor_packet->flags = REQUEST_COMPLETION_FLAG;
397283280Swhu	vstor_packet->u.multi_channels_cnt = request_channels_cnt;
398283280Swhu
399283280Swhu	ret = hv_vmbus_channel_send_packet(
400283280Swhu	    dev->channel,
401283280Swhu	    vstor_packet,
402283644Swhu	    VSTOR_PKT_SIZE,
403283280Swhu	    (uint64_t)(uintptr_t)request,
404283280Swhu	    HV_VMBUS_PACKET_TYPE_DATA_IN_BAND,
405283280Swhu	    HV_VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
406283280Swhu
407283280Swhu	/* wait for 5 seconds */
408283280Swhu	ret = sema_timedwait(&request->synch_sema, 5 * hz);
409283280Swhu	if (ret != 0) {
410283280Swhu		printf("Storvsc_error: create multi-channel timeout, %d\n",
411283280Swhu		    ret);
412283280Swhu		return;
413283280Swhu	}
414283280Swhu
415283280Swhu	if (vstor_packet->operation != VSTOR_OPERATION_COMPLETEIO ||
416283280Swhu	    vstor_packet->status != 0) {
417283280Swhu		printf("Storvsc_error: create multi-channel invalid operation "
418283280Swhu		    "(%d) or statue (%u)\n",
419283280Swhu		    vstor_packet->operation, vstor_packet->status);
420283280Swhu		return;
421283280Swhu	}
422283280Swhu
423283280Swhu	sc->hs_open_multi_channel = TRUE;
424283280Swhu
425283280Swhu	if (bootverbose)
426283280Swhu		printf("Storvsc create multi-channel success!\n");
427283280Swhu}
428283280Swhu
429283280Swhu/**
430250199Sgrehan * @brief initialize channel connection to parent partition
431250199Sgrehan *
432250199Sgrehan * @param dev  a Hyper-V device pointer
433250199Sgrehan * @returns  0 on success, non-zero error on failure
434250199Sgrehan */
435250199Sgrehanstatic int
436250199Sgrehanhv_storvsc_channel_init(struct hv_device *dev)
437250199Sgrehan{
438250199Sgrehan	int ret = 0;
439250199Sgrehan	struct hv_storvsc_request *request;
440250199Sgrehan	struct vstor_packet *vstor_packet;
441250199Sgrehan	struct storvsc_softc *sc;
442283280Swhu	uint16_t max_chans = 0;
443283280Swhu	boolean_t support_multichannel = FALSE;
444250199Sgrehan
445283280Swhu	max_chans = 0;
446283280Swhu	support_multichannel = FALSE;
447283280Swhu
448250199Sgrehan	sc = get_stor_device(dev, TRUE);
449283280Swhu	if (sc == NULL)
450283280Swhu		return (ENODEV);
451250199Sgrehan
452250199Sgrehan	request = &sc->hs_init_req;
453250199Sgrehan	memset(request, 0, sizeof(struct hv_storvsc_request));
454250199Sgrehan	vstor_packet = &request->vstor_packet;
455250199Sgrehan	request->softc = sc;
456250199Sgrehan
457250199Sgrehan	/**
458250199Sgrehan	 * Initiate the vsc/vsp initialization protocol on the open channel
459250199Sgrehan	 */
460250199Sgrehan	sema_init(&request->synch_sema, 0, ("stor_synch_sema"));
461250199Sgrehan
462250199Sgrehan	vstor_packet->operation = VSTOR_OPERATION_BEGININITIALIZATION;
463250199Sgrehan	vstor_packet->flags = REQUEST_COMPLETION_FLAG;
464250199Sgrehan
465250199Sgrehan
466250199Sgrehan	ret = hv_vmbus_channel_send_packet(
467250199Sgrehan			dev->channel,
468250199Sgrehan			vstor_packet,
469283644Swhu			VSTOR_PKT_SIZE,
470266794Smarius			(uint64_t)(uintptr_t)request,
471250199Sgrehan			HV_VMBUS_PACKET_TYPE_DATA_IN_BAND,
472250199Sgrehan			HV_VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
473250199Sgrehan
474283280Swhu	if (ret != 0)
475250199Sgrehan		goto cleanup;
476250199Sgrehan
477283280Swhu	/* wait 5 seconds */
478283280Swhu	ret = sema_timedwait(&request->synch_sema, 5 * hz);
479283280Swhu	if (ret != 0)
480250199Sgrehan		goto cleanup;
481250199Sgrehan
482250199Sgrehan	if (vstor_packet->operation != VSTOR_OPERATION_COMPLETEIO ||
483250199Sgrehan		vstor_packet->status != 0) {
484250199Sgrehan		goto cleanup;
485250199Sgrehan	}
486250199Sgrehan
487250199Sgrehan	/* reuse the packet for version range supported */
488250199Sgrehan
489250199Sgrehan	memset(vstor_packet, 0, sizeof(struct vstor_packet));
490250199Sgrehan	vstor_packet->operation = VSTOR_OPERATION_QUERYPROTOCOLVERSION;
491250199Sgrehan	vstor_packet->flags = REQUEST_COMPLETION_FLAG;
492250199Sgrehan
493283280Swhu	vstor_packet->u.version.major_minor =
494283280Swhu	    VMSTOR_PROTOCOL_VERSION(storvsc_current_major, storvsc_current_minor);
495250199Sgrehan
496250199Sgrehan	/* revision is only significant for Windows guests */
497256276Sdim	vstor_packet->u.version.revision = 0;
498250199Sgrehan
499250199Sgrehan	ret = hv_vmbus_channel_send_packet(
500250199Sgrehan			dev->channel,
501250199Sgrehan			vstor_packet,
502283644Swhu			VSTOR_PKT_SIZE,
503266794Smarius			(uint64_t)(uintptr_t)request,
504250199Sgrehan			HV_VMBUS_PACKET_TYPE_DATA_IN_BAND,
505250199Sgrehan			HV_VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
506250199Sgrehan
507283280Swhu	if (ret != 0)
508250199Sgrehan		goto cleanup;
509250199Sgrehan
510283280Swhu	/* wait 5 seconds */
511283280Swhu	ret = sema_timedwait(&request->synch_sema, 5 * hz);
512250199Sgrehan
513283280Swhu	if (ret)
514250199Sgrehan		goto cleanup;
515250199Sgrehan
516250199Sgrehan	/* TODO: Check returned version */
517250199Sgrehan	if (vstor_packet->operation != VSTOR_OPERATION_COMPLETEIO ||
518283280Swhu		vstor_packet->status != 0)
519250199Sgrehan		goto cleanup;
520250199Sgrehan
521250199Sgrehan	/**
522250199Sgrehan	 * Query channel properties
523250199Sgrehan	 */
524250199Sgrehan	memset(vstor_packet, 0, sizeof(struct vstor_packet));
525250199Sgrehan	vstor_packet->operation = VSTOR_OPERATION_QUERYPROPERTIES;
526250199Sgrehan	vstor_packet->flags = REQUEST_COMPLETION_FLAG;
527250199Sgrehan
528250199Sgrehan	ret = hv_vmbus_channel_send_packet(
529250199Sgrehan				dev->channel,
530250199Sgrehan				vstor_packet,
531283644Swhu				VSTOR_PKT_SIZE,
532266794Smarius				(uint64_t)(uintptr_t)request,
533250199Sgrehan				HV_VMBUS_PACKET_TYPE_DATA_IN_BAND,
534250199Sgrehan				HV_VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
535250199Sgrehan
536283280Swhu	if ( ret != 0)
537250199Sgrehan		goto cleanup;
538250199Sgrehan
539283280Swhu	/* wait 5 seconds */
540283280Swhu	ret = sema_timedwait(&request->synch_sema, 5 * hz);
541250199Sgrehan
542283280Swhu	if (ret != 0)
543250199Sgrehan		goto cleanup;
544250199Sgrehan
545250199Sgrehan	/* TODO: Check returned version */
546250199Sgrehan	if (vstor_packet->operation != VSTOR_OPERATION_COMPLETEIO ||
547283280Swhu	    vstor_packet->status != 0) {
548250199Sgrehan		goto cleanup;
549250199Sgrehan	}
550250199Sgrehan
551283280Swhu	/* multi-channels feature is supported by WIN8 and above version */
552283280Swhu	max_chans = vstor_packet->u.chan_props.max_channel_cnt;
553283280Swhu	if ((hv_vmbus_protocal_version != HV_VMBUS_VERSION_WIN7) &&
554283280Swhu	    (hv_vmbus_protocal_version != HV_VMBUS_VERSION_WS2008) &&
555283280Swhu	    (vstor_packet->u.chan_props.flags &
556283280Swhu	     HV_STORAGE_SUPPORTS_MULTI_CHANNEL)) {
557283280Swhu		support_multichannel = TRUE;
558283280Swhu	}
559283280Swhu
560250199Sgrehan	memset(vstor_packet, 0, sizeof(struct vstor_packet));
561250199Sgrehan	vstor_packet->operation = VSTOR_OPERATION_ENDINITIALIZATION;
562250199Sgrehan	vstor_packet->flags = REQUEST_COMPLETION_FLAG;
563250199Sgrehan
564250199Sgrehan	ret = hv_vmbus_channel_send_packet(
565250199Sgrehan			dev->channel,
566250199Sgrehan			vstor_packet,
567283644Swhu			VSTOR_PKT_SIZE,
568266794Smarius			(uint64_t)(uintptr_t)request,
569250199Sgrehan			HV_VMBUS_PACKET_TYPE_DATA_IN_BAND,
570250199Sgrehan			HV_VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
571250199Sgrehan
572250199Sgrehan	if (ret != 0) {
573250199Sgrehan		goto cleanup;
574250199Sgrehan	}
575250199Sgrehan
576283280Swhu	/* wait 5 seconds */
577283280Swhu	ret = sema_timedwait(&request->synch_sema, 5 * hz);
578250199Sgrehan
579283280Swhu	if (ret != 0)
580250199Sgrehan		goto cleanup;
581250199Sgrehan
582250199Sgrehan	if (vstor_packet->operation != VSTOR_OPERATION_COMPLETEIO ||
583283280Swhu	    vstor_packet->status != 0)
584250199Sgrehan		goto cleanup;
585250199Sgrehan
586283280Swhu	/*
587283280Swhu	 * If multi-channel is supported, send multichannel create
588283280Swhu	 * request to host.
589283280Swhu	 */
590283280Swhu	if (support_multichannel)
591283280Swhu		storvsc_send_multichannel_request(dev, max_chans);
592283280Swhu
593250199Sgrehancleanup:
594250199Sgrehan	sema_destroy(&request->synch_sema);
595250199Sgrehan	return (ret);
596250199Sgrehan}
597250199Sgrehan
598250199Sgrehan/**
599250199Sgrehan * @brief Open channel connection to paraent partition StorVSP driver
600250199Sgrehan *
601250199Sgrehan * Open and initialize channel connection to parent partition StorVSP driver.
602250199Sgrehan *
603250199Sgrehan * @param pointer to a Hyper-V device
604250199Sgrehan * @returns 0 on success, non-zero error on failure
605250199Sgrehan */
606250199Sgrehanstatic int
607250199Sgrehanhv_storvsc_connect_vsp(struct hv_device *dev)
608250199Sgrehan{
609250199Sgrehan	int ret = 0;
610250199Sgrehan	struct vmstor_chan_props props;
611250199Sgrehan	struct storvsc_softc *sc;
612250199Sgrehan
613250199Sgrehan	sc = device_get_softc(dev->device);
614250199Sgrehan
615250199Sgrehan	memset(&props, 0, sizeof(struct vmstor_chan_props));
616250199Sgrehan
617250199Sgrehan	/*
618250199Sgrehan	 * Open the channel
619250199Sgrehan	 */
620250199Sgrehan
621250199Sgrehan	ret = hv_vmbus_channel_open(
622250199Sgrehan		dev->channel,
623250199Sgrehan		sc->hs_drv_props->drv_ringbuffer_size,
624250199Sgrehan		sc->hs_drv_props->drv_ringbuffer_size,
625250199Sgrehan		(void *)&props,
626250199Sgrehan		sizeof(struct vmstor_chan_props),
627250199Sgrehan		hv_storvsc_on_channel_callback,
628283280Swhu		dev->channel);
629250199Sgrehan
630250199Sgrehan	if (ret != 0) {
631250199Sgrehan		return ret;
632250199Sgrehan	}
633250199Sgrehan
634250199Sgrehan	ret = hv_storvsc_channel_init(dev);
635250199Sgrehan
636250199Sgrehan	return (ret);
637250199Sgrehan}
638250199Sgrehan
639250199Sgrehan#if HVS_HOST_RESET
640250199Sgrehanstatic int
641250199Sgrehanhv_storvsc_host_reset(struct hv_device *dev)
642250199Sgrehan{
643250199Sgrehan	int ret = 0;
644250199Sgrehan	struct storvsc_softc *sc;
645250199Sgrehan
646250199Sgrehan	struct hv_storvsc_request *request;
647250199Sgrehan	struct vstor_packet *vstor_packet;
648250199Sgrehan
649250199Sgrehan	sc = get_stor_device(dev, TRUE);
650250199Sgrehan	if (sc == NULL) {
651250199Sgrehan		return ENODEV;
652250199Sgrehan	}
653250199Sgrehan
654250199Sgrehan	request = &sc->hs_reset_req;
655250199Sgrehan	request->softc = sc;
656250199Sgrehan	vstor_packet = &request->vstor_packet;
657250199Sgrehan
658250199Sgrehan	sema_init(&request->synch_sema, 0, "stor synch sema");
659250199Sgrehan
660250199Sgrehan	vstor_packet->operation = VSTOR_OPERATION_RESETBUS;
661250199Sgrehan	vstor_packet->flags = REQUEST_COMPLETION_FLAG;
662250199Sgrehan
663250199Sgrehan	ret = hv_vmbus_channel_send_packet(dev->channel,
664250199Sgrehan			vstor_packet,
665283644Swhu			VSTOR_PKT_SIZE,
666266794Smarius			(uint64_t)(uintptr_t)&sc->hs_reset_req,
667250199Sgrehan			HV_VMBUS_PACKET_TYPE_DATA_IN_BAND,
668250199Sgrehan			HV_VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
669250199Sgrehan
670250199Sgrehan	if (ret != 0) {
671250199Sgrehan		goto cleanup;
672250199Sgrehan	}
673250199Sgrehan
674283280Swhu	ret = sema_timedwait(&request->synch_sema, 5 * hz); /* KYS 5 seconds */
675250199Sgrehan
676250199Sgrehan	if (ret) {
677250199Sgrehan		goto cleanup;
678250199Sgrehan	}
679250199Sgrehan
680250199Sgrehan
681250199Sgrehan	/*
682283280Swhu	 * At this point, all outstanding requests in the adapter
683250199Sgrehan	 * should have been flushed out and return to us
684250199Sgrehan	 */
685250199Sgrehan
686250199Sgrehancleanup:
687250199Sgrehan	sema_destroy(&request->synch_sema);
688250199Sgrehan	return (ret);
689250199Sgrehan}
690250199Sgrehan#endif /* HVS_HOST_RESET */
691250199Sgrehan
692250199Sgrehan/**
693250199Sgrehan * @brief Function to initiate an I/O request
694250199Sgrehan *
695250199Sgrehan * @param device Hyper-V device pointer
696250199Sgrehan * @param request pointer to a request structure
697250199Sgrehan * @returns 0 on success, non-zero error on failure
698250199Sgrehan */
699250199Sgrehanstatic int
700250199Sgrehanhv_storvsc_io_request(struct hv_device *device,
701250199Sgrehan					  struct hv_storvsc_request *request)
702250199Sgrehan{
703250199Sgrehan	struct storvsc_softc *sc;
704250199Sgrehan	struct vstor_packet *vstor_packet = &request->vstor_packet;
705283280Swhu	struct hv_vmbus_channel* outgoing_channel = NULL;
706250199Sgrehan	int ret = 0;
707250199Sgrehan
708250199Sgrehan	sc = get_stor_device(device, TRUE);
709250199Sgrehan
710250199Sgrehan	if (sc == NULL) {
711250199Sgrehan		return ENODEV;
712250199Sgrehan	}
713250199Sgrehan
714250199Sgrehan	vstor_packet->flags |= REQUEST_COMPLETION_FLAG;
715250199Sgrehan
716283644Swhu	vstor_packet->u.vm_srb.length = VSTOR_PKT_SIZE;
717250199Sgrehan
718283644Swhu	vstor_packet->u.vm_srb.sense_info_len = sense_buffer_size;
719250199Sgrehan
720256276Sdim	vstor_packet->u.vm_srb.transfer_len = request->data_buf.length;
721250199Sgrehan
722250199Sgrehan	vstor_packet->operation = VSTOR_OPERATION_EXECUTESRB;
723250199Sgrehan
724283280Swhu	outgoing_channel = vmbus_select_outgoing_channel(device->channel);
725250199Sgrehan
726250199Sgrehan	mtx_unlock(&request->softc->hs_lock);
727250199Sgrehan	if (request->data_buf.length) {
728250199Sgrehan		ret = hv_vmbus_channel_send_packet_multipagebuffer(
729283280Swhu				outgoing_channel,
730250199Sgrehan				&request->data_buf,
731283280Swhu				vstor_packet,
732283644Swhu				VSTOR_PKT_SIZE,
733266794Smarius				(uint64_t)(uintptr_t)request);
734250199Sgrehan
735250199Sgrehan	} else {
736250199Sgrehan		ret = hv_vmbus_channel_send_packet(
737283280Swhu			outgoing_channel,
738250199Sgrehan			vstor_packet,
739283644Swhu			VSTOR_PKT_SIZE,
740266794Smarius			(uint64_t)(uintptr_t)request,
741250199Sgrehan			HV_VMBUS_PACKET_TYPE_DATA_IN_BAND,
742250199Sgrehan			HV_VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
743250199Sgrehan	}
744250199Sgrehan	mtx_lock(&request->softc->hs_lock);
745250199Sgrehan
746250199Sgrehan	if (ret != 0) {
747250199Sgrehan		printf("Unable to send packet %p ret %d", vstor_packet, ret);
748250199Sgrehan	} else {
749250199Sgrehan		atomic_add_int(&sc->hs_num_out_reqs, 1);
750250199Sgrehan	}
751250199Sgrehan
752250199Sgrehan	return (ret);
753250199Sgrehan}
754250199Sgrehan
755250199Sgrehan
756250199Sgrehan/**
757250199Sgrehan * Process IO_COMPLETION_OPERATION and ready
758250199Sgrehan * the result to be completed for upper layer
759250199Sgrehan * processing by the CAM layer.
760250199Sgrehan */
761250199Sgrehanstatic void
762250199Sgrehanhv_storvsc_on_iocompletion(struct storvsc_softc *sc,
763250199Sgrehan			   struct vstor_packet *vstor_packet,
764250199Sgrehan			   struct hv_storvsc_request *request)
765250199Sgrehan{
766250199Sgrehan	struct vmscsi_req *vm_srb;
767250199Sgrehan
768256276Sdim	vm_srb = &vstor_packet->u.vm_srb;
769250199Sgrehan
770250199Sgrehan	if (((vm_srb->scsi_status & 0xFF) == SCSI_STATUS_CHECK_COND) &&
771250199Sgrehan			(vm_srb->srb_status & SRB_STATUS_AUTOSENSE_VALID)) {
772250199Sgrehan		/* Autosense data available */
773250199Sgrehan
774250199Sgrehan		KASSERT(vm_srb->sense_info_len <= request->sense_info_len,
775250199Sgrehan				("vm_srb->sense_info_len <= "
776250199Sgrehan				 "request->sense_info_len"));
777250199Sgrehan
778256276Sdim		memcpy(request->sense_data, vm_srb->u.sense_data,
779250199Sgrehan			vm_srb->sense_info_len);
780250199Sgrehan
781250199Sgrehan		request->sense_info_len = vm_srb->sense_info_len;
782250199Sgrehan	}
783250199Sgrehan
784250199Sgrehan	/* Complete request by passing to the CAM layer */
785250199Sgrehan	storvsc_io_done(request);
786250199Sgrehan	atomic_subtract_int(&sc->hs_num_out_reqs, 1);
787250199Sgrehan	if (sc->hs_drain_notify && (sc->hs_num_out_reqs == 0)) {
788250199Sgrehan		sema_post(&sc->hs_drain_sema);
789250199Sgrehan	}
790250199Sgrehan}
791250199Sgrehan
792250199Sgrehanstatic void
793283644Swhuhv_storvsc_rescan_target(struct storvsc_softc *sc)
794283644Swhu{
795283644Swhu	path_id_t pathid;
796283644Swhu	target_id_t targetid;
797283644Swhu	union ccb *ccb;
798283644Swhu
799283644Swhu	pathid = cam_sim_path(sc->hs_sim);
800283644Swhu	targetid = CAM_TARGET_WILDCARD;
801283644Swhu
802283644Swhu	/*
803283644Swhu	 * Allocate a CCB and schedule a rescan.
804283644Swhu	 */
805283644Swhu	ccb = xpt_alloc_ccb_nowait();
806283644Swhu	if (ccb == NULL) {
807283644Swhu		printf("unable to alloc CCB for rescan\n");
808283644Swhu		return;
809283644Swhu	}
810283644Swhu
811283644Swhu	if (xpt_create_path(&ccb->ccb_h.path, NULL, pathid, targetid,
812283644Swhu	    CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
813283644Swhu		printf("unable to create path for rescan, pathid: %d,"
814283644Swhu		    "targetid: %d\n", pathid, targetid);
815283644Swhu		xpt_free_ccb(ccb);
816283644Swhu		return;
817283644Swhu	}
818283644Swhu
819283644Swhu	if (targetid == CAM_TARGET_WILDCARD)
820283644Swhu		ccb->ccb_h.func_code = XPT_SCAN_BUS;
821283644Swhu	else
822283644Swhu		ccb->ccb_h.func_code = XPT_SCAN_TGT;
823283644Swhu
824283644Swhu	xpt_rescan(ccb);
825283644Swhu}
826283644Swhu
827283644Swhustatic void
828250199Sgrehanhv_storvsc_on_channel_callback(void *context)
829250199Sgrehan{
830250199Sgrehan	int ret = 0;
831283280Swhu	hv_vmbus_channel *channel = (hv_vmbus_channel *)context;
832283280Swhu	struct hv_device *device = NULL;
833250199Sgrehan	struct storvsc_softc *sc;
834250199Sgrehan	uint32_t bytes_recvd;
835250199Sgrehan	uint64_t request_id;
836250199Sgrehan	uint8_t packet[roundup2(sizeof(struct vstor_packet), 8)];
837250199Sgrehan	struct hv_storvsc_request *request;
838250199Sgrehan	struct vstor_packet *vstor_packet;
839250199Sgrehan
840283280Swhu	if (channel->primary_channel != NULL){
841283280Swhu		device = channel->primary_channel->device;
842283280Swhu	} else {
843283280Swhu		device = channel->device;
844283280Swhu	}
845283280Swhu
846283280Swhu	KASSERT(device, ("device is NULL"));
847283280Swhu
848250199Sgrehan	sc = get_stor_device(device, FALSE);
849250199Sgrehan	if (sc == NULL) {
850283280Swhu		printf("Storvsc_error: get stor device failed.\n");
851250199Sgrehan		return;
852250199Sgrehan	}
853250199Sgrehan
854250199Sgrehan	ret = hv_vmbus_channel_recv_packet(
855283280Swhu			channel,
856250199Sgrehan			packet,
857283644Swhu			roundup2(VSTOR_PKT_SIZE, 8),
858250199Sgrehan			&bytes_recvd,
859250199Sgrehan			&request_id);
860250199Sgrehan
861250199Sgrehan	while ((ret == 0) && (bytes_recvd > 0)) {
862266794Smarius		request = (struct hv_storvsc_request *)(uintptr_t)request_id;
863250199Sgrehan
864250199Sgrehan		if ((request == &sc->hs_init_req) ||
865250199Sgrehan			(request == &sc->hs_reset_req)) {
866250199Sgrehan			memcpy(&request->vstor_packet, packet,
867250199Sgrehan				   sizeof(struct vstor_packet));
868283280Swhu			sema_post(&request->synch_sema);
869250199Sgrehan		} else {
870250199Sgrehan			vstor_packet = (struct vstor_packet *)packet;
871250199Sgrehan			switch(vstor_packet->operation) {
872250199Sgrehan			case VSTOR_OPERATION_COMPLETEIO:
873283280Swhu				if (request == NULL)
874283280Swhu					panic("VMBUS: storvsc received a "
875283280Swhu					    "packet with NULL request id in "
876283280Swhu					    "COMPLETEIO operation.");
877283280Swhu
878250199Sgrehan				hv_storvsc_on_iocompletion(sc,
879250199Sgrehan							vstor_packet, request);
880250199Sgrehan				break;
881250199Sgrehan			case VSTOR_OPERATION_REMOVEDEVICE:
882283280Swhu				printf("VMBUS: storvsc operation %d not "
883283280Swhu				    "implemented.\n", vstor_packet->operation);
884250199Sgrehan				/* TODO: implement */
885250199Sgrehan				break;
886283644Swhu			case VSTOR_OPERATION_ENUMERATE_BUS:
887283644Swhu				hv_storvsc_rescan_target(sc);
888283644Swhu				break;
889250199Sgrehan			default:
890250199Sgrehan				break;
891250199Sgrehan			}
892250199Sgrehan		}
893250199Sgrehan		ret = hv_vmbus_channel_recv_packet(
894283280Swhu				channel,
895250199Sgrehan				packet,
896283644Swhu				roundup2(VSTOR_PKT_SIZE, 8),
897250199Sgrehan				&bytes_recvd,
898250199Sgrehan				&request_id);
899250199Sgrehan	}
900250199Sgrehan}
901250199Sgrehan
902250199Sgrehan/**
903250199Sgrehan * @brief StorVSC probe function
904250199Sgrehan *
905250199Sgrehan * Device probe function.  Returns 0 if the input device is a StorVSC
906250199Sgrehan * device.  Otherwise, a ENXIO is returned.  If the input device is
907250199Sgrehan * for BlkVSC (paravirtual IDE) device and this support is disabled in
908250199Sgrehan * favor of the emulated ATA/IDE device, return ENXIO.
909250199Sgrehan *
910250199Sgrehan * @param a device
911250199Sgrehan * @returns 0 on success, ENXIO if not a matcing StorVSC device
912250199Sgrehan */
913250199Sgrehanstatic int
914250199Sgrehanstorvsc_probe(device_t dev)
915250199Sgrehan{
916252645Sgrehan	int ata_disk_enable = 0;
917250199Sgrehan	int ret	= ENXIO;
918283280Swhu
919283644Swhu	if (hv_vmbus_protocal_version == HV_VMBUS_VERSION_WS2008 ||
920283644Swhu	    hv_vmbus_protocal_version == HV_VMBUS_VERSION_WIN7) {
921283644Swhu		sense_buffer_size = PRE_WIN8_STORVSC_SENSE_BUFFER_SIZE;
922283644Swhu		vmscsi_size_delta = sizeof(struct vmscsi_win8_extension);
923283644Swhu		storvsc_current_major = STORVSC_WIN7_MAJOR;
924283644Swhu		storvsc_current_minor = STORVSC_WIN7_MINOR;
925283644Swhu	} else {
926283644Swhu		sense_buffer_size = POST_WIN7_STORVSC_SENSE_BUFFER_SIZE;
927283644Swhu		vmscsi_size_delta = 0;
928283280Swhu		storvsc_current_major = STORVSC_WIN8_MAJOR;
929283280Swhu		storvsc_current_minor = STORVSC_WIN8_MINOR;
930283280Swhu	}
931283280Swhu
932250199Sgrehan	switch (storvsc_get_storage_type(dev)) {
933250199Sgrehan	case DRIVER_BLKVSC:
934252645Sgrehan		if(bootverbose)
935252645Sgrehan			device_printf(dev, "DRIVER_BLKVSC-Emulated ATA/IDE probe\n");
936252645Sgrehan		if (!getenv_int("hw.ata.disk_enable", &ata_disk_enable)) {
937252645Sgrehan			if(bootverbose)
938252645Sgrehan				device_printf(dev,
939252645Sgrehan					"Enlightened ATA/IDE detected\n");
940273580Sdelphij			ret = BUS_PROBE_DEFAULT;
941252645Sgrehan		} else if(bootverbose)
942252645Sgrehan			device_printf(dev, "Emulated ATA/IDE set (hw.ata.disk_enable set)\n");
943250199Sgrehan		break;
944250199Sgrehan	case DRIVER_STORVSC:
945252645Sgrehan		if(bootverbose)
946252645Sgrehan			device_printf(dev, "Enlightened SCSI device detected\n");
947273580Sdelphij		ret = BUS_PROBE_DEFAULT;
948250199Sgrehan		break;
949250199Sgrehan	default:
950250199Sgrehan		ret = ENXIO;
951250199Sgrehan	}
952250199Sgrehan	return (ret);
953250199Sgrehan}
954250199Sgrehan
955250199Sgrehan/**
956250199Sgrehan * @brief StorVSC attach function
957250199Sgrehan *
958250199Sgrehan * Function responsible for allocating per-device structures,
959250199Sgrehan * setting up CAM interfaces and scanning for available LUNs to
960250199Sgrehan * be used for SCSI device peripherals.
961250199Sgrehan *
962250199Sgrehan * @param a device
963250199Sgrehan * @returns 0 on success or an error on failure
964250199Sgrehan */
965250199Sgrehanstatic int
966250199Sgrehanstorvsc_attach(device_t dev)
967250199Sgrehan{
968250199Sgrehan	struct hv_device *hv_dev = vmbus_get_devctx(dev);
969250199Sgrehan	enum hv_storage_type stor_type;
970250199Sgrehan	struct storvsc_softc *sc;
971250199Sgrehan	struct cam_devq *devq;
972283280Swhu	int ret, i, j;
973250199Sgrehan	struct hv_storvsc_request *reqp;
974250199Sgrehan	struct root_hold_token *root_mount_token = NULL;
975283280Swhu	struct hv_sgl_node *sgl_node = NULL;
976283280Swhu	void *tmp_buff = NULL;
977250199Sgrehan
978250199Sgrehan	/*
979250199Sgrehan	 * We need to serialize storvsc attach calls.
980250199Sgrehan	 */
981250199Sgrehan	root_mount_token = root_mount_hold("storvsc");
982250199Sgrehan
983250199Sgrehan	sc = device_get_softc(dev);
984250199Sgrehan	if (sc == NULL) {
985250199Sgrehan		ret = ENOMEM;
986250199Sgrehan		goto cleanup;
987250199Sgrehan	}
988250199Sgrehan
989250199Sgrehan	stor_type = storvsc_get_storage_type(dev);
990250199Sgrehan
991250199Sgrehan	if (stor_type == DRIVER_UNKNOWN) {
992250199Sgrehan		ret = ENODEV;
993250199Sgrehan		goto cleanup;
994250199Sgrehan	}
995250199Sgrehan
996250199Sgrehan	bzero(sc, sizeof(struct storvsc_softc));
997250199Sgrehan
998250199Sgrehan	/* fill in driver specific properties */
999250199Sgrehan	sc->hs_drv_props = &g_drv_props_table[stor_type];
1000250199Sgrehan
1001250199Sgrehan	/* fill in device specific properties */
1002250199Sgrehan	sc->hs_unit	= device_get_unit(dev);
1003250199Sgrehan	sc->hs_dev	= hv_dev;
1004250199Sgrehan	device_set_desc(dev, g_drv_props_table[stor_type].drv_desc);
1005250199Sgrehan
1006250199Sgrehan	LIST_INIT(&sc->hs_free_list);
1007250199Sgrehan	mtx_init(&sc->hs_lock, "hvslck", NULL, MTX_DEF);
1008250199Sgrehan
1009250199Sgrehan	for (i = 0; i < sc->hs_drv_props->drv_max_ios_per_target; ++i) {
1010250199Sgrehan		reqp = malloc(sizeof(struct hv_storvsc_request),
1011250199Sgrehan				 M_DEVBUF, M_WAITOK|M_ZERO);
1012250199Sgrehan		reqp->softc = sc;
1013250199Sgrehan
1014250199Sgrehan		LIST_INSERT_HEAD(&sc->hs_free_list, reqp, link);
1015250199Sgrehan	}
1016250199Sgrehan
1017283280Swhu	/* create sg-list page pool */
1018283280Swhu	if (FALSE == g_hv_sgl_page_pool.is_init) {
1019283280Swhu		g_hv_sgl_page_pool.is_init = TRUE;
1020283280Swhu		LIST_INIT(&g_hv_sgl_page_pool.in_use_sgl_list);
1021283280Swhu		LIST_INIT(&g_hv_sgl_page_pool.free_sgl_list);
1022283280Swhu
1023283280Swhu		/*
1024283280Swhu		 * Pre-create SG list, each SG list with
1025283280Swhu		 * HV_MAX_MULTIPAGE_BUFFER_COUNT segments, each
1026283280Swhu		 * segment has one page buffer
1027283280Swhu		 */
1028283280Swhu		for (i = 0; i < STORVSC_MAX_IO_REQUESTS; i++) {
1029283280Swhu	        	sgl_node = malloc(sizeof(struct hv_sgl_node),
1030283280Swhu			    M_DEVBUF, M_WAITOK|M_ZERO);
1031283280Swhu
1032283280Swhu			sgl_node->sgl_data =
1033283280Swhu			    sglist_alloc(HV_MAX_MULTIPAGE_BUFFER_COUNT,
1034283280Swhu			    M_WAITOK|M_ZERO);
1035283280Swhu
1036283280Swhu			for (j = 0; j < HV_MAX_MULTIPAGE_BUFFER_COUNT; j++) {
1037283280Swhu				tmp_buff = malloc(PAGE_SIZE,
1038283280Swhu				    M_DEVBUF, M_WAITOK|M_ZERO);
1039283280Swhu
1040283280Swhu				sgl_node->sgl_data->sg_segs[j].ss_paddr =
1041283280Swhu				    (vm_paddr_t)tmp_buff;
1042283280Swhu			}
1043283280Swhu
1044283280Swhu			LIST_INSERT_HEAD(&g_hv_sgl_page_pool.free_sgl_list,
1045283280Swhu			    sgl_node, link);
1046283280Swhu		}
1047283280Swhu	}
1048283280Swhu
1049250199Sgrehan	sc->hs_destroy = FALSE;
1050250199Sgrehan	sc->hs_drain_notify = FALSE;
1051283280Swhu	sc->hs_open_multi_channel = FALSE;
1052250199Sgrehan	sema_init(&sc->hs_drain_sema, 0, "Store Drain Sema");
1053250199Sgrehan
1054250199Sgrehan	ret = hv_storvsc_connect_vsp(hv_dev);
1055250199Sgrehan	if (ret != 0) {
1056250199Sgrehan		goto cleanup;
1057250199Sgrehan	}
1058250199Sgrehan
1059250199Sgrehan	/*
1060250199Sgrehan	 * Create the device queue.
1061250199Sgrehan	 * Hyper-V maps each target to one SCSI HBA
1062250199Sgrehan	 */
1063250199Sgrehan	devq = cam_simq_alloc(sc->hs_drv_props->drv_max_ios_per_target);
1064250199Sgrehan	if (devq == NULL) {
1065250199Sgrehan		device_printf(dev, "Failed to alloc device queue\n");
1066250199Sgrehan		ret = ENOMEM;
1067250199Sgrehan		goto cleanup;
1068250199Sgrehan	}
1069250199Sgrehan
1070250199Sgrehan	sc->hs_sim = cam_sim_alloc(storvsc_action,
1071250199Sgrehan				storvsc_poll,
1072250199Sgrehan				sc->hs_drv_props->drv_name,
1073250199Sgrehan				sc,
1074250199Sgrehan				sc->hs_unit,
1075250199Sgrehan				&sc->hs_lock, 1,
1076250199Sgrehan				sc->hs_drv_props->drv_max_ios_per_target,
1077250199Sgrehan				devq);
1078250199Sgrehan
1079250199Sgrehan	if (sc->hs_sim == NULL) {
1080250199Sgrehan		device_printf(dev, "Failed to alloc sim\n");
1081250199Sgrehan		cam_simq_free(devq);
1082250199Sgrehan		ret = ENOMEM;
1083250199Sgrehan		goto cleanup;
1084250199Sgrehan	}
1085250199Sgrehan
1086250199Sgrehan	mtx_lock(&sc->hs_lock);
1087250199Sgrehan	/* bus_id is set to 0, need to get it from VMBUS channel query? */
1088250199Sgrehan	if (xpt_bus_register(sc->hs_sim, dev, 0) != CAM_SUCCESS) {
1089250199Sgrehan		cam_sim_free(sc->hs_sim, /*free_devq*/TRUE);
1090250199Sgrehan		mtx_unlock(&sc->hs_lock);
1091250199Sgrehan		device_printf(dev, "Unable to register SCSI bus\n");
1092250199Sgrehan		ret = ENXIO;
1093250199Sgrehan		goto cleanup;
1094250199Sgrehan	}
1095250199Sgrehan
1096250199Sgrehan	if (xpt_create_path(&sc->hs_path, /*periph*/NULL,
1097250199Sgrehan		 cam_sim_path(sc->hs_sim),
1098250199Sgrehan		CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
1099250199Sgrehan		xpt_bus_deregister(cam_sim_path(sc->hs_sim));
1100250199Sgrehan		cam_sim_free(sc->hs_sim, /*free_devq*/TRUE);
1101250199Sgrehan		mtx_unlock(&sc->hs_lock);
1102250199Sgrehan		device_printf(dev, "Unable to create path\n");
1103250199Sgrehan		ret = ENXIO;
1104250199Sgrehan		goto cleanup;
1105250199Sgrehan	}
1106250199Sgrehan
1107250199Sgrehan	mtx_unlock(&sc->hs_lock);
1108250199Sgrehan
1109250199Sgrehan	root_mount_rel(root_mount_token);
1110250199Sgrehan	return (0);
1111250199Sgrehan
1112250199Sgrehan
1113250199Sgrehancleanup:
1114250199Sgrehan	root_mount_rel(root_mount_token);
1115250199Sgrehan	while (!LIST_EMPTY(&sc->hs_free_list)) {
1116250199Sgrehan		reqp = LIST_FIRST(&sc->hs_free_list);
1117250199Sgrehan		LIST_REMOVE(reqp, link);
1118250199Sgrehan		free(reqp, M_DEVBUF);
1119250199Sgrehan	}
1120283280Swhu
1121283280Swhu	while (!LIST_EMPTY(&g_hv_sgl_page_pool.free_sgl_list)) {
1122283280Swhu		sgl_node = LIST_FIRST(&g_hv_sgl_page_pool.free_sgl_list);
1123283280Swhu		LIST_REMOVE(sgl_node, link);
1124283280Swhu		for (j = 0; j < HV_MAX_MULTIPAGE_BUFFER_COUNT; j++) {
1125283280Swhu			if (NULL !=
1126283280Swhu			    (void*)sgl_node->sgl_data->sg_segs[j].ss_paddr) {
1127283280Swhu				free((void*)sgl_node->sgl_data->sg_segs[j].ss_paddr, M_DEVBUF);
1128283280Swhu			}
1129283280Swhu		}
1130283280Swhu		sglist_free(sgl_node->sgl_data);
1131283280Swhu		free(sgl_node, M_DEVBUF);
1132283280Swhu	}
1133283280Swhu
1134250199Sgrehan	return (ret);
1135250199Sgrehan}
1136250199Sgrehan
1137250199Sgrehan/**
1138250199Sgrehan * @brief StorVSC device detach function
1139250199Sgrehan *
1140250199Sgrehan * This function is responsible for safely detaching a
1141250199Sgrehan * StorVSC device.  This includes waiting for inbound responses
1142250199Sgrehan * to complete and freeing associated per-device structures.
1143250199Sgrehan *
1144250199Sgrehan * @param dev a device
1145250199Sgrehan * returns 0 on success
1146250199Sgrehan */
1147250199Sgrehanstatic int
1148250199Sgrehanstorvsc_detach(device_t dev)
1149250199Sgrehan{
1150250199Sgrehan	struct storvsc_softc *sc = device_get_softc(dev);
1151250199Sgrehan	struct hv_storvsc_request *reqp = NULL;
1152250199Sgrehan	struct hv_device *hv_device = vmbus_get_devctx(dev);
1153283280Swhu	struct hv_sgl_node *sgl_node = NULL;
1154283280Swhu	int j = 0;
1155250199Sgrehan
1156250199Sgrehan	mtx_lock(&hv_device->channel->inbound_lock);
1157250199Sgrehan	sc->hs_destroy = TRUE;
1158250199Sgrehan	mtx_unlock(&hv_device->channel->inbound_lock);
1159250199Sgrehan
1160250199Sgrehan	/*
1161250199Sgrehan	 * At this point, all outbound traffic should be disabled. We
1162250199Sgrehan	 * only allow inbound traffic (responses) to proceed so that
1163250199Sgrehan	 * outstanding requests can be completed.
1164250199Sgrehan	 */
1165250199Sgrehan
1166250199Sgrehan	sc->hs_drain_notify = TRUE;
1167250199Sgrehan	sema_wait(&sc->hs_drain_sema);
1168250199Sgrehan	sc->hs_drain_notify = FALSE;
1169250199Sgrehan
1170250199Sgrehan	/*
1171250199Sgrehan	 * Since we have already drained, we don't need to busy wait.
1172250199Sgrehan	 * The call to close the channel will reset the callback
1173250199Sgrehan	 * under the protection of the incoming channel lock.
1174250199Sgrehan	 */
1175250199Sgrehan
1176250199Sgrehan	hv_vmbus_channel_close(hv_device->channel);
1177250199Sgrehan
1178250199Sgrehan	mtx_lock(&sc->hs_lock);
1179250199Sgrehan	while (!LIST_EMPTY(&sc->hs_free_list)) {
1180250199Sgrehan		reqp = LIST_FIRST(&sc->hs_free_list);
1181250199Sgrehan		LIST_REMOVE(reqp, link);
1182250199Sgrehan
1183250199Sgrehan		free(reqp, M_DEVBUF);
1184250199Sgrehan	}
1185250199Sgrehan	mtx_unlock(&sc->hs_lock);
1186283280Swhu
1187283280Swhu	while (!LIST_EMPTY(&g_hv_sgl_page_pool.free_sgl_list)) {
1188283280Swhu		sgl_node = LIST_FIRST(&g_hv_sgl_page_pool.free_sgl_list);
1189283280Swhu		LIST_REMOVE(sgl_node, link);
1190283280Swhu		for (j = 0; j < HV_MAX_MULTIPAGE_BUFFER_COUNT; j++){
1191283280Swhu			if (NULL !=
1192283280Swhu			    (void*)sgl_node->sgl_data->sg_segs[j].ss_paddr) {
1193283280Swhu				free((void*)sgl_node->sgl_data->sg_segs[j].ss_paddr, M_DEVBUF);
1194283280Swhu			}
1195283280Swhu		}
1196283280Swhu		sglist_free(sgl_node->sgl_data);
1197283280Swhu		free(sgl_node, M_DEVBUF);
1198283280Swhu	}
1199283280Swhu
1200250199Sgrehan	return (0);
1201250199Sgrehan}
1202250199Sgrehan
1203250199Sgrehan#if HVS_TIMEOUT_TEST
1204250199Sgrehan/**
1205250199Sgrehan * @brief unit test for timed out operations
1206250199Sgrehan *
1207250199Sgrehan * This function provides unit testing capability to simulate
1208250199Sgrehan * timed out operations.  Recompilation with HV_TIMEOUT_TEST=1
1209250199Sgrehan * is required.
1210250199Sgrehan *
1211250199Sgrehan * @param reqp pointer to a request structure
1212250199Sgrehan * @param opcode SCSI operation being performed
1213250199Sgrehan * @param wait if 1, wait for I/O to complete
1214250199Sgrehan */
1215250199Sgrehanstatic void
1216250199Sgrehanstorvsc_timeout_test(struct hv_storvsc_request *reqp,
1217250199Sgrehan		uint8_t opcode, int wait)
1218250199Sgrehan{
1219250199Sgrehan	int ret;
1220250199Sgrehan	union ccb *ccb = reqp->ccb;
1221250199Sgrehan	struct storvsc_softc *sc = reqp->softc;
1222250199Sgrehan
1223250199Sgrehan	if (reqp->vstor_packet.vm_srb.cdb[0] != opcode) {
1224250199Sgrehan		return;
1225250199Sgrehan	}
1226250199Sgrehan
1227250199Sgrehan	if (wait) {
1228250199Sgrehan		mtx_lock(&reqp->event.mtx);
1229250199Sgrehan	}
1230250199Sgrehan	ret = hv_storvsc_io_request(sc->hs_dev, reqp);
1231250199Sgrehan	if (ret != 0) {
1232250199Sgrehan		if (wait) {
1233250199Sgrehan			mtx_unlock(&reqp->event.mtx);
1234250199Sgrehan		}
1235250199Sgrehan		printf("%s: io_request failed with %d.\n",
1236250199Sgrehan				__func__, ret);
1237250199Sgrehan		ccb->ccb_h.status = CAM_PROVIDE_FAIL;
1238250199Sgrehan		mtx_lock(&sc->hs_lock);
1239250199Sgrehan		storvsc_free_request(sc, reqp);
1240250199Sgrehan		xpt_done(ccb);
1241250199Sgrehan		mtx_unlock(&sc->hs_lock);
1242250199Sgrehan		return;
1243250199Sgrehan	}
1244250199Sgrehan
1245250199Sgrehan	if (wait) {
1246250199Sgrehan		xpt_print(ccb->ccb_h.path,
1247250199Sgrehan				"%u: %s: waiting for IO return.\n",
1248250199Sgrehan				ticks, __func__);
1249250199Sgrehan		ret = cv_timedwait(&reqp->event.cv, &reqp->event.mtx, 60*hz);
1250250199Sgrehan		mtx_unlock(&reqp->event.mtx);
1251250199Sgrehan		xpt_print(ccb->ccb_h.path, "%u: %s: %s.\n",
1252250199Sgrehan				ticks, __func__, (ret == 0)?
1253250199Sgrehan				"IO return detected" :
1254250199Sgrehan				"IO return not detected");
1255283280Swhu		/*
1256250199Sgrehan		 * Now both the timer handler and io done are running
1257250199Sgrehan		 * simultaneously. We want to confirm the io done always
1258250199Sgrehan		 * finishes after the timer handler exits. So reqp used by
1259250199Sgrehan		 * timer handler is not freed or stale. Do busy loop for
1260250199Sgrehan		 * another 1/10 second to make sure io done does
1261250199Sgrehan		 * wait for the timer handler to complete.
1262250199Sgrehan		 */
1263250199Sgrehan		DELAY(100*1000);
1264250199Sgrehan		mtx_lock(&sc->hs_lock);
1265250199Sgrehan		xpt_print(ccb->ccb_h.path,
1266250199Sgrehan				"%u: %s: finishing, queue frozen %d, "
1267250199Sgrehan				"ccb status 0x%x scsi_status 0x%x.\n",
1268250199Sgrehan				ticks, __func__, sc->hs_frozen,
1269250199Sgrehan				ccb->ccb_h.status,
1270250199Sgrehan				ccb->csio.scsi_status);
1271250199Sgrehan		mtx_unlock(&sc->hs_lock);
1272250199Sgrehan	}
1273250199Sgrehan}
1274250199Sgrehan#endif /* HVS_TIMEOUT_TEST */
1275250199Sgrehan
1276250199Sgrehan/**
1277250199Sgrehan * @brief timeout handler for requests
1278250199Sgrehan *
1279250199Sgrehan * This function is called as a result of a callout expiring.
1280250199Sgrehan *
1281250199Sgrehan * @param arg pointer to a request
1282250199Sgrehan */
1283250199Sgrehanstatic void
1284250199Sgrehanstorvsc_timeout(void *arg)
1285250199Sgrehan{
1286250199Sgrehan	struct hv_storvsc_request *reqp = arg;
1287250199Sgrehan	struct storvsc_softc *sc = reqp->softc;
1288250199Sgrehan	union ccb *ccb = reqp->ccb;
1289250199Sgrehan
1290250199Sgrehan	if (reqp->retries == 0) {
1291250199Sgrehan		mtx_lock(&sc->hs_lock);
1292250199Sgrehan		xpt_print(ccb->ccb_h.path,
1293250199Sgrehan		    "%u: IO timed out (req=0x%p), wait for another %u secs.\n",
1294250199Sgrehan		    ticks, reqp, ccb->ccb_h.timeout / 1000);
1295250199Sgrehan		cam_error_print(ccb, CAM_ESF_ALL, CAM_EPF_ALL);
1296250199Sgrehan		mtx_unlock(&sc->hs_lock);
1297250199Sgrehan
1298250199Sgrehan		reqp->retries++;
1299275982Ssmh		callout_reset_sbt(&reqp->callout, SBT_1MS * ccb->ccb_h.timeout,
1300275982Ssmh		    0, storvsc_timeout, reqp, 0);
1301250199Sgrehan#if HVS_TIMEOUT_TEST
1302250199Sgrehan		storvsc_timeout_test(reqp, SEND_DIAGNOSTIC, 0);
1303250199Sgrehan#endif
1304250199Sgrehan		return;
1305250199Sgrehan	}
1306250199Sgrehan
1307250199Sgrehan	mtx_lock(&sc->hs_lock);
1308250199Sgrehan	xpt_print(ccb->ccb_h.path,
1309250199Sgrehan		"%u: IO (reqp = 0x%p) did not return for %u seconds, %s.\n",
1310250199Sgrehan		ticks, reqp, ccb->ccb_h.timeout * (reqp->retries+1) / 1000,
1311250199Sgrehan		(sc->hs_frozen == 0)?
1312250199Sgrehan		"freezing the queue" : "the queue is already frozen");
1313250199Sgrehan	if (sc->hs_frozen == 0) {
1314250199Sgrehan		sc->hs_frozen = 1;
1315250199Sgrehan		xpt_freeze_simq(xpt_path_sim(ccb->ccb_h.path), 1);
1316250199Sgrehan	}
1317250199Sgrehan	mtx_unlock(&sc->hs_lock);
1318250199Sgrehan
1319250199Sgrehan#if HVS_TIMEOUT_TEST
1320250199Sgrehan	storvsc_timeout_test(reqp, MODE_SELECT_10, 1);
1321250199Sgrehan#endif
1322250199Sgrehan}
1323250199Sgrehan
1324250199Sgrehan/**
1325250199Sgrehan * @brief StorVSC device poll function
1326250199Sgrehan *
1327250199Sgrehan * This function is responsible for servicing requests when
1328250199Sgrehan * interrupts are disabled (i.e when we are dumping core.)
1329250199Sgrehan *
1330250199Sgrehan * @param sim a pointer to a CAM SCSI interface module
1331250199Sgrehan */
1332250199Sgrehanstatic void
1333250199Sgrehanstorvsc_poll(struct cam_sim *sim)
1334250199Sgrehan{
1335250199Sgrehan	struct storvsc_softc *sc = cam_sim_softc(sim);
1336250199Sgrehan
1337250199Sgrehan	mtx_assert(&sc->hs_lock, MA_OWNED);
1338250199Sgrehan	mtx_unlock(&sc->hs_lock);
1339283280Swhu	hv_storvsc_on_channel_callback(sc->hs_dev->channel);
1340250199Sgrehan	mtx_lock(&sc->hs_lock);
1341250199Sgrehan}
1342250199Sgrehan
1343250199Sgrehan/**
1344250199Sgrehan * @brief StorVSC device action function
1345250199Sgrehan *
1346250199Sgrehan * This function is responsible for handling SCSI operations which
1347250199Sgrehan * are passed from the CAM layer.  The requests are in the form of
1348250199Sgrehan * CAM control blocks which indicate the action being performed.
1349250199Sgrehan * Not all actions require converting the request to a VSCSI protocol
1350250199Sgrehan * message - these actions can be responded to by this driver.
1351250199Sgrehan * Requests which are destined for a backend storage device are converted
1352250199Sgrehan * to a VSCSI protocol message and sent on the channel connection associated
1353250199Sgrehan * with this device.
1354250199Sgrehan *
1355250199Sgrehan * @param sim pointer to a CAM SCSI interface module
1356250199Sgrehan * @param ccb pointer to a CAM control block
1357250199Sgrehan */
1358250199Sgrehanstatic void
1359250199Sgrehanstorvsc_action(struct cam_sim *sim, union ccb *ccb)
1360250199Sgrehan{
1361250199Sgrehan	struct storvsc_softc *sc = cam_sim_softc(sim);
1362250199Sgrehan	int res;
1363250199Sgrehan
1364250199Sgrehan	mtx_assert(&sc->hs_lock, MA_OWNED);
1365250199Sgrehan	switch (ccb->ccb_h.func_code) {
1366250199Sgrehan	case XPT_PATH_INQ: {
1367250199Sgrehan		struct ccb_pathinq *cpi = &ccb->cpi;
1368250199Sgrehan
1369250199Sgrehan		cpi->version_num = 1;
1370250199Sgrehan		cpi->hba_inquiry = PI_TAG_ABLE|PI_SDTR_ABLE;
1371250199Sgrehan		cpi->target_sprt = 0;
1372250199Sgrehan		cpi->hba_misc = PIM_NOBUSRESET;
1373250199Sgrehan		cpi->hba_eng_cnt = 0;
1374250199Sgrehan		cpi->max_target = STORVSC_MAX_TARGETS;
1375250199Sgrehan		cpi->max_lun = sc->hs_drv_props->drv_max_luns_per_target;
1376263065Smav		cpi->initiator_id = cpi->max_target;
1377250199Sgrehan		cpi->bus_id = cam_sim_bus(sim);
1378250199Sgrehan		cpi->base_transfer_speed = 300000;
1379250199Sgrehan		cpi->transport = XPORT_SAS;
1380250199Sgrehan		cpi->transport_version = 0;
1381250199Sgrehan		cpi->protocol = PROTO_SCSI;
1382250199Sgrehan		cpi->protocol_version = SCSI_REV_SPC2;
1383250199Sgrehan		strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
1384250199Sgrehan		strncpy(cpi->hba_vid, sc->hs_drv_props->drv_name, HBA_IDLEN);
1385250199Sgrehan		strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
1386250199Sgrehan		cpi->unit_number = cam_sim_unit(sim);
1387250199Sgrehan
1388250199Sgrehan		ccb->ccb_h.status = CAM_REQ_CMP;
1389250199Sgrehan		xpt_done(ccb);
1390250199Sgrehan		return;
1391250199Sgrehan	}
1392250199Sgrehan	case XPT_GET_TRAN_SETTINGS: {
1393250199Sgrehan		struct  ccb_trans_settings *cts = &ccb->cts;
1394250199Sgrehan
1395250199Sgrehan		cts->transport = XPORT_SAS;
1396250199Sgrehan		cts->transport_version = 0;
1397250199Sgrehan		cts->protocol = PROTO_SCSI;
1398250199Sgrehan		cts->protocol_version = SCSI_REV_SPC2;
1399250199Sgrehan
1400250199Sgrehan		/* enable tag queuing and disconnected mode */
1401250199Sgrehan		cts->proto_specific.valid = CTS_SCSI_VALID_TQ;
1402250199Sgrehan		cts->proto_specific.scsi.valid = CTS_SCSI_VALID_TQ;
1403250199Sgrehan		cts->proto_specific.scsi.flags = CTS_SCSI_FLAGS_TAG_ENB;
1404250199Sgrehan		cts->xport_specific.valid = CTS_SPI_VALID_DISC;
1405250199Sgrehan		cts->xport_specific.spi.flags = CTS_SPI_FLAGS_DISC_ENB;
1406250199Sgrehan
1407250199Sgrehan		ccb->ccb_h.status = CAM_REQ_CMP;
1408250199Sgrehan		xpt_done(ccb);
1409250199Sgrehan		return;
1410250199Sgrehan	}
1411250199Sgrehan	case XPT_SET_TRAN_SETTINGS:	{
1412250199Sgrehan		ccb->ccb_h.status = CAM_REQ_CMP;
1413250199Sgrehan		xpt_done(ccb);
1414250199Sgrehan		return;
1415250199Sgrehan	}
1416250199Sgrehan	case XPT_CALC_GEOMETRY:{
1417250199Sgrehan		cam_calc_geometry(&ccb->ccg, 1);
1418250199Sgrehan		xpt_done(ccb);
1419250199Sgrehan		return;
1420250199Sgrehan	}
1421250199Sgrehan	case  XPT_RESET_BUS:
1422250199Sgrehan	case  XPT_RESET_DEV:{
1423250199Sgrehan#if HVS_HOST_RESET
1424250199Sgrehan		if ((res = hv_storvsc_host_reset(sc->hs_dev)) != 0) {
1425250199Sgrehan			xpt_print(ccb->ccb_h.path,
1426250199Sgrehan				"hv_storvsc_host_reset failed with %d\n", res);
1427250199Sgrehan			ccb->ccb_h.status = CAM_PROVIDE_FAIL;
1428250199Sgrehan			xpt_done(ccb);
1429250199Sgrehan			return;
1430250199Sgrehan		}
1431250199Sgrehan		ccb->ccb_h.status = CAM_REQ_CMP;
1432250199Sgrehan		xpt_done(ccb);
1433250199Sgrehan		return;
1434250199Sgrehan#else
1435250199Sgrehan		xpt_print(ccb->ccb_h.path,
1436250199Sgrehan				  "%s reset not supported.\n",
1437250199Sgrehan				  (ccb->ccb_h.func_code == XPT_RESET_BUS)?
1438250199Sgrehan				  "bus" : "dev");
1439250199Sgrehan		ccb->ccb_h.status = CAM_REQ_INVALID;
1440250199Sgrehan		xpt_done(ccb);
1441250199Sgrehan		return;
1442250199Sgrehan#endif	/* HVS_HOST_RESET */
1443250199Sgrehan	}
1444250199Sgrehan	case XPT_SCSI_IO:
1445250199Sgrehan	case XPT_IMMED_NOTIFY: {
1446250199Sgrehan		struct hv_storvsc_request *reqp = NULL;
1447250199Sgrehan
1448250199Sgrehan		if (ccb->csio.cdb_len == 0) {
1449250199Sgrehan			panic("cdl_len is 0\n");
1450250199Sgrehan		}
1451250199Sgrehan
1452250199Sgrehan		if (LIST_EMPTY(&sc->hs_free_list)) {
1453250199Sgrehan			ccb->ccb_h.status = CAM_REQUEUE_REQ;
1454250199Sgrehan			if (sc->hs_frozen == 0) {
1455250199Sgrehan				sc->hs_frozen = 1;
1456250199Sgrehan				xpt_freeze_simq(sim, /* count*/1);
1457250199Sgrehan			}
1458250199Sgrehan			xpt_done(ccb);
1459250199Sgrehan			return;
1460250199Sgrehan		}
1461250199Sgrehan
1462250199Sgrehan		reqp = LIST_FIRST(&sc->hs_free_list);
1463250199Sgrehan		LIST_REMOVE(reqp, link);
1464250199Sgrehan
1465250199Sgrehan		bzero(reqp, sizeof(struct hv_storvsc_request));
1466250199Sgrehan		reqp->softc = sc;
1467283280Swhu
1468283280Swhu		ccb->ccb_h.status |= CAM_SIM_QUEUED;
1469283280Swhu		if ((res = create_storvsc_request(ccb, reqp)) != 0) {
1470283280Swhu			ccb->ccb_h.status = CAM_REQ_INVALID;
1471283280Swhu			xpt_done(ccb);
1472283280Swhu			return;
1473283280Swhu		}
1474250199Sgrehan
1475250199Sgrehan		if (ccb->ccb_h.timeout != CAM_TIME_INFINITY) {
1476250199Sgrehan			callout_init(&reqp->callout, CALLOUT_MPSAFE);
1477275982Ssmh			callout_reset_sbt(&reqp->callout,
1478275982Ssmh			    SBT_1MS * ccb->ccb_h.timeout, 0,
1479275982Ssmh			    storvsc_timeout, reqp, 0);
1480250199Sgrehan#if HVS_TIMEOUT_TEST
1481250199Sgrehan			cv_init(&reqp->event.cv, "storvsc timeout cv");
1482250199Sgrehan			mtx_init(&reqp->event.mtx, "storvsc timeout mutex",
1483250199Sgrehan					NULL, MTX_DEF);
1484250199Sgrehan			switch (reqp->vstor_packet.vm_srb.cdb[0]) {
1485250199Sgrehan				case MODE_SELECT_10:
1486250199Sgrehan				case SEND_DIAGNOSTIC:
1487250199Sgrehan					/* To have timer send the request. */
1488250199Sgrehan					return;
1489250199Sgrehan				default:
1490250199Sgrehan					break;
1491250199Sgrehan			}
1492250199Sgrehan#endif /* HVS_TIMEOUT_TEST */
1493250199Sgrehan		}
1494250199Sgrehan
1495250199Sgrehan		if ((res = hv_storvsc_io_request(sc->hs_dev, reqp)) != 0) {
1496250199Sgrehan			xpt_print(ccb->ccb_h.path,
1497250199Sgrehan				"hv_storvsc_io_request failed with %d\n", res);
1498250199Sgrehan			ccb->ccb_h.status = CAM_PROVIDE_FAIL;
1499250199Sgrehan			storvsc_free_request(sc, reqp);
1500250199Sgrehan			xpt_done(ccb);
1501250199Sgrehan			return;
1502250199Sgrehan		}
1503250199Sgrehan		return;
1504250199Sgrehan	}
1505250199Sgrehan
1506250199Sgrehan	default:
1507250199Sgrehan		ccb->ccb_h.status = CAM_REQ_INVALID;
1508250199Sgrehan		xpt_done(ccb);
1509250199Sgrehan		return;
1510250199Sgrehan	}
1511250199Sgrehan}
1512250199Sgrehan
1513250199Sgrehan/**
1514283280Swhu * @brief destroy bounce buffer
1515283280Swhu *
1516283280Swhu * This function is responsible for destroy a Scatter/Gather list
1517283280Swhu * that create by storvsc_create_bounce_buffer()
1518283280Swhu *
1519283280Swhu * @param sgl- the Scatter/Gather need be destroy
1520283280Swhu * @param sg_count- page count of the SG list.
1521283280Swhu *
1522283280Swhu */
1523283280Swhustatic void
1524283280Swhustorvsc_destroy_bounce_buffer(struct sglist *sgl)
1525283280Swhu{
1526283280Swhu	struct hv_sgl_node *sgl_node = NULL;
1527283280Swhu
1528283280Swhu	sgl_node = LIST_FIRST(&g_hv_sgl_page_pool.in_use_sgl_list);
1529283280Swhu	LIST_REMOVE(sgl_node, link);
1530283280Swhu	if (NULL == sgl_node) {
1531283280Swhu		printf("storvsc error: not enough in use sgl\n");
1532283280Swhu		return;
1533283280Swhu	}
1534283280Swhu	sgl_node->sgl_data = sgl;
1535283280Swhu	LIST_INSERT_HEAD(&g_hv_sgl_page_pool.free_sgl_list, sgl_node, link);
1536283280Swhu}
1537283280Swhu
1538283280Swhu/**
1539283280Swhu * @brief create bounce buffer
1540283280Swhu *
1541283280Swhu * This function is responsible for create a Scatter/Gather list,
1542283280Swhu * which hold several pages that can be aligned with page size.
1543283280Swhu *
1544283280Swhu * @param seg_count- SG-list segments count
1545283280Swhu * @param write - if WRITE_TYPE, set SG list page used size to 0,
1546283280Swhu * otherwise set used size to page size.
1547283280Swhu *
1548283280Swhu * return NULL if create failed
1549283280Swhu */
1550283280Swhustatic struct sglist *
1551283280Swhustorvsc_create_bounce_buffer(uint16_t seg_count, int write)
1552283280Swhu{
1553283280Swhu	int i = 0;
1554283280Swhu	struct sglist *bounce_sgl = NULL;
1555283280Swhu	unsigned int buf_len = ((write == WRITE_TYPE) ? 0 : PAGE_SIZE);
1556283280Swhu	struct hv_sgl_node *sgl_node = NULL;
1557283280Swhu
1558283280Swhu	/* get struct sglist from free_sgl_list */
1559283280Swhu	sgl_node = LIST_FIRST(&g_hv_sgl_page_pool.free_sgl_list);
1560283280Swhu	LIST_REMOVE(sgl_node, link);
1561283280Swhu	if (NULL == sgl_node) {
1562283280Swhu		printf("storvsc error: not enough free sgl\n");
1563283280Swhu		return NULL;
1564283280Swhu	}
1565283280Swhu	bounce_sgl = sgl_node->sgl_data;
1566283280Swhu	LIST_INSERT_HEAD(&g_hv_sgl_page_pool.in_use_sgl_list, sgl_node, link);
1567283280Swhu
1568283280Swhu	bounce_sgl->sg_maxseg = seg_count;
1569283280Swhu
1570283280Swhu	if (write == WRITE_TYPE)
1571283280Swhu		bounce_sgl->sg_nseg = 0;
1572283280Swhu	else
1573283280Swhu		bounce_sgl->sg_nseg = seg_count;
1574283280Swhu
1575283280Swhu	for (i = 0; i < seg_count; i++)
1576283280Swhu	        bounce_sgl->sg_segs[i].ss_len = buf_len;
1577283280Swhu
1578283280Swhu	return bounce_sgl;
1579283280Swhu}
1580283280Swhu
1581283280Swhu/**
1582283280Swhu * @brief copy data from SG list to bounce buffer
1583283280Swhu *
1584283280Swhu * This function is responsible for copy data from one SG list's segments
1585283280Swhu * to another SG list which used as bounce buffer.
1586283280Swhu *
1587283280Swhu * @param bounce_sgl - the destination SG list
1588283280Swhu * @param orig_sgl - the segment of the source SG list.
1589283280Swhu * @param orig_sgl_count - the count of segments.
1590283280Swhu * @param orig_sgl_count - indicate which segment need bounce buffer,
1591283280Swhu *  set 1 means need.
1592283280Swhu *
1593283280Swhu */
1594283280Swhustatic void
1595283280Swhustorvsc_copy_sgl_to_bounce_buf(struct sglist *bounce_sgl,
1596283280Swhu			       bus_dma_segment_t *orig_sgl,
1597283280Swhu			       unsigned int orig_sgl_count,
1598283280Swhu			       uint64_t seg_bits)
1599283280Swhu{
1600283280Swhu	int src_sgl_idx = 0;
1601283280Swhu
1602283280Swhu	for (src_sgl_idx = 0; src_sgl_idx < orig_sgl_count; src_sgl_idx++) {
1603283280Swhu		if (seg_bits & (1 << src_sgl_idx)) {
1604283280Swhu			memcpy((void*)bounce_sgl->sg_segs[src_sgl_idx].ss_paddr,
1605283280Swhu			    (void*)orig_sgl[src_sgl_idx].ds_addr,
1606283280Swhu			    orig_sgl[src_sgl_idx].ds_len);
1607283280Swhu
1608283280Swhu			bounce_sgl->sg_segs[src_sgl_idx].ss_len =
1609283280Swhu			    orig_sgl[src_sgl_idx].ds_len;
1610283280Swhu		}
1611283280Swhu	}
1612283280Swhu}
1613283280Swhu
1614283280Swhu/**
1615283280Swhu * @brief copy data from SG list which used as bounce to another SG list
1616283280Swhu *
1617283280Swhu * This function is responsible for copy data from one SG list with bounce
1618283280Swhu * buffer to another SG list's segments.
1619283280Swhu *
1620283280Swhu * @param dest_sgl - the destination SG list's segments
1621283280Swhu * @param dest_sgl_count - the count of destination SG list's segment.
1622283280Swhu * @param src_sgl - the source SG list.
1623283280Swhu * @param seg_bits - indicate which segment used bounce buffer of src SG-list.
1624283280Swhu *
1625283280Swhu */
1626283280Swhuvoid
1627283280Swhustorvsc_copy_from_bounce_buf_to_sgl(bus_dma_segment_t *dest_sgl,
1628283280Swhu				    unsigned int dest_sgl_count,
1629283280Swhu				    struct sglist* src_sgl,
1630283280Swhu				    uint64_t seg_bits)
1631283280Swhu{
1632283280Swhu	int sgl_idx = 0;
1633283280Swhu
1634283280Swhu	for (sgl_idx = 0; sgl_idx < dest_sgl_count; sgl_idx++) {
1635283280Swhu		if (seg_bits & (1 << sgl_idx)) {
1636283280Swhu			memcpy((void*)(dest_sgl[sgl_idx].ds_addr),
1637283280Swhu			    (void*)(src_sgl->sg_segs[sgl_idx].ss_paddr),
1638283280Swhu			    src_sgl->sg_segs[sgl_idx].ss_len);
1639283280Swhu		}
1640283280Swhu	}
1641283280Swhu}
1642283280Swhu
1643283280Swhu/**
1644283280Swhu * @brief check SG list with bounce buffer or not
1645283280Swhu *
1646283280Swhu * This function is responsible for check if need bounce buffer for SG list.
1647283280Swhu *
1648283280Swhu * @param sgl - the SG list's segments
1649283280Swhu * @param sg_count - the count of SG list's segment.
1650283280Swhu * @param bits - segmengs number that need bounce buffer
1651283280Swhu *
1652283280Swhu * return -1 if SG list needless bounce buffer
1653283280Swhu */
1654283280Swhustatic int
1655283280Swhustorvsc_check_bounce_buffer_sgl(bus_dma_segment_t *sgl,
1656283280Swhu				unsigned int sg_count,
1657283280Swhu				uint64_t *bits)
1658283280Swhu{
1659283280Swhu	int i = 0;
1660283280Swhu	int offset = 0;
1661283280Swhu	uint64_t phys_addr = 0;
1662283280Swhu	uint64_t tmp_bits = 0;
1663283280Swhu	boolean_t found_hole = FALSE;
1664283280Swhu	boolean_t pre_aligned = TRUE;
1665283280Swhu
1666283280Swhu	if (sg_count < 2){
1667283280Swhu		return -1;
1668283280Swhu	}
1669283280Swhu
1670283280Swhu	*bits = 0;
1671283280Swhu
1672283280Swhu	phys_addr = vtophys(sgl[0].ds_addr);
1673283280Swhu	offset =  phys_addr - trunc_page(phys_addr);
1674283280Swhu
1675283280Swhu	if (offset != 0) {
1676283280Swhu		pre_aligned = FALSE;
1677283280Swhu		tmp_bits |= 1;
1678283280Swhu	}
1679283280Swhu
1680283280Swhu	for (i = 1; i < sg_count; i++) {
1681283280Swhu		phys_addr = vtophys(sgl[i].ds_addr);
1682283280Swhu		offset =  phys_addr - trunc_page(phys_addr);
1683283280Swhu
1684283280Swhu		if (offset == 0) {
1685283280Swhu			if (FALSE == pre_aligned){
1686283280Swhu				/*
1687283280Swhu				 * This segment is aligned, if the previous
1688283280Swhu				 * one is not aligned, find a hole
1689283280Swhu				 */
1690283280Swhu				found_hole = TRUE;
1691283280Swhu			}
1692283280Swhu			pre_aligned = TRUE;
1693283280Swhu		} else {
1694283280Swhu			tmp_bits |= 1 << i;
1695283280Swhu			if (!pre_aligned) {
1696283280Swhu				if (phys_addr != vtophys(sgl[i-1].ds_addr +
1697283280Swhu				    sgl[i-1].ds_len)) {
1698283280Swhu					/*
1699283280Swhu					 * Check whether connect to previous
1700283280Swhu					 * segment,if not, find the hole
1701283280Swhu					 */
1702283280Swhu					found_hole = TRUE;
1703283280Swhu				}
1704283280Swhu			} else {
1705283280Swhu				found_hole = TRUE;
1706283280Swhu			}
1707283280Swhu			pre_aligned = FALSE;
1708283280Swhu		}
1709283280Swhu	}
1710283280Swhu
1711283280Swhu	if (!found_hole) {
1712283280Swhu		return (-1);
1713283280Swhu	} else {
1714283280Swhu		*bits = tmp_bits;
1715283280Swhu		return 0;
1716283280Swhu	}
1717283280Swhu}
1718283280Swhu
1719283280Swhu/**
1720250199Sgrehan * @brief Fill in a request structure based on a CAM control block
1721250199Sgrehan *
1722250199Sgrehan * Fills in a request structure based on the contents of a CAM control
1723250199Sgrehan * block.  The request structure holds the payload information for
1724250199Sgrehan * VSCSI protocol request.
1725250199Sgrehan *
1726250199Sgrehan * @param ccb pointer to a CAM contorl block
1727250199Sgrehan * @param reqp pointer to a request structure
1728250199Sgrehan */
1729283280Swhustatic int
1730250199Sgrehancreate_storvsc_request(union ccb *ccb, struct hv_storvsc_request *reqp)
1731250199Sgrehan{
1732250199Sgrehan	struct ccb_scsiio *csio = &ccb->csio;
1733250199Sgrehan	uint64_t phys_addr;
1734250199Sgrehan	uint32_t bytes_to_copy = 0;
1735250199Sgrehan	uint32_t pfn_num = 0;
1736250199Sgrehan	uint32_t pfn;
1737283280Swhu	uint64_t not_aligned_seg_bits = 0;
1738250199Sgrehan
1739250199Sgrehan	/* refer to struct vmscsi_req for meanings of these two fields */
1740256276Sdim	reqp->vstor_packet.u.vm_srb.port =
1741250199Sgrehan		cam_sim_unit(xpt_path_sim(ccb->ccb_h.path));
1742256276Sdim	reqp->vstor_packet.u.vm_srb.path_id =
1743250199Sgrehan		cam_sim_bus(xpt_path_sim(ccb->ccb_h.path));
1744250199Sgrehan
1745256276Sdim	reqp->vstor_packet.u.vm_srb.target_id = ccb->ccb_h.target_id;
1746256276Sdim	reqp->vstor_packet.u.vm_srb.lun = ccb->ccb_h.target_lun;
1747250199Sgrehan
1748256276Sdim	reqp->vstor_packet.u.vm_srb.cdb_len = csio->cdb_len;
1749250199Sgrehan	if(ccb->ccb_h.flags & CAM_CDB_POINTER) {
1750256276Sdim		memcpy(&reqp->vstor_packet.u.vm_srb.u.cdb, csio->cdb_io.cdb_ptr,
1751250199Sgrehan			csio->cdb_len);
1752250199Sgrehan	} else {
1753256276Sdim		memcpy(&reqp->vstor_packet.u.vm_srb.u.cdb, csio->cdb_io.cdb_bytes,
1754250199Sgrehan			csio->cdb_len);
1755250199Sgrehan	}
1756250199Sgrehan
1757250199Sgrehan	switch (ccb->ccb_h.flags & CAM_DIR_MASK) {
1758283280Swhu	case CAM_DIR_OUT:
1759283280Swhu		reqp->vstor_packet.u.vm_srb.data_in = WRITE_TYPE;
1760283280Swhu		break;
1761283280Swhu	case CAM_DIR_IN:
1762283280Swhu		reqp->vstor_packet.u.vm_srb.data_in = READ_TYPE;
1763283280Swhu		break;
1764283280Swhu	case CAM_DIR_NONE:
1765283280Swhu		reqp->vstor_packet.u.vm_srb.data_in = UNKNOWN_TYPE;
1766283280Swhu		break;
1767283280Swhu	default:
1768283280Swhu		reqp->vstor_packet.u.vm_srb.data_in = UNKNOWN_TYPE;
1769283280Swhu		break;
1770250199Sgrehan	}
1771250199Sgrehan
1772250199Sgrehan	reqp->sense_data     = &csio->sense_data;
1773250199Sgrehan	reqp->sense_info_len = csio->sense_len;
1774250199Sgrehan
1775250199Sgrehan	reqp->ccb = ccb;
1776283280Swhu
1777283280Swhu	if (0 == csio->dxfer_len) {
1778283280Swhu		return (0);
1779283280Swhu	}
1780283280Swhu
1781283280Swhu	reqp->data_buf.length = csio->dxfer_len;
1782283280Swhu
1783283280Swhu	switch (ccb->ccb_h.flags & CAM_DATA_MASK) {
1784283280Swhu	case CAM_DATA_VADDR:
1785283280Swhu	{
1786250199Sgrehan		bytes_to_copy = csio->dxfer_len;
1787250199Sgrehan		phys_addr = vtophys(csio->data_ptr);
1788283280Swhu		reqp->data_buf.offset = phys_addr & PAGE_MASK;
1789283280Swhu
1790283280Swhu		while (bytes_to_copy != 0) {
1791283280Swhu			int bytes, page_offset;
1792283280Swhu			phys_addr =
1793283280Swhu			    vtophys(&csio->data_ptr[reqp->data_buf.length -
1794283280Swhu			    bytes_to_copy]);
1795283280Swhu			pfn = phys_addr >> PAGE_SHIFT;
1796283280Swhu			reqp->data_buf.pfn_array[pfn_num] = pfn;
1797283280Swhu			page_offset = phys_addr & PAGE_MASK;
1798283280Swhu
1799283280Swhu			bytes = min(PAGE_SIZE - page_offset, bytes_to_copy);
1800283280Swhu
1801283280Swhu			bytes_to_copy -= bytes;
1802283280Swhu			pfn_num++;
1803283280Swhu		}
1804283280Swhu		break;
1805250199Sgrehan	}
1806250199Sgrehan
1807283280Swhu	case CAM_DATA_SG:
1808283280Swhu	{
1809283280Swhu		int i = 0;
1810283280Swhu		int offset = 0;
1811283280Swhu		int ret;
1812250199Sgrehan
1813283280Swhu		bus_dma_segment_t *storvsc_sglist =
1814283280Swhu		    (bus_dma_segment_t *)ccb->csio.data_ptr;
1815283280Swhu		u_int16_t storvsc_sg_count = ccb->csio.sglist_cnt;
1816250199Sgrehan
1817283280Swhu		printf("Storvsc: get SG I/O operation, %d\n",
1818283280Swhu		    reqp->vstor_packet.u.vm_srb.data_in);
1819283280Swhu
1820283280Swhu		if (storvsc_sg_count > HV_MAX_MULTIPAGE_BUFFER_COUNT){
1821283280Swhu			printf("Storvsc: %d segments is too much, "
1822283280Swhu			    "only support %d segments\n",
1823283280Swhu			    storvsc_sg_count, HV_MAX_MULTIPAGE_BUFFER_COUNT);
1824283280Swhu			return (EINVAL);
1825283280Swhu		}
1826283280Swhu
1827283280Swhu		/*
1828283280Swhu		 * We create our own bounce buffer function currently. Idealy
1829283280Swhu		 * we should use BUS_DMA(9) framework. But with current BUS_DMA
1830283280Swhu		 * code there is no callback API to check the page alignment of
1831283280Swhu		 * middle segments before busdma can decide if a bounce buffer
1832283280Swhu		 * is needed for particular segment. There is callback,
1833283280Swhu		 * "bus_dma_filter_t *filter", but the parrameters are not
1834283280Swhu		 * sufficient for storvsc driver.
1835283280Swhu		 * TODO:
1836283280Swhu		 *	Add page alignment check in BUS_DMA(9) callback. Once
1837283280Swhu		 *	this is complete, switch the following code to use
1838283280Swhu		 *	BUS_DMA(9) for storvsc bounce buffer support.
1839283280Swhu		 */
1840283280Swhu		/* check if we need to create bounce buffer */
1841283280Swhu		ret = storvsc_check_bounce_buffer_sgl(storvsc_sglist,
1842283280Swhu		    storvsc_sg_count, &not_aligned_seg_bits);
1843283280Swhu		if (ret != -1) {
1844283280Swhu			reqp->bounce_sgl =
1845283280Swhu			    storvsc_create_bounce_buffer(storvsc_sg_count,
1846283280Swhu			    reqp->vstor_packet.u.vm_srb.data_in);
1847283280Swhu			if (NULL == reqp->bounce_sgl) {
1848283280Swhu				printf("Storvsc_error: "
1849283280Swhu				    "create bounce buffer failed.\n");
1850283280Swhu				return (ENOMEM);
1851283280Swhu			}
1852283280Swhu
1853283280Swhu			reqp->bounce_sgl_count = storvsc_sg_count;
1854283280Swhu			reqp->not_aligned_seg_bits = not_aligned_seg_bits;
1855283280Swhu
1856283280Swhu			/*
1857283280Swhu			 * if it is write, we need copy the original data
1858283280Swhu			 *to bounce buffer
1859283280Swhu			 */
1860283280Swhu			if (WRITE_TYPE == reqp->vstor_packet.u.vm_srb.data_in) {
1861283280Swhu				storvsc_copy_sgl_to_bounce_buf(
1862283280Swhu				    reqp->bounce_sgl,
1863283280Swhu				    storvsc_sglist,
1864283280Swhu				    storvsc_sg_count,
1865283280Swhu				    reqp->not_aligned_seg_bits);
1866283280Swhu			}
1867283280Swhu
1868283280Swhu			/* transfer virtual address to physical frame number */
1869283280Swhu			if (reqp->not_aligned_seg_bits & 0x1){
1870283280Swhu 				phys_addr =
1871283280Swhu				    vtophys(reqp->bounce_sgl->sg_segs[0].ss_paddr);
1872283280Swhu			}else{
1873283280Swhu 				phys_addr =
1874283280Swhu					vtophys(storvsc_sglist[0].ds_addr);
1875283280Swhu			}
1876283280Swhu			reqp->data_buf.offset = phys_addr & PAGE_MASK;
1877283280Swhu
1878283280Swhu			pfn = phys_addr >> PAGE_SHIFT;
1879283280Swhu			reqp->data_buf.pfn_array[0] = pfn;
1880283280Swhu
1881283280Swhu			for (i = 1; i < storvsc_sg_count; i++) {
1882283280Swhu				if (reqp->not_aligned_seg_bits & (1 << i)) {
1883283280Swhu					phys_addr =
1884283280Swhu					    vtophys(reqp->bounce_sgl->sg_segs[i].ss_paddr);
1885283280Swhu				} else {
1886283280Swhu					phys_addr =
1887283280Swhu					    vtophys(storvsc_sglist[i].ds_addr);
1888283280Swhu				}
1889283280Swhu
1890283280Swhu				pfn = phys_addr >> PAGE_SHIFT;
1891283280Swhu				reqp->data_buf.pfn_array[i] = pfn;
1892283280Swhu			}
1893283280Swhu		} else {
1894283280Swhu			phys_addr = vtophys(storvsc_sglist[0].ds_addr);
1895283280Swhu
1896283280Swhu			reqp->data_buf.offset = phys_addr & PAGE_MASK;
1897283280Swhu
1898283280Swhu			for (i = 0; i < storvsc_sg_count; i++) {
1899283280Swhu				phys_addr = vtophys(storvsc_sglist[i].ds_addr);
1900283280Swhu				pfn = phys_addr >> PAGE_SHIFT;
1901283280Swhu				reqp->data_buf.pfn_array[i] = pfn;
1902283280Swhu			}
1903283280Swhu
1904283280Swhu			/* check the last segment cross boundary or not */
1905283280Swhu			offset = phys_addr & PAGE_MASK;
1906283280Swhu			if (offset) {
1907283280Swhu				phys_addr =
1908283280Swhu				    vtophys(storvsc_sglist[i-1].ds_addr +
1909283280Swhu				    PAGE_SIZE - offset);
1910283280Swhu				pfn = phys_addr >> PAGE_SHIFT;
1911283280Swhu				reqp->data_buf.pfn_array[i] = pfn;
1912283280Swhu			}
1913283280Swhu
1914283280Swhu			reqp->bounce_sgl_count = 0;
1915283280Swhu		}
1916283280Swhu		break;
1917250199Sgrehan	}
1918283280Swhu	default:
1919283280Swhu		printf("Unknow flags: %d\n", ccb->ccb_h.flags);
1920283280Swhu		return(EINVAL);
1921283280Swhu	}
1922283280Swhu
1923283280Swhu	return(0);
1924250199Sgrehan}
1925250199Sgrehan
1926250199Sgrehan/**
1927250199Sgrehan * @brief completion function before returning to CAM
1928250199Sgrehan *
1929250199Sgrehan * I/O process has been completed and the result needs
1930250199Sgrehan * to be passed to the CAM layer.
1931250199Sgrehan * Free resources related to this request.
1932250199Sgrehan *
1933250199Sgrehan * @param reqp pointer to a request structure
1934250199Sgrehan */
1935250199Sgrehanstatic void
1936250199Sgrehanstorvsc_io_done(struct hv_storvsc_request *reqp)
1937250199Sgrehan{
1938250199Sgrehan	union ccb *ccb = reqp->ccb;
1939250199Sgrehan	struct ccb_scsiio *csio = &ccb->csio;
1940250199Sgrehan	struct storvsc_softc *sc = reqp->softc;
1941256276Sdim	struct vmscsi_req *vm_srb = &reqp->vstor_packet.u.vm_srb;
1942283280Swhu	bus_dma_segment_t *ori_sglist = NULL;
1943283280Swhu	int ori_sg_count = 0;
1944283280Swhu
1945283280Swhu	/* destroy bounce buffer if it is used */
1946283280Swhu	if (reqp->bounce_sgl_count) {
1947283280Swhu		ori_sglist = (bus_dma_segment_t *)ccb->csio.data_ptr;
1948283280Swhu		ori_sg_count = ccb->csio.sglist_cnt;
1949283280Swhu
1950283280Swhu		/*
1951283280Swhu		 * If it is READ operation, we should copy back the data
1952283280Swhu		 * to original SG list.
1953283280Swhu		 */
1954283280Swhu		if (READ_TYPE == reqp->vstor_packet.u.vm_srb.data_in) {
1955283280Swhu			storvsc_copy_from_bounce_buf_to_sgl(ori_sglist,
1956283280Swhu			    ori_sg_count,
1957283280Swhu			    reqp->bounce_sgl,
1958283280Swhu			    reqp->not_aligned_seg_bits);
1959283280Swhu		}
1960283280Swhu
1961283280Swhu		storvsc_destroy_bounce_buffer(reqp->bounce_sgl);
1962283280Swhu		reqp->bounce_sgl_count = 0;
1963283280Swhu	}
1964283280Swhu
1965250199Sgrehan	if (reqp->retries > 0) {
1966250199Sgrehan		mtx_lock(&sc->hs_lock);
1967250199Sgrehan#if HVS_TIMEOUT_TEST
1968250199Sgrehan		xpt_print(ccb->ccb_h.path,
1969250199Sgrehan			"%u: IO returned after timeout, "
1970250199Sgrehan			"waking up timer handler if any.\n", ticks);
1971250199Sgrehan		mtx_lock(&reqp->event.mtx);
1972250199Sgrehan		cv_signal(&reqp->event.cv);
1973250199Sgrehan		mtx_unlock(&reqp->event.mtx);
1974250199Sgrehan#endif
1975250199Sgrehan		reqp->retries = 0;
1976250199Sgrehan		xpt_print(ccb->ccb_h.path,
1977250199Sgrehan			"%u: IO returned after timeout, "
1978250199Sgrehan			"stopping timer if any.\n", ticks);
1979250199Sgrehan		mtx_unlock(&sc->hs_lock);
1980250199Sgrehan	}
1981250199Sgrehan
1982283280Swhu	/*
1983250199Sgrehan	 * callout_drain() will wait for the timer handler to finish
1984250199Sgrehan	 * if it is running. So we don't need any lock to synchronize
1985250199Sgrehan	 * between this routine and the timer handler.
1986250199Sgrehan	 * Note that we need to make sure reqp is not freed when timer
1987250199Sgrehan	 * handler is using or will use it.
1988250199Sgrehan	 */
1989250199Sgrehan	if (ccb->ccb_h.timeout != CAM_TIME_INFINITY) {
1990250199Sgrehan		callout_drain(&reqp->callout);
1991250199Sgrehan	}
1992250199Sgrehan
1993250199Sgrehan	ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
1994250199Sgrehan	ccb->ccb_h.status &= ~CAM_STATUS_MASK;
1995250199Sgrehan	if (vm_srb->scsi_status == SCSI_STATUS_OK) {
1996250199Sgrehan		ccb->ccb_h.status |= CAM_REQ_CMP;
1997250199Sgrehan	 } else {
1998250199Sgrehan		mtx_lock(&sc->hs_lock);
1999250199Sgrehan		xpt_print(ccb->ccb_h.path,
2000250199Sgrehan			"srovsc scsi_status = %d\n",
2001250199Sgrehan			vm_srb->scsi_status);
2002250199Sgrehan		mtx_unlock(&sc->hs_lock);
2003250199Sgrehan		ccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR;
2004250199Sgrehan	}
2005250199Sgrehan
2006250199Sgrehan	ccb->csio.scsi_status = (vm_srb->scsi_status & 0xFF);
2007250199Sgrehan	ccb->csio.resid = ccb->csio.dxfer_len - vm_srb->transfer_len;
2008250199Sgrehan
2009250199Sgrehan	if (reqp->sense_info_len != 0) {
2010250199Sgrehan		csio->sense_resid = csio->sense_len - reqp->sense_info_len;
2011250199Sgrehan		ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
2012250199Sgrehan	}
2013250199Sgrehan
2014250199Sgrehan	mtx_lock(&sc->hs_lock);
2015250199Sgrehan	if (reqp->softc->hs_frozen == 1) {
2016250199Sgrehan		xpt_print(ccb->ccb_h.path,
2017250199Sgrehan			"%u: storvsc unfreezing softc 0x%p.\n",
2018250199Sgrehan			ticks, reqp->softc);
2019250199Sgrehan		ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
2020250199Sgrehan		reqp->softc->hs_frozen = 0;
2021250199Sgrehan	}
2022250199Sgrehan	storvsc_free_request(sc, reqp);
2023250199Sgrehan	xpt_done(ccb);
2024250199Sgrehan	mtx_unlock(&sc->hs_lock);
2025250199Sgrehan}
2026250199Sgrehan
2027250199Sgrehan/**
2028250199Sgrehan * @brief Free a request structure
2029250199Sgrehan *
2030250199Sgrehan * Free a request structure by returning it to the free list
2031250199Sgrehan *
2032250199Sgrehan * @param sc pointer to a softc
2033250199Sgrehan * @param reqp pointer to a request structure
2034250199Sgrehan */
2035250199Sgrehanstatic void
2036250199Sgrehanstorvsc_free_request(struct storvsc_softc *sc, struct hv_storvsc_request *reqp)
2037250199Sgrehan{
2038250199Sgrehan
2039250199Sgrehan	LIST_INSERT_HEAD(&sc->hs_free_list, reqp, link);
2040250199Sgrehan}
2041250199Sgrehan
2042250199Sgrehan/**
2043250199Sgrehan * @brief Determine type of storage device from GUID
2044250199Sgrehan *
2045250199Sgrehan * Using the type GUID, determine if this is a StorVSC (paravirtual
2046250199Sgrehan * SCSI or BlkVSC (paravirtual IDE) device.
2047250199Sgrehan *
2048250199Sgrehan * @param dev a device
2049250199Sgrehan * returns an enum
2050250199Sgrehan */
2051250199Sgrehanstatic enum hv_storage_type
2052250199Sgrehanstorvsc_get_storage_type(device_t dev)
2053250199Sgrehan{
2054250199Sgrehan	const char *p = vmbus_get_type(dev);
2055250199Sgrehan
2056250199Sgrehan	if (!memcmp(p, &gBlkVscDeviceType, sizeof(hv_guid))) {
2057250199Sgrehan		return DRIVER_BLKVSC;
2058250199Sgrehan	} else if (!memcmp(p, &gStorVscDeviceType, sizeof(hv_guid))) {
2059250199Sgrehan		return DRIVER_STORVSC;
2060250199Sgrehan	}
2061250199Sgrehan	return (DRIVER_UNKNOWN);
2062250199Sgrehan}
2063250199Sgrehan
2064