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