1ef270ab1SKenneth D. Merry /*- 2ef270ab1SKenneth D. Merry * Copyright (c) 2017 Broadcom. All rights reserved. 3ef270ab1SKenneth D. Merry * The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries. 4ef270ab1SKenneth D. Merry * 5ef270ab1SKenneth D. Merry * Redistribution and use in source and binary forms, with or without 6ef270ab1SKenneth D. Merry * modification, are permitted provided that the following conditions are met: 7ef270ab1SKenneth D. Merry * 8ef270ab1SKenneth D. Merry * 1. Redistributions of source code must retain the above copyright notice, 9ef270ab1SKenneth D. Merry * this list of conditions and the following disclaimer. 10ef270ab1SKenneth D. Merry * 11ef270ab1SKenneth D. Merry * 2. Redistributions in binary form must reproduce the above copyright notice, 12ef270ab1SKenneth D. Merry * this list of conditions and the following disclaimer in the documentation 13ef270ab1SKenneth D. Merry * and/or other materials provided with the distribution. 14ef270ab1SKenneth D. Merry * 15ef270ab1SKenneth D. Merry * 3. Neither the name of the copyright holder nor the names of its contributors 16ef270ab1SKenneth D. Merry * may be used to endorse or promote products derived from this software 17ef270ab1SKenneth D. Merry * without specific prior written permission. 18ef270ab1SKenneth D. Merry * 19ef270ab1SKenneth D. Merry * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20ef270ab1SKenneth D. Merry * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21ef270ab1SKenneth D. Merry * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22ef270ab1SKenneth D. Merry * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 23ef270ab1SKenneth D. Merry * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24ef270ab1SKenneth D. Merry * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25ef270ab1SKenneth D. Merry * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26ef270ab1SKenneth D. Merry * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27ef270ab1SKenneth D. Merry * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28ef270ab1SKenneth D. Merry * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29ef270ab1SKenneth D. Merry * POSSIBILITY OF SUCH DAMAGE. 30ef270ab1SKenneth D. Merry */ 31ef270ab1SKenneth D. Merry 32ef270ab1SKenneth D. Merry /** 33ef270ab1SKenneth D. Merry * @defgroup scsi_api_target SCSI Target API 34ef270ab1SKenneth D. Merry * @defgroup scsi_api_initiator SCSI Initiator API 35ef270ab1SKenneth D. Merry * @defgroup cam_api Common Access Method (CAM) API 36ef270ab1SKenneth D. Merry * @defgroup cam_io CAM IO 37ef270ab1SKenneth D. Merry */ 38ef270ab1SKenneth D. Merry 39ef270ab1SKenneth D. Merry /** 40ef270ab1SKenneth D. Merry * @file 41ef270ab1SKenneth D. Merry * Provides CAM functionality. 42ef270ab1SKenneth D. Merry */ 43ef270ab1SKenneth D. Merry 44ef270ab1SKenneth D. Merry #include "ocs.h" 45ef270ab1SKenneth D. Merry #include "ocs_scsi.h" 46ef270ab1SKenneth D. Merry #include "ocs_device.h" 4770547544SRam Kishore Vegesna #include <sys/sbuf.h> 48ef270ab1SKenneth D. Merry 49ef270ab1SKenneth D. Merry /* Default IO timeout value for initiators is 30 seconds */ 50ef270ab1SKenneth D. Merry #define OCS_CAM_IO_TIMEOUT 30 51ef270ab1SKenneth D. Merry 52ef270ab1SKenneth D. Merry typedef struct { 53ef270ab1SKenneth D. Merry ocs_scsi_sgl_t *sgl; 54ef270ab1SKenneth D. Merry uint32_t sgl_max; 55ef270ab1SKenneth D. Merry uint32_t sgl_count; 56ef270ab1SKenneth D. Merry int32_t rc; 57ef270ab1SKenneth D. Merry } ocs_dmamap_load_arg_t; 58ef270ab1SKenneth D. Merry 5970547544SRam Kishore Vegesna struct ocs_scsi_status_desc { 6070547544SRam Kishore Vegesna ocs_scsi_io_status_e status; 6170547544SRam Kishore Vegesna const char *desc; 6270547544SRam Kishore Vegesna } ocs_status_desc[] = { 6370547544SRam Kishore Vegesna { OCS_SCSI_STATUS_GOOD, "Good" }, 6470547544SRam Kishore Vegesna { OCS_SCSI_STATUS_ABORTED, "Aborted" }, 6570547544SRam Kishore Vegesna { OCS_SCSI_STATUS_ERROR, "Error" }, 6670547544SRam Kishore Vegesna { OCS_SCSI_STATUS_DIF_GUARD_ERROR, "DIF Guard Error" }, 6770547544SRam Kishore Vegesna { OCS_SCSI_STATUS_DIF_REF_TAG_ERROR, "DIF REF Tag Error" }, 6870547544SRam Kishore Vegesna { OCS_SCSI_STATUS_DIF_APP_TAG_ERROR, "DIF App Tag Error" }, 6970547544SRam Kishore Vegesna { OCS_SCSI_STATUS_DIF_UNKNOWN_ERROR, "DIF Unknown Error" }, 7070547544SRam Kishore Vegesna { OCS_SCSI_STATUS_PROTOCOL_CRC_ERROR, "Proto CRC Error" }, 7170547544SRam Kishore Vegesna { OCS_SCSI_STATUS_NO_IO, "No IO" }, 7270547544SRam Kishore Vegesna { OCS_SCSI_STATUS_ABORT_IN_PROGRESS, "Abort in Progress" }, 7370547544SRam Kishore Vegesna { OCS_SCSI_STATUS_CHECK_RESPONSE, "Check Response" }, 7470547544SRam Kishore Vegesna { OCS_SCSI_STATUS_COMMAND_TIMEOUT, "Command Timeout" }, 7570547544SRam Kishore Vegesna { OCS_SCSI_STATUS_TIMEDOUT_AND_ABORTED, "Timed out and Aborted" }, 7670547544SRam Kishore Vegesna { OCS_SCSI_STATUS_SHUTDOWN, "Shutdown" }, 7770547544SRam Kishore Vegesna { OCS_SCSI_STATUS_NEXUS_LOST, "Nexus Lost" } 7870547544SRam Kishore Vegesna }; 7970547544SRam Kishore Vegesna 80ef270ab1SKenneth D. Merry static void ocs_action(struct cam_sim *, union ccb *); 81ef270ab1SKenneth D. Merry static void ocs_poll(struct cam_sim *); 82ef270ab1SKenneth D. Merry 83ef270ab1SKenneth D. Merry static ocs_tgt_resource_t *ocs_tgt_resource_get(ocs_fcport *, 84ef270ab1SKenneth D. Merry struct ccb_hdr *, uint32_t *); 85ef270ab1SKenneth D. Merry static int32_t ocs_tgt_resource_abort(struct ocs_softc *, ocs_tgt_resource_t *); 86ef270ab1SKenneth D. Merry static uint32_t ocs_abort_initiator_io(struct ocs_softc *ocs, union ccb *accb); 87ef270ab1SKenneth D. Merry static void ocs_abort_inot(struct ocs_softc *ocs, union ccb *ccb); 88ef270ab1SKenneth D. Merry static void ocs_abort_atio(struct ocs_softc *ocs, union ccb *ccb); 89ef270ab1SKenneth D. Merry static int32_t ocs_target_tmf_cb(ocs_io_t *, ocs_scsi_io_status_e, uint32_t, void *); 90ef270ab1SKenneth D. Merry static int32_t ocs_io_abort_cb(ocs_io_t *, ocs_scsi_io_status_e, uint32_t, void *); 91ef270ab1SKenneth D. Merry static int32_t ocs_task_set_full_or_busy(ocs_io_t *io); 92ef270ab1SKenneth D. Merry static int32_t ocs_initiator_tmf_cb(ocs_io_t *, ocs_scsi_io_status_e, 93ef270ab1SKenneth D. Merry ocs_scsi_cmd_resp_t *, uint32_t, void *); 94ef270ab1SKenneth D. Merry static uint32_t 95ef270ab1SKenneth D. Merry ocs_fcp_change_role(struct ocs_softc *ocs, ocs_fcport *fcp, uint32_t new_role); 96ef270ab1SKenneth D. Merry 976affb8ebSRam Kishore Vegesna static void ocs_ldt(void *arg); 986affb8ebSRam Kishore Vegesna static void ocs_ldt_task(void *arg, int pending); 996affb8ebSRam Kishore Vegesna static void ocs_delete_target(ocs_t *ocs, ocs_fcport *fcp, int tgt); 1006affb8ebSRam Kishore Vegesna uint32_t ocs_add_new_tgt(ocs_node_t *node, ocs_fcport *fcp); 1016affb8ebSRam Kishore Vegesna uint32_t ocs_update_tgt(ocs_node_t *node, ocs_fcport *fcp, uint32_t tgt_id); 1026affb8ebSRam Kishore Vegesna 1036affb8ebSRam Kishore Vegesna int32_t ocs_tgt_find(ocs_fcport *fcp, ocs_node_t *node); 1046affb8ebSRam Kishore Vegesna 105ef270ab1SKenneth D. Merry static inline ocs_io_t *ocs_scsi_find_io(struct ocs_softc *ocs, uint32_t tag) 106ef270ab1SKenneth D. Merry { 107ef270ab1SKenneth D. Merry 108ef270ab1SKenneth D. Merry return ocs_io_get_instance(ocs, tag); 109ef270ab1SKenneth D. Merry } 110ef270ab1SKenneth D. Merry 111ef270ab1SKenneth D. Merry static inline void ocs_target_io_free(ocs_io_t *io) 112ef270ab1SKenneth D. Merry { 113ef270ab1SKenneth D. Merry io->tgt_io.state = OCS_CAM_IO_FREE; 114ef270ab1SKenneth D. Merry io->tgt_io.flags = 0; 115ef270ab1SKenneth D. Merry io->tgt_io.app = NULL; 116ef270ab1SKenneth D. Merry ocs_scsi_io_complete(io); 117ef270ab1SKenneth D. Merry if(io->ocs->io_in_use != 0) 118ef270ab1SKenneth D. Merry atomic_subtract_acq_32(&io->ocs->io_in_use, 1); 119ef270ab1SKenneth D. Merry } 120ef270ab1SKenneth D. Merry 121ef270ab1SKenneth D. Merry static int32_t 122ef270ab1SKenneth D. Merry ocs_attach_port(ocs_t *ocs, int chan) 123ef270ab1SKenneth D. Merry { 124ef270ab1SKenneth D. Merry 125ef270ab1SKenneth D. Merry struct cam_sim *sim = NULL; 126ef270ab1SKenneth D. Merry struct cam_path *path = NULL; 127ef270ab1SKenneth D. Merry uint32_t max_io = ocs_scsi_get_property(ocs, OCS_SCSI_MAX_IOS); 128ef270ab1SKenneth D. Merry ocs_fcport *fcp = FCPORT(ocs, chan); 129ef270ab1SKenneth D. Merry 130ef270ab1SKenneth D. Merry if (NULL == (sim = cam_sim_alloc(ocs_action, ocs_poll, 131ef270ab1SKenneth D. Merry device_get_name(ocs->dev), ocs, 132ef270ab1SKenneth D. Merry device_get_unit(ocs->dev), &ocs->sim_lock, 133ef270ab1SKenneth D. Merry max_io, max_io, ocs->devq))) { 134ef270ab1SKenneth D. Merry device_printf(ocs->dev, "Can't allocate SIM\n"); 135ef270ab1SKenneth D. Merry return 1; 136ef270ab1SKenneth D. Merry } 137ef270ab1SKenneth D. Merry 138ef270ab1SKenneth D. Merry mtx_lock(&ocs->sim_lock); 139ef270ab1SKenneth D. Merry if (CAM_SUCCESS != xpt_bus_register(sim, ocs->dev, chan)) { 140ef270ab1SKenneth D. Merry device_printf(ocs->dev, "Can't register bus %d\n", 0); 141ef270ab1SKenneth D. Merry mtx_unlock(&ocs->sim_lock); 142ef270ab1SKenneth D. Merry cam_sim_free(sim, FALSE); 143ef270ab1SKenneth D. Merry return 1; 144ef270ab1SKenneth D. Merry } 145ef270ab1SKenneth D. Merry mtx_unlock(&ocs->sim_lock); 146ef270ab1SKenneth D. Merry 147ef270ab1SKenneth D. Merry if (CAM_REQ_CMP != xpt_create_path(&path, NULL, cam_sim_path(sim), 148ef270ab1SKenneth D. Merry CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD)) { 149ef270ab1SKenneth D. Merry device_printf(ocs->dev, "Can't create path\n"); 150ef270ab1SKenneth D. Merry xpt_bus_deregister(cam_sim_path(sim)); 151ef270ab1SKenneth D. Merry mtx_unlock(&ocs->sim_lock); 152ef270ab1SKenneth D. Merry cam_sim_free(sim, FALSE); 153ef270ab1SKenneth D. Merry return 1; 154ef270ab1SKenneth D. Merry } 155ef270ab1SKenneth D. Merry 1566affb8ebSRam Kishore Vegesna fcp->ocs = ocs; 157ef270ab1SKenneth D. Merry fcp->sim = sim; 158ef270ab1SKenneth D. Merry fcp->path = path; 159ef270ab1SKenneth D. Merry 1606affb8ebSRam Kishore Vegesna callout_init_mtx(&fcp->ldt, &ocs->sim_lock, 0); 1616affb8ebSRam Kishore Vegesna TASK_INIT(&fcp->ltask, 1, ocs_ldt_task, fcp); 162ef270ab1SKenneth D. Merry 1636affb8ebSRam Kishore Vegesna return 0; 164ef270ab1SKenneth D. Merry } 165ef270ab1SKenneth D. Merry 166ef270ab1SKenneth D. Merry static int32_t 167ef270ab1SKenneth D. Merry ocs_detach_port(ocs_t *ocs, int32_t chan) 168ef270ab1SKenneth D. Merry { 169ef270ab1SKenneth D. Merry ocs_fcport *fcp = NULL; 170ef270ab1SKenneth D. Merry struct cam_sim *sim = NULL; 171ef270ab1SKenneth D. Merry struct cam_path *path = NULL; 172ef270ab1SKenneth D. Merry fcp = FCPORT(ocs, chan); 173ef270ab1SKenneth D. Merry 174ef270ab1SKenneth D. Merry sim = fcp->sim; 175ef270ab1SKenneth D. Merry path = fcp->path; 176ef270ab1SKenneth D. Merry 1776affb8ebSRam Kishore Vegesna callout_drain(&fcp->ldt); 1786affb8ebSRam Kishore Vegesna ocs_ldt_task(fcp, 0); 1796affb8ebSRam Kishore Vegesna 180ef270ab1SKenneth D. Merry if (fcp->sim) { 181ef270ab1SKenneth D. Merry mtx_lock(&ocs->sim_lock); 182ef270ab1SKenneth D. Merry ocs_tgt_resource_abort(ocs, &fcp->targ_rsrc_wildcard); 183ef270ab1SKenneth D. Merry if (path) { 184ef270ab1SKenneth D. Merry xpt_async(AC_LOST_DEVICE, path, NULL); 185ef270ab1SKenneth D. Merry xpt_free_path(path); 186ef270ab1SKenneth D. Merry fcp->path = NULL; 187ef270ab1SKenneth D. Merry } 188ef270ab1SKenneth D. Merry xpt_bus_deregister(cam_sim_path(sim)); 189ef270ab1SKenneth D. Merry 190ef270ab1SKenneth D. Merry cam_sim_free(sim, FALSE); 191ef270ab1SKenneth D. Merry fcp->sim = NULL; 192ef270ab1SKenneth D. Merry mtx_unlock(&ocs->sim_lock); 193ef270ab1SKenneth D. Merry } 194ef270ab1SKenneth D. Merry 195ef270ab1SKenneth D. Merry return 0; 196ef270ab1SKenneth D. Merry } 197ef270ab1SKenneth D. Merry 198ef270ab1SKenneth D. Merry int32_t 199ef270ab1SKenneth D. Merry ocs_cam_attach(ocs_t *ocs) 200ef270ab1SKenneth D. Merry { 201ef270ab1SKenneth D. Merry struct cam_devq *devq = NULL; 202ef270ab1SKenneth D. Merry int i = 0; 203ef270ab1SKenneth D. Merry uint32_t max_io = ocs_scsi_get_property(ocs, OCS_SCSI_MAX_IOS); 204ef270ab1SKenneth D. Merry 205ef270ab1SKenneth D. Merry if (NULL == (devq = cam_simq_alloc(max_io))) { 206ef270ab1SKenneth D. Merry device_printf(ocs->dev, "Can't allocate SIMQ\n"); 207ef270ab1SKenneth D. Merry return -1; 208ef270ab1SKenneth D. Merry } 209ef270ab1SKenneth D. Merry 210ef270ab1SKenneth D. Merry ocs->devq = devq; 211ef270ab1SKenneth D. Merry 212ef270ab1SKenneth D. Merry if (mtx_initialized(&ocs->sim_lock) == 0) { 213ef270ab1SKenneth D. Merry mtx_init(&ocs->sim_lock, "ocs_sim_lock", NULL, MTX_DEF); 214ef270ab1SKenneth D. Merry } 215ef270ab1SKenneth D. Merry 216ef270ab1SKenneth D. Merry for (i = 0; i < (ocs->num_vports + 1); i++) { 217ef270ab1SKenneth D. Merry if (ocs_attach_port(ocs, i)) { 218ef270ab1SKenneth D. Merry ocs_log_err(ocs, "Attach port failed for chan: %d\n", i); 219ef270ab1SKenneth D. Merry goto detach_port; 220ef270ab1SKenneth D. Merry } 221ef270ab1SKenneth D. Merry } 222ef270ab1SKenneth D. Merry 223ef270ab1SKenneth D. Merry ocs->io_high_watermark = max_io; 224ef270ab1SKenneth D. Merry ocs->io_in_use = 0; 225ef270ab1SKenneth D. Merry return 0; 226ef270ab1SKenneth D. Merry 227ef270ab1SKenneth D. Merry detach_port: 228ef270ab1SKenneth D. Merry while (--i >= 0) { 229ef270ab1SKenneth D. Merry ocs_detach_port(ocs, i); 230ef270ab1SKenneth D. Merry } 231ef270ab1SKenneth D. Merry 232ef270ab1SKenneth D. Merry cam_simq_free(ocs->devq); 233ef270ab1SKenneth D. Merry 234ef270ab1SKenneth D. Merry if (mtx_initialized(&ocs->sim_lock)) 235ef270ab1SKenneth D. Merry mtx_destroy(&ocs->sim_lock); 236ef270ab1SKenneth D. Merry 237ef270ab1SKenneth D. Merry return 1; 238ef270ab1SKenneth D. Merry } 239ef270ab1SKenneth D. Merry 240ef270ab1SKenneth D. Merry int32_t 241ef270ab1SKenneth D. Merry ocs_cam_detach(ocs_t *ocs) 242ef270ab1SKenneth D. Merry { 243ef270ab1SKenneth D. Merry int i = 0; 244ef270ab1SKenneth D. Merry 245ef270ab1SKenneth D. Merry for (i = (ocs->num_vports); i >= 0; i--) { 246ef270ab1SKenneth D. Merry ocs_detach_port(ocs, i); 247ef270ab1SKenneth D. Merry } 248ef270ab1SKenneth D. Merry 249ef270ab1SKenneth D. Merry cam_simq_free(ocs->devq); 250ef270ab1SKenneth D. Merry 251ef270ab1SKenneth D. Merry if (mtx_initialized(&ocs->sim_lock)) 252ef270ab1SKenneth D. Merry mtx_destroy(&ocs->sim_lock); 253ef270ab1SKenneth D. Merry 254ef270ab1SKenneth D. Merry return 0; 255ef270ab1SKenneth D. Merry } 256ef270ab1SKenneth D. Merry 257ef270ab1SKenneth D. Merry /*************************************************************************** 258ef270ab1SKenneth D. Merry * Functions required by SCSI base driver API 259ef270ab1SKenneth D. Merry */ 260ef270ab1SKenneth D. Merry 261ef270ab1SKenneth D. Merry /** 262ef270ab1SKenneth D. Merry * @ingroup scsi_api_target 263ef270ab1SKenneth D. Merry * @brief Attach driver to the BSD SCSI layer (a.k.a CAM) 264ef270ab1SKenneth D. Merry * 265ef270ab1SKenneth D. Merry * Allocates + initializes CAM related resources and attaches to the CAM 266ef270ab1SKenneth D. Merry * 267ef270ab1SKenneth D. Merry * @param ocs the driver instance's software context 268ef270ab1SKenneth D. Merry * 269ef270ab1SKenneth D. Merry * @return 0 on success, non-zero otherwise 270ef270ab1SKenneth D. Merry */ 271ef270ab1SKenneth D. Merry int32_t 272ef270ab1SKenneth D. Merry ocs_scsi_tgt_new_device(ocs_t *ocs) 273ef270ab1SKenneth D. Merry { 274ef270ab1SKenneth D. Merry ocs->enable_task_set_full = ocs_scsi_get_property(ocs, 275ef270ab1SKenneth D. Merry OCS_SCSI_ENABLE_TASK_SET_FULL); 276ef270ab1SKenneth D. Merry ocs_log_debug(ocs, "task set full processing is %s\n", 277ef270ab1SKenneth D. Merry ocs->enable_task_set_full ? "enabled" : "disabled"); 278ef270ab1SKenneth D. Merry 279ef270ab1SKenneth D. Merry return 0; 280ef270ab1SKenneth D. Merry } 281ef270ab1SKenneth D. Merry 282ef270ab1SKenneth D. Merry /** 283ef270ab1SKenneth D. Merry * @ingroup scsi_api_target 284ef270ab1SKenneth D. Merry * @brief Tears down target members of ocs structure. 285ef270ab1SKenneth D. Merry * 286ef270ab1SKenneth D. Merry * Called by OS code when device is removed. 287ef270ab1SKenneth D. Merry * 288ef270ab1SKenneth D. Merry * @param ocs pointer to ocs 289ef270ab1SKenneth D. Merry * 290ef270ab1SKenneth D. Merry * @return returns 0 for success, a negative error code value for failure. 291ef270ab1SKenneth D. Merry */ 292ef270ab1SKenneth D. Merry int32_t 293ef270ab1SKenneth D. Merry ocs_scsi_tgt_del_device(ocs_t *ocs) 294ef270ab1SKenneth D. Merry { 295ef270ab1SKenneth D. Merry 296ef270ab1SKenneth D. Merry return 0; 297ef270ab1SKenneth D. Merry } 298ef270ab1SKenneth D. Merry 299ef270ab1SKenneth D. Merry /** 300ef270ab1SKenneth D. Merry * @ingroup scsi_api_target 301ef270ab1SKenneth D. Merry * @brief accept new domain notification 302ef270ab1SKenneth D. Merry * 303ef270ab1SKenneth D. Merry * Called by base drive when new domain is discovered. A target-server 304ef270ab1SKenneth D. Merry * will use this call to prepare for new remote node notifications 305ef270ab1SKenneth D. Merry * arising from ocs_scsi_new_initiator(). 306ef270ab1SKenneth D. Merry * 307ef270ab1SKenneth D. Merry * The domain context has an element <b>ocs_scsi_tgt_domain_t tgt_domain</b> 308ef270ab1SKenneth D. Merry * which is declared by the target-server code and is used for target-server 309ef270ab1SKenneth D. Merry * private data. 310ef270ab1SKenneth D. Merry * 311ef270ab1SKenneth D. Merry * This function will only be called if the base-driver has been enabled for 312ef270ab1SKenneth D. Merry * target capability. 313ef270ab1SKenneth D. Merry * 314ef270ab1SKenneth D. Merry * Note that this call is made to target-server backends, 315ef270ab1SKenneth D. Merry * the ocs_scsi_ini_new_domain() function is called to initiator-client backends. 316ef270ab1SKenneth D. Merry * 317ef270ab1SKenneth D. Merry * @param domain pointer to domain 318ef270ab1SKenneth D. Merry * 319ef270ab1SKenneth D. Merry * @return returns 0 for success, a negative error code value for failure. 320ef270ab1SKenneth D. Merry */ 321ef270ab1SKenneth D. Merry int32_t 322ef270ab1SKenneth D. Merry ocs_scsi_tgt_new_domain(ocs_domain_t *domain) 323ef270ab1SKenneth D. Merry { 324ef270ab1SKenneth D. Merry return 0; 325ef270ab1SKenneth D. Merry } 326ef270ab1SKenneth D. Merry 327ef270ab1SKenneth D. Merry /** 328ef270ab1SKenneth D. Merry * @ingroup scsi_api_target 329ef270ab1SKenneth D. Merry * @brief accept domain lost notification 330ef270ab1SKenneth D. Merry * 331ef270ab1SKenneth D. Merry * Called by base-driver when a domain goes away. A target-server will 332ef270ab1SKenneth D. Merry * use this call to clean up all domain scoped resources. 333ef270ab1SKenneth D. Merry * 334ef270ab1SKenneth D. Merry * Note that this call is made to target-server backends, 335ef270ab1SKenneth D. Merry * the ocs_scsi_ini_del_domain() function is called to initiator-client backends. 336ef270ab1SKenneth D. Merry * 337ef270ab1SKenneth D. Merry * @param domain pointer to domain 338ef270ab1SKenneth D. Merry * 339ef270ab1SKenneth D. Merry * @return returns 0 for success, a negative error code value for failure. 340ef270ab1SKenneth D. Merry */ 341ef270ab1SKenneth D. Merry void 342ef270ab1SKenneth D. Merry ocs_scsi_tgt_del_domain(ocs_domain_t *domain) 343ef270ab1SKenneth D. Merry { 344ef270ab1SKenneth D. Merry } 345ef270ab1SKenneth D. Merry 346ef270ab1SKenneth D. Merry /** 347ef270ab1SKenneth D. Merry * @ingroup scsi_api_target 348ef270ab1SKenneth D. Merry * @brief accept new sli port (sport) notification 349ef270ab1SKenneth D. Merry * 350ef270ab1SKenneth D. Merry * Called by base drive when new sport is discovered. A target-server 351ef270ab1SKenneth D. Merry * will use this call to prepare for new remote node notifications 352ef270ab1SKenneth D. Merry * arising from ocs_scsi_new_initiator(). 353ef270ab1SKenneth D. Merry * 354ef270ab1SKenneth D. Merry * The domain context has an element <b>ocs_scsi_tgt_sport_t tgt_sport</b> 355ef270ab1SKenneth D. Merry * which is declared by the target-server code and is used for 356ef270ab1SKenneth D. Merry * target-server private data. 357ef270ab1SKenneth D. Merry * 358ef270ab1SKenneth D. Merry * This function will only be called if the base-driver has been enabled for 359ef270ab1SKenneth D. Merry * target capability. 360ef270ab1SKenneth D. Merry * 361ef270ab1SKenneth D. Merry * Note that this call is made to target-server backends, 362ef270ab1SKenneth D. Merry * the ocs_scsi_tgt_new_domain() is called to initiator-client backends. 363ef270ab1SKenneth D. Merry * 364ef270ab1SKenneth D. Merry * @param sport pointer to SLI port 365ef270ab1SKenneth D. Merry * 366ef270ab1SKenneth D. Merry * @return returns 0 for success, a negative error code value for failure. 367ef270ab1SKenneth D. Merry */ 368ef270ab1SKenneth D. Merry int32_t 369ef270ab1SKenneth D. Merry ocs_scsi_tgt_new_sport(ocs_sport_t *sport) 370ef270ab1SKenneth D. Merry { 371ef270ab1SKenneth D. Merry ocs_t *ocs = sport->ocs; 372ef270ab1SKenneth D. Merry 373ef270ab1SKenneth D. Merry if(!sport->is_vport) { 374ef270ab1SKenneth D. Merry sport->tgt_data = FCPORT(ocs, 0); 375ef270ab1SKenneth D. Merry } 376ef270ab1SKenneth D. Merry 377ef270ab1SKenneth D. Merry return 0; 378ef270ab1SKenneth D. Merry } 379ef270ab1SKenneth D. Merry 380ef270ab1SKenneth D. Merry /** 381ef270ab1SKenneth D. Merry * @ingroup scsi_api_target 382ef270ab1SKenneth D. Merry * @brief accept SLI port gone notification 383ef270ab1SKenneth D. Merry * 384ef270ab1SKenneth D. Merry * Called by base-driver when a sport goes away. A target-server will 385ef270ab1SKenneth D. Merry * use this call to clean up all sport scoped resources. 386ef270ab1SKenneth D. Merry * 387ef270ab1SKenneth D. Merry * Note that this call is made to target-server backends, 388ef270ab1SKenneth D. Merry * the ocs_scsi_ini_del_sport() is called to initiator-client backends. 389ef270ab1SKenneth D. Merry * 390ef270ab1SKenneth D. Merry * @param sport pointer to SLI port 391ef270ab1SKenneth D. Merry * 392ef270ab1SKenneth D. Merry * @return returns 0 for success, a negative error code value for failure. 393ef270ab1SKenneth D. Merry */ 394ef270ab1SKenneth D. Merry void 395ef270ab1SKenneth D. Merry ocs_scsi_tgt_del_sport(ocs_sport_t *sport) 396ef270ab1SKenneth D. Merry { 397ef270ab1SKenneth D. Merry return; 398ef270ab1SKenneth D. Merry } 399ef270ab1SKenneth D. Merry 400ef270ab1SKenneth D. Merry /** 401ef270ab1SKenneth D. Merry * @ingroup scsi_api_target 402ef270ab1SKenneth D. Merry * @brief receive notification of a new SCSI initiator node 403ef270ab1SKenneth D. Merry * 404ef270ab1SKenneth D. Merry * Sent by base driver to notify a target-server of the presense of a new 405ef270ab1SKenneth D. Merry * remote initiator. The target-server may use this call to prepare for 406ef270ab1SKenneth D. Merry * inbound IO from this node. 407ef270ab1SKenneth D. Merry * 408ef270ab1SKenneth D. Merry * The ocs_node_t structure has and elment of type ocs_scsi_tgt_node_t named 409ef270ab1SKenneth D. Merry * tgt_node that is declared and used by a target-server for private 410ef270ab1SKenneth D. Merry * information. 411ef270ab1SKenneth D. Merry * 412ef270ab1SKenneth D. Merry * This function is only called if the target capability is enabled in driver. 413ef270ab1SKenneth D. Merry * 414ef270ab1SKenneth D. Merry * @param node pointer to new remote initiator node 415ef270ab1SKenneth D. Merry * 416ef270ab1SKenneth D. Merry * @return returns 0 for success, a negative error code value for failure. 417ef270ab1SKenneth D. Merry * 418ef270ab1SKenneth D. Merry * @note 419ef270ab1SKenneth D. Merry */ 420ef270ab1SKenneth D. Merry int32_t 421ef270ab1SKenneth D. Merry ocs_scsi_new_initiator(ocs_node_t *node) 422ef270ab1SKenneth D. Merry { 423ef270ab1SKenneth D. Merry ocs_t *ocs = node->ocs; 424ef270ab1SKenneth D. Merry struct ac_contract ac; 425ef270ab1SKenneth D. Merry struct ac_device_changed *adc; 426ef270ab1SKenneth D. Merry 427ef270ab1SKenneth D. Merry ocs_fcport *fcp = NULL; 428ef270ab1SKenneth D. Merry 429ef270ab1SKenneth D. Merry fcp = node->sport->tgt_data; 430ef270ab1SKenneth D. Merry if (fcp == NULL) { 431ef270ab1SKenneth D. Merry ocs_log_err(ocs, "FCP is NULL \n"); 432ef270ab1SKenneth D. Merry return 1; 433ef270ab1SKenneth D. Merry } 434ef270ab1SKenneth D. Merry 435ef270ab1SKenneth D. Merry /* 436ef270ab1SKenneth D. Merry * Update the IO watermark by decrementing it by the 437ef270ab1SKenneth D. Merry * number of IOs reserved for each initiator. 438ef270ab1SKenneth D. Merry */ 439ef270ab1SKenneth D. Merry atomic_subtract_acq_32(&ocs->io_high_watermark, OCS_RSVD_INI_IO); 440ef270ab1SKenneth D. Merry 441ef270ab1SKenneth D. Merry ac.contract_number = AC_CONTRACT_DEV_CHG; 442ef270ab1SKenneth D. Merry adc = (struct ac_device_changed *) ac.contract_data; 443ef270ab1SKenneth D. Merry adc->wwpn = ocs_node_get_wwpn(node); 444ef270ab1SKenneth D. Merry adc->port = node->rnode.fc_id; 445ef270ab1SKenneth D. Merry adc->target = node->instance_index; 446ef270ab1SKenneth D. Merry adc->arrived = 1; 447ef270ab1SKenneth D. Merry xpt_async(AC_CONTRACT, fcp->path, &ac); 448ef270ab1SKenneth D. Merry 449ef270ab1SKenneth D. Merry return 0; 450ef270ab1SKenneth D. Merry } 451ef270ab1SKenneth D. Merry 452ef270ab1SKenneth D. Merry /** 453ef270ab1SKenneth D. Merry * @ingroup scsi_api_target 454ef270ab1SKenneth D. Merry * @brief validate new initiator 455ef270ab1SKenneth D. Merry * 456ef270ab1SKenneth D. Merry * Sent by base driver to validate a remote initiatiator. The target-server 457ef270ab1SKenneth D. Merry * returns TRUE if this initiator should be accepted. 458ef270ab1SKenneth D. Merry * 459ef270ab1SKenneth D. Merry * This function is only called if the target capability is enabled in driver. 460ef270ab1SKenneth D. Merry * 461ef270ab1SKenneth D. Merry * @param node pointer to remote initiator node to validate 462ef270ab1SKenneth D. Merry * 463ef270ab1SKenneth D. Merry * @return TRUE if initiator should be accepted, FALSE if it should be rejected 464ef270ab1SKenneth D. Merry * 465ef270ab1SKenneth D. Merry * @note 466ef270ab1SKenneth D. Merry */ 467ef270ab1SKenneth D. Merry 468ef270ab1SKenneth D. Merry int32_t 469ef270ab1SKenneth D. Merry ocs_scsi_validate_initiator(ocs_node_t *node) 470ef270ab1SKenneth D. Merry { 471ef270ab1SKenneth D. Merry return 1; 472ef270ab1SKenneth D. Merry } 473ef270ab1SKenneth D. Merry 474ef270ab1SKenneth D. Merry /** 475ef270ab1SKenneth D. Merry * @ingroup scsi_api_target 476ef270ab1SKenneth D. Merry * @brief Delete a SCSI initiator node 477ef270ab1SKenneth D. Merry * 478ef270ab1SKenneth D. Merry * Sent by base driver to notify a target-server that a remote initiator 479ef270ab1SKenneth D. Merry * is now gone. The base driver will have terminated all outstanding IOs 480ef270ab1SKenneth D. Merry * and the target-server will receive appropriate completions. 481ef270ab1SKenneth D. Merry * 482ef270ab1SKenneth D. Merry * This function is only called if the base driver is enabled for 483ef270ab1SKenneth D. Merry * target capability. 484ef270ab1SKenneth D. Merry * 485ef270ab1SKenneth D. Merry * @param node pointer node being deleted 486ef270ab1SKenneth D. Merry * @param reason Reason why initiator is gone. 487ef270ab1SKenneth D. Merry * 488ef270ab1SKenneth D. Merry * @return OCS_SCSI_CALL_COMPLETE to indicate that all work was completed 489ef270ab1SKenneth D. Merry * 490ef270ab1SKenneth D. Merry * @note 491ef270ab1SKenneth D. Merry */ 492ef270ab1SKenneth D. Merry int32_t 493ef270ab1SKenneth D. Merry ocs_scsi_del_initiator(ocs_node_t *node, ocs_scsi_del_initiator_reason_e reason) 494ef270ab1SKenneth D. Merry { 495ef270ab1SKenneth D. Merry ocs_t *ocs = node->ocs; 496ef270ab1SKenneth D. Merry 497ef270ab1SKenneth D. Merry struct ac_contract ac; 498ef270ab1SKenneth D. Merry struct ac_device_changed *adc; 499ef270ab1SKenneth D. Merry ocs_fcport *fcp = NULL; 500ef270ab1SKenneth D. Merry 501ef270ab1SKenneth D. Merry fcp = node->sport->tgt_data; 502ef270ab1SKenneth D. Merry if (fcp == NULL) { 503ef270ab1SKenneth D. Merry ocs_log_err(ocs, "FCP is NULL \n"); 504ef270ab1SKenneth D. Merry return 1; 505ef270ab1SKenneth D. Merry } 506ef270ab1SKenneth D. Merry 507ef270ab1SKenneth D. Merry ac.contract_number = AC_CONTRACT_DEV_CHG; 508ef270ab1SKenneth D. Merry adc = (struct ac_device_changed *) ac.contract_data; 509ef270ab1SKenneth D. Merry adc->wwpn = ocs_node_get_wwpn(node); 510ef270ab1SKenneth D. Merry adc->port = node->rnode.fc_id; 511ef270ab1SKenneth D. Merry adc->target = node->instance_index; 512ef270ab1SKenneth D. Merry adc->arrived = 0; 513ef270ab1SKenneth D. Merry xpt_async(AC_CONTRACT, fcp->path, &ac); 514ef270ab1SKenneth D. Merry 515ef270ab1SKenneth D. Merry if (reason == OCS_SCSI_INITIATOR_MISSING) { 516ef270ab1SKenneth D. Merry return OCS_SCSI_CALL_COMPLETE; 517ef270ab1SKenneth D. Merry } 518ef270ab1SKenneth D. Merry 519ef270ab1SKenneth D. Merry /* 520ef270ab1SKenneth D. Merry * Update the IO watermark by incrementing it by the 521ef270ab1SKenneth D. Merry * number of IOs reserved for each initiator. 522ef270ab1SKenneth D. Merry */ 523ef270ab1SKenneth D. Merry atomic_add_acq_32(&ocs->io_high_watermark, OCS_RSVD_INI_IO); 524ef270ab1SKenneth D. Merry 525ef270ab1SKenneth D. Merry return OCS_SCSI_CALL_COMPLETE; 526ef270ab1SKenneth D. Merry } 527ef270ab1SKenneth D. Merry 528ef270ab1SKenneth D. Merry /** 529ef270ab1SKenneth D. Merry * @ingroup scsi_api_target 530ef270ab1SKenneth D. Merry * @brief receive FCP SCSI Command 531ef270ab1SKenneth D. Merry * 532ef270ab1SKenneth D. Merry * Called by the base driver when a new SCSI command has been received. The 533ef270ab1SKenneth D. Merry * target-server will process the command, and issue data and/or response phase 534ef270ab1SKenneth D. Merry * requests to the base driver. 535ef270ab1SKenneth D. Merry * 536ef270ab1SKenneth D. Merry * The IO context (ocs_io_t) structure has and element of type 537ef270ab1SKenneth D. Merry * ocs_scsi_tgt_io_t named tgt_io that is declared and used by 538ef270ab1SKenneth D. Merry * a target-server for private information. 539ef270ab1SKenneth D. Merry * 540ef270ab1SKenneth D. Merry * @param io pointer to IO context 541ef270ab1SKenneth D. Merry * @param lun LUN for this IO 542ef270ab1SKenneth D. Merry * @param cdb pointer to SCSI CDB 543ef270ab1SKenneth D. Merry * @param cdb_len length of CDB in bytes 544ef270ab1SKenneth D. Merry * @param flags command flags 545ef270ab1SKenneth D. Merry * 546ef270ab1SKenneth D. Merry * @return returns 0 for success, a negative error code value for failure. 547ef270ab1SKenneth D. Merry */ 548ef270ab1SKenneth D. Merry int32_t ocs_scsi_recv_cmd(ocs_io_t *io, uint64_t lun, uint8_t *cdb, 549ef270ab1SKenneth D. Merry uint32_t cdb_len, uint32_t flags) 550ef270ab1SKenneth D. Merry { 551ef270ab1SKenneth D. Merry ocs_t *ocs = io->ocs; 552ef270ab1SKenneth D. Merry struct ccb_accept_tio *atio = NULL; 553ef270ab1SKenneth D. Merry ocs_node_t *node = io->node; 554ef270ab1SKenneth D. Merry ocs_tgt_resource_t *trsrc = NULL; 555ef270ab1SKenneth D. Merry int32_t rc = -1; 556ef270ab1SKenneth D. Merry ocs_fcport *fcp = NULL; 557ef270ab1SKenneth D. Merry 558ef270ab1SKenneth D. Merry fcp = node->sport->tgt_data; 559ef270ab1SKenneth D. Merry if (fcp == NULL) { 560ef270ab1SKenneth D. Merry ocs_log_err(ocs, "FCP is NULL \n"); 561ef270ab1SKenneth D. Merry return 1; 562ef270ab1SKenneth D. Merry } 563ef270ab1SKenneth D. Merry 564ef270ab1SKenneth D. Merry atomic_add_acq_32(&ocs->io_in_use, 1); 565ef270ab1SKenneth D. Merry 566ef270ab1SKenneth D. Merry /* set target io timeout */ 567ef270ab1SKenneth D. Merry io->timeout = ocs->target_io_timer_sec; 568ef270ab1SKenneth D. Merry 569ef270ab1SKenneth D. Merry if (ocs->enable_task_set_full && 570ef270ab1SKenneth D. Merry (ocs->io_in_use >= ocs->io_high_watermark)) { 571ef270ab1SKenneth D. Merry return ocs_task_set_full_or_busy(io); 572ef270ab1SKenneth D. Merry } else { 573ef270ab1SKenneth D. Merry atomic_store_rel_32(&io->node->tgt_node.busy_sent, FALSE); 574ef270ab1SKenneth D. Merry } 575ef270ab1SKenneth D. Merry 576ef270ab1SKenneth D. Merry if ((lun < OCS_MAX_LUN) && fcp->targ_rsrc[lun].enabled) { 577ef270ab1SKenneth D. Merry trsrc = &fcp->targ_rsrc[lun]; 578ef270ab1SKenneth D. Merry } else if (fcp->targ_rsrc_wildcard.enabled) { 579ef270ab1SKenneth D. Merry trsrc = &fcp->targ_rsrc_wildcard; 580ef270ab1SKenneth D. Merry } 581ef270ab1SKenneth D. Merry 582ef270ab1SKenneth D. Merry if (trsrc) { 583ef270ab1SKenneth D. Merry atio = (struct ccb_accept_tio *)STAILQ_FIRST(&trsrc->atio); 584ef270ab1SKenneth D. Merry } 585ef270ab1SKenneth D. Merry 586ef270ab1SKenneth D. Merry if (atio) { 587ef270ab1SKenneth D. Merry STAILQ_REMOVE_HEAD(&trsrc->atio, sim_links.stqe); 588ef270ab1SKenneth D. Merry 589ef270ab1SKenneth D. Merry atio->ccb_h.status = CAM_CDB_RECVD; 590ef270ab1SKenneth D. Merry atio->ccb_h.target_lun = lun; 591ef270ab1SKenneth D. Merry atio->sense_len = 0; 592ef270ab1SKenneth D. Merry 593ef270ab1SKenneth D. Merry atio->init_id = node->instance_index; 594ef270ab1SKenneth D. Merry atio->tag_id = io->tag; 595ef270ab1SKenneth D. Merry atio->ccb_h.ccb_io_ptr = io; 596ef270ab1SKenneth D. Merry 597ef270ab1SKenneth D. Merry if (flags & OCS_SCSI_CMD_SIMPLE) 598ef270ab1SKenneth D. Merry atio->tag_action = MSG_SIMPLE_Q_TAG; 599eb5a54f8SAlexander Motin else if (flags & OCS_SCSI_CMD_HEAD_OF_QUEUE) 600ef270ab1SKenneth D. Merry atio->tag_action = MSG_HEAD_OF_Q_TAG; 601eb5a54f8SAlexander Motin else if (flags & OCS_SCSI_CMD_ORDERED) 602ef270ab1SKenneth D. Merry atio->tag_action = MSG_ORDERED_Q_TAG; 60388364968SAlexander Motin else if (flags & OCS_SCSI_CMD_ACA) 60488364968SAlexander Motin atio->tag_action = MSG_ACA_TASK; 605ef270ab1SKenneth D. Merry else 60688364968SAlexander Motin atio->tag_action = CAM_TAG_ACTION_NONE; 60788364968SAlexander Motin atio->priority = (flags & OCS_SCSI_PRIORITY_MASK) >> 60888364968SAlexander Motin OCS_SCSI_PRIORITY_SHIFT; 609ef270ab1SKenneth D. Merry 610ef270ab1SKenneth D. Merry atio->cdb_len = cdb_len; 611ef270ab1SKenneth D. Merry ocs_memcpy(atio->cdb_io.cdb_bytes, cdb, cdb_len); 612ef270ab1SKenneth D. Merry 613ef270ab1SKenneth D. Merry io->tgt_io.flags = 0; 614ef270ab1SKenneth D. Merry io->tgt_io.state = OCS_CAM_IO_COMMAND; 615ef270ab1SKenneth D. Merry io->tgt_io.lun = lun; 616ef270ab1SKenneth D. Merry 617ef270ab1SKenneth D. Merry xpt_done((union ccb *)atio); 618ef270ab1SKenneth D. Merry 619ef270ab1SKenneth D. Merry rc = 0; 620ef270ab1SKenneth D. Merry } else { 621ef270ab1SKenneth D. Merry device_printf( 622ef270ab1SKenneth D. Merry ocs->dev, "%s: no ATIO for LUN %lx (en=%s) OX_ID %#x\n", 623ef270ab1SKenneth D. Merry __func__, (unsigned long)lun, 624ef270ab1SKenneth D. Merry trsrc ? (trsrc->enabled ? "T" : "F") : "X", 625ef270ab1SKenneth D. Merry be16toh(io->init_task_tag)); 626ef270ab1SKenneth D. Merry 627ef270ab1SKenneth D. Merry io->tgt_io.state = OCS_CAM_IO_MAX; 628ef270ab1SKenneth D. Merry ocs_target_io_free(io); 629ef270ab1SKenneth D. Merry } 630ef270ab1SKenneth D. Merry 631ef270ab1SKenneth D. Merry return rc; 632ef270ab1SKenneth D. Merry } 633ef270ab1SKenneth D. Merry 634ef270ab1SKenneth D. Merry /** 635ef270ab1SKenneth D. Merry * @ingroup scsi_api_target 636ef270ab1SKenneth D. Merry * @brief receive FCP SCSI Command with first burst data. 637ef270ab1SKenneth D. Merry * 638ef270ab1SKenneth D. Merry * Receive a new FCP SCSI command from the base driver with first burst data. 639ef270ab1SKenneth D. Merry * 640ef270ab1SKenneth D. Merry * @param io pointer to IO context 641ef270ab1SKenneth D. Merry * @param lun LUN for this IO 642ef270ab1SKenneth D. Merry * @param cdb pointer to SCSI CDB 643ef270ab1SKenneth D. Merry * @param cdb_len length of CDB in bytes 644ef270ab1SKenneth D. Merry * @param flags command flags 645ef270ab1SKenneth D. Merry * @param first_burst_buffers first burst buffers 646ef270ab1SKenneth D. Merry * @param first_burst_buffer_count The number of bytes received in the first burst 647ef270ab1SKenneth D. Merry * 648ef270ab1SKenneth D. Merry * @return returns 0 for success, a negative error code value for failure. 649ef270ab1SKenneth D. Merry */ 650ef270ab1SKenneth D. Merry int32_t ocs_scsi_recv_cmd_first_burst(ocs_io_t *io, uint64_t lun, uint8_t *cdb, 651ef270ab1SKenneth D. Merry uint32_t cdb_len, uint32_t flags, 652ef270ab1SKenneth D. Merry ocs_dma_t first_burst_buffers[], 653ef270ab1SKenneth D. Merry uint32_t first_burst_buffer_count) 654ef270ab1SKenneth D. Merry { 655ef270ab1SKenneth D. Merry return -1; 656ef270ab1SKenneth D. Merry } 657ef270ab1SKenneth D. Merry 658ef270ab1SKenneth D. Merry /** 659ef270ab1SKenneth D. Merry * @ingroup scsi_api_target 660ef270ab1SKenneth D. Merry * @brief receive a TMF command IO 661ef270ab1SKenneth D. Merry * 662ef270ab1SKenneth D. Merry * Called by the base driver when a SCSI TMF command has been received. The 663ef270ab1SKenneth D. Merry * target-server will process the command, aborting commands as needed, and post 664ef270ab1SKenneth D. Merry * a response using ocs_scsi_send_resp() 665ef270ab1SKenneth D. Merry * 666ef270ab1SKenneth D. Merry * The IO context (ocs_io_t) structure has and element of type ocs_scsi_tgt_io_t named 667ef270ab1SKenneth D. Merry * tgt_io that is declared and used by a target-server for private information. 668ef270ab1SKenneth D. Merry * 669ef270ab1SKenneth D. Merry * If the target-server walks the nodes active_ios linked list, and starts IO 670ef270ab1SKenneth D. Merry * abort processing, the code <b>must</b> be sure not to abort the IO passed into the 671ef270ab1SKenneth D. Merry * ocs_scsi_recv_tmf() command. 672ef270ab1SKenneth D. Merry * 673ef270ab1SKenneth D. Merry * @param tmfio pointer to IO context 674ef270ab1SKenneth D. Merry * @param lun logical unit value 675ef270ab1SKenneth D. Merry * @param cmd command request 676ef270ab1SKenneth D. Merry * @param abortio pointer to IO object to abort for TASK_ABORT (NULL for all other TMF) 677ef270ab1SKenneth D. Merry * @param flags flags 678ef270ab1SKenneth D. Merry * 679ef270ab1SKenneth D. Merry * @return returns 0 for success, a negative error code value for failure. 680ef270ab1SKenneth D. Merry */ 681ef270ab1SKenneth D. Merry int32_t ocs_scsi_recv_tmf(ocs_io_t *tmfio, uint64_t lun, ocs_scsi_tmf_cmd_e cmd, 682ef270ab1SKenneth D. Merry ocs_io_t *abortio, uint32_t flags) 683ef270ab1SKenneth D. Merry { 684ef270ab1SKenneth D. Merry ocs_t *ocs = tmfio->ocs; 685ef270ab1SKenneth D. Merry ocs_node_t *node = tmfio->node; 686ef270ab1SKenneth D. Merry ocs_tgt_resource_t *trsrc = NULL; 687ef270ab1SKenneth D. Merry struct ccb_immediate_notify *inot = NULL; 688ef270ab1SKenneth D. Merry int32_t rc = -1; 689ef270ab1SKenneth D. Merry ocs_fcport *fcp = NULL; 690ef270ab1SKenneth D. Merry 691ef270ab1SKenneth D. Merry fcp = node->sport->tgt_data; 692ef270ab1SKenneth D. Merry if (fcp == NULL) { 693ef270ab1SKenneth D. Merry ocs_log_err(ocs, "FCP is NULL \n"); 694ef270ab1SKenneth D. Merry return 1; 695ef270ab1SKenneth D. Merry } 696ef270ab1SKenneth D. Merry 697ef270ab1SKenneth D. Merry if ((lun < OCS_MAX_LUN) && fcp->targ_rsrc[lun].enabled) { 698ef270ab1SKenneth D. Merry trsrc = &fcp->targ_rsrc[lun]; 699ef270ab1SKenneth D. Merry } else if (fcp->targ_rsrc_wildcard.enabled) { 700ef270ab1SKenneth D. Merry trsrc = &fcp->targ_rsrc_wildcard; 701ef270ab1SKenneth D. Merry } 702ef270ab1SKenneth D. Merry 703*792e47a5SFuqian Huang device_printf(tmfio->ocs->dev, "%s: io=%u(index) cmd=%#x LU=%lx en=%s\n", 704*792e47a5SFuqian Huang __func__, tmfio->instance_index, cmd, (unsigned long)lun, 705ef270ab1SKenneth D. Merry trsrc ? (trsrc->enabled ? "T" : "F") : "X"); 706ef270ab1SKenneth D. Merry if (trsrc) { 707ef270ab1SKenneth D. Merry inot = (struct ccb_immediate_notify *)STAILQ_FIRST(&trsrc->inot); 708ef270ab1SKenneth D. Merry } 709ef270ab1SKenneth D. Merry 710ef270ab1SKenneth D. Merry if (!inot) { 711ef270ab1SKenneth D. Merry device_printf( 712ef270ab1SKenneth D. Merry ocs->dev, "%s: no INOT for LUN %llx (en=%s) OX_ID %#x\n", 713ef270ab1SKenneth D. Merry __func__, (unsigned long long)lun, trsrc ? (trsrc->enabled ? "T" : "F") : "X", 714ef270ab1SKenneth D. Merry be16toh(tmfio->init_task_tag)); 715ef270ab1SKenneth D. Merry 716ef270ab1SKenneth D. Merry if (abortio) { 717ef270ab1SKenneth D. Merry ocs_scsi_io_complete(abortio); 718ef270ab1SKenneth D. Merry } 719ef270ab1SKenneth D. Merry ocs_scsi_io_complete(tmfio); 720ef270ab1SKenneth D. Merry goto ocs_scsi_recv_tmf_out; 721ef270ab1SKenneth D. Merry } 722ef270ab1SKenneth D. Merry 723ef270ab1SKenneth D. Merry tmfio->tgt_io.app = abortio; 724ef270ab1SKenneth D. Merry 725ef270ab1SKenneth D. Merry STAILQ_REMOVE_HEAD(&trsrc->inot, sim_links.stqe); 726ef270ab1SKenneth D. Merry 727ef270ab1SKenneth D. Merry inot->tag_id = tmfio->tag; 728ef270ab1SKenneth D. Merry inot->seq_id = tmfio->tag; 729ef270ab1SKenneth D. Merry 730ef270ab1SKenneth D. Merry if ((lun < OCS_MAX_LUN) && fcp->targ_rsrc[lun].enabled) { 731ef270ab1SKenneth D. Merry inot->initiator_id = node->instance_index; 732ef270ab1SKenneth D. Merry } else { 733ef270ab1SKenneth D. Merry inot->initiator_id = CAM_TARGET_WILDCARD; 734ef270ab1SKenneth D. Merry } 735ef270ab1SKenneth D. Merry 736ef270ab1SKenneth D. Merry inot->ccb_h.status = CAM_MESSAGE_RECV; 737ef270ab1SKenneth D. Merry inot->ccb_h.target_lun = lun; 738ef270ab1SKenneth D. Merry 739ef270ab1SKenneth D. Merry switch (cmd) { 740ef270ab1SKenneth D. Merry case OCS_SCSI_TMF_ABORT_TASK: 741ef270ab1SKenneth D. Merry inot->arg = MSG_ABORT_TASK; 742ef270ab1SKenneth D. Merry inot->seq_id = abortio->tag; 743ef270ab1SKenneth D. Merry device_printf(ocs->dev, "%s: ABTS IO.%#x st=%#x\n", 744ef270ab1SKenneth D. Merry __func__, abortio->tag, abortio->tgt_io.state); 745ef270ab1SKenneth D. Merry abortio->tgt_io.flags |= OCS_CAM_IO_F_ABORT_RECV; 746ef270ab1SKenneth D. Merry abortio->tgt_io.flags |= OCS_CAM_IO_F_ABORT_NOTIFY; 747ef270ab1SKenneth D. Merry break; 748ef270ab1SKenneth D. Merry case OCS_SCSI_TMF_QUERY_TASK_SET: 749ef270ab1SKenneth D. Merry device_printf(ocs->dev, 750ef270ab1SKenneth D. Merry "%s: OCS_SCSI_TMF_QUERY_TASK_SET not supported\n", 751ef270ab1SKenneth D. Merry __func__); 752ef270ab1SKenneth D. Merry STAILQ_INSERT_TAIL(&trsrc->inot, &inot->ccb_h, sim_links.stqe); 753ef270ab1SKenneth D. Merry ocs_scsi_io_complete(tmfio); 754ef270ab1SKenneth D. Merry goto ocs_scsi_recv_tmf_out; 755ef270ab1SKenneth D. Merry break; 756ef270ab1SKenneth D. Merry case OCS_SCSI_TMF_ABORT_TASK_SET: 757ef270ab1SKenneth D. Merry inot->arg = MSG_ABORT_TASK_SET; 758ef270ab1SKenneth D. Merry break; 759ef270ab1SKenneth D. Merry case OCS_SCSI_TMF_CLEAR_TASK_SET: 760ef270ab1SKenneth D. Merry inot->arg = MSG_CLEAR_TASK_SET; 761ef270ab1SKenneth D. Merry break; 762ef270ab1SKenneth D. Merry case OCS_SCSI_TMF_QUERY_ASYNCHRONOUS_EVENT: 763ef270ab1SKenneth D. Merry inot->arg = MSG_QUERY_ASYNC_EVENT; 764ef270ab1SKenneth D. Merry break; 765ef270ab1SKenneth D. Merry case OCS_SCSI_TMF_LOGICAL_UNIT_RESET: 766ef270ab1SKenneth D. Merry inot->arg = MSG_LOGICAL_UNIT_RESET; 767ef270ab1SKenneth D. Merry break; 768ef270ab1SKenneth D. Merry case OCS_SCSI_TMF_CLEAR_ACA: 769ef270ab1SKenneth D. Merry inot->arg = MSG_CLEAR_ACA; 770ef270ab1SKenneth D. Merry break; 771ef270ab1SKenneth D. Merry case OCS_SCSI_TMF_TARGET_RESET: 772ef270ab1SKenneth D. Merry inot->arg = MSG_TARGET_RESET; 773ef270ab1SKenneth D. Merry break; 774ef270ab1SKenneth D. Merry default: 775ef270ab1SKenneth D. Merry device_printf(ocs->dev, "%s: unsupported TMF %#x\n", 776ef270ab1SKenneth D. Merry __func__, cmd); 777ef270ab1SKenneth D. Merry STAILQ_INSERT_TAIL(&trsrc->inot, &inot->ccb_h, sim_links.stqe); 778ef270ab1SKenneth D. Merry goto ocs_scsi_recv_tmf_out; 779ef270ab1SKenneth D. Merry } 780ef270ab1SKenneth D. Merry 781ef270ab1SKenneth D. Merry rc = 0; 782ef270ab1SKenneth D. Merry 783ef270ab1SKenneth D. Merry xpt_print(inot->ccb_h.path, "%s: func=%#x stat=%#x id=%#x lun=%#x" 784ef270ab1SKenneth D. Merry " flags=%#x tag=%#x seq=%#x ini=%#x arg=%#x\n", 785ef270ab1SKenneth D. Merry __func__, inot->ccb_h.func_code, inot->ccb_h.status, 786ef270ab1SKenneth D. Merry inot->ccb_h.target_id, 787ef270ab1SKenneth D. Merry (unsigned int)inot->ccb_h.target_lun, inot->ccb_h.flags, 788ef270ab1SKenneth D. Merry inot->tag_id, inot->seq_id, inot->initiator_id, 789ef270ab1SKenneth D. Merry inot->arg); 790ef270ab1SKenneth D. Merry xpt_done((union ccb *)inot); 791ef270ab1SKenneth D. Merry 792ef270ab1SKenneth D. Merry if (abortio) { 793ef270ab1SKenneth D. Merry abortio->tgt_io.flags |= OCS_CAM_IO_F_ABORT_DEV; 794ef270ab1SKenneth D. Merry rc = ocs_scsi_tgt_abort_io(abortio, ocs_io_abort_cb, tmfio); 795ef270ab1SKenneth D. Merry } 796ef270ab1SKenneth D. Merry 797ef270ab1SKenneth D. Merry ocs_scsi_recv_tmf_out: 798ef270ab1SKenneth D. Merry return rc; 799ef270ab1SKenneth D. Merry } 800ef270ab1SKenneth D. Merry 801ef270ab1SKenneth D. Merry /** 802ef270ab1SKenneth D. Merry * @ingroup scsi_api_initiator 803ef270ab1SKenneth D. Merry * @brief Initializes any initiator fields on the ocs structure. 804ef270ab1SKenneth D. Merry * 805ef270ab1SKenneth D. Merry * Called by OS initialization code when a new device is discovered. 806ef270ab1SKenneth D. Merry * 807ef270ab1SKenneth D. Merry * @param ocs pointer to ocs 808ef270ab1SKenneth D. Merry * 809ef270ab1SKenneth D. Merry * @return returns 0 for success, a negative error code value for failure. 810ef270ab1SKenneth D. Merry */ 811ef270ab1SKenneth D. Merry int32_t 812ef270ab1SKenneth D. Merry ocs_scsi_ini_new_device(ocs_t *ocs) 813ef270ab1SKenneth D. Merry { 814ef270ab1SKenneth D. Merry 815ef270ab1SKenneth D. Merry return 0; 816ef270ab1SKenneth D. Merry } 817ef270ab1SKenneth D. Merry 818ef270ab1SKenneth D. Merry /** 819ef270ab1SKenneth D. Merry * @ingroup scsi_api_initiator 820ef270ab1SKenneth D. Merry * @brief Tears down initiator members of ocs structure. 821ef270ab1SKenneth D. Merry * 822ef270ab1SKenneth D. Merry * Called by OS code when device is removed. 823ef270ab1SKenneth D. Merry * 824ef270ab1SKenneth D. Merry * @param ocs pointer to ocs 825ef270ab1SKenneth D. Merry * 826ef270ab1SKenneth D. Merry * @return returns 0 for success, a negative error code value for failure. 827ef270ab1SKenneth D. Merry */ 828ef270ab1SKenneth D. Merry 829ef270ab1SKenneth D. Merry int32_t 830ef270ab1SKenneth D. Merry ocs_scsi_ini_del_device(ocs_t *ocs) 831ef270ab1SKenneth D. Merry { 832ef270ab1SKenneth D. Merry 833ef270ab1SKenneth D. Merry return 0; 834ef270ab1SKenneth D. Merry } 835ef270ab1SKenneth D. Merry 836ef270ab1SKenneth D. Merry /** 837ef270ab1SKenneth D. Merry * @ingroup scsi_api_initiator 838ef270ab1SKenneth D. Merry * @brief accept new domain notification 839ef270ab1SKenneth D. Merry * 840ef270ab1SKenneth D. Merry * Called by base drive when new domain is discovered. An initiator-client 841ef270ab1SKenneth D. Merry * will accept this call to prepare for new remote node notifications 842ef270ab1SKenneth D. Merry * arising from ocs_scsi_new_target(). 843ef270ab1SKenneth D. Merry * 844ef270ab1SKenneth D. Merry * The domain context has the element <b>ocs_scsi_ini_domain_t ini_domain</b> 845ef270ab1SKenneth D. Merry * which is declared by the initiator-client code and is used for 846ef270ab1SKenneth D. Merry * initiator-client private data. 847ef270ab1SKenneth D. Merry * 848ef270ab1SKenneth D. Merry * This function will only be called if the base-driver has been enabled for 849ef270ab1SKenneth D. Merry * initiator capability. 850ef270ab1SKenneth D. Merry * 851ef270ab1SKenneth D. Merry * Note that this call is made to initiator-client backends, 852ef270ab1SKenneth D. Merry * the ocs_scsi_tgt_new_domain() function is called to target-server backends. 853ef270ab1SKenneth D. Merry * 854ef270ab1SKenneth D. Merry * @param domain pointer to domain 855ef270ab1SKenneth D. Merry * 856ef270ab1SKenneth D. Merry * @return returns 0 for success, a negative error code value for failure. 857ef270ab1SKenneth D. Merry */ 858ef270ab1SKenneth D. Merry int32_t 859ef270ab1SKenneth D. Merry ocs_scsi_ini_new_domain(ocs_domain_t *domain) 860ef270ab1SKenneth D. Merry { 861ef270ab1SKenneth D. Merry return 0; 862ef270ab1SKenneth D. Merry } 863ef270ab1SKenneth D. Merry 864ef270ab1SKenneth D. Merry /** 865ef270ab1SKenneth D. Merry * @ingroup scsi_api_initiator 866ef270ab1SKenneth D. Merry * @brief accept domain lost notification 867ef270ab1SKenneth D. Merry * 868ef270ab1SKenneth D. Merry * Called by base-driver when a domain goes away. An initiator-client will 869ef270ab1SKenneth D. Merry * use this call to clean up all domain scoped resources. 870ef270ab1SKenneth D. Merry * 871ef270ab1SKenneth D. Merry * This function will only be called if the base-driver has been enabled for 872ef270ab1SKenneth D. Merry * initiator capability. 873ef270ab1SKenneth D. Merry * 874ef270ab1SKenneth D. Merry * Note that this call is made to initiator-client backends, 875ef270ab1SKenneth D. Merry * the ocs_scsi_tgt_del_domain() function is called to target-server backends. 876ef270ab1SKenneth D. Merry * 877ef270ab1SKenneth D. Merry * @param domain pointer to domain 878ef270ab1SKenneth D. Merry * 879ef270ab1SKenneth D. Merry * @return returns 0 for success, a negative error code value for failure. 880ef270ab1SKenneth D. Merry */ 881ef270ab1SKenneth D. Merry void 882ef270ab1SKenneth D. Merry ocs_scsi_ini_del_domain(ocs_domain_t *domain) 883ef270ab1SKenneth D. Merry { 884ef270ab1SKenneth D. Merry } 885ef270ab1SKenneth D. Merry 886ef270ab1SKenneth D. Merry /** 887ef270ab1SKenneth D. Merry * @ingroup scsi_api_initiator 888ef270ab1SKenneth D. Merry * @brief accept new sli port notification 889ef270ab1SKenneth D. Merry * 890ef270ab1SKenneth D. Merry * Called by base drive when new sli port (sport) is discovered. 891ef270ab1SKenneth D. Merry * A target-server will use this call to prepare for new remote node 892ef270ab1SKenneth D. Merry * notifications arising from ocs_scsi_new_initiator(). 893ef270ab1SKenneth D. Merry * 894ef270ab1SKenneth D. Merry * This function will only be called if the base-driver has been enabled for 895ef270ab1SKenneth D. Merry * target capability. 896ef270ab1SKenneth D. Merry * 897ef270ab1SKenneth D. Merry * Note that this call is made to target-server backends, 898ef270ab1SKenneth D. Merry * the ocs_scsi_ini_new_sport() function is called to initiator-client backends. 899ef270ab1SKenneth D. Merry * 900ef270ab1SKenneth D. Merry * @param sport pointer to sport 901ef270ab1SKenneth D. Merry * 902ef270ab1SKenneth D. Merry * @return returns 0 for success, a negative error code value for failure. 903ef270ab1SKenneth D. Merry */ 904ef270ab1SKenneth D. Merry int32_t 905ef270ab1SKenneth D. Merry ocs_scsi_ini_new_sport(ocs_sport_t *sport) 906ef270ab1SKenneth D. Merry { 907ef270ab1SKenneth D. Merry ocs_t *ocs = sport->ocs; 908b9732f78SRam Kishore Vegesna ocs_fcport *fcp = FCPORT(ocs, 0); 909ef270ab1SKenneth D. Merry 910ef270ab1SKenneth D. Merry if (!sport->is_vport) { 911b9732f78SRam Kishore Vegesna sport->tgt_data = fcp; 912b9732f78SRam Kishore Vegesna fcp->fc_id = sport->fc_id; 913ef270ab1SKenneth D. Merry } 914ef270ab1SKenneth D. Merry 915ef270ab1SKenneth D. Merry return 0; 916ef270ab1SKenneth D. Merry } 917ef270ab1SKenneth D. Merry 918ef270ab1SKenneth D. Merry /** 919ef270ab1SKenneth D. Merry * @ingroup scsi_api_initiator 920ef270ab1SKenneth D. Merry * @brief accept sli port gone notification 921ef270ab1SKenneth D. Merry * 922ef270ab1SKenneth D. Merry * Called by base-driver when a sport goes away. A target-server will 923ef270ab1SKenneth D. Merry * use this call to clean up all sport scoped resources. 924ef270ab1SKenneth D. Merry * 925ef270ab1SKenneth D. Merry * Note that this call is made to target-server backends, 926ef270ab1SKenneth D. Merry * the ocs_scsi_ini_del_sport() function is called to initiator-client backends. 927ef270ab1SKenneth D. Merry * 928ef270ab1SKenneth D. Merry * @param sport pointer to SLI port 929ef270ab1SKenneth D. Merry * 930ef270ab1SKenneth D. Merry * @return returns 0 for success, a negative error code value for failure. 931ef270ab1SKenneth D. Merry */ 932ef270ab1SKenneth D. Merry void 933ef270ab1SKenneth D. Merry ocs_scsi_ini_del_sport(ocs_sport_t *sport) 934ef270ab1SKenneth D. Merry { 935b9732f78SRam Kishore Vegesna ocs_t *ocs = sport->ocs; 936b9732f78SRam Kishore Vegesna ocs_fcport *fcp = FCPORT(ocs, 0); 937b9732f78SRam Kishore Vegesna 938b9732f78SRam Kishore Vegesna if (!sport->is_vport) { 939b9732f78SRam Kishore Vegesna fcp->fc_id = 0; 940b9732f78SRam Kishore Vegesna } 941ef270ab1SKenneth D. Merry } 942ef270ab1SKenneth D. Merry 943ef270ab1SKenneth D. Merry void 944ef270ab1SKenneth D. Merry ocs_scsi_sport_deleted(ocs_sport_t *sport) 945ef270ab1SKenneth D. Merry { 946ef270ab1SKenneth D. Merry ocs_t *ocs = sport->ocs; 947ef270ab1SKenneth D. Merry ocs_fcport *fcp = NULL; 948ef270ab1SKenneth D. Merry 949ef270ab1SKenneth D. Merry ocs_xport_stats_t value; 950ef270ab1SKenneth D. Merry 951ef270ab1SKenneth D. Merry if (!sport->is_vport) { 952ef270ab1SKenneth D. Merry return; 953ef270ab1SKenneth D. Merry } 954ef270ab1SKenneth D. Merry 955ef270ab1SKenneth D. Merry fcp = sport->tgt_data; 956ef270ab1SKenneth D. Merry 957ef270ab1SKenneth D. Merry ocs_xport_status(ocs->xport, OCS_XPORT_PORT_STATUS, &value); 958ef270ab1SKenneth D. Merry 959ef270ab1SKenneth D. Merry if (value.value == 0) { 960ef270ab1SKenneth D. Merry ocs_log_debug(ocs, "PORT offline,.. skipping\n"); 961ef270ab1SKenneth D. Merry return; 962ef270ab1SKenneth D. Merry } 963ef270ab1SKenneth D. Merry 964ef270ab1SKenneth D. Merry if ((fcp->role != KNOB_ROLE_NONE)) { 965ef270ab1SKenneth D. Merry if(fcp->vport->sport != NULL) { 966ef270ab1SKenneth D. Merry ocs_log_debug(ocs,"sport is not NULL, skipping\n"); 967ef270ab1SKenneth D. Merry return; 968ef270ab1SKenneth D. Merry } 969ef270ab1SKenneth D. Merry 970ef270ab1SKenneth D. Merry ocs_sport_vport_alloc(ocs->domain, fcp->vport); 971ef270ab1SKenneth D. Merry return; 972ef270ab1SKenneth D. Merry } 973ef270ab1SKenneth D. Merry 974ef270ab1SKenneth D. Merry } 975ef270ab1SKenneth D. Merry 9766affb8ebSRam Kishore Vegesna int32_t 9776affb8ebSRam Kishore Vegesna ocs_tgt_find(ocs_fcport *fcp, ocs_node_t *node) 9786affb8ebSRam Kishore Vegesna { 9796affb8ebSRam Kishore Vegesna ocs_fc_target_t *tgt = NULL; 9806affb8ebSRam Kishore Vegesna uint32_t i; 9816affb8ebSRam Kishore Vegesna 9826affb8ebSRam Kishore Vegesna for (i = 0; i < OCS_MAX_TARGETS; i++) { 9836affb8ebSRam Kishore Vegesna tgt = &fcp->tgt[i]; 9846affb8ebSRam Kishore Vegesna 9856affb8ebSRam Kishore Vegesna if (tgt->state == OCS_TGT_STATE_NONE) 9866affb8ebSRam Kishore Vegesna continue; 9876affb8ebSRam Kishore Vegesna 9886affb8ebSRam Kishore Vegesna if (ocs_node_get_wwpn(node) == tgt->wwpn) { 9896affb8ebSRam Kishore Vegesna return i; 9906affb8ebSRam Kishore Vegesna } 9916affb8ebSRam Kishore Vegesna } 9926affb8ebSRam Kishore Vegesna 9936affb8ebSRam Kishore Vegesna return -1; 9946affb8ebSRam Kishore Vegesna } 9956affb8ebSRam Kishore Vegesna 996ef270ab1SKenneth D. Merry /** 997ef270ab1SKenneth D. Merry * @ingroup scsi_api_initiator 998ef270ab1SKenneth D. Merry * @brief receive notification of a new SCSI target node 999ef270ab1SKenneth D. Merry * 1000ef270ab1SKenneth D. Merry * Sent by base driver to notify an initiator-client of the presense of a new 1001ef270ab1SKenneth D. Merry * remote target. The initiator-server may use this call to prepare for 1002ef270ab1SKenneth D. Merry * inbound IO from this node. 1003ef270ab1SKenneth D. Merry * 1004ef270ab1SKenneth D. Merry * This function is only called if the base driver is enabled for 1005ef270ab1SKenneth D. Merry * initiator capability. 1006ef270ab1SKenneth D. Merry * 1007ef270ab1SKenneth D. Merry * @param node pointer to new remote initiator node 1008ef270ab1SKenneth D. Merry * 1009ef270ab1SKenneth D. Merry * @return none 1010ef270ab1SKenneth D. Merry * 1011ef270ab1SKenneth D. Merry * @note 1012ef270ab1SKenneth D. Merry */ 10136affb8ebSRam Kishore Vegesna 10146affb8ebSRam Kishore Vegesna uint32_t 10156affb8ebSRam Kishore Vegesna ocs_update_tgt(ocs_node_t *node, ocs_fcport *fcp, uint32_t tgt_id) 1016ef270ab1SKenneth D. Merry { 10176affb8ebSRam Kishore Vegesna ocs_fc_target_t *tgt = NULL; 10186affb8ebSRam Kishore Vegesna 10196affb8ebSRam Kishore Vegesna tgt = &fcp->tgt[tgt_id]; 10206affb8ebSRam Kishore Vegesna 10216affb8ebSRam Kishore Vegesna tgt->node_id = node->instance_index; 10226affb8ebSRam Kishore Vegesna tgt->state = OCS_TGT_STATE_VALID; 10236affb8ebSRam Kishore Vegesna 10246affb8ebSRam Kishore Vegesna tgt->port_id = node->rnode.fc_id; 10256affb8ebSRam Kishore Vegesna tgt->wwpn = ocs_node_get_wwpn(node); 10266affb8ebSRam Kishore Vegesna tgt->wwnn = ocs_node_get_wwnn(node); 10276affb8ebSRam Kishore Vegesna return 0; 10286affb8ebSRam Kishore Vegesna } 10296affb8ebSRam Kishore Vegesna 10306affb8ebSRam Kishore Vegesna uint32_t 10316affb8ebSRam Kishore Vegesna ocs_add_new_tgt(ocs_node_t *node, ocs_fcport *fcp) 10326affb8ebSRam Kishore Vegesna { 10336affb8ebSRam Kishore Vegesna uint32_t i; 10346affb8ebSRam Kishore Vegesna 1035ef270ab1SKenneth D. Merry struct ocs_softc *ocs = node->ocs; 1036ef270ab1SKenneth D. Merry union ccb *ccb = NULL; 10376affb8ebSRam Kishore Vegesna for (i = 0; i < OCS_MAX_TARGETS; i++) { 10386affb8ebSRam Kishore Vegesna if (fcp->tgt[i].state == OCS_TGT_STATE_NONE) 10396affb8ebSRam Kishore Vegesna break; 1040ef270ab1SKenneth D. Merry } 1041ef270ab1SKenneth D. Merry 1042ef270ab1SKenneth D. Merry if (NULL == (ccb = xpt_alloc_ccb_nowait())) { 1043ef270ab1SKenneth D. Merry device_printf(ocs->dev, "%s: ccb allocation failed\n", __func__); 1044ef270ab1SKenneth D. Merry return -1; 1045ef270ab1SKenneth D. Merry } 1046ef270ab1SKenneth D. Merry 1047ef270ab1SKenneth D. Merry if (CAM_REQ_CMP != xpt_create_path(&ccb->ccb_h.path, xpt_periph, 1048ef270ab1SKenneth D. Merry cam_sim_path(fcp->sim), 10496affb8ebSRam Kishore Vegesna i, CAM_LUN_WILDCARD)) { 1050ef270ab1SKenneth D. Merry device_printf( 1051ef270ab1SKenneth D. Merry ocs->dev, "%s: target path creation failed\n", __func__); 1052ef270ab1SKenneth D. Merry xpt_free_ccb(ccb); 1053ef270ab1SKenneth D. Merry return -1; 1054ef270ab1SKenneth D. Merry } 1055ef270ab1SKenneth D. Merry 10566affb8ebSRam Kishore Vegesna ocs_update_tgt(node, fcp, i); 1057ef270ab1SKenneth D. Merry xpt_rescan(ccb); 1058ef270ab1SKenneth D. Merry return 0; 1059ef270ab1SKenneth D. Merry } 1060ef270ab1SKenneth D. Merry 10616affb8ebSRam Kishore Vegesna int32_t 10626affb8ebSRam Kishore Vegesna ocs_scsi_new_target(ocs_node_t *node) 10636affb8ebSRam Kishore Vegesna { 10646affb8ebSRam Kishore Vegesna ocs_fcport *fcp = NULL; 10656affb8ebSRam Kishore Vegesna int32_t i; 10666affb8ebSRam Kishore Vegesna 10676affb8ebSRam Kishore Vegesna fcp = node->sport->tgt_data; 10686affb8ebSRam Kishore Vegesna if (fcp == NULL) { 10696affb8ebSRam Kishore Vegesna printf("%s:FCP is NULL \n", __func__); 10706affb8ebSRam Kishore Vegesna return 0; 10716affb8ebSRam Kishore Vegesna } 10726affb8ebSRam Kishore Vegesna 10736affb8ebSRam Kishore Vegesna i = ocs_tgt_find(fcp, node); 10746affb8ebSRam Kishore Vegesna 10756affb8ebSRam Kishore Vegesna if (i < 0) { 10766affb8ebSRam Kishore Vegesna ocs_add_new_tgt(node, fcp); 10776affb8ebSRam Kishore Vegesna return 0; 10786affb8ebSRam Kishore Vegesna } 10796affb8ebSRam Kishore Vegesna 10806affb8ebSRam Kishore Vegesna ocs_update_tgt(node, fcp, i); 10816affb8ebSRam Kishore Vegesna return 0; 10826affb8ebSRam Kishore Vegesna } 10836affb8ebSRam Kishore Vegesna 10846affb8ebSRam Kishore Vegesna static void 10856affb8ebSRam Kishore Vegesna ocs_delete_target(ocs_t *ocs, ocs_fcport *fcp, int tgt) 10866affb8ebSRam Kishore Vegesna { 10876affb8ebSRam Kishore Vegesna struct cam_path *cpath = NULL; 10886affb8ebSRam Kishore Vegesna 10896affb8ebSRam Kishore Vegesna if (!fcp->sim) { 10906affb8ebSRam Kishore Vegesna device_printf(ocs->dev, "%s: calling with NULL sim\n", __func__); 10916affb8ebSRam Kishore Vegesna return; 10926affb8ebSRam Kishore Vegesna } 10936affb8ebSRam Kishore Vegesna 10946affb8ebSRam Kishore Vegesna if (CAM_REQ_CMP == xpt_create_path(&cpath, NULL, cam_sim_path(fcp->sim), 10956affb8ebSRam Kishore Vegesna tgt, CAM_LUN_WILDCARD)) { 10966affb8ebSRam Kishore Vegesna xpt_async(AC_LOST_DEVICE, cpath, NULL); 10976affb8ebSRam Kishore Vegesna 10986affb8ebSRam Kishore Vegesna xpt_free_path(cpath); 10996affb8ebSRam Kishore Vegesna } 11006affb8ebSRam Kishore Vegesna } 11016affb8ebSRam Kishore Vegesna 11026affb8ebSRam Kishore Vegesna /* 11036affb8ebSRam Kishore Vegesna * Device Lost Timer Function- when we have decided that a device was lost, 11046affb8ebSRam Kishore Vegesna * we wait a specific period of time prior to telling the OS about lost device. 11056affb8ebSRam Kishore Vegesna * 11066affb8ebSRam Kishore Vegesna * This timer function gets activated when the device was lost. 11076affb8ebSRam Kishore Vegesna * This function fires once a second and then scans the port database 11086affb8ebSRam Kishore Vegesna * for devices that are marked dead but still have a virtual target assigned. 11096affb8ebSRam Kishore Vegesna * We decrement a counter for that port database entry, and when it hits zero, 11106affb8ebSRam Kishore Vegesna * we tell the OS the device was lost. Timer will be stopped when the device 11116affb8ebSRam Kishore Vegesna * comes back active or removed from the OS. 11126affb8ebSRam Kishore Vegesna */ 11136affb8ebSRam Kishore Vegesna static void 11146affb8ebSRam Kishore Vegesna ocs_ldt(void *arg) 11156affb8ebSRam Kishore Vegesna { 11166affb8ebSRam Kishore Vegesna ocs_fcport *fcp = arg; 11176affb8ebSRam Kishore Vegesna taskqueue_enqueue(taskqueue_thread, &fcp->ltask); 11186affb8ebSRam Kishore Vegesna } 11196affb8ebSRam Kishore Vegesna 11206affb8ebSRam Kishore Vegesna static void 11216affb8ebSRam Kishore Vegesna ocs_ldt_task(void *arg, int pending) 11226affb8ebSRam Kishore Vegesna { 11236affb8ebSRam Kishore Vegesna ocs_fcport *fcp = arg; 11246affb8ebSRam Kishore Vegesna ocs_t *ocs = fcp->ocs; 11256affb8ebSRam Kishore Vegesna int i, more_to_do = 0; 11266affb8ebSRam Kishore Vegesna ocs_fc_target_t *tgt = NULL; 11276affb8ebSRam Kishore Vegesna 11286affb8ebSRam Kishore Vegesna for (i = 0; i < OCS_MAX_TARGETS; i++) { 11296affb8ebSRam Kishore Vegesna tgt = &fcp->tgt[i]; 11306affb8ebSRam Kishore Vegesna 11316affb8ebSRam Kishore Vegesna if (tgt->state != OCS_TGT_STATE_LOST) { 11326affb8ebSRam Kishore Vegesna continue; 11336affb8ebSRam Kishore Vegesna } 11346affb8ebSRam Kishore Vegesna 11356affb8ebSRam Kishore Vegesna if ((tgt->gone_timer != 0) && (ocs->attached)){ 11366affb8ebSRam Kishore Vegesna tgt->gone_timer -= 1; 11376affb8ebSRam Kishore Vegesna more_to_do++; 11386affb8ebSRam Kishore Vegesna continue; 11396affb8ebSRam Kishore Vegesna } 11406affb8ebSRam Kishore Vegesna 11416affb8ebSRam Kishore Vegesna ocs_delete_target(ocs, fcp, i); 11426affb8ebSRam Kishore Vegesna 11436affb8ebSRam Kishore Vegesna tgt->state = OCS_TGT_STATE_NONE; 11446affb8ebSRam Kishore Vegesna } 11456affb8ebSRam Kishore Vegesna 11466affb8ebSRam Kishore Vegesna if (more_to_do) { 11476affb8ebSRam Kishore Vegesna callout_reset(&fcp->ldt, hz, ocs_ldt, fcp); 11486affb8ebSRam Kishore Vegesna } else { 11496affb8ebSRam Kishore Vegesna callout_deactivate(&fcp->ldt); 11506affb8ebSRam Kishore Vegesna } 11516affb8ebSRam Kishore Vegesna 11526affb8ebSRam Kishore Vegesna } 11536affb8ebSRam Kishore Vegesna 1154ef270ab1SKenneth D. Merry /** 1155ef270ab1SKenneth D. Merry * @ingroup scsi_api_initiator 1156ef270ab1SKenneth D. Merry * @brief Delete a SCSI target node 1157ef270ab1SKenneth D. Merry * 1158ef270ab1SKenneth D. Merry * Sent by base driver to notify a initiator-client that a remote target 1159ef270ab1SKenneth D. Merry * is now gone. The base driver will have terminated all outstanding IOs 1160ef270ab1SKenneth D. Merry * and the initiator-client will receive appropriate completions. 1161ef270ab1SKenneth D. Merry * 1162ef270ab1SKenneth D. Merry * The ocs_node_t structure has and elment of type ocs_scsi_ini_node_t named 1163ef270ab1SKenneth D. Merry * ini_node that is declared and used by a target-server for private 1164ef270ab1SKenneth D. Merry * information. 1165ef270ab1SKenneth D. Merry * 1166ef270ab1SKenneth D. Merry * This function is only called if the base driver is enabled for 1167ef270ab1SKenneth D. Merry * initiator capability. 1168ef270ab1SKenneth D. Merry * 1169ef270ab1SKenneth D. Merry * @param node pointer node being deleted 1170ef270ab1SKenneth D. Merry * @param reason reason for deleting the target 1171ef270ab1SKenneth D. Merry * 1172ef270ab1SKenneth D. Merry * @return Returns OCS_SCSI_CALL_ASYNC if target delete is queued for async 1173ef270ab1SKenneth D. Merry * completion and OCS_SCSI_CALL_COMPLETE if call completed or error. 1174ef270ab1SKenneth D. Merry * 1175ef270ab1SKenneth D. Merry * @note 1176ef270ab1SKenneth D. Merry */ 1177ef270ab1SKenneth D. Merry int32_t 1178ef270ab1SKenneth D. Merry ocs_scsi_del_target(ocs_node_t *node, ocs_scsi_del_target_reason_e reason) 1179ef270ab1SKenneth D. Merry { 1180ef270ab1SKenneth D. Merry struct ocs_softc *ocs = node->ocs; 1181ef270ab1SKenneth D. Merry ocs_fcport *fcp = NULL; 11826affb8ebSRam Kishore Vegesna ocs_fc_target_t *tgt = NULL; 11834915e5c7SRam Kishore Vegesna int32_t tgt_id; 11844915e5c7SRam Kishore Vegesna 11854915e5c7SRam Kishore Vegesna if (ocs == NULL) { 11864915e5c7SRam Kishore Vegesna ocs_log_err(ocs,"OCS is NULL \n"); 11874915e5c7SRam Kishore Vegesna return -1; 11884915e5c7SRam Kishore Vegesna } 1189ef270ab1SKenneth D. Merry 1190ef270ab1SKenneth D. Merry fcp = node->sport->tgt_data; 1191ef270ab1SKenneth D. Merry if (fcp == NULL) { 1192ef270ab1SKenneth D. Merry ocs_log_err(ocs,"FCP is NULL \n"); 11934915e5c7SRam Kishore Vegesna return -1; 1194ef270ab1SKenneth D. Merry } 1195ef270ab1SKenneth D. Merry 11966affb8ebSRam Kishore Vegesna tgt_id = ocs_tgt_find(fcp, node); 11974915e5c7SRam Kishore Vegesna if (tgt_id == -1) { 11984915e5c7SRam Kishore Vegesna ocs_log_err(ocs,"target is invalid\n"); 11994915e5c7SRam Kishore Vegesna return -1; 12004915e5c7SRam Kishore Vegesna } 12016affb8ebSRam Kishore Vegesna 12026affb8ebSRam Kishore Vegesna tgt = &fcp->tgt[tgt_id]; 12036affb8ebSRam Kishore Vegesna 12046affb8ebSRam Kishore Vegesna // IF in shutdown delete target. 12056affb8ebSRam Kishore Vegesna if(!ocs->attached) { 12066affb8ebSRam Kishore Vegesna ocs_delete_target(ocs, fcp, tgt_id); 12076affb8ebSRam Kishore Vegesna } else { 12086affb8ebSRam Kishore Vegesna tgt->state = OCS_TGT_STATE_LOST; 12096affb8ebSRam Kishore Vegesna tgt->gone_timer = 30; 12106affb8ebSRam Kishore Vegesna if (!callout_active(&fcp->ldt)) { 12116affb8ebSRam Kishore Vegesna callout_reset(&fcp->ldt, hz, ocs_ldt, fcp); 12126affb8ebSRam Kishore Vegesna } 1213ef270ab1SKenneth D. Merry } 1214ef270ab1SKenneth D. Merry 12156affb8ebSRam Kishore Vegesna return 0; 1216ef270ab1SKenneth D. Merry } 1217ef270ab1SKenneth D. Merry 1218ef270ab1SKenneth D. Merry /** 1219ef270ab1SKenneth D. Merry * @brief Initialize SCSI IO 1220ef270ab1SKenneth D. Merry * 1221ef270ab1SKenneth D. Merry * Initialize SCSI IO, this function is called once per IO during IO pool 1222ef270ab1SKenneth D. Merry * allocation so that the target server may initialize any of its own private 1223ef270ab1SKenneth D. Merry * data. 1224ef270ab1SKenneth D. Merry * 1225ef270ab1SKenneth D. Merry * @param io pointer to SCSI IO object 1226ef270ab1SKenneth D. Merry * 1227ef270ab1SKenneth D. Merry * @return returns 0 for success, a negative error code value for failure. 1228ef270ab1SKenneth D. Merry */ 1229ef270ab1SKenneth D. Merry int32_t 1230ef270ab1SKenneth D. Merry ocs_scsi_tgt_io_init(ocs_io_t *io) 1231ef270ab1SKenneth D. Merry { 1232ef270ab1SKenneth D. Merry return 0; 1233ef270ab1SKenneth D. Merry } 1234ef270ab1SKenneth D. Merry 1235ef270ab1SKenneth D. Merry /** 1236ef270ab1SKenneth D. Merry * @brief Uninitialize SCSI IO 1237ef270ab1SKenneth D. Merry * 1238ef270ab1SKenneth D. Merry * Uninitialize target server private data in a SCSI io object 1239ef270ab1SKenneth D. Merry * 1240ef270ab1SKenneth D. Merry * @param io pointer to SCSI IO object 1241ef270ab1SKenneth D. Merry * 1242ef270ab1SKenneth D. Merry * @return returns 0 for success, a negative error code value for failure. 1243ef270ab1SKenneth D. Merry */ 1244ef270ab1SKenneth D. Merry int32_t 1245ef270ab1SKenneth D. Merry ocs_scsi_tgt_io_exit(ocs_io_t *io) 1246ef270ab1SKenneth D. Merry { 1247ef270ab1SKenneth D. Merry return 0; 1248ef270ab1SKenneth D. Merry } 1249ef270ab1SKenneth D. Merry 1250ef270ab1SKenneth D. Merry /** 1251ef270ab1SKenneth D. Merry * @brief Initialize SCSI IO 1252ef270ab1SKenneth D. Merry * 1253ef270ab1SKenneth D. Merry * Initialize SCSI IO, this function is called once per IO during IO pool 1254ef270ab1SKenneth D. Merry * allocation so that the initiator client may initialize any of its own private 1255ef270ab1SKenneth D. Merry * data. 1256ef270ab1SKenneth D. Merry * 1257ef270ab1SKenneth D. Merry * @param io pointer to SCSI IO object 1258ef270ab1SKenneth D. Merry * 1259ef270ab1SKenneth D. Merry * @return returns 0 for success, a negative error code value for failure. 1260ef270ab1SKenneth D. Merry */ 1261ef270ab1SKenneth D. Merry int32_t 1262ef270ab1SKenneth D. Merry ocs_scsi_ini_io_init(ocs_io_t *io) 1263ef270ab1SKenneth D. Merry { 1264ef270ab1SKenneth D. Merry return 0; 1265ef270ab1SKenneth D. Merry } 1266ef270ab1SKenneth D. Merry 1267ef270ab1SKenneth D. Merry /** 1268ef270ab1SKenneth D. Merry * @brief Uninitialize SCSI IO 1269ef270ab1SKenneth D. Merry * 1270ef270ab1SKenneth D. Merry * Uninitialize initiator client private data in a SCSI io object 1271ef270ab1SKenneth D. Merry * 1272ef270ab1SKenneth D. Merry * @param io pointer to SCSI IO object 1273ef270ab1SKenneth D. Merry * 1274ef270ab1SKenneth D. Merry * @return returns 0 for success, a negative error code value for failure. 1275ef270ab1SKenneth D. Merry */ 1276ef270ab1SKenneth D. Merry int32_t 1277ef270ab1SKenneth D. Merry ocs_scsi_ini_io_exit(ocs_io_t *io) 1278ef270ab1SKenneth D. Merry { 1279ef270ab1SKenneth D. Merry return 0; 1280ef270ab1SKenneth D. Merry } 1281ef270ab1SKenneth D. Merry /* 1282ef270ab1SKenneth D. Merry * End of functions required by SCSI base driver API 1283ef270ab1SKenneth D. Merry ***************************************************************************/ 1284ef270ab1SKenneth D. Merry 1285ef270ab1SKenneth D. Merry static __inline void 1286ef270ab1SKenneth D. Merry ocs_set_ccb_status(union ccb *ccb, cam_status status) 1287ef270ab1SKenneth D. Merry { 1288ef270ab1SKenneth D. Merry ccb->ccb_h.status &= ~CAM_STATUS_MASK; 1289ef270ab1SKenneth D. Merry ccb->ccb_h.status |= status; 1290ef270ab1SKenneth D. Merry } 1291ef270ab1SKenneth D. Merry 1292ef270ab1SKenneth D. Merry static int32_t 1293ef270ab1SKenneth D. Merry ocs_task_set_full_or_busy_cb(ocs_io_t *io, ocs_scsi_io_status_e scsi_status, 1294ef270ab1SKenneth D. Merry uint32_t flags, void *arg) 1295ef270ab1SKenneth D. Merry { 1296ef270ab1SKenneth D. Merry 1297ef270ab1SKenneth D. Merry ocs_target_io_free(io); 1298ef270ab1SKenneth D. Merry 1299ef270ab1SKenneth D. Merry return 0; 1300ef270ab1SKenneth D. Merry } 1301ef270ab1SKenneth D. Merry 1302ef270ab1SKenneth D. Merry /** 1303ef270ab1SKenneth D. Merry * @brief send SCSI task set full or busy status 1304ef270ab1SKenneth D. Merry * 1305ef270ab1SKenneth D. Merry * A SCSI task set full or busy response is sent depending on whether 1306ef270ab1SKenneth D. Merry * another IO is already active on the LUN. 1307ef270ab1SKenneth D. Merry * 1308ef270ab1SKenneth D. Merry * @param io pointer to IO context 1309ef270ab1SKenneth D. Merry * 1310ef270ab1SKenneth D. Merry * @return returns 0 for success, a negative error code value for failure. 1311ef270ab1SKenneth D. Merry */ 1312ef270ab1SKenneth D. Merry 1313ef270ab1SKenneth D. Merry static int32_t 1314ef270ab1SKenneth D. Merry ocs_task_set_full_or_busy(ocs_io_t *io) 1315ef270ab1SKenneth D. Merry { 1316ef270ab1SKenneth D. Merry ocs_scsi_cmd_resp_t rsp = { 0 }; 1317ef270ab1SKenneth D. Merry ocs_t *ocs = io->ocs; 1318ef270ab1SKenneth D. Merry 1319ef270ab1SKenneth D. Merry /* 1320ef270ab1SKenneth D. Merry * If there is another command for the LUN, then send task set full, 1321ef270ab1SKenneth D. Merry * if this is the first one, then send the busy status. 1322ef270ab1SKenneth D. Merry * 1323ef270ab1SKenneth D. Merry * if 'busy sent' is FALSE, set it to TRUE and send BUSY 1324ef270ab1SKenneth D. Merry * otherwise send FULL 1325ef270ab1SKenneth D. Merry */ 1326ef270ab1SKenneth D. Merry if (atomic_cmpset_acq_32(&io->node->tgt_node.busy_sent, FALSE, TRUE)) { 1327ef270ab1SKenneth D. Merry rsp.scsi_status = SCSI_STATUS_BUSY; /* Busy */ 1328ef270ab1SKenneth D. Merry printf("%s: busy [%s] tag=%x iiu=%d ihw=%d\n", __func__, 1329ef270ab1SKenneth D. Merry io->node->display_name, io->tag, 1330ef270ab1SKenneth D. Merry io->ocs->io_in_use, io->ocs->io_high_watermark); 1331ef270ab1SKenneth D. Merry } else { 1332ef270ab1SKenneth D. Merry rsp.scsi_status = SCSI_STATUS_TASK_SET_FULL; /* Task set full */ 1333ef270ab1SKenneth D. Merry printf("%s: full tag=%x iiu=%d\n", __func__, io->tag, 1334ef270ab1SKenneth D. Merry io->ocs->io_in_use); 1335ef270ab1SKenneth D. Merry } 1336ef270ab1SKenneth D. Merry 1337ef270ab1SKenneth D. Merry /* Log a message here indicating a busy or task set full state */ 1338ef270ab1SKenneth D. Merry if (OCS_LOG_ENABLE_Q_FULL_BUSY_MSG(ocs)) { 1339ef270ab1SKenneth D. Merry /* Log Task Set Full */ 1340ef270ab1SKenneth D. Merry if (rsp.scsi_status == SCSI_STATUS_TASK_SET_FULL) { 1341ef270ab1SKenneth D. Merry /* Task Set Full Message */ 1342ef270ab1SKenneth D. Merry ocs_log_info(ocs, "OCS CAM TASK SET FULL. Tasks >= %d\n", 1343ef270ab1SKenneth D. Merry ocs->io_high_watermark); 1344ef270ab1SKenneth D. Merry } 1345ef270ab1SKenneth D. Merry else if (rsp.scsi_status == SCSI_STATUS_BUSY) { 1346ef270ab1SKenneth D. Merry /* Log Busy Message */ 1347ef270ab1SKenneth D. Merry ocs_log_info(ocs, "OCS CAM SCSI BUSY\n"); 1348ef270ab1SKenneth D. Merry } 1349ef270ab1SKenneth D. Merry } 1350ef270ab1SKenneth D. Merry 1351ef270ab1SKenneth D. Merry /* Send the response */ 1352ef270ab1SKenneth D. Merry return 1353ef270ab1SKenneth D. Merry ocs_scsi_send_resp(io, 0, &rsp, ocs_task_set_full_or_busy_cb, NULL); 1354ef270ab1SKenneth D. Merry } 1355ef270ab1SKenneth D. Merry 1356ef270ab1SKenneth D. Merry /** 1357ef270ab1SKenneth D. Merry * @ingroup cam_io 1358ef270ab1SKenneth D. Merry * @brief Process target IO completions 1359ef270ab1SKenneth D. Merry * 1360ef270ab1SKenneth D. Merry * @param io 1361ef270ab1SKenneth D. Merry * @param scsi_status did the IO complete successfully 1362ef270ab1SKenneth D. Merry * @param flags 1363ef270ab1SKenneth D. Merry * @param arg application specific pointer provided in the call to ocs_target_io() 1364ef270ab1SKenneth D. Merry * 1365ef270ab1SKenneth D. Merry * @todo 1366ef270ab1SKenneth D. Merry */ 1367ef270ab1SKenneth D. Merry static int32_t ocs_scsi_target_io_cb(ocs_io_t *io, 1368ef270ab1SKenneth D. Merry ocs_scsi_io_status_e scsi_status, 1369ef270ab1SKenneth D. Merry uint32_t flags, void *arg) 1370ef270ab1SKenneth D. Merry { 1371ef270ab1SKenneth D. Merry union ccb *ccb = arg; 1372ef270ab1SKenneth D. Merry struct ccb_scsiio *csio = &ccb->csio; 1373ef270ab1SKenneth D. Merry struct ocs_softc *ocs = csio->ccb_h.ccb_ocs_ptr; 1374ef270ab1SKenneth D. Merry uint32_t cam_dir = ccb->ccb_h.flags & CAM_DIR_MASK; 1375ef270ab1SKenneth D. Merry uint32_t io_is_done = 1376ef270ab1SKenneth D. Merry (ccb->ccb_h.flags & CAM_SEND_STATUS) == CAM_SEND_STATUS; 1377ef270ab1SKenneth D. Merry 1378ef270ab1SKenneth D. Merry ccb->ccb_h.status &= ~CAM_SIM_QUEUED; 1379ef270ab1SKenneth D. Merry 1380ef270ab1SKenneth D. Merry if (CAM_DIR_NONE != cam_dir) { 1381ef270ab1SKenneth D. Merry bus_dmasync_op_t op; 1382ef270ab1SKenneth D. Merry 1383ef270ab1SKenneth D. Merry if (CAM_DIR_IN == cam_dir) { 1384ef270ab1SKenneth D. Merry op = BUS_DMASYNC_POSTREAD; 1385ef270ab1SKenneth D. Merry } else { 1386ef270ab1SKenneth D. Merry op = BUS_DMASYNC_POSTWRITE; 1387ef270ab1SKenneth D. Merry } 1388ef270ab1SKenneth D. Merry /* Synchronize the DMA memory with the CPU and free the mapping */ 1389ef270ab1SKenneth D. Merry bus_dmamap_sync(ocs->buf_dmat, io->tgt_io.dmap, op); 1390ef270ab1SKenneth D. Merry if (io->tgt_io.flags & OCS_CAM_IO_F_DMAPPED) { 1391ef270ab1SKenneth D. Merry bus_dmamap_unload(ocs->buf_dmat, io->tgt_io.dmap); 1392ef270ab1SKenneth D. Merry } 1393ef270ab1SKenneth D. Merry } 1394ef270ab1SKenneth D. Merry 1395ef270ab1SKenneth D. Merry if (io->tgt_io.sendresp) { 1396ef270ab1SKenneth D. Merry io->tgt_io.sendresp = 0; 1397ef270ab1SKenneth D. Merry ocs_scsi_cmd_resp_t resp = { 0 }; 1398ef270ab1SKenneth D. Merry io->tgt_io.state = OCS_CAM_IO_RESP; 1399ef270ab1SKenneth D. Merry resp.scsi_status = scsi_status; 1400ef270ab1SKenneth D. Merry if (ccb->ccb_h.flags & CAM_SEND_SENSE) { 1401ef270ab1SKenneth D. Merry resp.sense_data = (uint8_t *)&csio->sense_data; 1402ef270ab1SKenneth D. Merry resp.sense_data_length = csio->sense_len; 1403ef270ab1SKenneth D. Merry } 1404ef270ab1SKenneth D. Merry resp.residual = io->exp_xfer_len - io->transferred; 1405ef270ab1SKenneth D. Merry 1406ef270ab1SKenneth D. Merry return ocs_scsi_send_resp(io, 0, &resp, ocs_scsi_target_io_cb, ccb); 1407ef270ab1SKenneth D. Merry } 1408ef270ab1SKenneth D. Merry 1409ef270ab1SKenneth D. Merry switch (scsi_status) { 1410ef270ab1SKenneth D. Merry case OCS_SCSI_STATUS_GOOD: 1411ef270ab1SKenneth D. Merry ocs_set_ccb_status(ccb, CAM_REQ_CMP); 1412ef270ab1SKenneth D. Merry break; 1413ef270ab1SKenneth D. Merry case OCS_SCSI_STATUS_ABORTED: 1414ef270ab1SKenneth D. Merry ocs_set_ccb_status(ccb, CAM_REQ_ABORTED); 1415ef270ab1SKenneth D. Merry break; 1416ef270ab1SKenneth D. Merry default: 1417ef270ab1SKenneth D. Merry ocs_set_ccb_status(ccb, CAM_REQ_CMP_ERR); 1418ef270ab1SKenneth D. Merry } 1419ef270ab1SKenneth D. Merry 1420ef270ab1SKenneth D. Merry if (io_is_done) { 1421ef270ab1SKenneth D. Merry if ((io->tgt_io.flags & OCS_CAM_IO_F_ABORT_NOTIFY) == 0) { 1422ef270ab1SKenneth D. Merry ocs_target_io_free(io); 1423ef270ab1SKenneth D. Merry } 1424ef270ab1SKenneth D. Merry } else { 1425ef270ab1SKenneth D. Merry io->tgt_io.state = OCS_CAM_IO_DATA_DONE; 1426ef270ab1SKenneth D. Merry /*device_printf(ocs->dev, "%s: CTIO state=%d tag=%#x\n", 1427ef270ab1SKenneth D. Merry __func__, io->tgt_io.state, io->tag);*/ 1428ef270ab1SKenneth D. Merry } 1429ef270ab1SKenneth D. Merry 1430ef270ab1SKenneth D. Merry xpt_done(ccb); 1431ef270ab1SKenneth D. Merry 1432ef270ab1SKenneth D. Merry return 0; 1433ef270ab1SKenneth D. Merry } 1434ef270ab1SKenneth D. Merry 1435ef270ab1SKenneth D. Merry /** 1436ef270ab1SKenneth D. Merry * @note 1. Since the CCB is assigned to the ocs_io_t on an XPT_CONT_TARGET_IO 1437ef270ab1SKenneth D. Merry * action, if an initiator aborts a command prior to the SIM receiving 1438ef270ab1SKenneth D. Merry * a CTIO, the IO's CCB will be NULL. 1439ef270ab1SKenneth D. Merry */ 1440ef270ab1SKenneth D. Merry static int32_t 1441ef270ab1SKenneth D. Merry ocs_io_abort_cb(ocs_io_t *io, ocs_scsi_io_status_e scsi_status, uint32_t flags, void *arg) 1442ef270ab1SKenneth D. Merry { 1443ef270ab1SKenneth D. Merry struct ocs_softc *ocs = NULL; 1444ef270ab1SKenneth D. Merry ocs_io_t *tmfio = arg; 1445ef270ab1SKenneth D. Merry ocs_scsi_tmf_resp_e tmf_resp = OCS_SCSI_TMF_FUNCTION_COMPLETE; 1446ef270ab1SKenneth D. Merry int32_t rc = 0; 1447ef270ab1SKenneth D. Merry 1448ef270ab1SKenneth D. Merry ocs = io->ocs; 1449ef270ab1SKenneth D. Merry 1450ef270ab1SKenneth D. Merry io->tgt_io.flags &= ~OCS_CAM_IO_F_ABORT_DEV; 1451ef270ab1SKenneth D. Merry 1452ef270ab1SKenneth D. Merry /* A good status indicates the IO was aborted and will be completed in 1453ef270ab1SKenneth D. Merry * the IO's completion handler. Handle the other cases here. */ 1454ef270ab1SKenneth D. Merry switch (scsi_status) { 1455ef270ab1SKenneth D. Merry case OCS_SCSI_STATUS_GOOD: 1456ef270ab1SKenneth D. Merry break; 1457ef270ab1SKenneth D. Merry case OCS_SCSI_STATUS_NO_IO: 1458ef270ab1SKenneth D. Merry break; 1459ef270ab1SKenneth D. Merry default: 1460ef270ab1SKenneth D. Merry device_printf(ocs->dev, "%s: unhandled status %d\n", 1461ef270ab1SKenneth D. Merry __func__, scsi_status); 1462ef270ab1SKenneth D. Merry tmf_resp = OCS_SCSI_TMF_FUNCTION_REJECTED; 1463ef270ab1SKenneth D. Merry rc = -1; 1464ef270ab1SKenneth D. Merry } 1465ef270ab1SKenneth D. Merry 1466ef270ab1SKenneth D. Merry ocs_scsi_send_tmf_resp(tmfio, tmf_resp, NULL, ocs_target_tmf_cb, NULL); 1467ef270ab1SKenneth D. Merry 1468ef270ab1SKenneth D. Merry return rc; 1469ef270ab1SKenneth D. Merry } 1470ef270ab1SKenneth D. Merry 1471ef270ab1SKenneth D. Merry /** 1472ef270ab1SKenneth D. Merry * @ingroup cam_io 1473ef270ab1SKenneth D. Merry * @brief Process initiator IO completions 1474ef270ab1SKenneth D. Merry * 1475ef270ab1SKenneth D. Merry * @param io 1476ef270ab1SKenneth D. Merry * @param scsi_status did the IO complete successfully 1477ef270ab1SKenneth D. Merry * @param rsp pointer to response buffer 1478ef270ab1SKenneth D. Merry * @param flags 1479ef270ab1SKenneth D. Merry * @param arg application specific pointer provided in the call to ocs_target_io() 1480ef270ab1SKenneth D. Merry * 1481ef270ab1SKenneth D. Merry * @todo 1482ef270ab1SKenneth D. Merry */ 1483ef270ab1SKenneth D. Merry static int32_t ocs_scsi_initiator_io_cb(ocs_io_t *io, 1484ef270ab1SKenneth D. Merry ocs_scsi_io_status_e scsi_status, 1485ef270ab1SKenneth D. Merry ocs_scsi_cmd_resp_t *rsp, 1486ef270ab1SKenneth D. Merry uint32_t flags, void *arg) 1487ef270ab1SKenneth D. Merry { 1488ef270ab1SKenneth D. Merry union ccb *ccb = arg; 1489ef270ab1SKenneth D. Merry struct ccb_scsiio *csio = &ccb->csio; 1490ef270ab1SKenneth D. Merry struct ocs_softc *ocs = csio->ccb_h.ccb_ocs_ptr; 1491ef270ab1SKenneth D. Merry uint32_t cam_dir = ccb->ccb_h.flags & CAM_DIR_MASK; 1492ef270ab1SKenneth D. Merry cam_status ccb_status= CAM_REQ_CMP_ERR; 1493ef270ab1SKenneth D. Merry 1494ef270ab1SKenneth D. Merry if (CAM_DIR_NONE != cam_dir) { 1495ef270ab1SKenneth D. Merry bus_dmasync_op_t op; 1496ef270ab1SKenneth D. Merry 1497ef270ab1SKenneth D. Merry if (CAM_DIR_IN == cam_dir) { 1498ef270ab1SKenneth D. Merry op = BUS_DMASYNC_POSTREAD; 1499ef270ab1SKenneth D. Merry } else { 1500ef270ab1SKenneth D. Merry op = BUS_DMASYNC_POSTWRITE; 1501ef270ab1SKenneth D. Merry } 1502ef270ab1SKenneth D. Merry /* Synchronize the DMA memory with the CPU and free the mapping */ 1503ef270ab1SKenneth D. Merry bus_dmamap_sync(ocs->buf_dmat, io->tgt_io.dmap, op); 1504ef270ab1SKenneth D. Merry if (io->tgt_io.flags & OCS_CAM_IO_F_DMAPPED) { 1505ef270ab1SKenneth D. Merry bus_dmamap_unload(ocs->buf_dmat, io->tgt_io.dmap); 1506ef270ab1SKenneth D. Merry } 1507ef270ab1SKenneth D. Merry } 1508ef270ab1SKenneth D. Merry 1509ef270ab1SKenneth D. Merry if (scsi_status == OCS_SCSI_STATUS_CHECK_RESPONSE) { 1510ef270ab1SKenneth D. Merry csio->scsi_status = rsp->scsi_status; 15111af49c2eSRam Kishore Vegesna if (SCSI_STATUS_OK != rsp->scsi_status) 1512ef270ab1SKenneth D. Merry ccb_status = CAM_SCSI_STATUS_ERROR; 15131af49c2eSRam Kishore Vegesna else 15141af49c2eSRam Kishore Vegesna ccb_status = CAM_REQ_CMP; 1515ef270ab1SKenneth D. Merry 1516ef270ab1SKenneth D. Merry csio->resid = rsp->residual; 15171af49c2eSRam Kishore Vegesna 15181af49c2eSRam Kishore Vegesna /* 15191af49c2eSRam Kishore Vegesna * If we've already got a SCSI error, prefer that because it 15201af49c2eSRam Kishore Vegesna * will have more detail. 15211af49c2eSRam Kishore Vegesna */ 15221af49c2eSRam Kishore Vegesna if ((rsp->residual < 0) && (ccb_status == CAM_REQ_CMP)) { 1523ef270ab1SKenneth D. Merry ccb_status = CAM_DATA_RUN_ERR; 1524ef270ab1SKenneth D. Merry } 1525ef270ab1SKenneth D. Merry 1526ef270ab1SKenneth D. Merry if ((rsp->sense_data_length) && 1527ef270ab1SKenneth D. Merry !(ccb->ccb_h.flags & (CAM_SENSE_PHYS | CAM_SENSE_PTR))) { 1528ef270ab1SKenneth D. Merry uint32_t sense_len = 0; 1529ef270ab1SKenneth D. Merry 1530ef270ab1SKenneth D. Merry ccb->ccb_h.status |= CAM_AUTOSNS_VALID; 1531ef270ab1SKenneth D. Merry if (rsp->sense_data_length < csio->sense_len) { 1532ef270ab1SKenneth D. Merry csio->sense_resid = 1533ef270ab1SKenneth D. Merry csio->sense_len - rsp->sense_data_length; 1534ef270ab1SKenneth D. Merry sense_len = rsp->sense_data_length; 1535ef270ab1SKenneth D. Merry } else { 1536ef270ab1SKenneth D. Merry csio->sense_resid = 0; 1537ef270ab1SKenneth D. Merry sense_len = csio->sense_len; 1538ef270ab1SKenneth D. Merry } 1539ef270ab1SKenneth D. Merry ocs_memcpy(&csio->sense_data, rsp->sense_data, sense_len); 1540ef270ab1SKenneth D. Merry } 1541ef270ab1SKenneth D. Merry } else if (scsi_status != OCS_SCSI_STATUS_GOOD) { 154270547544SRam Kishore Vegesna const char *err_desc = NULL; 154370547544SRam Kishore Vegesna char err_str[224]; 154470547544SRam Kishore Vegesna struct sbuf sb; 154570547544SRam Kishore Vegesna size_t i; 154670547544SRam Kishore Vegesna 154770547544SRam Kishore Vegesna sbuf_new(&sb, err_str, sizeof(err_str), 0); 154870547544SRam Kishore Vegesna 1549a9504d76SRam Kishore Vegesna xpt_path_sbuf(ccb->ccb_h.path, &sb); 155070547544SRam Kishore Vegesna 155170547544SRam Kishore Vegesna for (i = 0; i < (sizeof(ocs_status_desc) / 155270547544SRam Kishore Vegesna sizeof(ocs_status_desc[0])); i++) { 155370547544SRam Kishore Vegesna if (scsi_status == ocs_status_desc[i].status) { 155470547544SRam Kishore Vegesna err_desc = ocs_status_desc[i].desc; 155570547544SRam Kishore Vegesna break; 155670547544SRam Kishore Vegesna } 155770547544SRam Kishore Vegesna } 155870547544SRam Kishore Vegesna if (ccb->ccb_h.func_code == XPT_SCSI_IO) { 155970547544SRam Kishore Vegesna scsi_command_string(&ccb->csio, &sb); 156070547544SRam Kishore Vegesna sbuf_printf(&sb, "length %d ", ccb->csio.dxfer_len); 156170547544SRam Kishore Vegesna } 156270547544SRam Kishore Vegesna sbuf_printf(&sb, "error status %d (%s)\n", scsi_status, 156370547544SRam Kishore Vegesna (err_desc != NULL) ? err_desc : "Unknown"); 156470547544SRam Kishore Vegesna sbuf_finish(&sb); 156570547544SRam Kishore Vegesna printf("%s", sbuf_data(&sb)); 156670547544SRam Kishore Vegesna 156770547544SRam Kishore Vegesna switch (scsi_status) { 156870547544SRam Kishore Vegesna case OCS_SCSI_STATUS_ABORTED: 156970547544SRam Kishore Vegesna case OCS_SCSI_STATUS_ABORT_IN_PROGRESS: 157070547544SRam Kishore Vegesna ccb_status = CAM_REQ_ABORTED; 157170547544SRam Kishore Vegesna break; 157270547544SRam Kishore Vegesna case OCS_SCSI_STATUS_DIF_GUARD_ERROR: 157370547544SRam Kishore Vegesna case OCS_SCSI_STATUS_DIF_REF_TAG_ERROR: 157470547544SRam Kishore Vegesna case OCS_SCSI_STATUS_DIF_APP_TAG_ERROR: 157570547544SRam Kishore Vegesna case OCS_SCSI_STATUS_DIF_UNKNOWN_ERROR: 157670547544SRam Kishore Vegesna case OCS_SCSI_STATUS_PROTOCOL_CRC_ERROR: 157770547544SRam Kishore Vegesna ccb_status = CAM_IDE; 157870547544SRam Kishore Vegesna break; 157970547544SRam Kishore Vegesna case OCS_SCSI_STATUS_ERROR: 158070547544SRam Kishore Vegesna case OCS_SCSI_STATUS_NO_IO: 1581ef270ab1SKenneth D. Merry ccb_status = CAM_REQ_CMP_ERR; 158270547544SRam Kishore Vegesna break; 158370547544SRam Kishore Vegesna case OCS_SCSI_STATUS_COMMAND_TIMEOUT: 158470547544SRam Kishore Vegesna case OCS_SCSI_STATUS_TIMEDOUT_AND_ABORTED: 158570547544SRam Kishore Vegesna ccb_status = CAM_CMD_TIMEOUT; 158670547544SRam Kishore Vegesna break; 158770547544SRam Kishore Vegesna case OCS_SCSI_STATUS_SHUTDOWN: 158870547544SRam Kishore Vegesna case OCS_SCSI_STATUS_NEXUS_LOST: 158970547544SRam Kishore Vegesna ccb_status = CAM_SCSI_IT_NEXUS_LOST; 159070547544SRam Kishore Vegesna break; 159170547544SRam Kishore Vegesna default: 159270547544SRam Kishore Vegesna ccb_status = CAM_REQ_CMP_ERR; 159370547544SRam Kishore Vegesna break; 159470547544SRam Kishore Vegesna } 159570547544SRam Kishore Vegesna 1596ef270ab1SKenneth D. Merry } else { 1597ef270ab1SKenneth D. Merry ccb_status = CAM_REQ_CMP; 1598ef270ab1SKenneth D. Merry } 1599ef270ab1SKenneth D. Merry 1600ef270ab1SKenneth D. Merry ocs_set_ccb_status(ccb, ccb_status); 1601ef270ab1SKenneth D. Merry 1602ef270ab1SKenneth D. Merry ocs_scsi_io_free(io); 1603ef270ab1SKenneth D. Merry 1604ef270ab1SKenneth D. Merry csio->ccb_h.ccb_io_ptr = NULL; 1605ef270ab1SKenneth D. Merry csio->ccb_h.ccb_ocs_ptr = NULL; 1606d063d1bcSRam Kishore Vegesna 1607ef270ab1SKenneth D. Merry ccb->ccb_h.status &= ~CAM_SIM_QUEUED; 1608ef270ab1SKenneth D. Merry 1609d063d1bcSRam Kishore Vegesna if ((ccb_status != CAM_REQ_CMP) && 1610d063d1bcSRam Kishore Vegesna ((ccb->ccb_h.status & CAM_DEV_QFRZN) == 0)) { 1611d063d1bcSRam Kishore Vegesna ccb->ccb_h.status |= CAM_DEV_QFRZN; 1612d063d1bcSRam Kishore Vegesna xpt_freeze_devq(ccb->ccb_h.path, 1); 1613d063d1bcSRam Kishore Vegesna } 1614d063d1bcSRam Kishore Vegesna 1615ef270ab1SKenneth D. Merry xpt_done(ccb); 1616ef270ab1SKenneth D. Merry 1617ef270ab1SKenneth D. Merry return 0; 1618ef270ab1SKenneth D. Merry } 1619ef270ab1SKenneth D. Merry 1620ef270ab1SKenneth D. Merry /** 1621ef270ab1SKenneth D. Merry * @brief Load scatter-gather list entries into an IO 1622ef270ab1SKenneth D. Merry * 1623ef270ab1SKenneth D. Merry * This routine relies on the driver instance's software context pointer and 1624ef270ab1SKenneth D. Merry * the IO object pointer having been already assigned to hooks in the CCB. 1625ef270ab1SKenneth D. Merry * Although the routine does not return success/fail, callers can look at the 1626ef270ab1SKenneth D. Merry * n_sge member to determine if the mapping failed (0 on failure). 1627ef270ab1SKenneth D. Merry * 1628ef270ab1SKenneth D. Merry * @param arg pointer to the CAM ccb for this IO 1629ef270ab1SKenneth D. Merry * @param seg DMA address/length pairs 1630ef270ab1SKenneth D. Merry * @param nseg number of DMA address/length pairs 1631ef270ab1SKenneth D. Merry * @param error any errors while mapping the IO 1632ef270ab1SKenneth D. Merry */ 1633ef270ab1SKenneth D. Merry static void 1634ef270ab1SKenneth D. Merry ocs_scsi_dmamap_load(void *arg, bus_dma_segment_t *seg, int nseg, int error) 1635ef270ab1SKenneth D. Merry { 1636ef270ab1SKenneth D. Merry ocs_dmamap_load_arg_t *sglarg = (ocs_dmamap_load_arg_t*) arg; 1637ef270ab1SKenneth D. Merry 1638ef270ab1SKenneth D. Merry if (error) { 1639ef270ab1SKenneth D. Merry printf("%s: seg=%p nseg=%d error=%d\n", 1640ef270ab1SKenneth D. Merry __func__, seg, nseg, error); 1641ef270ab1SKenneth D. Merry sglarg->rc = -1; 1642ef270ab1SKenneth D. Merry } else { 1643ef270ab1SKenneth D. Merry uint32_t i = 0; 1644ef270ab1SKenneth D. Merry uint32_t c = 0; 1645ef270ab1SKenneth D. Merry 1646ef270ab1SKenneth D. Merry if ((sglarg->sgl_count + nseg) > sglarg->sgl_max) { 1647ef270ab1SKenneth D. Merry printf("%s: sgl_count=%d nseg=%d max=%d\n", __func__, 1648ef270ab1SKenneth D. Merry sglarg->sgl_count, nseg, sglarg->sgl_max); 1649ef270ab1SKenneth D. Merry sglarg->rc = -2; 1650ef270ab1SKenneth D. Merry return; 1651ef270ab1SKenneth D. Merry } 1652ef270ab1SKenneth D. Merry 1653ef270ab1SKenneth D. Merry for (i = 0, c = sglarg->sgl_count; i < nseg; i++, c++) { 1654ef270ab1SKenneth D. Merry sglarg->sgl[c].addr = seg[i].ds_addr; 1655ef270ab1SKenneth D. Merry sglarg->sgl[c].len = seg[i].ds_len; 1656ef270ab1SKenneth D. Merry } 1657ef270ab1SKenneth D. Merry 1658ef270ab1SKenneth D. Merry sglarg->sgl_count = c; 1659ef270ab1SKenneth D. Merry 1660ef270ab1SKenneth D. Merry sglarg->rc = 0; 1661ef270ab1SKenneth D. Merry } 1662ef270ab1SKenneth D. Merry } 1663ef270ab1SKenneth D. Merry 1664ef270ab1SKenneth D. Merry /** 1665ef270ab1SKenneth D. Merry * @brief Build a scatter-gather list from a CAM CCB 1666ef270ab1SKenneth D. Merry * 1667ef270ab1SKenneth D. Merry * @param ocs the driver instance's software context 1668ef270ab1SKenneth D. Merry * @param ccb pointer to the CCB 1669ef270ab1SKenneth D. Merry * @param io pointer to the previously allocated IO object 1670ef270ab1SKenneth D. Merry * @param sgl pointer to SGL 1671ef270ab1SKenneth D. Merry * @param sgl_max number of entries in sgl 1672ef270ab1SKenneth D. Merry * 1673ef270ab1SKenneth D. Merry * @return 0 on success, non-zero otherwise 1674ef270ab1SKenneth D. Merry */ 1675ef270ab1SKenneth D. Merry static int32_t 1676ef270ab1SKenneth D. Merry ocs_build_scsi_sgl(struct ocs_softc *ocs, union ccb *ccb, ocs_io_t *io, 1677ef270ab1SKenneth D. Merry ocs_scsi_sgl_t *sgl, uint32_t sgl_max) 1678ef270ab1SKenneth D. Merry { 1679ef270ab1SKenneth D. Merry ocs_dmamap_load_arg_t dmaarg; 1680ef270ab1SKenneth D. Merry int32_t err = 0; 1681ef270ab1SKenneth D. Merry 1682ef270ab1SKenneth D. Merry if (!ocs || !ccb || !io || !sgl) { 1683ef270ab1SKenneth D. Merry printf("%s: bad param o=%p c=%p i=%p s=%p\n", __func__, 1684ef270ab1SKenneth D. Merry ocs, ccb, io, sgl); 1685ef270ab1SKenneth D. Merry return -1; 1686ef270ab1SKenneth D. Merry } 1687ef270ab1SKenneth D. Merry 1688ef270ab1SKenneth D. Merry io->tgt_io.flags &= ~OCS_CAM_IO_F_DMAPPED; 1689ef270ab1SKenneth D. Merry 1690ef270ab1SKenneth D. Merry dmaarg.sgl = sgl; 1691ef270ab1SKenneth D. Merry dmaarg.sgl_count = 0; 1692ef270ab1SKenneth D. Merry dmaarg.sgl_max = sgl_max; 1693ef270ab1SKenneth D. Merry dmaarg.rc = 0; 1694ef270ab1SKenneth D. Merry 1695ef270ab1SKenneth D. Merry err = bus_dmamap_load_ccb(ocs->buf_dmat, io->tgt_io.dmap, ccb, 1696ef270ab1SKenneth D. Merry ocs_scsi_dmamap_load, &dmaarg, 0); 1697ef270ab1SKenneth D. Merry 1698ef270ab1SKenneth D. Merry if (err || dmaarg.rc) { 1699ef270ab1SKenneth D. Merry device_printf( 1700ef270ab1SKenneth D. Merry ocs->dev, "%s: bus_dmamap_load_ccb error (%d %d)\n", 1701ef270ab1SKenneth D. Merry __func__, err, dmaarg.rc); 1702ef270ab1SKenneth D. Merry return -1; 1703ef270ab1SKenneth D. Merry } 1704ef270ab1SKenneth D. Merry 1705ef270ab1SKenneth D. Merry io->tgt_io.flags |= OCS_CAM_IO_F_DMAPPED; 1706ef270ab1SKenneth D. Merry return dmaarg.sgl_count; 1707ef270ab1SKenneth D. Merry } 1708ef270ab1SKenneth D. Merry 1709ef270ab1SKenneth D. Merry /** 1710ef270ab1SKenneth D. Merry * @ingroup cam_io 1711ef270ab1SKenneth D. Merry * @brief Send a target IO 1712ef270ab1SKenneth D. Merry * 1713ef270ab1SKenneth D. Merry * @param ocs the driver instance's software context 1714ef270ab1SKenneth D. Merry * @param ccb pointer to the CCB 1715ef270ab1SKenneth D. Merry * 1716ef270ab1SKenneth D. Merry * @return 0 on success, non-zero otherwise 1717ef270ab1SKenneth D. Merry */ 1718ef270ab1SKenneth D. Merry static int32_t 1719ef270ab1SKenneth D. Merry ocs_target_io(struct ocs_softc *ocs, union ccb *ccb) 1720ef270ab1SKenneth D. Merry { 1721ef270ab1SKenneth D. Merry struct ccb_scsiio *csio = &ccb->csio; 1722ef270ab1SKenneth D. Merry ocs_io_t *io = NULL; 1723ef270ab1SKenneth D. Merry uint32_t cam_dir = ccb->ccb_h.flags & CAM_DIR_MASK; 1724ef270ab1SKenneth D. Merry bool sendstatus = ccb->ccb_h.flags & CAM_SEND_STATUS; 1725ef270ab1SKenneth D. Merry uint32_t xferlen = csio->dxfer_len; 1726ef270ab1SKenneth D. Merry int32_t rc = 0; 1727ef270ab1SKenneth D. Merry 1728ef270ab1SKenneth D. Merry io = ocs_scsi_find_io(ocs, csio->tag_id); 1729ef270ab1SKenneth D. Merry if (io == NULL) { 1730ef270ab1SKenneth D. Merry ocs_set_ccb_status(ccb, CAM_REQ_CMP_ERR); 1731ef270ab1SKenneth D. Merry panic("bad tag value"); 1732ef270ab1SKenneth D. Merry return 1; 1733ef270ab1SKenneth D. Merry } 1734ef270ab1SKenneth D. Merry 1735ef270ab1SKenneth D. Merry /* Received an ABORT TASK for this IO */ 1736ef270ab1SKenneth D. Merry if (io->tgt_io.flags & OCS_CAM_IO_F_ABORT_RECV) { 1737ef270ab1SKenneth D. Merry /*device_printf(ocs->dev, 1738ef270ab1SKenneth D. Merry "%s: XPT_CONT_TARGET_IO state=%d tag=%#x xid=%#x flags=%#x\n", 1739ef270ab1SKenneth D. Merry __func__, io->tgt_io.state, io->tag, io->init_task_tag, 1740ef270ab1SKenneth D. Merry io->tgt_io.flags);*/ 1741ef270ab1SKenneth D. Merry io->tgt_io.flags |= OCS_CAM_IO_F_ABORT_CAM; 1742ef270ab1SKenneth D. Merry 1743ef270ab1SKenneth D. Merry if (ccb->ccb_h.flags & CAM_SEND_STATUS) { 1744ef270ab1SKenneth D. Merry ocs_set_ccb_status(ccb, CAM_REQ_CMP); 1745ef270ab1SKenneth D. Merry ocs_target_io_free(io); 1746ef270ab1SKenneth D. Merry return 1; 1747ef270ab1SKenneth D. Merry } 1748ef270ab1SKenneth D. Merry 1749ef270ab1SKenneth D. Merry ocs_set_ccb_status(ccb, CAM_REQ_ABORTED); 1750ef270ab1SKenneth D. Merry 1751ef270ab1SKenneth D. Merry return 1; 1752ef270ab1SKenneth D. Merry } 1753ef270ab1SKenneth D. Merry 1754ef270ab1SKenneth D. Merry io->tgt_io.app = ccb; 1755ef270ab1SKenneth D. Merry 1756ef270ab1SKenneth D. Merry ocs_set_ccb_status(ccb, CAM_REQ_INPROG); 1757ef270ab1SKenneth D. Merry ccb->ccb_h.status |= CAM_SIM_QUEUED; 1758ef270ab1SKenneth D. Merry 1759ef270ab1SKenneth D. Merry csio->ccb_h.ccb_ocs_ptr = ocs; 1760ef270ab1SKenneth D. Merry csio->ccb_h.ccb_io_ptr = io; 1761ef270ab1SKenneth D. Merry 1762ef270ab1SKenneth D. Merry if ((sendstatus && (xferlen == 0))) { 1763ef270ab1SKenneth D. Merry ocs_scsi_cmd_resp_t resp = { 0 }; 1764ef270ab1SKenneth D. Merry 1765ef270ab1SKenneth D. Merry ocs_assert(ccb->ccb_h.flags & CAM_SEND_STATUS, -1); 1766ef270ab1SKenneth D. Merry 1767ef270ab1SKenneth D. Merry io->tgt_io.state = OCS_CAM_IO_RESP; 1768ef270ab1SKenneth D. Merry 1769ef270ab1SKenneth D. Merry resp.scsi_status = csio->scsi_status; 1770ef270ab1SKenneth D. Merry 1771ef270ab1SKenneth D. Merry if (ccb->ccb_h.flags & CAM_SEND_SENSE) { 1772ef270ab1SKenneth D. Merry resp.sense_data = (uint8_t *)&csio->sense_data; 1773ef270ab1SKenneth D. Merry resp.sense_data_length = csio->sense_len; 1774ef270ab1SKenneth D. Merry } 1775ef270ab1SKenneth D. Merry 1776ef270ab1SKenneth D. Merry resp.residual = io->exp_xfer_len - io->transferred; 1777ef270ab1SKenneth D. Merry rc = ocs_scsi_send_resp(io, 0, &resp, ocs_scsi_target_io_cb, ccb); 1778ef270ab1SKenneth D. Merry 1779ef270ab1SKenneth D. Merry } else if (xferlen != 0) { 1780322dbb8cSRam Kishore Vegesna ocs_scsi_sgl_t *sgl; 1781ef270ab1SKenneth D. Merry int32_t sgl_count = 0; 1782ef270ab1SKenneth D. Merry 1783ef270ab1SKenneth D. Merry io->tgt_io.state = OCS_CAM_IO_DATA; 1784ef270ab1SKenneth D. Merry 1785ef270ab1SKenneth D. Merry if (sendstatus) 1786ef270ab1SKenneth D. Merry io->tgt_io.sendresp = 1; 1787ef270ab1SKenneth D. Merry 1788322dbb8cSRam Kishore Vegesna sgl = io->sgl; 1789322dbb8cSRam Kishore Vegesna 1790322dbb8cSRam Kishore Vegesna sgl_count = ocs_build_scsi_sgl(ocs, ccb, io, sgl, io->sgl_allocated); 1791ef270ab1SKenneth D. Merry if (sgl_count > 0) { 1792ef270ab1SKenneth D. Merry if (cam_dir == CAM_DIR_IN) { 1793ef270ab1SKenneth D. Merry rc = ocs_scsi_send_rd_data(io, 0, NULL, sgl, 1794ef270ab1SKenneth D. Merry sgl_count, csio->dxfer_len, 1795ef270ab1SKenneth D. Merry ocs_scsi_target_io_cb, ccb); 1796ef270ab1SKenneth D. Merry } else if (cam_dir == CAM_DIR_OUT) { 1797ef270ab1SKenneth D. Merry rc = ocs_scsi_recv_wr_data(io, 0, NULL, sgl, 1798ef270ab1SKenneth D. Merry sgl_count, csio->dxfer_len, 1799ef270ab1SKenneth D. Merry ocs_scsi_target_io_cb, ccb); 1800ef270ab1SKenneth D. Merry } else { 1801ef270ab1SKenneth D. Merry device_printf(ocs->dev, "%s:" 1802ef270ab1SKenneth D. Merry " unknown CAM direction %#x\n", 1803ef270ab1SKenneth D. Merry __func__, cam_dir); 1804ef270ab1SKenneth D. Merry ocs_set_ccb_status(ccb, CAM_REQ_INVALID); 1805ef270ab1SKenneth D. Merry rc = 1; 1806ef270ab1SKenneth D. Merry } 1807ef270ab1SKenneth D. Merry } else { 1808ef270ab1SKenneth D. Merry device_printf(ocs->dev, "%s: building SGL failed\n", 1809ef270ab1SKenneth D. Merry __func__); 1810ef270ab1SKenneth D. Merry ocs_set_ccb_status(ccb, CAM_REQ_CMP_ERR); 1811ef270ab1SKenneth D. Merry rc = 1; 1812ef270ab1SKenneth D. Merry } 1813ef270ab1SKenneth D. Merry } else { 1814ef270ab1SKenneth D. Merry device_printf(ocs->dev, "%s: Wrong value xfer and sendstatus" 1815ef270ab1SKenneth D. Merry " are 0 \n", __func__); 1816ef270ab1SKenneth D. Merry ocs_set_ccb_status(ccb, CAM_REQ_INVALID); 1817ef270ab1SKenneth D. Merry rc = 1; 1818ef270ab1SKenneth D. Merry } 1819ef270ab1SKenneth D. Merry 1820ef270ab1SKenneth D. Merry if (rc) { 1821ef270ab1SKenneth D. Merry ocs_set_ccb_status(ccb, CAM_REQ_CMP_ERR); 1822ef270ab1SKenneth D. Merry ccb->ccb_h.status &= ~CAM_SIM_QUEUED; 1823ef270ab1SKenneth D. Merry io->tgt_io.state = OCS_CAM_IO_DATA_DONE; 1824ef270ab1SKenneth D. Merry device_printf(ocs->dev, "%s: CTIO state=%d tag=%#x\n", 1825ef270ab1SKenneth D. Merry __func__, io->tgt_io.state, io->tag); 1826ef270ab1SKenneth D. Merry if ((sendstatus && (xferlen == 0))) { 1827ef270ab1SKenneth D. Merry ocs_target_io_free(io); 1828ef270ab1SKenneth D. Merry } 1829ef270ab1SKenneth D. Merry } 1830ef270ab1SKenneth D. Merry 1831ef270ab1SKenneth D. Merry return rc; 1832ef270ab1SKenneth D. Merry } 1833ef270ab1SKenneth D. Merry 1834ef270ab1SKenneth D. Merry static int32_t 1835ef270ab1SKenneth D. Merry ocs_target_tmf_cb(ocs_io_t *io, ocs_scsi_io_status_e scsi_status, uint32_t flags, 1836ef270ab1SKenneth D. Merry void *arg) 1837ef270ab1SKenneth D. Merry { 1838ef270ab1SKenneth D. Merry 1839ef270ab1SKenneth D. Merry /*device_printf(io->ocs->dev, "%s: tag=%x io=%p s=%#x\n", 1840ef270ab1SKenneth D. Merry __func__, io->tag, io, scsi_status);*/ 1841ef270ab1SKenneth D. Merry ocs_scsi_io_complete(io); 1842ef270ab1SKenneth D. Merry 1843ef270ab1SKenneth D. Merry return 0; 1844ef270ab1SKenneth D. Merry } 1845ef270ab1SKenneth D. Merry 1846ef270ab1SKenneth D. Merry /** 1847ef270ab1SKenneth D. Merry * @ingroup cam_io 1848ef270ab1SKenneth D. Merry * @brief Send an initiator IO 1849ef270ab1SKenneth D. Merry * 1850ef270ab1SKenneth D. Merry * @param ocs the driver instance's software context 1851ef270ab1SKenneth D. Merry * @param ccb pointer to the CCB 1852ef270ab1SKenneth D. Merry * 1853ef270ab1SKenneth D. Merry * @return 0 on success, non-zero otherwise 1854ef270ab1SKenneth D. Merry */ 1855ef270ab1SKenneth D. Merry static int32_t 1856ef270ab1SKenneth D. Merry ocs_initiator_io(struct ocs_softc *ocs, union ccb *ccb) 1857ef270ab1SKenneth D. Merry { 1858ef270ab1SKenneth D. Merry int32_t rc; 1859ef270ab1SKenneth D. Merry struct ccb_scsiio *csio = &ccb->csio; 1860ef270ab1SKenneth D. Merry struct ccb_hdr *ccb_h = &csio->ccb_h; 1861ef270ab1SKenneth D. Merry ocs_node_t *node = NULL; 1862ef270ab1SKenneth D. Merry ocs_io_t *io = NULL; 1863322dbb8cSRam Kishore Vegesna ocs_scsi_sgl_t *sgl; 186488364968SAlexander Motin int32_t flags, sgl_count; 18654915e5c7SRam Kishore Vegesna ocs_fcport *fcp; 1866ef270ab1SKenneth D. Merry 18676affb8ebSRam Kishore Vegesna fcp = FCPORT(ocs, cam_sim_bus(xpt_path_sim((ccb)->ccb_h.path))); 18686affb8ebSRam Kishore Vegesna 18696affb8ebSRam Kishore Vegesna if (fcp->tgt[ccb_h->target_id].state == OCS_TGT_STATE_LOST) { 18706affb8ebSRam Kishore Vegesna device_printf(ocs->dev, "%s: device LOST %d\n", __func__, 18716affb8ebSRam Kishore Vegesna ccb_h->target_id); 18726affb8ebSRam Kishore Vegesna return CAM_REQUEUE_REQ; 18736affb8ebSRam Kishore Vegesna } 18746affb8ebSRam Kishore Vegesna 18756affb8ebSRam Kishore Vegesna if (fcp->tgt[ccb_h->target_id].state == OCS_TGT_STATE_NONE) { 18766affb8ebSRam Kishore Vegesna device_printf(ocs->dev, "%s: device not ready %d\n", __func__, 18776affb8ebSRam Kishore Vegesna ccb_h->target_id); 18786affb8ebSRam Kishore Vegesna return CAM_SEL_TIMEOUT; 18796affb8ebSRam Kishore Vegesna } 18806affb8ebSRam Kishore Vegesna 18816affb8ebSRam Kishore Vegesna node = ocs_node_get_instance(ocs, fcp->tgt[ccb_h->target_id].node_id); 1882ef270ab1SKenneth D. Merry if (node == NULL) { 1883ef270ab1SKenneth D. Merry device_printf(ocs->dev, "%s: no device %d\n", __func__, 1884ef270ab1SKenneth D. Merry ccb_h->target_id); 18856affb8ebSRam Kishore Vegesna return CAM_SEL_TIMEOUT; 1886ef270ab1SKenneth D. Merry } 1887ef270ab1SKenneth D. Merry 1888ef270ab1SKenneth D. Merry if (!node->targ) { 1889ef270ab1SKenneth D. Merry device_printf(ocs->dev, "%s: not target device %d\n", __func__, 1890ef270ab1SKenneth D. Merry ccb_h->target_id); 18916affb8ebSRam Kishore Vegesna return CAM_SEL_TIMEOUT; 1892ef270ab1SKenneth D. Merry } 1893ef270ab1SKenneth D. Merry 1894ef270ab1SKenneth D. Merry io = ocs_scsi_io_alloc(node, OCS_SCSI_IO_ROLE_ORIGINATOR); 1895ef270ab1SKenneth D. Merry if (io == NULL) { 1896ef270ab1SKenneth D. Merry device_printf(ocs->dev, "%s: unable to alloc IO\n", __func__); 1897ef270ab1SKenneth D. Merry return -1; 1898ef270ab1SKenneth D. Merry } 1899ef270ab1SKenneth D. Merry 1900ef270ab1SKenneth D. Merry /* eventhough this is INI, use target structure as ocs_build_scsi_sgl 1901ef270ab1SKenneth D. Merry * only references the tgt_io part of an ocs_io_t */ 1902ef270ab1SKenneth D. Merry io->tgt_io.app = ccb; 1903ef270ab1SKenneth D. Merry 1904ef270ab1SKenneth D. Merry csio->ccb_h.ccb_ocs_ptr = ocs; 1905ef270ab1SKenneth D. Merry csio->ccb_h.ccb_io_ptr = io; 1906322dbb8cSRam Kishore Vegesna sgl = io->sgl; 1907ef270ab1SKenneth D. Merry 1908322dbb8cSRam Kishore Vegesna sgl_count = ocs_build_scsi_sgl(ocs, ccb, io, sgl, io->sgl_allocated); 1909ef270ab1SKenneth D. Merry if (sgl_count < 0) { 1910ef270ab1SKenneth D. Merry ocs_scsi_io_free(io); 1911ef270ab1SKenneth D. Merry device_printf(ocs->dev, "%s: building SGL failed\n", __func__); 1912ef270ab1SKenneth D. Merry return -1; 1913ef270ab1SKenneth D. Merry } 1914ef270ab1SKenneth D. Merry 1915ef270ab1SKenneth D. Merry if (ccb->ccb_h.timeout == CAM_TIME_INFINITY) { 1916ef270ab1SKenneth D. Merry io->timeout = 0; 1917ef270ab1SKenneth D. Merry } else if (ccb->ccb_h.timeout == CAM_TIME_DEFAULT) { 1918ef270ab1SKenneth D. Merry io->timeout = OCS_CAM_IO_TIMEOUT; 1919ef270ab1SKenneth D. Merry } else { 192070547544SRam Kishore Vegesna if (ccb->ccb_h.timeout < 1000) 192170547544SRam Kishore Vegesna io->timeout = 1; 192270547544SRam Kishore Vegesna else { 192370547544SRam Kishore Vegesna io->timeout = ccb->ccb_h.timeout / 1000; 192470547544SRam Kishore Vegesna } 1925ef270ab1SKenneth D. Merry } 1926ef270ab1SKenneth D. Merry 192788364968SAlexander Motin switch (csio->tag_action) { 192888364968SAlexander Motin case MSG_HEAD_OF_Q_TAG: 192988364968SAlexander Motin flags = OCS_SCSI_CMD_HEAD_OF_QUEUE; 193088364968SAlexander Motin break; 193188364968SAlexander Motin case MSG_ORDERED_Q_TAG: 193288364968SAlexander Motin flags = OCS_SCSI_CMD_ORDERED; 193388364968SAlexander Motin break; 193488364968SAlexander Motin case MSG_ACA_TASK: 193588364968SAlexander Motin flags = OCS_SCSI_CMD_ACA; 193688364968SAlexander Motin break; 193788364968SAlexander Motin case CAM_TAG_ACTION_NONE: 193888364968SAlexander Motin case MSG_SIMPLE_Q_TAG: 193988364968SAlexander Motin default: 194088364968SAlexander Motin flags = OCS_SCSI_CMD_SIMPLE; 194188364968SAlexander Motin break; 194288364968SAlexander Motin } 194388364968SAlexander Motin flags |= (csio->priority << OCS_SCSI_PRIORITY_SHIFT) & 194488364968SAlexander Motin OCS_SCSI_PRIORITY_MASK; 194588364968SAlexander Motin 1946ef270ab1SKenneth D. Merry switch (ccb->ccb_h.flags & CAM_DIR_MASK) { 1947ef270ab1SKenneth D. Merry case CAM_DIR_NONE: 1948ef270ab1SKenneth D. Merry rc = ocs_scsi_send_nodata_io(node, io, ccb_h->target_lun, 1949ef270ab1SKenneth D. Merry ccb->ccb_h.flags & CAM_CDB_POINTER ? 1950ef270ab1SKenneth D. Merry csio->cdb_io.cdb_ptr: csio->cdb_io.cdb_bytes, 1951ef270ab1SKenneth D. Merry csio->cdb_len, 195288364968SAlexander Motin ocs_scsi_initiator_io_cb, ccb, flags); 1953ef270ab1SKenneth D. Merry break; 1954ef270ab1SKenneth D. Merry case CAM_DIR_IN: 1955ef270ab1SKenneth D. Merry rc = ocs_scsi_send_rd_io(node, io, ccb_h->target_lun, 1956ef270ab1SKenneth D. Merry ccb->ccb_h.flags & CAM_CDB_POINTER ? 1957ef270ab1SKenneth D. Merry csio->cdb_io.cdb_ptr: csio->cdb_io.cdb_bytes, 1958ef270ab1SKenneth D. Merry csio->cdb_len, 1959ef270ab1SKenneth D. Merry NULL, 1960ef270ab1SKenneth D. Merry sgl, sgl_count, csio->dxfer_len, 196188364968SAlexander Motin ocs_scsi_initiator_io_cb, ccb, flags); 1962ef270ab1SKenneth D. Merry break; 1963ef270ab1SKenneth D. Merry case CAM_DIR_OUT: 1964ef270ab1SKenneth D. Merry rc = ocs_scsi_send_wr_io(node, io, ccb_h->target_lun, 1965ef270ab1SKenneth D. Merry ccb->ccb_h.flags & CAM_CDB_POINTER ? 1966ef270ab1SKenneth D. Merry csio->cdb_io.cdb_ptr: csio->cdb_io.cdb_bytes, 1967ef270ab1SKenneth D. Merry csio->cdb_len, 1968ef270ab1SKenneth D. Merry NULL, 1969ef270ab1SKenneth D. Merry sgl, sgl_count, csio->dxfer_len, 197088364968SAlexander Motin ocs_scsi_initiator_io_cb, ccb, flags); 1971ef270ab1SKenneth D. Merry break; 1972ef270ab1SKenneth D. Merry default: 1973ef270ab1SKenneth D. Merry panic("%s invalid data direction %08x\n", __func__, 1974ef270ab1SKenneth D. Merry ccb->ccb_h.flags); 1975ef270ab1SKenneth D. Merry break; 1976ef270ab1SKenneth D. Merry } 1977ef270ab1SKenneth D. Merry 1978ef270ab1SKenneth D. Merry return rc; 1979ef270ab1SKenneth D. Merry } 1980ef270ab1SKenneth D. Merry 1981ef270ab1SKenneth D. Merry static uint32_t 1982ef270ab1SKenneth D. Merry ocs_fcp_change_role(struct ocs_softc *ocs, ocs_fcport *fcp, uint32_t new_role) 1983ef270ab1SKenneth D. Merry { 1984ef270ab1SKenneth D. Merry 1985ef270ab1SKenneth D. Merry uint32_t rc = 0, was = 0, i = 0; 1986ef270ab1SKenneth D. Merry ocs_vport_spec_t *vport = fcp->vport; 1987ef270ab1SKenneth D. Merry 1988ef270ab1SKenneth D. Merry for (was = 0, i = 0; i < (ocs->num_vports + 1); i++) { 1989ef270ab1SKenneth D. Merry if (FCPORT(ocs, i)->role != KNOB_ROLE_NONE) 1990ef270ab1SKenneth D. Merry was++; 1991ef270ab1SKenneth D. Merry } 1992ef270ab1SKenneth D. Merry 1993ef270ab1SKenneth D. Merry // Physical port 1994ef270ab1SKenneth D. Merry if ((was == 0) || (vport == NULL)) { 1995ef270ab1SKenneth D. Merry fcp->role = new_role; 1996ef270ab1SKenneth D. Merry if (vport == NULL) { 1997ef270ab1SKenneth D. Merry ocs->enable_ini = (new_role & KNOB_ROLE_INITIATOR)? 1:0; 1998ef270ab1SKenneth D. Merry ocs->enable_tgt = (new_role & KNOB_ROLE_TARGET)? 1:0; 1999ef270ab1SKenneth D. Merry } else { 2000ef270ab1SKenneth D. Merry vport->enable_ini = (new_role & KNOB_ROLE_INITIATOR)? 1:0; 2001ef270ab1SKenneth D. Merry vport->enable_tgt = (new_role & KNOB_ROLE_TARGET)? 1:0; 2002ef270ab1SKenneth D. Merry } 2003ef270ab1SKenneth D. Merry 2004ef270ab1SKenneth D. Merry rc = ocs_xport_control(ocs->xport, OCS_XPORT_PORT_OFFLINE); 2005ef270ab1SKenneth D. Merry if (rc) { 2006ef270ab1SKenneth D. Merry ocs_log_debug(ocs, "port offline failed : %d\n", rc); 2007ef270ab1SKenneth D. Merry } 2008ef270ab1SKenneth D. Merry 2009ef270ab1SKenneth D. Merry rc = ocs_xport_control(ocs->xport, OCS_XPORT_PORT_ONLINE); 2010ef270ab1SKenneth D. Merry if (rc) { 2011ef270ab1SKenneth D. Merry ocs_log_debug(ocs, "port online failed : %d\n", rc); 2012ef270ab1SKenneth D. Merry } 2013ef270ab1SKenneth D. Merry 2014ef270ab1SKenneth D. Merry return 0; 2015ef270ab1SKenneth D. Merry } 2016ef270ab1SKenneth D. Merry 2017ef270ab1SKenneth D. Merry if ((fcp->role != KNOB_ROLE_NONE)){ 2018ef270ab1SKenneth D. Merry fcp->role = new_role; 2019ef270ab1SKenneth D. Merry vport->enable_ini = (new_role & KNOB_ROLE_INITIATOR)? 1:0; 2020ef270ab1SKenneth D. Merry vport->enable_tgt = (new_role & KNOB_ROLE_TARGET)? 1:0; 2021ef270ab1SKenneth D. Merry /* New Sport will be created in sport deleted cb */ 2022ef270ab1SKenneth D. Merry return ocs_sport_vport_del(ocs, ocs->domain, vport->wwpn, vport->wwnn); 2023ef270ab1SKenneth D. Merry } 2024ef270ab1SKenneth D. Merry 2025ef270ab1SKenneth D. Merry fcp->role = new_role; 2026ef270ab1SKenneth D. Merry 2027ef270ab1SKenneth D. Merry vport->enable_ini = (new_role & KNOB_ROLE_INITIATOR)? 1:0; 2028ef270ab1SKenneth D. Merry vport->enable_tgt = (new_role & KNOB_ROLE_TARGET)? 1:0; 2029ef270ab1SKenneth D. Merry 2030ef270ab1SKenneth D. Merry if (fcp->role != KNOB_ROLE_NONE) { 2031ef270ab1SKenneth D. Merry return ocs_sport_vport_alloc(ocs->domain, vport); 2032ef270ab1SKenneth D. Merry } 2033ef270ab1SKenneth D. Merry 2034ef270ab1SKenneth D. Merry return (0); 2035ef270ab1SKenneth D. Merry } 2036ef270ab1SKenneth D. Merry 2037ef270ab1SKenneth D. Merry /** 2038ef270ab1SKenneth D. Merry * @ingroup cam_api 2039ef270ab1SKenneth D. Merry * @brief Process CAM actions 2040ef270ab1SKenneth D. Merry * 2041ef270ab1SKenneth D. Merry * The driver supplies this routine to the CAM during intialization and 2042ef270ab1SKenneth D. Merry * is the main entry point for processing CAM Control Blocks (CCB) 2043ef270ab1SKenneth D. Merry * 2044ef270ab1SKenneth D. Merry * @param sim pointer to the SCSI Interface Module 2045ef270ab1SKenneth D. Merry * @param ccb CAM control block 2046ef270ab1SKenneth D. Merry * 2047ef270ab1SKenneth D. Merry * @todo 2048ef270ab1SKenneth D. Merry * - populate path inquiry data via info retrieved from SLI port 2049ef270ab1SKenneth D. Merry */ 2050ef270ab1SKenneth D. Merry static void 2051ef270ab1SKenneth D. Merry ocs_action(struct cam_sim *sim, union ccb *ccb) 2052ef270ab1SKenneth D. Merry { 2053ef270ab1SKenneth D. Merry struct ocs_softc *ocs = (struct ocs_softc *)cam_sim_softc(sim); 2054ef270ab1SKenneth D. Merry struct ccb_hdr *ccb_h = &ccb->ccb_h; 2055ef270ab1SKenneth D. Merry 2056ef270ab1SKenneth D. Merry int32_t rc, bus; 2057ef270ab1SKenneth D. Merry bus = cam_sim_bus(sim); 2058ef270ab1SKenneth D. Merry 2059ef270ab1SKenneth D. Merry switch (ccb_h->func_code) { 2060ef270ab1SKenneth D. Merry case XPT_SCSI_IO: 2061ef270ab1SKenneth D. Merry 2062ef270ab1SKenneth D. Merry if ((ccb->ccb_h.flags & CAM_CDB_POINTER) != 0) { 2063ef270ab1SKenneth D. Merry if ((ccb->ccb_h.flags & CAM_CDB_PHYS) != 0) { 2064ef270ab1SKenneth D. Merry ccb->ccb_h.status = CAM_REQ_INVALID; 2065ef270ab1SKenneth D. Merry xpt_done(ccb); 2066ef270ab1SKenneth D. Merry break; 2067ef270ab1SKenneth D. Merry } 2068ef270ab1SKenneth D. Merry } 2069ef270ab1SKenneth D. Merry 2070ef270ab1SKenneth D. Merry rc = ocs_initiator_io(ocs, ccb); 2071ef270ab1SKenneth D. Merry if (0 == rc) { 2072ef270ab1SKenneth D. Merry ocs_set_ccb_status(ccb, CAM_REQ_INPROG | CAM_SIM_QUEUED); 2073ef270ab1SKenneth D. Merry break; 2074ef270ab1SKenneth D. Merry } else { 20756affb8ebSRam Kishore Vegesna if (rc == CAM_REQUEUE_REQ) { 20766affb8ebSRam Kishore Vegesna cam_freeze_devq(ccb->ccb_h.path); 20776affb8ebSRam Kishore Vegesna cam_release_devq(ccb->ccb_h.path, RELSIM_RELEASE_AFTER_TIMEOUT, 0, 100, 0); 20786affb8ebSRam Kishore Vegesna ccb->ccb_h.status = CAM_REQUEUE_REQ; 20796affb8ebSRam Kishore Vegesna xpt_done(ccb); 20806affb8ebSRam Kishore Vegesna break; 20816affb8ebSRam Kishore Vegesna } 20826affb8ebSRam Kishore Vegesna 2083ef270ab1SKenneth D. Merry ccb->ccb_h.status &= ~CAM_SIM_QUEUED; 2084ef270ab1SKenneth D. Merry if (rc > 0) { 2085ef270ab1SKenneth D. Merry ocs_set_ccb_status(ccb, rc); 2086ef270ab1SKenneth D. Merry } else { 2087ef270ab1SKenneth D. Merry ocs_set_ccb_status(ccb, CAM_SEL_TIMEOUT); 2088ef270ab1SKenneth D. Merry } 2089ef270ab1SKenneth D. Merry } 2090ef270ab1SKenneth D. Merry xpt_done(ccb); 2091ef270ab1SKenneth D. Merry break; 2092ef270ab1SKenneth D. Merry case XPT_PATH_INQ: 2093ef270ab1SKenneth D. Merry { 2094ef270ab1SKenneth D. Merry struct ccb_pathinq *cpi = &ccb->cpi; 2095ef270ab1SKenneth D. Merry struct ccb_pathinq_settings_fc *fc = &cpi->xport_specific.fc; 2096b9732f78SRam Kishore Vegesna ocs_fcport *fcp = FCPORT(ocs, bus); 2097ef270ab1SKenneth D. Merry 2098ef270ab1SKenneth D. Merry uint64_t wwn = 0; 2099ef270ab1SKenneth D. Merry ocs_xport_stats_t value; 2100ef270ab1SKenneth D. Merry 2101ef270ab1SKenneth D. Merry cpi->version_num = 1; 2102ef270ab1SKenneth D. Merry 2103ef270ab1SKenneth D. Merry cpi->protocol = PROTO_SCSI; 2104ef270ab1SKenneth D. Merry cpi->protocol_version = SCSI_REV_SPC; 2105ef270ab1SKenneth D. Merry 2106ef270ab1SKenneth D. Merry if (ocs->ocs_xport == OCS_XPORT_FC) { 2107ef270ab1SKenneth D. Merry cpi->transport = XPORT_FC; 2108ef270ab1SKenneth D. Merry } else { 2109ef270ab1SKenneth D. Merry cpi->transport = XPORT_UNKNOWN; 2110ef270ab1SKenneth D. Merry } 2111ef270ab1SKenneth D. Merry 2112ef270ab1SKenneth D. Merry cpi->transport_version = 0; 2113ef270ab1SKenneth D. Merry 2114ef270ab1SKenneth D. Merry /* Set the transport parameters of the SIM */ 2115ef270ab1SKenneth D. Merry ocs_xport_status(ocs->xport, OCS_XPORT_LINK_SPEED, &value); 2116ef270ab1SKenneth D. Merry fc->bitrate = value.value * 1000; /* speed in Mbps */ 2117ef270ab1SKenneth D. Merry 2118ef270ab1SKenneth D. Merry wwn = *((uint64_t *)ocs_scsi_get_property_ptr(ocs, OCS_SCSI_WWPN)); 2119ef270ab1SKenneth D. Merry fc->wwpn = be64toh(wwn); 2120ef270ab1SKenneth D. Merry 2121ef270ab1SKenneth D. Merry wwn = *((uint64_t *)ocs_scsi_get_property_ptr(ocs, OCS_SCSI_WWNN)); 2122ef270ab1SKenneth D. Merry fc->wwnn = be64toh(wwn); 2123ef270ab1SKenneth D. Merry 2124b9732f78SRam Kishore Vegesna fc->port = fcp->fc_id; 2125ef270ab1SKenneth D. Merry 2126ef270ab1SKenneth D. Merry if (ocs->config_tgt) { 2127ef270ab1SKenneth D. Merry cpi->target_sprt = 2128ef270ab1SKenneth D. Merry PIT_PROCESSOR | PIT_DISCONNECT | PIT_TERM_IO; 2129ef270ab1SKenneth D. Merry } 2130ef270ab1SKenneth D. Merry 2131ef270ab1SKenneth D. Merry cpi->hba_misc = PIM_NOBUSRESET | PIM_UNMAPPED; 2132ef270ab1SKenneth D. Merry cpi->hba_misc |= PIM_EXTLUNS | PIM_NOSCAN; 2133ef270ab1SKenneth D. Merry 2134ef270ab1SKenneth D. Merry cpi->hba_inquiry = PI_TAG_ABLE; 2135ef270ab1SKenneth D. Merry cpi->max_target = OCS_MAX_TARGETS; 2136ef270ab1SKenneth D. Merry cpi->initiator_id = ocs->max_remote_nodes + 1; 2137ef270ab1SKenneth D. Merry 2138ef270ab1SKenneth D. Merry if (!ocs->enable_ini) { 2139ef270ab1SKenneth D. Merry cpi->hba_misc |= PIM_NOINITIATOR; 2140ef270ab1SKenneth D. Merry } 2141ef270ab1SKenneth D. Merry 2142ef270ab1SKenneth D. Merry cpi->max_lun = OCS_MAX_LUN; 2143ef270ab1SKenneth D. Merry cpi->bus_id = cam_sim_bus(sim); 2144ef270ab1SKenneth D. Merry 2145ef270ab1SKenneth D. Merry /* Need to supply a base transfer speed prior to linking up 2146ef270ab1SKenneth D. Merry * Worst case, this would be FC 1Gbps */ 2147ef270ab1SKenneth D. Merry cpi->base_transfer_speed = 1 * 1000 * 1000; 2148ef270ab1SKenneth D. Merry 2149ef270ab1SKenneth D. Merry /* Calculate the max IO supported 2150ef270ab1SKenneth D. Merry * Worst case would be an OS page per SGL entry */ 2151322dbb8cSRam Kishore Vegesna 2152ef270ab1SKenneth D. Merry cpi->maxio = PAGE_SIZE * 2153ef270ab1SKenneth D. Merry (ocs_scsi_get_property(ocs, OCS_SCSI_MAX_SGL) - 1); 2154ef270ab1SKenneth D. Merry 2155ef270ab1SKenneth D. Merry strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 2156ef270ab1SKenneth D. Merry strncpy(cpi->hba_vid, "Emulex", HBA_IDLEN); 2157ef270ab1SKenneth D. Merry strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 2158ef270ab1SKenneth D. Merry cpi->unit_number = cam_sim_unit(sim); 2159ef270ab1SKenneth D. Merry 2160ef270ab1SKenneth D. Merry cpi->ccb_h.status = CAM_REQ_CMP; 2161ef270ab1SKenneth D. Merry xpt_done(ccb); 2162ef270ab1SKenneth D. Merry break; 2163ef270ab1SKenneth D. Merry } 2164ef270ab1SKenneth D. Merry case XPT_GET_TRAN_SETTINGS: 2165ef270ab1SKenneth D. Merry { 2166ef270ab1SKenneth D. Merry struct ccb_trans_settings *cts = &ccb->cts; 2167ef270ab1SKenneth D. Merry struct ccb_trans_settings_scsi *scsi = &cts->proto_specific.scsi; 2168ef270ab1SKenneth D. Merry struct ccb_trans_settings_fc *fc = &cts->xport_specific.fc; 2169ef270ab1SKenneth D. Merry ocs_xport_stats_t value; 21706affb8ebSRam Kishore Vegesna ocs_fcport *fcp = FCPORT(ocs, bus); 2171b9732f78SRam Kishore Vegesna ocs_fc_target_t *tgt = NULL; 2172ef270ab1SKenneth D. Merry 2173ef270ab1SKenneth D. Merry if (ocs->ocs_xport != OCS_XPORT_FC) { 2174ef270ab1SKenneth D. Merry ocs_set_ccb_status(ccb, CAM_REQ_INVALID); 2175ef270ab1SKenneth D. Merry xpt_done(ccb); 2176ef270ab1SKenneth D. Merry break; 2177ef270ab1SKenneth D. Merry } 2178ef270ab1SKenneth D. Merry 2179b9732f78SRam Kishore Vegesna if (cts->ccb_h.target_id > OCS_MAX_TARGETS) { 2180b9732f78SRam Kishore Vegesna ocs_set_ccb_status(ccb, CAM_DEV_NOT_THERE); 2181b9732f78SRam Kishore Vegesna xpt_done(ccb); 2182b9732f78SRam Kishore Vegesna break; 2183b9732f78SRam Kishore Vegesna } 2184b9732f78SRam Kishore Vegesna 2185b9732f78SRam Kishore Vegesna tgt = &fcp->tgt[cts->ccb_h.target_id]; 2186b9732f78SRam Kishore Vegesna if (tgt->state == OCS_TGT_STATE_NONE) { 2187ef270ab1SKenneth D. Merry ocs_set_ccb_status(ccb, CAM_DEV_NOT_THERE); 2188ef270ab1SKenneth D. Merry xpt_done(ccb); 2189ef270ab1SKenneth D. Merry break; 2190ef270ab1SKenneth D. Merry } 2191ef270ab1SKenneth D. Merry 2192ef270ab1SKenneth D. Merry cts->protocol = PROTO_SCSI; 2193ef270ab1SKenneth D. Merry cts->protocol_version = SCSI_REV_SPC2; 2194ef270ab1SKenneth D. Merry cts->transport = XPORT_FC; 2195ef270ab1SKenneth D. Merry cts->transport_version = 2; 2196ef270ab1SKenneth D. Merry 2197ef270ab1SKenneth D. Merry scsi->valid = CTS_SCSI_VALID_TQ; 2198ef270ab1SKenneth D. Merry scsi->flags = CTS_SCSI_FLAGS_TAG_ENB; 2199ef270ab1SKenneth D. Merry 2200ef270ab1SKenneth D. Merry /* speed in Mbps */ 2201ef270ab1SKenneth D. Merry ocs_xport_status(ocs->xport, OCS_XPORT_LINK_SPEED, &value); 2202ef270ab1SKenneth D. Merry fc->bitrate = value.value * 100; 2203ef270ab1SKenneth D. Merry 2204b9732f78SRam Kishore Vegesna fc->wwpn = tgt->wwpn; 2205ef270ab1SKenneth D. Merry 2206b9732f78SRam Kishore Vegesna fc->wwnn = tgt->wwnn; 2207ef270ab1SKenneth D. Merry 2208b9732f78SRam Kishore Vegesna fc->port = tgt->port_id; 2209ef270ab1SKenneth D. Merry 2210ef270ab1SKenneth D. Merry fc->valid = CTS_FC_VALID_SPEED | 2211ef270ab1SKenneth D. Merry CTS_FC_VALID_WWPN | 2212ef270ab1SKenneth D. Merry CTS_FC_VALID_WWNN | 2213ef270ab1SKenneth D. Merry CTS_FC_VALID_PORT; 2214ef270ab1SKenneth D. Merry 2215ef270ab1SKenneth D. Merry ocs_set_ccb_status(ccb, CAM_REQ_CMP); 2216ef270ab1SKenneth D. Merry xpt_done(ccb); 2217ef270ab1SKenneth D. Merry break; 2218ef270ab1SKenneth D. Merry } 2219ef270ab1SKenneth D. Merry case XPT_SET_TRAN_SETTINGS: 2220ef270ab1SKenneth D. Merry ocs_set_ccb_status(ccb, CAM_REQ_CMP); 2221ef270ab1SKenneth D. Merry xpt_done(ccb); 2222ef270ab1SKenneth D. Merry break; 2223ef270ab1SKenneth D. Merry 2224ef270ab1SKenneth D. Merry case XPT_CALC_GEOMETRY: 2225ef270ab1SKenneth D. Merry cam_calc_geometry(&ccb->ccg, TRUE); 2226ef270ab1SKenneth D. Merry xpt_done(ccb); 2227ef270ab1SKenneth D. Merry break; 2228ef270ab1SKenneth D. Merry 2229ef270ab1SKenneth D. Merry case XPT_GET_SIM_KNOB: 2230ef270ab1SKenneth D. Merry { 2231ef270ab1SKenneth D. Merry struct ccb_sim_knob *knob = &ccb->knob; 2232ef270ab1SKenneth D. Merry uint64_t wwn = 0; 2233ef270ab1SKenneth D. Merry ocs_fcport *fcp = FCPORT(ocs, bus); 2234ef270ab1SKenneth D. Merry 2235ef270ab1SKenneth D. Merry if (ocs->ocs_xport != OCS_XPORT_FC) { 2236ef270ab1SKenneth D. Merry ocs_set_ccb_status(ccb, CAM_REQ_INVALID); 2237ef270ab1SKenneth D. Merry xpt_done(ccb); 2238ef270ab1SKenneth D. Merry break; 2239ef270ab1SKenneth D. Merry } 2240ef270ab1SKenneth D. Merry 2241ef270ab1SKenneth D. Merry if (bus == 0) { 2242ef270ab1SKenneth D. Merry wwn = *((uint64_t *)ocs_scsi_get_property_ptr(ocs, 2243ef270ab1SKenneth D. Merry OCS_SCSI_WWNN)); 2244ef270ab1SKenneth D. Merry knob->xport_specific.fc.wwnn = be64toh(wwn); 2245ef270ab1SKenneth D. Merry 2246ef270ab1SKenneth D. Merry wwn = *((uint64_t *)ocs_scsi_get_property_ptr(ocs, 2247ef270ab1SKenneth D. Merry OCS_SCSI_WWPN)); 2248ef270ab1SKenneth D. Merry knob->xport_specific.fc.wwpn = be64toh(wwn); 2249ef270ab1SKenneth D. Merry } else { 2250ef270ab1SKenneth D. Merry knob->xport_specific.fc.wwnn = fcp->vport->wwnn; 2251ef270ab1SKenneth D. Merry knob->xport_specific.fc.wwpn = fcp->vport->wwpn; 2252ef270ab1SKenneth D. Merry } 2253ef270ab1SKenneth D. Merry 2254ef270ab1SKenneth D. Merry knob->xport_specific.fc.role = fcp->role; 2255ef270ab1SKenneth D. Merry knob->xport_specific.fc.valid = KNOB_VALID_ADDRESS | 2256ef270ab1SKenneth D. Merry KNOB_VALID_ROLE; 2257ef270ab1SKenneth D. Merry 2258ef270ab1SKenneth D. Merry ocs_set_ccb_status(ccb, CAM_REQ_CMP); 2259ef270ab1SKenneth D. Merry xpt_done(ccb); 2260ef270ab1SKenneth D. Merry break; 2261ef270ab1SKenneth D. Merry } 2262ef270ab1SKenneth D. Merry case XPT_SET_SIM_KNOB: 2263ef270ab1SKenneth D. Merry { 2264ef270ab1SKenneth D. Merry struct ccb_sim_knob *knob = &ccb->knob; 2265ef270ab1SKenneth D. Merry bool role_changed = FALSE; 2266ef270ab1SKenneth D. Merry ocs_fcport *fcp = FCPORT(ocs, bus); 2267ef270ab1SKenneth D. Merry 2268ef270ab1SKenneth D. Merry if (ocs->ocs_xport != OCS_XPORT_FC) { 2269ef270ab1SKenneth D. Merry ocs_set_ccb_status(ccb, CAM_REQ_INVALID); 2270ef270ab1SKenneth D. Merry xpt_done(ccb); 2271ef270ab1SKenneth D. Merry break; 2272ef270ab1SKenneth D. Merry } 2273ef270ab1SKenneth D. Merry 2274ef270ab1SKenneth D. Merry if (knob->xport_specific.fc.valid & KNOB_VALID_ADDRESS) { 2275ef270ab1SKenneth D. Merry device_printf(ocs->dev, 2276ef270ab1SKenneth D. Merry "%s: XPT_SET_SIM_KNOB wwnn=%llx wwpn=%llx\n", 2277ef270ab1SKenneth D. Merry __func__, 2278ef270ab1SKenneth D. Merry (unsigned long long)knob->xport_specific.fc.wwnn, 2279ef270ab1SKenneth D. Merry (unsigned long long)knob->xport_specific.fc.wwpn); 2280ef270ab1SKenneth D. Merry } 2281ef270ab1SKenneth D. Merry 2282ef270ab1SKenneth D. Merry if (knob->xport_specific.fc.valid & KNOB_VALID_ROLE) { 2283ef270ab1SKenneth D. Merry switch (knob->xport_specific.fc.role) { 2284ef270ab1SKenneth D. Merry case KNOB_ROLE_NONE: 2285ef270ab1SKenneth D. Merry if (fcp->role != KNOB_ROLE_NONE) { 2286ef270ab1SKenneth D. Merry role_changed = TRUE; 2287ef270ab1SKenneth D. Merry } 2288ef270ab1SKenneth D. Merry break; 2289ef270ab1SKenneth D. Merry case KNOB_ROLE_TARGET: 2290ef270ab1SKenneth D. Merry if (fcp->role != KNOB_ROLE_TARGET) { 2291ef270ab1SKenneth D. Merry role_changed = TRUE; 2292ef270ab1SKenneth D. Merry } 2293ef270ab1SKenneth D. Merry break; 2294ef270ab1SKenneth D. Merry case KNOB_ROLE_INITIATOR: 2295ef270ab1SKenneth D. Merry if (fcp->role != KNOB_ROLE_INITIATOR) { 2296ef270ab1SKenneth D. Merry role_changed = TRUE; 2297ef270ab1SKenneth D. Merry } 2298ef270ab1SKenneth D. Merry break; 2299ef270ab1SKenneth D. Merry case KNOB_ROLE_BOTH: 2300ef270ab1SKenneth D. Merry if (fcp->role != KNOB_ROLE_BOTH) { 2301ef270ab1SKenneth D. Merry role_changed = TRUE; 2302ef270ab1SKenneth D. Merry } 2303ef270ab1SKenneth D. Merry break; 2304ef270ab1SKenneth D. Merry default: 2305ef270ab1SKenneth D. Merry device_printf(ocs->dev, 2306ef270ab1SKenneth D. Merry "%s: XPT_SET_SIM_KNOB unsupported role: %d\n", 2307ef270ab1SKenneth D. Merry __func__, knob->xport_specific.fc.role); 2308ef270ab1SKenneth D. Merry } 2309ef270ab1SKenneth D. Merry 2310ef270ab1SKenneth D. Merry if (role_changed) { 2311ef270ab1SKenneth D. Merry device_printf(ocs->dev, 2312ef270ab1SKenneth D. Merry "BUS:%d XPT_SET_SIM_KNOB old_role: %d new_role: %d\n", 2313ef270ab1SKenneth D. Merry bus, fcp->role, knob->xport_specific.fc.role); 2314ef270ab1SKenneth D. Merry 2315ef270ab1SKenneth D. Merry ocs_fcp_change_role(ocs, fcp, knob->xport_specific.fc.role); 2316ef270ab1SKenneth D. Merry } 2317ef270ab1SKenneth D. Merry } 2318ef270ab1SKenneth D. Merry 2319ef270ab1SKenneth D. Merry 2320ef270ab1SKenneth D. Merry 2321ef270ab1SKenneth D. Merry ocs_set_ccb_status(ccb, CAM_REQ_CMP); 2322ef270ab1SKenneth D. Merry xpt_done(ccb); 2323ef270ab1SKenneth D. Merry break; 2324ef270ab1SKenneth D. Merry } 2325ef270ab1SKenneth D. Merry case XPT_ABORT: 2326ef270ab1SKenneth D. Merry { 2327ef270ab1SKenneth D. Merry union ccb *accb = ccb->cab.abort_ccb; 2328ef270ab1SKenneth D. Merry 2329ef270ab1SKenneth D. Merry switch (accb->ccb_h.func_code) { 2330ef270ab1SKenneth D. Merry case XPT_ACCEPT_TARGET_IO: 2331ef270ab1SKenneth D. Merry ocs_abort_atio(ocs, ccb); 2332ef270ab1SKenneth D. Merry break; 2333ef270ab1SKenneth D. Merry case XPT_IMMEDIATE_NOTIFY: 2334ef270ab1SKenneth D. Merry ocs_abort_inot(ocs, ccb); 2335ef270ab1SKenneth D. Merry break; 2336ef270ab1SKenneth D. Merry case XPT_SCSI_IO: 2337ef270ab1SKenneth D. Merry rc = ocs_abort_initiator_io(ocs, accb); 2338ef270ab1SKenneth D. Merry if (rc) { 2339ef270ab1SKenneth D. Merry ccb->ccb_h.status = CAM_UA_ABORT; 2340ef270ab1SKenneth D. Merry } else { 2341ef270ab1SKenneth D. Merry ccb->ccb_h.status = CAM_REQ_CMP; 2342ef270ab1SKenneth D. Merry } 2343ef270ab1SKenneth D. Merry 2344ef270ab1SKenneth D. Merry break; 2345ef270ab1SKenneth D. Merry default: 2346ef270ab1SKenneth D. Merry printf("abort of unknown func %#x\n", 2347ef270ab1SKenneth D. Merry accb->ccb_h.func_code); 2348ef270ab1SKenneth D. Merry ccb->ccb_h.status = CAM_REQ_INVALID; 2349ef270ab1SKenneth D. Merry break; 2350ef270ab1SKenneth D. Merry } 2351ef270ab1SKenneth D. Merry break; 2352ef270ab1SKenneth D. Merry } 2353ef270ab1SKenneth D. Merry case XPT_RESET_BUS: 2354ef270ab1SKenneth D. Merry if (ocs_xport_control(ocs->xport, OCS_XPORT_PORT_OFFLINE) == 0) { 23554915e5c7SRam Kishore Vegesna rc = ocs_xport_control(ocs->xport, OCS_XPORT_PORT_ONLINE); 23564915e5c7SRam Kishore Vegesna if (rc) { 23574915e5c7SRam Kishore Vegesna ocs_log_debug(ocs, "Failed to bring port online" 23584915e5c7SRam Kishore Vegesna " : %d\n", rc); 23594915e5c7SRam Kishore Vegesna } 2360ef270ab1SKenneth D. Merry ocs_set_ccb_status(ccb, CAM_REQ_CMP); 2361ef270ab1SKenneth D. Merry } else { 2362ef270ab1SKenneth D. Merry ocs_set_ccb_status(ccb, CAM_REQ_CMP_ERR); 2363ef270ab1SKenneth D. Merry } 2364ef270ab1SKenneth D. Merry xpt_done(ccb); 2365ef270ab1SKenneth D. Merry break; 2366ef270ab1SKenneth D. Merry case XPT_RESET_DEV: 2367ef270ab1SKenneth D. Merry { 2368ef270ab1SKenneth D. Merry ocs_node_t *node = NULL; 2369ef270ab1SKenneth D. Merry ocs_io_t *io = NULL; 2370ef270ab1SKenneth D. Merry int32_t rc = 0; 23716affb8ebSRam Kishore Vegesna ocs_fcport *fcp = FCPORT(ocs, bus); 2372ef270ab1SKenneth D. Merry 23736affb8ebSRam Kishore Vegesna node = ocs_node_get_instance(ocs, fcp->tgt[ccb_h->target_id].node_id); 2374ef270ab1SKenneth D. Merry if (node == NULL) { 2375ef270ab1SKenneth D. Merry device_printf(ocs->dev, "%s: no device %d\n", 2376ef270ab1SKenneth D. Merry __func__, ccb_h->target_id); 2377ef270ab1SKenneth D. Merry ocs_set_ccb_status(ccb, CAM_DEV_NOT_THERE); 2378ef270ab1SKenneth D. Merry xpt_done(ccb); 2379ef270ab1SKenneth D. Merry break; 2380ef270ab1SKenneth D. Merry } 2381ef270ab1SKenneth D. Merry 2382ef270ab1SKenneth D. Merry io = ocs_scsi_io_alloc(node, OCS_SCSI_IO_ROLE_ORIGINATOR); 2383ef270ab1SKenneth D. Merry if (io == NULL) { 2384ef270ab1SKenneth D. Merry device_printf(ocs->dev, "%s: unable to alloc IO\n", 2385ef270ab1SKenneth D. Merry __func__); 2386ef270ab1SKenneth D. Merry ocs_set_ccb_status(ccb, CAM_REQ_CMP_ERR); 2387ef270ab1SKenneth D. Merry xpt_done(ccb); 2388ef270ab1SKenneth D. Merry break; 2389ef270ab1SKenneth D. Merry } 2390ef270ab1SKenneth D. Merry 2391ef270ab1SKenneth D. Merry rc = ocs_scsi_send_tmf(node, io, NULL, ccb_h->target_lun, 2392ef270ab1SKenneth D. Merry OCS_SCSI_TMF_LOGICAL_UNIT_RESET, 2393ef270ab1SKenneth D. Merry NULL, 0, 0, /* sgl, sgl_count, length */ 2394ef270ab1SKenneth D. Merry ocs_initiator_tmf_cb, NULL/*arg*/); 2395ef270ab1SKenneth D. Merry 2396ef270ab1SKenneth D. Merry if (rc) { 2397ef270ab1SKenneth D. Merry ocs_set_ccb_status(ccb, CAM_REQ_CMP_ERR); 2398ef270ab1SKenneth D. Merry } else { 2399ef270ab1SKenneth D. Merry ocs_set_ccb_status(ccb, CAM_REQ_CMP); 2400ef270ab1SKenneth D. Merry } 2401ef270ab1SKenneth D. Merry 2402ef270ab1SKenneth D. Merry if (node->fcp2device) { 2403ef270ab1SKenneth D. Merry ocs_reset_crn(node, ccb_h->target_lun); 2404ef270ab1SKenneth D. Merry } 2405ef270ab1SKenneth D. Merry 2406ef270ab1SKenneth D. Merry xpt_done(ccb); 2407ef270ab1SKenneth D. Merry break; 2408ef270ab1SKenneth D. Merry } 2409ef270ab1SKenneth D. Merry case XPT_EN_LUN: /* target support */ 2410ef270ab1SKenneth D. Merry { 2411ef270ab1SKenneth D. Merry ocs_tgt_resource_t *trsrc = NULL; 2412ef270ab1SKenneth D. Merry uint32_t status = 0; 2413ef270ab1SKenneth D. Merry ocs_fcport *fcp = FCPORT(ocs, bus); 2414ef270ab1SKenneth D. Merry 2415ef270ab1SKenneth D. Merry device_printf(ocs->dev, "XPT_EN_LUN %sable %d:%d\n", 2416ef270ab1SKenneth D. Merry ccb->cel.enable ? "en" : "dis", 2417ef270ab1SKenneth D. Merry ccb->ccb_h.target_id, 2418ef270ab1SKenneth D. Merry (unsigned int)ccb->ccb_h.target_lun); 2419ef270ab1SKenneth D. Merry 2420ef270ab1SKenneth D. Merry trsrc = ocs_tgt_resource_get(fcp, &ccb->ccb_h, &status); 2421ef270ab1SKenneth D. Merry if (trsrc) { 2422ef270ab1SKenneth D. Merry trsrc->enabled = ccb->cel.enable; 2423ef270ab1SKenneth D. Merry 2424ef270ab1SKenneth D. Merry /* Abort all ATIO/INOT on LUN disable */ 2425ef270ab1SKenneth D. Merry if (trsrc->enabled == FALSE) { 2426ef270ab1SKenneth D. Merry ocs_tgt_resource_abort(ocs, trsrc); 2427ef270ab1SKenneth D. Merry } else { 2428ef270ab1SKenneth D. Merry STAILQ_INIT(&trsrc->atio); 2429ef270ab1SKenneth D. Merry STAILQ_INIT(&trsrc->inot); 2430ef270ab1SKenneth D. Merry } 2431ef270ab1SKenneth D. Merry status = CAM_REQ_CMP; 2432ef270ab1SKenneth D. Merry } 2433ef270ab1SKenneth D. Merry 2434ef270ab1SKenneth D. Merry ocs_set_ccb_status(ccb, status); 2435ef270ab1SKenneth D. Merry xpt_done(ccb); 2436ef270ab1SKenneth D. Merry break; 2437ef270ab1SKenneth D. Merry } 2438ef270ab1SKenneth D. Merry /* 2439ef270ab1SKenneth D. Merry * The flow of target IOs in CAM is: 2440ef270ab1SKenneth D. Merry * - CAM supplies a number of CCBs to the driver used for received 2441ef270ab1SKenneth D. Merry * commands. 2442ef270ab1SKenneth D. Merry * - when the driver receives a command, it copies the relevant 2443ef270ab1SKenneth D. Merry * information to the CCB and returns it to the CAM using xpt_done() 2444ef270ab1SKenneth D. Merry * - after the target server processes the request, it creates 2445ef270ab1SKenneth D. Merry * a new CCB containing information on how to continue the IO and 2446ef270ab1SKenneth D. Merry * passes that to the driver 2447ef270ab1SKenneth D. Merry * - the driver processes the "continue IO" (a.k.a CTIO) CCB 2448ef270ab1SKenneth D. Merry * - once the IO completes, the driver returns the CTIO to the CAM 2449ef270ab1SKenneth D. Merry * using xpt_done() 2450ef270ab1SKenneth D. Merry */ 2451ef270ab1SKenneth D. Merry case XPT_ACCEPT_TARGET_IO: /* used to inform upper layer of 2452ef270ab1SKenneth D. Merry received CDB (a.k.a. ATIO) */ 2453ef270ab1SKenneth D. Merry case XPT_IMMEDIATE_NOTIFY: /* used to inform upper layer of other 2454ef270ab1SKenneth D. Merry event (a.k.a. INOT) */ 2455ef270ab1SKenneth D. Merry { 2456ef270ab1SKenneth D. Merry ocs_tgt_resource_t *trsrc = NULL; 2457ef270ab1SKenneth D. Merry uint32_t status = 0; 2458ef270ab1SKenneth D. Merry ocs_fcport *fcp = FCPORT(ocs, bus); 2459ef270ab1SKenneth D. Merry 2460ef270ab1SKenneth D. Merry /*printf("XPT_%s %p\n", ccb_h->func_code == XPT_ACCEPT_TARGET_IO ? 2461ef270ab1SKenneth D. Merry "ACCEPT_TARGET_IO" : "IMMEDIATE_NOTIFY", ccb);*/ 2462ef270ab1SKenneth D. Merry trsrc = ocs_tgt_resource_get(fcp, &ccb->ccb_h, &status); 2463ef270ab1SKenneth D. Merry if (trsrc == NULL) { 2464ef270ab1SKenneth D. Merry ocs_set_ccb_status(ccb, CAM_DEV_NOT_THERE); 2465ef270ab1SKenneth D. Merry xpt_done(ccb); 2466ef270ab1SKenneth D. Merry break; 2467ef270ab1SKenneth D. Merry } 2468ef270ab1SKenneth D. Merry 2469ef270ab1SKenneth D. Merry if (XPT_ACCEPT_TARGET_IO == ccb->ccb_h.func_code) { 2470ef270ab1SKenneth D. Merry struct ccb_accept_tio *atio = NULL; 2471ef270ab1SKenneth D. Merry 2472ef270ab1SKenneth D. Merry atio = (struct ccb_accept_tio *)ccb; 2473ef270ab1SKenneth D. Merry atio->init_id = 0x0badbeef; 2474ef270ab1SKenneth D. Merry atio->tag_id = 0xdeadc0de; 2475ef270ab1SKenneth D. Merry 2476ef270ab1SKenneth D. Merry STAILQ_INSERT_TAIL(&trsrc->atio, &ccb->ccb_h, 2477ef270ab1SKenneth D. Merry sim_links.stqe); 2478ef270ab1SKenneth D. Merry } else { 2479ef270ab1SKenneth D. Merry STAILQ_INSERT_TAIL(&trsrc->inot, &ccb->ccb_h, 2480ef270ab1SKenneth D. Merry sim_links.stqe); 2481ef270ab1SKenneth D. Merry } 2482ef270ab1SKenneth D. Merry ccb->ccb_h.ccb_io_ptr = NULL; 2483ef270ab1SKenneth D. Merry ccb->ccb_h.ccb_ocs_ptr = ocs; 2484ef270ab1SKenneth D. Merry ocs_set_ccb_status(ccb, CAM_REQ_INPROG); 2485ef270ab1SKenneth D. Merry /* 2486ef270ab1SKenneth D. Merry * These actions give resources to the target driver. 2487ef270ab1SKenneth D. Merry * If we didn't return here, this function would call 2488ef270ab1SKenneth D. Merry * xpt_done(), signaling to the upper layers that an 2489ef270ab1SKenneth D. Merry * IO or other event had arrived. 2490ef270ab1SKenneth D. Merry */ 2491ef270ab1SKenneth D. Merry break; 2492ef270ab1SKenneth D. Merry } 2493ef270ab1SKenneth D. Merry case XPT_NOTIFY_ACKNOWLEDGE: 2494ef270ab1SKenneth D. Merry { 2495ef270ab1SKenneth D. Merry ocs_io_t *io = NULL; 2496ef270ab1SKenneth D. Merry ocs_io_t *abortio = NULL; 2497ef270ab1SKenneth D. Merry 2498ef270ab1SKenneth D. Merry /* Get the IO reference for this tag */ 2499ef270ab1SKenneth D. Merry io = ocs_scsi_find_io(ocs, ccb->cna2.tag_id); 2500ef270ab1SKenneth D. Merry if (io == NULL) { 2501ef270ab1SKenneth D. Merry device_printf(ocs->dev, 2502ef270ab1SKenneth D. Merry "%s: XPT_NOTIFY_ACKNOWLEDGE no IO with tag %#x\n", 2503ef270ab1SKenneth D. Merry __func__, ccb->cna2.tag_id); 2504ef270ab1SKenneth D. Merry ocs_set_ccb_status(ccb, CAM_REQ_CMP_ERR); 2505ef270ab1SKenneth D. Merry xpt_done(ccb); 2506ef270ab1SKenneth D. Merry break; 2507ef270ab1SKenneth D. Merry } 2508ef270ab1SKenneth D. Merry 2509ef270ab1SKenneth D. Merry abortio = io->tgt_io.app; 2510ef270ab1SKenneth D. Merry if (abortio) { 2511ef270ab1SKenneth D. Merry abortio->tgt_io.flags &= ~OCS_CAM_IO_F_ABORT_NOTIFY; 2512ef270ab1SKenneth D. Merry device_printf(ocs->dev, 2513ef270ab1SKenneth D. Merry "%s: XPT_NOTIFY_ACK state=%d tag=%#x xid=%#x" 2514ef270ab1SKenneth D. Merry " flags=%#x\n", __func__, abortio->tgt_io.state, 2515ef270ab1SKenneth D. Merry abortio->tag, abortio->init_task_tag, 2516ef270ab1SKenneth D. Merry abortio->tgt_io.flags); 2517ef270ab1SKenneth D. Merry /* TMF response was sent in abort callback */ 2518ef270ab1SKenneth D. Merry } else { 2519ef270ab1SKenneth D. Merry ocs_scsi_send_tmf_resp(io, 2520ef270ab1SKenneth D. Merry OCS_SCSI_TMF_FUNCTION_COMPLETE, 2521ef270ab1SKenneth D. Merry NULL, ocs_target_tmf_cb, NULL); 2522ef270ab1SKenneth D. Merry } 2523ef270ab1SKenneth D. Merry 2524ef270ab1SKenneth D. Merry ocs_set_ccb_status(ccb, CAM_REQ_CMP); 2525ef270ab1SKenneth D. Merry xpt_done(ccb); 2526ef270ab1SKenneth D. Merry break; 2527ef270ab1SKenneth D. Merry } 2528ef270ab1SKenneth D. Merry case XPT_CONT_TARGET_IO: /* continue target IO, sending data/response (a.k.a. CTIO) */ 2529ef270ab1SKenneth D. Merry if (ocs_target_io(ocs, ccb)) { 2530ef270ab1SKenneth D. Merry device_printf(ocs->dev, 2531ef270ab1SKenneth D. Merry "XPT_CONT_TARGET_IO failed flags=%x tag=%#x\n", 2532ef270ab1SKenneth D. Merry ccb->ccb_h.flags, ccb->csio.tag_id); 2533ef270ab1SKenneth D. Merry xpt_done(ccb); 2534ef270ab1SKenneth D. Merry } 2535ef270ab1SKenneth D. Merry break; 2536ef270ab1SKenneth D. Merry default: 2537ef270ab1SKenneth D. Merry device_printf(ocs->dev, "unhandled func_code = %#x\n", 2538ef270ab1SKenneth D. Merry ccb_h->func_code); 2539ef270ab1SKenneth D. Merry ccb_h->status = CAM_REQ_INVALID; 2540ef270ab1SKenneth D. Merry xpt_done(ccb); 2541ef270ab1SKenneth D. Merry break; 2542ef270ab1SKenneth D. Merry } 2543ef270ab1SKenneth D. Merry } 2544ef270ab1SKenneth D. Merry 2545ef270ab1SKenneth D. Merry /** 2546ef270ab1SKenneth D. Merry * @ingroup cam_api 2547ef270ab1SKenneth D. Merry * @brief Process events 2548ef270ab1SKenneth D. Merry * 2549ef270ab1SKenneth D. Merry * @param sim pointer to the SCSI Interface Module 2550ef270ab1SKenneth D. Merry * 2551ef270ab1SKenneth D. Merry */ 2552ef270ab1SKenneth D. Merry static void 2553ef270ab1SKenneth D. Merry ocs_poll(struct cam_sim *sim) 2554ef270ab1SKenneth D. Merry { 2555ef270ab1SKenneth D. Merry printf("%s\n", __func__); 2556ef270ab1SKenneth D. Merry } 2557ef270ab1SKenneth D. Merry 2558ef270ab1SKenneth D. Merry static int32_t 2559ef270ab1SKenneth D. Merry ocs_initiator_tmf_cb(ocs_io_t *io, ocs_scsi_io_status_e scsi_status, 2560ef270ab1SKenneth D. Merry ocs_scsi_cmd_resp_t *rsp, uint32_t flags, void *arg) 2561ef270ab1SKenneth D. Merry { 2562ef270ab1SKenneth D. Merry int32_t rc = 0; 2563ef270ab1SKenneth D. Merry 2564ef270ab1SKenneth D. Merry switch (scsi_status) { 2565ef270ab1SKenneth D. Merry case OCS_SCSI_STATUS_GOOD: 2566ef270ab1SKenneth D. Merry case OCS_SCSI_STATUS_NO_IO: 2567ef270ab1SKenneth D. Merry break; 2568ef270ab1SKenneth D. Merry case OCS_SCSI_STATUS_CHECK_RESPONSE: 2569ef270ab1SKenneth D. Merry if (rsp->response_data_length == 0) { 2570ef270ab1SKenneth D. Merry ocs_log_test(io->ocs, "check response without data?!?\n"); 2571ef270ab1SKenneth D. Merry rc = -1; 2572ef270ab1SKenneth D. Merry break; 2573ef270ab1SKenneth D. Merry } 2574ef270ab1SKenneth D. Merry 2575ef270ab1SKenneth D. Merry if (rsp->response_data[3] != 0) { 2576ef270ab1SKenneth D. Merry ocs_log_test(io->ocs, "TMF status %08x\n", 2577ef270ab1SKenneth D. Merry be32toh(*((uint32_t *)rsp->response_data))); 2578ef270ab1SKenneth D. Merry rc = -1; 2579ef270ab1SKenneth D. Merry break; 2580ef270ab1SKenneth D. Merry } 2581ef270ab1SKenneth D. Merry break; 2582ef270ab1SKenneth D. Merry default: 2583ef270ab1SKenneth D. Merry ocs_log_test(io->ocs, "status=%#x\n", scsi_status); 2584ef270ab1SKenneth D. Merry rc = -1; 2585ef270ab1SKenneth D. Merry } 2586ef270ab1SKenneth D. Merry 2587ef270ab1SKenneth D. Merry ocs_scsi_io_free(io); 2588ef270ab1SKenneth D. Merry 2589ef270ab1SKenneth D. Merry return rc; 2590ef270ab1SKenneth D. Merry } 2591ef270ab1SKenneth D. Merry 2592ef270ab1SKenneth D. Merry /** 2593ef270ab1SKenneth D. Merry * @brief lookup target resource structure 2594ef270ab1SKenneth D. Merry * 2595ef270ab1SKenneth D. Merry * Arbitrarily support 2596ef270ab1SKenneth D. Merry * - wildcard target ID + LU 2597ef270ab1SKenneth D. Merry * - 0 target ID + non-wildcard LU 2598ef270ab1SKenneth D. Merry * 2599ef270ab1SKenneth D. Merry * @param ocs the driver instance's software context 2600ef270ab1SKenneth D. Merry * @param ccb_h pointer to the CCB header 2601ef270ab1SKenneth D. Merry * @param status returned status value 2602ef270ab1SKenneth D. Merry * 2603ef270ab1SKenneth D. Merry * @return pointer to the target resource, NULL if none available (e.g. if LU 2604ef270ab1SKenneth D. Merry * is not enabled) 2605ef270ab1SKenneth D. Merry */ 2606ef270ab1SKenneth D. Merry static ocs_tgt_resource_t *ocs_tgt_resource_get(ocs_fcport *fcp, 2607ef270ab1SKenneth D. Merry struct ccb_hdr *ccb_h, uint32_t *status) 2608ef270ab1SKenneth D. Merry { 2609ef270ab1SKenneth D. Merry target_id_t tid = ccb_h->target_id; 2610ef270ab1SKenneth D. Merry lun_id_t lun = ccb_h->target_lun; 2611ef270ab1SKenneth D. Merry 2612ef270ab1SKenneth D. Merry if (CAM_TARGET_WILDCARD == tid) { 2613ef270ab1SKenneth D. Merry if (CAM_LUN_WILDCARD != lun) { 2614ef270ab1SKenneth D. Merry *status = CAM_LUN_INVALID; 2615ef270ab1SKenneth D. Merry return NULL; 2616ef270ab1SKenneth D. Merry } 2617ef270ab1SKenneth D. Merry return &fcp->targ_rsrc_wildcard; 2618ef270ab1SKenneth D. Merry } else { 2619ef270ab1SKenneth D. Merry if (lun < OCS_MAX_LUN) { 2620ef270ab1SKenneth D. Merry return &fcp->targ_rsrc[lun]; 2621ef270ab1SKenneth D. Merry } else { 2622ef270ab1SKenneth D. Merry *status = CAM_LUN_INVALID; 2623ef270ab1SKenneth D. Merry return NULL; 2624ef270ab1SKenneth D. Merry } 2625ef270ab1SKenneth D. Merry } 2626ef270ab1SKenneth D. Merry 2627ef270ab1SKenneth D. Merry } 2628ef270ab1SKenneth D. Merry 2629ef270ab1SKenneth D. Merry static int32_t 2630ef270ab1SKenneth D. Merry ocs_tgt_resource_abort(struct ocs_softc *ocs, ocs_tgt_resource_t *trsrc) 2631ef270ab1SKenneth D. Merry { 2632ef270ab1SKenneth D. Merry union ccb *ccb = NULL; 2633ef270ab1SKenneth D. Merry 2634ef270ab1SKenneth D. Merry do { 2635ef270ab1SKenneth D. Merry ccb = (union ccb *)STAILQ_FIRST(&trsrc->atio); 2636ef270ab1SKenneth D. Merry if (ccb) { 2637ef270ab1SKenneth D. Merry STAILQ_REMOVE_HEAD(&trsrc->atio, sim_links.stqe); 2638ef270ab1SKenneth D. Merry ccb->ccb_h.status = CAM_REQ_ABORTED; 2639ef270ab1SKenneth D. Merry xpt_done(ccb); 2640ef270ab1SKenneth D. Merry } 2641ef270ab1SKenneth D. Merry } while (ccb); 2642ef270ab1SKenneth D. Merry 2643ef270ab1SKenneth D. Merry do { 2644ef270ab1SKenneth D. Merry ccb = (union ccb *)STAILQ_FIRST(&trsrc->inot); 2645ef270ab1SKenneth D. Merry if (ccb) { 2646ef270ab1SKenneth D. Merry STAILQ_REMOVE_HEAD(&trsrc->inot, sim_links.stqe); 2647ef270ab1SKenneth D. Merry ccb->ccb_h.status = CAM_REQ_ABORTED; 2648ef270ab1SKenneth D. Merry xpt_done(ccb); 2649ef270ab1SKenneth D. Merry } 2650ef270ab1SKenneth D. Merry } while (ccb); 2651ef270ab1SKenneth D. Merry 2652ef270ab1SKenneth D. Merry return 0; 2653ef270ab1SKenneth D. Merry } 2654ef270ab1SKenneth D. Merry 2655ef270ab1SKenneth D. Merry static void 2656ef270ab1SKenneth D. Merry ocs_abort_atio(struct ocs_softc *ocs, union ccb *ccb) 2657ef270ab1SKenneth D. Merry { 2658ef270ab1SKenneth D. Merry 2659ef270ab1SKenneth D. Merry ocs_io_t *aio = NULL; 2660ef270ab1SKenneth D. Merry ocs_tgt_resource_t *trsrc = NULL; 2661ef270ab1SKenneth D. Merry uint32_t status = CAM_REQ_INVALID; 2662ef270ab1SKenneth D. Merry struct ccb_hdr *cur = NULL; 2663ef270ab1SKenneth D. Merry union ccb *accb = ccb->cab.abort_ccb; 2664ef270ab1SKenneth D. Merry 2665ef270ab1SKenneth D. Merry int bus = cam_sim_bus(xpt_path_sim((ccb)->ccb_h.path)); 2666ef270ab1SKenneth D. Merry ocs_fcport *fcp = FCPORT(ocs, bus); 2667ef270ab1SKenneth D. Merry 2668ef270ab1SKenneth D. Merry trsrc = ocs_tgt_resource_get(fcp, &accb->ccb_h, &status); 2669ef270ab1SKenneth D. Merry if (trsrc != NULL) { 2670ef270ab1SKenneth D. Merry STAILQ_FOREACH(cur, &trsrc->atio, sim_links.stqe) { 2671ef270ab1SKenneth D. Merry if (cur != &accb->ccb_h) 2672ef270ab1SKenneth D. Merry continue; 2673ef270ab1SKenneth D. Merry 2674ef270ab1SKenneth D. Merry STAILQ_REMOVE(&trsrc->atio, cur, ccb_hdr, 2675ef270ab1SKenneth D. Merry sim_links.stqe); 2676ef270ab1SKenneth D. Merry accb->ccb_h.status = CAM_REQ_ABORTED; 2677ef270ab1SKenneth D. Merry xpt_done(accb); 2678ef270ab1SKenneth D. Merry ocs_set_ccb_status(ccb, CAM_REQ_CMP); 2679ef270ab1SKenneth D. Merry return; 2680ef270ab1SKenneth D. Merry } 2681ef270ab1SKenneth D. Merry } 2682ef270ab1SKenneth D. Merry 2683ef270ab1SKenneth D. Merry /* if the ATIO has a valid IO pointer, CAM is telling 2684ef270ab1SKenneth D. Merry * the driver that the ATIO (which represents the entire 2685ef270ab1SKenneth D. Merry * exchange) has been aborted. */ 2686ef270ab1SKenneth D. Merry 2687ef270ab1SKenneth D. Merry aio = accb->ccb_h.ccb_io_ptr; 2688ef270ab1SKenneth D. Merry if (aio == NULL) { 2689ef270ab1SKenneth D. Merry ccb->ccb_h.status = CAM_UA_ABORT; 2690ef270ab1SKenneth D. Merry return; 2691ef270ab1SKenneth D. Merry } 2692ef270ab1SKenneth D. Merry 2693ef270ab1SKenneth D. Merry device_printf(ocs->dev, 2694ef270ab1SKenneth D. Merry "%s: XPT_ABORT ATIO state=%d tag=%#x" 2695ef270ab1SKenneth D. Merry " xid=%#x flags=%#x\n", __func__, 2696ef270ab1SKenneth D. Merry aio->tgt_io.state, aio->tag, 2697ef270ab1SKenneth D. Merry aio->init_task_tag, aio->tgt_io.flags); 2698ef270ab1SKenneth D. Merry /* Expectations are: 2699ef270ab1SKenneth D. Merry * - abort task was received 2700ef270ab1SKenneth D. Merry * - already aborted IO in the DEVICE 2701ef270ab1SKenneth D. Merry * - already received NOTIFY ACKNOWLEDGE */ 2702ef270ab1SKenneth D. Merry 2703ef270ab1SKenneth D. Merry if ((aio->tgt_io.flags & OCS_CAM_IO_F_ABORT_RECV) == 0) { 2704ef270ab1SKenneth D. Merry device_printf(ocs->dev, "%s: abort not received or io completed \n", __func__); 2705ef270ab1SKenneth D. Merry ocs_set_ccb_status(ccb, CAM_REQ_CMP); 2706ef270ab1SKenneth D. Merry return; 2707ef270ab1SKenneth D. Merry } 2708ef270ab1SKenneth D. Merry 2709ef270ab1SKenneth D. Merry aio->tgt_io.flags |= OCS_CAM_IO_F_ABORT_CAM; 2710ef270ab1SKenneth D. Merry ocs_target_io_free(aio); 2711ef270ab1SKenneth D. Merry ocs_set_ccb_status(ccb, CAM_REQ_CMP); 2712ef270ab1SKenneth D. Merry 2713ef270ab1SKenneth D. Merry return; 2714ef270ab1SKenneth D. Merry } 2715ef270ab1SKenneth D. Merry 2716ef270ab1SKenneth D. Merry static void 2717ef270ab1SKenneth D. Merry ocs_abort_inot(struct ocs_softc *ocs, union ccb *ccb) 2718ef270ab1SKenneth D. Merry { 2719ef270ab1SKenneth D. Merry ocs_tgt_resource_t *trsrc = NULL; 2720ef270ab1SKenneth D. Merry uint32_t status = CAM_REQ_INVALID; 2721ef270ab1SKenneth D. Merry struct ccb_hdr *cur = NULL; 2722ef270ab1SKenneth D. Merry union ccb *accb = ccb->cab.abort_ccb; 2723ef270ab1SKenneth D. Merry 2724ef270ab1SKenneth D. Merry int bus = cam_sim_bus(xpt_path_sim((ccb)->ccb_h.path)); 2725ef270ab1SKenneth D. Merry ocs_fcport *fcp = FCPORT(ocs, bus); 2726ef270ab1SKenneth D. Merry 2727ef270ab1SKenneth D. Merry trsrc = ocs_tgt_resource_get(fcp, &accb->ccb_h, &status); 2728ef270ab1SKenneth D. Merry if (trsrc) { 2729ef270ab1SKenneth D. Merry STAILQ_FOREACH(cur, &trsrc->inot, sim_links.stqe) { 2730ef270ab1SKenneth D. Merry if (cur != &accb->ccb_h) 2731ef270ab1SKenneth D. Merry continue; 2732ef270ab1SKenneth D. Merry 2733ef270ab1SKenneth D. Merry STAILQ_REMOVE(&trsrc->inot, cur, ccb_hdr, 2734ef270ab1SKenneth D. Merry sim_links.stqe); 2735ef270ab1SKenneth D. Merry accb->ccb_h.status = CAM_REQ_ABORTED; 2736ef270ab1SKenneth D. Merry xpt_done(accb); 2737ef270ab1SKenneth D. Merry ocs_set_ccb_status(ccb, CAM_REQ_CMP); 2738ef270ab1SKenneth D. Merry return; 2739ef270ab1SKenneth D. Merry } 2740ef270ab1SKenneth D. Merry } 2741ef270ab1SKenneth D. Merry 2742ef270ab1SKenneth D. Merry ocs_set_ccb_status(ccb, CAM_UA_ABORT); 2743ef270ab1SKenneth D. Merry return; 2744ef270ab1SKenneth D. Merry } 2745ef270ab1SKenneth D. Merry 2746ef270ab1SKenneth D. Merry static uint32_t 2747ef270ab1SKenneth D. Merry ocs_abort_initiator_io(struct ocs_softc *ocs, union ccb *accb) 2748ef270ab1SKenneth D. Merry { 2749ef270ab1SKenneth D. Merry 2750ef270ab1SKenneth D. Merry ocs_node_t *node = NULL; 2751ef270ab1SKenneth D. Merry ocs_io_t *io = NULL; 2752ef270ab1SKenneth D. Merry int32_t rc = 0; 2753ef270ab1SKenneth D. Merry struct ccb_scsiio *csio = &accb->csio; 2754ef270ab1SKenneth D. Merry 27556affb8ebSRam Kishore Vegesna ocs_fcport *fcp = FCPORT(ocs, cam_sim_bus(xpt_path_sim((accb)->ccb_h.path))); 27566affb8ebSRam Kishore Vegesna node = ocs_node_get_instance(ocs, fcp->tgt[accb->ccb_h.target_id].node_id); 2757ef270ab1SKenneth D. Merry if (node == NULL) { 2758ef270ab1SKenneth D. Merry device_printf(ocs->dev, "%s: no device %d\n", 2759ef270ab1SKenneth D. Merry __func__, accb->ccb_h.target_id); 2760ef270ab1SKenneth D. Merry ocs_set_ccb_status(accb, CAM_DEV_NOT_THERE); 2761ef270ab1SKenneth D. Merry xpt_done(accb); 2762ef270ab1SKenneth D. Merry return (-1); 2763ef270ab1SKenneth D. Merry } 2764ef270ab1SKenneth D. Merry 2765ef270ab1SKenneth D. Merry io = ocs_scsi_io_alloc(node, OCS_SCSI_IO_ROLE_ORIGINATOR); 2766ef270ab1SKenneth D. Merry if (io == NULL) { 2767ef270ab1SKenneth D. Merry device_printf(ocs->dev, 2768ef270ab1SKenneth D. Merry "%s: unable to alloc IO\n", __func__); 2769ef270ab1SKenneth D. Merry ocs_set_ccb_status(accb, CAM_REQ_CMP_ERR); 2770ef270ab1SKenneth D. Merry xpt_done(accb); 2771ef270ab1SKenneth D. Merry return (-1); 2772ef270ab1SKenneth D. Merry } 2773ef270ab1SKenneth D. Merry 2774ef270ab1SKenneth D. Merry rc = ocs_scsi_send_tmf(node, io, 2775ef270ab1SKenneth D. Merry (ocs_io_t *)csio->ccb_h.ccb_io_ptr, 2776ef270ab1SKenneth D. Merry accb->ccb_h.target_lun, 2777ef270ab1SKenneth D. Merry OCS_SCSI_TMF_ABORT_TASK, 2778ef270ab1SKenneth D. Merry NULL, 0, 0, 2779ef270ab1SKenneth D. Merry ocs_initiator_tmf_cb, NULL/*arg*/); 2780ef270ab1SKenneth D. Merry 2781ef270ab1SKenneth D. Merry return rc; 2782ef270ab1SKenneth D. Merry } 2783ef270ab1SKenneth D. Merry 2784ef270ab1SKenneth D. Merry void 2785ef270ab1SKenneth D. Merry ocs_scsi_ini_ddump(ocs_textbuf_t *textbuf, ocs_scsi_ddump_type_e type, void *obj) 2786ef270ab1SKenneth D. Merry { 2787ef270ab1SKenneth D. Merry switch(type) { 2788ef270ab1SKenneth D. Merry case OCS_SCSI_DDUMP_DEVICE: { 2789ef270ab1SKenneth D. Merry //ocs_t *ocs = obj; 2790ef270ab1SKenneth D. Merry break; 2791ef270ab1SKenneth D. Merry } 2792ef270ab1SKenneth D. Merry case OCS_SCSI_DDUMP_DOMAIN: { 2793ef270ab1SKenneth D. Merry //ocs_domain_t *domain = obj; 2794ef270ab1SKenneth D. Merry break; 2795ef270ab1SKenneth D. Merry } 2796ef270ab1SKenneth D. Merry case OCS_SCSI_DDUMP_SPORT: { 2797ef270ab1SKenneth D. Merry //ocs_sport_t *sport = obj; 2798ef270ab1SKenneth D. Merry break; 2799ef270ab1SKenneth D. Merry } 2800ef270ab1SKenneth D. Merry case OCS_SCSI_DDUMP_NODE: { 2801ef270ab1SKenneth D. Merry //ocs_node_t *node = obj; 2802ef270ab1SKenneth D. Merry break; 2803ef270ab1SKenneth D. Merry } 2804ef270ab1SKenneth D. Merry case OCS_SCSI_DDUMP_IO: { 2805ef270ab1SKenneth D. Merry //ocs_io_t *io = obj; 2806ef270ab1SKenneth D. Merry break; 2807ef270ab1SKenneth D. Merry } 2808ef270ab1SKenneth D. Merry default: { 2809ef270ab1SKenneth D. Merry break; 2810ef270ab1SKenneth D. Merry } 2811ef270ab1SKenneth D. Merry } 2812ef270ab1SKenneth D. Merry } 2813ef270ab1SKenneth D. Merry 2814ef270ab1SKenneth D. Merry void 2815ef270ab1SKenneth D. Merry ocs_scsi_tgt_ddump(ocs_textbuf_t *textbuf, ocs_scsi_ddump_type_e type, void *obj) 2816ef270ab1SKenneth D. Merry { 2817ef270ab1SKenneth D. Merry switch(type) { 2818ef270ab1SKenneth D. Merry case OCS_SCSI_DDUMP_DEVICE: { 2819ef270ab1SKenneth D. Merry //ocs_t *ocs = obj; 2820ef270ab1SKenneth D. Merry break; 2821ef270ab1SKenneth D. Merry } 2822ef270ab1SKenneth D. Merry case OCS_SCSI_DDUMP_DOMAIN: { 2823ef270ab1SKenneth D. Merry //ocs_domain_t *domain = obj; 2824ef270ab1SKenneth D. Merry break; 2825ef270ab1SKenneth D. Merry } 2826ef270ab1SKenneth D. Merry case OCS_SCSI_DDUMP_SPORT: { 2827ef270ab1SKenneth D. Merry //ocs_sport_t *sport = obj; 2828ef270ab1SKenneth D. Merry break; 2829ef270ab1SKenneth D. Merry } 2830ef270ab1SKenneth D. Merry case OCS_SCSI_DDUMP_NODE: { 2831ef270ab1SKenneth D. Merry //ocs_node_t *node = obj; 2832ef270ab1SKenneth D. Merry break; 2833ef270ab1SKenneth D. Merry } 2834ef270ab1SKenneth D. Merry case OCS_SCSI_DDUMP_IO: { 2835ef270ab1SKenneth D. Merry ocs_io_t *io = obj; 2836ef270ab1SKenneth D. Merry char *state_str = NULL; 2837ef270ab1SKenneth D. Merry 2838ef270ab1SKenneth D. Merry switch (io->tgt_io.state) { 2839ef270ab1SKenneth D. Merry case OCS_CAM_IO_FREE: 2840ef270ab1SKenneth D. Merry state_str = "FREE"; 2841ef270ab1SKenneth D. Merry break; 2842ef270ab1SKenneth D. Merry case OCS_CAM_IO_COMMAND: 2843ef270ab1SKenneth D. Merry state_str = "COMMAND"; 2844ef270ab1SKenneth D. Merry break; 2845ef270ab1SKenneth D. Merry case OCS_CAM_IO_DATA: 2846ef270ab1SKenneth D. Merry state_str = "DATA"; 2847ef270ab1SKenneth D. Merry break; 2848ef270ab1SKenneth D. Merry case OCS_CAM_IO_DATA_DONE: 2849ef270ab1SKenneth D. Merry state_str = "DATA_DONE"; 2850ef270ab1SKenneth D. Merry break; 2851ef270ab1SKenneth D. Merry case OCS_CAM_IO_RESP: 2852ef270ab1SKenneth D. Merry state_str = "RESP"; 2853ef270ab1SKenneth D. Merry break; 2854ef270ab1SKenneth D. Merry default: 2855ef270ab1SKenneth D. Merry state_str = "xxx BAD xxx"; 2856ef270ab1SKenneth D. Merry } 2857ef270ab1SKenneth D. Merry ocs_ddump_value(textbuf, "cam_st", "%s", state_str); 2858ef270ab1SKenneth D. Merry if (io->tgt_io.app) { 2859ef270ab1SKenneth D. Merry ocs_ddump_value(textbuf, "cam_flags", "%#x", 2860ef270ab1SKenneth D. Merry ((union ccb *)(io->tgt_io.app))->ccb_h.flags); 2861ef270ab1SKenneth D. Merry ocs_ddump_value(textbuf, "cam_status", "%#x", 2862ef270ab1SKenneth D. Merry ((union ccb *)(io->tgt_io.app))->ccb_h.status); 2863ef270ab1SKenneth D. Merry } 2864ef270ab1SKenneth D. Merry 2865ef270ab1SKenneth D. Merry break; 2866ef270ab1SKenneth D. Merry } 2867ef270ab1SKenneth D. Merry default: { 2868ef270ab1SKenneth D. Merry break; 2869ef270ab1SKenneth D. Merry } 2870ef270ab1SKenneth D. Merry } 2871ef270ab1SKenneth D. Merry } 2872ef270ab1SKenneth D. Merry 2873ef270ab1SKenneth D. Merry int32_t ocs_scsi_get_block_vaddr(ocs_io_t *io, uint64_t blocknumber, 2874ef270ab1SKenneth D. Merry ocs_scsi_vaddr_len_t addrlen[], 2875ef270ab1SKenneth D. Merry uint32_t max_addrlen, void **dif_vaddr) 2876ef270ab1SKenneth D. Merry { 2877ef270ab1SKenneth D. Merry return -1; 2878ef270ab1SKenneth D. Merry } 2879ef270ab1SKenneth D. Merry 2880ef270ab1SKenneth D. Merry uint32_t 2881ef270ab1SKenneth D. Merry ocs_get_crn(ocs_node_t *node, uint8_t *crn, uint64_t lun) 2882ef270ab1SKenneth D. Merry { 2883ef270ab1SKenneth D. Merry uint32_t idx; 2884ef270ab1SKenneth D. Merry struct ocs_lun_crn *lcrn = NULL; 2885ef270ab1SKenneth D. Merry idx = lun % OCS_MAX_LUN; 2886ef270ab1SKenneth D. Merry 2887ef270ab1SKenneth D. Merry lcrn = node->ini_node.lun_crn[idx]; 2888ef270ab1SKenneth D. Merry 2889ef270ab1SKenneth D. Merry if (lcrn == NULL) { 2890ef270ab1SKenneth D. Merry lcrn = ocs_malloc(node->ocs, sizeof(struct ocs_lun_crn), 2891ef270ab1SKenneth D. Merry M_ZERO|M_NOWAIT); 2892ef270ab1SKenneth D. Merry if (lcrn == NULL) { 2893ef270ab1SKenneth D. Merry return (1); 2894ef270ab1SKenneth D. Merry } 2895ef270ab1SKenneth D. Merry 2896ef270ab1SKenneth D. Merry lcrn->lun = lun; 2897ef270ab1SKenneth D. Merry node->ini_node.lun_crn[idx] = lcrn; 2898ef270ab1SKenneth D. Merry } 2899ef270ab1SKenneth D. Merry 2900ef270ab1SKenneth D. Merry if (lcrn->lun != lun) { 2901ef270ab1SKenneth D. Merry return (1); 2902ef270ab1SKenneth D. Merry } 2903ef270ab1SKenneth D. Merry 2904ef270ab1SKenneth D. Merry if (lcrn->crnseed == 0) 2905ef270ab1SKenneth D. Merry lcrn->crnseed = 1; 2906ef270ab1SKenneth D. Merry 2907ef270ab1SKenneth D. Merry *crn = lcrn->crnseed++; 2908ef270ab1SKenneth D. Merry return (0); 2909ef270ab1SKenneth D. Merry } 2910ef270ab1SKenneth D. Merry 2911ef270ab1SKenneth D. Merry void 2912ef270ab1SKenneth D. Merry ocs_del_crn(ocs_node_t *node) 2913ef270ab1SKenneth D. Merry { 2914ef270ab1SKenneth D. Merry uint32_t i; 2915ef270ab1SKenneth D. Merry struct ocs_lun_crn *lcrn = NULL; 2916ef270ab1SKenneth D. Merry 2917ef270ab1SKenneth D. Merry for(i = 0; i < OCS_MAX_LUN; i++) { 2918ef270ab1SKenneth D. Merry lcrn = node->ini_node.lun_crn[i]; 2919ef270ab1SKenneth D. Merry if (lcrn) { 2920ef270ab1SKenneth D. Merry ocs_free(node->ocs, lcrn, sizeof(*lcrn)); 2921ef270ab1SKenneth D. Merry } 2922ef270ab1SKenneth D. Merry } 2923ef270ab1SKenneth D. Merry 2924ef270ab1SKenneth D. Merry return; 2925ef270ab1SKenneth D. Merry } 2926ef270ab1SKenneth D. Merry 2927ef270ab1SKenneth D. Merry void 2928ef270ab1SKenneth D. Merry ocs_reset_crn(ocs_node_t *node, uint64_t lun) 2929ef270ab1SKenneth D. Merry { 2930ef270ab1SKenneth D. Merry uint32_t idx; 2931ef270ab1SKenneth D. Merry struct ocs_lun_crn *lcrn = NULL; 2932ef270ab1SKenneth D. Merry idx = lun % OCS_MAX_LUN; 2933ef270ab1SKenneth D. Merry 2934ef270ab1SKenneth D. Merry lcrn = node->ini_node.lun_crn[idx]; 2935ef270ab1SKenneth D. Merry if (lcrn) 2936ef270ab1SKenneth D. Merry lcrn->crnseed = 0; 2937ef270ab1SKenneth D. Merry 2938ef270ab1SKenneth D. Merry return; 2939ef270ab1SKenneth D. Merry } 2940