cam_sim.c revision 248800
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: head/sys/cam/cam_sim.c 248800 2013-03-27 18:55:01Z 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;
90203108Smav	sim->max_ccbs = 8;	/* Reserve for management purposes. */
91168752Sscottl	sim->mtx = mtx;
92168752Sscottl	if (mtx == &Giant) {
93168752Sscottl		sim->flags |= 0;
94168752Sscottl		callout_init(&sim->callout, 0);
95168752Sscottl	} else {
96168752Sscottl		sim->flags |= CAM_SIM_MPSAFE;
97168752Sscottl		callout_init(&sim->callout, 1);
9839212Sgibbs	}
9939212Sgibbs
100168752Sscottl	SLIST_INIT(&sim->ccb_freeq);
101168864Sscottl	TAILQ_INIT(&sim->sim_doneq);
102168752Sscottl
10339212Sgibbs	return (sim);
10439212Sgibbs}
10539212Sgibbs
10639212Sgibbsvoid
10739212Sgibbscam_sim_free(struct cam_sim *sim, int free_devq)
10839212Sgibbs{
109248800Smav	union ccb *ccb;
110186185Strasz	int error;
111186185Strasz
112186185Strasz	sim->refcount--;
113186185Strasz	if (sim->refcount > 0) {
114186185Strasz		error = msleep(sim, sim->mtx, PRIBIO, "simfree", 0);
115186185Strasz		KASSERT(error == 0, ("invalid error value for msleep(9)"));
116186185Strasz	}
117186185Strasz
118186185Strasz	KASSERT(sim->refcount == 0, ("sim->refcount == 0"));
119186185Strasz
120248800Smav	while ((ccb = (union ccb *)SLIST_FIRST(&sim->ccb_freeq)) != NULL) {
121248800Smav		SLIST_REMOVE_HEAD(&sim->ccb_freeq, xpt_links.sle);
122248800Smav		xpt_free_ccb(ccb);
123248800Smav	}
12439212Sgibbs	if (free_devq)
12539212Sgibbs		cam_simq_free(sim->devq);
126147723Savatar	free(sim, M_CAMSIM);
12739212Sgibbs}
12839212Sgibbs
12939212Sgibbsvoid
130186185Straszcam_sim_release(struct cam_sim *sim)
131186185Strasz{
132186185Strasz	KASSERT(sim->refcount >= 1, ("sim->refcount >= 1"));
133186320Strasz	mtx_assert(sim->mtx, MA_OWNED);
134186185Strasz
135186185Strasz	sim->refcount--;
136186320Strasz	if (sim->refcount == 0)
137186185Strasz		wakeup(sim);
138186185Strasz}
139186185Strasz
140186185Straszvoid
141186185Straszcam_sim_hold(struct cam_sim *sim)
142186185Strasz{
143186185Strasz	KASSERT(sim->refcount >= 1, ("sim->refcount >= 1"));
144186320Strasz	mtx_assert(sim->mtx, MA_OWNED);
145186185Strasz
146186185Strasz	sim->refcount++;
147186185Strasz}
148186185Strasz
149186185Straszvoid
15039212Sgibbscam_sim_set_path(struct cam_sim *sim, u_int32_t path_id)
15139212Sgibbs{
15239212Sgibbs	sim->path_id = path_id;
15339212Sgibbs}
154