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