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_mem_pool.h> 69229997Sken#include <cam/ctl/ctl_debug.h> 70229997Sken 71229997Sken#define io_ptr spriv_ptr1 72229997Sken 73229997Skenstruct cfcs_io { 74229997Sken union ccb *ccb; 75229997Sken}; 76229997Sken 77229997Skenstruct cfcs_softc { 78229997Sken struct ctl_frontend fe; 79229997Sken char port_name[32]; 80229997Sken struct cam_sim *sim; 81229997Sken struct cam_devq *devq; 82229997Sken struct cam_path *path; 83229997Sken struct mtx lock; 84229997Sken char lock_desc[32]; 85229997Sken uint64_t wwnn; 86229997Sken uint64_t wwpn; 87229997Sken uint32_t cur_tag_num; 88229997Sken int online; 89229997Sken}; 90229997Sken 91229997Sken/* 92229997Sken * We can't handle CCBs with these flags. For the most part, we just don't 93229997Sken * handle physical addresses yet. That would require mapping things in 94229997Sken * order to do the copy. 95229997Sken */ 96246713Skib#define CFCS_BAD_CCB_FLAGS (CAM_DATA_ISPHYS | CAM_MSG_BUF_PHYS | \ 97246713Skib CAM_SNS_BUF_PHYS | CAM_CDB_PHYS | CAM_SENSE_PTR | \ 98229997Sken CAM_SENSE_PHYS) 99229997Sken 100229997Skenint cfcs_init(void); 101229997Skenvoid cfcs_shutdown(void); 102229997Skenstatic void cfcs_poll(struct cam_sim *sim); 103229997Skenstatic void cfcs_online(void *arg); 104229997Skenstatic void cfcs_offline(void *arg); 105229997Skenstatic int cfcs_targ_enable(void *arg, struct ctl_id targ_id); 106229997Skenstatic int cfcs_targ_disable(void *arg, struct ctl_id targ_id); 107229997Skenstatic int cfcs_lun_enable(void *arg, struct ctl_id target_id, int lun_id); 108229997Skenstatic int cfcs_lun_disable(void *arg, struct ctl_id target_id, int lun_id); 109229997Skenstatic void cfcs_datamove(union ctl_io *io); 110229997Skenstatic void cfcs_done(union ctl_io *io); 111229997Skenvoid cfcs_action(struct cam_sim *sim, union ccb *ccb); 112229997Skenstatic void cfcs_async(void *callback_arg, uint32_t code, 113229997Sken struct cam_path *path, void *arg); 114229997Sken 115229997Skenstruct cfcs_softc cfcs_softc; 116229997Sken/* 117229997Sken * This is primarly intended to allow for error injection to test the CAM 118229997Sken * sense data and sense residual handling code. This sets the maximum 119229997Sken * amount of SCSI sense data that we will report to CAM. 120229997Sken */ 121229997Skenstatic int cfcs_max_sense = sizeof(struct scsi_sense_data); 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 128249009Straszstatic int cfcs_module_event_handler(module_t, int /*modeventtype_t*/, void *); 129229997Sken 130249009Straszstatic moduledata_t cfcs_moduledata = { 131249009Strasz "ctlcfcs", 132249009Strasz cfcs_module_event_handler, 133249009Strasz NULL 134249009Strasz}; 135249009Strasz 136249009StraszDECLARE_MODULE(ctlcfcs, cfcs_moduledata, SI_SUB_CONFIGURE, SI_ORDER_FOURTH); 137249009StraszMODULE_VERSION(ctlcfcs, 1); 138249009StraszMODULE_DEPEND(ctlcfi, ctl, 1, 1, 1); 139249009StraszMODULE_DEPEND(ctlcfi, cam, 1, 1, 1); 140249009Strasz 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 152229997Sken softc = &cfcs_softc; 153229997Sken retval = 0; 154229997Sken bzero(softc, sizeof(*softc)); 155229997Sken sprintf(softc->lock_desc, "ctl2cam"); 156229997Sken mtx_init(&softc->lock, softc->lock_desc, NULL, MTX_DEF); 157229997Sken fe = &softc->fe; 158229997Sken 159229997Sken fe->port_type = CTL_PORT_INTERNAL; 160229997Sken /* XXX KDM what should the real number be here? */ 161229997Sken fe->num_requested_ctl_io = 4096; 162229997Sken snprintf(softc->port_name, sizeof(softc->port_name), "ctl2cam"); 163229997Sken fe->port_name = softc->port_name; 164229997Sken fe->port_online = cfcs_online; 165229997Sken fe->port_offline = cfcs_offline; 166229997Sken fe->onoff_arg = softc; 167229997Sken fe->targ_enable = cfcs_targ_enable; 168229997Sken fe->targ_disable = cfcs_targ_disable; 169229997Sken fe->lun_enable = cfcs_lun_enable; 170229997Sken fe->lun_disable = cfcs_lun_disable; 171229997Sken fe->targ_lun_arg = softc; 172229997Sken fe->fe_datamove = cfcs_datamove; 173229997Sken fe->fe_done = cfcs_done; 174229997Sken 175229997Sken /* XXX KDM what should we report here? */ 176229997Sken /* XXX These should probably be fetched from CTL. */ 177229997Sken fe->max_targets = 1; 178229997Sken fe->max_target_id = 15; 179229997Sken 180229997Sken retval = ctl_frontend_register(fe, /*master_SC*/ 1); 181229997Sken if (retval != 0) { 182229997Sken printf("%s: ctl_frontend_register() failed with error %d!\n", 183229997Sken __func__, retval); 184241508Smav mtx_destroy(&softc->lock); 185249009Strasz return (retval); 186229997Sken } 187229997Sken 188229997Sken /* 189229997Sken * Get the WWNN out of the database, and create a WWPN as well. 190229997Sken */ 191229997Sken#ifdef NEEDTOPORT 192229997Sken ddb_GetWWNN((char *)wwnn); 193229997Sken softc->wwnn = be64dec(wwnn); 194229997Sken softc->wwpn = softc->wwnn + (softc->fe.targ_port & 0xff); 195229997Sken#endif 196229997Sken 197229997Sken /* 198229997Sken * If the CTL frontend didn't tell us what our WWNN/WWPN is, go 199229997Sken * ahead and set something random. 200229997Sken */ 201229997Sken if (fe->wwnn == 0) { 202229997Sken uint64_t random_bits; 203229997Sken 204229997Sken arc4rand(&random_bits, sizeof(random_bits), 0); 205229997Sken softc->wwnn = (random_bits & 0x0000000fffffff00ULL) | 206229997Sken /* Company ID */ 0x5000000000000000ULL | 207229997Sken /* NL-Port */ 0x0300; 208229997Sken softc->wwpn = softc->wwnn + fe->targ_port + 1; 209229997Sken fe->wwnn = softc->wwnn; 210229997Sken fe->wwpn = softc->wwpn; 211229997Sken } else { 212229997Sken softc->wwnn = fe->wwnn; 213229997Sken softc->wwpn = fe->wwpn; 214229997Sken } 215229997Sken 216241508Smav mtx_lock(&softc->lock); 217229997Sken softc->devq = cam_simq_alloc(fe->num_requested_ctl_io); 218229997Sken if (softc->devq == NULL) { 219229997Sken printf("%s: error allocating devq\n", __func__); 220229997Sken retval = ENOMEM; 221229997Sken goto bailout; 222229997Sken } 223229997Sken 224229997Sken softc->sim = cam_sim_alloc(cfcs_action, cfcs_poll, softc->port_name, 225229997Sken softc, /*unit*/ 0, &softc->lock, 1, 226229997Sken fe->num_requested_ctl_io, softc->devq); 227229997Sken if (softc->sim == NULL) { 228229997Sken printf("%s: error allocating SIM\n", __func__); 229229997Sken retval = ENOMEM; 230229997Sken goto bailout; 231229997Sken } 232229997Sken 233229997Sken if (xpt_bus_register(softc->sim, NULL, 0) != CAM_SUCCESS) { 234229997Sken printf("%s: error registering SIM\n", __func__); 235229997Sken retval = ENOMEM; 236229997Sken goto bailout; 237229997Sken } 238229997Sken 239229997Sken if (xpt_create_path(&softc->path, /*periph*/NULL, 240229997Sken cam_sim_path(softc->sim), 241229997Sken CAM_TARGET_WILDCARD, 242229997Sken CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 243229997Sken printf("%s: error creating path\n", __func__); 244229997Sken xpt_bus_deregister(cam_sim_path(softc->sim)); 245249009Strasz retval = EINVAL; 246229997Sken goto bailout; 247229997Sken } 248229997Sken 249242174Smav xpt_setup_ccb(&csa.ccb_h, softc->path, CAM_PRIORITY_NONE); 250229997Sken csa.ccb_h.func_code = XPT_SASYNC_CB; 251229997Sken csa.event_enable = AC_LOST_DEVICE; 252229997Sken csa.callback = cfcs_async; 253229997Sken csa.callback_arg = softc->sim; 254229997Sken xpt_action((union ccb *)&csa); 255229997Sken 256241508Smav mtx_unlock(&softc->lock); 257241508Smav 258229997Sken return (retval); 259229997Sken 260229997Skenbailout: 261229997Sken if (softc->sim) 262229997Sken cam_sim_free(softc->sim, /*free_devq*/ TRUE); 263229997Sken else if (softc->devq) 264229997Sken cam_simq_free(softc->devq); 265241508Smav mtx_unlock(&softc->lock); 266241508Smav mtx_destroy(&softc->lock); 267229997Sken 268229997Sken return (retval); 269229997Sken} 270229997Sken 271229997Skenstatic void 272229997Skencfcs_poll(struct cam_sim *sim) 273229997Sken{ 274229997Sken 275229997Sken} 276229997Sken 277229997Skenvoid 278229997Skencfcs_shutdown(void) 279229997Sken{ 280229997Sken 281229997Sken} 282229997Sken 283249009Straszstatic int 284249009Straszcfcs_module_event_handler(module_t mod, int what, void *arg) 285249009Strasz{ 286249009Strasz 287249009Strasz switch (what) { 288249009Strasz case MOD_LOAD: 289249009Strasz return (cfcs_init()); 290249009Strasz case MOD_UNLOAD: 291249009Strasz return (EBUSY); 292249009Strasz default: 293249009Strasz return (EOPNOTSUPP); 294249009Strasz } 295249009Strasz} 296249009Strasz 297229997Skenstatic void 298244052Skencfcs_onoffline(void *arg, int online) 299229997Sken{ 300229997Sken struct cfcs_softc *softc; 301229997Sken union ccb *ccb; 302229997Sken 303229997Sken softc = (struct cfcs_softc *)arg; 304229997Sken 305229997Sken mtx_lock(&softc->lock); 306244052Sken softc->online = online; 307229997Sken 308229997Sken ccb = xpt_alloc_ccb_nowait(); 309229997Sken if (ccb == NULL) { 310229997Sken printf("%s: unable to allocate CCB for rescan\n", __func__); 311244052Sken goto bailout; 312229997Sken } 313229997Sken 314249468Smav if (xpt_create_path(&ccb->ccb_h.path, NULL, 315229997Sken cam_sim_path(softc->sim), CAM_TARGET_WILDCARD, 316229997Sken CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 317229997Sken printf("%s: can't allocate path for rescan\n", __func__); 318229997Sken xpt_free_ccb(ccb); 319244052Sken goto bailout; 320229997Sken } 321229997Sken xpt_rescan(ccb); 322244052Sken 323244052Skenbailout: 324244052Sken mtx_unlock(&softc->lock); 325229997Sken} 326229997Sken 327229997Skenstatic void 328244052Skencfcs_online(void *arg) 329244052Sken{ 330244052Sken cfcs_onoffline(arg, /*online*/ 1); 331244052Sken} 332244052Sken 333244052Skenstatic void 334229997Skencfcs_offline(void *arg) 335229997Sken{ 336244052Sken cfcs_onoffline(arg, /*online*/ 0); 337229997Sken} 338229997Sken 339229997Skenstatic int 340229997Skencfcs_targ_enable(void *arg, struct ctl_id targ_id) 341229997Sken{ 342229997Sken return (0); 343229997Sken} 344229997Sken 345229997Skenstatic int 346229997Skencfcs_targ_disable(void *arg, struct ctl_id targ_id) 347229997Sken{ 348229997Sken return (0); 349229997Sken} 350229997Sken 351229997Skenstatic int 352229997Skencfcs_lun_enable(void *arg, struct ctl_id target_id, int lun_id) 353229997Sken{ 354229997Sken return (0); 355229997Sken} 356229997Skenstatic int 357229997Skencfcs_lun_disable(void *arg, struct ctl_id target_id, int lun_id) 358229997Sken{ 359229997Sken return (0); 360229997Sken} 361229997Sken 362229997Sken/* 363229997Sken * This function is very similar to ctl_ioctl_do_datamove(). Is there a 364229997Sken * way to combine the functionality? 365229997Sken * 366229997Sken * XXX KDM may need to move this into a thread. We're doing a bcopy in the 367229997Sken * caller's context, which will usually be the backend. That may not be a 368229997Sken * good thing. 369229997Sken */ 370229997Skenstatic void 371229997Skencfcs_datamove(union ctl_io *io) 372229997Sken{ 373229997Sken union ccb *ccb; 374229997Sken bus_dma_segment_t cam_sg_entry, *cam_sglist; 375229997Sken struct ctl_sg_entry ctl_sg_entry, *ctl_sglist; 376229997Sken int cam_sg_count, ctl_sg_count, cam_sg_start; 377229997Sken int cam_sg_offset; 378229997Sken int len_to_copy, len_copied; 379229997Sken int ctl_watermark, cam_watermark; 380229997Sken int i, j; 381229997Sken 382229997Sken 383229997Sken cam_sg_offset = 0; 384229997Sken cam_sg_start = 0; 385229997Sken 386229997Sken ccb = io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr; 387229997Sken 388229997Sken /* 389229997Sken * Note that we have a check in cfcs_action() to make sure that any 390229997Sken * CCBs with "bad" flags are returned with CAM_REQ_INVALID. This 391229997Sken * is just to make sure no one removes that check without updating 392229997Sken * this code to provide the additional functionality necessary to 393229997Sken * support those modes of operation. 394229997Sken */ 395229997Sken KASSERT(((ccb->ccb_h.flags & CFCS_BAD_CCB_FLAGS) == 0), ("invalid " 396229997Sken "CAM flags %#x", (ccb->ccb_h.flags & CFCS_BAD_CCB_FLAGS))); 397229997Sken 398229997Sken /* 399229997Sken * Simplify things on both sides by putting single buffers into a 400229997Sken * single entry S/G list. 401229997Sken */ 402246713Skib switch ((ccb->ccb_h.flags & CAM_DATA_MASK)) { 403246713Skib case CAM_DATA_SG: { 404246713Skib int len_seen; 405229997Sken 406246713Skib cam_sglist = (bus_dma_segment_t *)ccb->csio.data_ptr; 407246713Skib cam_sg_count = ccb->csio.sglist_cnt; 408229997Sken 409246713Skib for (i = 0, len_seen = 0; i < cam_sg_count; i++) { 410246713Skib if ((len_seen + cam_sglist[i].ds_len) >= 411246713Skib io->scsiio.kern_rel_offset) { 412246713Skib cam_sg_start = i; 413246713Skib cam_sg_offset = io->scsiio.kern_rel_offset - 414246713Skib len_seen; 415246713Skib break; 416229997Sken } 417246713Skib len_seen += cam_sglist[i].ds_len; 418229997Sken } 419246713Skib break; 420246713Skib } 421246713Skib case CAM_DATA_VADDR: 422229997Sken cam_sglist = &cam_sg_entry; 423229997Sken cam_sglist[0].ds_len = ccb->csio.dxfer_len; 424229997Sken cam_sglist[0].ds_addr = (bus_addr_t)ccb->csio.data_ptr; 425229997Sken cam_sg_count = 1; 426229997Sken cam_sg_start = 0; 427229997Sken cam_sg_offset = io->scsiio.kern_rel_offset; 428246713Skib break; 429246713Skib default: 430246713Skib panic("Invalid CAM flags %#x", ccb->ccb_h.flags); 431229997Sken } 432229997Sken 433229997Sken if (io->scsiio.kern_sg_entries > 0) { 434229997Sken ctl_sglist = (struct ctl_sg_entry *)io->scsiio.kern_data_ptr; 435229997Sken ctl_sg_count = io->scsiio.kern_sg_entries; 436229997Sken } else { 437229997Sken ctl_sglist = &ctl_sg_entry; 438229997Sken ctl_sglist->addr = io->scsiio.kern_data_ptr; 439229997Sken ctl_sglist->len = io->scsiio.kern_data_len; 440229997Sken ctl_sg_count = 1; 441229997Sken } 442229997Sken 443229997Sken ctl_watermark = 0; 444229997Sken cam_watermark = cam_sg_offset; 445229997Sken len_copied = 0; 446229997Sken for (i = cam_sg_start, j = 0; 447229997Sken i < cam_sg_count && j < ctl_sg_count;) { 448229997Sken uint8_t *cam_ptr, *ctl_ptr; 449229997Sken 450229997Sken len_to_copy = ctl_min(cam_sglist[i].ds_len - cam_watermark, 451229997Sken ctl_sglist[j].len - ctl_watermark); 452229997Sken 453229997Sken cam_ptr = (uint8_t *)cam_sglist[i].ds_addr; 454229997Sken cam_ptr = cam_ptr + cam_watermark; 455229997Sken if (io->io_hdr.flags & CTL_FLAG_BUS_ADDR) { 456229997Sken /* 457229997Sken * XXX KDM fix this! 458229997Sken */ 459229997Sken panic("need to implement bus address support"); 460229997Sken#if 0 461229997Sken kern_ptr = bus_to_virt(kern_sglist[j].addr); 462229997Sken#endif 463229997Sken } else 464229997Sken ctl_ptr = (uint8_t *)ctl_sglist[j].addr; 465229997Sken ctl_ptr = ctl_ptr + ctl_watermark; 466229997Sken 467229997Sken ctl_watermark += len_to_copy; 468229997Sken cam_watermark += len_to_copy; 469229997Sken 470229997Sken if ((io->io_hdr.flags & CTL_FLAG_DATA_MASK) == 471229997Sken CTL_FLAG_DATA_IN) { 472229997Sken CTL_DEBUG_PRINT(("%s: copying %d bytes to CAM\n", 473229997Sken __func__, len_to_copy)); 474229997Sken CTL_DEBUG_PRINT(("%s: from %p to %p\n", ctl_ptr, 475229997Sken __func__, cam_ptr)); 476229997Sken bcopy(ctl_ptr, cam_ptr, len_to_copy); 477229997Sken } else { 478229997Sken CTL_DEBUG_PRINT(("%s: copying %d bytes from CAM\n", 479229997Sken __func__, len_to_copy)); 480229997Sken CTL_DEBUG_PRINT(("%s: from %p to %p\n", cam_ptr, 481229997Sken __func__, ctl_ptr)); 482229997Sken bcopy(cam_ptr, ctl_ptr, len_to_copy); 483229997Sken } 484229997Sken 485229997Sken len_copied += len_to_copy; 486229997Sken 487229997Sken if (cam_sglist[i].ds_len == cam_watermark) { 488229997Sken i++; 489229997Sken cam_watermark = 0; 490229997Sken } 491229997Sken 492229997Sken if (ctl_sglist[j].len == ctl_watermark) { 493229997Sken j++; 494229997Sken ctl_watermark = 0; 495229997Sken } 496229997Sken } 497229997Sken 498229997Sken io->scsiio.ext_data_filled += len_copied; 499229997Sken 500229997Sken io->scsiio.be_move_done(io); 501229997Sken} 502229997Sken 503229997Skenstatic void 504229997Skencfcs_done(union ctl_io *io) 505229997Sken{ 506229997Sken union ccb *ccb; 507229997Sken struct cfcs_softc *softc; 508229997Sken struct cam_sim *sim; 509229997Sken 510229997Sken ccb = io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr; 511229997Sken 512229997Sken sim = xpt_path_sim(ccb->ccb_h.path); 513229997Sken softc = (struct cfcs_softc *)cam_sim_softc(sim); 514229997Sken 515229997Sken /* 516229997Sken * At this point we should have status. If we don't, that's a bug. 517229997Sken */ 518229997Sken KASSERT(((io->io_hdr.status & CTL_STATUS_MASK) != CTL_STATUS_NONE), 519229997Sken ("invalid CTL status %#x", io->io_hdr.status)); 520229997Sken 521229997Sken /* 522229997Sken * Translate CTL status to CAM status. 523229997Sken */ 524229997Sken switch (io->io_hdr.status & CTL_STATUS_MASK) { 525229997Sken case CTL_SUCCESS: 526229997Sken ccb->ccb_h.status = CAM_REQ_CMP; 527229997Sken break; 528229997Sken case CTL_SCSI_ERROR: 529229997Sken ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR | CAM_AUTOSNS_VALID; 530229997Sken ccb->csio.scsi_status = io->scsiio.scsi_status; 531229997Sken bcopy(&io->scsiio.sense_data, &ccb->csio.sense_data, 532229997Sken min(io->scsiio.sense_len, ccb->csio.sense_len)); 533229997Sken if (ccb->csio.sense_len > io->scsiio.sense_len) 534229997Sken ccb->csio.sense_resid = ccb->csio.sense_len - 535229997Sken io->scsiio.sense_len; 536229997Sken else 537229997Sken ccb->csio.sense_resid = 0; 538229997Sken if ((ccb->csio.sense_len - ccb->csio.sense_resid) > 539229997Sken cfcs_max_sense) { 540229997Sken ccb->csio.sense_resid = ccb->csio.sense_len - 541229997Sken cfcs_max_sense; 542229997Sken } 543229997Sken break; 544229997Sken case CTL_CMD_ABORTED: 545229997Sken ccb->ccb_h.status = CAM_REQ_ABORTED; 546229997Sken break; 547229997Sken case CTL_ERROR: 548229997Sken default: 549229997Sken ccb->ccb_h.status = CAM_REQ_CMP_ERR; 550229997Sken break; 551229997Sken } 552229997Sken 553229997Sken mtx_lock(sim->mtx); 554229997Sken xpt_done(ccb); 555229997Sken mtx_unlock(sim->mtx); 556229997Sken 557229997Sken ctl_free_io(io); 558229997Sken} 559229997Sken 560229997Skenvoid 561229997Skencfcs_action(struct cam_sim *sim, union ccb *ccb) 562229997Sken{ 563229997Sken struct cfcs_softc *softc; 564229997Sken int err; 565229997Sken 566229997Sken softc = (struct cfcs_softc *)cam_sim_softc(sim); 567229997Sken mtx_assert(&softc->lock, MA_OWNED); 568229997Sken 569229997Sken switch (ccb->ccb_h.func_code) { 570229997Sken case XPT_SCSI_IO: { 571229997Sken union ctl_io *io; 572229997Sken struct ccb_scsiio *csio; 573229997Sken 574229997Sken csio = &ccb->csio; 575229997Sken 576229997Sken /* 577229997Sken * Catch CCB flags, like physical address flags, that 578229997Sken * indicate situations we currently can't handle. 579229997Sken */ 580229997Sken if (ccb->ccb_h.flags & CFCS_BAD_CCB_FLAGS) { 581229997Sken ccb->ccb_h.status = CAM_REQ_INVALID; 582229997Sken printf("%s: bad CCB flags %#x (all flags %#x)\n", 583229997Sken __func__, ccb->ccb_h.flags & CFCS_BAD_CCB_FLAGS, 584229997Sken ccb->ccb_h.flags); 585229997Sken xpt_done(ccb); 586229997Sken return; 587229997Sken } 588229997Sken 589229997Sken /* 590229997Sken * If we aren't online, there are no devices to see. 591229997Sken */ 592229997Sken if (softc->online == 0) { 593229997Sken ccb->ccb_h.status = CAM_DEV_NOT_THERE; 594229997Sken xpt_done(ccb); 595229997Sken return; 596229997Sken } 597229997Sken 598229997Sken io = ctl_alloc_io(softc->fe.ctl_pool_ref); 599229997Sken if (io == NULL) { 600229997Sken printf("%s: can't allocate ctl_io\n", __func__); 601229997Sken ccb->ccb_h.status = CAM_BUSY | CAM_DEV_QFRZN; 602229997Sken xpt_freeze_devq(ccb->ccb_h.path, 1); 603229997Sken xpt_done(ccb); 604229997Sken return; 605229997Sken } 606229997Sken ctl_zero_io(io); 607229997Sken /* Save pointers on both sides */ 608229997Sken io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = ccb; 609229997Sken ccb->ccb_h.io_ptr = io; 610229997Sken 611229997Sken /* 612229997Sken * Only SCSI I/O comes down this path, resets, etc. come 613229997Sken * down via the XPT_RESET_BUS/LUN CCBs below. 614229997Sken */ 615229997Sken io->io_hdr.io_type = CTL_IO_SCSI; 616229997Sken io->io_hdr.nexus.initid.id = 1; 617229997Sken io->io_hdr.nexus.targ_port = softc->fe.targ_port; 618229997Sken /* 619229997Sken * XXX KDM how do we handle target IDs? 620229997Sken */ 621229997Sken io->io_hdr.nexus.targ_target.id = ccb->ccb_h.target_id; 622229997Sken io->io_hdr.nexus.targ_lun = ccb->ccb_h.target_lun; 623229997Sken /* 624229997Sken * This tag scheme isn't the best, since we could in theory 625229997Sken * have a very long-lived I/O and tag collision, especially 626229997Sken * in a high I/O environment. But it should work well 627229997Sken * enough for now. Since we're using unsigned ints, 628229997Sken * they'll just wrap around. 629229997Sken */ 630229997Sken io->scsiio.tag_num = softc->cur_tag_num++; 631229997Sken csio->tag_id = io->scsiio.tag_num; 632229997Sken switch (csio->tag_action) { 633229997Sken case CAM_TAG_ACTION_NONE: 634229997Sken io->scsiio.tag_type = CTL_TAG_UNTAGGED; 635229997Sken break; 636229997Sken case MSG_SIMPLE_TASK: 637229997Sken io->scsiio.tag_type = CTL_TAG_SIMPLE; 638229997Sken break; 639229997Sken case MSG_HEAD_OF_QUEUE_TASK: 640229997Sken io->scsiio.tag_type = CTL_TAG_HEAD_OF_QUEUE; 641229997Sken break; 642229997Sken case MSG_ORDERED_TASK: 643229997Sken io->scsiio.tag_type = CTL_TAG_ORDERED; 644229997Sken break; 645229997Sken case MSG_ACA_TASK: 646229997Sken io->scsiio.tag_type = CTL_TAG_ACA; 647229997Sken break; 648229997Sken default: 649229997Sken io->scsiio.tag_type = CTL_TAG_UNTAGGED; 650229997Sken printf("%s: unhandled tag type %#x!!\n", __func__, 651229997Sken csio->tag_action); 652229997Sken break; 653229997Sken } 654229997Sken if (csio->cdb_len > sizeof(io->scsiio.cdb)) { 655229997Sken printf("%s: WARNING: CDB len %d > ctl_io space %zd\n", 656229997Sken __func__, csio->cdb_len, sizeof(io->scsiio.cdb)); 657229997Sken } 658229997Sken io->scsiio.cdb_len = min(csio->cdb_len, sizeof(io->scsiio.cdb)); 659229997Sken bcopy(csio->cdb_io.cdb_bytes, io->scsiio.cdb, 660229997Sken io->scsiio.cdb_len); 661229997Sken 662229997Sken err = ctl_queue(io); 663229997Sken if (err != CTL_RETVAL_COMPLETE) { 664229997Sken printf("%s: func %d: error %d returned by " 665229997Sken "ctl_queue()!\n", __func__, 666229997Sken ccb->ccb_h.func_code, err); 667229997Sken ctl_free_io(io); 668229997Sken } else { 669229997Sken ccb->ccb_h.status |= CAM_SIM_QUEUED; 670229997Sken } 671229997Sken break; 672229997Sken } 673229997Sken case XPT_ABORT: { 674229997Sken union ctl_io *io; 675229997Sken union ccb *abort_ccb; 676229997Sken 677229997Sken abort_ccb = ccb->cab.abort_ccb; 678229997Sken 679229997Sken if (abort_ccb->ccb_h.func_code != XPT_SCSI_IO) { 680229997Sken ccb->ccb_h.status = CAM_REQ_INVALID; 681229997Sken xpt_done(ccb); 682229997Sken } 683229997Sken 684229997Sken /* 685229997Sken * If we aren't online, there are no devices to talk to. 686229997Sken */ 687229997Sken if (softc->online == 0) { 688229997Sken ccb->ccb_h.status = CAM_DEV_NOT_THERE; 689229997Sken xpt_done(ccb); 690229997Sken return; 691229997Sken } 692229997Sken 693229997Sken io = ctl_alloc_io(softc->fe.ctl_pool_ref); 694229997Sken if (io == NULL) { 695229997Sken ccb->ccb_h.status = CAM_BUSY | CAM_DEV_QFRZN; 696229997Sken xpt_freeze_devq(ccb->ccb_h.path, 1); 697229997Sken xpt_done(ccb); 698229997Sken return; 699229997Sken } 700229997Sken 701229997Sken ctl_zero_io(io); 702229997Sken /* Save pointers on both sides */ 703229997Sken io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = ccb; 704229997Sken ccb->ccb_h.io_ptr = io; 705229997Sken 706229997Sken io->io_hdr.io_type = CTL_IO_TASK; 707229997Sken io->io_hdr.nexus.initid.id = 1; 708229997Sken io->io_hdr.nexus.targ_port = softc->fe.targ_port; 709229997Sken io->io_hdr.nexus.targ_target.id = ccb->ccb_h.target_id; 710229997Sken io->io_hdr.nexus.targ_lun = ccb->ccb_h.target_lun; 711229997Sken io->taskio.task_action = CTL_TASK_ABORT_TASK; 712229997Sken io->taskio.tag_num = abort_ccb->csio.tag_id; 713229997Sken switch (abort_ccb->csio.tag_action) { 714229997Sken case CAM_TAG_ACTION_NONE: 715229997Sken io->taskio.tag_type = CTL_TAG_UNTAGGED; 716229997Sken break; 717229997Sken case MSG_SIMPLE_TASK: 718229997Sken io->taskio.tag_type = CTL_TAG_SIMPLE; 719229997Sken break; 720229997Sken case MSG_HEAD_OF_QUEUE_TASK: 721229997Sken io->taskio.tag_type = CTL_TAG_HEAD_OF_QUEUE; 722229997Sken break; 723229997Sken case MSG_ORDERED_TASK: 724229997Sken io->taskio.tag_type = CTL_TAG_ORDERED; 725229997Sken break; 726229997Sken case MSG_ACA_TASK: 727229997Sken io->taskio.tag_type = CTL_TAG_ACA; 728229997Sken break; 729229997Sken default: 730229997Sken io->taskio.tag_type = CTL_TAG_UNTAGGED; 731229997Sken printf("%s: unhandled tag type %#x!!\n", __func__, 732229997Sken abort_ccb->csio.tag_action); 733229997Sken break; 734229997Sken } 735229997Sken err = ctl_queue(io); 736229997Sken if (err != CTL_RETVAL_COMPLETE) { 737229997Sken printf("%s func %d: error %d returned by " 738229997Sken "ctl_queue()!\n", __func__, 739229997Sken ccb->ccb_h.func_code, err); 740229997Sken ctl_free_io(io); 741229997Sken } 742229997Sken break; 743229997Sken } 744229997Sken case XPT_GET_TRAN_SETTINGS: { 745229997Sken struct ccb_trans_settings *cts; 746229997Sken struct ccb_trans_settings_scsi *scsi; 747229997Sken struct ccb_trans_settings_fc *fc; 748229997Sken 749229997Sken cts = &ccb->cts; 750229997Sken scsi = &cts->proto_specific.scsi; 751229997Sken fc = &cts->xport_specific.fc; 752229997Sken 753229997Sken 754229997Sken cts->protocol = PROTO_SCSI; 755229997Sken cts->protocol_version = SCSI_REV_SPC2; 756229997Sken cts->transport = XPORT_FC; 757229997Sken cts->transport_version = 0; 758229997Sken 759229997Sken scsi->valid = CTS_SCSI_VALID_TQ; 760229997Sken scsi->flags = CTS_SCSI_FLAGS_TAG_ENB; 761229997Sken fc->valid = CTS_FC_VALID_SPEED; 762229997Sken fc->bitrate = 800000; 763229997Sken fc->wwnn = softc->wwnn; 764229997Sken fc->wwpn = softc->wwpn; 765229997Sken fc->port = softc->fe.targ_port; 766229997Sken fc->valid |= CTS_FC_VALID_WWNN | CTS_FC_VALID_WWPN | 767229997Sken CTS_FC_VALID_PORT; 768229997Sken ccb->ccb_h.status = CAM_REQ_CMP; 769229997Sken break; 770229997Sken } 771229997Sken case XPT_SET_TRAN_SETTINGS: 772229997Sken /* XXX KDM should we actually do something here? */ 773229997Sken ccb->ccb_h.status = CAM_REQ_CMP; 774229997Sken break; 775229997Sken case XPT_RESET_BUS: 776229997Sken case XPT_RESET_DEV: { 777229997Sken union ctl_io *io; 778229997Sken 779229997Sken /* 780229997Sken * If we aren't online, there are no devices to talk to. 781229997Sken */ 782229997Sken if (softc->online == 0) { 783229997Sken ccb->ccb_h.status = CAM_DEV_NOT_THERE; 784229997Sken xpt_done(ccb); 785229997Sken return; 786229997Sken } 787229997Sken 788229997Sken io = ctl_alloc_io(softc->fe.ctl_pool_ref); 789229997Sken if (io == NULL) { 790229997Sken ccb->ccb_h.status = CAM_BUSY | CAM_DEV_QFRZN; 791229997Sken xpt_freeze_devq(ccb->ccb_h.path, 1); 792229997Sken xpt_done(ccb); 793229997Sken return; 794229997Sken } 795229997Sken 796229997Sken ctl_zero_io(io); 797229997Sken /* Save pointers on both sides */ 798229997Sken io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = ccb; 799229997Sken ccb->ccb_h.io_ptr = io; 800229997Sken 801229997Sken io->io_hdr.io_type = CTL_IO_TASK; 802229997Sken io->io_hdr.nexus.initid.id = 0; 803229997Sken io->io_hdr.nexus.targ_port = softc->fe.targ_port; 804229997Sken io->io_hdr.nexus.targ_target.id = ccb->ccb_h.target_id; 805229997Sken io->io_hdr.nexus.targ_lun = ccb->ccb_h.target_lun; 806229997Sken if (ccb->ccb_h.func_code == XPT_RESET_BUS) 807229997Sken io->taskio.task_action = CTL_TASK_BUS_RESET; 808229997Sken else 809229997Sken io->taskio.task_action = CTL_TASK_LUN_RESET; 810229997Sken 811229997Sken err = ctl_queue(io); 812229997Sken if (err != CTL_RETVAL_COMPLETE) { 813229997Sken printf("%s func %d: error %d returned by " 814229997Sken "ctl_queue()!\n", __func__, 815229997Sken ccb->ccb_h.func_code, err); 816229997Sken ctl_free_io(io); 817229997Sken } 818229997Sken break; 819229997Sken } 820229997Sken case XPT_CALC_GEOMETRY: 821229997Sken cam_calc_geometry(&ccb->ccg, 1); 822229997Sken xpt_done(ccb); 823229997Sken break; 824229997Sken case XPT_PATH_INQ: { 825229997Sken struct ccb_pathinq *cpi; 826229997Sken 827229997Sken cpi = &ccb->cpi; 828229997Sken 829229997Sken cpi->version_num = 0; 830229997Sken cpi->hba_inquiry = PI_TAG_ABLE; 831229997Sken cpi->target_sprt = 0; 832229997Sken cpi->hba_misc = 0; 833229997Sken cpi->hba_eng_cnt = 0; 834229997Sken cpi->max_target = 1; 835229997Sken cpi->max_lun = 1024; 836229997Sken /* Do we really have a limit? */ 837229997Sken cpi->maxio = 1024 * 1024; 838229997Sken cpi->async_flags = 0; 839229997Sken cpi->hpath_id = 0; 840229997Sken cpi->initiator_id = 0; 841229997Sken 842229997Sken strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 843229997Sken strncpy(cpi->hba_vid, "FreeBSD", HBA_IDLEN); 844229997Sken strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 845229997Sken cpi->unit_number = 0; 846229997Sken cpi->bus_id = 0; 847229997Sken cpi->base_transfer_speed = 800000; 848229997Sken cpi->protocol = PROTO_SCSI; 849229997Sken cpi->protocol_version = SCSI_REV_SPC2; 850229997Sken /* 851229997Sken * Pretend to be Fibre Channel. 852229997Sken */ 853229997Sken cpi->transport = XPORT_FC; 854229997Sken cpi->transport_version = 0; 855229997Sken cpi->xport_specific.fc.wwnn = softc->wwnn; 856229997Sken cpi->xport_specific.fc.wwpn = softc->wwpn; 857229997Sken cpi->xport_specific.fc.port = softc->fe.targ_port; 858229997Sken cpi->xport_specific.fc.bitrate = 8 * 1000 * 1000; 859229997Sken cpi->ccb_h.status = CAM_REQ_CMP; 860229997Sken break; 861229997Sken } 862229997Sken default: 863229997Sken ccb->ccb_h.status = CAM_PROVIDE_FAIL; 864229997Sken printf("%s: unsupported CCB type %#x\n", __func__, 865229997Sken ccb->ccb_h.func_code); 866229997Sken xpt_done(ccb); 867229997Sken break; 868229997Sken } 869229997Sken} 870229997Sken 871229997Skenstatic void 872229997Skencfcs_async(void *callback_arg, uint32_t code, struct cam_path *path, void *arg) 873229997Sken{ 874229997Sken 875229997Sken} 876