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