12d1d418eSSumit Saxena /* 22d1d418eSSumit Saxena * SPDX-License-Identifier: BSD-2-Clause 32d1d418eSSumit Saxena * 4945c3ce4SChandrakanth patil * Copyright (c) 2020-2024, Broadcom Inc. All rights reserved. 52d1d418eSSumit Saxena * Support: <fbsd-storage-driver.pdl@broadcom.com> 62d1d418eSSumit Saxena * 72d1d418eSSumit Saxena * Authors: Sumit Saxena <sumit.saxena@broadcom.com> 82d1d418eSSumit Saxena * Chandrakanth Patil <chandrakanth.patil@broadcom.com> 92d1d418eSSumit Saxena * 102d1d418eSSumit Saxena * Redistribution and use in source and binary forms, with or without 112d1d418eSSumit Saxena * modification, are permitted provided that the following conditions are 122d1d418eSSumit Saxena * met: 132d1d418eSSumit Saxena * 142d1d418eSSumit Saxena * 1. Redistributions of source code must retain the above copyright notice, 152d1d418eSSumit Saxena * this list of conditions and the following disclaimer. 162d1d418eSSumit Saxena * 2. Redistributions in binary form must reproduce the above copyright notice, 172d1d418eSSumit Saxena * this list of conditions and the following disclaimer in the documentation and/or other 182d1d418eSSumit Saxena * materials provided with the distribution. 192d1d418eSSumit Saxena * 3. Neither the name of the Broadcom Inc. nor the names of its contributors 202d1d418eSSumit Saxena * may be used to endorse or promote products derived from this software without 212d1d418eSSumit Saxena * specific prior written permission. 222d1d418eSSumit Saxena * 232d1d418eSSumit Saxena * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 242d1d418eSSumit Saxena * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 252d1d418eSSumit Saxena * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 262d1d418eSSumit Saxena * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 272d1d418eSSumit Saxena * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 282d1d418eSSumit Saxena * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 292d1d418eSSumit Saxena * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 302d1d418eSSumit Saxena * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 312d1d418eSSumit Saxena * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 322d1d418eSSumit Saxena * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 332d1d418eSSumit Saxena * POSSIBILITY OF SUCH DAMAGE. 342d1d418eSSumit Saxena * 352d1d418eSSumit Saxena * The views and conclusions contained in the software and documentation are 362d1d418eSSumit Saxena * those of the authors and should not be interpreted as representing 372d1d418eSSumit Saxena * official policies,either expressed or implied, of the FreeBSD Project. 382d1d418eSSumit Saxena * 392d1d418eSSumit Saxena * Mail to: Broadcom Inc 1320 Ridder Park Dr, San Jose, CA 95131 402d1d418eSSumit Saxena * 412d1d418eSSumit Saxena * Broadcom Inc. (Broadcom) MPI3MR Adapter FreeBSD 422d1d418eSSumit Saxena */ 432d1d418eSSumit Saxena 442d1d418eSSumit Saxena #include <sys/types.h> 452d1d418eSSumit Saxena #include <sys/param.h> 462d1d418eSSumit Saxena #include <sys/systm.h> 472d1d418eSSumit Saxena #include <sys/kernel.h> 482d1d418eSSumit Saxena #include <sys/selinfo.h> 492d1d418eSSumit Saxena #include <sys/module.h> 502d1d418eSSumit Saxena #include <sys/bus.h> 512d1d418eSSumit Saxena #include <sys/conf.h> 522d1d418eSSumit Saxena #include <sys/bio.h> 532d1d418eSSumit Saxena #include <sys/malloc.h> 542d1d418eSSumit Saxena #include <sys/uio.h> 552d1d418eSSumit Saxena #include <sys/sysctl.h> 562d1d418eSSumit Saxena #include <sys/endian.h> 572d1d418eSSumit Saxena #include <sys/queue.h> 582d1d418eSSumit Saxena #include <sys/kthread.h> 592d1d418eSSumit Saxena #include <sys/taskqueue.h> 602d1d418eSSumit Saxena #include <sys/sbuf.h> 612d1d418eSSumit Saxena 622d1d418eSSumit Saxena #include <machine/bus.h> 632d1d418eSSumit Saxena #include <machine/resource.h> 642d1d418eSSumit Saxena #include <sys/rman.h> 652d1d418eSSumit Saxena 662d1d418eSSumit Saxena #include <machine/stdarg.h> 672d1d418eSSumit Saxena 682d1d418eSSumit Saxena #include <cam/cam.h> 692d1d418eSSumit Saxena #include <cam/cam_ccb.h> 702d1d418eSSumit Saxena #include <cam/cam_debug.h> 712d1d418eSSumit Saxena #include <cam/cam_sim.h> 722d1d418eSSumit Saxena #include <cam/cam_xpt_sim.h> 732d1d418eSSumit Saxena #include <cam/cam_xpt_periph.h> 742d1d418eSSumit Saxena #include <cam/cam_periph.h> 752d1d418eSSumit Saxena #include <cam/scsi/scsi_all.h> 762d1d418eSSumit Saxena #include <cam/scsi/scsi_message.h> 772d1d418eSSumit Saxena #include <cam/scsi/smp_all.h> 782d1d418eSSumit Saxena 792d1d418eSSumit Saxena #include <dev/nvme/nvme.h> 802d1d418eSSumit Saxena #include "mpi/mpi30_api.h" 812d1d418eSSumit Saxena #include "mpi3mr_cam.h" 822d1d418eSSumit Saxena #include "mpi3mr.h" 832d1d418eSSumit Saxena #include <sys/time.h> /* XXX for pcpu.h */ 842d1d418eSSumit Saxena #include <sys/pcpu.h> /* XXX for PCPU_GET */ 853f3a1554SChandrakanth patil #include <asm/unaligned.h> 862d1d418eSSumit Saxena 872d1d418eSSumit Saxena #define smp_processor_id() PCPU_GET(cpuid) 882d1d418eSSumit Saxena 893208a189SWarner Losh static void 903208a189SWarner Losh mpi3mr_enqueue_request(struct mpi3mr_softc *sc, struct mpi3mr_cmd *cm); 913208a189SWarner Losh static void 922d1d418eSSumit Saxena mpi3mr_map_request(struct mpi3mr_softc *sc, struct mpi3mr_cmd *cm); 932d1d418eSSumit Saxena void 942d1d418eSSumit Saxena mpi3mr_release_simq_reinit(struct mpi3mr_cam_softc *cam_sc); 952d1d418eSSumit Saxena static void 962d1d418eSSumit Saxena mpi3mr_freeup_events(struct mpi3mr_softc *sc); 972d1d418eSSumit Saxena 982d1d418eSSumit Saxena extern int 992d1d418eSSumit Saxena mpi3mr_register_events(struct mpi3mr_softc *sc); 1002d1d418eSSumit Saxena extern void mpi3mr_add_sg_single(void *paddr, U8 flags, U32 length, 1012d1d418eSSumit Saxena bus_addr_t dma_addr); 1022d1d418eSSumit Saxena 1032d1d418eSSumit Saxena static U32 event_count; 1042d1d418eSSumit Saxena 1053f3a1554SChandrakanth patil static 1063f3a1554SChandrakanth patil inline void mpi3mr_divert_ws(Mpi3SCSIIORequest_t *req, 1073f3a1554SChandrakanth patil struct ccb_scsiio *csio, 1083f3a1554SChandrakanth patil U16 ws_len) 1093f3a1554SChandrakanth patil { 1103f3a1554SChandrakanth patil U8 unmap = 0, ndob = 0; 1113f3a1554SChandrakanth patil U32 num_blocks = 0; 1123f3a1554SChandrakanth patil U8 opcode = scsiio_cdb_ptr(csio)[0]; 1133f3a1554SChandrakanth patil U16 service_action = ((scsiio_cdb_ptr(csio)[8] << 8) | scsiio_cdb_ptr(csio)[9]); 1143f3a1554SChandrakanth patil 1153f3a1554SChandrakanth patil 1163f3a1554SChandrakanth patil if (opcode == WRITE_SAME_16 || 1173f3a1554SChandrakanth patil (opcode == VARIABLE_LEN_CDB && 1183f3a1554SChandrakanth patil service_action == WRITE_SAME_32)) { 1193f3a1554SChandrakanth patil 1203f3a1554SChandrakanth patil int unmap_ndob_index = (opcode == WRITE_SAME_16) ? 1 : 10; 1213f3a1554SChandrakanth patil 1223f3a1554SChandrakanth patil unmap = scsiio_cdb_ptr(csio)[unmap_ndob_index] & 0x08; 1233f3a1554SChandrakanth patil ndob = scsiio_cdb_ptr(csio)[unmap_ndob_index] & 0x01; 1243f3a1554SChandrakanth patil num_blocks = get_unaligned_be32(scsiio_cdb_ptr(csio) + 1253f3a1554SChandrakanth patil ((opcode == WRITE_SAME_16) ? 10 : 28)); 1263f3a1554SChandrakanth patil 1273f3a1554SChandrakanth patil /* Check conditions for diversion to firmware */ 1283f3a1554SChandrakanth patil if (unmap && ndob && num_blocks > ws_len) { 1293f3a1554SChandrakanth patil req->MsgFlags |= MPI3_SCSIIO_MSGFLAGS_DIVERT_TO_FIRMWARE; 1303f3a1554SChandrakanth patil req->Flags = htole32(le32toh(req->Flags) | 1313f3a1554SChandrakanth patil MPI3_SCSIIO_FLAGS_DIVERT_REASON_WRITE_SAME_TOO_LARGE); 1323f3a1554SChandrakanth patil } 1333f3a1554SChandrakanth patil } 1343f3a1554SChandrakanth patil } 1353f3a1554SChandrakanth patil 1362d1d418eSSumit Saxena static void mpi3mr_prepare_sgls(void *arg, 1372d1d418eSSumit Saxena bus_dma_segment_t *segs, int nsegs, int error) 1382d1d418eSSumit Saxena { 1392d1d418eSSumit Saxena struct mpi3mr_softc *sc; 1402d1d418eSSumit Saxena struct mpi3mr_cmd *cm; 1412d1d418eSSumit Saxena u_int i; 1422d1d418eSSumit Saxena bus_addr_t chain_dma; 1432d1d418eSSumit Saxena void *chain; 1442d1d418eSSumit Saxena U8 *sg_local; 1452d1d418eSSumit Saxena U32 chain_length; 1462d1d418eSSumit Saxena int sges_left; 1472d1d418eSSumit Saxena U32 sges_in_segment; 1482d1d418eSSumit Saxena U8 simple_sgl_flags; 1492d1d418eSSumit Saxena U8 simple_sgl_flags_last; 1502d1d418eSSumit Saxena U8 last_chain_sgl_flags; 1512d1d418eSSumit Saxena struct mpi3mr_chain *chain_req; 1522d1d418eSSumit Saxena Mpi3SCSIIORequest_t *scsiio_req; 1533208a189SWarner Losh union ccb *ccb; 1542d1d418eSSumit Saxena 1552d1d418eSSumit Saxena cm = (struct mpi3mr_cmd *)arg; 1562d1d418eSSumit Saxena sc = cm->sc; 1572d1d418eSSumit Saxena scsiio_req = (Mpi3SCSIIORequest_t *) &cm->io_request; 1583208a189SWarner Losh ccb = cm->ccb; 1592d1d418eSSumit Saxena 1602d1d418eSSumit Saxena if (error) { 1612d1d418eSSumit Saxena device_printf(sc->mpi3mr_dev, "%s: error=%d\n",__func__, error); 1622d1d418eSSumit Saxena if (error == EFBIG) { 1633208a189SWarner Losh mpi3mr_set_ccbstatus(ccb, CAM_REQ_TOO_BIG); 1643208a189SWarner Losh } else { 1653208a189SWarner Losh mpi3mr_set_ccbstatus(ccb, CAM_REQ_CMP_ERR); 1662d1d418eSSumit Saxena } 1673208a189SWarner Losh mpi3mr_release_command(cm); 1683208a189SWarner Losh xpt_done(ccb); 1693208a189SWarner Losh return; 1702d1d418eSSumit Saxena } 1712d1d418eSSumit Saxena 1722d1d418eSSumit Saxena if (cm->data_dir == MPI3MR_READ) 1732d1d418eSSumit Saxena bus_dmamap_sync(sc->buffer_dmat, cm->dmamap, 1742d1d418eSSumit Saxena BUS_DMASYNC_PREREAD); 1752d1d418eSSumit Saxena if (cm->data_dir == MPI3MR_WRITE) 1762d1d418eSSumit Saxena bus_dmamap_sync(sc->buffer_dmat, cm->dmamap, 1772d1d418eSSumit Saxena BUS_DMASYNC_PREWRITE); 1783208a189SWarner Losh 1793208a189SWarner Losh KASSERT(nsegs <= MPI3MR_SG_DEPTH && nsegs > 0, 1803208a189SWarner Losh ("%s: bad SGE count: %d\n", device_get_nameunit(sc->mpi3mr_dev), nsegs)); 1812361a005SWarner Losh KASSERT(scsiio_req->DataLength != 0, 1822361a005SWarner Losh ("%s: Data segments (%d), but DataLength == 0\n", 1832361a005SWarner Losh device_get_nameunit(sc->mpi3mr_dev), nsegs)); 1842d1d418eSSumit Saxena 1852d1d418eSSumit Saxena simple_sgl_flags = MPI3_SGE_FLAGS_ELEMENT_TYPE_SIMPLE | 1862d1d418eSSumit Saxena MPI3_SGE_FLAGS_DLAS_SYSTEM; 1872d1d418eSSumit Saxena simple_sgl_flags_last = simple_sgl_flags | 1882d1d418eSSumit Saxena MPI3_SGE_FLAGS_END_OF_LIST; 1892d1d418eSSumit Saxena last_chain_sgl_flags = MPI3_SGE_FLAGS_ELEMENT_TYPE_LAST_CHAIN | 1902d1d418eSSumit Saxena MPI3_SGE_FLAGS_DLAS_SYSTEM; 1912d1d418eSSumit Saxena 1922d1d418eSSumit Saxena sg_local = (U8 *)&scsiio_req->SGL; 1932d1d418eSSumit Saxena 1942d1d418eSSumit Saxena sges_left = nsegs; 1952d1d418eSSumit Saxena 1962d1d418eSSumit Saxena sges_in_segment = (sc->facts.op_req_sz - 1972d1d418eSSumit Saxena offsetof(Mpi3SCSIIORequest_t, SGL))/sizeof(Mpi3SGESimple_t); 1982d1d418eSSumit Saxena 1992d1d418eSSumit Saxena i = 0; 2002d1d418eSSumit Saxena 2012d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_TRACE, "SGE count: %d IO size: %d\n", 2022d1d418eSSumit Saxena nsegs, scsiio_req->DataLength); 2032d1d418eSSumit Saxena 2042d1d418eSSumit Saxena if (sges_left <= sges_in_segment) 2052d1d418eSSumit Saxena goto fill_in_last_segment; 2062d1d418eSSumit Saxena 2072d1d418eSSumit Saxena /* fill in main message segment when there is a chain following */ 2082d1d418eSSumit Saxena while (sges_in_segment > 1) { 2092d1d418eSSumit Saxena mpi3mr_add_sg_single(sg_local, simple_sgl_flags, 2102d1d418eSSumit Saxena segs[i].ds_len, segs[i].ds_addr); 2112d1d418eSSumit Saxena sg_local += sizeof(Mpi3SGESimple_t); 2122d1d418eSSumit Saxena sges_left--; 2132d1d418eSSumit Saxena sges_in_segment--; 2142d1d418eSSumit Saxena i++; 2152d1d418eSSumit Saxena } 2162d1d418eSSumit Saxena 2172d1d418eSSumit Saxena chain_req = &sc->chain_sgl_list[cm->hosttag]; 2182d1d418eSSumit Saxena 2192d1d418eSSumit Saxena chain = chain_req->buf; 2202d1d418eSSumit Saxena chain_dma = chain_req->buf_phys; 2212d1d418eSSumit Saxena memset(chain_req->buf, 0, PAGE_SIZE); 2222d1d418eSSumit Saxena sges_in_segment = sges_left; 2232d1d418eSSumit Saxena chain_length = sges_in_segment * sizeof(Mpi3SGESimple_t); 2242d1d418eSSumit Saxena 2252d1d418eSSumit Saxena mpi3mr_add_sg_single(sg_local, last_chain_sgl_flags, 2262d1d418eSSumit Saxena chain_length, chain_dma); 2272d1d418eSSumit Saxena 2282d1d418eSSumit Saxena sg_local = chain; 2292d1d418eSSumit Saxena 2302d1d418eSSumit Saxena fill_in_last_segment: 2312d1d418eSSumit Saxena while (sges_left > 0) { 2322d1d418eSSumit Saxena if (sges_left == 1) 2332d1d418eSSumit Saxena mpi3mr_add_sg_single(sg_local, 2342d1d418eSSumit Saxena simple_sgl_flags_last, segs[i].ds_len, 2352d1d418eSSumit Saxena segs[i].ds_addr); 2362d1d418eSSumit Saxena else 2372d1d418eSSumit Saxena mpi3mr_add_sg_single(sg_local, simple_sgl_flags, 2382d1d418eSSumit Saxena segs[i].ds_len, segs[i].ds_addr); 2392d1d418eSSumit Saxena sg_local += sizeof(Mpi3SGESimple_t); 2402d1d418eSSumit Saxena sges_left--; 2412d1d418eSSumit Saxena i++; 2422d1d418eSSumit Saxena } 2432d1d418eSSumit Saxena 2443208a189SWarner Losh /* 2453208a189SWarner Losh * Now that we've created the sgls, we send the request to the device. 2463208a189SWarner Losh * Unlike in Linux, dmaload isn't guaranteed to load every time, but 2473208a189SWarner Losh * this function is always called when the resources are available, so 2483208a189SWarner Losh * we can send the request to hardware here always. mpi3mr_map_request 2493208a189SWarner Losh * knows about this quirk and will only take evasive action when an 2503208a189SWarner Losh * error other than EINPROGRESS is returned from dmaload. 2513208a189SWarner Losh */ 2523208a189SWarner Losh mpi3mr_enqueue_request(sc, cm); 2533208a189SWarner Losh 2542d1d418eSSumit Saxena return; 2552d1d418eSSumit Saxena } 2562d1d418eSSumit Saxena 2573208a189SWarner Losh static void 2582d1d418eSSumit Saxena mpi3mr_map_request(struct mpi3mr_softc *sc, struct mpi3mr_cmd *cm) 2592d1d418eSSumit Saxena { 2602d1d418eSSumit Saxena u_int32_t retcode = 0; 2613208a189SWarner Losh union ccb *ccb; 2622d1d418eSSumit Saxena 2633208a189SWarner Losh ccb = cm->ccb; 2642d1d418eSSumit Saxena if (cm->data != NULL) { 2652d1d418eSSumit Saxena mtx_lock(&sc->io_lock); 2662d1d418eSSumit Saxena /* Map data buffer into bus space */ 2672d1d418eSSumit Saxena retcode = bus_dmamap_load_ccb(sc->buffer_dmat, cm->dmamap, 2683208a189SWarner Losh ccb, mpi3mr_prepare_sgls, cm, 0); 2692d1d418eSSumit Saxena mtx_unlock(&sc->io_lock); 2703208a189SWarner Losh if (retcode != 0 && retcode != EINPROGRESS) { 2713208a189SWarner Losh device_printf(sc->mpi3mr_dev, 2723208a189SWarner Losh "bus_dmamap_load(): retcode = %d\n", retcode); 2733208a189SWarner Losh /* 2743208a189SWarner Losh * Any other error means prepare_sgls wasn't called, and 2753208a189SWarner Losh * will never be called, so we have to mop up. This error 2763208a189SWarner Losh * should never happen, though. 2773208a189SWarner Losh */ 2783208a189SWarner Losh mpi3mr_set_ccbstatus(ccb, CAM_REQ_CMP_ERR); 2793208a189SWarner Losh mpi3mr_release_command(cm); 2803208a189SWarner Losh xpt_done(ccb); 2812d1d418eSSumit Saxena } 2823208a189SWarner Losh } else { 2833208a189SWarner Losh /* 2843208a189SWarner Losh * No data, we enqueue it directly here. 2853208a189SWarner Losh */ 2863208a189SWarner Losh mpi3mr_enqueue_request(sc, cm); 2872d1d418eSSumit Saxena } 2882d1d418eSSumit Saxena } 2892d1d418eSSumit Saxena 2902d1d418eSSumit Saxena void 2912d1d418eSSumit Saxena mpi3mr_unmap_request(struct mpi3mr_softc *sc, struct mpi3mr_cmd *cmd) 2922d1d418eSSumit Saxena { 2932d1d418eSSumit Saxena if (cmd->data != NULL) { 2942d1d418eSSumit Saxena if (cmd->data_dir == MPI3MR_READ) 2952d1d418eSSumit Saxena bus_dmamap_sync(sc->buffer_dmat, cmd->dmamap, BUS_DMASYNC_POSTREAD); 2962d1d418eSSumit Saxena if (cmd->data_dir == MPI3MR_WRITE) 2972d1d418eSSumit Saxena bus_dmamap_sync(sc->buffer_dmat, cmd->dmamap, BUS_DMASYNC_POSTWRITE); 2982d1d418eSSumit Saxena mtx_lock(&sc->io_lock); 2992d1d418eSSumit Saxena bus_dmamap_unload(sc->buffer_dmat, cmd->dmamap); 3002d1d418eSSumit Saxena mtx_unlock(&sc->io_lock); 3012d1d418eSSumit Saxena } 3022d1d418eSSumit Saxena } 3032d1d418eSSumit Saxena 3042d1d418eSSumit Saxena /** 3052d1d418eSSumit Saxena * mpi3mr_allow_unmap_to_fw - Whether an unmap is allowed to fw 3062d1d418eSSumit Saxena * @sc: Adapter instance reference 3072d1d418eSSumit Saxena * @ccb: SCSI Command reference 3082d1d418eSSumit Saxena * 3092d1d418eSSumit Saxena * The controller hardware cannot handle certain unmap commands 3102d1d418eSSumit Saxena * for NVMe drives, this routine checks those and return true 3112d1d418eSSumit Saxena * and completes the SCSI command with proper status and sense 3122d1d418eSSumit Saxena * data. 3132d1d418eSSumit Saxena * 3142d1d418eSSumit Saxena * Return: TRUE for allowed unmap, FALSE otherwise. 3152d1d418eSSumit Saxena */ 3162d1d418eSSumit Saxena static bool mpi3mr_allow_unmap_to_fw(struct mpi3mr_softc *sc, 3172d1d418eSSumit Saxena union ccb *ccb) 3182d1d418eSSumit Saxena { 3192d1d418eSSumit Saxena struct ccb_scsiio *csio; 3202d1d418eSSumit Saxena uint16_t param_list_len, block_desc_len, trunc_param_len = 0; 3212d1d418eSSumit Saxena 3222d1d418eSSumit Saxena csio = &ccb->csio; 3232d1d418eSSumit Saxena param_list_len = (uint16_t) ((scsiio_cdb_ptr(csio)[7] << 8) | scsiio_cdb_ptr(csio)[8]); 3242d1d418eSSumit Saxena 3252d1d418eSSumit Saxena switch(pci_get_revid(sc->mpi3mr_dev)) { 3262d1d418eSSumit Saxena case SAS4116_CHIP_REV_A0: 3272d1d418eSSumit Saxena if (!param_list_len) { 3282d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_ERROR, 3292d1d418eSSumit Saxena "%s: CDB received with zero parameter length\n", 3302d1d418eSSumit Saxena __func__); 3312d1d418eSSumit Saxena mpi3mr_print_cdb(ccb); 3322d1d418eSSumit Saxena mpi3mr_set_ccbstatus(ccb, CAM_REQ_CMP); 3332d1d418eSSumit Saxena xpt_done(ccb); 3342d1d418eSSumit Saxena return false; 3352d1d418eSSumit Saxena } 3362d1d418eSSumit Saxena 3372d1d418eSSumit Saxena if (param_list_len < 24) { 3382d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_ERROR, 3392d1d418eSSumit Saxena "%s: CDB received with invalid param_list_len: %d\n", 3402d1d418eSSumit Saxena __func__, param_list_len); 3412d1d418eSSumit Saxena mpi3mr_print_cdb(ccb); 3422d1d418eSSumit Saxena scsi_set_sense_data(&ccb->csio.sense_data, 3432d1d418eSSumit Saxena /*sense_format*/ SSD_TYPE_FIXED, 3442d1d418eSSumit Saxena /*current_error*/ 1, 3452d1d418eSSumit Saxena /*sense_key*/ SSD_KEY_ILLEGAL_REQUEST, 3462d1d418eSSumit Saxena /*asc*/ 0x1A, 3472d1d418eSSumit Saxena /*ascq*/ 0x00, 3482d1d418eSSumit Saxena /*extra args*/ SSD_ELEM_NONE); 3492d1d418eSSumit Saxena ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND; 3502d1d418eSSumit Saxena ccb->ccb_h.status = 3512d1d418eSSumit Saxena CAM_SCSI_STATUS_ERROR | 3522d1d418eSSumit Saxena CAM_AUTOSNS_VALID; 3532d1d418eSSumit Saxena return false; 3542d1d418eSSumit Saxena } 3552d1d418eSSumit Saxena 3562d1d418eSSumit Saxena if (param_list_len != csio->dxfer_len) { 3572d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_ERROR, 3582d1d418eSSumit Saxena "%s: CDB received with param_list_len: %d bufflen: %d\n", 3592d1d418eSSumit Saxena __func__, param_list_len, csio->dxfer_len); 3602d1d418eSSumit Saxena mpi3mr_print_cdb(ccb); 3612d1d418eSSumit Saxena scsi_set_sense_data(&ccb->csio.sense_data, 3622d1d418eSSumit Saxena /*sense_format*/ SSD_TYPE_FIXED, 3632d1d418eSSumit Saxena /*current_error*/ 1, 3642d1d418eSSumit Saxena /*sense_key*/ SSD_KEY_ILLEGAL_REQUEST, 3652d1d418eSSumit Saxena /*asc*/ 0x1A, 3662d1d418eSSumit Saxena /*ascq*/ 0x00, 3672d1d418eSSumit Saxena /*extra args*/ SSD_ELEM_NONE); 3682d1d418eSSumit Saxena ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND; 3692d1d418eSSumit Saxena ccb->ccb_h.status = 3702d1d418eSSumit Saxena CAM_SCSI_STATUS_ERROR | 3712d1d418eSSumit Saxena CAM_AUTOSNS_VALID; 3722d1d418eSSumit Saxena xpt_done(ccb); 3732d1d418eSSumit Saxena return false; 3742d1d418eSSumit Saxena } 3752d1d418eSSumit Saxena 3762d1d418eSSumit Saxena block_desc_len = (uint16_t) (csio->data_ptr[2] << 8 | csio->data_ptr[3]); 3772d1d418eSSumit Saxena 3782d1d418eSSumit Saxena if (block_desc_len < 16) { 3792d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_ERROR, 3802d1d418eSSumit Saxena "%s: Invalid descriptor length in param list: %d\n", 3812d1d418eSSumit Saxena __func__, block_desc_len); 3822d1d418eSSumit Saxena mpi3mr_print_cdb(ccb); 3832d1d418eSSumit Saxena scsi_set_sense_data(&ccb->csio.sense_data, 3842d1d418eSSumit Saxena /*sense_format*/ SSD_TYPE_FIXED, 3852d1d418eSSumit Saxena /*current_error*/ 1, 3862d1d418eSSumit Saxena /*sense_key*/ SSD_KEY_ILLEGAL_REQUEST, 3872d1d418eSSumit Saxena /*asc*/ 0x26, 3882d1d418eSSumit Saxena /*ascq*/ 0x00, 3892d1d418eSSumit Saxena /*extra args*/ SSD_ELEM_NONE); 3902d1d418eSSumit Saxena ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND; 3912d1d418eSSumit Saxena ccb->ccb_h.status = 3922d1d418eSSumit Saxena CAM_SCSI_STATUS_ERROR | 3932d1d418eSSumit Saxena CAM_AUTOSNS_VALID; 3942d1d418eSSumit Saxena xpt_done(ccb); 3952d1d418eSSumit Saxena return false; 3962d1d418eSSumit Saxena } 3972d1d418eSSumit Saxena 3982d1d418eSSumit Saxena if (param_list_len > (block_desc_len + 8)) { 3992d1d418eSSumit Saxena mpi3mr_print_cdb(ccb); 4002d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_INFO, 4012d1d418eSSumit Saxena "%s: Truncating param_list_len(%d) to block_desc_len+8(%d)\n", 4022d1d418eSSumit Saxena __func__, param_list_len, (block_desc_len + 8)); 4032d1d418eSSumit Saxena param_list_len = block_desc_len + 8; 4042d1d418eSSumit Saxena scsiio_cdb_ptr(csio)[7] = (param_list_len >> 8) | 0xff; 4052d1d418eSSumit Saxena scsiio_cdb_ptr(csio)[8] = param_list_len | 0xff; 4062d1d418eSSumit Saxena mpi3mr_print_cdb(ccb); 4072d1d418eSSumit Saxena } 4082d1d418eSSumit Saxena break; 4092d1d418eSSumit Saxena 4102d1d418eSSumit Saxena case SAS4116_CHIP_REV_B0: 4112d1d418eSSumit Saxena if ((param_list_len > 24) && ((param_list_len - 8) & 0xF)) { 4122d1d418eSSumit Saxena trunc_param_len -= (param_list_len - 8) & 0xF; 4132d1d418eSSumit Saxena mpi3mr_print_cdb(ccb); 4142d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_INFO, 4152d1d418eSSumit Saxena "%s: Truncating param_list_len from (%d) to (%d)\n", 4162d1d418eSSumit Saxena __func__, param_list_len, trunc_param_len); 4172d1d418eSSumit Saxena scsiio_cdb_ptr(csio)[7] = (param_list_len >> 8) | 0xff; 4182d1d418eSSumit Saxena scsiio_cdb_ptr(csio)[8] = param_list_len | 0xff; 4192d1d418eSSumit Saxena mpi3mr_print_cdb(ccb); 4202d1d418eSSumit Saxena } 4212d1d418eSSumit Saxena break; 4222d1d418eSSumit Saxena } 4232d1d418eSSumit Saxena 4242d1d418eSSumit Saxena return true; 4252d1d418eSSumit Saxena } 4262d1d418eSSumit Saxena 4272d1d418eSSumit Saxena /** 4282d1d418eSSumit Saxena * mpi3mr_tm_response_name - get TM response as a string 4292d1d418eSSumit Saxena * @resp_code: TM response code 4302d1d418eSSumit Saxena * 4312d1d418eSSumit Saxena * Convert known task management response code as a readable 4322d1d418eSSumit Saxena * string. 4332d1d418eSSumit Saxena * 4342d1d418eSSumit Saxena * Return: response code string. 4352d1d418eSSumit Saxena */ 4362d1d418eSSumit Saxena static const char* mpi3mr_tm_response_name(U8 resp_code) 4372d1d418eSSumit Saxena { 4382d1d418eSSumit Saxena char *desc; 4392d1d418eSSumit Saxena 4402d1d418eSSumit Saxena switch (resp_code) { 4412d1d418eSSumit Saxena case MPI3_SCSITASKMGMT_RSPCODE_TM_COMPLETE: 4422d1d418eSSumit Saxena desc = "task management request completed"; 4432d1d418eSSumit Saxena break; 4442d1d418eSSumit Saxena case MPI3_SCSITASKMGMT_RSPCODE_INVALID_FRAME: 4452d1d418eSSumit Saxena desc = "invalid frame"; 4462d1d418eSSumit Saxena break; 4472d1d418eSSumit Saxena case MPI3_SCSITASKMGMT_RSPCODE_TM_FUNCTION_NOT_SUPPORTED: 4482d1d418eSSumit Saxena desc = "task management request not supported"; 4492d1d418eSSumit Saxena break; 4502d1d418eSSumit Saxena case MPI3_SCSITASKMGMT_RSPCODE_TM_FAILED: 4512d1d418eSSumit Saxena desc = "task management request failed"; 4522d1d418eSSumit Saxena break; 4532d1d418eSSumit Saxena case MPI3_SCSITASKMGMT_RSPCODE_TM_SUCCEEDED: 4542d1d418eSSumit Saxena desc = "task management request succeeded"; 4552d1d418eSSumit Saxena break; 4562d1d418eSSumit Saxena case MPI3_SCSITASKMGMT_RSPCODE_TM_INVALID_LUN: 4572d1d418eSSumit Saxena desc = "invalid LUN"; 4582d1d418eSSumit Saxena break; 4592d1d418eSSumit Saxena case MPI3_SCSITASKMGMT_RSPCODE_TM_OVERLAPPED_TAG: 4602d1d418eSSumit Saxena desc = "overlapped tag attempted"; 4612d1d418eSSumit Saxena break; 4622d1d418eSSumit Saxena case MPI3_SCSITASKMGMT_RSPCODE_IO_QUEUED_ON_IOC: 4632d1d418eSSumit Saxena desc = "task queued, however not sent to target"; 4642d1d418eSSumit Saxena break; 4652d1d418eSSumit Saxena case MPI3_SCSITASKMGMT_RSPCODE_TM_NVME_DENIED: 4662d1d418eSSumit Saxena desc = "task management request denied by NVMe device"; 4672d1d418eSSumit Saxena break; 4682d1d418eSSumit Saxena default: 4692d1d418eSSumit Saxena desc = "unknown"; 4702d1d418eSSumit Saxena break; 4712d1d418eSSumit Saxena } 4722d1d418eSSumit Saxena 4732d1d418eSSumit Saxena return desc; 4742d1d418eSSumit Saxena } 4752d1d418eSSumit Saxena 4762d1d418eSSumit Saxena void mpi3mr_poll_pend_io_completions(struct mpi3mr_softc *sc) 4772d1d418eSSumit Saxena { 4782d1d418eSSumit Saxena int i; 4792d1d418eSSumit Saxena int num_of_reply_queues = sc->num_queues; 4802d1d418eSSumit Saxena struct mpi3mr_irq_context *irq_ctx; 4812d1d418eSSumit Saxena 4822d1d418eSSumit Saxena for (i = 0; i < num_of_reply_queues; i++) { 4832d1d418eSSumit Saxena irq_ctx = &sc->irq_ctx[i]; 4842d1d418eSSumit Saxena mpi3mr_complete_io_cmd(sc, irq_ctx); 4852d1d418eSSumit Saxena } 4862d1d418eSSumit Saxena } 4872d1d418eSSumit Saxena 4882d1d418eSSumit Saxena void 4893012fa8fSChandrakanth patil trigger_reset_from_watchdog(struct mpi3mr_softc *sc, U8 reset_type, U16 reset_reason) 4902d1d418eSSumit Saxena { 4912d1d418eSSumit Saxena if (sc->reset_in_progress) { 4922d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_INFO, "Another reset is in progress, no need to trigger the reset\n"); 4932d1d418eSSumit Saxena return; 4942d1d418eSSumit Saxena } 4952d1d418eSSumit Saxena sc->reset.type = reset_type; 4962d1d418eSSumit Saxena sc->reset.reason = reset_reason; 4972d1d418eSSumit Saxena 4982d1d418eSSumit Saxena return; 4992d1d418eSSumit Saxena } 5002d1d418eSSumit Saxena 5012d1d418eSSumit Saxena /** 5022d1d418eSSumit Saxena * mpi3mr_issue_tm - Issue Task Management request 5032d1d418eSSumit Saxena * @sc: Adapter instance reference 5042d1d418eSSumit Saxena * @tm_type: Task Management type 5052d1d418eSSumit Saxena * @handle: Device handle 5062d1d418eSSumit Saxena * @lun: lun ID 5072d1d418eSSumit Saxena * @htag: Host tag of the TM request 5082d1d418eSSumit Saxena * @timeout: TM timeout value 5092d1d418eSSumit Saxena * @drv_cmd: Internal command tracker 5102d1d418eSSumit Saxena * @resp_code: Response code place holder 5112d1d418eSSumit Saxena * @cmd: Timed out command reference 5122d1d418eSSumit Saxena * 5132d1d418eSSumit Saxena * Issues a Task Management Request to the controller for a 5142d1d418eSSumit Saxena * specified target, lun and command and wait for its completion 5152d1d418eSSumit Saxena * and check TM response. Recover the TM if it timed out by 5162d1d418eSSumit Saxena * issuing controller reset. 5172d1d418eSSumit Saxena * 5182d1d418eSSumit Saxena * Return: 0 on success, non-zero on errors 5192d1d418eSSumit Saxena */ 5202d1d418eSSumit Saxena static int 5212d1d418eSSumit Saxena mpi3mr_issue_tm(struct mpi3mr_softc *sc, struct mpi3mr_cmd *cmd, 5222d1d418eSSumit Saxena U8 tm_type, unsigned long timeout) 5232d1d418eSSumit Saxena { 5242d1d418eSSumit Saxena int retval = 0; 5252d1d418eSSumit Saxena MPI3_SCSI_TASK_MGMT_REQUEST tm_req; 5262d1d418eSSumit Saxena MPI3_SCSI_TASK_MGMT_REPLY *tm_reply = NULL; 5272d1d418eSSumit Saxena struct mpi3mr_drvr_cmd *drv_cmd = NULL; 5282d1d418eSSumit Saxena struct mpi3mr_target *tgtdev = NULL; 5292d1d418eSSumit Saxena struct mpi3mr_op_req_queue *op_req_q = NULL; 5302d1d418eSSumit Saxena union ccb *ccb; 5312d1d418eSSumit Saxena U8 resp_code; 5322d1d418eSSumit Saxena 5332d1d418eSSumit Saxena 5342d1d418eSSumit Saxena if (sc->unrecoverable) { 5352d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_INFO, 5362d1d418eSSumit Saxena "Controller is in unrecoverable state!! TM not required\n"); 5372d1d418eSSumit Saxena return retval; 5382d1d418eSSumit Saxena } 5392d1d418eSSumit Saxena if (sc->reset_in_progress) { 5402d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_INFO, 5412d1d418eSSumit Saxena "controller reset in progress!! TM not required\n"); 5422d1d418eSSumit Saxena return retval; 5432d1d418eSSumit Saxena } 5442d1d418eSSumit Saxena 5452d1d418eSSumit Saxena if (!cmd->ccb) { 5462d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_ERROR, "SCSIIO command timed-out with NULL ccb\n"); 5472d1d418eSSumit Saxena return retval; 5482d1d418eSSumit Saxena } 5492d1d418eSSumit Saxena ccb = cmd->ccb; 5502d1d418eSSumit Saxena 5512d1d418eSSumit Saxena tgtdev = cmd->targ; 5522d1d418eSSumit Saxena if (tgtdev == NULL) { 5532d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_ERROR, "Device does not exist target ID:0x%x," 5542d1d418eSSumit Saxena "TM is not required\n", ccb->ccb_h.target_id); 5552d1d418eSSumit Saxena return retval; 5562d1d418eSSumit Saxena } 5572d1d418eSSumit Saxena if (tgtdev->dev_removed == 1) { 5582d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_ERROR, "Device(0x%x) is removed, TM is not required\n", 5592d1d418eSSumit Saxena ccb->ccb_h.target_id); 5602d1d418eSSumit Saxena return retval; 5612d1d418eSSumit Saxena } 5622d1d418eSSumit Saxena 5632d1d418eSSumit Saxena drv_cmd = &sc->host_tm_cmds; 5642d1d418eSSumit Saxena mtx_lock(&drv_cmd->lock); 5652d1d418eSSumit Saxena 5662d1d418eSSumit Saxena memset(&tm_req, 0, sizeof(tm_req)); 5672d1d418eSSumit Saxena tm_req.DevHandle = htole16(tgtdev->dev_handle); 5682d1d418eSSumit Saxena tm_req.TaskType = tm_type; 5692d1d418eSSumit Saxena tm_req.HostTag = htole16(MPI3MR_HOSTTAG_TMS); 5702d1d418eSSumit Saxena int_to_lun(ccb->ccb_h.target_lun, tm_req.LUN); 5712d1d418eSSumit Saxena tm_req.Function = MPI3_FUNCTION_SCSI_TASK_MGMT; 5722d1d418eSSumit Saxena drv_cmd->state = MPI3MR_CMD_PENDING; 5732d1d418eSSumit Saxena drv_cmd->is_waiting = 1; 5742d1d418eSSumit Saxena drv_cmd->callback = NULL; 5752d1d418eSSumit Saxena 5762d1d418eSSumit Saxena if (ccb) { 5772d1d418eSSumit Saxena if (tm_type == MPI3_SCSITASKMGMT_TASKTYPE_ABORT_TASK) { 5782d1d418eSSumit Saxena op_req_q = &sc->op_req_q[cmd->req_qidx]; 5792d1d418eSSumit Saxena tm_req.TaskHostTag = htole16(cmd->hosttag); 5802d1d418eSSumit Saxena tm_req.TaskRequestQueueID = htole16(op_req_q->qid); 5812d1d418eSSumit Saxena } 5822d1d418eSSumit Saxena } 5832d1d418eSSumit Saxena 5842d1d418eSSumit Saxena if (tgtdev) 5852d1d418eSSumit Saxena mpi3mr_atomic_inc(&tgtdev->block_io); 5862d1d418eSSumit Saxena 5872d1d418eSSumit Saxena if (tgtdev && (tgtdev->dev_type == MPI3_DEVICE_DEVFORM_PCIE)) { 5882d1d418eSSumit Saxena if ((tm_type == MPI3_SCSITASKMGMT_TASKTYPE_ABORT_TASK) 5892d1d418eSSumit Saxena && tgtdev->dev_spec.pcie_inf.abort_to) 5902d1d418eSSumit Saxena timeout = tgtdev->dev_spec.pcie_inf.abort_to; 5912d1d418eSSumit Saxena else if ((tm_type == MPI3_SCSITASKMGMT_TASKTYPE_TARGET_RESET) 5922d1d418eSSumit Saxena && tgtdev->dev_spec.pcie_inf.reset_to) 5932d1d418eSSumit Saxena timeout = tgtdev->dev_spec.pcie_inf.reset_to; 5942d1d418eSSumit Saxena } 5952d1d418eSSumit Saxena 5962d1d418eSSumit Saxena sc->tm_chan = (void *)&drv_cmd; 5972d1d418eSSumit Saxena 5982d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_DEBUG_TM, 5992d1d418eSSumit Saxena "posting task management request: type(%d), handle(0x%04x)\n", 6002d1d418eSSumit Saxena tm_type, tgtdev->dev_handle); 6012d1d418eSSumit Saxena 6022d1d418eSSumit Saxena init_completion(&drv_cmd->completion); 6032d1d418eSSumit Saxena retval = mpi3mr_submit_admin_cmd(sc, &tm_req, sizeof(tm_req)); 6042d1d418eSSumit Saxena if (retval) { 6052d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_ERROR, 6062d1d418eSSumit Saxena "posting task management request is failed\n"); 6072d1d418eSSumit Saxena retval = -1; 6082d1d418eSSumit Saxena goto out_unlock; 6092d1d418eSSumit Saxena } 6102d1d418eSSumit Saxena wait_for_completion_timeout_tm(&drv_cmd->completion, timeout, sc); 6112d1d418eSSumit Saxena 6122d1d418eSSumit Saxena if (!(drv_cmd->state & MPI3MR_CMD_COMPLETE)) { 6132d1d418eSSumit Saxena drv_cmd->is_waiting = 0; 6142d1d418eSSumit Saxena retval = -1; 6152d1d418eSSumit Saxena if (!(drv_cmd->state & MPI3MR_CMD_RESET)) { 6162d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_ERROR, 6172d1d418eSSumit Saxena "task management request timed out after %ld seconds\n", timeout); 6182d1d418eSSumit Saxena if (sc->mpi3mr_debug & MPI3MR_DEBUG_TM) { 6192d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_INFO, "tm_request dump\n"); 6202d1d418eSSumit Saxena mpi3mr_hexdump(&tm_req, sizeof(tm_req), 8); 6212d1d418eSSumit Saxena } 6222d1d418eSSumit Saxena trigger_reset_from_watchdog(sc, MPI3MR_TRIGGER_SOFT_RESET, MPI3MR_RESET_FROM_TM_TIMEOUT); 6232d1d418eSSumit Saxena retval = ETIMEDOUT; 6242d1d418eSSumit Saxena } 6252d1d418eSSumit Saxena goto out_unlock; 6262d1d418eSSumit Saxena } 6272d1d418eSSumit Saxena 6282d1d418eSSumit Saxena if (!(drv_cmd->state & MPI3MR_CMD_REPLYVALID)) { 6292d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_ERROR, 6302d1d418eSSumit Saxena "invalid task management reply message\n"); 6312d1d418eSSumit Saxena retval = -1; 6322d1d418eSSumit Saxena goto out_unlock; 6332d1d418eSSumit Saxena } 6342d1d418eSSumit Saxena tm_reply = (MPI3_SCSI_TASK_MGMT_REPLY *)drv_cmd->reply; 6352d1d418eSSumit Saxena 6362d1d418eSSumit Saxena switch (drv_cmd->ioc_status) { 6372d1d418eSSumit Saxena case MPI3_IOCSTATUS_SUCCESS: 6382d1d418eSSumit Saxena resp_code = tm_reply->ResponseData & MPI3MR_RI_MASK_RESPCODE; 6392d1d418eSSumit Saxena break; 6402d1d418eSSumit Saxena case MPI3_IOCSTATUS_SCSI_IOC_TERMINATED: 6412d1d418eSSumit Saxena resp_code = MPI3_SCSITASKMGMT_RSPCODE_TM_COMPLETE; 6422d1d418eSSumit Saxena break; 6432d1d418eSSumit Saxena default: 6442d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_ERROR, 6452d1d418eSSumit Saxena "task management request to handle(0x%04x) is failed with ioc_status(0x%04x) log_info(0x%08x)\n", 6462d1d418eSSumit Saxena tgtdev->dev_handle, drv_cmd->ioc_status, drv_cmd->ioc_loginfo); 6472d1d418eSSumit Saxena retval = -1; 6482d1d418eSSumit Saxena goto out_unlock; 6492d1d418eSSumit Saxena } 6502d1d418eSSumit Saxena 6512d1d418eSSumit Saxena switch (resp_code) { 6522d1d418eSSumit Saxena case MPI3_SCSITASKMGMT_RSPCODE_TM_SUCCEEDED: 6532d1d418eSSumit Saxena case MPI3_SCSITASKMGMT_RSPCODE_TM_COMPLETE: 6542d1d418eSSumit Saxena break; 6552d1d418eSSumit Saxena case MPI3_SCSITASKMGMT_RSPCODE_IO_QUEUED_ON_IOC: 6562d1d418eSSumit Saxena if (tm_type != MPI3_SCSITASKMGMT_TASKTYPE_QUERY_TASK) 6572d1d418eSSumit Saxena retval = -1; 6582d1d418eSSumit Saxena break; 6592d1d418eSSumit Saxena default: 6602d1d418eSSumit Saxena retval = -1; 6612d1d418eSSumit Saxena break; 6622d1d418eSSumit Saxena } 6632d1d418eSSumit Saxena 6642d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_DEBUG_TM, 6652d1d418eSSumit Saxena "task management request type(%d) completed for handle(0x%04x) with ioc_status(0x%04x), log_info(0x%08x)" 6662d1d418eSSumit Saxena "termination_count(%u), response:%s(0x%x)\n", tm_type, tgtdev->dev_handle, drv_cmd->ioc_status, drv_cmd->ioc_loginfo, 6672d1d418eSSumit Saxena tm_reply->TerminationCount, mpi3mr_tm_response_name(resp_code), resp_code); 6682d1d418eSSumit Saxena 6692d1d418eSSumit Saxena if (retval) 6702d1d418eSSumit Saxena goto out_unlock; 6712d1d418eSSumit Saxena 6722d1d418eSSumit Saxena mpi3mr_disable_interrupts(sc); 6732d1d418eSSumit Saxena mpi3mr_poll_pend_io_completions(sc); 6742d1d418eSSumit Saxena mpi3mr_enable_interrupts(sc); 6752d1d418eSSumit Saxena mpi3mr_poll_pend_io_completions(sc); 6762d1d418eSSumit Saxena 6772d1d418eSSumit Saxena switch (tm_type) { 6782d1d418eSSumit Saxena case MPI3_SCSITASKMGMT_TASKTYPE_ABORT_TASK: 6792d1d418eSSumit Saxena if (cmd->state == MPI3MR_CMD_STATE_IN_TM) { 6802d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_ERROR, 6812d1d418eSSumit Saxena "%s: task abort returned success from firmware but corresponding CCB (%p) was not terminated" 6822d1d418eSSumit Saxena "marking task abort failed!\n", sc->name, cmd->ccb); 6832d1d418eSSumit Saxena retval = -1; 6842d1d418eSSumit Saxena } 6852d1d418eSSumit Saxena break; 6862d1d418eSSumit Saxena case MPI3_SCSITASKMGMT_TASKTYPE_TARGET_RESET: 6872d1d418eSSumit Saxena if (mpi3mr_atomic_read(&tgtdev->outstanding)) { 6882d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_ERROR, 6892d1d418eSSumit Saxena "%s: target reset returned success from firmware but IOs are still pending on the target (%p)" 6902d1d418eSSumit Saxena "marking target reset failed!\n", 6912d1d418eSSumit Saxena sc->name, tgtdev); 6922d1d418eSSumit Saxena retval = -1; 6932d1d418eSSumit Saxena } 6942d1d418eSSumit Saxena break; 6952d1d418eSSumit Saxena default: 6962d1d418eSSumit Saxena break; 6972d1d418eSSumit Saxena } 6982d1d418eSSumit Saxena 6992d1d418eSSumit Saxena out_unlock: 7002d1d418eSSumit Saxena drv_cmd->state = MPI3MR_CMD_NOTUSED; 7012d1d418eSSumit Saxena mtx_unlock(&drv_cmd->lock); 7022d1d418eSSumit Saxena if (tgtdev && mpi3mr_atomic_read(&tgtdev->block_io) > 0) 7032d1d418eSSumit Saxena mpi3mr_atomic_dec(&tgtdev->block_io); 7042d1d418eSSumit Saxena 7052d1d418eSSumit Saxena return retval; 7062d1d418eSSumit Saxena } 7072d1d418eSSumit Saxena 7082d1d418eSSumit Saxena /** 7092d1d418eSSumit Saxena * mpi3mr_task_abort- Abort error handling callback 7102d1d418eSSumit Saxena * @cmd: Timed out command reference 7112d1d418eSSumit Saxena * 7122d1d418eSSumit Saxena * Issue Abort Task Management if the command is in LLD scope 7132d1d418eSSumit Saxena * and verify if it is aborted successfully and return status 7142d1d418eSSumit Saxena * accordingly. 7152d1d418eSSumit Saxena * 7162d1d418eSSumit Saxena * Return: SUCCESS of successful abort the SCSI command else FAILED 7172d1d418eSSumit Saxena */ 7182d1d418eSSumit Saxena static int mpi3mr_task_abort(struct mpi3mr_cmd *cmd) 7192d1d418eSSumit Saxena { 7202d1d418eSSumit Saxena int retval = 0; 7212d1d418eSSumit Saxena struct mpi3mr_softc *sc; 7222d1d418eSSumit Saxena union ccb *ccb; 7232d1d418eSSumit Saxena 7242d1d418eSSumit Saxena sc = cmd->sc; 7252d1d418eSSumit Saxena 7262d1d418eSSumit Saxena if (!cmd->ccb) { 7272d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_ERROR, "SCSIIO command timed-out with NULL ccb\n"); 7282d1d418eSSumit Saxena return retval; 7292d1d418eSSumit Saxena } 7302d1d418eSSumit Saxena ccb = cmd->ccb; 7312d1d418eSSumit Saxena 7322d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_INFO, 7332d1d418eSSumit Saxena "attempting abort task for ccb(%p)\n", ccb); 7342d1d418eSSumit Saxena 7352d1d418eSSumit Saxena mpi3mr_print_cdb(ccb); 7362d1d418eSSumit Saxena 7372d1d418eSSumit Saxena if (cmd->state != MPI3MR_CMD_STATE_BUSY) { 7382d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_INFO, 7392d1d418eSSumit Saxena "%s: ccb is not in driver scope, abort task is not required\n", 7402d1d418eSSumit Saxena sc->name); 7412d1d418eSSumit Saxena return retval; 7422d1d418eSSumit Saxena } 7432d1d418eSSumit Saxena cmd->state = MPI3MR_CMD_STATE_IN_TM; 7442d1d418eSSumit Saxena 7452d1d418eSSumit Saxena retval = mpi3mr_issue_tm(sc, cmd, MPI3_SCSITASKMGMT_TASKTYPE_ABORT_TASK, MPI3MR_ABORTTM_TIMEOUT); 7462d1d418eSSumit Saxena 7472d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_INFO, 7482d1d418eSSumit Saxena "abort task is %s for ccb(%p)\n", ((retval == 0) ? "SUCCESS" : "FAILED"), ccb); 7492d1d418eSSumit Saxena 7502d1d418eSSumit Saxena return retval; 7512d1d418eSSumit Saxena } 7522d1d418eSSumit Saxena 7532d1d418eSSumit Saxena /** 7542d1d418eSSumit Saxena * mpi3mr_target_reset - Target reset error handling callback 7552d1d418eSSumit Saxena * @cmd: Timed out command reference 7562d1d418eSSumit Saxena * 7572d1d418eSSumit Saxena * Issue Target reset Task Management and verify the SCSI commands are 7582d1d418eSSumit Saxena * terminated successfully and return status accordingly. 7592d1d418eSSumit Saxena * 7602d1d418eSSumit Saxena * Return: SUCCESS of successful termination of the SCSI commands else 7612d1d418eSSumit Saxena * FAILED 7622d1d418eSSumit Saxena */ 7632d1d418eSSumit Saxena static int mpi3mr_target_reset(struct mpi3mr_cmd *cmd) 7642d1d418eSSumit Saxena { 7652d1d418eSSumit Saxena int retval = 0; 7662d1d418eSSumit Saxena struct mpi3mr_softc *sc; 7672d1d418eSSumit Saxena struct mpi3mr_target *target; 7682d1d418eSSumit Saxena 7692d1d418eSSumit Saxena sc = cmd->sc; 7702d1d418eSSumit Saxena 7712d1d418eSSumit Saxena target = cmd->targ; 7722d1d418eSSumit Saxena if (target == NULL) { 7732d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_XINFO, "Device does not exist for target:0x%p," 7742d1d418eSSumit Saxena "target reset is not required\n", target); 7752d1d418eSSumit Saxena return retval; 7762d1d418eSSumit Saxena } 7772d1d418eSSumit Saxena 7782d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_INFO, 7792d1d418eSSumit Saxena "attempting target reset on target(%d)\n", target->per_id); 7802d1d418eSSumit Saxena 7812d1d418eSSumit Saxena 7822d1d418eSSumit Saxena if (mpi3mr_atomic_read(&target->outstanding)) { 7832d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_INFO, 7842d1d418eSSumit Saxena "no outstanding IOs on the target(%d)," 7852d1d418eSSumit Saxena " target reset not required.\n", target->per_id); 7862d1d418eSSumit Saxena return retval; 7872d1d418eSSumit Saxena } 7882d1d418eSSumit Saxena 7892d1d418eSSumit Saxena retval = mpi3mr_issue_tm(sc, cmd, MPI3_SCSITASKMGMT_TASKTYPE_TARGET_RESET, MPI3MR_RESETTM_TIMEOUT); 7902d1d418eSSumit Saxena 7912d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_INFO, 7922d1d418eSSumit Saxena "target reset is %s for target(%d)\n", ((retval == 0) ? "SUCCESS" : "FAILED"), 7932d1d418eSSumit Saxena target->per_id); 7942d1d418eSSumit Saxena 7952d1d418eSSumit Saxena return retval; 7962d1d418eSSumit Saxena } 7972d1d418eSSumit Saxena 7982d1d418eSSumit Saxena /** 7992d1d418eSSumit Saxena * mpi3mr_get_fw_pending_ios - Calculate pending I/O count 8002d1d418eSSumit Saxena * @sc: Adapter instance reference 8012d1d418eSSumit Saxena * 8022d1d418eSSumit Saxena * Calculate the pending I/Os for the controller and return. 8032d1d418eSSumit Saxena * 8042d1d418eSSumit Saxena * Return: Number of pending I/Os 8052d1d418eSSumit Saxena */ 8062d1d418eSSumit Saxena static inline int mpi3mr_get_fw_pending_ios(struct mpi3mr_softc *sc) 8072d1d418eSSumit Saxena { 8082d1d418eSSumit Saxena U16 i, pend_ios = 0; 8092d1d418eSSumit Saxena 8102d1d418eSSumit Saxena for (i = 0; i < sc->num_queues; i++) 8112d1d418eSSumit Saxena pend_ios += mpi3mr_atomic_read(&sc->op_reply_q[i].pend_ios); 8122d1d418eSSumit Saxena return pend_ios; 8132d1d418eSSumit Saxena } 8142d1d418eSSumit Saxena 8152d1d418eSSumit Saxena /** 8162d1d418eSSumit Saxena * mpi3mr_wait_for_host_io - block for I/Os to complete 8172d1d418eSSumit Saxena * @sc: Adapter instance reference 8182d1d418eSSumit Saxena * @timeout: time out in seconds 8192d1d418eSSumit Saxena * 8202d1d418eSSumit Saxena * Waits for pending I/Os for the given adapter to complete or 8212d1d418eSSumit Saxena * to hit the timeout. 8222d1d418eSSumit Saxena * 8232d1d418eSSumit Saxena * Return: Nothing 8242d1d418eSSumit Saxena */ 8252d1d418eSSumit Saxena static int mpi3mr_wait_for_host_io(struct mpi3mr_softc *sc, U32 timeout) 8262d1d418eSSumit Saxena { 8272d1d418eSSumit Saxena enum mpi3mr_iocstate iocstate; 8282d1d418eSSumit Saxena 8292d1d418eSSumit Saxena iocstate = mpi3mr_get_iocstate(sc); 8302d1d418eSSumit Saxena if (iocstate != MRIOC_STATE_READY) { 8312d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_XINFO, "%s :Controller is in NON-READY state! Proceed with Reset\n", __func__); 8322d1d418eSSumit Saxena return -1; 8332d1d418eSSumit Saxena } 8342d1d418eSSumit Saxena 8352d1d418eSSumit Saxena if (!mpi3mr_get_fw_pending_ios(sc)) 8362d1d418eSSumit Saxena return 0; 8372d1d418eSSumit Saxena 8382d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_INFO, 8392d1d418eSSumit Saxena "%s :Waiting for %d seconds prior to reset for %d pending I/Os to complete\n", 8402d1d418eSSumit Saxena __func__, timeout, mpi3mr_get_fw_pending_ios(sc)); 8412d1d418eSSumit Saxena 8422d1d418eSSumit Saxena int i; 8432d1d418eSSumit Saxena for (i = 0; i < timeout; i++) { 8442d1d418eSSumit Saxena if (!mpi3mr_get_fw_pending_ios(sc)) { 8452d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_INFO, "%s :All pending I/Os got completed while waiting! Reset not required\n", __func__); 8462d1d418eSSumit Saxena return 0; 8472d1d418eSSumit Saxena 8482d1d418eSSumit Saxena } 8492d1d418eSSumit Saxena iocstate = mpi3mr_get_iocstate(sc); 8502d1d418eSSumit Saxena if (iocstate != MRIOC_STATE_READY) { 8512d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_XINFO, "%s :Controller state becomes NON-READY while waiting! dont wait further" 8522d1d418eSSumit Saxena "Proceed with Reset\n", __func__); 8532d1d418eSSumit Saxena return -1; 8542d1d418eSSumit Saxena } 8552d1d418eSSumit Saxena DELAY(1000 * 1000); 8562d1d418eSSumit Saxena } 8572d1d418eSSumit Saxena 8582d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_INFO, "%s :Pending I/Os after wait exaust is %d! Proceed with Reset\n", __func__, 8592d1d418eSSumit Saxena mpi3mr_get_fw_pending_ios(sc)); 8602d1d418eSSumit Saxena 8612d1d418eSSumit Saxena return -1; 8622d1d418eSSumit Saxena } 8632d1d418eSSumit Saxena 8642d1d418eSSumit Saxena static void 8652d1d418eSSumit Saxena mpi3mr_scsiio_timeout(void *data) 8662d1d418eSSumit Saxena { 8672d1d418eSSumit Saxena int retval = 0; 8682d1d418eSSumit Saxena struct mpi3mr_softc *sc; 8692d1d418eSSumit Saxena struct mpi3mr_cmd *cmd; 8702d1d418eSSumit Saxena struct mpi3mr_target *targ_dev = NULL; 8712d1d418eSSumit Saxena 8722d1d418eSSumit Saxena if (!data) 8732d1d418eSSumit Saxena return; 8742d1d418eSSumit Saxena 8752d1d418eSSumit Saxena cmd = (struct mpi3mr_cmd *)data; 8762d1d418eSSumit Saxena sc = cmd->sc; 8772d1d418eSSumit Saxena 8782d1d418eSSumit Saxena if (cmd->ccb == NULL) { 8792d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_ERROR, "SCSIIO command timed-out with NULL ccb\n"); 8802d1d418eSSumit Saxena return; 8812d1d418eSSumit Saxena } 8822d1d418eSSumit Saxena 8832d1d418eSSumit Saxena /* 8842d1d418eSSumit Saxena * TMs are not supported for IO timeouts on VD/LD, so directly issue controller reset 8852d1d418eSSumit Saxena * with max timeout for outstanding IOs to complete is 180sec. 8862d1d418eSSumit Saxena */ 8872d1d418eSSumit Saxena targ_dev = cmd->targ; 8882d1d418eSSumit Saxena if (targ_dev && (targ_dev->dev_type == MPI3_DEVICE_DEVFORM_VD)) { 8892d1d418eSSumit Saxena if (mpi3mr_wait_for_host_io(sc, MPI3MR_RAID_ERRREC_RESET_TIMEOUT)) 8902d1d418eSSumit Saxena trigger_reset_from_watchdog(sc, MPI3MR_TRIGGER_SOFT_RESET, MPI3MR_RESET_FROM_SCSIIO_TIMEOUT); 8912d1d418eSSumit Saxena return; 8922d1d418eSSumit Saxena } 8932d1d418eSSumit Saxena 8942d1d418eSSumit Saxena /* Issue task abort to recover the timed out IO */ 8952d1d418eSSumit Saxena retval = mpi3mr_task_abort(cmd); 8962d1d418eSSumit Saxena if (!retval || (retval == ETIMEDOUT)) 8972d1d418eSSumit Saxena return; 8982d1d418eSSumit Saxena 8992d1d418eSSumit Saxena /* 9002d1d418eSSumit Saxena * task abort has failed to recover the timed out IO, 9012d1d418eSSumit Saxena * try with the target reset 9022d1d418eSSumit Saxena */ 9032d1d418eSSumit Saxena retval = mpi3mr_target_reset(cmd); 9042d1d418eSSumit Saxena if (!retval || (retval == ETIMEDOUT)) 9052d1d418eSSumit Saxena return; 9062d1d418eSSumit Saxena 9072d1d418eSSumit Saxena /* 9082d1d418eSSumit Saxena * task abort and target reset has failed. So issue Controller reset(soft reset) 9092d1d418eSSumit Saxena * through OCR thread context 9102d1d418eSSumit Saxena */ 9112d1d418eSSumit Saxena trigger_reset_from_watchdog(sc, MPI3MR_TRIGGER_SOFT_RESET, MPI3MR_RESET_FROM_SCSIIO_TIMEOUT); 9122d1d418eSSumit Saxena 9132d1d418eSSumit Saxena return; 9142d1d418eSSumit Saxena } 9152d1d418eSSumit Saxena 9162d1d418eSSumit Saxena void int_to_lun(unsigned int lun, U8 *req_lun) 9172d1d418eSSumit Saxena { 9182d1d418eSSumit Saxena int i; 9192d1d418eSSumit Saxena 9202d1d418eSSumit Saxena memset(req_lun, 0, sizeof(*req_lun)); 9212d1d418eSSumit Saxena 9222d1d418eSSumit Saxena for (i = 0; i < sizeof(lun); i += 2) { 9232d1d418eSSumit Saxena req_lun[i] = (lun >> 8) & 0xFF; 9242d1d418eSSumit Saxena req_lun[i+1] = lun & 0xFF; 9252d1d418eSSumit Saxena lun = lun >> 16; 9262d1d418eSSumit Saxena } 9272d1d418eSSumit Saxena 9282d1d418eSSumit Saxena } 9292d1d418eSSumit Saxena 9302d1d418eSSumit Saxena static U16 get_req_queue_index(struct mpi3mr_softc *sc) 9312d1d418eSSumit Saxena { 9322d1d418eSSumit Saxena U16 i = 0, reply_q_index = 0, reply_q_pend_ios = 0; 9332d1d418eSSumit Saxena 9342d1d418eSSumit Saxena reply_q_pend_ios = mpi3mr_atomic_read(&sc->op_reply_q[0].pend_ios); 9352d1d418eSSumit Saxena for (i = 0; i < sc->num_queues; i++) { 9362d1d418eSSumit Saxena if (reply_q_pend_ios > mpi3mr_atomic_read(&sc->op_reply_q[i].pend_ios)) { 9372d1d418eSSumit Saxena reply_q_pend_ios = mpi3mr_atomic_read(&sc->op_reply_q[i].pend_ios); 9382d1d418eSSumit Saxena reply_q_index = i; 9392d1d418eSSumit Saxena } 9402d1d418eSSumit Saxena } 9412d1d418eSSumit Saxena 9422d1d418eSSumit Saxena return reply_q_index; 9432d1d418eSSumit Saxena } 9442d1d418eSSumit Saxena 9452d1d418eSSumit Saxena static void 9462d1d418eSSumit Saxena mpi3mr_action_scsiio(struct mpi3mr_cam_softc *cam_sc, union ccb *ccb) 9472d1d418eSSumit Saxena { 9482d1d418eSSumit Saxena Mpi3SCSIIORequest_t *req = NULL; 9492d1d418eSSumit Saxena struct ccb_scsiio *csio; 9502d1d418eSSumit Saxena struct mpi3mr_softc *sc; 9512d1d418eSSumit Saxena struct mpi3mr_target *targ; 9522d1d418eSSumit Saxena struct mpi3mr_cmd *cm; 9532d1d418eSSumit Saxena uint8_t scsi_opcode, queue_idx; 9542d1d418eSSumit Saxena uint32_t mpi_control; 9552d1d418eSSumit Saxena 9562d1d418eSSumit Saxena sc = cam_sc->sc; 9572d1d418eSSumit Saxena mtx_assert(&sc->mpi3mr_mtx, MA_OWNED); 9582d1d418eSSumit Saxena 9592d1d418eSSumit Saxena if (sc->unrecoverable) { 9602d1d418eSSumit Saxena mpi3mr_set_ccbstatus(ccb, CAM_DEV_NOT_THERE); 9612d1d418eSSumit Saxena xpt_done(ccb); 9622d1d418eSSumit Saxena return; 9632d1d418eSSumit Saxena } 9642d1d418eSSumit Saxena 9652d1d418eSSumit Saxena csio = &ccb->csio; 9662d1d418eSSumit Saxena KASSERT(csio->ccb_h.target_id < cam_sc->maxtargets, 9672d1d418eSSumit Saxena ("Target %d out of bounds in XPT_SCSI_IO\n", 9682d1d418eSSumit Saxena csio->ccb_h.target_id)); 9692d1d418eSSumit Saxena 9702d1d418eSSumit Saxena scsi_opcode = scsiio_cdb_ptr(csio)[0]; 9712d1d418eSSumit Saxena 9722d1d418eSSumit Saxena if ((sc->mpi3mr_flags & MPI3MR_FLAGS_SHUTDOWN) && 9732d1d418eSSumit Saxena !((scsi_opcode == SYNCHRONIZE_CACHE) || 9742d1d418eSSumit Saxena (scsi_opcode == START_STOP_UNIT))) { 9752d1d418eSSumit Saxena mpi3mr_set_ccbstatus(ccb, CAM_REQ_CMP); 9762d1d418eSSumit Saxena xpt_done(ccb); 9772d1d418eSSumit Saxena return; 9782d1d418eSSumit Saxena } 9792d1d418eSSumit Saxena 9802d1d418eSSumit Saxena targ = mpi3mr_find_target_by_per_id(cam_sc, csio->ccb_h.target_id); 9812d1d418eSSumit Saxena if (targ == NULL) { 9822d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_XINFO, "Device with target ID: 0x%x does not exist\n", 9832d1d418eSSumit Saxena csio->ccb_h.target_id); 9842d1d418eSSumit Saxena mpi3mr_set_ccbstatus(ccb, CAM_DEV_NOT_THERE); 9852d1d418eSSumit Saxena xpt_done(ccb); 9862d1d418eSSumit Saxena return; 9872d1d418eSSumit Saxena } 9882d1d418eSSumit Saxena 9892d1d418eSSumit Saxena if (targ && targ->is_hidden) { 9902d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_XINFO, "Device with target ID: 0x%x is hidden\n", 9912d1d418eSSumit Saxena csio->ccb_h.target_id); 9922d1d418eSSumit Saxena mpi3mr_set_ccbstatus(ccb, CAM_DEV_NOT_THERE); 9932d1d418eSSumit Saxena xpt_done(ccb); 9942d1d418eSSumit Saxena return; 9952d1d418eSSumit Saxena } 9962d1d418eSSumit Saxena 9972d1d418eSSumit Saxena if (targ->dev_removed == 1) { 9982d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_XINFO, "Device with target ID: 0x%x is removed\n", csio->ccb_h.target_id); 9992d1d418eSSumit Saxena mpi3mr_set_ccbstatus(ccb, CAM_DEV_NOT_THERE); 10002d1d418eSSumit Saxena xpt_done(ccb); 10012d1d418eSSumit Saxena return; 10022d1d418eSSumit Saxena } 10032d1d418eSSumit Saxena 10042d1d418eSSumit Saxena if (targ->dev_handle == 0x0) { 10052d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_ERROR, "%s NULL handle for target 0x%x\n", 10062d1d418eSSumit Saxena __func__, csio->ccb_h.target_id); 10072d1d418eSSumit Saxena mpi3mr_set_ccbstatus(ccb, CAM_DEV_NOT_THERE); 10082d1d418eSSumit Saxena xpt_done(ccb); 10092d1d418eSSumit Saxena return; 10102d1d418eSSumit Saxena } 10112d1d418eSSumit Saxena 10122d1d418eSSumit Saxena if (mpi3mr_atomic_read(&targ->block_io) || 10132d1d418eSSumit Saxena (sc->reset_in_progress == 1) || (sc->prepare_for_reset == 1)) { 10142d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_TRACE, "%s target is busy target_id: 0x%x\n", 10152d1d418eSSumit Saxena __func__, csio->ccb_h.target_id); 10162d1d418eSSumit Saxena mpi3mr_set_ccbstatus(ccb, CAM_REQUEUE_REQ); 10172d1d418eSSumit Saxena xpt_done(ccb); 10182d1d418eSSumit Saxena return; 10192d1d418eSSumit Saxena } 10202d1d418eSSumit Saxena 10212d1d418eSSumit Saxena /* 10222d1d418eSSumit Saxena * Sometimes, it is possible to get a command that is not "In 10232d1d418eSSumit Saxena * Progress" and was actually aborted by the upper layer. Check for 10242d1d418eSSumit Saxena * this here and complete the command without error. 10252d1d418eSSumit Saxena */ 10262d1d418eSSumit Saxena if (mpi3mr_get_ccbstatus(ccb) != CAM_REQ_INPROG) { 10272d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_TRACE, "%s Command is not in progress for " 10282d1d418eSSumit Saxena "target %u\n", __func__, csio->ccb_h.target_id); 10292d1d418eSSumit Saxena xpt_done(ccb); 10302d1d418eSSumit Saxena return; 10312d1d418eSSumit Saxena } 10322d1d418eSSumit Saxena /* 10332d1d418eSSumit Saxena * If devinfo is 0 this will be a volume. In that case don't tell CAM 10342d1d418eSSumit Saxena * that the volume has timed out. We want volumes to be enumerated 10352d1d418eSSumit Saxena * until they are deleted/removed, not just failed. 10362d1d418eSSumit Saxena */ 10372d1d418eSSumit Saxena if (targ->flags & MPI3MRSAS_TARGET_INREMOVAL) { 10382d1d418eSSumit Saxena if (targ->devinfo == 0) 10392d1d418eSSumit Saxena mpi3mr_set_ccbstatus(ccb, CAM_REQ_CMP); 10402d1d418eSSumit Saxena else 10412d1d418eSSumit Saxena mpi3mr_set_ccbstatus(ccb, CAM_SEL_TIMEOUT); 10422d1d418eSSumit Saxena xpt_done(ccb); 10432d1d418eSSumit Saxena return; 10442d1d418eSSumit Saxena } 10452d1d418eSSumit Saxena 10462d1d418eSSumit Saxena if ((scsi_opcode == UNMAP) && 10472d1d418eSSumit Saxena (pci_get_device(sc->mpi3mr_dev) == MPI3_MFGPAGE_DEVID_SAS4116) && 10482d1d418eSSumit Saxena (targ->dev_type == MPI3_DEVICE_DEVFORM_PCIE) && 10492d1d418eSSumit Saxena (mpi3mr_allow_unmap_to_fw(sc, ccb) == false)) 10502d1d418eSSumit Saxena return; 10512d1d418eSSumit Saxena 10522d1d418eSSumit Saxena cm = mpi3mr_get_command(sc); 10532d1d418eSSumit Saxena if (cm == NULL || (sc->mpi3mr_flags & MPI3MR_FLAGS_DIAGRESET)) { 10542d1d418eSSumit Saxena if (cm != NULL) { 10552d1d418eSSumit Saxena mpi3mr_release_command(cm); 10562d1d418eSSumit Saxena } 10572d1d418eSSumit Saxena if ((cam_sc->flags & MPI3MRSAS_QUEUE_FROZEN) == 0) { 10582d1d418eSSumit Saxena xpt_freeze_simq(cam_sc->sim, 1); 10592d1d418eSSumit Saxena cam_sc->flags |= MPI3MRSAS_QUEUE_FROZEN; 10602d1d418eSSumit Saxena } 10612d1d418eSSumit Saxena ccb->ccb_h.status &= ~CAM_SIM_QUEUED; 1062cf8c2323SWarner Losh mpi3mr_set_ccbstatus(ccb, CAM_REQUEUE_REQ); 10632d1d418eSSumit Saxena xpt_done(ccb); 10642d1d418eSSumit Saxena return; 10652d1d418eSSumit Saxena } 10662d1d418eSSumit Saxena 10672d1d418eSSumit Saxena switch (csio->ccb_h.flags & CAM_DIR_MASK) { 10682d1d418eSSumit Saxena case CAM_DIR_IN: 10692d1d418eSSumit Saxena mpi_control = MPI3_SCSIIO_FLAGS_DATADIRECTION_READ; 10702d1d418eSSumit Saxena cm->data_dir = MPI3MR_READ; 10712d1d418eSSumit Saxena break; 10722d1d418eSSumit Saxena case CAM_DIR_OUT: 10732d1d418eSSumit Saxena mpi_control = MPI3_SCSIIO_FLAGS_DATADIRECTION_WRITE; 10742d1d418eSSumit Saxena cm->data_dir = MPI3MR_WRITE; 10752d1d418eSSumit Saxena break; 10762d1d418eSSumit Saxena case CAM_DIR_NONE: 10772d1d418eSSumit Saxena default: 10782d1d418eSSumit Saxena mpi_control = MPI3_SCSIIO_FLAGS_DATADIRECTION_NO_DATA_TRANSFER; 10792d1d418eSSumit Saxena break; 10802d1d418eSSumit Saxena } 10812d1d418eSSumit Saxena 10822d1d418eSSumit Saxena if (csio->cdb_len > 16) 10832d1d418eSSumit Saxena mpi_control |= MPI3_SCSIIO_FLAGS_CDB_GREATER_THAN_16; 10842d1d418eSSumit Saxena 10852d1d418eSSumit Saxena req = (Mpi3SCSIIORequest_t *)&cm->io_request; 10862d1d418eSSumit Saxena bzero(req, sizeof(*req)); 10872d1d418eSSumit Saxena req->Function = MPI3_FUNCTION_SCSI_IO; 10882d1d418eSSumit Saxena req->HostTag = cm->hosttag; 10892d1d418eSSumit Saxena req->DataLength = htole32(csio->dxfer_len); 10902d1d418eSSumit Saxena req->DevHandle = htole16(targ->dev_handle); 10912d1d418eSSumit Saxena 10922d1d418eSSumit Saxena /* 10932d1d418eSSumit Saxena * It looks like the hardware doesn't require an explicit tag 10942d1d418eSSumit Saxena * number for each transaction. SAM Task Management not supported 10952d1d418eSSumit Saxena * at the moment. 10962d1d418eSSumit Saxena */ 10972d1d418eSSumit Saxena switch (csio->tag_action) { 10982d1d418eSSumit Saxena case MSG_HEAD_OF_Q_TAG: 10992d1d418eSSumit Saxena mpi_control |= MPI3_SCSIIO_FLAGS_TASKATTRIBUTE_HEADOFQ; 11002d1d418eSSumit Saxena break; 11012d1d418eSSumit Saxena case MSG_ORDERED_Q_TAG: 11022d1d418eSSumit Saxena mpi_control |= MPI3_SCSIIO_FLAGS_TASKATTRIBUTE_ORDEREDQ; 11032d1d418eSSumit Saxena break; 11042d1d418eSSumit Saxena case MSG_ACA_TASK: 11052d1d418eSSumit Saxena mpi_control |= MPI3_SCSIIO_FLAGS_TASKATTRIBUTE_ACAQ; 11062d1d418eSSumit Saxena break; 11072d1d418eSSumit Saxena case CAM_TAG_ACTION_NONE: 11082d1d418eSSumit Saxena case MSG_SIMPLE_Q_TAG: 11092d1d418eSSumit Saxena default: 11102d1d418eSSumit Saxena mpi_control |= MPI3_SCSIIO_FLAGS_TASKATTRIBUTE_SIMPLEQ; 11112d1d418eSSumit Saxena break; 11122d1d418eSSumit Saxena } 11132d1d418eSSumit Saxena 11143f3a1554SChandrakanth patil if (targ->ws_len) 11153f3a1554SChandrakanth patil mpi3mr_divert_ws(req, csio, targ->ws_len); 11163f3a1554SChandrakanth patil 11172d1d418eSSumit Saxena req->Flags = htole32(mpi_control); 11182d1d418eSSumit Saxena 11192d1d418eSSumit Saxena if (csio->ccb_h.flags & CAM_CDB_POINTER) 11202d1d418eSSumit Saxena bcopy(csio->cdb_io.cdb_ptr, &req->CDB.CDB32[0], csio->cdb_len); 11212d1d418eSSumit Saxena else { 11222d1d418eSSumit Saxena KASSERT(csio->cdb_len <= IOCDBLEN, 11232d1d418eSSumit Saxena ("cdb_len %d is greater than IOCDBLEN but CAM_CDB_POINTER " 11242d1d418eSSumit Saxena "is not set", csio->cdb_len)); 11252d1d418eSSumit Saxena bcopy(csio->cdb_io.cdb_bytes, &req->CDB.CDB32[0],csio->cdb_len); 11262d1d418eSSumit Saxena } 11272d1d418eSSumit Saxena 11282d1d418eSSumit Saxena cm->length = csio->dxfer_len; 11292d1d418eSSumit Saxena cm->targ = targ; 11302d1d418eSSumit Saxena int_to_lun(csio->ccb_h.target_lun, req->LUN); 11312d1d418eSSumit Saxena cm->ccb = ccb; 11322d1d418eSSumit Saxena csio->ccb_h.qos.sim_data = sbinuptime(); 11332d1d418eSSumit Saxena queue_idx = get_req_queue_index(sc); 11342d1d418eSSumit Saxena cm->req_qidx = queue_idx; 11352d1d418eSSumit Saxena 11362d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_TRACE, "[QID:%d]: func: %s line:%d CDB: 0x%x targetid: %x SMID: 0x%x\n", 11372d1d418eSSumit Saxena (queue_idx + 1), __func__, __LINE__, scsi_opcode, csio->ccb_h.target_id, cm->hosttag); 11382d1d418eSSumit Saxena 11392d1d418eSSumit Saxena switch ((ccb->ccb_h.flags & CAM_DATA_MASK)) { 11402d1d418eSSumit Saxena case CAM_DATA_PADDR: 11412d1d418eSSumit Saxena case CAM_DATA_SG_PADDR: 11422d1d418eSSumit Saxena device_printf(sc->mpi3mr_dev, "%s: physical addresses not supported\n", 11432d1d418eSSumit Saxena __func__); 1144cf8c2323SWarner Losh mpi3mr_set_ccbstatus(ccb, CAM_REQ_INVALID); 11453208a189SWarner Losh mpi3mr_release_command(cm); 11462d1d418eSSumit Saxena xpt_done(ccb); 11472d1d418eSSumit Saxena return; 11482d1d418eSSumit Saxena case CAM_DATA_SG: 11492d1d418eSSumit Saxena device_printf(sc->mpi3mr_dev, "%s: scatter gather is not supported\n", 11502d1d418eSSumit Saxena __func__); 1151cf8c2323SWarner Losh mpi3mr_set_ccbstatus(ccb, CAM_REQ_INVALID); 11523208a189SWarner Losh mpi3mr_release_command(cm); 11532d1d418eSSumit Saxena xpt_done(ccb); 11542d1d418eSSumit Saxena return; 11552d1d418eSSumit Saxena case CAM_DATA_VADDR: 11562d1d418eSSumit Saxena case CAM_DATA_BIO: 11572d1d418eSSumit Saxena if (csio->dxfer_len > (MPI3MR_SG_DEPTH * MPI3MR_4K_PGSZ)) { 1158cf8c2323SWarner Losh mpi3mr_set_ccbstatus(ccb, CAM_REQ_TOO_BIG); 11592d1d418eSSumit Saxena mpi3mr_release_command(cm); 11602d1d418eSSumit Saxena xpt_done(ccb); 11612d1d418eSSumit Saxena return; 11622d1d418eSSumit Saxena } 1163cf8c2323SWarner Losh ccb->ccb_h.status |= CAM_SIM_QUEUED; 11642d1d418eSSumit Saxena cm->length = csio->dxfer_len; 11652d1d418eSSumit Saxena if (cm->length) 11662d1d418eSSumit Saxena cm->data = csio->data_ptr; 11672d1d418eSSumit Saxena break; 11682d1d418eSSumit Saxena default: 1169cf8c2323SWarner Losh mpi3mr_set_ccbstatus(ccb, CAM_REQ_INVALID); 11702d1d418eSSumit Saxena mpi3mr_release_command(cm); 11712d1d418eSSumit Saxena xpt_done(ccb); 11722d1d418eSSumit Saxena return; 11732d1d418eSSumit Saxena } 11742d1d418eSSumit Saxena 11753208a189SWarner Losh /* Prepare SGEs and queue to hardware */ 11763208a189SWarner Losh mpi3mr_map_request(sc, cm); 11773208a189SWarner Losh } 11783208a189SWarner Losh 11793208a189SWarner Losh static void 11803208a189SWarner Losh mpi3mr_enqueue_request(struct mpi3mr_softc *sc, struct mpi3mr_cmd *cm) 11813208a189SWarner Losh { 11823208a189SWarner Losh static int ratelimit; 11833208a189SWarner Losh struct mpi3mr_op_req_queue *opreqq = &sc->op_req_q[cm->req_qidx]; 11843208a189SWarner Losh struct mpi3mr_throttle_group_info *tg = NULL; 11853208a189SWarner Losh uint32_t data_len_blks = 0; 11863208a189SWarner Losh uint32_t tracked_io_sz = 0; 11873208a189SWarner Losh uint32_t ioc_pend_data_len = 0, tg_pend_data_len = 0; 11883208a189SWarner Losh struct mpi3mr_target *targ = cm->targ; 11893208a189SWarner Losh union ccb *ccb = cm->ccb; 11903208a189SWarner Losh Mpi3SCSIIORequest_t *req = (Mpi3SCSIIORequest_t *)&cm->io_request; 11912d1d418eSSumit Saxena 11922d1d418eSSumit Saxena if (sc->iot_enable) { 11933208a189SWarner Losh data_len_blks = ccb->csio.dxfer_len >> 9; 11942d1d418eSSumit Saxena 11952d1d418eSSumit Saxena if ((data_len_blks >= sc->io_throttle_data_length) && 11962d1d418eSSumit Saxena targ->io_throttle_enabled) { 11973208a189SWarner Losh 11982d1d418eSSumit Saxena tracked_io_sz = data_len_blks; 11992d1d418eSSumit Saxena tg = targ->throttle_group; 12002d1d418eSSumit Saxena if (tg) { 12012d1d418eSSumit Saxena mpi3mr_atomic_add(&sc->pend_large_data_sz, data_len_blks); 12022d1d418eSSumit Saxena mpi3mr_atomic_add(&tg->pend_large_data_sz, data_len_blks); 12032d1d418eSSumit Saxena 12042d1d418eSSumit Saxena ioc_pend_data_len = mpi3mr_atomic_read(&sc->pend_large_data_sz); 12052d1d418eSSumit Saxena tg_pend_data_len = mpi3mr_atomic_read(&tg->pend_large_data_sz); 12062d1d418eSSumit Saxena 12072d1d418eSSumit Saxena if (ratelimit % 1000) { 12082d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_IOT, 12092d1d418eSSumit Saxena "large vd_io persist_id(%d), handle(0x%04x), data_len(%d)," 12102d1d418eSSumit Saxena "ioc_pending(%d), tg_pending(%d), ioc_high(%d), tg_high(%d)\n", 12112d1d418eSSumit Saxena targ->per_id, targ->dev_handle, 12122d1d418eSSumit Saxena data_len_blks, ioc_pend_data_len, 12132d1d418eSSumit Saxena tg_pend_data_len, sc->io_throttle_high, 12142d1d418eSSumit Saxena tg->high); 12152d1d418eSSumit Saxena ratelimit++; 12162d1d418eSSumit Saxena } 12172d1d418eSSumit Saxena 12182d1d418eSSumit Saxena if (!tg->io_divert && ((ioc_pend_data_len >= 12192d1d418eSSumit Saxena sc->io_throttle_high) || 12202d1d418eSSumit Saxena (tg_pend_data_len >= tg->high))) { 12212d1d418eSSumit Saxena tg->io_divert = 1; 12222d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_IOT, 12232d1d418eSSumit Saxena "VD: Setting divert flag for tg_id(%d), persist_id(%d)\n", 12242d1d418eSSumit Saxena tg->id, targ->per_id); 122534f0a01bSWarner Losh if (sc->mpi3mr_debug & MPI3MR_IOT) 12262d1d418eSSumit Saxena mpi3mr_print_cdb(ccb); 12272d1d418eSSumit Saxena mpi3mr_set_io_divert_for_all_vd_in_tg(sc, 12282d1d418eSSumit Saxena tg, 1); 12292d1d418eSSumit Saxena } 12302d1d418eSSumit Saxena } else { 12312d1d418eSSumit Saxena mpi3mr_atomic_add(&sc->pend_large_data_sz, data_len_blks); 12322d1d418eSSumit Saxena ioc_pend_data_len = mpi3mr_atomic_read(&sc->pend_large_data_sz); 12332d1d418eSSumit Saxena if (ratelimit % 1000) { 12342d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_IOT, 12352d1d418eSSumit Saxena "large pd_io persist_id(%d), handle(0x%04x), data_len(%d), ioc_pending(%d), ioc_high(%d)\n", 12362d1d418eSSumit Saxena targ->per_id, targ->dev_handle, 12372d1d418eSSumit Saxena data_len_blks, ioc_pend_data_len, 12382d1d418eSSumit Saxena sc->io_throttle_high); 12392d1d418eSSumit Saxena ratelimit++; 12402d1d418eSSumit Saxena } 12412d1d418eSSumit Saxena 12422d1d418eSSumit Saxena if (ioc_pend_data_len >= sc->io_throttle_high) { 12432d1d418eSSumit Saxena targ->io_divert = 1; 12442d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_IOT, 12452d1d418eSSumit Saxena "PD: Setting divert flag for persist_id(%d)\n", 12462d1d418eSSumit Saxena targ->per_id); 124734f0a01bSWarner Losh if (sc->mpi3mr_debug & MPI3MR_IOT) 12482d1d418eSSumit Saxena mpi3mr_print_cdb(ccb); 12492d1d418eSSumit Saxena } 12502d1d418eSSumit Saxena } 12512d1d418eSSumit Saxena } 12522d1d418eSSumit Saxena 12532d1d418eSSumit Saxena if (targ->io_divert) { 12542d1d418eSSumit Saxena req->MsgFlags |= MPI3_SCSIIO_MSGFLAGS_DIVERT_TO_FIRMWARE; 12553208a189SWarner Losh req->Flags = htole32(le32toh(req->Flags) | MPI3_SCSIIO_FLAGS_DIVERT_REASON_IO_THROTTLING); 12562d1d418eSSumit Saxena } 12572d1d418eSSumit Saxena } 12582d1d418eSSumit Saxena 1259e2b27df9SWarner Losh if (mpi3mr_submit_io(sc, opreqq, (U8 *)&cm->io_request)) { 12602d1d418eSSumit Saxena if (tracked_io_sz) { 12612d1d418eSSumit Saxena mpi3mr_atomic_sub(&sc->pend_large_data_sz, tracked_io_sz); 12622d1d418eSSumit Saxena if (tg) 12632d1d418eSSumit Saxena mpi3mr_atomic_sub(&tg->pend_large_data_sz, tracked_io_sz); 12642d1d418eSSumit Saxena } 12652d1d418eSSumit Saxena mpi3mr_set_ccbstatus(ccb, CAM_RESRC_UNAVAIL); 12663208a189SWarner Losh mpi3mr_release_command(cm); 12672d1d418eSSumit Saxena xpt_done(ccb); 12682d1d418eSSumit Saxena } else { 12691cfd0111SWarner Losh callout_reset_sbt(&cm->callout, mstosbt(ccb->ccb_h.timeout), 0, 12702d1d418eSSumit Saxena mpi3mr_scsiio_timeout, cm, 0); 12711cfd0111SWarner Losh cm->callout_owner = true; 12722d1d418eSSumit Saxena mpi3mr_atomic_inc(&sc->fw_outstanding); 12732d1d418eSSumit Saxena mpi3mr_atomic_inc(&targ->outstanding); 12742d1d418eSSumit Saxena if (mpi3mr_atomic_read(&sc->fw_outstanding) > sc->io_cmds_highwater) 12752d1d418eSSumit Saxena sc->io_cmds_highwater++; 12762d1d418eSSumit Saxena } 12772d1d418eSSumit Saxena 12782d1d418eSSumit Saxena return; 12792d1d418eSSumit Saxena } 12802d1d418eSSumit Saxena 12812d1d418eSSumit Saxena static void 12822d1d418eSSumit Saxena mpi3mr_cam_poll(struct cam_sim *sim) 12832d1d418eSSumit Saxena { 12842d1d418eSSumit Saxena struct mpi3mr_cam_softc *cam_sc; 12852d1d418eSSumit Saxena struct mpi3mr_irq_context *irq_ctx; 12862d1d418eSSumit Saxena struct mpi3mr_softc *sc; 12872d1d418eSSumit Saxena int i; 12882d1d418eSSumit Saxena 12892d1d418eSSumit Saxena cam_sc = cam_sim_softc(sim); 12902d1d418eSSumit Saxena sc = cam_sc->sc; 12912d1d418eSSumit Saxena 12922d1d418eSSumit Saxena mpi3mr_dprint(cam_sc->sc, MPI3MR_TRACE, "func: %s line: %d is called\n", 12932d1d418eSSumit Saxena __func__, __LINE__); 12942d1d418eSSumit Saxena 12952d1d418eSSumit Saxena for (i = 0; i < sc->num_queues; i++) { 12962d1d418eSSumit Saxena irq_ctx = sc->irq_ctx + i; 12972d1d418eSSumit Saxena if (irq_ctx->op_reply_q->qid) { 12982d1d418eSSumit Saxena mpi3mr_complete_io_cmd(sc, irq_ctx); 12992d1d418eSSumit Saxena } 13002d1d418eSSumit Saxena } 13012d1d418eSSumit Saxena } 13022d1d418eSSumit Saxena 13032d1d418eSSumit Saxena static void 13042d1d418eSSumit Saxena mpi3mr_cam_action(struct cam_sim *sim, union ccb *ccb) 13052d1d418eSSumit Saxena { 13062d1d418eSSumit Saxena struct mpi3mr_cam_softc *cam_sc; 13072d1d418eSSumit Saxena struct mpi3mr_target *targ; 13082d1d418eSSumit Saxena 13092d1d418eSSumit Saxena cam_sc = cam_sim_softc(sim); 13102d1d418eSSumit Saxena 13112d1d418eSSumit Saxena mpi3mr_dprint(cam_sc->sc, MPI3MR_TRACE, "ccb func_code 0x%x target id: 0x%x\n", 13122d1d418eSSumit Saxena ccb->ccb_h.func_code, ccb->ccb_h.target_id); 13132d1d418eSSumit Saxena 13142d1d418eSSumit Saxena mtx_assert(&cam_sc->sc->mpi3mr_mtx, MA_OWNED); 13152d1d418eSSumit Saxena 13162d1d418eSSumit Saxena switch (ccb->ccb_h.func_code) { 13172d1d418eSSumit Saxena case XPT_PATH_INQ: 13182d1d418eSSumit Saxena { 13192d1d418eSSumit Saxena struct ccb_pathinq *cpi = &ccb->cpi; 13202d1d418eSSumit Saxena 13212d1d418eSSumit Saxena cpi->version_num = 1; 13222d1d418eSSumit Saxena cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE|PI_WIDE_16; 13232d1d418eSSumit Saxena cpi->target_sprt = 0; 13242d1d418eSSumit Saxena cpi->hba_misc = PIM_NOBUSRESET | PIM_UNMAPPED | PIM_NOSCAN; 13252d1d418eSSumit Saxena cpi->hba_eng_cnt = 0; 13262d1d418eSSumit Saxena cpi->max_target = cam_sc->maxtargets - 1; 13272d1d418eSSumit Saxena cpi->max_lun = 0; 13282d1d418eSSumit Saxena 13292d1d418eSSumit Saxena /* 13302d1d418eSSumit Saxena * initiator_id is set here to an ID outside the set of valid 13312d1d418eSSumit Saxena * target IDs (including volumes). 13322d1d418eSSumit Saxena */ 13332d1d418eSSumit Saxena cpi->initiator_id = cam_sc->maxtargets; 13342d1d418eSSumit Saxena strlcpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 13352d1d418eSSumit Saxena strlcpy(cpi->hba_vid, "Broadcom", HBA_IDLEN); 13362d1d418eSSumit Saxena strlcpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 13372d1d418eSSumit Saxena cpi->unit_number = cam_sim_unit(sim); 13382d1d418eSSumit Saxena cpi->bus_id = cam_sim_bus(sim); 13392d1d418eSSumit Saxena /* 13402d1d418eSSumit Saxena * XXXSLM-I think this needs to change based on config page or 13412d1d418eSSumit Saxena * something instead of hardcoded to 150000. 13422d1d418eSSumit Saxena */ 13432d1d418eSSumit Saxena cpi->base_transfer_speed = 150000; 13442d1d418eSSumit Saxena cpi->transport = XPORT_SAS; 13452d1d418eSSumit Saxena cpi->transport_version = 0; 13462d1d418eSSumit Saxena cpi->protocol = PROTO_SCSI; 13472d1d418eSSumit Saxena cpi->protocol_version = SCSI_REV_SPC; 13482d1d418eSSumit Saxena 13492d1d418eSSumit Saxena targ = mpi3mr_find_target_by_per_id(cam_sc, ccb->ccb_h.target_id); 13502d1d418eSSumit Saxena 13512d1d418eSSumit Saxena if (targ && (targ->dev_type == MPI3_DEVICE_DEVFORM_PCIE) && 13522d1d418eSSumit Saxena ((targ->dev_spec.pcie_inf.dev_info & 13532d1d418eSSumit Saxena MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_MASK) == 13542d1d418eSSumit Saxena MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_NVME_DEVICE)) { 13552d1d418eSSumit Saxena cpi->maxio = targ->dev_spec.pcie_inf.mdts; 13562d1d418eSSumit Saxena mpi3mr_dprint(cam_sc->sc, MPI3MR_XINFO, 13572d1d418eSSumit Saxena "PCI device target_id: %u max io size: %u\n", 13582d1d418eSSumit Saxena ccb->ccb_h.target_id, cpi->maxio); 13592d1d418eSSumit Saxena } else { 13602d1d418eSSumit Saxena cpi->maxio = PAGE_SIZE * (MPI3MR_SG_DEPTH - 1); 13612d1d418eSSumit Saxena } 13622d1d418eSSumit Saxena mpi3mr_set_ccbstatus(ccb, CAM_REQ_CMP); 13632d1d418eSSumit Saxena break; 13642d1d418eSSumit Saxena } 13652d1d418eSSumit Saxena case XPT_GET_TRAN_SETTINGS: 13662d1d418eSSumit Saxena { 13672d1d418eSSumit Saxena struct ccb_trans_settings *cts; 13682d1d418eSSumit Saxena struct ccb_trans_settings_sas *sas; 13692d1d418eSSumit Saxena struct ccb_trans_settings_scsi *scsi; 13702d1d418eSSumit Saxena 13712d1d418eSSumit Saxena cts = &ccb->cts; 13722d1d418eSSumit Saxena sas = &cts->xport_specific.sas; 13732d1d418eSSumit Saxena scsi = &cts->proto_specific.scsi; 13742d1d418eSSumit Saxena 13752d1d418eSSumit Saxena KASSERT(cts->ccb_h.target_id < cam_sc->maxtargets, 13762d1d418eSSumit Saxena ("Target %d out of bounds in XPT_GET_TRAN_SETTINGS\n", 13772d1d418eSSumit Saxena cts->ccb_h.target_id)); 13782d1d418eSSumit Saxena targ = mpi3mr_find_target_by_per_id(cam_sc, cts->ccb_h.target_id); 13792d1d418eSSumit Saxena 13802d1d418eSSumit Saxena if (targ == NULL) { 13812d1d418eSSumit Saxena mpi3mr_dprint(cam_sc->sc, MPI3MR_TRACE, "Device with target ID: 0x%x does not exist\n", 13822d1d418eSSumit Saxena cts->ccb_h.target_id); 13832d1d418eSSumit Saxena mpi3mr_set_ccbstatus(ccb, CAM_DEV_NOT_THERE); 13842d1d418eSSumit Saxena break; 13852d1d418eSSumit Saxena } 13862d1d418eSSumit Saxena 13872d1d418eSSumit Saxena if ((targ->dev_handle == 0x0) || (targ->dev_removed == 1)) { 13882d1d418eSSumit Saxena mpi3mr_set_ccbstatus(ccb, CAM_DEV_NOT_THERE); 13892d1d418eSSumit Saxena break; 13902d1d418eSSumit Saxena } 13912d1d418eSSumit Saxena 13922d1d418eSSumit Saxena cts->protocol_version = SCSI_REV_SPC2; 13932d1d418eSSumit Saxena cts->transport = XPORT_SAS; 13942d1d418eSSumit Saxena cts->transport_version = 0; 13952d1d418eSSumit Saxena 13962d1d418eSSumit Saxena sas->valid = CTS_SAS_VALID_SPEED; 13972d1d418eSSumit Saxena 13982d1d418eSSumit Saxena switch (targ->link_rate) { 13992d1d418eSSumit Saxena case 0x08: 14002d1d418eSSumit Saxena sas->bitrate = 150000; 14012d1d418eSSumit Saxena break; 14022d1d418eSSumit Saxena case 0x09: 14032d1d418eSSumit Saxena sas->bitrate = 300000; 14042d1d418eSSumit Saxena break; 14052d1d418eSSumit Saxena case 0x0a: 14062d1d418eSSumit Saxena sas->bitrate = 600000; 14072d1d418eSSumit Saxena break; 14082d1d418eSSumit Saxena case 0x0b: 14092d1d418eSSumit Saxena sas->bitrate = 1200000; 14102d1d418eSSumit Saxena break; 14112d1d418eSSumit Saxena default: 14122d1d418eSSumit Saxena sas->valid = 0; 14132d1d418eSSumit Saxena } 14142d1d418eSSumit Saxena 14152d1d418eSSumit Saxena cts->protocol = PROTO_SCSI; 14162d1d418eSSumit Saxena scsi->valid = CTS_SCSI_VALID_TQ; 14172d1d418eSSumit Saxena scsi->flags = CTS_SCSI_FLAGS_TAG_ENB; 14182d1d418eSSumit Saxena 14192d1d418eSSumit Saxena mpi3mr_set_ccbstatus(ccb, CAM_REQ_CMP); 14202d1d418eSSumit Saxena break; 14212d1d418eSSumit Saxena } 14222d1d418eSSumit Saxena case XPT_CALC_GEOMETRY: 14232d1d418eSSumit Saxena cam_calc_geometry(&ccb->ccg, /*extended*/1); 14242d1d418eSSumit Saxena mpi3mr_set_ccbstatus(ccb, CAM_REQ_CMP); 14252d1d418eSSumit Saxena break; 14262d1d418eSSumit Saxena case XPT_RESET_DEV: 14272d1d418eSSumit Saxena mpi3mr_dprint(cam_sc->sc, MPI3MR_INFO, "mpi3mr_action " 14282d1d418eSSumit Saxena "XPT_RESET_DEV\n"); 14292d1d418eSSumit Saxena return; 14302d1d418eSSumit Saxena case XPT_RESET_BUS: 14312d1d418eSSumit Saxena case XPT_ABORT: 14322d1d418eSSumit Saxena case XPT_TERM_IO: 14332d1d418eSSumit Saxena mpi3mr_dprint(cam_sc->sc, MPI3MR_INFO, "mpi3mr_action faking success " 14342d1d418eSSumit Saxena "for abort or reset\n"); 14352d1d418eSSumit Saxena mpi3mr_set_ccbstatus(ccb, CAM_REQ_CMP); 14362d1d418eSSumit Saxena break; 14372d1d418eSSumit Saxena case XPT_SCSI_IO: 14382d1d418eSSumit Saxena mpi3mr_action_scsiio(cam_sc, ccb); 14392d1d418eSSumit Saxena return; 14402d1d418eSSumit Saxena default: 14412d1d418eSSumit Saxena mpi3mr_set_ccbstatus(ccb, CAM_FUNC_NOTAVAIL); 14422d1d418eSSumit Saxena break; 14432d1d418eSSumit Saxena } 14442d1d418eSSumit Saxena xpt_done(ccb); 14452d1d418eSSumit Saxena } 14462d1d418eSSumit Saxena 14472d1d418eSSumit Saxena void 14482d1d418eSSumit Saxena mpi3mr_startup_increment(struct mpi3mr_cam_softc *cam_sc) 14492d1d418eSSumit Saxena { 14502d1d418eSSumit Saxena if ((cam_sc->flags & MPI3MRSAS_IN_STARTUP) != 0) { 14512d1d418eSSumit Saxena if (cam_sc->startup_refcount++ == 0) { 14522d1d418eSSumit Saxena /* just starting, freeze the simq */ 14532d1d418eSSumit Saxena mpi3mr_dprint(cam_sc->sc, MPI3MR_XINFO, 14542d1d418eSSumit Saxena "%s freezing simq\n", __func__); 14552d1d418eSSumit Saxena xpt_hold_boot(); 14562d1d418eSSumit Saxena } 14572d1d418eSSumit Saxena mpi3mr_dprint(cam_sc->sc, MPI3MR_XINFO, "%s refcount %u\n", __func__, 14582d1d418eSSumit Saxena cam_sc->startup_refcount); 14592d1d418eSSumit Saxena } 14602d1d418eSSumit Saxena } 14612d1d418eSSumit Saxena 14622d1d418eSSumit Saxena void 14632d1d418eSSumit Saxena mpi3mr_release_simq_reinit(struct mpi3mr_cam_softc *cam_sc) 14642d1d418eSSumit Saxena { 14652d1d418eSSumit Saxena if (cam_sc->flags & MPI3MRSAS_QUEUE_FROZEN) { 14662d1d418eSSumit Saxena cam_sc->flags &= ~MPI3MRSAS_QUEUE_FROZEN; 14672d1d418eSSumit Saxena xpt_release_simq(cam_sc->sim, 1); 14682d1d418eSSumit Saxena mpi3mr_dprint(cam_sc->sc, MPI3MR_INFO, "Unfreezing SIM queue\n"); 14692d1d418eSSumit Saxena } 14702d1d418eSSumit Saxena } 14712d1d418eSSumit Saxena 14722d1d418eSSumit Saxena void 14732d1d418eSSumit Saxena mpi3mr_rescan_target(struct mpi3mr_softc *sc, struct mpi3mr_target *targ) 14742d1d418eSSumit Saxena { 14752d1d418eSSumit Saxena struct mpi3mr_cam_softc *cam_sc = sc->cam_sc; 14762d1d418eSSumit Saxena path_id_t pathid; 14772d1d418eSSumit Saxena target_id_t targetid; 14782d1d418eSSumit Saxena union ccb *ccb; 14792d1d418eSSumit Saxena 14802d1d418eSSumit Saxena pathid = cam_sim_path(cam_sc->sim); 14812d1d418eSSumit Saxena if (targ == NULL) 14822d1d418eSSumit Saxena targetid = CAM_TARGET_WILDCARD; 14832d1d418eSSumit Saxena else 14842d1d418eSSumit Saxena targetid = targ->per_id; 14852d1d418eSSumit Saxena 14862d1d418eSSumit Saxena /* 14872d1d418eSSumit Saxena * Allocate a CCB and schedule a rescan. 14882d1d418eSSumit Saxena */ 14892d1d418eSSumit Saxena ccb = xpt_alloc_ccb_nowait(); 14902d1d418eSSumit Saxena if (ccb == NULL) { 14912d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_ERROR, "unable to alloc CCB for rescan\n"); 14922d1d418eSSumit Saxena return; 14932d1d418eSSumit Saxena } 14942d1d418eSSumit Saxena 14952d1d418eSSumit Saxena if (xpt_create_path(&ccb->ccb_h.path, NULL, pathid, targetid, 14962d1d418eSSumit Saxena CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 14972d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_ERROR, "unable to create path for rescan\n"); 14982d1d418eSSumit Saxena xpt_free_ccb(ccb); 14992d1d418eSSumit Saxena return; 15002d1d418eSSumit Saxena } 15012d1d418eSSumit Saxena 15022d1d418eSSumit Saxena if (targetid == CAM_TARGET_WILDCARD) 15032d1d418eSSumit Saxena ccb->ccb_h.func_code = XPT_SCAN_BUS; 15042d1d418eSSumit Saxena else 15052d1d418eSSumit Saxena ccb->ccb_h.func_code = XPT_SCAN_TGT; 15062d1d418eSSumit Saxena 15072d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_EVENT, "%s target id 0x%x\n", __func__, targetid); 15082d1d418eSSumit Saxena xpt_rescan(ccb); 15092d1d418eSSumit Saxena } 15102d1d418eSSumit Saxena 15112d1d418eSSumit Saxena void 15122d1d418eSSumit Saxena mpi3mr_startup_decrement(struct mpi3mr_cam_softc *cam_sc) 15132d1d418eSSumit Saxena { 15142d1d418eSSumit Saxena if ((cam_sc->flags & MPI3MRSAS_IN_STARTUP) != 0) { 15152d1d418eSSumit Saxena if (--cam_sc->startup_refcount == 0) { 15162d1d418eSSumit Saxena /* finished all discovery-related actions, release 15172d1d418eSSumit Saxena * the simq and rescan for the latest topology. 15182d1d418eSSumit Saxena */ 15192d1d418eSSumit Saxena mpi3mr_dprint(cam_sc->sc, MPI3MR_XINFO, 15202d1d418eSSumit Saxena "%s releasing simq\n", __func__); 15212d1d418eSSumit Saxena cam_sc->flags &= ~MPI3MRSAS_IN_STARTUP; 15222d1d418eSSumit Saxena xpt_release_simq(cam_sc->sim, 1); 15232d1d418eSSumit Saxena xpt_release_boot(); 15242d1d418eSSumit Saxena } 15252d1d418eSSumit Saxena mpi3mr_dprint(cam_sc->sc, MPI3MR_XINFO, "%s refcount %u\n", __func__, 15262d1d418eSSumit Saxena cam_sc->startup_refcount); 15272d1d418eSSumit Saxena } 15282d1d418eSSumit Saxena } 15292d1d418eSSumit Saxena 15302d1d418eSSumit Saxena static void 15312d1d418eSSumit Saxena mpi3mr_fw_event_free(struct mpi3mr_softc *sc, struct mpi3mr_fw_event_work *fw_event) 15322d1d418eSSumit Saxena { 15332d1d418eSSumit Saxena if (!fw_event) 15342d1d418eSSumit Saxena return; 15352d1d418eSSumit Saxena 15362d1d418eSSumit Saxena if (fw_event->event_data != NULL) { 15372d1d418eSSumit Saxena free(fw_event->event_data, M_MPI3MR); 15382d1d418eSSumit Saxena fw_event->event_data = NULL; 15392d1d418eSSumit Saxena } 15402d1d418eSSumit Saxena 15412d1d418eSSumit Saxena free(fw_event, M_MPI3MR); 15422d1d418eSSumit Saxena fw_event = NULL; 15432d1d418eSSumit Saxena } 15442d1d418eSSumit Saxena 15452d1d418eSSumit Saxena static void 15462d1d418eSSumit Saxena mpi3mr_freeup_events(struct mpi3mr_softc *sc) 15472d1d418eSSumit Saxena { 15482d1d418eSSumit Saxena struct mpi3mr_fw_event_work *fw_event = NULL; 15492d1d418eSSumit Saxena mtx_lock(&sc->mpi3mr_mtx); 15502d1d418eSSumit Saxena while ((fw_event = TAILQ_FIRST(&sc->cam_sc->ev_queue)) != NULL) { 15512d1d418eSSumit Saxena TAILQ_REMOVE(&sc->cam_sc->ev_queue, fw_event, ev_link); 15522d1d418eSSumit Saxena mpi3mr_fw_event_free(sc, fw_event); 15532d1d418eSSumit Saxena } 15542d1d418eSSumit Saxena mtx_unlock(&sc->mpi3mr_mtx); 15552d1d418eSSumit Saxena } 15562d1d418eSSumit Saxena 15572d1d418eSSumit Saxena static void 15582d1d418eSSumit Saxena mpi3mr_sastopochg_evt_debug(struct mpi3mr_softc *sc, 15592d1d418eSSumit Saxena Mpi3EventDataSasTopologyChangeList_t *event_data) 15602d1d418eSSumit Saxena { 15612d1d418eSSumit Saxena int i; 15622d1d418eSSumit Saxena U16 handle; 15632d1d418eSSumit Saxena U8 reason_code, phy_number; 15642d1d418eSSumit Saxena char *status_str = NULL; 15652d1d418eSSumit Saxena U8 link_rate, prev_link_rate; 15662d1d418eSSumit Saxena 15672d1d418eSSumit Saxena switch (event_data->ExpStatus) { 15682d1d418eSSumit Saxena case MPI3_EVENT_SAS_TOPO_ES_NOT_RESPONDING: 15692d1d418eSSumit Saxena status_str = "remove"; 15702d1d418eSSumit Saxena break; 15712d1d418eSSumit Saxena case MPI3_EVENT_SAS_TOPO_ES_RESPONDING: 15722d1d418eSSumit Saxena status_str = "responding"; 15732d1d418eSSumit Saxena break; 15742d1d418eSSumit Saxena case MPI3_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING: 15752d1d418eSSumit Saxena status_str = "remove delay"; 15762d1d418eSSumit Saxena break; 15772d1d418eSSumit Saxena case MPI3_EVENT_SAS_TOPO_ES_NO_EXPANDER: 15782d1d418eSSumit Saxena status_str = "direct attached"; 15792d1d418eSSumit Saxena break; 15802d1d418eSSumit Saxena default: 15812d1d418eSSumit Saxena status_str = "unknown status"; 15822d1d418eSSumit Saxena break; 15832d1d418eSSumit Saxena } 15842d1d418eSSumit Saxena 15852d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_INFO, "%s :sas topology change: (%s)\n", 15862d1d418eSSumit Saxena __func__, status_str); 15872d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_INFO, 15882d1d418eSSumit Saxena "%s :\texpander_handle(0x%04x), enclosure_handle(0x%04x) " 15892d1d418eSSumit Saxena "start_phy(%02d), num_entries(%d)\n", __func__, 15902d1d418eSSumit Saxena (event_data->ExpanderDevHandle), 15912d1d418eSSumit Saxena (event_data->EnclosureHandle), 15922d1d418eSSumit Saxena event_data->StartPhyNum, event_data->NumEntries); 15932d1d418eSSumit Saxena for (i = 0; i < event_data->NumEntries; i++) { 15942d1d418eSSumit Saxena handle = (event_data->PhyEntry[i].AttachedDevHandle); 15952d1d418eSSumit Saxena if (!handle) 15962d1d418eSSumit Saxena continue; 15972d1d418eSSumit Saxena phy_number = event_data->StartPhyNum + i; 1598baabb919SChandrakanth patil reason_code = event_data->PhyEntry[i].PhyStatus & 15992d1d418eSSumit Saxena MPI3_EVENT_SAS_TOPO_PHY_RC_MASK; 16002d1d418eSSumit Saxena switch (reason_code) { 16012d1d418eSSumit Saxena case MPI3_EVENT_SAS_TOPO_PHY_RC_TARG_NOT_RESPONDING: 16022d1d418eSSumit Saxena status_str = "target remove"; 16032d1d418eSSumit Saxena break; 16042d1d418eSSumit Saxena case MPI3_EVENT_SAS_TOPO_PHY_RC_DELAY_NOT_RESPONDING: 16052d1d418eSSumit Saxena status_str = "delay target remove"; 16062d1d418eSSumit Saxena break; 16072d1d418eSSumit Saxena case MPI3_EVENT_SAS_TOPO_PHY_RC_PHY_CHANGED: 16082d1d418eSSumit Saxena status_str = "link rate change"; 16092d1d418eSSumit Saxena break; 16102d1d418eSSumit Saxena case MPI3_EVENT_SAS_TOPO_PHY_RC_NO_CHANGE: 16112d1d418eSSumit Saxena status_str = "target responding"; 16122d1d418eSSumit Saxena break; 16132d1d418eSSumit Saxena default: 16142d1d418eSSumit Saxena status_str = "unknown"; 16152d1d418eSSumit Saxena break; 16162d1d418eSSumit Saxena } 16172d1d418eSSumit Saxena link_rate = event_data->PhyEntry[i].LinkRate >> 4; 16182d1d418eSSumit Saxena prev_link_rate = event_data->PhyEntry[i].LinkRate & 0xF; 16192d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_INFO, "%s :\tphy(%02d), attached_handle(0x%04x): %s:" 16202d1d418eSSumit Saxena " link rate: new(0x%02x), old(0x%02x)\n", __func__, 16212d1d418eSSumit Saxena phy_number, handle, status_str, link_rate, prev_link_rate); 16222d1d418eSSumit Saxena } 16232d1d418eSSumit Saxena } 16242d1d418eSSumit Saxena 16252d1d418eSSumit Saxena static void 16262d1d418eSSumit Saxena mpi3mr_process_sastopochg_evt(struct mpi3mr_softc *sc, struct mpi3mr_fw_event_work *fwevt) 16272d1d418eSSumit Saxena { 16282d1d418eSSumit Saxena 16292d1d418eSSumit Saxena Mpi3EventDataSasTopologyChangeList_t *event_data = 16302d1d418eSSumit Saxena (Mpi3EventDataSasTopologyChangeList_t *)fwevt->event_data; 16312d1d418eSSumit Saxena int i; 16322d1d418eSSumit Saxena U16 handle; 16332d1d418eSSumit Saxena U8 reason_code, link_rate; 16342d1d418eSSumit Saxena struct mpi3mr_target *target = NULL; 16352d1d418eSSumit Saxena 16362d1d418eSSumit Saxena 16372d1d418eSSumit Saxena mpi3mr_sastopochg_evt_debug(sc, event_data); 16382d1d418eSSumit Saxena 16392d1d418eSSumit Saxena for (i = 0; i < event_data->NumEntries; i++) { 16402d1d418eSSumit Saxena handle = le16toh(event_data->PhyEntry[i].AttachedDevHandle); 16412d1d418eSSumit Saxena link_rate = event_data->PhyEntry[i].LinkRate >> 4; 16422d1d418eSSumit Saxena 16432d1d418eSSumit Saxena if (!handle) 16442d1d418eSSumit Saxena continue; 16452d1d418eSSumit Saxena target = mpi3mr_find_target_by_dev_handle(sc->cam_sc, handle); 16462d1d418eSSumit Saxena 16472d1d418eSSumit Saxena if (!target) 16482d1d418eSSumit Saxena continue; 16492d1d418eSSumit Saxena 16502d1d418eSSumit Saxena target->link_rate = link_rate; 1651baabb919SChandrakanth patil reason_code = event_data->PhyEntry[i].PhyStatus & 16522d1d418eSSumit Saxena MPI3_EVENT_SAS_TOPO_PHY_RC_MASK; 16532d1d418eSSumit Saxena 16542d1d418eSSumit Saxena switch (reason_code) { 16552d1d418eSSumit Saxena case MPI3_EVENT_SAS_TOPO_PHY_RC_TARG_NOT_RESPONDING: 16562d1d418eSSumit Saxena if (target->exposed_to_os) 16572d1d418eSSumit Saxena mpi3mr_remove_device_from_os(sc, target->dev_handle); 16582d1d418eSSumit Saxena mpi3mr_remove_device_from_list(sc, target, false); 16592d1d418eSSumit Saxena break; 16602d1d418eSSumit Saxena case MPI3_EVENT_SAS_TOPO_PHY_RC_PHY_CHANGED: 16612d1d418eSSumit Saxena break; 16622d1d418eSSumit Saxena default: 16632d1d418eSSumit Saxena break; 16642d1d418eSSumit Saxena } 16652d1d418eSSumit Saxena } 16662d1d418eSSumit Saxena 16672d1d418eSSumit Saxena /* 16682d1d418eSSumit Saxena * refcount was incremented for this event in 16692d1d418eSSumit Saxena * mpi3mr_evt_handler. Decrement it here because the event has 16702d1d418eSSumit Saxena * been processed. 16712d1d418eSSumit Saxena */ 16722d1d418eSSumit Saxena mpi3mr_startup_decrement(sc->cam_sc); 16732d1d418eSSumit Saxena return; 16742d1d418eSSumit Saxena } 16752d1d418eSSumit Saxena 16762d1d418eSSumit Saxena static inline void 16772d1d418eSSumit Saxena mpi3mr_logdata_evt_bh(struct mpi3mr_softc *sc, 16782d1d418eSSumit Saxena struct mpi3mr_fw_event_work *fwevt) 16792d1d418eSSumit Saxena { 16802d1d418eSSumit Saxena mpi3mr_app_save_logdata(sc, fwevt->event_data, 16812d1d418eSSumit Saxena fwevt->event_data_size); 16822d1d418eSSumit Saxena } 16832d1d418eSSumit Saxena 16842d1d418eSSumit Saxena static void 16852d1d418eSSumit Saxena mpi3mr_pcietopochg_evt_debug(struct mpi3mr_softc *sc, 16862d1d418eSSumit Saxena Mpi3EventDataPcieTopologyChangeList_t *event_data) 16872d1d418eSSumit Saxena { 16882d1d418eSSumit Saxena int i; 16892d1d418eSSumit Saxena U16 handle; 16902d1d418eSSumit Saxena U16 reason_code; 16912d1d418eSSumit Saxena U8 port_number; 16922d1d418eSSumit Saxena char *status_str = NULL; 16932d1d418eSSumit Saxena U8 link_rate, prev_link_rate; 16942d1d418eSSumit Saxena 16952d1d418eSSumit Saxena switch (event_data->SwitchStatus) { 16962d1d418eSSumit Saxena case MPI3_EVENT_PCIE_TOPO_SS_NOT_RESPONDING: 16972d1d418eSSumit Saxena status_str = "remove"; 16982d1d418eSSumit Saxena break; 16992d1d418eSSumit Saxena case MPI3_EVENT_PCIE_TOPO_SS_RESPONDING: 17002d1d418eSSumit Saxena status_str = "responding"; 17012d1d418eSSumit Saxena break; 17022d1d418eSSumit Saxena case MPI3_EVENT_PCIE_TOPO_SS_DELAY_NOT_RESPONDING: 17032d1d418eSSumit Saxena status_str = "remove delay"; 17042d1d418eSSumit Saxena break; 17052d1d418eSSumit Saxena case MPI3_EVENT_PCIE_TOPO_SS_NO_PCIE_SWITCH: 17062d1d418eSSumit Saxena status_str = "direct attached"; 17072d1d418eSSumit Saxena break; 17082d1d418eSSumit Saxena default: 17092d1d418eSSumit Saxena status_str = "unknown status"; 17102d1d418eSSumit Saxena break; 17112d1d418eSSumit Saxena } 17122d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_INFO, "%s :pcie topology change: (%s)\n", 17132d1d418eSSumit Saxena __func__, status_str); 17142d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_INFO, 17152d1d418eSSumit Saxena "%s :\tswitch_handle(0x%04x), enclosure_handle(0x%04x)" 17162d1d418eSSumit Saxena "start_port(%02d), num_entries(%d)\n", __func__, 17172d1d418eSSumit Saxena le16toh(event_data->SwitchDevHandle), 17182d1d418eSSumit Saxena le16toh(event_data->EnclosureHandle), 17192d1d418eSSumit Saxena event_data->StartPortNum, event_data->NumEntries); 17202d1d418eSSumit Saxena for (i = 0; i < event_data->NumEntries; i++) { 17212d1d418eSSumit Saxena handle = 17222d1d418eSSumit Saxena le16toh(event_data->PortEntry[i].AttachedDevHandle); 17232d1d418eSSumit Saxena if (!handle) 17242d1d418eSSumit Saxena continue; 17252d1d418eSSumit Saxena port_number = event_data->StartPortNum + i; 17262d1d418eSSumit Saxena reason_code = event_data->PortEntry[i].PortStatus; 17272d1d418eSSumit Saxena switch (reason_code) { 17282d1d418eSSumit Saxena case MPI3_EVENT_PCIE_TOPO_PS_NOT_RESPONDING: 17292d1d418eSSumit Saxena status_str = "target remove"; 17302d1d418eSSumit Saxena break; 17312d1d418eSSumit Saxena case MPI3_EVENT_PCIE_TOPO_PS_DELAY_NOT_RESPONDING: 17322d1d418eSSumit Saxena status_str = "delay target remove"; 17332d1d418eSSumit Saxena break; 17342d1d418eSSumit Saxena case MPI3_EVENT_PCIE_TOPO_PS_PORT_CHANGED: 17352d1d418eSSumit Saxena status_str = "link rate change"; 17362d1d418eSSumit Saxena break; 17372d1d418eSSumit Saxena case MPI3_EVENT_PCIE_TOPO_PS_NO_CHANGE: 17382d1d418eSSumit Saxena status_str = "target responding"; 17392d1d418eSSumit Saxena break; 17402d1d418eSSumit Saxena default: 17412d1d418eSSumit Saxena status_str = "unknown"; 17422d1d418eSSumit Saxena break; 17432d1d418eSSumit Saxena } 17442d1d418eSSumit Saxena link_rate = event_data->PortEntry[i].CurrentPortInfo & 17452d1d418eSSumit Saxena MPI3_EVENT_PCIE_TOPO_PI_RATE_MASK; 17462d1d418eSSumit Saxena prev_link_rate = event_data->PortEntry[i].PreviousPortInfo & 17472d1d418eSSumit Saxena MPI3_EVENT_PCIE_TOPO_PI_RATE_MASK; 17482d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_INFO, "%s :\tport(%02d), attached_handle(0x%04x): %s:" 17492d1d418eSSumit Saxena " link rate: new(0x%02x), old(0x%02x)\n", __func__, 17502d1d418eSSumit Saxena port_number, handle, status_str, link_rate, prev_link_rate); 17512d1d418eSSumit Saxena } 17522d1d418eSSumit Saxena } 17532d1d418eSSumit Saxena 17542d1d418eSSumit Saxena static void mpi3mr_process_pcietopochg_evt(struct mpi3mr_softc *sc, 17552d1d418eSSumit Saxena struct mpi3mr_fw_event_work *fwevt) 17562d1d418eSSumit Saxena { 17572d1d418eSSumit Saxena Mpi3EventDataPcieTopologyChangeList_t *event_data = 17582d1d418eSSumit Saxena (Mpi3EventDataPcieTopologyChangeList_t *)fwevt->event_data; 17592d1d418eSSumit Saxena int i; 17602d1d418eSSumit Saxena U16 handle; 17612d1d418eSSumit Saxena U8 reason_code, link_rate; 17622d1d418eSSumit Saxena struct mpi3mr_target *target = NULL; 17632d1d418eSSumit Saxena 17642d1d418eSSumit Saxena 17652d1d418eSSumit Saxena mpi3mr_pcietopochg_evt_debug(sc, event_data); 17662d1d418eSSumit Saxena 17672d1d418eSSumit Saxena for (i = 0; i < event_data->NumEntries; i++) { 17682d1d418eSSumit Saxena handle = 17692d1d418eSSumit Saxena le16toh(event_data->PortEntry[i].AttachedDevHandle); 17702d1d418eSSumit Saxena if (!handle) 17712d1d418eSSumit Saxena continue; 17722d1d418eSSumit Saxena target = mpi3mr_find_target_by_dev_handle(sc->cam_sc, handle); 17732d1d418eSSumit Saxena if (!target) 17742d1d418eSSumit Saxena continue; 17752d1d418eSSumit Saxena 17762d1d418eSSumit Saxena link_rate = event_data->PortEntry[i].CurrentPortInfo & 17772d1d418eSSumit Saxena MPI3_EVENT_PCIE_TOPO_PI_RATE_MASK; 17782d1d418eSSumit Saxena target->link_rate = link_rate; 17792d1d418eSSumit Saxena 17802d1d418eSSumit Saxena reason_code = event_data->PortEntry[i].PortStatus; 17812d1d418eSSumit Saxena 17822d1d418eSSumit Saxena switch (reason_code) { 17832d1d418eSSumit Saxena case MPI3_EVENT_PCIE_TOPO_PS_NOT_RESPONDING: 17842d1d418eSSumit Saxena if (target->exposed_to_os) 17852d1d418eSSumit Saxena mpi3mr_remove_device_from_os(sc, target->dev_handle); 17862d1d418eSSumit Saxena mpi3mr_remove_device_from_list(sc, target, false); 17872d1d418eSSumit Saxena break; 17882d1d418eSSumit Saxena case MPI3_EVENT_PCIE_TOPO_PS_PORT_CHANGED: 17892d1d418eSSumit Saxena break; 17902d1d418eSSumit Saxena default: 17912d1d418eSSumit Saxena break; 17922d1d418eSSumit Saxena } 17932d1d418eSSumit Saxena } 17942d1d418eSSumit Saxena 17952d1d418eSSumit Saxena /* 17962d1d418eSSumit Saxena * refcount was incremented for this event in 17972d1d418eSSumit Saxena * mpi3mr_evt_handler. Decrement it here because the event has 17982d1d418eSSumit Saxena * been processed. 17992d1d418eSSumit Saxena */ 18002d1d418eSSumit Saxena mpi3mr_startup_decrement(sc->cam_sc); 18012d1d418eSSumit Saxena return; 18022d1d418eSSumit Saxena } 18032d1d418eSSumit Saxena 18042d1d418eSSumit Saxena void mpi3mr_add_device(struct mpi3mr_softc *sc, U16 per_id) 18052d1d418eSSumit Saxena { 18062d1d418eSSumit Saxena struct mpi3mr_target *target; 18072d1d418eSSumit Saxena 18082d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_EVENT, 18092d1d418eSSumit Saxena "Adding device(persistent id: 0x%x)\n", per_id); 18102d1d418eSSumit Saxena 18112d1d418eSSumit Saxena mpi3mr_startup_increment(sc->cam_sc); 18122d1d418eSSumit Saxena target = mpi3mr_find_target_by_per_id(sc->cam_sc, per_id); 18132d1d418eSSumit Saxena 18142d1d418eSSumit Saxena if (!target) { 18152d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_INFO, "Not available in driver's" 18162d1d418eSSumit Saxena "internal target list, persistent_id: %d\n", 18172d1d418eSSumit Saxena per_id); 18182d1d418eSSumit Saxena goto out; 18192d1d418eSSumit Saxena } 18202d1d418eSSumit Saxena 18212d1d418eSSumit Saxena if (target->is_hidden) { 18222d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_EVENT, "Target is hidden, persistent_id: %d\n", 18232d1d418eSSumit Saxena per_id); 18242d1d418eSSumit Saxena goto out; 18252d1d418eSSumit Saxena } 18262d1d418eSSumit Saxena 18272d1d418eSSumit Saxena if (!target->exposed_to_os && !sc->reset_in_progress) { 18282d1d418eSSumit Saxena mpi3mr_rescan_target(sc, target); 18292d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_INFO, 18302d1d418eSSumit Saxena "Added device persistent_id: %d dev_handle: %d\n", per_id, target->dev_handle); 18312d1d418eSSumit Saxena target->exposed_to_os = 1; 18322d1d418eSSumit Saxena } 18332d1d418eSSumit Saxena 18342d1d418eSSumit Saxena out: 18352d1d418eSSumit Saxena mpi3mr_startup_decrement(sc->cam_sc); 18362d1d418eSSumit Saxena } 18372d1d418eSSumit Saxena 18382d1d418eSSumit Saxena int mpi3mr_remove_device_from_os(struct mpi3mr_softc *sc, U16 handle) 18392d1d418eSSumit Saxena { 18402d1d418eSSumit Saxena int retval = 0; 18412d1d418eSSumit Saxena struct mpi3mr_target *target; 1842*8d3c3b52SChandrakanth patil unsigned int target_outstanding; 18432d1d418eSSumit Saxena 18442d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_EVENT, 18452d1d418eSSumit Saxena "Removing Device (dev_handle: %d)\n", handle); 18462d1d418eSSumit Saxena 18472d1d418eSSumit Saxena target = mpi3mr_find_target_by_dev_handle(sc->cam_sc, handle); 18482d1d418eSSumit Saxena 18492d1d418eSSumit Saxena if (!target) { 18502d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_INFO, 18512d1d418eSSumit Saxena "Device (persistent_id: %d dev_handle: %d) is already removed from driver's list\n", 18522d1d418eSSumit Saxena target->per_id, handle); 18532d1d418eSSumit Saxena mpi3mr_rescan_target(sc, NULL); 18542d1d418eSSumit Saxena retval = -1; 18552d1d418eSSumit Saxena goto out; 18562d1d418eSSumit Saxena } 18572d1d418eSSumit Saxena 18582d1d418eSSumit Saxena target->flags |= MPI3MRSAS_TARGET_INREMOVAL; 18592d1d418eSSumit Saxena 1860*8d3c3b52SChandrakanth patil target_outstanding = mpi3mr_atomic_read(&target->outstanding); 1861*8d3c3b52SChandrakanth patil if (target_outstanding) { 1862701d776cSChandrakanth patil mpi3mr_dprint(sc, MPI3MR_ERROR, "there are [%2d] outstanding IOs on target: %d " 1863*8d3c3b52SChandrakanth patil "Poll reply queue once\n", target_outstanding, target->per_id); 1864701d776cSChandrakanth patil mpi3mr_poll_pend_io_completions(sc); 1865*8d3c3b52SChandrakanth patil target_outstanding = mpi3mr_atomic_read(&target->outstanding); 1866*8d3c3b52SChandrakanth patil if (target_outstanding) 1867*8d3c3b52SChandrakanth patil target_outstanding = mpi3mr_atomic_read(&target->outstanding); 1868701d776cSChandrakanth patil mpi3mr_dprint(sc, MPI3MR_ERROR, "[%2d] outstanding IOs present on target: %d " 1869*8d3c3b52SChandrakanth patil "despite poll\n", target_outstanding, target->per_id); 1870701d776cSChandrakanth patil } 1871701d776cSChandrakanth patil 18722d1d418eSSumit Saxena if (target->exposed_to_os && !sc->reset_in_progress) { 18732d1d418eSSumit Saxena mpi3mr_rescan_target(sc, target); 18742d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_INFO, 18752d1d418eSSumit Saxena "Removed device(persistent_id: %d dev_handle: %d)\n", target->per_id, handle); 18762d1d418eSSumit Saxena target->exposed_to_os = 0; 18772d1d418eSSumit Saxena } 18782d1d418eSSumit Saxena 18792d1d418eSSumit Saxena target->flags &= ~MPI3MRSAS_TARGET_INREMOVAL; 18802d1d418eSSumit Saxena out: 18812d1d418eSSumit Saxena return retval; 18822d1d418eSSumit Saxena } 18832d1d418eSSumit Saxena 18842d1d418eSSumit Saxena void mpi3mr_remove_device_from_list(struct mpi3mr_softc *sc, 18852d1d418eSSumit Saxena struct mpi3mr_target *target, bool must_delete) 18862d1d418eSSumit Saxena { 1887701d776cSChandrakanth patil if ((must_delete == false) && 1888701d776cSChandrakanth patil (target->state != MPI3MR_DEV_REMOVE_HS_COMPLETED)) 1889701d776cSChandrakanth patil return; 1890701d776cSChandrakanth patil 18912d1d418eSSumit Saxena mtx_lock_spin(&sc->target_lock); 18922d1d418eSSumit Saxena TAILQ_REMOVE(&sc->cam_sc->tgt_list, target, tgt_next); 18932d1d418eSSumit Saxena mtx_unlock_spin(&sc->target_lock); 18942d1d418eSSumit Saxena 18952d1d418eSSumit Saxena free(target, M_MPI3MR); 18962d1d418eSSumit Saxena target = NULL; 18972d1d418eSSumit Saxena 18982d1d418eSSumit Saxena return; 18992d1d418eSSumit Saxena } 19002d1d418eSSumit Saxena 19012d1d418eSSumit Saxena /** 19022d1d418eSSumit Saxena * mpi3mr_devstatuschg_evt_bh - DevStatusChange evt bottomhalf 19032d1d418eSSumit Saxena * @sc: Adapter instance reference 19042d1d418eSSumit Saxena * @fwevt: Firmware event 19052d1d418eSSumit Saxena * 19062d1d418eSSumit Saxena * Process Device Status Change event and based on device's new 19072d1d418eSSumit Saxena * information, either expose the device to the upper layers, or 19082d1d418eSSumit Saxena * remove the device from upper layers. 19092d1d418eSSumit Saxena * 19102d1d418eSSumit Saxena * Return: Nothing. 19112d1d418eSSumit Saxena */ 19122d1d418eSSumit Saxena static void mpi3mr_devstatuschg_evt_bh(struct mpi3mr_softc *sc, 19132d1d418eSSumit Saxena struct mpi3mr_fw_event_work *fwevt) 19142d1d418eSSumit Saxena { 19152d1d418eSSumit Saxena U16 dev_handle = 0; 19162d1d418eSSumit Saxena U8 uhide = 0, delete = 0, cleanup = 0; 19172d1d418eSSumit Saxena struct mpi3mr_target *tgtdev = NULL; 19182d1d418eSSumit Saxena Mpi3EventDataDeviceStatusChange_t *evtdata = 19192d1d418eSSumit Saxena (Mpi3EventDataDeviceStatusChange_t *)fwevt->event_data; 19202d1d418eSSumit Saxena 19212d1d418eSSumit Saxena 19222d1d418eSSumit Saxena 19232d1d418eSSumit Saxena dev_handle = le16toh(evtdata->DevHandle); 19242d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_INFO, 19252d1d418eSSumit Saxena "%s :device status change: handle(0x%04x): reason code(0x%x)\n", 19262d1d418eSSumit Saxena __func__, dev_handle, evtdata->ReasonCode); 19272d1d418eSSumit Saxena switch (evtdata->ReasonCode) { 19282d1d418eSSumit Saxena case MPI3_EVENT_DEV_STAT_RC_HIDDEN: 19292d1d418eSSumit Saxena delete = 1; 19302d1d418eSSumit Saxena break; 19312d1d418eSSumit Saxena case MPI3_EVENT_DEV_STAT_RC_NOT_HIDDEN: 19322d1d418eSSumit Saxena uhide = 1; 19332d1d418eSSumit Saxena break; 19342d1d418eSSumit Saxena case MPI3_EVENT_DEV_STAT_RC_VD_NOT_RESPONDING: 19352d1d418eSSumit Saxena delete = 1; 19362d1d418eSSumit Saxena cleanup = 1; 19372d1d418eSSumit Saxena break; 19382d1d418eSSumit Saxena default: 19392d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_INFO, "%s :Unhandled reason code(0x%x)\n", __func__, 19402d1d418eSSumit Saxena evtdata->ReasonCode); 19412d1d418eSSumit Saxena break; 19422d1d418eSSumit Saxena } 19432d1d418eSSumit Saxena 19442d1d418eSSumit Saxena tgtdev = mpi3mr_find_target_by_dev_handle(sc->cam_sc, dev_handle); 19452d1d418eSSumit Saxena if (!tgtdev) 19462d1d418eSSumit Saxena return; 19472d1d418eSSumit Saxena 19482d1d418eSSumit Saxena if (uhide) { 19492d1d418eSSumit Saxena if (!tgtdev->exposed_to_os) 19502d1d418eSSumit Saxena mpi3mr_add_device(sc, tgtdev->per_id); 19512d1d418eSSumit Saxena } 19522d1d418eSSumit Saxena 19532d1d418eSSumit Saxena if (delete) 19542d1d418eSSumit Saxena mpi3mr_remove_device_from_os(sc, dev_handle); 19552d1d418eSSumit Saxena 19562d1d418eSSumit Saxena if (cleanup) 19572d1d418eSSumit Saxena mpi3mr_remove_device_from_list(sc, tgtdev, false); 19582d1d418eSSumit Saxena } 19592d1d418eSSumit Saxena 19602d1d418eSSumit Saxena /** 19612d1d418eSSumit Saxena * mpi3mr_devinfochg_evt_bh - DeviceInfoChange evt bottomhalf 19622d1d418eSSumit Saxena * @sc: Adapter instance reference 19632d1d418eSSumit Saxena * @dev_pg0: New device page0 19642d1d418eSSumit Saxena * 19652d1d418eSSumit Saxena * Process Device Info Change event and based on device's new 19662d1d418eSSumit Saxena * information, either expose the device to the upper layers, or 19672d1d418eSSumit Saxena * remove the device from upper layers or update the details of 19682d1d418eSSumit Saxena * the device. 19692d1d418eSSumit Saxena * 19702d1d418eSSumit Saxena * Return: Nothing. 19712d1d418eSSumit Saxena */ 19722d1d418eSSumit Saxena static void mpi3mr_devinfochg_evt_bh(struct mpi3mr_softc *sc, 19732d1d418eSSumit Saxena Mpi3DevicePage0_t *dev_pg0) 19742d1d418eSSumit Saxena { 19752d1d418eSSumit Saxena struct mpi3mr_target *tgtdev = NULL; 19762d1d418eSSumit Saxena U16 dev_handle = 0, perst_id = 0; 19772d1d418eSSumit Saxena 19782d1d418eSSumit Saxena perst_id = le16toh(dev_pg0->PersistentID); 19792d1d418eSSumit Saxena dev_handle = le16toh(dev_pg0->DevHandle); 19802d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_INFO, 19812d1d418eSSumit Saxena "%s :Device info change: handle(0x%04x): persist_id(0x%x)\n", 19822d1d418eSSumit Saxena __func__, dev_handle, perst_id); 19832d1d418eSSumit Saxena tgtdev = mpi3mr_find_target_by_dev_handle(sc->cam_sc, dev_handle); 19842d1d418eSSumit Saxena if (!tgtdev) 19852d1d418eSSumit Saxena return; 19862d1d418eSSumit Saxena 19872d1d418eSSumit Saxena mpi3mr_update_device(sc, tgtdev, dev_pg0, false); 19882d1d418eSSumit Saxena if (!tgtdev->is_hidden && !tgtdev->exposed_to_os) 19892d1d418eSSumit Saxena mpi3mr_add_device(sc, perst_id); 19902d1d418eSSumit Saxena 19912d1d418eSSumit Saxena if (tgtdev->is_hidden && tgtdev->exposed_to_os) 19922d1d418eSSumit Saxena mpi3mr_remove_device_from_os(sc, tgtdev->dev_handle); 19932d1d418eSSumit Saxena } 19942d1d418eSSumit Saxena 19952d1d418eSSumit Saxena static void 19962d1d418eSSumit Saxena mpi3mr_fw_work(struct mpi3mr_softc *sc, struct mpi3mr_fw_event_work *fw_event) 19972d1d418eSSumit Saxena { 19982d1d418eSSumit Saxena if (sc->mpi3mr_flags & MPI3MR_FLAGS_SHUTDOWN) 19992d1d418eSSumit Saxena goto out; 20002d1d418eSSumit Saxena 20012d1d418eSSumit Saxena if (!fw_event->process_event) 20022d1d418eSSumit Saxena goto evt_ack; 20032d1d418eSSumit Saxena 20042d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_EVENT, "(%d)->(%s) Working on Event: [%x]\n", 20052d1d418eSSumit Saxena event_count++, __func__, fw_event->event); 20062d1d418eSSumit Saxena 20072d1d418eSSumit Saxena switch (fw_event->event) { 20082d1d418eSSumit Saxena case MPI3_EVENT_DEVICE_ADDED: 20092d1d418eSSumit Saxena { 20102d1d418eSSumit Saxena Mpi3DevicePage0_t *dev_pg0 = 20112d1d418eSSumit Saxena (Mpi3DevicePage0_t *) fw_event->event_data; 20122d1d418eSSumit Saxena mpi3mr_add_device(sc, dev_pg0->PersistentID); 20132d1d418eSSumit Saxena break; 20142d1d418eSSumit Saxena } 20152d1d418eSSumit Saxena case MPI3_EVENT_DEVICE_INFO_CHANGED: 20162d1d418eSSumit Saxena { 20172d1d418eSSumit Saxena mpi3mr_devinfochg_evt_bh(sc, 20182d1d418eSSumit Saxena (Mpi3DevicePage0_t *) fw_event->event_data); 20192d1d418eSSumit Saxena break; 20202d1d418eSSumit Saxena } 20212d1d418eSSumit Saxena case MPI3_EVENT_DEVICE_STATUS_CHANGE: 20222d1d418eSSumit Saxena { 20232d1d418eSSumit Saxena mpi3mr_devstatuschg_evt_bh(sc, fw_event); 20242d1d418eSSumit Saxena break; 20252d1d418eSSumit Saxena } 20262d1d418eSSumit Saxena case MPI3_EVENT_SAS_TOPOLOGY_CHANGE_LIST: 20272d1d418eSSumit Saxena { 20282d1d418eSSumit Saxena mpi3mr_process_sastopochg_evt(sc, fw_event); 20292d1d418eSSumit Saxena break; 20302d1d418eSSumit Saxena } 20312d1d418eSSumit Saxena case MPI3_EVENT_PCIE_TOPOLOGY_CHANGE_LIST: 20322d1d418eSSumit Saxena { 20332d1d418eSSumit Saxena mpi3mr_process_pcietopochg_evt(sc, fw_event); 20342d1d418eSSumit Saxena break; 20352d1d418eSSumit Saxena } 20362d1d418eSSumit Saxena case MPI3_EVENT_LOG_DATA: 20372d1d418eSSumit Saxena { 20382d1d418eSSumit Saxena mpi3mr_logdata_evt_bh(sc, fw_event); 20392d1d418eSSumit Saxena break; 20402d1d418eSSumit Saxena } 20412d1d418eSSumit Saxena default: 20422d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_TRACE,"Unhandled event 0x%0X\n", 20432d1d418eSSumit Saxena fw_event->event); 20442d1d418eSSumit Saxena break; 20452d1d418eSSumit Saxena 20462d1d418eSSumit Saxena } 20472d1d418eSSumit Saxena 20482d1d418eSSumit Saxena evt_ack: 20492d1d418eSSumit Saxena if (fw_event->send_ack) { 20502d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_EVENT,"Process event ACK for event 0x%0X\n", 20512d1d418eSSumit Saxena fw_event->event); 20522d1d418eSSumit Saxena mpi3mr_process_event_ack(sc, fw_event->event, 20532d1d418eSSumit Saxena fw_event->event_context); 20542d1d418eSSumit Saxena } 20552d1d418eSSumit Saxena 20562d1d418eSSumit Saxena out: 20572d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_EVENT, "(%d)->(%s) Event Free: [%x]\n", event_count, 20582d1d418eSSumit Saxena __func__, fw_event->event); 20592d1d418eSSumit Saxena 20602d1d418eSSumit Saxena mpi3mr_fw_event_free(sc, fw_event); 20612d1d418eSSumit Saxena } 20622d1d418eSSumit Saxena 20632d1d418eSSumit Saxena void 20642d1d418eSSumit Saxena mpi3mr_firmware_event_work(void *arg, int pending) 20652d1d418eSSumit Saxena { 20662d1d418eSSumit Saxena struct mpi3mr_fw_event_work *fw_event; 20672d1d418eSSumit Saxena struct mpi3mr_softc *sc; 20682d1d418eSSumit Saxena 20692d1d418eSSumit Saxena sc = (struct mpi3mr_softc *)arg; 20702d1d418eSSumit Saxena 20712d1d418eSSumit Saxena mtx_lock(&sc->fwevt_lock); 20722d1d418eSSumit Saxena while ((fw_event = TAILQ_FIRST(&sc->cam_sc->ev_queue)) != NULL) { 20732d1d418eSSumit Saxena TAILQ_REMOVE(&sc->cam_sc->ev_queue, fw_event, ev_link); 20742d1d418eSSumit Saxena mtx_unlock(&sc->fwevt_lock); 20752d1d418eSSumit Saxena mpi3mr_fw_work(sc, fw_event); 20762d1d418eSSumit Saxena mtx_lock(&sc->fwevt_lock); 20772d1d418eSSumit Saxena } 20782d1d418eSSumit Saxena mtx_unlock(&sc->fwevt_lock); 20792d1d418eSSumit Saxena } 20802d1d418eSSumit Saxena 20812d1d418eSSumit Saxena 20822d1d418eSSumit Saxena /* 20832d1d418eSSumit Saxena * mpi3mr_cam_attach - CAM layer registration 20842d1d418eSSumit Saxena * @sc: Adapter reference 20852d1d418eSSumit Saxena * 20862d1d418eSSumit Saxena * This function does simq allocation, cam registration, xpt_bus registration, 20872d1d418eSSumit Saxena * event taskqueue initialization and async event handler registration. 20882d1d418eSSumit Saxena * 20892d1d418eSSumit Saxena * Return: 0 on success and proper error codes on failure 20902d1d418eSSumit Saxena */ 20912d1d418eSSumit Saxena int 20922d1d418eSSumit Saxena mpi3mr_cam_attach(struct mpi3mr_softc *sc) 20932d1d418eSSumit Saxena { 20942d1d418eSSumit Saxena struct mpi3mr_cam_softc *cam_sc; 20952d1d418eSSumit Saxena cam_status status; 20962d1d418eSSumit Saxena int unit, error = 0, reqs; 20972d1d418eSSumit Saxena 20982d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_XINFO, "Starting CAM Attach\n"); 20992d1d418eSSumit Saxena 21002d1d418eSSumit Saxena cam_sc = malloc(sizeof(struct mpi3mr_cam_softc), M_MPI3MR, M_WAITOK|M_ZERO); 21012d1d418eSSumit Saxena cam_sc->maxtargets = sc->facts.max_perids + 1; 21022d1d418eSSumit Saxena 21032d1d418eSSumit Saxena TAILQ_INIT(&cam_sc->tgt_list); 21042d1d418eSSumit Saxena 21052d1d418eSSumit Saxena sc->cam_sc = cam_sc; 21062d1d418eSSumit Saxena cam_sc->sc = sc; 21072d1d418eSSumit Saxena 21082d1d418eSSumit Saxena reqs = sc->max_host_ios; 21092d1d418eSSumit Saxena 21102d1d418eSSumit Saxena if ((cam_sc->devq = cam_simq_alloc(reqs)) == NULL) { 21112d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to allocate SIMQ\n"); 21122d1d418eSSumit Saxena error = ENOMEM; 21132d1d418eSSumit Saxena goto out; 21142d1d418eSSumit Saxena } 21152d1d418eSSumit Saxena 21162d1d418eSSumit Saxena unit = device_get_unit(sc->mpi3mr_dev); 21172d1d418eSSumit Saxena cam_sc->sim = cam_sim_alloc(mpi3mr_cam_action, mpi3mr_cam_poll, "mpi3mr", cam_sc, 21182d1d418eSSumit Saxena unit, &sc->mpi3mr_mtx, reqs, reqs, cam_sc->devq); 21192d1d418eSSumit Saxena if (cam_sc->sim == NULL) { 21202d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to allocate SIM\n"); 21212d1d418eSSumit Saxena error = EINVAL; 21222d1d418eSSumit Saxena goto out; 21232d1d418eSSumit Saxena } 21242d1d418eSSumit Saxena 21252d1d418eSSumit Saxena TAILQ_INIT(&cam_sc->ev_queue); 21262d1d418eSSumit Saxena 21272d1d418eSSumit Saxena /* Initialize taskqueue for Event Handling */ 21282d1d418eSSumit Saxena TASK_INIT(&cam_sc->ev_task, 0, mpi3mr_firmware_event_work, sc); 21292d1d418eSSumit Saxena cam_sc->ev_tq = taskqueue_create("mpi3mr_taskq", M_NOWAIT | M_ZERO, 21302d1d418eSSumit Saxena taskqueue_thread_enqueue, &cam_sc->ev_tq); 21312d1d418eSSumit Saxena taskqueue_start_threads(&cam_sc->ev_tq, 1, PRIBIO, "%s taskq", 21322d1d418eSSumit Saxena device_get_nameunit(sc->mpi3mr_dev)); 21332d1d418eSSumit Saxena 21342d1d418eSSumit Saxena mtx_lock(&sc->mpi3mr_mtx); 21352d1d418eSSumit Saxena 21362d1d418eSSumit Saxena /* 21372d1d418eSSumit Saxena * XXX There should be a bus for every port on the adapter, but since 21382d1d418eSSumit Saxena * we're just going to fake the topology for now, we'll pretend that 21392d1d418eSSumit Saxena * everything is just a target on a single bus. 21402d1d418eSSumit Saxena */ 21412d1d418eSSumit Saxena if ((error = xpt_bus_register(cam_sc->sim, sc->mpi3mr_dev, 0)) != 0) { 21422d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_ERROR, 21432d1d418eSSumit Saxena "Error 0x%x registering SCSI bus\n", error); 21442d1d418eSSumit Saxena mtx_unlock(&sc->mpi3mr_mtx); 21452d1d418eSSumit Saxena goto out; 21462d1d418eSSumit Saxena } 21472d1d418eSSumit Saxena 21482d1d418eSSumit Saxena /* 21492d1d418eSSumit Saxena * Assume that discovery events will start right away. 21502d1d418eSSumit Saxena * 21512d1d418eSSumit Saxena * Hold off boot until discovery is complete. 21522d1d418eSSumit Saxena */ 21532d1d418eSSumit Saxena cam_sc->flags |= MPI3MRSAS_IN_STARTUP | MPI3MRSAS_IN_DISCOVERY; 21542d1d418eSSumit Saxena sc->cam_sc->startup_refcount = 0; 21552d1d418eSSumit Saxena mpi3mr_startup_increment(cam_sc); 21562d1d418eSSumit Saxena 21572d1d418eSSumit Saxena callout_init(&cam_sc->discovery_callout, 1 /*mpsafe*/); 21582d1d418eSSumit Saxena 21592d1d418eSSumit Saxena /* 21602d1d418eSSumit Saxena * Register for async events so we can determine the EEDP 21612d1d418eSSumit Saxena * capabilities of devices. 21622d1d418eSSumit Saxena */ 21632d1d418eSSumit Saxena status = xpt_create_path(&cam_sc->path, /*periph*/NULL, 21642d1d418eSSumit Saxena cam_sim_path(sc->cam_sc->sim), CAM_TARGET_WILDCARD, 21652d1d418eSSumit Saxena CAM_LUN_WILDCARD); 21662d1d418eSSumit Saxena if (status != CAM_REQ_CMP) { 21672d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_ERROR, 21682d1d418eSSumit Saxena "Error 0x%x creating sim path\n", status); 21692d1d418eSSumit Saxena cam_sc->path = NULL; 21702d1d418eSSumit Saxena } 21712d1d418eSSumit Saxena 21722d1d418eSSumit Saxena if (status != CAM_REQ_CMP) { 21732d1d418eSSumit Saxena /* 21742d1d418eSSumit Saxena * EEDP use is the exception, not the rule. 21752d1d418eSSumit Saxena * Warn the user, but do not fail to attach. 21762d1d418eSSumit Saxena */ 21772d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_INFO, "EEDP capabilities disabled.\n"); 21782d1d418eSSumit Saxena } 21792d1d418eSSumit Saxena 21802d1d418eSSumit Saxena mtx_unlock(&sc->mpi3mr_mtx); 21812d1d418eSSumit Saxena 21822d1d418eSSumit Saxena error = mpi3mr_register_events(sc); 21832d1d418eSSumit Saxena 21842d1d418eSSumit Saxena out: 21852d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_XINFO, "%s Exiting CAM attach, error: 0x%x n", __func__, error); 21862d1d418eSSumit Saxena return (error); 21872d1d418eSSumit Saxena } 21882d1d418eSSumit Saxena 21892d1d418eSSumit Saxena int 21902d1d418eSSumit Saxena mpi3mr_cam_detach(struct mpi3mr_softc *sc) 21912d1d418eSSumit Saxena { 21922d1d418eSSumit Saxena struct mpi3mr_cam_softc *cam_sc; 21932d1d418eSSumit Saxena struct mpi3mr_target *target; 21942d1d418eSSumit Saxena 21952d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_XINFO, "%s, Starting CAM detach\n", __func__); 21962d1d418eSSumit Saxena if (sc->cam_sc == NULL) 21972d1d418eSSumit Saxena return (0); 21982d1d418eSSumit Saxena 21992d1d418eSSumit Saxena cam_sc = sc->cam_sc; 22002d1d418eSSumit Saxena 22012d1d418eSSumit Saxena mpi3mr_freeup_events(sc); 22022d1d418eSSumit Saxena 22032d1d418eSSumit Saxena /* 22042d1d418eSSumit Saxena * Drain and free the event handling taskqueue with the lock 22052d1d418eSSumit Saxena * unheld so that any parallel processing tasks drain properly 22062d1d418eSSumit Saxena * without deadlocking. 22072d1d418eSSumit Saxena */ 22082d1d418eSSumit Saxena if (cam_sc->ev_tq != NULL) 22092d1d418eSSumit Saxena taskqueue_free(cam_sc->ev_tq); 22102d1d418eSSumit Saxena 22112d1d418eSSumit Saxena mtx_lock(&sc->mpi3mr_mtx); 22122d1d418eSSumit Saxena 22132d1d418eSSumit Saxena while (cam_sc->startup_refcount != 0) 22142d1d418eSSumit Saxena mpi3mr_startup_decrement(cam_sc); 22152d1d418eSSumit Saxena 22162d1d418eSSumit Saxena /* Deregister our async handler */ 22172d1d418eSSumit Saxena if (cam_sc->path != NULL) { 22182d1d418eSSumit Saxena xpt_free_path(cam_sc->path); 22192d1d418eSSumit Saxena cam_sc->path = NULL; 22202d1d418eSSumit Saxena } 22212d1d418eSSumit Saxena 22222d1d418eSSumit Saxena if (cam_sc->flags & MPI3MRSAS_IN_STARTUP) 22232d1d418eSSumit Saxena xpt_release_simq(cam_sc->sim, 1); 22242d1d418eSSumit Saxena 22252d1d418eSSumit Saxena if (cam_sc->sim != NULL) { 22262d1d418eSSumit Saxena xpt_bus_deregister(cam_sim_path(cam_sc->sim)); 22272d1d418eSSumit Saxena cam_sim_free(cam_sc->sim, FALSE); 22282d1d418eSSumit Saxena } 22292d1d418eSSumit Saxena 22302d1d418eSSumit Saxena mtx_unlock(&sc->mpi3mr_mtx); 22312d1d418eSSumit Saxena 22322d1d418eSSumit Saxena if (cam_sc->devq != NULL) 22332d1d418eSSumit Saxena cam_simq_free(cam_sc->devq); 22342d1d418eSSumit Saxena 22352d1d418eSSumit Saxena get_target: 22362d1d418eSSumit Saxena mtx_lock_spin(&sc->target_lock); 22372d1d418eSSumit Saxena TAILQ_FOREACH(target, &cam_sc->tgt_list, tgt_next) { 22382d1d418eSSumit Saxena TAILQ_REMOVE(&sc->cam_sc->tgt_list, target, tgt_next); 22392d1d418eSSumit Saxena mtx_unlock_spin(&sc->target_lock); 22402d1d418eSSumit Saxena goto out_tgt_free; 22412d1d418eSSumit Saxena } 22422d1d418eSSumit Saxena mtx_unlock_spin(&sc->target_lock); 22432d1d418eSSumit Saxena out_tgt_free: 22442d1d418eSSumit Saxena if (target) { 22452d1d418eSSumit Saxena free(target, M_MPI3MR); 22462d1d418eSSumit Saxena target = NULL; 22472d1d418eSSumit Saxena goto get_target; 22482d1d418eSSumit Saxena } 22492d1d418eSSumit Saxena 22502d1d418eSSumit Saxena free(cam_sc, M_MPI3MR); 22512d1d418eSSumit Saxena sc->cam_sc = NULL; 22522d1d418eSSumit Saxena 22532d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_XINFO, "%s, Exiting CAM detach\n", __func__); 22542d1d418eSSumit Saxena return (0); 22552d1d418eSSumit Saxena } 2256