1 /*- 2 * Common functions for SCSI Interface Modules (SIMs). 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 * 6 * Copyright (c) 1997 Justin T. Gibbs. 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions, and the following disclaimer, 14 * without modification, immediately at the beginning of the file. 15 * 2. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 22 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31 #include <sys/param.h> 32 #include <sys/bus.h> 33 #include <sys/kernel.h> 34 #include <sys/lock.h> 35 #include <sys/malloc.h> 36 #include <sys/mutex.h> 37 38 #include <cam/cam.h> 39 #include <cam/cam_ccb.h> 40 #include <cam/cam_queue.h> 41 #include <cam/cam_sim.h> 42 #include <cam/cam_xpt.h> 43 44 #define CAM_PATH_ANY (uint32_t)-1 45 46 static MALLOC_DEFINE(M_CAMSIM, "CAM SIM", "CAM SIM buffers"); 47 48 static struct mtx cam_sim_free_mtx; 49 MTX_SYSINIT(cam_sim_free_init, &cam_sim_free_mtx, "CAM SIM free lock", MTX_DEF); 50 51 struct cam_devq * 52 cam_simq_alloc(uint32_t max_sim_transactions) 53 { 54 return (cam_devq_alloc(/*size*/0, max_sim_transactions)); 55 } 56 57 void 58 cam_simq_free(struct cam_devq *devq) 59 { 60 cam_devq_free(devq); 61 } 62 63 64 65 /** 66 * @brief allocate a new sim and fill in the details 67 * 68 * A Storage Interface Module (SIM) is the interface between CAM and 69 * hardware. SIM receives CCBs from CAM via @p sim_action callback and 70 * translates them into DMA or other hardware transactions. During system 71 * dumps, it can be polled with the @p sim_poll callback. CCB processing is 72 * terminated by calling @c xpt_done(). 73 * 74 * The @p mtx acts as a perimeter lock for the SIM. All calls into the SIM's 75 * @p sim_action are made with this lock held. It is also used to hold/release 76 * a SIM, managing its reference count. When the lock is NULL, the SIM is 100% 77 * responsible for locking (and the reference counting is done with a shared 78 * lock. 79 * 80 * The cam_devq passed in (@c queue) is used to arbitrate the number of 81 * outstanding transactions to the SIM. For HBAs that have global limits shared 82 * between the different buses, the same devq should be specified for each bus 83 * attached to the SIM. 84 * 85 * @param sim_action Function to call to process CCBs 86 * @param sim_poll Function to poll the hardware for completions 87 * @param sim_name Name of SIM class 88 * @param softc Software context associated with the SIM 89 * @param unit Unit number of SIM 90 * @param mtx Mutex to lock while interacting with the SIM, or NULL 91 * for a SIM that handle its own locking to enable multi 92 * queue support. 93 * @param max_dev_transactions Maximum number of concurrent untagged 94 * transactions possible 95 * @param max_tagged_dev_transactions Maximum number of concurrent tagged 96 * transactions possible. 97 * @param queue The cam_devq to use for this SIM. 98 */ 99 struct cam_sim * 100 cam_sim_alloc(sim_action_func sim_action, sim_poll_func sim_poll, 101 const char *sim_name, void *softc, uint32_t unit, 102 struct mtx *mtx, int max_dev_transactions, 103 int max_tagged_dev_transactions, struct cam_devq *queue) 104 { 105 struct cam_sim *sim; 106 107 sim = malloc(sizeof(struct cam_sim), M_CAMSIM, M_ZERO | M_NOWAIT); 108 if (sim == NULL) 109 return (NULL); 110 111 sim->sim_action = sim_action; 112 sim->sim_poll = sim_poll; 113 sim->sim_name = sim_name; 114 sim->softc = softc; 115 sim->path_id = CAM_PATH_ANY; 116 sim->unit_number = unit; 117 sim->bus_id = 0; /* set in xpt_bus_register */ 118 sim->max_tagged_dev_openings = max_tagged_dev_transactions; 119 sim->max_dev_openings = max_dev_transactions; 120 sim->flags = 0; 121 sim->refcount = 1; 122 sim->devq = queue; 123 sim->mtx = mtx; 124 return (sim); 125 } 126 127 /** 128 * @brief frees up the sim 129 * 130 * Frees up the CAM @c sim and optionally the devq. If a mutex is associated 131 * with the sim, it must be locked on entry. It will remain locked on 132 * return. 133 * 134 * This function will wait for all outstanding reference to the sim to clear 135 * before returning. 136 * 137 * @param sim The sim to free 138 * @param free_devq Free the devq associated with the sim at creation. 139 */ 140 void 141 cam_sim_free(struct cam_sim *sim, int free_devq) 142 { 143 struct mtx *mtx; 144 int error __diagused; 145 146 if (sim->mtx == NULL) { 147 mtx = &cam_sim_free_mtx; 148 mtx_lock(mtx); 149 } else { 150 mtx = sim->mtx; 151 mtx_assert(mtx, MA_OWNED); 152 } 153 KASSERT(sim->refcount >= 1, ("sim->refcount >= 1")); 154 sim->refcount--; 155 if (sim->refcount > 0) { 156 error = msleep(sim, mtx, PRIBIO, "simfree", 0); 157 KASSERT(error == 0, ("invalid error value for msleep(9)")); 158 } 159 KASSERT(sim->refcount == 0, ("sim->refcount == 0")); 160 if (mtx == &cam_sim_free_mtx) /* sim->mtx == NULL */ 161 mtx_unlock(mtx); 162 163 if (free_devq) 164 cam_simq_free(sim->devq); 165 free(sim, M_CAMSIM); 166 } 167 168 void 169 cam_sim_release(struct cam_sim *sim) 170 { 171 struct mtx *mtx; 172 173 if (sim->mtx == NULL) 174 mtx = &cam_sim_free_mtx; 175 else if (!mtx_owned(sim->mtx)) 176 mtx = sim->mtx; 177 else 178 mtx = NULL; /* We hold the lock. */ 179 if (mtx) 180 mtx_lock(mtx); 181 KASSERT(sim->refcount >= 1, ("sim->refcount >= 1")); 182 sim->refcount--; 183 if (sim->refcount == 0) 184 wakeup(sim); 185 if (mtx) 186 mtx_unlock(mtx); 187 } 188 189 void 190 cam_sim_hold(struct cam_sim *sim) 191 { 192 struct mtx *mtx; 193 194 if (sim->mtx == NULL) 195 mtx = &cam_sim_free_mtx; 196 else if (!mtx_owned(sim->mtx)) 197 mtx = sim->mtx; 198 else 199 mtx = NULL; /* We hold the lock. */ 200 if (mtx) 201 mtx_lock(mtx); 202 KASSERT(sim->refcount >= 1, ("sim->refcount >= 1")); 203 sim->refcount++; 204 if (mtx) 205 mtx_unlock(mtx); 206 } 207 208 void 209 cam_sim_set_path(struct cam_sim *sim, uint32_t path_id) 210 { 211 sim->path_id = path_id; 212 } 213