1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2012, Bryan Venteicher <bryanv@FreeBSD.org> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice unmodified, this list of conditions, and the following 12 * disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * $FreeBSD$ 29 */ 30 31 #ifndef _VIRTIO_SCSIVAR_H 32 #define _VIRTIO_SCSIVAR_H 33 34 struct vtscsi_softc; 35 struct vtscsi_request; 36 37 typedef void vtscsi_request_cb_t(struct vtscsi_softc *, 38 struct vtscsi_request *); 39 40 struct vtscsi_statistics { 41 unsigned long scsi_cmd_timeouts; 42 unsigned long dequeue_no_requests; 43 }; 44 45 struct vtscsi_softc { 46 device_t vtscsi_dev; 47 struct mtx vtscsi_mtx; 48 uint64_t vtscsi_features; 49 50 uint16_t vtscsi_flags; 51 #define VTSCSI_FLAG_INDIRECT 0x0001 52 #define VTSCSI_FLAG_BIDIRECTIONAL 0x0002 53 #define VTSCSI_FLAG_HOTPLUG 0x0004 54 #define VTSCSI_FLAG_RESET 0x0008 55 #define VTSCSI_FLAG_DETACH 0x0010 56 57 uint16_t vtscsi_frozen; 58 #define VTSCSI_FROZEN_NO_REQUESTS 0x01 59 #define VTSCSI_FROZEN_REQUEST_VQ_FULL 0x02 60 61 struct sglist *vtscsi_sglist; 62 63 struct virtqueue *vtscsi_control_vq; 64 struct virtqueue *vtscsi_event_vq; 65 struct virtqueue *vtscsi_request_vq; 66 67 struct cam_sim *vtscsi_sim; 68 struct cam_path *vtscsi_path; 69 70 int vtscsi_debug; 71 int vtscsi_nrequests; 72 int vtscsi_max_nsegs; 73 int vtscsi_event_buf_size; 74 75 TAILQ_HEAD(,vtscsi_request) 76 vtscsi_req_free; 77 78 uint16_t vtscsi_max_channel; 79 uint16_t vtscsi_max_target; 80 uint32_t vtscsi_max_lun; 81 82 #define VTSCSI_NUM_EVENT_BUFS 4 83 struct virtio_scsi_event 84 vtscsi_event_bufs[VTSCSI_NUM_EVENT_BUFS]; 85 86 struct vtscsi_statistics vtscsi_stats; 87 }; 88 89 enum vtscsi_request_state { 90 VTSCSI_REQ_STATE_FREE, 91 VTSCSI_REQ_STATE_INUSE, 92 VTSCSI_REQ_STATE_ABORTED, 93 VTSCSI_REQ_STATE_TIMEDOUT 94 }; 95 96 struct vtscsi_request { 97 struct vtscsi_softc *vsr_softc; 98 union ccb *vsr_ccb; 99 vtscsi_request_cb_t *vsr_complete; 100 101 void *vsr_ptr0; 102 /* Request when aborting a timedout command. */ 103 #define vsr_timedout_req vsr_ptr0 104 105 enum vtscsi_request_state vsr_state; 106 107 uint16_t vsr_flags; 108 #define VTSCSI_REQ_FLAG_POLLED 0x01 109 #define VTSCSI_REQ_FLAG_COMPLETE 0x02 110 #define VTSCSI_REQ_FLAG_TIMEOUT_SET 0x04 111 112 union { 113 struct virtio_scsi_cmd_req cmd; 114 struct virtio_scsi_ctrl_tmf_req tmf; 115 struct virtio_scsi_ctrl_an_req an; 116 } vsr_ureq; 117 #define vsr_cmd_req vsr_ureq.cmd 118 #define vsr_tmf_req vsr_ureq.tmf 119 #define vsr_an_req vsr_ureq.an 120 121 /* Make request and response non-contiguous. */ 122 uint32_t vsr_pad; 123 124 union { 125 struct virtio_scsi_cmd_resp cmd; 126 struct virtio_scsi_ctrl_tmf_resp tmf; 127 struct virtio_scsi_ctrl_an_resp an; 128 } vsr_uresp; 129 #define vsr_cmd_resp vsr_uresp.cmd 130 #define vsr_tmf_resp vsr_uresp.tmf 131 #define vsr_an_resp vsr_uresp.an 132 133 struct callout vsr_callout; 134 135 TAILQ_ENTRY(vtscsi_request) vsr_link; 136 }; 137 138 /* Private field in the CCB header that points to our request. */ 139 #define ccbh_vtscsi_req spriv_ptr0 140 141 /* Features desired/implemented by this driver. */ 142 #define VTSCSI_FEATURES \ 143 (VIRTIO_SCSI_F_HOTPLUG | \ 144 VIRTIO_RING_F_INDIRECT_DESC) 145 146 #define VTSCSI_MTX(_sc) &(_sc)->vtscsi_mtx 147 #define VTSCSI_LOCK_INIT(_sc, _name) mtx_init(VTSCSI_MTX(_sc), _name, \ 148 "VTSCSI Lock", MTX_DEF) 149 #define VTSCSI_LOCK(_sc) mtx_lock(VTSCSI_MTX(_sc)) 150 #define VTSCSI_UNLOCK(_sc) mtx_unlock(VTSCSI_MTX(_sc)) 151 #define VTSCSI_LOCK_OWNED(_sc) mtx_assert(VTSCSI_MTX(_sc), MA_OWNED) 152 #define VTSCSI_LOCK_NOTOWNED(_sc) mtx_assert(VTSCSI_MTX(_sc), MA_NOTOWNED) 153 #define VTSCSI_LOCK_DESTROY(_sc) mtx_destroy(VTSCSI_MTX(_sc)) 154 155 /* 156 * Reasons for either freezing or thawing the SIMQ. 157 * 158 * VirtIO SCSI is a bit unique in the sense that SCSI and TMF 159 * commands go over different queues. Both queues are fed by 160 * the same SIMQ, but we only freeze the SIMQ when the request 161 * (SCSI) virtqueue is full, not caring if the control (TMF) 162 * virtqueue unlikely gets full. However, both queues share the 163 * same pool of requests, so the completion of a TMF command 164 * could cause the SIMQ to be unfrozen. 165 */ 166 #define VTSCSI_REQUEST 0x01 167 #define VTSCSI_REQUEST_VQ 0x02 168 169 /* Debug trace levels. */ 170 #define VTSCSI_INFO 0x01 171 #define VTSCSI_ERROR 0x02 172 #define VTSCSI_TRACE 0x04 173 174 #define vtscsi_dprintf(_sc, _level, _msg, _args ...) do { \ 175 if ((_sc)->vtscsi_debug & (_level)) \ 176 device_printf((_sc)->vtscsi_dev, "%s: "_msg, \ 177 __FUNCTION__, ##_args); \ 178 } while (0) 179 180 #define vtscsi_dprintf_req(_req, _level, _msg, _args ...) do { \ 181 struct vtscsi_softc *__sc = (_req)->vsr_softc; \ 182 if ((__sc)->vtscsi_debug & (_level)) \ 183 vtscsi_printf_req(_req, __FUNCTION__, _msg, ##_args); \ 184 } while (0) 185 186 /* 187 * Set the status field in a CCB, optionally clearing non CCB_STATUS_* flags. 188 */ 189 #define vtscsi_set_ccb_status(_ccbh, _status, _mask) do { \ 190 KASSERT(((_mask) & CAM_STATUS_MASK) == 0, \ 191 ("%s:%d bad mask: 0x%x", __FUNCTION__, __LINE__, (_mask))); \ 192 (_ccbh)->status &= ~(CAM_STATUS_MASK | (_mask)); \ 193 (_ccbh)->status |= (_status); \ 194 } while (0) 195 196 /* 197 * One segment each for the request and the response. 198 */ 199 #define VTSCSI_MIN_SEGMENTS 2 200 201 /* 202 * Allocate additional requests for internal use such 203 * as TM commands (e.g. aborting timedout commands). 204 */ 205 #define VTSCSI_RESERVED_REQUESTS 10 206 207 /* 208 * How to wait (or not) for request completion. 209 */ 210 #define VTSCSI_EXECUTE_ASYNC 0 211 #define VTSCSI_EXECUTE_POLL 1 212 213 #endif /* _VIRTIO_SCSIVAR_H */ 214