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