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