xref: /freebsd/sys/dev/mpi3mr/mpi3mr_cam.c (revision 2d1d418e1e7bc8325bb052185c17c81a674d0c4e)
1*2d1d418eSSumit Saxena /*
2*2d1d418eSSumit Saxena  * SPDX-License-Identifier: BSD-2-Clause
3*2d1d418eSSumit Saxena  *
4*2d1d418eSSumit Saxena  * Copyright (c) 2020-2023, Broadcom Inc. All rights reserved.
5*2d1d418eSSumit Saxena  * Support: <fbsd-storage-driver.pdl@broadcom.com>
6*2d1d418eSSumit Saxena  *
7*2d1d418eSSumit Saxena  * Authors: Sumit Saxena <sumit.saxena@broadcom.com>
8*2d1d418eSSumit Saxena  *	    Chandrakanth Patil <chandrakanth.patil@broadcom.com>
9*2d1d418eSSumit Saxena  *
10*2d1d418eSSumit Saxena  * Redistribution and use in source and binary forms, with or without
11*2d1d418eSSumit Saxena  * modification, are permitted provided that the following conditions are
12*2d1d418eSSumit Saxena  * met:
13*2d1d418eSSumit Saxena  *
14*2d1d418eSSumit Saxena  * 1. Redistributions of source code must retain the above copyright notice,
15*2d1d418eSSumit Saxena  *    this list of conditions and the following disclaimer.
16*2d1d418eSSumit Saxena  * 2. Redistributions in binary form must reproduce the above copyright notice,
17*2d1d418eSSumit Saxena  *    this list of conditions and the following disclaimer in the documentation and/or other
18*2d1d418eSSumit Saxena  *    materials provided with the distribution.
19*2d1d418eSSumit Saxena  * 3. Neither the name of the Broadcom Inc. nor the names of its contributors
20*2d1d418eSSumit Saxena  *    may be used to endorse or promote products derived from this software without
21*2d1d418eSSumit Saxena  *    specific prior written permission.
22*2d1d418eSSumit Saxena  *
23*2d1d418eSSumit Saxena  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24*2d1d418eSSumit Saxena  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25*2d1d418eSSumit Saxena  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26*2d1d418eSSumit Saxena  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
27*2d1d418eSSumit Saxena  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28*2d1d418eSSumit Saxena  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29*2d1d418eSSumit Saxena  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30*2d1d418eSSumit Saxena  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31*2d1d418eSSumit Saxena  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32*2d1d418eSSumit Saxena  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33*2d1d418eSSumit Saxena  * POSSIBILITY OF SUCH DAMAGE.
34*2d1d418eSSumit Saxena  *
35*2d1d418eSSumit Saxena  * The views and conclusions contained in the software and documentation are
36*2d1d418eSSumit Saxena  * those of the authors and should not be interpreted as representing
37*2d1d418eSSumit Saxena  * official policies,either expressed or implied, of the FreeBSD Project.
38*2d1d418eSSumit Saxena  *
39*2d1d418eSSumit Saxena  * Mail to: Broadcom Inc 1320 Ridder Park Dr, San Jose, CA 95131
40*2d1d418eSSumit Saxena  *
41*2d1d418eSSumit Saxena  * Broadcom Inc. (Broadcom) MPI3MR Adapter FreeBSD
42*2d1d418eSSumit Saxena  */
43*2d1d418eSSumit Saxena 
44*2d1d418eSSumit Saxena #include <sys/cdefs.h>
45*2d1d418eSSumit Saxena __FBSDID("$FreeBSD$");
46*2d1d418eSSumit Saxena 
47*2d1d418eSSumit Saxena #include <sys/types.h>
48*2d1d418eSSumit Saxena #include <sys/param.h>
49*2d1d418eSSumit Saxena #include <sys/systm.h>
50*2d1d418eSSumit Saxena #include <sys/kernel.h>
51*2d1d418eSSumit Saxena #include <sys/selinfo.h>
52*2d1d418eSSumit Saxena #include <sys/module.h>
53*2d1d418eSSumit Saxena #include <sys/bus.h>
54*2d1d418eSSumit Saxena #include <sys/conf.h>
55*2d1d418eSSumit Saxena #include <sys/bio.h>
56*2d1d418eSSumit Saxena #include <sys/malloc.h>
57*2d1d418eSSumit Saxena #include <sys/uio.h>
58*2d1d418eSSumit Saxena #include <sys/sysctl.h>
59*2d1d418eSSumit Saxena #include <sys/endian.h>
60*2d1d418eSSumit Saxena #include <sys/queue.h>
61*2d1d418eSSumit Saxena #include <sys/kthread.h>
62*2d1d418eSSumit Saxena #include <sys/taskqueue.h>
63*2d1d418eSSumit Saxena #include <sys/sbuf.h>
64*2d1d418eSSumit Saxena 
65*2d1d418eSSumit Saxena #include <machine/bus.h>
66*2d1d418eSSumit Saxena #include <machine/resource.h>
67*2d1d418eSSumit Saxena #include <sys/rman.h>
68*2d1d418eSSumit Saxena 
69*2d1d418eSSumit Saxena #include <machine/stdarg.h>
70*2d1d418eSSumit Saxena 
71*2d1d418eSSumit Saxena #include <cam/cam.h>
72*2d1d418eSSumit Saxena #include <cam/cam_ccb.h>
73*2d1d418eSSumit Saxena #include <cam/cam_debug.h>
74*2d1d418eSSumit Saxena #include <cam/cam_sim.h>
75*2d1d418eSSumit Saxena #include <cam/cam_xpt_sim.h>
76*2d1d418eSSumit Saxena #include <cam/cam_xpt_periph.h>
77*2d1d418eSSumit Saxena #include <cam/cam_periph.h>
78*2d1d418eSSumit Saxena #include <cam/scsi/scsi_all.h>
79*2d1d418eSSumit Saxena #include <cam/scsi/scsi_message.h>
80*2d1d418eSSumit Saxena #include <cam/scsi/smp_all.h>
81*2d1d418eSSumit Saxena 
82*2d1d418eSSumit Saxena #include <dev/nvme/nvme.h>
83*2d1d418eSSumit Saxena #include "mpi/mpi30_api.h"
84*2d1d418eSSumit Saxena #include "mpi3mr_cam.h"
85*2d1d418eSSumit Saxena #include "mpi3mr.h"
86*2d1d418eSSumit Saxena #include <sys/time.h>			/* XXX for pcpu.h */
87*2d1d418eSSumit Saxena #include <sys/pcpu.h>			/* XXX for PCPU_GET */
88*2d1d418eSSumit Saxena 
89*2d1d418eSSumit Saxena #define	smp_processor_id()  PCPU_GET(cpuid)
90*2d1d418eSSumit Saxena 
91*2d1d418eSSumit Saxena static int
92*2d1d418eSSumit Saxena mpi3mr_map_request(struct mpi3mr_softc *sc, struct mpi3mr_cmd *cm);
93*2d1d418eSSumit Saxena void
94*2d1d418eSSumit Saxena mpi3mr_release_simq_reinit(struct mpi3mr_cam_softc *cam_sc);
95*2d1d418eSSumit Saxena static void
96*2d1d418eSSumit Saxena mpi3mr_freeup_events(struct mpi3mr_softc *sc);
97*2d1d418eSSumit Saxena 
98*2d1d418eSSumit Saxena extern int
99*2d1d418eSSumit Saxena mpi3mr_register_events(struct mpi3mr_softc *sc);
100*2d1d418eSSumit Saxena extern void mpi3mr_add_sg_single(void *paddr, U8 flags, U32 length,
101*2d1d418eSSumit Saxena     bus_addr_t dma_addr);
102*2d1d418eSSumit Saxena extern void mpi3mr_build_zero_len_sge(void *paddr);
103*2d1d418eSSumit Saxena 
104*2d1d418eSSumit Saxena static U32 event_count;
105*2d1d418eSSumit Saxena 
106*2d1d418eSSumit Saxena static void mpi3mr_prepare_sgls(void *arg,
107*2d1d418eSSumit Saxena 	bus_dma_segment_t *segs, int nsegs, int error)
108*2d1d418eSSumit Saxena {
109*2d1d418eSSumit Saxena 	struct mpi3mr_softc *sc;
110*2d1d418eSSumit Saxena 	struct mpi3mr_cmd *cm;
111*2d1d418eSSumit Saxena 	u_int i;
112*2d1d418eSSumit Saxena 	bus_addr_t chain_dma;
113*2d1d418eSSumit Saxena 	void *chain;
114*2d1d418eSSumit Saxena 	U8 *sg_local;
115*2d1d418eSSumit Saxena 	U32 chain_length;
116*2d1d418eSSumit Saxena 	int sges_left;
117*2d1d418eSSumit Saxena 	U32 sges_in_segment;
118*2d1d418eSSumit Saxena 	U8 simple_sgl_flags;
119*2d1d418eSSumit Saxena 	U8 simple_sgl_flags_last;
120*2d1d418eSSumit Saxena 	U8 last_chain_sgl_flags;
121*2d1d418eSSumit Saxena 	struct mpi3mr_chain *chain_req;
122*2d1d418eSSumit Saxena 	Mpi3SCSIIORequest_t *scsiio_req;
123*2d1d418eSSumit Saxena 
124*2d1d418eSSumit Saxena 	cm = (struct mpi3mr_cmd *)arg;
125*2d1d418eSSumit Saxena 	sc = cm->sc;
126*2d1d418eSSumit Saxena 	scsiio_req = (Mpi3SCSIIORequest_t *) &cm->io_request;
127*2d1d418eSSumit Saxena 
128*2d1d418eSSumit Saxena 	if (error) {
129*2d1d418eSSumit Saxena 		cm->error_code = error;
130*2d1d418eSSumit Saxena 		device_printf(sc->mpi3mr_dev, "%s: error=%d\n",__func__, error);
131*2d1d418eSSumit Saxena 		if (error == EFBIG) {
132*2d1d418eSSumit Saxena 			cm->ccb->ccb_h.status = CAM_REQ_TOO_BIG;
133*2d1d418eSSumit Saxena 			return;
134*2d1d418eSSumit Saxena 		}
135*2d1d418eSSumit Saxena 	}
136*2d1d418eSSumit Saxena 
137*2d1d418eSSumit Saxena 	if (cm->data_dir == MPI3MR_READ)
138*2d1d418eSSumit Saxena 		bus_dmamap_sync(sc->buffer_dmat, cm->dmamap,
139*2d1d418eSSumit Saxena 		    BUS_DMASYNC_PREREAD);
140*2d1d418eSSumit Saxena 	if (cm->data_dir == MPI3MR_WRITE)
141*2d1d418eSSumit Saxena 		bus_dmamap_sync(sc->buffer_dmat, cm->dmamap,
142*2d1d418eSSumit Saxena 		    BUS_DMASYNC_PREWRITE);
143*2d1d418eSSumit Saxena 	if (nsegs > MPI3MR_SG_DEPTH) {
144*2d1d418eSSumit Saxena 		device_printf(sc->mpi3mr_dev, "SGE count is too large or 0.\n");
145*2d1d418eSSumit Saxena 		return;
146*2d1d418eSSumit Saxena 	}
147*2d1d418eSSumit Saxena 
148*2d1d418eSSumit Saxena 	simple_sgl_flags = MPI3_SGE_FLAGS_ELEMENT_TYPE_SIMPLE |
149*2d1d418eSSumit Saxena 	    MPI3_SGE_FLAGS_DLAS_SYSTEM;
150*2d1d418eSSumit Saxena 	simple_sgl_flags_last = simple_sgl_flags |
151*2d1d418eSSumit Saxena 	    MPI3_SGE_FLAGS_END_OF_LIST;
152*2d1d418eSSumit Saxena 	last_chain_sgl_flags = MPI3_SGE_FLAGS_ELEMENT_TYPE_LAST_CHAIN |
153*2d1d418eSSumit Saxena 	    MPI3_SGE_FLAGS_DLAS_SYSTEM;
154*2d1d418eSSumit Saxena 
155*2d1d418eSSumit Saxena 	sg_local = (U8 *)&scsiio_req->SGL;
156*2d1d418eSSumit Saxena 
157*2d1d418eSSumit Saxena 	if (!scsiio_req->DataLength) {
158*2d1d418eSSumit Saxena 		mpi3mr_build_zero_len_sge(sg_local);
159*2d1d418eSSumit Saxena 		return;
160*2d1d418eSSumit Saxena 	}
161*2d1d418eSSumit Saxena 
162*2d1d418eSSumit Saxena 	sges_left = nsegs;
163*2d1d418eSSumit Saxena 
164*2d1d418eSSumit Saxena 	if (sges_left < 0) {
165*2d1d418eSSumit Saxena 		printf("scsi_dma_map failed: request for %d bytes!\n",
166*2d1d418eSSumit Saxena 			scsiio_req->DataLength);
167*2d1d418eSSumit Saxena 		return;
168*2d1d418eSSumit Saxena 	}
169*2d1d418eSSumit Saxena 	if (sges_left > MPI3MR_SG_DEPTH) {
170*2d1d418eSSumit Saxena 		printf("scsi_dma_map returned unsupported sge count %d!\n",
171*2d1d418eSSumit Saxena 			sges_left);
172*2d1d418eSSumit Saxena 		return;
173*2d1d418eSSumit Saxena 	}
174*2d1d418eSSumit Saxena 
175*2d1d418eSSumit Saxena 	sges_in_segment = (sc->facts.op_req_sz -
176*2d1d418eSSumit Saxena 	    offsetof(Mpi3SCSIIORequest_t, SGL))/sizeof(Mpi3SGESimple_t);
177*2d1d418eSSumit Saxena 
178*2d1d418eSSumit Saxena 	i = 0;
179*2d1d418eSSumit Saxena 
180*2d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_TRACE, "SGE count: %d IO size: %d\n",
181*2d1d418eSSumit Saxena 		nsegs, scsiio_req->DataLength);
182*2d1d418eSSumit Saxena 
183*2d1d418eSSumit Saxena 	if (sges_left <= sges_in_segment)
184*2d1d418eSSumit Saxena 		goto fill_in_last_segment;
185*2d1d418eSSumit Saxena 
186*2d1d418eSSumit Saxena 	/* fill in main message segment when there is a chain following */
187*2d1d418eSSumit Saxena 	while (sges_in_segment > 1) {
188*2d1d418eSSumit Saxena 		mpi3mr_add_sg_single(sg_local, simple_sgl_flags,
189*2d1d418eSSumit Saxena 		    segs[i].ds_len, segs[i].ds_addr);
190*2d1d418eSSumit Saxena 		sg_local += sizeof(Mpi3SGESimple_t);
191*2d1d418eSSumit Saxena 		sges_left--;
192*2d1d418eSSumit Saxena 		sges_in_segment--;
193*2d1d418eSSumit Saxena 		i++;
194*2d1d418eSSumit Saxena 	}
195*2d1d418eSSumit Saxena 
196*2d1d418eSSumit Saxena 	chain_req = &sc->chain_sgl_list[cm->hosttag];
197*2d1d418eSSumit Saxena 
198*2d1d418eSSumit Saxena 	chain = chain_req->buf;
199*2d1d418eSSumit Saxena 	chain_dma = chain_req->buf_phys;
200*2d1d418eSSumit Saxena 	memset(chain_req->buf, 0, PAGE_SIZE);
201*2d1d418eSSumit Saxena 	sges_in_segment = sges_left;
202*2d1d418eSSumit Saxena 	chain_length = sges_in_segment * sizeof(Mpi3SGESimple_t);
203*2d1d418eSSumit Saxena 
204*2d1d418eSSumit Saxena 	mpi3mr_add_sg_single(sg_local, last_chain_sgl_flags,
205*2d1d418eSSumit Saxena 	    chain_length, chain_dma);
206*2d1d418eSSumit Saxena 
207*2d1d418eSSumit Saxena 	sg_local = chain;
208*2d1d418eSSumit Saxena 
209*2d1d418eSSumit Saxena fill_in_last_segment:
210*2d1d418eSSumit Saxena 	while (sges_left > 0) {
211*2d1d418eSSumit Saxena 		if (sges_left == 1)
212*2d1d418eSSumit Saxena 			mpi3mr_add_sg_single(sg_local,
213*2d1d418eSSumit Saxena 			    simple_sgl_flags_last, segs[i].ds_len,
214*2d1d418eSSumit Saxena 			    segs[i].ds_addr);
215*2d1d418eSSumit Saxena 		else
216*2d1d418eSSumit Saxena 			mpi3mr_add_sg_single(sg_local, simple_sgl_flags,
217*2d1d418eSSumit Saxena 			    segs[i].ds_len, segs[i].ds_addr);
218*2d1d418eSSumit Saxena 		sg_local += sizeof(Mpi3SGESimple_t);
219*2d1d418eSSumit Saxena 		sges_left--;
220*2d1d418eSSumit Saxena 		i++;
221*2d1d418eSSumit Saxena 	}
222*2d1d418eSSumit Saxena 
223*2d1d418eSSumit Saxena 	return;
224*2d1d418eSSumit Saxena }
225*2d1d418eSSumit Saxena 
226*2d1d418eSSumit Saxena int
227*2d1d418eSSumit Saxena mpi3mr_map_request(struct mpi3mr_softc *sc, struct mpi3mr_cmd *cm)
228*2d1d418eSSumit Saxena {
229*2d1d418eSSumit Saxena 	u_int32_t retcode = 0;
230*2d1d418eSSumit Saxena 
231*2d1d418eSSumit Saxena 	if (cm->data != NULL) {
232*2d1d418eSSumit Saxena 		mtx_lock(&sc->io_lock);
233*2d1d418eSSumit Saxena 		/* Map data buffer into bus space */
234*2d1d418eSSumit Saxena 		retcode = bus_dmamap_load_ccb(sc->buffer_dmat, cm->dmamap,
235*2d1d418eSSumit Saxena 		    cm->ccb, mpi3mr_prepare_sgls, cm, 0);
236*2d1d418eSSumit Saxena 		mtx_unlock(&sc->io_lock);
237*2d1d418eSSumit Saxena 		if (retcode)
238*2d1d418eSSumit Saxena 			device_printf(sc->mpi3mr_dev, "bus_dmamap_load(): retcode = %d\n", retcode);
239*2d1d418eSSumit Saxena 		if (retcode == EINPROGRESS) {
240*2d1d418eSSumit Saxena 			device_printf(sc->mpi3mr_dev, "request load in progress\n");
241*2d1d418eSSumit Saxena 			xpt_freeze_simq(sc->cam_sc->sim, 1);
242*2d1d418eSSumit Saxena 		}
243*2d1d418eSSumit Saxena 	}
244*2d1d418eSSumit Saxena 	if (cm->error_code)
245*2d1d418eSSumit Saxena 		return cm->error_code;
246*2d1d418eSSumit Saxena 	if (retcode)
247*2d1d418eSSumit Saxena 		mpi3mr_set_ccbstatus(cm->ccb, CAM_REQ_INVALID);
248*2d1d418eSSumit Saxena 
249*2d1d418eSSumit Saxena 	return (retcode);
250*2d1d418eSSumit Saxena }
251*2d1d418eSSumit Saxena 
252*2d1d418eSSumit Saxena void
253*2d1d418eSSumit Saxena mpi3mr_unmap_request(struct mpi3mr_softc *sc, struct mpi3mr_cmd *cmd)
254*2d1d418eSSumit Saxena {
255*2d1d418eSSumit Saxena 	if (cmd->data != NULL) {
256*2d1d418eSSumit Saxena 		if (cmd->data_dir == MPI3MR_READ)
257*2d1d418eSSumit Saxena 			bus_dmamap_sync(sc->buffer_dmat, cmd->dmamap, BUS_DMASYNC_POSTREAD);
258*2d1d418eSSumit Saxena 		if (cmd->data_dir == MPI3MR_WRITE)
259*2d1d418eSSumit Saxena 			bus_dmamap_sync(sc->buffer_dmat, cmd->dmamap, BUS_DMASYNC_POSTWRITE);
260*2d1d418eSSumit Saxena 		mtx_lock(&sc->io_lock);
261*2d1d418eSSumit Saxena 		bus_dmamap_unload(sc->buffer_dmat, cmd->dmamap);
262*2d1d418eSSumit Saxena 		mtx_unlock(&sc->io_lock);
263*2d1d418eSSumit Saxena 	}
264*2d1d418eSSumit Saxena }
265*2d1d418eSSumit Saxena 
266*2d1d418eSSumit Saxena /**
267*2d1d418eSSumit Saxena  * mpi3mr_allow_unmap_to_fw - Whether an unmap is allowed to fw
268*2d1d418eSSumit Saxena  * @sc: Adapter instance reference
269*2d1d418eSSumit Saxena  * @ccb: SCSI Command reference
270*2d1d418eSSumit Saxena  *
271*2d1d418eSSumit Saxena  * The controller hardware cannot handle certain unmap commands
272*2d1d418eSSumit Saxena  * for NVMe drives, this routine checks those and return true
273*2d1d418eSSumit Saxena  * and completes the SCSI command with proper status and sense
274*2d1d418eSSumit Saxena  * data.
275*2d1d418eSSumit Saxena  *
276*2d1d418eSSumit Saxena  * Return: TRUE for allowed unmap, FALSE otherwise.
277*2d1d418eSSumit Saxena  */
278*2d1d418eSSumit Saxena static bool mpi3mr_allow_unmap_to_fw(struct mpi3mr_softc *sc,
279*2d1d418eSSumit Saxena 	union ccb *ccb)
280*2d1d418eSSumit Saxena {
281*2d1d418eSSumit Saxena 	struct ccb_scsiio *csio;
282*2d1d418eSSumit Saxena 	uint16_t param_list_len, block_desc_len, trunc_param_len = 0;
283*2d1d418eSSumit Saxena 
284*2d1d418eSSumit Saxena 	csio = &ccb->csio;
285*2d1d418eSSumit Saxena 	param_list_len = (uint16_t) ((scsiio_cdb_ptr(csio)[7] << 8) | scsiio_cdb_ptr(csio)[8]);
286*2d1d418eSSumit Saxena 
287*2d1d418eSSumit Saxena 	switch(pci_get_revid(sc->mpi3mr_dev)) {
288*2d1d418eSSumit Saxena 	case SAS4116_CHIP_REV_A0:
289*2d1d418eSSumit Saxena 		if (!param_list_len) {
290*2d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_ERROR,
291*2d1d418eSSumit Saxena 			    "%s: CDB received with zero parameter length\n",
292*2d1d418eSSumit Saxena 			    __func__);
293*2d1d418eSSumit Saxena 			mpi3mr_print_cdb(ccb);
294*2d1d418eSSumit Saxena 			mpi3mr_set_ccbstatus(ccb, CAM_REQ_CMP);
295*2d1d418eSSumit Saxena 			xpt_done(ccb);
296*2d1d418eSSumit Saxena 			return false;
297*2d1d418eSSumit Saxena 		}
298*2d1d418eSSumit Saxena 
299*2d1d418eSSumit Saxena 		if (param_list_len < 24) {
300*2d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_ERROR,
301*2d1d418eSSumit Saxena 			    "%s: CDB received with invalid param_list_len: %d\n",
302*2d1d418eSSumit Saxena 			    __func__, param_list_len);
303*2d1d418eSSumit Saxena 			mpi3mr_print_cdb(ccb);
304*2d1d418eSSumit Saxena 			scsi_set_sense_data(&ccb->csio.sense_data,
305*2d1d418eSSumit Saxena 				/*sense_format*/ SSD_TYPE_FIXED,
306*2d1d418eSSumit Saxena 				/*current_error*/ 1,
307*2d1d418eSSumit Saxena 				/*sense_key*/ SSD_KEY_ILLEGAL_REQUEST,
308*2d1d418eSSumit Saxena 				/*asc*/ 0x1A,
309*2d1d418eSSumit Saxena 				/*ascq*/ 0x00,
310*2d1d418eSSumit Saxena 				/*extra args*/ SSD_ELEM_NONE);
311*2d1d418eSSumit Saxena 			ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND;
312*2d1d418eSSumit Saxena 			ccb->ccb_h.status =
313*2d1d418eSSumit Saxena 			    CAM_SCSI_STATUS_ERROR |
314*2d1d418eSSumit Saxena 			    CAM_AUTOSNS_VALID;
315*2d1d418eSSumit Saxena 			return false;
316*2d1d418eSSumit Saxena 		}
317*2d1d418eSSumit Saxena 
318*2d1d418eSSumit Saxena 		if (param_list_len != csio->dxfer_len) {
319*2d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_ERROR,
320*2d1d418eSSumit Saxena 			    "%s: CDB received with param_list_len: %d bufflen: %d\n",
321*2d1d418eSSumit Saxena 			    __func__, param_list_len, csio->dxfer_len);
322*2d1d418eSSumit Saxena 			mpi3mr_print_cdb(ccb);
323*2d1d418eSSumit Saxena 			scsi_set_sense_data(&ccb->csio.sense_data,
324*2d1d418eSSumit Saxena 				/*sense_format*/ SSD_TYPE_FIXED,
325*2d1d418eSSumit Saxena 				/*current_error*/ 1,
326*2d1d418eSSumit Saxena 				/*sense_key*/ SSD_KEY_ILLEGAL_REQUEST,
327*2d1d418eSSumit Saxena 				/*asc*/ 0x1A,
328*2d1d418eSSumit Saxena 				/*ascq*/ 0x00,
329*2d1d418eSSumit Saxena 				/*extra args*/ SSD_ELEM_NONE);
330*2d1d418eSSumit Saxena 			ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND;
331*2d1d418eSSumit Saxena 			ccb->ccb_h.status =
332*2d1d418eSSumit Saxena 			    CAM_SCSI_STATUS_ERROR |
333*2d1d418eSSumit Saxena 			    CAM_AUTOSNS_VALID;
334*2d1d418eSSumit Saxena 			xpt_done(ccb);
335*2d1d418eSSumit Saxena 			return false;
336*2d1d418eSSumit Saxena 		}
337*2d1d418eSSumit Saxena 
338*2d1d418eSSumit Saxena 		block_desc_len = (uint16_t) (csio->data_ptr[2] << 8 | csio->data_ptr[3]);
339*2d1d418eSSumit Saxena 
340*2d1d418eSSumit Saxena 		if (block_desc_len < 16) {
341*2d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_ERROR,
342*2d1d418eSSumit Saxena 			    "%s: Invalid descriptor length in param list: %d\n",
343*2d1d418eSSumit Saxena 			    __func__, block_desc_len);
344*2d1d418eSSumit Saxena 			mpi3mr_print_cdb(ccb);
345*2d1d418eSSumit Saxena 			scsi_set_sense_data(&ccb->csio.sense_data,
346*2d1d418eSSumit Saxena 				/*sense_format*/ SSD_TYPE_FIXED,
347*2d1d418eSSumit Saxena 				/*current_error*/ 1,
348*2d1d418eSSumit Saxena 				/*sense_key*/ SSD_KEY_ILLEGAL_REQUEST,
349*2d1d418eSSumit Saxena 				/*asc*/ 0x26,
350*2d1d418eSSumit Saxena 				/*ascq*/ 0x00,
351*2d1d418eSSumit Saxena 				/*extra args*/ SSD_ELEM_NONE);
352*2d1d418eSSumit Saxena 			ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND;
353*2d1d418eSSumit Saxena 			ccb->ccb_h.status =
354*2d1d418eSSumit Saxena 			    CAM_SCSI_STATUS_ERROR |
355*2d1d418eSSumit Saxena 			    CAM_AUTOSNS_VALID;
356*2d1d418eSSumit Saxena 			xpt_done(ccb);
357*2d1d418eSSumit Saxena 			return false;
358*2d1d418eSSumit Saxena 		}
359*2d1d418eSSumit Saxena 
360*2d1d418eSSumit Saxena 		if (param_list_len > (block_desc_len + 8)) {
361*2d1d418eSSumit Saxena 			mpi3mr_print_cdb(ccb);
362*2d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_INFO,
363*2d1d418eSSumit Saxena 			    "%s: Truncating param_list_len(%d) to block_desc_len+8(%d)\n",
364*2d1d418eSSumit Saxena 			    __func__, param_list_len, (block_desc_len + 8));
365*2d1d418eSSumit Saxena 			param_list_len = block_desc_len + 8;
366*2d1d418eSSumit Saxena 			scsiio_cdb_ptr(csio)[7] = (param_list_len >> 8) | 0xff;
367*2d1d418eSSumit Saxena 			scsiio_cdb_ptr(csio)[8] = param_list_len | 0xff;
368*2d1d418eSSumit Saxena 			mpi3mr_print_cdb(ccb);
369*2d1d418eSSumit Saxena 		}
370*2d1d418eSSumit Saxena 		break;
371*2d1d418eSSumit Saxena 
372*2d1d418eSSumit Saxena 	case SAS4116_CHIP_REV_B0:
373*2d1d418eSSumit Saxena 		if ((param_list_len > 24) && ((param_list_len - 8) & 0xF)) {
374*2d1d418eSSumit Saxena 			trunc_param_len -= (param_list_len - 8) & 0xF;
375*2d1d418eSSumit Saxena 			mpi3mr_print_cdb(ccb);
376*2d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_INFO,
377*2d1d418eSSumit Saxena 			    "%s: Truncating param_list_len from (%d) to (%d)\n",
378*2d1d418eSSumit Saxena 			    __func__, param_list_len, trunc_param_len);
379*2d1d418eSSumit Saxena 			scsiio_cdb_ptr(csio)[7] = (param_list_len >> 8) | 0xff;
380*2d1d418eSSumit Saxena 			scsiio_cdb_ptr(csio)[8] = param_list_len | 0xff;
381*2d1d418eSSumit Saxena 			mpi3mr_print_cdb(ccb);
382*2d1d418eSSumit Saxena 		}
383*2d1d418eSSumit Saxena 		break;
384*2d1d418eSSumit Saxena 	}
385*2d1d418eSSumit Saxena 
386*2d1d418eSSumit Saxena 	return true;
387*2d1d418eSSumit Saxena }
388*2d1d418eSSumit Saxena 
389*2d1d418eSSumit Saxena /**
390*2d1d418eSSumit Saxena  * mpi3mr_tm_response_name -  get TM response as a string
391*2d1d418eSSumit Saxena  * @resp_code: TM response code
392*2d1d418eSSumit Saxena  *
393*2d1d418eSSumit Saxena  * Convert known task management response code as a readable
394*2d1d418eSSumit Saxena  * string.
395*2d1d418eSSumit Saxena  *
396*2d1d418eSSumit Saxena  * Return: response code string.
397*2d1d418eSSumit Saxena  */
398*2d1d418eSSumit Saxena static const char* mpi3mr_tm_response_name(U8 resp_code)
399*2d1d418eSSumit Saxena {
400*2d1d418eSSumit Saxena 	char *desc;
401*2d1d418eSSumit Saxena 
402*2d1d418eSSumit Saxena 	switch (resp_code) {
403*2d1d418eSSumit Saxena 	case MPI3_SCSITASKMGMT_RSPCODE_TM_COMPLETE:
404*2d1d418eSSumit Saxena 		desc = "task management request completed";
405*2d1d418eSSumit Saxena 		break;
406*2d1d418eSSumit Saxena 	case MPI3_SCSITASKMGMT_RSPCODE_INVALID_FRAME:
407*2d1d418eSSumit Saxena 		desc = "invalid frame";
408*2d1d418eSSumit Saxena 		break;
409*2d1d418eSSumit Saxena 	case MPI3_SCSITASKMGMT_RSPCODE_TM_FUNCTION_NOT_SUPPORTED:
410*2d1d418eSSumit Saxena 		desc = "task management request not supported";
411*2d1d418eSSumit Saxena 		break;
412*2d1d418eSSumit Saxena 	case MPI3_SCSITASKMGMT_RSPCODE_TM_FAILED:
413*2d1d418eSSumit Saxena 		desc = "task management request failed";
414*2d1d418eSSumit Saxena 		break;
415*2d1d418eSSumit Saxena 	case MPI3_SCSITASKMGMT_RSPCODE_TM_SUCCEEDED:
416*2d1d418eSSumit Saxena 		desc = "task management request succeeded";
417*2d1d418eSSumit Saxena 		break;
418*2d1d418eSSumit Saxena 	case MPI3_SCSITASKMGMT_RSPCODE_TM_INVALID_LUN:
419*2d1d418eSSumit Saxena 		desc = "invalid LUN";
420*2d1d418eSSumit Saxena 		break;
421*2d1d418eSSumit Saxena 	case MPI3_SCSITASKMGMT_RSPCODE_TM_OVERLAPPED_TAG:
422*2d1d418eSSumit Saxena 		desc = "overlapped tag attempted";
423*2d1d418eSSumit Saxena 		break;
424*2d1d418eSSumit Saxena 	case MPI3_SCSITASKMGMT_RSPCODE_IO_QUEUED_ON_IOC:
425*2d1d418eSSumit Saxena 		desc = "task queued, however not sent to target";
426*2d1d418eSSumit Saxena 		break;
427*2d1d418eSSumit Saxena 	case MPI3_SCSITASKMGMT_RSPCODE_TM_NVME_DENIED:
428*2d1d418eSSumit Saxena 		desc = "task management request denied by NVMe device";
429*2d1d418eSSumit Saxena 		break;
430*2d1d418eSSumit Saxena 	default:
431*2d1d418eSSumit Saxena 		desc = "unknown";
432*2d1d418eSSumit Saxena 		break;
433*2d1d418eSSumit Saxena 	}
434*2d1d418eSSumit Saxena 
435*2d1d418eSSumit Saxena 	return desc;
436*2d1d418eSSumit Saxena }
437*2d1d418eSSumit Saxena 
438*2d1d418eSSumit Saxena void mpi3mr_poll_pend_io_completions(struct mpi3mr_softc *sc)
439*2d1d418eSSumit Saxena {
440*2d1d418eSSumit Saxena 	int i;
441*2d1d418eSSumit Saxena 	int num_of_reply_queues = sc->num_queues;
442*2d1d418eSSumit Saxena 	struct mpi3mr_irq_context *irq_ctx;
443*2d1d418eSSumit Saxena 
444*2d1d418eSSumit Saxena 	for (i = 0; i < num_of_reply_queues; i++) {
445*2d1d418eSSumit Saxena 		irq_ctx = &sc->irq_ctx[i];
446*2d1d418eSSumit Saxena 		mpi3mr_complete_io_cmd(sc, irq_ctx);
447*2d1d418eSSumit Saxena 	}
448*2d1d418eSSumit Saxena }
449*2d1d418eSSumit Saxena 
450*2d1d418eSSumit Saxena void
451*2d1d418eSSumit Saxena trigger_reset_from_watchdog(struct mpi3mr_softc *sc, U8 reset_type, U32 reset_reason)
452*2d1d418eSSumit Saxena {
453*2d1d418eSSumit Saxena 	if (sc->reset_in_progress) {
454*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_INFO, "Another reset is in progress, no need to trigger the reset\n");
455*2d1d418eSSumit Saxena 		return;
456*2d1d418eSSumit Saxena 	}
457*2d1d418eSSumit Saxena 	sc->reset.type = reset_type;
458*2d1d418eSSumit Saxena 	sc->reset.reason = reset_reason;
459*2d1d418eSSumit Saxena 
460*2d1d418eSSumit Saxena 	return;
461*2d1d418eSSumit Saxena }
462*2d1d418eSSumit Saxena 
463*2d1d418eSSumit Saxena /**
464*2d1d418eSSumit Saxena  * mpi3mr_issue_tm - Issue Task Management request
465*2d1d418eSSumit Saxena  * @sc: Adapter instance reference
466*2d1d418eSSumit Saxena  * @tm_type: Task Management type
467*2d1d418eSSumit Saxena  * @handle: Device handle
468*2d1d418eSSumit Saxena  * @lun: lun ID
469*2d1d418eSSumit Saxena  * @htag: Host tag of the TM request
470*2d1d418eSSumit Saxena  * @timeout: TM timeout value
471*2d1d418eSSumit Saxena  * @drv_cmd: Internal command tracker
472*2d1d418eSSumit Saxena  * @resp_code: Response code place holder
473*2d1d418eSSumit Saxena  * @cmd: Timed out command reference
474*2d1d418eSSumit Saxena  *
475*2d1d418eSSumit Saxena  * Issues a Task Management Request to the controller for a
476*2d1d418eSSumit Saxena  * specified target, lun and command and wait for its completion
477*2d1d418eSSumit Saxena  * and check TM response. Recover the TM if it timed out by
478*2d1d418eSSumit Saxena  * issuing controller reset.
479*2d1d418eSSumit Saxena  *
480*2d1d418eSSumit Saxena  * Return: 0 on success, non-zero on errors
481*2d1d418eSSumit Saxena  */
482*2d1d418eSSumit Saxena static int
483*2d1d418eSSumit Saxena mpi3mr_issue_tm(struct mpi3mr_softc *sc, struct mpi3mr_cmd *cmd,
484*2d1d418eSSumit Saxena 		U8 tm_type, unsigned long timeout)
485*2d1d418eSSumit Saxena {
486*2d1d418eSSumit Saxena 	int retval = 0;
487*2d1d418eSSumit Saxena 	MPI3_SCSI_TASK_MGMT_REQUEST tm_req;
488*2d1d418eSSumit Saxena 	MPI3_SCSI_TASK_MGMT_REPLY *tm_reply = NULL;
489*2d1d418eSSumit Saxena 	struct mpi3mr_drvr_cmd *drv_cmd = NULL;
490*2d1d418eSSumit Saxena 	struct mpi3mr_target *tgtdev = NULL;
491*2d1d418eSSumit Saxena 	struct mpi3mr_op_req_queue *op_req_q = NULL;
492*2d1d418eSSumit Saxena 	union ccb *ccb;
493*2d1d418eSSumit Saxena 	U8 resp_code;
494*2d1d418eSSumit Saxena 
495*2d1d418eSSumit Saxena 
496*2d1d418eSSumit Saxena 	if (sc->unrecoverable) {
497*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_INFO,
498*2d1d418eSSumit Saxena 			"Controller is in unrecoverable state!! TM not required\n");
499*2d1d418eSSumit Saxena 		return retval;
500*2d1d418eSSumit Saxena 	}
501*2d1d418eSSumit Saxena 	if (sc->reset_in_progress) {
502*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_INFO,
503*2d1d418eSSumit Saxena 			"controller reset in progress!! TM not required\n");
504*2d1d418eSSumit Saxena 		return retval;
505*2d1d418eSSumit Saxena 	}
506*2d1d418eSSumit Saxena 
507*2d1d418eSSumit Saxena 	if (!cmd->ccb) {
508*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "SCSIIO command timed-out with NULL ccb\n");
509*2d1d418eSSumit Saxena 		return retval;
510*2d1d418eSSumit Saxena 	}
511*2d1d418eSSumit Saxena 	ccb = cmd->ccb;
512*2d1d418eSSumit Saxena 
513*2d1d418eSSumit Saxena 	tgtdev = cmd->targ;
514*2d1d418eSSumit Saxena 	if (tgtdev == NULL)  {
515*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "Device does not exist target ID:0x%x,"
516*2d1d418eSSumit Saxena 			      "TM is not required\n", ccb->ccb_h.target_id);
517*2d1d418eSSumit Saxena 		return retval;
518*2d1d418eSSumit Saxena 	}
519*2d1d418eSSumit Saxena 	if (tgtdev->dev_removed == 1)  {
520*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "Device(0x%x) is removed, TM is not required\n",
521*2d1d418eSSumit Saxena 			      ccb->ccb_h.target_id);
522*2d1d418eSSumit Saxena 		return retval;
523*2d1d418eSSumit Saxena 	}
524*2d1d418eSSumit Saxena 
525*2d1d418eSSumit Saxena 	drv_cmd = &sc->host_tm_cmds;
526*2d1d418eSSumit Saxena 	mtx_lock(&drv_cmd->lock);
527*2d1d418eSSumit Saxena 
528*2d1d418eSSumit Saxena 	memset(&tm_req, 0, sizeof(tm_req));
529*2d1d418eSSumit Saxena 	tm_req.DevHandle = htole16(tgtdev->dev_handle);
530*2d1d418eSSumit Saxena 	tm_req.TaskType = tm_type;
531*2d1d418eSSumit Saxena 	tm_req.HostTag = htole16(MPI3MR_HOSTTAG_TMS);
532*2d1d418eSSumit Saxena 	int_to_lun(ccb->ccb_h.target_lun, tm_req.LUN);
533*2d1d418eSSumit Saxena 	tm_req.Function = MPI3_FUNCTION_SCSI_TASK_MGMT;
534*2d1d418eSSumit Saxena 	drv_cmd->state = MPI3MR_CMD_PENDING;
535*2d1d418eSSumit Saxena 	drv_cmd->is_waiting = 1;
536*2d1d418eSSumit Saxena 	drv_cmd->callback = NULL;
537*2d1d418eSSumit Saxena 
538*2d1d418eSSumit Saxena 	if (ccb) {
539*2d1d418eSSumit Saxena 		if (tm_type == MPI3_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
540*2d1d418eSSumit Saxena 			op_req_q = &sc->op_req_q[cmd->req_qidx];
541*2d1d418eSSumit Saxena 			tm_req.TaskHostTag = htole16(cmd->hosttag);
542*2d1d418eSSumit Saxena 			tm_req.TaskRequestQueueID = htole16(op_req_q->qid);
543*2d1d418eSSumit Saxena 		}
544*2d1d418eSSumit Saxena 	}
545*2d1d418eSSumit Saxena 
546*2d1d418eSSumit Saxena 	if (tgtdev)
547*2d1d418eSSumit Saxena 		mpi3mr_atomic_inc(&tgtdev->block_io);
548*2d1d418eSSumit Saxena 
549*2d1d418eSSumit Saxena 	if (tgtdev && (tgtdev->dev_type == MPI3_DEVICE_DEVFORM_PCIE)) {
550*2d1d418eSSumit Saxena 		if ((tm_type == MPI3_SCSITASKMGMT_TASKTYPE_ABORT_TASK)
551*2d1d418eSSumit Saxena 		     && tgtdev->dev_spec.pcie_inf.abort_to)
552*2d1d418eSSumit Saxena  			timeout = tgtdev->dev_spec.pcie_inf.abort_to;
553*2d1d418eSSumit Saxena 		else if ((tm_type == MPI3_SCSITASKMGMT_TASKTYPE_TARGET_RESET)
554*2d1d418eSSumit Saxena 			 && tgtdev->dev_spec.pcie_inf.reset_to)
555*2d1d418eSSumit Saxena 			 timeout = tgtdev->dev_spec.pcie_inf.reset_to;
556*2d1d418eSSumit Saxena 	}
557*2d1d418eSSumit Saxena 
558*2d1d418eSSumit Saxena 	sc->tm_chan = (void *)&drv_cmd;
559*2d1d418eSSumit Saxena 
560*2d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_DEBUG_TM,
561*2d1d418eSSumit Saxena 		      "posting task management request: type(%d), handle(0x%04x)\n",
562*2d1d418eSSumit Saxena 		       tm_type, tgtdev->dev_handle);
563*2d1d418eSSumit Saxena 
564*2d1d418eSSumit Saxena 	init_completion(&drv_cmd->completion);
565*2d1d418eSSumit Saxena 	retval = mpi3mr_submit_admin_cmd(sc, &tm_req, sizeof(tm_req));
566*2d1d418eSSumit Saxena 	if (retval) {
567*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR,
568*2d1d418eSSumit Saxena 			      "posting task management request is failed\n");
569*2d1d418eSSumit Saxena 		retval = -1;
570*2d1d418eSSumit Saxena 		goto out_unlock;
571*2d1d418eSSumit Saxena 	}
572*2d1d418eSSumit Saxena 	wait_for_completion_timeout_tm(&drv_cmd->completion, timeout, sc);
573*2d1d418eSSumit Saxena 
574*2d1d418eSSumit Saxena 	if (!(drv_cmd->state & MPI3MR_CMD_COMPLETE)) {
575*2d1d418eSSumit Saxena 		drv_cmd->is_waiting = 0;
576*2d1d418eSSumit Saxena 		retval = -1;
577*2d1d418eSSumit Saxena 		if (!(drv_cmd->state & MPI3MR_CMD_RESET)) {
578*2d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_ERROR,
579*2d1d418eSSumit Saxena 				      "task management request timed out after %ld seconds\n", timeout);
580*2d1d418eSSumit Saxena 			if (sc->mpi3mr_debug & MPI3MR_DEBUG_TM) {
581*2d1d418eSSumit Saxena 				mpi3mr_dprint(sc, MPI3MR_INFO, "tm_request dump\n");
582*2d1d418eSSumit Saxena 				mpi3mr_hexdump(&tm_req, sizeof(tm_req), 8);
583*2d1d418eSSumit Saxena 			}
584*2d1d418eSSumit Saxena 			trigger_reset_from_watchdog(sc, MPI3MR_TRIGGER_SOFT_RESET, MPI3MR_RESET_FROM_TM_TIMEOUT);
585*2d1d418eSSumit Saxena 			retval = ETIMEDOUT;
586*2d1d418eSSumit Saxena 		}
587*2d1d418eSSumit Saxena 		goto out_unlock;
588*2d1d418eSSumit Saxena 	}
589*2d1d418eSSumit Saxena 
590*2d1d418eSSumit Saxena 	if (!(drv_cmd->state & MPI3MR_CMD_REPLYVALID)) {
591*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR,
592*2d1d418eSSumit Saxena 			      "invalid task management reply message\n");
593*2d1d418eSSumit Saxena 		retval = -1;
594*2d1d418eSSumit Saxena 		goto out_unlock;
595*2d1d418eSSumit Saxena 	}
596*2d1d418eSSumit Saxena 	tm_reply = (MPI3_SCSI_TASK_MGMT_REPLY *)drv_cmd->reply;
597*2d1d418eSSumit Saxena 
598*2d1d418eSSumit Saxena 	switch (drv_cmd->ioc_status) {
599*2d1d418eSSumit Saxena 	case MPI3_IOCSTATUS_SUCCESS:
600*2d1d418eSSumit Saxena 		resp_code = tm_reply->ResponseData & MPI3MR_RI_MASK_RESPCODE;
601*2d1d418eSSumit Saxena 		break;
602*2d1d418eSSumit Saxena 	case MPI3_IOCSTATUS_SCSI_IOC_TERMINATED:
603*2d1d418eSSumit Saxena 		resp_code = MPI3_SCSITASKMGMT_RSPCODE_TM_COMPLETE;
604*2d1d418eSSumit Saxena 		break;
605*2d1d418eSSumit Saxena 	default:
606*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR,
607*2d1d418eSSumit Saxena 			      "task management request to handle(0x%04x) is failed with ioc_status(0x%04x) log_info(0x%08x)\n",
608*2d1d418eSSumit Saxena 			       tgtdev->dev_handle, drv_cmd->ioc_status, drv_cmd->ioc_loginfo);
609*2d1d418eSSumit Saxena 		retval = -1;
610*2d1d418eSSumit Saxena 		goto out_unlock;
611*2d1d418eSSumit Saxena 	}
612*2d1d418eSSumit Saxena 
613*2d1d418eSSumit Saxena 	switch (resp_code) {
614*2d1d418eSSumit Saxena 	case MPI3_SCSITASKMGMT_RSPCODE_TM_SUCCEEDED:
615*2d1d418eSSumit Saxena 	case MPI3_SCSITASKMGMT_RSPCODE_TM_COMPLETE:
616*2d1d418eSSumit Saxena 		break;
617*2d1d418eSSumit Saxena 	case MPI3_SCSITASKMGMT_RSPCODE_IO_QUEUED_ON_IOC:
618*2d1d418eSSumit Saxena 		if (tm_type != MPI3_SCSITASKMGMT_TASKTYPE_QUERY_TASK)
619*2d1d418eSSumit Saxena 			retval = -1;
620*2d1d418eSSumit Saxena 		break;
621*2d1d418eSSumit Saxena 	default:
622*2d1d418eSSumit Saxena 		retval = -1;
623*2d1d418eSSumit Saxena 		break;
624*2d1d418eSSumit Saxena 	}
625*2d1d418eSSumit Saxena 
626*2d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_DEBUG_TM,
627*2d1d418eSSumit Saxena 		      "task management request type(%d) completed for handle(0x%04x) with ioc_status(0x%04x), log_info(0x%08x)"
628*2d1d418eSSumit Saxena 		      "termination_count(%u), response:%s(0x%x)\n", tm_type, tgtdev->dev_handle, drv_cmd->ioc_status, drv_cmd->ioc_loginfo,
629*2d1d418eSSumit Saxena 		      tm_reply->TerminationCount, mpi3mr_tm_response_name(resp_code), resp_code);
630*2d1d418eSSumit Saxena 
631*2d1d418eSSumit Saxena 	if (retval)
632*2d1d418eSSumit Saxena 		goto out_unlock;
633*2d1d418eSSumit Saxena 
634*2d1d418eSSumit Saxena 	mpi3mr_disable_interrupts(sc);
635*2d1d418eSSumit Saxena 	mpi3mr_poll_pend_io_completions(sc);
636*2d1d418eSSumit Saxena 	mpi3mr_enable_interrupts(sc);
637*2d1d418eSSumit Saxena 	mpi3mr_poll_pend_io_completions(sc);
638*2d1d418eSSumit Saxena 
639*2d1d418eSSumit Saxena 	switch (tm_type) {
640*2d1d418eSSumit Saxena 	case MPI3_SCSITASKMGMT_TASKTYPE_ABORT_TASK:
641*2d1d418eSSumit Saxena 		if (cmd->state == MPI3MR_CMD_STATE_IN_TM) {
642*2d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_ERROR,
643*2d1d418eSSumit Saxena 				      "%s: task abort returned success from firmware but corresponding CCB (%p) was not terminated"
644*2d1d418eSSumit Saxena 				      "marking task abort failed!\n", sc->name, cmd->ccb);
645*2d1d418eSSumit Saxena 			retval = -1;
646*2d1d418eSSumit Saxena 		}
647*2d1d418eSSumit Saxena 		break;
648*2d1d418eSSumit Saxena 	case MPI3_SCSITASKMGMT_TASKTYPE_TARGET_RESET:
649*2d1d418eSSumit Saxena 		if (mpi3mr_atomic_read(&tgtdev->outstanding)) {
650*2d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_ERROR,
651*2d1d418eSSumit Saxena 				      "%s: target reset returned success from firmware but IOs are still pending on the target (%p)"
652*2d1d418eSSumit Saxena 				      "marking target reset failed!\n",
653*2d1d418eSSumit Saxena 				      sc->name, tgtdev);
654*2d1d418eSSumit Saxena 			retval = -1;
655*2d1d418eSSumit Saxena 		}
656*2d1d418eSSumit Saxena 		break;
657*2d1d418eSSumit Saxena 	default:
658*2d1d418eSSumit Saxena 		break;
659*2d1d418eSSumit Saxena 	}
660*2d1d418eSSumit Saxena 
661*2d1d418eSSumit Saxena out_unlock:
662*2d1d418eSSumit Saxena 	drv_cmd->state = MPI3MR_CMD_NOTUSED;
663*2d1d418eSSumit Saxena 	mtx_unlock(&drv_cmd->lock);
664*2d1d418eSSumit Saxena 	if (tgtdev && mpi3mr_atomic_read(&tgtdev->block_io) > 0)
665*2d1d418eSSumit Saxena 		mpi3mr_atomic_dec(&tgtdev->block_io);
666*2d1d418eSSumit Saxena 
667*2d1d418eSSumit Saxena 	return retval;
668*2d1d418eSSumit Saxena }
669*2d1d418eSSumit Saxena 
670*2d1d418eSSumit Saxena /**
671*2d1d418eSSumit Saxena  * mpi3mr_task_abort- Abort error handling callback
672*2d1d418eSSumit Saxena  * @cmd: Timed out command reference
673*2d1d418eSSumit Saxena  *
674*2d1d418eSSumit Saxena  * Issue Abort Task Management if the command is in LLD scope
675*2d1d418eSSumit Saxena  * and verify if it is aborted successfully and return status
676*2d1d418eSSumit Saxena  * accordingly.
677*2d1d418eSSumit Saxena  *
678*2d1d418eSSumit Saxena  * Return: SUCCESS of successful abort the SCSI command else FAILED
679*2d1d418eSSumit Saxena  */
680*2d1d418eSSumit Saxena static int mpi3mr_task_abort(struct mpi3mr_cmd *cmd)
681*2d1d418eSSumit Saxena {
682*2d1d418eSSumit Saxena 	int retval = 0;
683*2d1d418eSSumit Saxena 	struct mpi3mr_softc *sc;
684*2d1d418eSSumit Saxena 	union ccb *ccb;
685*2d1d418eSSumit Saxena 
686*2d1d418eSSumit Saxena 	sc = cmd->sc;
687*2d1d418eSSumit Saxena 
688*2d1d418eSSumit Saxena 	if (!cmd->ccb) {
689*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "SCSIIO command timed-out with NULL ccb\n");
690*2d1d418eSSumit Saxena 		return retval;
691*2d1d418eSSumit Saxena 	}
692*2d1d418eSSumit Saxena 	ccb = cmd->ccb;
693*2d1d418eSSumit Saxena 
694*2d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_INFO,
695*2d1d418eSSumit Saxena 		      "attempting abort task for ccb(%p)\n", ccb);
696*2d1d418eSSumit Saxena 
697*2d1d418eSSumit Saxena 	mpi3mr_print_cdb(ccb);
698*2d1d418eSSumit Saxena 
699*2d1d418eSSumit Saxena 	if (cmd->state != MPI3MR_CMD_STATE_BUSY) {
700*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_INFO,
701*2d1d418eSSumit Saxena 			      "%s: ccb is not in driver scope, abort task is not required\n",
702*2d1d418eSSumit Saxena 			      sc->name);
703*2d1d418eSSumit Saxena 		return retval;
704*2d1d418eSSumit Saxena 	}
705*2d1d418eSSumit Saxena 	cmd->state = MPI3MR_CMD_STATE_IN_TM;
706*2d1d418eSSumit Saxena 
707*2d1d418eSSumit Saxena 	retval = mpi3mr_issue_tm(sc, cmd, MPI3_SCSITASKMGMT_TASKTYPE_ABORT_TASK, MPI3MR_ABORTTM_TIMEOUT);
708*2d1d418eSSumit Saxena 
709*2d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_INFO,
710*2d1d418eSSumit Saxena 		      "abort task is %s for ccb(%p)\n", ((retval == 0) ? "SUCCESS" : "FAILED"), ccb);
711*2d1d418eSSumit Saxena 
712*2d1d418eSSumit Saxena 	return retval;
713*2d1d418eSSumit Saxena }
714*2d1d418eSSumit Saxena 
715*2d1d418eSSumit Saxena /**
716*2d1d418eSSumit Saxena  * mpi3mr_target_reset - Target reset error handling callback
717*2d1d418eSSumit Saxena  * @cmd: Timed out command reference
718*2d1d418eSSumit Saxena  *
719*2d1d418eSSumit Saxena  * Issue Target reset Task Management and verify the SCSI commands are
720*2d1d418eSSumit Saxena  * terminated successfully and return status accordingly.
721*2d1d418eSSumit Saxena  *
722*2d1d418eSSumit Saxena  * Return: SUCCESS of successful termination of the SCSI commands else
723*2d1d418eSSumit Saxena  *         FAILED
724*2d1d418eSSumit Saxena  */
725*2d1d418eSSumit Saxena static int mpi3mr_target_reset(struct mpi3mr_cmd *cmd)
726*2d1d418eSSumit Saxena {
727*2d1d418eSSumit Saxena 	int retval = 0;
728*2d1d418eSSumit Saxena 	struct mpi3mr_softc *sc;
729*2d1d418eSSumit Saxena 	struct mpi3mr_target *target;
730*2d1d418eSSumit Saxena 
731*2d1d418eSSumit Saxena 	sc = cmd->sc;
732*2d1d418eSSumit Saxena 
733*2d1d418eSSumit Saxena 	target = cmd->targ;
734*2d1d418eSSumit Saxena 	if (target == NULL)  {
735*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_XINFO, "Device does not exist for target:0x%p,"
736*2d1d418eSSumit Saxena 			      "target reset is not required\n", target);
737*2d1d418eSSumit Saxena 		return retval;
738*2d1d418eSSumit Saxena 	}
739*2d1d418eSSumit Saxena 
740*2d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_INFO,
741*2d1d418eSSumit Saxena 		      "attempting target reset on target(%d)\n", target->per_id);
742*2d1d418eSSumit Saxena 
743*2d1d418eSSumit Saxena 
744*2d1d418eSSumit Saxena 	if (mpi3mr_atomic_read(&target->outstanding)) {
745*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_INFO,
746*2d1d418eSSumit Saxena 			      "no outstanding IOs on the target(%d),"
747*2d1d418eSSumit Saxena 			      " target reset not required.\n", target->per_id);
748*2d1d418eSSumit Saxena 		return retval;
749*2d1d418eSSumit Saxena 	}
750*2d1d418eSSumit Saxena 
751*2d1d418eSSumit Saxena 	retval = mpi3mr_issue_tm(sc, cmd, MPI3_SCSITASKMGMT_TASKTYPE_TARGET_RESET, MPI3MR_RESETTM_TIMEOUT);
752*2d1d418eSSumit Saxena 
753*2d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_INFO,
754*2d1d418eSSumit Saxena 		      "target reset is %s for target(%d)\n", ((retval == 0) ? "SUCCESS" : "FAILED"),
755*2d1d418eSSumit Saxena 		      target->per_id);
756*2d1d418eSSumit Saxena 
757*2d1d418eSSumit Saxena 	return retval;
758*2d1d418eSSumit Saxena }
759*2d1d418eSSumit Saxena 
760*2d1d418eSSumit Saxena /**
761*2d1d418eSSumit Saxena  * mpi3mr_get_fw_pending_ios - Calculate pending I/O count
762*2d1d418eSSumit Saxena  * @sc: Adapter instance reference
763*2d1d418eSSumit Saxena  *
764*2d1d418eSSumit Saxena  * Calculate the pending I/Os for the controller and return.
765*2d1d418eSSumit Saxena  *
766*2d1d418eSSumit Saxena  * Return: Number of pending I/Os
767*2d1d418eSSumit Saxena  */
768*2d1d418eSSumit Saxena static inline int mpi3mr_get_fw_pending_ios(struct mpi3mr_softc *sc)
769*2d1d418eSSumit Saxena {
770*2d1d418eSSumit Saxena 	U16 i, pend_ios = 0;
771*2d1d418eSSumit Saxena 
772*2d1d418eSSumit Saxena 	for (i = 0; i < sc->num_queues; i++)
773*2d1d418eSSumit Saxena 		pend_ios += mpi3mr_atomic_read(&sc->op_reply_q[i].pend_ios);
774*2d1d418eSSumit Saxena 	return pend_ios;
775*2d1d418eSSumit Saxena }
776*2d1d418eSSumit Saxena 
777*2d1d418eSSumit Saxena /**
778*2d1d418eSSumit Saxena  * mpi3mr_wait_for_host_io - block for I/Os to complete
779*2d1d418eSSumit Saxena  * @sc: Adapter instance reference
780*2d1d418eSSumit Saxena  * @timeout: time out in seconds
781*2d1d418eSSumit Saxena  *
782*2d1d418eSSumit Saxena  * Waits for pending I/Os for the given adapter to complete or
783*2d1d418eSSumit Saxena  * to hit the timeout.
784*2d1d418eSSumit Saxena  *
785*2d1d418eSSumit Saxena  * Return: Nothing
786*2d1d418eSSumit Saxena  */
787*2d1d418eSSumit Saxena static int mpi3mr_wait_for_host_io(struct mpi3mr_softc *sc, U32 timeout)
788*2d1d418eSSumit Saxena {
789*2d1d418eSSumit Saxena 	enum mpi3mr_iocstate iocstate;
790*2d1d418eSSumit Saxena 
791*2d1d418eSSumit Saxena 	iocstate = mpi3mr_get_iocstate(sc);
792*2d1d418eSSumit Saxena 	if (iocstate != MRIOC_STATE_READY) {
793*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_XINFO, "%s :Controller is in NON-READY state! Proceed with Reset\n", __func__);
794*2d1d418eSSumit Saxena 		return -1;
795*2d1d418eSSumit Saxena 	}
796*2d1d418eSSumit Saxena 
797*2d1d418eSSumit Saxena 	if (!mpi3mr_get_fw_pending_ios(sc))
798*2d1d418eSSumit Saxena 		return 0;
799*2d1d418eSSumit Saxena 
800*2d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_INFO,
801*2d1d418eSSumit Saxena 		      "%s :Waiting for %d seconds prior to reset for %d pending I/Os to complete\n",
802*2d1d418eSSumit Saxena 		      __func__, timeout, mpi3mr_get_fw_pending_ios(sc));
803*2d1d418eSSumit Saxena 
804*2d1d418eSSumit Saxena 	int i;
805*2d1d418eSSumit Saxena 	for (i = 0; i < timeout; i++) {
806*2d1d418eSSumit Saxena 		if (!mpi3mr_get_fw_pending_ios(sc)) {
807*2d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_INFO, "%s :All pending I/Os got completed while waiting! Reset not required\n", __func__);
808*2d1d418eSSumit Saxena 			return 0;
809*2d1d418eSSumit Saxena 
810*2d1d418eSSumit Saxena 		}
811*2d1d418eSSumit Saxena 		iocstate = mpi3mr_get_iocstate(sc);
812*2d1d418eSSumit Saxena 		if (iocstate != MRIOC_STATE_READY) {
813*2d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_XINFO, "%s :Controller state becomes NON-READY while waiting! dont wait further"
814*2d1d418eSSumit Saxena 				      "Proceed with Reset\n", __func__);
815*2d1d418eSSumit Saxena 			return -1;
816*2d1d418eSSumit Saxena 		}
817*2d1d418eSSumit Saxena 		DELAY(1000 * 1000);
818*2d1d418eSSumit Saxena 	}
819*2d1d418eSSumit Saxena 
820*2d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_INFO, "%s :Pending I/Os after wait exaust is %d! Proceed with Reset\n", __func__,
821*2d1d418eSSumit Saxena 		      mpi3mr_get_fw_pending_ios(sc));
822*2d1d418eSSumit Saxena 
823*2d1d418eSSumit Saxena 	return -1;
824*2d1d418eSSumit Saxena }
825*2d1d418eSSumit Saxena 
826*2d1d418eSSumit Saxena static void
827*2d1d418eSSumit Saxena mpi3mr_scsiio_timeout(void *data)
828*2d1d418eSSumit Saxena {
829*2d1d418eSSumit Saxena 	int retval = 0;
830*2d1d418eSSumit Saxena 	struct mpi3mr_softc *sc;
831*2d1d418eSSumit Saxena 	struct mpi3mr_cmd *cmd;
832*2d1d418eSSumit Saxena 	struct mpi3mr_target *targ_dev = NULL;
833*2d1d418eSSumit Saxena 
834*2d1d418eSSumit Saxena 	if (!data)
835*2d1d418eSSumit Saxena 		return;
836*2d1d418eSSumit Saxena 
837*2d1d418eSSumit Saxena 	cmd = (struct mpi3mr_cmd *)data;
838*2d1d418eSSumit Saxena 	sc = cmd->sc;
839*2d1d418eSSumit Saxena 
840*2d1d418eSSumit Saxena 	if (cmd->ccb == NULL) {
841*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "SCSIIO command timed-out with NULL ccb\n");
842*2d1d418eSSumit Saxena 		return;
843*2d1d418eSSumit Saxena 	}
844*2d1d418eSSumit Saxena 
845*2d1d418eSSumit Saxena 	/*
846*2d1d418eSSumit Saxena 	 * TMs are not supported for IO timeouts on VD/LD, so directly issue controller reset
847*2d1d418eSSumit Saxena 	 * with max timeout for outstanding IOs to complete is 180sec.
848*2d1d418eSSumit Saxena 	 */
849*2d1d418eSSumit Saxena 	targ_dev = cmd->targ;
850*2d1d418eSSumit Saxena 	if (targ_dev && (targ_dev->dev_type == MPI3_DEVICE_DEVFORM_VD)) {
851*2d1d418eSSumit Saxena 		if (mpi3mr_wait_for_host_io(sc, MPI3MR_RAID_ERRREC_RESET_TIMEOUT))
852*2d1d418eSSumit Saxena 			trigger_reset_from_watchdog(sc, MPI3MR_TRIGGER_SOFT_RESET, MPI3MR_RESET_FROM_SCSIIO_TIMEOUT);
853*2d1d418eSSumit Saxena 		return;
854*2d1d418eSSumit Saxena  	}
855*2d1d418eSSumit Saxena 
856*2d1d418eSSumit Saxena 	/* Issue task abort to recover the timed out IO */
857*2d1d418eSSumit Saxena 	retval = mpi3mr_task_abort(cmd);
858*2d1d418eSSumit Saxena 	if (!retval || (retval == ETIMEDOUT))
859*2d1d418eSSumit Saxena 		return;
860*2d1d418eSSumit Saxena 
861*2d1d418eSSumit Saxena 	/*
862*2d1d418eSSumit Saxena 	 * task abort has failed to recover the timed out IO,
863*2d1d418eSSumit Saxena 	 * try with the target reset
864*2d1d418eSSumit Saxena 	 */
865*2d1d418eSSumit Saxena 	retval = mpi3mr_target_reset(cmd);
866*2d1d418eSSumit Saxena 	if (!retval || (retval == ETIMEDOUT))
867*2d1d418eSSumit Saxena 		return;
868*2d1d418eSSumit Saxena 
869*2d1d418eSSumit Saxena 	/*
870*2d1d418eSSumit Saxena 	 * task abort and target reset has failed. So issue Controller reset(soft reset)
871*2d1d418eSSumit Saxena 	 * through OCR thread context
872*2d1d418eSSumit Saxena 	 */
873*2d1d418eSSumit Saxena 	trigger_reset_from_watchdog(sc, MPI3MR_TRIGGER_SOFT_RESET, MPI3MR_RESET_FROM_SCSIIO_TIMEOUT);
874*2d1d418eSSumit Saxena 
875*2d1d418eSSumit Saxena 	return;
876*2d1d418eSSumit Saxena }
877*2d1d418eSSumit Saxena 
878*2d1d418eSSumit Saxena void int_to_lun(unsigned int lun, U8 *req_lun)
879*2d1d418eSSumit Saxena {
880*2d1d418eSSumit Saxena 	int i;
881*2d1d418eSSumit Saxena 
882*2d1d418eSSumit Saxena 	memset(req_lun, 0, sizeof(*req_lun));
883*2d1d418eSSumit Saxena 
884*2d1d418eSSumit Saxena 	for (i = 0; i < sizeof(lun); i += 2) {
885*2d1d418eSSumit Saxena 		req_lun[i] = (lun >> 8) & 0xFF;
886*2d1d418eSSumit Saxena 		req_lun[i+1] = lun & 0xFF;
887*2d1d418eSSumit Saxena 		lun = lun >> 16;
888*2d1d418eSSumit Saxena 	}
889*2d1d418eSSumit Saxena 
890*2d1d418eSSumit Saxena }
891*2d1d418eSSumit Saxena 
892*2d1d418eSSumit Saxena static U16 get_req_queue_index(struct mpi3mr_softc *sc)
893*2d1d418eSSumit Saxena {
894*2d1d418eSSumit Saxena 	U16 i = 0, reply_q_index = 0, reply_q_pend_ios = 0;
895*2d1d418eSSumit Saxena 
896*2d1d418eSSumit Saxena 	reply_q_pend_ios = mpi3mr_atomic_read(&sc->op_reply_q[0].pend_ios);
897*2d1d418eSSumit Saxena 	for (i = 0; i < sc->num_queues; i++) {
898*2d1d418eSSumit Saxena 		if (reply_q_pend_ios > mpi3mr_atomic_read(&sc->op_reply_q[i].pend_ios)) {
899*2d1d418eSSumit Saxena 			reply_q_pend_ios = mpi3mr_atomic_read(&sc->op_reply_q[i].pend_ios);
900*2d1d418eSSumit Saxena 			reply_q_index = i;
901*2d1d418eSSumit Saxena 		}
902*2d1d418eSSumit Saxena 	}
903*2d1d418eSSumit Saxena 
904*2d1d418eSSumit Saxena 	return reply_q_index;
905*2d1d418eSSumit Saxena }
906*2d1d418eSSumit Saxena 
907*2d1d418eSSumit Saxena static void
908*2d1d418eSSumit Saxena mpi3mr_action_scsiio(struct mpi3mr_cam_softc *cam_sc, union ccb *ccb)
909*2d1d418eSSumit Saxena {
910*2d1d418eSSumit Saxena 	Mpi3SCSIIORequest_t *req = NULL;
911*2d1d418eSSumit Saxena 	struct ccb_scsiio *csio;
912*2d1d418eSSumit Saxena 	struct mpi3mr_softc *sc;
913*2d1d418eSSumit Saxena 	struct mpi3mr_target *targ;
914*2d1d418eSSumit Saxena 	struct mpi3mr_cmd *cm;
915*2d1d418eSSumit Saxena 	uint8_t scsi_opcode, queue_idx;
916*2d1d418eSSumit Saxena 	uint32_t mpi_control;
917*2d1d418eSSumit Saxena 	struct mpi3mr_op_req_queue *opreqq = NULL;
918*2d1d418eSSumit Saxena 	U32 data_len_blks = 0;
919*2d1d418eSSumit Saxena 	U32 tracked_io_sz = 0;
920*2d1d418eSSumit Saxena 	U32 ioc_pend_data_len = 0, tg_pend_data_len = 0;
921*2d1d418eSSumit Saxena 	struct mpi3mr_throttle_group_info *tg = NULL;
922*2d1d418eSSumit Saxena 	static int ratelimit;
923*2d1d418eSSumit Saxena 
924*2d1d418eSSumit Saxena 	sc = cam_sc->sc;
925*2d1d418eSSumit Saxena 	mtx_assert(&sc->mpi3mr_mtx, MA_OWNED);
926*2d1d418eSSumit Saxena 
927*2d1d418eSSumit Saxena 	if (sc->unrecoverable) {
928*2d1d418eSSumit Saxena 		mpi3mr_set_ccbstatus(ccb, CAM_DEV_NOT_THERE);
929*2d1d418eSSumit Saxena 		xpt_done(ccb);
930*2d1d418eSSumit Saxena 		return;
931*2d1d418eSSumit Saxena 	}
932*2d1d418eSSumit Saxena 
933*2d1d418eSSumit Saxena 	csio = &ccb->csio;
934*2d1d418eSSumit Saxena 	KASSERT(csio->ccb_h.target_id < cam_sc->maxtargets,
935*2d1d418eSSumit Saxena 	    ("Target %d out of bounds in XPT_SCSI_IO\n",
936*2d1d418eSSumit Saxena 	     csio->ccb_h.target_id));
937*2d1d418eSSumit Saxena 
938*2d1d418eSSumit Saxena 	scsi_opcode = scsiio_cdb_ptr(csio)[0];
939*2d1d418eSSumit Saxena 
940*2d1d418eSSumit Saxena 	if ((sc->mpi3mr_flags & MPI3MR_FLAGS_SHUTDOWN) &&
941*2d1d418eSSumit Saxena 	    !((scsi_opcode == SYNCHRONIZE_CACHE) ||
942*2d1d418eSSumit Saxena 	      (scsi_opcode == START_STOP_UNIT))) {
943*2d1d418eSSumit Saxena 		mpi3mr_set_ccbstatus(ccb, CAM_REQ_CMP);
944*2d1d418eSSumit Saxena 		xpt_done(ccb);
945*2d1d418eSSumit Saxena 		return;
946*2d1d418eSSumit Saxena 	}
947*2d1d418eSSumit Saxena 
948*2d1d418eSSumit Saxena 	targ = mpi3mr_find_target_by_per_id(cam_sc, csio->ccb_h.target_id);
949*2d1d418eSSumit Saxena 	if (targ == NULL)  {
950*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_XINFO, "Device with target ID: 0x%x does not exist\n",
951*2d1d418eSSumit Saxena 			      csio->ccb_h.target_id);
952*2d1d418eSSumit Saxena 		mpi3mr_set_ccbstatus(ccb, CAM_DEV_NOT_THERE);
953*2d1d418eSSumit Saxena 		xpt_done(ccb);
954*2d1d418eSSumit Saxena 		return;
955*2d1d418eSSumit Saxena 	}
956*2d1d418eSSumit Saxena 
957*2d1d418eSSumit Saxena 	if (targ && targ->is_hidden)  {
958*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_XINFO, "Device with target ID: 0x%x is hidden\n",
959*2d1d418eSSumit Saxena 			      csio->ccb_h.target_id);
960*2d1d418eSSumit Saxena 		mpi3mr_set_ccbstatus(ccb, CAM_DEV_NOT_THERE);
961*2d1d418eSSumit Saxena 		xpt_done(ccb);
962*2d1d418eSSumit Saxena 		return;
963*2d1d418eSSumit Saxena 	}
964*2d1d418eSSumit Saxena 
965*2d1d418eSSumit Saxena 	if (targ->dev_removed == 1)  {
966*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_XINFO, "Device with target ID: 0x%x is removed\n", csio->ccb_h.target_id);
967*2d1d418eSSumit Saxena 		mpi3mr_set_ccbstatus(ccb, CAM_DEV_NOT_THERE);
968*2d1d418eSSumit Saxena 		xpt_done(ccb);
969*2d1d418eSSumit Saxena 		return;
970*2d1d418eSSumit Saxena 	}
971*2d1d418eSSumit Saxena 
972*2d1d418eSSumit Saxena 	if (targ->dev_handle == 0x0) {
973*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "%s NULL handle for target 0x%x\n",
974*2d1d418eSSumit Saxena 		    __func__, csio->ccb_h.target_id);
975*2d1d418eSSumit Saxena 		mpi3mr_set_ccbstatus(ccb, CAM_DEV_NOT_THERE);
976*2d1d418eSSumit Saxena 		xpt_done(ccb);
977*2d1d418eSSumit Saxena 		return;
978*2d1d418eSSumit Saxena 	}
979*2d1d418eSSumit Saxena 
980*2d1d418eSSumit Saxena 	if (mpi3mr_atomic_read(&targ->block_io) ||
981*2d1d418eSSumit Saxena 		(sc->reset_in_progress == 1) || (sc->prepare_for_reset == 1)) {
982*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_TRACE, "%s target is busy target_id: 0x%x\n",
983*2d1d418eSSumit Saxena 		    __func__, csio->ccb_h.target_id);
984*2d1d418eSSumit Saxena 		mpi3mr_set_ccbstatus(ccb, CAM_REQUEUE_REQ);
985*2d1d418eSSumit Saxena 		xpt_done(ccb);
986*2d1d418eSSumit Saxena 		return;
987*2d1d418eSSumit Saxena 	}
988*2d1d418eSSumit Saxena 
989*2d1d418eSSumit Saxena 	/*
990*2d1d418eSSumit Saxena 	 * Sometimes, it is possible to get a command that is not "In
991*2d1d418eSSumit Saxena 	 * Progress" and was actually aborted by the upper layer.  Check for
992*2d1d418eSSumit Saxena 	 * this here and complete the command without error.
993*2d1d418eSSumit Saxena 	 */
994*2d1d418eSSumit Saxena 	if (mpi3mr_get_ccbstatus(ccb) != CAM_REQ_INPROG) {
995*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_TRACE, "%s Command is not in progress for "
996*2d1d418eSSumit Saxena 		    "target %u\n", __func__, csio->ccb_h.target_id);
997*2d1d418eSSumit Saxena 		xpt_done(ccb);
998*2d1d418eSSumit Saxena 		return;
999*2d1d418eSSumit Saxena 	}
1000*2d1d418eSSumit Saxena 	/*
1001*2d1d418eSSumit Saxena 	 * If devinfo is 0 this will be a volume.  In that case don't tell CAM
1002*2d1d418eSSumit Saxena 	 * that the volume has timed out.  We want volumes to be enumerated
1003*2d1d418eSSumit Saxena 	 * until they are deleted/removed, not just failed.
1004*2d1d418eSSumit Saxena 	 */
1005*2d1d418eSSumit Saxena 	if (targ->flags & MPI3MRSAS_TARGET_INREMOVAL) {
1006*2d1d418eSSumit Saxena 		if (targ->devinfo == 0)
1007*2d1d418eSSumit Saxena 			mpi3mr_set_ccbstatus(ccb, CAM_REQ_CMP);
1008*2d1d418eSSumit Saxena 		else
1009*2d1d418eSSumit Saxena 			mpi3mr_set_ccbstatus(ccb, CAM_SEL_TIMEOUT);
1010*2d1d418eSSumit Saxena 		xpt_done(ccb);
1011*2d1d418eSSumit Saxena 		return;
1012*2d1d418eSSumit Saxena 	}
1013*2d1d418eSSumit Saxena 
1014*2d1d418eSSumit Saxena 	if ((scsi_opcode == UNMAP) &&
1015*2d1d418eSSumit Saxena 		(pci_get_device(sc->mpi3mr_dev) == MPI3_MFGPAGE_DEVID_SAS4116) &&
1016*2d1d418eSSumit Saxena 		(targ->dev_type == MPI3_DEVICE_DEVFORM_PCIE) &&
1017*2d1d418eSSumit Saxena 		(mpi3mr_allow_unmap_to_fw(sc, ccb) == false))
1018*2d1d418eSSumit Saxena 		return;
1019*2d1d418eSSumit Saxena 
1020*2d1d418eSSumit Saxena 	cm = mpi3mr_get_command(sc);
1021*2d1d418eSSumit Saxena 	if (cm == NULL || (sc->mpi3mr_flags & MPI3MR_FLAGS_DIAGRESET)) {
1022*2d1d418eSSumit Saxena 		if (cm != NULL) {
1023*2d1d418eSSumit Saxena 			mpi3mr_release_command(cm);
1024*2d1d418eSSumit Saxena 		}
1025*2d1d418eSSumit Saxena 		if ((cam_sc->flags & MPI3MRSAS_QUEUE_FROZEN) == 0) {
1026*2d1d418eSSumit Saxena 			xpt_freeze_simq(cam_sc->sim, 1);
1027*2d1d418eSSumit Saxena 			cam_sc->flags |= MPI3MRSAS_QUEUE_FROZEN;
1028*2d1d418eSSumit Saxena 		}
1029*2d1d418eSSumit Saxena 		ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
1030*2d1d418eSSumit Saxena 		ccb->ccb_h.status |= CAM_REQUEUE_REQ;
1031*2d1d418eSSumit Saxena 		xpt_done(ccb);
1032*2d1d418eSSumit Saxena 		return;
1033*2d1d418eSSumit Saxena 	}
1034*2d1d418eSSumit Saxena 
1035*2d1d418eSSumit Saxena 	switch (csio->ccb_h.flags & CAM_DIR_MASK) {
1036*2d1d418eSSumit Saxena 	case CAM_DIR_IN:
1037*2d1d418eSSumit Saxena 		mpi_control = MPI3_SCSIIO_FLAGS_DATADIRECTION_READ;
1038*2d1d418eSSumit Saxena 		cm->data_dir = MPI3MR_READ;
1039*2d1d418eSSumit Saxena 		break;
1040*2d1d418eSSumit Saxena 	case CAM_DIR_OUT:
1041*2d1d418eSSumit Saxena 		mpi_control = MPI3_SCSIIO_FLAGS_DATADIRECTION_WRITE;
1042*2d1d418eSSumit Saxena 		cm->data_dir = MPI3MR_WRITE;
1043*2d1d418eSSumit Saxena 		break;
1044*2d1d418eSSumit Saxena 	case CAM_DIR_NONE:
1045*2d1d418eSSumit Saxena 	default:
1046*2d1d418eSSumit Saxena 		mpi_control = MPI3_SCSIIO_FLAGS_DATADIRECTION_NO_DATA_TRANSFER;
1047*2d1d418eSSumit Saxena 		break;
1048*2d1d418eSSumit Saxena 	}
1049*2d1d418eSSumit Saxena 
1050*2d1d418eSSumit Saxena 	if (csio->cdb_len > 16)
1051*2d1d418eSSumit Saxena 		mpi_control |= MPI3_SCSIIO_FLAGS_CDB_GREATER_THAN_16;
1052*2d1d418eSSumit Saxena 
1053*2d1d418eSSumit Saxena 	req = (Mpi3SCSIIORequest_t *)&cm->io_request;
1054*2d1d418eSSumit Saxena 	bzero(req, sizeof(*req));
1055*2d1d418eSSumit Saxena 	req->Function = MPI3_FUNCTION_SCSI_IO;
1056*2d1d418eSSumit Saxena 	req->HostTag = cm->hosttag;
1057*2d1d418eSSumit Saxena 	req->DataLength = htole32(csio->dxfer_len);
1058*2d1d418eSSumit Saxena 	req->DevHandle = htole16(targ->dev_handle);
1059*2d1d418eSSumit Saxena 
1060*2d1d418eSSumit Saxena 	/*
1061*2d1d418eSSumit Saxena 	 * It looks like the hardware doesn't require an explicit tag
1062*2d1d418eSSumit Saxena 	 * number for each transaction.  SAM Task Management not supported
1063*2d1d418eSSumit Saxena 	 * at the moment.
1064*2d1d418eSSumit Saxena 	 */
1065*2d1d418eSSumit Saxena 	switch (csio->tag_action) {
1066*2d1d418eSSumit Saxena 	case MSG_HEAD_OF_Q_TAG:
1067*2d1d418eSSumit Saxena 		mpi_control |= MPI3_SCSIIO_FLAGS_TASKATTRIBUTE_HEADOFQ;
1068*2d1d418eSSumit Saxena 		break;
1069*2d1d418eSSumit Saxena 	case MSG_ORDERED_Q_TAG:
1070*2d1d418eSSumit Saxena 		mpi_control |= MPI3_SCSIIO_FLAGS_TASKATTRIBUTE_ORDEREDQ;
1071*2d1d418eSSumit Saxena 		break;
1072*2d1d418eSSumit Saxena 	case MSG_ACA_TASK:
1073*2d1d418eSSumit Saxena 		mpi_control |= MPI3_SCSIIO_FLAGS_TASKATTRIBUTE_ACAQ;
1074*2d1d418eSSumit Saxena 		break;
1075*2d1d418eSSumit Saxena 	case CAM_TAG_ACTION_NONE:
1076*2d1d418eSSumit Saxena 	case MSG_SIMPLE_Q_TAG:
1077*2d1d418eSSumit Saxena 	default:
1078*2d1d418eSSumit Saxena 		mpi_control |= MPI3_SCSIIO_FLAGS_TASKATTRIBUTE_SIMPLEQ;
1079*2d1d418eSSumit Saxena 		break;
1080*2d1d418eSSumit Saxena 	}
1081*2d1d418eSSumit Saxena 
1082*2d1d418eSSumit Saxena 	req->Flags = htole32(mpi_control);
1083*2d1d418eSSumit Saxena 
1084*2d1d418eSSumit Saxena 	if (csio->ccb_h.flags & CAM_CDB_POINTER)
1085*2d1d418eSSumit Saxena 		bcopy(csio->cdb_io.cdb_ptr, &req->CDB.CDB32[0], csio->cdb_len);
1086*2d1d418eSSumit Saxena 	else {
1087*2d1d418eSSumit Saxena 		KASSERT(csio->cdb_len <= IOCDBLEN,
1088*2d1d418eSSumit Saxena 		    ("cdb_len %d is greater than IOCDBLEN but CAM_CDB_POINTER "
1089*2d1d418eSSumit Saxena 		    "is not set", csio->cdb_len));
1090*2d1d418eSSumit Saxena 		bcopy(csio->cdb_io.cdb_bytes, &req->CDB.CDB32[0],csio->cdb_len);
1091*2d1d418eSSumit Saxena 	}
1092*2d1d418eSSumit Saxena 
1093*2d1d418eSSumit Saxena 	cm->length = csio->dxfer_len;
1094*2d1d418eSSumit Saxena 	cm->targ = targ;
1095*2d1d418eSSumit Saxena 	int_to_lun(csio->ccb_h.target_lun, req->LUN);
1096*2d1d418eSSumit Saxena 	cm->ccb = ccb;
1097*2d1d418eSSumit Saxena 	csio->ccb_h.qos.sim_data = sbinuptime();
1098*2d1d418eSSumit Saxena 	queue_idx = get_req_queue_index(sc);
1099*2d1d418eSSumit Saxena 	cm->req_qidx = queue_idx;
1100*2d1d418eSSumit Saxena 
1101*2d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_TRACE, "[QID:%d]: func: %s line:%d CDB: 0x%x targetid: %x SMID: 0x%x\n",
1102*2d1d418eSSumit Saxena 		(queue_idx + 1), __func__, __LINE__, scsi_opcode, csio->ccb_h.target_id, cm->hosttag);
1103*2d1d418eSSumit Saxena 
1104*2d1d418eSSumit Saxena 	ccb->ccb_h.status |= CAM_SIM_QUEUED;
1105*2d1d418eSSumit Saxena 
1106*2d1d418eSSumit Saxena 	switch ((ccb->ccb_h.flags & CAM_DATA_MASK)) {
1107*2d1d418eSSumit Saxena 	case CAM_DATA_PADDR:
1108*2d1d418eSSumit Saxena 	case CAM_DATA_SG_PADDR:
1109*2d1d418eSSumit Saxena 		device_printf(sc->mpi3mr_dev, "%s: physical addresses not supported\n",
1110*2d1d418eSSumit Saxena 		    __func__);
1111*2d1d418eSSumit Saxena 		mpi3mr_release_command(cm);
1112*2d1d418eSSumit Saxena 		ccb->ccb_h.status = CAM_REQ_INVALID;
1113*2d1d418eSSumit Saxena 		ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
1114*2d1d418eSSumit Saxena 		xpt_done(ccb);
1115*2d1d418eSSumit Saxena 		return;
1116*2d1d418eSSumit Saxena 	case CAM_DATA_SG:
1117*2d1d418eSSumit Saxena 		device_printf(sc->mpi3mr_dev, "%s: scatter gather is not supported\n",
1118*2d1d418eSSumit Saxena 		    __func__);
1119*2d1d418eSSumit Saxena 		mpi3mr_release_command(cm);
1120*2d1d418eSSumit Saxena 		ccb->ccb_h.status = CAM_REQ_INVALID;
1121*2d1d418eSSumit Saxena 		xpt_done(ccb);
1122*2d1d418eSSumit Saxena 		return;
1123*2d1d418eSSumit Saxena 	case CAM_DATA_VADDR:
1124*2d1d418eSSumit Saxena 	case CAM_DATA_BIO:
1125*2d1d418eSSumit Saxena 		if (csio->dxfer_len > (MPI3MR_SG_DEPTH * MPI3MR_4K_PGSZ)) {
1126*2d1d418eSSumit Saxena 			mpi3mr_release_command(cm);
1127*2d1d418eSSumit Saxena 			ccb->ccb_h.status = CAM_REQ_TOO_BIG;
1128*2d1d418eSSumit Saxena 			xpt_done(ccb);
1129*2d1d418eSSumit Saxena 			return;
1130*2d1d418eSSumit Saxena 		}
1131*2d1d418eSSumit Saxena 		cm->length = csio->dxfer_len;
1132*2d1d418eSSumit Saxena 		if (cm->length)
1133*2d1d418eSSumit Saxena 			cm->data = csio->data_ptr;
1134*2d1d418eSSumit Saxena 		break;
1135*2d1d418eSSumit Saxena 	default:
1136*2d1d418eSSumit Saxena 		ccb->ccb_h.status = CAM_REQ_INVALID;
1137*2d1d418eSSumit Saxena 		xpt_done(ccb);
1138*2d1d418eSSumit Saxena 		return;
1139*2d1d418eSSumit Saxena 	}
1140*2d1d418eSSumit Saxena 
1141*2d1d418eSSumit Saxena 	/* Prepare SGEs */
1142*2d1d418eSSumit Saxena 	if (mpi3mr_map_request(sc, cm)) {
1143*2d1d418eSSumit Saxena 		mpi3mr_release_command(cm);
1144*2d1d418eSSumit Saxena 		xpt_done(ccb);
1145*2d1d418eSSumit Saxena 		printf("func: %s line: %d Build SGLs failed\n", __func__, __LINE__);
1146*2d1d418eSSumit Saxena 		return;
1147*2d1d418eSSumit Saxena 	}
1148*2d1d418eSSumit Saxena 
1149*2d1d418eSSumit Saxena 	opreqq = &sc->op_req_q[queue_idx];
1150*2d1d418eSSumit Saxena 
1151*2d1d418eSSumit Saxena 	if (sc->iot_enable) {
1152*2d1d418eSSumit Saxena 		data_len_blks = csio->dxfer_len >> 9;
1153*2d1d418eSSumit Saxena 
1154*2d1d418eSSumit Saxena 		if ((data_len_blks >= sc->io_throttle_data_length) &&
1155*2d1d418eSSumit Saxena 		    targ->io_throttle_enabled) {
1156*2d1d418eSSumit Saxena 			tracked_io_sz = data_len_blks;
1157*2d1d418eSSumit Saxena 			tg = targ->throttle_group;
1158*2d1d418eSSumit Saxena 			if (tg) {
1159*2d1d418eSSumit Saxena 				mpi3mr_atomic_add(&sc->pend_large_data_sz, data_len_blks);
1160*2d1d418eSSumit Saxena 				mpi3mr_atomic_add(&tg->pend_large_data_sz, data_len_blks);
1161*2d1d418eSSumit Saxena 
1162*2d1d418eSSumit Saxena 				ioc_pend_data_len = mpi3mr_atomic_read(&sc->pend_large_data_sz);
1163*2d1d418eSSumit Saxena 				tg_pend_data_len = mpi3mr_atomic_read(&tg->pend_large_data_sz);
1164*2d1d418eSSumit Saxena 
1165*2d1d418eSSumit Saxena 				if (ratelimit % 1000) {
1166*2d1d418eSSumit Saxena 					mpi3mr_dprint(sc, MPI3MR_IOT,
1167*2d1d418eSSumit Saxena 						"large vd_io persist_id(%d), handle(0x%04x), data_len(%d),"
1168*2d1d418eSSumit Saxena 						"ioc_pending(%d), tg_pending(%d), ioc_high(%d), tg_high(%d)\n",
1169*2d1d418eSSumit Saxena 						targ->per_id, targ->dev_handle,
1170*2d1d418eSSumit Saxena 						data_len_blks, ioc_pend_data_len,
1171*2d1d418eSSumit Saxena 						tg_pend_data_len, sc->io_throttle_high,
1172*2d1d418eSSumit Saxena 						tg->high);
1173*2d1d418eSSumit Saxena 					ratelimit++;
1174*2d1d418eSSumit Saxena 				}
1175*2d1d418eSSumit Saxena 
1176*2d1d418eSSumit Saxena 				if (!tg->io_divert  && ((ioc_pend_data_len >=
1177*2d1d418eSSumit Saxena 				    sc->io_throttle_high) ||
1178*2d1d418eSSumit Saxena 				    (tg_pend_data_len >= tg->high))) {
1179*2d1d418eSSumit Saxena 					tg->io_divert = 1;
1180*2d1d418eSSumit Saxena 					mpi3mr_dprint(sc, MPI3MR_IOT,
1181*2d1d418eSSumit Saxena 						"VD: Setting divert flag for tg_id(%d), persist_id(%d)\n",
1182*2d1d418eSSumit Saxena 						tg->id, targ->per_id);
1183*2d1d418eSSumit Saxena 					if (sc->mpi3mr_debug | MPI3MR_IOT)
1184*2d1d418eSSumit Saxena 						mpi3mr_print_cdb(ccb);
1185*2d1d418eSSumit Saxena 					mpi3mr_set_io_divert_for_all_vd_in_tg(sc,
1186*2d1d418eSSumit Saxena 					    tg, 1);
1187*2d1d418eSSumit Saxena 				}
1188*2d1d418eSSumit Saxena 			} else {
1189*2d1d418eSSumit Saxena 				mpi3mr_atomic_add(&sc->pend_large_data_sz, data_len_blks);
1190*2d1d418eSSumit Saxena 				ioc_pend_data_len = mpi3mr_atomic_read(&sc->pend_large_data_sz);
1191*2d1d418eSSumit Saxena 				if (ratelimit % 1000) {
1192*2d1d418eSSumit Saxena 					mpi3mr_dprint(sc, MPI3MR_IOT,
1193*2d1d418eSSumit Saxena 					    "large pd_io persist_id(%d), handle(0x%04x), data_len(%d), ioc_pending(%d), ioc_high(%d)\n",
1194*2d1d418eSSumit Saxena 					    targ->per_id, targ->dev_handle,
1195*2d1d418eSSumit Saxena 					    data_len_blks, ioc_pend_data_len,
1196*2d1d418eSSumit Saxena 					    sc->io_throttle_high);
1197*2d1d418eSSumit Saxena 					ratelimit++;
1198*2d1d418eSSumit Saxena 				}
1199*2d1d418eSSumit Saxena 
1200*2d1d418eSSumit Saxena 				if (ioc_pend_data_len >= sc->io_throttle_high) {
1201*2d1d418eSSumit Saxena 					targ->io_divert = 1;
1202*2d1d418eSSumit Saxena 					mpi3mr_dprint(sc, MPI3MR_IOT,
1203*2d1d418eSSumit Saxena 						"PD: Setting divert flag for persist_id(%d)\n",
1204*2d1d418eSSumit Saxena 						targ->per_id);
1205*2d1d418eSSumit Saxena 					if (sc->mpi3mr_debug | MPI3MR_IOT)
1206*2d1d418eSSumit Saxena 						mpi3mr_print_cdb(ccb);
1207*2d1d418eSSumit Saxena 				}
1208*2d1d418eSSumit Saxena 			}
1209*2d1d418eSSumit Saxena 		}
1210*2d1d418eSSumit Saxena 
1211*2d1d418eSSumit Saxena 		if (targ->io_divert) {
1212*2d1d418eSSumit Saxena 			req->MsgFlags |= MPI3_SCSIIO_MSGFLAGS_DIVERT_TO_FIRMWARE;
1213*2d1d418eSSumit Saxena 			mpi_control |= MPI3_SCSIIO_FLAGS_DIVERT_REASON_IO_THROTTLING;
1214*2d1d418eSSumit Saxena 		}
1215*2d1d418eSSumit Saxena 	}
1216*2d1d418eSSumit Saxena 	req->Flags = htole32(mpi_control);
1217*2d1d418eSSumit Saxena 
1218*2d1d418eSSumit Saxena 	if (mpi3mr_submit_io(sc, opreqq,
1219*2d1d418eSSumit Saxena 	    	(U8 *)&cm->io_request)) {
1220*2d1d418eSSumit Saxena 		mpi3mr_release_command(cm);
1221*2d1d418eSSumit Saxena 		if (tracked_io_sz) {
1222*2d1d418eSSumit Saxena 			mpi3mr_atomic_sub(&sc->pend_large_data_sz, tracked_io_sz);
1223*2d1d418eSSumit Saxena 			if (tg)
1224*2d1d418eSSumit Saxena 				mpi3mr_atomic_sub(&tg->pend_large_data_sz, tracked_io_sz);
1225*2d1d418eSSumit Saxena 		}
1226*2d1d418eSSumit Saxena 		mpi3mr_set_ccbstatus(ccb, CAM_RESRC_UNAVAIL);
1227*2d1d418eSSumit Saxena 		xpt_done(ccb);
1228*2d1d418eSSumit Saxena 	} else {
1229*2d1d418eSSumit Saxena 		callout_reset_sbt(&cm->callout, SBT_1S * 90 , 0,
1230*2d1d418eSSumit Saxena 				  mpi3mr_scsiio_timeout, cm, 0);
1231*2d1d418eSSumit Saxena 		mpi3mr_atomic_inc(&sc->fw_outstanding);
1232*2d1d418eSSumit Saxena 		mpi3mr_atomic_inc(&targ->outstanding);
1233*2d1d418eSSumit Saxena 		if (mpi3mr_atomic_read(&sc->fw_outstanding) > sc->io_cmds_highwater)
1234*2d1d418eSSumit Saxena 			sc->io_cmds_highwater++;
1235*2d1d418eSSumit Saxena 	}
1236*2d1d418eSSumit Saxena 
1237*2d1d418eSSumit Saxena 	cm->callout_owner = true;
1238*2d1d418eSSumit Saxena 	return;
1239*2d1d418eSSumit Saxena }
1240*2d1d418eSSumit Saxena 
1241*2d1d418eSSumit Saxena static void
1242*2d1d418eSSumit Saxena mpi3mr_cam_poll(struct cam_sim *sim)
1243*2d1d418eSSumit Saxena {
1244*2d1d418eSSumit Saxena 	struct mpi3mr_cam_softc *cam_sc;
1245*2d1d418eSSumit Saxena 	struct mpi3mr_irq_context *irq_ctx;
1246*2d1d418eSSumit Saxena 	struct mpi3mr_softc *sc;
1247*2d1d418eSSumit Saxena 	int i;
1248*2d1d418eSSumit Saxena 
1249*2d1d418eSSumit Saxena 	cam_sc = cam_sim_softc(sim);
1250*2d1d418eSSumit Saxena 	sc = cam_sc->sc;
1251*2d1d418eSSumit Saxena 
1252*2d1d418eSSumit Saxena 	mpi3mr_dprint(cam_sc->sc, MPI3MR_TRACE, "func: %s line: %d is called\n",
1253*2d1d418eSSumit Saxena 		__func__, __LINE__);
1254*2d1d418eSSumit Saxena 
1255*2d1d418eSSumit Saxena 	for (i = 0; i < sc->num_queues; i++) {
1256*2d1d418eSSumit Saxena 		irq_ctx = sc->irq_ctx + i;
1257*2d1d418eSSumit Saxena 		if (irq_ctx->op_reply_q->qid) {
1258*2d1d418eSSumit Saxena 			mpi3mr_complete_io_cmd(sc, irq_ctx);
1259*2d1d418eSSumit Saxena 		}
1260*2d1d418eSSumit Saxena 	}
1261*2d1d418eSSumit Saxena }
1262*2d1d418eSSumit Saxena 
1263*2d1d418eSSumit Saxena static void
1264*2d1d418eSSumit Saxena mpi3mr_cam_action(struct cam_sim *sim, union ccb *ccb)
1265*2d1d418eSSumit Saxena {
1266*2d1d418eSSumit Saxena 	struct mpi3mr_cam_softc *cam_sc;
1267*2d1d418eSSumit Saxena 	struct mpi3mr_target *targ;
1268*2d1d418eSSumit Saxena 
1269*2d1d418eSSumit Saxena 	cam_sc = cam_sim_softc(sim);
1270*2d1d418eSSumit Saxena 
1271*2d1d418eSSumit Saxena 	mpi3mr_dprint(cam_sc->sc, MPI3MR_TRACE, "ccb func_code 0x%x target id: 0x%x\n",
1272*2d1d418eSSumit Saxena 	    ccb->ccb_h.func_code, ccb->ccb_h.target_id);
1273*2d1d418eSSumit Saxena 
1274*2d1d418eSSumit Saxena 	mtx_assert(&cam_sc->sc->mpi3mr_mtx, MA_OWNED);
1275*2d1d418eSSumit Saxena 
1276*2d1d418eSSumit Saxena 	switch (ccb->ccb_h.func_code) {
1277*2d1d418eSSumit Saxena 	case XPT_PATH_INQ:
1278*2d1d418eSSumit Saxena 	{
1279*2d1d418eSSumit Saxena 		struct ccb_pathinq *cpi = &ccb->cpi;
1280*2d1d418eSSumit Saxena 
1281*2d1d418eSSumit Saxena 		cpi->version_num = 1;
1282*2d1d418eSSumit Saxena 		cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE|PI_WIDE_16;
1283*2d1d418eSSumit Saxena 		cpi->target_sprt = 0;
1284*2d1d418eSSumit Saxena 		cpi->hba_misc = PIM_NOBUSRESET | PIM_UNMAPPED | PIM_NOSCAN;
1285*2d1d418eSSumit Saxena 		cpi->hba_eng_cnt = 0;
1286*2d1d418eSSumit Saxena 		cpi->max_target = cam_sc->maxtargets - 1;
1287*2d1d418eSSumit Saxena 		cpi->max_lun = 0;
1288*2d1d418eSSumit Saxena 
1289*2d1d418eSSumit Saxena 		/*
1290*2d1d418eSSumit Saxena 		 * initiator_id is set here to an ID outside the set of valid
1291*2d1d418eSSumit Saxena 		 * target IDs (including volumes).
1292*2d1d418eSSumit Saxena 		 */
1293*2d1d418eSSumit Saxena 		cpi->initiator_id = cam_sc->maxtargets;
1294*2d1d418eSSumit Saxena 		strlcpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
1295*2d1d418eSSumit Saxena 		strlcpy(cpi->hba_vid, "Broadcom", HBA_IDLEN);
1296*2d1d418eSSumit Saxena 		strlcpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
1297*2d1d418eSSumit Saxena 		cpi->unit_number = cam_sim_unit(sim);
1298*2d1d418eSSumit Saxena 		cpi->bus_id = cam_sim_bus(sim);
1299*2d1d418eSSumit Saxena 		/*
1300*2d1d418eSSumit Saxena 		 * XXXSLM-I think this needs to change based on config page or
1301*2d1d418eSSumit Saxena 		 * something instead of hardcoded to 150000.
1302*2d1d418eSSumit Saxena 		 */
1303*2d1d418eSSumit Saxena 		cpi->base_transfer_speed = 150000;
1304*2d1d418eSSumit Saxena 		cpi->transport = XPORT_SAS;
1305*2d1d418eSSumit Saxena 		cpi->transport_version = 0;
1306*2d1d418eSSumit Saxena 		cpi->protocol = PROTO_SCSI;
1307*2d1d418eSSumit Saxena 		cpi->protocol_version = SCSI_REV_SPC;
1308*2d1d418eSSumit Saxena 
1309*2d1d418eSSumit Saxena 		targ = mpi3mr_find_target_by_per_id(cam_sc, ccb->ccb_h.target_id);
1310*2d1d418eSSumit Saxena 
1311*2d1d418eSSumit Saxena 		if (targ && (targ->dev_type == MPI3_DEVICE_DEVFORM_PCIE) &&
1312*2d1d418eSSumit Saxena 		    ((targ->dev_spec.pcie_inf.dev_info &
1313*2d1d418eSSumit Saxena 		    MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_MASK) ==
1314*2d1d418eSSumit Saxena 		    MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_NVME_DEVICE)) {
1315*2d1d418eSSumit Saxena 			cpi->maxio = targ->dev_spec.pcie_inf.mdts;
1316*2d1d418eSSumit Saxena 			mpi3mr_dprint(cam_sc->sc, MPI3MR_XINFO,
1317*2d1d418eSSumit Saxena 				"PCI device target_id: %u max io size: %u\n",
1318*2d1d418eSSumit Saxena 				ccb->ccb_h.target_id, cpi->maxio);
1319*2d1d418eSSumit Saxena 		} else {
1320*2d1d418eSSumit Saxena 			cpi->maxio = PAGE_SIZE * (MPI3MR_SG_DEPTH - 1);
1321*2d1d418eSSumit Saxena 		}
1322*2d1d418eSSumit Saxena 		mpi3mr_set_ccbstatus(ccb, CAM_REQ_CMP);
1323*2d1d418eSSumit Saxena 		break;
1324*2d1d418eSSumit Saxena 	}
1325*2d1d418eSSumit Saxena 	case XPT_GET_TRAN_SETTINGS:
1326*2d1d418eSSumit Saxena 	{
1327*2d1d418eSSumit Saxena 		struct ccb_trans_settings	*cts;
1328*2d1d418eSSumit Saxena 		struct ccb_trans_settings_sas	*sas;
1329*2d1d418eSSumit Saxena 		struct ccb_trans_settings_scsi	*scsi;
1330*2d1d418eSSumit Saxena 
1331*2d1d418eSSumit Saxena 		cts = &ccb->cts;
1332*2d1d418eSSumit Saxena 		sas = &cts->xport_specific.sas;
1333*2d1d418eSSumit Saxena 		scsi = &cts->proto_specific.scsi;
1334*2d1d418eSSumit Saxena 
1335*2d1d418eSSumit Saxena 		KASSERT(cts->ccb_h.target_id < cam_sc->maxtargets,
1336*2d1d418eSSumit Saxena 		    ("Target %d out of bounds in XPT_GET_TRAN_SETTINGS\n",
1337*2d1d418eSSumit Saxena 		    cts->ccb_h.target_id));
1338*2d1d418eSSumit Saxena 		targ = mpi3mr_find_target_by_per_id(cam_sc, cts->ccb_h.target_id);
1339*2d1d418eSSumit Saxena 
1340*2d1d418eSSumit Saxena 		if (targ == NULL) {
1341*2d1d418eSSumit Saxena 			mpi3mr_dprint(cam_sc->sc, MPI3MR_TRACE, "Device with target ID: 0x%x does not exist\n",
1342*2d1d418eSSumit Saxena 			cts->ccb_h.target_id);
1343*2d1d418eSSumit Saxena 			mpi3mr_set_ccbstatus(ccb, CAM_DEV_NOT_THERE);
1344*2d1d418eSSumit Saxena 			break;
1345*2d1d418eSSumit Saxena 		}
1346*2d1d418eSSumit Saxena 
1347*2d1d418eSSumit Saxena 		if ((targ->dev_handle == 0x0) || (targ->dev_removed == 1))  {
1348*2d1d418eSSumit Saxena 			mpi3mr_set_ccbstatus(ccb, CAM_DEV_NOT_THERE);
1349*2d1d418eSSumit Saxena 			break;
1350*2d1d418eSSumit Saxena 		}
1351*2d1d418eSSumit Saxena 
1352*2d1d418eSSumit Saxena 		cts->protocol_version = SCSI_REV_SPC2;
1353*2d1d418eSSumit Saxena 		cts->transport = XPORT_SAS;
1354*2d1d418eSSumit Saxena 		cts->transport_version = 0;
1355*2d1d418eSSumit Saxena 
1356*2d1d418eSSumit Saxena 		sas->valid = CTS_SAS_VALID_SPEED;
1357*2d1d418eSSumit Saxena 
1358*2d1d418eSSumit Saxena 		switch (targ->link_rate) {
1359*2d1d418eSSumit Saxena 		case 0x08:
1360*2d1d418eSSumit Saxena 			sas->bitrate = 150000;
1361*2d1d418eSSumit Saxena 			break;
1362*2d1d418eSSumit Saxena 		case 0x09:
1363*2d1d418eSSumit Saxena 			sas->bitrate = 300000;
1364*2d1d418eSSumit Saxena 			break;
1365*2d1d418eSSumit Saxena 		case 0x0a:
1366*2d1d418eSSumit Saxena 			sas->bitrate = 600000;
1367*2d1d418eSSumit Saxena 			break;
1368*2d1d418eSSumit Saxena 		case 0x0b:
1369*2d1d418eSSumit Saxena 			sas->bitrate = 1200000;
1370*2d1d418eSSumit Saxena 			break;
1371*2d1d418eSSumit Saxena 		default:
1372*2d1d418eSSumit Saxena 			sas->valid = 0;
1373*2d1d418eSSumit Saxena 		}
1374*2d1d418eSSumit Saxena 
1375*2d1d418eSSumit Saxena 		cts->protocol = PROTO_SCSI;
1376*2d1d418eSSumit Saxena 		scsi->valid = CTS_SCSI_VALID_TQ;
1377*2d1d418eSSumit Saxena 		scsi->flags = CTS_SCSI_FLAGS_TAG_ENB;
1378*2d1d418eSSumit Saxena 
1379*2d1d418eSSumit Saxena 		mpi3mr_set_ccbstatus(ccb, CAM_REQ_CMP);
1380*2d1d418eSSumit Saxena 		break;
1381*2d1d418eSSumit Saxena 	}
1382*2d1d418eSSumit Saxena 	case XPT_CALC_GEOMETRY:
1383*2d1d418eSSumit Saxena 		cam_calc_geometry(&ccb->ccg, /*extended*/1);
1384*2d1d418eSSumit Saxena 		mpi3mr_set_ccbstatus(ccb, CAM_REQ_CMP);
1385*2d1d418eSSumit Saxena 		break;
1386*2d1d418eSSumit Saxena 	case XPT_RESET_DEV:
1387*2d1d418eSSumit Saxena 		mpi3mr_dprint(cam_sc->sc, MPI3MR_INFO, "mpi3mr_action "
1388*2d1d418eSSumit Saxena 		    "XPT_RESET_DEV\n");
1389*2d1d418eSSumit Saxena 		return;
1390*2d1d418eSSumit Saxena 	case XPT_RESET_BUS:
1391*2d1d418eSSumit Saxena 	case XPT_ABORT:
1392*2d1d418eSSumit Saxena 	case XPT_TERM_IO:
1393*2d1d418eSSumit Saxena 		mpi3mr_dprint(cam_sc->sc, MPI3MR_INFO, "mpi3mr_action faking success "
1394*2d1d418eSSumit Saxena 		    "for abort or reset\n");
1395*2d1d418eSSumit Saxena 		mpi3mr_set_ccbstatus(ccb, CAM_REQ_CMP);
1396*2d1d418eSSumit Saxena 		break;
1397*2d1d418eSSumit Saxena 	case XPT_SCSI_IO:
1398*2d1d418eSSumit Saxena 		mpi3mr_action_scsiio(cam_sc, ccb);
1399*2d1d418eSSumit Saxena 		return;
1400*2d1d418eSSumit Saxena 	default:
1401*2d1d418eSSumit Saxena 		mpi3mr_set_ccbstatus(ccb, CAM_FUNC_NOTAVAIL);
1402*2d1d418eSSumit Saxena 		break;
1403*2d1d418eSSumit Saxena 	}
1404*2d1d418eSSumit Saxena 	xpt_done(ccb);
1405*2d1d418eSSumit Saxena }
1406*2d1d418eSSumit Saxena 
1407*2d1d418eSSumit Saxena void
1408*2d1d418eSSumit Saxena mpi3mr_startup_increment(struct mpi3mr_cam_softc *cam_sc)
1409*2d1d418eSSumit Saxena {
1410*2d1d418eSSumit Saxena 	if ((cam_sc->flags & MPI3MRSAS_IN_STARTUP) != 0) {
1411*2d1d418eSSumit Saxena 		if (cam_sc->startup_refcount++ == 0) {
1412*2d1d418eSSumit Saxena 			/* just starting, freeze the simq */
1413*2d1d418eSSumit Saxena 			mpi3mr_dprint(cam_sc->sc, MPI3MR_XINFO,
1414*2d1d418eSSumit Saxena 			    "%s freezing simq\n", __func__);
1415*2d1d418eSSumit Saxena 			xpt_hold_boot();
1416*2d1d418eSSumit Saxena 		}
1417*2d1d418eSSumit Saxena 		mpi3mr_dprint(cam_sc->sc, MPI3MR_XINFO, "%s refcount %u\n", __func__,
1418*2d1d418eSSumit Saxena 		    cam_sc->startup_refcount);
1419*2d1d418eSSumit Saxena 	}
1420*2d1d418eSSumit Saxena }
1421*2d1d418eSSumit Saxena 
1422*2d1d418eSSumit Saxena void
1423*2d1d418eSSumit Saxena mpi3mr_release_simq_reinit(struct mpi3mr_cam_softc *cam_sc)
1424*2d1d418eSSumit Saxena {
1425*2d1d418eSSumit Saxena 	if (cam_sc->flags & MPI3MRSAS_QUEUE_FROZEN) {
1426*2d1d418eSSumit Saxena 		cam_sc->flags &= ~MPI3MRSAS_QUEUE_FROZEN;
1427*2d1d418eSSumit Saxena 		xpt_release_simq(cam_sc->sim, 1);
1428*2d1d418eSSumit Saxena 		mpi3mr_dprint(cam_sc->sc, MPI3MR_INFO, "Unfreezing SIM queue\n");
1429*2d1d418eSSumit Saxena 	}
1430*2d1d418eSSumit Saxena }
1431*2d1d418eSSumit Saxena 
1432*2d1d418eSSumit Saxena void
1433*2d1d418eSSumit Saxena mpi3mr_rescan_target(struct mpi3mr_softc *sc, struct mpi3mr_target *targ)
1434*2d1d418eSSumit Saxena {
1435*2d1d418eSSumit Saxena 	struct mpi3mr_cam_softc *cam_sc = sc->cam_sc;
1436*2d1d418eSSumit Saxena 	path_id_t pathid;
1437*2d1d418eSSumit Saxena 	target_id_t targetid;
1438*2d1d418eSSumit Saxena 	union ccb *ccb;
1439*2d1d418eSSumit Saxena 
1440*2d1d418eSSumit Saxena 	pathid = cam_sim_path(cam_sc->sim);
1441*2d1d418eSSumit Saxena 	if (targ == NULL)
1442*2d1d418eSSumit Saxena 		targetid = CAM_TARGET_WILDCARD;
1443*2d1d418eSSumit Saxena 	else
1444*2d1d418eSSumit Saxena 		targetid = targ->per_id;
1445*2d1d418eSSumit Saxena 
1446*2d1d418eSSumit Saxena 	/*
1447*2d1d418eSSumit Saxena 	 * Allocate a CCB and schedule a rescan.
1448*2d1d418eSSumit Saxena 	 */
1449*2d1d418eSSumit Saxena 	ccb = xpt_alloc_ccb_nowait();
1450*2d1d418eSSumit Saxena 	if (ccb == NULL) {
1451*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "unable to alloc CCB for rescan\n");
1452*2d1d418eSSumit Saxena 		return;
1453*2d1d418eSSumit Saxena 	}
1454*2d1d418eSSumit Saxena 
1455*2d1d418eSSumit Saxena 	if (xpt_create_path(&ccb->ccb_h.path, NULL, pathid, targetid,
1456*2d1d418eSSumit Saxena 	    CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
1457*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "unable to create path for rescan\n");
1458*2d1d418eSSumit Saxena 		xpt_free_ccb(ccb);
1459*2d1d418eSSumit Saxena 		return;
1460*2d1d418eSSumit Saxena 	}
1461*2d1d418eSSumit Saxena 
1462*2d1d418eSSumit Saxena 	if (targetid == CAM_TARGET_WILDCARD)
1463*2d1d418eSSumit Saxena 		ccb->ccb_h.func_code = XPT_SCAN_BUS;
1464*2d1d418eSSumit Saxena 	else
1465*2d1d418eSSumit Saxena 		ccb->ccb_h.func_code = XPT_SCAN_TGT;
1466*2d1d418eSSumit Saxena 
1467*2d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_EVENT, "%s target id 0x%x\n", __func__, targetid);
1468*2d1d418eSSumit Saxena 	xpt_rescan(ccb);
1469*2d1d418eSSumit Saxena }
1470*2d1d418eSSumit Saxena 
1471*2d1d418eSSumit Saxena void
1472*2d1d418eSSumit Saxena mpi3mr_startup_decrement(struct mpi3mr_cam_softc *cam_sc)
1473*2d1d418eSSumit Saxena {
1474*2d1d418eSSumit Saxena 	if ((cam_sc->flags & MPI3MRSAS_IN_STARTUP) != 0) {
1475*2d1d418eSSumit Saxena 		if (--cam_sc->startup_refcount == 0) {
1476*2d1d418eSSumit Saxena 			/* finished all discovery-related actions, release
1477*2d1d418eSSumit Saxena 			 * the simq and rescan for the latest topology.
1478*2d1d418eSSumit Saxena 			 */
1479*2d1d418eSSumit Saxena 			mpi3mr_dprint(cam_sc->sc, MPI3MR_XINFO,
1480*2d1d418eSSumit Saxena 			    "%s releasing simq\n", __func__);
1481*2d1d418eSSumit Saxena 			cam_sc->flags &= ~MPI3MRSAS_IN_STARTUP;
1482*2d1d418eSSumit Saxena 			xpt_release_simq(cam_sc->sim, 1);
1483*2d1d418eSSumit Saxena 			xpt_release_boot();
1484*2d1d418eSSumit Saxena 		}
1485*2d1d418eSSumit Saxena 		mpi3mr_dprint(cam_sc->sc, MPI3MR_XINFO, "%s refcount %u\n", __func__,
1486*2d1d418eSSumit Saxena 		    cam_sc->startup_refcount);
1487*2d1d418eSSumit Saxena 	}
1488*2d1d418eSSumit Saxena }
1489*2d1d418eSSumit Saxena 
1490*2d1d418eSSumit Saxena static void
1491*2d1d418eSSumit Saxena mpi3mr_fw_event_free(struct mpi3mr_softc *sc, struct mpi3mr_fw_event_work *fw_event)
1492*2d1d418eSSumit Saxena {
1493*2d1d418eSSumit Saxena 	if (!fw_event)
1494*2d1d418eSSumit Saxena 		return;
1495*2d1d418eSSumit Saxena 
1496*2d1d418eSSumit Saxena 	if (fw_event->event_data != NULL) {
1497*2d1d418eSSumit Saxena 		free(fw_event->event_data, M_MPI3MR);
1498*2d1d418eSSumit Saxena 		fw_event->event_data = NULL;
1499*2d1d418eSSumit Saxena 	}
1500*2d1d418eSSumit Saxena 
1501*2d1d418eSSumit Saxena 	free(fw_event, M_MPI3MR);
1502*2d1d418eSSumit Saxena 	fw_event = NULL;
1503*2d1d418eSSumit Saxena }
1504*2d1d418eSSumit Saxena 
1505*2d1d418eSSumit Saxena static void
1506*2d1d418eSSumit Saxena mpi3mr_freeup_events(struct mpi3mr_softc *sc)
1507*2d1d418eSSumit Saxena {
1508*2d1d418eSSumit Saxena 	struct mpi3mr_fw_event_work *fw_event = NULL;
1509*2d1d418eSSumit Saxena 	mtx_lock(&sc->mpi3mr_mtx);
1510*2d1d418eSSumit Saxena 	while ((fw_event = TAILQ_FIRST(&sc->cam_sc->ev_queue)) != NULL) {
1511*2d1d418eSSumit Saxena 		TAILQ_REMOVE(&sc->cam_sc->ev_queue, fw_event, ev_link);
1512*2d1d418eSSumit Saxena 		mpi3mr_fw_event_free(sc, fw_event);
1513*2d1d418eSSumit Saxena 	}
1514*2d1d418eSSumit Saxena 	mtx_unlock(&sc->mpi3mr_mtx);
1515*2d1d418eSSumit Saxena }
1516*2d1d418eSSumit Saxena 
1517*2d1d418eSSumit Saxena static void
1518*2d1d418eSSumit Saxena mpi3mr_sastopochg_evt_debug(struct mpi3mr_softc *sc,
1519*2d1d418eSSumit Saxena 	Mpi3EventDataSasTopologyChangeList_t *event_data)
1520*2d1d418eSSumit Saxena {
1521*2d1d418eSSumit Saxena 	int i;
1522*2d1d418eSSumit Saxena 	U16 handle;
1523*2d1d418eSSumit Saxena 	U8 reason_code, phy_number;
1524*2d1d418eSSumit Saxena 	char *status_str = NULL;
1525*2d1d418eSSumit Saxena 	U8 link_rate, prev_link_rate;
1526*2d1d418eSSumit Saxena 
1527*2d1d418eSSumit Saxena 	switch (event_data->ExpStatus) {
1528*2d1d418eSSumit Saxena 	case MPI3_EVENT_SAS_TOPO_ES_NOT_RESPONDING:
1529*2d1d418eSSumit Saxena 		status_str = "remove";
1530*2d1d418eSSumit Saxena 		break;
1531*2d1d418eSSumit Saxena 	case MPI3_EVENT_SAS_TOPO_ES_RESPONDING:
1532*2d1d418eSSumit Saxena 		status_str =  "responding";
1533*2d1d418eSSumit Saxena 		break;
1534*2d1d418eSSumit Saxena 	case MPI3_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING:
1535*2d1d418eSSumit Saxena 		status_str = "remove delay";
1536*2d1d418eSSumit Saxena 		break;
1537*2d1d418eSSumit Saxena 	case MPI3_EVENT_SAS_TOPO_ES_NO_EXPANDER:
1538*2d1d418eSSumit Saxena 		status_str = "direct attached";
1539*2d1d418eSSumit Saxena 		break;
1540*2d1d418eSSumit Saxena 	default:
1541*2d1d418eSSumit Saxena 		status_str = "unknown status";
1542*2d1d418eSSumit Saxena 		break;
1543*2d1d418eSSumit Saxena 	}
1544*2d1d418eSSumit Saxena 
1545*2d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_INFO, "%s :sas topology change: (%s)\n",
1546*2d1d418eSSumit Saxena 	    __func__, status_str);
1547*2d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_INFO,
1548*2d1d418eSSumit Saxena 		"%s :\texpander_handle(0x%04x), enclosure_handle(0x%04x) "
1549*2d1d418eSSumit Saxena 	    "start_phy(%02d), num_entries(%d)\n", __func__,
1550*2d1d418eSSumit Saxena 	    (event_data->ExpanderDevHandle),
1551*2d1d418eSSumit Saxena 	    (event_data->EnclosureHandle),
1552*2d1d418eSSumit Saxena 	    event_data->StartPhyNum, event_data->NumEntries);
1553*2d1d418eSSumit Saxena 	for (i = 0; i < event_data->NumEntries; i++) {
1554*2d1d418eSSumit Saxena 		handle = (event_data->PhyEntry[i].AttachedDevHandle);
1555*2d1d418eSSumit Saxena 		if (!handle)
1556*2d1d418eSSumit Saxena 			continue;
1557*2d1d418eSSumit Saxena 		phy_number = event_data->StartPhyNum + i;
1558*2d1d418eSSumit Saxena 		reason_code = event_data->PhyEntry[i].Status &
1559*2d1d418eSSumit Saxena 		    MPI3_EVENT_SAS_TOPO_PHY_RC_MASK;
1560*2d1d418eSSumit Saxena 		switch (reason_code) {
1561*2d1d418eSSumit Saxena 		case MPI3_EVENT_SAS_TOPO_PHY_RC_TARG_NOT_RESPONDING:
1562*2d1d418eSSumit Saxena 			status_str = "target remove";
1563*2d1d418eSSumit Saxena 			break;
1564*2d1d418eSSumit Saxena 		case MPI3_EVENT_SAS_TOPO_PHY_RC_DELAY_NOT_RESPONDING:
1565*2d1d418eSSumit Saxena 			status_str = "delay target remove";
1566*2d1d418eSSumit Saxena 			break;
1567*2d1d418eSSumit Saxena 		case MPI3_EVENT_SAS_TOPO_PHY_RC_PHY_CHANGED:
1568*2d1d418eSSumit Saxena 			status_str = "link rate change";
1569*2d1d418eSSumit Saxena 			break;
1570*2d1d418eSSumit Saxena 		case MPI3_EVENT_SAS_TOPO_PHY_RC_NO_CHANGE:
1571*2d1d418eSSumit Saxena 			status_str = "target responding";
1572*2d1d418eSSumit Saxena 			break;
1573*2d1d418eSSumit Saxena 		default:
1574*2d1d418eSSumit Saxena 			status_str = "unknown";
1575*2d1d418eSSumit Saxena 			break;
1576*2d1d418eSSumit Saxena 		}
1577*2d1d418eSSumit Saxena 		link_rate = event_data->PhyEntry[i].LinkRate >> 4;
1578*2d1d418eSSumit Saxena 		prev_link_rate = event_data->PhyEntry[i].LinkRate & 0xF;
1579*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_INFO, "%s :\tphy(%02d), attached_handle(0x%04x): %s:"
1580*2d1d418eSSumit Saxena 		    " link rate: new(0x%02x), old(0x%02x)\n", __func__,
1581*2d1d418eSSumit Saxena 		    phy_number, handle, status_str, link_rate, prev_link_rate);
1582*2d1d418eSSumit Saxena 	}
1583*2d1d418eSSumit Saxena }
1584*2d1d418eSSumit Saxena 
1585*2d1d418eSSumit Saxena static void
1586*2d1d418eSSumit Saxena mpi3mr_process_sastopochg_evt(struct mpi3mr_softc *sc, struct mpi3mr_fw_event_work *fwevt)
1587*2d1d418eSSumit Saxena {
1588*2d1d418eSSumit Saxena 
1589*2d1d418eSSumit Saxena 	Mpi3EventDataSasTopologyChangeList_t *event_data =
1590*2d1d418eSSumit Saxena 		    (Mpi3EventDataSasTopologyChangeList_t *)fwevt->event_data;
1591*2d1d418eSSumit Saxena 	int i;
1592*2d1d418eSSumit Saxena 	U16 handle;
1593*2d1d418eSSumit Saxena 	U8 reason_code, link_rate;
1594*2d1d418eSSumit Saxena 	struct mpi3mr_target *target = NULL;
1595*2d1d418eSSumit Saxena 
1596*2d1d418eSSumit Saxena 
1597*2d1d418eSSumit Saxena 	mpi3mr_sastopochg_evt_debug(sc, event_data);
1598*2d1d418eSSumit Saxena 
1599*2d1d418eSSumit Saxena 	for (i = 0; i < event_data->NumEntries; i++) {
1600*2d1d418eSSumit Saxena 		handle = le16toh(event_data->PhyEntry[i].AttachedDevHandle);
1601*2d1d418eSSumit Saxena 		link_rate = event_data->PhyEntry[i].LinkRate >> 4;
1602*2d1d418eSSumit Saxena 
1603*2d1d418eSSumit Saxena 		if (!handle)
1604*2d1d418eSSumit Saxena 			continue;
1605*2d1d418eSSumit Saxena 		target = mpi3mr_find_target_by_dev_handle(sc->cam_sc, handle);
1606*2d1d418eSSumit Saxena 
1607*2d1d418eSSumit Saxena 		if (!target)
1608*2d1d418eSSumit Saxena 			continue;
1609*2d1d418eSSumit Saxena 
1610*2d1d418eSSumit Saxena 		target->link_rate = link_rate;
1611*2d1d418eSSumit Saxena 		reason_code = event_data->PhyEntry[i].Status &
1612*2d1d418eSSumit Saxena 			MPI3_EVENT_SAS_TOPO_PHY_RC_MASK;
1613*2d1d418eSSumit Saxena 
1614*2d1d418eSSumit Saxena 		switch (reason_code) {
1615*2d1d418eSSumit Saxena 		case MPI3_EVENT_SAS_TOPO_PHY_RC_TARG_NOT_RESPONDING:
1616*2d1d418eSSumit Saxena 			if (target->exposed_to_os)
1617*2d1d418eSSumit Saxena 				mpi3mr_remove_device_from_os(sc, target->dev_handle);
1618*2d1d418eSSumit Saxena 			mpi3mr_remove_device_from_list(sc, target, false);
1619*2d1d418eSSumit Saxena 			break;
1620*2d1d418eSSumit Saxena 		case MPI3_EVENT_SAS_TOPO_PHY_RC_PHY_CHANGED:
1621*2d1d418eSSumit Saxena 			break;
1622*2d1d418eSSumit Saxena 		default:
1623*2d1d418eSSumit Saxena 			break;
1624*2d1d418eSSumit Saxena 		}
1625*2d1d418eSSumit Saxena 	}
1626*2d1d418eSSumit Saxena 
1627*2d1d418eSSumit Saxena 	/*
1628*2d1d418eSSumit Saxena 	 * refcount was incremented for this event in
1629*2d1d418eSSumit Saxena 	 * mpi3mr_evt_handler. Decrement it here because the event has
1630*2d1d418eSSumit Saxena 	 * been processed.
1631*2d1d418eSSumit Saxena 	 */
1632*2d1d418eSSumit Saxena 	mpi3mr_startup_decrement(sc->cam_sc);
1633*2d1d418eSSumit Saxena 	return;
1634*2d1d418eSSumit Saxena }
1635*2d1d418eSSumit Saxena 
1636*2d1d418eSSumit Saxena static inline void
1637*2d1d418eSSumit Saxena mpi3mr_logdata_evt_bh(struct mpi3mr_softc *sc,
1638*2d1d418eSSumit Saxena 		      struct mpi3mr_fw_event_work *fwevt)
1639*2d1d418eSSumit Saxena {
1640*2d1d418eSSumit Saxena 	mpi3mr_app_save_logdata(sc, fwevt->event_data,
1641*2d1d418eSSumit Saxena 				fwevt->event_data_size);
1642*2d1d418eSSumit Saxena }
1643*2d1d418eSSumit Saxena 
1644*2d1d418eSSumit Saxena static void
1645*2d1d418eSSumit Saxena mpi3mr_pcietopochg_evt_debug(struct mpi3mr_softc *sc,
1646*2d1d418eSSumit Saxena 	Mpi3EventDataPcieTopologyChangeList_t *event_data)
1647*2d1d418eSSumit Saxena {
1648*2d1d418eSSumit Saxena 	int i;
1649*2d1d418eSSumit Saxena 	U16 handle;
1650*2d1d418eSSumit Saxena 	U16 reason_code;
1651*2d1d418eSSumit Saxena 	U8 port_number;
1652*2d1d418eSSumit Saxena 	char *status_str = NULL;
1653*2d1d418eSSumit Saxena 	U8 link_rate, prev_link_rate;
1654*2d1d418eSSumit Saxena 
1655*2d1d418eSSumit Saxena 	switch (event_data->SwitchStatus) {
1656*2d1d418eSSumit Saxena 	case MPI3_EVENT_PCIE_TOPO_SS_NOT_RESPONDING:
1657*2d1d418eSSumit Saxena 		status_str = "remove";
1658*2d1d418eSSumit Saxena 		break;
1659*2d1d418eSSumit Saxena 	case MPI3_EVENT_PCIE_TOPO_SS_RESPONDING:
1660*2d1d418eSSumit Saxena 		status_str =  "responding";
1661*2d1d418eSSumit Saxena 		break;
1662*2d1d418eSSumit Saxena 	case MPI3_EVENT_PCIE_TOPO_SS_DELAY_NOT_RESPONDING:
1663*2d1d418eSSumit Saxena 		status_str = "remove delay";
1664*2d1d418eSSumit Saxena 		break;
1665*2d1d418eSSumit Saxena 	case MPI3_EVENT_PCIE_TOPO_SS_NO_PCIE_SWITCH:
1666*2d1d418eSSumit Saxena 		status_str = "direct attached";
1667*2d1d418eSSumit Saxena 		break;
1668*2d1d418eSSumit Saxena 	default:
1669*2d1d418eSSumit Saxena 		status_str = "unknown status";
1670*2d1d418eSSumit Saxena 		break;
1671*2d1d418eSSumit Saxena 	}
1672*2d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_INFO, "%s :pcie topology change: (%s)\n",
1673*2d1d418eSSumit Saxena 		__func__, status_str);
1674*2d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_INFO,
1675*2d1d418eSSumit Saxena 		"%s :\tswitch_handle(0x%04x), enclosure_handle(0x%04x)"
1676*2d1d418eSSumit Saxena 		"start_port(%02d), num_entries(%d)\n", __func__,
1677*2d1d418eSSumit Saxena 		le16toh(event_data->SwitchDevHandle),
1678*2d1d418eSSumit Saxena 		le16toh(event_data->EnclosureHandle),
1679*2d1d418eSSumit Saxena 		event_data->StartPortNum, event_data->NumEntries);
1680*2d1d418eSSumit Saxena 	for (i = 0; i < event_data->NumEntries; i++) {
1681*2d1d418eSSumit Saxena 		handle =
1682*2d1d418eSSumit Saxena 			le16toh(event_data->PortEntry[i].AttachedDevHandle);
1683*2d1d418eSSumit Saxena 		if (!handle)
1684*2d1d418eSSumit Saxena 			continue;
1685*2d1d418eSSumit Saxena 		port_number = event_data->StartPortNum + i;
1686*2d1d418eSSumit Saxena 		reason_code = event_data->PortEntry[i].PortStatus;
1687*2d1d418eSSumit Saxena 		switch (reason_code) {
1688*2d1d418eSSumit Saxena 		case MPI3_EVENT_PCIE_TOPO_PS_NOT_RESPONDING:
1689*2d1d418eSSumit Saxena 			status_str = "target remove";
1690*2d1d418eSSumit Saxena 			break;
1691*2d1d418eSSumit Saxena 		case MPI3_EVENT_PCIE_TOPO_PS_DELAY_NOT_RESPONDING:
1692*2d1d418eSSumit Saxena 			status_str = "delay target remove";
1693*2d1d418eSSumit Saxena 			break;
1694*2d1d418eSSumit Saxena 		case MPI3_EVENT_PCIE_TOPO_PS_PORT_CHANGED:
1695*2d1d418eSSumit Saxena 			status_str = "link rate change";
1696*2d1d418eSSumit Saxena 			break;
1697*2d1d418eSSumit Saxena 		case MPI3_EVENT_PCIE_TOPO_PS_NO_CHANGE:
1698*2d1d418eSSumit Saxena 			status_str = "target responding";
1699*2d1d418eSSumit Saxena 			break;
1700*2d1d418eSSumit Saxena 		default:
1701*2d1d418eSSumit Saxena 			status_str = "unknown";
1702*2d1d418eSSumit Saxena 			break;
1703*2d1d418eSSumit Saxena 		}
1704*2d1d418eSSumit Saxena 		link_rate = event_data->PortEntry[i].CurrentPortInfo &
1705*2d1d418eSSumit Saxena 			MPI3_EVENT_PCIE_TOPO_PI_RATE_MASK;
1706*2d1d418eSSumit Saxena 		prev_link_rate = event_data->PortEntry[i].PreviousPortInfo &
1707*2d1d418eSSumit Saxena 			MPI3_EVENT_PCIE_TOPO_PI_RATE_MASK;
1708*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_INFO, "%s :\tport(%02d), attached_handle(0x%04x): %s:"
1709*2d1d418eSSumit Saxena 		    " link rate: new(0x%02x), old(0x%02x)\n", __func__,
1710*2d1d418eSSumit Saxena 		    port_number, handle, status_str, link_rate, prev_link_rate);
1711*2d1d418eSSumit Saxena 	}
1712*2d1d418eSSumit Saxena }
1713*2d1d418eSSumit Saxena 
1714*2d1d418eSSumit Saxena static void mpi3mr_process_pcietopochg_evt(struct mpi3mr_softc *sc,
1715*2d1d418eSSumit Saxena     struct mpi3mr_fw_event_work *fwevt)
1716*2d1d418eSSumit Saxena {
1717*2d1d418eSSumit Saxena 	Mpi3EventDataPcieTopologyChangeList_t *event_data =
1718*2d1d418eSSumit Saxena 		    (Mpi3EventDataPcieTopologyChangeList_t *)fwevt->event_data;
1719*2d1d418eSSumit Saxena 	int i;
1720*2d1d418eSSumit Saxena 	U16 handle;
1721*2d1d418eSSumit Saxena 	U8 reason_code, link_rate;
1722*2d1d418eSSumit Saxena 	struct mpi3mr_target *target = NULL;
1723*2d1d418eSSumit Saxena 
1724*2d1d418eSSumit Saxena 
1725*2d1d418eSSumit Saxena 	mpi3mr_pcietopochg_evt_debug(sc, event_data);
1726*2d1d418eSSumit Saxena 
1727*2d1d418eSSumit Saxena 	for (i = 0; i < event_data->NumEntries; i++) {
1728*2d1d418eSSumit Saxena 		handle =
1729*2d1d418eSSumit Saxena 			le16toh(event_data->PortEntry[i].AttachedDevHandle);
1730*2d1d418eSSumit Saxena 		if (!handle)
1731*2d1d418eSSumit Saxena 			continue;
1732*2d1d418eSSumit Saxena 		target = mpi3mr_find_target_by_dev_handle(sc->cam_sc, handle);
1733*2d1d418eSSumit Saxena 		if (!target)
1734*2d1d418eSSumit Saxena 			continue;
1735*2d1d418eSSumit Saxena 
1736*2d1d418eSSumit Saxena 		link_rate = event_data->PortEntry[i].CurrentPortInfo &
1737*2d1d418eSSumit Saxena 			MPI3_EVENT_PCIE_TOPO_PI_RATE_MASK;
1738*2d1d418eSSumit Saxena 		target->link_rate = link_rate;
1739*2d1d418eSSumit Saxena 
1740*2d1d418eSSumit Saxena 		reason_code = event_data->PortEntry[i].PortStatus;
1741*2d1d418eSSumit Saxena 
1742*2d1d418eSSumit Saxena 		switch (reason_code) {
1743*2d1d418eSSumit Saxena 		case MPI3_EVENT_PCIE_TOPO_PS_NOT_RESPONDING:
1744*2d1d418eSSumit Saxena 			if (target->exposed_to_os)
1745*2d1d418eSSumit Saxena 				mpi3mr_remove_device_from_os(sc, target->dev_handle);
1746*2d1d418eSSumit Saxena 			mpi3mr_remove_device_from_list(sc, target, false);
1747*2d1d418eSSumit Saxena 			break;
1748*2d1d418eSSumit Saxena 		case MPI3_EVENT_PCIE_TOPO_PS_PORT_CHANGED:
1749*2d1d418eSSumit Saxena 			break;
1750*2d1d418eSSumit Saxena 		default:
1751*2d1d418eSSumit Saxena 			break;
1752*2d1d418eSSumit Saxena 		}
1753*2d1d418eSSumit Saxena 	}
1754*2d1d418eSSumit Saxena 
1755*2d1d418eSSumit Saxena 	/*
1756*2d1d418eSSumit Saxena 	 * refcount was incremented for this event in
1757*2d1d418eSSumit Saxena 	 * mpi3mr_evt_handler. Decrement it here because the event has
1758*2d1d418eSSumit Saxena 	 * been processed.
1759*2d1d418eSSumit Saxena 	 */
1760*2d1d418eSSumit Saxena 	mpi3mr_startup_decrement(sc->cam_sc);
1761*2d1d418eSSumit Saxena 	return;
1762*2d1d418eSSumit Saxena }
1763*2d1d418eSSumit Saxena 
1764*2d1d418eSSumit Saxena void mpi3mr_add_device(struct mpi3mr_softc *sc, U16 per_id)
1765*2d1d418eSSumit Saxena {
1766*2d1d418eSSumit Saxena 	struct mpi3mr_target *target;
1767*2d1d418eSSumit Saxena 
1768*2d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_EVENT,
1769*2d1d418eSSumit Saxena 		"Adding device(persistent id: 0x%x)\n", per_id);
1770*2d1d418eSSumit Saxena 
1771*2d1d418eSSumit Saxena 	mpi3mr_startup_increment(sc->cam_sc);
1772*2d1d418eSSumit Saxena 	target = mpi3mr_find_target_by_per_id(sc->cam_sc, per_id);
1773*2d1d418eSSumit Saxena 
1774*2d1d418eSSumit Saxena 	if (!target) {
1775*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_INFO, "Not available in driver's"
1776*2d1d418eSSumit Saxena 		    "internal target list, persistent_id: %d\n",
1777*2d1d418eSSumit Saxena 		    per_id);
1778*2d1d418eSSumit Saxena 		goto out;
1779*2d1d418eSSumit Saxena 	}
1780*2d1d418eSSumit Saxena 
1781*2d1d418eSSumit Saxena 	if (target->is_hidden) {
1782*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_EVENT, "Target is hidden, persistent_id: %d\n",
1783*2d1d418eSSumit Saxena 			per_id);
1784*2d1d418eSSumit Saxena 		goto out;
1785*2d1d418eSSumit Saxena 	}
1786*2d1d418eSSumit Saxena 
1787*2d1d418eSSumit Saxena 	if (!target->exposed_to_os && !sc->reset_in_progress) {
1788*2d1d418eSSumit Saxena 		mpi3mr_rescan_target(sc, target);
1789*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_INFO,
1790*2d1d418eSSumit Saxena 			"Added device persistent_id: %d dev_handle: %d\n", per_id, target->dev_handle);
1791*2d1d418eSSumit Saxena 		target->exposed_to_os = 1;
1792*2d1d418eSSumit Saxena 	}
1793*2d1d418eSSumit Saxena 
1794*2d1d418eSSumit Saxena out:
1795*2d1d418eSSumit Saxena 	mpi3mr_startup_decrement(sc->cam_sc);
1796*2d1d418eSSumit Saxena }
1797*2d1d418eSSumit Saxena 
1798*2d1d418eSSumit Saxena int mpi3mr_remove_device_from_os(struct mpi3mr_softc *sc, U16 handle)
1799*2d1d418eSSumit Saxena {
1800*2d1d418eSSumit Saxena 	U32 i = 0;
1801*2d1d418eSSumit Saxena 	int retval = 0;
1802*2d1d418eSSumit Saxena 	struct mpi3mr_target *target;
1803*2d1d418eSSumit Saxena 
1804*2d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_EVENT,
1805*2d1d418eSSumit Saxena 		"Removing Device (dev_handle: %d)\n", handle);
1806*2d1d418eSSumit Saxena 
1807*2d1d418eSSumit Saxena 	target = mpi3mr_find_target_by_dev_handle(sc->cam_sc, handle);
1808*2d1d418eSSumit Saxena 
1809*2d1d418eSSumit Saxena 	if (!target) {
1810*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_INFO,
1811*2d1d418eSSumit Saxena 			"Device (persistent_id: %d dev_handle: %d) is already removed from driver's list\n",
1812*2d1d418eSSumit Saxena 			target->per_id, handle);
1813*2d1d418eSSumit Saxena 		mpi3mr_rescan_target(sc, NULL);
1814*2d1d418eSSumit Saxena 		retval = -1;
1815*2d1d418eSSumit Saxena 		goto out;
1816*2d1d418eSSumit Saxena 	}
1817*2d1d418eSSumit Saxena 
1818*2d1d418eSSumit Saxena 	target->flags |= MPI3MRSAS_TARGET_INREMOVAL;
1819*2d1d418eSSumit Saxena 
1820*2d1d418eSSumit Saxena 	while (mpi3mr_atomic_read(&target->outstanding) && (i < 30)) {
1821*2d1d418eSSumit Saxena 		i++;
1822*2d1d418eSSumit Saxena 		if (!(i % 2)) {
1823*2d1d418eSSumit Saxena 			mpi3mr_dprint(sc, MPI3MR_INFO,
1824*2d1d418eSSumit Saxena 			    "[%2d]waiting for "
1825*2d1d418eSSumit Saxena 			    "waiting for outstanding commands to complete on target: %d\n",
1826*2d1d418eSSumit Saxena 			    i, target->per_id);
1827*2d1d418eSSumit Saxena 		}
1828*2d1d418eSSumit Saxena 		DELAY(1000 * 1000);
1829*2d1d418eSSumit Saxena 	}
1830*2d1d418eSSumit Saxena 
1831*2d1d418eSSumit Saxena 	if (target->exposed_to_os && !sc->reset_in_progress) {
1832*2d1d418eSSumit Saxena 		mpi3mr_rescan_target(sc, target);
1833*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_INFO,
1834*2d1d418eSSumit Saxena 			"Removed device(persistent_id: %d dev_handle: %d)\n", target->per_id, handle);
1835*2d1d418eSSumit Saxena 		target->exposed_to_os = 0;
1836*2d1d418eSSumit Saxena 	}
1837*2d1d418eSSumit Saxena 
1838*2d1d418eSSumit Saxena 	target->flags &= ~MPI3MRSAS_TARGET_INREMOVAL;
1839*2d1d418eSSumit Saxena out:
1840*2d1d418eSSumit Saxena 	return retval;
1841*2d1d418eSSumit Saxena }
1842*2d1d418eSSumit Saxena 
1843*2d1d418eSSumit Saxena void mpi3mr_remove_device_from_list(struct mpi3mr_softc *sc,
1844*2d1d418eSSumit Saxena 	struct mpi3mr_target *target, bool must_delete)
1845*2d1d418eSSumit Saxena {
1846*2d1d418eSSumit Saxena 	mtx_lock_spin(&sc->target_lock);
1847*2d1d418eSSumit Saxena 	if ((target->state == MPI3MR_DEV_REMOVE_HS_STARTED) ||
1848*2d1d418eSSumit Saxena 	    (must_delete == true)) {
1849*2d1d418eSSumit Saxena 		TAILQ_REMOVE(&sc->cam_sc->tgt_list, target, tgt_next);
1850*2d1d418eSSumit Saxena 		target->state = MPI3MR_DEV_DELETED;
1851*2d1d418eSSumit Saxena 	}
1852*2d1d418eSSumit Saxena 	mtx_unlock_spin(&sc->target_lock);
1853*2d1d418eSSumit Saxena 
1854*2d1d418eSSumit Saxena 	if (target->state == MPI3MR_DEV_DELETED) {
1855*2d1d418eSSumit Saxena  		free(target, M_MPI3MR);
1856*2d1d418eSSumit Saxena  		target = NULL;
1857*2d1d418eSSumit Saxena  	}
1858*2d1d418eSSumit Saxena 
1859*2d1d418eSSumit Saxena 	return;
1860*2d1d418eSSumit Saxena }
1861*2d1d418eSSumit Saxena 
1862*2d1d418eSSumit Saxena /**
1863*2d1d418eSSumit Saxena  * mpi3mr_devstatuschg_evt_bh - DevStatusChange evt bottomhalf
1864*2d1d418eSSumit Saxena  * @sc: Adapter instance reference
1865*2d1d418eSSumit Saxena  * @fwevt: Firmware event
1866*2d1d418eSSumit Saxena  *
1867*2d1d418eSSumit Saxena  * Process Device Status Change event and based on device's new
1868*2d1d418eSSumit Saxena  * information, either expose the device to the upper layers, or
1869*2d1d418eSSumit Saxena  * remove the device from upper layers.
1870*2d1d418eSSumit Saxena  *
1871*2d1d418eSSumit Saxena  * Return: Nothing.
1872*2d1d418eSSumit Saxena  */
1873*2d1d418eSSumit Saxena static void mpi3mr_devstatuschg_evt_bh(struct mpi3mr_softc *sc,
1874*2d1d418eSSumit Saxena 	struct mpi3mr_fw_event_work *fwevt)
1875*2d1d418eSSumit Saxena {
1876*2d1d418eSSumit Saxena 	U16 dev_handle = 0;
1877*2d1d418eSSumit Saxena 	U8 uhide = 0, delete = 0, cleanup = 0;
1878*2d1d418eSSumit Saxena 	struct mpi3mr_target *tgtdev = NULL;
1879*2d1d418eSSumit Saxena 	Mpi3EventDataDeviceStatusChange_t *evtdata =
1880*2d1d418eSSumit Saxena 	    (Mpi3EventDataDeviceStatusChange_t *)fwevt->event_data;
1881*2d1d418eSSumit Saxena 
1882*2d1d418eSSumit Saxena 
1883*2d1d418eSSumit Saxena 
1884*2d1d418eSSumit Saxena 	dev_handle = le16toh(evtdata->DevHandle);
1885*2d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_INFO,
1886*2d1d418eSSumit Saxena 	    "%s :device status change: handle(0x%04x): reason code(0x%x)\n",
1887*2d1d418eSSumit Saxena 	    __func__, dev_handle, evtdata->ReasonCode);
1888*2d1d418eSSumit Saxena 	switch (evtdata->ReasonCode) {
1889*2d1d418eSSumit Saxena 	case MPI3_EVENT_DEV_STAT_RC_HIDDEN:
1890*2d1d418eSSumit Saxena 		delete = 1;
1891*2d1d418eSSumit Saxena 		break;
1892*2d1d418eSSumit Saxena 	case MPI3_EVENT_DEV_STAT_RC_NOT_HIDDEN:
1893*2d1d418eSSumit Saxena 		uhide = 1;
1894*2d1d418eSSumit Saxena 		break;
1895*2d1d418eSSumit Saxena 	case MPI3_EVENT_DEV_STAT_RC_VD_NOT_RESPONDING:
1896*2d1d418eSSumit Saxena 		delete = 1;
1897*2d1d418eSSumit Saxena 		cleanup = 1;
1898*2d1d418eSSumit Saxena 		break;
1899*2d1d418eSSumit Saxena 	default:
1900*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_INFO, "%s :Unhandled reason code(0x%x)\n", __func__,
1901*2d1d418eSSumit Saxena 		    evtdata->ReasonCode);
1902*2d1d418eSSumit Saxena 		break;
1903*2d1d418eSSumit Saxena 	}
1904*2d1d418eSSumit Saxena 
1905*2d1d418eSSumit Saxena 	tgtdev = mpi3mr_find_target_by_dev_handle(sc->cam_sc, dev_handle);
1906*2d1d418eSSumit Saxena 	if (!tgtdev)
1907*2d1d418eSSumit Saxena 		return;
1908*2d1d418eSSumit Saxena 
1909*2d1d418eSSumit Saxena 	if (uhide) {
1910*2d1d418eSSumit Saxena 		if (!tgtdev->exposed_to_os)
1911*2d1d418eSSumit Saxena 			mpi3mr_add_device(sc, tgtdev->per_id);
1912*2d1d418eSSumit Saxena 	}
1913*2d1d418eSSumit Saxena 
1914*2d1d418eSSumit Saxena 	if (delete)
1915*2d1d418eSSumit Saxena 		mpi3mr_remove_device_from_os(sc, dev_handle);
1916*2d1d418eSSumit Saxena 
1917*2d1d418eSSumit Saxena 	if (cleanup)
1918*2d1d418eSSumit Saxena 		mpi3mr_remove_device_from_list(sc, tgtdev, false);
1919*2d1d418eSSumit Saxena }
1920*2d1d418eSSumit Saxena 
1921*2d1d418eSSumit Saxena /**
1922*2d1d418eSSumit Saxena  * mpi3mr_devinfochg_evt_bh - DeviceInfoChange evt bottomhalf
1923*2d1d418eSSumit Saxena  * @sc: Adapter instance reference
1924*2d1d418eSSumit Saxena  * @dev_pg0: New device page0
1925*2d1d418eSSumit Saxena  *
1926*2d1d418eSSumit Saxena  * Process Device Info Change event and based on device's new
1927*2d1d418eSSumit Saxena  * information, either expose the device to the upper layers, or
1928*2d1d418eSSumit Saxena  * remove the device from upper layers or update the details of
1929*2d1d418eSSumit Saxena  * the device.
1930*2d1d418eSSumit Saxena  *
1931*2d1d418eSSumit Saxena  * Return: Nothing.
1932*2d1d418eSSumit Saxena  */
1933*2d1d418eSSumit Saxena static void mpi3mr_devinfochg_evt_bh(struct mpi3mr_softc *sc,
1934*2d1d418eSSumit Saxena 	Mpi3DevicePage0_t *dev_pg0)
1935*2d1d418eSSumit Saxena {
1936*2d1d418eSSumit Saxena 	struct mpi3mr_target *tgtdev = NULL;
1937*2d1d418eSSumit Saxena 	U16 dev_handle = 0, perst_id = 0;
1938*2d1d418eSSumit Saxena 
1939*2d1d418eSSumit Saxena 	perst_id = le16toh(dev_pg0->PersistentID);
1940*2d1d418eSSumit Saxena 	dev_handle = le16toh(dev_pg0->DevHandle);
1941*2d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_INFO,
1942*2d1d418eSSumit Saxena 	    "%s :Device info change: handle(0x%04x): persist_id(0x%x)\n",
1943*2d1d418eSSumit Saxena 	    __func__, dev_handle, perst_id);
1944*2d1d418eSSumit Saxena 	tgtdev = mpi3mr_find_target_by_dev_handle(sc->cam_sc, dev_handle);
1945*2d1d418eSSumit Saxena 	if (!tgtdev)
1946*2d1d418eSSumit Saxena 		return;
1947*2d1d418eSSumit Saxena 
1948*2d1d418eSSumit Saxena 	mpi3mr_update_device(sc, tgtdev, dev_pg0, false);
1949*2d1d418eSSumit Saxena 	if (!tgtdev->is_hidden && !tgtdev->exposed_to_os)
1950*2d1d418eSSumit Saxena 		mpi3mr_add_device(sc, perst_id);
1951*2d1d418eSSumit Saxena 
1952*2d1d418eSSumit Saxena 	if (tgtdev->is_hidden && tgtdev->exposed_to_os)
1953*2d1d418eSSumit Saxena 		mpi3mr_remove_device_from_os(sc, tgtdev->dev_handle);
1954*2d1d418eSSumit Saxena }
1955*2d1d418eSSumit Saxena 
1956*2d1d418eSSumit Saxena static void
1957*2d1d418eSSumit Saxena mpi3mr_fw_work(struct mpi3mr_softc *sc, struct mpi3mr_fw_event_work *fw_event)
1958*2d1d418eSSumit Saxena {
1959*2d1d418eSSumit Saxena 	if (sc->mpi3mr_flags & MPI3MR_FLAGS_SHUTDOWN)
1960*2d1d418eSSumit Saxena 		goto out;
1961*2d1d418eSSumit Saxena 
1962*2d1d418eSSumit Saxena 	if (!fw_event->process_event)
1963*2d1d418eSSumit Saxena 		goto evt_ack;
1964*2d1d418eSSumit Saxena 
1965*2d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_EVENT, "(%d)->(%s) Working on  Event: [%x]\n",
1966*2d1d418eSSumit Saxena 	    event_count++, __func__, fw_event->event);
1967*2d1d418eSSumit Saxena 
1968*2d1d418eSSumit Saxena 	switch (fw_event->event) {
1969*2d1d418eSSumit Saxena 	case MPI3_EVENT_DEVICE_ADDED:
1970*2d1d418eSSumit Saxena 	{
1971*2d1d418eSSumit Saxena 		Mpi3DevicePage0_t *dev_pg0 =
1972*2d1d418eSSumit Saxena 			(Mpi3DevicePage0_t *) fw_event->event_data;
1973*2d1d418eSSumit Saxena 		mpi3mr_add_device(sc, dev_pg0->PersistentID);
1974*2d1d418eSSumit Saxena 		break;
1975*2d1d418eSSumit Saxena 	}
1976*2d1d418eSSumit Saxena 	case MPI3_EVENT_DEVICE_INFO_CHANGED:
1977*2d1d418eSSumit Saxena 	{
1978*2d1d418eSSumit Saxena 		mpi3mr_devinfochg_evt_bh(sc,
1979*2d1d418eSSumit Saxena 		    (Mpi3DevicePage0_t *) fw_event->event_data);
1980*2d1d418eSSumit Saxena 		break;
1981*2d1d418eSSumit Saxena 	}
1982*2d1d418eSSumit Saxena 	case MPI3_EVENT_DEVICE_STATUS_CHANGE:
1983*2d1d418eSSumit Saxena 	{
1984*2d1d418eSSumit Saxena 		mpi3mr_devstatuschg_evt_bh(sc, fw_event);
1985*2d1d418eSSumit Saxena 		break;
1986*2d1d418eSSumit Saxena 	}
1987*2d1d418eSSumit Saxena 	case MPI3_EVENT_SAS_TOPOLOGY_CHANGE_LIST:
1988*2d1d418eSSumit Saxena 	{
1989*2d1d418eSSumit Saxena 		mpi3mr_process_sastopochg_evt(sc, fw_event);
1990*2d1d418eSSumit Saxena 		break;
1991*2d1d418eSSumit Saxena 	}
1992*2d1d418eSSumit Saxena 	case MPI3_EVENT_PCIE_TOPOLOGY_CHANGE_LIST:
1993*2d1d418eSSumit Saxena 	{
1994*2d1d418eSSumit Saxena 		mpi3mr_process_pcietopochg_evt(sc, fw_event);
1995*2d1d418eSSumit Saxena 		break;
1996*2d1d418eSSumit Saxena 	}
1997*2d1d418eSSumit Saxena 	case MPI3_EVENT_LOG_DATA:
1998*2d1d418eSSumit Saxena 	{
1999*2d1d418eSSumit Saxena 		mpi3mr_logdata_evt_bh(sc, fw_event);
2000*2d1d418eSSumit Saxena 		break;
2001*2d1d418eSSumit Saxena 	}
2002*2d1d418eSSumit Saxena 	default:
2003*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_TRACE,"Unhandled event 0x%0X\n",
2004*2d1d418eSSumit Saxena 		    fw_event->event);
2005*2d1d418eSSumit Saxena 		break;
2006*2d1d418eSSumit Saxena 
2007*2d1d418eSSumit Saxena 	}
2008*2d1d418eSSumit Saxena 
2009*2d1d418eSSumit Saxena evt_ack:
2010*2d1d418eSSumit Saxena 	if (fw_event->send_ack) {
2011*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_EVENT,"Process event ACK for event 0x%0X\n",
2012*2d1d418eSSumit Saxena 		    fw_event->event);
2013*2d1d418eSSumit Saxena 		mpi3mr_process_event_ack(sc, fw_event->event,
2014*2d1d418eSSumit Saxena 		    fw_event->event_context);
2015*2d1d418eSSumit Saxena 	}
2016*2d1d418eSSumit Saxena 
2017*2d1d418eSSumit Saxena out:
2018*2d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_EVENT, "(%d)->(%s) Event Free: [%x]\n", event_count,
2019*2d1d418eSSumit Saxena 	    __func__, fw_event->event);
2020*2d1d418eSSumit Saxena 
2021*2d1d418eSSumit Saxena 	mpi3mr_fw_event_free(sc, fw_event);
2022*2d1d418eSSumit Saxena }
2023*2d1d418eSSumit Saxena 
2024*2d1d418eSSumit Saxena void
2025*2d1d418eSSumit Saxena mpi3mr_firmware_event_work(void *arg, int pending)
2026*2d1d418eSSumit Saxena {
2027*2d1d418eSSumit Saxena 	struct mpi3mr_fw_event_work *fw_event;
2028*2d1d418eSSumit Saxena 	struct mpi3mr_softc *sc;
2029*2d1d418eSSumit Saxena 
2030*2d1d418eSSumit Saxena 	sc = (struct mpi3mr_softc *)arg;
2031*2d1d418eSSumit Saxena 
2032*2d1d418eSSumit Saxena 	mtx_lock(&sc->fwevt_lock);
2033*2d1d418eSSumit Saxena 	while ((fw_event = TAILQ_FIRST(&sc->cam_sc->ev_queue)) != NULL) {
2034*2d1d418eSSumit Saxena 		TAILQ_REMOVE(&sc->cam_sc->ev_queue, fw_event, ev_link);
2035*2d1d418eSSumit Saxena 		mtx_unlock(&sc->fwevt_lock);
2036*2d1d418eSSumit Saxena 		mpi3mr_fw_work(sc, fw_event);
2037*2d1d418eSSumit Saxena 		mtx_lock(&sc->fwevt_lock);
2038*2d1d418eSSumit Saxena 	}
2039*2d1d418eSSumit Saxena 	mtx_unlock(&sc->fwevt_lock);
2040*2d1d418eSSumit Saxena }
2041*2d1d418eSSumit Saxena 
2042*2d1d418eSSumit Saxena 
2043*2d1d418eSSumit Saxena /*
2044*2d1d418eSSumit Saxena  * mpi3mr_cam_attach - CAM layer registration
2045*2d1d418eSSumit Saxena  * @sc: Adapter reference
2046*2d1d418eSSumit Saxena  *
2047*2d1d418eSSumit Saxena  * This function does simq allocation, cam registration, xpt_bus registration,
2048*2d1d418eSSumit Saxena  * event taskqueue initialization and async event handler registration.
2049*2d1d418eSSumit Saxena  *
2050*2d1d418eSSumit Saxena  * Return: 0 on success and proper error codes on failure
2051*2d1d418eSSumit Saxena  */
2052*2d1d418eSSumit Saxena int
2053*2d1d418eSSumit Saxena mpi3mr_cam_attach(struct mpi3mr_softc *sc)
2054*2d1d418eSSumit Saxena {
2055*2d1d418eSSumit Saxena 	struct mpi3mr_cam_softc *cam_sc;
2056*2d1d418eSSumit Saxena 	cam_status status;
2057*2d1d418eSSumit Saxena 	int unit, error = 0, reqs;
2058*2d1d418eSSumit Saxena 
2059*2d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_XINFO, "Starting CAM Attach\n");
2060*2d1d418eSSumit Saxena 
2061*2d1d418eSSumit Saxena 	cam_sc = malloc(sizeof(struct mpi3mr_cam_softc), M_MPI3MR, M_WAITOK|M_ZERO);
2062*2d1d418eSSumit Saxena 	if (!cam_sc) {
2063*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR,
2064*2d1d418eSSumit Saxena 		    "Failed to allocate memory for controller CAM instance\n");
2065*2d1d418eSSumit Saxena 		return (ENOMEM);
2066*2d1d418eSSumit Saxena 	}
2067*2d1d418eSSumit Saxena 
2068*2d1d418eSSumit Saxena 	cam_sc->maxtargets = sc->facts.max_perids + 1;
2069*2d1d418eSSumit Saxena 
2070*2d1d418eSSumit Saxena 	TAILQ_INIT(&cam_sc->tgt_list);
2071*2d1d418eSSumit Saxena 
2072*2d1d418eSSumit Saxena 	sc->cam_sc = cam_sc;
2073*2d1d418eSSumit Saxena 	cam_sc->sc = sc;
2074*2d1d418eSSumit Saxena 
2075*2d1d418eSSumit Saxena 	reqs = sc->max_host_ios;
2076*2d1d418eSSumit Saxena 
2077*2d1d418eSSumit Saxena 	if ((cam_sc->devq = cam_simq_alloc(reqs)) == NULL) {
2078*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to allocate SIMQ\n");
2079*2d1d418eSSumit Saxena 		error = ENOMEM;
2080*2d1d418eSSumit Saxena 		goto out;
2081*2d1d418eSSumit Saxena 	}
2082*2d1d418eSSumit Saxena 
2083*2d1d418eSSumit Saxena 	unit = device_get_unit(sc->mpi3mr_dev);
2084*2d1d418eSSumit Saxena 	cam_sc->sim = cam_sim_alloc(mpi3mr_cam_action, mpi3mr_cam_poll, "mpi3mr", cam_sc,
2085*2d1d418eSSumit Saxena 	    unit, &sc->mpi3mr_mtx, reqs, reqs, cam_sc->devq);
2086*2d1d418eSSumit Saxena 	if (cam_sc->sim == NULL) {
2087*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to allocate SIM\n");
2088*2d1d418eSSumit Saxena 		error = EINVAL;
2089*2d1d418eSSumit Saxena 		goto out;
2090*2d1d418eSSumit Saxena 	}
2091*2d1d418eSSumit Saxena 
2092*2d1d418eSSumit Saxena 	TAILQ_INIT(&cam_sc->ev_queue);
2093*2d1d418eSSumit Saxena 
2094*2d1d418eSSumit Saxena 	/* Initialize taskqueue for Event Handling */
2095*2d1d418eSSumit Saxena 	TASK_INIT(&cam_sc->ev_task, 0, mpi3mr_firmware_event_work, sc);
2096*2d1d418eSSumit Saxena 	cam_sc->ev_tq = taskqueue_create("mpi3mr_taskq", M_NOWAIT | M_ZERO,
2097*2d1d418eSSumit Saxena 	    taskqueue_thread_enqueue, &cam_sc->ev_tq);
2098*2d1d418eSSumit Saxena 	taskqueue_start_threads(&cam_sc->ev_tq, 1, PRIBIO, "%s taskq",
2099*2d1d418eSSumit Saxena 	    device_get_nameunit(sc->mpi3mr_dev));
2100*2d1d418eSSumit Saxena 
2101*2d1d418eSSumit Saxena 	mtx_lock(&sc->mpi3mr_mtx);
2102*2d1d418eSSumit Saxena 
2103*2d1d418eSSumit Saxena 	/*
2104*2d1d418eSSumit Saxena 	 * XXX There should be a bus for every port on the adapter, but since
2105*2d1d418eSSumit Saxena 	 * we're just going to fake the topology for now, we'll pretend that
2106*2d1d418eSSumit Saxena 	 * everything is just a target on a single bus.
2107*2d1d418eSSumit Saxena 	 */
2108*2d1d418eSSumit Saxena 	if ((error = xpt_bus_register(cam_sc->sim, sc->mpi3mr_dev, 0)) != 0) {
2109*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR,
2110*2d1d418eSSumit Saxena 		    "Error 0x%x registering SCSI bus\n", error);
2111*2d1d418eSSumit Saxena 		mtx_unlock(&sc->mpi3mr_mtx);
2112*2d1d418eSSumit Saxena 		goto out;
2113*2d1d418eSSumit Saxena 	}
2114*2d1d418eSSumit Saxena 
2115*2d1d418eSSumit Saxena 	/*
2116*2d1d418eSSumit Saxena 	 * Assume that discovery events will start right away.
2117*2d1d418eSSumit Saxena 	 *
2118*2d1d418eSSumit Saxena 	 * Hold off boot until discovery is complete.
2119*2d1d418eSSumit Saxena 	 */
2120*2d1d418eSSumit Saxena 	cam_sc->flags |= MPI3MRSAS_IN_STARTUP | MPI3MRSAS_IN_DISCOVERY;
2121*2d1d418eSSumit Saxena 	sc->cam_sc->startup_refcount = 0;
2122*2d1d418eSSumit Saxena 	mpi3mr_startup_increment(cam_sc);
2123*2d1d418eSSumit Saxena 
2124*2d1d418eSSumit Saxena 	callout_init(&cam_sc->discovery_callout, 1 /*mpsafe*/);
2125*2d1d418eSSumit Saxena 
2126*2d1d418eSSumit Saxena 	/*
2127*2d1d418eSSumit Saxena 	 * Register for async events so we can determine the EEDP
2128*2d1d418eSSumit Saxena 	 * capabilities of devices.
2129*2d1d418eSSumit Saxena 	 */
2130*2d1d418eSSumit Saxena 	status = xpt_create_path(&cam_sc->path, /*periph*/NULL,
2131*2d1d418eSSumit Saxena 	    cam_sim_path(sc->cam_sc->sim), CAM_TARGET_WILDCARD,
2132*2d1d418eSSumit Saxena 	    CAM_LUN_WILDCARD);
2133*2d1d418eSSumit Saxena 	if (status != CAM_REQ_CMP) {
2134*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_ERROR,
2135*2d1d418eSSumit Saxena 		    "Error 0x%x creating sim path\n", status);
2136*2d1d418eSSumit Saxena 		cam_sc->path = NULL;
2137*2d1d418eSSumit Saxena 	}
2138*2d1d418eSSumit Saxena 
2139*2d1d418eSSumit Saxena 	if (status != CAM_REQ_CMP) {
2140*2d1d418eSSumit Saxena 		/*
2141*2d1d418eSSumit Saxena 		 * EEDP use is the exception, not the rule.
2142*2d1d418eSSumit Saxena 		 * Warn the user, but do not fail to attach.
2143*2d1d418eSSumit Saxena 		 */
2144*2d1d418eSSumit Saxena 		mpi3mr_dprint(sc, MPI3MR_INFO, "EEDP capabilities disabled.\n");
2145*2d1d418eSSumit Saxena 	}
2146*2d1d418eSSumit Saxena 
2147*2d1d418eSSumit Saxena 	mtx_unlock(&sc->mpi3mr_mtx);
2148*2d1d418eSSumit Saxena 
2149*2d1d418eSSumit Saxena 	error = mpi3mr_register_events(sc);
2150*2d1d418eSSumit Saxena 
2151*2d1d418eSSumit Saxena out:
2152*2d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_XINFO, "%s Exiting CAM attach, error: 0x%x n", __func__, error);
2153*2d1d418eSSumit Saxena 	return (error);
2154*2d1d418eSSumit Saxena }
2155*2d1d418eSSumit Saxena 
2156*2d1d418eSSumit Saxena int
2157*2d1d418eSSumit Saxena mpi3mr_cam_detach(struct mpi3mr_softc *sc)
2158*2d1d418eSSumit Saxena {
2159*2d1d418eSSumit Saxena 	struct mpi3mr_cam_softc *cam_sc;
2160*2d1d418eSSumit Saxena 	struct mpi3mr_target *target;
2161*2d1d418eSSumit Saxena 
2162*2d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_XINFO, "%s, Starting CAM detach\n", __func__);
2163*2d1d418eSSumit Saxena 	if (sc->cam_sc == NULL)
2164*2d1d418eSSumit Saxena 		return (0);
2165*2d1d418eSSumit Saxena 
2166*2d1d418eSSumit Saxena 	cam_sc = sc->cam_sc;
2167*2d1d418eSSumit Saxena 
2168*2d1d418eSSumit Saxena 	mpi3mr_freeup_events(sc);
2169*2d1d418eSSumit Saxena 
2170*2d1d418eSSumit Saxena 	/*
2171*2d1d418eSSumit Saxena 	 * Drain and free the event handling taskqueue with the lock
2172*2d1d418eSSumit Saxena 	 * unheld so that any parallel processing tasks drain properly
2173*2d1d418eSSumit Saxena 	 * without deadlocking.
2174*2d1d418eSSumit Saxena 	 */
2175*2d1d418eSSumit Saxena 	if (cam_sc->ev_tq != NULL)
2176*2d1d418eSSumit Saxena 		taskqueue_free(cam_sc->ev_tq);
2177*2d1d418eSSumit Saxena 
2178*2d1d418eSSumit Saxena 	mtx_lock(&sc->mpi3mr_mtx);
2179*2d1d418eSSumit Saxena 
2180*2d1d418eSSumit Saxena 	while (cam_sc->startup_refcount != 0)
2181*2d1d418eSSumit Saxena 		mpi3mr_startup_decrement(cam_sc);
2182*2d1d418eSSumit Saxena 
2183*2d1d418eSSumit Saxena 	/* Deregister our async handler */
2184*2d1d418eSSumit Saxena 	if (cam_sc->path != NULL) {
2185*2d1d418eSSumit Saxena 		xpt_free_path(cam_sc->path);
2186*2d1d418eSSumit Saxena 		cam_sc->path = NULL;
2187*2d1d418eSSumit Saxena 	}
2188*2d1d418eSSumit Saxena 
2189*2d1d418eSSumit Saxena 	if (cam_sc->flags & MPI3MRSAS_IN_STARTUP)
2190*2d1d418eSSumit Saxena 		xpt_release_simq(cam_sc->sim, 1);
2191*2d1d418eSSumit Saxena 
2192*2d1d418eSSumit Saxena 	if (cam_sc->sim != NULL) {
2193*2d1d418eSSumit Saxena 		xpt_bus_deregister(cam_sim_path(cam_sc->sim));
2194*2d1d418eSSumit Saxena 		cam_sim_free(cam_sc->sim, FALSE);
2195*2d1d418eSSumit Saxena 	}
2196*2d1d418eSSumit Saxena 
2197*2d1d418eSSumit Saxena 	mtx_unlock(&sc->mpi3mr_mtx);
2198*2d1d418eSSumit Saxena 
2199*2d1d418eSSumit Saxena 	if (cam_sc->devq != NULL)
2200*2d1d418eSSumit Saxena 		cam_simq_free(cam_sc->devq);
2201*2d1d418eSSumit Saxena 
2202*2d1d418eSSumit Saxena get_target:
2203*2d1d418eSSumit Saxena 	mtx_lock_spin(&sc->target_lock);
2204*2d1d418eSSumit Saxena  	TAILQ_FOREACH(target, &cam_sc->tgt_list, tgt_next) {
2205*2d1d418eSSumit Saxena  		TAILQ_REMOVE(&sc->cam_sc->tgt_list, target, tgt_next);
2206*2d1d418eSSumit Saxena 		mtx_unlock_spin(&sc->target_lock);
2207*2d1d418eSSumit Saxena 		goto out_tgt_free;
2208*2d1d418eSSumit Saxena 	}
2209*2d1d418eSSumit Saxena 	mtx_unlock_spin(&sc->target_lock);
2210*2d1d418eSSumit Saxena out_tgt_free:
2211*2d1d418eSSumit Saxena 	if (target) {
2212*2d1d418eSSumit Saxena 		free(target, M_MPI3MR);
2213*2d1d418eSSumit Saxena 		target = NULL;
2214*2d1d418eSSumit Saxena 		goto get_target;
2215*2d1d418eSSumit Saxena  	}
2216*2d1d418eSSumit Saxena 
2217*2d1d418eSSumit Saxena 	free(cam_sc, M_MPI3MR);
2218*2d1d418eSSumit Saxena 	sc->cam_sc = NULL;
2219*2d1d418eSSumit Saxena 
2220*2d1d418eSSumit Saxena 	mpi3mr_dprint(sc, MPI3MR_XINFO, "%s, Exiting CAM detach\n", __func__);
2221*2d1d418eSSumit Saxena 	return (0);
2222*2d1d418eSSumit Saxena }
2223