xref: /freebsd/sys/dev/virtio/scsi/virtio_scsi.c (revision e453e498cbb88570a3ff7b3679de65c88707da95)
12f001371SPeter Grehan /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
3718cf2ccSPedro F. Giffuni  *
4abd6790cSBryan Venteicher  * Copyright (c) 2012, Bryan Venteicher <bryanv@FreeBSD.org>
52f001371SPeter Grehan  * All rights reserved.
62f001371SPeter Grehan  *
72f001371SPeter Grehan  * Redistribution and use in source and binary forms, with or without
82f001371SPeter Grehan  * modification, are permitted provided that the following conditions
92f001371SPeter Grehan  * are met:
102f001371SPeter Grehan  * 1. Redistributions of source code must retain the above copyright
112f001371SPeter Grehan  *    notice unmodified, this list of conditions, and the following
122f001371SPeter Grehan  *    disclaimer.
132f001371SPeter Grehan  * 2. Redistributions in binary form must reproduce the above copyright
142f001371SPeter Grehan  *    notice, this list of conditions and the following disclaimer in the
152f001371SPeter Grehan  *    documentation and/or other materials provided with the distribution.
162f001371SPeter Grehan  *
172f001371SPeter Grehan  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
182f001371SPeter Grehan  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
192f001371SPeter Grehan  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
202f001371SPeter Grehan  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
212f001371SPeter Grehan  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
222f001371SPeter Grehan  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
232f001371SPeter Grehan  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
242f001371SPeter Grehan  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
252f001371SPeter Grehan  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
262f001371SPeter Grehan  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
272f001371SPeter Grehan  */
282f001371SPeter Grehan 
292f001371SPeter Grehan /* Driver for VirtIO SCSI devices. */
302f001371SPeter Grehan 
312f001371SPeter Grehan #include <sys/param.h>
322f001371SPeter Grehan #include <sys/systm.h>
332f001371SPeter Grehan #include <sys/kernel.h>
342f001371SPeter Grehan #include <sys/kthread.h>
352f001371SPeter Grehan #include <sys/malloc.h>
362f001371SPeter Grehan #include <sys/module.h>
372f001371SPeter Grehan #include <sys/sglist.h>
382f001371SPeter Grehan #include <sys/sysctl.h>
392f001371SPeter Grehan #include <sys/lock.h>
402f001371SPeter Grehan #include <sys/mutex.h>
412f001371SPeter Grehan #include <sys/callout.h>
422f001371SPeter Grehan #include <sys/queue.h>
432f001371SPeter Grehan #include <sys/sbuf.h>
44*e453e498SBrooks Davis #include <sys/stdarg.h>
452f001371SPeter Grehan 
462f001371SPeter Grehan #include <machine/bus.h>
472f001371SPeter Grehan #include <machine/resource.h>
482f001371SPeter Grehan #include <sys/bus.h>
492f001371SPeter Grehan #include <sys/rman.h>
502f001371SPeter Grehan 
512f001371SPeter Grehan #include <cam/cam.h>
522f001371SPeter Grehan #include <cam/cam_ccb.h>
532f001371SPeter Grehan #include <cam/cam_sim.h>
542f001371SPeter Grehan #include <cam/cam_periph.h>
552f001371SPeter Grehan #include <cam/cam_xpt_sim.h>
562f001371SPeter Grehan #include <cam/cam_debug.h>
572f001371SPeter Grehan #include <cam/scsi/scsi_all.h>
582f001371SPeter Grehan #include <cam/scsi/scsi_message.h>
592f001371SPeter Grehan 
602f001371SPeter Grehan #include <dev/virtio/virtio.h>
612f001371SPeter Grehan #include <dev/virtio/virtqueue.h>
622f001371SPeter Grehan #include <dev/virtio/scsi/virtio_scsi.h>
632f001371SPeter Grehan #include <dev/virtio/scsi/virtio_scsivar.h>
642f001371SPeter Grehan 
652f001371SPeter Grehan #include "virtio_if.h"
662f001371SPeter Grehan 
672f001371SPeter Grehan static int	vtscsi_modevent(module_t, int, void *);
682f001371SPeter Grehan 
692f001371SPeter Grehan static int	vtscsi_probe(device_t);
702f001371SPeter Grehan static int	vtscsi_attach(device_t);
712f001371SPeter Grehan static int	vtscsi_detach(device_t);
722f001371SPeter Grehan static int	vtscsi_suspend(device_t);
732f001371SPeter Grehan static int	vtscsi_resume(device_t);
742f001371SPeter Grehan 
75e6cc42f1SBryan Venteicher static int	vtscsi_negotiate_features(struct vtscsi_softc *);
76e6cc42f1SBryan Venteicher static int	vtscsi_setup_features(struct vtscsi_softc *);
778c457c88SBryan Venteicher static void	vtscsi_read_config(struct vtscsi_softc *,
788c457c88SBryan Venteicher 		    struct virtio_scsi_config *);
792f001371SPeter Grehan static int	vtscsi_maximum_segments(struct vtscsi_softc *, int);
802f001371SPeter Grehan static int	vtscsi_alloc_virtqueues(struct vtscsi_softc *);
81df840654SEric van Gyzen static void	vtscsi_check_sizes(struct vtscsi_softc *);
822f001371SPeter Grehan static void	vtscsi_write_device_config(struct vtscsi_softc *);
832f001371SPeter Grehan static int	vtscsi_reinit(struct vtscsi_softc *);
842f001371SPeter Grehan 
852f001371SPeter Grehan static int	vtscsi_alloc_cam(struct vtscsi_softc *);
862f001371SPeter Grehan static int	vtscsi_register_cam(struct vtscsi_softc *);
872f001371SPeter Grehan static void	vtscsi_free_cam(struct vtscsi_softc *);
882f001371SPeter Grehan static void	vtscsi_cam_async(void *, uint32_t, struct cam_path *, void *);
892f001371SPeter Grehan static int	vtscsi_register_async(struct vtscsi_softc *);
902f001371SPeter Grehan static void	vtscsi_deregister_async(struct vtscsi_softc *);
912f001371SPeter Grehan static void	vtscsi_cam_action(struct cam_sim *, union ccb *);
922f001371SPeter Grehan static void	vtscsi_cam_poll(struct cam_sim *);
932f001371SPeter Grehan 
942f001371SPeter Grehan static void	vtscsi_cam_scsi_io(struct vtscsi_softc *, struct cam_sim *,
952f001371SPeter Grehan 		    union ccb *);
962f001371SPeter Grehan static void	vtscsi_cam_get_tran_settings(struct vtscsi_softc *,
972f001371SPeter Grehan 		    union ccb *);
982f001371SPeter Grehan static void	vtscsi_cam_reset_bus(struct vtscsi_softc *, union ccb *);
992f001371SPeter Grehan static void	vtscsi_cam_reset_dev(struct vtscsi_softc *, union ccb *);
1002f001371SPeter Grehan static void	vtscsi_cam_abort(struct vtscsi_softc *, union ccb *);
1012f001371SPeter Grehan static void	vtscsi_cam_path_inquiry(struct vtscsi_softc *,
1022f001371SPeter Grehan 		    struct cam_sim *, union ccb *);
1032f001371SPeter Grehan 
1042f001371SPeter Grehan static int	vtscsi_sg_append_scsi_buf(struct vtscsi_softc *,
1052f001371SPeter Grehan 		    struct sglist *, struct ccb_scsiio *);
1062f001371SPeter Grehan static int	vtscsi_fill_scsi_cmd_sglist(struct vtscsi_softc *,
1072f001371SPeter Grehan 		    struct vtscsi_request *, int *, int *);
1082f001371SPeter Grehan static int	vtscsi_execute_scsi_cmd(struct vtscsi_softc *,
1092f001371SPeter Grehan 		    struct vtscsi_request *);
1102f001371SPeter Grehan static int	vtscsi_start_scsi_cmd(struct vtscsi_softc *, union ccb *);
1112f001371SPeter Grehan static void	vtscsi_complete_abort_timedout_scsi_cmd(struct vtscsi_softc *,
1122f001371SPeter Grehan 		    struct vtscsi_request *);
1132f001371SPeter Grehan static int	vtscsi_abort_timedout_scsi_cmd(struct vtscsi_softc *,
1142f001371SPeter Grehan 		    struct vtscsi_request *);
1152f001371SPeter Grehan static void	vtscsi_timedout_scsi_cmd(void *);
1162f001371SPeter Grehan static cam_status vtscsi_scsi_cmd_cam_status(struct virtio_scsi_cmd_resp *);
1172f001371SPeter Grehan static cam_status vtscsi_complete_scsi_cmd_response(struct vtscsi_softc *,
1182f001371SPeter Grehan 		    struct ccb_scsiio *, struct virtio_scsi_cmd_resp *);
1192f001371SPeter Grehan static void	vtscsi_complete_scsi_cmd(struct vtscsi_softc *,
1202f001371SPeter Grehan 		    struct vtscsi_request *);
1212f001371SPeter Grehan 
1222f001371SPeter Grehan static void	vtscsi_poll_ctrl_req(struct vtscsi_softc *,
1232f001371SPeter Grehan 		    struct vtscsi_request *);
1242f001371SPeter Grehan static int	vtscsi_execute_ctrl_req(struct vtscsi_softc *,
1252f001371SPeter Grehan 		    struct vtscsi_request *, struct sglist *, int, int, int);
1262f001371SPeter Grehan static void	vtscsi_complete_abort_task_cmd(struct vtscsi_softc *c,
1272f001371SPeter Grehan 		    struct vtscsi_request *);
1282f001371SPeter Grehan static int	vtscsi_execute_abort_task_cmd(struct vtscsi_softc *,
1292f001371SPeter Grehan 		    struct vtscsi_request *);
1302f001371SPeter Grehan static int	vtscsi_execute_reset_dev_cmd(struct vtscsi_softc *,
1312f001371SPeter Grehan 		    struct vtscsi_request *);
1322f001371SPeter Grehan 
1332aaf349cSBryan Venteicher static void	vtscsi_get_request_lun(uint8_t [], target_id_t *, lun_id_t *);
1342f001371SPeter Grehan static void	vtscsi_set_request_lun(struct ccb_hdr *, uint8_t []);
13515be4953SBryan Venteicher static void	vtscsi_init_scsi_cmd_req(struct vtscsi_softc *,
13615be4953SBryan Venteicher 		    struct ccb_scsiio *, struct virtio_scsi_cmd_req *);
13715be4953SBryan Venteicher static void	vtscsi_init_ctrl_tmf_req(struct vtscsi_softc *, struct ccb_hdr *,
13815be4953SBryan Venteicher 		    uint32_t, uintptr_t, struct virtio_scsi_ctrl_tmf_req *);
1392f001371SPeter Grehan 
1402f001371SPeter Grehan static void	vtscsi_freeze_simq(struct vtscsi_softc *, int);
1412f001371SPeter Grehan static int	vtscsi_thaw_simq(struct vtscsi_softc *, int);
1422f001371SPeter Grehan 
1432f001371SPeter Grehan static void	vtscsi_announce(struct vtscsi_softc *, uint32_t, target_id_t,
1442f001371SPeter Grehan 		    lun_id_t);
1452f001371SPeter Grehan static void	vtscsi_execute_rescan(struct vtscsi_softc *, target_id_t,
1462f001371SPeter Grehan 		    lun_id_t);
1472f001371SPeter Grehan static void	vtscsi_execute_rescan_bus(struct vtscsi_softc *);
1482f001371SPeter Grehan 
1492f001371SPeter Grehan static void	vtscsi_handle_event(struct vtscsi_softc *,
1502f001371SPeter Grehan 		    struct virtio_scsi_event *);
1512f001371SPeter Grehan static int	vtscsi_enqueue_event_buf(struct vtscsi_softc *,
1522f001371SPeter Grehan 		    struct virtio_scsi_event *);
1532f001371SPeter Grehan static int	vtscsi_init_event_vq(struct vtscsi_softc *);
1542f001371SPeter Grehan static void	vtscsi_reinit_event_vq(struct vtscsi_softc *);
1552f001371SPeter Grehan static void	vtscsi_drain_event_vq(struct vtscsi_softc *);
1562f001371SPeter Grehan 
1572f001371SPeter Grehan static void	vtscsi_complete_vqs_locked(struct vtscsi_softc *);
1582f001371SPeter Grehan static void	vtscsi_complete_vqs(struct vtscsi_softc *);
1592f001371SPeter Grehan static void	vtscsi_drain_vqs(struct vtscsi_softc *);
1602f001371SPeter Grehan static void	vtscsi_cancel_request(struct vtscsi_softc *,
1612f001371SPeter Grehan 		    struct vtscsi_request *);
1622f001371SPeter Grehan static void	vtscsi_drain_vq(struct vtscsi_softc *, struct virtqueue *);
1632f001371SPeter Grehan static void	vtscsi_stop(struct vtscsi_softc *);
1642f001371SPeter Grehan static int	vtscsi_reset_bus(struct vtscsi_softc *);
1652f001371SPeter Grehan 
1662f001371SPeter Grehan static void	vtscsi_init_request(struct vtscsi_softc *,
1672f001371SPeter Grehan 		    struct vtscsi_request *);
1682f001371SPeter Grehan static int	vtscsi_alloc_requests(struct vtscsi_softc *);
1692f001371SPeter Grehan static void	vtscsi_free_requests(struct vtscsi_softc *);
1702f001371SPeter Grehan static void	vtscsi_enqueue_request(struct vtscsi_softc *,
1712f001371SPeter Grehan 		    struct vtscsi_request *);
1722f001371SPeter Grehan static struct vtscsi_request * vtscsi_dequeue_request(struct vtscsi_softc *);
1732f001371SPeter Grehan 
1742f001371SPeter Grehan static void	vtscsi_complete_request(struct vtscsi_request *);
1752f001371SPeter Grehan static void	vtscsi_complete_vq(struct vtscsi_softc *, struct virtqueue *);
1762f001371SPeter Grehan 
1776632efe4SBryan Venteicher static void	vtscsi_control_vq_intr(void *);
1786632efe4SBryan Venteicher static void	vtscsi_event_vq_intr(void *);
1796632efe4SBryan Venteicher static void	vtscsi_request_vq_intr(void *);
1802f001371SPeter Grehan static void	vtscsi_disable_vqs_intr(struct vtscsi_softc *);
1812f001371SPeter Grehan static void	vtscsi_enable_vqs_intr(struct vtscsi_softc *);
1822f001371SPeter Grehan 
1832f001371SPeter Grehan static void	vtscsi_get_tunables(struct vtscsi_softc *);
184e6cc42f1SBryan Venteicher static void	vtscsi_setup_sysctl(struct vtscsi_softc *);
1852f001371SPeter Grehan 
1862f001371SPeter Grehan static void	vtscsi_printf_req(struct vtscsi_request *, const char *,
1872f001371SPeter Grehan 		    const char *, ...);
1882f001371SPeter Grehan 
18915be4953SBryan Venteicher #define vtscsi_modern(_sc) (((_sc)->vtscsi_features & VIRTIO_F_VERSION_1) != 0)
19015be4953SBryan Venteicher #define vtscsi_htog16(_sc, _val)	virtio_htog16(vtscsi_modern(_sc), _val)
19115be4953SBryan Venteicher #define vtscsi_htog32(_sc, _val)	virtio_htog32(vtscsi_modern(_sc), _val)
19215be4953SBryan Venteicher #define vtscsi_htog64(_sc, _val)	virtio_htog64(vtscsi_modern(_sc), _val)
19315be4953SBryan Venteicher #define vtscsi_gtoh16(_sc, _val)	virtio_gtoh16(vtscsi_modern(_sc), _val)
19415be4953SBryan Venteicher #define vtscsi_gtoh32(_sc, _val)	virtio_gtoh32(vtscsi_modern(_sc), _val)
19515be4953SBryan Venteicher #define vtscsi_gtoh64(_sc, _val)	virtio_gtoh64(vtscsi_modern(_sc), _val)
19615be4953SBryan Venteicher 
1972f001371SPeter Grehan /* Global tunables. */
1982f001371SPeter Grehan /*
1992f001371SPeter Grehan  * The current QEMU VirtIO SCSI implementation does not cancel in-flight
2002f001371SPeter Grehan  * IO during virtio_stop(). So in-flight requests still complete after the
2012f001371SPeter Grehan  * device reset. We would have to wait for all the in-flight IO to complete,
2022f001371SPeter Grehan  * which defeats the typical purpose of a bus reset. We could simulate the
2032f001371SPeter Grehan  * bus reset with either I_T_NEXUS_RESET of all the targets, or with
2042f001371SPeter Grehan  * LOGICAL_UNIT_RESET of all the LUNs (assuming there is space in the
2052f001371SPeter Grehan  * control virtqueue). But this isn't very useful if things really go off
2062f001371SPeter Grehan  * the rails, so default to disabled for now.
2072f001371SPeter Grehan  */
2082f001371SPeter Grehan static int vtscsi_bus_reset_disable = 1;
2092f001371SPeter Grehan TUNABLE_INT("hw.vtscsi.bus_reset_disable", &vtscsi_bus_reset_disable);
2102f001371SPeter Grehan 
2112f001371SPeter Grehan static struct virtio_feature_desc vtscsi_feature_desc[] = {
2122f001371SPeter Grehan 	{ VIRTIO_SCSI_F_INOUT,		"InOut"		},
2132f001371SPeter Grehan 	{ VIRTIO_SCSI_F_HOTPLUG,	"Hotplug"	},
21415be4953SBryan Venteicher 	{ VIRTIO_SCSI_F_CHANGE,		"ChangeEvent"	},
21515be4953SBryan Venteicher 	{ VIRTIO_SCSI_F_T10_PI, 	"T10PI"		},
21615be4953SBryan Venteicher 
2172f001371SPeter Grehan 	{ 0, NULL }
2182f001371SPeter Grehan };
2192f001371SPeter Grehan 
2202f001371SPeter Grehan static device_method_t vtscsi_methods[] = {
2212f001371SPeter Grehan 	/* Device methods. */
2222f001371SPeter Grehan 	DEVMETHOD(device_probe,		vtscsi_probe),
2232f001371SPeter Grehan 	DEVMETHOD(device_attach,	vtscsi_attach),
2242f001371SPeter Grehan 	DEVMETHOD(device_detach,	vtscsi_detach),
2252f001371SPeter Grehan 	DEVMETHOD(device_suspend,	vtscsi_suspend),
2262f001371SPeter Grehan 	DEVMETHOD(device_resume,	vtscsi_resume),
2272f001371SPeter Grehan 
2282f001371SPeter Grehan 	DEVMETHOD_END
2292f001371SPeter Grehan };
2302f001371SPeter Grehan 
2312f001371SPeter Grehan static driver_t vtscsi_driver = {
2322f001371SPeter Grehan 	"vtscsi",
2332f001371SPeter Grehan 	vtscsi_methods,
2342f001371SPeter Grehan 	sizeof(struct vtscsi_softc)
2352f001371SPeter Grehan };
2362f001371SPeter Grehan 
2375c4c96d3SJohn Baldwin VIRTIO_DRIVER_MODULE(virtio_scsi, vtscsi_driver, vtscsi_modevent, NULL);
2382f001371SPeter Grehan MODULE_VERSION(virtio_scsi, 1);
2392f001371SPeter Grehan MODULE_DEPEND(virtio_scsi, virtio, 1, 1, 1);
2402f001371SPeter Grehan MODULE_DEPEND(virtio_scsi, cam, 1, 1, 1);
2412f001371SPeter Grehan 
242633218eeSJessica Clarke VIRTIO_SIMPLE_PNPINFO(virtio_scsi, VIRTIO_ID_SCSI, "VirtIO SCSI Adapter");
2430f6040f0SConrad Meyer 
2442f001371SPeter Grehan static int
vtscsi_modevent(module_t mod,int type,void * unused)2452f001371SPeter Grehan vtscsi_modevent(module_t mod, int type, void *unused)
2462f001371SPeter Grehan {
2472f001371SPeter Grehan 	int error;
2482f001371SPeter Grehan 
2492f001371SPeter Grehan 	switch (type) {
2502f001371SPeter Grehan 	case MOD_LOAD:
2512f001371SPeter Grehan 	case MOD_QUIESCE:
2522f001371SPeter Grehan 	case MOD_UNLOAD:
2532f001371SPeter Grehan 	case MOD_SHUTDOWN:
2542f001371SPeter Grehan 		error = 0;
2552f001371SPeter Grehan 		break;
2562f001371SPeter Grehan 	default:
2572f001371SPeter Grehan 		error = EOPNOTSUPP;
2582f001371SPeter Grehan 		break;
2592f001371SPeter Grehan 	}
2602f001371SPeter Grehan 
2612f001371SPeter Grehan 	return (error);
2622f001371SPeter Grehan }
2632f001371SPeter Grehan 
2642f001371SPeter Grehan static int
vtscsi_probe(device_t dev)2652f001371SPeter Grehan vtscsi_probe(device_t dev)
2662f001371SPeter Grehan {
2670f6040f0SConrad Meyer 	return (VIRTIO_SIMPLE_PROBE(dev, virtio_scsi));
2682f001371SPeter Grehan }
2692f001371SPeter Grehan 
2702f001371SPeter Grehan static int
vtscsi_attach(device_t dev)2712f001371SPeter Grehan vtscsi_attach(device_t dev)
2722f001371SPeter Grehan {
2732f001371SPeter Grehan 	struct vtscsi_softc *sc;
2742f001371SPeter Grehan 	struct virtio_scsi_config scsicfg;
2752f001371SPeter Grehan 	int error;
2762f001371SPeter Grehan 
2772f001371SPeter Grehan 	sc = device_get_softc(dev);
2782f001371SPeter Grehan 	sc->vtscsi_dev = dev;
279e6cc42f1SBryan Venteicher 	virtio_set_feature_desc(dev, vtscsi_feature_desc);
2802f001371SPeter Grehan 
2812f001371SPeter Grehan 	VTSCSI_LOCK_INIT(sc, device_get_nameunit(dev));
2822f001371SPeter Grehan 	TAILQ_INIT(&sc->vtscsi_req_free);
2832f001371SPeter Grehan 
2842f001371SPeter Grehan 	vtscsi_get_tunables(sc);
285e6cc42f1SBryan Venteicher 	vtscsi_setup_sysctl(sc);
2862f001371SPeter Grehan 
287e6cc42f1SBryan Venteicher 	error = vtscsi_setup_features(sc);
288e6cc42f1SBryan Venteicher 	if (error) {
289e6cc42f1SBryan Venteicher 		device_printf(dev, "cannot setup features\n");
290e6cc42f1SBryan Venteicher 		goto fail;
291e6cc42f1SBryan Venteicher 	}
2922f001371SPeter Grehan 
2938c457c88SBryan Venteicher 	vtscsi_read_config(sc, &scsicfg);
2942f001371SPeter Grehan 
2952f001371SPeter Grehan 	sc->vtscsi_max_channel = scsicfg.max_channel;
2962f001371SPeter Grehan 	sc->vtscsi_max_target = scsicfg.max_target;
2972f001371SPeter Grehan 	sc->vtscsi_max_lun = scsicfg.max_lun;
2982f001371SPeter Grehan 	sc->vtscsi_event_buf_size = scsicfg.event_info_size;
2992f001371SPeter Grehan 
3002f001371SPeter Grehan 	vtscsi_write_device_config(sc);
3012f001371SPeter Grehan 
3022f001371SPeter Grehan 	sc->vtscsi_max_nsegs = vtscsi_maximum_segments(sc, scsicfg.seg_max);
3032f001371SPeter Grehan 	sc->vtscsi_sglist = sglist_alloc(sc->vtscsi_max_nsegs, M_NOWAIT);
3042f001371SPeter Grehan 	if (sc->vtscsi_sglist == NULL) {
3052f001371SPeter Grehan 		error = ENOMEM;
3062f001371SPeter Grehan 		device_printf(dev, "cannot allocate sglist\n");
3072f001371SPeter Grehan 		goto fail;
3082f001371SPeter Grehan 	}
3092f001371SPeter Grehan 
3102f001371SPeter Grehan 	error = vtscsi_alloc_virtqueues(sc);
3112f001371SPeter Grehan 	if (error) {
3122f001371SPeter Grehan 		device_printf(dev, "cannot allocate virtqueues\n");
3132f001371SPeter Grehan 		goto fail;
3142f001371SPeter Grehan 	}
3152f001371SPeter Grehan 
316df840654SEric van Gyzen 	vtscsi_check_sizes(sc);
317df840654SEric van Gyzen 
3182f001371SPeter Grehan 	error = vtscsi_init_event_vq(sc);
3192f001371SPeter Grehan 	if (error) {
3202f001371SPeter Grehan 		device_printf(dev, "cannot populate the eventvq\n");
3212f001371SPeter Grehan 		goto fail;
3222f001371SPeter Grehan 	}
3232f001371SPeter Grehan 
3242f001371SPeter Grehan 	error = vtscsi_alloc_requests(sc);
3252f001371SPeter Grehan 	if (error) {
3262f001371SPeter Grehan 		device_printf(dev, "cannot allocate requests\n");
3272f001371SPeter Grehan 		goto fail;
3282f001371SPeter Grehan 	}
3292f001371SPeter Grehan 
3302f001371SPeter Grehan 	error = vtscsi_alloc_cam(sc);
3312f001371SPeter Grehan 	if (error) {
3322f001371SPeter Grehan 		device_printf(dev, "cannot allocate CAM structures\n");
3332f001371SPeter Grehan 		goto fail;
3342f001371SPeter Grehan 	}
3352f001371SPeter Grehan 
3362f001371SPeter Grehan 	error = virtio_setup_intr(dev, INTR_TYPE_CAM);
3372f001371SPeter Grehan 	if (error) {
3382f001371SPeter Grehan 		device_printf(dev, "cannot setup virtqueue interrupts\n");
3392f001371SPeter Grehan 		goto fail;
3402f001371SPeter Grehan 	}
3412f001371SPeter Grehan 
3422f001371SPeter Grehan 	vtscsi_enable_vqs_intr(sc);
3432f001371SPeter Grehan 
3442f001371SPeter Grehan 	/*
3452f001371SPeter Grehan 	 * Register with CAM after interrupts are enabled so we will get
3462f001371SPeter Grehan 	 * notified of the probe responses.
3472f001371SPeter Grehan 	 */
3482f001371SPeter Grehan 	error = vtscsi_register_cam(sc);
3492f001371SPeter Grehan 	if (error) {
3502f001371SPeter Grehan 		device_printf(dev, "cannot register with CAM\n");
3512f001371SPeter Grehan 		goto fail;
3522f001371SPeter Grehan 	}
3532f001371SPeter Grehan 
3542f001371SPeter Grehan fail:
3552f001371SPeter Grehan 	if (error)
3562f001371SPeter Grehan 		vtscsi_detach(dev);
3572f001371SPeter Grehan 
3582f001371SPeter Grehan 	return (error);
3592f001371SPeter Grehan }
3602f001371SPeter Grehan 
3612f001371SPeter Grehan static int
vtscsi_detach(device_t dev)3622f001371SPeter Grehan vtscsi_detach(device_t dev)
3632f001371SPeter Grehan {
3642f001371SPeter Grehan 	struct vtscsi_softc *sc;
3652f001371SPeter Grehan 
3662f001371SPeter Grehan 	sc = device_get_softc(dev);
3672f001371SPeter Grehan 
3682f001371SPeter Grehan 	VTSCSI_LOCK(sc);
3692f001371SPeter Grehan 	sc->vtscsi_flags |= VTSCSI_FLAG_DETACH;
3702f001371SPeter Grehan 	if (device_is_attached(dev))
3712f001371SPeter Grehan 		vtscsi_stop(sc);
3722f001371SPeter Grehan 	VTSCSI_UNLOCK(sc);
3732f001371SPeter Grehan 
3742f001371SPeter Grehan 	vtscsi_complete_vqs(sc);
3752f001371SPeter Grehan 	vtscsi_drain_vqs(sc);
3762f001371SPeter Grehan 
3772f001371SPeter Grehan 	vtscsi_free_cam(sc);
3782f001371SPeter Grehan 	vtscsi_free_requests(sc);
3792f001371SPeter Grehan 
3802f001371SPeter Grehan 	if (sc->vtscsi_sglist != NULL) {
3812f001371SPeter Grehan 		sglist_free(sc->vtscsi_sglist);
3822f001371SPeter Grehan 		sc->vtscsi_sglist = NULL;
3832f001371SPeter Grehan 	}
3842f001371SPeter Grehan 
3852f001371SPeter Grehan 	VTSCSI_LOCK_DESTROY(sc);
3862f001371SPeter Grehan 
3872f001371SPeter Grehan 	return (0);
3882f001371SPeter Grehan }
3892f001371SPeter Grehan 
3902f001371SPeter Grehan static int
vtscsi_suspend(device_t dev)3912f001371SPeter Grehan vtscsi_suspend(device_t dev)
3922f001371SPeter Grehan {
3932f001371SPeter Grehan 
3942f001371SPeter Grehan 	return (0);
3952f001371SPeter Grehan }
3962f001371SPeter Grehan 
3972f001371SPeter Grehan static int
vtscsi_resume(device_t dev)3982f001371SPeter Grehan vtscsi_resume(device_t dev)
3992f001371SPeter Grehan {
4002f001371SPeter Grehan 
4012f001371SPeter Grehan 	return (0);
4022f001371SPeter Grehan }
4032f001371SPeter Grehan 
404e6cc42f1SBryan Venteicher static int
vtscsi_negotiate_features(struct vtscsi_softc * sc)4052f001371SPeter Grehan vtscsi_negotiate_features(struct vtscsi_softc *sc)
4062f001371SPeter Grehan {
4072f001371SPeter Grehan 	device_t dev;
4082f001371SPeter Grehan 	uint64_t features;
4092f001371SPeter Grehan 
4102f001371SPeter Grehan 	dev = sc->vtscsi_dev;
41115be4953SBryan Venteicher 	features = VTSCSI_FEATURES;
41215be4953SBryan Venteicher 
41315be4953SBryan Venteicher 	sc->vtscsi_features = virtio_negotiate_features(dev, features);
414e6cc42f1SBryan Venteicher 	return (virtio_finalize_features(dev));
415e6cc42f1SBryan Venteicher }
416e6cc42f1SBryan Venteicher 
417e6cc42f1SBryan Venteicher static int
vtscsi_setup_features(struct vtscsi_softc * sc)418e6cc42f1SBryan Venteicher vtscsi_setup_features(struct vtscsi_softc *sc)
419e6cc42f1SBryan Venteicher {
420e6cc42f1SBryan Venteicher 	device_t dev;
421e6cc42f1SBryan Venteicher 	int error;
422e6cc42f1SBryan Venteicher 
423e6cc42f1SBryan Venteicher 	dev = sc->vtscsi_dev;
424e6cc42f1SBryan Venteicher 
425e6cc42f1SBryan Venteicher 	error = vtscsi_negotiate_features(sc);
426e6cc42f1SBryan Venteicher 	if (error)
427e6cc42f1SBryan Venteicher 		return (error);
428e6cc42f1SBryan Venteicher 
429e6cc42f1SBryan Venteicher 	if (virtio_with_feature(dev, VIRTIO_RING_F_INDIRECT_DESC))
430e6cc42f1SBryan Venteicher 		sc->vtscsi_flags |= VTSCSI_FLAG_INDIRECT;
431e6cc42f1SBryan Venteicher 	if (virtio_with_feature(dev, VIRTIO_SCSI_F_INOUT))
432e6cc42f1SBryan Venteicher 		sc->vtscsi_flags |= VTSCSI_FLAG_BIDIRECTIONAL;
433e6cc42f1SBryan Venteicher 	if (virtio_with_feature(dev, VIRTIO_SCSI_F_HOTPLUG))
434e6cc42f1SBryan Venteicher 		sc->vtscsi_flags |= VTSCSI_FLAG_HOTPLUG;
435e6cc42f1SBryan Venteicher 
436e6cc42f1SBryan Venteicher 	return (0);
4372f001371SPeter Grehan }
4382f001371SPeter Grehan 
4398c457c88SBryan Venteicher #define VTSCSI_GET_CONFIG(_dev, _field, _cfg)			\
4408c457c88SBryan Venteicher 	virtio_read_device_config(_dev,				\
4418c457c88SBryan Venteicher 	    offsetof(struct virtio_scsi_config, _field),	\
4428c457c88SBryan Venteicher 	    &(_cfg)->_field, sizeof((_cfg)->_field))		\
4438c457c88SBryan Venteicher 
4448c457c88SBryan Venteicher static void
vtscsi_read_config(struct vtscsi_softc * sc,struct virtio_scsi_config * scsicfg)4458c457c88SBryan Venteicher vtscsi_read_config(struct vtscsi_softc *sc,
4468c457c88SBryan Venteicher     struct virtio_scsi_config *scsicfg)
4478c457c88SBryan Venteicher {
4488c457c88SBryan Venteicher 	device_t dev;
4498c457c88SBryan Venteicher 
4508c457c88SBryan Venteicher 	dev = sc->vtscsi_dev;
4518c457c88SBryan Venteicher 
4528c457c88SBryan Venteicher 	bzero(scsicfg, sizeof(struct virtio_scsi_config));
4538c457c88SBryan Venteicher 
4548c457c88SBryan Venteicher 	VTSCSI_GET_CONFIG(dev, num_queues, scsicfg);
4558c457c88SBryan Venteicher 	VTSCSI_GET_CONFIG(dev, seg_max, scsicfg);
4568c457c88SBryan Venteicher 	VTSCSI_GET_CONFIG(dev, max_sectors, scsicfg);
4578c457c88SBryan Venteicher 	VTSCSI_GET_CONFIG(dev, cmd_per_lun, scsicfg);
4588c457c88SBryan Venteicher 	VTSCSI_GET_CONFIG(dev, event_info_size, scsicfg);
4598c457c88SBryan Venteicher 	VTSCSI_GET_CONFIG(dev, sense_size, scsicfg);
4608c457c88SBryan Venteicher 	VTSCSI_GET_CONFIG(dev, cdb_size, scsicfg);
4618c457c88SBryan Venteicher 	VTSCSI_GET_CONFIG(dev, max_channel, scsicfg);
4628c457c88SBryan Venteicher 	VTSCSI_GET_CONFIG(dev, max_target, scsicfg);
4638c457c88SBryan Venteicher 	VTSCSI_GET_CONFIG(dev, max_lun, scsicfg);
4648c457c88SBryan Venteicher }
4658c457c88SBryan Venteicher 
4668c457c88SBryan Venteicher #undef VTSCSI_GET_CONFIG
4678c457c88SBryan Venteicher 
4682f001371SPeter Grehan static int
vtscsi_maximum_segments(struct vtscsi_softc * sc,int seg_max)4692f001371SPeter Grehan vtscsi_maximum_segments(struct vtscsi_softc *sc, int seg_max)
4702f001371SPeter Grehan {
4712f001371SPeter Grehan 	int nsegs;
4722f001371SPeter Grehan 
4732f001371SPeter Grehan 	nsegs = VTSCSI_MIN_SEGMENTS;
4742f001371SPeter Grehan 
4752f001371SPeter Grehan 	if (seg_max > 0) {
476cd853791SKonstantin Belousov 		nsegs += MIN(seg_max, maxphys / PAGE_SIZE + 1);
4772f001371SPeter Grehan 		if (sc->vtscsi_flags & VTSCSI_FLAG_INDIRECT)
4782f001371SPeter Grehan 			nsegs = MIN(nsegs, VIRTIO_MAX_INDIRECT);
4792f001371SPeter Grehan 	} else
4802f001371SPeter Grehan 		nsegs += 1;
4812f001371SPeter Grehan 
4822f001371SPeter Grehan 	return (nsegs);
4832f001371SPeter Grehan }
4842f001371SPeter Grehan 
4852f001371SPeter Grehan static int
vtscsi_alloc_virtqueues(struct vtscsi_softc * sc)4862f001371SPeter Grehan vtscsi_alloc_virtqueues(struct vtscsi_softc *sc)
4872f001371SPeter Grehan {
4882f001371SPeter Grehan 	device_t dev;
4892f001371SPeter Grehan 	struct vq_alloc_info vq_info[3];
4902f001371SPeter Grehan 	int nvqs;
4912f001371SPeter Grehan 
4922f001371SPeter Grehan 	dev = sc->vtscsi_dev;
4932f001371SPeter Grehan 	nvqs = 3;
4942f001371SPeter Grehan 
4952f001371SPeter Grehan 	VQ_ALLOC_INFO_INIT(&vq_info[0], 0, vtscsi_control_vq_intr, sc,
4962f001371SPeter Grehan 	    &sc->vtscsi_control_vq, "%s control", device_get_nameunit(dev));
4972f001371SPeter Grehan 
4982f001371SPeter Grehan 	VQ_ALLOC_INFO_INIT(&vq_info[1], 0, vtscsi_event_vq_intr, sc,
4992f001371SPeter Grehan 	    &sc->vtscsi_event_vq, "%s event", device_get_nameunit(dev));
5002f001371SPeter Grehan 
5012f001371SPeter Grehan 	VQ_ALLOC_INFO_INIT(&vq_info[2], sc->vtscsi_max_nsegs,
5022f001371SPeter Grehan 	    vtscsi_request_vq_intr, sc, &sc->vtscsi_request_vq,
5032f001371SPeter Grehan 	    "%s request", device_get_nameunit(dev));
5042f001371SPeter Grehan 
505180c0240SMina Galić 	return (virtio_alloc_virtqueues(dev, nvqs, vq_info));
5062f001371SPeter Grehan }
5072f001371SPeter Grehan 
5082f001371SPeter Grehan static void
vtscsi_check_sizes(struct vtscsi_softc * sc)509df840654SEric van Gyzen vtscsi_check_sizes(struct vtscsi_softc *sc)
510df840654SEric van Gyzen {
511df840654SEric van Gyzen 	int rqsize;
512df840654SEric van Gyzen 
513df840654SEric van Gyzen 	if ((sc->vtscsi_flags & VTSCSI_FLAG_INDIRECT) == 0) {
514df840654SEric van Gyzen 		/*
515df840654SEric van Gyzen 		 * Ensure the assertions in virtqueue_enqueue(),
516df840654SEric van Gyzen 		 * even if the hypervisor reports a bad seg_max.
517df840654SEric van Gyzen 		 */
518df840654SEric van Gyzen 		rqsize = virtqueue_size(sc->vtscsi_request_vq);
519df840654SEric van Gyzen 		if (sc->vtscsi_max_nsegs > rqsize) {
520df840654SEric van Gyzen 			device_printf(sc->vtscsi_dev,
521df840654SEric van Gyzen 			    "clamping seg_max (%d %d)\n", sc->vtscsi_max_nsegs,
522df840654SEric van Gyzen 			    rqsize);
523df840654SEric van Gyzen 			sc->vtscsi_max_nsegs = rqsize;
524df840654SEric van Gyzen 		}
525df840654SEric van Gyzen 	}
526df840654SEric van Gyzen }
527df840654SEric van Gyzen 
528df840654SEric van Gyzen static void
vtscsi_write_device_config(struct vtscsi_softc * sc)5292f001371SPeter Grehan vtscsi_write_device_config(struct vtscsi_softc *sc)
5302f001371SPeter Grehan {
5312f001371SPeter Grehan 
5322f001371SPeter Grehan 	virtio_write_dev_config_4(sc->vtscsi_dev,
5332f001371SPeter Grehan 	    offsetof(struct virtio_scsi_config, sense_size),
5342f001371SPeter Grehan 	    VIRTIO_SCSI_SENSE_SIZE);
5352f001371SPeter Grehan 
5362f001371SPeter Grehan 	/*
5372f001371SPeter Grehan 	 * This is the size in the virtio_scsi_cmd_req structure. Note
5382f001371SPeter Grehan 	 * this value (32) is larger than the maximum CAM CDB size (16).
5392f001371SPeter Grehan 	 */
5402f001371SPeter Grehan 	virtio_write_dev_config_4(sc->vtscsi_dev,
5412f001371SPeter Grehan 	    offsetof(struct virtio_scsi_config, cdb_size),
5422f001371SPeter Grehan 	    VIRTIO_SCSI_CDB_SIZE);
5432f001371SPeter Grehan }
5442f001371SPeter Grehan 
5452f001371SPeter Grehan static int
vtscsi_reinit(struct vtscsi_softc * sc)5462f001371SPeter Grehan vtscsi_reinit(struct vtscsi_softc *sc)
5472f001371SPeter Grehan {
5482f001371SPeter Grehan 	device_t dev;
5492f001371SPeter Grehan 	int error;
5502f001371SPeter Grehan 
5512f001371SPeter Grehan 	dev = sc->vtscsi_dev;
5522f001371SPeter Grehan 
5532f001371SPeter Grehan 	error = virtio_reinit(dev, sc->vtscsi_features);
5542f001371SPeter Grehan 	if (error == 0) {
5552f001371SPeter Grehan 		vtscsi_write_device_config(sc);
5562f001371SPeter Grehan 		virtio_reinit_complete(dev);
55715be4953SBryan Venteicher 		vtscsi_reinit_event_vq(sc);
5582f001371SPeter Grehan 
5592f001371SPeter Grehan 		vtscsi_enable_vqs_intr(sc);
5602f001371SPeter Grehan 	}
5612f001371SPeter Grehan 
5622f001371SPeter Grehan 	vtscsi_dprintf(sc, VTSCSI_TRACE, "error=%d\n", error);
5632f001371SPeter Grehan 
5642f001371SPeter Grehan 	return (error);
5652f001371SPeter Grehan }
5662f001371SPeter Grehan 
5672f001371SPeter Grehan static int
vtscsi_alloc_cam(struct vtscsi_softc * sc)5682f001371SPeter Grehan vtscsi_alloc_cam(struct vtscsi_softc *sc)
5692f001371SPeter Grehan {
5702f001371SPeter Grehan 	device_t dev;
5712f001371SPeter Grehan 	struct cam_devq *devq;
5722f001371SPeter Grehan 	int openings;
5732f001371SPeter Grehan 
5742f001371SPeter Grehan 	dev = sc->vtscsi_dev;
5752f001371SPeter Grehan 	openings = sc->vtscsi_nrequests - VTSCSI_RESERVED_REQUESTS;
5762f001371SPeter Grehan 
5772f001371SPeter Grehan 	devq = cam_simq_alloc(openings);
5782f001371SPeter Grehan 	if (devq == NULL) {
5792f001371SPeter Grehan 		device_printf(dev, "cannot allocate SIM queue\n");
5802f001371SPeter Grehan 		return (ENOMEM);
5812f001371SPeter Grehan 	}
5822f001371SPeter Grehan 
5832f001371SPeter Grehan 	sc->vtscsi_sim = cam_sim_alloc(vtscsi_cam_action, vtscsi_cam_poll,
5842f001371SPeter Grehan 	    "vtscsi", sc, device_get_unit(dev), VTSCSI_MTX(sc), 1,
5852f001371SPeter Grehan 	    openings, devq);
5862f001371SPeter Grehan 	if (sc->vtscsi_sim == NULL) {
5872f001371SPeter Grehan 		cam_simq_free(devq);
5882f001371SPeter Grehan 		device_printf(dev, "cannot allocate SIM\n");
5892f001371SPeter Grehan 		return (ENOMEM);
5902f001371SPeter Grehan 	}
5912f001371SPeter Grehan 
5922f001371SPeter Grehan 	return (0);
5932f001371SPeter Grehan }
5942f001371SPeter Grehan 
5952f001371SPeter Grehan static int
vtscsi_register_cam(struct vtscsi_softc * sc)5962f001371SPeter Grehan vtscsi_register_cam(struct vtscsi_softc *sc)
5972f001371SPeter Grehan {
5982f001371SPeter Grehan 	device_t dev;
5992f001371SPeter Grehan 	int registered, error;
6002f001371SPeter Grehan 
6012f001371SPeter Grehan 	dev = sc->vtscsi_dev;
6022f001371SPeter Grehan 	registered = 0;
6032f001371SPeter Grehan 
6042f001371SPeter Grehan 	VTSCSI_LOCK(sc);
6052f001371SPeter Grehan 
6062f001371SPeter Grehan 	if (xpt_bus_register(sc->vtscsi_sim, dev, 0) != CAM_SUCCESS) {
6072f001371SPeter Grehan 		error = ENOMEM;
6082f001371SPeter Grehan 		device_printf(dev, "cannot register XPT bus\n");
6092f001371SPeter Grehan 		goto fail;
6102f001371SPeter Grehan 	}
6112f001371SPeter Grehan 
6122f001371SPeter Grehan 	registered = 1;
6132f001371SPeter Grehan 
6142f001371SPeter Grehan 	if (xpt_create_path(&sc->vtscsi_path, NULL,
6152f001371SPeter Grehan 	    cam_sim_path(sc->vtscsi_sim), CAM_TARGET_WILDCARD,
6162f001371SPeter Grehan 	    CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
6172f001371SPeter Grehan 		error = ENOMEM;
6182f001371SPeter Grehan 		device_printf(dev, "cannot create bus path\n");
6192f001371SPeter Grehan 		goto fail;
6202f001371SPeter Grehan 	}
6212f001371SPeter Grehan 
6222f001371SPeter Grehan 	if (vtscsi_register_async(sc) != CAM_REQ_CMP) {
6232f001371SPeter Grehan 		error = EIO;
6242f001371SPeter Grehan 		device_printf(dev, "cannot register async callback\n");
6252f001371SPeter Grehan 		goto fail;
6262f001371SPeter Grehan 	}
6272f001371SPeter Grehan 
6284d5919ecSBryan Venteicher 	VTSCSI_UNLOCK(sc);
6294d5919ecSBryan Venteicher 
6302f001371SPeter Grehan 	return (0);
6312f001371SPeter Grehan 
6322f001371SPeter Grehan fail:
6332f001371SPeter Grehan 	if (sc->vtscsi_path != NULL) {
6342f001371SPeter Grehan 		xpt_free_path(sc->vtscsi_path);
6352f001371SPeter Grehan 		sc->vtscsi_path = NULL;
6362f001371SPeter Grehan 	}
6372f001371SPeter Grehan 
6382f001371SPeter Grehan 	if (registered != 0)
6392f001371SPeter Grehan 		xpt_bus_deregister(cam_sim_path(sc->vtscsi_sim));
6402f001371SPeter Grehan 
6412f001371SPeter Grehan 	VTSCSI_UNLOCK(sc);
6422f001371SPeter Grehan 
6432f001371SPeter Grehan 	return (error);
6442f001371SPeter Grehan }
6452f001371SPeter Grehan 
6462f001371SPeter Grehan static void
vtscsi_free_cam(struct vtscsi_softc * sc)6472f001371SPeter Grehan vtscsi_free_cam(struct vtscsi_softc *sc)
6482f001371SPeter Grehan {
6492f001371SPeter Grehan 
6502f001371SPeter Grehan 	VTSCSI_LOCK(sc);
6512f001371SPeter Grehan 
6522f001371SPeter Grehan 	if (sc->vtscsi_path != NULL) {
6532f001371SPeter Grehan 		vtscsi_deregister_async(sc);
6542f001371SPeter Grehan 
6552f001371SPeter Grehan 		xpt_free_path(sc->vtscsi_path);
6562f001371SPeter Grehan 		sc->vtscsi_path = NULL;
6572f001371SPeter Grehan 
6582f001371SPeter Grehan 		xpt_bus_deregister(cam_sim_path(sc->vtscsi_sim));
6592f001371SPeter Grehan 	}
6602f001371SPeter Grehan 
6612f001371SPeter Grehan 	if (sc->vtscsi_sim != NULL) {
6622f001371SPeter Grehan 		cam_sim_free(sc->vtscsi_sim, 1);
6632f001371SPeter Grehan 		sc->vtscsi_sim = NULL;
6642f001371SPeter Grehan 	}
6652f001371SPeter Grehan 
6662f001371SPeter Grehan 	VTSCSI_UNLOCK(sc);
6672f001371SPeter Grehan }
6682f001371SPeter Grehan 
6692f001371SPeter Grehan static void
vtscsi_cam_async(void * cb_arg,uint32_t code,struct cam_path * path,void * arg)6702f001371SPeter Grehan vtscsi_cam_async(void *cb_arg, uint32_t code, struct cam_path *path, void *arg)
6712f001371SPeter Grehan {
6722f001371SPeter Grehan 	struct cam_sim *sim;
6732f001371SPeter Grehan 	struct vtscsi_softc *sc;
6742f001371SPeter Grehan 
6752f001371SPeter Grehan 	sim = cb_arg;
6762f001371SPeter Grehan 	sc = cam_sim_softc(sim);
6772f001371SPeter Grehan 
6782f001371SPeter Grehan 	vtscsi_dprintf(sc, VTSCSI_TRACE, "code=%u\n", code);
6792f001371SPeter Grehan 
6802f001371SPeter Grehan 	/*
6812f001371SPeter Grehan 	 * TODO Once QEMU supports event reporting, we should
6822f001371SPeter Grehan 	 *      (un)subscribe to events here.
6832f001371SPeter Grehan 	 */
6842f001371SPeter Grehan 	switch (code) {
6852f001371SPeter Grehan 	case AC_FOUND_DEVICE:
6862f001371SPeter Grehan 		break;
6872f001371SPeter Grehan 	case AC_LOST_DEVICE:
6882f001371SPeter Grehan 		break;
6892f001371SPeter Grehan 	}
6902f001371SPeter Grehan }
6912f001371SPeter Grehan 
6922f001371SPeter Grehan static int
vtscsi_register_async(struct vtscsi_softc * sc)6932f001371SPeter Grehan vtscsi_register_async(struct vtscsi_softc *sc)
6942f001371SPeter Grehan {
6952f001371SPeter Grehan 	struct ccb_setasync csa;
6962f001371SPeter Grehan 
6975b81e2e1SMark Johnston 	memset(&csa, 0, sizeof(csa));
6982f001371SPeter Grehan 	xpt_setup_ccb(&csa.ccb_h, sc->vtscsi_path, 5);
6992f001371SPeter Grehan 	csa.ccb_h.func_code = XPT_SASYNC_CB;
7002f001371SPeter Grehan 	csa.event_enable = AC_LOST_DEVICE | AC_FOUND_DEVICE;
7012f001371SPeter Grehan 	csa.callback = vtscsi_cam_async;
7022f001371SPeter Grehan 	csa.callback_arg = sc->vtscsi_sim;
7032f001371SPeter Grehan 
7042f001371SPeter Grehan 	xpt_action((union ccb *) &csa);
7052f001371SPeter Grehan 
7062f001371SPeter Grehan 	return (csa.ccb_h.status);
7072f001371SPeter Grehan }
7082f001371SPeter Grehan 
7092f001371SPeter Grehan static void
vtscsi_deregister_async(struct vtscsi_softc * sc)7102f001371SPeter Grehan vtscsi_deregister_async(struct vtscsi_softc *sc)
7112f001371SPeter Grehan {
7122f001371SPeter Grehan 	struct ccb_setasync csa;
7132f001371SPeter Grehan 
7145b81e2e1SMark Johnston 	memset(&csa, 0, sizeof(csa));
7152f001371SPeter Grehan 	xpt_setup_ccb(&csa.ccb_h, sc->vtscsi_path, 5);
7162f001371SPeter Grehan 	csa.ccb_h.func_code = XPT_SASYNC_CB;
7172f001371SPeter Grehan 	csa.event_enable = 0;
7182f001371SPeter Grehan 	csa.callback = vtscsi_cam_async;
7192f001371SPeter Grehan 	csa.callback_arg = sc->vtscsi_sim;
7202f001371SPeter Grehan 
7212f001371SPeter Grehan 	xpt_action((union ccb *) &csa);
7222f001371SPeter Grehan }
7232f001371SPeter Grehan 
7242f001371SPeter Grehan static void
vtscsi_cam_action(struct cam_sim * sim,union ccb * ccb)7252f001371SPeter Grehan vtscsi_cam_action(struct cam_sim *sim, union ccb *ccb)
7262f001371SPeter Grehan {
7272f001371SPeter Grehan 	struct vtscsi_softc *sc;
7282f001371SPeter Grehan 	struct ccb_hdr *ccbh;
7292f001371SPeter Grehan 
7302f001371SPeter Grehan 	sc = cam_sim_softc(sim);
7312f001371SPeter Grehan 	ccbh = &ccb->ccb_h;
7322f001371SPeter Grehan 
7332f001371SPeter Grehan 	VTSCSI_LOCK_OWNED(sc);
7342f001371SPeter Grehan 
7352f001371SPeter Grehan 	if (sc->vtscsi_flags & VTSCSI_FLAG_DETACH) {
7362f001371SPeter Grehan 		/*
7372f001371SPeter Grehan 		 * The VTSCSI_MTX is briefly dropped between setting
7382f001371SPeter Grehan 		 * VTSCSI_FLAG_DETACH and deregistering with CAM, so
7392f001371SPeter Grehan 		 * drop any CCBs that come in during that window.
7402f001371SPeter Grehan 		 */
7412f001371SPeter Grehan 		ccbh->status = CAM_NO_HBA;
7422f001371SPeter Grehan 		xpt_done(ccb);
7432f001371SPeter Grehan 		return;
7442f001371SPeter Grehan 	}
7452f001371SPeter Grehan 
7462f001371SPeter Grehan 	switch (ccbh->func_code) {
7472f001371SPeter Grehan 	case XPT_SCSI_IO:
7482f001371SPeter Grehan 		vtscsi_cam_scsi_io(sc, sim, ccb);
7492f001371SPeter Grehan 		break;
7502f001371SPeter Grehan 
7512f001371SPeter Grehan 	case XPT_SET_TRAN_SETTINGS:
7522f001371SPeter Grehan 		ccbh->status = CAM_FUNC_NOTAVAIL;
7532f001371SPeter Grehan 		xpt_done(ccb);
7542f001371SPeter Grehan 		break;
7552f001371SPeter Grehan 
7562f001371SPeter Grehan 	case XPT_GET_TRAN_SETTINGS:
7572f001371SPeter Grehan 		vtscsi_cam_get_tran_settings(sc, ccb);
7582f001371SPeter Grehan 		break;
7592f001371SPeter Grehan 
7602f001371SPeter Grehan 	case XPT_RESET_BUS:
7612f001371SPeter Grehan 		vtscsi_cam_reset_bus(sc, ccb);
7622f001371SPeter Grehan 		break;
7632f001371SPeter Grehan 
7642f001371SPeter Grehan 	case XPT_RESET_DEV:
7652f001371SPeter Grehan 		vtscsi_cam_reset_dev(sc, ccb);
7662f001371SPeter Grehan 		break;
7672f001371SPeter Grehan 
7682f001371SPeter Grehan 	case XPT_ABORT:
7692f001371SPeter Grehan 		vtscsi_cam_abort(sc, ccb);
7702f001371SPeter Grehan 		break;
7712f001371SPeter Grehan 
7722f001371SPeter Grehan 	case XPT_CALC_GEOMETRY:
7732f001371SPeter Grehan 		cam_calc_geometry(&ccb->ccg, 1);
7742f001371SPeter Grehan 		xpt_done(ccb);
7752f001371SPeter Grehan 		break;
7762f001371SPeter Grehan 
7772f001371SPeter Grehan 	case XPT_PATH_INQ:
7782f001371SPeter Grehan 		vtscsi_cam_path_inquiry(sc, sim, ccb);
7792f001371SPeter Grehan 		break;
7802f001371SPeter Grehan 
7812f001371SPeter Grehan 	default:
7822f001371SPeter Grehan 		vtscsi_dprintf(sc, VTSCSI_ERROR,
7832f001371SPeter Grehan 		    "invalid ccb=%p func=%#x\n", ccb, ccbh->func_code);
7842f001371SPeter Grehan 
7852f001371SPeter Grehan 		ccbh->status = CAM_REQ_INVALID;
7862f001371SPeter Grehan 		xpt_done(ccb);
7872f001371SPeter Grehan 		break;
7882f001371SPeter Grehan 	}
7892f001371SPeter Grehan }
7902f001371SPeter Grehan 
7912f001371SPeter Grehan static void
vtscsi_cam_poll(struct cam_sim * sim)7922f001371SPeter Grehan vtscsi_cam_poll(struct cam_sim *sim)
7932f001371SPeter Grehan {
7942f001371SPeter Grehan 	struct vtscsi_softc *sc;
7952f001371SPeter Grehan 
7962f001371SPeter Grehan 	sc = cam_sim_softc(sim);
7972f001371SPeter Grehan 
7982f001371SPeter Grehan 	vtscsi_complete_vqs_locked(sc);
7992f001371SPeter Grehan }
8002f001371SPeter Grehan 
8012f001371SPeter Grehan static void
vtscsi_cam_scsi_io(struct vtscsi_softc * sc,struct cam_sim * sim,union ccb * ccb)8022f001371SPeter Grehan vtscsi_cam_scsi_io(struct vtscsi_softc *sc, struct cam_sim *sim,
8032f001371SPeter Grehan     union ccb *ccb)
8042f001371SPeter Grehan {
8052f001371SPeter Grehan 	struct ccb_hdr *ccbh;
8062f001371SPeter Grehan 	struct ccb_scsiio *csio;
8072f001371SPeter Grehan 	int error;
8082f001371SPeter Grehan 
8092f001371SPeter Grehan 	ccbh = &ccb->ccb_h;
8102f001371SPeter Grehan 	csio = &ccb->csio;
8112f001371SPeter Grehan 
8122f001371SPeter Grehan 	if (csio->cdb_len > VIRTIO_SCSI_CDB_SIZE) {
8132f001371SPeter Grehan 		error = EINVAL;
8142f001371SPeter Grehan 		ccbh->status = CAM_REQ_INVALID;
8152f001371SPeter Grehan 		goto done;
8162f001371SPeter Grehan 	}
8172f001371SPeter Grehan 
8182f001371SPeter Grehan 	if ((ccbh->flags & CAM_DIR_MASK) == CAM_DIR_BOTH &&
8192f001371SPeter Grehan 	    (sc->vtscsi_flags & VTSCSI_FLAG_BIDIRECTIONAL) == 0) {
8202f001371SPeter Grehan 		error = EINVAL;
8212f001371SPeter Grehan 		ccbh->status = CAM_REQ_INVALID;
8222f001371SPeter Grehan 		goto done;
8232f001371SPeter Grehan 	}
8242f001371SPeter Grehan 
8252f001371SPeter Grehan 	error = vtscsi_start_scsi_cmd(sc, ccb);
8262f001371SPeter Grehan 
8272f001371SPeter Grehan done:
8282f001371SPeter Grehan 	if (error) {
8292f001371SPeter Grehan 		vtscsi_dprintf(sc, VTSCSI_ERROR,
8302f001371SPeter Grehan 		    "error=%d ccb=%p status=%#x\n", error, ccb, ccbh->status);
8312f001371SPeter Grehan 		xpt_done(ccb);
8322f001371SPeter Grehan 	}
8332f001371SPeter Grehan }
8342f001371SPeter Grehan 
8352f001371SPeter Grehan static void
vtscsi_cam_get_tran_settings(struct vtscsi_softc * sc,union ccb * ccb)8362f001371SPeter Grehan vtscsi_cam_get_tran_settings(struct vtscsi_softc *sc, union ccb *ccb)
8372f001371SPeter Grehan {
8382f001371SPeter Grehan 	struct ccb_trans_settings *cts;
8392f001371SPeter Grehan 	struct ccb_trans_settings_scsi *scsi;
8402f001371SPeter Grehan 
8412f001371SPeter Grehan 	cts = &ccb->cts;
8422f001371SPeter Grehan 	scsi = &cts->proto_specific.scsi;
8432f001371SPeter Grehan 
8442f001371SPeter Grehan 	cts->protocol = PROTO_SCSI;
8452f001371SPeter Grehan 	cts->protocol_version = SCSI_REV_SPC3;
8462f001371SPeter Grehan 	cts->transport = XPORT_SAS;
8472f001371SPeter Grehan 	cts->transport_version = 0;
8482f001371SPeter Grehan 
8492f001371SPeter Grehan 	scsi->valid = CTS_SCSI_VALID_TQ;
8502f001371SPeter Grehan 	scsi->flags = CTS_SCSI_FLAGS_TAG_ENB;
8512f001371SPeter Grehan 
8522f001371SPeter Grehan 	ccb->ccb_h.status = CAM_REQ_CMP;
8532f001371SPeter Grehan 	xpt_done(ccb);
8542f001371SPeter Grehan }
8552f001371SPeter Grehan 
8562f001371SPeter Grehan static void
vtscsi_cam_reset_bus(struct vtscsi_softc * sc,union ccb * ccb)8572f001371SPeter Grehan vtscsi_cam_reset_bus(struct vtscsi_softc *sc, union ccb *ccb)
8582f001371SPeter Grehan {
8592f001371SPeter Grehan 	int error;
8602f001371SPeter Grehan 
8612f001371SPeter Grehan 	error = vtscsi_reset_bus(sc);
8622f001371SPeter Grehan 	if (error == 0)
8632f001371SPeter Grehan 		ccb->ccb_h.status = CAM_REQ_CMP;
8642f001371SPeter Grehan 	else
8652f001371SPeter Grehan 		ccb->ccb_h.status = CAM_REQ_CMP_ERR;
8662f001371SPeter Grehan 
8672f001371SPeter Grehan 	vtscsi_dprintf(sc, VTSCSI_TRACE, "error=%d ccb=%p status=%#x\n",
8682f001371SPeter Grehan 	    error, ccb, ccb->ccb_h.status);
8692f001371SPeter Grehan 
8702f001371SPeter Grehan 	xpt_done(ccb);
8712f001371SPeter Grehan }
8722f001371SPeter Grehan 
8732f001371SPeter Grehan static void
vtscsi_cam_reset_dev(struct vtscsi_softc * sc,union ccb * ccb)8742f001371SPeter Grehan vtscsi_cam_reset_dev(struct vtscsi_softc *sc, union ccb *ccb)
8752f001371SPeter Grehan {
8762f001371SPeter Grehan 	struct ccb_hdr *ccbh;
8772f001371SPeter Grehan 	struct vtscsi_request *req;
8782f001371SPeter Grehan 	int error;
8792f001371SPeter Grehan 
8802f001371SPeter Grehan 	ccbh = &ccb->ccb_h;
8812f001371SPeter Grehan 
8822f001371SPeter Grehan 	req = vtscsi_dequeue_request(sc);
8832f001371SPeter Grehan 	if (req == NULL) {
8842f001371SPeter Grehan 		error = EAGAIN;
8852f001371SPeter Grehan 		vtscsi_freeze_simq(sc, VTSCSI_REQUEST);
8862f001371SPeter Grehan 		goto fail;
8872f001371SPeter Grehan 	}
8882f001371SPeter Grehan 
8892f001371SPeter Grehan 	req->vsr_ccb = ccb;
8902f001371SPeter Grehan 
8912f001371SPeter Grehan 	error = vtscsi_execute_reset_dev_cmd(sc, req);
8922f001371SPeter Grehan 	if (error == 0)
8932f001371SPeter Grehan 		return;
8942f001371SPeter Grehan 
8952f001371SPeter Grehan 	vtscsi_enqueue_request(sc, req);
8962f001371SPeter Grehan 
8972f001371SPeter Grehan fail:
8982f001371SPeter Grehan 	vtscsi_dprintf(sc, VTSCSI_ERROR, "error=%d req=%p ccb=%p\n",
8992f001371SPeter Grehan 	    error, req, ccb);
9002f001371SPeter Grehan 
9012f001371SPeter Grehan 	if (error == EAGAIN)
9022f001371SPeter Grehan 		ccbh->status = CAM_RESRC_UNAVAIL;
9032f001371SPeter Grehan 	else
9042f001371SPeter Grehan 		ccbh->status = CAM_REQ_CMP_ERR;
9052f001371SPeter Grehan 
9062f001371SPeter Grehan 	xpt_done(ccb);
9072f001371SPeter Grehan }
9082f001371SPeter Grehan 
9092f001371SPeter Grehan static void
vtscsi_cam_abort(struct vtscsi_softc * sc,union ccb * ccb)9102f001371SPeter Grehan vtscsi_cam_abort(struct vtscsi_softc *sc, union ccb *ccb)
9112f001371SPeter Grehan {
9122f001371SPeter Grehan 	struct vtscsi_request *req;
9132f001371SPeter Grehan 	struct ccb_hdr *ccbh;
9142f001371SPeter Grehan 	int error;
9152f001371SPeter Grehan 
9162f001371SPeter Grehan 	ccbh = &ccb->ccb_h;
9172f001371SPeter Grehan 
9182f001371SPeter Grehan 	req = vtscsi_dequeue_request(sc);
9192f001371SPeter Grehan 	if (req == NULL) {
9202f001371SPeter Grehan 		error = EAGAIN;
9212f001371SPeter Grehan 		vtscsi_freeze_simq(sc, VTSCSI_REQUEST);
9222f001371SPeter Grehan 		goto fail;
9232f001371SPeter Grehan 	}
9242f001371SPeter Grehan 
9252f001371SPeter Grehan 	req->vsr_ccb = ccb;
9262f001371SPeter Grehan 
9272f001371SPeter Grehan 	error = vtscsi_execute_abort_task_cmd(sc, req);
9282f001371SPeter Grehan 	if (error == 0)
9292f001371SPeter Grehan 		return;
9302f001371SPeter Grehan 
9312f001371SPeter Grehan 	vtscsi_enqueue_request(sc, req);
9322f001371SPeter Grehan 
9332f001371SPeter Grehan fail:
9342f001371SPeter Grehan 	vtscsi_dprintf(sc, VTSCSI_ERROR, "error=%d req=%p ccb=%p\n",
9352f001371SPeter Grehan 	    error, req, ccb);
9362f001371SPeter Grehan 
9372f001371SPeter Grehan 	if (error == EAGAIN)
9382f001371SPeter Grehan 		ccbh->status = CAM_RESRC_UNAVAIL;
9392f001371SPeter Grehan 	else
9402f001371SPeter Grehan 		ccbh->status = CAM_REQ_CMP_ERR;
9412f001371SPeter Grehan 
9422f001371SPeter Grehan 	xpt_done(ccb);
9432f001371SPeter Grehan }
9442f001371SPeter Grehan 
9452f001371SPeter Grehan static void
vtscsi_cam_path_inquiry(struct vtscsi_softc * sc,struct cam_sim * sim,union ccb * ccb)9462f001371SPeter Grehan vtscsi_cam_path_inquiry(struct vtscsi_softc *sc, struct cam_sim *sim,
9472f001371SPeter Grehan     union ccb *ccb)
9482f001371SPeter Grehan {
9492f001371SPeter Grehan 	device_t dev;
9502f001371SPeter Grehan 	struct ccb_pathinq *cpi;
9512f001371SPeter Grehan 
9522f001371SPeter Grehan 	dev = sc->vtscsi_dev;
9532f001371SPeter Grehan 	cpi = &ccb->cpi;
9542f001371SPeter Grehan 
9552f001371SPeter Grehan 	vtscsi_dprintf(sc, VTSCSI_TRACE, "sim=%p ccb=%p\n", sim, ccb);
9562f001371SPeter Grehan 
9572f001371SPeter Grehan 	cpi->version_num = 1;
9582f001371SPeter Grehan 	cpi->hba_inquiry = PI_TAG_ABLE;
9592f001371SPeter Grehan 	cpi->target_sprt = 0;
96022525db5SBryan Venteicher 	cpi->hba_misc = PIM_SEQSCAN | PIM_UNMAPPED;
9612f001371SPeter Grehan 	if (vtscsi_bus_reset_disable != 0)
9622f001371SPeter Grehan 		cpi->hba_misc |= PIM_NOBUSRESET;
9632f001371SPeter Grehan 	cpi->hba_eng_cnt = 0;
9642f001371SPeter Grehan 
9652f001371SPeter Grehan 	cpi->max_target = sc->vtscsi_max_target;
9662f001371SPeter Grehan 	cpi->max_lun = sc->vtscsi_max_lun;
967adbf6af7SAndriy Gapon 	cpi->initiator_id = cpi->max_target + 1;
9682f001371SPeter Grehan 
9694195c7deSAlan Somers 	strlcpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
9704195c7deSAlan Somers 	strlcpy(cpi->hba_vid, "VirtIO", HBA_IDLEN);
9714195c7deSAlan Somers 	strlcpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
9722f001371SPeter Grehan 
9732f001371SPeter Grehan 	cpi->unit_number = cam_sim_unit(sim);
9742f001371SPeter Grehan 	cpi->bus_id = cam_sim_bus(sim);
9752f001371SPeter Grehan 
9762f001371SPeter Grehan 	cpi->base_transfer_speed = 300000;
9772f001371SPeter Grehan 
9782f001371SPeter Grehan 	cpi->protocol = PROTO_SCSI;
9792f001371SPeter Grehan 	cpi->protocol_version = SCSI_REV_SPC3;
9802f001371SPeter Grehan 	cpi->transport = XPORT_SAS;
9812f001371SPeter Grehan 	cpi->transport_version = 0;
9822f001371SPeter Grehan 
9832f001371SPeter Grehan 	cpi->maxio = (sc->vtscsi_max_nsegs - VTSCSI_MIN_SEGMENTS - 1) *
9842f001371SPeter Grehan 	    PAGE_SIZE;
9852f001371SPeter Grehan 
9862f001371SPeter Grehan 	cpi->hba_vendor = virtio_get_vendor(dev);
9872f001371SPeter Grehan 	cpi->hba_device = virtio_get_device(dev);
9882f001371SPeter Grehan 	cpi->hba_subvendor = virtio_get_subvendor(dev);
9892f001371SPeter Grehan 	cpi->hba_subdevice = virtio_get_subdevice(dev);
9902f001371SPeter Grehan 
9912f001371SPeter Grehan 	ccb->ccb_h.status = CAM_REQ_CMP;
9922f001371SPeter Grehan 	xpt_done(ccb);
9932f001371SPeter Grehan }
9942f001371SPeter Grehan 
9952f001371SPeter Grehan static int
vtscsi_sg_append_scsi_buf(struct vtscsi_softc * sc,struct sglist * sg,struct ccb_scsiio * csio)9962f001371SPeter Grehan vtscsi_sg_append_scsi_buf(struct vtscsi_softc *sc, struct sglist *sg,
9972f001371SPeter Grehan     struct ccb_scsiio *csio)
9982f001371SPeter Grehan {
9992f001371SPeter Grehan 	struct ccb_hdr *ccbh;
10002f001371SPeter Grehan 	struct bus_dma_segment *dseg;
10012f001371SPeter Grehan 	int i, error;
10022f001371SPeter Grehan 
10032f001371SPeter Grehan 	ccbh = &csio->ccb_h;
10042f001371SPeter Grehan 	error = 0;
10052f001371SPeter Grehan 
1006dd0b4fb6SKonstantin Belousov 	switch ((ccbh->flags & CAM_DATA_MASK)) {
1007dd0b4fb6SKonstantin Belousov 	case CAM_DATA_VADDR:
1008dd0b4fb6SKonstantin Belousov 		error = sglist_append(sg, csio->data_ptr, csio->dxfer_len);
1009dd0b4fb6SKonstantin Belousov 		break;
1010dd0b4fb6SKonstantin Belousov 	case CAM_DATA_PADDR:
10112f001371SPeter Grehan 		error = sglist_append_phys(sg,
1012dd0b4fb6SKonstantin Belousov 		    (vm_paddr_t)(vm_offset_t) csio->data_ptr, csio->dxfer_len);
1013dd0b4fb6SKonstantin Belousov 		break;
1014dd0b4fb6SKonstantin Belousov 	case CAM_DATA_SG:
10152f001371SPeter Grehan 		for (i = 0; i < csio->sglist_cnt && error == 0; i++) {
10162f001371SPeter Grehan 			dseg = &((struct bus_dma_segment *)csio->data_ptr)[i];
10172f001371SPeter Grehan 			error = sglist_append(sg,
1018dd0b4fb6SKonstantin Belousov 			    (void *)(vm_offset_t) dseg->ds_addr, dseg->ds_len);
1019dd0b4fb6SKonstantin Belousov 		}
1020dd0b4fb6SKonstantin Belousov 		break;
1021dd0b4fb6SKonstantin Belousov 	case CAM_DATA_SG_PADDR:
1022dd0b4fb6SKonstantin Belousov 		for (i = 0; i < csio->sglist_cnt && error == 0; i++) {
1023dd0b4fb6SKonstantin Belousov 			dseg = &((struct bus_dma_segment *)csio->data_ptr)[i];
10242f001371SPeter Grehan 			error = sglist_append_phys(sg,
10252f001371SPeter Grehan 			    (vm_paddr_t) dseg->ds_addr, dseg->ds_len);
10262f001371SPeter Grehan 		}
1027dd0b4fb6SKonstantin Belousov 		break;
102822525db5SBryan Venteicher 	case CAM_DATA_BIO:
102922525db5SBryan Venteicher 		error = sglist_append_bio(sg, (struct bio *) csio->data_ptr);
103022525db5SBryan Venteicher 		break;
1031dd0b4fb6SKonstantin Belousov 	default:
1032dd0b4fb6SKonstantin Belousov 		error = EINVAL;
1033dd0b4fb6SKonstantin Belousov 		break;
10342f001371SPeter Grehan 	}
10352f001371SPeter Grehan 
10362f001371SPeter Grehan 	return (error);
10372f001371SPeter Grehan }
10382f001371SPeter Grehan 
10392f001371SPeter Grehan static int
vtscsi_fill_scsi_cmd_sglist(struct vtscsi_softc * sc,struct vtscsi_request * req,int * readable,int * writable)10402f001371SPeter Grehan vtscsi_fill_scsi_cmd_sglist(struct vtscsi_softc *sc, struct vtscsi_request *req,
10412f001371SPeter Grehan     int *readable, int *writable)
10422f001371SPeter Grehan {
10432f001371SPeter Grehan 	struct sglist *sg;
10442f001371SPeter Grehan 	struct ccb_hdr *ccbh;
10452f001371SPeter Grehan 	struct ccb_scsiio *csio;
10462f001371SPeter Grehan 	struct virtio_scsi_cmd_req *cmd_req;
10472f001371SPeter Grehan 	struct virtio_scsi_cmd_resp *cmd_resp;
10482f001371SPeter Grehan 	int error;
10492f001371SPeter Grehan 
10502f001371SPeter Grehan 	sg = sc->vtscsi_sglist;
10512f001371SPeter Grehan 	csio = &req->vsr_ccb->csio;
10522f001371SPeter Grehan 	ccbh = &csio->ccb_h;
10532f001371SPeter Grehan 	cmd_req = &req->vsr_cmd_req;
10542f001371SPeter Grehan 	cmd_resp = &req->vsr_cmd_resp;
10552f001371SPeter Grehan 
10562f001371SPeter Grehan 	sglist_reset(sg);
10572f001371SPeter Grehan 
10582f001371SPeter Grehan 	sglist_append(sg, cmd_req, sizeof(struct virtio_scsi_cmd_req));
10592f001371SPeter Grehan 	if ((ccbh->flags & CAM_DIR_MASK) == CAM_DIR_OUT) {
10602f001371SPeter Grehan 		error = vtscsi_sg_append_scsi_buf(sc, sg, csio);
10612f001371SPeter Grehan 		/* At least one segment must be left for the response. */
10622f001371SPeter Grehan 		if (error || sg->sg_nseg == sg->sg_maxseg)
10632f001371SPeter Grehan 			goto fail;
10642f001371SPeter Grehan 	}
10652f001371SPeter Grehan 
10662f001371SPeter Grehan 	*readable = sg->sg_nseg;
10672f001371SPeter Grehan 
10682f001371SPeter Grehan 	sglist_append(sg, cmd_resp, sizeof(struct virtio_scsi_cmd_resp));
10692f001371SPeter Grehan 	if ((ccbh->flags & CAM_DIR_MASK) == CAM_DIR_IN) {
10702f001371SPeter Grehan 		error = vtscsi_sg_append_scsi_buf(sc, sg, csio);
10712f001371SPeter Grehan 		if (error)
10722f001371SPeter Grehan 			goto fail;
10732f001371SPeter Grehan 	}
10742f001371SPeter Grehan 
10752f001371SPeter Grehan 	*writable = sg->sg_nseg - *readable;
10762f001371SPeter Grehan 
10772f001371SPeter Grehan 	vtscsi_dprintf(sc, VTSCSI_TRACE, "req=%p ccb=%p readable=%d "
10782f001371SPeter Grehan 	    "writable=%d\n", req, ccbh, *readable, *writable);
10792f001371SPeter Grehan 
10802f001371SPeter Grehan 	return (0);
10812f001371SPeter Grehan 
10822f001371SPeter Grehan fail:
10832f001371SPeter Grehan 	/*
10842f001371SPeter Grehan 	 * This should never happen unless maxio was incorrectly set.
10852f001371SPeter Grehan 	 */
10862f001371SPeter Grehan 	vtscsi_set_ccb_status(ccbh, CAM_REQ_TOO_BIG, 0);
10872f001371SPeter Grehan 
10882f001371SPeter Grehan 	vtscsi_dprintf(sc, VTSCSI_ERROR, "error=%d req=%p ccb=%p "
10892f001371SPeter Grehan 	    "nseg=%d maxseg=%d\n",
10902f001371SPeter Grehan 	    error, req, ccbh, sg->sg_nseg, sg->sg_maxseg);
10912f001371SPeter Grehan 
10922f001371SPeter Grehan 	return (EFBIG);
10932f001371SPeter Grehan }
10942f001371SPeter Grehan 
10952f001371SPeter Grehan static int
vtscsi_execute_scsi_cmd(struct vtscsi_softc * sc,struct vtscsi_request * req)10962f001371SPeter Grehan vtscsi_execute_scsi_cmd(struct vtscsi_softc *sc, struct vtscsi_request *req)
10972f001371SPeter Grehan {
10982f001371SPeter Grehan 	struct sglist *sg;
10992f001371SPeter Grehan 	struct virtqueue *vq;
11002f001371SPeter Grehan 	struct ccb_scsiio *csio;
11012f001371SPeter Grehan 	struct ccb_hdr *ccbh;
11022f001371SPeter Grehan 	struct virtio_scsi_cmd_req *cmd_req;
11032f001371SPeter Grehan 	struct virtio_scsi_cmd_resp *cmd_resp;
11042f001371SPeter Grehan 	int readable, writable, error;
11052f001371SPeter Grehan 
11062f001371SPeter Grehan 	sg = sc->vtscsi_sglist;
11072f001371SPeter Grehan 	vq = sc->vtscsi_request_vq;
11082f001371SPeter Grehan 	csio = &req->vsr_ccb->csio;
11092f001371SPeter Grehan 	ccbh = &csio->ccb_h;
11102f001371SPeter Grehan 	cmd_req = &req->vsr_cmd_req;
11112f001371SPeter Grehan 	cmd_resp = &req->vsr_cmd_resp;
11122f001371SPeter Grehan 
111315be4953SBryan Venteicher 	vtscsi_init_scsi_cmd_req(sc, csio, cmd_req);
11142f001371SPeter Grehan 
11152f001371SPeter Grehan 	error = vtscsi_fill_scsi_cmd_sglist(sc, req, &readable, &writable);
11162f001371SPeter Grehan 	if (error)
11172f001371SPeter Grehan 		return (error);
11182f001371SPeter Grehan 
11192f001371SPeter Grehan 	req->vsr_complete = vtscsi_complete_scsi_cmd;
11202f001371SPeter Grehan 	cmd_resp->response = -1;
11212f001371SPeter Grehan 
11222f001371SPeter Grehan 	error = virtqueue_enqueue(vq, req, sg, readable, writable);
11232f001371SPeter Grehan 	if (error) {
11242f001371SPeter Grehan 		vtscsi_dprintf(sc, VTSCSI_ERROR,
11252f001371SPeter Grehan 		    "enqueue error=%d req=%p ccb=%p\n", error, req, ccbh);
11262f001371SPeter Grehan 
11272f001371SPeter Grehan 		ccbh->status = CAM_REQUEUE_REQ;
11282f001371SPeter Grehan 		vtscsi_freeze_simq(sc, VTSCSI_REQUEST_VQ);
11292f001371SPeter Grehan 		return (error);
11302f001371SPeter Grehan 	}
11312f001371SPeter Grehan 
11322f001371SPeter Grehan 	ccbh->status |= CAM_SIM_QUEUED;
11332f001371SPeter Grehan 	ccbh->ccbh_vtscsi_req = req;
11342f001371SPeter Grehan 
11352f001371SPeter Grehan 	virtqueue_notify(vq);
11362f001371SPeter Grehan 
11372f001371SPeter Grehan 	if (ccbh->timeout != CAM_TIME_INFINITY) {
11382f001371SPeter Grehan 		req->vsr_flags |= VTSCSI_REQ_FLAG_TIMEOUT_SET;
113985c9dd9dSSteven Hartland 		callout_reset_sbt(&req->vsr_callout, SBT_1MS * ccbh->timeout,
114085c9dd9dSSteven Hartland 		    0, vtscsi_timedout_scsi_cmd, req, 0);
11412f001371SPeter Grehan 	}
11422f001371SPeter Grehan 
11432f001371SPeter Grehan 	vtscsi_dprintf_req(req, VTSCSI_TRACE, "enqueued req=%p ccb=%p\n",
11442f001371SPeter Grehan 	    req, ccbh);
11452f001371SPeter Grehan 
11462f001371SPeter Grehan 	return (0);
11472f001371SPeter Grehan }
11482f001371SPeter Grehan 
11492f001371SPeter Grehan static int
vtscsi_start_scsi_cmd(struct vtscsi_softc * sc,union ccb * ccb)11502f001371SPeter Grehan vtscsi_start_scsi_cmd(struct vtscsi_softc *sc, union ccb *ccb)
11512f001371SPeter Grehan {
11522f001371SPeter Grehan 	struct vtscsi_request *req;
11532f001371SPeter Grehan 	int error;
11542f001371SPeter Grehan 
11552f001371SPeter Grehan 	req = vtscsi_dequeue_request(sc);
11562f001371SPeter Grehan 	if (req == NULL) {
11572f001371SPeter Grehan 		ccb->ccb_h.status = CAM_REQUEUE_REQ;
11582f001371SPeter Grehan 		vtscsi_freeze_simq(sc, VTSCSI_REQUEST);
11592f001371SPeter Grehan 		return (ENOBUFS);
11602f001371SPeter Grehan 	}
11612f001371SPeter Grehan 
11622f001371SPeter Grehan 	req->vsr_ccb = ccb;
11632f001371SPeter Grehan 
11642f001371SPeter Grehan 	error = vtscsi_execute_scsi_cmd(sc, req);
11652f001371SPeter Grehan 	if (error)
11662f001371SPeter Grehan 		vtscsi_enqueue_request(sc, req);
11672f001371SPeter Grehan 
11682f001371SPeter Grehan 	return (error);
11692f001371SPeter Grehan }
11702f001371SPeter Grehan 
11712f001371SPeter Grehan static void
vtscsi_complete_abort_timedout_scsi_cmd(struct vtscsi_softc * sc,struct vtscsi_request * req)11722f001371SPeter Grehan vtscsi_complete_abort_timedout_scsi_cmd(struct vtscsi_softc *sc,
11732f001371SPeter Grehan     struct vtscsi_request *req)
11742f001371SPeter Grehan {
11752f001371SPeter Grehan 	struct virtio_scsi_ctrl_tmf_resp *tmf_resp;
11762f001371SPeter Grehan 	struct vtscsi_request *to_req;
11772f001371SPeter Grehan 	uint8_t response;
11782f001371SPeter Grehan 
11792f001371SPeter Grehan 	tmf_resp = &req->vsr_tmf_resp;
11802f001371SPeter Grehan 	response = tmf_resp->response;
11812f001371SPeter Grehan 	to_req = req->vsr_timedout_req;
11822f001371SPeter Grehan 
11832f001371SPeter Grehan 	vtscsi_dprintf(sc, VTSCSI_TRACE, "req=%p to_req=%p response=%d\n",
11842f001371SPeter Grehan 	    req, to_req, response);
11852f001371SPeter Grehan 
11862f001371SPeter Grehan 	vtscsi_enqueue_request(sc, req);
11872f001371SPeter Grehan 
11882f001371SPeter Grehan 	/*
11892f001371SPeter Grehan 	 * The timedout request could have completed between when the
11902f001371SPeter Grehan 	 * abort task was sent and when the host processed it.
11912f001371SPeter Grehan 	 */
11922f001371SPeter Grehan 	if (to_req->vsr_state != VTSCSI_REQ_STATE_TIMEDOUT)
11932f001371SPeter Grehan 		return;
11942f001371SPeter Grehan 
11952f001371SPeter Grehan 	/* The timedout request was successfully aborted. */
11962f001371SPeter Grehan 	if (response == VIRTIO_SCSI_S_FUNCTION_COMPLETE)
11972f001371SPeter Grehan 		return;
11982f001371SPeter Grehan 
11992f001371SPeter Grehan 	/* Don't bother if the device is going away. */
12002f001371SPeter Grehan 	if (sc->vtscsi_flags & VTSCSI_FLAG_DETACH)
12012f001371SPeter Grehan 		return;
12022f001371SPeter Grehan 
12032f001371SPeter Grehan 	/* The timedout request will be aborted by the reset. */
12042f001371SPeter Grehan 	if (sc->vtscsi_flags & VTSCSI_FLAG_RESET)
12052f001371SPeter Grehan 		return;
12062f001371SPeter Grehan 
12072f001371SPeter Grehan 	vtscsi_reset_bus(sc);
12082f001371SPeter Grehan }
12092f001371SPeter Grehan 
12102f001371SPeter Grehan static int
vtscsi_abort_timedout_scsi_cmd(struct vtscsi_softc * sc,struct vtscsi_request * to_req)12112f001371SPeter Grehan vtscsi_abort_timedout_scsi_cmd(struct vtscsi_softc *sc,
12122f001371SPeter Grehan     struct vtscsi_request *to_req)
12132f001371SPeter Grehan {
12142f001371SPeter Grehan 	struct sglist *sg;
12152f001371SPeter Grehan 	struct ccb_hdr *to_ccbh;
12162f001371SPeter Grehan 	struct vtscsi_request *req;
12172f001371SPeter Grehan 	struct virtio_scsi_ctrl_tmf_req *tmf_req;
12182f001371SPeter Grehan 	struct virtio_scsi_ctrl_tmf_resp *tmf_resp;
12192f001371SPeter Grehan 	int error;
12202f001371SPeter Grehan 
12212f001371SPeter Grehan 	sg = sc->vtscsi_sglist;
12222f001371SPeter Grehan 	to_ccbh = &to_req->vsr_ccb->ccb_h;
12232f001371SPeter Grehan 
12242f001371SPeter Grehan 	req = vtscsi_dequeue_request(sc);
12252f001371SPeter Grehan 	if (req == NULL) {
12262f001371SPeter Grehan 		error = ENOBUFS;
12272f001371SPeter Grehan 		goto fail;
12282f001371SPeter Grehan 	}
12292f001371SPeter Grehan 
12302f001371SPeter Grehan 	tmf_req = &req->vsr_tmf_req;
12312f001371SPeter Grehan 	tmf_resp = &req->vsr_tmf_resp;
12322f001371SPeter Grehan 
123315be4953SBryan Venteicher 	vtscsi_init_ctrl_tmf_req(sc, to_ccbh, VIRTIO_SCSI_T_TMF_ABORT_TASK,
12342f001371SPeter Grehan 	    (uintptr_t) to_ccbh, tmf_req);
12352f001371SPeter Grehan 
12362f001371SPeter Grehan 	sglist_reset(sg);
12372f001371SPeter Grehan 	sglist_append(sg, tmf_req, sizeof(struct virtio_scsi_ctrl_tmf_req));
12382f001371SPeter Grehan 	sglist_append(sg, tmf_resp, sizeof(struct virtio_scsi_ctrl_tmf_resp));
12392f001371SPeter Grehan 
12402f001371SPeter Grehan 	req->vsr_timedout_req = to_req;
12412f001371SPeter Grehan 	req->vsr_complete = vtscsi_complete_abort_timedout_scsi_cmd;
12422f001371SPeter Grehan 	tmf_resp->response = -1;
12432f001371SPeter Grehan 
12442f001371SPeter Grehan 	error = vtscsi_execute_ctrl_req(sc, req, sg, 1, 1,
12452f001371SPeter Grehan 	    VTSCSI_EXECUTE_ASYNC);
12462f001371SPeter Grehan 	if (error == 0)
12472f001371SPeter Grehan 		return (0);
12482f001371SPeter Grehan 
12492f001371SPeter Grehan 	vtscsi_enqueue_request(sc, req);
12502f001371SPeter Grehan 
12512f001371SPeter Grehan fail:
12522f001371SPeter Grehan 	vtscsi_dprintf(sc, VTSCSI_ERROR, "error=%d req=%p "
12532f001371SPeter Grehan 	    "timedout req=%p ccb=%p\n", error, req, to_req, to_ccbh);
12542f001371SPeter Grehan 
12552f001371SPeter Grehan 	return (error);
12562f001371SPeter Grehan }
12572f001371SPeter Grehan 
12582f001371SPeter Grehan static void
vtscsi_timedout_scsi_cmd(void * xreq)12592f001371SPeter Grehan vtscsi_timedout_scsi_cmd(void *xreq)
12602f001371SPeter Grehan {
12612f001371SPeter Grehan 	struct vtscsi_softc *sc;
12622f001371SPeter Grehan 	struct vtscsi_request *to_req;
12632f001371SPeter Grehan 
12642f001371SPeter Grehan 	to_req = xreq;
12652f001371SPeter Grehan 	sc = to_req->vsr_softc;
12662f001371SPeter Grehan 
12672f001371SPeter Grehan 	vtscsi_dprintf(sc, VTSCSI_INFO, "timedout req=%p ccb=%p state=%#x\n",
12682f001371SPeter Grehan 	    to_req, to_req->vsr_ccb, to_req->vsr_state);
12692f001371SPeter Grehan 
12702f001371SPeter Grehan 	/* Don't bother if the device is going away. */
12712f001371SPeter Grehan 	if (sc->vtscsi_flags & VTSCSI_FLAG_DETACH)
12722f001371SPeter Grehan 		return;
12732f001371SPeter Grehan 
12742f001371SPeter Grehan 	/*
12752f001371SPeter Grehan 	 * Bail if the request is not in use. We likely raced when
12762f001371SPeter Grehan 	 * stopping the callout handler or it has already been aborted.
12772f001371SPeter Grehan 	 */
12782f001371SPeter Grehan 	if (to_req->vsr_state != VTSCSI_REQ_STATE_INUSE ||
12792f001371SPeter Grehan 	    (to_req->vsr_flags & VTSCSI_REQ_FLAG_TIMEOUT_SET) == 0)
12802f001371SPeter Grehan 		return;
12812f001371SPeter Grehan 
12822f001371SPeter Grehan 	/*
12832f001371SPeter Grehan 	 * Complete the request queue in case the timedout request is
12842f001371SPeter Grehan 	 * actually just pending.
12852f001371SPeter Grehan 	 */
12862f001371SPeter Grehan 	vtscsi_complete_vq(sc, sc->vtscsi_request_vq);
12872f001371SPeter Grehan 	if (to_req->vsr_state == VTSCSI_REQ_STATE_FREE)
12882f001371SPeter Grehan 		return;
12892f001371SPeter Grehan 
12902f001371SPeter Grehan 	sc->vtscsi_stats.scsi_cmd_timeouts++;
12912f001371SPeter Grehan 	to_req->vsr_state = VTSCSI_REQ_STATE_TIMEDOUT;
12922f001371SPeter Grehan 
12932f001371SPeter Grehan 	if (vtscsi_abort_timedout_scsi_cmd(sc, to_req) == 0)
12942f001371SPeter Grehan 		return;
12952f001371SPeter Grehan 
12962f001371SPeter Grehan 	vtscsi_dprintf(sc, VTSCSI_ERROR, "resetting bus\n");
12972f001371SPeter Grehan 	vtscsi_reset_bus(sc);
12982f001371SPeter Grehan }
12992f001371SPeter Grehan 
13002f001371SPeter Grehan static cam_status
vtscsi_scsi_cmd_cam_status(struct virtio_scsi_cmd_resp * cmd_resp)13012f001371SPeter Grehan vtscsi_scsi_cmd_cam_status(struct virtio_scsi_cmd_resp *cmd_resp)
13022f001371SPeter Grehan {
13032f001371SPeter Grehan 	cam_status status;
13042f001371SPeter Grehan 
13052f001371SPeter Grehan 	switch (cmd_resp->response) {
13062f001371SPeter Grehan 	case VIRTIO_SCSI_S_OK:
13072f001371SPeter Grehan 		status = CAM_REQ_CMP;
13082f001371SPeter Grehan 		break;
13092f001371SPeter Grehan 	case VIRTIO_SCSI_S_OVERRUN:
13102f001371SPeter Grehan 		status = CAM_DATA_RUN_ERR;
13112f001371SPeter Grehan 		break;
13122f001371SPeter Grehan 	case VIRTIO_SCSI_S_ABORTED:
13132f001371SPeter Grehan 		status = CAM_REQ_ABORTED;
13142f001371SPeter Grehan 		break;
13152f001371SPeter Grehan 	case VIRTIO_SCSI_S_BAD_TARGET:
13164d5919ecSBryan Venteicher 		status = CAM_SEL_TIMEOUT;
13172f001371SPeter Grehan 		break;
13182f001371SPeter Grehan 	case VIRTIO_SCSI_S_RESET:
13192f001371SPeter Grehan 		status = CAM_SCSI_BUS_RESET;
13202f001371SPeter Grehan 		break;
13212f001371SPeter Grehan 	case VIRTIO_SCSI_S_BUSY:
13222f001371SPeter Grehan 		status = CAM_SCSI_BUSY;
13232f001371SPeter Grehan 		break;
13242f001371SPeter Grehan 	case VIRTIO_SCSI_S_TRANSPORT_FAILURE:
13252f001371SPeter Grehan 	case VIRTIO_SCSI_S_TARGET_FAILURE:
13262f001371SPeter Grehan 	case VIRTIO_SCSI_S_NEXUS_FAILURE:
13272f001371SPeter Grehan 		status = CAM_SCSI_IT_NEXUS_LOST;
13282f001371SPeter Grehan 		break;
13292f001371SPeter Grehan 	default: /* VIRTIO_SCSI_S_FAILURE */
13302f001371SPeter Grehan 		status = CAM_REQ_CMP_ERR;
13312f001371SPeter Grehan 		break;
13322f001371SPeter Grehan 	}
13332f001371SPeter Grehan 
13342f001371SPeter Grehan 	return (status);
13352f001371SPeter Grehan }
13362f001371SPeter Grehan 
13372f001371SPeter Grehan static cam_status
vtscsi_complete_scsi_cmd_response(struct vtscsi_softc * sc,struct ccb_scsiio * csio,struct virtio_scsi_cmd_resp * cmd_resp)13382f001371SPeter Grehan vtscsi_complete_scsi_cmd_response(struct vtscsi_softc *sc,
13392f001371SPeter Grehan     struct ccb_scsiio *csio, struct virtio_scsi_cmd_resp *cmd_resp)
13402f001371SPeter Grehan {
134115be4953SBryan Venteicher 	uint32_t resp_sense_length;
13422f001371SPeter Grehan 	cam_status status;
13432f001371SPeter Grehan 
13442f001371SPeter Grehan 	csio->scsi_status = cmd_resp->status;
134515be4953SBryan Venteicher 	csio->resid = vtscsi_htog32(sc, cmd_resp->resid);
13462f001371SPeter Grehan 
13472f001371SPeter Grehan 	if (csio->scsi_status == SCSI_STATUS_OK)
13482f001371SPeter Grehan 		status = CAM_REQ_CMP;
13492f001371SPeter Grehan 	else
13502f001371SPeter Grehan 		status = CAM_SCSI_STATUS_ERROR;
13512f001371SPeter Grehan 
135215be4953SBryan Venteicher 	resp_sense_length = vtscsi_htog32(sc, cmd_resp->sense_len);
135315be4953SBryan Venteicher 
135415be4953SBryan Venteicher 	if (resp_sense_length > 0) {
13552f001371SPeter Grehan 		status |= CAM_AUTOSNS_VALID;
13562f001371SPeter Grehan 
135715be4953SBryan Venteicher 		if (resp_sense_length < csio->sense_len)
135815be4953SBryan Venteicher 			csio->sense_resid = csio->sense_len - resp_sense_length;
13592f001371SPeter Grehan 		else
13602f001371SPeter Grehan 			csio->sense_resid = 0;
13612f001371SPeter Grehan 
1362e5355d33SAlexander Motin 		memcpy(&csio->sense_data, cmd_resp->sense,
13632f001371SPeter Grehan 		    csio->sense_len - csio->sense_resid);
13642f001371SPeter Grehan 	}
13652f001371SPeter Grehan 
13662f001371SPeter Grehan 	vtscsi_dprintf(sc, status == CAM_REQ_CMP ? VTSCSI_TRACE : VTSCSI_ERROR,
13672f001371SPeter Grehan 	    "ccb=%p scsi_status=%#x resid=%u sense_resid=%u\n",
13682f001371SPeter Grehan 	    csio, csio->scsi_status, csio->resid, csio->sense_resid);
13692f001371SPeter Grehan 
13702f001371SPeter Grehan 	return (status);
13712f001371SPeter Grehan }
13722f001371SPeter Grehan 
13732f001371SPeter Grehan static void
vtscsi_complete_scsi_cmd(struct vtscsi_softc * sc,struct vtscsi_request * req)13742f001371SPeter Grehan vtscsi_complete_scsi_cmd(struct vtscsi_softc *sc, struct vtscsi_request *req)
13752f001371SPeter Grehan {
13762f001371SPeter Grehan 	struct ccb_hdr *ccbh;
13772f001371SPeter Grehan 	struct ccb_scsiio *csio;
13782f001371SPeter Grehan 	struct virtio_scsi_cmd_resp *cmd_resp;
13792f001371SPeter Grehan 	cam_status status;
13802f001371SPeter Grehan 
13812f001371SPeter Grehan 	csio = &req->vsr_ccb->csio;
13822f001371SPeter Grehan 	ccbh = &csio->ccb_h;
13832f001371SPeter Grehan 	cmd_resp = &req->vsr_cmd_resp;
13842f001371SPeter Grehan 
13852f001371SPeter Grehan 	KASSERT(ccbh->ccbh_vtscsi_req == req,
13862f001371SPeter Grehan 	    ("ccb %p req mismatch %p/%p", ccbh, ccbh->ccbh_vtscsi_req, req));
13872f001371SPeter Grehan 
13882f001371SPeter Grehan 	if (req->vsr_flags & VTSCSI_REQ_FLAG_TIMEOUT_SET)
13892f001371SPeter Grehan 		callout_stop(&req->vsr_callout);
13902f001371SPeter Grehan 
13912f001371SPeter Grehan 	status = vtscsi_scsi_cmd_cam_status(cmd_resp);
13922f001371SPeter Grehan 	if (status == CAM_REQ_ABORTED) {
13932f001371SPeter Grehan 		if (req->vsr_state == VTSCSI_REQ_STATE_TIMEDOUT)
13942f001371SPeter Grehan 			status = CAM_CMD_TIMEOUT;
13952f001371SPeter Grehan 	} else if (status == CAM_REQ_CMP)
13962f001371SPeter Grehan 		status = vtscsi_complete_scsi_cmd_response(sc, csio, cmd_resp);
13972f001371SPeter Grehan 
13982f001371SPeter Grehan 	if ((status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
13992f001371SPeter Grehan 		status |= CAM_DEV_QFRZN;
14002f001371SPeter Grehan 		xpt_freeze_devq(ccbh->path, 1);
14012f001371SPeter Grehan 	}
14022f001371SPeter Grehan 
14032f001371SPeter Grehan 	if (vtscsi_thaw_simq(sc, VTSCSI_REQUEST | VTSCSI_REQUEST_VQ) != 0)
14042f001371SPeter Grehan 		status |= CAM_RELEASE_SIMQ;
14052f001371SPeter Grehan 
14062f001371SPeter Grehan 	vtscsi_dprintf(sc, VTSCSI_TRACE, "req=%p ccb=%p status=%#x\n",
14072f001371SPeter Grehan 	    req, ccbh, status);
14082f001371SPeter Grehan 
14092f001371SPeter Grehan 	ccbh->status = status;
14102f001371SPeter Grehan 	xpt_done(req->vsr_ccb);
14112f001371SPeter Grehan 	vtscsi_enqueue_request(sc, req);
14122f001371SPeter Grehan }
14132f001371SPeter Grehan 
14142f001371SPeter Grehan static void
vtscsi_poll_ctrl_req(struct vtscsi_softc * sc,struct vtscsi_request * req)14152f001371SPeter Grehan vtscsi_poll_ctrl_req(struct vtscsi_softc *sc, struct vtscsi_request *req)
14162f001371SPeter Grehan {
14172f001371SPeter Grehan 
14182f001371SPeter Grehan 	/* XXX We probably shouldn't poll forever. */
14192f001371SPeter Grehan 	req->vsr_flags |= VTSCSI_REQ_FLAG_POLLED;
14202f001371SPeter Grehan 	do
14212f001371SPeter Grehan 		vtscsi_complete_vq(sc, sc->vtscsi_control_vq);
14222f001371SPeter Grehan 	while ((req->vsr_flags & VTSCSI_REQ_FLAG_COMPLETE) == 0);
14232f001371SPeter Grehan 
14242f001371SPeter Grehan 	req->vsr_flags &= ~VTSCSI_REQ_FLAG_POLLED;
14252f001371SPeter Grehan }
14262f001371SPeter Grehan 
14272f001371SPeter Grehan static int
vtscsi_execute_ctrl_req(struct vtscsi_softc * sc,struct vtscsi_request * req,struct sglist * sg,int readable,int writable,int flag)14282f001371SPeter Grehan vtscsi_execute_ctrl_req(struct vtscsi_softc *sc, struct vtscsi_request *req,
14292f001371SPeter Grehan     struct sglist *sg, int readable, int writable, int flag)
14302f001371SPeter Grehan {
14312f001371SPeter Grehan 	struct virtqueue *vq;
14322f001371SPeter Grehan 	int error;
14332f001371SPeter Grehan 
14342f001371SPeter Grehan 	vq = sc->vtscsi_control_vq;
14352f001371SPeter Grehan 
14362f001371SPeter Grehan 	MPASS(flag == VTSCSI_EXECUTE_POLL || req->vsr_complete != NULL);
14372f001371SPeter Grehan 
14382f001371SPeter Grehan 	error = virtqueue_enqueue(vq, req, sg, readable, writable);
14392f001371SPeter Grehan 	if (error) {
14402f001371SPeter Grehan 		/*
14412f001371SPeter Grehan 		 * Return EAGAIN when the virtqueue does not have enough
14422f001371SPeter Grehan 		 * descriptors available.
14432f001371SPeter Grehan 		 */
14442f001371SPeter Grehan 		if (error == ENOSPC || error == EMSGSIZE)
14452f001371SPeter Grehan 			error = EAGAIN;
14462f001371SPeter Grehan 
14472f001371SPeter Grehan 		return (error);
14482f001371SPeter Grehan 	}
14492f001371SPeter Grehan 
14502f001371SPeter Grehan 	virtqueue_notify(vq);
14512f001371SPeter Grehan 	if (flag == VTSCSI_EXECUTE_POLL)
14522f001371SPeter Grehan 		vtscsi_poll_ctrl_req(sc, req);
14532f001371SPeter Grehan 
14542f001371SPeter Grehan 	return (0);
14552f001371SPeter Grehan }
14562f001371SPeter Grehan 
14572f001371SPeter Grehan static void
vtscsi_complete_abort_task_cmd(struct vtscsi_softc * sc,struct vtscsi_request * req)14582f001371SPeter Grehan vtscsi_complete_abort_task_cmd(struct vtscsi_softc *sc,
14592f001371SPeter Grehan     struct vtscsi_request *req)
14602f001371SPeter Grehan {
14612f001371SPeter Grehan 	union ccb *ccb;
14622f001371SPeter Grehan 	struct ccb_hdr *ccbh;
14632f001371SPeter Grehan 	struct virtio_scsi_ctrl_tmf_resp *tmf_resp;
14642f001371SPeter Grehan 
14652f001371SPeter Grehan 	ccb = req->vsr_ccb;
14662f001371SPeter Grehan 	ccbh = &ccb->ccb_h;
14672f001371SPeter Grehan 	tmf_resp = &req->vsr_tmf_resp;
14682f001371SPeter Grehan 
14692f001371SPeter Grehan 	switch (tmf_resp->response) {
14702f001371SPeter Grehan 	case VIRTIO_SCSI_S_FUNCTION_COMPLETE:
14712f001371SPeter Grehan 		ccbh->status = CAM_REQ_CMP;
14722f001371SPeter Grehan 		break;
14732f001371SPeter Grehan 	case VIRTIO_SCSI_S_FUNCTION_REJECTED:
14742f001371SPeter Grehan 		ccbh->status = CAM_UA_ABORT;
14752f001371SPeter Grehan 		break;
14762f001371SPeter Grehan 	default:
14772f001371SPeter Grehan 		ccbh->status = CAM_REQ_CMP_ERR;
14782f001371SPeter Grehan 		break;
14792f001371SPeter Grehan 	}
14802f001371SPeter Grehan 
14812f001371SPeter Grehan 	xpt_done(ccb);
14822f001371SPeter Grehan 	vtscsi_enqueue_request(sc, req);
14832f001371SPeter Grehan }
14842f001371SPeter Grehan 
14852f001371SPeter Grehan static int
vtscsi_execute_abort_task_cmd(struct vtscsi_softc * sc,struct vtscsi_request * req)14862f001371SPeter Grehan vtscsi_execute_abort_task_cmd(struct vtscsi_softc *sc,
14872f001371SPeter Grehan     struct vtscsi_request *req)
14882f001371SPeter Grehan {
14892f001371SPeter Grehan 	struct sglist *sg;
14902f001371SPeter Grehan 	struct ccb_abort *cab;
14912f001371SPeter Grehan 	struct ccb_hdr *ccbh;
14922f001371SPeter Grehan 	struct ccb_hdr *abort_ccbh;
14932f001371SPeter Grehan 	struct vtscsi_request *abort_req;
14942f001371SPeter Grehan 	struct virtio_scsi_ctrl_tmf_req *tmf_req;
14952f001371SPeter Grehan 	struct virtio_scsi_ctrl_tmf_resp *tmf_resp;
14962f001371SPeter Grehan 	int error;
14972f001371SPeter Grehan 
14982f001371SPeter Grehan 	sg = sc->vtscsi_sglist;
14992f001371SPeter Grehan 	cab = &req->vsr_ccb->cab;
15002f001371SPeter Grehan 	ccbh = &cab->ccb_h;
15012f001371SPeter Grehan 	tmf_req = &req->vsr_tmf_req;
15022f001371SPeter Grehan 	tmf_resp = &req->vsr_tmf_resp;
15032f001371SPeter Grehan 
15042f001371SPeter Grehan 	/* CCB header and request that's to be aborted. */
15052f001371SPeter Grehan 	abort_ccbh = &cab->abort_ccb->ccb_h;
15062f001371SPeter Grehan 	abort_req = abort_ccbh->ccbh_vtscsi_req;
15072f001371SPeter Grehan 
15082f001371SPeter Grehan 	if (abort_ccbh->func_code != XPT_SCSI_IO || abort_req == NULL) {
15092f001371SPeter Grehan 		error = EINVAL;
15102f001371SPeter Grehan 		goto fail;
15112f001371SPeter Grehan 	}
15122f001371SPeter Grehan 
15132f001371SPeter Grehan 	/* Only attempt to abort requests that could be in-flight. */
15142f001371SPeter Grehan 	if (abort_req->vsr_state != VTSCSI_REQ_STATE_INUSE) {
15152f001371SPeter Grehan 		error = EALREADY;
15162f001371SPeter Grehan 		goto fail;
15172f001371SPeter Grehan 	}
15182f001371SPeter Grehan 
15192f001371SPeter Grehan 	abort_req->vsr_state = VTSCSI_REQ_STATE_ABORTED;
15202f001371SPeter Grehan 	if (abort_req->vsr_flags & VTSCSI_REQ_FLAG_TIMEOUT_SET)
15212f001371SPeter Grehan 		callout_stop(&abort_req->vsr_callout);
15222f001371SPeter Grehan 
152315be4953SBryan Venteicher 	vtscsi_init_ctrl_tmf_req(sc, ccbh, VIRTIO_SCSI_T_TMF_ABORT_TASK,
15242f001371SPeter Grehan 	    (uintptr_t) abort_ccbh, tmf_req);
15252f001371SPeter Grehan 
15262f001371SPeter Grehan 	sglist_reset(sg);
15272f001371SPeter Grehan 	sglist_append(sg, tmf_req, sizeof(struct virtio_scsi_ctrl_tmf_req));
15282f001371SPeter Grehan 	sglist_append(sg, tmf_resp, sizeof(struct virtio_scsi_ctrl_tmf_resp));
15292f001371SPeter Grehan 
15302f001371SPeter Grehan 	req->vsr_complete = vtscsi_complete_abort_task_cmd;
15312f001371SPeter Grehan 	tmf_resp->response = -1;
15322f001371SPeter Grehan 
15332f001371SPeter Grehan 	error = vtscsi_execute_ctrl_req(sc, req, sg, 1, 1,
15342f001371SPeter Grehan 	    VTSCSI_EXECUTE_ASYNC);
15352f001371SPeter Grehan 
15362f001371SPeter Grehan fail:
15372f001371SPeter Grehan 	vtscsi_dprintf(sc, VTSCSI_TRACE, "error=%d req=%p abort_ccb=%p "
15382f001371SPeter Grehan 	    "abort_req=%p\n", error, req, abort_ccbh, abort_req);
15392f001371SPeter Grehan 
15402f001371SPeter Grehan 	return (error);
15412f001371SPeter Grehan }
15422f001371SPeter Grehan 
15432f001371SPeter Grehan static void
vtscsi_complete_reset_dev_cmd(struct vtscsi_softc * sc,struct vtscsi_request * req)15442f001371SPeter Grehan vtscsi_complete_reset_dev_cmd(struct vtscsi_softc *sc,
15452f001371SPeter Grehan     struct vtscsi_request *req)
15462f001371SPeter Grehan {
15472f001371SPeter Grehan 	union ccb *ccb;
15482f001371SPeter Grehan 	struct ccb_hdr *ccbh;
15492f001371SPeter Grehan 	struct virtio_scsi_ctrl_tmf_resp *tmf_resp;
15502f001371SPeter Grehan 
15512f001371SPeter Grehan 	ccb = req->vsr_ccb;
15522f001371SPeter Grehan 	ccbh = &ccb->ccb_h;
15532f001371SPeter Grehan 	tmf_resp = &req->vsr_tmf_resp;
15542f001371SPeter Grehan 
15552f001371SPeter Grehan 	vtscsi_dprintf(sc, VTSCSI_TRACE, "req=%p ccb=%p response=%d\n",
15562f001371SPeter Grehan 	    req, ccb, tmf_resp->response);
15572f001371SPeter Grehan 
15582f001371SPeter Grehan 	if (tmf_resp->response == VIRTIO_SCSI_S_FUNCTION_COMPLETE) {
15592f001371SPeter Grehan 		ccbh->status = CAM_REQ_CMP;
15602f001371SPeter Grehan 		vtscsi_announce(sc, AC_SENT_BDR, ccbh->target_id,
15612f001371SPeter Grehan 		    ccbh->target_lun);
15622f001371SPeter Grehan 	} else
15632f001371SPeter Grehan 		ccbh->status = CAM_REQ_CMP_ERR;
15642f001371SPeter Grehan 
15652f001371SPeter Grehan 	xpt_done(ccb);
15662f001371SPeter Grehan 	vtscsi_enqueue_request(sc, req);
15672f001371SPeter Grehan }
15682f001371SPeter Grehan 
15692f001371SPeter Grehan static int
vtscsi_execute_reset_dev_cmd(struct vtscsi_softc * sc,struct vtscsi_request * req)15702f001371SPeter Grehan vtscsi_execute_reset_dev_cmd(struct vtscsi_softc *sc,
15712f001371SPeter Grehan     struct vtscsi_request *req)
15722f001371SPeter Grehan {
15732f001371SPeter Grehan 	struct sglist *sg;
15742f001371SPeter Grehan 	struct ccb_resetdev *crd;
15752f001371SPeter Grehan 	struct ccb_hdr *ccbh;
15762f001371SPeter Grehan 	struct virtio_scsi_ctrl_tmf_req *tmf_req;
15772f001371SPeter Grehan 	struct virtio_scsi_ctrl_tmf_resp *tmf_resp;
15782f001371SPeter Grehan 	uint32_t subtype;
15792f001371SPeter Grehan 	int error;
15802f001371SPeter Grehan 
15812f001371SPeter Grehan 	sg = sc->vtscsi_sglist;
15822f001371SPeter Grehan 	crd = &req->vsr_ccb->crd;
15832f001371SPeter Grehan 	ccbh = &crd->ccb_h;
15842f001371SPeter Grehan 	tmf_req = &req->vsr_tmf_req;
15852f001371SPeter Grehan 	tmf_resp = &req->vsr_tmf_resp;
15862f001371SPeter Grehan 
15872f001371SPeter Grehan 	if (ccbh->target_lun == CAM_LUN_WILDCARD)
15882f001371SPeter Grehan 		subtype = VIRTIO_SCSI_T_TMF_I_T_NEXUS_RESET;
15892f001371SPeter Grehan 	else
15902f001371SPeter Grehan 		subtype = VIRTIO_SCSI_T_TMF_LOGICAL_UNIT_RESET;
15912f001371SPeter Grehan 
159215be4953SBryan Venteicher 	vtscsi_init_ctrl_tmf_req(sc, ccbh, subtype, 0, tmf_req);
15932f001371SPeter Grehan 
15942f001371SPeter Grehan 	sglist_reset(sg);
15952f001371SPeter Grehan 	sglist_append(sg, tmf_req, sizeof(struct virtio_scsi_ctrl_tmf_req));
15962f001371SPeter Grehan 	sglist_append(sg, tmf_resp, sizeof(struct virtio_scsi_ctrl_tmf_resp));
15972f001371SPeter Grehan 
15982f001371SPeter Grehan 	req->vsr_complete = vtscsi_complete_reset_dev_cmd;
15992f001371SPeter Grehan 	tmf_resp->response = -1;
16002f001371SPeter Grehan 
16012f001371SPeter Grehan 	error = vtscsi_execute_ctrl_req(sc, req, sg, 1, 1,
16022f001371SPeter Grehan 	    VTSCSI_EXECUTE_ASYNC);
16032f001371SPeter Grehan 
16042f001371SPeter Grehan 	vtscsi_dprintf(sc, VTSCSI_TRACE, "error=%d req=%p ccb=%p\n",
16052f001371SPeter Grehan 	    error, req, ccbh);
16062f001371SPeter Grehan 
16072f001371SPeter Grehan 	return (error);
16082f001371SPeter Grehan }
16092f001371SPeter Grehan 
16102f001371SPeter Grehan static void
vtscsi_get_request_lun(uint8_t lun[],target_id_t * target_id,lun_id_t * lun_id)16112f001371SPeter Grehan vtscsi_get_request_lun(uint8_t lun[], target_id_t *target_id, lun_id_t *lun_id)
16122f001371SPeter Grehan {
16132f001371SPeter Grehan 
16142f001371SPeter Grehan 	*target_id = lun[1];
16152f001371SPeter Grehan 	*lun_id = (lun[2] << 8) | lun[3];
16162f001371SPeter Grehan }
16172f001371SPeter Grehan 
16182f001371SPeter Grehan static void
vtscsi_set_request_lun(struct ccb_hdr * ccbh,uint8_t lun[])16192f001371SPeter Grehan vtscsi_set_request_lun(struct ccb_hdr *ccbh, uint8_t lun[])
16202f001371SPeter Grehan {
16212f001371SPeter Grehan 
16222f001371SPeter Grehan 	lun[0] = 1;
16232f001371SPeter Grehan 	lun[1] = ccbh->target_id;
16242f001371SPeter Grehan 	lun[2] = 0x40 | ((ccbh->target_lun >> 8) & 0x3F);
1625bf51187bSBryan Venteicher 	lun[3] = ccbh->target_lun & 0xFF;
16262f001371SPeter Grehan }
16272f001371SPeter Grehan 
16282f001371SPeter Grehan static void
vtscsi_init_scsi_cmd_req(struct vtscsi_softc * sc,struct ccb_scsiio * csio,struct virtio_scsi_cmd_req * cmd_req)162915be4953SBryan Venteicher vtscsi_init_scsi_cmd_req(struct vtscsi_softc *sc, struct ccb_scsiio *csio,
16302f001371SPeter Grehan     struct virtio_scsi_cmd_req *cmd_req)
16312f001371SPeter Grehan {
16322f001371SPeter Grehan 	uint8_t attr;
16332f001371SPeter Grehan 
16342f001371SPeter Grehan 	switch (csio->tag_action) {
16352f001371SPeter Grehan 	case MSG_HEAD_OF_Q_TAG:
16362f001371SPeter Grehan 		attr = VIRTIO_SCSI_S_HEAD;
16372f001371SPeter Grehan 		break;
16382f001371SPeter Grehan 	case MSG_ORDERED_Q_TAG:
16392f001371SPeter Grehan 		attr = VIRTIO_SCSI_S_ORDERED;
16402f001371SPeter Grehan 		break;
16412f001371SPeter Grehan 	case MSG_ACA_TASK:
16422f001371SPeter Grehan 		attr = VIRTIO_SCSI_S_ACA;
16432f001371SPeter Grehan 		break;
16442f001371SPeter Grehan 	default: /* MSG_SIMPLE_Q_TAG */
16452f001371SPeter Grehan 		attr = VIRTIO_SCSI_S_SIMPLE;
16462f001371SPeter Grehan 		break;
16472f001371SPeter Grehan 	}
16482f001371SPeter Grehan 
16492f001371SPeter Grehan 	vtscsi_set_request_lun(&csio->ccb_h, cmd_req->lun);
165015be4953SBryan Venteicher 	cmd_req->tag = vtscsi_gtoh64(sc, (uintptr_t) csio);
16512f001371SPeter Grehan 	cmd_req->task_attr = attr;
16522f001371SPeter Grehan 
16532f001371SPeter Grehan 	memcpy(cmd_req->cdb,
16542f001371SPeter Grehan 	    csio->ccb_h.flags & CAM_CDB_POINTER ?
16552f001371SPeter Grehan 	        csio->cdb_io.cdb_ptr : csio->cdb_io.cdb_bytes,
16562f001371SPeter Grehan 	    csio->cdb_len);
16572f001371SPeter Grehan }
16582f001371SPeter Grehan 
16592f001371SPeter Grehan static void
vtscsi_init_ctrl_tmf_req(struct vtscsi_softc * sc,struct ccb_hdr * ccbh,uint32_t subtype,uintptr_t tag,struct virtio_scsi_ctrl_tmf_req * tmf_req)166015be4953SBryan Venteicher vtscsi_init_ctrl_tmf_req(struct vtscsi_softc *sc, struct ccb_hdr *ccbh,
166115be4953SBryan Venteicher     uint32_t subtype, uintptr_t tag, struct virtio_scsi_ctrl_tmf_req *tmf_req)
16622f001371SPeter Grehan {
16632f001371SPeter Grehan 
16642f001371SPeter Grehan 	vtscsi_set_request_lun(ccbh, tmf_req->lun);
16652f001371SPeter Grehan 
166615be4953SBryan Venteicher 	tmf_req->type = vtscsi_gtoh32(sc, VIRTIO_SCSI_T_TMF);
166715be4953SBryan Venteicher 	tmf_req->subtype = vtscsi_gtoh32(sc, subtype);
166815be4953SBryan Venteicher 	tmf_req->tag = vtscsi_gtoh64(sc, tag);
16692f001371SPeter Grehan }
16702f001371SPeter Grehan 
16712f001371SPeter Grehan static void
vtscsi_freeze_simq(struct vtscsi_softc * sc,int reason)16722f001371SPeter Grehan vtscsi_freeze_simq(struct vtscsi_softc *sc, int reason)
16732f001371SPeter Grehan {
16742f001371SPeter Grehan 	int frozen;
16752f001371SPeter Grehan 
16762f001371SPeter Grehan 	frozen = sc->vtscsi_frozen;
16772f001371SPeter Grehan 
16782f001371SPeter Grehan 	if (reason & VTSCSI_REQUEST &&
16792f001371SPeter Grehan 	    (sc->vtscsi_frozen & VTSCSI_FROZEN_NO_REQUESTS) == 0)
16802f001371SPeter Grehan 		sc->vtscsi_frozen |= VTSCSI_FROZEN_NO_REQUESTS;
16812f001371SPeter Grehan 
16822f001371SPeter Grehan 	if (reason & VTSCSI_REQUEST_VQ &&
16832f001371SPeter Grehan 	    (sc->vtscsi_frozen & VTSCSI_FROZEN_REQUEST_VQ_FULL) == 0)
16842f001371SPeter Grehan 		sc->vtscsi_frozen |= VTSCSI_FROZEN_REQUEST_VQ_FULL;
16852f001371SPeter Grehan 
16862f001371SPeter Grehan 	/* Freeze the SIMQ if transitioned to frozen. */
16872f001371SPeter Grehan 	if (frozen == 0 && sc->vtscsi_frozen != 0) {
16882f001371SPeter Grehan 		vtscsi_dprintf(sc, VTSCSI_INFO, "SIMQ frozen\n");
16892f001371SPeter Grehan 		xpt_freeze_simq(sc->vtscsi_sim, 1);
16902f001371SPeter Grehan 	}
16912f001371SPeter Grehan }
16922f001371SPeter Grehan 
16932f001371SPeter Grehan static int
vtscsi_thaw_simq(struct vtscsi_softc * sc,int reason)16942f001371SPeter Grehan vtscsi_thaw_simq(struct vtscsi_softc *sc, int reason)
16952f001371SPeter Grehan {
16962f001371SPeter Grehan 	int thawed;
16972f001371SPeter Grehan 
16982f001371SPeter Grehan 	if (sc->vtscsi_frozen == 0 || reason == 0)
16992f001371SPeter Grehan 		return (0);
17002f001371SPeter Grehan 
17012f001371SPeter Grehan 	if (reason & VTSCSI_REQUEST &&
17022f001371SPeter Grehan 	    sc->vtscsi_frozen & VTSCSI_FROZEN_NO_REQUESTS)
17032f001371SPeter Grehan 		sc->vtscsi_frozen &= ~VTSCSI_FROZEN_NO_REQUESTS;
17042f001371SPeter Grehan 
17052f001371SPeter Grehan 	if (reason & VTSCSI_REQUEST_VQ &&
17062f001371SPeter Grehan 	    sc->vtscsi_frozen & VTSCSI_FROZEN_REQUEST_VQ_FULL)
17072f001371SPeter Grehan 		sc->vtscsi_frozen &= ~VTSCSI_FROZEN_REQUEST_VQ_FULL;
17082f001371SPeter Grehan 
17092f001371SPeter Grehan 	thawed = sc->vtscsi_frozen == 0;
17102f001371SPeter Grehan 	if (thawed != 0)
17112f001371SPeter Grehan 		vtscsi_dprintf(sc, VTSCSI_INFO, "SIMQ thawed\n");
17122f001371SPeter Grehan 
17132f001371SPeter Grehan 	return (thawed);
17142f001371SPeter Grehan }
17152f001371SPeter Grehan 
17162f001371SPeter Grehan static void
vtscsi_announce(struct vtscsi_softc * sc,uint32_t ac_code,target_id_t target_id,lun_id_t lun_id)17172f001371SPeter Grehan vtscsi_announce(struct vtscsi_softc *sc, uint32_t ac_code,
17182f001371SPeter Grehan     target_id_t target_id, lun_id_t lun_id)
17192f001371SPeter Grehan {
17202f001371SPeter Grehan 	struct cam_path *path;
17212f001371SPeter Grehan 
17222f001371SPeter Grehan 	/* Use the wildcard path from our softc for bus announcements. */
17232f001371SPeter Grehan 	if (target_id == CAM_TARGET_WILDCARD && lun_id == CAM_LUN_WILDCARD) {
17242f001371SPeter Grehan 		xpt_async(ac_code, sc->vtscsi_path, NULL);
17252f001371SPeter Grehan 		return;
17262f001371SPeter Grehan 	}
17272f001371SPeter Grehan 
17282f001371SPeter Grehan 	if (xpt_create_path(&path, NULL, cam_sim_path(sc->vtscsi_sim),
17292f001371SPeter Grehan 	    target_id, lun_id) != CAM_REQ_CMP) {
17302f001371SPeter Grehan 		vtscsi_dprintf(sc, VTSCSI_ERROR, "cannot create path\n");
17312f001371SPeter Grehan 		return;
17322f001371SPeter Grehan 	}
17332f001371SPeter Grehan 
17342f001371SPeter Grehan 	xpt_async(ac_code, path, NULL);
17352f001371SPeter Grehan 	xpt_free_path(path);
17362f001371SPeter Grehan }
17372f001371SPeter Grehan 
17382f001371SPeter Grehan static void
vtscsi_execute_rescan(struct vtscsi_softc * sc,target_id_t target_id,lun_id_t lun_id)17392f001371SPeter Grehan vtscsi_execute_rescan(struct vtscsi_softc *sc, target_id_t target_id,
17402f001371SPeter Grehan     lun_id_t lun_id)
17412f001371SPeter Grehan {
17422f001371SPeter Grehan 	union ccb *ccb;
17432f001371SPeter Grehan 	cam_status status;
17442f001371SPeter Grehan 
17452f001371SPeter Grehan 	ccb = xpt_alloc_ccb_nowait();
17462f001371SPeter Grehan 	if (ccb == NULL) {
17472f001371SPeter Grehan 		vtscsi_dprintf(sc, VTSCSI_ERROR, "cannot allocate CCB\n");
17482f001371SPeter Grehan 		return;
17492f001371SPeter Grehan 	}
17502f001371SPeter Grehan 
1751e5dfa058SAlexander Motin 	status = xpt_create_path(&ccb->ccb_h.path, NULL,
17522f001371SPeter Grehan 	    cam_sim_path(sc->vtscsi_sim), target_id, lun_id);
17532f001371SPeter Grehan 	if (status != CAM_REQ_CMP) {
17542f001371SPeter Grehan 		xpt_free_ccb(ccb);
17552f001371SPeter Grehan 		return;
17562f001371SPeter Grehan 	}
17572f001371SPeter Grehan 
17582f001371SPeter Grehan 	xpt_rescan(ccb);
17592f001371SPeter Grehan }
17602f001371SPeter Grehan 
17612f001371SPeter Grehan static void
vtscsi_execute_rescan_bus(struct vtscsi_softc * sc)17622f001371SPeter Grehan vtscsi_execute_rescan_bus(struct vtscsi_softc *sc)
17632f001371SPeter Grehan {
17642f001371SPeter Grehan 
17652f001371SPeter Grehan 	vtscsi_execute_rescan(sc, CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD);
17662f001371SPeter Grehan }
17672f001371SPeter Grehan 
17682f001371SPeter Grehan static void
vtscsi_transport_reset_event(struct vtscsi_softc * sc,struct virtio_scsi_event * event)17692f001371SPeter Grehan vtscsi_transport_reset_event(struct vtscsi_softc *sc,
17702f001371SPeter Grehan     struct virtio_scsi_event *event)
17712f001371SPeter Grehan {
17722f001371SPeter Grehan 	target_id_t target_id;
17732f001371SPeter Grehan 	lun_id_t lun_id;
17742f001371SPeter Grehan 
17752f001371SPeter Grehan 	vtscsi_get_request_lun(event->lun, &target_id, &lun_id);
17762f001371SPeter Grehan 
17772f001371SPeter Grehan 	switch (event->reason) {
17782f001371SPeter Grehan 	case VIRTIO_SCSI_EVT_RESET_RESCAN:
17792f001371SPeter Grehan 	case VIRTIO_SCSI_EVT_RESET_REMOVED:
17802f001371SPeter Grehan 		vtscsi_execute_rescan(sc, target_id, lun_id);
17812f001371SPeter Grehan 		break;
17822f001371SPeter Grehan 	default:
17832f001371SPeter Grehan 		device_printf(sc->vtscsi_dev,
17842f001371SPeter Grehan 		    "unhandled transport event reason: %d\n", event->reason);
17852f001371SPeter Grehan 		break;
17862f001371SPeter Grehan 	}
17872f001371SPeter Grehan }
17882f001371SPeter Grehan 
17892f001371SPeter Grehan static void
vtscsi_handle_event(struct vtscsi_softc * sc,struct virtio_scsi_event * event)17902f001371SPeter Grehan vtscsi_handle_event(struct vtscsi_softc *sc, struct virtio_scsi_event *event)
17912f001371SPeter Grehan {
1792b25ddb78SJohn Baldwin 	int error __diagused;
17932f001371SPeter Grehan 
17942f001371SPeter Grehan 	if ((event->event & VIRTIO_SCSI_T_EVENTS_MISSED) == 0) {
17952f001371SPeter Grehan 		switch (event->event) {
17962f001371SPeter Grehan 		case VIRTIO_SCSI_T_TRANSPORT_RESET:
17972f001371SPeter Grehan 			vtscsi_transport_reset_event(sc, event);
17982f001371SPeter Grehan 			break;
17992f001371SPeter Grehan 		default:
18002f001371SPeter Grehan 			device_printf(sc->vtscsi_dev,
18012f001371SPeter Grehan 			    "unhandled event: %d\n", event->event);
18022f001371SPeter Grehan 			break;
18032f001371SPeter Grehan 		}
18042f001371SPeter Grehan 	} else
18052f001371SPeter Grehan 		vtscsi_execute_rescan_bus(sc);
18062f001371SPeter Grehan 
18072f001371SPeter Grehan 	/*
18082f001371SPeter Grehan 	 * This should always be successful since the buffer
18092f001371SPeter Grehan 	 * was just dequeued.
18102f001371SPeter Grehan 	 */
18112f001371SPeter Grehan 	error = vtscsi_enqueue_event_buf(sc, event);
18122f001371SPeter Grehan 	KASSERT(error == 0,
18132f001371SPeter Grehan 	    ("cannot requeue event buffer: %d", error));
18142f001371SPeter Grehan }
18152f001371SPeter Grehan 
18162f001371SPeter Grehan static int
vtscsi_enqueue_event_buf(struct vtscsi_softc * sc,struct virtio_scsi_event * event)18172f001371SPeter Grehan vtscsi_enqueue_event_buf(struct vtscsi_softc *sc,
18182f001371SPeter Grehan     struct virtio_scsi_event *event)
18192f001371SPeter Grehan {
18202f001371SPeter Grehan 	struct sglist *sg;
18212f001371SPeter Grehan 	struct virtqueue *vq;
18222f001371SPeter Grehan 	int size, error;
18232f001371SPeter Grehan 
18242f001371SPeter Grehan 	sg = sc->vtscsi_sglist;
18252f001371SPeter Grehan 	vq = sc->vtscsi_event_vq;
18262f001371SPeter Grehan 	size = sc->vtscsi_event_buf_size;
18272f001371SPeter Grehan 
18282f001371SPeter Grehan 	bzero(event, size);
18292f001371SPeter Grehan 
18302f001371SPeter Grehan 	sglist_reset(sg);
18312f001371SPeter Grehan 	error = sglist_append(sg, event, size);
18322f001371SPeter Grehan 	if (error)
18332f001371SPeter Grehan 		return (error);
18342f001371SPeter Grehan 
18352f001371SPeter Grehan 	error = virtqueue_enqueue(vq, event, sg, 0, sg->sg_nseg);
18362f001371SPeter Grehan 	if (error)
18372f001371SPeter Grehan 		return (error);
18382f001371SPeter Grehan 
18392f001371SPeter Grehan 	virtqueue_notify(vq);
18402f001371SPeter Grehan 
18412f001371SPeter Grehan 	return (0);
18422f001371SPeter Grehan }
18432f001371SPeter Grehan 
18442f001371SPeter Grehan static int
vtscsi_init_event_vq(struct vtscsi_softc * sc)18452f001371SPeter Grehan vtscsi_init_event_vq(struct vtscsi_softc *sc)
18462f001371SPeter Grehan {
18472f001371SPeter Grehan 	struct virtio_scsi_event *event;
18482f001371SPeter Grehan 	int i, size, error;
18492f001371SPeter Grehan 
18502f001371SPeter Grehan 	/*
18512f001371SPeter Grehan 	 * The first release of QEMU with VirtIO SCSI support would crash
18522f001371SPeter Grehan 	 * when attempting to notify the event virtqueue. This was fixed
18532f001371SPeter Grehan 	 * when hotplug support was added.
18542f001371SPeter Grehan 	 */
18552f001371SPeter Grehan 	if (sc->vtscsi_flags & VTSCSI_FLAG_HOTPLUG)
18562f001371SPeter Grehan 		size = sc->vtscsi_event_buf_size;
18572f001371SPeter Grehan 	else
18582f001371SPeter Grehan 		size = 0;
18592f001371SPeter Grehan 
18602f001371SPeter Grehan 	if (size < sizeof(struct virtio_scsi_event))
18612f001371SPeter Grehan 		return (0);
18622f001371SPeter Grehan 
18632f001371SPeter Grehan 	for (i = 0; i < VTSCSI_NUM_EVENT_BUFS; i++) {
18642f001371SPeter Grehan 		event = &sc->vtscsi_event_bufs[i];
18652f001371SPeter Grehan 
18662f001371SPeter Grehan 		error = vtscsi_enqueue_event_buf(sc, event);
18672f001371SPeter Grehan 		if (error)
18682f001371SPeter Grehan 			break;
18692f001371SPeter Grehan 	}
18702f001371SPeter Grehan 
18712f001371SPeter Grehan 	/*
18722f001371SPeter Grehan 	 * Even just one buffer is enough. Missed events are
18732f001371SPeter Grehan 	 * denoted with the VIRTIO_SCSI_T_EVENTS_MISSED flag.
18742f001371SPeter Grehan 	 */
18752f001371SPeter Grehan 	if (i > 0)
18762f001371SPeter Grehan 		error = 0;
18772f001371SPeter Grehan 
18782f001371SPeter Grehan 	return (error);
18792f001371SPeter Grehan }
18802f001371SPeter Grehan 
18812f001371SPeter Grehan static void
vtscsi_reinit_event_vq(struct vtscsi_softc * sc)18822f001371SPeter Grehan vtscsi_reinit_event_vq(struct vtscsi_softc *sc)
18832f001371SPeter Grehan {
18842f001371SPeter Grehan 	struct virtio_scsi_event *event;
18852f001371SPeter Grehan 	int i, error;
18862f001371SPeter Grehan 
18872f001371SPeter Grehan 	if ((sc->vtscsi_flags & VTSCSI_FLAG_HOTPLUG) == 0 ||
18882f001371SPeter Grehan 	    sc->vtscsi_event_buf_size < sizeof(struct virtio_scsi_event))
18892f001371SPeter Grehan 		return;
18902f001371SPeter Grehan 
18912f001371SPeter Grehan 	for (i = 0; i < VTSCSI_NUM_EVENT_BUFS; i++) {
18922f001371SPeter Grehan 		event = &sc->vtscsi_event_bufs[i];
18932f001371SPeter Grehan 
18942f001371SPeter Grehan 		error = vtscsi_enqueue_event_buf(sc, event);
18952f001371SPeter Grehan 		if (error)
18962f001371SPeter Grehan 			break;
18972f001371SPeter Grehan 	}
18982f001371SPeter Grehan 
18992f001371SPeter Grehan 	KASSERT(i > 0, ("cannot reinit event vq: %d", error));
19002f001371SPeter Grehan }
19012f001371SPeter Grehan 
19022f001371SPeter Grehan static void
vtscsi_drain_event_vq(struct vtscsi_softc * sc)19032f001371SPeter Grehan vtscsi_drain_event_vq(struct vtscsi_softc *sc)
19042f001371SPeter Grehan {
19052f001371SPeter Grehan 	struct virtqueue *vq;
19062f001371SPeter Grehan 	int last;
19072f001371SPeter Grehan 
19082f001371SPeter Grehan 	vq = sc->vtscsi_event_vq;
19092f001371SPeter Grehan 	last = 0;
19102f001371SPeter Grehan 
19112f001371SPeter Grehan 	while (virtqueue_drain(vq, &last) != NULL)
19122f001371SPeter Grehan 		;
19132f001371SPeter Grehan 
19142f001371SPeter Grehan 	KASSERT(virtqueue_empty(vq), ("eventvq not empty"));
19152f001371SPeter Grehan }
19162f001371SPeter Grehan 
19172f001371SPeter Grehan static void
vtscsi_complete_vqs_locked(struct vtscsi_softc * sc)19182f001371SPeter Grehan vtscsi_complete_vqs_locked(struct vtscsi_softc *sc)
19192f001371SPeter Grehan {
19202f001371SPeter Grehan 
19212f001371SPeter Grehan 	VTSCSI_LOCK_OWNED(sc);
19222f001371SPeter Grehan 
19232f001371SPeter Grehan 	if (sc->vtscsi_request_vq != NULL)
19242f001371SPeter Grehan 		vtscsi_complete_vq(sc, sc->vtscsi_request_vq);
19252f001371SPeter Grehan 	if (sc->vtscsi_control_vq != NULL)
19262f001371SPeter Grehan 		vtscsi_complete_vq(sc, sc->vtscsi_control_vq);
19272f001371SPeter Grehan }
19282f001371SPeter Grehan 
19292f001371SPeter Grehan static void
vtscsi_complete_vqs(struct vtscsi_softc * sc)19302f001371SPeter Grehan vtscsi_complete_vqs(struct vtscsi_softc *sc)
19312f001371SPeter Grehan {
19322f001371SPeter Grehan 
19332f001371SPeter Grehan 	VTSCSI_LOCK(sc);
19342f001371SPeter Grehan 	vtscsi_complete_vqs_locked(sc);
19352f001371SPeter Grehan 	VTSCSI_UNLOCK(sc);
19362f001371SPeter Grehan }
19372f001371SPeter Grehan 
19382f001371SPeter Grehan static void
vtscsi_cancel_request(struct vtscsi_softc * sc,struct vtscsi_request * req)19392f001371SPeter Grehan vtscsi_cancel_request(struct vtscsi_softc *sc, struct vtscsi_request *req)
19402f001371SPeter Grehan {
19412f001371SPeter Grehan 	union ccb *ccb;
19422f001371SPeter Grehan 	int detach;
19432f001371SPeter Grehan 
19442f001371SPeter Grehan 	ccb = req->vsr_ccb;
19452f001371SPeter Grehan 
19462f001371SPeter Grehan 	vtscsi_dprintf(sc, VTSCSI_TRACE, "req=%p ccb=%p\n", req, ccb);
19472f001371SPeter Grehan 
19482f001371SPeter Grehan 	/*
19492f001371SPeter Grehan 	 * The callout must be drained when detaching since the request is
19502f001371SPeter Grehan 	 * about to be freed. The VTSCSI_MTX must not be held for this in
19512f001371SPeter Grehan 	 * case the callout is pending because there is a deadlock potential.
19522f001371SPeter Grehan 	 * Otherwise, the virtqueue is being drained because of a bus reset
19532f001371SPeter Grehan 	 * so we only need to attempt to stop the callouts.
19542f001371SPeter Grehan 	 */
19552f001371SPeter Grehan 	detach = (sc->vtscsi_flags & VTSCSI_FLAG_DETACH) != 0;
19562f001371SPeter Grehan 	if (detach != 0)
19572f001371SPeter Grehan 		VTSCSI_LOCK_NOTOWNED(sc);
19582f001371SPeter Grehan 	else
19592f001371SPeter Grehan 		VTSCSI_LOCK_OWNED(sc);
19602f001371SPeter Grehan 
19612f001371SPeter Grehan 	if (req->vsr_flags & VTSCSI_REQ_FLAG_TIMEOUT_SET) {
19622f001371SPeter Grehan 		if (detach != 0)
19632f001371SPeter Grehan 			callout_drain(&req->vsr_callout);
19642f001371SPeter Grehan 		else
19652f001371SPeter Grehan 			callout_stop(&req->vsr_callout);
19662f001371SPeter Grehan 	}
19672f001371SPeter Grehan 
19682f001371SPeter Grehan 	if (ccb != NULL) {
19692f001371SPeter Grehan 		if (detach != 0) {
19702f001371SPeter Grehan 			VTSCSI_LOCK(sc);
19712f001371SPeter Grehan 			ccb->ccb_h.status = CAM_NO_HBA;
19722f001371SPeter Grehan 		} else
19732f001371SPeter Grehan 			ccb->ccb_h.status = CAM_REQUEUE_REQ;
19742f001371SPeter Grehan 		xpt_done(ccb);
19752f001371SPeter Grehan 		if (detach != 0)
19762f001371SPeter Grehan 			VTSCSI_UNLOCK(sc);
19772f001371SPeter Grehan 	}
19782f001371SPeter Grehan 
19792f001371SPeter Grehan 	vtscsi_enqueue_request(sc, req);
19802f001371SPeter Grehan }
19812f001371SPeter Grehan 
19822f001371SPeter Grehan static void
vtscsi_drain_vq(struct vtscsi_softc * sc,struct virtqueue * vq)19832f001371SPeter Grehan vtscsi_drain_vq(struct vtscsi_softc *sc, struct virtqueue *vq)
19842f001371SPeter Grehan {
19852f001371SPeter Grehan 	struct vtscsi_request *req;
19862f001371SPeter Grehan 	int last;
19872f001371SPeter Grehan 
19882f001371SPeter Grehan 	last = 0;
19892f001371SPeter Grehan 
19902f001371SPeter Grehan 	vtscsi_dprintf(sc, VTSCSI_TRACE, "vq=%p\n", vq);
19912f001371SPeter Grehan 
19922f001371SPeter Grehan 	while ((req = virtqueue_drain(vq, &last)) != NULL)
19932f001371SPeter Grehan 		vtscsi_cancel_request(sc, req);
19942f001371SPeter Grehan 
19952f001371SPeter Grehan 	KASSERT(virtqueue_empty(vq), ("virtqueue not empty"));
19962f001371SPeter Grehan }
19972f001371SPeter Grehan 
19982f001371SPeter Grehan static void
vtscsi_drain_vqs(struct vtscsi_softc * sc)19992f001371SPeter Grehan vtscsi_drain_vqs(struct vtscsi_softc *sc)
20002f001371SPeter Grehan {
20012f001371SPeter Grehan 
20022f001371SPeter Grehan 	if (sc->vtscsi_control_vq != NULL)
20032f001371SPeter Grehan 		vtscsi_drain_vq(sc, sc->vtscsi_control_vq);
20042f001371SPeter Grehan 	if (sc->vtscsi_request_vq != NULL)
20052f001371SPeter Grehan 		vtscsi_drain_vq(sc, sc->vtscsi_request_vq);
20062f001371SPeter Grehan 	if (sc->vtscsi_event_vq != NULL)
20072f001371SPeter Grehan 		vtscsi_drain_event_vq(sc);
20082f001371SPeter Grehan }
20092f001371SPeter Grehan 
20102f001371SPeter Grehan static void
vtscsi_stop(struct vtscsi_softc * sc)20112f001371SPeter Grehan vtscsi_stop(struct vtscsi_softc *sc)
20122f001371SPeter Grehan {
20132f001371SPeter Grehan 
20142f001371SPeter Grehan 	vtscsi_disable_vqs_intr(sc);
20152f001371SPeter Grehan 	virtio_stop(sc->vtscsi_dev);
20162f001371SPeter Grehan }
20172f001371SPeter Grehan 
20182f001371SPeter Grehan static int
vtscsi_reset_bus(struct vtscsi_softc * sc)20192f001371SPeter Grehan vtscsi_reset_bus(struct vtscsi_softc *sc)
20202f001371SPeter Grehan {
20212f001371SPeter Grehan 	int error;
20222f001371SPeter Grehan 
20232f001371SPeter Grehan 	VTSCSI_LOCK_OWNED(sc);
20242f001371SPeter Grehan 
20252f001371SPeter Grehan 	if (vtscsi_bus_reset_disable != 0) {
20262f001371SPeter Grehan 		device_printf(sc->vtscsi_dev, "bus reset disabled\n");
20272f001371SPeter Grehan 		return (0);
20282f001371SPeter Grehan 	}
20292f001371SPeter Grehan 
20302f001371SPeter Grehan 	sc->vtscsi_flags |= VTSCSI_FLAG_RESET;
20312f001371SPeter Grehan 
20322f001371SPeter Grehan 	/*
20332f001371SPeter Grehan 	 * vtscsi_stop() will cause the in-flight requests to be canceled.
20342f001371SPeter Grehan 	 * Those requests are then completed here so CAM will retry them
20352f001371SPeter Grehan 	 * after the reset is complete.
20362f001371SPeter Grehan 	 */
20372f001371SPeter Grehan 	vtscsi_stop(sc);
20382f001371SPeter Grehan 	vtscsi_complete_vqs_locked(sc);
20392f001371SPeter Grehan 
20402f001371SPeter Grehan 	/* Rid the virtqueues of any remaining requests. */
20412f001371SPeter Grehan 	vtscsi_drain_vqs(sc);
20422f001371SPeter Grehan 
20432f001371SPeter Grehan 	/*
20442f001371SPeter Grehan 	 * Any resource shortage that froze the SIMQ cannot persist across
20452f001371SPeter Grehan 	 * a bus reset so ensure it gets thawed here.
20462f001371SPeter Grehan 	 */
20472f001371SPeter Grehan 	if (vtscsi_thaw_simq(sc, VTSCSI_REQUEST | VTSCSI_REQUEST_VQ) != 0)
20482f001371SPeter Grehan 		xpt_release_simq(sc->vtscsi_sim, 0);
20492f001371SPeter Grehan 
20502f001371SPeter Grehan 	error = vtscsi_reinit(sc);
20512f001371SPeter Grehan 	if (error) {
20522f001371SPeter Grehan 		device_printf(sc->vtscsi_dev,
20532f001371SPeter Grehan 		    "reinitialization failed, stopping device...\n");
20542f001371SPeter Grehan 		vtscsi_stop(sc);
20552f001371SPeter Grehan 	} else
20562f001371SPeter Grehan 		vtscsi_announce(sc, AC_BUS_RESET, CAM_TARGET_WILDCARD,
20572f001371SPeter Grehan 		    CAM_LUN_WILDCARD);
20582f001371SPeter Grehan 
20592f001371SPeter Grehan 	sc->vtscsi_flags &= ~VTSCSI_FLAG_RESET;
20602f001371SPeter Grehan 
20612f001371SPeter Grehan 	return (error);
20622f001371SPeter Grehan }
20632f001371SPeter Grehan 
20642f001371SPeter Grehan static void
vtscsi_init_request(struct vtscsi_softc * sc,struct vtscsi_request * req)20652f001371SPeter Grehan vtscsi_init_request(struct vtscsi_softc *sc, struct vtscsi_request *req)
20662f001371SPeter Grehan {
20672f001371SPeter Grehan 
20682f001371SPeter Grehan #ifdef INVARIANTS
20692f001371SPeter Grehan 	int req_nsegs, resp_nsegs;
20702f001371SPeter Grehan 
20712f001371SPeter Grehan 	req_nsegs = sglist_count(&req->vsr_ureq, sizeof(req->vsr_ureq));
20722f001371SPeter Grehan 	resp_nsegs = sglist_count(&req->vsr_uresp, sizeof(req->vsr_uresp));
20732f001371SPeter Grehan 
20742f001371SPeter Grehan 	KASSERT(req_nsegs == 1, ("request crossed page boundary"));
20752f001371SPeter Grehan 	KASSERT(resp_nsegs == 1, ("response crossed page boundary"));
20762f001371SPeter Grehan #endif
20772f001371SPeter Grehan 
20782f001371SPeter Grehan 	req->vsr_softc = sc;
20792f001371SPeter Grehan 	callout_init_mtx(&req->vsr_callout, VTSCSI_MTX(sc), 0);
20802f001371SPeter Grehan }
20812f001371SPeter Grehan 
20822f001371SPeter Grehan static int
vtscsi_alloc_requests(struct vtscsi_softc * sc)20832f001371SPeter Grehan vtscsi_alloc_requests(struct vtscsi_softc *sc)
20842f001371SPeter Grehan {
20852f001371SPeter Grehan 	struct vtscsi_request *req;
20862f001371SPeter Grehan 	int i, nreqs;
20872f001371SPeter Grehan 
20882f001371SPeter Grehan 	/*
20892f001371SPeter Grehan 	 * Commands destined for either the request or control queues come
20902f001371SPeter Grehan 	 * from the same SIM queue. Use the size of the request virtqueue
20912f001371SPeter Grehan 	 * as it (should) be much more frequently used. Some additional
20922f001371SPeter Grehan 	 * requests are allocated for internal (TMF) use.
20932f001371SPeter Grehan 	 */
20942f001371SPeter Grehan 	nreqs = virtqueue_size(sc->vtscsi_request_vq);
20952f001371SPeter Grehan 	if ((sc->vtscsi_flags & VTSCSI_FLAG_INDIRECT) == 0)
20962f001371SPeter Grehan 		nreqs /= VTSCSI_MIN_SEGMENTS;
20972f001371SPeter Grehan 	nreqs += VTSCSI_RESERVED_REQUESTS;
20982f001371SPeter Grehan 
20992f001371SPeter Grehan 	for (i = 0; i < nreqs; i++) {
21002f001371SPeter Grehan 		req = malloc(sizeof(struct vtscsi_request), M_DEVBUF,
21012f001371SPeter Grehan 		    M_NOWAIT);
21022f001371SPeter Grehan 		if (req == NULL)
21032f001371SPeter Grehan 			return (ENOMEM);
21042f001371SPeter Grehan 
21052f001371SPeter Grehan 		vtscsi_init_request(sc, req);
21062f001371SPeter Grehan 
21072f001371SPeter Grehan 		sc->vtscsi_nrequests++;
21082f001371SPeter Grehan 		vtscsi_enqueue_request(sc, req);
21092f001371SPeter Grehan 	}
21102f001371SPeter Grehan 
21112f001371SPeter Grehan 	return (0);
21122f001371SPeter Grehan }
21132f001371SPeter Grehan 
21142f001371SPeter Grehan static void
vtscsi_free_requests(struct vtscsi_softc * sc)21152f001371SPeter Grehan vtscsi_free_requests(struct vtscsi_softc *sc)
21162f001371SPeter Grehan {
21172f001371SPeter Grehan 	struct vtscsi_request *req;
21182f001371SPeter Grehan 
21192f001371SPeter Grehan 	while ((req = vtscsi_dequeue_request(sc)) != NULL) {
21202f001371SPeter Grehan 		KASSERT(callout_active(&req->vsr_callout) == 0,
21212f001371SPeter Grehan 		    ("request callout still active"));
21222f001371SPeter Grehan 
21232f001371SPeter Grehan 		sc->vtscsi_nrequests--;
21242f001371SPeter Grehan 		free(req, M_DEVBUF);
21252f001371SPeter Grehan 	}
21262f001371SPeter Grehan 
21272f001371SPeter Grehan 	KASSERT(sc->vtscsi_nrequests == 0, ("leaked requests: %d",
21282f001371SPeter Grehan 	    sc->vtscsi_nrequests));
21292f001371SPeter Grehan }
21302f001371SPeter Grehan 
21312f001371SPeter Grehan static void
vtscsi_enqueue_request(struct vtscsi_softc * sc,struct vtscsi_request * req)21322f001371SPeter Grehan vtscsi_enqueue_request(struct vtscsi_softc *sc, struct vtscsi_request *req)
21332f001371SPeter Grehan {
21342f001371SPeter Grehan 
21352f001371SPeter Grehan 	KASSERT(req->vsr_softc == sc,
21362f001371SPeter Grehan 	    ("non-matching request vsr_softc %p/%p", req->vsr_softc, sc));
21372f001371SPeter Grehan 
21382f001371SPeter Grehan 	vtscsi_dprintf(sc, VTSCSI_TRACE, "req=%p\n", req);
21392f001371SPeter Grehan 
21402f001371SPeter Grehan 	/* A request is available so the SIMQ could be released. */
21412f001371SPeter Grehan 	if (vtscsi_thaw_simq(sc, VTSCSI_REQUEST) != 0)
21422f001371SPeter Grehan 		xpt_release_simq(sc->vtscsi_sim, 1);
21432f001371SPeter Grehan 
21442f001371SPeter Grehan 	req->vsr_ccb = NULL;
21452f001371SPeter Grehan 	req->vsr_complete = NULL;
21462f001371SPeter Grehan 	req->vsr_ptr0 = NULL;
21472f001371SPeter Grehan 	req->vsr_state = VTSCSI_REQ_STATE_FREE;
21482f001371SPeter Grehan 	req->vsr_flags = 0;
21492f001371SPeter Grehan 
21502f001371SPeter Grehan 	bzero(&req->vsr_ureq, sizeof(req->vsr_ureq));
21512f001371SPeter Grehan 	bzero(&req->vsr_uresp, sizeof(req->vsr_uresp));
21522f001371SPeter Grehan 
21532f001371SPeter Grehan 	/*
21542f001371SPeter Grehan 	 * We insert at the tail of the queue in order to make it
21552f001371SPeter Grehan 	 * very unlikely a request will be reused if we race with
21562f001371SPeter Grehan 	 * stopping its callout handler.
21572f001371SPeter Grehan 	 */
21582f001371SPeter Grehan 	TAILQ_INSERT_TAIL(&sc->vtscsi_req_free, req, vsr_link);
21592f001371SPeter Grehan }
21602f001371SPeter Grehan 
21612f001371SPeter Grehan static struct vtscsi_request *
vtscsi_dequeue_request(struct vtscsi_softc * sc)21622f001371SPeter Grehan vtscsi_dequeue_request(struct vtscsi_softc *sc)
21632f001371SPeter Grehan {
21642f001371SPeter Grehan 	struct vtscsi_request *req;
21652f001371SPeter Grehan 
21662f001371SPeter Grehan 	req = TAILQ_FIRST(&sc->vtscsi_req_free);
21672f001371SPeter Grehan 	if (req != NULL) {
21682f001371SPeter Grehan 		req->vsr_state = VTSCSI_REQ_STATE_INUSE;
21692f001371SPeter Grehan 		TAILQ_REMOVE(&sc->vtscsi_req_free, req, vsr_link);
21702f001371SPeter Grehan 	} else
21712f001371SPeter Grehan 		sc->vtscsi_stats.dequeue_no_requests++;
21722f001371SPeter Grehan 
21732f001371SPeter Grehan 	vtscsi_dprintf(sc, VTSCSI_TRACE, "req=%p\n", req);
21742f001371SPeter Grehan 
21752f001371SPeter Grehan 	return (req);
21762f001371SPeter Grehan }
21772f001371SPeter Grehan 
21782f001371SPeter Grehan static void
vtscsi_complete_request(struct vtscsi_request * req)21792f001371SPeter Grehan vtscsi_complete_request(struct vtscsi_request *req)
21802f001371SPeter Grehan {
21812f001371SPeter Grehan 
21822f001371SPeter Grehan 	if (req->vsr_flags & VTSCSI_REQ_FLAG_POLLED)
21832f001371SPeter Grehan 		req->vsr_flags |= VTSCSI_REQ_FLAG_COMPLETE;
21842f001371SPeter Grehan 
21852f001371SPeter Grehan 	if (req->vsr_complete != NULL)
21862f001371SPeter Grehan 		req->vsr_complete(req->vsr_softc, req);
21872f001371SPeter Grehan }
21882f001371SPeter Grehan 
21892f001371SPeter Grehan static void
vtscsi_complete_vq(struct vtscsi_softc * sc,struct virtqueue * vq)21902f001371SPeter Grehan vtscsi_complete_vq(struct vtscsi_softc *sc, struct virtqueue *vq)
21912f001371SPeter Grehan {
21922f001371SPeter Grehan 	struct vtscsi_request *req;
21932f001371SPeter Grehan 
21942f001371SPeter Grehan 	VTSCSI_LOCK_OWNED(sc);
21952f001371SPeter Grehan 
21962f001371SPeter Grehan 	while ((req = virtqueue_dequeue(vq, NULL)) != NULL)
21972f001371SPeter Grehan 		vtscsi_complete_request(req);
21982f001371SPeter Grehan }
21992f001371SPeter Grehan 
22002f001371SPeter Grehan static void
vtscsi_control_vq_intr(void * xsc)22016632efe4SBryan Venteicher vtscsi_control_vq_intr(void *xsc)
22022f001371SPeter Grehan {
22032f001371SPeter Grehan 	struct vtscsi_softc *sc;
22042f001371SPeter Grehan 	struct virtqueue *vq;
22052f001371SPeter Grehan 
22066632efe4SBryan Venteicher 	sc = xsc;
22072f001371SPeter Grehan 	vq = sc->vtscsi_control_vq;
22082f001371SPeter Grehan 
22096632efe4SBryan Venteicher again:
22102f001371SPeter Grehan 	VTSCSI_LOCK(sc);
22112f001371SPeter Grehan 
22122f001371SPeter Grehan 	vtscsi_complete_vq(sc, sc->vtscsi_control_vq);
22132f001371SPeter Grehan 
22142f001371SPeter Grehan 	if (virtqueue_enable_intr(vq) != 0) {
22152f001371SPeter Grehan 		virtqueue_disable_intr(vq);
22162f001371SPeter Grehan 		VTSCSI_UNLOCK(sc);
22176632efe4SBryan Venteicher 		goto again;
22182f001371SPeter Grehan 	}
22192f001371SPeter Grehan 
22202f001371SPeter Grehan 	VTSCSI_UNLOCK(sc);
22212f001371SPeter Grehan }
22222f001371SPeter Grehan 
22232f001371SPeter Grehan static void
vtscsi_event_vq_intr(void * xsc)22246632efe4SBryan Venteicher vtscsi_event_vq_intr(void *xsc)
22252f001371SPeter Grehan {
22262f001371SPeter Grehan 	struct vtscsi_softc *sc;
22272f001371SPeter Grehan 	struct virtqueue *vq;
22282f001371SPeter Grehan 	struct virtio_scsi_event *event;
22292f001371SPeter Grehan 
22306632efe4SBryan Venteicher 	sc = xsc;
22312f001371SPeter Grehan 	vq = sc->vtscsi_event_vq;
22322f001371SPeter Grehan 
22336632efe4SBryan Venteicher again:
22342f001371SPeter Grehan 	VTSCSI_LOCK(sc);
22352f001371SPeter Grehan 
22362f001371SPeter Grehan 	while ((event = virtqueue_dequeue(vq, NULL)) != NULL)
22372f001371SPeter Grehan 		vtscsi_handle_event(sc, event);
22382f001371SPeter Grehan 
22392f001371SPeter Grehan 	if (virtqueue_enable_intr(vq) != 0) {
22402f001371SPeter Grehan 		virtqueue_disable_intr(vq);
22412f001371SPeter Grehan 		VTSCSI_UNLOCK(sc);
22426632efe4SBryan Venteicher 		goto again;
22432f001371SPeter Grehan 	}
22442f001371SPeter Grehan 
22452f001371SPeter Grehan 	VTSCSI_UNLOCK(sc);
22462f001371SPeter Grehan }
22472f001371SPeter Grehan 
22482f001371SPeter Grehan static void
vtscsi_request_vq_intr(void * xsc)22496632efe4SBryan Venteicher vtscsi_request_vq_intr(void *xsc)
22502f001371SPeter Grehan {
22512f001371SPeter Grehan 	struct vtscsi_softc *sc;
22522f001371SPeter Grehan 	struct virtqueue *vq;
22532f001371SPeter Grehan 
22546632efe4SBryan Venteicher 	sc = xsc;
22552f001371SPeter Grehan 	vq = sc->vtscsi_request_vq;
22562f001371SPeter Grehan 
22576632efe4SBryan Venteicher again:
22582f001371SPeter Grehan 	VTSCSI_LOCK(sc);
22592f001371SPeter Grehan 
22602f001371SPeter Grehan 	vtscsi_complete_vq(sc, sc->vtscsi_request_vq);
22612f001371SPeter Grehan 
22622f001371SPeter Grehan 	if (virtqueue_enable_intr(vq) != 0) {
22632f001371SPeter Grehan 		virtqueue_disable_intr(vq);
22642f001371SPeter Grehan 		VTSCSI_UNLOCK(sc);
22656632efe4SBryan Venteicher 		goto again;
22662f001371SPeter Grehan 	}
22672f001371SPeter Grehan 
22682f001371SPeter Grehan 	VTSCSI_UNLOCK(sc);
22692f001371SPeter Grehan }
22702f001371SPeter Grehan 
22712f001371SPeter Grehan static void
vtscsi_disable_vqs_intr(struct vtscsi_softc * sc)22722f001371SPeter Grehan vtscsi_disable_vqs_intr(struct vtscsi_softc *sc)
22732f001371SPeter Grehan {
22742f001371SPeter Grehan 
22752f001371SPeter Grehan 	virtqueue_disable_intr(sc->vtscsi_control_vq);
22762f001371SPeter Grehan 	virtqueue_disable_intr(sc->vtscsi_event_vq);
22772f001371SPeter Grehan 	virtqueue_disable_intr(sc->vtscsi_request_vq);
22782f001371SPeter Grehan }
22792f001371SPeter Grehan 
22802f001371SPeter Grehan static void
vtscsi_enable_vqs_intr(struct vtscsi_softc * sc)22812f001371SPeter Grehan vtscsi_enable_vqs_intr(struct vtscsi_softc *sc)
22822f001371SPeter Grehan {
22832f001371SPeter Grehan 
22842f001371SPeter Grehan 	virtqueue_enable_intr(sc->vtscsi_control_vq);
22852f001371SPeter Grehan 	virtqueue_enable_intr(sc->vtscsi_event_vq);
22862f001371SPeter Grehan 	virtqueue_enable_intr(sc->vtscsi_request_vq);
22872f001371SPeter Grehan }
22882f001371SPeter Grehan 
22892f001371SPeter Grehan static void
vtscsi_get_tunables(struct vtscsi_softc * sc)22902f001371SPeter Grehan vtscsi_get_tunables(struct vtscsi_softc *sc)
22912f001371SPeter Grehan {
22922f001371SPeter Grehan 	char tmpstr[64];
22932f001371SPeter Grehan 
22942f001371SPeter Grehan 	TUNABLE_INT_FETCH("hw.vtscsi.debug_level", &sc->vtscsi_debug);
22952f001371SPeter Grehan 
22962f001371SPeter Grehan 	snprintf(tmpstr, sizeof(tmpstr), "dev.vtscsi.%d.debug_level",
22972f001371SPeter Grehan 	    device_get_unit(sc->vtscsi_dev));
22982f001371SPeter Grehan 	TUNABLE_INT_FETCH(tmpstr, &sc->vtscsi_debug);
22992f001371SPeter Grehan }
23002f001371SPeter Grehan 
23012f001371SPeter Grehan static void
vtscsi_setup_sysctl(struct vtscsi_softc * sc)2302e6cc42f1SBryan Venteicher vtscsi_setup_sysctl(struct vtscsi_softc *sc)
23032f001371SPeter Grehan {
23042f001371SPeter Grehan 	device_t dev;
23052f001371SPeter Grehan 	struct vtscsi_statistics *stats;
23062f001371SPeter Grehan         struct sysctl_ctx_list *ctx;
23072f001371SPeter Grehan 	struct sysctl_oid *tree;
23082f001371SPeter Grehan 	struct sysctl_oid_list *child;
23092f001371SPeter Grehan 
23102f001371SPeter Grehan 	dev = sc->vtscsi_dev;
23112f001371SPeter Grehan 	stats = &sc->vtscsi_stats;
23122f001371SPeter Grehan 	ctx = device_get_sysctl_ctx(dev);
23132f001371SPeter Grehan 	tree = device_get_sysctl_tree(dev);
23142f001371SPeter Grehan 	child = SYSCTL_CHILDREN(tree);
23152f001371SPeter Grehan 
23162f001371SPeter Grehan 	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "debug_level",
23172f001371SPeter Grehan 	    CTLFLAG_RW, &sc->vtscsi_debug, 0,
23182f001371SPeter Grehan 	    "Debug level");
23192f001371SPeter Grehan 
23202f001371SPeter Grehan 	SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "scsi_cmd_timeouts",
23212f001371SPeter Grehan 	    CTLFLAG_RD, &stats->scsi_cmd_timeouts,
23222f001371SPeter Grehan 	    "SCSI command timeouts");
23232f001371SPeter Grehan 	SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "dequeue_no_requests",
23242f001371SPeter Grehan 	    CTLFLAG_RD, &stats->dequeue_no_requests,
23252f001371SPeter Grehan 	    "No available requests to dequeue");
23262f001371SPeter Grehan }
23272f001371SPeter Grehan 
23282f001371SPeter Grehan static void
vtscsi_printf_req(struct vtscsi_request * req,const char * func,const char * fmt,...)23292f001371SPeter Grehan vtscsi_printf_req(struct vtscsi_request *req, const char *func,
23302f001371SPeter Grehan     const char *fmt, ...)
23312f001371SPeter Grehan {
23322f001371SPeter Grehan 	struct vtscsi_softc *sc;
23332f001371SPeter Grehan 	union ccb *ccb;
23342f001371SPeter Grehan 	struct sbuf sb;
23352f001371SPeter Grehan 	va_list ap;
23362f001371SPeter Grehan 	char str[192];
23372f001371SPeter Grehan 
23382f001371SPeter Grehan 	if (req == NULL)
23392f001371SPeter Grehan 		return;
23402f001371SPeter Grehan 
23412f001371SPeter Grehan 	sc = req->vsr_softc;
23422f001371SPeter Grehan 	ccb = req->vsr_ccb;
23432f001371SPeter Grehan 
23442f001371SPeter Grehan 	va_start(ap, fmt);
23452f001371SPeter Grehan 	sbuf_new(&sb, str, sizeof(str), 0);
23462f001371SPeter Grehan 
23472f001371SPeter Grehan 	if (ccb == NULL) {
23482f001371SPeter Grehan 		sbuf_printf(&sb, "(noperiph:%s%d:%u): ",
23492f001371SPeter Grehan 		    cam_sim_name(sc->vtscsi_sim), cam_sim_unit(sc->vtscsi_sim),
23502f001371SPeter Grehan 		    cam_sim_bus(sc->vtscsi_sim));
23512f001371SPeter Grehan 	} else {
23528c4ee0b2SAlexander Motin 		xpt_path_sbuf(ccb->ccb_h.path, &sb);
23532f001371SPeter Grehan 		if (ccb->ccb_h.func_code == XPT_SCSI_IO) {
23542f001371SPeter Grehan 			scsi_command_string(&ccb->csio, &sb);
23552f001371SPeter Grehan 			sbuf_printf(&sb, "length %d ", ccb->csio.dxfer_len);
23562f001371SPeter Grehan 		}
23572f001371SPeter Grehan 	}
23582f001371SPeter Grehan 
23592f001371SPeter Grehan 	sbuf_vprintf(&sb, fmt, ap);
23602f001371SPeter Grehan 	va_end(ap);
23612f001371SPeter Grehan 
23622f001371SPeter Grehan 	sbuf_finish(&sb);
23632f001371SPeter Grehan 	printf("%s: %s: %s", device_get_nameunit(sc->vtscsi_dev), func,
23642f001371SPeter Grehan 	    sbuf_data(&sb));
23652f001371SPeter Grehan }
2366