1898b0535SWarner Losh /*- 28b8a9b1dSJustin T. Gibbs * Common functions for SCSI Interface Modules (SIMs). 38b8a9b1dSJustin T. Gibbs * 4bec9534dSPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 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> 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> 406e40542aSBjoern A. Zeeb #include <sys/bus.h> 418b8a9b1dSJustin T. Gibbs 428b8a9b1dSJustin T. Gibbs #include <cam/cam.h> 438b8a9b1dSJustin T. Gibbs #include <cam/cam_ccb.h> 448b8a9b1dSJustin T. Gibbs #include <cam/cam_sim.h> 458b8a9b1dSJustin T. Gibbs #include <cam/cam_queue.h> 46cd05a36eSAlexander Motin #include <cam/cam_xpt.h> 478b8a9b1dSJustin T. Gibbs 488b8a9b1dSJustin T. Gibbs #define CAM_PATH_ANY (u_int32_t)-1 498b8a9b1dSJustin T. Gibbs 50d745c852SEd Schouten static MALLOC_DEFINE(M_CAMSIM, "CAM SIM", "CAM SIM buffers"); 51362abc44STai-hwa Liang 52401ed17aSAlexander Motin static struct mtx cam_sim_free_mtx; 53401ed17aSAlexander Motin MTX_SYSINIT(cam_sim_free_init, &cam_sim_free_mtx, "CAM SIM free lock", MTX_DEF); 54401ed17aSAlexander Motin 558b8a9b1dSJustin T. Gibbs struct cam_devq * 568b8a9b1dSJustin T. Gibbs cam_simq_alloc(u_int32_t max_sim_transactions) 578b8a9b1dSJustin T. Gibbs { 588b8a9b1dSJustin T. Gibbs return (cam_devq_alloc(/*size*/0, max_sim_transactions)); 598b8a9b1dSJustin T. Gibbs } 608b8a9b1dSJustin T. Gibbs 618b8a9b1dSJustin T. Gibbs void 628b8a9b1dSJustin T. Gibbs cam_simq_free(struct cam_devq *devq) 638b8a9b1dSJustin T. Gibbs { 648b8a9b1dSJustin T. Gibbs cam_devq_free(devq); 658b8a9b1dSJustin T. Gibbs } 668b8a9b1dSJustin T. Gibbs 678b8a9b1dSJustin T. Gibbs struct cam_sim * 688b8a9b1dSJustin T. Gibbs cam_sim_alloc(sim_action_func sim_action, sim_poll_func sim_poll, 69e2138feeSJohn Baldwin const char *sim_name, void *softc, u_int32_t unit, 702b83592fSScott Long struct mtx *mtx, int max_dev_transactions, 719deea857SKenneth D. Merry int max_tagged_dev_transactions, struct cam_devq *queue) 728b8a9b1dSJustin T. Gibbs { 738b8a9b1dSJustin T. Gibbs struct cam_sim *sim; 748b8a9b1dSJustin T. Gibbs 758b8a9b1dSJustin T. Gibbs sim = (struct cam_sim *)malloc(sizeof(struct cam_sim), 7683c5d981SAlexander Motin M_CAMSIM, M_ZERO | M_NOWAIT); 778b8a9b1dSJustin T. Gibbs 782b83592fSScott Long if (sim == NULL) 792b83592fSScott Long return (NULL); 802b83592fSScott Long 818b8a9b1dSJustin T. Gibbs sim->sim_action = sim_action; 828b8a9b1dSJustin T. Gibbs sim->sim_poll = sim_poll; 838b8a9b1dSJustin T. Gibbs sim->sim_name = sim_name; 848b8a9b1dSJustin T. Gibbs sim->softc = softc; 858b8a9b1dSJustin T. Gibbs sim->path_id = CAM_PATH_ANY; 866e40542aSBjoern A. Zeeb sim->sim_dev = NULL; /* set only by cam_sim_alloc_dev */ 878b8a9b1dSJustin T. Gibbs sim->unit_number = unit; 888b8a9b1dSJustin T. Gibbs sim->bus_id = 0; /* set in xpt_bus_register */ 898b8a9b1dSJustin T. Gibbs sim->max_tagged_dev_openings = max_tagged_dev_transactions; 908b8a9b1dSJustin T. Gibbs sim->max_dev_openings = max_dev_transactions; 918b8a9b1dSJustin T. Gibbs sim->flags = 0; 92fa6099fdSEdward Tomasz Napierala sim->refcount = 1; 938b8a9b1dSJustin T. Gibbs sim->devq = queue; 942b83592fSScott Long sim->mtx = mtx; 952b83592fSScott Long if (mtx == &Giant) { 962b83592fSScott Long sim->flags |= 0; 972b83592fSScott Long callout_init(&sim->callout, 0); 982b83592fSScott Long } else { 992b83592fSScott Long sim->flags |= CAM_SIM_MPSAFE; 1002b83592fSScott Long callout_init(&sim->callout, 1); 1018b8a9b1dSJustin T. Gibbs } 1028b8a9b1dSJustin T. Gibbs return (sim); 1038b8a9b1dSJustin T. Gibbs } 1048b8a9b1dSJustin T. Gibbs 1056e40542aSBjoern A. Zeeb struct cam_sim * 1066e40542aSBjoern A. Zeeb cam_sim_alloc_dev(sim_action_func sim_action, sim_poll_func sim_poll, 1076e40542aSBjoern A. Zeeb const char *sim_name, void *softc, device_t dev, 1086e40542aSBjoern A. Zeeb struct mtx *mtx, int max_dev_transactions, 1096e40542aSBjoern A. Zeeb int max_tagged_dev_transactions, struct cam_devq *queue) 1106e40542aSBjoern A. Zeeb { 1116e40542aSBjoern A. Zeeb struct cam_sim *sim; 1126e40542aSBjoern A. Zeeb 1136e40542aSBjoern A. Zeeb KASSERT(dev != NULL, ("%s: dev is null for sim_name %s softc %p\n", 1146e40542aSBjoern A. Zeeb __func__, sim_name, softc)); 1156e40542aSBjoern A. Zeeb 1166e40542aSBjoern A. Zeeb sim = cam_sim_alloc(sim_action, sim_poll, sim_name, softc, 1176e40542aSBjoern A. Zeeb device_get_unit(dev), mtx, max_dev_transactions, 1186e40542aSBjoern A. Zeeb max_tagged_dev_transactions, queue); 1196e40542aSBjoern A. Zeeb if (sim != NULL) 1206e40542aSBjoern A. Zeeb sim->sim_dev = dev; 1216e40542aSBjoern A. Zeeb return (sim); 1226e40542aSBjoern A. Zeeb } 1236e40542aSBjoern A. Zeeb 1248b8a9b1dSJustin T. Gibbs void 1258b8a9b1dSJustin T. Gibbs cam_sim_free(struct cam_sim *sim, int free_devq) 1268b8a9b1dSJustin T. Gibbs { 1277a7ca53fSBjoern A. Zeeb struct mtx *mtx; 128fa6099fdSEdward Tomasz Napierala int error; 129fa6099fdSEdward Tomasz Napierala 1307a7ca53fSBjoern A. Zeeb if (sim->mtx == NULL) { 131401ed17aSAlexander Motin mtx = &cam_sim_free_mtx; 132401ed17aSAlexander Motin mtx_lock(mtx); 1337a7ca53fSBjoern A. Zeeb } else { 1347a7ca53fSBjoern A. Zeeb mtx = sim->mtx; 1357a7ca53fSBjoern A. Zeeb mtx_assert(mtx, MA_OWNED); 136401ed17aSAlexander Motin } 137*a1975719SWarner Losh KASSERT(sim->refcount >= 1, ("sim->refcount >= 1")); 138fa6099fdSEdward Tomasz Napierala sim->refcount--; 139fa6099fdSEdward Tomasz Napierala if (sim->refcount > 0) { 140401ed17aSAlexander Motin error = msleep(sim, mtx, PRIBIO, "simfree", 0); 141fa6099fdSEdward Tomasz Napierala KASSERT(error == 0, ("invalid error value for msleep(9)")); 142fa6099fdSEdward Tomasz Napierala } 143fa6099fdSEdward Tomasz Napierala KASSERT(sim->refcount == 0, ("sim->refcount == 0")); 1447a7ca53fSBjoern A. Zeeb if (mtx == &cam_sim_free_mtx) /* sim->mtx == NULL */ 145401ed17aSAlexander Motin mtx_unlock(mtx); 146fa6099fdSEdward Tomasz Napierala 1478b8a9b1dSJustin T. Gibbs if (free_devq) 1488b8a9b1dSJustin T. Gibbs cam_simq_free(sim->devq); 149362abc44STai-hwa Liang free(sim, M_CAMSIM); 1508b8a9b1dSJustin T. Gibbs } 1518b8a9b1dSJustin T. Gibbs 1528b8a9b1dSJustin T. Gibbs void 153fa6099fdSEdward Tomasz Napierala cam_sim_release(struct cam_sim *sim) 154fa6099fdSEdward Tomasz Napierala { 1557a7ca53fSBjoern A. Zeeb struct mtx *mtx; 156fa6099fdSEdward Tomasz Napierala 1577a7ca53fSBjoern A. Zeeb if (sim->mtx == NULL) 158401ed17aSAlexander Motin mtx = &cam_sim_free_mtx; 1597a7ca53fSBjoern A. Zeeb else if (!mtx_owned(sim->mtx)) 1607a7ca53fSBjoern A. Zeeb mtx = sim->mtx; 1617a7ca53fSBjoern A. Zeeb else 1627a7ca53fSBjoern A. Zeeb mtx = NULL; /* We hold the lock. */ 1637a7ca53fSBjoern A. Zeeb if (mtx) 164401ed17aSAlexander Motin mtx_lock(mtx); 165227d67aaSAlexander Motin KASSERT(sim->refcount >= 1, ("sim->refcount >= 1")); 166fa6099fdSEdward Tomasz Napierala sim->refcount--; 1677412d60dSEdward Tomasz Napierala if (sim->refcount == 0) 168fa6099fdSEdward Tomasz Napierala wakeup(sim); 169401ed17aSAlexander Motin if (mtx) 170401ed17aSAlexander Motin mtx_unlock(mtx); 171fa6099fdSEdward Tomasz Napierala } 172fa6099fdSEdward Tomasz Napierala 173fa6099fdSEdward Tomasz Napierala void 174fa6099fdSEdward Tomasz Napierala cam_sim_hold(struct cam_sim *sim) 175fa6099fdSEdward Tomasz Napierala { 1767a7ca53fSBjoern A. Zeeb struct mtx *mtx; 177fa6099fdSEdward Tomasz Napierala 1787a7ca53fSBjoern A. Zeeb if (sim->mtx == NULL) 179401ed17aSAlexander Motin mtx = &cam_sim_free_mtx; 1807a7ca53fSBjoern A. Zeeb else if (!mtx_owned(sim->mtx)) 1817a7ca53fSBjoern A. Zeeb mtx = sim->mtx; 1827a7ca53fSBjoern A. Zeeb else 1837a7ca53fSBjoern A. Zeeb mtx = NULL; /* We hold the lock. */ 1847a7ca53fSBjoern A. Zeeb if (mtx) 185401ed17aSAlexander Motin mtx_lock(mtx); 186227d67aaSAlexander Motin KASSERT(sim->refcount >= 1, ("sim->refcount >= 1")); 187fa6099fdSEdward Tomasz Napierala sim->refcount++; 188401ed17aSAlexander Motin if (mtx) 189401ed17aSAlexander Motin mtx_unlock(mtx); 190fa6099fdSEdward Tomasz Napierala } 191fa6099fdSEdward Tomasz Napierala 192fa6099fdSEdward Tomasz Napierala void 1938b8a9b1dSJustin T. Gibbs cam_sim_set_path(struct cam_sim *sim, u_int32_t path_id) 1948b8a9b1dSJustin T. Gibbs { 1958b8a9b1dSJustin T. Gibbs sim->path_id = path_id; 1968b8a9b1dSJustin T. Gibbs } 197