xref: /freebsd/sys/dev/mps/mps_sas.c (revision 8c4ee0b22c98fc1e208dd133f617bd329cd10728)
1d3c7b9a0SKenneth D. Merry /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
3718cf2ccSPedro F. Giffuni  *
4d3c7b9a0SKenneth D. Merry  * Copyright (c) 2009 Yahoo! Inc.
5ef065d89SStephen McConnell  * Copyright (c) 2011-2015 LSI Corp.
6ef065d89SStephen McConnell  * Copyright (c) 2013-2015 Avago Technologies
7d043c564SKenneth D. Merry  * All rights reserved.
8d043c564SKenneth D. Merry  *
9d043c564SKenneth D. Merry  * Redistribution and use in source and binary forms, with or without
10d043c564SKenneth D. Merry  * modification, are permitted provided that the following conditions
11d043c564SKenneth D. Merry  * are met:
12d043c564SKenneth D. Merry  * 1. Redistributions of source code must retain the above copyright
13d043c564SKenneth D. Merry  *    notice, this list of conditions and the following disclaimer.
14d043c564SKenneth D. Merry  * 2. Redistributions in binary form must reproduce the above copyright
15d043c564SKenneth D. Merry  *    notice, this list of conditions and the following disclaimer in the
16d043c564SKenneth D. Merry  *    documentation and/or other materials provided with the distribution.
17d043c564SKenneth D. Merry  *
18d043c564SKenneth D. Merry  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19d043c564SKenneth D. Merry  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20d043c564SKenneth D. Merry  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21d043c564SKenneth D. Merry  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22d043c564SKenneth D. Merry  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23d043c564SKenneth D. Merry  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24d043c564SKenneth D. Merry  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25d043c564SKenneth D. Merry  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26d043c564SKenneth D. Merry  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27d043c564SKenneth D. Merry  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28d043c564SKenneth D. Merry  * SUCH DAMAGE.
29d043c564SKenneth D. Merry  *
30ef065d89SStephen McConnell  * Avago Technologies (LSI) MPT-Fusion Host Adapter FreeBSD
31d043c564SKenneth D. Merry  */
32d3c7b9a0SKenneth D. Merry 
33d3c7b9a0SKenneth D. Merry #include <sys/cdefs.h>
34ef065d89SStephen McConnell /* Communications core for Avago Technologies (LSI) MPT2 */
35d3c7b9a0SKenneth D. Merry 
36d043c564SKenneth D. Merry /* TODO Move headers to mpsvar */
37d3c7b9a0SKenneth D. Merry #include <sys/types.h>
38d3c7b9a0SKenneth D. Merry #include <sys/param.h>
39d3c7b9a0SKenneth D. Merry #include <sys/systm.h>
40d3c7b9a0SKenneth D. Merry #include <sys/kernel.h>
41d3c7b9a0SKenneth D. Merry #include <sys/selinfo.h>
42d3c7b9a0SKenneth D. Merry #include <sys/module.h>
43d3c7b9a0SKenneth D. Merry #include <sys/bus.h>
44d3c7b9a0SKenneth D. Merry #include <sys/conf.h>
45d3c7b9a0SKenneth D. Merry #include <sys/bio.h>
46d3c7b9a0SKenneth D. Merry #include <sys/malloc.h>
47d3c7b9a0SKenneth D. Merry #include <sys/uio.h>
48d3c7b9a0SKenneth D. Merry #include <sys/sysctl.h>
4906e79492SKenneth D. Merry #include <sys/endian.h>
50d043c564SKenneth D. Merry #include <sys/queue.h>
51d043c564SKenneth D. Merry #include <sys/kthread.h>
52d043c564SKenneth D. Merry #include <sys/taskqueue.h>
53d043c564SKenneth D. Merry #include <sys/sbuf.h>
54d3c7b9a0SKenneth D. Merry 
55d3c7b9a0SKenneth D. Merry #include <machine/bus.h>
56d3c7b9a0SKenneth D. Merry #include <machine/resource.h>
57d3c7b9a0SKenneth D. Merry #include <sys/rman.h>
58d3c7b9a0SKenneth D. Merry 
59d043c564SKenneth D. Merry #include <machine/stdarg.h>
60d043c564SKenneth D. Merry 
61d3c7b9a0SKenneth D. Merry #include <cam/cam.h>
62d3c7b9a0SKenneth D. Merry #include <cam/cam_ccb.h>
63d043c564SKenneth D. Merry #include <cam/cam_xpt.h>
64d3c7b9a0SKenneth D. Merry #include <cam/cam_debug.h>
65d3c7b9a0SKenneth D. Merry #include <cam/cam_sim.h>
66d3c7b9a0SKenneth D. Merry #include <cam/cam_xpt_sim.h>
67d3c7b9a0SKenneth D. Merry #include <cam/cam_xpt_periph.h>
68d3c7b9a0SKenneth D. Merry #include <cam/cam_periph.h>
69d3c7b9a0SKenneth D. Merry #include <cam/scsi/scsi_all.h>
70d3c7b9a0SKenneth D. Merry #include <cam/scsi/scsi_message.h>
7106e79492SKenneth D. Merry #include <cam/scsi/smp_all.h>
72d3c7b9a0SKenneth D. Merry 
73d3c7b9a0SKenneth D. Merry #include <dev/mps/mpi/mpi2_type.h>
74d3c7b9a0SKenneth D. Merry #include <dev/mps/mpi/mpi2.h>
75d3c7b9a0SKenneth D. Merry #include <dev/mps/mpi/mpi2_ioc.h>
76d3c7b9a0SKenneth D. Merry #include <dev/mps/mpi/mpi2_sas.h>
77d3c7b9a0SKenneth D. Merry #include <dev/mps/mpi/mpi2_cnfg.h>
78d3c7b9a0SKenneth D. Merry #include <dev/mps/mpi/mpi2_init.h>
79d043c564SKenneth D. Merry #include <dev/mps/mpi/mpi2_tool.h>
80d043c564SKenneth D. Merry #include <dev/mps/mps_ioctl.h>
81d3c7b9a0SKenneth D. Merry #include <dev/mps/mpsvar.h>
82d3c7b9a0SKenneth D. Merry #include <dev/mps/mps_table.h>
83d043c564SKenneth D. Merry #include <dev/mps/mps_sas.h>
84d3c7b9a0SKenneth D. Merry 
85d043c564SKenneth D. Merry /*
86d043c564SKenneth D. Merry  * static array to check SCSI OpCode for EEDP protection bits
87d043c564SKenneth D. Merry  */
88d043c564SKenneth D. Merry #define	PRO_R MPI2_SCSIIO_EEDPFLAGS_CHECK_REMOVE_OP
89d043c564SKenneth D. Merry #define	PRO_W MPI2_SCSIIO_EEDPFLAGS_INSERT_OP
90d043c564SKenneth D. Merry #define	PRO_V MPI2_SCSIIO_EEDPFLAGS_INSERT_OP
91d043c564SKenneth D. Merry static uint8_t op_code_prot[256] = {
92d043c564SKenneth D. Merry 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
93d043c564SKenneth D. Merry 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
94d043c564SKenneth D. Merry 	0, 0, 0, 0, 0, 0, 0, 0, PRO_R, 0, PRO_W, 0, 0, 0, PRO_W, PRO_V,
95d043c564SKenneth D. Merry 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
96d043c564SKenneth D. Merry 	0, PRO_W, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
97d043c564SKenneth D. Merry 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
98d043c564SKenneth D. Merry 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
99d043c564SKenneth D. Merry 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
100d043c564SKenneth D. Merry 	0, 0, 0, 0, 0, 0, 0, 0, PRO_R, 0, PRO_W, 0, 0, 0, PRO_W, PRO_V,
101d043c564SKenneth D. Merry 	0, 0, 0, PRO_W, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
102d043c564SKenneth D. Merry 	0, 0, 0, 0, 0, 0, 0, 0, PRO_R, 0, PRO_W, 0, 0, 0, PRO_W, PRO_V,
103d043c564SKenneth D. Merry 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
104d043c564SKenneth D. Merry 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
105d043c564SKenneth D. Merry 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
106d043c564SKenneth D. Merry 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
107d043c564SKenneth D. Merry 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
108d043c564SKenneth D. Merry };
109d3c7b9a0SKenneth D. Merry 
110d043c564SKenneth D. Merry MALLOC_DEFINE(M_MPSSAS, "MPSSAS", "MPS SAS memory");
111d043c564SKenneth D. Merry 
112d3c7b9a0SKenneth D. Merry static void mpssas_remove_device(struct mps_softc *, struct mps_command *);
113d3c7b9a0SKenneth D. Merry static void mpssas_remove_complete(struct mps_softc *, struct mps_command *);
114d3c7b9a0SKenneth D. Merry static void mpssas_action(struct cam_sim *sim, union ccb *ccb);
115d3c7b9a0SKenneth D. Merry static void mpssas_poll(struct cam_sim *sim);
116ef065d89SStephen McConnell static int mpssas_send_abort(struct mps_softc *sc, struct mps_command *tm,
117ef065d89SStephen McConnell     struct mps_command *cm);
118d3c7b9a0SKenneth D. Merry static void mpssas_scsiio_timeout(void *data);
119d3c7b9a0SKenneth D. Merry static void mpssas_abort_complete(struct mps_softc *sc, struct mps_command *cm);
120d043c564SKenneth D. Merry static void mpssas_direct_drive_io(struct mpssas_softc *sassc,
121d043c564SKenneth D. Merry     struct mps_command *cm, union ccb *ccb);
122d3c7b9a0SKenneth D. Merry static void mpssas_action_scsiio(struct mpssas_softc *, union ccb *);
123d3c7b9a0SKenneth D. Merry static void mpssas_scsiio_complete(struct mps_softc *, struct mps_command *);
124d043c564SKenneth D. Merry static void mpssas_action_resetdev(struct mpssas_softc *, union ccb *);
12506e79492SKenneth D. Merry static void mpssas_smpio_complete(struct mps_softc *sc, struct mps_command *cm);
12606e79492SKenneth D. Merry static void mpssas_send_smpcmd(struct mpssas_softc *sassc, union ccb *ccb,
12706e79492SKenneth D. Merry 			       uint64_t sasaddr);
12806e79492SKenneth D. Merry static void mpssas_action_smpio(struct mpssas_softc *sassc, union ccb *ccb);
129d3c7b9a0SKenneth D. Merry static void mpssas_resetdev_complete(struct mps_softc *, struct mps_command *);
130d043c564SKenneth D. Merry static void mpssas_async(void *callback_arg, uint32_t code,
131d043c564SKenneth D. Merry 			 struct cam_path *path, void *arg);
132d043c564SKenneth D. Merry static int mpssas_send_portenable(struct mps_softc *sc);
133d043c564SKenneth D. Merry static void mpssas_portenable_complete(struct mps_softc *sc,
134d043c564SKenneth D. Merry     struct mps_command *cm);
135d3c7b9a0SKenneth D. Merry 
136653c521fSKenneth D. Merry struct mpssas_target *
mpssas_find_target_by_handle(struct mpssas_softc * sassc,int start,uint16_t handle)137d043c564SKenneth D. Merry mpssas_find_target_by_handle(struct mpssas_softc *sassc, int start, uint16_t handle)
138d3c7b9a0SKenneth D. Merry {
139d3c7b9a0SKenneth D. Merry 	struct mpssas_target *target;
140d3c7b9a0SKenneth D. Merry 	int i;
141d3c7b9a0SKenneth D. Merry 
14208235773SScott Long 	for (i = start; i < sassc->maxtargets; i++) {
143d3c7b9a0SKenneth D. Merry 		target = &sassc->targets[i];
144d3c7b9a0SKenneth D. Merry 		if (target->handle == handle)
145d3c7b9a0SKenneth D. Merry 			return (target);
146d3c7b9a0SKenneth D. Merry 	}
147d3c7b9a0SKenneth D. Merry 
148d3c7b9a0SKenneth D. Merry 	return (NULL);
149d3c7b9a0SKenneth D. Merry }
150d3c7b9a0SKenneth D. Merry 
151d043c564SKenneth D. Merry /* we need to freeze the simq during attach and diag reset, to avoid failing
152d043c564SKenneth D. Merry  * commands before device handles have been found by discovery.  Since
153d043c564SKenneth D. Merry  * discovery involves reading config pages and possibly sending commands,
154d043c564SKenneth D. Merry  * discovery actions may continue even after we receive the end of discovery
155d043c564SKenneth D. Merry  * event, so refcount discovery actions instead of assuming we can unfreeze
156d043c564SKenneth D. Merry  * the simq when we get the event.
157d3c7b9a0SKenneth D. Merry  */
158d043c564SKenneth D. Merry void
mpssas_startup_increment(struct mpssas_softc * sassc)159d043c564SKenneth D. Merry mpssas_startup_increment(struct mpssas_softc *sassc)
160d3c7b9a0SKenneth D. Merry {
1611610f95cSScott Long 	MPS_FUNCTRACE(sassc->sc);
1621610f95cSScott Long 
163d043c564SKenneth D. Merry 	if ((sassc->flags & MPSSAS_IN_STARTUP) != 0) {
164d043c564SKenneth D. Merry 		if (sassc->startup_refcount++ == 0) {
165d043c564SKenneth D. Merry 			/* just starting, freeze the simq */
1661610f95cSScott Long 			mps_dprint(sassc->sc, MPS_INIT,
167d043c564SKenneth D. Merry 			    "%s freezing simq\n", __func__);
16837b8d8c4SAlexander Motin 			xpt_hold_boot();
169d043c564SKenneth D. Merry 			xpt_freeze_simq(sassc->sim, 1);
170d043c564SKenneth D. Merry 		}
1711610f95cSScott Long 		mps_dprint(sassc->sc, MPS_INIT, "%s refcount %u\n", __func__,
172d043c564SKenneth D. Merry 		    sassc->startup_refcount);
173d043c564SKenneth D. Merry 	}
174d043c564SKenneth D. Merry }
175d3c7b9a0SKenneth D. Merry 
176d043c564SKenneth D. Merry void
mpssas_release_simq_reinit(struct mpssas_softc * sassc)1777571e7f6SSteven Hartland mpssas_release_simq_reinit(struct mpssas_softc *sassc)
1787571e7f6SSteven Hartland {
1797571e7f6SSteven Hartland 	if (sassc->flags & MPSSAS_QUEUE_FROZEN) {
1807571e7f6SSteven Hartland 		sassc->flags &= ~MPSSAS_QUEUE_FROZEN;
1817571e7f6SSteven Hartland 		xpt_release_simq(sassc->sim, 1);
1827571e7f6SSteven Hartland 		mps_dprint(sassc->sc, MPS_INFO, "Unfreezing SIM queue\n");
1837571e7f6SSteven Hartland 	}
1847571e7f6SSteven Hartland }
1857571e7f6SSteven Hartland 
1867571e7f6SSteven Hartland void
mpssas_startup_decrement(struct mpssas_softc * sassc)187d043c564SKenneth D. Merry mpssas_startup_decrement(struct mpssas_softc *sassc)
188d043c564SKenneth D. Merry {
1891610f95cSScott Long 	MPS_FUNCTRACE(sassc->sc);
1901610f95cSScott Long 
191d043c564SKenneth D. Merry 	if ((sassc->flags & MPSSAS_IN_STARTUP) != 0) {
192d043c564SKenneth D. Merry 		if (--sassc->startup_refcount == 0) {
193d043c564SKenneth D. Merry 			/* finished all discovery-related actions, release
194d043c564SKenneth D. Merry 			 * the simq and rescan for the latest topology.
195d043c564SKenneth D. Merry 			 */
1961610f95cSScott Long 			mps_dprint(sassc->sc, MPS_INIT,
197d043c564SKenneth D. Merry 			    "%s releasing simq\n", __func__);
198d043c564SKenneth D. Merry 			sassc->flags &= ~MPSSAS_IN_STARTUP;
19937b8d8c4SAlexander Motin 			xpt_release_simq(sassc->sim, 1);
200b01773b0SKenneth D. Merry 			xpt_release_boot();
201d043c564SKenneth D. Merry 		}
2021610f95cSScott Long 		mps_dprint(sassc->sc, MPS_INIT, "%s refcount %u\n", __func__,
203d043c564SKenneth D. Merry 		    sassc->startup_refcount);
204d043c564SKenneth D. Merry 	}
205d043c564SKenneth D. Merry }
206d3c7b9a0SKenneth D. Merry 
207b7f1ee79SScott Long /*
208b7f1ee79SScott Long  * The firmware requires us to stop sending commands when we're doing task
209b7f1ee79SScott Long  * management.
210b7f1ee79SScott Long  * XXX The logic for serializing the device has been made lazy and moved to
211b7f1ee79SScott Long  * mpssas_prepare_for_tm().
212d043c564SKenneth D. Merry  */
213d043c564SKenneth D. Merry struct mps_command *
mpssas_alloc_tm(struct mps_softc * sc)214d043c564SKenneth D. Merry mpssas_alloc_tm(struct mps_softc *sc)
215d043c564SKenneth D. Merry {
21646b9415fSScott Long 	MPI2_SCSI_TASK_MANAGE_REQUEST *req;
217d043c564SKenneth D. Merry 	struct mps_command *tm;
218d043c564SKenneth D. Merry 
219d043c564SKenneth D. Merry 	tm = mps_alloc_high_priority_command(sc);
22046b9415fSScott Long 	if (tm == NULL)
22146b9415fSScott Long 		return (NULL);
22246b9415fSScott Long 
22346b9415fSScott Long 	req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req;
22446b9415fSScott Long 	req->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
225d043c564SKenneth D. Merry 	return tm;
226d043c564SKenneth D. Merry }
227d043c564SKenneth D. Merry 
228d043c564SKenneth D. Merry void
mpssas_free_tm(struct mps_softc * sc,struct mps_command * tm)229d043c564SKenneth D. Merry mpssas_free_tm(struct mps_softc *sc, struct mps_command *tm)
230d043c564SKenneth D. Merry {
231d043c564SKenneth D. Merry 	if (tm == NULL)
232d043c564SKenneth D. Merry 		return;
233d043c564SKenneth D. Merry 
234ef065d89SStephen McConnell 	/*
235ef065d89SStephen McConnell 	 * For TM's the devq is frozen for the device.  Unfreeze it here and
236ef065d89SStephen McConnell 	 * free the resources used for freezing the devq.  Must clear the
237ef065d89SStephen McConnell 	 * INRESET flag as well or scsi I/O will not work.
238d043c564SKenneth D. Merry 	 */
239266f97b5SCy Schubert 	if (tm->cm_ccb) {
240db0ac6deSCy Schubert 		mps_dprint(sc, MPS_XINFO | MPS_RECOVERY,
241db0ac6deSCy Schubert 		    "Unfreezing devq for target ID %d\n",
242db0ac6deSCy Schubert 		    tm->cm_targ->tid);
243db0ac6deSCy Schubert 		tm->cm_targ->flags &= ~MPSSAS_TARGET_INRESET;
244ef065d89SStephen McConnell 		xpt_release_devq(tm->cm_ccb->ccb_h.path, 1, TRUE);
245ef065d89SStephen McConnell 		xpt_free_path(tm->cm_ccb->ccb_h.path);
246ef065d89SStephen McConnell 		xpt_free_ccb(tm->cm_ccb);
247ef065d89SStephen McConnell 	}
248d043c564SKenneth D. Merry 
249d043c564SKenneth D. Merry 	mps_free_high_priority_command(sc, tm);
250d043c564SKenneth D. Merry }
251d043c564SKenneth D. Merry 
252d043c564SKenneth D. Merry void
mpssas_rescan_target(struct mps_softc * sc,struct mpssas_target * targ)253d043c564SKenneth D. Merry mpssas_rescan_target(struct mps_softc *sc, struct mpssas_target *targ)
254d043c564SKenneth D. Merry {
255d043c564SKenneth D. Merry 	struct mpssas_softc *sassc = sc->sassc;
256d043c564SKenneth D. Merry 	path_id_t pathid;
257d043c564SKenneth D. Merry 	target_id_t targetid;
258d043c564SKenneth D. Merry 	union ccb *ccb;
259d043c564SKenneth D. Merry 
2601610f95cSScott Long 	MPS_FUNCTRACE(sc);
261d043c564SKenneth D. Merry 	pathid = cam_sim_path(sassc->sim);
262d043c564SKenneth D. Merry 	if (targ == NULL)
263d043c564SKenneth D. Merry 		targetid = CAM_TARGET_WILDCARD;
264d043c564SKenneth D. Merry 	else
265d043c564SKenneth D. Merry 		targetid = targ - sassc->targets;
266d043c564SKenneth D. Merry 
267d043c564SKenneth D. Merry 	/*
268d043c564SKenneth D. Merry 	 * Allocate a CCB and schedule a rescan.
269d043c564SKenneth D. Merry 	 */
270d043c564SKenneth D. Merry 	ccb = xpt_alloc_ccb_nowait();
271d043c564SKenneth D. Merry 	if (ccb == NULL) {
2721610f95cSScott Long 		mps_dprint(sc, MPS_ERROR, "unable to alloc CCB for rescan\n");
273d3c7b9a0SKenneth D. Merry 		return;
274d3c7b9a0SKenneth D. Merry 	}
275d3c7b9a0SKenneth D. Merry 
276e5dfa058SAlexander Motin 	if (xpt_create_path(&ccb->ccb_h.path, NULL, pathid,
277d043c564SKenneth D. Merry 	    targetid, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
2781610f95cSScott Long 		mps_dprint(sc, MPS_ERROR, "unable to create path for rescan\n");
279d043c564SKenneth D. Merry 		xpt_free_ccb(ccb);
280d3c7b9a0SKenneth D. Merry 		return;
281d3c7b9a0SKenneth D. Merry 	}
282d043c564SKenneth D. Merry 
28382e4855cSKenneth D. Merry 	if (targetid == CAM_TARGET_WILDCARD)
284d043c564SKenneth D. Merry 		ccb->ccb_h.func_code = XPT_SCAN_BUS;
28582e4855cSKenneth D. Merry 	else
28682e4855cSKenneth D. Merry 		ccb->ccb_h.func_code = XPT_SCAN_TGT;
28782e4855cSKenneth D. Merry 
288d043c564SKenneth D. Merry 	mps_dprint(sc, MPS_TRACE, "%s targetid %u\n", __func__, targetid);
289b01773b0SKenneth D. Merry 	xpt_rescan(ccb);
290d3c7b9a0SKenneth D. Merry }
291d3c7b9a0SKenneth D. Merry 
292d3c7b9a0SKenneth D. Merry static void
mpssas_log_command(struct mps_command * cm,u_int level,const char * fmt,...)2931610f95cSScott Long mpssas_log_command(struct mps_command *cm, u_int level, const char *fmt, ...)
294d3c7b9a0SKenneth D. Merry {
295d043c564SKenneth D. Merry 	struct sbuf sb;
296d043c564SKenneth D. Merry 	va_list ap;
297a2386b6fSAlexander Motin 	char str[224];
298d3c7b9a0SKenneth D. Merry 
299d043c564SKenneth D. Merry 	if (cm == NULL)
300d3c7b9a0SKenneth D. Merry 		return;
301d043c564SKenneth D. Merry 
30232373512SScott Long 	/* No need to be in here if debugging isn't enabled */
303fe97b88cSAlexander Motin 	if ((cm->cm_sc->mps_debug & level) == 0)
30432373512SScott Long 		return;
30532373512SScott Long 
306d043c564SKenneth D. Merry 	sbuf_new(&sb, str, sizeof(str), 0);
307d043c564SKenneth D. Merry 
308d043c564SKenneth D. Merry 	va_start(ap, fmt);
309d043c564SKenneth D. Merry 
310d043c564SKenneth D. Merry 	if (cm->cm_ccb != NULL) {
311*8c4ee0b2SAlexander Motin 		xpt_path_sbuf(cm->cm_ccb->csio.ccb_h.path, &sb);
312d043c564SKenneth D. Merry 		if (cm->cm_ccb->ccb_h.func_code == XPT_SCSI_IO) {
313d043c564SKenneth D. Merry 			scsi_command_string(&cm->cm_ccb->csio, &sb);
314d043c564SKenneth D. Merry 			sbuf_printf(&sb, "length %d ",
315d043c564SKenneth D. Merry 				    cm->cm_ccb->csio.dxfer_len);
316d3c7b9a0SKenneth D. Merry 		}
317d3c7b9a0SKenneth D. Merry 	}
318d043c564SKenneth D. Merry 	else {
319d043c564SKenneth D. Merry 		sbuf_printf(&sb, "(noperiph:%s%d:%u:%u:%u): ",
320d043c564SKenneth D. Merry 		    cam_sim_name(cm->cm_sc->sassc->sim),
321d043c564SKenneth D. Merry 		    cam_sim_unit(cm->cm_sc->sassc->sim),
322d043c564SKenneth D. Merry 		    cam_sim_bus(cm->cm_sc->sassc->sim),
323d043c564SKenneth D. Merry 		    cm->cm_targ ? cm->cm_targ->tid : 0xFFFFFFFF,
324d043c564SKenneth D. Merry 		    cm->cm_lun);
325d043c564SKenneth D. Merry 	}
326d043c564SKenneth D. Merry 
327d043c564SKenneth D. Merry 	sbuf_printf(&sb, "SMID %u ", cm->cm_desc.Default.SMID);
328d043c564SKenneth D. Merry 	sbuf_vprintf(&sb, fmt, ap);
329d043c564SKenneth D. Merry 	sbuf_finish(&sb);
330c11c484fSScott Long 	mps_print_field(cm->cm_sc, "%s", sbuf_data(&sb));
331d043c564SKenneth D. Merry 
332d043c564SKenneth D. Merry 	va_end(ap);
333d043c564SKenneth D. Merry }
334d043c564SKenneth D. Merry 
335653c521fSKenneth D. Merry static void
mpssas_remove_volume(struct mps_softc * sc,struct mps_command * tm)336653c521fSKenneth D. Merry mpssas_remove_volume(struct mps_softc *sc, struct mps_command *tm)
337653c521fSKenneth D. Merry {
338653c521fSKenneth D. Merry 	MPI2_SCSI_TASK_MANAGE_REPLY *reply;
339653c521fSKenneth D. Merry 	struct mpssas_target *targ;
340653c521fSKenneth D. Merry 	uint16_t handle;
341653c521fSKenneth D. Merry 
3421610f95cSScott Long 	MPS_FUNCTRACE(sc);
343653c521fSKenneth D. Merry 
344653c521fSKenneth D. Merry 	reply = (MPI2_SCSI_TASK_MANAGE_REPLY *)tm->cm_reply;
345653c521fSKenneth D. Merry 	handle = (uint16_t)(uintptr_t)tm->cm_complete_data;
346653c521fSKenneth D. Merry 	targ = tm->cm_targ;
347653c521fSKenneth D. Merry 
348653c521fSKenneth D. Merry 	if (reply == NULL) {
349653c521fSKenneth D. Merry 		/* XXX retry the remove after the diag reset completes? */
3501610f95cSScott Long 		mps_dprint(sc, MPS_FAULT,
351ef065d89SStephen McConnell 		    "%s NULL reply resetting device 0x%04x\n", __func__,
352ef065d89SStephen McConnell 		    handle);
353653c521fSKenneth D. Merry 		mpssas_free_tm(sc, tm);
354d3c7b9a0SKenneth D. Merry 		return;
355d3c7b9a0SKenneth D. Merry 	}
356d3c7b9a0SKenneth D. Merry 
357f4e69c98SStephen McConnell 	if ((le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK) !=
358f4e69c98SStephen McConnell 	    MPI2_IOCSTATUS_SUCCESS) {
359f4e69c98SStephen McConnell 		mps_dprint(sc, MPS_ERROR,
3601610f95cSScott Long 		   "IOCStatus = 0x%x while resetting device 0x%x\n",
361f4e69c98SStephen McConnell 		   le16toh(reply->IOCStatus), handle);
362653c521fSKenneth D. Merry 	}
363653c521fSKenneth D. Merry 
3641610f95cSScott Long 	mps_dprint(sc, MPS_XINFO,
3651610f95cSScott Long 	    "Reset aborted %u commands\n", reply->TerminationCount);
366653c521fSKenneth D. Merry 	mps_free_reply(sc, tm->cm_reply_data);
36796240c89SEitan Adler 	tm->cm_reply = NULL;	/* Ensures the reply won't get re-freed */
368653c521fSKenneth D. Merry 
3691610f95cSScott Long 	mps_dprint(sc, MPS_XINFO,
3701610f95cSScott Long 	    "clearing target %u handle 0x%04x\n", targ->tid, handle);
371653c521fSKenneth D. Merry 
372653c521fSKenneth D. Merry 	/*
373653c521fSKenneth D. Merry 	 * Don't clear target if remove fails because things will get confusing.
374653c521fSKenneth D. Merry 	 * Leave the devname and sasaddr intact so that we know to avoid reusing
375653c521fSKenneth D. Merry 	 * this target id if possible, and so we can assign the same target id
376653c521fSKenneth D. Merry 	 * to this device if it comes back in the future.
377653c521fSKenneth D. Merry 	 */
378f4e69c98SStephen McConnell 	if ((le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK) ==
379f4e69c98SStephen McConnell 	    MPI2_IOCSTATUS_SUCCESS) {
380653c521fSKenneth D. Merry 		targ = tm->cm_targ;
381653c521fSKenneth D. Merry 		targ->handle = 0x0;
382653c521fSKenneth D. Merry 		targ->encl_handle = 0x0;
383653c521fSKenneth D. Merry 		targ->encl_slot = 0x0;
384653c521fSKenneth D. Merry 		targ->exp_dev_handle = 0x0;
385653c521fSKenneth D. Merry 		targ->phy_num = 0x0;
386653c521fSKenneth D. Merry 		targ->linkrate = 0x0;
387653c521fSKenneth D. Merry 		targ->devinfo = 0x0;
388653c521fSKenneth D. Merry 		targ->flags = 0x0;
389653c521fSKenneth D. Merry 	}
390653c521fSKenneth D. Merry 
391653c521fSKenneth D. Merry 	mpssas_free_tm(sc, tm);
392653c521fSKenneth D. Merry }
393653c521fSKenneth D. Merry 
394653c521fSKenneth D. Merry /*
395653c521fSKenneth D. Merry  * No Need to call "MPI2_SAS_OP_REMOVE_DEVICE" For Volume removal.
396653c521fSKenneth D. Merry  * Otherwise Volume Delete is same as Bare Drive Removal.
397653c521fSKenneth D. Merry  */
398653c521fSKenneth D. Merry void
mpssas_prepare_volume_remove(struct mpssas_softc * sassc,uint16_t handle)399653c521fSKenneth D. Merry mpssas_prepare_volume_remove(struct mpssas_softc *sassc, uint16_t handle)
400653c521fSKenneth D. Merry {
401653c521fSKenneth D. Merry 	MPI2_SCSI_TASK_MANAGE_REQUEST *req;
402653c521fSKenneth D. Merry 	struct mps_softc *sc;
40346b9415fSScott Long 	struct mps_command *tm;
404653c521fSKenneth D. Merry 	struct mpssas_target *targ = NULL;
405653c521fSKenneth D. Merry 
4061610f95cSScott Long 	MPS_FUNCTRACE(sassc->sc);
407653c521fSKenneth D. Merry 	sc = sassc->sc;
408653c521fSKenneth D. Merry 
409653c521fSKenneth D. Merry #ifdef WD_SUPPORT
410653c521fSKenneth D. Merry 	/*
411653c521fSKenneth D. Merry 	 * If this is a WD controller, determine if the disk should be exposed
412653c521fSKenneth D. Merry 	 * to the OS or not.  If disk should be exposed, return from this
413653c521fSKenneth D. Merry 	 * function without doing anything.
414653c521fSKenneth D. Merry 	 */
415653c521fSKenneth D. Merry 	if (sc->WD_available && (sc->WD_hide_expose ==
416653c521fSKenneth D. Merry 	    MPS_WD_EXPOSE_ALWAYS)) {
417653c521fSKenneth D. Merry 		return;
418653c521fSKenneth D. Merry 	}
419653c521fSKenneth D. Merry #endif //WD_SUPPORT
420653c521fSKenneth D. Merry 
421653c521fSKenneth D. Merry 	targ = mpssas_find_target_by_handle(sassc, 0, handle);
422653c521fSKenneth D. Merry 	if (targ == NULL) {
423653c521fSKenneth D. Merry 		/* FIXME: what is the action? */
424653c521fSKenneth D. Merry 		/* We don't know about this device? */
4251610f95cSScott Long 		mps_dprint(sc, MPS_ERROR,
4261610f95cSScott Long 		   "%s %d : invalid handle 0x%x \n", __func__,__LINE__, handle);
427653c521fSKenneth D. Merry 		return;
428653c521fSKenneth D. Merry 	}
429653c521fSKenneth D. Merry 
430653c521fSKenneth D. Merry 	targ->flags |= MPSSAS_TARGET_INREMOVAL;
431653c521fSKenneth D. Merry 
43246b9415fSScott Long 	tm = mpssas_alloc_tm(sc);
43346b9415fSScott Long 	if (tm == NULL) {
4341610f95cSScott Long 		mps_dprint(sc, MPS_ERROR,
4351610f95cSScott Long 		    "%s: command alloc failure\n", __func__);
436653c521fSKenneth D. Merry 		return;
437653c521fSKenneth D. Merry 	}
438653c521fSKenneth D. Merry 
439653c521fSKenneth D. Merry 	mpssas_rescan_target(sc, targ);
440653c521fSKenneth D. Merry 
44146b9415fSScott Long 	req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req;
442653c521fSKenneth D. Merry 	req->DevHandle = targ->handle;
443653c521fSKenneth D. Merry 	req->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
444653c521fSKenneth D. Merry 
445653c521fSKenneth D. Merry 	/* SAS Hard Link Reset / SATA Link Reset */
446653c521fSKenneth D. Merry 	req->MsgFlags = MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET;
447653c521fSKenneth D. Merry 
44846b9415fSScott Long 	tm->cm_targ = targ;
44946b9415fSScott Long 	tm->cm_data = NULL;
45046b9415fSScott Long 	tm->cm_complete = mpssas_remove_volume;
45146b9415fSScott Long 	tm->cm_complete_data = (void *)(uintptr_t)handle;
452ef065d89SStephen McConnell 
453ef065d89SStephen McConnell 	mps_dprint(sc, MPS_INFO, "%s: Sending reset for target ID %d\n",
454ef065d89SStephen McConnell 	    __func__, targ->tid);
45546b9415fSScott Long 	mpssas_prepare_for_tm(sc, tm, targ, CAM_LUN_WILDCARD);
456ef065d89SStephen McConnell 
45746b9415fSScott Long 	mps_map_command(sc, tm);
458d3c7b9a0SKenneth D. Merry }
459d3c7b9a0SKenneth D. Merry 
460d3c7b9a0SKenneth D. Merry /*
461d043c564SKenneth D. Merry  * The MPT2 firmware performs debounce on the link to avoid transient link
462d043c564SKenneth D. Merry  * errors and false removals.  When it does decide that link has been lost
463d043c564SKenneth D. Merry  * and a device need to go away, it expects that the host will perform a
464d043c564SKenneth D. Merry  * target reset and then an op remove.  The reset has the side-effect of
465d043c564SKenneth D. Merry  * aborting any outstanding requests for the device, which is required for
466d043c564SKenneth D. Merry  * the op-remove to succeed.  It's not clear if the host should check for
467d043c564SKenneth D. Merry  * the device coming back alive after the reset.
468d3c7b9a0SKenneth D. Merry  */
469d043c564SKenneth D. Merry void
mpssas_prepare_remove(struct mpssas_softc * sassc,uint16_t handle)470d043c564SKenneth D. Merry mpssas_prepare_remove(struct mpssas_softc *sassc, uint16_t handle)
471d3c7b9a0SKenneth D. Merry {
472d3c7b9a0SKenneth D. Merry 	MPI2_SCSI_TASK_MANAGE_REQUEST *req;
473d3c7b9a0SKenneth D. Merry 	struct mps_softc *sc;
474d3c7b9a0SKenneth D. Merry 	struct mps_command *cm;
475d3c7b9a0SKenneth D. Merry 	struct mpssas_target *targ = NULL;
476d3c7b9a0SKenneth D. Merry 
4771610f95cSScott Long 	MPS_FUNCTRACE(sassc->sc);
478d3c7b9a0SKenneth D. Merry 
479d3c7b9a0SKenneth D. Merry 	sc = sassc->sc;
480d3c7b9a0SKenneth D. Merry 
481d043c564SKenneth D. Merry 	targ = mpssas_find_target_by_handle(sassc, 0, handle);
482d043c564SKenneth D. Merry 	if (targ == NULL) {
483d043c564SKenneth D. Merry 		/* FIXME: what is the action? */
484d043c564SKenneth D. Merry 		/* We don't know about this device? */
4851610f95cSScott Long 		mps_dprint(sc, MPS_ERROR,
4861610f95cSScott Long 		    "%s : invalid handle 0x%x \n", __func__, handle);
487d043c564SKenneth D. Merry 		return;
488d043c564SKenneth D. Merry 	}
489d043c564SKenneth D. Merry 
490d043c564SKenneth D. Merry 	targ->flags |= MPSSAS_TARGET_INREMOVAL;
491d043c564SKenneth D. Merry 
492d043c564SKenneth D. Merry 	cm = mpssas_alloc_tm(sc);
493d043c564SKenneth D. Merry 	if (cm == NULL) {
4941610f95cSScott Long 		mps_dprint(sc, MPS_ERROR,
4951610f95cSScott Long 		    "%s: command alloc failure\n", __func__);
496d043c564SKenneth D. Merry 		return;
497d043c564SKenneth D. Merry 	}
498d043c564SKenneth D. Merry 
499653c521fSKenneth D. Merry 	mpssas_rescan_target(sc, targ);
5009866848aSKenneth D. Merry 
501d3c7b9a0SKenneth D. Merry 	req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)cm->cm_req;
502be4aa869SKenneth D. Merry 	req->DevHandle = htole16(targ->handle);
503d3c7b9a0SKenneth D. Merry 	req->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
504d3c7b9a0SKenneth D. Merry 
505d3c7b9a0SKenneth D. Merry 	/* SAS Hard Link Reset / SATA Link Reset */
506d3c7b9a0SKenneth D. Merry 	req->MsgFlags = MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET;
507d3c7b9a0SKenneth D. Merry 
508d3c7b9a0SKenneth D. Merry 	cm->cm_targ = targ;
509d043c564SKenneth D. Merry 	cm->cm_data = NULL;
510d043c564SKenneth D. Merry 	cm->cm_complete = mpssas_remove_device;
511d043c564SKenneth D. Merry 	cm->cm_complete_data = (void *)(uintptr_t)handle;
512ef065d89SStephen McConnell 
513ef065d89SStephen McConnell 	mps_dprint(sc, MPS_INFO, "%s: Sending reset for target ID %d\n",
514ef065d89SStephen McConnell 	    __func__, targ->tid);
515ef065d89SStephen McConnell 	mpssas_prepare_for_tm(sc, cm, targ, CAM_LUN_WILDCARD);
516ef065d89SStephen McConnell 
517d043c564SKenneth D. Merry 	mps_map_command(sc, cm);
518d3c7b9a0SKenneth D. Merry }
519d3c7b9a0SKenneth D. Merry 
520d3c7b9a0SKenneth D. Merry static void
mpssas_remove_device(struct mps_softc * sc,struct mps_command * tm)521d043c564SKenneth D. Merry mpssas_remove_device(struct mps_softc *sc, struct mps_command *tm)
522d3c7b9a0SKenneth D. Merry {
523d3c7b9a0SKenneth D. Merry 	MPI2_SCSI_TASK_MANAGE_REPLY *reply;
524d3c7b9a0SKenneth D. Merry 	MPI2_SAS_IOUNIT_CONTROL_REQUEST *req;
525d3c7b9a0SKenneth D. Merry 	struct mpssas_target *targ;
526d3c7b9a0SKenneth D. Merry 	uint16_t handle;
527d3c7b9a0SKenneth D. Merry 
5281610f95cSScott Long 	MPS_FUNCTRACE(sc);
529d3c7b9a0SKenneth D. Merry 
530d043c564SKenneth D. Merry 	reply = (MPI2_SCSI_TASK_MANAGE_REPLY *)tm->cm_reply;
531d043c564SKenneth D. Merry 	handle = (uint16_t)(uintptr_t)tm->cm_complete_data;
532d043c564SKenneth D. Merry 	targ = tm->cm_targ;
5331476ba40SKenneth D. Merry 
534550e2acdSKenneth D. Merry 	/*
535550e2acdSKenneth D. Merry 	 * Currently there should be no way we can hit this case.  It only
536550e2acdSKenneth D. Merry 	 * happens when we have a failure to allocate chain frames, and
537550e2acdSKenneth D. Merry 	 * task management commands don't have S/G lists.
538550e2acdSKenneth D. Merry 	 */
539d043c564SKenneth D. Merry 	if ((tm->cm_flags & MPS_CM_FLAGS_ERROR_MASK) != 0) {
5401610f95cSScott Long 		mps_dprint(sc, MPS_ERROR,
5411610f95cSScott Long 		    "%s: cm_flags = %#x for remove of handle %#04x! "
542d043c564SKenneth D. Merry 		    "This should not happen!\n", __func__, tm->cm_flags,
543550e2acdSKenneth D. Merry 		    handle);
544d043c564SKenneth D. Merry 	}
545d043c564SKenneth D. Merry 
546d043c564SKenneth D. Merry 	if (reply == NULL) {
547d043c564SKenneth D. Merry 		/* XXX retry the remove after the diag reset completes? */
5481610f95cSScott Long 		mps_dprint(sc, MPS_FAULT,
549f4e69c98SStephen McConnell 		    "%s NULL reply resetting device 0x%04x\n", __func__,
550f4e69c98SStephen McConnell 		    handle);
551d043c564SKenneth D. Merry 		mpssas_free_tm(sc, tm);
552550e2acdSKenneth D. Merry 		return;
553550e2acdSKenneth D. Merry 	}
554550e2acdSKenneth D. Merry 
555f4e69c98SStephen McConnell 	if ((le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK) !=
556f4e69c98SStephen McConnell 	    MPI2_IOCSTATUS_SUCCESS) {
557f4e69c98SStephen McConnell 		mps_dprint(sc, MPS_ERROR,
5581610f95cSScott Long 		   "IOCStatus = 0x%x while resetting device 0x%x\n",
559be4aa869SKenneth D. Merry 		   le16toh(reply->IOCStatus), handle);
560d3c7b9a0SKenneth D. Merry 	}
561d3c7b9a0SKenneth D. Merry 
5621610f95cSScott Long 	mps_dprint(sc, MPS_XINFO, "Reset aborted %u commands\n",
563be4aa869SKenneth D. Merry 	    le32toh(reply->TerminationCount));
564d043c564SKenneth D. Merry 	mps_free_reply(sc, tm->cm_reply_data);
56596240c89SEitan Adler 	tm->cm_reply = NULL;	/* Ensures the reply won't get re-freed */
566d3c7b9a0SKenneth D. Merry 
567d3c7b9a0SKenneth D. Merry 	/* Reuse the existing command */
568d043c564SKenneth D. Merry 	req = (MPI2_SAS_IOUNIT_CONTROL_REQUEST *)tm->cm_req;
5699866848aSKenneth D. Merry 	memset(req, 0, sizeof(*req));
570d3c7b9a0SKenneth D. Merry 	req->Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL;
571d3c7b9a0SKenneth D. Merry 	req->Operation = MPI2_SAS_OP_REMOVE_DEVICE;
572be4aa869SKenneth D. Merry 	req->DevHandle = htole16(handle);
573d043c564SKenneth D. Merry 	tm->cm_data = NULL;
574d043c564SKenneth D. Merry 	tm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
575d043c564SKenneth D. Merry 	tm->cm_complete = mpssas_remove_complete;
576d043c564SKenneth D. Merry 	tm->cm_complete_data = (void *)(uintptr_t)handle;
577d3c7b9a0SKenneth D. Merry 
5784c1cdd4aSWarner Losh 	/*
5794c1cdd4aSWarner Losh 	 * Wait to send the REMOVE_DEVICE until all the commands have cleared.
5804c1cdd4aSWarner Losh 	 * They should be aborted or time out and we'll kick thus off there
5814c1cdd4aSWarner Losh 	 * if so.
5824c1cdd4aSWarner Losh 	 */
5834c1cdd4aSWarner Losh 	if (TAILQ_FIRST(&targ->commands) == NULL) {
584ca420b4eSWarner Losh 		mps_dprint(sc, MPS_INFO,
585ca420b4eSWarner Losh 		    "No pending commands: starting remove_device target %u handle 0x%04x\n",
586ca420b4eSWarner Losh 		    targ->tid, handle);
587d043c564SKenneth D. Merry 		mps_map_command(sc, tm);
5884c1cdd4aSWarner Losh 		targ->pending_remove_tm = NULL;
5894c1cdd4aSWarner Losh 	} else {
5904c1cdd4aSWarner Losh 		targ->pending_remove_tm = tm;
5914c1cdd4aSWarner Losh 	}
5924c1cdd4aSWarner Losh 
5931610f95cSScott Long 	mps_dprint(sc, MPS_XINFO, "clearing target %u handle 0x%04x\n",
594d043c564SKenneth D. Merry 		   targ->tid, handle);
595d3c7b9a0SKenneth D. Merry }
596d3c7b9a0SKenneth D. Merry 
597d3c7b9a0SKenneth D. Merry static void
mpssas_remove_complete(struct mps_softc * sc,struct mps_command * tm)598d043c564SKenneth D. Merry mpssas_remove_complete(struct mps_softc *sc, struct mps_command *tm)
599d3c7b9a0SKenneth D. Merry {
600d3c7b9a0SKenneth D. Merry 	MPI2_SAS_IOUNIT_CONTROL_REPLY *reply;
601d043c564SKenneth D. Merry 	uint16_t handle;
602d043c564SKenneth D. Merry 	struct mpssas_target *targ;
603be4aa869SKenneth D. Merry 	struct mpssas_lun *lun;
604d3c7b9a0SKenneth D. Merry 
6051610f95cSScott Long 	MPS_FUNCTRACE(sc);
606d3c7b9a0SKenneth D. Merry 
607d043c564SKenneth D. Merry 	reply = (MPI2_SAS_IOUNIT_CONTROL_REPLY *)tm->cm_reply;
608d043c564SKenneth D. Merry 	handle = (uint16_t)(uintptr_t)tm->cm_complete_data;
6094c1cdd4aSWarner Losh 	targ = tm->cm_targ;
6104c1cdd4aSWarner Losh 
6114c1cdd4aSWarner Losh 	/*
6124c1cdd4aSWarner Losh 	 * At this point, we should have no pending commands for the target.
6134c1cdd4aSWarner Losh 	 * The remove target has just completed.
6144c1cdd4aSWarner Losh 	 */
6154c1cdd4aSWarner Losh 	KASSERT(TAILQ_FIRST(&targ->commands) == NULL,
6164c1cdd4aSWarner Losh 	    ("%s: no commands should be pending\n", __func__));
6174c1cdd4aSWarner Losh 
618d043c564SKenneth D. Merry 	/*
619d043c564SKenneth D. Merry 	 * Currently there should be no way we can hit this case.  It only
620d043c564SKenneth D. Merry 	 * happens when we have a failure to allocate chain frames, and
621d043c564SKenneth D. Merry 	 * task management commands don't have S/G lists.
622d043c564SKenneth D. Merry 	 */
623d043c564SKenneth D. Merry 	if ((tm->cm_flags & MPS_CM_FLAGS_ERROR_MASK) != 0) {
6241610f95cSScott Long 		mps_dprint(sc, MPS_XINFO,
6251610f95cSScott Long 			   "%s: cm_flags = %#x for remove of handle %#04x! "
626d043c564SKenneth D. Merry 			   "This should not happen!\n", __func__, tm->cm_flags,
627d043c564SKenneth D. Merry 			   handle);
628d043c564SKenneth D. Merry 		mpssas_free_tm(sc, tm);
629d043c564SKenneth D. Merry 		return;
630d3c7b9a0SKenneth D. Merry 	}
631d3c7b9a0SKenneth D. Merry 
632d043c564SKenneth D. Merry 	if (reply == NULL) {
633d043c564SKenneth D. Merry 		/* most likely a chip reset */
6341610f95cSScott Long 		mps_dprint(sc, MPS_FAULT,
6351610f95cSScott Long 		    "%s NULL reply removing device 0x%04x\n", __func__, handle);
636d043c564SKenneth D. Merry 		mpssas_free_tm(sc, tm);
637d043c564SKenneth D. Merry 		return;
638d3c7b9a0SKenneth D. Merry 	}
639d3c7b9a0SKenneth D. Merry 
6401610f95cSScott Long 	mps_dprint(sc, MPS_XINFO,
6411610f95cSScott Long 	    "%s on handle 0x%04x, IOCStatus= 0x%x\n", __func__,
642be4aa869SKenneth D. Merry 	    handle, le16toh(reply->IOCStatus));
643d043c564SKenneth D. Merry 
644d043c564SKenneth D. Merry 	/*
645d043c564SKenneth D. Merry 	 * Don't clear target if remove fails because things will get confusing.
646d043c564SKenneth D. Merry 	 * Leave the devname and sasaddr intact so that we know to avoid reusing
647d043c564SKenneth D. Merry 	 * this target id if possible, and so we can assign the same target id
648d043c564SKenneth D. Merry 	 * to this device if it comes back in the future.
649d043c564SKenneth D. Merry 	 */
650f4e69c98SStephen McConnell 	if ((le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK) ==
651f4e69c98SStephen McConnell 	    MPI2_IOCSTATUS_SUCCESS) {
652d043c564SKenneth D. Merry 		targ->handle = 0x0;
653d043c564SKenneth D. Merry 		targ->encl_handle = 0x0;
654d043c564SKenneth D. Merry 		targ->encl_slot = 0x0;
655d043c564SKenneth D. Merry 		targ->exp_dev_handle = 0x0;
656d043c564SKenneth D. Merry 		targ->phy_num = 0x0;
657d043c564SKenneth D. Merry 		targ->linkrate = 0x0;
658d043c564SKenneth D. Merry 		targ->devinfo = 0x0;
659653c521fSKenneth D. Merry 		targ->flags = 0x0;
660be4aa869SKenneth D. Merry 
661be4aa869SKenneth D. Merry 		while(!SLIST_EMPTY(&targ->luns)) {
662be4aa869SKenneth D. Merry 			lun = SLIST_FIRST(&targ->luns);
663be4aa869SKenneth D. Merry 			SLIST_REMOVE_HEAD(&targ->luns, lun_link);
664be4aa869SKenneth D. Merry 			free(lun, M_MPT2);
665d3c7b9a0SKenneth D. Merry 		}
666be4aa869SKenneth D. Merry 	}
667be4aa869SKenneth D. Merry 
668d043c564SKenneth D. Merry 	mpssas_free_tm(sc, tm);
669d3c7b9a0SKenneth D. Merry }
670d3c7b9a0SKenneth D. Merry 
671d3c7b9a0SKenneth D. Merry static int
mpssas_register_events(struct mps_softc * sc)672d3c7b9a0SKenneth D. Merry mpssas_register_events(struct mps_softc *sc)
673d3c7b9a0SKenneth D. Merry {
674be4aa869SKenneth D. Merry 	u32 events[MPI2_EVENT_NOTIFY_EVENTMASK_WORDS];
675d3c7b9a0SKenneth D. Merry 
676d3c7b9a0SKenneth D. Merry 	bzero(events, 16);
677d3c7b9a0SKenneth D. Merry 	setbit(events, MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE);
678d3c7b9a0SKenneth D. Merry 	setbit(events, MPI2_EVENT_SAS_DISCOVERY);
679d3c7b9a0SKenneth D. Merry 	setbit(events, MPI2_EVENT_SAS_BROADCAST_PRIMITIVE);
680d3c7b9a0SKenneth D. Merry 	setbit(events, MPI2_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE);
681d3c7b9a0SKenneth D. Merry 	setbit(events, MPI2_EVENT_SAS_INIT_TABLE_OVERFLOW);
682d3c7b9a0SKenneth D. Merry 	setbit(events, MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST);
683d3c7b9a0SKenneth D. Merry 	setbit(events, MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE);
684d043c564SKenneth D. Merry 	setbit(events, MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST);
685d043c564SKenneth D. Merry 	setbit(events, MPI2_EVENT_IR_VOLUME);
686d043c564SKenneth D. Merry 	setbit(events, MPI2_EVENT_IR_PHYSICAL_DISK);
687d043c564SKenneth D. Merry 	setbit(events, MPI2_EVENT_IR_OPERATION_STATUS);
688d043c564SKenneth D. Merry 	setbit(events, MPI2_EVENT_LOG_ENTRY_ADDED);
689d3c7b9a0SKenneth D. Merry 
690d3c7b9a0SKenneth D. Merry 	mps_register_events(sc, events, mpssas_evt_handler, NULL,
691d3c7b9a0SKenneth D. Merry 	    &sc->sassc->mpssas_eh);
692d3c7b9a0SKenneth D. Merry 
693d3c7b9a0SKenneth D. Merry 	return (0);
694d3c7b9a0SKenneth D. Merry }
695d3c7b9a0SKenneth D. Merry 
696d3c7b9a0SKenneth D. Merry int
mps_attach_sas(struct mps_softc * sc)697d3c7b9a0SKenneth D. Merry mps_attach_sas(struct mps_softc *sc)
698d3c7b9a0SKenneth D. Merry {
699d3c7b9a0SKenneth D. Merry 	struct mpssas_softc *sassc;
700d043c564SKenneth D. Merry 	cam_status status;
70162a09ee9SAlexander Motin 	int unit, error = 0, reqs;
702d3c7b9a0SKenneth D. Merry 
7031610f95cSScott Long 	MPS_FUNCTRACE(sc);
704757ff642SScott Long 	mps_dprint(sc, MPS_INIT, "%s entered\n", __func__);
705d3c7b9a0SKenneth D. Merry 
706d3c7b9a0SKenneth D. Merry 	sassc = malloc(sizeof(struct mpssas_softc), M_MPT2, M_WAITOK|M_ZERO);
70708235773SScott Long 
70808235773SScott Long 	/*
70908235773SScott Long 	 * XXX MaxTargets could change during a reinit.  Since we don't
71008235773SScott Long 	 * resize the targets[] array during such an event, cache the value
71108235773SScott Long 	 * of MaxTargets here so that we don't get into trouble later.  This
71208235773SScott Long 	 * should move into the reinit logic.
71308235773SScott Long 	 */
714635e58c7SStephen McConnell 	sassc->maxtargets = sc->facts->MaxTargets + sc->facts->MaxVolumes;
715d3c7b9a0SKenneth D. Merry 	sassc->targets = malloc(sizeof(struct mpssas_target) *
71608235773SScott Long 	    sassc->maxtargets, M_MPT2, M_WAITOK|M_ZERO);
717d3c7b9a0SKenneth D. Merry 	sc->sassc = sassc;
718d3c7b9a0SKenneth D. Merry 	sassc->sc = sc;
719d3c7b9a0SKenneth D. Merry 
72062a09ee9SAlexander Motin 	reqs = sc->num_reqs - sc->num_prireqs - 1;
72162a09ee9SAlexander Motin 	if ((sassc->devq = cam_simq_alloc(reqs)) == NULL) {
7221610f95cSScott Long 		mps_dprint(sc, MPS_ERROR, "Cannot allocate SIMQ\n");
723d3c7b9a0SKenneth D. Merry 		error = ENOMEM;
724d3c7b9a0SKenneth D. Merry 		goto out;
725d3c7b9a0SKenneth D. Merry 	}
726d3c7b9a0SKenneth D. Merry 
727d043c564SKenneth D. Merry 	unit = device_get_unit(sc->mps_dev);
728d3c7b9a0SKenneth D. Merry 	sassc->sim = cam_sim_alloc(mpssas_action, mpssas_poll, "mps", sassc,
72962a09ee9SAlexander Motin 	    unit, &sc->mps_mtx, reqs, reqs, sassc->devq);
730d3c7b9a0SKenneth D. Merry 	if (sassc->sim == NULL) {
731757ff642SScott Long 		mps_dprint(sc, MPS_INIT|MPS_ERROR, "Cannot allocate SIM\n");
732d3c7b9a0SKenneth D. Merry 		error = EINVAL;
733d3c7b9a0SKenneth D. Merry 		goto out;
734d3c7b9a0SKenneth D. Merry 	}
735d3c7b9a0SKenneth D. Merry 
736d043c564SKenneth D. Merry 	TAILQ_INIT(&sassc->ev_queue);
737d043c564SKenneth D. Merry 
738d043c564SKenneth D. Merry 	/* Initialize taskqueue for Event Handling */
739d043c564SKenneth D. Merry 	TASK_INIT(&sassc->ev_task, 0, mpssas_firmware_event_work, sc);
740d043c564SKenneth D. Merry 	sassc->ev_tq = taskqueue_create("mps_taskq", M_NOWAIT | M_ZERO,
741d043c564SKenneth D. Merry 	    taskqueue_thread_enqueue, &sassc->ev_tq);
742c2a0f07aSAlexander Motin 	taskqueue_start_threads(&sassc->ev_tq, 1, PRIBIO, "%s taskq",
743d043c564SKenneth D. Merry 	    device_get_nameunit(sc->mps_dev));
744d043c564SKenneth D. Merry 
745d043c564SKenneth D. Merry 	mps_lock(sc);
746d043c564SKenneth D. Merry 
747d3c7b9a0SKenneth D. Merry 	/*
748d3c7b9a0SKenneth D. Merry 	 * XXX There should be a bus for every port on the adapter, but since
749d3c7b9a0SKenneth D. Merry 	 * we're just going to fake the topology for now, we'll pretend that
750d3c7b9a0SKenneth D. Merry 	 * everything is just a target on a single bus.
751d3c7b9a0SKenneth D. Merry 	 */
752d3c7b9a0SKenneth D. Merry 	if ((error = xpt_bus_register(sassc->sim, sc->mps_dev, 0)) != 0) {
753757ff642SScott Long 		mps_dprint(sc, MPS_INIT|MPS_ERROR,
754757ff642SScott Long 		    "Error %d registering SCSI bus\n", error);
755d3c7b9a0SKenneth D. Merry 		mps_unlock(sc);
756d3c7b9a0SKenneth D. Merry 		goto out;
757d3c7b9a0SKenneth D. Merry 	}
758d3c7b9a0SKenneth D. Merry 
759d3c7b9a0SKenneth D. Merry 	/*
760b01773b0SKenneth D. Merry 	 * Assume that discovery events will start right away.
761b01773b0SKenneth D. Merry 	 *
762b01773b0SKenneth D. Merry 	 * Hold off boot until discovery is complete.
763d3c7b9a0SKenneth D. Merry 	 */
764d043c564SKenneth D. Merry 	sassc->flags |= MPSSAS_IN_STARTUP | MPSSAS_IN_DISCOVERY;
765d043c564SKenneth D. Merry 	sc->sassc->startup_refcount = 0;
76637b8d8c4SAlexander Motin 	mpssas_startup_increment(sassc);
767d3c7b9a0SKenneth D. Merry 
76802d81940SAlexander Motin 	mps_unlock(sc);
76902d81940SAlexander Motin 
770b01773b0SKenneth D. Merry 	/*
771b01773b0SKenneth D. Merry 	 * Register for async events so we can determine the EEDP
772b01773b0SKenneth D. Merry 	 * capabilities of devices.
773b01773b0SKenneth D. Merry 	 */
774b01773b0SKenneth D. Merry 	status = xpt_create_path(&sassc->path, /*periph*/NULL,
775b01773b0SKenneth D. Merry 	    cam_sim_path(sc->sassc->sim), CAM_TARGET_WILDCARD,
776b01773b0SKenneth D. Merry 	    CAM_LUN_WILDCARD);
777b01773b0SKenneth D. Merry 	if (status != CAM_REQ_CMP) {
778757ff642SScott Long 		mps_dprint(sc, MPS_ERROR|MPS_INIT,
779757ff642SScott Long 		    "Error %#x creating sim path\n", status);
780b01773b0SKenneth D. Merry 		sassc->path = NULL;
781b01773b0SKenneth D. Merry 	} else {
782b01773b0SKenneth D. Merry 		int event;
783b01773b0SKenneth D. Merry 
784b01773b0SKenneth D. Merry 		event = AC_ADVINFO_CHANGED;
785b01773b0SKenneth D. Merry 		status = xpt_register_async(event, mpssas_async, sc,
786b01773b0SKenneth D. Merry 					    sassc->path);
787d043c564SKenneth D. Merry 		if (status != CAM_REQ_CMP) {
7881610f95cSScott Long 			mps_dprint(sc, MPS_ERROR,
7891610f95cSScott Long 			    "Error %#x registering async handler for "
790d043c564SKenneth D. Merry 			    "AC_ADVINFO_CHANGED events\n", status);
791b01773b0SKenneth D. Merry 			xpt_free_path(sassc->path);
792b01773b0SKenneth D. Merry 			sassc->path = NULL;
793d043c564SKenneth D. Merry 		}
794b01773b0SKenneth D. Merry 	}
795b01773b0SKenneth D. Merry 	if (status != CAM_REQ_CMP) {
796b01773b0SKenneth D. Merry 		/*
797b01773b0SKenneth D. Merry 		 * EEDP use is the exception, not the rule.
798b01773b0SKenneth D. Merry 		 * Warn the user, but do not fail to attach.
799b01773b0SKenneth D. Merry 		 */
800b01773b0SKenneth D. Merry 		mps_printf(sc, "EEDP capabilities disabled.\n");
801b01773b0SKenneth D. Merry 	}
802d043c564SKenneth D. Merry 
803d3c7b9a0SKenneth D. Merry 	mpssas_register_events(sc);
804d3c7b9a0SKenneth D. Merry out:
805d3c7b9a0SKenneth D. Merry 	if (error)
806d3c7b9a0SKenneth D. Merry 		mps_detach_sas(sc);
807757ff642SScott Long 
808757ff642SScott Long 	mps_dprint(sc, MPS_INIT, "%s exit error= %d\n", __func__, error);
809d3c7b9a0SKenneth D. Merry 	return (error);
810d3c7b9a0SKenneth D. Merry }
811d3c7b9a0SKenneth D. Merry 
812d3c7b9a0SKenneth D. Merry int
mps_detach_sas(struct mps_softc * sc)813d3c7b9a0SKenneth D. Merry mps_detach_sas(struct mps_softc *sc)
814d3c7b9a0SKenneth D. Merry {
815d3c7b9a0SKenneth D. Merry 	struct mpssas_softc *sassc;
816be4aa869SKenneth D. Merry 	struct mpssas_lun *lun, *lun_tmp;
817be4aa869SKenneth D. Merry 	struct mpssas_target *targ;
818be4aa869SKenneth D. Merry 	int i;
819d3c7b9a0SKenneth D. Merry 
8201610f95cSScott Long 	MPS_FUNCTRACE(sc);
821d3c7b9a0SKenneth D. Merry 
822d3c7b9a0SKenneth D. Merry 	if (sc->sassc == NULL)
823d3c7b9a0SKenneth D. Merry 		return (0);
824d3c7b9a0SKenneth D. Merry 
825d3c7b9a0SKenneth D. Merry 	sassc = sc->sassc;
826d043c564SKenneth D. Merry 	mps_deregister_events(sc, sassc->mpssas_eh);
827d043c564SKenneth D. Merry 
828d043c564SKenneth D. Merry 	/*
829d043c564SKenneth D. Merry 	 * Drain and free the event handling taskqueue with the lock
830d043c564SKenneth D. Merry 	 * unheld so that any parallel processing tasks drain properly
831d043c564SKenneth D. Merry 	 * without deadlocking.
832d043c564SKenneth D. Merry 	 */
833d043c564SKenneth D. Merry 	if (sassc->ev_tq != NULL)
834d043c564SKenneth D. Merry 		taskqueue_free(sassc->ev_tq);
835d3c7b9a0SKenneth D. Merry 
836d043c564SKenneth D. Merry 	/* Deregister our async handler */
837b01773b0SKenneth D. Merry 	if (sassc->path != NULL) {
838b01773b0SKenneth D. Merry 		xpt_register_async(0, mpssas_async, sc, sassc->path);
839b01773b0SKenneth D. Merry 		xpt_free_path(sassc->path);
840b01773b0SKenneth D. Merry 		sassc->path = NULL;
841b01773b0SKenneth D. Merry 	}
842d043c564SKenneth D. Merry 
84302d81940SAlexander Motin 	/* Make sure CAM doesn't wedge if we had to bail out early. */
84402d81940SAlexander Motin 	mps_lock(sc);
84502d81940SAlexander Motin 
84602d81940SAlexander Motin 	while (sassc->startup_refcount != 0)
84702d81940SAlexander Motin 		mpssas_startup_decrement(sassc);
84802d81940SAlexander Motin 
849d3c7b9a0SKenneth D. Merry 	if (sassc->flags & MPSSAS_IN_STARTUP)
850d3c7b9a0SKenneth D. Merry 		xpt_release_simq(sassc->sim, 1);
851d3c7b9a0SKenneth D. Merry 
852d3c7b9a0SKenneth D. Merry 	if (sassc->sim != NULL) {
853d3c7b9a0SKenneth D. Merry 		xpt_bus_deregister(cam_sim_path(sassc->sim));
854d3c7b9a0SKenneth D. Merry 		cam_sim_free(sassc->sim, FALSE);
855d3c7b9a0SKenneth D. Merry 	}
856d043c564SKenneth D. Merry 
857d3c7b9a0SKenneth D. Merry 	mps_unlock(sc);
858d3c7b9a0SKenneth D. Merry 
859d3c7b9a0SKenneth D. Merry 	if (sassc->devq != NULL)
860d3c7b9a0SKenneth D. Merry 		cam_simq_free(sassc->devq);
861d3c7b9a0SKenneth D. Merry 
86208235773SScott Long 	for(i=0; i< sassc->maxtargets ;i++) {
863be4aa869SKenneth D. Merry 		targ = &sassc->targets[i];
864be4aa869SKenneth D. Merry 		SLIST_FOREACH_SAFE(lun, &targ->luns, lun_link, lun_tmp) {
865be4aa869SKenneth D. Merry 			free(lun, M_MPT2);
866be4aa869SKenneth D. Merry 		}
867be4aa869SKenneth D. Merry 	}
868d3c7b9a0SKenneth D. Merry 	free(sassc->targets, M_MPT2);
869d3c7b9a0SKenneth D. Merry 	free(sassc, M_MPT2);
870d3c7b9a0SKenneth D. Merry 	sc->sassc = NULL;
871d3c7b9a0SKenneth D. Merry 
872d3c7b9a0SKenneth D. Merry 	return (0);
873d3c7b9a0SKenneth D. Merry }
874d3c7b9a0SKenneth D. Merry 
875d043c564SKenneth D. Merry void
mpssas_discovery_end(struct mpssas_softc * sassc)876d3c7b9a0SKenneth D. Merry mpssas_discovery_end(struct mpssas_softc *sassc)
877d3c7b9a0SKenneth D. Merry {
878d3c7b9a0SKenneth D. Merry 	struct mps_softc *sc = sassc->sc;
879d3c7b9a0SKenneth D. Merry 
8801610f95cSScott Long 	MPS_FUNCTRACE(sc);
881d3c7b9a0SKenneth D. Merry 
882635e58c7SStephen McConnell 	/*
883635e58c7SStephen McConnell 	 * After discovery has completed, check the mapping table for any
884635e58c7SStephen McConnell 	 * missing devices and update their missing counts. Only do this once
885635e58c7SStephen McConnell 	 * whenever the driver is initialized so that missing counts aren't
886635e58c7SStephen McConnell 	 * updated unnecessarily. Note that just because discovery has
887635e58c7SStephen McConnell 	 * completed doesn't mean that events have been processed yet. The
888635e58c7SStephen McConnell 	 * check_devices function is a callout timer that checks if ALL devices
889635e58c7SStephen McConnell 	 * are missing. If so, it will wait a little longer for events to
890635e58c7SStephen McConnell 	 * complete and keep resetting itself until some device in the mapping
891635e58c7SStephen McConnell 	 * table is not missing, meaning that event processing has started.
892635e58c7SStephen McConnell 	 */
893635e58c7SStephen McConnell 	if (sc->track_mapping_events) {
894635e58c7SStephen McConnell 		mps_dprint(sc, MPS_XINFO | MPS_MAPPING, "Discovery has "
895635e58c7SStephen McConnell 		    "completed. Check for missing devices in the mapping "
896635e58c7SStephen McConnell 		    "table.\n");
897635e58c7SStephen McConnell 		callout_reset(&sc->device_check_callout,
898635e58c7SStephen McConnell 		    MPS_MISSING_CHECK_DELAY * hz, mps_mapping_check_devices,
899635e58c7SStephen McConnell 		    sc);
900635e58c7SStephen McConnell 	}
901d3c7b9a0SKenneth D. Merry }
902d3c7b9a0SKenneth D. Merry 
903d3c7b9a0SKenneth D. Merry static void
mpssas_action(struct cam_sim * sim,union ccb * ccb)904d3c7b9a0SKenneth D. Merry mpssas_action(struct cam_sim *sim, union ccb *ccb)
905d3c7b9a0SKenneth D. Merry {
906d3c7b9a0SKenneth D. Merry 	struct mpssas_softc *sassc;
907d3c7b9a0SKenneth D. Merry 
908d3c7b9a0SKenneth D. Merry 	sassc = cam_sim_softc(sim);
909d3c7b9a0SKenneth D. Merry 
9101610f95cSScott Long 	MPS_FUNCTRACE(sassc->sc);
9111610f95cSScott Long 	mps_dprint(sassc->sc, MPS_TRACE, "ccb func_code 0x%x\n",
912d3c7b9a0SKenneth D. Merry 	    ccb->ccb_h.func_code);
913d043c564SKenneth D. Merry 	mtx_assert(&sassc->sc->mps_mtx, MA_OWNED);
914d3c7b9a0SKenneth D. Merry 
915d3c7b9a0SKenneth D. Merry 	switch (ccb->ccb_h.func_code) {
916d3c7b9a0SKenneth D. Merry 	case XPT_PATH_INQ:
917d3c7b9a0SKenneth D. Merry 	{
918d3c7b9a0SKenneth D. Merry 		struct ccb_pathinq *cpi = &ccb->cpi;
91932b0a21eSStephen McConnell 		struct mps_softc *sc = sassc->sc;
920d3c7b9a0SKenneth D. Merry 
921d3c7b9a0SKenneth D. Merry 		cpi->version_num = 1;
922d3c7b9a0SKenneth D. Merry 		cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE|PI_WIDE_16;
923d3c7b9a0SKenneth D. Merry 		cpi->target_sprt = 0;
924b01773b0SKenneth D. Merry 		cpi->hba_misc = PIM_NOBUSRESET | PIM_UNMAPPED | PIM_NOSCAN;
925d3c7b9a0SKenneth D. Merry 		cpi->hba_eng_cnt = 0;
92608235773SScott Long 		cpi->max_target = sassc->maxtargets - 1;
927be4aa869SKenneth D. Merry 		cpi->max_lun = 255;
928635e58c7SStephen McConnell 
929635e58c7SStephen McConnell 		/*
930635e58c7SStephen McConnell 		 * initiator_id is set here to an ID outside the set of valid
931635e58c7SStephen McConnell 		 * target IDs (including volumes).
932635e58c7SStephen McConnell 		 */
933635e58c7SStephen McConnell 		cpi->initiator_id = sassc->maxtargets;
9344195c7deSAlan Somers 		strlcpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
9354195c7deSAlan Somers 		strlcpy(cpi->hba_vid, "Avago Tech", HBA_IDLEN);
9364195c7deSAlan Somers 		strlcpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
937d3c7b9a0SKenneth D. Merry 		cpi->unit_number = cam_sim_unit(sim);
938d3c7b9a0SKenneth D. Merry 		cpi->bus_id = cam_sim_bus(sim);
939d3c7b9a0SKenneth D. Merry 		cpi->base_transfer_speed = 150000;
940d3c7b9a0SKenneth D. Merry 		cpi->transport = XPORT_SAS;
941d3c7b9a0SKenneth D. Merry 		cpi->transport_version = 0;
942d3c7b9a0SKenneth D. Merry 		cpi->protocol = PROTO_SCSI;
943d3c7b9a0SKenneth D. Merry 		cpi->protocol_version = SCSI_REV_SPC;
9444f5d6573SAlexander Motin 		cpi->maxio = sc->maxio;
945601781ccSScott Long 		mpssas_set_ccbstatus(ccb, CAM_REQ_CMP);
946d3c7b9a0SKenneth D. Merry 		break;
947d3c7b9a0SKenneth D. Merry 	}
948d3c7b9a0SKenneth D. Merry 	case XPT_GET_TRAN_SETTINGS:
949d3c7b9a0SKenneth D. Merry 	{
950d3c7b9a0SKenneth D. Merry 		struct ccb_trans_settings	*cts;
951d3c7b9a0SKenneth D. Merry 		struct ccb_trans_settings_sas	*sas;
952d3c7b9a0SKenneth D. Merry 		struct ccb_trans_settings_scsi	*scsi;
953d3c7b9a0SKenneth D. Merry 		struct mpssas_target *targ;
954d3c7b9a0SKenneth D. Merry 
955d3c7b9a0SKenneth D. Merry 		cts = &ccb->cts;
956d3c7b9a0SKenneth D. Merry 		sas = &cts->xport_specific.sas;
957d3c7b9a0SKenneth D. Merry 		scsi = &cts->proto_specific.scsi;
958d3c7b9a0SKenneth D. Merry 
95908235773SScott Long 		KASSERT(cts->ccb_h.target_id < sassc->maxtargets,
96008235773SScott Long 		    ("Target %d out of bounds in XPT_GET_TRANS_SETTINGS\n",
96108235773SScott Long 		    cts->ccb_h.target_id));
962d3c7b9a0SKenneth D. Merry 		targ = &sassc->targets[cts->ccb_h.target_id];
963d3c7b9a0SKenneth D. Merry 		if (targ->handle == 0x0) {
9647571e7f6SSteven Hartland 			mpssas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE);
965d3c7b9a0SKenneth D. Merry 			break;
966d3c7b9a0SKenneth D. Merry 		}
967d3c7b9a0SKenneth D. Merry 
968d3c7b9a0SKenneth D. Merry 		cts->protocol_version = SCSI_REV_SPC2;
969d3c7b9a0SKenneth D. Merry 		cts->transport = XPORT_SAS;
970d3c7b9a0SKenneth D. Merry 		cts->transport_version = 0;
971d3c7b9a0SKenneth D. Merry 
972d3c7b9a0SKenneth D. Merry 		sas->valid = CTS_SAS_VALID_SPEED;
973d3c7b9a0SKenneth D. Merry 		switch (targ->linkrate) {
974d3c7b9a0SKenneth D. Merry 		case 0x08:
975d3c7b9a0SKenneth D. Merry 			sas->bitrate = 150000;
976d3c7b9a0SKenneth D. Merry 			break;
977d3c7b9a0SKenneth D. Merry 		case 0x09:
978d3c7b9a0SKenneth D. Merry 			sas->bitrate = 300000;
979d3c7b9a0SKenneth D. Merry 			break;
980d3c7b9a0SKenneth D. Merry 		case 0x0a:
981d3c7b9a0SKenneth D. Merry 			sas->bitrate = 600000;
982d3c7b9a0SKenneth D. Merry 			break;
983d3c7b9a0SKenneth D. Merry 		default:
984d3c7b9a0SKenneth D. Merry 			sas->valid = 0;
985d3c7b9a0SKenneth D. Merry 		}
986d3c7b9a0SKenneth D. Merry 
987d3c7b9a0SKenneth D. Merry 		cts->protocol = PROTO_SCSI;
988d3c7b9a0SKenneth D. Merry 		scsi->valid = CTS_SCSI_VALID_TQ;
989d3c7b9a0SKenneth D. Merry 		scsi->flags = CTS_SCSI_FLAGS_TAG_ENB;
990d3c7b9a0SKenneth D. Merry 
991601781ccSScott Long 		mpssas_set_ccbstatus(ccb, CAM_REQ_CMP);
992d3c7b9a0SKenneth D. Merry 		break;
993d3c7b9a0SKenneth D. Merry 	}
994d3c7b9a0SKenneth D. Merry 	case XPT_CALC_GEOMETRY:
995d3c7b9a0SKenneth D. Merry 		cam_calc_geometry(&ccb->ccg, /*extended*/1);
996601781ccSScott Long 		mpssas_set_ccbstatus(ccb, CAM_REQ_CMP);
997d3c7b9a0SKenneth D. Merry 		break;
998d3c7b9a0SKenneth D. Merry 	case XPT_RESET_DEV:
9991610f95cSScott Long 		mps_dprint(sassc->sc, MPS_XINFO, "mpssas_action XPT_RESET_DEV\n");
1000d3c7b9a0SKenneth D. Merry 		mpssas_action_resetdev(sassc, ccb);
1001d3c7b9a0SKenneth D. Merry 		return;
1002d3c7b9a0SKenneth D. Merry 	case XPT_RESET_BUS:
1003d3c7b9a0SKenneth D. Merry 	case XPT_ABORT:
1004d3c7b9a0SKenneth D. Merry 	case XPT_TERM_IO:
10051610f95cSScott Long 		mps_dprint(sassc->sc, MPS_XINFO,
10061610f95cSScott Long 		    "mpssas_action faking success for abort or reset\n");
1007601781ccSScott Long 		mpssas_set_ccbstatus(ccb, CAM_REQ_CMP);
1008d3c7b9a0SKenneth D. Merry 		break;
1009d3c7b9a0SKenneth D. Merry 	case XPT_SCSI_IO:
1010d3c7b9a0SKenneth D. Merry 		mpssas_action_scsiio(sassc, ccb);
1011d3c7b9a0SKenneth D. Merry 		return;
101206e79492SKenneth D. Merry 	case XPT_SMP_IO:
101306e79492SKenneth D. Merry 		mpssas_action_smpio(sassc, ccb);
101406e79492SKenneth D. Merry 		return;
1015d3c7b9a0SKenneth D. Merry 	default:
1016601781ccSScott Long 		mpssas_set_ccbstatus(ccb, CAM_FUNC_NOTAVAIL);
1017d3c7b9a0SKenneth D. Merry 		break;
1018d3c7b9a0SKenneth D. Merry 	}
1019d3c7b9a0SKenneth D. Merry 	xpt_done(ccb);
1020d3c7b9a0SKenneth D. Merry 
1021d3c7b9a0SKenneth D. Merry }
1022d3c7b9a0SKenneth D. Merry 
1023d3c7b9a0SKenneth D. Merry static void
mpssas_announce_reset(struct mps_softc * sc,uint32_t ac_code,target_id_t target_id,lun_id_t lun_id)1024d043c564SKenneth D. Merry mpssas_announce_reset(struct mps_softc *sc, uint32_t ac_code,
1025d043c564SKenneth D. Merry     target_id_t target_id, lun_id_t lun_id)
1026d3c7b9a0SKenneth D. Merry {
1027d043c564SKenneth D. Merry 	path_id_t path_id = cam_sim_path(sc->sassc->sim);
1028d043c564SKenneth D. Merry 	struct cam_path *path;
1029d3c7b9a0SKenneth D. Merry 
1030123055f0SNathan Whitehorn 	mps_dprint(sc, MPS_XINFO, "%s code %x target %d lun %jx\n", __func__,
1031123055f0SNathan Whitehorn 	    ac_code, target_id, (uintmax_t)lun_id);
1032d3c7b9a0SKenneth D. Merry 
1033d043c564SKenneth D. Merry 	if (xpt_create_path(&path, NULL,
1034d043c564SKenneth D. Merry 		path_id, target_id, lun_id) != CAM_REQ_CMP) {
10351610f95cSScott Long 		mps_dprint(sc, MPS_ERROR, "unable to create path for reset "
1036d043c564SKenneth D. Merry 			   "notification\n");
1037d3c7b9a0SKenneth D. Merry 		return;
1038d3c7b9a0SKenneth D. Merry 	}
1039d043c564SKenneth D. Merry 
1040d043c564SKenneth D. Merry 	xpt_async(ac_code, path, NULL);
1041d043c564SKenneth D. Merry 	xpt_free_path(path);
1042d043c564SKenneth D. Merry }
1043d3c7b9a0SKenneth D. Merry 
1044d3c7b9a0SKenneth D. Merry static void
mpssas_complete_all_commands(struct mps_softc * sc)1045d043c564SKenneth D. Merry mpssas_complete_all_commands(struct mps_softc *sc)
1046d3c7b9a0SKenneth D. Merry {
1047d043c564SKenneth D. Merry 	struct mps_command *cm;
1048d043c564SKenneth D. Merry 	int i;
1049d043c564SKenneth D. Merry 	int completed;
1050d043c564SKenneth D. Merry 
10511610f95cSScott Long 	MPS_FUNCTRACE(sc);
1052d043c564SKenneth D. Merry 	mtx_assert(&sc->mps_mtx, MA_OWNED);
1053d043c564SKenneth D. Merry 
1054d043c564SKenneth D. Merry 	/* complete all commands with a NULL reply */
1055d043c564SKenneth D. Merry 	for (i = 1; i < sc->num_reqs; i++) {
1056d043c564SKenneth D. Merry 		cm = &sc->commands[i];
1057f0779b04SScott Long 		if (cm->cm_state == MPS_CM_STATE_FREE)
1058f0779b04SScott Long 			continue;
1059f0779b04SScott Long 
1060f0779b04SScott Long 		cm->cm_state = MPS_CM_STATE_BUSY;
1061d043c564SKenneth D. Merry 		cm->cm_reply = NULL;
1062d043c564SKenneth D. Merry 		completed = 0;
1063d043c564SKenneth D. Merry 
10648277ce2bSConrad Meyer 		if (cm->cm_flags & MPS_CM_FLAGS_SATA_ID_TIMEOUT) {
10658277ce2bSConrad Meyer 			MPASS(cm->cm_data);
10668277ce2bSConrad Meyer 			free(cm->cm_data, M_MPT2);
10678277ce2bSConrad Meyer 			cm->cm_data = NULL;
10688277ce2bSConrad Meyer 		}
10698277ce2bSConrad Meyer 
1070d043c564SKenneth D. Merry 		if (cm->cm_flags & MPS_CM_FLAGS_POLLED)
1071d043c564SKenneth D. Merry 			cm->cm_flags |= MPS_CM_FLAGS_COMPLETE;
1072d043c564SKenneth D. Merry 
1073d043c564SKenneth D. Merry 		if (cm->cm_complete != NULL) {
10741610f95cSScott Long 			mpssas_log_command(cm, MPS_RECOVERY,
1075d043c564SKenneth D. Merry 			    "completing cm %p state %x ccb %p for diag reset\n",
1076d043c564SKenneth D. Merry 			    cm, cm->cm_state, cm->cm_ccb);
1077d043c564SKenneth D. Merry 
1078d043c564SKenneth D. Merry 			cm->cm_complete(sc, cm);
1079d043c564SKenneth D. Merry 			completed = 1;
1080f0779b04SScott Long 		} else if (cm->cm_flags & MPS_CM_FLAGS_WAKEUP) {
10811610f95cSScott Long 			mpssas_log_command(cm, MPS_RECOVERY,
1082d043c564SKenneth D. Merry 			    "waking up cm %p state %x ccb %p for diag reset\n",
1083d043c564SKenneth D. Merry 			    cm, cm->cm_state, cm->cm_ccb);
1084d043c564SKenneth D. Merry 			wakeup(cm);
1085d043c564SKenneth D. Merry 			completed = 1;
1086d043c564SKenneth D. Merry 		}
1087d043c564SKenneth D. Merry 
1088d043c564SKenneth D. Merry 		if ((completed == 0) && (cm->cm_state != MPS_CM_STATE_FREE)) {
1089d043c564SKenneth D. Merry 			/* this should never happen, but if it does, log */
10901610f95cSScott Long 			mpssas_log_command(cm, MPS_RECOVERY,
1091d043c564SKenneth D. Merry 			    "cm %p state %x flags 0x%x ccb %p during diag "
1092d043c564SKenneth D. Merry 			    "reset\n", cm, cm->cm_state, cm->cm_flags,
1093d043c564SKenneth D. Merry 			    cm->cm_ccb);
1094d043c564SKenneth D. Merry 		}
1095d043c564SKenneth D. Merry 	}
1096f0779b04SScott Long 
1097f0779b04SScott Long 	sc->io_cmds_active = 0;
1098d043c564SKenneth D. Merry }
1099d043c564SKenneth D. Merry 
1100d043c564SKenneth D. Merry void
mpssas_handle_reinit(struct mps_softc * sc)1101d043c564SKenneth D. Merry mpssas_handle_reinit(struct mps_softc *sc)
1102d043c564SKenneth D. Merry {
1103d043c564SKenneth D. Merry 	int i;
1104d043c564SKenneth D. Merry 
1105d043c564SKenneth D. Merry 	/* Go back into startup mode and freeze the simq, so that CAM
1106d043c564SKenneth D. Merry 	 * doesn't send any commands until after we've rediscovered all
1107d043c564SKenneth D. Merry 	 * targets and found the proper device handles for them.
1108d043c564SKenneth D. Merry 	 *
1109d043c564SKenneth D. Merry 	 * After the reset, portenable will trigger discovery, and after all
1110d043c564SKenneth D. Merry 	 * discovery-related activities have finished, the simq will be
1111d043c564SKenneth D. Merry 	 * released.
1112d043c564SKenneth D. Merry 	 */
11131610f95cSScott Long 	mps_dprint(sc, MPS_INIT, "%s startup\n", __func__);
1114d043c564SKenneth D. Merry 	sc->sassc->flags |= MPSSAS_IN_STARTUP;
1115d043c564SKenneth D. Merry 	sc->sassc->flags |= MPSSAS_IN_DISCOVERY;
111637b8d8c4SAlexander Motin 	mpssas_startup_increment(sc->sassc);
1117d043c564SKenneth D. Merry 
1118d043c564SKenneth D. Merry 	/* notify CAM of a bus reset */
1119d043c564SKenneth D. Merry 	mpssas_announce_reset(sc, AC_BUS_RESET, CAM_TARGET_WILDCARD,
1120d043c564SKenneth D. Merry 	    CAM_LUN_WILDCARD);
1121d043c564SKenneth D. Merry 
1122d043c564SKenneth D. Merry 	/* complete and cleanup after all outstanding commands */
1123d043c564SKenneth D. Merry 	mpssas_complete_all_commands(sc);
1124d043c564SKenneth D. Merry 
11251610f95cSScott Long 	mps_dprint(sc, MPS_INIT,
1126ef065d89SStephen McConnell 	    "%s startup %u after command completion\n", __func__,
1127ef065d89SStephen McConnell 	    sc->sassc->startup_refcount);
1128d043c564SKenneth D. Merry 
1129d043c564SKenneth D. Merry 	/* zero all the target handles, since they may change after the
1130d043c564SKenneth D. Merry 	 * reset, and we have to rediscover all the targets and use the new
1131d043c564SKenneth D. Merry 	 * handles.
1132d043c564SKenneth D. Merry 	 */
113308235773SScott Long 	for (i = 0; i < sc->sassc->maxtargets; i++) {
1134d043c564SKenneth D. Merry 		if (sc->sassc->targets[i].outstanding != 0)
11351610f95cSScott Long 			mps_dprint(sc, MPS_INIT, "target %u outstanding %u\n",
1136d043c564SKenneth D. Merry 			    i, sc->sassc->targets[i].outstanding);
1137d043c564SKenneth D. Merry 		sc->sassc->targets[i].handle = 0x0;
1138d043c564SKenneth D. Merry 		sc->sassc->targets[i].exp_dev_handle = 0x0;
1139d043c564SKenneth D. Merry 		sc->sassc->targets[i].outstanding = 0;
1140d043c564SKenneth D. Merry 		sc->sassc->targets[i].flags = MPSSAS_TARGET_INDIAGRESET;
1141d043c564SKenneth D. Merry 	}
1142d043c564SKenneth D. Merry }
11431610f95cSScott Long 
1144d043c564SKenneth D. Merry static void
mpssas_tm_timeout(void * data)1145d043c564SKenneth D. Merry mpssas_tm_timeout(void *data)
1146d043c564SKenneth D. Merry {
1147d043c564SKenneth D. Merry 	struct mps_command *tm = data;
1148d043c564SKenneth D. Merry 	struct mps_softc *sc = tm->cm_sc;
1149d043c564SKenneth D. Merry 
1150d043c564SKenneth D. Merry 	mtx_assert(&sc->mps_mtx, MA_OWNED);
1151d043c564SKenneth D. Merry 
11521610f95cSScott Long 	mpssas_log_command(tm, MPS_INFO|MPS_RECOVERY,
11531610f95cSScott Long 	    "task mgmt %p timed out\n", tm);
1154f0779b04SScott Long 
1155f0779b04SScott Long 	KASSERT(tm->cm_state == MPS_CM_STATE_INQUEUE,
1156175ad3d0SKenneth D. Merry 	    ("command not inqueue, state = %u\n", tm->cm_state));
1157f0779b04SScott Long 
1158f0779b04SScott Long 	tm->cm_state = MPS_CM_STATE_BUSY;
1159d043c564SKenneth D. Merry 	mps_reinit(sc);
1160d043c564SKenneth D. Merry }
1161d043c564SKenneth D. Merry 
1162d043c564SKenneth D. Merry static void
mpssas_logical_unit_reset_complete(struct mps_softc * sc,struct mps_command * tm)1163d043c564SKenneth D. Merry mpssas_logical_unit_reset_complete(struct mps_softc *sc, struct mps_command *tm)
1164d043c564SKenneth D. Merry {
1165d043c564SKenneth D. Merry 	MPI2_SCSI_TASK_MANAGE_REPLY *reply;
1166d043c564SKenneth D. Merry 	unsigned int cm_count = 0;
1167d3c7b9a0SKenneth D. Merry 	struct mps_command *cm;
1168d3c7b9a0SKenneth D. Merry 	struct mpssas_target *targ;
1169d3c7b9a0SKenneth D. Merry 
1170d043c564SKenneth D. Merry 	callout_stop(&tm->cm_callout);
1171d3c7b9a0SKenneth D. Merry 
1172d043c564SKenneth D. Merry 	reply = (MPI2_SCSI_TASK_MANAGE_REPLY *)tm->cm_reply;
1173d043c564SKenneth D. Merry 	targ = tm->cm_targ;
1174d3c7b9a0SKenneth D. Merry 
1175550e2acdSKenneth D. Merry 	/*
1176550e2acdSKenneth D. Merry 	 * Currently there should be no way we can hit this case.  It only
1177550e2acdSKenneth D. Merry 	 * happens when we have a failure to allocate chain frames, and
1178550e2acdSKenneth D. Merry 	 * task management commands don't have S/G lists.
11791610f95cSScott Long 	 * XXXSL So should it be an assertion?
1180550e2acdSKenneth D. Merry 	 */
1181d043c564SKenneth D. Merry 	if ((tm->cm_flags & MPS_CM_FLAGS_ERROR_MASK) != 0) {
11826eea4f46SScott Long 		mps_dprint(sc, MPS_RECOVERY|MPS_ERROR,
11836eea4f46SScott Long 		    "%s: cm_flags = %#x for LUN reset! "
1184d043c564SKenneth D. Merry 		   "This should not happen!\n", __func__, tm->cm_flags);
1185d043c564SKenneth D. Merry 		mpssas_free_tm(sc, tm);
1186d3c7b9a0SKenneth D. Merry 		return;
1187d3c7b9a0SKenneth D. Merry 	}
1188d3c7b9a0SKenneth D. Merry 
1189d043c564SKenneth D. Merry 	if (reply == NULL) {
11906eea4f46SScott Long 		mps_dprint(sc, MPS_RECOVERY, "NULL reset reply for tm %p\n",
11916eea4f46SScott Long 		    tm);
1192d043c564SKenneth D. Merry 		if ((sc->mps_flags & MPS_FLAGS_DIAGRESET) != 0) {
1193d043c564SKenneth D. Merry 			/* this completion was due to a reset, just cleanup */
11946eea4f46SScott Long 			mps_dprint(sc, MPS_RECOVERY, "Hardware undergoing "
11956eea4f46SScott Long 			    "reset, ignoring NULL LUN reset reply\n");
1196d043c564SKenneth D. Merry 			targ->tm = NULL;
1197d043c564SKenneth D. Merry 			mpssas_free_tm(sc, tm);
1198d043c564SKenneth D. Merry 		}
1199d043c564SKenneth D. Merry 		else {
1200d043c564SKenneth D. Merry 			/* we should have gotten a reply. */
12016eea4f46SScott Long 			mps_dprint(sc, MPS_INFO|MPS_RECOVERY, "NULL reply on "
12026eea4f46SScott Long 			    "LUN reset attempt, resetting controller\n");
1203d043c564SKenneth D. Merry 			mps_reinit(sc);
1204d043c564SKenneth D. Merry 		}
1205d043c564SKenneth D. Merry 		return;
1206d043c564SKenneth D. Merry 	}
1207d3c7b9a0SKenneth D. Merry 
12086eea4f46SScott Long 	mps_dprint(sc, MPS_RECOVERY,
1209d043c564SKenneth D. Merry 	    "logical unit reset status 0x%x code 0x%x count %u\n",
1210be4aa869SKenneth D. Merry 	    le16toh(reply->IOCStatus), le32toh(reply->ResponseCode),
1211be4aa869SKenneth D. Merry 	    le32toh(reply->TerminationCount));
1212d043c564SKenneth D. Merry 
12136eea4f46SScott Long 	/*
12146eea4f46SScott Long 	 * See if there are any outstanding commands for this LUN.
1215d043c564SKenneth D. Merry 	 * This could be made more efficient by using a per-LU data
1216d043c564SKenneth D. Merry 	 * structure of some sort.
1217d043c564SKenneth D. Merry 	 */
1218d043c564SKenneth D. Merry 	TAILQ_FOREACH(cm, &targ->commands, cm_link) {
1219d043c564SKenneth D. Merry 		if (cm->cm_lun == tm->cm_lun)
1220d043c564SKenneth D. Merry 			cm_count++;
1221d043c564SKenneth D. Merry 	}
1222d043c564SKenneth D. Merry 
1223d043c564SKenneth D. Merry 	if (cm_count == 0) {
12246eea4f46SScott Long 		mps_dprint(sc, MPS_RECOVERY|MPS_INFO,
12256eea4f46SScott Long 		    "Finished recovery after LUN reset for target %u\n",
12266eea4f46SScott Long 		    targ->tid);
1227d043c564SKenneth D. Merry 
12286eea4f46SScott Long 		mpssas_announce_reset(sc, AC_SENT_BDR, targ->tid, tm->cm_lun);
1229d043c564SKenneth D. Merry 
12306eea4f46SScott Long 		/*
12316eea4f46SScott Long 		 * We've finished recovery for this logical unit.  check and
1232d043c564SKenneth D. Merry 		 * see if some other logical unit has a timedout command
1233d043c564SKenneth D. Merry 		 * that needs to be processed.
1234d043c564SKenneth D. Merry 		 */
1235d043c564SKenneth D. Merry 		cm = TAILQ_FIRST(&targ->timedout_commands);
1236d043c564SKenneth D. Merry 		if (cm) {
12376eea4f46SScott Long 			mps_dprint(sc, MPS_INFO|MPS_RECOVERY,
12386eea4f46SScott Long 			    "More commands to abort for target %u\n",
12396eea4f46SScott Long 			    targ->tid);
1240d043c564SKenneth D. Merry 			mpssas_send_abort(sc, tm, cm);
12416eea4f46SScott Long 		} else {
1242d043c564SKenneth D. Merry 			targ->tm = NULL;
1243d043c564SKenneth D. Merry 			mpssas_free_tm(sc, tm);
1244d043c564SKenneth D. Merry 		}
12456eea4f46SScott Long 	} else {
12466eea4f46SScott Long 		/*
12476eea4f46SScott Long 		 * If we still have commands for this LUN, the reset
1248d043c564SKenneth D. Merry 		 * effectively failed, regardless of the status reported.
1249d043c564SKenneth D. Merry 		 * Escalate to a target reset.
1250d043c564SKenneth D. Merry 		 */
12516eea4f46SScott Long 		mps_dprint(sc, MPS_INFO|MPS_RECOVERY,
12526eea4f46SScott Long 		    "logical unit reset complete for target %u, but still "
12536eea4f46SScott Long 		    "have %u command(s), sending target reset\n", targ->tid,
12546eea4f46SScott Long 		    cm_count);
1255d043c564SKenneth D. Merry 		mpssas_send_reset(sc, tm,
1256d043c564SKenneth D. Merry 		    MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET);
1257d043c564SKenneth D. Merry 	}
1258d043c564SKenneth D. Merry }
1259d043c564SKenneth D. Merry 
1260d043c564SKenneth D. Merry static void
mpssas_target_reset_complete(struct mps_softc * sc,struct mps_command * tm)1261d043c564SKenneth D. Merry mpssas_target_reset_complete(struct mps_softc *sc, struct mps_command *tm)
1262d043c564SKenneth D. Merry {
1263d043c564SKenneth D. Merry 	MPI2_SCSI_TASK_MANAGE_REPLY *reply;
1264d043c564SKenneth D. Merry 	MPI2_SCSI_TASK_MANAGE_REQUEST *req;
1265d043c564SKenneth D. Merry 	struct mpssas_target *targ;
1266d043c564SKenneth D. Merry 
1267d043c564SKenneth D. Merry 	callout_stop(&tm->cm_callout);
1268d043c564SKenneth D. Merry 
1269d043c564SKenneth D. Merry 	req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req;
1270d043c564SKenneth D. Merry 	reply = (MPI2_SCSI_TASK_MANAGE_REPLY *)tm->cm_reply;
1271d043c564SKenneth D. Merry 	targ = tm->cm_targ;
1272d043c564SKenneth D. Merry 
1273d043c564SKenneth D. Merry 	/*
1274d043c564SKenneth D. Merry 	 * Currently there should be no way we can hit this case.  It only
1275d043c564SKenneth D. Merry 	 * happens when we have a failure to allocate chain frames, and
1276d043c564SKenneth D. Merry 	 * task management commands don't have S/G lists.
1277d043c564SKenneth D. Merry 	 */
1278d043c564SKenneth D. Merry 	if ((tm->cm_flags & MPS_CM_FLAGS_ERROR_MASK) != 0) {
12791610f95cSScott Long 		mps_dprint(sc, MPS_ERROR,"%s: cm_flags = %#x for target reset! "
1280d043c564SKenneth D. Merry 			   "This should not happen!\n", __func__, tm->cm_flags);
1281d043c564SKenneth D. Merry 		mpssas_free_tm(sc, tm);
1282d043c564SKenneth D. Merry 		return;
1283d043c564SKenneth D. Merry 	}
1284d043c564SKenneth D. Merry 
1285d043c564SKenneth D. Merry 	if (reply == NULL) {
12866eea4f46SScott Long 		mps_dprint(sc, MPS_RECOVERY,
12876eea4f46SScott Long 		    "NULL target reset reply for tm %pi TaskMID %u\n",
12886eea4f46SScott Long 		    tm, le16toh(req->TaskMID));
1289d043c564SKenneth D. Merry 		if ((sc->mps_flags & MPS_FLAGS_DIAGRESET) != 0) {
1290d043c564SKenneth D. Merry 			/* this completion was due to a reset, just cleanup */
12916eea4f46SScott Long 			mps_dprint(sc, MPS_RECOVERY, "Hardware undergoing "
12926eea4f46SScott Long 			    "reset, ignoring NULL target reset reply\n");
1293d043c564SKenneth D. Merry 			targ->tm = NULL;
1294d043c564SKenneth D. Merry 			mpssas_free_tm(sc, tm);
12956eea4f46SScott Long 		} else {
1296d043c564SKenneth D. Merry 			/* we should have gotten a reply. */
12976eea4f46SScott Long 			mps_dprint(sc, MPS_INFO|MPS_RECOVERY, "NULL reply on "
12986eea4f46SScott Long 			    "target reset attempt, resetting controller\n");
1299d043c564SKenneth D. Merry 			mps_reinit(sc);
1300d043c564SKenneth D. Merry 		}
1301d043c564SKenneth D. Merry 		return;
1302d043c564SKenneth D. Merry 	}
1303d043c564SKenneth D. Merry 
13046eea4f46SScott Long 	mps_dprint(sc, MPS_RECOVERY,
1305d043c564SKenneth D. Merry 	    "target reset status 0x%x code 0x%x count %u\n",
1306be4aa869SKenneth D. Merry 	    le16toh(reply->IOCStatus), le32toh(reply->ResponseCode),
1307be4aa869SKenneth D. Merry 	    le32toh(reply->TerminationCount));
1308d043c564SKenneth D. Merry 
1309d043c564SKenneth D. Merry 	if (targ->outstanding == 0) {
1310d043c564SKenneth D. Merry 		/* we've finished recovery for this target and all
1311d043c564SKenneth D. Merry 		 * of its logical units.
1312d043c564SKenneth D. Merry 		 */
13136eea4f46SScott Long 		mps_dprint(sc, MPS_RECOVERY|MPS_INFO,
13146eea4f46SScott Long 		    "Finished reset recovery for target %u\n", targ->tid);
1315d043c564SKenneth D. Merry 
1316d043c564SKenneth D. Merry 		mpssas_announce_reset(sc, AC_SENT_BDR, tm->cm_targ->tid,
1317d043c564SKenneth D. Merry 		    CAM_LUN_WILDCARD);
1318d043c564SKenneth D. Merry 
1319d043c564SKenneth D. Merry 		targ->tm = NULL;
1320d043c564SKenneth D. Merry 		mpssas_free_tm(sc, tm);
13216eea4f46SScott Long 	} else {
13226eea4f46SScott Long 		/*
13236eea4f46SScott Long 		 * After a target reset, if this target still has
1324d043c564SKenneth D. Merry 		 * outstanding commands, the reset effectively failed,
1325d043c564SKenneth D. Merry 		 * regardless of the status reported.  escalate.
1326d043c564SKenneth D. Merry 		 */
13276eea4f46SScott Long 		mps_dprint(sc, MPS_INFO|MPS_RECOVERY,
13286eea4f46SScott Long 		    "Target reset complete for target %u, but still have %u "
13296eea4f46SScott Long 		    "command(s), resetting controller\n", targ->tid,
13306eea4f46SScott Long 		    targ->outstanding);
1331d043c564SKenneth D. Merry 		mps_reinit(sc);
1332d043c564SKenneth D. Merry 	}
1333d043c564SKenneth D. Merry }
1334d043c564SKenneth D. Merry 
1335d043c564SKenneth D. Merry #define MPS_RESET_TIMEOUT 30
1336d043c564SKenneth D. Merry 
1337ef065d89SStephen McConnell int
mpssas_send_reset(struct mps_softc * sc,struct mps_command * tm,uint8_t type)1338d043c564SKenneth D. Merry mpssas_send_reset(struct mps_softc *sc, struct mps_command *tm, uint8_t type)
1339d043c564SKenneth D. Merry {
1340d043c564SKenneth D. Merry 	MPI2_SCSI_TASK_MANAGE_REQUEST *req;
1341d043c564SKenneth D. Merry 	struct mpssas_target *target;
1342d043c564SKenneth D. Merry 	int err;
1343d043c564SKenneth D. Merry 
1344d043c564SKenneth D. Merry 	target = tm->cm_targ;
1345d043c564SKenneth D. Merry 	if (target->handle == 0) {
13461610f95cSScott Long 		mps_dprint(sc, MPS_ERROR,"%s null devhandle for target_id %d\n",
1347d043c564SKenneth D. Merry 		    __func__, target->tid);
1348d043c564SKenneth D. Merry 		return -1;
1349d043c564SKenneth D. Merry 	}
1350d043c564SKenneth D. Merry 
1351d043c564SKenneth D. Merry 	req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req;
1352be4aa869SKenneth D. Merry 	req->DevHandle = htole16(target->handle);
1353d043c564SKenneth D. Merry 	req->TaskType = type;
1354d043c564SKenneth D. Merry 
1355d043c564SKenneth D. Merry 	if (type == MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET) {
1356d043c564SKenneth D. Merry 		/* XXX Need to handle invalid LUNs */
1357d043c564SKenneth D. Merry 		MPS_SET_LUN(req->LUN, tm->cm_lun);
1358d043c564SKenneth D. Merry 		tm->cm_targ->logical_unit_resets++;
13596eea4f46SScott Long 		mps_dprint(sc, MPS_RECOVERY|MPS_INFO,
13606eea4f46SScott Long 		    "Sending logical unit reset to target %u lun %d\n",
13616eea4f46SScott Long 		    target->tid, tm->cm_lun);
1362d043c564SKenneth D. Merry 		tm->cm_complete = mpssas_logical_unit_reset_complete;
1363ef065d89SStephen McConnell 		mpssas_prepare_for_tm(sc, tm, target, tm->cm_lun);
13646eea4f46SScott Long 	} else if (type == MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET) {
1365ef065d89SStephen McConnell 		/*
1366ef065d89SStephen McConnell 		 * Target reset method =
1367ef065d89SStephen McConnell 		 * 	SAS Hard Link Reset / SATA Link Reset
1368ef065d89SStephen McConnell 		 */
1369d043c564SKenneth D. Merry 		req->MsgFlags = MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET;
1370d043c564SKenneth D. Merry 		tm->cm_targ->target_resets++;
13716eea4f46SScott Long 		mps_dprint(sc, MPS_RECOVERY|MPS_INFO,
13726eea4f46SScott Long 		    "Sending target reset to target %u\n", target->tid);
1373d043c564SKenneth D. Merry 		tm->cm_complete = mpssas_target_reset_complete;
1374ef065d89SStephen McConnell 		mpssas_prepare_for_tm(sc, tm, target, CAM_LUN_WILDCARD);
13756eea4f46SScott Long 	} else {
13761610f95cSScott Long 		mps_dprint(sc, MPS_ERROR, "unexpected reset type 0x%x\n", type);
1377d043c564SKenneth D. Merry 		return -1;
1378d043c564SKenneth D. Merry 	}
1379d043c564SKenneth D. Merry 
1380d043c564SKenneth D. Merry 	tm->cm_data = NULL;
1381d043c564SKenneth D. Merry 	tm->cm_complete_data = (void *)tm;
1382d043c564SKenneth D. Merry 
1383d043c564SKenneth D. Merry 	callout_reset(&tm->cm_callout, MPS_RESET_TIMEOUT * hz,
1384d043c564SKenneth D. Merry 	    mpssas_tm_timeout, tm);
1385d043c564SKenneth D. Merry 
1386d043c564SKenneth D. Merry 	err = mps_map_command(sc, tm);
1387d043c564SKenneth D. Merry 	if (err)
13886eea4f46SScott Long 		mps_dprint(sc, MPS_ERROR|MPS_RECOVERY,
1389d043c564SKenneth D. Merry 		    "error %d sending reset type %u\n",
1390d043c564SKenneth D. Merry 		    err, type);
1391d043c564SKenneth D. Merry 
1392d043c564SKenneth D. Merry 	return err;
1393d043c564SKenneth D. Merry }
1394d043c564SKenneth D. Merry 
1395d043c564SKenneth D. Merry static void
mpssas_abort_complete(struct mps_softc * sc,struct mps_command * tm)1396d043c564SKenneth D. Merry mpssas_abort_complete(struct mps_softc *sc, struct mps_command *tm)
1397d043c564SKenneth D. Merry {
1398d043c564SKenneth D. Merry 	struct mps_command *cm;
1399d043c564SKenneth D. Merry 	MPI2_SCSI_TASK_MANAGE_REPLY *reply;
1400d043c564SKenneth D. Merry 	MPI2_SCSI_TASK_MANAGE_REQUEST *req;
1401d043c564SKenneth D. Merry 	struct mpssas_target *targ;
1402d043c564SKenneth D. Merry 
1403d043c564SKenneth D. Merry 	callout_stop(&tm->cm_callout);
1404d043c564SKenneth D. Merry 
1405d043c564SKenneth D. Merry 	req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req;
1406d043c564SKenneth D. Merry 	reply = (MPI2_SCSI_TASK_MANAGE_REPLY *)tm->cm_reply;
1407d043c564SKenneth D. Merry 	targ = tm->cm_targ;
1408d043c564SKenneth D. Merry 
1409d043c564SKenneth D. Merry 	/*
1410d043c564SKenneth D. Merry 	 * Currently there should be no way we can hit this case.  It only
1411d043c564SKenneth D. Merry 	 * happens when we have a failure to allocate chain frames, and
1412d043c564SKenneth D. Merry 	 * task management commands don't have S/G lists.
1413d043c564SKenneth D. Merry 	 */
1414d043c564SKenneth D. Merry 	if ((tm->cm_flags & MPS_CM_FLAGS_ERROR_MASK) != 0) {
14156eea4f46SScott Long 		mps_dprint(sc, MPS_RECOVERY,
1416d043c564SKenneth D. Merry 		    "cm_flags = %#x for abort %p TaskMID %u!\n",
1417be4aa869SKenneth D. Merry 		    tm->cm_flags, tm, le16toh(req->TaskMID));
1418d043c564SKenneth D. Merry 		mpssas_free_tm(sc, tm);
1419d043c564SKenneth D. Merry 		return;
1420d043c564SKenneth D. Merry 	}
1421d043c564SKenneth D. Merry 
1422d043c564SKenneth D. Merry 	if (reply == NULL) {
14236eea4f46SScott Long 		mps_dprint(sc, MPS_RECOVERY,
1424d043c564SKenneth D. Merry 		    "NULL abort reply for tm %p TaskMID %u\n",
1425be4aa869SKenneth D. Merry 		    tm, le16toh(req->TaskMID));
1426d043c564SKenneth D. Merry 		if ((sc->mps_flags & MPS_FLAGS_DIAGRESET) != 0) {
1427d043c564SKenneth D. Merry 			/* this completion was due to a reset, just cleanup */
14286eea4f46SScott Long 			mps_dprint(sc, MPS_RECOVERY, "Hardware undergoing "
14296eea4f46SScott Long 			    "reset, ignoring NULL abort reply\n");
1430d043c564SKenneth D. Merry 			targ->tm = NULL;
1431d043c564SKenneth D. Merry 			mpssas_free_tm(sc, tm);
14326eea4f46SScott Long 		} else {
1433d043c564SKenneth D. Merry 			/* we should have gotten a reply. */
14346eea4f46SScott Long 			mps_dprint(sc, MPS_INFO|MPS_RECOVERY, "NULL reply on "
14356eea4f46SScott Long 			    "abort attempt, resetting controller\n");
1436d043c564SKenneth D. Merry 			mps_reinit(sc);
1437d043c564SKenneth D. Merry 		}
1438d043c564SKenneth D. Merry 		return;
1439d043c564SKenneth D. Merry 	}
1440d043c564SKenneth D. Merry 
14416eea4f46SScott Long 	mps_dprint(sc, MPS_RECOVERY,
1442d043c564SKenneth D. Merry 	    "abort TaskMID %u status 0x%x code 0x%x count %u\n",
1443be4aa869SKenneth D. Merry 	    le16toh(req->TaskMID),
1444be4aa869SKenneth D. Merry 	    le16toh(reply->IOCStatus), le32toh(reply->ResponseCode),
1445be4aa869SKenneth D. Merry 	    le32toh(reply->TerminationCount));
1446d043c564SKenneth D. Merry 
1447d043c564SKenneth D. Merry 	cm = TAILQ_FIRST(&tm->cm_targ->timedout_commands);
1448d043c564SKenneth D. Merry 	if (cm == NULL) {
14496eea4f46SScott Long 		/*
14506eea4f46SScott Long 		 * If there are no more timedout commands, we're done with
1451d043c564SKenneth D. Merry 		 * error recovery for this target.
1452d043c564SKenneth D. Merry 		 */
14536eea4f46SScott Long 		mps_dprint(sc, MPS_INFO|MPS_RECOVERY,
14546eea4f46SScott Long 		    "Finished abort recovery for target %u\n", targ->tid);
1455d043c564SKenneth D. Merry 
1456d043c564SKenneth D. Merry 		targ->tm = NULL;
1457d043c564SKenneth D. Merry 		mpssas_free_tm(sc, tm);
14586eea4f46SScott Long 	} else if (le16toh(req->TaskMID) != cm->cm_desc.Default.SMID) {
1459d043c564SKenneth D. Merry 		/* abort success, but we have more timedout commands to abort */
14606eea4f46SScott Long 		mps_dprint(sc, MPS_INFO|MPS_RECOVERY,
14616eea4f46SScott Long 		    "Continuing abort recovery for target %u\n", targ->tid);
1462d043c564SKenneth D. Merry 
1463d043c564SKenneth D. Merry 		mpssas_send_abort(sc, tm, cm);
14646eea4f46SScott Long 	} else {
1465d043c564SKenneth D. Merry 		/* we didn't get a command completion, so the abort
1466d043c564SKenneth D. Merry 		 * failed as far as we're concerned.  escalate.
1467d043c564SKenneth D. Merry 		 */
14686eea4f46SScott Long 		mps_dprint(sc, MPS_RECOVERY,
14696eea4f46SScott Long 		    "Abort failed for target %u, sending logical unit reset\n",
14706eea4f46SScott Long 		    targ->tid);
1471d043c564SKenneth D. Merry 
1472d043c564SKenneth D. Merry 		mpssas_send_reset(sc, tm,
1473d043c564SKenneth D. Merry 		    MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET);
1474d043c564SKenneth D. Merry 	}
1475d043c564SKenneth D. Merry }
1476d043c564SKenneth D. Merry 
1477d043c564SKenneth D. Merry #define MPS_ABORT_TIMEOUT 5
1478d043c564SKenneth D. Merry 
1479d043c564SKenneth D. Merry static int
mpssas_send_abort(struct mps_softc * sc,struct mps_command * tm,struct mps_command * cm)1480d043c564SKenneth D. Merry mpssas_send_abort(struct mps_softc *sc, struct mps_command *tm, struct mps_command *cm)
1481d043c564SKenneth D. Merry {
1482d043c564SKenneth D. Merry 	MPI2_SCSI_TASK_MANAGE_REQUEST *req;
1483d043c564SKenneth D. Merry 	struct mpssas_target *targ;
1484d043c564SKenneth D. Merry 	int err;
1485d043c564SKenneth D. Merry 
1486d043c564SKenneth D. Merry 	targ = cm->cm_targ;
1487d043c564SKenneth D. Merry 	if (targ->handle == 0) {
14886eea4f46SScott Long 		mps_dprint(sc, MPS_ERROR|MPS_RECOVERY,
14896eea4f46SScott Long 		    "%s null devhandle for target_id %d\n",
1490d043c564SKenneth D. Merry 		    __func__, cm->cm_ccb->ccb_h.target_id);
1491d043c564SKenneth D. Merry 		return -1;
1492d043c564SKenneth D. Merry 	}
1493d043c564SKenneth D. Merry 
1494855fe445SScott Long 	mpssas_log_command(cm, MPS_RECOVERY|MPS_INFO,
14951610f95cSScott Long 	    "Aborting command %p\n", cm);
14961610f95cSScott Long 
1497d043c564SKenneth D. Merry 	req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req;
1498be4aa869SKenneth D. Merry 	req->DevHandle = htole16(targ->handle);
1499d3c7b9a0SKenneth D. Merry 	req->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK;
1500d3c7b9a0SKenneth D. Merry 
1501d043c564SKenneth D. Merry 	/* XXX Need to handle invalid LUNs */
1502d043c564SKenneth D. Merry 	MPS_SET_LUN(req->LUN, cm->cm_ccb->ccb_h.target_lun);
1503d3c7b9a0SKenneth D. Merry 
1504be4aa869SKenneth D. Merry 	req->TaskMID = htole16(cm->cm_desc.Default.SMID);
15051476ba40SKenneth D. Merry 
1506d043c564SKenneth D. Merry 	tm->cm_data = NULL;
1507d043c564SKenneth D. Merry 	tm->cm_complete = mpssas_abort_complete;
1508d043c564SKenneth D. Merry 	tm->cm_complete_data = (void *)tm;
1509d043c564SKenneth D. Merry 	tm->cm_targ = cm->cm_targ;
1510d043c564SKenneth D. Merry 	tm->cm_lun = cm->cm_lun;
1511d043c564SKenneth D. Merry 
1512d043c564SKenneth D. Merry 	callout_reset(&tm->cm_callout, MPS_ABORT_TIMEOUT * hz,
1513d043c564SKenneth D. Merry 	    mpssas_tm_timeout, tm);
1514d043c564SKenneth D. Merry 
1515d043c564SKenneth D. Merry 	targ->aborts++;
1516d043c564SKenneth D. Merry 
1517ef065d89SStephen McConnell 	mpssas_prepare_for_tm(sc, tm, targ, tm->cm_lun);
1518ef065d89SStephen McConnell 
1519d043c564SKenneth D. Merry 	err = mps_map_command(sc, tm);
1520d043c564SKenneth D. Merry 	if (err)
15216eea4f46SScott Long 		mps_dprint(sc, MPS_ERROR|MPS_RECOVERY,
1522d043c564SKenneth D. Merry 		    "error %d sending abort for cm %p SMID %u\n",
1523d043c564SKenneth D. Merry 		    err, cm, req->TaskMID);
1524d043c564SKenneth D. Merry 	return err;
15251476ba40SKenneth D. Merry }
15261476ba40SKenneth D. Merry 
15271476ba40SKenneth D. Merry static void
mpssas_scsiio_timeout(void * data)1528d043c564SKenneth D. Merry mpssas_scsiio_timeout(void *data)
15291476ba40SKenneth D. Merry {
15306eea4f46SScott Long 	sbintime_t elapsed, now;
15316eea4f46SScott Long 	union ccb *ccb;
1532d043c564SKenneth D. Merry 	struct mps_softc *sc;
1533d043c564SKenneth D. Merry 	struct mps_command *cm;
1534d043c564SKenneth D. Merry 	struct mpssas_target *targ;
15351476ba40SKenneth D. Merry 
1536d043c564SKenneth D. Merry 	cm = (struct mps_command *)data;
1537d043c564SKenneth D. Merry 	sc = cm->cm_sc;
15386eea4f46SScott Long 	ccb = cm->cm_ccb;
15396eea4f46SScott Long 	now = sbinuptime();
15401476ba40SKenneth D. Merry 
15411610f95cSScott Long 	MPS_FUNCTRACE(sc);
15421476ba40SKenneth D. Merry 	mtx_assert(&sc->mps_mtx, MA_OWNED);
15431476ba40SKenneth D. Merry 
1544b086bc0bSWarner Losh 	mps_dprint(sc, MPS_XINFO|MPS_RECOVERY, "Timeout checking cm %p\n", cm);
1545d3c7b9a0SKenneth D. Merry 
15461476ba40SKenneth D. Merry 	/*
1547d043c564SKenneth D. Merry 	 * Run the interrupt handler to make sure it's not pending.  This
1548d043c564SKenneth D. Merry 	 * isn't perfect because the command could have already completed
1549d043c564SKenneth D. Merry 	 * and been re-used, though this is unlikely.
15501476ba40SKenneth D. Merry 	 */
1551d043c564SKenneth D. Merry 	mps_intr_locked(sc);
15528fe7bf06SWarner Losh 	if (cm->cm_flags & MPS_CM_FLAGS_ON_RECOVERY) {
15531610f95cSScott Long 		mpssas_log_command(cm, MPS_XINFO,
15541610f95cSScott Long 		    "SCSI command %p almost timed out\n", cm);
1555d043c564SKenneth D. Merry 		return;
15561476ba40SKenneth D. Merry 	}
15571476ba40SKenneth D. Merry 
1558d043c564SKenneth D. Merry 	if (cm->cm_ccb == NULL) {
15591610f95cSScott Long 		mps_dprint(sc, MPS_ERROR, "command timeout with NULL ccb\n");
1560d043c564SKenneth D. Merry 		return;
15611476ba40SKenneth D. Merry 	}
15621476ba40SKenneth D. Merry 
1563d043c564SKenneth D. Merry 	targ = cm->cm_targ;
1564d043c564SKenneth D. Merry 	targ->timeouts++;
1565d043c564SKenneth D. Merry 
15666eea4f46SScott Long 	elapsed = now - ccb->ccb_h.qos.sim_data;
15676eea4f46SScott Long 	mpssas_log_command(cm, MPS_INFO|MPS_RECOVERY,
15686eea4f46SScott Long 	    "Command timeout on target %u(0x%04x) %d set, %d.%d elapsed\n",
15696eea4f46SScott Long 	    targ->tid, targ->handle, ccb->ccb_h.timeout,
15706eea4f46SScott Long 	    sbintime_getsec(elapsed), elapsed & 0xffffffff);
1571855fe445SScott Long 
1572d043c564SKenneth D. Merry 	/* XXX first, check the firmware state, to see if it's still
1573d043c564SKenneth D. Merry 	 * operational.  if not, do a diag reset.
15741476ba40SKenneth D. Merry 	 */
1575601781ccSScott Long 	mpssas_set_ccbstatus(cm->cm_ccb, CAM_CMD_TIMEOUT);
15768fe7bf06SWarner Losh 	cm->cm_flags |= MPS_CM_FLAGS_ON_RECOVERY | MPS_CM_FLAGS_TIMEDOUT;
1577d043c564SKenneth D. Merry 	TAILQ_INSERT_TAIL(&targ->timedout_commands, cm, cm_recovery);
15781476ba40SKenneth D. Merry 
1579d043c564SKenneth D. Merry 	if (targ->tm != NULL) {
1580d043c564SKenneth D. Merry 		/* target already in recovery, just queue up another
1581d043c564SKenneth D. Merry 		 * timedout command to be processed later.
15821476ba40SKenneth D. Merry 		 */
15831610f95cSScott Long 		mps_dprint(sc, MPS_RECOVERY,
15841610f95cSScott Long 		    "queued timedout cm %p for processing by tm %p\n",
1585d043c564SKenneth D. Merry 		    cm, targ->tm);
15866eea4f46SScott Long 	} else if ((targ->tm = mpssas_alloc_tm(sc)) != NULL) {
15876eea4f46SScott Long 		mps_dprint(sc, MPS_RECOVERY|MPS_INFO,
15886eea4f46SScott Long 		    "Sending abort to target %u for SMID %d\n", targ->tid,
15896eea4f46SScott Long 		    cm->cm_desc.Default.SMID);
15901610f95cSScott Long 		mps_dprint(sc, MPS_RECOVERY, "timedout cm %p allocated tm %p\n",
1591d043c564SKenneth D. Merry 		    cm, targ->tm);
15921476ba40SKenneth D. Merry 
1593d043c564SKenneth D. Merry 		/* start recovery by aborting the first timedout command */
1594d043c564SKenneth D. Merry 		mpssas_send_abort(sc, targ->tm, cm);
15956eea4f46SScott Long 	} else {
1596d043c564SKenneth D. Merry 		/* XXX queue this target up for recovery once a TM becomes
1597d043c564SKenneth D. Merry 		 * available.  The firmware only has a limited number of
1598d043c564SKenneth D. Merry 		 * HighPriority credits for the high priority requests used
1599d043c564SKenneth D. Merry 		 * for task management, and we ran out.
16001476ba40SKenneth D. Merry 		 *
1601d043c564SKenneth D. Merry 		 * Isilon: don't worry about this for now, since we have
1602d043c564SKenneth D. Merry 		 * more credits than disks in an enclosure, and limit
1603d043c564SKenneth D. Merry 		 * ourselves to one TM per target for recovery.
16041476ba40SKenneth D. Merry 		 */
16056eea4f46SScott Long 		mps_dprint(sc, MPS_ERROR|MPS_RECOVERY,
16061610f95cSScott Long 		    "timedout cm %p failed to allocate a tm\n", cm);
1607d3c7b9a0SKenneth D. Merry 	}
1608d3c7b9a0SKenneth D. Merry 
1609d3c7b9a0SKenneth D. Merry }
1610d3c7b9a0SKenneth D. Merry 
1611d3c7b9a0SKenneth D. Merry static void
mpssas_action_scsiio(struct mpssas_softc * sassc,union ccb * ccb)1612d3c7b9a0SKenneth D. Merry mpssas_action_scsiio(struct mpssas_softc *sassc, union ccb *ccb)
1613d3c7b9a0SKenneth D. Merry {
1614d3c7b9a0SKenneth D. Merry 	MPI2_SCSI_IO_REQUEST *req;
1615d3c7b9a0SKenneth D. Merry 	struct ccb_scsiio *csio;
1616d3c7b9a0SKenneth D. Merry 	struct mps_softc *sc;
1617d3c7b9a0SKenneth D. Merry 	struct mpssas_target *targ;
1618d043c564SKenneth D. Merry 	struct mpssas_lun *lun;
1619d3c7b9a0SKenneth D. Merry 	struct mps_command *cm;
1620d043c564SKenneth D. Merry 	uint8_t i, lba_byte, *ref_tag_addr;
1621d043c564SKenneth D. Merry 	uint16_t eedp_flags;
1622be4aa869SKenneth D. Merry 	uint32_t mpi_control;
1623d3c7b9a0SKenneth D. Merry 
1624d3c7b9a0SKenneth D. Merry 	sc = sassc->sc;
16251610f95cSScott Long 	MPS_FUNCTRACE(sc);
1626d043c564SKenneth D. Merry 	mtx_assert(&sc->mps_mtx, MA_OWNED);
1627d3c7b9a0SKenneth D. Merry 
1628d3c7b9a0SKenneth D. Merry 	csio = &ccb->csio;
162908235773SScott Long 	KASSERT(csio->ccb_h.target_id < sassc->maxtargets,
163008235773SScott Long 	    ("Target %d out of bounds in XPT_SCSI_IO\n",
163108235773SScott Long 	     csio->ccb_h.target_id));
1632d3c7b9a0SKenneth D. Merry 	targ = &sassc->targets[csio->ccb_h.target_id];
16331610f95cSScott Long 	mps_dprint(sc, MPS_TRACE, "ccb %p target flag %x\n", ccb, targ->flags);
1634d3c7b9a0SKenneth D. Merry 	if (targ->handle == 0x0) {
1635e35816c1SWarner Losh 		if (targ->flags & MPSSAS_TARGET_INDIAGRESET) {
1636e35816c1SWarner Losh 			mps_dprint(sc, MPS_ERROR,
1637e35816c1SWarner Losh 			    "%s NULL handle for target %u in diag reset freezing queue\n",
1638e35816c1SWarner Losh 			    __func__, csio->ccb_h.target_id);
1639e35816c1SWarner Losh 			ccb->ccb_h.status = CAM_REQUEUE_REQ | CAM_DEV_QFRZN;
1640e35816c1SWarner Losh 			xpt_freeze_devq(ccb->ccb_h.path, 1);
1641e35816c1SWarner Losh 			xpt_done(ccb);
1642e35816c1SWarner Losh 			return;
1643e35816c1SWarner Losh 		}
16441610f95cSScott Long 		mps_dprint(sc, MPS_ERROR, "%s NULL handle for target %u\n",
1645d043c564SKenneth D. Merry 		    __func__, csio->ccb_h.target_id);
16467571e7f6SSteven Hartland 		mpssas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE);
1647d043c564SKenneth D. Merry 		xpt_done(ccb);
1648d043c564SKenneth D. Merry 		return;
1649d043c564SKenneth D. Merry 	}
1650653c521fSKenneth D. Merry 	if (targ->flags & MPS_TARGET_FLAGS_RAID_COMPONENT) {
16519b91b192SKenneth D. Merry 		mps_dprint(sc, MPS_ERROR, "%s Raid component no SCSI IO "
16529b91b192SKenneth D. Merry 		    "supported %u\n", __func__, csio->ccb_h.target_id);
16537571e7f6SSteven Hartland 		mpssas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE);
1654653c521fSKenneth D. Merry 		xpt_done(ccb);
1655653c521fSKenneth D. Merry 		return;
1656653c521fSKenneth D. Merry 	}
1657d043c564SKenneth D. Merry 	/*
16589b91b192SKenneth D. Merry 	 * Sometimes, it is possible to get a command that is not "In
16599b91b192SKenneth D. Merry 	 * Progress" and was actually aborted by the upper layer.  Check for
16609b91b192SKenneth D. Merry 	 * this here and complete the command without error.
16619b91b192SKenneth D. Merry 	 */
1662601781ccSScott Long 	if (mpssas_get_ccbstatus(ccb) != CAM_REQ_INPROG) {
16639b91b192SKenneth D. Merry 		mps_dprint(sc, MPS_TRACE, "%s Command is not in progress for "
16649b91b192SKenneth D. Merry 		    "target %u\n", __func__, csio->ccb_h.target_id);
16659b91b192SKenneth D. Merry 		xpt_done(ccb);
16669b91b192SKenneth D. Merry 		return;
16679b91b192SKenneth D. Merry 	}
16689b91b192SKenneth D. Merry 	/*
1669d043c564SKenneth D. Merry 	 * If devinfo is 0 this will be a volume.  In that case don't tell CAM
1670d043c564SKenneth D. Merry 	 * that the volume has timed out.  We want volumes to be enumerated
16714c1cdd4aSWarner Losh 	 * until they are deleted/removed, not just failed. In either event,
16724c1cdd4aSWarner Losh 	 * we're removing the target due to a firmware event telling us
16734c1cdd4aSWarner Losh 	 * the device is now gone (as opposed to some transient event). Since
16744c1cdd4aSWarner Losh 	 * we're opting to remove failed devices from the OS's view, we need
16754c1cdd4aSWarner Losh 	 * to propagate that status up the stack.
1676d043c564SKenneth D. Merry 	 */
1677d043c564SKenneth D. Merry 	if (targ->flags & MPSSAS_TARGET_INREMOVAL) {
1678d043c564SKenneth D. Merry 		if (targ->devinfo == 0)
1679601781ccSScott Long 			mpssas_set_ccbstatus(ccb, CAM_REQ_CMP);
1680d043c564SKenneth D. Merry 		else
16814c1cdd4aSWarner Losh 			mpssas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE);
1682d3c7b9a0SKenneth D. Merry 		xpt_done(ccb);
1683d3c7b9a0SKenneth D. Merry 		return;
1684d3c7b9a0SKenneth D. Merry 	}
1685d3c7b9a0SKenneth D. Merry 
1686d043c564SKenneth D. Merry 	if ((sc->mps_flags & MPS_FLAGS_SHUTDOWN) != 0) {
16871610f95cSScott Long 		mps_dprint(sc, MPS_INFO, "%s shutting down\n", __func__);
16887571e7f6SSteven Hartland 		mpssas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE);
1689d043c564SKenneth D. Merry 		xpt_done(ccb);
1690d043c564SKenneth D. Merry 		return;
1691d043c564SKenneth D. Merry 	}
1692d043c564SKenneth D. Merry 
1693ef065d89SStephen McConnell 	/*
1694db0ac6deSCy Schubert 	 * If target has a reset in progress, the devq should be frozen.
1695db0ac6deSCy Schubert 	 * Geting here we likely hit a race, so just requeue.
1696ef065d89SStephen McConnell 	 */
1697ef065d89SStephen McConnell 	if (targ->flags & MPSSAS_TARGET_INRESET) {
1698db0ac6deSCy Schubert 		ccb->ccb_h.status = CAM_REQUEUE_REQ | CAM_DEV_QFRZN;
1699ef065d89SStephen McConnell 		mps_dprint(sc, MPS_INFO, "%s: Freezing devq for target ID %d\n",
1700ef065d89SStephen McConnell 		    __func__, targ->tid);
1701ef065d89SStephen McConnell 		xpt_freeze_devq(ccb->ccb_h.path, 1);
1702ef065d89SStephen McConnell 		xpt_done(ccb);
1703ef065d89SStephen McConnell 		return;
1704ef065d89SStephen McConnell 	}
1705ef065d89SStephen McConnell 
1706d3c7b9a0SKenneth D. Merry 	cm = mps_alloc_command(sc);
17077571e7f6SSteven Hartland 	if (cm == NULL || (sc->mps_flags & MPS_FLAGS_DIAGRESET)) {
17087571e7f6SSteven Hartland 		if (cm != NULL) {
17097571e7f6SSteven Hartland 			mps_free_command(sc, cm);
17107571e7f6SSteven Hartland 		}
1711d3c7b9a0SKenneth D. Merry 		if ((sassc->flags & MPSSAS_QUEUE_FROZEN) == 0) {
1712d3c7b9a0SKenneth D. Merry 			xpt_freeze_simq(sassc->sim, 1);
1713d3c7b9a0SKenneth D. Merry 			sassc->flags |= MPSSAS_QUEUE_FROZEN;
1714d3c7b9a0SKenneth D. Merry 		}
1715d3c7b9a0SKenneth D. Merry 		ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
1716d3c7b9a0SKenneth D. Merry 		ccb->ccb_h.status |= CAM_REQUEUE_REQ;
1717d3c7b9a0SKenneth D. Merry 		xpt_done(ccb);
1718d3c7b9a0SKenneth D. Merry 		return;
1719d3c7b9a0SKenneth D. Merry 	}
1720d3c7b9a0SKenneth D. Merry 
1721d3c7b9a0SKenneth D. Merry 	req = (MPI2_SCSI_IO_REQUEST *)cm->cm_req;
1722550e2acdSKenneth D. Merry 	bzero(req, sizeof(*req));
1723be4aa869SKenneth D. Merry 	req->DevHandle = htole16(targ->handle);
1724d3c7b9a0SKenneth D. Merry 	req->Function = MPI2_FUNCTION_SCSI_IO_REQUEST;
1725d3c7b9a0SKenneth D. Merry 	req->MsgFlags = 0;
1726be4aa869SKenneth D. Merry 	req->SenseBufferLowAddress = htole32(cm->cm_sense_busaddr);
1727d3c7b9a0SKenneth D. Merry 	req->SenseBufferLength = MPS_SENSE_LEN;
1728d3c7b9a0SKenneth D. Merry 	req->SGLFlags = 0;
1729d3c7b9a0SKenneth D. Merry 	req->ChainOffset = 0;
1730d3c7b9a0SKenneth D. Merry 	req->SGLOffset0 = 24;	/* 32bit word offset to the SGL */
1731d3c7b9a0SKenneth D. Merry 	req->SGLOffset1= 0;
1732d3c7b9a0SKenneth D. Merry 	req->SGLOffset2= 0;
1733d3c7b9a0SKenneth D. Merry 	req->SGLOffset3= 0;
1734d3c7b9a0SKenneth D. Merry 	req->SkipCount = 0;
1735be4aa869SKenneth D. Merry 	req->DataLength = htole32(csio->dxfer_len);
1736d3c7b9a0SKenneth D. Merry 	req->BidirectionalDataLength = 0;
1737be4aa869SKenneth D. Merry 	req->IoFlags = htole16(csio->cdb_len);
1738d3c7b9a0SKenneth D. Merry 	req->EEDPFlags = 0;
1739d3c7b9a0SKenneth D. Merry 
1740d3c7b9a0SKenneth D. Merry 	/* Note: BiDirectional transfers are not supported */
1741d3c7b9a0SKenneth D. Merry 	switch (csio->ccb_h.flags & CAM_DIR_MASK) {
1742d3c7b9a0SKenneth D. Merry 	case CAM_DIR_IN:
1743be4aa869SKenneth D. Merry 		mpi_control = MPI2_SCSIIO_CONTROL_READ;
1744d3c7b9a0SKenneth D. Merry 		cm->cm_flags |= MPS_CM_FLAGS_DATAIN;
1745d3c7b9a0SKenneth D. Merry 		break;
1746d3c7b9a0SKenneth D. Merry 	case CAM_DIR_OUT:
1747be4aa869SKenneth D. Merry 		mpi_control = MPI2_SCSIIO_CONTROL_WRITE;
1748d3c7b9a0SKenneth D. Merry 		cm->cm_flags |= MPS_CM_FLAGS_DATAOUT;
1749d3c7b9a0SKenneth D. Merry 		break;
1750d3c7b9a0SKenneth D. Merry 	case CAM_DIR_NONE:
1751d3c7b9a0SKenneth D. Merry 	default:
1752be4aa869SKenneth D. Merry 		mpi_control = MPI2_SCSIIO_CONTROL_NODATATRANSFER;
1753d3c7b9a0SKenneth D. Merry 		break;
1754d3c7b9a0SKenneth D. Merry 	}
1755d3c7b9a0SKenneth D. Merry 
1756be4aa869SKenneth D. Merry 	if (csio->cdb_len == 32)
1757be4aa869SKenneth D. Merry                 mpi_control |= 4 << MPI2_SCSIIO_CONTROL_ADDCDBLEN_SHIFT;
1758d3c7b9a0SKenneth D. Merry 	/*
1759d3c7b9a0SKenneth D. Merry 	 * It looks like the hardware doesn't require an explicit tag
1760d3c7b9a0SKenneth D. Merry 	 * number for each transaction.  SAM Task Management not supported
1761d3c7b9a0SKenneth D. Merry 	 * at the moment.
1762d3c7b9a0SKenneth D. Merry 	 */
1763d3c7b9a0SKenneth D. Merry 	switch (csio->tag_action) {
1764d3c7b9a0SKenneth D. Merry 	case MSG_HEAD_OF_Q_TAG:
1765be4aa869SKenneth D. Merry 		mpi_control |= MPI2_SCSIIO_CONTROL_HEADOFQ;
1766d3c7b9a0SKenneth D. Merry 		break;
1767d3c7b9a0SKenneth D. Merry 	case MSG_ORDERED_Q_TAG:
1768be4aa869SKenneth D. Merry 		mpi_control |= MPI2_SCSIIO_CONTROL_ORDEREDQ;
1769d3c7b9a0SKenneth D. Merry 		break;
1770d3c7b9a0SKenneth D. Merry 	case MSG_ACA_TASK:
1771be4aa869SKenneth D. Merry 		mpi_control |= MPI2_SCSIIO_CONTROL_ACAQ;
1772d3c7b9a0SKenneth D. Merry 		break;
1773d3c7b9a0SKenneth D. Merry 	case CAM_TAG_ACTION_NONE:
1774d3c7b9a0SKenneth D. Merry 	case MSG_SIMPLE_Q_TAG:
1775d3c7b9a0SKenneth D. Merry 	default:
1776be4aa869SKenneth D. Merry 		mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ;
1777d3c7b9a0SKenneth D. Merry 		break;
1778d3c7b9a0SKenneth D. Merry 	}
177988364968SAlexander Motin 	mpi_control |= (csio->priority << MPI2_SCSIIO_CONTROL_TASKPRI_SHIFT) &
178088364968SAlexander Motin 	    MPI2_SCSIIO_CONTROL_TASKPRI_MASK;
1781be4aa869SKenneth D. Merry 	mpi_control |= sc->mapping_table[csio->ccb_h.target_id].TLR_bits;
1782be4aa869SKenneth D. Merry 	req->Control = htole32(mpi_control);
1783d970279cSKenneth D. Merry 	if (MPS_SET_LUN(req->LUN, csio->ccb_h.target_lun) != 0) {
1784d3c7b9a0SKenneth D. Merry 		mps_free_command(sc, cm);
1785601781ccSScott Long 		mpssas_set_ccbstatus(ccb, CAM_LUN_INVALID);
1786d3c7b9a0SKenneth D. Merry 		xpt_done(ccb);
1787d3c7b9a0SKenneth D. Merry 		return;
1788d3c7b9a0SKenneth D. Merry 	}
1789d3c7b9a0SKenneth D. Merry 
1790d3c7b9a0SKenneth D. Merry 	if (csio->ccb_h.flags & CAM_CDB_POINTER)
1791d3c7b9a0SKenneth D. Merry 		bcopy(csio->cdb_io.cdb_ptr, &req->CDB.CDB32[0], csio->cdb_len);
1792d3c7b9a0SKenneth D. Merry 	else
1793d3c7b9a0SKenneth D. Merry 		bcopy(csio->cdb_io.cdb_bytes, &req->CDB.CDB32[0],csio->cdb_len);
1794be4aa869SKenneth D. Merry 	req->IoFlags = htole16(csio->cdb_len);
1795d3c7b9a0SKenneth D. Merry 
179606e79492SKenneth D. Merry 	/*
1797d043c564SKenneth D. Merry 	 * Check if EEDP is supported and enabled.  If it is then check if the
1798d043c564SKenneth D. Merry 	 * SCSI opcode could be using EEDP.  If so, make sure the LUN exists and
1799d043c564SKenneth D. Merry 	 * is formatted for EEDP support.  If all of this is true, set CDB up
1800d043c564SKenneth D. Merry 	 * for EEDP transfer.
180106e79492SKenneth D. Merry 	 */
1802d043c564SKenneth D. Merry 	eedp_flags = op_code_prot[req->CDB.CDB32[0]];
1803d043c564SKenneth D. Merry 	if (sc->eedp_enabled && eedp_flags) {
1804d043c564SKenneth D. Merry 		SLIST_FOREACH(lun, &targ->luns, lun_link) {
1805d043c564SKenneth D. Merry 			if (lun->lun_id == csio->ccb_h.target_lun) {
1806d043c564SKenneth D. Merry 				break;
1807d043c564SKenneth D. Merry 			}
1808d043c564SKenneth D. Merry 		}
1809d043c564SKenneth D. Merry 
1810d043c564SKenneth D. Merry 		if ((lun != NULL) && (lun->eedp_formatted)) {
1811be4aa869SKenneth D. Merry 			req->EEDPBlockSize = htole16(lun->eedp_block_size);
1812d043c564SKenneth D. Merry 			eedp_flags |= (MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG |
1813d043c564SKenneth D. Merry 			    MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG |
1814d043c564SKenneth D. Merry 			    MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD);
1815be4aa869SKenneth D. Merry 			req->EEDPFlags = htole16(eedp_flags);
1816d043c564SKenneth D. Merry 
1817d043c564SKenneth D. Merry 			/*
1818d043c564SKenneth D. Merry 			 * If CDB less than 32, fill in Primary Ref Tag with
1819d043c564SKenneth D. Merry 			 * low 4 bytes of LBA.  If CDB is 32, tag stuff is
1820d043c564SKenneth D. Merry 			 * already there.  Also, set protection bit.  FreeBSD
1821d043c564SKenneth D. Merry 			 * currently does not support CDBs bigger than 16, but
1822d043c564SKenneth D. Merry 			 * the code doesn't hurt, and will be here for the
1823d043c564SKenneth D. Merry 			 * future.
1824d043c564SKenneth D. Merry 			 */
1825d043c564SKenneth D. Merry 			if (csio->cdb_len != 32) {
1826d043c564SKenneth D. Merry 				lba_byte = (csio->cdb_len == 16) ? 6 : 2;
1827d043c564SKenneth D. Merry 				ref_tag_addr = (uint8_t *)&req->CDB.EEDP32.
1828d043c564SKenneth D. Merry 				    PrimaryReferenceTag;
1829d043c564SKenneth D. Merry 				for (i = 0; i < 4; i++) {
1830d043c564SKenneth D. Merry 					*ref_tag_addr =
1831d043c564SKenneth D. Merry 					    req->CDB.CDB32[lba_byte + i];
1832d043c564SKenneth D. Merry 					ref_tag_addr++;
1833d043c564SKenneth D. Merry 				}
1834be4aa869SKenneth D. Merry 				req->CDB.EEDP32.PrimaryReferenceTag =
1835be4aa869SKenneth D. Merry 					htole32(req->CDB.EEDP32.PrimaryReferenceTag);
1836d043c564SKenneth D. Merry 				req->CDB.EEDP32.PrimaryApplicationTagMask =
1837d043c564SKenneth D. Merry 				    0xFFFF;
1838d043c564SKenneth D. Merry 				req->CDB.CDB32[1] = (req->CDB.CDB32[1] & 0x1F) |
1839d043c564SKenneth D. Merry 				    0x20;
1840d043c564SKenneth D. Merry 			} else {
1841d043c564SKenneth D. Merry 				eedp_flags |=
1842d043c564SKenneth D. Merry 				    MPI2_SCSIIO_EEDPFLAGS_INC_PRI_APPTAG;
1843be4aa869SKenneth D. Merry 				req->EEDPFlags = htole16(eedp_flags);
1844d043c564SKenneth D. Merry 				req->CDB.CDB32[10] = (req->CDB.CDB32[10] &
1845d043c564SKenneth D. Merry 				    0x1F) | 0x20;
1846d043c564SKenneth D. Merry 			}
1847d043c564SKenneth D. Merry 		}
1848d043c564SKenneth D. Merry 	}
1849d043c564SKenneth D. Merry 
1850d3c7b9a0SKenneth D. Merry 	cm->cm_length = csio->dxfer_len;
1851dd0b4fb6SKonstantin Belousov 	if (cm->cm_length != 0) {
1852dd0b4fb6SKonstantin Belousov 		cm->cm_data = ccb;
1853dd0b4fb6SKonstantin Belousov 		cm->cm_flags |= MPS_CM_FLAGS_USE_CCB;
1854dd0b4fb6SKonstantin Belousov 	} else {
1855dd0b4fb6SKonstantin Belousov 		cm->cm_data = NULL;
1856dd0b4fb6SKonstantin Belousov 	}
1857d3c7b9a0SKenneth D. Merry 	cm->cm_sge = &req->SGL;
1858d3c7b9a0SKenneth D. Merry 	cm->cm_sglsize = (32 - 24) * 4;
1859d3c7b9a0SKenneth D. Merry 	cm->cm_desc.SCSIIO.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO;
1860be4aa869SKenneth D. Merry 	cm->cm_desc.SCSIIO.DevHandle = htole16(targ->handle);
1861d3c7b9a0SKenneth D. Merry 	cm->cm_complete = mpssas_scsiio_complete;
1862d3c7b9a0SKenneth D. Merry 	cm->cm_complete_data = ccb;
1863d3c7b9a0SKenneth D. Merry 	cm->cm_targ = targ;
1864d043c564SKenneth D. Merry 	cm->cm_lun = csio->ccb_h.target_lun;
1865d043c564SKenneth D. Merry 	cm->cm_ccb = ccb;
1866d3c7b9a0SKenneth D. Merry 
1867d043c564SKenneth D. Merry 	/*
1868d043c564SKenneth D. Merry 	 * If HBA is a WD and the command is not for a retry, try to build a
1869d043c564SKenneth D. Merry 	 * direct I/O message. If failed, or the command is for a retry, send
1870d043c564SKenneth D. Merry 	 * the I/O to the IR volume itself.
1871d043c564SKenneth D. Merry 	 */
1872d043c564SKenneth D. Merry 	if (sc->WD_valid_config) {
18739b6ea4e7SScott Long 		if (ccb->ccb_h.sim_priv.entries[0].field == MPS_WD_RETRY) {
1874d043c564SKenneth D. Merry 			mpssas_direct_drive_io(sassc, cm, ccb);
1875d043c564SKenneth D. Merry 		} else {
1876601781ccSScott Long 			mpssas_set_ccbstatus(ccb, CAM_REQ_INPROG);
1877d043c564SKenneth D. Merry 		}
1878d043c564SKenneth D. Merry 	}
1879550e2acdSKenneth D. Merry 
18808532d381SConrad Meyer #if defined(BUF_TRACKING) || defined(FULL_BUF_TRACKING)
18818532d381SConrad Meyer 	if (csio->bio != NULL)
18828532d381SConrad Meyer 		biotrack(csio->bio, __func__);
18838532d381SConrad Meyer #endif
18846eea4f46SScott Long 	csio->ccb_h.qos.sim_data = sbinuptime();
188585c9dd9dSSteven Hartland 	callout_reset_sbt(&cm->cm_callout, SBT_1MS * ccb->ccb_h.timeout, 0,
188685c9dd9dSSteven Hartland 	    mpssas_scsiio_timeout, cm, 0);
1887d3c7b9a0SKenneth D. Merry 
1888d043c564SKenneth D. Merry 	targ->issued++;
1889d043c564SKenneth D. Merry 	targ->outstanding++;
1890d043c564SKenneth D. Merry 	TAILQ_INSERT_TAIL(&targ->commands, cm, cm_link);
18919b91b192SKenneth D. Merry 	ccb->ccb_h.status |= CAM_SIM_QUEUED;
1892d043c564SKenneth D. Merry 
18931610f95cSScott Long 	mpssas_log_command(cm, MPS_XINFO, "%s cm %p ccb %p outstanding %u\n",
1894d043c564SKenneth D. Merry 	    __func__, cm, ccb, targ->outstanding);
1895d043c564SKenneth D. Merry 
1896d3c7b9a0SKenneth D. Merry 	mps_map_command(sc, cm);
1897d3c7b9a0SKenneth D. Merry 	return;
1898d3c7b9a0SKenneth D. Merry }
1899d3c7b9a0SKenneth D. Merry 
1900653c521fSKenneth D. Merry /**
1901653c521fSKenneth D. Merry  * mps_sc_failed_io_info - translated non-succesfull SCSI_IO request
1902653c521fSKenneth D. Merry  */
1903653c521fSKenneth D. Merry static void
mps_sc_failed_io_info(struct mps_softc * sc,struct ccb_scsiio * csio,Mpi2SCSIIOReply_t * mpi_reply)1904653c521fSKenneth D. Merry mps_sc_failed_io_info(struct mps_softc *sc, struct ccb_scsiio *csio,
1905653c521fSKenneth D. Merry     Mpi2SCSIIOReply_t *mpi_reply)
1906653c521fSKenneth D. Merry {
1907653c521fSKenneth D. Merry 	u32 response_info;
1908653c521fSKenneth D. Merry 	u8 *response_bytes;
1909653c521fSKenneth D. Merry 	u16 ioc_status = le16toh(mpi_reply->IOCStatus) &
1910653c521fSKenneth D. Merry 	    MPI2_IOCSTATUS_MASK;
1911653c521fSKenneth D. Merry 	u8 scsi_state = mpi_reply->SCSIState;
1912653c521fSKenneth D. Merry 	u8 scsi_status = mpi_reply->SCSIStatus;
1913653c521fSKenneth D. Merry 	u32 log_info = le32toh(mpi_reply->IOCLogInfo);
19142bf620cbSScott Long 	const char *desc_ioc_state, *desc_scsi_status;
1915653c521fSKenneth D. Merry 
1916653c521fSKenneth D. Merry 	if (log_info == 0x31170000)
1917653c521fSKenneth D. Merry 		return;
1918653c521fSKenneth D. Merry 
19192bf620cbSScott Long 	desc_ioc_state = mps_describe_table(mps_iocstatus_string,
19202bf620cbSScott Long 	    ioc_status);
19212bf620cbSScott Long 	desc_scsi_status = mps_describe_table(mps_scsi_status_string,
19222bf620cbSScott Long 	    scsi_status);
1923653c521fSKenneth D. Merry 
19241610f95cSScott Long 	mps_dprint(sc, MPS_XINFO, "\thandle(0x%04x), ioc_status(%s)(0x%04x)\n",
19251610f95cSScott Long 	    le16toh(mpi_reply->DevHandle), desc_ioc_state, ioc_status);
19262bf620cbSScott Long 
19272bf620cbSScott Long 	/*
19282bf620cbSScott Long 	 *We can add more detail about underflow data here
1929653c521fSKenneth D. Merry 	 * TO-DO
19302bf620cbSScott Long 	 */
19311610f95cSScott Long 	mps_dprint(sc, MPS_XINFO, "\tscsi_status(%s)(0x%02x), "
19322bf620cbSScott Long 	    "scsi_state %b\n", desc_scsi_status, scsi_status,
19332bf620cbSScott Long 	    scsi_state, "\20" "\1AutosenseValid" "\2AutosenseFailed"
19342bf620cbSScott Long 	    "\3NoScsiStatus" "\4Terminated" "\5Response InfoValid");
1935653c521fSKenneth D. Merry 
19361610f95cSScott Long 	if (sc->mps_debug & MPS_XINFO &&
1937653c521fSKenneth D. Merry 		scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID) {
19381610f95cSScott Long 		mps_dprint(sc, MPS_XINFO, "-> Sense Buffer Data : Start :\n");
1939653c521fSKenneth D. Merry 		scsi_sense_print(csio);
19401610f95cSScott Long 		mps_dprint(sc, MPS_XINFO, "-> Sense Buffer Data : End :\n");
1941653c521fSKenneth D. Merry 	}
1942653c521fSKenneth D. Merry 
1943653c521fSKenneth D. Merry 	if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) {
1944653c521fSKenneth D. Merry 		response_info = le32toh(mpi_reply->ResponseInfo);
1945653c521fSKenneth D. Merry 		response_bytes = (u8 *)&response_info;
19462bf620cbSScott Long 		mps_dprint(sc, MPS_XINFO, "response code(0x%1x): %s\n",
19472bf620cbSScott Long 		    response_bytes[0],
19482bf620cbSScott Long 		    mps_describe_table(mps_scsi_taskmgmt_string,
19492bf620cbSScott Long 		    response_bytes[0]));
1950653c521fSKenneth D. Merry 	}
1951653c521fSKenneth D. Merry }
1952653c521fSKenneth D. Merry 
1953653c521fSKenneth D. Merry static void
mpssas_scsiio_complete(struct mps_softc * sc,struct mps_command * cm)1954d3c7b9a0SKenneth D. Merry mpssas_scsiio_complete(struct mps_softc *sc, struct mps_command *cm)
1955d3c7b9a0SKenneth D. Merry {
1956d3c7b9a0SKenneth D. Merry 	MPI2_SCSI_IO_REPLY *rep;
1957d3c7b9a0SKenneth D. Merry 	union ccb *ccb;
1958d043c564SKenneth D. Merry 	struct ccb_scsiio *csio;
1959d3c7b9a0SKenneth D. Merry 	struct mpssas_softc *sassc;
1960d043c564SKenneth D. Merry 	struct scsi_vpd_supported_page_list *vpd_list = NULL;
1961d043c564SKenneth D. Merry 	u8 *TLR_bits, TLR_on;
1962d043c564SKenneth D. Merry 	int dir = 0, i;
1963d043c564SKenneth D. Merry 	u16 alloc_len;
1964ef065d89SStephen McConnell 	struct mpssas_target *target;
1965ef065d89SStephen McConnell 	target_id_t target_id;
1966d3c7b9a0SKenneth D. Merry 
19671610f95cSScott Long 	MPS_FUNCTRACE(sc);
1968d043c564SKenneth D. Merry 	mps_dprint(sc, MPS_TRACE,
19691610f95cSScott Long 	    "cm %p SMID %u ccb %p reply %p outstanding %u\n", cm,
19701610f95cSScott Long 	    cm->cm_desc.Default.SMID, cm->cm_ccb, cm->cm_reply,
1971d043c564SKenneth D. Merry 	    cm->cm_targ->outstanding);
1972d3c7b9a0SKenneth D. Merry 
1973d3c7b9a0SKenneth D. Merry 	callout_stop(&cm->cm_callout);
1974d043c564SKenneth D. Merry 	mtx_assert(&sc->mps_mtx, MA_OWNED);
1975d3c7b9a0SKenneth D. Merry 
1976d3c7b9a0SKenneth D. Merry 	sassc = sc->sassc;
1977d3c7b9a0SKenneth D. Merry 	ccb = cm->cm_complete_data;
1978d043c564SKenneth D. Merry 	csio = &ccb->csio;
1979ef065d89SStephen McConnell 	target_id = csio->ccb_h.target_id;
1980d3c7b9a0SKenneth D. Merry 	rep = (MPI2_SCSI_IO_REPLY *)cm->cm_reply;
1981550e2acdSKenneth D. Merry 	/*
1982550e2acdSKenneth D. Merry 	 * XXX KDM if the chain allocation fails, does it matter if we do
1983550e2acdSKenneth D. Merry 	 * the sync and unload here?  It is simpler to do it in every case,
1984550e2acdSKenneth D. Merry 	 * assuming it doesn't cause problems.
1985550e2acdSKenneth D. Merry 	 */
1986d3c7b9a0SKenneth D. Merry 	if (cm->cm_data != NULL) {
1987d3c7b9a0SKenneth D. Merry 		if (cm->cm_flags & MPS_CM_FLAGS_DATAIN)
1988d3c7b9a0SKenneth D. Merry 			dir = BUS_DMASYNC_POSTREAD;
1989d3c7b9a0SKenneth D. Merry 		else if (cm->cm_flags & MPS_CM_FLAGS_DATAOUT)
1990db702c59SEitan Adler 			dir = BUS_DMASYNC_POSTWRITE;
1991d3c7b9a0SKenneth D. Merry 		bus_dmamap_sync(sc->buffer_dmat, cm->cm_dmamap, dir);
1992d3c7b9a0SKenneth D. Merry 		bus_dmamap_unload(sc->buffer_dmat, cm->cm_dmamap);
1993d3c7b9a0SKenneth D. Merry 	}
1994d3c7b9a0SKenneth D. Merry 
1995d043c564SKenneth D. Merry 	cm->cm_targ->completed++;
1996d043c564SKenneth D. Merry 	cm->cm_targ->outstanding--;
1997d043c564SKenneth D. Merry 	TAILQ_REMOVE(&cm->cm_targ->commands, cm, cm_link);
1998ec99409eSKenneth D. Merry 	ccb->ccb_h.status &= ~(CAM_STATUS_MASK | CAM_SIM_QUEUED);
1999d043c564SKenneth D. Merry 
20008532d381SConrad Meyer #if defined(BUF_TRACKING) || defined(FULL_BUF_TRACKING)
20018532d381SConrad Meyer 	if (ccb->csio.bio != NULL)
20028532d381SConrad Meyer 		biotrack(ccb->csio.bio, __func__);
20038532d381SConrad Meyer #endif
20048532d381SConrad Meyer 
20058fe7bf06SWarner Losh 	if (cm->cm_flags & MPS_CM_FLAGS_ON_RECOVERY) {
2006d043c564SKenneth D. Merry 		TAILQ_REMOVE(&cm->cm_targ->timedout_commands, cm, cm_recovery);
20078fe7bf06SWarner Losh 		KASSERT(cm->cm_state == MPS_CM_STATE_BUSY,
2008175ad3d0SKenneth D. Merry 		    ("Not busy for CM_FLAGS_TIMEDOUT: %u\n", cm->cm_state));
20098fe7bf06SWarner Losh 		cm->cm_flags &= ~MPS_CM_FLAGS_ON_RECOVERY;
2010d043c564SKenneth D. Merry 		if (cm->cm_reply != NULL)
20111610f95cSScott Long 			mpssas_log_command(cm, MPS_RECOVERY,
2012d043c564SKenneth D. Merry 			    "completed timedout cm %p ccb %p during recovery "
2013d043c564SKenneth D. Merry 			    "ioc %x scsi %x state %x xfer %u\n",
2014f0779b04SScott Long 			    cm, cm->cm_ccb, le16toh(rep->IOCStatus),
2015f0779b04SScott Long 			    rep->SCSIStatus, rep->SCSIState,
2016be4aa869SKenneth D. Merry 			    le32toh(rep->TransferCount));
2017d043c564SKenneth D. Merry 		else
20181610f95cSScott Long 			mpssas_log_command(cm, MPS_RECOVERY,
2019d043c564SKenneth D. Merry 			    "completed timedout cm %p ccb %p during recovery\n",
2020d043c564SKenneth D. Merry 			    cm, cm->cm_ccb);
2021d043c564SKenneth D. Merry 	} else if (cm->cm_targ->tm != NULL) {
2022d043c564SKenneth D. Merry 		if (cm->cm_reply != NULL)
20231610f95cSScott Long 			mpssas_log_command(cm, MPS_RECOVERY,
2024d043c564SKenneth D. Merry 			    "completed cm %p ccb %p during recovery "
2025d043c564SKenneth D. Merry 			    "ioc %x scsi %x state %x xfer %u\n",
2026f0779b04SScott Long 			    cm, cm->cm_ccb, le16toh(rep->IOCStatus),
2027f0779b04SScott Long 			    rep->SCSIStatus, rep->SCSIState,
2028be4aa869SKenneth D. Merry 			    le32toh(rep->TransferCount));
2029d043c564SKenneth D. Merry 		else
20301610f95cSScott Long 			mpssas_log_command(cm, MPS_RECOVERY,
2031d043c564SKenneth D. Merry 			    "completed cm %p ccb %p during recovery\n",
2032d043c564SKenneth D. Merry 			    cm, cm->cm_ccb);
2033d043c564SKenneth D. Merry 	} else if ((sc->mps_flags & MPS_FLAGS_DIAGRESET) != 0) {
20341610f95cSScott Long 		mpssas_log_command(cm, MPS_RECOVERY,
2035d043c564SKenneth D. Merry 		    "reset completed cm %p ccb %p\n",
2036d043c564SKenneth D. Merry 		    cm, cm->cm_ccb);
2037d043c564SKenneth D. Merry 	}
2038d043c564SKenneth D. Merry 
2039550e2acdSKenneth D. Merry 	if ((cm->cm_flags & MPS_CM_FLAGS_ERROR_MASK) != 0) {
2040550e2acdSKenneth D. Merry 		/*
2041550e2acdSKenneth D. Merry 		 * We ran into an error after we tried to map the command,
2042550e2acdSKenneth D. Merry 		 * so we're getting a callback without queueing the command
2043550e2acdSKenneth D. Merry 		 * to the hardware.  So we set the status here, and it will
2044550e2acdSKenneth D. Merry 		 * be retained below.  We'll go through the "fast path",
2045550e2acdSKenneth D. Merry 		 * because there can be no reply when we haven't actually
2046550e2acdSKenneth D. Merry 		 * gone out to the hardware.
2047550e2acdSKenneth D. Merry 		 */
2048601781ccSScott Long 		mpssas_set_ccbstatus(ccb, CAM_REQUEUE_REQ);
2049550e2acdSKenneth D. Merry 
2050550e2acdSKenneth D. Merry 		/*
2051550e2acdSKenneth D. Merry 		 * Currently the only error included in the mask is
2052550e2acdSKenneth D. Merry 		 * MPS_CM_FLAGS_CHAIN_FAILED, which means we're out of
2053550e2acdSKenneth D. Merry 		 * chain frames.  We need to freeze the queue until we get
2054550e2acdSKenneth D. Merry 		 * a command that completed without this error, which will
2055550e2acdSKenneth D. Merry 		 * hopefully have some chain frames attached that we can
2056550e2acdSKenneth D. Merry 		 * use.  If we wanted to get smarter about it, we would
2057550e2acdSKenneth D. Merry 		 * only unfreeze the queue in this condition when we're
2058550e2acdSKenneth D. Merry 		 * sure that we're getting some chain frames back.  That's
2059550e2acdSKenneth D. Merry 		 * probably unnecessary.
2060550e2acdSKenneth D. Merry 		 */
2061550e2acdSKenneth D. Merry 		if ((sassc->flags & MPSSAS_QUEUE_FROZEN) == 0) {
2062550e2acdSKenneth D. Merry 			xpt_freeze_simq(sassc->sim, 1);
2063550e2acdSKenneth D. Merry 			sassc->flags |= MPSSAS_QUEUE_FROZEN;
20641610f95cSScott Long 			mps_dprint(sc, MPS_XINFO, "Error sending command, "
2065750ffe84SKenneth D. Merry 				   "freezing SIM queue\n");
2066550e2acdSKenneth D. Merry 		}
2067d3c7b9a0SKenneth D. Merry 	}
2068d3c7b9a0SKenneth D. Merry 
20697571e7f6SSteven Hartland 	/*
20707571e7f6SSteven Hartland 	 * If this is a Start Stop Unit command and it was issued by the driver
20717571e7f6SSteven Hartland 	 * during shutdown, decrement the refcount to account for all of the
20727571e7f6SSteven Hartland 	 * commands that were sent.  All SSU commands should be completed before
20737571e7f6SSteven Hartland 	 * shutdown completes, meaning SSU_refcount will be 0 after SSU_started
20747571e7f6SSteven Hartland 	 * is TRUE.
20757571e7f6SSteven Hartland 	 */
20767571e7f6SSteven Hartland 	if (sc->SSU_started && (csio->cdb_io.cdb_bytes[0] == START_STOP_UNIT)) {
20777571e7f6SSteven Hartland 		mps_dprint(sc, MPS_INFO, "Decrementing SSU count.\n");
20787571e7f6SSteven Hartland 		sc->SSU_refcount--;
20797571e7f6SSteven Hartland 	}
20807571e7f6SSteven Hartland 
2081d3c7b9a0SKenneth D. Merry 	/* Take the fast path to completion */
2082d3c7b9a0SKenneth D. Merry 	if (cm->cm_reply == NULL) {
2083601781ccSScott Long 		if (mpssas_get_ccbstatus(ccb) == CAM_REQ_INPROG) {
2084d043c564SKenneth D. Merry 			if ((sc->mps_flags & MPS_FLAGS_DIAGRESET) != 0)
2085601781ccSScott Long 				mpssas_set_ccbstatus(ccb, CAM_SCSI_BUS_RESET);
2086d043c564SKenneth D. Merry 			else {
2087601781ccSScott Long 				mpssas_set_ccbstatus(ccb, CAM_REQ_CMP);
2088d3c7b9a0SKenneth D. Merry 				ccb->csio.scsi_status = SCSI_STATUS_OK;
2089d043c564SKenneth D. Merry 			}
2090550e2acdSKenneth D. Merry 			if (sassc->flags & MPSSAS_QUEUE_FROZEN) {
2091550e2acdSKenneth D. Merry 				ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
2092550e2acdSKenneth D. Merry 				sassc->flags &= ~MPSSAS_QUEUE_FROZEN;
20931610f95cSScott Long 				mps_dprint(sc, MPS_XINFO,
2094750ffe84SKenneth D. Merry 				    "Unfreezing SIM queue\n");
2095550e2acdSKenneth D. Merry 			}
2096d043c564SKenneth D. Merry 		}
2097d043c564SKenneth D. Merry 
2098d043c564SKenneth D. Merry 		/*
2099d043c564SKenneth D. Merry 		 * There are two scenarios where the status won't be
2100d043c564SKenneth D. Merry 		 * CAM_REQ_CMP.  The first is if MPS_CM_FLAGS_ERROR_MASK is
2101d043c564SKenneth D. Merry 		 * set, the second is in the MPS_FLAGS_DIAGRESET above.
2102d043c564SKenneth D. Merry 		 */
2103601781ccSScott Long 		if (mpssas_get_ccbstatus(ccb) != CAM_REQ_CMP) {
2104d043c564SKenneth D. Merry 			/*
2105d043c564SKenneth D. Merry 			 * Freeze the dev queue so that commands are
2106601781ccSScott Long 			 * executed in the correct order after error
2107d043c564SKenneth D. Merry 			 * recovery.
2108d043c564SKenneth D. Merry 			 */
2109550e2acdSKenneth D. Merry 			ccb->ccb_h.status |= CAM_DEV_QFRZN;
2110550e2acdSKenneth D. Merry 			xpt_freeze_devq(ccb->ccb_h.path, /*count*/ 1);
21119866848aSKenneth D. Merry 		}
2112d3c7b9a0SKenneth D. Merry 		mps_free_command(sc, cm);
2113d3c7b9a0SKenneth D. Merry 		xpt_done(ccb);
2114d3c7b9a0SKenneth D. Merry 		return;
2115d3c7b9a0SKenneth D. Merry 	}
2116d3c7b9a0SKenneth D. Merry 
21171610f95cSScott Long 	mpssas_log_command(cm, MPS_XINFO,
2118d043c564SKenneth D. Merry 	    "ioc %x scsi %x state %x xfer %u\n",
2119be4aa869SKenneth D. Merry 	    le16toh(rep->IOCStatus), rep->SCSIStatus, rep->SCSIState,
2120be4aa869SKenneth D. Merry 	    le32toh(rep->TransferCount));
2121d043c564SKenneth D. Merry 
2122d043c564SKenneth D. Merry 	/*
2123d043c564SKenneth D. Merry 	 * If this is a Direct Drive I/O, reissue the I/O to the original IR
2124d043c564SKenneth D. Merry 	 * Volume if an error occurred (normal I/O retry).  Use the original
2125d043c564SKenneth D. Merry 	 * CCB, but set a flag that this will be a retry so that it's sent to
2126d043c564SKenneth D. Merry 	 * the original volume.  Free the command but reuse the CCB.
2127d043c564SKenneth D. Merry 	 */
2128d043c564SKenneth D. Merry 	if (cm->cm_flags & MPS_CM_FLAGS_DD_IO) {
2129d043c564SKenneth D. Merry 		mps_free_command(sc, cm);
21309b6ea4e7SScott Long 		ccb->ccb_h.sim_priv.entries[0].field = MPS_WD_RETRY;
2131d043c564SKenneth D. Merry 		mpssas_action_scsiio(sassc, ccb);
2132d043c564SKenneth D. Merry 		return;
21339b6ea4e7SScott Long 	} else
21349b6ea4e7SScott Long 		ccb->ccb_h.sim_priv.entries[0].field = 0;
2135d3c7b9a0SKenneth D. Merry 
2136be4aa869SKenneth D. Merry 	switch (le16toh(rep->IOCStatus) & MPI2_IOCSTATUS_MASK) {
2137d3c7b9a0SKenneth D. Merry 	case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN:
2138be4aa869SKenneth D. Merry 		csio->resid = cm->cm_length - le32toh(rep->TransferCount);
2139d3c7b9a0SKenneth D. Merry 		/* FALLTHROUGH */
2140d3c7b9a0SKenneth D. Merry 	case MPI2_IOCSTATUS_SUCCESS:
2141d3c7b9a0SKenneth D. Merry 	case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR:
2142d043c564SKenneth D. Merry 
2143be4aa869SKenneth D. Merry 		if ((le16toh(rep->IOCStatus) & MPI2_IOCSTATUS_MASK) ==
2144d043c564SKenneth D. Merry 		    MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR)
21451610f95cSScott Long 			mpssas_log_command(cm, MPS_XINFO, "recovered error\n");
2146d043c564SKenneth D. Merry 
2147d043c564SKenneth D. Merry 		/* Completion failed at the transport level. */
2148d043c564SKenneth D. Merry 		if (rep->SCSIState & (MPI2_SCSI_STATE_NO_SCSI_STATUS |
2149d043c564SKenneth D. Merry 		    MPI2_SCSI_STATE_TERMINATED)) {
2150601781ccSScott Long 			mpssas_set_ccbstatus(ccb, CAM_REQ_CMP_ERR);
2151d3c7b9a0SKenneth D. Merry 			break;
2152d043c564SKenneth D. Merry 		}
2153d043c564SKenneth D. Merry 
2154d043c564SKenneth D. Merry 		/* In a modern packetized environment, an autosense failure
2155d043c564SKenneth D. Merry 		 * implies that there's not much else that can be done to
2156d043c564SKenneth D. Merry 		 * recover the command.
2157d043c564SKenneth D. Merry 		 */
2158d043c564SKenneth D. Merry 		if (rep->SCSIState & MPI2_SCSI_STATE_AUTOSENSE_FAILED) {
2159601781ccSScott Long 			mpssas_set_ccbstatus(ccb, CAM_AUTOSENSE_FAIL);
2160d043c564SKenneth D. Merry 			break;
2161d043c564SKenneth D. Merry 		}
2162d043c564SKenneth D. Merry 
2163d043c564SKenneth D. Merry 		/*
2164d043c564SKenneth D. Merry 		 * CAM doesn't care about SAS Response Info data, but if this is
2165d043c564SKenneth D. Merry 		 * the state check if TLR should be done.  If not, clear the
2166d043c564SKenneth D. Merry 		 * TLR_bits for the target.
2167d043c564SKenneth D. Merry 		 */
2168d043c564SKenneth D. Merry 		if ((rep->SCSIState & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) &&
2169ef065d89SStephen McConnell 		    ((le32toh(rep->ResponseInfo) &
2170ef065d89SStephen McConnell 		    MPI2_SCSI_RI_MASK_REASONCODE) ==
2171d043c564SKenneth D. Merry 		    MPS_SCSI_RI_INVALID_FRAME)) {
2172ef065d89SStephen McConnell 			sc->mapping_table[target_id].TLR_bits =
2173d043c564SKenneth D. Merry 			    (u8)MPI2_SCSIIO_CONTROL_NO_TLR;
2174d043c564SKenneth D. Merry 		}
2175d043c564SKenneth D. Merry 
2176d043c564SKenneth D. Merry 		/*
2177d043c564SKenneth D. Merry 		 * Intentionally override the normal SCSI status reporting
2178d043c564SKenneth D. Merry 		 * for these two cases.  These are likely to happen in a
2179d043c564SKenneth D. Merry 		 * multi-initiator environment, and we want to make sure that
2180d043c564SKenneth D. Merry 		 * CAM retries these commands rather than fail them.
2181d043c564SKenneth D. Merry 		 */
2182d043c564SKenneth D. Merry 		if ((rep->SCSIStatus == MPI2_SCSI_STATUS_COMMAND_TERMINATED) ||
2183d043c564SKenneth D. Merry 		    (rep->SCSIStatus == MPI2_SCSI_STATUS_TASK_ABORTED)) {
2184601781ccSScott Long 			mpssas_set_ccbstatus(ccb, CAM_REQ_ABORTED);
2185d043c564SKenneth D. Merry 			break;
2186d043c564SKenneth D. Merry 		}
2187d043c564SKenneth D. Merry 
2188d043c564SKenneth D. Merry 		/* Handle normal status and sense */
2189d043c564SKenneth D. Merry 		csio->scsi_status = rep->SCSIStatus;
2190d043c564SKenneth D. Merry 		if (rep->SCSIStatus == MPI2_SCSI_STATUS_GOOD)
2191601781ccSScott Long 			mpssas_set_ccbstatus(ccb, CAM_REQ_CMP);
2192d043c564SKenneth D. Merry 		else
2193601781ccSScott Long 			mpssas_set_ccbstatus(ccb, CAM_SCSI_STATUS_ERROR);
2194d043c564SKenneth D. Merry 
2195d043c564SKenneth D. Merry 		if (rep->SCSIState & MPI2_SCSI_STATE_AUTOSENSE_VALID) {
2196d043c564SKenneth D. Merry 			int sense_len, returned_sense_len;
2197d043c564SKenneth D. Merry 
2198be4aa869SKenneth D. Merry 			returned_sense_len = min(le32toh(rep->SenseCount),
2199d043c564SKenneth D. Merry 			    sizeof(struct scsi_sense_data));
2200d043c564SKenneth D. Merry 			if (returned_sense_len < ccb->csio.sense_len)
2201d043c564SKenneth D. Merry 				ccb->csio.sense_resid = ccb->csio.sense_len -
2202d043c564SKenneth D. Merry 					returned_sense_len;
2203d043c564SKenneth D. Merry 			else
2204d043c564SKenneth D. Merry 				ccb->csio.sense_resid = 0;
2205d043c564SKenneth D. Merry 
2206d043c564SKenneth D. Merry 			sense_len = min(returned_sense_len,
2207d043c564SKenneth D. Merry 			    ccb->csio.sense_len - ccb->csio.sense_resid);
2208d043c564SKenneth D. Merry 			bzero(&ccb->csio.sense_data,
2209c61325d0SKevin Lo 			      sizeof(ccb->csio.sense_data));
2210d043c564SKenneth D. Merry 			bcopy(cm->cm_sense, &ccb->csio.sense_data, sense_len);
2211d043c564SKenneth D. Merry 			ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
2212d043c564SKenneth D. Merry 		}
2213d043c564SKenneth D. Merry 
2214d043c564SKenneth D. Merry 		/*
2215d043c564SKenneth D. Merry 		 * Check if this is an INQUIRY command.  If it's a VPD inquiry,
2216d043c564SKenneth D. Merry 		 * and it's page code 0 (Supported Page List), and there is
2217d043c564SKenneth D. Merry 		 * inquiry data, and this is for a sequential access device, and
2218d043c564SKenneth D. Merry 		 * the device is an SSP target, and TLR is supported by the
2219d043c564SKenneth D. Merry 		 * controller, turn the TLR_bits value ON if page 0x90 is
2220d043c564SKenneth D. Merry 		 * supported.
2221d043c564SKenneth D. Merry 		 */
2222d043c564SKenneth D. Merry 		if ((csio->cdb_io.cdb_bytes[0] == INQUIRY) &&
2223d043c564SKenneth D. Merry 		    (csio->cdb_io.cdb_bytes[1] & SI_EVPD) &&
2224d043c564SKenneth D. Merry 		    (csio->cdb_io.cdb_bytes[2] == SVPD_SUPPORTED_PAGE_LIST) &&
222547bf7bcbSAlexander Motin 		    ((csio->ccb_h.flags & CAM_DATA_MASK) == CAM_DATA_VADDR) &&
2226d2b4e18bSKenneth D. Merry 		    (csio->data_ptr != NULL) &&
2227d2b4e18bSKenneth D. Merry 		    ((csio->data_ptr[0] & 0x1f) == T_SEQUENTIAL) &&
2228d2b4e18bSKenneth D. Merry 		    (sc->control_TLR) &&
2229ef065d89SStephen McConnell 		    (sc->mapping_table[target_id].device_info &
2230d043c564SKenneth D. Merry 		    MPI2_SAS_DEVICE_INFO_SSP_TARGET)) {
2231d043c564SKenneth D. Merry 			vpd_list = (struct scsi_vpd_supported_page_list *)
2232d043c564SKenneth D. Merry 			    csio->data_ptr;
2233ef065d89SStephen McConnell 			TLR_bits = &sc->mapping_table[target_id].TLR_bits;
2234d043c564SKenneth D. Merry 			*TLR_bits = (u8)MPI2_SCSIIO_CONTROL_NO_TLR;
2235d043c564SKenneth D. Merry 			TLR_on = (u8)MPI2_SCSIIO_CONTROL_TLR_ON;
2236d043c564SKenneth D. Merry 			alloc_len = ((u16)csio->cdb_io.cdb_bytes[3] << 8) +
2237d043c564SKenneth D. Merry 			    csio->cdb_io.cdb_bytes[4];
2238d2b4e18bSKenneth D. Merry 			alloc_len -= csio->resid;
2239d043c564SKenneth D. Merry 			for (i = 0; i < MIN(vpd_list->length, alloc_len); i++) {
2240d043c564SKenneth D. Merry 				if (vpd_list->list[i] == 0x90) {
2241d043c564SKenneth D. Merry 					*TLR_bits = TLR_on;
2242d043c564SKenneth D. Merry 					break;
2243d043c564SKenneth D. Merry 				}
2244d043c564SKenneth D. Merry 			}
2245d043c564SKenneth D. Merry 		}
2246ef065d89SStephen McConnell 
2247ef065d89SStephen McConnell 		/*
2248ef065d89SStephen McConnell 		 * If this is a SATA direct-access end device, mark it so that
2249ef065d89SStephen McConnell 		 * a SCSI StartStopUnit command will be sent to it when the
2250ef065d89SStephen McConnell 		 * driver is being shutdown.
2251ef065d89SStephen McConnell 		 */
2252ef065d89SStephen McConnell 		if ((csio->cdb_io.cdb_bytes[0] == INQUIRY) &&
2253ef065d89SStephen McConnell 		    ((csio->data_ptr[0] & 0x1f) == T_DIRECT) &&
2254ef065d89SStephen McConnell 		    (sc->mapping_table[target_id].device_info &
2255ef065d89SStephen McConnell 		    MPI2_SAS_DEVICE_INFO_SATA_DEVICE) &&
2256ef065d89SStephen McConnell 		    ((sc->mapping_table[target_id].device_info &
2257ef065d89SStephen McConnell 		    MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) ==
2258ef065d89SStephen McConnell 		    MPI2_SAS_DEVICE_INFO_END_DEVICE)) {
2259ef065d89SStephen McConnell 			target = &sassc->targets[target_id];
2260ef065d89SStephen McConnell 			target->supports_SSU = TRUE;
2261ef065d89SStephen McConnell 			mps_dprint(sc, MPS_XINFO, "Target %d supports SSU\n",
2262ef065d89SStephen McConnell 			    target_id);
2263ef065d89SStephen McConnell 		}
2264d3c7b9a0SKenneth D. Merry 		break;
2265d3c7b9a0SKenneth D. Merry 	case MPI2_IOCSTATUS_SCSI_INVALID_DEVHANDLE:
2266d3c7b9a0SKenneth D. Merry 	case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
2267d043c564SKenneth D. Merry 		/*
2268d043c564SKenneth D. Merry 		 * If devinfo is 0 this will be a volume.  In that case don't
2269d043c564SKenneth D. Merry 		 * tell CAM that the volume is not there.  We want volumes to
2270d043c564SKenneth D. Merry 		 * be enumerated until they are deleted/removed, not just
2271d043c564SKenneth D. Merry 		 * failed.
2272d043c564SKenneth D. Merry 		 */
2273d043c564SKenneth D. Merry 		if (cm->cm_targ->devinfo == 0)
2274601781ccSScott Long 			mpssas_set_ccbstatus(ccb, CAM_REQ_CMP);
2275d043c564SKenneth D. Merry 		else
2276601781ccSScott Long 			mpssas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE);
2277d3c7b9a0SKenneth D. Merry 		break;
2278d043c564SKenneth D. Merry 	case MPI2_IOCSTATUS_INVALID_SGL:
2279d043c564SKenneth D. Merry 		mps_print_scsiio_cmd(sc, cm);
2280601781ccSScott Long 		mpssas_set_ccbstatus(ccb, CAM_UNREC_HBA_ERROR);
2281d043c564SKenneth D. Merry 		break;
2282d3c7b9a0SKenneth D. Merry 	case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED:
2283d3c7b9a0SKenneth D. Merry 		/*
2284d3c7b9a0SKenneth D. Merry 		 * This is one of the responses that comes back when an I/O
2285d3c7b9a0SKenneth D. Merry 		 * has been aborted.  If it is because of a timeout that we
2286d3c7b9a0SKenneth D. Merry 		 * initiated, just set the status to CAM_CMD_TIMEOUT.
2287d3c7b9a0SKenneth D. Merry 		 * Otherwise set it to CAM_REQ_ABORTED.  The effect on the
2288d3c7b9a0SKenneth D. Merry 		 * command is the same (it gets retried, subject to the
2289d3c7b9a0SKenneth D. Merry 		 * retry counter), the only difference is what gets printed
2290d3c7b9a0SKenneth D. Merry 		 * on the console.
2291d3c7b9a0SKenneth D. Merry 		 */
22928fe7bf06SWarner Losh 		if (cm->cm_flags & MPS_CM_FLAGS_TIMEDOUT)
2293601781ccSScott Long 			mpssas_set_ccbstatus(ccb, CAM_CMD_TIMEOUT);
2294d3c7b9a0SKenneth D. Merry 		else
2295601781ccSScott Long 			mpssas_set_ccbstatus(ccb, CAM_REQ_ABORTED);
2296d3c7b9a0SKenneth D. Merry 		break;
2297d043c564SKenneth D. Merry 	case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN:
2298d043c564SKenneth D. Merry 		/* resid is ignored for this condition */
2299d043c564SKenneth D. Merry 		csio->resid = 0;
2300601781ccSScott Long 		mpssas_set_ccbstatus(ccb, CAM_DATA_RUN_ERR);
2301d043c564SKenneth D. Merry 		break;
2302d3c7b9a0SKenneth D. Merry 	case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED:
2303d3c7b9a0SKenneth D. Merry 	case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED:
2304d043c564SKenneth D. Merry 		/*
23056adfa7edSAlan Somers 		 * These can sometimes be transient transport-related
23066adfa7edSAlan Somers 		 * errors, and sometimes persistent drive-related errors.
23076adfa7edSAlan Somers 		 * We used to retry these without decrementing the retry
23086adfa7edSAlan Somers 		 * count by returning CAM_REQUEUE_REQ.  Unfortunately, if
23096adfa7edSAlan Somers 		 * we hit a persistent drive problem that returns one of
23106adfa7edSAlan Somers 		 * these error codes, we would retry indefinitely.  So,
23116adfa7edSAlan Somers 		 * return CAM_REQ_CMP_ERROR so that we decrement the retry
23126adfa7edSAlan Somers 		 * count and avoid infinite retries.  We're taking the
23136adfa7edSAlan Somers 		 * potential risk of flagging false failures in the event
23146adfa7edSAlan Somers 		 * of a topology-related error (e.g. a SAS expander problem
23156adfa7edSAlan Somers 		 * causes a command addressed to a drive to fail), but
23164c1cdd4aSWarner Losh 		 * avoiding getting into an infinite retry loop. However,
23174c1cdd4aSWarner Losh 		 * if we get them while were moving a device, we should
23184c1cdd4aSWarner Losh 		 * fail the request as 'not there' because the device
23194c1cdd4aSWarner Losh 		 * is effectively gone.
2320d043c564SKenneth D. Merry 		 */
23214c1cdd4aSWarner Losh 		if (cm->cm_targ->flags & MPSSAS_TARGET_INREMOVAL)
23224c1cdd4aSWarner Losh 			mpssas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE);
23234c1cdd4aSWarner Losh 		else
23246adfa7edSAlan Somers 			mpssas_set_ccbstatus(ccb, CAM_REQ_CMP_ERR);
23256eea4f46SScott Long 		mps_dprint(sc, MPS_INFO,
23264c1cdd4aSWarner Losh 		    "Controller reported %s tgt %u SMID %u loginfo %x%s\n",
23272bf620cbSScott Long 		    mps_describe_table(mps_iocstatus_string,
23282bf620cbSScott Long 		    le16toh(rep->IOCStatus) & MPI2_IOCSTATUS_MASK),
23292bf620cbSScott Long 		    target_id, cm->cm_desc.Default.SMID,
23304c1cdd4aSWarner Losh 		    le32toh(rep->IOCLogInfo),
23314c1cdd4aSWarner Losh 		    (cm->cm_targ->flags & MPSSAS_TARGET_INREMOVAL) ? " departing" : "");
23326eea4f46SScott Long 		mps_dprint(sc, MPS_XINFO,
23336eea4f46SScott Long 		    "SCSIStatus %x SCSIState %x xfercount %u\n",
2334694cb8b8SScott Long 		    rep->SCSIStatus, rep->SCSIState,
2335be4aa869SKenneth D. Merry 		    le32toh(rep->TransferCount));
2336d3c7b9a0SKenneth D. Merry 		break;
2337d3c7b9a0SKenneth D. Merry 	case MPI2_IOCSTATUS_INVALID_FUNCTION:
2338d3c7b9a0SKenneth D. Merry 	case MPI2_IOCSTATUS_INTERNAL_ERROR:
2339d3c7b9a0SKenneth D. Merry 	case MPI2_IOCSTATUS_INVALID_VPID:
2340d3c7b9a0SKenneth D. Merry 	case MPI2_IOCSTATUS_INVALID_FIELD:
2341d3c7b9a0SKenneth D. Merry 	case MPI2_IOCSTATUS_INVALID_STATE:
2342d3c7b9a0SKenneth D. Merry 	case MPI2_IOCSTATUS_OP_STATE_NOT_SUPPORTED:
2343d3c7b9a0SKenneth D. Merry 	case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR:
2344d3c7b9a0SKenneth D. Merry 	case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR:
2345d3c7b9a0SKenneth D. Merry 	case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
2346d3c7b9a0SKenneth D. Merry 	case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
2347d3c7b9a0SKenneth D. Merry 	default:
23481610f95cSScott Long 		mpssas_log_command(cm, MPS_XINFO,
2349694cb8b8SScott Long 		    "completed ioc %x loginfo %x scsi %x state %x xfer %u\n",
2350694cb8b8SScott Long 		    le16toh(rep->IOCStatus), le32toh(rep->IOCLogInfo),
2351694cb8b8SScott Long 		    rep->SCSIStatus, rep->SCSIState,
2352be4aa869SKenneth D. Merry 		    le32toh(rep->TransferCount));
2353d043c564SKenneth D. Merry 		csio->resid = cm->cm_length;
2354601781ccSScott Long 		mpssas_set_ccbstatus(ccb, CAM_REQ_CMP_ERR);
2355d3c7b9a0SKenneth D. Merry 		break;
2356d3c7b9a0SKenneth D. Merry 	}
2357d3c7b9a0SKenneth D. Merry 
2358653c521fSKenneth D. Merry 	mps_sc_failed_io_info(sc,csio,rep);
2359653c521fSKenneth D. Merry 
2360550e2acdSKenneth D. Merry 	if (sassc->flags & MPSSAS_QUEUE_FROZEN) {
2361550e2acdSKenneth D. Merry 		ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
2362550e2acdSKenneth D. Merry 		sassc->flags &= ~MPSSAS_QUEUE_FROZEN;
23631610f95cSScott Long 		mps_dprint(sc, MPS_XINFO, "Command completed, "
2364d043c564SKenneth D. Merry 		    "unfreezing SIM queue\n");
2365550e2acdSKenneth D. Merry 	}
2366d043c564SKenneth D. Merry 
2367601781ccSScott Long 	if (mpssas_get_ccbstatus(ccb) != CAM_REQ_CMP) {
2368550e2acdSKenneth D. Merry 		ccb->ccb_h.status |= CAM_DEV_QFRZN;
2369550e2acdSKenneth D. Merry 		xpt_freeze_devq(ccb->ccb_h.path, /*count*/ 1);
2370550e2acdSKenneth D. Merry 	}
2371d043c564SKenneth D. Merry 
23724c1cdd4aSWarner Losh 	/*
23734c1cdd4aSWarner Losh 	 * Check to see if we're removing the device. If so, and this is the
23744c1cdd4aSWarner Losh 	 * last command on the queue, proceed with the deferred removal of the
23754c1cdd4aSWarner Losh 	 * device.  Note, for removing a volume, this won't trigger because
23764c1cdd4aSWarner Losh 	 * pending_remove_tm will be NULL.
23774c1cdd4aSWarner Losh 	 */
23784c1cdd4aSWarner Losh 	if (cm->cm_targ->flags & MPSSAS_TARGET_INREMOVAL) {
23794c1cdd4aSWarner Losh 		if (TAILQ_FIRST(&cm->cm_targ->commands) == NULL &&
23804c1cdd4aSWarner Losh 		    cm->cm_targ->pending_remove_tm != NULL) {
2381ca420b4eSWarner Losh 			mps_dprint(sc, MPS_INFO,
2382ca420b4eSWarner Losh 			    "Last pending command complete: starting remove_device target %u handle 0x%04x\n",
2383ca420b4eSWarner Losh 			    cm->cm_targ->tid, cm->cm_targ->handle);
23844c1cdd4aSWarner Losh 			mps_map_command(sc, cm->cm_targ->pending_remove_tm);
23854c1cdd4aSWarner Losh 			cm->cm_targ->pending_remove_tm = NULL;
23864c1cdd4aSWarner Losh 		}
23874c1cdd4aSWarner Losh 	}
23884c1cdd4aSWarner Losh 
2389d3c7b9a0SKenneth D. Merry 	mps_free_command(sc, cm);
2390d3c7b9a0SKenneth D. Merry 	xpt_done(ccb);
2391d3c7b9a0SKenneth D. Merry }
2392d3c7b9a0SKenneth D. Merry 
2393be4aa869SKenneth D. Merry /* All Request reached here are Endian safe */
2394d043c564SKenneth D. Merry static void
mpssas_direct_drive_io(struct mpssas_softc * sassc,struct mps_command * cm,union ccb * ccb)2395d043c564SKenneth D. Merry mpssas_direct_drive_io(struct mpssas_softc *sassc, struct mps_command *cm,
2396d043c564SKenneth D. Merry     union ccb *ccb) {
2397d043c564SKenneth D. Merry 	pMpi2SCSIIORequest_t	pIO_req;
2398d043c564SKenneth D. Merry 	struct mps_softc	*sc = sassc->sc;
2399d043c564SKenneth D. Merry 	uint64_t		virtLBA;
2400d043c564SKenneth D. Merry 	uint32_t		physLBA, stripe_offset, stripe_unit;
2401d043c564SKenneth D. Merry 	uint32_t		io_size, column;
2402d043c564SKenneth D. Merry 	uint8_t			*ptrLBA, lba_idx, physLBA_byte, *CDB;
2403d043c564SKenneth D. Merry 
2404d043c564SKenneth D. Merry 	/*
2405d043c564SKenneth D. Merry 	 * If this is a valid SCSI command (Read6, Read10, Read16, Write6,
2406d043c564SKenneth D. Merry 	 * Write10, or Write16), build a direct I/O message.  Otherwise, the I/O
2407d043c564SKenneth D. Merry 	 * will be sent to the IR volume itself.  Since Read6 and Write6 are a
2408d043c564SKenneth D. Merry 	 * bit different than the 10/16 CDBs, handle them separately.
2409d043c564SKenneth D. Merry 	 */
2410d043c564SKenneth D. Merry 	pIO_req = (pMpi2SCSIIORequest_t)cm->cm_req;
2411d043c564SKenneth D. Merry 	CDB = pIO_req->CDB.CDB32;
2412d043c564SKenneth D. Merry 
2413d043c564SKenneth D. Merry 	/*
2414d043c564SKenneth D. Merry 	 * Handle 6 byte CDBs.
2415d043c564SKenneth D. Merry 	 */
2416d043c564SKenneth D. Merry 	if ((pIO_req->DevHandle == sc->DD_dev_handle) && ((CDB[0] == READ_6) ||
2417d043c564SKenneth D. Merry 	    (CDB[0] == WRITE_6))) {
2418d043c564SKenneth D. Merry 		/*
2419d043c564SKenneth D. Merry 		 * Get the transfer size in blocks.
2420d043c564SKenneth D. Merry 		 */
2421d043c564SKenneth D. Merry 		io_size = (cm->cm_length >> sc->DD_block_exponent);
2422d043c564SKenneth D. Merry 
2423d043c564SKenneth D. Merry 		/*
2424d043c564SKenneth D. Merry 		 * Get virtual LBA given in the CDB.
2425d043c564SKenneth D. Merry 		 */
2426d043c564SKenneth D. Merry 		virtLBA = ((uint64_t)(CDB[1] & 0x1F) << 16) |
2427d043c564SKenneth D. Merry 		    ((uint64_t)CDB[2] << 8) | (uint64_t)CDB[3];
2428d043c564SKenneth D. Merry 
2429d043c564SKenneth D. Merry 		/*
2430d043c564SKenneth D. Merry 		 * Check that LBA range for I/O does not exceed volume's
2431d043c564SKenneth D. Merry 		 * MaxLBA.
2432d043c564SKenneth D. Merry 		 */
2433d043c564SKenneth D. Merry 		if ((virtLBA + (uint64_t)io_size - 1) <=
2434d043c564SKenneth D. Merry 		    sc->DD_max_lba) {
2435d043c564SKenneth D. Merry 			/*
2436d043c564SKenneth D. Merry 			 * Check if the I/O crosses a stripe boundary.  If not,
2437d043c564SKenneth D. Merry 			 * translate the virtual LBA to a physical LBA and set
2438d043c564SKenneth D. Merry 			 * the DevHandle for the PhysDisk to be used.  If it
2439453130d9SPedro F. Giffuni 			 * does cross a boundary, do normal I/O.  To get the
2440d043c564SKenneth D. Merry 			 * right DevHandle to use, get the map number for the
2441d043c564SKenneth D. Merry 			 * column, then use that map number to look up the
2442d043c564SKenneth D. Merry 			 * DevHandle of the PhysDisk.
2443d043c564SKenneth D. Merry 			 */
2444d043c564SKenneth D. Merry 			stripe_offset = (uint32_t)virtLBA &
2445d043c564SKenneth D. Merry 			    (sc->DD_stripe_size - 1);
2446d043c564SKenneth D. Merry 			if ((stripe_offset + io_size) <= sc->DD_stripe_size) {
2447d043c564SKenneth D. Merry 				physLBA = (uint32_t)virtLBA >>
2448d043c564SKenneth D. Merry 				    sc->DD_stripe_exponent;
2449d043c564SKenneth D. Merry 				stripe_unit = physLBA / sc->DD_num_phys_disks;
2450d043c564SKenneth D. Merry 				column = physLBA % sc->DD_num_phys_disks;
2451d043c564SKenneth D. Merry 				pIO_req->DevHandle =
2452be4aa869SKenneth D. Merry 				    htole16(sc->DD_column_map[column].dev_handle);
2453be4aa869SKenneth D. Merry 				/* ???? Is this endian safe*/
2454d043c564SKenneth D. Merry 				cm->cm_desc.SCSIIO.DevHandle =
2455d043c564SKenneth D. Merry 				    pIO_req->DevHandle;
2456d043c564SKenneth D. Merry 
2457d043c564SKenneth D. Merry 				physLBA = (stripe_unit <<
2458d043c564SKenneth D. Merry 				    sc->DD_stripe_exponent) + stripe_offset;
2459d043c564SKenneth D. Merry 				ptrLBA = &pIO_req->CDB.CDB32[1];
2460d043c564SKenneth D. Merry 				physLBA_byte = (uint8_t)(physLBA >> 16);
2461d043c564SKenneth D. Merry 				*ptrLBA = physLBA_byte;
2462d043c564SKenneth D. Merry 				ptrLBA = &pIO_req->CDB.CDB32[2];
2463d043c564SKenneth D. Merry 				physLBA_byte = (uint8_t)(physLBA >> 8);
2464d043c564SKenneth D. Merry 				*ptrLBA = physLBA_byte;
2465d043c564SKenneth D. Merry 				ptrLBA = &pIO_req->CDB.CDB32[3];
2466d043c564SKenneth D. Merry 				physLBA_byte = (uint8_t)physLBA;
2467d043c564SKenneth D. Merry 				*ptrLBA = physLBA_byte;
2468d043c564SKenneth D. Merry 
2469d043c564SKenneth D. Merry 				/*
2470d043c564SKenneth D. Merry 				 * Set flag that Direct Drive I/O is
2471d043c564SKenneth D. Merry 				 * being done.
2472d043c564SKenneth D. Merry 				 */
2473d043c564SKenneth D. Merry 				cm->cm_flags |= MPS_CM_FLAGS_DD_IO;
2474d043c564SKenneth D. Merry 			}
2475d043c564SKenneth D. Merry 		}
2476d043c564SKenneth D. Merry 		return;
2477d043c564SKenneth D. Merry 	}
2478d043c564SKenneth D. Merry 
2479d043c564SKenneth D. Merry 	/*
2480be4aa869SKenneth D. Merry 	 * Handle 10, 12 or 16 byte CDBs.
2481d043c564SKenneth D. Merry 	 */
2482d043c564SKenneth D. Merry 	if ((pIO_req->DevHandle == sc->DD_dev_handle) && ((CDB[0] == READ_10) ||
2483d043c564SKenneth D. Merry 	    (CDB[0] == WRITE_10) || (CDB[0] == READ_16) ||
2484be4aa869SKenneth D. Merry 	    (CDB[0] == WRITE_16) || (CDB[0] == READ_12) ||
2485be4aa869SKenneth D. Merry 	    (CDB[0] == WRITE_12))) {
2486d043c564SKenneth D. Merry 		/*
2487d043c564SKenneth D. Merry 		 * For 16-byte CDB's, verify that the upper 4 bytes of the CDB
2488d043c564SKenneth D. Merry 		 * are 0.  If not, this is accessing beyond 2TB so handle it in
2489be4aa869SKenneth D. Merry 		 * the else section.  10-byte and 12-byte CDB's are OK.
2490be4aa869SKenneth D. Merry 		 * FreeBSD sends very rare 12 byte READ/WRITE, but driver is
2491be4aa869SKenneth D. Merry 		 * ready to accept 12byte CDB for Direct IOs.
2492d043c564SKenneth D. Merry 		 */
2493be4aa869SKenneth D. Merry 		if ((CDB[0] == READ_10 || CDB[0] == WRITE_10) ||
2494be4aa869SKenneth D. Merry 		    (CDB[0] == READ_12 || CDB[0] == WRITE_12) ||
2495d043c564SKenneth D. Merry 		    !(CDB[2] | CDB[3] | CDB[4] | CDB[5])) {
2496d043c564SKenneth D. Merry 			/*
2497d043c564SKenneth D. Merry 			 * Get the transfer size in blocks.
2498d043c564SKenneth D. Merry 			 */
2499d043c564SKenneth D. Merry 			io_size = (cm->cm_length >> sc->DD_block_exponent);
2500d043c564SKenneth D. Merry 
2501d043c564SKenneth D. Merry 			/*
2502d043c564SKenneth D. Merry 			 * Get virtual LBA.  Point to correct lower 4 bytes of
2503d043c564SKenneth D. Merry 			 * LBA in the CDB depending on command.
2504d043c564SKenneth D. Merry 			 */
2505be4aa869SKenneth D. Merry 			lba_idx = ((CDB[0] == READ_12) ||
2506be4aa869SKenneth D. Merry 				(CDB[0] == WRITE_12) ||
2507be4aa869SKenneth D. Merry 				(CDB[0] == READ_10) ||
2508be4aa869SKenneth D. Merry 				(CDB[0] == WRITE_10))? 2 : 6;
2509d043c564SKenneth D. Merry 			virtLBA = ((uint64_t)CDB[lba_idx] << 24) |
2510d043c564SKenneth D. Merry 			    ((uint64_t)CDB[lba_idx + 1] << 16) |
2511d043c564SKenneth D. Merry 			    ((uint64_t)CDB[lba_idx + 2] << 8) |
2512d043c564SKenneth D. Merry 			    (uint64_t)CDB[lba_idx + 3];
2513d043c564SKenneth D. Merry 
2514d043c564SKenneth D. Merry 			/*
2515d043c564SKenneth D. Merry 			 * Check that LBA range for I/O does not exceed volume's
2516d043c564SKenneth D. Merry 			 * MaxLBA.
2517d043c564SKenneth D. Merry 			 */
2518d043c564SKenneth D. Merry 			if ((virtLBA + (uint64_t)io_size - 1) <=
2519d043c564SKenneth D. Merry 			    sc->DD_max_lba) {
2520d043c564SKenneth D. Merry 				/*
2521d043c564SKenneth D. Merry 				 * Check if the I/O crosses a stripe boundary.
2522d043c564SKenneth D. Merry 				 * If not, translate the virtual LBA to a
2523d043c564SKenneth D. Merry 				 * physical LBA and set the DevHandle for the
2524d043c564SKenneth D. Merry 				 * PhysDisk to be used.  If it does cross a
2525453130d9SPedro F. Giffuni 				 * boundary, do normal I/O.  To get the right
2526d043c564SKenneth D. Merry 				 * DevHandle to use, get the map number for the
2527d043c564SKenneth D. Merry 				 * column, then use that map number to look up
2528d043c564SKenneth D. Merry 				 * the DevHandle of the PhysDisk.
2529d043c564SKenneth D. Merry 				 */
2530d043c564SKenneth D. Merry 				stripe_offset = (uint32_t)virtLBA &
2531d043c564SKenneth D. Merry 				    (sc->DD_stripe_size - 1);
2532d043c564SKenneth D. Merry 				if ((stripe_offset + io_size) <=
2533d043c564SKenneth D. Merry 				    sc->DD_stripe_size) {
2534d043c564SKenneth D. Merry 					physLBA = (uint32_t)virtLBA >>
2535d043c564SKenneth D. Merry 					    sc->DD_stripe_exponent;
2536d043c564SKenneth D. Merry 					stripe_unit = physLBA /
2537d043c564SKenneth D. Merry 					    sc->DD_num_phys_disks;
2538d043c564SKenneth D. Merry 					column = physLBA %
2539d043c564SKenneth D. Merry 					    sc->DD_num_phys_disks;
2540d043c564SKenneth D. Merry 					pIO_req->DevHandle =
2541be4aa869SKenneth D. Merry 					    htole16(sc->DD_column_map[column].
2542be4aa869SKenneth D. Merry 					    dev_handle);
2543d043c564SKenneth D. Merry 					cm->cm_desc.SCSIIO.DevHandle =
2544d043c564SKenneth D. Merry 					    pIO_req->DevHandle;
2545d043c564SKenneth D. Merry 
2546d043c564SKenneth D. Merry 					physLBA = (stripe_unit <<
2547d043c564SKenneth D. Merry 					    sc->DD_stripe_exponent) +
2548d043c564SKenneth D. Merry 					    stripe_offset;
2549d043c564SKenneth D. Merry 					ptrLBA =
2550d043c564SKenneth D. Merry 					    &pIO_req->CDB.CDB32[lba_idx];
2551d043c564SKenneth D. Merry 					physLBA_byte = (uint8_t)(physLBA >> 24);
2552d043c564SKenneth D. Merry 					*ptrLBA = physLBA_byte;
2553d043c564SKenneth D. Merry 					ptrLBA =
2554d043c564SKenneth D. Merry 					    &pIO_req->CDB.CDB32[lba_idx + 1];
2555d043c564SKenneth D. Merry 					physLBA_byte = (uint8_t)(physLBA >> 16);
2556d043c564SKenneth D. Merry 					*ptrLBA = physLBA_byte;
2557d043c564SKenneth D. Merry 					ptrLBA =
2558d043c564SKenneth D. Merry 					    &pIO_req->CDB.CDB32[lba_idx + 2];
2559d043c564SKenneth D. Merry 					physLBA_byte = (uint8_t)(physLBA >> 8);
2560d043c564SKenneth D. Merry 					*ptrLBA = physLBA_byte;
2561d043c564SKenneth D. Merry 					ptrLBA =
2562d043c564SKenneth D. Merry 					    &pIO_req->CDB.CDB32[lba_idx + 3];
2563d043c564SKenneth D. Merry 					physLBA_byte = (uint8_t)physLBA;
2564d043c564SKenneth D. Merry 					*ptrLBA = physLBA_byte;
2565d043c564SKenneth D. Merry 
2566d043c564SKenneth D. Merry 					/*
2567d043c564SKenneth D. Merry 					 * Set flag that Direct Drive I/O is
2568d043c564SKenneth D. Merry 					 * being done.
2569d043c564SKenneth D. Merry 					 */
2570d043c564SKenneth D. Merry 					cm->cm_flags |= MPS_CM_FLAGS_DD_IO;
2571d043c564SKenneth D. Merry 				}
2572d043c564SKenneth D. Merry 			}
2573d043c564SKenneth D. Merry 		} else {
2574d043c564SKenneth D. Merry 			/*
2575d043c564SKenneth D. Merry 			 * 16-byte CDB and the upper 4 bytes of the CDB are not
2576d043c564SKenneth D. Merry 			 * 0.  Get the transfer size in blocks.
2577d043c564SKenneth D. Merry 			 */
2578d043c564SKenneth D. Merry 			io_size = (cm->cm_length >> sc->DD_block_exponent);
2579d043c564SKenneth D. Merry 
2580d043c564SKenneth D. Merry 			/*
2581d043c564SKenneth D. Merry 			 * Get virtual LBA.
2582d043c564SKenneth D. Merry 			 */
2583d043c564SKenneth D. Merry 			virtLBA = ((uint64_t)CDB[2] << 54) |
2584d043c564SKenneth D. Merry 			    ((uint64_t)CDB[3] << 48) |
2585d043c564SKenneth D. Merry 			    ((uint64_t)CDB[4] << 40) |
2586d043c564SKenneth D. Merry 			    ((uint64_t)CDB[5] << 32) |
2587d043c564SKenneth D. Merry 			    ((uint64_t)CDB[6] << 24) |
2588d043c564SKenneth D. Merry 			    ((uint64_t)CDB[7] << 16) |
2589d043c564SKenneth D. Merry 			    ((uint64_t)CDB[8] << 8) |
2590d043c564SKenneth D. Merry 			    (uint64_t)CDB[9];
2591d043c564SKenneth D. Merry 
2592d043c564SKenneth D. Merry 			/*
2593d043c564SKenneth D. Merry 			 * Check that LBA range for I/O does not exceed volume's
2594d043c564SKenneth D. Merry 			 * MaxLBA.
2595d043c564SKenneth D. Merry 			 */
2596d043c564SKenneth D. Merry 			if ((virtLBA + (uint64_t)io_size - 1) <=
2597d043c564SKenneth D. Merry 			    sc->DD_max_lba) {
2598d043c564SKenneth D. Merry 				/*
2599d043c564SKenneth D. Merry 				 * Check if the I/O crosses a stripe boundary.
2600d043c564SKenneth D. Merry 				 * If not, translate the virtual LBA to a
2601d043c564SKenneth D. Merry 				 * physical LBA and set the DevHandle for the
2602d043c564SKenneth D. Merry 				 * PhysDisk to be used.  If it does cross a
2603453130d9SPedro F. Giffuni 				 * boundary, do normal I/O.  To get the right
2604d043c564SKenneth D. Merry 				 * DevHandle to use, get the map number for the
2605d043c564SKenneth D. Merry 				 * column, then use that map number to look up
2606d043c564SKenneth D. Merry 				 * the DevHandle of the PhysDisk.
2607d043c564SKenneth D. Merry 				 */
2608d043c564SKenneth D. Merry 				stripe_offset = (uint32_t)virtLBA &
2609d043c564SKenneth D. Merry 				    (sc->DD_stripe_size - 1);
2610d043c564SKenneth D. Merry 				if ((stripe_offset + io_size) <=
2611d043c564SKenneth D. Merry 				    sc->DD_stripe_size) {
2612d043c564SKenneth D. Merry 					physLBA = (uint32_t)(virtLBA >>
2613d043c564SKenneth D. Merry 					    sc->DD_stripe_exponent);
2614d043c564SKenneth D. Merry 					stripe_unit = physLBA /
2615d043c564SKenneth D. Merry 					    sc->DD_num_phys_disks;
2616d043c564SKenneth D. Merry 					column = physLBA %
2617d043c564SKenneth D. Merry 					    sc->DD_num_phys_disks;
2618d043c564SKenneth D. Merry 					pIO_req->DevHandle =
2619be4aa869SKenneth D. Merry 					    htole16(sc->DD_column_map[column].
2620be4aa869SKenneth D. Merry 					    dev_handle);
2621d043c564SKenneth D. Merry 					cm->cm_desc.SCSIIO.DevHandle =
2622d043c564SKenneth D. Merry 					    pIO_req->DevHandle;
2623d043c564SKenneth D. Merry 
2624d043c564SKenneth D. Merry 					physLBA = (stripe_unit <<
2625d043c564SKenneth D. Merry 					    sc->DD_stripe_exponent) +
2626d043c564SKenneth D. Merry 					    stripe_offset;
2627d043c564SKenneth D. Merry 
2628d043c564SKenneth D. Merry 					/*
2629d043c564SKenneth D. Merry 					 * Set upper 4 bytes of LBA to 0.  We
2630d043c564SKenneth D. Merry 					 * assume that the phys disks are less
2631d043c564SKenneth D. Merry 					 * than 2 TB's in size.  Then, set the
2632d043c564SKenneth D. Merry 					 * lower 4 bytes.
2633d043c564SKenneth D. Merry 					 */
2634d043c564SKenneth D. Merry 					pIO_req->CDB.CDB32[2] = 0;
2635d043c564SKenneth D. Merry 					pIO_req->CDB.CDB32[3] = 0;
2636d043c564SKenneth D. Merry 					pIO_req->CDB.CDB32[4] = 0;
2637d043c564SKenneth D. Merry 					pIO_req->CDB.CDB32[5] = 0;
2638d043c564SKenneth D. Merry 					ptrLBA = &pIO_req->CDB.CDB32[6];
2639d043c564SKenneth D. Merry 					physLBA_byte = (uint8_t)(physLBA >> 24);
2640d043c564SKenneth D. Merry 					*ptrLBA = physLBA_byte;
2641d043c564SKenneth D. Merry 					ptrLBA = &pIO_req->CDB.CDB32[7];
2642d043c564SKenneth D. Merry 					physLBA_byte = (uint8_t)(physLBA >> 16);
2643d043c564SKenneth D. Merry 					*ptrLBA = physLBA_byte;
2644d043c564SKenneth D. Merry 					ptrLBA = &pIO_req->CDB.CDB32[8];
2645d043c564SKenneth D. Merry 					physLBA_byte = (uint8_t)(physLBA >> 8);
2646d043c564SKenneth D. Merry 					*ptrLBA = physLBA_byte;
2647d043c564SKenneth D. Merry 					ptrLBA = &pIO_req->CDB.CDB32[9];
2648d043c564SKenneth D. Merry 					physLBA_byte = (uint8_t)physLBA;
2649d043c564SKenneth D. Merry 					*ptrLBA = physLBA_byte;
2650d043c564SKenneth D. Merry 
2651d043c564SKenneth D. Merry 					/*
2652d043c564SKenneth D. Merry 					 * Set flag that Direct Drive I/O is
2653d043c564SKenneth D. Merry 					 * being done.
2654d043c564SKenneth D. Merry 					 */
2655d043c564SKenneth D. Merry 					cm->cm_flags |= MPS_CM_FLAGS_DD_IO;
2656d043c564SKenneth D. Merry 				}
2657d043c564SKenneth D. Merry 			}
2658d043c564SKenneth D. Merry 		}
2659d043c564SKenneth D. Merry 	}
2660d043c564SKenneth D. Merry }
2661d043c564SKenneth D. Merry 
266206e79492SKenneth D. Merry static void
mpssas_smpio_complete(struct mps_softc * sc,struct mps_command * cm)266306e79492SKenneth D. Merry mpssas_smpio_complete(struct mps_softc *sc, struct mps_command *cm)
266406e79492SKenneth D. Merry {
266506e79492SKenneth D. Merry 	MPI2_SMP_PASSTHROUGH_REPLY *rpl;
266606e79492SKenneth D. Merry 	MPI2_SMP_PASSTHROUGH_REQUEST *req;
266706e79492SKenneth D. Merry 	uint64_t sasaddr;
266806e79492SKenneth D. Merry 	union ccb *ccb;
266906e79492SKenneth D. Merry 
267006e79492SKenneth D. Merry 	ccb = cm->cm_complete_data;
2671550e2acdSKenneth D. Merry 
2672550e2acdSKenneth D. Merry 	/*
2673550e2acdSKenneth D. Merry 	 * Currently there should be no way we can hit this case.  It only
2674550e2acdSKenneth D. Merry 	 * happens when we have a failure to allocate chain frames, and SMP
2675550e2acdSKenneth D. Merry 	 * commands require two S/G elements only.  That should be handled
2676550e2acdSKenneth D. Merry 	 * in the standard request size.
2677550e2acdSKenneth D. Merry 	 */
2678550e2acdSKenneth D. Merry 	if ((cm->cm_flags & MPS_CM_FLAGS_ERROR_MASK) != 0) {
26791610f95cSScott Long 		mps_dprint(sc, MPS_ERROR,"%s: cm_flags = %#x on SMP request!\n",
2680550e2acdSKenneth D. Merry 			   __func__, cm->cm_flags);
2681601781ccSScott Long 		mpssas_set_ccbstatus(ccb, CAM_REQ_CMP_ERR);
2682550e2acdSKenneth D. Merry 		goto bailout;
2683550e2acdSKenneth D. Merry         }
2684550e2acdSKenneth D. Merry 
268506e79492SKenneth D. Merry 	rpl = (MPI2_SMP_PASSTHROUGH_REPLY *)cm->cm_reply;
268606e79492SKenneth D. Merry 	if (rpl == NULL) {
26871610f95cSScott Long 		mps_dprint(sc, MPS_ERROR, "%s: NULL cm_reply!\n", __func__);
2688601781ccSScott Long 		mpssas_set_ccbstatus(ccb, CAM_REQ_CMP_ERR);
268906e79492SKenneth D. Merry 		goto bailout;
269006e79492SKenneth D. Merry 	}
269106e79492SKenneth D. Merry 
269206e79492SKenneth D. Merry 	req = (MPI2_SMP_PASSTHROUGH_REQUEST *)cm->cm_req;
269306e79492SKenneth D. Merry 	sasaddr = le32toh(req->SASAddress.Low);
269406e79492SKenneth D. Merry 	sasaddr |= ((uint64_t)(le32toh(req->SASAddress.High))) << 32;
269506e79492SKenneth D. Merry 
26969b91b192SKenneth D. Merry 	if ((le16toh(rpl->IOCStatus) & MPI2_IOCSTATUS_MASK) !=
26979b91b192SKenneth D. Merry 	    MPI2_IOCSTATUS_SUCCESS ||
269806e79492SKenneth D. Merry 	    rpl->SASStatus != MPI2_SASSTATUS_SUCCESS) {
26991610f95cSScott Long 		mps_dprint(sc, MPS_XINFO, "%s: IOCStatus %04x SASStatus %02x\n",
2700be4aa869SKenneth D. Merry 		    __func__, le16toh(rpl->IOCStatus), rpl->SASStatus);
2701601781ccSScott Long 		mpssas_set_ccbstatus(ccb, CAM_REQ_CMP_ERR);
270206e79492SKenneth D. Merry 		goto bailout;
270306e79492SKenneth D. Merry 	}
270406e79492SKenneth D. Merry 
27051610f95cSScott Long 	mps_dprint(sc, MPS_XINFO, "%s: SMP request to SAS address "
270606e79492SKenneth D. Merry 		   "%#jx completed successfully\n", __func__,
270706e79492SKenneth D. Merry 		   (uintmax_t)sasaddr);
270806e79492SKenneth D. Merry 
270906e79492SKenneth D. Merry 	if (ccb->smpio.smp_response[2] == SMP_FR_ACCEPTED)
2710601781ccSScott Long 		mpssas_set_ccbstatus(ccb, CAM_REQ_CMP);
271106e79492SKenneth D. Merry 	else
2712601781ccSScott Long 		mpssas_set_ccbstatus(ccb, CAM_SMP_STATUS_ERROR);
271306e79492SKenneth D. Merry 
271406e79492SKenneth D. Merry bailout:
271506e79492SKenneth D. Merry 	/*
271606e79492SKenneth D. Merry 	 * We sync in both directions because we had DMAs in the S/G list
271706e79492SKenneth D. Merry 	 * in both directions.
271806e79492SKenneth D. Merry 	 */
271906e79492SKenneth D. Merry 	bus_dmamap_sync(sc->buffer_dmat, cm->cm_dmamap,
272006e79492SKenneth D. Merry 			BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
272106e79492SKenneth D. Merry 	bus_dmamap_unload(sc->buffer_dmat, cm->cm_dmamap);
272206e79492SKenneth D. Merry 	mps_free_command(sc, cm);
272306e79492SKenneth D. Merry 	xpt_done(ccb);
272406e79492SKenneth D. Merry }
272506e79492SKenneth D. Merry 
272606e79492SKenneth D. Merry static void
mpssas_send_smpcmd(struct mpssas_softc * sassc,union ccb * ccb,uint64_t sasaddr)272706e79492SKenneth D. Merry mpssas_send_smpcmd(struct mpssas_softc *sassc, union ccb *ccb, uint64_t sasaddr)
272806e79492SKenneth D. Merry {
272906e79492SKenneth D. Merry 	struct mps_command *cm;
273006e79492SKenneth D. Merry 	uint8_t *request, *response;
273106e79492SKenneth D. Merry 	MPI2_SMP_PASSTHROUGH_REQUEST *req;
273206e79492SKenneth D. Merry 	struct mps_softc *sc;
273306e79492SKenneth D. Merry 	int error;
273406e79492SKenneth D. Merry 
273506e79492SKenneth D. Merry 	sc = sassc->sc;
273606e79492SKenneth D. Merry 	error = 0;
273706e79492SKenneth D. Merry 
273806e79492SKenneth D. Merry 	/*
273906e79492SKenneth D. Merry 	 * XXX We don't yet support physical addresses here.
274006e79492SKenneth D. Merry 	 */
2741dd0b4fb6SKonstantin Belousov 	switch ((ccb->ccb_h.flags & CAM_DATA_MASK)) {
2742dd0b4fb6SKonstantin Belousov 	case CAM_DATA_PADDR:
2743dd0b4fb6SKonstantin Belousov 	case CAM_DATA_SG_PADDR:
27441610f95cSScott Long 		mps_dprint(sc, MPS_ERROR,
27451610f95cSScott Long 			   "%s: physical addresses not supported\n", __func__);
2746601781ccSScott Long 		mpssas_set_ccbstatus(ccb, CAM_REQ_INVALID);
274706e79492SKenneth D. Merry 		xpt_done(ccb);
274806e79492SKenneth D. Merry 		return;
2749dd0b4fb6SKonstantin Belousov 	case CAM_DATA_SG:
275006e79492SKenneth D. Merry 		/*
275106e79492SKenneth D. Merry 		 * The chip does not support more than one buffer for the
275206e79492SKenneth D. Merry 		 * request or response.
275306e79492SKenneth D. Merry 		 */
275406e79492SKenneth D. Merry 	 	if ((ccb->smpio.smp_request_sglist_cnt > 1)
275506e79492SKenneth D. Merry 		  || (ccb->smpio.smp_response_sglist_cnt > 1)) {
27561610f95cSScott Long 			mps_dprint(sc, MPS_ERROR,
27571610f95cSScott Long 				   "%s: multiple request or response "
275806e79492SKenneth D. Merry 				   "buffer segments not supported for SMP\n",
275906e79492SKenneth D. Merry 				   __func__);
2760601781ccSScott Long 			mpssas_set_ccbstatus(ccb, CAM_REQ_INVALID);
276106e79492SKenneth D. Merry 			xpt_done(ccb);
276206e79492SKenneth D. Merry 			return;
276306e79492SKenneth D. Merry 		}
276406e79492SKenneth D. Merry 
276506e79492SKenneth D. Merry 		/*
276606e79492SKenneth D. Merry 		 * The CAM_SCATTER_VALID flag was originally implemented
276706e79492SKenneth D. Merry 		 * for the XPT_SCSI_IO CCB, which only has one data pointer.
276806e79492SKenneth D. Merry 		 * We have two.  So, just take that flag to mean that we
276906e79492SKenneth D. Merry 		 * might have S/G lists, and look at the S/G segment count
277006e79492SKenneth D. Merry 		 * to figure out whether that is the case for each individual
277106e79492SKenneth D. Merry 		 * buffer.
277206e79492SKenneth D. Merry 		 */
277306e79492SKenneth D. Merry 		if (ccb->smpio.smp_request_sglist_cnt != 0) {
277406e79492SKenneth D. Merry 			bus_dma_segment_t *req_sg;
277506e79492SKenneth D. Merry 
277606e79492SKenneth D. Merry 			req_sg = (bus_dma_segment_t *)ccb->smpio.smp_request;
27770e28d282SKenneth D. Merry 			request = (uint8_t *)(uintptr_t)req_sg[0].ds_addr;
277806e79492SKenneth D. Merry 		} else
277906e79492SKenneth D. Merry 			request = ccb->smpio.smp_request;
278006e79492SKenneth D. Merry 
278106e79492SKenneth D. Merry 		if (ccb->smpio.smp_response_sglist_cnt != 0) {
278206e79492SKenneth D. Merry 			bus_dma_segment_t *rsp_sg;
278306e79492SKenneth D. Merry 
278406e79492SKenneth D. Merry 			rsp_sg = (bus_dma_segment_t *)ccb->smpio.smp_response;
27850e28d282SKenneth D. Merry 			response = (uint8_t *)(uintptr_t)rsp_sg[0].ds_addr;
278606e79492SKenneth D. Merry 		} else
278706e79492SKenneth D. Merry 			response = ccb->smpio.smp_response;
2788dd0b4fb6SKonstantin Belousov 		break;
2789dd0b4fb6SKonstantin Belousov 	case CAM_DATA_VADDR:
279006e79492SKenneth D. Merry 		request = ccb->smpio.smp_request;
279106e79492SKenneth D. Merry 		response = ccb->smpio.smp_response;
2792dd0b4fb6SKonstantin Belousov 		break;
2793dd0b4fb6SKonstantin Belousov 	default:
2794601781ccSScott Long 		mpssas_set_ccbstatus(ccb, CAM_REQ_INVALID);
2795dd0b4fb6SKonstantin Belousov 		xpt_done(ccb);
2796dd0b4fb6SKonstantin Belousov 		return;
279706e79492SKenneth D. Merry 	}
279806e79492SKenneth D. Merry 
279906e79492SKenneth D. Merry 	cm = mps_alloc_command(sc);
280006e79492SKenneth D. Merry 	if (cm == NULL) {
28011610f95cSScott Long 		mps_dprint(sc, MPS_ERROR,
28021610f95cSScott Long 		    "%s: cannot allocate command\n", __func__);
2803601781ccSScott Long 		mpssas_set_ccbstatus(ccb, CAM_RESRC_UNAVAIL);
280406e79492SKenneth D. Merry 		xpt_done(ccb);
280506e79492SKenneth D. Merry 		return;
280606e79492SKenneth D. Merry 	}
280706e79492SKenneth D. Merry 
280806e79492SKenneth D. Merry 	req = (MPI2_SMP_PASSTHROUGH_REQUEST *)cm->cm_req;
280906e79492SKenneth D. Merry 	bzero(req, sizeof(*req));
281006e79492SKenneth D. Merry 	req->Function = MPI2_FUNCTION_SMP_PASSTHROUGH;
281106e79492SKenneth D. Merry 
281206e79492SKenneth D. Merry 	/* Allow the chip to use any route to this SAS address. */
281306e79492SKenneth D. Merry 	req->PhysicalPort = 0xff;
281406e79492SKenneth D. Merry 
2815be4aa869SKenneth D. Merry 	req->RequestDataLength = htole16(ccb->smpio.smp_request_len);
281606e79492SKenneth D. Merry 	req->SGLFlags =
281706e79492SKenneth D. Merry 	    MPI2_SGLFLAGS_SYSTEM_ADDRESS_SPACE | MPI2_SGLFLAGS_SGL_TYPE_MPI;
281806e79492SKenneth D. Merry 
28191610f95cSScott Long 	mps_dprint(sc, MPS_XINFO, "%s: sending SMP request to SAS "
282006e79492SKenneth D. Merry 	    "address %#jx\n", __func__, (uintmax_t)sasaddr);
282106e79492SKenneth D. Merry 
282206e79492SKenneth D. Merry 	mpi_init_sge(cm, req, &req->SGL);
282306e79492SKenneth D. Merry 
282406e79492SKenneth D. Merry 	/*
282506e79492SKenneth D. Merry 	 * Set up a uio to pass into mps_map_command().  This allows us to
282606e79492SKenneth D. Merry 	 * do one map command, and one busdma call in there.
282706e79492SKenneth D. Merry 	 */
282806e79492SKenneth D. Merry 	cm->cm_uio.uio_iov = cm->cm_iovec;
282906e79492SKenneth D. Merry 	cm->cm_uio.uio_iovcnt = 2;
283006e79492SKenneth D. Merry 	cm->cm_uio.uio_segflg = UIO_SYSSPACE;
283106e79492SKenneth D. Merry 
283206e79492SKenneth D. Merry 	/*
283306e79492SKenneth D. Merry 	 * The read/write flag isn't used by busdma, but set it just in
283406e79492SKenneth D. Merry 	 * case.  This isn't exactly accurate, either, since we're going in
283506e79492SKenneth D. Merry 	 * both directions.
283606e79492SKenneth D. Merry 	 */
283706e79492SKenneth D. Merry 	cm->cm_uio.uio_rw = UIO_WRITE;
283806e79492SKenneth D. Merry 
283906e79492SKenneth D. Merry 	cm->cm_iovec[0].iov_base = request;
2840be4aa869SKenneth D. Merry 	cm->cm_iovec[0].iov_len = le16toh(req->RequestDataLength);
284106e79492SKenneth D. Merry 	cm->cm_iovec[1].iov_base = response;
284206e79492SKenneth D. Merry 	cm->cm_iovec[1].iov_len = ccb->smpio.smp_response_len;
284306e79492SKenneth D. Merry 
284406e79492SKenneth D. Merry 	cm->cm_uio.uio_resid = cm->cm_iovec[0].iov_len +
284506e79492SKenneth D. Merry 			       cm->cm_iovec[1].iov_len;
284606e79492SKenneth D. Merry 
284706e79492SKenneth D. Merry 	/*
284806e79492SKenneth D. Merry 	 * Trigger a warning message in mps_data_cb() for the user if we
284906e79492SKenneth D. Merry 	 * wind up exceeding two S/G segments.  The chip expects one
285006e79492SKenneth D. Merry 	 * segment for the request and another for the response.
285106e79492SKenneth D. Merry 	 */
285206e79492SKenneth D. Merry 	cm->cm_max_segs = 2;
285306e79492SKenneth D. Merry 
285406e79492SKenneth D. Merry 	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
285506e79492SKenneth D. Merry 	cm->cm_complete = mpssas_smpio_complete;
285606e79492SKenneth D. Merry 	cm->cm_complete_data = ccb;
285706e79492SKenneth D. Merry 
285806e79492SKenneth D. Merry 	/*
285906e79492SKenneth D. Merry 	 * Tell the mapping code that we're using a uio, and that this is
286006e79492SKenneth D. Merry 	 * an SMP passthrough request.  There is a little special-case
286106e79492SKenneth D. Merry 	 * logic there (in mps_data_cb()) to handle the bidirectional
286206e79492SKenneth D. Merry 	 * transfer.
286306e79492SKenneth D. Merry 	 */
286406e79492SKenneth D. Merry 	cm->cm_flags |= MPS_CM_FLAGS_USE_UIO | MPS_CM_FLAGS_SMP_PASS |
286506e79492SKenneth D. Merry 			MPS_CM_FLAGS_DATAIN | MPS_CM_FLAGS_DATAOUT;
286606e79492SKenneth D. Merry 
286706e79492SKenneth D. Merry 	/* The chip data format is little endian. */
286806e79492SKenneth D. Merry 	req->SASAddress.High = htole32(sasaddr >> 32);
286906e79492SKenneth D. Merry 	req->SASAddress.Low = htole32(sasaddr);
287006e79492SKenneth D. Merry 
287106e79492SKenneth D. Merry 	/*
287206e79492SKenneth D. Merry 	 * XXX Note that we don't have a timeout/abort mechanism here.
287306e79492SKenneth D. Merry 	 * From the manual, it looks like task management requests only
287406e79492SKenneth D. Merry 	 * work for SCSI IO and SATA passthrough requests.  We may need to
287506e79492SKenneth D. Merry 	 * have a mechanism to retry requests in the event of a chip reset
287606e79492SKenneth D. Merry 	 * at least.  Hopefully the chip will insure that any errors short
287706e79492SKenneth D. Merry 	 * of that are relayed back to the driver.
287806e79492SKenneth D. Merry 	 */
287906e79492SKenneth D. Merry 	error = mps_map_command(sc, cm);
288006e79492SKenneth D. Merry 	if ((error != 0) && (error != EINPROGRESS)) {
28811610f95cSScott Long 		mps_dprint(sc, MPS_ERROR,
28821610f95cSScott Long 			   "%s: error %d returned from mps_map_command()\n",
288306e79492SKenneth D. Merry 			   __func__, error);
288406e79492SKenneth D. Merry 		goto bailout_error;
288506e79492SKenneth D. Merry 	}
288606e79492SKenneth D. Merry 
288706e79492SKenneth D. Merry 	return;
288806e79492SKenneth D. Merry 
288906e79492SKenneth D. Merry bailout_error:
289006e79492SKenneth D. Merry 	mps_free_command(sc, cm);
2891601781ccSScott Long 	mpssas_set_ccbstatus(ccb, CAM_RESRC_UNAVAIL);
289206e79492SKenneth D. Merry 	xpt_done(ccb);
289306e79492SKenneth D. Merry 	return;
289406e79492SKenneth D. Merry 
289506e79492SKenneth D. Merry }
289606e79492SKenneth D. Merry 
289706e79492SKenneth D. Merry static void
mpssas_action_smpio(struct mpssas_softc * sassc,union ccb * ccb)289806e79492SKenneth D. Merry mpssas_action_smpio(struct mpssas_softc *sassc, union ccb *ccb)
289906e79492SKenneth D. Merry {
290006e79492SKenneth D. Merry 	struct mps_softc *sc;
290106e79492SKenneth D. Merry 	struct mpssas_target *targ;
290206e79492SKenneth D. Merry 	uint64_t sasaddr = 0;
290306e79492SKenneth D. Merry 
290406e79492SKenneth D. Merry 	sc = sassc->sc;
290506e79492SKenneth D. Merry 
290606e79492SKenneth D. Merry 	/*
290706e79492SKenneth D. Merry 	 * Make sure the target exists.
290806e79492SKenneth D. Merry 	 */
290908235773SScott Long 	KASSERT(ccb->ccb_h.target_id < sassc->maxtargets,
291008235773SScott Long 	    ("Target %d out of bounds in XPT_SMP_IO\n", ccb->ccb_h.target_id));
291106e79492SKenneth D. Merry 	targ = &sassc->targets[ccb->ccb_h.target_id];
291206e79492SKenneth D. Merry 	if (targ->handle == 0x0) {
29131610f95cSScott Long 		mps_dprint(sc, MPS_ERROR,
29141610f95cSScott Long 			   "%s: target %d does not exist!\n", __func__,
291506e79492SKenneth D. Merry 			   ccb->ccb_h.target_id);
2916601781ccSScott Long 		mpssas_set_ccbstatus(ccb, CAM_SEL_TIMEOUT);
291706e79492SKenneth D. Merry 		xpt_done(ccb);
291806e79492SKenneth D. Merry 		return;
291906e79492SKenneth D. Merry 	}
292006e79492SKenneth D. Merry 
292106e79492SKenneth D. Merry 	/*
292206e79492SKenneth D. Merry 	 * If this device has an embedded SMP target, we'll talk to it
292306e79492SKenneth D. Merry 	 * directly.
292406e79492SKenneth D. Merry 	 * figure out what the expander's address is.
292506e79492SKenneth D. Merry 	 */
292606e79492SKenneth D. Merry 	if ((targ->devinfo & MPI2_SAS_DEVICE_INFO_SMP_TARGET) != 0)
292706e79492SKenneth D. Merry 		sasaddr = targ->sasaddr;
292806e79492SKenneth D. Merry 
292906e79492SKenneth D. Merry 	/*
293006e79492SKenneth D. Merry 	 * If we don't have a SAS address for the expander yet, try
293106e79492SKenneth D. Merry 	 * grabbing it from the page 0x83 information cached in the
293206e79492SKenneth D. Merry 	 * transport layer for this target.  LSI expanders report the
293306e79492SKenneth D. Merry 	 * expander SAS address as the port-associated SAS address in
293406e79492SKenneth D. Merry 	 * Inquiry VPD page 0x83.  Maxim expanders don't report it in page
293506e79492SKenneth D. Merry 	 * 0x83.
293606e79492SKenneth D. Merry 	 *
293706e79492SKenneth D. Merry 	 * XXX KDM disable this for now, but leave it commented out so that
293806e79492SKenneth D. Merry 	 * it is obvious that this is another possible way to get the SAS
293906e79492SKenneth D. Merry 	 * address.
294006e79492SKenneth D. Merry 	 *
294106e79492SKenneth D. Merry 	 * The parent handle method below is a little more reliable, and
294206e79492SKenneth D. Merry 	 * the other benefit is that it works for devices other than SES
294306e79492SKenneth D. Merry 	 * devices.  So you can send a SMP request to a da(4) device and it
294406e79492SKenneth D. Merry 	 * will get routed to the expander that device is attached to.
294506e79492SKenneth D. Merry 	 * (Assuming the da(4) device doesn't contain an SMP target...)
294606e79492SKenneth D. Merry 	 */
294706e79492SKenneth D. Merry #if 0
294806e79492SKenneth D. Merry 	if (sasaddr == 0)
294906e79492SKenneth D. Merry 		sasaddr = xpt_path_sas_addr(ccb->ccb_h.path);
295006e79492SKenneth D. Merry #endif
295106e79492SKenneth D. Merry 
295206e79492SKenneth D. Merry 	/*
295306e79492SKenneth D. Merry 	 * If we still don't have a SAS address for the expander, look for
295406e79492SKenneth D. Merry 	 * the parent device of this device, which is probably the expander.
295506e79492SKenneth D. Merry 	 */
295606e79492SKenneth D. Merry 	if (sasaddr == 0) {
2957d043c564SKenneth D. Merry #ifdef OLD_MPS_PROBE
295806e79492SKenneth D. Merry 		struct mpssas_target *parent_target;
2959d043c564SKenneth D. Merry #endif
296006e79492SKenneth D. Merry 
296106e79492SKenneth D. Merry 		if (targ->parent_handle == 0x0) {
29621610f95cSScott Long 			mps_dprint(sc, MPS_ERROR,
29631610f95cSScott Long 				   "%s: handle %d does not have a valid "
296406e79492SKenneth D. Merry 				   "parent handle!\n", __func__, targ->handle);
29657571e7f6SSteven Hartland 			mpssas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE);
296606e79492SKenneth D. Merry 			goto bailout;
296706e79492SKenneth D. Merry 		}
2968d043c564SKenneth D. Merry #ifdef OLD_MPS_PROBE
2969d043c564SKenneth D. Merry 		parent_target = mpssas_find_target_by_handle(sassc, 0,
297006e79492SKenneth D. Merry 			targ->parent_handle);
297106e79492SKenneth D. Merry 
297206e79492SKenneth D. Merry 		if (parent_target == NULL) {
29731610f95cSScott Long 			mps_dprint(sc, MPS_ERROR,
29741610f95cSScott Long 				   "%s: handle %d does not have a valid "
297506e79492SKenneth D. Merry 				   "parent target!\n", __func__, targ->handle);
29767571e7f6SSteven Hartland 			mpssas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE);
297706e79492SKenneth D. Merry 			goto bailout;
297806e79492SKenneth D. Merry 		}
297906e79492SKenneth D. Merry 
298006e79492SKenneth D. Merry 		if ((parent_target->devinfo &
298106e79492SKenneth D. Merry 		     MPI2_SAS_DEVICE_INFO_SMP_TARGET) == 0) {
29821610f95cSScott Long 			mps_dprint(sc, MPS_ERROR,
29831610f95cSScott Long 				   "%s: handle %d parent %d does not "
298406e79492SKenneth D. Merry 				   "have an SMP target!\n", __func__,
298506e79492SKenneth D. Merry 				   targ->handle, parent_target->handle);
29867571e7f6SSteven Hartland 			mpssas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE);
298706e79492SKenneth D. Merry 			goto bailout;
298806e79492SKenneth D. Merry 		}
298906e79492SKenneth D. Merry 
299006e79492SKenneth D. Merry 		sasaddr = parent_target->sasaddr;
2991d043c564SKenneth D. Merry #else /* OLD_MPS_PROBE */
2992d043c564SKenneth D. Merry 		if ((targ->parent_devinfo &
2993d043c564SKenneth D. Merry 		     MPI2_SAS_DEVICE_INFO_SMP_TARGET) == 0) {
29941610f95cSScott Long 			mps_dprint(sc, MPS_ERROR,
29951610f95cSScott Long 				   "%s: handle %d parent %d does not "
2996d043c564SKenneth D. Merry 				   "have an SMP target!\n", __func__,
2997d043c564SKenneth D. Merry 				   targ->handle, targ->parent_handle);
29987571e7f6SSteven Hartland 			mpssas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE);
2999d043c564SKenneth D. Merry 			goto bailout;
3000d043c564SKenneth D. Merry 		}
3001d043c564SKenneth D. Merry 		if (targ->parent_sasaddr == 0x0) {
30021610f95cSScott Long 			mps_dprint(sc, MPS_ERROR,
30031610f95cSScott Long 				   "%s: handle %d parent handle %d does "
3004d043c564SKenneth D. Merry 				   "not have a valid SAS address!\n",
3005d043c564SKenneth D. Merry 				   __func__, targ->handle, targ->parent_handle);
30067571e7f6SSteven Hartland 			mpssas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE);
3007d043c564SKenneth D. Merry 			goto bailout;
3008d043c564SKenneth D. Merry 		}
3009d043c564SKenneth D. Merry 
3010d043c564SKenneth D. Merry 		sasaddr = targ->parent_sasaddr;
3011d043c564SKenneth D. Merry #endif /* OLD_MPS_PROBE */
301206e79492SKenneth D. Merry 	}
301306e79492SKenneth D. Merry 
301406e79492SKenneth D. Merry 	if (sasaddr == 0) {
30151610f95cSScott Long 		mps_dprint(sc, MPS_INFO,
30161610f95cSScott Long 			   "%s: unable to find SAS address for handle %d\n",
301706e79492SKenneth D. Merry 			   __func__, targ->handle);
30187571e7f6SSteven Hartland 		mpssas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE);
301906e79492SKenneth D. Merry 		goto bailout;
302006e79492SKenneth D. Merry 	}
302106e79492SKenneth D. Merry 	mpssas_send_smpcmd(sassc, ccb, sasaddr);
302206e79492SKenneth D. Merry 
302306e79492SKenneth D. Merry 	return;
302406e79492SKenneth D. Merry 
302506e79492SKenneth D. Merry bailout:
302606e79492SKenneth D. Merry 	xpt_done(ccb);
302706e79492SKenneth D. Merry 
302806e79492SKenneth D. Merry }
302906e79492SKenneth D. Merry 
3030d3c7b9a0SKenneth D. Merry static void
mpssas_action_resetdev(struct mpssas_softc * sassc,union ccb * ccb)3031d3c7b9a0SKenneth D. Merry mpssas_action_resetdev(struct mpssas_softc *sassc, union ccb *ccb)
3032d3c7b9a0SKenneth D. Merry {
3033d3c7b9a0SKenneth D. Merry 	MPI2_SCSI_TASK_MANAGE_REQUEST *req;
3034d3c7b9a0SKenneth D. Merry 	struct mps_softc *sc;
3035d043c564SKenneth D. Merry 	struct mps_command *tm;
3036d043c564SKenneth D. Merry 	struct mpssas_target *targ;
3037d3c7b9a0SKenneth D. Merry 
30381610f95cSScott Long 	MPS_FUNCTRACE(sassc->sc);
3039d043c564SKenneth D. Merry 	mtx_assert(&sassc->sc->mps_mtx, MA_OWNED);
3040d3c7b9a0SKenneth D. Merry 
304108235773SScott Long 	KASSERT(ccb->ccb_h.target_id < sassc->maxtargets,
304208235773SScott Long 	    ("Target %d out of bounds in XPT_RESET_DEV\n",
304308235773SScott Long 	     ccb->ccb_h.target_id));
3044d3c7b9a0SKenneth D. Merry 	sc = sassc->sc;
30453921a9f7SScott Long 	tm = mpssas_alloc_tm(sc);
3046d043c564SKenneth D. Merry 	if (tm == NULL) {
30471610f95cSScott Long 		mps_dprint(sc, MPS_ERROR,
30487263f45eSScott Long 		    "command alloc failure in mpssas_action_resetdev\n");
3049601781ccSScott Long 		mpssas_set_ccbstatus(ccb, CAM_RESRC_UNAVAIL);
3050d043c564SKenneth D. Merry 		xpt_done(ccb);
3051d043c564SKenneth D. Merry 		return;
3052d043c564SKenneth D. Merry 	}
3053d3c7b9a0SKenneth D. Merry 
3054d043c564SKenneth D. Merry 	targ = &sassc->targets[ccb->ccb_h.target_id];
3055d043c564SKenneth D. Merry 	req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req;
3056be4aa869SKenneth D. Merry 	req->DevHandle = htole16(targ->handle);
3057d3c7b9a0SKenneth D. Merry 	req->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
3058d3c7b9a0SKenneth D. Merry 
3059d3c7b9a0SKenneth D. Merry 	/* SAS Hard Link Reset / SATA Link Reset */
3060d3c7b9a0SKenneth D. Merry 	req->MsgFlags = MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET;
3061d3c7b9a0SKenneth D. Merry 
3062d043c564SKenneth D. Merry 	tm->cm_data = NULL;
3063d043c564SKenneth D. Merry 	tm->cm_complete = mpssas_resetdev_complete;
3064d043c564SKenneth D. Merry 	tm->cm_complete_data = ccb;
30651914fdecSAlexander Motin 	tm->cm_targ = targ;
3066ef065d89SStephen McConnell 
30673921a9f7SScott Long 	mpssas_prepare_for_tm(sc, tm, targ, CAM_LUN_WILDCARD);
3068d043c564SKenneth D. Merry 	mps_map_command(sc, tm);
3069d3c7b9a0SKenneth D. Merry }
3070d3c7b9a0SKenneth D. Merry 
3071d3c7b9a0SKenneth D. Merry static void
mpssas_resetdev_complete(struct mps_softc * sc,struct mps_command * tm)3072d043c564SKenneth D. Merry mpssas_resetdev_complete(struct mps_softc *sc, struct mps_command *tm)
3073d3c7b9a0SKenneth D. Merry {
3074d3c7b9a0SKenneth D. Merry 	MPI2_SCSI_TASK_MANAGE_REPLY *resp;
3075d3c7b9a0SKenneth D. Merry 	union ccb *ccb;
3076d3c7b9a0SKenneth D. Merry 
30771610f95cSScott Long 	MPS_FUNCTRACE(sc);
3078d043c564SKenneth D. Merry 	mtx_assert(&sc->mps_mtx, MA_OWNED);
3079d3c7b9a0SKenneth D. Merry 
3080d043c564SKenneth D. Merry 	resp = (MPI2_SCSI_TASK_MANAGE_REPLY *)tm->cm_reply;
3081d043c564SKenneth D. Merry 	ccb = tm->cm_complete_data;
3082d3c7b9a0SKenneth D. Merry 
3083d043c564SKenneth D. Merry 	/*
3084d043c564SKenneth D. Merry 	 * Currently there should be no way we can hit this case.  It only
3085d043c564SKenneth D. Merry 	 * happens when we have a failure to allocate chain frames, and
3086d043c564SKenneth D. Merry 	 * task management commands don't have S/G lists.
3087d043c564SKenneth D. Merry 	 */
3088d043c564SKenneth D. Merry 	if ((tm->cm_flags & MPS_CM_FLAGS_ERROR_MASK) != 0) {
3089550e2acdSKenneth D. Merry 		MPI2_SCSI_TASK_MANAGE_REQUEST *req;
3090550e2acdSKenneth D. Merry 
3091d043c564SKenneth D. Merry 		req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req;
3092550e2acdSKenneth D. Merry 
30931610f95cSScott Long 		mps_dprint(sc, MPS_ERROR,
30941610f95cSScott Long 			   "%s: cm_flags = %#x for reset of handle %#04x! "
3095d043c564SKenneth D. Merry 			   "This should not happen!\n", __func__, tm->cm_flags,
3096550e2acdSKenneth D. Merry 			   req->DevHandle);
3097601781ccSScott Long 		mpssas_set_ccbstatus(ccb, CAM_REQ_CMP_ERR);
3098550e2acdSKenneth D. Merry 		goto bailout;
3099550e2acdSKenneth D. Merry 	}
3100550e2acdSKenneth D. Merry 
31011610f95cSScott Long 	mps_dprint(sc, MPS_XINFO,
31021610f95cSScott Long 	    "%s: IOCStatus = 0x%x ResponseCode = 0x%x\n", __func__,
3103be4aa869SKenneth D. Merry 	    le16toh(resp->IOCStatus), le32toh(resp->ResponseCode));
3104d3c7b9a0SKenneth D. Merry 
3105be4aa869SKenneth D. Merry 	if (le32toh(resp->ResponseCode) == MPI2_SCSITASKMGMT_RSP_TM_COMPLETE) {
3106601781ccSScott Long 		mpssas_set_ccbstatus(ccb, CAM_REQ_CMP);
3107d043c564SKenneth D. Merry 		mpssas_announce_reset(sc, AC_SENT_BDR, tm->cm_targ->tid,
3108d043c564SKenneth D. Merry 		    CAM_LUN_WILDCARD);
3109d043c564SKenneth D. Merry 	}
3110d3c7b9a0SKenneth D. Merry 	else
3111601781ccSScott Long 		mpssas_set_ccbstatus(ccb, CAM_REQ_CMP_ERR);
3112d3c7b9a0SKenneth D. Merry 
3113550e2acdSKenneth D. Merry bailout:
311463feedfdSKenneth D. Merry 
3115d043c564SKenneth D. Merry 	mpssas_free_tm(sc, tm);
3116d3c7b9a0SKenneth D. Merry 	xpt_done(ccb);
3117d3c7b9a0SKenneth D. Merry }
3118d3c7b9a0SKenneth D. Merry 
3119d3c7b9a0SKenneth D. Merry static void
mpssas_poll(struct cam_sim * sim)3120d3c7b9a0SKenneth D. Merry mpssas_poll(struct cam_sim *sim)
3121d3c7b9a0SKenneth D. Merry {
3122d3c7b9a0SKenneth D. Merry 	struct mpssas_softc *sassc;
3123d3c7b9a0SKenneth D. Merry 
3124d3c7b9a0SKenneth D. Merry 	sassc = cam_sim_softc(sim);
3125d043c564SKenneth D. Merry 
3126d043c564SKenneth D. Merry 	if (sassc->sc->mps_debug & MPS_TRACE) {
3127d043c564SKenneth D. Merry 		/* frequent debug messages during a panic just slow
3128d043c564SKenneth D. Merry 		 * everything down too much.
3129d043c564SKenneth D. Merry 		 */
3130d043c564SKenneth D. Merry 		mps_printf(sassc->sc, "%s clearing MPS_TRACE\n", __func__);
3131d043c564SKenneth D. Merry 		sassc->sc->mps_debug &= ~MPS_TRACE;
3132d043c564SKenneth D. Merry 	}
3133d043c564SKenneth D. Merry 
3134d3c7b9a0SKenneth D. Merry 	mps_intr_locked(sassc->sc);
3135d3c7b9a0SKenneth D. Merry }
3136d3c7b9a0SKenneth D. Merry 
3137d3c7b9a0SKenneth D. Merry static void
mpssas_async(void * callback_arg,uint32_t code,struct cam_path * path,void * arg)3138d043c564SKenneth D. Merry mpssas_async(void *callback_arg, uint32_t code, struct cam_path *path,
3139d043c564SKenneth D. Merry 	     void *arg)
3140d043c564SKenneth D. Merry {
3141d043c564SKenneth D. Merry 	struct mps_softc *sc;
3142d043c564SKenneth D. Merry 
3143d043c564SKenneth D. Merry 	sc = (struct mps_softc *)callback_arg;
3144d043c564SKenneth D. Merry 
314502d81940SAlexander Motin 	mps_lock(sc);
3146d043c564SKenneth D. Merry 	switch (code) {
3147d043c564SKenneth D. Merry 	case AC_ADVINFO_CHANGED: {
3148d043c564SKenneth D. Merry 		struct mpssas_target *target;
3149d043c564SKenneth D. Merry 		struct mpssas_softc *sassc;
3150d043c564SKenneth D. Merry 		struct scsi_read_capacity_data_long rcap_buf;
3151d043c564SKenneth D. Merry 		struct ccb_dev_advinfo cdai;
3152d043c564SKenneth D. Merry 		struct mpssas_lun *lun;
3153d043c564SKenneth D. Merry 		lun_id_t lunid;
3154d043c564SKenneth D. Merry 		int found_lun;
3155d043c564SKenneth D. Merry 		uintptr_t buftype;
3156d043c564SKenneth D. Merry 
3157d043c564SKenneth D. Merry 		buftype = (uintptr_t)arg;
3158d043c564SKenneth D. Merry 
3159d043c564SKenneth D. Merry 		found_lun = 0;
3160d043c564SKenneth D. Merry 		sassc = sc->sassc;
3161d043c564SKenneth D. Merry 
3162d043c564SKenneth D. Merry 		/*
3163d043c564SKenneth D. Merry 		 * We're only interested in read capacity data changes.
3164d043c564SKenneth D. Merry 		 */
3165d043c564SKenneth D. Merry 		if (buftype != CDAI_TYPE_RCAPLONG)
3166d043c564SKenneth D. Merry 			break;
3167d043c564SKenneth D. Merry 
3168d043c564SKenneth D. Merry 		/*
3169d043c564SKenneth D. Merry 		 * We should have a handle for this, but check to make sure.
3170d043c564SKenneth D. Merry 		 */
317108235773SScott Long 		KASSERT(xpt_path_target_id(path) < sassc->maxtargets,
317208235773SScott Long 		    ("Target %d out of bounds in mpssas_async\n",
317308235773SScott Long 		    xpt_path_target_id(path)));
3174d043c564SKenneth D. Merry 		target = &sassc->targets[xpt_path_target_id(path)];
3175d043c564SKenneth D. Merry 		if (target->handle == 0)
3176d043c564SKenneth D. Merry 			break;
3177d043c564SKenneth D. Merry 
3178d043c564SKenneth D. Merry 		lunid = xpt_path_lun_id(path);
3179d043c564SKenneth D. Merry 
3180d043c564SKenneth D. Merry 		SLIST_FOREACH(lun, &target->luns, lun_link) {
3181d043c564SKenneth D. Merry 			if (lun->lun_id == lunid) {
3182d043c564SKenneth D. Merry 				found_lun = 1;
3183d043c564SKenneth D. Merry 				break;
3184d043c564SKenneth D. Merry 			}
3185d043c564SKenneth D. Merry 		}
3186d043c564SKenneth D. Merry 
3187d043c564SKenneth D. Merry 		if (found_lun == 0) {
3188d043c564SKenneth D. Merry 			lun = malloc(sizeof(struct mpssas_lun), M_MPT2,
3189d043c564SKenneth D. Merry 				     M_NOWAIT | M_ZERO);
3190d043c564SKenneth D. Merry 			if (lun == NULL) {
31911610f95cSScott Long 				mps_dprint(sc, MPS_ERROR, "Unable to alloc "
3192d043c564SKenneth D. Merry 					   "LUN for EEDP support.\n");
3193d043c564SKenneth D. Merry 				break;
3194d043c564SKenneth D. Merry 			}
3195d043c564SKenneth D. Merry 			lun->lun_id = lunid;
3196d043c564SKenneth D. Merry 			SLIST_INSERT_HEAD(&target->luns, lun, lun_link);
3197d043c564SKenneth D. Merry 		}
3198d043c564SKenneth D. Merry 
3199d043c564SKenneth D. Merry 		bzero(&rcap_buf, sizeof(rcap_buf));
32007608b98cSEdward Tomasz Napierala 		bzero(&cdai, sizeof(cdai));
3201d043c564SKenneth D. Merry 		xpt_setup_ccb(&cdai.ccb_h, path, CAM_PRIORITY_NORMAL);
3202d043c564SKenneth D. Merry 		cdai.ccb_h.func_code = XPT_DEV_ADVINFO;
3203d043c564SKenneth D. Merry 		cdai.ccb_h.flags = CAM_DIR_IN;
3204d043c564SKenneth D. Merry 		cdai.buftype = CDAI_TYPE_RCAPLONG;
3205e8577fb4SKenneth D. Merry 		cdai.flags = CDAI_FLAG_NONE;
3206d043c564SKenneth D. Merry 		cdai.bufsiz = sizeof(rcap_buf);
3207d043c564SKenneth D. Merry 		cdai.buf = (uint8_t *)&rcap_buf;
3208d043c564SKenneth D. Merry 		xpt_action((union ccb *)&cdai);
3209d043c564SKenneth D. Merry 		if ((cdai.ccb_h.status & CAM_DEV_QFRZN) != 0)
3210d043c564SKenneth D. Merry 			cam_release_devq(cdai.ccb_h.path,
3211d043c564SKenneth D. Merry 					 0, 0, 0, FALSE);
3212d043c564SKenneth D. Merry 
3213601781ccSScott Long 		if ((mpssas_get_ccbstatus((union ccb *)&cdai) == CAM_REQ_CMP)
3214d043c564SKenneth D. Merry 		 && (rcap_buf.prot & SRC16_PROT_EN)) {
32158881681bSKenneth D. Merry 			switch (rcap_buf.prot & SRC16_P_TYPE) {
32168881681bSKenneth D. Merry 			case SRC16_PTYPE_1:
32178881681bSKenneth D. Merry 			case SRC16_PTYPE_3:
3218d043c564SKenneth D. Merry 				lun->eedp_formatted = TRUE;
32198881681bSKenneth D. Merry 				lun->eedp_block_size =
32208881681bSKenneth D. Merry 				    scsi_4btoul(rcap_buf.length);
32218881681bSKenneth D. Merry 				break;
32228881681bSKenneth D. Merry 			case SRC16_PTYPE_2:
32238881681bSKenneth D. Merry 			default:
32248881681bSKenneth D. Merry 				lun->eedp_formatted = FALSE;
32258881681bSKenneth D. Merry 				lun->eedp_block_size = 0;
32268881681bSKenneth D. Merry 				break;
32278881681bSKenneth D. Merry 			}
3228d043c564SKenneth D. Merry 		} else {
3229d043c564SKenneth D. Merry 			lun->eedp_formatted = FALSE;
3230d043c564SKenneth D. Merry 			lun->eedp_block_size = 0;
3231d043c564SKenneth D. Merry 		}
3232d043c564SKenneth D. Merry 		break;
3233d043c564SKenneth D. Merry 	}
3234d043c564SKenneth D. Merry 	default:
3235d043c564SKenneth D. Merry 		break;
3236d043c564SKenneth D. Merry 	}
323702d81940SAlexander Motin 	mps_unlock(sc);
3238d043c564SKenneth D. Merry }
3239d043c564SKenneth D. Merry 
3240ef065d89SStephen McConnell /*
3241db0ac6deSCy Schubert  * Freeze the devq and set the INRESET flag so that no I/O will be sent to
3242db0ac6deSCy Schubert  * the target until the reset has completed.  The CCB holds the path which
3243db0ac6deSCy Schubert  * is used to release the devq.  The devq is released and the CCB is freed
3244ef065d89SStephen McConnell  * when the TM completes.
3245db0ac6deSCy Schubert  * We only need to do this when we're entering reset, not at each time we
3246db0ac6deSCy Schubert  * need to send an abort (which will happen if multiple commands timeout
3247db0ac6deSCy Schubert  * while we're sending the abort). We do not release the queue for each
3248db0ac6deSCy Schubert  * command we complete (just at the end when we free the tm), so freezing
3249db0ac6deSCy Schubert  * it each time doesn't make sense.
3250ef065d89SStephen McConnell  */
3251b7f1ee79SScott Long void
mpssas_prepare_for_tm(struct mps_softc * sc,struct mps_command * tm,struct mpssas_target * target,lun_id_t lun_id)3252b7f1ee79SScott Long mpssas_prepare_for_tm(struct mps_softc *sc, struct mps_command *tm,
3253b7f1ee79SScott Long     struct mpssas_target *target, lun_id_t lun_id)
3254b7f1ee79SScott Long {
3255b7f1ee79SScott Long 	union ccb *ccb;
3256b7f1ee79SScott Long 	path_id_t path_id;
3257b7f1ee79SScott Long 
3258ef065d89SStephen McConnell 	ccb = xpt_alloc_ccb_nowait();
3259ef065d89SStephen McConnell 	if (ccb) {
3260ef065d89SStephen McConnell 		path_id = cam_sim_path(sc->sassc->sim);
3261ef065d89SStephen McConnell 		if (xpt_create_path(&ccb->ccb_h.path, xpt_periph, path_id,
3262ef065d89SStephen McConnell 		    target->tid, lun_id) != CAM_REQ_CMP) {
3263ef065d89SStephen McConnell 			xpt_free_ccb(ccb);
3264ef065d89SStephen McConnell 		} else {
3265ef065d89SStephen McConnell 			tm->cm_ccb = ccb;
3266ef065d89SStephen McConnell 			tm->cm_targ = target;
3267db0ac6deSCy Schubert 			if ((target->flags & MPSSAS_TARGET_INRESET) == 0) {
3268db0ac6deSCy Schubert 				mps_dprint(sc, MPS_XINFO | MPS_RECOVERY,
3269db0ac6deSCy Schubert 				    "%s: Freezing devq for target ID %d\n",
3270db0ac6deSCy Schubert 				    __func__, target->tid);
3271db0ac6deSCy Schubert 				xpt_freeze_devq(ccb->ccb_h.path, 1);
3272ef065d89SStephen McConnell 				target->flags |= MPSSAS_TARGET_INRESET;
3273ef065d89SStephen McConnell 			}
3274ef065d89SStephen McConnell 		}
3275ef065d89SStephen McConnell 	}
3276db0ac6deSCy Schubert }
3277ef065d89SStephen McConnell 
3278d043c564SKenneth D. Merry int
mpssas_startup(struct mps_softc * sc)3279d043c564SKenneth D. Merry mpssas_startup(struct mps_softc *sc)
3280d043c564SKenneth D. Merry {
3281d043c564SKenneth D. Merry 
3282d043c564SKenneth D. Merry 	/*
3283d043c564SKenneth D. Merry 	 * Send the port enable message and set the wait_for_port_enable flag.
3284d043c564SKenneth D. Merry 	 * This flag helps to keep the simq frozen until all discovery events
3285d043c564SKenneth D. Merry 	 * are processed.
3286d043c564SKenneth D. Merry 	 */
3287d043c564SKenneth D. Merry 	sc->wait_for_port_enable = 1;
3288d043c564SKenneth D. Merry 	mpssas_send_portenable(sc);
3289d043c564SKenneth D. Merry 	return (0);
3290d043c564SKenneth D. Merry }
3291d043c564SKenneth D. Merry 
3292d043c564SKenneth D. Merry static int
mpssas_send_portenable(struct mps_softc * sc)3293d043c564SKenneth D. Merry mpssas_send_portenable(struct mps_softc *sc)
3294d043c564SKenneth D. Merry {
3295d043c564SKenneth D. Merry 	MPI2_PORT_ENABLE_REQUEST *request;
3296d043c564SKenneth D. Merry 	struct mps_command *cm;
3297d043c564SKenneth D. Merry 
32981610f95cSScott Long 	MPS_FUNCTRACE(sc);
3299d043c564SKenneth D. Merry 
3300d043c564SKenneth D. Merry 	if ((cm = mps_alloc_command(sc)) == NULL)
3301d043c564SKenneth D. Merry 		return (EBUSY);
3302d043c564SKenneth D. Merry 	request = (MPI2_PORT_ENABLE_REQUEST *)cm->cm_req;
3303d043c564SKenneth D. Merry 	request->Function = MPI2_FUNCTION_PORT_ENABLE;
3304d043c564SKenneth D. Merry 	request->MsgFlags = 0;
3305d043c564SKenneth D. Merry 	request->VP_ID = 0;
3306d043c564SKenneth D. Merry 	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
3307d043c564SKenneth D. Merry 	cm->cm_complete = mpssas_portenable_complete;
3308d043c564SKenneth D. Merry 	cm->cm_data = NULL;
3309d043c564SKenneth D. Merry 	cm->cm_sge = NULL;
3310d043c564SKenneth D. Merry 
3311d043c564SKenneth D. Merry 	mps_map_command(sc, cm);
33121610f95cSScott Long 	mps_dprint(sc, MPS_XINFO,
3313d043c564SKenneth D. Merry 	    "mps_send_portenable finished cm %p req %p complete %p\n",
3314d043c564SKenneth D. Merry 	    cm, cm->cm_req, cm->cm_complete);
3315d043c564SKenneth D. Merry 	return (0);
3316d043c564SKenneth D. Merry }
3317d043c564SKenneth D. Merry 
3318d043c564SKenneth D. Merry static void
mpssas_portenable_complete(struct mps_softc * sc,struct mps_command * cm)3319d043c564SKenneth D. Merry mpssas_portenable_complete(struct mps_softc *sc, struct mps_command *cm)
3320d043c564SKenneth D. Merry {
3321d043c564SKenneth D. Merry 	MPI2_PORT_ENABLE_REPLY *reply;
3322d043c564SKenneth D. Merry 	struct mpssas_softc *sassc;
3323d043c564SKenneth D. Merry 
33241610f95cSScott Long 	MPS_FUNCTRACE(sc);
3325d043c564SKenneth D. Merry 	sassc = sc->sassc;
3326d043c564SKenneth D. Merry 
3327d043c564SKenneth D. Merry 	/*
3328d043c564SKenneth D. Merry 	 * Currently there should be no way we can hit this case.  It only
3329d043c564SKenneth D. Merry 	 * happens when we have a failure to allocate chain frames, and
3330d043c564SKenneth D. Merry 	 * port enable commands don't have S/G lists.
3331d043c564SKenneth D. Merry 	 */
3332d043c564SKenneth D. Merry 	if ((cm->cm_flags & MPS_CM_FLAGS_ERROR_MASK) != 0) {
33331610f95cSScott Long 		mps_dprint(sc, MPS_ERROR, "%s: cm_flags = %#x for port enable! "
3334d043c564SKenneth D. Merry 			   "This should not happen!\n", __func__, cm->cm_flags);
3335d043c564SKenneth D. Merry 	}
3336d043c564SKenneth D. Merry 
3337d043c564SKenneth D. Merry 	reply = (MPI2_PORT_ENABLE_REPLY *)cm->cm_reply;
3338d043c564SKenneth D. Merry 	if (reply == NULL)
3339d043c564SKenneth D. Merry 		mps_dprint(sc, MPS_FAULT, "Portenable NULL reply\n");
3340be4aa869SKenneth D. Merry 	else if (le16toh(reply->IOCStatus & MPI2_IOCSTATUS_MASK) !=
3341d043c564SKenneth D. Merry 	    MPI2_IOCSTATUS_SUCCESS)
3342d043c564SKenneth D. Merry 		mps_dprint(sc, MPS_FAULT, "Portenable failed\n");
3343d043c564SKenneth D. Merry 
3344d043c564SKenneth D. Merry 	mps_free_command(sc, cm);
3345d043c564SKenneth D. Merry 
3346d043c564SKenneth D. Merry 	/*
3347d043c564SKenneth D. Merry 	 * Get WarpDrive info after discovery is complete but before the scan
3348d043c564SKenneth D. Merry 	 * starts.  At this point, all devices are ready to be exposed to the
3349d043c564SKenneth D. Merry 	 * OS.  If devices should be hidden instead, take them out of the
3350d043c564SKenneth D. Merry 	 * 'targets' array before the scan.  The devinfo for a disk will have
3351d043c564SKenneth D. Merry 	 * some info and a volume's will be 0.  Use that to remove disks.
3352d043c564SKenneth D. Merry 	 */
3353d043c564SKenneth D. Merry 	mps_wd_config_pages(sc);
3354d043c564SKenneth D. Merry 
3355d043c564SKenneth D. Merry 	/*
3356d043c564SKenneth D. Merry 	 * Done waiting for port enable to complete.  Decrement the refcount.
3357d043c564SKenneth D. Merry 	 * If refcount is 0, discovery is complete and a rescan of the bus can
3358d043c564SKenneth D. Merry 	 * take place.  Since the simq was explicitly frozen before port
3359d043c564SKenneth D. Merry 	 * enable, it must be explicitly released here to keep the
3360d043c564SKenneth D. Merry 	 * freeze/release count in sync.
3361d043c564SKenneth D. Merry 	 */
3362d043c564SKenneth D. Merry 	sc->wait_for_port_enable = 0;
3363d043c564SKenneth D. Merry 	sc->port_enable_complete = 1;
3364be4aa869SKenneth D. Merry 	wakeup(&sc->port_enable_complete);
3365d043c564SKenneth D. Merry 	mpssas_startup_decrement(sassc);
3366d3c7b9a0SKenneth D. Merry }
3367d3c7b9a0SKenneth D. Merry 
3368d9802debSScott Long int
mpssas_check_id(struct mpssas_softc * sassc,int id)3369d9802debSScott Long mpssas_check_id(struct mpssas_softc *sassc, int id)
3370d9802debSScott Long {
3371d9802debSScott Long 	struct mps_softc *sc = sassc->sc;
3372d9802debSScott Long 	char *ids;
3373d9802debSScott Long 	char *name;
3374d9802debSScott Long 
3375d9802debSScott Long 	ids = &sc->exclude_ids[0];
3376d9802debSScott Long 	while((name = strsep(&ids, ",")) != NULL) {
3377d9802debSScott Long 		if (name[0] == '\0')
3378d9802debSScott Long 			continue;
3379d9802debSScott Long 		if (strtol(name, NULL, 0) == (long)id)
3380d9802debSScott Long 			return (1);
3381d9802debSScott Long 	}
3382d9802debSScott Long 
3383d9802debSScott Long 	return (0);
3384d9802debSScott Long }
3385b7f77127SScott Long 
3386b7f77127SScott Long void
mpssas_realloc_targets(struct mps_softc * sc,int maxtargets)3387b7f77127SScott Long mpssas_realloc_targets(struct mps_softc *sc, int maxtargets)
3388b7f77127SScott Long {
3389b7f77127SScott Long 	struct mpssas_softc *sassc;
3390b7f77127SScott Long 	struct mpssas_lun *lun, *lun_tmp;
3391b7f77127SScott Long 	struct mpssas_target *targ;
3392b7f77127SScott Long 	int i;
3393b7f77127SScott Long 
3394b7f77127SScott Long 	sassc = sc->sassc;
3395b7f77127SScott Long 	/*
3396b7f77127SScott Long 	 * The number of targets is based on IOC Facts, so free all of
3397b7f77127SScott Long 	 * the allocated LUNs for each target and then the target buffer
3398b7f77127SScott Long 	 * itself.
3399b7f77127SScott Long 	 */
3400b7f77127SScott Long 	for (i=0; i< maxtargets; i++) {
3401b7f77127SScott Long 		targ = &sassc->targets[i];
3402b7f77127SScott Long 		SLIST_FOREACH_SAFE(lun, &targ->luns, lun_link, lun_tmp) {
3403b7f77127SScott Long 			free(lun, M_MPT2);
3404b7f77127SScott Long 		}
3405b7f77127SScott Long 	}
3406b7f77127SScott Long 	free(sassc->targets, M_MPT2);
3407b7f77127SScott Long 
3408b7f77127SScott Long 	sassc->targets = malloc(sizeof(struct mpssas_target) * maxtargets,
3409b7f77127SScott Long 	    M_MPT2, M_WAITOK|M_ZERO);
3410b7f77127SScott Long }
3411