1139743Simp/*-
2107178Snjl * Generic SCSI Target Kernel Mode Driver
339213Sgibbs *
4107178Snjl * Copyright (c) 2002 Nate Lawson.
5107178Snjl * Copyright (c) 1998, 1999, 2001, 2002 Justin T. Gibbs.
639213Sgibbs * All rights reserved.
739213Sgibbs *
839213Sgibbs * Redistribution and use in source and binary forms, with or without
939213Sgibbs * modification, are permitted provided that the following conditions
1039213Sgibbs * are met:
1139213Sgibbs * 1. Redistributions of source code must retain the above copyright
1239213Sgibbs *    notice, this list of conditions, and the following disclaimer,
1339213Sgibbs *    without modification, immediately at the beginning of the file.
1439213Sgibbs * 2. The name of the author may not be used to endorse or promote products
1539213Sgibbs *    derived from this software without specific prior written permission.
1639213Sgibbs *
1739213Sgibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1839213Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1939213Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2039213Sgibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
2139213Sgibbs * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2239213Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2339213Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2439213Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2539213Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2639213Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2739213Sgibbs * SUCH DAMAGE.
2839213Sgibbs */
2939213Sgibbs
30116162Sobrien#include <sys/cdefs.h>
31116162Sobrien__FBSDID("$FreeBSD: releng/10.3/sys/cam/scsi/scsi_target.c 288817 2015-10-05 11:45:28Z mav $");
32116162Sobrien
33158885Smjacob
3439213Sgibbs#include <sys/param.h>
3539213Sgibbs#include <sys/systm.h>
3639213Sgibbs#include <sys/kernel.h>
3739213Sgibbs#include <sys/conf.h>
3839213Sgibbs#include <sys/malloc.h>
3939213Sgibbs#include <sys/poll.h>
40107178Snjl#include <sys/vnode.h>
41107240Snjl#include <sys/lock.h>
42107240Snjl#include <sys/mutex.h>
43107178Snjl#include <sys/devicestat.h>
44158883Smjacob#include <sys/proc.h>
45197332Smjacob/* Includes to support callout */
46197332Smjacob#include <sys/types.h>
47197332Smjacob#include <sys/systm.h>
4839213Sgibbs
4939213Sgibbs#include <cam/cam.h>
5039213Sgibbs#include <cam/cam_ccb.h>
5139213Sgibbs#include <cam/cam_periph.h>
5239213Sgibbs#include <cam/cam_xpt_periph.h>
53168752Sscottl#include <cam/cam_sim.h>
5439213Sgibbs#include <cam/scsi/scsi_targetio.h>
5539213Sgibbs
56197332Smjacob
57107178Snjl/* Transaction information attached to each CCB sent by the user */
58107178Snjlstruct targ_cmd_descr {
59107178Snjl	struct cam_periph_map_info  mapinfo;
60107178Snjl	TAILQ_ENTRY(targ_cmd_descr) tqe;
61107178Snjl	union ccb *user_ccb;
62107178Snjl	int	   priority;
63107178Snjl	int	   func_code;
64107178Snjl};
6539213Sgibbs
66107178Snjl/* Offset into the private CCB area for storing our descriptor */
67107178Snjl#define targ_descr	periph_priv.entries[1].ptr
6839213Sgibbs
69107178SnjlTAILQ_HEAD(descr_queue, targ_cmd_descr);
70107178Snjl
7139213Sgibbstypedef enum {
72107178Snjl	TARG_STATE_RESV		= 0x00, /* Invalid state */
73107178Snjl	TARG_STATE_OPENED	= 0x01, /* Device opened, softc initialized */
74107178Snjl	TARG_STATE_LUN_ENABLED	= 0x02  /* Device enabled for a path */
75107178Snjl} targ_state;
7639213Sgibbs
77107178Snjl/* Per-instance device software context */
7839213Sgibbsstruct targ_softc {
79107178Snjl	/* CCBs (CTIOs, ATIOs, INOTs) pending on the controller */
80107178Snjl	struct ccb_queue	 pending_ccb_queue;
8149929Sgibbs
82107178Snjl	/* Command descriptors awaiting CTIO resources from the XPT */
83107178Snjl	struct descr_queue	 work_queue;
8449929Sgibbs
85107178Snjl	/* Command descriptors that have been aborted back to the user. */
86107178Snjl	struct descr_queue	 abort_queue;
8749929Sgibbs
8849929Sgibbs	/*
89107178Snjl	 * Queue of CCBs that have been copied out to userland, but our
90107178Snjl	 * userland daemon has not yet seen.
9149929Sgibbs	 */
92107178Snjl	struct ccb_queue	 user_ccb_queue;
9349929Sgibbs
94107178Snjl	struct cam_periph	*periph;
95107178Snjl	struct cam_path		*path;
96107178Snjl	targ_state		 state;
97288817Smav	u_int			 maxio;
98107178Snjl	struct selinfo		 read_select;
99107178Snjl	struct devstat		 device_stats;
10039213Sgibbs};
10139213Sgibbs
102107178Snjlstatic d_open_t		targopen;
103107178Snjlstatic d_read_t		targread;
104107178Snjlstatic d_write_t	targwrite;
105107178Snjlstatic d_ioctl_t	targioctl;
106107178Snjlstatic d_poll_t		targpoll;
107107178Snjlstatic d_kqfilter_t	targkqfilter;
108107178Snjlstatic void		targreadfiltdetach(struct knote *kn);
109107178Snjlstatic int		targreadfilt(struct knote *kn, long hint);
110197134Srwatsonstatic struct filterops targread_filtops = {
111197134Srwatson	.f_isfd = 1,
112197134Srwatson	.f_detach = targreadfiltdetach,
113197134Srwatson	.f_event = targreadfilt,
114197134Srwatson};
11539213Sgibbs
11639213Sgibbsstatic struct cdevsw targ_cdevsw = {
117126080Sphk	.d_version =	D_VERSION,
118126080Sphk	.d_flags =	D_NEEDGIANT,
119111815Sphk	.d_open =	targopen,
120111815Sphk	.d_read =	targread,
121111815Sphk	.d_write =	targwrite,
122111815Sphk	.d_ioctl =	targioctl,
123111815Sphk	.d_poll =	targpoll,
124111815Sphk	.d_name =	"targ",
125111815Sphk	.d_kqfilter =	targkqfilter
12639213Sgibbs};
12739213Sgibbs
128107178Snjlstatic cam_status	targendislun(struct cam_path *path, int enable,
129107178Snjl				     int grp6_len, int grp7_len);
130107178Snjlstatic cam_status	targenable(struct targ_softc *softc,
131107178Snjl				   struct cam_path *path,
132107178Snjl				   int grp6_len, int grp7_len);
133107178Snjlstatic cam_status	targdisable(struct targ_softc *softc);
134107178Snjlstatic periph_ctor_t    targctor;
135107178Snjlstatic periph_dtor_t    targdtor;
136107178Snjlstatic periph_start_t   targstart;
137107178Snjlstatic int		targusermerge(struct targ_softc *softc,
138107178Snjl				      struct targ_cmd_descr *descr,
139107178Snjl				      union ccb *ccb);
140107178Snjlstatic int		targsendccb(struct targ_softc *softc, union ccb *ccb,
141107178Snjl				    struct targ_cmd_descr *descr);
142107178Snjlstatic void		targdone(struct cam_periph *periph,
143107178Snjl				 union  ccb *done_ccb);
144107178Snjlstatic int		targreturnccb(struct targ_softc *softc,
145107178Snjl				      union  ccb *ccb);
146107178Snjlstatic union ccb *	targgetccb(struct targ_softc *softc, xpt_opcode type,
147107178Snjl				   int priority);
148107178Snjlstatic void		targfreeccb(struct targ_softc *softc, union ccb *ccb);
149107178Snjlstatic struct targ_cmd_descr *
150107178Snjl			targgetdescr(struct targ_softc *softc);
15139213Sgibbsstatic periph_init_t	targinit;
15239213Sgibbsstatic void		targasync(void *callback_arg, u_int32_t code,
153107178Snjl				  struct cam_path *path, void *arg);
154107178Snjlstatic void		abort_all_pending(struct targ_softc *softc);
155107178Snjlstatic void		notify_user(struct targ_softc *softc);
156107178Snjlstatic int		targcamstatus(cam_status status);
157107178Snjlstatic size_t		targccblen(xpt_opcode func_code);
158107178Snjl
15939213Sgibbsstatic struct periph_driver targdriver =
16039213Sgibbs{
16139213Sgibbs	targinit, "targ",
16239213Sgibbs	TAILQ_HEAD_INITIALIZER(targdriver.units), /* generation */ 0
16339213Sgibbs};
16472119SpeterPERIPHDRIVER_DECLARE(targ, targdriver);
16539213Sgibbs
166107178Snjlstatic MALLOC_DEFINE(M_TARG, "TARG", "TARG data");
16739213Sgibbs
168228481Sed/* Disable LUN if enabled and teardown softc */
169228481Sedstatic void
170228481Sedtargcdevdtor(void *data)
17139213Sgibbs{
17249929Sgibbs	struct targ_softc *softc;
173228481Sed	struct cam_periph *periph;
17439213Sgibbs
175228481Sed	softc = data;
176197332Smjacob	if (softc->periph == NULL) {
177228481Sed		printf("%s: destroying non-enabled target\n", __func__);
178184205Sdes		free(softc, M_TARG);
179228481Sed		return;
180168752Sscottl	}
181168752Sscottl
182168752Sscottl	/*
183168752Sscottl	 * Acquire a hold on the periph so that it doesn't go away before
184168752Sscottl	 * we are ready at the end of the function.
185168752Sscottl	 */
186168752Sscottl	periph = softc->periph;
187168752Sscottl	cam_periph_acquire(periph);
188168752Sscottl	cam_periph_lock(periph);
189228481Sed	(void)targdisable(softc);
190197332Smjacob	if (softc->periph != NULL) {
191197332Smjacob		cam_periph_invalidate(softc->periph);
192197332Smjacob		softc->periph = NULL;
19339213Sgibbs	}
194168752Sscottl	cam_periph_unlock(periph);
195168752Sscottl	cam_periph_release(periph);
196197332Smjacob	free(softc, M_TARG);
197228481Sed}
198197332Smjacob
199228481Sed/*
200228481Sed * Create softc and initialize it.  There is no locking here because a
201228481Sed * periph doesn't get created until an ioctl is issued to do so, and
202228481Sed * that can't happen until this method returns.
203228481Sed */
204228481Sedstatic int
205228481Sedtargopen(struct cdev *dev, int flags, int fmt, struct thread *td)
206228481Sed{
207228481Sed	struct targ_softc *softc;
208228481Sed
209228481Sed	/* Allocate its softc, initialize it */
210228481Sed	softc = malloc(sizeof(*softc), M_TARG,
211228481Sed	       M_WAITOK | M_ZERO);
212228481Sed	softc->state = TARG_STATE_OPENED;
213228481Sed	softc->periph = NULL;
214228481Sed	softc->path = NULL;
215228481Sed
216228481Sed	TAILQ_INIT(&softc->pending_ccb_queue);
217228481Sed	TAILQ_INIT(&softc->work_queue);
218228481Sed	TAILQ_INIT(&softc->abort_queue);
219228481Sed	TAILQ_INIT(&softc->user_ccb_queue);
220228481Sed	knlist_init_mtx(&softc->read_select.si_note, NULL);
221228481Sed
222228481Sed	devfs_set_cdevpriv(softc, targcdevdtor);
223228481Sed	return (0);
224107178Snjl}
22539213Sgibbs
226107178Snjl/* Enable/disable LUNs, set debugging level */
227107178Snjlstatic int
228130585Sphktargioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td)
229107178Snjl{
230107178Snjl	struct targ_softc *softc;
231107178Snjl	cam_status	   status;
23239213Sgibbs
233228481Sed	devfs_get_cdevpriv((void **)&softc);
23439213Sgibbs
235107178Snjl	switch (cmd) {
236107178Snjl	case TARGIOCENABLE:
237107178Snjl	{
238107178Snjl		struct ioc_enable_lun	*new_lun;
239107178Snjl		struct cam_path		*path;
24039213Sgibbs
241107178Snjl		new_lun = (struct ioc_enable_lun *)addr;
242260387Sscottl		status = xpt_create_path(&path, /*periph*/NULL,
243260387Sscottl					  new_lun->path_id,
244260387Sscottl					  new_lun->target_id,
245260387Sscottl					  new_lun->lun_id);
246107178Snjl		if (status != CAM_REQ_CMP) {
247107178Snjl			printf("Couldn't create path, status %#x\n", status);
24839213Sgibbs			break;
24939213Sgibbs		}
250260387Sscottl		xpt_path_lock(path);
251107178Snjl		status = targenable(softc, path, new_lun->grp6_len,
252107178Snjl				    new_lun->grp7_len);
253260387Sscottl		xpt_path_unlock(path);
254107178Snjl		xpt_free_path(path);
255107178Snjl		break;
25639213Sgibbs	}
257107178Snjl	case TARGIOCDISABLE:
258168752Sscottl		if (softc->periph == NULL) {
259168752Sscottl			status = CAM_DEV_NOT_THERE;
260168752Sscottl			break;
261168752Sscottl		}
262168752Sscottl		cam_periph_lock(softc->periph);
263107178Snjl		status = targdisable(softc);
264168752Sscottl		cam_periph_unlock(softc->periph);
265107178Snjl		break;
266107178Snjl	case TARGIOCDEBUG:
267107178Snjl	{
268107178Snjl		struct ccb_debug cdbg;
26939213Sgibbs
270168752Sscottl		/* If no periph available, disallow debugging changes */
271168752Sscottl		if ((softc->state & TARG_STATE_LUN_ENABLED) == 0) {
272168752Sscottl			status = CAM_DEV_NOT_THERE;
273168752Sscottl			break;
274168752Sscottl		}
275107178Snjl		bzero(&cdbg, sizeof cdbg);
276107178Snjl		if (*((int *)addr) != 0)
277107178Snjl			cdbg.flags = CAM_DEBUG_PERIPH;
278107178Snjl		else
279107178Snjl			cdbg.flags = CAM_DEBUG_NONE;
280198382Smav		xpt_setup_ccb(&cdbg.ccb_h, softc->path, CAM_PRIORITY_NORMAL);
281107178Snjl		cdbg.ccb_h.func_code = XPT_DEBUG;
282107178Snjl		cdbg.ccb_h.cbfcnp = targdone;
283107178Snjl		xpt_action((union ccb *)&cdbg);
284107178Snjl		status = cdbg.ccb_h.status & CAM_STATUS_MASK;
285107178Snjl		break;
28639213Sgibbs	}
287107178Snjl	default:
288107178Snjl		status = CAM_PROVIDE_FAIL;
289107178Snjl		break;
29039213Sgibbs	}
29139213Sgibbs
292107178Snjl	return (targcamstatus(status));
29339213Sgibbs}
29439213Sgibbs
295107178Snjl/* Writes are always ready, reads wait for user_ccb_queue or abort_queue */
296107178Snjlstatic int
297130585Sphktargpoll(struct cdev *dev, int poll_events, struct thread *td)
29841815Sgibbs{
29941815Sgibbs	struct targ_softc *softc;
300107178Snjl	int	revents;
30141815Sgibbs
302228481Sed	devfs_get_cdevpriv((void **)&softc);
30341815Sgibbs
304107178Snjl	/* Poll for write() is always ok. */
305107178Snjl	revents = poll_events & (POLLOUT | POLLWRNORM);
306107178Snjl	if ((poll_events & (POLLIN | POLLRDNORM)) != 0) {
307107178Snjl		/* Poll for read() depends on user and abort queues. */
308168752Sscottl		cam_periph_lock(softc->periph);
309107178Snjl		if (!TAILQ_EMPTY(&softc->user_ccb_queue) ||
310107178Snjl		    !TAILQ_EMPTY(&softc->abort_queue)) {
311107178Snjl			revents |= poll_events & (POLLIN | POLLRDNORM);
312107178Snjl		}
313168752Sscottl		cam_periph_unlock(softc->periph);
314107178Snjl		/* Only sleep if the user didn't poll for write. */
315107178Snjl		if (revents == 0)
316107178Snjl			selrecord(td, &softc->read_select);
31741815Sgibbs	}
31841815Sgibbs
319107178Snjl	return (revents);
32041815Sgibbs}
32141815Sgibbs
322107178Snjlstatic int
323130585Sphktargkqfilter(struct cdev *dev, struct knote *kn)
32441815Sgibbs{
325107178Snjl	struct  targ_softc *softc;
32641815Sgibbs
327228481Sed	devfs_get_cdevpriv((void **)&softc);
328107178Snjl	kn->kn_hook = (caddr_t)softc;
329107178Snjl	kn->kn_fop = &targread_filtops;
330133741Sjmg	knlist_add(&softc->read_select.si_note, kn, 0);
331107178Snjl	return (0);
33241815Sgibbs}
33341815Sgibbs
33439213Sgibbsstatic void
335107178Snjltargreadfiltdetach(struct knote *kn)
33639213Sgibbs{
337107178Snjl	struct  targ_softc *softc;
33839213Sgibbs
339107178Snjl	softc = (struct targ_softc *)kn->kn_hook;
340133741Sjmg	knlist_remove(&softc->read_select.si_note, kn, 0);
34139213Sgibbs}
34239213Sgibbs
343107178Snjl/* Notify the user's kqueue when the user queue or abort queue gets a CCB */
34439213Sgibbsstatic int
345107178Snjltargreadfilt(struct knote *kn, long hint)
34639213Sgibbs{
347107178Snjl	struct targ_softc *softc;
348107178Snjl	int	retval;
34939213Sgibbs
350107178Snjl	softc = (struct targ_softc *)kn->kn_hook;
351168752Sscottl	cam_periph_lock(softc->periph);
352107178Snjl	retval = !TAILQ_EMPTY(&softc->user_ccb_queue) ||
353107178Snjl		 !TAILQ_EMPTY(&softc->abort_queue);
354168752Sscottl	cam_periph_unlock(softc->periph);
355107178Snjl	return (retval);
35639213Sgibbs}
35739213Sgibbs
358107178Snjl/* Send the HBA the enable/disable message */
359107178Snjlstatic cam_status
360107178Snjltargendislun(struct cam_path *path, int enable, int grp6_len, int grp7_len)
36139213Sgibbs{
362107178Snjl	struct ccb_en_lun en_ccb;
363107178Snjl	cam_status	  status;
36439213Sgibbs
365107178Snjl	/* Tell the lun to begin answering selects */
366198382Smav	xpt_setup_ccb(&en_ccb.ccb_h, path, CAM_PRIORITY_NORMAL);
367107178Snjl	en_ccb.ccb_h.func_code = XPT_EN_LUN;
368107178Snjl	/* Don't need support for any vendor specific commands */
369107178Snjl	en_ccb.grp6_len = grp6_len;
370107178Snjl	en_ccb.grp7_len = grp7_len;
371107178Snjl	en_ccb.enable = enable ? 1 : 0;
372107178Snjl	xpt_action((union ccb *)&en_ccb);
373107178Snjl	status = en_ccb.ccb_h.status & CAM_STATUS_MASK;
374107178Snjl	if (status != CAM_REQ_CMP) {
375164906Smjacob		xpt_print(path, "%sable lun CCB rejected, status %#x\n",
376164906Smjacob		    enable ? "en" : "dis", status);
37741815Sgibbs	}
378107178Snjl	return (status);
37939213Sgibbs}
38039213Sgibbs
381107178Snjl/* Enable target mode on a LUN, given its path */
382107178Snjlstatic cam_status
383107178Snjltargenable(struct targ_softc *softc, struct cam_path *path, int grp6_len,
384107178Snjl	   int grp7_len)
38544504Sgibbs{
386107178Snjl	struct cam_periph *periph;
38744504Sgibbs	struct ccb_pathinq cpi;
388107178Snjl	cam_status	   status;
38944504Sgibbs
390107178Snjl	if ((softc->state & TARG_STATE_LUN_ENABLED) != 0)
391107178Snjl		return (CAM_LUN_ALRDY_ENA);
39252575Smjacob
393107178Snjl	/* Make sure SIM supports target mode */
394198382Smav	xpt_setup_ccb(&cpi.ccb_h, path, CAM_PRIORITY_NORMAL);
39544504Sgibbs	cpi.ccb_h.func_code = XPT_PATH_INQ;
39644504Sgibbs	xpt_action((union ccb *)&cpi);
397107178Snjl	status = cpi.ccb_h.status & CAM_STATUS_MASK;
39844504Sgibbs	if (status != CAM_REQ_CMP) {
399107178Snjl		printf("pathinq failed, status %#x\n", status);
400107178Snjl		goto enable_fail;
40144504Sgibbs	}
40244504Sgibbs	if ((cpi.target_sprt & PIT_PROCESSOR) == 0) {
403107178Snjl		printf("controller does not support target mode\n");
404107178Snjl		status = CAM_FUNC_NOTAVAIL;
405107178Snjl		goto enable_fail;
40644504Sgibbs	}
407288817Smav	if (cpi.maxio == 0)
408288817Smav		softc->maxio = DFLTPHYS;	/* traditional default */
409288817Smav	else if (cpi.maxio > MAXPHYS)
410288817Smav		softc->maxio = MAXPHYS;		/* for safety */
411288817Smav	else
412288817Smav		softc->maxio = cpi.maxio;	/* real value */
41344504Sgibbs
414107178Snjl	/* Destroy any periph on our path if it is disabled */
415107178Snjl	periph = cam_periph_find(path, "targ");
416107178Snjl	if (periph != NULL) {
417107178Snjl		struct targ_softc *del_softc;
41844504Sgibbs
419107178Snjl		del_softc = (struct targ_softc *)periph->softc;
420107178Snjl		if ((del_softc->state & TARG_STATE_LUN_ENABLED) == 0) {
421107178Snjl			cam_periph_invalidate(del_softc->periph);
422107178Snjl			del_softc->periph = NULL;
423107178Snjl		} else {
424107178Snjl			printf("Requested path still in use by targ%d\n",
425107178Snjl			       periph->unit_number);
426107178Snjl			status = CAM_LUN_ALRDY_ENA;
427107178Snjl			goto enable_fail;
428107178Snjl		}
42980574Smjacob	}
43080574Smjacob
431107178Snjl	/* Create a periph instance attached to this path */
43244504Sgibbs	status = cam_periph_alloc(targctor, NULL, targdtor, targstart,
433107178Snjl			"targ", CAM_PERIPH_BIO, path, targasync, 0, softc);
434107178Snjl	if (status != CAM_REQ_CMP) {
435107178Snjl		printf("cam_periph_alloc failed, status %#x\n", status);
436107178Snjl		goto enable_fail;
437107178Snjl	}
43844504Sgibbs
439107178Snjl	/* Ensure that the periph now exists. */
440107178Snjl	if (cam_periph_find(path, "targ") == NULL) {
441107178Snjl		panic("targenable: succeeded but no periph?");
442107178Snjl		/* NOTREACHED */
443107178Snjl	}
44444504Sgibbs
445107178Snjl	/* Send the enable lun message */
446107178Snjl	status = targendislun(path, /*enable*/1, grp6_len, grp7_len);
447107178Snjl	if (status != CAM_REQ_CMP) {
448107178Snjl		printf("enable lun failed, status %#x\n", status);
449107178Snjl		goto enable_fail;
45044504Sgibbs	}
451107178Snjl	softc->state |= TARG_STATE_LUN_ENABLED;
45246437Sgibbs
453107178Snjlenable_fail:
454107178Snjl	return (status);
455107178Snjl}
45646437Sgibbs
457107178Snjl/* Disable this softc's target instance if enabled */
458107178Snjlstatic cam_status
459107178Snjltargdisable(struct targ_softc *softc)
460107178Snjl{
461107178Snjl	cam_status status;
462107178Snjl
463107178Snjl	if ((softc->state & TARG_STATE_LUN_ENABLED) == 0)
464107178Snjl		return (CAM_REQ_CMP);
465107178Snjl
466107178Snjl	CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, ("targdisable\n"));
467107178Snjl
468107178Snjl	/* Abort any ccbs pending on the controller */
469107178Snjl	abort_all_pending(softc);
470107178Snjl
471107178Snjl	/* Disable this lun */
472107178Snjl	status = targendislun(softc->path, /*enable*/0,
473107178Snjl			      /*grp6_len*/0, /*grp7_len*/0);
474107178Snjl	if (status == CAM_REQ_CMP)
475107178Snjl		softc->state &= ~TARG_STATE_LUN_ENABLED;
476107178Snjl	else
477107178Snjl		printf("Disable lun failed, status %#x\n", status);
478107178Snjl
479107178Snjl	return (status);
48044504Sgibbs}
48144504Sgibbs
482107178Snjl/* Initialize a periph (called from cam_periph_alloc) */
483107178Snjlstatic cam_status
484107178Snjltargctor(struct cam_periph *periph, void *arg)
48544504Sgibbs{
48644504Sgibbs	struct targ_softc *softc;
48744504Sgibbs
488107178Snjl	/* Store pointer to softc for periph-driven routines */
489107178Snjl	softc = (struct targ_softc *)arg;
490107178Snjl	periph->softc = softc;
491107178Snjl	softc->periph = periph;
492107178Snjl	softc->path = periph->path;
493107178Snjl	return (CAM_REQ_CMP);
494107178Snjl}
49544504Sgibbs
496107178Snjlstatic void
497107178Snjltargdtor(struct cam_periph *periph)
498107178Snjl{
499107178Snjl	struct targ_softc     *softc;
500107178Snjl	struct ccb_hdr	      *ccb_h;
501107178Snjl	struct targ_cmd_descr *descr;
50244504Sgibbs
503107178Snjl	softc = (struct targ_softc *)periph->softc;
504107178Snjl
505107178Snjl	/*
506107178Snjl	 * targdisable() aborts CCBs back to the user and leaves them
507107178Snjl	 * on user_ccb_queue and abort_queue in case the user is still
508107178Snjl	 * interested in them.  We free them now.
509107178Snjl	 */
510107178Snjl	while ((ccb_h = TAILQ_FIRST(&softc->user_ccb_queue)) != NULL) {
511107178Snjl		TAILQ_REMOVE(&softc->user_ccb_queue, ccb_h, periph_links.tqe);
512107178Snjl		targfreeccb(softc, (union ccb *)ccb_h);
51344504Sgibbs	}
514107178Snjl	while ((descr = TAILQ_FIRST(&softc->abort_queue)) != NULL) {
515107178Snjl		TAILQ_REMOVE(&softc->abort_queue, descr, tqe);
516184205Sdes		free(descr, M_TARG);
517107178Snjl	}
51844504Sgibbs
519107178Snjl	softc->periph = NULL;
520107178Snjl	softc->path = NULL;
521107178Snjl	periph->softc = NULL;
52244504Sgibbs}
52344504Sgibbs
524107178Snjl/* Receive CCBs from user mode proc and send them to the HBA */
52544504Sgibbsstatic int
526130585Sphktargwrite(struct cdev *dev, struct uio *uio, int ioflag)
52739213Sgibbs{
528107178Snjl	union ccb *user_ccb;
52939213Sgibbs	struct targ_softc *softc;
530107178Snjl	struct targ_cmd_descr *descr;
531107178Snjl	int write_len, error;
532107178Snjl	int func_code, priority;
53339213Sgibbs
534228481Sed	devfs_get_cdevpriv((void **)&softc);
535107178Snjl	write_len = error = 0;
536107178Snjl	CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH,
537194990Skib		  ("write - uio_resid %zd\n", uio->uio_resid));
538107178Snjl	while (uio->uio_resid >= sizeof(user_ccb) && error == 0) {
539107178Snjl		union ccb *ccb;
540107178Snjl
541107178Snjl		error = uiomove((caddr_t)&user_ccb, sizeof(user_ccb), uio);
542107178Snjl		if (error != 0) {
543107178Snjl			CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH,
544107178Snjl				  ("write - uiomove failed (%d)\n", error));
54544504Sgibbs			break;
546107178Snjl		}
547120663Ssimokawa		priority = fuword32(&user_ccb->ccb_h.pinfo.priority);
548198382Smav		if (priority == CAM_PRIORITY_NONE) {
549107178Snjl			error = EINVAL;
55044504Sgibbs			break;
551107178Snjl		}
552120663Ssimokawa		func_code = fuword32(&user_ccb->ccb_h.func_code);
553107178Snjl		switch (func_code) {
554107178Snjl		case XPT_ACCEPT_TARGET_IO:
555107178Snjl		case XPT_IMMED_NOTIFY:
556255120Smav		case XPT_IMMEDIATE_NOTIFY:
557168752Sscottl			cam_periph_lock(softc->periph);
558107178Snjl			ccb = targgetccb(softc, func_code, priority);
559107178Snjl			descr = (struct targ_cmd_descr *)ccb->ccb_h.targ_descr;
560107178Snjl			descr->user_ccb = user_ccb;
561107178Snjl			descr->func_code = func_code;
562107178Snjl			CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH,
563107178Snjl				  ("Sent ATIO/INOT (%p)\n", user_ccb));
564107178Snjl			xpt_action(ccb);
565107178Snjl			TAILQ_INSERT_TAIL(&softc->pending_ccb_queue,
566107178Snjl					  &ccb->ccb_h,
567107178Snjl					  periph_links.tqe);
568168752Sscottl			cam_periph_unlock(softc->periph);
569107178Snjl			break;
57044504Sgibbs		default:
571168752Sscottl			cam_periph_lock(softc->periph);
572107178Snjl			if ((func_code & XPT_FC_QUEUED) != 0) {
573107178Snjl				CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH,
574107178Snjl					  ("Sending queued ccb %#x (%p)\n",
575107178Snjl					  func_code, user_ccb));
576107178Snjl				descr = targgetdescr(softc);
577107178Snjl				descr->user_ccb = user_ccb;
578107178Snjl				descr->priority = priority;
579107178Snjl				descr->func_code = func_code;
580107178Snjl				TAILQ_INSERT_TAIL(&softc->work_queue,
581107178Snjl						  descr, tqe);
582107178Snjl				xpt_schedule(softc->periph, priority);
583107178Snjl			} else {
584107178Snjl				CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH,
585107178Snjl					  ("Sending inline ccb %#x (%p)\n",
586107178Snjl					  func_code, user_ccb));
587107178Snjl				ccb = targgetccb(softc, func_code, priority);
588107178Snjl				descr = (struct targ_cmd_descr *)
589107178Snjl					 ccb->ccb_h.targ_descr;
590107178Snjl				descr->user_ccb = user_ccb;
591107178Snjl				descr->priority = priority;
592107178Snjl				descr->func_code = func_code;
593107178Snjl				if (targusermerge(softc, descr, ccb) != EFAULT)
594107178Snjl					targsendccb(softc, ccb, descr);
595107178Snjl				targreturnccb(softc, ccb);
596107178Snjl			}
597168752Sscottl			cam_periph_unlock(softc->periph);
59844504Sgibbs			break;
59944504Sgibbs		}
600107178Snjl		write_len += sizeof(user_ccb);
601107178Snjl	}
602107178Snjl
603107178Snjl	/*
604107178Snjl	 * If we've successfully taken in some amount of
605107178Snjl	 * data, return success for that data first.  If
606107178Snjl	 * an error is persistent, it will be reported
607107178Snjl	 * on the next write.
608107178Snjl	 */
609107178Snjl	if (error != 0 && write_len == 0)
61044504Sgibbs		return (error);
611107178Snjl	if (write_len == 0 && uio->uio_resid != 0)
612107178Snjl		return (ENOSPC);
613107178Snjl	return (0);
614107178Snjl}
61544504Sgibbs
616107178Snjl/* Process requests (descrs) via the periph-supplied CCBs */
617107178Snjlstatic void
618107178Snjltargstart(struct cam_periph *periph, union ccb *start_ccb)
619107178Snjl{
620107178Snjl	struct targ_softc *softc;
621107178Snjl	struct targ_cmd_descr *descr, *next_descr;
622107178Snjl	int error;
623107178Snjl
62439213Sgibbs	softc = (struct targ_softc *)periph->softc;
625107178Snjl	CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, ("targstart %p\n", start_ccb));
62639213Sgibbs
627107178Snjl	descr = TAILQ_FIRST(&softc->work_queue);
628107178Snjl	if (descr == NULL) {
629107178Snjl		xpt_release_ccb(start_ccb);
630107178Snjl	} else {
631107178Snjl		TAILQ_REMOVE(&softc->work_queue, descr, tqe);
632107178Snjl		next_descr = TAILQ_FIRST(&softc->work_queue);
63339213Sgibbs
634107178Snjl		/* Initiate a transaction using the descr and supplied CCB */
635107178Snjl		error = targusermerge(softc, descr, start_ccb);
636107178Snjl		if (error == 0)
637107178Snjl			error = targsendccb(softc, start_ccb, descr);
638107178Snjl		if (error != 0) {
639164906Smjacob			xpt_print(periph->path,
640164906Smjacob			    "targsendccb failed, err %d\n", error);
641107178Snjl			xpt_release_ccb(start_ccb);
642107178Snjl			suword(&descr->user_ccb->ccb_h.status,
643107178Snjl			       CAM_REQ_CMP_ERR);
644107178Snjl			TAILQ_INSERT_TAIL(&softc->abort_queue, descr, tqe);
645107178Snjl			notify_user(softc);
64639213Sgibbs		}
64739213Sgibbs
648107178Snjl		/* If we have more work to do, stay scheduled */
649107178Snjl		if (next_descr != NULL)
650107178Snjl			xpt_schedule(periph, next_descr->priority);
65139213Sgibbs	}
652107178Snjl}
65339213Sgibbs
654107178Snjlstatic int
655107178Snjltargusermerge(struct targ_softc *softc, struct targ_cmd_descr *descr,
656107178Snjl	      union ccb *ccb)
657107178Snjl{
658107178Snjl	struct ccb_hdr *u_ccbh, *k_ccbh;
659107178Snjl	size_t ccb_len;
660107178Snjl	int error;
66139213Sgibbs
662107178Snjl	u_ccbh = &descr->user_ccb->ccb_h;
663107178Snjl	k_ccbh = &ccb->ccb_h;
66439213Sgibbs
665107178Snjl	/*
666107178Snjl	 * There are some fields in the CCB header that need to be
667107178Snjl	 * preserved, the rest we get from the user ccb. (See xpt_merge_ccb)
668107178Snjl	 */
669107178Snjl	xpt_setup_ccb(k_ccbh, softc->path, descr->priority);
670120663Ssimokawa	k_ccbh->retry_count = fuword32(&u_ccbh->retry_count);
671107178Snjl	k_ccbh->func_code = descr->func_code;
672120663Ssimokawa	k_ccbh->flags = fuword32(&u_ccbh->flags);
673120663Ssimokawa	k_ccbh->timeout = fuword32(&u_ccbh->timeout);
674107178Snjl	ccb_len = targccblen(k_ccbh->func_code) - sizeof(struct ccb_hdr);
675107178Snjl	error = copyin(u_ccbh + 1, k_ccbh + 1, ccb_len);
676107178Snjl	if (error != 0) {
677107178Snjl		k_ccbh->status = CAM_REQ_CMP_ERR;
678107178Snjl		return (error);
67939213Sgibbs	}
68039213Sgibbs
681107178Snjl	/* Translate usermode abort_ccb pointer to its kernel counterpart */
682107178Snjl	if (k_ccbh->func_code == XPT_ABORT) {
683107178Snjl		struct ccb_abort *cab;
684107178Snjl		struct ccb_hdr *ccb_h;
685107178Snjl
686107178Snjl		cab = (struct ccb_abort *)ccb;
687107178Snjl		TAILQ_FOREACH(ccb_h, &softc->pending_ccb_queue,
688107178Snjl		    periph_links.tqe) {
689107178Snjl			struct targ_cmd_descr *ab_descr;
690107178Snjl
691107178Snjl			ab_descr = (struct targ_cmd_descr *)ccb_h->targ_descr;
692107178Snjl			if (ab_descr->user_ccb == cab->abort_ccb) {
693107178Snjl				CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH,
694107178Snjl					  ("Changing abort for %p to %p\n",
695107178Snjl					  cab->abort_ccb, ccb_h));
696107178Snjl				cab->abort_ccb = (union ccb *)ccb_h;
697107178Snjl				break;
698107178Snjl			}
69939213Sgibbs		}
700107178Snjl		/* CCB not found, set appropriate status */
701107178Snjl		if (ccb_h == NULL) {
702107178Snjl			k_ccbh->status = CAM_PATH_INVALID;
703107178Snjl			error = ESRCH;
70439213Sgibbs		}
70539213Sgibbs	}
706107178Snjl
70739213Sgibbs	return (error);
70839213Sgibbs}
70939213Sgibbs
710107178Snjl/* Build and send a kernel CCB formed from descr->user_ccb */
71139213Sgibbsstatic int
712107178Snjltargsendccb(struct targ_softc *softc, union ccb *ccb,
713107178Snjl	    struct targ_cmd_descr *descr)
71439213Sgibbs{
715107178Snjl	struct cam_periph_map_info *mapinfo;
716107178Snjl	struct ccb_hdr *ccb_h;
717107178Snjl	int error;
71839213Sgibbs
719107178Snjl	ccb_h = &ccb->ccb_h;
720107178Snjl	mapinfo = &descr->mapinfo;
721107178Snjl	mapinfo->num_bufs_used = 0;
72239213Sgibbs
72339213Sgibbs	/*
72439213Sgibbs	 * There's no way for the user to have a completion
72539213Sgibbs	 * function, so we put our own completion function in here.
726107178Snjl	 * We also stash in a reference to our descriptor so targreturnccb()
727107178Snjl	 * can find our mapping info.
72839213Sgibbs	 */
729107178Snjl	ccb_h->cbfcnp = targdone;
730107178Snjl	ccb_h->targ_descr = descr;
73139213Sgibbs
732251479Sscottl	if ((ccb_h->func_code == XPT_CONT_TARGET_IO) ||
733251479Sscottl	    (ccb_h->func_code == XPT_DEV_MATCH)) {
73439213Sgibbs
735288817Smav		error = cam_periph_mapmem(ccb, mapinfo, softc->maxio);
73639213Sgibbs
73739213Sgibbs		/*
73839213Sgibbs		 * cam_periph_mapmem returned an error, we can't continue.
73939213Sgibbs		 * Return the error to the user.
74039213Sgibbs		 */
741107178Snjl		if (error) {
742107178Snjl			ccb_h->status = CAM_REQ_CMP_ERR;
743107178Snjl			mapinfo->num_bufs_used = 0;
744107178Snjl			return (error);
745107178Snjl		}
74639213Sgibbs	}
74739213Sgibbs
74839213Sgibbs	/*
74949929Sgibbs	 * Once queued on the pending CCB list, this CCB will be protected
750107178Snjl	 * by our error recovery handler.
75139213Sgibbs	 */
752107178Snjl	CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, ("sendccb %p\n", ccb));
753107178Snjl	if (XPT_FC_IS_QUEUED(ccb)) {
754107178Snjl		TAILQ_INSERT_TAIL(&softc->pending_ccb_queue, ccb_h,
755107178Snjl				  periph_links.tqe);
75649929Sgibbs	}
757107178Snjl	xpt_action(ccb);
75849929Sgibbs
759107178Snjl	return (0);
76039213Sgibbs}
76139213Sgibbs
762107178Snjl/* Completion routine for CCBs (called at splsoftcam) */
763107178Snjlstatic void
764107178Snjltargdone(struct cam_periph *periph, union ccb *done_ccb)
76539213Sgibbs{
76639213Sgibbs	struct targ_softc *softc;
767107178Snjl	cam_status status;
76839213Sgibbs
769107178Snjl	CAM_DEBUG(periph->path, CAM_DEBUG_PERIPH, ("targdone %p\n", done_ccb));
77039213Sgibbs	softc = (struct targ_softc *)periph->softc;
771107178Snjl	TAILQ_REMOVE(&softc->pending_ccb_queue, &done_ccb->ccb_h,
772107178Snjl		     periph_links.tqe);
773107178Snjl	status = done_ccb->ccb_h.status & CAM_STATUS_MASK;
77439213Sgibbs
775107178Snjl	/* If we're no longer enabled, throw away CCB */
776107178Snjl	if ((softc->state & TARG_STATE_LUN_ENABLED) == 0) {
777107178Snjl		targfreeccb(softc, done_ccb);
778107178Snjl		return;
77939213Sgibbs	}
780107178Snjl	/* abort_all_pending() waits for pending queue to be empty */
781107178Snjl	if (TAILQ_EMPTY(&softc->pending_ccb_queue))
782107178Snjl		wakeup(&softc->pending_ccb_queue);
78339213Sgibbs
784107178Snjl	switch (done_ccb->ccb_h.func_code) {
785107178Snjl	/* All FC_*_QUEUED CCBs go back to userland */
786107178Snjl	case XPT_IMMED_NOTIFY:
787255120Smav	case XPT_IMMEDIATE_NOTIFY:
788107178Snjl	case XPT_ACCEPT_TARGET_IO:
789107178Snjl	case XPT_CONT_TARGET_IO:
790107178Snjl		TAILQ_INSERT_TAIL(&softc->user_ccb_queue, &done_ccb->ccb_h,
791107178Snjl				  periph_links.tqe);
792197332Smjacob 		cam_periph_unlock(softc->periph);
793107178Snjl		notify_user(softc);
794197332Smjacob 		cam_periph_lock(softc->periph);
795107178Snjl		break;
796107178Snjl	default:
797107178Snjl		panic("targdone: impossible xpt opcode %#x",
798107178Snjl		      done_ccb->ccb_h.func_code);
799107178Snjl		/* NOTREACHED */
80039213Sgibbs	}
80139213Sgibbs}
80239213Sgibbs
803107178Snjl/* Return CCBs to the user from the user queue and abort queue */
80439213Sgibbsstatic int
805130585Sphktargread(struct cdev *dev, struct uio *uio, int ioflag)
80639213Sgibbs{
807107178Snjl	struct descr_queue	*abort_queue;
808107178Snjl	struct targ_cmd_descr	*user_descr;
809107178Snjl	struct targ_softc	*softc;
810107178Snjl	struct ccb_queue  *user_queue;
811107178Snjl	struct ccb_hdr	  *ccb_h;
812107178Snjl	union  ccb	  *user_ccb;
813107178Snjl	int		   read_len, error;
81444504Sgibbs
815107178Snjl	error = 0;
816107178Snjl	read_len = 0;
817228481Sed	devfs_get_cdevpriv((void **)&softc);
818107178Snjl	user_queue = &softc->user_ccb_queue;
819107178Snjl	abort_queue = &softc->abort_queue;
820107178Snjl	CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, ("targread\n"));
82139213Sgibbs
822107178Snjl	/* If no data is available, wait or return immediately */
823168752Sscottl	cam_periph_lock(softc->periph);
824107178Snjl	ccb_h = TAILQ_FIRST(user_queue);
825107178Snjl	user_descr = TAILQ_FIRST(abort_queue);
826107178Snjl	while (ccb_h == NULL && user_descr == NULL) {
827107178Snjl		if ((ioflag & IO_NDELAY) == 0) {
828260387Sscottl			error = cam_periph_sleep(softc->periph, user_queue,
829167082Sjhb			    PRIBIO | PCATCH, "targrd", 0);
830107178Snjl			ccb_h = TAILQ_FIRST(user_queue);
831107178Snjl			user_descr = TAILQ_FIRST(abort_queue);
832107178Snjl			if (error != 0) {
833107178Snjl				if (error == ERESTART) {
834107178Snjl					continue;
835107178Snjl				} else {
836107178Snjl					goto read_fail;
837107178Snjl				}
838107178Snjl			}
839107178Snjl		} else {
840168752Sscottl			cam_periph_unlock(softc->periph);
841107178Snjl			return (EAGAIN);
842107178Snjl		}
84339213Sgibbs	}
84439213Sgibbs
845107178Snjl	/* Data is available so fill the user's buffer */
846107178Snjl	while (ccb_h != NULL) {
847107178Snjl		struct targ_cmd_descr *descr;
84844504Sgibbs
849107178Snjl		if (uio->uio_resid < sizeof(user_ccb))
850107178Snjl			break;
851107178Snjl		TAILQ_REMOVE(user_queue, ccb_h, periph_links.tqe);
852107178Snjl		descr = (struct targ_cmd_descr *)ccb_h->targ_descr;
853107178Snjl		user_ccb = descr->user_ccb;
854107178Snjl		CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH,
855107178Snjl			  ("targread ccb %p (%p)\n", ccb_h, user_ccb));
856107178Snjl		error = targreturnccb(softc, (union ccb *)ccb_h);
857107178Snjl		if (error != 0)
858107178Snjl			goto read_fail;
859168752Sscottl		cam_periph_unlock(softc->periph);
860107178Snjl		error = uiomove((caddr_t)&user_ccb, sizeof(user_ccb), uio);
861168752Sscottl		cam_periph_lock(softc->periph);
862107178Snjl		if (error != 0)
863107178Snjl			goto read_fail;
864107178Snjl		read_len += sizeof(user_ccb);
86544504Sgibbs
866107178Snjl		ccb_h = TAILQ_FIRST(user_queue);
86739213Sgibbs	}
86839213Sgibbs
869107178Snjl	/* Flush out any aborted descriptors */
870107178Snjl	while (user_descr != NULL) {
871107178Snjl		if (uio->uio_resid < sizeof(user_ccb))
872107178Snjl			break;
873107178Snjl		TAILQ_REMOVE(abort_queue, user_descr, tqe);
874107178Snjl		user_ccb = user_descr->user_ccb;
875107178Snjl		CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH,
876107178Snjl			  ("targread aborted descr %p (%p)\n",
877107178Snjl			  user_descr, user_ccb));
878107178Snjl		suword(&user_ccb->ccb_h.status, CAM_REQ_ABORTED);
879168752Sscottl		cam_periph_unlock(softc->periph);
880107178Snjl		error = uiomove((caddr_t)&user_ccb, sizeof(user_ccb), uio);
881168752Sscottl		cam_periph_lock(softc->periph);
882107178Snjl		if (error != 0)
883107178Snjl			goto read_fail;
884107178Snjl		read_len += sizeof(user_ccb);
885107178Snjl
886107178Snjl		user_descr = TAILQ_FIRST(abort_queue);
88739213Sgibbs	}
88839213Sgibbs
88939213Sgibbs	/*
890107178Snjl	 * If we've successfully read some amount of data, don't report an
891107178Snjl	 * error.  If the error is persistent, it will be reported on the
892107178Snjl	 * next read().
89339213Sgibbs	 */
894107178Snjl	if (read_len == 0 && uio->uio_resid != 0)
895107178Snjl		error = ENOSPC;
89639213Sgibbs
897107178Snjlread_fail:
898168752Sscottl	cam_periph_unlock(softc->periph);
899107178Snjl	return (error);
90039213Sgibbs}
90139213Sgibbs
902107178Snjl/* Copy completed ccb back to the user */
903107178Snjlstatic int
904107178Snjltargreturnccb(struct targ_softc *softc, union ccb *ccb)
90539213Sgibbs{
906107178Snjl	struct targ_cmd_descr *descr;
907107178Snjl	struct ccb_hdr *u_ccbh;
908107178Snjl	size_t ccb_len;
909107178Snjl	int error;
91039213Sgibbs
911107178Snjl	CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, ("targreturnccb %p\n", ccb));
912107178Snjl	descr = (struct targ_cmd_descr *)ccb->ccb_h.targ_descr;
913107178Snjl	u_ccbh = &descr->user_ccb->ccb_h;
91439213Sgibbs
915107178Snjl	/* Copy out the central portion of the ccb_hdr */
916107178Snjl	copyout(&ccb->ccb_h.retry_count, &u_ccbh->retry_count,
917107178Snjl		offsetof(struct ccb_hdr, periph_priv) -
918107178Snjl		offsetof(struct ccb_hdr, retry_count));
91939213Sgibbs
920107178Snjl	/* Copy out the rest of the ccb (after the ccb_hdr) */
921107178Snjl	ccb_len = targccblen(ccb->ccb_h.func_code) - sizeof(struct ccb_hdr);
922107178Snjl	if (descr->mapinfo.num_bufs_used != 0)
923107178Snjl		cam_periph_unmapmem(ccb, &descr->mapinfo);
924107178Snjl	error = copyout(&ccb->ccb_h + 1, u_ccbh + 1, ccb_len);
925107178Snjl	if (error != 0) {
926164906Smjacob		xpt_print(softc->path,
927164906Smjacob		    "targreturnccb - CCB copyout failed (%d)\n", error);
92839213Sgibbs	}
929107178Snjl	/* Free CCB or send back to devq. */
930107178Snjl	targfreeccb(softc, ccb);
93139213Sgibbs
932107178Snjl	return (error);
93339213Sgibbs}
93439213Sgibbs
935107178Snjlstatic union ccb *
936107178Snjltarggetccb(struct targ_softc *softc, xpt_opcode type, int priority)
93739213Sgibbs{
938107178Snjl	union ccb *ccb;
939107178Snjl	int ccb_len;
94039213Sgibbs
941107178Snjl	ccb_len = targccblen(type);
942197332Smjacob	ccb = malloc(ccb_len, M_TARG, M_NOWAIT);
943107178Snjl	CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, ("getccb %p\n", ccb));
944197332Smjacob	if (ccb == NULL) {
945197332Smjacob		return (ccb);
946197332Smjacob	}
947107178Snjl	xpt_setup_ccb(&ccb->ccb_h, softc->path, priority);
948107178Snjl	ccb->ccb_h.func_code = type;
949107178Snjl	ccb->ccb_h.cbfcnp = targdone;
950107178Snjl	ccb->ccb_h.targ_descr = targgetdescr(softc);
951197332Smjacob	if (ccb->ccb_h.targ_descr == NULL) {
952197332Smjacob		free (ccb, M_TARG);
953197332Smjacob		ccb = NULL;
954197332Smjacob	}
955107178Snjl	return (ccb);
95639213Sgibbs}
95739213Sgibbs
95839213Sgibbsstatic void
959107178Snjltargfreeccb(struct targ_softc *softc, union ccb *ccb)
96039213Sgibbs{
961107178Snjl	CAM_DEBUG_PRINT(CAM_DEBUG_PERIPH, ("targfreeccb descr %p and\n",
962107178Snjl			ccb->ccb_h.targ_descr));
963184205Sdes	free(ccb->ccb_h.targ_descr, M_TARG);
96439213Sgibbs
965107178Snjl	switch (ccb->ccb_h.func_code) {
96639213Sgibbs	case XPT_ACCEPT_TARGET_IO:
967107178Snjl	case XPT_IMMED_NOTIFY:
968255120Smav	case XPT_IMMEDIATE_NOTIFY:
969107178Snjl		CAM_DEBUG_PRINT(CAM_DEBUG_PERIPH, ("freeing ccb %p\n", ccb));
970184205Sdes		free(ccb, M_TARG);
971107178Snjl		break;
972107178Snjl	default:
973107178Snjl		/* Send back CCB if we got it from the periph */
974107178Snjl		if (XPT_FC_IS_QUEUED(ccb)) {
975107178Snjl			CAM_DEBUG_PRINT(CAM_DEBUG_PERIPH,
976107178Snjl					("returning queued ccb %p\n", ccb));
977107178Snjl			xpt_release_ccb(ccb);
97856595Smjacob		} else {
979107178Snjl			CAM_DEBUG_PRINT(CAM_DEBUG_PERIPH,
980107178Snjl					("freeing ccb %p\n", ccb));
981184205Sdes			free(ccb, M_TARG);
98239213Sgibbs		}
98339213Sgibbs		break;
98439213Sgibbs	}
985107178Snjl}
98639213Sgibbs
987107178Snjlstatic struct targ_cmd_descr *
988107178Snjltarggetdescr(struct targ_softc *softc)
989107178Snjl{
990107178Snjl	struct targ_cmd_descr *descr;
99139213Sgibbs
992184205Sdes	descr = malloc(sizeof(*descr), M_TARG,
993197332Smjacob	       M_NOWAIT);
994197332Smjacob	if (descr) {
995197332Smjacob		descr->mapinfo.num_bufs_used = 0;
996197332Smjacob	}
997107178Snjl	return (descr);
998107178Snjl}
99939213Sgibbs
1000107178Snjlstatic void
1001107178Snjltarginit(void)
1002107178Snjl{
1003228481Sed	struct cdev *dev;
100456595Smjacob
1005228481Sed	/* Add symbolic link to targ0 for compatibility. */
1006228481Sed	dev = make_dev(&targ_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "targ");
1007228481Sed	make_dev_alias(dev, "targ0");
1008107178Snjl}
100956595Smjacob
1010107178Snjlstatic void
1011107178Snjltargasync(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg)
1012107178Snjl{
1013107178Snjl	/* All events are handled in usermode by INOTs */
1014107178Snjl	panic("targasync() called, should be an INOT instead");
1015107178Snjl}
101680574Smjacob
1017107178Snjl/* Cancel all pending requests and CCBs awaiting work. */
1018107178Snjlstatic void
1019107178Snjlabort_all_pending(struct targ_softc *softc)
1020107178Snjl{
1021107178Snjl	struct targ_cmd_descr   *descr;
1022107178Snjl	struct ccb_abort	 cab;
1023107178Snjl	struct ccb_hdr		*ccb_h;
102480574Smjacob
1025107178Snjl	CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, ("abort_all_pending\n"));
102639213Sgibbs
1027107178Snjl	/* First abort the descriptors awaiting resources */
1028107178Snjl	while ((descr = TAILQ_FIRST(&softc->work_queue)) != NULL) {
1029107178Snjl		CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH,
1030107178Snjl			  ("Aborting descr from workq %p\n", descr));
1031107178Snjl		TAILQ_REMOVE(&softc->work_queue, descr, tqe);
1032107178Snjl		TAILQ_INSERT_TAIL(&softc->abort_queue, descr, tqe);
1033107178Snjl	}
103439213Sgibbs
1035107178Snjl	/*
1036107178Snjl	 * Then abort all pending CCBs.
1037107178Snjl	 * targdone() will return the aborted CCB via user_ccb_queue
1038107178Snjl	 */
1039198382Smav	xpt_setup_ccb(&cab.ccb_h, softc->path, CAM_PRIORITY_NORMAL);
1040107178Snjl	cab.ccb_h.func_code = XPT_ABORT;
1041107178Snjl	cab.ccb_h.status = CAM_REQ_CMP_ERR;
1042107178Snjl	TAILQ_FOREACH(ccb_h, &softc->pending_ccb_queue, periph_links.tqe) {
1043107178Snjl		CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH,
1044107178Snjl			  ("Aborting pending CCB %p\n", ccb_h));
1045107178Snjl		cab.abort_ccb = (union ccb *)ccb_h;
1046107178Snjl		xpt_action((union ccb *)&cab);
1047107178Snjl		if (cab.ccb_h.status != CAM_REQ_CMP) {
1048164906Smjacob			xpt_print(cab.ccb_h.path,
1049164906Smjacob			    "Unable to abort CCB, status %#x\n",
1050164906Smjacob			    cab.ccb_h.status);
105139213Sgibbs		}
1052107178Snjl	}
105339213Sgibbs
1054107178Snjl	/* If we aborted at least one pending CCB ok, wait for it. */
1055107178Snjl	if (cab.ccb_h.status == CAM_REQ_CMP) {
1056260387Sscottl		cam_periph_sleep(softc->periph, &softc->pending_ccb_queue,
1057107178Snjl		       PRIBIO | PCATCH, "tgabrt", 0);
105839213Sgibbs	}
105949929Sgibbs
1060107178Snjl	/* If we aborted anything from the work queue, wakeup user. */
1061107178Snjl	if (!TAILQ_EMPTY(&softc->user_ccb_queue)
1062197332Smjacob	 || !TAILQ_EMPTY(&softc->abort_queue)) {
1063197332Smjacob		cam_periph_unlock(softc->periph);
1064107178Snjl		notify_user(softc);
1065197332Smjacob		cam_periph_lock(softc->periph);
1066197332Smjacob	}
106739213Sgibbs}
106839213Sgibbs
1069107178Snjl/* Notify the user that data is ready */
107039213Sgibbsstatic void
1071107178Snjlnotify_user(struct targ_softc *softc)
107239213Sgibbs{
107339213Sgibbs	/*
1074107178Snjl	 * Notify users sleeping via poll(), kqueue(), and
1075107178Snjl	 * blocking read().
107639213Sgibbs	 */
1077122352Stanimura	selwakeuppri(&softc->read_select, PRIBIO);
1078158883Smjacob	KNOTE_UNLOCKED(&softc->read_select.si_note, 0);
1079107178Snjl	wakeup(&softc->user_ccb_queue);
108039213Sgibbs}
108139213Sgibbs
1082107178Snjl/* Convert CAM status to errno values */
1083107178Snjlstatic int
1084107178Snjltargcamstatus(cam_status status)
108549929Sgibbs{
1086107178Snjl	switch (status & CAM_STATUS_MASK) {
1087107178Snjl	case CAM_REQ_CMP:	/* CCB request completed without error */
1088107178Snjl		return (0);
1089107178Snjl	case CAM_REQ_INPROG:	/* CCB request is in progress */
1090107178Snjl		return (EINPROGRESS);
1091107178Snjl	case CAM_REQ_CMP_ERR:	/* CCB request completed with an error */
1092107178Snjl		return (EIO);
1093107178Snjl	case CAM_PROVIDE_FAIL:	/* Unable to provide requested capability */
1094107178Snjl		return (ENOTTY);
1095107178Snjl	case CAM_FUNC_NOTAVAIL:	/* The requested function is not available */
1096107178Snjl		return (ENOTSUP);
1097107178Snjl	case CAM_LUN_ALRDY_ENA:	/* LUN is already enabled for target mode */
1098107178Snjl		return (EADDRINUSE);
1099107178Snjl	case CAM_PATH_INVALID:	/* Supplied Path ID is invalid */
1100107178Snjl	case CAM_DEV_NOT_THERE:	/* SCSI Device Not Installed/there */
1101107178Snjl		return (ENOENT);
1102107178Snjl	case CAM_REQ_ABORTED:	/* CCB request aborted by the host */
1103107178Snjl		return (ECANCELED);
1104107178Snjl	case CAM_CMD_TIMEOUT:	/* Command timeout */
1105107178Snjl		return (ETIMEDOUT);
1106107178Snjl	case CAM_REQUEUE_REQ:	/* Requeue to preserve transaction ordering */
1107107178Snjl		return (EAGAIN);
1108107178Snjl	case CAM_REQ_INVALID:	/* CCB request was invalid */
1109107178Snjl		return (EINVAL);
1110107178Snjl	case CAM_RESRC_UNAVAIL:	/* Resource Unavailable */
1111107178Snjl		return (ENOMEM);
1112210779Sbcr	case CAM_BUSY:		/* CAM subsystem is busy */
1113107178Snjl	case CAM_UA_ABORT:	/* Unable to abort CCB request */
1114107178Snjl		return (EBUSY);
111549929Sgibbs	default:
1116107178Snjl		return (ENXIO);
111749929Sgibbs	}
111849929Sgibbs}
111949929Sgibbs
1120107178Snjlstatic size_t
1121107178Snjltargccblen(xpt_opcode func_code)
112239213Sgibbs{
1123107178Snjl	int len;
112449929Sgibbs
1125107178Snjl	/* Codes we expect to see as a target */
1126107178Snjl	switch (func_code) {
1127107178Snjl	case XPT_CONT_TARGET_IO:
1128107178Snjl	case XPT_SCSI_IO:
1129107178Snjl		len = sizeof(struct ccb_scsiio);
113049929Sgibbs		break;
1131107178Snjl	case XPT_ACCEPT_TARGET_IO:
1132107178Snjl		len = sizeof(struct ccb_accept_tio);
113349929Sgibbs		break;
1134107178Snjl	case XPT_IMMED_NOTIFY:
1135107178Snjl		len = sizeof(struct ccb_immed_notify);
113649929Sgibbs		break;
1137255120Smav	case XPT_IMMEDIATE_NOTIFY:
1138255120Smav		len = sizeof(struct ccb_immediate_notify);
1139255120Smav		break;
1140107178Snjl	case XPT_REL_SIMQ:
1141107178Snjl		len = sizeof(struct ccb_relsim);
114249929Sgibbs		break;
1143107178Snjl	case XPT_PATH_INQ:
1144107178Snjl		len = sizeof(struct ccb_pathinq);
114549929Sgibbs		break;
1146107178Snjl	case XPT_DEBUG:
1147107178Snjl		len = sizeof(struct ccb_debug);
114849929Sgibbs		break;
1149107178Snjl	case XPT_ABORT:
1150107178Snjl		len = sizeof(struct ccb_abort);
115149929Sgibbs		break;
1152107178Snjl	case XPT_EN_LUN:
1153107178Snjl		len = sizeof(struct ccb_en_lun);
1154107178Snjl		break;
115549929Sgibbs	default:
1156107178Snjl		len = sizeof(union ccb);
1157107178Snjl		break;
115849929Sgibbs	}
115949929Sgibbs
1160107178Snjl	return (len);
116139213Sgibbs}
1162