xref: /freebsd/sys/dev/mpr/mpr_sas.c (revision 991554f2c46fdbc7e9acbf87fc8da089618c3a19)
1*991554f2SKenneth D. Merry /*-
2*991554f2SKenneth D. Merry  * Copyright (c) 2009 Yahoo! Inc.
3*991554f2SKenneth D. Merry  * Copyright (c) 2011-2014 LSI Corp.
4*991554f2SKenneth D. Merry  * All rights reserved.
5*991554f2SKenneth D. Merry  *
6*991554f2SKenneth D. Merry  * Redistribution and use in source and binary forms, with or without
7*991554f2SKenneth D. Merry  * modification, are permitted provided that the following conditions
8*991554f2SKenneth D. Merry  * are met:
9*991554f2SKenneth D. Merry  * 1. Redistributions of source code must retain the above copyright
10*991554f2SKenneth D. Merry  *    notice, this list of conditions and the following disclaimer.
11*991554f2SKenneth D. Merry  * 2. Redistributions in binary form must reproduce the above copyright
12*991554f2SKenneth D. Merry  *    notice, this list of conditions and the following disclaimer in the
13*991554f2SKenneth D. Merry  *    documentation and/or other materials provided with the distribution.
14*991554f2SKenneth D. Merry  *
15*991554f2SKenneth D. Merry  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16*991554f2SKenneth D. Merry  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17*991554f2SKenneth D. Merry  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18*991554f2SKenneth D. Merry  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19*991554f2SKenneth D. Merry  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20*991554f2SKenneth D. Merry  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21*991554f2SKenneth D. Merry  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22*991554f2SKenneth D. Merry  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23*991554f2SKenneth D. Merry  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24*991554f2SKenneth D. Merry  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25*991554f2SKenneth D. Merry  * SUCH DAMAGE.
26*991554f2SKenneth D. Merry  */
27*991554f2SKenneth D. Merry 
28*991554f2SKenneth D. Merry #include <sys/cdefs.h>
29*991554f2SKenneth D. Merry __FBSDID("$FreeBSD$");
30*991554f2SKenneth D. Merry 
31*991554f2SKenneth D. Merry /* Communications core for LSI MPT2 */
32*991554f2SKenneth D. Merry 
33*991554f2SKenneth D. Merry /* TODO Move headers to mprvar */
34*991554f2SKenneth D. Merry #include <sys/types.h>
35*991554f2SKenneth D. Merry #include <sys/param.h>
36*991554f2SKenneth D. Merry #include <sys/systm.h>
37*991554f2SKenneth D. Merry #include <sys/kernel.h>
38*991554f2SKenneth D. Merry #include <sys/selinfo.h>
39*991554f2SKenneth D. Merry #include <sys/module.h>
40*991554f2SKenneth D. Merry #include <sys/bus.h>
41*991554f2SKenneth D. Merry #include <sys/conf.h>
42*991554f2SKenneth D. Merry #include <sys/bio.h>
43*991554f2SKenneth D. Merry #include <sys/malloc.h>
44*991554f2SKenneth D. Merry #include <sys/uio.h>
45*991554f2SKenneth D. Merry #include <sys/sysctl.h>
46*991554f2SKenneth D. Merry #include <sys/endian.h>
47*991554f2SKenneth D. Merry #include <sys/queue.h>
48*991554f2SKenneth D. Merry #include <sys/kthread.h>
49*991554f2SKenneth D. Merry #include <sys/taskqueue.h>
50*991554f2SKenneth D. Merry #include <sys/sbuf.h>
51*991554f2SKenneth D. Merry 
52*991554f2SKenneth D. Merry #include <machine/bus.h>
53*991554f2SKenneth D. Merry #include <machine/resource.h>
54*991554f2SKenneth D. Merry #include <sys/rman.h>
55*991554f2SKenneth D. Merry 
56*991554f2SKenneth D. Merry #include <machine/stdarg.h>
57*991554f2SKenneth D. Merry 
58*991554f2SKenneth D. Merry #include <cam/cam.h>
59*991554f2SKenneth D. Merry #include <cam/cam_ccb.h>
60*991554f2SKenneth D. Merry #include <cam/cam_debug.h>
61*991554f2SKenneth D. Merry #include <cam/cam_sim.h>
62*991554f2SKenneth D. Merry #include <cam/cam_xpt_sim.h>
63*991554f2SKenneth D. Merry #include <cam/cam_xpt_periph.h>
64*991554f2SKenneth D. Merry #include <cam/cam_periph.h>
65*991554f2SKenneth D. Merry #include <cam/scsi/scsi_all.h>
66*991554f2SKenneth D. Merry #include <cam/scsi/scsi_message.h>
67*991554f2SKenneth D. Merry #if __FreeBSD_version >= 900026
68*991554f2SKenneth D. Merry #include <cam/scsi/smp_all.h>
69*991554f2SKenneth D. Merry #endif
70*991554f2SKenneth D. Merry 
71*991554f2SKenneth D. Merry #include <dev/mpr/mpi/mpi2_type.h>
72*991554f2SKenneth D. Merry #include <dev/mpr/mpi/mpi2.h>
73*991554f2SKenneth D. Merry #include <dev/mpr/mpi/mpi2_ioc.h>
74*991554f2SKenneth D. Merry #include <dev/mpr/mpi/mpi2_sas.h>
75*991554f2SKenneth D. Merry #include <dev/mpr/mpi/mpi2_cnfg.h>
76*991554f2SKenneth D. Merry #include <dev/mpr/mpi/mpi2_init.h>
77*991554f2SKenneth D. Merry #include <dev/mpr/mpi/mpi2_tool.h>
78*991554f2SKenneth D. Merry #include <dev/mpr/mpr_ioctl.h>
79*991554f2SKenneth D. Merry #include <dev/mpr/mprvar.h>
80*991554f2SKenneth D. Merry #include <dev/mpr/mpr_table.h>
81*991554f2SKenneth D. Merry #include <dev/mpr/mpr_sas.h>
82*991554f2SKenneth D. Merry 
83*991554f2SKenneth D. Merry #define MPRSAS_DISCOVERY_TIMEOUT	20
84*991554f2SKenneth D. Merry #define MPRSAS_MAX_DISCOVERY_TIMEOUTS	10 /* 200 seconds */
85*991554f2SKenneth D. Merry 
86*991554f2SKenneth D. Merry /*
87*991554f2SKenneth D. Merry  * static array to check SCSI OpCode for EEDP protection bits
88*991554f2SKenneth D. Merry  */
89*991554f2SKenneth D. Merry #define	PRO_R MPI2_SCSIIO_EEDPFLAGS_CHECK_REMOVE_OP
90*991554f2SKenneth D. Merry #define	PRO_W MPI2_SCSIIO_EEDPFLAGS_INSERT_OP
91*991554f2SKenneth D. Merry #define	PRO_V MPI2_SCSIIO_EEDPFLAGS_INSERT_OP
92*991554f2SKenneth D. Merry static uint8_t op_code_prot[256] = {
93*991554f2SKenneth D. Merry 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
94*991554f2SKenneth D. Merry 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
95*991554f2SKenneth D. Merry 	0, 0, 0, 0, 0, 0, 0, 0, PRO_R, 0, PRO_W, 0, 0, 0, PRO_W, PRO_V,
96*991554f2SKenneth D. Merry 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
97*991554f2SKenneth D. Merry 	0, PRO_W, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
98*991554f2SKenneth D. Merry 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
99*991554f2SKenneth D. Merry 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
100*991554f2SKenneth D. Merry 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
101*991554f2SKenneth D. Merry 	0, 0, 0, 0, 0, 0, 0, 0, PRO_R, 0, PRO_W, 0, 0, 0, PRO_W, PRO_V,
102*991554f2SKenneth D. Merry 	0, 0, 0, PRO_W, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
103*991554f2SKenneth D. Merry 	0, 0, 0, 0, 0, 0, 0, 0, PRO_R, 0, PRO_W, 0, 0, 0, PRO_W, PRO_V,
104*991554f2SKenneth D. Merry 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
105*991554f2SKenneth D. Merry 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
106*991554f2SKenneth D. Merry 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
107*991554f2SKenneth D. Merry 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
108*991554f2SKenneth D. Merry 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
109*991554f2SKenneth D. Merry };
110*991554f2SKenneth D. Merry 
111*991554f2SKenneth D. Merry MALLOC_DEFINE(M_MPRSAS, "MPRSAS", "MPR SAS memory");
112*991554f2SKenneth D. Merry 
113*991554f2SKenneth D. Merry static void mprsas_remove_device(struct mpr_softc *, struct mpr_command *);
114*991554f2SKenneth D. Merry static void mprsas_remove_complete(struct mpr_softc *, struct mpr_command *);
115*991554f2SKenneth D. Merry static void mprsas_action(struct cam_sim *sim, union ccb *ccb);
116*991554f2SKenneth D. Merry static void mprsas_poll(struct cam_sim *sim);
117*991554f2SKenneth D. Merry static void mprsas_scsiio_timeout(void *data);
118*991554f2SKenneth D. Merry static void mprsas_abort_complete(struct mpr_softc *sc,
119*991554f2SKenneth D. Merry     struct mpr_command *cm);
120*991554f2SKenneth D. Merry static void mprsas_action_scsiio(struct mprsas_softc *, union ccb *);
121*991554f2SKenneth D. Merry static void mprsas_scsiio_complete(struct mpr_softc *, struct mpr_command *);
122*991554f2SKenneth D. Merry static void mprsas_action_resetdev(struct mprsas_softc *, union ccb *);
123*991554f2SKenneth D. Merry static void mprsas_resetdev_complete(struct mpr_softc *,
124*991554f2SKenneth D. Merry     struct mpr_command *);
125*991554f2SKenneth D. Merry static int  mprsas_send_abort(struct mpr_softc *sc, struct mpr_command *tm,
126*991554f2SKenneth D. Merry     struct mpr_command *cm);
127*991554f2SKenneth D. Merry static int  mprsas_send_reset(struct mpr_softc *sc, struct mpr_command *tm,
128*991554f2SKenneth D. Merry     uint8_t type);
129*991554f2SKenneth D. Merry static void mprsas_async(void *callback_arg, uint32_t code,
130*991554f2SKenneth D. Merry     struct cam_path *path, void *arg);
131*991554f2SKenneth D. Merry static void mprsas_prepare_ssu(struct mpr_softc *sc, struct cam_path *path,
132*991554f2SKenneth D. Merry     struct ccb_getdev *cgd);
133*991554f2SKenneth D. Merry #if (__FreeBSD_version < 901503) || \
134*991554f2SKenneth D. Merry     ((__FreeBSD_version >= 1000000) && (__FreeBSD_version < 1000006))
135*991554f2SKenneth D. Merry static void mprsas_check_eedp(struct mpr_softc *sc, struct cam_path *path,
136*991554f2SKenneth D. Merry     struct ccb_getdev *cgd);
137*991554f2SKenneth D. Merry static void mprsas_read_cap_done(struct cam_periph *periph,
138*991554f2SKenneth D. Merry     union ccb *done_ccb);
139*991554f2SKenneth D. Merry #endif
140*991554f2SKenneth D. Merry static int mprsas_send_portenable(struct mpr_softc *sc);
141*991554f2SKenneth D. Merry static void mprsas_portenable_complete(struct mpr_softc *sc,
142*991554f2SKenneth D. Merry     struct mpr_command *cm);
143*991554f2SKenneth D. Merry 
144*991554f2SKenneth D. Merry #if __FreeBSD_version >= 900026
145*991554f2SKenneth D. Merry static void
146*991554f2SKenneth D. Merry mprsas_smpio_complete(struct mpr_softc *sc, struct mpr_command *cm);
147*991554f2SKenneth D. Merry static void mprsas_send_smpcmd(struct mprsas_softc *sassc,
148*991554f2SKenneth D. Merry 	       	union ccb *ccb, uint64_t sasaddr);
149*991554f2SKenneth D. Merry static void
150*991554f2SKenneth D. Merry mprsas_action_smpio(struct mprsas_softc *sassc, union ccb *ccb);
151*991554f2SKenneth D. Merry #endif
152*991554f2SKenneth D. Merry 
153*991554f2SKenneth D. Merry struct mprsas_target *
154*991554f2SKenneth D. Merry mprsas_find_target_by_handle(struct mprsas_softc *sassc, int start,
155*991554f2SKenneth D. Merry     uint16_t handle)
156*991554f2SKenneth D. Merry {
157*991554f2SKenneth D. Merry 	struct mprsas_target *target;
158*991554f2SKenneth D. Merry 	int i;
159*991554f2SKenneth D. Merry 
160*991554f2SKenneth D. Merry 	for (i = start; i < sassc->maxtargets; i++) {
161*991554f2SKenneth D. Merry 		target = &sassc->targets[i];
162*991554f2SKenneth D. Merry 		if (target->handle == handle)
163*991554f2SKenneth D. Merry 			return (target);
164*991554f2SKenneth D. Merry 	}
165*991554f2SKenneth D. Merry 
166*991554f2SKenneth D. Merry 	return (NULL);
167*991554f2SKenneth D. Merry }
168*991554f2SKenneth D. Merry 
169*991554f2SKenneth D. Merry /* we need to freeze the simq during attach and diag reset, to avoid failing
170*991554f2SKenneth D. Merry  * commands before device handles have been found by discovery.  Since
171*991554f2SKenneth D. Merry  * discovery involves reading config pages and possibly sending commands,
172*991554f2SKenneth D. Merry  * discovery actions may continue even after we receive the end of discovery
173*991554f2SKenneth D. Merry  * event, so refcount discovery actions instead of assuming we can unfreeze
174*991554f2SKenneth D. Merry  * the simq when we get the event.
175*991554f2SKenneth D. Merry  */
176*991554f2SKenneth D. Merry void
177*991554f2SKenneth D. Merry mprsas_startup_increment(struct mprsas_softc *sassc)
178*991554f2SKenneth D. Merry {
179*991554f2SKenneth D. Merry 	MPR_FUNCTRACE(sassc->sc);
180*991554f2SKenneth D. Merry 
181*991554f2SKenneth D. Merry 	if ((sassc->flags & MPRSAS_IN_STARTUP) != 0) {
182*991554f2SKenneth D. Merry 		if (sassc->startup_refcount++ == 0) {
183*991554f2SKenneth D. Merry 			/* just starting, freeze the simq */
184*991554f2SKenneth D. Merry 			mpr_dprint(sassc->sc, MPR_INIT,
185*991554f2SKenneth D. Merry 			    "%s freezing simq\n", __func__);
186*991554f2SKenneth D. Merry #if __FreeBSD_version >= 1000039
187*991554f2SKenneth D. Merry 			xpt_hold_boot();
188*991554f2SKenneth D. Merry #endif
189*991554f2SKenneth D. Merry 			xpt_freeze_simq(sassc->sim, 1);
190*991554f2SKenneth D. Merry 		}
191*991554f2SKenneth D. Merry 		mpr_dprint(sassc->sc, MPR_INIT, "%s refcount %u\n", __func__,
192*991554f2SKenneth D. Merry 		    sassc->startup_refcount);
193*991554f2SKenneth D. Merry 	}
194*991554f2SKenneth D. Merry }
195*991554f2SKenneth D. Merry 
196*991554f2SKenneth D. Merry void
197*991554f2SKenneth D. Merry mprsas_release_simq_reinit(struct mprsas_softc *sassc)
198*991554f2SKenneth D. Merry {
199*991554f2SKenneth D. Merry 	if (sassc->flags & MPRSAS_QUEUE_FROZEN) {
200*991554f2SKenneth D. Merry 		sassc->flags &= ~MPRSAS_QUEUE_FROZEN;
201*991554f2SKenneth D. Merry 		xpt_release_simq(sassc->sim, 1);
202*991554f2SKenneth D. Merry 		mpr_dprint(sassc->sc, MPR_INFO, "Unfreezing SIM queue\n");
203*991554f2SKenneth D. Merry 	}
204*991554f2SKenneth D. Merry }
205*991554f2SKenneth D. Merry 
206*991554f2SKenneth D. Merry void
207*991554f2SKenneth D. Merry mprsas_startup_decrement(struct mprsas_softc *sassc)
208*991554f2SKenneth D. Merry {
209*991554f2SKenneth D. Merry 	MPR_FUNCTRACE(sassc->sc);
210*991554f2SKenneth D. Merry 
211*991554f2SKenneth D. Merry 	if ((sassc->flags & MPRSAS_IN_STARTUP) != 0) {
212*991554f2SKenneth D. Merry 		if (--sassc->startup_refcount == 0) {
213*991554f2SKenneth D. Merry 			/* finished all discovery-related actions, release
214*991554f2SKenneth D. Merry 			 * the simq and rescan for the latest topology.
215*991554f2SKenneth D. Merry 			 */
216*991554f2SKenneth D. Merry 			mpr_dprint(sassc->sc, MPR_INIT,
217*991554f2SKenneth D. Merry 			    "%s releasing simq\n", __func__);
218*991554f2SKenneth D. Merry 			sassc->flags &= ~MPRSAS_IN_STARTUP;
219*991554f2SKenneth D. Merry 			xpt_release_simq(sassc->sim, 1);
220*991554f2SKenneth D. Merry #if __FreeBSD_version >= 1000039
221*991554f2SKenneth D. Merry 			xpt_release_boot();
222*991554f2SKenneth D. Merry #else
223*991554f2SKenneth D. Merry 			mprsas_rescan_target(sassc->sc, NULL);
224*991554f2SKenneth D. Merry #endif
225*991554f2SKenneth D. Merry 		}
226*991554f2SKenneth D. Merry 		mpr_dprint(sassc->sc, MPR_INIT, "%s refcount %u\n", __func__,
227*991554f2SKenneth D. Merry 		    sassc->startup_refcount);
228*991554f2SKenneth D. Merry 	}
229*991554f2SKenneth D. Merry }
230*991554f2SKenneth D. Merry 
231*991554f2SKenneth D. Merry /* LSI's firmware requires us to stop sending commands when we're doing task
232*991554f2SKenneth D. Merry  * management, so refcount the TMs and keep the simq frozen when any are in
233*991554f2SKenneth D. Merry  * use.
234*991554f2SKenneth D. Merry  */
235*991554f2SKenneth D. Merry struct mpr_command *
236*991554f2SKenneth D. Merry mprsas_alloc_tm(struct mpr_softc *sc)
237*991554f2SKenneth D. Merry {
238*991554f2SKenneth D. Merry 	struct mpr_command *tm;
239*991554f2SKenneth D. Merry 
240*991554f2SKenneth D. Merry 	MPR_FUNCTRACE(sc);
241*991554f2SKenneth D. Merry 	tm = mpr_alloc_high_priority_command(sc);
242*991554f2SKenneth D. Merry 	if (tm != NULL) {
243*991554f2SKenneth D. Merry 		if (sc->sassc->tm_count++ == 0) {
244*991554f2SKenneth D. Merry 			mpr_dprint(sc, MPR_RECOVERY,
245*991554f2SKenneth D. Merry 			    "%s freezing simq\n", __func__);
246*991554f2SKenneth D. Merry 			xpt_freeze_simq(sc->sassc->sim, 1);
247*991554f2SKenneth D. Merry 		}
248*991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_RECOVERY, "%s tm_count %u\n", __func__,
249*991554f2SKenneth D. Merry 		    sc->sassc->tm_count);
250*991554f2SKenneth D. Merry 	}
251*991554f2SKenneth D. Merry 	return tm;
252*991554f2SKenneth D. Merry }
253*991554f2SKenneth D. Merry 
254*991554f2SKenneth D. Merry void
255*991554f2SKenneth D. Merry mprsas_free_tm(struct mpr_softc *sc, struct mpr_command *tm)
256*991554f2SKenneth D. Merry {
257*991554f2SKenneth D. Merry 	mpr_dprint(sc, MPR_TRACE, "%s", __func__);
258*991554f2SKenneth D. Merry 	if (tm == NULL)
259*991554f2SKenneth D. Merry 		return;
260*991554f2SKenneth D. Merry 
261*991554f2SKenneth D. Merry 	/* if there are no TMs in use, we can release the simq.  We use our
262*991554f2SKenneth D. Merry 	 * own refcount so that it's easier for a diag reset to cleanup and
263*991554f2SKenneth D. Merry 	 * release the simq.
264*991554f2SKenneth D. Merry 	 */
265*991554f2SKenneth D. Merry 	if (--sc->sassc->tm_count == 0) {
266*991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_RECOVERY, "%s releasing simq\n", __func__);
267*991554f2SKenneth D. Merry 		xpt_release_simq(sc->sassc->sim, 1);
268*991554f2SKenneth D. Merry 	}
269*991554f2SKenneth D. Merry 	mpr_dprint(sc, MPR_RECOVERY, "%s tm_count %u\n", __func__,
270*991554f2SKenneth D. Merry 	    sc->sassc->tm_count);
271*991554f2SKenneth D. Merry 
272*991554f2SKenneth D. Merry 	mpr_free_high_priority_command(sc, tm);
273*991554f2SKenneth D. Merry }
274*991554f2SKenneth D. Merry 
275*991554f2SKenneth D. Merry void
276*991554f2SKenneth D. Merry mprsas_rescan_target(struct mpr_softc *sc, struct mprsas_target *targ)
277*991554f2SKenneth D. Merry {
278*991554f2SKenneth D. Merry 	struct mprsas_softc *sassc = sc->sassc;
279*991554f2SKenneth D. Merry 	path_id_t pathid;
280*991554f2SKenneth D. Merry 	target_id_t targetid;
281*991554f2SKenneth D. Merry 	union ccb *ccb;
282*991554f2SKenneth D. Merry 
283*991554f2SKenneth D. Merry 	MPR_FUNCTRACE(sc);
284*991554f2SKenneth D. Merry 	pathid = cam_sim_path(sassc->sim);
285*991554f2SKenneth D. Merry 	if (targ == NULL)
286*991554f2SKenneth D. Merry 		targetid = CAM_TARGET_WILDCARD;
287*991554f2SKenneth D. Merry 	else
288*991554f2SKenneth D. Merry 		targetid = targ - sassc->targets;
289*991554f2SKenneth D. Merry 
290*991554f2SKenneth D. Merry 	/*
291*991554f2SKenneth D. Merry 	 * Allocate a CCB and schedule a rescan.
292*991554f2SKenneth D. Merry 	 */
293*991554f2SKenneth D. Merry 	ccb = xpt_alloc_ccb_nowait();
294*991554f2SKenneth D. Merry 	if (ccb == NULL) {
295*991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_ERROR, "unable to alloc CCB for rescan\n");
296*991554f2SKenneth D. Merry 		return;
297*991554f2SKenneth D. Merry 	}
298*991554f2SKenneth D. Merry 
299*991554f2SKenneth D. Merry 	if (xpt_create_path(&ccb->ccb_h.path, NULL, pathid,
300*991554f2SKenneth D. Merry 	    targetid, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
301*991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_ERROR, "unable to create path for rescan\n");
302*991554f2SKenneth D. Merry 		xpt_free_ccb(ccb);
303*991554f2SKenneth D. Merry 		return;
304*991554f2SKenneth D. Merry 	}
305*991554f2SKenneth D. Merry 
306*991554f2SKenneth D. Merry 	if (targetid == CAM_TARGET_WILDCARD)
307*991554f2SKenneth D. Merry 		ccb->ccb_h.func_code = XPT_SCAN_BUS;
308*991554f2SKenneth D. Merry 	else
309*991554f2SKenneth D. Merry 		ccb->ccb_h.func_code = XPT_SCAN_TGT;
310*991554f2SKenneth D. Merry 
311*991554f2SKenneth D. Merry 	mpr_dprint(sc, MPR_TRACE, "%s targetid %u\n", __func__, targetid);
312*991554f2SKenneth D. Merry 	xpt_rescan(ccb);
313*991554f2SKenneth D. Merry }
314*991554f2SKenneth D. Merry 
315*991554f2SKenneth D. Merry static void
316*991554f2SKenneth D. Merry mprsas_log_command(struct mpr_command *cm, u_int level, const char *fmt, ...)
317*991554f2SKenneth D. Merry {
318*991554f2SKenneth D. Merry 	struct sbuf sb;
319*991554f2SKenneth D. Merry 	va_list ap;
320*991554f2SKenneth D. Merry 	char str[192];
321*991554f2SKenneth D. Merry 	char path_str[64];
322*991554f2SKenneth D. Merry 
323*991554f2SKenneth D. Merry 	if (cm == NULL)
324*991554f2SKenneth D. Merry 		return;
325*991554f2SKenneth D. Merry 
326*991554f2SKenneth D. Merry 	/* No need to be in here if debugging isn't enabled */
327*991554f2SKenneth D. Merry 	if ((cm->cm_sc->mpr_debug & level) == 0)
328*991554f2SKenneth D. Merry 		return;
329*991554f2SKenneth D. Merry 
330*991554f2SKenneth D. Merry 	sbuf_new(&sb, str, sizeof(str), 0);
331*991554f2SKenneth D. Merry 
332*991554f2SKenneth D. Merry 	va_start(ap, fmt);
333*991554f2SKenneth D. Merry 
334*991554f2SKenneth D. Merry 	if (cm->cm_ccb != NULL) {
335*991554f2SKenneth D. Merry 		xpt_path_string(cm->cm_ccb->csio.ccb_h.path, path_str,
336*991554f2SKenneth D. Merry 		    sizeof(path_str));
337*991554f2SKenneth D. Merry 		sbuf_cat(&sb, path_str);
338*991554f2SKenneth D. Merry 		if (cm->cm_ccb->ccb_h.func_code == XPT_SCSI_IO) {
339*991554f2SKenneth D. Merry 			scsi_command_string(&cm->cm_ccb->csio, &sb);
340*991554f2SKenneth D. Merry 			sbuf_printf(&sb, "length %d ",
341*991554f2SKenneth D. Merry 			    cm->cm_ccb->csio.dxfer_len);
342*991554f2SKenneth D. Merry 		}
343*991554f2SKenneth D. Merry 	} else {
344*991554f2SKenneth D. Merry 		sbuf_printf(&sb, "(noperiph:%s%d:%u:%u:%u): ",
345*991554f2SKenneth D. Merry 		    cam_sim_name(cm->cm_sc->sassc->sim),
346*991554f2SKenneth D. Merry 		    cam_sim_unit(cm->cm_sc->sassc->sim),
347*991554f2SKenneth D. Merry 		    cam_sim_bus(cm->cm_sc->sassc->sim),
348*991554f2SKenneth D. Merry 		    cm->cm_targ ? cm->cm_targ->tid : 0xFFFFFFFF,
349*991554f2SKenneth D. Merry 		    cm->cm_lun);
350*991554f2SKenneth D. Merry 	}
351*991554f2SKenneth D. Merry 
352*991554f2SKenneth D. Merry 	sbuf_printf(&sb, "SMID %u ", cm->cm_desc.Default.SMID);
353*991554f2SKenneth D. Merry 	sbuf_vprintf(&sb, fmt, ap);
354*991554f2SKenneth D. Merry 	sbuf_finish(&sb);
355*991554f2SKenneth D. Merry 	mpr_dprint_field(cm->cm_sc, level, "%s", sbuf_data(&sb));
356*991554f2SKenneth D. Merry 
357*991554f2SKenneth D. Merry 	va_end(ap);
358*991554f2SKenneth D. Merry }
359*991554f2SKenneth D. Merry 
360*991554f2SKenneth D. Merry static void
361*991554f2SKenneth D. Merry mprsas_remove_volume(struct mpr_softc *sc, struct mpr_command *tm)
362*991554f2SKenneth D. Merry {
363*991554f2SKenneth D. Merry 	MPI2_SCSI_TASK_MANAGE_REPLY *reply;
364*991554f2SKenneth D. Merry 	struct mprsas_target *targ;
365*991554f2SKenneth D. Merry 	uint16_t handle;
366*991554f2SKenneth D. Merry 
367*991554f2SKenneth D. Merry 	MPR_FUNCTRACE(sc);
368*991554f2SKenneth D. Merry 
369*991554f2SKenneth D. Merry 	reply = (MPI2_SCSI_TASK_MANAGE_REPLY *)tm->cm_reply;
370*991554f2SKenneth D. Merry 	handle = (uint16_t)(uintptr_t)tm->cm_complete_data;
371*991554f2SKenneth D. Merry 	targ = tm->cm_targ;
372*991554f2SKenneth D. Merry 
373*991554f2SKenneth D. Merry 	if (reply == NULL) {
374*991554f2SKenneth D. Merry 		/* XXX retry the remove after the diag reset completes? */
375*991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_FAULT, "%s NULL reply resetting device "
376*991554f2SKenneth D. Merry 		    "0x%04x\n", __func__, handle);
377*991554f2SKenneth D. Merry 		mprsas_free_tm(sc, tm);
378*991554f2SKenneth D. Merry 		return;
379*991554f2SKenneth D. Merry 	}
380*991554f2SKenneth D. Merry 
381*991554f2SKenneth D. Merry 	if (reply->IOCStatus != MPI2_IOCSTATUS_SUCCESS) {
382*991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_FAULT, "IOCStatus = 0x%x while resetting "
383*991554f2SKenneth D. Merry 		    "device 0x%x\n", reply->IOCStatus, handle);
384*991554f2SKenneth D. Merry 		mprsas_free_tm(sc, tm);
385*991554f2SKenneth D. Merry 		return;
386*991554f2SKenneth D. Merry 	}
387*991554f2SKenneth D. Merry 
388*991554f2SKenneth D. Merry 	mpr_dprint(sc, MPR_XINFO, "Reset aborted %u commands\n",
389*991554f2SKenneth D. Merry 	    reply->TerminationCount);
390*991554f2SKenneth D. Merry 	mpr_free_reply(sc, tm->cm_reply_data);
391*991554f2SKenneth D. Merry 	tm->cm_reply = NULL;	/* Ensures the reply won't get re-freed */
392*991554f2SKenneth D. Merry 
393*991554f2SKenneth D. Merry 	mpr_dprint(sc, MPR_XINFO, "clearing target %u handle 0x%04x\n",
394*991554f2SKenneth D. Merry 	    targ->tid, handle);
395*991554f2SKenneth D. Merry 
396*991554f2SKenneth D. Merry 	/*
397*991554f2SKenneth D. Merry 	 * Don't clear target if remove fails because things will get confusing.
398*991554f2SKenneth D. Merry 	 * Leave the devname and sasaddr intact so that we know to avoid reusing
399*991554f2SKenneth D. Merry 	 * this target id if possible, and so we can assign the same target id
400*991554f2SKenneth D. Merry 	 * to this device if it comes back in the future.
401*991554f2SKenneth D. Merry 	 */
402*991554f2SKenneth D. Merry 	if (reply->IOCStatus == MPI2_IOCSTATUS_SUCCESS) {
403*991554f2SKenneth D. Merry 		targ = tm->cm_targ;
404*991554f2SKenneth D. Merry 		targ->handle = 0x0;
405*991554f2SKenneth D. Merry 		targ->encl_handle = 0x0;
406*991554f2SKenneth D. Merry 		targ->encl_level_valid = 0x0;
407*991554f2SKenneth D. Merry 		targ->encl_level = 0x0;
408*991554f2SKenneth D. Merry 		targ->connector_name[0] = ' ';
409*991554f2SKenneth D. Merry 		targ->connector_name[1] = ' ';
410*991554f2SKenneth D. Merry 		targ->connector_name[2] = ' ';
411*991554f2SKenneth D. Merry 		targ->connector_name[3] = ' ';
412*991554f2SKenneth D. Merry 		targ->encl_slot = 0x0;
413*991554f2SKenneth D. Merry 		targ->exp_dev_handle = 0x0;
414*991554f2SKenneth D. Merry 		targ->phy_num = 0x0;
415*991554f2SKenneth D. Merry 		targ->linkrate = 0x0;
416*991554f2SKenneth D. Merry 		targ->devinfo = 0x0;
417*991554f2SKenneth D. Merry 		targ->flags = 0x0;
418*991554f2SKenneth D. Merry 		targ->scsi_req_desc_type = 0;
419*991554f2SKenneth D. Merry 	}
420*991554f2SKenneth D. Merry 
421*991554f2SKenneth D. Merry 	mprsas_free_tm(sc, tm);
422*991554f2SKenneth D. Merry }
423*991554f2SKenneth D. Merry 
424*991554f2SKenneth D. Merry 
425*991554f2SKenneth D. Merry /*
426*991554f2SKenneth D. Merry  * No Need to call "MPI2_SAS_OP_REMOVE_DEVICE" For Volume removal.
427*991554f2SKenneth D. Merry  * Otherwise Volume Delete is same as Bare Drive Removal.
428*991554f2SKenneth D. Merry  */
429*991554f2SKenneth D. Merry void
430*991554f2SKenneth D. Merry mprsas_prepare_volume_remove(struct mprsas_softc *sassc, uint16_t handle)
431*991554f2SKenneth D. Merry {
432*991554f2SKenneth D. Merry 	MPI2_SCSI_TASK_MANAGE_REQUEST *req;
433*991554f2SKenneth D. Merry 	struct mpr_softc *sc;
434*991554f2SKenneth D. Merry 	struct mpr_command *cm;
435*991554f2SKenneth D. Merry 	struct mprsas_target *targ = NULL;
436*991554f2SKenneth D. Merry 
437*991554f2SKenneth D. Merry 	MPR_FUNCTRACE(sassc->sc);
438*991554f2SKenneth D. Merry 	sc = sassc->sc;
439*991554f2SKenneth D. Merry 
440*991554f2SKenneth D. Merry 	targ = mprsas_find_target_by_handle(sassc, 0, handle);
441*991554f2SKenneth D. Merry 	if (targ == NULL) {
442*991554f2SKenneth D. Merry 		/* FIXME: what is the action? */
443*991554f2SKenneth D. Merry 		/* We don't know about this device? */
444*991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_ERROR,
445*991554f2SKenneth D. Merry 		   "%s %d : invalid handle 0x%x \n", __func__,__LINE__, handle);
446*991554f2SKenneth D. Merry 		return;
447*991554f2SKenneth D. Merry 	}
448*991554f2SKenneth D. Merry 
449*991554f2SKenneth D. Merry 	targ->flags |= MPRSAS_TARGET_INREMOVAL;
450*991554f2SKenneth D. Merry 
451*991554f2SKenneth D. Merry 	cm = mprsas_alloc_tm(sc);
452*991554f2SKenneth D. Merry 	if (cm == NULL) {
453*991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_ERROR,
454*991554f2SKenneth D. Merry 		    "%s: command alloc failure\n", __func__);
455*991554f2SKenneth D. Merry 		return;
456*991554f2SKenneth D. Merry 	}
457*991554f2SKenneth D. Merry 
458*991554f2SKenneth D. Merry 	mprsas_rescan_target(sc, targ);
459*991554f2SKenneth D. Merry 
460*991554f2SKenneth D. Merry 	req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)cm->cm_req;
461*991554f2SKenneth D. Merry 	req->DevHandle = targ->handle;
462*991554f2SKenneth D. Merry 	req->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
463*991554f2SKenneth D. Merry 	req->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
464*991554f2SKenneth D. Merry 
465*991554f2SKenneth D. Merry 	/* SAS Hard Link Reset / SATA Link Reset */
466*991554f2SKenneth D. Merry 	req->MsgFlags = MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET;
467*991554f2SKenneth D. Merry 
468*991554f2SKenneth D. Merry 	cm->cm_targ = targ;
469*991554f2SKenneth D. Merry 	cm->cm_data = NULL;
470*991554f2SKenneth D. Merry 	cm->cm_desc.HighPriority.RequestFlags =
471*991554f2SKenneth D. Merry 	    MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY;
472*991554f2SKenneth D. Merry 	cm->cm_complete = mprsas_remove_volume;
473*991554f2SKenneth D. Merry 	cm->cm_complete_data = (void *)(uintptr_t)handle;
474*991554f2SKenneth D. Merry 	mpr_map_command(sc, cm);
475*991554f2SKenneth D. Merry }
476*991554f2SKenneth D. Merry 
477*991554f2SKenneth D. Merry /*
478*991554f2SKenneth D. Merry  * The MPT2 firmware performs debounce on the link to avoid transient link
479*991554f2SKenneth D. Merry  * errors and false removals.  When it does decide that link has been lost
480*991554f2SKenneth D. Merry  * and a device needs to go away, it expects that the host will perform a
481*991554f2SKenneth D. Merry  * target reset and then an op remove.  The reset has the side-effect of
482*991554f2SKenneth D. Merry  * aborting any outstanding requests for the device, which is required for
483*991554f2SKenneth D. Merry  * the op-remove to succeed.  It's not clear if the host should check for
484*991554f2SKenneth D. Merry  * the device coming back alive after the reset.
485*991554f2SKenneth D. Merry  */
486*991554f2SKenneth D. Merry void
487*991554f2SKenneth D. Merry mprsas_prepare_remove(struct mprsas_softc *sassc, uint16_t handle)
488*991554f2SKenneth D. Merry {
489*991554f2SKenneth D. Merry 	MPI2_SCSI_TASK_MANAGE_REQUEST *req;
490*991554f2SKenneth D. Merry 	struct mpr_softc *sc;
491*991554f2SKenneth D. Merry 	struct mpr_command *cm;
492*991554f2SKenneth D. Merry 	struct mprsas_target *targ = NULL;
493*991554f2SKenneth D. Merry 
494*991554f2SKenneth D. Merry 	MPR_FUNCTRACE(sassc->sc);
495*991554f2SKenneth D. Merry 
496*991554f2SKenneth D. Merry 	sc = sassc->sc;
497*991554f2SKenneth D. Merry 
498*991554f2SKenneth D. Merry 	targ = mprsas_find_target_by_handle(sassc, 0, handle);
499*991554f2SKenneth D. Merry 	if (targ == NULL) {
500*991554f2SKenneth D. Merry 		/* FIXME: what is the action? */
501*991554f2SKenneth D. Merry 		/* We don't know about this device? */
502*991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_ERROR, "%s : invalid handle 0x%x \n",
503*991554f2SKenneth D. Merry 		    __func__, handle);
504*991554f2SKenneth D. Merry 		return;
505*991554f2SKenneth D. Merry 	}
506*991554f2SKenneth D. Merry 
507*991554f2SKenneth D. Merry 	targ->flags |= MPRSAS_TARGET_INREMOVAL;
508*991554f2SKenneth D. Merry 
509*991554f2SKenneth D. Merry 	cm = mprsas_alloc_tm(sc);
510*991554f2SKenneth D. Merry 	if (cm == NULL) {
511*991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_ERROR, "%s: command alloc failure\n",
512*991554f2SKenneth D. Merry 		    __func__);
513*991554f2SKenneth D. Merry 		return;
514*991554f2SKenneth D. Merry 	}
515*991554f2SKenneth D. Merry 
516*991554f2SKenneth D. Merry 	mprsas_rescan_target(sc, targ);
517*991554f2SKenneth D. Merry 
518*991554f2SKenneth D. Merry 	req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)cm->cm_req;
519*991554f2SKenneth D. Merry 	memset(req, 0, sizeof(*req));
520*991554f2SKenneth D. Merry 	req->DevHandle = htole16(targ->handle);
521*991554f2SKenneth D. Merry 	req->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
522*991554f2SKenneth D. Merry 	req->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
523*991554f2SKenneth D. Merry 
524*991554f2SKenneth D. Merry 	/* SAS Hard Link Reset / SATA Link Reset */
525*991554f2SKenneth D. Merry 	req->MsgFlags = MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET;
526*991554f2SKenneth D. Merry 
527*991554f2SKenneth D. Merry 	cm->cm_targ = targ;
528*991554f2SKenneth D. Merry 	cm->cm_data = NULL;
529*991554f2SKenneth D. Merry 	cm->cm_desc.HighPriority.RequestFlags =
530*991554f2SKenneth D. Merry 	    MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY;
531*991554f2SKenneth D. Merry 	cm->cm_complete = mprsas_remove_device;
532*991554f2SKenneth D. Merry 	cm->cm_complete_data = (void *)(uintptr_t)handle;
533*991554f2SKenneth D. Merry 	mpr_map_command(sc, cm);
534*991554f2SKenneth D. Merry }
535*991554f2SKenneth D. Merry 
536*991554f2SKenneth D. Merry static void
537*991554f2SKenneth D. Merry mprsas_remove_device(struct mpr_softc *sc, struct mpr_command *tm)
538*991554f2SKenneth D. Merry {
539*991554f2SKenneth D. Merry 	MPI2_SCSI_TASK_MANAGE_REPLY *reply;
540*991554f2SKenneth D. Merry 	MPI2_SAS_IOUNIT_CONTROL_REQUEST *req;
541*991554f2SKenneth D. Merry 	struct mprsas_target *targ;
542*991554f2SKenneth D. Merry 	struct mpr_command *next_cm;
543*991554f2SKenneth D. Merry 	uint16_t handle;
544*991554f2SKenneth D. Merry 
545*991554f2SKenneth D. Merry 	MPR_FUNCTRACE(sc);
546*991554f2SKenneth D. Merry 
547*991554f2SKenneth D. Merry 	reply = (MPI2_SCSI_TASK_MANAGE_REPLY *)tm->cm_reply;
548*991554f2SKenneth D. Merry 	handle = (uint16_t)(uintptr_t)tm->cm_complete_data;
549*991554f2SKenneth D. Merry 	targ = tm->cm_targ;
550*991554f2SKenneth D. Merry 
551*991554f2SKenneth D. Merry 	/*
552*991554f2SKenneth D. Merry 	 * Currently there should be no way we can hit this case.  It only
553*991554f2SKenneth D. Merry 	 * happens when we have a failure to allocate chain frames, and
554*991554f2SKenneth D. Merry 	 * task management commands don't have S/G lists.
555*991554f2SKenneth D. Merry 	 */
556*991554f2SKenneth D. Merry 	if ((tm->cm_flags & MPR_CM_FLAGS_ERROR_MASK) != 0) {
557*991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_ERROR, "%s: cm_flags = %#x for remove of "
558*991554f2SKenneth D. Merry 		    "handle %#04x! This should not happen!\n", __func__,
559*991554f2SKenneth D. Merry 		    tm->cm_flags, handle);
560*991554f2SKenneth D. Merry 		mprsas_free_tm(sc, tm);
561*991554f2SKenneth D. Merry 		return;
562*991554f2SKenneth D. Merry 	}
563*991554f2SKenneth D. Merry 
564*991554f2SKenneth D. Merry 	if (reply == NULL) {
565*991554f2SKenneth D. Merry 		/* XXX retry the remove after the diag reset completes? */
566*991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_FAULT, "%s NULL reply resetting device "
567*991554f2SKenneth D. Merry 		    "0x%04x\n", __func__, handle);
568*991554f2SKenneth D. Merry 		mprsas_free_tm(sc, tm);
569*991554f2SKenneth D. Merry 		return;
570*991554f2SKenneth D. Merry 	}
571*991554f2SKenneth D. Merry 
572*991554f2SKenneth D. Merry 	if (le16toh(reply->IOCStatus) != MPI2_IOCSTATUS_SUCCESS) {
573*991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_FAULT, "IOCStatus = 0x%x while resetting "
574*991554f2SKenneth D. Merry 		    "device 0x%x\n", le16toh(reply->IOCStatus), handle);
575*991554f2SKenneth D. Merry 		mprsas_free_tm(sc, tm);
576*991554f2SKenneth D. Merry 		return;
577*991554f2SKenneth D. Merry 	}
578*991554f2SKenneth D. Merry 
579*991554f2SKenneth D. Merry 	mpr_dprint(sc, MPR_XINFO, "Reset aborted %u commands\n",
580*991554f2SKenneth D. Merry 	    le32toh(reply->TerminationCount));
581*991554f2SKenneth D. Merry 	mpr_free_reply(sc, tm->cm_reply_data);
582*991554f2SKenneth D. Merry 	tm->cm_reply = NULL;	/* Ensures the reply won't get re-freed */
583*991554f2SKenneth D. Merry 
584*991554f2SKenneth D. Merry 	/* Reuse the existing command */
585*991554f2SKenneth D. Merry 	req = (MPI2_SAS_IOUNIT_CONTROL_REQUEST *)tm->cm_req;
586*991554f2SKenneth D. Merry 	memset(req, 0, sizeof(*req));
587*991554f2SKenneth D. Merry 	req->Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL;
588*991554f2SKenneth D. Merry 	req->Operation = MPI2_SAS_OP_REMOVE_DEVICE;
589*991554f2SKenneth D. Merry 	req->DevHandle = htole16(handle);
590*991554f2SKenneth D. Merry 	tm->cm_data = NULL;
591*991554f2SKenneth D. Merry 	tm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
592*991554f2SKenneth D. Merry 	tm->cm_complete = mprsas_remove_complete;
593*991554f2SKenneth D. Merry 	tm->cm_complete_data = (void *)(uintptr_t)handle;
594*991554f2SKenneth D. Merry 
595*991554f2SKenneth D. Merry 	mpr_map_command(sc, tm);
596*991554f2SKenneth D. Merry 
597*991554f2SKenneth D. Merry 	mpr_dprint(sc, MPR_XINFO, "clearing target %u handle 0x%04x\n",
598*991554f2SKenneth D. Merry 	    targ->tid, handle);
599*991554f2SKenneth D. Merry 	if (targ->encl_level_valid) {
600*991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_XINFO, "At enclosure level %d, slot %d, "
601*991554f2SKenneth D. Merry 		    "connector name (%4s)\n", targ->encl_level, targ->encl_slot,
602*991554f2SKenneth D. Merry 		    targ->connector_name);
603*991554f2SKenneth D. Merry 	}
604*991554f2SKenneth D. Merry 	TAILQ_FOREACH_SAFE(tm, &targ->commands, cm_link, next_cm) {
605*991554f2SKenneth D. Merry 		union ccb *ccb;
606*991554f2SKenneth D. Merry 
607*991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_XINFO, "Completing missed command %p\n", tm);
608*991554f2SKenneth D. Merry 		ccb = tm->cm_complete_data;
609*991554f2SKenneth D. Merry 		ccb->ccb_h.status = CAM_DEV_NOT_THERE;
610*991554f2SKenneth D. Merry 		mprsas_scsiio_complete(sc, tm);
611*991554f2SKenneth D. Merry 	}
612*991554f2SKenneth D. Merry }
613*991554f2SKenneth D. Merry 
614*991554f2SKenneth D. Merry static void
615*991554f2SKenneth D. Merry mprsas_remove_complete(struct mpr_softc *sc, struct mpr_command *tm)
616*991554f2SKenneth D. Merry {
617*991554f2SKenneth D. Merry 	MPI2_SAS_IOUNIT_CONTROL_REPLY *reply;
618*991554f2SKenneth D. Merry 	uint16_t handle;
619*991554f2SKenneth D. Merry 	struct mprsas_target *targ;
620*991554f2SKenneth D. Merry 	struct mprsas_lun *lun;
621*991554f2SKenneth D. Merry 
622*991554f2SKenneth D. Merry 	MPR_FUNCTRACE(sc);
623*991554f2SKenneth D. Merry 
624*991554f2SKenneth D. Merry 	reply = (MPI2_SAS_IOUNIT_CONTROL_REPLY *)tm->cm_reply;
625*991554f2SKenneth D. Merry 	handle = (uint16_t)(uintptr_t)tm->cm_complete_data;
626*991554f2SKenneth D. Merry 
627*991554f2SKenneth D. Merry 	/*
628*991554f2SKenneth D. Merry 	 * Currently there should be no way we can hit this case.  It only
629*991554f2SKenneth D. Merry 	 * happens when we have a failure to allocate chain frames, and
630*991554f2SKenneth D. Merry 	 * task management commands don't have S/G lists.
631*991554f2SKenneth D. Merry 	 */
632*991554f2SKenneth D. Merry 	if ((tm->cm_flags & MPR_CM_FLAGS_ERROR_MASK) != 0) {
633*991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_XINFO, "%s: cm_flags = %#x for remove of "
634*991554f2SKenneth D. Merry 		    "handle %#04x! This should not happen!\n", __func__,
635*991554f2SKenneth D. Merry 		    tm->cm_flags, handle);
636*991554f2SKenneth D. Merry 		mprsas_free_tm(sc, tm);
637*991554f2SKenneth D. Merry 		return;
638*991554f2SKenneth D. Merry 	}
639*991554f2SKenneth D. Merry 
640*991554f2SKenneth D. Merry 	if (reply == NULL) {
641*991554f2SKenneth D. Merry 		/* most likely a chip reset */
642*991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_FAULT, "%s NULL reply removing device "
643*991554f2SKenneth D. Merry 		    "0x%04x\n", __func__, handle);
644*991554f2SKenneth D. Merry 		mprsas_free_tm(sc, tm);
645*991554f2SKenneth D. Merry 		return;
646*991554f2SKenneth D. Merry 	}
647*991554f2SKenneth D. Merry 
648*991554f2SKenneth D. Merry 	mpr_dprint(sc, MPR_XINFO, "%s on handle 0x%04x, IOCStatus= 0x%x\n",
649*991554f2SKenneth D. Merry 	    __func__, handle, le16toh(reply->IOCStatus));
650*991554f2SKenneth D. Merry 
651*991554f2SKenneth D. Merry 	/*
652*991554f2SKenneth D. Merry 	 * Don't clear target if remove fails because things will get confusing.
653*991554f2SKenneth D. Merry 	 * Leave the devname and sasaddr intact so that we know to avoid reusing
654*991554f2SKenneth D. Merry 	 * this target id if possible, and so we can assign the same target id
655*991554f2SKenneth D. Merry 	 * to this device if it comes back in the future.
656*991554f2SKenneth D. Merry 	 */
657*991554f2SKenneth D. Merry 	if (le16toh(reply->IOCStatus) == MPI2_IOCSTATUS_SUCCESS) {
658*991554f2SKenneth D. Merry 		targ = tm->cm_targ;
659*991554f2SKenneth D. Merry 		targ->handle = 0x0;
660*991554f2SKenneth D. Merry 		targ->encl_handle = 0x0;
661*991554f2SKenneth D. Merry 		targ->encl_level_valid = 0x0;
662*991554f2SKenneth D. Merry 		targ->encl_level = 0x0;
663*991554f2SKenneth D. Merry 		targ->connector_name[0] = ' ';
664*991554f2SKenneth D. Merry 		targ->connector_name[1] = ' ';
665*991554f2SKenneth D. Merry 		targ->connector_name[2] = ' ';
666*991554f2SKenneth D. Merry 		targ->connector_name[3] = ' ';
667*991554f2SKenneth D. Merry 		targ->encl_slot = 0x0;
668*991554f2SKenneth D. Merry 		targ->exp_dev_handle = 0x0;
669*991554f2SKenneth D. Merry 		targ->phy_num = 0x0;
670*991554f2SKenneth D. Merry 		targ->linkrate = 0x0;
671*991554f2SKenneth D. Merry 		targ->devinfo = 0x0;
672*991554f2SKenneth D. Merry 		targ->flags = 0x0;
673*991554f2SKenneth D. Merry 		targ->scsi_req_desc_type = 0;
674*991554f2SKenneth D. Merry 
675*991554f2SKenneth D. Merry 		while (!SLIST_EMPTY(&targ->luns)) {
676*991554f2SKenneth D. Merry 			lun = SLIST_FIRST(&targ->luns);
677*991554f2SKenneth D. Merry 			SLIST_REMOVE_HEAD(&targ->luns, lun_link);
678*991554f2SKenneth D. Merry 			free(lun, M_MPR);
679*991554f2SKenneth D. Merry 		}
680*991554f2SKenneth D. Merry 	}
681*991554f2SKenneth D. Merry 
682*991554f2SKenneth D. Merry 	mprsas_free_tm(sc, tm);
683*991554f2SKenneth D. Merry }
684*991554f2SKenneth D. Merry 
685*991554f2SKenneth D. Merry static int
686*991554f2SKenneth D. Merry mprsas_register_events(struct mpr_softc *sc)
687*991554f2SKenneth D. Merry {
688*991554f2SKenneth D. Merry 	uint8_t events[16];
689*991554f2SKenneth D. Merry 
690*991554f2SKenneth D. Merry 	bzero(events, 16);
691*991554f2SKenneth D. Merry 	setbit(events, MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE);
692*991554f2SKenneth D. Merry 	setbit(events, MPI2_EVENT_SAS_DISCOVERY);
693*991554f2SKenneth D. Merry 	setbit(events, MPI2_EVENT_SAS_BROADCAST_PRIMITIVE);
694*991554f2SKenneth D. Merry 	setbit(events, MPI2_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE);
695*991554f2SKenneth D. Merry 	setbit(events, MPI2_EVENT_SAS_INIT_TABLE_OVERFLOW);
696*991554f2SKenneth D. Merry 	setbit(events, MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST);
697*991554f2SKenneth D. Merry 	setbit(events, MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE);
698*991554f2SKenneth D. Merry 	setbit(events, MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST);
699*991554f2SKenneth D. Merry 	setbit(events, MPI2_EVENT_IR_VOLUME);
700*991554f2SKenneth D. Merry 	setbit(events, MPI2_EVENT_IR_PHYSICAL_DISK);
701*991554f2SKenneth D. Merry 	setbit(events, MPI2_EVENT_IR_OPERATION_STATUS);
702*991554f2SKenneth D. Merry 	setbit(events, MPI2_EVENT_TEMP_THRESHOLD);
703*991554f2SKenneth D. Merry 
704*991554f2SKenneth D. Merry 	mpr_register_events(sc, events, mprsas_evt_handler, NULL,
705*991554f2SKenneth D. Merry 	    &sc->sassc->mprsas_eh);
706*991554f2SKenneth D. Merry 
707*991554f2SKenneth D. Merry 	return (0);
708*991554f2SKenneth D. Merry }
709*991554f2SKenneth D. Merry 
710*991554f2SKenneth D. Merry int
711*991554f2SKenneth D. Merry mpr_attach_sas(struct mpr_softc *sc)
712*991554f2SKenneth D. Merry {
713*991554f2SKenneth D. Merry 	struct mprsas_softc *sassc;
714*991554f2SKenneth D. Merry 	cam_status status;
715*991554f2SKenneth D. Merry 	int unit, error = 0;
716*991554f2SKenneth D. Merry 
717*991554f2SKenneth D. Merry 	MPR_FUNCTRACE(sc);
718*991554f2SKenneth D. Merry 
719*991554f2SKenneth D. Merry 	sassc = malloc(sizeof(struct mprsas_softc), M_MPR, M_WAITOK|M_ZERO);
720*991554f2SKenneth D. Merry 	if (!sassc) {
721*991554f2SKenneth D. Merry 		device_printf(sc->mpr_dev, "Cannot allocate memory %s %d\n",
722*991554f2SKenneth D. Merry 		    __func__, __LINE__);
723*991554f2SKenneth D. Merry 		return (ENOMEM);
724*991554f2SKenneth D. Merry 	}
725*991554f2SKenneth D. Merry 
726*991554f2SKenneth D. Merry 	/*
727*991554f2SKenneth D. Merry 	 * XXX MaxTargets could change during a reinit.  since we don't
728*991554f2SKenneth D. Merry 	 * resize the targets[] array during such an event, cache the value
729*991554f2SKenneth D. Merry 	 * of MaxTargets here so that we don't get into trouble later.  This
730*991554f2SKenneth D. Merry 	 * should move into the reinit logic.
731*991554f2SKenneth D. Merry 	 */
732*991554f2SKenneth D. Merry 	sassc->maxtargets = sc->facts->MaxTargets;
733*991554f2SKenneth D. Merry 	sassc->targets = malloc(sizeof(struct mprsas_target) *
734*991554f2SKenneth D. Merry 	    sassc->maxtargets, M_MPR, M_WAITOK|M_ZERO);
735*991554f2SKenneth D. Merry 	if (!sassc->targets) {
736*991554f2SKenneth D. Merry 		device_printf(sc->mpr_dev, "Cannot allocate memory %s %d\n",
737*991554f2SKenneth D. Merry 		    __func__, __LINE__);
738*991554f2SKenneth D. Merry 		free(sassc, M_MPR);
739*991554f2SKenneth D. Merry 		return (ENOMEM);
740*991554f2SKenneth D. Merry 	}
741*991554f2SKenneth D. Merry 	sc->sassc = sassc;
742*991554f2SKenneth D. Merry 	sassc->sc = sc;
743*991554f2SKenneth D. Merry 
744*991554f2SKenneth D. Merry 	if ((sassc->devq = cam_simq_alloc(sc->num_reqs)) == NULL) {
745*991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_ERROR, "Cannot allocate SIMQ\n");
746*991554f2SKenneth D. Merry 		error = ENOMEM;
747*991554f2SKenneth D. Merry 		goto out;
748*991554f2SKenneth D. Merry 	}
749*991554f2SKenneth D. Merry 
750*991554f2SKenneth D. Merry 	unit = device_get_unit(sc->mpr_dev);
751*991554f2SKenneth D. Merry 	sassc->sim = cam_sim_alloc(mprsas_action, mprsas_poll, "mpr", sassc,
752*991554f2SKenneth D. Merry 	    unit, &sc->mpr_mtx, sc->num_reqs, sc->num_reqs, sassc->devq);
753*991554f2SKenneth D. Merry 	if (sassc->sim == NULL) {
754*991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_ERROR, "Cannot allocate SIM\n");
755*991554f2SKenneth D. Merry 		error = EINVAL;
756*991554f2SKenneth D. Merry 		goto out;
757*991554f2SKenneth D. Merry 	}
758*991554f2SKenneth D. Merry 
759*991554f2SKenneth D. Merry 	TAILQ_INIT(&sassc->ev_queue);
760*991554f2SKenneth D. Merry 
761*991554f2SKenneth D. Merry 	/* Initialize taskqueue for Event Handling */
762*991554f2SKenneth D. Merry 	TASK_INIT(&sassc->ev_task, 0, mprsas_firmware_event_work, sc);
763*991554f2SKenneth D. Merry 	sassc->ev_tq = taskqueue_create("mpr_taskq", M_NOWAIT | M_ZERO,
764*991554f2SKenneth D. Merry 	    taskqueue_thread_enqueue, &sassc->ev_tq);
765*991554f2SKenneth D. Merry 
766*991554f2SKenneth D. Merry 	/* Run the task queue with lowest priority */
767*991554f2SKenneth D. Merry 	taskqueue_start_threads(&sassc->ev_tq, 1, 255, "%s taskq",
768*991554f2SKenneth D. Merry 	    device_get_nameunit(sc->mpr_dev));
769*991554f2SKenneth D. Merry 
770*991554f2SKenneth D. Merry 	mpr_lock(sc);
771*991554f2SKenneth D. Merry 
772*991554f2SKenneth D. Merry 	/*
773*991554f2SKenneth D. Merry 	 * XXX There should be a bus for every port on the adapter, but since
774*991554f2SKenneth D. Merry 	 * we're just going to fake the topology for now, we'll pretend that
775*991554f2SKenneth D. Merry 	 * everything is just a target on a single bus.
776*991554f2SKenneth D. Merry 	 */
777*991554f2SKenneth D. Merry 	if ((error = xpt_bus_register(sassc->sim, sc->mpr_dev, 0)) != 0) {
778*991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_ERROR, "Error %d registering SCSI bus\n",
779*991554f2SKenneth D. Merry 		    error);
780*991554f2SKenneth D. Merry 		mpr_unlock(sc);
781*991554f2SKenneth D. Merry 		goto out;
782*991554f2SKenneth D. Merry 	}
783*991554f2SKenneth D. Merry 
784*991554f2SKenneth D. Merry 	/*
785*991554f2SKenneth D. Merry 	 * Assume that discovery events will start right away.  Freezing
786*991554f2SKenneth D. Merry 	 *
787*991554f2SKenneth D. Merry 	 * Hold off boot until discovery is complete.
788*991554f2SKenneth D. Merry 	 */
789*991554f2SKenneth D. Merry 	sassc->flags |= MPRSAS_IN_STARTUP | MPRSAS_IN_DISCOVERY;
790*991554f2SKenneth D. Merry 	sc->sassc->startup_refcount = 0;
791*991554f2SKenneth D. Merry 	mprsas_startup_increment(sassc);
792*991554f2SKenneth D. Merry 
793*991554f2SKenneth D. Merry 	callout_init(&sassc->discovery_callout, 1 /*mprafe*/);
794*991554f2SKenneth D. Merry 
795*991554f2SKenneth D. Merry 	sassc->tm_count = 0;
796*991554f2SKenneth D. Merry 
797*991554f2SKenneth D. Merry 	/*
798*991554f2SKenneth D. Merry 	 * Register for async events so we can determine the EEDP
799*991554f2SKenneth D. Merry 	 * capabilities of devices.
800*991554f2SKenneth D. Merry 	 */
801*991554f2SKenneth D. Merry 	status = xpt_create_path(&sassc->path, /*periph*/NULL,
802*991554f2SKenneth D. Merry 	    cam_sim_path(sc->sassc->sim), CAM_TARGET_WILDCARD,
803*991554f2SKenneth D. Merry 	    CAM_LUN_WILDCARD);
804*991554f2SKenneth D. Merry 	if (status != CAM_REQ_CMP) {
805*991554f2SKenneth D. Merry 		mpr_printf(sc, "Error %#x creating sim path\n", status);
806*991554f2SKenneth D. Merry 		sassc->path = NULL;
807*991554f2SKenneth D. Merry 	} else {
808*991554f2SKenneth D. Merry 		int event;
809*991554f2SKenneth D. Merry 
810*991554f2SKenneth D. Merry #if (__FreeBSD_version >= 1000006) || \
811*991554f2SKenneth D. Merry     ((__FreeBSD_version >= 901503) && (__FreeBSD_version < 1000000))
812*991554f2SKenneth D. Merry 		event = AC_ADVINFO_CHANGED | AC_FOUND_DEVICE;
813*991554f2SKenneth D. Merry #else
814*991554f2SKenneth D. Merry 		event = AC_FOUND_DEVICE;
815*991554f2SKenneth D. Merry #endif
816*991554f2SKenneth D. Merry 		status = xpt_register_async(event, mprsas_async, sc,
817*991554f2SKenneth D. Merry 					    sassc->path);
818*991554f2SKenneth D. Merry 		if (status != CAM_REQ_CMP) {
819*991554f2SKenneth D. Merry 			mpr_dprint(sc, MPR_ERROR,
820*991554f2SKenneth D. Merry 			    "Error %#x registering async handler for "
821*991554f2SKenneth D. Merry 			    "AC_ADVINFO_CHANGED events\n", status);
822*991554f2SKenneth D. Merry 			xpt_free_path(sassc->path);
823*991554f2SKenneth D. Merry 			sassc->path = NULL;
824*991554f2SKenneth D. Merry 		}
825*991554f2SKenneth D. Merry 	}
826*991554f2SKenneth D. Merry 	if (status != CAM_REQ_CMP) {
827*991554f2SKenneth D. Merry 		/*
828*991554f2SKenneth D. Merry 		 * EEDP use is the exception, not the rule.
829*991554f2SKenneth D. Merry 		 * Warn the user, but do not fail to attach.
830*991554f2SKenneth D. Merry 		 */
831*991554f2SKenneth D. Merry 		mpr_printf(sc, "EEDP capabilities disabled.\n");
832*991554f2SKenneth D. Merry 	}
833*991554f2SKenneth D. Merry 
834*991554f2SKenneth D. Merry 	mpr_unlock(sc);
835*991554f2SKenneth D. Merry 
836*991554f2SKenneth D. Merry 	mprsas_register_events(sc);
837*991554f2SKenneth D. Merry out:
838*991554f2SKenneth D. Merry 	if (error)
839*991554f2SKenneth D. Merry 		mpr_detach_sas(sc);
840*991554f2SKenneth D. Merry 	return (error);
841*991554f2SKenneth D. Merry }
842*991554f2SKenneth D. Merry 
843*991554f2SKenneth D. Merry int
844*991554f2SKenneth D. Merry mpr_detach_sas(struct mpr_softc *sc)
845*991554f2SKenneth D. Merry {
846*991554f2SKenneth D. Merry 	struct mprsas_softc *sassc;
847*991554f2SKenneth D. Merry 	struct mprsas_lun *lun, *lun_tmp;
848*991554f2SKenneth D. Merry 	struct mprsas_target *targ;
849*991554f2SKenneth D. Merry 	int i;
850*991554f2SKenneth D. Merry 
851*991554f2SKenneth D. Merry 	MPR_FUNCTRACE(sc);
852*991554f2SKenneth D. Merry 
853*991554f2SKenneth D. Merry 	if (sc->sassc == NULL)
854*991554f2SKenneth D. Merry 		return (0);
855*991554f2SKenneth D. Merry 
856*991554f2SKenneth D. Merry 	sassc = sc->sassc;
857*991554f2SKenneth D. Merry 	mpr_deregister_events(sc, sassc->mprsas_eh);
858*991554f2SKenneth D. Merry 
859*991554f2SKenneth D. Merry 	/*
860*991554f2SKenneth D. Merry 	 * Drain and free the event handling taskqueue with the lock
861*991554f2SKenneth D. Merry 	 * unheld so that any parallel processing tasks drain properly
862*991554f2SKenneth D. Merry 	 * without deadlocking.
863*991554f2SKenneth D. Merry 	 */
864*991554f2SKenneth D. Merry 	if (sassc->ev_tq != NULL)
865*991554f2SKenneth D. Merry 		taskqueue_free(sassc->ev_tq);
866*991554f2SKenneth D. Merry 
867*991554f2SKenneth D. Merry 	/* Make sure CAM doesn't wedge if we had to bail out early. */
868*991554f2SKenneth D. Merry 	mpr_lock(sc);
869*991554f2SKenneth D. Merry 
870*991554f2SKenneth D. Merry 	/* Deregister our async handler */
871*991554f2SKenneth D. Merry 	if (sassc->path != NULL) {
872*991554f2SKenneth D. Merry 		xpt_register_async(0, mprsas_async, sc, sassc->path);
873*991554f2SKenneth D. Merry 		xpt_free_path(sassc->path);
874*991554f2SKenneth D. Merry 		sassc->path = NULL;
875*991554f2SKenneth D. Merry 	}
876*991554f2SKenneth D. Merry 
877*991554f2SKenneth D. Merry 	if (sassc->flags & MPRSAS_IN_STARTUP)
878*991554f2SKenneth D. Merry 		xpt_release_simq(sassc->sim, 1);
879*991554f2SKenneth D. Merry 
880*991554f2SKenneth D. Merry 	if (sassc->sim != NULL) {
881*991554f2SKenneth D. Merry 		xpt_bus_deregister(cam_sim_path(sassc->sim));
882*991554f2SKenneth D. Merry 		cam_sim_free(sassc->sim, FALSE);
883*991554f2SKenneth D. Merry 	}
884*991554f2SKenneth D. Merry 
885*991554f2SKenneth D. Merry 	sassc->flags |= MPRSAS_SHUTDOWN;
886*991554f2SKenneth D. Merry 	mpr_unlock(sc);
887*991554f2SKenneth D. Merry 
888*991554f2SKenneth D. Merry 	if (sassc->devq != NULL)
889*991554f2SKenneth D. Merry 		cam_simq_free(sassc->devq);
890*991554f2SKenneth D. Merry 
891*991554f2SKenneth D. Merry 	for (i = 0; i < sassc->maxtargets; i++) {
892*991554f2SKenneth D. Merry 		targ = &sassc->targets[i];
893*991554f2SKenneth D. Merry 		SLIST_FOREACH_SAFE(lun, &targ->luns, lun_link, lun_tmp) {
894*991554f2SKenneth D. Merry 			free(lun, M_MPR);
895*991554f2SKenneth D. Merry 		}
896*991554f2SKenneth D. Merry 	}
897*991554f2SKenneth D. Merry 	free(sassc->targets, M_MPR);
898*991554f2SKenneth D. Merry 	free(sassc, M_MPR);
899*991554f2SKenneth D. Merry 	sc->sassc = NULL;
900*991554f2SKenneth D. Merry 
901*991554f2SKenneth D. Merry 	return (0);
902*991554f2SKenneth D. Merry }
903*991554f2SKenneth D. Merry 
904*991554f2SKenneth D. Merry void
905*991554f2SKenneth D. Merry mprsas_discovery_end(struct mprsas_softc *sassc)
906*991554f2SKenneth D. Merry {
907*991554f2SKenneth D. Merry 	struct mpr_softc *sc = sassc->sc;
908*991554f2SKenneth D. Merry 
909*991554f2SKenneth D. Merry 	MPR_FUNCTRACE(sc);
910*991554f2SKenneth D. Merry 
911*991554f2SKenneth D. Merry 	if (sassc->flags & MPRSAS_DISCOVERY_TIMEOUT_PENDING)
912*991554f2SKenneth D. Merry 		callout_stop(&sassc->discovery_callout);
913*991554f2SKenneth D. Merry 
914*991554f2SKenneth D. Merry }
915*991554f2SKenneth D. Merry 
916*991554f2SKenneth D. Merry static void
917*991554f2SKenneth D. Merry mprsas_action(struct cam_sim *sim, union ccb *ccb)
918*991554f2SKenneth D. Merry {
919*991554f2SKenneth D. Merry 	struct mprsas_softc *sassc;
920*991554f2SKenneth D. Merry 
921*991554f2SKenneth D. Merry 	sassc = cam_sim_softc(sim);
922*991554f2SKenneth D. Merry 
923*991554f2SKenneth D. Merry 	MPR_FUNCTRACE(sassc->sc);
924*991554f2SKenneth D. Merry 	mpr_dprint(sassc->sc, MPR_TRACE, "%s func 0x%x\n", __func__,
925*991554f2SKenneth D. Merry 	    ccb->ccb_h.func_code);
926*991554f2SKenneth D. Merry 	mtx_assert(&sassc->sc->mpr_mtx, MA_OWNED);
927*991554f2SKenneth D. Merry 
928*991554f2SKenneth D. Merry 	switch (ccb->ccb_h.func_code) {
929*991554f2SKenneth D. Merry 	case XPT_PATH_INQ:
930*991554f2SKenneth D. Merry 	{
931*991554f2SKenneth D. Merry 		struct ccb_pathinq *cpi = &ccb->cpi;
932*991554f2SKenneth D. Merry 
933*991554f2SKenneth D. Merry 		cpi->version_num = 1;
934*991554f2SKenneth D. Merry 		cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE|PI_WIDE_16;
935*991554f2SKenneth D. Merry 		cpi->target_sprt = 0;
936*991554f2SKenneth D. Merry #if __FreeBSD_version >= 1000039
937*991554f2SKenneth D. Merry 		cpi->hba_misc = PIM_NOBUSRESET | PIM_UNMAPPED | PIM_NOSCAN;
938*991554f2SKenneth D. Merry #else
939*991554f2SKenneth D. Merry 		cpi->hba_misc = PIM_NOBUSRESET | PIM_UNMAPPED;
940*991554f2SKenneth D. Merry #endif
941*991554f2SKenneth D. Merry 		cpi->hba_eng_cnt = 0;
942*991554f2SKenneth D. Merry 		cpi->max_target = sassc->maxtargets - 1;
943*991554f2SKenneth D. Merry 		cpi->max_lun = 255;
944*991554f2SKenneth D. Merry 		cpi->initiator_id = sassc->maxtargets - 1;
945*991554f2SKenneth D. Merry 		strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
946*991554f2SKenneth D. Merry 		strncpy(cpi->hba_vid, "LSILogic", HBA_IDLEN);
947*991554f2SKenneth D. Merry 		strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
948*991554f2SKenneth D. Merry 		cpi->unit_number = cam_sim_unit(sim);
949*991554f2SKenneth D. Merry 		cpi->bus_id = cam_sim_bus(sim);
950*991554f2SKenneth D. Merry 		/*
951*991554f2SKenneth D. Merry 		 * XXXSLM-I think this needs to change based on config page or
952*991554f2SKenneth D. Merry 		 * something instead of hardcoded to 150000.
953*991554f2SKenneth D. Merry 		 */
954*991554f2SKenneth D. Merry 		cpi->base_transfer_speed = 150000;
955*991554f2SKenneth D. Merry 		cpi->transport = XPORT_SAS;
956*991554f2SKenneth D. Merry 		cpi->transport_version = 0;
957*991554f2SKenneth D. Merry 		cpi->protocol = PROTO_SCSI;
958*991554f2SKenneth D. Merry 		cpi->protocol_version = SCSI_REV_SPC;
959*991554f2SKenneth D. Merry #if __FreeBSD_version >= 800001
960*991554f2SKenneth D. Merry 		/*
961*991554f2SKenneth D. Merry 		 * XXXSLM-probably need to base this number on max SGL's and
962*991554f2SKenneth D. Merry 		 * page size.
963*991554f2SKenneth D. Merry 		 */
964*991554f2SKenneth D. Merry 		cpi->maxio = 256 * 1024;
965*991554f2SKenneth D. Merry #endif
966*991554f2SKenneth D. Merry 		cpi->ccb_h.status = CAM_REQ_CMP;
967*991554f2SKenneth D. Merry 		break;
968*991554f2SKenneth D. Merry 	}
969*991554f2SKenneth D. Merry 	case XPT_GET_TRAN_SETTINGS:
970*991554f2SKenneth D. Merry 	{
971*991554f2SKenneth D. Merry 		struct ccb_trans_settings	*cts;
972*991554f2SKenneth D. Merry 		struct ccb_trans_settings_sas	*sas;
973*991554f2SKenneth D. Merry 		struct ccb_trans_settings_scsi	*scsi;
974*991554f2SKenneth D. Merry 		struct mprsas_target *targ;
975*991554f2SKenneth D. Merry 
976*991554f2SKenneth D. Merry 		cts = &ccb->cts;
977*991554f2SKenneth D. Merry 		sas = &cts->xport_specific.sas;
978*991554f2SKenneth D. Merry 		scsi = &cts->proto_specific.scsi;
979*991554f2SKenneth D. Merry 
980*991554f2SKenneth D. Merry 		KASSERT(cts->ccb_h.target_id < sassc->maxtargets,
981*991554f2SKenneth D. Merry 		    ("Target %d out of bounds in XPT_GET_TRAN_SETTINGS\n",
982*991554f2SKenneth D. Merry 		    cts->ccb_h.target_id));
983*991554f2SKenneth D. Merry 		targ = &sassc->targets[cts->ccb_h.target_id];
984*991554f2SKenneth D. Merry 		if (targ->handle == 0x0) {
985*991554f2SKenneth D. Merry 			cts->ccb_h.status = CAM_DEV_NOT_THERE;
986*991554f2SKenneth D. Merry 			break;
987*991554f2SKenneth D. Merry 		}
988*991554f2SKenneth D. Merry 
989*991554f2SKenneth D. Merry 		cts->protocol_version = SCSI_REV_SPC2;
990*991554f2SKenneth D. Merry 		cts->transport = XPORT_SAS;
991*991554f2SKenneth D. Merry 		cts->transport_version = 0;
992*991554f2SKenneth D. Merry 
993*991554f2SKenneth D. Merry 		sas->valid = CTS_SAS_VALID_SPEED;
994*991554f2SKenneth D. Merry 		switch (targ->linkrate) {
995*991554f2SKenneth D. Merry 		case 0x08:
996*991554f2SKenneth D. Merry 			sas->bitrate = 150000;
997*991554f2SKenneth D. Merry 			break;
998*991554f2SKenneth D. Merry 		case 0x09:
999*991554f2SKenneth D. Merry 			sas->bitrate = 300000;
1000*991554f2SKenneth D. Merry 			break;
1001*991554f2SKenneth D. Merry 		case 0x0a:
1002*991554f2SKenneth D. Merry 			sas->bitrate = 600000;
1003*991554f2SKenneth D. Merry 			break;
1004*991554f2SKenneth D. Merry 		default:
1005*991554f2SKenneth D. Merry 			sas->valid = 0;
1006*991554f2SKenneth D. Merry 		}
1007*991554f2SKenneth D. Merry 
1008*991554f2SKenneth D. Merry 		cts->protocol = PROTO_SCSI;
1009*991554f2SKenneth D. Merry 		scsi->valid = CTS_SCSI_VALID_TQ;
1010*991554f2SKenneth D. Merry 		scsi->flags = CTS_SCSI_FLAGS_TAG_ENB;
1011*991554f2SKenneth D. Merry 
1012*991554f2SKenneth D. Merry 		cts->ccb_h.status = CAM_REQ_CMP;
1013*991554f2SKenneth D. Merry 		break;
1014*991554f2SKenneth D. Merry 	}
1015*991554f2SKenneth D. Merry 	case XPT_CALC_GEOMETRY:
1016*991554f2SKenneth D. Merry 		cam_calc_geometry(&ccb->ccg, /*extended*/1);
1017*991554f2SKenneth D. Merry 		ccb->ccb_h.status = CAM_REQ_CMP;
1018*991554f2SKenneth D. Merry 		break;
1019*991554f2SKenneth D. Merry 	case XPT_RESET_DEV:
1020*991554f2SKenneth D. Merry 		mpr_dprint(sassc->sc, MPR_XINFO,
1021*991554f2SKenneth D. Merry 		    "mprsas_action XPT_RESET_DEV\n");
1022*991554f2SKenneth D. Merry 		mprsas_action_resetdev(sassc, ccb);
1023*991554f2SKenneth D. Merry 		return;
1024*991554f2SKenneth D. Merry 	case XPT_RESET_BUS:
1025*991554f2SKenneth D. Merry 	case XPT_ABORT:
1026*991554f2SKenneth D. Merry 	case XPT_TERM_IO:
1027*991554f2SKenneth D. Merry 		mpr_dprint(sassc->sc, MPR_XINFO,
1028*991554f2SKenneth D. Merry 		    "mprsas_action faking success for abort or reset\n");
1029*991554f2SKenneth D. Merry 		ccb->ccb_h.status = CAM_REQ_CMP;
1030*991554f2SKenneth D. Merry 		break;
1031*991554f2SKenneth D. Merry 	case XPT_SCSI_IO:
1032*991554f2SKenneth D. Merry 		mprsas_action_scsiio(sassc, ccb);
1033*991554f2SKenneth D. Merry 		return;
1034*991554f2SKenneth D. Merry #if __FreeBSD_version >= 900026
1035*991554f2SKenneth D. Merry 	case XPT_SMP_IO:
1036*991554f2SKenneth D. Merry 		mprsas_action_smpio(sassc, ccb);
1037*991554f2SKenneth D. Merry 		return;
1038*991554f2SKenneth D. Merry #endif
1039*991554f2SKenneth D. Merry 	default:
1040*991554f2SKenneth D. Merry 		ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
1041*991554f2SKenneth D. Merry 		break;
1042*991554f2SKenneth D. Merry 	}
1043*991554f2SKenneth D. Merry 	xpt_done(ccb);
1044*991554f2SKenneth D. Merry 
1045*991554f2SKenneth D. Merry }
1046*991554f2SKenneth D. Merry 
1047*991554f2SKenneth D. Merry static void
1048*991554f2SKenneth D. Merry mprsas_announce_reset(struct mpr_softc *sc, uint32_t ac_code,
1049*991554f2SKenneth D. Merry     target_id_t target_id, lun_id_t lun_id)
1050*991554f2SKenneth D. Merry {
1051*991554f2SKenneth D. Merry 	path_id_t path_id = cam_sim_path(sc->sassc->sim);
1052*991554f2SKenneth D. Merry 	struct cam_path *path;
1053*991554f2SKenneth D. Merry 
1054*991554f2SKenneth D. Merry 	mpr_dprint(sc, MPR_XINFO, "%s code %x target %d lun %jx\n", __func__,
1055*991554f2SKenneth D. Merry 	    ac_code, target_id, (uintmax_t)lun_id);
1056*991554f2SKenneth D. Merry 
1057*991554f2SKenneth D. Merry 	if (xpt_create_path(&path, NULL,
1058*991554f2SKenneth D. Merry 		path_id, target_id, lun_id) != CAM_REQ_CMP) {
1059*991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_ERROR, "unable to create path for reset "
1060*991554f2SKenneth D. Merry 			   "notification\n");
1061*991554f2SKenneth D. Merry 		return;
1062*991554f2SKenneth D. Merry 	}
1063*991554f2SKenneth D. Merry 
1064*991554f2SKenneth D. Merry 	xpt_async(ac_code, path, NULL);
1065*991554f2SKenneth D. Merry 	xpt_free_path(path);
1066*991554f2SKenneth D. Merry }
1067*991554f2SKenneth D. Merry 
1068*991554f2SKenneth D. Merry static void
1069*991554f2SKenneth D. Merry mprsas_complete_all_commands(struct mpr_softc *sc)
1070*991554f2SKenneth D. Merry {
1071*991554f2SKenneth D. Merry 	struct mpr_command *cm;
1072*991554f2SKenneth D. Merry 	int i;
1073*991554f2SKenneth D. Merry 	int completed;
1074*991554f2SKenneth D. Merry 
1075*991554f2SKenneth D. Merry 	MPR_FUNCTRACE(sc);
1076*991554f2SKenneth D. Merry 	mtx_assert(&sc->mpr_mtx, MA_OWNED);
1077*991554f2SKenneth D. Merry 
1078*991554f2SKenneth D. Merry 	/* complete all commands with a NULL reply */
1079*991554f2SKenneth D. Merry 	for (i = 1; i < sc->num_reqs; i++) {
1080*991554f2SKenneth D. Merry 		cm = &sc->commands[i];
1081*991554f2SKenneth D. Merry 		cm->cm_reply = NULL;
1082*991554f2SKenneth D. Merry 		completed = 0;
1083*991554f2SKenneth D. Merry 
1084*991554f2SKenneth D. Merry 		if (cm->cm_flags & MPR_CM_FLAGS_POLLED)
1085*991554f2SKenneth D. Merry 			cm->cm_flags |= MPR_CM_FLAGS_COMPLETE;
1086*991554f2SKenneth D. Merry 
1087*991554f2SKenneth D. Merry 		if (cm->cm_complete != NULL) {
1088*991554f2SKenneth D. Merry 			mprsas_log_command(cm, MPR_RECOVERY,
1089*991554f2SKenneth D. Merry 			    "completing cm %p state %x ccb %p for diag reset\n",
1090*991554f2SKenneth D. Merry 			    cm, cm->cm_state, cm->cm_ccb);
1091*991554f2SKenneth D. Merry 			cm->cm_complete(sc, cm);
1092*991554f2SKenneth D. Merry 			completed = 1;
1093*991554f2SKenneth D. Merry 		}
1094*991554f2SKenneth D. Merry 
1095*991554f2SKenneth D. Merry 		if (cm->cm_flags & MPR_CM_FLAGS_WAKEUP) {
1096*991554f2SKenneth D. Merry 			mprsas_log_command(cm, MPR_RECOVERY,
1097*991554f2SKenneth D. Merry 			    "waking up cm %p state %x ccb %p for diag reset\n",
1098*991554f2SKenneth D. Merry 			    cm, cm->cm_state, cm->cm_ccb);
1099*991554f2SKenneth D. Merry 			wakeup(cm);
1100*991554f2SKenneth D. Merry 			completed = 1;
1101*991554f2SKenneth D. Merry 		}
1102*991554f2SKenneth D. Merry 
1103*991554f2SKenneth D. Merry 		if ((completed == 0) && (cm->cm_state != MPR_CM_STATE_FREE)) {
1104*991554f2SKenneth D. Merry 			/* this should never happen, but if it does, log */
1105*991554f2SKenneth D. Merry 			mprsas_log_command(cm, MPR_RECOVERY,
1106*991554f2SKenneth D. Merry 			    "cm %p state %x flags 0x%x ccb %p during diag "
1107*991554f2SKenneth D. Merry 			    "reset\n", cm, cm->cm_state, cm->cm_flags,
1108*991554f2SKenneth D. Merry 			    cm->cm_ccb);
1109*991554f2SKenneth D. Merry 		}
1110*991554f2SKenneth D. Merry 	}
1111*991554f2SKenneth D. Merry }
1112*991554f2SKenneth D. Merry 
1113*991554f2SKenneth D. Merry void
1114*991554f2SKenneth D. Merry mprsas_handle_reinit(struct mpr_softc *sc)
1115*991554f2SKenneth D. Merry {
1116*991554f2SKenneth D. Merry 	int i;
1117*991554f2SKenneth D. Merry 
1118*991554f2SKenneth D. Merry 	/* Go back into startup mode and freeze the simq, so that CAM
1119*991554f2SKenneth D. Merry 	 * doesn't send any commands until after we've rediscovered all
1120*991554f2SKenneth D. Merry 	 * targets and found the proper device handles for them.
1121*991554f2SKenneth D. Merry 	 *
1122*991554f2SKenneth D. Merry 	 * After the reset, portenable will trigger discovery, and after all
1123*991554f2SKenneth D. Merry 	 * discovery-related activities have finished, the simq will be
1124*991554f2SKenneth D. Merry 	 * released.
1125*991554f2SKenneth D. Merry 	 */
1126*991554f2SKenneth D. Merry 	mpr_dprint(sc, MPR_INIT, "%s startup\n", __func__);
1127*991554f2SKenneth D. Merry 	sc->sassc->flags |= MPRSAS_IN_STARTUP;
1128*991554f2SKenneth D. Merry 	sc->sassc->flags |= MPRSAS_IN_DISCOVERY;
1129*991554f2SKenneth D. Merry 	mprsas_startup_increment(sc->sassc);
1130*991554f2SKenneth D. Merry 
1131*991554f2SKenneth D. Merry 	/* notify CAM of a bus reset */
1132*991554f2SKenneth D. Merry 	mprsas_announce_reset(sc, AC_BUS_RESET, CAM_TARGET_WILDCARD,
1133*991554f2SKenneth D. Merry 	    CAM_LUN_WILDCARD);
1134*991554f2SKenneth D. Merry 
1135*991554f2SKenneth D. Merry 	/* complete and cleanup after all outstanding commands */
1136*991554f2SKenneth D. Merry 	mprsas_complete_all_commands(sc);
1137*991554f2SKenneth D. Merry 
1138*991554f2SKenneth D. Merry 	mpr_dprint(sc, MPR_INIT, "%s startup %u tm %u after command "
1139*991554f2SKenneth D. Merry 	    "completion\n", __func__, sc->sassc->startup_refcount,
1140*991554f2SKenneth D. Merry 	    sc->sassc->tm_count);
1141*991554f2SKenneth D. Merry 
1142*991554f2SKenneth D. Merry 	/* zero all the target handles, since they may change after the
1143*991554f2SKenneth D. Merry 	 * reset, and we have to rediscover all the targets and use the new
1144*991554f2SKenneth D. Merry 	 * handles.
1145*991554f2SKenneth D. Merry 	 */
1146*991554f2SKenneth D. Merry 	for (i = 0; i < sc->sassc->maxtargets; i++) {
1147*991554f2SKenneth D. Merry 		if (sc->sassc->targets[i].outstanding != 0)
1148*991554f2SKenneth D. Merry 			mpr_dprint(sc, MPR_INIT, "target %u outstanding %u\n",
1149*991554f2SKenneth D. Merry 			    i, sc->sassc->targets[i].outstanding);
1150*991554f2SKenneth D. Merry 		sc->sassc->targets[i].handle = 0x0;
1151*991554f2SKenneth D. Merry 		sc->sassc->targets[i].exp_dev_handle = 0x0;
1152*991554f2SKenneth D. Merry 		sc->sassc->targets[i].outstanding = 0;
1153*991554f2SKenneth D. Merry 		sc->sassc->targets[i].flags = MPRSAS_TARGET_INDIAGRESET;
1154*991554f2SKenneth D. Merry 	}
1155*991554f2SKenneth D. Merry }
1156*991554f2SKenneth D. Merry static void
1157*991554f2SKenneth D. Merry mprsas_tm_timeout(void *data)
1158*991554f2SKenneth D. Merry {
1159*991554f2SKenneth D. Merry 	struct mpr_command *tm = data;
1160*991554f2SKenneth D. Merry 	struct mpr_softc *sc = tm->cm_sc;
1161*991554f2SKenneth D. Merry 
1162*991554f2SKenneth D. Merry 	mtx_assert(&sc->mpr_mtx, MA_OWNED);
1163*991554f2SKenneth D. Merry 
1164*991554f2SKenneth D. Merry 	mprsas_log_command(tm, MPR_INFO|MPR_RECOVERY,
1165*991554f2SKenneth D. Merry 	    "task mgmt %p timed out\n", tm);
1166*991554f2SKenneth D. Merry 	mpr_reinit(sc);
1167*991554f2SKenneth D. Merry }
1168*991554f2SKenneth D. Merry 
1169*991554f2SKenneth D. Merry static void
1170*991554f2SKenneth D. Merry mprsas_logical_unit_reset_complete(struct mpr_softc *sc,
1171*991554f2SKenneth D. Merry     struct mpr_command *tm)
1172*991554f2SKenneth D. Merry {
1173*991554f2SKenneth D. Merry 	MPI2_SCSI_TASK_MANAGE_REPLY *reply;
1174*991554f2SKenneth D. Merry 	MPI2_SCSI_TASK_MANAGE_REQUEST *req;
1175*991554f2SKenneth D. Merry 	unsigned int cm_count = 0;
1176*991554f2SKenneth D. Merry 	struct mpr_command *cm;
1177*991554f2SKenneth D. Merry 	struct mprsas_target *targ;
1178*991554f2SKenneth D. Merry 
1179*991554f2SKenneth D. Merry 	callout_stop(&tm->cm_callout);
1180*991554f2SKenneth D. Merry 
1181*991554f2SKenneth D. Merry 	req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req;
1182*991554f2SKenneth D. Merry 	reply = (MPI2_SCSI_TASK_MANAGE_REPLY *)tm->cm_reply;
1183*991554f2SKenneth D. Merry 	targ = tm->cm_targ;
1184*991554f2SKenneth D. Merry 
1185*991554f2SKenneth D. Merry 	/*
1186*991554f2SKenneth D. Merry 	 * Currently there should be no way we can hit this case.  It only
1187*991554f2SKenneth D. Merry 	 * happens when we have a failure to allocate chain frames, and
1188*991554f2SKenneth D. Merry 	 * task management commands don't have S/G lists.
1189*991554f2SKenneth D. Merry 	 */
1190*991554f2SKenneth D. Merry 	if ((tm->cm_flags & MPR_CM_FLAGS_ERROR_MASK) != 0) {
1191*991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_ERROR, "%s: cm_flags = %#x for LUN reset! "
1192*991554f2SKenneth D. Merry 		    "This should not happen!\n", __func__, tm->cm_flags);
1193*991554f2SKenneth D. Merry 		mprsas_free_tm(sc, tm);
1194*991554f2SKenneth D. Merry 		return;
1195*991554f2SKenneth D. Merry 	}
1196*991554f2SKenneth D. Merry 
1197*991554f2SKenneth D. Merry 	if (reply == NULL) {
1198*991554f2SKenneth D. Merry 		mprsas_log_command(tm, MPR_RECOVERY,
1199*991554f2SKenneth D. Merry 		    "NULL reset reply for tm %p\n", tm);
1200*991554f2SKenneth D. Merry 		if ((sc->mpr_flags & MPR_FLAGS_DIAGRESET) != 0) {
1201*991554f2SKenneth D. Merry 			/* this completion was due to a reset, just cleanup */
1202*991554f2SKenneth D. Merry 			targ->flags &= ~MPRSAS_TARGET_INRESET;
1203*991554f2SKenneth D. Merry 			targ->tm = NULL;
1204*991554f2SKenneth D. Merry 			mprsas_free_tm(sc, tm);
1205*991554f2SKenneth D. Merry 		}
1206*991554f2SKenneth D. Merry 		else {
1207*991554f2SKenneth D. Merry 			/* we should have gotten a reply. */
1208*991554f2SKenneth D. Merry 			mpr_reinit(sc);
1209*991554f2SKenneth D. Merry 		}
1210*991554f2SKenneth D. Merry 		return;
1211*991554f2SKenneth D. Merry 	}
1212*991554f2SKenneth D. Merry 
1213*991554f2SKenneth D. Merry 	mprsas_log_command(tm, MPR_RECOVERY,
1214*991554f2SKenneth D. Merry 	    "logical unit reset status 0x%x code 0x%x count %u\n",
1215*991554f2SKenneth D. Merry 	    le16toh(reply->IOCStatus), le32toh(reply->ResponseCode),
1216*991554f2SKenneth D. Merry 	    le32toh(reply->TerminationCount));
1217*991554f2SKenneth D. Merry 
1218*991554f2SKenneth D. Merry 	/* See if there are any outstanding commands for this LUN.
1219*991554f2SKenneth D. Merry 	 * This could be made more efficient by using a per-LU data
1220*991554f2SKenneth D. Merry 	 * structure of some sort.
1221*991554f2SKenneth D. Merry 	 */
1222*991554f2SKenneth D. Merry 	TAILQ_FOREACH(cm, &targ->commands, cm_link) {
1223*991554f2SKenneth D. Merry 		if (cm->cm_lun == tm->cm_lun)
1224*991554f2SKenneth D. Merry 			cm_count++;
1225*991554f2SKenneth D. Merry 	}
1226*991554f2SKenneth D. Merry 
1227*991554f2SKenneth D. Merry 	if (cm_count == 0) {
1228*991554f2SKenneth D. Merry 		mprsas_log_command(tm, MPR_RECOVERY|MPR_INFO,
1229*991554f2SKenneth D. Merry 		    "logical unit %u finished recovery after reset\n",
1230*991554f2SKenneth D. Merry 		    tm->cm_lun, tm);
1231*991554f2SKenneth D. Merry 
1232*991554f2SKenneth D. Merry 		mprsas_announce_reset(sc, AC_SENT_BDR, tm->cm_targ->tid,
1233*991554f2SKenneth D. Merry 		    tm->cm_lun);
1234*991554f2SKenneth D. Merry 
1235*991554f2SKenneth D. Merry 		/* we've finished recovery for this logical unit.  check and
1236*991554f2SKenneth D. Merry 		 * see if some other logical unit has a timedout command
1237*991554f2SKenneth D. Merry 		 * that needs to be processed.
1238*991554f2SKenneth D. Merry 		 */
1239*991554f2SKenneth D. Merry 		cm = TAILQ_FIRST(&targ->timedout_commands);
1240*991554f2SKenneth D. Merry 		if (cm) {
1241*991554f2SKenneth D. Merry 			mprsas_send_abort(sc, tm, cm);
1242*991554f2SKenneth D. Merry 		}
1243*991554f2SKenneth D. Merry 		else {
1244*991554f2SKenneth D. Merry 			targ->tm = NULL;
1245*991554f2SKenneth D. Merry 			mprsas_free_tm(sc, tm);
1246*991554f2SKenneth D. Merry 		}
1247*991554f2SKenneth D. Merry 	}
1248*991554f2SKenneth D. Merry 	else {
1249*991554f2SKenneth D. Merry 		/* if we still have commands for this LUN, the reset
1250*991554f2SKenneth D. Merry 		 * effectively failed, regardless of the status reported.
1251*991554f2SKenneth D. Merry 		 * Escalate to a target reset.
1252*991554f2SKenneth D. Merry 		 */
1253*991554f2SKenneth D. Merry 		mprsas_log_command(tm, MPR_RECOVERY,
1254*991554f2SKenneth D. Merry 		    "logical unit reset complete for tm %p, but still have %u "
1255*991554f2SKenneth D. Merry 		    "command(s)\n", tm, cm_count);
1256*991554f2SKenneth D. Merry 		mprsas_send_reset(sc, tm,
1257*991554f2SKenneth D. Merry 		    MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET);
1258*991554f2SKenneth D. Merry 	}
1259*991554f2SKenneth D. Merry }
1260*991554f2SKenneth D. Merry 
1261*991554f2SKenneth D. Merry static void
1262*991554f2SKenneth D. Merry mprsas_target_reset_complete(struct mpr_softc *sc, struct mpr_command *tm)
1263*991554f2SKenneth D. Merry {
1264*991554f2SKenneth D. Merry 	MPI2_SCSI_TASK_MANAGE_REPLY *reply;
1265*991554f2SKenneth D. Merry 	MPI2_SCSI_TASK_MANAGE_REQUEST *req;
1266*991554f2SKenneth D. Merry 	struct mprsas_target *targ;
1267*991554f2SKenneth D. Merry 
1268*991554f2SKenneth D. Merry 	callout_stop(&tm->cm_callout);
1269*991554f2SKenneth D. Merry 
1270*991554f2SKenneth D. Merry 	req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req;
1271*991554f2SKenneth D. Merry 	reply = (MPI2_SCSI_TASK_MANAGE_REPLY *)tm->cm_reply;
1272*991554f2SKenneth D. Merry 	targ = tm->cm_targ;
1273*991554f2SKenneth D. Merry 
1274*991554f2SKenneth D. Merry 	/*
1275*991554f2SKenneth D. Merry 	 * Currently there should be no way we can hit this case.  It only
1276*991554f2SKenneth D. Merry 	 * happens when we have a failure to allocate chain frames, and
1277*991554f2SKenneth D. Merry 	 * task management commands don't have S/G lists.
1278*991554f2SKenneth D. Merry 	 */
1279*991554f2SKenneth D. Merry 	if ((tm->cm_flags & MPR_CM_FLAGS_ERROR_MASK) != 0) {
1280*991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_ERROR,"%s: cm_flags = %#x for target reset! "
1281*991554f2SKenneth D. Merry 		    "This should not happen!\n", __func__, tm->cm_flags);
1282*991554f2SKenneth D. Merry 		mprsas_free_tm(sc, tm);
1283*991554f2SKenneth D. Merry 		return;
1284*991554f2SKenneth D. Merry 	}
1285*991554f2SKenneth D. Merry 
1286*991554f2SKenneth D. Merry 	if (reply == NULL) {
1287*991554f2SKenneth D. Merry 		mprsas_log_command(tm, MPR_RECOVERY,
1288*991554f2SKenneth D. Merry 		    "NULL reset reply for tm %p\n", tm);
1289*991554f2SKenneth D. Merry 		if ((sc->mpr_flags & MPR_FLAGS_DIAGRESET) != 0) {
1290*991554f2SKenneth D. Merry 			/* this completion was due to a reset, just cleanup */
1291*991554f2SKenneth D. Merry 			targ->flags &= ~MPRSAS_TARGET_INRESET;
1292*991554f2SKenneth D. Merry 			targ->tm = NULL;
1293*991554f2SKenneth D. Merry 			mprsas_free_tm(sc, tm);
1294*991554f2SKenneth D. Merry 		}
1295*991554f2SKenneth D. Merry 		else {
1296*991554f2SKenneth D. Merry 			/* we should have gotten a reply. */
1297*991554f2SKenneth D. Merry 			mpr_reinit(sc);
1298*991554f2SKenneth D. Merry 		}
1299*991554f2SKenneth D. Merry 		return;
1300*991554f2SKenneth D. Merry 	}
1301*991554f2SKenneth D. Merry 
1302*991554f2SKenneth D. Merry 	mprsas_log_command(tm, MPR_RECOVERY,
1303*991554f2SKenneth D. Merry 	    "target reset status 0x%x code 0x%x count %u\n",
1304*991554f2SKenneth D. Merry 	    le16toh(reply->IOCStatus), le32toh(reply->ResponseCode),
1305*991554f2SKenneth D. Merry 	    le32toh(reply->TerminationCount));
1306*991554f2SKenneth D. Merry 
1307*991554f2SKenneth D. Merry 	targ->flags &= ~MPRSAS_TARGET_INRESET;
1308*991554f2SKenneth D. Merry 
1309*991554f2SKenneth D. Merry 	if (targ->outstanding == 0) {
1310*991554f2SKenneth D. Merry 		/* we've finished recovery for this target and all
1311*991554f2SKenneth D. Merry 		 * of its logical units.
1312*991554f2SKenneth D. Merry 		 */
1313*991554f2SKenneth D. Merry 		mprsas_log_command(tm, MPR_RECOVERY|MPR_INFO,
1314*991554f2SKenneth D. Merry 		    "recovery finished after target reset\n");
1315*991554f2SKenneth D. Merry 
1316*991554f2SKenneth D. Merry 		mprsas_announce_reset(sc, AC_SENT_BDR, tm->cm_targ->tid,
1317*991554f2SKenneth D. Merry 		    CAM_LUN_WILDCARD);
1318*991554f2SKenneth D. Merry 
1319*991554f2SKenneth D. Merry 		targ->tm = NULL;
1320*991554f2SKenneth D. Merry 		mprsas_free_tm(sc, tm);
1321*991554f2SKenneth D. Merry 	}
1322*991554f2SKenneth D. Merry 	else {
1323*991554f2SKenneth D. Merry 		/* after a target reset, if this target still has
1324*991554f2SKenneth D. Merry 		 * outstanding commands, the reset effectively failed,
1325*991554f2SKenneth D. Merry 		 * regardless of the status reported.  escalate.
1326*991554f2SKenneth D. Merry 		 */
1327*991554f2SKenneth D. Merry 		mprsas_log_command(tm, MPR_RECOVERY,
1328*991554f2SKenneth D. Merry 		    "target reset complete for tm %p, but still have %u "
1329*991554f2SKenneth D. Merry 		    "command(s)\n", tm, targ->outstanding);
1330*991554f2SKenneth D. Merry 		mpr_reinit(sc);
1331*991554f2SKenneth D. Merry 	}
1332*991554f2SKenneth D. Merry }
1333*991554f2SKenneth D. Merry 
1334*991554f2SKenneth D. Merry #define MPR_RESET_TIMEOUT 30
1335*991554f2SKenneth D. Merry 
1336*991554f2SKenneth D. Merry static int
1337*991554f2SKenneth D. Merry mprsas_send_reset(struct mpr_softc *sc, struct mpr_command *tm, uint8_t type)
1338*991554f2SKenneth D. Merry {
1339*991554f2SKenneth D. Merry 	MPI2_SCSI_TASK_MANAGE_REQUEST *req;
1340*991554f2SKenneth D. Merry 	struct mprsas_target *target;
1341*991554f2SKenneth D. Merry 	int err;
1342*991554f2SKenneth D. Merry 
1343*991554f2SKenneth D. Merry 	target = tm->cm_targ;
1344*991554f2SKenneth D. Merry 	if (target->handle == 0) {
1345*991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_ERROR,"%s null devhandle for target_id %d\n",
1346*991554f2SKenneth D. Merry 		    __func__, target->tid);
1347*991554f2SKenneth D. Merry 		return -1;
1348*991554f2SKenneth D. Merry 	}
1349*991554f2SKenneth D. Merry 
1350*991554f2SKenneth D. Merry 	req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req;
1351*991554f2SKenneth D. Merry 	req->DevHandle = htole16(target->handle);
1352*991554f2SKenneth D. Merry 	req->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
1353*991554f2SKenneth D. Merry 	req->TaskType = type;
1354*991554f2SKenneth D. Merry 
1355*991554f2SKenneth D. Merry 	if (type == MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET) {
1356*991554f2SKenneth D. Merry 		/* XXX Need to handle invalid LUNs */
1357*991554f2SKenneth D. Merry 		MPR_SET_LUN(req->LUN, tm->cm_lun);
1358*991554f2SKenneth D. Merry 		tm->cm_targ->logical_unit_resets++;
1359*991554f2SKenneth D. Merry 		mprsas_log_command(tm, MPR_RECOVERY|MPR_INFO,
1360*991554f2SKenneth D. Merry 		    "sending logical unit reset\n");
1361*991554f2SKenneth D. Merry 		tm->cm_complete = mprsas_logical_unit_reset_complete;
1362*991554f2SKenneth D. Merry 	}
1363*991554f2SKenneth D. Merry 	else if (type == MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET) {
1364*991554f2SKenneth D. Merry 		/*
1365*991554f2SKenneth D. Merry 		 * Target reset method =
1366*991554f2SKenneth D. Merry 		 *     SAS Hard Link Reset / SATA Link Reset
1367*991554f2SKenneth D. Merry 		 */
1368*991554f2SKenneth D. Merry 		req->MsgFlags = MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET;
1369*991554f2SKenneth D. Merry 		tm->cm_targ->target_resets++;
1370*991554f2SKenneth D. Merry 		tm->cm_targ->flags |= MPRSAS_TARGET_INRESET;
1371*991554f2SKenneth D. Merry 		mprsas_log_command(tm, MPR_RECOVERY|MPR_INFO,
1372*991554f2SKenneth D. Merry 		    "sending target reset\n");
1373*991554f2SKenneth D. Merry 		tm->cm_complete = mprsas_target_reset_complete;
1374*991554f2SKenneth D. Merry 	}
1375*991554f2SKenneth D. Merry 	else {
1376*991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_ERROR, "unexpected reset type 0x%x\n", type);
1377*991554f2SKenneth D. Merry 		return -1;
1378*991554f2SKenneth D. Merry 	}
1379*991554f2SKenneth D. Merry 
1380*991554f2SKenneth D. Merry 	mpr_dprint(sc, MPR_XINFO, "to target %u handle 0x%04x\n", target->tid,
1381*991554f2SKenneth D. Merry 	    target->handle);
1382*991554f2SKenneth D. Merry 	if (target->encl_level_valid) {
1383*991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_XINFO, "At enclosure level %d, slot %d, "
1384*991554f2SKenneth D. Merry 		    "connector name (%4s)\n", target->encl_level,
1385*991554f2SKenneth D. Merry 		    target->encl_slot, target->connector_name);
1386*991554f2SKenneth D. Merry 	}
1387*991554f2SKenneth D. Merry 
1388*991554f2SKenneth D. Merry 	tm->cm_data = NULL;
1389*991554f2SKenneth D. Merry 	tm->cm_desc.HighPriority.RequestFlags =
1390*991554f2SKenneth D. Merry 	    MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY;
1391*991554f2SKenneth D. Merry 	tm->cm_complete_data = (void *)tm;
1392*991554f2SKenneth D. Merry 
1393*991554f2SKenneth D. Merry 	callout_reset(&tm->cm_callout, MPR_RESET_TIMEOUT * hz,
1394*991554f2SKenneth D. Merry 	    mprsas_tm_timeout, tm);
1395*991554f2SKenneth D. Merry 
1396*991554f2SKenneth D. Merry 	err = mpr_map_command(sc, tm);
1397*991554f2SKenneth D. Merry 	if (err)
1398*991554f2SKenneth D. Merry 		mprsas_log_command(tm, MPR_RECOVERY,
1399*991554f2SKenneth D. Merry 		    "error %d sending reset type %u\n",
1400*991554f2SKenneth D. Merry 		    err, type);
1401*991554f2SKenneth D. Merry 
1402*991554f2SKenneth D. Merry 	return err;
1403*991554f2SKenneth D. Merry }
1404*991554f2SKenneth D. Merry 
1405*991554f2SKenneth D. Merry 
1406*991554f2SKenneth D. Merry static void
1407*991554f2SKenneth D. Merry mprsas_abort_complete(struct mpr_softc *sc, struct mpr_command *tm)
1408*991554f2SKenneth D. Merry {
1409*991554f2SKenneth D. Merry 	struct mpr_command *cm;
1410*991554f2SKenneth D. Merry 	MPI2_SCSI_TASK_MANAGE_REPLY *reply;
1411*991554f2SKenneth D. Merry 	MPI2_SCSI_TASK_MANAGE_REQUEST *req;
1412*991554f2SKenneth D. Merry 	struct mprsas_target *targ;
1413*991554f2SKenneth D. Merry 
1414*991554f2SKenneth D. Merry 	callout_stop(&tm->cm_callout);
1415*991554f2SKenneth D. Merry 
1416*991554f2SKenneth D. Merry 	req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req;
1417*991554f2SKenneth D. Merry 	reply = (MPI2_SCSI_TASK_MANAGE_REPLY *)tm->cm_reply;
1418*991554f2SKenneth D. Merry 	targ = tm->cm_targ;
1419*991554f2SKenneth D. Merry 
1420*991554f2SKenneth D. Merry 	/*
1421*991554f2SKenneth D. Merry 	 * Currently there should be no way we can hit this case.  It only
1422*991554f2SKenneth D. Merry 	 * happens when we have a failure to allocate chain frames, and
1423*991554f2SKenneth D. Merry 	 * task management commands don't have S/G lists.
1424*991554f2SKenneth D. Merry 	 */
1425*991554f2SKenneth D. Merry 	if ((tm->cm_flags & MPR_CM_FLAGS_ERROR_MASK) != 0) {
1426*991554f2SKenneth D. Merry 		mprsas_log_command(tm, MPR_RECOVERY,
1427*991554f2SKenneth D. Merry 		    "cm_flags = %#x for abort %p TaskMID %u!\n",
1428*991554f2SKenneth D. Merry 		    tm->cm_flags, tm, le16toh(req->TaskMID));
1429*991554f2SKenneth D. Merry 		mprsas_free_tm(sc, tm);
1430*991554f2SKenneth D. Merry 		return;
1431*991554f2SKenneth D. Merry 	}
1432*991554f2SKenneth D. Merry 
1433*991554f2SKenneth D. Merry 	if (reply == NULL) {
1434*991554f2SKenneth D. Merry 		mprsas_log_command(tm, MPR_RECOVERY,
1435*991554f2SKenneth D. Merry 		    "NULL abort reply for tm %p TaskMID %u\n",
1436*991554f2SKenneth D. Merry 		    tm, le16toh(req->TaskMID));
1437*991554f2SKenneth D. Merry 		if ((sc->mpr_flags & MPR_FLAGS_DIAGRESET) != 0) {
1438*991554f2SKenneth D. Merry 			/* this completion was due to a reset, just cleanup */
1439*991554f2SKenneth D. Merry 			targ->tm = NULL;
1440*991554f2SKenneth D. Merry 			mprsas_free_tm(sc, tm);
1441*991554f2SKenneth D. Merry 		}
1442*991554f2SKenneth D. Merry 		else {
1443*991554f2SKenneth D. Merry 			/* we should have gotten a reply. */
1444*991554f2SKenneth D. Merry 			mpr_reinit(sc);
1445*991554f2SKenneth D. Merry 		}
1446*991554f2SKenneth D. Merry 		return;
1447*991554f2SKenneth D. Merry 	}
1448*991554f2SKenneth D. Merry 
1449*991554f2SKenneth D. Merry 	mprsas_log_command(tm, MPR_RECOVERY,
1450*991554f2SKenneth D. Merry 	    "abort TaskMID %u status 0x%x code 0x%x count %u\n",
1451*991554f2SKenneth D. Merry 	    le16toh(req->TaskMID),
1452*991554f2SKenneth D. Merry 	    le16toh(reply->IOCStatus), le32toh(reply->ResponseCode),
1453*991554f2SKenneth D. Merry 	    le32toh(reply->TerminationCount));
1454*991554f2SKenneth D. Merry 
1455*991554f2SKenneth D. Merry 	cm = TAILQ_FIRST(&tm->cm_targ->timedout_commands);
1456*991554f2SKenneth D. Merry 	if (cm == NULL) {
1457*991554f2SKenneth D. Merry 		/* if there are no more timedout commands, we're done with
1458*991554f2SKenneth D. Merry 		 * error recovery for this target.
1459*991554f2SKenneth D. Merry 		 */
1460*991554f2SKenneth D. Merry 		mprsas_log_command(tm, MPR_RECOVERY,
1461*991554f2SKenneth D. Merry 		    "finished recovery after aborting TaskMID %u\n",
1462*991554f2SKenneth D. Merry 		    le16toh(req->TaskMID));
1463*991554f2SKenneth D. Merry 
1464*991554f2SKenneth D. Merry 		targ->tm = NULL;
1465*991554f2SKenneth D. Merry 		mprsas_free_tm(sc, tm);
1466*991554f2SKenneth D. Merry 	}
1467*991554f2SKenneth D. Merry 	else if (le16toh(req->TaskMID) != cm->cm_desc.Default.SMID) {
1468*991554f2SKenneth D. Merry 		/* abort success, but we have more timedout commands to abort */
1469*991554f2SKenneth D. Merry 		mprsas_log_command(tm, MPR_RECOVERY,
1470*991554f2SKenneth D. Merry 		    "continuing recovery after aborting TaskMID %u\n",
1471*991554f2SKenneth D. Merry 		    le16toh(req->TaskMID));
1472*991554f2SKenneth D. Merry 
1473*991554f2SKenneth D. Merry 		mprsas_send_abort(sc, tm, cm);
1474*991554f2SKenneth D. Merry 	}
1475*991554f2SKenneth D. Merry 	else {
1476*991554f2SKenneth D. Merry 		/* we didn't get a command completion, so the abort
1477*991554f2SKenneth D. Merry 		 * failed as far as we're concerned.  escalate.
1478*991554f2SKenneth D. Merry 		 */
1479*991554f2SKenneth D. Merry 		mprsas_log_command(tm, MPR_RECOVERY,
1480*991554f2SKenneth D. Merry 		    "abort failed for TaskMID %u tm %p\n",
1481*991554f2SKenneth D. Merry 		    le16toh(req->TaskMID), tm);
1482*991554f2SKenneth D. Merry 
1483*991554f2SKenneth D. Merry 		mprsas_send_reset(sc, tm,
1484*991554f2SKenneth D. Merry 		    MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET);
1485*991554f2SKenneth D. Merry 	}
1486*991554f2SKenneth D. Merry }
1487*991554f2SKenneth D. Merry 
1488*991554f2SKenneth D. Merry #define MPR_ABORT_TIMEOUT 5
1489*991554f2SKenneth D. Merry 
1490*991554f2SKenneth D. Merry static int
1491*991554f2SKenneth D. Merry mprsas_send_abort(struct mpr_softc *sc, struct mpr_command *tm,
1492*991554f2SKenneth D. Merry     struct mpr_command *cm)
1493*991554f2SKenneth D. Merry {
1494*991554f2SKenneth D. Merry 	MPI2_SCSI_TASK_MANAGE_REQUEST *req;
1495*991554f2SKenneth D. Merry 	struct mprsas_target *targ;
1496*991554f2SKenneth D. Merry 	int err;
1497*991554f2SKenneth D. Merry 
1498*991554f2SKenneth D. Merry 	targ = cm->cm_targ;
1499*991554f2SKenneth D. Merry 	if (targ->handle == 0) {
1500*991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_ERROR,"%s null devhandle for target_id %d\n",
1501*991554f2SKenneth D. Merry 		    __func__, cm->cm_ccb->ccb_h.target_id);
1502*991554f2SKenneth D. Merry 		return -1;
1503*991554f2SKenneth D. Merry 	}
1504*991554f2SKenneth D. Merry 
1505*991554f2SKenneth D. Merry 	mprsas_log_command(tm, MPR_RECOVERY|MPR_INFO,
1506*991554f2SKenneth D. Merry 	    "Aborting command %p\n", cm);
1507*991554f2SKenneth D. Merry 
1508*991554f2SKenneth D. Merry 	req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req;
1509*991554f2SKenneth D. Merry 	req->DevHandle = htole16(targ->handle);
1510*991554f2SKenneth D. Merry 	req->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
1511*991554f2SKenneth D. Merry 	req->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK;
1512*991554f2SKenneth D. Merry 
1513*991554f2SKenneth D. Merry 	/* XXX Need to handle invalid LUNs */
1514*991554f2SKenneth D. Merry 	MPR_SET_LUN(req->LUN, cm->cm_ccb->ccb_h.target_lun);
1515*991554f2SKenneth D. Merry 
1516*991554f2SKenneth D. Merry 	req->TaskMID = htole16(cm->cm_desc.Default.SMID);
1517*991554f2SKenneth D. Merry 
1518*991554f2SKenneth D. Merry 	tm->cm_data = NULL;
1519*991554f2SKenneth D. Merry 	tm->cm_desc.HighPriority.RequestFlags =
1520*991554f2SKenneth D. Merry 	    MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY;
1521*991554f2SKenneth D. Merry 	tm->cm_complete = mprsas_abort_complete;
1522*991554f2SKenneth D. Merry 	tm->cm_complete_data = (void *)tm;
1523*991554f2SKenneth D. Merry 	tm->cm_targ = cm->cm_targ;
1524*991554f2SKenneth D. Merry 	tm->cm_lun = cm->cm_lun;
1525*991554f2SKenneth D. Merry 
1526*991554f2SKenneth D. Merry 	callout_reset(&tm->cm_callout, MPR_ABORT_TIMEOUT * hz,
1527*991554f2SKenneth D. Merry 	    mprsas_tm_timeout, tm);
1528*991554f2SKenneth D. Merry 
1529*991554f2SKenneth D. Merry 	targ->aborts++;
1530*991554f2SKenneth D. Merry 
1531*991554f2SKenneth D. Merry 	err = mpr_map_command(sc, tm);
1532*991554f2SKenneth D. Merry 	if (err)
1533*991554f2SKenneth D. Merry 		mprsas_log_command(tm, MPR_RECOVERY,
1534*991554f2SKenneth D. Merry 		    "error %d sending abort for cm %p SMID %u\n",
1535*991554f2SKenneth D. Merry 		    err, cm, req->TaskMID);
1536*991554f2SKenneth D. Merry 	return err;
1537*991554f2SKenneth D. Merry }
1538*991554f2SKenneth D. Merry 
1539*991554f2SKenneth D. Merry 
1540*991554f2SKenneth D. Merry static void
1541*991554f2SKenneth D. Merry mprsas_scsiio_timeout(void *data)
1542*991554f2SKenneth D. Merry {
1543*991554f2SKenneth D. Merry 	struct mpr_softc *sc;
1544*991554f2SKenneth D. Merry 	struct mpr_command *cm;
1545*991554f2SKenneth D. Merry 	struct mprsas_target *targ;
1546*991554f2SKenneth D. Merry 
1547*991554f2SKenneth D. Merry 	cm = (struct mpr_command *)data;
1548*991554f2SKenneth D. Merry 	sc = cm->cm_sc;
1549*991554f2SKenneth D. Merry 
1550*991554f2SKenneth D. Merry 	MPR_FUNCTRACE(sc);
1551*991554f2SKenneth D. Merry 	mtx_assert(&sc->mpr_mtx, MA_OWNED);
1552*991554f2SKenneth D. Merry 
1553*991554f2SKenneth D. Merry 	mpr_dprint(sc, MPR_XINFO, "Timeout checking cm %p\n", cm);
1554*991554f2SKenneth D. Merry 
1555*991554f2SKenneth D. Merry 	/*
1556*991554f2SKenneth D. Merry 	 * Run the interrupt handler to make sure it's not pending.  This
1557*991554f2SKenneth D. Merry 	 * isn't perfect because the command could have already completed
1558*991554f2SKenneth D. Merry 	 * and been re-used, though this is unlikely.
1559*991554f2SKenneth D. Merry 	 */
1560*991554f2SKenneth D. Merry 	mpr_intr_locked(sc);
1561*991554f2SKenneth D. Merry 	if (cm->cm_state == MPR_CM_STATE_FREE) {
1562*991554f2SKenneth D. Merry 		mprsas_log_command(cm, MPR_XINFO,
1563*991554f2SKenneth D. Merry 		    "SCSI command %p almost timed out\n", cm);
1564*991554f2SKenneth D. Merry 		return;
1565*991554f2SKenneth D. Merry 	}
1566*991554f2SKenneth D. Merry 
1567*991554f2SKenneth D. Merry 	if (cm->cm_ccb == NULL) {
1568*991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_ERROR, "command timeout with NULL ccb\n");
1569*991554f2SKenneth D. Merry 		return;
1570*991554f2SKenneth D. Merry 	}
1571*991554f2SKenneth D. Merry 
1572*991554f2SKenneth D. Merry 	targ = cm->cm_targ;
1573*991554f2SKenneth D. Merry 	targ->timeouts++;
1574*991554f2SKenneth D. Merry 
1575*991554f2SKenneth D. Merry 	mprsas_log_command(cm, MPR_XINFO, "command timeout cm %p ccb %p "
1576*991554f2SKenneth D. Merry 	    "target %u, handle(0x%04x)\n", cm, cm->cm_ccb, targ->tid,
1577*991554f2SKenneth D. Merry 	    targ->handle);
1578*991554f2SKenneth D. Merry 	if (targ->encl_level_valid) {
1579*991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_XINFO, "At enclosure level %d, slot %d, "
1580*991554f2SKenneth D. Merry 		    "connector name (%4s)\n", targ->encl_level, targ->encl_slot,
1581*991554f2SKenneth D. Merry 		    targ->connector_name);
1582*991554f2SKenneth D. Merry 	}
1583*991554f2SKenneth D. Merry 
1584*991554f2SKenneth D. Merry 	/* XXX first, check the firmware state, to see if it's still
1585*991554f2SKenneth D. Merry 	 * operational.  if not, do a diag reset.
1586*991554f2SKenneth D. Merry 	 */
1587*991554f2SKenneth D. Merry 
1588*991554f2SKenneth D. Merry 	cm->cm_ccb->ccb_h.status = CAM_CMD_TIMEOUT;
1589*991554f2SKenneth D. Merry 	cm->cm_state = MPR_CM_STATE_TIMEDOUT;
1590*991554f2SKenneth D. Merry 	TAILQ_INSERT_TAIL(&targ->timedout_commands, cm, cm_recovery);
1591*991554f2SKenneth D. Merry 
1592*991554f2SKenneth D. Merry 	if (targ->tm != NULL) {
1593*991554f2SKenneth D. Merry 		/* target already in recovery, just queue up another
1594*991554f2SKenneth D. Merry 		 * timedout command to be processed later.
1595*991554f2SKenneth D. Merry 		 */
1596*991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_RECOVERY, "queued timedout cm %p for "
1597*991554f2SKenneth D. Merry 		    "processing by tm %p\n", cm, targ->tm);
1598*991554f2SKenneth D. Merry 	}
1599*991554f2SKenneth D. Merry 	else if ((targ->tm = mprsas_alloc_tm(sc)) != NULL) {
1600*991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_RECOVERY, "timedout cm %p allocated tm %p\n",
1601*991554f2SKenneth D. Merry 		    cm, targ->tm);
1602*991554f2SKenneth D. Merry 
1603*991554f2SKenneth D. Merry 		/* start recovery by aborting the first timedout command */
1604*991554f2SKenneth D. Merry 		mprsas_send_abort(sc, targ->tm, cm);
1605*991554f2SKenneth D. Merry 	}
1606*991554f2SKenneth D. Merry 	else {
1607*991554f2SKenneth D. Merry 		/* XXX queue this target up for recovery once a TM becomes
1608*991554f2SKenneth D. Merry 		 * available.  The firmware only has a limited number of
1609*991554f2SKenneth D. Merry 		 * HighPriority credits for the high priority requests used
1610*991554f2SKenneth D. Merry 		 * for task management, and we ran out.
1611*991554f2SKenneth D. Merry 		 *
1612*991554f2SKenneth D. Merry 		 * Isilon: don't worry about this for now, since we have
1613*991554f2SKenneth D. Merry 		 * more credits than disks in an enclosure, and limit
1614*991554f2SKenneth D. Merry 		 * ourselves to one TM per target for recovery.
1615*991554f2SKenneth D. Merry 		 */
1616*991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_RECOVERY,
1617*991554f2SKenneth D. Merry 		    "timedout cm %p failed to allocate a tm\n", cm);
1618*991554f2SKenneth D. Merry 	}
1619*991554f2SKenneth D. Merry }
1620*991554f2SKenneth D. Merry 
1621*991554f2SKenneth D. Merry static void
1622*991554f2SKenneth D. Merry mprsas_action_scsiio(struct mprsas_softc *sassc, union ccb *ccb)
1623*991554f2SKenneth D. Merry {
1624*991554f2SKenneth D. Merry 	MPI2_SCSI_IO_REQUEST *req;
1625*991554f2SKenneth D. Merry 	struct ccb_scsiio *csio;
1626*991554f2SKenneth D. Merry 	struct mpr_softc *sc;
1627*991554f2SKenneth D. Merry 	struct mprsas_target *targ;
1628*991554f2SKenneth D. Merry 	struct mprsas_lun *lun;
1629*991554f2SKenneth D. Merry 	struct mpr_command *cm;
1630*991554f2SKenneth D. Merry 	uint8_t i, lba_byte, *ref_tag_addr;
1631*991554f2SKenneth D. Merry 	uint16_t eedp_flags;
1632*991554f2SKenneth D. Merry 	uint32_t mpi_control;
1633*991554f2SKenneth D. Merry 
1634*991554f2SKenneth D. Merry 	sc = sassc->sc;
1635*991554f2SKenneth D. Merry 	MPR_FUNCTRACE(sc);
1636*991554f2SKenneth D. Merry 	mtx_assert(&sc->mpr_mtx, MA_OWNED);
1637*991554f2SKenneth D. Merry 
1638*991554f2SKenneth D. Merry 	csio = &ccb->csio;
1639*991554f2SKenneth D. Merry 	targ = &sassc->targets[csio->ccb_h.target_id];
1640*991554f2SKenneth D. Merry 	mpr_dprint(sc, MPR_TRACE, "ccb %p target flag %x\n", ccb, targ->flags);
1641*991554f2SKenneth D. Merry 	if (targ->handle == 0x0) {
1642*991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_ERROR, "%s NULL handle for target %u\n",
1643*991554f2SKenneth D. Merry 		    __func__, csio->ccb_h.target_id);
1644*991554f2SKenneth D. Merry 		csio->ccb_h.status = CAM_DEV_NOT_THERE;
1645*991554f2SKenneth D. Merry 		xpt_done(ccb);
1646*991554f2SKenneth D. Merry 		return;
1647*991554f2SKenneth D. Merry 	}
1648*991554f2SKenneth D. Merry 	if (targ->flags & MPR_TARGET_FLAGS_RAID_COMPONENT) {
1649*991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_TRACE, "%s Raid component no SCSI IO "
1650*991554f2SKenneth D. Merry 		    "supported %u\n", __func__, csio->ccb_h.target_id);
1651*991554f2SKenneth D. Merry 		csio->ccb_h.status = CAM_DEV_NOT_THERE;
1652*991554f2SKenneth D. Merry 		xpt_done(ccb);
1653*991554f2SKenneth D. Merry 		return;
1654*991554f2SKenneth D. Merry 	}
1655*991554f2SKenneth D. Merry 	/*
1656*991554f2SKenneth D. Merry 	 * Sometimes, it is possible to get a command that is not "In
1657*991554f2SKenneth D. Merry 	 * Progress" and was actually aborted by the upper layer.  Check for
1658*991554f2SKenneth D. Merry 	 * this here and complete the command without error.
1659*991554f2SKenneth D. Merry 	 */
1660*991554f2SKenneth D. Merry 	if (ccb->ccb_h.status != CAM_REQ_INPROG) {
1661*991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_TRACE, "%s Command is not in progress for "
1662*991554f2SKenneth D. Merry 		    "target %u\n", __func__, csio->ccb_h.target_id);
1663*991554f2SKenneth D. Merry 		xpt_done(ccb);
1664*991554f2SKenneth D. Merry 		return;
1665*991554f2SKenneth D. Merry 	}
1666*991554f2SKenneth D. Merry 	/*
1667*991554f2SKenneth D. Merry 	 * If devinfo is 0 this will be a volume.  In that case don't tell CAM
1668*991554f2SKenneth D. Merry 	 * that the volume has timed out.  We want volumes to be enumerated
1669*991554f2SKenneth D. Merry 	 * until they are deleted/removed, not just failed.
1670*991554f2SKenneth D. Merry 	 */
1671*991554f2SKenneth D. Merry 	if (targ->flags & MPRSAS_TARGET_INREMOVAL) {
1672*991554f2SKenneth D. Merry 		if (targ->devinfo == 0)
1673*991554f2SKenneth D. Merry 			csio->ccb_h.status = CAM_REQ_CMP;
1674*991554f2SKenneth D. Merry 		else
1675*991554f2SKenneth D. Merry 			csio->ccb_h.status = CAM_SEL_TIMEOUT;
1676*991554f2SKenneth D. Merry 		xpt_done(ccb);
1677*991554f2SKenneth D. Merry 		return;
1678*991554f2SKenneth D. Merry 	}
1679*991554f2SKenneth D. Merry 
1680*991554f2SKenneth D. Merry 	if ((sc->mpr_flags & MPR_FLAGS_SHUTDOWN) != 0) {
1681*991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_TRACE, "%s shutting down\n", __func__);
1682*991554f2SKenneth D. Merry 		csio->ccb_h.status = CAM_DEV_NOT_THERE;
1683*991554f2SKenneth D. Merry 		xpt_done(ccb);
1684*991554f2SKenneth D. Merry 		return;
1685*991554f2SKenneth D. Merry 	}
1686*991554f2SKenneth D. Merry 
1687*991554f2SKenneth D. Merry 	cm = mpr_alloc_command(sc);
1688*991554f2SKenneth D. Merry 	if (cm == NULL || (sc->mpr_flags & MPR_FLAGS_DIAGRESET)) {
1689*991554f2SKenneth D. Merry 		if (cm != NULL) {
1690*991554f2SKenneth D. Merry 			mpr_free_command(sc, cm);
1691*991554f2SKenneth D. Merry 		}
1692*991554f2SKenneth D. Merry 		if ((sassc->flags & MPRSAS_QUEUE_FROZEN) == 0) {
1693*991554f2SKenneth D. Merry 			xpt_freeze_simq(sassc->sim, 1);
1694*991554f2SKenneth D. Merry 			sassc->flags |= MPRSAS_QUEUE_FROZEN;
1695*991554f2SKenneth D. Merry 		}
1696*991554f2SKenneth D. Merry 		ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
1697*991554f2SKenneth D. Merry 		ccb->ccb_h.status |= CAM_REQUEUE_REQ;
1698*991554f2SKenneth D. Merry 		xpt_done(ccb);
1699*991554f2SKenneth D. Merry 		return;
1700*991554f2SKenneth D. Merry 	}
1701*991554f2SKenneth D. Merry 
1702*991554f2SKenneth D. Merry 	req = (MPI2_SCSI_IO_REQUEST *)cm->cm_req;
1703*991554f2SKenneth D. Merry 	bzero(req, sizeof(*req));
1704*991554f2SKenneth D. Merry 	req->DevHandle = htole16(targ->handle);
1705*991554f2SKenneth D. Merry 	req->Function = MPI2_FUNCTION_SCSI_IO_REQUEST;
1706*991554f2SKenneth D. Merry 	req->MsgFlags = 0;
1707*991554f2SKenneth D. Merry 	req->SenseBufferLowAddress = htole32(cm->cm_sense_busaddr);
1708*991554f2SKenneth D. Merry 	req->SenseBufferLength = MPR_SENSE_LEN;
1709*991554f2SKenneth D. Merry 	req->SGLFlags = 0;
1710*991554f2SKenneth D. Merry 	req->ChainOffset = 0;
1711*991554f2SKenneth D. Merry 	req->SGLOffset0 = 24;	/* 32bit word offset to the SGL */
1712*991554f2SKenneth D. Merry 	req->SGLOffset1= 0;
1713*991554f2SKenneth D. Merry 	req->SGLOffset2= 0;
1714*991554f2SKenneth D. Merry 	req->SGLOffset3= 0;
1715*991554f2SKenneth D. Merry 	req->SkipCount = 0;
1716*991554f2SKenneth D. Merry 	req->DataLength = htole32(csio->dxfer_len);
1717*991554f2SKenneth D. Merry 	req->BidirectionalDataLength = 0;
1718*991554f2SKenneth D. Merry 	req->IoFlags = htole16(csio->cdb_len);
1719*991554f2SKenneth D. Merry 	req->EEDPFlags = 0;
1720*991554f2SKenneth D. Merry 
1721*991554f2SKenneth D. Merry 	/* Note: BiDirectional transfers are not supported */
1722*991554f2SKenneth D. Merry 	switch (csio->ccb_h.flags & CAM_DIR_MASK) {
1723*991554f2SKenneth D. Merry 	case CAM_DIR_IN:
1724*991554f2SKenneth D. Merry 		mpi_control = MPI2_SCSIIO_CONTROL_READ;
1725*991554f2SKenneth D. Merry 		cm->cm_flags |= MPR_CM_FLAGS_DATAIN;
1726*991554f2SKenneth D. Merry 		break;
1727*991554f2SKenneth D. Merry 	case CAM_DIR_OUT:
1728*991554f2SKenneth D. Merry 		mpi_control = MPI2_SCSIIO_CONTROL_WRITE;
1729*991554f2SKenneth D. Merry 		cm->cm_flags |= MPR_CM_FLAGS_DATAOUT;
1730*991554f2SKenneth D. Merry 		break;
1731*991554f2SKenneth D. Merry 	case CAM_DIR_NONE:
1732*991554f2SKenneth D. Merry 	default:
1733*991554f2SKenneth D. Merry 		mpi_control = MPI2_SCSIIO_CONTROL_NODATATRANSFER;
1734*991554f2SKenneth D. Merry 		break;
1735*991554f2SKenneth D. Merry 	}
1736*991554f2SKenneth D. Merry 
1737*991554f2SKenneth D. Merry 	if (csio->cdb_len == 32)
1738*991554f2SKenneth D. Merry 		mpi_control |= 4 << MPI2_SCSIIO_CONTROL_ADDCDBLEN_SHIFT;
1739*991554f2SKenneth D. Merry 	/*
1740*991554f2SKenneth D. Merry 	 * It looks like the hardware doesn't require an explicit tag
1741*991554f2SKenneth D. Merry 	 * number for each transaction.  SAM Task Management not supported
1742*991554f2SKenneth D. Merry 	 * at the moment.
1743*991554f2SKenneth D. Merry 	 */
1744*991554f2SKenneth D. Merry 	switch (csio->tag_action) {
1745*991554f2SKenneth D. Merry 	case MSG_HEAD_OF_Q_TAG:
1746*991554f2SKenneth D. Merry 		mpi_control |= MPI2_SCSIIO_CONTROL_HEADOFQ;
1747*991554f2SKenneth D. Merry 		break;
1748*991554f2SKenneth D. Merry 	case MSG_ORDERED_Q_TAG:
1749*991554f2SKenneth D. Merry 		mpi_control |= MPI2_SCSIIO_CONTROL_ORDEREDQ;
1750*991554f2SKenneth D. Merry 		break;
1751*991554f2SKenneth D. Merry 	case MSG_ACA_TASK:
1752*991554f2SKenneth D. Merry 		mpi_control |= MPI2_SCSIIO_CONTROL_ACAQ;
1753*991554f2SKenneth D. Merry 		break;
1754*991554f2SKenneth D. Merry 	case CAM_TAG_ACTION_NONE:
1755*991554f2SKenneth D. Merry 	case MSG_SIMPLE_Q_TAG:
1756*991554f2SKenneth D. Merry 	default:
1757*991554f2SKenneth D. Merry 		mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ;
1758*991554f2SKenneth D. Merry 		break;
1759*991554f2SKenneth D. Merry 	}
1760*991554f2SKenneth D. Merry 	mpi_control |= sc->mapping_table[csio->ccb_h.target_id].TLR_bits;
1761*991554f2SKenneth D. Merry 	req->Control = htole32(mpi_control);
1762*991554f2SKenneth D. Merry 
1763*991554f2SKenneth D. Merry 	if (MPR_SET_LUN(req->LUN, csio->ccb_h.target_lun) != 0) {
1764*991554f2SKenneth D. Merry 		mpr_free_command(sc, cm);
1765*991554f2SKenneth D. Merry 		ccb->ccb_h.status = CAM_LUN_INVALID;
1766*991554f2SKenneth D. Merry 		xpt_done(ccb);
1767*991554f2SKenneth D. Merry 		return;
1768*991554f2SKenneth D. Merry 	}
1769*991554f2SKenneth D. Merry 
1770*991554f2SKenneth D. Merry 	if (csio->ccb_h.flags & CAM_CDB_POINTER)
1771*991554f2SKenneth D. Merry 		bcopy(csio->cdb_io.cdb_ptr, &req->CDB.CDB32[0], csio->cdb_len);
1772*991554f2SKenneth D. Merry 	else
1773*991554f2SKenneth D. Merry 		bcopy(csio->cdb_io.cdb_bytes, &req->CDB.CDB32[0],csio->cdb_len);
1774*991554f2SKenneth D. Merry 	req->IoFlags = htole16(csio->cdb_len);
1775*991554f2SKenneth D. Merry 
1776*991554f2SKenneth D. Merry 	/*
1777*991554f2SKenneth D. Merry 	 * Check if EEDP is supported and enabled.  If it is then check if the
1778*991554f2SKenneth D. Merry 	 * SCSI opcode could be using EEDP.  If so, make sure the LUN exists and
1779*991554f2SKenneth D. Merry 	 * is formatted for EEDP support.  If all of this is true, set CDB up
1780*991554f2SKenneth D. Merry 	 * for EEDP transfer.
1781*991554f2SKenneth D. Merry 	 */
1782*991554f2SKenneth D. Merry 	eedp_flags = op_code_prot[req->CDB.CDB32[0]];
1783*991554f2SKenneth D. Merry 	if (sc->eedp_enabled && eedp_flags) {
1784*991554f2SKenneth D. Merry 		SLIST_FOREACH(lun, &targ->luns, lun_link) {
1785*991554f2SKenneth D. Merry 			if (lun->lun_id == csio->ccb_h.target_lun) {
1786*991554f2SKenneth D. Merry 				break;
1787*991554f2SKenneth D. Merry 			}
1788*991554f2SKenneth D. Merry 		}
1789*991554f2SKenneth D. Merry 
1790*991554f2SKenneth D. Merry 		if ((lun != NULL) && (lun->eedp_formatted)) {
1791*991554f2SKenneth D. Merry 			req->EEDPBlockSize = htole16(lun->eedp_block_size);
1792*991554f2SKenneth D. Merry 			eedp_flags |= (MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG |
1793*991554f2SKenneth D. Merry 			    MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG |
1794*991554f2SKenneth D. Merry 			    MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD);
1795*991554f2SKenneth D. Merry 			req->EEDPFlags = htole16(eedp_flags);
1796*991554f2SKenneth D. Merry 
1797*991554f2SKenneth D. Merry 			/*
1798*991554f2SKenneth D. Merry 			 * If CDB less than 32, fill in Primary Ref Tag with
1799*991554f2SKenneth D. Merry 			 * low 4 bytes of LBA.  If CDB is 32, tag stuff is
1800*991554f2SKenneth D. Merry 			 * already there.  Also, set protection bit.  FreeBSD
1801*991554f2SKenneth D. Merry 			 * currently does not support CDBs bigger than 16, but
1802*991554f2SKenneth D. Merry 			 * the code doesn't hurt, and will be here for the
1803*991554f2SKenneth D. Merry 			 * future.
1804*991554f2SKenneth D. Merry 			 */
1805*991554f2SKenneth D. Merry 			if (csio->cdb_len != 32) {
1806*991554f2SKenneth D. Merry 				lba_byte = (csio->cdb_len == 16) ? 6 : 2;
1807*991554f2SKenneth D. Merry 				ref_tag_addr = (uint8_t *)&req->CDB.EEDP32.
1808*991554f2SKenneth D. Merry 				    PrimaryReferenceTag;
1809*991554f2SKenneth D. Merry 				for (i = 0; i < 4; i++) {
1810*991554f2SKenneth D. Merry 					*ref_tag_addr =
1811*991554f2SKenneth D. Merry 					    req->CDB.CDB32[lba_byte + i];
1812*991554f2SKenneth D. Merry 					ref_tag_addr++;
1813*991554f2SKenneth D. Merry 				}
1814*991554f2SKenneth D. Merry 				req->CDB.EEDP32.PrimaryReferenceTag =
1815*991554f2SKenneth D. Merry 				    htole32(req->
1816*991554f2SKenneth D. Merry 				    CDB.EEDP32.PrimaryReferenceTag);
1817*991554f2SKenneth D. Merry 				req->CDB.EEDP32.PrimaryApplicationTagMask =
1818*991554f2SKenneth D. Merry 				    0xFFFF;
1819*991554f2SKenneth D. Merry 				req->CDB.CDB32[1] = (req->CDB.CDB32[1] & 0x1F) |
1820*991554f2SKenneth D. Merry 				    0x20;
1821*991554f2SKenneth D. Merry 			} else {
1822*991554f2SKenneth D. Merry 				eedp_flags |=
1823*991554f2SKenneth D. Merry 				    MPI2_SCSIIO_EEDPFLAGS_INC_PRI_APPTAG;
1824*991554f2SKenneth D. Merry 				req->EEDPFlags = htole16(eedp_flags);
1825*991554f2SKenneth D. Merry 				req->CDB.CDB32[10] = (req->CDB.CDB32[10] &
1826*991554f2SKenneth D. Merry 				    0x1F) | 0x20;
1827*991554f2SKenneth D. Merry 			}
1828*991554f2SKenneth D. Merry 		}
1829*991554f2SKenneth D. Merry 	}
1830*991554f2SKenneth D. Merry 
1831*991554f2SKenneth D. Merry 	cm->cm_length = csio->dxfer_len;
1832*991554f2SKenneth D. Merry 	if (cm->cm_length != 0) {
1833*991554f2SKenneth D. Merry 		cm->cm_data = ccb;
1834*991554f2SKenneth D. Merry 		cm->cm_flags |= MPR_CM_FLAGS_USE_CCB;
1835*991554f2SKenneth D. Merry 	} else {
1836*991554f2SKenneth D. Merry 		cm->cm_data = NULL;
1837*991554f2SKenneth D. Merry 	}
1838*991554f2SKenneth D. Merry 	cm->cm_sge = &req->SGL;
1839*991554f2SKenneth D. Merry 	cm->cm_sglsize = (32 - 24) * 4;
1840*991554f2SKenneth D. Merry 	cm->cm_complete = mprsas_scsiio_complete;
1841*991554f2SKenneth D. Merry 	cm->cm_complete_data = ccb;
1842*991554f2SKenneth D. Merry 	cm->cm_targ = targ;
1843*991554f2SKenneth D. Merry 	cm->cm_lun = csio->ccb_h.target_lun;
1844*991554f2SKenneth D. Merry 	cm->cm_ccb = ccb;
1845*991554f2SKenneth D. Merry 	/*
1846*991554f2SKenneth D. Merry 	 * If using FP desc type, need to set a bit in IoFlags (SCSI IO is 0)
1847*991554f2SKenneth D. Merry 	 * and set descriptor type.
1848*991554f2SKenneth D. Merry 	 */
1849*991554f2SKenneth D. Merry 	if (targ->scsi_req_desc_type ==
1850*991554f2SKenneth D. Merry 	    MPI25_REQ_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO) {
1851*991554f2SKenneth D. Merry 		req->IoFlags |= MPI25_SCSIIO_IOFLAGS_FAST_PATH;
1852*991554f2SKenneth D. Merry 		cm->cm_desc.FastPathSCSIIO.RequestFlags =
1853*991554f2SKenneth D. Merry 		    MPI25_REQ_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO;
1854*991554f2SKenneth D. Merry 		cm->cm_desc.FastPathSCSIIO.DevHandle = htole16(targ->handle);
1855*991554f2SKenneth D. Merry 	} else {
1856*991554f2SKenneth D. Merry 		cm->cm_desc.SCSIIO.RequestFlags =
1857*991554f2SKenneth D. Merry 		    MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO;
1858*991554f2SKenneth D. Merry 		cm->cm_desc.SCSIIO.DevHandle = htole16(targ->handle);
1859*991554f2SKenneth D. Merry 	}
1860*991554f2SKenneth D. Merry 
1861*991554f2SKenneth D. Merry 	callout_reset(&cm->cm_callout, (ccb->ccb_h.timeout * hz) / 1000,
1862*991554f2SKenneth D. Merry 	   mprsas_scsiio_timeout, cm);
1863*991554f2SKenneth D. Merry 
1864*991554f2SKenneth D. Merry 	targ->issued++;
1865*991554f2SKenneth D. Merry 	targ->outstanding++;
1866*991554f2SKenneth D. Merry 	TAILQ_INSERT_TAIL(&targ->commands, cm, cm_link);
1867*991554f2SKenneth D. Merry 	ccb->ccb_h.status |= CAM_SIM_QUEUED;
1868*991554f2SKenneth D. Merry 
1869*991554f2SKenneth D. Merry 	mprsas_log_command(cm, MPR_XINFO, "%s cm %p ccb %p outstanding %u\n",
1870*991554f2SKenneth D. Merry 	    __func__, cm, ccb, targ->outstanding);
1871*991554f2SKenneth D. Merry 
1872*991554f2SKenneth D. Merry 	mpr_map_command(sc, cm);
1873*991554f2SKenneth D. Merry 	return;
1874*991554f2SKenneth D. Merry }
1875*991554f2SKenneth D. Merry 
1876*991554f2SKenneth D. Merry static void
1877*991554f2SKenneth D. Merry mpr_response_code(struct mpr_softc *sc, u8 response_code)
1878*991554f2SKenneth D. Merry {
1879*991554f2SKenneth D. Merry         char *desc;
1880*991554f2SKenneth D. Merry 
1881*991554f2SKenneth D. Merry         switch (response_code) {
1882*991554f2SKenneth D. Merry         case MPI2_SCSITASKMGMT_RSP_TM_COMPLETE:
1883*991554f2SKenneth D. Merry                 desc = "task management request completed";
1884*991554f2SKenneth D. Merry                 break;
1885*991554f2SKenneth D. Merry         case MPI2_SCSITASKMGMT_RSP_INVALID_FRAME:
1886*991554f2SKenneth D. Merry                 desc = "invalid frame";
1887*991554f2SKenneth D. Merry                 break;
1888*991554f2SKenneth D. Merry         case MPI2_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED:
1889*991554f2SKenneth D. Merry                 desc = "task management request not supported";
1890*991554f2SKenneth D. Merry                 break;
1891*991554f2SKenneth D. Merry         case MPI2_SCSITASKMGMT_RSP_TM_FAILED:
1892*991554f2SKenneth D. Merry                 desc = "task management request failed";
1893*991554f2SKenneth D. Merry                 break;
1894*991554f2SKenneth D. Merry         case MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED:
1895*991554f2SKenneth D. Merry                 desc = "task management request succeeded";
1896*991554f2SKenneth D. Merry                 break;
1897*991554f2SKenneth D. Merry         case MPI2_SCSITASKMGMT_RSP_TM_INVALID_LUN:
1898*991554f2SKenneth D. Merry                 desc = "invalid lun";
1899*991554f2SKenneth D. Merry                 break;
1900*991554f2SKenneth D. Merry         case 0xA:
1901*991554f2SKenneth D. Merry                 desc = "overlapped tag attempted";
1902*991554f2SKenneth D. Merry                 break;
1903*991554f2SKenneth D. Merry         case MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC:
1904*991554f2SKenneth D. Merry                 desc = "task queued, however not sent to target";
1905*991554f2SKenneth D. Merry                 break;
1906*991554f2SKenneth D. Merry         default:
1907*991554f2SKenneth D. Merry                 desc = "unknown";
1908*991554f2SKenneth D. Merry                 break;
1909*991554f2SKenneth D. Merry         }
1910*991554f2SKenneth D. Merry 	mpr_dprint(sc, MPR_XINFO, "response_code(0x%01x): %s\n", response_code,
1911*991554f2SKenneth D. Merry 	    desc);
1912*991554f2SKenneth D. Merry }
1913*991554f2SKenneth D. Merry 
1914*991554f2SKenneth D. Merry /**
1915*991554f2SKenneth D. Merry  * mpr_sc_failed_io_info - translated non-succesfull SCSI_IO request
1916*991554f2SKenneth D. Merry  */
1917*991554f2SKenneth D. Merry static void
1918*991554f2SKenneth D. Merry mpr_sc_failed_io_info(struct mpr_softc *sc, struct ccb_scsiio *csio,
1919*991554f2SKenneth D. Merry     Mpi2SCSIIOReply_t *mpi_reply, struct mprsas_target *targ)
1920*991554f2SKenneth D. Merry {
1921*991554f2SKenneth D. Merry 	u32 response_info;
1922*991554f2SKenneth D. Merry 	u8 *response_bytes;
1923*991554f2SKenneth D. Merry 	u16 ioc_status = le16toh(mpi_reply->IOCStatus) &
1924*991554f2SKenneth D. Merry 	    MPI2_IOCSTATUS_MASK;
1925*991554f2SKenneth D. Merry 	u8 scsi_state = mpi_reply->SCSIState;
1926*991554f2SKenneth D. Merry 	u8 scsi_status = mpi_reply->SCSIStatus;
1927*991554f2SKenneth D. Merry 	char *desc_ioc_state = NULL;
1928*991554f2SKenneth D. Merry 	char *desc_scsi_status = NULL;
1929*991554f2SKenneth D. Merry 	char *desc_scsi_state = sc->tmp_string;
1930*991554f2SKenneth D. Merry 	u32 log_info = le32toh(mpi_reply->IOCLogInfo);
1931*991554f2SKenneth D. Merry 
1932*991554f2SKenneth D. Merry 	if (log_info == 0x31170000)
1933*991554f2SKenneth D. Merry 		return;
1934*991554f2SKenneth D. Merry 
1935*991554f2SKenneth D. Merry 	switch (ioc_status) {
1936*991554f2SKenneth D. Merry 	case MPI2_IOCSTATUS_SUCCESS:
1937*991554f2SKenneth D. Merry 		desc_ioc_state = "success";
1938*991554f2SKenneth D. Merry 		break;
1939*991554f2SKenneth D. Merry 	case MPI2_IOCSTATUS_INVALID_FUNCTION:
1940*991554f2SKenneth D. Merry 		desc_ioc_state = "invalid function";
1941*991554f2SKenneth D. Merry 		break;
1942*991554f2SKenneth D. Merry 	case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR:
1943*991554f2SKenneth D. Merry 		desc_ioc_state = "scsi recovered error";
1944*991554f2SKenneth D. Merry 		break;
1945*991554f2SKenneth D. Merry 	case MPI2_IOCSTATUS_SCSI_INVALID_DEVHANDLE:
1946*991554f2SKenneth D. Merry 		desc_ioc_state = "scsi invalid dev handle";
1947*991554f2SKenneth D. Merry 		break;
1948*991554f2SKenneth D. Merry 	case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
1949*991554f2SKenneth D. Merry 		desc_ioc_state = "scsi device not there";
1950*991554f2SKenneth D. Merry 		break;
1951*991554f2SKenneth D. Merry 	case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN:
1952*991554f2SKenneth D. Merry 		desc_ioc_state = "scsi data overrun";
1953*991554f2SKenneth D. Merry 		break;
1954*991554f2SKenneth D. Merry 	case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN:
1955*991554f2SKenneth D. Merry 		desc_ioc_state = "scsi data underrun";
1956*991554f2SKenneth D. Merry 		break;
1957*991554f2SKenneth D. Merry 	case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR:
1958*991554f2SKenneth D. Merry 		desc_ioc_state = "scsi io data error";
1959*991554f2SKenneth D. Merry 		break;
1960*991554f2SKenneth D. Merry 	case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR:
1961*991554f2SKenneth D. Merry 		desc_ioc_state = "scsi protocol error";
1962*991554f2SKenneth D. Merry 		break;
1963*991554f2SKenneth D. Merry 	case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED:
1964*991554f2SKenneth D. Merry 		desc_ioc_state = "scsi task terminated";
1965*991554f2SKenneth D. Merry 		break;
1966*991554f2SKenneth D. Merry 	case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
1967*991554f2SKenneth D. Merry 		desc_ioc_state = "scsi residual mismatch";
1968*991554f2SKenneth D. Merry 		break;
1969*991554f2SKenneth D. Merry 	case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
1970*991554f2SKenneth D. Merry 		desc_ioc_state = "scsi task mgmt failed";
1971*991554f2SKenneth D. Merry 		break;
1972*991554f2SKenneth D. Merry 	case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED:
1973*991554f2SKenneth D. Merry 		desc_ioc_state = "scsi ioc terminated";
1974*991554f2SKenneth D. Merry 		break;
1975*991554f2SKenneth D. Merry 	case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED:
1976*991554f2SKenneth D. Merry 		desc_ioc_state = "scsi ext terminated";
1977*991554f2SKenneth D. Merry 		break;
1978*991554f2SKenneth D. Merry 	case MPI2_IOCSTATUS_EEDP_GUARD_ERROR:
1979*991554f2SKenneth D. Merry 		desc_ioc_state = "eedp guard error";
1980*991554f2SKenneth D. Merry 		break;
1981*991554f2SKenneth D. Merry 	case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR:
1982*991554f2SKenneth D. Merry 		desc_ioc_state = "eedp ref tag error";
1983*991554f2SKenneth D. Merry 		break;
1984*991554f2SKenneth D. Merry 	case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR:
1985*991554f2SKenneth D. Merry 		desc_ioc_state = "eedp app tag error";
1986*991554f2SKenneth D. Merry 		break;
1987*991554f2SKenneth D. Merry 	default:
1988*991554f2SKenneth D. Merry 		desc_ioc_state = "unknown";
1989*991554f2SKenneth D. Merry 		break;
1990*991554f2SKenneth D. Merry 	}
1991*991554f2SKenneth D. Merry 
1992*991554f2SKenneth D. Merry 	switch (scsi_status) {
1993*991554f2SKenneth D. Merry 	case MPI2_SCSI_STATUS_GOOD:
1994*991554f2SKenneth D. Merry 		desc_scsi_status = "good";
1995*991554f2SKenneth D. Merry 		break;
1996*991554f2SKenneth D. Merry 	case MPI2_SCSI_STATUS_CHECK_CONDITION:
1997*991554f2SKenneth D. Merry 		desc_scsi_status = "check condition";
1998*991554f2SKenneth D. Merry 		break;
1999*991554f2SKenneth D. Merry 	case MPI2_SCSI_STATUS_CONDITION_MET:
2000*991554f2SKenneth D. Merry 		desc_scsi_status = "condition met";
2001*991554f2SKenneth D. Merry 		break;
2002*991554f2SKenneth D. Merry 	case MPI2_SCSI_STATUS_BUSY:
2003*991554f2SKenneth D. Merry 		desc_scsi_status = "busy";
2004*991554f2SKenneth D. Merry 		break;
2005*991554f2SKenneth D. Merry 	case MPI2_SCSI_STATUS_INTERMEDIATE:
2006*991554f2SKenneth D. Merry 		desc_scsi_status = "intermediate";
2007*991554f2SKenneth D. Merry 		break;
2008*991554f2SKenneth D. Merry 	case MPI2_SCSI_STATUS_INTERMEDIATE_CONDMET:
2009*991554f2SKenneth D. Merry 		desc_scsi_status = "intermediate condmet";
2010*991554f2SKenneth D. Merry 		break;
2011*991554f2SKenneth D. Merry 	case MPI2_SCSI_STATUS_RESERVATION_CONFLICT:
2012*991554f2SKenneth D. Merry 		desc_scsi_status = "reservation conflict";
2013*991554f2SKenneth D. Merry 		break;
2014*991554f2SKenneth D. Merry 	case MPI2_SCSI_STATUS_COMMAND_TERMINATED:
2015*991554f2SKenneth D. Merry 		desc_scsi_status = "command terminated";
2016*991554f2SKenneth D. Merry 		break;
2017*991554f2SKenneth D. Merry 	case MPI2_SCSI_STATUS_TASK_SET_FULL:
2018*991554f2SKenneth D. Merry 		desc_scsi_status = "task set full";
2019*991554f2SKenneth D. Merry 		break;
2020*991554f2SKenneth D. Merry 	case MPI2_SCSI_STATUS_ACA_ACTIVE:
2021*991554f2SKenneth D. Merry 		desc_scsi_status = "aca active";
2022*991554f2SKenneth D. Merry 		break;
2023*991554f2SKenneth D. Merry 	case MPI2_SCSI_STATUS_TASK_ABORTED:
2024*991554f2SKenneth D. Merry 		desc_scsi_status = "task aborted";
2025*991554f2SKenneth D. Merry 		break;
2026*991554f2SKenneth D. Merry 	default:
2027*991554f2SKenneth D. Merry 		desc_scsi_status = "unknown";
2028*991554f2SKenneth D. Merry 		break;
2029*991554f2SKenneth D. Merry 	}
2030*991554f2SKenneth D. Merry 
2031*991554f2SKenneth D. Merry 	desc_scsi_state[0] = '\0';
2032*991554f2SKenneth D. Merry 	if (!scsi_state)
2033*991554f2SKenneth D. Merry 		desc_scsi_state = " ";
2034*991554f2SKenneth D. Merry 	if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID)
2035*991554f2SKenneth D. Merry 		strcat(desc_scsi_state, "response info ");
2036*991554f2SKenneth D. Merry 	if (scsi_state & MPI2_SCSI_STATE_TERMINATED)
2037*991554f2SKenneth D. Merry 		strcat(desc_scsi_state, "state terminated ");
2038*991554f2SKenneth D. Merry 	if (scsi_state & MPI2_SCSI_STATE_NO_SCSI_STATUS)
2039*991554f2SKenneth D. Merry 		strcat(desc_scsi_state, "no status ");
2040*991554f2SKenneth D. Merry 	if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_FAILED)
2041*991554f2SKenneth D. Merry 		strcat(desc_scsi_state, "autosense failed ");
2042*991554f2SKenneth D. Merry 	if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID)
2043*991554f2SKenneth D. Merry 		strcat(desc_scsi_state, "autosense valid ");
2044*991554f2SKenneth D. Merry 
2045*991554f2SKenneth D. Merry 	mpr_dprint(sc, MPR_XINFO, "\thandle(0x%04x), ioc_status(%s)(0x%04x)\n",
2046*991554f2SKenneth D. Merry 	    le16toh(mpi_reply->DevHandle), desc_ioc_state, ioc_status);
2047*991554f2SKenneth D. Merry 	if (targ->encl_level_valid) {
2048*991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_XINFO, "At enclosure level %d, slot %d, "
2049*991554f2SKenneth D. Merry 		    "connector name (%4s)\n", targ->encl_level, targ->encl_slot,
2050*991554f2SKenneth D. Merry 		    targ->connector_name);
2051*991554f2SKenneth D. Merry 	}
2052*991554f2SKenneth D. Merry 	/* We can add more detail about underflow data here
2053*991554f2SKenneth D. Merry 	 * TO-DO
2054*991554f2SKenneth D. Merry 	 * */
2055*991554f2SKenneth D. Merry 	mpr_dprint(sc, MPR_XINFO, "\tscsi_status(%s)(0x%02x), "
2056*991554f2SKenneth D. Merry 	    "scsi_state(%s)(0x%02x)\n", desc_scsi_status, scsi_status,
2057*991554f2SKenneth D. Merry 	    desc_scsi_state, scsi_state);
2058*991554f2SKenneth D. Merry 
2059*991554f2SKenneth D. Merry 	if (sc->mpr_debug & MPR_XINFO &&
2060*991554f2SKenneth D. Merry 		scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID) {
2061*991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_XINFO, "-> Sense Buffer Data : Start :\n");
2062*991554f2SKenneth D. Merry 		scsi_sense_print(csio);
2063*991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_XINFO, "-> Sense Buffer Data : End :\n");
2064*991554f2SKenneth D. Merry 	}
2065*991554f2SKenneth D. Merry 
2066*991554f2SKenneth D. Merry 	if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) {
2067*991554f2SKenneth D. Merry 		response_info = le32toh(mpi_reply->ResponseInfo);
2068*991554f2SKenneth D. Merry 		response_bytes = (u8 *)&response_info;
2069*991554f2SKenneth D. Merry 		mpr_response_code(sc,response_bytes[0]);
2070*991554f2SKenneth D. Merry 	}
2071*991554f2SKenneth D. Merry }
2072*991554f2SKenneth D. Merry 
2073*991554f2SKenneth D. Merry static void
2074*991554f2SKenneth D. Merry mprsas_scsiio_complete(struct mpr_softc *sc, struct mpr_command *cm)
2075*991554f2SKenneth D. Merry {
2076*991554f2SKenneth D. Merry 	MPI2_SCSI_IO_REPLY *rep;
2077*991554f2SKenneth D. Merry 	union ccb *ccb;
2078*991554f2SKenneth D. Merry 	struct ccb_scsiio *csio;
2079*991554f2SKenneth D. Merry 	struct mprsas_softc *sassc;
2080*991554f2SKenneth D. Merry 	struct scsi_vpd_supported_page_list *vpd_list = NULL;
2081*991554f2SKenneth D. Merry 	u8 *TLR_bits, TLR_on;
2082*991554f2SKenneth D. Merry 	int dir = 0, i;
2083*991554f2SKenneth D. Merry 	u16 alloc_len;
2084*991554f2SKenneth D. Merry 
2085*991554f2SKenneth D. Merry 	MPR_FUNCTRACE(sc);
2086*991554f2SKenneth D. Merry 	mpr_dprint(sc, MPR_TRACE,
2087*991554f2SKenneth D. Merry 	    "cm %p SMID %u ccb %p reply %p outstanding %u\n", cm,
2088*991554f2SKenneth D. Merry 	    cm->cm_desc.Default.SMID, cm->cm_ccb, cm->cm_reply,
2089*991554f2SKenneth D. Merry 	    cm->cm_targ->outstanding);
2090*991554f2SKenneth D. Merry 
2091*991554f2SKenneth D. Merry 	callout_stop(&cm->cm_callout);
2092*991554f2SKenneth D. Merry 	mtx_assert(&sc->mpr_mtx, MA_OWNED);
2093*991554f2SKenneth D. Merry 
2094*991554f2SKenneth D. Merry 	sassc = sc->sassc;
2095*991554f2SKenneth D. Merry 	ccb = cm->cm_complete_data;
2096*991554f2SKenneth D. Merry 	csio = &ccb->csio;
2097*991554f2SKenneth D. Merry 	rep = (MPI2_SCSI_IO_REPLY *)cm->cm_reply;
2098*991554f2SKenneth D. Merry 	/*
2099*991554f2SKenneth D. Merry 	 * XXX KDM if the chain allocation fails, does it matter if we do
2100*991554f2SKenneth D. Merry 	 * the sync and unload here?  It is simpler to do it in every case,
2101*991554f2SKenneth D. Merry 	 * assuming it doesn't cause problems.
2102*991554f2SKenneth D. Merry 	 */
2103*991554f2SKenneth D. Merry 	if (cm->cm_data != NULL) {
2104*991554f2SKenneth D. Merry 		if (cm->cm_flags & MPR_CM_FLAGS_DATAIN)
2105*991554f2SKenneth D. Merry 			dir = BUS_DMASYNC_POSTREAD;
2106*991554f2SKenneth D. Merry 		else if (cm->cm_flags & MPR_CM_FLAGS_DATAOUT)
2107*991554f2SKenneth D. Merry 			dir = BUS_DMASYNC_POSTWRITE;
2108*991554f2SKenneth D. Merry 		bus_dmamap_sync(sc->buffer_dmat, cm->cm_dmamap, dir);
2109*991554f2SKenneth D. Merry 		bus_dmamap_unload(sc->buffer_dmat, cm->cm_dmamap);
2110*991554f2SKenneth D. Merry 	}
2111*991554f2SKenneth D. Merry 
2112*991554f2SKenneth D. Merry 	cm->cm_targ->completed++;
2113*991554f2SKenneth D. Merry 	cm->cm_targ->outstanding--;
2114*991554f2SKenneth D. Merry 	TAILQ_REMOVE(&cm->cm_targ->commands, cm, cm_link);
2115*991554f2SKenneth D. Merry 	ccb->ccb_h.status &= ~(CAM_STATUS_MASK | CAM_SIM_QUEUED);
2116*991554f2SKenneth D. Merry 
2117*991554f2SKenneth D. Merry 	if (cm->cm_state == MPR_CM_STATE_TIMEDOUT) {
2118*991554f2SKenneth D. Merry 		TAILQ_REMOVE(&cm->cm_targ->timedout_commands, cm, cm_recovery);
2119*991554f2SKenneth D. Merry 		if (cm->cm_reply != NULL)
2120*991554f2SKenneth D. Merry 			mprsas_log_command(cm, MPR_RECOVERY,
2121*991554f2SKenneth D. Merry 			    "completed timedout cm %p ccb %p during recovery "
2122*991554f2SKenneth D. Merry 			    "ioc %x scsi %x state %x xfer %u\n", cm, cm->cm_ccb,
2123*991554f2SKenneth D. Merry 			    le16toh(rep->IOCStatus), rep->SCSIStatus,
2124*991554f2SKenneth D. Merry 			    rep->SCSIState, le32toh(rep->TransferCount));
2125*991554f2SKenneth D. Merry 		else
2126*991554f2SKenneth D. Merry 			mprsas_log_command(cm, MPR_RECOVERY,
2127*991554f2SKenneth D. Merry 			    "completed timedout cm %p ccb %p during recovery\n",
2128*991554f2SKenneth D. Merry 			    cm, cm->cm_ccb);
2129*991554f2SKenneth D. Merry 	} else if (cm->cm_targ->tm != NULL) {
2130*991554f2SKenneth D. Merry 		if (cm->cm_reply != NULL)
2131*991554f2SKenneth D. Merry 			mprsas_log_command(cm, MPR_RECOVERY,
2132*991554f2SKenneth D. Merry 			    "completed cm %p ccb %p during recovery "
2133*991554f2SKenneth D. Merry 			    "ioc %x scsi %x state %x xfer %u\n",
2134*991554f2SKenneth D. Merry 			    cm, cm->cm_ccb, le16toh(rep->IOCStatus),
2135*991554f2SKenneth D. Merry 			    rep->SCSIStatus, rep->SCSIState,
2136*991554f2SKenneth D. Merry 			    le32toh(rep->TransferCount));
2137*991554f2SKenneth D. Merry 		else
2138*991554f2SKenneth D. Merry 			mprsas_log_command(cm, MPR_RECOVERY,
2139*991554f2SKenneth D. Merry 			    "completed cm %p ccb %p during recovery\n",
2140*991554f2SKenneth D. Merry 			    cm, cm->cm_ccb);
2141*991554f2SKenneth D. Merry 	} else if ((sc->mpr_flags & MPR_FLAGS_DIAGRESET) != 0) {
2142*991554f2SKenneth D. Merry 		mprsas_log_command(cm, MPR_RECOVERY,
2143*991554f2SKenneth D. Merry 		    "reset completed cm %p ccb %p\n", cm, cm->cm_ccb);
2144*991554f2SKenneth D. Merry 	}
2145*991554f2SKenneth D. Merry 
2146*991554f2SKenneth D. Merry 	if ((cm->cm_flags & MPR_CM_FLAGS_ERROR_MASK) != 0) {
2147*991554f2SKenneth D. Merry 		/*
2148*991554f2SKenneth D. Merry 		 * We ran into an error after we tried to map the command,
2149*991554f2SKenneth D. Merry 		 * so we're getting a callback without queueing the command
2150*991554f2SKenneth D. Merry 		 * to the hardware.  So we set the status here, and it will
2151*991554f2SKenneth D. Merry 		 * be retained below.  We'll go through the "fast path",
2152*991554f2SKenneth D. Merry 		 * because there can be no reply when we haven't actually
2153*991554f2SKenneth D. Merry 		 * gone out to the hardware.
2154*991554f2SKenneth D. Merry 		 */
2155*991554f2SKenneth D. Merry 		ccb->ccb_h.status = CAM_REQUEUE_REQ;
2156*991554f2SKenneth D. Merry 
2157*991554f2SKenneth D. Merry 		/*
2158*991554f2SKenneth D. Merry 		 * Currently the only error included in the mask is
2159*991554f2SKenneth D. Merry 		 * MPR_CM_FLAGS_CHAIN_FAILED, which means we're out of
2160*991554f2SKenneth D. Merry 		 * chain frames.  We need to freeze the queue until we get
2161*991554f2SKenneth D. Merry 		 * a command that completed without this error, which will
2162*991554f2SKenneth D. Merry 		 * hopefully have some chain frames attached that we can
2163*991554f2SKenneth D. Merry 		 * use.  If we wanted to get smarter about it, we would
2164*991554f2SKenneth D. Merry 		 * only unfreeze the queue in this condition when we're
2165*991554f2SKenneth D. Merry 		 * sure that we're getting some chain frames back.  That's
2166*991554f2SKenneth D. Merry 		 * probably unnecessary.
2167*991554f2SKenneth D. Merry 		 */
2168*991554f2SKenneth D. Merry 		if ((sassc->flags & MPRSAS_QUEUE_FROZEN) == 0) {
2169*991554f2SKenneth D. Merry 			xpt_freeze_simq(sassc->sim, 1);
2170*991554f2SKenneth D. Merry 			sassc->flags |= MPRSAS_QUEUE_FROZEN;
2171*991554f2SKenneth D. Merry 			mpr_dprint(sc, MPR_INFO, "Error sending command, "
2172*991554f2SKenneth D. Merry 				   "freezing SIM queue\n");
2173*991554f2SKenneth D. Merry 		}
2174*991554f2SKenneth D. Merry 	}
2175*991554f2SKenneth D. Merry 
2176*991554f2SKenneth D. Merry 	/*
2177*991554f2SKenneth D. Merry 	 * If this is a Start Stop Unit command and it was issued by the driver
2178*991554f2SKenneth D. Merry 	 * during shutdown, decrement the refcount to account for all of the
2179*991554f2SKenneth D. Merry 	 * commands that were sent.  All SSU commands should be completed before
2180*991554f2SKenneth D. Merry 	 * shutdown completes, meaning SSU_refcount will be 0 after SSU_started
2181*991554f2SKenneth D. Merry 	 * is TRUE.
2182*991554f2SKenneth D. Merry 	 */
2183*991554f2SKenneth D. Merry 	if (sc->SSU_started && (csio->cdb_io.cdb_bytes[0] == START_STOP_UNIT)) {
2184*991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_INFO, "Decrementing SSU count.\n");
2185*991554f2SKenneth D. Merry 		sc->SSU_refcount--;
2186*991554f2SKenneth D. Merry 	}
2187*991554f2SKenneth D. Merry 
2188*991554f2SKenneth D. Merry 	/* Take the fast path to completion */
2189*991554f2SKenneth D. Merry 	if (cm->cm_reply == NULL) {
2190*991554f2SKenneth D. Merry 		if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INPROG) {
2191*991554f2SKenneth D. Merry 			if ((sc->mpr_flags & MPR_FLAGS_DIAGRESET) != 0)
2192*991554f2SKenneth D. Merry 				ccb->ccb_h.status = CAM_SCSI_BUS_RESET;
2193*991554f2SKenneth D. Merry 			else {
2194*991554f2SKenneth D. Merry 				ccb->ccb_h.status = CAM_REQ_CMP;
2195*991554f2SKenneth D. Merry 				ccb->csio.scsi_status = SCSI_STATUS_OK;
2196*991554f2SKenneth D. Merry 			}
2197*991554f2SKenneth D. Merry 			if (sassc->flags & MPRSAS_QUEUE_FROZEN) {
2198*991554f2SKenneth D. Merry 				ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
2199*991554f2SKenneth D. Merry 				sassc->flags &= ~MPRSAS_QUEUE_FROZEN;
2200*991554f2SKenneth D. Merry 				mpr_dprint(sc, MPR_XINFO,
2201*991554f2SKenneth D. Merry 				    "Unfreezing SIM queue\n");
2202*991554f2SKenneth D. Merry 			}
2203*991554f2SKenneth D. Merry 		}
2204*991554f2SKenneth D. Merry 
2205*991554f2SKenneth D. Merry 		/*
2206*991554f2SKenneth D. Merry 		 * There are two scenarios where the status won't be
2207*991554f2SKenneth D. Merry 		 * CAM_REQ_CMP.  The first is if MPR_CM_FLAGS_ERROR_MASK is
2208*991554f2SKenneth D. Merry 		 * set, the second is in the MPR_FLAGS_DIAGRESET above.
2209*991554f2SKenneth D. Merry 		 */
2210*991554f2SKenneth D. Merry 		if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
2211*991554f2SKenneth D. Merry 			/*
2212*991554f2SKenneth D. Merry 			 * Freeze the dev queue so that commands are
2213*991554f2SKenneth D. Merry 			 * executed in the correct order with after error
2214*991554f2SKenneth D. Merry 			 * recovery.
2215*991554f2SKenneth D. Merry 			 */
2216*991554f2SKenneth D. Merry 			ccb->ccb_h.status |= CAM_DEV_QFRZN;
2217*991554f2SKenneth D. Merry 			xpt_freeze_devq(ccb->ccb_h.path, /*count*/ 1);
2218*991554f2SKenneth D. Merry 		}
2219*991554f2SKenneth D. Merry 		mpr_free_command(sc, cm);
2220*991554f2SKenneth D. Merry 		xpt_done(ccb);
2221*991554f2SKenneth D. Merry 		return;
2222*991554f2SKenneth D. Merry 	}
2223*991554f2SKenneth D. Merry 
2224*991554f2SKenneth D. Merry 	mprsas_log_command(cm, MPR_XINFO,
2225*991554f2SKenneth D. Merry 	    "ioc %x scsi %x state %x xfer %u\n",
2226*991554f2SKenneth D. Merry 	    le16toh(rep->IOCStatus), rep->SCSIStatus, rep->SCSIState,
2227*991554f2SKenneth D. Merry 	    le32toh(rep->TransferCount));
2228*991554f2SKenneth D. Merry 
2229*991554f2SKenneth D. Merry 	switch (le16toh(rep->IOCStatus) & MPI2_IOCSTATUS_MASK) {
2230*991554f2SKenneth D. Merry 	case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN:
2231*991554f2SKenneth D. Merry 		csio->resid = cm->cm_length - le32toh(rep->TransferCount);
2232*991554f2SKenneth D. Merry 		/* FALLTHROUGH */
2233*991554f2SKenneth D. Merry 	case MPI2_IOCSTATUS_SUCCESS:
2234*991554f2SKenneth D. Merry 	case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR:
2235*991554f2SKenneth D. Merry 
2236*991554f2SKenneth D. Merry 		if ((le16toh(rep->IOCStatus) & MPI2_IOCSTATUS_MASK) ==
2237*991554f2SKenneth D. Merry 		    MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR)
2238*991554f2SKenneth D. Merry 			mprsas_log_command(cm, MPR_XINFO, "recovered error\n");
2239*991554f2SKenneth D. Merry 
2240*991554f2SKenneth D. Merry 		/* Completion failed at the transport level. */
2241*991554f2SKenneth D. Merry 		if (rep->SCSIState & (MPI2_SCSI_STATE_NO_SCSI_STATUS |
2242*991554f2SKenneth D. Merry 		    MPI2_SCSI_STATE_TERMINATED)) {
2243*991554f2SKenneth D. Merry 			ccb->ccb_h.status = CAM_REQ_CMP_ERR;
2244*991554f2SKenneth D. Merry 			break;
2245*991554f2SKenneth D. Merry 		}
2246*991554f2SKenneth D. Merry 
2247*991554f2SKenneth D. Merry 		/* In a modern packetized environment, an autosense failure
2248*991554f2SKenneth D. Merry 		 * implies that there's not much else that can be done to
2249*991554f2SKenneth D. Merry 		 * recover the command.
2250*991554f2SKenneth D. Merry 		 */
2251*991554f2SKenneth D. Merry 		if (rep->SCSIState & MPI2_SCSI_STATE_AUTOSENSE_FAILED) {
2252*991554f2SKenneth D. Merry 			ccb->ccb_h.status = CAM_AUTOSENSE_FAIL;
2253*991554f2SKenneth D. Merry 			break;
2254*991554f2SKenneth D. Merry 		}
2255*991554f2SKenneth D. Merry 
2256*991554f2SKenneth D. Merry 		/*
2257*991554f2SKenneth D. Merry 		 * CAM doesn't care about SAS Response Info data, but if this is
2258*991554f2SKenneth D. Merry 		 * the state check if TLR should be done.  If not, clear the
2259*991554f2SKenneth D. Merry 		 * TLR_bits for the target.
2260*991554f2SKenneth D. Merry 		 */
2261*991554f2SKenneth D. Merry 		if ((rep->SCSIState & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) &&
2262*991554f2SKenneth D. Merry 		    ((le32toh(rep->ResponseInfo) & MPI2_SCSI_RI_MASK_REASONCODE)
2263*991554f2SKenneth D. Merry 		    == MPR_SCSI_RI_INVALID_FRAME)) {
2264*991554f2SKenneth D. Merry 			sc->mapping_table[csio->ccb_h.target_id].TLR_bits =
2265*991554f2SKenneth D. Merry 			    (u8)MPI2_SCSIIO_CONTROL_NO_TLR;
2266*991554f2SKenneth D. Merry 		}
2267*991554f2SKenneth D. Merry 
2268*991554f2SKenneth D. Merry 		/*
2269*991554f2SKenneth D. Merry 		 * Intentionally override the normal SCSI status reporting
2270*991554f2SKenneth D. Merry 		 * for these two cases.  These are likely to happen in a
2271*991554f2SKenneth D. Merry 		 * multi-initiator environment, and we want to make sure that
2272*991554f2SKenneth D. Merry 		 * CAM retries these commands rather than fail them.
2273*991554f2SKenneth D. Merry 		 */
2274*991554f2SKenneth D. Merry 		if ((rep->SCSIStatus == MPI2_SCSI_STATUS_COMMAND_TERMINATED) ||
2275*991554f2SKenneth D. Merry 		    (rep->SCSIStatus == MPI2_SCSI_STATUS_TASK_ABORTED)) {
2276*991554f2SKenneth D. Merry 			ccb->ccb_h.status = CAM_REQ_ABORTED;
2277*991554f2SKenneth D. Merry 			break;
2278*991554f2SKenneth D. Merry 		}
2279*991554f2SKenneth D. Merry 
2280*991554f2SKenneth D. Merry 		/* Handle normal status and sense */
2281*991554f2SKenneth D. Merry 		csio->scsi_status = rep->SCSIStatus;
2282*991554f2SKenneth D. Merry 		if (rep->SCSIStatus == MPI2_SCSI_STATUS_GOOD)
2283*991554f2SKenneth D. Merry 			ccb->ccb_h.status = CAM_REQ_CMP;
2284*991554f2SKenneth D. Merry 		else
2285*991554f2SKenneth D. Merry 			ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR;
2286*991554f2SKenneth D. Merry 
2287*991554f2SKenneth D. Merry 		if (rep->SCSIState & MPI2_SCSI_STATE_AUTOSENSE_VALID) {
2288*991554f2SKenneth D. Merry 			int sense_len, returned_sense_len;
2289*991554f2SKenneth D. Merry 
2290*991554f2SKenneth D. Merry 			returned_sense_len = min(le32toh(rep->SenseCount),
2291*991554f2SKenneth D. Merry 			    sizeof(struct scsi_sense_data));
2292*991554f2SKenneth D. Merry 			if (returned_sense_len < csio->sense_len)
2293*991554f2SKenneth D. Merry 				csio->sense_resid = csio->sense_len -
2294*991554f2SKenneth D. Merry 				    returned_sense_len;
2295*991554f2SKenneth D. Merry 			else
2296*991554f2SKenneth D. Merry 				csio->sense_resid = 0;
2297*991554f2SKenneth D. Merry 
2298*991554f2SKenneth D. Merry 			sense_len = min(returned_sense_len,
2299*991554f2SKenneth D. Merry 			    csio->sense_len - csio->sense_resid);
2300*991554f2SKenneth D. Merry 			bzero(&csio->sense_data, sizeof(csio->sense_data));
2301*991554f2SKenneth D. Merry 			bcopy(cm->cm_sense, &csio->sense_data, sense_len);
2302*991554f2SKenneth D. Merry 			ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
2303*991554f2SKenneth D. Merry 		}
2304*991554f2SKenneth D. Merry 
2305*991554f2SKenneth D. Merry 		/*
2306*991554f2SKenneth D. Merry 		 * Check if this is an INQUIRY command.  If it's a VPD inquiry,
2307*991554f2SKenneth D. Merry 		 * and it's page code 0 (Supported Page List), and there is
2308*991554f2SKenneth D. Merry 		 * inquiry data, and this is for a sequential access device, and
2309*991554f2SKenneth D. Merry 		 * the device is an SSP target, and TLR is supported by the
2310*991554f2SKenneth D. Merry 		 * controller, turn the TLR_bits value ON if page 0x90 is
2311*991554f2SKenneth D. Merry 		 * supported.
2312*991554f2SKenneth D. Merry 		 */
2313*991554f2SKenneth D. Merry 		if ((csio->cdb_io.cdb_bytes[0] == INQUIRY) &&
2314*991554f2SKenneth D. Merry 		    (csio->cdb_io.cdb_bytes[1] & SI_EVPD) &&
2315*991554f2SKenneth D. Merry 		    (csio->cdb_io.cdb_bytes[2] == SVPD_SUPPORTED_PAGE_LIST) &&
2316*991554f2SKenneth D. Merry 		    ((csio->ccb_h.flags & CAM_DATA_MASK) == CAM_DATA_VADDR) &&
2317*991554f2SKenneth D. Merry 		    (csio->data_ptr != NULL) && (((uint8_t *)cm->cm_data)[0] ==
2318*991554f2SKenneth D. Merry 		    T_SEQUENTIAL) && (sc->control_TLR) &&
2319*991554f2SKenneth D. Merry 		    (sc->mapping_table[csio->ccb_h.target_id].device_info &
2320*991554f2SKenneth D. Merry 		    MPI2_SAS_DEVICE_INFO_SSP_TARGET)) {
2321*991554f2SKenneth D. Merry 			vpd_list = (struct scsi_vpd_supported_page_list *)
2322*991554f2SKenneth D. Merry 			    csio->data_ptr;
2323*991554f2SKenneth D. Merry 			TLR_bits = &sc->mapping_table[csio->ccb_h.target_id].
2324*991554f2SKenneth D. Merry 			    TLR_bits;
2325*991554f2SKenneth D. Merry 			*TLR_bits = (u8)MPI2_SCSIIO_CONTROL_NO_TLR;
2326*991554f2SKenneth D. Merry 			TLR_on = (u8)MPI2_SCSIIO_CONTROL_TLR_ON;
2327*991554f2SKenneth D. Merry 			alloc_len = ((u16)csio->cdb_io.cdb_bytes[3] << 8) +
2328*991554f2SKenneth D. Merry 			    csio->cdb_io.cdb_bytes[4];
2329*991554f2SKenneth D. Merry 			for (i = 0; i < MIN(vpd_list->length, alloc_len); i++) {
2330*991554f2SKenneth D. Merry 				if (vpd_list->list[i] == 0x90) {
2331*991554f2SKenneth D. Merry 					*TLR_bits = TLR_on;
2332*991554f2SKenneth D. Merry 					break;
2333*991554f2SKenneth D. Merry 				}
2334*991554f2SKenneth D. Merry 			}
2335*991554f2SKenneth D. Merry 		}
2336*991554f2SKenneth D. Merry 		break;
2337*991554f2SKenneth D. Merry 	case MPI2_IOCSTATUS_SCSI_INVALID_DEVHANDLE:
2338*991554f2SKenneth D. Merry 	case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
2339*991554f2SKenneth D. Merry 		/*
2340*991554f2SKenneth D. Merry 		 * If devinfo is 0 this will be a volume.  In that case don't
2341*991554f2SKenneth D. Merry 		 * tell CAM that the volume is not there.  We want volumes to
2342*991554f2SKenneth D. Merry 		 * be enumerated until they are deleted/removed, not just
2343*991554f2SKenneth D. Merry 		 * failed.
2344*991554f2SKenneth D. Merry 		 */
2345*991554f2SKenneth D. Merry 		if (cm->cm_targ->devinfo == 0)
2346*991554f2SKenneth D. Merry 			ccb->ccb_h.status = CAM_REQ_CMP;
2347*991554f2SKenneth D. Merry 		else
2348*991554f2SKenneth D. Merry 			ccb->ccb_h.status = CAM_DEV_NOT_THERE;
2349*991554f2SKenneth D. Merry 		break;
2350*991554f2SKenneth D. Merry 	case MPI2_IOCSTATUS_INVALID_SGL:
2351*991554f2SKenneth D. Merry 		mpr_print_scsiio_cmd(sc, cm);
2352*991554f2SKenneth D. Merry 		ccb->ccb_h.status = CAM_UNREC_HBA_ERROR;
2353*991554f2SKenneth D. Merry 		break;
2354*991554f2SKenneth D. Merry 	case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED:
2355*991554f2SKenneth D. Merry 		/*
2356*991554f2SKenneth D. Merry 		 * This is one of the responses that comes back when an I/O
2357*991554f2SKenneth D. Merry 		 * has been aborted.  If it is because of a timeout that we
2358*991554f2SKenneth D. Merry 		 * initiated, just set the status to CAM_CMD_TIMEOUT.
2359*991554f2SKenneth D. Merry 		 * Otherwise set it to CAM_REQ_ABORTED.  The effect on the
2360*991554f2SKenneth D. Merry 		 * command is the same (it gets retried, subject to the
2361*991554f2SKenneth D. Merry 		 * retry counter), the only difference is what gets printed
2362*991554f2SKenneth D. Merry 		 * on the console.
2363*991554f2SKenneth D. Merry 		 */
2364*991554f2SKenneth D. Merry 		if (cm->cm_state == MPR_CM_STATE_TIMEDOUT)
2365*991554f2SKenneth D. Merry 			ccb->ccb_h.status = CAM_CMD_TIMEOUT;
2366*991554f2SKenneth D. Merry 		else
2367*991554f2SKenneth D. Merry 			ccb->ccb_h.status = CAM_REQ_ABORTED;
2368*991554f2SKenneth D. Merry 		break;
2369*991554f2SKenneth D. Merry 	case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN:
2370*991554f2SKenneth D. Merry 		/* resid is ignored for this condition */
2371*991554f2SKenneth D. Merry 		csio->resid = 0;
2372*991554f2SKenneth D. Merry 		ccb->ccb_h.status = CAM_DATA_RUN_ERR;
2373*991554f2SKenneth D. Merry 		break;
2374*991554f2SKenneth D. Merry 	case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED:
2375*991554f2SKenneth D. Merry 	case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED:
2376*991554f2SKenneth D. Merry 		/*
2377*991554f2SKenneth D. Merry 		 * Since these are generally external (i.e. hopefully
2378*991554f2SKenneth D. Merry 		 * transient transport-related) errors, retry these without
2379*991554f2SKenneth D. Merry 		 * decrementing the retry count.
2380*991554f2SKenneth D. Merry 		 */
2381*991554f2SKenneth D. Merry 		ccb->ccb_h.status = CAM_REQUEUE_REQ;
2382*991554f2SKenneth D. Merry 		mprsas_log_command(cm, MPR_INFO,
2383*991554f2SKenneth D. Merry 		    "terminated ioc %x scsi %x state %x xfer %u\n",
2384*991554f2SKenneth D. Merry 		    le16toh(rep->IOCStatus), rep->SCSIStatus, rep->SCSIState,
2385*991554f2SKenneth D. Merry 		    le32toh(rep->TransferCount));
2386*991554f2SKenneth D. Merry 		break;
2387*991554f2SKenneth D. Merry 	case MPI2_IOCSTATUS_INVALID_FUNCTION:
2388*991554f2SKenneth D. Merry 	case MPI2_IOCSTATUS_INTERNAL_ERROR:
2389*991554f2SKenneth D. Merry 	case MPI2_IOCSTATUS_INVALID_VPID:
2390*991554f2SKenneth D. Merry 	case MPI2_IOCSTATUS_INVALID_FIELD:
2391*991554f2SKenneth D. Merry 	case MPI2_IOCSTATUS_INVALID_STATE:
2392*991554f2SKenneth D. Merry 	case MPI2_IOCSTATUS_OP_STATE_NOT_SUPPORTED:
2393*991554f2SKenneth D. Merry 	case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR:
2394*991554f2SKenneth D. Merry 	case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR:
2395*991554f2SKenneth D. Merry 	case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
2396*991554f2SKenneth D. Merry 	case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
2397*991554f2SKenneth D. Merry 	default:
2398*991554f2SKenneth D. Merry 		mprsas_log_command(cm, MPR_XINFO,
2399*991554f2SKenneth D. Merry 		    "completed ioc %x scsi %x state %x xfer %u\n",
2400*991554f2SKenneth D. Merry 		    le16toh(rep->IOCStatus), rep->SCSIStatus, rep->SCSIState,
2401*991554f2SKenneth D. Merry 		    le32toh(rep->TransferCount));
2402*991554f2SKenneth D. Merry 		csio->resid = cm->cm_length;
2403*991554f2SKenneth D. Merry 		ccb->ccb_h.status = CAM_REQ_CMP_ERR;
2404*991554f2SKenneth D. Merry 		break;
2405*991554f2SKenneth D. Merry 	}
2406*991554f2SKenneth D. Merry 
2407*991554f2SKenneth D. Merry 	mpr_sc_failed_io_info(sc, csio, rep, cm->cm_targ);
2408*991554f2SKenneth D. Merry 
2409*991554f2SKenneth D. Merry 	if (sassc->flags & MPRSAS_QUEUE_FROZEN) {
2410*991554f2SKenneth D. Merry 		ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
2411*991554f2SKenneth D. Merry 		sassc->flags &= ~MPRSAS_QUEUE_FROZEN;
2412*991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_XINFO, "Command completed, unfreezing SIM "
2413*991554f2SKenneth D. Merry 		    "queue\n");
2414*991554f2SKenneth D. Merry 	}
2415*991554f2SKenneth D. Merry 
2416*991554f2SKenneth D. Merry 	if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
2417*991554f2SKenneth D. Merry 		ccb->ccb_h.status |= CAM_DEV_QFRZN;
2418*991554f2SKenneth D. Merry 		xpt_freeze_devq(ccb->ccb_h.path, /*count*/ 1);
2419*991554f2SKenneth D. Merry 	}
2420*991554f2SKenneth D. Merry 
2421*991554f2SKenneth D. Merry 	mpr_free_command(sc, cm);
2422*991554f2SKenneth D. Merry 	xpt_done(ccb);
2423*991554f2SKenneth D. Merry }
2424*991554f2SKenneth D. Merry 
2425*991554f2SKenneth D. Merry #if __FreeBSD_version >= 900026
2426*991554f2SKenneth D. Merry static void
2427*991554f2SKenneth D. Merry mprsas_smpio_complete(struct mpr_softc *sc, struct mpr_command *cm)
2428*991554f2SKenneth D. Merry {
2429*991554f2SKenneth D. Merry 	MPI2_SMP_PASSTHROUGH_REPLY *rpl;
2430*991554f2SKenneth D. Merry 	MPI2_SMP_PASSTHROUGH_REQUEST *req;
2431*991554f2SKenneth D. Merry 	uint64_t sasaddr;
2432*991554f2SKenneth D. Merry 	union ccb *ccb;
2433*991554f2SKenneth D. Merry 
2434*991554f2SKenneth D. Merry 	ccb = cm->cm_complete_data;
2435*991554f2SKenneth D. Merry 
2436*991554f2SKenneth D. Merry 	/*
2437*991554f2SKenneth D. Merry 	 * Currently there should be no way we can hit this case.  It only
2438*991554f2SKenneth D. Merry 	 * happens when we have a failure to allocate chain frames, and SMP
2439*991554f2SKenneth D. Merry 	 * commands require two S/G elements only.  That should be handled
2440*991554f2SKenneth D. Merry 	 * in the standard request size.
2441*991554f2SKenneth D. Merry 	 */
2442*991554f2SKenneth D. Merry 	if ((cm->cm_flags & MPR_CM_FLAGS_ERROR_MASK) != 0) {
2443*991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_ERROR,"%s: cm_flags = %#x on SMP request!\n",
2444*991554f2SKenneth D. Merry 		    __func__, cm->cm_flags);
2445*991554f2SKenneth D. Merry 		ccb->ccb_h.status = CAM_REQ_CMP_ERR;
2446*991554f2SKenneth D. Merry 		goto bailout;
2447*991554f2SKenneth D. Merry         }
2448*991554f2SKenneth D. Merry 
2449*991554f2SKenneth D. Merry 	rpl = (MPI2_SMP_PASSTHROUGH_REPLY *)cm->cm_reply;
2450*991554f2SKenneth D. Merry 	if (rpl == NULL) {
2451*991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_ERROR, "%s: NULL cm_reply!\n", __func__);
2452*991554f2SKenneth D. Merry 		ccb->ccb_h.status = CAM_REQ_CMP_ERR;
2453*991554f2SKenneth D. Merry 		goto bailout;
2454*991554f2SKenneth D. Merry 	}
2455*991554f2SKenneth D. Merry 
2456*991554f2SKenneth D. Merry 	req = (MPI2_SMP_PASSTHROUGH_REQUEST *)cm->cm_req;
2457*991554f2SKenneth D. Merry 	sasaddr = le32toh(req->SASAddress.Low);
2458*991554f2SKenneth D. Merry 	sasaddr |= ((uint64_t)(le32toh(req->SASAddress.High))) << 32;
2459*991554f2SKenneth D. Merry 
2460*991554f2SKenneth D. Merry 	if ((le16toh(rpl->IOCStatus) & MPI2_IOCSTATUS_MASK) !=
2461*991554f2SKenneth D. Merry 	    MPI2_IOCSTATUS_SUCCESS ||
2462*991554f2SKenneth D. Merry 	    rpl->SASStatus != MPI2_SASSTATUS_SUCCESS) {
2463*991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_XINFO, "%s: IOCStatus %04x SASStatus %02x\n",
2464*991554f2SKenneth D. Merry 		    __func__, le16toh(rpl->IOCStatus), rpl->SASStatus);
2465*991554f2SKenneth D. Merry 		ccb->ccb_h.status = CAM_REQ_CMP_ERR;
2466*991554f2SKenneth D. Merry 		goto bailout;
2467*991554f2SKenneth D. Merry 	}
2468*991554f2SKenneth D. Merry 
2469*991554f2SKenneth D. Merry 	mpr_dprint(sc, MPR_XINFO, "%s: SMP request to SAS address "
2470*991554f2SKenneth D. Merry 	    "%#jx completed successfully\n", __func__, (uintmax_t)sasaddr);
2471*991554f2SKenneth D. Merry 
2472*991554f2SKenneth D. Merry 	if (ccb->smpio.smp_response[2] == SMP_FR_ACCEPTED)
2473*991554f2SKenneth D. Merry 		ccb->ccb_h.status = CAM_REQ_CMP;
2474*991554f2SKenneth D. Merry 	else
2475*991554f2SKenneth D. Merry 		ccb->ccb_h.status = CAM_SMP_STATUS_ERROR;
2476*991554f2SKenneth D. Merry 
2477*991554f2SKenneth D. Merry bailout:
2478*991554f2SKenneth D. Merry 	/*
2479*991554f2SKenneth D. Merry 	 * We sync in both directions because we had DMAs in the S/G list
2480*991554f2SKenneth D. Merry 	 * in both directions.
2481*991554f2SKenneth D. Merry 	 */
2482*991554f2SKenneth D. Merry 	bus_dmamap_sync(sc->buffer_dmat, cm->cm_dmamap,
2483*991554f2SKenneth D. Merry 			BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
2484*991554f2SKenneth D. Merry 	bus_dmamap_unload(sc->buffer_dmat, cm->cm_dmamap);
2485*991554f2SKenneth D. Merry 	mpr_free_command(sc, cm);
2486*991554f2SKenneth D. Merry 	xpt_done(ccb);
2487*991554f2SKenneth D. Merry }
2488*991554f2SKenneth D. Merry 
2489*991554f2SKenneth D. Merry static void
2490*991554f2SKenneth D. Merry mprsas_send_smpcmd(struct mprsas_softc *sassc, union ccb *ccb,
2491*991554f2SKenneth D. Merry     uint64_t sasaddr)
2492*991554f2SKenneth D. Merry {
2493*991554f2SKenneth D. Merry 	struct mpr_command *cm;
2494*991554f2SKenneth D. Merry 	uint8_t *request, *response;
2495*991554f2SKenneth D. Merry 	MPI2_SMP_PASSTHROUGH_REQUEST *req;
2496*991554f2SKenneth D. Merry 	struct mpr_softc *sc;
2497*991554f2SKenneth D. Merry 	struct sglist *sg;
2498*991554f2SKenneth D. Merry 	int error;
2499*991554f2SKenneth D. Merry 
2500*991554f2SKenneth D. Merry 	sc = sassc->sc;
2501*991554f2SKenneth D. Merry 	sg = NULL;
2502*991554f2SKenneth D. Merry 	error = 0;
2503*991554f2SKenneth D. Merry 
2504*991554f2SKenneth D. Merry #if __FreeBSD_version >= 1000029
2505*991554f2SKenneth D. Merry 	switch (ccb->ccb_h.flags & CAM_DATA_MASK) {
2506*991554f2SKenneth D. Merry 	case CAM_DATA_PADDR:
2507*991554f2SKenneth D. Merry 	case CAM_DATA_SG_PADDR:
2508*991554f2SKenneth D. Merry 		/*
2509*991554f2SKenneth D. Merry 		 * XXX We don't yet support physical addresses here.
2510*991554f2SKenneth D. Merry 		 */
2511*991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_ERROR, "%s: physical addresses not "
2512*991554f2SKenneth D. Merry 		    "supported\n", __func__);
2513*991554f2SKenneth D. Merry 		ccb->ccb_h.status = CAM_REQ_INVALID;
2514*991554f2SKenneth D. Merry 		xpt_done(ccb);
2515*991554f2SKenneth D. Merry 		return;
2516*991554f2SKenneth D. Merry 	case CAM_DATA_SG:
2517*991554f2SKenneth D. Merry 		/*
2518*991554f2SKenneth D. Merry 		 * The chip does not support more than one buffer for the
2519*991554f2SKenneth D. Merry 		 * request or response.
2520*991554f2SKenneth D. Merry 		 */
2521*991554f2SKenneth D. Merry 		if ((ccb->smpio.smp_request_sglist_cnt > 1)
2522*991554f2SKenneth D. Merry 		    || (ccb->smpio.smp_response_sglist_cnt > 1)) {
2523*991554f2SKenneth D. Merry 			mpr_dprint(sc, MPR_ERROR,
2524*991554f2SKenneth D. Merry 			    "%s: multiple request or response buffer segments "
2525*991554f2SKenneth D. Merry 			    "not supported for SMP\n", __func__);
2526*991554f2SKenneth D. Merry 			ccb->ccb_h.status = CAM_REQ_INVALID;
2527*991554f2SKenneth D. Merry 			xpt_done(ccb);
2528*991554f2SKenneth D. Merry 			return;
2529*991554f2SKenneth D. Merry 		}
2530*991554f2SKenneth D. Merry 
2531*991554f2SKenneth D. Merry 		/*
2532*991554f2SKenneth D. Merry 		 * The CAM_SCATTER_VALID flag was originally implemented
2533*991554f2SKenneth D. Merry 		 * for the XPT_SCSI_IO CCB, which only has one data pointer.
2534*991554f2SKenneth D. Merry 		 * We have two.  So, just take that flag to mean that we
2535*991554f2SKenneth D. Merry 		 * might have S/G lists, and look at the S/G segment count
2536*991554f2SKenneth D. Merry 		 * to figure out whether that is the case for each individual
2537*991554f2SKenneth D. Merry 		 * buffer.
2538*991554f2SKenneth D. Merry 		 */
2539*991554f2SKenneth D. Merry 		if (ccb->smpio.smp_request_sglist_cnt != 0) {
2540*991554f2SKenneth D. Merry 			bus_dma_segment_t *req_sg;
2541*991554f2SKenneth D. Merry 
2542*991554f2SKenneth D. Merry 			req_sg = (bus_dma_segment_t *)ccb->smpio.smp_request;
2543*991554f2SKenneth D. Merry 			request = (uint8_t *)(uintptr_t)req_sg[0].ds_addr;
2544*991554f2SKenneth D. Merry 		} else
2545*991554f2SKenneth D. Merry 			request = ccb->smpio.smp_request;
2546*991554f2SKenneth D. Merry 
2547*991554f2SKenneth D. Merry 		if (ccb->smpio.smp_response_sglist_cnt != 0) {
2548*991554f2SKenneth D. Merry 			bus_dma_segment_t *rsp_sg;
2549*991554f2SKenneth D. Merry 
2550*991554f2SKenneth D. Merry 			rsp_sg = (bus_dma_segment_t *)ccb->smpio.smp_response;
2551*991554f2SKenneth D. Merry 			response = (uint8_t *)(uintptr_t)rsp_sg[0].ds_addr;
2552*991554f2SKenneth D. Merry 		} else
2553*991554f2SKenneth D. Merry 			response = ccb->smpio.smp_response;
2554*991554f2SKenneth D. Merry 		break;
2555*991554f2SKenneth D. Merry 	case CAM_DATA_VADDR:
2556*991554f2SKenneth D. Merry 		request = ccb->smpio.smp_request;
2557*991554f2SKenneth D. Merry 		response = ccb->smpio.smp_response;
2558*991554f2SKenneth D. Merry 		break;
2559*991554f2SKenneth D. Merry 	default:
2560*991554f2SKenneth D. Merry 		ccb->ccb_h.status = CAM_REQ_INVALID;
2561*991554f2SKenneth D. Merry 		xpt_done(ccb);
2562*991554f2SKenneth D. Merry 		return;
2563*991554f2SKenneth D. Merry 	}
2564*991554f2SKenneth D. Merry #else //__FreeBSD_version < 1000029
2565*991554f2SKenneth D. Merry 	/*
2566*991554f2SKenneth D. Merry 	 * XXX We don't yet support physical addresses here.
2567*991554f2SKenneth D. Merry 	 */
2568*991554f2SKenneth D. Merry 	if (ccb->ccb_h.flags & (CAM_DATA_PHYS|CAM_SG_LIST_PHYS)) {
2569*991554f2SKenneth D. Merry 		mpr_printf(sc, "%s: physical addresses not supported\n",
2570*991554f2SKenneth D. Merry 			   __func__);
2571*991554f2SKenneth D. Merry 		ccb->ccb_h.status = CAM_REQ_INVALID;
2572*991554f2SKenneth D. Merry 		xpt_done(ccb);
2573*991554f2SKenneth D. Merry 		return;
2574*991554f2SKenneth D. Merry 	}
2575*991554f2SKenneth D. Merry 
2576*991554f2SKenneth D. Merry 	/*
2577*991554f2SKenneth D. Merry 	 * If the user wants to send an S/G list, check to make sure they
2578*991554f2SKenneth D. Merry 	 * have single buffers.
2579*991554f2SKenneth D. Merry 	 */
2580*991554f2SKenneth D. Merry 	if (ccb->ccb_h.flags & CAM_SCATTER_VALID) {
2581*991554f2SKenneth D. Merry 		/*
2582*991554f2SKenneth D. Merry 		 * The chip does not support more than one buffer for the
2583*991554f2SKenneth D. Merry 		 * request or response.
2584*991554f2SKenneth D. Merry 		 */
2585*991554f2SKenneth D. Merry 	 	if ((ccb->smpio.smp_request_sglist_cnt > 1)
2586*991554f2SKenneth D. Merry 		  || (ccb->smpio.smp_response_sglist_cnt > 1)) {
2587*991554f2SKenneth D. Merry 			mpr_dprint(sc, MPR_ERROR, "%s: multiple request or "
2588*991554f2SKenneth D. Merry 			    "response buffer segments not supported for SMP\n",
2589*991554f2SKenneth D. Merry 			    __func__);
2590*991554f2SKenneth D. Merry 			ccb->ccb_h.status = CAM_REQ_INVALID;
2591*991554f2SKenneth D. Merry 			xpt_done(ccb);
2592*991554f2SKenneth D. Merry 			return;
2593*991554f2SKenneth D. Merry 		}
2594*991554f2SKenneth D. Merry 
2595*991554f2SKenneth D. Merry 		/*
2596*991554f2SKenneth D. Merry 		 * The CAM_SCATTER_VALID flag was originally implemented
2597*991554f2SKenneth D. Merry 		 * for the XPT_SCSI_IO CCB, which only has one data pointer.
2598*991554f2SKenneth D. Merry 		 * We have two.  So, just take that flag to mean that we
2599*991554f2SKenneth D. Merry 		 * might have S/G lists, and look at the S/G segment count
2600*991554f2SKenneth D. Merry 		 * to figure out whether that is the case for each individual
2601*991554f2SKenneth D. Merry 		 * buffer.
2602*991554f2SKenneth D. Merry 		 */
2603*991554f2SKenneth D. Merry 		if (ccb->smpio.smp_request_sglist_cnt != 0) {
2604*991554f2SKenneth D. Merry 			bus_dma_segment_t *req_sg;
2605*991554f2SKenneth D. Merry 
2606*991554f2SKenneth D. Merry 			req_sg = (bus_dma_segment_t *)ccb->smpio.smp_request;
2607*991554f2SKenneth D. Merry 			request = (uint8_t *)req_sg[0].ds_addr;
2608*991554f2SKenneth D. Merry 		} else
2609*991554f2SKenneth D. Merry 			request = ccb->smpio.smp_request;
2610*991554f2SKenneth D. Merry 
2611*991554f2SKenneth D. Merry 		if (ccb->smpio.smp_response_sglist_cnt != 0) {
2612*991554f2SKenneth D. Merry 			bus_dma_segment_t *rsp_sg;
2613*991554f2SKenneth D. Merry 
2614*991554f2SKenneth D. Merry 			rsp_sg = (bus_dma_segment_t *)ccb->smpio.smp_response;
2615*991554f2SKenneth D. Merry 			response = (uint8_t *)rsp_sg[0].ds_addr;
2616*991554f2SKenneth D. Merry 		} else
2617*991554f2SKenneth D. Merry 			response = ccb->smpio.smp_response;
2618*991554f2SKenneth D. Merry 	} else {
2619*991554f2SKenneth D. Merry 		request = ccb->smpio.smp_request;
2620*991554f2SKenneth D. Merry 		response = ccb->smpio.smp_response;
2621*991554f2SKenneth D. Merry 	}
2622*991554f2SKenneth D. Merry #endif //__FreeBSD_version >= 1000029
2623*991554f2SKenneth D. Merry 
2624*991554f2SKenneth D. Merry 	cm = mpr_alloc_command(sc);
2625*991554f2SKenneth D. Merry 	if (cm == NULL) {
2626*991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_ERROR,
2627*991554f2SKenneth D. Merry 		    "%s: cannot allocate command\n", __func__);
2628*991554f2SKenneth D. Merry 		ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
2629*991554f2SKenneth D. Merry 		xpt_done(ccb);
2630*991554f2SKenneth D. Merry 		return;
2631*991554f2SKenneth D. Merry 	}
2632*991554f2SKenneth D. Merry 
2633*991554f2SKenneth D. Merry 	req = (MPI2_SMP_PASSTHROUGH_REQUEST *)cm->cm_req;
2634*991554f2SKenneth D. Merry 	bzero(req, sizeof(*req));
2635*991554f2SKenneth D. Merry 	req->Function = MPI2_FUNCTION_SMP_PASSTHROUGH;
2636*991554f2SKenneth D. Merry 
2637*991554f2SKenneth D. Merry 	/* Allow the chip to use any route to this SAS address. */
2638*991554f2SKenneth D. Merry 	req->PhysicalPort = 0xff;
2639*991554f2SKenneth D. Merry 
2640*991554f2SKenneth D. Merry 	req->RequestDataLength = htole16(ccb->smpio.smp_request_len);
2641*991554f2SKenneth D. Merry 	req->SGLFlags =
2642*991554f2SKenneth D. Merry 	    MPI2_SGLFLAGS_SYSTEM_ADDRESS_SPACE | MPI2_SGLFLAGS_SGL_TYPE_MPI;
2643*991554f2SKenneth D. Merry 
2644*991554f2SKenneth D. Merry 	mpr_dprint(sc, MPR_XINFO, "%s: sending SMP request to SAS address "
2645*991554f2SKenneth D. Merry 	    "%#jx\n", __func__, (uintmax_t)sasaddr);
2646*991554f2SKenneth D. Merry 
2647*991554f2SKenneth D. Merry 	mpr_init_sge(cm, req, &req->SGL);
2648*991554f2SKenneth D. Merry 
2649*991554f2SKenneth D. Merry 	/*
2650*991554f2SKenneth D. Merry 	 * Set up a uio to pass into mpr_map_command().  This allows us to
2651*991554f2SKenneth D. Merry 	 * do one map command, and one busdma call in there.
2652*991554f2SKenneth D. Merry 	 */
2653*991554f2SKenneth D. Merry 	cm->cm_uio.uio_iov = cm->cm_iovec;
2654*991554f2SKenneth D. Merry 	cm->cm_uio.uio_iovcnt = 2;
2655*991554f2SKenneth D. Merry 	cm->cm_uio.uio_segflg = UIO_SYSSPACE;
2656*991554f2SKenneth D. Merry 
2657*991554f2SKenneth D. Merry 	/*
2658*991554f2SKenneth D. Merry 	 * The read/write flag isn't used by busdma, but set it just in
2659*991554f2SKenneth D. Merry 	 * case.  This isn't exactly accurate, either, since we're going in
2660*991554f2SKenneth D. Merry 	 * both directions.
2661*991554f2SKenneth D. Merry 	 */
2662*991554f2SKenneth D. Merry 	cm->cm_uio.uio_rw = UIO_WRITE;
2663*991554f2SKenneth D. Merry 
2664*991554f2SKenneth D. Merry 	cm->cm_iovec[0].iov_base = request;
2665*991554f2SKenneth D. Merry 	cm->cm_iovec[0].iov_len = le16toh(req->RequestDataLength);
2666*991554f2SKenneth D. Merry 	cm->cm_iovec[1].iov_base = response;
2667*991554f2SKenneth D. Merry 	cm->cm_iovec[1].iov_len = ccb->smpio.smp_response_len;
2668*991554f2SKenneth D. Merry 
2669*991554f2SKenneth D. Merry 	cm->cm_uio.uio_resid = cm->cm_iovec[0].iov_len +
2670*991554f2SKenneth D. Merry 			       cm->cm_iovec[1].iov_len;
2671*991554f2SKenneth D. Merry 
2672*991554f2SKenneth D. Merry 	/*
2673*991554f2SKenneth D. Merry 	 * Trigger a warning message in mpr_data_cb() for the user if we
2674*991554f2SKenneth D. Merry 	 * wind up exceeding two S/G segments.  The chip expects one
2675*991554f2SKenneth D. Merry 	 * segment for the request and another for the response.
2676*991554f2SKenneth D. Merry 	 */
2677*991554f2SKenneth D. Merry 	cm->cm_max_segs = 2;
2678*991554f2SKenneth D. Merry 
2679*991554f2SKenneth D. Merry 	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
2680*991554f2SKenneth D. Merry 	cm->cm_complete = mprsas_smpio_complete;
2681*991554f2SKenneth D. Merry 	cm->cm_complete_data = ccb;
2682*991554f2SKenneth D. Merry 
2683*991554f2SKenneth D. Merry 	/*
2684*991554f2SKenneth D. Merry 	 * Tell the mapping code that we're using a uio, and that this is
2685*991554f2SKenneth D. Merry 	 * an SMP passthrough request.  There is a little special-case
2686*991554f2SKenneth D. Merry 	 * logic there (in mpr_data_cb()) to handle the bidirectional
2687*991554f2SKenneth D. Merry 	 * transfer.
2688*991554f2SKenneth D. Merry 	 */
2689*991554f2SKenneth D. Merry 	cm->cm_flags |= MPR_CM_FLAGS_USE_UIO | MPR_CM_FLAGS_SMP_PASS |
2690*991554f2SKenneth D. Merry 			MPR_CM_FLAGS_DATAIN | MPR_CM_FLAGS_DATAOUT;
2691*991554f2SKenneth D. Merry 
2692*991554f2SKenneth D. Merry 	/* The chip data format is little endian. */
2693*991554f2SKenneth D. Merry 	req->SASAddress.High = htole32(sasaddr >> 32);
2694*991554f2SKenneth D. Merry 	req->SASAddress.Low = htole32(sasaddr);
2695*991554f2SKenneth D. Merry 
2696*991554f2SKenneth D. Merry 	/*
2697*991554f2SKenneth D. Merry 	 * XXX Note that we don't have a timeout/abort mechanism here.
2698*991554f2SKenneth D. Merry 	 * From the manual, it looks like task management requests only
2699*991554f2SKenneth D. Merry 	 * work for SCSI IO and SATA passthrough requests.  We may need to
2700*991554f2SKenneth D. Merry 	 * have a mechanism to retry requests in the event of a chip reset
2701*991554f2SKenneth D. Merry 	 * at least.  Hopefully the chip will insure that any errors short
2702*991554f2SKenneth D. Merry 	 * of that are relayed back to the driver.
2703*991554f2SKenneth D. Merry 	 */
2704*991554f2SKenneth D. Merry 	error = mpr_map_command(sc, cm);
2705*991554f2SKenneth D. Merry 	if ((error != 0) && (error != EINPROGRESS)) {
2706*991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_ERROR, "%s: error %d returned from "
2707*991554f2SKenneth D. Merry 		    "mpr_map_command()\n", __func__, error);
2708*991554f2SKenneth D. Merry 		goto bailout_error;
2709*991554f2SKenneth D. Merry 	}
2710*991554f2SKenneth D. Merry 
2711*991554f2SKenneth D. Merry 	return;
2712*991554f2SKenneth D. Merry 
2713*991554f2SKenneth D. Merry bailout_error:
2714*991554f2SKenneth D. Merry 	mpr_free_command(sc, cm);
2715*991554f2SKenneth D. Merry 	ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
2716*991554f2SKenneth D. Merry 	xpt_done(ccb);
2717*991554f2SKenneth D. Merry 	return;
2718*991554f2SKenneth D. Merry }
2719*991554f2SKenneth D. Merry 
2720*991554f2SKenneth D. Merry static void
2721*991554f2SKenneth D. Merry mprsas_action_smpio(struct mprsas_softc *sassc, union ccb *ccb)
2722*991554f2SKenneth D. Merry {
2723*991554f2SKenneth D. Merry 	struct mpr_softc *sc;
2724*991554f2SKenneth D. Merry 	struct mprsas_target *targ;
2725*991554f2SKenneth D. Merry 	uint64_t sasaddr = 0;
2726*991554f2SKenneth D. Merry 
2727*991554f2SKenneth D. Merry 	sc = sassc->sc;
2728*991554f2SKenneth D. Merry 
2729*991554f2SKenneth D. Merry 	/*
2730*991554f2SKenneth D. Merry 	 * Make sure the target exists.
2731*991554f2SKenneth D. Merry 	 */
2732*991554f2SKenneth D. Merry 	KASSERT(ccb->ccb_h.target_id < sassc->maxtargets,
2733*991554f2SKenneth D. Merry 	    ("Target %d out of bounds in XPT_SMP_IO\n", ccb->ccb_h.target_id));
2734*991554f2SKenneth D. Merry 	targ = &sassc->targets[ccb->ccb_h.target_id];
2735*991554f2SKenneth D. Merry 	if (targ->handle == 0x0) {
2736*991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_ERROR, "%s: target %d does not exist!\n",
2737*991554f2SKenneth D. Merry 		    __func__, ccb->ccb_h.target_id);
2738*991554f2SKenneth D. Merry 		ccb->ccb_h.status = CAM_SEL_TIMEOUT;
2739*991554f2SKenneth D. Merry 		xpt_done(ccb);
2740*991554f2SKenneth D. Merry 		return;
2741*991554f2SKenneth D. Merry 	}
2742*991554f2SKenneth D. Merry 
2743*991554f2SKenneth D. Merry 	/*
2744*991554f2SKenneth D. Merry 	 * If this device has an embedded SMP target, we'll talk to it
2745*991554f2SKenneth D. Merry 	 * directly.
2746*991554f2SKenneth D. Merry 	 * figure out what the expander's address is.
2747*991554f2SKenneth D. Merry 	 */
2748*991554f2SKenneth D. Merry 	if ((targ->devinfo & MPI2_SAS_DEVICE_INFO_SMP_TARGET) != 0)
2749*991554f2SKenneth D. Merry 		sasaddr = targ->sasaddr;
2750*991554f2SKenneth D. Merry 
2751*991554f2SKenneth D. Merry 	/*
2752*991554f2SKenneth D. Merry 	 * If we don't have a SAS address for the expander yet, try
2753*991554f2SKenneth D. Merry 	 * grabbing it from the page 0x83 information cached in the
2754*991554f2SKenneth D. Merry 	 * transport layer for this target.  LSI expanders report the
2755*991554f2SKenneth D. Merry 	 * expander SAS address as the port-associated SAS address in
2756*991554f2SKenneth D. Merry 	 * Inquiry VPD page 0x83.  Maxim expanders don't report it in page
2757*991554f2SKenneth D. Merry 	 * 0x83.
2758*991554f2SKenneth D. Merry 	 *
2759*991554f2SKenneth D. Merry 	 * XXX KDM disable this for now, but leave it commented out so that
2760*991554f2SKenneth D. Merry 	 * it is obvious that this is another possible way to get the SAS
2761*991554f2SKenneth D. Merry 	 * address.
2762*991554f2SKenneth D. Merry 	 *
2763*991554f2SKenneth D. Merry 	 * The parent handle method below is a little more reliable, and
2764*991554f2SKenneth D. Merry 	 * the other benefit is that it works for devices other than SES
2765*991554f2SKenneth D. Merry 	 * devices.  So you can send a SMP request to a da(4) device and it
2766*991554f2SKenneth D. Merry 	 * will get routed to the expander that device is attached to.
2767*991554f2SKenneth D. Merry 	 * (Assuming the da(4) device doesn't contain an SMP target...)
2768*991554f2SKenneth D. Merry 	 */
2769*991554f2SKenneth D. Merry #if 0
2770*991554f2SKenneth D. Merry 	if (sasaddr == 0)
2771*991554f2SKenneth D. Merry 		sasaddr = xpt_path_sas_addr(ccb->ccb_h.path);
2772*991554f2SKenneth D. Merry #endif
2773*991554f2SKenneth D. Merry 
2774*991554f2SKenneth D. Merry 	/*
2775*991554f2SKenneth D. Merry 	 * If we still don't have a SAS address for the expander, look for
2776*991554f2SKenneth D. Merry 	 * the parent device of this device, which is probably the expander.
2777*991554f2SKenneth D. Merry 	 */
2778*991554f2SKenneth D. Merry 	if (sasaddr == 0) {
2779*991554f2SKenneth D. Merry #ifdef OLD_MPR_PROBE
2780*991554f2SKenneth D. Merry 		struct mprsas_target *parent_target;
2781*991554f2SKenneth D. Merry #endif
2782*991554f2SKenneth D. Merry 
2783*991554f2SKenneth D. Merry 		if (targ->parent_handle == 0x0) {
2784*991554f2SKenneth D. Merry 			mpr_dprint(sc, MPR_ERROR, "%s: handle %d does not have "
2785*991554f2SKenneth D. Merry 			    "a valid parent handle!\n", __func__, targ->handle);
2786*991554f2SKenneth D. Merry 			ccb->ccb_h.status = CAM_DEV_NOT_THERE;
2787*991554f2SKenneth D. Merry 			goto bailout;
2788*991554f2SKenneth D. Merry 		}
2789*991554f2SKenneth D. Merry #ifdef OLD_MPR_PROBE
2790*991554f2SKenneth D. Merry 		parent_target = mprsas_find_target_by_handle(sassc, 0,
2791*991554f2SKenneth D. Merry 		    targ->parent_handle);
2792*991554f2SKenneth D. Merry 
2793*991554f2SKenneth D. Merry 		if (parent_target == NULL) {
2794*991554f2SKenneth D. Merry 			mpr_dprint(sc, MPR_ERROR, "%s: handle %d does not have "
2795*991554f2SKenneth D. Merry 			    "a valid parent target!\n", __func__, targ->handle);
2796*991554f2SKenneth D. Merry 			ccb->ccb_h.status = CAM_DEV_NOT_THERE;
2797*991554f2SKenneth D. Merry 			goto bailout;
2798*991554f2SKenneth D. Merry 		}
2799*991554f2SKenneth D. Merry 
2800*991554f2SKenneth D. Merry 		if ((parent_target->devinfo &
2801*991554f2SKenneth D. Merry 		     MPI2_SAS_DEVICE_INFO_SMP_TARGET) == 0) {
2802*991554f2SKenneth D. Merry 			mpr_dprint(sc, MPR_ERROR, "%s: handle %d parent %d "
2803*991554f2SKenneth D. Merry 			    "does not have an SMP target!\n", __func__,
2804*991554f2SKenneth D. Merry 			    targ->handle, parent_target->handle);
2805*991554f2SKenneth D. Merry 			ccb->ccb_h.status = CAM_DEV_NOT_THERE;
2806*991554f2SKenneth D. Merry 			goto bailout;
2807*991554f2SKenneth D. Merry 
2808*991554f2SKenneth D. Merry 		}
2809*991554f2SKenneth D. Merry 
2810*991554f2SKenneth D. Merry 		sasaddr = parent_target->sasaddr;
2811*991554f2SKenneth D. Merry #else /* OLD_MPR_PROBE */
2812*991554f2SKenneth D. Merry 		if ((targ->parent_devinfo &
2813*991554f2SKenneth D. Merry 		     MPI2_SAS_DEVICE_INFO_SMP_TARGET) == 0) {
2814*991554f2SKenneth D. Merry 			mpr_dprint(sc, MPR_ERROR, "%s: handle %d parent %d "
2815*991554f2SKenneth D. Merry 			    "does not have an SMP target!\n", __func__,
2816*991554f2SKenneth D. Merry 			    targ->handle, targ->parent_handle);
2817*991554f2SKenneth D. Merry 			ccb->ccb_h.status = CAM_DEV_NOT_THERE;
2818*991554f2SKenneth D. Merry 			goto bailout;
2819*991554f2SKenneth D. Merry 
2820*991554f2SKenneth D. Merry 		}
2821*991554f2SKenneth D. Merry 		if (targ->parent_sasaddr == 0x0) {
2822*991554f2SKenneth D. Merry 			mpr_dprint(sc, MPR_ERROR, "%s: handle %d parent handle "
2823*991554f2SKenneth D. Merry 			    "%d does not have a valid SAS address!\n", __func__,
2824*991554f2SKenneth D. Merry 			    targ->handle, targ->parent_handle);
2825*991554f2SKenneth D. Merry 			ccb->ccb_h.status = CAM_DEV_NOT_THERE;
2826*991554f2SKenneth D. Merry 			goto bailout;
2827*991554f2SKenneth D. Merry 		}
2828*991554f2SKenneth D. Merry 
2829*991554f2SKenneth D. Merry 		sasaddr = targ->parent_sasaddr;
2830*991554f2SKenneth D. Merry #endif /* OLD_MPR_PROBE */
2831*991554f2SKenneth D. Merry 
2832*991554f2SKenneth D. Merry 	}
2833*991554f2SKenneth D. Merry 
2834*991554f2SKenneth D. Merry 	if (sasaddr == 0) {
2835*991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_INFO, "%s: unable to find SAS address for "
2836*991554f2SKenneth D. Merry 		    "handle %d\n", __func__, targ->handle);
2837*991554f2SKenneth D. Merry 		ccb->ccb_h.status = CAM_DEV_NOT_THERE;
2838*991554f2SKenneth D. Merry 		goto bailout;
2839*991554f2SKenneth D. Merry 	}
2840*991554f2SKenneth D. Merry 	mprsas_send_smpcmd(sassc, ccb, sasaddr);
2841*991554f2SKenneth D. Merry 
2842*991554f2SKenneth D. Merry 	return;
2843*991554f2SKenneth D. Merry 
2844*991554f2SKenneth D. Merry bailout:
2845*991554f2SKenneth D. Merry 	xpt_done(ccb);
2846*991554f2SKenneth D. Merry 
2847*991554f2SKenneth D. Merry }
2848*991554f2SKenneth D. Merry #endif //__FreeBSD_version >= 900026
2849*991554f2SKenneth D. Merry 
2850*991554f2SKenneth D. Merry static void
2851*991554f2SKenneth D. Merry mprsas_action_resetdev(struct mprsas_softc *sassc, union ccb *ccb)
2852*991554f2SKenneth D. Merry {
2853*991554f2SKenneth D. Merry 	MPI2_SCSI_TASK_MANAGE_REQUEST *req;
2854*991554f2SKenneth D. Merry 	struct mpr_softc *sc;
2855*991554f2SKenneth D. Merry 	struct mpr_command *tm;
2856*991554f2SKenneth D. Merry 	struct mprsas_target *targ;
2857*991554f2SKenneth D. Merry 
2858*991554f2SKenneth D. Merry 	MPR_FUNCTRACE(sassc->sc);
2859*991554f2SKenneth D. Merry 	mtx_assert(&sassc->sc->mpr_mtx, MA_OWNED);
2860*991554f2SKenneth D. Merry 
2861*991554f2SKenneth D. Merry 	KASSERT(ccb->ccb_h.target_id < sassc->maxtargets,
2862*991554f2SKenneth D. Merry 	    ("Target %d out of bounds in XPT_RESET_DEV\n",
2863*991554f2SKenneth D. Merry 	    ccb->ccb_h.target_id));
2864*991554f2SKenneth D. Merry 	sc = sassc->sc;
2865*991554f2SKenneth D. Merry 	tm = mpr_alloc_command(sc);
2866*991554f2SKenneth D. Merry 	if (tm == NULL) {
2867*991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_ERROR,
2868*991554f2SKenneth D. Merry 		    "command alloc failure in mprsas_action_resetdev\n");
2869*991554f2SKenneth D. Merry 		ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
2870*991554f2SKenneth D. Merry 		xpt_done(ccb);
2871*991554f2SKenneth D. Merry 		return;
2872*991554f2SKenneth D. Merry 	}
2873*991554f2SKenneth D. Merry 
2874*991554f2SKenneth D. Merry 	targ = &sassc->targets[ccb->ccb_h.target_id];
2875*991554f2SKenneth D. Merry 	req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req;
2876*991554f2SKenneth D. Merry 	req->DevHandle = htole16(targ->handle);
2877*991554f2SKenneth D. Merry 	req->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
2878*991554f2SKenneth D. Merry 	req->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
2879*991554f2SKenneth D. Merry 
2880*991554f2SKenneth D. Merry 	/* SAS Hard Link Reset / SATA Link Reset */
2881*991554f2SKenneth D. Merry 	req->MsgFlags = MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET;
2882*991554f2SKenneth D. Merry 
2883*991554f2SKenneth D. Merry 	tm->cm_data = NULL;
2884*991554f2SKenneth D. Merry 	tm->cm_desc.HighPriority.RequestFlags =
2885*991554f2SKenneth D. Merry 	    MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY;
2886*991554f2SKenneth D. Merry 	tm->cm_complete = mprsas_resetdev_complete;
2887*991554f2SKenneth D. Merry 	tm->cm_complete_data = ccb;
2888*991554f2SKenneth D. Merry 	tm->cm_targ = targ;
2889*991554f2SKenneth D. Merry 	mpr_map_command(sc, tm);
2890*991554f2SKenneth D. Merry }
2891*991554f2SKenneth D. Merry 
2892*991554f2SKenneth D. Merry static void
2893*991554f2SKenneth D. Merry mprsas_resetdev_complete(struct mpr_softc *sc, struct mpr_command *tm)
2894*991554f2SKenneth D. Merry {
2895*991554f2SKenneth D. Merry 	MPI2_SCSI_TASK_MANAGE_REPLY *resp;
2896*991554f2SKenneth D. Merry 	union ccb *ccb;
2897*991554f2SKenneth D. Merry 
2898*991554f2SKenneth D. Merry 	MPR_FUNCTRACE(sc);
2899*991554f2SKenneth D. Merry 	mtx_assert(&sc->mpr_mtx, MA_OWNED);
2900*991554f2SKenneth D. Merry 
2901*991554f2SKenneth D. Merry 	resp = (MPI2_SCSI_TASK_MANAGE_REPLY *)tm->cm_reply;
2902*991554f2SKenneth D. Merry 	ccb = tm->cm_complete_data;
2903*991554f2SKenneth D. Merry 
2904*991554f2SKenneth D. Merry 	/*
2905*991554f2SKenneth D. Merry 	 * Currently there should be no way we can hit this case.  It only
2906*991554f2SKenneth D. Merry 	 * happens when we have a failure to allocate chain frames, and
2907*991554f2SKenneth D. Merry 	 * task management commands don't have S/G lists.
2908*991554f2SKenneth D. Merry 	 */
2909*991554f2SKenneth D. Merry 	if ((tm->cm_flags & MPR_CM_FLAGS_ERROR_MASK) != 0) {
2910*991554f2SKenneth D. Merry 		MPI2_SCSI_TASK_MANAGE_REQUEST *req;
2911*991554f2SKenneth D. Merry 
2912*991554f2SKenneth D. Merry 		req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req;
2913*991554f2SKenneth D. Merry 
2914*991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_ERROR, "%s: cm_flags = %#x for reset of "
2915*991554f2SKenneth D. Merry 		    "handle %#04x! This should not happen!\n", __func__,
2916*991554f2SKenneth D. Merry 		    tm->cm_flags, req->DevHandle);
2917*991554f2SKenneth D. Merry 		ccb->ccb_h.status = CAM_REQ_CMP_ERR;
2918*991554f2SKenneth D. Merry 		goto bailout;
2919*991554f2SKenneth D. Merry 	}
2920*991554f2SKenneth D. Merry 
2921*991554f2SKenneth D. Merry 	mpr_dprint(sc, MPR_XINFO,
2922*991554f2SKenneth D. Merry 	    "%s: IOCStatus = 0x%x ResponseCode = 0x%x\n", __func__,
2923*991554f2SKenneth D. Merry 	    le16toh(resp->IOCStatus), le32toh(resp->ResponseCode));
2924*991554f2SKenneth D. Merry 
2925*991554f2SKenneth D. Merry 	if (le32toh(resp->ResponseCode) == MPI2_SCSITASKMGMT_RSP_TM_COMPLETE) {
2926*991554f2SKenneth D. Merry 		ccb->ccb_h.status = CAM_REQ_CMP;
2927*991554f2SKenneth D. Merry 		mprsas_announce_reset(sc, AC_SENT_BDR, tm->cm_targ->tid,
2928*991554f2SKenneth D. Merry 		    CAM_LUN_WILDCARD);
2929*991554f2SKenneth D. Merry 	}
2930*991554f2SKenneth D. Merry 	else
2931*991554f2SKenneth D. Merry 		ccb->ccb_h.status = CAM_REQ_CMP_ERR;
2932*991554f2SKenneth D. Merry 
2933*991554f2SKenneth D. Merry bailout:
2934*991554f2SKenneth D. Merry 
2935*991554f2SKenneth D. Merry 	mprsas_free_tm(sc, tm);
2936*991554f2SKenneth D. Merry 	xpt_done(ccb);
2937*991554f2SKenneth D. Merry }
2938*991554f2SKenneth D. Merry 
2939*991554f2SKenneth D. Merry static void
2940*991554f2SKenneth D. Merry mprsas_poll(struct cam_sim *sim)
2941*991554f2SKenneth D. Merry {
2942*991554f2SKenneth D. Merry 	struct mprsas_softc *sassc;
2943*991554f2SKenneth D. Merry 
2944*991554f2SKenneth D. Merry 	sassc = cam_sim_softc(sim);
2945*991554f2SKenneth D. Merry 
2946*991554f2SKenneth D. Merry 	if (sassc->sc->mpr_debug & MPR_TRACE) {
2947*991554f2SKenneth D. Merry 		/* frequent debug messages during a panic just slow
2948*991554f2SKenneth D. Merry 		 * everything down too much.
2949*991554f2SKenneth D. Merry 		 */
2950*991554f2SKenneth D. Merry 		mpr_printf(sassc->sc, "%s clearing MPR_TRACE\n", __func__);
2951*991554f2SKenneth D. Merry 		sassc->sc->mpr_debug &= ~MPR_TRACE;
2952*991554f2SKenneth D. Merry 	}
2953*991554f2SKenneth D. Merry 
2954*991554f2SKenneth D. Merry 	mpr_intr_locked(sassc->sc);
2955*991554f2SKenneth D. Merry }
2956*991554f2SKenneth D. Merry 
2957*991554f2SKenneth D. Merry static void
2958*991554f2SKenneth D. Merry mprsas_async(void *callback_arg, uint32_t code, struct cam_path *path,
2959*991554f2SKenneth D. Merry     void *arg)
2960*991554f2SKenneth D. Merry {
2961*991554f2SKenneth D. Merry 	struct mpr_softc *sc;
2962*991554f2SKenneth D. Merry 
2963*991554f2SKenneth D. Merry 	sc = (struct mpr_softc *)callback_arg;
2964*991554f2SKenneth D. Merry 
2965*991554f2SKenneth D. Merry 	switch (code) {
2966*991554f2SKenneth D. Merry #if (__FreeBSD_version >= 1000006) || \
2967*991554f2SKenneth D. Merry     ((__FreeBSD_version >= 901503) && (__FreeBSD_version < 1000000))
2968*991554f2SKenneth D. Merry 	case AC_ADVINFO_CHANGED: {
2969*991554f2SKenneth D. Merry 		struct mprsas_target *target;
2970*991554f2SKenneth D. Merry 		struct mprsas_softc *sassc;
2971*991554f2SKenneth D. Merry 		struct scsi_read_capacity_data_long rcap_buf;
2972*991554f2SKenneth D. Merry 		struct ccb_dev_advinfo cdai;
2973*991554f2SKenneth D. Merry 		struct mprsas_lun *lun;
2974*991554f2SKenneth D. Merry 		lun_id_t lunid;
2975*991554f2SKenneth D. Merry 		int found_lun;
2976*991554f2SKenneth D. Merry 		uintptr_t buftype;
2977*991554f2SKenneth D. Merry 
2978*991554f2SKenneth D. Merry 		buftype = (uintptr_t)arg;
2979*991554f2SKenneth D. Merry 
2980*991554f2SKenneth D. Merry 		found_lun = 0;
2981*991554f2SKenneth D. Merry 		sassc = sc->sassc;
2982*991554f2SKenneth D. Merry 
2983*991554f2SKenneth D. Merry 		/*
2984*991554f2SKenneth D. Merry 		 * We're only interested in read capacity data changes.
2985*991554f2SKenneth D. Merry 		 */
2986*991554f2SKenneth D. Merry 		if (buftype != CDAI_TYPE_RCAPLONG)
2987*991554f2SKenneth D. Merry 			break;
2988*991554f2SKenneth D. Merry 
2989*991554f2SKenneth D. Merry 		/*
2990*991554f2SKenneth D. Merry 		 * We should have a handle for this, but check to make sure.
2991*991554f2SKenneth D. Merry 		 */
2992*991554f2SKenneth D. Merry 		KASSERT(xpt_path_target_id(path) < sassc->maxtargets,
2993*991554f2SKenneth D. Merry 		    ("Target %d out of bounds in mprsas_async\n",
2994*991554f2SKenneth D. Merry 		    xpt_path_target_id(path)));
2995*991554f2SKenneth D. Merry 		target = &sassc->targets[xpt_path_target_id(path)];
2996*991554f2SKenneth D. Merry 		if (target->handle == 0)
2997*991554f2SKenneth D. Merry 			break;
2998*991554f2SKenneth D. Merry 
2999*991554f2SKenneth D. Merry 		lunid = xpt_path_lun_id(path);
3000*991554f2SKenneth D. Merry 
3001*991554f2SKenneth D. Merry 		SLIST_FOREACH(lun, &target->luns, lun_link) {
3002*991554f2SKenneth D. Merry 			if (lun->lun_id == lunid) {
3003*991554f2SKenneth D. Merry 				found_lun = 1;
3004*991554f2SKenneth D. Merry 				break;
3005*991554f2SKenneth D. Merry 			}
3006*991554f2SKenneth D. Merry 		}
3007*991554f2SKenneth D. Merry 
3008*991554f2SKenneth D. Merry 		if (found_lun == 0) {
3009*991554f2SKenneth D. Merry 			lun = malloc(sizeof(struct mprsas_lun), M_MPR,
3010*991554f2SKenneth D. Merry 			    M_NOWAIT | M_ZERO);
3011*991554f2SKenneth D. Merry 			if (lun == NULL) {
3012*991554f2SKenneth D. Merry 				mpr_dprint(sc, MPR_ERROR, "Unable to alloc "
3013*991554f2SKenneth D. Merry 				    "LUN for EEDP support.\n");
3014*991554f2SKenneth D. Merry 				break;
3015*991554f2SKenneth D. Merry 			}
3016*991554f2SKenneth D. Merry 			lun->lun_id = lunid;
3017*991554f2SKenneth D. Merry 			SLIST_INSERT_HEAD(&target->luns, lun, lun_link);
3018*991554f2SKenneth D. Merry 		}
3019*991554f2SKenneth D. Merry 
3020*991554f2SKenneth D. Merry 		bzero(&rcap_buf, sizeof(rcap_buf));
3021*991554f2SKenneth D. Merry 		xpt_setup_ccb(&cdai.ccb_h, path, CAM_PRIORITY_NORMAL);
3022*991554f2SKenneth D. Merry 		cdai.ccb_h.func_code = XPT_DEV_ADVINFO;
3023*991554f2SKenneth D. Merry 		cdai.ccb_h.flags = CAM_DIR_IN;
3024*991554f2SKenneth D. Merry 		cdai.buftype = CDAI_TYPE_RCAPLONG;
3025*991554f2SKenneth D. Merry 		cdai.flags = 0;
3026*991554f2SKenneth D. Merry 		cdai.bufsiz = sizeof(rcap_buf);
3027*991554f2SKenneth D. Merry 		cdai.buf = (uint8_t *)&rcap_buf;
3028*991554f2SKenneth D. Merry 		xpt_action((union ccb *)&cdai);
3029*991554f2SKenneth D. Merry 		if ((cdai.ccb_h.status & CAM_DEV_QFRZN) != 0)
3030*991554f2SKenneth D. Merry 			cam_release_devq(cdai.ccb_h.path, 0, 0, 0, FALSE);
3031*991554f2SKenneth D. Merry 
3032*991554f2SKenneth D. Merry 		if (((cdai.ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP)
3033*991554f2SKenneth D. Merry 		    && (rcap_buf.prot & SRC16_PROT_EN)) {
3034*991554f2SKenneth D. Merry 			lun->eedp_formatted = TRUE;
3035*991554f2SKenneth D. Merry 			lun->eedp_block_size = scsi_4btoul(rcap_buf.length);
3036*991554f2SKenneth D. Merry 		} else {
3037*991554f2SKenneth D. Merry 			lun->eedp_formatted = FALSE;
3038*991554f2SKenneth D. Merry 			lun->eedp_block_size = 0;
3039*991554f2SKenneth D. Merry 		}
3040*991554f2SKenneth D. Merry 		break;
3041*991554f2SKenneth D. Merry 	}
3042*991554f2SKenneth D. Merry #endif
3043*991554f2SKenneth D. Merry 	case AC_FOUND_DEVICE: {
3044*991554f2SKenneth D. Merry 		struct ccb_getdev *cgd;
3045*991554f2SKenneth D. Merry 
3046*991554f2SKenneth D. Merry 		cgd = arg;
3047*991554f2SKenneth D. Merry 		mprsas_prepare_ssu(sc, path, cgd);
3048*991554f2SKenneth D. Merry #if (__FreeBSD_version < 901503) || \
3049*991554f2SKenneth D. Merry     ((__FreeBSD_version >= 1000000) && (__FreeBSD_version < 1000006))
3050*991554f2SKenneth D. Merry 		mprsas_check_eedp(sc, path, cgd);
3051*991554f2SKenneth D. Merry #endif
3052*991554f2SKenneth D. Merry 		break;
3053*991554f2SKenneth D. Merry 	}
3054*991554f2SKenneth D. Merry 	default:
3055*991554f2SKenneth D. Merry 		break;
3056*991554f2SKenneth D. Merry 	}
3057*991554f2SKenneth D. Merry }
3058*991554f2SKenneth D. Merry 
3059*991554f2SKenneth D. Merry static void
3060*991554f2SKenneth D. Merry mprsas_prepare_ssu(struct mpr_softc *sc, struct cam_path *path,
3061*991554f2SKenneth D. Merry     struct ccb_getdev *cgd)
3062*991554f2SKenneth D. Merry {
3063*991554f2SKenneth D. Merry 	struct mprsas_softc *sassc = sc->sassc;
3064*991554f2SKenneth D. Merry 	path_id_t pathid;
3065*991554f2SKenneth D. Merry 	target_id_t targetid;
3066*991554f2SKenneth D. Merry 	lun_id_t lunid;
3067*991554f2SKenneth D. Merry 	struct mprsas_target *target;
3068*991554f2SKenneth D. Merry 	struct mprsas_lun *lun;
3069*991554f2SKenneth D. Merry 	uint8_t	found_lun;
3070*991554f2SKenneth D. Merry 
3071*991554f2SKenneth D. Merry 	sassc = sc->sassc;
3072*991554f2SKenneth D. Merry 	pathid = cam_sim_path(sassc->sim);
3073*991554f2SKenneth D. Merry 	targetid = xpt_path_target_id(path);
3074*991554f2SKenneth D. Merry 	lunid = xpt_path_lun_id(path);
3075*991554f2SKenneth D. Merry 
3076*991554f2SKenneth D. Merry 	KASSERT(targetid < sassc->maxtargets,
3077*991554f2SKenneth D. Merry 	    ("Target %d out of bounds in mprsas_prepare_ssu\n", targetid));
3078*991554f2SKenneth D. Merry 	target = &sassc->targets[targetid];
3079*991554f2SKenneth D. Merry 	if (target->handle == 0x0)
3080*991554f2SKenneth D. Merry 		return;
3081*991554f2SKenneth D. Merry 
3082*991554f2SKenneth D. Merry 	/*
3083*991554f2SKenneth D. Merry 	 * If LUN is already in list, don't create a new one.
3084*991554f2SKenneth D. Merry 	 */
3085*991554f2SKenneth D. Merry 	found_lun = FALSE;
3086*991554f2SKenneth D. Merry 	SLIST_FOREACH(lun, &target->luns, lun_link) {
3087*991554f2SKenneth D. Merry 		if (lun->lun_id == lunid) {
3088*991554f2SKenneth D. Merry 			found_lun = TRUE;
3089*991554f2SKenneth D. Merry 			break;
3090*991554f2SKenneth D. Merry 		}
3091*991554f2SKenneth D. Merry 	}
3092*991554f2SKenneth D. Merry 	if (!found_lun) {
3093*991554f2SKenneth D. Merry 		lun = malloc(sizeof(struct mprsas_lun), M_MPR,
3094*991554f2SKenneth D. Merry 		    M_NOWAIT | M_ZERO);
3095*991554f2SKenneth D. Merry 		if (lun == NULL) {
3096*991554f2SKenneth D. Merry 			mpr_dprint(sc, MPR_ERROR, "Unable to alloc LUN for "
3097*991554f2SKenneth D. Merry 			    "preparing SSU.\n");
3098*991554f2SKenneth D. Merry 			return;
3099*991554f2SKenneth D. Merry 		}
3100*991554f2SKenneth D. Merry 		lun->lun_id = lunid;
3101*991554f2SKenneth D. Merry 		SLIST_INSERT_HEAD(&target->luns, lun, lun_link);
3102*991554f2SKenneth D. Merry 	}
3103*991554f2SKenneth D. Merry 
3104*991554f2SKenneth D. Merry 	/*
3105*991554f2SKenneth D. Merry 	 * If this is a SATA direct-access end device, mark it so that a SCSI
3106*991554f2SKenneth D. Merry 	 * StartStopUnit command will be sent to it when the driver is being
3107*991554f2SKenneth D. Merry 	 * shutdown.
3108*991554f2SKenneth D. Merry 	 */
3109*991554f2SKenneth D. Merry 	if (((cgd->inq_data.device & 0x1F) == T_DIRECT) &&
3110*991554f2SKenneth D. Merry 	    (target->devinfo & MPI2_SAS_DEVICE_INFO_SATA_DEVICE) &&
3111*991554f2SKenneth D. Merry 	    ((target->devinfo & MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) ==
3112*991554f2SKenneth D. Merry 	    MPI2_SAS_DEVICE_INFO_END_DEVICE)) {
3113*991554f2SKenneth D. Merry 		lun->stop_at_shutdown = TRUE;
3114*991554f2SKenneth D. Merry 	}
3115*991554f2SKenneth D. Merry }
3116*991554f2SKenneth D. Merry 
3117*991554f2SKenneth D. Merry #if (__FreeBSD_version < 901503) || \
3118*991554f2SKenneth D. Merry     ((__FreeBSD_version >= 1000000) && (__FreeBSD_version < 1000006))
3119*991554f2SKenneth D. Merry static void
3120*991554f2SKenneth D. Merry mprsas_check_eedp(struct mpr_softc *sc, struct cam_path *path,
3121*991554f2SKenneth D. Merry     struct ccb_getdev *cgd)
3122*991554f2SKenneth D. Merry {
3123*991554f2SKenneth D. Merry 	struct mprsas_softc *sassc = sc->sassc;
3124*991554f2SKenneth D. Merry 	struct ccb_scsiio *csio;
3125*991554f2SKenneth D. Merry 	struct scsi_read_capacity_16 *scsi_cmd;
3126*991554f2SKenneth D. Merry 	struct scsi_read_capacity_eedp *rcap_buf;
3127*991554f2SKenneth D. Merry 	path_id_t pathid;
3128*991554f2SKenneth D. Merry 	target_id_t targetid;
3129*991554f2SKenneth D. Merry 	lun_id_t lunid;
3130*991554f2SKenneth D. Merry 	union ccb *ccb;
3131*991554f2SKenneth D. Merry 	struct cam_path *local_path;
3132*991554f2SKenneth D. Merry 	struct mprsas_target *target;
3133*991554f2SKenneth D. Merry 	struct mprsas_lun *lun;
3134*991554f2SKenneth D. Merry 	uint8_t	found_lun;
3135*991554f2SKenneth D. Merry 	char path_str[64];
3136*991554f2SKenneth D. Merry 
3137*991554f2SKenneth D. Merry 	sassc = sc->sassc;
3138*991554f2SKenneth D. Merry 	pathid = cam_sim_path(sassc->sim);
3139*991554f2SKenneth D. Merry 	targetid = xpt_path_target_id(path);
3140*991554f2SKenneth D. Merry 	lunid = xpt_path_lun_id(path);
3141*991554f2SKenneth D. Merry 
3142*991554f2SKenneth D. Merry 	KASSERT(targetid < sassc->maxtargets,
3143*991554f2SKenneth D. Merry 	    ("Target %d out of bounds in mprsas_check_eedp\n", targetid));
3144*991554f2SKenneth D. Merry 	target = &sassc->targets[targetid];
3145*991554f2SKenneth D. Merry 	if (target->handle == 0x0)
3146*991554f2SKenneth D. Merry 		return;
3147*991554f2SKenneth D. Merry 
3148*991554f2SKenneth D. Merry 	/*
3149*991554f2SKenneth D. Merry 	 * Determine if the device is EEDP capable.
3150*991554f2SKenneth D. Merry 	 *
3151*991554f2SKenneth D. Merry 	 * If this flag is set in the inquiry data, the device supports
3152*991554f2SKenneth D. Merry 	 * protection information, and must support the 16 byte read capacity
3153*991554f2SKenneth D. Merry 	 * command, otherwise continue without sending read cap 16
3154*991554f2SKenneth D. Merry 	 */
3155*991554f2SKenneth D. Merry 	if ((cgd->inq_data.spc3_flags & SPC3_SID_PROTECT) == 0)
3156*991554f2SKenneth D. Merry 		return;
3157*991554f2SKenneth D. Merry 
3158*991554f2SKenneth D. Merry 	/*
3159*991554f2SKenneth D. Merry 	 * Issue a READ CAPACITY 16 command.  This info is used to determine if
3160*991554f2SKenneth D. Merry 	 * the LUN is formatted for EEDP support.
3161*991554f2SKenneth D. Merry 	 */
3162*991554f2SKenneth D. Merry 	ccb = xpt_alloc_ccb_nowait();
3163*991554f2SKenneth D. Merry 	if (ccb == NULL) {
3164*991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_ERROR, "Unable to alloc CCB for EEDP "
3165*991554f2SKenneth D. Merry 		    "support.\n");
3166*991554f2SKenneth D. Merry 		return;
3167*991554f2SKenneth D. Merry 	}
3168*991554f2SKenneth D. Merry 
3169*991554f2SKenneth D. Merry 	if (xpt_create_path(&local_path, xpt_periph, pathid, targetid, lunid)
3170*991554f2SKenneth D. Merry 	    != CAM_REQ_CMP) {
3171*991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_ERROR, "Unable to create path for EEDP "
3172*991554f2SKenneth D. Merry 		    "support\n");
3173*991554f2SKenneth D. Merry 		xpt_free_ccb(ccb);
3174*991554f2SKenneth D. Merry 		return;
3175*991554f2SKenneth D. Merry 	}
3176*991554f2SKenneth D. Merry 
3177*991554f2SKenneth D. Merry 	/*
3178*991554f2SKenneth D. Merry 	 * If LUN is already in list, don't create a new one.
3179*991554f2SKenneth D. Merry 	 */
3180*991554f2SKenneth D. Merry 	found_lun = FALSE;
3181*991554f2SKenneth D. Merry 	SLIST_FOREACH(lun, &target->luns, lun_link) {
3182*991554f2SKenneth D. Merry 		if (lun->lun_id == lunid) {
3183*991554f2SKenneth D. Merry 			found_lun = TRUE;
3184*991554f2SKenneth D. Merry 			break;
3185*991554f2SKenneth D. Merry 		}
3186*991554f2SKenneth D. Merry 	}
3187*991554f2SKenneth D. Merry 	if (!found_lun) {
3188*991554f2SKenneth D. Merry 		lun = malloc(sizeof(struct mprsas_lun), M_MPR,
3189*991554f2SKenneth D. Merry 		    M_NOWAIT | M_ZERO);
3190*991554f2SKenneth D. Merry 		if (lun == NULL) {
3191*991554f2SKenneth D. Merry 			mpr_dprint(sc, MPR_ERROR, "Unable to alloc LUN for "
3192*991554f2SKenneth D. Merry 			    "EEDP support.\n");
3193*991554f2SKenneth D. Merry 			xpt_free_path(local_path);
3194*991554f2SKenneth D. Merry 			xpt_free_ccb(ccb);
3195*991554f2SKenneth D. Merry 			return;
3196*991554f2SKenneth D. Merry 		}
3197*991554f2SKenneth D. Merry 		lun->lun_id = lunid;
3198*991554f2SKenneth D. Merry 		SLIST_INSERT_HEAD(&target->luns, lun, lun_link);
3199*991554f2SKenneth D. Merry 	}
3200*991554f2SKenneth D. Merry 
3201*991554f2SKenneth D. Merry 	xpt_path_string(local_path, path_str, sizeof(path_str));
3202*991554f2SKenneth D. Merry 	mpr_dprint(sc, MPR_INFO, "Sending read cap: path %s handle %d\n",
3203*991554f2SKenneth D. Merry 	    path_str, target->handle);
3204*991554f2SKenneth D. Merry 
3205*991554f2SKenneth D. Merry 	/*
3206*991554f2SKenneth D. Merry 	 * Issue a READ CAPACITY 16 command for the LUN.  The
3207*991554f2SKenneth D. Merry 	 * mprsas_read_cap_done function will load the read cap info into the
3208*991554f2SKenneth D. Merry 	 * LUN struct.
3209*991554f2SKenneth D. Merry 	 */
3210*991554f2SKenneth D. Merry 	rcap_buf = malloc(sizeof(struct scsi_read_capacity_eedp), M_MPR,
3211*991554f2SKenneth D. Merry 	    M_NOWAIT | M_ZERO);
3212*991554f2SKenneth D. Merry 	if (rcap_buf == NULL) {
3213*991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_FAULT, "Unable to alloc read capacity "
3214*991554f2SKenneth D. Merry 		    "buffer for EEDP support.\n");
3215*991554f2SKenneth D. Merry 		xpt_free_path(ccb->ccb_h.path);
3216*991554f2SKenneth D. Merry 		xpt_free_ccb(ccb);
3217*991554f2SKenneth D. Merry 		return;
3218*991554f2SKenneth D. Merry 	}
3219*991554f2SKenneth D. Merry 	xpt_setup_ccb(&ccb->ccb_h, local_path, CAM_PRIORITY_XPT);
3220*991554f2SKenneth D. Merry 	csio = &ccb->csio;
3221*991554f2SKenneth D. Merry 	csio->ccb_h.func_code = XPT_SCSI_IO;
3222*991554f2SKenneth D. Merry 	csio->ccb_h.flags = CAM_DIR_IN;
3223*991554f2SKenneth D. Merry 	csio->ccb_h.retry_count = 4;
3224*991554f2SKenneth D. Merry 	csio->ccb_h.cbfcnp = mprsas_read_cap_done;
3225*991554f2SKenneth D. Merry 	csio->ccb_h.timeout = 60000;
3226*991554f2SKenneth D. Merry 	csio->data_ptr = (uint8_t *)rcap_buf;
3227*991554f2SKenneth D. Merry 	csio->dxfer_len = sizeof(struct scsi_read_capacity_eedp);
3228*991554f2SKenneth D. Merry 	csio->sense_len = MPR_SENSE_LEN;
3229*991554f2SKenneth D. Merry 	csio->cdb_len = sizeof(*scsi_cmd);
3230*991554f2SKenneth D. Merry 	csio->tag_action = MSG_SIMPLE_Q_TAG;
3231*991554f2SKenneth D. Merry 
3232*991554f2SKenneth D. Merry 	scsi_cmd = (struct scsi_read_capacity_16 *)&csio->cdb_io.cdb_bytes;
3233*991554f2SKenneth D. Merry 	bzero(scsi_cmd, sizeof(*scsi_cmd));
3234*991554f2SKenneth D. Merry 	scsi_cmd->opcode = 0x9E;
3235*991554f2SKenneth D. Merry 	scsi_cmd->service_action = SRC16_SERVICE_ACTION;
3236*991554f2SKenneth D. Merry 	((uint8_t *)scsi_cmd)[13] = sizeof(struct scsi_read_capacity_eedp);
3237*991554f2SKenneth D. Merry 
3238*991554f2SKenneth D. Merry 	ccb->ccb_h.ppriv_ptr1 = sassc;
3239*991554f2SKenneth D. Merry 	xpt_action(ccb);
3240*991554f2SKenneth D. Merry }
3241*991554f2SKenneth D. Merry 
3242*991554f2SKenneth D. Merry static void
3243*991554f2SKenneth D. Merry mprsas_read_cap_done(struct cam_periph *periph, union ccb *done_ccb)
3244*991554f2SKenneth D. Merry {
3245*991554f2SKenneth D. Merry 	struct mprsas_softc *sassc;
3246*991554f2SKenneth D. Merry 	struct mprsas_target *target;
3247*991554f2SKenneth D. Merry 	struct mprsas_lun *lun;
3248*991554f2SKenneth D. Merry 	struct scsi_read_capacity_eedp *rcap_buf;
3249*991554f2SKenneth D. Merry 
3250*991554f2SKenneth D. Merry 	if (done_ccb == NULL)
3251*991554f2SKenneth D. Merry 		return;
3252*991554f2SKenneth D. Merry 
3253*991554f2SKenneth D. Merry 	/* Driver need to release devq, it Scsi command is
3254*991554f2SKenneth D. Merry 	 * generated by driver internally.
3255*991554f2SKenneth D. Merry 	 * Currently there is a single place where driver
3256*991554f2SKenneth D. Merry 	 * calls scsi command internally. In future if driver
3257*991554f2SKenneth D. Merry 	 * calls more scsi command internally, it needs to release
3258*991554f2SKenneth D. Merry 	 * devq internally, since those command will not go back to
3259*991554f2SKenneth D. Merry 	 * cam_periph.
3260*991554f2SKenneth D. Merry 	 */
3261*991554f2SKenneth D. Merry 	if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) ) {
3262*991554f2SKenneth D. Merry         	done_ccb->ccb_h.status &= ~CAM_DEV_QFRZN;
3263*991554f2SKenneth D. Merry 		xpt_release_devq(done_ccb->ccb_h.path,
3264*991554f2SKenneth D. Merry 			       	/*count*/ 1, /*run_queue*/TRUE);
3265*991554f2SKenneth D. Merry 	}
3266*991554f2SKenneth D. Merry 
3267*991554f2SKenneth D. Merry 	rcap_buf = (struct scsi_read_capacity_eedp *)done_ccb->csio.data_ptr;
3268*991554f2SKenneth D. Merry 
3269*991554f2SKenneth D. Merry 	/*
3270*991554f2SKenneth D. Merry 	 * Get the LUN ID for the path and look it up in the LUN list for the
3271*991554f2SKenneth D. Merry 	 * target.
3272*991554f2SKenneth D. Merry 	 */
3273*991554f2SKenneth D. Merry 	sassc = (struct mprsas_softc *)done_ccb->ccb_h.ppriv_ptr1;
3274*991554f2SKenneth D. Merry 	KASSERT(done_ccb->ccb_h.target_id < sassc->maxtargets,
3275*991554f2SKenneth D. Merry 	    ("Target %d out of bounds in mprsas_read_cap_done\n",
3276*991554f2SKenneth D. Merry 	    done_ccb->ccb_h.target_id));
3277*991554f2SKenneth D. Merry 	target = &sassc->targets[done_ccb->ccb_h.target_id];
3278*991554f2SKenneth D. Merry 	SLIST_FOREACH(lun, &target->luns, lun_link) {
3279*991554f2SKenneth D. Merry 		if (lun->lun_id != done_ccb->ccb_h.target_lun)
3280*991554f2SKenneth D. Merry 			continue;
3281*991554f2SKenneth D. Merry 
3282*991554f2SKenneth D. Merry 		/*
3283*991554f2SKenneth D. Merry 		 * Got the LUN in the target's LUN list.  Fill it in with EEDP
3284*991554f2SKenneth D. Merry 		 * info.  If the READ CAP 16 command had some SCSI error (common
3285*991554f2SKenneth D. Merry 		 * if command is not supported), mark the lun as not supporting
3286*991554f2SKenneth D. Merry 		 * EEDP and set the block size to 0.
3287*991554f2SKenneth D. Merry 		 */
3288*991554f2SKenneth D. Merry 		if (((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)
3289*991554f2SKenneth D. Merry 		    || (done_ccb->csio.scsi_status != SCSI_STATUS_OK)) {
3290*991554f2SKenneth D. Merry 			lun->eedp_formatted = FALSE;
3291*991554f2SKenneth D. Merry 			lun->eedp_block_size = 0;
3292*991554f2SKenneth D. Merry 			break;
3293*991554f2SKenneth D. Merry 		}
3294*991554f2SKenneth D. Merry 
3295*991554f2SKenneth D. Merry 		if (rcap_buf->protect & 0x01) {
3296*991554f2SKenneth D. Merry 			mpr_dprint(sassc->sc, MPR_INFO, "LUN %d for "
3297*991554f2SKenneth D. Merry 			    "target ID %d is formatted for EEDP "
3298*991554f2SKenneth D. Merry 			    "support.\n", done_ccb->ccb_h.target_lun,
3299*991554f2SKenneth D. Merry 			    done_ccb->ccb_h.target_id);
3300*991554f2SKenneth D. Merry 			lun->eedp_formatted = TRUE;
3301*991554f2SKenneth D. Merry 			lun->eedp_block_size = scsi_4btoul(rcap_buf->length);
3302*991554f2SKenneth D. Merry 		}
3303*991554f2SKenneth D. Merry 		break;
3304*991554f2SKenneth D. Merry 	}
3305*991554f2SKenneth D. Merry 
3306*991554f2SKenneth D. Merry 	// Finished with this CCB and path.
3307*991554f2SKenneth D. Merry 	free(rcap_buf, M_MPR);
3308*991554f2SKenneth D. Merry 	xpt_free_path(done_ccb->ccb_h.path);
3309*991554f2SKenneth D. Merry 	xpt_free_ccb(done_ccb);
3310*991554f2SKenneth D. Merry }
3311*991554f2SKenneth D. Merry #endif /* (__FreeBSD_version < 901503) || \
3312*991554f2SKenneth D. Merry           ((__FreeBSD_version >= 1000000) && (__FreeBSD_version < 1000006)) */
3313*991554f2SKenneth D. Merry 
3314*991554f2SKenneth D. Merry int
3315*991554f2SKenneth D. Merry mprsas_startup(struct mpr_softc *sc)
3316*991554f2SKenneth D. Merry {
3317*991554f2SKenneth D. Merry 	/*
3318*991554f2SKenneth D. Merry 	 * Send the port enable message and set the wait_for_port_enable flag.
3319*991554f2SKenneth D. Merry 	 * This flag helps to keep the simq frozen until all discovery events
3320*991554f2SKenneth D. Merry 	 * are processed.
3321*991554f2SKenneth D. Merry 	 */
3322*991554f2SKenneth D. Merry 	sc->wait_for_port_enable = 1;
3323*991554f2SKenneth D. Merry 	mprsas_send_portenable(sc);
3324*991554f2SKenneth D. Merry 	return (0);
3325*991554f2SKenneth D. Merry }
3326*991554f2SKenneth D. Merry 
3327*991554f2SKenneth D. Merry static int
3328*991554f2SKenneth D. Merry mprsas_send_portenable(struct mpr_softc *sc)
3329*991554f2SKenneth D. Merry {
3330*991554f2SKenneth D. Merry 	MPI2_PORT_ENABLE_REQUEST *request;
3331*991554f2SKenneth D. Merry 	struct mpr_command *cm;
3332*991554f2SKenneth D. Merry 
3333*991554f2SKenneth D. Merry 	MPR_FUNCTRACE(sc);
3334*991554f2SKenneth D. Merry 
3335*991554f2SKenneth D. Merry 	if ((cm = mpr_alloc_command(sc)) == NULL)
3336*991554f2SKenneth D. Merry 		return (EBUSY);
3337*991554f2SKenneth D. Merry 	request = (MPI2_PORT_ENABLE_REQUEST *)cm->cm_req;
3338*991554f2SKenneth D. Merry 	request->Function = MPI2_FUNCTION_PORT_ENABLE;
3339*991554f2SKenneth D. Merry 	request->MsgFlags = 0;
3340*991554f2SKenneth D. Merry 	request->VP_ID = 0;
3341*991554f2SKenneth D. Merry 	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
3342*991554f2SKenneth D. Merry 	cm->cm_complete = mprsas_portenable_complete;
3343*991554f2SKenneth D. Merry 	cm->cm_data = NULL;
3344*991554f2SKenneth D. Merry 	cm->cm_sge = NULL;
3345*991554f2SKenneth D. Merry 
3346*991554f2SKenneth D. Merry 	mpr_map_command(sc, cm);
3347*991554f2SKenneth D. Merry 	mpr_dprint(sc, MPR_XINFO,
3348*991554f2SKenneth D. Merry 	    "mpr_send_portenable finished cm %p req %p complete %p\n",
3349*991554f2SKenneth D. Merry 	    cm, cm->cm_req, cm->cm_complete);
3350*991554f2SKenneth D. Merry 	return (0);
3351*991554f2SKenneth D. Merry }
3352*991554f2SKenneth D. Merry 
3353*991554f2SKenneth D. Merry static void
3354*991554f2SKenneth D. Merry mprsas_portenable_complete(struct mpr_softc *sc, struct mpr_command *cm)
3355*991554f2SKenneth D. Merry {
3356*991554f2SKenneth D. Merry 	MPI2_PORT_ENABLE_REPLY *reply;
3357*991554f2SKenneth D. Merry 	struct mprsas_softc *sassc;
3358*991554f2SKenneth D. Merry 
3359*991554f2SKenneth D. Merry 	MPR_FUNCTRACE(sc);
3360*991554f2SKenneth D. Merry 	sassc = sc->sassc;
3361*991554f2SKenneth D. Merry 
3362*991554f2SKenneth D. Merry 	/*
3363*991554f2SKenneth D. Merry 	 * Currently there should be no way we can hit this case.  It only
3364*991554f2SKenneth D. Merry 	 * happens when we have a failure to allocate chain frames, and
3365*991554f2SKenneth D. Merry 	 * port enable commands don't have S/G lists.
3366*991554f2SKenneth D. Merry 	 */
3367*991554f2SKenneth D. Merry 	if ((cm->cm_flags & MPR_CM_FLAGS_ERROR_MASK) != 0) {
3368*991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_ERROR, "%s: cm_flags = %#x for port enable! "
3369*991554f2SKenneth D. Merry 		    "This should not happen!\n", __func__, cm->cm_flags);
3370*991554f2SKenneth D. Merry 	}
3371*991554f2SKenneth D. Merry 
3372*991554f2SKenneth D. Merry 	reply = (MPI2_PORT_ENABLE_REPLY *)cm->cm_reply;
3373*991554f2SKenneth D. Merry 	if (reply == NULL)
3374*991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_FAULT, "Portenable NULL reply\n");
3375*991554f2SKenneth D. Merry 	else if (le16toh(reply->IOCStatus & MPI2_IOCSTATUS_MASK) !=
3376*991554f2SKenneth D. Merry 	    MPI2_IOCSTATUS_SUCCESS)
3377*991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_FAULT, "Portenable failed\n");
3378*991554f2SKenneth D. Merry 
3379*991554f2SKenneth D. Merry 	mpr_free_command(sc, cm);
3380*991554f2SKenneth D. Merry 	if (sc->mpr_ich.ich_arg != NULL) {
3381*991554f2SKenneth D. Merry 		mpr_dprint(sc, MPR_XINFO, "disestablish config intrhook\n");
3382*991554f2SKenneth D. Merry 		config_intrhook_disestablish(&sc->mpr_ich);
3383*991554f2SKenneth D. Merry 		sc->mpr_ich.ich_arg = NULL;
3384*991554f2SKenneth D. Merry 	}
3385*991554f2SKenneth D. Merry 
3386*991554f2SKenneth D. Merry 	/*
3387*991554f2SKenneth D. Merry 	 * Done waiting for port enable to complete.  Decrement the refcount.
3388*991554f2SKenneth D. Merry 	 * If refcount is 0, discovery is complete and a rescan of the bus can
3389*991554f2SKenneth D. Merry 	 * take place.
3390*991554f2SKenneth D. Merry 	 */
3391*991554f2SKenneth D. Merry 	sc->wait_for_port_enable = 0;
3392*991554f2SKenneth D. Merry 	sc->port_enable_complete = 1;
3393*991554f2SKenneth D. Merry 	wakeup(&sc->port_enable_complete);
3394*991554f2SKenneth D. Merry 	mprsas_startup_decrement(sassc);
3395*991554f2SKenneth D. Merry }
3396*991554f2SKenneth D. Merry 
3397*991554f2SKenneth D. Merry int
3398*991554f2SKenneth D. Merry mprsas_check_id(struct mprsas_softc *sassc, int id)
3399*991554f2SKenneth D. Merry {
3400*991554f2SKenneth D. Merry 	struct mpr_softc *sc = sassc->sc;
3401*991554f2SKenneth D. Merry 	char *ids;
3402*991554f2SKenneth D. Merry 	char *name;
3403*991554f2SKenneth D. Merry 
3404*991554f2SKenneth D. Merry 	ids = &sc->exclude_ids[0];
3405*991554f2SKenneth D. Merry 	while((name = strsep(&ids, ",")) != NULL) {
3406*991554f2SKenneth D. Merry 		if (name[0] == '\0')
3407*991554f2SKenneth D. Merry 			continue;
3408*991554f2SKenneth D. Merry 		if (strtol(name, NULL, 0) == (long)id)
3409*991554f2SKenneth D. Merry 			return (1);
3410*991554f2SKenneth D. Merry 	}
3411*991554f2SKenneth D. Merry 
3412*991554f2SKenneth D. Merry 	return (0);
3413*991554f2SKenneth D. Merry }
3414