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