1130f4520SKenneth D. Merry /*- 2130f4520SKenneth D. Merry * Copyright (c) 2009 Silicon Graphics International Corp. 3130f4520SKenneth D. Merry * All rights reserved. 4130f4520SKenneth D. Merry * 5130f4520SKenneth D. Merry * Redistribution and use in source and binary forms, with or without 6130f4520SKenneth D. Merry * modification, are permitted provided that the following conditions 7130f4520SKenneth D. Merry * are met: 8130f4520SKenneth D. Merry * 1. Redistributions of source code must retain the above copyright 9130f4520SKenneth D. Merry * notice, this list of conditions, and the following disclaimer, 10130f4520SKenneth D. Merry * without modification. 11130f4520SKenneth D. Merry * 2. Redistributions in binary form must reproduce at minimum a disclaimer 12130f4520SKenneth D. Merry * substantially similar to the "NO WARRANTY" disclaimer below 13130f4520SKenneth D. Merry * ("Disclaimer") and any redistribution must be conditioned upon 14130f4520SKenneth D. Merry * including a substantially similar Disclaimer requirement for further 15130f4520SKenneth D. Merry * binary redistribution. 16130f4520SKenneth D. Merry * 17130f4520SKenneth D. Merry * NO WARRANTY 18130f4520SKenneth D. Merry * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19130f4520SKenneth D. Merry * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20130f4520SKenneth D. Merry * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 21130f4520SKenneth D. Merry * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22130f4520SKenneth D. Merry * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23130f4520SKenneth D. Merry * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24130f4520SKenneth D. Merry * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25130f4520SKenneth D. Merry * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 26130f4520SKenneth D. Merry * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 27130f4520SKenneth D. Merry * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28130f4520SKenneth D. Merry * POSSIBILITY OF SUCH DAMAGES. 29130f4520SKenneth D. Merry * 30130f4520SKenneth D. Merry * $Id: //depot/users/kenm/FreeBSD-test2/sys/cam/ctl/ctl_frontend_cam_sim.c#4 $ 31130f4520SKenneth D. Merry */ 32130f4520SKenneth D. Merry /* 33130f4520SKenneth D. Merry * CTL frontend to CAM SIM interface. This allows access to CTL LUNs via 34130f4520SKenneth D. Merry * the da(4) and pass(4) drivers from inside the system. 35130f4520SKenneth D. Merry * 36130f4520SKenneth D. Merry * Author: Ken Merry <ken@FreeBSD.org> 37130f4520SKenneth D. Merry */ 38130f4520SKenneth D. Merry 39130f4520SKenneth D. Merry #include <sys/cdefs.h> 40130f4520SKenneth D. Merry __FBSDID("$FreeBSD$"); 41130f4520SKenneth D. Merry 42130f4520SKenneth D. Merry #include <sys/param.h> 43130f4520SKenneth D. Merry #include <sys/systm.h> 44130f4520SKenneth D. Merry #include <sys/kernel.h> 45130f4520SKenneth D. Merry #include <sys/types.h> 46130f4520SKenneth D. Merry #include <sys/malloc.h> 47130f4520SKenneth D. Merry #include <sys/lock.h> 48130f4520SKenneth D. Merry #include <sys/mutex.h> 49130f4520SKenneth D. Merry #include <sys/condvar.h> 50130f4520SKenneth D. Merry #include <sys/queue.h> 51130f4520SKenneth D. Merry #include <sys/bus.h> 52130f4520SKenneth D. Merry #include <sys/sysctl.h> 53130f4520SKenneth D. Merry #include <machine/bus.h> 54130f4520SKenneth D. Merry #include <sys/sbuf.h> 55130f4520SKenneth D. Merry 56130f4520SKenneth D. Merry #include <cam/cam.h> 57130f4520SKenneth D. Merry #include <cam/cam_ccb.h> 58130f4520SKenneth D. Merry #include <cam/cam_sim.h> 59130f4520SKenneth D. Merry #include <cam/cam_xpt_sim.h> 60130f4520SKenneth D. Merry #include <cam/cam_xpt.h> 61130f4520SKenneth D. Merry #include <cam/cam_periph.h> 62130f4520SKenneth D. Merry #include <cam/scsi/scsi_all.h> 63130f4520SKenneth D. Merry #include <cam/scsi/scsi_message.h> 64130f4520SKenneth D. Merry #include <cam/ctl/ctl_io.h> 65130f4520SKenneth D. Merry #include <cam/ctl/ctl.h> 66130f4520SKenneth D. Merry #include <cam/ctl/ctl_frontend.h> 67130f4520SKenneth D. Merry #include <cam/ctl/ctl_frontend_internal.h> 68130f4520SKenneth D. Merry #include <cam/ctl/ctl_mem_pool.h> 69130f4520SKenneth D. Merry #include <cam/ctl/ctl_debug.h> 70130f4520SKenneth D. Merry 71130f4520SKenneth D. Merry #define io_ptr spriv_ptr1 72130f4520SKenneth D. Merry 73130f4520SKenneth D. Merry struct cfcs_io { 74130f4520SKenneth D. Merry union ccb *ccb; 75130f4520SKenneth D. Merry }; 76130f4520SKenneth D. Merry 77130f4520SKenneth D. Merry struct cfcs_softc { 78130f4520SKenneth D. Merry struct ctl_frontend fe; 79130f4520SKenneth D. Merry char port_name[32]; 80130f4520SKenneth D. Merry struct cam_sim *sim; 81130f4520SKenneth D. Merry struct cam_devq *devq; 82130f4520SKenneth D. Merry struct cam_path *path; 83130f4520SKenneth D. Merry struct mtx lock; 84130f4520SKenneth D. Merry char lock_desc[32]; 85130f4520SKenneth D. Merry uint64_t wwnn; 86130f4520SKenneth D. Merry uint64_t wwpn; 87130f4520SKenneth D. Merry uint32_t cur_tag_num; 88130f4520SKenneth D. Merry int online; 89130f4520SKenneth D. Merry }; 90130f4520SKenneth D. Merry 91130f4520SKenneth D. Merry /* 92130f4520SKenneth D. Merry * We can't handle CCBs with these flags. For the most part, we just don't 93130f4520SKenneth D. Merry * handle physical addresses yet. That would require mapping things in 94130f4520SKenneth D. Merry * order to do the copy. 95130f4520SKenneth D. Merry */ 96dd0b4fb6SKonstantin Belousov #define CFCS_BAD_CCB_FLAGS (CAM_DATA_ISPHYS | CAM_MSG_BUF_PHYS | \ 97dd0b4fb6SKonstantin Belousov CAM_SNS_BUF_PHYS | CAM_CDB_PHYS | CAM_SENSE_PTR | \ 98130f4520SKenneth D. Merry CAM_SENSE_PHYS) 99130f4520SKenneth D. Merry 100130f4520SKenneth D. Merry int cfcs_init(void); 101130f4520SKenneth D. Merry void cfcs_shutdown(void); 102130f4520SKenneth D. Merry static void cfcs_poll(struct cam_sim *sim); 103130f4520SKenneth D. Merry static void cfcs_online(void *arg); 104130f4520SKenneth D. Merry static void cfcs_offline(void *arg); 105130f4520SKenneth D. Merry static int cfcs_targ_enable(void *arg, struct ctl_id targ_id); 106130f4520SKenneth D. Merry static int cfcs_targ_disable(void *arg, struct ctl_id targ_id); 107130f4520SKenneth D. Merry static int cfcs_lun_enable(void *arg, struct ctl_id target_id, int lun_id); 108130f4520SKenneth D. Merry static int cfcs_lun_disable(void *arg, struct ctl_id target_id, int lun_id); 109130f4520SKenneth D. Merry static void cfcs_datamove(union ctl_io *io); 110130f4520SKenneth D. Merry static void cfcs_done(union ctl_io *io); 111130f4520SKenneth D. Merry void cfcs_action(struct cam_sim *sim, union ccb *ccb); 112130f4520SKenneth D. Merry static void cfcs_async(void *callback_arg, uint32_t code, 113130f4520SKenneth D. Merry struct cam_path *path, void *arg); 114130f4520SKenneth D. Merry 115130f4520SKenneth D. Merry struct cfcs_softc cfcs_softc; 116130f4520SKenneth D. Merry /* 117130f4520SKenneth D. Merry * This is primarly intended to allow for error injection to test the CAM 118130f4520SKenneth D. Merry * sense data and sense residual handling code. This sets the maximum 119130f4520SKenneth D. Merry * amount of SCSI sense data that we will report to CAM. 120130f4520SKenneth D. Merry */ 121130f4520SKenneth D. Merry static int cfcs_max_sense = sizeof(struct scsi_sense_data); 122130f4520SKenneth D. Merry 123130f4520SKenneth D. Merry SYSCTL_NODE(_kern_cam, OID_AUTO, ctl2cam, CTLFLAG_RD, 0, 124130f4520SKenneth D. Merry "CAM Target Layer SIM frontend"); 125130f4520SKenneth D. Merry SYSCTL_INT(_kern_cam_ctl2cam, OID_AUTO, max_sense, CTLFLAG_RW, 126130f4520SKenneth D. Merry &cfcs_max_sense, 0, "Maximum sense data size"); 127130f4520SKenneth D. Merry 12832562145SEdward Tomasz Napierala static int cfcs_module_event_handler(module_t, int /*modeventtype_t*/, void *); 12932562145SEdward Tomasz Napierala 13032562145SEdward Tomasz Napierala static moduledata_t cfcs_moduledata = { 13132562145SEdward Tomasz Napierala "ctlcfcs", 13232562145SEdward Tomasz Napierala cfcs_module_event_handler, 13332562145SEdward Tomasz Napierala NULL 13432562145SEdward Tomasz Napierala }; 13532562145SEdward Tomasz Napierala 13632562145SEdward Tomasz Napierala DECLARE_MODULE(ctlcfcs, cfcs_moduledata, SI_SUB_CONFIGURE, SI_ORDER_FOURTH); 13732562145SEdward Tomasz Napierala MODULE_VERSION(ctlcfcs, 1); 13832562145SEdward Tomasz Napierala MODULE_DEPEND(ctlcfi, ctl, 1, 1, 1); 13932562145SEdward Tomasz Napierala MODULE_DEPEND(ctlcfi, cam, 1, 1, 1); 140130f4520SKenneth D. Merry 141130f4520SKenneth D. Merry int 142130f4520SKenneth D. Merry cfcs_init(void) 143130f4520SKenneth D. Merry { 144130f4520SKenneth D. Merry struct cfcs_softc *softc; 145130f4520SKenneth D. Merry struct ccb_setasync csa; 146130f4520SKenneth D. Merry struct ctl_frontend *fe; 147130f4520SKenneth D. Merry #ifdef NEEDTOPORT 148130f4520SKenneth D. Merry char wwnn[8]; 149130f4520SKenneth D. Merry #endif 150130f4520SKenneth D. Merry int retval; 151130f4520SKenneth D. Merry 152130f4520SKenneth D. Merry softc = &cfcs_softc; 153130f4520SKenneth D. Merry retval = 0; 154130f4520SKenneth D. Merry bzero(softc, sizeof(*softc)); 155130f4520SKenneth D. Merry sprintf(softc->lock_desc, "ctl2cam"); 156130f4520SKenneth D. Merry mtx_init(&softc->lock, softc->lock_desc, NULL, MTX_DEF); 157130f4520SKenneth D. Merry fe = &softc->fe; 158130f4520SKenneth D. Merry 159130f4520SKenneth D. Merry fe->port_type = CTL_PORT_INTERNAL; 160130f4520SKenneth D. Merry /* XXX KDM what should the real number be here? */ 161130f4520SKenneth D. Merry fe->num_requested_ctl_io = 4096; 162130f4520SKenneth D. Merry snprintf(softc->port_name, sizeof(softc->port_name), "ctl2cam"); 163130f4520SKenneth D. Merry fe->port_name = softc->port_name; 164130f4520SKenneth D. Merry fe->port_online = cfcs_online; 165130f4520SKenneth D. Merry fe->port_offline = cfcs_offline; 166130f4520SKenneth D. Merry fe->onoff_arg = softc; 167130f4520SKenneth D. Merry fe->targ_enable = cfcs_targ_enable; 168130f4520SKenneth D. Merry fe->targ_disable = cfcs_targ_disable; 169130f4520SKenneth D. Merry fe->lun_enable = cfcs_lun_enable; 170130f4520SKenneth D. Merry fe->lun_disable = cfcs_lun_disable; 171130f4520SKenneth D. Merry fe->targ_lun_arg = softc; 172130f4520SKenneth D. Merry fe->fe_datamove = cfcs_datamove; 173130f4520SKenneth D. Merry fe->fe_done = cfcs_done; 174130f4520SKenneth D. Merry 175130f4520SKenneth D. Merry /* XXX KDM what should we report here? */ 176130f4520SKenneth D. Merry /* XXX These should probably be fetched from CTL. */ 177130f4520SKenneth D. Merry fe->max_targets = 1; 178130f4520SKenneth D. Merry fe->max_target_id = 15; 179130f4520SKenneth D. Merry 180130f4520SKenneth D. Merry retval = ctl_frontend_register(fe, /*master_SC*/ 1); 181130f4520SKenneth D. Merry if (retval != 0) { 182130f4520SKenneth D. Merry printf("%s: ctl_frontend_register() failed with error %d!\n", 183130f4520SKenneth D. Merry __func__, retval); 184e6ce97d1SAlexander Motin mtx_destroy(&softc->lock); 18532562145SEdward Tomasz Napierala return (retval); 186130f4520SKenneth D. Merry } 187130f4520SKenneth D. Merry 188130f4520SKenneth D. Merry /* 189130f4520SKenneth D. Merry * Get the WWNN out of the database, and create a WWPN as well. 190130f4520SKenneth D. Merry */ 191130f4520SKenneth D. Merry #ifdef NEEDTOPORT 192130f4520SKenneth D. Merry ddb_GetWWNN((char *)wwnn); 193130f4520SKenneth D. Merry softc->wwnn = be64dec(wwnn); 194130f4520SKenneth D. Merry softc->wwpn = softc->wwnn + (softc->fe.targ_port & 0xff); 195130f4520SKenneth D. Merry #endif 196130f4520SKenneth D. Merry 197130f4520SKenneth D. Merry /* 198130f4520SKenneth D. Merry * If the CTL frontend didn't tell us what our WWNN/WWPN is, go 199130f4520SKenneth D. Merry * ahead and set something random. 200130f4520SKenneth D. Merry */ 201130f4520SKenneth D. Merry if (fe->wwnn == 0) { 202130f4520SKenneth D. Merry uint64_t random_bits; 203130f4520SKenneth D. Merry 204130f4520SKenneth D. Merry arc4rand(&random_bits, sizeof(random_bits), 0); 205130f4520SKenneth D. Merry softc->wwnn = (random_bits & 0x0000000fffffff00ULL) | 206130f4520SKenneth D. Merry /* Company ID */ 0x5000000000000000ULL | 207130f4520SKenneth D. Merry /* NL-Port */ 0x0300; 208130f4520SKenneth D. Merry softc->wwpn = softc->wwnn + fe->targ_port + 1; 209130f4520SKenneth D. Merry fe->wwnn = softc->wwnn; 210130f4520SKenneth D. Merry fe->wwpn = softc->wwpn; 211130f4520SKenneth D. Merry } else { 212130f4520SKenneth D. Merry softc->wwnn = fe->wwnn; 213130f4520SKenneth D. Merry softc->wwpn = fe->wwpn; 214130f4520SKenneth D. Merry } 215130f4520SKenneth D. Merry 216e6ce97d1SAlexander Motin mtx_lock(&softc->lock); 217130f4520SKenneth D. Merry softc->devq = cam_simq_alloc(fe->num_requested_ctl_io); 218130f4520SKenneth D. Merry if (softc->devq == NULL) { 219130f4520SKenneth D. Merry printf("%s: error allocating devq\n", __func__); 220130f4520SKenneth D. Merry retval = ENOMEM; 221130f4520SKenneth D. Merry goto bailout; 222130f4520SKenneth D. Merry } 223130f4520SKenneth D. Merry 224130f4520SKenneth D. Merry softc->sim = cam_sim_alloc(cfcs_action, cfcs_poll, softc->port_name, 225130f4520SKenneth D. Merry softc, /*unit*/ 0, &softc->lock, 1, 226130f4520SKenneth D. Merry fe->num_requested_ctl_io, softc->devq); 227130f4520SKenneth D. Merry if (softc->sim == NULL) { 228130f4520SKenneth D. Merry printf("%s: error allocating SIM\n", __func__); 229130f4520SKenneth D. Merry retval = ENOMEM; 230130f4520SKenneth D. Merry goto bailout; 231130f4520SKenneth D. Merry } 232130f4520SKenneth D. Merry 233130f4520SKenneth D. Merry if (xpt_bus_register(softc->sim, NULL, 0) != CAM_SUCCESS) { 234130f4520SKenneth D. Merry printf("%s: error registering SIM\n", __func__); 235130f4520SKenneth D. Merry retval = ENOMEM; 236130f4520SKenneth D. Merry goto bailout; 237130f4520SKenneth D. Merry } 238130f4520SKenneth D. Merry 239130f4520SKenneth D. Merry if (xpt_create_path(&softc->path, /*periph*/NULL, 240130f4520SKenneth D. Merry cam_sim_path(softc->sim), 241130f4520SKenneth D. Merry CAM_TARGET_WILDCARD, 242130f4520SKenneth D. Merry CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 243130f4520SKenneth D. Merry printf("%s: error creating path\n", __func__); 244130f4520SKenneth D. Merry xpt_bus_deregister(cam_sim_path(softc->sim)); 24532562145SEdward Tomasz Napierala retval = EINVAL; 246130f4520SKenneth D. Merry goto bailout; 247130f4520SKenneth D. Merry } 248130f4520SKenneth D. Merry 24915a2601bSAlexander Motin xpt_setup_ccb(&csa.ccb_h, softc->path, CAM_PRIORITY_NONE); 250130f4520SKenneth D. Merry csa.ccb_h.func_code = XPT_SASYNC_CB; 251130f4520SKenneth D. Merry csa.event_enable = AC_LOST_DEVICE; 252130f4520SKenneth D. Merry csa.callback = cfcs_async; 253130f4520SKenneth D. Merry csa.callback_arg = softc->sim; 254130f4520SKenneth D. Merry xpt_action((union ccb *)&csa); 255130f4520SKenneth D. Merry 256e6ce97d1SAlexander Motin mtx_unlock(&softc->lock); 257e6ce97d1SAlexander Motin 258130f4520SKenneth D. Merry return (retval); 259130f4520SKenneth D. Merry 260130f4520SKenneth D. Merry bailout: 261130f4520SKenneth D. Merry if (softc->sim) 262130f4520SKenneth D. Merry cam_sim_free(softc->sim, /*free_devq*/ TRUE); 263130f4520SKenneth D. Merry else if (softc->devq) 264130f4520SKenneth D. Merry cam_simq_free(softc->devq); 265e6ce97d1SAlexander Motin mtx_unlock(&softc->lock); 266e6ce97d1SAlexander Motin mtx_destroy(&softc->lock); 267130f4520SKenneth D. Merry 268130f4520SKenneth D. Merry return (retval); 269130f4520SKenneth D. Merry } 270130f4520SKenneth D. Merry 271130f4520SKenneth D. Merry static void 272130f4520SKenneth D. Merry cfcs_poll(struct cam_sim *sim) 273130f4520SKenneth D. Merry { 274130f4520SKenneth D. Merry 275130f4520SKenneth D. Merry } 276130f4520SKenneth D. Merry 277130f4520SKenneth D. Merry void 278130f4520SKenneth D. Merry cfcs_shutdown(void) 279130f4520SKenneth D. Merry { 280130f4520SKenneth D. Merry 281130f4520SKenneth D. Merry } 282130f4520SKenneth D. Merry 28332562145SEdward Tomasz Napierala static int 28432562145SEdward Tomasz Napierala cfcs_module_event_handler(module_t mod, int what, void *arg) 28532562145SEdward Tomasz Napierala { 28632562145SEdward Tomasz Napierala 28732562145SEdward Tomasz Napierala switch (what) { 28832562145SEdward Tomasz Napierala case MOD_LOAD: 28932562145SEdward Tomasz Napierala return (cfcs_init()); 29032562145SEdward Tomasz Napierala case MOD_UNLOAD: 29132562145SEdward Tomasz Napierala return (EBUSY); 29232562145SEdward Tomasz Napierala default: 29332562145SEdward Tomasz Napierala return (EOPNOTSUPP); 29432562145SEdward Tomasz Napierala } 29532562145SEdward Tomasz Napierala } 29632562145SEdward Tomasz Napierala 297130f4520SKenneth D. Merry static void 29854f90e77SKenneth D. Merry cfcs_onoffline(void *arg, int online) 299130f4520SKenneth D. Merry { 300130f4520SKenneth D. Merry struct cfcs_softc *softc; 301130f4520SKenneth D. Merry union ccb *ccb; 302130f4520SKenneth D. Merry 303130f4520SKenneth D. Merry softc = (struct cfcs_softc *)arg; 304130f4520SKenneth D. Merry 305130f4520SKenneth D. Merry mtx_lock(&softc->lock); 30654f90e77SKenneth D. Merry softc->online = online; 307130f4520SKenneth D. Merry 308130f4520SKenneth D. Merry ccb = xpt_alloc_ccb_nowait(); 309130f4520SKenneth D. Merry if (ccb == NULL) { 310130f4520SKenneth D. Merry printf("%s: unable to allocate CCB for rescan\n", __func__); 31154f90e77SKenneth D. Merry goto bailout; 312130f4520SKenneth D. Merry } 313130f4520SKenneth D. Merry 314*e5dfa058SAlexander Motin if (xpt_create_path(&ccb->ccb_h.path, NULL, 315130f4520SKenneth D. Merry cam_sim_path(softc->sim), CAM_TARGET_WILDCARD, 316130f4520SKenneth D. Merry CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 317130f4520SKenneth D. Merry printf("%s: can't allocate path for rescan\n", __func__); 318130f4520SKenneth D. Merry xpt_free_ccb(ccb); 31954f90e77SKenneth D. Merry goto bailout; 320130f4520SKenneth D. Merry } 321130f4520SKenneth D. Merry xpt_rescan(ccb); 32254f90e77SKenneth D. Merry 32354f90e77SKenneth D. Merry bailout: 32454f90e77SKenneth D. Merry mtx_unlock(&softc->lock); 32554f90e77SKenneth D. Merry } 32654f90e77SKenneth D. Merry 32754f90e77SKenneth D. Merry static void 32854f90e77SKenneth D. Merry cfcs_online(void *arg) 32954f90e77SKenneth D. Merry { 33054f90e77SKenneth D. Merry cfcs_onoffline(arg, /*online*/ 1); 331130f4520SKenneth D. Merry } 332130f4520SKenneth D. Merry 333130f4520SKenneth D. Merry static void 334130f4520SKenneth D. Merry cfcs_offline(void *arg) 335130f4520SKenneth D. Merry { 33654f90e77SKenneth D. Merry cfcs_onoffline(arg, /*online*/ 0); 337130f4520SKenneth D. Merry } 338130f4520SKenneth D. Merry 339130f4520SKenneth D. Merry static int 340130f4520SKenneth D. Merry cfcs_targ_enable(void *arg, struct ctl_id targ_id) 341130f4520SKenneth D. Merry { 342130f4520SKenneth D. Merry return (0); 343130f4520SKenneth D. Merry } 344130f4520SKenneth D. Merry 345130f4520SKenneth D. Merry static int 346130f4520SKenneth D. Merry cfcs_targ_disable(void *arg, struct ctl_id targ_id) 347130f4520SKenneth D. Merry { 348130f4520SKenneth D. Merry return (0); 349130f4520SKenneth D. Merry } 350130f4520SKenneth D. Merry 351130f4520SKenneth D. Merry static int 352130f4520SKenneth D. Merry cfcs_lun_enable(void *arg, struct ctl_id target_id, int lun_id) 353130f4520SKenneth D. Merry { 354130f4520SKenneth D. Merry return (0); 355130f4520SKenneth D. Merry } 356130f4520SKenneth D. Merry static int 357130f4520SKenneth D. Merry cfcs_lun_disable(void *arg, struct ctl_id target_id, int lun_id) 358130f4520SKenneth D. Merry { 359130f4520SKenneth D. Merry return (0); 360130f4520SKenneth D. Merry } 361130f4520SKenneth D. Merry 362130f4520SKenneth D. Merry /* 363130f4520SKenneth D. Merry * This function is very similar to ctl_ioctl_do_datamove(). Is there a 364130f4520SKenneth D. Merry * way to combine the functionality? 365130f4520SKenneth D. Merry * 366130f4520SKenneth D. Merry * XXX KDM may need to move this into a thread. We're doing a bcopy in the 367130f4520SKenneth D. Merry * caller's context, which will usually be the backend. That may not be a 368130f4520SKenneth D. Merry * good thing. 369130f4520SKenneth D. Merry */ 370130f4520SKenneth D. Merry static void 371130f4520SKenneth D. Merry cfcs_datamove(union ctl_io *io) 372130f4520SKenneth D. Merry { 373130f4520SKenneth D. Merry union ccb *ccb; 374130f4520SKenneth D. Merry bus_dma_segment_t cam_sg_entry, *cam_sglist; 375130f4520SKenneth D. Merry struct ctl_sg_entry ctl_sg_entry, *ctl_sglist; 376130f4520SKenneth D. Merry int cam_sg_count, ctl_sg_count, cam_sg_start; 377130f4520SKenneth D. Merry int cam_sg_offset; 378130f4520SKenneth D. Merry int len_to_copy, len_copied; 379130f4520SKenneth D. Merry int ctl_watermark, cam_watermark; 380130f4520SKenneth D. Merry int i, j; 381130f4520SKenneth D. Merry 382130f4520SKenneth D. Merry 383130f4520SKenneth D. Merry cam_sg_offset = 0; 384130f4520SKenneth D. Merry cam_sg_start = 0; 385130f4520SKenneth D. Merry 386130f4520SKenneth D. Merry ccb = io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr; 387130f4520SKenneth D. Merry 388130f4520SKenneth D. Merry /* 389130f4520SKenneth D. Merry * Note that we have a check in cfcs_action() to make sure that any 390130f4520SKenneth D. Merry * CCBs with "bad" flags are returned with CAM_REQ_INVALID. This 391130f4520SKenneth D. Merry * is just to make sure no one removes that check without updating 392130f4520SKenneth D. Merry * this code to provide the additional functionality necessary to 393130f4520SKenneth D. Merry * support those modes of operation. 394130f4520SKenneth D. Merry */ 395130f4520SKenneth D. Merry KASSERT(((ccb->ccb_h.flags & CFCS_BAD_CCB_FLAGS) == 0), ("invalid " 396130f4520SKenneth D. Merry "CAM flags %#x", (ccb->ccb_h.flags & CFCS_BAD_CCB_FLAGS))); 397130f4520SKenneth D. Merry 398130f4520SKenneth D. Merry /* 399130f4520SKenneth D. Merry * Simplify things on both sides by putting single buffers into a 400130f4520SKenneth D. Merry * single entry S/G list. 401130f4520SKenneth D. Merry */ 402dd0b4fb6SKonstantin Belousov switch ((ccb->ccb_h.flags & CAM_DATA_MASK)) { 403dd0b4fb6SKonstantin Belousov case CAM_DATA_SG: { 404130f4520SKenneth D. Merry int len_seen; 405130f4520SKenneth D. Merry 406130f4520SKenneth D. Merry cam_sglist = (bus_dma_segment_t *)ccb->csio.data_ptr; 407130f4520SKenneth D. Merry cam_sg_count = ccb->csio.sglist_cnt; 408130f4520SKenneth D. Merry 409130f4520SKenneth D. Merry for (i = 0, len_seen = 0; i < cam_sg_count; i++) { 410130f4520SKenneth D. Merry if ((len_seen + cam_sglist[i].ds_len) >= 411130f4520SKenneth D. Merry io->scsiio.kern_rel_offset) { 412130f4520SKenneth D. Merry cam_sg_start = i; 413dd0b4fb6SKonstantin Belousov cam_sg_offset = io->scsiio.kern_rel_offset - 414130f4520SKenneth D. Merry len_seen; 415130f4520SKenneth D. Merry break; 416130f4520SKenneth D. Merry } 417130f4520SKenneth D. Merry len_seen += cam_sglist[i].ds_len; 418130f4520SKenneth D. Merry } 419dd0b4fb6SKonstantin Belousov break; 420130f4520SKenneth D. Merry } 421dd0b4fb6SKonstantin Belousov case CAM_DATA_VADDR: 422130f4520SKenneth D. Merry cam_sglist = &cam_sg_entry; 423130f4520SKenneth D. Merry cam_sglist[0].ds_len = ccb->csio.dxfer_len; 424130f4520SKenneth D. Merry cam_sglist[0].ds_addr = (bus_addr_t)ccb->csio.data_ptr; 425130f4520SKenneth D. Merry cam_sg_count = 1; 426130f4520SKenneth D. Merry cam_sg_start = 0; 427130f4520SKenneth D. Merry cam_sg_offset = io->scsiio.kern_rel_offset; 428dd0b4fb6SKonstantin Belousov break; 429dd0b4fb6SKonstantin Belousov default: 430dd0b4fb6SKonstantin Belousov panic("Invalid CAM flags %#x", ccb->ccb_h.flags); 431130f4520SKenneth D. Merry } 432130f4520SKenneth D. Merry 433130f4520SKenneth D. Merry if (io->scsiio.kern_sg_entries > 0) { 434130f4520SKenneth D. Merry ctl_sglist = (struct ctl_sg_entry *)io->scsiio.kern_data_ptr; 435130f4520SKenneth D. Merry ctl_sg_count = io->scsiio.kern_sg_entries; 436130f4520SKenneth D. Merry } else { 437130f4520SKenneth D. Merry ctl_sglist = &ctl_sg_entry; 438130f4520SKenneth D. Merry ctl_sglist->addr = io->scsiio.kern_data_ptr; 439130f4520SKenneth D. Merry ctl_sglist->len = io->scsiio.kern_data_len; 440130f4520SKenneth D. Merry ctl_sg_count = 1; 441130f4520SKenneth D. Merry } 442130f4520SKenneth D. Merry 443130f4520SKenneth D. Merry ctl_watermark = 0; 444130f4520SKenneth D. Merry cam_watermark = cam_sg_offset; 445130f4520SKenneth D. Merry len_copied = 0; 446130f4520SKenneth D. Merry for (i = cam_sg_start, j = 0; 447130f4520SKenneth D. Merry i < cam_sg_count && j < ctl_sg_count;) { 448130f4520SKenneth D. Merry uint8_t *cam_ptr, *ctl_ptr; 449130f4520SKenneth D. Merry 450130f4520SKenneth D. Merry len_to_copy = ctl_min(cam_sglist[i].ds_len - cam_watermark, 451130f4520SKenneth D. Merry ctl_sglist[j].len - ctl_watermark); 452130f4520SKenneth D. Merry 453130f4520SKenneth D. Merry cam_ptr = (uint8_t *)cam_sglist[i].ds_addr; 454130f4520SKenneth D. Merry cam_ptr = cam_ptr + cam_watermark; 455130f4520SKenneth D. Merry if (io->io_hdr.flags & CTL_FLAG_BUS_ADDR) { 456130f4520SKenneth D. Merry /* 457130f4520SKenneth D. Merry * XXX KDM fix this! 458130f4520SKenneth D. Merry */ 459130f4520SKenneth D. Merry panic("need to implement bus address support"); 460130f4520SKenneth D. Merry #if 0 461130f4520SKenneth D. Merry kern_ptr = bus_to_virt(kern_sglist[j].addr); 462130f4520SKenneth D. Merry #endif 463130f4520SKenneth D. Merry } else 464130f4520SKenneth D. Merry ctl_ptr = (uint8_t *)ctl_sglist[j].addr; 465130f4520SKenneth D. Merry ctl_ptr = ctl_ptr + ctl_watermark; 466130f4520SKenneth D. Merry 467130f4520SKenneth D. Merry ctl_watermark += len_to_copy; 468130f4520SKenneth D. Merry cam_watermark += len_to_copy; 469130f4520SKenneth D. Merry 470130f4520SKenneth D. Merry if ((io->io_hdr.flags & CTL_FLAG_DATA_MASK) == 471130f4520SKenneth D. Merry CTL_FLAG_DATA_IN) { 472130f4520SKenneth D. Merry CTL_DEBUG_PRINT(("%s: copying %d bytes to CAM\n", 473130f4520SKenneth D. Merry __func__, len_to_copy)); 474130f4520SKenneth D. Merry CTL_DEBUG_PRINT(("%s: from %p to %p\n", ctl_ptr, 475130f4520SKenneth D. Merry __func__, cam_ptr)); 476130f4520SKenneth D. Merry bcopy(ctl_ptr, cam_ptr, len_to_copy); 477130f4520SKenneth D. Merry } else { 478130f4520SKenneth D. Merry CTL_DEBUG_PRINT(("%s: copying %d bytes from CAM\n", 479130f4520SKenneth D. Merry __func__, len_to_copy)); 480130f4520SKenneth D. Merry CTL_DEBUG_PRINT(("%s: from %p to %p\n", cam_ptr, 481130f4520SKenneth D. Merry __func__, ctl_ptr)); 482130f4520SKenneth D. Merry bcopy(cam_ptr, ctl_ptr, len_to_copy); 483130f4520SKenneth D. Merry } 484130f4520SKenneth D. Merry 485130f4520SKenneth D. Merry len_copied += len_to_copy; 486130f4520SKenneth D. Merry 487130f4520SKenneth D. Merry if (cam_sglist[i].ds_len == cam_watermark) { 488130f4520SKenneth D. Merry i++; 489130f4520SKenneth D. Merry cam_watermark = 0; 490130f4520SKenneth D. Merry } 491130f4520SKenneth D. Merry 492130f4520SKenneth D. Merry if (ctl_sglist[j].len == ctl_watermark) { 493130f4520SKenneth D. Merry j++; 494130f4520SKenneth D. Merry ctl_watermark = 0; 495130f4520SKenneth D. Merry } 496130f4520SKenneth D. Merry } 497130f4520SKenneth D. Merry 498130f4520SKenneth D. Merry io->scsiio.ext_data_filled += len_copied; 499130f4520SKenneth D. Merry 500130f4520SKenneth D. Merry io->scsiio.be_move_done(io); 501130f4520SKenneth D. Merry } 502130f4520SKenneth D. Merry 503130f4520SKenneth D. Merry static void 504130f4520SKenneth D. Merry cfcs_done(union ctl_io *io) 505130f4520SKenneth D. Merry { 506130f4520SKenneth D. Merry union ccb *ccb; 507130f4520SKenneth D. Merry struct cfcs_softc *softc; 508130f4520SKenneth D. Merry struct cam_sim *sim; 509130f4520SKenneth D. Merry 510130f4520SKenneth D. Merry ccb = io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr; 511130f4520SKenneth D. Merry 512130f4520SKenneth D. Merry sim = xpt_path_sim(ccb->ccb_h.path); 513130f4520SKenneth D. Merry softc = (struct cfcs_softc *)cam_sim_softc(sim); 514130f4520SKenneth D. Merry 515130f4520SKenneth D. Merry /* 516130f4520SKenneth D. Merry * At this point we should have status. If we don't, that's a bug. 517130f4520SKenneth D. Merry */ 518130f4520SKenneth D. Merry KASSERT(((io->io_hdr.status & CTL_STATUS_MASK) != CTL_STATUS_NONE), 519130f4520SKenneth D. Merry ("invalid CTL status %#x", io->io_hdr.status)); 520130f4520SKenneth D. Merry 521130f4520SKenneth D. Merry /* 522130f4520SKenneth D. Merry * Translate CTL status to CAM status. 523130f4520SKenneth D. Merry */ 524130f4520SKenneth D. Merry switch (io->io_hdr.status & CTL_STATUS_MASK) { 525130f4520SKenneth D. Merry case CTL_SUCCESS: 526130f4520SKenneth D. Merry ccb->ccb_h.status = CAM_REQ_CMP; 527130f4520SKenneth D. Merry break; 528130f4520SKenneth D. Merry case CTL_SCSI_ERROR: 529130f4520SKenneth D. Merry ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR | CAM_AUTOSNS_VALID; 530130f4520SKenneth D. Merry ccb->csio.scsi_status = io->scsiio.scsi_status; 531130f4520SKenneth D. Merry bcopy(&io->scsiio.sense_data, &ccb->csio.sense_data, 532130f4520SKenneth D. Merry min(io->scsiio.sense_len, ccb->csio.sense_len)); 533130f4520SKenneth D. Merry if (ccb->csio.sense_len > io->scsiio.sense_len) 534130f4520SKenneth D. Merry ccb->csio.sense_resid = ccb->csio.sense_len - 535130f4520SKenneth D. Merry io->scsiio.sense_len; 536130f4520SKenneth D. Merry else 537130f4520SKenneth D. Merry ccb->csio.sense_resid = 0; 538130f4520SKenneth D. Merry if ((ccb->csio.sense_len - ccb->csio.sense_resid) > 539130f4520SKenneth D. Merry cfcs_max_sense) { 540130f4520SKenneth D. Merry ccb->csio.sense_resid = ccb->csio.sense_len - 541130f4520SKenneth D. Merry cfcs_max_sense; 542130f4520SKenneth D. Merry } 543130f4520SKenneth D. Merry break; 544130f4520SKenneth D. Merry case CTL_CMD_ABORTED: 545130f4520SKenneth D. Merry ccb->ccb_h.status = CAM_REQ_ABORTED; 546130f4520SKenneth D. Merry break; 547130f4520SKenneth D. Merry case CTL_ERROR: 548130f4520SKenneth D. Merry default: 549130f4520SKenneth D. Merry ccb->ccb_h.status = CAM_REQ_CMP_ERR; 550130f4520SKenneth D. Merry break; 551130f4520SKenneth D. Merry } 552130f4520SKenneth D. Merry 553130f4520SKenneth D. Merry mtx_lock(sim->mtx); 554130f4520SKenneth D. Merry xpt_done(ccb); 555130f4520SKenneth D. Merry mtx_unlock(sim->mtx); 556130f4520SKenneth D. Merry 557130f4520SKenneth D. Merry ctl_free_io(io); 558130f4520SKenneth D. Merry } 559130f4520SKenneth D. Merry 560130f4520SKenneth D. Merry void 561130f4520SKenneth D. Merry cfcs_action(struct cam_sim *sim, union ccb *ccb) 562130f4520SKenneth D. Merry { 563130f4520SKenneth D. Merry struct cfcs_softc *softc; 564130f4520SKenneth D. Merry int err; 565130f4520SKenneth D. Merry 566130f4520SKenneth D. Merry softc = (struct cfcs_softc *)cam_sim_softc(sim); 567130f4520SKenneth D. Merry mtx_assert(&softc->lock, MA_OWNED); 568130f4520SKenneth D. Merry 569130f4520SKenneth D. Merry switch (ccb->ccb_h.func_code) { 570130f4520SKenneth D. Merry case XPT_SCSI_IO: { 571130f4520SKenneth D. Merry union ctl_io *io; 572130f4520SKenneth D. Merry struct ccb_scsiio *csio; 573130f4520SKenneth D. Merry 574130f4520SKenneth D. Merry csio = &ccb->csio; 575130f4520SKenneth D. Merry 576130f4520SKenneth D. Merry /* 577130f4520SKenneth D. Merry * Catch CCB flags, like physical address flags, that 578130f4520SKenneth D. Merry * indicate situations we currently can't handle. 579130f4520SKenneth D. Merry */ 580130f4520SKenneth D. Merry if (ccb->ccb_h.flags & CFCS_BAD_CCB_FLAGS) { 581130f4520SKenneth D. Merry ccb->ccb_h.status = CAM_REQ_INVALID; 582130f4520SKenneth D. Merry printf("%s: bad CCB flags %#x (all flags %#x)\n", 583130f4520SKenneth D. Merry __func__, ccb->ccb_h.flags & CFCS_BAD_CCB_FLAGS, 584130f4520SKenneth D. Merry ccb->ccb_h.flags); 585130f4520SKenneth D. Merry xpt_done(ccb); 586130f4520SKenneth D. Merry return; 587130f4520SKenneth D. Merry } 588130f4520SKenneth D. Merry 589130f4520SKenneth D. Merry /* 590130f4520SKenneth D. Merry * If we aren't online, there are no devices to see. 591130f4520SKenneth D. Merry */ 592130f4520SKenneth D. Merry if (softc->online == 0) { 593130f4520SKenneth D. Merry ccb->ccb_h.status = CAM_DEV_NOT_THERE; 594130f4520SKenneth D. Merry xpt_done(ccb); 595130f4520SKenneth D. Merry return; 596130f4520SKenneth D. Merry } 597130f4520SKenneth D. Merry 598130f4520SKenneth D. Merry io = ctl_alloc_io(softc->fe.ctl_pool_ref); 599130f4520SKenneth D. Merry if (io == NULL) { 600130f4520SKenneth D. Merry printf("%s: can't allocate ctl_io\n", __func__); 601130f4520SKenneth D. Merry ccb->ccb_h.status = CAM_BUSY | CAM_DEV_QFRZN; 602130f4520SKenneth D. Merry xpt_freeze_devq(ccb->ccb_h.path, 1); 603130f4520SKenneth D. Merry xpt_done(ccb); 604130f4520SKenneth D. Merry return; 605130f4520SKenneth D. Merry } 606130f4520SKenneth D. Merry ctl_zero_io(io); 607130f4520SKenneth D. Merry /* Save pointers on both sides */ 608130f4520SKenneth D. Merry io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = ccb; 609130f4520SKenneth D. Merry ccb->ccb_h.io_ptr = io; 610130f4520SKenneth D. Merry 611130f4520SKenneth D. Merry /* 612130f4520SKenneth D. Merry * Only SCSI I/O comes down this path, resets, etc. come 613130f4520SKenneth D. Merry * down via the XPT_RESET_BUS/LUN CCBs below. 614130f4520SKenneth D. Merry */ 615130f4520SKenneth D. Merry io->io_hdr.io_type = CTL_IO_SCSI; 616130f4520SKenneth D. Merry io->io_hdr.nexus.initid.id = 1; 617130f4520SKenneth D. Merry io->io_hdr.nexus.targ_port = softc->fe.targ_port; 618130f4520SKenneth D. Merry /* 619130f4520SKenneth D. Merry * XXX KDM how do we handle target IDs? 620130f4520SKenneth D. Merry */ 621130f4520SKenneth D. Merry io->io_hdr.nexus.targ_target.id = ccb->ccb_h.target_id; 622130f4520SKenneth D. Merry io->io_hdr.nexus.targ_lun = ccb->ccb_h.target_lun; 623130f4520SKenneth D. Merry /* 624130f4520SKenneth D. Merry * This tag scheme isn't the best, since we could in theory 625130f4520SKenneth D. Merry * have a very long-lived I/O and tag collision, especially 626130f4520SKenneth D. Merry * in a high I/O environment. But it should work well 627130f4520SKenneth D. Merry * enough for now. Since we're using unsigned ints, 628130f4520SKenneth D. Merry * they'll just wrap around. 629130f4520SKenneth D. Merry */ 630130f4520SKenneth D. Merry io->scsiio.tag_num = softc->cur_tag_num++; 631130f4520SKenneth D. Merry csio->tag_id = io->scsiio.tag_num; 632130f4520SKenneth D. Merry switch (csio->tag_action) { 633130f4520SKenneth D. Merry case CAM_TAG_ACTION_NONE: 634130f4520SKenneth D. Merry io->scsiio.tag_type = CTL_TAG_UNTAGGED; 635130f4520SKenneth D. Merry break; 636130f4520SKenneth D. Merry case MSG_SIMPLE_TASK: 637130f4520SKenneth D. Merry io->scsiio.tag_type = CTL_TAG_SIMPLE; 638130f4520SKenneth D. Merry break; 639130f4520SKenneth D. Merry case MSG_HEAD_OF_QUEUE_TASK: 640130f4520SKenneth D. Merry io->scsiio.tag_type = CTL_TAG_HEAD_OF_QUEUE; 641130f4520SKenneth D. Merry break; 642130f4520SKenneth D. Merry case MSG_ORDERED_TASK: 643130f4520SKenneth D. Merry io->scsiio.tag_type = CTL_TAG_ORDERED; 644130f4520SKenneth D. Merry break; 645130f4520SKenneth D. Merry case MSG_ACA_TASK: 646130f4520SKenneth D. Merry io->scsiio.tag_type = CTL_TAG_ACA; 647130f4520SKenneth D. Merry break; 648130f4520SKenneth D. Merry default: 649130f4520SKenneth D. Merry io->scsiio.tag_type = CTL_TAG_UNTAGGED; 650130f4520SKenneth D. Merry printf("%s: unhandled tag type %#x!!\n", __func__, 651130f4520SKenneth D. Merry csio->tag_action); 652130f4520SKenneth D. Merry break; 653130f4520SKenneth D. Merry } 654130f4520SKenneth D. Merry if (csio->cdb_len > sizeof(io->scsiio.cdb)) { 655130f4520SKenneth D. Merry printf("%s: WARNING: CDB len %d > ctl_io space %zd\n", 656130f4520SKenneth D. Merry __func__, csio->cdb_len, sizeof(io->scsiio.cdb)); 657130f4520SKenneth D. Merry } 658130f4520SKenneth D. Merry io->scsiio.cdb_len = min(csio->cdb_len, sizeof(io->scsiio.cdb)); 659130f4520SKenneth D. Merry bcopy(csio->cdb_io.cdb_bytes, io->scsiio.cdb, 660130f4520SKenneth D. Merry io->scsiio.cdb_len); 661130f4520SKenneth D. Merry 662130f4520SKenneth D. Merry err = ctl_queue(io); 663130f4520SKenneth D. Merry if (err != CTL_RETVAL_COMPLETE) { 664130f4520SKenneth D. Merry printf("%s: func %d: error %d returned by " 665130f4520SKenneth D. Merry "ctl_queue()!\n", __func__, 666130f4520SKenneth D. Merry ccb->ccb_h.func_code, err); 667130f4520SKenneth D. Merry ctl_free_io(io); 668130f4520SKenneth D. Merry } else { 669130f4520SKenneth D. Merry ccb->ccb_h.status |= CAM_SIM_QUEUED; 670130f4520SKenneth D. Merry } 671130f4520SKenneth D. Merry break; 672130f4520SKenneth D. Merry } 673130f4520SKenneth D. Merry case XPT_ABORT: { 674130f4520SKenneth D. Merry union ctl_io *io; 675130f4520SKenneth D. Merry union ccb *abort_ccb; 676130f4520SKenneth D. Merry 677130f4520SKenneth D. Merry abort_ccb = ccb->cab.abort_ccb; 678130f4520SKenneth D. Merry 679130f4520SKenneth D. Merry if (abort_ccb->ccb_h.func_code != XPT_SCSI_IO) { 680130f4520SKenneth D. Merry ccb->ccb_h.status = CAM_REQ_INVALID; 681130f4520SKenneth D. Merry xpt_done(ccb); 682130f4520SKenneth D. Merry } 683130f4520SKenneth D. Merry 684130f4520SKenneth D. Merry /* 685130f4520SKenneth D. Merry * If we aren't online, there are no devices to talk to. 686130f4520SKenneth D. Merry */ 687130f4520SKenneth D. Merry if (softc->online == 0) { 688130f4520SKenneth D. Merry ccb->ccb_h.status = CAM_DEV_NOT_THERE; 689130f4520SKenneth D. Merry xpt_done(ccb); 690130f4520SKenneth D. Merry return; 691130f4520SKenneth D. Merry } 692130f4520SKenneth D. Merry 693130f4520SKenneth D. Merry io = ctl_alloc_io(softc->fe.ctl_pool_ref); 694130f4520SKenneth D. Merry if (io == NULL) { 695130f4520SKenneth D. Merry ccb->ccb_h.status = CAM_BUSY | CAM_DEV_QFRZN; 696130f4520SKenneth D. Merry xpt_freeze_devq(ccb->ccb_h.path, 1); 697130f4520SKenneth D. Merry xpt_done(ccb); 698130f4520SKenneth D. Merry return; 699130f4520SKenneth D. Merry } 700130f4520SKenneth D. Merry 701130f4520SKenneth D. Merry ctl_zero_io(io); 702130f4520SKenneth D. Merry /* Save pointers on both sides */ 703130f4520SKenneth D. Merry io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = ccb; 704130f4520SKenneth D. Merry ccb->ccb_h.io_ptr = io; 705130f4520SKenneth D. Merry 706130f4520SKenneth D. Merry io->io_hdr.io_type = CTL_IO_TASK; 707130f4520SKenneth D. Merry io->io_hdr.nexus.initid.id = 1; 708130f4520SKenneth D. Merry io->io_hdr.nexus.targ_port = softc->fe.targ_port; 709130f4520SKenneth D. Merry io->io_hdr.nexus.targ_target.id = ccb->ccb_h.target_id; 710130f4520SKenneth D. Merry io->io_hdr.nexus.targ_lun = ccb->ccb_h.target_lun; 711130f4520SKenneth D. Merry io->taskio.task_action = CTL_TASK_ABORT_TASK; 712130f4520SKenneth D. Merry io->taskio.tag_num = abort_ccb->csio.tag_id; 713130f4520SKenneth D. Merry switch (abort_ccb->csio.tag_action) { 714130f4520SKenneth D. Merry case CAM_TAG_ACTION_NONE: 715130f4520SKenneth D. Merry io->taskio.tag_type = CTL_TAG_UNTAGGED; 716130f4520SKenneth D. Merry break; 717130f4520SKenneth D. Merry case MSG_SIMPLE_TASK: 718130f4520SKenneth D. Merry io->taskio.tag_type = CTL_TAG_SIMPLE; 719130f4520SKenneth D. Merry break; 720130f4520SKenneth D. Merry case MSG_HEAD_OF_QUEUE_TASK: 721130f4520SKenneth D. Merry io->taskio.tag_type = CTL_TAG_HEAD_OF_QUEUE; 722130f4520SKenneth D. Merry break; 723130f4520SKenneth D. Merry case MSG_ORDERED_TASK: 724130f4520SKenneth D. Merry io->taskio.tag_type = CTL_TAG_ORDERED; 725130f4520SKenneth D. Merry break; 726130f4520SKenneth D. Merry case MSG_ACA_TASK: 727130f4520SKenneth D. Merry io->taskio.tag_type = CTL_TAG_ACA; 728130f4520SKenneth D. Merry break; 729130f4520SKenneth D. Merry default: 730130f4520SKenneth D. Merry io->taskio.tag_type = CTL_TAG_UNTAGGED; 731130f4520SKenneth D. Merry printf("%s: unhandled tag type %#x!!\n", __func__, 732130f4520SKenneth D. Merry abort_ccb->csio.tag_action); 733130f4520SKenneth D. Merry break; 734130f4520SKenneth D. Merry } 735130f4520SKenneth D. Merry err = ctl_queue(io); 736130f4520SKenneth D. Merry if (err != CTL_RETVAL_COMPLETE) { 737130f4520SKenneth D. Merry printf("%s func %d: error %d returned by " 738130f4520SKenneth D. Merry "ctl_queue()!\n", __func__, 739130f4520SKenneth D. Merry ccb->ccb_h.func_code, err); 740130f4520SKenneth D. Merry ctl_free_io(io); 741130f4520SKenneth D. Merry } 742130f4520SKenneth D. Merry break; 743130f4520SKenneth D. Merry } 744130f4520SKenneth D. Merry case XPT_GET_TRAN_SETTINGS: { 745130f4520SKenneth D. Merry struct ccb_trans_settings *cts; 746130f4520SKenneth D. Merry struct ccb_trans_settings_scsi *scsi; 747130f4520SKenneth D. Merry struct ccb_trans_settings_fc *fc; 748130f4520SKenneth D. Merry 749130f4520SKenneth D. Merry cts = &ccb->cts; 750130f4520SKenneth D. Merry scsi = &cts->proto_specific.scsi; 751130f4520SKenneth D. Merry fc = &cts->xport_specific.fc; 752130f4520SKenneth D. Merry 753130f4520SKenneth D. Merry 754130f4520SKenneth D. Merry cts->protocol = PROTO_SCSI; 755130f4520SKenneth D. Merry cts->protocol_version = SCSI_REV_SPC2; 756130f4520SKenneth D. Merry cts->transport = XPORT_FC; 757130f4520SKenneth D. Merry cts->transport_version = 0; 758130f4520SKenneth D. Merry 759130f4520SKenneth D. Merry scsi->valid = CTS_SCSI_VALID_TQ; 760130f4520SKenneth D. Merry scsi->flags = CTS_SCSI_FLAGS_TAG_ENB; 761130f4520SKenneth D. Merry fc->valid = CTS_FC_VALID_SPEED; 762130f4520SKenneth D. Merry fc->bitrate = 800000; 763130f4520SKenneth D. Merry fc->wwnn = softc->wwnn; 764130f4520SKenneth D. Merry fc->wwpn = softc->wwpn; 765130f4520SKenneth D. Merry fc->port = softc->fe.targ_port; 766130f4520SKenneth D. Merry fc->valid |= CTS_FC_VALID_WWNN | CTS_FC_VALID_WWPN | 767130f4520SKenneth D. Merry CTS_FC_VALID_PORT; 768130f4520SKenneth D. Merry ccb->ccb_h.status = CAM_REQ_CMP; 769130f4520SKenneth D. Merry break; 770130f4520SKenneth D. Merry } 771130f4520SKenneth D. Merry case XPT_SET_TRAN_SETTINGS: 772130f4520SKenneth D. Merry /* XXX KDM should we actually do something here? */ 773130f4520SKenneth D. Merry ccb->ccb_h.status = CAM_REQ_CMP; 774130f4520SKenneth D. Merry break; 775130f4520SKenneth D. Merry case XPT_RESET_BUS: 776130f4520SKenneth D. Merry case XPT_RESET_DEV: { 777130f4520SKenneth D. Merry union ctl_io *io; 778130f4520SKenneth D. Merry 779130f4520SKenneth D. Merry /* 780130f4520SKenneth D. Merry * If we aren't online, there are no devices to talk to. 781130f4520SKenneth D. Merry */ 782130f4520SKenneth D. Merry if (softc->online == 0) { 783130f4520SKenneth D. Merry ccb->ccb_h.status = CAM_DEV_NOT_THERE; 784130f4520SKenneth D. Merry xpt_done(ccb); 785130f4520SKenneth D. Merry return; 786130f4520SKenneth D. Merry } 787130f4520SKenneth D. Merry 788130f4520SKenneth D. Merry io = ctl_alloc_io(softc->fe.ctl_pool_ref); 789130f4520SKenneth D. Merry if (io == NULL) { 790130f4520SKenneth D. Merry ccb->ccb_h.status = CAM_BUSY | CAM_DEV_QFRZN; 791130f4520SKenneth D. Merry xpt_freeze_devq(ccb->ccb_h.path, 1); 792130f4520SKenneth D. Merry xpt_done(ccb); 793130f4520SKenneth D. Merry return; 794130f4520SKenneth D. Merry } 795130f4520SKenneth D. Merry 796130f4520SKenneth D. Merry ctl_zero_io(io); 797130f4520SKenneth D. Merry /* Save pointers on both sides */ 798130f4520SKenneth D. Merry io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = ccb; 799130f4520SKenneth D. Merry ccb->ccb_h.io_ptr = io; 800130f4520SKenneth D. Merry 801130f4520SKenneth D. Merry io->io_hdr.io_type = CTL_IO_TASK; 802130f4520SKenneth D. Merry io->io_hdr.nexus.initid.id = 0; 803130f4520SKenneth D. Merry io->io_hdr.nexus.targ_port = softc->fe.targ_port; 804130f4520SKenneth D. Merry io->io_hdr.nexus.targ_target.id = ccb->ccb_h.target_id; 805130f4520SKenneth D. Merry io->io_hdr.nexus.targ_lun = ccb->ccb_h.target_lun; 806130f4520SKenneth D. Merry if (ccb->ccb_h.func_code == XPT_RESET_BUS) 807130f4520SKenneth D. Merry io->taskio.task_action = CTL_TASK_BUS_RESET; 808130f4520SKenneth D. Merry else 809130f4520SKenneth D. Merry io->taskio.task_action = CTL_TASK_LUN_RESET; 810130f4520SKenneth D. Merry 811130f4520SKenneth D. Merry err = ctl_queue(io); 812130f4520SKenneth D. Merry if (err != CTL_RETVAL_COMPLETE) { 813130f4520SKenneth D. Merry printf("%s func %d: error %d returned by " 814130f4520SKenneth D. Merry "ctl_queue()!\n", __func__, 815130f4520SKenneth D. Merry ccb->ccb_h.func_code, err); 816130f4520SKenneth D. Merry ctl_free_io(io); 817130f4520SKenneth D. Merry } 818130f4520SKenneth D. Merry break; 819130f4520SKenneth D. Merry } 820130f4520SKenneth D. Merry case XPT_CALC_GEOMETRY: 821130f4520SKenneth D. Merry cam_calc_geometry(&ccb->ccg, 1); 822130f4520SKenneth D. Merry xpt_done(ccb); 823130f4520SKenneth D. Merry break; 824130f4520SKenneth D. Merry case XPT_PATH_INQ: { 825130f4520SKenneth D. Merry struct ccb_pathinq *cpi; 826130f4520SKenneth D. Merry 827130f4520SKenneth D. Merry cpi = &ccb->cpi; 828130f4520SKenneth D. Merry 829130f4520SKenneth D. Merry cpi->version_num = 0; 830130f4520SKenneth D. Merry cpi->hba_inquiry = PI_TAG_ABLE; 831130f4520SKenneth D. Merry cpi->target_sprt = 0; 832130f4520SKenneth D. Merry cpi->hba_misc = 0; 833130f4520SKenneth D. Merry cpi->hba_eng_cnt = 0; 834130f4520SKenneth D. Merry cpi->max_target = 1; 835130f4520SKenneth D. Merry cpi->max_lun = 1024; 836130f4520SKenneth D. Merry /* Do we really have a limit? */ 837130f4520SKenneth D. Merry cpi->maxio = 1024 * 1024; 838130f4520SKenneth D. Merry cpi->async_flags = 0; 839130f4520SKenneth D. Merry cpi->hpath_id = 0; 840130f4520SKenneth D. Merry cpi->initiator_id = 0; 841130f4520SKenneth D. Merry 842130f4520SKenneth D. Merry strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 843130f4520SKenneth D. Merry strncpy(cpi->hba_vid, "FreeBSD", HBA_IDLEN); 844130f4520SKenneth D. Merry strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 845130f4520SKenneth D. Merry cpi->unit_number = 0; 846130f4520SKenneth D. Merry cpi->bus_id = 0; 847130f4520SKenneth D. Merry cpi->base_transfer_speed = 800000; 848130f4520SKenneth D. Merry cpi->protocol = PROTO_SCSI; 849130f4520SKenneth D. Merry cpi->protocol_version = SCSI_REV_SPC2; 850130f4520SKenneth D. Merry /* 851130f4520SKenneth D. Merry * Pretend to be Fibre Channel. 852130f4520SKenneth D. Merry */ 853130f4520SKenneth D. Merry cpi->transport = XPORT_FC; 854130f4520SKenneth D. Merry cpi->transport_version = 0; 855130f4520SKenneth D. Merry cpi->xport_specific.fc.wwnn = softc->wwnn; 856130f4520SKenneth D. Merry cpi->xport_specific.fc.wwpn = softc->wwpn; 857130f4520SKenneth D. Merry cpi->xport_specific.fc.port = softc->fe.targ_port; 858130f4520SKenneth D. Merry cpi->xport_specific.fc.bitrate = 8 * 1000 * 1000; 859130f4520SKenneth D. Merry cpi->ccb_h.status = CAM_REQ_CMP; 860130f4520SKenneth D. Merry break; 861130f4520SKenneth D. Merry } 862130f4520SKenneth D. Merry default: 863130f4520SKenneth D. Merry ccb->ccb_h.status = CAM_PROVIDE_FAIL; 864130f4520SKenneth D. Merry printf("%s: unsupported CCB type %#x\n", __func__, 865130f4520SKenneth D. Merry ccb->ccb_h.func_code); 866130f4520SKenneth D. Merry xpt_done(ccb); 867130f4520SKenneth D. Merry break; 868130f4520SKenneth D. Merry } 869130f4520SKenneth D. Merry } 870130f4520SKenneth D. Merry 871130f4520SKenneth D. Merry static void 872130f4520SKenneth D. Merry cfcs_async(void *callback_arg, uint32_t code, struct cam_path *path, void *arg) 873130f4520SKenneth D. Merry { 874130f4520SKenneth D. Merry 875130f4520SKenneth D. Merry } 876