1898b0535SWarner Losh /*- 28b8a9b1dSJustin T. Gibbs * Common functions for SCSI Interface Modules (SIMs). 38b8a9b1dSJustin T. Gibbs * 4*bec9534dSPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 5*bec9534dSPedro 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> 358b8a9b1dSJustin T. Gibbs #include <sys/systm.h> 368b8a9b1dSJustin T. Gibbs #include <sys/malloc.h> 37362abc44STai-hwa Liang #include <sys/kernel.h> 382b83592fSScott Long #include <sys/lock.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_sim.h> 448b8a9b1dSJustin T. Gibbs #include <cam/cam_queue.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 668b8a9b1dSJustin T. Gibbs struct cam_sim * 678b8a9b1dSJustin T. Gibbs cam_sim_alloc(sim_action_func sim_action, sim_poll_func sim_poll, 68e2138feeSJohn Baldwin const char *sim_name, void *softc, u_int32_t unit, 692b83592fSScott Long struct mtx *mtx, int max_dev_transactions, 709deea857SKenneth D. Merry int max_tagged_dev_transactions, struct cam_devq *queue) 718b8a9b1dSJustin T. Gibbs { 728b8a9b1dSJustin T. Gibbs struct cam_sim *sim; 738b8a9b1dSJustin T. Gibbs 748b8a9b1dSJustin T. Gibbs sim = (struct cam_sim *)malloc(sizeof(struct cam_sim), 7583c5d981SAlexander Motin M_CAMSIM, M_ZERO | M_NOWAIT); 768b8a9b1dSJustin T. Gibbs 772b83592fSScott Long if (sim == NULL) 782b83592fSScott Long return (NULL); 792b83592fSScott Long 808b8a9b1dSJustin T. Gibbs sim->sim_action = sim_action; 818b8a9b1dSJustin T. Gibbs sim->sim_poll = sim_poll; 828b8a9b1dSJustin T. Gibbs sim->sim_name = sim_name; 838b8a9b1dSJustin T. Gibbs sim->softc = softc; 848b8a9b1dSJustin T. Gibbs sim->path_id = CAM_PATH_ANY; 858b8a9b1dSJustin T. Gibbs sim->unit_number = unit; 868b8a9b1dSJustin T. Gibbs sim->bus_id = 0; /* set in xpt_bus_register */ 878b8a9b1dSJustin T. Gibbs sim->max_tagged_dev_openings = max_tagged_dev_transactions; 888b8a9b1dSJustin T. Gibbs sim->max_dev_openings = max_dev_transactions; 898b8a9b1dSJustin T. Gibbs sim->flags = 0; 90fa6099fdSEdward Tomasz Napierala sim->refcount = 1; 918b8a9b1dSJustin T. Gibbs sim->devq = queue; 922b83592fSScott Long sim->mtx = mtx; 932b83592fSScott Long if (mtx == &Giant) { 942b83592fSScott Long sim->flags |= 0; 952b83592fSScott Long callout_init(&sim->callout, 0); 962b83592fSScott Long } else { 972b83592fSScott Long sim->flags |= CAM_SIM_MPSAFE; 982b83592fSScott Long callout_init(&sim->callout, 1); 998b8a9b1dSJustin T. Gibbs } 1008b8a9b1dSJustin T. Gibbs return (sim); 1018b8a9b1dSJustin T. Gibbs } 1028b8a9b1dSJustin T. Gibbs 1038b8a9b1dSJustin T. Gibbs void 1048b8a9b1dSJustin T. Gibbs cam_sim_free(struct cam_sim *sim, int free_devq) 1058b8a9b1dSJustin T. Gibbs { 106401ed17aSAlexander Motin struct mtx *mtx = sim->mtx; 107fa6099fdSEdward Tomasz Napierala int error; 108fa6099fdSEdward Tomasz Napierala 109401ed17aSAlexander Motin if (mtx) { 110401ed17aSAlexander Motin mtx_assert(mtx, MA_OWNED); 111401ed17aSAlexander Motin } else { 112401ed17aSAlexander Motin mtx = &cam_sim_free_mtx; 113401ed17aSAlexander Motin mtx_lock(mtx); 114401ed17aSAlexander Motin } 115fa6099fdSEdward Tomasz Napierala sim->refcount--; 116fa6099fdSEdward Tomasz Napierala if (sim->refcount > 0) { 117401ed17aSAlexander Motin error = msleep(sim, mtx, PRIBIO, "simfree", 0); 118fa6099fdSEdward Tomasz Napierala KASSERT(error == 0, ("invalid error value for msleep(9)")); 119fa6099fdSEdward Tomasz Napierala } 120fa6099fdSEdward Tomasz Napierala KASSERT(sim->refcount == 0, ("sim->refcount == 0")); 121401ed17aSAlexander Motin if (sim->mtx == NULL) 122401ed17aSAlexander Motin mtx_unlock(mtx); 123fa6099fdSEdward Tomasz Napierala 1248b8a9b1dSJustin T. Gibbs if (free_devq) 1258b8a9b1dSJustin T. Gibbs cam_simq_free(sim->devq); 126362abc44STai-hwa Liang free(sim, M_CAMSIM); 1278b8a9b1dSJustin T. Gibbs } 1288b8a9b1dSJustin T. Gibbs 1298b8a9b1dSJustin T. Gibbs void 130fa6099fdSEdward Tomasz Napierala cam_sim_release(struct cam_sim *sim) 131fa6099fdSEdward Tomasz Napierala { 132401ed17aSAlexander Motin struct mtx *mtx = sim->mtx; 133fa6099fdSEdward Tomasz Napierala 134401ed17aSAlexander Motin if (mtx) { 135401ed17aSAlexander Motin if (!mtx_owned(mtx)) 136401ed17aSAlexander Motin mtx_lock(mtx); 137401ed17aSAlexander Motin else 138401ed17aSAlexander Motin mtx = NULL; 139401ed17aSAlexander Motin } else { 140401ed17aSAlexander Motin mtx = &cam_sim_free_mtx; 141401ed17aSAlexander Motin mtx_lock(mtx); 142401ed17aSAlexander Motin } 143227d67aaSAlexander Motin KASSERT(sim->refcount >= 1, ("sim->refcount >= 1")); 144fa6099fdSEdward Tomasz Napierala sim->refcount--; 1457412d60dSEdward Tomasz Napierala if (sim->refcount == 0) 146fa6099fdSEdward Tomasz Napierala wakeup(sim); 147401ed17aSAlexander Motin if (mtx) 148401ed17aSAlexander Motin mtx_unlock(mtx); 149fa6099fdSEdward Tomasz Napierala } 150fa6099fdSEdward Tomasz Napierala 151fa6099fdSEdward Tomasz Napierala void 152fa6099fdSEdward Tomasz Napierala cam_sim_hold(struct cam_sim *sim) 153fa6099fdSEdward Tomasz Napierala { 154401ed17aSAlexander Motin struct mtx *mtx = sim->mtx; 155fa6099fdSEdward Tomasz Napierala 156401ed17aSAlexander Motin if (mtx) { 157401ed17aSAlexander Motin if (!mtx_owned(mtx)) 158401ed17aSAlexander Motin mtx_lock(mtx); 159401ed17aSAlexander Motin else 160401ed17aSAlexander Motin mtx = NULL; 161401ed17aSAlexander Motin } else { 162401ed17aSAlexander Motin mtx = &cam_sim_free_mtx; 163401ed17aSAlexander Motin mtx_lock(mtx); 164401ed17aSAlexander Motin } 165227d67aaSAlexander Motin KASSERT(sim->refcount >= 1, ("sim->refcount >= 1")); 166fa6099fdSEdward Tomasz Napierala sim->refcount++; 167401ed17aSAlexander Motin if (mtx) 168401ed17aSAlexander Motin mtx_unlock(mtx); 169fa6099fdSEdward Tomasz Napierala } 170fa6099fdSEdward Tomasz Napierala 171fa6099fdSEdward Tomasz Napierala void 1728b8a9b1dSJustin T. Gibbs cam_sim_set_path(struct cam_sim *sim, u_int32_t path_id) 1738b8a9b1dSJustin T. Gibbs { 1748b8a9b1dSJustin T. Gibbs sim->path_id = path_id; 1758b8a9b1dSJustin T. Gibbs } 176