1d3c7b9a0SKenneth D. Merry /*-
24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
3718cf2ccSPedro F. Giffuni *
4d3c7b9a0SKenneth D. Merry * Copyright (c) 2009 Yahoo! Inc.
5ef065d89SStephen McConnell * Copyright (c) 2011-2015 LSI Corp.
6ef065d89SStephen McConnell * Copyright (c) 2013-2015 Avago Technologies
7d043c564SKenneth D. Merry * All rights reserved.
8d043c564SKenneth D. Merry *
9d043c564SKenneth D. Merry * Redistribution and use in source and binary forms, with or without
10d043c564SKenneth D. Merry * modification, are permitted provided that the following conditions
11d043c564SKenneth D. Merry * are met:
12d043c564SKenneth D. Merry * 1. Redistributions of source code must retain the above copyright
13d043c564SKenneth D. Merry * notice, this list of conditions and the following disclaimer.
14d043c564SKenneth D. Merry * 2. Redistributions in binary form must reproduce the above copyright
15d043c564SKenneth D. Merry * notice, this list of conditions and the following disclaimer in the
16d043c564SKenneth D. Merry * documentation and/or other materials provided with the distribution.
17d043c564SKenneth D. Merry *
18d043c564SKenneth D. Merry * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19d043c564SKenneth D. Merry * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20d043c564SKenneth D. Merry * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21d043c564SKenneth D. Merry * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22d043c564SKenneth D. Merry * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23d043c564SKenneth D. Merry * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24d043c564SKenneth D. Merry * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25d043c564SKenneth D. Merry * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26d043c564SKenneth D. Merry * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27d043c564SKenneth D. Merry * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28d043c564SKenneth D. Merry * SUCH DAMAGE.
29d043c564SKenneth D. Merry *
30ef065d89SStephen McConnell * Avago Technologies (LSI) MPT-Fusion Host Adapter FreeBSD
31d043c564SKenneth D. Merry */
32d3c7b9a0SKenneth D. Merry
33d3c7b9a0SKenneth D. Merry #include <sys/cdefs.h>
34ef065d89SStephen McConnell /* Communications core for Avago Technologies (LSI) MPT2 */
35d3c7b9a0SKenneth D. Merry
36d043c564SKenneth D. Merry /* TODO Move headers to mpsvar */
37d3c7b9a0SKenneth D. Merry #include <sys/types.h>
38d3c7b9a0SKenneth D. Merry #include <sys/param.h>
39d3c7b9a0SKenneth D. Merry #include <sys/systm.h>
40d3c7b9a0SKenneth D. Merry #include <sys/kernel.h>
41d3c7b9a0SKenneth D. Merry #include <sys/selinfo.h>
42d3c7b9a0SKenneth D. Merry #include <sys/module.h>
43d3c7b9a0SKenneth D. Merry #include <sys/bus.h>
44d3c7b9a0SKenneth D. Merry #include <sys/conf.h>
45d3c7b9a0SKenneth D. Merry #include <sys/bio.h>
46d3c7b9a0SKenneth D. Merry #include <sys/malloc.h>
47d3c7b9a0SKenneth D. Merry #include <sys/uio.h>
48d3c7b9a0SKenneth D. Merry #include <sys/sysctl.h>
4906e79492SKenneth D. Merry #include <sys/endian.h>
50d043c564SKenneth D. Merry #include <sys/queue.h>
51d043c564SKenneth D. Merry #include <sys/kthread.h>
52d043c564SKenneth D. Merry #include <sys/taskqueue.h>
53d043c564SKenneth D. Merry #include <sys/sbuf.h>
54d3c7b9a0SKenneth D. Merry
55d3c7b9a0SKenneth D. Merry #include <machine/bus.h>
56d3c7b9a0SKenneth D. Merry #include <machine/resource.h>
57d3c7b9a0SKenneth D. Merry #include <sys/rman.h>
58d3c7b9a0SKenneth D. Merry
59d043c564SKenneth D. Merry #include <machine/stdarg.h>
60d043c564SKenneth D. Merry
61d3c7b9a0SKenneth D. Merry #include <cam/cam.h>
62d3c7b9a0SKenneth D. Merry #include <cam/cam_ccb.h>
63d043c564SKenneth D. Merry #include <cam/cam_xpt.h>
64d3c7b9a0SKenneth D. Merry #include <cam/cam_debug.h>
65d3c7b9a0SKenneth D. Merry #include <cam/cam_sim.h>
66d3c7b9a0SKenneth D. Merry #include <cam/cam_xpt_sim.h>
67d3c7b9a0SKenneth D. Merry #include <cam/cam_xpt_periph.h>
68d3c7b9a0SKenneth D. Merry #include <cam/cam_periph.h>
69d3c7b9a0SKenneth D. Merry #include <cam/scsi/scsi_all.h>
70d3c7b9a0SKenneth D. Merry #include <cam/scsi/scsi_message.h>
7106e79492SKenneth D. Merry #include <cam/scsi/smp_all.h>
72d3c7b9a0SKenneth D. Merry
73d3c7b9a0SKenneth D. Merry #include <dev/mps/mpi/mpi2_type.h>
74d3c7b9a0SKenneth D. Merry #include <dev/mps/mpi/mpi2.h>
75d3c7b9a0SKenneth D. Merry #include <dev/mps/mpi/mpi2_ioc.h>
76d3c7b9a0SKenneth D. Merry #include <dev/mps/mpi/mpi2_sas.h>
77d3c7b9a0SKenneth D. Merry #include <dev/mps/mpi/mpi2_cnfg.h>
78d3c7b9a0SKenneth D. Merry #include <dev/mps/mpi/mpi2_init.h>
79d043c564SKenneth D. Merry #include <dev/mps/mpi/mpi2_tool.h>
80d043c564SKenneth D. Merry #include <dev/mps/mps_ioctl.h>
81d3c7b9a0SKenneth D. Merry #include <dev/mps/mpsvar.h>
82d3c7b9a0SKenneth D. Merry #include <dev/mps/mps_table.h>
83d043c564SKenneth D. Merry #include <dev/mps/mps_sas.h>
84d3c7b9a0SKenneth D. Merry
85d043c564SKenneth D. Merry /*
86d043c564SKenneth D. Merry * static array to check SCSI OpCode for EEDP protection bits
87d043c564SKenneth D. Merry */
88d043c564SKenneth D. Merry #define PRO_R MPI2_SCSIIO_EEDPFLAGS_CHECK_REMOVE_OP
89d043c564SKenneth D. Merry #define PRO_W MPI2_SCSIIO_EEDPFLAGS_INSERT_OP
90d043c564SKenneth D. Merry #define PRO_V MPI2_SCSIIO_EEDPFLAGS_INSERT_OP
91d043c564SKenneth D. Merry static uint8_t op_code_prot[256] = {
92d043c564SKenneth D. Merry 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
93d043c564SKenneth D. Merry 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
94d043c564SKenneth D. Merry 0, 0, 0, 0, 0, 0, 0, 0, PRO_R, 0, PRO_W, 0, 0, 0, PRO_W, PRO_V,
95d043c564SKenneth D. Merry 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
96d043c564SKenneth D. Merry 0, PRO_W, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
97d043c564SKenneth D. Merry 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
98d043c564SKenneth D. Merry 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
99d043c564SKenneth D. Merry 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
100d043c564SKenneth D. Merry 0, 0, 0, 0, 0, 0, 0, 0, PRO_R, 0, PRO_W, 0, 0, 0, PRO_W, PRO_V,
101d043c564SKenneth D. Merry 0, 0, 0, PRO_W, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
102d043c564SKenneth D. Merry 0, 0, 0, 0, 0, 0, 0, 0, PRO_R, 0, PRO_W, 0, 0, 0, PRO_W, PRO_V,
103d043c564SKenneth D. Merry 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
104d043c564SKenneth D. Merry 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
105d043c564SKenneth D. Merry 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
106d043c564SKenneth D. Merry 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
107d043c564SKenneth D. Merry 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
108d043c564SKenneth D. Merry };
109d3c7b9a0SKenneth D. Merry
110d043c564SKenneth D. Merry MALLOC_DEFINE(M_MPSSAS, "MPSSAS", "MPS SAS memory");
111d043c564SKenneth D. Merry
112d3c7b9a0SKenneth D. Merry static void mpssas_remove_device(struct mps_softc *, struct mps_command *);
113d3c7b9a0SKenneth D. Merry static void mpssas_remove_complete(struct mps_softc *, struct mps_command *);
114d3c7b9a0SKenneth D. Merry static void mpssas_action(struct cam_sim *sim, union ccb *ccb);
115d3c7b9a0SKenneth D. Merry static void mpssas_poll(struct cam_sim *sim);
116ef065d89SStephen McConnell static int mpssas_send_abort(struct mps_softc *sc, struct mps_command *tm,
117ef065d89SStephen McConnell struct mps_command *cm);
118d3c7b9a0SKenneth D. Merry static void mpssas_scsiio_timeout(void *data);
119d3c7b9a0SKenneth D. Merry static void mpssas_abort_complete(struct mps_softc *sc, struct mps_command *cm);
120d043c564SKenneth D. Merry static void mpssas_direct_drive_io(struct mpssas_softc *sassc,
121d043c564SKenneth D. Merry struct mps_command *cm, union ccb *ccb);
122d3c7b9a0SKenneth D. Merry static void mpssas_action_scsiio(struct mpssas_softc *, union ccb *);
123d3c7b9a0SKenneth D. Merry static void mpssas_scsiio_complete(struct mps_softc *, struct mps_command *);
124d043c564SKenneth D. Merry static void mpssas_action_resetdev(struct mpssas_softc *, union ccb *);
12506e79492SKenneth D. Merry static void mpssas_smpio_complete(struct mps_softc *sc, struct mps_command *cm);
12606e79492SKenneth D. Merry static void mpssas_send_smpcmd(struct mpssas_softc *sassc, union ccb *ccb,
12706e79492SKenneth D. Merry uint64_t sasaddr);
12806e79492SKenneth D. Merry static void mpssas_action_smpio(struct mpssas_softc *sassc, union ccb *ccb);
129d3c7b9a0SKenneth D. Merry static void mpssas_resetdev_complete(struct mps_softc *, struct mps_command *);
130d043c564SKenneth D. Merry static void mpssas_async(void *callback_arg, uint32_t code,
131d043c564SKenneth D. Merry struct cam_path *path, void *arg);
132d043c564SKenneth D. Merry static int mpssas_send_portenable(struct mps_softc *sc);
133d043c564SKenneth D. Merry static void mpssas_portenable_complete(struct mps_softc *sc,
134d043c564SKenneth D. Merry struct mps_command *cm);
135d3c7b9a0SKenneth D. Merry
136653c521fSKenneth D. Merry struct mpssas_target *
mpssas_find_target_by_handle(struct mpssas_softc * sassc,int start,uint16_t handle)137d043c564SKenneth D. Merry mpssas_find_target_by_handle(struct mpssas_softc *sassc, int start, uint16_t handle)
138d3c7b9a0SKenneth D. Merry {
139d3c7b9a0SKenneth D. Merry struct mpssas_target *target;
140d3c7b9a0SKenneth D. Merry int i;
141d3c7b9a0SKenneth D. Merry
14208235773SScott Long for (i = start; i < sassc->maxtargets; i++) {
143d3c7b9a0SKenneth D. Merry target = &sassc->targets[i];
144d3c7b9a0SKenneth D. Merry if (target->handle == handle)
145d3c7b9a0SKenneth D. Merry return (target);
146d3c7b9a0SKenneth D. Merry }
147d3c7b9a0SKenneth D. Merry
148d3c7b9a0SKenneth D. Merry return (NULL);
149d3c7b9a0SKenneth D. Merry }
150d3c7b9a0SKenneth D. Merry
151d043c564SKenneth D. Merry /* we need to freeze the simq during attach and diag reset, to avoid failing
152d043c564SKenneth D. Merry * commands before device handles have been found by discovery. Since
153d043c564SKenneth D. Merry * discovery involves reading config pages and possibly sending commands,
154d043c564SKenneth D. Merry * discovery actions may continue even after we receive the end of discovery
155d043c564SKenneth D. Merry * event, so refcount discovery actions instead of assuming we can unfreeze
156d043c564SKenneth D. Merry * the simq when we get the event.
157d3c7b9a0SKenneth D. Merry */
158d043c564SKenneth D. Merry void
mpssas_startup_increment(struct mpssas_softc * sassc)159d043c564SKenneth D. Merry mpssas_startup_increment(struct mpssas_softc *sassc)
160d3c7b9a0SKenneth D. Merry {
1611610f95cSScott Long MPS_FUNCTRACE(sassc->sc);
1621610f95cSScott Long
163d043c564SKenneth D. Merry if ((sassc->flags & MPSSAS_IN_STARTUP) != 0) {
164d043c564SKenneth D. Merry if (sassc->startup_refcount++ == 0) {
165d043c564SKenneth D. Merry /* just starting, freeze the simq */
1661610f95cSScott Long mps_dprint(sassc->sc, MPS_INIT,
167d043c564SKenneth D. Merry "%s freezing simq\n", __func__);
16837b8d8c4SAlexander Motin xpt_hold_boot();
169d043c564SKenneth D. Merry xpt_freeze_simq(sassc->sim, 1);
170d043c564SKenneth D. Merry }
1711610f95cSScott Long mps_dprint(sassc->sc, MPS_INIT, "%s refcount %u\n", __func__,
172d043c564SKenneth D. Merry sassc->startup_refcount);
173d043c564SKenneth D. Merry }
174d043c564SKenneth D. Merry }
175d3c7b9a0SKenneth D. Merry
176d043c564SKenneth D. Merry void
mpssas_release_simq_reinit(struct mpssas_softc * sassc)1777571e7f6SSteven Hartland mpssas_release_simq_reinit(struct mpssas_softc *sassc)
1787571e7f6SSteven Hartland {
1797571e7f6SSteven Hartland if (sassc->flags & MPSSAS_QUEUE_FROZEN) {
1807571e7f6SSteven Hartland sassc->flags &= ~MPSSAS_QUEUE_FROZEN;
1817571e7f6SSteven Hartland xpt_release_simq(sassc->sim, 1);
1827571e7f6SSteven Hartland mps_dprint(sassc->sc, MPS_INFO, "Unfreezing SIM queue\n");
1837571e7f6SSteven Hartland }
1847571e7f6SSteven Hartland }
1857571e7f6SSteven Hartland
1867571e7f6SSteven Hartland void
mpssas_startup_decrement(struct mpssas_softc * sassc)187d043c564SKenneth D. Merry mpssas_startup_decrement(struct mpssas_softc *sassc)
188d043c564SKenneth D. Merry {
1891610f95cSScott Long MPS_FUNCTRACE(sassc->sc);
1901610f95cSScott Long
191d043c564SKenneth D. Merry if ((sassc->flags & MPSSAS_IN_STARTUP) != 0) {
192d043c564SKenneth D. Merry if (--sassc->startup_refcount == 0) {
193d043c564SKenneth D. Merry /* finished all discovery-related actions, release
194d043c564SKenneth D. Merry * the simq and rescan for the latest topology.
195d043c564SKenneth D. Merry */
1961610f95cSScott Long mps_dprint(sassc->sc, MPS_INIT,
197d043c564SKenneth D. Merry "%s releasing simq\n", __func__);
198d043c564SKenneth D. Merry sassc->flags &= ~MPSSAS_IN_STARTUP;
19937b8d8c4SAlexander Motin xpt_release_simq(sassc->sim, 1);
200b01773b0SKenneth D. Merry xpt_release_boot();
201d043c564SKenneth D. Merry }
2021610f95cSScott Long mps_dprint(sassc->sc, MPS_INIT, "%s refcount %u\n", __func__,
203d043c564SKenneth D. Merry sassc->startup_refcount);
204d043c564SKenneth D. Merry }
205d043c564SKenneth D. Merry }
206d3c7b9a0SKenneth D. Merry
207b7f1ee79SScott Long /*
208b7f1ee79SScott Long * The firmware requires us to stop sending commands when we're doing task
209b7f1ee79SScott Long * management.
210b7f1ee79SScott Long * XXX The logic for serializing the device has been made lazy and moved to
211b7f1ee79SScott Long * mpssas_prepare_for_tm().
212d043c564SKenneth D. Merry */
213d043c564SKenneth D. Merry struct mps_command *
mpssas_alloc_tm(struct mps_softc * sc)214d043c564SKenneth D. Merry mpssas_alloc_tm(struct mps_softc *sc)
215d043c564SKenneth D. Merry {
21646b9415fSScott Long MPI2_SCSI_TASK_MANAGE_REQUEST *req;
217d043c564SKenneth D. Merry struct mps_command *tm;
218d043c564SKenneth D. Merry
219d043c564SKenneth D. Merry tm = mps_alloc_high_priority_command(sc);
22046b9415fSScott Long if (tm == NULL)
22146b9415fSScott Long return (NULL);
22246b9415fSScott Long
22346b9415fSScott Long req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req;
22446b9415fSScott Long req->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
225d043c564SKenneth D. Merry return tm;
226d043c564SKenneth D. Merry }
227d043c564SKenneth D. Merry
228d043c564SKenneth D. Merry void
mpssas_free_tm(struct mps_softc * sc,struct mps_command * tm)229d043c564SKenneth D. Merry mpssas_free_tm(struct mps_softc *sc, struct mps_command *tm)
230d043c564SKenneth D. Merry {
231d043c564SKenneth D. Merry if (tm == NULL)
232d043c564SKenneth D. Merry return;
233d043c564SKenneth D. Merry
234ef065d89SStephen McConnell /*
235ef065d89SStephen McConnell * For TM's the devq is frozen for the device. Unfreeze it here and
236ef065d89SStephen McConnell * free the resources used for freezing the devq. Must clear the
237ef065d89SStephen McConnell * INRESET flag as well or scsi I/O will not work.
238d043c564SKenneth D. Merry */
239266f97b5SCy Schubert if (tm->cm_ccb) {
240db0ac6deSCy Schubert mps_dprint(sc, MPS_XINFO | MPS_RECOVERY,
241db0ac6deSCy Schubert "Unfreezing devq for target ID %d\n",
242db0ac6deSCy Schubert tm->cm_targ->tid);
243db0ac6deSCy Schubert tm->cm_targ->flags &= ~MPSSAS_TARGET_INRESET;
244ef065d89SStephen McConnell xpt_release_devq(tm->cm_ccb->ccb_h.path, 1, TRUE);
245ef065d89SStephen McConnell xpt_free_path(tm->cm_ccb->ccb_h.path);
246ef065d89SStephen McConnell xpt_free_ccb(tm->cm_ccb);
247ef065d89SStephen McConnell }
248d043c564SKenneth D. Merry
249d043c564SKenneth D. Merry mps_free_high_priority_command(sc, tm);
250d043c564SKenneth D. Merry }
251d043c564SKenneth D. Merry
252d043c564SKenneth D. Merry void
mpssas_rescan_target(struct mps_softc * sc,struct mpssas_target * targ)253d043c564SKenneth D. Merry mpssas_rescan_target(struct mps_softc *sc, struct mpssas_target *targ)
254d043c564SKenneth D. Merry {
255d043c564SKenneth D. Merry struct mpssas_softc *sassc = sc->sassc;
256d043c564SKenneth D. Merry path_id_t pathid;
257d043c564SKenneth D. Merry target_id_t targetid;
258d043c564SKenneth D. Merry union ccb *ccb;
259d043c564SKenneth D. Merry
2601610f95cSScott Long MPS_FUNCTRACE(sc);
261d043c564SKenneth D. Merry pathid = cam_sim_path(sassc->sim);
262d043c564SKenneth D. Merry if (targ == NULL)
263d043c564SKenneth D. Merry targetid = CAM_TARGET_WILDCARD;
264d043c564SKenneth D. Merry else
265d043c564SKenneth D. Merry targetid = targ - sassc->targets;
266d043c564SKenneth D. Merry
267d043c564SKenneth D. Merry /*
268d043c564SKenneth D. Merry * Allocate a CCB and schedule a rescan.
269d043c564SKenneth D. Merry */
270d043c564SKenneth D. Merry ccb = xpt_alloc_ccb_nowait();
271d043c564SKenneth D. Merry if (ccb == NULL) {
2721610f95cSScott Long mps_dprint(sc, MPS_ERROR, "unable to alloc CCB for rescan\n");
273d3c7b9a0SKenneth D. Merry return;
274d3c7b9a0SKenneth D. Merry }
275d3c7b9a0SKenneth D. Merry
276e5dfa058SAlexander Motin if (xpt_create_path(&ccb->ccb_h.path, NULL, pathid,
277d043c564SKenneth D. Merry targetid, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
2781610f95cSScott Long mps_dprint(sc, MPS_ERROR, "unable to create path for rescan\n");
279d043c564SKenneth D. Merry xpt_free_ccb(ccb);
280d3c7b9a0SKenneth D. Merry return;
281d3c7b9a0SKenneth D. Merry }
282d043c564SKenneth D. Merry
28382e4855cSKenneth D. Merry if (targetid == CAM_TARGET_WILDCARD)
284d043c564SKenneth D. Merry ccb->ccb_h.func_code = XPT_SCAN_BUS;
28582e4855cSKenneth D. Merry else
28682e4855cSKenneth D. Merry ccb->ccb_h.func_code = XPT_SCAN_TGT;
28782e4855cSKenneth D. Merry
288d043c564SKenneth D. Merry mps_dprint(sc, MPS_TRACE, "%s targetid %u\n", __func__, targetid);
289b01773b0SKenneth D. Merry xpt_rescan(ccb);
290d3c7b9a0SKenneth D. Merry }
291d3c7b9a0SKenneth D. Merry
292d3c7b9a0SKenneth D. Merry static void
mpssas_log_command(struct mps_command * cm,u_int level,const char * fmt,...)2931610f95cSScott Long mpssas_log_command(struct mps_command *cm, u_int level, const char *fmt, ...)
294d3c7b9a0SKenneth D. Merry {
295d043c564SKenneth D. Merry struct sbuf sb;
296d043c564SKenneth D. Merry va_list ap;
297a2386b6fSAlexander Motin char str[224];
298d3c7b9a0SKenneth D. Merry
299d043c564SKenneth D. Merry if (cm == NULL)
300d3c7b9a0SKenneth D. Merry return;
301d043c564SKenneth D. Merry
30232373512SScott Long /* No need to be in here if debugging isn't enabled */
303fe97b88cSAlexander Motin if ((cm->cm_sc->mps_debug & level) == 0)
30432373512SScott Long return;
30532373512SScott Long
306d043c564SKenneth D. Merry sbuf_new(&sb, str, sizeof(str), 0);
307d043c564SKenneth D. Merry
308d043c564SKenneth D. Merry va_start(ap, fmt);
309d043c564SKenneth D. Merry
310d043c564SKenneth D. Merry if (cm->cm_ccb != NULL) {
311*8c4ee0b2SAlexander Motin xpt_path_sbuf(cm->cm_ccb->csio.ccb_h.path, &sb);
312d043c564SKenneth D. Merry if (cm->cm_ccb->ccb_h.func_code == XPT_SCSI_IO) {
313d043c564SKenneth D. Merry scsi_command_string(&cm->cm_ccb->csio, &sb);
314d043c564SKenneth D. Merry sbuf_printf(&sb, "length %d ",
315d043c564SKenneth D. Merry cm->cm_ccb->csio.dxfer_len);
316d3c7b9a0SKenneth D. Merry }
317d3c7b9a0SKenneth D. Merry }
318d043c564SKenneth D. Merry else {
319d043c564SKenneth D. Merry sbuf_printf(&sb, "(noperiph:%s%d:%u:%u:%u): ",
320d043c564SKenneth D. Merry cam_sim_name(cm->cm_sc->sassc->sim),
321d043c564SKenneth D. Merry cam_sim_unit(cm->cm_sc->sassc->sim),
322d043c564SKenneth D. Merry cam_sim_bus(cm->cm_sc->sassc->sim),
323d043c564SKenneth D. Merry cm->cm_targ ? cm->cm_targ->tid : 0xFFFFFFFF,
324d043c564SKenneth D. Merry cm->cm_lun);
325d043c564SKenneth D. Merry }
326d043c564SKenneth D. Merry
327d043c564SKenneth D. Merry sbuf_printf(&sb, "SMID %u ", cm->cm_desc.Default.SMID);
328d043c564SKenneth D. Merry sbuf_vprintf(&sb, fmt, ap);
329d043c564SKenneth D. Merry sbuf_finish(&sb);
330c11c484fSScott Long mps_print_field(cm->cm_sc, "%s", sbuf_data(&sb));
331d043c564SKenneth D. Merry
332d043c564SKenneth D. Merry va_end(ap);
333d043c564SKenneth D. Merry }
334d043c564SKenneth D. Merry
335653c521fSKenneth D. Merry static void
mpssas_remove_volume(struct mps_softc * sc,struct mps_command * tm)336653c521fSKenneth D. Merry mpssas_remove_volume(struct mps_softc *sc, struct mps_command *tm)
337653c521fSKenneth D. Merry {
338653c521fSKenneth D. Merry MPI2_SCSI_TASK_MANAGE_REPLY *reply;
339653c521fSKenneth D. Merry struct mpssas_target *targ;
340653c521fSKenneth D. Merry uint16_t handle;
341653c521fSKenneth D. Merry
3421610f95cSScott Long MPS_FUNCTRACE(sc);
343653c521fSKenneth D. Merry
344653c521fSKenneth D. Merry reply = (MPI2_SCSI_TASK_MANAGE_REPLY *)tm->cm_reply;
345653c521fSKenneth D. Merry handle = (uint16_t)(uintptr_t)tm->cm_complete_data;
346653c521fSKenneth D. Merry targ = tm->cm_targ;
347653c521fSKenneth D. Merry
348653c521fSKenneth D. Merry if (reply == NULL) {
349653c521fSKenneth D. Merry /* XXX retry the remove after the diag reset completes? */
3501610f95cSScott Long mps_dprint(sc, MPS_FAULT,
351ef065d89SStephen McConnell "%s NULL reply resetting device 0x%04x\n", __func__,
352ef065d89SStephen McConnell handle);
353653c521fSKenneth D. Merry mpssas_free_tm(sc, tm);
354d3c7b9a0SKenneth D. Merry return;
355d3c7b9a0SKenneth D. Merry }
356d3c7b9a0SKenneth D. Merry
357f4e69c98SStephen McConnell if ((le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK) !=
358f4e69c98SStephen McConnell MPI2_IOCSTATUS_SUCCESS) {
359f4e69c98SStephen McConnell mps_dprint(sc, MPS_ERROR,
3601610f95cSScott Long "IOCStatus = 0x%x while resetting device 0x%x\n",
361f4e69c98SStephen McConnell le16toh(reply->IOCStatus), handle);
362653c521fSKenneth D. Merry }
363653c521fSKenneth D. Merry
3641610f95cSScott Long mps_dprint(sc, MPS_XINFO,
3651610f95cSScott Long "Reset aborted %u commands\n", reply->TerminationCount);
366653c521fSKenneth D. Merry mps_free_reply(sc, tm->cm_reply_data);
36796240c89SEitan Adler tm->cm_reply = NULL; /* Ensures the reply won't get re-freed */
368653c521fSKenneth D. Merry
3691610f95cSScott Long mps_dprint(sc, MPS_XINFO,
3701610f95cSScott Long "clearing target %u handle 0x%04x\n", targ->tid, handle);
371653c521fSKenneth D. Merry
372653c521fSKenneth D. Merry /*
373653c521fSKenneth D. Merry * Don't clear target if remove fails because things will get confusing.
374653c521fSKenneth D. Merry * Leave the devname and sasaddr intact so that we know to avoid reusing
375653c521fSKenneth D. Merry * this target id if possible, and so we can assign the same target id
376653c521fSKenneth D. Merry * to this device if it comes back in the future.
377653c521fSKenneth D. Merry */
378f4e69c98SStephen McConnell if ((le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK) ==
379f4e69c98SStephen McConnell MPI2_IOCSTATUS_SUCCESS) {
380653c521fSKenneth D. Merry targ = tm->cm_targ;
381653c521fSKenneth D. Merry targ->handle = 0x0;
382653c521fSKenneth D. Merry targ->encl_handle = 0x0;
383653c521fSKenneth D. Merry targ->encl_slot = 0x0;
384653c521fSKenneth D. Merry targ->exp_dev_handle = 0x0;
385653c521fSKenneth D. Merry targ->phy_num = 0x0;
386653c521fSKenneth D. Merry targ->linkrate = 0x0;
387653c521fSKenneth D. Merry targ->devinfo = 0x0;
388653c521fSKenneth D. Merry targ->flags = 0x0;
389653c521fSKenneth D. Merry }
390653c521fSKenneth D. Merry
391653c521fSKenneth D. Merry mpssas_free_tm(sc, tm);
392653c521fSKenneth D. Merry }
393653c521fSKenneth D. Merry
394653c521fSKenneth D. Merry /*
395653c521fSKenneth D. Merry * No Need to call "MPI2_SAS_OP_REMOVE_DEVICE" For Volume removal.
396653c521fSKenneth D. Merry * Otherwise Volume Delete is same as Bare Drive Removal.
397653c521fSKenneth D. Merry */
398653c521fSKenneth D. Merry void
mpssas_prepare_volume_remove(struct mpssas_softc * sassc,uint16_t handle)399653c521fSKenneth D. Merry mpssas_prepare_volume_remove(struct mpssas_softc *sassc, uint16_t handle)
400653c521fSKenneth D. Merry {
401653c521fSKenneth D. Merry MPI2_SCSI_TASK_MANAGE_REQUEST *req;
402653c521fSKenneth D. Merry struct mps_softc *sc;
40346b9415fSScott Long struct mps_command *tm;
404653c521fSKenneth D. Merry struct mpssas_target *targ = NULL;
405653c521fSKenneth D. Merry
4061610f95cSScott Long MPS_FUNCTRACE(sassc->sc);
407653c521fSKenneth D. Merry sc = sassc->sc;
408653c521fSKenneth D. Merry
409653c521fSKenneth D. Merry #ifdef WD_SUPPORT
410653c521fSKenneth D. Merry /*
411653c521fSKenneth D. Merry * If this is a WD controller, determine if the disk should be exposed
412653c521fSKenneth D. Merry * to the OS or not. If disk should be exposed, return from this
413653c521fSKenneth D. Merry * function without doing anything.
414653c521fSKenneth D. Merry */
415653c521fSKenneth D. Merry if (sc->WD_available && (sc->WD_hide_expose ==
416653c521fSKenneth D. Merry MPS_WD_EXPOSE_ALWAYS)) {
417653c521fSKenneth D. Merry return;
418653c521fSKenneth D. Merry }
419653c521fSKenneth D. Merry #endif //WD_SUPPORT
420653c521fSKenneth D. Merry
421653c521fSKenneth D. Merry targ = mpssas_find_target_by_handle(sassc, 0, handle);
422653c521fSKenneth D. Merry if (targ == NULL) {
423653c521fSKenneth D. Merry /* FIXME: what is the action? */
424653c521fSKenneth D. Merry /* We don't know about this device? */
4251610f95cSScott Long mps_dprint(sc, MPS_ERROR,
4261610f95cSScott Long "%s %d : invalid handle 0x%x \n", __func__,__LINE__, handle);
427653c521fSKenneth D. Merry return;
428653c521fSKenneth D. Merry }
429653c521fSKenneth D. Merry
430653c521fSKenneth D. Merry targ->flags |= MPSSAS_TARGET_INREMOVAL;
431653c521fSKenneth D. Merry
43246b9415fSScott Long tm = mpssas_alloc_tm(sc);
43346b9415fSScott Long if (tm == NULL) {
4341610f95cSScott Long mps_dprint(sc, MPS_ERROR,
4351610f95cSScott Long "%s: command alloc failure\n", __func__);
436653c521fSKenneth D. Merry return;
437653c521fSKenneth D. Merry }
438653c521fSKenneth D. Merry
439653c521fSKenneth D. Merry mpssas_rescan_target(sc, targ);
440653c521fSKenneth D. Merry
44146b9415fSScott Long req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req;
442653c521fSKenneth D. Merry req->DevHandle = targ->handle;
443653c521fSKenneth D. Merry req->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
444653c521fSKenneth D. Merry
445653c521fSKenneth D. Merry /* SAS Hard Link Reset / SATA Link Reset */
446653c521fSKenneth D. Merry req->MsgFlags = MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET;
447653c521fSKenneth D. Merry
44846b9415fSScott Long tm->cm_targ = targ;
44946b9415fSScott Long tm->cm_data = NULL;
45046b9415fSScott Long tm->cm_complete = mpssas_remove_volume;
45146b9415fSScott Long tm->cm_complete_data = (void *)(uintptr_t)handle;
452ef065d89SStephen McConnell
453ef065d89SStephen McConnell mps_dprint(sc, MPS_INFO, "%s: Sending reset for target ID %d\n",
454ef065d89SStephen McConnell __func__, targ->tid);
45546b9415fSScott Long mpssas_prepare_for_tm(sc, tm, targ, CAM_LUN_WILDCARD);
456ef065d89SStephen McConnell
45746b9415fSScott Long mps_map_command(sc, tm);
458d3c7b9a0SKenneth D. Merry }
459d3c7b9a0SKenneth D. Merry
460d3c7b9a0SKenneth D. Merry /*
461d043c564SKenneth D. Merry * The MPT2 firmware performs debounce on the link to avoid transient link
462d043c564SKenneth D. Merry * errors and false removals. When it does decide that link has been lost
463d043c564SKenneth D. Merry * and a device need to go away, it expects that the host will perform a
464d043c564SKenneth D. Merry * target reset and then an op remove. The reset has the side-effect of
465d043c564SKenneth D. Merry * aborting any outstanding requests for the device, which is required for
466d043c564SKenneth D. Merry * the op-remove to succeed. It's not clear if the host should check for
467d043c564SKenneth D. Merry * the device coming back alive after the reset.
468d3c7b9a0SKenneth D. Merry */
469d043c564SKenneth D. Merry void
mpssas_prepare_remove(struct mpssas_softc * sassc,uint16_t handle)470d043c564SKenneth D. Merry mpssas_prepare_remove(struct mpssas_softc *sassc, uint16_t handle)
471d3c7b9a0SKenneth D. Merry {
472d3c7b9a0SKenneth D. Merry MPI2_SCSI_TASK_MANAGE_REQUEST *req;
473d3c7b9a0SKenneth D. Merry struct mps_softc *sc;
474d3c7b9a0SKenneth D. Merry struct mps_command *cm;
475d3c7b9a0SKenneth D. Merry struct mpssas_target *targ = NULL;
476d3c7b9a0SKenneth D. Merry
4771610f95cSScott Long MPS_FUNCTRACE(sassc->sc);
478d3c7b9a0SKenneth D. Merry
479d3c7b9a0SKenneth D. Merry sc = sassc->sc;
480d3c7b9a0SKenneth D. Merry
481d043c564SKenneth D. Merry targ = mpssas_find_target_by_handle(sassc, 0, handle);
482d043c564SKenneth D. Merry if (targ == NULL) {
483d043c564SKenneth D. Merry /* FIXME: what is the action? */
484d043c564SKenneth D. Merry /* We don't know about this device? */
4851610f95cSScott Long mps_dprint(sc, MPS_ERROR,
4861610f95cSScott Long "%s : invalid handle 0x%x \n", __func__, handle);
487d043c564SKenneth D. Merry return;
488d043c564SKenneth D. Merry }
489d043c564SKenneth D. Merry
490d043c564SKenneth D. Merry targ->flags |= MPSSAS_TARGET_INREMOVAL;
491d043c564SKenneth D. Merry
492d043c564SKenneth D. Merry cm = mpssas_alloc_tm(sc);
493d043c564SKenneth D. Merry if (cm == NULL) {
4941610f95cSScott Long mps_dprint(sc, MPS_ERROR,
4951610f95cSScott Long "%s: command alloc failure\n", __func__);
496d043c564SKenneth D. Merry return;
497d043c564SKenneth D. Merry }
498d043c564SKenneth D. Merry
499653c521fSKenneth D. Merry mpssas_rescan_target(sc, targ);
5009866848aSKenneth D. Merry
501d3c7b9a0SKenneth D. Merry req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)cm->cm_req;
502be4aa869SKenneth D. Merry req->DevHandle = htole16(targ->handle);
503d3c7b9a0SKenneth D. Merry req->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
504d3c7b9a0SKenneth D. Merry
505d3c7b9a0SKenneth D. Merry /* SAS Hard Link Reset / SATA Link Reset */
506d3c7b9a0SKenneth D. Merry req->MsgFlags = MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET;
507d3c7b9a0SKenneth D. Merry
508d3c7b9a0SKenneth D. Merry cm->cm_targ = targ;
509d043c564SKenneth D. Merry cm->cm_data = NULL;
510d043c564SKenneth D. Merry cm->cm_complete = mpssas_remove_device;
511d043c564SKenneth D. Merry cm->cm_complete_data = (void *)(uintptr_t)handle;
512ef065d89SStephen McConnell
513ef065d89SStephen McConnell mps_dprint(sc, MPS_INFO, "%s: Sending reset for target ID %d\n",
514ef065d89SStephen McConnell __func__, targ->tid);
515ef065d89SStephen McConnell mpssas_prepare_for_tm(sc, cm, targ, CAM_LUN_WILDCARD);
516ef065d89SStephen McConnell
517d043c564SKenneth D. Merry mps_map_command(sc, cm);
518d3c7b9a0SKenneth D. Merry }
519d3c7b9a0SKenneth D. Merry
520d3c7b9a0SKenneth D. Merry static void
mpssas_remove_device(struct mps_softc * sc,struct mps_command * tm)521d043c564SKenneth D. Merry mpssas_remove_device(struct mps_softc *sc, struct mps_command *tm)
522d3c7b9a0SKenneth D. Merry {
523d3c7b9a0SKenneth D. Merry MPI2_SCSI_TASK_MANAGE_REPLY *reply;
524d3c7b9a0SKenneth D. Merry MPI2_SAS_IOUNIT_CONTROL_REQUEST *req;
525d3c7b9a0SKenneth D. Merry struct mpssas_target *targ;
526d3c7b9a0SKenneth D. Merry uint16_t handle;
527d3c7b9a0SKenneth D. Merry
5281610f95cSScott Long MPS_FUNCTRACE(sc);
529d3c7b9a0SKenneth D. Merry
530d043c564SKenneth D. Merry reply = (MPI2_SCSI_TASK_MANAGE_REPLY *)tm->cm_reply;
531d043c564SKenneth D. Merry handle = (uint16_t)(uintptr_t)tm->cm_complete_data;
532d043c564SKenneth D. Merry targ = tm->cm_targ;
5331476ba40SKenneth D. Merry
534550e2acdSKenneth D. Merry /*
535550e2acdSKenneth D. Merry * Currently there should be no way we can hit this case. It only
536550e2acdSKenneth D. Merry * happens when we have a failure to allocate chain frames, and
537550e2acdSKenneth D. Merry * task management commands don't have S/G lists.
538550e2acdSKenneth D. Merry */
539d043c564SKenneth D. Merry if ((tm->cm_flags & MPS_CM_FLAGS_ERROR_MASK) != 0) {
5401610f95cSScott Long mps_dprint(sc, MPS_ERROR,
5411610f95cSScott Long "%s: cm_flags = %#x for remove of handle %#04x! "
542d043c564SKenneth D. Merry "This should not happen!\n", __func__, tm->cm_flags,
543550e2acdSKenneth D. Merry handle);
544d043c564SKenneth D. Merry }
545d043c564SKenneth D. Merry
546d043c564SKenneth D. Merry if (reply == NULL) {
547d043c564SKenneth D. Merry /* XXX retry the remove after the diag reset completes? */
5481610f95cSScott Long mps_dprint(sc, MPS_FAULT,
549f4e69c98SStephen McConnell "%s NULL reply resetting device 0x%04x\n", __func__,
550f4e69c98SStephen McConnell handle);
551d043c564SKenneth D. Merry mpssas_free_tm(sc, tm);
552550e2acdSKenneth D. Merry return;
553550e2acdSKenneth D. Merry }
554550e2acdSKenneth D. Merry
555f4e69c98SStephen McConnell if ((le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK) !=
556f4e69c98SStephen McConnell MPI2_IOCSTATUS_SUCCESS) {
557f4e69c98SStephen McConnell mps_dprint(sc, MPS_ERROR,
5581610f95cSScott Long "IOCStatus = 0x%x while resetting device 0x%x\n",
559be4aa869SKenneth D. Merry le16toh(reply->IOCStatus), handle);
560d3c7b9a0SKenneth D. Merry }
561d3c7b9a0SKenneth D. Merry
5621610f95cSScott Long mps_dprint(sc, MPS_XINFO, "Reset aborted %u commands\n",
563be4aa869SKenneth D. Merry le32toh(reply->TerminationCount));
564d043c564SKenneth D. Merry mps_free_reply(sc, tm->cm_reply_data);
56596240c89SEitan Adler tm->cm_reply = NULL; /* Ensures the reply won't get re-freed */
566d3c7b9a0SKenneth D. Merry
567d3c7b9a0SKenneth D. Merry /* Reuse the existing command */
568d043c564SKenneth D. Merry req = (MPI2_SAS_IOUNIT_CONTROL_REQUEST *)tm->cm_req;
5699866848aSKenneth D. Merry memset(req, 0, sizeof(*req));
570d3c7b9a0SKenneth D. Merry req->Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL;
571d3c7b9a0SKenneth D. Merry req->Operation = MPI2_SAS_OP_REMOVE_DEVICE;
572be4aa869SKenneth D. Merry req->DevHandle = htole16(handle);
573d043c564SKenneth D. Merry tm->cm_data = NULL;
574d043c564SKenneth D. Merry tm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
575d043c564SKenneth D. Merry tm->cm_complete = mpssas_remove_complete;
576d043c564SKenneth D. Merry tm->cm_complete_data = (void *)(uintptr_t)handle;
577d3c7b9a0SKenneth D. Merry
5784c1cdd4aSWarner Losh /*
5794c1cdd4aSWarner Losh * Wait to send the REMOVE_DEVICE until all the commands have cleared.
5804c1cdd4aSWarner Losh * They should be aborted or time out and we'll kick thus off there
5814c1cdd4aSWarner Losh * if so.
5824c1cdd4aSWarner Losh */
5834c1cdd4aSWarner Losh if (TAILQ_FIRST(&targ->commands) == NULL) {
584ca420b4eSWarner Losh mps_dprint(sc, MPS_INFO,
585ca420b4eSWarner Losh "No pending commands: starting remove_device target %u handle 0x%04x\n",
586ca420b4eSWarner Losh targ->tid, handle);
587d043c564SKenneth D. Merry mps_map_command(sc, tm);
5884c1cdd4aSWarner Losh targ->pending_remove_tm = NULL;
5894c1cdd4aSWarner Losh } else {
5904c1cdd4aSWarner Losh targ->pending_remove_tm = tm;
5914c1cdd4aSWarner Losh }
5924c1cdd4aSWarner Losh
5931610f95cSScott Long mps_dprint(sc, MPS_XINFO, "clearing target %u handle 0x%04x\n",
594d043c564SKenneth D. Merry targ->tid, handle);
595d3c7b9a0SKenneth D. Merry }
596d3c7b9a0SKenneth D. Merry
597d3c7b9a0SKenneth D. Merry static void
mpssas_remove_complete(struct mps_softc * sc,struct mps_command * tm)598d043c564SKenneth D. Merry mpssas_remove_complete(struct mps_softc *sc, struct mps_command *tm)
599d3c7b9a0SKenneth D. Merry {
600d3c7b9a0SKenneth D. Merry MPI2_SAS_IOUNIT_CONTROL_REPLY *reply;
601d043c564SKenneth D. Merry uint16_t handle;
602d043c564SKenneth D. Merry struct mpssas_target *targ;
603be4aa869SKenneth D. Merry struct mpssas_lun *lun;
604d3c7b9a0SKenneth D. Merry
6051610f95cSScott Long MPS_FUNCTRACE(sc);
606d3c7b9a0SKenneth D. Merry
607d043c564SKenneth D. Merry reply = (MPI2_SAS_IOUNIT_CONTROL_REPLY *)tm->cm_reply;
608d043c564SKenneth D. Merry handle = (uint16_t)(uintptr_t)tm->cm_complete_data;
6094c1cdd4aSWarner Losh targ = tm->cm_targ;
6104c1cdd4aSWarner Losh
6114c1cdd4aSWarner Losh /*
6124c1cdd4aSWarner Losh * At this point, we should have no pending commands for the target.
6134c1cdd4aSWarner Losh * The remove target has just completed.
6144c1cdd4aSWarner Losh */
6154c1cdd4aSWarner Losh KASSERT(TAILQ_FIRST(&targ->commands) == NULL,
6164c1cdd4aSWarner Losh ("%s: no commands should be pending\n", __func__));
6174c1cdd4aSWarner Losh
618d043c564SKenneth D. Merry /*
619d043c564SKenneth D. Merry * Currently there should be no way we can hit this case. It only
620d043c564SKenneth D. Merry * happens when we have a failure to allocate chain frames, and
621d043c564SKenneth D. Merry * task management commands don't have S/G lists.
622d043c564SKenneth D. Merry */
623d043c564SKenneth D. Merry if ((tm->cm_flags & MPS_CM_FLAGS_ERROR_MASK) != 0) {
6241610f95cSScott Long mps_dprint(sc, MPS_XINFO,
6251610f95cSScott Long "%s: cm_flags = %#x for remove of handle %#04x! "
626d043c564SKenneth D. Merry "This should not happen!\n", __func__, tm->cm_flags,
627d043c564SKenneth D. Merry handle);
628d043c564SKenneth D. Merry mpssas_free_tm(sc, tm);
629d043c564SKenneth D. Merry return;
630d3c7b9a0SKenneth D. Merry }
631d3c7b9a0SKenneth D. Merry
632d043c564SKenneth D. Merry if (reply == NULL) {
633d043c564SKenneth D. Merry /* most likely a chip reset */
6341610f95cSScott Long mps_dprint(sc, MPS_FAULT,
6351610f95cSScott Long "%s NULL reply removing device 0x%04x\n", __func__, handle);
636d043c564SKenneth D. Merry mpssas_free_tm(sc, tm);
637d043c564SKenneth D. Merry return;
638d3c7b9a0SKenneth D. Merry }
639d3c7b9a0SKenneth D. Merry
6401610f95cSScott Long mps_dprint(sc, MPS_XINFO,
6411610f95cSScott Long "%s on handle 0x%04x, IOCStatus= 0x%x\n", __func__,
642be4aa869SKenneth D. Merry handle, le16toh(reply->IOCStatus));
643d043c564SKenneth D. Merry
644d043c564SKenneth D. Merry /*
645d043c564SKenneth D. Merry * Don't clear target if remove fails because things will get confusing.
646d043c564SKenneth D. Merry * Leave the devname and sasaddr intact so that we know to avoid reusing
647d043c564SKenneth D. Merry * this target id if possible, and so we can assign the same target id
648d043c564SKenneth D. Merry * to this device if it comes back in the future.
649d043c564SKenneth D. Merry */
650f4e69c98SStephen McConnell if ((le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK) ==
651f4e69c98SStephen McConnell MPI2_IOCSTATUS_SUCCESS) {
652d043c564SKenneth D. Merry targ->handle = 0x0;
653d043c564SKenneth D. Merry targ->encl_handle = 0x0;
654d043c564SKenneth D. Merry targ->encl_slot = 0x0;
655d043c564SKenneth D. Merry targ->exp_dev_handle = 0x0;
656d043c564SKenneth D. Merry targ->phy_num = 0x0;
657d043c564SKenneth D. Merry targ->linkrate = 0x0;
658d043c564SKenneth D. Merry targ->devinfo = 0x0;
659653c521fSKenneth D. Merry targ->flags = 0x0;
660be4aa869SKenneth D. Merry
661be4aa869SKenneth D. Merry while(!SLIST_EMPTY(&targ->luns)) {
662be4aa869SKenneth D. Merry lun = SLIST_FIRST(&targ->luns);
663be4aa869SKenneth D. Merry SLIST_REMOVE_HEAD(&targ->luns, lun_link);
664be4aa869SKenneth D. Merry free(lun, M_MPT2);
665d3c7b9a0SKenneth D. Merry }
666be4aa869SKenneth D. Merry }
667be4aa869SKenneth D. Merry
668d043c564SKenneth D. Merry mpssas_free_tm(sc, tm);
669d3c7b9a0SKenneth D. Merry }
670d3c7b9a0SKenneth D. Merry
671d3c7b9a0SKenneth D. Merry static int
mpssas_register_events(struct mps_softc * sc)672d3c7b9a0SKenneth D. Merry mpssas_register_events(struct mps_softc *sc)
673d3c7b9a0SKenneth D. Merry {
674be4aa869SKenneth D. Merry u32 events[MPI2_EVENT_NOTIFY_EVENTMASK_WORDS];
675d3c7b9a0SKenneth D. Merry
676d3c7b9a0SKenneth D. Merry bzero(events, 16);
677d3c7b9a0SKenneth D. Merry setbit(events, MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE);
678d3c7b9a0SKenneth D. Merry setbit(events, MPI2_EVENT_SAS_DISCOVERY);
679d3c7b9a0SKenneth D. Merry setbit(events, MPI2_EVENT_SAS_BROADCAST_PRIMITIVE);
680d3c7b9a0SKenneth D. Merry setbit(events, MPI2_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE);
681d3c7b9a0SKenneth D. Merry setbit(events, MPI2_EVENT_SAS_INIT_TABLE_OVERFLOW);
682d3c7b9a0SKenneth D. Merry setbit(events, MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST);
683d3c7b9a0SKenneth D. Merry setbit(events, MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE);
684d043c564SKenneth D. Merry setbit(events, MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST);
685d043c564SKenneth D. Merry setbit(events, MPI2_EVENT_IR_VOLUME);
686d043c564SKenneth D. Merry setbit(events, MPI2_EVENT_IR_PHYSICAL_DISK);
687d043c564SKenneth D. Merry setbit(events, MPI2_EVENT_IR_OPERATION_STATUS);
688d043c564SKenneth D. Merry setbit(events, MPI2_EVENT_LOG_ENTRY_ADDED);
689d3c7b9a0SKenneth D. Merry
690d3c7b9a0SKenneth D. Merry mps_register_events(sc, events, mpssas_evt_handler, NULL,
691d3c7b9a0SKenneth D. Merry &sc->sassc->mpssas_eh);
692d3c7b9a0SKenneth D. Merry
693d3c7b9a0SKenneth D. Merry return (0);
694d3c7b9a0SKenneth D. Merry }
695d3c7b9a0SKenneth D. Merry
696d3c7b9a0SKenneth D. Merry int
mps_attach_sas(struct mps_softc * sc)697d3c7b9a0SKenneth D. Merry mps_attach_sas(struct mps_softc *sc)
698d3c7b9a0SKenneth D. Merry {
699d3c7b9a0SKenneth D. Merry struct mpssas_softc *sassc;
700d043c564SKenneth D. Merry cam_status status;
70162a09ee9SAlexander Motin int unit, error = 0, reqs;
702d3c7b9a0SKenneth D. Merry
7031610f95cSScott Long MPS_FUNCTRACE(sc);
704757ff642SScott Long mps_dprint(sc, MPS_INIT, "%s entered\n", __func__);
705d3c7b9a0SKenneth D. Merry
706d3c7b9a0SKenneth D. Merry sassc = malloc(sizeof(struct mpssas_softc), M_MPT2, M_WAITOK|M_ZERO);
70708235773SScott Long
70808235773SScott Long /*
70908235773SScott Long * XXX MaxTargets could change during a reinit. Since we don't
71008235773SScott Long * resize the targets[] array during such an event, cache the value
71108235773SScott Long * of MaxTargets here so that we don't get into trouble later. This
71208235773SScott Long * should move into the reinit logic.
71308235773SScott Long */
714635e58c7SStephen McConnell sassc->maxtargets = sc->facts->MaxTargets + sc->facts->MaxVolumes;
715d3c7b9a0SKenneth D. Merry sassc->targets = malloc(sizeof(struct mpssas_target) *
71608235773SScott Long sassc->maxtargets, M_MPT2, M_WAITOK|M_ZERO);
717d3c7b9a0SKenneth D. Merry sc->sassc = sassc;
718d3c7b9a0SKenneth D. Merry sassc->sc = sc;
719d3c7b9a0SKenneth D. Merry
72062a09ee9SAlexander Motin reqs = sc->num_reqs - sc->num_prireqs - 1;
72162a09ee9SAlexander Motin if ((sassc->devq = cam_simq_alloc(reqs)) == NULL) {
7221610f95cSScott Long mps_dprint(sc, MPS_ERROR, "Cannot allocate SIMQ\n");
723d3c7b9a0SKenneth D. Merry error = ENOMEM;
724d3c7b9a0SKenneth D. Merry goto out;
725d3c7b9a0SKenneth D. Merry }
726d3c7b9a0SKenneth D. Merry
727d043c564SKenneth D. Merry unit = device_get_unit(sc->mps_dev);
728d3c7b9a0SKenneth D. Merry sassc->sim = cam_sim_alloc(mpssas_action, mpssas_poll, "mps", sassc,
72962a09ee9SAlexander Motin unit, &sc->mps_mtx, reqs, reqs, sassc->devq);
730d3c7b9a0SKenneth D. Merry if (sassc->sim == NULL) {
731757ff642SScott Long mps_dprint(sc, MPS_INIT|MPS_ERROR, "Cannot allocate SIM\n");
732d3c7b9a0SKenneth D. Merry error = EINVAL;
733d3c7b9a0SKenneth D. Merry goto out;
734d3c7b9a0SKenneth D. Merry }
735d3c7b9a0SKenneth D. Merry
736d043c564SKenneth D. Merry TAILQ_INIT(&sassc->ev_queue);
737d043c564SKenneth D. Merry
738d043c564SKenneth D. Merry /* Initialize taskqueue for Event Handling */
739d043c564SKenneth D. Merry TASK_INIT(&sassc->ev_task, 0, mpssas_firmware_event_work, sc);
740d043c564SKenneth D. Merry sassc->ev_tq = taskqueue_create("mps_taskq", M_NOWAIT | M_ZERO,
741d043c564SKenneth D. Merry taskqueue_thread_enqueue, &sassc->ev_tq);
742c2a0f07aSAlexander Motin taskqueue_start_threads(&sassc->ev_tq, 1, PRIBIO, "%s taskq",
743d043c564SKenneth D. Merry device_get_nameunit(sc->mps_dev));
744d043c564SKenneth D. Merry
745d043c564SKenneth D. Merry mps_lock(sc);
746d043c564SKenneth D. Merry
747d3c7b9a0SKenneth D. Merry /*
748d3c7b9a0SKenneth D. Merry * XXX There should be a bus for every port on the adapter, but since
749d3c7b9a0SKenneth D. Merry * we're just going to fake the topology for now, we'll pretend that
750d3c7b9a0SKenneth D. Merry * everything is just a target on a single bus.
751d3c7b9a0SKenneth D. Merry */
752d3c7b9a0SKenneth D. Merry if ((error = xpt_bus_register(sassc->sim, sc->mps_dev, 0)) != 0) {
753757ff642SScott Long mps_dprint(sc, MPS_INIT|MPS_ERROR,
754757ff642SScott Long "Error %d registering SCSI bus\n", error);
755d3c7b9a0SKenneth D. Merry mps_unlock(sc);
756d3c7b9a0SKenneth D. Merry goto out;
757d3c7b9a0SKenneth D. Merry }
758d3c7b9a0SKenneth D. Merry
759d3c7b9a0SKenneth D. Merry /*
760b01773b0SKenneth D. Merry * Assume that discovery events will start right away.
761b01773b0SKenneth D. Merry *
762b01773b0SKenneth D. Merry * Hold off boot until discovery is complete.
763d3c7b9a0SKenneth D. Merry */
764d043c564SKenneth D. Merry sassc->flags |= MPSSAS_IN_STARTUP | MPSSAS_IN_DISCOVERY;
765d043c564SKenneth D. Merry sc->sassc->startup_refcount = 0;
76637b8d8c4SAlexander Motin mpssas_startup_increment(sassc);
767d3c7b9a0SKenneth D. Merry
76802d81940SAlexander Motin mps_unlock(sc);
76902d81940SAlexander Motin
770b01773b0SKenneth D. Merry /*
771b01773b0SKenneth D. Merry * Register for async events so we can determine the EEDP
772b01773b0SKenneth D. Merry * capabilities of devices.
773b01773b0SKenneth D. Merry */
774b01773b0SKenneth D. Merry status = xpt_create_path(&sassc->path, /*periph*/NULL,
775b01773b0SKenneth D. Merry cam_sim_path(sc->sassc->sim), CAM_TARGET_WILDCARD,
776b01773b0SKenneth D. Merry CAM_LUN_WILDCARD);
777b01773b0SKenneth D. Merry if (status != CAM_REQ_CMP) {
778757ff642SScott Long mps_dprint(sc, MPS_ERROR|MPS_INIT,
779757ff642SScott Long "Error %#x creating sim path\n", status);
780b01773b0SKenneth D. Merry sassc->path = NULL;
781b01773b0SKenneth D. Merry } else {
782b01773b0SKenneth D. Merry int event;
783b01773b0SKenneth D. Merry
784b01773b0SKenneth D. Merry event = AC_ADVINFO_CHANGED;
785b01773b0SKenneth D. Merry status = xpt_register_async(event, mpssas_async, sc,
786b01773b0SKenneth D. Merry sassc->path);
787d043c564SKenneth D. Merry if (status != CAM_REQ_CMP) {
7881610f95cSScott Long mps_dprint(sc, MPS_ERROR,
7891610f95cSScott Long "Error %#x registering async handler for "
790d043c564SKenneth D. Merry "AC_ADVINFO_CHANGED events\n", status);
791b01773b0SKenneth D. Merry xpt_free_path(sassc->path);
792b01773b0SKenneth D. Merry sassc->path = NULL;
793d043c564SKenneth D. Merry }
794b01773b0SKenneth D. Merry }
795b01773b0SKenneth D. Merry if (status != CAM_REQ_CMP) {
796b01773b0SKenneth D. Merry /*
797b01773b0SKenneth D. Merry * EEDP use is the exception, not the rule.
798b01773b0SKenneth D. Merry * Warn the user, but do not fail to attach.
799b01773b0SKenneth D. Merry */
800b01773b0SKenneth D. Merry mps_printf(sc, "EEDP capabilities disabled.\n");
801b01773b0SKenneth D. Merry }
802d043c564SKenneth D. Merry
803d3c7b9a0SKenneth D. Merry mpssas_register_events(sc);
804d3c7b9a0SKenneth D. Merry out:
805d3c7b9a0SKenneth D. Merry if (error)
806d3c7b9a0SKenneth D. Merry mps_detach_sas(sc);
807757ff642SScott Long
808757ff642SScott Long mps_dprint(sc, MPS_INIT, "%s exit error= %d\n", __func__, error);
809d3c7b9a0SKenneth D. Merry return (error);
810d3c7b9a0SKenneth D. Merry }
811d3c7b9a0SKenneth D. Merry
812d3c7b9a0SKenneth D. Merry int
mps_detach_sas(struct mps_softc * sc)813d3c7b9a0SKenneth D. Merry mps_detach_sas(struct mps_softc *sc)
814d3c7b9a0SKenneth D. Merry {
815d3c7b9a0SKenneth D. Merry struct mpssas_softc *sassc;
816be4aa869SKenneth D. Merry struct mpssas_lun *lun, *lun_tmp;
817be4aa869SKenneth D. Merry struct mpssas_target *targ;
818be4aa869SKenneth D. Merry int i;
819d3c7b9a0SKenneth D. Merry
8201610f95cSScott Long MPS_FUNCTRACE(sc);
821d3c7b9a0SKenneth D. Merry
822d3c7b9a0SKenneth D. Merry if (sc->sassc == NULL)
823d3c7b9a0SKenneth D. Merry return (0);
824d3c7b9a0SKenneth D. Merry
825d3c7b9a0SKenneth D. Merry sassc = sc->sassc;
826d043c564SKenneth D. Merry mps_deregister_events(sc, sassc->mpssas_eh);
827d043c564SKenneth D. Merry
828d043c564SKenneth D. Merry /*
829d043c564SKenneth D. Merry * Drain and free the event handling taskqueue with the lock
830d043c564SKenneth D. Merry * unheld so that any parallel processing tasks drain properly
831d043c564SKenneth D. Merry * without deadlocking.
832d043c564SKenneth D. Merry */
833d043c564SKenneth D. Merry if (sassc->ev_tq != NULL)
834d043c564SKenneth D. Merry taskqueue_free(sassc->ev_tq);
835d3c7b9a0SKenneth D. Merry
836d043c564SKenneth D. Merry /* Deregister our async handler */
837b01773b0SKenneth D. Merry if (sassc->path != NULL) {
838b01773b0SKenneth D. Merry xpt_register_async(0, mpssas_async, sc, sassc->path);
839b01773b0SKenneth D. Merry xpt_free_path(sassc->path);
840b01773b0SKenneth D. Merry sassc->path = NULL;
841b01773b0SKenneth D. Merry }
842d043c564SKenneth D. Merry
84302d81940SAlexander Motin /* Make sure CAM doesn't wedge if we had to bail out early. */
84402d81940SAlexander Motin mps_lock(sc);
84502d81940SAlexander Motin
84602d81940SAlexander Motin while (sassc->startup_refcount != 0)
84702d81940SAlexander Motin mpssas_startup_decrement(sassc);
84802d81940SAlexander Motin
849d3c7b9a0SKenneth D. Merry if (sassc->flags & MPSSAS_IN_STARTUP)
850d3c7b9a0SKenneth D. Merry xpt_release_simq(sassc->sim, 1);
851d3c7b9a0SKenneth D. Merry
852d3c7b9a0SKenneth D. Merry if (sassc->sim != NULL) {
853d3c7b9a0SKenneth D. Merry xpt_bus_deregister(cam_sim_path(sassc->sim));
854d3c7b9a0SKenneth D. Merry cam_sim_free(sassc->sim, FALSE);
855d3c7b9a0SKenneth D. Merry }
856d043c564SKenneth D. Merry
857d3c7b9a0SKenneth D. Merry mps_unlock(sc);
858d3c7b9a0SKenneth D. Merry
859d3c7b9a0SKenneth D. Merry if (sassc->devq != NULL)
860d3c7b9a0SKenneth D. Merry cam_simq_free(sassc->devq);
861d3c7b9a0SKenneth D. Merry
86208235773SScott Long for(i=0; i< sassc->maxtargets ;i++) {
863be4aa869SKenneth D. Merry targ = &sassc->targets[i];
864be4aa869SKenneth D. Merry SLIST_FOREACH_SAFE(lun, &targ->luns, lun_link, lun_tmp) {
865be4aa869SKenneth D. Merry free(lun, M_MPT2);
866be4aa869SKenneth D. Merry }
867be4aa869SKenneth D. Merry }
868d3c7b9a0SKenneth D. Merry free(sassc->targets, M_MPT2);
869d3c7b9a0SKenneth D. Merry free(sassc, M_MPT2);
870d3c7b9a0SKenneth D. Merry sc->sassc = NULL;
871d3c7b9a0SKenneth D. Merry
872d3c7b9a0SKenneth D. Merry return (0);
873d3c7b9a0SKenneth D. Merry }
874d3c7b9a0SKenneth D. Merry
875d043c564SKenneth D. Merry void
mpssas_discovery_end(struct mpssas_softc * sassc)876d3c7b9a0SKenneth D. Merry mpssas_discovery_end(struct mpssas_softc *sassc)
877d3c7b9a0SKenneth D. Merry {
878d3c7b9a0SKenneth D. Merry struct mps_softc *sc = sassc->sc;
879d3c7b9a0SKenneth D. Merry
8801610f95cSScott Long MPS_FUNCTRACE(sc);
881d3c7b9a0SKenneth D. Merry
882635e58c7SStephen McConnell /*
883635e58c7SStephen McConnell * After discovery has completed, check the mapping table for any
884635e58c7SStephen McConnell * missing devices and update their missing counts. Only do this once
885635e58c7SStephen McConnell * whenever the driver is initialized so that missing counts aren't
886635e58c7SStephen McConnell * updated unnecessarily. Note that just because discovery has
887635e58c7SStephen McConnell * completed doesn't mean that events have been processed yet. The
888635e58c7SStephen McConnell * check_devices function is a callout timer that checks if ALL devices
889635e58c7SStephen McConnell * are missing. If so, it will wait a little longer for events to
890635e58c7SStephen McConnell * complete and keep resetting itself until some device in the mapping
891635e58c7SStephen McConnell * table is not missing, meaning that event processing has started.
892635e58c7SStephen McConnell */
893635e58c7SStephen McConnell if (sc->track_mapping_events) {
894635e58c7SStephen McConnell mps_dprint(sc, MPS_XINFO | MPS_MAPPING, "Discovery has "
895635e58c7SStephen McConnell "completed. Check for missing devices in the mapping "
896635e58c7SStephen McConnell "table.\n");
897635e58c7SStephen McConnell callout_reset(&sc->device_check_callout,
898635e58c7SStephen McConnell MPS_MISSING_CHECK_DELAY * hz, mps_mapping_check_devices,
899635e58c7SStephen McConnell sc);
900635e58c7SStephen McConnell }
901d3c7b9a0SKenneth D. Merry }
902d3c7b9a0SKenneth D. Merry
903d3c7b9a0SKenneth D. Merry static void
mpssas_action(struct cam_sim * sim,union ccb * ccb)904d3c7b9a0SKenneth D. Merry mpssas_action(struct cam_sim *sim, union ccb *ccb)
905d3c7b9a0SKenneth D. Merry {
906d3c7b9a0SKenneth D. Merry struct mpssas_softc *sassc;
907d3c7b9a0SKenneth D. Merry
908d3c7b9a0SKenneth D. Merry sassc = cam_sim_softc(sim);
909d3c7b9a0SKenneth D. Merry
9101610f95cSScott Long MPS_FUNCTRACE(sassc->sc);
9111610f95cSScott Long mps_dprint(sassc->sc, MPS_TRACE, "ccb func_code 0x%x\n",
912d3c7b9a0SKenneth D. Merry ccb->ccb_h.func_code);
913d043c564SKenneth D. Merry mtx_assert(&sassc->sc->mps_mtx, MA_OWNED);
914d3c7b9a0SKenneth D. Merry
915d3c7b9a0SKenneth D. Merry switch (ccb->ccb_h.func_code) {
916d3c7b9a0SKenneth D. Merry case XPT_PATH_INQ:
917d3c7b9a0SKenneth D. Merry {
918d3c7b9a0SKenneth D. Merry struct ccb_pathinq *cpi = &ccb->cpi;
91932b0a21eSStephen McConnell struct mps_softc *sc = sassc->sc;
920d3c7b9a0SKenneth D. Merry
921d3c7b9a0SKenneth D. Merry cpi->version_num = 1;
922d3c7b9a0SKenneth D. Merry cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE|PI_WIDE_16;
923d3c7b9a0SKenneth D. Merry cpi->target_sprt = 0;
924b01773b0SKenneth D. Merry cpi->hba_misc = PIM_NOBUSRESET | PIM_UNMAPPED | PIM_NOSCAN;
925d3c7b9a0SKenneth D. Merry cpi->hba_eng_cnt = 0;
92608235773SScott Long cpi->max_target = sassc->maxtargets - 1;
927be4aa869SKenneth D. Merry cpi->max_lun = 255;
928635e58c7SStephen McConnell
929635e58c7SStephen McConnell /*
930635e58c7SStephen McConnell * initiator_id is set here to an ID outside the set of valid
931635e58c7SStephen McConnell * target IDs (including volumes).
932635e58c7SStephen McConnell */
933635e58c7SStephen McConnell cpi->initiator_id = sassc->maxtargets;
9344195c7deSAlan Somers strlcpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
9354195c7deSAlan Somers strlcpy(cpi->hba_vid, "Avago Tech", HBA_IDLEN);
9364195c7deSAlan Somers strlcpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
937d3c7b9a0SKenneth D. Merry cpi->unit_number = cam_sim_unit(sim);
938d3c7b9a0SKenneth D. Merry cpi->bus_id = cam_sim_bus(sim);
939d3c7b9a0SKenneth D. Merry cpi->base_transfer_speed = 150000;
940d3c7b9a0SKenneth D. Merry cpi->transport = XPORT_SAS;
941d3c7b9a0SKenneth D. Merry cpi->transport_version = 0;
942d3c7b9a0SKenneth D. Merry cpi->protocol = PROTO_SCSI;
943d3c7b9a0SKenneth D. Merry cpi->protocol_version = SCSI_REV_SPC;
9444f5d6573SAlexander Motin cpi->maxio = sc->maxio;
945601781ccSScott Long mpssas_set_ccbstatus(ccb, CAM_REQ_CMP);
946d3c7b9a0SKenneth D. Merry break;
947d3c7b9a0SKenneth D. Merry }
948d3c7b9a0SKenneth D. Merry case XPT_GET_TRAN_SETTINGS:
949d3c7b9a0SKenneth D. Merry {
950d3c7b9a0SKenneth D. Merry struct ccb_trans_settings *cts;
951d3c7b9a0SKenneth D. Merry struct ccb_trans_settings_sas *sas;
952d3c7b9a0SKenneth D. Merry struct ccb_trans_settings_scsi *scsi;
953d3c7b9a0SKenneth D. Merry struct mpssas_target *targ;
954d3c7b9a0SKenneth D. Merry
955d3c7b9a0SKenneth D. Merry cts = &ccb->cts;
956d3c7b9a0SKenneth D. Merry sas = &cts->xport_specific.sas;
957d3c7b9a0SKenneth D. Merry scsi = &cts->proto_specific.scsi;
958d3c7b9a0SKenneth D. Merry
95908235773SScott Long KASSERT(cts->ccb_h.target_id < sassc->maxtargets,
96008235773SScott Long ("Target %d out of bounds in XPT_GET_TRANS_SETTINGS\n",
96108235773SScott Long cts->ccb_h.target_id));
962d3c7b9a0SKenneth D. Merry targ = &sassc->targets[cts->ccb_h.target_id];
963d3c7b9a0SKenneth D. Merry if (targ->handle == 0x0) {
9647571e7f6SSteven Hartland mpssas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE);
965d3c7b9a0SKenneth D. Merry break;
966d3c7b9a0SKenneth D. Merry }
967d3c7b9a0SKenneth D. Merry
968d3c7b9a0SKenneth D. Merry cts->protocol_version = SCSI_REV_SPC2;
969d3c7b9a0SKenneth D. Merry cts->transport = XPORT_SAS;
970d3c7b9a0SKenneth D. Merry cts->transport_version = 0;
971d3c7b9a0SKenneth D. Merry
972d3c7b9a0SKenneth D. Merry sas->valid = CTS_SAS_VALID_SPEED;
973d3c7b9a0SKenneth D. Merry switch (targ->linkrate) {
974d3c7b9a0SKenneth D. Merry case 0x08:
975d3c7b9a0SKenneth D. Merry sas->bitrate = 150000;
976d3c7b9a0SKenneth D. Merry break;
977d3c7b9a0SKenneth D. Merry case 0x09:
978d3c7b9a0SKenneth D. Merry sas->bitrate = 300000;
979d3c7b9a0SKenneth D. Merry break;
980d3c7b9a0SKenneth D. Merry case 0x0a:
981d3c7b9a0SKenneth D. Merry sas->bitrate = 600000;
982d3c7b9a0SKenneth D. Merry break;
983d3c7b9a0SKenneth D. Merry default:
984d3c7b9a0SKenneth D. Merry sas->valid = 0;
985d3c7b9a0SKenneth D. Merry }
986d3c7b9a0SKenneth D. Merry
987d3c7b9a0SKenneth D. Merry cts->protocol = PROTO_SCSI;
988d3c7b9a0SKenneth D. Merry scsi->valid = CTS_SCSI_VALID_TQ;
989d3c7b9a0SKenneth D. Merry scsi->flags = CTS_SCSI_FLAGS_TAG_ENB;
990d3c7b9a0SKenneth D. Merry
991601781ccSScott Long mpssas_set_ccbstatus(ccb, CAM_REQ_CMP);
992d3c7b9a0SKenneth D. Merry break;
993d3c7b9a0SKenneth D. Merry }
994d3c7b9a0SKenneth D. Merry case XPT_CALC_GEOMETRY:
995d3c7b9a0SKenneth D. Merry cam_calc_geometry(&ccb->ccg, /*extended*/1);
996601781ccSScott Long mpssas_set_ccbstatus(ccb, CAM_REQ_CMP);
997d3c7b9a0SKenneth D. Merry break;
998d3c7b9a0SKenneth D. Merry case XPT_RESET_DEV:
9991610f95cSScott Long mps_dprint(sassc->sc, MPS_XINFO, "mpssas_action XPT_RESET_DEV\n");
1000d3c7b9a0SKenneth D. Merry mpssas_action_resetdev(sassc, ccb);
1001d3c7b9a0SKenneth D. Merry return;
1002d3c7b9a0SKenneth D. Merry case XPT_RESET_BUS:
1003d3c7b9a0SKenneth D. Merry case XPT_ABORT:
1004d3c7b9a0SKenneth D. Merry case XPT_TERM_IO:
10051610f95cSScott Long mps_dprint(sassc->sc, MPS_XINFO,
10061610f95cSScott Long "mpssas_action faking success for abort or reset\n");
1007601781ccSScott Long mpssas_set_ccbstatus(ccb, CAM_REQ_CMP);
1008d3c7b9a0SKenneth D. Merry break;
1009d3c7b9a0SKenneth D. Merry case XPT_SCSI_IO:
1010d3c7b9a0SKenneth D. Merry mpssas_action_scsiio(sassc, ccb);
1011d3c7b9a0SKenneth D. Merry return;
101206e79492SKenneth D. Merry case XPT_SMP_IO:
101306e79492SKenneth D. Merry mpssas_action_smpio(sassc, ccb);
101406e79492SKenneth D. Merry return;
1015d3c7b9a0SKenneth D. Merry default:
1016601781ccSScott Long mpssas_set_ccbstatus(ccb, CAM_FUNC_NOTAVAIL);
1017d3c7b9a0SKenneth D. Merry break;
1018d3c7b9a0SKenneth D. Merry }
1019d3c7b9a0SKenneth D. Merry xpt_done(ccb);
1020d3c7b9a0SKenneth D. Merry
1021d3c7b9a0SKenneth D. Merry }
1022d3c7b9a0SKenneth D. Merry
1023d3c7b9a0SKenneth D. Merry static void
mpssas_announce_reset(struct mps_softc * sc,uint32_t ac_code,target_id_t target_id,lun_id_t lun_id)1024d043c564SKenneth D. Merry mpssas_announce_reset(struct mps_softc *sc, uint32_t ac_code,
1025d043c564SKenneth D. Merry target_id_t target_id, lun_id_t lun_id)
1026d3c7b9a0SKenneth D. Merry {
1027d043c564SKenneth D. Merry path_id_t path_id = cam_sim_path(sc->sassc->sim);
1028d043c564SKenneth D. Merry struct cam_path *path;
1029d3c7b9a0SKenneth D. Merry
1030123055f0SNathan Whitehorn mps_dprint(sc, MPS_XINFO, "%s code %x target %d lun %jx\n", __func__,
1031123055f0SNathan Whitehorn ac_code, target_id, (uintmax_t)lun_id);
1032d3c7b9a0SKenneth D. Merry
1033d043c564SKenneth D. Merry if (xpt_create_path(&path, NULL,
1034d043c564SKenneth D. Merry path_id, target_id, lun_id) != CAM_REQ_CMP) {
10351610f95cSScott Long mps_dprint(sc, MPS_ERROR, "unable to create path for reset "
1036d043c564SKenneth D. Merry "notification\n");
1037d3c7b9a0SKenneth D. Merry return;
1038d3c7b9a0SKenneth D. Merry }
1039d043c564SKenneth D. Merry
1040d043c564SKenneth D. Merry xpt_async(ac_code, path, NULL);
1041d043c564SKenneth D. Merry xpt_free_path(path);
1042d043c564SKenneth D. Merry }
1043d3c7b9a0SKenneth D. Merry
1044d3c7b9a0SKenneth D. Merry static void
mpssas_complete_all_commands(struct mps_softc * sc)1045d043c564SKenneth D. Merry mpssas_complete_all_commands(struct mps_softc *sc)
1046d3c7b9a0SKenneth D. Merry {
1047d043c564SKenneth D. Merry struct mps_command *cm;
1048d043c564SKenneth D. Merry int i;
1049d043c564SKenneth D. Merry int completed;
1050d043c564SKenneth D. Merry
10511610f95cSScott Long MPS_FUNCTRACE(sc);
1052d043c564SKenneth D. Merry mtx_assert(&sc->mps_mtx, MA_OWNED);
1053d043c564SKenneth D. Merry
1054d043c564SKenneth D. Merry /* complete all commands with a NULL reply */
1055d043c564SKenneth D. Merry for (i = 1; i < sc->num_reqs; i++) {
1056d043c564SKenneth D. Merry cm = &sc->commands[i];
1057f0779b04SScott Long if (cm->cm_state == MPS_CM_STATE_FREE)
1058f0779b04SScott Long continue;
1059f0779b04SScott Long
1060f0779b04SScott Long cm->cm_state = MPS_CM_STATE_BUSY;
1061d043c564SKenneth D. Merry cm->cm_reply = NULL;
1062d043c564SKenneth D. Merry completed = 0;
1063d043c564SKenneth D. Merry
10648277ce2bSConrad Meyer if (cm->cm_flags & MPS_CM_FLAGS_SATA_ID_TIMEOUT) {
10658277ce2bSConrad Meyer MPASS(cm->cm_data);
10668277ce2bSConrad Meyer free(cm->cm_data, M_MPT2);
10678277ce2bSConrad Meyer cm->cm_data = NULL;
10688277ce2bSConrad Meyer }
10698277ce2bSConrad Meyer
1070d043c564SKenneth D. Merry if (cm->cm_flags & MPS_CM_FLAGS_POLLED)
1071d043c564SKenneth D. Merry cm->cm_flags |= MPS_CM_FLAGS_COMPLETE;
1072d043c564SKenneth D. Merry
1073d043c564SKenneth D. Merry if (cm->cm_complete != NULL) {
10741610f95cSScott Long mpssas_log_command(cm, MPS_RECOVERY,
1075d043c564SKenneth D. Merry "completing cm %p state %x ccb %p for diag reset\n",
1076d043c564SKenneth D. Merry cm, cm->cm_state, cm->cm_ccb);
1077d043c564SKenneth D. Merry
1078d043c564SKenneth D. Merry cm->cm_complete(sc, cm);
1079d043c564SKenneth D. Merry completed = 1;
1080f0779b04SScott Long } else if (cm->cm_flags & MPS_CM_FLAGS_WAKEUP) {
10811610f95cSScott Long mpssas_log_command(cm, MPS_RECOVERY,
1082d043c564SKenneth D. Merry "waking up cm %p state %x ccb %p for diag reset\n",
1083d043c564SKenneth D. Merry cm, cm->cm_state, cm->cm_ccb);
1084d043c564SKenneth D. Merry wakeup(cm);
1085d043c564SKenneth D. Merry completed = 1;
1086d043c564SKenneth D. Merry }
1087d043c564SKenneth D. Merry
1088d043c564SKenneth D. Merry if ((completed == 0) && (cm->cm_state != MPS_CM_STATE_FREE)) {
1089d043c564SKenneth D. Merry /* this should never happen, but if it does, log */
10901610f95cSScott Long mpssas_log_command(cm, MPS_RECOVERY,
1091d043c564SKenneth D. Merry "cm %p state %x flags 0x%x ccb %p during diag "
1092d043c564SKenneth D. Merry "reset\n", cm, cm->cm_state, cm->cm_flags,
1093d043c564SKenneth D. Merry cm->cm_ccb);
1094d043c564SKenneth D. Merry }
1095d043c564SKenneth D. Merry }
1096f0779b04SScott Long
1097f0779b04SScott Long sc->io_cmds_active = 0;
1098d043c564SKenneth D. Merry }
1099d043c564SKenneth D. Merry
1100d043c564SKenneth D. Merry void
mpssas_handle_reinit(struct mps_softc * sc)1101d043c564SKenneth D. Merry mpssas_handle_reinit(struct mps_softc *sc)
1102d043c564SKenneth D. Merry {
1103d043c564SKenneth D. Merry int i;
1104d043c564SKenneth D. Merry
1105d043c564SKenneth D. Merry /* Go back into startup mode and freeze the simq, so that CAM
1106d043c564SKenneth D. Merry * doesn't send any commands until after we've rediscovered all
1107d043c564SKenneth D. Merry * targets and found the proper device handles for them.
1108d043c564SKenneth D. Merry *
1109d043c564SKenneth D. Merry * After the reset, portenable will trigger discovery, and after all
1110d043c564SKenneth D. Merry * discovery-related activities have finished, the simq will be
1111d043c564SKenneth D. Merry * released.
1112d043c564SKenneth D. Merry */
11131610f95cSScott Long mps_dprint(sc, MPS_INIT, "%s startup\n", __func__);
1114d043c564SKenneth D. Merry sc->sassc->flags |= MPSSAS_IN_STARTUP;
1115d043c564SKenneth D. Merry sc->sassc->flags |= MPSSAS_IN_DISCOVERY;
111637b8d8c4SAlexander Motin mpssas_startup_increment(sc->sassc);
1117d043c564SKenneth D. Merry
1118d043c564SKenneth D. Merry /* notify CAM of a bus reset */
1119d043c564SKenneth D. Merry mpssas_announce_reset(sc, AC_BUS_RESET, CAM_TARGET_WILDCARD,
1120d043c564SKenneth D. Merry CAM_LUN_WILDCARD);
1121d043c564SKenneth D. Merry
1122d043c564SKenneth D. Merry /* complete and cleanup after all outstanding commands */
1123d043c564SKenneth D. Merry mpssas_complete_all_commands(sc);
1124d043c564SKenneth D. Merry
11251610f95cSScott Long mps_dprint(sc, MPS_INIT,
1126ef065d89SStephen McConnell "%s startup %u after command completion\n", __func__,
1127ef065d89SStephen McConnell sc->sassc->startup_refcount);
1128d043c564SKenneth D. Merry
1129d043c564SKenneth D. Merry /* zero all the target handles, since they may change after the
1130d043c564SKenneth D. Merry * reset, and we have to rediscover all the targets and use the new
1131d043c564SKenneth D. Merry * handles.
1132d043c564SKenneth D. Merry */
113308235773SScott Long for (i = 0; i < sc->sassc->maxtargets; i++) {
1134d043c564SKenneth D. Merry if (sc->sassc->targets[i].outstanding != 0)
11351610f95cSScott Long mps_dprint(sc, MPS_INIT, "target %u outstanding %u\n",
1136d043c564SKenneth D. Merry i, sc->sassc->targets[i].outstanding);
1137d043c564SKenneth D. Merry sc->sassc->targets[i].handle = 0x0;
1138d043c564SKenneth D. Merry sc->sassc->targets[i].exp_dev_handle = 0x0;
1139d043c564SKenneth D. Merry sc->sassc->targets[i].outstanding = 0;
1140d043c564SKenneth D. Merry sc->sassc->targets[i].flags = MPSSAS_TARGET_INDIAGRESET;
1141d043c564SKenneth D. Merry }
1142d043c564SKenneth D. Merry }
11431610f95cSScott Long
1144d043c564SKenneth D. Merry static void
mpssas_tm_timeout(void * data)1145d043c564SKenneth D. Merry mpssas_tm_timeout(void *data)
1146d043c564SKenneth D. Merry {
1147d043c564SKenneth D. Merry struct mps_command *tm = data;
1148d043c564SKenneth D. Merry struct mps_softc *sc = tm->cm_sc;
1149d043c564SKenneth D. Merry
1150d043c564SKenneth D. Merry mtx_assert(&sc->mps_mtx, MA_OWNED);
1151d043c564SKenneth D. Merry
11521610f95cSScott Long mpssas_log_command(tm, MPS_INFO|MPS_RECOVERY,
11531610f95cSScott Long "task mgmt %p timed out\n", tm);
1154f0779b04SScott Long
1155f0779b04SScott Long KASSERT(tm->cm_state == MPS_CM_STATE_INQUEUE,
1156175ad3d0SKenneth D. Merry ("command not inqueue, state = %u\n", tm->cm_state));
1157f0779b04SScott Long
1158f0779b04SScott Long tm->cm_state = MPS_CM_STATE_BUSY;
1159d043c564SKenneth D. Merry mps_reinit(sc);
1160d043c564SKenneth D. Merry }
1161d043c564SKenneth D. Merry
1162d043c564SKenneth D. Merry static void
mpssas_logical_unit_reset_complete(struct mps_softc * sc,struct mps_command * tm)1163d043c564SKenneth D. Merry mpssas_logical_unit_reset_complete(struct mps_softc *sc, struct mps_command *tm)
1164d043c564SKenneth D. Merry {
1165d043c564SKenneth D. Merry MPI2_SCSI_TASK_MANAGE_REPLY *reply;
1166d043c564SKenneth D. Merry unsigned int cm_count = 0;
1167d3c7b9a0SKenneth D. Merry struct mps_command *cm;
1168d3c7b9a0SKenneth D. Merry struct mpssas_target *targ;
1169d3c7b9a0SKenneth D. Merry
1170d043c564SKenneth D. Merry callout_stop(&tm->cm_callout);
1171d3c7b9a0SKenneth D. Merry
1172d043c564SKenneth D. Merry reply = (MPI2_SCSI_TASK_MANAGE_REPLY *)tm->cm_reply;
1173d043c564SKenneth D. Merry targ = tm->cm_targ;
1174d3c7b9a0SKenneth D. Merry
1175550e2acdSKenneth D. Merry /*
1176550e2acdSKenneth D. Merry * Currently there should be no way we can hit this case. It only
1177550e2acdSKenneth D. Merry * happens when we have a failure to allocate chain frames, and
1178550e2acdSKenneth D. Merry * task management commands don't have S/G lists.
11791610f95cSScott Long * XXXSL So should it be an assertion?
1180550e2acdSKenneth D. Merry */
1181d043c564SKenneth D. Merry if ((tm->cm_flags & MPS_CM_FLAGS_ERROR_MASK) != 0) {
11826eea4f46SScott Long mps_dprint(sc, MPS_RECOVERY|MPS_ERROR,
11836eea4f46SScott Long "%s: cm_flags = %#x for LUN reset! "
1184d043c564SKenneth D. Merry "This should not happen!\n", __func__, tm->cm_flags);
1185d043c564SKenneth D. Merry mpssas_free_tm(sc, tm);
1186d3c7b9a0SKenneth D. Merry return;
1187d3c7b9a0SKenneth D. Merry }
1188d3c7b9a0SKenneth D. Merry
1189d043c564SKenneth D. Merry if (reply == NULL) {
11906eea4f46SScott Long mps_dprint(sc, MPS_RECOVERY, "NULL reset reply for tm %p\n",
11916eea4f46SScott Long tm);
1192d043c564SKenneth D. Merry if ((sc->mps_flags & MPS_FLAGS_DIAGRESET) != 0) {
1193d043c564SKenneth D. Merry /* this completion was due to a reset, just cleanup */
11946eea4f46SScott Long mps_dprint(sc, MPS_RECOVERY, "Hardware undergoing "
11956eea4f46SScott Long "reset, ignoring NULL LUN reset reply\n");
1196d043c564SKenneth D. Merry targ->tm = NULL;
1197d043c564SKenneth D. Merry mpssas_free_tm(sc, tm);
1198d043c564SKenneth D. Merry }
1199d043c564SKenneth D. Merry else {
1200d043c564SKenneth D. Merry /* we should have gotten a reply. */
12016eea4f46SScott Long mps_dprint(sc, MPS_INFO|MPS_RECOVERY, "NULL reply on "
12026eea4f46SScott Long "LUN reset attempt, resetting controller\n");
1203d043c564SKenneth D. Merry mps_reinit(sc);
1204d043c564SKenneth D. Merry }
1205d043c564SKenneth D. Merry return;
1206d043c564SKenneth D. Merry }
1207d3c7b9a0SKenneth D. Merry
12086eea4f46SScott Long mps_dprint(sc, MPS_RECOVERY,
1209d043c564SKenneth D. Merry "logical unit reset status 0x%x code 0x%x count %u\n",
1210be4aa869SKenneth D. Merry le16toh(reply->IOCStatus), le32toh(reply->ResponseCode),
1211be4aa869SKenneth D. Merry le32toh(reply->TerminationCount));
1212d043c564SKenneth D. Merry
12136eea4f46SScott Long /*
12146eea4f46SScott Long * See if there are any outstanding commands for this LUN.
1215d043c564SKenneth D. Merry * This could be made more efficient by using a per-LU data
1216d043c564SKenneth D. Merry * structure of some sort.
1217d043c564SKenneth D. Merry */
1218d043c564SKenneth D. Merry TAILQ_FOREACH(cm, &targ->commands, cm_link) {
1219d043c564SKenneth D. Merry if (cm->cm_lun == tm->cm_lun)
1220d043c564SKenneth D. Merry cm_count++;
1221d043c564SKenneth D. Merry }
1222d043c564SKenneth D. Merry
1223d043c564SKenneth D. Merry if (cm_count == 0) {
12246eea4f46SScott Long mps_dprint(sc, MPS_RECOVERY|MPS_INFO,
12256eea4f46SScott Long "Finished recovery after LUN reset for target %u\n",
12266eea4f46SScott Long targ->tid);
1227d043c564SKenneth D. Merry
12286eea4f46SScott Long mpssas_announce_reset(sc, AC_SENT_BDR, targ->tid, tm->cm_lun);
1229d043c564SKenneth D. Merry
12306eea4f46SScott Long /*
12316eea4f46SScott Long * We've finished recovery for this logical unit. check and
1232d043c564SKenneth D. Merry * see if some other logical unit has a timedout command
1233d043c564SKenneth D. Merry * that needs to be processed.
1234d043c564SKenneth D. Merry */
1235d043c564SKenneth D. Merry cm = TAILQ_FIRST(&targ->timedout_commands);
1236d043c564SKenneth D. Merry if (cm) {
12376eea4f46SScott Long mps_dprint(sc, MPS_INFO|MPS_RECOVERY,
12386eea4f46SScott Long "More commands to abort for target %u\n",
12396eea4f46SScott Long targ->tid);
1240d043c564SKenneth D. Merry mpssas_send_abort(sc, tm, cm);
12416eea4f46SScott Long } else {
1242d043c564SKenneth D. Merry targ->tm = NULL;
1243d043c564SKenneth D. Merry mpssas_free_tm(sc, tm);
1244d043c564SKenneth D. Merry }
12456eea4f46SScott Long } else {
12466eea4f46SScott Long /*
12476eea4f46SScott Long * If we still have commands for this LUN, the reset
1248d043c564SKenneth D. Merry * effectively failed, regardless of the status reported.
1249d043c564SKenneth D. Merry * Escalate to a target reset.
1250d043c564SKenneth D. Merry */
12516eea4f46SScott Long mps_dprint(sc, MPS_INFO|MPS_RECOVERY,
12526eea4f46SScott Long "logical unit reset complete for target %u, but still "
12536eea4f46SScott Long "have %u command(s), sending target reset\n", targ->tid,
12546eea4f46SScott Long cm_count);
1255d043c564SKenneth D. Merry mpssas_send_reset(sc, tm,
1256d043c564SKenneth D. Merry MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET);
1257d043c564SKenneth D. Merry }
1258d043c564SKenneth D. Merry }
1259d043c564SKenneth D. Merry
1260d043c564SKenneth D. Merry static void
mpssas_target_reset_complete(struct mps_softc * sc,struct mps_command * tm)1261d043c564SKenneth D. Merry mpssas_target_reset_complete(struct mps_softc *sc, struct mps_command *tm)
1262d043c564SKenneth D. Merry {
1263d043c564SKenneth D. Merry MPI2_SCSI_TASK_MANAGE_REPLY *reply;
1264d043c564SKenneth D. Merry MPI2_SCSI_TASK_MANAGE_REQUEST *req;
1265d043c564SKenneth D. Merry struct mpssas_target *targ;
1266d043c564SKenneth D. Merry
1267d043c564SKenneth D. Merry callout_stop(&tm->cm_callout);
1268d043c564SKenneth D. Merry
1269d043c564SKenneth D. Merry req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req;
1270d043c564SKenneth D. Merry reply = (MPI2_SCSI_TASK_MANAGE_REPLY *)tm->cm_reply;
1271d043c564SKenneth D. Merry targ = tm->cm_targ;
1272d043c564SKenneth D. Merry
1273d043c564SKenneth D. Merry /*
1274d043c564SKenneth D. Merry * Currently there should be no way we can hit this case. It only
1275d043c564SKenneth D. Merry * happens when we have a failure to allocate chain frames, and
1276d043c564SKenneth D. Merry * task management commands don't have S/G lists.
1277d043c564SKenneth D. Merry */
1278d043c564SKenneth D. Merry if ((tm->cm_flags & MPS_CM_FLAGS_ERROR_MASK) != 0) {
12791610f95cSScott Long mps_dprint(sc, MPS_ERROR,"%s: cm_flags = %#x for target reset! "
1280d043c564SKenneth D. Merry "This should not happen!\n", __func__, tm->cm_flags);
1281d043c564SKenneth D. Merry mpssas_free_tm(sc, tm);
1282d043c564SKenneth D. Merry return;
1283d043c564SKenneth D. Merry }
1284d043c564SKenneth D. Merry
1285d043c564SKenneth D. Merry if (reply == NULL) {
12866eea4f46SScott Long mps_dprint(sc, MPS_RECOVERY,
12876eea4f46SScott Long "NULL target reset reply for tm %pi TaskMID %u\n",
12886eea4f46SScott Long tm, le16toh(req->TaskMID));
1289d043c564SKenneth D. Merry if ((sc->mps_flags & MPS_FLAGS_DIAGRESET) != 0) {
1290d043c564SKenneth D. Merry /* this completion was due to a reset, just cleanup */
12916eea4f46SScott Long mps_dprint(sc, MPS_RECOVERY, "Hardware undergoing "
12926eea4f46SScott Long "reset, ignoring NULL target reset reply\n");
1293d043c564SKenneth D. Merry targ->tm = NULL;
1294d043c564SKenneth D. Merry mpssas_free_tm(sc, tm);
12956eea4f46SScott Long } else {
1296d043c564SKenneth D. Merry /* we should have gotten a reply. */
12976eea4f46SScott Long mps_dprint(sc, MPS_INFO|MPS_RECOVERY, "NULL reply on "
12986eea4f46SScott Long "target reset attempt, resetting controller\n");
1299d043c564SKenneth D. Merry mps_reinit(sc);
1300d043c564SKenneth D. Merry }
1301d043c564SKenneth D. Merry return;
1302d043c564SKenneth D. Merry }
1303d043c564SKenneth D. Merry
13046eea4f46SScott Long mps_dprint(sc, MPS_RECOVERY,
1305d043c564SKenneth D. Merry "target reset status 0x%x code 0x%x count %u\n",
1306be4aa869SKenneth D. Merry le16toh(reply->IOCStatus), le32toh(reply->ResponseCode),
1307be4aa869SKenneth D. Merry le32toh(reply->TerminationCount));
1308d043c564SKenneth D. Merry
1309d043c564SKenneth D. Merry if (targ->outstanding == 0) {
1310d043c564SKenneth D. Merry /* we've finished recovery for this target and all
1311d043c564SKenneth D. Merry * of its logical units.
1312d043c564SKenneth D. Merry */
13136eea4f46SScott Long mps_dprint(sc, MPS_RECOVERY|MPS_INFO,
13146eea4f46SScott Long "Finished reset recovery for target %u\n", targ->tid);
1315d043c564SKenneth D. Merry
1316d043c564SKenneth D. Merry mpssas_announce_reset(sc, AC_SENT_BDR, tm->cm_targ->tid,
1317d043c564SKenneth D. Merry CAM_LUN_WILDCARD);
1318d043c564SKenneth D. Merry
1319d043c564SKenneth D. Merry targ->tm = NULL;
1320d043c564SKenneth D. Merry mpssas_free_tm(sc, tm);
13216eea4f46SScott Long } else {
13226eea4f46SScott Long /*
13236eea4f46SScott Long * After a target reset, if this target still has
1324d043c564SKenneth D. Merry * outstanding commands, the reset effectively failed,
1325d043c564SKenneth D. Merry * regardless of the status reported. escalate.
1326d043c564SKenneth D. Merry */
13276eea4f46SScott Long mps_dprint(sc, MPS_INFO|MPS_RECOVERY,
13286eea4f46SScott Long "Target reset complete for target %u, but still have %u "
13296eea4f46SScott Long "command(s), resetting controller\n", targ->tid,
13306eea4f46SScott Long targ->outstanding);
1331d043c564SKenneth D. Merry mps_reinit(sc);
1332d043c564SKenneth D. Merry }
1333d043c564SKenneth D. Merry }
1334d043c564SKenneth D. Merry
1335d043c564SKenneth D. Merry #define MPS_RESET_TIMEOUT 30
1336d043c564SKenneth D. Merry
1337ef065d89SStephen McConnell int
mpssas_send_reset(struct mps_softc * sc,struct mps_command * tm,uint8_t type)1338d043c564SKenneth D. Merry mpssas_send_reset(struct mps_softc *sc, struct mps_command *tm, uint8_t type)
1339d043c564SKenneth D. Merry {
1340d043c564SKenneth D. Merry MPI2_SCSI_TASK_MANAGE_REQUEST *req;
1341d043c564SKenneth D. Merry struct mpssas_target *target;
1342d043c564SKenneth D. Merry int err;
1343d043c564SKenneth D. Merry
1344d043c564SKenneth D. Merry target = tm->cm_targ;
1345d043c564SKenneth D. Merry if (target->handle == 0) {
13461610f95cSScott Long mps_dprint(sc, MPS_ERROR,"%s null devhandle for target_id %d\n",
1347d043c564SKenneth D. Merry __func__, target->tid);
1348d043c564SKenneth D. Merry return -1;
1349d043c564SKenneth D. Merry }
1350d043c564SKenneth D. Merry
1351d043c564SKenneth D. Merry req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req;
1352be4aa869SKenneth D. Merry req->DevHandle = htole16(target->handle);
1353d043c564SKenneth D. Merry req->TaskType = type;
1354d043c564SKenneth D. Merry
1355d043c564SKenneth D. Merry if (type == MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET) {
1356d043c564SKenneth D. Merry /* XXX Need to handle invalid LUNs */
1357d043c564SKenneth D. Merry MPS_SET_LUN(req->LUN, tm->cm_lun);
1358d043c564SKenneth D. Merry tm->cm_targ->logical_unit_resets++;
13596eea4f46SScott Long mps_dprint(sc, MPS_RECOVERY|MPS_INFO,
13606eea4f46SScott Long "Sending logical unit reset to target %u lun %d\n",
13616eea4f46SScott Long target->tid, tm->cm_lun);
1362d043c564SKenneth D. Merry tm->cm_complete = mpssas_logical_unit_reset_complete;
1363ef065d89SStephen McConnell mpssas_prepare_for_tm(sc, tm, target, tm->cm_lun);
13646eea4f46SScott Long } else if (type == MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET) {
1365ef065d89SStephen McConnell /*
1366ef065d89SStephen McConnell * Target reset method =
1367ef065d89SStephen McConnell * SAS Hard Link Reset / SATA Link Reset
1368ef065d89SStephen McConnell */
1369d043c564SKenneth D. Merry req->MsgFlags = MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET;
1370d043c564SKenneth D. Merry tm->cm_targ->target_resets++;
13716eea4f46SScott Long mps_dprint(sc, MPS_RECOVERY|MPS_INFO,
13726eea4f46SScott Long "Sending target reset to target %u\n", target->tid);
1373d043c564SKenneth D. Merry tm->cm_complete = mpssas_target_reset_complete;
1374ef065d89SStephen McConnell mpssas_prepare_for_tm(sc, tm, target, CAM_LUN_WILDCARD);
13756eea4f46SScott Long } else {
13761610f95cSScott Long mps_dprint(sc, MPS_ERROR, "unexpected reset type 0x%x\n", type);
1377d043c564SKenneth D. Merry return -1;
1378d043c564SKenneth D. Merry }
1379d043c564SKenneth D. Merry
1380d043c564SKenneth D. Merry tm->cm_data = NULL;
1381d043c564SKenneth D. Merry tm->cm_complete_data = (void *)tm;
1382d043c564SKenneth D. Merry
1383d043c564SKenneth D. Merry callout_reset(&tm->cm_callout, MPS_RESET_TIMEOUT * hz,
1384d043c564SKenneth D. Merry mpssas_tm_timeout, tm);
1385d043c564SKenneth D. Merry
1386d043c564SKenneth D. Merry err = mps_map_command(sc, tm);
1387d043c564SKenneth D. Merry if (err)
13886eea4f46SScott Long mps_dprint(sc, MPS_ERROR|MPS_RECOVERY,
1389d043c564SKenneth D. Merry "error %d sending reset type %u\n",
1390d043c564SKenneth D. Merry err, type);
1391d043c564SKenneth D. Merry
1392d043c564SKenneth D. Merry return err;
1393d043c564SKenneth D. Merry }
1394d043c564SKenneth D. Merry
1395d043c564SKenneth D. Merry static void
mpssas_abort_complete(struct mps_softc * sc,struct mps_command * tm)1396d043c564SKenneth D. Merry mpssas_abort_complete(struct mps_softc *sc, struct mps_command *tm)
1397d043c564SKenneth D. Merry {
1398d043c564SKenneth D. Merry struct mps_command *cm;
1399d043c564SKenneth D. Merry MPI2_SCSI_TASK_MANAGE_REPLY *reply;
1400d043c564SKenneth D. Merry MPI2_SCSI_TASK_MANAGE_REQUEST *req;
1401d043c564SKenneth D. Merry struct mpssas_target *targ;
1402d043c564SKenneth D. Merry
1403d043c564SKenneth D. Merry callout_stop(&tm->cm_callout);
1404d043c564SKenneth D. Merry
1405d043c564SKenneth D. Merry req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req;
1406d043c564SKenneth D. Merry reply = (MPI2_SCSI_TASK_MANAGE_REPLY *)tm->cm_reply;
1407d043c564SKenneth D. Merry targ = tm->cm_targ;
1408d043c564SKenneth D. Merry
1409d043c564SKenneth D. Merry /*
1410d043c564SKenneth D. Merry * Currently there should be no way we can hit this case. It only
1411d043c564SKenneth D. Merry * happens when we have a failure to allocate chain frames, and
1412d043c564SKenneth D. Merry * task management commands don't have S/G lists.
1413d043c564SKenneth D. Merry */
1414d043c564SKenneth D. Merry if ((tm->cm_flags & MPS_CM_FLAGS_ERROR_MASK) != 0) {
14156eea4f46SScott Long mps_dprint(sc, MPS_RECOVERY,
1416d043c564SKenneth D. Merry "cm_flags = %#x for abort %p TaskMID %u!\n",
1417be4aa869SKenneth D. Merry tm->cm_flags, tm, le16toh(req->TaskMID));
1418d043c564SKenneth D. Merry mpssas_free_tm(sc, tm);
1419d043c564SKenneth D. Merry return;
1420d043c564SKenneth D. Merry }
1421d043c564SKenneth D. Merry
1422d043c564SKenneth D. Merry if (reply == NULL) {
14236eea4f46SScott Long mps_dprint(sc, MPS_RECOVERY,
1424d043c564SKenneth D. Merry "NULL abort reply for tm %p TaskMID %u\n",
1425be4aa869SKenneth D. Merry tm, le16toh(req->TaskMID));
1426d043c564SKenneth D. Merry if ((sc->mps_flags & MPS_FLAGS_DIAGRESET) != 0) {
1427d043c564SKenneth D. Merry /* this completion was due to a reset, just cleanup */
14286eea4f46SScott Long mps_dprint(sc, MPS_RECOVERY, "Hardware undergoing "
14296eea4f46SScott Long "reset, ignoring NULL abort reply\n");
1430d043c564SKenneth D. Merry targ->tm = NULL;
1431d043c564SKenneth D. Merry mpssas_free_tm(sc, tm);
14326eea4f46SScott Long } else {
1433d043c564SKenneth D. Merry /* we should have gotten a reply. */
14346eea4f46SScott Long mps_dprint(sc, MPS_INFO|MPS_RECOVERY, "NULL reply on "
14356eea4f46SScott Long "abort attempt, resetting controller\n");
1436d043c564SKenneth D. Merry mps_reinit(sc);
1437d043c564SKenneth D. Merry }
1438d043c564SKenneth D. Merry return;
1439d043c564SKenneth D. Merry }
1440d043c564SKenneth D. Merry
14416eea4f46SScott Long mps_dprint(sc, MPS_RECOVERY,
1442d043c564SKenneth D. Merry "abort TaskMID %u status 0x%x code 0x%x count %u\n",
1443be4aa869SKenneth D. Merry le16toh(req->TaskMID),
1444be4aa869SKenneth D. Merry le16toh(reply->IOCStatus), le32toh(reply->ResponseCode),
1445be4aa869SKenneth D. Merry le32toh(reply->TerminationCount));
1446d043c564SKenneth D. Merry
1447d043c564SKenneth D. Merry cm = TAILQ_FIRST(&tm->cm_targ->timedout_commands);
1448d043c564SKenneth D. Merry if (cm == NULL) {
14496eea4f46SScott Long /*
14506eea4f46SScott Long * If there are no more timedout commands, we're done with
1451d043c564SKenneth D. Merry * error recovery for this target.
1452d043c564SKenneth D. Merry */
14536eea4f46SScott Long mps_dprint(sc, MPS_INFO|MPS_RECOVERY,
14546eea4f46SScott Long "Finished abort recovery for target %u\n", targ->tid);
1455d043c564SKenneth D. Merry
1456d043c564SKenneth D. Merry targ->tm = NULL;
1457d043c564SKenneth D. Merry mpssas_free_tm(sc, tm);
14586eea4f46SScott Long } else if (le16toh(req->TaskMID) != cm->cm_desc.Default.SMID) {
1459d043c564SKenneth D. Merry /* abort success, but we have more timedout commands to abort */
14606eea4f46SScott Long mps_dprint(sc, MPS_INFO|MPS_RECOVERY,
14616eea4f46SScott Long "Continuing abort recovery for target %u\n", targ->tid);
1462d043c564SKenneth D. Merry
1463d043c564SKenneth D. Merry mpssas_send_abort(sc, tm, cm);
14646eea4f46SScott Long } else {
1465d043c564SKenneth D. Merry /* we didn't get a command completion, so the abort
1466d043c564SKenneth D. Merry * failed as far as we're concerned. escalate.
1467d043c564SKenneth D. Merry */
14686eea4f46SScott Long mps_dprint(sc, MPS_RECOVERY,
14696eea4f46SScott Long "Abort failed for target %u, sending logical unit reset\n",
14706eea4f46SScott Long targ->tid);
1471d043c564SKenneth D. Merry
1472d043c564SKenneth D. Merry mpssas_send_reset(sc, tm,
1473d043c564SKenneth D. Merry MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET);
1474d043c564SKenneth D. Merry }
1475d043c564SKenneth D. Merry }
1476d043c564SKenneth D. Merry
1477d043c564SKenneth D. Merry #define MPS_ABORT_TIMEOUT 5
1478d043c564SKenneth D. Merry
1479d043c564SKenneth D. Merry static int
mpssas_send_abort(struct mps_softc * sc,struct mps_command * tm,struct mps_command * cm)1480d043c564SKenneth D. Merry mpssas_send_abort(struct mps_softc *sc, struct mps_command *tm, struct mps_command *cm)
1481d043c564SKenneth D. Merry {
1482d043c564SKenneth D. Merry MPI2_SCSI_TASK_MANAGE_REQUEST *req;
1483d043c564SKenneth D. Merry struct mpssas_target *targ;
1484d043c564SKenneth D. Merry int err;
1485d043c564SKenneth D. Merry
1486d043c564SKenneth D. Merry targ = cm->cm_targ;
1487d043c564SKenneth D. Merry if (targ->handle == 0) {
14886eea4f46SScott Long mps_dprint(sc, MPS_ERROR|MPS_RECOVERY,
14896eea4f46SScott Long "%s null devhandle for target_id %d\n",
1490d043c564SKenneth D. Merry __func__, cm->cm_ccb->ccb_h.target_id);
1491d043c564SKenneth D. Merry return -1;
1492d043c564SKenneth D. Merry }
1493d043c564SKenneth D. Merry
1494855fe445SScott Long mpssas_log_command(cm, MPS_RECOVERY|MPS_INFO,
14951610f95cSScott Long "Aborting command %p\n", cm);
14961610f95cSScott Long
1497d043c564SKenneth D. Merry req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req;
1498be4aa869SKenneth D. Merry req->DevHandle = htole16(targ->handle);
1499d3c7b9a0SKenneth D. Merry req->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK;
1500d3c7b9a0SKenneth D. Merry
1501d043c564SKenneth D. Merry /* XXX Need to handle invalid LUNs */
1502d043c564SKenneth D. Merry MPS_SET_LUN(req->LUN, cm->cm_ccb->ccb_h.target_lun);
1503d3c7b9a0SKenneth D. Merry
1504be4aa869SKenneth D. Merry req->TaskMID = htole16(cm->cm_desc.Default.SMID);
15051476ba40SKenneth D. Merry
1506d043c564SKenneth D. Merry tm->cm_data = NULL;
1507d043c564SKenneth D. Merry tm->cm_complete = mpssas_abort_complete;
1508d043c564SKenneth D. Merry tm->cm_complete_data = (void *)tm;
1509d043c564SKenneth D. Merry tm->cm_targ = cm->cm_targ;
1510d043c564SKenneth D. Merry tm->cm_lun = cm->cm_lun;
1511d043c564SKenneth D. Merry
1512d043c564SKenneth D. Merry callout_reset(&tm->cm_callout, MPS_ABORT_TIMEOUT * hz,
1513d043c564SKenneth D. Merry mpssas_tm_timeout, tm);
1514d043c564SKenneth D. Merry
1515d043c564SKenneth D. Merry targ->aborts++;
1516d043c564SKenneth D. Merry
1517ef065d89SStephen McConnell mpssas_prepare_for_tm(sc, tm, targ, tm->cm_lun);
1518ef065d89SStephen McConnell
1519d043c564SKenneth D. Merry err = mps_map_command(sc, tm);
1520d043c564SKenneth D. Merry if (err)
15216eea4f46SScott Long mps_dprint(sc, MPS_ERROR|MPS_RECOVERY,
1522d043c564SKenneth D. Merry "error %d sending abort for cm %p SMID %u\n",
1523d043c564SKenneth D. Merry err, cm, req->TaskMID);
1524d043c564SKenneth D. Merry return err;
15251476ba40SKenneth D. Merry }
15261476ba40SKenneth D. Merry
15271476ba40SKenneth D. Merry static void
mpssas_scsiio_timeout(void * data)1528d043c564SKenneth D. Merry mpssas_scsiio_timeout(void *data)
15291476ba40SKenneth D. Merry {
15306eea4f46SScott Long sbintime_t elapsed, now;
15316eea4f46SScott Long union ccb *ccb;
1532d043c564SKenneth D. Merry struct mps_softc *sc;
1533d043c564SKenneth D. Merry struct mps_command *cm;
1534d043c564SKenneth D. Merry struct mpssas_target *targ;
15351476ba40SKenneth D. Merry
1536d043c564SKenneth D. Merry cm = (struct mps_command *)data;
1537d043c564SKenneth D. Merry sc = cm->cm_sc;
15386eea4f46SScott Long ccb = cm->cm_ccb;
15396eea4f46SScott Long now = sbinuptime();
15401476ba40SKenneth D. Merry
15411610f95cSScott Long MPS_FUNCTRACE(sc);
15421476ba40SKenneth D. Merry mtx_assert(&sc->mps_mtx, MA_OWNED);
15431476ba40SKenneth D. Merry
1544b086bc0bSWarner Losh mps_dprint(sc, MPS_XINFO|MPS_RECOVERY, "Timeout checking cm %p\n", cm);
1545d3c7b9a0SKenneth D. Merry
15461476ba40SKenneth D. Merry /*
1547d043c564SKenneth D. Merry * Run the interrupt handler to make sure it's not pending. This
1548d043c564SKenneth D. Merry * isn't perfect because the command could have already completed
1549d043c564SKenneth D. Merry * and been re-used, though this is unlikely.
15501476ba40SKenneth D. Merry */
1551d043c564SKenneth D. Merry mps_intr_locked(sc);
15528fe7bf06SWarner Losh if (cm->cm_flags & MPS_CM_FLAGS_ON_RECOVERY) {
15531610f95cSScott Long mpssas_log_command(cm, MPS_XINFO,
15541610f95cSScott Long "SCSI command %p almost timed out\n", cm);
1555d043c564SKenneth D. Merry return;
15561476ba40SKenneth D. Merry }
15571476ba40SKenneth D. Merry
1558d043c564SKenneth D. Merry if (cm->cm_ccb == NULL) {
15591610f95cSScott Long mps_dprint(sc, MPS_ERROR, "command timeout with NULL ccb\n");
1560d043c564SKenneth D. Merry return;
15611476ba40SKenneth D. Merry }
15621476ba40SKenneth D. Merry
1563d043c564SKenneth D. Merry targ = cm->cm_targ;
1564d043c564SKenneth D. Merry targ->timeouts++;
1565d043c564SKenneth D. Merry
15666eea4f46SScott Long elapsed = now - ccb->ccb_h.qos.sim_data;
15676eea4f46SScott Long mpssas_log_command(cm, MPS_INFO|MPS_RECOVERY,
15686eea4f46SScott Long "Command timeout on target %u(0x%04x) %d set, %d.%d elapsed\n",
15696eea4f46SScott Long targ->tid, targ->handle, ccb->ccb_h.timeout,
15706eea4f46SScott Long sbintime_getsec(elapsed), elapsed & 0xffffffff);
1571855fe445SScott Long
1572d043c564SKenneth D. Merry /* XXX first, check the firmware state, to see if it's still
1573d043c564SKenneth D. Merry * operational. if not, do a diag reset.
15741476ba40SKenneth D. Merry */
1575601781ccSScott Long mpssas_set_ccbstatus(cm->cm_ccb, CAM_CMD_TIMEOUT);
15768fe7bf06SWarner Losh cm->cm_flags |= MPS_CM_FLAGS_ON_RECOVERY | MPS_CM_FLAGS_TIMEDOUT;
1577d043c564SKenneth D. Merry TAILQ_INSERT_TAIL(&targ->timedout_commands, cm, cm_recovery);
15781476ba40SKenneth D. Merry
1579d043c564SKenneth D. Merry if (targ->tm != NULL) {
1580d043c564SKenneth D. Merry /* target already in recovery, just queue up another
1581d043c564SKenneth D. Merry * timedout command to be processed later.
15821476ba40SKenneth D. Merry */
15831610f95cSScott Long mps_dprint(sc, MPS_RECOVERY,
15841610f95cSScott Long "queued timedout cm %p for processing by tm %p\n",
1585d043c564SKenneth D. Merry cm, targ->tm);
15866eea4f46SScott Long } else if ((targ->tm = mpssas_alloc_tm(sc)) != NULL) {
15876eea4f46SScott Long mps_dprint(sc, MPS_RECOVERY|MPS_INFO,
15886eea4f46SScott Long "Sending abort to target %u for SMID %d\n", targ->tid,
15896eea4f46SScott Long cm->cm_desc.Default.SMID);
15901610f95cSScott Long mps_dprint(sc, MPS_RECOVERY, "timedout cm %p allocated tm %p\n",
1591d043c564SKenneth D. Merry cm, targ->tm);
15921476ba40SKenneth D. Merry
1593d043c564SKenneth D. Merry /* start recovery by aborting the first timedout command */
1594d043c564SKenneth D. Merry mpssas_send_abort(sc, targ->tm, cm);
15956eea4f46SScott Long } else {
1596d043c564SKenneth D. Merry /* XXX queue this target up for recovery once a TM becomes
1597d043c564SKenneth D. Merry * available. The firmware only has a limited number of
1598d043c564SKenneth D. Merry * HighPriority credits for the high priority requests used
1599d043c564SKenneth D. Merry * for task management, and we ran out.
16001476ba40SKenneth D. Merry *
1601d043c564SKenneth D. Merry * Isilon: don't worry about this for now, since we have
1602d043c564SKenneth D. Merry * more credits than disks in an enclosure, and limit
1603d043c564SKenneth D. Merry * ourselves to one TM per target for recovery.
16041476ba40SKenneth D. Merry */
16056eea4f46SScott Long mps_dprint(sc, MPS_ERROR|MPS_RECOVERY,
16061610f95cSScott Long "timedout cm %p failed to allocate a tm\n", cm);
1607d3c7b9a0SKenneth D. Merry }
1608d3c7b9a0SKenneth D. Merry
1609d3c7b9a0SKenneth D. Merry }
1610d3c7b9a0SKenneth D. Merry
1611d3c7b9a0SKenneth D. Merry static void
mpssas_action_scsiio(struct mpssas_softc * sassc,union ccb * ccb)1612d3c7b9a0SKenneth D. Merry mpssas_action_scsiio(struct mpssas_softc *sassc, union ccb *ccb)
1613d3c7b9a0SKenneth D. Merry {
1614d3c7b9a0SKenneth D. Merry MPI2_SCSI_IO_REQUEST *req;
1615d3c7b9a0SKenneth D. Merry struct ccb_scsiio *csio;
1616d3c7b9a0SKenneth D. Merry struct mps_softc *sc;
1617d3c7b9a0SKenneth D. Merry struct mpssas_target *targ;
1618d043c564SKenneth D. Merry struct mpssas_lun *lun;
1619d3c7b9a0SKenneth D. Merry struct mps_command *cm;
1620d043c564SKenneth D. Merry uint8_t i, lba_byte, *ref_tag_addr;
1621d043c564SKenneth D. Merry uint16_t eedp_flags;
1622be4aa869SKenneth D. Merry uint32_t mpi_control;
1623d3c7b9a0SKenneth D. Merry
1624d3c7b9a0SKenneth D. Merry sc = sassc->sc;
16251610f95cSScott Long MPS_FUNCTRACE(sc);
1626d043c564SKenneth D. Merry mtx_assert(&sc->mps_mtx, MA_OWNED);
1627d3c7b9a0SKenneth D. Merry
1628d3c7b9a0SKenneth D. Merry csio = &ccb->csio;
162908235773SScott Long KASSERT(csio->ccb_h.target_id < sassc->maxtargets,
163008235773SScott Long ("Target %d out of bounds in XPT_SCSI_IO\n",
163108235773SScott Long csio->ccb_h.target_id));
1632d3c7b9a0SKenneth D. Merry targ = &sassc->targets[csio->ccb_h.target_id];
16331610f95cSScott Long mps_dprint(sc, MPS_TRACE, "ccb %p target flag %x\n", ccb, targ->flags);
1634d3c7b9a0SKenneth D. Merry if (targ->handle == 0x0) {
1635e35816c1SWarner Losh if (targ->flags & MPSSAS_TARGET_INDIAGRESET) {
1636e35816c1SWarner Losh mps_dprint(sc, MPS_ERROR,
1637e35816c1SWarner Losh "%s NULL handle for target %u in diag reset freezing queue\n",
1638e35816c1SWarner Losh __func__, csio->ccb_h.target_id);
1639e35816c1SWarner Losh ccb->ccb_h.status = CAM_REQUEUE_REQ | CAM_DEV_QFRZN;
1640e35816c1SWarner Losh xpt_freeze_devq(ccb->ccb_h.path, 1);
1641e35816c1SWarner Losh xpt_done(ccb);
1642e35816c1SWarner Losh return;
1643e35816c1SWarner Losh }
16441610f95cSScott Long mps_dprint(sc, MPS_ERROR, "%s NULL handle for target %u\n",
1645d043c564SKenneth D. Merry __func__, csio->ccb_h.target_id);
16467571e7f6SSteven Hartland mpssas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE);
1647d043c564SKenneth D. Merry xpt_done(ccb);
1648d043c564SKenneth D. Merry return;
1649d043c564SKenneth D. Merry }
1650653c521fSKenneth D. Merry if (targ->flags & MPS_TARGET_FLAGS_RAID_COMPONENT) {
16519b91b192SKenneth D. Merry mps_dprint(sc, MPS_ERROR, "%s Raid component no SCSI IO "
16529b91b192SKenneth D. Merry "supported %u\n", __func__, csio->ccb_h.target_id);
16537571e7f6SSteven Hartland mpssas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE);
1654653c521fSKenneth D. Merry xpt_done(ccb);
1655653c521fSKenneth D. Merry return;
1656653c521fSKenneth D. Merry }
1657d043c564SKenneth D. Merry /*
16589b91b192SKenneth D. Merry * Sometimes, it is possible to get a command that is not "In
16599b91b192SKenneth D. Merry * Progress" and was actually aborted by the upper layer. Check for
16609b91b192SKenneth D. Merry * this here and complete the command without error.
16619b91b192SKenneth D. Merry */
1662601781ccSScott Long if (mpssas_get_ccbstatus(ccb) != CAM_REQ_INPROG) {
16639b91b192SKenneth D. Merry mps_dprint(sc, MPS_TRACE, "%s Command is not in progress for "
16649b91b192SKenneth D. Merry "target %u\n", __func__, csio->ccb_h.target_id);
16659b91b192SKenneth D. Merry xpt_done(ccb);
16669b91b192SKenneth D. Merry return;
16679b91b192SKenneth D. Merry }
16689b91b192SKenneth D. Merry /*
1669d043c564SKenneth D. Merry * If devinfo is 0 this will be a volume. In that case don't tell CAM
1670d043c564SKenneth D. Merry * that the volume has timed out. We want volumes to be enumerated
16714c1cdd4aSWarner Losh * until they are deleted/removed, not just failed. In either event,
16724c1cdd4aSWarner Losh * we're removing the target due to a firmware event telling us
16734c1cdd4aSWarner Losh * the device is now gone (as opposed to some transient event). Since
16744c1cdd4aSWarner Losh * we're opting to remove failed devices from the OS's view, we need
16754c1cdd4aSWarner Losh * to propagate that status up the stack.
1676d043c564SKenneth D. Merry */
1677d043c564SKenneth D. Merry if (targ->flags & MPSSAS_TARGET_INREMOVAL) {
1678d043c564SKenneth D. Merry if (targ->devinfo == 0)
1679601781ccSScott Long mpssas_set_ccbstatus(ccb, CAM_REQ_CMP);
1680d043c564SKenneth D. Merry else
16814c1cdd4aSWarner Losh mpssas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE);
1682d3c7b9a0SKenneth D. Merry xpt_done(ccb);
1683d3c7b9a0SKenneth D. Merry return;
1684d3c7b9a0SKenneth D. Merry }
1685d3c7b9a0SKenneth D. Merry
1686d043c564SKenneth D. Merry if ((sc->mps_flags & MPS_FLAGS_SHUTDOWN) != 0) {
16871610f95cSScott Long mps_dprint(sc, MPS_INFO, "%s shutting down\n", __func__);
16887571e7f6SSteven Hartland mpssas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE);
1689d043c564SKenneth D. Merry xpt_done(ccb);
1690d043c564SKenneth D. Merry return;
1691d043c564SKenneth D. Merry }
1692d043c564SKenneth D. Merry
1693ef065d89SStephen McConnell /*
1694db0ac6deSCy Schubert * If target has a reset in progress, the devq should be frozen.
1695db0ac6deSCy Schubert * Geting here we likely hit a race, so just requeue.
1696ef065d89SStephen McConnell */
1697ef065d89SStephen McConnell if (targ->flags & MPSSAS_TARGET_INRESET) {
1698db0ac6deSCy Schubert ccb->ccb_h.status = CAM_REQUEUE_REQ | CAM_DEV_QFRZN;
1699ef065d89SStephen McConnell mps_dprint(sc, MPS_INFO, "%s: Freezing devq for target ID %d\n",
1700ef065d89SStephen McConnell __func__, targ->tid);
1701ef065d89SStephen McConnell xpt_freeze_devq(ccb->ccb_h.path, 1);
1702ef065d89SStephen McConnell xpt_done(ccb);
1703ef065d89SStephen McConnell return;
1704ef065d89SStephen McConnell }
1705ef065d89SStephen McConnell
1706d3c7b9a0SKenneth D. Merry cm = mps_alloc_command(sc);
17077571e7f6SSteven Hartland if (cm == NULL || (sc->mps_flags & MPS_FLAGS_DIAGRESET)) {
17087571e7f6SSteven Hartland if (cm != NULL) {
17097571e7f6SSteven Hartland mps_free_command(sc, cm);
17107571e7f6SSteven Hartland }
1711d3c7b9a0SKenneth D. Merry if ((sassc->flags & MPSSAS_QUEUE_FROZEN) == 0) {
1712d3c7b9a0SKenneth D. Merry xpt_freeze_simq(sassc->sim, 1);
1713d3c7b9a0SKenneth D. Merry sassc->flags |= MPSSAS_QUEUE_FROZEN;
1714d3c7b9a0SKenneth D. Merry }
1715d3c7b9a0SKenneth D. Merry ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
1716d3c7b9a0SKenneth D. Merry ccb->ccb_h.status |= CAM_REQUEUE_REQ;
1717d3c7b9a0SKenneth D. Merry xpt_done(ccb);
1718d3c7b9a0SKenneth D. Merry return;
1719d3c7b9a0SKenneth D. Merry }
1720d3c7b9a0SKenneth D. Merry
1721d3c7b9a0SKenneth D. Merry req = (MPI2_SCSI_IO_REQUEST *)cm->cm_req;
1722550e2acdSKenneth D. Merry bzero(req, sizeof(*req));
1723be4aa869SKenneth D. Merry req->DevHandle = htole16(targ->handle);
1724d3c7b9a0SKenneth D. Merry req->Function = MPI2_FUNCTION_SCSI_IO_REQUEST;
1725d3c7b9a0SKenneth D. Merry req->MsgFlags = 0;
1726be4aa869SKenneth D. Merry req->SenseBufferLowAddress = htole32(cm->cm_sense_busaddr);
1727d3c7b9a0SKenneth D. Merry req->SenseBufferLength = MPS_SENSE_LEN;
1728d3c7b9a0SKenneth D. Merry req->SGLFlags = 0;
1729d3c7b9a0SKenneth D. Merry req->ChainOffset = 0;
1730d3c7b9a0SKenneth D. Merry req->SGLOffset0 = 24; /* 32bit word offset to the SGL */
1731d3c7b9a0SKenneth D. Merry req->SGLOffset1= 0;
1732d3c7b9a0SKenneth D. Merry req->SGLOffset2= 0;
1733d3c7b9a0SKenneth D. Merry req->SGLOffset3= 0;
1734d3c7b9a0SKenneth D. Merry req->SkipCount = 0;
1735be4aa869SKenneth D. Merry req->DataLength = htole32(csio->dxfer_len);
1736d3c7b9a0SKenneth D. Merry req->BidirectionalDataLength = 0;
1737be4aa869SKenneth D. Merry req->IoFlags = htole16(csio->cdb_len);
1738d3c7b9a0SKenneth D. Merry req->EEDPFlags = 0;
1739d3c7b9a0SKenneth D. Merry
1740d3c7b9a0SKenneth D. Merry /* Note: BiDirectional transfers are not supported */
1741d3c7b9a0SKenneth D. Merry switch (csio->ccb_h.flags & CAM_DIR_MASK) {
1742d3c7b9a0SKenneth D. Merry case CAM_DIR_IN:
1743be4aa869SKenneth D. Merry mpi_control = MPI2_SCSIIO_CONTROL_READ;
1744d3c7b9a0SKenneth D. Merry cm->cm_flags |= MPS_CM_FLAGS_DATAIN;
1745d3c7b9a0SKenneth D. Merry break;
1746d3c7b9a0SKenneth D. Merry case CAM_DIR_OUT:
1747be4aa869SKenneth D. Merry mpi_control = MPI2_SCSIIO_CONTROL_WRITE;
1748d3c7b9a0SKenneth D. Merry cm->cm_flags |= MPS_CM_FLAGS_DATAOUT;
1749d3c7b9a0SKenneth D. Merry break;
1750d3c7b9a0SKenneth D. Merry case CAM_DIR_NONE:
1751d3c7b9a0SKenneth D. Merry default:
1752be4aa869SKenneth D. Merry mpi_control = MPI2_SCSIIO_CONTROL_NODATATRANSFER;
1753d3c7b9a0SKenneth D. Merry break;
1754d3c7b9a0SKenneth D. Merry }
1755d3c7b9a0SKenneth D. Merry
1756be4aa869SKenneth D. Merry if (csio->cdb_len == 32)
1757be4aa869SKenneth D. Merry mpi_control |= 4 << MPI2_SCSIIO_CONTROL_ADDCDBLEN_SHIFT;
1758d3c7b9a0SKenneth D. Merry /*
1759d3c7b9a0SKenneth D. Merry * It looks like the hardware doesn't require an explicit tag
1760d3c7b9a0SKenneth D. Merry * number for each transaction. SAM Task Management not supported
1761d3c7b9a0SKenneth D. Merry * at the moment.
1762d3c7b9a0SKenneth D. Merry */
1763d3c7b9a0SKenneth D. Merry switch (csio->tag_action) {
1764d3c7b9a0SKenneth D. Merry case MSG_HEAD_OF_Q_TAG:
1765be4aa869SKenneth D. Merry mpi_control |= MPI2_SCSIIO_CONTROL_HEADOFQ;
1766d3c7b9a0SKenneth D. Merry break;
1767d3c7b9a0SKenneth D. Merry case MSG_ORDERED_Q_TAG:
1768be4aa869SKenneth D. Merry mpi_control |= MPI2_SCSIIO_CONTROL_ORDEREDQ;
1769d3c7b9a0SKenneth D. Merry break;
1770d3c7b9a0SKenneth D. Merry case MSG_ACA_TASK:
1771be4aa869SKenneth D. Merry mpi_control |= MPI2_SCSIIO_CONTROL_ACAQ;
1772d3c7b9a0SKenneth D. Merry break;
1773d3c7b9a0SKenneth D. Merry case CAM_TAG_ACTION_NONE:
1774d3c7b9a0SKenneth D. Merry case MSG_SIMPLE_Q_TAG:
1775d3c7b9a0SKenneth D. Merry default:
1776be4aa869SKenneth D. Merry mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ;
1777d3c7b9a0SKenneth D. Merry break;
1778d3c7b9a0SKenneth D. Merry }
177988364968SAlexander Motin mpi_control |= (csio->priority << MPI2_SCSIIO_CONTROL_TASKPRI_SHIFT) &
178088364968SAlexander Motin MPI2_SCSIIO_CONTROL_TASKPRI_MASK;
1781be4aa869SKenneth D. Merry mpi_control |= sc->mapping_table[csio->ccb_h.target_id].TLR_bits;
1782be4aa869SKenneth D. Merry req->Control = htole32(mpi_control);
1783d970279cSKenneth D. Merry if (MPS_SET_LUN(req->LUN, csio->ccb_h.target_lun) != 0) {
1784d3c7b9a0SKenneth D. Merry mps_free_command(sc, cm);
1785601781ccSScott Long mpssas_set_ccbstatus(ccb, CAM_LUN_INVALID);
1786d3c7b9a0SKenneth D. Merry xpt_done(ccb);
1787d3c7b9a0SKenneth D. Merry return;
1788d3c7b9a0SKenneth D. Merry }
1789d3c7b9a0SKenneth D. Merry
1790d3c7b9a0SKenneth D. Merry if (csio->ccb_h.flags & CAM_CDB_POINTER)
1791d3c7b9a0SKenneth D. Merry bcopy(csio->cdb_io.cdb_ptr, &req->CDB.CDB32[0], csio->cdb_len);
1792d3c7b9a0SKenneth D. Merry else
1793d3c7b9a0SKenneth D. Merry bcopy(csio->cdb_io.cdb_bytes, &req->CDB.CDB32[0],csio->cdb_len);
1794be4aa869SKenneth D. Merry req->IoFlags = htole16(csio->cdb_len);
1795d3c7b9a0SKenneth D. Merry
179606e79492SKenneth D. Merry /*
1797d043c564SKenneth D. Merry * Check if EEDP is supported and enabled. If it is then check if the
1798d043c564SKenneth D. Merry * SCSI opcode could be using EEDP. If so, make sure the LUN exists and
1799d043c564SKenneth D. Merry * is formatted for EEDP support. If all of this is true, set CDB up
1800d043c564SKenneth D. Merry * for EEDP transfer.
180106e79492SKenneth D. Merry */
1802d043c564SKenneth D. Merry eedp_flags = op_code_prot[req->CDB.CDB32[0]];
1803d043c564SKenneth D. Merry if (sc->eedp_enabled && eedp_flags) {
1804d043c564SKenneth D. Merry SLIST_FOREACH(lun, &targ->luns, lun_link) {
1805d043c564SKenneth D. Merry if (lun->lun_id == csio->ccb_h.target_lun) {
1806d043c564SKenneth D. Merry break;
1807d043c564SKenneth D. Merry }
1808d043c564SKenneth D. Merry }
1809d043c564SKenneth D. Merry
1810d043c564SKenneth D. Merry if ((lun != NULL) && (lun->eedp_formatted)) {
1811be4aa869SKenneth D. Merry req->EEDPBlockSize = htole16(lun->eedp_block_size);
1812d043c564SKenneth D. Merry eedp_flags |= (MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG |
1813d043c564SKenneth D. Merry MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG |
1814d043c564SKenneth D. Merry MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD);
1815be4aa869SKenneth D. Merry req->EEDPFlags = htole16(eedp_flags);
1816d043c564SKenneth D. Merry
1817d043c564SKenneth D. Merry /*
1818d043c564SKenneth D. Merry * If CDB less than 32, fill in Primary Ref Tag with
1819d043c564SKenneth D. Merry * low 4 bytes of LBA. If CDB is 32, tag stuff is
1820d043c564SKenneth D. Merry * already there. Also, set protection bit. FreeBSD
1821d043c564SKenneth D. Merry * currently does not support CDBs bigger than 16, but
1822d043c564SKenneth D. Merry * the code doesn't hurt, and will be here for the
1823d043c564SKenneth D. Merry * future.
1824d043c564SKenneth D. Merry */
1825d043c564SKenneth D. Merry if (csio->cdb_len != 32) {
1826d043c564SKenneth D. Merry lba_byte = (csio->cdb_len == 16) ? 6 : 2;
1827d043c564SKenneth D. Merry ref_tag_addr = (uint8_t *)&req->CDB.EEDP32.
1828d043c564SKenneth D. Merry PrimaryReferenceTag;
1829d043c564SKenneth D. Merry for (i = 0; i < 4; i++) {
1830d043c564SKenneth D. Merry *ref_tag_addr =
1831d043c564SKenneth D. Merry req->CDB.CDB32[lba_byte + i];
1832d043c564SKenneth D. Merry ref_tag_addr++;
1833d043c564SKenneth D. Merry }
1834be4aa869SKenneth D. Merry req->CDB.EEDP32.PrimaryReferenceTag =
1835be4aa869SKenneth D. Merry htole32(req->CDB.EEDP32.PrimaryReferenceTag);
1836d043c564SKenneth D. Merry req->CDB.EEDP32.PrimaryApplicationTagMask =
1837d043c564SKenneth D. Merry 0xFFFF;
1838d043c564SKenneth D. Merry req->CDB.CDB32[1] = (req->CDB.CDB32[1] & 0x1F) |
1839d043c564SKenneth D. Merry 0x20;
1840d043c564SKenneth D. Merry } else {
1841d043c564SKenneth D. Merry eedp_flags |=
1842d043c564SKenneth D. Merry MPI2_SCSIIO_EEDPFLAGS_INC_PRI_APPTAG;
1843be4aa869SKenneth D. Merry req->EEDPFlags = htole16(eedp_flags);
1844d043c564SKenneth D. Merry req->CDB.CDB32[10] = (req->CDB.CDB32[10] &
1845d043c564SKenneth D. Merry 0x1F) | 0x20;
1846d043c564SKenneth D. Merry }
1847d043c564SKenneth D. Merry }
1848d043c564SKenneth D. Merry }
1849d043c564SKenneth D. Merry
1850d3c7b9a0SKenneth D. Merry cm->cm_length = csio->dxfer_len;
1851dd0b4fb6SKonstantin Belousov if (cm->cm_length != 0) {
1852dd0b4fb6SKonstantin Belousov cm->cm_data = ccb;
1853dd0b4fb6SKonstantin Belousov cm->cm_flags |= MPS_CM_FLAGS_USE_CCB;
1854dd0b4fb6SKonstantin Belousov } else {
1855dd0b4fb6SKonstantin Belousov cm->cm_data = NULL;
1856dd0b4fb6SKonstantin Belousov }
1857d3c7b9a0SKenneth D. Merry cm->cm_sge = &req->SGL;
1858d3c7b9a0SKenneth D. Merry cm->cm_sglsize = (32 - 24) * 4;
1859d3c7b9a0SKenneth D. Merry cm->cm_desc.SCSIIO.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO;
1860be4aa869SKenneth D. Merry cm->cm_desc.SCSIIO.DevHandle = htole16(targ->handle);
1861d3c7b9a0SKenneth D. Merry cm->cm_complete = mpssas_scsiio_complete;
1862d3c7b9a0SKenneth D. Merry cm->cm_complete_data = ccb;
1863d3c7b9a0SKenneth D. Merry cm->cm_targ = targ;
1864d043c564SKenneth D. Merry cm->cm_lun = csio->ccb_h.target_lun;
1865d043c564SKenneth D. Merry cm->cm_ccb = ccb;
1866d3c7b9a0SKenneth D. Merry
1867d043c564SKenneth D. Merry /*
1868d043c564SKenneth D. Merry * If HBA is a WD and the command is not for a retry, try to build a
1869d043c564SKenneth D. Merry * direct I/O message. If failed, or the command is for a retry, send
1870d043c564SKenneth D. Merry * the I/O to the IR volume itself.
1871d043c564SKenneth D. Merry */
1872d043c564SKenneth D. Merry if (sc->WD_valid_config) {
18739b6ea4e7SScott Long if (ccb->ccb_h.sim_priv.entries[0].field == MPS_WD_RETRY) {
1874d043c564SKenneth D. Merry mpssas_direct_drive_io(sassc, cm, ccb);
1875d043c564SKenneth D. Merry } else {
1876601781ccSScott Long mpssas_set_ccbstatus(ccb, CAM_REQ_INPROG);
1877d043c564SKenneth D. Merry }
1878d043c564SKenneth D. Merry }
1879550e2acdSKenneth D. Merry
18808532d381SConrad Meyer #if defined(BUF_TRACKING) || defined(FULL_BUF_TRACKING)
18818532d381SConrad Meyer if (csio->bio != NULL)
18828532d381SConrad Meyer biotrack(csio->bio, __func__);
18838532d381SConrad Meyer #endif
18846eea4f46SScott Long csio->ccb_h.qos.sim_data = sbinuptime();
188585c9dd9dSSteven Hartland callout_reset_sbt(&cm->cm_callout, SBT_1MS * ccb->ccb_h.timeout, 0,
188685c9dd9dSSteven Hartland mpssas_scsiio_timeout, cm, 0);
1887d3c7b9a0SKenneth D. Merry
1888d043c564SKenneth D. Merry targ->issued++;
1889d043c564SKenneth D. Merry targ->outstanding++;
1890d043c564SKenneth D. Merry TAILQ_INSERT_TAIL(&targ->commands, cm, cm_link);
18919b91b192SKenneth D. Merry ccb->ccb_h.status |= CAM_SIM_QUEUED;
1892d043c564SKenneth D. Merry
18931610f95cSScott Long mpssas_log_command(cm, MPS_XINFO, "%s cm %p ccb %p outstanding %u\n",
1894d043c564SKenneth D. Merry __func__, cm, ccb, targ->outstanding);
1895d043c564SKenneth D. Merry
1896d3c7b9a0SKenneth D. Merry mps_map_command(sc, cm);
1897d3c7b9a0SKenneth D. Merry return;
1898d3c7b9a0SKenneth D. Merry }
1899d3c7b9a0SKenneth D. Merry
1900653c521fSKenneth D. Merry /**
1901653c521fSKenneth D. Merry * mps_sc_failed_io_info - translated non-succesfull SCSI_IO request
1902653c521fSKenneth D. Merry */
1903653c521fSKenneth D. Merry static void
mps_sc_failed_io_info(struct mps_softc * sc,struct ccb_scsiio * csio,Mpi2SCSIIOReply_t * mpi_reply)1904653c521fSKenneth D. Merry mps_sc_failed_io_info(struct mps_softc *sc, struct ccb_scsiio *csio,
1905653c521fSKenneth D. Merry Mpi2SCSIIOReply_t *mpi_reply)
1906653c521fSKenneth D. Merry {
1907653c521fSKenneth D. Merry u32 response_info;
1908653c521fSKenneth D. Merry u8 *response_bytes;
1909653c521fSKenneth D. Merry u16 ioc_status = le16toh(mpi_reply->IOCStatus) &
1910653c521fSKenneth D. Merry MPI2_IOCSTATUS_MASK;
1911653c521fSKenneth D. Merry u8 scsi_state = mpi_reply->SCSIState;
1912653c521fSKenneth D. Merry u8 scsi_status = mpi_reply->SCSIStatus;
1913653c521fSKenneth D. Merry u32 log_info = le32toh(mpi_reply->IOCLogInfo);
19142bf620cbSScott Long const char *desc_ioc_state, *desc_scsi_status;
1915653c521fSKenneth D. Merry
1916653c521fSKenneth D. Merry if (log_info == 0x31170000)
1917653c521fSKenneth D. Merry return;
1918653c521fSKenneth D. Merry
19192bf620cbSScott Long desc_ioc_state = mps_describe_table(mps_iocstatus_string,
19202bf620cbSScott Long ioc_status);
19212bf620cbSScott Long desc_scsi_status = mps_describe_table(mps_scsi_status_string,
19222bf620cbSScott Long scsi_status);
1923653c521fSKenneth D. Merry
19241610f95cSScott Long mps_dprint(sc, MPS_XINFO, "\thandle(0x%04x), ioc_status(%s)(0x%04x)\n",
19251610f95cSScott Long le16toh(mpi_reply->DevHandle), desc_ioc_state, ioc_status);
19262bf620cbSScott Long
19272bf620cbSScott Long /*
19282bf620cbSScott Long *We can add more detail about underflow data here
1929653c521fSKenneth D. Merry * TO-DO
19302bf620cbSScott Long */
19311610f95cSScott Long mps_dprint(sc, MPS_XINFO, "\tscsi_status(%s)(0x%02x), "
19322bf620cbSScott Long "scsi_state %b\n", desc_scsi_status, scsi_status,
19332bf620cbSScott Long scsi_state, "\20" "\1AutosenseValid" "\2AutosenseFailed"
19342bf620cbSScott Long "\3NoScsiStatus" "\4Terminated" "\5Response InfoValid");
1935653c521fSKenneth D. Merry
19361610f95cSScott Long if (sc->mps_debug & MPS_XINFO &&
1937653c521fSKenneth D. Merry scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID) {
19381610f95cSScott Long mps_dprint(sc, MPS_XINFO, "-> Sense Buffer Data : Start :\n");
1939653c521fSKenneth D. Merry scsi_sense_print(csio);
19401610f95cSScott Long mps_dprint(sc, MPS_XINFO, "-> Sense Buffer Data : End :\n");
1941653c521fSKenneth D. Merry }
1942653c521fSKenneth D. Merry
1943653c521fSKenneth D. Merry if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) {
1944653c521fSKenneth D. Merry response_info = le32toh(mpi_reply->ResponseInfo);
1945653c521fSKenneth D. Merry response_bytes = (u8 *)&response_info;
19462bf620cbSScott Long mps_dprint(sc, MPS_XINFO, "response code(0x%1x): %s\n",
19472bf620cbSScott Long response_bytes[0],
19482bf620cbSScott Long mps_describe_table(mps_scsi_taskmgmt_string,
19492bf620cbSScott Long response_bytes[0]));
1950653c521fSKenneth D. Merry }
1951653c521fSKenneth D. Merry }
1952653c521fSKenneth D. Merry
1953653c521fSKenneth D. Merry static void
mpssas_scsiio_complete(struct mps_softc * sc,struct mps_command * cm)1954d3c7b9a0SKenneth D. Merry mpssas_scsiio_complete(struct mps_softc *sc, struct mps_command *cm)
1955d3c7b9a0SKenneth D. Merry {
1956d3c7b9a0SKenneth D. Merry MPI2_SCSI_IO_REPLY *rep;
1957d3c7b9a0SKenneth D. Merry union ccb *ccb;
1958d043c564SKenneth D. Merry struct ccb_scsiio *csio;
1959d3c7b9a0SKenneth D. Merry struct mpssas_softc *sassc;
1960d043c564SKenneth D. Merry struct scsi_vpd_supported_page_list *vpd_list = NULL;
1961d043c564SKenneth D. Merry u8 *TLR_bits, TLR_on;
1962d043c564SKenneth D. Merry int dir = 0, i;
1963d043c564SKenneth D. Merry u16 alloc_len;
1964ef065d89SStephen McConnell struct mpssas_target *target;
1965ef065d89SStephen McConnell target_id_t target_id;
1966d3c7b9a0SKenneth D. Merry
19671610f95cSScott Long MPS_FUNCTRACE(sc);
1968d043c564SKenneth D. Merry mps_dprint(sc, MPS_TRACE,
19691610f95cSScott Long "cm %p SMID %u ccb %p reply %p outstanding %u\n", cm,
19701610f95cSScott Long cm->cm_desc.Default.SMID, cm->cm_ccb, cm->cm_reply,
1971d043c564SKenneth D. Merry cm->cm_targ->outstanding);
1972d3c7b9a0SKenneth D. Merry
1973d3c7b9a0SKenneth D. Merry callout_stop(&cm->cm_callout);
1974d043c564SKenneth D. Merry mtx_assert(&sc->mps_mtx, MA_OWNED);
1975d3c7b9a0SKenneth D. Merry
1976d3c7b9a0SKenneth D. Merry sassc = sc->sassc;
1977d3c7b9a0SKenneth D. Merry ccb = cm->cm_complete_data;
1978d043c564SKenneth D. Merry csio = &ccb->csio;
1979ef065d89SStephen McConnell target_id = csio->ccb_h.target_id;
1980d3c7b9a0SKenneth D. Merry rep = (MPI2_SCSI_IO_REPLY *)cm->cm_reply;
1981550e2acdSKenneth D. Merry /*
1982550e2acdSKenneth D. Merry * XXX KDM if the chain allocation fails, does it matter if we do
1983550e2acdSKenneth D. Merry * the sync and unload here? It is simpler to do it in every case,
1984550e2acdSKenneth D. Merry * assuming it doesn't cause problems.
1985550e2acdSKenneth D. Merry */
1986d3c7b9a0SKenneth D. Merry if (cm->cm_data != NULL) {
1987d3c7b9a0SKenneth D. Merry if (cm->cm_flags & MPS_CM_FLAGS_DATAIN)
1988d3c7b9a0SKenneth D. Merry dir = BUS_DMASYNC_POSTREAD;
1989d3c7b9a0SKenneth D. Merry else if (cm->cm_flags & MPS_CM_FLAGS_DATAOUT)
1990db702c59SEitan Adler dir = BUS_DMASYNC_POSTWRITE;
1991d3c7b9a0SKenneth D. Merry bus_dmamap_sync(sc->buffer_dmat, cm->cm_dmamap, dir);
1992d3c7b9a0SKenneth D. Merry bus_dmamap_unload(sc->buffer_dmat, cm->cm_dmamap);
1993d3c7b9a0SKenneth D. Merry }
1994d3c7b9a0SKenneth D. Merry
1995d043c564SKenneth D. Merry cm->cm_targ->completed++;
1996d043c564SKenneth D. Merry cm->cm_targ->outstanding--;
1997d043c564SKenneth D. Merry TAILQ_REMOVE(&cm->cm_targ->commands, cm, cm_link);
1998ec99409eSKenneth D. Merry ccb->ccb_h.status &= ~(CAM_STATUS_MASK | CAM_SIM_QUEUED);
1999d043c564SKenneth D. Merry
20008532d381SConrad Meyer #if defined(BUF_TRACKING) || defined(FULL_BUF_TRACKING)
20018532d381SConrad Meyer if (ccb->csio.bio != NULL)
20028532d381SConrad Meyer biotrack(ccb->csio.bio, __func__);
20038532d381SConrad Meyer #endif
20048532d381SConrad Meyer
20058fe7bf06SWarner Losh if (cm->cm_flags & MPS_CM_FLAGS_ON_RECOVERY) {
2006d043c564SKenneth D. Merry TAILQ_REMOVE(&cm->cm_targ->timedout_commands, cm, cm_recovery);
20078fe7bf06SWarner Losh KASSERT(cm->cm_state == MPS_CM_STATE_BUSY,
2008175ad3d0SKenneth D. Merry ("Not busy for CM_FLAGS_TIMEDOUT: %u\n", cm->cm_state));
20098fe7bf06SWarner Losh cm->cm_flags &= ~MPS_CM_FLAGS_ON_RECOVERY;
2010d043c564SKenneth D. Merry if (cm->cm_reply != NULL)
20111610f95cSScott Long mpssas_log_command(cm, MPS_RECOVERY,
2012d043c564SKenneth D. Merry "completed timedout cm %p ccb %p during recovery "
2013d043c564SKenneth D. Merry "ioc %x scsi %x state %x xfer %u\n",
2014f0779b04SScott Long cm, cm->cm_ccb, le16toh(rep->IOCStatus),
2015f0779b04SScott Long rep->SCSIStatus, rep->SCSIState,
2016be4aa869SKenneth D. Merry le32toh(rep->TransferCount));
2017d043c564SKenneth D. Merry else
20181610f95cSScott Long mpssas_log_command(cm, MPS_RECOVERY,
2019d043c564SKenneth D. Merry "completed timedout cm %p ccb %p during recovery\n",
2020d043c564SKenneth D. Merry cm, cm->cm_ccb);
2021d043c564SKenneth D. Merry } else if (cm->cm_targ->tm != NULL) {
2022d043c564SKenneth D. Merry if (cm->cm_reply != NULL)
20231610f95cSScott Long mpssas_log_command(cm, MPS_RECOVERY,
2024d043c564SKenneth D. Merry "completed cm %p ccb %p during recovery "
2025d043c564SKenneth D. Merry "ioc %x scsi %x state %x xfer %u\n",
2026f0779b04SScott Long cm, cm->cm_ccb, le16toh(rep->IOCStatus),
2027f0779b04SScott Long rep->SCSIStatus, rep->SCSIState,
2028be4aa869SKenneth D. Merry le32toh(rep->TransferCount));
2029d043c564SKenneth D. Merry else
20301610f95cSScott Long mpssas_log_command(cm, MPS_RECOVERY,
2031d043c564SKenneth D. Merry "completed cm %p ccb %p during recovery\n",
2032d043c564SKenneth D. Merry cm, cm->cm_ccb);
2033d043c564SKenneth D. Merry } else if ((sc->mps_flags & MPS_FLAGS_DIAGRESET) != 0) {
20341610f95cSScott Long mpssas_log_command(cm, MPS_RECOVERY,
2035d043c564SKenneth D. Merry "reset completed cm %p ccb %p\n",
2036d043c564SKenneth D. Merry cm, cm->cm_ccb);
2037d043c564SKenneth D. Merry }
2038d043c564SKenneth D. Merry
2039550e2acdSKenneth D. Merry if ((cm->cm_flags & MPS_CM_FLAGS_ERROR_MASK) != 0) {
2040550e2acdSKenneth D. Merry /*
2041550e2acdSKenneth D. Merry * We ran into an error after we tried to map the command,
2042550e2acdSKenneth D. Merry * so we're getting a callback without queueing the command
2043550e2acdSKenneth D. Merry * to the hardware. So we set the status here, and it will
2044550e2acdSKenneth D. Merry * be retained below. We'll go through the "fast path",
2045550e2acdSKenneth D. Merry * because there can be no reply when we haven't actually
2046550e2acdSKenneth D. Merry * gone out to the hardware.
2047550e2acdSKenneth D. Merry */
2048601781ccSScott Long mpssas_set_ccbstatus(ccb, CAM_REQUEUE_REQ);
2049550e2acdSKenneth D. Merry
2050550e2acdSKenneth D. Merry /*
2051550e2acdSKenneth D. Merry * Currently the only error included in the mask is
2052550e2acdSKenneth D. Merry * MPS_CM_FLAGS_CHAIN_FAILED, which means we're out of
2053550e2acdSKenneth D. Merry * chain frames. We need to freeze the queue until we get
2054550e2acdSKenneth D. Merry * a command that completed without this error, which will
2055550e2acdSKenneth D. Merry * hopefully have some chain frames attached that we can
2056550e2acdSKenneth D. Merry * use. If we wanted to get smarter about it, we would
2057550e2acdSKenneth D. Merry * only unfreeze the queue in this condition when we're
2058550e2acdSKenneth D. Merry * sure that we're getting some chain frames back. That's
2059550e2acdSKenneth D. Merry * probably unnecessary.
2060550e2acdSKenneth D. Merry */
2061550e2acdSKenneth D. Merry if ((sassc->flags & MPSSAS_QUEUE_FROZEN) == 0) {
2062550e2acdSKenneth D. Merry xpt_freeze_simq(sassc->sim, 1);
2063550e2acdSKenneth D. Merry sassc->flags |= MPSSAS_QUEUE_FROZEN;
20641610f95cSScott Long mps_dprint(sc, MPS_XINFO, "Error sending command, "
2065750ffe84SKenneth D. Merry "freezing SIM queue\n");
2066550e2acdSKenneth D. Merry }
2067d3c7b9a0SKenneth D. Merry }
2068d3c7b9a0SKenneth D. Merry
20697571e7f6SSteven Hartland /*
20707571e7f6SSteven Hartland * If this is a Start Stop Unit command and it was issued by the driver
20717571e7f6SSteven Hartland * during shutdown, decrement the refcount to account for all of the
20727571e7f6SSteven Hartland * commands that were sent. All SSU commands should be completed before
20737571e7f6SSteven Hartland * shutdown completes, meaning SSU_refcount will be 0 after SSU_started
20747571e7f6SSteven Hartland * is TRUE.
20757571e7f6SSteven Hartland */
20767571e7f6SSteven Hartland if (sc->SSU_started && (csio->cdb_io.cdb_bytes[0] == START_STOP_UNIT)) {
20777571e7f6SSteven Hartland mps_dprint(sc, MPS_INFO, "Decrementing SSU count.\n");
20787571e7f6SSteven Hartland sc->SSU_refcount--;
20797571e7f6SSteven Hartland }
20807571e7f6SSteven Hartland
2081d3c7b9a0SKenneth D. Merry /* Take the fast path to completion */
2082d3c7b9a0SKenneth D. Merry if (cm->cm_reply == NULL) {
2083601781ccSScott Long if (mpssas_get_ccbstatus(ccb) == CAM_REQ_INPROG) {
2084d043c564SKenneth D. Merry if ((sc->mps_flags & MPS_FLAGS_DIAGRESET) != 0)
2085601781ccSScott Long mpssas_set_ccbstatus(ccb, CAM_SCSI_BUS_RESET);
2086d043c564SKenneth D. Merry else {
2087601781ccSScott Long mpssas_set_ccbstatus(ccb, CAM_REQ_CMP);
2088d3c7b9a0SKenneth D. Merry ccb->csio.scsi_status = SCSI_STATUS_OK;
2089d043c564SKenneth D. Merry }
2090550e2acdSKenneth D. Merry if (sassc->flags & MPSSAS_QUEUE_FROZEN) {
2091550e2acdSKenneth D. Merry ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
2092550e2acdSKenneth D. Merry sassc->flags &= ~MPSSAS_QUEUE_FROZEN;
20931610f95cSScott Long mps_dprint(sc, MPS_XINFO,
2094750ffe84SKenneth D. Merry "Unfreezing SIM queue\n");
2095550e2acdSKenneth D. Merry }
2096d043c564SKenneth D. Merry }
2097d043c564SKenneth D. Merry
2098d043c564SKenneth D. Merry /*
2099d043c564SKenneth D. Merry * There are two scenarios where the status won't be
2100d043c564SKenneth D. Merry * CAM_REQ_CMP. The first is if MPS_CM_FLAGS_ERROR_MASK is
2101d043c564SKenneth D. Merry * set, the second is in the MPS_FLAGS_DIAGRESET above.
2102d043c564SKenneth D. Merry */
2103601781ccSScott Long if (mpssas_get_ccbstatus(ccb) != CAM_REQ_CMP) {
2104d043c564SKenneth D. Merry /*
2105d043c564SKenneth D. Merry * Freeze the dev queue so that commands are
2106601781ccSScott Long * executed in the correct order after error
2107d043c564SKenneth D. Merry * recovery.
2108d043c564SKenneth D. Merry */
2109550e2acdSKenneth D. Merry ccb->ccb_h.status |= CAM_DEV_QFRZN;
2110550e2acdSKenneth D. Merry xpt_freeze_devq(ccb->ccb_h.path, /*count*/ 1);
21119866848aSKenneth D. Merry }
2112d3c7b9a0SKenneth D. Merry mps_free_command(sc, cm);
2113d3c7b9a0SKenneth D. Merry xpt_done(ccb);
2114d3c7b9a0SKenneth D. Merry return;
2115d3c7b9a0SKenneth D. Merry }
2116d3c7b9a0SKenneth D. Merry
21171610f95cSScott Long mpssas_log_command(cm, MPS_XINFO,
2118d043c564SKenneth D. Merry "ioc %x scsi %x state %x xfer %u\n",
2119be4aa869SKenneth D. Merry le16toh(rep->IOCStatus), rep->SCSIStatus, rep->SCSIState,
2120be4aa869SKenneth D. Merry le32toh(rep->TransferCount));
2121d043c564SKenneth D. Merry
2122d043c564SKenneth D. Merry /*
2123d043c564SKenneth D. Merry * If this is a Direct Drive I/O, reissue the I/O to the original IR
2124d043c564SKenneth D. Merry * Volume if an error occurred (normal I/O retry). Use the original
2125d043c564SKenneth D. Merry * CCB, but set a flag that this will be a retry so that it's sent to
2126d043c564SKenneth D. Merry * the original volume. Free the command but reuse the CCB.
2127d043c564SKenneth D. Merry */
2128d043c564SKenneth D. Merry if (cm->cm_flags & MPS_CM_FLAGS_DD_IO) {
2129d043c564SKenneth D. Merry mps_free_command(sc, cm);
21309b6ea4e7SScott Long ccb->ccb_h.sim_priv.entries[0].field = MPS_WD_RETRY;
2131d043c564SKenneth D. Merry mpssas_action_scsiio(sassc, ccb);
2132d043c564SKenneth D. Merry return;
21339b6ea4e7SScott Long } else
21349b6ea4e7SScott Long ccb->ccb_h.sim_priv.entries[0].field = 0;
2135d3c7b9a0SKenneth D. Merry
2136be4aa869SKenneth D. Merry switch (le16toh(rep->IOCStatus) & MPI2_IOCSTATUS_MASK) {
2137d3c7b9a0SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN:
2138be4aa869SKenneth D. Merry csio->resid = cm->cm_length - le32toh(rep->TransferCount);
2139d3c7b9a0SKenneth D. Merry /* FALLTHROUGH */
2140d3c7b9a0SKenneth D. Merry case MPI2_IOCSTATUS_SUCCESS:
2141d3c7b9a0SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR:
2142d043c564SKenneth D. Merry
2143be4aa869SKenneth D. Merry if ((le16toh(rep->IOCStatus) & MPI2_IOCSTATUS_MASK) ==
2144d043c564SKenneth D. Merry MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR)
21451610f95cSScott Long mpssas_log_command(cm, MPS_XINFO, "recovered error\n");
2146d043c564SKenneth D. Merry
2147d043c564SKenneth D. Merry /* Completion failed at the transport level. */
2148d043c564SKenneth D. Merry if (rep->SCSIState & (MPI2_SCSI_STATE_NO_SCSI_STATUS |
2149d043c564SKenneth D. Merry MPI2_SCSI_STATE_TERMINATED)) {
2150601781ccSScott Long mpssas_set_ccbstatus(ccb, CAM_REQ_CMP_ERR);
2151d3c7b9a0SKenneth D. Merry break;
2152d043c564SKenneth D. Merry }
2153d043c564SKenneth D. Merry
2154d043c564SKenneth D. Merry /* In a modern packetized environment, an autosense failure
2155d043c564SKenneth D. Merry * implies that there's not much else that can be done to
2156d043c564SKenneth D. Merry * recover the command.
2157d043c564SKenneth D. Merry */
2158d043c564SKenneth D. Merry if (rep->SCSIState & MPI2_SCSI_STATE_AUTOSENSE_FAILED) {
2159601781ccSScott Long mpssas_set_ccbstatus(ccb, CAM_AUTOSENSE_FAIL);
2160d043c564SKenneth D. Merry break;
2161d043c564SKenneth D. Merry }
2162d043c564SKenneth D. Merry
2163d043c564SKenneth D. Merry /*
2164d043c564SKenneth D. Merry * CAM doesn't care about SAS Response Info data, but if this is
2165d043c564SKenneth D. Merry * the state check if TLR should be done. If not, clear the
2166d043c564SKenneth D. Merry * TLR_bits for the target.
2167d043c564SKenneth D. Merry */
2168d043c564SKenneth D. Merry if ((rep->SCSIState & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) &&
2169ef065d89SStephen McConnell ((le32toh(rep->ResponseInfo) &
2170ef065d89SStephen McConnell MPI2_SCSI_RI_MASK_REASONCODE) ==
2171d043c564SKenneth D. Merry MPS_SCSI_RI_INVALID_FRAME)) {
2172ef065d89SStephen McConnell sc->mapping_table[target_id].TLR_bits =
2173d043c564SKenneth D. Merry (u8)MPI2_SCSIIO_CONTROL_NO_TLR;
2174d043c564SKenneth D. Merry }
2175d043c564SKenneth D. Merry
2176d043c564SKenneth D. Merry /*
2177d043c564SKenneth D. Merry * Intentionally override the normal SCSI status reporting
2178d043c564SKenneth D. Merry * for these two cases. These are likely to happen in a
2179d043c564SKenneth D. Merry * multi-initiator environment, and we want to make sure that
2180d043c564SKenneth D. Merry * CAM retries these commands rather than fail them.
2181d043c564SKenneth D. Merry */
2182d043c564SKenneth D. Merry if ((rep->SCSIStatus == MPI2_SCSI_STATUS_COMMAND_TERMINATED) ||
2183d043c564SKenneth D. Merry (rep->SCSIStatus == MPI2_SCSI_STATUS_TASK_ABORTED)) {
2184601781ccSScott Long mpssas_set_ccbstatus(ccb, CAM_REQ_ABORTED);
2185d043c564SKenneth D. Merry break;
2186d043c564SKenneth D. Merry }
2187d043c564SKenneth D. Merry
2188d043c564SKenneth D. Merry /* Handle normal status and sense */
2189d043c564SKenneth D. Merry csio->scsi_status = rep->SCSIStatus;
2190d043c564SKenneth D. Merry if (rep->SCSIStatus == MPI2_SCSI_STATUS_GOOD)
2191601781ccSScott Long mpssas_set_ccbstatus(ccb, CAM_REQ_CMP);
2192d043c564SKenneth D. Merry else
2193601781ccSScott Long mpssas_set_ccbstatus(ccb, CAM_SCSI_STATUS_ERROR);
2194d043c564SKenneth D. Merry
2195d043c564SKenneth D. Merry if (rep->SCSIState & MPI2_SCSI_STATE_AUTOSENSE_VALID) {
2196d043c564SKenneth D. Merry int sense_len, returned_sense_len;
2197d043c564SKenneth D. Merry
2198be4aa869SKenneth D. Merry returned_sense_len = min(le32toh(rep->SenseCount),
2199d043c564SKenneth D. Merry sizeof(struct scsi_sense_data));
2200d043c564SKenneth D. Merry if (returned_sense_len < ccb->csio.sense_len)
2201d043c564SKenneth D. Merry ccb->csio.sense_resid = ccb->csio.sense_len -
2202d043c564SKenneth D. Merry returned_sense_len;
2203d043c564SKenneth D. Merry else
2204d043c564SKenneth D. Merry ccb->csio.sense_resid = 0;
2205d043c564SKenneth D. Merry
2206d043c564SKenneth D. Merry sense_len = min(returned_sense_len,
2207d043c564SKenneth D. Merry ccb->csio.sense_len - ccb->csio.sense_resid);
2208d043c564SKenneth D. Merry bzero(&ccb->csio.sense_data,
2209c61325d0SKevin Lo sizeof(ccb->csio.sense_data));
2210d043c564SKenneth D. Merry bcopy(cm->cm_sense, &ccb->csio.sense_data, sense_len);
2211d043c564SKenneth D. Merry ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
2212d043c564SKenneth D. Merry }
2213d043c564SKenneth D. Merry
2214d043c564SKenneth D. Merry /*
2215d043c564SKenneth D. Merry * Check if this is an INQUIRY command. If it's a VPD inquiry,
2216d043c564SKenneth D. Merry * and it's page code 0 (Supported Page List), and there is
2217d043c564SKenneth D. Merry * inquiry data, and this is for a sequential access device, and
2218d043c564SKenneth D. Merry * the device is an SSP target, and TLR is supported by the
2219d043c564SKenneth D. Merry * controller, turn the TLR_bits value ON if page 0x90 is
2220d043c564SKenneth D. Merry * supported.
2221d043c564SKenneth D. Merry */
2222d043c564SKenneth D. Merry if ((csio->cdb_io.cdb_bytes[0] == INQUIRY) &&
2223d043c564SKenneth D. Merry (csio->cdb_io.cdb_bytes[1] & SI_EVPD) &&
2224d043c564SKenneth D. Merry (csio->cdb_io.cdb_bytes[2] == SVPD_SUPPORTED_PAGE_LIST) &&
222547bf7bcbSAlexander Motin ((csio->ccb_h.flags & CAM_DATA_MASK) == CAM_DATA_VADDR) &&
2226d2b4e18bSKenneth D. Merry (csio->data_ptr != NULL) &&
2227d2b4e18bSKenneth D. Merry ((csio->data_ptr[0] & 0x1f) == T_SEQUENTIAL) &&
2228d2b4e18bSKenneth D. Merry (sc->control_TLR) &&
2229ef065d89SStephen McConnell (sc->mapping_table[target_id].device_info &
2230d043c564SKenneth D. Merry MPI2_SAS_DEVICE_INFO_SSP_TARGET)) {
2231d043c564SKenneth D. Merry vpd_list = (struct scsi_vpd_supported_page_list *)
2232d043c564SKenneth D. Merry csio->data_ptr;
2233ef065d89SStephen McConnell TLR_bits = &sc->mapping_table[target_id].TLR_bits;
2234d043c564SKenneth D. Merry *TLR_bits = (u8)MPI2_SCSIIO_CONTROL_NO_TLR;
2235d043c564SKenneth D. Merry TLR_on = (u8)MPI2_SCSIIO_CONTROL_TLR_ON;
2236d043c564SKenneth D. Merry alloc_len = ((u16)csio->cdb_io.cdb_bytes[3] << 8) +
2237d043c564SKenneth D. Merry csio->cdb_io.cdb_bytes[4];
2238d2b4e18bSKenneth D. Merry alloc_len -= csio->resid;
2239d043c564SKenneth D. Merry for (i = 0; i < MIN(vpd_list->length, alloc_len); i++) {
2240d043c564SKenneth D. Merry if (vpd_list->list[i] == 0x90) {
2241d043c564SKenneth D. Merry *TLR_bits = TLR_on;
2242d043c564SKenneth D. Merry break;
2243d043c564SKenneth D. Merry }
2244d043c564SKenneth D. Merry }
2245d043c564SKenneth D. Merry }
2246ef065d89SStephen McConnell
2247ef065d89SStephen McConnell /*
2248ef065d89SStephen McConnell * If this is a SATA direct-access end device, mark it so that
2249ef065d89SStephen McConnell * a SCSI StartStopUnit command will be sent to it when the
2250ef065d89SStephen McConnell * driver is being shutdown.
2251ef065d89SStephen McConnell */
2252ef065d89SStephen McConnell if ((csio->cdb_io.cdb_bytes[0] == INQUIRY) &&
2253ef065d89SStephen McConnell ((csio->data_ptr[0] & 0x1f) == T_DIRECT) &&
2254ef065d89SStephen McConnell (sc->mapping_table[target_id].device_info &
2255ef065d89SStephen McConnell MPI2_SAS_DEVICE_INFO_SATA_DEVICE) &&
2256ef065d89SStephen McConnell ((sc->mapping_table[target_id].device_info &
2257ef065d89SStephen McConnell MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) ==
2258ef065d89SStephen McConnell MPI2_SAS_DEVICE_INFO_END_DEVICE)) {
2259ef065d89SStephen McConnell target = &sassc->targets[target_id];
2260ef065d89SStephen McConnell target->supports_SSU = TRUE;
2261ef065d89SStephen McConnell mps_dprint(sc, MPS_XINFO, "Target %d supports SSU\n",
2262ef065d89SStephen McConnell target_id);
2263ef065d89SStephen McConnell }
2264d3c7b9a0SKenneth D. Merry break;
2265d3c7b9a0SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_INVALID_DEVHANDLE:
2266d3c7b9a0SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
2267d043c564SKenneth D. Merry /*
2268d043c564SKenneth D. Merry * If devinfo is 0 this will be a volume. In that case don't
2269d043c564SKenneth D. Merry * tell CAM that the volume is not there. We want volumes to
2270d043c564SKenneth D. Merry * be enumerated until they are deleted/removed, not just
2271d043c564SKenneth D. Merry * failed.
2272d043c564SKenneth D. Merry */
2273d043c564SKenneth D. Merry if (cm->cm_targ->devinfo == 0)
2274601781ccSScott Long mpssas_set_ccbstatus(ccb, CAM_REQ_CMP);
2275d043c564SKenneth D. Merry else
2276601781ccSScott Long mpssas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE);
2277d3c7b9a0SKenneth D. Merry break;
2278d043c564SKenneth D. Merry case MPI2_IOCSTATUS_INVALID_SGL:
2279d043c564SKenneth D. Merry mps_print_scsiio_cmd(sc, cm);
2280601781ccSScott Long mpssas_set_ccbstatus(ccb, CAM_UNREC_HBA_ERROR);
2281d043c564SKenneth D. Merry break;
2282d3c7b9a0SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED:
2283d3c7b9a0SKenneth D. Merry /*
2284d3c7b9a0SKenneth D. Merry * This is one of the responses that comes back when an I/O
2285d3c7b9a0SKenneth D. Merry * has been aborted. If it is because of a timeout that we
2286d3c7b9a0SKenneth D. Merry * initiated, just set the status to CAM_CMD_TIMEOUT.
2287d3c7b9a0SKenneth D. Merry * Otherwise set it to CAM_REQ_ABORTED. The effect on the
2288d3c7b9a0SKenneth D. Merry * command is the same (it gets retried, subject to the
2289d3c7b9a0SKenneth D. Merry * retry counter), the only difference is what gets printed
2290d3c7b9a0SKenneth D. Merry * on the console.
2291d3c7b9a0SKenneth D. Merry */
22928fe7bf06SWarner Losh if (cm->cm_flags & MPS_CM_FLAGS_TIMEDOUT)
2293601781ccSScott Long mpssas_set_ccbstatus(ccb, CAM_CMD_TIMEOUT);
2294d3c7b9a0SKenneth D. Merry else
2295601781ccSScott Long mpssas_set_ccbstatus(ccb, CAM_REQ_ABORTED);
2296d3c7b9a0SKenneth D. Merry break;
2297d043c564SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN:
2298d043c564SKenneth D. Merry /* resid is ignored for this condition */
2299d043c564SKenneth D. Merry csio->resid = 0;
2300601781ccSScott Long mpssas_set_ccbstatus(ccb, CAM_DATA_RUN_ERR);
2301d043c564SKenneth D. Merry break;
2302d3c7b9a0SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED:
2303d3c7b9a0SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED:
2304d043c564SKenneth D. Merry /*
23056adfa7edSAlan Somers * These can sometimes be transient transport-related
23066adfa7edSAlan Somers * errors, and sometimes persistent drive-related errors.
23076adfa7edSAlan Somers * We used to retry these without decrementing the retry
23086adfa7edSAlan Somers * count by returning CAM_REQUEUE_REQ. Unfortunately, if
23096adfa7edSAlan Somers * we hit a persistent drive problem that returns one of
23106adfa7edSAlan Somers * these error codes, we would retry indefinitely. So,
23116adfa7edSAlan Somers * return CAM_REQ_CMP_ERROR so that we decrement the retry
23126adfa7edSAlan Somers * count and avoid infinite retries. We're taking the
23136adfa7edSAlan Somers * potential risk of flagging false failures in the event
23146adfa7edSAlan Somers * of a topology-related error (e.g. a SAS expander problem
23156adfa7edSAlan Somers * causes a command addressed to a drive to fail), but
23164c1cdd4aSWarner Losh * avoiding getting into an infinite retry loop. However,
23174c1cdd4aSWarner Losh * if we get them while were moving a device, we should
23184c1cdd4aSWarner Losh * fail the request as 'not there' because the device
23194c1cdd4aSWarner Losh * is effectively gone.
2320d043c564SKenneth D. Merry */
23214c1cdd4aSWarner Losh if (cm->cm_targ->flags & MPSSAS_TARGET_INREMOVAL)
23224c1cdd4aSWarner Losh mpssas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE);
23234c1cdd4aSWarner Losh else
23246adfa7edSAlan Somers mpssas_set_ccbstatus(ccb, CAM_REQ_CMP_ERR);
23256eea4f46SScott Long mps_dprint(sc, MPS_INFO,
23264c1cdd4aSWarner Losh "Controller reported %s tgt %u SMID %u loginfo %x%s\n",
23272bf620cbSScott Long mps_describe_table(mps_iocstatus_string,
23282bf620cbSScott Long le16toh(rep->IOCStatus) & MPI2_IOCSTATUS_MASK),
23292bf620cbSScott Long target_id, cm->cm_desc.Default.SMID,
23304c1cdd4aSWarner Losh le32toh(rep->IOCLogInfo),
23314c1cdd4aSWarner Losh (cm->cm_targ->flags & MPSSAS_TARGET_INREMOVAL) ? " departing" : "");
23326eea4f46SScott Long mps_dprint(sc, MPS_XINFO,
23336eea4f46SScott Long "SCSIStatus %x SCSIState %x xfercount %u\n",
2334694cb8b8SScott Long rep->SCSIStatus, rep->SCSIState,
2335be4aa869SKenneth D. Merry le32toh(rep->TransferCount));
2336d3c7b9a0SKenneth D. Merry break;
2337d3c7b9a0SKenneth D. Merry case MPI2_IOCSTATUS_INVALID_FUNCTION:
2338d3c7b9a0SKenneth D. Merry case MPI2_IOCSTATUS_INTERNAL_ERROR:
2339d3c7b9a0SKenneth D. Merry case MPI2_IOCSTATUS_INVALID_VPID:
2340d3c7b9a0SKenneth D. Merry case MPI2_IOCSTATUS_INVALID_FIELD:
2341d3c7b9a0SKenneth D. Merry case MPI2_IOCSTATUS_INVALID_STATE:
2342d3c7b9a0SKenneth D. Merry case MPI2_IOCSTATUS_OP_STATE_NOT_SUPPORTED:
2343d3c7b9a0SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR:
2344d3c7b9a0SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR:
2345d3c7b9a0SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
2346d3c7b9a0SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
2347d3c7b9a0SKenneth D. Merry default:
23481610f95cSScott Long mpssas_log_command(cm, MPS_XINFO,
2349694cb8b8SScott Long "completed ioc %x loginfo %x scsi %x state %x xfer %u\n",
2350694cb8b8SScott Long le16toh(rep->IOCStatus), le32toh(rep->IOCLogInfo),
2351694cb8b8SScott Long rep->SCSIStatus, rep->SCSIState,
2352be4aa869SKenneth D. Merry le32toh(rep->TransferCount));
2353d043c564SKenneth D. Merry csio->resid = cm->cm_length;
2354601781ccSScott Long mpssas_set_ccbstatus(ccb, CAM_REQ_CMP_ERR);
2355d3c7b9a0SKenneth D. Merry break;
2356d3c7b9a0SKenneth D. Merry }
2357d3c7b9a0SKenneth D. Merry
2358653c521fSKenneth D. Merry mps_sc_failed_io_info(sc,csio,rep);
2359653c521fSKenneth D. Merry
2360550e2acdSKenneth D. Merry if (sassc->flags & MPSSAS_QUEUE_FROZEN) {
2361550e2acdSKenneth D. Merry ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
2362550e2acdSKenneth D. Merry sassc->flags &= ~MPSSAS_QUEUE_FROZEN;
23631610f95cSScott Long mps_dprint(sc, MPS_XINFO, "Command completed, "
2364d043c564SKenneth D. Merry "unfreezing SIM queue\n");
2365550e2acdSKenneth D. Merry }
2366d043c564SKenneth D. Merry
2367601781ccSScott Long if (mpssas_get_ccbstatus(ccb) != CAM_REQ_CMP) {
2368550e2acdSKenneth D. Merry ccb->ccb_h.status |= CAM_DEV_QFRZN;
2369550e2acdSKenneth D. Merry xpt_freeze_devq(ccb->ccb_h.path, /*count*/ 1);
2370550e2acdSKenneth D. Merry }
2371d043c564SKenneth D. Merry
23724c1cdd4aSWarner Losh /*
23734c1cdd4aSWarner Losh * Check to see if we're removing the device. If so, and this is the
23744c1cdd4aSWarner Losh * last command on the queue, proceed with the deferred removal of the
23754c1cdd4aSWarner Losh * device. Note, for removing a volume, this won't trigger because
23764c1cdd4aSWarner Losh * pending_remove_tm will be NULL.
23774c1cdd4aSWarner Losh */
23784c1cdd4aSWarner Losh if (cm->cm_targ->flags & MPSSAS_TARGET_INREMOVAL) {
23794c1cdd4aSWarner Losh if (TAILQ_FIRST(&cm->cm_targ->commands) == NULL &&
23804c1cdd4aSWarner Losh cm->cm_targ->pending_remove_tm != NULL) {
2381ca420b4eSWarner Losh mps_dprint(sc, MPS_INFO,
2382ca420b4eSWarner Losh "Last pending command complete: starting remove_device target %u handle 0x%04x\n",
2383ca420b4eSWarner Losh cm->cm_targ->tid, cm->cm_targ->handle);
23844c1cdd4aSWarner Losh mps_map_command(sc, cm->cm_targ->pending_remove_tm);
23854c1cdd4aSWarner Losh cm->cm_targ->pending_remove_tm = NULL;
23864c1cdd4aSWarner Losh }
23874c1cdd4aSWarner Losh }
23884c1cdd4aSWarner Losh
2389d3c7b9a0SKenneth D. Merry mps_free_command(sc, cm);
2390d3c7b9a0SKenneth D. Merry xpt_done(ccb);
2391d3c7b9a0SKenneth D. Merry }
2392d3c7b9a0SKenneth D. Merry
2393be4aa869SKenneth D. Merry /* All Request reached here are Endian safe */
2394d043c564SKenneth D. Merry static void
mpssas_direct_drive_io(struct mpssas_softc * sassc,struct mps_command * cm,union ccb * ccb)2395d043c564SKenneth D. Merry mpssas_direct_drive_io(struct mpssas_softc *sassc, struct mps_command *cm,
2396d043c564SKenneth D. Merry union ccb *ccb) {
2397d043c564SKenneth D. Merry pMpi2SCSIIORequest_t pIO_req;
2398d043c564SKenneth D. Merry struct mps_softc *sc = sassc->sc;
2399d043c564SKenneth D. Merry uint64_t virtLBA;
2400d043c564SKenneth D. Merry uint32_t physLBA, stripe_offset, stripe_unit;
2401d043c564SKenneth D. Merry uint32_t io_size, column;
2402d043c564SKenneth D. Merry uint8_t *ptrLBA, lba_idx, physLBA_byte, *CDB;
2403d043c564SKenneth D. Merry
2404d043c564SKenneth D. Merry /*
2405d043c564SKenneth D. Merry * If this is a valid SCSI command (Read6, Read10, Read16, Write6,
2406d043c564SKenneth D. Merry * Write10, or Write16), build a direct I/O message. Otherwise, the I/O
2407d043c564SKenneth D. Merry * will be sent to the IR volume itself. Since Read6 and Write6 are a
2408d043c564SKenneth D. Merry * bit different than the 10/16 CDBs, handle them separately.
2409d043c564SKenneth D. Merry */
2410d043c564SKenneth D. Merry pIO_req = (pMpi2SCSIIORequest_t)cm->cm_req;
2411d043c564SKenneth D. Merry CDB = pIO_req->CDB.CDB32;
2412d043c564SKenneth D. Merry
2413d043c564SKenneth D. Merry /*
2414d043c564SKenneth D. Merry * Handle 6 byte CDBs.
2415d043c564SKenneth D. Merry */
2416d043c564SKenneth D. Merry if ((pIO_req->DevHandle == sc->DD_dev_handle) && ((CDB[0] == READ_6) ||
2417d043c564SKenneth D. Merry (CDB[0] == WRITE_6))) {
2418d043c564SKenneth D. Merry /*
2419d043c564SKenneth D. Merry * Get the transfer size in blocks.
2420d043c564SKenneth D. Merry */
2421d043c564SKenneth D. Merry io_size = (cm->cm_length >> sc->DD_block_exponent);
2422d043c564SKenneth D. Merry
2423d043c564SKenneth D. Merry /*
2424d043c564SKenneth D. Merry * Get virtual LBA given in the CDB.
2425d043c564SKenneth D. Merry */
2426d043c564SKenneth D. Merry virtLBA = ((uint64_t)(CDB[1] & 0x1F) << 16) |
2427d043c564SKenneth D. Merry ((uint64_t)CDB[2] << 8) | (uint64_t)CDB[3];
2428d043c564SKenneth D. Merry
2429d043c564SKenneth D. Merry /*
2430d043c564SKenneth D. Merry * Check that LBA range for I/O does not exceed volume's
2431d043c564SKenneth D. Merry * MaxLBA.
2432d043c564SKenneth D. Merry */
2433d043c564SKenneth D. Merry if ((virtLBA + (uint64_t)io_size - 1) <=
2434d043c564SKenneth D. Merry sc->DD_max_lba) {
2435d043c564SKenneth D. Merry /*
2436d043c564SKenneth D. Merry * Check if the I/O crosses a stripe boundary. If not,
2437d043c564SKenneth D. Merry * translate the virtual LBA to a physical LBA and set
2438d043c564SKenneth D. Merry * the DevHandle for the PhysDisk to be used. If it
2439453130d9SPedro F. Giffuni * does cross a boundary, do normal I/O. To get the
2440d043c564SKenneth D. Merry * right DevHandle to use, get the map number for the
2441d043c564SKenneth D. Merry * column, then use that map number to look up the
2442d043c564SKenneth D. Merry * DevHandle of the PhysDisk.
2443d043c564SKenneth D. Merry */
2444d043c564SKenneth D. Merry stripe_offset = (uint32_t)virtLBA &
2445d043c564SKenneth D. Merry (sc->DD_stripe_size - 1);
2446d043c564SKenneth D. Merry if ((stripe_offset + io_size) <= sc->DD_stripe_size) {
2447d043c564SKenneth D. Merry physLBA = (uint32_t)virtLBA >>
2448d043c564SKenneth D. Merry sc->DD_stripe_exponent;
2449d043c564SKenneth D. Merry stripe_unit = physLBA / sc->DD_num_phys_disks;
2450d043c564SKenneth D. Merry column = physLBA % sc->DD_num_phys_disks;
2451d043c564SKenneth D. Merry pIO_req->DevHandle =
2452be4aa869SKenneth D. Merry htole16(sc->DD_column_map[column].dev_handle);
2453be4aa869SKenneth D. Merry /* ???? Is this endian safe*/
2454d043c564SKenneth D. Merry cm->cm_desc.SCSIIO.DevHandle =
2455d043c564SKenneth D. Merry pIO_req->DevHandle;
2456d043c564SKenneth D. Merry
2457d043c564SKenneth D. Merry physLBA = (stripe_unit <<
2458d043c564SKenneth D. Merry sc->DD_stripe_exponent) + stripe_offset;
2459d043c564SKenneth D. Merry ptrLBA = &pIO_req->CDB.CDB32[1];
2460d043c564SKenneth D. Merry physLBA_byte = (uint8_t)(physLBA >> 16);
2461d043c564SKenneth D. Merry *ptrLBA = physLBA_byte;
2462d043c564SKenneth D. Merry ptrLBA = &pIO_req->CDB.CDB32[2];
2463d043c564SKenneth D. Merry physLBA_byte = (uint8_t)(physLBA >> 8);
2464d043c564SKenneth D. Merry *ptrLBA = physLBA_byte;
2465d043c564SKenneth D. Merry ptrLBA = &pIO_req->CDB.CDB32[3];
2466d043c564SKenneth D. Merry physLBA_byte = (uint8_t)physLBA;
2467d043c564SKenneth D. Merry *ptrLBA = physLBA_byte;
2468d043c564SKenneth D. Merry
2469d043c564SKenneth D. Merry /*
2470d043c564SKenneth D. Merry * Set flag that Direct Drive I/O is
2471d043c564SKenneth D. Merry * being done.
2472d043c564SKenneth D. Merry */
2473d043c564SKenneth D. Merry cm->cm_flags |= MPS_CM_FLAGS_DD_IO;
2474d043c564SKenneth D. Merry }
2475d043c564SKenneth D. Merry }
2476d043c564SKenneth D. Merry return;
2477d043c564SKenneth D. Merry }
2478d043c564SKenneth D. Merry
2479d043c564SKenneth D. Merry /*
2480be4aa869SKenneth D. Merry * Handle 10, 12 or 16 byte CDBs.
2481d043c564SKenneth D. Merry */
2482d043c564SKenneth D. Merry if ((pIO_req->DevHandle == sc->DD_dev_handle) && ((CDB[0] == READ_10) ||
2483d043c564SKenneth D. Merry (CDB[0] == WRITE_10) || (CDB[0] == READ_16) ||
2484be4aa869SKenneth D. Merry (CDB[0] == WRITE_16) || (CDB[0] == READ_12) ||
2485be4aa869SKenneth D. Merry (CDB[0] == WRITE_12))) {
2486d043c564SKenneth D. Merry /*
2487d043c564SKenneth D. Merry * For 16-byte CDB's, verify that the upper 4 bytes of the CDB
2488d043c564SKenneth D. Merry * are 0. If not, this is accessing beyond 2TB so handle it in
2489be4aa869SKenneth D. Merry * the else section. 10-byte and 12-byte CDB's are OK.
2490be4aa869SKenneth D. Merry * FreeBSD sends very rare 12 byte READ/WRITE, but driver is
2491be4aa869SKenneth D. Merry * ready to accept 12byte CDB for Direct IOs.
2492d043c564SKenneth D. Merry */
2493be4aa869SKenneth D. Merry if ((CDB[0] == READ_10 || CDB[0] == WRITE_10) ||
2494be4aa869SKenneth D. Merry (CDB[0] == READ_12 || CDB[0] == WRITE_12) ||
2495d043c564SKenneth D. Merry !(CDB[2] | CDB[3] | CDB[4] | CDB[5])) {
2496d043c564SKenneth D. Merry /*
2497d043c564SKenneth D. Merry * Get the transfer size in blocks.
2498d043c564SKenneth D. Merry */
2499d043c564SKenneth D. Merry io_size = (cm->cm_length >> sc->DD_block_exponent);
2500d043c564SKenneth D. Merry
2501d043c564SKenneth D. Merry /*
2502d043c564SKenneth D. Merry * Get virtual LBA. Point to correct lower 4 bytes of
2503d043c564SKenneth D. Merry * LBA in the CDB depending on command.
2504d043c564SKenneth D. Merry */
2505be4aa869SKenneth D. Merry lba_idx = ((CDB[0] == READ_12) ||
2506be4aa869SKenneth D. Merry (CDB[0] == WRITE_12) ||
2507be4aa869SKenneth D. Merry (CDB[0] == READ_10) ||
2508be4aa869SKenneth D. Merry (CDB[0] == WRITE_10))? 2 : 6;
2509d043c564SKenneth D. Merry virtLBA = ((uint64_t)CDB[lba_idx] << 24) |
2510d043c564SKenneth D. Merry ((uint64_t)CDB[lba_idx + 1] << 16) |
2511d043c564SKenneth D. Merry ((uint64_t)CDB[lba_idx + 2] << 8) |
2512d043c564SKenneth D. Merry (uint64_t)CDB[lba_idx + 3];
2513d043c564SKenneth D. Merry
2514d043c564SKenneth D. Merry /*
2515d043c564SKenneth D. Merry * Check that LBA range for I/O does not exceed volume's
2516d043c564SKenneth D. Merry * MaxLBA.
2517d043c564SKenneth D. Merry */
2518d043c564SKenneth D. Merry if ((virtLBA + (uint64_t)io_size - 1) <=
2519d043c564SKenneth D. Merry sc->DD_max_lba) {
2520d043c564SKenneth D. Merry /*
2521d043c564SKenneth D. Merry * Check if the I/O crosses a stripe boundary.
2522d043c564SKenneth D. Merry * If not, translate the virtual LBA to a
2523d043c564SKenneth D. Merry * physical LBA and set the DevHandle for the
2524d043c564SKenneth D. Merry * PhysDisk to be used. If it does cross a
2525453130d9SPedro F. Giffuni * boundary, do normal I/O. To get the right
2526d043c564SKenneth D. Merry * DevHandle to use, get the map number for the
2527d043c564SKenneth D. Merry * column, then use that map number to look up
2528d043c564SKenneth D. Merry * the DevHandle of the PhysDisk.
2529d043c564SKenneth D. Merry */
2530d043c564SKenneth D. Merry stripe_offset = (uint32_t)virtLBA &
2531d043c564SKenneth D. Merry (sc->DD_stripe_size - 1);
2532d043c564SKenneth D. Merry if ((stripe_offset + io_size) <=
2533d043c564SKenneth D. Merry sc->DD_stripe_size) {
2534d043c564SKenneth D. Merry physLBA = (uint32_t)virtLBA >>
2535d043c564SKenneth D. Merry sc->DD_stripe_exponent;
2536d043c564SKenneth D. Merry stripe_unit = physLBA /
2537d043c564SKenneth D. Merry sc->DD_num_phys_disks;
2538d043c564SKenneth D. Merry column = physLBA %
2539d043c564SKenneth D. Merry sc->DD_num_phys_disks;
2540d043c564SKenneth D. Merry pIO_req->DevHandle =
2541be4aa869SKenneth D. Merry htole16(sc->DD_column_map[column].
2542be4aa869SKenneth D. Merry dev_handle);
2543d043c564SKenneth D. Merry cm->cm_desc.SCSIIO.DevHandle =
2544d043c564SKenneth D. Merry pIO_req->DevHandle;
2545d043c564SKenneth D. Merry
2546d043c564SKenneth D. Merry physLBA = (stripe_unit <<
2547d043c564SKenneth D. Merry sc->DD_stripe_exponent) +
2548d043c564SKenneth D. Merry stripe_offset;
2549d043c564SKenneth D. Merry ptrLBA =
2550d043c564SKenneth D. Merry &pIO_req->CDB.CDB32[lba_idx];
2551d043c564SKenneth D. Merry physLBA_byte = (uint8_t)(physLBA >> 24);
2552d043c564SKenneth D. Merry *ptrLBA = physLBA_byte;
2553d043c564SKenneth D. Merry ptrLBA =
2554d043c564SKenneth D. Merry &pIO_req->CDB.CDB32[lba_idx + 1];
2555d043c564SKenneth D. Merry physLBA_byte = (uint8_t)(physLBA >> 16);
2556d043c564SKenneth D. Merry *ptrLBA = physLBA_byte;
2557d043c564SKenneth D. Merry ptrLBA =
2558d043c564SKenneth D. Merry &pIO_req->CDB.CDB32[lba_idx + 2];
2559d043c564SKenneth D. Merry physLBA_byte = (uint8_t)(physLBA >> 8);
2560d043c564SKenneth D. Merry *ptrLBA = physLBA_byte;
2561d043c564SKenneth D. Merry ptrLBA =
2562d043c564SKenneth D. Merry &pIO_req->CDB.CDB32[lba_idx + 3];
2563d043c564SKenneth D. Merry physLBA_byte = (uint8_t)physLBA;
2564d043c564SKenneth D. Merry *ptrLBA = physLBA_byte;
2565d043c564SKenneth D. Merry
2566d043c564SKenneth D. Merry /*
2567d043c564SKenneth D. Merry * Set flag that Direct Drive I/O is
2568d043c564SKenneth D. Merry * being done.
2569d043c564SKenneth D. Merry */
2570d043c564SKenneth D. Merry cm->cm_flags |= MPS_CM_FLAGS_DD_IO;
2571d043c564SKenneth D. Merry }
2572d043c564SKenneth D. Merry }
2573d043c564SKenneth D. Merry } else {
2574d043c564SKenneth D. Merry /*
2575d043c564SKenneth D. Merry * 16-byte CDB and the upper 4 bytes of the CDB are not
2576d043c564SKenneth D. Merry * 0. Get the transfer size in blocks.
2577d043c564SKenneth D. Merry */
2578d043c564SKenneth D. Merry io_size = (cm->cm_length >> sc->DD_block_exponent);
2579d043c564SKenneth D. Merry
2580d043c564SKenneth D. Merry /*
2581d043c564SKenneth D. Merry * Get virtual LBA.
2582d043c564SKenneth D. Merry */
2583d043c564SKenneth D. Merry virtLBA = ((uint64_t)CDB[2] << 54) |
2584d043c564SKenneth D. Merry ((uint64_t)CDB[3] << 48) |
2585d043c564SKenneth D. Merry ((uint64_t)CDB[4] << 40) |
2586d043c564SKenneth D. Merry ((uint64_t)CDB[5] << 32) |
2587d043c564SKenneth D. Merry ((uint64_t)CDB[6] << 24) |
2588d043c564SKenneth D. Merry ((uint64_t)CDB[7] << 16) |
2589d043c564SKenneth D. Merry ((uint64_t)CDB[8] << 8) |
2590d043c564SKenneth D. Merry (uint64_t)CDB[9];
2591d043c564SKenneth D. Merry
2592d043c564SKenneth D. Merry /*
2593d043c564SKenneth D. Merry * Check that LBA range for I/O does not exceed volume's
2594d043c564SKenneth D. Merry * MaxLBA.
2595d043c564SKenneth D. Merry */
2596d043c564SKenneth D. Merry if ((virtLBA + (uint64_t)io_size - 1) <=
2597d043c564SKenneth D. Merry sc->DD_max_lba) {
2598d043c564SKenneth D. Merry /*
2599d043c564SKenneth D. Merry * Check if the I/O crosses a stripe boundary.
2600d043c564SKenneth D. Merry * If not, translate the virtual LBA to a
2601d043c564SKenneth D. Merry * physical LBA and set the DevHandle for the
2602d043c564SKenneth D. Merry * PhysDisk to be used. If it does cross a
2603453130d9SPedro F. Giffuni * boundary, do normal I/O. To get the right
2604d043c564SKenneth D. Merry * DevHandle to use, get the map number for the
2605d043c564SKenneth D. Merry * column, then use that map number to look up
2606d043c564SKenneth D. Merry * the DevHandle of the PhysDisk.
2607d043c564SKenneth D. Merry */
2608d043c564SKenneth D. Merry stripe_offset = (uint32_t)virtLBA &
2609d043c564SKenneth D. Merry (sc->DD_stripe_size - 1);
2610d043c564SKenneth D. Merry if ((stripe_offset + io_size) <=
2611d043c564SKenneth D. Merry sc->DD_stripe_size) {
2612d043c564SKenneth D. Merry physLBA = (uint32_t)(virtLBA >>
2613d043c564SKenneth D. Merry sc->DD_stripe_exponent);
2614d043c564SKenneth D. Merry stripe_unit = physLBA /
2615d043c564SKenneth D. Merry sc->DD_num_phys_disks;
2616d043c564SKenneth D. Merry column = physLBA %
2617d043c564SKenneth D. Merry sc->DD_num_phys_disks;
2618d043c564SKenneth D. Merry pIO_req->DevHandle =
2619be4aa869SKenneth D. Merry htole16(sc->DD_column_map[column].
2620be4aa869SKenneth D. Merry dev_handle);
2621d043c564SKenneth D. Merry cm->cm_desc.SCSIIO.DevHandle =
2622d043c564SKenneth D. Merry pIO_req->DevHandle;
2623d043c564SKenneth D. Merry
2624d043c564SKenneth D. Merry physLBA = (stripe_unit <<
2625d043c564SKenneth D. Merry sc->DD_stripe_exponent) +
2626d043c564SKenneth D. Merry stripe_offset;
2627d043c564SKenneth D. Merry
2628d043c564SKenneth D. Merry /*
2629d043c564SKenneth D. Merry * Set upper 4 bytes of LBA to 0. We
2630d043c564SKenneth D. Merry * assume that the phys disks are less
2631d043c564SKenneth D. Merry * than 2 TB's in size. Then, set the
2632d043c564SKenneth D. Merry * lower 4 bytes.
2633d043c564SKenneth D. Merry */
2634d043c564SKenneth D. Merry pIO_req->CDB.CDB32[2] = 0;
2635d043c564SKenneth D. Merry pIO_req->CDB.CDB32[3] = 0;
2636d043c564SKenneth D. Merry pIO_req->CDB.CDB32[4] = 0;
2637d043c564SKenneth D. Merry pIO_req->CDB.CDB32[5] = 0;
2638d043c564SKenneth D. Merry ptrLBA = &pIO_req->CDB.CDB32[6];
2639d043c564SKenneth D. Merry physLBA_byte = (uint8_t)(physLBA >> 24);
2640d043c564SKenneth D. Merry *ptrLBA = physLBA_byte;
2641d043c564SKenneth D. Merry ptrLBA = &pIO_req->CDB.CDB32[7];
2642d043c564SKenneth D. Merry physLBA_byte = (uint8_t)(physLBA >> 16);
2643d043c564SKenneth D. Merry *ptrLBA = physLBA_byte;
2644d043c564SKenneth D. Merry ptrLBA = &pIO_req->CDB.CDB32[8];
2645d043c564SKenneth D. Merry physLBA_byte = (uint8_t)(physLBA >> 8);
2646d043c564SKenneth D. Merry *ptrLBA = physLBA_byte;
2647d043c564SKenneth D. Merry ptrLBA = &pIO_req->CDB.CDB32[9];
2648d043c564SKenneth D. Merry physLBA_byte = (uint8_t)physLBA;
2649d043c564SKenneth D. Merry *ptrLBA = physLBA_byte;
2650d043c564SKenneth D. Merry
2651d043c564SKenneth D. Merry /*
2652d043c564SKenneth D. Merry * Set flag that Direct Drive I/O is
2653d043c564SKenneth D. Merry * being done.
2654d043c564SKenneth D. Merry */
2655d043c564SKenneth D. Merry cm->cm_flags |= MPS_CM_FLAGS_DD_IO;
2656d043c564SKenneth D. Merry }
2657d043c564SKenneth D. Merry }
2658d043c564SKenneth D. Merry }
2659d043c564SKenneth D. Merry }
2660d043c564SKenneth D. Merry }
2661d043c564SKenneth D. Merry
266206e79492SKenneth D. Merry static void
mpssas_smpio_complete(struct mps_softc * sc,struct mps_command * cm)266306e79492SKenneth D. Merry mpssas_smpio_complete(struct mps_softc *sc, struct mps_command *cm)
266406e79492SKenneth D. Merry {
266506e79492SKenneth D. Merry MPI2_SMP_PASSTHROUGH_REPLY *rpl;
266606e79492SKenneth D. Merry MPI2_SMP_PASSTHROUGH_REQUEST *req;
266706e79492SKenneth D. Merry uint64_t sasaddr;
266806e79492SKenneth D. Merry union ccb *ccb;
266906e79492SKenneth D. Merry
267006e79492SKenneth D. Merry ccb = cm->cm_complete_data;
2671550e2acdSKenneth D. Merry
2672550e2acdSKenneth D. Merry /*
2673550e2acdSKenneth D. Merry * Currently there should be no way we can hit this case. It only
2674550e2acdSKenneth D. Merry * happens when we have a failure to allocate chain frames, and SMP
2675550e2acdSKenneth D. Merry * commands require two S/G elements only. That should be handled
2676550e2acdSKenneth D. Merry * in the standard request size.
2677550e2acdSKenneth D. Merry */
2678550e2acdSKenneth D. Merry if ((cm->cm_flags & MPS_CM_FLAGS_ERROR_MASK) != 0) {
26791610f95cSScott Long mps_dprint(sc, MPS_ERROR,"%s: cm_flags = %#x on SMP request!\n",
2680550e2acdSKenneth D. Merry __func__, cm->cm_flags);
2681601781ccSScott Long mpssas_set_ccbstatus(ccb, CAM_REQ_CMP_ERR);
2682550e2acdSKenneth D. Merry goto bailout;
2683550e2acdSKenneth D. Merry }
2684550e2acdSKenneth D. Merry
268506e79492SKenneth D. Merry rpl = (MPI2_SMP_PASSTHROUGH_REPLY *)cm->cm_reply;
268606e79492SKenneth D. Merry if (rpl == NULL) {
26871610f95cSScott Long mps_dprint(sc, MPS_ERROR, "%s: NULL cm_reply!\n", __func__);
2688601781ccSScott Long mpssas_set_ccbstatus(ccb, CAM_REQ_CMP_ERR);
268906e79492SKenneth D. Merry goto bailout;
269006e79492SKenneth D. Merry }
269106e79492SKenneth D. Merry
269206e79492SKenneth D. Merry req = (MPI2_SMP_PASSTHROUGH_REQUEST *)cm->cm_req;
269306e79492SKenneth D. Merry sasaddr = le32toh(req->SASAddress.Low);
269406e79492SKenneth D. Merry sasaddr |= ((uint64_t)(le32toh(req->SASAddress.High))) << 32;
269506e79492SKenneth D. Merry
26969b91b192SKenneth D. Merry if ((le16toh(rpl->IOCStatus) & MPI2_IOCSTATUS_MASK) !=
26979b91b192SKenneth D. Merry MPI2_IOCSTATUS_SUCCESS ||
269806e79492SKenneth D. Merry rpl->SASStatus != MPI2_SASSTATUS_SUCCESS) {
26991610f95cSScott Long mps_dprint(sc, MPS_XINFO, "%s: IOCStatus %04x SASStatus %02x\n",
2700be4aa869SKenneth D. Merry __func__, le16toh(rpl->IOCStatus), rpl->SASStatus);
2701601781ccSScott Long mpssas_set_ccbstatus(ccb, CAM_REQ_CMP_ERR);
270206e79492SKenneth D. Merry goto bailout;
270306e79492SKenneth D. Merry }
270406e79492SKenneth D. Merry
27051610f95cSScott Long mps_dprint(sc, MPS_XINFO, "%s: SMP request to SAS address "
270606e79492SKenneth D. Merry "%#jx completed successfully\n", __func__,
270706e79492SKenneth D. Merry (uintmax_t)sasaddr);
270806e79492SKenneth D. Merry
270906e79492SKenneth D. Merry if (ccb->smpio.smp_response[2] == SMP_FR_ACCEPTED)
2710601781ccSScott Long mpssas_set_ccbstatus(ccb, CAM_REQ_CMP);
271106e79492SKenneth D. Merry else
2712601781ccSScott Long mpssas_set_ccbstatus(ccb, CAM_SMP_STATUS_ERROR);
271306e79492SKenneth D. Merry
271406e79492SKenneth D. Merry bailout:
271506e79492SKenneth D. Merry /*
271606e79492SKenneth D. Merry * We sync in both directions because we had DMAs in the S/G list
271706e79492SKenneth D. Merry * in both directions.
271806e79492SKenneth D. Merry */
271906e79492SKenneth D. Merry bus_dmamap_sync(sc->buffer_dmat, cm->cm_dmamap,
272006e79492SKenneth D. Merry BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
272106e79492SKenneth D. Merry bus_dmamap_unload(sc->buffer_dmat, cm->cm_dmamap);
272206e79492SKenneth D. Merry mps_free_command(sc, cm);
272306e79492SKenneth D. Merry xpt_done(ccb);
272406e79492SKenneth D. Merry }
272506e79492SKenneth D. Merry
272606e79492SKenneth D. Merry static void
mpssas_send_smpcmd(struct mpssas_softc * sassc,union ccb * ccb,uint64_t sasaddr)272706e79492SKenneth D. Merry mpssas_send_smpcmd(struct mpssas_softc *sassc, union ccb *ccb, uint64_t sasaddr)
272806e79492SKenneth D. Merry {
272906e79492SKenneth D. Merry struct mps_command *cm;
273006e79492SKenneth D. Merry uint8_t *request, *response;
273106e79492SKenneth D. Merry MPI2_SMP_PASSTHROUGH_REQUEST *req;
273206e79492SKenneth D. Merry struct mps_softc *sc;
273306e79492SKenneth D. Merry int error;
273406e79492SKenneth D. Merry
273506e79492SKenneth D. Merry sc = sassc->sc;
273606e79492SKenneth D. Merry error = 0;
273706e79492SKenneth D. Merry
273806e79492SKenneth D. Merry /*
273906e79492SKenneth D. Merry * XXX We don't yet support physical addresses here.
274006e79492SKenneth D. Merry */
2741dd0b4fb6SKonstantin Belousov switch ((ccb->ccb_h.flags & CAM_DATA_MASK)) {
2742dd0b4fb6SKonstantin Belousov case CAM_DATA_PADDR:
2743dd0b4fb6SKonstantin Belousov case CAM_DATA_SG_PADDR:
27441610f95cSScott Long mps_dprint(sc, MPS_ERROR,
27451610f95cSScott Long "%s: physical addresses not supported\n", __func__);
2746601781ccSScott Long mpssas_set_ccbstatus(ccb, CAM_REQ_INVALID);
274706e79492SKenneth D. Merry xpt_done(ccb);
274806e79492SKenneth D. Merry return;
2749dd0b4fb6SKonstantin Belousov case CAM_DATA_SG:
275006e79492SKenneth D. Merry /*
275106e79492SKenneth D. Merry * The chip does not support more than one buffer for the
275206e79492SKenneth D. Merry * request or response.
275306e79492SKenneth D. Merry */
275406e79492SKenneth D. Merry if ((ccb->smpio.smp_request_sglist_cnt > 1)
275506e79492SKenneth D. Merry || (ccb->smpio.smp_response_sglist_cnt > 1)) {
27561610f95cSScott Long mps_dprint(sc, MPS_ERROR,
27571610f95cSScott Long "%s: multiple request or response "
275806e79492SKenneth D. Merry "buffer segments not supported for SMP\n",
275906e79492SKenneth D. Merry __func__);
2760601781ccSScott Long mpssas_set_ccbstatus(ccb, CAM_REQ_INVALID);
276106e79492SKenneth D. Merry xpt_done(ccb);
276206e79492SKenneth D. Merry return;
276306e79492SKenneth D. Merry }
276406e79492SKenneth D. Merry
276506e79492SKenneth D. Merry /*
276606e79492SKenneth D. Merry * The CAM_SCATTER_VALID flag was originally implemented
276706e79492SKenneth D. Merry * for the XPT_SCSI_IO CCB, which only has one data pointer.
276806e79492SKenneth D. Merry * We have two. So, just take that flag to mean that we
276906e79492SKenneth D. Merry * might have S/G lists, and look at the S/G segment count
277006e79492SKenneth D. Merry * to figure out whether that is the case for each individual
277106e79492SKenneth D. Merry * buffer.
277206e79492SKenneth D. Merry */
277306e79492SKenneth D. Merry if (ccb->smpio.smp_request_sglist_cnt != 0) {
277406e79492SKenneth D. Merry bus_dma_segment_t *req_sg;
277506e79492SKenneth D. Merry
277606e79492SKenneth D. Merry req_sg = (bus_dma_segment_t *)ccb->smpio.smp_request;
27770e28d282SKenneth D. Merry request = (uint8_t *)(uintptr_t)req_sg[0].ds_addr;
277806e79492SKenneth D. Merry } else
277906e79492SKenneth D. Merry request = ccb->smpio.smp_request;
278006e79492SKenneth D. Merry
278106e79492SKenneth D. Merry if (ccb->smpio.smp_response_sglist_cnt != 0) {
278206e79492SKenneth D. Merry bus_dma_segment_t *rsp_sg;
278306e79492SKenneth D. Merry
278406e79492SKenneth D. Merry rsp_sg = (bus_dma_segment_t *)ccb->smpio.smp_response;
27850e28d282SKenneth D. Merry response = (uint8_t *)(uintptr_t)rsp_sg[0].ds_addr;
278606e79492SKenneth D. Merry } else
278706e79492SKenneth D. Merry response = ccb->smpio.smp_response;
2788dd0b4fb6SKonstantin Belousov break;
2789dd0b4fb6SKonstantin Belousov case CAM_DATA_VADDR:
279006e79492SKenneth D. Merry request = ccb->smpio.smp_request;
279106e79492SKenneth D. Merry response = ccb->smpio.smp_response;
2792dd0b4fb6SKonstantin Belousov break;
2793dd0b4fb6SKonstantin Belousov default:
2794601781ccSScott Long mpssas_set_ccbstatus(ccb, CAM_REQ_INVALID);
2795dd0b4fb6SKonstantin Belousov xpt_done(ccb);
2796dd0b4fb6SKonstantin Belousov return;
279706e79492SKenneth D. Merry }
279806e79492SKenneth D. Merry
279906e79492SKenneth D. Merry cm = mps_alloc_command(sc);
280006e79492SKenneth D. Merry if (cm == NULL) {
28011610f95cSScott Long mps_dprint(sc, MPS_ERROR,
28021610f95cSScott Long "%s: cannot allocate command\n", __func__);
2803601781ccSScott Long mpssas_set_ccbstatus(ccb, CAM_RESRC_UNAVAIL);
280406e79492SKenneth D. Merry xpt_done(ccb);
280506e79492SKenneth D. Merry return;
280606e79492SKenneth D. Merry }
280706e79492SKenneth D. Merry
280806e79492SKenneth D. Merry req = (MPI2_SMP_PASSTHROUGH_REQUEST *)cm->cm_req;
280906e79492SKenneth D. Merry bzero(req, sizeof(*req));
281006e79492SKenneth D. Merry req->Function = MPI2_FUNCTION_SMP_PASSTHROUGH;
281106e79492SKenneth D. Merry
281206e79492SKenneth D. Merry /* Allow the chip to use any route to this SAS address. */
281306e79492SKenneth D. Merry req->PhysicalPort = 0xff;
281406e79492SKenneth D. Merry
2815be4aa869SKenneth D. Merry req->RequestDataLength = htole16(ccb->smpio.smp_request_len);
281606e79492SKenneth D. Merry req->SGLFlags =
281706e79492SKenneth D. Merry MPI2_SGLFLAGS_SYSTEM_ADDRESS_SPACE | MPI2_SGLFLAGS_SGL_TYPE_MPI;
281806e79492SKenneth D. Merry
28191610f95cSScott Long mps_dprint(sc, MPS_XINFO, "%s: sending SMP request to SAS "
282006e79492SKenneth D. Merry "address %#jx\n", __func__, (uintmax_t)sasaddr);
282106e79492SKenneth D. Merry
282206e79492SKenneth D. Merry mpi_init_sge(cm, req, &req->SGL);
282306e79492SKenneth D. Merry
282406e79492SKenneth D. Merry /*
282506e79492SKenneth D. Merry * Set up a uio to pass into mps_map_command(). This allows us to
282606e79492SKenneth D. Merry * do one map command, and one busdma call in there.
282706e79492SKenneth D. Merry */
282806e79492SKenneth D. Merry cm->cm_uio.uio_iov = cm->cm_iovec;
282906e79492SKenneth D. Merry cm->cm_uio.uio_iovcnt = 2;
283006e79492SKenneth D. Merry cm->cm_uio.uio_segflg = UIO_SYSSPACE;
283106e79492SKenneth D. Merry
283206e79492SKenneth D. Merry /*
283306e79492SKenneth D. Merry * The read/write flag isn't used by busdma, but set it just in
283406e79492SKenneth D. Merry * case. This isn't exactly accurate, either, since we're going in
283506e79492SKenneth D. Merry * both directions.
283606e79492SKenneth D. Merry */
283706e79492SKenneth D. Merry cm->cm_uio.uio_rw = UIO_WRITE;
283806e79492SKenneth D. Merry
283906e79492SKenneth D. Merry cm->cm_iovec[0].iov_base = request;
2840be4aa869SKenneth D. Merry cm->cm_iovec[0].iov_len = le16toh(req->RequestDataLength);
284106e79492SKenneth D. Merry cm->cm_iovec[1].iov_base = response;
284206e79492SKenneth D. Merry cm->cm_iovec[1].iov_len = ccb->smpio.smp_response_len;
284306e79492SKenneth D. Merry
284406e79492SKenneth D. Merry cm->cm_uio.uio_resid = cm->cm_iovec[0].iov_len +
284506e79492SKenneth D. Merry cm->cm_iovec[1].iov_len;
284606e79492SKenneth D. Merry
284706e79492SKenneth D. Merry /*
284806e79492SKenneth D. Merry * Trigger a warning message in mps_data_cb() for the user if we
284906e79492SKenneth D. Merry * wind up exceeding two S/G segments. The chip expects one
285006e79492SKenneth D. Merry * segment for the request and another for the response.
285106e79492SKenneth D. Merry */
285206e79492SKenneth D. Merry cm->cm_max_segs = 2;
285306e79492SKenneth D. Merry
285406e79492SKenneth D. Merry cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
285506e79492SKenneth D. Merry cm->cm_complete = mpssas_smpio_complete;
285606e79492SKenneth D. Merry cm->cm_complete_data = ccb;
285706e79492SKenneth D. Merry
285806e79492SKenneth D. Merry /*
285906e79492SKenneth D. Merry * Tell the mapping code that we're using a uio, and that this is
286006e79492SKenneth D. Merry * an SMP passthrough request. There is a little special-case
286106e79492SKenneth D. Merry * logic there (in mps_data_cb()) to handle the bidirectional
286206e79492SKenneth D. Merry * transfer.
286306e79492SKenneth D. Merry */
286406e79492SKenneth D. Merry cm->cm_flags |= MPS_CM_FLAGS_USE_UIO | MPS_CM_FLAGS_SMP_PASS |
286506e79492SKenneth D. Merry MPS_CM_FLAGS_DATAIN | MPS_CM_FLAGS_DATAOUT;
286606e79492SKenneth D. Merry
286706e79492SKenneth D. Merry /* The chip data format is little endian. */
286806e79492SKenneth D. Merry req->SASAddress.High = htole32(sasaddr >> 32);
286906e79492SKenneth D. Merry req->SASAddress.Low = htole32(sasaddr);
287006e79492SKenneth D. Merry
287106e79492SKenneth D. Merry /*
287206e79492SKenneth D. Merry * XXX Note that we don't have a timeout/abort mechanism here.
287306e79492SKenneth D. Merry * From the manual, it looks like task management requests only
287406e79492SKenneth D. Merry * work for SCSI IO and SATA passthrough requests. We may need to
287506e79492SKenneth D. Merry * have a mechanism to retry requests in the event of a chip reset
287606e79492SKenneth D. Merry * at least. Hopefully the chip will insure that any errors short
287706e79492SKenneth D. Merry * of that are relayed back to the driver.
287806e79492SKenneth D. Merry */
287906e79492SKenneth D. Merry error = mps_map_command(sc, cm);
288006e79492SKenneth D. Merry if ((error != 0) && (error != EINPROGRESS)) {
28811610f95cSScott Long mps_dprint(sc, MPS_ERROR,
28821610f95cSScott Long "%s: error %d returned from mps_map_command()\n",
288306e79492SKenneth D. Merry __func__, error);
288406e79492SKenneth D. Merry goto bailout_error;
288506e79492SKenneth D. Merry }
288606e79492SKenneth D. Merry
288706e79492SKenneth D. Merry return;
288806e79492SKenneth D. Merry
288906e79492SKenneth D. Merry bailout_error:
289006e79492SKenneth D. Merry mps_free_command(sc, cm);
2891601781ccSScott Long mpssas_set_ccbstatus(ccb, CAM_RESRC_UNAVAIL);
289206e79492SKenneth D. Merry xpt_done(ccb);
289306e79492SKenneth D. Merry return;
289406e79492SKenneth D. Merry
289506e79492SKenneth D. Merry }
289606e79492SKenneth D. Merry
289706e79492SKenneth D. Merry static void
mpssas_action_smpio(struct mpssas_softc * sassc,union ccb * ccb)289806e79492SKenneth D. Merry mpssas_action_smpio(struct mpssas_softc *sassc, union ccb *ccb)
289906e79492SKenneth D. Merry {
290006e79492SKenneth D. Merry struct mps_softc *sc;
290106e79492SKenneth D. Merry struct mpssas_target *targ;
290206e79492SKenneth D. Merry uint64_t sasaddr = 0;
290306e79492SKenneth D. Merry
290406e79492SKenneth D. Merry sc = sassc->sc;
290506e79492SKenneth D. Merry
290606e79492SKenneth D. Merry /*
290706e79492SKenneth D. Merry * Make sure the target exists.
290806e79492SKenneth D. Merry */
290908235773SScott Long KASSERT(ccb->ccb_h.target_id < sassc->maxtargets,
291008235773SScott Long ("Target %d out of bounds in XPT_SMP_IO\n", ccb->ccb_h.target_id));
291106e79492SKenneth D. Merry targ = &sassc->targets[ccb->ccb_h.target_id];
291206e79492SKenneth D. Merry if (targ->handle == 0x0) {
29131610f95cSScott Long mps_dprint(sc, MPS_ERROR,
29141610f95cSScott Long "%s: target %d does not exist!\n", __func__,
291506e79492SKenneth D. Merry ccb->ccb_h.target_id);
2916601781ccSScott Long mpssas_set_ccbstatus(ccb, CAM_SEL_TIMEOUT);
291706e79492SKenneth D. Merry xpt_done(ccb);
291806e79492SKenneth D. Merry return;
291906e79492SKenneth D. Merry }
292006e79492SKenneth D. Merry
292106e79492SKenneth D. Merry /*
292206e79492SKenneth D. Merry * If this device has an embedded SMP target, we'll talk to it
292306e79492SKenneth D. Merry * directly.
292406e79492SKenneth D. Merry * figure out what the expander's address is.
292506e79492SKenneth D. Merry */
292606e79492SKenneth D. Merry if ((targ->devinfo & MPI2_SAS_DEVICE_INFO_SMP_TARGET) != 0)
292706e79492SKenneth D. Merry sasaddr = targ->sasaddr;
292806e79492SKenneth D. Merry
292906e79492SKenneth D. Merry /*
293006e79492SKenneth D. Merry * If we don't have a SAS address for the expander yet, try
293106e79492SKenneth D. Merry * grabbing it from the page 0x83 information cached in the
293206e79492SKenneth D. Merry * transport layer for this target. LSI expanders report the
293306e79492SKenneth D. Merry * expander SAS address as the port-associated SAS address in
293406e79492SKenneth D. Merry * Inquiry VPD page 0x83. Maxim expanders don't report it in page
293506e79492SKenneth D. Merry * 0x83.
293606e79492SKenneth D. Merry *
293706e79492SKenneth D. Merry * XXX KDM disable this for now, but leave it commented out so that
293806e79492SKenneth D. Merry * it is obvious that this is another possible way to get the SAS
293906e79492SKenneth D. Merry * address.
294006e79492SKenneth D. Merry *
294106e79492SKenneth D. Merry * The parent handle method below is a little more reliable, and
294206e79492SKenneth D. Merry * the other benefit is that it works for devices other than SES
294306e79492SKenneth D. Merry * devices. So you can send a SMP request to a da(4) device and it
294406e79492SKenneth D. Merry * will get routed to the expander that device is attached to.
294506e79492SKenneth D. Merry * (Assuming the da(4) device doesn't contain an SMP target...)
294606e79492SKenneth D. Merry */
294706e79492SKenneth D. Merry #if 0
294806e79492SKenneth D. Merry if (sasaddr == 0)
294906e79492SKenneth D. Merry sasaddr = xpt_path_sas_addr(ccb->ccb_h.path);
295006e79492SKenneth D. Merry #endif
295106e79492SKenneth D. Merry
295206e79492SKenneth D. Merry /*
295306e79492SKenneth D. Merry * If we still don't have a SAS address for the expander, look for
295406e79492SKenneth D. Merry * the parent device of this device, which is probably the expander.
295506e79492SKenneth D. Merry */
295606e79492SKenneth D. Merry if (sasaddr == 0) {
2957d043c564SKenneth D. Merry #ifdef OLD_MPS_PROBE
295806e79492SKenneth D. Merry struct mpssas_target *parent_target;
2959d043c564SKenneth D. Merry #endif
296006e79492SKenneth D. Merry
296106e79492SKenneth D. Merry if (targ->parent_handle == 0x0) {
29621610f95cSScott Long mps_dprint(sc, MPS_ERROR,
29631610f95cSScott Long "%s: handle %d does not have a valid "
296406e79492SKenneth D. Merry "parent handle!\n", __func__, targ->handle);
29657571e7f6SSteven Hartland mpssas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE);
296606e79492SKenneth D. Merry goto bailout;
296706e79492SKenneth D. Merry }
2968d043c564SKenneth D. Merry #ifdef OLD_MPS_PROBE
2969d043c564SKenneth D. Merry parent_target = mpssas_find_target_by_handle(sassc, 0,
297006e79492SKenneth D. Merry targ->parent_handle);
297106e79492SKenneth D. Merry
297206e79492SKenneth D. Merry if (parent_target == NULL) {
29731610f95cSScott Long mps_dprint(sc, MPS_ERROR,
29741610f95cSScott Long "%s: handle %d does not have a valid "
297506e79492SKenneth D. Merry "parent target!\n", __func__, targ->handle);
29767571e7f6SSteven Hartland mpssas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE);
297706e79492SKenneth D. Merry goto bailout;
297806e79492SKenneth D. Merry }
297906e79492SKenneth D. Merry
298006e79492SKenneth D. Merry if ((parent_target->devinfo &
298106e79492SKenneth D. Merry MPI2_SAS_DEVICE_INFO_SMP_TARGET) == 0) {
29821610f95cSScott Long mps_dprint(sc, MPS_ERROR,
29831610f95cSScott Long "%s: handle %d parent %d does not "
298406e79492SKenneth D. Merry "have an SMP target!\n", __func__,
298506e79492SKenneth D. Merry targ->handle, parent_target->handle);
29867571e7f6SSteven Hartland mpssas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE);
298706e79492SKenneth D. Merry goto bailout;
298806e79492SKenneth D. Merry }
298906e79492SKenneth D. Merry
299006e79492SKenneth D. Merry sasaddr = parent_target->sasaddr;
2991d043c564SKenneth D. Merry #else /* OLD_MPS_PROBE */
2992d043c564SKenneth D. Merry if ((targ->parent_devinfo &
2993d043c564SKenneth D. Merry MPI2_SAS_DEVICE_INFO_SMP_TARGET) == 0) {
29941610f95cSScott Long mps_dprint(sc, MPS_ERROR,
29951610f95cSScott Long "%s: handle %d parent %d does not "
2996d043c564SKenneth D. Merry "have an SMP target!\n", __func__,
2997d043c564SKenneth D. Merry targ->handle, targ->parent_handle);
29987571e7f6SSteven Hartland mpssas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE);
2999d043c564SKenneth D. Merry goto bailout;
3000d043c564SKenneth D. Merry }
3001d043c564SKenneth D. Merry if (targ->parent_sasaddr == 0x0) {
30021610f95cSScott Long mps_dprint(sc, MPS_ERROR,
30031610f95cSScott Long "%s: handle %d parent handle %d does "
3004d043c564SKenneth D. Merry "not have a valid SAS address!\n",
3005d043c564SKenneth D. Merry __func__, targ->handle, targ->parent_handle);
30067571e7f6SSteven Hartland mpssas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE);
3007d043c564SKenneth D. Merry goto bailout;
3008d043c564SKenneth D. Merry }
3009d043c564SKenneth D. Merry
3010d043c564SKenneth D. Merry sasaddr = targ->parent_sasaddr;
3011d043c564SKenneth D. Merry #endif /* OLD_MPS_PROBE */
301206e79492SKenneth D. Merry }
301306e79492SKenneth D. Merry
301406e79492SKenneth D. Merry if (sasaddr == 0) {
30151610f95cSScott Long mps_dprint(sc, MPS_INFO,
30161610f95cSScott Long "%s: unable to find SAS address for handle %d\n",
301706e79492SKenneth D. Merry __func__, targ->handle);
30187571e7f6SSteven Hartland mpssas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE);
301906e79492SKenneth D. Merry goto bailout;
302006e79492SKenneth D. Merry }
302106e79492SKenneth D. Merry mpssas_send_smpcmd(sassc, ccb, sasaddr);
302206e79492SKenneth D. Merry
302306e79492SKenneth D. Merry return;
302406e79492SKenneth D. Merry
302506e79492SKenneth D. Merry bailout:
302606e79492SKenneth D. Merry xpt_done(ccb);
302706e79492SKenneth D. Merry
302806e79492SKenneth D. Merry }
302906e79492SKenneth D. Merry
3030d3c7b9a0SKenneth D. Merry static void
mpssas_action_resetdev(struct mpssas_softc * sassc,union ccb * ccb)3031d3c7b9a0SKenneth D. Merry mpssas_action_resetdev(struct mpssas_softc *sassc, union ccb *ccb)
3032d3c7b9a0SKenneth D. Merry {
3033d3c7b9a0SKenneth D. Merry MPI2_SCSI_TASK_MANAGE_REQUEST *req;
3034d3c7b9a0SKenneth D. Merry struct mps_softc *sc;
3035d043c564SKenneth D. Merry struct mps_command *tm;
3036d043c564SKenneth D. Merry struct mpssas_target *targ;
3037d3c7b9a0SKenneth D. Merry
30381610f95cSScott Long MPS_FUNCTRACE(sassc->sc);
3039d043c564SKenneth D. Merry mtx_assert(&sassc->sc->mps_mtx, MA_OWNED);
3040d3c7b9a0SKenneth D. Merry
304108235773SScott Long KASSERT(ccb->ccb_h.target_id < sassc->maxtargets,
304208235773SScott Long ("Target %d out of bounds in XPT_RESET_DEV\n",
304308235773SScott Long ccb->ccb_h.target_id));
3044d3c7b9a0SKenneth D. Merry sc = sassc->sc;
30453921a9f7SScott Long tm = mpssas_alloc_tm(sc);
3046d043c564SKenneth D. Merry if (tm == NULL) {
30471610f95cSScott Long mps_dprint(sc, MPS_ERROR,
30487263f45eSScott Long "command alloc failure in mpssas_action_resetdev\n");
3049601781ccSScott Long mpssas_set_ccbstatus(ccb, CAM_RESRC_UNAVAIL);
3050d043c564SKenneth D. Merry xpt_done(ccb);
3051d043c564SKenneth D. Merry return;
3052d043c564SKenneth D. Merry }
3053d3c7b9a0SKenneth D. Merry
3054d043c564SKenneth D. Merry targ = &sassc->targets[ccb->ccb_h.target_id];
3055d043c564SKenneth D. Merry req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req;
3056be4aa869SKenneth D. Merry req->DevHandle = htole16(targ->handle);
3057d3c7b9a0SKenneth D. Merry req->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
3058d3c7b9a0SKenneth D. Merry
3059d3c7b9a0SKenneth D. Merry /* SAS Hard Link Reset / SATA Link Reset */
3060d3c7b9a0SKenneth D. Merry req->MsgFlags = MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET;
3061d3c7b9a0SKenneth D. Merry
3062d043c564SKenneth D. Merry tm->cm_data = NULL;
3063d043c564SKenneth D. Merry tm->cm_complete = mpssas_resetdev_complete;
3064d043c564SKenneth D. Merry tm->cm_complete_data = ccb;
30651914fdecSAlexander Motin tm->cm_targ = targ;
3066ef065d89SStephen McConnell
30673921a9f7SScott Long mpssas_prepare_for_tm(sc, tm, targ, CAM_LUN_WILDCARD);
3068d043c564SKenneth D. Merry mps_map_command(sc, tm);
3069d3c7b9a0SKenneth D. Merry }
3070d3c7b9a0SKenneth D. Merry
3071d3c7b9a0SKenneth D. Merry static void
mpssas_resetdev_complete(struct mps_softc * sc,struct mps_command * tm)3072d043c564SKenneth D. Merry mpssas_resetdev_complete(struct mps_softc *sc, struct mps_command *tm)
3073d3c7b9a0SKenneth D. Merry {
3074d3c7b9a0SKenneth D. Merry MPI2_SCSI_TASK_MANAGE_REPLY *resp;
3075d3c7b9a0SKenneth D. Merry union ccb *ccb;
3076d3c7b9a0SKenneth D. Merry
30771610f95cSScott Long MPS_FUNCTRACE(sc);
3078d043c564SKenneth D. Merry mtx_assert(&sc->mps_mtx, MA_OWNED);
3079d3c7b9a0SKenneth D. Merry
3080d043c564SKenneth D. Merry resp = (MPI2_SCSI_TASK_MANAGE_REPLY *)tm->cm_reply;
3081d043c564SKenneth D. Merry ccb = tm->cm_complete_data;
3082d3c7b9a0SKenneth D. Merry
3083d043c564SKenneth D. Merry /*
3084d043c564SKenneth D. Merry * Currently there should be no way we can hit this case. It only
3085d043c564SKenneth D. Merry * happens when we have a failure to allocate chain frames, and
3086d043c564SKenneth D. Merry * task management commands don't have S/G lists.
3087d043c564SKenneth D. Merry */
3088d043c564SKenneth D. Merry if ((tm->cm_flags & MPS_CM_FLAGS_ERROR_MASK) != 0) {
3089550e2acdSKenneth D. Merry MPI2_SCSI_TASK_MANAGE_REQUEST *req;
3090550e2acdSKenneth D. Merry
3091d043c564SKenneth D. Merry req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req;
3092550e2acdSKenneth D. Merry
30931610f95cSScott Long mps_dprint(sc, MPS_ERROR,
30941610f95cSScott Long "%s: cm_flags = %#x for reset of handle %#04x! "
3095d043c564SKenneth D. Merry "This should not happen!\n", __func__, tm->cm_flags,
3096550e2acdSKenneth D. Merry req->DevHandle);
3097601781ccSScott Long mpssas_set_ccbstatus(ccb, CAM_REQ_CMP_ERR);
3098550e2acdSKenneth D. Merry goto bailout;
3099550e2acdSKenneth D. Merry }
3100550e2acdSKenneth D. Merry
31011610f95cSScott Long mps_dprint(sc, MPS_XINFO,
31021610f95cSScott Long "%s: IOCStatus = 0x%x ResponseCode = 0x%x\n", __func__,
3103be4aa869SKenneth D. Merry le16toh(resp->IOCStatus), le32toh(resp->ResponseCode));
3104d3c7b9a0SKenneth D. Merry
3105be4aa869SKenneth D. Merry if (le32toh(resp->ResponseCode) == MPI2_SCSITASKMGMT_RSP_TM_COMPLETE) {
3106601781ccSScott Long mpssas_set_ccbstatus(ccb, CAM_REQ_CMP);
3107d043c564SKenneth D. Merry mpssas_announce_reset(sc, AC_SENT_BDR, tm->cm_targ->tid,
3108d043c564SKenneth D. Merry CAM_LUN_WILDCARD);
3109d043c564SKenneth D. Merry }
3110d3c7b9a0SKenneth D. Merry else
3111601781ccSScott Long mpssas_set_ccbstatus(ccb, CAM_REQ_CMP_ERR);
3112d3c7b9a0SKenneth D. Merry
3113550e2acdSKenneth D. Merry bailout:
311463feedfdSKenneth D. Merry
3115d043c564SKenneth D. Merry mpssas_free_tm(sc, tm);
3116d3c7b9a0SKenneth D. Merry xpt_done(ccb);
3117d3c7b9a0SKenneth D. Merry }
3118d3c7b9a0SKenneth D. Merry
3119d3c7b9a0SKenneth D. Merry static void
mpssas_poll(struct cam_sim * sim)3120d3c7b9a0SKenneth D. Merry mpssas_poll(struct cam_sim *sim)
3121d3c7b9a0SKenneth D. Merry {
3122d3c7b9a0SKenneth D. Merry struct mpssas_softc *sassc;
3123d3c7b9a0SKenneth D. Merry
3124d3c7b9a0SKenneth D. Merry sassc = cam_sim_softc(sim);
3125d043c564SKenneth D. Merry
3126d043c564SKenneth D. Merry if (sassc->sc->mps_debug & MPS_TRACE) {
3127d043c564SKenneth D. Merry /* frequent debug messages during a panic just slow
3128d043c564SKenneth D. Merry * everything down too much.
3129d043c564SKenneth D. Merry */
3130d043c564SKenneth D. Merry mps_printf(sassc->sc, "%s clearing MPS_TRACE\n", __func__);
3131d043c564SKenneth D. Merry sassc->sc->mps_debug &= ~MPS_TRACE;
3132d043c564SKenneth D. Merry }
3133d043c564SKenneth D. Merry
3134d3c7b9a0SKenneth D. Merry mps_intr_locked(sassc->sc);
3135d3c7b9a0SKenneth D. Merry }
3136d3c7b9a0SKenneth D. Merry
3137d3c7b9a0SKenneth D. Merry static void
mpssas_async(void * callback_arg,uint32_t code,struct cam_path * path,void * arg)3138d043c564SKenneth D. Merry mpssas_async(void *callback_arg, uint32_t code, struct cam_path *path,
3139d043c564SKenneth D. Merry void *arg)
3140d043c564SKenneth D. Merry {
3141d043c564SKenneth D. Merry struct mps_softc *sc;
3142d043c564SKenneth D. Merry
3143d043c564SKenneth D. Merry sc = (struct mps_softc *)callback_arg;
3144d043c564SKenneth D. Merry
314502d81940SAlexander Motin mps_lock(sc);
3146d043c564SKenneth D. Merry switch (code) {
3147d043c564SKenneth D. Merry case AC_ADVINFO_CHANGED: {
3148d043c564SKenneth D. Merry struct mpssas_target *target;
3149d043c564SKenneth D. Merry struct mpssas_softc *sassc;
3150d043c564SKenneth D. Merry struct scsi_read_capacity_data_long rcap_buf;
3151d043c564SKenneth D. Merry struct ccb_dev_advinfo cdai;
3152d043c564SKenneth D. Merry struct mpssas_lun *lun;
3153d043c564SKenneth D. Merry lun_id_t lunid;
3154d043c564SKenneth D. Merry int found_lun;
3155d043c564SKenneth D. Merry uintptr_t buftype;
3156d043c564SKenneth D. Merry
3157d043c564SKenneth D. Merry buftype = (uintptr_t)arg;
3158d043c564SKenneth D. Merry
3159d043c564SKenneth D. Merry found_lun = 0;
3160d043c564SKenneth D. Merry sassc = sc->sassc;
3161d043c564SKenneth D. Merry
3162d043c564SKenneth D. Merry /*
3163d043c564SKenneth D. Merry * We're only interested in read capacity data changes.
3164d043c564SKenneth D. Merry */
3165d043c564SKenneth D. Merry if (buftype != CDAI_TYPE_RCAPLONG)
3166d043c564SKenneth D. Merry break;
3167d043c564SKenneth D. Merry
3168d043c564SKenneth D. Merry /*
3169d043c564SKenneth D. Merry * We should have a handle for this, but check to make sure.
3170d043c564SKenneth D. Merry */
317108235773SScott Long KASSERT(xpt_path_target_id(path) < sassc->maxtargets,
317208235773SScott Long ("Target %d out of bounds in mpssas_async\n",
317308235773SScott Long xpt_path_target_id(path)));
3174d043c564SKenneth D. Merry target = &sassc->targets[xpt_path_target_id(path)];
3175d043c564SKenneth D. Merry if (target->handle == 0)
3176d043c564SKenneth D. Merry break;
3177d043c564SKenneth D. Merry
3178d043c564SKenneth D. Merry lunid = xpt_path_lun_id(path);
3179d043c564SKenneth D. Merry
3180d043c564SKenneth D. Merry SLIST_FOREACH(lun, &target->luns, lun_link) {
3181d043c564SKenneth D. Merry if (lun->lun_id == lunid) {
3182d043c564SKenneth D. Merry found_lun = 1;
3183d043c564SKenneth D. Merry break;
3184d043c564SKenneth D. Merry }
3185d043c564SKenneth D. Merry }
3186d043c564SKenneth D. Merry
3187d043c564SKenneth D. Merry if (found_lun == 0) {
3188d043c564SKenneth D. Merry lun = malloc(sizeof(struct mpssas_lun), M_MPT2,
3189d043c564SKenneth D. Merry M_NOWAIT | M_ZERO);
3190d043c564SKenneth D. Merry if (lun == NULL) {
31911610f95cSScott Long mps_dprint(sc, MPS_ERROR, "Unable to alloc "
3192d043c564SKenneth D. Merry "LUN for EEDP support.\n");
3193d043c564SKenneth D. Merry break;
3194d043c564SKenneth D. Merry }
3195d043c564SKenneth D. Merry lun->lun_id = lunid;
3196d043c564SKenneth D. Merry SLIST_INSERT_HEAD(&target->luns, lun, lun_link);
3197d043c564SKenneth D. Merry }
3198d043c564SKenneth D. Merry
3199d043c564SKenneth D. Merry bzero(&rcap_buf, sizeof(rcap_buf));
32007608b98cSEdward Tomasz Napierala bzero(&cdai, sizeof(cdai));
3201d043c564SKenneth D. Merry xpt_setup_ccb(&cdai.ccb_h, path, CAM_PRIORITY_NORMAL);
3202d043c564SKenneth D. Merry cdai.ccb_h.func_code = XPT_DEV_ADVINFO;
3203d043c564SKenneth D. Merry cdai.ccb_h.flags = CAM_DIR_IN;
3204d043c564SKenneth D. Merry cdai.buftype = CDAI_TYPE_RCAPLONG;
3205e8577fb4SKenneth D. Merry cdai.flags = CDAI_FLAG_NONE;
3206d043c564SKenneth D. Merry cdai.bufsiz = sizeof(rcap_buf);
3207d043c564SKenneth D. Merry cdai.buf = (uint8_t *)&rcap_buf;
3208d043c564SKenneth D. Merry xpt_action((union ccb *)&cdai);
3209d043c564SKenneth D. Merry if ((cdai.ccb_h.status & CAM_DEV_QFRZN) != 0)
3210d043c564SKenneth D. Merry cam_release_devq(cdai.ccb_h.path,
3211d043c564SKenneth D. Merry 0, 0, 0, FALSE);
3212d043c564SKenneth D. Merry
3213601781ccSScott Long if ((mpssas_get_ccbstatus((union ccb *)&cdai) == CAM_REQ_CMP)
3214d043c564SKenneth D. Merry && (rcap_buf.prot & SRC16_PROT_EN)) {
32158881681bSKenneth D. Merry switch (rcap_buf.prot & SRC16_P_TYPE) {
32168881681bSKenneth D. Merry case SRC16_PTYPE_1:
32178881681bSKenneth D. Merry case SRC16_PTYPE_3:
3218d043c564SKenneth D. Merry lun->eedp_formatted = TRUE;
32198881681bSKenneth D. Merry lun->eedp_block_size =
32208881681bSKenneth D. Merry scsi_4btoul(rcap_buf.length);
32218881681bSKenneth D. Merry break;
32228881681bSKenneth D. Merry case SRC16_PTYPE_2:
32238881681bSKenneth D. Merry default:
32248881681bSKenneth D. Merry lun->eedp_formatted = FALSE;
32258881681bSKenneth D. Merry lun->eedp_block_size = 0;
32268881681bSKenneth D. Merry break;
32278881681bSKenneth D. Merry }
3228d043c564SKenneth D. Merry } else {
3229d043c564SKenneth D. Merry lun->eedp_formatted = FALSE;
3230d043c564SKenneth D. Merry lun->eedp_block_size = 0;
3231d043c564SKenneth D. Merry }
3232d043c564SKenneth D. Merry break;
3233d043c564SKenneth D. Merry }
3234d043c564SKenneth D. Merry default:
3235d043c564SKenneth D. Merry break;
3236d043c564SKenneth D. Merry }
323702d81940SAlexander Motin mps_unlock(sc);
3238d043c564SKenneth D. Merry }
3239d043c564SKenneth D. Merry
3240ef065d89SStephen McConnell /*
3241db0ac6deSCy Schubert * Freeze the devq and set the INRESET flag so that no I/O will be sent to
3242db0ac6deSCy Schubert * the target until the reset has completed. The CCB holds the path which
3243db0ac6deSCy Schubert * is used to release the devq. The devq is released and the CCB is freed
3244ef065d89SStephen McConnell * when the TM completes.
3245db0ac6deSCy Schubert * We only need to do this when we're entering reset, not at each time we
3246db0ac6deSCy Schubert * need to send an abort (which will happen if multiple commands timeout
3247db0ac6deSCy Schubert * while we're sending the abort). We do not release the queue for each
3248db0ac6deSCy Schubert * command we complete (just at the end when we free the tm), so freezing
3249db0ac6deSCy Schubert * it each time doesn't make sense.
3250ef065d89SStephen McConnell */
3251b7f1ee79SScott Long void
mpssas_prepare_for_tm(struct mps_softc * sc,struct mps_command * tm,struct mpssas_target * target,lun_id_t lun_id)3252b7f1ee79SScott Long mpssas_prepare_for_tm(struct mps_softc *sc, struct mps_command *tm,
3253b7f1ee79SScott Long struct mpssas_target *target, lun_id_t lun_id)
3254b7f1ee79SScott Long {
3255b7f1ee79SScott Long union ccb *ccb;
3256b7f1ee79SScott Long path_id_t path_id;
3257b7f1ee79SScott Long
3258ef065d89SStephen McConnell ccb = xpt_alloc_ccb_nowait();
3259ef065d89SStephen McConnell if (ccb) {
3260ef065d89SStephen McConnell path_id = cam_sim_path(sc->sassc->sim);
3261ef065d89SStephen McConnell if (xpt_create_path(&ccb->ccb_h.path, xpt_periph, path_id,
3262ef065d89SStephen McConnell target->tid, lun_id) != CAM_REQ_CMP) {
3263ef065d89SStephen McConnell xpt_free_ccb(ccb);
3264ef065d89SStephen McConnell } else {
3265ef065d89SStephen McConnell tm->cm_ccb = ccb;
3266ef065d89SStephen McConnell tm->cm_targ = target;
3267db0ac6deSCy Schubert if ((target->flags & MPSSAS_TARGET_INRESET) == 0) {
3268db0ac6deSCy Schubert mps_dprint(sc, MPS_XINFO | MPS_RECOVERY,
3269db0ac6deSCy Schubert "%s: Freezing devq for target ID %d\n",
3270db0ac6deSCy Schubert __func__, target->tid);
3271db0ac6deSCy Schubert xpt_freeze_devq(ccb->ccb_h.path, 1);
3272ef065d89SStephen McConnell target->flags |= MPSSAS_TARGET_INRESET;
3273ef065d89SStephen McConnell }
3274ef065d89SStephen McConnell }
3275ef065d89SStephen McConnell }
3276db0ac6deSCy Schubert }
3277ef065d89SStephen McConnell
3278d043c564SKenneth D. Merry int
mpssas_startup(struct mps_softc * sc)3279d043c564SKenneth D. Merry mpssas_startup(struct mps_softc *sc)
3280d043c564SKenneth D. Merry {
3281d043c564SKenneth D. Merry
3282d043c564SKenneth D. Merry /*
3283d043c564SKenneth D. Merry * Send the port enable message and set the wait_for_port_enable flag.
3284d043c564SKenneth D. Merry * This flag helps to keep the simq frozen until all discovery events
3285d043c564SKenneth D. Merry * are processed.
3286d043c564SKenneth D. Merry */
3287d043c564SKenneth D. Merry sc->wait_for_port_enable = 1;
3288d043c564SKenneth D. Merry mpssas_send_portenable(sc);
3289d043c564SKenneth D. Merry return (0);
3290d043c564SKenneth D. Merry }
3291d043c564SKenneth D. Merry
3292d043c564SKenneth D. Merry static int
mpssas_send_portenable(struct mps_softc * sc)3293d043c564SKenneth D. Merry mpssas_send_portenable(struct mps_softc *sc)
3294d043c564SKenneth D. Merry {
3295d043c564SKenneth D. Merry MPI2_PORT_ENABLE_REQUEST *request;
3296d043c564SKenneth D. Merry struct mps_command *cm;
3297d043c564SKenneth D. Merry
32981610f95cSScott Long MPS_FUNCTRACE(sc);
3299d043c564SKenneth D. Merry
3300d043c564SKenneth D. Merry if ((cm = mps_alloc_command(sc)) == NULL)
3301d043c564SKenneth D. Merry return (EBUSY);
3302d043c564SKenneth D. Merry request = (MPI2_PORT_ENABLE_REQUEST *)cm->cm_req;
3303d043c564SKenneth D. Merry request->Function = MPI2_FUNCTION_PORT_ENABLE;
3304d043c564SKenneth D. Merry request->MsgFlags = 0;
3305d043c564SKenneth D. Merry request->VP_ID = 0;
3306d043c564SKenneth D. Merry cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
3307d043c564SKenneth D. Merry cm->cm_complete = mpssas_portenable_complete;
3308d043c564SKenneth D. Merry cm->cm_data = NULL;
3309d043c564SKenneth D. Merry cm->cm_sge = NULL;
3310d043c564SKenneth D. Merry
3311d043c564SKenneth D. Merry mps_map_command(sc, cm);
33121610f95cSScott Long mps_dprint(sc, MPS_XINFO,
3313d043c564SKenneth D. Merry "mps_send_portenable finished cm %p req %p complete %p\n",
3314d043c564SKenneth D. Merry cm, cm->cm_req, cm->cm_complete);
3315d043c564SKenneth D. Merry return (0);
3316d043c564SKenneth D. Merry }
3317d043c564SKenneth D. Merry
3318d043c564SKenneth D. Merry static void
mpssas_portenable_complete(struct mps_softc * sc,struct mps_command * cm)3319d043c564SKenneth D. Merry mpssas_portenable_complete(struct mps_softc *sc, struct mps_command *cm)
3320d043c564SKenneth D. Merry {
3321d043c564SKenneth D. Merry MPI2_PORT_ENABLE_REPLY *reply;
3322d043c564SKenneth D. Merry struct mpssas_softc *sassc;
3323d043c564SKenneth D. Merry
33241610f95cSScott Long MPS_FUNCTRACE(sc);
3325d043c564SKenneth D. Merry sassc = sc->sassc;
3326d043c564SKenneth D. Merry
3327d043c564SKenneth D. Merry /*
3328d043c564SKenneth D. Merry * Currently there should be no way we can hit this case. It only
3329d043c564SKenneth D. Merry * happens when we have a failure to allocate chain frames, and
3330d043c564SKenneth D. Merry * port enable commands don't have S/G lists.
3331d043c564SKenneth D. Merry */
3332d043c564SKenneth D. Merry if ((cm->cm_flags & MPS_CM_FLAGS_ERROR_MASK) != 0) {
33331610f95cSScott Long mps_dprint(sc, MPS_ERROR, "%s: cm_flags = %#x for port enable! "
3334d043c564SKenneth D. Merry "This should not happen!\n", __func__, cm->cm_flags);
3335d043c564SKenneth D. Merry }
3336d043c564SKenneth D. Merry
3337d043c564SKenneth D. Merry reply = (MPI2_PORT_ENABLE_REPLY *)cm->cm_reply;
3338d043c564SKenneth D. Merry if (reply == NULL)
3339d043c564SKenneth D. Merry mps_dprint(sc, MPS_FAULT, "Portenable NULL reply\n");
3340be4aa869SKenneth D. Merry else if (le16toh(reply->IOCStatus & MPI2_IOCSTATUS_MASK) !=
3341d043c564SKenneth D. Merry MPI2_IOCSTATUS_SUCCESS)
3342d043c564SKenneth D. Merry mps_dprint(sc, MPS_FAULT, "Portenable failed\n");
3343d043c564SKenneth D. Merry
3344d043c564SKenneth D. Merry mps_free_command(sc, cm);
3345d043c564SKenneth D. Merry
3346d043c564SKenneth D. Merry /*
3347d043c564SKenneth D. Merry * Get WarpDrive info after discovery is complete but before the scan
3348d043c564SKenneth D. Merry * starts. At this point, all devices are ready to be exposed to the
3349d043c564SKenneth D. Merry * OS. If devices should be hidden instead, take them out of the
3350d043c564SKenneth D. Merry * 'targets' array before the scan. The devinfo for a disk will have
3351d043c564SKenneth D. Merry * some info and a volume's will be 0. Use that to remove disks.
3352d043c564SKenneth D. Merry */
3353d043c564SKenneth D. Merry mps_wd_config_pages(sc);
3354d043c564SKenneth D. Merry
3355d043c564SKenneth D. Merry /*
3356d043c564SKenneth D. Merry * Done waiting for port enable to complete. Decrement the refcount.
3357d043c564SKenneth D. Merry * If refcount is 0, discovery is complete and a rescan of the bus can
3358d043c564SKenneth D. Merry * take place. Since the simq was explicitly frozen before port
3359d043c564SKenneth D. Merry * enable, it must be explicitly released here to keep the
3360d043c564SKenneth D. Merry * freeze/release count in sync.
3361d043c564SKenneth D. Merry */
3362d043c564SKenneth D. Merry sc->wait_for_port_enable = 0;
3363d043c564SKenneth D. Merry sc->port_enable_complete = 1;
3364be4aa869SKenneth D. Merry wakeup(&sc->port_enable_complete);
3365d043c564SKenneth D. Merry mpssas_startup_decrement(sassc);
3366d3c7b9a0SKenneth D. Merry }
3367d3c7b9a0SKenneth D. Merry
3368d9802debSScott Long int
mpssas_check_id(struct mpssas_softc * sassc,int id)3369d9802debSScott Long mpssas_check_id(struct mpssas_softc *sassc, int id)
3370d9802debSScott Long {
3371d9802debSScott Long struct mps_softc *sc = sassc->sc;
3372d9802debSScott Long char *ids;
3373d9802debSScott Long char *name;
3374d9802debSScott Long
3375d9802debSScott Long ids = &sc->exclude_ids[0];
3376d9802debSScott Long while((name = strsep(&ids, ",")) != NULL) {
3377d9802debSScott Long if (name[0] == '\0')
3378d9802debSScott Long continue;
3379d9802debSScott Long if (strtol(name, NULL, 0) == (long)id)
3380d9802debSScott Long return (1);
3381d9802debSScott Long }
3382d9802debSScott Long
3383d9802debSScott Long return (0);
3384d9802debSScott Long }
3385b7f77127SScott Long
3386b7f77127SScott Long void
mpssas_realloc_targets(struct mps_softc * sc,int maxtargets)3387b7f77127SScott Long mpssas_realloc_targets(struct mps_softc *sc, int maxtargets)
3388b7f77127SScott Long {
3389b7f77127SScott Long struct mpssas_softc *sassc;
3390b7f77127SScott Long struct mpssas_lun *lun, *lun_tmp;
3391b7f77127SScott Long struct mpssas_target *targ;
3392b7f77127SScott Long int i;
3393b7f77127SScott Long
3394b7f77127SScott Long sassc = sc->sassc;
3395b7f77127SScott Long /*
3396b7f77127SScott Long * The number of targets is based on IOC Facts, so free all of
3397b7f77127SScott Long * the allocated LUNs for each target and then the target buffer
3398b7f77127SScott Long * itself.
3399b7f77127SScott Long */
3400b7f77127SScott Long for (i=0; i< maxtargets; i++) {
3401b7f77127SScott Long targ = &sassc->targets[i];
3402b7f77127SScott Long SLIST_FOREACH_SAFE(lun, &targ->luns, lun_link, lun_tmp) {
3403b7f77127SScott Long free(lun, M_MPT2);
3404b7f77127SScott Long }
3405b7f77127SScott Long }
3406b7f77127SScott Long free(sassc->targets, M_MPT2);
3407b7f77127SScott Long
3408b7f77127SScott Long sassc->targets = malloc(sizeof(struct mpssas_target) * maxtargets,
3409b7f77127SScott Long M_MPT2, M_WAITOK|M_ZERO);
3410b7f77127SScott Long }
3411