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