12f001371SPeter Grehan /*- 2*abd6790cSBryan Venteicher * Copyright (c) 2012, Bryan Venteicher <bryanv@FreeBSD.org> 32f001371SPeter Grehan * All rights reserved. 42f001371SPeter Grehan * 52f001371SPeter Grehan * Redistribution and use in source and binary forms, with or without 62f001371SPeter Grehan * modification, are permitted provided that the following conditions 72f001371SPeter Grehan * are met: 82f001371SPeter Grehan * 1. Redistributions of source code must retain the above copyright 92f001371SPeter Grehan * notice unmodified, this list of conditions, and the following 102f001371SPeter Grehan * disclaimer. 112f001371SPeter Grehan * 2. Redistributions in binary form must reproduce the above copyright 122f001371SPeter Grehan * notice, this list of conditions and the following disclaimer in the 132f001371SPeter Grehan * documentation and/or other materials provided with the distribution. 142f001371SPeter Grehan * 152f001371SPeter Grehan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 162f001371SPeter Grehan * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 172f001371SPeter Grehan * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 182f001371SPeter Grehan * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 192f001371SPeter Grehan * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 202f001371SPeter Grehan * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 212f001371SPeter Grehan * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 222f001371SPeter Grehan * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 232f001371SPeter Grehan * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 242f001371SPeter Grehan * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 252f001371SPeter Grehan * 262f001371SPeter Grehan * $FreeBSD$ 272f001371SPeter Grehan */ 282f001371SPeter Grehan 292f001371SPeter Grehan #ifndef _VIRTIO_SCSIVAR_H 302f001371SPeter Grehan #define _VIRTIO_SCSIVAR_H 312f001371SPeter Grehan 322f001371SPeter Grehan struct vtscsi_softc; 332f001371SPeter Grehan struct vtscsi_request; 342f001371SPeter Grehan 352f001371SPeter Grehan typedef void vtscsi_request_cb_t(struct vtscsi_softc *, 362f001371SPeter Grehan struct vtscsi_request *); 372f001371SPeter Grehan 382f001371SPeter Grehan struct vtscsi_statistics { 392f001371SPeter Grehan unsigned long scsi_cmd_timeouts; 402f001371SPeter Grehan unsigned long dequeue_no_requests; 412f001371SPeter Grehan }; 422f001371SPeter Grehan 432f001371SPeter Grehan struct vtscsi_softc { 442f001371SPeter Grehan device_t vtscsi_dev; 452f001371SPeter Grehan struct mtx vtscsi_mtx; 462f001371SPeter Grehan uint64_t vtscsi_features; 472f001371SPeter Grehan 482f001371SPeter Grehan uint16_t vtscsi_flags; 492f001371SPeter Grehan #define VTSCSI_FLAG_INDIRECT 0x0001 502f001371SPeter Grehan #define VTSCSI_FLAG_BIDIRECTIONAL 0x0002 512f001371SPeter Grehan #define VTSCSI_FLAG_HOTPLUG 0x0004 522f001371SPeter Grehan #define VTSCSI_FLAG_RESET 0x0008 532f001371SPeter Grehan #define VTSCSI_FLAG_DETACH 0x0010 542f001371SPeter Grehan 552f001371SPeter Grehan uint16_t vtscsi_frozen; 562f001371SPeter Grehan #define VTSCSI_FROZEN_NO_REQUESTS 0x01 572f001371SPeter Grehan #define VTSCSI_FROZEN_REQUEST_VQ_FULL 0x02 582f001371SPeter Grehan 592f001371SPeter Grehan struct sglist *vtscsi_sglist; 602f001371SPeter Grehan 612f001371SPeter Grehan struct virtqueue *vtscsi_control_vq; 622f001371SPeter Grehan struct virtqueue *vtscsi_event_vq; 632f001371SPeter Grehan struct virtqueue *vtscsi_request_vq; 642f001371SPeter Grehan 652f001371SPeter Grehan struct cam_sim *vtscsi_sim; 662f001371SPeter Grehan struct cam_path *vtscsi_path; 672f001371SPeter Grehan 682f001371SPeter Grehan int vtscsi_debug; 692f001371SPeter Grehan int vtscsi_nrequests; 702f001371SPeter Grehan int vtscsi_max_nsegs; 712f001371SPeter Grehan int vtscsi_event_buf_size; 722f001371SPeter Grehan 732f001371SPeter Grehan TAILQ_HEAD(,vtscsi_request) 742f001371SPeter Grehan vtscsi_req_free; 752f001371SPeter Grehan 762f001371SPeter Grehan uint16_t vtscsi_max_channel; 772f001371SPeter Grehan uint16_t vtscsi_max_target; 782f001371SPeter Grehan uint32_t vtscsi_max_lun; 792f001371SPeter Grehan 802f001371SPeter Grehan #define VTSCSI_NUM_EVENT_BUFS 4 812f001371SPeter Grehan struct virtio_scsi_event 822f001371SPeter Grehan vtscsi_event_bufs[VTSCSI_NUM_EVENT_BUFS]; 832f001371SPeter Grehan 842f001371SPeter Grehan struct vtscsi_statistics vtscsi_stats; 852f001371SPeter Grehan }; 862f001371SPeter Grehan 872f001371SPeter Grehan enum vtscsi_request_state { 882f001371SPeter Grehan VTSCSI_REQ_STATE_FREE, 892f001371SPeter Grehan VTSCSI_REQ_STATE_INUSE, 902f001371SPeter Grehan VTSCSI_REQ_STATE_ABORTED, 912f001371SPeter Grehan VTSCSI_REQ_STATE_TIMEDOUT 922f001371SPeter Grehan }; 932f001371SPeter Grehan 942f001371SPeter Grehan struct vtscsi_request { 952f001371SPeter Grehan struct vtscsi_softc *vsr_softc; 962f001371SPeter Grehan union ccb *vsr_ccb; 972f001371SPeter Grehan vtscsi_request_cb_t *vsr_complete; 982f001371SPeter Grehan 992f001371SPeter Grehan void *vsr_ptr0; 1002f001371SPeter Grehan /* Request when aborting a timedout command. */ 1012f001371SPeter Grehan #define vsr_timedout_req vsr_ptr0 1022f001371SPeter Grehan 1032f001371SPeter Grehan enum vtscsi_request_state vsr_state; 1042f001371SPeter Grehan 1052f001371SPeter Grehan uint16_t vsr_flags; 1062f001371SPeter Grehan #define VTSCSI_REQ_FLAG_POLLED 0x01 1072f001371SPeter Grehan #define VTSCSI_REQ_FLAG_COMPLETE 0x02 1082f001371SPeter Grehan #define VTSCSI_REQ_FLAG_TIMEOUT_SET 0x04 1092f001371SPeter Grehan 1102f001371SPeter Grehan union { 1112f001371SPeter Grehan struct virtio_scsi_cmd_req cmd; 1122f001371SPeter Grehan struct virtio_scsi_ctrl_tmf_req tmf; 1132f001371SPeter Grehan struct virtio_scsi_ctrl_an_req an; 1142f001371SPeter Grehan } vsr_ureq; 1152f001371SPeter Grehan #define vsr_cmd_req vsr_ureq.cmd 1162f001371SPeter Grehan #define vsr_tmf_req vsr_ureq.tmf 1172f001371SPeter Grehan #define vsr_an_req vsr_ureq.an 1182f001371SPeter Grehan 1192f001371SPeter Grehan /* Make request and response non-contiguous. */ 1202f001371SPeter Grehan uint32_t vsr_pad; 1212f001371SPeter Grehan 1222f001371SPeter Grehan union { 1232f001371SPeter Grehan struct virtio_scsi_cmd_resp cmd; 1242f001371SPeter Grehan struct virtio_scsi_ctrl_tmf_resp tmf; 1252f001371SPeter Grehan struct virtio_scsi_ctrl_an_resp an; 1262f001371SPeter Grehan } vsr_uresp; 1272f001371SPeter Grehan #define vsr_cmd_resp vsr_uresp.cmd 1282f001371SPeter Grehan #define vsr_tmf_resp vsr_uresp.tmf 1292f001371SPeter Grehan #define vsr_an_resp vsr_uresp.an 1302f001371SPeter Grehan 1312f001371SPeter Grehan struct callout vsr_callout; 1322f001371SPeter Grehan 1332f001371SPeter Grehan TAILQ_ENTRY(vtscsi_request) vsr_link; 1342f001371SPeter Grehan }; 1352f001371SPeter Grehan 1362f001371SPeter Grehan /* Private field in the CCB header that points to our request. */ 1372f001371SPeter Grehan #define ccbh_vtscsi_req spriv_ptr0 1382f001371SPeter Grehan 1392f001371SPeter Grehan /* Features desired/implemented by this driver. */ 1402f001371SPeter Grehan #define VTSCSI_FEATURES \ 1412f001371SPeter Grehan (VIRTIO_SCSI_F_HOTPLUG | \ 1422f001371SPeter Grehan VIRTIO_RING_F_INDIRECT_DESC) 1432f001371SPeter Grehan 1442f001371SPeter Grehan #define VTSCSI_MTX(_sc) &(_sc)->vtscsi_mtx 1452f001371SPeter Grehan #define VTSCSI_LOCK_INIT(_sc, _name) mtx_init(VTSCSI_MTX(_sc), _name, \ 1462f001371SPeter Grehan "VTSCSI Lock", MTX_DEF) 1472f001371SPeter Grehan #define VTSCSI_LOCK(_sc) mtx_lock(VTSCSI_MTX(_sc)) 1482f001371SPeter Grehan #define VTSCSI_UNLOCK(_sc) mtx_unlock(VTSCSI_MTX(_sc)) 1492f001371SPeter Grehan #define VTSCSI_LOCK_OWNED(_sc) mtx_assert(VTSCSI_MTX(_sc), MA_OWNED) 1502f001371SPeter Grehan #define VTSCSI_LOCK_NOTOWNED(_sc) mtx_assert(VTSCSI_MTX(_sc), MA_NOTOWNED) 1512f001371SPeter Grehan #define VTSCSI_LOCK_DESTROY(_sc) mtx_destroy(VTSCSI_MTX(_sc)) 1522f001371SPeter Grehan 1532f001371SPeter Grehan /* 1542f001371SPeter Grehan * Reasons for either freezing or thawing the SIMQ. 1552f001371SPeter Grehan * 1562f001371SPeter Grehan * VirtIO SCSI is a bit unique in the sense that SCSI and TMF 1572f001371SPeter Grehan * commands go over different queues. Both queues are fed by 1582f001371SPeter Grehan * the same SIMQ, but we only freeze the SIMQ when the request 1592f001371SPeter Grehan * (SCSI) virtqueue is full, not caring if the control (TMF) 1602f001371SPeter Grehan * virtqueue unlikely gets full. However, both queues share the 1612f001371SPeter Grehan * same pool of requests, so the completion of a TMF command 1622f001371SPeter Grehan * could cause the SIMQ to be unfrozen. 1632f001371SPeter Grehan */ 1642f001371SPeter Grehan #define VTSCSI_REQUEST 0x01 1652f001371SPeter Grehan #define VTSCSI_REQUEST_VQ 0x02 1662f001371SPeter Grehan 1672f001371SPeter Grehan /* Debug trace levels. */ 1682f001371SPeter Grehan #define VTSCSI_INFO 0x01 1692f001371SPeter Grehan #define VTSCSI_ERROR 0x02 1702f001371SPeter Grehan #define VTSCSI_TRACE 0x04 1712f001371SPeter Grehan 1722f001371SPeter Grehan #define vtscsi_dprintf(_sc, _level, _msg, _args ...) do { \ 1732f001371SPeter Grehan if ((_sc)->vtscsi_debug & (_level)) \ 1742f001371SPeter Grehan device_printf((_sc)->vtscsi_dev, "%s: "_msg, \ 1752f001371SPeter Grehan __FUNCTION__, ##_args); \ 1762f001371SPeter Grehan } while (0) 1772f001371SPeter Grehan 1782f001371SPeter Grehan #define vtscsi_dprintf_req(_req, _level, _msg, _args ...) do { \ 1792f001371SPeter Grehan struct vtscsi_softc *__sc = (_req)->vsr_softc; \ 1802f001371SPeter Grehan if ((__sc)->vtscsi_debug & (_level)) \ 1812f001371SPeter Grehan vtscsi_printf_req(_req, __FUNCTION__, _msg, ##_args); \ 1822f001371SPeter Grehan } while (0) 1832f001371SPeter Grehan 1842f001371SPeter Grehan /* 1852f001371SPeter Grehan * Set the status field in a CCB, optionally clearing non CCB_STATUS_* flags. 1862f001371SPeter Grehan */ 1872f001371SPeter Grehan #define vtscsi_set_ccb_status(_ccbh, _status, _mask) do { \ 1882f001371SPeter Grehan KASSERT(((_mask) & CAM_STATUS_MASK) == 0, \ 1892f001371SPeter Grehan ("%s:%d bad mask: 0x%x", __FUNCTION__, __LINE__, (_mask))); \ 1902f001371SPeter Grehan (_ccbh)->status &= ~(CAM_STATUS_MASK | (_mask)); \ 1912f001371SPeter Grehan (_ccbh)->status |= (_status); \ 1922f001371SPeter Grehan } while (0) 1932f001371SPeter Grehan 1942f001371SPeter Grehan /* 1952f001371SPeter Grehan * One segment each for the request and the response. 1962f001371SPeter Grehan */ 1972f001371SPeter Grehan #define VTSCSI_MIN_SEGMENTS 2 1982f001371SPeter Grehan 1992f001371SPeter Grehan /* 2002f001371SPeter Grehan * Allocate additional requests for internal use such 2012f001371SPeter Grehan * as TM commands (e.g. aborting timedout commands). 2022f001371SPeter Grehan */ 2032f001371SPeter Grehan #define VTSCSI_RESERVED_REQUESTS 10 2042f001371SPeter Grehan 2052f001371SPeter Grehan /* 2062f001371SPeter Grehan * Specification doesn't say, use traditional SCSI default. 2072f001371SPeter Grehan */ 2082f001371SPeter Grehan #define VTSCSI_INITIATOR_ID 7 2092f001371SPeter Grehan 2102f001371SPeter Grehan /* 2112f001371SPeter Grehan * How to wait (or not) for request completion. 2122f001371SPeter Grehan */ 2132f001371SPeter Grehan #define VTSCSI_EXECUTE_ASYNC 0 2142f001371SPeter Grehan #define VTSCSI_EXECUTE_POLL 1 2152f001371SPeter Grehan 2162f001371SPeter Grehan #endif /* _VIRTIO_SCSIVAR_H */ 217