Path: blob/main/sys/cam/ctl/ctl_frontend_cam_sim.c
39478 views
/*-1* SPDX-License-Identifier: BSD-2-Clause2*3* Copyright (c) 2009 Silicon Graphics International Corp.4* All rights reserved.5*6* Redistribution and use in source and binary forms, with or without7* modification, are permitted provided that the following conditions8* are met:9* 1. Redistributions of source code must retain the above copyright10* notice, this list of conditions, and the following disclaimer,11* without modification.12* 2. Redistributions in binary form must reproduce at minimum a disclaimer13* substantially similar to the "NO WARRANTY" disclaimer below14* ("Disclaimer") and any redistribution must be conditioned upon15* including a substantially similar Disclaimer requirement for further16* binary redistribution.17*18* NO WARRANTY19* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS20* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT21* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR22* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT23* HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL24* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS25* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)26* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,27* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING28* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE29* POSSIBILITY OF SUCH DAMAGES.30*31* $Id: //depot/users/kenm/FreeBSD-test2/sys/cam/ctl/ctl_frontend_cam_sim.c#4 $32*/33/*34* CTL frontend to CAM SIM interface. This allows access to CTL LUNs via35* the da(4) and pass(4) drivers from inside the system.36*37* Author: Ken Merry <[email protected]>38*/3940#include <sys/param.h>41#include <sys/systm.h>42#include <sys/kernel.h>43#include <sys/types.h>44#include <sys/malloc.h>45#include <sys/bus.h>46#include <sys/sysctl.h>47#include <machine/atomic.h>48#include <machine/bus.h>49#include <sys/sbuf.h>5051#include <cam/cam.h>52#include <cam/cam_ccb.h>53#include <cam/cam_sim.h>54#include <cam/cam_xpt_sim.h>55#include <cam/cam_xpt.h>56#include <cam/cam_periph.h>57#include <cam/scsi/scsi_all.h>58#include <cam/scsi/scsi_message.h>59#include <cam/ctl/ctl_io.h>60#include <cam/ctl/ctl.h>61#include <cam/ctl/ctl_frontend.h>62#include <cam/ctl/ctl_debug.h>6364#define io_ptr spriv_ptr16566struct cfcs_io {67union ccb *ccb;68};6970struct cfcs_softc {71struct ctl_port port;72char port_name[32];73struct cam_sim *sim;74struct cam_devq *devq;75struct cam_path *path;76uint64_t wwnn;77uint64_t wwpn;78uint32_t cur_tag_num;79int online;80};8182/*83* We can't handle CCBs with these flags. For the most part, we just don't84* handle physical addresses yet. That would require mapping things in85* order to do the copy.86*/87#define CFCS_BAD_CCB_FLAGS (CAM_DATA_ISPHYS | CAM_CDB_PHYS | CAM_SENSE_PTR | \88CAM_SENSE_PHYS)8990static int cfcs_init(void);91static int cfcs_shutdown(void);92static void cfcs_poll(struct cam_sim *sim);93static void cfcs_online(void *arg);94static void cfcs_offline(void *arg);95static void cfcs_datamove(union ctl_io *io);96static void cfcs_done(union ctl_io *io);97void cfcs_action(struct cam_sim *sim, union ccb *ccb);9899struct cfcs_softc cfcs_softc;100/*101* This is primarily intended to allow for error injection to test the CAM102* sense data and sense residual handling code. This sets the maximum103* amount of SCSI sense data that we will report to CAM.104*/105static int cfcs_max_sense = sizeof(struct scsi_sense_data);106107SYSCTL_NODE(_kern_cam, OID_AUTO, ctl2cam, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,108"CAM Target Layer SIM frontend");109SYSCTL_INT(_kern_cam_ctl2cam, OID_AUTO, max_sense, CTLFLAG_RW,110&cfcs_max_sense, 0, "Maximum sense data size");111112static struct ctl_frontend cfcs_frontend =113{114.name = "camsim",115.init = cfcs_init,116.shutdown = cfcs_shutdown,117};118CTL_FRONTEND_DECLARE(ctlcfcs, cfcs_frontend);119120static int121cfcs_init(void)122{123struct cfcs_softc *softc;124struct ctl_port *port;125int retval;126127softc = &cfcs_softc;128bzero(softc, sizeof(*softc));129port = &softc->port;130131port->frontend = &cfcs_frontend;132port->port_type = CTL_PORT_INTERNAL;133/* XXX KDM what should the real number be here? */134port->num_requested_ctl_io = 4096;135snprintf(softc->port_name, sizeof(softc->port_name), "camsim");136port->port_name = softc->port_name;137port->port_online = cfcs_online;138port->port_offline = cfcs_offline;139port->onoff_arg = softc;140port->fe_datamove = cfcs_datamove;141port->fe_done = cfcs_done;142port->targ_port = -1;143144retval = ctl_port_register(port);145if (retval != 0) {146printf("%s: ctl_port_register() failed with error %d!\n",147__func__, retval);148return (retval);149}150151/*152* If the CTL frontend didn't tell us what our WWNN/WWPN is, go153* ahead and set something random.154*/155if (port->wwnn == 0) {156uint64_t random_bits;157158arc4rand(&random_bits, sizeof(random_bits), 0);159softc->wwnn = (random_bits & 0x0000000fffffff00ULL) |160/* Company ID */ 0x5000000000000000ULL |161/* NL-Port */ 0x0300;162softc->wwpn = softc->wwnn + port->targ_port + 1;163ctl_port_set_wwns(port, true, softc->wwnn, true, softc->wwpn);164} else {165softc->wwnn = port->wwnn;166softc->wwpn = port->wwpn;167}168169softc->devq = cam_simq_alloc(port->num_requested_ctl_io);170if (softc->devq == NULL) {171printf("%s: error allocating devq\n", __func__);172retval = ENOMEM;173goto bailout;174}175176softc->sim = cam_sim_alloc(cfcs_action, cfcs_poll, softc->port_name,177softc, /*unit*/ 0, NULL, 1,178port->num_requested_ctl_io, softc->devq);179if (softc->sim == NULL) {180printf("%s: error allocating SIM\n", __func__);181retval = ENOMEM;182goto bailout;183}184185if (xpt_bus_register(softc->sim, NULL, 0) != CAM_SUCCESS) {186printf("%s: error registering SIM\n", __func__);187retval = ENOMEM;188goto bailout;189}190191if (xpt_create_path(&softc->path, /*periph*/NULL,192cam_sim_path(softc->sim),193CAM_TARGET_WILDCARD,194CAM_LUN_WILDCARD) != CAM_REQ_CMP) {195printf("%s: error creating path\n", __func__);196xpt_bus_deregister(cam_sim_path(softc->sim));197retval = EINVAL;198goto bailout;199}200201return (retval);202203bailout:204if (softc->sim)205cam_sim_free(softc->sim, /*free_devq*/ TRUE);206else if (softc->devq)207cam_simq_free(softc->devq);208return (retval);209}210211static int212cfcs_shutdown(void)213{214struct cfcs_softc *softc = &cfcs_softc;215struct ctl_port *port = &softc->port;216int error;217218ctl_port_offline(port);219220xpt_free_path(softc->path);221xpt_bus_deregister(cam_sim_path(softc->sim));222cam_sim_free(softc->sim, /*free_devq*/ TRUE);223224if ((error = ctl_port_deregister(port)) != 0)225printf("%s: cam_sim port deregistration failed\n", __func__);226return (error);227}228229static void230cfcs_poll(struct cam_sim *sim)231{232233}234235static void236cfcs_onoffline(void *arg, int online)237{238struct cfcs_softc *softc = (struct cfcs_softc *)arg;239union ccb *ccb;240241softc->online = online;242243ccb = xpt_alloc_ccb_nowait();244if (ccb == NULL) {245printf("%s: unable to allocate CCB for rescan\n", __func__);246return;247}248249if (xpt_create_path(&ccb->ccb_h.path, NULL,250cam_sim_path(softc->sim), CAM_TARGET_WILDCARD,251CAM_LUN_WILDCARD) != CAM_REQ_CMP) {252printf("%s: can't allocate path for rescan\n", __func__);253xpt_free_ccb(ccb);254return;255}256xpt_rescan(ccb);257}258259static void260cfcs_online(void *arg)261{262cfcs_onoffline(arg, /*online*/ 1);263}264265static void266cfcs_offline(void *arg)267{268cfcs_onoffline(arg, /*online*/ 0);269}270271/*272* This function is very similar to ctl_ioctl_do_datamove(). Is there a273* way to combine the functionality?274*275* XXX KDM may need to move this into a thread. We're doing a bcopy in the276* caller's context, which will usually be the backend. That may not be a277* good thing.278*/279static void280cfcs_datamove(union ctl_io *io)281{282union ccb *ccb;283bus_dma_segment_t cam_sg_entry, *cam_sglist;284struct ctl_sg_entry ctl_sg_entry, *ctl_sglist;285int cam_sg_count, ctl_sg_count, cam_sg_start;286int cam_sg_offset;287int len_to_copy;288int ctl_watermark, cam_watermark;289int i, j;290291ccb = io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr;292293/*294* Note that we have a check in cfcs_action() to make sure that any295* CCBs with "bad" flags are returned with CAM_REQ_INVALID. This296* is just to make sure no one removes that check without updating297* this code to provide the additional functionality necessary to298* support those modes of operation.299*/300KASSERT(((ccb->ccb_h.flags & CFCS_BAD_CCB_FLAGS) == 0), ("invalid "301"CAM flags %#x", (ccb->ccb_h.flags & CFCS_BAD_CCB_FLAGS)));302303/*304* Simplify things on both sides by putting single buffers into a305* single entry S/G list.306*/307switch ((ccb->ccb_h.flags & CAM_DATA_MASK)) {308case CAM_DATA_SG: {309int len_seen;310311cam_sglist = (bus_dma_segment_t *)ccb->csio.data_ptr;312cam_sg_count = ccb->csio.sglist_cnt;313cam_sg_start = cam_sg_count;314cam_sg_offset = 0;315316for (i = 0, len_seen = 0; i < cam_sg_count; i++) {317if ((len_seen + cam_sglist[i].ds_len) >=318io->scsiio.kern_rel_offset) {319cam_sg_start = i;320cam_sg_offset = io->scsiio.kern_rel_offset -321len_seen;322break;323}324len_seen += cam_sglist[i].ds_len;325}326break;327}328case CAM_DATA_VADDR:329cam_sglist = &cam_sg_entry;330cam_sglist[0].ds_len = ccb->csio.dxfer_len;331cam_sglist[0].ds_addr = (bus_addr_t)(uintptr_t)ccb->csio.data_ptr;332cam_sg_count = 1;333cam_sg_start = 0;334cam_sg_offset = io->scsiio.kern_rel_offset;335break;336default:337panic("Invalid CAM flags %#x", ccb->ccb_h.flags);338}339340if (io->scsiio.kern_sg_entries > 0) {341ctl_sglist = (struct ctl_sg_entry *)io->scsiio.kern_data_ptr;342ctl_sg_count = io->scsiio.kern_sg_entries;343} else {344ctl_sglist = &ctl_sg_entry;345ctl_sglist->addr = io->scsiio.kern_data_ptr;346ctl_sglist->len = io->scsiio.kern_data_len;347ctl_sg_count = 1;348}349350ctl_watermark = 0;351cam_watermark = cam_sg_offset;352for (i = cam_sg_start, j = 0;353i < cam_sg_count && j < ctl_sg_count;) {354uint8_t *cam_ptr, *ctl_ptr;355356len_to_copy = MIN(cam_sglist[i].ds_len - cam_watermark,357ctl_sglist[j].len - ctl_watermark);358359cam_ptr = (uint8_t *)(uintptr_t)cam_sglist[i].ds_addr;360cam_ptr = cam_ptr + cam_watermark;361if (io->io_hdr.flags & CTL_FLAG_BUS_ADDR) {362/*363* XXX KDM fix this!364*/365panic("need to implement bus address support");366#if 0367kern_ptr = bus_to_virt(kern_sglist[j].addr);368#endif369} else370ctl_ptr = (uint8_t *)ctl_sglist[j].addr;371ctl_ptr = ctl_ptr + ctl_watermark;372373if ((io->io_hdr.flags & CTL_FLAG_DATA_MASK) ==374CTL_FLAG_DATA_IN) {375CTL_DEBUG_PRINT(("%s: copying %d bytes to CAM\n",376__func__, len_to_copy));377CTL_DEBUG_PRINT(("%s: from %p to %p\n", ctl_ptr,378__func__, cam_ptr));379bcopy(ctl_ptr, cam_ptr, len_to_copy);380} else {381CTL_DEBUG_PRINT(("%s: copying %d bytes from CAM\n",382__func__, len_to_copy));383CTL_DEBUG_PRINT(("%s: from %p to %p\n", cam_ptr,384__func__, ctl_ptr));385bcopy(cam_ptr, ctl_ptr, len_to_copy);386}387388io->scsiio.ext_data_filled += len_to_copy;389io->scsiio.kern_data_resid -= len_to_copy;390391cam_watermark += len_to_copy;392if (cam_sglist[i].ds_len == cam_watermark) {393i++;394cam_watermark = 0;395}396397ctl_watermark += len_to_copy;398if (ctl_sglist[j].len == ctl_watermark) {399j++;400ctl_watermark = 0;401}402}403404if ((io->io_hdr.status & CTL_STATUS_MASK) == CTL_SUCCESS) {405io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = NULL;406io->io_hdr.flags |= CTL_FLAG_STATUS_SENT;407ccb->csio.resid = ccb->csio.dxfer_len -408io->scsiio.ext_data_filled;409ccb->ccb_h.status &= ~CAM_STATUS_MASK;410ccb->ccb_h.status |= CAM_REQ_CMP;411xpt_done(ccb);412}413414ctl_datamove_done(io, true);415}416417static void418cfcs_done(union ctl_io *io)419{420union ccb *ccb;421422ccb = io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr;423if (ccb == NULL) {424ctl_free_io(io);425return;426}427428/*429* At this point we should have status. If we don't, that's a bug.430*/431KASSERT(((io->io_hdr.status & CTL_STATUS_MASK) != CTL_STATUS_NONE),432("invalid CTL status %#x", io->io_hdr.status));433434/*435* Translate CTL status to CAM status.436*/437if (ccb->ccb_h.func_code == XPT_SCSI_IO) {438ccb->csio.resid = ccb->csio.dxfer_len -439io->scsiio.ext_data_filled;440}441ccb->ccb_h.status &= ~CAM_STATUS_MASK;442switch (io->io_hdr.status & CTL_STATUS_MASK) {443case CTL_SUCCESS:444ccb->ccb_h.status |= CAM_REQ_CMP;445break;446case CTL_SCSI_ERROR:447ccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR | CAM_AUTOSNS_VALID;448ccb->csio.scsi_status = io->scsiio.scsi_status;449bcopy(&io->scsiio.sense_data, &ccb->csio.sense_data,450min(io->scsiio.sense_len, ccb->csio.sense_len));451if (ccb->csio.sense_len > io->scsiio.sense_len)452ccb->csio.sense_resid = ccb->csio.sense_len -453io->scsiio.sense_len;454else455ccb->csio.sense_resid = 0;456if ((ccb->csio.sense_len - ccb->csio.sense_resid) >457cfcs_max_sense) {458ccb->csio.sense_resid = ccb->csio.sense_len -459cfcs_max_sense;460}461break;462case CTL_CMD_ABORTED:463ccb->ccb_h.status |= CAM_REQ_ABORTED;464break;465case CTL_ERROR:466default:467ccb->ccb_h.status |= CAM_REQ_CMP_ERR;468break;469}470ctl_free_io(io);471if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP &&472(ccb->ccb_h.status & CAM_DEV_QFRZN) == 0) {473xpt_freeze_devq(ccb->ccb_h.path, 1);474ccb->ccb_h.status |= CAM_DEV_QFRZN;475}476xpt_done(ccb);477}478479void480cfcs_action(struct cam_sim *sim, union ccb *ccb)481{482struct cfcs_softc *softc;483int err;484485softc = (struct cfcs_softc *)cam_sim_softc(sim);486487switch (ccb->ccb_h.func_code) {488case XPT_SCSI_IO: {489union ctl_io *io;490struct ccb_scsiio *csio;491492csio = &ccb->csio;493494/*495* Catch CCB flags, like physical address flags, that496* indicate situations we currently can't handle.497*/498if (ccb->ccb_h.flags & CFCS_BAD_CCB_FLAGS) {499ccb->ccb_h.status = CAM_REQ_INVALID;500printf("%s: bad CCB flags %#x (all flags %#x)\n",501__func__, ccb->ccb_h.flags & CFCS_BAD_CCB_FLAGS,502ccb->ccb_h.flags);503xpt_done(ccb);504return;505}506507/*508* If we aren't online, there are no devices to see.509*/510if (softc->online == 0) {511ccb->ccb_h.status = CAM_DEV_NOT_THERE;512xpt_done(ccb);513return;514}515516io = ctl_alloc_io_nowait(softc->port.ctl_pool_ref);517if (io == NULL) {518printf("%s: can't allocate ctl_io\n", __func__);519ccb->ccb_h.status = CAM_BUSY | CAM_DEV_QFRZN;520xpt_freeze_devq(ccb->ccb_h.path, 1);521xpt_done(ccb);522return;523}524ctl_zero_io(io);525/* Save pointers on both sides */526io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = ccb;527ccb->ccb_h.io_ptr = io;528529/*530* Only SCSI I/O comes down this path, resets, etc. come531* down via the XPT_RESET_BUS/LUN CCBs below.532*/533io->io_hdr.io_type = CTL_IO_SCSI;534io->io_hdr.nexus.initid = 1;535io->io_hdr.nexus.targ_port = softc->port.targ_port;536io->io_hdr.nexus.targ_lun = ctl_decode_lun(537CAM_EXTLUN_BYTE_SWIZZLE(ccb->ccb_h.target_lun));538io->scsiio.priority = csio->priority;539/*540* This tag scheme isn't the best, since we could in theory541* have a very long-lived I/O and tag collision, especially542* in a high I/O environment. But it should work well543* enough for now. Since we're using unsigned ints,544* they'll just wrap around.545*/546io->scsiio.tag_num = atomic_fetchadd_32(&softc->cur_tag_num, 1);547csio->tag_id = io->scsiio.tag_num;548switch (csio->tag_action) {549case CAM_TAG_ACTION_NONE:550io->scsiio.tag_type = CTL_TAG_UNTAGGED;551break;552case MSG_SIMPLE_TASK:553io->scsiio.tag_type = CTL_TAG_SIMPLE;554break;555case MSG_HEAD_OF_QUEUE_TASK:556io->scsiio.tag_type = CTL_TAG_HEAD_OF_QUEUE;557break;558case MSG_ORDERED_TASK:559io->scsiio.tag_type = CTL_TAG_ORDERED;560break;561case MSG_ACA_TASK:562io->scsiio.tag_type = CTL_TAG_ACA;563break;564default:565io->scsiio.tag_type = CTL_TAG_UNTAGGED;566printf("%s: unhandled tag type %#x!!\n", __func__,567csio->tag_action);568break;569}570if (csio->cdb_len > sizeof(io->scsiio.cdb)) {571printf("%s: WARNING: CDB len %d > ctl_io space %zd\n",572__func__, csio->cdb_len, sizeof(io->scsiio.cdb));573}574io->scsiio.cdb_len = min(csio->cdb_len, sizeof(io->scsiio.cdb));575bcopy(scsiio_cdb_ptr(csio), io->scsiio.cdb, io->scsiio.cdb_len);576577ccb->ccb_h.status |= CAM_SIM_QUEUED;578err = ctl_queue(io);579if (err != CTL_RETVAL_COMPLETE) {580printf("%s: func %d: error %d returned by "581"ctl_queue()!\n", __func__,582ccb->ccb_h.func_code, err);583ctl_free_io(io);584ccb->ccb_h.status = CAM_REQ_INVALID;585xpt_done(ccb);586return;587}588break;589}590case XPT_ABORT: {591union ctl_io *io;592union ccb *abort_ccb;593594abort_ccb = ccb->cab.abort_ccb;595596if (abort_ccb->ccb_h.func_code != XPT_SCSI_IO) {597ccb->ccb_h.status = CAM_REQ_INVALID;598xpt_done(ccb);599}600601/*602* If we aren't online, there are no devices to talk to.603*/604if (softc->online == 0) {605ccb->ccb_h.status = CAM_DEV_NOT_THERE;606xpt_done(ccb);607return;608}609610io = ctl_alloc_io_nowait(softc->port.ctl_pool_ref);611if (io == NULL) {612ccb->ccb_h.status = CAM_BUSY | CAM_DEV_QFRZN;613xpt_freeze_devq(ccb->ccb_h.path, 1);614xpt_done(ccb);615return;616}617618ctl_zero_io(io);619/* Save pointers on both sides */620io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = ccb;621ccb->ccb_h.io_ptr = io;622623io->io_hdr.io_type = CTL_IO_TASK;624io->io_hdr.nexus.initid = 1;625io->io_hdr.nexus.targ_port = softc->port.targ_port;626io->io_hdr.nexus.targ_lun = ctl_decode_lun(627CAM_EXTLUN_BYTE_SWIZZLE(ccb->ccb_h.target_lun));628io->taskio.task_action = CTL_TASK_ABORT_TASK;629io->taskio.tag_num = abort_ccb->csio.tag_id;630switch (abort_ccb->csio.tag_action) {631case CAM_TAG_ACTION_NONE:632io->taskio.tag_type = CTL_TAG_UNTAGGED;633break;634case MSG_SIMPLE_TASK:635io->taskio.tag_type = CTL_TAG_SIMPLE;636break;637case MSG_HEAD_OF_QUEUE_TASK:638io->taskio.tag_type = CTL_TAG_HEAD_OF_QUEUE;639break;640case MSG_ORDERED_TASK:641io->taskio.tag_type = CTL_TAG_ORDERED;642break;643case MSG_ACA_TASK:644io->taskio.tag_type = CTL_TAG_ACA;645break;646default:647io->taskio.tag_type = CTL_TAG_UNTAGGED;648printf("%s: unhandled tag type %#x!!\n", __func__,649abort_ccb->csio.tag_action);650break;651}652err = ctl_queue(io);653if (err != CTL_RETVAL_COMPLETE) {654printf("%s func %d: error %d returned by "655"ctl_queue()!\n", __func__,656ccb->ccb_h.func_code, err);657ctl_free_io(io);658}659break;660}661case XPT_GET_TRAN_SETTINGS: {662struct ccb_trans_settings *cts;663struct ccb_trans_settings_scsi *scsi;664struct ccb_trans_settings_fc *fc;665666cts = &ccb->cts;667scsi = &cts->proto_specific.scsi;668fc = &cts->xport_specific.fc;669670671cts->protocol = PROTO_SCSI;672cts->protocol_version = SCSI_REV_SPC2;673cts->transport = XPORT_FC;674cts->transport_version = 0;675676scsi->valid = CTS_SCSI_VALID_TQ;677scsi->flags = CTS_SCSI_FLAGS_TAG_ENB;678fc->valid = CTS_FC_VALID_SPEED;679fc->bitrate = 800000;680fc->wwnn = softc->wwnn;681fc->wwpn = softc->wwpn;682fc->port = softc->port.targ_port;683fc->valid |= CTS_FC_VALID_WWNN | CTS_FC_VALID_WWPN |684CTS_FC_VALID_PORT;685ccb->ccb_h.status = CAM_REQ_CMP;686break;687}688case XPT_SET_TRAN_SETTINGS:689/* XXX KDM should we actually do something here? */690ccb->ccb_h.status = CAM_REQ_CMP;691break;692case XPT_RESET_BUS:693case XPT_RESET_DEV: {694union ctl_io *io;695696/*697* If we aren't online, there are no devices to talk to.698*/699if (softc->online == 0) {700ccb->ccb_h.status = CAM_DEV_NOT_THERE;701xpt_done(ccb);702return;703}704705io = ctl_alloc_io_nowait(softc->port.ctl_pool_ref);706if (io == NULL) {707ccb->ccb_h.status = CAM_BUSY | CAM_DEV_QFRZN;708xpt_freeze_devq(ccb->ccb_h.path, 1);709xpt_done(ccb);710return;711}712713ctl_zero_io(io);714/* Save pointers on both sides */715if (ccb->ccb_h.func_code == XPT_RESET_DEV)716io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = ccb;717ccb->ccb_h.io_ptr = io;718719io->io_hdr.io_type = CTL_IO_TASK;720io->io_hdr.nexus.initid = 1;721io->io_hdr.nexus.targ_port = softc->port.targ_port;722io->io_hdr.nexus.targ_lun = ctl_decode_lun(723CAM_EXTLUN_BYTE_SWIZZLE(ccb->ccb_h.target_lun));724if (ccb->ccb_h.func_code == XPT_RESET_BUS)725io->taskio.task_action = CTL_TASK_BUS_RESET;726else727io->taskio.task_action = CTL_TASK_LUN_RESET;728729err = ctl_queue(io);730if (err != CTL_RETVAL_COMPLETE) {731printf("%s func %d: error %d returned by "732"ctl_queue()!\n", __func__,733ccb->ccb_h.func_code, err);734ctl_free_io(io);735}736break;737}738case XPT_CALC_GEOMETRY:739cam_calc_geometry(&ccb->ccg, 1);740xpt_done(ccb);741break;742case XPT_PATH_INQ: {743struct ccb_pathinq *cpi;744745cpi = &ccb->cpi;746747cpi->version_num = 0;748cpi->hba_inquiry = PI_TAG_ABLE;749cpi->target_sprt = 0;750cpi->hba_misc = PIM_EXTLUNS;751cpi->hba_eng_cnt = 0;752cpi->max_target = 0;753cpi->max_lun = 1024;754/* Do we really have a limit? */755cpi->maxio = 1024 * 1024;756cpi->async_flags = 0;757cpi->hpath_id = 0;758cpi->initiator_id = 1;759760strlcpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);761strlcpy(cpi->hba_vid, "FreeBSD", HBA_IDLEN);762strlcpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);763cpi->unit_number = 0;764cpi->bus_id = 0;765cpi->base_transfer_speed = 800000;766cpi->protocol = PROTO_SCSI;767cpi->protocol_version = SCSI_REV_SPC2;768/*769* Pretend to be Fibre Channel.770*/771cpi->transport = XPORT_FC;772cpi->transport_version = 0;773cpi->xport_specific.fc.wwnn = softc->wwnn;774cpi->xport_specific.fc.wwpn = softc->wwpn;775cpi->xport_specific.fc.port = softc->port.targ_port;776cpi->xport_specific.fc.bitrate = 8 * 1000 * 1000;777cpi->ccb_h.status = CAM_REQ_CMP;778break;779}780default:781ccb->ccb_h.status = CAM_PROVIDE_FAIL;782printf("%s: unsupported CCB type %#x\n", __func__,783ccb->ccb_h.func_code);784xpt_done(ccb);785break;786}787}788789790