1898b0535SWarner Losh /*- 28b8a9b1dSJustin T. Gibbs * Common functions for SCSI Interface Modules (SIMs). 38b8a9b1dSJustin T. Gibbs * 4*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 5bec9534dSPedro F. Giffuni * 68b8a9b1dSJustin T. Gibbs * Copyright (c) 1997 Justin T. Gibbs. 78b8a9b1dSJustin T. Gibbs * All rights reserved. 88b8a9b1dSJustin T. Gibbs * 98b8a9b1dSJustin T. Gibbs * Redistribution and use in source and binary forms, with or without 108b8a9b1dSJustin T. Gibbs * modification, are permitted provided that the following conditions 118b8a9b1dSJustin T. Gibbs * are met: 128b8a9b1dSJustin T. Gibbs * 1. Redistributions of source code must retain the above copyright 138b8a9b1dSJustin T. Gibbs * notice, this list of conditions, and the following disclaimer, 148b8a9b1dSJustin T. Gibbs * without modification, immediately at the beginning of the file. 158b8a9b1dSJustin T. Gibbs * 2. The name of the author may not be used to endorse or promote products 168b8a9b1dSJustin T. Gibbs * derived from this software without specific prior written permission. 178b8a9b1dSJustin T. Gibbs * 188b8a9b1dSJustin T. Gibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 198b8a9b1dSJustin T. Gibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 208b8a9b1dSJustin T. Gibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 218b8a9b1dSJustin T. Gibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 228b8a9b1dSJustin T. Gibbs * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 238b8a9b1dSJustin T. Gibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 248b8a9b1dSJustin T. Gibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 258b8a9b1dSJustin T. Gibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 268b8a9b1dSJustin T. Gibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 278b8a9b1dSJustin T. Gibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 288b8a9b1dSJustin T. Gibbs * SUCH DAMAGE. 298b8a9b1dSJustin T. Gibbs */ 308b8a9b1dSJustin T. Gibbs 319c963d87SDavid E. O'Brien #include <sys/cdefs.h> 329c963d87SDavid E. O'Brien __FBSDID("$FreeBSD$"); 339c963d87SDavid E. O'Brien 348b8a9b1dSJustin T. Gibbs #include <sys/param.h> 3500e7a553SWarner Losh #include <sys/bus.h> 36362abc44STai-hwa Liang #include <sys/kernel.h> 372b83592fSScott Long #include <sys/lock.h> 3800e7a553SWarner Losh #include <sys/malloc.h> 392b83592fSScott Long #include <sys/mutex.h> 408b8a9b1dSJustin T. Gibbs 418b8a9b1dSJustin T. Gibbs #include <cam/cam.h> 428b8a9b1dSJustin T. Gibbs #include <cam/cam_ccb.h> 438b8a9b1dSJustin T. Gibbs #include <cam/cam_queue.h> 4400e7a553SWarner Losh #include <cam/cam_sim.h> 45cd05a36eSAlexander Motin #include <cam/cam_xpt.h> 468b8a9b1dSJustin T. Gibbs 478b8a9b1dSJustin T. Gibbs #define CAM_PATH_ANY (u_int32_t)-1 488b8a9b1dSJustin T. Gibbs 49d745c852SEd Schouten static MALLOC_DEFINE(M_CAMSIM, "CAM SIM", "CAM SIM buffers"); 50362abc44STai-hwa Liang 51401ed17aSAlexander Motin static struct mtx cam_sim_free_mtx; 52401ed17aSAlexander Motin MTX_SYSINIT(cam_sim_free_init, &cam_sim_free_mtx, "CAM SIM free lock", MTX_DEF); 53401ed17aSAlexander Motin 548b8a9b1dSJustin T. Gibbs struct cam_devq * 558b8a9b1dSJustin T. Gibbs cam_simq_alloc(u_int32_t max_sim_transactions) 568b8a9b1dSJustin T. Gibbs { 578b8a9b1dSJustin T. Gibbs return (cam_devq_alloc(/*size*/0, max_sim_transactions)); 588b8a9b1dSJustin T. Gibbs } 598b8a9b1dSJustin T. Gibbs 608b8a9b1dSJustin T. Gibbs void 618b8a9b1dSJustin T. Gibbs cam_simq_free(struct cam_devq *devq) 628b8a9b1dSJustin T. Gibbs { 638b8a9b1dSJustin T. Gibbs cam_devq_free(devq); 648b8a9b1dSJustin T. Gibbs } 658b8a9b1dSJustin T. Gibbs 66cb588059SWarner Losh 67cb588059SWarner Losh 68cb588059SWarner Losh /** 69cb588059SWarner Losh * @brief allocate a new sim and fill in the details 70cb588059SWarner Losh * 71cb588059SWarner Losh * A Storage Interface Module (SIM) is the interface between CAM and 72cb588059SWarner Losh * hardware. SIM receives CCBs from CAM via @p sim_action callback and 73cb588059SWarner Losh * translates them into DMA or other hardware transactions. During system 74cb588059SWarner Losh * dumps, it can be polled with the @p sim_poll callback. CCB processing is 75cb588059SWarner Losh * terminated by calling @c xpt_done(). 76cb588059SWarner Losh * 77cb588059SWarner Losh * The @p mtx acts as a perimeter lock for the SIM. All calls into the SIM's 78cb588059SWarner Losh * @p sim_action are made with this lock held. It is also used to hold/release 79cb588059SWarner Losh * a SIM, managing its reference count. When the lock is NULL, the SIM is 100% 80cb588059SWarner Losh * responsible for locking (and the reference counting is done with a shared 81cb588059SWarner Losh * lock. 82cb588059SWarner Losh * 83cb588059SWarner Losh * The cam_devq passed in (@c queue) is used to arbitrate the number of 84cb588059SWarner Losh * outstanding transactions to the SIM. For HBAs that have global limits shared 85cb588059SWarner Losh * between the different buses, the same devq should be specified for each bus 86cb588059SWarner Losh * attached to the SIM. 87cb588059SWarner Losh * 88cb588059SWarner Losh * @param sim_action Function to call to process CCBs 89cb588059SWarner Losh * @param sim_poll Function to poll the hardware for completions 90cb588059SWarner Losh * @param sim_name Name of SIM class 91cb588059SWarner Losh * @param softc Software context associated with the SIM 92cb588059SWarner Losh * @param unit Unit number of SIM 93cb588059SWarner Losh * @param mtx Mutex to lock while interacting with the SIM, or NULL 94cb588059SWarner Losh * for a SIM that handle its own locking to enable multi 95cb588059SWarner Losh * queue support. 96cb588059SWarner Losh * @param max_dev_transactions Maximum number of concurrent untagged 97cb588059SWarner Losh * transactions possible 98cb588059SWarner Losh * @param max_tagged_dev_transactions Maximum number of concurrent tagged 99cb588059SWarner Losh * transactions possible. 100cb588059SWarner Losh * @param queue The cam_devq to use for this SIM. 101cb588059SWarner Losh */ 1028b8a9b1dSJustin T. Gibbs struct cam_sim * 1038b8a9b1dSJustin T. Gibbs cam_sim_alloc(sim_action_func sim_action, sim_poll_func sim_poll, 104e2138feeSJohn Baldwin const char *sim_name, void *softc, u_int32_t unit, 1052b83592fSScott Long struct mtx *mtx, int max_dev_transactions, 1069deea857SKenneth D. Merry int max_tagged_dev_transactions, struct cam_devq *queue) 1078b8a9b1dSJustin T. Gibbs { 1088b8a9b1dSJustin T. Gibbs struct cam_sim *sim; 1098b8a9b1dSJustin T. Gibbs 1102ce5eef6SMark Johnston sim = malloc(sizeof(struct cam_sim), M_CAMSIM, M_ZERO | M_NOWAIT); 1112b83592fSScott Long if (sim == NULL) 1122b83592fSScott Long return (NULL); 1132b83592fSScott Long 1148b8a9b1dSJustin T. Gibbs sim->sim_action = sim_action; 1158b8a9b1dSJustin T. Gibbs sim->sim_poll = sim_poll; 1168b8a9b1dSJustin T. Gibbs sim->sim_name = sim_name; 1178b8a9b1dSJustin T. Gibbs sim->softc = softc; 1188b8a9b1dSJustin T. Gibbs sim->path_id = CAM_PATH_ANY; 1198b8a9b1dSJustin T. Gibbs sim->unit_number = unit; 1208b8a9b1dSJustin T. Gibbs sim->bus_id = 0; /* set in xpt_bus_register */ 1218b8a9b1dSJustin T. Gibbs sim->max_tagged_dev_openings = max_tagged_dev_transactions; 1228b8a9b1dSJustin T. Gibbs sim->max_dev_openings = max_dev_transactions; 1238b8a9b1dSJustin T. Gibbs sim->flags = 0; 124fa6099fdSEdward Tomasz Napierala sim->refcount = 1; 1258b8a9b1dSJustin T. Gibbs sim->devq = queue; 1262b83592fSScott Long sim->mtx = mtx; 1278b8a9b1dSJustin T. Gibbs return (sim); 1288b8a9b1dSJustin T. Gibbs } 1298b8a9b1dSJustin T. Gibbs 130b3b15d92SWarner Losh /** 131b3b15d92SWarner Losh * @brief frees up the sim 132b3b15d92SWarner Losh * 133b3b15d92SWarner Losh * Frees up the CAM @c sim and optionally the devq. If a mutex is associated 134b3b15d92SWarner Losh * with the sim, it must be locked on entry. It will remain locked on 135b3b15d92SWarner Losh * return. 136b3b15d92SWarner Losh * 137b3b15d92SWarner Losh * This function will wait for all outstanding reference to the sim to clear 138b3b15d92SWarner Losh * before returning. 139b3b15d92SWarner Losh * 140b3b15d92SWarner Losh * @param sim The sim to free 141b3b15d92SWarner Losh * @param free_devq Free the devq associated with the sim at creation. 142b3b15d92SWarner Losh */ 1438b8a9b1dSJustin T. Gibbs void 1448b8a9b1dSJustin T. Gibbs cam_sim_free(struct cam_sim *sim, int free_devq) 1458b8a9b1dSJustin T. Gibbs { 1467a7ca53fSBjoern A. Zeeb struct mtx *mtx; 147c154feacSScott Long int error __diagused; 148fa6099fdSEdward Tomasz Napierala 1497a7ca53fSBjoern A. Zeeb if (sim->mtx == NULL) { 150401ed17aSAlexander Motin mtx = &cam_sim_free_mtx; 151401ed17aSAlexander Motin mtx_lock(mtx); 1527a7ca53fSBjoern A. Zeeb } else { 1537a7ca53fSBjoern A. Zeeb mtx = sim->mtx; 1547a7ca53fSBjoern A. Zeeb mtx_assert(mtx, MA_OWNED); 155401ed17aSAlexander Motin } 156a1975719SWarner Losh KASSERT(sim->refcount >= 1, ("sim->refcount >= 1")); 157fa6099fdSEdward Tomasz Napierala sim->refcount--; 158fa6099fdSEdward Tomasz Napierala if (sim->refcount > 0) { 159401ed17aSAlexander Motin error = msleep(sim, mtx, PRIBIO, "simfree", 0); 160fa6099fdSEdward Tomasz Napierala KASSERT(error == 0, ("invalid error value for msleep(9)")); 161fa6099fdSEdward Tomasz Napierala } 162fa6099fdSEdward Tomasz Napierala KASSERT(sim->refcount == 0, ("sim->refcount == 0")); 1637a7ca53fSBjoern A. Zeeb if (mtx == &cam_sim_free_mtx) /* sim->mtx == NULL */ 164401ed17aSAlexander Motin mtx_unlock(mtx); 165fa6099fdSEdward Tomasz Napierala 1668b8a9b1dSJustin T. Gibbs if (free_devq) 1678b8a9b1dSJustin T. Gibbs cam_simq_free(sim->devq); 168362abc44STai-hwa Liang free(sim, M_CAMSIM); 1698b8a9b1dSJustin T. Gibbs } 1708b8a9b1dSJustin T. Gibbs 1718b8a9b1dSJustin T. Gibbs void 172fa6099fdSEdward Tomasz Napierala cam_sim_release(struct cam_sim *sim) 173fa6099fdSEdward Tomasz Napierala { 1747a7ca53fSBjoern A. Zeeb struct mtx *mtx; 175fa6099fdSEdward Tomasz Napierala 1767a7ca53fSBjoern A. Zeeb if (sim->mtx == NULL) 177401ed17aSAlexander Motin mtx = &cam_sim_free_mtx; 1787a7ca53fSBjoern A. Zeeb else if (!mtx_owned(sim->mtx)) 1797a7ca53fSBjoern A. Zeeb mtx = sim->mtx; 1807a7ca53fSBjoern A. Zeeb else 1817a7ca53fSBjoern A. Zeeb mtx = NULL; /* We hold the lock. */ 1827a7ca53fSBjoern A. Zeeb if (mtx) 183401ed17aSAlexander Motin mtx_lock(mtx); 184227d67aaSAlexander Motin KASSERT(sim->refcount >= 1, ("sim->refcount >= 1")); 185fa6099fdSEdward Tomasz Napierala sim->refcount--; 1867412d60dSEdward Tomasz Napierala if (sim->refcount == 0) 187fa6099fdSEdward Tomasz Napierala wakeup(sim); 188401ed17aSAlexander Motin if (mtx) 189401ed17aSAlexander Motin mtx_unlock(mtx); 190fa6099fdSEdward Tomasz Napierala } 191fa6099fdSEdward Tomasz Napierala 192fa6099fdSEdward Tomasz Napierala void 193fa6099fdSEdward Tomasz Napierala cam_sim_hold(struct cam_sim *sim) 194fa6099fdSEdward Tomasz Napierala { 1957a7ca53fSBjoern A. Zeeb struct mtx *mtx; 196fa6099fdSEdward Tomasz Napierala 1977a7ca53fSBjoern A. Zeeb if (sim->mtx == NULL) 198401ed17aSAlexander Motin mtx = &cam_sim_free_mtx; 1997a7ca53fSBjoern A. Zeeb else if (!mtx_owned(sim->mtx)) 2007a7ca53fSBjoern A. Zeeb mtx = sim->mtx; 2017a7ca53fSBjoern A. Zeeb else 2027a7ca53fSBjoern A. Zeeb mtx = NULL; /* We hold the lock. */ 2037a7ca53fSBjoern A. Zeeb if (mtx) 204401ed17aSAlexander Motin mtx_lock(mtx); 205227d67aaSAlexander Motin KASSERT(sim->refcount >= 1, ("sim->refcount >= 1")); 206fa6099fdSEdward Tomasz Napierala sim->refcount++; 207401ed17aSAlexander Motin if (mtx) 208401ed17aSAlexander Motin mtx_unlock(mtx); 209fa6099fdSEdward Tomasz Napierala } 210fa6099fdSEdward Tomasz Napierala 211fa6099fdSEdward Tomasz Napierala void 2128b8a9b1dSJustin T. Gibbs cam_sim_set_path(struct cam_sim *sim, u_int32_t path_id) 2138b8a9b1dSJustin T. Gibbs { 2148b8a9b1dSJustin T. Gibbs sim->path_id = path_id; 2158b8a9b1dSJustin T. Gibbs } 216