1241470Sgrehan/*- 2253132Sbryanv * Copyright (c) 2012, Bryan Venteicher <bryanv@FreeBSD.org> 3241470Sgrehan * All rights reserved. 4241470Sgrehan * 5241470Sgrehan * Redistribution and use in source and binary forms, with or without 6241470Sgrehan * modification, are permitted provided that the following conditions 7241470Sgrehan * are met: 8241470Sgrehan * 1. Redistributions of source code must retain the above copyright 9241470Sgrehan * notice unmodified, this list of conditions, and the following 10241470Sgrehan * disclaimer. 11241470Sgrehan * 2. Redistributions in binary form must reproduce the above copyright 12241470Sgrehan * notice, this list of conditions and the following disclaimer in the 13241470Sgrehan * documentation and/or other materials provided with the distribution. 14241470Sgrehan * 15241470Sgrehan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16241470Sgrehan * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17241470Sgrehan * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18241470Sgrehan * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19241470Sgrehan * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20241470Sgrehan * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21241470Sgrehan * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22241470Sgrehan * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23241470Sgrehan * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24241470Sgrehan * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25241470Sgrehan */ 26241470Sgrehan 27241470Sgrehan/* Driver for VirtIO SCSI devices. */ 28241470Sgrehan 29241470Sgrehan#include <sys/cdefs.h> 30241470Sgrehan__FBSDID("$FreeBSD$"); 31241470Sgrehan 32241470Sgrehan#include <sys/param.h> 33241470Sgrehan#include <sys/systm.h> 34241470Sgrehan#include <sys/kernel.h> 35241470Sgrehan#include <sys/kthread.h> 36241470Sgrehan#include <sys/malloc.h> 37241470Sgrehan#include <sys/module.h> 38241470Sgrehan#include <sys/sglist.h> 39241470Sgrehan#include <sys/sysctl.h> 40241470Sgrehan#include <sys/lock.h> 41241470Sgrehan#include <sys/mutex.h> 42241470Sgrehan#include <sys/callout.h> 43241470Sgrehan#include <sys/queue.h> 44241470Sgrehan#include <sys/sbuf.h> 45241470Sgrehan 46241470Sgrehan#include <machine/stdarg.h> 47241470Sgrehan 48241470Sgrehan#include <machine/bus.h> 49241470Sgrehan#include <machine/resource.h> 50241470Sgrehan#include <sys/bus.h> 51241470Sgrehan#include <sys/rman.h> 52241470Sgrehan 53241470Sgrehan#include <cam/cam.h> 54241470Sgrehan#include <cam/cam_ccb.h> 55241470Sgrehan#include <cam/cam_sim.h> 56241470Sgrehan#include <cam/cam_periph.h> 57241470Sgrehan#include <cam/cam_xpt_sim.h> 58241470Sgrehan#include <cam/cam_debug.h> 59241470Sgrehan#include <cam/scsi/scsi_all.h> 60241470Sgrehan#include <cam/scsi/scsi_message.h> 61241470Sgrehan 62241470Sgrehan#include <dev/virtio/virtio.h> 63241470Sgrehan#include <dev/virtio/virtqueue.h> 64241470Sgrehan#include <dev/virtio/scsi/virtio_scsi.h> 65241470Sgrehan#include <dev/virtio/scsi/virtio_scsivar.h> 66241470Sgrehan 67241470Sgrehan#include "virtio_if.h" 68241470Sgrehan 69241470Sgrehanstatic int vtscsi_modevent(module_t, int, void *); 70241470Sgrehan 71241470Sgrehanstatic int vtscsi_probe(device_t); 72241470Sgrehanstatic int vtscsi_attach(device_t); 73241470Sgrehanstatic int vtscsi_detach(device_t); 74241470Sgrehanstatic int vtscsi_suspend(device_t); 75241470Sgrehanstatic int vtscsi_resume(device_t); 76241470Sgrehan 77241470Sgrehanstatic void vtscsi_negotiate_features(struct vtscsi_softc *); 78265302Sbryanvstatic void vtscsi_read_config(struct vtscsi_softc *, 79265302Sbryanv struct virtio_scsi_config *); 80241470Sgrehanstatic int vtscsi_maximum_segments(struct vtscsi_softc *, int); 81241470Sgrehanstatic int vtscsi_alloc_virtqueues(struct vtscsi_softc *); 82241470Sgrehanstatic void vtscsi_write_device_config(struct vtscsi_softc *); 83241470Sgrehanstatic int vtscsi_reinit(struct vtscsi_softc *); 84241470Sgrehan 85241470Sgrehanstatic int vtscsi_alloc_cam(struct vtscsi_softc *); 86265302Sbryanvstatic int vtscsi_register_cam(struct vtscsi_softc *); 87241470Sgrehanstatic void vtscsi_free_cam(struct vtscsi_softc *); 88241470Sgrehanstatic void vtscsi_cam_async(void *, uint32_t, struct cam_path *, void *); 89241470Sgrehanstatic int vtscsi_register_async(struct vtscsi_softc *); 90241470Sgrehanstatic void vtscsi_deregister_async(struct vtscsi_softc *); 91241470Sgrehanstatic void vtscsi_cam_action(struct cam_sim *, union ccb *); 92241470Sgrehanstatic void vtscsi_cam_poll(struct cam_sim *); 93241470Sgrehan 94241470Sgrehanstatic void vtscsi_cam_scsi_io(struct vtscsi_softc *, struct cam_sim *, 95241470Sgrehan union ccb *); 96265302Sbryanvstatic void vtscsi_cam_get_tran_settings(struct vtscsi_softc *, 97241470Sgrehan union ccb *); 98241470Sgrehanstatic void vtscsi_cam_reset_bus(struct vtscsi_softc *, union ccb *); 99241470Sgrehanstatic void vtscsi_cam_reset_dev(struct vtscsi_softc *, union ccb *); 100241470Sgrehanstatic void vtscsi_cam_abort(struct vtscsi_softc *, union ccb *); 101241470Sgrehanstatic void vtscsi_cam_path_inquiry(struct vtscsi_softc *, 102241470Sgrehan struct cam_sim *, union ccb *); 103241470Sgrehan 104265302Sbryanvstatic int vtscsi_sg_append_scsi_buf(struct vtscsi_softc *, 105241470Sgrehan struct sglist *, struct ccb_scsiio *); 106265302Sbryanvstatic int vtscsi_fill_scsi_cmd_sglist(struct vtscsi_softc *, 107241470Sgrehan struct vtscsi_request *, int *, int *); 108265302Sbryanvstatic int vtscsi_execute_scsi_cmd(struct vtscsi_softc *, 109241470Sgrehan struct vtscsi_request *); 110265302Sbryanvstatic int vtscsi_start_scsi_cmd(struct vtscsi_softc *, union ccb *); 111241470Sgrehanstatic void vtscsi_complete_abort_timedout_scsi_cmd(struct vtscsi_softc *, 112241470Sgrehan struct vtscsi_request *); 113265302Sbryanvstatic int vtscsi_abort_timedout_scsi_cmd(struct vtscsi_softc *, 114241470Sgrehan struct vtscsi_request *); 115241470Sgrehanstatic void vtscsi_timedout_scsi_cmd(void *); 116241470Sgrehanstatic cam_status vtscsi_scsi_cmd_cam_status(struct virtio_scsi_cmd_resp *); 117241470Sgrehanstatic cam_status vtscsi_complete_scsi_cmd_response(struct vtscsi_softc *, 118241470Sgrehan struct ccb_scsiio *, struct virtio_scsi_cmd_resp *); 119265302Sbryanvstatic void vtscsi_complete_scsi_cmd(struct vtscsi_softc *, 120241470Sgrehan struct vtscsi_request *); 121241470Sgrehan 122241470Sgrehanstatic void vtscsi_poll_ctrl_req(struct vtscsi_softc *, 123241470Sgrehan struct vtscsi_request *); 124265302Sbryanvstatic int vtscsi_execute_ctrl_req(struct vtscsi_softc *, 125241470Sgrehan struct vtscsi_request *, struct sglist *, int, int, int); 126265302Sbryanvstatic void vtscsi_complete_abort_task_cmd(struct vtscsi_softc *c, 127241470Sgrehan struct vtscsi_request *); 128265302Sbryanvstatic int vtscsi_execute_abort_task_cmd(struct vtscsi_softc *, 129241470Sgrehan struct vtscsi_request *); 130265302Sbryanvstatic int vtscsi_execute_reset_dev_cmd(struct vtscsi_softc *, 131241470Sgrehan struct vtscsi_request *); 132241470Sgrehan 133265302Sbryanvstatic void vtscsi_get_request_lun(uint8_t [], target_id_t *, lun_id_t *); 134241470Sgrehanstatic void vtscsi_set_request_lun(struct ccb_hdr *, uint8_t []); 135241470Sgrehanstatic void vtscsi_init_scsi_cmd_req(struct ccb_scsiio *, 136241470Sgrehan struct virtio_scsi_cmd_req *); 137241470Sgrehanstatic void vtscsi_init_ctrl_tmf_req(struct ccb_hdr *, uint32_t, 138241470Sgrehan uintptr_t, struct virtio_scsi_ctrl_tmf_req *); 139241470Sgrehan 140265302Sbryanvstatic void vtscsi_freeze_simq(struct vtscsi_softc *, int); 141241470Sgrehanstatic int vtscsi_thaw_simq(struct vtscsi_softc *, int); 142241470Sgrehan 143265302Sbryanvstatic void vtscsi_announce(struct vtscsi_softc *, uint32_t, target_id_t, 144241470Sgrehan lun_id_t); 145265302Sbryanvstatic void vtscsi_execute_rescan(struct vtscsi_softc *, target_id_t, 146241470Sgrehan lun_id_t); 147265302Sbryanvstatic void vtscsi_execute_rescan_bus(struct vtscsi_softc *); 148241470Sgrehan 149265302Sbryanvstatic void vtscsi_handle_event(struct vtscsi_softc *, 150241470Sgrehan struct virtio_scsi_event *); 151265302Sbryanvstatic int vtscsi_enqueue_event_buf(struct vtscsi_softc *, 152241470Sgrehan struct virtio_scsi_event *); 153241470Sgrehanstatic int vtscsi_init_event_vq(struct vtscsi_softc *); 154265302Sbryanvstatic void vtscsi_reinit_event_vq(struct vtscsi_softc *); 155265302Sbryanvstatic void vtscsi_drain_event_vq(struct vtscsi_softc *); 156241470Sgrehan 157265302Sbryanvstatic void vtscsi_complete_vqs_locked(struct vtscsi_softc *); 158265302Sbryanvstatic void vtscsi_complete_vqs(struct vtscsi_softc *); 159265302Sbryanvstatic void vtscsi_drain_vqs(struct vtscsi_softc *); 160265302Sbryanvstatic void vtscsi_cancel_request(struct vtscsi_softc *, 161241470Sgrehan struct vtscsi_request *); 162241470Sgrehanstatic void vtscsi_drain_vq(struct vtscsi_softc *, struct virtqueue *); 163241470Sgrehanstatic void vtscsi_stop(struct vtscsi_softc *); 164241470Sgrehanstatic int vtscsi_reset_bus(struct vtscsi_softc *); 165241470Sgrehan 166265302Sbryanvstatic void vtscsi_init_request(struct vtscsi_softc *, 167241470Sgrehan struct vtscsi_request *); 168241470Sgrehanstatic int vtscsi_alloc_requests(struct vtscsi_softc *); 169241470Sgrehanstatic void vtscsi_free_requests(struct vtscsi_softc *); 170241470Sgrehanstatic void vtscsi_enqueue_request(struct vtscsi_softc *, 171241470Sgrehan struct vtscsi_request *); 172241470Sgrehanstatic struct vtscsi_request * vtscsi_dequeue_request(struct vtscsi_softc *); 173241470Sgrehan 174241470Sgrehanstatic void vtscsi_complete_request(struct vtscsi_request *); 175265302Sbryanvstatic void vtscsi_complete_vq(struct vtscsi_softc *, struct virtqueue *); 176241470Sgrehan 177253132Sbryanvstatic void vtscsi_control_vq_intr(void *); 178253132Sbryanvstatic void vtscsi_event_vq_intr(void *); 179253132Sbryanvstatic void vtscsi_request_vq_intr(void *); 180265302Sbryanvstatic void vtscsi_disable_vqs_intr(struct vtscsi_softc *); 181265302Sbryanvstatic void vtscsi_enable_vqs_intr(struct vtscsi_softc *); 182241470Sgrehan 183265302Sbryanvstatic void vtscsi_get_tunables(struct vtscsi_softc *); 184265302Sbryanvstatic void vtscsi_add_sysctl(struct vtscsi_softc *); 185241470Sgrehan 186265302Sbryanvstatic void vtscsi_printf_req(struct vtscsi_request *, const char *, 187241470Sgrehan const char *, ...); 188241470Sgrehan 189241470Sgrehan/* Global tunables. */ 190241470Sgrehan/* 191241470Sgrehan * The current QEMU VirtIO SCSI implementation does not cancel in-flight 192241470Sgrehan * IO during virtio_stop(). So in-flight requests still complete after the 193241470Sgrehan * device reset. We would have to wait for all the in-flight IO to complete, 194241470Sgrehan * which defeats the typical purpose of a bus reset. We could simulate the 195241470Sgrehan * bus reset with either I_T_NEXUS_RESET of all the targets, or with 196241470Sgrehan * LOGICAL_UNIT_RESET of all the LUNs (assuming there is space in the 197241470Sgrehan * control virtqueue). But this isn't very useful if things really go off 198241470Sgrehan * the rails, so default to disabled for now. 199241470Sgrehan */ 200241470Sgrehanstatic int vtscsi_bus_reset_disable = 1; 201241470SgrehanTUNABLE_INT("hw.vtscsi.bus_reset_disable", &vtscsi_bus_reset_disable); 202241470Sgrehan 203241470Sgrehanstatic struct virtio_feature_desc vtscsi_feature_desc[] = { 204241470Sgrehan { VIRTIO_SCSI_F_INOUT, "InOut" }, 205241470Sgrehan { VIRTIO_SCSI_F_HOTPLUG, "Hotplug" }, 206241470Sgrehan 207241470Sgrehan { 0, NULL } 208241470Sgrehan}; 209241470Sgrehan 210241470Sgrehanstatic device_method_t vtscsi_methods[] = { 211241470Sgrehan /* Device methods. */ 212241470Sgrehan DEVMETHOD(device_probe, vtscsi_probe), 213241470Sgrehan DEVMETHOD(device_attach, vtscsi_attach), 214241470Sgrehan DEVMETHOD(device_detach, vtscsi_detach), 215241470Sgrehan DEVMETHOD(device_suspend, vtscsi_suspend), 216241470Sgrehan DEVMETHOD(device_resume, vtscsi_resume), 217241470Sgrehan 218241470Sgrehan DEVMETHOD_END 219241470Sgrehan}; 220241470Sgrehan 221241470Sgrehanstatic driver_t vtscsi_driver = { 222241470Sgrehan "vtscsi", 223241470Sgrehan vtscsi_methods, 224241470Sgrehan sizeof(struct vtscsi_softc) 225241470Sgrehan}; 226241470Sgrehanstatic devclass_t vtscsi_devclass; 227241470Sgrehan 228241470SgrehanDRIVER_MODULE(virtio_scsi, virtio_pci, vtscsi_driver, vtscsi_devclass, 229241470Sgrehan vtscsi_modevent, 0); 230241470SgrehanMODULE_VERSION(virtio_scsi, 1); 231241470SgrehanMODULE_DEPEND(virtio_scsi, virtio, 1, 1, 1); 232241470SgrehanMODULE_DEPEND(virtio_scsi, cam, 1, 1, 1); 233241470Sgrehan 234241470Sgrehanstatic int 235241470Sgrehanvtscsi_modevent(module_t mod, int type, void *unused) 236241470Sgrehan{ 237241470Sgrehan int error; 238241470Sgrehan 239241470Sgrehan switch (type) { 240241470Sgrehan case MOD_LOAD: 241241470Sgrehan case MOD_QUIESCE: 242241470Sgrehan case MOD_UNLOAD: 243241470Sgrehan case MOD_SHUTDOWN: 244241470Sgrehan error = 0; 245241470Sgrehan break; 246241470Sgrehan default: 247241470Sgrehan error = EOPNOTSUPP; 248241470Sgrehan break; 249241470Sgrehan } 250241470Sgrehan 251241470Sgrehan return (error); 252241470Sgrehan} 253241470Sgrehan 254241470Sgrehanstatic int 255241470Sgrehanvtscsi_probe(device_t dev) 256241470Sgrehan{ 257241470Sgrehan 258241470Sgrehan if (virtio_get_device_type(dev) != VIRTIO_ID_SCSI) 259241470Sgrehan return (ENXIO); 260241470Sgrehan 261241470Sgrehan device_set_desc(dev, "VirtIO SCSI Adapter"); 262241470Sgrehan 263241470Sgrehan return (BUS_PROBE_DEFAULT); 264241470Sgrehan} 265241470Sgrehan 266241470Sgrehanstatic int 267241470Sgrehanvtscsi_attach(device_t dev) 268241470Sgrehan{ 269241470Sgrehan struct vtscsi_softc *sc; 270241470Sgrehan struct virtio_scsi_config scsicfg; 271241470Sgrehan int error; 272241470Sgrehan 273241470Sgrehan sc = device_get_softc(dev); 274241470Sgrehan sc->vtscsi_dev = dev; 275241470Sgrehan 276241470Sgrehan VTSCSI_LOCK_INIT(sc, device_get_nameunit(dev)); 277241470Sgrehan TAILQ_INIT(&sc->vtscsi_req_free); 278241470Sgrehan 279241470Sgrehan vtscsi_get_tunables(sc); 280241470Sgrehan vtscsi_add_sysctl(sc); 281241470Sgrehan 282241470Sgrehan virtio_set_feature_desc(dev, vtscsi_feature_desc); 283241470Sgrehan vtscsi_negotiate_features(sc); 284241470Sgrehan 285241470Sgrehan if (virtio_with_feature(dev, VIRTIO_RING_F_INDIRECT_DESC)) 286241470Sgrehan sc->vtscsi_flags |= VTSCSI_FLAG_INDIRECT; 287241470Sgrehan if (virtio_with_feature(dev, VIRTIO_SCSI_F_INOUT)) 288241470Sgrehan sc->vtscsi_flags |= VTSCSI_FLAG_BIDIRECTIONAL; 289241470Sgrehan if (virtio_with_feature(dev, VIRTIO_SCSI_F_HOTPLUG)) 290241470Sgrehan sc->vtscsi_flags |= VTSCSI_FLAG_HOTPLUG; 291241470Sgrehan 292265302Sbryanv vtscsi_read_config(sc, &scsicfg); 293241470Sgrehan 294241470Sgrehan sc->vtscsi_max_channel = scsicfg.max_channel; 295241470Sgrehan sc->vtscsi_max_target = scsicfg.max_target; 296241470Sgrehan sc->vtscsi_max_lun = scsicfg.max_lun; 297241470Sgrehan sc->vtscsi_event_buf_size = scsicfg.event_info_size; 298241470Sgrehan 299241470Sgrehan vtscsi_write_device_config(sc); 300241470Sgrehan 301241470Sgrehan sc->vtscsi_max_nsegs = vtscsi_maximum_segments(sc, scsicfg.seg_max); 302241470Sgrehan sc->vtscsi_sglist = sglist_alloc(sc->vtscsi_max_nsegs, M_NOWAIT); 303241470Sgrehan if (sc->vtscsi_sglist == NULL) { 304241470Sgrehan error = ENOMEM; 305241470Sgrehan device_printf(dev, "cannot allocate sglist\n"); 306241470Sgrehan goto fail; 307241470Sgrehan } 308241470Sgrehan 309241470Sgrehan error = vtscsi_alloc_virtqueues(sc); 310241470Sgrehan if (error) { 311241470Sgrehan device_printf(dev, "cannot allocate virtqueues\n"); 312241470Sgrehan goto fail; 313241470Sgrehan } 314241470Sgrehan 315241470Sgrehan error = vtscsi_init_event_vq(sc); 316241470Sgrehan if (error) { 317241470Sgrehan device_printf(dev, "cannot populate the eventvq\n"); 318241470Sgrehan goto fail; 319241470Sgrehan } 320241470Sgrehan 321241470Sgrehan error = vtscsi_alloc_requests(sc); 322241470Sgrehan if (error) { 323241470Sgrehan device_printf(dev, "cannot allocate requests\n"); 324241470Sgrehan goto fail; 325241470Sgrehan } 326241470Sgrehan 327241470Sgrehan error = vtscsi_alloc_cam(sc); 328241470Sgrehan if (error) { 329241470Sgrehan device_printf(dev, "cannot allocate CAM structures\n"); 330241470Sgrehan goto fail; 331241470Sgrehan } 332241470Sgrehan 333241470Sgrehan error = virtio_setup_intr(dev, INTR_TYPE_CAM); 334241470Sgrehan if (error) { 335241470Sgrehan device_printf(dev, "cannot setup virtqueue interrupts\n"); 336241470Sgrehan goto fail; 337241470Sgrehan } 338241470Sgrehan 339241470Sgrehan vtscsi_enable_vqs_intr(sc); 340241470Sgrehan 341241470Sgrehan /* 342241470Sgrehan * Register with CAM after interrupts are enabled so we will get 343241470Sgrehan * notified of the probe responses. 344241470Sgrehan */ 345241470Sgrehan error = vtscsi_register_cam(sc); 346241470Sgrehan if (error) { 347241470Sgrehan device_printf(dev, "cannot register with CAM\n"); 348241470Sgrehan goto fail; 349241470Sgrehan } 350241470Sgrehan 351241470Sgrehanfail: 352241470Sgrehan if (error) 353241470Sgrehan vtscsi_detach(dev); 354241470Sgrehan 355241470Sgrehan return (error); 356241470Sgrehan} 357241470Sgrehan 358241470Sgrehanstatic int 359241470Sgrehanvtscsi_detach(device_t dev) 360241470Sgrehan{ 361241470Sgrehan struct vtscsi_softc *sc; 362241470Sgrehan 363241470Sgrehan sc = device_get_softc(dev); 364241470Sgrehan 365241470Sgrehan VTSCSI_LOCK(sc); 366241470Sgrehan sc->vtscsi_flags |= VTSCSI_FLAG_DETACH; 367241470Sgrehan if (device_is_attached(dev)) 368241470Sgrehan vtscsi_stop(sc); 369241470Sgrehan VTSCSI_UNLOCK(sc); 370241470Sgrehan 371241470Sgrehan vtscsi_complete_vqs(sc); 372241470Sgrehan vtscsi_drain_vqs(sc); 373241470Sgrehan 374241470Sgrehan vtscsi_free_cam(sc); 375241470Sgrehan vtscsi_free_requests(sc); 376241470Sgrehan 377241470Sgrehan if (sc->vtscsi_sglist != NULL) { 378241470Sgrehan sglist_free(sc->vtscsi_sglist); 379241470Sgrehan sc->vtscsi_sglist = NULL; 380241470Sgrehan } 381241470Sgrehan 382241470Sgrehan VTSCSI_LOCK_DESTROY(sc); 383241470Sgrehan 384241470Sgrehan return (0); 385241470Sgrehan} 386241470Sgrehan 387241470Sgrehanstatic int 388241470Sgrehanvtscsi_suspend(device_t dev) 389241470Sgrehan{ 390241470Sgrehan 391241470Sgrehan return (0); 392241470Sgrehan} 393241470Sgrehan 394241470Sgrehanstatic int 395241470Sgrehanvtscsi_resume(device_t dev) 396241470Sgrehan{ 397241470Sgrehan 398241470Sgrehan return (0); 399241470Sgrehan} 400241470Sgrehan 401241470Sgrehanstatic void 402241470Sgrehanvtscsi_negotiate_features(struct vtscsi_softc *sc) 403241470Sgrehan{ 404241470Sgrehan device_t dev; 405241470Sgrehan uint64_t features; 406241470Sgrehan 407241470Sgrehan dev = sc->vtscsi_dev; 408241470Sgrehan features = virtio_negotiate_features(dev, VTSCSI_FEATURES); 409241470Sgrehan sc->vtscsi_features = features; 410241470Sgrehan} 411241470Sgrehan 412265302Sbryanv#define VTSCSI_GET_CONFIG(_dev, _field, _cfg) \ 413265302Sbryanv virtio_read_device_config(_dev, \ 414265302Sbryanv offsetof(struct virtio_scsi_config, _field), \ 415265302Sbryanv &(_cfg)->_field, sizeof((_cfg)->_field)) \ 416265302Sbryanv 417265302Sbryanvstatic void 418265302Sbryanvvtscsi_read_config(struct vtscsi_softc *sc, 419265302Sbryanv struct virtio_scsi_config *scsicfg) 420265302Sbryanv{ 421265302Sbryanv device_t dev; 422265302Sbryanv 423265302Sbryanv dev = sc->vtscsi_dev; 424265302Sbryanv 425265302Sbryanv bzero(scsicfg, sizeof(struct virtio_scsi_config)); 426265302Sbryanv 427265302Sbryanv VTSCSI_GET_CONFIG(dev, num_queues, scsicfg); 428265302Sbryanv VTSCSI_GET_CONFIG(dev, seg_max, scsicfg); 429265302Sbryanv VTSCSI_GET_CONFIG(dev, max_sectors, scsicfg); 430265302Sbryanv VTSCSI_GET_CONFIG(dev, cmd_per_lun, scsicfg); 431265302Sbryanv VTSCSI_GET_CONFIG(dev, event_info_size, scsicfg); 432265302Sbryanv VTSCSI_GET_CONFIG(dev, sense_size, scsicfg); 433265302Sbryanv VTSCSI_GET_CONFIG(dev, cdb_size, scsicfg); 434265302Sbryanv VTSCSI_GET_CONFIG(dev, max_channel, scsicfg); 435265302Sbryanv VTSCSI_GET_CONFIG(dev, max_target, scsicfg); 436265302Sbryanv VTSCSI_GET_CONFIG(dev, max_lun, scsicfg); 437265302Sbryanv} 438265302Sbryanv 439265302Sbryanv#undef VTSCSI_GET_CONFIG 440265302Sbryanv 441241470Sgrehanstatic int 442241470Sgrehanvtscsi_maximum_segments(struct vtscsi_softc *sc, int seg_max) 443241470Sgrehan{ 444241470Sgrehan int nsegs; 445241470Sgrehan 446241470Sgrehan nsegs = VTSCSI_MIN_SEGMENTS; 447241470Sgrehan 448241470Sgrehan if (seg_max > 0) { 449241470Sgrehan nsegs += MIN(seg_max, MAXPHYS / PAGE_SIZE + 1); 450241470Sgrehan if (sc->vtscsi_flags & VTSCSI_FLAG_INDIRECT) 451241470Sgrehan nsegs = MIN(nsegs, VIRTIO_MAX_INDIRECT); 452241470Sgrehan } else 453241470Sgrehan nsegs += 1; 454241470Sgrehan 455241470Sgrehan return (nsegs); 456241470Sgrehan} 457241470Sgrehan 458241470Sgrehanstatic int 459241470Sgrehanvtscsi_alloc_virtqueues(struct vtscsi_softc *sc) 460241470Sgrehan{ 461241470Sgrehan device_t dev; 462241470Sgrehan struct vq_alloc_info vq_info[3]; 463241470Sgrehan int nvqs; 464241470Sgrehan 465241470Sgrehan dev = sc->vtscsi_dev; 466241470Sgrehan nvqs = 3; 467241470Sgrehan 468241470Sgrehan VQ_ALLOC_INFO_INIT(&vq_info[0], 0, vtscsi_control_vq_intr, sc, 469241470Sgrehan &sc->vtscsi_control_vq, "%s control", device_get_nameunit(dev)); 470241470Sgrehan 471241470Sgrehan VQ_ALLOC_INFO_INIT(&vq_info[1], 0, vtscsi_event_vq_intr, sc, 472241470Sgrehan &sc->vtscsi_event_vq, "%s event", device_get_nameunit(dev)); 473241470Sgrehan 474241470Sgrehan VQ_ALLOC_INFO_INIT(&vq_info[2], sc->vtscsi_max_nsegs, 475241470Sgrehan vtscsi_request_vq_intr, sc, &sc->vtscsi_request_vq, 476241470Sgrehan "%s request", device_get_nameunit(dev)); 477241470Sgrehan 478241470Sgrehan return (virtio_alloc_virtqueues(dev, 0, nvqs, vq_info)); 479241470Sgrehan} 480241470Sgrehan 481241470Sgrehanstatic void 482241470Sgrehanvtscsi_write_device_config(struct vtscsi_softc *sc) 483241470Sgrehan{ 484241470Sgrehan 485241470Sgrehan virtio_write_dev_config_4(sc->vtscsi_dev, 486241470Sgrehan offsetof(struct virtio_scsi_config, sense_size), 487241470Sgrehan VIRTIO_SCSI_SENSE_SIZE); 488241470Sgrehan 489241470Sgrehan /* 490241470Sgrehan * This is the size in the virtio_scsi_cmd_req structure. Note 491241470Sgrehan * this value (32) is larger than the maximum CAM CDB size (16). 492241470Sgrehan */ 493241470Sgrehan virtio_write_dev_config_4(sc->vtscsi_dev, 494241470Sgrehan offsetof(struct virtio_scsi_config, cdb_size), 495241470Sgrehan VIRTIO_SCSI_CDB_SIZE); 496241470Sgrehan} 497241470Sgrehan 498241470Sgrehanstatic int 499241470Sgrehanvtscsi_reinit(struct vtscsi_softc *sc) 500241470Sgrehan{ 501241470Sgrehan device_t dev; 502241470Sgrehan int error; 503241470Sgrehan 504241470Sgrehan dev = sc->vtscsi_dev; 505241470Sgrehan 506241470Sgrehan error = virtio_reinit(dev, sc->vtscsi_features); 507241470Sgrehan if (error == 0) { 508241470Sgrehan vtscsi_write_device_config(sc); 509241470Sgrehan vtscsi_reinit_event_vq(sc); 510241470Sgrehan virtio_reinit_complete(dev); 511241470Sgrehan 512241470Sgrehan vtscsi_enable_vqs_intr(sc); 513241470Sgrehan } 514241470Sgrehan 515241470Sgrehan vtscsi_dprintf(sc, VTSCSI_TRACE, "error=%d\n", error); 516241470Sgrehan 517241470Sgrehan return (error); 518241470Sgrehan} 519241470Sgrehan 520241470Sgrehanstatic int 521241470Sgrehanvtscsi_alloc_cam(struct vtscsi_softc *sc) 522241470Sgrehan{ 523241470Sgrehan device_t dev; 524241470Sgrehan struct cam_devq *devq; 525241470Sgrehan int openings; 526241470Sgrehan 527241470Sgrehan dev = sc->vtscsi_dev; 528241470Sgrehan openings = sc->vtscsi_nrequests - VTSCSI_RESERVED_REQUESTS; 529241470Sgrehan 530241470Sgrehan devq = cam_simq_alloc(openings); 531241470Sgrehan if (devq == NULL) { 532241470Sgrehan device_printf(dev, "cannot allocate SIM queue\n"); 533241470Sgrehan return (ENOMEM); 534241470Sgrehan } 535241470Sgrehan 536241470Sgrehan sc->vtscsi_sim = cam_sim_alloc(vtscsi_cam_action, vtscsi_cam_poll, 537241470Sgrehan "vtscsi", sc, device_get_unit(dev), VTSCSI_MTX(sc), 1, 538241470Sgrehan openings, devq); 539241470Sgrehan if (sc->vtscsi_sim == NULL) { 540241470Sgrehan cam_simq_free(devq); 541241470Sgrehan device_printf(dev, "cannot allocate SIM\n"); 542241470Sgrehan return (ENOMEM); 543241470Sgrehan } 544241470Sgrehan 545241470Sgrehan return (0); 546241470Sgrehan} 547241470Sgrehan 548241470Sgrehanstatic int 549241470Sgrehanvtscsi_register_cam(struct vtscsi_softc *sc) 550241470Sgrehan{ 551241470Sgrehan device_t dev; 552241470Sgrehan int registered, error; 553241470Sgrehan 554241470Sgrehan dev = sc->vtscsi_dev; 555241470Sgrehan registered = 0; 556241470Sgrehan 557241470Sgrehan VTSCSI_LOCK(sc); 558241470Sgrehan 559241470Sgrehan if (xpt_bus_register(sc->vtscsi_sim, dev, 0) != CAM_SUCCESS) { 560241470Sgrehan error = ENOMEM; 561241470Sgrehan device_printf(dev, "cannot register XPT bus\n"); 562241470Sgrehan goto fail; 563241470Sgrehan } 564241470Sgrehan 565241470Sgrehan registered = 1; 566241470Sgrehan 567241470Sgrehan if (xpt_create_path(&sc->vtscsi_path, NULL, 568241470Sgrehan cam_sim_path(sc->vtscsi_sim), CAM_TARGET_WILDCARD, 569241470Sgrehan CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 570241470Sgrehan error = ENOMEM; 571241470Sgrehan device_printf(dev, "cannot create bus path\n"); 572241470Sgrehan goto fail; 573241470Sgrehan } 574241470Sgrehan 575241470Sgrehan if (vtscsi_register_async(sc) != CAM_REQ_CMP) { 576241470Sgrehan error = EIO; 577241470Sgrehan device_printf(dev, "cannot register async callback\n"); 578241470Sgrehan goto fail; 579241470Sgrehan } 580241470Sgrehan 581253132Sbryanv VTSCSI_UNLOCK(sc); 582253132Sbryanv 583241470Sgrehan return (0); 584241470Sgrehan 585241470Sgrehanfail: 586241470Sgrehan if (sc->vtscsi_path != NULL) { 587241470Sgrehan xpt_free_path(sc->vtscsi_path); 588241470Sgrehan sc->vtscsi_path = NULL; 589241470Sgrehan } 590241470Sgrehan 591241470Sgrehan if (registered != 0) 592241470Sgrehan xpt_bus_deregister(cam_sim_path(sc->vtscsi_sim)); 593241470Sgrehan 594241470Sgrehan VTSCSI_UNLOCK(sc); 595241470Sgrehan 596241470Sgrehan return (error); 597241470Sgrehan} 598241470Sgrehan 599241470Sgrehanstatic void 600241470Sgrehanvtscsi_free_cam(struct vtscsi_softc *sc) 601241470Sgrehan{ 602241470Sgrehan 603241470Sgrehan VTSCSI_LOCK(sc); 604241470Sgrehan 605241470Sgrehan if (sc->vtscsi_path != NULL) { 606241470Sgrehan vtscsi_deregister_async(sc); 607241470Sgrehan 608241470Sgrehan xpt_free_path(sc->vtscsi_path); 609241470Sgrehan sc->vtscsi_path = NULL; 610241470Sgrehan 611241470Sgrehan xpt_bus_deregister(cam_sim_path(sc->vtscsi_sim)); 612241470Sgrehan } 613241470Sgrehan 614241470Sgrehan if (sc->vtscsi_sim != NULL) { 615241470Sgrehan cam_sim_free(sc->vtscsi_sim, 1); 616241470Sgrehan sc->vtscsi_sim = NULL; 617241470Sgrehan } 618241470Sgrehan 619241470Sgrehan VTSCSI_UNLOCK(sc); 620241470Sgrehan} 621241470Sgrehan 622241470Sgrehanstatic void 623241470Sgrehanvtscsi_cam_async(void *cb_arg, uint32_t code, struct cam_path *path, void *arg) 624241470Sgrehan{ 625241470Sgrehan struct cam_sim *sim; 626241470Sgrehan struct vtscsi_softc *sc; 627241470Sgrehan 628241470Sgrehan sim = cb_arg; 629241470Sgrehan sc = cam_sim_softc(sim); 630241470Sgrehan 631241470Sgrehan vtscsi_dprintf(sc, VTSCSI_TRACE, "code=%u\n", code); 632241470Sgrehan 633241470Sgrehan /* 634241470Sgrehan * TODO Once QEMU supports event reporting, we should 635241470Sgrehan * (un)subscribe to events here. 636241470Sgrehan */ 637241470Sgrehan switch (code) { 638241470Sgrehan case AC_FOUND_DEVICE: 639241470Sgrehan break; 640241470Sgrehan case AC_LOST_DEVICE: 641241470Sgrehan break; 642241470Sgrehan } 643241470Sgrehan} 644241470Sgrehan 645241470Sgrehanstatic int 646241470Sgrehanvtscsi_register_async(struct vtscsi_softc *sc) 647241470Sgrehan{ 648241470Sgrehan struct ccb_setasync csa; 649241470Sgrehan 650241470Sgrehan xpt_setup_ccb(&csa.ccb_h, sc->vtscsi_path, 5); 651241470Sgrehan csa.ccb_h.func_code = XPT_SASYNC_CB; 652241470Sgrehan csa.event_enable = AC_LOST_DEVICE | AC_FOUND_DEVICE; 653241470Sgrehan csa.callback = vtscsi_cam_async; 654241470Sgrehan csa.callback_arg = sc->vtscsi_sim; 655241470Sgrehan 656241470Sgrehan xpt_action((union ccb *) &csa); 657241470Sgrehan 658241470Sgrehan return (csa.ccb_h.status); 659241470Sgrehan} 660241470Sgrehan 661241470Sgrehanstatic void 662241470Sgrehanvtscsi_deregister_async(struct vtscsi_softc *sc) 663241470Sgrehan{ 664241470Sgrehan struct ccb_setasync csa; 665241470Sgrehan 666241470Sgrehan xpt_setup_ccb(&csa.ccb_h, sc->vtscsi_path, 5); 667241470Sgrehan csa.ccb_h.func_code = XPT_SASYNC_CB; 668241470Sgrehan csa.event_enable = 0; 669241470Sgrehan csa.callback = vtscsi_cam_async; 670241470Sgrehan csa.callback_arg = sc->vtscsi_sim; 671241470Sgrehan 672241470Sgrehan xpt_action((union ccb *) &csa); 673241470Sgrehan} 674241470Sgrehan 675241470Sgrehanstatic void 676241470Sgrehanvtscsi_cam_action(struct cam_sim *sim, union ccb *ccb) 677241470Sgrehan{ 678241470Sgrehan struct vtscsi_softc *sc; 679241470Sgrehan struct ccb_hdr *ccbh; 680241470Sgrehan 681241470Sgrehan sc = cam_sim_softc(sim); 682241470Sgrehan ccbh = &ccb->ccb_h; 683241470Sgrehan 684241470Sgrehan VTSCSI_LOCK_OWNED(sc); 685241470Sgrehan 686241470Sgrehan if (sc->vtscsi_flags & VTSCSI_FLAG_DETACH) { 687241470Sgrehan /* 688241470Sgrehan * The VTSCSI_MTX is briefly dropped between setting 689241470Sgrehan * VTSCSI_FLAG_DETACH and deregistering with CAM, so 690241470Sgrehan * drop any CCBs that come in during that window. 691241470Sgrehan */ 692241470Sgrehan ccbh->status = CAM_NO_HBA; 693241470Sgrehan xpt_done(ccb); 694241470Sgrehan return; 695241470Sgrehan } 696241470Sgrehan 697241470Sgrehan switch (ccbh->func_code) { 698241470Sgrehan case XPT_SCSI_IO: 699241470Sgrehan vtscsi_cam_scsi_io(sc, sim, ccb); 700241470Sgrehan break; 701241470Sgrehan 702241470Sgrehan case XPT_SET_TRAN_SETTINGS: 703241470Sgrehan ccbh->status = CAM_FUNC_NOTAVAIL; 704241470Sgrehan xpt_done(ccb); 705241470Sgrehan break; 706241470Sgrehan 707241470Sgrehan case XPT_GET_TRAN_SETTINGS: 708241470Sgrehan vtscsi_cam_get_tran_settings(sc, ccb); 709241470Sgrehan break; 710241470Sgrehan 711241470Sgrehan case XPT_RESET_BUS: 712241470Sgrehan vtscsi_cam_reset_bus(sc, ccb); 713241470Sgrehan break; 714241470Sgrehan 715241470Sgrehan case XPT_RESET_DEV: 716241470Sgrehan vtscsi_cam_reset_dev(sc, ccb); 717241470Sgrehan break; 718241470Sgrehan 719241470Sgrehan case XPT_ABORT: 720241470Sgrehan vtscsi_cam_abort(sc, ccb); 721241470Sgrehan break; 722241470Sgrehan 723241470Sgrehan case XPT_CALC_GEOMETRY: 724241470Sgrehan cam_calc_geometry(&ccb->ccg, 1); 725241470Sgrehan xpt_done(ccb); 726241470Sgrehan break; 727241470Sgrehan 728241470Sgrehan case XPT_PATH_INQ: 729241470Sgrehan vtscsi_cam_path_inquiry(sc, sim, ccb); 730241470Sgrehan break; 731241470Sgrehan 732241470Sgrehan default: 733241470Sgrehan vtscsi_dprintf(sc, VTSCSI_ERROR, 734241470Sgrehan "invalid ccb=%p func=%#x\n", ccb, ccbh->func_code); 735241470Sgrehan 736241470Sgrehan ccbh->status = CAM_REQ_INVALID; 737241470Sgrehan xpt_done(ccb); 738241470Sgrehan break; 739241470Sgrehan } 740241470Sgrehan} 741241470Sgrehan 742241470Sgrehanstatic void 743241470Sgrehanvtscsi_cam_poll(struct cam_sim *sim) 744241470Sgrehan{ 745241470Sgrehan struct vtscsi_softc *sc; 746241470Sgrehan 747241470Sgrehan sc = cam_sim_softc(sim); 748241470Sgrehan 749241470Sgrehan vtscsi_complete_vqs_locked(sc); 750241470Sgrehan} 751241470Sgrehan 752241470Sgrehanstatic void 753241470Sgrehanvtscsi_cam_scsi_io(struct vtscsi_softc *sc, struct cam_sim *sim, 754241470Sgrehan union ccb *ccb) 755241470Sgrehan{ 756241470Sgrehan struct ccb_hdr *ccbh; 757241470Sgrehan struct ccb_scsiio *csio; 758241470Sgrehan int error; 759241470Sgrehan 760241470Sgrehan ccbh = &ccb->ccb_h; 761241470Sgrehan csio = &ccb->csio; 762241470Sgrehan 763241470Sgrehan if (csio->cdb_len > VIRTIO_SCSI_CDB_SIZE) { 764241470Sgrehan error = EINVAL; 765241470Sgrehan ccbh->status = CAM_REQ_INVALID; 766241470Sgrehan goto done; 767241470Sgrehan } 768241470Sgrehan 769241470Sgrehan if ((ccbh->flags & CAM_DIR_MASK) == CAM_DIR_BOTH && 770241470Sgrehan (sc->vtscsi_flags & VTSCSI_FLAG_BIDIRECTIONAL) == 0) { 771241470Sgrehan error = EINVAL; 772241470Sgrehan ccbh->status = CAM_REQ_INVALID; 773241470Sgrehan goto done; 774241470Sgrehan } 775241470Sgrehan 776241470Sgrehan error = vtscsi_start_scsi_cmd(sc, ccb); 777241470Sgrehan 778241470Sgrehandone: 779241470Sgrehan if (error) { 780241470Sgrehan vtscsi_dprintf(sc, VTSCSI_ERROR, 781241470Sgrehan "error=%d ccb=%p status=%#x\n", error, ccb, ccbh->status); 782241470Sgrehan xpt_done(ccb); 783241470Sgrehan } 784241470Sgrehan} 785241470Sgrehan 786241470Sgrehanstatic void 787241470Sgrehanvtscsi_cam_get_tran_settings(struct vtscsi_softc *sc, union ccb *ccb) 788241470Sgrehan{ 789241470Sgrehan struct ccb_trans_settings *cts; 790241470Sgrehan struct ccb_trans_settings_scsi *scsi; 791241470Sgrehan 792241470Sgrehan cts = &ccb->cts; 793241470Sgrehan scsi = &cts->proto_specific.scsi; 794241470Sgrehan 795241470Sgrehan cts->protocol = PROTO_SCSI; 796241470Sgrehan cts->protocol_version = SCSI_REV_SPC3; 797241470Sgrehan cts->transport = XPORT_SAS; 798241470Sgrehan cts->transport_version = 0; 799241470Sgrehan 800241470Sgrehan scsi->valid = CTS_SCSI_VALID_TQ; 801241470Sgrehan scsi->flags = CTS_SCSI_FLAGS_TAG_ENB; 802241470Sgrehan 803241470Sgrehan ccb->ccb_h.status = CAM_REQ_CMP; 804241470Sgrehan xpt_done(ccb); 805241470Sgrehan} 806241470Sgrehan 807241470Sgrehanstatic void 808241470Sgrehanvtscsi_cam_reset_bus(struct vtscsi_softc *sc, union ccb *ccb) 809241470Sgrehan{ 810241470Sgrehan int error; 811241470Sgrehan 812241470Sgrehan error = vtscsi_reset_bus(sc); 813241470Sgrehan if (error == 0) 814241470Sgrehan ccb->ccb_h.status = CAM_REQ_CMP; 815241470Sgrehan else 816241470Sgrehan ccb->ccb_h.status = CAM_REQ_CMP_ERR; 817241470Sgrehan 818241470Sgrehan vtscsi_dprintf(sc, VTSCSI_TRACE, "error=%d ccb=%p status=%#x\n", 819241470Sgrehan error, ccb, ccb->ccb_h.status); 820241470Sgrehan 821241470Sgrehan xpt_done(ccb); 822241470Sgrehan} 823241470Sgrehan 824241470Sgrehanstatic void 825241470Sgrehanvtscsi_cam_reset_dev(struct vtscsi_softc *sc, union ccb *ccb) 826241470Sgrehan{ 827241470Sgrehan struct ccb_hdr *ccbh; 828241470Sgrehan struct vtscsi_request *req; 829241470Sgrehan int error; 830241470Sgrehan 831241470Sgrehan ccbh = &ccb->ccb_h; 832241470Sgrehan 833241470Sgrehan req = vtscsi_dequeue_request(sc); 834241470Sgrehan if (req == NULL) { 835241470Sgrehan error = EAGAIN; 836241470Sgrehan vtscsi_freeze_simq(sc, VTSCSI_REQUEST); 837241470Sgrehan goto fail; 838241470Sgrehan } 839241470Sgrehan 840241470Sgrehan req->vsr_ccb = ccb; 841241470Sgrehan 842241470Sgrehan error = vtscsi_execute_reset_dev_cmd(sc, req); 843241470Sgrehan if (error == 0) 844241470Sgrehan return; 845241470Sgrehan 846241470Sgrehan vtscsi_enqueue_request(sc, req); 847241470Sgrehan 848241470Sgrehanfail: 849241470Sgrehan vtscsi_dprintf(sc, VTSCSI_ERROR, "error=%d req=%p ccb=%p\n", 850241470Sgrehan error, req, ccb); 851241470Sgrehan 852241470Sgrehan if (error == EAGAIN) 853241470Sgrehan ccbh->status = CAM_RESRC_UNAVAIL; 854241470Sgrehan else 855241470Sgrehan ccbh->status = CAM_REQ_CMP_ERR; 856241470Sgrehan 857241470Sgrehan xpt_done(ccb); 858241470Sgrehan} 859241470Sgrehan 860241470Sgrehanstatic void 861241470Sgrehanvtscsi_cam_abort(struct vtscsi_softc *sc, union ccb *ccb) 862241470Sgrehan{ 863241470Sgrehan struct vtscsi_request *req; 864241470Sgrehan struct ccb_hdr *ccbh; 865241470Sgrehan int error; 866241470Sgrehan 867241470Sgrehan ccbh = &ccb->ccb_h; 868241470Sgrehan 869241470Sgrehan req = vtscsi_dequeue_request(sc); 870241470Sgrehan if (req == NULL) { 871241470Sgrehan error = EAGAIN; 872241470Sgrehan vtscsi_freeze_simq(sc, VTSCSI_REQUEST); 873241470Sgrehan goto fail; 874241470Sgrehan } 875241470Sgrehan 876241470Sgrehan req->vsr_ccb = ccb; 877241470Sgrehan 878241470Sgrehan error = vtscsi_execute_abort_task_cmd(sc, req); 879241470Sgrehan if (error == 0) 880241470Sgrehan return; 881241470Sgrehan 882241470Sgrehan vtscsi_enqueue_request(sc, req); 883241470Sgrehan 884241470Sgrehanfail: 885241470Sgrehan vtscsi_dprintf(sc, VTSCSI_ERROR, "error=%d req=%p ccb=%p\n", 886241470Sgrehan error, req, ccb); 887241470Sgrehan 888241470Sgrehan if (error == EAGAIN) 889241470Sgrehan ccbh->status = CAM_RESRC_UNAVAIL; 890241470Sgrehan else 891241470Sgrehan ccbh->status = CAM_REQ_CMP_ERR; 892241470Sgrehan 893241470Sgrehan xpt_done(ccb); 894241470Sgrehan} 895241470Sgrehan 896241470Sgrehanstatic void 897241470Sgrehanvtscsi_cam_path_inquiry(struct vtscsi_softc *sc, struct cam_sim *sim, 898241470Sgrehan union ccb *ccb) 899241470Sgrehan{ 900241470Sgrehan device_t dev; 901241470Sgrehan struct ccb_pathinq *cpi; 902241470Sgrehan 903241470Sgrehan dev = sc->vtscsi_dev; 904241470Sgrehan cpi = &ccb->cpi; 905241470Sgrehan 906241470Sgrehan vtscsi_dprintf(sc, VTSCSI_TRACE, "sim=%p ccb=%p\n", sim, ccb); 907241470Sgrehan 908241470Sgrehan cpi->version_num = 1; 909241470Sgrehan cpi->hba_inquiry = PI_TAG_ABLE; 910241470Sgrehan cpi->target_sprt = 0; 911265301Sbryanv cpi->hba_misc = PIM_SEQSCAN | PIM_UNMAPPED; 912241470Sgrehan if (vtscsi_bus_reset_disable != 0) 913241470Sgrehan cpi->hba_misc |= PIM_NOBUSRESET; 914241470Sgrehan cpi->hba_eng_cnt = 0; 915241470Sgrehan 916241470Sgrehan cpi->max_target = sc->vtscsi_max_target; 917241470Sgrehan cpi->max_lun = sc->vtscsi_max_lun; 918241470Sgrehan cpi->initiator_id = VTSCSI_INITIATOR_ID; 919241470Sgrehan 920241470Sgrehan strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 921241470Sgrehan strncpy(cpi->hba_vid, "VirtIO", HBA_IDLEN); 922241470Sgrehan strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 923241470Sgrehan 924241470Sgrehan cpi->unit_number = cam_sim_unit(sim); 925241470Sgrehan cpi->bus_id = cam_sim_bus(sim); 926241470Sgrehan 927241470Sgrehan cpi->base_transfer_speed = 300000; 928241470Sgrehan 929241470Sgrehan cpi->protocol = PROTO_SCSI; 930241470Sgrehan cpi->protocol_version = SCSI_REV_SPC3; 931241470Sgrehan cpi->transport = XPORT_SAS; 932241470Sgrehan cpi->transport_version = 0; 933241470Sgrehan 934241470Sgrehan cpi->maxio = (sc->vtscsi_max_nsegs - VTSCSI_MIN_SEGMENTS - 1) * 935241470Sgrehan PAGE_SIZE; 936241470Sgrehan 937241470Sgrehan cpi->hba_vendor = virtio_get_vendor(dev); 938241470Sgrehan cpi->hba_device = virtio_get_device(dev); 939241470Sgrehan cpi->hba_subvendor = virtio_get_subvendor(dev); 940241470Sgrehan cpi->hba_subdevice = virtio_get_subdevice(dev); 941241470Sgrehan 942241470Sgrehan ccb->ccb_h.status = CAM_REQ_CMP; 943241470Sgrehan xpt_done(ccb); 944241470Sgrehan} 945241470Sgrehan 946241470Sgrehanstatic int 947241470Sgrehanvtscsi_sg_append_scsi_buf(struct vtscsi_softc *sc, struct sglist *sg, 948241470Sgrehan struct ccb_scsiio *csio) 949241470Sgrehan{ 950241470Sgrehan struct ccb_hdr *ccbh; 951241470Sgrehan struct bus_dma_segment *dseg; 952241470Sgrehan int i, error; 953241470Sgrehan 954241470Sgrehan ccbh = &csio->ccb_h; 955241470Sgrehan error = 0; 956241470Sgrehan 957251874Sscottl switch ((ccbh->flags & CAM_DATA_MASK)) { 958251874Sscottl case CAM_DATA_VADDR: 959251874Sscottl error = sglist_append(sg, csio->data_ptr, csio->dxfer_len); 960251874Sscottl break; 961251874Sscottl case CAM_DATA_PADDR: 962251874Sscottl error = sglist_append_phys(sg, 963251874Sscottl (vm_paddr_t)(vm_offset_t) csio->data_ptr, csio->dxfer_len); 964251874Sscottl break; 965251874Sscottl case CAM_DATA_SG: 966251874Sscottl for (i = 0; i < csio->sglist_cnt && error == 0; i++) { 967251874Sscottl dseg = &((struct bus_dma_segment *)csio->data_ptr)[i]; 968241470Sgrehan error = sglist_append(sg, 969251874Sscottl (void *)(vm_offset_t) dseg->ds_addr, dseg->ds_len); 970251874Sscottl } 971251874Sscottl break; 972251874Sscottl case CAM_DATA_SG_PADDR: 973241470Sgrehan for (i = 0; i < csio->sglist_cnt && error == 0; i++) { 974241470Sgrehan dseg = &((struct bus_dma_segment *)csio->data_ptr)[i]; 975251874Sscottl error = sglist_append_phys(sg, 976251874Sscottl (vm_paddr_t) dseg->ds_addr, dseg->ds_len); 977241470Sgrehan } 978251874Sscottl break; 979265301Sbryanv case CAM_DATA_BIO: 980265301Sbryanv error = sglist_append_bio(sg, (struct bio *) csio->data_ptr); 981265301Sbryanv break; 982251874Sscottl default: 983251874Sscottl error = EINVAL; 984251874Sscottl break; 985241470Sgrehan } 986241470Sgrehan 987241470Sgrehan return (error); 988241470Sgrehan} 989241470Sgrehan 990241470Sgrehanstatic int 991241470Sgrehanvtscsi_fill_scsi_cmd_sglist(struct vtscsi_softc *sc, struct vtscsi_request *req, 992241470Sgrehan int *readable, int *writable) 993241470Sgrehan{ 994241470Sgrehan struct sglist *sg; 995241470Sgrehan struct ccb_hdr *ccbh; 996241470Sgrehan struct ccb_scsiio *csio; 997241470Sgrehan struct virtio_scsi_cmd_req *cmd_req; 998241470Sgrehan struct virtio_scsi_cmd_resp *cmd_resp; 999241470Sgrehan int error; 1000241470Sgrehan 1001241470Sgrehan sg = sc->vtscsi_sglist; 1002241470Sgrehan csio = &req->vsr_ccb->csio; 1003241470Sgrehan ccbh = &csio->ccb_h; 1004241470Sgrehan cmd_req = &req->vsr_cmd_req; 1005241470Sgrehan cmd_resp = &req->vsr_cmd_resp; 1006241470Sgrehan 1007241470Sgrehan sglist_reset(sg); 1008241470Sgrehan 1009241470Sgrehan sglist_append(sg, cmd_req, sizeof(struct virtio_scsi_cmd_req)); 1010241470Sgrehan if ((ccbh->flags & CAM_DIR_MASK) == CAM_DIR_OUT) { 1011241470Sgrehan error = vtscsi_sg_append_scsi_buf(sc, sg, csio); 1012241470Sgrehan /* At least one segment must be left for the response. */ 1013241470Sgrehan if (error || sg->sg_nseg == sg->sg_maxseg) 1014241470Sgrehan goto fail; 1015241470Sgrehan } 1016241470Sgrehan 1017241470Sgrehan *readable = sg->sg_nseg; 1018241470Sgrehan 1019241470Sgrehan sglist_append(sg, cmd_resp, sizeof(struct virtio_scsi_cmd_resp)); 1020241470Sgrehan if ((ccbh->flags & CAM_DIR_MASK) == CAM_DIR_IN) { 1021241470Sgrehan error = vtscsi_sg_append_scsi_buf(sc, sg, csio); 1022241470Sgrehan if (error) 1023241470Sgrehan goto fail; 1024241470Sgrehan } 1025241470Sgrehan 1026241470Sgrehan *writable = sg->sg_nseg - *readable; 1027241470Sgrehan 1028241470Sgrehan vtscsi_dprintf(sc, VTSCSI_TRACE, "req=%p ccb=%p readable=%d " 1029241470Sgrehan "writable=%d\n", req, ccbh, *readable, *writable); 1030241470Sgrehan 1031241470Sgrehan return (0); 1032241470Sgrehan 1033241470Sgrehanfail: 1034241470Sgrehan /* 1035241470Sgrehan * This should never happen unless maxio was incorrectly set. 1036241470Sgrehan */ 1037241470Sgrehan vtscsi_set_ccb_status(ccbh, CAM_REQ_TOO_BIG, 0); 1038241470Sgrehan 1039241470Sgrehan vtscsi_dprintf(sc, VTSCSI_ERROR, "error=%d req=%p ccb=%p " 1040241470Sgrehan "nseg=%d maxseg=%d\n", 1041241470Sgrehan error, req, ccbh, sg->sg_nseg, sg->sg_maxseg); 1042241470Sgrehan 1043241470Sgrehan return (EFBIG); 1044241470Sgrehan} 1045241470Sgrehan 1046241470Sgrehanstatic int 1047241470Sgrehanvtscsi_execute_scsi_cmd(struct vtscsi_softc *sc, struct vtscsi_request *req) 1048241470Sgrehan{ 1049241470Sgrehan struct sglist *sg; 1050241470Sgrehan struct virtqueue *vq; 1051241470Sgrehan struct ccb_scsiio *csio; 1052241470Sgrehan struct ccb_hdr *ccbh; 1053241470Sgrehan struct virtio_scsi_cmd_req *cmd_req; 1054241470Sgrehan struct virtio_scsi_cmd_resp *cmd_resp; 1055241470Sgrehan int readable, writable, error; 1056241470Sgrehan 1057241470Sgrehan sg = sc->vtscsi_sglist; 1058241470Sgrehan vq = sc->vtscsi_request_vq; 1059241470Sgrehan csio = &req->vsr_ccb->csio; 1060241470Sgrehan ccbh = &csio->ccb_h; 1061241470Sgrehan cmd_req = &req->vsr_cmd_req; 1062241470Sgrehan cmd_resp = &req->vsr_cmd_resp; 1063241470Sgrehan 1064241470Sgrehan vtscsi_init_scsi_cmd_req(csio, cmd_req); 1065241470Sgrehan 1066241470Sgrehan error = vtscsi_fill_scsi_cmd_sglist(sc, req, &readable, &writable); 1067241470Sgrehan if (error) 1068241470Sgrehan return (error); 1069241470Sgrehan 1070241470Sgrehan req->vsr_complete = vtscsi_complete_scsi_cmd; 1071241470Sgrehan cmd_resp->response = -1; 1072241470Sgrehan 1073241470Sgrehan error = virtqueue_enqueue(vq, req, sg, readable, writable); 1074241470Sgrehan if (error) { 1075241470Sgrehan vtscsi_dprintf(sc, VTSCSI_ERROR, 1076241470Sgrehan "enqueue error=%d req=%p ccb=%p\n", error, req, ccbh); 1077241470Sgrehan 1078241470Sgrehan ccbh->status = CAM_REQUEUE_REQ; 1079241470Sgrehan vtscsi_freeze_simq(sc, VTSCSI_REQUEST_VQ); 1080241470Sgrehan return (error); 1081241470Sgrehan } 1082241470Sgrehan 1083241470Sgrehan ccbh->status |= CAM_SIM_QUEUED; 1084241470Sgrehan ccbh->ccbh_vtscsi_req = req; 1085241470Sgrehan 1086241470Sgrehan virtqueue_notify(vq); 1087241470Sgrehan 1088241470Sgrehan if (ccbh->timeout != CAM_TIME_INFINITY) { 1089241470Sgrehan req->vsr_flags |= VTSCSI_REQ_FLAG_TIMEOUT_SET; 1090241470Sgrehan callout_reset(&req->vsr_callout, ccbh->timeout * hz / 1000, 1091241470Sgrehan vtscsi_timedout_scsi_cmd, req); 1092241470Sgrehan } 1093241470Sgrehan 1094241470Sgrehan vtscsi_dprintf_req(req, VTSCSI_TRACE, "enqueued req=%p ccb=%p\n", 1095241470Sgrehan req, ccbh); 1096241470Sgrehan 1097241470Sgrehan return (0); 1098241470Sgrehan} 1099241470Sgrehan 1100241470Sgrehanstatic int 1101241470Sgrehanvtscsi_start_scsi_cmd(struct vtscsi_softc *sc, union ccb *ccb) 1102241470Sgrehan{ 1103241470Sgrehan struct vtscsi_request *req; 1104241470Sgrehan int error; 1105241470Sgrehan 1106241470Sgrehan req = vtscsi_dequeue_request(sc); 1107241470Sgrehan if (req == NULL) { 1108241470Sgrehan ccb->ccb_h.status = CAM_REQUEUE_REQ; 1109241470Sgrehan vtscsi_freeze_simq(sc, VTSCSI_REQUEST); 1110241470Sgrehan return (ENOBUFS); 1111241470Sgrehan } 1112241470Sgrehan 1113241470Sgrehan req->vsr_ccb = ccb; 1114241470Sgrehan 1115241470Sgrehan error = vtscsi_execute_scsi_cmd(sc, req); 1116241470Sgrehan if (error) 1117241470Sgrehan vtscsi_enqueue_request(sc, req); 1118241470Sgrehan 1119241470Sgrehan return (error); 1120241470Sgrehan} 1121241470Sgrehan 1122241470Sgrehanstatic void 1123241470Sgrehanvtscsi_complete_abort_timedout_scsi_cmd(struct vtscsi_softc *sc, 1124241470Sgrehan struct vtscsi_request *req) 1125241470Sgrehan{ 1126241470Sgrehan struct virtio_scsi_ctrl_tmf_resp *tmf_resp; 1127241470Sgrehan struct vtscsi_request *to_req; 1128241470Sgrehan uint8_t response; 1129241470Sgrehan 1130241470Sgrehan tmf_resp = &req->vsr_tmf_resp; 1131241470Sgrehan response = tmf_resp->response; 1132241470Sgrehan to_req = req->vsr_timedout_req; 1133241470Sgrehan 1134241470Sgrehan vtscsi_dprintf(sc, VTSCSI_TRACE, "req=%p to_req=%p response=%d\n", 1135241470Sgrehan req, to_req, response); 1136241470Sgrehan 1137241470Sgrehan vtscsi_enqueue_request(sc, req); 1138241470Sgrehan 1139241470Sgrehan /* 1140241470Sgrehan * The timedout request could have completed between when the 1141241470Sgrehan * abort task was sent and when the host processed it. 1142241470Sgrehan */ 1143241470Sgrehan if (to_req->vsr_state != VTSCSI_REQ_STATE_TIMEDOUT) 1144241470Sgrehan return; 1145241470Sgrehan 1146241470Sgrehan /* The timedout request was successfully aborted. */ 1147241470Sgrehan if (response == VIRTIO_SCSI_S_FUNCTION_COMPLETE) 1148241470Sgrehan return; 1149241470Sgrehan 1150241470Sgrehan /* Don't bother if the device is going away. */ 1151241470Sgrehan if (sc->vtscsi_flags & VTSCSI_FLAG_DETACH) 1152241470Sgrehan return; 1153241470Sgrehan 1154241470Sgrehan /* The timedout request will be aborted by the reset. */ 1155241470Sgrehan if (sc->vtscsi_flags & VTSCSI_FLAG_RESET) 1156241470Sgrehan return; 1157241470Sgrehan 1158241470Sgrehan vtscsi_reset_bus(sc); 1159241470Sgrehan} 1160241470Sgrehan 1161241470Sgrehanstatic int 1162241470Sgrehanvtscsi_abort_timedout_scsi_cmd(struct vtscsi_softc *sc, 1163241470Sgrehan struct vtscsi_request *to_req) 1164241470Sgrehan{ 1165241470Sgrehan struct sglist *sg; 1166241470Sgrehan struct ccb_hdr *to_ccbh; 1167241470Sgrehan struct vtscsi_request *req; 1168241470Sgrehan struct virtio_scsi_ctrl_tmf_req *tmf_req; 1169241470Sgrehan struct virtio_scsi_ctrl_tmf_resp *tmf_resp; 1170241470Sgrehan int error; 1171241470Sgrehan 1172241470Sgrehan sg = sc->vtscsi_sglist; 1173241470Sgrehan to_ccbh = &to_req->vsr_ccb->ccb_h; 1174241470Sgrehan 1175241470Sgrehan req = vtscsi_dequeue_request(sc); 1176241470Sgrehan if (req == NULL) { 1177241470Sgrehan error = ENOBUFS; 1178241470Sgrehan goto fail; 1179241470Sgrehan } 1180241470Sgrehan 1181241470Sgrehan tmf_req = &req->vsr_tmf_req; 1182241470Sgrehan tmf_resp = &req->vsr_tmf_resp; 1183241470Sgrehan 1184241470Sgrehan vtscsi_init_ctrl_tmf_req(to_ccbh, VIRTIO_SCSI_T_TMF_ABORT_TASK, 1185241470Sgrehan (uintptr_t) to_ccbh, tmf_req); 1186241470Sgrehan 1187241470Sgrehan sglist_reset(sg); 1188241470Sgrehan sglist_append(sg, tmf_req, sizeof(struct virtio_scsi_ctrl_tmf_req)); 1189241470Sgrehan sglist_append(sg, tmf_resp, sizeof(struct virtio_scsi_ctrl_tmf_resp)); 1190241470Sgrehan 1191241470Sgrehan req->vsr_timedout_req = to_req; 1192241470Sgrehan req->vsr_complete = vtscsi_complete_abort_timedout_scsi_cmd; 1193241470Sgrehan tmf_resp->response = -1; 1194241470Sgrehan 1195241470Sgrehan error = vtscsi_execute_ctrl_req(sc, req, sg, 1, 1, 1196241470Sgrehan VTSCSI_EXECUTE_ASYNC); 1197241470Sgrehan if (error == 0) 1198241470Sgrehan return (0); 1199241470Sgrehan 1200241470Sgrehan vtscsi_enqueue_request(sc, req); 1201241470Sgrehan 1202241470Sgrehanfail: 1203241470Sgrehan vtscsi_dprintf(sc, VTSCSI_ERROR, "error=%d req=%p " 1204241470Sgrehan "timedout req=%p ccb=%p\n", error, req, to_req, to_ccbh); 1205241470Sgrehan 1206241470Sgrehan return (error); 1207241470Sgrehan} 1208241470Sgrehan 1209241470Sgrehanstatic void 1210241470Sgrehanvtscsi_timedout_scsi_cmd(void *xreq) 1211241470Sgrehan{ 1212241470Sgrehan struct vtscsi_softc *sc; 1213241470Sgrehan struct vtscsi_request *to_req; 1214241470Sgrehan 1215241470Sgrehan to_req = xreq; 1216241470Sgrehan sc = to_req->vsr_softc; 1217241470Sgrehan 1218241470Sgrehan vtscsi_dprintf(sc, VTSCSI_INFO, "timedout req=%p ccb=%p state=%#x\n", 1219241470Sgrehan to_req, to_req->vsr_ccb, to_req->vsr_state); 1220241470Sgrehan 1221241470Sgrehan /* Don't bother if the device is going away. */ 1222241470Sgrehan if (sc->vtscsi_flags & VTSCSI_FLAG_DETACH) 1223241470Sgrehan return; 1224241470Sgrehan 1225241470Sgrehan /* 1226241470Sgrehan * Bail if the request is not in use. We likely raced when 1227241470Sgrehan * stopping the callout handler or it has already been aborted. 1228241470Sgrehan */ 1229241470Sgrehan if (to_req->vsr_state != VTSCSI_REQ_STATE_INUSE || 1230241470Sgrehan (to_req->vsr_flags & VTSCSI_REQ_FLAG_TIMEOUT_SET) == 0) 1231241470Sgrehan return; 1232241470Sgrehan 1233241470Sgrehan /* 1234241470Sgrehan * Complete the request queue in case the timedout request is 1235241470Sgrehan * actually just pending. 1236241470Sgrehan */ 1237241470Sgrehan vtscsi_complete_vq(sc, sc->vtscsi_request_vq); 1238241470Sgrehan if (to_req->vsr_state == VTSCSI_REQ_STATE_FREE) 1239241470Sgrehan return; 1240241470Sgrehan 1241241470Sgrehan sc->vtscsi_stats.scsi_cmd_timeouts++; 1242241470Sgrehan to_req->vsr_state = VTSCSI_REQ_STATE_TIMEDOUT; 1243241470Sgrehan 1244241470Sgrehan if (vtscsi_abort_timedout_scsi_cmd(sc, to_req) == 0) 1245241470Sgrehan return; 1246241470Sgrehan 1247241470Sgrehan vtscsi_dprintf(sc, VTSCSI_ERROR, "resetting bus\n"); 1248241470Sgrehan vtscsi_reset_bus(sc); 1249241470Sgrehan} 1250241470Sgrehan 1251241470Sgrehanstatic cam_status 1252241470Sgrehanvtscsi_scsi_cmd_cam_status(struct virtio_scsi_cmd_resp *cmd_resp) 1253241470Sgrehan{ 1254241470Sgrehan cam_status status; 1255241470Sgrehan 1256241470Sgrehan switch (cmd_resp->response) { 1257241470Sgrehan case VIRTIO_SCSI_S_OK: 1258241470Sgrehan status = CAM_REQ_CMP; 1259241470Sgrehan break; 1260241470Sgrehan case VIRTIO_SCSI_S_OVERRUN: 1261241470Sgrehan status = CAM_DATA_RUN_ERR; 1262241470Sgrehan break; 1263241470Sgrehan case VIRTIO_SCSI_S_ABORTED: 1264241470Sgrehan status = CAM_REQ_ABORTED; 1265241470Sgrehan break; 1266241470Sgrehan case VIRTIO_SCSI_S_BAD_TARGET: 1267253132Sbryanv status = CAM_SEL_TIMEOUT; 1268241470Sgrehan break; 1269241470Sgrehan case VIRTIO_SCSI_S_RESET: 1270241470Sgrehan status = CAM_SCSI_BUS_RESET; 1271241470Sgrehan break; 1272241470Sgrehan case VIRTIO_SCSI_S_BUSY: 1273241470Sgrehan status = CAM_SCSI_BUSY; 1274241470Sgrehan break; 1275241470Sgrehan case VIRTIO_SCSI_S_TRANSPORT_FAILURE: 1276241470Sgrehan case VIRTIO_SCSI_S_TARGET_FAILURE: 1277241470Sgrehan case VIRTIO_SCSI_S_NEXUS_FAILURE: 1278241470Sgrehan status = CAM_SCSI_IT_NEXUS_LOST; 1279241470Sgrehan break; 1280241470Sgrehan default: /* VIRTIO_SCSI_S_FAILURE */ 1281241470Sgrehan status = CAM_REQ_CMP_ERR; 1282241470Sgrehan break; 1283241470Sgrehan } 1284241470Sgrehan 1285241470Sgrehan return (status); 1286241470Sgrehan} 1287241470Sgrehan 1288241470Sgrehanstatic cam_status 1289241470Sgrehanvtscsi_complete_scsi_cmd_response(struct vtscsi_softc *sc, 1290241470Sgrehan struct ccb_scsiio *csio, struct virtio_scsi_cmd_resp *cmd_resp) 1291241470Sgrehan{ 1292241470Sgrehan cam_status status; 1293241470Sgrehan 1294241470Sgrehan csio->scsi_status = cmd_resp->status; 1295241470Sgrehan csio->resid = cmd_resp->resid; 1296241470Sgrehan 1297241470Sgrehan if (csio->scsi_status == SCSI_STATUS_OK) 1298241470Sgrehan status = CAM_REQ_CMP; 1299241470Sgrehan else 1300241470Sgrehan status = CAM_SCSI_STATUS_ERROR; 1301241470Sgrehan 1302241470Sgrehan if (cmd_resp->sense_len > 0) { 1303241470Sgrehan status |= CAM_AUTOSNS_VALID; 1304241470Sgrehan 1305241470Sgrehan if (cmd_resp->sense_len < csio->sense_len) 1306241470Sgrehan csio->sense_resid = csio->sense_len - 1307241470Sgrehan cmd_resp->sense_len; 1308241470Sgrehan else 1309241470Sgrehan csio->sense_resid = 0; 1310241470Sgrehan 1311241470Sgrehan bzero(&csio->sense_data, sizeof(csio->sense_data)); 1312241470Sgrehan memcpy(cmd_resp->sense, &csio->sense_data, 1313241470Sgrehan csio->sense_len - csio->sense_resid); 1314241470Sgrehan } 1315241470Sgrehan 1316241470Sgrehan vtscsi_dprintf(sc, status == CAM_REQ_CMP ? VTSCSI_TRACE : VTSCSI_ERROR, 1317241470Sgrehan "ccb=%p scsi_status=%#x resid=%u sense_resid=%u\n", 1318241470Sgrehan csio, csio->scsi_status, csio->resid, csio->sense_resid); 1319241470Sgrehan 1320241470Sgrehan return (status); 1321241470Sgrehan} 1322241470Sgrehan 1323241470Sgrehanstatic void 1324241470Sgrehanvtscsi_complete_scsi_cmd(struct vtscsi_softc *sc, struct vtscsi_request *req) 1325241470Sgrehan{ 1326241470Sgrehan struct ccb_hdr *ccbh; 1327241470Sgrehan struct ccb_scsiio *csio; 1328241470Sgrehan struct virtio_scsi_cmd_resp *cmd_resp; 1329241470Sgrehan cam_status status; 1330241470Sgrehan 1331241470Sgrehan csio = &req->vsr_ccb->csio; 1332241470Sgrehan ccbh = &csio->ccb_h; 1333241470Sgrehan cmd_resp = &req->vsr_cmd_resp; 1334241470Sgrehan 1335241470Sgrehan KASSERT(ccbh->ccbh_vtscsi_req == req, 1336241470Sgrehan ("ccb %p req mismatch %p/%p", ccbh, ccbh->ccbh_vtscsi_req, req)); 1337241470Sgrehan 1338241470Sgrehan if (req->vsr_flags & VTSCSI_REQ_FLAG_TIMEOUT_SET) 1339241470Sgrehan callout_stop(&req->vsr_callout); 1340241470Sgrehan 1341241470Sgrehan status = vtscsi_scsi_cmd_cam_status(cmd_resp); 1342241470Sgrehan if (status == CAM_REQ_ABORTED) { 1343241470Sgrehan if (req->vsr_state == VTSCSI_REQ_STATE_TIMEDOUT) 1344241470Sgrehan status = CAM_CMD_TIMEOUT; 1345241470Sgrehan } else if (status == CAM_REQ_CMP) 1346241470Sgrehan status = vtscsi_complete_scsi_cmd_response(sc, csio, cmd_resp); 1347241470Sgrehan 1348241470Sgrehan if ((status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 1349241470Sgrehan status |= CAM_DEV_QFRZN; 1350241470Sgrehan xpt_freeze_devq(ccbh->path, 1); 1351241470Sgrehan } 1352241470Sgrehan 1353241470Sgrehan if (vtscsi_thaw_simq(sc, VTSCSI_REQUEST | VTSCSI_REQUEST_VQ) != 0) 1354241470Sgrehan status |= CAM_RELEASE_SIMQ; 1355241470Sgrehan 1356241470Sgrehan vtscsi_dprintf(sc, VTSCSI_TRACE, "req=%p ccb=%p status=%#x\n", 1357241470Sgrehan req, ccbh, status); 1358241470Sgrehan 1359241470Sgrehan ccbh->status = status; 1360241470Sgrehan xpt_done(req->vsr_ccb); 1361241470Sgrehan vtscsi_enqueue_request(sc, req); 1362241470Sgrehan} 1363241470Sgrehan 1364241470Sgrehanstatic void 1365241470Sgrehanvtscsi_poll_ctrl_req(struct vtscsi_softc *sc, struct vtscsi_request *req) 1366241470Sgrehan{ 1367241470Sgrehan 1368241470Sgrehan /* XXX We probably shouldn't poll forever. */ 1369241470Sgrehan req->vsr_flags |= VTSCSI_REQ_FLAG_POLLED; 1370241470Sgrehan do 1371241470Sgrehan vtscsi_complete_vq(sc, sc->vtscsi_control_vq); 1372241470Sgrehan while ((req->vsr_flags & VTSCSI_REQ_FLAG_COMPLETE) == 0); 1373241470Sgrehan 1374241470Sgrehan req->vsr_flags &= ~VTSCSI_REQ_FLAG_POLLED; 1375241470Sgrehan} 1376241470Sgrehan 1377241470Sgrehanstatic int 1378241470Sgrehanvtscsi_execute_ctrl_req(struct vtscsi_softc *sc, struct vtscsi_request *req, 1379241470Sgrehan struct sglist *sg, int readable, int writable, int flag) 1380241470Sgrehan{ 1381241470Sgrehan struct virtqueue *vq; 1382241470Sgrehan int error; 1383241470Sgrehan 1384241470Sgrehan vq = sc->vtscsi_control_vq; 1385241470Sgrehan 1386241470Sgrehan MPASS(flag == VTSCSI_EXECUTE_POLL || req->vsr_complete != NULL); 1387241470Sgrehan 1388241470Sgrehan error = virtqueue_enqueue(vq, req, sg, readable, writable); 1389241470Sgrehan if (error) { 1390241470Sgrehan /* 1391241470Sgrehan * Return EAGAIN when the virtqueue does not have enough 1392241470Sgrehan * descriptors available. 1393241470Sgrehan */ 1394241470Sgrehan if (error == ENOSPC || error == EMSGSIZE) 1395241470Sgrehan error = EAGAIN; 1396241470Sgrehan 1397241470Sgrehan return (error); 1398241470Sgrehan } 1399241470Sgrehan 1400241470Sgrehan virtqueue_notify(vq); 1401241470Sgrehan if (flag == VTSCSI_EXECUTE_POLL) 1402241470Sgrehan vtscsi_poll_ctrl_req(sc, req); 1403241470Sgrehan 1404241470Sgrehan return (0); 1405241470Sgrehan} 1406241470Sgrehan 1407241470Sgrehanstatic void 1408241470Sgrehanvtscsi_complete_abort_task_cmd(struct vtscsi_softc *sc, 1409241470Sgrehan struct vtscsi_request *req) 1410241470Sgrehan{ 1411241470Sgrehan union ccb *ccb; 1412241470Sgrehan struct ccb_hdr *ccbh; 1413241470Sgrehan struct virtio_scsi_ctrl_tmf_resp *tmf_resp; 1414241470Sgrehan 1415241470Sgrehan ccb = req->vsr_ccb; 1416241470Sgrehan ccbh = &ccb->ccb_h; 1417241470Sgrehan tmf_resp = &req->vsr_tmf_resp; 1418241470Sgrehan 1419241470Sgrehan switch (tmf_resp->response) { 1420241470Sgrehan case VIRTIO_SCSI_S_FUNCTION_COMPLETE: 1421241470Sgrehan ccbh->status = CAM_REQ_CMP; 1422241470Sgrehan break; 1423241470Sgrehan case VIRTIO_SCSI_S_FUNCTION_REJECTED: 1424241470Sgrehan ccbh->status = CAM_UA_ABORT; 1425241470Sgrehan break; 1426241470Sgrehan default: 1427241470Sgrehan ccbh->status = CAM_REQ_CMP_ERR; 1428241470Sgrehan break; 1429241470Sgrehan } 1430241470Sgrehan 1431241470Sgrehan xpt_done(ccb); 1432241470Sgrehan vtscsi_enqueue_request(sc, req); 1433241470Sgrehan} 1434241470Sgrehan 1435241470Sgrehanstatic int 1436241470Sgrehanvtscsi_execute_abort_task_cmd(struct vtscsi_softc *sc, 1437241470Sgrehan struct vtscsi_request *req) 1438241470Sgrehan{ 1439241470Sgrehan struct sglist *sg; 1440241470Sgrehan struct ccb_abort *cab; 1441241470Sgrehan struct ccb_hdr *ccbh; 1442241470Sgrehan struct ccb_hdr *abort_ccbh; 1443241470Sgrehan struct vtscsi_request *abort_req; 1444241470Sgrehan struct virtio_scsi_ctrl_tmf_req *tmf_req; 1445241470Sgrehan struct virtio_scsi_ctrl_tmf_resp *tmf_resp; 1446241470Sgrehan int error; 1447241470Sgrehan 1448241470Sgrehan sg = sc->vtscsi_sglist; 1449241470Sgrehan cab = &req->vsr_ccb->cab; 1450241470Sgrehan ccbh = &cab->ccb_h; 1451241470Sgrehan tmf_req = &req->vsr_tmf_req; 1452241470Sgrehan tmf_resp = &req->vsr_tmf_resp; 1453241470Sgrehan 1454241470Sgrehan /* CCB header and request that's to be aborted. */ 1455241470Sgrehan abort_ccbh = &cab->abort_ccb->ccb_h; 1456241470Sgrehan abort_req = abort_ccbh->ccbh_vtscsi_req; 1457241470Sgrehan 1458241470Sgrehan if (abort_ccbh->func_code != XPT_SCSI_IO || abort_req == NULL) { 1459241470Sgrehan error = EINVAL; 1460241470Sgrehan goto fail; 1461241470Sgrehan } 1462241470Sgrehan 1463241470Sgrehan /* Only attempt to abort requests that could be in-flight. */ 1464241470Sgrehan if (abort_req->vsr_state != VTSCSI_REQ_STATE_INUSE) { 1465241470Sgrehan error = EALREADY; 1466241470Sgrehan goto fail; 1467241470Sgrehan } 1468241470Sgrehan 1469241470Sgrehan abort_req->vsr_state = VTSCSI_REQ_STATE_ABORTED; 1470241470Sgrehan if (abort_req->vsr_flags & VTSCSI_REQ_FLAG_TIMEOUT_SET) 1471241470Sgrehan callout_stop(&abort_req->vsr_callout); 1472241470Sgrehan 1473241470Sgrehan vtscsi_init_ctrl_tmf_req(ccbh, VIRTIO_SCSI_T_TMF_ABORT_TASK, 1474241470Sgrehan (uintptr_t) abort_ccbh, tmf_req); 1475241470Sgrehan 1476241470Sgrehan sglist_reset(sg); 1477241470Sgrehan sglist_append(sg, tmf_req, sizeof(struct virtio_scsi_ctrl_tmf_req)); 1478241470Sgrehan sglist_append(sg, tmf_resp, sizeof(struct virtio_scsi_ctrl_tmf_resp)); 1479241470Sgrehan 1480241470Sgrehan req->vsr_complete = vtscsi_complete_abort_task_cmd; 1481241470Sgrehan tmf_resp->response = -1; 1482241470Sgrehan 1483241470Sgrehan error = vtscsi_execute_ctrl_req(sc, req, sg, 1, 1, 1484241470Sgrehan VTSCSI_EXECUTE_ASYNC); 1485241470Sgrehan 1486241470Sgrehanfail: 1487241470Sgrehan vtscsi_dprintf(sc, VTSCSI_TRACE, "error=%d req=%p abort_ccb=%p " 1488241470Sgrehan "abort_req=%p\n", error, req, abort_ccbh, abort_req); 1489241470Sgrehan 1490241470Sgrehan return (error); 1491241470Sgrehan} 1492241470Sgrehan 1493241470Sgrehanstatic void 1494241470Sgrehanvtscsi_complete_reset_dev_cmd(struct vtscsi_softc *sc, 1495241470Sgrehan struct vtscsi_request *req) 1496241470Sgrehan{ 1497241470Sgrehan union ccb *ccb; 1498241470Sgrehan struct ccb_hdr *ccbh; 1499241470Sgrehan struct virtio_scsi_ctrl_tmf_resp *tmf_resp; 1500241470Sgrehan 1501241470Sgrehan ccb = req->vsr_ccb; 1502241470Sgrehan ccbh = &ccb->ccb_h; 1503241470Sgrehan tmf_resp = &req->vsr_tmf_resp; 1504241470Sgrehan 1505241470Sgrehan vtscsi_dprintf(sc, VTSCSI_TRACE, "req=%p ccb=%p response=%d\n", 1506241470Sgrehan req, ccb, tmf_resp->response); 1507241470Sgrehan 1508241470Sgrehan if (tmf_resp->response == VIRTIO_SCSI_S_FUNCTION_COMPLETE) { 1509241470Sgrehan ccbh->status = CAM_REQ_CMP; 1510241470Sgrehan vtscsi_announce(sc, AC_SENT_BDR, ccbh->target_id, 1511241470Sgrehan ccbh->target_lun); 1512241470Sgrehan } else 1513241470Sgrehan ccbh->status = CAM_REQ_CMP_ERR; 1514241470Sgrehan 1515241470Sgrehan xpt_done(ccb); 1516241470Sgrehan vtscsi_enqueue_request(sc, req); 1517241470Sgrehan} 1518241470Sgrehan 1519241470Sgrehanstatic int 1520241470Sgrehanvtscsi_execute_reset_dev_cmd(struct vtscsi_softc *sc, 1521241470Sgrehan struct vtscsi_request *req) 1522241470Sgrehan{ 1523241470Sgrehan struct sglist *sg; 1524241470Sgrehan struct ccb_resetdev *crd; 1525241470Sgrehan struct ccb_hdr *ccbh; 1526241470Sgrehan struct virtio_scsi_ctrl_tmf_req *tmf_req; 1527241470Sgrehan struct virtio_scsi_ctrl_tmf_resp *tmf_resp; 1528241470Sgrehan uint32_t subtype; 1529241470Sgrehan int error; 1530241470Sgrehan 1531241470Sgrehan sg = sc->vtscsi_sglist; 1532241470Sgrehan crd = &req->vsr_ccb->crd; 1533241470Sgrehan ccbh = &crd->ccb_h; 1534241470Sgrehan tmf_req = &req->vsr_tmf_req; 1535241470Sgrehan tmf_resp = &req->vsr_tmf_resp; 1536241470Sgrehan 1537241470Sgrehan if (ccbh->target_lun == CAM_LUN_WILDCARD) 1538241470Sgrehan subtype = VIRTIO_SCSI_T_TMF_I_T_NEXUS_RESET; 1539241470Sgrehan else 1540241470Sgrehan subtype = VIRTIO_SCSI_T_TMF_LOGICAL_UNIT_RESET; 1541241470Sgrehan 1542241470Sgrehan vtscsi_init_ctrl_tmf_req(ccbh, subtype, 0, tmf_req); 1543241470Sgrehan 1544241470Sgrehan sglist_reset(sg); 1545241470Sgrehan sglist_append(sg, tmf_req, sizeof(struct virtio_scsi_ctrl_tmf_req)); 1546241470Sgrehan sglist_append(sg, tmf_resp, sizeof(struct virtio_scsi_ctrl_tmf_resp)); 1547241470Sgrehan 1548241470Sgrehan req->vsr_complete = vtscsi_complete_reset_dev_cmd; 1549241470Sgrehan tmf_resp->response = -1; 1550241470Sgrehan 1551241470Sgrehan error = vtscsi_execute_ctrl_req(sc, req, sg, 1, 1, 1552241470Sgrehan VTSCSI_EXECUTE_ASYNC); 1553241470Sgrehan 1554241470Sgrehan vtscsi_dprintf(sc, VTSCSI_TRACE, "error=%d req=%p ccb=%p\n", 1555241470Sgrehan error, req, ccbh); 1556241470Sgrehan 1557241470Sgrehan return (error); 1558241470Sgrehan} 1559241470Sgrehan 1560241470Sgrehanstatic void 1561241470Sgrehanvtscsi_get_request_lun(uint8_t lun[], target_id_t *target_id, lun_id_t *lun_id) 1562241470Sgrehan{ 1563241470Sgrehan 1564241470Sgrehan *target_id = lun[1]; 1565241470Sgrehan *lun_id = (lun[2] << 8) | lun[3]; 1566241470Sgrehan} 1567241470Sgrehan 1568241470Sgrehanstatic void 1569241470Sgrehanvtscsi_set_request_lun(struct ccb_hdr *ccbh, uint8_t lun[]) 1570241470Sgrehan{ 1571241470Sgrehan 1572241470Sgrehan lun[0] = 1; 1573241470Sgrehan lun[1] = ccbh->target_id; 1574241470Sgrehan lun[2] = 0x40 | ((ccbh->target_lun >> 8) & 0x3F); 1575260838Sbryanv lun[3] = ccbh->target_lun & 0xFF; 1576241470Sgrehan} 1577241470Sgrehan 1578241470Sgrehanstatic void 1579241470Sgrehanvtscsi_init_scsi_cmd_req(struct ccb_scsiio *csio, 1580241470Sgrehan struct virtio_scsi_cmd_req *cmd_req) 1581241470Sgrehan{ 1582241470Sgrehan uint8_t attr; 1583241470Sgrehan 1584241470Sgrehan switch (csio->tag_action) { 1585241470Sgrehan case MSG_HEAD_OF_Q_TAG: 1586241470Sgrehan attr = VIRTIO_SCSI_S_HEAD; 1587241470Sgrehan break; 1588241470Sgrehan case MSG_ORDERED_Q_TAG: 1589241470Sgrehan attr = VIRTIO_SCSI_S_ORDERED; 1590241470Sgrehan break; 1591241470Sgrehan case MSG_ACA_TASK: 1592241470Sgrehan attr = VIRTIO_SCSI_S_ACA; 1593241470Sgrehan break; 1594241470Sgrehan default: /* MSG_SIMPLE_Q_TAG */ 1595241470Sgrehan attr = VIRTIO_SCSI_S_SIMPLE; 1596241470Sgrehan break; 1597241470Sgrehan } 1598241470Sgrehan 1599241470Sgrehan vtscsi_set_request_lun(&csio->ccb_h, cmd_req->lun); 1600241470Sgrehan cmd_req->tag = (uintptr_t) csio; 1601241470Sgrehan cmd_req->task_attr = attr; 1602241470Sgrehan 1603241470Sgrehan memcpy(cmd_req->cdb, 1604241470Sgrehan csio->ccb_h.flags & CAM_CDB_POINTER ? 1605241470Sgrehan csio->cdb_io.cdb_ptr : csio->cdb_io.cdb_bytes, 1606241470Sgrehan csio->cdb_len); 1607241470Sgrehan} 1608241470Sgrehan 1609241470Sgrehanstatic void 1610241470Sgrehanvtscsi_init_ctrl_tmf_req(struct ccb_hdr *ccbh, uint32_t subtype, 1611241470Sgrehan uintptr_t tag, struct virtio_scsi_ctrl_tmf_req *tmf_req) 1612241470Sgrehan{ 1613241470Sgrehan 1614241470Sgrehan vtscsi_set_request_lun(ccbh, tmf_req->lun); 1615241470Sgrehan 1616241470Sgrehan tmf_req->type = VIRTIO_SCSI_T_TMF; 1617241470Sgrehan tmf_req->subtype = subtype; 1618241470Sgrehan tmf_req->tag = tag; 1619241470Sgrehan} 1620241470Sgrehan 1621241470Sgrehanstatic void 1622241470Sgrehanvtscsi_freeze_simq(struct vtscsi_softc *sc, int reason) 1623241470Sgrehan{ 1624241470Sgrehan int frozen; 1625241470Sgrehan 1626241470Sgrehan frozen = sc->vtscsi_frozen; 1627241470Sgrehan 1628241470Sgrehan if (reason & VTSCSI_REQUEST && 1629241470Sgrehan (sc->vtscsi_frozen & VTSCSI_FROZEN_NO_REQUESTS) == 0) 1630241470Sgrehan sc->vtscsi_frozen |= VTSCSI_FROZEN_NO_REQUESTS; 1631241470Sgrehan 1632241470Sgrehan if (reason & VTSCSI_REQUEST_VQ && 1633241470Sgrehan (sc->vtscsi_frozen & VTSCSI_FROZEN_REQUEST_VQ_FULL) == 0) 1634241470Sgrehan sc->vtscsi_frozen |= VTSCSI_FROZEN_REQUEST_VQ_FULL; 1635241470Sgrehan 1636241470Sgrehan /* Freeze the SIMQ if transitioned to frozen. */ 1637241470Sgrehan if (frozen == 0 && sc->vtscsi_frozen != 0) { 1638241470Sgrehan vtscsi_dprintf(sc, VTSCSI_INFO, "SIMQ frozen\n"); 1639241470Sgrehan xpt_freeze_simq(sc->vtscsi_sim, 1); 1640241470Sgrehan } 1641241470Sgrehan} 1642241470Sgrehan 1643241470Sgrehanstatic int 1644241470Sgrehanvtscsi_thaw_simq(struct vtscsi_softc *sc, int reason) 1645241470Sgrehan{ 1646241470Sgrehan int thawed; 1647241470Sgrehan 1648241470Sgrehan if (sc->vtscsi_frozen == 0 || reason == 0) 1649241470Sgrehan return (0); 1650241470Sgrehan 1651241470Sgrehan if (reason & VTSCSI_REQUEST && 1652241470Sgrehan sc->vtscsi_frozen & VTSCSI_FROZEN_NO_REQUESTS) 1653241470Sgrehan sc->vtscsi_frozen &= ~VTSCSI_FROZEN_NO_REQUESTS; 1654241470Sgrehan 1655241470Sgrehan if (reason & VTSCSI_REQUEST_VQ && 1656241470Sgrehan sc->vtscsi_frozen & VTSCSI_FROZEN_REQUEST_VQ_FULL) 1657241470Sgrehan sc->vtscsi_frozen &= ~VTSCSI_FROZEN_REQUEST_VQ_FULL; 1658241470Sgrehan 1659241470Sgrehan thawed = sc->vtscsi_frozen == 0; 1660241470Sgrehan if (thawed != 0) 1661241470Sgrehan vtscsi_dprintf(sc, VTSCSI_INFO, "SIMQ thawed\n"); 1662241470Sgrehan 1663241470Sgrehan return (thawed); 1664241470Sgrehan} 1665241470Sgrehan 1666241470Sgrehanstatic void 1667241470Sgrehanvtscsi_announce(struct vtscsi_softc *sc, uint32_t ac_code, 1668241470Sgrehan target_id_t target_id, lun_id_t lun_id) 1669241470Sgrehan{ 1670241470Sgrehan struct cam_path *path; 1671241470Sgrehan 1672241470Sgrehan /* Use the wildcard path from our softc for bus announcements. */ 1673241470Sgrehan if (target_id == CAM_TARGET_WILDCARD && lun_id == CAM_LUN_WILDCARD) { 1674241470Sgrehan xpt_async(ac_code, sc->vtscsi_path, NULL); 1675241470Sgrehan return; 1676241470Sgrehan } 1677241470Sgrehan 1678241470Sgrehan if (xpt_create_path(&path, NULL, cam_sim_path(sc->vtscsi_sim), 1679241470Sgrehan target_id, lun_id) != CAM_REQ_CMP) { 1680241470Sgrehan vtscsi_dprintf(sc, VTSCSI_ERROR, "cannot create path\n"); 1681241470Sgrehan return; 1682241470Sgrehan } 1683241470Sgrehan 1684241470Sgrehan xpt_async(ac_code, path, NULL); 1685241470Sgrehan xpt_free_path(path); 1686241470Sgrehan} 1687241470Sgrehan 1688241470Sgrehanstatic void 1689241470Sgrehanvtscsi_execute_rescan(struct vtscsi_softc *sc, target_id_t target_id, 1690241470Sgrehan lun_id_t lun_id) 1691241470Sgrehan{ 1692241470Sgrehan union ccb *ccb; 1693241470Sgrehan cam_status status; 1694241470Sgrehan 1695241470Sgrehan ccb = xpt_alloc_ccb_nowait(); 1696241470Sgrehan if (ccb == NULL) { 1697241470Sgrehan vtscsi_dprintf(sc, VTSCSI_ERROR, "cannot allocate CCB\n"); 1698241470Sgrehan return; 1699241470Sgrehan } 1700241470Sgrehan 1701253037Smav status = xpt_create_path(&ccb->ccb_h.path, NULL, 1702241470Sgrehan cam_sim_path(sc->vtscsi_sim), target_id, lun_id); 1703241470Sgrehan if (status != CAM_REQ_CMP) { 1704241470Sgrehan xpt_free_ccb(ccb); 1705241470Sgrehan return; 1706241470Sgrehan } 1707241470Sgrehan 1708241470Sgrehan xpt_rescan(ccb); 1709241470Sgrehan} 1710241470Sgrehan 1711241470Sgrehanstatic void 1712241470Sgrehanvtscsi_execute_rescan_bus(struct vtscsi_softc *sc) 1713241470Sgrehan{ 1714241470Sgrehan 1715241470Sgrehan vtscsi_execute_rescan(sc, CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); 1716241470Sgrehan} 1717241470Sgrehan 1718241470Sgrehanstatic void 1719241470Sgrehanvtscsi_transport_reset_event(struct vtscsi_softc *sc, 1720241470Sgrehan struct virtio_scsi_event *event) 1721241470Sgrehan{ 1722241470Sgrehan target_id_t target_id; 1723241470Sgrehan lun_id_t lun_id; 1724241470Sgrehan 1725241470Sgrehan vtscsi_get_request_lun(event->lun, &target_id, &lun_id); 1726241470Sgrehan 1727241470Sgrehan switch (event->reason) { 1728241470Sgrehan case VIRTIO_SCSI_EVT_RESET_RESCAN: 1729241470Sgrehan case VIRTIO_SCSI_EVT_RESET_REMOVED: 1730241470Sgrehan vtscsi_execute_rescan(sc, target_id, lun_id); 1731241470Sgrehan break; 1732241470Sgrehan default: 1733241470Sgrehan device_printf(sc->vtscsi_dev, 1734241470Sgrehan "unhandled transport event reason: %d\n", event->reason); 1735241470Sgrehan break; 1736241470Sgrehan } 1737241470Sgrehan} 1738241470Sgrehan 1739241470Sgrehanstatic void 1740241470Sgrehanvtscsi_handle_event(struct vtscsi_softc *sc, struct virtio_scsi_event *event) 1741241470Sgrehan{ 1742241470Sgrehan int error; 1743241470Sgrehan 1744241470Sgrehan if ((event->event & VIRTIO_SCSI_T_EVENTS_MISSED) == 0) { 1745241470Sgrehan switch (event->event) { 1746241470Sgrehan case VIRTIO_SCSI_T_TRANSPORT_RESET: 1747241470Sgrehan vtscsi_transport_reset_event(sc, event); 1748241470Sgrehan break; 1749241470Sgrehan default: 1750241470Sgrehan device_printf(sc->vtscsi_dev, 1751241470Sgrehan "unhandled event: %d\n", event->event); 1752241470Sgrehan break; 1753241470Sgrehan } 1754241470Sgrehan } else 1755241470Sgrehan vtscsi_execute_rescan_bus(sc); 1756241470Sgrehan 1757241470Sgrehan /* 1758241470Sgrehan * This should always be successful since the buffer 1759241470Sgrehan * was just dequeued. 1760241470Sgrehan */ 1761241470Sgrehan error = vtscsi_enqueue_event_buf(sc, event); 1762241470Sgrehan KASSERT(error == 0, 1763241470Sgrehan ("cannot requeue event buffer: %d", error)); 1764241470Sgrehan} 1765241470Sgrehan 1766241470Sgrehanstatic int 1767241470Sgrehanvtscsi_enqueue_event_buf(struct vtscsi_softc *sc, 1768241470Sgrehan struct virtio_scsi_event *event) 1769241470Sgrehan{ 1770241470Sgrehan struct sglist *sg; 1771241470Sgrehan struct virtqueue *vq; 1772241470Sgrehan int size, error; 1773241470Sgrehan 1774241470Sgrehan sg = sc->vtscsi_sglist; 1775241470Sgrehan vq = sc->vtscsi_event_vq; 1776241470Sgrehan size = sc->vtscsi_event_buf_size; 1777241470Sgrehan 1778241470Sgrehan bzero(event, size); 1779241470Sgrehan 1780241470Sgrehan sglist_reset(sg); 1781241470Sgrehan error = sglist_append(sg, event, size); 1782241470Sgrehan if (error) 1783241470Sgrehan return (error); 1784241470Sgrehan 1785241470Sgrehan error = virtqueue_enqueue(vq, event, sg, 0, sg->sg_nseg); 1786241470Sgrehan if (error) 1787241470Sgrehan return (error); 1788241470Sgrehan 1789241470Sgrehan virtqueue_notify(vq); 1790241470Sgrehan 1791241470Sgrehan return (0); 1792241470Sgrehan} 1793241470Sgrehan 1794241470Sgrehanstatic int 1795241470Sgrehanvtscsi_init_event_vq(struct vtscsi_softc *sc) 1796241470Sgrehan{ 1797241470Sgrehan struct virtio_scsi_event *event; 1798241470Sgrehan int i, size, error; 1799241470Sgrehan 1800241470Sgrehan /* 1801241470Sgrehan * The first release of QEMU with VirtIO SCSI support would crash 1802241470Sgrehan * when attempting to notify the event virtqueue. This was fixed 1803241470Sgrehan * when hotplug support was added. 1804241470Sgrehan */ 1805241470Sgrehan if (sc->vtscsi_flags & VTSCSI_FLAG_HOTPLUG) 1806241470Sgrehan size = sc->vtscsi_event_buf_size; 1807241470Sgrehan else 1808241470Sgrehan size = 0; 1809241470Sgrehan 1810241470Sgrehan if (size < sizeof(struct virtio_scsi_event)) 1811241470Sgrehan return (0); 1812241470Sgrehan 1813241470Sgrehan for (i = 0; i < VTSCSI_NUM_EVENT_BUFS; i++) { 1814241470Sgrehan event = &sc->vtscsi_event_bufs[i]; 1815241470Sgrehan 1816241470Sgrehan error = vtscsi_enqueue_event_buf(sc, event); 1817241470Sgrehan if (error) 1818241470Sgrehan break; 1819241470Sgrehan } 1820241470Sgrehan 1821241470Sgrehan /* 1822241470Sgrehan * Even just one buffer is enough. Missed events are 1823241470Sgrehan * denoted with the VIRTIO_SCSI_T_EVENTS_MISSED flag. 1824241470Sgrehan */ 1825241470Sgrehan if (i > 0) 1826241470Sgrehan error = 0; 1827241470Sgrehan 1828241470Sgrehan return (error); 1829241470Sgrehan} 1830241470Sgrehan 1831241470Sgrehanstatic void 1832241470Sgrehanvtscsi_reinit_event_vq(struct vtscsi_softc *sc) 1833241470Sgrehan{ 1834241470Sgrehan struct virtio_scsi_event *event; 1835241470Sgrehan int i, error; 1836241470Sgrehan 1837241470Sgrehan if ((sc->vtscsi_flags & VTSCSI_FLAG_HOTPLUG) == 0 || 1838241470Sgrehan sc->vtscsi_event_buf_size < sizeof(struct virtio_scsi_event)) 1839241470Sgrehan return; 1840241470Sgrehan 1841241470Sgrehan for (i = 0; i < VTSCSI_NUM_EVENT_BUFS; i++) { 1842241470Sgrehan event = &sc->vtscsi_event_bufs[i]; 1843241470Sgrehan 1844241470Sgrehan error = vtscsi_enqueue_event_buf(sc, event); 1845241470Sgrehan if (error) 1846241470Sgrehan break; 1847241470Sgrehan } 1848241470Sgrehan 1849241470Sgrehan KASSERT(i > 0, ("cannot reinit event vq: %d", error)); 1850241470Sgrehan} 1851241470Sgrehan 1852241470Sgrehanstatic void 1853241470Sgrehanvtscsi_drain_event_vq(struct vtscsi_softc *sc) 1854241470Sgrehan{ 1855241470Sgrehan struct virtqueue *vq; 1856241470Sgrehan int last; 1857241470Sgrehan 1858241470Sgrehan vq = sc->vtscsi_event_vq; 1859241470Sgrehan last = 0; 1860241470Sgrehan 1861241470Sgrehan while (virtqueue_drain(vq, &last) != NULL) 1862241470Sgrehan ; 1863241470Sgrehan 1864241470Sgrehan KASSERT(virtqueue_empty(vq), ("eventvq not empty")); 1865241470Sgrehan} 1866241470Sgrehan 1867241470Sgrehanstatic void 1868241470Sgrehanvtscsi_complete_vqs_locked(struct vtscsi_softc *sc) 1869241470Sgrehan{ 1870241470Sgrehan 1871241470Sgrehan VTSCSI_LOCK_OWNED(sc); 1872241470Sgrehan 1873241470Sgrehan if (sc->vtscsi_request_vq != NULL) 1874241470Sgrehan vtscsi_complete_vq(sc, sc->vtscsi_request_vq); 1875241470Sgrehan if (sc->vtscsi_control_vq != NULL) 1876241470Sgrehan vtscsi_complete_vq(sc, sc->vtscsi_control_vq); 1877241470Sgrehan} 1878241470Sgrehan 1879241470Sgrehanstatic void 1880241470Sgrehanvtscsi_complete_vqs(struct vtscsi_softc *sc) 1881241470Sgrehan{ 1882241470Sgrehan 1883241470Sgrehan VTSCSI_LOCK(sc); 1884241470Sgrehan vtscsi_complete_vqs_locked(sc); 1885241470Sgrehan VTSCSI_UNLOCK(sc); 1886241470Sgrehan} 1887241470Sgrehan 1888241470Sgrehanstatic void 1889241470Sgrehanvtscsi_cancel_request(struct vtscsi_softc *sc, struct vtscsi_request *req) 1890241470Sgrehan{ 1891241470Sgrehan union ccb *ccb; 1892241470Sgrehan int detach; 1893241470Sgrehan 1894241470Sgrehan ccb = req->vsr_ccb; 1895241470Sgrehan 1896241470Sgrehan vtscsi_dprintf(sc, VTSCSI_TRACE, "req=%p ccb=%p\n", req, ccb); 1897241470Sgrehan 1898241470Sgrehan /* 1899241470Sgrehan * The callout must be drained when detaching since the request is 1900241470Sgrehan * about to be freed. The VTSCSI_MTX must not be held for this in 1901241470Sgrehan * case the callout is pending because there is a deadlock potential. 1902241470Sgrehan * Otherwise, the virtqueue is being drained because of a bus reset 1903241470Sgrehan * so we only need to attempt to stop the callouts. 1904241470Sgrehan */ 1905241470Sgrehan detach = (sc->vtscsi_flags & VTSCSI_FLAG_DETACH) != 0; 1906241470Sgrehan if (detach != 0) 1907241470Sgrehan VTSCSI_LOCK_NOTOWNED(sc); 1908241470Sgrehan else 1909241470Sgrehan VTSCSI_LOCK_OWNED(sc); 1910241470Sgrehan 1911241470Sgrehan if (req->vsr_flags & VTSCSI_REQ_FLAG_TIMEOUT_SET) { 1912241470Sgrehan if (detach != 0) 1913241470Sgrehan callout_drain(&req->vsr_callout); 1914241470Sgrehan else 1915241470Sgrehan callout_stop(&req->vsr_callout); 1916241470Sgrehan } 1917241470Sgrehan 1918241470Sgrehan if (ccb != NULL) { 1919241470Sgrehan if (detach != 0) { 1920241470Sgrehan VTSCSI_LOCK(sc); 1921241470Sgrehan ccb->ccb_h.status = CAM_NO_HBA; 1922241470Sgrehan } else 1923241470Sgrehan ccb->ccb_h.status = CAM_REQUEUE_REQ; 1924241470Sgrehan xpt_done(ccb); 1925241470Sgrehan if (detach != 0) 1926241470Sgrehan VTSCSI_UNLOCK(sc); 1927241470Sgrehan } 1928241470Sgrehan 1929241470Sgrehan vtscsi_enqueue_request(sc, req); 1930241470Sgrehan} 1931241470Sgrehan 1932241470Sgrehanstatic void 1933241470Sgrehanvtscsi_drain_vq(struct vtscsi_softc *sc, struct virtqueue *vq) 1934241470Sgrehan{ 1935241470Sgrehan struct vtscsi_request *req; 1936241470Sgrehan int last; 1937241470Sgrehan 1938241470Sgrehan last = 0; 1939241470Sgrehan 1940241470Sgrehan vtscsi_dprintf(sc, VTSCSI_TRACE, "vq=%p\n", vq); 1941241470Sgrehan 1942241470Sgrehan while ((req = virtqueue_drain(vq, &last)) != NULL) 1943241470Sgrehan vtscsi_cancel_request(sc, req); 1944241470Sgrehan 1945241470Sgrehan KASSERT(virtqueue_empty(vq), ("virtqueue not empty")); 1946241470Sgrehan} 1947241470Sgrehan 1948241470Sgrehanstatic void 1949241470Sgrehanvtscsi_drain_vqs(struct vtscsi_softc *sc) 1950241470Sgrehan{ 1951241470Sgrehan 1952241470Sgrehan if (sc->vtscsi_control_vq != NULL) 1953241470Sgrehan vtscsi_drain_vq(sc, sc->vtscsi_control_vq); 1954241470Sgrehan if (sc->vtscsi_request_vq != NULL) 1955241470Sgrehan vtscsi_drain_vq(sc, sc->vtscsi_request_vq); 1956241470Sgrehan if (sc->vtscsi_event_vq != NULL) 1957241470Sgrehan vtscsi_drain_event_vq(sc); 1958241470Sgrehan} 1959241470Sgrehan 1960241470Sgrehanstatic void 1961241470Sgrehanvtscsi_stop(struct vtscsi_softc *sc) 1962241470Sgrehan{ 1963241470Sgrehan 1964241470Sgrehan vtscsi_disable_vqs_intr(sc); 1965241470Sgrehan virtio_stop(sc->vtscsi_dev); 1966241470Sgrehan} 1967241470Sgrehan 1968241470Sgrehanstatic int 1969241470Sgrehanvtscsi_reset_bus(struct vtscsi_softc *sc) 1970241470Sgrehan{ 1971241470Sgrehan int error; 1972241470Sgrehan 1973241470Sgrehan VTSCSI_LOCK_OWNED(sc); 1974241470Sgrehan 1975241470Sgrehan if (vtscsi_bus_reset_disable != 0) { 1976241470Sgrehan device_printf(sc->vtscsi_dev, "bus reset disabled\n"); 1977241470Sgrehan return (0); 1978241470Sgrehan } 1979241470Sgrehan 1980241470Sgrehan sc->vtscsi_flags |= VTSCSI_FLAG_RESET; 1981241470Sgrehan 1982241470Sgrehan /* 1983241470Sgrehan * vtscsi_stop() will cause the in-flight requests to be canceled. 1984241470Sgrehan * Those requests are then completed here so CAM will retry them 1985241470Sgrehan * after the reset is complete. 1986241470Sgrehan */ 1987241470Sgrehan vtscsi_stop(sc); 1988241470Sgrehan vtscsi_complete_vqs_locked(sc); 1989241470Sgrehan 1990241470Sgrehan /* Rid the virtqueues of any remaining requests. */ 1991241470Sgrehan vtscsi_drain_vqs(sc); 1992241470Sgrehan 1993241470Sgrehan /* 1994241470Sgrehan * Any resource shortage that froze the SIMQ cannot persist across 1995241470Sgrehan * a bus reset so ensure it gets thawed here. 1996241470Sgrehan */ 1997241470Sgrehan if (vtscsi_thaw_simq(sc, VTSCSI_REQUEST | VTSCSI_REQUEST_VQ) != 0) 1998241470Sgrehan xpt_release_simq(sc->vtscsi_sim, 0); 1999241470Sgrehan 2000241470Sgrehan error = vtscsi_reinit(sc); 2001241470Sgrehan if (error) { 2002241470Sgrehan device_printf(sc->vtscsi_dev, 2003241470Sgrehan "reinitialization failed, stopping device...\n"); 2004241470Sgrehan vtscsi_stop(sc); 2005241470Sgrehan } else 2006241470Sgrehan vtscsi_announce(sc, AC_BUS_RESET, CAM_TARGET_WILDCARD, 2007241470Sgrehan CAM_LUN_WILDCARD); 2008241470Sgrehan 2009241470Sgrehan sc->vtscsi_flags &= ~VTSCSI_FLAG_RESET; 2010241470Sgrehan 2011241470Sgrehan return (error); 2012241470Sgrehan} 2013241470Sgrehan 2014241470Sgrehanstatic void 2015241470Sgrehanvtscsi_init_request(struct vtscsi_softc *sc, struct vtscsi_request *req) 2016241470Sgrehan{ 2017241470Sgrehan 2018241470Sgrehan#ifdef INVARIANTS 2019241470Sgrehan int req_nsegs, resp_nsegs; 2020241470Sgrehan 2021241470Sgrehan req_nsegs = sglist_count(&req->vsr_ureq, sizeof(req->vsr_ureq)); 2022241470Sgrehan resp_nsegs = sglist_count(&req->vsr_uresp, sizeof(req->vsr_uresp)); 2023241470Sgrehan 2024241470Sgrehan KASSERT(req_nsegs == 1, ("request crossed page boundary")); 2025241470Sgrehan KASSERT(resp_nsegs == 1, ("response crossed page boundary")); 2026241470Sgrehan#endif 2027241470Sgrehan 2028241470Sgrehan req->vsr_softc = sc; 2029241470Sgrehan callout_init_mtx(&req->vsr_callout, VTSCSI_MTX(sc), 0); 2030241470Sgrehan} 2031241470Sgrehan 2032241470Sgrehanstatic int 2033241470Sgrehanvtscsi_alloc_requests(struct vtscsi_softc *sc) 2034241470Sgrehan{ 2035241470Sgrehan struct vtscsi_request *req; 2036241470Sgrehan int i, nreqs; 2037241470Sgrehan 2038241470Sgrehan /* 2039241470Sgrehan * Commands destined for either the request or control queues come 2040241470Sgrehan * from the same SIM queue. Use the size of the request virtqueue 2041241470Sgrehan * as it (should) be much more frequently used. Some additional 2042241470Sgrehan * requests are allocated for internal (TMF) use. 2043241470Sgrehan */ 2044241470Sgrehan nreqs = virtqueue_size(sc->vtscsi_request_vq); 2045241470Sgrehan if ((sc->vtscsi_flags & VTSCSI_FLAG_INDIRECT) == 0) 2046241470Sgrehan nreqs /= VTSCSI_MIN_SEGMENTS; 2047241470Sgrehan nreqs += VTSCSI_RESERVED_REQUESTS; 2048241470Sgrehan 2049241470Sgrehan for (i = 0; i < nreqs; i++) { 2050241470Sgrehan req = malloc(sizeof(struct vtscsi_request), M_DEVBUF, 2051241470Sgrehan M_NOWAIT); 2052241470Sgrehan if (req == NULL) 2053241470Sgrehan return (ENOMEM); 2054241470Sgrehan 2055241470Sgrehan vtscsi_init_request(sc, req); 2056241470Sgrehan 2057241470Sgrehan sc->vtscsi_nrequests++; 2058241470Sgrehan vtscsi_enqueue_request(sc, req); 2059241470Sgrehan } 2060241470Sgrehan 2061241470Sgrehan return (0); 2062241470Sgrehan} 2063241470Sgrehan 2064241470Sgrehanstatic void 2065241470Sgrehanvtscsi_free_requests(struct vtscsi_softc *sc) 2066241470Sgrehan{ 2067241470Sgrehan struct vtscsi_request *req; 2068241470Sgrehan 2069241470Sgrehan while ((req = vtscsi_dequeue_request(sc)) != NULL) { 2070241470Sgrehan KASSERT(callout_active(&req->vsr_callout) == 0, 2071241470Sgrehan ("request callout still active")); 2072241470Sgrehan 2073241470Sgrehan sc->vtscsi_nrequests--; 2074241470Sgrehan free(req, M_DEVBUF); 2075241470Sgrehan } 2076241470Sgrehan 2077241470Sgrehan KASSERT(sc->vtscsi_nrequests == 0, ("leaked requests: %d", 2078241470Sgrehan sc->vtscsi_nrequests)); 2079241470Sgrehan} 2080241470Sgrehan 2081241470Sgrehanstatic void 2082241470Sgrehanvtscsi_enqueue_request(struct vtscsi_softc *sc, struct vtscsi_request *req) 2083241470Sgrehan{ 2084241470Sgrehan 2085241470Sgrehan KASSERT(req->vsr_softc == sc, 2086241470Sgrehan ("non-matching request vsr_softc %p/%p", req->vsr_softc, sc)); 2087241470Sgrehan 2088241470Sgrehan vtscsi_dprintf(sc, VTSCSI_TRACE, "req=%p\n", req); 2089241470Sgrehan 2090241470Sgrehan /* A request is available so the SIMQ could be released. */ 2091241470Sgrehan if (vtscsi_thaw_simq(sc, VTSCSI_REQUEST) != 0) 2092241470Sgrehan xpt_release_simq(sc->vtscsi_sim, 1); 2093241470Sgrehan 2094241470Sgrehan req->vsr_ccb = NULL; 2095241470Sgrehan req->vsr_complete = NULL; 2096241470Sgrehan req->vsr_ptr0 = NULL; 2097241470Sgrehan req->vsr_state = VTSCSI_REQ_STATE_FREE; 2098241470Sgrehan req->vsr_flags = 0; 2099241470Sgrehan 2100241470Sgrehan bzero(&req->vsr_ureq, sizeof(req->vsr_ureq)); 2101241470Sgrehan bzero(&req->vsr_uresp, sizeof(req->vsr_uresp)); 2102241470Sgrehan 2103241470Sgrehan /* 2104241470Sgrehan * We insert at the tail of the queue in order to make it 2105241470Sgrehan * very unlikely a request will be reused if we race with 2106241470Sgrehan * stopping its callout handler. 2107241470Sgrehan */ 2108241470Sgrehan TAILQ_INSERT_TAIL(&sc->vtscsi_req_free, req, vsr_link); 2109241470Sgrehan} 2110241470Sgrehan 2111241470Sgrehanstatic struct vtscsi_request * 2112241470Sgrehanvtscsi_dequeue_request(struct vtscsi_softc *sc) 2113241470Sgrehan{ 2114241470Sgrehan struct vtscsi_request *req; 2115241470Sgrehan 2116241470Sgrehan req = TAILQ_FIRST(&sc->vtscsi_req_free); 2117241470Sgrehan if (req != NULL) { 2118241470Sgrehan req->vsr_state = VTSCSI_REQ_STATE_INUSE; 2119241470Sgrehan TAILQ_REMOVE(&sc->vtscsi_req_free, req, vsr_link); 2120241470Sgrehan } else 2121241470Sgrehan sc->vtscsi_stats.dequeue_no_requests++; 2122241470Sgrehan 2123241470Sgrehan vtscsi_dprintf(sc, VTSCSI_TRACE, "req=%p\n", req); 2124241470Sgrehan 2125241470Sgrehan return (req); 2126241470Sgrehan} 2127241470Sgrehan 2128241470Sgrehanstatic void 2129241470Sgrehanvtscsi_complete_request(struct vtscsi_request *req) 2130241470Sgrehan{ 2131241470Sgrehan 2132241470Sgrehan if (req->vsr_flags & VTSCSI_REQ_FLAG_POLLED) 2133241470Sgrehan req->vsr_flags |= VTSCSI_REQ_FLAG_COMPLETE; 2134241470Sgrehan 2135241470Sgrehan if (req->vsr_complete != NULL) 2136241470Sgrehan req->vsr_complete(req->vsr_softc, req); 2137241470Sgrehan} 2138241470Sgrehan 2139241470Sgrehanstatic void 2140241470Sgrehanvtscsi_complete_vq(struct vtscsi_softc *sc, struct virtqueue *vq) 2141241470Sgrehan{ 2142241470Sgrehan struct vtscsi_request *req; 2143241470Sgrehan 2144241470Sgrehan VTSCSI_LOCK_OWNED(sc); 2145241470Sgrehan 2146241470Sgrehan while ((req = virtqueue_dequeue(vq, NULL)) != NULL) 2147241470Sgrehan vtscsi_complete_request(req); 2148241470Sgrehan} 2149241470Sgrehan 2150241470Sgrehanstatic void 2151253132Sbryanvvtscsi_control_vq_intr(void *xsc) 2152241470Sgrehan{ 2153241470Sgrehan struct vtscsi_softc *sc; 2154241470Sgrehan struct virtqueue *vq; 2155241470Sgrehan 2156253132Sbryanv sc = xsc; 2157241470Sgrehan vq = sc->vtscsi_control_vq; 2158241470Sgrehan 2159253132Sbryanvagain: 2160241470Sgrehan VTSCSI_LOCK(sc); 2161241470Sgrehan 2162241470Sgrehan vtscsi_complete_vq(sc, sc->vtscsi_control_vq); 2163241470Sgrehan 2164241470Sgrehan if (virtqueue_enable_intr(vq) != 0) { 2165241470Sgrehan virtqueue_disable_intr(vq); 2166241470Sgrehan VTSCSI_UNLOCK(sc); 2167253132Sbryanv goto again; 2168241470Sgrehan } 2169241470Sgrehan 2170241470Sgrehan VTSCSI_UNLOCK(sc); 2171241470Sgrehan} 2172241470Sgrehan 2173241470Sgrehanstatic void 2174253132Sbryanvvtscsi_event_vq_intr(void *xsc) 2175241470Sgrehan{ 2176241470Sgrehan struct vtscsi_softc *sc; 2177241470Sgrehan struct virtqueue *vq; 2178241470Sgrehan struct virtio_scsi_event *event; 2179241470Sgrehan 2180253132Sbryanv sc = xsc; 2181241470Sgrehan vq = sc->vtscsi_event_vq; 2182241470Sgrehan 2183253132Sbryanvagain: 2184241470Sgrehan VTSCSI_LOCK(sc); 2185241470Sgrehan 2186241470Sgrehan while ((event = virtqueue_dequeue(vq, NULL)) != NULL) 2187241470Sgrehan vtscsi_handle_event(sc, event); 2188241470Sgrehan 2189241470Sgrehan if (virtqueue_enable_intr(vq) != 0) { 2190241470Sgrehan virtqueue_disable_intr(vq); 2191241470Sgrehan VTSCSI_UNLOCK(sc); 2192253132Sbryanv goto again; 2193241470Sgrehan } 2194241470Sgrehan 2195241470Sgrehan VTSCSI_UNLOCK(sc); 2196241470Sgrehan} 2197241470Sgrehan 2198241470Sgrehanstatic void 2199253132Sbryanvvtscsi_request_vq_intr(void *xsc) 2200241470Sgrehan{ 2201241470Sgrehan struct vtscsi_softc *sc; 2202241470Sgrehan struct virtqueue *vq; 2203241470Sgrehan 2204253132Sbryanv sc = xsc; 2205241470Sgrehan vq = sc->vtscsi_request_vq; 2206241470Sgrehan 2207253132Sbryanvagain: 2208241470Sgrehan VTSCSI_LOCK(sc); 2209241470Sgrehan 2210241470Sgrehan vtscsi_complete_vq(sc, sc->vtscsi_request_vq); 2211241470Sgrehan 2212241470Sgrehan if (virtqueue_enable_intr(vq) != 0) { 2213241470Sgrehan virtqueue_disable_intr(vq); 2214241470Sgrehan VTSCSI_UNLOCK(sc); 2215253132Sbryanv goto again; 2216241470Sgrehan } 2217241470Sgrehan 2218241470Sgrehan VTSCSI_UNLOCK(sc); 2219241470Sgrehan} 2220241470Sgrehan 2221241470Sgrehanstatic void 2222241470Sgrehanvtscsi_disable_vqs_intr(struct vtscsi_softc *sc) 2223241470Sgrehan{ 2224241470Sgrehan 2225241470Sgrehan virtqueue_disable_intr(sc->vtscsi_control_vq); 2226241470Sgrehan virtqueue_disable_intr(sc->vtscsi_event_vq); 2227241470Sgrehan virtqueue_disable_intr(sc->vtscsi_request_vq); 2228241470Sgrehan} 2229241470Sgrehan 2230241470Sgrehanstatic void 2231241470Sgrehanvtscsi_enable_vqs_intr(struct vtscsi_softc *sc) 2232241470Sgrehan{ 2233241470Sgrehan 2234241470Sgrehan virtqueue_enable_intr(sc->vtscsi_control_vq); 2235241470Sgrehan virtqueue_enable_intr(sc->vtscsi_event_vq); 2236241470Sgrehan virtqueue_enable_intr(sc->vtscsi_request_vq); 2237241470Sgrehan} 2238241470Sgrehan 2239241470Sgrehanstatic void 2240241470Sgrehanvtscsi_get_tunables(struct vtscsi_softc *sc) 2241241470Sgrehan{ 2242241470Sgrehan char tmpstr[64]; 2243241470Sgrehan 2244241470Sgrehan TUNABLE_INT_FETCH("hw.vtscsi.debug_level", &sc->vtscsi_debug); 2245241470Sgrehan 2246241470Sgrehan snprintf(tmpstr, sizeof(tmpstr), "dev.vtscsi.%d.debug_level", 2247241470Sgrehan device_get_unit(sc->vtscsi_dev)); 2248241470Sgrehan TUNABLE_INT_FETCH(tmpstr, &sc->vtscsi_debug); 2249241470Sgrehan} 2250241470Sgrehan 2251241470Sgrehanstatic void 2252241470Sgrehanvtscsi_add_sysctl(struct vtscsi_softc *sc) 2253241470Sgrehan{ 2254241470Sgrehan device_t dev; 2255241470Sgrehan struct vtscsi_statistics *stats; 2256241470Sgrehan struct sysctl_ctx_list *ctx; 2257241470Sgrehan struct sysctl_oid *tree; 2258241470Sgrehan struct sysctl_oid_list *child; 2259241470Sgrehan 2260241470Sgrehan dev = sc->vtscsi_dev; 2261241470Sgrehan stats = &sc->vtscsi_stats; 2262241470Sgrehan ctx = device_get_sysctl_ctx(dev); 2263241470Sgrehan tree = device_get_sysctl_tree(dev); 2264241470Sgrehan child = SYSCTL_CHILDREN(tree); 2265241470Sgrehan 2266241470Sgrehan SYSCTL_ADD_INT(ctx, child, OID_AUTO, "debug_level", 2267241470Sgrehan CTLFLAG_RW, &sc->vtscsi_debug, 0, 2268241470Sgrehan "Debug level"); 2269241470Sgrehan 2270241470Sgrehan SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "scsi_cmd_timeouts", 2271241470Sgrehan CTLFLAG_RD, &stats->scsi_cmd_timeouts, 2272241470Sgrehan "SCSI command timeouts"); 2273241470Sgrehan SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "dequeue_no_requests", 2274241470Sgrehan CTLFLAG_RD, &stats->dequeue_no_requests, 2275241470Sgrehan "No available requests to dequeue"); 2276241470Sgrehan} 2277241470Sgrehan 2278241470Sgrehanstatic void 2279241470Sgrehanvtscsi_printf_req(struct vtscsi_request *req, const char *func, 2280241470Sgrehan const char *fmt, ...) 2281241470Sgrehan{ 2282241470Sgrehan struct vtscsi_softc *sc; 2283241470Sgrehan union ccb *ccb; 2284241470Sgrehan struct sbuf sb; 2285241470Sgrehan va_list ap; 2286241470Sgrehan char str[192]; 2287241470Sgrehan char path_str[64]; 2288241470Sgrehan 2289241470Sgrehan if (req == NULL) 2290241470Sgrehan return; 2291241470Sgrehan 2292241470Sgrehan sc = req->vsr_softc; 2293241470Sgrehan ccb = req->vsr_ccb; 2294241470Sgrehan 2295241470Sgrehan va_start(ap, fmt); 2296241470Sgrehan sbuf_new(&sb, str, sizeof(str), 0); 2297241470Sgrehan 2298241470Sgrehan if (ccb == NULL) { 2299241470Sgrehan sbuf_printf(&sb, "(noperiph:%s%d:%u): ", 2300241470Sgrehan cam_sim_name(sc->vtscsi_sim), cam_sim_unit(sc->vtscsi_sim), 2301241470Sgrehan cam_sim_bus(sc->vtscsi_sim)); 2302241470Sgrehan } else { 2303241470Sgrehan xpt_path_string(ccb->ccb_h.path, path_str, sizeof(path_str)); 2304241470Sgrehan sbuf_cat(&sb, path_str); 2305241470Sgrehan if (ccb->ccb_h.func_code == XPT_SCSI_IO) { 2306241470Sgrehan scsi_command_string(&ccb->csio, &sb); 2307241470Sgrehan sbuf_printf(&sb, "length %d ", ccb->csio.dxfer_len); 2308241470Sgrehan } 2309241470Sgrehan } 2310241470Sgrehan 2311241470Sgrehan sbuf_vprintf(&sb, fmt, ap); 2312241470Sgrehan va_end(ap); 2313241470Sgrehan 2314241470Sgrehan sbuf_finish(&sb); 2315241470Sgrehan printf("%s: %s: %s", device_get_nameunit(sc->vtscsi_dev), func, 2316241470Sgrehan sbuf_data(&sb)); 2317241470Sgrehan} 2318