1229997Sken/*- 2229997Sken * Copyright (c) 2009 Silicon Graphics International Corp. 3229997Sken * All rights reserved. 4229997Sken * 5229997Sken * Redistribution and use in source and binary forms, with or without 6229997Sken * modification, are permitted provided that the following conditions 7229997Sken * are met: 8229997Sken * 1. Redistributions of source code must retain the above copyright 9229997Sken * notice, this list of conditions, and the following disclaimer, 10229997Sken * without modification. 11229997Sken * 2. Redistributions in binary form must reproduce at minimum a disclaimer 12229997Sken * substantially similar to the "NO WARRANTY" disclaimer below 13229997Sken * ("Disclaimer") and any redistribution must be conditioned upon 14229997Sken * including a substantially similar Disclaimer requirement for further 15229997Sken * binary redistribution. 16229997Sken * 17229997Sken * NO WARRANTY 18229997Sken * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19229997Sken * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20229997Sken * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 21229997Sken * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22229997Sken * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23229997Sken * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24229997Sken * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25229997Sken * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 26229997Sken * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 27229997Sken * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28229997Sken * POSSIBILITY OF SUCH DAMAGES. 29229997Sken * 30229997Sken * $Id: //depot/users/kenm/FreeBSD-test2/sys/cam/ctl/ctl_frontend_cam_sim.c#4 $ 31229997Sken */ 32229997Sken/* 33229997Sken * CTL frontend to CAM SIM interface. This allows access to CTL LUNs via 34229997Sken * the da(4) and pass(4) drivers from inside the system. 35229997Sken * 36229997Sken * Author: Ken Merry <ken@FreeBSD.org> 37229997Sken */ 38229997Sken 39229997Sken#include <sys/cdefs.h> 40229997Sken__FBSDID("$FreeBSD$"); 41229997Sken 42229997Sken#include <sys/param.h> 43229997Sken#include <sys/systm.h> 44229997Sken#include <sys/kernel.h> 45229997Sken#include <sys/types.h> 46229997Sken#include <sys/malloc.h> 47229997Sken#include <sys/lock.h> 48229997Sken#include <sys/mutex.h> 49229997Sken#include <sys/condvar.h> 50229997Sken#include <sys/queue.h> 51229997Sken#include <sys/bus.h> 52229997Sken#include <sys/sysctl.h> 53229997Sken#include <machine/bus.h> 54229997Sken#include <sys/sbuf.h> 55229997Sken 56229997Sken#include <cam/cam.h> 57229997Sken#include <cam/cam_ccb.h> 58229997Sken#include <cam/cam_sim.h> 59229997Sken#include <cam/cam_xpt_sim.h> 60229997Sken#include <cam/cam_xpt.h> 61229997Sken#include <cam/cam_periph.h> 62229997Sken#include <cam/scsi/scsi_all.h> 63229997Sken#include <cam/scsi/scsi_message.h> 64229997Sken#include <cam/ctl/ctl_io.h> 65229997Sken#include <cam/ctl/ctl.h> 66229997Sken#include <cam/ctl/ctl_frontend.h> 67229997Sken#include <cam/ctl/ctl_frontend_internal.h> 68229997Sken#include <cam/ctl/ctl_debug.h> 69229997Sken 70229997Sken#define io_ptr spriv_ptr1 71229997Sken 72229997Skenstruct cfcs_io { 73229997Sken union ccb *ccb; 74229997Sken}; 75229997Sken 76229997Skenstruct cfcs_softc { 77229997Sken struct ctl_frontend fe; 78229997Sken char port_name[32]; 79229997Sken struct cam_sim *sim; 80229997Sken struct cam_devq *devq; 81229997Sken struct cam_path *path; 82229997Sken struct mtx lock; 83229997Sken char lock_desc[32]; 84229997Sken uint64_t wwnn; 85229997Sken uint64_t wwpn; 86229997Sken uint32_t cur_tag_num; 87229997Sken int online; 88229997Sken}; 89229997Sken 90229997Sken/* 91229997Sken * We can't handle CCBs with these flags. For the most part, we just don't 92229997Sken * handle physical addresses yet. That would require mapping things in 93229997Sken * order to do the copy. 94229997Sken */ 95251874Sscottl#define CFCS_BAD_CCB_FLAGS (CAM_DATA_ISPHYS | CAM_MSG_BUF_PHYS | \ 96251874Sscottl CAM_SNS_BUF_PHYS | CAM_CDB_PHYS | CAM_SENSE_PTR | \ 97229997Sken CAM_SENSE_PHYS) 98229997Sken 99229997Skenint cfcs_init(void); 100229997Skenvoid cfcs_shutdown(void); 101229997Skenstatic void cfcs_poll(struct cam_sim *sim); 102229997Skenstatic void cfcs_online(void *arg); 103229997Skenstatic void cfcs_offline(void *arg); 104229997Skenstatic int cfcs_targ_enable(void *arg, struct ctl_id targ_id); 105229997Skenstatic int cfcs_targ_disable(void *arg, struct ctl_id targ_id); 106229997Skenstatic int cfcs_lun_enable(void *arg, struct ctl_id target_id, int lun_id); 107229997Skenstatic int cfcs_lun_disable(void *arg, struct ctl_id target_id, int lun_id); 108229997Skenstatic void cfcs_datamove(union ctl_io *io); 109229997Skenstatic void cfcs_done(union ctl_io *io); 110229997Skenvoid cfcs_action(struct cam_sim *sim, union ccb *ccb); 111229997Skenstatic void cfcs_async(void *callback_arg, uint32_t code, 112229997Sken struct cam_path *path, void *arg); 113229997Sken 114229997Skenstruct cfcs_softc cfcs_softc; 115229997Sken/* 116229997Sken * This is primarly intended to allow for error injection to test the CAM 117229997Sken * sense data and sense residual handling code. This sets the maximum 118229997Sken * amount of SCSI sense data that we will report to CAM. 119229997Sken */ 120229997Skenstatic int cfcs_max_sense = sizeof(struct scsi_sense_data); 121237941Skenextern int ctl_disable; 122229997Sken 123229997SkenSYSCTL_NODE(_kern_cam, OID_AUTO, ctl2cam, CTLFLAG_RD, 0, 124229997Sken "CAM Target Layer SIM frontend"); 125229997SkenSYSCTL_INT(_kern_cam_ctl2cam, OID_AUTO, max_sense, CTLFLAG_RW, 126229997Sken &cfcs_max_sense, 0, "Maximum sense data size"); 127229997Sken 128249510Straszstatic int cfcs_module_event_handler(module_t, int /*modeventtype_t*/, void *); 129229997Sken 130249510Straszstatic moduledata_t cfcs_moduledata = { 131249510Strasz "ctlcfcs", 132249510Strasz cfcs_module_event_handler, 133249510Strasz NULL 134249510Strasz}; 135249510Strasz 136249510StraszDECLARE_MODULE(ctlcfcs, cfcs_moduledata, SI_SUB_CONFIGURE, SI_ORDER_FOURTH); 137249510StraszMODULE_VERSION(ctlcfcs, 1); 138249510StraszMODULE_DEPEND(ctlcfi, ctl, 1, 1, 1); 139249510StraszMODULE_DEPEND(ctlcfi, cam, 1, 1, 1); 140249510Strasz 141229997Skenint 142229997Skencfcs_init(void) 143229997Sken{ 144229997Sken struct cfcs_softc *softc; 145229997Sken struct ccb_setasync csa; 146229997Sken struct ctl_frontend *fe; 147229997Sken#ifdef NEEDTOPORT 148229997Sken char wwnn[8]; 149229997Sken#endif 150229997Sken int retval; 151229997Sken 152237941Sken /* Don't continue if CTL is disabled */ 153237941Sken if (ctl_disable != 0) 154237941Sken return (0); 155237941Sken 156229997Sken softc = &cfcs_softc; 157229997Sken retval = 0; 158229997Sken bzero(softc, sizeof(*softc)); 159229997Sken sprintf(softc->lock_desc, "ctl2cam"); 160229997Sken mtx_init(&softc->lock, softc->lock_desc, NULL, MTX_DEF); 161229997Sken fe = &softc->fe; 162229997Sken 163229997Sken fe->port_type = CTL_PORT_INTERNAL; 164229997Sken /* XXX KDM what should the real number be here? */ 165229997Sken fe->num_requested_ctl_io = 4096; 166229997Sken snprintf(softc->port_name, sizeof(softc->port_name), "ctl2cam"); 167229997Sken fe->port_name = softc->port_name; 168229997Sken fe->port_online = cfcs_online; 169229997Sken fe->port_offline = cfcs_offline; 170229997Sken fe->onoff_arg = softc; 171229997Sken fe->targ_enable = cfcs_targ_enable; 172229997Sken fe->targ_disable = cfcs_targ_disable; 173229997Sken fe->lun_enable = cfcs_lun_enable; 174229997Sken fe->lun_disable = cfcs_lun_disable; 175229997Sken fe->targ_lun_arg = softc; 176229997Sken fe->fe_datamove = cfcs_datamove; 177229997Sken fe->fe_done = cfcs_done; 178229997Sken 179229997Sken /* XXX KDM what should we report here? */ 180229997Sken /* XXX These should probably be fetched from CTL. */ 181229997Sken fe->max_targets = 1; 182229997Sken fe->max_target_id = 15; 183229997Sken 184229997Sken retval = ctl_frontend_register(fe, /*master_SC*/ 1); 185229997Sken if (retval != 0) { 186229997Sken printf("%s: ctl_frontend_register() failed with error %d!\n", 187229997Sken __func__, retval); 188241945Smav mtx_destroy(&softc->lock); 189249510Strasz return (retval); 190229997Sken } 191229997Sken 192229997Sken /* 193229997Sken * Get the WWNN out of the database, and create a WWPN as well. 194229997Sken */ 195229997Sken#ifdef NEEDTOPORT 196229997Sken ddb_GetWWNN((char *)wwnn); 197229997Sken softc->wwnn = be64dec(wwnn); 198229997Sken softc->wwpn = softc->wwnn + (softc->fe.targ_port & 0xff); 199229997Sken#endif 200229997Sken 201229997Sken /* 202229997Sken * If the CTL frontend didn't tell us what our WWNN/WWPN is, go 203229997Sken * ahead and set something random. 204229997Sken */ 205229997Sken if (fe->wwnn == 0) { 206229997Sken uint64_t random_bits; 207229997Sken 208229997Sken arc4rand(&random_bits, sizeof(random_bits), 0); 209229997Sken softc->wwnn = (random_bits & 0x0000000fffffff00ULL) | 210229997Sken /* Company ID */ 0x5000000000000000ULL | 211229997Sken /* NL-Port */ 0x0300; 212229997Sken softc->wwpn = softc->wwnn + fe->targ_port + 1; 213229997Sken fe->wwnn = softc->wwnn; 214229997Sken fe->wwpn = softc->wwpn; 215229997Sken } else { 216229997Sken softc->wwnn = fe->wwnn; 217229997Sken softc->wwpn = fe->wwpn; 218229997Sken } 219229997Sken 220241945Smav mtx_lock(&softc->lock); 221229997Sken softc->devq = cam_simq_alloc(fe->num_requested_ctl_io); 222229997Sken if (softc->devq == NULL) { 223229997Sken printf("%s: error allocating devq\n", __func__); 224229997Sken retval = ENOMEM; 225229997Sken goto bailout; 226229997Sken } 227229997Sken 228229997Sken softc->sim = cam_sim_alloc(cfcs_action, cfcs_poll, softc->port_name, 229229997Sken softc, /*unit*/ 0, &softc->lock, 1, 230229997Sken fe->num_requested_ctl_io, softc->devq); 231229997Sken if (softc->sim == NULL) { 232229997Sken printf("%s: error allocating SIM\n", __func__); 233229997Sken retval = ENOMEM; 234229997Sken goto bailout; 235229997Sken } 236229997Sken 237229997Sken if (xpt_bus_register(softc->sim, NULL, 0) != CAM_SUCCESS) { 238229997Sken printf("%s: error registering SIM\n", __func__); 239229997Sken retval = ENOMEM; 240229997Sken goto bailout; 241229997Sken } 242229997Sken 243229997Sken if (xpt_create_path(&softc->path, /*periph*/NULL, 244229997Sken cam_sim_path(softc->sim), 245229997Sken CAM_TARGET_WILDCARD, 246229997Sken CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 247229997Sken printf("%s: error creating path\n", __func__); 248229997Sken xpt_bus_deregister(cam_sim_path(softc->sim)); 249249510Strasz retval = EINVAL; 250229997Sken goto bailout; 251229997Sken } 252229997Sken 253246429Smav xpt_setup_ccb(&csa.ccb_h, softc->path, CAM_PRIORITY_NONE); 254229997Sken csa.ccb_h.func_code = XPT_SASYNC_CB; 255229997Sken csa.event_enable = AC_LOST_DEVICE; 256229997Sken csa.callback = cfcs_async; 257229997Sken csa.callback_arg = softc->sim; 258229997Sken xpt_action((union ccb *)&csa); 259229997Sken 260241945Smav mtx_unlock(&softc->lock); 261241945Smav 262229997Sken return (retval); 263229997Sken 264229997Skenbailout: 265229997Sken if (softc->sim) 266229997Sken cam_sim_free(softc->sim, /*free_devq*/ TRUE); 267229997Sken else if (softc->devq) 268229997Sken cam_simq_free(softc->devq); 269241945Smav mtx_unlock(&softc->lock); 270241945Smav mtx_destroy(&softc->lock); 271229997Sken 272229997Sken return (retval); 273229997Sken} 274229997Sken 275229997Skenstatic void 276229997Skencfcs_poll(struct cam_sim *sim) 277229997Sken{ 278229997Sken 279229997Sken} 280229997Sken 281229997Skenvoid 282229997Skencfcs_shutdown(void) 283229997Sken{ 284229997Sken 285229997Sken} 286229997Sken 287249510Straszstatic int 288249510Straszcfcs_module_event_handler(module_t mod, int what, void *arg) 289249510Strasz{ 290249510Strasz 291249510Strasz switch (what) { 292249510Strasz case MOD_LOAD: 293249510Strasz return (cfcs_init()); 294249510Strasz case MOD_UNLOAD: 295249510Strasz return (EBUSY); 296249510Strasz default: 297249510Strasz return (EOPNOTSUPP); 298249510Strasz } 299249510Strasz} 300249510Strasz 301229997Skenstatic void 302249167Skencfcs_onoffline(void *arg, int online) 303229997Sken{ 304229997Sken struct cfcs_softc *softc; 305229997Sken union ccb *ccb; 306229997Sken 307229997Sken softc = (struct cfcs_softc *)arg; 308229997Sken 309229997Sken mtx_lock(&softc->lock); 310249167Sken softc->online = online; 311229997Sken 312229997Sken ccb = xpt_alloc_ccb_nowait(); 313229997Sken if (ccb == NULL) { 314229997Sken printf("%s: unable to allocate CCB for rescan\n", __func__); 315249167Sken goto bailout; 316229997Sken } 317229997Sken 318253037Smav if (xpt_create_path(&ccb->ccb_h.path, NULL, 319229997Sken cam_sim_path(softc->sim), CAM_TARGET_WILDCARD, 320229997Sken CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 321229997Sken printf("%s: can't allocate path for rescan\n", __func__); 322229997Sken xpt_free_ccb(ccb); 323249167Sken goto bailout; 324229997Sken } 325229997Sken xpt_rescan(ccb); 326249167Sken 327249167Skenbailout: 328249167Sken mtx_unlock(&softc->lock); 329229997Sken} 330229997Sken 331229997Skenstatic void 332249167Skencfcs_online(void *arg) 333249167Sken{ 334249167Sken cfcs_onoffline(arg, /*online*/ 1); 335249167Sken} 336249167Sken 337249167Skenstatic void 338229997Skencfcs_offline(void *arg) 339229997Sken{ 340249167Sken cfcs_onoffline(arg, /*online*/ 0); 341229997Sken} 342229997Sken 343229997Skenstatic int 344229997Skencfcs_targ_enable(void *arg, struct ctl_id targ_id) 345229997Sken{ 346229997Sken return (0); 347229997Sken} 348229997Sken 349229997Skenstatic int 350229997Skencfcs_targ_disable(void *arg, struct ctl_id targ_id) 351229997Sken{ 352229997Sken return (0); 353229997Sken} 354229997Sken 355229997Skenstatic int 356229997Skencfcs_lun_enable(void *arg, struct ctl_id target_id, int lun_id) 357229997Sken{ 358229997Sken return (0); 359229997Sken} 360229997Skenstatic int 361229997Skencfcs_lun_disable(void *arg, struct ctl_id target_id, int lun_id) 362229997Sken{ 363229997Sken return (0); 364229997Sken} 365229997Sken 366229997Sken/* 367229997Sken * This function is very similar to ctl_ioctl_do_datamove(). Is there a 368229997Sken * way to combine the functionality? 369229997Sken * 370229997Sken * XXX KDM may need to move this into a thread. We're doing a bcopy in the 371229997Sken * caller's context, which will usually be the backend. That may not be a 372229997Sken * good thing. 373229997Sken */ 374229997Skenstatic void 375229997Skencfcs_datamove(union ctl_io *io) 376229997Sken{ 377229997Sken union ccb *ccb; 378229997Sken bus_dma_segment_t cam_sg_entry, *cam_sglist; 379229997Sken struct ctl_sg_entry ctl_sg_entry, *ctl_sglist; 380229997Sken int cam_sg_count, ctl_sg_count, cam_sg_start; 381229997Sken int cam_sg_offset; 382229997Sken int len_to_copy, len_copied; 383229997Sken int ctl_watermark, cam_watermark; 384229997Sken int i, j; 385229997Sken 386229997Sken 387229997Sken cam_sg_offset = 0; 388229997Sken cam_sg_start = 0; 389229997Sken 390229997Sken ccb = io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr; 391229997Sken 392229997Sken /* 393229997Sken * Note that we have a check in cfcs_action() to make sure that any 394229997Sken * CCBs with "bad" flags are returned with CAM_REQ_INVALID. This 395229997Sken * is just to make sure no one removes that check without updating 396229997Sken * this code to provide the additional functionality necessary to 397229997Sken * support those modes of operation. 398229997Sken */ 399229997Sken KASSERT(((ccb->ccb_h.flags & CFCS_BAD_CCB_FLAGS) == 0), ("invalid " 400229997Sken "CAM flags %#x", (ccb->ccb_h.flags & CFCS_BAD_CCB_FLAGS))); 401229997Sken 402229997Sken /* 403229997Sken * Simplify things on both sides by putting single buffers into a 404229997Sken * single entry S/G list. 405229997Sken */ 406251874Sscottl switch ((ccb->ccb_h.flags & CAM_DATA_MASK)) { 407251874Sscottl case CAM_DATA_SG: { 408251874Sscottl int len_seen; 409229997Sken 410251874Sscottl cam_sglist = (bus_dma_segment_t *)ccb->csio.data_ptr; 411251874Sscottl cam_sg_count = ccb->csio.sglist_cnt; 412229997Sken 413251874Sscottl for (i = 0, len_seen = 0; i < cam_sg_count; i++) { 414251874Sscottl if ((len_seen + cam_sglist[i].ds_len) >= 415251874Sscottl io->scsiio.kern_rel_offset) { 416251874Sscottl cam_sg_start = i; 417251874Sscottl cam_sg_offset = io->scsiio.kern_rel_offset - 418251874Sscottl len_seen; 419251874Sscottl break; 420229997Sken } 421251874Sscottl len_seen += cam_sglist[i].ds_len; 422229997Sken } 423251874Sscottl break; 424251874Sscottl } 425251874Sscottl case CAM_DATA_VADDR: 426229997Sken cam_sglist = &cam_sg_entry; 427229997Sken cam_sglist[0].ds_len = ccb->csio.dxfer_len; 428229997Sken cam_sglist[0].ds_addr = (bus_addr_t)ccb->csio.data_ptr; 429229997Sken cam_sg_count = 1; 430229997Sken cam_sg_start = 0; 431229997Sken cam_sg_offset = io->scsiio.kern_rel_offset; 432251874Sscottl break; 433251874Sscottl default: 434251874Sscottl panic("Invalid CAM flags %#x", ccb->ccb_h.flags); 435229997Sken } 436229997Sken 437229997Sken if (io->scsiio.kern_sg_entries > 0) { 438229997Sken ctl_sglist = (struct ctl_sg_entry *)io->scsiio.kern_data_ptr; 439229997Sken ctl_sg_count = io->scsiio.kern_sg_entries; 440229997Sken } else { 441229997Sken ctl_sglist = &ctl_sg_entry; 442229997Sken ctl_sglist->addr = io->scsiio.kern_data_ptr; 443229997Sken ctl_sglist->len = io->scsiio.kern_data_len; 444229997Sken ctl_sg_count = 1; 445229997Sken } 446229997Sken 447229997Sken ctl_watermark = 0; 448229997Sken cam_watermark = cam_sg_offset; 449229997Sken len_copied = 0; 450229997Sken for (i = cam_sg_start, j = 0; 451229997Sken i < cam_sg_count && j < ctl_sg_count;) { 452229997Sken uint8_t *cam_ptr, *ctl_ptr; 453229997Sken 454229997Sken len_to_copy = ctl_min(cam_sglist[i].ds_len - cam_watermark, 455229997Sken ctl_sglist[j].len - ctl_watermark); 456229997Sken 457229997Sken cam_ptr = (uint8_t *)cam_sglist[i].ds_addr; 458229997Sken cam_ptr = cam_ptr + cam_watermark; 459229997Sken if (io->io_hdr.flags & CTL_FLAG_BUS_ADDR) { 460229997Sken /* 461229997Sken * XXX KDM fix this! 462229997Sken */ 463229997Sken panic("need to implement bus address support"); 464229997Sken#if 0 465229997Sken kern_ptr = bus_to_virt(kern_sglist[j].addr); 466229997Sken#endif 467229997Sken } else 468229997Sken ctl_ptr = (uint8_t *)ctl_sglist[j].addr; 469229997Sken ctl_ptr = ctl_ptr + ctl_watermark; 470229997Sken 471229997Sken ctl_watermark += len_to_copy; 472229997Sken cam_watermark += len_to_copy; 473229997Sken 474229997Sken if ((io->io_hdr.flags & CTL_FLAG_DATA_MASK) == 475229997Sken CTL_FLAG_DATA_IN) { 476229997Sken CTL_DEBUG_PRINT(("%s: copying %d bytes to CAM\n", 477229997Sken __func__, len_to_copy)); 478229997Sken CTL_DEBUG_PRINT(("%s: from %p to %p\n", ctl_ptr, 479229997Sken __func__, cam_ptr)); 480229997Sken bcopy(ctl_ptr, cam_ptr, len_to_copy); 481229997Sken } else { 482229997Sken CTL_DEBUG_PRINT(("%s: copying %d bytes from CAM\n", 483229997Sken __func__, len_to_copy)); 484229997Sken CTL_DEBUG_PRINT(("%s: from %p to %p\n", cam_ptr, 485229997Sken __func__, ctl_ptr)); 486229997Sken bcopy(cam_ptr, ctl_ptr, len_to_copy); 487229997Sken } 488229997Sken 489229997Sken len_copied += len_to_copy; 490229997Sken 491229997Sken if (cam_sglist[i].ds_len == cam_watermark) { 492229997Sken i++; 493229997Sken cam_watermark = 0; 494229997Sken } 495229997Sken 496229997Sken if (ctl_sglist[j].len == ctl_watermark) { 497229997Sken j++; 498229997Sken ctl_watermark = 0; 499229997Sken } 500229997Sken } 501229997Sken 502229997Sken io->scsiio.ext_data_filled += len_copied; 503229997Sken 504229997Sken io->scsiio.be_move_done(io); 505229997Sken} 506229997Sken 507229997Skenstatic void 508229997Skencfcs_done(union ctl_io *io) 509229997Sken{ 510229997Sken union ccb *ccb; 511229997Sken struct cfcs_softc *softc; 512229997Sken struct cam_sim *sim; 513229997Sken 514229997Sken ccb = io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr; 515229997Sken 516229997Sken sim = xpt_path_sim(ccb->ccb_h.path); 517229997Sken softc = (struct cfcs_softc *)cam_sim_softc(sim); 518229997Sken 519229997Sken /* 520229997Sken * At this point we should have status. If we don't, that's a bug. 521229997Sken */ 522229997Sken KASSERT(((io->io_hdr.status & CTL_STATUS_MASK) != CTL_STATUS_NONE), 523229997Sken ("invalid CTL status %#x", io->io_hdr.status)); 524229997Sken 525229997Sken /* 526229997Sken * Translate CTL status to CAM status. 527229997Sken */ 528229997Sken switch (io->io_hdr.status & CTL_STATUS_MASK) { 529229997Sken case CTL_SUCCESS: 530229997Sken ccb->ccb_h.status = CAM_REQ_CMP; 531229997Sken break; 532229997Sken case CTL_SCSI_ERROR: 533229997Sken ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR | CAM_AUTOSNS_VALID; 534229997Sken ccb->csio.scsi_status = io->scsiio.scsi_status; 535229997Sken bcopy(&io->scsiio.sense_data, &ccb->csio.sense_data, 536229997Sken min(io->scsiio.sense_len, ccb->csio.sense_len)); 537229997Sken if (ccb->csio.sense_len > io->scsiio.sense_len) 538229997Sken ccb->csio.sense_resid = ccb->csio.sense_len - 539229997Sken io->scsiio.sense_len; 540229997Sken else 541229997Sken ccb->csio.sense_resid = 0; 542229997Sken if ((ccb->csio.sense_len - ccb->csio.sense_resid) > 543229997Sken cfcs_max_sense) { 544229997Sken ccb->csio.sense_resid = ccb->csio.sense_len - 545229997Sken cfcs_max_sense; 546229997Sken } 547229997Sken break; 548229997Sken case CTL_CMD_ABORTED: 549229997Sken ccb->ccb_h.status = CAM_REQ_ABORTED; 550229997Sken break; 551229997Sken case CTL_ERROR: 552229997Sken default: 553229997Sken ccb->ccb_h.status = CAM_REQ_CMP_ERR; 554229997Sken break; 555229997Sken } 556229997Sken 557229997Sken mtx_lock(sim->mtx); 558229997Sken xpt_done(ccb); 559229997Sken mtx_unlock(sim->mtx); 560229997Sken 561229997Sken ctl_free_io(io); 562229997Sken} 563229997Sken 564229997Skenvoid 565229997Skencfcs_action(struct cam_sim *sim, union ccb *ccb) 566229997Sken{ 567229997Sken struct cfcs_softc *softc; 568229997Sken int err; 569229997Sken 570229997Sken softc = (struct cfcs_softc *)cam_sim_softc(sim); 571229997Sken mtx_assert(&softc->lock, MA_OWNED); 572229997Sken 573229997Sken switch (ccb->ccb_h.func_code) { 574229997Sken case XPT_SCSI_IO: { 575229997Sken union ctl_io *io; 576229997Sken struct ccb_scsiio *csio; 577229997Sken 578229997Sken csio = &ccb->csio; 579229997Sken 580229997Sken /* 581229997Sken * Catch CCB flags, like physical address flags, that 582229997Sken * indicate situations we currently can't handle. 583229997Sken */ 584229997Sken if (ccb->ccb_h.flags & CFCS_BAD_CCB_FLAGS) { 585229997Sken ccb->ccb_h.status = CAM_REQ_INVALID; 586229997Sken printf("%s: bad CCB flags %#x (all flags %#x)\n", 587229997Sken __func__, ccb->ccb_h.flags & CFCS_BAD_CCB_FLAGS, 588229997Sken ccb->ccb_h.flags); 589229997Sken xpt_done(ccb); 590229997Sken return; 591229997Sken } 592229997Sken 593229997Sken /* 594229997Sken * If we aren't online, there are no devices to see. 595229997Sken */ 596229997Sken if (softc->online == 0) { 597229997Sken ccb->ccb_h.status = CAM_DEV_NOT_THERE; 598229997Sken xpt_done(ccb); 599229997Sken return; 600229997Sken } 601229997Sken 602229997Sken io = ctl_alloc_io(softc->fe.ctl_pool_ref); 603229997Sken if (io == NULL) { 604229997Sken printf("%s: can't allocate ctl_io\n", __func__); 605229997Sken ccb->ccb_h.status = CAM_BUSY | CAM_DEV_QFRZN; 606229997Sken xpt_freeze_devq(ccb->ccb_h.path, 1); 607229997Sken xpt_done(ccb); 608229997Sken return; 609229997Sken } 610229997Sken ctl_zero_io(io); 611229997Sken /* Save pointers on both sides */ 612229997Sken io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = ccb; 613229997Sken ccb->ccb_h.io_ptr = io; 614229997Sken 615229997Sken /* 616229997Sken * Only SCSI I/O comes down this path, resets, etc. come 617229997Sken * down via the XPT_RESET_BUS/LUN CCBs below. 618229997Sken */ 619229997Sken io->io_hdr.io_type = CTL_IO_SCSI; 620229997Sken io->io_hdr.nexus.initid.id = 1; 621229997Sken io->io_hdr.nexus.targ_port = softc->fe.targ_port; 622229997Sken /* 623229997Sken * XXX KDM how do we handle target IDs? 624229997Sken */ 625229997Sken io->io_hdr.nexus.targ_target.id = ccb->ccb_h.target_id; 626229997Sken io->io_hdr.nexus.targ_lun = ccb->ccb_h.target_lun; 627229997Sken /* 628229997Sken * This tag scheme isn't the best, since we could in theory 629229997Sken * have a very long-lived I/O and tag collision, especially 630229997Sken * in a high I/O environment. But it should work well 631229997Sken * enough for now. Since we're using unsigned ints, 632229997Sken * they'll just wrap around. 633229997Sken */ 634229997Sken io->scsiio.tag_num = softc->cur_tag_num++; 635229997Sken csio->tag_id = io->scsiio.tag_num; 636229997Sken switch (csio->tag_action) { 637229997Sken case CAM_TAG_ACTION_NONE: 638229997Sken io->scsiio.tag_type = CTL_TAG_UNTAGGED; 639229997Sken break; 640229997Sken case MSG_SIMPLE_TASK: 641229997Sken io->scsiio.tag_type = CTL_TAG_SIMPLE; 642229997Sken break; 643229997Sken case MSG_HEAD_OF_QUEUE_TASK: 644229997Sken io->scsiio.tag_type = CTL_TAG_HEAD_OF_QUEUE; 645229997Sken break; 646229997Sken case MSG_ORDERED_TASK: 647229997Sken io->scsiio.tag_type = CTL_TAG_ORDERED; 648229997Sken break; 649229997Sken case MSG_ACA_TASK: 650229997Sken io->scsiio.tag_type = CTL_TAG_ACA; 651229997Sken break; 652229997Sken default: 653229997Sken io->scsiio.tag_type = CTL_TAG_UNTAGGED; 654229997Sken printf("%s: unhandled tag type %#x!!\n", __func__, 655229997Sken csio->tag_action); 656229997Sken break; 657229997Sken } 658229997Sken if (csio->cdb_len > sizeof(io->scsiio.cdb)) { 659229997Sken printf("%s: WARNING: CDB len %d > ctl_io space %zd\n", 660229997Sken __func__, csio->cdb_len, sizeof(io->scsiio.cdb)); 661229997Sken } 662229997Sken io->scsiio.cdb_len = min(csio->cdb_len, sizeof(io->scsiio.cdb)); 663229997Sken bcopy(csio->cdb_io.cdb_bytes, io->scsiio.cdb, 664229997Sken io->scsiio.cdb_len); 665229997Sken 666229997Sken err = ctl_queue(io); 667229997Sken if (err != CTL_RETVAL_COMPLETE) { 668229997Sken printf("%s: func %d: error %d returned by " 669229997Sken "ctl_queue()!\n", __func__, 670229997Sken ccb->ccb_h.func_code, err); 671229997Sken ctl_free_io(io); 672229997Sken } else { 673229997Sken ccb->ccb_h.status |= CAM_SIM_QUEUED; 674229997Sken } 675229997Sken break; 676229997Sken } 677229997Sken case XPT_ABORT: { 678229997Sken union ctl_io *io; 679229997Sken union ccb *abort_ccb; 680229997Sken 681229997Sken abort_ccb = ccb->cab.abort_ccb; 682229997Sken 683229997Sken if (abort_ccb->ccb_h.func_code != XPT_SCSI_IO) { 684229997Sken ccb->ccb_h.status = CAM_REQ_INVALID; 685229997Sken xpt_done(ccb); 686229997Sken } 687229997Sken 688229997Sken /* 689229997Sken * If we aren't online, there are no devices to talk to. 690229997Sken */ 691229997Sken if (softc->online == 0) { 692229997Sken ccb->ccb_h.status = CAM_DEV_NOT_THERE; 693229997Sken xpt_done(ccb); 694229997Sken return; 695229997Sken } 696229997Sken 697229997Sken io = ctl_alloc_io(softc->fe.ctl_pool_ref); 698229997Sken if (io == NULL) { 699229997Sken ccb->ccb_h.status = CAM_BUSY | CAM_DEV_QFRZN; 700229997Sken xpt_freeze_devq(ccb->ccb_h.path, 1); 701229997Sken xpt_done(ccb); 702229997Sken return; 703229997Sken } 704229997Sken 705229997Sken ctl_zero_io(io); 706229997Sken /* Save pointers on both sides */ 707229997Sken io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = ccb; 708229997Sken ccb->ccb_h.io_ptr = io; 709229997Sken 710229997Sken io->io_hdr.io_type = CTL_IO_TASK; 711229997Sken io->io_hdr.nexus.initid.id = 1; 712229997Sken io->io_hdr.nexus.targ_port = softc->fe.targ_port; 713229997Sken io->io_hdr.nexus.targ_target.id = ccb->ccb_h.target_id; 714229997Sken io->io_hdr.nexus.targ_lun = ccb->ccb_h.target_lun; 715229997Sken io->taskio.task_action = CTL_TASK_ABORT_TASK; 716229997Sken io->taskio.tag_num = abort_ccb->csio.tag_id; 717229997Sken switch (abort_ccb->csio.tag_action) { 718229997Sken case CAM_TAG_ACTION_NONE: 719229997Sken io->taskio.tag_type = CTL_TAG_UNTAGGED; 720229997Sken break; 721229997Sken case MSG_SIMPLE_TASK: 722229997Sken io->taskio.tag_type = CTL_TAG_SIMPLE; 723229997Sken break; 724229997Sken case MSG_HEAD_OF_QUEUE_TASK: 725229997Sken io->taskio.tag_type = CTL_TAG_HEAD_OF_QUEUE; 726229997Sken break; 727229997Sken case MSG_ORDERED_TASK: 728229997Sken io->taskio.tag_type = CTL_TAG_ORDERED; 729229997Sken break; 730229997Sken case MSG_ACA_TASK: 731229997Sken io->taskio.tag_type = CTL_TAG_ACA; 732229997Sken break; 733229997Sken default: 734229997Sken io->taskio.tag_type = CTL_TAG_UNTAGGED; 735229997Sken printf("%s: unhandled tag type %#x!!\n", __func__, 736229997Sken abort_ccb->csio.tag_action); 737229997Sken break; 738229997Sken } 739229997Sken err = ctl_queue(io); 740229997Sken if (err != CTL_RETVAL_COMPLETE) { 741229997Sken printf("%s func %d: error %d returned by " 742229997Sken "ctl_queue()!\n", __func__, 743229997Sken ccb->ccb_h.func_code, err); 744229997Sken ctl_free_io(io); 745229997Sken } 746229997Sken break; 747229997Sken } 748229997Sken case XPT_GET_TRAN_SETTINGS: { 749229997Sken struct ccb_trans_settings *cts; 750229997Sken struct ccb_trans_settings_scsi *scsi; 751229997Sken struct ccb_trans_settings_fc *fc; 752229997Sken 753229997Sken cts = &ccb->cts; 754229997Sken scsi = &cts->proto_specific.scsi; 755229997Sken fc = &cts->xport_specific.fc; 756229997Sken 757229997Sken 758229997Sken cts->protocol = PROTO_SCSI; 759229997Sken cts->protocol_version = SCSI_REV_SPC2; 760229997Sken cts->transport = XPORT_FC; 761229997Sken cts->transport_version = 0; 762229997Sken 763229997Sken scsi->valid = CTS_SCSI_VALID_TQ; 764229997Sken scsi->flags = CTS_SCSI_FLAGS_TAG_ENB; 765229997Sken fc->valid = CTS_FC_VALID_SPEED; 766229997Sken fc->bitrate = 800000; 767229997Sken fc->wwnn = softc->wwnn; 768229997Sken fc->wwpn = softc->wwpn; 769229997Sken fc->port = softc->fe.targ_port; 770229997Sken fc->valid |= CTS_FC_VALID_WWNN | CTS_FC_VALID_WWPN | 771229997Sken CTS_FC_VALID_PORT; 772229997Sken ccb->ccb_h.status = CAM_REQ_CMP; 773229997Sken break; 774229997Sken } 775229997Sken case XPT_SET_TRAN_SETTINGS: 776229997Sken /* XXX KDM should we actually do something here? */ 777229997Sken ccb->ccb_h.status = CAM_REQ_CMP; 778229997Sken break; 779229997Sken case XPT_RESET_BUS: 780229997Sken case XPT_RESET_DEV: { 781229997Sken union ctl_io *io; 782229997Sken 783229997Sken /* 784229997Sken * If we aren't online, there are no devices to talk to. 785229997Sken */ 786229997Sken if (softc->online == 0) { 787229997Sken ccb->ccb_h.status = CAM_DEV_NOT_THERE; 788229997Sken xpt_done(ccb); 789229997Sken return; 790229997Sken } 791229997Sken 792229997Sken io = ctl_alloc_io(softc->fe.ctl_pool_ref); 793229997Sken if (io == NULL) { 794229997Sken ccb->ccb_h.status = CAM_BUSY | CAM_DEV_QFRZN; 795229997Sken xpt_freeze_devq(ccb->ccb_h.path, 1); 796229997Sken xpt_done(ccb); 797229997Sken return; 798229997Sken } 799229997Sken 800229997Sken ctl_zero_io(io); 801229997Sken /* Save pointers on both sides */ 802229997Sken io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = ccb; 803229997Sken ccb->ccb_h.io_ptr = io; 804229997Sken 805229997Sken io->io_hdr.io_type = CTL_IO_TASK; 806229997Sken io->io_hdr.nexus.initid.id = 0; 807229997Sken io->io_hdr.nexus.targ_port = softc->fe.targ_port; 808229997Sken io->io_hdr.nexus.targ_target.id = ccb->ccb_h.target_id; 809229997Sken io->io_hdr.nexus.targ_lun = ccb->ccb_h.target_lun; 810229997Sken if (ccb->ccb_h.func_code == XPT_RESET_BUS) 811229997Sken io->taskio.task_action = CTL_TASK_BUS_RESET; 812229997Sken else 813229997Sken io->taskio.task_action = CTL_TASK_LUN_RESET; 814229997Sken 815229997Sken err = ctl_queue(io); 816229997Sken if (err != CTL_RETVAL_COMPLETE) { 817229997Sken printf("%s func %d: error %d returned by " 818229997Sken "ctl_queue()!\n", __func__, 819229997Sken ccb->ccb_h.func_code, err); 820229997Sken ctl_free_io(io); 821229997Sken } 822229997Sken break; 823229997Sken } 824229997Sken case XPT_CALC_GEOMETRY: 825229997Sken cam_calc_geometry(&ccb->ccg, 1); 826229997Sken xpt_done(ccb); 827229997Sken break; 828229997Sken case XPT_PATH_INQ: { 829229997Sken struct ccb_pathinq *cpi; 830229997Sken 831229997Sken cpi = &ccb->cpi; 832229997Sken 833229997Sken cpi->version_num = 0; 834229997Sken cpi->hba_inquiry = PI_TAG_ABLE; 835229997Sken cpi->target_sprt = 0; 836229997Sken cpi->hba_misc = 0; 837229997Sken cpi->hba_eng_cnt = 0; 838229997Sken cpi->max_target = 1; 839229997Sken cpi->max_lun = 1024; 840229997Sken /* Do we really have a limit? */ 841229997Sken cpi->maxio = 1024 * 1024; 842229997Sken cpi->async_flags = 0; 843229997Sken cpi->hpath_id = 0; 844229997Sken cpi->initiator_id = 0; 845229997Sken 846229997Sken strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 847229997Sken strncpy(cpi->hba_vid, "FreeBSD", HBA_IDLEN); 848229997Sken strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 849229997Sken cpi->unit_number = 0; 850229997Sken cpi->bus_id = 0; 851229997Sken cpi->base_transfer_speed = 800000; 852229997Sken cpi->protocol = PROTO_SCSI; 853229997Sken cpi->protocol_version = SCSI_REV_SPC2; 854229997Sken /* 855229997Sken * Pretend to be Fibre Channel. 856229997Sken */ 857229997Sken cpi->transport = XPORT_FC; 858229997Sken cpi->transport_version = 0; 859229997Sken cpi->xport_specific.fc.wwnn = softc->wwnn; 860229997Sken cpi->xport_specific.fc.wwpn = softc->wwpn; 861229997Sken cpi->xport_specific.fc.port = softc->fe.targ_port; 862229997Sken cpi->xport_specific.fc.bitrate = 8 * 1000 * 1000; 863229997Sken cpi->ccb_h.status = CAM_REQ_CMP; 864229997Sken break; 865229997Sken } 866229997Sken default: 867229997Sken ccb->ccb_h.status = CAM_PROVIDE_FAIL; 868229997Sken printf("%s: unsupported CCB type %#x\n", __func__, 869229997Sken ccb->ccb_h.func_code); 870229997Sken xpt_done(ccb); 871229997Sken break; 872229997Sken } 873229997Sken} 874229997Sken 875229997Skenstatic void 876229997Skencfcs_async(void *callback_arg, uint32_t code, struct cam_path *path, void *arg) 877229997Sken{ 878229997Sken 879229997Sken} 880