1139743Simp/*-
239212Sgibbs * Common functions for SCSI Interface Modules (SIMs).
339212Sgibbs *
439212Sgibbs * Copyright (c) 1997 Justin T. Gibbs.
539212Sgibbs * All rights reserved.
639212Sgibbs *
739212Sgibbs * Redistribution and use in source and binary forms, with or without
839212Sgibbs * modification, are permitted provided that the following conditions
939212Sgibbs * are met:
1039212Sgibbs * 1. Redistributions of source code must retain the above copyright
1139212Sgibbs *    notice, this list of conditions, and the following disclaimer,
1239212Sgibbs *    without modification, immediately at the beginning of the file.
1339212Sgibbs * 2. The name of the author may not be used to endorse or promote products
1439212Sgibbs *    derived from this software without specific prior written permission.
1539212Sgibbs *
1639212Sgibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1739212Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1839212Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1939212Sgibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
2039212Sgibbs * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2139212Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2239212Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2339212Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2439212Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2539212Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2639212Sgibbs * SUCH DAMAGE.
2739212Sgibbs */
2839212Sgibbs
29116161Sobrien#include <sys/cdefs.h>
30116161Sobrien__FBSDID("$FreeBSD: releng/11.0/sys/cam/cam_sim.c 256843 2013-10-21 12:00:26Z mav $");
31116161Sobrien
3239212Sgibbs#include <sys/param.h>
3339212Sgibbs#include <sys/systm.h>
3439212Sgibbs#include <sys/malloc.h>
35147723Savatar#include <sys/kernel.h>
36168752Sscottl#include <sys/lock.h>
37168752Sscottl#include <sys/mutex.h>
3839212Sgibbs
3939212Sgibbs#include <cam/cam.h>
4039212Sgibbs#include <cam/cam_ccb.h>
4139212Sgibbs#include <cam/cam_sim.h>
4239212Sgibbs#include <cam/cam_queue.h>
43248800Smav#include <cam/cam_xpt.h>
4439212Sgibbs
4539212Sgibbs#define CAM_PATH_ANY (u_int32_t)-1
4639212Sgibbs
47227293Sedstatic MALLOC_DEFINE(M_CAMSIM, "CAM SIM", "CAM SIM buffers");
48147723Savatar
4939212Sgibbsstruct cam_devq *
5039212Sgibbscam_simq_alloc(u_int32_t max_sim_transactions)
5139212Sgibbs{
5239212Sgibbs	return (cam_devq_alloc(/*size*/0, max_sim_transactions));
5339212Sgibbs}
5439212Sgibbs
5539212Sgibbsvoid
5639212Sgibbscam_simq_free(struct cam_devq *devq)
5739212Sgibbs{
5839212Sgibbs	cam_devq_free(devq);
5939212Sgibbs}
6039212Sgibbs
6139212Sgibbsstruct cam_sim *
6239212Sgibbscam_sim_alloc(sim_action_func sim_action, sim_poll_func sim_poll,
6371507Sjhb	      const char *sim_name, void *softc, u_int32_t unit,
64168752Sscottl	      struct mtx *mtx, int max_dev_transactions,
6546581Sken	      int max_tagged_dev_transactions, struct cam_devq *queue)
6639212Sgibbs{
6739212Sgibbs	struct cam_sim *sim;
6839212Sgibbs
69168752Sscottl	if (mtx == NULL)
70168752Sscottl		return (NULL);
7139212Sgibbs
72168752Sscottl	sim = (struct cam_sim *)malloc(sizeof(struct cam_sim),
73203108Smav	    M_CAMSIM, M_ZERO | M_NOWAIT);
74168752Sscottl
75168752Sscottl	if (sim == NULL)
76168752Sscottl		return (NULL);
77168752Sscottl
78168752Sscottl	sim->sim_action = sim_action;
79168752Sscottl	sim->sim_poll = sim_poll;
80168752Sscottl	sim->sim_name = sim_name;
81168752Sscottl	sim->softc = softc;
82168752Sscottl	sim->path_id = CAM_PATH_ANY;
83168752Sscottl	sim->unit_number = unit;
84168752Sscottl	sim->bus_id = 0;	/* set in xpt_bus_register */
85168752Sscottl	sim->max_tagged_dev_openings = max_tagged_dev_transactions;
86168752Sscottl	sim->max_dev_openings = max_dev_transactions;
87168752Sscottl	sim->flags = 0;
88186185Strasz	sim->refcount = 1;
89168752Sscottl	sim->devq = queue;
90168752Sscottl	sim->mtx = mtx;
91168752Sscottl	if (mtx == &Giant) {
92168752Sscottl		sim->flags |= 0;
93168752Sscottl		callout_init(&sim->callout, 0);
94168752Sscottl	} else {
95168752Sscottl		sim->flags |= CAM_SIM_MPSAFE;
96168752Sscottl		callout_init(&sim->callout, 1);
9739212Sgibbs	}
9839212Sgibbs	return (sim);
9939212Sgibbs}
10039212Sgibbs
10139212Sgibbsvoid
10239212Sgibbscam_sim_free(struct cam_sim *sim, int free_devq)
10339212Sgibbs{
104186185Strasz	int error;
105186185Strasz
106249108Smav	mtx_assert(sim->mtx, MA_OWNED);
107186185Strasz	sim->refcount--;
108186185Strasz	if (sim->refcount > 0) {
109186185Strasz		error = msleep(sim, sim->mtx, PRIBIO, "simfree", 0);
110186185Strasz		KASSERT(error == 0, ("invalid error value for msleep(9)"));
111186185Strasz	}
112186185Strasz
113186185Strasz	KASSERT(sim->refcount == 0, ("sim->refcount == 0"));
114186185Strasz
11539212Sgibbs	if (free_devq)
11639212Sgibbs		cam_simq_free(sim->devq);
117147723Savatar	free(sim, M_CAMSIM);
11839212Sgibbs}
11939212Sgibbs
12039212Sgibbsvoid
121186185Straszcam_sim_release(struct cam_sim *sim)
122186185Strasz{
123256843Smav	int lock;
124256843Smav
125256843Smav	lock = (mtx_owned(sim->mtx) == 0);
126256843Smav	if (lock)
127256843Smav		CAM_SIM_LOCK(sim);
128186185Strasz	KASSERT(sim->refcount >= 1, ("sim->refcount >= 1"));
129186185Strasz	sim->refcount--;
130186320Strasz	if (sim->refcount == 0)
131186185Strasz		wakeup(sim);
132256843Smav	if (lock)
133256843Smav		CAM_SIM_UNLOCK(sim);
134186185Strasz}
135186185Strasz
136186185Straszvoid
137186185Straszcam_sim_hold(struct cam_sim *sim)
138186185Strasz{
139256843Smav	int lock;
140256843Smav
141256843Smav	lock = (mtx_owned(sim->mtx) == 0);
142256843Smav	if (lock)
143256843Smav		CAM_SIM_LOCK(sim);
144186185Strasz	KASSERT(sim->refcount >= 1, ("sim->refcount >= 1"));
145186185Strasz	sim->refcount++;
146256843Smav	if (lock)
147256843Smav		CAM_SIM_UNLOCK(sim);
148186185Strasz}
149186185Strasz
150186185Straszvoid
15139212Sgibbscam_sim_set_path(struct cam_sim *sim, u_int32_t path_id)
15239212Sgibbs{
15339212Sgibbs	sim->path_id = path_id;
15439212Sgibbs}
155