xref: /freebsd/sys/dev/mpr/mpr_sas.c (revision e8577fb489cfcf475d9ab58e3e0e74756c776505)
1991554f2SKenneth D. Merry /*-
2991554f2SKenneth D. Merry  * Copyright (c) 2009 Yahoo! Inc.
3991554f2SKenneth D. Merry  * Copyright (c) 2011-2014 LSI Corp.
4991554f2SKenneth D. Merry  * All rights reserved.
5991554f2SKenneth D. Merry  *
6991554f2SKenneth D. Merry  * Redistribution and use in source and binary forms, with or without
7991554f2SKenneth D. Merry  * modification, are permitted provided that the following conditions
8991554f2SKenneth D. Merry  * are met:
9991554f2SKenneth D. Merry  * 1. Redistributions of source code must retain the above copyright
10991554f2SKenneth D. Merry  *    notice, this list of conditions and the following disclaimer.
11991554f2SKenneth D. Merry  * 2. Redistributions in binary form must reproduce the above copyright
12991554f2SKenneth D. Merry  *    notice, this list of conditions and the following disclaimer in the
13991554f2SKenneth D. Merry  *    documentation and/or other materials provided with the distribution.
14991554f2SKenneth D. Merry  *
15991554f2SKenneth D. Merry  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16991554f2SKenneth D. Merry  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17991554f2SKenneth D. Merry  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18991554f2SKenneth D. Merry  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19991554f2SKenneth D. Merry  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20991554f2SKenneth D. Merry  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21991554f2SKenneth D. Merry  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22991554f2SKenneth D. Merry  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23991554f2SKenneth D. Merry  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24991554f2SKenneth D. Merry  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25991554f2SKenneth D. Merry  * SUCH DAMAGE.
26991554f2SKenneth D. Merry  */
27991554f2SKenneth D. Merry 
28991554f2SKenneth D. Merry #include <sys/cdefs.h>
29991554f2SKenneth D. Merry __FBSDID("$FreeBSD$");
30991554f2SKenneth D. Merry 
31991554f2SKenneth D. Merry /* Communications core for LSI MPT2 */
32991554f2SKenneth D. Merry 
33991554f2SKenneth D. Merry /* TODO Move headers to mprvar */
34991554f2SKenneth D. Merry #include <sys/types.h>
35991554f2SKenneth D. Merry #include <sys/param.h>
36991554f2SKenneth D. Merry #include <sys/systm.h>
37991554f2SKenneth D. Merry #include <sys/kernel.h>
38991554f2SKenneth D. Merry #include <sys/selinfo.h>
39991554f2SKenneth D. Merry #include <sys/module.h>
40991554f2SKenneth D. Merry #include <sys/bus.h>
41991554f2SKenneth D. Merry #include <sys/conf.h>
42991554f2SKenneth D. Merry #include <sys/bio.h>
43991554f2SKenneth D. Merry #include <sys/malloc.h>
44991554f2SKenneth D. Merry #include <sys/uio.h>
45991554f2SKenneth D. Merry #include <sys/sysctl.h>
46991554f2SKenneth D. Merry #include <sys/endian.h>
47991554f2SKenneth D. Merry #include <sys/queue.h>
48991554f2SKenneth D. Merry #include <sys/kthread.h>
49991554f2SKenneth D. Merry #include <sys/taskqueue.h>
50991554f2SKenneth D. Merry #include <sys/sbuf.h>
51991554f2SKenneth D. Merry 
52991554f2SKenneth D. Merry #include <machine/bus.h>
53991554f2SKenneth D. Merry #include <machine/resource.h>
54991554f2SKenneth D. Merry #include <sys/rman.h>
55991554f2SKenneth D. Merry 
56991554f2SKenneth D. Merry #include <machine/stdarg.h>
57991554f2SKenneth D. Merry 
58991554f2SKenneth D. Merry #include <cam/cam.h>
59991554f2SKenneth D. Merry #include <cam/cam_ccb.h>
60991554f2SKenneth D. Merry #include <cam/cam_debug.h>
61991554f2SKenneth D. Merry #include <cam/cam_sim.h>
62991554f2SKenneth D. Merry #include <cam/cam_xpt_sim.h>
63991554f2SKenneth D. Merry #include <cam/cam_xpt_periph.h>
64991554f2SKenneth D. Merry #include <cam/cam_periph.h>
65991554f2SKenneth D. Merry #include <cam/scsi/scsi_all.h>
66991554f2SKenneth D. Merry #include <cam/scsi/scsi_message.h>
67991554f2SKenneth D. Merry #if __FreeBSD_version >= 900026
68991554f2SKenneth D. Merry #include <cam/scsi/smp_all.h>
69991554f2SKenneth D. Merry #endif
70991554f2SKenneth D. Merry 
71991554f2SKenneth D. Merry #include <dev/mpr/mpi/mpi2_type.h>
72991554f2SKenneth D. Merry #include <dev/mpr/mpi/mpi2.h>
73991554f2SKenneth D. Merry #include <dev/mpr/mpi/mpi2_ioc.h>
74991554f2SKenneth D. Merry #include <dev/mpr/mpi/mpi2_sas.h>
75991554f2SKenneth D. Merry #include <dev/mpr/mpi/mpi2_cnfg.h>
76991554f2SKenneth D. Merry #include <dev/mpr/mpi/mpi2_init.h>
77991554f2SKenneth D. Merry #include <dev/mpr/mpi/mpi2_tool.h>
78991554f2SKenneth D. Merry #include <dev/mpr/mpr_ioctl.h>
79991554f2SKenneth D. Merry #include <dev/mpr/mprvar.h>
80991554f2SKenneth D. Merry #include <dev/mpr/mpr_table.h>
81991554f2SKenneth D. Merry #include <dev/mpr/mpr_sas.h>
82991554f2SKenneth D. Merry 
83991554f2SKenneth D. Merry #define MPRSAS_DISCOVERY_TIMEOUT	20
84991554f2SKenneth D. Merry #define MPRSAS_MAX_DISCOVERY_TIMEOUTS	10 /* 200 seconds */
85991554f2SKenneth D. Merry 
86991554f2SKenneth D. Merry /*
87991554f2SKenneth D. Merry  * static array to check SCSI OpCode for EEDP protection bits
88991554f2SKenneth D. Merry  */
89991554f2SKenneth D. Merry #define	PRO_R MPI2_SCSIIO_EEDPFLAGS_CHECK_REMOVE_OP
90991554f2SKenneth D. Merry #define	PRO_W MPI2_SCSIIO_EEDPFLAGS_INSERT_OP
91991554f2SKenneth D. Merry #define	PRO_V MPI2_SCSIIO_EEDPFLAGS_INSERT_OP
92991554f2SKenneth D. Merry static uint8_t op_code_prot[256] = {
93991554f2SKenneth D. Merry 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
94991554f2SKenneth D. Merry 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
95991554f2SKenneth D. Merry 	0, 0, 0, 0, 0, 0, 0, 0, PRO_R, 0, PRO_W, 0, 0, 0, PRO_W, PRO_V,
96991554f2SKenneth D. Merry 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
97991554f2SKenneth D. Merry 	0, PRO_W, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
98991554f2SKenneth D. Merry 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
99991554f2SKenneth D. Merry 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
100991554f2SKenneth D. Merry 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
101991554f2SKenneth D. Merry 	0, 0, 0, 0, 0, 0, 0, 0, PRO_R, 0, PRO_W, 0, 0, 0, PRO_W, PRO_V,
102991554f2SKenneth D. Merry 	0, 0, 0, PRO_W, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
103991554f2SKenneth D. Merry 	0, 0, 0, 0, 0, 0, 0, 0, PRO_R, 0, PRO_W, 0, 0, 0, PRO_W, PRO_V,
104991554f2SKenneth D. Merry 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
105991554f2SKenneth D. Merry 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
106991554f2SKenneth D. Merry 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
107991554f2SKenneth D. Merry 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
108991554f2SKenneth D. Merry 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
109991554f2SKenneth D. Merry };
110991554f2SKenneth D. Merry 
111991554f2SKenneth D. Merry MALLOC_DEFINE(M_MPRSAS, "MPRSAS", "MPR SAS memory");
112991554f2SKenneth D. Merry 
113991554f2SKenneth D. Merry static void mprsas_remove_device(struct mpr_softc *, struct mpr_command *);
114991554f2SKenneth D. Merry static void mprsas_remove_complete(struct mpr_softc *, struct mpr_command *);
115991554f2SKenneth D. Merry static void mprsas_action(struct cam_sim *sim, union ccb *ccb);
116991554f2SKenneth D. Merry static void mprsas_poll(struct cam_sim *sim);
117991554f2SKenneth D. Merry static void mprsas_scsiio_timeout(void *data);
118991554f2SKenneth D. Merry static void mprsas_abort_complete(struct mpr_softc *sc,
119991554f2SKenneth D. Merry     struct mpr_command *cm);
120991554f2SKenneth D. Merry static void mprsas_action_scsiio(struct mprsas_softc *, union ccb *);
121991554f2SKenneth D. Merry static void mprsas_scsiio_complete(struct mpr_softc *, struct mpr_command *);
122991554f2SKenneth D. Merry static void mprsas_action_resetdev(struct mprsas_softc *, union ccb *);
123991554f2SKenneth D. Merry static void mprsas_resetdev_complete(struct mpr_softc *,
124991554f2SKenneth D. Merry     struct mpr_command *);
125991554f2SKenneth D. Merry static int  mprsas_send_abort(struct mpr_softc *sc, struct mpr_command *tm,
126991554f2SKenneth D. Merry     struct mpr_command *cm);
127991554f2SKenneth D. Merry static int  mprsas_send_reset(struct mpr_softc *sc, struct mpr_command *tm,
128991554f2SKenneth D. Merry     uint8_t type);
129991554f2SKenneth D. Merry static void mprsas_async(void *callback_arg, uint32_t code,
130991554f2SKenneth D. Merry     struct cam_path *path, void *arg);
131991554f2SKenneth D. Merry static void mprsas_prepare_ssu(struct mpr_softc *sc, struct cam_path *path,
132991554f2SKenneth D. Merry     struct ccb_getdev *cgd);
133991554f2SKenneth D. Merry #if (__FreeBSD_version < 901503) || \
134991554f2SKenneth D. Merry     ((__FreeBSD_version >= 1000000) && (__FreeBSD_version < 1000006))
135991554f2SKenneth D. Merry static void mprsas_check_eedp(struct mpr_softc *sc, struct cam_path *path,
136991554f2SKenneth D. Merry     struct ccb_getdev *cgd);
137991554f2SKenneth D. Merry static void mprsas_read_cap_done(struct cam_periph *periph,
138991554f2SKenneth D. Merry     union ccb *done_ccb);
139991554f2SKenneth D. Merry #endif
140991554f2SKenneth D. Merry static int mprsas_send_portenable(struct mpr_softc *sc);
141991554f2SKenneth D. Merry static void mprsas_portenable_complete(struct mpr_softc *sc,
142991554f2SKenneth D. Merry     struct mpr_command *cm);
143991554f2SKenneth D. Merry 
144991554f2SKenneth D. Merry #if __FreeBSD_version >= 900026
145991554f2SKenneth D. Merry static void
146991554f2SKenneth D. Merry mprsas_smpio_complete(struct mpr_softc *sc, struct mpr_command *cm);
147991554f2SKenneth D. Merry static void mprsas_send_smpcmd(struct mprsas_softc *sassc,
148991554f2SKenneth D. Merry 	       	union ccb *ccb, uint64_t sasaddr);
149991554f2SKenneth D. Merry static void
150991554f2SKenneth D. Merry mprsas_action_smpio(struct mprsas_softc *sassc, union ccb *ccb);
151991554f2SKenneth D. Merry #endif
152991554f2SKenneth D. Merry 
153991554f2SKenneth D. Merry struct mprsas_target *
154991554f2SKenneth D. Merry mprsas_find_target_by_handle(struct mprsas_softc *sassc, int start,
155991554f2SKenneth D. Merry     uint16_t handle)
156991554f2SKenneth D. Merry {
157991554f2SKenneth D. Merry 	struct mprsas_target *target;
158991554f2SKenneth D. Merry 	int i;
159991554f2SKenneth D. Merry 
160991554f2SKenneth D. Merry 	for (i = start; i < sassc->maxtargets; i++) {
161991554f2SKenneth D. Merry 		target = &sassc->targets[i];
162991554f2SKenneth D. Merry 		if (target->handle == handle)
163991554f2SKenneth D. Merry 			return (target);
164991554f2SKenneth D. Merry 	}
165991554f2SKenneth D. Merry 
166991554f2SKenneth D. Merry 	return (NULL);
167991554f2SKenneth D. Merry }
168991554f2SKenneth D. Merry 
169991554f2SKenneth D. Merry /* we need to freeze the simq during attach and diag reset, to avoid failing
170991554f2SKenneth D. Merry  * commands before device handles have been found by discovery.  Since
171991554f2SKenneth D. Merry  * discovery involves reading config pages and possibly sending commands,
172991554f2SKenneth D. Merry  * discovery actions may continue even after we receive the end of discovery
173991554f2SKenneth D. Merry  * event, so refcount discovery actions instead of assuming we can unfreeze
174991554f2SKenneth D. Merry  * the simq when we get the event.
175991554f2SKenneth D. Merry  */
176991554f2SKenneth D. Merry void
177991554f2SKenneth D. Merry mprsas_startup_increment(struct mprsas_softc *sassc)
178991554f2SKenneth D. Merry {
179991554f2SKenneth D. Merry 	MPR_FUNCTRACE(sassc->sc);
180991554f2SKenneth D. Merry 
181991554f2SKenneth D. Merry 	if ((sassc->flags & MPRSAS_IN_STARTUP) != 0) {
182991554f2SKenneth D. Merry 		if (sassc->startup_refcount++ == 0) {
183991554f2SKenneth D. Merry 			/* just starting, freeze the simq */
184991554f2SKenneth D. Merry 			mpr_dprint(sassc->sc, MPR_INIT,
185991554f2SKenneth D. Merry 			    "%s freezing simq\n", __func__);
186a371d6f9SKenneth D. Merry #if (__FreeBSD_version >= 1000039) || \
187a371d6f9SKenneth D. Merry     ((__FreeBSD_version < 1000000) && (__FreeBSD_version >= 902502))
188991554f2SKenneth D. Merry 			xpt_hold_boot();
189991554f2SKenneth D. Merry #endif
190991554f2SKenneth D. Merry 			xpt_freeze_simq(sassc->sim, 1);
191991554f2SKenneth D. Merry 		}
192991554f2SKenneth D. Merry 		mpr_dprint(sassc->sc, MPR_INIT, "%s refcount %u\n", __func__,
193991554f2SKenneth D. Merry 		    sassc->startup_refcount);
194991554f2SKenneth D. Merry 	}
195991554f2SKenneth D. Merry }
196991554f2SKenneth D. Merry 
197991554f2SKenneth D. Merry void
198991554f2SKenneth D. Merry mprsas_release_simq_reinit(struct mprsas_softc *sassc)
199991554f2SKenneth D. Merry {
200991554f2SKenneth D. Merry 	if (sassc->flags & MPRSAS_QUEUE_FROZEN) {
201991554f2SKenneth D. Merry 		sassc->flags &= ~MPRSAS_QUEUE_FROZEN;
202991554f2SKenneth D. Merry 		xpt_release_simq(sassc->sim, 1);
203991554f2SKenneth D. Merry 		mpr_dprint(sassc->sc, MPR_INFO, "Unfreezing SIM queue\n");
204991554f2SKenneth D. Merry 	}
205991554f2SKenneth D. Merry }
206991554f2SKenneth D. Merry 
207991554f2SKenneth D. Merry void
208991554f2SKenneth D. Merry mprsas_startup_decrement(struct mprsas_softc *sassc)
209991554f2SKenneth D. Merry {
210991554f2SKenneth D. Merry 	MPR_FUNCTRACE(sassc->sc);
211991554f2SKenneth D. Merry 
212991554f2SKenneth D. Merry 	if ((sassc->flags & MPRSAS_IN_STARTUP) != 0) {
213991554f2SKenneth D. Merry 		if (--sassc->startup_refcount == 0) {
214991554f2SKenneth D. Merry 			/* finished all discovery-related actions, release
215991554f2SKenneth D. Merry 			 * the simq and rescan for the latest topology.
216991554f2SKenneth D. Merry 			 */
217991554f2SKenneth D. Merry 			mpr_dprint(sassc->sc, MPR_INIT,
218991554f2SKenneth D. Merry 			    "%s releasing simq\n", __func__);
219991554f2SKenneth D. Merry 			sassc->flags &= ~MPRSAS_IN_STARTUP;
220991554f2SKenneth D. Merry 			xpt_release_simq(sassc->sim, 1);
221a371d6f9SKenneth D. Merry #if (__FreeBSD_version >= 1000039) || \
222a371d6f9SKenneth D. Merry     ((__FreeBSD_version < 1000000) && (__FreeBSD_version >= 902502))
223991554f2SKenneth D. Merry 			xpt_release_boot();
224991554f2SKenneth D. Merry #else
225991554f2SKenneth D. Merry 			mprsas_rescan_target(sassc->sc, NULL);
226991554f2SKenneth D. Merry #endif
227991554f2SKenneth D. Merry 		}
228991554f2SKenneth D. Merry 		mpr_dprint(sassc->sc, MPR_INIT, "%s refcount %u\n", __func__,
229991554f2SKenneth D. Merry 		    sassc->startup_refcount);
230991554f2SKenneth D. Merry 	}
231991554f2SKenneth D. Merry }
232991554f2SKenneth D. Merry 
233991554f2SKenneth D. Merry /* LSI's firmware requires us to stop sending commands when we're doing task
234991554f2SKenneth D. Merry  * management, so refcount the TMs and keep the simq frozen when any are in
235991554f2SKenneth D. Merry  * use.
236991554f2SKenneth D. Merry  */
237991554f2SKenneth D. Merry struct mpr_command *
238991554f2SKenneth D. Merry mprsas_alloc_tm(struct mpr_softc *sc)
239991554f2SKenneth D. Merry {
240991554f2SKenneth D. Merry 	struct mpr_command *tm;
241991554f2SKenneth D. Merry 
242991554f2SKenneth D. Merry 	MPR_FUNCTRACE(sc);
243991554f2SKenneth D. Merry 	tm = mpr_alloc_high_priority_command(sc);
244991554f2SKenneth D. Merry 	if (tm != NULL) {
245991554f2SKenneth D. Merry 		if (sc->sassc->tm_count++ == 0) {
246991554f2SKenneth D. Merry 			mpr_dprint(sc, MPR_RECOVERY,
247991554f2SKenneth D. Merry 			    "%s freezing simq\n", __func__);
248991554f2SKenneth D. Merry 			xpt_freeze_simq(sc->sassc->sim, 1);
249991554f2SKenneth D. Merry 		}
250991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_RECOVERY, "%s tm_count %u\n", __func__,
251991554f2SKenneth D. Merry 		    sc->sassc->tm_count);
252991554f2SKenneth D. Merry 	}
253991554f2SKenneth D. Merry 	return tm;
254991554f2SKenneth D. Merry }
255991554f2SKenneth D. Merry 
256991554f2SKenneth D. Merry void
257991554f2SKenneth D. Merry mprsas_free_tm(struct mpr_softc *sc, struct mpr_command *tm)
258991554f2SKenneth D. Merry {
259991554f2SKenneth D. Merry 	mpr_dprint(sc, MPR_TRACE, "%s", __func__);
260991554f2SKenneth D. Merry 	if (tm == NULL)
261991554f2SKenneth D. Merry 		return;
262991554f2SKenneth D. Merry 
263991554f2SKenneth D. Merry 	/* if there are no TMs in use, we can release the simq.  We use our
264991554f2SKenneth D. Merry 	 * own refcount so that it's easier for a diag reset to cleanup and
265991554f2SKenneth D. Merry 	 * release the simq.
266991554f2SKenneth D. Merry 	 */
267991554f2SKenneth D. Merry 	if (--sc->sassc->tm_count == 0) {
268991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_RECOVERY, "%s releasing simq\n", __func__);
269991554f2SKenneth D. Merry 		xpt_release_simq(sc->sassc->sim, 1);
270991554f2SKenneth D. Merry 	}
271991554f2SKenneth D. Merry 	mpr_dprint(sc, MPR_RECOVERY, "%s tm_count %u\n", __func__,
272991554f2SKenneth D. Merry 	    sc->sassc->tm_count);
273991554f2SKenneth D. Merry 
274991554f2SKenneth D. Merry 	mpr_free_high_priority_command(sc, tm);
275991554f2SKenneth D. Merry }
276991554f2SKenneth D. Merry 
277991554f2SKenneth D. Merry void
278991554f2SKenneth D. Merry mprsas_rescan_target(struct mpr_softc *sc, struct mprsas_target *targ)
279991554f2SKenneth D. Merry {
280991554f2SKenneth D. Merry 	struct mprsas_softc *sassc = sc->sassc;
281991554f2SKenneth D. Merry 	path_id_t pathid;
282991554f2SKenneth D. Merry 	target_id_t targetid;
283991554f2SKenneth D. Merry 	union ccb *ccb;
284991554f2SKenneth D. Merry 
285991554f2SKenneth D. Merry 	MPR_FUNCTRACE(sc);
286991554f2SKenneth D. Merry 	pathid = cam_sim_path(sassc->sim);
287991554f2SKenneth D. Merry 	if (targ == NULL)
288991554f2SKenneth D. Merry 		targetid = CAM_TARGET_WILDCARD;
289991554f2SKenneth D. Merry 	else
290991554f2SKenneth D. Merry 		targetid = targ - sassc->targets;
291991554f2SKenneth D. Merry 
292991554f2SKenneth D. Merry 	/*
293991554f2SKenneth D. Merry 	 * Allocate a CCB and schedule a rescan.
294991554f2SKenneth D. Merry 	 */
295991554f2SKenneth D. Merry 	ccb = xpt_alloc_ccb_nowait();
296991554f2SKenneth D. Merry 	if (ccb == NULL) {
297991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_ERROR, "unable to alloc CCB for rescan\n");
298991554f2SKenneth D. Merry 		return;
299991554f2SKenneth D. Merry 	}
300991554f2SKenneth D. Merry 
301991554f2SKenneth D. Merry 	if (xpt_create_path(&ccb->ccb_h.path, NULL, pathid,
302991554f2SKenneth D. Merry 	    targetid, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
303991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_ERROR, "unable to create path for rescan\n");
304991554f2SKenneth D. Merry 		xpt_free_ccb(ccb);
305991554f2SKenneth D. Merry 		return;
306991554f2SKenneth D. Merry 	}
307991554f2SKenneth D. Merry 
308991554f2SKenneth D. Merry 	if (targetid == CAM_TARGET_WILDCARD)
309991554f2SKenneth D. Merry 		ccb->ccb_h.func_code = XPT_SCAN_BUS;
310991554f2SKenneth D. Merry 	else
311991554f2SKenneth D. Merry 		ccb->ccb_h.func_code = XPT_SCAN_TGT;
312991554f2SKenneth D. Merry 
313991554f2SKenneth D. Merry 	mpr_dprint(sc, MPR_TRACE, "%s targetid %u\n", __func__, targetid);
314991554f2SKenneth D. Merry 	xpt_rescan(ccb);
315991554f2SKenneth D. Merry }
316991554f2SKenneth D. Merry 
317991554f2SKenneth D. Merry static void
318991554f2SKenneth D. Merry mprsas_log_command(struct mpr_command *cm, u_int level, const char *fmt, ...)
319991554f2SKenneth D. Merry {
320991554f2SKenneth D. Merry 	struct sbuf sb;
321991554f2SKenneth D. Merry 	va_list ap;
322991554f2SKenneth D. Merry 	char str[192];
323991554f2SKenneth D. Merry 	char path_str[64];
324991554f2SKenneth D. Merry 
325991554f2SKenneth D. Merry 	if (cm == NULL)
326991554f2SKenneth D. Merry 		return;
327991554f2SKenneth D. Merry 
328991554f2SKenneth D. Merry 	/* No need to be in here if debugging isn't enabled */
329991554f2SKenneth D. Merry 	if ((cm->cm_sc->mpr_debug & level) == 0)
330991554f2SKenneth D. Merry 		return;
331991554f2SKenneth D. Merry 
332991554f2SKenneth D. Merry 	sbuf_new(&sb, str, sizeof(str), 0);
333991554f2SKenneth D. Merry 
334991554f2SKenneth D. Merry 	va_start(ap, fmt);
335991554f2SKenneth D. Merry 
336991554f2SKenneth D. Merry 	if (cm->cm_ccb != NULL) {
337991554f2SKenneth D. Merry 		xpt_path_string(cm->cm_ccb->csio.ccb_h.path, path_str,
338991554f2SKenneth D. Merry 		    sizeof(path_str));
339991554f2SKenneth D. Merry 		sbuf_cat(&sb, path_str);
340991554f2SKenneth D. Merry 		if (cm->cm_ccb->ccb_h.func_code == XPT_SCSI_IO) {
341991554f2SKenneth D. Merry 			scsi_command_string(&cm->cm_ccb->csio, &sb);
342991554f2SKenneth D. Merry 			sbuf_printf(&sb, "length %d ",
343991554f2SKenneth D. Merry 			    cm->cm_ccb->csio.dxfer_len);
344991554f2SKenneth D. Merry 		}
345991554f2SKenneth D. Merry 	} else {
346991554f2SKenneth D. Merry 		sbuf_printf(&sb, "(noperiph:%s%d:%u:%u:%u): ",
347991554f2SKenneth D. Merry 		    cam_sim_name(cm->cm_sc->sassc->sim),
348991554f2SKenneth D. Merry 		    cam_sim_unit(cm->cm_sc->sassc->sim),
349991554f2SKenneth D. Merry 		    cam_sim_bus(cm->cm_sc->sassc->sim),
350991554f2SKenneth D. Merry 		    cm->cm_targ ? cm->cm_targ->tid : 0xFFFFFFFF,
351991554f2SKenneth D. Merry 		    cm->cm_lun);
352991554f2SKenneth D. Merry 	}
353991554f2SKenneth D. Merry 
354991554f2SKenneth D. Merry 	sbuf_printf(&sb, "SMID %u ", cm->cm_desc.Default.SMID);
355991554f2SKenneth D. Merry 	sbuf_vprintf(&sb, fmt, ap);
356991554f2SKenneth D. Merry 	sbuf_finish(&sb);
357991554f2SKenneth D. Merry 	mpr_dprint_field(cm->cm_sc, level, "%s", sbuf_data(&sb));
358991554f2SKenneth D. Merry 
359991554f2SKenneth D. Merry 	va_end(ap);
360991554f2SKenneth D. Merry }
361991554f2SKenneth D. Merry 
362991554f2SKenneth D. Merry static void
363991554f2SKenneth D. Merry mprsas_remove_volume(struct mpr_softc *sc, struct mpr_command *tm)
364991554f2SKenneth D. Merry {
365991554f2SKenneth D. Merry 	MPI2_SCSI_TASK_MANAGE_REPLY *reply;
366991554f2SKenneth D. Merry 	struct mprsas_target *targ;
367991554f2SKenneth D. Merry 	uint16_t handle;
368991554f2SKenneth D. Merry 
369991554f2SKenneth D. Merry 	MPR_FUNCTRACE(sc);
370991554f2SKenneth D. Merry 
371991554f2SKenneth D. Merry 	reply = (MPI2_SCSI_TASK_MANAGE_REPLY *)tm->cm_reply;
372991554f2SKenneth D. Merry 	handle = (uint16_t)(uintptr_t)tm->cm_complete_data;
373991554f2SKenneth D. Merry 	targ = tm->cm_targ;
374991554f2SKenneth D. Merry 
375991554f2SKenneth D. Merry 	if (reply == NULL) {
376991554f2SKenneth D. Merry 		/* XXX retry the remove after the diag reset completes? */
377991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_FAULT, "%s NULL reply resetting device "
378991554f2SKenneth D. Merry 		    "0x%04x\n", __func__, handle);
379991554f2SKenneth D. Merry 		mprsas_free_tm(sc, tm);
380991554f2SKenneth D. Merry 		return;
381991554f2SKenneth D. Merry 	}
382991554f2SKenneth D. Merry 
383991554f2SKenneth D. Merry 	if (reply->IOCStatus != MPI2_IOCSTATUS_SUCCESS) {
384991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_FAULT, "IOCStatus = 0x%x while resetting "
385991554f2SKenneth D. Merry 		    "device 0x%x\n", reply->IOCStatus, handle);
386991554f2SKenneth D. Merry 		mprsas_free_tm(sc, tm);
387991554f2SKenneth D. Merry 		return;
388991554f2SKenneth D. Merry 	}
389991554f2SKenneth D. Merry 
390991554f2SKenneth D. Merry 	mpr_dprint(sc, MPR_XINFO, "Reset aborted %u commands\n",
391991554f2SKenneth D. Merry 	    reply->TerminationCount);
392991554f2SKenneth D. Merry 	mpr_free_reply(sc, tm->cm_reply_data);
393991554f2SKenneth D. Merry 	tm->cm_reply = NULL;	/* Ensures the reply won't get re-freed */
394991554f2SKenneth D. Merry 
395991554f2SKenneth D. Merry 	mpr_dprint(sc, MPR_XINFO, "clearing target %u handle 0x%04x\n",
396991554f2SKenneth D. Merry 	    targ->tid, handle);
397991554f2SKenneth D. Merry 
398991554f2SKenneth D. Merry 	/*
399991554f2SKenneth D. Merry 	 * Don't clear target if remove fails because things will get confusing.
400991554f2SKenneth D. Merry 	 * Leave the devname and sasaddr intact so that we know to avoid reusing
401991554f2SKenneth D. Merry 	 * this target id if possible, and so we can assign the same target id
402991554f2SKenneth D. Merry 	 * to this device if it comes back in the future.
403991554f2SKenneth D. Merry 	 */
404991554f2SKenneth D. Merry 	if (reply->IOCStatus == MPI2_IOCSTATUS_SUCCESS) {
405991554f2SKenneth D. Merry 		targ = tm->cm_targ;
406991554f2SKenneth D. Merry 		targ->handle = 0x0;
407991554f2SKenneth D. Merry 		targ->encl_handle = 0x0;
408991554f2SKenneth D. Merry 		targ->encl_level_valid = 0x0;
409991554f2SKenneth D. Merry 		targ->encl_level = 0x0;
410991554f2SKenneth D. Merry 		targ->connector_name[0] = ' ';
411991554f2SKenneth D. Merry 		targ->connector_name[1] = ' ';
412991554f2SKenneth D. Merry 		targ->connector_name[2] = ' ';
413991554f2SKenneth D. Merry 		targ->connector_name[3] = ' ';
414991554f2SKenneth D. Merry 		targ->encl_slot = 0x0;
415991554f2SKenneth D. Merry 		targ->exp_dev_handle = 0x0;
416991554f2SKenneth D. Merry 		targ->phy_num = 0x0;
417991554f2SKenneth D. Merry 		targ->linkrate = 0x0;
418991554f2SKenneth D. Merry 		targ->devinfo = 0x0;
419991554f2SKenneth D. Merry 		targ->flags = 0x0;
420991554f2SKenneth D. Merry 		targ->scsi_req_desc_type = 0;
421991554f2SKenneth D. Merry 	}
422991554f2SKenneth D. Merry 
423991554f2SKenneth D. Merry 	mprsas_free_tm(sc, tm);
424991554f2SKenneth D. Merry }
425991554f2SKenneth D. Merry 
426991554f2SKenneth D. Merry 
427991554f2SKenneth D. Merry /*
428991554f2SKenneth D. Merry  * No Need to call "MPI2_SAS_OP_REMOVE_DEVICE" For Volume removal.
429991554f2SKenneth D. Merry  * Otherwise Volume Delete is same as Bare Drive Removal.
430991554f2SKenneth D. Merry  */
431991554f2SKenneth D. Merry void
432991554f2SKenneth D. Merry mprsas_prepare_volume_remove(struct mprsas_softc *sassc, uint16_t handle)
433991554f2SKenneth D. Merry {
434991554f2SKenneth D. Merry 	MPI2_SCSI_TASK_MANAGE_REQUEST *req;
435991554f2SKenneth D. Merry 	struct mpr_softc *sc;
436991554f2SKenneth D. Merry 	struct mpr_command *cm;
437991554f2SKenneth D. Merry 	struct mprsas_target *targ = NULL;
438991554f2SKenneth D. Merry 
439991554f2SKenneth D. Merry 	MPR_FUNCTRACE(sassc->sc);
440991554f2SKenneth D. Merry 	sc = sassc->sc;
441991554f2SKenneth D. Merry 
442991554f2SKenneth D. Merry 	targ = mprsas_find_target_by_handle(sassc, 0, handle);
443991554f2SKenneth D. Merry 	if (targ == NULL) {
444991554f2SKenneth D. Merry 		/* FIXME: what is the action? */
445991554f2SKenneth D. Merry 		/* We don't know about this device? */
446991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_ERROR,
447991554f2SKenneth D. Merry 		   "%s %d : invalid handle 0x%x \n", __func__,__LINE__, handle);
448991554f2SKenneth D. Merry 		return;
449991554f2SKenneth D. Merry 	}
450991554f2SKenneth D. Merry 
451991554f2SKenneth D. Merry 	targ->flags |= MPRSAS_TARGET_INREMOVAL;
452991554f2SKenneth D. Merry 
453991554f2SKenneth D. Merry 	cm = mprsas_alloc_tm(sc);
454991554f2SKenneth D. Merry 	if (cm == NULL) {
455991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_ERROR,
456991554f2SKenneth D. Merry 		    "%s: command alloc failure\n", __func__);
457991554f2SKenneth D. Merry 		return;
458991554f2SKenneth D. Merry 	}
459991554f2SKenneth D. Merry 
460991554f2SKenneth D. Merry 	mprsas_rescan_target(sc, targ);
461991554f2SKenneth D. Merry 
462991554f2SKenneth D. Merry 	req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)cm->cm_req;
463991554f2SKenneth D. Merry 	req->DevHandle = targ->handle;
464991554f2SKenneth D. Merry 	req->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
465991554f2SKenneth D. Merry 	req->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
466991554f2SKenneth D. Merry 
467991554f2SKenneth D. Merry 	/* SAS Hard Link Reset / SATA Link Reset */
468991554f2SKenneth D. Merry 	req->MsgFlags = MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET;
469991554f2SKenneth D. Merry 
470991554f2SKenneth D. Merry 	cm->cm_targ = targ;
471991554f2SKenneth D. Merry 	cm->cm_data = NULL;
472991554f2SKenneth D. Merry 	cm->cm_desc.HighPriority.RequestFlags =
473991554f2SKenneth D. Merry 	    MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY;
474991554f2SKenneth D. Merry 	cm->cm_complete = mprsas_remove_volume;
475991554f2SKenneth D. Merry 	cm->cm_complete_data = (void *)(uintptr_t)handle;
476991554f2SKenneth D. Merry 	mpr_map_command(sc, cm);
477991554f2SKenneth D. Merry }
478991554f2SKenneth D. Merry 
479991554f2SKenneth D. Merry /*
480991554f2SKenneth D. Merry  * The MPT2 firmware performs debounce on the link to avoid transient link
481991554f2SKenneth D. Merry  * errors and false removals.  When it does decide that link has been lost
482991554f2SKenneth D. Merry  * and a device needs to go away, it expects that the host will perform a
483991554f2SKenneth D. Merry  * target reset and then an op remove.  The reset has the side-effect of
484991554f2SKenneth D. Merry  * aborting any outstanding requests for the device, which is required for
485991554f2SKenneth D. Merry  * the op-remove to succeed.  It's not clear if the host should check for
486991554f2SKenneth D. Merry  * the device coming back alive after the reset.
487991554f2SKenneth D. Merry  */
488991554f2SKenneth D. Merry void
489991554f2SKenneth D. Merry mprsas_prepare_remove(struct mprsas_softc *sassc, uint16_t handle)
490991554f2SKenneth D. Merry {
491991554f2SKenneth D. Merry 	MPI2_SCSI_TASK_MANAGE_REQUEST *req;
492991554f2SKenneth D. Merry 	struct mpr_softc *sc;
493991554f2SKenneth D. Merry 	struct mpr_command *cm;
494991554f2SKenneth D. Merry 	struct mprsas_target *targ = NULL;
495991554f2SKenneth D. Merry 
496991554f2SKenneth D. Merry 	MPR_FUNCTRACE(sassc->sc);
497991554f2SKenneth D. Merry 
498991554f2SKenneth D. Merry 	sc = sassc->sc;
499991554f2SKenneth D. Merry 
500991554f2SKenneth D. Merry 	targ = mprsas_find_target_by_handle(sassc, 0, handle);
501991554f2SKenneth D. Merry 	if (targ == NULL) {
502991554f2SKenneth D. Merry 		/* FIXME: what is the action? */
503991554f2SKenneth D. Merry 		/* We don't know about this device? */
504991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_ERROR, "%s : invalid handle 0x%x \n",
505991554f2SKenneth D. Merry 		    __func__, handle);
506991554f2SKenneth D. Merry 		return;
507991554f2SKenneth D. Merry 	}
508991554f2SKenneth D. Merry 
509991554f2SKenneth D. Merry 	targ->flags |= MPRSAS_TARGET_INREMOVAL;
510991554f2SKenneth D. Merry 
511991554f2SKenneth D. Merry 	cm = mprsas_alloc_tm(sc);
512991554f2SKenneth D. Merry 	if (cm == NULL) {
513991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_ERROR, "%s: command alloc failure\n",
514991554f2SKenneth D. Merry 		    __func__);
515991554f2SKenneth D. Merry 		return;
516991554f2SKenneth D. Merry 	}
517991554f2SKenneth D. Merry 
518991554f2SKenneth D. Merry 	mprsas_rescan_target(sc, targ);
519991554f2SKenneth D. Merry 
520991554f2SKenneth D. Merry 	req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)cm->cm_req;
521991554f2SKenneth D. Merry 	memset(req, 0, sizeof(*req));
522991554f2SKenneth D. Merry 	req->DevHandle = htole16(targ->handle);
523991554f2SKenneth D. Merry 	req->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
524991554f2SKenneth D. Merry 	req->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
525991554f2SKenneth D. Merry 
526991554f2SKenneth D. Merry 	/* SAS Hard Link Reset / SATA Link Reset */
527991554f2SKenneth D. Merry 	req->MsgFlags = MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET;
528991554f2SKenneth D. Merry 
529991554f2SKenneth D. Merry 	cm->cm_targ = targ;
530991554f2SKenneth D. Merry 	cm->cm_data = NULL;
531991554f2SKenneth D. Merry 	cm->cm_desc.HighPriority.RequestFlags =
532991554f2SKenneth D. Merry 	    MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY;
533991554f2SKenneth D. Merry 	cm->cm_complete = mprsas_remove_device;
534991554f2SKenneth D. Merry 	cm->cm_complete_data = (void *)(uintptr_t)handle;
535991554f2SKenneth D. Merry 	mpr_map_command(sc, cm);
536991554f2SKenneth D. Merry }
537991554f2SKenneth D. Merry 
538991554f2SKenneth D. Merry static void
539991554f2SKenneth D. Merry mprsas_remove_device(struct mpr_softc *sc, struct mpr_command *tm)
540991554f2SKenneth D. Merry {
541991554f2SKenneth D. Merry 	MPI2_SCSI_TASK_MANAGE_REPLY *reply;
542991554f2SKenneth D. Merry 	MPI2_SAS_IOUNIT_CONTROL_REQUEST *req;
543991554f2SKenneth D. Merry 	struct mprsas_target *targ;
544991554f2SKenneth D. Merry 	struct mpr_command *next_cm;
545991554f2SKenneth D. Merry 	uint16_t handle;
546991554f2SKenneth D. Merry 
547991554f2SKenneth D. Merry 	MPR_FUNCTRACE(sc);
548991554f2SKenneth D. Merry 
549991554f2SKenneth D. Merry 	reply = (MPI2_SCSI_TASK_MANAGE_REPLY *)tm->cm_reply;
550991554f2SKenneth D. Merry 	handle = (uint16_t)(uintptr_t)tm->cm_complete_data;
551991554f2SKenneth D. Merry 	targ = tm->cm_targ;
552991554f2SKenneth D. Merry 
553991554f2SKenneth D. Merry 	/*
554991554f2SKenneth D. Merry 	 * Currently there should be no way we can hit this case.  It only
555991554f2SKenneth D. Merry 	 * happens when we have a failure to allocate chain frames, and
556991554f2SKenneth D. Merry 	 * task management commands don't have S/G lists.
557991554f2SKenneth D. Merry 	 */
558991554f2SKenneth D. Merry 	if ((tm->cm_flags & MPR_CM_FLAGS_ERROR_MASK) != 0) {
559991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_ERROR, "%s: cm_flags = %#x for remove of "
560991554f2SKenneth D. Merry 		    "handle %#04x! This should not happen!\n", __func__,
561991554f2SKenneth D. Merry 		    tm->cm_flags, handle);
562991554f2SKenneth D. Merry 		mprsas_free_tm(sc, tm);
563991554f2SKenneth D. Merry 		return;
564991554f2SKenneth D. Merry 	}
565991554f2SKenneth D. Merry 
566991554f2SKenneth D. Merry 	if (reply == NULL) {
567991554f2SKenneth D. Merry 		/* XXX retry the remove after the diag reset completes? */
568991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_FAULT, "%s NULL reply resetting device "
569991554f2SKenneth D. Merry 		    "0x%04x\n", __func__, handle);
570991554f2SKenneth D. Merry 		mprsas_free_tm(sc, tm);
571991554f2SKenneth D. Merry 		return;
572991554f2SKenneth D. Merry 	}
573991554f2SKenneth D. Merry 
574991554f2SKenneth D. Merry 	if (le16toh(reply->IOCStatus) != MPI2_IOCSTATUS_SUCCESS) {
575991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_FAULT, "IOCStatus = 0x%x while resetting "
576991554f2SKenneth D. Merry 		    "device 0x%x\n", le16toh(reply->IOCStatus), handle);
577991554f2SKenneth D. Merry 		mprsas_free_tm(sc, tm);
578991554f2SKenneth D. Merry 		return;
579991554f2SKenneth D. Merry 	}
580991554f2SKenneth D. Merry 
581991554f2SKenneth D. Merry 	mpr_dprint(sc, MPR_XINFO, "Reset aborted %u commands\n",
582991554f2SKenneth D. Merry 	    le32toh(reply->TerminationCount));
583991554f2SKenneth D. Merry 	mpr_free_reply(sc, tm->cm_reply_data);
584991554f2SKenneth D. Merry 	tm->cm_reply = NULL;	/* Ensures the reply won't get re-freed */
585991554f2SKenneth D. Merry 
586991554f2SKenneth D. Merry 	/* Reuse the existing command */
587991554f2SKenneth D. Merry 	req = (MPI2_SAS_IOUNIT_CONTROL_REQUEST *)tm->cm_req;
588991554f2SKenneth D. Merry 	memset(req, 0, sizeof(*req));
589991554f2SKenneth D. Merry 	req->Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL;
590991554f2SKenneth D. Merry 	req->Operation = MPI2_SAS_OP_REMOVE_DEVICE;
591991554f2SKenneth D. Merry 	req->DevHandle = htole16(handle);
592991554f2SKenneth D. Merry 	tm->cm_data = NULL;
593991554f2SKenneth D. Merry 	tm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
594991554f2SKenneth D. Merry 	tm->cm_complete = mprsas_remove_complete;
595991554f2SKenneth D. Merry 	tm->cm_complete_data = (void *)(uintptr_t)handle;
596991554f2SKenneth D. Merry 
597991554f2SKenneth D. Merry 	mpr_map_command(sc, tm);
598991554f2SKenneth D. Merry 
599991554f2SKenneth D. Merry 	mpr_dprint(sc, MPR_XINFO, "clearing target %u handle 0x%04x\n",
600991554f2SKenneth D. Merry 	    targ->tid, handle);
601991554f2SKenneth D. Merry 	if (targ->encl_level_valid) {
602991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_XINFO, "At enclosure level %d, slot %d, "
603991554f2SKenneth D. Merry 		    "connector name (%4s)\n", targ->encl_level, targ->encl_slot,
604991554f2SKenneth D. Merry 		    targ->connector_name);
605991554f2SKenneth D. Merry 	}
606991554f2SKenneth D. Merry 	TAILQ_FOREACH_SAFE(tm, &targ->commands, cm_link, next_cm) {
607991554f2SKenneth D. Merry 		union ccb *ccb;
608991554f2SKenneth D. Merry 
609991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_XINFO, "Completing missed command %p\n", tm);
610991554f2SKenneth D. Merry 		ccb = tm->cm_complete_data;
611991554f2SKenneth D. Merry 		ccb->ccb_h.status = CAM_DEV_NOT_THERE;
612991554f2SKenneth D. Merry 		mprsas_scsiio_complete(sc, tm);
613991554f2SKenneth D. Merry 	}
614991554f2SKenneth D. Merry }
615991554f2SKenneth D. Merry 
616991554f2SKenneth D. Merry static void
617991554f2SKenneth D. Merry mprsas_remove_complete(struct mpr_softc *sc, struct mpr_command *tm)
618991554f2SKenneth D. Merry {
619991554f2SKenneth D. Merry 	MPI2_SAS_IOUNIT_CONTROL_REPLY *reply;
620991554f2SKenneth D. Merry 	uint16_t handle;
621991554f2SKenneth D. Merry 	struct mprsas_target *targ;
622991554f2SKenneth D. Merry 	struct mprsas_lun *lun;
623991554f2SKenneth D. Merry 
624991554f2SKenneth D. Merry 	MPR_FUNCTRACE(sc);
625991554f2SKenneth D. Merry 
626991554f2SKenneth D. Merry 	reply = (MPI2_SAS_IOUNIT_CONTROL_REPLY *)tm->cm_reply;
627991554f2SKenneth D. Merry 	handle = (uint16_t)(uintptr_t)tm->cm_complete_data;
628991554f2SKenneth D. Merry 
629991554f2SKenneth D. Merry 	/*
630991554f2SKenneth D. Merry 	 * Currently there should be no way we can hit this case.  It only
631991554f2SKenneth D. Merry 	 * happens when we have a failure to allocate chain frames, and
632991554f2SKenneth D. Merry 	 * task management commands don't have S/G lists.
633991554f2SKenneth D. Merry 	 */
634991554f2SKenneth D. Merry 	if ((tm->cm_flags & MPR_CM_FLAGS_ERROR_MASK) != 0) {
635991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_XINFO, "%s: cm_flags = %#x for remove of "
636991554f2SKenneth D. Merry 		    "handle %#04x! This should not happen!\n", __func__,
637991554f2SKenneth D. Merry 		    tm->cm_flags, handle);
638991554f2SKenneth D. Merry 		mprsas_free_tm(sc, tm);
639991554f2SKenneth D. Merry 		return;
640991554f2SKenneth D. Merry 	}
641991554f2SKenneth D. Merry 
642991554f2SKenneth D. Merry 	if (reply == NULL) {
643991554f2SKenneth D. Merry 		/* most likely a chip reset */
644991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_FAULT, "%s NULL reply removing device "
645991554f2SKenneth D. Merry 		    "0x%04x\n", __func__, handle);
646991554f2SKenneth D. Merry 		mprsas_free_tm(sc, tm);
647991554f2SKenneth D. Merry 		return;
648991554f2SKenneth D. Merry 	}
649991554f2SKenneth D. Merry 
650991554f2SKenneth D. Merry 	mpr_dprint(sc, MPR_XINFO, "%s on handle 0x%04x, IOCStatus= 0x%x\n",
651991554f2SKenneth D. Merry 	    __func__, handle, le16toh(reply->IOCStatus));
652991554f2SKenneth D. Merry 
653991554f2SKenneth D. Merry 	/*
654991554f2SKenneth D. Merry 	 * Don't clear target if remove fails because things will get confusing.
655991554f2SKenneth D. Merry 	 * Leave the devname and sasaddr intact so that we know to avoid reusing
656991554f2SKenneth D. Merry 	 * this target id if possible, and so we can assign the same target id
657991554f2SKenneth D. Merry 	 * to this device if it comes back in the future.
658991554f2SKenneth D. Merry 	 */
659991554f2SKenneth D. Merry 	if (le16toh(reply->IOCStatus) == MPI2_IOCSTATUS_SUCCESS) {
660991554f2SKenneth D. Merry 		targ = tm->cm_targ;
661991554f2SKenneth D. Merry 		targ->handle = 0x0;
662991554f2SKenneth D. Merry 		targ->encl_handle = 0x0;
663991554f2SKenneth D. Merry 		targ->encl_level_valid = 0x0;
664991554f2SKenneth D. Merry 		targ->encl_level = 0x0;
665991554f2SKenneth D. Merry 		targ->connector_name[0] = ' ';
666991554f2SKenneth D. Merry 		targ->connector_name[1] = ' ';
667991554f2SKenneth D. Merry 		targ->connector_name[2] = ' ';
668991554f2SKenneth D. Merry 		targ->connector_name[3] = ' ';
669991554f2SKenneth D. Merry 		targ->encl_slot = 0x0;
670991554f2SKenneth D. Merry 		targ->exp_dev_handle = 0x0;
671991554f2SKenneth D. Merry 		targ->phy_num = 0x0;
672991554f2SKenneth D. Merry 		targ->linkrate = 0x0;
673991554f2SKenneth D. Merry 		targ->devinfo = 0x0;
674991554f2SKenneth D. Merry 		targ->flags = 0x0;
675991554f2SKenneth D. Merry 		targ->scsi_req_desc_type = 0;
676991554f2SKenneth D. Merry 
677991554f2SKenneth D. Merry 		while (!SLIST_EMPTY(&targ->luns)) {
678991554f2SKenneth D. Merry 			lun = SLIST_FIRST(&targ->luns);
679991554f2SKenneth D. Merry 			SLIST_REMOVE_HEAD(&targ->luns, lun_link);
680991554f2SKenneth D. Merry 			free(lun, M_MPR);
681991554f2SKenneth D. Merry 		}
682991554f2SKenneth D. Merry 	}
683991554f2SKenneth D. Merry 
684991554f2SKenneth D. Merry 	mprsas_free_tm(sc, tm);
685991554f2SKenneth D. Merry }
686991554f2SKenneth D. Merry 
687991554f2SKenneth D. Merry static int
688991554f2SKenneth D. Merry mprsas_register_events(struct mpr_softc *sc)
689991554f2SKenneth D. Merry {
690991554f2SKenneth D. Merry 	uint8_t events[16];
691991554f2SKenneth D. Merry 
692991554f2SKenneth D. Merry 	bzero(events, 16);
693991554f2SKenneth D. Merry 	setbit(events, MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE);
694991554f2SKenneth D. Merry 	setbit(events, MPI2_EVENT_SAS_DISCOVERY);
695991554f2SKenneth D. Merry 	setbit(events, MPI2_EVENT_SAS_BROADCAST_PRIMITIVE);
696991554f2SKenneth D. Merry 	setbit(events, MPI2_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE);
697991554f2SKenneth D. Merry 	setbit(events, MPI2_EVENT_SAS_INIT_TABLE_OVERFLOW);
698991554f2SKenneth D. Merry 	setbit(events, MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST);
699991554f2SKenneth D. Merry 	setbit(events, MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE);
700991554f2SKenneth D. Merry 	setbit(events, MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST);
701991554f2SKenneth D. Merry 	setbit(events, MPI2_EVENT_IR_VOLUME);
702991554f2SKenneth D. Merry 	setbit(events, MPI2_EVENT_IR_PHYSICAL_DISK);
703991554f2SKenneth D. Merry 	setbit(events, MPI2_EVENT_IR_OPERATION_STATUS);
704991554f2SKenneth D. Merry 	setbit(events, MPI2_EVENT_TEMP_THRESHOLD);
705991554f2SKenneth D. Merry 
706991554f2SKenneth D. Merry 	mpr_register_events(sc, events, mprsas_evt_handler, NULL,
707991554f2SKenneth D. Merry 	    &sc->sassc->mprsas_eh);
708991554f2SKenneth D. Merry 
709991554f2SKenneth D. Merry 	return (0);
710991554f2SKenneth D. Merry }
711991554f2SKenneth D. Merry 
712991554f2SKenneth D. Merry int
713991554f2SKenneth D. Merry mpr_attach_sas(struct mpr_softc *sc)
714991554f2SKenneth D. Merry {
715991554f2SKenneth D. Merry 	struct mprsas_softc *sassc;
716991554f2SKenneth D. Merry 	cam_status status;
717991554f2SKenneth D. Merry 	int unit, error = 0;
718991554f2SKenneth D. Merry 
719991554f2SKenneth D. Merry 	MPR_FUNCTRACE(sc);
720991554f2SKenneth D. Merry 
721991554f2SKenneth D. Merry 	sassc = malloc(sizeof(struct mprsas_softc), M_MPR, M_WAITOK|M_ZERO);
722991554f2SKenneth D. Merry 	if (!sassc) {
723991554f2SKenneth D. Merry 		device_printf(sc->mpr_dev, "Cannot allocate memory %s %d\n",
724991554f2SKenneth D. Merry 		    __func__, __LINE__);
725991554f2SKenneth D. Merry 		return (ENOMEM);
726991554f2SKenneth D. Merry 	}
727991554f2SKenneth D. Merry 
728991554f2SKenneth D. Merry 	/*
729991554f2SKenneth D. Merry 	 * XXX MaxTargets could change during a reinit.  since we don't
730991554f2SKenneth D. Merry 	 * resize the targets[] array during such an event, cache the value
731991554f2SKenneth D. Merry 	 * of MaxTargets here so that we don't get into trouble later.  This
732991554f2SKenneth D. Merry 	 * should move into the reinit logic.
733991554f2SKenneth D. Merry 	 */
734991554f2SKenneth D. Merry 	sassc->maxtargets = sc->facts->MaxTargets;
735991554f2SKenneth D. Merry 	sassc->targets = malloc(sizeof(struct mprsas_target) *
736991554f2SKenneth D. Merry 	    sassc->maxtargets, M_MPR, M_WAITOK|M_ZERO);
737991554f2SKenneth D. Merry 	if (!sassc->targets) {
738991554f2SKenneth D. Merry 		device_printf(sc->mpr_dev, "Cannot allocate memory %s %d\n",
739991554f2SKenneth D. Merry 		    __func__, __LINE__);
740991554f2SKenneth D. Merry 		free(sassc, M_MPR);
741991554f2SKenneth D. Merry 		return (ENOMEM);
742991554f2SKenneth D. Merry 	}
743991554f2SKenneth D. Merry 	sc->sassc = sassc;
744991554f2SKenneth D. Merry 	sassc->sc = sc;
745991554f2SKenneth D. Merry 
746991554f2SKenneth D. Merry 	if ((sassc->devq = cam_simq_alloc(sc->num_reqs)) == NULL) {
747991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_ERROR, "Cannot allocate SIMQ\n");
748991554f2SKenneth D. Merry 		error = ENOMEM;
749991554f2SKenneth D. Merry 		goto out;
750991554f2SKenneth D. Merry 	}
751991554f2SKenneth D. Merry 
752991554f2SKenneth D. Merry 	unit = device_get_unit(sc->mpr_dev);
753991554f2SKenneth D. Merry 	sassc->sim = cam_sim_alloc(mprsas_action, mprsas_poll, "mpr", sassc,
754991554f2SKenneth D. Merry 	    unit, &sc->mpr_mtx, sc->num_reqs, sc->num_reqs, sassc->devq);
755991554f2SKenneth D. Merry 	if (sassc->sim == NULL) {
756991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_ERROR, "Cannot allocate SIM\n");
757991554f2SKenneth D. Merry 		error = EINVAL;
758991554f2SKenneth D. Merry 		goto out;
759991554f2SKenneth D. Merry 	}
760991554f2SKenneth D. Merry 
761991554f2SKenneth D. Merry 	TAILQ_INIT(&sassc->ev_queue);
762991554f2SKenneth D. Merry 
763991554f2SKenneth D. Merry 	/* Initialize taskqueue for Event Handling */
764991554f2SKenneth D. Merry 	TASK_INIT(&sassc->ev_task, 0, mprsas_firmware_event_work, sc);
765991554f2SKenneth D. Merry 	sassc->ev_tq = taskqueue_create("mpr_taskq", M_NOWAIT | M_ZERO,
766991554f2SKenneth D. Merry 	    taskqueue_thread_enqueue, &sassc->ev_tq);
767c2a0f07aSAlexander Motin 	taskqueue_start_threads(&sassc->ev_tq, 1, PRIBIO, "%s taskq",
768991554f2SKenneth D. Merry 	    device_get_nameunit(sc->mpr_dev));
769991554f2SKenneth D. Merry 
770991554f2SKenneth D. Merry 	mpr_lock(sc);
771991554f2SKenneth D. Merry 
772991554f2SKenneth D. Merry 	/*
773991554f2SKenneth D. Merry 	 * XXX There should be a bus for every port on the adapter, but since
774991554f2SKenneth D. Merry 	 * we're just going to fake the topology for now, we'll pretend that
775991554f2SKenneth D. Merry 	 * everything is just a target on a single bus.
776991554f2SKenneth D. Merry 	 */
777991554f2SKenneth D. Merry 	if ((error = xpt_bus_register(sassc->sim, sc->mpr_dev, 0)) != 0) {
778991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_ERROR, "Error %d registering SCSI bus\n",
779991554f2SKenneth D. Merry 		    error);
780991554f2SKenneth D. Merry 		mpr_unlock(sc);
781991554f2SKenneth D. Merry 		goto out;
782991554f2SKenneth D. Merry 	}
783991554f2SKenneth D. Merry 
784991554f2SKenneth D. Merry 	/*
785991554f2SKenneth D. Merry 	 * Assume that discovery events will start right away.  Freezing
786991554f2SKenneth D. Merry 	 *
787991554f2SKenneth D. Merry 	 * Hold off boot until discovery is complete.
788991554f2SKenneth D. Merry 	 */
789991554f2SKenneth D. Merry 	sassc->flags |= MPRSAS_IN_STARTUP | MPRSAS_IN_DISCOVERY;
790991554f2SKenneth D. Merry 	sc->sassc->startup_refcount = 0;
791991554f2SKenneth D. Merry 	mprsas_startup_increment(sassc);
792991554f2SKenneth D. Merry 
793991554f2SKenneth D. Merry 	callout_init(&sassc->discovery_callout, 1 /*mprafe*/);
794991554f2SKenneth D. Merry 
795991554f2SKenneth D. Merry 	sassc->tm_count = 0;
796991554f2SKenneth D. Merry 
797991554f2SKenneth D. Merry 	/*
798991554f2SKenneth D. Merry 	 * Register for async events so we can determine the EEDP
799991554f2SKenneth D. Merry 	 * capabilities of devices.
800991554f2SKenneth D. Merry 	 */
801991554f2SKenneth D. Merry 	status = xpt_create_path(&sassc->path, /*periph*/NULL,
802991554f2SKenneth D. Merry 	    cam_sim_path(sc->sassc->sim), CAM_TARGET_WILDCARD,
803991554f2SKenneth D. Merry 	    CAM_LUN_WILDCARD);
804991554f2SKenneth D. Merry 	if (status != CAM_REQ_CMP) {
805991554f2SKenneth D. Merry 		mpr_printf(sc, "Error %#x creating sim path\n", status);
806991554f2SKenneth D. Merry 		sassc->path = NULL;
807991554f2SKenneth D. Merry 	} else {
808991554f2SKenneth D. Merry 		int event;
809991554f2SKenneth D. Merry 
810991554f2SKenneth D. Merry #if (__FreeBSD_version >= 1000006) || \
811991554f2SKenneth D. Merry     ((__FreeBSD_version >= 901503) && (__FreeBSD_version < 1000000))
812991554f2SKenneth D. Merry 		event = AC_ADVINFO_CHANGED | AC_FOUND_DEVICE;
813991554f2SKenneth D. Merry #else
814991554f2SKenneth D. Merry 		event = AC_FOUND_DEVICE;
815991554f2SKenneth D. Merry #endif
81607aa4de1SKenneth D. Merry 
81707aa4de1SKenneth D. Merry 		/*
81807aa4de1SKenneth D. Merry 		 * Prior to the CAM locking improvements, we can't call
81907aa4de1SKenneth D. Merry 		 * xpt_register_async() with a particular path specified.
82007aa4de1SKenneth D. Merry 		 *
82107aa4de1SKenneth D. Merry 		 * If a path isn't specified, xpt_register_async() will
82207aa4de1SKenneth D. Merry 		 * generate a wildcard path and acquire the XPT lock while
82307aa4de1SKenneth D. Merry 		 * it calls xpt_action() to execute the XPT_SASYNC_CB CCB.
82407aa4de1SKenneth D. Merry 		 * It will then drop the XPT lock once that is done.
82507aa4de1SKenneth D. Merry 		 *
82607aa4de1SKenneth D. Merry 		 * If a path is specified for xpt_register_async(), it will
82707aa4de1SKenneth D. Merry 		 * not acquire and drop the XPT lock around the call to
82807aa4de1SKenneth D. Merry 		 * xpt_action().  xpt_action() asserts that the caller
82907aa4de1SKenneth D. Merry 		 * holds the SIM lock, so the SIM lock has to be held when
83007aa4de1SKenneth D. Merry 		 * calling xpt_register_async() when the path is specified.
83107aa4de1SKenneth D. Merry 		 *
83207aa4de1SKenneth D. Merry 		 * But xpt_register_async calls xpt_for_all_devices(),
83307aa4de1SKenneth D. Merry 		 * which calls xptbustraverse(), which will acquire each
83407aa4de1SKenneth D. Merry 		 * SIM lock.  When it traverses our particular bus, it will
83507aa4de1SKenneth D. Merry 		 * necessarily acquire the SIM lock, which will lead to a
83607aa4de1SKenneth D. Merry 		 * recursive lock acquisition.
83707aa4de1SKenneth D. Merry 		 *
83807aa4de1SKenneth D. Merry 		 * The CAM locking changes fix this problem by acquiring
83907aa4de1SKenneth D. Merry 		 * the XPT topology lock around bus traversal in
84007aa4de1SKenneth D. Merry 		 * xptbustraverse(), so the caller can hold the SIM lock
84107aa4de1SKenneth D. Merry 		 * and it does not cause a recursive lock acquisition.
84207aa4de1SKenneth D. Merry 		 *
84307aa4de1SKenneth D. Merry 		 * These __FreeBSD_version values are approximate, especially
84407aa4de1SKenneth D. Merry 		 * for stable/10, which is two months later than the actual
84507aa4de1SKenneth D. Merry 		 * change.
84607aa4de1SKenneth D. Merry 		 */
84707aa4de1SKenneth D. Merry 
84807aa4de1SKenneth D. Merry #if (__FreeBSD_version < 1000703) || \
84907aa4de1SKenneth D. Merry     ((__FreeBSD_version >= 1100000) && (__FreeBSD_version < 1100002))
85007aa4de1SKenneth D. Merry 		mpr_unlock(sc);
85107aa4de1SKenneth D. Merry 		status = xpt_register_async(event, mprsas_async, sc,
85207aa4de1SKenneth D. Merry 					    NULL);
85307aa4de1SKenneth D. Merry 		mpr_lock(sc);
85407aa4de1SKenneth D. Merry #else
855991554f2SKenneth D. Merry 		status = xpt_register_async(event, mprsas_async, sc,
856991554f2SKenneth D. Merry 					    sassc->path);
85707aa4de1SKenneth D. Merry #endif
85807aa4de1SKenneth D. Merry 
859991554f2SKenneth D. Merry 		if (status != CAM_REQ_CMP) {
860991554f2SKenneth D. Merry 			mpr_dprint(sc, MPR_ERROR,
861991554f2SKenneth D. Merry 			    "Error %#x registering async handler for "
862991554f2SKenneth D. Merry 			    "AC_ADVINFO_CHANGED events\n", status);
863991554f2SKenneth D. Merry 			xpt_free_path(sassc->path);
864991554f2SKenneth D. Merry 			sassc->path = NULL;
865991554f2SKenneth D. Merry 		}
866991554f2SKenneth D. Merry 	}
867991554f2SKenneth D. Merry 	if (status != CAM_REQ_CMP) {
868991554f2SKenneth D. Merry 		/*
869991554f2SKenneth D. Merry 		 * EEDP use is the exception, not the rule.
870991554f2SKenneth D. Merry 		 * Warn the user, but do not fail to attach.
871991554f2SKenneth D. Merry 		 */
872991554f2SKenneth D. Merry 		mpr_printf(sc, "EEDP capabilities disabled.\n");
873991554f2SKenneth D. Merry 	}
874991554f2SKenneth D. Merry 
875991554f2SKenneth D. Merry 	mpr_unlock(sc);
876991554f2SKenneth D. Merry 
877991554f2SKenneth D. Merry 	mprsas_register_events(sc);
878991554f2SKenneth D. Merry out:
879991554f2SKenneth D. Merry 	if (error)
880991554f2SKenneth D. Merry 		mpr_detach_sas(sc);
881991554f2SKenneth D. Merry 	return (error);
882991554f2SKenneth D. Merry }
883991554f2SKenneth D. Merry 
884991554f2SKenneth D. Merry int
885991554f2SKenneth D. Merry mpr_detach_sas(struct mpr_softc *sc)
886991554f2SKenneth D. Merry {
887991554f2SKenneth D. Merry 	struct mprsas_softc *sassc;
888991554f2SKenneth D. Merry 	struct mprsas_lun *lun, *lun_tmp;
889991554f2SKenneth D. Merry 	struct mprsas_target *targ;
890991554f2SKenneth D. Merry 	int i;
891991554f2SKenneth D. Merry 
892991554f2SKenneth D. Merry 	MPR_FUNCTRACE(sc);
893991554f2SKenneth D. Merry 
894991554f2SKenneth D. Merry 	if (sc->sassc == NULL)
895991554f2SKenneth D. Merry 		return (0);
896991554f2SKenneth D. Merry 
897991554f2SKenneth D. Merry 	sassc = sc->sassc;
898991554f2SKenneth D. Merry 	mpr_deregister_events(sc, sassc->mprsas_eh);
899991554f2SKenneth D. Merry 
900991554f2SKenneth D. Merry 	/*
901991554f2SKenneth D. Merry 	 * Drain and free the event handling taskqueue with the lock
902991554f2SKenneth D. Merry 	 * unheld so that any parallel processing tasks drain properly
903991554f2SKenneth D. Merry 	 * without deadlocking.
904991554f2SKenneth D. Merry 	 */
905991554f2SKenneth D. Merry 	if (sassc->ev_tq != NULL)
906991554f2SKenneth D. Merry 		taskqueue_free(sassc->ev_tq);
907991554f2SKenneth D. Merry 
908991554f2SKenneth D. Merry 	/* Make sure CAM doesn't wedge if we had to bail out early. */
909991554f2SKenneth D. Merry 	mpr_lock(sc);
910991554f2SKenneth D. Merry 
911991554f2SKenneth D. Merry 	/* Deregister our async handler */
912991554f2SKenneth D. Merry 	if (sassc->path != NULL) {
913991554f2SKenneth D. Merry 		xpt_register_async(0, mprsas_async, sc, sassc->path);
914991554f2SKenneth D. Merry 		xpt_free_path(sassc->path);
915991554f2SKenneth D. Merry 		sassc->path = NULL;
916991554f2SKenneth D. Merry 	}
917991554f2SKenneth D. Merry 
918991554f2SKenneth D. Merry 	if (sassc->flags & MPRSAS_IN_STARTUP)
919991554f2SKenneth D. Merry 		xpt_release_simq(sassc->sim, 1);
920991554f2SKenneth D. Merry 
921991554f2SKenneth D. Merry 	if (sassc->sim != NULL) {
922991554f2SKenneth D. Merry 		xpt_bus_deregister(cam_sim_path(sassc->sim));
923991554f2SKenneth D. Merry 		cam_sim_free(sassc->sim, FALSE);
924991554f2SKenneth D. Merry 	}
925991554f2SKenneth D. Merry 
926991554f2SKenneth D. Merry 	sassc->flags |= MPRSAS_SHUTDOWN;
927991554f2SKenneth D. Merry 	mpr_unlock(sc);
928991554f2SKenneth D. Merry 
929991554f2SKenneth D. Merry 	if (sassc->devq != NULL)
930991554f2SKenneth D. Merry 		cam_simq_free(sassc->devq);
931991554f2SKenneth D. Merry 
932991554f2SKenneth D. Merry 	for (i = 0; i < sassc->maxtargets; i++) {
933991554f2SKenneth D. Merry 		targ = &sassc->targets[i];
934991554f2SKenneth D. Merry 		SLIST_FOREACH_SAFE(lun, &targ->luns, lun_link, lun_tmp) {
935991554f2SKenneth D. Merry 			free(lun, M_MPR);
936991554f2SKenneth D. Merry 		}
937991554f2SKenneth D. Merry 	}
938991554f2SKenneth D. Merry 	free(sassc->targets, M_MPR);
939991554f2SKenneth D. Merry 	free(sassc, M_MPR);
940991554f2SKenneth D. Merry 	sc->sassc = NULL;
941991554f2SKenneth D. Merry 
942991554f2SKenneth D. Merry 	return (0);
943991554f2SKenneth D. Merry }
944991554f2SKenneth D. Merry 
945991554f2SKenneth D. Merry void
946991554f2SKenneth D. Merry mprsas_discovery_end(struct mprsas_softc *sassc)
947991554f2SKenneth D. Merry {
948991554f2SKenneth D. Merry 	struct mpr_softc *sc = sassc->sc;
949991554f2SKenneth D. Merry 
950991554f2SKenneth D. Merry 	MPR_FUNCTRACE(sc);
951991554f2SKenneth D. Merry 
952991554f2SKenneth D. Merry 	if (sassc->flags & MPRSAS_DISCOVERY_TIMEOUT_PENDING)
953991554f2SKenneth D. Merry 		callout_stop(&sassc->discovery_callout);
954991554f2SKenneth D. Merry 
955991554f2SKenneth D. Merry }
956991554f2SKenneth D. Merry 
957991554f2SKenneth D. Merry static void
958991554f2SKenneth D. Merry mprsas_action(struct cam_sim *sim, union ccb *ccb)
959991554f2SKenneth D. Merry {
960991554f2SKenneth D. Merry 	struct mprsas_softc *sassc;
961991554f2SKenneth D. Merry 
962991554f2SKenneth D. Merry 	sassc = cam_sim_softc(sim);
963991554f2SKenneth D. Merry 
964991554f2SKenneth D. Merry 	MPR_FUNCTRACE(sassc->sc);
965991554f2SKenneth D. Merry 	mpr_dprint(sassc->sc, MPR_TRACE, "%s func 0x%x\n", __func__,
966991554f2SKenneth D. Merry 	    ccb->ccb_h.func_code);
967991554f2SKenneth D. Merry 	mtx_assert(&sassc->sc->mpr_mtx, MA_OWNED);
968991554f2SKenneth D. Merry 
969991554f2SKenneth D. Merry 	switch (ccb->ccb_h.func_code) {
970991554f2SKenneth D. Merry 	case XPT_PATH_INQ:
971991554f2SKenneth D. Merry 	{
972991554f2SKenneth D. Merry 		struct ccb_pathinq *cpi = &ccb->cpi;
973991554f2SKenneth D. Merry 
974991554f2SKenneth D. Merry 		cpi->version_num = 1;
975991554f2SKenneth D. Merry 		cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE|PI_WIDE_16;
976991554f2SKenneth D. Merry 		cpi->target_sprt = 0;
977a371d6f9SKenneth D. Merry #if (__FreeBSD_version >= 1000039) || \
978a371d6f9SKenneth D. Merry     ((__FreeBSD_version < 1000000) && (__FreeBSD_version >= 902502))
979991554f2SKenneth D. Merry 		cpi->hba_misc = PIM_NOBUSRESET | PIM_UNMAPPED | PIM_NOSCAN;
980991554f2SKenneth D. Merry #else
981991554f2SKenneth D. Merry 		cpi->hba_misc = PIM_NOBUSRESET | PIM_UNMAPPED;
982991554f2SKenneth D. Merry #endif
983991554f2SKenneth D. Merry 		cpi->hba_eng_cnt = 0;
984991554f2SKenneth D. Merry 		cpi->max_target = sassc->maxtargets - 1;
985991554f2SKenneth D. Merry 		cpi->max_lun = 255;
986991554f2SKenneth D. Merry 		cpi->initiator_id = sassc->maxtargets - 1;
987991554f2SKenneth D. Merry 		strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
988991554f2SKenneth D. Merry 		strncpy(cpi->hba_vid, "LSILogic", HBA_IDLEN);
989991554f2SKenneth D. Merry 		strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
990991554f2SKenneth D. Merry 		cpi->unit_number = cam_sim_unit(sim);
991991554f2SKenneth D. Merry 		cpi->bus_id = cam_sim_bus(sim);
992991554f2SKenneth D. Merry 		/*
993991554f2SKenneth D. Merry 		 * XXXSLM-I think this needs to change based on config page or
994991554f2SKenneth D. Merry 		 * something instead of hardcoded to 150000.
995991554f2SKenneth D. Merry 		 */
996991554f2SKenneth D. Merry 		cpi->base_transfer_speed = 150000;
997991554f2SKenneth D. Merry 		cpi->transport = XPORT_SAS;
998991554f2SKenneth D. Merry 		cpi->transport_version = 0;
999991554f2SKenneth D. Merry 		cpi->protocol = PROTO_SCSI;
1000991554f2SKenneth D. Merry 		cpi->protocol_version = SCSI_REV_SPC;
1001991554f2SKenneth D. Merry #if __FreeBSD_version >= 800001
1002991554f2SKenneth D. Merry 		/*
1003991554f2SKenneth D. Merry 		 * XXXSLM-probably need to base this number on max SGL's and
1004991554f2SKenneth D. Merry 		 * page size.
1005991554f2SKenneth D. Merry 		 */
1006991554f2SKenneth D. Merry 		cpi->maxio = 256 * 1024;
1007991554f2SKenneth D. Merry #endif
1008991554f2SKenneth D. Merry 		cpi->ccb_h.status = CAM_REQ_CMP;
1009991554f2SKenneth D. Merry 		break;
1010991554f2SKenneth D. Merry 	}
1011991554f2SKenneth D. Merry 	case XPT_GET_TRAN_SETTINGS:
1012991554f2SKenneth D. Merry 	{
1013991554f2SKenneth D. Merry 		struct ccb_trans_settings	*cts;
1014991554f2SKenneth D. Merry 		struct ccb_trans_settings_sas	*sas;
1015991554f2SKenneth D. Merry 		struct ccb_trans_settings_scsi	*scsi;
1016991554f2SKenneth D. Merry 		struct mprsas_target *targ;
1017991554f2SKenneth D. Merry 
1018991554f2SKenneth D. Merry 		cts = &ccb->cts;
1019991554f2SKenneth D. Merry 		sas = &cts->xport_specific.sas;
1020991554f2SKenneth D. Merry 		scsi = &cts->proto_specific.scsi;
1021991554f2SKenneth D. Merry 
1022991554f2SKenneth D. Merry 		KASSERT(cts->ccb_h.target_id < sassc->maxtargets,
1023991554f2SKenneth D. Merry 		    ("Target %d out of bounds in XPT_GET_TRAN_SETTINGS\n",
1024991554f2SKenneth D. Merry 		    cts->ccb_h.target_id));
1025991554f2SKenneth D. Merry 		targ = &sassc->targets[cts->ccb_h.target_id];
1026991554f2SKenneth D. Merry 		if (targ->handle == 0x0) {
1027991554f2SKenneth D. Merry 			cts->ccb_h.status = CAM_DEV_NOT_THERE;
1028991554f2SKenneth D. Merry 			break;
1029991554f2SKenneth D. Merry 		}
1030991554f2SKenneth D. Merry 
1031991554f2SKenneth D. Merry 		cts->protocol_version = SCSI_REV_SPC2;
1032991554f2SKenneth D. Merry 		cts->transport = XPORT_SAS;
1033991554f2SKenneth D. Merry 		cts->transport_version = 0;
1034991554f2SKenneth D. Merry 
1035991554f2SKenneth D. Merry 		sas->valid = CTS_SAS_VALID_SPEED;
1036991554f2SKenneth D. Merry 		switch (targ->linkrate) {
1037991554f2SKenneth D. Merry 		case 0x08:
1038991554f2SKenneth D. Merry 			sas->bitrate = 150000;
1039991554f2SKenneth D. Merry 			break;
1040991554f2SKenneth D. Merry 		case 0x09:
1041991554f2SKenneth D. Merry 			sas->bitrate = 300000;
1042991554f2SKenneth D. Merry 			break;
1043991554f2SKenneth D. Merry 		case 0x0a:
1044991554f2SKenneth D. Merry 			sas->bitrate = 600000;
1045991554f2SKenneth D. Merry 			break;
104682315915SAlexander Motin 		case 0x0b:
104782315915SAlexander Motin 			sas->bitrate = 1200000;
104882315915SAlexander Motin 			break;
1049991554f2SKenneth D. Merry 		default:
1050991554f2SKenneth D. Merry 			sas->valid = 0;
1051991554f2SKenneth D. Merry 		}
1052991554f2SKenneth D. Merry 
1053991554f2SKenneth D. Merry 		cts->protocol = PROTO_SCSI;
1054991554f2SKenneth D. Merry 		scsi->valid = CTS_SCSI_VALID_TQ;
1055991554f2SKenneth D. Merry 		scsi->flags = CTS_SCSI_FLAGS_TAG_ENB;
1056991554f2SKenneth D. Merry 
1057991554f2SKenneth D. Merry 		cts->ccb_h.status = CAM_REQ_CMP;
1058991554f2SKenneth D. Merry 		break;
1059991554f2SKenneth D. Merry 	}
1060991554f2SKenneth D. Merry 	case XPT_CALC_GEOMETRY:
1061991554f2SKenneth D. Merry 		cam_calc_geometry(&ccb->ccg, /*extended*/1);
1062991554f2SKenneth D. Merry 		ccb->ccb_h.status = CAM_REQ_CMP;
1063991554f2SKenneth D. Merry 		break;
1064991554f2SKenneth D. Merry 	case XPT_RESET_DEV:
1065991554f2SKenneth D. Merry 		mpr_dprint(sassc->sc, MPR_XINFO,
1066991554f2SKenneth D. Merry 		    "mprsas_action XPT_RESET_DEV\n");
1067991554f2SKenneth D. Merry 		mprsas_action_resetdev(sassc, ccb);
1068991554f2SKenneth D. Merry 		return;
1069991554f2SKenneth D. Merry 	case XPT_RESET_BUS:
1070991554f2SKenneth D. Merry 	case XPT_ABORT:
1071991554f2SKenneth D. Merry 	case XPT_TERM_IO:
1072991554f2SKenneth D. Merry 		mpr_dprint(sassc->sc, MPR_XINFO,
1073991554f2SKenneth D. Merry 		    "mprsas_action faking success for abort or reset\n");
1074991554f2SKenneth D. Merry 		ccb->ccb_h.status = CAM_REQ_CMP;
1075991554f2SKenneth D. Merry 		break;
1076991554f2SKenneth D. Merry 	case XPT_SCSI_IO:
1077991554f2SKenneth D. Merry 		mprsas_action_scsiio(sassc, ccb);
1078991554f2SKenneth D. Merry 		return;
1079991554f2SKenneth D. Merry #if __FreeBSD_version >= 900026
1080991554f2SKenneth D. Merry 	case XPT_SMP_IO:
1081991554f2SKenneth D. Merry 		mprsas_action_smpio(sassc, ccb);
1082991554f2SKenneth D. Merry 		return;
1083991554f2SKenneth D. Merry #endif
1084991554f2SKenneth D. Merry 	default:
1085991554f2SKenneth D. Merry 		ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
1086991554f2SKenneth D. Merry 		break;
1087991554f2SKenneth D. Merry 	}
1088991554f2SKenneth D. Merry 	xpt_done(ccb);
1089991554f2SKenneth D. Merry 
1090991554f2SKenneth D. Merry }
1091991554f2SKenneth D. Merry 
1092991554f2SKenneth D. Merry static void
1093991554f2SKenneth D. Merry mprsas_announce_reset(struct mpr_softc *sc, uint32_t ac_code,
1094991554f2SKenneth D. Merry     target_id_t target_id, lun_id_t lun_id)
1095991554f2SKenneth D. Merry {
1096991554f2SKenneth D. Merry 	path_id_t path_id = cam_sim_path(sc->sassc->sim);
1097991554f2SKenneth D. Merry 	struct cam_path *path;
1098991554f2SKenneth D. Merry 
1099991554f2SKenneth D. Merry 	mpr_dprint(sc, MPR_XINFO, "%s code %x target %d lun %jx\n", __func__,
1100991554f2SKenneth D. Merry 	    ac_code, target_id, (uintmax_t)lun_id);
1101991554f2SKenneth D. Merry 
1102991554f2SKenneth D. Merry 	if (xpt_create_path(&path, NULL,
1103991554f2SKenneth D. Merry 		path_id, target_id, lun_id) != CAM_REQ_CMP) {
1104991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_ERROR, "unable to create path for reset "
1105991554f2SKenneth D. Merry 			   "notification\n");
1106991554f2SKenneth D. Merry 		return;
1107991554f2SKenneth D. Merry 	}
1108991554f2SKenneth D. Merry 
1109991554f2SKenneth D. Merry 	xpt_async(ac_code, path, NULL);
1110991554f2SKenneth D. Merry 	xpt_free_path(path);
1111991554f2SKenneth D. Merry }
1112991554f2SKenneth D. Merry 
1113991554f2SKenneth D. Merry static void
1114991554f2SKenneth D. Merry mprsas_complete_all_commands(struct mpr_softc *sc)
1115991554f2SKenneth D. Merry {
1116991554f2SKenneth D. Merry 	struct mpr_command *cm;
1117991554f2SKenneth D. Merry 	int i;
1118991554f2SKenneth D. Merry 	int completed;
1119991554f2SKenneth D. Merry 
1120991554f2SKenneth D. Merry 	MPR_FUNCTRACE(sc);
1121991554f2SKenneth D. Merry 	mtx_assert(&sc->mpr_mtx, MA_OWNED);
1122991554f2SKenneth D. Merry 
1123991554f2SKenneth D. Merry 	/* complete all commands with a NULL reply */
1124991554f2SKenneth D. Merry 	for (i = 1; i < sc->num_reqs; i++) {
1125991554f2SKenneth D. Merry 		cm = &sc->commands[i];
1126991554f2SKenneth D. Merry 		cm->cm_reply = NULL;
1127991554f2SKenneth D. Merry 		completed = 0;
1128991554f2SKenneth D. Merry 
1129991554f2SKenneth D. Merry 		if (cm->cm_flags & MPR_CM_FLAGS_POLLED)
1130991554f2SKenneth D. Merry 			cm->cm_flags |= MPR_CM_FLAGS_COMPLETE;
1131991554f2SKenneth D. Merry 
1132991554f2SKenneth D. Merry 		if (cm->cm_complete != NULL) {
1133991554f2SKenneth D. Merry 			mprsas_log_command(cm, MPR_RECOVERY,
1134991554f2SKenneth D. Merry 			    "completing cm %p state %x ccb %p for diag reset\n",
1135991554f2SKenneth D. Merry 			    cm, cm->cm_state, cm->cm_ccb);
1136991554f2SKenneth D. Merry 			cm->cm_complete(sc, cm);
1137991554f2SKenneth D. Merry 			completed = 1;
1138991554f2SKenneth D. Merry 		}
1139991554f2SKenneth D. Merry 
1140991554f2SKenneth D. Merry 		if (cm->cm_flags & MPR_CM_FLAGS_WAKEUP) {
1141991554f2SKenneth D. Merry 			mprsas_log_command(cm, MPR_RECOVERY,
1142991554f2SKenneth D. Merry 			    "waking up cm %p state %x ccb %p for diag reset\n",
1143991554f2SKenneth D. Merry 			    cm, cm->cm_state, cm->cm_ccb);
1144991554f2SKenneth D. Merry 			wakeup(cm);
1145991554f2SKenneth D. Merry 			completed = 1;
1146991554f2SKenneth D. Merry 		}
1147991554f2SKenneth D. Merry 
1148991554f2SKenneth D. Merry 		if ((completed == 0) && (cm->cm_state != MPR_CM_STATE_FREE)) {
1149991554f2SKenneth D. Merry 			/* this should never happen, but if it does, log */
1150991554f2SKenneth D. Merry 			mprsas_log_command(cm, MPR_RECOVERY,
1151991554f2SKenneth D. Merry 			    "cm %p state %x flags 0x%x ccb %p during diag "
1152991554f2SKenneth D. Merry 			    "reset\n", cm, cm->cm_state, cm->cm_flags,
1153991554f2SKenneth D. Merry 			    cm->cm_ccb);
1154991554f2SKenneth D. Merry 		}
1155991554f2SKenneth D. Merry 	}
1156991554f2SKenneth D. Merry }
1157991554f2SKenneth D. Merry 
1158991554f2SKenneth D. Merry void
1159991554f2SKenneth D. Merry mprsas_handle_reinit(struct mpr_softc *sc)
1160991554f2SKenneth D. Merry {
1161991554f2SKenneth D. Merry 	int i;
1162991554f2SKenneth D. Merry 
1163991554f2SKenneth D. Merry 	/* Go back into startup mode and freeze the simq, so that CAM
1164991554f2SKenneth D. Merry 	 * doesn't send any commands until after we've rediscovered all
1165991554f2SKenneth D. Merry 	 * targets and found the proper device handles for them.
1166991554f2SKenneth D. Merry 	 *
1167991554f2SKenneth D. Merry 	 * After the reset, portenable will trigger discovery, and after all
1168991554f2SKenneth D. Merry 	 * discovery-related activities have finished, the simq will be
1169991554f2SKenneth D. Merry 	 * released.
1170991554f2SKenneth D. Merry 	 */
1171991554f2SKenneth D. Merry 	mpr_dprint(sc, MPR_INIT, "%s startup\n", __func__);
1172991554f2SKenneth D. Merry 	sc->sassc->flags |= MPRSAS_IN_STARTUP;
1173991554f2SKenneth D. Merry 	sc->sassc->flags |= MPRSAS_IN_DISCOVERY;
1174991554f2SKenneth D. Merry 	mprsas_startup_increment(sc->sassc);
1175991554f2SKenneth D. Merry 
1176991554f2SKenneth D. Merry 	/* notify CAM of a bus reset */
1177991554f2SKenneth D. Merry 	mprsas_announce_reset(sc, AC_BUS_RESET, CAM_TARGET_WILDCARD,
1178991554f2SKenneth D. Merry 	    CAM_LUN_WILDCARD);
1179991554f2SKenneth D. Merry 
1180991554f2SKenneth D. Merry 	/* complete and cleanup after all outstanding commands */
1181991554f2SKenneth D. Merry 	mprsas_complete_all_commands(sc);
1182991554f2SKenneth D. Merry 
1183991554f2SKenneth D. Merry 	mpr_dprint(sc, MPR_INIT, "%s startup %u tm %u after command "
1184991554f2SKenneth D. Merry 	    "completion\n", __func__, sc->sassc->startup_refcount,
1185991554f2SKenneth D. Merry 	    sc->sassc->tm_count);
1186991554f2SKenneth D. Merry 
1187991554f2SKenneth D. Merry 	/* zero all the target handles, since they may change after the
1188991554f2SKenneth D. Merry 	 * reset, and we have to rediscover all the targets and use the new
1189991554f2SKenneth D. Merry 	 * handles.
1190991554f2SKenneth D. Merry 	 */
1191991554f2SKenneth D. Merry 	for (i = 0; i < sc->sassc->maxtargets; i++) {
1192991554f2SKenneth D. Merry 		if (sc->sassc->targets[i].outstanding != 0)
1193991554f2SKenneth D. Merry 			mpr_dprint(sc, MPR_INIT, "target %u outstanding %u\n",
1194991554f2SKenneth D. Merry 			    i, sc->sassc->targets[i].outstanding);
1195991554f2SKenneth D. Merry 		sc->sassc->targets[i].handle = 0x0;
1196991554f2SKenneth D. Merry 		sc->sassc->targets[i].exp_dev_handle = 0x0;
1197991554f2SKenneth D. Merry 		sc->sassc->targets[i].outstanding = 0;
1198991554f2SKenneth D. Merry 		sc->sassc->targets[i].flags = MPRSAS_TARGET_INDIAGRESET;
1199991554f2SKenneth D. Merry 	}
1200991554f2SKenneth D. Merry }
1201991554f2SKenneth D. Merry static void
1202991554f2SKenneth D. Merry mprsas_tm_timeout(void *data)
1203991554f2SKenneth D. Merry {
1204991554f2SKenneth D. Merry 	struct mpr_command *tm = data;
1205991554f2SKenneth D. Merry 	struct mpr_softc *sc = tm->cm_sc;
1206991554f2SKenneth D. Merry 
1207991554f2SKenneth D. Merry 	mtx_assert(&sc->mpr_mtx, MA_OWNED);
1208991554f2SKenneth D. Merry 
1209991554f2SKenneth D. Merry 	mprsas_log_command(tm, MPR_INFO|MPR_RECOVERY,
1210991554f2SKenneth D. Merry 	    "task mgmt %p timed out\n", tm);
1211991554f2SKenneth D. Merry 	mpr_reinit(sc);
1212991554f2SKenneth D. Merry }
1213991554f2SKenneth D. Merry 
1214991554f2SKenneth D. Merry static void
1215991554f2SKenneth D. Merry mprsas_logical_unit_reset_complete(struct mpr_softc *sc,
1216991554f2SKenneth D. Merry     struct mpr_command *tm)
1217991554f2SKenneth D. Merry {
1218991554f2SKenneth D. Merry 	MPI2_SCSI_TASK_MANAGE_REPLY *reply;
1219991554f2SKenneth D. Merry 	MPI2_SCSI_TASK_MANAGE_REQUEST *req;
1220991554f2SKenneth D. Merry 	unsigned int cm_count = 0;
1221991554f2SKenneth D. Merry 	struct mpr_command *cm;
1222991554f2SKenneth D. Merry 	struct mprsas_target *targ;
1223991554f2SKenneth D. Merry 
1224991554f2SKenneth D. Merry 	callout_stop(&tm->cm_callout);
1225991554f2SKenneth D. Merry 
1226991554f2SKenneth D. Merry 	req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req;
1227991554f2SKenneth D. Merry 	reply = (MPI2_SCSI_TASK_MANAGE_REPLY *)tm->cm_reply;
1228991554f2SKenneth D. Merry 	targ = tm->cm_targ;
1229991554f2SKenneth D. Merry 
1230991554f2SKenneth D. Merry 	/*
1231991554f2SKenneth D. Merry 	 * Currently there should be no way we can hit this case.  It only
1232991554f2SKenneth D. Merry 	 * happens when we have a failure to allocate chain frames, and
1233991554f2SKenneth D. Merry 	 * task management commands don't have S/G lists.
1234991554f2SKenneth D. Merry 	 */
1235991554f2SKenneth D. Merry 	if ((tm->cm_flags & MPR_CM_FLAGS_ERROR_MASK) != 0) {
1236991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_ERROR, "%s: cm_flags = %#x for LUN reset! "
1237991554f2SKenneth D. Merry 		    "This should not happen!\n", __func__, tm->cm_flags);
1238991554f2SKenneth D. Merry 		mprsas_free_tm(sc, tm);
1239991554f2SKenneth D. Merry 		return;
1240991554f2SKenneth D. Merry 	}
1241991554f2SKenneth D. Merry 
1242991554f2SKenneth D. Merry 	if (reply == NULL) {
1243991554f2SKenneth D. Merry 		mprsas_log_command(tm, MPR_RECOVERY,
1244991554f2SKenneth D. Merry 		    "NULL reset reply for tm %p\n", tm);
1245991554f2SKenneth D. Merry 		if ((sc->mpr_flags & MPR_FLAGS_DIAGRESET) != 0) {
1246991554f2SKenneth D. Merry 			/* this completion was due to a reset, just cleanup */
1247991554f2SKenneth D. Merry 			targ->flags &= ~MPRSAS_TARGET_INRESET;
1248991554f2SKenneth D. Merry 			targ->tm = NULL;
1249991554f2SKenneth D. Merry 			mprsas_free_tm(sc, tm);
1250991554f2SKenneth D. Merry 		}
1251991554f2SKenneth D. Merry 		else {
1252991554f2SKenneth D. Merry 			/* we should have gotten a reply. */
1253991554f2SKenneth D. Merry 			mpr_reinit(sc);
1254991554f2SKenneth D. Merry 		}
1255991554f2SKenneth D. Merry 		return;
1256991554f2SKenneth D. Merry 	}
1257991554f2SKenneth D. Merry 
1258991554f2SKenneth D. Merry 	mprsas_log_command(tm, MPR_RECOVERY,
1259991554f2SKenneth D. Merry 	    "logical unit reset status 0x%x code 0x%x count %u\n",
1260991554f2SKenneth D. Merry 	    le16toh(reply->IOCStatus), le32toh(reply->ResponseCode),
1261991554f2SKenneth D. Merry 	    le32toh(reply->TerminationCount));
1262991554f2SKenneth D. Merry 
1263991554f2SKenneth D. Merry 	/* See if there are any outstanding commands for this LUN.
1264991554f2SKenneth D. Merry 	 * This could be made more efficient by using a per-LU data
1265991554f2SKenneth D. Merry 	 * structure of some sort.
1266991554f2SKenneth D. Merry 	 */
1267991554f2SKenneth D. Merry 	TAILQ_FOREACH(cm, &targ->commands, cm_link) {
1268991554f2SKenneth D. Merry 		if (cm->cm_lun == tm->cm_lun)
1269991554f2SKenneth D. Merry 			cm_count++;
1270991554f2SKenneth D. Merry 	}
1271991554f2SKenneth D. Merry 
1272991554f2SKenneth D. Merry 	if (cm_count == 0) {
1273991554f2SKenneth D. Merry 		mprsas_log_command(tm, MPR_RECOVERY|MPR_INFO,
1274991554f2SKenneth D. Merry 		    "logical unit %u finished recovery after reset\n",
1275991554f2SKenneth D. Merry 		    tm->cm_lun, tm);
1276991554f2SKenneth D. Merry 
1277991554f2SKenneth D. Merry 		mprsas_announce_reset(sc, AC_SENT_BDR, tm->cm_targ->tid,
1278991554f2SKenneth D. Merry 		    tm->cm_lun);
1279991554f2SKenneth D. Merry 
1280991554f2SKenneth D. Merry 		/* we've finished recovery for this logical unit.  check and
1281991554f2SKenneth D. Merry 		 * see if some other logical unit has a timedout command
1282991554f2SKenneth D. Merry 		 * that needs to be processed.
1283991554f2SKenneth D. Merry 		 */
1284991554f2SKenneth D. Merry 		cm = TAILQ_FIRST(&targ->timedout_commands);
1285991554f2SKenneth D. Merry 		if (cm) {
1286991554f2SKenneth D. Merry 			mprsas_send_abort(sc, tm, cm);
1287991554f2SKenneth D. Merry 		}
1288991554f2SKenneth D. Merry 		else {
1289991554f2SKenneth D. Merry 			targ->tm = NULL;
1290991554f2SKenneth D. Merry 			mprsas_free_tm(sc, tm);
1291991554f2SKenneth D. Merry 		}
1292991554f2SKenneth D. Merry 	}
1293991554f2SKenneth D. Merry 	else {
1294991554f2SKenneth D. Merry 		/* if we still have commands for this LUN, the reset
1295991554f2SKenneth D. Merry 		 * effectively failed, regardless of the status reported.
1296991554f2SKenneth D. Merry 		 * Escalate to a target reset.
1297991554f2SKenneth D. Merry 		 */
1298991554f2SKenneth D. Merry 		mprsas_log_command(tm, MPR_RECOVERY,
1299991554f2SKenneth D. Merry 		    "logical unit reset complete for tm %p, but still have %u "
1300991554f2SKenneth D. Merry 		    "command(s)\n", tm, cm_count);
1301991554f2SKenneth D. Merry 		mprsas_send_reset(sc, tm,
1302991554f2SKenneth D. Merry 		    MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET);
1303991554f2SKenneth D. Merry 	}
1304991554f2SKenneth D. Merry }
1305991554f2SKenneth D. Merry 
1306991554f2SKenneth D. Merry static void
1307991554f2SKenneth D. Merry mprsas_target_reset_complete(struct mpr_softc *sc, struct mpr_command *tm)
1308991554f2SKenneth D. Merry {
1309991554f2SKenneth D. Merry 	MPI2_SCSI_TASK_MANAGE_REPLY *reply;
1310991554f2SKenneth D. Merry 	MPI2_SCSI_TASK_MANAGE_REQUEST *req;
1311991554f2SKenneth D. Merry 	struct mprsas_target *targ;
1312991554f2SKenneth D. Merry 
1313991554f2SKenneth D. Merry 	callout_stop(&tm->cm_callout);
1314991554f2SKenneth D. Merry 
1315991554f2SKenneth D. Merry 	req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req;
1316991554f2SKenneth D. Merry 	reply = (MPI2_SCSI_TASK_MANAGE_REPLY *)tm->cm_reply;
1317991554f2SKenneth D. Merry 	targ = tm->cm_targ;
1318991554f2SKenneth D. Merry 
1319991554f2SKenneth D. Merry 	/*
1320991554f2SKenneth D. Merry 	 * Currently there should be no way we can hit this case.  It only
1321991554f2SKenneth D. Merry 	 * happens when we have a failure to allocate chain frames, and
1322991554f2SKenneth D. Merry 	 * task management commands don't have S/G lists.
1323991554f2SKenneth D. Merry 	 */
1324991554f2SKenneth D. Merry 	if ((tm->cm_flags & MPR_CM_FLAGS_ERROR_MASK) != 0) {
1325991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_ERROR,"%s: cm_flags = %#x for target reset! "
1326991554f2SKenneth D. Merry 		    "This should not happen!\n", __func__, tm->cm_flags);
1327991554f2SKenneth D. Merry 		mprsas_free_tm(sc, tm);
1328991554f2SKenneth D. Merry 		return;
1329991554f2SKenneth D. Merry 	}
1330991554f2SKenneth D. Merry 
1331991554f2SKenneth D. Merry 	if (reply == NULL) {
1332991554f2SKenneth D. Merry 		mprsas_log_command(tm, MPR_RECOVERY,
1333991554f2SKenneth D. Merry 		    "NULL reset reply for tm %p\n", tm);
1334991554f2SKenneth D. Merry 		if ((sc->mpr_flags & MPR_FLAGS_DIAGRESET) != 0) {
1335991554f2SKenneth D. Merry 			/* this completion was due to a reset, just cleanup */
1336991554f2SKenneth D. Merry 			targ->flags &= ~MPRSAS_TARGET_INRESET;
1337991554f2SKenneth D. Merry 			targ->tm = NULL;
1338991554f2SKenneth D. Merry 			mprsas_free_tm(sc, tm);
1339991554f2SKenneth D. Merry 		}
1340991554f2SKenneth D. Merry 		else {
1341991554f2SKenneth D. Merry 			/* we should have gotten a reply. */
1342991554f2SKenneth D. Merry 			mpr_reinit(sc);
1343991554f2SKenneth D. Merry 		}
1344991554f2SKenneth D. Merry 		return;
1345991554f2SKenneth D. Merry 	}
1346991554f2SKenneth D. Merry 
1347991554f2SKenneth D. Merry 	mprsas_log_command(tm, MPR_RECOVERY,
1348991554f2SKenneth D. Merry 	    "target reset status 0x%x code 0x%x count %u\n",
1349991554f2SKenneth D. Merry 	    le16toh(reply->IOCStatus), le32toh(reply->ResponseCode),
1350991554f2SKenneth D. Merry 	    le32toh(reply->TerminationCount));
1351991554f2SKenneth D. Merry 
1352991554f2SKenneth D. Merry 	targ->flags &= ~MPRSAS_TARGET_INRESET;
1353991554f2SKenneth D. Merry 
1354991554f2SKenneth D. Merry 	if (targ->outstanding == 0) {
1355991554f2SKenneth D. Merry 		/* we've finished recovery for this target and all
1356991554f2SKenneth D. Merry 		 * of its logical units.
1357991554f2SKenneth D. Merry 		 */
1358991554f2SKenneth D. Merry 		mprsas_log_command(tm, MPR_RECOVERY|MPR_INFO,
1359991554f2SKenneth D. Merry 		    "recovery finished after target reset\n");
1360991554f2SKenneth D. Merry 
1361991554f2SKenneth D. Merry 		mprsas_announce_reset(sc, AC_SENT_BDR, tm->cm_targ->tid,
1362991554f2SKenneth D. Merry 		    CAM_LUN_WILDCARD);
1363991554f2SKenneth D. Merry 
1364991554f2SKenneth D. Merry 		targ->tm = NULL;
1365991554f2SKenneth D. Merry 		mprsas_free_tm(sc, tm);
1366991554f2SKenneth D. Merry 	}
1367991554f2SKenneth D. Merry 	else {
1368991554f2SKenneth D. Merry 		/* after a target reset, if this target still has
1369991554f2SKenneth D. Merry 		 * outstanding commands, the reset effectively failed,
1370991554f2SKenneth D. Merry 		 * regardless of the status reported.  escalate.
1371991554f2SKenneth D. Merry 		 */
1372991554f2SKenneth D. Merry 		mprsas_log_command(tm, MPR_RECOVERY,
1373991554f2SKenneth D. Merry 		    "target reset complete for tm %p, but still have %u "
1374991554f2SKenneth D. Merry 		    "command(s)\n", tm, targ->outstanding);
1375991554f2SKenneth D. Merry 		mpr_reinit(sc);
1376991554f2SKenneth D. Merry 	}
1377991554f2SKenneth D. Merry }
1378991554f2SKenneth D. Merry 
1379991554f2SKenneth D. Merry #define MPR_RESET_TIMEOUT 30
1380991554f2SKenneth D. Merry 
1381991554f2SKenneth D. Merry static int
1382991554f2SKenneth D. Merry mprsas_send_reset(struct mpr_softc *sc, struct mpr_command *tm, uint8_t type)
1383991554f2SKenneth D. Merry {
1384991554f2SKenneth D. Merry 	MPI2_SCSI_TASK_MANAGE_REQUEST *req;
1385991554f2SKenneth D. Merry 	struct mprsas_target *target;
1386991554f2SKenneth D. Merry 	int err;
1387991554f2SKenneth D. Merry 
1388991554f2SKenneth D. Merry 	target = tm->cm_targ;
1389991554f2SKenneth D. Merry 	if (target->handle == 0) {
1390991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_ERROR,"%s null devhandle for target_id %d\n",
1391991554f2SKenneth D. Merry 		    __func__, target->tid);
1392991554f2SKenneth D. Merry 		return -1;
1393991554f2SKenneth D. Merry 	}
1394991554f2SKenneth D. Merry 
1395991554f2SKenneth D. Merry 	req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req;
1396991554f2SKenneth D. Merry 	req->DevHandle = htole16(target->handle);
1397991554f2SKenneth D. Merry 	req->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
1398991554f2SKenneth D. Merry 	req->TaskType = type;
1399991554f2SKenneth D. Merry 
1400991554f2SKenneth D. Merry 	if (type == MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET) {
1401991554f2SKenneth D. Merry 		/* XXX Need to handle invalid LUNs */
1402991554f2SKenneth D. Merry 		MPR_SET_LUN(req->LUN, tm->cm_lun);
1403991554f2SKenneth D. Merry 		tm->cm_targ->logical_unit_resets++;
1404991554f2SKenneth D. Merry 		mprsas_log_command(tm, MPR_RECOVERY|MPR_INFO,
1405991554f2SKenneth D. Merry 		    "sending logical unit reset\n");
1406991554f2SKenneth D. Merry 		tm->cm_complete = mprsas_logical_unit_reset_complete;
1407991554f2SKenneth D. Merry 	}
1408991554f2SKenneth D. Merry 	else if (type == MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET) {
1409991554f2SKenneth D. Merry 		/*
1410991554f2SKenneth D. Merry 		 * Target reset method =
1411991554f2SKenneth D. Merry 		 *     SAS Hard Link Reset / SATA Link Reset
1412991554f2SKenneth D. Merry 		 */
1413991554f2SKenneth D. Merry 		req->MsgFlags = MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET;
1414991554f2SKenneth D. Merry 		tm->cm_targ->target_resets++;
1415991554f2SKenneth D. Merry 		tm->cm_targ->flags |= MPRSAS_TARGET_INRESET;
1416991554f2SKenneth D. Merry 		mprsas_log_command(tm, MPR_RECOVERY|MPR_INFO,
1417991554f2SKenneth D. Merry 		    "sending target reset\n");
1418991554f2SKenneth D. Merry 		tm->cm_complete = mprsas_target_reset_complete;
1419991554f2SKenneth D. Merry 	}
1420991554f2SKenneth D. Merry 	else {
1421991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_ERROR, "unexpected reset type 0x%x\n", type);
1422991554f2SKenneth D. Merry 		return -1;
1423991554f2SKenneth D. Merry 	}
1424991554f2SKenneth D. Merry 
1425991554f2SKenneth D. Merry 	mpr_dprint(sc, MPR_XINFO, "to target %u handle 0x%04x\n", target->tid,
1426991554f2SKenneth D. Merry 	    target->handle);
1427991554f2SKenneth D. Merry 	if (target->encl_level_valid) {
1428991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_XINFO, "At enclosure level %d, slot %d, "
1429991554f2SKenneth D. Merry 		    "connector name (%4s)\n", target->encl_level,
1430991554f2SKenneth D. Merry 		    target->encl_slot, target->connector_name);
1431991554f2SKenneth D. Merry 	}
1432991554f2SKenneth D. Merry 
1433991554f2SKenneth D. Merry 	tm->cm_data = NULL;
1434991554f2SKenneth D. Merry 	tm->cm_desc.HighPriority.RequestFlags =
1435991554f2SKenneth D. Merry 	    MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY;
1436991554f2SKenneth D. Merry 	tm->cm_complete_data = (void *)tm;
1437991554f2SKenneth D. Merry 
1438991554f2SKenneth D. Merry 	callout_reset(&tm->cm_callout, MPR_RESET_TIMEOUT * hz,
1439991554f2SKenneth D. Merry 	    mprsas_tm_timeout, tm);
1440991554f2SKenneth D. Merry 
1441991554f2SKenneth D. Merry 	err = mpr_map_command(sc, tm);
1442991554f2SKenneth D. Merry 	if (err)
1443991554f2SKenneth D. Merry 		mprsas_log_command(tm, MPR_RECOVERY,
1444991554f2SKenneth D. Merry 		    "error %d sending reset type %u\n",
1445991554f2SKenneth D. Merry 		    err, type);
1446991554f2SKenneth D. Merry 
1447991554f2SKenneth D. Merry 	return err;
1448991554f2SKenneth D. Merry }
1449991554f2SKenneth D. Merry 
1450991554f2SKenneth D. Merry 
1451991554f2SKenneth D. Merry static void
1452991554f2SKenneth D. Merry mprsas_abort_complete(struct mpr_softc *sc, struct mpr_command *tm)
1453991554f2SKenneth D. Merry {
1454991554f2SKenneth D. Merry 	struct mpr_command *cm;
1455991554f2SKenneth D. Merry 	MPI2_SCSI_TASK_MANAGE_REPLY *reply;
1456991554f2SKenneth D. Merry 	MPI2_SCSI_TASK_MANAGE_REQUEST *req;
1457991554f2SKenneth D. Merry 	struct mprsas_target *targ;
1458991554f2SKenneth D. Merry 
1459991554f2SKenneth D. Merry 	callout_stop(&tm->cm_callout);
1460991554f2SKenneth D. Merry 
1461991554f2SKenneth D. Merry 	req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req;
1462991554f2SKenneth D. Merry 	reply = (MPI2_SCSI_TASK_MANAGE_REPLY *)tm->cm_reply;
1463991554f2SKenneth D. Merry 	targ = tm->cm_targ;
1464991554f2SKenneth D. Merry 
1465991554f2SKenneth D. Merry 	/*
1466991554f2SKenneth D. Merry 	 * Currently there should be no way we can hit this case.  It only
1467991554f2SKenneth D. Merry 	 * happens when we have a failure to allocate chain frames, and
1468991554f2SKenneth D. Merry 	 * task management commands don't have S/G lists.
1469991554f2SKenneth D. Merry 	 */
1470991554f2SKenneth D. Merry 	if ((tm->cm_flags & MPR_CM_FLAGS_ERROR_MASK) != 0) {
1471991554f2SKenneth D. Merry 		mprsas_log_command(tm, MPR_RECOVERY,
1472991554f2SKenneth D. Merry 		    "cm_flags = %#x for abort %p TaskMID %u!\n",
1473991554f2SKenneth D. Merry 		    tm->cm_flags, tm, le16toh(req->TaskMID));
1474991554f2SKenneth D. Merry 		mprsas_free_tm(sc, tm);
1475991554f2SKenneth D. Merry 		return;
1476991554f2SKenneth D. Merry 	}
1477991554f2SKenneth D. Merry 
1478991554f2SKenneth D. Merry 	if (reply == NULL) {
1479991554f2SKenneth D. Merry 		mprsas_log_command(tm, MPR_RECOVERY,
1480991554f2SKenneth D. Merry 		    "NULL abort reply for tm %p TaskMID %u\n",
1481991554f2SKenneth D. Merry 		    tm, le16toh(req->TaskMID));
1482991554f2SKenneth D. Merry 		if ((sc->mpr_flags & MPR_FLAGS_DIAGRESET) != 0) {
1483991554f2SKenneth D. Merry 			/* this completion was due to a reset, just cleanup */
1484991554f2SKenneth D. Merry 			targ->tm = NULL;
1485991554f2SKenneth D. Merry 			mprsas_free_tm(sc, tm);
1486991554f2SKenneth D. Merry 		}
1487991554f2SKenneth D. Merry 		else {
1488991554f2SKenneth D. Merry 			/* we should have gotten a reply. */
1489991554f2SKenneth D. Merry 			mpr_reinit(sc);
1490991554f2SKenneth D. Merry 		}
1491991554f2SKenneth D. Merry 		return;
1492991554f2SKenneth D. Merry 	}
1493991554f2SKenneth D. Merry 
1494991554f2SKenneth D. Merry 	mprsas_log_command(tm, MPR_RECOVERY,
1495991554f2SKenneth D. Merry 	    "abort TaskMID %u status 0x%x code 0x%x count %u\n",
1496991554f2SKenneth D. Merry 	    le16toh(req->TaskMID),
1497991554f2SKenneth D. Merry 	    le16toh(reply->IOCStatus), le32toh(reply->ResponseCode),
1498991554f2SKenneth D. Merry 	    le32toh(reply->TerminationCount));
1499991554f2SKenneth D. Merry 
1500991554f2SKenneth D. Merry 	cm = TAILQ_FIRST(&tm->cm_targ->timedout_commands);
1501991554f2SKenneth D. Merry 	if (cm == NULL) {
1502991554f2SKenneth D. Merry 		/* if there are no more timedout commands, we're done with
1503991554f2SKenneth D. Merry 		 * error recovery for this target.
1504991554f2SKenneth D. Merry 		 */
1505991554f2SKenneth D. Merry 		mprsas_log_command(tm, MPR_RECOVERY,
1506991554f2SKenneth D. Merry 		    "finished recovery after aborting TaskMID %u\n",
1507991554f2SKenneth D. Merry 		    le16toh(req->TaskMID));
1508991554f2SKenneth D. Merry 
1509991554f2SKenneth D. Merry 		targ->tm = NULL;
1510991554f2SKenneth D. Merry 		mprsas_free_tm(sc, tm);
1511991554f2SKenneth D. Merry 	}
1512991554f2SKenneth D. Merry 	else if (le16toh(req->TaskMID) != cm->cm_desc.Default.SMID) {
1513991554f2SKenneth D. Merry 		/* abort success, but we have more timedout commands to abort */
1514991554f2SKenneth D. Merry 		mprsas_log_command(tm, MPR_RECOVERY,
1515991554f2SKenneth D. Merry 		    "continuing recovery after aborting TaskMID %u\n",
1516991554f2SKenneth D. Merry 		    le16toh(req->TaskMID));
1517991554f2SKenneth D. Merry 
1518991554f2SKenneth D. Merry 		mprsas_send_abort(sc, tm, cm);
1519991554f2SKenneth D. Merry 	}
1520991554f2SKenneth D. Merry 	else {
1521991554f2SKenneth D. Merry 		/* we didn't get a command completion, so the abort
1522991554f2SKenneth D. Merry 		 * failed as far as we're concerned.  escalate.
1523991554f2SKenneth D. Merry 		 */
1524991554f2SKenneth D. Merry 		mprsas_log_command(tm, MPR_RECOVERY,
1525991554f2SKenneth D. Merry 		    "abort failed for TaskMID %u tm %p\n",
1526991554f2SKenneth D. Merry 		    le16toh(req->TaskMID), tm);
1527991554f2SKenneth D. Merry 
1528991554f2SKenneth D. Merry 		mprsas_send_reset(sc, tm,
1529991554f2SKenneth D. Merry 		    MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET);
1530991554f2SKenneth D. Merry 	}
1531991554f2SKenneth D. Merry }
1532991554f2SKenneth D. Merry 
1533991554f2SKenneth D. Merry #define MPR_ABORT_TIMEOUT 5
1534991554f2SKenneth D. Merry 
1535991554f2SKenneth D. Merry static int
1536991554f2SKenneth D. Merry mprsas_send_abort(struct mpr_softc *sc, struct mpr_command *tm,
1537991554f2SKenneth D. Merry     struct mpr_command *cm)
1538991554f2SKenneth D. Merry {
1539991554f2SKenneth D. Merry 	MPI2_SCSI_TASK_MANAGE_REQUEST *req;
1540991554f2SKenneth D. Merry 	struct mprsas_target *targ;
1541991554f2SKenneth D. Merry 	int err;
1542991554f2SKenneth D. Merry 
1543991554f2SKenneth D. Merry 	targ = cm->cm_targ;
1544991554f2SKenneth D. Merry 	if (targ->handle == 0) {
1545991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_ERROR,"%s null devhandle for target_id %d\n",
1546991554f2SKenneth D. Merry 		    __func__, cm->cm_ccb->ccb_h.target_id);
1547991554f2SKenneth D. Merry 		return -1;
1548991554f2SKenneth D. Merry 	}
1549991554f2SKenneth D. Merry 
1550991554f2SKenneth D. Merry 	mprsas_log_command(tm, MPR_RECOVERY|MPR_INFO,
1551991554f2SKenneth D. Merry 	    "Aborting command %p\n", cm);
1552991554f2SKenneth D. Merry 
1553991554f2SKenneth D. Merry 	req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req;
1554991554f2SKenneth D. Merry 	req->DevHandle = htole16(targ->handle);
1555991554f2SKenneth D. Merry 	req->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
1556991554f2SKenneth D. Merry 	req->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK;
1557991554f2SKenneth D. Merry 
1558991554f2SKenneth D. Merry 	/* XXX Need to handle invalid LUNs */
1559991554f2SKenneth D. Merry 	MPR_SET_LUN(req->LUN, cm->cm_ccb->ccb_h.target_lun);
1560991554f2SKenneth D. Merry 
1561991554f2SKenneth D. Merry 	req->TaskMID = htole16(cm->cm_desc.Default.SMID);
1562991554f2SKenneth D. Merry 
1563991554f2SKenneth D. Merry 	tm->cm_data = NULL;
1564991554f2SKenneth D. Merry 	tm->cm_desc.HighPriority.RequestFlags =
1565991554f2SKenneth D. Merry 	    MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY;
1566991554f2SKenneth D. Merry 	tm->cm_complete = mprsas_abort_complete;
1567991554f2SKenneth D. Merry 	tm->cm_complete_data = (void *)tm;
1568991554f2SKenneth D. Merry 	tm->cm_targ = cm->cm_targ;
1569991554f2SKenneth D. Merry 	tm->cm_lun = cm->cm_lun;
1570991554f2SKenneth D. Merry 
1571991554f2SKenneth D. Merry 	callout_reset(&tm->cm_callout, MPR_ABORT_TIMEOUT * hz,
1572991554f2SKenneth D. Merry 	    mprsas_tm_timeout, tm);
1573991554f2SKenneth D. Merry 
1574991554f2SKenneth D. Merry 	targ->aborts++;
1575991554f2SKenneth D. Merry 
1576991554f2SKenneth D. Merry 	err = mpr_map_command(sc, tm);
1577991554f2SKenneth D. Merry 	if (err)
1578991554f2SKenneth D. Merry 		mprsas_log_command(tm, MPR_RECOVERY,
1579991554f2SKenneth D. Merry 		    "error %d sending abort for cm %p SMID %u\n",
1580991554f2SKenneth D. Merry 		    err, cm, req->TaskMID);
1581991554f2SKenneth D. Merry 	return err;
1582991554f2SKenneth D. Merry }
1583991554f2SKenneth D. Merry 
1584991554f2SKenneth D. Merry 
1585991554f2SKenneth D. Merry static void
1586991554f2SKenneth D. Merry mprsas_scsiio_timeout(void *data)
1587991554f2SKenneth D. Merry {
1588991554f2SKenneth D. Merry 	struct mpr_softc *sc;
1589991554f2SKenneth D. Merry 	struct mpr_command *cm;
1590991554f2SKenneth D. Merry 	struct mprsas_target *targ;
1591991554f2SKenneth D. Merry 
1592991554f2SKenneth D. Merry 	cm = (struct mpr_command *)data;
1593991554f2SKenneth D. Merry 	sc = cm->cm_sc;
1594991554f2SKenneth D. Merry 
1595991554f2SKenneth D. Merry 	MPR_FUNCTRACE(sc);
1596991554f2SKenneth D. Merry 	mtx_assert(&sc->mpr_mtx, MA_OWNED);
1597991554f2SKenneth D. Merry 
1598991554f2SKenneth D. Merry 	mpr_dprint(sc, MPR_XINFO, "Timeout checking cm %p\n", cm);
1599991554f2SKenneth D. Merry 
1600991554f2SKenneth D. Merry 	/*
1601991554f2SKenneth D. Merry 	 * Run the interrupt handler to make sure it's not pending.  This
1602991554f2SKenneth D. Merry 	 * isn't perfect because the command could have already completed
1603991554f2SKenneth D. Merry 	 * and been re-used, though this is unlikely.
1604991554f2SKenneth D. Merry 	 */
1605991554f2SKenneth D. Merry 	mpr_intr_locked(sc);
1606991554f2SKenneth D. Merry 	if (cm->cm_state == MPR_CM_STATE_FREE) {
1607991554f2SKenneth D. Merry 		mprsas_log_command(cm, MPR_XINFO,
1608991554f2SKenneth D. Merry 		    "SCSI command %p almost timed out\n", cm);
1609991554f2SKenneth D. Merry 		return;
1610991554f2SKenneth D. Merry 	}
1611991554f2SKenneth D. Merry 
1612991554f2SKenneth D. Merry 	if (cm->cm_ccb == NULL) {
1613991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_ERROR, "command timeout with NULL ccb\n");
1614991554f2SKenneth D. Merry 		return;
1615991554f2SKenneth D. Merry 	}
1616991554f2SKenneth D. Merry 
1617991554f2SKenneth D. Merry 	targ = cm->cm_targ;
1618991554f2SKenneth D. Merry 	targ->timeouts++;
1619991554f2SKenneth D. Merry 
1620991554f2SKenneth D. Merry 	mprsas_log_command(cm, MPR_XINFO, "command timeout cm %p ccb %p "
1621991554f2SKenneth D. Merry 	    "target %u, handle(0x%04x)\n", cm, cm->cm_ccb, targ->tid,
1622991554f2SKenneth D. Merry 	    targ->handle);
1623991554f2SKenneth D. Merry 	if (targ->encl_level_valid) {
1624991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_XINFO, "At enclosure level %d, slot %d, "
1625991554f2SKenneth D. Merry 		    "connector name (%4s)\n", targ->encl_level, targ->encl_slot,
1626991554f2SKenneth D. Merry 		    targ->connector_name);
1627991554f2SKenneth D. Merry 	}
1628991554f2SKenneth D. Merry 
1629991554f2SKenneth D. Merry 	/* XXX first, check the firmware state, to see if it's still
1630991554f2SKenneth D. Merry 	 * operational.  if not, do a diag reset.
1631991554f2SKenneth D. Merry 	 */
1632991554f2SKenneth D. Merry 
1633991554f2SKenneth D. Merry 	cm->cm_ccb->ccb_h.status = CAM_CMD_TIMEOUT;
1634991554f2SKenneth D. Merry 	cm->cm_state = MPR_CM_STATE_TIMEDOUT;
1635991554f2SKenneth D. Merry 	TAILQ_INSERT_TAIL(&targ->timedout_commands, cm, cm_recovery);
1636991554f2SKenneth D. Merry 
1637991554f2SKenneth D. Merry 	if (targ->tm != NULL) {
1638991554f2SKenneth D. Merry 		/* target already in recovery, just queue up another
1639991554f2SKenneth D. Merry 		 * timedout command to be processed later.
1640991554f2SKenneth D. Merry 		 */
1641991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_RECOVERY, "queued timedout cm %p for "
1642991554f2SKenneth D. Merry 		    "processing by tm %p\n", cm, targ->tm);
1643991554f2SKenneth D. Merry 	}
1644991554f2SKenneth D. Merry 	else if ((targ->tm = mprsas_alloc_tm(sc)) != NULL) {
1645991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_RECOVERY, "timedout cm %p allocated tm %p\n",
1646991554f2SKenneth D. Merry 		    cm, targ->tm);
1647991554f2SKenneth D. Merry 
1648991554f2SKenneth D. Merry 		/* start recovery by aborting the first timedout command */
1649991554f2SKenneth D. Merry 		mprsas_send_abort(sc, targ->tm, cm);
1650991554f2SKenneth D. Merry 	}
1651991554f2SKenneth D. Merry 	else {
1652991554f2SKenneth D. Merry 		/* XXX queue this target up for recovery once a TM becomes
1653991554f2SKenneth D. Merry 		 * available.  The firmware only has a limited number of
1654991554f2SKenneth D. Merry 		 * HighPriority credits for the high priority requests used
1655991554f2SKenneth D. Merry 		 * for task management, and we ran out.
1656991554f2SKenneth D. Merry 		 *
1657991554f2SKenneth D. Merry 		 * Isilon: don't worry about this for now, since we have
1658991554f2SKenneth D. Merry 		 * more credits than disks in an enclosure, and limit
1659991554f2SKenneth D. Merry 		 * ourselves to one TM per target for recovery.
1660991554f2SKenneth D. Merry 		 */
1661991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_RECOVERY,
1662991554f2SKenneth D. Merry 		    "timedout cm %p failed to allocate a tm\n", cm);
1663991554f2SKenneth D. Merry 	}
1664991554f2SKenneth D. Merry }
1665991554f2SKenneth D. Merry 
1666991554f2SKenneth D. Merry static void
1667991554f2SKenneth D. Merry mprsas_action_scsiio(struct mprsas_softc *sassc, union ccb *ccb)
1668991554f2SKenneth D. Merry {
1669991554f2SKenneth D. Merry 	MPI2_SCSI_IO_REQUEST *req;
1670991554f2SKenneth D. Merry 	struct ccb_scsiio *csio;
1671991554f2SKenneth D. Merry 	struct mpr_softc *sc;
1672991554f2SKenneth D. Merry 	struct mprsas_target *targ;
1673991554f2SKenneth D. Merry 	struct mprsas_lun *lun;
1674991554f2SKenneth D. Merry 	struct mpr_command *cm;
1675991554f2SKenneth D. Merry 	uint8_t i, lba_byte, *ref_tag_addr;
1676991554f2SKenneth D. Merry 	uint16_t eedp_flags;
1677991554f2SKenneth D. Merry 	uint32_t mpi_control;
1678991554f2SKenneth D. Merry 
1679991554f2SKenneth D. Merry 	sc = sassc->sc;
1680991554f2SKenneth D. Merry 	MPR_FUNCTRACE(sc);
1681991554f2SKenneth D. Merry 	mtx_assert(&sc->mpr_mtx, MA_OWNED);
1682991554f2SKenneth D. Merry 
1683991554f2SKenneth D. Merry 	csio = &ccb->csio;
1684991554f2SKenneth D. Merry 	targ = &sassc->targets[csio->ccb_h.target_id];
1685991554f2SKenneth D. Merry 	mpr_dprint(sc, MPR_TRACE, "ccb %p target flag %x\n", ccb, targ->flags);
1686991554f2SKenneth D. Merry 	if (targ->handle == 0x0) {
1687991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_ERROR, "%s NULL handle for target %u\n",
1688991554f2SKenneth D. Merry 		    __func__, csio->ccb_h.target_id);
1689991554f2SKenneth D. Merry 		csio->ccb_h.status = CAM_DEV_NOT_THERE;
1690991554f2SKenneth D. Merry 		xpt_done(ccb);
1691991554f2SKenneth D. Merry 		return;
1692991554f2SKenneth D. Merry 	}
1693991554f2SKenneth D. Merry 	if (targ->flags & MPR_TARGET_FLAGS_RAID_COMPONENT) {
1694991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_TRACE, "%s Raid component no SCSI IO "
1695991554f2SKenneth D. Merry 		    "supported %u\n", __func__, csio->ccb_h.target_id);
1696991554f2SKenneth D. Merry 		csio->ccb_h.status = CAM_DEV_NOT_THERE;
1697991554f2SKenneth D. Merry 		xpt_done(ccb);
1698991554f2SKenneth D. Merry 		return;
1699991554f2SKenneth D. Merry 	}
1700991554f2SKenneth D. Merry 	/*
1701991554f2SKenneth D. Merry 	 * Sometimes, it is possible to get a command that is not "In
1702991554f2SKenneth D. Merry 	 * Progress" and was actually aborted by the upper layer.  Check for
1703991554f2SKenneth D. Merry 	 * this here and complete the command without error.
1704991554f2SKenneth D. Merry 	 */
1705991554f2SKenneth D. Merry 	if (ccb->ccb_h.status != CAM_REQ_INPROG) {
1706991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_TRACE, "%s Command is not in progress for "
1707991554f2SKenneth D. Merry 		    "target %u\n", __func__, csio->ccb_h.target_id);
1708991554f2SKenneth D. Merry 		xpt_done(ccb);
1709991554f2SKenneth D. Merry 		return;
1710991554f2SKenneth D. Merry 	}
1711991554f2SKenneth D. Merry 	/*
1712991554f2SKenneth D. Merry 	 * If devinfo is 0 this will be a volume.  In that case don't tell CAM
1713991554f2SKenneth D. Merry 	 * that the volume has timed out.  We want volumes to be enumerated
1714991554f2SKenneth D. Merry 	 * until they are deleted/removed, not just failed.
1715991554f2SKenneth D. Merry 	 */
1716991554f2SKenneth D. Merry 	if (targ->flags & MPRSAS_TARGET_INREMOVAL) {
1717991554f2SKenneth D. Merry 		if (targ->devinfo == 0)
1718991554f2SKenneth D. Merry 			csio->ccb_h.status = CAM_REQ_CMP;
1719991554f2SKenneth D. Merry 		else
1720991554f2SKenneth D. Merry 			csio->ccb_h.status = CAM_SEL_TIMEOUT;
1721991554f2SKenneth D. Merry 		xpt_done(ccb);
1722991554f2SKenneth D. Merry 		return;
1723991554f2SKenneth D. Merry 	}
1724991554f2SKenneth D. Merry 
1725991554f2SKenneth D. Merry 	if ((sc->mpr_flags & MPR_FLAGS_SHUTDOWN) != 0) {
1726991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_TRACE, "%s shutting down\n", __func__);
1727991554f2SKenneth D. Merry 		csio->ccb_h.status = CAM_DEV_NOT_THERE;
1728991554f2SKenneth D. Merry 		xpt_done(ccb);
1729991554f2SKenneth D. Merry 		return;
1730991554f2SKenneth D. Merry 	}
1731991554f2SKenneth D. Merry 
1732991554f2SKenneth D. Merry 	cm = mpr_alloc_command(sc);
1733991554f2SKenneth D. Merry 	if (cm == NULL || (sc->mpr_flags & MPR_FLAGS_DIAGRESET)) {
1734991554f2SKenneth D. Merry 		if (cm != NULL) {
1735991554f2SKenneth D. Merry 			mpr_free_command(sc, cm);
1736991554f2SKenneth D. Merry 		}
1737991554f2SKenneth D. Merry 		if ((sassc->flags & MPRSAS_QUEUE_FROZEN) == 0) {
1738991554f2SKenneth D. Merry 			xpt_freeze_simq(sassc->sim, 1);
1739991554f2SKenneth D. Merry 			sassc->flags |= MPRSAS_QUEUE_FROZEN;
1740991554f2SKenneth D. Merry 		}
1741991554f2SKenneth D. Merry 		ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
1742991554f2SKenneth D. Merry 		ccb->ccb_h.status |= CAM_REQUEUE_REQ;
1743991554f2SKenneth D. Merry 		xpt_done(ccb);
1744991554f2SKenneth D. Merry 		return;
1745991554f2SKenneth D. Merry 	}
1746991554f2SKenneth D. Merry 
1747991554f2SKenneth D. Merry 	req = (MPI2_SCSI_IO_REQUEST *)cm->cm_req;
1748991554f2SKenneth D. Merry 	bzero(req, sizeof(*req));
1749991554f2SKenneth D. Merry 	req->DevHandle = htole16(targ->handle);
1750991554f2SKenneth D. Merry 	req->Function = MPI2_FUNCTION_SCSI_IO_REQUEST;
1751991554f2SKenneth D. Merry 	req->MsgFlags = 0;
1752991554f2SKenneth D. Merry 	req->SenseBufferLowAddress = htole32(cm->cm_sense_busaddr);
1753991554f2SKenneth D. Merry 	req->SenseBufferLength = MPR_SENSE_LEN;
1754991554f2SKenneth D. Merry 	req->SGLFlags = 0;
1755991554f2SKenneth D. Merry 	req->ChainOffset = 0;
1756991554f2SKenneth D. Merry 	req->SGLOffset0 = 24;	/* 32bit word offset to the SGL */
1757991554f2SKenneth D. Merry 	req->SGLOffset1= 0;
1758991554f2SKenneth D. Merry 	req->SGLOffset2= 0;
1759991554f2SKenneth D. Merry 	req->SGLOffset3= 0;
1760991554f2SKenneth D. Merry 	req->SkipCount = 0;
1761991554f2SKenneth D. Merry 	req->DataLength = htole32(csio->dxfer_len);
1762991554f2SKenneth D. Merry 	req->BidirectionalDataLength = 0;
1763991554f2SKenneth D. Merry 	req->IoFlags = htole16(csio->cdb_len);
1764991554f2SKenneth D. Merry 	req->EEDPFlags = 0;
1765991554f2SKenneth D. Merry 
1766991554f2SKenneth D. Merry 	/* Note: BiDirectional transfers are not supported */
1767991554f2SKenneth D. Merry 	switch (csio->ccb_h.flags & CAM_DIR_MASK) {
1768991554f2SKenneth D. Merry 	case CAM_DIR_IN:
1769991554f2SKenneth D. Merry 		mpi_control = MPI2_SCSIIO_CONTROL_READ;
1770991554f2SKenneth D. Merry 		cm->cm_flags |= MPR_CM_FLAGS_DATAIN;
1771991554f2SKenneth D. Merry 		break;
1772991554f2SKenneth D. Merry 	case CAM_DIR_OUT:
1773991554f2SKenneth D. Merry 		mpi_control = MPI2_SCSIIO_CONTROL_WRITE;
1774991554f2SKenneth D. Merry 		cm->cm_flags |= MPR_CM_FLAGS_DATAOUT;
1775991554f2SKenneth D. Merry 		break;
1776991554f2SKenneth D. Merry 	case CAM_DIR_NONE:
1777991554f2SKenneth D. Merry 	default:
1778991554f2SKenneth D. Merry 		mpi_control = MPI2_SCSIIO_CONTROL_NODATATRANSFER;
1779991554f2SKenneth D. Merry 		break;
1780991554f2SKenneth D. Merry 	}
1781991554f2SKenneth D. Merry 
1782991554f2SKenneth D. Merry 	if (csio->cdb_len == 32)
1783991554f2SKenneth D. Merry 		mpi_control |= 4 << MPI2_SCSIIO_CONTROL_ADDCDBLEN_SHIFT;
1784991554f2SKenneth D. Merry 	/*
1785991554f2SKenneth D. Merry 	 * It looks like the hardware doesn't require an explicit tag
1786991554f2SKenneth D. Merry 	 * number for each transaction.  SAM Task Management not supported
1787991554f2SKenneth D. Merry 	 * at the moment.
1788991554f2SKenneth D. Merry 	 */
1789991554f2SKenneth D. Merry 	switch (csio->tag_action) {
1790991554f2SKenneth D. Merry 	case MSG_HEAD_OF_Q_TAG:
1791991554f2SKenneth D. Merry 		mpi_control |= MPI2_SCSIIO_CONTROL_HEADOFQ;
1792991554f2SKenneth D. Merry 		break;
1793991554f2SKenneth D. Merry 	case MSG_ORDERED_Q_TAG:
1794991554f2SKenneth D. Merry 		mpi_control |= MPI2_SCSIIO_CONTROL_ORDEREDQ;
1795991554f2SKenneth D. Merry 		break;
1796991554f2SKenneth D. Merry 	case MSG_ACA_TASK:
1797991554f2SKenneth D. Merry 		mpi_control |= MPI2_SCSIIO_CONTROL_ACAQ;
1798991554f2SKenneth D. Merry 		break;
1799991554f2SKenneth D. Merry 	case CAM_TAG_ACTION_NONE:
1800991554f2SKenneth D. Merry 	case MSG_SIMPLE_Q_TAG:
1801991554f2SKenneth D. Merry 	default:
1802991554f2SKenneth D. Merry 		mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ;
1803991554f2SKenneth D. Merry 		break;
1804991554f2SKenneth D. Merry 	}
1805991554f2SKenneth D. Merry 	mpi_control |= sc->mapping_table[csio->ccb_h.target_id].TLR_bits;
1806991554f2SKenneth D. Merry 	req->Control = htole32(mpi_control);
1807991554f2SKenneth D. Merry 
1808991554f2SKenneth D. Merry 	if (MPR_SET_LUN(req->LUN, csio->ccb_h.target_lun) != 0) {
1809991554f2SKenneth D. Merry 		mpr_free_command(sc, cm);
1810991554f2SKenneth D. Merry 		ccb->ccb_h.status = CAM_LUN_INVALID;
1811991554f2SKenneth D. Merry 		xpt_done(ccb);
1812991554f2SKenneth D. Merry 		return;
1813991554f2SKenneth D. Merry 	}
1814991554f2SKenneth D. Merry 
1815991554f2SKenneth D. Merry 	if (csio->ccb_h.flags & CAM_CDB_POINTER)
1816991554f2SKenneth D. Merry 		bcopy(csio->cdb_io.cdb_ptr, &req->CDB.CDB32[0], csio->cdb_len);
1817991554f2SKenneth D. Merry 	else
1818991554f2SKenneth D. Merry 		bcopy(csio->cdb_io.cdb_bytes, &req->CDB.CDB32[0],csio->cdb_len);
1819991554f2SKenneth D. Merry 	req->IoFlags = htole16(csio->cdb_len);
1820991554f2SKenneth D. Merry 
1821991554f2SKenneth D. Merry 	/*
1822991554f2SKenneth D. Merry 	 * Check if EEDP is supported and enabled.  If it is then check if the
1823991554f2SKenneth D. Merry 	 * SCSI opcode could be using EEDP.  If so, make sure the LUN exists and
1824991554f2SKenneth D. Merry 	 * is formatted for EEDP support.  If all of this is true, set CDB up
1825991554f2SKenneth D. Merry 	 * for EEDP transfer.
1826991554f2SKenneth D. Merry 	 */
1827991554f2SKenneth D. Merry 	eedp_flags = op_code_prot[req->CDB.CDB32[0]];
1828991554f2SKenneth D. Merry 	if (sc->eedp_enabled && eedp_flags) {
1829991554f2SKenneth D. Merry 		SLIST_FOREACH(lun, &targ->luns, lun_link) {
1830991554f2SKenneth D. Merry 			if (lun->lun_id == csio->ccb_h.target_lun) {
1831991554f2SKenneth D. Merry 				break;
1832991554f2SKenneth D. Merry 			}
1833991554f2SKenneth D. Merry 		}
1834991554f2SKenneth D. Merry 
1835991554f2SKenneth D. Merry 		if ((lun != NULL) && (lun->eedp_formatted)) {
1836991554f2SKenneth D. Merry 			req->EEDPBlockSize = htole16(lun->eedp_block_size);
1837991554f2SKenneth D. Merry 			eedp_flags |= (MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG |
1838991554f2SKenneth D. Merry 			    MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG |
1839991554f2SKenneth D. Merry 			    MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD);
1840991554f2SKenneth D. Merry 			req->EEDPFlags = htole16(eedp_flags);
1841991554f2SKenneth D. Merry 
1842991554f2SKenneth D. Merry 			/*
1843991554f2SKenneth D. Merry 			 * If CDB less than 32, fill in Primary Ref Tag with
1844991554f2SKenneth D. Merry 			 * low 4 bytes of LBA.  If CDB is 32, tag stuff is
1845991554f2SKenneth D. Merry 			 * already there.  Also, set protection bit.  FreeBSD
1846991554f2SKenneth D. Merry 			 * currently does not support CDBs bigger than 16, but
1847991554f2SKenneth D. Merry 			 * the code doesn't hurt, and will be here for the
1848991554f2SKenneth D. Merry 			 * future.
1849991554f2SKenneth D. Merry 			 */
1850991554f2SKenneth D. Merry 			if (csio->cdb_len != 32) {
1851991554f2SKenneth D. Merry 				lba_byte = (csio->cdb_len == 16) ? 6 : 2;
1852991554f2SKenneth D. Merry 				ref_tag_addr = (uint8_t *)&req->CDB.EEDP32.
1853991554f2SKenneth D. Merry 				    PrimaryReferenceTag;
1854991554f2SKenneth D. Merry 				for (i = 0; i < 4; i++) {
1855991554f2SKenneth D. Merry 					*ref_tag_addr =
1856991554f2SKenneth D. Merry 					    req->CDB.CDB32[lba_byte + i];
1857991554f2SKenneth D. Merry 					ref_tag_addr++;
1858991554f2SKenneth D. Merry 				}
1859991554f2SKenneth D. Merry 				req->CDB.EEDP32.PrimaryReferenceTag =
1860991554f2SKenneth D. Merry 				    htole32(req->
1861991554f2SKenneth D. Merry 				    CDB.EEDP32.PrimaryReferenceTag);
1862991554f2SKenneth D. Merry 				req->CDB.EEDP32.PrimaryApplicationTagMask =
1863991554f2SKenneth D. Merry 				    0xFFFF;
1864991554f2SKenneth D. Merry 				req->CDB.CDB32[1] = (req->CDB.CDB32[1] & 0x1F) |
1865991554f2SKenneth D. Merry 				    0x20;
1866991554f2SKenneth D. Merry 			} else {
1867991554f2SKenneth D. Merry 				eedp_flags |=
1868991554f2SKenneth D. Merry 				    MPI2_SCSIIO_EEDPFLAGS_INC_PRI_APPTAG;
1869991554f2SKenneth D. Merry 				req->EEDPFlags = htole16(eedp_flags);
1870991554f2SKenneth D. Merry 				req->CDB.CDB32[10] = (req->CDB.CDB32[10] &
1871991554f2SKenneth D. Merry 				    0x1F) | 0x20;
1872991554f2SKenneth D. Merry 			}
1873991554f2SKenneth D. Merry 		}
1874991554f2SKenneth D. Merry 	}
1875991554f2SKenneth D. Merry 
1876991554f2SKenneth D. Merry 	cm->cm_length = csio->dxfer_len;
1877991554f2SKenneth D. Merry 	if (cm->cm_length != 0) {
1878991554f2SKenneth D. Merry 		cm->cm_data = ccb;
1879991554f2SKenneth D. Merry 		cm->cm_flags |= MPR_CM_FLAGS_USE_CCB;
1880991554f2SKenneth D. Merry 	} else {
1881991554f2SKenneth D. Merry 		cm->cm_data = NULL;
1882991554f2SKenneth D. Merry 	}
1883991554f2SKenneth D. Merry 	cm->cm_sge = &req->SGL;
1884991554f2SKenneth D. Merry 	cm->cm_sglsize = (32 - 24) * 4;
1885991554f2SKenneth D. Merry 	cm->cm_complete = mprsas_scsiio_complete;
1886991554f2SKenneth D. Merry 	cm->cm_complete_data = ccb;
1887991554f2SKenneth D. Merry 	cm->cm_targ = targ;
1888991554f2SKenneth D. Merry 	cm->cm_lun = csio->ccb_h.target_lun;
1889991554f2SKenneth D. Merry 	cm->cm_ccb = ccb;
1890991554f2SKenneth D. Merry 	/*
1891991554f2SKenneth D. Merry 	 * If using FP desc type, need to set a bit in IoFlags (SCSI IO is 0)
1892991554f2SKenneth D. Merry 	 * and set descriptor type.
1893991554f2SKenneth D. Merry 	 */
1894991554f2SKenneth D. Merry 	if (targ->scsi_req_desc_type ==
1895991554f2SKenneth D. Merry 	    MPI25_REQ_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO) {
1896991554f2SKenneth D. Merry 		req->IoFlags |= MPI25_SCSIIO_IOFLAGS_FAST_PATH;
1897991554f2SKenneth D. Merry 		cm->cm_desc.FastPathSCSIIO.RequestFlags =
1898991554f2SKenneth D. Merry 		    MPI25_REQ_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO;
1899991554f2SKenneth D. Merry 		cm->cm_desc.FastPathSCSIIO.DevHandle = htole16(targ->handle);
1900991554f2SKenneth D. Merry 	} else {
1901991554f2SKenneth D. Merry 		cm->cm_desc.SCSIIO.RequestFlags =
1902991554f2SKenneth D. Merry 		    MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO;
1903991554f2SKenneth D. Merry 		cm->cm_desc.SCSIIO.DevHandle = htole16(targ->handle);
1904991554f2SKenneth D. Merry 	}
1905991554f2SKenneth D. Merry 
190685c9dd9dSSteven Hartland 	callout_reset_sbt(&cm->cm_callout, SBT_1MS * ccb->ccb_h.timeout, 0,
190785c9dd9dSSteven Hartland 	   mprsas_scsiio_timeout, cm, 0);
1908991554f2SKenneth D. Merry 
1909991554f2SKenneth D. Merry 	targ->issued++;
1910991554f2SKenneth D. Merry 	targ->outstanding++;
1911991554f2SKenneth D. Merry 	TAILQ_INSERT_TAIL(&targ->commands, cm, cm_link);
1912991554f2SKenneth D. Merry 	ccb->ccb_h.status |= CAM_SIM_QUEUED;
1913991554f2SKenneth D. Merry 
1914991554f2SKenneth D. Merry 	mprsas_log_command(cm, MPR_XINFO, "%s cm %p ccb %p outstanding %u\n",
1915991554f2SKenneth D. Merry 	    __func__, cm, ccb, targ->outstanding);
1916991554f2SKenneth D. Merry 
1917991554f2SKenneth D. Merry 	mpr_map_command(sc, cm);
1918991554f2SKenneth D. Merry 	return;
1919991554f2SKenneth D. Merry }
1920991554f2SKenneth D. Merry 
1921991554f2SKenneth D. Merry static void
1922991554f2SKenneth D. Merry mpr_response_code(struct mpr_softc *sc, u8 response_code)
1923991554f2SKenneth D. Merry {
1924991554f2SKenneth D. Merry         char *desc;
1925991554f2SKenneth D. Merry 
1926991554f2SKenneth D. Merry         switch (response_code) {
1927991554f2SKenneth D. Merry         case MPI2_SCSITASKMGMT_RSP_TM_COMPLETE:
1928991554f2SKenneth D. Merry                 desc = "task management request completed";
1929991554f2SKenneth D. Merry                 break;
1930991554f2SKenneth D. Merry         case MPI2_SCSITASKMGMT_RSP_INVALID_FRAME:
1931991554f2SKenneth D. Merry                 desc = "invalid frame";
1932991554f2SKenneth D. Merry                 break;
1933991554f2SKenneth D. Merry         case MPI2_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED:
1934991554f2SKenneth D. Merry                 desc = "task management request not supported";
1935991554f2SKenneth D. Merry                 break;
1936991554f2SKenneth D. Merry         case MPI2_SCSITASKMGMT_RSP_TM_FAILED:
1937991554f2SKenneth D. Merry                 desc = "task management request failed";
1938991554f2SKenneth D. Merry                 break;
1939991554f2SKenneth D. Merry         case MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED:
1940991554f2SKenneth D. Merry                 desc = "task management request succeeded";
1941991554f2SKenneth D. Merry                 break;
1942991554f2SKenneth D. Merry         case MPI2_SCSITASKMGMT_RSP_TM_INVALID_LUN:
1943991554f2SKenneth D. Merry                 desc = "invalid lun";
1944991554f2SKenneth D. Merry                 break;
1945991554f2SKenneth D. Merry         case 0xA:
1946991554f2SKenneth D. Merry                 desc = "overlapped tag attempted";
1947991554f2SKenneth D. Merry                 break;
1948991554f2SKenneth D. Merry         case MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC:
1949991554f2SKenneth D. Merry                 desc = "task queued, however not sent to target";
1950991554f2SKenneth D. Merry                 break;
1951991554f2SKenneth D. Merry         default:
1952991554f2SKenneth D. Merry                 desc = "unknown";
1953991554f2SKenneth D. Merry                 break;
1954991554f2SKenneth D. Merry         }
1955991554f2SKenneth D. Merry 	mpr_dprint(sc, MPR_XINFO, "response_code(0x%01x): %s\n", response_code,
1956991554f2SKenneth D. Merry 	    desc);
1957991554f2SKenneth D. Merry }
1958991554f2SKenneth D. Merry 
1959991554f2SKenneth D. Merry /**
1960991554f2SKenneth D. Merry  * mpr_sc_failed_io_info - translated non-succesfull SCSI_IO request
1961991554f2SKenneth D. Merry  */
1962991554f2SKenneth D. Merry static void
1963991554f2SKenneth D. Merry mpr_sc_failed_io_info(struct mpr_softc *sc, struct ccb_scsiio *csio,
1964991554f2SKenneth D. Merry     Mpi2SCSIIOReply_t *mpi_reply, struct mprsas_target *targ)
1965991554f2SKenneth D. Merry {
1966991554f2SKenneth D. Merry 	u32 response_info;
1967991554f2SKenneth D. Merry 	u8 *response_bytes;
1968991554f2SKenneth D. Merry 	u16 ioc_status = le16toh(mpi_reply->IOCStatus) &
1969991554f2SKenneth D. Merry 	    MPI2_IOCSTATUS_MASK;
1970991554f2SKenneth D. Merry 	u8 scsi_state = mpi_reply->SCSIState;
1971991554f2SKenneth D. Merry 	u8 scsi_status = mpi_reply->SCSIStatus;
1972991554f2SKenneth D. Merry 	char *desc_ioc_state = NULL;
1973991554f2SKenneth D. Merry 	char *desc_scsi_status = NULL;
1974991554f2SKenneth D. Merry 	char *desc_scsi_state = sc->tmp_string;
1975991554f2SKenneth D. Merry 	u32 log_info = le32toh(mpi_reply->IOCLogInfo);
1976991554f2SKenneth D. Merry 
1977991554f2SKenneth D. Merry 	if (log_info == 0x31170000)
1978991554f2SKenneth D. Merry 		return;
1979991554f2SKenneth D. Merry 
1980991554f2SKenneth D. Merry 	switch (ioc_status) {
1981991554f2SKenneth D. Merry 	case MPI2_IOCSTATUS_SUCCESS:
1982991554f2SKenneth D. Merry 		desc_ioc_state = "success";
1983991554f2SKenneth D. Merry 		break;
1984991554f2SKenneth D. Merry 	case MPI2_IOCSTATUS_INVALID_FUNCTION:
1985991554f2SKenneth D. Merry 		desc_ioc_state = "invalid function";
1986991554f2SKenneth D. Merry 		break;
1987991554f2SKenneth D. Merry 	case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR:
1988991554f2SKenneth D. Merry 		desc_ioc_state = "scsi recovered error";
1989991554f2SKenneth D. Merry 		break;
1990991554f2SKenneth D. Merry 	case MPI2_IOCSTATUS_SCSI_INVALID_DEVHANDLE:
1991991554f2SKenneth D. Merry 		desc_ioc_state = "scsi invalid dev handle";
1992991554f2SKenneth D. Merry 		break;
1993991554f2SKenneth D. Merry 	case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
1994991554f2SKenneth D. Merry 		desc_ioc_state = "scsi device not there";
1995991554f2SKenneth D. Merry 		break;
1996991554f2SKenneth D. Merry 	case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN:
1997991554f2SKenneth D. Merry 		desc_ioc_state = "scsi data overrun";
1998991554f2SKenneth D. Merry 		break;
1999991554f2SKenneth D. Merry 	case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN:
2000991554f2SKenneth D. Merry 		desc_ioc_state = "scsi data underrun";
2001991554f2SKenneth D. Merry 		break;
2002991554f2SKenneth D. Merry 	case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR:
2003991554f2SKenneth D. Merry 		desc_ioc_state = "scsi io data error";
2004991554f2SKenneth D. Merry 		break;
2005991554f2SKenneth D. Merry 	case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR:
2006991554f2SKenneth D. Merry 		desc_ioc_state = "scsi protocol error";
2007991554f2SKenneth D. Merry 		break;
2008991554f2SKenneth D. Merry 	case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED:
2009991554f2SKenneth D. Merry 		desc_ioc_state = "scsi task terminated";
2010991554f2SKenneth D. Merry 		break;
2011991554f2SKenneth D. Merry 	case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
2012991554f2SKenneth D. Merry 		desc_ioc_state = "scsi residual mismatch";
2013991554f2SKenneth D. Merry 		break;
2014991554f2SKenneth D. Merry 	case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
2015991554f2SKenneth D. Merry 		desc_ioc_state = "scsi task mgmt failed";
2016991554f2SKenneth D. Merry 		break;
2017991554f2SKenneth D. Merry 	case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED:
2018991554f2SKenneth D. Merry 		desc_ioc_state = "scsi ioc terminated";
2019991554f2SKenneth D. Merry 		break;
2020991554f2SKenneth D. Merry 	case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED:
2021991554f2SKenneth D. Merry 		desc_ioc_state = "scsi ext terminated";
2022991554f2SKenneth D. Merry 		break;
2023991554f2SKenneth D. Merry 	case MPI2_IOCSTATUS_EEDP_GUARD_ERROR:
2024991554f2SKenneth D. Merry 		desc_ioc_state = "eedp guard error";
2025991554f2SKenneth D. Merry 		break;
2026991554f2SKenneth D. Merry 	case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR:
2027991554f2SKenneth D. Merry 		desc_ioc_state = "eedp ref tag error";
2028991554f2SKenneth D. Merry 		break;
2029991554f2SKenneth D. Merry 	case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR:
2030991554f2SKenneth D. Merry 		desc_ioc_state = "eedp app tag error";
2031991554f2SKenneth D. Merry 		break;
2032991554f2SKenneth D. Merry 	default:
2033991554f2SKenneth D. Merry 		desc_ioc_state = "unknown";
2034991554f2SKenneth D. Merry 		break;
2035991554f2SKenneth D. Merry 	}
2036991554f2SKenneth D. Merry 
2037991554f2SKenneth D. Merry 	switch (scsi_status) {
2038991554f2SKenneth D. Merry 	case MPI2_SCSI_STATUS_GOOD:
2039991554f2SKenneth D. Merry 		desc_scsi_status = "good";
2040991554f2SKenneth D. Merry 		break;
2041991554f2SKenneth D. Merry 	case MPI2_SCSI_STATUS_CHECK_CONDITION:
2042991554f2SKenneth D. Merry 		desc_scsi_status = "check condition";
2043991554f2SKenneth D. Merry 		break;
2044991554f2SKenneth D. Merry 	case MPI2_SCSI_STATUS_CONDITION_MET:
2045991554f2SKenneth D. Merry 		desc_scsi_status = "condition met";
2046991554f2SKenneth D. Merry 		break;
2047991554f2SKenneth D. Merry 	case MPI2_SCSI_STATUS_BUSY:
2048991554f2SKenneth D. Merry 		desc_scsi_status = "busy";
2049991554f2SKenneth D. Merry 		break;
2050991554f2SKenneth D. Merry 	case MPI2_SCSI_STATUS_INTERMEDIATE:
2051991554f2SKenneth D. Merry 		desc_scsi_status = "intermediate";
2052991554f2SKenneth D. Merry 		break;
2053991554f2SKenneth D. Merry 	case MPI2_SCSI_STATUS_INTERMEDIATE_CONDMET:
2054991554f2SKenneth D. Merry 		desc_scsi_status = "intermediate condmet";
2055991554f2SKenneth D. Merry 		break;
2056991554f2SKenneth D. Merry 	case MPI2_SCSI_STATUS_RESERVATION_CONFLICT:
2057991554f2SKenneth D. Merry 		desc_scsi_status = "reservation conflict";
2058991554f2SKenneth D. Merry 		break;
2059991554f2SKenneth D. Merry 	case MPI2_SCSI_STATUS_COMMAND_TERMINATED:
2060991554f2SKenneth D. Merry 		desc_scsi_status = "command terminated";
2061991554f2SKenneth D. Merry 		break;
2062991554f2SKenneth D. Merry 	case MPI2_SCSI_STATUS_TASK_SET_FULL:
2063991554f2SKenneth D. Merry 		desc_scsi_status = "task set full";
2064991554f2SKenneth D. Merry 		break;
2065991554f2SKenneth D. Merry 	case MPI2_SCSI_STATUS_ACA_ACTIVE:
2066991554f2SKenneth D. Merry 		desc_scsi_status = "aca active";
2067991554f2SKenneth D. Merry 		break;
2068991554f2SKenneth D. Merry 	case MPI2_SCSI_STATUS_TASK_ABORTED:
2069991554f2SKenneth D. Merry 		desc_scsi_status = "task aborted";
2070991554f2SKenneth D. Merry 		break;
2071991554f2SKenneth D. Merry 	default:
2072991554f2SKenneth D. Merry 		desc_scsi_status = "unknown";
2073991554f2SKenneth D. Merry 		break;
2074991554f2SKenneth D. Merry 	}
2075991554f2SKenneth D. Merry 
2076991554f2SKenneth D. Merry 	desc_scsi_state[0] = '\0';
2077991554f2SKenneth D. Merry 	if (!scsi_state)
2078991554f2SKenneth D. Merry 		desc_scsi_state = " ";
2079991554f2SKenneth D. Merry 	if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID)
2080991554f2SKenneth D. Merry 		strcat(desc_scsi_state, "response info ");
2081991554f2SKenneth D. Merry 	if (scsi_state & MPI2_SCSI_STATE_TERMINATED)
2082991554f2SKenneth D. Merry 		strcat(desc_scsi_state, "state terminated ");
2083991554f2SKenneth D. Merry 	if (scsi_state & MPI2_SCSI_STATE_NO_SCSI_STATUS)
2084991554f2SKenneth D. Merry 		strcat(desc_scsi_state, "no status ");
2085991554f2SKenneth D. Merry 	if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_FAILED)
2086991554f2SKenneth D. Merry 		strcat(desc_scsi_state, "autosense failed ");
2087991554f2SKenneth D. Merry 	if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID)
2088991554f2SKenneth D. Merry 		strcat(desc_scsi_state, "autosense valid ");
2089991554f2SKenneth D. Merry 
2090991554f2SKenneth D. Merry 	mpr_dprint(sc, MPR_XINFO, "\thandle(0x%04x), ioc_status(%s)(0x%04x)\n",
2091991554f2SKenneth D. Merry 	    le16toh(mpi_reply->DevHandle), desc_ioc_state, ioc_status);
2092991554f2SKenneth D. Merry 	if (targ->encl_level_valid) {
2093991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_XINFO, "At enclosure level %d, slot %d, "
2094991554f2SKenneth D. Merry 		    "connector name (%4s)\n", targ->encl_level, targ->encl_slot,
2095991554f2SKenneth D. Merry 		    targ->connector_name);
2096991554f2SKenneth D. Merry 	}
2097991554f2SKenneth D. Merry 	/* We can add more detail about underflow data here
2098991554f2SKenneth D. Merry 	 * TO-DO
2099991554f2SKenneth D. Merry 	 * */
2100991554f2SKenneth D. Merry 	mpr_dprint(sc, MPR_XINFO, "\tscsi_status(%s)(0x%02x), "
2101991554f2SKenneth D. Merry 	    "scsi_state(%s)(0x%02x)\n", desc_scsi_status, scsi_status,
2102991554f2SKenneth D. Merry 	    desc_scsi_state, scsi_state);
2103991554f2SKenneth D. Merry 
2104991554f2SKenneth D. Merry 	if (sc->mpr_debug & MPR_XINFO &&
2105991554f2SKenneth D. Merry 		scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID) {
2106991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_XINFO, "-> Sense Buffer Data : Start :\n");
2107991554f2SKenneth D. Merry 		scsi_sense_print(csio);
2108991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_XINFO, "-> Sense Buffer Data : End :\n");
2109991554f2SKenneth D. Merry 	}
2110991554f2SKenneth D. Merry 
2111991554f2SKenneth D. Merry 	if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) {
2112991554f2SKenneth D. Merry 		response_info = le32toh(mpi_reply->ResponseInfo);
2113991554f2SKenneth D. Merry 		response_bytes = (u8 *)&response_info;
2114991554f2SKenneth D. Merry 		mpr_response_code(sc,response_bytes[0]);
2115991554f2SKenneth D. Merry 	}
2116991554f2SKenneth D. Merry }
2117991554f2SKenneth D. Merry 
2118991554f2SKenneth D. Merry static void
2119991554f2SKenneth D. Merry mprsas_scsiio_complete(struct mpr_softc *sc, struct mpr_command *cm)
2120991554f2SKenneth D. Merry {
2121991554f2SKenneth D. Merry 	MPI2_SCSI_IO_REPLY *rep;
2122991554f2SKenneth D. Merry 	union ccb *ccb;
2123991554f2SKenneth D. Merry 	struct ccb_scsiio *csio;
2124991554f2SKenneth D. Merry 	struct mprsas_softc *sassc;
2125991554f2SKenneth D. Merry 	struct scsi_vpd_supported_page_list *vpd_list = NULL;
2126991554f2SKenneth D. Merry 	u8 *TLR_bits, TLR_on;
2127991554f2SKenneth D. Merry 	int dir = 0, i;
2128991554f2SKenneth D. Merry 	u16 alloc_len;
2129991554f2SKenneth D. Merry 
2130991554f2SKenneth D. Merry 	MPR_FUNCTRACE(sc);
2131991554f2SKenneth D. Merry 	mpr_dprint(sc, MPR_TRACE,
2132991554f2SKenneth D. Merry 	    "cm %p SMID %u ccb %p reply %p outstanding %u\n", cm,
2133991554f2SKenneth D. Merry 	    cm->cm_desc.Default.SMID, cm->cm_ccb, cm->cm_reply,
2134991554f2SKenneth D. Merry 	    cm->cm_targ->outstanding);
2135991554f2SKenneth D. Merry 
2136991554f2SKenneth D. Merry 	callout_stop(&cm->cm_callout);
2137991554f2SKenneth D. Merry 	mtx_assert(&sc->mpr_mtx, MA_OWNED);
2138991554f2SKenneth D. Merry 
2139991554f2SKenneth D. Merry 	sassc = sc->sassc;
2140991554f2SKenneth D. Merry 	ccb = cm->cm_complete_data;
2141991554f2SKenneth D. Merry 	csio = &ccb->csio;
2142991554f2SKenneth D. Merry 	rep = (MPI2_SCSI_IO_REPLY *)cm->cm_reply;
2143991554f2SKenneth D. Merry 	/*
2144991554f2SKenneth D. Merry 	 * XXX KDM if the chain allocation fails, does it matter if we do
2145991554f2SKenneth D. Merry 	 * the sync and unload here?  It is simpler to do it in every case,
2146991554f2SKenneth D. Merry 	 * assuming it doesn't cause problems.
2147991554f2SKenneth D. Merry 	 */
2148991554f2SKenneth D. Merry 	if (cm->cm_data != NULL) {
2149991554f2SKenneth D. Merry 		if (cm->cm_flags & MPR_CM_FLAGS_DATAIN)
2150991554f2SKenneth D. Merry 			dir = BUS_DMASYNC_POSTREAD;
2151991554f2SKenneth D. Merry 		else if (cm->cm_flags & MPR_CM_FLAGS_DATAOUT)
2152991554f2SKenneth D. Merry 			dir = BUS_DMASYNC_POSTWRITE;
2153991554f2SKenneth D. Merry 		bus_dmamap_sync(sc->buffer_dmat, cm->cm_dmamap, dir);
2154991554f2SKenneth D. Merry 		bus_dmamap_unload(sc->buffer_dmat, cm->cm_dmamap);
2155991554f2SKenneth D. Merry 	}
2156991554f2SKenneth D. Merry 
2157991554f2SKenneth D. Merry 	cm->cm_targ->completed++;
2158991554f2SKenneth D. Merry 	cm->cm_targ->outstanding--;
2159991554f2SKenneth D. Merry 	TAILQ_REMOVE(&cm->cm_targ->commands, cm, cm_link);
2160991554f2SKenneth D. Merry 	ccb->ccb_h.status &= ~(CAM_STATUS_MASK | CAM_SIM_QUEUED);
2161991554f2SKenneth D. Merry 
2162991554f2SKenneth D. Merry 	if (cm->cm_state == MPR_CM_STATE_TIMEDOUT) {
2163991554f2SKenneth D. Merry 		TAILQ_REMOVE(&cm->cm_targ->timedout_commands, cm, cm_recovery);
2164991554f2SKenneth D. Merry 		if (cm->cm_reply != NULL)
2165991554f2SKenneth D. Merry 			mprsas_log_command(cm, MPR_RECOVERY,
2166991554f2SKenneth D. Merry 			    "completed timedout cm %p ccb %p during recovery "
2167991554f2SKenneth D. Merry 			    "ioc %x scsi %x state %x xfer %u\n", cm, cm->cm_ccb,
2168991554f2SKenneth D. Merry 			    le16toh(rep->IOCStatus), rep->SCSIStatus,
2169991554f2SKenneth D. Merry 			    rep->SCSIState, le32toh(rep->TransferCount));
2170991554f2SKenneth D. Merry 		else
2171991554f2SKenneth D. Merry 			mprsas_log_command(cm, MPR_RECOVERY,
2172991554f2SKenneth D. Merry 			    "completed timedout cm %p ccb %p during recovery\n",
2173991554f2SKenneth D. Merry 			    cm, cm->cm_ccb);
2174991554f2SKenneth D. Merry 	} else if (cm->cm_targ->tm != NULL) {
2175991554f2SKenneth D. Merry 		if (cm->cm_reply != NULL)
2176991554f2SKenneth D. Merry 			mprsas_log_command(cm, MPR_RECOVERY,
2177991554f2SKenneth D. Merry 			    "completed cm %p ccb %p during recovery "
2178991554f2SKenneth D. Merry 			    "ioc %x scsi %x state %x xfer %u\n",
2179991554f2SKenneth D. Merry 			    cm, cm->cm_ccb, le16toh(rep->IOCStatus),
2180991554f2SKenneth D. Merry 			    rep->SCSIStatus, rep->SCSIState,
2181991554f2SKenneth D. Merry 			    le32toh(rep->TransferCount));
2182991554f2SKenneth D. Merry 		else
2183991554f2SKenneth D. Merry 			mprsas_log_command(cm, MPR_RECOVERY,
2184991554f2SKenneth D. Merry 			    "completed cm %p ccb %p during recovery\n",
2185991554f2SKenneth D. Merry 			    cm, cm->cm_ccb);
2186991554f2SKenneth D. Merry 	} else if ((sc->mpr_flags & MPR_FLAGS_DIAGRESET) != 0) {
2187991554f2SKenneth D. Merry 		mprsas_log_command(cm, MPR_RECOVERY,
2188991554f2SKenneth D. Merry 		    "reset completed cm %p ccb %p\n", cm, cm->cm_ccb);
2189991554f2SKenneth D. Merry 	}
2190991554f2SKenneth D. Merry 
2191991554f2SKenneth D. Merry 	if ((cm->cm_flags & MPR_CM_FLAGS_ERROR_MASK) != 0) {
2192991554f2SKenneth D. Merry 		/*
2193991554f2SKenneth D. Merry 		 * We ran into an error after we tried to map the command,
2194991554f2SKenneth D. Merry 		 * so we're getting a callback without queueing the command
2195991554f2SKenneth D. Merry 		 * to the hardware.  So we set the status here, and it will
2196991554f2SKenneth D. Merry 		 * be retained below.  We'll go through the "fast path",
2197991554f2SKenneth D. Merry 		 * because there can be no reply when we haven't actually
2198991554f2SKenneth D. Merry 		 * gone out to the hardware.
2199991554f2SKenneth D. Merry 		 */
2200991554f2SKenneth D. Merry 		ccb->ccb_h.status = CAM_REQUEUE_REQ;
2201991554f2SKenneth D. Merry 
2202991554f2SKenneth D. Merry 		/*
2203991554f2SKenneth D. Merry 		 * Currently the only error included in the mask is
2204991554f2SKenneth D. Merry 		 * MPR_CM_FLAGS_CHAIN_FAILED, which means we're out of
2205991554f2SKenneth D. Merry 		 * chain frames.  We need to freeze the queue until we get
2206991554f2SKenneth D. Merry 		 * a command that completed without this error, which will
2207991554f2SKenneth D. Merry 		 * hopefully have some chain frames attached that we can
2208991554f2SKenneth D. Merry 		 * use.  If we wanted to get smarter about it, we would
2209991554f2SKenneth D. Merry 		 * only unfreeze the queue in this condition when we're
2210991554f2SKenneth D. Merry 		 * sure that we're getting some chain frames back.  That's
2211991554f2SKenneth D. Merry 		 * probably unnecessary.
2212991554f2SKenneth D. Merry 		 */
2213991554f2SKenneth D. Merry 		if ((sassc->flags & MPRSAS_QUEUE_FROZEN) == 0) {
2214991554f2SKenneth D. Merry 			xpt_freeze_simq(sassc->sim, 1);
2215991554f2SKenneth D. Merry 			sassc->flags |= MPRSAS_QUEUE_FROZEN;
2216991554f2SKenneth D. Merry 			mpr_dprint(sc, MPR_INFO, "Error sending command, "
2217991554f2SKenneth D. Merry 				   "freezing SIM queue\n");
2218991554f2SKenneth D. Merry 		}
2219991554f2SKenneth D. Merry 	}
2220991554f2SKenneth D. Merry 
2221991554f2SKenneth D. Merry 	/*
2222991554f2SKenneth D. Merry 	 * If this is a Start Stop Unit command and it was issued by the driver
2223991554f2SKenneth D. Merry 	 * during shutdown, decrement the refcount to account for all of the
2224991554f2SKenneth D. Merry 	 * commands that were sent.  All SSU commands should be completed before
2225991554f2SKenneth D. Merry 	 * shutdown completes, meaning SSU_refcount will be 0 after SSU_started
2226991554f2SKenneth D. Merry 	 * is TRUE.
2227991554f2SKenneth D. Merry 	 */
2228991554f2SKenneth D. Merry 	if (sc->SSU_started && (csio->cdb_io.cdb_bytes[0] == START_STOP_UNIT)) {
2229991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_INFO, "Decrementing SSU count.\n");
2230991554f2SKenneth D. Merry 		sc->SSU_refcount--;
2231991554f2SKenneth D. Merry 	}
2232991554f2SKenneth D. Merry 
2233991554f2SKenneth D. Merry 	/* Take the fast path to completion */
2234991554f2SKenneth D. Merry 	if (cm->cm_reply == NULL) {
2235991554f2SKenneth D. Merry 		if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INPROG) {
2236991554f2SKenneth D. Merry 			if ((sc->mpr_flags & MPR_FLAGS_DIAGRESET) != 0)
2237991554f2SKenneth D. Merry 				ccb->ccb_h.status = CAM_SCSI_BUS_RESET;
2238991554f2SKenneth D. Merry 			else {
2239991554f2SKenneth D. Merry 				ccb->ccb_h.status = CAM_REQ_CMP;
2240991554f2SKenneth D. Merry 				ccb->csio.scsi_status = SCSI_STATUS_OK;
2241991554f2SKenneth D. Merry 			}
2242991554f2SKenneth D. Merry 			if (sassc->flags & MPRSAS_QUEUE_FROZEN) {
2243991554f2SKenneth D. Merry 				ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
2244991554f2SKenneth D. Merry 				sassc->flags &= ~MPRSAS_QUEUE_FROZEN;
2245991554f2SKenneth D. Merry 				mpr_dprint(sc, MPR_XINFO,
2246991554f2SKenneth D. Merry 				    "Unfreezing SIM queue\n");
2247991554f2SKenneth D. Merry 			}
2248991554f2SKenneth D. Merry 		}
2249991554f2SKenneth D. Merry 
2250991554f2SKenneth D. Merry 		/*
2251991554f2SKenneth D. Merry 		 * There are two scenarios where the status won't be
2252991554f2SKenneth D. Merry 		 * CAM_REQ_CMP.  The first is if MPR_CM_FLAGS_ERROR_MASK is
2253991554f2SKenneth D. Merry 		 * set, the second is in the MPR_FLAGS_DIAGRESET above.
2254991554f2SKenneth D. Merry 		 */
2255991554f2SKenneth D. Merry 		if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
2256991554f2SKenneth D. Merry 			/*
2257991554f2SKenneth D. Merry 			 * Freeze the dev queue so that commands are
2258991554f2SKenneth D. Merry 			 * executed in the correct order with after error
2259991554f2SKenneth D. Merry 			 * recovery.
2260991554f2SKenneth D. Merry 			 */
2261991554f2SKenneth D. Merry 			ccb->ccb_h.status |= CAM_DEV_QFRZN;
2262991554f2SKenneth D. Merry 			xpt_freeze_devq(ccb->ccb_h.path, /*count*/ 1);
2263991554f2SKenneth D. Merry 		}
2264991554f2SKenneth D. Merry 		mpr_free_command(sc, cm);
2265991554f2SKenneth D. Merry 		xpt_done(ccb);
2266991554f2SKenneth D. Merry 		return;
2267991554f2SKenneth D. Merry 	}
2268991554f2SKenneth D. Merry 
2269991554f2SKenneth D. Merry 	mprsas_log_command(cm, MPR_XINFO,
2270991554f2SKenneth D. Merry 	    "ioc %x scsi %x state %x xfer %u\n",
2271991554f2SKenneth D. Merry 	    le16toh(rep->IOCStatus), rep->SCSIStatus, rep->SCSIState,
2272991554f2SKenneth D. Merry 	    le32toh(rep->TransferCount));
2273991554f2SKenneth D. Merry 
2274991554f2SKenneth D. Merry 	switch (le16toh(rep->IOCStatus) & MPI2_IOCSTATUS_MASK) {
2275991554f2SKenneth D. Merry 	case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN:
2276991554f2SKenneth D. Merry 		csio->resid = cm->cm_length - le32toh(rep->TransferCount);
2277991554f2SKenneth D. Merry 		/* FALLTHROUGH */
2278991554f2SKenneth D. Merry 	case MPI2_IOCSTATUS_SUCCESS:
2279991554f2SKenneth D. Merry 	case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR:
2280991554f2SKenneth D. Merry 
2281991554f2SKenneth D. Merry 		if ((le16toh(rep->IOCStatus) & MPI2_IOCSTATUS_MASK) ==
2282991554f2SKenneth D. Merry 		    MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR)
2283991554f2SKenneth D. Merry 			mprsas_log_command(cm, MPR_XINFO, "recovered error\n");
2284991554f2SKenneth D. Merry 
2285991554f2SKenneth D. Merry 		/* Completion failed at the transport level. */
2286991554f2SKenneth D. Merry 		if (rep->SCSIState & (MPI2_SCSI_STATE_NO_SCSI_STATUS |
2287991554f2SKenneth D. Merry 		    MPI2_SCSI_STATE_TERMINATED)) {
2288991554f2SKenneth D. Merry 			ccb->ccb_h.status = CAM_REQ_CMP_ERR;
2289991554f2SKenneth D. Merry 			break;
2290991554f2SKenneth D. Merry 		}
2291991554f2SKenneth D. Merry 
2292991554f2SKenneth D. Merry 		/* In a modern packetized environment, an autosense failure
2293991554f2SKenneth D. Merry 		 * implies that there's not much else that can be done to
2294991554f2SKenneth D. Merry 		 * recover the command.
2295991554f2SKenneth D. Merry 		 */
2296991554f2SKenneth D. Merry 		if (rep->SCSIState & MPI2_SCSI_STATE_AUTOSENSE_FAILED) {
2297991554f2SKenneth D. Merry 			ccb->ccb_h.status = CAM_AUTOSENSE_FAIL;
2298991554f2SKenneth D. Merry 			break;
2299991554f2SKenneth D. Merry 		}
2300991554f2SKenneth D. Merry 
2301991554f2SKenneth D. Merry 		/*
2302991554f2SKenneth D. Merry 		 * CAM doesn't care about SAS Response Info data, but if this is
2303991554f2SKenneth D. Merry 		 * the state check if TLR should be done.  If not, clear the
2304991554f2SKenneth D. Merry 		 * TLR_bits for the target.
2305991554f2SKenneth D. Merry 		 */
2306991554f2SKenneth D. Merry 		if ((rep->SCSIState & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) &&
2307991554f2SKenneth D. Merry 		    ((le32toh(rep->ResponseInfo) & MPI2_SCSI_RI_MASK_REASONCODE)
2308991554f2SKenneth D. Merry 		    == MPR_SCSI_RI_INVALID_FRAME)) {
2309991554f2SKenneth D. Merry 			sc->mapping_table[csio->ccb_h.target_id].TLR_bits =
2310991554f2SKenneth D. Merry 			    (u8)MPI2_SCSIIO_CONTROL_NO_TLR;
2311991554f2SKenneth D. Merry 		}
2312991554f2SKenneth D. Merry 
2313991554f2SKenneth D. Merry 		/*
2314991554f2SKenneth D. Merry 		 * Intentionally override the normal SCSI status reporting
2315991554f2SKenneth D. Merry 		 * for these two cases.  These are likely to happen in a
2316991554f2SKenneth D. Merry 		 * multi-initiator environment, and we want to make sure that
2317991554f2SKenneth D. Merry 		 * CAM retries these commands rather than fail them.
2318991554f2SKenneth D. Merry 		 */
2319991554f2SKenneth D. Merry 		if ((rep->SCSIStatus == MPI2_SCSI_STATUS_COMMAND_TERMINATED) ||
2320991554f2SKenneth D. Merry 		    (rep->SCSIStatus == MPI2_SCSI_STATUS_TASK_ABORTED)) {
2321991554f2SKenneth D. Merry 			ccb->ccb_h.status = CAM_REQ_ABORTED;
2322991554f2SKenneth D. Merry 			break;
2323991554f2SKenneth D. Merry 		}
2324991554f2SKenneth D. Merry 
2325991554f2SKenneth D. Merry 		/* Handle normal status and sense */
2326991554f2SKenneth D. Merry 		csio->scsi_status = rep->SCSIStatus;
2327991554f2SKenneth D. Merry 		if (rep->SCSIStatus == MPI2_SCSI_STATUS_GOOD)
2328991554f2SKenneth D. Merry 			ccb->ccb_h.status = CAM_REQ_CMP;
2329991554f2SKenneth D. Merry 		else
2330991554f2SKenneth D. Merry 			ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR;
2331991554f2SKenneth D. Merry 
2332991554f2SKenneth D. Merry 		if (rep->SCSIState & MPI2_SCSI_STATE_AUTOSENSE_VALID) {
2333991554f2SKenneth D. Merry 			int sense_len, returned_sense_len;
2334991554f2SKenneth D. Merry 
2335991554f2SKenneth D. Merry 			returned_sense_len = min(le32toh(rep->SenseCount),
2336991554f2SKenneth D. Merry 			    sizeof(struct scsi_sense_data));
2337991554f2SKenneth D. Merry 			if (returned_sense_len < csio->sense_len)
2338991554f2SKenneth D. Merry 				csio->sense_resid = csio->sense_len -
2339991554f2SKenneth D. Merry 				    returned_sense_len;
2340991554f2SKenneth D. Merry 			else
2341991554f2SKenneth D. Merry 				csio->sense_resid = 0;
2342991554f2SKenneth D. Merry 
2343991554f2SKenneth D. Merry 			sense_len = min(returned_sense_len,
2344991554f2SKenneth D. Merry 			    csio->sense_len - csio->sense_resid);
2345991554f2SKenneth D. Merry 			bzero(&csio->sense_data, sizeof(csio->sense_data));
2346991554f2SKenneth D. Merry 			bcopy(cm->cm_sense, &csio->sense_data, sense_len);
2347991554f2SKenneth D. Merry 			ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
2348991554f2SKenneth D. Merry 		}
2349991554f2SKenneth D. Merry 
2350991554f2SKenneth D. Merry 		/*
2351991554f2SKenneth D. Merry 		 * Check if this is an INQUIRY command.  If it's a VPD inquiry,
2352991554f2SKenneth D. Merry 		 * and it's page code 0 (Supported Page List), and there is
2353991554f2SKenneth D. Merry 		 * inquiry data, and this is for a sequential access device, and
2354991554f2SKenneth D. Merry 		 * the device is an SSP target, and TLR is supported by the
2355991554f2SKenneth D. Merry 		 * controller, turn the TLR_bits value ON if page 0x90 is
2356991554f2SKenneth D. Merry 		 * supported.
2357991554f2SKenneth D. Merry 		 */
2358991554f2SKenneth D. Merry 		if ((csio->cdb_io.cdb_bytes[0] == INQUIRY) &&
2359991554f2SKenneth D. Merry 		    (csio->cdb_io.cdb_bytes[1] & SI_EVPD) &&
2360991554f2SKenneth D. Merry 		    (csio->cdb_io.cdb_bytes[2] == SVPD_SUPPORTED_PAGE_LIST) &&
2361991554f2SKenneth D. Merry 		    ((csio->ccb_h.flags & CAM_DATA_MASK) == CAM_DATA_VADDR) &&
2362d2b4e18bSKenneth D. Merry 		    (csio->data_ptr != NULL) &&
2363d2b4e18bSKenneth D. Merry 		    ((csio->data_ptr[0] & 0x1f) == T_SEQUENTIAL) &&
2364d2b4e18bSKenneth D. Merry 		    (sc->control_TLR) &&
2365991554f2SKenneth D. Merry 		    (sc->mapping_table[csio->ccb_h.target_id].device_info &
2366991554f2SKenneth D. Merry 		    MPI2_SAS_DEVICE_INFO_SSP_TARGET)) {
2367991554f2SKenneth D. Merry 			vpd_list = (struct scsi_vpd_supported_page_list *)
2368991554f2SKenneth D. Merry 			    csio->data_ptr;
2369991554f2SKenneth D. Merry 			TLR_bits = &sc->mapping_table[csio->ccb_h.target_id].
2370991554f2SKenneth D. Merry 			    TLR_bits;
2371991554f2SKenneth D. Merry 			*TLR_bits = (u8)MPI2_SCSIIO_CONTROL_NO_TLR;
2372991554f2SKenneth D. Merry 			TLR_on = (u8)MPI2_SCSIIO_CONTROL_TLR_ON;
2373991554f2SKenneth D. Merry 			alloc_len = ((u16)csio->cdb_io.cdb_bytes[3] << 8) +
2374991554f2SKenneth D. Merry 			    csio->cdb_io.cdb_bytes[4];
2375d2b4e18bSKenneth D. Merry 			alloc_len -= csio->resid;
2376991554f2SKenneth D. Merry 			for (i = 0; i < MIN(vpd_list->length, alloc_len); i++) {
2377991554f2SKenneth D. Merry 				if (vpd_list->list[i] == 0x90) {
2378991554f2SKenneth D. Merry 					*TLR_bits = TLR_on;
2379991554f2SKenneth D. Merry 					break;
2380991554f2SKenneth D. Merry 				}
2381991554f2SKenneth D. Merry 			}
2382991554f2SKenneth D. Merry 		}
2383991554f2SKenneth D. Merry 		break;
2384991554f2SKenneth D. Merry 	case MPI2_IOCSTATUS_SCSI_INVALID_DEVHANDLE:
2385991554f2SKenneth D. Merry 	case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
2386991554f2SKenneth D. Merry 		/*
2387991554f2SKenneth D. Merry 		 * If devinfo is 0 this will be a volume.  In that case don't
2388991554f2SKenneth D. Merry 		 * tell CAM that the volume is not there.  We want volumes to
2389991554f2SKenneth D. Merry 		 * be enumerated until they are deleted/removed, not just
2390991554f2SKenneth D. Merry 		 * failed.
2391991554f2SKenneth D. Merry 		 */
2392991554f2SKenneth D. Merry 		if (cm->cm_targ->devinfo == 0)
2393991554f2SKenneth D. Merry 			ccb->ccb_h.status = CAM_REQ_CMP;
2394991554f2SKenneth D. Merry 		else
2395991554f2SKenneth D. Merry 			ccb->ccb_h.status = CAM_DEV_NOT_THERE;
2396991554f2SKenneth D. Merry 		break;
2397991554f2SKenneth D. Merry 	case MPI2_IOCSTATUS_INVALID_SGL:
2398991554f2SKenneth D. Merry 		mpr_print_scsiio_cmd(sc, cm);
2399991554f2SKenneth D. Merry 		ccb->ccb_h.status = CAM_UNREC_HBA_ERROR;
2400991554f2SKenneth D. Merry 		break;
2401991554f2SKenneth D. Merry 	case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED:
2402991554f2SKenneth D. Merry 		/*
2403991554f2SKenneth D. Merry 		 * This is one of the responses that comes back when an I/O
2404991554f2SKenneth D. Merry 		 * has been aborted.  If it is because of a timeout that we
2405991554f2SKenneth D. Merry 		 * initiated, just set the status to CAM_CMD_TIMEOUT.
2406991554f2SKenneth D. Merry 		 * Otherwise set it to CAM_REQ_ABORTED.  The effect on the
2407991554f2SKenneth D. Merry 		 * command is the same (it gets retried, subject to the
2408991554f2SKenneth D. Merry 		 * retry counter), the only difference is what gets printed
2409991554f2SKenneth D. Merry 		 * on the console.
2410991554f2SKenneth D. Merry 		 */
2411991554f2SKenneth D. Merry 		if (cm->cm_state == MPR_CM_STATE_TIMEDOUT)
2412991554f2SKenneth D. Merry 			ccb->ccb_h.status = CAM_CMD_TIMEOUT;
2413991554f2SKenneth D. Merry 		else
2414991554f2SKenneth D. Merry 			ccb->ccb_h.status = CAM_REQ_ABORTED;
2415991554f2SKenneth D. Merry 		break;
2416991554f2SKenneth D. Merry 	case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN:
2417991554f2SKenneth D. Merry 		/* resid is ignored for this condition */
2418991554f2SKenneth D. Merry 		csio->resid = 0;
2419991554f2SKenneth D. Merry 		ccb->ccb_h.status = CAM_DATA_RUN_ERR;
2420991554f2SKenneth D. Merry 		break;
2421991554f2SKenneth D. Merry 	case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED:
2422991554f2SKenneth D. Merry 	case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED:
2423991554f2SKenneth D. Merry 		/*
2424991554f2SKenneth D. Merry 		 * Since these are generally external (i.e. hopefully
2425991554f2SKenneth D. Merry 		 * transient transport-related) errors, retry these without
2426991554f2SKenneth D. Merry 		 * decrementing the retry count.
2427991554f2SKenneth D. Merry 		 */
2428991554f2SKenneth D. Merry 		ccb->ccb_h.status = CAM_REQUEUE_REQ;
2429991554f2SKenneth D. Merry 		mprsas_log_command(cm, MPR_INFO,
2430991554f2SKenneth D. Merry 		    "terminated ioc %x scsi %x state %x xfer %u\n",
2431991554f2SKenneth D. Merry 		    le16toh(rep->IOCStatus), rep->SCSIStatus, rep->SCSIState,
2432991554f2SKenneth D. Merry 		    le32toh(rep->TransferCount));
2433991554f2SKenneth D. Merry 		break;
2434991554f2SKenneth D. Merry 	case MPI2_IOCSTATUS_INVALID_FUNCTION:
2435991554f2SKenneth D. Merry 	case MPI2_IOCSTATUS_INTERNAL_ERROR:
2436991554f2SKenneth D. Merry 	case MPI2_IOCSTATUS_INVALID_VPID:
2437991554f2SKenneth D. Merry 	case MPI2_IOCSTATUS_INVALID_FIELD:
2438991554f2SKenneth D. Merry 	case MPI2_IOCSTATUS_INVALID_STATE:
2439991554f2SKenneth D. Merry 	case MPI2_IOCSTATUS_OP_STATE_NOT_SUPPORTED:
2440991554f2SKenneth D. Merry 	case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR:
2441991554f2SKenneth D. Merry 	case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR:
2442991554f2SKenneth D. Merry 	case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
2443991554f2SKenneth D. Merry 	case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
2444991554f2SKenneth D. Merry 	default:
2445991554f2SKenneth D. Merry 		mprsas_log_command(cm, MPR_XINFO,
2446991554f2SKenneth D. Merry 		    "completed ioc %x scsi %x state %x xfer %u\n",
2447991554f2SKenneth D. Merry 		    le16toh(rep->IOCStatus), rep->SCSIStatus, rep->SCSIState,
2448991554f2SKenneth D. Merry 		    le32toh(rep->TransferCount));
2449991554f2SKenneth D. Merry 		csio->resid = cm->cm_length;
2450991554f2SKenneth D. Merry 		ccb->ccb_h.status = CAM_REQ_CMP_ERR;
2451991554f2SKenneth D. Merry 		break;
2452991554f2SKenneth D. Merry 	}
2453991554f2SKenneth D. Merry 
2454991554f2SKenneth D. Merry 	mpr_sc_failed_io_info(sc, csio, rep, cm->cm_targ);
2455991554f2SKenneth D. Merry 
2456991554f2SKenneth D. Merry 	if (sassc->flags & MPRSAS_QUEUE_FROZEN) {
2457991554f2SKenneth D. Merry 		ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
2458991554f2SKenneth D. Merry 		sassc->flags &= ~MPRSAS_QUEUE_FROZEN;
2459991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_XINFO, "Command completed, unfreezing SIM "
2460991554f2SKenneth D. Merry 		    "queue\n");
2461991554f2SKenneth D. Merry 	}
2462991554f2SKenneth D. Merry 
2463991554f2SKenneth D. Merry 	if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
2464991554f2SKenneth D. Merry 		ccb->ccb_h.status |= CAM_DEV_QFRZN;
2465991554f2SKenneth D. Merry 		xpt_freeze_devq(ccb->ccb_h.path, /*count*/ 1);
2466991554f2SKenneth D. Merry 	}
2467991554f2SKenneth D. Merry 
2468991554f2SKenneth D. Merry 	mpr_free_command(sc, cm);
2469991554f2SKenneth D. Merry 	xpt_done(ccb);
2470991554f2SKenneth D. Merry }
2471991554f2SKenneth D. Merry 
2472991554f2SKenneth D. Merry #if __FreeBSD_version >= 900026
2473991554f2SKenneth D. Merry static void
2474991554f2SKenneth D. Merry mprsas_smpio_complete(struct mpr_softc *sc, struct mpr_command *cm)
2475991554f2SKenneth D. Merry {
2476991554f2SKenneth D. Merry 	MPI2_SMP_PASSTHROUGH_REPLY *rpl;
2477991554f2SKenneth D. Merry 	MPI2_SMP_PASSTHROUGH_REQUEST *req;
2478991554f2SKenneth D. Merry 	uint64_t sasaddr;
2479991554f2SKenneth D. Merry 	union ccb *ccb;
2480991554f2SKenneth D. Merry 
2481991554f2SKenneth D. Merry 	ccb = cm->cm_complete_data;
2482991554f2SKenneth D. Merry 
2483991554f2SKenneth D. Merry 	/*
2484991554f2SKenneth D. Merry 	 * Currently there should be no way we can hit this case.  It only
2485991554f2SKenneth D. Merry 	 * happens when we have a failure to allocate chain frames, and SMP
2486991554f2SKenneth D. Merry 	 * commands require two S/G elements only.  That should be handled
2487991554f2SKenneth D. Merry 	 * in the standard request size.
2488991554f2SKenneth D. Merry 	 */
2489991554f2SKenneth D. Merry 	if ((cm->cm_flags & MPR_CM_FLAGS_ERROR_MASK) != 0) {
2490991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_ERROR,"%s: cm_flags = %#x on SMP request!\n",
2491991554f2SKenneth D. Merry 		    __func__, cm->cm_flags);
2492991554f2SKenneth D. Merry 		ccb->ccb_h.status = CAM_REQ_CMP_ERR;
2493991554f2SKenneth D. Merry 		goto bailout;
2494991554f2SKenneth D. Merry         }
2495991554f2SKenneth D. Merry 
2496991554f2SKenneth D. Merry 	rpl = (MPI2_SMP_PASSTHROUGH_REPLY *)cm->cm_reply;
2497991554f2SKenneth D. Merry 	if (rpl == NULL) {
2498991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_ERROR, "%s: NULL cm_reply!\n", __func__);
2499991554f2SKenneth D. Merry 		ccb->ccb_h.status = CAM_REQ_CMP_ERR;
2500991554f2SKenneth D. Merry 		goto bailout;
2501991554f2SKenneth D. Merry 	}
2502991554f2SKenneth D. Merry 
2503991554f2SKenneth D. Merry 	req = (MPI2_SMP_PASSTHROUGH_REQUEST *)cm->cm_req;
2504991554f2SKenneth D. Merry 	sasaddr = le32toh(req->SASAddress.Low);
2505991554f2SKenneth D. Merry 	sasaddr |= ((uint64_t)(le32toh(req->SASAddress.High))) << 32;
2506991554f2SKenneth D. Merry 
2507991554f2SKenneth D. Merry 	if ((le16toh(rpl->IOCStatus) & MPI2_IOCSTATUS_MASK) !=
2508991554f2SKenneth D. Merry 	    MPI2_IOCSTATUS_SUCCESS ||
2509991554f2SKenneth D. Merry 	    rpl->SASStatus != MPI2_SASSTATUS_SUCCESS) {
2510991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_XINFO, "%s: IOCStatus %04x SASStatus %02x\n",
2511991554f2SKenneth D. Merry 		    __func__, le16toh(rpl->IOCStatus), rpl->SASStatus);
2512991554f2SKenneth D. Merry 		ccb->ccb_h.status = CAM_REQ_CMP_ERR;
2513991554f2SKenneth D. Merry 		goto bailout;
2514991554f2SKenneth D. Merry 	}
2515991554f2SKenneth D. Merry 
2516991554f2SKenneth D. Merry 	mpr_dprint(sc, MPR_XINFO, "%s: SMP request to SAS address "
2517991554f2SKenneth D. Merry 	    "%#jx completed successfully\n", __func__, (uintmax_t)sasaddr);
2518991554f2SKenneth D. Merry 
2519991554f2SKenneth D. Merry 	if (ccb->smpio.smp_response[2] == SMP_FR_ACCEPTED)
2520991554f2SKenneth D. Merry 		ccb->ccb_h.status = CAM_REQ_CMP;
2521991554f2SKenneth D. Merry 	else
2522991554f2SKenneth D. Merry 		ccb->ccb_h.status = CAM_SMP_STATUS_ERROR;
2523991554f2SKenneth D. Merry 
2524991554f2SKenneth D. Merry bailout:
2525991554f2SKenneth D. Merry 	/*
2526991554f2SKenneth D. Merry 	 * We sync in both directions because we had DMAs in the S/G list
2527991554f2SKenneth D. Merry 	 * in both directions.
2528991554f2SKenneth D. Merry 	 */
2529991554f2SKenneth D. Merry 	bus_dmamap_sync(sc->buffer_dmat, cm->cm_dmamap,
2530991554f2SKenneth D. Merry 			BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
2531991554f2SKenneth D. Merry 	bus_dmamap_unload(sc->buffer_dmat, cm->cm_dmamap);
2532991554f2SKenneth D. Merry 	mpr_free_command(sc, cm);
2533991554f2SKenneth D. Merry 	xpt_done(ccb);
2534991554f2SKenneth D. Merry }
2535991554f2SKenneth D. Merry 
2536991554f2SKenneth D. Merry static void
2537991554f2SKenneth D. Merry mprsas_send_smpcmd(struct mprsas_softc *sassc, union ccb *ccb,
2538991554f2SKenneth D. Merry     uint64_t sasaddr)
2539991554f2SKenneth D. Merry {
2540991554f2SKenneth D. Merry 	struct mpr_command *cm;
2541991554f2SKenneth D. Merry 	uint8_t *request, *response;
2542991554f2SKenneth D. Merry 	MPI2_SMP_PASSTHROUGH_REQUEST *req;
2543991554f2SKenneth D. Merry 	struct mpr_softc *sc;
2544991554f2SKenneth D. Merry 	struct sglist *sg;
2545991554f2SKenneth D. Merry 	int error;
2546991554f2SKenneth D. Merry 
2547991554f2SKenneth D. Merry 	sc = sassc->sc;
2548991554f2SKenneth D. Merry 	sg = NULL;
2549991554f2SKenneth D. Merry 	error = 0;
2550991554f2SKenneth D. Merry 
2551c503306dSKenneth D. Merry #if (__FreeBSD_version >= 1000028) || \
2552c503306dSKenneth D. Merry     ((__FreeBSD_version >= 902001) && (__FreeBSD_version < 1000000))
2553991554f2SKenneth D. Merry 	switch (ccb->ccb_h.flags & CAM_DATA_MASK) {
2554991554f2SKenneth D. Merry 	case CAM_DATA_PADDR:
2555991554f2SKenneth D. Merry 	case CAM_DATA_SG_PADDR:
2556991554f2SKenneth D. Merry 		/*
2557991554f2SKenneth D. Merry 		 * XXX We don't yet support physical addresses here.
2558991554f2SKenneth D. Merry 		 */
2559991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_ERROR, "%s: physical addresses not "
2560991554f2SKenneth D. Merry 		    "supported\n", __func__);
2561991554f2SKenneth D. Merry 		ccb->ccb_h.status = CAM_REQ_INVALID;
2562991554f2SKenneth D. Merry 		xpt_done(ccb);
2563991554f2SKenneth D. Merry 		return;
2564991554f2SKenneth D. Merry 	case CAM_DATA_SG:
2565991554f2SKenneth D. Merry 		/*
2566991554f2SKenneth D. Merry 		 * The chip does not support more than one buffer for the
2567991554f2SKenneth D. Merry 		 * request or response.
2568991554f2SKenneth D. Merry 		 */
2569991554f2SKenneth D. Merry 		if ((ccb->smpio.smp_request_sglist_cnt > 1)
2570991554f2SKenneth D. Merry 		    || (ccb->smpio.smp_response_sglist_cnt > 1)) {
2571991554f2SKenneth D. Merry 			mpr_dprint(sc, MPR_ERROR,
2572991554f2SKenneth D. Merry 			    "%s: multiple request or response buffer segments "
2573991554f2SKenneth D. Merry 			    "not supported for SMP\n", __func__);
2574991554f2SKenneth D. Merry 			ccb->ccb_h.status = CAM_REQ_INVALID;
2575991554f2SKenneth D. Merry 			xpt_done(ccb);
2576991554f2SKenneth D. Merry 			return;
2577991554f2SKenneth D. Merry 		}
2578991554f2SKenneth D. Merry 
2579991554f2SKenneth D. Merry 		/*
2580991554f2SKenneth D. Merry 		 * The CAM_SCATTER_VALID flag was originally implemented
2581991554f2SKenneth D. Merry 		 * for the XPT_SCSI_IO CCB, which only has one data pointer.
2582991554f2SKenneth D. Merry 		 * We have two.  So, just take that flag to mean that we
2583991554f2SKenneth D. Merry 		 * might have S/G lists, and look at the S/G segment count
2584991554f2SKenneth D. Merry 		 * to figure out whether that is the case for each individual
2585991554f2SKenneth D. Merry 		 * buffer.
2586991554f2SKenneth D. Merry 		 */
2587991554f2SKenneth D. Merry 		if (ccb->smpio.smp_request_sglist_cnt != 0) {
2588991554f2SKenneth D. Merry 			bus_dma_segment_t *req_sg;
2589991554f2SKenneth D. Merry 
2590991554f2SKenneth D. Merry 			req_sg = (bus_dma_segment_t *)ccb->smpio.smp_request;
2591991554f2SKenneth D. Merry 			request = (uint8_t *)(uintptr_t)req_sg[0].ds_addr;
2592991554f2SKenneth D. Merry 		} else
2593991554f2SKenneth D. Merry 			request = ccb->smpio.smp_request;
2594991554f2SKenneth D. Merry 
2595991554f2SKenneth D. Merry 		if (ccb->smpio.smp_response_sglist_cnt != 0) {
2596991554f2SKenneth D. Merry 			bus_dma_segment_t *rsp_sg;
2597991554f2SKenneth D. Merry 
2598991554f2SKenneth D. Merry 			rsp_sg = (bus_dma_segment_t *)ccb->smpio.smp_response;
2599991554f2SKenneth D. Merry 			response = (uint8_t *)(uintptr_t)rsp_sg[0].ds_addr;
2600991554f2SKenneth D. Merry 		} else
2601991554f2SKenneth D. Merry 			response = ccb->smpio.smp_response;
2602991554f2SKenneth D. Merry 		break;
2603991554f2SKenneth D. Merry 	case CAM_DATA_VADDR:
2604991554f2SKenneth D. Merry 		request = ccb->smpio.smp_request;
2605991554f2SKenneth D. Merry 		response = ccb->smpio.smp_response;
2606991554f2SKenneth D. Merry 		break;
2607991554f2SKenneth D. Merry 	default:
2608991554f2SKenneth D. Merry 		ccb->ccb_h.status = CAM_REQ_INVALID;
2609991554f2SKenneth D. Merry 		xpt_done(ccb);
2610991554f2SKenneth D. Merry 		return;
2611991554f2SKenneth D. Merry 	}
2612c503306dSKenneth D. Merry #else /* __FreeBSD_version < 1000028 */
2613991554f2SKenneth D. Merry 	/*
2614991554f2SKenneth D. Merry 	 * XXX We don't yet support physical addresses here.
2615991554f2SKenneth D. Merry 	 */
2616991554f2SKenneth D. Merry 	if (ccb->ccb_h.flags & (CAM_DATA_PHYS|CAM_SG_LIST_PHYS)) {
2617991554f2SKenneth D. Merry 		mpr_printf(sc, "%s: physical addresses not supported\n",
2618991554f2SKenneth D. Merry 			   __func__);
2619991554f2SKenneth D. Merry 		ccb->ccb_h.status = CAM_REQ_INVALID;
2620991554f2SKenneth D. Merry 		xpt_done(ccb);
2621991554f2SKenneth D. Merry 		return;
2622991554f2SKenneth D. Merry 	}
2623991554f2SKenneth D. Merry 
2624991554f2SKenneth D. Merry 	/*
2625991554f2SKenneth D. Merry 	 * If the user wants to send an S/G list, check to make sure they
2626991554f2SKenneth D. Merry 	 * have single buffers.
2627991554f2SKenneth D. Merry 	 */
2628991554f2SKenneth D. Merry 	if (ccb->ccb_h.flags & CAM_SCATTER_VALID) {
2629991554f2SKenneth D. Merry 		/*
2630991554f2SKenneth D. Merry 		 * The chip does not support more than one buffer for the
2631991554f2SKenneth D. Merry 		 * request or response.
2632991554f2SKenneth D. Merry 		 */
2633991554f2SKenneth D. Merry 	 	if ((ccb->smpio.smp_request_sglist_cnt > 1)
2634991554f2SKenneth D. Merry 		  || (ccb->smpio.smp_response_sglist_cnt > 1)) {
2635991554f2SKenneth D. Merry 			mpr_dprint(sc, MPR_ERROR, "%s: multiple request or "
2636991554f2SKenneth D. Merry 			    "response buffer segments not supported for SMP\n",
2637991554f2SKenneth D. Merry 			    __func__);
2638991554f2SKenneth D. Merry 			ccb->ccb_h.status = CAM_REQ_INVALID;
2639991554f2SKenneth D. Merry 			xpt_done(ccb);
2640991554f2SKenneth D. Merry 			return;
2641991554f2SKenneth D. Merry 		}
2642991554f2SKenneth D. Merry 
2643991554f2SKenneth D. Merry 		/*
2644991554f2SKenneth D. Merry 		 * The CAM_SCATTER_VALID flag was originally implemented
2645991554f2SKenneth D. Merry 		 * for the XPT_SCSI_IO CCB, which only has one data pointer.
2646991554f2SKenneth D. Merry 		 * We have two.  So, just take that flag to mean that we
2647991554f2SKenneth D. Merry 		 * might have S/G lists, and look at the S/G segment count
2648991554f2SKenneth D. Merry 		 * to figure out whether that is the case for each individual
2649991554f2SKenneth D. Merry 		 * buffer.
2650991554f2SKenneth D. Merry 		 */
2651991554f2SKenneth D. Merry 		if (ccb->smpio.smp_request_sglist_cnt != 0) {
2652991554f2SKenneth D. Merry 			bus_dma_segment_t *req_sg;
2653991554f2SKenneth D. Merry 
2654991554f2SKenneth D. Merry 			req_sg = (bus_dma_segment_t *)ccb->smpio.smp_request;
2655c503306dSKenneth D. Merry 			request = (uint8_t *)(uintptr_t)req_sg[0].ds_addr;
2656991554f2SKenneth D. Merry 		} else
2657991554f2SKenneth D. Merry 			request = ccb->smpio.smp_request;
2658991554f2SKenneth D. Merry 
2659991554f2SKenneth D. Merry 		if (ccb->smpio.smp_response_sglist_cnt != 0) {
2660991554f2SKenneth D. Merry 			bus_dma_segment_t *rsp_sg;
2661991554f2SKenneth D. Merry 
2662991554f2SKenneth D. Merry 			rsp_sg = (bus_dma_segment_t *)ccb->smpio.smp_response;
2663c503306dSKenneth D. Merry 			response = (uint8_t *)(uintptr_t)rsp_sg[0].ds_addr;
2664991554f2SKenneth D. Merry 		} else
2665991554f2SKenneth D. Merry 			response = ccb->smpio.smp_response;
2666991554f2SKenneth D. Merry 	} else {
2667991554f2SKenneth D. Merry 		request = ccb->smpio.smp_request;
2668991554f2SKenneth D. Merry 		response = ccb->smpio.smp_response;
2669991554f2SKenneth D. Merry 	}
2670c503306dSKenneth D. Merry #endif /* __FreeBSD_version < 1000028 */
2671991554f2SKenneth D. Merry 
2672991554f2SKenneth D. Merry 	cm = mpr_alloc_command(sc);
2673991554f2SKenneth D. Merry 	if (cm == NULL) {
2674991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_ERROR,
2675991554f2SKenneth D. Merry 		    "%s: cannot allocate command\n", __func__);
2676991554f2SKenneth D. Merry 		ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
2677991554f2SKenneth D. Merry 		xpt_done(ccb);
2678991554f2SKenneth D. Merry 		return;
2679991554f2SKenneth D. Merry 	}
2680991554f2SKenneth D. Merry 
2681991554f2SKenneth D. Merry 	req = (MPI2_SMP_PASSTHROUGH_REQUEST *)cm->cm_req;
2682991554f2SKenneth D. Merry 	bzero(req, sizeof(*req));
2683991554f2SKenneth D. Merry 	req->Function = MPI2_FUNCTION_SMP_PASSTHROUGH;
2684991554f2SKenneth D. Merry 
2685991554f2SKenneth D. Merry 	/* Allow the chip to use any route to this SAS address. */
2686991554f2SKenneth D. Merry 	req->PhysicalPort = 0xff;
2687991554f2SKenneth D. Merry 
2688991554f2SKenneth D. Merry 	req->RequestDataLength = htole16(ccb->smpio.smp_request_len);
2689991554f2SKenneth D. Merry 	req->SGLFlags =
2690991554f2SKenneth D. Merry 	    MPI2_SGLFLAGS_SYSTEM_ADDRESS_SPACE | MPI2_SGLFLAGS_SGL_TYPE_MPI;
2691991554f2SKenneth D. Merry 
2692991554f2SKenneth D. Merry 	mpr_dprint(sc, MPR_XINFO, "%s: sending SMP request to SAS address "
2693991554f2SKenneth D. Merry 	    "%#jx\n", __func__, (uintmax_t)sasaddr);
2694991554f2SKenneth D. Merry 
2695991554f2SKenneth D. Merry 	mpr_init_sge(cm, req, &req->SGL);
2696991554f2SKenneth D. Merry 
2697991554f2SKenneth D. Merry 	/*
2698991554f2SKenneth D. Merry 	 * Set up a uio to pass into mpr_map_command().  This allows us to
2699991554f2SKenneth D. Merry 	 * do one map command, and one busdma call in there.
2700991554f2SKenneth D. Merry 	 */
2701991554f2SKenneth D. Merry 	cm->cm_uio.uio_iov = cm->cm_iovec;
2702991554f2SKenneth D. Merry 	cm->cm_uio.uio_iovcnt = 2;
2703991554f2SKenneth D. Merry 	cm->cm_uio.uio_segflg = UIO_SYSSPACE;
2704991554f2SKenneth D. Merry 
2705991554f2SKenneth D. Merry 	/*
2706991554f2SKenneth D. Merry 	 * The read/write flag isn't used by busdma, but set it just in
2707991554f2SKenneth D. Merry 	 * case.  This isn't exactly accurate, either, since we're going in
2708991554f2SKenneth D. Merry 	 * both directions.
2709991554f2SKenneth D. Merry 	 */
2710991554f2SKenneth D. Merry 	cm->cm_uio.uio_rw = UIO_WRITE;
2711991554f2SKenneth D. Merry 
2712991554f2SKenneth D. Merry 	cm->cm_iovec[0].iov_base = request;
2713991554f2SKenneth D. Merry 	cm->cm_iovec[0].iov_len = le16toh(req->RequestDataLength);
2714991554f2SKenneth D. Merry 	cm->cm_iovec[1].iov_base = response;
2715991554f2SKenneth D. Merry 	cm->cm_iovec[1].iov_len = ccb->smpio.smp_response_len;
2716991554f2SKenneth D. Merry 
2717991554f2SKenneth D. Merry 	cm->cm_uio.uio_resid = cm->cm_iovec[0].iov_len +
2718991554f2SKenneth D. Merry 			       cm->cm_iovec[1].iov_len;
2719991554f2SKenneth D. Merry 
2720991554f2SKenneth D. Merry 	/*
2721991554f2SKenneth D. Merry 	 * Trigger a warning message in mpr_data_cb() for the user if we
2722991554f2SKenneth D. Merry 	 * wind up exceeding two S/G segments.  The chip expects one
2723991554f2SKenneth D. Merry 	 * segment for the request and another for the response.
2724991554f2SKenneth D. Merry 	 */
2725991554f2SKenneth D. Merry 	cm->cm_max_segs = 2;
2726991554f2SKenneth D. Merry 
2727991554f2SKenneth D. Merry 	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
2728991554f2SKenneth D. Merry 	cm->cm_complete = mprsas_smpio_complete;
2729991554f2SKenneth D. Merry 	cm->cm_complete_data = ccb;
2730991554f2SKenneth D. Merry 
2731991554f2SKenneth D. Merry 	/*
2732991554f2SKenneth D. Merry 	 * Tell the mapping code that we're using a uio, and that this is
2733991554f2SKenneth D. Merry 	 * an SMP passthrough request.  There is a little special-case
2734991554f2SKenneth D. Merry 	 * logic there (in mpr_data_cb()) to handle the bidirectional
2735991554f2SKenneth D. Merry 	 * transfer.
2736991554f2SKenneth D. Merry 	 */
2737991554f2SKenneth D. Merry 	cm->cm_flags |= MPR_CM_FLAGS_USE_UIO | MPR_CM_FLAGS_SMP_PASS |
2738991554f2SKenneth D. Merry 			MPR_CM_FLAGS_DATAIN | MPR_CM_FLAGS_DATAOUT;
2739991554f2SKenneth D. Merry 
2740991554f2SKenneth D. Merry 	/* The chip data format is little endian. */
2741991554f2SKenneth D. Merry 	req->SASAddress.High = htole32(sasaddr >> 32);
2742991554f2SKenneth D. Merry 	req->SASAddress.Low = htole32(sasaddr);
2743991554f2SKenneth D. Merry 
2744991554f2SKenneth D. Merry 	/*
2745991554f2SKenneth D. Merry 	 * XXX Note that we don't have a timeout/abort mechanism here.
2746991554f2SKenneth D. Merry 	 * From the manual, it looks like task management requests only
2747991554f2SKenneth D. Merry 	 * work for SCSI IO and SATA passthrough requests.  We may need to
2748991554f2SKenneth D. Merry 	 * have a mechanism to retry requests in the event of a chip reset
2749991554f2SKenneth D. Merry 	 * at least.  Hopefully the chip will insure that any errors short
2750991554f2SKenneth D. Merry 	 * of that are relayed back to the driver.
2751991554f2SKenneth D. Merry 	 */
2752991554f2SKenneth D. Merry 	error = mpr_map_command(sc, cm);
2753991554f2SKenneth D. Merry 	if ((error != 0) && (error != EINPROGRESS)) {
2754991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_ERROR, "%s: error %d returned from "
2755991554f2SKenneth D. Merry 		    "mpr_map_command()\n", __func__, error);
2756991554f2SKenneth D. Merry 		goto bailout_error;
2757991554f2SKenneth D. Merry 	}
2758991554f2SKenneth D. Merry 
2759991554f2SKenneth D. Merry 	return;
2760991554f2SKenneth D. Merry 
2761991554f2SKenneth D. Merry bailout_error:
2762991554f2SKenneth D. Merry 	mpr_free_command(sc, cm);
2763991554f2SKenneth D. Merry 	ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
2764991554f2SKenneth D. Merry 	xpt_done(ccb);
2765991554f2SKenneth D. Merry 	return;
2766991554f2SKenneth D. Merry }
2767991554f2SKenneth D. Merry 
2768991554f2SKenneth D. Merry static void
2769991554f2SKenneth D. Merry mprsas_action_smpio(struct mprsas_softc *sassc, union ccb *ccb)
2770991554f2SKenneth D. Merry {
2771991554f2SKenneth D. Merry 	struct mpr_softc *sc;
2772991554f2SKenneth D. Merry 	struct mprsas_target *targ;
2773991554f2SKenneth D. Merry 	uint64_t sasaddr = 0;
2774991554f2SKenneth D. Merry 
2775991554f2SKenneth D. Merry 	sc = sassc->sc;
2776991554f2SKenneth D. Merry 
2777991554f2SKenneth D. Merry 	/*
2778991554f2SKenneth D. Merry 	 * Make sure the target exists.
2779991554f2SKenneth D. Merry 	 */
2780991554f2SKenneth D. Merry 	KASSERT(ccb->ccb_h.target_id < sassc->maxtargets,
2781991554f2SKenneth D. Merry 	    ("Target %d out of bounds in XPT_SMP_IO\n", ccb->ccb_h.target_id));
2782991554f2SKenneth D. Merry 	targ = &sassc->targets[ccb->ccb_h.target_id];
2783991554f2SKenneth D. Merry 	if (targ->handle == 0x0) {
2784991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_ERROR, "%s: target %d does not exist!\n",
2785991554f2SKenneth D. Merry 		    __func__, ccb->ccb_h.target_id);
2786991554f2SKenneth D. Merry 		ccb->ccb_h.status = CAM_SEL_TIMEOUT;
2787991554f2SKenneth D. Merry 		xpt_done(ccb);
2788991554f2SKenneth D. Merry 		return;
2789991554f2SKenneth D. Merry 	}
2790991554f2SKenneth D. Merry 
2791991554f2SKenneth D. Merry 	/*
2792991554f2SKenneth D. Merry 	 * If this device has an embedded SMP target, we'll talk to it
2793991554f2SKenneth D. Merry 	 * directly.
2794991554f2SKenneth D. Merry 	 * figure out what the expander's address is.
2795991554f2SKenneth D. Merry 	 */
2796991554f2SKenneth D. Merry 	if ((targ->devinfo & MPI2_SAS_DEVICE_INFO_SMP_TARGET) != 0)
2797991554f2SKenneth D. Merry 		sasaddr = targ->sasaddr;
2798991554f2SKenneth D. Merry 
2799991554f2SKenneth D. Merry 	/*
2800991554f2SKenneth D. Merry 	 * If we don't have a SAS address for the expander yet, try
2801991554f2SKenneth D. Merry 	 * grabbing it from the page 0x83 information cached in the
2802991554f2SKenneth D. Merry 	 * transport layer for this target.  LSI expanders report the
2803991554f2SKenneth D. Merry 	 * expander SAS address as the port-associated SAS address in
2804991554f2SKenneth D. Merry 	 * Inquiry VPD page 0x83.  Maxim expanders don't report it in page
2805991554f2SKenneth D. Merry 	 * 0x83.
2806991554f2SKenneth D. Merry 	 *
2807991554f2SKenneth D. Merry 	 * XXX KDM disable this for now, but leave it commented out so that
2808991554f2SKenneth D. Merry 	 * it is obvious that this is another possible way to get the SAS
2809991554f2SKenneth D. Merry 	 * address.
2810991554f2SKenneth D. Merry 	 *
2811991554f2SKenneth D. Merry 	 * The parent handle method below is a little more reliable, and
2812991554f2SKenneth D. Merry 	 * the other benefit is that it works for devices other than SES
2813991554f2SKenneth D. Merry 	 * devices.  So you can send a SMP request to a da(4) device and it
2814991554f2SKenneth D. Merry 	 * will get routed to the expander that device is attached to.
2815991554f2SKenneth D. Merry 	 * (Assuming the da(4) device doesn't contain an SMP target...)
2816991554f2SKenneth D. Merry 	 */
2817991554f2SKenneth D. Merry #if 0
2818991554f2SKenneth D. Merry 	if (sasaddr == 0)
2819991554f2SKenneth D. Merry 		sasaddr = xpt_path_sas_addr(ccb->ccb_h.path);
2820991554f2SKenneth D. Merry #endif
2821991554f2SKenneth D. Merry 
2822991554f2SKenneth D. Merry 	/*
2823991554f2SKenneth D. Merry 	 * If we still don't have a SAS address for the expander, look for
2824991554f2SKenneth D. Merry 	 * the parent device of this device, which is probably the expander.
2825991554f2SKenneth D. Merry 	 */
2826991554f2SKenneth D. Merry 	if (sasaddr == 0) {
2827991554f2SKenneth D. Merry #ifdef OLD_MPR_PROBE
2828991554f2SKenneth D. Merry 		struct mprsas_target *parent_target;
2829991554f2SKenneth D. Merry #endif
2830991554f2SKenneth D. Merry 
2831991554f2SKenneth D. Merry 		if (targ->parent_handle == 0x0) {
2832991554f2SKenneth D. Merry 			mpr_dprint(sc, MPR_ERROR, "%s: handle %d does not have "
2833991554f2SKenneth D. Merry 			    "a valid parent handle!\n", __func__, targ->handle);
2834991554f2SKenneth D. Merry 			ccb->ccb_h.status = CAM_DEV_NOT_THERE;
2835991554f2SKenneth D. Merry 			goto bailout;
2836991554f2SKenneth D. Merry 		}
2837991554f2SKenneth D. Merry #ifdef OLD_MPR_PROBE
2838991554f2SKenneth D. Merry 		parent_target = mprsas_find_target_by_handle(sassc, 0,
2839991554f2SKenneth D. Merry 		    targ->parent_handle);
2840991554f2SKenneth D. Merry 
2841991554f2SKenneth D. Merry 		if (parent_target == NULL) {
2842991554f2SKenneth D. Merry 			mpr_dprint(sc, MPR_ERROR, "%s: handle %d does not have "
2843991554f2SKenneth D. Merry 			    "a valid parent target!\n", __func__, targ->handle);
2844991554f2SKenneth D. Merry 			ccb->ccb_h.status = CAM_DEV_NOT_THERE;
2845991554f2SKenneth D. Merry 			goto bailout;
2846991554f2SKenneth D. Merry 		}
2847991554f2SKenneth D. Merry 
2848991554f2SKenneth D. Merry 		if ((parent_target->devinfo &
2849991554f2SKenneth D. Merry 		     MPI2_SAS_DEVICE_INFO_SMP_TARGET) == 0) {
2850991554f2SKenneth D. Merry 			mpr_dprint(sc, MPR_ERROR, "%s: handle %d parent %d "
2851991554f2SKenneth D. Merry 			    "does not have an SMP target!\n", __func__,
2852991554f2SKenneth D. Merry 			    targ->handle, parent_target->handle);
2853991554f2SKenneth D. Merry 			ccb->ccb_h.status = CAM_DEV_NOT_THERE;
2854991554f2SKenneth D. Merry 			goto bailout;
2855991554f2SKenneth D. Merry 
2856991554f2SKenneth D. Merry 		}
2857991554f2SKenneth D. Merry 
2858991554f2SKenneth D. Merry 		sasaddr = parent_target->sasaddr;
2859991554f2SKenneth D. Merry #else /* OLD_MPR_PROBE */
2860991554f2SKenneth D. Merry 		if ((targ->parent_devinfo &
2861991554f2SKenneth D. Merry 		     MPI2_SAS_DEVICE_INFO_SMP_TARGET) == 0) {
2862991554f2SKenneth D. Merry 			mpr_dprint(sc, MPR_ERROR, "%s: handle %d parent %d "
2863991554f2SKenneth D. Merry 			    "does not have an SMP target!\n", __func__,
2864991554f2SKenneth D. Merry 			    targ->handle, targ->parent_handle);
2865991554f2SKenneth D. Merry 			ccb->ccb_h.status = CAM_DEV_NOT_THERE;
2866991554f2SKenneth D. Merry 			goto bailout;
2867991554f2SKenneth D. Merry 
2868991554f2SKenneth D. Merry 		}
2869991554f2SKenneth D. Merry 		if (targ->parent_sasaddr == 0x0) {
2870991554f2SKenneth D. Merry 			mpr_dprint(sc, MPR_ERROR, "%s: handle %d parent handle "
2871991554f2SKenneth D. Merry 			    "%d does not have a valid SAS address!\n", __func__,
2872991554f2SKenneth D. Merry 			    targ->handle, targ->parent_handle);
2873991554f2SKenneth D. Merry 			ccb->ccb_h.status = CAM_DEV_NOT_THERE;
2874991554f2SKenneth D. Merry 			goto bailout;
2875991554f2SKenneth D. Merry 		}
2876991554f2SKenneth D. Merry 
2877991554f2SKenneth D. Merry 		sasaddr = targ->parent_sasaddr;
2878991554f2SKenneth D. Merry #endif /* OLD_MPR_PROBE */
2879991554f2SKenneth D. Merry 
2880991554f2SKenneth D. Merry 	}
2881991554f2SKenneth D. Merry 
2882991554f2SKenneth D. Merry 	if (sasaddr == 0) {
2883991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_INFO, "%s: unable to find SAS address for "
2884991554f2SKenneth D. Merry 		    "handle %d\n", __func__, targ->handle);
2885991554f2SKenneth D. Merry 		ccb->ccb_h.status = CAM_DEV_NOT_THERE;
2886991554f2SKenneth D. Merry 		goto bailout;
2887991554f2SKenneth D. Merry 	}
2888991554f2SKenneth D. Merry 	mprsas_send_smpcmd(sassc, ccb, sasaddr);
2889991554f2SKenneth D. Merry 
2890991554f2SKenneth D. Merry 	return;
2891991554f2SKenneth D. Merry 
2892991554f2SKenneth D. Merry bailout:
2893991554f2SKenneth D. Merry 	xpt_done(ccb);
2894991554f2SKenneth D. Merry 
2895991554f2SKenneth D. Merry }
2896991554f2SKenneth D. Merry #endif //__FreeBSD_version >= 900026
2897991554f2SKenneth D. Merry 
2898991554f2SKenneth D. Merry static void
2899991554f2SKenneth D. Merry mprsas_action_resetdev(struct mprsas_softc *sassc, union ccb *ccb)
2900991554f2SKenneth D. Merry {
2901991554f2SKenneth D. Merry 	MPI2_SCSI_TASK_MANAGE_REQUEST *req;
2902991554f2SKenneth D. Merry 	struct mpr_softc *sc;
2903991554f2SKenneth D. Merry 	struct mpr_command *tm;
2904991554f2SKenneth D. Merry 	struct mprsas_target *targ;
2905991554f2SKenneth D. Merry 
2906991554f2SKenneth D. Merry 	MPR_FUNCTRACE(sassc->sc);
2907991554f2SKenneth D. Merry 	mtx_assert(&sassc->sc->mpr_mtx, MA_OWNED);
2908991554f2SKenneth D. Merry 
2909991554f2SKenneth D. Merry 	KASSERT(ccb->ccb_h.target_id < sassc->maxtargets,
2910991554f2SKenneth D. Merry 	    ("Target %d out of bounds in XPT_RESET_DEV\n",
2911991554f2SKenneth D. Merry 	    ccb->ccb_h.target_id));
2912991554f2SKenneth D. Merry 	sc = sassc->sc;
2913991554f2SKenneth D. Merry 	tm = mpr_alloc_command(sc);
2914991554f2SKenneth D. Merry 	if (tm == NULL) {
2915991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_ERROR,
2916991554f2SKenneth D. Merry 		    "command alloc failure in mprsas_action_resetdev\n");
2917991554f2SKenneth D. Merry 		ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
2918991554f2SKenneth D. Merry 		xpt_done(ccb);
2919991554f2SKenneth D. Merry 		return;
2920991554f2SKenneth D. Merry 	}
2921991554f2SKenneth D. Merry 
2922991554f2SKenneth D. Merry 	targ = &sassc->targets[ccb->ccb_h.target_id];
2923991554f2SKenneth D. Merry 	req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req;
2924991554f2SKenneth D. Merry 	req->DevHandle = htole16(targ->handle);
2925991554f2SKenneth D. Merry 	req->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
2926991554f2SKenneth D. Merry 	req->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
2927991554f2SKenneth D. Merry 
2928991554f2SKenneth D. Merry 	/* SAS Hard Link Reset / SATA Link Reset */
2929991554f2SKenneth D. Merry 	req->MsgFlags = MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET;
2930991554f2SKenneth D. Merry 
2931991554f2SKenneth D. Merry 	tm->cm_data = NULL;
2932991554f2SKenneth D. Merry 	tm->cm_desc.HighPriority.RequestFlags =
2933991554f2SKenneth D. Merry 	    MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY;
2934991554f2SKenneth D. Merry 	tm->cm_complete = mprsas_resetdev_complete;
2935991554f2SKenneth D. Merry 	tm->cm_complete_data = ccb;
2936991554f2SKenneth D. Merry 	tm->cm_targ = targ;
2937991554f2SKenneth D. Merry 	mpr_map_command(sc, tm);
2938991554f2SKenneth D. Merry }
2939991554f2SKenneth D. Merry 
2940991554f2SKenneth D. Merry static void
2941991554f2SKenneth D. Merry mprsas_resetdev_complete(struct mpr_softc *sc, struct mpr_command *tm)
2942991554f2SKenneth D. Merry {
2943991554f2SKenneth D. Merry 	MPI2_SCSI_TASK_MANAGE_REPLY *resp;
2944991554f2SKenneth D. Merry 	union ccb *ccb;
2945991554f2SKenneth D. Merry 
2946991554f2SKenneth D. Merry 	MPR_FUNCTRACE(sc);
2947991554f2SKenneth D. Merry 	mtx_assert(&sc->mpr_mtx, MA_OWNED);
2948991554f2SKenneth D. Merry 
2949991554f2SKenneth D. Merry 	resp = (MPI2_SCSI_TASK_MANAGE_REPLY *)tm->cm_reply;
2950991554f2SKenneth D. Merry 	ccb = tm->cm_complete_data;
2951991554f2SKenneth D. Merry 
2952991554f2SKenneth D. Merry 	/*
2953991554f2SKenneth D. Merry 	 * Currently there should be no way we can hit this case.  It only
2954991554f2SKenneth D. Merry 	 * happens when we have a failure to allocate chain frames, and
2955991554f2SKenneth D. Merry 	 * task management commands don't have S/G lists.
2956991554f2SKenneth D. Merry 	 */
2957991554f2SKenneth D. Merry 	if ((tm->cm_flags & MPR_CM_FLAGS_ERROR_MASK) != 0) {
2958991554f2SKenneth D. Merry 		MPI2_SCSI_TASK_MANAGE_REQUEST *req;
2959991554f2SKenneth D. Merry 
2960991554f2SKenneth D. Merry 		req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req;
2961991554f2SKenneth D. Merry 
2962991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_ERROR, "%s: cm_flags = %#x for reset of "
2963991554f2SKenneth D. Merry 		    "handle %#04x! This should not happen!\n", __func__,
2964991554f2SKenneth D. Merry 		    tm->cm_flags, req->DevHandle);
2965991554f2SKenneth D. Merry 		ccb->ccb_h.status = CAM_REQ_CMP_ERR;
2966991554f2SKenneth D. Merry 		goto bailout;
2967991554f2SKenneth D. Merry 	}
2968991554f2SKenneth D. Merry 
2969991554f2SKenneth D. Merry 	mpr_dprint(sc, MPR_XINFO,
2970991554f2SKenneth D. Merry 	    "%s: IOCStatus = 0x%x ResponseCode = 0x%x\n", __func__,
2971991554f2SKenneth D. Merry 	    le16toh(resp->IOCStatus), le32toh(resp->ResponseCode));
2972991554f2SKenneth D. Merry 
2973991554f2SKenneth D. Merry 	if (le32toh(resp->ResponseCode) == MPI2_SCSITASKMGMT_RSP_TM_COMPLETE) {
2974991554f2SKenneth D. Merry 		ccb->ccb_h.status = CAM_REQ_CMP;
2975991554f2SKenneth D. Merry 		mprsas_announce_reset(sc, AC_SENT_BDR, tm->cm_targ->tid,
2976991554f2SKenneth D. Merry 		    CAM_LUN_WILDCARD);
2977991554f2SKenneth D. Merry 	}
2978991554f2SKenneth D. Merry 	else
2979991554f2SKenneth D. Merry 		ccb->ccb_h.status = CAM_REQ_CMP_ERR;
2980991554f2SKenneth D. Merry 
2981991554f2SKenneth D. Merry bailout:
2982991554f2SKenneth D. Merry 
2983991554f2SKenneth D. Merry 	mprsas_free_tm(sc, tm);
2984991554f2SKenneth D. Merry 	xpt_done(ccb);
2985991554f2SKenneth D. Merry }
2986991554f2SKenneth D. Merry 
2987991554f2SKenneth D. Merry static void
2988991554f2SKenneth D. Merry mprsas_poll(struct cam_sim *sim)
2989991554f2SKenneth D. Merry {
2990991554f2SKenneth D. Merry 	struct mprsas_softc *sassc;
2991991554f2SKenneth D. Merry 
2992991554f2SKenneth D. Merry 	sassc = cam_sim_softc(sim);
2993991554f2SKenneth D. Merry 
2994991554f2SKenneth D. Merry 	if (sassc->sc->mpr_debug & MPR_TRACE) {
2995991554f2SKenneth D. Merry 		/* frequent debug messages during a panic just slow
2996991554f2SKenneth D. Merry 		 * everything down too much.
2997991554f2SKenneth D. Merry 		 */
2998991554f2SKenneth D. Merry 		mpr_printf(sassc->sc, "%s clearing MPR_TRACE\n", __func__);
2999991554f2SKenneth D. Merry 		sassc->sc->mpr_debug &= ~MPR_TRACE;
3000991554f2SKenneth D. Merry 	}
3001991554f2SKenneth D. Merry 
3002991554f2SKenneth D. Merry 	mpr_intr_locked(sassc->sc);
3003991554f2SKenneth D. Merry }
3004991554f2SKenneth D. Merry 
3005991554f2SKenneth D. Merry static void
3006991554f2SKenneth D. Merry mprsas_async(void *callback_arg, uint32_t code, struct cam_path *path,
3007991554f2SKenneth D. Merry     void *arg)
3008991554f2SKenneth D. Merry {
3009991554f2SKenneth D. Merry 	struct mpr_softc *sc;
3010991554f2SKenneth D. Merry 
3011991554f2SKenneth D. Merry 	sc = (struct mpr_softc *)callback_arg;
3012991554f2SKenneth D. Merry 
3013991554f2SKenneth D. Merry 	switch (code) {
3014991554f2SKenneth D. Merry #if (__FreeBSD_version >= 1000006) || \
3015991554f2SKenneth D. Merry     ((__FreeBSD_version >= 901503) && (__FreeBSD_version < 1000000))
3016991554f2SKenneth D. Merry 	case AC_ADVINFO_CHANGED: {
3017991554f2SKenneth D. Merry 		struct mprsas_target *target;
3018991554f2SKenneth D. Merry 		struct mprsas_softc *sassc;
3019991554f2SKenneth D. Merry 		struct scsi_read_capacity_data_long rcap_buf;
3020991554f2SKenneth D. Merry 		struct ccb_dev_advinfo cdai;
3021991554f2SKenneth D. Merry 		struct mprsas_lun *lun;
3022991554f2SKenneth D. Merry 		lun_id_t lunid;
3023991554f2SKenneth D. Merry 		int found_lun;
3024991554f2SKenneth D. Merry 		uintptr_t buftype;
3025991554f2SKenneth D. Merry 
3026991554f2SKenneth D. Merry 		buftype = (uintptr_t)arg;
3027991554f2SKenneth D. Merry 
3028991554f2SKenneth D. Merry 		found_lun = 0;
3029991554f2SKenneth D. Merry 		sassc = sc->sassc;
3030991554f2SKenneth D. Merry 
3031991554f2SKenneth D. Merry 		/*
3032991554f2SKenneth D. Merry 		 * We're only interested in read capacity data changes.
3033991554f2SKenneth D. Merry 		 */
3034991554f2SKenneth D. Merry 		if (buftype != CDAI_TYPE_RCAPLONG)
3035991554f2SKenneth D. Merry 			break;
3036991554f2SKenneth D. Merry 
3037991554f2SKenneth D. Merry 		/*
303807aa4de1SKenneth D. Merry 		 * See the comment in mpr_attach_sas() for a detailed
303907aa4de1SKenneth D. Merry 		 * explanation.  In these versions of FreeBSD we register
304007aa4de1SKenneth D. Merry 		 * for all events and filter out the events that don't
304107aa4de1SKenneth D. Merry 		 * apply to us.
304207aa4de1SKenneth D. Merry 		 */
304307aa4de1SKenneth D. Merry #if (__FreeBSD_version < 1000703) || \
304407aa4de1SKenneth D. Merry     ((__FreeBSD_version >= 1100000) && (__FreeBSD_version < 1100002))
304507aa4de1SKenneth D. Merry 		if (xpt_path_path_id(path) != sassc->sim->path_id)
304607aa4de1SKenneth D. Merry 			break;
304707aa4de1SKenneth D. Merry #endif
304807aa4de1SKenneth D. Merry 
304907aa4de1SKenneth D. Merry 		/*
3050991554f2SKenneth D. Merry 		 * We should have a handle for this, but check to make sure.
3051991554f2SKenneth D. Merry 		 */
3052991554f2SKenneth D. Merry 		KASSERT(xpt_path_target_id(path) < sassc->maxtargets,
3053991554f2SKenneth D. Merry 		    ("Target %d out of bounds in mprsas_async\n",
3054991554f2SKenneth D. Merry 		    xpt_path_target_id(path)));
3055991554f2SKenneth D. Merry 		target = &sassc->targets[xpt_path_target_id(path)];
3056991554f2SKenneth D. Merry 		if (target->handle == 0)
3057991554f2SKenneth D. Merry 			break;
3058991554f2SKenneth D. Merry 
3059991554f2SKenneth D. Merry 		lunid = xpt_path_lun_id(path);
3060991554f2SKenneth D. Merry 
3061991554f2SKenneth D. Merry 		SLIST_FOREACH(lun, &target->luns, lun_link) {
3062991554f2SKenneth D. Merry 			if (lun->lun_id == lunid) {
3063991554f2SKenneth D. Merry 				found_lun = 1;
3064991554f2SKenneth D. Merry 				break;
3065991554f2SKenneth D. Merry 			}
3066991554f2SKenneth D. Merry 		}
3067991554f2SKenneth D. Merry 
3068991554f2SKenneth D. Merry 		if (found_lun == 0) {
3069991554f2SKenneth D. Merry 			lun = malloc(sizeof(struct mprsas_lun), M_MPR,
3070991554f2SKenneth D. Merry 			    M_NOWAIT | M_ZERO);
3071991554f2SKenneth D. Merry 			if (lun == NULL) {
3072991554f2SKenneth D. Merry 				mpr_dprint(sc, MPR_ERROR, "Unable to alloc "
3073991554f2SKenneth D. Merry 				    "LUN for EEDP support.\n");
3074991554f2SKenneth D. Merry 				break;
3075991554f2SKenneth D. Merry 			}
3076991554f2SKenneth D. Merry 			lun->lun_id = lunid;
3077991554f2SKenneth D. Merry 			SLIST_INSERT_HEAD(&target->luns, lun, lun_link);
3078991554f2SKenneth D. Merry 		}
3079991554f2SKenneth D. Merry 
3080991554f2SKenneth D. Merry 		bzero(&rcap_buf, sizeof(rcap_buf));
3081991554f2SKenneth D. Merry 		xpt_setup_ccb(&cdai.ccb_h, path, CAM_PRIORITY_NORMAL);
3082991554f2SKenneth D. Merry 		cdai.ccb_h.func_code = XPT_DEV_ADVINFO;
3083991554f2SKenneth D. Merry 		cdai.ccb_h.flags = CAM_DIR_IN;
3084991554f2SKenneth D. Merry 		cdai.buftype = CDAI_TYPE_RCAPLONG;
3085*e8577fb4SKenneth D. Merry #if __FreeBSD_version >= 1100061
3086*e8577fb4SKenneth D. Merry 		cdai.flags = CDAI_FLAG_NONE;
3087*e8577fb4SKenneth D. Merry #else
3088991554f2SKenneth D. Merry 		cdai.flags = 0;
3089*e8577fb4SKenneth D. Merry #endif
3090991554f2SKenneth D. Merry 		cdai.bufsiz = sizeof(rcap_buf);
3091991554f2SKenneth D. Merry 		cdai.buf = (uint8_t *)&rcap_buf;
3092991554f2SKenneth D. Merry 		xpt_action((union ccb *)&cdai);
3093991554f2SKenneth D. Merry 		if ((cdai.ccb_h.status & CAM_DEV_QFRZN) != 0)
3094991554f2SKenneth D. Merry 			cam_release_devq(cdai.ccb_h.path, 0, 0, 0, FALSE);
3095991554f2SKenneth D. Merry 
3096991554f2SKenneth D. Merry 		if (((cdai.ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP)
3097991554f2SKenneth D. Merry 		    && (rcap_buf.prot & SRC16_PROT_EN)) {
3098991554f2SKenneth D. Merry 			lun->eedp_formatted = TRUE;
3099991554f2SKenneth D. Merry 			lun->eedp_block_size = scsi_4btoul(rcap_buf.length);
3100991554f2SKenneth D. Merry 		} else {
3101991554f2SKenneth D. Merry 			lun->eedp_formatted = FALSE;
3102991554f2SKenneth D. Merry 			lun->eedp_block_size = 0;
3103991554f2SKenneth D. Merry 		}
3104991554f2SKenneth D. Merry 		break;
3105991554f2SKenneth D. Merry 	}
3106991554f2SKenneth D. Merry #endif
3107991554f2SKenneth D. Merry 	case AC_FOUND_DEVICE: {
3108991554f2SKenneth D. Merry 		struct ccb_getdev *cgd;
3109991554f2SKenneth D. Merry 
311007aa4de1SKenneth D. Merry 		/*
311107aa4de1SKenneth D. Merry 		 * See the comment in mpr_attach_sas() for a detailed
311207aa4de1SKenneth D. Merry 		 * explanation.  In these versions of FreeBSD we register
311307aa4de1SKenneth D. Merry 		 * for all events and filter out the events that don't
311407aa4de1SKenneth D. Merry 		 * apply to us.
311507aa4de1SKenneth D. Merry 		 */
311607aa4de1SKenneth D. Merry #if (__FreeBSD_version < 1000703) || \
311707aa4de1SKenneth D. Merry     ((__FreeBSD_version >= 1100000) && (__FreeBSD_version < 1100002))
311807aa4de1SKenneth D. Merry 		if (xpt_path_path_id(path) != sc->sassc->sim->path_id)
311907aa4de1SKenneth D. Merry 			break;
312007aa4de1SKenneth D. Merry #endif
312107aa4de1SKenneth D. Merry 
3122991554f2SKenneth D. Merry 		cgd = arg;
3123991554f2SKenneth D. Merry 		mprsas_prepare_ssu(sc, path, cgd);
312407aa4de1SKenneth D. Merry 
3125991554f2SKenneth D. Merry #if (__FreeBSD_version < 901503) || \
3126991554f2SKenneth D. Merry     ((__FreeBSD_version >= 1000000) && (__FreeBSD_version < 1000006))
3127991554f2SKenneth D. Merry 		mprsas_check_eedp(sc, path, cgd);
3128991554f2SKenneth D. Merry #endif
3129991554f2SKenneth D. Merry 		break;
3130991554f2SKenneth D. Merry 	}
3131991554f2SKenneth D. Merry 	default:
3132991554f2SKenneth D. Merry 		break;
3133991554f2SKenneth D. Merry 	}
3134991554f2SKenneth D. Merry }
3135991554f2SKenneth D. Merry 
3136991554f2SKenneth D. Merry static void
3137991554f2SKenneth D. Merry mprsas_prepare_ssu(struct mpr_softc *sc, struct cam_path *path,
3138991554f2SKenneth D. Merry     struct ccb_getdev *cgd)
3139991554f2SKenneth D. Merry {
3140991554f2SKenneth D. Merry 	struct mprsas_softc *sassc = sc->sassc;
3141991554f2SKenneth D. Merry 	path_id_t pathid;
3142991554f2SKenneth D. Merry 	target_id_t targetid;
3143991554f2SKenneth D. Merry 	lun_id_t lunid;
3144991554f2SKenneth D. Merry 	struct mprsas_target *target;
3145991554f2SKenneth D. Merry 	struct mprsas_lun *lun;
3146991554f2SKenneth D. Merry 	uint8_t	found_lun;
3147991554f2SKenneth D. Merry 
3148991554f2SKenneth D. Merry 	sassc = sc->sassc;
3149991554f2SKenneth D. Merry 	pathid = cam_sim_path(sassc->sim);
3150991554f2SKenneth D. Merry 	targetid = xpt_path_target_id(path);
3151991554f2SKenneth D. Merry 	lunid = xpt_path_lun_id(path);
3152991554f2SKenneth D. Merry 
3153991554f2SKenneth D. Merry 	KASSERT(targetid < sassc->maxtargets,
3154991554f2SKenneth D. Merry 	    ("Target %d out of bounds in mprsas_prepare_ssu\n", targetid));
3155991554f2SKenneth D. Merry 	target = &sassc->targets[targetid];
3156991554f2SKenneth D. Merry 	if (target->handle == 0x0)
3157991554f2SKenneth D. Merry 		return;
3158991554f2SKenneth D. Merry 
3159991554f2SKenneth D. Merry 	/*
3160991554f2SKenneth D. Merry 	 * If LUN is already in list, don't create a new one.
3161991554f2SKenneth D. Merry 	 */
3162991554f2SKenneth D. Merry 	found_lun = FALSE;
3163991554f2SKenneth D. Merry 	SLIST_FOREACH(lun, &target->luns, lun_link) {
3164991554f2SKenneth D. Merry 		if (lun->lun_id == lunid) {
3165991554f2SKenneth D. Merry 			found_lun = TRUE;
3166991554f2SKenneth D. Merry 			break;
3167991554f2SKenneth D. Merry 		}
3168991554f2SKenneth D. Merry 	}
3169991554f2SKenneth D. Merry 	if (!found_lun) {
3170991554f2SKenneth D. Merry 		lun = malloc(sizeof(struct mprsas_lun), M_MPR,
3171991554f2SKenneth D. Merry 		    M_NOWAIT | M_ZERO);
3172991554f2SKenneth D. Merry 		if (lun == NULL) {
3173991554f2SKenneth D. Merry 			mpr_dprint(sc, MPR_ERROR, "Unable to alloc LUN for "
3174991554f2SKenneth D. Merry 			    "preparing SSU.\n");
3175991554f2SKenneth D. Merry 			return;
3176991554f2SKenneth D. Merry 		}
3177991554f2SKenneth D. Merry 		lun->lun_id = lunid;
3178991554f2SKenneth D. Merry 		SLIST_INSERT_HEAD(&target->luns, lun, lun_link);
3179991554f2SKenneth D. Merry 	}
3180991554f2SKenneth D. Merry 
3181991554f2SKenneth D. Merry 	/*
3182991554f2SKenneth D. Merry 	 * If this is a SATA direct-access end device, mark it so that a SCSI
3183991554f2SKenneth D. Merry 	 * StartStopUnit command will be sent to it when the driver is being
3184991554f2SKenneth D. Merry 	 * shutdown.
3185991554f2SKenneth D. Merry 	 */
3186991554f2SKenneth D. Merry 	if (((cgd->inq_data.device & 0x1F) == T_DIRECT) &&
3187991554f2SKenneth D. Merry 	    (target->devinfo & MPI2_SAS_DEVICE_INFO_SATA_DEVICE) &&
3188991554f2SKenneth D. Merry 	    ((target->devinfo & MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) ==
3189991554f2SKenneth D. Merry 	    MPI2_SAS_DEVICE_INFO_END_DEVICE)) {
3190991554f2SKenneth D. Merry 		lun->stop_at_shutdown = TRUE;
3191991554f2SKenneth D. Merry 	}
3192991554f2SKenneth D. Merry }
3193991554f2SKenneth D. Merry 
3194991554f2SKenneth D. Merry #if (__FreeBSD_version < 901503) || \
3195991554f2SKenneth D. Merry     ((__FreeBSD_version >= 1000000) && (__FreeBSD_version < 1000006))
3196991554f2SKenneth D. Merry static void
3197991554f2SKenneth D. Merry mprsas_check_eedp(struct mpr_softc *sc, struct cam_path *path,
3198991554f2SKenneth D. Merry     struct ccb_getdev *cgd)
3199991554f2SKenneth D. Merry {
3200991554f2SKenneth D. Merry 	struct mprsas_softc *sassc = sc->sassc;
3201991554f2SKenneth D. Merry 	struct ccb_scsiio *csio;
3202991554f2SKenneth D. Merry 	struct scsi_read_capacity_16 *scsi_cmd;
3203991554f2SKenneth D. Merry 	struct scsi_read_capacity_eedp *rcap_buf;
3204991554f2SKenneth D. Merry 	path_id_t pathid;
3205991554f2SKenneth D. Merry 	target_id_t targetid;
3206991554f2SKenneth D. Merry 	lun_id_t lunid;
3207991554f2SKenneth D. Merry 	union ccb *ccb;
3208991554f2SKenneth D. Merry 	struct cam_path *local_path;
3209991554f2SKenneth D. Merry 	struct mprsas_target *target;
3210991554f2SKenneth D. Merry 	struct mprsas_lun *lun;
3211991554f2SKenneth D. Merry 	uint8_t	found_lun;
3212991554f2SKenneth D. Merry 	char path_str[64];
3213991554f2SKenneth D. Merry 
3214991554f2SKenneth D. Merry 	sassc = sc->sassc;
3215991554f2SKenneth D. Merry 	pathid = cam_sim_path(sassc->sim);
3216991554f2SKenneth D. Merry 	targetid = xpt_path_target_id(path);
3217991554f2SKenneth D. Merry 	lunid = xpt_path_lun_id(path);
3218991554f2SKenneth D. Merry 
3219991554f2SKenneth D. Merry 	KASSERT(targetid < sassc->maxtargets,
3220991554f2SKenneth D. Merry 	    ("Target %d out of bounds in mprsas_check_eedp\n", targetid));
3221991554f2SKenneth D. Merry 	target = &sassc->targets[targetid];
3222991554f2SKenneth D. Merry 	if (target->handle == 0x0)
3223991554f2SKenneth D. Merry 		return;
3224991554f2SKenneth D. Merry 
3225991554f2SKenneth D. Merry 	/*
3226991554f2SKenneth D. Merry 	 * Determine if the device is EEDP capable.
3227991554f2SKenneth D. Merry 	 *
3228991554f2SKenneth D. Merry 	 * If this flag is set in the inquiry data, the device supports
3229991554f2SKenneth D. Merry 	 * protection information, and must support the 16 byte read capacity
3230991554f2SKenneth D. Merry 	 * command, otherwise continue without sending read cap 16
3231991554f2SKenneth D. Merry 	 */
3232991554f2SKenneth D. Merry 	if ((cgd->inq_data.spc3_flags & SPC3_SID_PROTECT) == 0)
3233991554f2SKenneth D. Merry 		return;
3234991554f2SKenneth D. Merry 
3235991554f2SKenneth D. Merry 	/*
3236991554f2SKenneth D. Merry 	 * Issue a READ CAPACITY 16 command.  This info is used to determine if
3237991554f2SKenneth D. Merry 	 * the LUN is formatted for EEDP support.
3238991554f2SKenneth D. Merry 	 */
3239991554f2SKenneth D. Merry 	ccb = xpt_alloc_ccb_nowait();
3240991554f2SKenneth D. Merry 	if (ccb == NULL) {
3241991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_ERROR, "Unable to alloc CCB for EEDP "
3242991554f2SKenneth D. Merry 		    "support.\n");
3243991554f2SKenneth D. Merry 		return;
3244991554f2SKenneth D. Merry 	}
3245991554f2SKenneth D. Merry 
3246991554f2SKenneth D. Merry 	if (xpt_create_path(&local_path, xpt_periph, pathid, targetid, lunid)
3247991554f2SKenneth D. Merry 	    != CAM_REQ_CMP) {
3248991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_ERROR, "Unable to create path for EEDP "
3249991554f2SKenneth D. Merry 		    "support\n");
3250991554f2SKenneth D. Merry 		xpt_free_ccb(ccb);
3251991554f2SKenneth D. Merry 		return;
3252991554f2SKenneth D. Merry 	}
3253991554f2SKenneth D. Merry 
3254991554f2SKenneth D. Merry 	/*
3255991554f2SKenneth D. Merry 	 * If LUN is already in list, don't create a new one.
3256991554f2SKenneth D. Merry 	 */
3257991554f2SKenneth D. Merry 	found_lun = FALSE;
3258991554f2SKenneth D. Merry 	SLIST_FOREACH(lun, &target->luns, lun_link) {
3259991554f2SKenneth D. Merry 		if (lun->lun_id == lunid) {
3260991554f2SKenneth D. Merry 			found_lun = TRUE;
3261991554f2SKenneth D. Merry 			break;
3262991554f2SKenneth D. Merry 		}
3263991554f2SKenneth D. Merry 	}
3264991554f2SKenneth D. Merry 	if (!found_lun) {
3265991554f2SKenneth D. Merry 		lun = malloc(sizeof(struct mprsas_lun), M_MPR,
3266991554f2SKenneth D. Merry 		    M_NOWAIT | M_ZERO);
3267991554f2SKenneth D. Merry 		if (lun == NULL) {
3268991554f2SKenneth D. Merry 			mpr_dprint(sc, MPR_ERROR, "Unable to alloc LUN for "
3269991554f2SKenneth D. Merry 			    "EEDP support.\n");
3270991554f2SKenneth D. Merry 			xpt_free_path(local_path);
3271991554f2SKenneth D. Merry 			xpt_free_ccb(ccb);
3272991554f2SKenneth D. Merry 			return;
3273991554f2SKenneth D. Merry 		}
3274991554f2SKenneth D. Merry 		lun->lun_id = lunid;
3275991554f2SKenneth D. Merry 		SLIST_INSERT_HEAD(&target->luns, lun, lun_link);
3276991554f2SKenneth D. Merry 	}
3277991554f2SKenneth D. Merry 
3278991554f2SKenneth D. Merry 	xpt_path_string(local_path, path_str, sizeof(path_str));
3279991554f2SKenneth D. Merry 	mpr_dprint(sc, MPR_INFO, "Sending read cap: path %s handle %d\n",
3280991554f2SKenneth D. Merry 	    path_str, target->handle);
3281991554f2SKenneth D. Merry 
3282991554f2SKenneth D. Merry 	/*
3283991554f2SKenneth D. Merry 	 * Issue a READ CAPACITY 16 command for the LUN.  The
3284991554f2SKenneth D. Merry 	 * mprsas_read_cap_done function will load the read cap info into the
3285991554f2SKenneth D. Merry 	 * LUN struct.
3286991554f2SKenneth D. Merry 	 */
3287991554f2SKenneth D. Merry 	rcap_buf = malloc(sizeof(struct scsi_read_capacity_eedp), M_MPR,
3288991554f2SKenneth D. Merry 	    M_NOWAIT | M_ZERO);
3289991554f2SKenneth D. Merry 	if (rcap_buf == NULL) {
3290991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_FAULT, "Unable to alloc read capacity "
3291991554f2SKenneth D. Merry 		    "buffer for EEDP support.\n");
3292991554f2SKenneth D. Merry 		xpt_free_path(ccb->ccb_h.path);
3293991554f2SKenneth D. Merry 		xpt_free_ccb(ccb);
3294991554f2SKenneth D. Merry 		return;
3295991554f2SKenneth D. Merry 	}
3296991554f2SKenneth D. Merry 	xpt_setup_ccb(&ccb->ccb_h, local_path, CAM_PRIORITY_XPT);
3297991554f2SKenneth D. Merry 	csio = &ccb->csio;
3298991554f2SKenneth D. Merry 	csio->ccb_h.func_code = XPT_SCSI_IO;
3299991554f2SKenneth D. Merry 	csio->ccb_h.flags = CAM_DIR_IN;
3300991554f2SKenneth D. Merry 	csio->ccb_h.retry_count = 4;
3301991554f2SKenneth D. Merry 	csio->ccb_h.cbfcnp = mprsas_read_cap_done;
3302991554f2SKenneth D. Merry 	csio->ccb_h.timeout = 60000;
3303991554f2SKenneth D. Merry 	csio->data_ptr = (uint8_t *)rcap_buf;
3304991554f2SKenneth D. Merry 	csio->dxfer_len = sizeof(struct scsi_read_capacity_eedp);
3305991554f2SKenneth D. Merry 	csio->sense_len = MPR_SENSE_LEN;
3306991554f2SKenneth D. Merry 	csio->cdb_len = sizeof(*scsi_cmd);
3307991554f2SKenneth D. Merry 	csio->tag_action = MSG_SIMPLE_Q_TAG;
3308991554f2SKenneth D. Merry 
3309991554f2SKenneth D. Merry 	scsi_cmd = (struct scsi_read_capacity_16 *)&csio->cdb_io.cdb_bytes;
3310991554f2SKenneth D. Merry 	bzero(scsi_cmd, sizeof(*scsi_cmd));
3311991554f2SKenneth D. Merry 	scsi_cmd->opcode = 0x9E;
3312991554f2SKenneth D. Merry 	scsi_cmd->service_action = SRC16_SERVICE_ACTION;
3313991554f2SKenneth D. Merry 	((uint8_t *)scsi_cmd)[13] = sizeof(struct scsi_read_capacity_eedp);
3314991554f2SKenneth D. Merry 
3315991554f2SKenneth D. Merry 	ccb->ccb_h.ppriv_ptr1 = sassc;
3316991554f2SKenneth D. Merry 	xpt_action(ccb);
3317991554f2SKenneth D. Merry }
3318991554f2SKenneth D. Merry 
3319991554f2SKenneth D. Merry static void
3320991554f2SKenneth D. Merry mprsas_read_cap_done(struct cam_periph *periph, union ccb *done_ccb)
3321991554f2SKenneth D. Merry {
3322991554f2SKenneth D. Merry 	struct mprsas_softc *sassc;
3323991554f2SKenneth D. Merry 	struct mprsas_target *target;
3324991554f2SKenneth D. Merry 	struct mprsas_lun *lun;
3325991554f2SKenneth D. Merry 	struct scsi_read_capacity_eedp *rcap_buf;
3326991554f2SKenneth D. Merry 
3327991554f2SKenneth D. Merry 	if (done_ccb == NULL)
3328991554f2SKenneth D. Merry 		return;
3329991554f2SKenneth D. Merry 
3330991554f2SKenneth D. Merry 	/* Driver need to release devq, it Scsi command is
3331991554f2SKenneth D. Merry 	 * generated by driver internally.
3332991554f2SKenneth D. Merry 	 * Currently there is a single place where driver
3333991554f2SKenneth D. Merry 	 * calls scsi command internally. In future if driver
3334991554f2SKenneth D. Merry 	 * calls more scsi command internally, it needs to release
3335991554f2SKenneth D. Merry 	 * devq internally, since those command will not go back to
3336991554f2SKenneth D. Merry 	 * cam_periph.
3337991554f2SKenneth D. Merry 	 */
3338991554f2SKenneth D. Merry 	if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) ) {
3339991554f2SKenneth D. Merry         	done_ccb->ccb_h.status &= ~CAM_DEV_QFRZN;
3340991554f2SKenneth D. Merry 		xpt_release_devq(done_ccb->ccb_h.path,
3341991554f2SKenneth D. Merry 			       	/*count*/ 1, /*run_queue*/TRUE);
3342991554f2SKenneth D. Merry 	}
3343991554f2SKenneth D. Merry 
3344991554f2SKenneth D. Merry 	rcap_buf = (struct scsi_read_capacity_eedp *)done_ccb->csio.data_ptr;
3345991554f2SKenneth D. Merry 
3346991554f2SKenneth D. Merry 	/*
3347991554f2SKenneth D. Merry 	 * Get the LUN ID for the path and look it up in the LUN list for the
3348991554f2SKenneth D. Merry 	 * target.
3349991554f2SKenneth D. Merry 	 */
3350991554f2SKenneth D. Merry 	sassc = (struct mprsas_softc *)done_ccb->ccb_h.ppriv_ptr1;
3351991554f2SKenneth D. Merry 	KASSERT(done_ccb->ccb_h.target_id < sassc->maxtargets,
3352991554f2SKenneth D. Merry 	    ("Target %d out of bounds in mprsas_read_cap_done\n",
3353991554f2SKenneth D. Merry 	    done_ccb->ccb_h.target_id));
3354991554f2SKenneth D. Merry 	target = &sassc->targets[done_ccb->ccb_h.target_id];
3355991554f2SKenneth D. Merry 	SLIST_FOREACH(lun, &target->luns, lun_link) {
3356991554f2SKenneth D. Merry 		if (lun->lun_id != done_ccb->ccb_h.target_lun)
3357991554f2SKenneth D. Merry 			continue;
3358991554f2SKenneth D. Merry 
3359991554f2SKenneth D. Merry 		/*
3360991554f2SKenneth D. Merry 		 * Got the LUN in the target's LUN list.  Fill it in with EEDP
3361991554f2SKenneth D. Merry 		 * info.  If the READ CAP 16 command had some SCSI error (common
3362991554f2SKenneth D. Merry 		 * if command is not supported), mark the lun as not supporting
3363991554f2SKenneth D. Merry 		 * EEDP and set the block size to 0.
3364991554f2SKenneth D. Merry 		 */
3365991554f2SKenneth D. Merry 		if (((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)
3366991554f2SKenneth D. Merry 		    || (done_ccb->csio.scsi_status != SCSI_STATUS_OK)) {
3367991554f2SKenneth D. Merry 			lun->eedp_formatted = FALSE;
3368991554f2SKenneth D. Merry 			lun->eedp_block_size = 0;
3369991554f2SKenneth D. Merry 			break;
3370991554f2SKenneth D. Merry 		}
3371991554f2SKenneth D. Merry 
3372991554f2SKenneth D. Merry 		if (rcap_buf->protect & 0x01) {
3373991554f2SKenneth D. Merry 			mpr_dprint(sassc->sc, MPR_INFO, "LUN %d for "
3374991554f2SKenneth D. Merry 			    "target ID %d is formatted for EEDP "
3375991554f2SKenneth D. Merry 			    "support.\n", done_ccb->ccb_h.target_lun,
3376991554f2SKenneth D. Merry 			    done_ccb->ccb_h.target_id);
3377991554f2SKenneth D. Merry 			lun->eedp_formatted = TRUE;
3378991554f2SKenneth D. Merry 			lun->eedp_block_size = scsi_4btoul(rcap_buf->length);
3379991554f2SKenneth D. Merry 		}
3380991554f2SKenneth D. Merry 		break;
3381991554f2SKenneth D. Merry 	}
3382991554f2SKenneth D. Merry 
3383991554f2SKenneth D. Merry 	// Finished with this CCB and path.
3384991554f2SKenneth D. Merry 	free(rcap_buf, M_MPR);
3385991554f2SKenneth D. Merry 	xpt_free_path(done_ccb->ccb_h.path);
3386991554f2SKenneth D. Merry 	xpt_free_ccb(done_ccb);
3387991554f2SKenneth D. Merry }
3388991554f2SKenneth D. Merry #endif /* (__FreeBSD_version < 901503) || \
3389991554f2SKenneth D. Merry           ((__FreeBSD_version >= 1000000) && (__FreeBSD_version < 1000006)) */
3390991554f2SKenneth D. Merry 
3391991554f2SKenneth D. Merry int
3392991554f2SKenneth D. Merry mprsas_startup(struct mpr_softc *sc)
3393991554f2SKenneth D. Merry {
3394991554f2SKenneth D. Merry 	/*
3395991554f2SKenneth D. Merry 	 * Send the port enable message and set the wait_for_port_enable flag.
3396991554f2SKenneth D. Merry 	 * This flag helps to keep the simq frozen until all discovery events
3397991554f2SKenneth D. Merry 	 * are processed.
3398991554f2SKenneth D. Merry 	 */
3399991554f2SKenneth D. Merry 	sc->wait_for_port_enable = 1;
3400991554f2SKenneth D. Merry 	mprsas_send_portenable(sc);
3401991554f2SKenneth D. Merry 	return (0);
3402991554f2SKenneth D. Merry }
3403991554f2SKenneth D. Merry 
3404991554f2SKenneth D. Merry static int
3405991554f2SKenneth D. Merry mprsas_send_portenable(struct mpr_softc *sc)
3406991554f2SKenneth D. Merry {
3407991554f2SKenneth D. Merry 	MPI2_PORT_ENABLE_REQUEST *request;
3408991554f2SKenneth D. Merry 	struct mpr_command *cm;
3409991554f2SKenneth D. Merry 
3410991554f2SKenneth D. Merry 	MPR_FUNCTRACE(sc);
3411991554f2SKenneth D. Merry 
3412991554f2SKenneth D. Merry 	if ((cm = mpr_alloc_command(sc)) == NULL)
3413991554f2SKenneth D. Merry 		return (EBUSY);
3414991554f2SKenneth D. Merry 	request = (MPI2_PORT_ENABLE_REQUEST *)cm->cm_req;
3415991554f2SKenneth D. Merry 	request->Function = MPI2_FUNCTION_PORT_ENABLE;
3416991554f2SKenneth D. Merry 	request->MsgFlags = 0;
3417991554f2SKenneth D. Merry 	request->VP_ID = 0;
3418991554f2SKenneth D. Merry 	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
3419991554f2SKenneth D. Merry 	cm->cm_complete = mprsas_portenable_complete;
3420991554f2SKenneth D. Merry 	cm->cm_data = NULL;
3421991554f2SKenneth D. Merry 	cm->cm_sge = NULL;
3422991554f2SKenneth D. Merry 
3423991554f2SKenneth D. Merry 	mpr_map_command(sc, cm);
3424991554f2SKenneth D. Merry 	mpr_dprint(sc, MPR_XINFO,
3425991554f2SKenneth D. Merry 	    "mpr_send_portenable finished cm %p req %p complete %p\n",
3426991554f2SKenneth D. Merry 	    cm, cm->cm_req, cm->cm_complete);
3427991554f2SKenneth D. Merry 	return (0);
3428991554f2SKenneth D. Merry }
3429991554f2SKenneth D. Merry 
3430991554f2SKenneth D. Merry static void
3431991554f2SKenneth D. Merry mprsas_portenable_complete(struct mpr_softc *sc, struct mpr_command *cm)
3432991554f2SKenneth D. Merry {
3433991554f2SKenneth D. Merry 	MPI2_PORT_ENABLE_REPLY *reply;
3434991554f2SKenneth D. Merry 	struct mprsas_softc *sassc;
3435991554f2SKenneth D. Merry 
3436991554f2SKenneth D. Merry 	MPR_FUNCTRACE(sc);
3437991554f2SKenneth D. Merry 	sassc = sc->sassc;
3438991554f2SKenneth D. Merry 
3439991554f2SKenneth D. Merry 	/*
3440991554f2SKenneth D. Merry 	 * Currently there should be no way we can hit this case.  It only
3441991554f2SKenneth D. Merry 	 * happens when we have a failure to allocate chain frames, and
3442991554f2SKenneth D. Merry 	 * port enable commands don't have S/G lists.
3443991554f2SKenneth D. Merry 	 */
3444991554f2SKenneth D. Merry 	if ((cm->cm_flags & MPR_CM_FLAGS_ERROR_MASK) != 0) {
3445991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_ERROR, "%s: cm_flags = %#x for port enable! "
3446991554f2SKenneth D. Merry 		    "This should not happen!\n", __func__, cm->cm_flags);
3447991554f2SKenneth D. Merry 	}
3448991554f2SKenneth D. Merry 
3449991554f2SKenneth D. Merry 	reply = (MPI2_PORT_ENABLE_REPLY *)cm->cm_reply;
3450991554f2SKenneth D. Merry 	if (reply == NULL)
3451991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_FAULT, "Portenable NULL reply\n");
3452991554f2SKenneth D. Merry 	else if (le16toh(reply->IOCStatus & MPI2_IOCSTATUS_MASK) !=
3453991554f2SKenneth D. Merry 	    MPI2_IOCSTATUS_SUCCESS)
3454991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_FAULT, "Portenable failed\n");
3455991554f2SKenneth D. Merry 
3456991554f2SKenneth D. Merry 	mpr_free_command(sc, cm);
3457991554f2SKenneth D. Merry 	if (sc->mpr_ich.ich_arg != NULL) {
3458991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_XINFO, "disestablish config intrhook\n");
3459991554f2SKenneth D. Merry 		config_intrhook_disestablish(&sc->mpr_ich);
3460991554f2SKenneth D. Merry 		sc->mpr_ich.ich_arg = NULL;
3461991554f2SKenneth D. Merry 	}
3462991554f2SKenneth D. Merry 
3463991554f2SKenneth D. Merry 	/*
3464991554f2SKenneth D. Merry 	 * Done waiting for port enable to complete.  Decrement the refcount.
3465991554f2SKenneth D. Merry 	 * If refcount is 0, discovery is complete and a rescan of the bus can
3466991554f2SKenneth D. Merry 	 * take place.
3467991554f2SKenneth D. Merry 	 */
3468991554f2SKenneth D. Merry 	sc->wait_for_port_enable = 0;
3469991554f2SKenneth D. Merry 	sc->port_enable_complete = 1;
3470991554f2SKenneth D. Merry 	wakeup(&sc->port_enable_complete);
3471991554f2SKenneth D. Merry 	mprsas_startup_decrement(sassc);
3472991554f2SKenneth D. Merry }
3473991554f2SKenneth D. Merry 
3474991554f2SKenneth D. Merry int
3475991554f2SKenneth D. Merry mprsas_check_id(struct mprsas_softc *sassc, int id)
3476991554f2SKenneth D. Merry {
3477991554f2SKenneth D. Merry 	struct mpr_softc *sc = sassc->sc;
3478991554f2SKenneth D. Merry 	char *ids;
3479991554f2SKenneth D. Merry 	char *name;
3480991554f2SKenneth D. Merry 
3481991554f2SKenneth D. Merry 	ids = &sc->exclude_ids[0];
3482991554f2SKenneth D. Merry 	while((name = strsep(&ids, ",")) != NULL) {
3483991554f2SKenneth D. Merry 		if (name[0] == '\0')
3484991554f2SKenneth D. Merry 			continue;
3485991554f2SKenneth D. Merry 		if (strtol(name, NULL, 0) == (long)id)
3486991554f2SKenneth D. Merry 			return (1);
3487991554f2SKenneth D. Merry 	}
3488991554f2SKenneth D. Merry 
3489991554f2SKenneth D. Merry 	return (0);
3490991554f2SKenneth D. Merry }
3491