xref: /dragonfly/sys/bus/cam/scsi/scsi_target.c (revision 335b9e93)
1 /*
2  * Generic SCSI Target Kernel Mode Driver
3  *
4  * Copyright (c) 2002 Nate Lawson.
5  * Copyright (c) 1998, 1999, 2001, 2002 Justin T. Gibbs.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions, and the following disclaimer,
13  *    without modification, immediately at the beginning of the file.
14  * 2. The name of the author may not be used to endorse or promote products
15  *    derived from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
21  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * $FreeBSD: src/sys/cam/scsi/scsi_target.c,v 1.22.2.7 2003/02/18 22:07:10 njl Exp $
30  */
31 
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/uio.h>
35 #include <sys/kernel.h>
36 #include <sys/conf.h>
37 #include <sys/device.h>
38 #include <sys/malloc.h>
39 #include <sys/vnode.h>
40 #include <sys/devicestat.h>
41 #include <sys/thread2.h>
42 #include <sys/devfs.h>
43 
44 #include "../cam.h"
45 #include "../cam_ccb.h"
46 #include "../cam_periph.h"
47 #include "../cam_xpt_periph.h"
48 #include "../cam_sim.h"
49 #include "scsi_targetio.h"
50 
51 /* Transaction information attached to each CCB sent by the user */
52 struct targ_cmd_descr {
53 	struct cam_periph_map_info  mapinfo;
54 	TAILQ_ENTRY(targ_cmd_descr) tqe;
55 	union ccb *user_ccb;
56 	int	   priority;
57 	int	   func_code;
58 };
59 
60 /* Offset into the private CCB area for storing our descriptor */
61 #define targ_descr	periph_priv.entries[1].ptr
62 
63 TAILQ_HEAD(descr_queue, targ_cmd_descr);
64 
65 typedef enum {
66 	TARG_STATE_RESV		= 0x00, /* Invalid state */
67 	TARG_STATE_OPENED	= 0x01, /* Device opened, softc initialized */
68 	TARG_STATE_LUN_ENABLED	= 0x02  /* Device enabled for a path */
69 } targ_state;
70 
71 /* Per-instance device software context */
72 struct targ_softc {
73 	/* CCBs (CTIOs, ATIOs, INOTs) pending on the controller */
74 	struct ccb_queue	 pending_ccb_queue;
75 
76 	/* Command descriptors awaiting CTIO resources from the XPT */
77 	struct descr_queue	 work_queue;
78 
79 	/* Command descriptors that have been aborted back to the user. */
80 	struct descr_queue	 abort_queue;
81 
82 	/*
83 	 * Queue of CCBs that have been copied out to userland, but our
84 	 * userland daemon has not yet seen.
85 	 */
86 	struct ccb_queue	 user_ccb_queue;
87 
88 	struct cam_periph	*periph;
89 	struct cam_path		*path;
90 	targ_state		 state;
91 	struct kqinfo		 read_kq;
92 	struct devstat		 device_stats;
93 };
94 
95 static d_open_t		targopen;
96 static d_close_t	targclose;
97 static d_read_t		targread;
98 static d_write_t	targwrite;
99 static d_ioctl_t	targioctl;
100 static d_kqfilter_t	targkqfilter;
101 static d_clone_t	targclone;
102 DEVFS_DEFINE_CLONE_BITMAP(targ);
103 
104 static void		targfiltdetach(struct knote *kn);
105 static int		targreadfilt(struct knote *kn, long hint);
106 static int		targwritefilt(struct knote *kn, long hint);
107 static struct filterops targread_filtops =
108 	{ FILTEROP_ISFD, NULL, targfiltdetach, targreadfilt };
109 static struct filterops targwrite_filtops =
110 	{ FILTEROP_ISFD, NULL, targfiltdetach, targwritefilt };
111 
112 static struct dev_ops targ_ops = {
113 	{ "targ", 0, 0 },
114 	.d_open = targopen,
115 	.d_close = targclose,
116 	.d_read = targread,
117 	.d_write = targwrite,
118 	.d_ioctl = targioctl,
119 	.d_kqfilter = targkqfilter
120 };
121 
122 static cam_status	targendislun(struct cam_path *path, int enable,
123 				     int grp6_len, int grp7_len);
124 static cam_status	targenable(struct targ_softc *softc,
125 				   struct cam_path *path,
126 				   int grp6_len, int grp7_len);
127 static cam_status	targdisable(struct targ_softc *softc);
128 static periph_ctor_t    targctor;
129 static periph_dtor_t    targdtor;
130 static periph_start_t   targstart;
131 static int		targusermerge(struct targ_softc *softc,
132 				      struct targ_cmd_descr *descr,
133 				      union ccb *ccb);
134 static int		targsendccb(struct targ_softc *softc, union ccb *ccb,
135 				    struct targ_cmd_descr *descr);
136 static void		targdone(struct cam_periph *periph,
137 				 union  ccb *done_ccb);
138 static int		targreturnccb(struct targ_softc *softc,
139 				      union  ccb *ccb);
140 static union ccb *	targgetccb(struct targ_softc *softc, xpt_opcode type,
141 				   int priority);
142 static void		targfreeccb(struct targ_softc *softc, union ccb *ccb);
143 static struct targ_cmd_descr *
144 			targgetdescr(struct targ_softc *softc);
145 static periph_init_t	targinit;
146 static void		targasync(void *callback_arg, u_int32_t code,
147 				  struct cam_path *path, void *arg);
148 static void		abort_all_pending(struct targ_softc *softc);
149 static void		notify_user(struct targ_softc *softc);
150 static int		targcamstatus(cam_status status);
151 static size_t		targccblen(xpt_opcode func_code);
152 
153 static struct periph_driver targdriver =
154 {
155 	targinit, "targ",
156 	TAILQ_HEAD_INITIALIZER(targdriver.units), /* generation */ 0
157 };
158 PERIPHDRIVER_DECLARE(targ, targdriver);
159 
160 static MALLOC_DEFINE(M_TARG, "TARG", "TARG data");
161 
162 /*
163  * Create softc and initialize it. Only one proc can open each targ device.
164  * There is no locking here because a periph doesn't get created until an
165  * ioctl is issued to do so, and that can't happen until this method returns.
166  */
167 static int
168 targopen(struct dev_open_args *ap)
169 {
170 	cdev_t dev = ap->a_head.a_dev;
171 	struct targ_softc *softc;
172 
173 	if (dev->si_drv1 != 0) {
174 		return (EBUSY);
175 	}
176 
177 	/* Mark device busy before any potentially blocking operations */
178 	dev->si_drv1 = (void *)~0;
179 	reference_dev(dev);		/* save ref for later destroy_dev() */
180 
181 	/* Create the targ device, allocate its softc, initialize it */
182 #if 0
183 	make_dev(&targ_ops, minor(dev), UID_ROOT, GID_WHEEL, 0600,
184 			 "targ%d", lminor(dev));
185 #endif
186 	softc = kmalloc(sizeof(*softc), M_TARG, M_INTWAIT | M_ZERO);
187 	dev->si_drv1 = softc;
188 	softc->state = TARG_STATE_OPENED;
189 	softc->periph = NULL;
190 	softc->path = NULL;
191 
192 	TAILQ_INIT(&softc->pending_ccb_queue);
193 	TAILQ_INIT(&softc->work_queue);
194 	TAILQ_INIT(&softc->abort_queue);
195 	TAILQ_INIT(&softc->user_ccb_queue);
196 
197 	return (0);
198 }
199 
200 /* Disable LUN if enabled and teardown softc */
201 static int
202 targclose(struct dev_close_args *ap)
203 {
204 	cdev_t dev = ap->a_head.a_dev;
205 	struct targ_softc     *softc;
206 	struct cam_periph     *periph;
207 	int    error;
208 
209 	softc = (struct targ_softc *)dev->si_drv1;
210 	if ((softc->periph == NULL) ||
211 	    (softc->state & TARG_STATE_LUN_ENABLED) == 0) {
212 		devfs_clone_bitmap_put(&DEVFS_CLONE_BITMAP(targ), dev->si_uminor);
213 		destroy_dev(dev);
214 		kfree(softc, M_TARG);
215 		return (0);
216 	}
217 
218 	/*
219 	 * Acquire a hold on the periph so that it doesn't go away before
220 	 * we are ready at the end of the function.
221 	 */
222 	periph = softc->periph;
223 	cam_periph_acquire(periph);
224 	cam_periph_lock(periph);
225 	error = targdisable(softc);
226 	if (error == CAM_REQ_CMP) {
227 		dev->si_drv1 = 0;
228 		if (softc->periph != NULL) {
229 			cam_periph_invalidate(softc->periph);
230 			softc->periph = NULL;
231 		}
232 		destroy_dev(dev);	/* eats the open ref */
233 		devfs_clone_bitmap_put(&DEVFS_CLONE_BITMAP(targ), dev->si_uminor);
234 		kfree(softc, M_TARG);
235 	} else {
236 		release_dev(dev);
237 	}
238 	cam_periph_unlock(periph);
239 	cam_periph_release(periph);
240 
241 	return (error);
242 }
243 
244 /* Enable/disable LUNs, set debugging level */
245 static int
246 targioctl(struct dev_ioctl_args *ap)
247 {
248 	struct targ_softc *softc;
249 	cam_status	   status;
250 
251 	softc = (struct targ_softc *)ap->a_head.a_dev->si_drv1;
252 
253 	switch (ap->a_cmd) {
254 	case TARGIOCENABLE:
255 	{
256 		struct ioc_enable_lun	*new_lun;
257 		struct cam_path		*path;
258 		struct cam_sim		*sim;
259 
260 		new_lun = (struct ioc_enable_lun *)ap->a_data;
261 		status = xpt_create_path_unlocked(&path, /*periph*/NULL,
262 						  new_lun->path_id,
263 						  new_lun->target_id,
264 						  new_lun->lun_id);
265 		if (status != CAM_REQ_CMP) {
266 			kprintf("Couldn't create path, status %#x\n", status);
267 			break;
268 		}
269 		sim = xpt_path_sim(path);
270 		CAM_SIM_LOCK(sim);
271 		status = targenable(softc, path, new_lun->grp6_len,
272 				    new_lun->grp7_len);
273 		xpt_free_path(path);
274 		CAM_SIM_UNLOCK(sim);
275 		break;
276 	}
277 	case TARGIOCDISABLE:
278 		if (softc->periph == NULL) {
279 			status = CAM_DEV_NOT_THERE;
280 			break;
281 		}
282 		cam_periph_lock(softc->periph);
283 		status = targdisable(softc);
284 		cam_periph_unlock(softc->periph);
285 		break;
286 	case TARGIOCDEBUG:
287 	{
288 #ifdef	CAMDEBUG
289 		struct ccb_debug *cdbg;
290 
291 		/* If no periph available, disallow debugging changes */
292 		if ((softc->state & TARG_STATE_LUN_ENABLED) == 0) {
293 			status = CAM_DEV_NOT_THERE;
294 			break;
295 		}
296 		cdbg = &xpt_alloc_ccb()->cdbg;
297 		if (*((int *)ap->a_data) != 0)
298 			cdbg->flags = CAM_DEBUG_PERIPH;
299 		else
300 			cdbg->flags = CAM_DEBUG_NONE;
301 		cam_periph_lock(softc->periph);
302 		xpt_setup_ccb(&cdbg->ccb_h, softc->path, /*priority*/0);
303 		cdbg->ccb_h.func_code = XPT_DEBUG;
304 		cdbg->ccb_h.cbfcnp = targdone;
305 
306 		xpt_action((union ccb *)cdbg);
307 		cam_periph_unlock(softc->periph);
308 		status = cdbg->ccb_h.status & CAM_STATUS_MASK;
309 		xpt_free_ccb(&cdbg->ccb_h);
310 #else
311 		status = CAM_FUNC_NOTAVAIL;
312 #endif
313 		break;
314 	}
315 	default:
316 		status = CAM_PROVIDE_FAIL;
317 		break;
318 	}
319 
320 	return (targcamstatus(status));
321 }
322 
323 static int
324 targkqfilter(struct dev_kqfilter_args *ap)
325 {
326 	struct	knote *kn = ap->a_kn;
327 	struct  targ_softc *softc;
328 
329 	softc = (struct targ_softc *)ap->a_head.a_dev->si_drv1;
330 
331 	ap->a_result = 0;
332 
333 	switch (kn->kn_filter) {
334 	case EVFILT_READ:
335 		kn->kn_hook = (caddr_t)softc;
336 		kn->kn_fop = &targread_filtops;
337 		break;
338 	case EVFILT_WRITE:
339 		kn->kn_hook = (caddr_t)softc;
340 		kn->kn_fop = &targwrite_filtops;
341 	default:
342 		ap->a_result = EOPNOTSUPP;
343 		return (0);
344 	}
345 
346 	knote_insert(&softc->read_kq.ki_note, kn);
347 	return (0);
348 }
349 
350 static void
351 targfiltdetach(struct knote *kn)
352 {
353 	struct  targ_softc *softc;
354 
355 	softc = (struct targ_softc *)kn->kn_hook;
356 	knote_remove(&softc->read_kq.ki_note, kn);
357 }
358 
359 /* Notify the user's kqueue when the user queue or abort queue gets a CCB */
360 static int
361 targreadfilt(struct knote *kn, long hint)
362 {
363 	struct targ_softc *softc;
364 	int	retval;
365 
366 	softc = (struct targ_softc *)kn->kn_hook;
367 	cam_periph_lock(softc->periph);
368 	retval = !TAILQ_EMPTY(&softc->user_ccb_queue) ||
369 		 !TAILQ_EMPTY(&softc->abort_queue);
370 	cam_periph_unlock(softc->periph);
371 	return (retval);
372 }
373 
374 /* write() is always ok */
375 static int
376 targwritefilt(struct knote *kn, long hint)
377 {
378 	return (1);
379 }
380 
381 /* Send the HBA the enable/disable message */
382 static cam_status
383 targendislun(struct cam_path *path, int enable, int grp6_len, int grp7_len)
384 {
385 	struct ccb_en_lun *en_ccb;
386 	cam_status	  status;
387 
388 	/* Tell the lun to begin answering selects */
389 	en_ccb = &xpt_alloc_ccb()->cel;
390 	xpt_setup_ccb(&en_ccb->ccb_h, path, /*priority*/1);
391 	en_ccb->ccb_h.func_code = XPT_EN_LUN;
392 	/* Don't need support for any vendor specific commands */
393 	en_ccb->grp6_len = grp6_len;
394 	en_ccb->grp7_len = grp7_len;
395 	en_ccb->enable = enable ? 1 : 0;
396 	xpt_action((union ccb *)en_ccb);
397 	status = en_ccb->ccb_h.status & CAM_STATUS_MASK;
398 	if (status != CAM_REQ_CMP) {
399 		xpt_print(path, "%sable lun CCB rejected, status %#x\n",
400 		    enable ? "en" : "dis", status);
401 	}
402 	xpt_free_ccb(&en_ccb->ccb_h);
403 
404 	return (status);
405 }
406 
407 /* Enable target mode on a LUN, given its path */
408 static cam_status
409 targenable(struct targ_softc *softc, struct cam_path *path, int grp6_len,
410 	   int grp7_len)
411 {
412 	struct cam_periph *periph;
413 	struct ccb_pathinq *cpi;
414 	cam_status	   status;
415 
416 	if ((softc->state & TARG_STATE_LUN_ENABLED) != 0)
417 		return (CAM_LUN_ALRDY_ENA);
418 
419 	/* Make sure SIM supports target mode */
420 	cpi = &xpt_alloc_ccb()->cpi;
421 	xpt_setup_ccb(&cpi->ccb_h, path, /*priority*/1);
422 	cpi->ccb_h.func_code = XPT_PATH_INQ;
423 	xpt_action((union ccb *)cpi);
424 	status = cpi->ccb_h.status & CAM_STATUS_MASK;
425 	if (status != CAM_REQ_CMP) {
426 		kprintf("pathinq failed, status %#x\n", status);
427 		goto enable_fail;
428 	}
429 	if ((cpi->target_sprt & PIT_PROCESSOR) == 0) {
430 		kprintf("controller does not support target mode\n");
431 		status = CAM_FUNC_NOTAVAIL;
432 		goto enable_fail;
433 	}
434 
435 	/* Destroy any periph on our path if it is disabled */
436 	periph = cam_periph_find(path, "targ");
437 	if (periph != NULL) {
438 		struct targ_softc *del_softc;
439 
440 		del_softc = (struct targ_softc *)periph->softc;
441 		if ((del_softc->state & TARG_STATE_LUN_ENABLED) == 0) {
442 			cam_periph_invalidate(del_softc->periph);
443 			del_softc->periph = NULL;
444 		} else {
445 			kprintf("Requested path still in use by targ%d\n",
446 			       periph->unit_number);
447 			status = CAM_LUN_ALRDY_ENA;
448 			goto enable_fail;
449 		}
450 	}
451 
452 	/* Create a periph instance attached to this path */
453 	status = cam_periph_alloc(targctor, NULL, targdtor, targstart,
454 			"targ", CAM_PERIPH_BIO, path, targasync, 0, softc);
455 	if (status != CAM_REQ_CMP) {
456 		kprintf("cam_periph_alloc failed, status %#x\n", status);
457 		goto enable_fail;
458 	}
459 
460 	/* Ensure that the periph now exists. */
461 	if (cam_periph_find(path, "targ") == NULL) {
462 		panic("targenable: succeeded but no periph?");
463 		/* NOTREACHED */
464 	}
465 
466 	/* Send the enable lun message */
467 	status = targendislun(path, /*enable*/1, grp6_len, grp7_len);
468 	if (status != CAM_REQ_CMP) {
469 		kprintf("enable lun failed, status %#x\n", status);
470 		goto enable_fail;
471 	}
472 	softc->state |= TARG_STATE_LUN_ENABLED;
473 
474 enable_fail:
475 	xpt_free_ccb(&cpi->ccb_h);
476 
477 	return (status);
478 }
479 
480 /* Disable this softc's target instance if enabled */
481 static cam_status
482 targdisable(struct targ_softc *softc)
483 {
484 	cam_status status;
485 
486 	if ((softc->state & TARG_STATE_LUN_ENABLED) == 0)
487 		return (CAM_REQ_CMP);
488 
489 	CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, ("targdisable\n"));
490 
491 	/* Abort any ccbs pending on the controller */
492 	crit_enter();
493 	abort_all_pending(softc);
494 	crit_exit();
495 
496 	/* Disable this lun */
497 	status = targendislun(softc->path, /*enable*/0,
498 			      /*grp6_len*/0, /*grp7_len*/0);
499 	if (status == CAM_REQ_CMP)
500 		softc->state &= ~TARG_STATE_LUN_ENABLED;
501 	else
502 		kprintf("Disable lun failed, status %#x\n", status);
503 
504 	return (status);
505 }
506 
507 /* Initialize a periph (called from cam_periph_alloc) */
508 static cam_status
509 targctor(struct cam_periph *periph, void *arg)
510 {
511 	struct targ_softc *softc;
512 
513 	/* Store pointer to softc for periph-driven routines */
514 	softc = (struct targ_softc *)arg;
515 	periph->softc = softc;
516 	softc->periph = periph;
517 	softc->path = periph->path;
518 	return (CAM_REQ_CMP);
519 }
520 
521 static void
522 targdtor(struct cam_periph *periph)
523 {
524 	struct targ_softc     *softc;
525 	struct ccb_hdr	      *ccb_h;
526 	struct targ_cmd_descr *descr;
527 
528 	softc = (struct targ_softc *)periph->softc;
529 
530 	/*
531 	 * targdisable() aborts CCBs back to the user and leaves them
532 	 * on user_ccb_queue and abort_queue in case the user is still
533 	 * interested in them.  We free them now.
534 	 */
535 	while ((ccb_h = TAILQ_FIRST(&softc->user_ccb_queue)) != NULL) {
536 		TAILQ_REMOVE(&softc->user_ccb_queue, ccb_h, periph_links.tqe);
537 		targfreeccb(softc, (union ccb *)ccb_h);
538 	}
539 	while ((descr = TAILQ_FIRST(&softc->abort_queue)) != NULL) {
540 		TAILQ_REMOVE(&softc->abort_queue, descr, tqe);
541 		kfree(descr, M_TARG);
542 	}
543 
544 	softc->periph = NULL;
545 	softc->path = NULL;
546 	periph->softc = NULL;
547 }
548 
549 /* Receive CCBs from user mode proc and send them to the HBA */
550 static int
551 targwrite(struct dev_write_args *ap)
552 {
553 	struct uio *uio = ap->a_uio;
554 	union ccb *user_ccb;
555 	struct targ_softc *softc;
556 	struct targ_cmd_descr *descr;
557 	int write_len, error;
558 	int func_code, priority;
559 
560 	softc = (struct targ_softc *)ap->a_head.a_dev->si_drv1;
561 	write_len = error = 0;
562 	CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH,
563 		  ("write - uio_resid %zu\n", uio->uio_resid));
564 	while (uio->uio_resid >= sizeof(user_ccb) && error == 0) {
565 		union ccb *ccb;
566 
567 		error = uiomove((caddr_t)&user_ccb, sizeof(user_ccb), uio);
568 		if (error != 0) {
569 			CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH,
570 				  ("write - uiomove failed (%d)\n", error));
571 			break;
572 		}
573 		priority = fuword32(&user_ccb->ccb_h.pinfo.priority);
574 		if (priority == -1) {
575 			error = EINVAL;
576 			break;
577 		}
578 		func_code = fuword32(&user_ccb->ccb_h.func_code);
579 		switch (func_code) {
580 		case XPT_ACCEPT_TARGET_IO:
581 		case XPT_IMMED_NOTIFY:
582 			cam_periph_lock(softc->periph);
583 			ccb = targgetccb(softc, func_code, priority);
584 			descr = (struct targ_cmd_descr *)ccb->ccb_h.targ_descr;
585 			descr->user_ccb = user_ccb;
586 			descr->func_code = func_code;
587 			CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH,
588 				  ("Sent ATIO/INOT (%p)\n", user_ccb));
589 			xpt_action(ccb);
590 			TAILQ_INSERT_TAIL(&softc->pending_ccb_queue,
591 					  &ccb->ccb_h,
592 					  periph_links.tqe);
593 			cam_periph_unlock(softc->periph);
594 			break;
595 		default:
596 			cam_periph_lock(softc->periph);
597 			if ((func_code & XPT_FC_QUEUED) != 0) {
598 				CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH,
599 					  ("Sending queued ccb %#x (%p)\n",
600 					  func_code, user_ccb));
601 				descr = targgetdescr(softc);
602 				descr->user_ccb = user_ccb;
603 				descr->priority = priority;
604 				descr->func_code = func_code;
605 				crit_enter();
606 				TAILQ_INSERT_TAIL(&softc->work_queue,
607 						  descr, tqe);
608 				crit_exit();
609 				xpt_schedule(softc->periph, priority);
610 			} else {
611 				CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH,
612 					  ("Sending inline ccb %#x (%p)\n",
613 					  func_code, user_ccb));
614 				ccb = targgetccb(softc, func_code, priority);
615 				descr = (struct targ_cmd_descr *)
616 					 ccb->ccb_h.targ_descr;
617 				descr->user_ccb = user_ccb;
618 				descr->priority = priority;
619 				descr->func_code = func_code;
620 				if (targusermerge(softc, descr, ccb) != EFAULT)
621 					targsendccb(softc, ccb, descr);
622 				targreturnccb(softc, ccb);
623 			}
624 			cam_periph_unlock(softc->periph);
625 			break;
626 		}
627 		write_len += sizeof(user_ccb);
628 	}
629 
630 	/*
631 	 * If we've successfully taken in some amount of
632 	 * data, return success for that data first.  If
633 	 * an error is persistent, it will be reported
634 	 * on the next write.
635 	 */
636 	if (error != 0 && write_len == 0)
637 		return (error);
638 	if (write_len == 0 && uio->uio_resid != 0)
639 		return (ENOSPC);
640 	return (0);
641 }
642 
643 /* Process requests (descrs) via the periph-supplied CCBs */
644 static void
645 targstart(struct cam_periph *periph, union ccb *start_ccb)
646 {
647 	struct targ_softc *softc;
648 	struct targ_cmd_descr *descr, *next_descr;
649 	int error;
650 
651 	softc = (struct targ_softc *)periph->softc;
652 	CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, ("targstart %p\n", start_ccb));
653 
654 	crit_enter();
655 	descr = TAILQ_FIRST(&softc->work_queue);
656 	if (descr == NULL) {
657 		crit_exit();
658 		xpt_release_ccb(start_ccb);
659 	} else {
660 		TAILQ_REMOVE(&softc->work_queue, descr, tqe);
661 		next_descr = TAILQ_FIRST(&softc->work_queue);
662 		crit_exit();
663 
664 		/* Initiate a transaction using the descr and supplied CCB */
665 		error = targusermerge(softc, descr, start_ccb);
666 		if (error == 0)
667 			error = targsendccb(softc, start_ccb, descr);
668 		if (error != 0) {
669 			xpt_print(periph->path,
670 			    "targsendccb failed, err %d\n", error);
671 			xpt_release_ccb(start_ccb);
672 			suword32(&descr->user_ccb->ccb_h.status,
673 			         CAM_REQ_CMP_ERR);
674 			crit_enter();
675 			TAILQ_INSERT_TAIL(&softc->abort_queue, descr, tqe);
676 			crit_exit();
677 			notify_user(softc);
678 		}
679 
680 		/* If we have more work to do, stay scheduled */
681 		if (next_descr != NULL)
682 			xpt_schedule(periph, next_descr->priority);
683 	}
684 }
685 
686 static int
687 targusermerge(struct targ_softc *softc, struct targ_cmd_descr *descr,
688 	      union ccb *ccb)
689 {
690 	struct ccb_hdr *u_ccbh, *k_ccbh;
691 	size_t ccb_len;
692 	int error;
693 
694 	u_ccbh = &descr->user_ccb->ccb_h;
695 	k_ccbh = &ccb->ccb_h;
696 
697 	/*
698 	 * There are some fields in the CCB header that need to be
699 	 * preserved, the rest we get from the user ccb. (See xpt_merge_ccb)
700 	 */
701 	xpt_setup_ccb(k_ccbh, softc->path, descr->priority);
702 	k_ccbh->retry_count = fuword32(&u_ccbh->retry_count);
703 	k_ccbh->func_code = descr->func_code;
704 	k_ccbh->flags = fuword32(&u_ccbh->flags);
705 	k_ccbh->timeout = fuword32(&u_ccbh->timeout);
706 	ccb_len = targccblen(k_ccbh->func_code) - sizeof(struct ccb_hdr);
707 	error = copyin(u_ccbh + 1, k_ccbh + 1, ccb_len);
708 	if (error != 0) {
709 		k_ccbh->status = CAM_REQ_CMP_ERR;
710 		return (error);
711 	}
712 
713 	/* Translate usermode abort_ccb pointer to its kernel counterpart */
714 	if (k_ccbh->func_code == XPT_ABORT) {
715 		struct ccb_abort *cab;
716 		struct ccb_hdr *ccb_h;
717 
718 		cab = (struct ccb_abort *)ccb;
719 		crit_enter();
720 		TAILQ_FOREACH(ccb_h, &softc->pending_ccb_queue,
721 		    periph_links.tqe) {
722 			struct targ_cmd_descr *ab_descr;
723 
724 			ab_descr = (struct targ_cmd_descr *)ccb_h->targ_descr;
725 			if (ab_descr->user_ccb == cab->abort_ccb) {
726 				CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH,
727 					  ("Changing abort for %p to %p\n",
728 					  cab->abort_ccb, ccb_h));
729 				cab->abort_ccb = (union ccb *)ccb_h;
730 				break;
731 			}
732 		}
733 		crit_exit();
734 		/* CCB not found, set appropriate status */
735 		if (ccb_h == NULL) {
736 			k_ccbh->status = CAM_PATH_INVALID;
737 			error = ESRCH;
738 		}
739 	}
740 
741 	return (error);
742 }
743 
744 /* Build and send a kernel CCB formed from descr->user_ccb */
745 static int
746 targsendccb(struct targ_softc *softc, union ccb *ccb,
747 	    struct targ_cmd_descr *descr)
748 {
749 	struct cam_periph_map_info *mapinfo;
750 	struct ccb_hdr *ccb_h;
751 	int error;
752 
753 	ccb_h = &ccb->ccb_h;
754 	mapinfo = &descr->mapinfo;
755 	mapinfo->num_bufs_used = 0;
756 
757 	/*
758 	 * There's no way for the user to have a completion
759 	 * function, so we put our own completion function in here.
760 	 * We also stash in a reference to our descriptor so targreturnccb()
761 	 * can find our mapping info.
762 	 */
763 	ccb_h->cbfcnp = targdone;
764 	ccb_h->targ_descr = descr;
765 
766 	/*
767 	 * We only attempt to map the user memory into kernel space
768 	 * if they haven't passed in a physical memory pointer,
769 	 * and if there is actually an I/O operation to perform.
770 	 * Right now cam_periph_mapmem() only supports SCSI and device
771 	 * match CCBs.  For the SCSI CCBs, we only pass the CCB in if
772 	 * there's actually data to map.  cam_periph_mapmem() will do the
773 	 * right thing, even if there isn't data to map, but since CCBs
774 	 * without data are a reasonably common occurance (e.g. test unit
775 	 * ready), it will save a few cycles if we check for it here.
776 	 */
777 	if (((ccb_h->flags & CAM_DATA_PHYS) == 0)
778 	 && (((ccb_h->func_code == XPT_CONT_TARGET_IO)
779 	    && ((ccb_h->flags & CAM_DIR_MASK) != CAM_DIR_NONE))
780 	  || (ccb_h->func_code == XPT_DEV_MATCH))) {
781 
782 		error = cam_periph_mapmem(ccb, mapinfo);
783 
784 		/*
785 		 * cam_periph_mapmem returned an error, we can't continue.
786 		 * Return the error to the user.
787 		 */
788 		if (error) {
789 			ccb_h->status = CAM_REQ_CMP_ERR;
790 			mapinfo->num_bufs_used = 0;
791 			return (error);
792 		}
793 	}
794 
795 	/*
796 	 * Once queued on the pending CCB list, this CCB will be protected
797 	 * by our error recovery handler.
798 	 */
799 	CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, ("sendccb %p\n", ccb));
800 	if (XPT_FC_IS_QUEUED(ccb)) {
801 		crit_enter();
802 		TAILQ_INSERT_TAIL(&softc->pending_ccb_queue, ccb_h,
803 				  periph_links.tqe);
804 		crit_exit();
805 	}
806 	xpt_action(ccb);
807 
808 	return (0);
809 }
810 
811 /* Completion routine for CCBs (called in a critical section) */
812 static void
813 targdone(struct cam_periph *periph, union ccb *done_ccb)
814 {
815 	struct targ_softc *softc;
816 
817 	CAM_DEBUG(periph->path, CAM_DEBUG_PERIPH, ("targdone %p\n", done_ccb));
818 	softc = (struct targ_softc *)periph->softc;
819 	TAILQ_REMOVE(&softc->pending_ccb_queue, &done_ccb->ccb_h,
820 		     periph_links.tqe);
821 
822 	/* If we're no longer enabled, throw away CCB */
823 	if ((softc->state & TARG_STATE_LUN_ENABLED) == 0) {
824 		targfreeccb(softc, done_ccb);
825 		return;
826 	}
827 	/* abort_all_pending() waits for pending queue to be empty */
828 	if (TAILQ_EMPTY(&softc->pending_ccb_queue))
829 		wakeup(&softc->pending_ccb_queue);
830 
831 	switch (done_ccb->ccb_h.func_code) {
832 	/* All FC_*_QUEUED CCBs go back to userland */
833 	case XPT_IMMED_NOTIFY:
834 	case XPT_ACCEPT_TARGET_IO:
835 	case XPT_CONT_TARGET_IO:
836 		TAILQ_INSERT_TAIL(&softc->user_ccb_queue, &done_ccb->ccb_h,
837 				  periph_links.tqe);
838 		notify_user(softc);
839 		break;
840 	default:
841 		panic("targdone: impossible xpt opcode %#x",
842 		      done_ccb->ccb_h.func_code);
843 		/* NOTREACHED */
844 	}
845 }
846 
847 /* Return CCBs to the user from the user queue and abort queue */
848 static int
849 targread(struct dev_read_args *ap)
850 {
851 	struct uio *uio = ap->a_uio;
852 	struct descr_queue	*abort_queue;
853 	struct targ_cmd_descr	*user_descr;
854 	struct targ_softc	*softc;
855 	struct ccb_queue  *user_queue;
856 	struct ccb_hdr	  *ccb_h;
857 	union  ccb	  *user_ccb;
858 	int		   read_len, error;
859 
860 	error = 0;
861 	read_len = 0;
862 	softc = (struct targ_softc *)ap->a_head.a_dev->si_drv1;
863 	user_queue = &softc->user_ccb_queue;
864 	abort_queue = &softc->abort_queue;
865 	CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, ("targread\n"));
866 
867 	/* If no data is available, wait or return immediately */
868 	cam_periph_lock(softc->periph);
869 	ccb_h = TAILQ_FIRST(user_queue);
870 	user_descr = TAILQ_FIRST(abort_queue);
871 	while (ccb_h == NULL && user_descr == NULL) {
872 		if ((ap->a_ioflag & IO_NDELAY) == 0) {
873 			error = sim_lock_sleep(user_queue, PCATCH, "targrd", 0,
874 					       softc->periph->sim->lock);
875 			ccb_h = TAILQ_FIRST(user_queue);
876 			user_descr = TAILQ_FIRST(abort_queue);
877 			if (error != 0) {
878 				if (error == ERESTART) {
879 					continue;
880 				} else {
881 					goto read_fail;
882 				}
883 			}
884 		} else {
885 			cam_periph_unlock(softc->periph);
886 			return (EAGAIN);
887 		}
888 	}
889 
890 	/* Data is available so fill the user's buffer */
891 	while (ccb_h != NULL) {
892 		struct targ_cmd_descr *descr;
893 
894 		if (uio->uio_resid < sizeof(user_ccb))
895 			break;
896 		TAILQ_REMOVE(user_queue, ccb_h, periph_links.tqe);
897 		descr = (struct targ_cmd_descr *)ccb_h->targ_descr;
898 		user_ccb = descr->user_ccb;
899 		CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH,
900 			  ("targread ccb %p (%p)\n", ccb_h, user_ccb));
901 		error = targreturnccb(softc, (union ccb *)ccb_h);
902 		if (error != 0)
903 			goto read_fail;
904 		cam_periph_unlock(softc->periph);
905 		error = uiomove((caddr_t)&user_ccb, sizeof(user_ccb), uio);
906 		cam_periph_lock(softc->periph);
907 		if (error != 0)
908 			goto read_fail;
909 		read_len += sizeof(user_ccb);
910 
911 		ccb_h = TAILQ_FIRST(user_queue);
912 	}
913 
914 	/* Flush out any aborted descriptors */
915 	while (user_descr != NULL) {
916 		if (uio->uio_resid < sizeof(user_ccb))
917 			break;
918 		TAILQ_REMOVE(abort_queue, user_descr, tqe);
919 		user_ccb = user_descr->user_ccb;
920 		CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH,
921 			  ("targread aborted descr %p (%p)\n",
922 			  user_descr, user_ccb));
923 		suword32(&user_ccb->ccb_h.status, CAM_REQ_ABORTED);
924 		cam_periph_unlock(softc->periph);
925 		error = uiomove((caddr_t)&user_ccb, sizeof(user_ccb), uio);
926 		cam_periph_lock(softc->periph);
927 		if (error != 0)
928 			goto read_fail;
929 		read_len += sizeof(user_ccb);
930 
931 		user_descr = TAILQ_FIRST(abort_queue);
932 	}
933 
934 	/*
935 	 * If we've successfully read some amount of data, don't report an
936 	 * error.  If the error is persistent, it will be reported on the
937 	 * next read().
938 	 */
939 	if (read_len == 0 && uio->uio_resid != 0)
940 		error = ENOSPC;
941 
942 read_fail:
943 	cam_periph_unlock(softc->periph);
944 	return (error);
945 }
946 
947 /* Copy completed ccb back to the user */
948 static int
949 targreturnccb(struct targ_softc *softc, union ccb *ccb)
950 {
951 	struct targ_cmd_descr *descr;
952 	struct ccb_hdr *u_ccbh;
953 	size_t ccb_len;
954 	int error;
955 
956 	CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, ("targreturnccb %p\n", ccb));
957 	descr = (struct targ_cmd_descr *)ccb->ccb_h.targ_descr;
958 	u_ccbh = &descr->user_ccb->ccb_h;
959 
960 	/* Copy out the central portion of the ccb_hdr */
961 	copyout(&ccb->ccb_h.retry_count, &u_ccbh->retry_count,
962 		offsetof(struct ccb_hdr, periph_priv) -
963 		offsetof(struct ccb_hdr, retry_count));
964 
965 	/* Copy out the rest of the ccb (after the ccb_hdr) */
966 	ccb_len = targccblen(ccb->ccb_h.func_code) - sizeof(struct ccb_hdr);
967 	if (descr->mapinfo.num_bufs_used != 0)
968 		cam_periph_unmapmem(ccb, &descr->mapinfo);
969 	error = copyout(&ccb->ccb_h + 1, u_ccbh + 1, ccb_len);
970 	if (error != 0) {
971 		xpt_print(softc->path,
972 		    "targreturnccb - CCB copyout failed (%d)\n", error);
973 	}
974 	/* Free CCB or send back to devq. */
975 	targfreeccb(softc, ccb);
976 
977 	return (error);
978 }
979 
980 static union ccb *
981 targgetccb(struct targ_softc *softc, xpt_opcode type, int priority)
982 {
983 	union ccb *ccb;
984 
985 #if 0
986 	int ccb_len;
987 	ccb_len = targccblen(type);
988 	ccb = kmalloc(ccb_len, M_TARG, M_INTWAIT);
989 #endif
990 	ccb = xpt_alloc_ccb();
991 	CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, ("getccb %p\n", ccb));
992 
993 	xpt_setup_ccb(&ccb->ccb_h, softc->path, priority);
994 	ccb->ccb_h.func_code = type;
995 	ccb->ccb_h.cbfcnp = targdone;
996 	ccb->ccb_h.targ_descr = targgetdescr(softc);
997 
998 	return (ccb);
999 }
1000 
1001 static void
1002 targfreeccb(struct targ_softc *softc, union ccb *ccb)
1003 {
1004 	CAM_DEBUG_PRINT(CAM_DEBUG_PERIPH, ("targfreeccb descr %p and\n",
1005 			ccb->ccb_h.targ_descr));
1006 	kfree(ccb->ccb_h.targ_descr, M_TARG);
1007 	ccb->ccb_h.targ_descr = NULL;	/* safety */
1008 
1009 	switch (ccb->ccb_h.func_code) {
1010 	case XPT_ACCEPT_TARGET_IO:
1011 	case XPT_IMMED_NOTIFY:
1012 		CAM_DEBUG_PRINT(CAM_DEBUG_PERIPH, ("freeing ccb %p\n", ccb));
1013 		xpt_free_ccb(&ccb->ccb_h);
1014 		break;
1015 	default:
1016 		/* Send back CCB if we got it from the periph */
1017 		if (XPT_FC_IS_QUEUED(ccb)) {
1018 			CAM_DEBUG_PRINT(CAM_DEBUG_PERIPH,
1019 					("returning queued ccb %p\n", ccb));
1020 			xpt_release_ccb(ccb);
1021 		} else {
1022 			CAM_DEBUG_PRINT(CAM_DEBUG_PERIPH,
1023 					("freeing ccb %p\n", ccb));
1024 			xpt_free_ccb(&ccb->ccb_h);
1025 		}
1026 		break;
1027 	}
1028 }
1029 
1030 static struct targ_cmd_descr *
1031 targgetdescr(struct targ_softc *softc)
1032 {
1033 	struct targ_cmd_descr *descr;
1034 
1035 	descr = kmalloc(sizeof(*descr), M_TARG, M_INTWAIT);
1036 	descr->mapinfo.num_bufs_used = 0;
1037 	return (descr);
1038 }
1039 
1040 static int
1041 targclone(struct dev_clone_args *ap)
1042 {
1043 	int unit;
1044 
1045 	unit = devfs_clone_bitmap_get(&DEVFS_CLONE_BITMAP(targ), 0);
1046 	ap->a_dev = make_only_dev(&targ_ops, unit, UID_ROOT, GID_WHEEL,
1047 				  0600, "targ%d", unit);
1048 	return 0;
1049 }
1050 
1051 static void
1052 targinit(void)
1053 {
1054 	make_autoclone_dev(&targ_ops, &DEVFS_CLONE_BITMAP(targ),
1055 		targclone, UID_ROOT, GID_WHEEL, 0600, "targ");
1056 	/* XXX: need uninit or so? */
1057 }
1058 
1059 static void
1060 targasync(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg)
1061 {
1062 	/* All events are handled in usermode by INOTs */
1063 	panic("targasync() called, should be an INOT instead");
1064 }
1065 
1066 /* Cancel all pending requests and CCBs awaiting work. */
1067 static void
1068 abort_all_pending(struct targ_softc *softc)
1069 {
1070 	struct targ_cmd_descr   *descr;
1071 	struct ccb_abort	 *cab;
1072 	struct ccb_hdr		*ccb_h;
1073 	struct cam_sim		*sim;
1074 
1075 	CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, ("abort_all_pending\n"));
1076 
1077 	/* First abort the descriptors awaiting resources */
1078 	while ((descr = TAILQ_FIRST(&softc->work_queue)) != NULL) {
1079 		CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH,
1080 			  ("Aborting descr from workq %p\n", descr));
1081 		TAILQ_REMOVE(&softc->work_queue, descr, tqe);
1082 		TAILQ_INSERT_TAIL(&softc->abort_queue, descr, tqe);
1083 	}
1084 
1085 	/*
1086 	 * Then abort all pending CCBs.
1087 	 * targdone() will return the aborted CCB via user_ccb_queue
1088 	 */
1089 	cab = &xpt_alloc_ccb()->cab;
1090 	xpt_setup_ccb(&cab->ccb_h, softc->path, /*priority*/0);
1091 	cab->ccb_h.func_code = XPT_ABORT;
1092 	cab->ccb_h.status = CAM_REQ_CMP_ERR;
1093 	TAILQ_FOREACH(ccb_h, &softc->pending_ccb_queue, periph_links.tqe) {
1094 		CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH,
1095 			  ("Aborting pending CCB %p\n", ccb_h));
1096 		cab->abort_ccb = (union ccb *)ccb_h;
1097 		xpt_action((union ccb *)cab);
1098 		if (cab->ccb_h.status != CAM_REQ_CMP) {
1099 			xpt_print(cab->ccb_h.path,
1100 			    "Unable to abort CCB, status %#x\n",
1101 			    cab->ccb_h.status);
1102 		}
1103 	}
1104 
1105 	/* If we aborted at least one pending CCB ok, wait for it. */
1106 	if (cab->ccb_h.status == CAM_REQ_CMP) {
1107 		sim = xpt_path_sim(softc->path);
1108 		sim_lock_sleep(&softc->pending_ccb_queue, PCATCH, "tgabrt", 0,
1109 			       sim->lock);
1110 	}
1111 
1112 	/* If we aborted anything from the work queue, wakeup user. */
1113 	if (!TAILQ_EMPTY(&softc->user_ccb_queue) ||
1114 	    !TAILQ_EMPTY(&softc->abort_queue)) {
1115 		notify_user(softc);
1116 	}
1117 
1118 	xpt_free_ccb(&cab->ccb_h);
1119 }
1120 
1121 /* Notify the user that data is ready */
1122 static void
1123 notify_user(struct targ_softc *softc)
1124 {
1125 	/*
1126 	 * Notify users sleeping via poll(), kqueue(), and
1127 	 * blocking read().
1128 	 */
1129 	KNOTE(&softc->read_kq.ki_note, 0);
1130 	wakeup(&softc->user_ccb_queue);
1131 }
1132 
1133 /* Convert CAM status to errno values */
1134 static int
1135 targcamstatus(cam_status status)
1136 {
1137 	switch (status & CAM_STATUS_MASK) {
1138 	case CAM_REQ_CMP:	/* CCB request completed without error */
1139 		return (0);
1140 	case CAM_REQ_INPROG:	/* CCB request is in progress */
1141 		return (EINPROGRESS);
1142 	case CAM_REQ_CMP_ERR:	/* CCB request completed with an error */
1143 		return (EIO);
1144 	case CAM_PROVIDE_FAIL:	/* Unable to provide requested capability */
1145 		return (ENOTTY);
1146 	case CAM_FUNC_NOTAVAIL:	/* The requested function is not available */
1147 		return (ENOTSUP);
1148 	case CAM_LUN_ALRDY_ENA:	/* LUN is already enabled for target mode */
1149 		return (EADDRINUSE);
1150 	case CAM_PATH_INVALID:	/* Supplied Path ID is invalid */
1151 	case CAM_DEV_NOT_THERE:	/* SCSI Device Not Installed/there */
1152 		return (ENOENT);
1153 	case CAM_REQ_ABORTED:	/* CCB request aborted by the host */
1154 		return (ECANCELED);
1155 	case CAM_CMD_TIMEOUT:	/* Command timeout */
1156 		return (ETIMEDOUT);
1157 	case CAM_REQUEUE_REQ:	/* Requeue to preserve transaction ordering */
1158 		return (EAGAIN);
1159 	case CAM_REQ_INVALID:	/* CCB request was invalid */
1160 		return (EINVAL);
1161 	case CAM_RESRC_UNAVAIL:	/* Resource Unavailable */
1162 		return (ENOMEM);
1163 	case CAM_BUSY:		/* CAM subsytem is busy */
1164 	case CAM_UA_ABORT:	/* Unable to abort CCB request */
1165 		return (EBUSY);
1166 	default:
1167 		return (ENXIO);
1168 	}
1169 }
1170 
1171 static size_t
1172 targccblen(xpt_opcode func_code)
1173 {
1174 	int len;
1175 
1176 	/* Codes we expect to see as a target */
1177 	switch (func_code) {
1178 	case XPT_CONT_TARGET_IO:
1179 	case XPT_SCSI_IO:
1180 		len = sizeof(struct ccb_scsiio);
1181 		break;
1182 	case XPT_ACCEPT_TARGET_IO:
1183 		len = sizeof(struct ccb_accept_tio);
1184 		break;
1185 	case XPT_IMMED_NOTIFY:
1186 		len = sizeof(struct ccb_immed_notify);
1187 		break;
1188 	case XPT_REL_SIMQ:
1189 		len = sizeof(struct ccb_relsim);
1190 		break;
1191 	case XPT_PATH_INQ:
1192 		len = sizeof(struct ccb_pathinq);
1193 		break;
1194 	case XPT_DEBUG:
1195 		len = sizeof(struct ccb_debug);
1196 		break;
1197 	case XPT_ABORT:
1198 		len = sizeof(struct ccb_abort);
1199 		break;
1200 	case XPT_EN_LUN:
1201 		len = sizeof(struct ccb_en_lun);
1202 		break;
1203 	default:
1204 		len = sizeof(union ccb);
1205 		break;
1206 	}
1207 
1208 	return (len);
1209 }
1210