1130f4520SKenneth D. Merry /*- 24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 3bec9534dSPedro F. Giffuni * 4130f4520SKenneth D. Merry * Copyright (c) 2008, 2009 Silicon Graphics International Corp. 559f063d5SAlexander Motin * Copyright (c) 2014-2015 Alexander Motin <mav@FreeBSD.org> 6130f4520SKenneth D. Merry * All rights reserved. 7130f4520SKenneth D. Merry * 8130f4520SKenneth D. Merry * Redistribution and use in source and binary forms, with or without 9130f4520SKenneth D. Merry * modification, are permitted provided that the following conditions 10130f4520SKenneth D. Merry * are met: 11130f4520SKenneth D. Merry * 1. Redistributions of source code must retain the above copyright 12130f4520SKenneth D. Merry * notice, this list of conditions, and the following disclaimer, 13130f4520SKenneth D. Merry * without modification. 14130f4520SKenneth D. Merry * 2. Redistributions in binary form must reproduce at minimum a disclaimer 15130f4520SKenneth D. Merry * substantially similar to the "NO WARRANTY" disclaimer below 16130f4520SKenneth D. Merry * ("Disclaimer") and any redistribution must be conditioned upon 17130f4520SKenneth D. Merry * including a substantially similar Disclaimer requirement for further 18130f4520SKenneth D. Merry * binary redistribution. 19130f4520SKenneth D. Merry * 20130f4520SKenneth D. Merry * NO WARRANTY 21130f4520SKenneth D. Merry * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22130f4520SKenneth D. Merry * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23130f4520SKenneth D. Merry * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 24130f4520SKenneth D. Merry * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25130f4520SKenneth D. Merry * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26130f4520SKenneth D. Merry * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27130f4520SKenneth D. Merry * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28130f4520SKenneth D. Merry * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 29130f4520SKenneth D. Merry * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 30130f4520SKenneth D. Merry * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31130f4520SKenneth D. Merry * POSSIBILITY OF SUCH DAMAGES. 32130f4520SKenneth D. Merry * 33130f4520SKenneth D. Merry * $Id: //depot/users/kenm/FreeBSD-test2/sys/cam/ctl/scsi_ctl.c#4 $ 34130f4520SKenneth D. Merry */ 35130f4520SKenneth D. Merry /* 36130f4520SKenneth D. Merry * Peripheral driver interface between CAM and CTL (CAM Target Layer). 37130f4520SKenneth D. Merry * 38130f4520SKenneth D. Merry * Author: Ken Merry <ken@FreeBSD.org> 39130f4520SKenneth D. Merry */ 40130f4520SKenneth D. Merry 41130f4520SKenneth D. Merry #include <sys/param.h> 42130f4520SKenneth D. Merry #include <sys/queue.h> 43130f4520SKenneth D. Merry #include <sys/systm.h> 44130f4520SKenneth D. Merry #include <sys/kernel.h> 45130f4520SKenneth D. Merry #include <sys/lock.h> 46130f4520SKenneth D. Merry #include <sys/mutex.h> 47130f4520SKenneth D. Merry #include <sys/condvar.h> 48130f4520SKenneth D. Merry #include <sys/malloc.h> 49130f4520SKenneth D. Merry #include <sys/bus.h> 50130f4520SKenneth D. Merry #include <sys/endian.h> 51130f4520SKenneth D. Merry #include <sys/sbuf.h> 52130f4520SKenneth D. Merry #include <sys/sysctl.h> 53130f4520SKenneth D. Merry #include <sys/types.h> 54130f4520SKenneth D. Merry #include <sys/systm.h> 553afd4806SAlexander Motin #include <sys/taskqueue.h> 56130f4520SKenneth D. Merry #include <machine/bus.h> 57130f4520SKenneth D. Merry 58130f4520SKenneth D. Merry #include <cam/cam.h> 59130f4520SKenneth D. Merry #include <cam/cam_ccb.h> 60130f4520SKenneth D. Merry #include <cam/cam_periph.h> 61130f4520SKenneth D. Merry #include <cam/cam_queue.h> 62130f4520SKenneth D. Merry #include <cam/cam_xpt_periph.h> 63130f4520SKenneth D. Merry #include <cam/cam_debug.h> 64130f4520SKenneth D. Merry #include <cam/cam_sim.h> 65130f4520SKenneth D. Merry #include <cam/cam_xpt.h> 66130f4520SKenneth D. Merry 67130f4520SKenneth D. Merry #include <cam/scsi/scsi_all.h> 68130f4520SKenneth D. Merry #include <cam/scsi/scsi_message.h> 69130f4520SKenneth D. Merry 70130f4520SKenneth D. Merry #include <cam/ctl/ctl_io.h> 71130f4520SKenneth D. Merry #include <cam/ctl/ctl.h> 72130f4520SKenneth D. Merry #include <cam/ctl/ctl_frontend.h> 73130f4520SKenneth D. Merry #include <cam/ctl/ctl_util.h> 74130f4520SKenneth D. Merry #include <cam/ctl/ctl_error.h> 75130f4520SKenneth D. Merry 76130f4520SKenneth D. Merry struct ctlfe_softc { 7792168f4cSAlexander Motin struct ctl_port port; 78130f4520SKenneth D. Merry path_id_t path_id; 79d1f40587SAlexander Motin target_id_t target_id; 8059f063d5SAlexander Motin uint32_t hba_misc; 81acf5bea4SAlexander Motin u_int maxio; 82130f4520SKenneth D. Merry struct cam_sim *sim; 83130f4520SKenneth D. Merry char port_name[DEV_IDLEN]; 84227d67aaSAlexander Motin struct mtx lun_softc_mtx; 85130f4520SKenneth D. Merry STAILQ_HEAD(, ctlfe_lun_softc) lun_softc_list; 86130f4520SKenneth D. Merry STAILQ_ENTRY(ctlfe_softc) links; 87130f4520SKenneth D. Merry }; 88130f4520SKenneth D. Merry 89130f4520SKenneth D. Merry STAILQ_HEAD(, ctlfe_softc) ctlfe_softc_list; 90130f4520SKenneth D. Merry struct mtx ctlfe_list_mtx; 91130f4520SKenneth D. Merry static char ctlfe_mtx_desc[] = "ctlfelist"; 92130f4520SKenneth D. Merry 93130f4520SKenneth D. Merry typedef enum { 94130f4520SKenneth D. Merry CTLFE_LUN_NONE = 0x00, 95130f4520SKenneth D. Merry CTLFE_LUN_WILDCARD = 0x01 96130f4520SKenneth D. Merry } ctlfe_lun_flags; 97130f4520SKenneth D. Merry 98130f4520SKenneth D. Merry struct ctlfe_lun_softc { 99130f4520SKenneth D. Merry struct ctlfe_softc *parent_softc; 100130f4520SKenneth D. Merry struct cam_periph *periph; 101130f4520SKenneth D. Merry ctlfe_lun_flags flags; 1023afd4806SAlexander Motin int ctios_sent; /* Number of active CTIOs */ 1033afd4806SAlexander Motin int refcount; /* Number of active xpt_action() */ 1043afd4806SAlexander Motin int atios_alloced; /* Number of ATIOs not freed */ 1053afd4806SAlexander Motin int inots_alloced; /* Number of INOTs not freed */ 1063afd4806SAlexander Motin struct task refdrain_task; 107832529c5SAlexander Motin STAILQ_HEAD(, ccb_hdr) work_queue; 108ad0f05e6SAlexander Motin LIST_HEAD(, ccb_hdr) atio_list; /* List of ATIOs queued to SIM. */ 109ad0f05e6SAlexander Motin LIST_HEAD(, ccb_hdr) inot_list; /* List of INOTs queued to SIM. */ 110130f4520SKenneth D. Merry STAILQ_ENTRY(ctlfe_lun_softc) links; 111130f4520SKenneth D. Merry }; 112130f4520SKenneth D. Merry 113130f4520SKenneth D. Merry typedef enum { 114130f4520SKenneth D. Merry CTLFE_CMD_NONE = 0x00, 115130f4520SKenneth D. Merry CTLFE_CMD_PIECEWISE = 0x01 116130f4520SKenneth D. Merry } ctlfe_cmd_flags; 117130f4520SKenneth D. Merry 1187278725bSAlexander Motin struct ctlfe_cmd_info { 119130f4520SKenneth D. Merry int cur_transfer_index; 120acf5bea4SAlexander Motin size_t cur_transfer_off; 121130f4520SKenneth D. Merry ctlfe_cmd_flags flags; 122130f4520SKenneth D. Merry /* 123130f4520SKenneth D. Merry * XXX KDM struct bus_dma_segment is 8 bytes on i386, and 16 124130f4520SKenneth D. Merry * bytes on amd64. So with 32 elements, this is 256 bytes on 125130f4520SKenneth D. Merry * i386 and 512 bytes on amd64. 126130f4520SKenneth D. Merry */ 127acf5bea4SAlexander Motin #define CTLFE_MAX_SEGS 32 128acf5bea4SAlexander Motin bus_dma_segment_t cam_sglist[CTLFE_MAX_SEGS]; 129130f4520SKenneth D. Merry }; 130130f4520SKenneth D. Merry 131130f4520SKenneth D. Merry /* 132130f4520SKenneth D. Merry * When we register the adapter/bus, request that this many ctl_ios be 133130f4520SKenneth D. Merry * allocated. This should be the maximum supported by the adapter, but we 134130f4520SKenneth D. Merry * currently don't have a way to get that back from the path inquiry. 135130f4520SKenneth D. Merry * XXX KDM add that to the path inquiry. 136130f4520SKenneth D. Merry */ 137130f4520SKenneth D. Merry #define CTLFE_REQ_CTL_IO 4096 138130f4520SKenneth D. Merry /* 139130f4520SKenneth D. Merry * Number of Accept Target I/O CCBs to allocate and queue down to the 140130f4520SKenneth D. Merry * adapter per LUN. 141130f4520SKenneth D. Merry * XXX KDM should this be controlled by CTL? 142130f4520SKenneth D. Merry */ 143130f4520SKenneth D. Merry #define CTLFE_ATIO_PER_LUN 1024 144130f4520SKenneth D. Merry /* 145130f4520SKenneth D. Merry * Number of Immediate Notify CCBs (used for aborts, resets, etc.) to 146130f4520SKenneth D. Merry * allocate and queue down to the adapter per LUN. 147130f4520SKenneth D. Merry * XXX KDM should this be controlled by CTL? 148130f4520SKenneth D. Merry */ 149130f4520SKenneth D. Merry #define CTLFE_IN_PER_LUN 1024 150130f4520SKenneth D. Merry 151130f4520SKenneth D. Merry /* 15203ea6ef2SAlexander Motin * Timeout (in seconds) on CTIO CCB doing DMA or sending status 153130f4520SKenneth D. Merry */ 15403ea6ef2SAlexander Motin #define CTLFE_TIMEOUT 5 155130f4520SKenneth D. Merry 156130f4520SKenneth D. Merry /* 157130f4520SKenneth D. Merry * Turn this on to enable extra debugging prints. 158130f4520SKenneth D. Merry */ 159130f4520SKenneth D. Merry #if 0 160130f4520SKenneth D. Merry #define CTLFE_DEBUG 161130f4520SKenneth D. Merry #endif 162130f4520SKenneth D. Merry 163130f4520SKenneth D. Merry MALLOC_DEFINE(M_CTLFE, "CAM CTL FE", "CAM CTL FE interface"); 164130f4520SKenneth D. Merry 1651251a76bSAlexander Motin #define io_ptr ppriv_ptr0 166130f4520SKenneth D. Merry 167130f4520SKenneth D. Merry /* This is only used in the CTIO */ 168130f4520SKenneth D. Merry #define ccb_atio ppriv_ptr1 169130f4520SKenneth D. Merry 170e67ac203SAlexander Motin #define PRIV_CCB(io) ((io)->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptrs[0]) 171e67ac203SAlexander Motin #define PRIV_INFO(io) ((io)->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptrs[1]) 172e67ac203SAlexander Motin 1730c629e28SAlexander Motin static int ctlfeinitialize(void); 1740c629e28SAlexander Motin static int ctlfeshutdown(void); 17592168f4cSAlexander Motin static periph_init_t ctlfeperiphinit; 17694173c3cSAlexander Motin static periph_deinit_t ctlfeperiphdeinit; 177130f4520SKenneth D. Merry static void ctlfeasync(void *callback_arg, uint32_t code, 178130f4520SKenneth D. Merry struct cam_path *path, void *arg); 179130f4520SKenneth D. Merry static periph_ctor_t ctlferegister; 180130f4520SKenneth D. Merry static periph_oninv_t ctlfeoninvalidate; 181130f4520SKenneth D. Merry static periph_dtor_t ctlfecleanup; 182130f4520SKenneth D. Merry static periph_start_t ctlfestart; 183130f4520SKenneth D. Merry static void ctlfedone(struct cam_periph *periph, 184130f4520SKenneth D. Merry union ccb *done_ccb); 185130f4520SKenneth D. Merry 186130f4520SKenneth D. Merry static void ctlfe_onoffline(void *arg, int online); 187130f4520SKenneth D. Merry static void ctlfe_online(void *arg); 188130f4520SKenneth D. Merry static void ctlfe_offline(void *arg); 1897834ea88SAlexander Motin static int ctlfe_lun_enable(void *arg, int lun_id); 1907834ea88SAlexander Motin static int ctlfe_lun_disable(void *arg, int lun_id); 191130f4520SKenneth D. Merry static void ctlfe_dump_sim(struct cam_sim *sim); 192130f4520SKenneth D. Merry static void ctlfe_dump_queue(struct ctlfe_lun_softc *softc); 193993a751eSAlexander Motin static void ctlfe_datamove(union ctl_io *io); 194993a751eSAlexander Motin static void ctlfe_done(union ctl_io *io); 195130f4520SKenneth D. Merry static void ctlfe_dump(void); 196a504738fSAlexander Motin static void ctlfe_free_ccb(struct cam_periph *periph, 197a504738fSAlexander Motin union ccb *ccb); 198a504738fSAlexander Motin static void ctlfe_requeue_ccb(struct cam_periph *periph, 199a504738fSAlexander Motin union ccb *ccb, int unlock); 200130f4520SKenneth D. Merry 201130f4520SKenneth D. Merry static struct periph_driver ctlfe_driver = 202130f4520SKenneth D. Merry { 20392168f4cSAlexander Motin ctlfeperiphinit, "ctl", 204dc5362fdSAlexander Motin TAILQ_HEAD_INITIALIZER(ctlfe_driver.units), /*generation*/ 0, 20594173c3cSAlexander Motin CAM_PERIPH_DRV_EARLY, 20694173c3cSAlexander Motin ctlfeperiphdeinit 207130f4520SKenneth D. Merry }; 20832562145SEdward Tomasz Napierala 20992168f4cSAlexander Motin static struct ctl_frontend ctlfe_frontend = 21092168f4cSAlexander Motin { 2115c8dcc11SAlexander Motin .name = "camtgt", 21292168f4cSAlexander Motin .init = ctlfeinitialize, 21392168f4cSAlexander Motin .fe_dump = ctlfe_dump, 21492168f4cSAlexander Motin .shutdown = ctlfeshutdown, 21532562145SEdward Tomasz Napierala }; 21692168f4cSAlexander Motin CTL_FRONTEND_DECLARE(ctlfe, ctlfe_frontend); 217130f4520SKenneth D. Merry 2180c629e28SAlexander Motin static int 21992168f4cSAlexander Motin ctlfeinitialize(void) 22092168f4cSAlexander Motin { 22192168f4cSAlexander Motin 22292168f4cSAlexander Motin STAILQ_INIT(&ctlfe_softc_list); 22392168f4cSAlexander Motin mtx_init(&ctlfe_list_mtx, ctlfe_mtx_desc, NULL, MTX_DEF); 22492168f4cSAlexander Motin periphdriver_register(&ctlfe_driver); 22592168f4cSAlexander Motin return (0); 22692168f4cSAlexander Motin } 22792168f4cSAlexander Motin 22894173c3cSAlexander Motin static int 22994173c3cSAlexander Motin ctlfeshutdown(void) 23094173c3cSAlexander Motin { 23194173c3cSAlexander Motin int error; 23294173c3cSAlexander Motin 23394173c3cSAlexander Motin error = periphdriver_unregister(&ctlfe_driver); 23494173c3cSAlexander Motin if (error != 0) 23594173c3cSAlexander Motin return (error); 23694173c3cSAlexander Motin mtx_destroy(&ctlfe_list_mtx); 23794173c3cSAlexander Motin return (0); 23894173c3cSAlexander Motin } 23994173c3cSAlexander Motin 2400c629e28SAlexander Motin static void 24192168f4cSAlexander Motin ctlfeperiphinit(void) 242130f4520SKenneth D. Merry { 243130f4520SKenneth D. Merry cam_status status; 244130f4520SKenneth D. Merry 245130f4520SKenneth D. Merry status = xpt_register_async(AC_PATH_REGISTERED | AC_PATH_DEREGISTERED | 246130f4520SKenneth D. Merry AC_CONTRACT, ctlfeasync, NULL, NULL); 247130f4520SKenneth D. Merry if (status != CAM_REQ_CMP) { 248130f4520SKenneth D. Merry printf("ctl: Failed to attach async callback due to CAM " 249130f4520SKenneth D. Merry "status 0x%x!\n", status); 250130f4520SKenneth D. Merry } 251130f4520SKenneth D. Merry } 252130f4520SKenneth D. Merry 25394173c3cSAlexander Motin static int 25494173c3cSAlexander Motin ctlfeperiphdeinit(void) 25594173c3cSAlexander Motin { 25694173c3cSAlexander Motin 25794173c3cSAlexander Motin /* XXX: It would be good to tear down active ports here. */ 25894173c3cSAlexander Motin if (!TAILQ_EMPTY(&ctlfe_driver.units)) 25994173c3cSAlexander Motin return (EBUSY); 26094173c3cSAlexander Motin xpt_register_async(0, ctlfeasync, NULL, NULL); 26194173c3cSAlexander Motin return (0); 26294173c3cSAlexander Motin } 26394173c3cSAlexander Motin 264130f4520SKenneth D. Merry static void 265130f4520SKenneth D. Merry ctlfeasync(void *callback_arg, uint32_t code, struct cam_path *path, void *arg) 266130f4520SKenneth D. Merry { 2677d9cb4d9SAlexander Motin struct ctlfe_softc *softc; 268130f4520SKenneth D. Merry 269130f4520SKenneth D. Merry #ifdef CTLFEDEBUG 270130f4520SKenneth D. Merry printf("%s: entered\n", __func__); 271130f4520SKenneth D. Merry #endif 272130f4520SKenneth D. Merry 2737d9cb4d9SAlexander Motin mtx_lock(&ctlfe_list_mtx); 2747d9cb4d9SAlexander Motin STAILQ_FOREACH(softc, &ctlfe_softc_list, links) { 2757d9cb4d9SAlexander Motin if (softc->path_id == xpt_path_path_id(path)) 2767d9cb4d9SAlexander Motin break; 2777d9cb4d9SAlexander Motin } 2787d9cb4d9SAlexander Motin mtx_unlock(&ctlfe_list_mtx); 2797d9cb4d9SAlexander Motin 280130f4520SKenneth D. Merry /* 281130f4520SKenneth D. Merry * When a new path gets registered, and it is capable of target 282130f4520SKenneth D. Merry * mode, go ahead and attach. Later on, we may need to be more 283130f4520SKenneth D. Merry * selective, but for now this will be sufficient. 284130f4520SKenneth D. Merry */ 285130f4520SKenneth D. Merry switch (code) { 286130f4520SKenneth D. Merry case AC_PATH_REGISTERED: { 28792168f4cSAlexander Motin struct ctl_port *port; 288130f4520SKenneth D. Merry struct ccb_pathinq *cpi; 289130f4520SKenneth D. Merry int retval; 290130f4520SKenneth D. Merry 291130f4520SKenneth D. Merry cpi = (struct ccb_pathinq *)arg; 292130f4520SKenneth D. Merry 293130f4520SKenneth D. Merry /* Don't attach if it doesn't support target mode */ 294130f4520SKenneth D. Merry if ((cpi->target_sprt & PIT_PROCESSOR) == 0) { 295b87c6ae0SKenneth D. Merry #ifdef CTLFEDEBUG 296130f4520SKenneth D. Merry printf("%s: SIM %s%d doesn't support target mode\n", 297130f4520SKenneth D. Merry __func__, cpi->dev_name, cpi->unit_number); 298b87c6ae0SKenneth D. Merry #endif 299130f4520SKenneth D. Merry break; 300130f4520SKenneth D. Merry } 301130f4520SKenneth D. Merry 3027d9cb4d9SAlexander Motin if (softc != NULL) { 3037d9cb4d9SAlexander Motin #ifdef CTLFEDEBUG 3047d9cb4d9SAlexander Motin printf("%s: CTL port for CAM path %u already exists\n", 3057d9cb4d9SAlexander Motin __func__, xpt_path_path_id(path)); 3067d9cb4d9SAlexander Motin #endif 3077d9cb4d9SAlexander Motin break; 3087d9cb4d9SAlexander Motin } 3097d9cb4d9SAlexander Motin 310130f4520SKenneth D. Merry /* 311130f4520SKenneth D. Merry * We're in an interrupt context here, so we have to 312130f4520SKenneth D. Merry * use M_NOWAIT. Of course this means trouble if we 313130f4520SKenneth D. Merry * can't allocate memory. 314130f4520SKenneth D. Merry */ 3157d9cb4d9SAlexander Motin softc = malloc(sizeof(*softc), M_CTLFE, M_NOWAIT | M_ZERO); 3167d9cb4d9SAlexander Motin if (softc == NULL) { 317130f4520SKenneth D. Merry printf("%s: unable to malloc %zd bytes for softc\n", 3187d9cb4d9SAlexander Motin __func__, sizeof(*softc)); 319130f4520SKenneth D. Merry return; 320130f4520SKenneth D. Merry } 321130f4520SKenneth D. Merry 3227d9cb4d9SAlexander Motin softc->path_id = cpi->ccb_h.path_id; 323d1f40587SAlexander Motin softc->target_id = cpi->initiator_id; 3247d9cb4d9SAlexander Motin softc->sim = xpt_path_sim(path); 32559f063d5SAlexander Motin softc->hba_misc = cpi->hba_misc; 326acf5bea4SAlexander Motin if (cpi->maxio != 0) 3277d9cb4d9SAlexander Motin softc->maxio = cpi->maxio; 328acf5bea4SAlexander Motin else 3297d9cb4d9SAlexander Motin softc->maxio = DFLTPHYS; 3307d9cb4d9SAlexander Motin mtx_init(&softc->lun_softc_mtx, "LUN softc mtx", NULL, MTX_DEF); 3317d9cb4d9SAlexander Motin STAILQ_INIT(&softc->lun_softc_list); 332130f4520SKenneth D. Merry 3337d9cb4d9SAlexander Motin port = &softc->port; 33492168f4cSAlexander Motin port->frontend = &ctlfe_frontend; 335130f4520SKenneth D. Merry 336130f4520SKenneth D. Merry /* 337130f4520SKenneth D. Merry * XXX KDM should we be more accurate here ? 338130f4520SKenneth D. Merry */ 339130f4520SKenneth D. Merry if (cpi->transport == XPORT_FC) 34092168f4cSAlexander Motin port->port_type = CTL_PORT_FC; 3411e5a8b8fSAlexander Motin else if (cpi->transport == XPORT_SAS) 3421e5a8b8fSAlexander Motin port->port_type = CTL_PORT_SAS; 343130f4520SKenneth D. Merry else 34492168f4cSAlexander Motin port->port_type = CTL_PORT_SCSI; 345130f4520SKenneth D. Merry 346130f4520SKenneth D. Merry /* XXX KDM what should the real number be here? */ 34703ea6ef2SAlexander Motin port->num_requested_ctl_io = CTLFE_REQ_CTL_IO; 3487d9cb4d9SAlexander Motin snprintf(softc->port_name, sizeof(softc->port_name), 349130f4520SKenneth D. Merry "%s%d", cpi->dev_name, cpi->unit_number); 350130f4520SKenneth D. Merry /* 351130f4520SKenneth D. Merry * XXX KDM it would be nice to allocate storage in the 352130f4520SKenneth D. Merry * frontend structure itself. 353130f4520SKenneth D. Merry */ 3547d9cb4d9SAlexander Motin port->port_name = softc->port_name; 3559045dbb2SAlexander Motin port->physical_port = cpi->bus_id; 3569045dbb2SAlexander Motin port->virtual_port = 0; 35792168f4cSAlexander Motin port->port_online = ctlfe_online; 35892168f4cSAlexander Motin port->port_offline = ctlfe_offline; 3597d9cb4d9SAlexander Motin port->onoff_arg = softc; 36092168f4cSAlexander Motin port->lun_enable = ctlfe_lun_enable; 36192168f4cSAlexander Motin port->lun_disable = ctlfe_lun_disable; 3627d9cb4d9SAlexander Motin port->targ_lun_arg = softc; 363993a751eSAlexander Motin port->fe_datamove = ctlfe_datamove; 364993a751eSAlexander Motin port->fe_done = ctlfe_done; 3657ac58230SAlexander Motin port->targ_port = -1; 366130f4520SKenneth D. Merry 36723b30f56SAlexander Motin retval = ctl_port_register(port); 368130f4520SKenneth D. Merry if (retval != 0) { 36992168f4cSAlexander Motin printf("%s: ctl_port_register() failed with " 370130f4520SKenneth D. Merry "error %d!\n", __func__, retval); 3717d9cb4d9SAlexander Motin mtx_destroy(&softc->lun_softc_mtx); 3727d9cb4d9SAlexander Motin free(softc, M_CTLFE); 373130f4520SKenneth D. Merry break; 374130f4520SKenneth D. Merry } else { 375130f4520SKenneth D. Merry mtx_lock(&ctlfe_list_mtx); 3767d9cb4d9SAlexander Motin STAILQ_INSERT_TAIL(&ctlfe_softc_list, softc, links); 377130f4520SKenneth D. Merry mtx_unlock(&ctlfe_list_mtx); 378130f4520SKenneth D. Merry } 379130f4520SKenneth D. Merry 380130f4520SKenneth D. Merry break; 381130f4520SKenneth D. Merry } 382744c26b2SKenneth D. Merry case AC_PATH_DEREGISTERED: { 383744c26b2SKenneth D. Merry if (softc != NULL) { 384744c26b2SKenneth D. Merry /* 385744c26b2SKenneth D. Merry * XXX KDM are we certain at this point that there 386744c26b2SKenneth D. Merry * are no outstanding commands for this frontend? 387744c26b2SKenneth D. Merry */ 3887d9cb4d9SAlexander Motin mtx_lock(&ctlfe_list_mtx); 3897d9cb4d9SAlexander Motin STAILQ_REMOVE(&ctlfe_softc_list, softc, ctlfe_softc, 3907d9cb4d9SAlexander Motin links); 3917d9cb4d9SAlexander Motin mtx_unlock(&ctlfe_list_mtx); 39292168f4cSAlexander Motin ctl_port_deregister(&softc->port); 393227d67aaSAlexander Motin mtx_destroy(&softc->lun_softc_mtx); 394744c26b2SKenneth D. Merry free(softc, M_CTLFE); 395744c26b2SKenneth D. Merry } 396130f4520SKenneth D. Merry break; 397130f4520SKenneth D. Merry } 398130f4520SKenneth D. Merry case AC_CONTRACT: { 399130f4520SKenneth D. Merry struct ac_contract *ac; 400130f4520SKenneth D. Merry 401130f4520SKenneth D. Merry ac = (struct ac_contract *)arg; 402130f4520SKenneth D. Merry 403130f4520SKenneth D. Merry switch (ac->contract_number) { 404130f4520SKenneth D. Merry case AC_CONTRACT_DEV_CHG: { 405130f4520SKenneth D. Merry struct ac_device_changed *dev_chg; 4067d9cb4d9SAlexander Motin int retval; 407130f4520SKenneth D. Merry 408130f4520SKenneth D. Merry dev_chg = (struct ac_device_changed *)ac->contract_data; 409130f4520SKenneth D. Merry 4105a1ae35dSMatt Jacob printf("%s: WWPN %#jx port 0x%06x path %u target %u %s\n", 411130f4520SKenneth D. Merry __func__, dev_chg->wwpn, dev_chg->port, 412130f4520SKenneth D. Merry xpt_path_path_id(path), dev_chg->target, 413130f4520SKenneth D. Merry (dev_chg->arrived == 0) ? "left" : "arrived"); 414130f4520SKenneth D. Merry 4157d9cb4d9SAlexander Motin if (softc == NULL) { 416130f4520SKenneth D. Merry printf("%s: CTL port for CAM path %u not " 417130f4520SKenneth D. Merry "found!\n", __func__, 418130f4520SKenneth D. Merry xpt_path_path_id(path)); 419130f4520SKenneth D. Merry break; 420130f4520SKenneth D. Merry } 421130f4520SKenneth D. Merry if (dev_chg->arrived != 0) { 422604e2579SAlexander Motin retval = ctl_add_initiator(&softc->port, 423604e2579SAlexander Motin dev_chg->target, dev_chg->wwpn, NULL); 424130f4520SKenneth D. Merry } else { 425604e2579SAlexander Motin retval = ctl_remove_initiator(&softc->port, 426604e2579SAlexander Motin dev_chg->target); 427130f4520SKenneth D. Merry } 428130f4520SKenneth D. Merry 429604e2579SAlexander Motin if (retval < 0) { 430130f4520SKenneth D. Merry printf("%s: could not %s port %d iid %u " 431130f4520SKenneth D. Merry "WWPN %#jx!\n", __func__, 432130f4520SKenneth D. Merry (dev_chg->arrived != 0) ? "add" : 43392168f4cSAlexander Motin "remove", softc->port.targ_port, 434130f4520SKenneth D. Merry dev_chg->target, 435130f4520SKenneth D. Merry (uintmax_t)dev_chg->wwpn); 436130f4520SKenneth D. Merry } 437130f4520SKenneth D. Merry break; 438130f4520SKenneth D. Merry } 439130f4520SKenneth D. Merry default: 440130f4520SKenneth D. Merry printf("%s: unsupported contract number %ju\n", 441130f4520SKenneth D. Merry __func__, (uintmax_t)ac->contract_number); 442130f4520SKenneth D. Merry break; 443130f4520SKenneth D. Merry } 444130f4520SKenneth D. Merry break; 445130f4520SKenneth D. Merry } 446130f4520SKenneth D. Merry default: 447130f4520SKenneth D. Merry break; 448130f4520SKenneth D. Merry } 449130f4520SKenneth D. Merry } 450130f4520SKenneth D. Merry 451130f4520SKenneth D. Merry static cam_status 452130f4520SKenneth D. Merry ctlferegister(struct cam_periph *periph, void *arg) 453130f4520SKenneth D. Merry { 454130f4520SKenneth D. Merry struct ctlfe_softc *bus_softc; 455130f4520SKenneth D. Merry struct ctlfe_lun_softc *softc; 456ad0f05e6SAlexander Motin union ccb ccb; 457130f4520SKenneth D. Merry cam_status status; 45899e7a4adSScott Long int i, acstatus; 459130f4520SKenneth D. Merry 460130f4520SKenneth D. Merry softc = (struct ctlfe_lun_softc *)arg; 461130f4520SKenneth D. Merry bus_softc = softc->parent_softc; 462130f4520SKenneth D. Merry 463832529c5SAlexander Motin STAILQ_INIT(&softc->work_queue); 464ad0f05e6SAlexander Motin LIST_INIT(&softc->atio_list); 465ad0f05e6SAlexander Motin LIST_INIT(&softc->inot_list); 466130f4520SKenneth D. Merry softc->periph = periph; 467130f4520SKenneth D. Merry periph->softc = softc; 468130f4520SKenneth D. Merry 469b1303ffeSAlexander Motin /* Increase device openings to maximum for the SIM. */ 470b1303ffeSAlexander Motin if (bus_softc->sim->max_tagged_dev_openings > 471b1303ffeSAlexander Motin bus_softc->sim->max_dev_openings) { 472b1303ffeSAlexander Motin cam_release_devq(periph->path, 473b1303ffeSAlexander Motin /*relsim_flags*/RELSIM_ADJUST_OPENINGS, 474b1303ffeSAlexander Motin /*openings*/bus_softc->sim->max_tagged_dev_openings, 475b1303ffeSAlexander Motin /*timeout*/0, 476b1303ffeSAlexander Motin /*getcount_only*/1); 477b1303ffeSAlexander Motin } 478b1303ffeSAlexander Motin 479616a676aSEdward Tomasz Napierala memset(&ccb, 0, sizeof(ccb)); 480ad0f05e6SAlexander Motin xpt_setup_ccb(&ccb.ccb_h, periph->path, CAM_PRIORITY_NONE); 481ad0f05e6SAlexander Motin ccb.ccb_h.func_code = XPT_EN_LUN; 482ad0f05e6SAlexander Motin ccb.cel.grp6_len = 0; 483ad0f05e6SAlexander Motin ccb.cel.grp7_len = 0; 484ad0f05e6SAlexander Motin ccb.cel.enable = 1; 485ad0f05e6SAlexander Motin xpt_action(&ccb); 486ad0f05e6SAlexander Motin status = (ccb.ccb_h.status & CAM_STATUS_MASK); 487130f4520SKenneth D. Merry if (status != CAM_REQ_CMP) { 488130f4520SKenneth D. Merry xpt_print(periph->path, "%s: Enable LUN failed, status 0x%x\n", 489ad0f05e6SAlexander Motin __func__, ccb.ccb_h.status); 490130f4520SKenneth D. Merry return (status); 491130f4520SKenneth D. Merry } 492130f4520SKenneth D. Merry 493130f4520SKenneth D. Merry status = CAM_REQ_CMP; 494130f4520SKenneth D. Merry 495130f4520SKenneth D. Merry for (i = 0; i < CTLFE_ATIO_PER_LUN; i++) { 496130f4520SKenneth D. Merry union ccb *new_ccb; 4971251a76bSAlexander Motin union ctl_io *new_io; 4987278725bSAlexander Motin struct ctlfe_cmd_info *cmd_info; 499130f4520SKenneth D. Merry 500130f4520SKenneth D. Merry new_ccb = (union ccb *)malloc(sizeof(*new_ccb), M_CTLFE, 5015a1ae35dSMatt Jacob M_ZERO|M_NOWAIT); 502130f4520SKenneth D. Merry if (new_ccb == NULL) { 503130f4520SKenneth D. Merry status = CAM_RESRC_UNAVAIL; 504130f4520SKenneth D. Merry break; 505130f4520SKenneth D. Merry } 5061251a76bSAlexander Motin new_io = ctl_alloc_io_nowait(bus_softc->port.ctl_pool_ref); 5071251a76bSAlexander Motin if (new_io == NULL) { 5081251a76bSAlexander Motin free(new_ccb, M_CTLFE); 5091251a76bSAlexander Motin status = CAM_RESRC_UNAVAIL; 5101251a76bSAlexander Motin break; 5111251a76bSAlexander Motin } 5127278725bSAlexander Motin cmd_info = malloc(sizeof(*cmd_info), M_CTLFE, 5137278725bSAlexander Motin M_ZERO | M_NOWAIT); 5147278725bSAlexander Motin if (cmd_info == NULL) { 5157278725bSAlexander Motin ctl_free_io(new_io); 5167278725bSAlexander Motin free(new_ccb, M_CTLFE); 5177278725bSAlexander Motin status = CAM_RESRC_UNAVAIL; 5187278725bSAlexander Motin break; 5197278725bSAlexander Motin } 520e67ac203SAlexander Motin PRIV_INFO(new_io) = cmd_info; 521521db0acSAlexander Motin softc->atios_alloced++; 5221251a76bSAlexander Motin new_ccb->ccb_h.io_ptr = new_io; 523ad0f05e6SAlexander Motin LIST_INSERT_HEAD(&softc->atio_list, &new_ccb->ccb_h, periph_links.le); 5241251a76bSAlexander Motin 52586ce2be6SAlexander Motin xpt_setup_ccb(&new_ccb->ccb_h, periph->path, CAM_PRIORITY_NONE); 526130f4520SKenneth D. Merry new_ccb->ccb_h.func_code = XPT_ACCEPT_TARGET_IO; 527130f4520SKenneth D. Merry new_ccb->ccb_h.cbfcnp = ctlfedone; 528227d67aaSAlexander Motin new_ccb->ccb_h.flags |= CAM_UNLOCKED; 529130f4520SKenneth D. Merry xpt_action(new_ccb); 530130f4520SKenneth D. Merry status = new_ccb->ccb_h.status; 531130f4520SKenneth D. Merry if ((status & CAM_STATUS_MASK) != CAM_REQ_INPROG) { 5327278725bSAlexander Motin free(cmd_info, M_CTLFE); 5331251a76bSAlexander Motin ctl_free_io(new_io); 534130f4520SKenneth D. Merry free(new_ccb, M_CTLFE); 535130f4520SKenneth D. Merry break; 536130f4520SKenneth D. Merry } 537130f4520SKenneth D. Merry } 538130f4520SKenneth D. Merry 53999e7a4adSScott Long acstatus = cam_periph_acquire(periph); 54099e7a4adSScott Long if (acstatus != 0) { 541130f4520SKenneth D. Merry xpt_print(periph->path, "%s: could not acquire reference " 54299e7a4adSScott Long "count, status = %#x\n", __func__, acstatus); 54399e7a4adSScott Long return (CAM_REQ_CMP_ERR); 544130f4520SKenneth D. Merry } 545130f4520SKenneth D. Merry 546130f4520SKenneth D. Merry if (i == 0) { 547130f4520SKenneth D. Merry xpt_print(periph->path, "%s: could not allocate ATIO CCBs, " 548130f4520SKenneth D. Merry "status 0x%x\n", __func__, status); 549130f4520SKenneth D. Merry return (CAM_REQ_CMP_ERR); 550130f4520SKenneth D. Merry } 551130f4520SKenneth D. Merry 552130f4520SKenneth D. Merry for (i = 0; i < CTLFE_IN_PER_LUN; i++) { 553130f4520SKenneth D. Merry union ccb *new_ccb; 5541251a76bSAlexander Motin union ctl_io *new_io; 555130f4520SKenneth D. Merry 556130f4520SKenneth D. Merry new_ccb = (union ccb *)malloc(sizeof(*new_ccb), M_CTLFE, 5575a1ae35dSMatt Jacob M_ZERO|M_NOWAIT); 558130f4520SKenneth D. Merry if (new_ccb == NULL) { 559130f4520SKenneth D. Merry status = CAM_RESRC_UNAVAIL; 560130f4520SKenneth D. Merry break; 561130f4520SKenneth D. Merry } 5621251a76bSAlexander Motin new_io = ctl_alloc_io_nowait(bus_softc->port.ctl_pool_ref); 5631251a76bSAlexander Motin if (new_io == NULL) { 5641251a76bSAlexander Motin free(new_ccb, M_CTLFE); 5651251a76bSAlexander Motin status = CAM_RESRC_UNAVAIL; 5661251a76bSAlexander Motin break; 5671251a76bSAlexander Motin } 568521db0acSAlexander Motin softc->inots_alloced++; 5691251a76bSAlexander Motin new_ccb->ccb_h.io_ptr = new_io; 570ad0f05e6SAlexander Motin LIST_INSERT_HEAD(&softc->inot_list, &new_ccb->ccb_h, periph_links.le); 571130f4520SKenneth D. Merry 57286ce2be6SAlexander Motin xpt_setup_ccb(&new_ccb->ccb_h, periph->path, CAM_PRIORITY_NONE); 573130f4520SKenneth D. Merry new_ccb->ccb_h.func_code = XPT_IMMEDIATE_NOTIFY; 574130f4520SKenneth D. Merry new_ccb->ccb_h.cbfcnp = ctlfedone; 575227d67aaSAlexander Motin new_ccb->ccb_h.flags |= CAM_UNLOCKED; 576130f4520SKenneth D. Merry xpt_action(new_ccb); 577130f4520SKenneth D. Merry status = new_ccb->ccb_h.status; 578b79dc8a8SKenneth D. Merry if ((status & CAM_STATUS_MASK) != CAM_REQ_INPROG) { 579b79dc8a8SKenneth D. Merry /* 580b79dc8a8SKenneth D. Merry * Note that we don't free the CCB here. If the 581b79dc8a8SKenneth D. Merry * status is not CAM_REQ_INPROG, then we're 582b79dc8a8SKenneth D. Merry * probably talking to a SIM that says it is 583b79dc8a8SKenneth D. Merry * target-capable but doesn't support the 584b79dc8a8SKenneth D. Merry * XPT_IMMEDIATE_NOTIFY CCB. i.e. it supports the 585b79dc8a8SKenneth D. Merry * older API. In that case, it'll call xpt_done() 586b79dc8a8SKenneth D. Merry * on the CCB, and we need to free it in our done 587b79dc8a8SKenneth D. Merry * routine as a result. 588b79dc8a8SKenneth D. Merry */ 589130f4520SKenneth D. Merry break; 590130f4520SKenneth D. Merry } 591130f4520SKenneth D. Merry } 592b79dc8a8SKenneth D. Merry if ((i == 0) 593b79dc8a8SKenneth D. Merry || (status != CAM_REQ_INPROG)) { 594130f4520SKenneth D. Merry xpt_print(periph->path, "%s: could not allocate immediate " 595130f4520SKenneth D. Merry "notify CCBs, status 0x%x\n", __func__, status); 596130f4520SKenneth D. Merry return (CAM_REQ_CMP_ERR); 597130f4520SKenneth D. Merry } 5987511bd04SAlexander Motin mtx_lock(&bus_softc->lun_softc_mtx); 5997511bd04SAlexander Motin STAILQ_INSERT_TAIL(&bus_softc->lun_softc_list, softc, links); 6007511bd04SAlexander Motin mtx_unlock(&bus_softc->lun_softc_mtx); 601130f4520SKenneth D. Merry return (CAM_REQ_CMP); 602130f4520SKenneth D. Merry } 603130f4520SKenneth D. Merry 604130f4520SKenneth D. Merry static void 605130f4520SKenneth D. Merry ctlfeoninvalidate(struct cam_periph *periph) 606130f4520SKenneth D. Merry { 607ad0f05e6SAlexander Motin struct ctlfe_lun_softc *softc = (struct ctlfe_lun_softc *)periph->softc; 608227d67aaSAlexander Motin struct ctlfe_softc *bus_softc; 609ad0f05e6SAlexander Motin union ccb ccb; 610ad0f05e6SAlexander Motin struct ccb_hdr *hdr; 611ad0f05e6SAlexander Motin cam_status status; 612130f4520SKenneth D. Merry 613ad0f05e6SAlexander Motin /* Abort all ATIOs and INOTs queued to SIM. */ 614616a676aSEdward Tomasz Napierala memset(&ccb, 0, sizeof(ccb)); 615ad0f05e6SAlexander Motin xpt_setup_ccb(&ccb.ccb_h, periph->path, CAM_PRIORITY_NONE); 616ad0f05e6SAlexander Motin ccb.ccb_h.func_code = XPT_ABORT; 617ad0f05e6SAlexander Motin LIST_FOREACH(hdr, &softc->atio_list, periph_links.le) { 618ad0f05e6SAlexander Motin ccb.cab.abort_ccb = (union ccb *)hdr; 619ad0f05e6SAlexander Motin xpt_action(&ccb); 620ad0f05e6SAlexander Motin } 621ad0f05e6SAlexander Motin LIST_FOREACH(hdr, &softc->inot_list, periph_links.le) { 622ad0f05e6SAlexander Motin ccb.cab.abort_ccb = (union ccb *)hdr; 623ad0f05e6SAlexander Motin xpt_action(&ccb); 624ad0f05e6SAlexander Motin } 625130f4520SKenneth D. Merry 626ad0f05e6SAlexander Motin /* Disable the LUN in SIM. */ 627ad0f05e6SAlexander Motin ccb.ccb_h.func_code = XPT_EN_LUN; 628ad0f05e6SAlexander Motin ccb.cel.grp6_len = 0; 629ad0f05e6SAlexander Motin ccb.cel.grp7_len = 0; 630ad0f05e6SAlexander Motin ccb.cel.enable = 0; 631ad0f05e6SAlexander Motin xpt_action(&ccb); 632ad0f05e6SAlexander Motin status = (ccb.ccb_h.status & CAM_STATUS_MASK); 633130f4520SKenneth D. Merry if (status != CAM_REQ_CMP) { 634130f4520SKenneth D. Merry xpt_print(periph->path, "%s: Disable LUN failed, status 0x%x\n", 635ad0f05e6SAlexander Motin __func__, ccb.ccb_h.status); 636130f4520SKenneth D. Merry /* 637130f4520SKenneth D. Merry * XXX KDM what do we do now? 638130f4520SKenneth D. Merry */ 639130f4520SKenneth D. Merry } 640227d67aaSAlexander Motin 641227d67aaSAlexander Motin bus_softc = softc->parent_softc; 642227d67aaSAlexander Motin mtx_lock(&bus_softc->lun_softc_mtx); 643227d67aaSAlexander Motin STAILQ_REMOVE(&bus_softc->lun_softc_list, softc, ctlfe_lun_softc, links); 644227d67aaSAlexander Motin mtx_unlock(&bus_softc->lun_softc_mtx); 645130f4520SKenneth D. Merry } 646130f4520SKenneth D. Merry 647130f4520SKenneth D. Merry static void 648130f4520SKenneth D. Merry ctlfecleanup(struct cam_periph *periph) 649130f4520SKenneth D. Merry { 650130f4520SKenneth D. Merry struct ctlfe_lun_softc *softc; 651130f4520SKenneth D. Merry 652130f4520SKenneth D. Merry softc = (struct ctlfe_lun_softc *)periph->softc; 653130f4520SKenneth D. Merry 6543afd4806SAlexander Motin KASSERT(softc->ctios_sent == 0, ("%s: ctios_sent %d != 0", 6553afd4806SAlexander Motin __func__, softc->ctios_sent)); 6563afd4806SAlexander Motin KASSERT(softc->refcount == 0, ("%s: refcount %d != 0", 6573afd4806SAlexander Motin __func__, softc->refcount)); 6583afd4806SAlexander Motin KASSERT(softc->atios_alloced == 0, ("%s: atios_alloced %d != 0", 6593afd4806SAlexander Motin __func__, softc->atios_alloced)); 6603afd4806SAlexander Motin KASSERT(softc->inots_alloced == 0, ("%s: inots_alloced %d != 0", 6613afd4806SAlexander Motin __func__, softc->inots_alloced)); 662744c26b2SKenneth D. Merry 663130f4520SKenneth D. Merry free(softc, M_CTLFE); 664130f4520SKenneth D. Merry } 665130f4520SKenneth D. Merry 666130f4520SKenneth D. Merry static void 667acf5bea4SAlexander Motin ctlfedata(struct ctlfe_lun_softc *softc, union ctl_io *io, 668acf5bea4SAlexander Motin ccb_flags *flags, uint8_t **data_ptr, uint32_t *dxfer_len, 669a74530d9SWarner Losh uint16_t *sglist_cnt) 670acf5bea4SAlexander Motin { 671acf5bea4SAlexander Motin struct ctlfe_softc *bus_softc; 6727278725bSAlexander Motin struct ctlfe_cmd_info *cmd_info; 673acf5bea4SAlexander Motin struct ctl_sg_entry *ctl_sglist; 674acf5bea4SAlexander Motin bus_dma_segment_t *cam_sglist; 675acf5bea4SAlexander Motin size_t off; 676acf5bea4SAlexander Motin int i, idx; 677acf5bea4SAlexander Motin 678e67ac203SAlexander Motin cmd_info = PRIV_INFO(io); 679acf5bea4SAlexander Motin bus_softc = softc->parent_softc; 680acf5bea4SAlexander Motin 681acf5bea4SAlexander Motin /* 682acf5bea4SAlexander Motin * Set the direction, relative to the initiator. 683acf5bea4SAlexander Motin */ 684acf5bea4SAlexander Motin *flags &= ~CAM_DIR_MASK; 685acf5bea4SAlexander Motin if ((io->io_hdr.flags & CTL_FLAG_DATA_MASK) == CTL_FLAG_DATA_IN) 686acf5bea4SAlexander Motin *flags |= CAM_DIR_IN; 687acf5bea4SAlexander Motin else 688acf5bea4SAlexander Motin *flags |= CAM_DIR_OUT; 689acf5bea4SAlexander Motin 690acf5bea4SAlexander Motin *flags &= ~CAM_DATA_MASK; 691acf5bea4SAlexander Motin idx = cmd_info->cur_transfer_index; 692acf5bea4SAlexander Motin off = cmd_info->cur_transfer_off; 693acf5bea4SAlexander Motin cmd_info->flags &= ~CTLFE_CMD_PIECEWISE; 694eb6ac6f9SAlexander Motin if (io->scsiio.kern_sg_entries == 0) { /* No S/G list. */ 695eb6ac6f9SAlexander Motin 696eb6ac6f9SAlexander Motin /* One time shift for SRR offset. */ 697eb6ac6f9SAlexander Motin off += io->scsiio.ext_data_filled; 698eb6ac6f9SAlexander Motin io->scsiio.ext_data_filled = 0; 699eb6ac6f9SAlexander Motin 700acf5bea4SAlexander Motin *data_ptr = io->scsiio.kern_data_ptr + off; 701acf5bea4SAlexander Motin if (io->scsiio.kern_data_len - off <= bus_softc->maxio) { 702acf5bea4SAlexander Motin *dxfer_len = io->scsiio.kern_data_len - off; 703acf5bea4SAlexander Motin } else { 704acf5bea4SAlexander Motin *dxfer_len = bus_softc->maxio; 705eb6ac6f9SAlexander Motin cmd_info->cur_transfer_off += bus_softc->maxio; 706acf5bea4SAlexander Motin cmd_info->flags |= CTLFE_CMD_PIECEWISE; 707acf5bea4SAlexander Motin } 708acf5bea4SAlexander Motin *sglist_cnt = 0; 709acf5bea4SAlexander Motin 710acf5bea4SAlexander Motin if (io->io_hdr.flags & CTL_FLAG_BUS_ADDR) 711acf5bea4SAlexander Motin *flags |= CAM_DATA_PADDR; 712acf5bea4SAlexander Motin else 713acf5bea4SAlexander Motin *flags |= CAM_DATA_VADDR; 714eb6ac6f9SAlexander Motin } else { /* S/G list with physical or virtual pointers. */ 715acf5bea4SAlexander Motin ctl_sglist = (struct ctl_sg_entry *)io->scsiio.kern_data_ptr; 716eb6ac6f9SAlexander Motin 717eb6ac6f9SAlexander Motin /* One time shift for SRR offset. */ 718eb6ac6f9SAlexander Motin while (io->scsiio.ext_data_filled >= ctl_sglist[idx].len - off) { 719eb6ac6f9SAlexander Motin io->scsiio.ext_data_filled -= ctl_sglist[idx].len - off; 720eb6ac6f9SAlexander Motin idx++; 721eb6ac6f9SAlexander Motin off = 0; 722eb6ac6f9SAlexander Motin } 723eb6ac6f9SAlexander Motin off += io->scsiio.ext_data_filled; 724eb6ac6f9SAlexander Motin io->scsiio.ext_data_filled = 0; 725eb6ac6f9SAlexander Motin 726acf5bea4SAlexander Motin cam_sglist = cmd_info->cam_sglist; 727acf5bea4SAlexander Motin *dxfer_len = 0; 728acf5bea4SAlexander Motin for (i = 0; i < io->scsiio.kern_sg_entries - idx; i++) { 729a99028fcSJustin Hibbits cam_sglist[i].ds_addr = (bus_addr_t)(uintptr_t)ctl_sglist[i + idx].addr + off; 730acf5bea4SAlexander Motin if (ctl_sglist[i + idx].len - off <= bus_softc->maxio - *dxfer_len) { 731acf5bea4SAlexander Motin cam_sglist[i].ds_len = ctl_sglist[idx + i].len - off; 732acf5bea4SAlexander Motin *dxfer_len += cam_sglist[i].ds_len; 733acf5bea4SAlexander Motin } else { 734acf5bea4SAlexander Motin cam_sglist[i].ds_len = bus_softc->maxio - *dxfer_len; 735acf5bea4SAlexander Motin cmd_info->cur_transfer_index = idx + i; 736acf5bea4SAlexander Motin cmd_info->cur_transfer_off = cam_sglist[i].ds_len + off; 737acf5bea4SAlexander Motin cmd_info->flags |= CTLFE_CMD_PIECEWISE; 738acf5bea4SAlexander Motin *dxfer_len += cam_sglist[i].ds_len; 739acf5bea4SAlexander Motin if (ctl_sglist[i].len != 0) 740acf5bea4SAlexander Motin i++; 741acf5bea4SAlexander Motin break; 742acf5bea4SAlexander Motin } 743acf5bea4SAlexander Motin if (i == (CTLFE_MAX_SEGS - 1) && 744acf5bea4SAlexander Motin idx + i < (io->scsiio.kern_sg_entries - 1)) { 745acf5bea4SAlexander Motin cmd_info->cur_transfer_index = idx + i + 1; 746acf5bea4SAlexander Motin cmd_info->cur_transfer_off = 0; 747acf5bea4SAlexander Motin cmd_info->flags |= CTLFE_CMD_PIECEWISE; 748acf5bea4SAlexander Motin i++; 749acf5bea4SAlexander Motin break; 750acf5bea4SAlexander Motin } 751acf5bea4SAlexander Motin off = 0; 752acf5bea4SAlexander Motin } 753acf5bea4SAlexander Motin *sglist_cnt = i; 754acf5bea4SAlexander Motin if (io->io_hdr.flags & CTL_FLAG_BUS_ADDR) 755acf5bea4SAlexander Motin *flags |= CAM_DATA_SG_PADDR; 756acf5bea4SAlexander Motin else 757acf5bea4SAlexander Motin *flags |= CAM_DATA_SG; 758acf5bea4SAlexander Motin *data_ptr = (uint8_t *)cam_sglist; 759acf5bea4SAlexander Motin } 760acf5bea4SAlexander Motin } 761acf5bea4SAlexander Motin 762acf5bea4SAlexander Motin static void 763130f4520SKenneth D. Merry ctlfestart(struct cam_periph *periph, union ccb *start_ccb) 764130f4520SKenneth D. Merry { 765130f4520SKenneth D. Merry struct ctlfe_lun_softc *softc; 7667278725bSAlexander Motin struct ctlfe_cmd_info *cmd_info; 767130f4520SKenneth D. Merry struct ccb_hdr *ccb_h; 768130f4520SKenneth D. Merry struct ccb_accept_tio *atio; 769130f4520SKenneth D. Merry struct ccb_scsiio *csio; 770130f4520SKenneth D. Merry uint8_t *data_ptr; 771130f4520SKenneth D. Merry uint32_t dxfer_len; 772130f4520SKenneth D. Merry ccb_flags flags; 773130f4520SKenneth D. Merry union ctl_io *io; 774130f4520SKenneth D. Merry uint8_t scsi_status; 775130f4520SKenneth D. Merry 776993a751eSAlexander Motin softc = (struct ctlfe_lun_softc *)periph->softc; 777993a751eSAlexander Motin 778a504738fSAlexander Motin next: 779832529c5SAlexander Motin /* Take the ATIO off the work queue */ 780832529c5SAlexander Motin ccb_h = STAILQ_FIRST(&softc->work_queue); 781993a751eSAlexander Motin if (ccb_h == NULL) { 782993a751eSAlexander Motin xpt_release_ccb(start_ccb); 783993a751eSAlexander Motin return; 784993a751eSAlexander Motin } 785832529c5SAlexander Motin STAILQ_REMOVE_HEAD(&softc->work_queue, periph_links.stqe); 786130f4520SKenneth D. Merry atio = (struct ccb_accept_tio *)ccb_h; 787130f4520SKenneth D. Merry io = (union ctl_io *)ccb_h->io_ptr; 788130f4520SKenneth D. Merry csio = &start_ccb->csio; 789130f4520SKenneth D. Merry 790130f4520SKenneth D. Merry flags = atio->ccb_h.flags & 791130f4520SKenneth D. Merry (CAM_DIS_DISCONNECT|CAM_TAG_ACTION_VALID|CAM_DIR_MASK); 792e67ac203SAlexander Motin cmd_info = PRIV_INFO(io); 793f7241cceSAlexander Motin cmd_info->cur_transfer_index = 0; 794f7241cceSAlexander Motin cmd_info->cur_transfer_off = 0; 795f7241cceSAlexander Motin cmd_info->flags = 0; 796130f4520SKenneth D. Merry 797993a751eSAlexander Motin if (io->io_hdr.flags & CTL_FLAG_DMA_QUEUED) { 798993a751eSAlexander Motin /* 799993a751eSAlexander Motin * Datamove call, we need to setup the S/G list. 800993a751eSAlexander Motin */ 801993a751eSAlexander Motin ctlfedata(softc, io, &flags, &data_ptr, &dxfer_len, 802993a751eSAlexander Motin &csio->sglist_cnt); 803993a751eSAlexander Motin } else { 804130f4520SKenneth D. Merry /* 805130f4520SKenneth D. Merry * We're done, send status back. 806130f4520SKenneth D. Merry */ 807993a751eSAlexander Motin if ((io->io_hdr.flags & CTL_FLAG_ABORT) && 808b33b96e3SAlexander Motin (io->io_hdr.flags & CTL_FLAG_ABORT_STATUS) == 0) { 809130f4520SKenneth D. Merry io->io_hdr.flags &= ~CTL_FLAG_STATUS_QUEUED; 810130f4520SKenneth D. Merry 8116b087850SAlexander Motin /* Tell the SIM that we've aborted this ATIO */ 8126b087850SAlexander Motin #ifdef CTLFEDEBUG 8136b087850SAlexander Motin printf("%s: tag %04x abort\n", __func__, atio->tag_id); 8146b087850SAlexander Motin #endif 8156b087850SAlexander Motin KASSERT(atio->ccb_h.func_code == XPT_ACCEPT_TARGET_IO, 8166b087850SAlexander Motin ("func_code %#x is not ATIO", atio->ccb_h.func_code)); 817130f4520SKenneth D. Merry start_ccb->ccb_h.func_code = XPT_ABORT; 818130f4520SKenneth D. Merry start_ccb->cab.abort_ccb = (union ccb *)atio; 819130f4520SKenneth D. Merry xpt_action(start_ccb); 820130f4520SKenneth D. Merry 821a504738fSAlexander Motin ctlfe_requeue_ccb(periph, (union ccb *)atio, 822a504738fSAlexander Motin /* unlock */0); 823130f4520SKenneth D. Merry 824a504738fSAlexander Motin /* XPT_ABORT is not queued, so we can take next I/O. */ 825a504738fSAlexander Motin goto next; 826993a751eSAlexander Motin } 827f7241cceSAlexander Motin data_ptr = NULL; 828f7241cceSAlexander Motin dxfer_len = 0; 829f7241cceSAlexander Motin csio->sglist_cnt = 0; 830f7241cceSAlexander Motin } 831eb6ac6f9SAlexander Motin scsi_status = 0; 832f7241cceSAlexander Motin if ((io->io_hdr.flags & CTL_FLAG_STATUS_QUEUED) && 833f7241cceSAlexander Motin (cmd_info->flags & CTLFE_CMD_PIECEWISE) == 0 && 834f7241cceSAlexander Motin ((io->io_hdr.flags & CTL_FLAG_DMA_QUEUED) == 0 || 835f7241cceSAlexander Motin io->io_hdr.status == CTL_SUCCESS)) { 836993a751eSAlexander Motin flags |= CAM_SEND_STATUS; 837130f4520SKenneth D. Merry scsi_status = io->scsiio.scsi_status; 838130f4520SKenneth D. Merry csio->sense_len = io->scsiio.sense_len; 839130f4520SKenneth D. Merry #ifdef CTLFEDEBUG 840130f4520SKenneth D. Merry printf("%s: tag %04x status %x\n", __func__, 841130f4520SKenneth D. Merry atio->tag_id, io->io_hdr.status); 842130f4520SKenneth D. Merry #endif 843130f4520SKenneth D. Merry if (csio->sense_len != 0) { 844130f4520SKenneth D. Merry csio->sense_data = io->scsiio.sense_data; 845130f4520SKenneth D. Merry flags |= CAM_SEND_SENSE; 846130f4520SKenneth D. Merry } 847130f4520SKenneth D. Merry } 848130f4520SKenneth D. Merry 849130f4520SKenneth D. Merry #ifdef CTLFEDEBUG 850130f4520SKenneth D. Merry printf("%s: %s: tag %04x flags %x ptr %p len %u\n", __func__, 851130f4520SKenneth D. Merry (flags & CAM_SEND_STATUS) ? "done" : "datamove", 852130f4520SKenneth D. Merry atio->tag_id, flags, data_ptr, dxfer_len); 853130f4520SKenneth D. Merry #endif 854130f4520SKenneth D. Merry 855130f4520SKenneth D. Merry /* 856130f4520SKenneth D. Merry * Valid combinations: 85727492beaSAlexander Motin * - CAM_SEND_STATUS, CAM_DATA_SG = 0, dxfer_len = 0, 858130f4520SKenneth D. Merry * sglist_cnt = 0 85927492beaSAlexander Motin * - CAM_SEND_STATUS = 0, CAM_DATA_SG = 0, dxfer_len != 0, 860130f4520SKenneth D. Merry * sglist_cnt = 0 86127492beaSAlexander Motin * - CAM_SEND_STATUS = 0, CAM_DATA_SG, dxfer_len != 0, 862130f4520SKenneth D. Merry * sglist_cnt != 0 863130f4520SKenneth D. Merry */ 864130f4520SKenneth D. Merry #ifdef CTLFEDEBUG 865130f4520SKenneth D. Merry if (((flags & CAM_SEND_STATUS) 86627492beaSAlexander Motin && (((flags & CAM_DATA_SG) != 0) 867130f4520SKenneth D. Merry || (dxfer_len != 0) 868130f4520SKenneth D. Merry || (csio->sglist_cnt != 0))) 869130f4520SKenneth D. Merry || (((flags & CAM_SEND_STATUS) == 0) 870130f4520SKenneth D. Merry && (dxfer_len == 0)) 87127492beaSAlexander Motin || ((flags & CAM_DATA_SG) 872130f4520SKenneth D. Merry && (csio->sglist_cnt == 0)) 87327492beaSAlexander Motin || (((flags & CAM_DATA_SG) == 0) 874130f4520SKenneth D. Merry && (csio->sglist_cnt != 0))) { 875130f4520SKenneth D. Merry printf("%s: tag %04x cdb %02x flags %#x dxfer_len " 876130f4520SKenneth D. Merry "%d sg %u\n", __func__, atio->tag_id, 8774902e14dSAlexander Motin atio_cdb_ptr(atio)[0], flags, dxfer_len, 878130f4520SKenneth D. Merry csio->sglist_cnt); 879130f4520SKenneth D. Merry printf("%s: tag %04x io status %#x\n", __func__, 880130f4520SKenneth D. Merry atio->tag_id, io->io_hdr.status); 881130f4520SKenneth D. Merry } 882130f4520SKenneth D. Merry #endif 883130f4520SKenneth D. Merry cam_fill_ctio(csio, 884130f4520SKenneth D. Merry /*retries*/ 2, 885130f4520SKenneth D. Merry ctlfedone, 886130f4520SKenneth D. Merry flags, 887993a751eSAlexander Motin (flags & CAM_TAG_ACTION_VALID) ? MSG_SIMPLE_Q_TAG : 0, 888130f4520SKenneth D. Merry atio->tag_id, 889130f4520SKenneth D. Merry atio->init_id, 890130f4520SKenneth D. Merry scsi_status, 891130f4520SKenneth D. Merry /*data_ptr*/ data_ptr, 892130f4520SKenneth D. Merry /*dxfer_len*/ dxfer_len, 89303ea6ef2SAlexander Motin /*timeout*/ CTLFE_TIMEOUT * 1000); 894227d67aaSAlexander Motin start_ccb->ccb_h.flags |= CAM_UNLOCKED; 895130f4520SKenneth D. Merry start_ccb->ccb_h.ccb_atio = atio; 896993a751eSAlexander Motin if (io->io_hdr.flags & CTL_FLAG_DMA_QUEUED) 897130f4520SKenneth D. Merry io->io_hdr.flags |= CTL_FLAG_DMA_INPROG; 898993a751eSAlexander Motin io->io_hdr.flags &= ~(CTL_FLAG_DMA_QUEUED | CTL_FLAG_STATUS_QUEUED); 899130f4520SKenneth D. Merry 900130f4520SKenneth D. Merry softc->ctios_sent++; 9013afd4806SAlexander Motin softc->refcount++; 902227d67aaSAlexander Motin cam_periph_unlock(periph); 903130f4520SKenneth D. Merry xpt_action(start_ccb); 904227d67aaSAlexander Motin cam_periph_lock(periph); 9053afd4806SAlexander Motin softc->refcount--; 906130f4520SKenneth D. Merry 907130f4520SKenneth D. Merry /* 908993a751eSAlexander Motin * If we still have work to do, ask for another CCB. 909130f4520SKenneth D. Merry */ 910832529c5SAlexander Motin if (!STAILQ_EMPTY(&softc->work_queue)) 9113afd4806SAlexander Motin xpt_schedule(periph, CAM_PRIORITY_NORMAL); 9123afd4806SAlexander Motin } 9133afd4806SAlexander Motin 9143afd4806SAlexander Motin static void 9153afd4806SAlexander Motin ctlfe_drain(void *context, int pending) 9163afd4806SAlexander Motin { 9173afd4806SAlexander Motin struct cam_periph *periph = context; 9183afd4806SAlexander Motin struct ctlfe_lun_softc *softc = periph->softc; 9193afd4806SAlexander Motin 9203afd4806SAlexander Motin cam_periph_lock(periph); 9213afd4806SAlexander Motin while (softc->refcount != 0) { 9223afd4806SAlexander Motin cam_periph_sleep(periph, &softc->refcount, PRIBIO, 9233afd4806SAlexander Motin "ctlfe_drain", 1); 9243afd4806SAlexander Motin } 9253afd4806SAlexander Motin cam_periph_unlock(periph); 9263afd4806SAlexander Motin cam_periph_release(periph); 927130f4520SKenneth D. Merry } 928130f4520SKenneth D. Merry 929130f4520SKenneth D. Merry static void 930130f4520SKenneth D. Merry ctlfe_free_ccb(struct cam_periph *periph, union ccb *ccb) 931130f4520SKenneth D. Merry { 932130f4520SKenneth D. Merry struct ctlfe_lun_softc *softc; 9337278725bSAlexander Motin union ctl_io *io; 9347278725bSAlexander Motin struct ctlfe_cmd_info *cmd_info; 935130f4520SKenneth D. Merry 936130f4520SKenneth D. Merry softc = (struct ctlfe_lun_softc *)periph->softc; 9377278725bSAlexander Motin io = ccb->ccb_h.io_ptr; 938130f4520SKenneth D. Merry 939130f4520SKenneth D. Merry switch (ccb->ccb_h.func_code) { 940130f4520SKenneth D. Merry case XPT_ACCEPT_TARGET_IO: 9413afd4806SAlexander Motin softc->atios_alloced--; 942e67ac203SAlexander Motin cmd_info = PRIV_INFO(io); 9437278725bSAlexander Motin free(cmd_info, M_CTLFE); 944130f4520SKenneth D. Merry break; 945130f4520SKenneth D. Merry case XPT_IMMEDIATE_NOTIFY: 946130f4520SKenneth D. Merry case XPT_NOTIFY_ACKNOWLEDGE: 9473afd4806SAlexander Motin softc->inots_alloced--; 948130f4520SKenneth D. Merry break; 949130f4520SKenneth D. Merry default: 950130f4520SKenneth D. Merry break; 951130f4520SKenneth D. Merry } 952130f4520SKenneth D. Merry 9537278725bSAlexander Motin ctl_free_io(io); 954130f4520SKenneth D. Merry free(ccb, M_CTLFE); 955130f4520SKenneth D. Merry 9563afd4806SAlexander Motin KASSERT(softc->atios_alloced >= 0, ("%s: atios_alloced %d < 0", 9573afd4806SAlexander Motin __func__, softc->atios_alloced)); 9583afd4806SAlexander Motin KASSERT(softc->inots_alloced >= 0, ("%s: inots_alloced %d < 0", 9593afd4806SAlexander Motin __func__, softc->inots_alloced)); 960130f4520SKenneth D. Merry 961130f4520SKenneth D. Merry /* 962130f4520SKenneth D. Merry * If we have received all of our CCBs, we can release our 963130f4520SKenneth D. Merry * reference on the peripheral driver. It will probably go away 964130f4520SKenneth D. Merry * now. 965130f4520SKenneth D. Merry */ 9663afd4806SAlexander Motin if (softc->atios_alloced == 0 && softc->inots_alloced == 0) { 9673afd4806SAlexander Motin if (softc->refcount == 0) { 968130f4520SKenneth D. Merry cam_periph_release_locked(periph); 9693afd4806SAlexander Motin } else { 9703afd4806SAlexander Motin TASK_INIT(&softc->refdrain_task, 0, ctlfe_drain, periph); 9713afd4806SAlexander Motin taskqueue_enqueue(taskqueue_thread, 9723afd4806SAlexander Motin &softc->refdrain_task); 9733afd4806SAlexander Motin } 974130f4520SKenneth D. Merry } 975130f4520SKenneth D. Merry } 976130f4520SKenneth D. Merry 977a504738fSAlexander Motin /* 978a504738fSAlexander Motin * Send the ATIO/INOT back to the SIM, or free it if periph was invalidated. 979a504738fSAlexander Motin */ 980a504738fSAlexander Motin static void 981a504738fSAlexander Motin ctlfe_requeue_ccb(struct cam_periph *periph, union ccb *ccb, int unlock) 982a504738fSAlexander Motin { 983a504738fSAlexander Motin struct ctlfe_lun_softc *softc; 9848d1316f9SAlexander Motin struct mtx *mtx; 985a504738fSAlexander Motin 986a504738fSAlexander Motin if (periph->flags & CAM_PERIPH_INVALID) { 9878d1316f9SAlexander Motin mtx = cam_periph_mtx(periph); 988a504738fSAlexander Motin ctlfe_free_ccb(periph, ccb); 989a504738fSAlexander Motin if (unlock) 9908d1316f9SAlexander Motin mtx_unlock(mtx); 991a504738fSAlexander Motin return; 992a504738fSAlexander Motin } 993ad0f05e6SAlexander Motin softc = (struct ctlfe_lun_softc *)periph->softc; 994ad0f05e6SAlexander Motin if (ccb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO) 995ad0f05e6SAlexander Motin LIST_INSERT_HEAD(&softc->atio_list, &ccb->ccb_h, periph_links.le); 996ad0f05e6SAlexander Motin else 997ad0f05e6SAlexander Motin LIST_INSERT_HEAD(&softc->inot_list, &ccb->ccb_h, periph_links.le); 998a504738fSAlexander Motin if (unlock) 999a504738fSAlexander Motin cam_periph_unlock(periph); 1000a504738fSAlexander Motin 1001a504738fSAlexander Motin /* 1002a504738fSAlexander Motin * For a wildcard attachment, commands can come in with a specific 1003a504738fSAlexander Motin * target/lun. Reset the target and LUN fields back to the wildcard 1004a504738fSAlexander Motin * values before we send them back down to the SIM. 1005a504738fSAlexander Motin */ 1006c901a9b1SAlexander Motin xpt_setup_ccb_flags(&ccb->ccb_h, periph->path, CAM_PRIORITY_NONE, 1007c901a9b1SAlexander Motin ccb->ccb_h.flags); 1008a504738fSAlexander Motin 1009a504738fSAlexander Motin xpt_action(ccb); 1010a504738fSAlexander Motin } 1011a504738fSAlexander Motin 10123388f7a9SMatt Jacob static int 10133388f7a9SMatt Jacob ctlfe_adjust_cdb(struct ccb_accept_tio *atio, uint32_t offset) 10143388f7a9SMatt Jacob { 10153388f7a9SMatt Jacob uint64_t lba; 10163388f7a9SMatt Jacob uint32_t num_blocks, nbc; 10174902e14dSAlexander Motin uint8_t *cmdbyt = atio_cdb_ptr(atio); 10183388f7a9SMatt Jacob 10193388f7a9SMatt Jacob nbc = offset >> 9; /* ASSUMING 512 BYTE BLOCKS */ 10203388f7a9SMatt Jacob 10213388f7a9SMatt Jacob switch (cmdbyt[0]) { 10223388f7a9SMatt Jacob case READ_6: 10233388f7a9SMatt Jacob case WRITE_6: 10243388f7a9SMatt Jacob { 10253388f7a9SMatt Jacob struct scsi_rw_6 *cdb = (struct scsi_rw_6 *)cmdbyt; 10263388f7a9SMatt Jacob lba = scsi_3btoul(cdb->addr); 10273388f7a9SMatt Jacob lba &= 0x1fffff; 10283388f7a9SMatt Jacob num_blocks = cdb->length; 10293388f7a9SMatt Jacob if (num_blocks == 0) 10303388f7a9SMatt Jacob num_blocks = 256; 10313388f7a9SMatt Jacob lba += nbc; 10323388f7a9SMatt Jacob num_blocks -= nbc; 10333388f7a9SMatt Jacob scsi_ulto3b(lba, cdb->addr); 10343388f7a9SMatt Jacob cdb->length = num_blocks; 10353388f7a9SMatt Jacob break; 10363388f7a9SMatt Jacob } 10373388f7a9SMatt Jacob case READ_10: 10383388f7a9SMatt Jacob case WRITE_10: 10393388f7a9SMatt Jacob { 10403388f7a9SMatt Jacob struct scsi_rw_10 *cdb = (struct scsi_rw_10 *)cmdbyt; 10413388f7a9SMatt Jacob lba = scsi_4btoul(cdb->addr); 10423388f7a9SMatt Jacob num_blocks = scsi_2btoul(cdb->length); 10433388f7a9SMatt Jacob lba += nbc; 10443388f7a9SMatt Jacob num_blocks -= nbc; 10453388f7a9SMatt Jacob scsi_ulto4b(lba, cdb->addr); 10463388f7a9SMatt Jacob scsi_ulto2b(num_blocks, cdb->length); 10473388f7a9SMatt Jacob break; 10483388f7a9SMatt Jacob } 10493388f7a9SMatt Jacob case READ_12: 10503388f7a9SMatt Jacob case WRITE_12: 10513388f7a9SMatt Jacob { 10523388f7a9SMatt Jacob struct scsi_rw_12 *cdb = (struct scsi_rw_12 *)cmdbyt; 10533388f7a9SMatt Jacob lba = scsi_4btoul(cdb->addr); 10543388f7a9SMatt Jacob num_blocks = scsi_4btoul(cdb->length); 10553388f7a9SMatt Jacob lba += nbc; 10563388f7a9SMatt Jacob num_blocks -= nbc; 10573388f7a9SMatt Jacob scsi_ulto4b(lba, cdb->addr); 10583388f7a9SMatt Jacob scsi_ulto4b(num_blocks, cdb->length); 10593388f7a9SMatt Jacob break; 10603388f7a9SMatt Jacob } 10613388f7a9SMatt Jacob case READ_16: 10623388f7a9SMatt Jacob case WRITE_16: 10633388f7a9SMatt Jacob { 10643388f7a9SMatt Jacob struct scsi_rw_16 *cdb = (struct scsi_rw_16 *)cmdbyt; 10653388f7a9SMatt Jacob lba = scsi_8btou64(cdb->addr); 10663388f7a9SMatt Jacob num_blocks = scsi_4btoul(cdb->length); 10673388f7a9SMatt Jacob lba += nbc; 10683388f7a9SMatt Jacob num_blocks -= nbc; 10693388f7a9SMatt Jacob scsi_u64to8b(lba, cdb->addr); 10703388f7a9SMatt Jacob scsi_ulto4b(num_blocks, cdb->length); 10713388f7a9SMatt Jacob break; 10723388f7a9SMatt Jacob } 10733388f7a9SMatt Jacob default: 10743388f7a9SMatt Jacob return -1; 10753388f7a9SMatt Jacob } 10763388f7a9SMatt Jacob return (0); 10773388f7a9SMatt Jacob } 10783388f7a9SMatt Jacob 1079130f4520SKenneth D. Merry static void 1080130f4520SKenneth D. Merry ctlfedone(struct cam_periph *periph, union ccb *done_ccb) 1081130f4520SKenneth D. Merry { 1082130f4520SKenneth D. Merry struct ctlfe_lun_softc *softc; 1083130f4520SKenneth D. Merry struct ctlfe_softc *bus_softc; 10847278725bSAlexander Motin struct ctlfe_cmd_info *cmd_info; 10853388f7a9SMatt Jacob struct ccb_accept_tio *atio = NULL; 10863388f7a9SMatt Jacob union ctl_io *io = NULL; 1087227d67aaSAlexander Motin struct mtx *mtx; 10883b63a91dSAlexander Motin cam_status status; 1089130f4520SKenneth D. Merry 1090227d67aaSAlexander Motin KASSERT((done_ccb->ccb_h.flags & CAM_UNLOCKED) != 0, 1091227d67aaSAlexander Motin ("CCB in ctlfedone() without CAM_UNLOCKED flag")); 1092130f4520SKenneth D. Merry #ifdef CTLFE_DEBUG 10931251a76bSAlexander Motin printf("%s: entered, func_code = %#x\n", __func__, 10941251a76bSAlexander Motin done_ccb->ccb_h.func_code); 1095130f4520SKenneth D. Merry #endif 1096130f4520SKenneth D. Merry 1097b9807a43SAlexander Motin /* 1098b9807a43SAlexander Motin * At this point CTL has no known use case for device queue freezes. 1099b9807a43SAlexander Motin * In case some SIM think different -- drop its freeze right here. 1100b9807a43SAlexander Motin */ 1101b9807a43SAlexander Motin if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { 1102b9807a43SAlexander Motin cam_release_devq(periph->path, 1103b9807a43SAlexander Motin /*relsim_flags*/0, 1104b9807a43SAlexander Motin /*reduction*/0, 1105b9807a43SAlexander Motin /*timeout*/0, 1106b9807a43SAlexander Motin /*getcount_only*/0); 1107b9807a43SAlexander Motin done_ccb->ccb_h.status &= ~CAM_DEV_QFRZN; 1108b9807a43SAlexander Motin } 1109b9807a43SAlexander Motin 1110130f4520SKenneth D. Merry softc = (struct ctlfe_lun_softc *)periph->softc; 1111130f4520SKenneth D. Merry bus_softc = softc->parent_softc; 1112227d67aaSAlexander Motin mtx = cam_periph_mtx(periph); 1113227d67aaSAlexander Motin mtx_lock(mtx); 1114130f4520SKenneth D. Merry 1115130f4520SKenneth D. Merry switch (done_ccb->ccb_h.func_code) { 1116130f4520SKenneth D. Merry case XPT_ACCEPT_TARGET_IO: { 1117ad0f05e6SAlexander Motin LIST_REMOVE(&done_ccb->ccb_h, periph_links.le); 1118130f4520SKenneth D. Merry atio = &done_ccb->atio; 11193b63a91dSAlexander Motin status = atio->ccb_h.status & CAM_STATUS_MASK; 11203b63a91dSAlexander Motin if (status != CAM_CDB_RECVD) { 11213b63a91dSAlexander Motin ctlfe_free_ccb(periph, done_ccb); 11223b63a91dSAlexander Motin goto out; 11233b63a91dSAlexander Motin } 1124130f4520SKenneth D. Merry 11253388f7a9SMatt Jacob resubmit: 1126130f4520SKenneth D. Merry /* 1127130f4520SKenneth D. Merry * Allocate a ctl_io, pass it to CTL, and wait for the 1128130f4520SKenneth D. Merry * datamove or done. 1129130f4520SKenneth D. Merry */ 1130227d67aaSAlexander Motin mtx_unlock(mtx); 11311251a76bSAlexander Motin io = done_ccb->ccb_h.io_ptr; 1132e67ac203SAlexander Motin cmd_info = PRIV_INFO(io); 1133130f4520SKenneth D. Merry ctl_zero_io(io); 1134130f4520SKenneth D. Merry 1135130f4520SKenneth D. Merry /* Save pointers on both sides */ 1136e67ac203SAlexander Motin PRIV_CCB(io) = done_ccb; 1137e67ac203SAlexander Motin PRIV_INFO(io) = cmd_info; 1138130f4520SKenneth D. Merry done_ccb->ccb_h.io_ptr = io; 1139130f4520SKenneth D. Merry 1140130f4520SKenneth D. Merry /* 1141130f4520SKenneth D. Merry * Only SCSI I/O comes down this path, resets, etc. come 1142130f4520SKenneth D. Merry * down the immediate notify path below. 1143130f4520SKenneth D. Merry */ 1144130f4520SKenneth D. Merry io->io_hdr.io_type = CTL_IO_SCSI; 1145fb606ebaSAlexander Motin io->io_hdr.nexus.initid = atio->init_id; 114692168f4cSAlexander Motin io->io_hdr.nexus.targ_port = bus_softc->port.targ_port; 114759f063d5SAlexander Motin if (bus_softc->hba_misc & PIM_EXTLUNS) { 114859f063d5SAlexander Motin io->io_hdr.nexus.targ_lun = ctl_decode_lun( 114959f063d5SAlexander Motin CAM_EXTLUN_BYTE_SWIZZLE(atio->ccb_h.target_lun)); 115059f063d5SAlexander Motin } else { 1151130f4520SKenneth D. Merry io->io_hdr.nexus.targ_lun = atio->ccb_h.target_lun; 115259f063d5SAlexander Motin } 115388364968SAlexander Motin io->scsiio.priority = atio->priority; 1154130f4520SKenneth D. Merry io->scsiio.tag_num = atio->tag_id; 1155130f4520SKenneth D. Merry switch (atio->tag_action) { 1156130f4520SKenneth D. Merry case CAM_TAG_ACTION_NONE: 1157130f4520SKenneth D. Merry io->scsiio.tag_type = CTL_TAG_UNTAGGED; 1158130f4520SKenneth D. Merry break; 1159130f4520SKenneth D. Merry case MSG_SIMPLE_TASK: 1160130f4520SKenneth D. Merry io->scsiio.tag_type = CTL_TAG_SIMPLE; 1161130f4520SKenneth D. Merry break; 1162130f4520SKenneth D. Merry case MSG_HEAD_OF_QUEUE_TASK: 1163130f4520SKenneth D. Merry io->scsiio.tag_type = CTL_TAG_HEAD_OF_QUEUE; 1164130f4520SKenneth D. Merry break; 1165130f4520SKenneth D. Merry case MSG_ORDERED_TASK: 1166130f4520SKenneth D. Merry io->scsiio.tag_type = CTL_TAG_ORDERED; 1167130f4520SKenneth D. Merry break; 1168130f4520SKenneth D. Merry case MSG_ACA_TASK: 1169130f4520SKenneth D. Merry io->scsiio.tag_type = CTL_TAG_ACA; 1170130f4520SKenneth D. Merry break; 1171130f4520SKenneth D. Merry default: 1172130f4520SKenneth D. Merry io->scsiio.tag_type = CTL_TAG_UNTAGGED; 1173130f4520SKenneth D. Merry printf("%s: unhandled tag type %#x!!\n", __func__, 1174130f4520SKenneth D. Merry atio->tag_action); 1175130f4520SKenneth D. Merry break; 1176130f4520SKenneth D. Merry } 1177130f4520SKenneth D. Merry if (atio->cdb_len > sizeof(io->scsiio.cdb)) { 1178130f4520SKenneth D. Merry printf("%s: WARNING: CDB len %d > ctl_io space %zd\n", 1179130f4520SKenneth D. Merry __func__, atio->cdb_len, sizeof(io->scsiio.cdb)); 1180130f4520SKenneth D. Merry } 1181130f4520SKenneth D. Merry io->scsiio.cdb_len = min(atio->cdb_len, sizeof(io->scsiio.cdb)); 11824902e14dSAlexander Motin bcopy(atio_cdb_ptr(atio), io->scsiio.cdb, io->scsiio.cdb_len); 1183130f4520SKenneth D. Merry 1184130f4520SKenneth D. Merry #ifdef CTLFEDEBUG 11850acc026dSAlexander Motin printf("%s: %u:%u:%u: tag %jx CDB %02x\n", __func__, 1186fb606ebaSAlexander Motin io->io_hdr.nexus.initid, 1187130f4520SKenneth D. Merry io->io_hdr.nexus.targ_port, 1188130f4520SKenneth D. Merry io->io_hdr.nexus.targ_lun, 1189130f4520SKenneth D. Merry io->scsiio.tag_num, io->scsiio.cdb[0]); 1190130f4520SKenneth D. Merry #endif 1191130f4520SKenneth D. Merry 1192130f4520SKenneth D. Merry ctl_queue(io); 1193227d67aaSAlexander Motin return; 1194130f4520SKenneth D. Merry } 1195130f4520SKenneth D. Merry case XPT_CONT_TARGET_IO: { 11963388f7a9SMatt Jacob int srr = 0; 11973388f7a9SMatt Jacob uint32_t srr_off = 0; 1198130f4520SKenneth D. Merry 1199130f4520SKenneth D. Merry atio = (struct ccb_accept_tio *)done_ccb->ccb_h.ccb_atio; 1200130f4520SKenneth D. Merry io = (union ctl_io *)atio->ccb_h.io_ptr; 1201130f4520SKenneth D. Merry 12023afd4806SAlexander Motin softc->ctios_sent--; 1203130f4520SKenneth D. Merry #ifdef CTLFEDEBUG 1204130f4520SKenneth D. Merry printf("%s: got XPT_CONT_TARGET_IO tag %#x flags %#x\n", 1205130f4520SKenneth D. Merry __func__, atio->tag_id, done_ccb->ccb_h.flags); 1206130f4520SKenneth D. Merry #endif 1207130f4520SKenneth D. Merry /* 12083388f7a9SMatt Jacob * Handle SRR case were the data pointer is pushed back hack 12093388f7a9SMatt Jacob */ 12103388f7a9SMatt Jacob if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_MESSAGE_RECV 12113388f7a9SMatt Jacob && done_ccb->csio.msg_ptr != NULL 12123388f7a9SMatt Jacob && done_ccb->csio.msg_ptr[0] == MSG_EXTENDED 12133388f7a9SMatt Jacob && done_ccb->csio.msg_ptr[1] == 5 12143388f7a9SMatt Jacob && done_ccb->csio.msg_ptr[2] == 0) { 12153388f7a9SMatt Jacob srr = 1; 12163388f7a9SMatt Jacob srr_off = 12173388f7a9SMatt Jacob (done_ccb->csio.msg_ptr[3] << 24) 12183388f7a9SMatt Jacob | (done_ccb->csio.msg_ptr[4] << 16) 12193388f7a9SMatt Jacob | (done_ccb->csio.msg_ptr[5] << 8) 12203388f7a9SMatt Jacob | (done_ccb->csio.msg_ptr[6]); 12213388f7a9SMatt Jacob } 12223388f7a9SMatt Jacob 12233388f7a9SMatt Jacob /* 1224eb6ac6f9SAlexander Motin * If we have an SRR and we're still sending data, we 1225eb6ac6f9SAlexander Motin * should be able to adjust offsets and cycle again. 1226eb6ac6f9SAlexander Motin * It is possible only if offset is from this datamove. 12273388f7a9SMatt Jacob */ 1228eb6ac6f9SAlexander Motin if (srr && (io->io_hdr.flags & CTL_FLAG_DMA_INPROG) && 1229eb6ac6f9SAlexander Motin srr_off >= io->scsiio.kern_rel_offset && 1230eb6ac6f9SAlexander Motin srr_off < io->scsiio.kern_rel_offset + 1231eb6ac6f9SAlexander Motin io->scsiio.kern_data_len) { 1232eb6ac6f9SAlexander Motin io->scsiio.kern_data_resid = 1233eb6ac6f9SAlexander Motin io->scsiio.kern_rel_offset + 1234eb6ac6f9SAlexander Motin io->scsiio.kern_data_len - srr_off; 1235eb6ac6f9SAlexander Motin io->scsiio.ext_data_filled = srr_off; 1236eb6ac6f9SAlexander Motin io->scsiio.io_hdr.status = CTL_STATUS_NONE; 1237eb6ac6f9SAlexander Motin io->io_hdr.flags |= CTL_FLAG_DMA_QUEUED; 1238eb6ac6f9SAlexander Motin xpt_release_ccb(done_ccb); 1239832529c5SAlexander Motin STAILQ_INSERT_HEAD(&softc->work_queue, &atio->ccb_h, 1240832529c5SAlexander Motin periph_links.stqe); 12413afd4806SAlexander Motin xpt_schedule(periph, CAM_PRIORITY_NORMAL); 1242eb6ac6f9SAlexander Motin break; 1243eb6ac6f9SAlexander Motin } 1244eb6ac6f9SAlexander Motin 1245eb6ac6f9SAlexander Motin /* 1246eb6ac6f9SAlexander Motin * If status was being sent, the back end data is now history. 1247eb6ac6f9SAlexander Motin * Hack it up and resubmit a new command with the CDB adjusted. 1248eb6ac6f9SAlexander Motin * If the SIM does the right thing, all of the resid math 1249eb6ac6f9SAlexander Motin * should work. 1250eb6ac6f9SAlexander Motin */ 1251eb6ac6f9SAlexander Motin if (srr && (io->io_hdr.flags & CTL_FLAG_DMA_INPROG) == 0) { 12523388f7a9SMatt Jacob xpt_release_ccb(done_ccb); 12533388f7a9SMatt Jacob if (ctlfe_adjust_cdb(atio, srr_off) == 0) { 12543388f7a9SMatt Jacob done_ccb = (union ccb *)atio; 12553388f7a9SMatt Jacob goto resubmit; 12563388f7a9SMatt Jacob } 12573388f7a9SMatt Jacob /* 12583388f7a9SMatt Jacob * Fall through to doom.... 12593388f7a9SMatt Jacob */ 12603388f7a9SMatt Jacob } 12613388f7a9SMatt Jacob 12621b922b70SAlexander Motin if ((done_ccb->ccb_h.flags & CAM_SEND_STATUS) && 12631b922b70SAlexander Motin (done_ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) 12641b922b70SAlexander Motin io->io_hdr.flags |= CTL_FLAG_STATUS_SENT; 12651b922b70SAlexander Motin 12663388f7a9SMatt Jacob /* 1267130f4520SKenneth D. Merry * If we were sending status back to the initiator, free up 1268130f4520SKenneth D. Merry * resources. If we were doing a datamove, call the 1269130f4520SKenneth D. Merry * datamove done routine. 1270130f4520SKenneth D. Merry */ 1271993a751eSAlexander Motin if ((io->io_hdr.flags & CTL_FLAG_DMA_INPROG) == 0) { 1272b371466eSAlexander Motin /* 1273b371466eSAlexander Motin * If we asked to send sense data but it wasn't sent, 1274b371466eSAlexander Motin * queue the I/O back to CTL for later REQUEST SENSE. 1275b371466eSAlexander Motin */ 1276b371466eSAlexander Motin if ((done_ccb->ccb_h.flags & CAM_SEND_SENSE) != 0 && 1277b371466eSAlexander Motin (done_ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP && 1278b371466eSAlexander Motin (done_ccb->ccb_h.status & CAM_SENT_SENSE) == 0 && 1279b371466eSAlexander Motin (io = ctl_alloc_io_nowait(bus_softc->port.ctl_pool_ref)) != NULL) { 1280b371466eSAlexander Motin PRIV_INFO(io) = PRIV_INFO( 1281b371466eSAlexander Motin (union ctl_io *)atio->ccb_h.io_ptr); 1282b371466eSAlexander Motin ctl_queue_sense(atio->ccb_h.io_ptr); 1283b371466eSAlexander Motin atio->ccb_h.io_ptr = io; 1284b371466eSAlexander Motin } 1285b371466eSAlexander Motin 1286d7c2cc35SAlexander Motin /* Abort ATIO if CTIO sending status has failed. */ 1287d7c2cc35SAlexander Motin if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != 1288d7c2cc35SAlexander Motin CAM_REQ_CMP) { 1289d7c2cc35SAlexander Motin done_ccb->ccb_h.func_code = XPT_ABORT; 1290d7c2cc35SAlexander Motin done_ccb->cab.abort_ccb = (union ccb *)atio; 1291d7c2cc35SAlexander Motin xpt_action(done_ccb); 1292d7c2cc35SAlexander Motin } 1293d7c2cc35SAlexander Motin 1294130f4520SKenneth D. Merry xpt_release_ccb(done_ccb); 1295a504738fSAlexander Motin ctlfe_requeue_ccb(periph, (union ccb *)atio, 1296a504738fSAlexander Motin /* unlock */1); 1297227d67aaSAlexander Motin return; 1298130f4520SKenneth D. Merry } else { 12997278725bSAlexander Motin struct ctlfe_cmd_info *cmd_info; 1300130f4520SKenneth D. Merry struct ccb_scsiio *csio; 1301130f4520SKenneth D. Merry 1302130f4520SKenneth D. Merry csio = &done_ccb->csio; 1303e67ac203SAlexander Motin cmd_info = PRIV_INFO(io); 1304130f4520SKenneth D. Merry 1305130f4520SKenneth D. Merry io->io_hdr.flags &= ~CTL_FLAG_DMA_INPROG; 1306130f4520SKenneth D. Merry 1307130f4520SKenneth D. Merry /* 1308130f4520SKenneth D. Merry * Translate CAM status to CTL status. Success 1309130f4520SKenneth D. Merry * does not change the overall, ctl_io status. In 1310130f4520SKenneth D. Merry * that case we just set port_status to 0. If we 1311130f4520SKenneth D. Merry * have a failure, though, set a data phase error 1312130f4520SKenneth D. Merry * for the overall ctl_io. 1313130f4520SKenneth D. Merry */ 1314130f4520SKenneth D. Merry switch (done_ccb->ccb_h.status & CAM_STATUS_MASK) { 1315130f4520SKenneth D. Merry case CAM_REQ_CMP: 131615b2cdedSAlexander Motin io->scsiio.kern_data_resid -= 131715b2cdedSAlexander Motin csio->dxfer_len - csio->resid; 1318130f4520SKenneth D. Merry io->io_hdr.port_status = 0; 1319130f4520SKenneth D. Merry break; 1320130f4520SKenneth D. Merry default: 1321130f4520SKenneth D. Merry /* 1322744c26b2SKenneth D. Merry * XXX KDM we probably need to figure out a 1323744c26b2SKenneth D. Merry * standard set of errors that the SIM 1324744c26b2SKenneth D. Merry * drivers should return in the event of a 1325744c26b2SKenneth D. Merry * data transfer failure. A data phase 1326744c26b2SKenneth D. Merry * error will at least point the user to a 1327744c26b2SKenneth D. Merry * data transfer error of some sort. 1328744c26b2SKenneth D. Merry * Hopefully the SIM printed out some 1329744c26b2SKenneth D. Merry * additional information to give the user 1330744c26b2SKenneth D. Merry * a clue what happened. 1331130f4520SKenneth D. Merry */ 1332130f4520SKenneth D. Merry io->io_hdr.port_status = 0xbad1; 1333130f4520SKenneth D. Merry ctl_set_data_phase_error(&io->scsiio); 1334130f4520SKenneth D. Merry /* 1335130f4520SKenneth D. Merry * XXX KDM figure out residual. 1336130f4520SKenneth D. Merry */ 1337130f4520SKenneth D. Merry break; 1338130f4520SKenneth D. Merry } 1339130f4520SKenneth D. Merry /* 1340130f4520SKenneth D. Merry * If we had to break this S/G list into multiple 1341130f4520SKenneth D. Merry * pieces, figure out where we are in the list, and 1342130f4520SKenneth D. Merry * continue sending pieces if necessary. 1343130f4520SKenneth D. Merry */ 134415b2cdedSAlexander Motin if ((cmd_info->flags & CTLFE_CMD_PIECEWISE) && 134515b2cdedSAlexander Motin io->io_hdr.port_status == 0 && csio->resid == 0) { 1346130f4520SKenneth D. Merry ccb_flags flags; 1347130f4520SKenneth D. Merry uint8_t *data_ptr; 1348130f4520SKenneth D. Merry uint32_t dxfer_len; 1349130f4520SKenneth D. Merry 1350130f4520SKenneth D. Merry flags = atio->ccb_h.flags & 1351130f4520SKenneth D. Merry (CAM_DIS_DISCONNECT| 1352acf5bea4SAlexander Motin CAM_TAG_ACTION_VALID); 1353130f4520SKenneth D. Merry 1354acf5bea4SAlexander Motin ctlfedata(softc, io, &flags, &data_ptr, 1355acf5bea4SAlexander Motin &dxfer_len, &csio->sglist_cnt); 1356130f4520SKenneth D. Merry 1357130f4520SKenneth D. Merry if (((flags & CAM_SEND_STATUS) == 0) 1358130f4520SKenneth D. Merry && (dxfer_len == 0)) { 1359130f4520SKenneth D. Merry printf("%s: tag %04x no status or " 1360130f4520SKenneth D. Merry "len cdb = %02x\n", __func__, 1361130f4520SKenneth D. Merry atio->tag_id, 13624902e14dSAlexander Motin atio_cdb_ptr(atio)[0]); 1363130f4520SKenneth D. Merry printf("%s: tag %04x io status %#x\n", 1364130f4520SKenneth D. Merry __func__, atio->tag_id, 1365130f4520SKenneth D. Merry io->io_hdr.status); 1366130f4520SKenneth D. Merry } 1367130f4520SKenneth D. Merry 1368130f4520SKenneth D. Merry cam_fill_ctio(csio, 1369130f4520SKenneth D. Merry /*retries*/ 2, 1370130f4520SKenneth D. Merry ctlfedone, 1371130f4520SKenneth D. Merry flags, 1372130f4520SKenneth D. Merry (flags & CAM_TAG_ACTION_VALID) ? 1373130f4520SKenneth D. Merry MSG_SIMPLE_Q_TAG : 0, 1374130f4520SKenneth D. Merry atio->tag_id, 1375130f4520SKenneth D. Merry atio->init_id, 1376eb6ac6f9SAlexander Motin 0, 1377130f4520SKenneth D. Merry /*data_ptr*/ data_ptr, 1378130f4520SKenneth D. Merry /*dxfer_len*/ dxfer_len, 137903ea6ef2SAlexander Motin CTLFE_TIMEOUT * 1000); 1380130f4520SKenneth D. Merry 1381227d67aaSAlexander Motin csio->ccb_h.flags |= CAM_UNLOCKED; 1382130f4520SKenneth D. Merry csio->resid = 0; 1383130f4520SKenneth D. Merry csio->ccb_h.ccb_atio = atio; 1384130f4520SKenneth D. Merry io->io_hdr.flags |= CTL_FLAG_DMA_INPROG; 1385130f4520SKenneth D. Merry softc->ctios_sent++; 1386227d67aaSAlexander Motin mtx_unlock(mtx); 1387130f4520SKenneth D. Merry xpt_action((union ccb *)csio); 1388130f4520SKenneth D. Merry } else { 1389130f4520SKenneth D. Merry /* 1390130f4520SKenneth D. Merry * Release the CTIO. The ATIO will be sent back 1391130f4520SKenneth D. Merry * down to the SIM once we send status. 1392130f4520SKenneth D. Merry */ 1393130f4520SKenneth D. Merry xpt_release_ccb(done_ccb); 1394227d67aaSAlexander Motin mtx_unlock(mtx); 1395130f4520SKenneth D. Merry 13962c7dc6baSAlexander Motin ctl_datamove_done(io, false); 1397130f4520SKenneth D. Merry } 1398227d67aaSAlexander Motin return; 1399130f4520SKenneth D. Merry } 1400130f4520SKenneth D. Merry break; 1401130f4520SKenneth D. Merry } 1402130f4520SKenneth D. Merry case XPT_IMMEDIATE_NOTIFY: { 1403130f4520SKenneth D. Merry union ctl_io *io; 1404130f4520SKenneth D. Merry struct ccb_immediate_notify *inot; 1405b9807a43SAlexander Motin int send_ctl_io; 1406130f4520SKenneth D. Merry 1407ad0f05e6SAlexander Motin LIST_REMOVE(&done_ccb->ccb_h, periph_links.le); 1408130f4520SKenneth D. Merry inot = &done_ccb->cin1; 14091251a76bSAlexander Motin io = done_ccb->ccb_h.io_ptr; 14101251a76bSAlexander Motin ctl_zero_io(io); 1411130f4520SKenneth D. Merry 1412130f4520SKenneth D. Merry send_ctl_io = 1; 1413130f4520SKenneth D. Merry 1414130f4520SKenneth D. Merry io->io_hdr.io_type = CTL_IO_TASK; 1415e67ac203SAlexander Motin PRIV_CCB(io) = done_ccb; 1416130f4520SKenneth D. Merry inot->ccb_h.io_ptr = io; 1417fb606ebaSAlexander Motin io->io_hdr.nexus.initid = inot->initiator_id; 141892168f4cSAlexander Motin io->io_hdr.nexus.targ_port = bus_softc->port.targ_port; 141959f063d5SAlexander Motin if (bus_softc->hba_misc & PIM_EXTLUNS) { 142059f063d5SAlexander Motin io->io_hdr.nexus.targ_lun = ctl_decode_lun( 142159f063d5SAlexander Motin CAM_EXTLUN_BYTE_SWIZZLE(inot->ccb_h.target_lun)); 142259f063d5SAlexander Motin } else { 1423130f4520SKenneth D. Merry io->io_hdr.nexus.targ_lun = inot->ccb_h.target_lun; 142459f063d5SAlexander Motin } 1425130f4520SKenneth D. Merry /* XXX KDM should this be the tag_id? */ 1426130f4520SKenneth D. Merry io->taskio.tag_num = inot->seq_id; 1427130f4520SKenneth D. Merry 1428130f4520SKenneth D. Merry status = inot->ccb_h.status & CAM_STATUS_MASK; 1429130f4520SKenneth D. Merry switch (status) { 1430130f4520SKenneth D. Merry case CAM_SCSI_BUS_RESET: 1431130f4520SKenneth D. Merry io->taskio.task_action = CTL_TASK_BUS_RESET; 1432130f4520SKenneth D. Merry break; 1433130f4520SKenneth D. Merry case CAM_BDR_SENT: 1434130f4520SKenneth D. Merry io->taskio.task_action = CTL_TASK_TARGET_RESET; 1435130f4520SKenneth D. Merry break; 1436130f4520SKenneth D. Merry case CAM_MESSAGE_RECV: 1437130f4520SKenneth D. Merry switch (inot->arg) { 1438130f4520SKenneth D. Merry case MSG_ABORT_TASK_SET: 1439130f4520SKenneth D. Merry io->taskio.task_action = 1440130f4520SKenneth D. Merry CTL_TASK_ABORT_TASK_SET; 1441130f4520SKenneth D. Merry break; 1442130f4520SKenneth D. Merry case MSG_TARGET_RESET: 1443c98d2b1fSAlexander Motin io->taskio.task_action = CTL_TASK_TARGET_RESET; 1444130f4520SKenneth D. Merry break; 1445130f4520SKenneth D. Merry case MSG_ABORT_TASK: 1446c98d2b1fSAlexander Motin io->taskio.task_action = CTL_TASK_ABORT_TASK; 1447130f4520SKenneth D. Merry break; 1448130f4520SKenneth D. Merry case MSG_LOGICAL_UNIT_RESET: 1449c98d2b1fSAlexander Motin io->taskio.task_action = CTL_TASK_LUN_RESET; 1450130f4520SKenneth D. Merry break; 1451130f4520SKenneth D. Merry case MSG_CLEAR_TASK_SET: 1452130f4520SKenneth D. Merry io->taskio.task_action = 1453130f4520SKenneth D. Merry CTL_TASK_CLEAR_TASK_SET; 1454130f4520SKenneth D. Merry break; 1455130f4520SKenneth D. Merry case MSG_CLEAR_ACA: 1456c98d2b1fSAlexander Motin io->taskio.task_action = CTL_TASK_CLEAR_ACA; 1457c98d2b1fSAlexander Motin break; 1458c98d2b1fSAlexander Motin case MSG_QUERY_TASK: 1459c98d2b1fSAlexander Motin io->taskio.task_action = CTL_TASK_QUERY_TASK; 1460c98d2b1fSAlexander Motin break; 1461c98d2b1fSAlexander Motin case MSG_QUERY_TASK_SET: 1462130f4520SKenneth D. Merry io->taskio.task_action = 1463c98d2b1fSAlexander Motin CTL_TASK_QUERY_TASK_SET; 1464c98d2b1fSAlexander Motin break; 1465c98d2b1fSAlexander Motin case MSG_QUERY_ASYNC_EVENT: 1466c98d2b1fSAlexander Motin io->taskio.task_action = 1467c98d2b1fSAlexander Motin CTL_TASK_QUERY_ASYNC_EVENT; 1468130f4520SKenneth D. Merry break; 1469130f4520SKenneth D. Merry case MSG_NOOP: 1470130f4520SKenneth D. Merry send_ctl_io = 0; 1471130f4520SKenneth D. Merry break; 1472130f4520SKenneth D. Merry default: 14731251a76bSAlexander Motin xpt_print(periph->path, 14743b63a91dSAlexander Motin "%s: unsupported INOT message 0x%x\n", 1475130f4520SKenneth D. Merry __func__, inot->arg); 1476130f4520SKenneth D. Merry send_ctl_io = 0; 1477130f4520SKenneth D. Merry break; 1478130f4520SKenneth D. Merry } 1479130f4520SKenneth D. Merry break; 1480130f4520SKenneth D. Merry default: 14811251a76bSAlexander Motin xpt_print(periph->path, 14823b63a91dSAlexander Motin "%s: unsupported INOT status 0x%x\n", 14831251a76bSAlexander Motin __func__, status); 14843b63a91dSAlexander Motin /* FALLTHROUGH */ 14853b63a91dSAlexander Motin case CAM_REQ_ABORTED: 14863b63a91dSAlexander Motin case CAM_REQ_INVALID: 14873b63a91dSAlexander Motin case CAM_DEV_NOT_THERE: 14883b63a91dSAlexander Motin case CAM_PROVIDE_FAIL: 1489b79dc8a8SKenneth D. Merry ctlfe_free_ccb(periph, done_ccb); 1490227d67aaSAlexander Motin goto out; 1491130f4520SKenneth D. Merry } 1492c67a2909SAlexander Motin mtx_unlock(mtx); 1493130f4520SKenneth D. Merry if (send_ctl_io != 0) { 1494130f4520SKenneth D. Merry ctl_queue(io); 1495130f4520SKenneth D. Merry } else { 1496130f4520SKenneth D. Merry done_ccb->ccb_h.status = CAM_REQ_INPROG; 1497130f4520SKenneth D. Merry done_ccb->ccb_h.func_code = XPT_NOTIFY_ACKNOWLEDGE; 1498130f4520SKenneth D. Merry xpt_action(done_ccb); 1499130f4520SKenneth D. Merry } 1500c67a2909SAlexander Motin return; 1501130f4520SKenneth D. Merry } 1502130f4520SKenneth D. Merry case XPT_NOTIFY_ACKNOWLEDGE: 1503a504738fSAlexander Motin /* Queue this back down to the SIM as an immediate notify. */ 150496b5475bSAlexander Motin done_ccb->ccb_h.status = CAM_REQ_INPROG; 1505130f4520SKenneth D. Merry done_ccb->ccb_h.func_code = XPT_IMMEDIATE_NOTIFY; 1506a504738fSAlexander Motin ctlfe_requeue_ccb(periph, done_ccb, /* unlock */1); 1507a504738fSAlexander Motin return; 1508130f4520SKenneth D. Merry case XPT_SET_SIM_KNOB: 1509130f4520SKenneth D. Merry case XPT_GET_SIM_KNOB: 1510a2531862SWarner Losh case XPT_GET_SIM_KNOB_OLD: 1511130f4520SKenneth D. Merry break; 1512130f4520SKenneth D. Merry default: 1513130f4520SKenneth D. Merry panic("%s: unexpected CCB type %#x", __func__, 1514130f4520SKenneth D. Merry done_ccb->ccb_h.func_code); 1515130f4520SKenneth D. Merry break; 1516130f4520SKenneth D. Merry } 1517227d67aaSAlexander Motin 1518227d67aaSAlexander Motin out: 1519227d67aaSAlexander Motin mtx_unlock(mtx); 1520130f4520SKenneth D. Merry } 1521130f4520SKenneth D. Merry 1522130f4520SKenneth D. Merry static void 1523130f4520SKenneth D. Merry ctlfe_onoffline(void *arg, int online) 1524130f4520SKenneth D. Merry { 152545400376SAlexander Motin struct ctlfe_softc *bus_softc = arg; 1526130f4520SKenneth D. Merry union ccb *ccb; 1527130f4520SKenneth D. Merry cam_status status; 1528130f4520SKenneth D. Merry struct cam_path *path; 152945400376SAlexander Motin int set_wwnn = 0; 1530130f4520SKenneth D. Merry 1531130f4520SKenneth D. Merry status = xpt_create_path(&path, /*periph*/ NULL, bus_softc->path_id, 1532130f4520SKenneth D. Merry CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); 1533130f4520SKenneth D. Merry if (status != CAM_REQ_CMP) { 1534130f4520SKenneth D. Merry printf("%s: unable to create path!\n", __func__); 1535130f4520SKenneth D. Merry return; 1536130f4520SKenneth D. Merry } 15377511bd04SAlexander Motin ccb = xpt_alloc_ccb(); 153815a2601bSAlexander Motin xpt_setup_ccb(&ccb->ccb_h, path, CAM_PRIORITY_NONE); 1539d1f40587SAlexander Motin ccb->ccb_h.func_code = XPT_GET_SIM_KNOB; 1540d1f40587SAlexander Motin xpt_action(ccb); 1541130f4520SKenneth D. Merry 154245400376SAlexander Motin /* Check whether we should change WWNs. */ 1543130f4520SKenneth D. Merry if (online != 0) { 1544130f4520SKenneth D. Merry if ((ccb->knob.xport_specific.valid & KNOB_VALID_ADDRESS) != 0){ 1545130f4520SKenneth D. Merry printf("%s: %s current WWNN %#jx\n", __func__, 1546130f4520SKenneth D. Merry bus_softc->port_name, 1547130f4520SKenneth D. Merry ccb->knob.xport_specific.fc.wwnn); 1548130f4520SKenneth D. Merry printf("%s: %s current WWPN %#jx\n", __func__, 1549130f4520SKenneth D. Merry bus_softc->port_name, 1550130f4520SKenneth D. Merry ccb->knob.xport_specific.fc.wwpn); 1551130f4520SKenneth D. Merry 1552130f4520SKenneth D. Merry /* 1553130f4520SKenneth D. Merry * If the user has specified a WWNN/WWPN, send them 1554130f4520SKenneth D. Merry * down to the SIM. Otherwise, record what the SIM 1555130f4520SKenneth D. Merry * has reported. 1556130f4520SKenneth D. Merry */ 15577607afb1SAlexander Motin if (bus_softc->port.wwnn != 0 && bus_softc->port.wwnn 15587607afb1SAlexander Motin != ccb->knob.xport_specific.fc.wwnn) { 1559130f4520SKenneth D. Merry ccb->knob.xport_specific.fc.wwnn = 156092168f4cSAlexander Motin bus_softc->port.wwnn; 15617607afb1SAlexander Motin set_wwnn = 1; 15627607afb1SAlexander Motin } else { 15637607afb1SAlexander Motin ctl_port_set_wwns(&bus_softc->port, 15647607afb1SAlexander Motin true, ccb->knob.xport_specific.fc.wwnn, 15657607afb1SAlexander Motin false, 0); 15667607afb1SAlexander Motin } 15677607afb1SAlexander Motin if (bus_softc->port.wwpn != 0 && bus_softc->port.wwpn 15687607afb1SAlexander Motin != ccb->knob.xport_specific.fc.wwpn) { 1569130f4520SKenneth D. Merry ccb->knob.xport_specific.fc.wwpn = 157092168f4cSAlexander Motin bus_softc->port.wwpn; 1571130f4520SKenneth D. Merry set_wwnn = 1; 1572130f4520SKenneth D. Merry } else { 1573027e5269SAlexander Motin ctl_port_set_wwns(&bus_softc->port, 15747607afb1SAlexander Motin false, 0, 1575027e5269SAlexander Motin true, ccb->knob.xport_specific.fc.wwpn); 1576130f4520SKenneth D. Merry } 157745400376SAlexander Motin } else { 157845400376SAlexander Motin printf("%s: %s has no valid WWNN/WWPN\n", __func__, 157945400376SAlexander Motin bus_softc->port_name); 158045400376SAlexander Motin if (bus_softc->port.wwnn != 0) { 158145400376SAlexander Motin ccb->knob.xport_specific.fc.wwnn = 158245400376SAlexander Motin bus_softc->port.wwnn; 158345400376SAlexander Motin set_wwnn = 1; 158445400376SAlexander Motin } 158545400376SAlexander Motin if (bus_softc->port.wwpn != 0) { 158645400376SAlexander Motin ccb->knob.xport_specific.fc.wwpn = 158745400376SAlexander Motin bus_softc->port.wwpn; 158845400376SAlexander Motin set_wwnn = 1; 158945400376SAlexander Motin } 159045400376SAlexander Motin } 159145400376SAlexander Motin } 159245400376SAlexander Motin if (set_wwnn) { 159345400376SAlexander Motin ccb->ccb_h.func_code = XPT_SET_SIM_KNOB; 159445400376SAlexander Motin ccb->knob.xport_specific.valid = KNOB_VALID_ADDRESS; 159545400376SAlexander Motin xpt_action(ccb); 159645400376SAlexander Motin if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 159745400376SAlexander Motin printf("%s: %s (path id %d) failed set WWNs: %#x\n", 159845400376SAlexander Motin __func__, bus_softc->port_name, bus_softc->path_id, 159945400376SAlexander Motin ccb->ccb_h.status); 160045400376SAlexander Motin } else { 1601130f4520SKenneth D. Merry printf("%s: %s new WWNN %#jx\n", __func__, 1602130f4520SKenneth D. Merry bus_softc->port_name, 1603130f4520SKenneth D. Merry ccb->knob.xport_specific.fc.wwnn); 1604130f4520SKenneth D. Merry printf("%s: %s new WWPN %#jx\n", __func__, 1605130f4520SKenneth D. Merry bus_softc->port_name, 1606130f4520SKenneth D. Merry ccb->knob.xport_specific.fc.wwpn); 1607130f4520SKenneth D. Merry } 1608130f4520SKenneth D. Merry } 160945400376SAlexander Motin 161045400376SAlexander Motin /* Check whether we should change role. */ 161145400376SAlexander Motin if ((ccb->knob.xport_specific.valid & KNOB_VALID_ROLE) == 0 || 161245400376SAlexander Motin ((online != 0) ^ 161345400376SAlexander Motin ((ccb->knob.xport_specific.fc.role & KNOB_ROLE_TARGET) != 0)) != 0) { 1614130f4520SKenneth D. Merry ccb->ccb_h.func_code = XPT_SET_SIM_KNOB; 1615130f4520SKenneth D. Merry ccb->knob.xport_specific.valid = KNOB_VALID_ROLE; 161645400376SAlexander Motin if (online) 1617d1f40587SAlexander Motin ccb->knob.xport_specific.fc.role |= KNOB_ROLE_TARGET; 1618130f4520SKenneth D. Merry else 1619d1f40587SAlexander Motin ccb->knob.xport_specific.fc.role &= ~KNOB_ROLE_TARGET; 1620130f4520SKenneth D. Merry xpt_action(ccb); 1621130f4520SKenneth D. Merry if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 162245400376SAlexander Motin printf("%s: %s (path id %d) failed %s target role: %#x\n", 1623130f4520SKenneth D. Merry __func__, bus_softc->port_name, bus_softc->path_id, 162445400376SAlexander Motin online ? "enable" : "disable", ccb->ccb_h.status); 1625130f4520SKenneth D. Merry } else { 162645400376SAlexander Motin printf("%s: %s (path id %d) target role %s succeeded\n", 1627130f4520SKenneth D. Merry __func__, bus_softc->port_name, bus_softc->path_id, 162845400376SAlexander Motin online ? "enable" : "disable"); 162945400376SAlexander Motin } 1630130f4520SKenneth D. Merry } 1631130f4520SKenneth D. Merry 1632130f4520SKenneth D. Merry xpt_free_path(path); 16337511bd04SAlexander Motin xpt_free_ccb(ccb); 1634130f4520SKenneth D. Merry } 1635130f4520SKenneth D. Merry 1636130f4520SKenneth D. Merry static void 1637130f4520SKenneth D. Merry ctlfe_online(void *arg) 1638130f4520SKenneth D. Merry { 1639744c26b2SKenneth D. Merry struct ctlfe_softc *bus_softc; 1640744c26b2SKenneth D. Merry struct cam_path *path; 1641744c26b2SKenneth D. Merry cam_status status; 1642744c26b2SKenneth D. Merry struct ctlfe_lun_softc *lun_softc; 16433134cce0SAlexander Motin struct cam_periph *periph; 1644744c26b2SKenneth D. Merry 1645744c26b2SKenneth D. Merry bus_softc = (struct ctlfe_softc *)arg; 1646744c26b2SKenneth D. Merry 1647744c26b2SKenneth D. Merry /* 1648744c26b2SKenneth D. Merry * Create the wildcard LUN before bringing the port online. 1649744c26b2SKenneth D. Merry */ 1650744c26b2SKenneth D. Merry status = xpt_create_path(&path, /*periph*/ NULL, 1651744c26b2SKenneth D. Merry bus_softc->path_id, CAM_TARGET_WILDCARD, 1652744c26b2SKenneth D. Merry CAM_LUN_WILDCARD); 1653744c26b2SKenneth D. Merry if (status != CAM_REQ_CMP) { 1654744c26b2SKenneth D. Merry printf("%s: unable to create path for wildcard periph\n", 1655744c26b2SKenneth D. Merry __func__); 1656744c26b2SKenneth D. Merry return; 1657744c26b2SKenneth D. Merry } 1658744c26b2SKenneth D. Merry 16597511bd04SAlexander Motin lun_softc = malloc(sizeof(*lun_softc), M_CTLFE, M_WAITOK | M_ZERO); 1660744c26b2SKenneth D. Merry 1661227d67aaSAlexander Motin xpt_path_lock(path); 16623134cce0SAlexander Motin periph = cam_periph_find(path, "ctl"); 16633134cce0SAlexander Motin if (periph != NULL) { 16643134cce0SAlexander Motin /* We've already got a periph, no need to alloc a new one. */ 16653134cce0SAlexander Motin xpt_path_unlock(path); 16663134cce0SAlexander Motin xpt_free_path(path); 16673134cce0SAlexander Motin free(lun_softc, M_CTLFE); 16683134cce0SAlexander Motin return; 16693134cce0SAlexander Motin } 1670744c26b2SKenneth D. Merry lun_softc->parent_softc = bus_softc; 1671744c26b2SKenneth D. Merry lun_softc->flags |= CTLFE_LUN_WILDCARD; 1672744c26b2SKenneth D. Merry 1673744c26b2SKenneth D. Merry status = cam_periph_alloc(ctlferegister, 1674744c26b2SKenneth D. Merry ctlfeoninvalidate, 1675744c26b2SKenneth D. Merry ctlfecleanup, 1676744c26b2SKenneth D. Merry ctlfestart, 1677744c26b2SKenneth D. Merry "ctl", 1678744c26b2SKenneth D. Merry CAM_PERIPH_BIO, 1679744c26b2SKenneth D. Merry path, 1680744c26b2SKenneth D. Merry ctlfeasync, 1681744c26b2SKenneth D. Merry 0, 1682744c26b2SKenneth D. Merry lun_softc); 1683744c26b2SKenneth D. Merry 1684744c26b2SKenneth D. Merry if ((status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 1685744c26b2SKenneth D. Merry const struct cam_status_entry *entry; 1686744c26b2SKenneth D. Merry 1687744c26b2SKenneth D. Merry entry = cam_fetch_status_entry(status); 1688744c26b2SKenneth D. Merry printf("%s: CAM error %s (%#x) returned from " 1689744c26b2SKenneth D. Merry "cam_periph_alloc()\n", __func__, (entry != NULL) ? 1690744c26b2SKenneth D. Merry entry->status_text : "Unknown", status); 16913134cce0SAlexander Motin free(lun_softc, M_CTLFE); 16923134cce0SAlexander Motin } 1693744c26b2SKenneth D. Merry 1694227d67aaSAlexander Motin xpt_path_unlock(path); 16957511bd04SAlexander Motin ctlfe_onoffline(arg, /*online*/ 1); 1696227d67aaSAlexander Motin xpt_free_path(path); 1697130f4520SKenneth D. Merry } 1698130f4520SKenneth D. Merry 1699130f4520SKenneth D. Merry static void 1700130f4520SKenneth D. Merry ctlfe_offline(void *arg) 1701130f4520SKenneth D. Merry { 1702744c26b2SKenneth D. Merry struct ctlfe_softc *bus_softc; 1703744c26b2SKenneth D. Merry struct cam_path *path; 1704744c26b2SKenneth D. Merry cam_status status; 1705744c26b2SKenneth D. Merry struct cam_periph *periph; 1706744c26b2SKenneth D. Merry 1707744c26b2SKenneth D. Merry bus_softc = (struct ctlfe_softc *)arg; 1708744c26b2SKenneth D. Merry 17097511bd04SAlexander Motin ctlfe_onoffline(arg, /*online*/ 0); 17107511bd04SAlexander Motin 1711744c26b2SKenneth D. Merry /* 1712744c26b2SKenneth D. Merry * Disable the wildcard LUN for this port now that we have taken 1713744c26b2SKenneth D. Merry * the port offline. 1714744c26b2SKenneth D. Merry */ 1715744c26b2SKenneth D. Merry status = xpt_create_path(&path, /*periph*/ NULL, 1716744c26b2SKenneth D. Merry bus_softc->path_id, CAM_TARGET_WILDCARD, 1717744c26b2SKenneth D. Merry CAM_LUN_WILDCARD); 1718744c26b2SKenneth D. Merry if (status != CAM_REQ_CMP) { 1719744c26b2SKenneth D. Merry printf("%s: unable to create path for wildcard periph\n", 1720744c26b2SKenneth D. Merry __func__); 1721744c26b2SKenneth D. Merry return; 1722744c26b2SKenneth D. Merry } 1723227d67aaSAlexander Motin xpt_path_lock(path); 1724744c26b2SKenneth D. Merry if ((periph = cam_periph_find(path, "ctl")) != NULL) 1725744c26b2SKenneth D. Merry cam_periph_invalidate(periph); 1726227d67aaSAlexander Motin xpt_path_unlock(path); 1727744c26b2SKenneth D. Merry xpt_free_path(path); 1728130f4520SKenneth D. Merry } 1729130f4520SKenneth D. Merry 1730130f4520SKenneth D. Merry /* 1731130f4520SKenneth D. Merry * This will get called to enable a LUN on every bus that is attached to 1732130f4520SKenneth D. Merry * CTL. So we only need to create a path/periph for this particular bus. 1733130f4520SKenneth D. Merry */ 1734130f4520SKenneth D. Merry static int 17357834ea88SAlexander Motin ctlfe_lun_enable(void *arg, int lun_id) 1736130f4520SKenneth D. Merry { 1737130f4520SKenneth D. Merry struct ctlfe_softc *bus_softc; 1738130f4520SKenneth D. Merry struct ctlfe_lun_softc *softc; 1739130f4520SKenneth D. Merry struct cam_path *path; 1740130f4520SKenneth D. Merry struct cam_periph *periph; 1741130f4520SKenneth D. Merry cam_status status; 1742130f4520SKenneth D. Merry 1743130f4520SKenneth D. Merry bus_softc = (struct ctlfe_softc *)arg; 174459f063d5SAlexander Motin if (bus_softc->hba_misc & PIM_EXTLUNS) 174559f063d5SAlexander Motin lun_id = CAM_EXTLUN_BYTE_SWIZZLE(ctl_encode_lun(lun_id)); 1746130f4520SKenneth D. Merry 1747227d67aaSAlexander Motin status = xpt_create_path(&path, /*periph*/ NULL, 1748d1f40587SAlexander Motin bus_softc->path_id, bus_softc->target_id, lun_id); 1749130f4520SKenneth D. Merry /* XXX KDM need some way to return status to CTL here? */ 1750130f4520SKenneth D. Merry if (status != CAM_REQ_CMP) { 1751130f4520SKenneth D. Merry printf("%s: could not create path, status %#x\n", __func__, 1752130f4520SKenneth D. Merry status); 1753130f4520SKenneth D. Merry return (1); 1754130f4520SKenneth D. Merry } 1755130f4520SKenneth D. Merry 1756130f4520SKenneth D. Merry softc = malloc(sizeof(*softc), M_CTLFE, M_WAITOK | M_ZERO); 1757227d67aaSAlexander Motin xpt_path_lock(path); 1758130f4520SKenneth D. Merry periph = cam_periph_find(path, "ctl"); 1759130f4520SKenneth D. Merry if (periph != NULL) { 1760130f4520SKenneth D. Merry /* We've already got a periph, no need to alloc a new one. */ 1761227d67aaSAlexander Motin xpt_path_unlock(path); 1762130f4520SKenneth D. Merry xpt_free_path(path); 1763130f4520SKenneth D. Merry free(softc, M_CTLFE); 1764130f4520SKenneth D. Merry return (0); 1765130f4520SKenneth D. Merry } 1766130f4520SKenneth D. Merry softc->parent_softc = bus_softc; 1767130f4520SKenneth D. Merry 1768130f4520SKenneth D. Merry status = cam_periph_alloc(ctlferegister, 1769130f4520SKenneth D. Merry ctlfeoninvalidate, 1770130f4520SKenneth D. Merry ctlfecleanup, 1771130f4520SKenneth D. Merry ctlfestart, 1772130f4520SKenneth D. Merry "ctl", 1773130f4520SKenneth D. Merry CAM_PERIPH_BIO, 1774130f4520SKenneth D. Merry path, 1775130f4520SKenneth D. Merry ctlfeasync, 1776130f4520SKenneth D. Merry 0, 1777130f4520SKenneth D. Merry softc); 1778130f4520SKenneth D. Merry 17793134cce0SAlexander Motin if ((status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 17803134cce0SAlexander Motin const struct cam_status_entry *entry; 17813134cce0SAlexander Motin 17823134cce0SAlexander Motin entry = cam_fetch_status_entry(status); 17833134cce0SAlexander Motin printf("%s: CAM error %s (%#x) returned from " 17843134cce0SAlexander Motin "cam_periph_alloc()\n", __func__, (entry != NULL) ? 17853134cce0SAlexander Motin entry->status_text : "Unknown", status); 17863134cce0SAlexander Motin free(softc, M_CTLFE); 17873134cce0SAlexander Motin } 17883134cce0SAlexander Motin 1789227d67aaSAlexander Motin xpt_path_unlock(path); 1790130f4520SKenneth D. Merry xpt_free_path(path); 1791130f4520SKenneth D. Merry return (0); 1792130f4520SKenneth D. Merry } 1793130f4520SKenneth D. Merry 1794130f4520SKenneth D. Merry /* 1795744c26b2SKenneth D. Merry * This will get called when the user removes a LUN to disable that LUN 1796744c26b2SKenneth D. Merry * on every bus that is attached to CTL. 1797130f4520SKenneth D. Merry */ 1798130f4520SKenneth D. Merry static int 17997834ea88SAlexander Motin ctlfe_lun_disable(void *arg, int lun_id) 1800130f4520SKenneth D. Merry { 1801130f4520SKenneth D. Merry struct ctlfe_softc *softc; 1802130f4520SKenneth D. Merry struct ctlfe_lun_softc *lun_softc; 1803130f4520SKenneth D. Merry 1804130f4520SKenneth D. Merry softc = (struct ctlfe_softc *)arg; 180559f063d5SAlexander Motin if (softc->hba_misc & PIM_EXTLUNS) 180659f063d5SAlexander Motin lun_id = CAM_EXTLUN_BYTE_SWIZZLE(ctl_encode_lun(lun_id)); 1807130f4520SKenneth D. Merry 1808227d67aaSAlexander Motin mtx_lock(&softc->lun_softc_mtx); 1809130f4520SKenneth D. Merry STAILQ_FOREACH(lun_softc, &softc->lun_softc_list, links) { 1810130f4520SKenneth D. Merry struct cam_path *path; 1811130f4520SKenneth D. Merry 1812130f4520SKenneth D. Merry path = lun_softc->periph->path; 1813130f4520SKenneth D. Merry 1814aeb1faa0SAlexander Motin if ((xpt_path_target_id(path) == softc->target_id) 1815130f4520SKenneth D. Merry && (xpt_path_lun_id(path) == lun_id)) { 1816130f4520SKenneth D. Merry break; 1817130f4520SKenneth D. Merry } 1818130f4520SKenneth D. Merry } 1819130f4520SKenneth D. Merry if (lun_softc == NULL) { 1820227d67aaSAlexander Motin mtx_unlock(&softc->lun_softc_mtx); 18217834ea88SAlexander Motin printf("%s: can't find lun %d\n", __func__, lun_id); 1822130f4520SKenneth D. Merry return (1); 1823130f4520SKenneth D. Merry } 1824227d67aaSAlexander Motin cam_periph_acquire(lun_softc->periph); 1825227d67aaSAlexander Motin mtx_unlock(&softc->lun_softc_mtx); 1826130f4520SKenneth D. Merry 1827227d67aaSAlexander Motin cam_periph_lock(lun_softc->periph); 1828130f4520SKenneth D. Merry cam_periph_invalidate(lun_softc->periph); 1829227d67aaSAlexander Motin cam_periph_unlock(lun_softc->periph); 1830227d67aaSAlexander Motin cam_periph_release(lun_softc->periph); 1831130f4520SKenneth D. Merry return (0); 1832130f4520SKenneth D. Merry } 1833130f4520SKenneth D. Merry 1834130f4520SKenneth D. Merry static void 1835130f4520SKenneth D. Merry ctlfe_dump_sim(struct cam_sim *sim) 1836130f4520SKenneth D. Merry { 1837130f4520SKenneth D. Merry 1838b1303ffeSAlexander Motin printf("%s%d: max dev openings: %d, max tagged dev openings: %d\n", 1839b1303ffeSAlexander Motin sim->sim_name, sim->unit_number, sim->max_dev_openings, 1840b1303ffeSAlexander Motin sim->max_tagged_dev_openings); 1841130f4520SKenneth D. Merry } 1842130f4520SKenneth D. Merry 1843130f4520SKenneth D. Merry /* 1844130f4520SKenneth D. Merry * Assumes that the SIM lock is held. 1845130f4520SKenneth D. Merry */ 1846130f4520SKenneth D. Merry static void 1847130f4520SKenneth D. Merry ctlfe_dump_queue(struct ctlfe_lun_softc *softc) 1848130f4520SKenneth D. Merry { 1849b1303ffeSAlexander Motin struct cam_periph *periph = softc->periph; 1850130f4520SKenneth D. Merry struct ccb_hdr *hdr; 1851b1303ffeSAlexander Motin struct ccb_getdevstats cgds; 1852130f4520SKenneth D. Merry int num_items; 1853130f4520SKenneth D. Merry 1854616a676aSEdward Tomasz Napierala memset(&cgds, 0, sizeof(cgds)); 1855b1303ffeSAlexander Motin xpt_setup_ccb(&cgds.ccb_h, periph->path, CAM_PRIORITY_NORMAL); 1856b1303ffeSAlexander Motin cgds.ccb_h.func_code = XPT_GDEV_STATS; 1857b1303ffeSAlexander Motin xpt_action((union ccb *)&cgds); 1858b1303ffeSAlexander Motin if ((cgds.ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { 1859b1303ffeSAlexander Motin xpt_print(periph->path, "devq: openings %d, active %d, " 1860b1303ffeSAlexander Motin "allocated %d, queued %d, held %d\n", 1861b1303ffeSAlexander Motin cgds.dev_openings, cgds.dev_active, cgds.allocated, 1862b1303ffeSAlexander Motin cgds.queued, cgds.held); 1863b1303ffeSAlexander Motin } 1864b1303ffeSAlexander Motin 1865130f4520SKenneth D. Merry num_items = 0; 1866130f4520SKenneth D. Merry 1867832529c5SAlexander Motin STAILQ_FOREACH(hdr, &softc->work_queue, periph_links.stqe) { 1868993a751eSAlexander Motin union ctl_io *io = hdr->io_ptr; 1869130f4520SKenneth D. Merry 1870130f4520SKenneth D. Merry num_items++; 1871130f4520SKenneth D. Merry 1872130f4520SKenneth D. Merry /* 1873130f4520SKenneth D. Merry * Only regular SCSI I/O is put on the work 1874130f4520SKenneth D. Merry * queue, so we can print sense here. There may be no 1875130f4520SKenneth D. Merry * sense if it's no the queue for a DMA, but this serves to 1876130f4520SKenneth D. Merry * print out the CCB as well. 1877130f4520SKenneth D. Merry * 1878130f4520SKenneth D. Merry * XXX KDM switch this over to scsi_sense_print() when 1879130f4520SKenneth D. Merry * CTL is merged in with CAM. 1880130f4520SKenneth D. Merry */ 1881130f4520SKenneth D. Merry ctl_io_error_print(io, NULL); 1882130f4520SKenneth D. Merry 1883130f4520SKenneth D. Merry /* 1884993a751eSAlexander Motin * Print DMA status if we are DMA_QUEUED. 1885130f4520SKenneth D. Merry */ 1886993a751eSAlexander Motin if (io->io_hdr.flags & CTL_FLAG_DMA_QUEUED) { 1887993a751eSAlexander Motin xpt_print(periph->path, 1888993a751eSAlexander Motin "Total %u, Current %u, Resid %u\n", 1889993a751eSAlexander Motin io->scsiio.kern_total_len, 1890993a751eSAlexander Motin io->scsiio.kern_data_len, 1891130f4520SKenneth D. Merry io->scsiio.kern_data_resid); 1892130f4520SKenneth D. Merry } 1893993a751eSAlexander Motin } 1894130f4520SKenneth D. Merry 18953afd4806SAlexander Motin xpt_print(periph->path, "%d requests waiting for CCBs\n", num_items); 18963afd4806SAlexander Motin xpt_print(periph->path, "%d CTIOs outstanding\n", softc->ctios_sent); 1897130f4520SKenneth D. Merry } 1898130f4520SKenneth D. Merry 1899130f4520SKenneth D. Merry /* 1900130f4520SKenneth D. Merry * Datamove/done routine called by CTL. Put ourselves on the queue to 1901130f4520SKenneth D. Merry * receive a CCB from CAM so we can queue the continue I/O request down 1902130f4520SKenneth D. Merry * to the adapter. 1903130f4520SKenneth D. Merry */ 1904130f4520SKenneth D. Merry static void 1905993a751eSAlexander Motin ctlfe_datamove(union ctl_io *io) 1906993a751eSAlexander Motin { 1907993a751eSAlexander Motin union ccb *ccb; 1908993a751eSAlexander Motin struct cam_periph *periph; 1909993a751eSAlexander Motin struct ctlfe_lun_softc *softc; 1910993a751eSAlexander Motin 1911*ac7a514eSJohn Baldwin CTL_IO_ASSERT(io, SCSI); 1912993a751eSAlexander Motin 1913eb6ac6f9SAlexander Motin io->scsiio.ext_data_filled = 0; 1914e67ac203SAlexander Motin ccb = PRIV_CCB(io); 1915993a751eSAlexander Motin periph = xpt_path_periph(ccb->ccb_h.path); 1916993a751eSAlexander Motin cam_periph_lock(periph); 1917993a751eSAlexander Motin softc = (struct ctlfe_lun_softc *)periph->softc; 1918993a751eSAlexander Motin io->io_hdr.flags |= CTL_FLAG_DMA_QUEUED; 1919993a751eSAlexander Motin if ((io->io_hdr.status & CTL_STATUS_MASK) != CTL_STATUS_NONE) 1920993a751eSAlexander Motin io->io_hdr.flags |= CTL_FLAG_STATUS_QUEUED; 1921832529c5SAlexander Motin STAILQ_INSERT_TAIL(&softc->work_queue, &ccb->ccb_h, 1922832529c5SAlexander Motin periph_links.stqe); 19233afd4806SAlexander Motin xpt_schedule(periph, CAM_PRIORITY_NORMAL); 1924993a751eSAlexander Motin cam_periph_unlock(periph); 1925993a751eSAlexander Motin } 1926993a751eSAlexander Motin 1927993a751eSAlexander Motin static void 1928993a751eSAlexander Motin ctlfe_done(union ctl_io *io) 1929130f4520SKenneth D. Merry { 1930130f4520SKenneth D. Merry union ccb *ccb; 1931130f4520SKenneth D. Merry struct cam_periph *periph; 1932130f4520SKenneth D. Merry struct ctlfe_lun_softc *softc; 1933130f4520SKenneth D. Merry 1934e67ac203SAlexander Motin ccb = PRIV_CCB(io); 1935130f4520SKenneth D. Merry periph = xpt_path_periph(ccb->ccb_h.path); 1936227d67aaSAlexander Motin cam_periph_lock(periph); 1937130f4520SKenneth D. Merry softc = (struct ctlfe_lun_softc *)periph->softc; 1938130f4520SKenneth D. Merry 1939130f4520SKenneth D. Merry if (io->io_hdr.io_type == CTL_IO_TASK) { 1940130f4520SKenneth D. Merry /* 1941130f4520SKenneth D. Merry * Send the notify acknowledge down to the SIM, to let it 1942130f4520SKenneth D. Merry * know we processed the task management command. 1943130f4520SKenneth D. Merry */ 1944130f4520SKenneth D. Merry ccb->ccb_h.status = CAM_REQ_INPROG; 1945130f4520SKenneth D. Merry ccb->ccb_h.func_code = XPT_NOTIFY_ACKNOWLEDGE; 194696b5475bSAlexander Motin switch (io->taskio.task_status) { 194796b5475bSAlexander Motin case CTL_TASK_FUNCTION_COMPLETE: 194896b5475bSAlexander Motin ccb->cna2.arg = CAM_RSP_TMF_COMPLETE; 194996b5475bSAlexander Motin break; 195096b5475bSAlexander Motin case CTL_TASK_FUNCTION_SUCCEEDED: 195196b5475bSAlexander Motin ccb->cna2.arg = CAM_RSP_TMF_SUCCEEDED; 195296b5475bSAlexander Motin ccb->ccb_h.flags |= CAM_SEND_STATUS; 195396b5475bSAlexander Motin break; 195496b5475bSAlexander Motin case CTL_TASK_FUNCTION_REJECTED: 195596b5475bSAlexander Motin ccb->cna2.arg = CAM_RSP_TMF_REJECTED; 195696b5475bSAlexander Motin ccb->ccb_h.flags |= CAM_SEND_STATUS; 195796b5475bSAlexander Motin break; 195896b5475bSAlexander Motin case CTL_TASK_LUN_DOES_NOT_EXIST: 195996b5475bSAlexander Motin ccb->cna2.arg = CAM_RSP_TMF_INCORRECT_LUN; 196096b5475bSAlexander Motin ccb->ccb_h.flags |= CAM_SEND_STATUS; 196196b5475bSAlexander Motin break; 196296b5475bSAlexander Motin case CTL_TASK_FUNCTION_NOT_SUPPORTED: 196396b5475bSAlexander Motin ccb->cna2.arg = CAM_RSP_TMF_FAILED; 196496b5475bSAlexander Motin ccb->ccb_h.flags |= CAM_SEND_STATUS; 196596b5475bSAlexander Motin break; 196696b5475bSAlexander Motin } 196796b5475bSAlexander Motin ccb->cna2.arg |= scsi_3btoul(io->taskio.task_resp) << 8; 1968130f4520SKenneth D. Merry xpt_action(ccb); 1969f7241cceSAlexander Motin } else if (io->io_hdr.flags & CTL_FLAG_STATUS_SENT) { 1970a504738fSAlexander Motin ctlfe_requeue_ccb(periph, ccb, /* unlock */1); 1971f7241cceSAlexander Motin return; 1972130f4520SKenneth D. Merry } else { 1973130f4520SKenneth D. Merry io->io_hdr.flags |= CTL_FLAG_STATUS_QUEUED; 1974832529c5SAlexander Motin STAILQ_INSERT_TAIL(&softc->work_queue, &ccb->ccb_h, 1975832529c5SAlexander Motin periph_links.stqe); 19763afd4806SAlexander Motin xpt_schedule(periph, CAM_PRIORITY_NORMAL); 1977130f4520SKenneth D. Merry } 1978130f4520SKenneth D. Merry 1979227d67aaSAlexander Motin cam_periph_unlock(periph); 1980130f4520SKenneth D. Merry } 1981130f4520SKenneth D. Merry 1982130f4520SKenneth D. Merry static void 1983130f4520SKenneth D. Merry ctlfe_dump(void) 1984130f4520SKenneth D. Merry { 1985130f4520SKenneth D. Merry struct ctlfe_softc *bus_softc; 1986130f4520SKenneth D. Merry struct ctlfe_lun_softc *lun_softc; 1987130f4520SKenneth D. Merry 1988993a751eSAlexander Motin STAILQ_FOREACH(bus_softc, &ctlfe_softc_list, links) { 1989130f4520SKenneth D. Merry ctlfe_dump_sim(bus_softc->sim); 1990993a751eSAlexander Motin STAILQ_FOREACH(lun_softc, &bus_softc->lun_softc_list, links) 1991130f4520SKenneth D. Merry ctlfe_dump_queue(lun_softc); 1992130f4520SKenneth D. Merry } 1993130f4520SKenneth D. Merry } 1994