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