xref: /freebsd/sys/cam/ctl/ctl_frontend_cam_sim.c (revision 56e53cb8ef000c3ef72337a4095987a932cdedef)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2009 Silicon Graphics International Corp.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions, and the following disclaimer,
12  *    without modification.
13  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
14  *    substantially similar to the "NO WARRANTY" disclaimer below
15  *    ("Disclaimer") and any redistribution must be conditioned upon
16  *    including a substantially similar Disclaimer requirement for further
17  *    binary redistribution.
18  *
19  * NO WARRANTY
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
29  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGES.
31  *
32  * $Id: //depot/users/kenm/FreeBSD-test2/sys/cam/ctl/ctl_frontend_cam_sim.c#4 $
33  */
34 /*
35  * CTL frontend to CAM SIM interface.  This allows access to CTL LUNs via
36  * the da(4) and pass(4) drivers from inside the system.
37  *
38  * Author: Ken Merry <ken@FreeBSD.org>
39  */
40 
41 #include <sys/cdefs.h>
42 __FBSDID("$FreeBSD$");
43 
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/kernel.h>
47 #include <sys/types.h>
48 #include <sys/malloc.h>
49 #include <sys/lock.h>
50 #include <sys/mutex.h>
51 #include <sys/condvar.h>
52 #include <sys/queue.h>
53 #include <sys/bus.h>
54 #include <sys/sysctl.h>
55 #include <machine/bus.h>
56 #include <sys/sbuf.h>
57 
58 #include <cam/cam.h>
59 #include <cam/cam_ccb.h>
60 #include <cam/cam_sim.h>
61 #include <cam/cam_xpt_sim.h>
62 #include <cam/cam_xpt.h>
63 #include <cam/cam_periph.h>
64 #include <cam/scsi/scsi_all.h>
65 #include <cam/scsi/scsi_message.h>
66 #include <cam/ctl/ctl_io.h>
67 #include <cam/ctl/ctl.h>
68 #include <cam/ctl/ctl_frontend.h>
69 #include <cam/ctl/ctl_debug.h>
70 
71 #define	io_ptr		spriv_ptr1
72 
73 struct cfcs_io {
74 	union ccb *ccb;
75 };
76 
77 struct cfcs_softc {
78 	struct ctl_port port;
79 	char port_name[32];
80 	struct cam_sim *sim;
81 	struct cam_devq *devq;
82 	struct cam_path *path;
83 	struct mtx lock;
84 	uint64_t wwnn;
85 	uint64_t wwpn;
86 	uint32_t cur_tag_num;
87 	int online;
88 };
89 
90 /*
91  * We can't handle CCBs with these flags.  For the most part, we just don't
92  * handle physical addresses yet.  That would require mapping things in
93  * order to do the copy.
94  */
95 #define	CFCS_BAD_CCB_FLAGS (CAM_DATA_ISPHYS | CAM_MSG_BUF_PHYS |	\
96 	CAM_SNS_BUF_PHYS | CAM_CDB_PHYS | CAM_SENSE_PTR |		\
97 	CAM_SENSE_PHYS)
98 
99 static int cfcs_init(void);
100 static int cfcs_shutdown(void);
101 static void cfcs_poll(struct cam_sim *sim);
102 static void cfcs_online(void *arg);
103 static void cfcs_offline(void *arg);
104 static void cfcs_datamove(union ctl_io *io);
105 static void cfcs_done(union ctl_io *io);
106 void cfcs_action(struct cam_sim *sim, union ccb *ccb);
107 
108 struct cfcs_softc cfcs_softc;
109 /*
110  * This is primarily intended to allow for error injection to test the CAM
111  * sense data and sense residual handling code.  This sets the maximum
112  * amount of SCSI sense data that we will report to CAM.
113  */
114 static int cfcs_max_sense = sizeof(struct scsi_sense_data);
115 
116 SYSCTL_NODE(_kern_cam, OID_AUTO, ctl2cam, CTLFLAG_RD, 0,
117 	    "CAM Target Layer SIM frontend");
118 SYSCTL_INT(_kern_cam_ctl2cam, OID_AUTO, max_sense, CTLFLAG_RW,
119            &cfcs_max_sense, 0, "Maximum sense data size");
120 
121 static struct ctl_frontend cfcs_frontend =
122 {
123 	.name = "camsim",
124 	.init = cfcs_init,
125 	.shutdown = cfcs_shutdown,
126 };
127 CTL_FRONTEND_DECLARE(ctlcfcs, cfcs_frontend);
128 
129 static int
130 cfcs_init(void)
131 {
132 	struct cfcs_softc *softc;
133 	struct ctl_port *port;
134 	int retval;
135 
136 	softc = &cfcs_softc;
137 	bzero(softc, sizeof(*softc));
138 	mtx_init(&softc->lock, "ctl2cam", NULL, MTX_DEF);
139 	port = &softc->port;
140 
141 	port->frontend = &cfcs_frontend;
142 	port->port_type = CTL_PORT_INTERNAL;
143 	/* XXX KDM what should the real number be here? */
144 	port->num_requested_ctl_io = 4096;
145 	snprintf(softc->port_name, sizeof(softc->port_name), "camsim");
146 	port->port_name = softc->port_name;
147 	port->port_online = cfcs_online;
148 	port->port_offline = cfcs_offline;
149 	port->onoff_arg = softc;
150 	port->fe_datamove = cfcs_datamove;
151 	port->fe_done = cfcs_done;
152 	port->targ_port = -1;
153 
154 	retval = ctl_port_register(port);
155 	if (retval != 0) {
156 		printf("%s: ctl_port_register() failed with error %d!\n",
157 		       __func__, retval);
158 		mtx_destroy(&softc->lock);
159 		return (retval);
160 	}
161 
162 	/*
163 	 * If the CTL frontend didn't tell us what our WWNN/WWPN is, go
164 	 * ahead and set something random.
165 	 */
166 	if (port->wwnn == 0) {
167 		uint64_t random_bits;
168 
169 		arc4rand(&random_bits, sizeof(random_bits), 0);
170 		softc->wwnn = (random_bits & 0x0000000fffffff00ULL) |
171 			/* Company ID */ 0x5000000000000000ULL |
172 			/* NL-Port */    0x0300;
173 		softc->wwpn = softc->wwnn + port->targ_port + 1;
174 		ctl_port_set_wwns(port, true, softc->wwnn, true, softc->wwpn);
175 	} else {
176 		softc->wwnn = port->wwnn;
177 		softc->wwpn = port->wwpn;
178 	}
179 
180 	mtx_lock(&softc->lock);
181 	softc->devq = cam_simq_alloc(port->num_requested_ctl_io);
182 	if (softc->devq == NULL) {
183 		printf("%s: error allocating devq\n", __func__);
184 		retval = ENOMEM;
185 		goto bailout;
186 	}
187 
188 	softc->sim = cam_sim_alloc(cfcs_action, cfcs_poll, softc->port_name,
189 				   softc, /*unit*/ 0, &softc->lock, 1,
190 				   port->num_requested_ctl_io, softc->devq);
191 	if (softc->sim == NULL) {
192 		printf("%s: error allocating SIM\n", __func__);
193 		retval = ENOMEM;
194 		goto bailout;
195 	}
196 
197 	if (xpt_bus_register(softc->sim, NULL, 0) != CAM_SUCCESS) {
198 		printf("%s: error registering SIM\n", __func__);
199 		retval = ENOMEM;
200 		goto bailout;
201 	}
202 
203 	if (xpt_create_path(&softc->path, /*periph*/NULL,
204 			    cam_sim_path(softc->sim),
205 			    CAM_TARGET_WILDCARD,
206 			    CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
207 		printf("%s: error creating path\n", __func__);
208 		xpt_bus_deregister(cam_sim_path(softc->sim));
209 		retval = EINVAL;
210 		goto bailout;
211 	}
212 
213 	mtx_unlock(&softc->lock);
214 
215 	return (retval);
216 
217 bailout:
218 	if (softc->sim)
219 		cam_sim_free(softc->sim, /*free_devq*/ TRUE);
220 	else if (softc->devq)
221 		cam_simq_free(softc->devq);
222 	mtx_unlock(&softc->lock);
223 	mtx_destroy(&softc->lock);
224 
225 	return (retval);
226 }
227 
228 static int
229 cfcs_shutdown(void)
230 {
231 	struct cfcs_softc *softc = &cfcs_softc;
232 	struct ctl_port *port = &softc->port;
233 	int error;
234 
235 	ctl_port_offline(port);
236 
237 	mtx_lock(&softc->lock);
238 	xpt_free_path(softc->path);
239 	xpt_bus_deregister(cam_sim_path(softc->sim));
240 	cam_sim_free(softc->sim, /*free_devq*/ TRUE);
241 	mtx_unlock(&softc->lock);
242 	mtx_destroy(&softc->lock);
243 
244 	if ((error = ctl_port_deregister(port)) != 0)
245 		printf("%s: cam_sim port deregistration failed\n", __func__);
246 	return (error);
247 }
248 
249 static void
250 cfcs_poll(struct cam_sim *sim)
251 {
252 
253 }
254 
255 static void
256 cfcs_onoffline(void *arg, int online)
257 {
258 	struct cfcs_softc *softc;
259 	union ccb *ccb;
260 
261 	softc = (struct cfcs_softc *)arg;
262 
263 	mtx_lock(&softc->lock);
264 	softc->online = online;
265 
266 	ccb = xpt_alloc_ccb_nowait();
267 	if (ccb == NULL) {
268 		printf("%s: unable to allocate CCB for rescan\n", __func__);
269 		goto bailout;
270 	}
271 
272 	if (xpt_create_path(&ccb->ccb_h.path, NULL,
273 			    cam_sim_path(softc->sim), CAM_TARGET_WILDCARD,
274 			    CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
275 		printf("%s: can't allocate path for rescan\n", __func__);
276 		xpt_free_ccb(ccb);
277 		goto bailout;
278 	}
279 	xpt_rescan(ccb);
280 
281 bailout:
282 	mtx_unlock(&softc->lock);
283 }
284 
285 static void
286 cfcs_online(void *arg)
287 {
288 	cfcs_onoffline(arg, /*online*/ 1);
289 }
290 
291 static void
292 cfcs_offline(void *arg)
293 {
294 	cfcs_onoffline(arg, /*online*/ 0);
295 }
296 
297 /*
298  * This function is very similar to ctl_ioctl_do_datamove().  Is there a
299  * way to combine the functionality?
300  *
301  * XXX KDM may need to move this into a thread.  We're doing a bcopy in the
302  * caller's context, which will usually be the backend.  That may not be a
303  * good thing.
304  */
305 static void
306 cfcs_datamove(union ctl_io *io)
307 {
308 	union ccb *ccb;
309 	bus_dma_segment_t cam_sg_entry, *cam_sglist;
310 	struct ctl_sg_entry ctl_sg_entry, *ctl_sglist;
311 	int cam_sg_count, ctl_sg_count, cam_sg_start;
312 	int cam_sg_offset;
313 	int len_to_copy;
314 	int ctl_watermark, cam_watermark;
315 	int i, j;
316 
317 	ccb = io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr;
318 
319 	/*
320 	 * Note that we have a check in cfcs_action() to make sure that any
321 	 * CCBs with "bad" flags are returned with CAM_REQ_INVALID.  This
322 	 * is just to make sure no one removes that check without updating
323 	 * this code to provide the additional functionality necessary to
324 	 * support those modes of operation.
325 	 */
326 	KASSERT(((ccb->ccb_h.flags & CFCS_BAD_CCB_FLAGS) == 0), ("invalid "
327 		  "CAM flags %#x", (ccb->ccb_h.flags & CFCS_BAD_CCB_FLAGS)));
328 
329 	/*
330 	 * Simplify things on both sides by putting single buffers into a
331 	 * single entry S/G list.
332 	 */
333 	switch ((ccb->ccb_h.flags & CAM_DATA_MASK)) {
334 	case CAM_DATA_SG: {
335 		int len_seen;
336 
337 		cam_sglist = (bus_dma_segment_t *)ccb->csio.data_ptr;
338 		cam_sg_count = ccb->csio.sglist_cnt;
339 		cam_sg_start = cam_sg_count;
340 		cam_sg_offset = 0;
341 
342 		for (i = 0, len_seen = 0; i < cam_sg_count; i++) {
343 			if ((len_seen + cam_sglist[i].ds_len) >=
344 			     io->scsiio.kern_rel_offset) {
345 				cam_sg_start = i;
346 				cam_sg_offset = io->scsiio.kern_rel_offset -
347 					len_seen;
348 				break;
349 			}
350 			len_seen += cam_sglist[i].ds_len;
351 		}
352 		break;
353 	}
354 	case CAM_DATA_VADDR:
355 		cam_sglist = &cam_sg_entry;
356 		cam_sglist[0].ds_len = ccb->csio.dxfer_len;
357 		cam_sglist[0].ds_addr = (bus_addr_t)(uintptr_t)ccb->csio.data_ptr;
358 		cam_sg_count = 1;
359 		cam_sg_start = 0;
360 		cam_sg_offset = io->scsiio.kern_rel_offset;
361 		break;
362 	default:
363 		panic("Invalid CAM flags %#x", ccb->ccb_h.flags);
364 	}
365 
366 	if (io->scsiio.kern_sg_entries > 0) {
367 		ctl_sglist = (struct ctl_sg_entry *)io->scsiio.kern_data_ptr;
368 		ctl_sg_count = io->scsiio.kern_sg_entries;
369 	} else {
370 		ctl_sglist = &ctl_sg_entry;
371 		ctl_sglist->addr = io->scsiio.kern_data_ptr;
372 		ctl_sglist->len = io->scsiio.kern_data_len;
373 		ctl_sg_count = 1;
374 	}
375 
376 	ctl_watermark = 0;
377 	cam_watermark = cam_sg_offset;
378 	for (i = cam_sg_start, j = 0;
379 	     i < cam_sg_count && j < ctl_sg_count;) {
380 		uint8_t *cam_ptr, *ctl_ptr;
381 
382 		len_to_copy = MIN(cam_sglist[i].ds_len - cam_watermark,
383 				  ctl_sglist[j].len - ctl_watermark);
384 
385 		cam_ptr = (uint8_t *)(uintptr_t)cam_sglist[i].ds_addr;
386 		cam_ptr = cam_ptr + cam_watermark;
387 		if (io->io_hdr.flags & CTL_FLAG_BUS_ADDR) {
388 			/*
389 			 * XXX KDM fix this!
390 			 */
391 			panic("need to implement bus address support");
392 #if 0
393 			kern_ptr = bus_to_virt(kern_sglist[j].addr);
394 #endif
395 		} else
396 			ctl_ptr = (uint8_t *)ctl_sglist[j].addr;
397 		ctl_ptr = ctl_ptr + ctl_watermark;
398 
399 		if ((io->io_hdr.flags & CTL_FLAG_DATA_MASK) ==
400 		     CTL_FLAG_DATA_IN) {
401 			CTL_DEBUG_PRINT(("%s: copying %d bytes to CAM\n",
402 					 __func__, len_to_copy));
403 			CTL_DEBUG_PRINT(("%s: from %p to %p\n", ctl_ptr,
404 					 __func__, cam_ptr));
405 			bcopy(ctl_ptr, cam_ptr, len_to_copy);
406 		} else {
407 			CTL_DEBUG_PRINT(("%s: copying %d bytes from CAM\n",
408 					 __func__, len_to_copy));
409 			CTL_DEBUG_PRINT(("%s: from %p to %p\n", cam_ptr,
410 					 __func__, ctl_ptr));
411 			bcopy(cam_ptr, ctl_ptr, len_to_copy);
412 		}
413 
414 		io->scsiio.ext_data_filled += len_to_copy;
415 		io->scsiio.kern_data_resid -= len_to_copy;
416 
417 		cam_watermark += len_to_copy;
418 		if (cam_sglist[i].ds_len == cam_watermark) {
419 			i++;
420 			cam_watermark = 0;
421 		}
422 
423 		ctl_watermark += len_to_copy;
424 		if (ctl_sglist[j].len == ctl_watermark) {
425 			j++;
426 			ctl_watermark = 0;
427 		}
428 	}
429 
430 	if ((io->io_hdr.status & CTL_STATUS_MASK) == CTL_SUCCESS) {
431 		io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = NULL;
432 		io->io_hdr.flags |= CTL_FLAG_STATUS_SENT;
433 		ccb->csio.resid = ccb->csio.dxfer_len -
434 		    io->scsiio.ext_data_filled;
435 		ccb->ccb_h.status &= ~CAM_STATUS_MASK;
436 		ccb->ccb_h.status |= CAM_REQ_CMP;
437 		xpt_done(ccb);
438 	}
439 
440 	io->scsiio.be_move_done(io);
441 }
442 
443 static void
444 cfcs_done(union ctl_io *io)
445 {
446 	union ccb *ccb;
447 
448 	ccb = io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr;
449 	if (ccb == NULL) {
450 		ctl_free_io(io);
451 		return;
452 	}
453 
454 	/*
455 	 * At this point we should have status.  If we don't, that's a bug.
456 	 */
457 	KASSERT(((io->io_hdr.status & CTL_STATUS_MASK) != CTL_STATUS_NONE),
458 		("invalid CTL status %#x", io->io_hdr.status));
459 
460 	/*
461 	 * Translate CTL status to CAM status.
462 	 */
463 	if (ccb->ccb_h.func_code == XPT_SCSI_IO) {
464 		ccb->csio.resid = ccb->csio.dxfer_len -
465 		    io->scsiio.ext_data_filled;
466 	}
467 	ccb->ccb_h.status &= ~CAM_STATUS_MASK;
468 	switch (io->io_hdr.status & CTL_STATUS_MASK) {
469 	case CTL_SUCCESS:
470 		ccb->ccb_h.status |= CAM_REQ_CMP;
471 		break;
472 	case CTL_SCSI_ERROR:
473 		ccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR | CAM_AUTOSNS_VALID;
474 		ccb->csio.scsi_status = io->scsiio.scsi_status;
475 		bcopy(&io->scsiio.sense_data, &ccb->csio.sense_data,
476 		      min(io->scsiio.sense_len, ccb->csio.sense_len));
477 		if (ccb->csio.sense_len > io->scsiio.sense_len)
478 			ccb->csio.sense_resid = ccb->csio.sense_len -
479 						io->scsiio.sense_len;
480 		else
481 			ccb->csio.sense_resid = 0;
482 		if ((ccb->csio.sense_len - ccb->csio.sense_resid) >
483 		     cfcs_max_sense) {
484 			ccb->csio.sense_resid = ccb->csio.sense_len -
485 						cfcs_max_sense;
486 		}
487 		break;
488 	case CTL_CMD_ABORTED:
489 		ccb->ccb_h.status |= CAM_REQ_ABORTED;
490 		break;
491 	case CTL_ERROR:
492 	default:
493 		ccb->ccb_h.status |= CAM_REQ_CMP_ERR;
494 		break;
495 	}
496 	if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP &&
497 	    (ccb->ccb_h.status & CAM_DEV_QFRZN) == 0) {
498 		xpt_freeze_devq(ccb->ccb_h.path, 1);
499 		ccb->ccb_h.status |= CAM_DEV_QFRZN;
500 	}
501 	xpt_done(ccb);
502 	ctl_free_io(io);
503 }
504 
505 void
506 cfcs_action(struct cam_sim *sim, union ccb *ccb)
507 {
508 	struct cfcs_softc *softc;
509 	int err;
510 
511 	softc = (struct cfcs_softc *)cam_sim_softc(sim);
512 	mtx_assert(&softc->lock, MA_OWNED);
513 
514 	switch (ccb->ccb_h.func_code) {
515 	case XPT_SCSI_IO: {
516 		union ctl_io *io;
517 		struct ccb_scsiio *csio;
518 
519 		csio = &ccb->csio;
520 
521 		/*
522 		 * Catch CCB flags, like physical address flags, that
523 	 	 * indicate situations we currently can't handle.
524 		 */
525 		if (ccb->ccb_h.flags & CFCS_BAD_CCB_FLAGS) {
526 			ccb->ccb_h.status = CAM_REQ_INVALID;
527 			printf("%s: bad CCB flags %#x (all flags %#x)\n",
528 			       __func__, ccb->ccb_h.flags & CFCS_BAD_CCB_FLAGS,
529 			       ccb->ccb_h.flags);
530 			xpt_done(ccb);
531 			return;
532 		}
533 
534 		/*
535 		 * If we aren't online, there are no devices to see.
536 		 */
537 		if (softc->online == 0) {
538 			ccb->ccb_h.status = CAM_DEV_NOT_THERE;
539 			xpt_done(ccb);
540 			return;
541 		}
542 
543 		io = ctl_alloc_io_nowait(softc->port.ctl_pool_ref);
544 		if (io == NULL) {
545 			printf("%s: can't allocate ctl_io\n", __func__);
546 			ccb->ccb_h.status = CAM_BUSY | CAM_DEV_QFRZN;
547 			xpt_freeze_devq(ccb->ccb_h.path, 1);
548 			xpt_done(ccb);
549 			return;
550 		}
551 		ctl_zero_io(io);
552 		/* Save pointers on both sides */
553 		io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = ccb;
554 		ccb->ccb_h.io_ptr = io;
555 
556 		/*
557 		 * Only SCSI I/O comes down this path, resets, etc. come
558 		 * down via the XPT_RESET_BUS/LUN CCBs below.
559 		 */
560 		io->io_hdr.io_type = CTL_IO_SCSI;
561 		io->io_hdr.nexus.initid = 1;
562 		io->io_hdr.nexus.targ_port = softc->port.targ_port;
563 		io->io_hdr.nexus.targ_lun = ctl_decode_lun(
564 		    CAM_EXTLUN_BYTE_SWIZZLE(ccb->ccb_h.target_lun));
565 		/*
566 		 * This tag scheme isn't the best, since we could in theory
567 		 * have a very long-lived I/O and tag collision, especially
568 		 * in a high I/O environment.  But it should work well
569 		 * enough for now.  Since we're using unsigned ints,
570 		 * they'll just wrap around.
571 		 */
572 		io->scsiio.tag_num = softc->cur_tag_num++;
573 		csio->tag_id = io->scsiio.tag_num;
574 		switch (csio->tag_action) {
575 		case CAM_TAG_ACTION_NONE:
576 			io->scsiio.tag_type = CTL_TAG_UNTAGGED;
577 			break;
578 		case MSG_SIMPLE_TASK:
579 			io->scsiio.tag_type = CTL_TAG_SIMPLE;
580 			break;
581 		case MSG_HEAD_OF_QUEUE_TASK:
582         		io->scsiio.tag_type = CTL_TAG_HEAD_OF_QUEUE;
583 			break;
584 		case MSG_ORDERED_TASK:
585         		io->scsiio.tag_type = CTL_TAG_ORDERED;
586 			break;
587 		case MSG_ACA_TASK:
588 			io->scsiio.tag_type = CTL_TAG_ACA;
589 			break;
590 		default:
591 			io->scsiio.tag_type = CTL_TAG_UNTAGGED;
592 			printf("%s: unhandled tag type %#x!!\n", __func__,
593 			       csio->tag_action);
594 			break;
595 		}
596 		if (csio->cdb_len > sizeof(io->scsiio.cdb)) {
597 			printf("%s: WARNING: CDB len %d > ctl_io space %zd\n",
598 			       __func__, csio->cdb_len, sizeof(io->scsiio.cdb));
599 		}
600 		io->scsiio.cdb_len = min(csio->cdb_len, sizeof(io->scsiio.cdb));
601 		bcopy(scsiio_cdb_ptr(csio), io->scsiio.cdb, io->scsiio.cdb_len);
602 
603 		ccb->ccb_h.status |= CAM_SIM_QUEUED;
604 		err = ctl_queue(io);
605 		if (err != CTL_RETVAL_COMPLETE) {
606 			printf("%s: func %d: error %d returned by "
607 			       "ctl_queue()!\n", __func__,
608 			       ccb->ccb_h.func_code, err);
609 			ctl_free_io(io);
610 			ccb->ccb_h.status = CAM_REQ_INVALID;
611 			xpt_done(ccb);
612 			return;
613 		}
614 		break;
615 	}
616 	case XPT_ABORT: {
617 		union ctl_io *io;
618 		union ccb *abort_ccb;
619 
620 		abort_ccb = ccb->cab.abort_ccb;
621 
622 		if (abort_ccb->ccb_h.func_code != XPT_SCSI_IO) {
623 			ccb->ccb_h.status = CAM_REQ_INVALID;
624 			xpt_done(ccb);
625 		}
626 
627 		/*
628 		 * If we aren't online, there are no devices to talk to.
629 		 */
630 		if (softc->online == 0) {
631 			ccb->ccb_h.status = CAM_DEV_NOT_THERE;
632 			xpt_done(ccb);
633 			return;
634 		}
635 
636 		io = ctl_alloc_io_nowait(softc->port.ctl_pool_ref);
637 		if (io == NULL) {
638 			ccb->ccb_h.status = CAM_BUSY | CAM_DEV_QFRZN;
639 			xpt_freeze_devq(ccb->ccb_h.path, 1);
640 			xpt_done(ccb);
641 			return;
642 		}
643 
644 		ctl_zero_io(io);
645 		/* Save pointers on both sides */
646 		io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = ccb;
647 		ccb->ccb_h.io_ptr = io;
648 
649 		io->io_hdr.io_type = CTL_IO_TASK;
650 		io->io_hdr.nexus.initid = 1;
651 		io->io_hdr.nexus.targ_port = softc->port.targ_port;
652 		io->io_hdr.nexus.targ_lun = ctl_decode_lun(
653 		    CAM_EXTLUN_BYTE_SWIZZLE(ccb->ccb_h.target_lun));
654 		io->taskio.task_action = CTL_TASK_ABORT_TASK;
655 		io->taskio.tag_num = abort_ccb->csio.tag_id;
656 		switch (abort_ccb->csio.tag_action) {
657 		case CAM_TAG_ACTION_NONE:
658 			io->taskio.tag_type = CTL_TAG_UNTAGGED;
659 			break;
660 		case MSG_SIMPLE_TASK:
661 			io->taskio.tag_type = CTL_TAG_SIMPLE;
662 			break;
663 		case MSG_HEAD_OF_QUEUE_TASK:
664         		io->taskio.tag_type = CTL_TAG_HEAD_OF_QUEUE;
665 			break;
666 		case MSG_ORDERED_TASK:
667         		io->taskio.tag_type = CTL_TAG_ORDERED;
668 			break;
669 		case MSG_ACA_TASK:
670 			io->taskio.tag_type = CTL_TAG_ACA;
671 			break;
672 		default:
673 			io->taskio.tag_type = CTL_TAG_UNTAGGED;
674 			printf("%s: unhandled tag type %#x!!\n", __func__,
675 			       abort_ccb->csio.tag_action);
676 			break;
677 		}
678 		err = ctl_queue(io);
679 		if (err != CTL_RETVAL_COMPLETE) {
680 			printf("%s func %d: error %d returned by "
681 			       "ctl_queue()!\n", __func__,
682 			       ccb->ccb_h.func_code, err);
683 			ctl_free_io(io);
684 		}
685 		break;
686 	}
687 	case XPT_GET_TRAN_SETTINGS: {
688 		struct ccb_trans_settings *cts;
689 		struct ccb_trans_settings_scsi *scsi;
690 		struct ccb_trans_settings_fc *fc;
691 
692 		cts = &ccb->cts;
693 		scsi = &cts->proto_specific.scsi;
694 		fc = &cts->xport_specific.fc;
695 
696 
697 		cts->protocol = PROTO_SCSI;
698 		cts->protocol_version = SCSI_REV_SPC2;
699 		cts->transport = XPORT_FC;
700 		cts->transport_version = 0;
701 
702 		scsi->valid = CTS_SCSI_VALID_TQ;
703 		scsi->flags = CTS_SCSI_FLAGS_TAG_ENB;
704 		fc->valid = CTS_FC_VALID_SPEED;
705 		fc->bitrate = 800000;
706 		fc->wwnn = softc->wwnn;
707 		fc->wwpn = softc->wwpn;
708 		fc->port = softc->port.targ_port;
709 		fc->valid |= CTS_FC_VALID_WWNN | CTS_FC_VALID_WWPN |
710 			CTS_FC_VALID_PORT;
711 		ccb->ccb_h.status = CAM_REQ_CMP;
712 		break;
713 	}
714 	case XPT_SET_TRAN_SETTINGS:
715 		/* XXX KDM should we actually do something here? */
716 		ccb->ccb_h.status = CAM_REQ_CMP;
717 		break;
718 	case XPT_RESET_BUS:
719 	case XPT_RESET_DEV: {
720 		union ctl_io *io;
721 
722 		/*
723 		 * If we aren't online, there are no devices to talk to.
724 		 */
725 		if (softc->online == 0) {
726 			ccb->ccb_h.status = CAM_DEV_NOT_THERE;
727 			xpt_done(ccb);
728 			return;
729 		}
730 
731 		io = ctl_alloc_io_nowait(softc->port.ctl_pool_ref);
732 		if (io == NULL) {
733 			ccb->ccb_h.status = CAM_BUSY | CAM_DEV_QFRZN;
734 			xpt_freeze_devq(ccb->ccb_h.path, 1);
735 			xpt_done(ccb);
736 			return;
737 		}
738 
739 		ctl_zero_io(io);
740 		/* Save pointers on both sides */
741 		if (ccb->ccb_h.func_code == XPT_RESET_DEV)
742 			io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = ccb;
743 		ccb->ccb_h.io_ptr = io;
744 
745 		io->io_hdr.io_type = CTL_IO_TASK;
746 		io->io_hdr.nexus.initid = 1;
747 		io->io_hdr.nexus.targ_port = softc->port.targ_port;
748 		io->io_hdr.nexus.targ_lun = ctl_decode_lun(
749 		    CAM_EXTLUN_BYTE_SWIZZLE(ccb->ccb_h.target_lun));
750 		if (ccb->ccb_h.func_code == XPT_RESET_BUS)
751 			io->taskio.task_action = CTL_TASK_BUS_RESET;
752 		else
753 			io->taskio.task_action = CTL_TASK_LUN_RESET;
754 
755 		err = ctl_queue(io);
756 		if (err != CTL_RETVAL_COMPLETE) {
757 			printf("%s func %d: error %d returned by "
758 			      "ctl_queue()!\n", __func__,
759 			      ccb->ccb_h.func_code, err);
760 			ctl_free_io(io);
761 		}
762 		break;
763 	}
764 	case XPT_CALC_GEOMETRY:
765 		cam_calc_geometry(&ccb->ccg, 1);
766 		xpt_done(ccb);
767 		break;
768 	case XPT_PATH_INQ: {
769 		struct ccb_pathinq *cpi;
770 
771 		cpi = &ccb->cpi;
772 
773 		cpi->version_num = 0;
774 		cpi->hba_inquiry = PI_TAG_ABLE;
775 		cpi->target_sprt = 0;
776 		cpi->hba_misc = PIM_EXTLUNS;
777 		cpi->hba_eng_cnt = 0;
778 		cpi->max_target = 1;
779 		cpi->max_lun = 1024;
780 		/* Do we really have a limit? */
781 		cpi->maxio = 1024 * 1024;
782 		cpi->async_flags = 0;
783 		cpi->hpath_id = 0;
784 		cpi->initiator_id = 0;
785 
786 		strlcpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
787 		strlcpy(cpi->hba_vid, "FreeBSD", HBA_IDLEN);
788 		strlcpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
789 		cpi->unit_number = 0;
790 		cpi->bus_id = 0;
791 		cpi->base_transfer_speed = 800000;
792 		cpi->protocol = PROTO_SCSI;
793 		cpi->protocol_version = SCSI_REV_SPC2;
794 		/*
795 		 * Pretend to be Fibre Channel.
796 		 */
797 		cpi->transport = XPORT_FC;
798 		cpi->transport_version = 0;
799 		cpi->xport_specific.fc.wwnn = softc->wwnn;
800 		cpi->xport_specific.fc.wwpn = softc->wwpn;
801 		cpi->xport_specific.fc.port = softc->port.targ_port;
802 		cpi->xport_specific.fc.bitrate = 8 * 1000 * 1000;
803 		cpi->ccb_h.status = CAM_REQ_CMP;
804 		break;
805 	}
806 	default:
807 		ccb->ccb_h.status = CAM_PROVIDE_FAIL;
808 		printf("%s: unsupported CCB type %#x\n", __func__,
809 		       ccb->ccb_h.func_code);
810 		xpt_done(ccb);
811 		break;
812 	}
813 }
814