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