xref: /freebsd/sys/dev/mpi3mr/mpi3mr_cam.c (revision 849f9ac370bd66993ce5cc6fca0d2ef9bd03c2c9)
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
mpi3mr_divert_ws(Mpi3SCSIIORequest_t * req,struct ccb_scsiio * csio,U16 ws_len)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 
mpi3mr_prepare_sgls(void * arg,bus_dma_segment_t * segs,int nsegs,int error)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
mpi3mr_map_request(struct mpi3mr_softc * sc,struct mpi3mr_cmd * cm)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
mpi3mr_unmap_request(struct mpi3mr_softc * sc,struct mpi3mr_cmd * cmd)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  */
mpi3mr_allow_unmap_to_fw(struct mpi3mr_softc * sc,union ccb * ccb)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  */
mpi3mr_tm_response_name(U8 resp_code)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 
mpi3mr_poll_pend_io_completions(struct mpi3mr_softc * sc)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
trigger_reset_from_watchdog(struct mpi3mr_softc * sc,U8 reset_type,U16 reset_reason)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
mpi3mr_issue_tm(struct mpi3mr_softc * sc,struct mpi3mr_cmd * cmd,U8 tm_type,unsigned long timeout)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  */
mpi3mr_task_abort(struct mpi3mr_cmd * cmd)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  */
mpi3mr_target_reset(struct mpi3mr_cmd * cmd)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  */
mpi3mr_get_fw_pending_ios(struct mpi3mr_softc * sc)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  */
mpi3mr_wait_for_host_io(struct mpi3mr_softc * sc,U32 timeout)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
mpi3mr_scsiio_timeout(void * data)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 
int_to_lun(unsigned int lun,U8 * req_lun)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 
get_req_queue_index(struct mpi3mr_softc * sc)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
mpi3mr_action_scsiio(struct mpi3mr_cam_softc * cam_sc,union ccb * ccb)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
mpi3mr_enqueue_request(struct mpi3mr_softc * sc,struct mpi3mr_cmd * cm)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
mpi3mr_cam_poll(struct cam_sim * sim)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
mpi3mr_cam_action(struct cam_sim * sim,union ccb * ccb)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
mpi3mr_startup_increment(struct mpi3mr_cam_softc * cam_sc)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
mpi3mr_release_simq_reinit(struct mpi3mr_cam_softc * cam_sc)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
mpi3mr_rescan_target(struct mpi3mr_softc * sc,struct mpi3mr_target * targ)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
mpi3mr_startup_decrement(struct mpi3mr_cam_softc * cam_sc)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
mpi3mr_fw_event_free(struct mpi3mr_softc * sc,struct mpi3mr_fw_event_work * fw_event)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
mpi3mr_freeup_events(struct mpi3mr_softc * sc)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
mpi3mr_sastopochg_evt_debug(struct mpi3mr_softc * sc,Mpi3EventDataSasTopologyChangeList_t * event_data)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
mpi3mr_process_sastopochg_evt(struct mpi3mr_softc * sc,struct mpi3mr_fw_event_work * fwevt)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
mpi3mr_logdata_evt_bh(struct mpi3mr_softc * sc,struct mpi3mr_fw_event_work * fwevt)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
mpi3mr_pcietopochg_evt_debug(struct mpi3mr_softc * sc,Mpi3EventDataPcieTopologyChangeList_t * event_data)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 
mpi3mr_process_pcietopochg_evt(struct mpi3mr_softc * sc,struct mpi3mr_fw_event_work * fwevt)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 
mpi3mr_add_device(struct mpi3mr_softc * sc,U16 per_id)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 
mpi3mr_remove_device_from_os(struct mpi3mr_softc * sc,U16 handle)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 
mpi3mr_remove_device_from_list(struct mpi3mr_softc * sc,struct mpi3mr_target * target,bool must_delete)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  */
mpi3mr_devstatuschg_evt_bh(struct mpi3mr_softc * sc,struct mpi3mr_fw_event_work * fwevt)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  */
mpi3mr_devinfochg_evt_bh(struct mpi3mr_softc * sc,Mpi3DevicePage0_t * dev_pg0)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
mpi3mr_fw_work(struct mpi3mr_softc * sc,struct mpi3mr_fw_event_work * fw_event)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
mpi3mr_firmware_event_work(void * arg,int pending)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
mpi3mr_cam_attach(struct mpi3mr_softc * sc)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
mpi3mr_cam_detach(struct mpi3mr_softc * sc)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