1*665484d8SDoug Ambrisko /* 2*665484d8SDoug Ambrisko * Copyright (c) 2014, LSI Corp. 3*665484d8SDoug Ambrisko * All rights reserved. 4*665484d8SDoug Ambrisko * Author: Marian Choy 5*665484d8SDoug Ambrisko * Support: freebsdraid@lsi.com 6*665484d8SDoug Ambrisko * 7*665484d8SDoug Ambrisko * Redistribution and use in source and binary forms, with or without 8*665484d8SDoug Ambrisko * modification, are permitted provided that the following conditions 9*665484d8SDoug Ambrisko * are met: 10*665484d8SDoug Ambrisko * 11*665484d8SDoug Ambrisko * 1. Redistributions of source code must retain the above copyright 12*665484d8SDoug Ambrisko * notice, this list of conditions and the following disclaimer. 13*665484d8SDoug Ambrisko * 2. Redistributions in binary form must reproduce the above copyright 14*665484d8SDoug Ambrisko * notice, this list of conditions and the following disclaimer in 15*665484d8SDoug Ambrisko * the documentation and/or other materials provided with the 16*665484d8SDoug Ambrisko * distribution. 17*665484d8SDoug Ambrisko * 3. Neither the name of the <ORGANIZATION> nor the names of its 18*665484d8SDoug Ambrisko * contributors may be used to endorse or promote products derived 19*665484d8SDoug Ambrisko * from this software without specific prior written permission. 20*665484d8SDoug Ambrisko * 21*665484d8SDoug Ambrisko * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22*665484d8SDoug Ambrisko * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23*665484d8SDoug Ambrisko * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24*665484d8SDoug Ambrisko * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25*665484d8SDoug Ambrisko * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26*665484d8SDoug Ambrisko * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 27*665484d8SDoug Ambrisko * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28*665484d8SDoug Ambrisko * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 29*665484d8SDoug Ambrisko * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30*665484d8SDoug Ambrisko * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 31*665484d8SDoug Ambrisko * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32*665484d8SDoug Ambrisko * POSSIBILITY OF SUCH DAMAGE. 33*665484d8SDoug Ambrisko * 34*665484d8SDoug Ambrisko */ 35*665484d8SDoug Ambrisko 36*665484d8SDoug Ambrisko #include <sys/cdefs.h> 37*665484d8SDoug Ambrisko __FBSDID("$FreeBSD$"); 38*665484d8SDoug Ambrisko 39*665484d8SDoug Ambrisko #include "dev/mrsas/mrsas.h" 40*665484d8SDoug Ambrisko 41*665484d8SDoug Ambrisko #include <cam/cam.h> 42*665484d8SDoug Ambrisko #include <cam/cam_ccb.h> 43*665484d8SDoug Ambrisko #include <cam/cam_sim.h> 44*665484d8SDoug Ambrisko #include <cam/cam_xpt_sim.h> 45*665484d8SDoug Ambrisko #include <cam/cam_debug.h> 46*665484d8SDoug Ambrisko #include <cam/cam_periph.h> 47*665484d8SDoug Ambrisko #include <cam/cam_xpt_periph.h> 48*665484d8SDoug Ambrisko 49*665484d8SDoug Ambrisko #include <cam/scsi/scsi_all.h> 50*665484d8SDoug Ambrisko #include <cam/scsi/scsi_message.h> 51*665484d8SDoug Ambrisko #include <sys/taskqueue.h> 52*665484d8SDoug Ambrisko 53*665484d8SDoug Ambrisko 54*665484d8SDoug Ambrisko /* 55*665484d8SDoug Ambrisko * Function prototypes 56*665484d8SDoug Ambrisko */ 57*665484d8SDoug Ambrisko int mrsas_cam_attach(struct mrsas_softc *sc); 58*665484d8SDoug Ambrisko //int mrsas_ldio_inq(union ccb *ccb); 59*665484d8SDoug Ambrisko int mrsas_ldio_inq(struct cam_sim *sim, union ccb *ccb); 60*665484d8SDoug Ambrisko int mrsas_bus_scan(struct mrsas_softc *sc); 61*665484d8SDoug Ambrisko int mrsas_bus_scan_sim(struct mrsas_softc *sc, struct cam_sim *sim); 62*665484d8SDoug Ambrisko int mrsas_map_request(struct mrsas_softc *sc, struct mrsas_mpt_cmd *cmd); 63*665484d8SDoug Ambrisko int mrsas_build_ldio(struct mrsas_softc *sc, struct mrsas_mpt_cmd *cmd, 64*665484d8SDoug Ambrisko union ccb *ccb); 65*665484d8SDoug Ambrisko int mrsas_build_dcdb(struct mrsas_softc *sc, struct mrsas_mpt_cmd *cmd, 66*665484d8SDoug Ambrisko union ccb *ccb, struct cam_sim *sim); 67*665484d8SDoug Ambrisko int mrsas_setup_io(struct mrsas_softc *sc, struct mrsas_mpt_cmd *cmd, 68*665484d8SDoug Ambrisko union ccb *ccb, u_int32_t device_id, 69*665484d8SDoug Ambrisko MRSAS_RAID_SCSI_IO_REQUEST *io_request); 70*665484d8SDoug Ambrisko void mrsas_xpt_freeze(struct mrsas_softc *sc); 71*665484d8SDoug Ambrisko void mrsas_xpt_release(struct mrsas_softc *sc); 72*665484d8SDoug Ambrisko void mrsas_cam_detach(struct mrsas_softc *sc); 73*665484d8SDoug Ambrisko void mrsas_release_mpt_cmd(struct mrsas_mpt_cmd *cmd); 74*665484d8SDoug Ambrisko void mrsas_unmap_request(struct mrsas_softc *sc, struct mrsas_mpt_cmd *cmd); 75*665484d8SDoug Ambrisko void mrsas_cmd_done(struct mrsas_softc *sc, struct mrsas_mpt_cmd *cmd); 76*665484d8SDoug Ambrisko void mrsas_fire_cmd(struct mrsas_softc *sc, u_int32_t req_desc_lo, 77*665484d8SDoug Ambrisko u_int32_t req_desc_hi); 78*665484d8SDoug Ambrisko void mrsas_set_pd_lba(MRSAS_RAID_SCSI_IO_REQUEST *io_request, u_int8_t cdb_len, 79*665484d8SDoug Ambrisko struct IO_REQUEST_INFO *io_info, union ccb *ccb, 80*665484d8SDoug Ambrisko MR_FW_RAID_MAP_ALL *local_map_ptr, u_int32_t ref_tag, 81*665484d8SDoug Ambrisko u_int32_t ld_block_size); 82*665484d8SDoug Ambrisko static void mrsas_freeze_simq(struct mrsas_mpt_cmd *cmd, struct cam_sim *sim); 83*665484d8SDoug Ambrisko static void mrsas_poll(struct cam_sim *sim); 84*665484d8SDoug Ambrisko static void mrsas_action(struct cam_sim *sim, union ccb *ccb); 85*665484d8SDoug Ambrisko static void mrsas_scsiio_timeout(void *data); 86*665484d8SDoug Ambrisko static void mrsas_data_load_cb(void *arg, bus_dma_segment_t *segs, 87*665484d8SDoug Ambrisko int nseg, int error); 88*665484d8SDoug Ambrisko static int32_t mrsas_startio(struct mrsas_softc *sc, struct cam_sim *sim, 89*665484d8SDoug Ambrisko union ccb *ccb); 90*665484d8SDoug Ambrisko struct mrsas_mpt_cmd * mrsas_get_mpt_cmd(struct mrsas_softc *sc); 91*665484d8SDoug Ambrisko MRSAS_REQUEST_DESCRIPTOR_UNION *mrsas_get_request_desc(struct mrsas_softc *sc, 92*665484d8SDoug Ambrisko u_int16_t index); 93*665484d8SDoug Ambrisko 94*665484d8SDoug Ambrisko extern u_int16_t MR_TargetIdToLdGet(u_int32_t ldTgtId, MR_FW_RAID_MAP_ALL *map); 95*665484d8SDoug Ambrisko extern u_int32_t MR_LdBlockSizeGet(u_int32_t ldTgtId, MR_FW_RAID_MAP_ALL *map, 96*665484d8SDoug Ambrisko struct mrsas_softc *sc); 97*665484d8SDoug Ambrisko extern void mrsas_isr(void *arg); 98*665484d8SDoug Ambrisko extern void mrsas_aen_handler(struct mrsas_softc *sc); 99*665484d8SDoug Ambrisko extern u_int8_t MR_BuildRaidContext(struct mrsas_softc *sc, 100*665484d8SDoug Ambrisko struct IO_REQUEST_INFO *io_info,RAID_CONTEXT *pRAID_Context, 101*665484d8SDoug Ambrisko MR_FW_RAID_MAP_ALL *map); 102*665484d8SDoug Ambrisko extern u_int16_t MR_LdSpanArrayGet(u_int32_t ld, u_int32_t span, 103*665484d8SDoug Ambrisko MR_FW_RAID_MAP_ALL *map); 104*665484d8SDoug Ambrisko extern u_int16_t mrsas_get_updated_dev_handle(PLD_LOAD_BALANCE_INFO lbInfo, 105*665484d8SDoug Ambrisko struct IO_REQUEST_INFO *io_info); 106*665484d8SDoug Ambrisko extern u_int8_t megasas_get_best_arm(PLD_LOAD_BALANCE_INFO lbInfo, u_int8_t arm, 107*665484d8SDoug Ambrisko u_int64_t block, u_int32_t count); 108*665484d8SDoug Ambrisko 109*665484d8SDoug Ambrisko 110*665484d8SDoug Ambrisko /** 111*665484d8SDoug Ambrisko * mrsas_cam_attach: Main entry to CAM subsystem 112*665484d8SDoug Ambrisko * input: Adapter instance soft state 113*665484d8SDoug Ambrisko * 114*665484d8SDoug Ambrisko * This function is called from mrsas_attach() during initialization 115*665484d8SDoug Ambrisko * to perform SIM allocations and XPT bus registration. If the kernel 116*665484d8SDoug Ambrisko * version is 7.4 or earlier, it would also initiate a bus scan. 117*665484d8SDoug Ambrisko */ 118*665484d8SDoug Ambrisko int mrsas_cam_attach(struct mrsas_softc *sc) 119*665484d8SDoug Ambrisko { 120*665484d8SDoug Ambrisko struct cam_devq *devq; 121*665484d8SDoug Ambrisko int mrsas_cam_depth; 122*665484d8SDoug Ambrisko 123*665484d8SDoug Ambrisko mrsas_cam_depth = sc->max_fw_cmds - MRSAS_INTERNAL_CMDS; 124*665484d8SDoug Ambrisko 125*665484d8SDoug Ambrisko if ((devq = cam_simq_alloc(mrsas_cam_depth)) == NULL) { 126*665484d8SDoug Ambrisko device_printf(sc->mrsas_dev, "Cannot allocate SIM queue\n"); 127*665484d8SDoug Ambrisko return(ENOMEM); 128*665484d8SDoug Ambrisko } 129*665484d8SDoug Ambrisko 130*665484d8SDoug Ambrisko 131*665484d8SDoug Ambrisko /* 132*665484d8SDoug Ambrisko * Create SIM for bus 0 and register, also create path 133*665484d8SDoug Ambrisko */ 134*665484d8SDoug Ambrisko sc->sim_0 = cam_sim_alloc(mrsas_action, mrsas_poll, "mrsas", sc, 135*665484d8SDoug Ambrisko device_get_unit(sc->mrsas_dev), &sc->sim_lock, mrsas_cam_depth, 136*665484d8SDoug Ambrisko mrsas_cam_depth, devq); 137*665484d8SDoug Ambrisko if (sc->sim_0 == NULL){ 138*665484d8SDoug Ambrisko cam_simq_free(devq); 139*665484d8SDoug Ambrisko device_printf(sc->mrsas_dev, "Cannot register SIM\n"); 140*665484d8SDoug Ambrisko return(ENXIO); 141*665484d8SDoug Ambrisko } 142*665484d8SDoug Ambrisko /* Initialize taskqueue for Event Handling */ 143*665484d8SDoug Ambrisko TASK_INIT(&sc->ev_task, 0, (void *)mrsas_aen_handler, sc); 144*665484d8SDoug Ambrisko sc->ev_tq = taskqueue_create("mrsas_taskq", M_NOWAIT | M_ZERO, 145*665484d8SDoug Ambrisko taskqueue_thread_enqueue, &sc->ev_tq); 146*665484d8SDoug Ambrisko 147*665484d8SDoug Ambrisko /* Run the task queue with lowest priority */ 148*665484d8SDoug Ambrisko taskqueue_start_threads(&sc->ev_tq, 1, 255, "%s taskq", 149*665484d8SDoug Ambrisko device_get_nameunit(sc->mrsas_dev)); 150*665484d8SDoug Ambrisko mtx_lock(&sc->sim_lock); 151*665484d8SDoug Ambrisko if (xpt_bus_register(sc->sim_0, sc->mrsas_dev,0) != CAM_SUCCESS) 152*665484d8SDoug Ambrisko { 153*665484d8SDoug Ambrisko cam_sim_free(sc->sim_0, TRUE); // passing true frees the devq 154*665484d8SDoug Ambrisko mtx_unlock(&sc->sim_lock); 155*665484d8SDoug Ambrisko return(ENXIO); 156*665484d8SDoug Ambrisko } 157*665484d8SDoug Ambrisko if (xpt_create_path(&sc->path_0, NULL, cam_sim_path(sc->sim_0), 158*665484d8SDoug Ambrisko CAM_TARGET_WILDCARD, 159*665484d8SDoug Ambrisko CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 160*665484d8SDoug Ambrisko xpt_bus_deregister(cam_sim_path(sc->sim_0)); 161*665484d8SDoug Ambrisko cam_sim_free(sc->sim_0, TRUE); // passing true will free the devq 162*665484d8SDoug Ambrisko mtx_unlock(&sc->sim_lock); 163*665484d8SDoug Ambrisko return(ENXIO); 164*665484d8SDoug Ambrisko } 165*665484d8SDoug Ambrisko mtx_unlock(&sc->sim_lock); 166*665484d8SDoug Ambrisko 167*665484d8SDoug Ambrisko /* 168*665484d8SDoug Ambrisko * Create SIM for bus 1 and register, also create path 169*665484d8SDoug Ambrisko */ 170*665484d8SDoug Ambrisko sc->sim_1 = cam_sim_alloc(mrsas_action, mrsas_poll, "mrsas", sc, 171*665484d8SDoug Ambrisko device_get_unit(sc->mrsas_dev), &sc->sim_lock, mrsas_cam_depth, 172*665484d8SDoug Ambrisko mrsas_cam_depth, devq); 173*665484d8SDoug Ambrisko if (sc->sim_1 == NULL){ 174*665484d8SDoug Ambrisko cam_simq_free(devq); 175*665484d8SDoug Ambrisko device_printf(sc->mrsas_dev, "Cannot register SIM\n"); 176*665484d8SDoug Ambrisko return(ENXIO); 177*665484d8SDoug Ambrisko } 178*665484d8SDoug Ambrisko 179*665484d8SDoug Ambrisko mtx_lock(&sc->sim_lock); 180*665484d8SDoug Ambrisko if (xpt_bus_register(sc->sim_1, sc->mrsas_dev, 1) != CAM_SUCCESS){ 181*665484d8SDoug Ambrisko cam_sim_free(sc->sim_1, TRUE); // passing true frees the devq 182*665484d8SDoug Ambrisko mtx_unlock(&sc->sim_lock); 183*665484d8SDoug Ambrisko return(ENXIO); 184*665484d8SDoug Ambrisko } 185*665484d8SDoug Ambrisko if (xpt_create_path(&sc->path_1, NULL, cam_sim_path(sc->sim_1), 186*665484d8SDoug Ambrisko CAM_TARGET_WILDCARD, 187*665484d8SDoug Ambrisko CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 188*665484d8SDoug Ambrisko xpt_bus_deregister(cam_sim_path(sc->sim_1)); 189*665484d8SDoug Ambrisko cam_sim_free(sc->sim_1, TRUE); 190*665484d8SDoug Ambrisko mtx_unlock(&sc->sim_lock); 191*665484d8SDoug Ambrisko return(ENXIO); 192*665484d8SDoug Ambrisko } 193*665484d8SDoug Ambrisko mtx_unlock(&sc->sim_lock); 194*665484d8SDoug Ambrisko 195*665484d8SDoug Ambrisko #if (__FreeBSD_version <= 704000) 196*665484d8SDoug Ambrisko if (mrsas_bus_scan(sc)){ 197*665484d8SDoug Ambrisko device_printf(sc->mrsas_dev, "Error in bus scan.\n"); 198*665484d8SDoug Ambrisko return(1); 199*665484d8SDoug Ambrisko } 200*665484d8SDoug Ambrisko #endif 201*665484d8SDoug Ambrisko return(0); 202*665484d8SDoug Ambrisko } 203*665484d8SDoug Ambrisko 204*665484d8SDoug Ambrisko /** 205*665484d8SDoug Ambrisko * mrsas_cam_detach: De-allocates and teardown CAM 206*665484d8SDoug Ambrisko * input: Adapter instance soft state 207*665484d8SDoug Ambrisko * 208*665484d8SDoug Ambrisko * De-registers and frees the paths and SIMs. 209*665484d8SDoug Ambrisko */ 210*665484d8SDoug Ambrisko void mrsas_cam_detach(struct mrsas_softc *sc) 211*665484d8SDoug Ambrisko { 212*665484d8SDoug Ambrisko if (sc->ev_tq != NULL) 213*665484d8SDoug Ambrisko taskqueue_free(sc->ev_tq); 214*665484d8SDoug Ambrisko mtx_lock(&sc->sim_lock); 215*665484d8SDoug Ambrisko if (sc->path_0) 216*665484d8SDoug Ambrisko xpt_free_path(sc->path_0); 217*665484d8SDoug Ambrisko if (sc->sim_0) { 218*665484d8SDoug Ambrisko xpt_bus_deregister(cam_sim_path(sc->sim_0)); 219*665484d8SDoug Ambrisko cam_sim_free(sc->sim_0, FALSE); 220*665484d8SDoug Ambrisko } 221*665484d8SDoug Ambrisko if (sc->path_1) 222*665484d8SDoug Ambrisko xpt_free_path(sc->path_1); 223*665484d8SDoug Ambrisko if (sc->sim_1) { 224*665484d8SDoug Ambrisko xpt_bus_deregister(cam_sim_path(sc->sim_1)); 225*665484d8SDoug Ambrisko cam_sim_free(sc->sim_1, TRUE); 226*665484d8SDoug Ambrisko } 227*665484d8SDoug Ambrisko mtx_unlock(&sc->sim_lock); 228*665484d8SDoug Ambrisko } 229*665484d8SDoug Ambrisko 230*665484d8SDoug Ambrisko /** 231*665484d8SDoug Ambrisko * mrsas_action: SIM callback entry point 232*665484d8SDoug Ambrisko * input: pointer to SIM 233*665484d8SDoug Ambrisko * pointer to CAM Control Block 234*665484d8SDoug Ambrisko * 235*665484d8SDoug Ambrisko * This function processes CAM subsystem requests. The type of request is 236*665484d8SDoug Ambrisko * stored in ccb->ccb_h.func_code. The preprocessor #ifdef is necessary 237*665484d8SDoug Ambrisko * because ccb->cpi.maxio is not supported for FreeBSD version 7.4 or 238*665484d8SDoug Ambrisko * earlier. 239*665484d8SDoug Ambrisko */ 240*665484d8SDoug Ambrisko static void mrsas_action(struct cam_sim *sim, union ccb *ccb) 241*665484d8SDoug Ambrisko { 242*665484d8SDoug Ambrisko struct mrsas_softc *sc = (struct mrsas_softc *)cam_sim_softc(sim); 243*665484d8SDoug Ambrisko struct ccb_hdr *ccb_h = &(ccb->ccb_h); 244*665484d8SDoug Ambrisko u_int32_t device_id; 245*665484d8SDoug Ambrisko 246*665484d8SDoug Ambrisko switch (ccb->ccb_h.func_code) { 247*665484d8SDoug Ambrisko case XPT_SCSI_IO: 248*665484d8SDoug Ambrisko { 249*665484d8SDoug Ambrisko device_id = ccb_h->target_id; 250*665484d8SDoug Ambrisko 251*665484d8SDoug Ambrisko /* 252*665484d8SDoug Ambrisko * bus 0 is LD, bus 1 is for system-PD 253*665484d8SDoug Ambrisko */ 254*665484d8SDoug Ambrisko if (cam_sim_bus(sim) == 1 && 255*665484d8SDoug Ambrisko sc->pd_list[device_id].driveState != MR_PD_STATE_SYSTEM) { 256*665484d8SDoug Ambrisko ccb->ccb_h.status |= CAM_DEV_NOT_THERE; 257*665484d8SDoug Ambrisko xpt_done(ccb); 258*665484d8SDoug Ambrisko } 259*665484d8SDoug Ambrisko else { 260*665484d8SDoug Ambrisko if (mrsas_startio(sc, sim, ccb)){ 261*665484d8SDoug Ambrisko ccb->ccb_h.status |= CAM_REQ_INVALID; 262*665484d8SDoug Ambrisko xpt_done(ccb); 263*665484d8SDoug Ambrisko } 264*665484d8SDoug Ambrisko } 265*665484d8SDoug Ambrisko break; 266*665484d8SDoug Ambrisko } 267*665484d8SDoug Ambrisko case XPT_ABORT: 268*665484d8SDoug Ambrisko { 269*665484d8SDoug Ambrisko ccb->ccb_h.status = CAM_UA_ABORT; 270*665484d8SDoug Ambrisko xpt_done(ccb); 271*665484d8SDoug Ambrisko break; 272*665484d8SDoug Ambrisko } 273*665484d8SDoug Ambrisko case XPT_RESET_BUS: 274*665484d8SDoug Ambrisko { 275*665484d8SDoug Ambrisko xpt_done(ccb); 276*665484d8SDoug Ambrisko break; 277*665484d8SDoug Ambrisko } 278*665484d8SDoug Ambrisko case XPT_GET_TRAN_SETTINGS: 279*665484d8SDoug Ambrisko { 280*665484d8SDoug Ambrisko ccb->cts.protocol = PROTO_SCSI; 281*665484d8SDoug Ambrisko ccb->cts.protocol_version = SCSI_REV_2; 282*665484d8SDoug Ambrisko ccb->cts.transport = XPORT_SPI; 283*665484d8SDoug Ambrisko ccb->cts.transport_version = 2; 284*665484d8SDoug Ambrisko ccb->cts.xport_specific.spi.valid = CTS_SPI_VALID_DISC; 285*665484d8SDoug Ambrisko ccb->cts.xport_specific.spi.flags = CTS_SPI_FLAGS_DISC_ENB; 286*665484d8SDoug Ambrisko ccb->cts.proto_specific.scsi.valid = CTS_SCSI_VALID_TQ; 287*665484d8SDoug Ambrisko ccb->cts.proto_specific.scsi.flags = CTS_SCSI_FLAGS_TAG_ENB; 288*665484d8SDoug Ambrisko ccb->ccb_h.status = CAM_REQ_CMP; 289*665484d8SDoug Ambrisko xpt_done(ccb); 290*665484d8SDoug Ambrisko break; 291*665484d8SDoug Ambrisko } 292*665484d8SDoug Ambrisko case XPT_SET_TRAN_SETTINGS: 293*665484d8SDoug Ambrisko { 294*665484d8SDoug Ambrisko ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 295*665484d8SDoug Ambrisko xpt_done(ccb); 296*665484d8SDoug Ambrisko break; 297*665484d8SDoug Ambrisko } 298*665484d8SDoug Ambrisko case XPT_CALC_GEOMETRY: 299*665484d8SDoug Ambrisko { 300*665484d8SDoug Ambrisko cam_calc_geometry(&ccb->ccg, 1); 301*665484d8SDoug Ambrisko xpt_done(ccb); 302*665484d8SDoug Ambrisko break; 303*665484d8SDoug Ambrisko } 304*665484d8SDoug Ambrisko case XPT_PATH_INQ: 305*665484d8SDoug Ambrisko { 306*665484d8SDoug Ambrisko ccb->cpi.version_num = 1; 307*665484d8SDoug Ambrisko ccb->cpi.hba_inquiry = 0; 308*665484d8SDoug Ambrisko ccb->cpi.target_sprt = 0; 309*665484d8SDoug Ambrisko ccb->cpi.hba_misc = 0; 310*665484d8SDoug Ambrisko ccb->cpi.hba_eng_cnt = 0; 311*665484d8SDoug Ambrisko ccb->cpi.max_lun = MRSAS_SCSI_MAX_LUNS; 312*665484d8SDoug Ambrisko ccb->cpi.unit_number = cam_sim_unit(sim); 313*665484d8SDoug Ambrisko ccb->cpi.bus_id = cam_sim_bus(sim); 314*665484d8SDoug Ambrisko ccb->cpi.initiator_id = MRSAS_SCSI_INITIATOR_ID; 315*665484d8SDoug Ambrisko ccb->cpi.base_transfer_speed = 150000; 316*665484d8SDoug Ambrisko strncpy(ccb->cpi.sim_vid, "FreeBSD", SIM_IDLEN); 317*665484d8SDoug Ambrisko strncpy(ccb->cpi.hba_vid, "LSI", HBA_IDLEN); 318*665484d8SDoug Ambrisko strncpy(ccb->cpi.dev_name, cam_sim_name(sim), DEV_IDLEN); 319*665484d8SDoug Ambrisko ccb->cpi.transport = XPORT_SPI; 320*665484d8SDoug Ambrisko ccb->cpi.transport_version = 2; 321*665484d8SDoug Ambrisko ccb->cpi.protocol = PROTO_SCSI; 322*665484d8SDoug Ambrisko ccb->cpi.protocol_version = SCSI_REV_2; 323*665484d8SDoug Ambrisko if (ccb->cpi.bus_id == 0) 324*665484d8SDoug Ambrisko ccb->cpi.max_target = MRSAS_MAX_LD-1; 325*665484d8SDoug Ambrisko else 326*665484d8SDoug Ambrisko ccb->cpi.max_target = MRSAS_MAX_PD-1; 327*665484d8SDoug Ambrisko #if (__FreeBSD_version > 704000) 328*665484d8SDoug Ambrisko ccb->cpi.maxio = MRSAS_MAX_IO_SIZE; 329*665484d8SDoug Ambrisko #endif 330*665484d8SDoug Ambrisko ccb->ccb_h.status = CAM_REQ_CMP; 331*665484d8SDoug Ambrisko xpt_done(ccb); 332*665484d8SDoug Ambrisko break; 333*665484d8SDoug Ambrisko } 334*665484d8SDoug Ambrisko default: 335*665484d8SDoug Ambrisko { 336*665484d8SDoug Ambrisko ccb->ccb_h.status = CAM_REQ_INVALID; 337*665484d8SDoug Ambrisko xpt_done(ccb); 338*665484d8SDoug Ambrisko break; 339*665484d8SDoug Ambrisko } 340*665484d8SDoug Ambrisko } 341*665484d8SDoug Ambrisko } 342*665484d8SDoug Ambrisko 343*665484d8SDoug Ambrisko /** 344*665484d8SDoug Ambrisko * mrsas_scsiio_timeout Callback function for IO timed out 345*665484d8SDoug Ambrisko * input: mpt command context 346*665484d8SDoug Ambrisko * 347*665484d8SDoug Ambrisko * This function will execute after timeout value 348*665484d8SDoug Ambrisko * provided by ccb header from CAM layer, if timer expires. 349*665484d8SDoug Ambrisko * Driver will run timer for all DCDM and LDIO comming from CAM layer. 350*665484d8SDoug Ambrisko * This function is callback function for IO timeout and it runs in 351*665484d8SDoug Ambrisko * no-sleep context. Set do_timedout_reset in Adapter context so that 352*665484d8SDoug Ambrisko * it will execute OCR/Kill adpter from ocr_thread context. 353*665484d8SDoug Ambrisko */ 354*665484d8SDoug Ambrisko static void 355*665484d8SDoug Ambrisko mrsas_scsiio_timeout(void *data) 356*665484d8SDoug Ambrisko { 357*665484d8SDoug Ambrisko struct mrsas_mpt_cmd *cmd; 358*665484d8SDoug Ambrisko struct mrsas_softc *sc; 359*665484d8SDoug Ambrisko 360*665484d8SDoug Ambrisko cmd = (struct mrsas_mpt_cmd *)data; 361*665484d8SDoug Ambrisko sc = cmd->sc; 362*665484d8SDoug Ambrisko 363*665484d8SDoug Ambrisko if (cmd->ccb_ptr == NULL) { 364*665484d8SDoug Ambrisko printf("command timeout with NULL ccb\n"); 365*665484d8SDoug Ambrisko return; 366*665484d8SDoug Ambrisko } 367*665484d8SDoug Ambrisko 368*665484d8SDoug Ambrisko /* Below callout is dummy entry so that it will be 369*665484d8SDoug Ambrisko * cancelled from mrsas_cmd_done(). Now Controller will 370*665484d8SDoug Ambrisko * go to OCR/Kill Adapter based on OCR enable/disable 371*665484d8SDoug Ambrisko * property of Controller from ocr_thread context. 372*665484d8SDoug Ambrisko */ 373*665484d8SDoug Ambrisko callout_reset(&cmd->cm_callout, (600000 * hz) / 1000, 374*665484d8SDoug Ambrisko mrsas_scsiio_timeout, cmd); 375*665484d8SDoug Ambrisko sc->do_timedout_reset = 1; 376*665484d8SDoug Ambrisko if(sc->ocr_thread_active) 377*665484d8SDoug Ambrisko wakeup(&sc->ocr_chan); 378*665484d8SDoug Ambrisko } 379*665484d8SDoug Ambrisko 380*665484d8SDoug Ambrisko /** 381*665484d8SDoug Ambrisko * mrsas_startio: SCSI IO entry point 382*665484d8SDoug Ambrisko * input: Adapter instance soft state 383*665484d8SDoug Ambrisko * pointer to CAM Control Block 384*665484d8SDoug Ambrisko * 385*665484d8SDoug Ambrisko * This function is the SCSI IO entry point and it initiates IO processing. 386*665484d8SDoug Ambrisko * It copies the IO and depending if the IO is read/write or inquiry, it would 387*665484d8SDoug Ambrisko * call mrsas_build_ldio() or mrsas_build_dcdb(), respectively. It returns 388*665484d8SDoug Ambrisko * 0 if the command is sent to firmware successfully, otherwise it returns 1. 389*665484d8SDoug Ambrisko */ 390*665484d8SDoug Ambrisko static int32_t mrsas_startio(struct mrsas_softc *sc, struct cam_sim *sim, 391*665484d8SDoug Ambrisko union ccb *ccb) 392*665484d8SDoug Ambrisko { 393*665484d8SDoug Ambrisko struct mrsas_mpt_cmd *cmd; 394*665484d8SDoug Ambrisko struct ccb_hdr *ccb_h = &(ccb->ccb_h); 395*665484d8SDoug Ambrisko struct ccb_scsiio *csio = &(ccb->csio); 396*665484d8SDoug Ambrisko MRSAS_REQUEST_DESCRIPTOR_UNION *req_desc; 397*665484d8SDoug Ambrisko 398*665484d8SDoug Ambrisko if ((csio->cdb_io.cdb_bytes[0]) == SYNCHRONIZE_CACHE){ 399*665484d8SDoug Ambrisko ccb->ccb_h.status = CAM_REQ_CMP; 400*665484d8SDoug Ambrisko xpt_done(ccb); 401*665484d8SDoug Ambrisko return(0); 402*665484d8SDoug Ambrisko } 403*665484d8SDoug Ambrisko 404*665484d8SDoug Ambrisko ccb_h->status |= CAM_SIM_QUEUED; 405*665484d8SDoug Ambrisko cmd = mrsas_get_mpt_cmd(sc); 406*665484d8SDoug Ambrisko 407*665484d8SDoug Ambrisko if (!cmd) { 408*665484d8SDoug Ambrisko ccb_h->status |= CAM_REQUEUE_REQ; 409*665484d8SDoug Ambrisko xpt_done(ccb); 410*665484d8SDoug Ambrisko return(0); 411*665484d8SDoug Ambrisko } 412*665484d8SDoug Ambrisko 413*665484d8SDoug Ambrisko if ((ccb_h->flags & CAM_DIR_MASK) != CAM_DIR_NONE) { 414*665484d8SDoug Ambrisko if(ccb_h->flags & CAM_DIR_IN) 415*665484d8SDoug Ambrisko cmd->flags |= MRSAS_DIR_IN; 416*665484d8SDoug Ambrisko if(ccb_h->flags & CAM_DIR_OUT) 417*665484d8SDoug Ambrisko cmd->flags |= MRSAS_DIR_OUT; 418*665484d8SDoug Ambrisko } 419*665484d8SDoug Ambrisko else 420*665484d8SDoug Ambrisko cmd->flags = MRSAS_DIR_NONE; /* no data */ 421*665484d8SDoug Ambrisko 422*665484d8SDoug Ambrisko /* For FreeBSD 10.0 and higher */ 423*665484d8SDoug Ambrisko #if (__FreeBSD_version >= 1000000) 424*665484d8SDoug Ambrisko /* 425*665484d8SDoug Ambrisko * * XXX We don't yet support physical addresses here. 426*665484d8SDoug Ambrisko */ 427*665484d8SDoug Ambrisko switch ((ccb->ccb_h.flags & CAM_DATA_MASK)) { 428*665484d8SDoug Ambrisko case CAM_DATA_PADDR: 429*665484d8SDoug Ambrisko case CAM_DATA_SG_PADDR: 430*665484d8SDoug Ambrisko printf("%s: physical addresses not supported\n", 431*665484d8SDoug Ambrisko __func__); 432*665484d8SDoug Ambrisko mrsas_release_mpt_cmd(cmd); 433*665484d8SDoug Ambrisko ccb_h->status = CAM_REQ_INVALID; 434*665484d8SDoug Ambrisko ccb_h->status &= ~CAM_SIM_QUEUED; 435*665484d8SDoug Ambrisko goto done; 436*665484d8SDoug Ambrisko case CAM_DATA_SG: 437*665484d8SDoug Ambrisko printf("%s: scatter gather is not supported\n", 438*665484d8SDoug Ambrisko __func__); 439*665484d8SDoug Ambrisko mrsas_release_mpt_cmd(cmd); 440*665484d8SDoug Ambrisko ccb_h->status = CAM_REQ_INVALID; 441*665484d8SDoug Ambrisko goto done; 442*665484d8SDoug Ambrisko case CAM_DATA_VADDR: 443*665484d8SDoug Ambrisko if (csio->dxfer_len > MRSAS_MAX_IO_SIZE) { 444*665484d8SDoug Ambrisko mrsas_release_mpt_cmd(cmd); 445*665484d8SDoug Ambrisko ccb_h->status = CAM_REQ_TOO_BIG; 446*665484d8SDoug Ambrisko goto done; 447*665484d8SDoug Ambrisko } 448*665484d8SDoug Ambrisko cmd->length = csio->dxfer_len; 449*665484d8SDoug Ambrisko if (cmd->length) 450*665484d8SDoug Ambrisko cmd->data = csio->data_ptr; 451*665484d8SDoug Ambrisko break; 452*665484d8SDoug Ambrisko default: 453*665484d8SDoug Ambrisko ccb->ccb_h.status = CAM_REQ_INVALID; 454*665484d8SDoug Ambrisko goto done; 455*665484d8SDoug Ambrisko } 456*665484d8SDoug Ambrisko #else 457*665484d8SDoug Ambrisko if (!(ccb_h->flags & CAM_DATA_PHYS)) { //Virtual data address 458*665484d8SDoug Ambrisko if (!(ccb_h->flags & CAM_SCATTER_VALID)) { 459*665484d8SDoug Ambrisko if (csio->dxfer_len > MRSAS_MAX_IO_SIZE) { 460*665484d8SDoug Ambrisko mrsas_release_mpt_cmd(cmd); 461*665484d8SDoug Ambrisko ccb_h->status = CAM_REQ_TOO_BIG; 462*665484d8SDoug Ambrisko goto done; 463*665484d8SDoug Ambrisko } 464*665484d8SDoug Ambrisko cmd->length = csio->dxfer_len; 465*665484d8SDoug Ambrisko if (cmd->length) 466*665484d8SDoug Ambrisko cmd->data = csio->data_ptr; 467*665484d8SDoug Ambrisko } 468*665484d8SDoug Ambrisko else { 469*665484d8SDoug Ambrisko mrsas_release_mpt_cmd(cmd); 470*665484d8SDoug Ambrisko ccb_h->status = CAM_REQ_INVALID; 471*665484d8SDoug Ambrisko goto done; 472*665484d8SDoug Ambrisko } 473*665484d8SDoug Ambrisko } 474*665484d8SDoug Ambrisko else { //Data addresses are physical. 475*665484d8SDoug Ambrisko mrsas_release_mpt_cmd(cmd); 476*665484d8SDoug Ambrisko ccb_h->status = CAM_REQ_INVALID; 477*665484d8SDoug Ambrisko ccb_h->status &= ~CAM_SIM_QUEUED; 478*665484d8SDoug Ambrisko goto done; 479*665484d8SDoug Ambrisko } 480*665484d8SDoug Ambrisko #endif 481*665484d8SDoug Ambrisko /* save ccb ptr */ 482*665484d8SDoug Ambrisko cmd->ccb_ptr = ccb; 483*665484d8SDoug Ambrisko 484*665484d8SDoug Ambrisko req_desc = mrsas_get_request_desc(sc, (cmd->index)-1); 485*665484d8SDoug Ambrisko if (!req_desc) { 486*665484d8SDoug Ambrisko device_printf(sc->mrsas_dev, "Cannot get request_descriptor.\n"); 487*665484d8SDoug Ambrisko return (FAIL); 488*665484d8SDoug Ambrisko } 489*665484d8SDoug Ambrisko memset(req_desc, 0, sizeof(MRSAS_REQUEST_DESCRIPTOR_UNION)); 490*665484d8SDoug Ambrisko cmd->request_desc = req_desc; 491*665484d8SDoug Ambrisko 492*665484d8SDoug Ambrisko if (ccb_h->flags & CAM_CDB_POINTER) 493*665484d8SDoug Ambrisko bcopy(csio->cdb_io.cdb_ptr, cmd->io_request->CDB.CDB32, csio->cdb_len); 494*665484d8SDoug Ambrisko else 495*665484d8SDoug Ambrisko bcopy(csio->cdb_io.cdb_bytes, cmd->io_request->CDB.CDB32, csio->cdb_len); 496*665484d8SDoug Ambrisko mtx_lock(&sc->raidmap_lock); 497*665484d8SDoug Ambrisko 498*665484d8SDoug Ambrisko if (mrsas_ldio_inq(sim, ccb)) { 499*665484d8SDoug Ambrisko if (mrsas_build_ldio(sc, cmd, ccb)){ 500*665484d8SDoug Ambrisko device_printf(sc->mrsas_dev, "Build LDIO failed.\n"); 501*665484d8SDoug Ambrisko mtx_unlock(&sc->raidmap_lock); 502*665484d8SDoug Ambrisko return(1); 503*665484d8SDoug Ambrisko } 504*665484d8SDoug Ambrisko } 505*665484d8SDoug Ambrisko else { 506*665484d8SDoug Ambrisko if (mrsas_build_dcdb(sc, cmd, ccb, sim)) { 507*665484d8SDoug Ambrisko device_printf(sc->mrsas_dev, "Build DCDB failed.\n"); 508*665484d8SDoug Ambrisko mtx_unlock(&sc->raidmap_lock); 509*665484d8SDoug Ambrisko return(1); 510*665484d8SDoug Ambrisko } 511*665484d8SDoug Ambrisko } 512*665484d8SDoug Ambrisko mtx_unlock(&sc->raidmap_lock); 513*665484d8SDoug Ambrisko 514*665484d8SDoug Ambrisko if (cmd->flags == MRSAS_DIR_IN) //from device 515*665484d8SDoug Ambrisko cmd->io_request->Control |= MPI2_SCSIIO_CONTROL_READ; 516*665484d8SDoug Ambrisko else if (cmd->flags == MRSAS_DIR_OUT) //to device 517*665484d8SDoug Ambrisko cmd->io_request->Control |= MPI2_SCSIIO_CONTROL_WRITE; 518*665484d8SDoug Ambrisko 519*665484d8SDoug Ambrisko cmd->io_request->SGLFlags = MPI2_SGE_FLAGS_64_BIT_ADDRESSING; 520*665484d8SDoug Ambrisko cmd->io_request->SGLOffset0 = offsetof(MRSAS_RAID_SCSI_IO_REQUEST, SGL)/4; 521*665484d8SDoug Ambrisko cmd->io_request->SenseBufferLowAddress = cmd->sense_phys_addr; 522*665484d8SDoug Ambrisko cmd->io_request->SenseBufferLength = MRSAS_SCSI_SENSE_BUFFERSIZE; 523*665484d8SDoug Ambrisko 524*665484d8SDoug Ambrisko req_desc = cmd->request_desc; 525*665484d8SDoug Ambrisko req_desc->SCSIIO.SMID = cmd->index; 526*665484d8SDoug Ambrisko 527*665484d8SDoug Ambrisko /* 528*665484d8SDoug Ambrisko * Start timer for IO timeout. Default timeout value is 90 second. 529*665484d8SDoug Ambrisko */ 530*665484d8SDoug Ambrisko callout_reset(&cmd->cm_callout, (sc->mrsas_io_timeout * hz) / 1000, 531*665484d8SDoug Ambrisko mrsas_scsiio_timeout, cmd); 532*665484d8SDoug Ambrisko atomic_inc(&sc->fw_outstanding); 533*665484d8SDoug Ambrisko 534*665484d8SDoug Ambrisko if(atomic_read(&sc->fw_outstanding) > sc->io_cmds_highwater) 535*665484d8SDoug Ambrisko sc->io_cmds_highwater++; 536*665484d8SDoug Ambrisko 537*665484d8SDoug Ambrisko mrsas_fire_cmd(sc, req_desc->addr.u.low, req_desc->addr.u.high); 538*665484d8SDoug Ambrisko return(0); 539*665484d8SDoug Ambrisko 540*665484d8SDoug Ambrisko done: 541*665484d8SDoug Ambrisko xpt_done(ccb); 542*665484d8SDoug Ambrisko return(0); 543*665484d8SDoug Ambrisko } 544*665484d8SDoug Ambrisko 545*665484d8SDoug Ambrisko /** 546*665484d8SDoug Ambrisko * mrsas_ldio_inq: Determines if IO is read/write or inquiry 547*665484d8SDoug Ambrisko * input: pointer to CAM Control Block 548*665484d8SDoug Ambrisko * 549*665484d8SDoug Ambrisko * This function determines if the IO is read/write or inquiry. It returns a 550*665484d8SDoug Ambrisko * 1 if the IO is read/write and 0 if it is inquiry. 551*665484d8SDoug Ambrisko */ 552*665484d8SDoug Ambrisko int mrsas_ldio_inq(struct cam_sim *sim, union ccb *ccb) 553*665484d8SDoug Ambrisko { 554*665484d8SDoug Ambrisko struct ccb_scsiio *csio = &(ccb->csio); 555*665484d8SDoug Ambrisko 556*665484d8SDoug Ambrisko if (cam_sim_bus(sim) == 1) 557*665484d8SDoug Ambrisko return(0); 558*665484d8SDoug Ambrisko 559*665484d8SDoug Ambrisko switch (csio->cdb_io.cdb_bytes[0]) { 560*665484d8SDoug Ambrisko case READ_10: 561*665484d8SDoug Ambrisko case WRITE_10: 562*665484d8SDoug Ambrisko case READ_12: 563*665484d8SDoug Ambrisko case WRITE_12: 564*665484d8SDoug Ambrisko case READ_6: 565*665484d8SDoug Ambrisko case WRITE_6: 566*665484d8SDoug Ambrisko case READ_16: 567*665484d8SDoug Ambrisko case WRITE_16: 568*665484d8SDoug Ambrisko return 1; 569*665484d8SDoug Ambrisko default: 570*665484d8SDoug Ambrisko return 0; 571*665484d8SDoug Ambrisko } 572*665484d8SDoug Ambrisko } 573*665484d8SDoug Ambrisko 574*665484d8SDoug Ambrisko /** 575*665484d8SDoug Ambrisko * mrsas_get_mpt_cmd: Get a cmd from free command pool 576*665484d8SDoug Ambrisko * input: Adapter instance soft state 577*665484d8SDoug Ambrisko * 578*665484d8SDoug Ambrisko * This function removes an MPT command from the command free list and 579*665484d8SDoug Ambrisko * initializes it. 580*665484d8SDoug Ambrisko */ 581*665484d8SDoug Ambrisko struct mrsas_mpt_cmd* mrsas_get_mpt_cmd(struct mrsas_softc *sc) 582*665484d8SDoug Ambrisko { 583*665484d8SDoug Ambrisko struct mrsas_mpt_cmd *cmd = NULL; 584*665484d8SDoug Ambrisko 585*665484d8SDoug Ambrisko mtx_lock(&sc->mpt_cmd_pool_lock); 586*665484d8SDoug Ambrisko if (!TAILQ_EMPTY(&sc->mrsas_mpt_cmd_list_head)){ 587*665484d8SDoug Ambrisko cmd = TAILQ_FIRST(&sc->mrsas_mpt_cmd_list_head); 588*665484d8SDoug Ambrisko TAILQ_REMOVE(&sc->mrsas_mpt_cmd_list_head, cmd, next); 589*665484d8SDoug Ambrisko } 590*665484d8SDoug Ambrisko memset((uint8_t *)cmd->io_request, 0, MRSAS_MPI2_RAID_DEFAULT_IO_FRAME_SIZE); 591*665484d8SDoug Ambrisko cmd->data = NULL; 592*665484d8SDoug Ambrisko cmd->length = 0; 593*665484d8SDoug Ambrisko cmd->flags = 0; 594*665484d8SDoug Ambrisko cmd->error_code = 0; 595*665484d8SDoug Ambrisko cmd->load_balance = 0; 596*665484d8SDoug Ambrisko cmd->ccb_ptr = NULL; 597*665484d8SDoug Ambrisko mtx_unlock(&sc->mpt_cmd_pool_lock); 598*665484d8SDoug Ambrisko 599*665484d8SDoug Ambrisko return cmd; 600*665484d8SDoug Ambrisko } 601*665484d8SDoug Ambrisko 602*665484d8SDoug Ambrisko /** 603*665484d8SDoug Ambrisko * mrsas_release_mpt_cmd: Return a cmd to free command pool 604*665484d8SDoug Ambrisko * input: Command packet for return to free command pool 605*665484d8SDoug Ambrisko * 606*665484d8SDoug Ambrisko * This function returns an MPT command to the free command list. 607*665484d8SDoug Ambrisko */ 608*665484d8SDoug Ambrisko void mrsas_release_mpt_cmd(struct mrsas_mpt_cmd *cmd) 609*665484d8SDoug Ambrisko { 610*665484d8SDoug Ambrisko struct mrsas_softc *sc = cmd->sc; 611*665484d8SDoug Ambrisko 612*665484d8SDoug Ambrisko mtx_lock(&sc->mpt_cmd_pool_lock); 613*665484d8SDoug Ambrisko cmd->sync_cmd_idx = (u_int32_t)MRSAS_ULONG_MAX; 614*665484d8SDoug Ambrisko TAILQ_INSERT_TAIL(&(sc->mrsas_mpt_cmd_list_head), cmd, next); 615*665484d8SDoug Ambrisko mtx_unlock(&sc->mpt_cmd_pool_lock); 616*665484d8SDoug Ambrisko 617*665484d8SDoug Ambrisko return; 618*665484d8SDoug Ambrisko } 619*665484d8SDoug Ambrisko 620*665484d8SDoug Ambrisko /** 621*665484d8SDoug Ambrisko * mrsas_get_request_desc: Get request descriptor from array 622*665484d8SDoug Ambrisko * input: Adapter instance soft state 623*665484d8SDoug Ambrisko * SMID index 624*665484d8SDoug Ambrisko * 625*665484d8SDoug Ambrisko * This function returns a pointer to the request descriptor. 626*665484d8SDoug Ambrisko */ 627*665484d8SDoug Ambrisko MRSAS_REQUEST_DESCRIPTOR_UNION * 628*665484d8SDoug Ambrisko mrsas_get_request_desc(struct mrsas_softc *sc, u_int16_t index) 629*665484d8SDoug Ambrisko { 630*665484d8SDoug Ambrisko u_int8_t *p; 631*665484d8SDoug Ambrisko 632*665484d8SDoug Ambrisko if (index >= sc->max_fw_cmds) { 633*665484d8SDoug Ambrisko device_printf(sc->mrsas_dev, "Invalid SMID (0x%x)request for desc\n", index); 634*665484d8SDoug Ambrisko return NULL; 635*665484d8SDoug Ambrisko } 636*665484d8SDoug Ambrisko p = sc->req_desc + sizeof(MRSAS_REQUEST_DESCRIPTOR_UNION) * index; 637*665484d8SDoug Ambrisko 638*665484d8SDoug Ambrisko return (MRSAS_REQUEST_DESCRIPTOR_UNION *)p; 639*665484d8SDoug Ambrisko } 640*665484d8SDoug Ambrisko 641*665484d8SDoug Ambrisko /** 642*665484d8SDoug Ambrisko * mrsas_build_ldio: Builds an LDIO command 643*665484d8SDoug Ambrisko * input: Adapter instance soft state 644*665484d8SDoug Ambrisko * Pointer to command packet 645*665484d8SDoug Ambrisko * Pointer to CCB 646*665484d8SDoug Ambrisko * 647*665484d8SDoug Ambrisko * This function builds the LDIO command packet. It returns 0 if the 648*665484d8SDoug Ambrisko * command is built successfully, otherwise it returns a 1. 649*665484d8SDoug Ambrisko */ 650*665484d8SDoug Ambrisko int mrsas_build_ldio(struct mrsas_softc *sc, struct mrsas_mpt_cmd *cmd, 651*665484d8SDoug Ambrisko union ccb *ccb) 652*665484d8SDoug Ambrisko { 653*665484d8SDoug Ambrisko struct ccb_hdr *ccb_h = &(ccb->ccb_h); 654*665484d8SDoug Ambrisko struct ccb_scsiio *csio = &(ccb->csio); 655*665484d8SDoug Ambrisko u_int32_t device_id; 656*665484d8SDoug Ambrisko MRSAS_RAID_SCSI_IO_REQUEST *io_request; 657*665484d8SDoug Ambrisko 658*665484d8SDoug Ambrisko device_id = ccb_h->target_id; 659*665484d8SDoug Ambrisko 660*665484d8SDoug Ambrisko io_request = cmd->io_request; 661*665484d8SDoug Ambrisko io_request->RaidContext.VirtualDiskTgtId = device_id; 662*665484d8SDoug Ambrisko io_request->RaidContext.status = 0; 663*665484d8SDoug Ambrisko io_request->RaidContext.exStatus = 0; 664*665484d8SDoug Ambrisko 665*665484d8SDoug Ambrisko /* just the cdb len, other flags zero, and ORed-in later for FP */ 666*665484d8SDoug Ambrisko io_request->IoFlags = csio->cdb_len; 667*665484d8SDoug Ambrisko 668*665484d8SDoug Ambrisko if (mrsas_setup_io(sc, cmd, ccb, device_id, io_request) != SUCCESS) 669*665484d8SDoug Ambrisko device_printf(sc->mrsas_dev, "Build ldio or fpio error\n"); 670*665484d8SDoug Ambrisko 671*665484d8SDoug Ambrisko io_request->DataLength = cmd->length; 672*665484d8SDoug Ambrisko 673*665484d8SDoug Ambrisko if (mrsas_map_request(sc, cmd) == SUCCESS) { 674*665484d8SDoug Ambrisko if (cmd->sge_count > MRSAS_MAX_SGL) { 675*665484d8SDoug Ambrisko device_printf(sc->mrsas_dev, "Error: sge_count (0x%x) exceeds" 676*665484d8SDoug Ambrisko "max (0x%x) allowed\n", cmd->sge_count, sc->max_num_sge); 677*665484d8SDoug Ambrisko return (FAIL); 678*665484d8SDoug Ambrisko } 679*665484d8SDoug Ambrisko io_request->RaidContext.numSGE = cmd->sge_count; 680*665484d8SDoug Ambrisko } 681*665484d8SDoug Ambrisko else { 682*665484d8SDoug Ambrisko device_printf(sc->mrsas_dev, "Data map/load failed.\n"); 683*665484d8SDoug Ambrisko return(FAIL); 684*665484d8SDoug Ambrisko } 685*665484d8SDoug Ambrisko return(0); 686*665484d8SDoug Ambrisko } 687*665484d8SDoug Ambrisko 688*665484d8SDoug Ambrisko /** 689*665484d8SDoug Ambrisko * mrsas_setup_io: Set up data including Fast Path I/O 690*665484d8SDoug Ambrisko * input: Adapter instance soft state 691*665484d8SDoug Ambrisko * Pointer to command packet 692*665484d8SDoug Ambrisko * Pointer to CCB 693*665484d8SDoug Ambrisko * 694*665484d8SDoug Ambrisko * This function builds the DCDB inquiry command. It returns 0 if the 695*665484d8SDoug Ambrisko * command is built successfully, otherwise it returns a 1. 696*665484d8SDoug Ambrisko */ 697*665484d8SDoug Ambrisko int mrsas_setup_io(struct mrsas_softc *sc, struct mrsas_mpt_cmd *cmd, 698*665484d8SDoug Ambrisko union ccb *ccb, u_int32_t device_id, 699*665484d8SDoug Ambrisko MRSAS_RAID_SCSI_IO_REQUEST *io_request) 700*665484d8SDoug Ambrisko { 701*665484d8SDoug Ambrisko struct ccb_hdr *ccb_h = &(ccb->ccb_h); 702*665484d8SDoug Ambrisko struct ccb_scsiio *csio = &(ccb->csio); 703*665484d8SDoug Ambrisko struct IO_REQUEST_INFO io_info; 704*665484d8SDoug Ambrisko MR_FW_RAID_MAP_ALL *map_ptr; 705*665484d8SDoug Ambrisko u_int8_t fp_possible; 706*665484d8SDoug Ambrisko u_int32_t start_lba_hi, start_lba_lo, ld_block_size; 707*665484d8SDoug Ambrisko u_int32_t datalength = 0; 708*665484d8SDoug Ambrisko 709*665484d8SDoug Ambrisko start_lba_lo = 0; 710*665484d8SDoug Ambrisko start_lba_hi = 0; 711*665484d8SDoug Ambrisko fp_possible = 0; 712*665484d8SDoug Ambrisko 713*665484d8SDoug Ambrisko /* 714*665484d8SDoug Ambrisko * READ_6 (0x08) or WRITE_6 (0x0A) cdb 715*665484d8SDoug Ambrisko */ 716*665484d8SDoug Ambrisko if (csio->cdb_len == 6) { 717*665484d8SDoug Ambrisko datalength = (u_int32_t)csio->cdb_io.cdb_bytes[4]; 718*665484d8SDoug Ambrisko start_lba_lo = ((u_int32_t) csio->cdb_io.cdb_bytes[1] << 16) | 719*665484d8SDoug Ambrisko ((u_int32_t) csio->cdb_io.cdb_bytes[2] << 8) | 720*665484d8SDoug Ambrisko (u_int32_t) csio->cdb_io.cdb_bytes[3]; 721*665484d8SDoug Ambrisko start_lba_lo &= 0x1FFFFF; 722*665484d8SDoug Ambrisko } 723*665484d8SDoug Ambrisko /* 724*665484d8SDoug Ambrisko * READ_10 (0x28) or WRITE_6 (0x2A) cdb 725*665484d8SDoug Ambrisko */ 726*665484d8SDoug Ambrisko else if (csio->cdb_len == 10) { 727*665484d8SDoug Ambrisko datalength = (u_int32_t)csio->cdb_io.cdb_bytes[8] | 728*665484d8SDoug Ambrisko ((u_int32_t)csio->cdb_io.cdb_bytes[7] << 8); 729*665484d8SDoug Ambrisko start_lba_lo = ((u_int32_t) csio->cdb_io.cdb_bytes[2] << 24) | 730*665484d8SDoug Ambrisko ((u_int32_t) csio->cdb_io.cdb_bytes[3] << 16) | 731*665484d8SDoug Ambrisko (u_int32_t) csio->cdb_io.cdb_bytes[4] << 8 | 732*665484d8SDoug Ambrisko ((u_int32_t) csio->cdb_io.cdb_bytes[5]); 733*665484d8SDoug Ambrisko } 734*665484d8SDoug Ambrisko /* 735*665484d8SDoug Ambrisko * READ_12 (0xA8) or WRITE_12 (0xAA) cdb 736*665484d8SDoug Ambrisko */ 737*665484d8SDoug Ambrisko else if (csio->cdb_len == 12) { 738*665484d8SDoug Ambrisko datalength = (u_int32_t)csio->cdb_io.cdb_bytes[6] << 24 | 739*665484d8SDoug Ambrisko ((u_int32_t)csio->cdb_io.cdb_bytes[7] << 16) | 740*665484d8SDoug Ambrisko ((u_int32_t)csio->cdb_io.cdb_bytes[8] << 8) | 741*665484d8SDoug Ambrisko ((u_int32_t)csio->cdb_io.cdb_bytes[9]); 742*665484d8SDoug Ambrisko start_lba_lo = ((u_int32_t) csio->cdb_io.cdb_bytes[2] << 24) | 743*665484d8SDoug Ambrisko ((u_int32_t) csio->cdb_io.cdb_bytes[3] << 16) | 744*665484d8SDoug Ambrisko (u_int32_t) csio->cdb_io.cdb_bytes[4] << 8 | 745*665484d8SDoug Ambrisko ((u_int32_t) csio->cdb_io.cdb_bytes[5]); 746*665484d8SDoug Ambrisko } 747*665484d8SDoug Ambrisko /* 748*665484d8SDoug Ambrisko * READ_16 (0x88) or WRITE_16 (0xx8A) cdb 749*665484d8SDoug Ambrisko */ 750*665484d8SDoug Ambrisko else if (csio->cdb_len == 16) { 751*665484d8SDoug Ambrisko datalength = (u_int32_t)csio->cdb_io.cdb_bytes[10] << 24 | 752*665484d8SDoug Ambrisko ((u_int32_t)csio->cdb_io.cdb_bytes[11] << 16) | 753*665484d8SDoug Ambrisko ((u_int32_t)csio->cdb_io.cdb_bytes[12] << 8) | 754*665484d8SDoug Ambrisko ((u_int32_t)csio->cdb_io.cdb_bytes[13]); 755*665484d8SDoug Ambrisko start_lba_lo = ((u_int32_t) csio->cdb_io.cdb_bytes[6] << 24) | 756*665484d8SDoug Ambrisko ((u_int32_t) csio->cdb_io.cdb_bytes[7] << 16) | 757*665484d8SDoug Ambrisko (u_int32_t) csio->cdb_io.cdb_bytes[8] << 8 | 758*665484d8SDoug Ambrisko ((u_int32_t) csio->cdb_io.cdb_bytes[9]); 759*665484d8SDoug Ambrisko start_lba_hi = ((u_int32_t) csio->cdb_io.cdb_bytes[2] << 24) | 760*665484d8SDoug Ambrisko ((u_int32_t) csio->cdb_io.cdb_bytes[3] << 16) | 761*665484d8SDoug Ambrisko (u_int32_t) csio->cdb_io.cdb_bytes[4] << 8 | 762*665484d8SDoug Ambrisko ((u_int32_t) csio->cdb_io.cdb_bytes[5]); 763*665484d8SDoug Ambrisko } 764*665484d8SDoug Ambrisko 765*665484d8SDoug Ambrisko memset(&io_info, 0, sizeof(struct IO_REQUEST_INFO)); 766*665484d8SDoug Ambrisko io_info.ldStartBlock = ((u_int64_t)start_lba_hi << 32) | start_lba_lo; 767*665484d8SDoug Ambrisko io_info.numBlocks = datalength; 768*665484d8SDoug Ambrisko io_info.ldTgtId = device_id; 769*665484d8SDoug Ambrisko 770*665484d8SDoug Ambrisko switch (ccb_h->flags & CAM_DIR_MASK) { 771*665484d8SDoug Ambrisko case CAM_DIR_IN: 772*665484d8SDoug Ambrisko io_info.isRead = 1; 773*665484d8SDoug Ambrisko break; 774*665484d8SDoug Ambrisko case CAM_DIR_OUT: 775*665484d8SDoug Ambrisko io_info.isRead = 0; 776*665484d8SDoug Ambrisko break; 777*665484d8SDoug Ambrisko case CAM_DIR_NONE: 778*665484d8SDoug Ambrisko default: 779*665484d8SDoug Ambrisko mrsas_dprint(sc, MRSAS_TRACE, "From %s : DMA Flag is %d \n", __func__, ccb_h->flags & CAM_DIR_MASK); 780*665484d8SDoug Ambrisko break; 781*665484d8SDoug Ambrisko } 782*665484d8SDoug Ambrisko 783*665484d8SDoug Ambrisko map_ptr = sc->raidmap_mem[(sc->map_id & 1)]; 784*665484d8SDoug Ambrisko ld_block_size = MR_LdBlockSizeGet(device_id, map_ptr, sc); 785*665484d8SDoug Ambrisko 786*665484d8SDoug Ambrisko if ((MR_TargetIdToLdGet(device_id, map_ptr) >= MAX_LOGICAL_DRIVES) || 787*665484d8SDoug Ambrisko (!sc->fast_path_io)) { 788*665484d8SDoug Ambrisko io_request->RaidContext.regLockFlags = 0; 789*665484d8SDoug Ambrisko fp_possible = 0; 790*665484d8SDoug Ambrisko } 791*665484d8SDoug Ambrisko else 792*665484d8SDoug Ambrisko { 793*665484d8SDoug Ambrisko if (MR_BuildRaidContext(sc, &io_info, &io_request->RaidContext, map_ptr)) 794*665484d8SDoug Ambrisko fp_possible = io_info.fpOkForIo; 795*665484d8SDoug Ambrisko } 796*665484d8SDoug Ambrisko 797*665484d8SDoug Ambrisko if (fp_possible) { 798*665484d8SDoug Ambrisko mrsas_set_pd_lba(io_request, csio->cdb_len, &io_info, ccb, map_ptr, 799*665484d8SDoug Ambrisko start_lba_lo, ld_block_size); 800*665484d8SDoug Ambrisko io_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST; 801*665484d8SDoug Ambrisko cmd->request_desc->SCSIIO.RequestFlags = 802*665484d8SDoug Ambrisko (MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY 803*665484d8SDoug Ambrisko << MRSAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); 804*665484d8SDoug Ambrisko if ((sc->device_id == MRSAS_INVADER) || (sc->device_id == MRSAS_FURY)) { 805*665484d8SDoug Ambrisko if (io_request->RaidContext.regLockFlags == REGION_TYPE_UNUSED) 806*665484d8SDoug Ambrisko cmd->request_desc->SCSIIO.RequestFlags = (MRSAS_REQ_DESCRIPT_FLAGS_NO_LOCK << MRSAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); 807*665484d8SDoug Ambrisko io_request->RaidContext.Type = MPI2_TYPE_CUDA; 808*665484d8SDoug Ambrisko io_request->RaidContext.nseg = 0x1; 809*665484d8SDoug Ambrisko io_request->IoFlags |= MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH; 810*665484d8SDoug Ambrisko io_request->RaidContext.regLockFlags |= (MR_RL_FLAGS_GRANT_DESTINATION_CUDA | MR_RL_FLAGS_SEQ_NUM_ENABLE); 811*665484d8SDoug Ambrisko } 812*665484d8SDoug Ambrisko if ((sc->load_balance_info[device_id].loadBalanceFlag) && (io_info.isRead)) { 813*665484d8SDoug Ambrisko io_info.devHandle = mrsas_get_updated_dev_handle(&sc->load_balance_info[device_id], 814*665484d8SDoug Ambrisko &io_info); 815*665484d8SDoug Ambrisko cmd->load_balance = MRSAS_LOAD_BALANCE_FLAG; 816*665484d8SDoug Ambrisko } 817*665484d8SDoug Ambrisko else 818*665484d8SDoug Ambrisko cmd->load_balance = 0; 819*665484d8SDoug Ambrisko cmd->request_desc->SCSIIO.DevHandle = io_info.devHandle; 820*665484d8SDoug Ambrisko io_request->DevHandle = io_info.devHandle; 821*665484d8SDoug Ambrisko } 822*665484d8SDoug Ambrisko else { 823*665484d8SDoug Ambrisko /* Not FP IO */ 824*665484d8SDoug Ambrisko io_request->RaidContext.timeoutValue = map_ptr->raidMap.fpPdIoTimeoutSec; 825*665484d8SDoug Ambrisko cmd->request_desc->SCSIIO.RequestFlags = 826*665484d8SDoug Ambrisko (MRSAS_REQ_DESCRIPT_FLAGS_LD_IO << MRSAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); 827*665484d8SDoug Ambrisko if ((sc->device_id == MRSAS_INVADER) || (sc->device_id == MRSAS_FURY)) { 828*665484d8SDoug Ambrisko if (io_request->RaidContext.regLockFlags == REGION_TYPE_UNUSED) 829*665484d8SDoug Ambrisko cmd->request_desc->SCSIIO.RequestFlags = (MRSAS_REQ_DESCRIPT_FLAGS_NO_LOCK << MRSAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); 830*665484d8SDoug Ambrisko io_request->RaidContext.Type = MPI2_TYPE_CUDA; 831*665484d8SDoug Ambrisko io_request->RaidContext.regLockFlags |= (MR_RL_FLAGS_GRANT_DESTINATION_CPU0 | MR_RL_FLAGS_SEQ_NUM_ENABLE); 832*665484d8SDoug Ambrisko io_request->RaidContext.nseg = 0x1; 833*665484d8SDoug Ambrisko } 834*665484d8SDoug Ambrisko io_request->Function = MRSAS_MPI2_FUNCTION_LD_IO_REQUEST; 835*665484d8SDoug Ambrisko io_request->DevHandle = device_id; 836*665484d8SDoug Ambrisko } 837*665484d8SDoug Ambrisko return(0); 838*665484d8SDoug Ambrisko } 839*665484d8SDoug Ambrisko 840*665484d8SDoug Ambrisko /** 841*665484d8SDoug Ambrisko * mrsas_build_dcdb: Builds an DCDB command 842*665484d8SDoug Ambrisko * input: Adapter instance soft state 843*665484d8SDoug Ambrisko * Pointer to command packet 844*665484d8SDoug Ambrisko * Pointer to CCB 845*665484d8SDoug Ambrisko * 846*665484d8SDoug Ambrisko * This function builds the DCDB inquiry command. It returns 0 if the 847*665484d8SDoug Ambrisko * command is built successfully, otherwise it returns a 1. 848*665484d8SDoug Ambrisko */ 849*665484d8SDoug Ambrisko int mrsas_build_dcdb(struct mrsas_softc *sc, struct mrsas_mpt_cmd *cmd, 850*665484d8SDoug Ambrisko union ccb *ccb, struct cam_sim *sim) 851*665484d8SDoug Ambrisko { 852*665484d8SDoug Ambrisko struct ccb_hdr *ccb_h = &(ccb->ccb_h); 853*665484d8SDoug Ambrisko u_int32_t device_id; 854*665484d8SDoug Ambrisko MR_FW_RAID_MAP_ALL *map_ptr; 855*665484d8SDoug Ambrisko MRSAS_RAID_SCSI_IO_REQUEST *io_request; 856*665484d8SDoug Ambrisko 857*665484d8SDoug Ambrisko io_request = cmd->io_request; 858*665484d8SDoug Ambrisko device_id = ccb_h->target_id; 859*665484d8SDoug Ambrisko map_ptr = sc->raidmap_mem[(sc->map_id & 1)]; 860*665484d8SDoug Ambrisko 861*665484d8SDoug Ambrisko /* Check if this is for system PD */ 862*665484d8SDoug Ambrisko if (cam_sim_bus(sim) == 1 && 863*665484d8SDoug Ambrisko sc->pd_list[device_id].driveState == MR_PD_STATE_SYSTEM) { 864*665484d8SDoug Ambrisko io_request->Function = 0; 865*665484d8SDoug Ambrisko io_request->DevHandle = map_ptr->raidMap.devHndlInfo[device_id].curDevHdl; 866*665484d8SDoug Ambrisko io_request->RaidContext.timeoutValue = map_ptr->raidMap.fpPdIoTimeoutSec; 867*665484d8SDoug Ambrisko io_request->RaidContext.regLockFlags = 0; 868*665484d8SDoug Ambrisko io_request->RaidContext.regLockRowLBA = 0; 869*665484d8SDoug Ambrisko io_request->RaidContext.regLockLength = 0; 870*665484d8SDoug Ambrisko io_request->RaidContext.RAIDFlags = MR_RAID_FLAGS_IO_SUB_TYPE_SYSTEM_PD << 871*665484d8SDoug Ambrisko MR_RAID_CTX_RAID_FLAGS_IO_SUB_TYPE_SHIFT; 872*665484d8SDoug Ambrisko if ((sc->device_id == MRSAS_INVADER) || (sc->device_id == MRSAS_FURY)) 873*665484d8SDoug Ambrisko io_request->IoFlags |= MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH; 874*665484d8SDoug Ambrisko cmd->request_desc->SCSIIO.RequestFlags = 875*665484d8SDoug Ambrisko (MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY << 876*665484d8SDoug Ambrisko MRSAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); 877*665484d8SDoug Ambrisko cmd->request_desc->SCSIIO.DevHandle = 878*665484d8SDoug Ambrisko map_ptr->raidMap.devHndlInfo[device_id].curDevHdl; 879*665484d8SDoug Ambrisko } 880*665484d8SDoug Ambrisko else { 881*665484d8SDoug Ambrisko io_request->Function = MRSAS_MPI2_FUNCTION_LD_IO_REQUEST; 882*665484d8SDoug Ambrisko io_request->DevHandle = device_id; 883*665484d8SDoug Ambrisko cmd->request_desc->SCSIIO.RequestFlags = 884*665484d8SDoug Ambrisko (MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO << MRSAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); 885*665484d8SDoug Ambrisko } 886*665484d8SDoug Ambrisko 887*665484d8SDoug Ambrisko io_request->RaidContext.VirtualDiskTgtId = device_id; 888*665484d8SDoug Ambrisko io_request->LUN[1] = ccb_h->target_lun & 0xF; 889*665484d8SDoug Ambrisko io_request->DataLength = cmd->length; 890*665484d8SDoug Ambrisko 891*665484d8SDoug Ambrisko if (mrsas_map_request(sc, cmd) == SUCCESS) { 892*665484d8SDoug Ambrisko if (cmd->sge_count > sc->max_num_sge) { 893*665484d8SDoug Ambrisko device_printf(sc->mrsas_dev, "Error: sge_count (0x%x) exceeds" 894*665484d8SDoug Ambrisko "max (0x%x) allowed\n", cmd->sge_count, sc->max_num_sge); 895*665484d8SDoug Ambrisko return (1); 896*665484d8SDoug Ambrisko } 897*665484d8SDoug Ambrisko io_request->RaidContext.numSGE = cmd->sge_count; 898*665484d8SDoug Ambrisko } 899*665484d8SDoug Ambrisko else { 900*665484d8SDoug Ambrisko device_printf(sc->mrsas_dev, "Data map/load failed.\n"); 901*665484d8SDoug Ambrisko return(1); 902*665484d8SDoug Ambrisko } 903*665484d8SDoug Ambrisko return(0); 904*665484d8SDoug Ambrisko } 905*665484d8SDoug Ambrisko 906*665484d8SDoug Ambrisko /** 907*665484d8SDoug Ambrisko * mrsas_map_request: Map and load data 908*665484d8SDoug Ambrisko * input: Adapter instance soft state 909*665484d8SDoug Ambrisko * Pointer to command packet 910*665484d8SDoug Ambrisko * 911*665484d8SDoug Ambrisko * For data from OS, map and load the data buffer into bus space. The 912*665484d8SDoug Ambrisko * SG list is built in the callback. If the bus dmamap load is not 913*665484d8SDoug Ambrisko * successful, cmd->error_code will contain the error code and a 1 is 914*665484d8SDoug Ambrisko * returned. 915*665484d8SDoug Ambrisko */ 916*665484d8SDoug Ambrisko int mrsas_map_request(struct mrsas_softc *sc, struct mrsas_mpt_cmd *cmd) 917*665484d8SDoug Ambrisko { 918*665484d8SDoug Ambrisko u_int32_t retcode = 0; 919*665484d8SDoug Ambrisko struct cam_sim *sim; 920*665484d8SDoug Ambrisko int flag = BUS_DMA_NOWAIT; 921*665484d8SDoug Ambrisko 922*665484d8SDoug Ambrisko sim = xpt_path_sim(cmd->ccb_ptr->ccb_h.path); 923*665484d8SDoug Ambrisko 924*665484d8SDoug Ambrisko if (cmd->data != NULL) { 925*665484d8SDoug Ambrisko mtx_lock(&sc->io_lock); 926*665484d8SDoug Ambrisko /* Map data buffer into bus space */ 927*665484d8SDoug Ambrisko retcode = bus_dmamap_load(sc->data_tag, cmd->data_dmamap, cmd->data, 928*665484d8SDoug Ambrisko cmd->length, mrsas_data_load_cb, cmd, flag); 929*665484d8SDoug Ambrisko mtx_unlock(&sc->io_lock); 930*665484d8SDoug Ambrisko if (retcode) 931*665484d8SDoug Ambrisko device_printf(sc->mrsas_dev, "bus_dmamap_load(): retcode = %d\n", retcode); 932*665484d8SDoug Ambrisko if (retcode == EINPROGRESS) { 933*665484d8SDoug Ambrisko device_printf(sc->mrsas_dev, "request load in progress\n"); 934*665484d8SDoug Ambrisko mrsas_freeze_simq(cmd, sim); 935*665484d8SDoug Ambrisko } 936*665484d8SDoug Ambrisko } 937*665484d8SDoug Ambrisko if (cmd->error_code) 938*665484d8SDoug Ambrisko return(1); 939*665484d8SDoug Ambrisko return(retcode); 940*665484d8SDoug Ambrisko } 941*665484d8SDoug Ambrisko 942*665484d8SDoug Ambrisko /** 943*665484d8SDoug Ambrisko * mrsas_unmap_request: Unmap and unload data 944*665484d8SDoug Ambrisko * input: Adapter instance soft state 945*665484d8SDoug Ambrisko * Pointer to command packet 946*665484d8SDoug Ambrisko * 947*665484d8SDoug Ambrisko * This function unmaps and unloads data from OS. 948*665484d8SDoug Ambrisko */ 949*665484d8SDoug Ambrisko void mrsas_unmap_request(struct mrsas_softc *sc, struct mrsas_mpt_cmd *cmd) 950*665484d8SDoug Ambrisko { 951*665484d8SDoug Ambrisko if (cmd->data != NULL) { 952*665484d8SDoug Ambrisko if (cmd->flags & MRSAS_DIR_IN) 953*665484d8SDoug Ambrisko bus_dmamap_sync(sc->data_tag, cmd->data_dmamap, BUS_DMASYNC_POSTREAD); 954*665484d8SDoug Ambrisko if (cmd->flags & MRSAS_DIR_OUT) 955*665484d8SDoug Ambrisko bus_dmamap_sync(sc->data_tag, cmd->data_dmamap, BUS_DMASYNC_POSTWRITE); 956*665484d8SDoug Ambrisko mtx_lock(&sc->io_lock); 957*665484d8SDoug Ambrisko bus_dmamap_unload(sc->data_tag, cmd->data_dmamap); 958*665484d8SDoug Ambrisko mtx_unlock(&sc->io_lock); 959*665484d8SDoug Ambrisko } 960*665484d8SDoug Ambrisko } 961*665484d8SDoug Ambrisko 962*665484d8SDoug Ambrisko /** 963*665484d8SDoug Ambrisko * mrsas_data_load_cb: Callback entry point 964*665484d8SDoug Ambrisko * input: Pointer to command packet as argument 965*665484d8SDoug Ambrisko * Pointer to segment 966*665484d8SDoug Ambrisko * Number of segments 967*665484d8SDoug Ambrisko * Error 968*665484d8SDoug Ambrisko * 969*665484d8SDoug Ambrisko * This is the callback function of the bus dma map load. It builds 970*665484d8SDoug Ambrisko * the SG list. 971*665484d8SDoug Ambrisko */ 972*665484d8SDoug Ambrisko static void 973*665484d8SDoug Ambrisko mrsas_data_load_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error) 974*665484d8SDoug Ambrisko { 975*665484d8SDoug Ambrisko struct mrsas_mpt_cmd *cmd = (struct mrsas_mpt_cmd *)arg; 976*665484d8SDoug Ambrisko struct mrsas_softc *sc = cmd->sc; 977*665484d8SDoug Ambrisko MRSAS_RAID_SCSI_IO_REQUEST *io_request; 978*665484d8SDoug Ambrisko pMpi25IeeeSgeChain64_t sgl_ptr; 979*665484d8SDoug Ambrisko int i=0, sg_processed=0; 980*665484d8SDoug Ambrisko 981*665484d8SDoug Ambrisko if (error) 982*665484d8SDoug Ambrisko { 983*665484d8SDoug Ambrisko cmd->error_code = error; 984*665484d8SDoug Ambrisko device_printf(sc->mrsas_dev, "mrsas_data_load_cb: error=%d\n", error); 985*665484d8SDoug Ambrisko if (error == EFBIG) { 986*665484d8SDoug Ambrisko cmd->ccb_ptr->ccb_h.status = CAM_REQ_TOO_BIG; 987*665484d8SDoug Ambrisko return; 988*665484d8SDoug Ambrisko } 989*665484d8SDoug Ambrisko } 990*665484d8SDoug Ambrisko 991*665484d8SDoug Ambrisko if (cmd->flags & MRSAS_DIR_IN) 992*665484d8SDoug Ambrisko bus_dmamap_sync(cmd->sc->data_tag, cmd->data_dmamap, 993*665484d8SDoug Ambrisko BUS_DMASYNC_PREREAD); 994*665484d8SDoug Ambrisko if (cmd->flags & MRSAS_DIR_OUT) 995*665484d8SDoug Ambrisko bus_dmamap_sync(cmd->sc->data_tag, cmd->data_dmamap, 996*665484d8SDoug Ambrisko BUS_DMASYNC_PREWRITE); 997*665484d8SDoug Ambrisko if (nseg > sc->max_num_sge) { 998*665484d8SDoug Ambrisko device_printf(sc->mrsas_dev, "SGE count is too large or 0.\n"); 999*665484d8SDoug Ambrisko return; 1000*665484d8SDoug Ambrisko } 1001*665484d8SDoug Ambrisko 1002*665484d8SDoug Ambrisko io_request = cmd->io_request; 1003*665484d8SDoug Ambrisko sgl_ptr = (pMpi25IeeeSgeChain64_t)&io_request->SGL; 1004*665484d8SDoug Ambrisko 1005*665484d8SDoug Ambrisko if ((sc->device_id == MRSAS_INVADER) || (sc->device_id == MRSAS_FURY)) { 1006*665484d8SDoug Ambrisko pMpi25IeeeSgeChain64_t sgl_ptr_end = sgl_ptr; 1007*665484d8SDoug Ambrisko sgl_ptr_end += sc->max_sge_in_main_msg - 1; 1008*665484d8SDoug Ambrisko sgl_ptr_end->Flags = 0; 1009*665484d8SDoug Ambrisko } 1010*665484d8SDoug Ambrisko 1011*665484d8SDoug Ambrisko if (nseg != 0) { 1012*665484d8SDoug Ambrisko for (i=0; i < nseg; i++) { 1013*665484d8SDoug Ambrisko sgl_ptr->Address = segs[i].ds_addr; 1014*665484d8SDoug Ambrisko sgl_ptr->Length = segs[i].ds_len; 1015*665484d8SDoug Ambrisko sgl_ptr->Flags = 0; 1016*665484d8SDoug Ambrisko if ((sc->device_id == MRSAS_INVADER) || (sc->device_id == MRSAS_FURY)) { 1017*665484d8SDoug Ambrisko if (i == nseg - 1) 1018*665484d8SDoug Ambrisko sgl_ptr->Flags = IEEE_SGE_FLAGS_END_OF_LIST; 1019*665484d8SDoug Ambrisko } 1020*665484d8SDoug Ambrisko sgl_ptr++; 1021*665484d8SDoug Ambrisko sg_processed = i + 1; 1022*665484d8SDoug Ambrisko /* 1023*665484d8SDoug Ambrisko * Prepare chain element 1024*665484d8SDoug Ambrisko */ 1025*665484d8SDoug Ambrisko if ((sg_processed == (sc->max_sge_in_main_msg - 1)) && 1026*665484d8SDoug Ambrisko (nseg > sc->max_sge_in_main_msg)) { 1027*665484d8SDoug Ambrisko pMpi25IeeeSgeChain64_t sg_chain; 1028*665484d8SDoug Ambrisko if ((sc->device_id == MRSAS_INVADER) || (sc->device_id == MRSAS_FURY)) { 1029*665484d8SDoug Ambrisko if ((cmd->io_request->IoFlags & MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH) 1030*665484d8SDoug Ambrisko != MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH) 1031*665484d8SDoug Ambrisko cmd->io_request->ChainOffset = sc->chain_offset_io_request; 1032*665484d8SDoug Ambrisko else 1033*665484d8SDoug Ambrisko cmd->io_request->ChainOffset = 0; 1034*665484d8SDoug Ambrisko } else 1035*665484d8SDoug Ambrisko cmd->io_request->ChainOffset = sc->chain_offset_io_request; 1036*665484d8SDoug Ambrisko sg_chain = sgl_ptr; 1037*665484d8SDoug Ambrisko if ((sc->device_id == MRSAS_INVADER) || (sc->device_id == MRSAS_FURY)) 1038*665484d8SDoug Ambrisko sg_chain->Flags = IEEE_SGE_FLAGS_CHAIN_ELEMENT; 1039*665484d8SDoug Ambrisko else 1040*665484d8SDoug Ambrisko sg_chain->Flags = (IEEE_SGE_FLAGS_CHAIN_ELEMENT | MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR); 1041*665484d8SDoug Ambrisko sg_chain->Length = (sizeof(MPI2_SGE_IO_UNION) * (nseg - sg_processed)); 1042*665484d8SDoug Ambrisko sg_chain->Address = cmd->chain_frame_phys_addr; 1043*665484d8SDoug Ambrisko sgl_ptr = (pMpi25IeeeSgeChain64_t)cmd->chain_frame; 1044*665484d8SDoug Ambrisko } 1045*665484d8SDoug Ambrisko } 1046*665484d8SDoug Ambrisko } 1047*665484d8SDoug Ambrisko cmd->sge_count = nseg; 1048*665484d8SDoug Ambrisko } 1049*665484d8SDoug Ambrisko 1050*665484d8SDoug Ambrisko /** 1051*665484d8SDoug Ambrisko * mrsas_freeze_simq: Freeze SIM queue 1052*665484d8SDoug Ambrisko * input: Pointer to command packet 1053*665484d8SDoug Ambrisko * Pointer to SIM 1054*665484d8SDoug Ambrisko * 1055*665484d8SDoug Ambrisko * This function freezes the sim queue. 1056*665484d8SDoug Ambrisko */ 1057*665484d8SDoug Ambrisko static void mrsas_freeze_simq(struct mrsas_mpt_cmd *cmd, struct cam_sim *sim) 1058*665484d8SDoug Ambrisko { 1059*665484d8SDoug Ambrisko union ccb *ccb = (union ccb *)(cmd->ccb_ptr); 1060*665484d8SDoug Ambrisko 1061*665484d8SDoug Ambrisko xpt_freeze_simq(sim, 1); 1062*665484d8SDoug Ambrisko ccb->ccb_h.status |= CAM_RELEASE_SIMQ; 1063*665484d8SDoug Ambrisko ccb->ccb_h.status |= CAM_REQUEUE_REQ; 1064*665484d8SDoug Ambrisko } 1065*665484d8SDoug Ambrisko 1066*665484d8SDoug Ambrisko void mrsas_xpt_freeze(struct mrsas_softc *sc) { 1067*665484d8SDoug Ambrisko xpt_freeze_simq(sc->sim_0, 1); 1068*665484d8SDoug Ambrisko xpt_freeze_simq(sc->sim_1, 1); 1069*665484d8SDoug Ambrisko } 1070*665484d8SDoug Ambrisko 1071*665484d8SDoug Ambrisko void mrsas_xpt_release(struct mrsas_softc *sc) { 1072*665484d8SDoug Ambrisko xpt_release_simq(sc->sim_0, 1); 1073*665484d8SDoug Ambrisko xpt_release_simq(sc->sim_1, 1); 1074*665484d8SDoug Ambrisko } 1075*665484d8SDoug Ambrisko 1076*665484d8SDoug Ambrisko /** 1077*665484d8SDoug Ambrisko * mrsas_cmd_done: Perform remaining command completion 1078*665484d8SDoug Ambrisko * input: Adapter instance soft state 1079*665484d8SDoug Ambrisko * Pointer to command packet 1080*665484d8SDoug Ambrisko * 1081*665484d8SDoug Ambrisko * This function calls ummap request and releases the MPT command. 1082*665484d8SDoug Ambrisko */ 1083*665484d8SDoug Ambrisko void mrsas_cmd_done(struct mrsas_softc *sc, struct mrsas_mpt_cmd *cmd) 1084*665484d8SDoug Ambrisko { 1085*665484d8SDoug Ambrisko callout_stop(&cmd->cm_callout); 1086*665484d8SDoug Ambrisko mrsas_unmap_request(sc, cmd); 1087*665484d8SDoug Ambrisko mtx_lock(&sc->sim_lock); 1088*665484d8SDoug Ambrisko xpt_done(cmd->ccb_ptr); 1089*665484d8SDoug Ambrisko cmd->ccb_ptr = NULL; 1090*665484d8SDoug Ambrisko mtx_unlock(&sc->sim_lock); 1091*665484d8SDoug Ambrisko mrsas_release_mpt_cmd(cmd); 1092*665484d8SDoug Ambrisko } 1093*665484d8SDoug Ambrisko 1094*665484d8SDoug Ambrisko /** 1095*665484d8SDoug Ambrisko * mrsas_poll: Polling entry point 1096*665484d8SDoug Ambrisko * input: Pointer to SIM 1097*665484d8SDoug Ambrisko * 1098*665484d8SDoug Ambrisko * This is currently a stub function. 1099*665484d8SDoug Ambrisko */ 1100*665484d8SDoug Ambrisko static void mrsas_poll(struct cam_sim *sim) 1101*665484d8SDoug Ambrisko { 1102*665484d8SDoug Ambrisko struct mrsas_softc *sc = (struct mrsas_softc *)cam_sim_softc(sim); 1103*665484d8SDoug Ambrisko mrsas_isr((void *) sc); 1104*665484d8SDoug Ambrisko } 1105*665484d8SDoug Ambrisko 1106*665484d8SDoug Ambrisko /* 1107*665484d8SDoug Ambrisko * mrsas_bus_scan: Perform bus scan 1108*665484d8SDoug Ambrisko * input: Adapter instance soft state 1109*665484d8SDoug Ambrisko * 1110*665484d8SDoug Ambrisko * This mrsas_bus_scan function is needed for FreeBSD 7.x. Also, it should 1111*665484d8SDoug Ambrisko * not be called in FreeBSD 8.x and later versions, where the bus scan is 1112*665484d8SDoug Ambrisko * automatic. 1113*665484d8SDoug Ambrisko */ 1114*665484d8SDoug Ambrisko int mrsas_bus_scan(struct mrsas_softc *sc) 1115*665484d8SDoug Ambrisko { 1116*665484d8SDoug Ambrisko union ccb *ccb_0; 1117*665484d8SDoug Ambrisko union ccb *ccb_1; 1118*665484d8SDoug Ambrisko 1119*665484d8SDoug Ambrisko mtx_lock(&sc->sim_lock); 1120*665484d8SDoug Ambrisko if ((ccb_0 = xpt_alloc_ccb()) == NULL) { 1121*665484d8SDoug Ambrisko mtx_unlock(&sc->sim_lock); 1122*665484d8SDoug Ambrisko return(ENOMEM); 1123*665484d8SDoug Ambrisko } 1124*665484d8SDoug Ambrisko 1125*665484d8SDoug Ambrisko if ((ccb_1 = xpt_alloc_ccb()) == NULL) { 1126*665484d8SDoug Ambrisko xpt_free_ccb(ccb_0); 1127*665484d8SDoug Ambrisko mtx_unlock(&sc->sim_lock); 1128*665484d8SDoug Ambrisko return(ENOMEM); 1129*665484d8SDoug Ambrisko } 1130*665484d8SDoug Ambrisko 1131*665484d8SDoug Ambrisko if (xpt_create_path(&ccb_0->ccb_h.path, xpt_periph, cam_sim_path(sc->sim_0), 1132*665484d8SDoug Ambrisko CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP){ 1133*665484d8SDoug Ambrisko xpt_free_ccb(ccb_0); 1134*665484d8SDoug Ambrisko xpt_free_ccb(ccb_1); 1135*665484d8SDoug Ambrisko mtx_unlock(&sc->sim_lock); 1136*665484d8SDoug Ambrisko return(EIO); 1137*665484d8SDoug Ambrisko } 1138*665484d8SDoug Ambrisko 1139*665484d8SDoug Ambrisko if (xpt_create_path(&ccb_1->ccb_h.path, xpt_periph, cam_sim_path(sc->sim_1), 1140*665484d8SDoug Ambrisko CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP){ 1141*665484d8SDoug Ambrisko xpt_free_ccb(ccb_0); 1142*665484d8SDoug Ambrisko xpt_free_ccb(ccb_1); 1143*665484d8SDoug Ambrisko mtx_unlock(&sc->sim_lock); 1144*665484d8SDoug Ambrisko return(EIO); 1145*665484d8SDoug Ambrisko } 1146*665484d8SDoug Ambrisko 1147*665484d8SDoug Ambrisko xpt_rescan(ccb_0); 1148*665484d8SDoug Ambrisko xpt_rescan(ccb_1); 1149*665484d8SDoug Ambrisko mtx_unlock(&sc->sim_lock); 1150*665484d8SDoug Ambrisko 1151*665484d8SDoug Ambrisko return(0); 1152*665484d8SDoug Ambrisko } 1153*665484d8SDoug Ambrisko 1154*665484d8SDoug Ambrisko /* 1155*665484d8SDoug Ambrisko * mrsas_bus_scan_sim: Perform bus scan per SIM 1156*665484d8SDoug Ambrisko * input: Adapter instance soft state 1157*665484d8SDoug Ambrisko * This function will be called from Event handler 1158*665484d8SDoug Ambrisko * on LD creation/deletion, JBOD on/off. 1159*665484d8SDoug Ambrisko */ 1160*665484d8SDoug Ambrisko int mrsas_bus_scan_sim(struct mrsas_softc *sc, struct cam_sim *sim) 1161*665484d8SDoug Ambrisko { 1162*665484d8SDoug Ambrisko union ccb *ccb; 1163*665484d8SDoug Ambrisko 1164*665484d8SDoug Ambrisko mtx_lock(&sc->sim_lock); 1165*665484d8SDoug Ambrisko if ((ccb = xpt_alloc_ccb()) == NULL) { 1166*665484d8SDoug Ambrisko mtx_unlock(&sc->sim_lock); 1167*665484d8SDoug Ambrisko return(ENOMEM); 1168*665484d8SDoug Ambrisko } 1169*665484d8SDoug Ambrisko if (xpt_create_path(&ccb->ccb_h.path, xpt_periph, cam_sim_path(sim), 1170*665484d8SDoug Ambrisko CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP){ 1171*665484d8SDoug Ambrisko xpt_free_ccb(ccb); 1172*665484d8SDoug Ambrisko mtx_unlock(&sc->sim_lock); 1173*665484d8SDoug Ambrisko return(EIO); 1174*665484d8SDoug Ambrisko } 1175*665484d8SDoug Ambrisko xpt_rescan(ccb); 1176*665484d8SDoug Ambrisko mtx_unlock(&sc->sim_lock); 1177*665484d8SDoug Ambrisko 1178*665484d8SDoug Ambrisko return(0); 1179*665484d8SDoug Ambrisko } 1180