1212420Sken/*-
2212420Sken * Copyright (c) 2009 Yahoo! Inc.
3237683Sken * Copyright (c) 2011, 2012 LSI Corp.
4212420Sken * All rights reserved.
5212420Sken *
6212420Sken * Redistribution and use in source and binary forms, with or without
7212420Sken * modification, are permitted provided that the following conditions
8212420Sken * are met:
9212420Sken * 1. Redistributions of source code must retain the above copyright
10212420Sken *    notice, this list of conditions and the following disclaimer.
11212420Sken * 2. Redistributions in binary form must reproduce the above copyright
12212420Sken *    notice, this list of conditions and the following disclaimer in the
13212420Sken *    documentation and/or other materials provided with the distribution.
14212420Sken *
15212420Sken * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16212420Sken * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17212420Sken * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18212420Sken * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19212420Sken * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20212420Sken * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21212420Sken * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22212420Sken * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23212420Sken * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24212420Sken * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25212420Sken * SUCH DAMAGE.
26230592Sken *
27230592Sken * LSI MPT-Fusion Host Adapter FreeBSD
28230592Sken *
29230592Sken * $FreeBSD$
30230592Sken */
31212420Sken
32212420Sken#include <sys/cdefs.h>
33212420Sken__FBSDID("$FreeBSD$");
34212420Sken
35212420Sken/* Communications core for LSI MPT2 */
36212420Sken
37230592Sken/* TODO Move headers to mpsvar */
38212420Sken#include <sys/types.h>
39212420Sken#include <sys/param.h>
40212420Sken#include <sys/systm.h>
41212420Sken#include <sys/kernel.h>
42212420Sken#include <sys/selinfo.h>
43212420Sken#include <sys/module.h>
44212420Sken#include <sys/bus.h>
45212420Sken#include <sys/conf.h>
46212420Sken#include <sys/bio.h>
47212420Sken#include <sys/malloc.h>
48212420Sken#include <sys/uio.h>
49212420Sken#include <sys/sysctl.h>
50216088Sken#include <sys/endian.h>
51230592Sken#include <sys/queue.h>
52230592Sken#include <sys/kthread.h>
53230592Sken#include <sys/taskqueue.h>
54230592Sken#include <sys/sbuf.h>
55212420Sken
56212420Sken#include <machine/bus.h>
57212420Sken#include <machine/resource.h>
58212420Sken#include <sys/rman.h>
59212420Sken
60230592Sken#include <machine/stdarg.h>
61230592Sken
62212420Sken#include <cam/cam.h>
63212420Sken#include <cam/cam_ccb.h>
64230592Sken#include <cam/cam_xpt.h>
65212420Sken#include <cam/cam_debug.h>
66212420Sken#include <cam/cam_sim.h>
67212420Sken#include <cam/cam_xpt_sim.h>
68212420Sken#include <cam/cam_xpt_periph.h>
69212420Sken#include <cam/cam_periph.h>
70212420Sken#include <cam/scsi/scsi_all.h>
71212420Sken#include <cam/scsi/scsi_message.h>
72216088Sken#if __FreeBSD_version >= 900026
73216088Sken#include <cam/scsi/smp_all.h>
74216088Sken#endif
75212420Sken
76212420Sken#include <dev/mps/mpi/mpi2_type.h>
77212420Sken#include <dev/mps/mpi/mpi2.h>
78212420Sken#include <dev/mps/mpi/mpi2_ioc.h>
79212420Sken#include <dev/mps/mpi/mpi2_sas.h>
80212420Sken#include <dev/mps/mpi/mpi2_cnfg.h>
81212420Sken#include <dev/mps/mpi/mpi2_init.h>
82230592Sken#include <dev/mps/mpi/mpi2_tool.h>
83230592Sken#include <dev/mps/mps_ioctl.h>
84212420Sken#include <dev/mps/mpsvar.h>
85212420Sken#include <dev/mps/mps_table.h>
86230592Sken#include <dev/mps/mps_sas.h>
87212420Sken
88230592Sken#define MPSSAS_DISCOVERY_TIMEOUT	20
89230592Sken#define MPSSAS_MAX_DISCOVERY_TIMEOUTS	10 /* 200 seconds */
90212420Sken
91230592Sken/*
92230592Sken * static array to check SCSI OpCode for EEDP protection bits
93230592Sken */
94230592Sken#define	PRO_R MPI2_SCSIIO_EEDPFLAGS_CHECK_REMOVE_OP
95230592Sken#define	PRO_W MPI2_SCSIIO_EEDPFLAGS_INSERT_OP
96230592Sken#define	PRO_V MPI2_SCSIIO_EEDPFLAGS_INSERT_OP
97230592Skenstatic uint8_t op_code_prot[256] = {
98230592Sken	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
99230592Sken	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
100230592Sken	0, 0, 0, 0, 0, 0, 0, 0, PRO_R, 0, PRO_W, 0, 0, 0, PRO_W, PRO_V,
101230592Sken	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
102230592Sken	0, PRO_W, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
103230592Sken	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
104230592Sken	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
105230592Sken	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
106230592Sken	0, 0, 0, 0, 0, 0, 0, 0, PRO_R, 0, PRO_W, 0, 0, 0, PRO_W, PRO_V,
107230592Sken	0, 0, 0, PRO_W, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
108230592Sken	0, 0, 0, 0, 0, 0, 0, 0, PRO_R, 0, PRO_W, 0, 0, 0, PRO_W, PRO_V,
109230592Sken	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
110230592Sken	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
111230592Sken	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
112230592Sken	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
113230592Sken	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
114212420Sken};
115212420Sken
116230592SkenMALLOC_DEFINE(M_MPSSAS, "MPSSAS", "MPS SAS memory");
117212420Sken
118212420Skenstatic void mpssas_discovery_timeout(void *data);
119212420Skenstatic void mpssas_remove_device(struct mps_softc *, struct mps_command *);
120212420Skenstatic void mpssas_remove_complete(struct mps_softc *, struct mps_command *);
121212420Skenstatic void mpssas_action(struct cam_sim *sim, union ccb *ccb);
122212420Skenstatic void mpssas_poll(struct cam_sim *sim);
123212420Skenstatic void mpssas_scsiio_timeout(void *data);
124212420Skenstatic void mpssas_abort_complete(struct mps_softc *sc, struct mps_command *cm);
125230592Skenstatic void mpssas_direct_drive_io(struct mpssas_softc *sassc,
126230592Sken    struct mps_command *cm, union ccb *ccb);
127212420Skenstatic void mpssas_action_scsiio(struct mpssas_softc *, union ccb *);
128212420Skenstatic void mpssas_scsiio_complete(struct mps_softc *, struct mps_command *);
129230592Skenstatic void mpssas_action_resetdev(struct mpssas_softc *, union ccb *);
130216088Sken#if __FreeBSD_version >= 900026
131216088Skenstatic void mpssas_smpio_complete(struct mps_softc *sc, struct mps_command *cm);
132216088Skenstatic void mpssas_send_smpcmd(struct mpssas_softc *sassc, union ccb *ccb,
133216088Sken			       uint64_t sasaddr);
134216088Skenstatic void mpssas_action_smpio(struct mpssas_softc *sassc, union ccb *ccb);
135230592Sken#endif //FreeBSD_version >= 900026
136212420Skenstatic void mpssas_resetdev_complete(struct mps_softc *, struct mps_command *);
137230592Skenstatic int  mpssas_send_abort(struct mps_softc *sc, struct mps_command *tm, struct mps_command *cm);
138230592Skenstatic int  mpssas_send_reset(struct mps_softc *sc, struct mps_command *tm, uint8_t type);
139230592Skenstatic void mpssas_async(void *callback_arg, uint32_t code,
140230592Sken			 struct cam_path *path, void *arg);
141253549Sken#if (__FreeBSD_version < 901503) || \
142253549Sken    ((__FreeBSD_version >= 1000000) && (__FreeBSD_version < 1000006))
143253549Skenstatic void mpssas_check_eedp(struct mps_softc *sc, struct cam_path *path,
144253549Sken			      struct ccb_getdev *cgd);
145230592Skenstatic void mpssas_read_cap_done(struct cam_periph *periph, union ccb *done_ccb);
146230592Sken#endif
147230592Skenstatic int mpssas_send_portenable(struct mps_softc *sc);
148230592Skenstatic void mpssas_portenable_complete(struct mps_softc *sc,
149230592Sken    struct mps_command *cm);
150212420Sken
151231240Skenstruct mpssas_target *
152230592Skenmpssas_find_target_by_handle(struct mpssas_softc *sassc, int start, uint16_t handle)
153216368Sken{
154230592Sken	struct mpssas_target *target;
155230592Sken	int i;
156216368Sken
157230592Sken	for (i = start; i < sassc->sc->facts->MaxTargets; i++) {
158230592Sken		target = &sassc->targets[i];
159230592Sken		if (target->handle == handle)
160230592Sken			return (target);
161216368Sken	}
162216368Sken
163230592Sken	return (NULL);
164216368Sken}
165216368Sken
166230592Sken/* we need to freeze the simq during attach and diag reset, to avoid failing
167230592Sken * commands before device handles have been found by discovery.  Since
168230592Sken * discovery involves reading config pages and possibly sending commands,
169230592Sken * discovery actions may continue even after we receive the end of discovery
170230592Sken * event, so refcount discovery actions instead of assuming we can unfreeze
171230592Sken * the simq when we get the event.
172230592Sken */
173230592Skenvoid
174230592Skenmpssas_startup_increment(struct mpssas_softc *sassc)
175212420Sken{
176253460Sscottl	MPS_FUNCTRACE(sassc->sc);
177253460Sscottl
178230592Sken	if ((sassc->flags & MPSSAS_IN_STARTUP) != 0) {
179230592Sken		if (sassc->startup_refcount++ == 0) {
180230592Sken			/* just starting, freeze the simq */
181253460Sscottl			mps_dprint(sassc->sc, MPS_INIT,
182230592Sken			    "%s freezing simq\n", __func__);
183230592Sken			xpt_freeze_simq(sassc->sim, 1);
184230592Sken		}
185253460Sscottl		mps_dprint(sassc->sc, MPS_INIT, "%s refcount %u\n", __func__,
186230592Sken		    sassc->startup_refcount);
187230592Sken	}
188230592Sken}
189212420Sken
190230592Skenvoid
191230592Skenmpssas_startup_decrement(struct mpssas_softc *sassc)
192230592Sken{
193253460Sscottl	MPS_FUNCTRACE(sassc->sc);
194253460Sscottl
195230592Sken	if ((sassc->flags & MPSSAS_IN_STARTUP) != 0) {
196230592Sken		if (--sassc->startup_refcount == 0) {
197230592Sken			/* finished all discovery-related actions, release
198230592Sken			 * the simq and rescan for the latest topology.
199230592Sken			 */
200253460Sscottl			mps_dprint(sassc->sc, MPS_INIT,
201230592Sken			    "%s releasing simq\n", __func__);
202230592Sken			sassc->flags &= ~MPSSAS_IN_STARTUP;
203253549Sken#if __FreeBSD_version >= 1000039
204253549Sken			xpt_release_boot();
205253549Sken#else
206230592Sken			xpt_release_simq(sassc->sim, 1);
207230592Sken			mpssas_rescan_target(sassc->sc, NULL);
208253549Sken#endif
209230592Sken		}
210253460Sscottl		mps_dprint(sassc->sc, MPS_INIT, "%s refcount %u\n", __func__,
211230592Sken		    sassc->startup_refcount);
212212420Sken	}
213230592Sken}
214212420Sken
215230592Sken/* LSI's firmware requires us to stop sending commands when we're doing task
216230592Sken * management, so refcount the TMs and keep the simq frozen when any are in
217230592Sken * use.
218230592Sken */
219230592Skenstruct mps_command *
220230592Skenmpssas_alloc_tm(struct mps_softc *sc)
221230592Sken{
222230592Sken	struct mps_command *tm;
223212420Sken
224253460Sscottl	MPS_FUNCTRACE(sc);
225230592Sken	tm = mps_alloc_high_priority_command(sc);
226230592Sken	if (tm != NULL) {
227230592Sken		if (sc->sassc->tm_count++ == 0) {
228253460Sscottl			mps_dprint(sc, MPS_RECOVERY,
229253460Sscottl			    "%s freezing simq\n", __func__);
230230592Sken			xpt_freeze_simq(sc->sassc->sim, 1);
231230592Sken		}
232253460Sscottl		mps_dprint(sc, MPS_RECOVERY, "%s tm_count %u\n", __func__,
233230592Sken		    sc->sassc->tm_count);
234230592Sken	}
235230592Sken	return tm;
236212420Sken}
237212420Sken
238230592Skenvoid
239230592Skenmpssas_free_tm(struct mps_softc *sc, struct mps_command *tm)
240212420Sken{
241253460Sscottl	mps_dprint(sc, MPS_TRACE, "%s", __func__);
242230592Sken	if (tm == NULL)
243230592Sken		return;
244212420Sken
245230592Sken	/* if there are no TMs in use, we can release the simq.  We use our
246230592Sken	 * own refcount so that it's easier for a diag reset to cleanup and
247230592Sken	 * release the simq.
248230592Sken	 */
249230592Sken	if (--sc->sassc->tm_count == 0) {
250253460Sscottl		mps_dprint(sc, MPS_RECOVERY, "%s releasing simq\n", __func__);
251230592Sken		xpt_release_simq(sc->sassc->sim, 1);
252212420Sken	}
253253460Sscottl	mps_dprint(sc, MPS_RECOVERY, "%s tm_count %u\n", __func__,
254230592Sken	    sc->sassc->tm_count);
255212420Sken
256230592Sken	mps_free_high_priority_command(sc, tm);
257212420Sken}
258212420Sken
259230592Skenvoid
260230592Skenmpssas_rescan_target(struct mps_softc *sc, struct mpssas_target *targ)
261212420Sken{
262230592Sken	struct mpssas_softc *sassc = sc->sassc;
263230592Sken	path_id_t pathid;
264230592Sken	target_id_t targetid;
265230592Sken	union ccb *ccb;
266212420Sken
267253460Sscottl	MPS_FUNCTRACE(sc);
268230592Sken	pathid = cam_sim_path(sassc->sim);
269230592Sken	if (targ == NULL)
270230592Sken		targetid = CAM_TARGET_WILDCARD;
271230592Sken	else
272230592Sken		targetid = targ - sassc->targets;
273212420Sken
274230592Sken	/*
275230592Sken	 * Allocate a CCB and schedule a rescan.
276230592Sken	 */
277230592Sken	ccb = xpt_alloc_ccb_nowait();
278230592Sken	if (ccb == NULL) {
279253460Sscottl		mps_dprint(sc, MPS_ERROR, "unable to alloc CCB for rescan\n");
280212420Sken		return;
281212420Sken	}
282212420Sken
283249468Smav	if (xpt_create_path(&ccb->ccb_h.path, NULL, pathid,
284253550Sken	    targetid, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
285253460Sscottl		mps_dprint(sc, MPS_ERROR, "unable to create path for rescan\n");
286230592Sken		xpt_free_ccb(ccb);
287212420Sken		return;
288212420Sken	}
289230592Sken
290237800Sken	if (targetid == CAM_TARGET_WILDCARD)
291237800Sken		ccb->ccb_h.func_code = XPT_SCAN_BUS;
292237800Sken	else
293237800Sken		ccb->ccb_h.func_code = XPT_SCAN_TGT;
294237800Sken
295230592Sken	mps_dprint(sc, MPS_TRACE, "%s targetid %u\n", __func__, targetid);
296253549Sken	xpt_rescan(ccb);
297212420Sken}
298212420Sken
299212420Skenstatic void
300253460Sscottlmpssas_log_command(struct mps_command *cm, u_int level, const char *fmt, ...)
301212420Sken{
302230592Sken	struct sbuf sb;
303230592Sken	va_list ap;
304230592Sken	char str[192];
305230592Sken	char path_str[64];
306212420Sken
307230592Sken	if (cm == NULL)
308230592Sken		return;
309212420Sken
310254253Sscottl	/* No need to be in here if debugging isn't enabled */
311254257Smav	if ((cm->cm_sc->mps_debug & level) == 0)
312254253Sscottl		return;
313254253Sscottl
314230592Sken	sbuf_new(&sb, str, sizeof(str), 0);
315212420Sken
316230592Sken	va_start(ap, fmt);
317212420Sken
318230592Sken	if (cm->cm_ccb != NULL) {
319230592Sken		xpt_path_string(cm->cm_ccb->csio.ccb_h.path, path_str,
320230592Sken				sizeof(path_str));
321230592Sken		sbuf_cat(&sb, path_str);
322230592Sken		if (cm->cm_ccb->ccb_h.func_code == XPT_SCSI_IO) {
323230592Sken			scsi_command_string(&cm->cm_ccb->csio, &sb);
324230592Sken			sbuf_printf(&sb, "length %d ",
325230592Sken				    cm->cm_ccb->csio.dxfer_len);
326212420Sken		}
327212420Sken	}
328230592Sken	else {
329230592Sken		sbuf_printf(&sb, "(noperiph:%s%d:%u:%u:%u): ",
330230592Sken		    cam_sim_name(cm->cm_sc->sassc->sim),
331230592Sken		    cam_sim_unit(cm->cm_sc->sassc->sim),
332230592Sken		    cam_sim_bus(cm->cm_sc->sassc->sim),
333230592Sken		    cm->cm_targ ? cm->cm_targ->tid : 0xFFFFFFFF,
334230592Sken		    cm->cm_lun);
335230592Sken	}
336212420Sken
337230592Sken	sbuf_printf(&sb, "SMID %u ", cm->cm_desc.Default.SMID);
338230592Sken	sbuf_vprintf(&sb, fmt, ap);
339230592Sken	sbuf_finish(&sb);
340253460Sscottl	mps_dprint_field(cm->cm_sc, level, "%s", sbuf_data(&sb));
341212420Sken
342230592Sken	va_end(ap);
343230592Sken}
344212420Sken
345231240Sken
346230592Skenstatic void
347231240Skenmpssas_remove_volume(struct mps_softc *sc, struct mps_command *tm)
348230592Sken{
349231240Sken	MPI2_SCSI_TASK_MANAGE_REPLY *reply;
350231240Sken	struct mpssas_target *targ;
351231240Sken	uint16_t handle;
352212420Sken
353253460Sscottl	MPS_FUNCTRACE(sc);
354231240Sken
355231240Sken	reply = (MPI2_SCSI_TASK_MANAGE_REPLY *)tm->cm_reply;
356231240Sken	handle = (uint16_t)(uintptr_t)tm->cm_complete_data;
357231240Sken	targ = tm->cm_targ;
358231240Sken
359231240Sken	if (reply == NULL) {
360231240Sken		/* XXX retry the remove after the diag reset completes? */
361253460Sscottl		mps_dprint(sc, MPS_FAULT,
362253460Sscottl		    "%s NULL reply reseting device 0x%04x\n", __func__, handle);
363231240Sken		mpssas_free_tm(sc, tm);
364230592Sken		return;
365230592Sken	}
366212420Sken
367231240Sken	if (reply->IOCStatus != MPI2_IOCSTATUS_SUCCESS) {
368253460Sscottl		mps_dprint(sc, MPS_FAULT,
369253460Sscottl		   "IOCStatus = 0x%x while resetting device 0x%x\n",
370231240Sken		   reply->IOCStatus, handle);
371231240Sken		mpssas_free_tm(sc, tm);
372231240Sken		return;
373231240Sken	}
374231240Sken
375253460Sscottl	mps_dprint(sc, MPS_XINFO,
376253460Sscottl	    "Reset aborted %u commands\n", reply->TerminationCount);
377231240Sken	mps_free_reply(sc, tm->cm_reply_data);
378240518Seadler	tm->cm_reply = NULL;	/* Ensures the reply won't get re-freed */
379231240Sken
380253460Sscottl	mps_dprint(sc, MPS_XINFO,
381253460Sscottl	    "clearing target %u handle 0x%04x\n", targ->tid, handle);
382231240Sken
383231240Sken	/*
384231240Sken	 * Don't clear target if remove fails because things will get confusing.
385231240Sken	 * Leave the devname and sasaddr intact so that we know to avoid reusing
386231240Sken	 * this target id if possible, and so we can assign the same target id
387231240Sken	 * to this device if it comes back in the future.
388231240Sken	 */
389231240Sken	if (reply->IOCStatus == MPI2_IOCSTATUS_SUCCESS) {
390231240Sken		targ = tm->cm_targ;
391231240Sken		targ->handle = 0x0;
392231240Sken		targ->encl_handle = 0x0;
393231240Sken		targ->encl_slot = 0x0;
394231240Sken		targ->exp_dev_handle = 0x0;
395231240Sken		targ->phy_num = 0x0;
396231240Sken		targ->linkrate = 0x0;
397231240Sken		targ->devinfo = 0x0;
398231240Sken		targ->flags = 0x0;
399231240Sken	}
400231240Sken
401231240Sken	mpssas_free_tm(sc, tm);
402212420Sken}
403212420Sken
404231240Sken
405212420Sken/*
406231240Sken * No Need to call "MPI2_SAS_OP_REMOVE_DEVICE" For Volume removal.
407231240Sken * Otherwise Volume Delete is same as Bare Drive Removal.
408231240Sken */
409231240Skenvoid
410231240Skenmpssas_prepare_volume_remove(struct mpssas_softc *sassc, uint16_t handle)
411231240Sken{
412231240Sken	MPI2_SCSI_TASK_MANAGE_REQUEST *req;
413231240Sken	struct mps_softc *sc;
414231240Sken	struct mps_command *cm;
415231240Sken	struct mpssas_target *targ = NULL;
416231240Sken
417253460Sscottl	MPS_FUNCTRACE(sassc->sc);
418231240Sken	sc = sassc->sc;
419231240Sken
420231240Sken#ifdef WD_SUPPORT
421231240Sken	/*
422231240Sken	 * If this is a WD controller, determine if the disk should be exposed
423231240Sken	 * to the OS or not.  If disk should be exposed, return from this
424231240Sken	 * function without doing anything.
425231240Sken	 */
426231240Sken	if (sc->WD_available && (sc->WD_hide_expose ==
427231240Sken	    MPS_WD_EXPOSE_ALWAYS)) {
428231240Sken		return;
429231240Sken	}
430231240Sken#endif //WD_SUPPORT
431231240Sken
432231240Sken	targ = mpssas_find_target_by_handle(sassc, 0, handle);
433231240Sken	if (targ == NULL) {
434231240Sken		/* FIXME: what is the action? */
435231240Sken		/* We don't know about this device? */
436253460Sscottl		mps_dprint(sc, MPS_ERROR,
437253460Sscottl		   "%s %d : invalid handle 0x%x \n", __func__,__LINE__, handle);
438231240Sken		return;
439231240Sken	}
440231240Sken
441231240Sken	targ->flags |= MPSSAS_TARGET_INREMOVAL;
442231240Sken
443231240Sken	cm = mpssas_alloc_tm(sc);
444231240Sken	if (cm == NULL) {
445253460Sscottl		mps_dprint(sc, MPS_ERROR,
446253460Sscottl		    "%s: command alloc failure\n", __func__);
447231240Sken		return;
448231240Sken	}
449231240Sken
450231240Sken	mpssas_rescan_target(sc, targ);
451231240Sken
452231240Sken	req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)cm->cm_req;
453231240Sken	req->DevHandle = targ->handle;
454231240Sken	req->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
455231240Sken	req->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
456231240Sken
457231240Sken	/* SAS Hard Link Reset / SATA Link Reset */
458231240Sken	req->MsgFlags = MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET;
459231240Sken
460231240Sken	cm->cm_targ = targ;
461231240Sken	cm->cm_data = NULL;
462231240Sken	cm->cm_desc.HighPriority.RequestFlags =
463231240Sken	    MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY;
464231240Sken	cm->cm_complete = mpssas_remove_volume;
465231240Sken	cm->cm_complete_data = (void *)(uintptr_t)handle;
466231240Sken	mps_map_command(sc, cm);
467231240Sken}
468231240Sken
469231240Sken/*
470230592Sken * The MPT2 firmware performs debounce on the link to avoid transient link
471230592Sken * errors and false removals.  When it does decide that link has been lost
472230592Sken * and a device need to go away, it expects that the host will perform a
473230592Sken * target reset and then an op remove.  The reset has the side-effect of
474230592Sken * aborting any outstanding requests for the device, which is required for
475230592Sken * the op-remove to succeed.  It's not clear if the host should check for
476230592Sken * the device coming back alive after the reset.
477212420Sken */
478230592Skenvoid
479230592Skenmpssas_prepare_remove(struct mpssas_softc *sassc, uint16_t handle)
480212420Sken{
481212420Sken	MPI2_SCSI_TASK_MANAGE_REQUEST *req;
482212420Sken	struct mps_softc *sc;
483212420Sken	struct mps_command *cm;
484212420Sken	struct mpssas_target *targ = NULL;
485212420Sken
486253460Sscottl	MPS_FUNCTRACE(sassc->sc);
487212420Sken
488230592Sken	sc = sassc->sc;
489230592Sken
490230592Sken	targ = mpssas_find_target_by_handle(sassc, 0, handle);
491230592Sken	if (targ == NULL) {
492230592Sken		/* FIXME: what is the action? */
493212420Sken		/* We don't know about this device? */
494253460Sscottl		mps_dprint(sc, MPS_ERROR,
495253460Sscottl		    "%s : invalid handle 0x%x \n", __func__, handle);
496212420Sken		return;
497230592Sken	}
498212420Sken
499230592Sken	targ->flags |= MPSSAS_TARGET_INREMOVAL;
500230592Sken
501230592Sken	cm = mpssas_alloc_tm(sc);
502212420Sken	if (cm == NULL) {
503253460Sscottl		mps_dprint(sc, MPS_ERROR,
504253460Sscottl		    "%s: command alloc failure\n", __func__);
505212420Sken		return;
506212420Sken	}
507212420Sken
508231240Sken	mpssas_rescan_target(sc, targ);
509218811Sken
510212420Sken	req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)cm->cm_req;
511218811Sken	memset(req, 0, sizeof(*req));
512237683Sken	req->DevHandle = htole16(targ->handle);
513212420Sken	req->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
514212420Sken	req->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
515212420Sken
516212420Sken	/* SAS Hard Link Reset / SATA Link Reset */
517212420Sken	req->MsgFlags = MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET;
518212420Sken
519230592Sken	cm->cm_targ = targ;
520212420Sken	cm->cm_data = NULL;
521230592Sken	cm->cm_desc.HighPriority.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY;
522212420Sken	cm->cm_complete = mpssas_remove_device;
523230592Sken	cm->cm_complete_data = (void *)(uintptr_t)handle;
524230592Sken	mps_map_command(sc, cm);
525212420Sken}
526212420Sken
527212420Skenstatic void
528230592Skenmpssas_remove_device(struct mps_softc *sc, struct mps_command *tm)
529212420Sken{
530212420Sken	MPI2_SCSI_TASK_MANAGE_REPLY *reply;
531212420Sken	MPI2_SAS_IOUNIT_CONTROL_REQUEST *req;
532212420Sken	struct mpssas_target *targ;
533218811Sken	struct mps_command *next_cm;
534212420Sken	uint16_t handle;
535212420Sken
536253460Sscottl	MPS_FUNCTRACE(sc);
537212420Sken
538230592Sken	reply = (MPI2_SCSI_TASK_MANAGE_REPLY *)tm->cm_reply;
539230592Sken	handle = (uint16_t)(uintptr_t)tm->cm_complete_data;
540230592Sken	targ = tm->cm_targ;
541213535Sken
542218812Sken	/*
543218812Sken	 * Currently there should be no way we can hit this case.  It only
544218812Sken	 * happens when we have a failure to allocate chain frames, and
545218812Sken	 * task management commands don't have S/G lists.
546218812Sken	 */
547230592Sken	if ((tm->cm_flags & MPS_CM_FLAGS_ERROR_MASK) != 0) {
548253460Sscottl		mps_dprint(sc, MPS_ERROR,
549253460Sscottl		    "%s: cm_flags = %#x for remove of handle %#04x! "
550253460Sscottl		    "This should not happen!\n", __func__, tm->cm_flags,
551253460Sscottl		    handle);
552230592Sken		mpssas_free_tm(sc, tm);
553218812Sken		return;
554218812Sken	}
555218812Sken
556230592Sken	if (reply == NULL) {
557230592Sken		/* XXX retry the remove after the diag reset completes? */
558253460Sscottl		mps_dprint(sc, MPS_FAULT,
559253460Sscottl		    "%s NULL reply reseting device 0x%04x\n", __func__, handle);
560230592Sken		mpssas_free_tm(sc, tm);
561230592Sken		return;
562230592Sken	}
563230592Sken
564237683Sken	if (le16toh(reply->IOCStatus) != MPI2_IOCSTATUS_SUCCESS) {
565253460Sscottl		mps_dprint(sc, MPS_FAULT,
566253460Sscottl		   "IOCStatus = 0x%x while resetting device 0x%x\n",
567237683Sken		   le16toh(reply->IOCStatus), handle);
568230592Sken		mpssas_free_tm(sc, tm);
569212420Sken		return;
570212420Sken	}
571212420Sken
572253460Sscottl	mps_dprint(sc, MPS_XINFO, "Reset aborted %u commands\n",
573237683Sken	    le32toh(reply->TerminationCount));
574230592Sken	mps_free_reply(sc, tm->cm_reply_data);
575240518Seadler	tm->cm_reply = NULL;	/* Ensures the reply won't get re-freed */
576212420Sken
577212420Sken	/* Reuse the existing command */
578230592Sken	req = (MPI2_SAS_IOUNIT_CONTROL_REQUEST *)tm->cm_req;
579218811Sken	memset(req, 0, sizeof(*req));
580212420Sken	req->Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL;
581212420Sken	req->Operation = MPI2_SAS_OP_REMOVE_DEVICE;
582237683Sken	req->DevHandle = htole16(handle);
583230592Sken	tm->cm_data = NULL;
584230592Sken	tm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
585230592Sken	tm->cm_complete = mpssas_remove_complete;
586230592Sken	tm->cm_complete_data = (void *)(uintptr_t)handle;
587212420Sken
588230592Sken	mps_map_command(sc, tm);
589212420Sken
590253460Sscottl	mps_dprint(sc, MPS_XINFO, "clearing target %u handle 0x%04x\n",
591230592Sken		   targ->tid, handle);
592230592Sken	TAILQ_FOREACH_SAFE(tm, &targ->commands, cm_link, next_cm) {
593218811Sken		union ccb *ccb;
594218811Sken
595253460Sscottl		mps_dprint(sc, MPS_XINFO, "Completing missed command %p\n", tm);
596230592Sken		ccb = tm->cm_complete_data;
597218811Sken		ccb->ccb_h.status = CAM_DEV_NOT_THERE;
598230592Sken		mpssas_scsiio_complete(sc, tm);
599218811Sken	}
600212420Sken}
601212420Sken
602212420Skenstatic void
603230592Skenmpssas_remove_complete(struct mps_softc *sc, struct mps_command *tm)
604212420Sken{
605212420Sken	MPI2_SAS_IOUNIT_CONTROL_REPLY *reply;
606230592Sken	uint16_t handle;
607230592Sken	struct mpssas_target *targ;
608237683Sken	struct mpssas_lun *lun;
609212420Sken
610253460Sscottl	MPS_FUNCTRACE(sc);
611212420Sken
612230592Sken	reply = (MPI2_SAS_IOUNIT_CONTROL_REPLY *)tm->cm_reply;
613230592Sken	handle = (uint16_t)(uintptr_t)tm->cm_complete_data;
614212420Sken
615230592Sken	/*
616230592Sken	 * Currently there should be no way we can hit this case.  It only
617230592Sken	 * happens when we have a failure to allocate chain frames, and
618230592Sken	 * task management commands don't have S/G lists.
619230592Sken	 */
620230592Sken	if ((tm->cm_flags & MPS_CM_FLAGS_ERROR_MASK) != 0) {
621253460Sscottl		mps_dprint(sc, MPS_XINFO,
622253460Sscottl			   "%s: cm_flags = %#x for remove of handle %#04x! "
623230592Sken			   "This should not happen!\n", __func__, tm->cm_flags,
624230592Sken			   handle);
625230592Sken		mpssas_free_tm(sc, tm);
626230592Sken		return;
627230592Sken	}
628212420Sken
629230592Sken	if (reply == NULL) {
630230592Sken		/* most likely a chip reset */
631253460Sscottl		mps_dprint(sc, MPS_FAULT,
632253460Sscottl		    "%s NULL reply removing device 0x%04x\n", __func__, handle);
633230592Sken		mpssas_free_tm(sc, tm);
634230592Sken		return;
635212420Sken	}
636212420Sken
637253460Sscottl	mps_dprint(sc, MPS_XINFO,
638253460Sscottl	    "%s on handle 0x%04x, IOCStatus= 0x%x\n", __func__,
639237683Sken	    handle, le16toh(reply->IOCStatus));
640212420Sken
641230592Sken	/*
642230592Sken	 * Don't clear target if remove fails because things will get confusing.
643230592Sken	 * Leave the devname and sasaddr intact so that we know to avoid reusing
644230592Sken	 * this target id if possible, and so we can assign the same target id
645230592Sken	 * to this device if it comes back in the future.
646230592Sken	 */
647237683Sken	if (le16toh(reply->IOCStatus) == MPI2_IOCSTATUS_SUCCESS) {
648230592Sken		targ = tm->cm_targ;
649230592Sken		targ->handle = 0x0;
650230592Sken		targ->encl_handle = 0x0;
651230592Sken		targ->encl_slot = 0x0;
652230592Sken		targ->exp_dev_handle = 0x0;
653230592Sken		targ->phy_num = 0x0;
654230592Sken		targ->linkrate = 0x0;
655230592Sken		targ->devinfo = 0x0;
656231240Sken		targ->flags = 0x0;
657237683Sken
658237683Sken		while(!SLIST_EMPTY(&targ->luns)) {
659237683Sken			lun = SLIST_FIRST(&targ->luns);
660237683Sken			SLIST_REMOVE_HEAD(&targ->luns, lun_link);
661237683Sken			free(lun, M_MPT2);
662237683Sken		}
663212420Sken	}
664237683Sken
665212420Sken
666230592Sken	mpssas_free_tm(sc, tm);
667212420Sken}
668212420Sken
669212420Skenstatic int
670212420Skenmpssas_register_events(struct mps_softc *sc)
671212420Sken{
672237683Sken	u32 events[MPI2_EVENT_NOTIFY_EVENTMASK_WORDS];
673212420Sken
674212420Sken	bzero(events, 16);
675212420Sken	setbit(events, MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE);
676212420Sken	setbit(events, MPI2_EVENT_SAS_DISCOVERY);
677212420Sken	setbit(events, MPI2_EVENT_SAS_BROADCAST_PRIMITIVE);
678212420Sken	setbit(events, MPI2_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE);
679212420Sken	setbit(events, MPI2_EVENT_SAS_INIT_TABLE_OVERFLOW);
680212420Sken	setbit(events, MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST);
681212420Sken	setbit(events, MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE);
682230592Sken	setbit(events, MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST);
683230592Sken	setbit(events, MPI2_EVENT_IR_VOLUME);
684230592Sken	setbit(events, MPI2_EVENT_IR_PHYSICAL_DISK);
685230592Sken	setbit(events, MPI2_EVENT_IR_OPERATION_STATUS);
686230592Sken	setbit(events, MPI2_EVENT_LOG_ENTRY_ADDED);
687212420Sken
688212420Sken	mps_register_events(sc, events, mpssas_evt_handler, NULL,
689212420Sken	    &sc->sassc->mpssas_eh);
690212420Sken
691212420Sken	return (0);
692212420Sken}
693212420Sken
694212420Skenint
695212420Skenmps_attach_sas(struct mps_softc *sc)
696212420Sken{
697212420Sken	struct mpssas_softc *sassc;
698230592Sken	cam_status status;
699230592Sken	int unit, error = 0;
700212420Sken
701253460Sscottl	MPS_FUNCTRACE(sc);
702212420Sken
703212420Sken	sassc = malloc(sizeof(struct mpssas_softc), M_MPT2, M_WAITOK|M_ZERO);
704237683Sken	if(!sassc) {
705237683Sken		device_printf(sc->mps_dev, "Cannot allocate memory %s %d\n",
706237683Sken		__func__, __LINE__);
707237683Sken		return (ENOMEM);
708237683Sken	}
709212420Sken	sassc->targets = malloc(sizeof(struct mpssas_target) *
710212420Sken	    sc->facts->MaxTargets, M_MPT2, M_WAITOK|M_ZERO);
711237683Sken	if(!sassc->targets) {
712237683Sken		device_printf(sc->mps_dev, "Cannot allocate memory %s %d\n",
713237683Sken		__func__, __LINE__);
714237683Sken		free(sassc, M_MPT2);
715237683Sken		return (ENOMEM);
716237683Sken	}
717212420Sken	sc->sassc = sassc;
718212420Sken	sassc->sc = sc;
719212420Sken
720230592Sken	if ((sassc->devq = cam_simq_alloc(sc->num_reqs)) == NULL) {
721253460Sscottl		mps_dprint(sc, MPS_ERROR, "Cannot allocate SIMQ\n");
722212420Sken		error = ENOMEM;
723212420Sken		goto out;
724212420Sken	}
725212420Sken
726230592Sken	unit = device_get_unit(sc->mps_dev);
727212420Sken	sassc->sim = cam_sim_alloc(mpssas_action, mpssas_poll, "mps", sassc,
728230592Sken	    unit, &sc->mps_mtx, sc->num_reqs, sc->num_reqs, sassc->devq);
729212420Sken	if (sassc->sim == NULL) {
730253460Sscottl		mps_dprint(sc, MPS_ERROR, "Cannot allocate SIM\n");
731212420Sken		error = EINVAL;
732212420Sken		goto out;
733212420Sken	}
734212420Sken
735230592Sken	TAILQ_INIT(&sassc->ev_queue);
736230592Sken
737230592Sken	/* Initialize taskqueue for Event Handling */
738230592Sken	TASK_INIT(&sassc->ev_task, 0, mpssas_firmware_event_work, sc);
739230592Sken	sassc->ev_tq = taskqueue_create("mps_taskq", M_NOWAIT | M_ZERO,
740230592Sken	    taskqueue_thread_enqueue, &sassc->ev_tq);
741230592Sken
742230592Sken	/* Run the task queue with lowest priority */
743230592Sken	taskqueue_start_threads(&sassc->ev_tq, 1, 255, "%s taskq",
744230592Sken	    device_get_nameunit(sc->mps_dev));
745230592Sken
746230592Sken	mps_lock(sc);
747230592Sken
748212420Sken	/*
749212420Sken	 * XXX There should be a bus for every port on the adapter, but since
750212420Sken	 * we're just going to fake the topology for now, we'll pretend that
751212420Sken	 * everything is just a target on a single bus.
752212420Sken	 */
753212420Sken	if ((error = xpt_bus_register(sassc->sim, sc->mps_dev, 0)) != 0) {
754253460Sscottl		mps_dprint(sc, MPS_ERROR, "Error %d registering SCSI bus\n",
755212420Sken		    error);
756212420Sken		mps_unlock(sc);
757212420Sken		goto out;
758212420Sken	}
759212420Sken
760212420Sken	/*
761253549Sken	 * Assume that discovery events will start right away.
762253549Sken	 *
763253549Sken	 * Hold off boot until discovery is complete.
764212420Sken	 */
765230592Sken	sassc->flags |= MPSSAS_IN_STARTUP | MPSSAS_IN_DISCOVERY;
766253549Sken#if __FreeBSD_version >= 1000039
767253549Sken	xpt_hold_boot();
768253549Sken#else
769212420Sken	xpt_freeze_simq(sassc->sim, 1);
770253549Sken#endif
771230592Sken	sc->sassc->startup_refcount = 0;
772212420Sken
773212420Sken	callout_init(&sassc->discovery_callout, 1 /*mpsafe*/);
774212420Sken	sassc->discovery_timeouts = 0;
775212420Sken
776230592Sken	sassc->tm_count = 0;
777230592Sken
778253549Sken	/*
779253549Sken	 * Register for async events so we can determine the EEDP
780253549Sken	 * capabilities of devices.
781253549Sken	 */
782253549Sken	status = xpt_create_path(&sassc->path, /*periph*/NULL,
783253549Sken	    cam_sim_path(sc->sassc->sim), CAM_TARGET_WILDCARD,
784253549Sken	    CAM_LUN_WILDCARD);
785230592Sken	if (status != CAM_REQ_CMP) {
786253549Sken		mps_printf(sc, "Error %#x creating sim path\n", status);
787253549Sken		sassc->path = NULL;
788253549Sken	} else {
789253549Sken		int event;
790253549Sken
791253549Sken#if (__FreeBSD_version >= 1000006) || \
792253549Sken    ((__FreeBSD_version >= 901503) && (__FreeBSD_version < 1000000))
793253549Sken		event = AC_ADVINFO_CHANGED;
794253549Sken#else
795253549Sken		event = AC_FOUND_DEVICE;
796253549Sken#endif
797253549Sken		status = xpt_register_async(event, mpssas_async, sc,
798253549Sken					    sassc->path);
799253549Sken		if (status != CAM_REQ_CMP) {
800253549Sken			mps_dprint(sc, MPS_ERROR,
801253549Sken			    "Error %#x registering async handler for "
802253549Sken			    "AC_ADVINFO_CHANGED events\n", status);
803253549Sken			xpt_free_path(sassc->path);
804253549Sken			sassc->path = NULL;
805253549Sken		}
806230592Sken	}
807253549Sken	if (status != CAM_REQ_CMP) {
808253549Sken		/*
809253549Sken		 * EEDP use is the exception, not the rule.
810253549Sken		 * Warn the user, but do not fail to attach.
811253549Sken		 */
812253549Sken		mps_printf(sc, "EEDP capabilities disabled.\n");
813253549Sken	}
814230592Sken
815230592Sken	mps_unlock(sc);
816230592Sken
817212420Sken	mpssas_register_events(sc);
818212420Skenout:
819212420Sken	if (error)
820212420Sken		mps_detach_sas(sc);
821212420Sken	return (error);
822212420Sken}
823212420Sken
824212420Skenint
825212420Skenmps_detach_sas(struct mps_softc *sc)
826212420Sken{
827212420Sken	struct mpssas_softc *sassc;
828237683Sken	struct mpssas_lun *lun, *lun_tmp;
829237683Sken	struct mpssas_target *targ;
830237683Sken	int i;
831212420Sken
832253460Sscottl	MPS_FUNCTRACE(sc);
833212420Sken
834212420Sken	if (sc->sassc == NULL)
835212420Sken		return (0);
836212420Sken
837212420Sken	sassc = sc->sassc;
838230592Sken	mps_deregister_events(sc, sassc->mpssas_eh);
839212420Sken
840230592Sken	/*
841230592Sken	 * Drain and free the event handling taskqueue with the lock
842230592Sken	 * unheld so that any parallel processing tasks drain properly
843230592Sken	 * without deadlocking.
844230592Sken	 */
845230592Sken	if (sassc->ev_tq != NULL)
846230592Sken		taskqueue_free(sassc->ev_tq);
847230592Sken
848212420Sken	/* Make sure CAM doesn't wedge if we had to bail out early. */
849212420Sken	mps_lock(sc);
850230592Sken
851230592Sken	/* Deregister our async handler */
852253549Sken	if (sassc->path != NULL) {
853253549Sken		xpt_register_async(0, mpssas_async, sc, sassc->path);
854253549Sken		xpt_free_path(sassc->path);
855253549Sken		sassc->path = NULL;
856253549Sken	}
857230592Sken
858212420Sken	if (sassc->flags & MPSSAS_IN_STARTUP)
859212420Sken		xpt_release_simq(sassc->sim, 1);
860212420Sken
861212420Sken	if (sassc->sim != NULL) {
862212420Sken		xpt_bus_deregister(cam_sim_path(sassc->sim));
863212420Sken		cam_sim_free(sassc->sim, FALSE);
864212420Sken	}
865230592Sken
866253549Sken	sassc->flags |= MPSSAS_SHUTDOWN;
867212420Sken	mps_unlock(sc);
868212420Sken
869212420Sken	if (sassc->devq != NULL)
870212420Sken		cam_simq_free(sassc->devq);
871212420Sken
872237683Sken	for(i=0; i< sc->facts->MaxTargets ;i++) {
873237683Sken		targ = &sassc->targets[i];
874237683Sken		SLIST_FOREACH_SAFE(lun, &targ->luns, lun_link, lun_tmp) {
875237683Sken			free(lun, M_MPT2);
876237683Sken		}
877237683Sken	}
878212420Sken	free(sassc->targets, M_MPT2);
879212420Sken	free(sassc, M_MPT2);
880212420Sken	sc->sassc = NULL;
881212420Sken
882212420Sken	return (0);
883212420Sken}
884212420Sken
885230592Skenvoid
886212420Skenmpssas_discovery_end(struct mpssas_softc *sassc)
887212420Sken{
888212420Sken	struct mps_softc *sc = sassc->sc;
889212420Sken
890253460Sscottl	MPS_FUNCTRACE(sc);
891212420Sken
892212420Sken	if (sassc->flags & MPSSAS_DISCOVERY_TIMEOUT_PENDING)
893212420Sken		callout_stop(&sassc->discovery_callout);
894212420Sken
895212420Sken}
896212420Sken
897212420Skenstatic void
898230592Skenmpssas_discovery_timeout(void *data)
899212420Sken{
900230592Sken	struct mpssas_softc *sassc = data;
901230592Sken	struct mps_softc *sc;
902212420Sken
903230592Sken	sc = sassc->sc;
904253460Sscottl	MPS_FUNCTRACE(sc);
905212420Sken
906230592Sken	mps_lock(sc);
907253460Sscottl	mps_dprint(sc, MPS_INFO,
908230592Sken	    "Timeout waiting for discovery, interrupts may not be working!\n");
909230592Sken	sassc->flags &= ~MPSSAS_DISCOVERY_TIMEOUT_PENDING;
910212420Sken
911230592Sken	/* Poll the hardware for events in case interrupts aren't working */
912230592Sken	mps_intr_locked(sc);
913212420Sken
914253460Sscottl	mps_dprint(sassc->sc, MPS_INFO,
915230592Sken	    "Finished polling after discovery timeout at %d\n", ticks);
916230592Sken
917212420Sken	if ((sassc->flags & MPSSAS_IN_DISCOVERY) == 0) {
918212420Sken		mpssas_discovery_end(sassc);
919212420Sken	} else {
920212420Sken		if (sassc->discovery_timeouts < MPSSAS_MAX_DISCOVERY_TIMEOUTS) {
921212420Sken			sassc->flags |= MPSSAS_DISCOVERY_TIMEOUT_PENDING;
922212420Sken			callout_reset(&sassc->discovery_callout,
923212420Sken			    MPSSAS_DISCOVERY_TIMEOUT * hz,
924212420Sken			    mpssas_discovery_timeout, sassc);
925212420Sken			sassc->discovery_timeouts++;
926212420Sken		} else {
927212420Sken			mps_dprint(sassc->sc, MPS_FAULT,
928212420Sken			    "Discovery timed out, continuing.\n");
929212420Sken			sassc->flags &= ~MPSSAS_IN_DISCOVERY;
930212420Sken			mpssas_discovery_end(sassc);
931212420Sken		}
932212420Sken	}
933212420Sken
934212420Sken	mps_unlock(sc);
935212420Sken}
936212420Sken
937212420Skenstatic void
938212420Skenmpssas_action(struct cam_sim *sim, union ccb *ccb)
939212420Sken{
940212420Sken	struct mpssas_softc *sassc;
941212420Sken
942212420Sken	sassc = cam_sim_softc(sim);
943212420Sken
944253460Sscottl	MPS_FUNCTRACE(sassc->sc);
945253460Sscottl	mps_dprint(sassc->sc, MPS_TRACE, "ccb func_code 0x%x\n",
946212420Sken	    ccb->ccb_h.func_code);
947230592Sken	mtx_assert(&sassc->sc->mps_mtx, MA_OWNED);
948212420Sken
949212420Sken	switch (ccb->ccb_h.func_code) {
950212420Sken	case XPT_PATH_INQ:
951212420Sken	{
952212420Sken		struct ccb_pathinq *cpi = &ccb->cpi;
953212420Sken
954212420Sken		cpi->version_num = 1;
955212420Sken		cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE|PI_WIDE_16;
956212420Sken		cpi->target_sprt = 0;
957253549Sken#if __FreeBSD_version >= 1000039
958253549Sken		cpi->hba_misc = PIM_NOBUSRESET | PIM_UNMAPPED | PIM_NOSCAN;
959253549Sken#else
960248825Smav		cpi->hba_misc = PIM_NOBUSRESET | PIM_UNMAPPED;
961253549Sken#endif
962212420Sken		cpi->hba_eng_cnt = 0;
963212420Sken		cpi->max_target = sassc->sc->facts->MaxTargets - 1;
964237683Sken		cpi->max_lun = 255;
965241759Sjwd		cpi->initiator_id = sassc->sc->facts->MaxTargets - 1;
966212420Sken		strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
967212420Sken		strncpy(cpi->hba_vid, "LSILogic", HBA_IDLEN);
968212420Sken		strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
969212420Sken		cpi->unit_number = cam_sim_unit(sim);
970212420Sken		cpi->bus_id = cam_sim_bus(sim);
971212420Sken		cpi->base_transfer_speed = 150000;
972212420Sken		cpi->transport = XPORT_SAS;
973212420Sken		cpi->transport_version = 0;
974212420Sken		cpi->protocol = PROTO_SCSI;
975212420Sken		cpi->protocol_version = SCSI_REV_SPC;
976230592Sken#if __FreeBSD_version >= 800001
977230592Sken		/*
978230592Sken		 * XXX KDM where does this number come from?
979230592Sken		 */
980230592Sken		cpi->maxio = 256 * 1024;
981230592Sken#endif
982212420Sken		cpi->ccb_h.status = CAM_REQ_CMP;
983212420Sken		break;
984212420Sken	}
985212420Sken	case XPT_GET_TRAN_SETTINGS:
986212420Sken	{
987212420Sken		struct ccb_trans_settings	*cts;
988212420Sken		struct ccb_trans_settings_sas	*sas;
989212420Sken		struct ccb_trans_settings_scsi	*scsi;
990212420Sken		struct mpssas_target *targ;
991212420Sken
992212420Sken		cts = &ccb->cts;
993212420Sken		sas = &cts->xport_specific.sas;
994212420Sken		scsi = &cts->proto_specific.scsi;
995212420Sken
996212420Sken		targ = &sassc->targets[cts->ccb_h.target_id];
997212420Sken		if (targ->handle == 0x0) {
998237683Sken			cts->ccb_h.status = CAM_SEL_TIMEOUT;
999212420Sken			break;
1000212420Sken		}
1001212420Sken
1002212420Sken		cts->protocol_version = SCSI_REV_SPC2;
1003212420Sken		cts->transport = XPORT_SAS;
1004212420Sken		cts->transport_version = 0;
1005212420Sken
1006212420Sken		sas->valid = CTS_SAS_VALID_SPEED;
1007212420Sken		switch (targ->linkrate) {
1008212420Sken		case 0x08:
1009212420Sken			sas->bitrate = 150000;
1010212420Sken			break;
1011212420Sken		case 0x09:
1012212420Sken			sas->bitrate = 300000;
1013212420Sken			break;
1014212420Sken		case 0x0a:
1015212420Sken			sas->bitrate = 600000;
1016212420Sken			break;
1017212420Sken		default:
1018212420Sken			sas->valid = 0;
1019212420Sken		}
1020212420Sken
1021212420Sken		cts->protocol = PROTO_SCSI;
1022212420Sken		scsi->valid = CTS_SCSI_VALID_TQ;
1023212420Sken		scsi->flags = CTS_SCSI_FLAGS_TAG_ENB;
1024212420Sken
1025212420Sken		cts->ccb_h.status = CAM_REQ_CMP;
1026212420Sken		break;
1027212420Sken	}
1028212420Sken	case XPT_CALC_GEOMETRY:
1029212420Sken		cam_calc_geometry(&ccb->ccg, /*extended*/1);
1030212420Sken		ccb->ccb_h.status = CAM_REQ_CMP;
1031212420Sken		break;
1032212420Sken	case XPT_RESET_DEV:
1033253460Sscottl		mps_dprint(sassc->sc, MPS_XINFO, "mpssas_action XPT_RESET_DEV\n");
1034212420Sken		mpssas_action_resetdev(sassc, ccb);
1035212420Sken		return;
1036212420Sken	case XPT_RESET_BUS:
1037212420Sken	case XPT_ABORT:
1038212420Sken	case XPT_TERM_IO:
1039253460Sscottl		mps_dprint(sassc->sc, MPS_XINFO,
1040253460Sscottl		    "mpssas_action faking success for abort or reset\n");
1041212420Sken		ccb->ccb_h.status = CAM_REQ_CMP;
1042212420Sken		break;
1043212420Sken	case XPT_SCSI_IO:
1044212420Sken		mpssas_action_scsiio(sassc, ccb);
1045212420Sken		return;
1046216088Sken#if __FreeBSD_version >= 900026
1047216088Sken	case XPT_SMP_IO:
1048216088Sken		mpssas_action_smpio(sassc, ccb);
1049216088Sken		return;
1050230592Sken#endif
1051212420Sken	default:
1052212420Sken		ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
1053212420Sken		break;
1054212420Sken	}
1055212420Sken	xpt_done(ccb);
1056212420Sken
1057212420Sken}
1058212420Sken
1059212420Skenstatic void
1060230592Skenmpssas_announce_reset(struct mps_softc *sc, uint32_t ac_code,
1061230592Sken    target_id_t target_id, lun_id_t lun_id)
1062212420Sken{
1063230592Sken	path_id_t path_id = cam_sim_path(sc->sassc->sim);
1064230592Sken	struct cam_path *path;
1065212420Sken
1066253460Sscottl	mps_dprint(sc, MPS_XINFO, "%s code %x target %d lun %d\n", __func__,
1067230592Sken	    ac_code, target_id, lun_id);
1068212420Sken
1069230592Sken	if (xpt_create_path(&path, NULL,
1070230592Sken		path_id, target_id, lun_id) != CAM_REQ_CMP) {
1071253460Sscottl		mps_dprint(sc, MPS_ERROR, "unable to create path for reset "
1072230592Sken			   "notification\n");
1073230592Sken		return;
1074212420Sken	}
1075212420Sken
1076230592Sken	xpt_async(ac_code, path, NULL);
1077230592Sken	xpt_free_path(path);
1078212420Sken}
1079212420Sken
1080230592Skenstatic void
1081230592Skenmpssas_complete_all_commands(struct mps_softc *sc)
1082212420Sken{
1083212420Sken	struct mps_command *cm;
1084230592Sken	int i;
1085230592Sken	int completed;
1086212420Sken
1087253460Sscottl	MPS_FUNCTRACE(sc);
1088230592Sken	mtx_assert(&sc->mps_mtx, MA_OWNED);
1089212420Sken
1090230592Sken	/* complete all commands with a NULL reply */
1091230592Sken	for (i = 1; i < sc->num_reqs; i++) {
1092230592Sken		cm = &sc->commands[i];
1093230592Sken		cm->cm_reply = NULL;
1094230592Sken		completed = 0;
1095230592Sken
1096230592Sken		if (cm->cm_flags & MPS_CM_FLAGS_POLLED)
1097230592Sken			cm->cm_flags |= MPS_CM_FLAGS_COMPLETE;
1098230592Sken
1099230592Sken		if (cm->cm_complete != NULL) {
1100253460Sscottl			mpssas_log_command(cm, MPS_RECOVERY,
1101230592Sken			    "completing cm %p state %x ccb %p for diag reset\n",
1102230592Sken			    cm, cm->cm_state, cm->cm_ccb);
1103230592Sken
1104230592Sken			cm->cm_complete(sc, cm);
1105230592Sken			completed = 1;
1106230592Sken		}
1107230592Sken
1108230592Sken		if (cm->cm_flags & MPS_CM_FLAGS_WAKEUP) {
1109253460Sscottl			mpssas_log_command(cm, MPS_RECOVERY,
1110230592Sken			    "waking up cm %p state %x ccb %p for diag reset\n",
1111230592Sken			    cm, cm->cm_state, cm->cm_ccb);
1112230592Sken			wakeup(cm);
1113230592Sken			completed = 1;
1114230592Sken		}
1115230592Sken
1116230592Sken		if ((completed == 0) && (cm->cm_state != MPS_CM_STATE_FREE)) {
1117230592Sken			/* this should never happen, but if it does, log */
1118253460Sscottl			mpssas_log_command(cm, MPS_RECOVERY,
1119230592Sken			    "cm %p state %x flags 0x%x ccb %p during diag "
1120230592Sken			    "reset\n", cm, cm->cm_state, cm->cm_flags,
1121230592Sken			    cm->cm_ccb);
1122230592Sken		}
1123212420Sken	}
1124230592Sken}
1125212420Sken
1126230592Skenvoid
1127230592Skenmpssas_handle_reinit(struct mps_softc *sc)
1128230592Sken{
1129230592Sken	int i;
1130212420Sken
1131230592Sken	/* Go back into startup mode and freeze the simq, so that CAM
1132230592Sken	 * doesn't send any commands until after we've rediscovered all
1133230592Sken	 * targets and found the proper device handles for them.
1134230592Sken	 *
1135230592Sken	 * After the reset, portenable will trigger discovery, and after all
1136230592Sken	 * discovery-related activities have finished, the simq will be
1137230592Sken	 * released.
1138212802Sken	 */
1139253460Sscottl	mps_dprint(sc, MPS_INIT, "%s startup\n", __func__);
1140230592Sken	sc->sassc->flags |= MPSSAS_IN_STARTUP;
1141230592Sken	sc->sassc->flags |= MPSSAS_IN_DISCOVERY;
1142230592Sken	xpt_freeze_simq(sc->sassc->sim, 1);
1143212420Sken
1144230592Sken	/* notify CAM of a bus reset */
1145230592Sken	mpssas_announce_reset(sc, AC_BUS_RESET, CAM_TARGET_WILDCARD,
1146230592Sken	    CAM_LUN_WILDCARD);
1147212420Sken
1148230592Sken	/* complete and cleanup after all outstanding commands */
1149230592Sken	mpssas_complete_all_commands(sc);
1150230592Sken
1151253460Sscottl	mps_dprint(sc, MPS_INIT,
1152253460Sscottl	    "%s startup %u tm %u after command completion\n",
1153230592Sken	    __func__, sc->sassc->startup_refcount, sc->sassc->tm_count);
1154230592Sken
1155212420Sken	/*
1156230592Sken	 * The simq was explicitly frozen above, so set the refcount to 0.
1157230592Sken	 * The simq will be explicitly released after port enable completes.
1158212420Sken	 */
1159230592Sken	sc->sassc->startup_refcount = 0;
1160230592Sken
1161230592Sken	/* zero all the target handles, since they may change after the
1162230592Sken	 * reset, and we have to rediscover all the targets and use the new
1163230592Sken	 * handles.
1164230592Sken	 */
1165230592Sken	for (i = 0; i < sc->facts->MaxTargets; i++) {
1166230592Sken		if (sc->sassc->targets[i].outstanding != 0)
1167253460Sscottl			mps_dprint(sc, MPS_INIT, "target %u outstanding %u\n",
1168230592Sken			    i, sc->sassc->targets[i].outstanding);
1169230592Sken		sc->sassc->targets[i].handle = 0x0;
1170230592Sken		sc->sassc->targets[i].exp_dev_handle = 0x0;
1171230592Sken		sc->sassc->targets[i].outstanding = 0;
1172230592Sken		sc->sassc->targets[i].flags = MPSSAS_TARGET_INDIAGRESET;
1173230592Sken	}
1174212420Sken}
1175253460Sscottl
1176230592Skenstatic void
1177230592Skenmpssas_tm_timeout(void *data)
1178230592Sken{
1179230592Sken	struct mps_command *tm = data;
1180230592Sken	struct mps_softc *sc = tm->cm_sc;
1181212420Sken
1182230592Sken	mtx_assert(&sc->mps_mtx, MA_OWNED);
1183230592Sken
1184253460Sscottl	mpssas_log_command(tm, MPS_INFO|MPS_RECOVERY,
1185253460Sscottl	    "task mgmt %p timed out\n", tm);
1186230592Sken	mps_reinit(sc);
1187230592Sken}
1188230592Sken
1189212420Skenstatic void
1190230592Skenmpssas_logical_unit_reset_complete(struct mps_softc *sc, struct mps_command *tm)
1191212420Sken{
1192230592Sken	MPI2_SCSI_TASK_MANAGE_REPLY *reply;
1193212420Sken	MPI2_SCSI_TASK_MANAGE_REQUEST *req;
1194230592Sken	unsigned int cm_count = 0;
1195230592Sken	struct mps_command *cm;
1196230592Sken	struct mpssas_target *targ;
1197212420Sken
1198230592Sken	callout_stop(&tm->cm_callout);
1199212420Sken
1200230592Sken	req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req;
1201230592Sken	reply = (MPI2_SCSI_TASK_MANAGE_REPLY *)tm->cm_reply;
1202230592Sken	targ = tm->cm_targ;
1203230592Sken
1204218812Sken	/*
1205218812Sken	 * Currently there should be no way we can hit this case.  It only
1206218812Sken	 * happens when we have a failure to allocate chain frames, and
1207218812Sken	 * task management commands don't have S/G lists.
1208253460Sscottl	 * XXXSL So should it be an assertion?
1209218812Sken	 */
1210230592Sken	if ((tm->cm_flags & MPS_CM_FLAGS_ERROR_MASK) != 0) {
1211253460Sscottl		mps_dprint(sc, MPS_ERROR, "%s: cm_flags = %#x for LUN reset! "
1212230592Sken			   "This should not happen!\n", __func__, tm->cm_flags);
1213230592Sken		mpssas_free_tm(sc, tm);
1214230592Sken		return;
1215218812Sken	}
1216218812Sken
1217230592Sken	if (reply == NULL) {
1218253460Sscottl		mpssas_log_command(tm, MPS_RECOVERY,
1219253460Sscottl		    "NULL reset reply for tm %p\n", tm);
1220230592Sken		if ((sc->mps_flags & MPS_FLAGS_DIAGRESET) != 0) {
1221230592Sken			/* this completion was due to a reset, just cleanup */
1222230592Sken			targ->flags &= ~MPSSAS_TARGET_INRESET;
1223230592Sken			targ->tm = NULL;
1224230592Sken			mpssas_free_tm(sc, tm);
1225230592Sken		}
1226230592Sken		else {
1227230592Sken			/* we should have gotten a reply. */
1228230592Sken			mps_reinit(sc);
1229230592Sken		}
1230230592Sken		return;
1231230592Sken	}
1232212420Sken
1233253460Sscottl	mpssas_log_command(tm, MPS_RECOVERY,
1234230592Sken	    "logical unit reset status 0x%x code 0x%x count %u\n",
1235237683Sken	    le16toh(reply->IOCStatus), le32toh(reply->ResponseCode),
1236237683Sken	    le32toh(reply->TerminationCount));
1237230592Sken
1238230592Sken	/* See if there are any outstanding commands for this LUN.
1239230592Sken	 * This could be made more efficient by using a per-LU data
1240230592Sken	 * structure of some sort.
1241230592Sken	 */
1242230592Sken	TAILQ_FOREACH(cm, &targ->commands, cm_link) {
1243230592Sken		if (cm->cm_lun == tm->cm_lun)
1244230592Sken			cm_count++;
1245230592Sken	}
1246230592Sken
1247230592Sken	if (cm_count == 0) {
1248253460Sscottl		mpssas_log_command(tm, MPS_RECOVERY|MPS_INFO,
1249230592Sken		    "logical unit %u finished recovery after reset\n",
1250230592Sken		    tm->cm_lun, tm);
1251230592Sken
1252230592Sken		mpssas_announce_reset(sc, AC_SENT_BDR, tm->cm_targ->tid,
1253230592Sken		    tm->cm_lun);
1254230592Sken
1255230592Sken		/* we've finished recovery for this logical unit.  check and
1256230592Sken		 * see if some other logical unit has a timedout command
1257230592Sken		 * that needs to be processed.
1258230592Sken		 */
1259230592Sken		cm = TAILQ_FIRST(&targ->timedout_commands);
1260230592Sken		if (cm) {
1261230592Sken			mpssas_send_abort(sc, tm, cm);
1262230592Sken		}
1263230592Sken		else {
1264230592Sken			targ->tm = NULL;
1265230592Sken			mpssas_free_tm(sc, tm);
1266230592Sken		}
1267230592Sken	}
1268230592Sken	else {
1269230592Sken		/* if we still have commands for this LUN, the reset
1270230592Sken		 * effectively failed, regardless of the status reported.
1271230592Sken		 * Escalate to a target reset.
1272230592Sken		 */
1273253460Sscottl		mpssas_log_command(tm, MPS_RECOVERY,
1274230592Sken		    "logical unit reset complete for tm %p, but still have %u command(s)\n",
1275230592Sken		    tm, cm_count);
1276230592Sken		mpssas_send_reset(sc, tm,
1277230592Sken		    MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET);
1278230592Sken	}
1279212420Sken}
1280212420Sken
1281212420Skenstatic void
1282230592Skenmpssas_target_reset_complete(struct mps_softc *sc, struct mps_command *tm)
1283212420Sken{
1284230592Sken	MPI2_SCSI_TASK_MANAGE_REPLY *reply;
1285230592Sken	MPI2_SCSI_TASK_MANAGE_REQUEST *req;
1286230592Sken	struct mpssas_target *targ;
1287212420Sken
1288230592Sken	callout_stop(&tm->cm_callout);
1289230592Sken
1290230592Sken	req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req;
1291230592Sken	reply = (MPI2_SCSI_TASK_MANAGE_REPLY *)tm->cm_reply;
1292230592Sken	targ = tm->cm_targ;
1293230592Sken
1294230592Sken	/*
1295230592Sken	 * Currently there should be no way we can hit this case.  It only
1296230592Sken	 * happens when we have a failure to allocate chain frames, and
1297230592Sken	 * task management commands don't have S/G lists.
1298230592Sken	 */
1299230592Sken	if ((tm->cm_flags & MPS_CM_FLAGS_ERROR_MASK) != 0) {
1300253460Sscottl		mps_dprint(sc, MPS_ERROR,"%s: cm_flags = %#x for target reset! "
1301230592Sken			   "This should not happen!\n", __func__, tm->cm_flags);
1302230592Sken		mpssas_free_tm(sc, tm);
1303212420Sken		return;
1304212420Sken	}
1305212420Sken
1306230592Sken	if (reply == NULL) {
1307253460Sscottl		mpssas_log_command(tm, MPS_RECOVERY,
1308253460Sscottl		    "NULL reset reply for tm %p\n", tm);
1309230592Sken		if ((sc->mps_flags & MPS_FLAGS_DIAGRESET) != 0) {
1310230592Sken			/* this completion was due to a reset, just cleanup */
1311230592Sken			targ->flags &= ~MPSSAS_TARGET_INRESET;
1312230592Sken			targ->tm = NULL;
1313230592Sken			mpssas_free_tm(sc, tm);
1314230592Sken		}
1315230592Sken		else {
1316230592Sken			/* we should have gotten a reply. */
1317230592Sken			mps_reinit(sc);
1318230592Sken		}
1319230592Sken		return;
1320230592Sken	}
1321212420Sken
1322253460Sscottl	mpssas_log_command(tm, MPS_RECOVERY,
1323230592Sken	    "target reset status 0x%x code 0x%x count %u\n",
1324237683Sken	    le16toh(reply->IOCStatus), le32toh(reply->ResponseCode),
1325237683Sken	    le32toh(reply->TerminationCount));
1326212420Sken
1327230592Sken	targ->flags &= ~MPSSAS_TARGET_INRESET;
1328212420Sken
1329230592Sken	if (targ->outstanding == 0) {
1330230592Sken		/* we've finished recovery for this target and all
1331230592Sken		 * of its logical units.
1332230592Sken		 */
1333253460Sscottl		mpssas_log_command(tm, MPS_RECOVERY|MPS_INFO,
1334230592Sken		    "recovery finished after target reset\n");
1335213535Sken
1336230592Sken		mpssas_announce_reset(sc, AC_SENT_BDR, tm->cm_targ->tid,
1337230592Sken		    CAM_LUN_WILDCARD);
1338230592Sken
1339230592Sken		targ->tm = NULL;
1340230592Sken		mpssas_free_tm(sc, tm);
1341230592Sken	}
1342230592Sken	else {
1343230592Sken		/* after a target reset, if this target still has
1344230592Sken		 * outstanding commands, the reset effectively failed,
1345230592Sken		 * regardless of the status reported.  escalate.
1346230592Sken		 */
1347253460Sscottl		mpssas_log_command(tm, MPS_RECOVERY,
1348230592Sken		    "target reset complete for tm %p, but still have %u command(s)\n",
1349230592Sken		    tm, targ->outstanding);
1350230592Sken		mps_reinit(sc);
1351230592Sken	}
1352213535Sken}
1353213535Sken
1354230592Sken#define MPS_RESET_TIMEOUT 30
1355230592Sken
1356213535Skenstatic int
1357230592Skenmpssas_send_reset(struct mps_softc *sc, struct mps_command *tm, uint8_t type)
1358213535Sken{
1359230592Sken	MPI2_SCSI_TASK_MANAGE_REQUEST *req;
1360230592Sken	struct mpssas_target *target;
1361230592Sken	int err;
1362213535Sken
1363230592Sken	target = tm->cm_targ;
1364230592Sken	if (target->handle == 0) {
1365253460Sscottl		mps_dprint(sc, MPS_ERROR,"%s null devhandle for target_id %d\n",
1366230592Sken		    __func__, target->tid);
1367230592Sken		return -1;
1368230592Sken	}
1369213535Sken
1370230592Sken	req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req;
1371237683Sken	req->DevHandle = htole16(target->handle);
1372230592Sken	req->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
1373230592Sken	req->TaskType = type;
1374213535Sken
1375230592Sken	if (type == MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET) {
1376230592Sken		/* XXX Need to handle invalid LUNs */
1377230592Sken		MPS_SET_LUN(req->LUN, tm->cm_lun);
1378230592Sken		tm->cm_targ->logical_unit_resets++;
1379253460Sscottl		mpssas_log_command(tm, MPS_RECOVERY|MPS_INFO,
1380253460Sscottl		    "sending logical unit reset\n");
1381230592Sken		tm->cm_complete = mpssas_logical_unit_reset_complete;
1382230592Sken	}
1383230592Sken	else if (type == MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET) {
1384230592Sken		/* Target reset method =  SAS Hard Link Reset / SATA Link Reset */
1385230592Sken		req->MsgFlags = MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET;
1386230592Sken		tm->cm_targ->target_resets++;
1387230592Sken		tm->cm_targ->flags |= MPSSAS_TARGET_INRESET;
1388253460Sscottl		mpssas_log_command(tm, MPS_RECOVERY|MPS_INFO,
1389253460Sscottl		    "sending target reset\n");
1390230592Sken		tm->cm_complete = mpssas_target_reset_complete;
1391230592Sken	}
1392230592Sken	else {
1393253460Sscottl		mps_dprint(sc, MPS_ERROR, "unexpected reset type 0x%x\n", type);
1394230592Sken		return -1;
1395230592Sken	}
1396230592Sken
1397230592Sken	tm->cm_data = NULL;
1398230592Sken	tm->cm_desc.HighPriority.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY;
1399230592Sken	tm->cm_complete_data = (void *)tm;
1400230592Sken
1401230592Sken	callout_reset(&tm->cm_callout, MPS_RESET_TIMEOUT * hz,
1402230592Sken	    mpssas_tm_timeout, tm);
1403230592Sken
1404230592Sken	err = mps_map_command(sc, tm);
1405230592Sken	if (err)
1406253460Sscottl		mpssas_log_command(tm, MPS_RECOVERY,
1407230592Sken		    "error %d sending reset type %u\n",
1408230592Sken		    err, type);
1409230592Sken
1410230592Sken	return err;
1411213535Sken}
1412213535Sken
1413230592Sken
1414213535Skenstatic void
1415230592Skenmpssas_abort_complete(struct mps_softc *sc, struct mps_command *tm)
1416213535Sken{
1417230592Sken	struct mps_command *cm;
1418230592Sken	MPI2_SCSI_TASK_MANAGE_REPLY *reply;
1419230592Sken	MPI2_SCSI_TASK_MANAGE_REQUEST *req;
1420230592Sken	struct mpssas_target *targ;
1421213535Sken
1422230592Sken	callout_stop(&tm->cm_callout);
1423213535Sken
1424230592Sken	req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req;
1425230592Sken	reply = (MPI2_SCSI_TASK_MANAGE_REPLY *)tm->cm_reply;
1426230592Sken	targ = tm->cm_targ;
1427213535Sken
1428212772Sken	/*
1429230592Sken	 * Currently there should be no way we can hit this case.  It only
1430230592Sken	 * happens when we have a failure to allocate chain frames, and
1431230592Sken	 * task management commands don't have S/G lists.
1432212772Sken	 */
1433230592Sken	if ((tm->cm_flags & MPS_CM_FLAGS_ERROR_MASK) != 0) {
1434253460Sscottl		mpssas_log_command(tm, MPS_RECOVERY,
1435230592Sken		    "cm_flags = %#x for abort %p TaskMID %u!\n",
1436237683Sken		    tm->cm_flags, tm, le16toh(req->TaskMID));
1437230592Sken		mpssas_free_tm(sc, tm);
1438230592Sken		return;
1439230592Sken	}
1440212772Sken
1441230592Sken	if (reply == NULL) {
1442253460Sscottl		mpssas_log_command(tm, MPS_RECOVERY,
1443230592Sken		    "NULL abort reply for tm %p TaskMID %u\n",
1444237683Sken		    tm, le16toh(req->TaskMID));
1445230592Sken		if ((sc->mps_flags & MPS_FLAGS_DIAGRESET) != 0) {
1446230592Sken			/* this completion was due to a reset, just cleanup */
1447230592Sken			targ->tm = NULL;
1448230592Sken			mpssas_free_tm(sc, tm);
1449230592Sken		}
1450230592Sken		else {
1451230592Sken			/* we should have gotten a reply. */
1452230592Sken			mps_reinit(sc);
1453230592Sken		}
1454230592Sken		return;
1455230592Sken	}
1456212420Sken
1457253460Sscottl	mpssas_log_command(tm, MPS_RECOVERY,
1458230592Sken	    "abort TaskMID %u status 0x%x code 0x%x count %u\n",
1459237683Sken	    le16toh(req->TaskMID),
1460237683Sken	    le16toh(reply->IOCStatus), le32toh(reply->ResponseCode),
1461237683Sken	    le32toh(reply->TerminationCount));
1462213535Sken
1463230592Sken	cm = TAILQ_FIRST(&tm->cm_targ->timedout_commands);
1464230592Sken	if (cm == NULL) {
1465230592Sken		/* if there are no more timedout commands, we're done with
1466230592Sken		 * error recovery for this target.
1467213535Sken		 */
1468253460Sscottl		mpssas_log_command(tm, MPS_RECOVERY,
1469230592Sken		    "finished recovery after aborting TaskMID %u\n",
1470237683Sken		    le16toh(req->TaskMID));
1471230592Sken
1472230592Sken		targ->tm = NULL;
1473230592Sken		mpssas_free_tm(sc, tm);
1474212420Sken	}
1475237683Sken	else if (le16toh(req->TaskMID) != cm->cm_desc.Default.SMID) {
1476230592Sken		/* abort success, but we have more timedout commands to abort */
1477253460Sscottl		mpssas_log_command(tm, MPS_RECOVERY,
1478230592Sken		    "continuing recovery after aborting TaskMID %u\n",
1479237683Sken		    le16toh(req->TaskMID));
1480230592Sken
1481230592Sken		mpssas_send_abort(sc, tm, cm);
1482230592Sken	}
1483230592Sken	else {
1484230592Sken		/* we didn't get a command completion, so the abort
1485230592Sken		 * failed as far as we're concerned.  escalate.
1486230592Sken		 */
1487253460Sscottl		mpssas_log_command(tm, MPS_RECOVERY,
1488230592Sken		    "abort failed for TaskMID %u tm %p\n",
1489237683Sken		    le16toh(req->TaskMID), tm);
1490230592Sken
1491230592Sken		mpssas_send_reset(sc, tm,
1492230592Sken		    MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET);
1493230592Sken	}
1494213535Sken}
1495212420Sken
1496230592Sken#define MPS_ABORT_TIMEOUT 5
1497230592Sken
1498230592Skenstatic int
1499230592Skenmpssas_send_abort(struct mps_softc *sc, struct mps_command *tm, struct mps_command *cm)
1500213535Sken{
1501230592Sken	MPI2_SCSI_TASK_MANAGE_REQUEST *req;
1502230592Sken	struct mpssas_target *targ;
1503230592Sken	int err;
1504212420Sken
1505230592Sken	targ = cm->cm_targ;
1506230592Sken	if (targ->handle == 0) {
1507253460Sscottl		mps_dprint(sc, MPS_ERROR,"%s null devhandle for target_id %d\n",
1508230592Sken		    __func__, cm->cm_ccb->ccb_h.target_id);
1509230592Sken		return -1;
1510230592Sken	}
1511213535Sken
1512253460Sscottl	mpssas_log_command(tm, MPS_RECOVERY|MPS_INFO,
1513253460Sscottl	    "Aborting command %p\n", cm);
1514253460Sscottl
1515230592Sken	req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req;
1516237683Sken	req->DevHandle = htole16(targ->handle);
1517230592Sken	req->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
1518230592Sken	req->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK;
1519213535Sken
1520230592Sken	/* XXX Need to handle invalid LUNs */
1521230592Sken	MPS_SET_LUN(req->LUN, cm->cm_ccb->ccb_h.target_lun);
1522212420Sken
1523237683Sken	req->TaskMID = htole16(cm->cm_desc.Default.SMID);
1524213535Sken
1525230592Sken	tm->cm_data = NULL;
1526230592Sken	tm->cm_desc.HighPriority.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY;
1527230592Sken	tm->cm_complete = mpssas_abort_complete;
1528230592Sken	tm->cm_complete_data = (void *)tm;
1529230592Sken	tm->cm_targ = cm->cm_targ;
1530230592Sken	tm->cm_lun = cm->cm_lun;
1531213535Sken
1532230592Sken	callout_reset(&tm->cm_callout, MPS_ABORT_TIMEOUT * hz,
1533230592Sken	    mpssas_tm_timeout, tm);
1534213535Sken
1535230592Sken	targ->aborts++;
1536213535Sken
1537230592Sken	err = mps_map_command(sc, tm);
1538230592Sken	if (err)
1539253460Sscottl		mpssas_log_command(tm, MPS_RECOVERY,
1540230592Sken		    "error %d sending abort for cm %p SMID %u\n",
1541230592Sken		    err, cm, req->TaskMID);
1542230592Sken	return err;
1543230592Sken}
1544213535Sken
1545213535Sken
1546230592Skenstatic void
1547230592Skenmpssas_scsiio_timeout(void *data)
1548230592Sken{
1549230592Sken	struct mps_softc *sc;
1550230592Sken	struct mps_command *cm;
1551230592Sken	struct mpssas_target *targ;
1552213535Sken
1553230592Sken	cm = (struct mps_command *)data;
1554230592Sken	sc = cm->cm_sc;
1555213535Sken
1556253460Sscottl	MPS_FUNCTRACE(sc);
1557230592Sken	mtx_assert(&sc->mps_mtx, MA_OWNED);
1558213535Sken
1559253460Sscottl	mps_dprint(sc, MPS_XINFO, "Timeout checking cm %p\n", sc);
1560213535Sken
1561230592Sken	/*
1562230592Sken	 * Run the interrupt handler to make sure it's not pending.  This
1563230592Sken	 * isn't perfect because the command could have already completed
1564230592Sken	 * and been re-used, though this is unlikely.
1565230592Sken	 */
1566230592Sken	mps_intr_locked(sc);
1567230592Sken	if (cm->cm_state == MPS_CM_STATE_FREE) {
1568253460Sscottl		mpssas_log_command(cm, MPS_XINFO,
1569253460Sscottl		    "SCSI command %p almost timed out\n", cm);
1570230592Sken		return;
1571230592Sken	}
1572213535Sken
1573230592Sken	if (cm->cm_ccb == NULL) {
1574253460Sscottl		mps_dprint(sc, MPS_ERROR, "command timeout with NULL ccb\n");
1575230592Sken		return;
1576230592Sken	}
1577213535Sken
1578253460Sscottl	mpssas_log_command(cm, MPS_INFO, "command timeout cm %p ccb %p\n",
1579230592Sken	    cm, cm->cm_ccb);
1580213535Sken
1581230592Sken	targ = cm->cm_targ;
1582230592Sken	targ->timeouts++;
1583213535Sken
1584230592Sken	/* XXX first, check the firmware state, to see if it's still
1585230592Sken	 * operational.  if not, do a diag reset.
1586230592Sken	 */
1587230592Sken
1588230592Sken	cm->cm_ccb->ccb_h.status = CAM_CMD_TIMEOUT;
1589230592Sken	cm->cm_state = MPS_CM_STATE_TIMEDOUT;
1590230592Sken	TAILQ_INSERT_TAIL(&targ->timedout_commands, cm, cm_recovery);
1591230592Sken
1592230592Sken	if (targ->tm != NULL) {
1593230592Sken		/* target already in recovery, just queue up another
1594230592Sken		 * timedout command to be processed later.
1595230592Sken		 */
1596253460Sscottl		mps_dprint(sc, MPS_RECOVERY,
1597253460Sscottl		    "queued timedout cm %p for processing by tm %p\n",
1598230592Sken		    cm, targ->tm);
1599213535Sken	}
1600230592Sken	else if ((targ->tm = mpssas_alloc_tm(sc)) != NULL) {
1601253460Sscottl		mps_dprint(sc, MPS_RECOVERY, "timedout cm %p allocated tm %p\n",
1602230592Sken		    cm, targ->tm);
1603213535Sken
1604230592Sken		/* start recovery by aborting the first timedout command */
1605230592Sken		mpssas_send_abort(sc, targ->tm, cm);
1606230592Sken	}
1607230592Sken	else {
1608230592Sken		/* XXX queue this target up for recovery once a TM becomes
1609230592Sken		 * available.  The firmware only has a limited number of
1610230592Sken		 * HighPriority credits for the high priority requests used
1611230592Sken		 * for task management, and we ran out.
1612230592Sken		 *
1613230592Sken		 * Isilon: don't worry about this for now, since we have
1614230592Sken		 * more credits than disks in an enclosure, and limit
1615230592Sken		 * ourselves to one TM per target for recovery.
1616230592Sken		 */
1617253460Sscottl		mps_dprint(sc, MPS_RECOVERY,
1618253460Sscottl		    "timedout cm %p failed to allocate a tm\n", cm);
1619230592Sken	}
1620230592Sken
1621213535Sken}
1622213535Sken
1623212420Skenstatic void
1624212420Skenmpssas_action_scsiio(struct mpssas_softc *sassc, union ccb *ccb)
1625212420Sken{
1626212420Sken	MPI2_SCSI_IO_REQUEST *req;
1627212420Sken	struct ccb_scsiio *csio;
1628212420Sken	struct mps_softc *sc;
1629212420Sken	struct mpssas_target *targ;
1630230592Sken	struct mpssas_lun *lun;
1631212420Sken	struct mps_command *cm;
1632230592Sken	uint8_t i, lba_byte, *ref_tag_addr;
1633230592Sken	uint16_t eedp_flags;
1634237683Sken	uint32_t mpi_control;
1635212420Sken
1636212420Sken	sc = sassc->sc;
1637253460Sscottl	MPS_FUNCTRACE(sc);
1638230592Sken	mtx_assert(&sc->mps_mtx, MA_OWNED);
1639212420Sken
1640212420Sken	csio = &ccb->csio;
1641212420Sken	targ = &sassc->targets[csio->ccb_h.target_id];
1642253460Sscottl	mps_dprint(sc, MPS_TRACE, "ccb %p target flag %x\n", ccb, targ->flags);
1643212420Sken	if (targ->handle == 0x0) {
1644253460Sscottl		mps_dprint(sc, MPS_ERROR, "%s NULL handle for target %u\n",
1645230592Sken		    __func__, csio->ccb_h.target_id);
1646237683Sken		csio->ccb_h.status = CAM_SEL_TIMEOUT;
1647212420Sken		xpt_done(ccb);
1648212420Sken		return;
1649212420Sken	}
1650231240Sken	if (targ->flags & MPS_TARGET_FLAGS_RAID_COMPONENT) {
1651253550Sken		mps_dprint(sc, MPS_ERROR, "%s Raid component no SCSI IO "
1652253550Sken		    "supported %u\n", __func__, csio->ccb_h.target_id);
1653231240Sken		csio->ccb_h.status = CAM_TID_INVALID;
1654231240Sken		xpt_done(ccb);
1655231240Sken		return;
1656231240Sken	}
1657230592Sken	/*
1658253550Sken	 * Sometimes, it is possible to get a command that is not "In
1659253550Sken	 * Progress" and was actually aborted by the upper layer.  Check for
1660253550Sken	 * this here and complete the command without error.
1661253550Sken	 */
1662253550Sken	if (ccb->ccb_h.status != CAM_REQ_INPROG) {
1663253550Sken		mps_dprint(sc, MPS_TRACE, "%s Command is not in progress for "
1664253550Sken		    "target %u\n", __func__, csio->ccb_h.target_id);
1665253550Sken		xpt_done(ccb);
1666253550Sken		return;
1667253550Sken	}
1668253550Sken	/*
1669230592Sken	 * If devinfo is 0 this will be a volume.  In that case don't tell CAM
1670230592Sken	 * that the volume has timed out.  We want volumes to be enumerated
1671230592Sken	 * until they are deleted/removed, not just failed.
1672230592Sken	 */
1673230592Sken	if (targ->flags & MPSSAS_TARGET_INREMOVAL) {
1674230592Sken		if (targ->devinfo == 0)
1675230592Sken			csio->ccb_h.status = CAM_REQ_CMP;
1676230592Sken		else
1677230592Sken			csio->ccb_h.status = CAM_SEL_TIMEOUT;
1678230592Sken		xpt_done(ccb);
1679230592Sken		return;
1680230592Sken	}
1681212420Sken
1682230592Sken	if ((sc->mps_flags & MPS_FLAGS_SHUTDOWN) != 0) {
1683253460Sscottl		mps_dprint(sc, MPS_INFO, "%s shutting down\n", __func__);
1684230592Sken		csio->ccb_h.status = CAM_TID_INVALID;
1685230592Sken		xpt_done(ccb);
1686230592Sken		return;
1687230592Sken	}
1688230592Sken
1689212420Sken	cm = mps_alloc_command(sc);
1690212420Sken	if (cm == NULL) {
1691212420Sken		if ((sassc->flags & MPSSAS_QUEUE_FROZEN) == 0) {
1692212420Sken			xpt_freeze_simq(sassc->sim, 1);
1693212420Sken			sassc->flags |= MPSSAS_QUEUE_FROZEN;
1694212420Sken		}
1695212420Sken		ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
1696212420Sken		ccb->ccb_h.status |= CAM_REQUEUE_REQ;
1697212420Sken		xpt_done(ccb);
1698212420Sken		return;
1699212420Sken	}
1700212420Sken
1701212420Sken	req = (MPI2_SCSI_IO_REQUEST *)cm->cm_req;
1702218812Sken	bzero(req, sizeof(*req));
1703237683Sken	req->DevHandle = htole16(targ->handle);
1704212420Sken	req->Function = MPI2_FUNCTION_SCSI_IO_REQUEST;
1705212420Sken	req->MsgFlags = 0;
1706237683Sken	req->SenseBufferLowAddress = htole32(cm->cm_sense_busaddr);
1707212420Sken	req->SenseBufferLength = MPS_SENSE_LEN;
1708212420Sken	req->SGLFlags = 0;
1709212420Sken	req->ChainOffset = 0;
1710212420Sken	req->SGLOffset0 = 24;	/* 32bit word offset to the SGL */
1711212420Sken	req->SGLOffset1= 0;
1712212420Sken	req->SGLOffset2= 0;
1713212420Sken	req->SGLOffset3= 0;
1714212420Sken	req->SkipCount = 0;
1715237683Sken	req->DataLength = htole32(csio->dxfer_len);
1716212420Sken	req->BidirectionalDataLength = 0;
1717237683Sken	req->IoFlags = htole16(csio->cdb_len);
1718212420Sken	req->EEDPFlags = 0;
1719212420Sken
1720212420Sken	/* Note: BiDirectional transfers are not supported */
1721212420Sken	switch (csio->ccb_h.flags & CAM_DIR_MASK) {
1722212420Sken	case CAM_DIR_IN:
1723237683Sken		mpi_control = MPI2_SCSIIO_CONTROL_READ;
1724212420Sken		cm->cm_flags |= MPS_CM_FLAGS_DATAIN;
1725212420Sken		break;
1726212420Sken	case CAM_DIR_OUT:
1727237683Sken		mpi_control = MPI2_SCSIIO_CONTROL_WRITE;
1728212420Sken		cm->cm_flags |= MPS_CM_FLAGS_DATAOUT;
1729212420Sken		break;
1730212420Sken	case CAM_DIR_NONE:
1731212420Sken	default:
1732237683Sken		mpi_control = MPI2_SCSIIO_CONTROL_NODATATRANSFER;
1733212420Sken		break;
1734212420Sken	}
1735237683Sken
1736253550Sken	if (csio->cdb_len == 32)
1737237683Sken                mpi_control |= 4 << MPI2_SCSIIO_CONTROL_ADDCDBLEN_SHIFT;
1738212420Sken	/*
1739212420Sken	 * It looks like the hardware doesn't require an explicit tag
1740212420Sken	 * number for each transaction.  SAM Task Management not supported
1741212420Sken	 * at the moment.
1742212420Sken	 */
1743212420Sken	switch (csio->tag_action) {
1744212420Sken	case MSG_HEAD_OF_Q_TAG:
1745237683Sken		mpi_control |= MPI2_SCSIIO_CONTROL_HEADOFQ;
1746212420Sken		break;
1747212420Sken	case MSG_ORDERED_Q_TAG:
1748237683Sken		mpi_control |= MPI2_SCSIIO_CONTROL_ORDEREDQ;
1749212420Sken		break;
1750212420Sken	case MSG_ACA_TASK:
1751237683Sken		mpi_control |= MPI2_SCSIIO_CONTROL_ACAQ;
1752212420Sken		break;
1753212420Sken	case CAM_TAG_ACTION_NONE:
1754212420Sken	case MSG_SIMPLE_Q_TAG:
1755212420Sken	default:
1756237683Sken		mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ;
1757212420Sken		break;
1758212420Sken	}
1759237683Sken	mpi_control |= sc->mapping_table[csio->ccb_h.target_id].TLR_bits;
1760237683Sken	req->Control = htole32(mpi_control);
1761216368Sken	if (MPS_SET_LUN(req->LUN, csio->ccb_h.target_lun) != 0) {
1762212420Sken		mps_free_command(sc, cm);
1763212420Sken		ccb->ccb_h.status = CAM_LUN_INVALID;
1764212420Sken		xpt_done(ccb);
1765212420Sken		return;
1766212420Sken	}
1767212420Sken
1768212420Sken	if (csio->ccb_h.flags & CAM_CDB_POINTER)
1769212420Sken		bcopy(csio->cdb_io.cdb_ptr, &req->CDB.CDB32[0], csio->cdb_len);
1770212420Sken	else
1771212420Sken		bcopy(csio->cdb_io.cdb_bytes, &req->CDB.CDB32[0],csio->cdb_len);
1772237683Sken	req->IoFlags = htole16(csio->cdb_len);
1773212420Sken
1774216088Sken	/*
1775230592Sken	 * Check if EEDP is supported and enabled.  If it is then check if the
1776230592Sken	 * SCSI opcode could be using EEDP.  If so, make sure the LUN exists and
1777230592Sken	 * is formatted for EEDP support.  If all of this is true, set CDB up
1778230592Sken	 * for EEDP transfer.
1779216088Sken	 */
1780230592Sken	eedp_flags = op_code_prot[req->CDB.CDB32[0]];
1781230592Sken	if (sc->eedp_enabled && eedp_flags) {
1782230592Sken		SLIST_FOREACH(lun, &targ->luns, lun_link) {
1783230592Sken			if (lun->lun_id == csio->ccb_h.target_lun) {
1784230592Sken				break;
1785230592Sken			}
1786230592Sken		}
1787230592Sken
1788230592Sken		if ((lun != NULL) && (lun->eedp_formatted)) {
1789237683Sken			req->EEDPBlockSize = htole16(lun->eedp_block_size);
1790230592Sken			eedp_flags |= (MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG |
1791230592Sken			    MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG |
1792230592Sken			    MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD);
1793237683Sken			req->EEDPFlags = htole16(eedp_flags);
1794230592Sken
1795230592Sken			/*
1796230592Sken			 * If CDB less than 32, fill in Primary Ref Tag with
1797230592Sken			 * low 4 bytes of LBA.  If CDB is 32, tag stuff is
1798230592Sken			 * already there.  Also, set protection bit.  FreeBSD
1799230592Sken			 * currently does not support CDBs bigger than 16, but
1800230592Sken			 * the code doesn't hurt, and will be here for the
1801230592Sken			 * future.
1802230592Sken			 */
1803230592Sken			if (csio->cdb_len != 32) {
1804230592Sken				lba_byte = (csio->cdb_len == 16) ? 6 : 2;
1805230592Sken				ref_tag_addr = (uint8_t *)&req->CDB.EEDP32.
1806230592Sken				    PrimaryReferenceTag;
1807230592Sken				for (i = 0; i < 4; i++) {
1808230592Sken					*ref_tag_addr =
1809230592Sken					    req->CDB.CDB32[lba_byte + i];
1810230592Sken					ref_tag_addr++;
1811230592Sken				}
1812237683Sken				req->CDB.EEDP32.PrimaryReferenceTag =
1813237683Sken					htole32(req->CDB.EEDP32.PrimaryReferenceTag);
1814230592Sken				req->CDB.EEDP32.PrimaryApplicationTagMask =
1815230592Sken				    0xFFFF;
1816230592Sken				req->CDB.CDB32[1] = (req->CDB.CDB32[1] & 0x1F) |
1817230592Sken				    0x20;
1818230592Sken			} else {
1819230592Sken				eedp_flags |=
1820230592Sken				    MPI2_SCSIIO_EEDPFLAGS_INC_PRI_APPTAG;
1821237683Sken				req->EEDPFlags = htole16(eedp_flags);
1822230592Sken				req->CDB.CDB32[10] = (req->CDB.CDB32[10] &
1823230592Sken				    0x1F) | 0x20;
1824230592Sken			}
1825230592Sken		}
1826230592Sken	}
1827230592Sken
1828212420Sken	cm->cm_length = csio->dxfer_len;
1829246713Skib	if (cm->cm_length != 0) {
1830246713Skib		cm->cm_data = ccb;
1831246713Skib		cm->cm_flags |= MPS_CM_FLAGS_USE_CCB;
1832246713Skib	} else {
1833246713Skib		cm->cm_data = NULL;
1834246713Skib	}
1835212420Sken	cm->cm_sge = &req->SGL;
1836212420Sken	cm->cm_sglsize = (32 - 24) * 4;
1837212420Sken	cm->cm_desc.SCSIIO.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO;
1838237683Sken	cm->cm_desc.SCSIIO.DevHandle = htole16(targ->handle);
1839212420Sken	cm->cm_complete = mpssas_scsiio_complete;
1840212420Sken	cm->cm_complete_data = ccb;
1841212420Sken	cm->cm_targ = targ;
1842230592Sken	cm->cm_lun = csio->ccb_h.target_lun;
1843230592Sken	cm->cm_ccb = ccb;
1844212420Sken
1845230592Sken	/*
1846230592Sken	 * If HBA is a WD and the command is not for a retry, try to build a
1847230592Sken	 * direct I/O message. If failed, or the command is for a retry, send
1848230592Sken	 * the I/O to the IR volume itself.
1849230592Sken	 */
1850230592Sken	if (sc->WD_valid_config) {
1851230592Sken		if (ccb->ccb_h.status != MPS_WD_RETRY) {
1852230592Sken			mpssas_direct_drive_io(sassc, cm, ccb);
1853230592Sken		} else {
1854230592Sken			ccb->ccb_h.status = CAM_REQ_INPROG;
1855230592Sken		}
1856230592Sken	}
1857218812Sken
1858212420Sken	callout_reset(&cm->cm_callout, (ccb->ccb_h.timeout * hz) / 1000,
1859212420Sken	   mpssas_scsiio_timeout, cm);
1860212420Sken
1861230592Sken	targ->issued++;
1862230592Sken	targ->outstanding++;
1863230592Sken	TAILQ_INSERT_TAIL(&targ->commands, cm, cm_link);
1864253550Sken	ccb->ccb_h.status |= CAM_SIM_QUEUED;
1865230592Sken
1866253460Sscottl	mpssas_log_command(cm, MPS_XINFO, "%s cm %p ccb %p outstanding %u\n",
1867253460Sscottl	    __func__, cm, ccb, targ->outstanding);
1868230592Sken
1869212420Sken	mps_map_command(sc, cm);
1870212420Sken	return;
1871212420Sken}
1872212420Sken
1873212420Skenstatic void
1874231240Skenmps_response_code(struct mps_softc *sc, u8 response_code)
1875231240Sken{
1876231240Sken        char *desc;
1877231240Sken
1878231240Sken        switch (response_code) {
1879231240Sken        case MPI2_SCSITASKMGMT_RSP_TM_COMPLETE:
1880231240Sken                desc = "task management request completed";
1881231240Sken                break;
1882231240Sken        case MPI2_SCSITASKMGMT_RSP_INVALID_FRAME:
1883231240Sken                desc = "invalid frame";
1884231240Sken                break;
1885231240Sken        case MPI2_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED:
1886231240Sken                desc = "task management request not supported";
1887231240Sken                break;
1888231240Sken        case MPI2_SCSITASKMGMT_RSP_TM_FAILED:
1889231240Sken                desc = "task management request failed";
1890231240Sken                break;
1891231240Sken        case MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED:
1892231240Sken                desc = "task management request succeeded";
1893231240Sken                break;
1894231240Sken        case MPI2_SCSITASKMGMT_RSP_TM_INVALID_LUN:
1895231240Sken                desc = "invalid lun";
1896231240Sken                break;
1897231240Sken        case 0xA:
1898231240Sken                desc = "overlapped tag attempted";
1899231240Sken                break;
1900231240Sken        case MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC:
1901231240Sken                desc = "task queued, however not sent to target";
1902231240Sken                break;
1903231240Sken        default:
1904231240Sken                desc = "unknown";
1905231240Sken                break;
1906231240Sken        }
1907253460Sscottl		mps_dprint(sc, MPS_XINFO, "response_code(0x%01x): %s\n",
1908231240Sken                response_code, desc);
1909231240Sken}
1910231240Sken/**
1911231240Sken * mps_sc_failed_io_info - translated non-succesfull SCSI_IO request
1912231240Sken */
1913231240Skenstatic void
1914231240Skenmps_sc_failed_io_info(struct mps_softc *sc, struct ccb_scsiio *csio,
1915231240Sken    Mpi2SCSIIOReply_t *mpi_reply)
1916231240Sken{
1917231240Sken	u32 response_info;
1918231240Sken	u8 *response_bytes;
1919231240Sken	u16 ioc_status = le16toh(mpi_reply->IOCStatus) &
1920231240Sken	    MPI2_IOCSTATUS_MASK;
1921231240Sken	u8 scsi_state = mpi_reply->SCSIState;
1922231240Sken	u8 scsi_status = mpi_reply->SCSIStatus;
1923231240Sken	char *desc_ioc_state = NULL;
1924231240Sken	char *desc_scsi_status = NULL;
1925231240Sken	char *desc_scsi_state = sc->tmp_string;
1926231240Sken	u32 log_info = le32toh(mpi_reply->IOCLogInfo);
1927231240Sken
1928231240Sken	if (log_info == 0x31170000)
1929231240Sken		return;
1930231240Sken
1931231240Sken	switch (ioc_status) {
1932231240Sken	case MPI2_IOCSTATUS_SUCCESS:
1933231240Sken		desc_ioc_state = "success";
1934231240Sken		break;
1935231240Sken	case MPI2_IOCSTATUS_INVALID_FUNCTION:
1936231240Sken		desc_ioc_state = "invalid function";
1937231240Sken		break;
1938231240Sken	case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR:
1939231240Sken		desc_ioc_state = "scsi recovered error";
1940231240Sken		break;
1941231240Sken	case MPI2_IOCSTATUS_SCSI_INVALID_DEVHANDLE:
1942231240Sken		desc_ioc_state = "scsi invalid dev handle";
1943231240Sken		break;
1944231240Sken	case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
1945231240Sken		desc_ioc_state = "scsi device not there";
1946231240Sken		break;
1947231240Sken	case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN:
1948231240Sken		desc_ioc_state = "scsi data overrun";
1949231240Sken		break;
1950231240Sken	case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN:
1951231240Sken		desc_ioc_state = "scsi data underrun";
1952231240Sken		break;
1953231240Sken	case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR:
1954231240Sken		desc_ioc_state = "scsi io data error";
1955231240Sken		break;
1956231240Sken	case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR:
1957231240Sken		desc_ioc_state = "scsi protocol error";
1958231240Sken		break;
1959231240Sken	case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED:
1960231240Sken		desc_ioc_state = "scsi task terminated";
1961231240Sken		break;
1962231240Sken	case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
1963231240Sken		desc_ioc_state = "scsi residual mismatch";
1964231240Sken		break;
1965231240Sken	case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
1966231240Sken		desc_ioc_state = "scsi task mgmt failed";
1967231240Sken		break;
1968231240Sken	case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED:
1969231240Sken		desc_ioc_state = "scsi ioc terminated";
1970231240Sken		break;
1971231240Sken	case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED:
1972231240Sken		desc_ioc_state = "scsi ext terminated";
1973231240Sken		break;
1974231240Sken	case MPI2_IOCSTATUS_EEDP_GUARD_ERROR:
1975231240Sken		desc_ioc_state = "eedp guard error";
1976231240Sken		break;
1977231240Sken	case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR:
1978231240Sken		desc_ioc_state = "eedp ref tag error";
1979231240Sken		break;
1980231240Sken	case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR:
1981231240Sken		desc_ioc_state = "eedp app tag error";
1982231240Sken		break;
1983231240Sken	default:
1984231240Sken		desc_ioc_state = "unknown";
1985231240Sken		break;
1986231240Sken	}
1987231240Sken
1988231240Sken	switch (scsi_status) {
1989231240Sken	case MPI2_SCSI_STATUS_GOOD:
1990231240Sken		desc_scsi_status = "good";
1991231240Sken		break;
1992231240Sken	case MPI2_SCSI_STATUS_CHECK_CONDITION:
1993231240Sken		desc_scsi_status = "check condition";
1994231240Sken		break;
1995231240Sken	case MPI2_SCSI_STATUS_CONDITION_MET:
1996231240Sken		desc_scsi_status = "condition met";
1997231240Sken		break;
1998231240Sken	case MPI2_SCSI_STATUS_BUSY:
1999231240Sken		desc_scsi_status = "busy";
2000231240Sken		break;
2001231240Sken	case MPI2_SCSI_STATUS_INTERMEDIATE:
2002231240Sken		desc_scsi_status = "intermediate";
2003231240Sken		break;
2004231240Sken	case MPI2_SCSI_STATUS_INTERMEDIATE_CONDMET:
2005231240Sken		desc_scsi_status = "intermediate condmet";
2006231240Sken		break;
2007231240Sken	case MPI2_SCSI_STATUS_RESERVATION_CONFLICT:
2008231240Sken		desc_scsi_status = "reservation conflict";
2009231240Sken		break;
2010231240Sken	case MPI2_SCSI_STATUS_COMMAND_TERMINATED:
2011231240Sken		desc_scsi_status = "command terminated";
2012231240Sken		break;
2013231240Sken	case MPI2_SCSI_STATUS_TASK_SET_FULL:
2014231240Sken		desc_scsi_status = "task set full";
2015231240Sken		break;
2016231240Sken	case MPI2_SCSI_STATUS_ACA_ACTIVE:
2017231240Sken		desc_scsi_status = "aca active";
2018231240Sken		break;
2019231240Sken	case MPI2_SCSI_STATUS_TASK_ABORTED:
2020231240Sken		desc_scsi_status = "task aborted";
2021231240Sken		break;
2022231240Sken	default:
2023231240Sken		desc_scsi_status = "unknown";
2024231240Sken		break;
2025231240Sken	}
2026231240Sken
2027231240Sken	desc_scsi_state[0] = '\0';
2028231240Sken	if (!scsi_state)
2029231240Sken		desc_scsi_state = " ";
2030231240Sken	if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID)
2031231240Sken		strcat(desc_scsi_state, "response info ");
2032231240Sken	if (scsi_state & MPI2_SCSI_STATE_TERMINATED)
2033231240Sken		strcat(desc_scsi_state, "state terminated ");
2034231240Sken	if (scsi_state & MPI2_SCSI_STATE_NO_SCSI_STATUS)
2035231240Sken		strcat(desc_scsi_state, "no status ");
2036231240Sken	if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_FAILED)
2037231240Sken		strcat(desc_scsi_state, "autosense failed ");
2038231240Sken	if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID)
2039231240Sken		strcat(desc_scsi_state, "autosense valid ");
2040231240Sken
2041253460Sscottl	mps_dprint(sc, MPS_XINFO, "\thandle(0x%04x), ioc_status(%s)(0x%04x)\n",
2042253460Sscottl	    le16toh(mpi_reply->DevHandle), desc_ioc_state, ioc_status);
2043231240Sken	/* We can add more detail about underflow data here
2044231240Sken	 * TO-DO
2045231240Sken	 * */
2046253460Sscottl	mps_dprint(sc, MPS_XINFO, "\tscsi_status(%s)(0x%02x), "
2047253550Sken	    "scsi_state(%s)(0x%02x)\n", desc_scsi_status, scsi_status,
2048253550Sken	    desc_scsi_state, scsi_state);
2049231240Sken
2050253460Sscottl	if (sc->mps_debug & MPS_XINFO &&
2051231240Sken		scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID) {
2052253460Sscottl		mps_dprint(sc, MPS_XINFO, "-> Sense Buffer Data : Start :\n");
2053231240Sken		scsi_sense_print(csio);
2054253460Sscottl		mps_dprint(sc, MPS_XINFO, "-> Sense Buffer Data : End :\n");
2055231240Sken	}
2056231240Sken
2057231240Sken	if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) {
2058231240Sken		response_info = le32toh(mpi_reply->ResponseInfo);
2059231240Sken		response_bytes = (u8 *)&response_info;
2060231240Sken		mps_response_code(sc,response_bytes[0]);
2061231240Sken	}
2062231240Sken}
2063231240Sken
2064231240Skenstatic void
2065212420Skenmpssas_scsiio_complete(struct mps_softc *sc, struct mps_command *cm)
2066212420Sken{
2067212420Sken	MPI2_SCSI_IO_REPLY *rep;
2068212420Sken	union ccb *ccb;
2069230592Sken	struct ccb_scsiio *csio;
2070212420Sken	struct mpssas_softc *sassc;
2071230592Sken	struct scsi_vpd_supported_page_list *vpd_list = NULL;
2072230592Sken	u8 *TLR_bits, TLR_on;
2073230592Sken	int dir = 0, i;
2074230592Sken	u16 alloc_len;
2075212420Sken
2076253460Sscottl	MPS_FUNCTRACE(sc);
2077230592Sken	mps_dprint(sc, MPS_TRACE,
2078253460Sscottl	    "cm %p SMID %u ccb %p reply %p outstanding %u\n", cm,
2079253460Sscottl	    cm->cm_desc.Default.SMID, cm->cm_ccb, cm->cm_reply,
2080230592Sken	    cm->cm_targ->outstanding);
2081212420Sken
2082212420Sken	callout_stop(&cm->cm_callout);
2083230592Sken	mtx_assert(&sc->mps_mtx, MA_OWNED);
2084212420Sken
2085212420Sken	sassc = sc->sassc;
2086212420Sken	ccb = cm->cm_complete_data;
2087230592Sken	csio = &ccb->csio;
2088212420Sken	rep = (MPI2_SCSI_IO_REPLY *)cm->cm_reply;
2089218812Sken	/*
2090218812Sken	 * XXX KDM if the chain allocation fails, does it matter if we do
2091218812Sken	 * the sync and unload here?  It is simpler to do it in every case,
2092218812Sken	 * assuming it doesn't cause problems.
2093218812Sken	 */
2094212420Sken	if (cm->cm_data != NULL) {
2095212420Sken		if (cm->cm_flags & MPS_CM_FLAGS_DATAIN)
2096212420Sken			dir = BUS_DMASYNC_POSTREAD;
2097212420Sken		else if (cm->cm_flags & MPS_CM_FLAGS_DATAOUT)
2098241844Seadler			dir = BUS_DMASYNC_POSTWRITE;
2099212420Sken		bus_dmamap_sync(sc->buffer_dmat, cm->cm_dmamap, dir);
2100212420Sken		bus_dmamap_unload(sc->buffer_dmat, cm->cm_dmamap);
2101212420Sken	}
2102212420Sken
2103230592Sken	cm->cm_targ->completed++;
2104230592Sken	cm->cm_targ->outstanding--;
2105230592Sken	TAILQ_REMOVE(&cm->cm_targ->commands, cm, cm_link);
2106254615Sken	ccb->ccb_h.status &= ~(CAM_STATUS_MASK | CAM_SIM_QUEUED);
2107230592Sken
2108230592Sken	if (cm->cm_state == MPS_CM_STATE_TIMEDOUT) {
2109230592Sken		TAILQ_REMOVE(&cm->cm_targ->timedout_commands, cm, cm_recovery);
2110230592Sken		if (cm->cm_reply != NULL)
2111253460Sscottl			mpssas_log_command(cm, MPS_RECOVERY,
2112230592Sken			    "completed timedout cm %p ccb %p during recovery "
2113230592Sken			    "ioc %x scsi %x state %x xfer %u\n",
2114230592Sken			    cm, cm->cm_ccb,
2115237683Sken			    le16toh(rep->IOCStatus), rep->SCSIStatus, rep->SCSIState,
2116237683Sken			    le32toh(rep->TransferCount));
2117230592Sken		else
2118253460Sscottl			mpssas_log_command(cm, MPS_RECOVERY,
2119230592Sken			    "completed timedout cm %p ccb %p during recovery\n",
2120230592Sken			    cm, cm->cm_ccb);
2121230592Sken	} else if (cm->cm_targ->tm != NULL) {
2122230592Sken		if (cm->cm_reply != NULL)
2123253460Sscottl			mpssas_log_command(cm, MPS_RECOVERY,
2124230592Sken			    "completed cm %p ccb %p during recovery "
2125230592Sken			    "ioc %x scsi %x state %x xfer %u\n",
2126230592Sken			    cm, cm->cm_ccb,
2127237683Sken			    le16toh(rep->IOCStatus), rep->SCSIStatus, rep->SCSIState,
2128237683Sken			    le32toh(rep->TransferCount));
2129230592Sken		else
2130253460Sscottl			mpssas_log_command(cm, MPS_RECOVERY,
2131230592Sken			    "completed cm %p ccb %p during recovery\n",
2132230592Sken			    cm, cm->cm_ccb);
2133230592Sken	} else if ((sc->mps_flags & MPS_FLAGS_DIAGRESET) != 0) {
2134253460Sscottl		mpssas_log_command(cm, MPS_RECOVERY,
2135230592Sken		    "reset completed cm %p ccb %p\n",
2136230592Sken		    cm, cm->cm_ccb);
2137230592Sken	}
2138230592Sken
2139218812Sken	if ((cm->cm_flags & MPS_CM_FLAGS_ERROR_MASK) != 0) {
2140218812Sken		/*
2141218812Sken		 * We ran into an error after we tried to map the command,
2142218812Sken		 * so we're getting a callback without queueing the command
2143218812Sken		 * to the hardware.  So we set the status here, and it will
2144218812Sken		 * be retained below.  We'll go through the "fast path",
2145218812Sken		 * because there can be no reply when we haven't actually
2146218812Sken		 * gone out to the hardware.
2147218812Sken		 */
2148254615Sken		ccb->ccb_h.status = CAM_REQUEUE_REQ;
2149218812Sken
2150218812Sken		/*
2151218812Sken		 * Currently the only error included in the mask is
2152218812Sken		 * MPS_CM_FLAGS_CHAIN_FAILED, which means we're out of
2153218812Sken		 * chain frames.  We need to freeze the queue until we get
2154218812Sken		 * a command that completed without this error, which will
2155218812Sken		 * hopefully have some chain frames attached that we can
2156218812Sken		 * use.  If we wanted to get smarter about it, we would
2157218812Sken		 * only unfreeze the queue in this condition when we're
2158218812Sken		 * sure that we're getting some chain frames back.  That's
2159218812Sken		 * probably unnecessary.
2160218812Sken		 */
2161218812Sken		if ((sassc->flags & MPSSAS_QUEUE_FROZEN) == 0) {
2162218812Sken			xpt_freeze_simq(sassc->sim, 1);
2163218812Sken			sassc->flags |= MPSSAS_QUEUE_FROZEN;
2164253460Sscottl			mps_dprint(sc, MPS_XINFO, "Error sending command, "
2165219036Sken				   "freezing SIM queue\n");
2166218812Sken		}
2167212420Sken	}
2168212420Sken
2169212420Sken	/* Take the fast path to completion */
2170212420Sken	if (cm->cm_reply == NULL) {
2171218811Sken		if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INPROG) {
2172230592Sken			if ((sc->mps_flags & MPS_FLAGS_DIAGRESET) != 0)
2173230592Sken				ccb->ccb_h.status = CAM_SCSI_BUS_RESET;
2174230592Sken			else {
2175230592Sken				ccb->ccb_h.status = CAM_REQ_CMP;
2176230592Sken				ccb->csio.scsi_status = SCSI_STATUS_OK;
2177230592Sken			}
2178218812Sken			if (sassc->flags & MPSSAS_QUEUE_FROZEN) {
2179218812Sken				ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
2180218812Sken				sassc->flags &= ~MPSSAS_QUEUE_FROZEN;
2181253460Sscottl				mps_dprint(sc, MPS_XINFO,
2182253550Sken				    "Unfreezing SIM queue\n");
2183218812Sken			}
2184230592Sken		}
2185230592Sken
2186230592Sken		/*
2187230592Sken		 * There are two scenarios where the status won't be
2188230592Sken		 * CAM_REQ_CMP.  The first is if MPS_CM_FLAGS_ERROR_MASK is
2189230592Sken		 * set, the second is in the MPS_FLAGS_DIAGRESET above.
2190230592Sken		 */
2191230592Sken		if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
2192230592Sken			/*
2193230592Sken			 * Freeze the dev queue so that commands are
2194230592Sken			 * executed in the correct order with after error
2195230592Sken			 * recovery.
2196230592Sken			 */
2197218812Sken			ccb->ccb_h.status |= CAM_DEV_QFRZN;
2198218812Sken			xpt_freeze_devq(ccb->ccb_h.path, /*count*/ 1);
2199218811Sken		}
2200212420Sken		mps_free_command(sc, cm);
2201212420Sken		xpt_done(ccb);
2202212420Sken		return;
2203212420Sken	}
2204212420Sken
2205253460Sscottl	mpssas_log_command(cm, MPS_XINFO,
2206253460Sscottl	    "ioc %x scsi %x state %x xfer %u\n",
2207253460Sscottl	    le16toh(rep->IOCStatus), rep->SCSIStatus, rep->SCSIState,
2208253460Sscottl	    le32toh(rep->TransferCount));
2209212420Sken
2210230592Sken	/*
2211230592Sken	 * If this is a Direct Drive I/O, reissue the I/O to the original IR
2212230592Sken	 * Volume if an error occurred (normal I/O retry).  Use the original
2213230592Sken	 * CCB, but set a flag that this will be a retry so that it's sent to
2214230592Sken	 * the original volume.  Free the command but reuse the CCB.
2215230592Sken	 */
2216230592Sken	if (cm->cm_flags & MPS_CM_FLAGS_DD_IO) {
2217230592Sken		mps_free_command(sc, cm);
2218230592Sken		ccb->ccb_h.status = MPS_WD_RETRY;
2219230592Sken		mpssas_action_scsiio(sassc, ccb);
2220230592Sken		return;
2221230592Sken	}
2222230592Sken
2223237683Sken	switch (le16toh(rep->IOCStatus) & MPI2_IOCSTATUS_MASK) {
2224212420Sken	case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN:
2225237683Sken		csio->resid = cm->cm_length - le32toh(rep->TransferCount);
2226212420Sken		/* FALLTHROUGH */
2227212420Sken	case MPI2_IOCSTATUS_SUCCESS:
2228212420Sken	case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR:
2229230592Sken
2230237683Sken		if ((le16toh(rep->IOCStatus) & MPI2_IOCSTATUS_MASK) ==
2231230592Sken		    MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR)
2232253460Sscottl			mpssas_log_command(cm, MPS_XINFO, "recovered error\n");
2233230592Sken
2234230592Sken		/* Completion failed at the transport level. */
2235230592Sken		if (rep->SCSIState & (MPI2_SCSI_STATE_NO_SCSI_STATUS |
2236230592Sken		    MPI2_SCSI_STATE_TERMINATED)) {
2237230592Sken			ccb->ccb_h.status = CAM_REQ_CMP_ERR;
2238230592Sken			break;
2239230592Sken		}
2240230592Sken
2241230592Sken		/* In a modern packetized environment, an autosense failure
2242230592Sken		 * implies that there's not much else that can be done to
2243230592Sken		 * recover the command.
2244230592Sken		 */
2245230592Sken		if (rep->SCSIState & MPI2_SCSI_STATE_AUTOSENSE_FAILED) {
2246230592Sken			ccb->ccb_h.status = CAM_AUTOSENSE_FAIL;
2247230592Sken			break;
2248230592Sken		}
2249230592Sken
2250230592Sken		/*
2251230592Sken		 * CAM doesn't care about SAS Response Info data, but if this is
2252230592Sken		 * the state check if TLR should be done.  If not, clear the
2253230592Sken		 * TLR_bits for the target.
2254230592Sken		 */
2255230592Sken		if ((rep->SCSIState & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) &&
2256237683Sken		    ((le32toh(rep->ResponseInfo) & MPI2_SCSI_RI_MASK_REASONCODE) ==
2257230592Sken		    MPS_SCSI_RI_INVALID_FRAME)) {
2258230592Sken			sc->mapping_table[csio->ccb_h.target_id].TLR_bits =
2259230592Sken			    (u8)MPI2_SCSIIO_CONTROL_NO_TLR;
2260230592Sken		}
2261230592Sken
2262230592Sken		/*
2263230592Sken		 * Intentionally override the normal SCSI status reporting
2264230592Sken		 * for these two cases.  These are likely to happen in a
2265230592Sken		 * multi-initiator environment, and we want to make sure that
2266230592Sken		 * CAM retries these commands rather than fail them.
2267230592Sken		 */
2268230592Sken		if ((rep->SCSIStatus == MPI2_SCSI_STATUS_COMMAND_TERMINATED) ||
2269230592Sken		    (rep->SCSIStatus == MPI2_SCSI_STATUS_TASK_ABORTED)) {
2270230592Sken			ccb->ccb_h.status = CAM_REQ_ABORTED;
2271230592Sken			break;
2272230592Sken		}
2273230592Sken
2274230592Sken		/* Handle normal status and sense */
2275230592Sken		csio->scsi_status = rep->SCSIStatus;
2276230592Sken		if (rep->SCSIStatus == MPI2_SCSI_STATUS_GOOD)
2277230592Sken			ccb->ccb_h.status = CAM_REQ_CMP;
2278230592Sken		else
2279230592Sken			ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR;
2280230592Sken
2281230592Sken		if (rep->SCSIState & MPI2_SCSI_STATE_AUTOSENSE_VALID) {
2282230592Sken			int sense_len, returned_sense_len;
2283230592Sken
2284237683Sken			returned_sense_len = min(le32toh(rep->SenseCount),
2285230592Sken			    sizeof(struct scsi_sense_data));
2286230592Sken			if (returned_sense_len < ccb->csio.sense_len)
2287230592Sken				ccb->csio.sense_resid = ccb->csio.sense_len -
2288230592Sken					returned_sense_len;
2289230592Sken			else
2290230592Sken				ccb->csio.sense_resid = 0;
2291230592Sken
2292230592Sken			sense_len = min(returned_sense_len,
2293230592Sken			    ccb->csio.sense_len - ccb->csio.sense_resid);
2294230592Sken			bzero(&ccb->csio.sense_data,
2295237546Skevlo			      sizeof(ccb->csio.sense_data));
2296230592Sken			bcopy(cm->cm_sense, &ccb->csio.sense_data, sense_len);
2297230592Sken			ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
2298230592Sken		}
2299230592Sken
2300230592Sken		/*
2301230592Sken		 * Check if this is an INQUIRY command.  If it's a VPD inquiry,
2302230592Sken		 * and it's page code 0 (Supported Page List), and there is
2303230592Sken		 * inquiry data, and this is for a sequential access device, and
2304230592Sken		 * the device is an SSP target, and TLR is supported by the
2305230592Sken		 * controller, turn the TLR_bits value ON if page 0x90 is
2306230592Sken		 * supported.
2307230592Sken		 */
2308230592Sken		if ((csio->cdb_io.cdb_bytes[0] == INQUIRY) &&
2309230592Sken		    (csio->cdb_io.cdb_bytes[1] & SI_EVPD) &&
2310230592Sken		    (csio->cdb_io.cdb_bytes[2] == SVPD_SUPPORTED_PAGE_LIST) &&
2311248825Smav		    ((csio->ccb_h.flags & CAM_DATA_MASK) == CAM_DATA_VADDR) &&
2312230592Sken		    (csio->data_ptr != NULL) && (((uint8_t *)cm->cm_data)[0] ==
2313230592Sken		    T_SEQUENTIAL) && (sc->control_TLR) &&
2314230592Sken		    (sc->mapping_table[csio->ccb_h.target_id].device_info &
2315230592Sken		    MPI2_SAS_DEVICE_INFO_SSP_TARGET)) {
2316230592Sken			vpd_list = (struct scsi_vpd_supported_page_list *)
2317230592Sken			    csio->data_ptr;
2318230592Sken			TLR_bits = &sc->mapping_table[csio->ccb_h.target_id].
2319230592Sken			    TLR_bits;
2320230592Sken			*TLR_bits = (u8)MPI2_SCSIIO_CONTROL_NO_TLR;
2321230592Sken			TLR_on = (u8)MPI2_SCSIIO_CONTROL_TLR_ON;
2322230592Sken			alloc_len = ((u16)csio->cdb_io.cdb_bytes[3] << 8) +
2323230592Sken			    csio->cdb_io.cdb_bytes[4];
2324230592Sken			for (i = 0; i < MIN(vpd_list->length, alloc_len); i++) {
2325230592Sken				if (vpd_list->list[i] == 0x90) {
2326230592Sken					*TLR_bits = TLR_on;
2327230592Sken					break;
2328230592Sken				}
2329230592Sken			}
2330230592Sken		}
2331212420Sken		break;
2332212420Sken	case MPI2_IOCSTATUS_SCSI_INVALID_DEVHANDLE:
2333212420Sken	case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
2334230592Sken		/*
2335230592Sken		 * If devinfo is 0 this will be a volume.  In that case don't
2336230592Sken		 * tell CAM that the volume is not there.  We want volumes to
2337230592Sken		 * be enumerated until they are deleted/removed, not just
2338230592Sken		 * failed.
2339230592Sken		 */
2340230592Sken		if (cm->cm_targ->devinfo == 0)
2341230592Sken			ccb->ccb_h.status = CAM_REQ_CMP;
2342230592Sken		else
2343230592Sken			ccb->ccb_h.status = CAM_DEV_NOT_THERE;
2344212420Sken		break;
2345230592Sken	case MPI2_IOCSTATUS_INVALID_SGL:
2346230592Sken		mps_print_scsiio_cmd(sc, cm);
2347230592Sken		ccb->ccb_h.status = CAM_UNREC_HBA_ERROR;
2348230592Sken		break;
2349212420Sken	case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED:
2350212420Sken		/*
2351212420Sken		 * This is one of the responses that comes back when an I/O
2352212420Sken		 * has been aborted.  If it is because of a timeout that we
2353212420Sken		 * initiated, just set the status to CAM_CMD_TIMEOUT.
2354212420Sken		 * Otherwise set it to CAM_REQ_ABORTED.  The effect on the
2355212420Sken		 * command is the same (it gets retried, subject to the
2356212420Sken		 * retry counter), the only difference is what gets printed
2357212420Sken		 * on the console.
2358212420Sken		 */
2359212420Sken		if (cm->cm_state == MPS_CM_STATE_TIMEDOUT)
2360212420Sken			ccb->ccb_h.status = CAM_CMD_TIMEOUT;
2361212420Sken		else
2362212420Sken			ccb->ccb_h.status = CAM_REQ_ABORTED;
2363212420Sken		break;
2364230592Sken	case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN:
2365230592Sken		/* resid is ignored for this condition */
2366230592Sken		csio->resid = 0;
2367230592Sken		ccb->ccb_h.status = CAM_DATA_RUN_ERR;
2368230592Sken		break;
2369212420Sken	case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED:
2370212420Sken	case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED:
2371230592Sken		/*
2372230592Sken		 * Since these are generally external (i.e. hopefully
2373230592Sken		 * transient transport-related) errors, retry these without
2374230592Sken		 * decrementing the retry count.
2375230592Sken		 */
2376218812Sken		ccb->ccb_h.status = CAM_REQUEUE_REQ;
2377253460Sscottl		mpssas_log_command(cm, MPS_INFO,
2378230592Sken		    "terminated ioc %x scsi %x state %x xfer %u\n",
2379253460Sscottl		    le16toh(rep->IOCStatus), rep->SCSIStatus, rep->SCSIState,
2380253460Sscottl		    le32toh(rep->TransferCount));
2381212420Sken		break;
2382212420Sken	case MPI2_IOCSTATUS_INVALID_FUNCTION:
2383212420Sken	case MPI2_IOCSTATUS_INTERNAL_ERROR:
2384212420Sken	case MPI2_IOCSTATUS_INVALID_VPID:
2385212420Sken	case MPI2_IOCSTATUS_INVALID_FIELD:
2386212420Sken	case MPI2_IOCSTATUS_INVALID_STATE:
2387212420Sken	case MPI2_IOCSTATUS_OP_STATE_NOT_SUPPORTED:
2388212420Sken	case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR:
2389212420Sken	case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR:
2390212420Sken	case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
2391212420Sken	case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
2392212420Sken	default:
2393253460Sscottl		mpssas_log_command(cm, MPS_XINFO,
2394230592Sken		    "completed ioc %x scsi %x state %x xfer %u\n",
2395253460Sscottl		    le16toh(rep->IOCStatus), rep->SCSIStatus, rep->SCSIState,
2396253460Sscottl		    le32toh(rep->TransferCount));
2397230592Sken		csio->resid = cm->cm_length;
2398212420Sken		ccb->ccb_h.status = CAM_REQ_CMP_ERR;
2399230592Sken		break;
2400212420Sken	}
2401231240Sken
2402231240Sken	mps_sc_failed_io_info(sc,csio,rep);
2403212420Sken
2404230592Sken	if (sassc->flags & MPSSAS_QUEUE_FROZEN) {
2405230592Sken		ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
2406230592Sken		sassc->flags &= ~MPSSAS_QUEUE_FROZEN;
2407253460Sscottl		mps_dprint(sc, MPS_XINFO, "Command completed, "
2408253550Sken		    "unfreezing SIM queue\n");
2409230592Sken	}
2410212420Sken
2411230592Sken	if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
2412230592Sken		ccb->ccb_h.status |= CAM_DEV_QFRZN;
2413230592Sken		xpt_freeze_devq(ccb->ccb_h.path, /*count*/ 1);
2414230592Sken	}
2415212420Sken
2416230592Sken	mps_free_command(sc, cm);
2417230592Sken	xpt_done(ccb);
2418230592Sken}
2419230592Sken
2420237683Sken/* All Request reached here are Endian safe */
2421230592Skenstatic void
2422230592Skenmpssas_direct_drive_io(struct mpssas_softc *sassc, struct mps_command *cm,
2423230592Sken    union ccb *ccb) {
2424230592Sken	pMpi2SCSIIORequest_t	pIO_req;
2425230592Sken	struct mps_softc	*sc = sassc->sc;
2426230592Sken	uint64_t		virtLBA;
2427230592Sken	uint32_t		physLBA, stripe_offset, stripe_unit;
2428230592Sken	uint32_t		io_size, column;
2429230592Sken	uint8_t			*ptrLBA, lba_idx, physLBA_byte, *CDB;
2430230592Sken
2431230592Sken	/*
2432230592Sken	 * If this is a valid SCSI command (Read6, Read10, Read16, Write6,
2433230592Sken	 * Write10, or Write16), build a direct I/O message.  Otherwise, the I/O
2434230592Sken	 * will be sent to the IR volume itself.  Since Read6 and Write6 are a
2435230592Sken	 * bit different than the 10/16 CDBs, handle them separately.
2436230592Sken	 */
2437230592Sken	pIO_req = (pMpi2SCSIIORequest_t)cm->cm_req;
2438230592Sken	CDB = pIO_req->CDB.CDB32;
2439230592Sken
2440230592Sken	/*
2441230592Sken	 * Handle 6 byte CDBs.
2442230592Sken	 */
2443230592Sken	if ((pIO_req->DevHandle == sc->DD_dev_handle) && ((CDB[0] == READ_6) ||
2444230592Sken	    (CDB[0] == WRITE_6))) {
2445230592Sken		/*
2446230592Sken		 * Get the transfer size in blocks.
2447230592Sken		 */
2448230592Sken		io_size = (cm->cm_length >> sc->DD_block_exponent);
2449230592Sken
2450230592Sken		/*
2451230592Sken		 * Get virtual LBA given in the CDB.
2452230592Sken		 */
2453230592Sken		virtLBA = ((uint64_t)(CDB[1] & 0x1F) << 16) |
2454230592Sken		    ((uint64_t)CDB[2] << 8) | (uint64_t)CDB[3];
2455230592Sken
2456230592Sken		/*
2457230592Sken		 * Check that LBA range for I/O does not exceed volume's
2458230592Sken		 * MaxLBA.
2459230592Sken		 */
2460230592Sken		if ((virtLBA + (uint64_t)io_size - 1) <=
2461230592Sken		    sc->DD_max_lba) {
2462230592Sken			/*
2463230592Sken			 * Check if the I/O crosses a stripe boundary.  If not,
2464230592Sken			 * translate the virtual LBA to a physical LBA and set
2465230592Sken			 * the DevHandle for the PhysDisk to be used.  If it
2466230592Sken			 * does cross a boundry, do normal I/O.  To get the
2467230592Sken			 * right DevHandle to use, get the map number for the
2468230592Sken			 * column, then use that map number to look up the
2469230592Sken			 * DevHandle of the PhysDisk.
2470230592Sken			 */
2471230592Sken			stripe_offset = (uint32_t)virtLBA &
2472230592Sken			    (sc->DD_stripe_size - 1);
2473230592Sken			if ((stripe_offset + io_size) <= sc->DD_stripe_size) {
2474230592Sken				physLBA = (uint32_t)virtLBA >>
2475230592Sken				    sc->DD_stripe_exponent;
2476230592Sken				stripe_unit = physLBA / sc->DD_num_phys_disks;
2477230592Sken				column = physLBA % sc->DD_num_phys_disks;
2478230592Sken				pIO_req->DevHandle =
2479237683Sken				    htole16(sc->DD_column_map[column].dev_handle);
2480237683Sken				/* ???? Is this endian safe*/
2481230592Sken				cm->cm_desc.SCSIIO.DevHandle =
2482230592Sken				    pIO_req->DevHandle;
2483230592Sken
2484230592Sken				physLBA = (stripe_unit <<
2485230592Sken				    sc->DD_stripe_exponent) + stripe_offset;
2486230592Sken				ptrLBA = &pIO_req->CDB.CDB32[1];
2487230592Sken				physLBA_byte = (uint8_t)(physLBA >> 16);
2488230592Sken				*ptrLBA = physLBA_byte;
2489230592Sken				ptrLBA = &pIO_req->CDB.CDB32[2];
2490230592Sken				physLBA_byte = (uint8_t)(physLBA >> 8);
2491230592Sken				*ptrLBA = physLBA_byte;
2492230592Sken				ptrLBA = &pIO_req->CDB.CDB32[3];
2493230592Sken				physLBA_byte = (uint8_t)physLBA;
2494230592Sken				*ptrLBA = physLBA_byte;
2495230592Sken
2496230592Sken				/*
2497230592Sken				 * Set flag that Direct Drive I/O is
2498230592Sken				 * being done.
2499230592Sken				 */
2500230592Sken				cm->cm_flags |= MPS_CM_FLAGS_DD_IO;
2501230592Sken			}
2502212420Sken		}
2503230592Sken		return;
2504212420Sken	}
2505212420Sken
2506230592Sken	/*
2507237683Sken	 * Handle 10, 12 or 16 byte CDBs.
2508230592Sken	 */
2509230592Sken	if ((pIO_req->DevHandle == sc->DD_dev_handle) && ((CDB[0] == READ_10) ||
2510230592Sken	    (CDB[0] == WRITE_10) || (CDB[0] == READ_16) ||
2511237683Sken	    (CDB[0] == WRITE_16) || (CDB[0] == READ_12) ||
2512237683Sken	    (CDB[0] == WRITE_12))) {
2513230592Sken		/*
2514230592Sken		 * For 16-byte CDB's, verify that the upper 4 bytes of the CDB
2515230592Sken		 * are 0.  If not, this is accessing beyond 2TB so handle it in
2516237683Sken		 * the else section.  10-byte and 12-byte CDB's are OK.
2517237683Sken		 * FreeBSD sends very rare 12 byte READ/WRITE, but driver is
2518237683Sken		 * ready to accept 12byte CDB for Direct IOs.
2519230592Sken		 */
2520237683Sken		if ((CDB[0] == READ_10 || CDB[0] == WRITE_10) ||
2521237683Sken		    (CDB[0] == READ_12 || CDB[0] == WRITE_12) ||
2522230592Sken		    !(CDB[2] | CDB[3] | CDB[4] | CDB[5])) {
2523230592Sken			/*
2524230592Sken			 * Get the transfer size in blocks.
2525230592Sken			 */
2526230592Sken			io_size = (cm->cm_length >> sc->DD_block_exponent);
2527225950Sken
2528230592Sken			/*
2529230592Sken			 * Get virtual LBA.  Point to correct lower 4 bytes of
2530230592Sken			 * LBA in the CDB depending on command.
2531230592Sken			 */
2532237683Sken			lba_idx = ((CDB[0] == READ_12) ||
2533237683Sken				(CDB[0] == WRITE_12) ||
2534237683Sken				(CDB[0] == READ_10) ||
2535237683Sken				(CDB[0] == WRITE_10))? 2 : 6;
2536230592Sken			virtLBA = ((uint64_t)CDB[lba_idx] << 24) |
2537230592Sken			    ((uint64_t)CDB[lba_idx + 1] << 16) |
2538230592Sken			    ((uint64_t)CDB[lba_idx + 2] << 8) |
2539230592Sken			    (uint64_t)CDB[lba_idx + 3];
2540225950Sken
2541230592Sken			/*
2542230592Sken			 * Check that LBA range for I/O does not exceed volume's
2543230592Sken			 * MaxLBA.
2544230592Sken			 */
2545230592Sken			if ((virtLBA + (uint64_t)io_size - 1) <=
2546230592Sken			    sc->DD_max_lba) {
2547230592Sken				/*
2548230592Sken				 * Check if the I/O crosses a stripe boundary.
2549230592Sken				 * If not, translate the virtual LBA to a
2550230592Sken				 * physical LBA and set the DevHandle for the
2551230592Sken				 * PhysDisk to be used.  If it does cross a
2552230592Sken				 * boundry, do normal I/O.  To get the right
2553230592Sken				 * DevHandle to use, get the map number for the
2554230592Sken				 * column, then use that map number to look up
2555230592Sken				 * the DevHandle of the PhysDisk.
2556230592Sken				 */
2557230592Sken				stripe_offset = (uint32_t)virtLBA &
2558230592Sken				    (sc->DD_stripe_size - 1);
2559230592Sken				if ((stripe_offset + io_size) <=
2560230592Sken				    sc->DD_stripe_size) {
2561230592Sken					physLBA = (uint32_t)virtLBA >>
2562230592Sken					    sc->DD_stripe_exponent;
2563230592Sken					stripe_unit = physLBA /
2564230592Sken					    sc->DD_num_phys_disks;
2565230592Sken					column = physLBA %
2566230592Sken					    sc->DD_num_phys_disks;
2567230592Sken					pIO_req->DevHandle =
2568237683Sken					    htole16(sc->DD_column_map[column].
2569237683Sken					    dev_handle);
2570230592Sken					cm->cm_desc.SCSIIO.DevHandle =
2571230592Sken					    pIO_req->DevHandle;
2572212420Sken
2573230592Sken					physLBA = (stripe_unit <<
2574230592Sken					    sc->DD_stripe_exponent) +
2575230592Sken					    stripe_offset;
2576230592Sken					ptrLBA =
2577230592Sken					    &pIO_req->CDB.CDB32[lba_idx];
2578230592Sken					physLBA_byte = (uint8_t)(physLBA >> 24);
2579230592Sken					*ptrLBA = physLBA_byte;
2580230592Sken					ptrLBA =
2581230592Sken					    &pIO_req->CDB.CDB32[lba_idx + 1];
2582230592Sken					physLBA_byte = (uint8_t)(physLBA >> 16);
2583230592Sken					*ptrLBA = physLBA_byte;
2584230592Sken					ptrLBA =
2585230592Sken					    &pIO_req->CDB.CDB32[lba_idx + 2];
2586230592Sken					physLBA_byte = (uint8_t)(physLBA >> 8);
2587230592Sken					*ptrLBA = physLBA_byte;
2588230592Sken					ptrLBA =
2589230592Sken					    &pIO_req->CDB.CDB32[lba_idx + 3];
2590230592Sken					physLBA_byte = (uint8_t)physLBA;
2591230592Sken					*ptrLBA = physLBA_byte;
2592212420Sken
2593230592Sken					/*
2594230592Sken					 * Set flag that Direct Drive I/O is
2595230592Sken					 * being done.
2596230592Sken					 */
2597230592Sken					cm->cm_flags |= MPS_CM_FLAGS_DD_IO;
2598230592Sken				}
2599230592Sken			}
2600230592Sken		} else {
2601230592Sken			/*
2602230592Sken			 * 16-byte CDB and the upper 4 bytes of the CDB are not
2603230592Sken			 * 0.  Get the transfer size in blocks.
2604230592Sken			 */
2605230592Sken			io_size = (cm->cm_length >> sc->DD_block_exponent);
2606212420Sken
2607230592Sken			/*
2608230592Sken			 * Get virtual LBA.
2609230592Sken			 */
2610230592Sken			virtLBA = ((uint64_t)CDB[2] << 54) |
2611230592Sken			    ((uint64_t)CDB[3] << 48) |
2612230592Sken			    ((uint64_t)CDB[4] << 40) |
2613230592Sken			    ((uint64_t)CDB[5] << 32) |
2614230592Sken			    ((uint64_t)CDB[6] << 24) |
2615230592Sken			    ((uint64_t)CDB[7] << 16) |
2616230592Sken			    ((uint64_t)CDB[8] << 8) |
2617230592Sken			    (uint64_t)CDB[9];
2618230592Sken
2619230592Sken			/*
2620230592Sken			 * Check that LBA range for I/O does not exceed volume's
2621230592Sken			 * MaxLBA.
2622230592Sken			 */
2623230592Sken			if ((virtLBA + (uint64_t)io_size - 1) <=
2624230592Sken			    sc->DD_max_lba) {
2625230592Sken				/*
2626230592Sken				 * Check if the I/O crosses a stripe boundary.
2627230592Sken				 * If not, translate the virtual LBA to a
2628230592Sken				 * physical LBA and set the DevHandle for the
2629230592Sken				 * PhysDisk to be used.  If it does cross a
2630230592Sken				 * boundry, do normal I/O.  To get the right
2631230592Sken				 * DevHandle to use, get the map number for the
2632230592Sken				 * column, then use that map number to look up
2633230592Sken				 * the DevHandle of the PhysDisk.
2634230592Sken				 */
2635230592Sken				stripe_offset = (uint32_t)virtLBA &
2636230592Sken				    (sc->DD_stripe_size - 1);
2637230592Sken				if ((stripe_offset + io_size) <=
2638230592Sken				    sc->DD_stripe_size) {
2639230592Sken					physLBA = (uint32_t)(virtLBA >>
2640230592Sken					    sc->DD_stripe_exponent);
2641230592Sken					stripe_unit = physLBA /
2642230592Sken					    sc->DD_num_phys_disks;
2643230592Sken					column = physLBA %
2644230592Sken					    sc->DD_num_phys_disks;
2645230592Sken					pIO_req->DevHandle =
2646237683Sken					    htole16(sc->DD_column_map[column].
2647237683Sken					    dev_handle);
2648230592Sken					cm->cm_desc.SCSIIO.DevHandle =
2649230592Sken					    pIO_req->DevHandle;
2650230592Sken
2651230592Sken					physLBA = (stripe_unit <<
2652230592Sken					    sc->DD_stripe_exponent) +
2653230592Sken					    stripe_offset;
2654230592Sken
2655230592Sken					/*
2656230592Sken					 * Set upper 4 bytes of LBA to 0.  We
2657230592Sken					 * assume that the phys disks are less
2658230592Sken					 * than 2 TB's in size.  Then, set the
2659230592Sken					 * lower 4 bytes.
2660230592Sken					 */
2661230592Sken					pIO_req->CDB.CDB32[2] = 0;
2662230592Sken					pIO_req->CDB.CDB32[3] = 0;
2663230592Sken					pIO_req->CDB.CDB32[4] = 0;
2664230592Sken					pIO_req->CDB.CDB32[5] = 0;
2665230592Sken					ptrLBA = &pIO_req->CDB.CDB32[6];
2666230592Sken					physLBA_byte = (uint8_t)(physLBA >> 24);
2667230592Sken					*ptrLBA = physLBA_byte;
2668230592Sken					ptrLBA = &pIO_req->CDB.CDB32[7];
2669230592Sken					physLBA_byte = (uint8_t)(physLBA >> 16);
2670230592Sken					*ptrLBA = physLBA_byte;
2671230592Sken					ptrLBA = &pIO_req->CDB.CDB32[8];
2672230592Sken					physLBA_byte = (uint8_t)(physLBA >> 8);
2673230592Sken					*ptrLBA = physLBA_byte;
2674230592Sken					ptrLBA = &pIO_req->CDB.CDB32[9];
2675230592Sken					physLBA_byte = (uint8_t)physLBA;
2676230592Sken					*ptrLBA = physLBA_byte;
2677230592Sken
2678230592Sken					/*
2679230592Sken					 * Set flag that Direct Drive I/O is
2680230592Sken					 * being done.
2681230592Sken					 */
2682230592Sken					cm->cm_flags |= MPS_CM_FLAGS_DD_IO;
2683230592Sken				}
2684230592Sken			}
2685230592Sken		}
2686218812Sken	}
2687212420Sken}
2688212420Sken
2689216088Sken#if __FreeBSD_version >= 900026
2690212420Skenstatic void
2691216088Skenmpssas_smpio_complete(struct mps_softc *sc, struct mps_command *cm)
2692216088Sken{
2693216088Sken	MPI2_SMP_PASSTHROUGH_REPLY *rpl;
2694216088Sken	MPI2_SMP_PASSTHROUGH_REQUEST *req;
2695216088Sken	uint64_t sasaddr;
2696216088Sken	union ccb *ccb;
2697216088Sken
2698216088Sken	ccb = cm->cm_complete_data;
2699218812Sken
2700218812Sken	/*
2701218812Sken	 * Currently there should be no way we can hit this case.  It only
2702218812Sken	 * happens when we have a failure to allocate chain frames, and SMP
2703218812Sken	 * commands require two S/G elements only.  That should be handled
2704218812Sken	 * in the standard request size.
2705218812Sken	 */
2706218812Sken	if ((cm->cm_flags & MPS_CM_FLAGS_ERROR_MASK) != 0) {
2707253460Sscottl		mps_dprint(sc, MPS_ERROR,"%s: cm_flags = %#x on SMP request!\n",
2708218812Sken			   __func__, cm->cm_flags);
2709218812Sken		ccb->ccb_h.status = CAM_REQ_CMP_ERR;
2710218812Sken		goto bailout;
2711230592Sken        }
2712218812Sken
2713216088Sken	rpl = (MPI2_SMP_PASSTHROUGH_REPLY *)cm->cm_reply;
2714216088Sken	if (rpl == NULL) {
2715253460Sscottl		mps_dprint(sc, MPS_ERROR, "%s: NULL cm_reply!\n", __func__);
2716216088Sken		ccb->ccb_h.status = CAM_REQ_CMP_ERR;
2717216088Sken		goto bailout;
2718216088Sken	}
2719216088Sken
2720216088Sken	req = (MPI2_SMP_PASSTHROUGH_REQUEST *)cm->cm_req;
2721216088Sken	sasaddr = le32toh(req->SASAddress.Low);
2722216088Sken	sasaddr |= ((uint64_t)(le32toh(req->SASAddress.High))) << 32;
2723216088Sken
2724253550Sken	if ((le16toh(rpl->IOCStatus) & MPI2_IOCSTATUS_MASK) !=
2725253550Sken	    MPI2_IOCSTATUS_SUCCESS ||
2726216088Sken	    rpl->SASStatus != MPI2_SASSTATUS_SUCCESS) {
2727253460Sscottl		mps_dprint(sc, MPS_XINFO, "%s: IOCStatus %04x SASStatus %02x\n",
2728237683Sken		    __func__, le16toh(rpl->IOCStatus), rpl->SASStatus);
2729216088Sken		ccb->ccb_h.status = CAM_REQ_CMP_ERR;
2730216088Sken		goto bailout;
2731216088Sken	}
2732216088Sken
2733253460Sscottl	mps_dprint(sc, MPS_XINFO, "%s: SMP request to SAS address "
2734216088Sken		   "%#jx completed successfully\n", __func__,
2735216088Sken		   (uintmax_t)sasaddr);
2736216088Sken
2737216088Sken	if (ccb->smpio.smp_response[2] == SMP_FR_ACCEPTED)
2738216088Sken		ccb->ccb_h.status = CAM_REQ_CMP;
2739216088Sken	else
2740216088Sken		ccb->ccb_h.status = CAM_SMP_STATUS_ERROR;
2741216088Sken
2742216088Skenbailout:
2743216088Sken	/*
2744216088Sken	 * We sync in both directions because we had DMAs in the S/G list
2745216088Sken	 * in both directions.
2746216088Sken	 */
2747216088Sken	bus_dmamap_sync(sc->buffer_dmat, cm->cm_dmamap,
2748216088Sken			BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
2749216088Sken	bus_dmamap_unload(sc->buffer_dmat, cm->cm_dmamap);
2750216088Sken	mps_free_command(sc, cm);
2751216088Sken	xpt_done(ccb);
2752216088Sken}
2753216088Sken
2754216088Skenstatic void
2755216088Skenmpssas_send_smpcmd(struct mpssas_softc *sassc, union ccb *ccb, uint64_t sasaddr)
2756216088Sken{
2757216088Sken	struct mps_command *cm;
2758216088Sken	uint8_t *request, *response;
2759216088Sken	MPI2_SMP_PASSTHROUGH_REQUEST *req;
2760216088Sken	struct mps_softc *sc;
2761216088Sken	struct sglist *sg;
2762216088Sken	int error;
2763216088Sken
2764216088Sken	sc = sassc->sc;
2765216088Sken	sg = NULL;
2766216088Sken	error = 0;
2767216088Sken
2768216088Sken	/*
2769216088Sken	 * XXX We don't yet support physical addresses here.
2770216088Sken	 */
2771246713Skib	switch ((ccb->ccb_h.flags & CAM_DATA_MASK)) {
2772246713Skib	case CAM_DATA_PADDR:
2773246713Skib	case CAM_DATA_SG_PADDR:
2774253460Sscottl		mps_dprint(sc, MPS_ERROR,
2775253460Sscottl			   "%s: physical addresses not supported\n", __func__);
2776216088Sken		ccb->ccb_h.status = CAM_REQ_INVALID;
2777216088Sken		xpt_done(ccb);
2778216088Sken		return;
2779246713Skib	case CAM_DATA_SG:
2780216088Sken		/*
2781216088Sken		 * The chip does not support more than one buffer for the
2782216088Sken		 * request or response.
2783216088Sken		 */
2784216088Sken	 	if ((ccb->smpio.smp_request_sglist_cnt > 1)
2785216088Sken		  || (ccb->smpio.smp_response_sglist_cnt > 1)) {
2786253460Sscottl			mps_dprint(sc, MPS_ERROR,
2787253460Sscottl				   "%s: multiple request or response "
2788216088Sken				   "buffer segments not supported for SMP\n",
2789216088Sken				   __func__);
2790216088Sken			ccb->ccb_h.status = CAM_REQ_INVALID;
2791216088Sken			xpt_done(ccb);
2792216088Sken			return;
2793216088Sken		}
2794216088Sken
2795216088Sken		/*
2796216088Sken		 * The CAM_SCATTER_VALID flag was originally implemented
2797216088Sken		 * for the XPT_SCSI_IO CCB, which only has one data pointer.
2798216088Sken		 * We have two.  So, just take that flag to mean that we
2799216088Sken		 * might have S/G lists, and look at the S/G segment count
2800216088Sken		 * to figure out whether that is the case for each individual
2801216088Sken		 * buffer.
2802216088Sken		 */
2803216088Sken		if (ccb->smpio.smp_request_sglist_cnt != 0) {
2804216088Sken			bus_dma_segment_t *req_sg;
2805216088Sken
2806216088Sken			req_sg = (bus_dma_segment_t *)ccb->smpio.smp_request;
2807241145Sken			request = (uint8_t *)(uintptr_t)req_sg[0].ds_addr;
2808216088Sken		} else
2809216088Sken			request = ccb->smpio.smp_request;
2810216088Sken
2811216088Sken		if (ccb->smpio.smp_response_sglist_cnt != 0) {
2812216088Sken			bus_dma_segment_t *rsp_sg;
2813216088Sken
2814216088Sken			rsp_sg = (bus_dma_segment_t *)ccb->smpio.smp_response;
2815241145Sken			response = (uint8_t *)(uintptr_t)rsp_sg[0].ds_addr;
2816216088Sken		} else
2817216088Sken			response = ccb->smpio.smp_response;
2818246713Skib		break;
2819246713Skib	case CAM_DATA_VADDR:
2820216088Sken		request = ccb->smpio.smp_request;
2821216088Sken		response = ccb->smpio.smp_response;
2822246713Skib		break;
2823246713Skib	default:
2824246713Skib		ccb->ccb_h.status = CAM_REQ_INVALID;
2825246713Skib		xpt_done(ccb);
2826246713Skib		return;
2827216088Sken	}
2828216088Sken
2829216088Sken	cm = mps_alloc_command(sc);
2830216088Sken	if (cm == NULL) {
2831253460Sscottl		mps_dprint(sc, MPS_ERROR,
2832253460Sscottl		    "%s: cannot allocate command\n", __func__);
2833216088Sken		ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
2834216088Sken		xpt_done(ccb);
2835216088Sken		return;
2836216088Sken	}
2837216088Sken
2838216088Sken	req = (MPI2_SMP_PASSTHROUGH_REQUEST *)cm->cm_req;
2839216088Sken	bzero(req, sizeof(*req));
2840216088Sken	req->Function = MPI2_FUNCTION_SMP_PASSTHROUGH;
2841216088Sken
2842216088Sken	/* Allow the chip to use any route to this SAS address. */
2843216088Sken	req->PhysicalPort = 0xff;
2844216088Sken
2845237683Sken	req->RequestDataLength = htole16(ccb->smpio.smp_request_len);
2846216088Sken	req->SGLFlags =
2847216088Sken	    MPI2_SGLFLAGS_SYSTEM_ADDRESS_SPACE | MPI2_SGLFLAGS_SGL_TYPE_MPI;
2848216088Sken
2849253460Sscottl	mps_dprint(sc, MPS_XINFO, "%s: sending SMP request to SAS "
2850253550Sken	    "address %#jx\n", __func__, (uintmax_t)sasaddr);
2851216088Sken
2852216088Sken	mpi_init_sge(cm, req, &req->SGL);
2853216088Sken
2854216088Sken	/*
2855216088Sken	 * Set up a uio to pass into mps_map_command().  This allows us to
2856216088Sken	 * do one map command, and one busdma call in there.
2857216088Sken	 */
2858216088Sken	cm->cm_uio.uio_iov = cm->cm_iovec;
2859216088Sken	cm->cm_uio.uio_iovcnt = 2;
2860216088Sken	cm->cm_uio.uio_segflg = UIO_SYSSPACE;
2861216088Sken
2862216088Sken	/*
2863216088Sken	 * The read/write flag isn't used by busdma, but set it just in
2864216088Sken	 * case.  This isn't exactly accurate, either, since we're going in
2865216088Sken	 * both directions.
2866216088Sken	 */
2867216088Sken	cm->cm_uio.uio_rw = UIO_WRITE;
2868216088Sken
2869216088Sken	cm->cm_iovec[0].iov_base = request;
2870237683Sken	cm->cm_iovec[0].iov_len = le16toh(req->RequestDataLength);
2871216088Sken	cm->cm_iovec[1].iov_base = response;
2872216088Sken	cm->cm_iovec[1].iov_len = ccb->smpio.smp_response_len;
2873216088Sken
2874216088Sken	cm->cm_uio.uio_resid = cm->cm_iovec[0].iov_len +
2875216088Sken			       cm->cm_iovec[1].iov_len;
2876216088Sken
2877216088Sken	/*
2878216088Sken	 * Trigger a warning message in mps_data_cb() for the user if we
2879216088Sken	 * wind up exceeding two S/G segments.  The chip expects one
2880216088Sken	 * segment for the request and another for the response.
2881216088Sken	 */
2882216088Sken	cm->cm_max_segs = 2;
2883216088Sken
2884216088Sken	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
2885216088Sken	cm->cm_complete = mpssas_smpio_complete;
2886216088Sken	cm->cm_complete_data = ccb;
2887216088Sken
2888216088Sken	/*
2889216088Sken	 * Tell the mapping code that we're using a uio, and that this is
2890216088Sken	 * an SMP passthrough request.  There is a little special-case
2891216088Sken	 * logic there (in mps_data_cb()) to handle the bidirectional
2892216088Sken	 * transfer.
2893216088Sken	 */
2894216088Sken	cm->cm_flags |= MPS_CM_FLAGS_USE_UIO | MPS_CM_FLAGS_SMP_PASS |
2895216088Sken			MPS_CM_FLAGS_DATAIN | MPS_CM_FLAGS_DATAOUT;
2896216088Sken
2897216088Sken	/* The chip data format is little endian. */
2898216088Sken	req->SASAddress.High = htole32(sasaddr >> 32);
2899216088Sken	req->SASAddress.Low = htole32(sasaddr);
2900216088Sken
2901216088Sken	/*
2902216088Sken	 * XXX Note that we don't have a timeout/abort mechanism here.
2903216088Sken	 * From the manual, it looks like task management requests only
2904216088Sken	 * work for SCSI IO and SATA passthrough requests.  We may need to
2905216088Sken	 * have a mechanism to retry requests in the event of a chip reset
2906216088Sken	 * at least.  Hopefully the chip will insure that any errors short
2907216088Sken	 * of that are relayed back to the driver.
2908216088Sken	 */
2909216088Sken	error = mps_map_command(sc, cm);
2910216088Sken	if ((error != 0) && (error != EINPROGRESS)) {
2911253460Sscottl		mps_dprint(sc, MPS_ERROR,
2912253460Sscottl			   "%s: error %d returned from mps_map_command()\n",
2913216088Sken			   __func__, error);
2914216088Sken		goto bailout_error;
2915216088Sken	}
2916216088Sken
2917216088Sken	return;
2918216088Sken
2919216088Skenbailout_error:
2920216088Sken	mps_free_command(sc, cm);
2921216088Sken	ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
2922216088Sken	xpt_done(ccb);
2923216088Sken	return;
2924216088Sken
2925216088Sken}
2926216088Sken
2927216088Skenstatic void
2928216088Skenmpssas_action_smpio(struct mpssas_softc *sassc, union ccb *ccb)
2929216088Sken{
2930216088Sken	struct mps_softc *sc;
2931216088Sken	struct mpssas_target *targ;
2932216088Sken	uint64_t sasaddr = 0;
2933216088Sken
2934216088Sken	sc = sassc->sc;
2935216088Sken
2936216088Sken	/*
2937216088Sken	 * Make sure the target exists.
2938216088Sken	 */
2939216088Sken	targ = &sassc->targets[ccb->ccb_h.target_id];
2940216088Sken	if (targ->handle == 0x0) {
2941253460Sscottl		mps_dprint(sc, MPS_ERROR,
2942253460Sscottl			   "%s: target %d does not exist!\n", __func__,
2943216088Sken			   ccb->ccb_h.target_id);
2944216088Sken		ccb->ccb_h.status = CAM_SEL_TIMEOUT;
2945216088Sken		xpt_done(ccb);
2946216088Sken		return;
2947216088Sken	}
2948216088Sken
2949216088Sken	/*
2950216088Sken	 * If this device has an embedded SMP target, we'll talk to it
2951216088Sken	 * directly.
2952216088Sken	 * figure out what the expander's address is.
2953216088Sken	 */
2954216088Sken	if ((targ->devinfo & MPI2_SAS_DEVICE_INFO_SMP_TARGET) != 0)
2955216088Sken		sasaddr = targ->sasaddr;
2956216088Sken
2957216088Sken	/*
2958216088Sken	 * If we don't have a SAS address for the expander yet, try
2959216088Sken	 * grabbing it from the page 0x83 information cached in the
2960216088Sken	 * transport layer for this target.  LSI expanders report the
2961216088Sken	 * expander SAS address as the port-associated SAS address in
2962216088Sken	 * Inquiry VPD page 0x83.  Maxim expanders don't report it in page
2963216088Sken	 * 0x83.
2964216088Sken	 *
2965216088Sken	 * XXX KDM disable this for now, but leave it commented out so that
2966216088Sken	 * it is obvious that this is another possible way to get the SAS
2967216088Sken	 * address.
2968216088Sken	 *
2969216088Sken	 * The parent handle method below is a little more reliable, and
2970216088Sken	 * the other benefit is that it works for devices other than SES
2971216088Sken	 * devices.  So you can send a SMP request to a da(4) device and it
2972216088Sken	 * will get routed to the expander that device is attached to.
2973216088Sken	 * (Assuming the da(4) device doesn't contain an SMP target...)
2974216088Sken	 */
2975216088Sken#if 0
2976216088Sken	if (sasaddr == 0)
2977216088Sken		sasaddr = xpt_path_sas_addr(ccb->ccb_h.path);
2978216088Sken#endif
2979216088Sken
2980216088Sken	/*
2981216088Sken	 * If we still don't have a SAS address for the expander, look for
2982216088Sken	 * the parent device of this device, which is probably the expander.
2983216088Sken	 */
2984216088Sken	if (sasaddr == 0) {
2985230592Sken#ifdef OLD_MPS_PROBE
2986216088Sken		struct mpssas_target *parent_target;
2987230592Sken#endif
2988216088Sken
2989216088Sken		if (targ->parent_handle == 0x0) {
2990253460Sscottl			mps_dprint(sc, MPS_ERROR,
2991253460Sscottl				   "%s: handle %d does not have a valid "
2992216088Sken				   "parent handle!\n", __func__, targ->handle);
2993216088Sken			ccb->ccb_h.status = CAM_REQ_INVALID;
2994216088Sken			goto bailout;
2995216088Sken		}
2996230592Sken#ifdef OLD_MPS_PROBE
2997230592Sken		parent_target = mpssas_find_target_by_handle(sassc, 0,
2998230592Sken			targ->parent_handle);
2999216088Sken
3000216088Sken		if (parent_target == NULL) {
3001253460Sscottl			mps_dprint(sc, MPS_ERROR,
3002253460Sscottl				   "%s: handle %d does not have a valid "
3003216088Sken				   "parent target!\n", __func__, targ->handle);
3004216088Sken			ccb->ccb_h.status = CAM_REQ_INVALID;
3005216088Sken			goto bailout;
3006216088Sken		}
3007216088Sken
3008216088Sken		if ((parent_target->devinfo &
3009216088Sken		     MPI2_SAS_DEVICE_INFO_SMP_TARGET) == 0) {
3010253460Sscottl			mps_dprint(sc, MPS_ERROR,
3011253460Sscottl				   "%s: handle %d parent %d does not "
3012216088Sken				   "have an SMP target!\n", __func__,
3013216088Sken				   targ->handle, parent_target->handle);
3014216088Sken			ccb->ccb_h.status = CAM_REQ_INVALID;
3015216088Sken			goto bailout;
3016216088Sken
3017216088Sken		}
3018216088Sken
3019216088Sken		sasaddr = parent_target->sasaddr;
3020230592Sken#else /* OLD_MPS_PROBE */
3021230592Sken		if ((targ->parent_devinfo &
3022230592Sken		     MPI2_SAS_DEVICE_INFO_SMP_TARGET) == 0) {
3023253460Sscottl			mps_dprint(sc, MPS_ERROR,
3024253460Sscottl				   "%s: handle %d parent %d does not "
3025230592Sken				   "have an SMP target!\n", __func__,
3026230592Sken				   targ->handle, targ->parent_handle);
3027230592Sken			ccb->ccb_h.status = CAM_REQ_INVALID;
3028230592Sken			goto bailout;
3029230592Sken
3030230592Sken		}
3031230592Sken		if (targ->parent_sasaddr == 0x0) {
3032253460Sscottl			mps_dprint(sc, MPS_ERROR,
3033253460Sscottl				   "%s: handle %d parent handle %d does "
3034230592Sken				   "not have a valid SAS address!\n",
3035230592Sken				   __func__, targ->handle, targ->parent_handle);
3036230592Sken			ccb->ccb_h.status = CAM_REQ_INVALID;
3037230592Sken			goto bailout;
3038230592Sken		}
3039230592Sken
3040230592Sken		sasaddr = targ->parent_sasaddr;
3041230592Sken#endif /* OLD_MPS_PROBE */
3042230592Sken
3043216088Sken	}
3044216088Sken
3045216088Sken	if (sasaddr == 0) {
3046253460Sscottl		mps_dprint(sc, MPS_INFO,
3047253460Sscottl			   "%s: unable to find SAS address for handle %d\n",
3048216088Sken			   __func__, targ->handle);
3049216088Sken		ccb->ccb_h.status = CAM_REQ_INVALID;
3050216088Sken		goto bailout;
3051216088Sken	}
3052216088Sken	mpssas_send_smpcmd(sassc, ccb, sasaddr);
3053216088Sken
3054216088Sken	return;
3055216088Sken
3056216088Skenbailout:
3057216088Sken	xpt_done(ccb);
3058216088Sken
3059216088Sken}
3060230592Sken#endif //__FreeBSD_version >= 900026
3061216088Sken
3062216088Skenstatic void
3063212420Skenmpssas_action_resetdev(struct mpssas_softc *sassc, union ccb *ccb)
3064212420Sken{
3065230592Sken	MPI2_SCSI_TASK_MANAGE_REQUEST *req;
3066212420Sken	struct mps_softc *sc;
3067230592Sken	struct mps_command *tm;
3068212420Sken	struct mpssas_target *targ;
3069212420Sken
3070253460Sscottl	MPS_FUNCTRACE(sassc->sc);
3071230592Sken	mtx_assert(&sassc->sc->mps_mtx, MA_OWNED);
3072230592Sken
3073212420Sken	sc = sassc->sc;
3074230592Sken	tm = mps_alloc_command(sc);
3075230592Sken	if (tm == NULL) {
3076253460Sscottl		mps_dprint(sc, MPS_ERROR,
3077253809Sscottl		    "command alloc failure in mpssas_action_resetdev\n");
3078212420Sken		ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
3079212420Sken		xpt_done(ccb);
3080212420Sken		return;
3081212420Sken	}
3082212420Sken
3083230592Sken	targ = &sassc->targets[ccb->ccb_h.target_id];
3084230592Sken	req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req;
3085237683Sken	req->DevHandle = htole16(targ->handle);
3086212420Sken	req->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
3087212420Sken	req->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
3088212420Sken
3089212420Sken	/* SAS Hard Link Reset / SATA Link Reset */
3090212420Sken	req->MsgFlags = MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET;
3091212420Sken
3092230592Sken	tm->cm_data = NULL;
3093230592Sken	tm->cm_desc.HighPriority.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY;
3094230592Sken	tm->cm_complete = mpssas_resetdev_complete;
3095230592Sken	tm->cm_complete_data = ccb;
3096238969Smav	tm->cm_targ = targ;
3097230592Sken	mps_map_command(sc, tm);
3098212420Sken}
3099212420Sken
3100212420Skenstatic void
3101230592Skenmpssas_resetdev_complete(struct mps_softc *sc, struct mps_command *tm)
3102212420Sken{
3103212420Sken	MPI2_SCSI_TASK_MANAGE_REPLY *resp;
3104212420Sken	union ccb *ccb;
3105212420Sken
3106253460Sscottl	MPS_FUNCTRACE(sc);
3107230592Sken	mtx_assert(&sc->mps_mtx, MA_OWNED);
3108212420Sken
3109230592Sken	resp = (MPI2_SCSI_TASK_MANAGE_REPLY *)tm->cm_reply;
3110230592Sken	ccb = tm->cm_complete_data;
3111212420Sken
3112230592Sken	/*
3113230592Sken	 * Currently there should be no way we can hit this case.  It only
3114230592Sken	 * happens when we have a failure to allocate chain frames, and
3115230592Sken	 * task management commands don't have S/G lists.
3116230592Sken	 */
3117230592Sken	if ((tm->cm_flags & MPS_CM_FLAGS_ERROR_MASK) != 0) {
3118218812Sken		MPI2_SCSI_TASK_MANAGE_REQUEST *req;
3119218812Sken
3120230592Sken		req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req;
3121218812Sken
3122253460Sscottl		mps_dprint(sc, MPS_ERROR,
3123253460Sscottl			   "%s: cm_flags = %#x for reset of handle %#04x! "
3124230592Sken			   "This should not happen!\n", __func__, tm->cm_flags,
3125218812Sken			   req->DevHandle);
3126218812Sken		ccb->ccb_h.status = CAM_REQ_CMP_ERR;
3127218812Sken		goto bailout;
3128218812Sken	}
3129218812Sken
3130253460Sscottl	mps_dprint(sc, MPS_XINFO,
3131253460Sscottl	    "%s: IOCStatus = 0x%x ResponseCode = 0x%x\n", __func__,
3132237683Sken	    le16toh(resp->IOCStatus), le32toh(resp->ResponseCode));
3133212420Sken
3134237683Sken	if (le32toh(resp->ResponseCode) == MPI2_SCSITASKMGMT_RSP_TM_COMPLETE) {
3135212420Sken		ccb->ccb_h.status = CAM_REQ_CMP;
3136230592Sken		mpssas_announce_reset(sc, AC_SENT_BDR, tm->cm_targ->tid,
3137230592Sken		    CAM_LUN_WILDCARD);
3138230592Sken	}
3139212420Sken	else
3140212420Sken		ccb->ccb_h.status = CAM_REQ_CMP_ERR;
3141212420Sken
3142218812Skenbailout:
3143212772Sken
3144230592Sken	mpssas_free_tm(sc, tm);
3145212420Sken	xpt_done(ccb);
3146212420Sken}
3147212420Sken
3148212420Skenstatic void
3149212420Skenmpssas_poll(struct cam_sim *sim)
3150212420Sken{
3151212420Sken	struct mpssas_softc *sassc;
3152212420Sken
3153212420Sken	sassc = cam_sim_softc(sim);
3154230592Sken
3155230592Sken	if (sassc->sc->mps_debug & MPS_TRACE) {
3156230592Sken		/* frequent debug messages during a panic just slow
3157230592Sken		 * everything down too much.
3158230592Sken		 */
3159230592Sken		mps_printf(sassc->sc, "%s clearing MPS_TRACE\n", __func__);
3160230592Sken		sassc->sc->mps_debug &= ~MPS_TRACE;
3161230592Sken	}
3162230592Sken
3163212420Sken	mps_intr_locked(sassc->sc);
3164212420Sken}
3165212420Sken
3166212420Skenstatic void
3167230592Skenmpssas_async(void *callback_arg, uint32_t code, struct cam_path *path,
3168230592Sken	     void *arg)
3169230592Sken{
3170230592Sken	struct mps_softc *sc;
3171230592Sken
3172230592Sken	sc = (struct mps_softc *)callback_arg;
3173230592Sken
3174230592Sken	switch (code) {
3175253549Sken#if (__FreeBSD_version >= 1000006) || \
3176253549Sken    ((__FreeBSD_version >= 901503) && (__FreeBSD_version < 1000000))
3177230592Sken	case AC_ADVINFO_CHANGED: {
3178230592Sken		struct mpssas_target *target;
3179230592Sken		struct mpssas_softc *sassc;
3180230592Sken		struct scsi_read_capacity_data_long rcap_buf;
3181230592Sken		struct ccb_dev_advinfo cdai;
3182230592Sken		struct mpssas_lun *lun;
3183230592Sken		lun_id_t lunid;
3184230592Sken		int found_lun;
3185230592Sken		uintptr_t buftype;
3186230592Sken
3187230592Sken		buftype = (uintptr_t)arg;
3188230592Sken
3189230592Sken		found_lun = 0;
3190230592Sken		sassc = sc->sassc;
3191230592Sken
3192230592Sken		/*
3193230592Sken		 * We're only interested in read capacity data changes.
3194230592Sken		 */
3195230592Sken		if (buftype != CDAI_TYPE_RCAPLONG)
3196230592Sken			break;
3197230592Sken
3198230592Sken		/*
3199230592Sken		 * We should have a handle for this, but check to make sure.
3200230592Sken		 */
3201230592Sken		target = &sassc->targets[xpt_path_target_id(path)];
3202230592Sken		if (target->handle == 0)
3203230592Sken			break;
3204230592Sken
3205230592Sken		lunid = xpt_path_lun_id(path);
3206230592Sken
3207230592Sken		SLIST_FOREACH(lun, &target->luns, lun_link) {
3208230592Sken			if (lun->lun_id == lunid) {
3209230592Sken				found_lun = 1;
3210230592Sken				break;
3211230592Sken			}
3212230592Sken		}
3213230592Sken
3214230592Sken		if (found_lun == 0) {
3215230592Sken			lun = malloc(sizeof(struct mpssas_lun), M_MPT2,
3216230592Sken				     M_NOWAIT | M_ZERO);
3217230592Sken			if (lun == NULL) {
3218253460Sscottl				mps_dprint(sc, MPS_ERROR, "Unable to alloc "
3219230592Sken					   "LUN for EEDP support.\n");
3220230592Sken				break;
3221230592Sken			}
3222230592Sken			lun->lun_id = lunid;
3223230592Sken			SLIST_INSERT_HEAD(&target->luns, lun, lun_link);
3224230592Sken		}
3225230592Sken
3226230592Sken		bzero(&rcap_buf, sizeof(rcap_buf));
3227230592Sken		xpt_setup_ccb(&cdai.ccb_h, path, CAM_PRIORITY_NORMAL);
3228230592Sken		cdai.ccb_h.func_code = XPT_DEV_ADVINFO;
3229230592Sken		cdai.ccb_h.flags = CAM_DIR_IN;
3230230592Sken		cdai.buftype = CDAI_TYPE_RCAPLONG;
3231230592Sken		cdai.flags = 0;
3232230592Sken		cdai.bufsiz = sizeof(rcap_buf);
3233230592Sken		cdai.buf = (uint8_t *)&rcap_buf;
3234230592Sken		xpt_action((union ccb *)&cdai);
3235230592Sken		if ((cdai.ccb_h.status & CAM_DEV_QFRZN) != 0)
3236230592Sken			cam_release_devq(cdai.ccb_h.path,
3237230592Sken					 0, 0, 0, FALSE);
3238230592Sken
3239230592Sken		if (((cdai.ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP)
3240230592Sken		 && (rcap_buf.prot & SRC16_PROT_EN)) {
3241230592Sken			lun->eedp_formatted = TRUE;
3242230592Sken			lun->eedp_block_size = scsi_4btoul(rcap_buf.length);
3243230592Sken		} else {
3244230592Sken			lun->eedp_formatted = FALSE;
3245230592Sken			lun->eedp_block_size = 0;
3246230592Sken		}
3247230592Sken		break;
3248230592Sken	}
3249253549Sken#else
3250253549Sken	case AC_FOUND_DEVICE: {
3251253549Sken		struct ccb_getdev *cgd;
3252253549Sken
3253253549Sken		cgd = arg;
3254253549Sken		mpssas_check_eedp(sc, path, cgd);
3255253549Sken		break;
3256253549Sken	}
3257253549Sken#endif
3258230592Sken	default:
3259230592Sken		break;
3260230592Sken	}
3261230592Sken}
3262230592Sken
3263253549Sken#if (__FreeBSD_version < 901503) || \
3264253549Sken    ((__FreeBSD_version >= 1000000) && (__FreeBSD_version < 1000006))
3265230592Skenstatic void
3266253549Skenmpssas_check_eedp(struct mps_softc *sc, struct cam_path *path,
3267253549Sken		  struct ccb_getdev *cgd)
3268230592Sken{
3269253549Sken	struct mpssas_softc *sassc = sc->sassc;
3270230592Sken	struct ccb_scsiio *csio;
3271230592Sken	struct scsi_read_capacity_16 *scsi_cmd;
3272230592Sken	struct scsi_read_capacity_eedp *rcap_buf;
3273253549Sken	path_id_t pathid;
3274230592Sken	target_id_t targetid;
3275230592Sken	lun_id_t lunid;
3276253549Sken	union ccb *ccb;
3277253549Sken	struct cam_path *local_path;
3278230592Sken	struct mpssas_target *target;
3279230592Sken	struct mpssas_lun *lun;
3280230592Sken	uint8_t	found_lun;
3281237683Sken	char path_str[64];
3282230592Sken
3283253549Sken	sassc = sc->sassc;
3284253549Sken	pathid = cam_sim_path(sassc->sim);
3285253549Sken	targetid = xpt_path_target_id(path);
3286253549Sken	lunid = xpt_path_lun_id(path);
3287253549Sken
3288253549Sken	target = &sassc->targets[targetid];
3289253549Sken	if (target->handle == 0x0)
3290253549Sken		return;
3291253549Sken
3292230592Sken	/*
3293253549Sken	 * Determine if the device is EEDP capable.
3294253549Sken	 *
3295253549Sken	 * If this flag is set in the inquiry data,
3296253549Sken	 * the device supports protection information,
3297253549Sken	 * and must support the 16 byte read
3298253549Sken	 * capacity command, otherwise continue without
3299253549Sken	 * sending read cap 16
3300230592Sken	 */
3301253549Sken	if ((cgd->inq_data.spc3_flags & SPC3_SID_PROTECT) == 0)
3302253549Sken		return;
3303230592Sken
3304253549Sken	/*
3305253549Sken	 * Issue a READ CAPACITY 16 command.  This info
3306253549Sken	 * is used to determine if the LUN is formatted
3307253549Sken	 * for EEDP support.
3308253549Sken	 */
3309253549Sken	ccb = xpt_alloc_ccb_nowait();
3310253549Sken	if (ccb == NULL) {
3311253549Sken		mps_dprint(sc, MPS_ERROR, "Unable to alloc CCB "
3312253549Sken		    "for EEDP support.\n");
3313253549Sken		return;
3314253549Sken	}
3315230592Sken
3316253549Sken	if (xpt_create_path(&local_path, xpt_periph,
3317253549Sken	    pathid, targetid, lunid) != CAM_REQ_CMP) {
3318253549Sken		mps_dprint(sc, MPS_ERROR, "Unable to create "
3319253549Sken		    "path for EEDP support\n");
3320253549Sken		xpt_free_ccb(ccb);
3321253549Sken		return;
3322253549Sken	}
3323230592Sken
3324253549Sken	/*
3325253549Sken	 * If LUN is already in list, don't create a new
3326253549Sken	 * one.
3327253549Sken	 */
3328253549Sken	found_lun = FALSE;
3329253549Sken	SLIST_FOREACH(lun, &target->luns, lun_link) {
3330253549Sken		if (lun->lun_id == lunid) {
3331253549Sken			found_lun = TRUE;
3332253549Sken			break;
3333253549Sken		}
3334253549Sken	}
3335253549Sken	if (!found_lun) {
3336253549Sken		lun = malloc(sizeof(struct mpssas_lun), M_MPT2,
3337253549Sken		    M_NOWAIT | M_ZERO);
3338253549Sken		if (lun == NULL) {
3339253549Sken			mps_dprint(sc, MPS_ERROR,
3340253549Sken			    "Unable to alloc LUN for EEDP support.\n");
3341253549Sken			xpt_free_path(local_path);
3342253549Sken			xpt_free_ccb(ccb);
3343253549Sken			return;
3344253549Sken		}
3345253549Sken		lun->lun_id = lunid;
3346253549Sken		SLIST_INSERT_HEAD(&target->luns, lun,
3347253549Sken		    lun_link);
3348253549Sken	}
3349230592Sken
3350253549Sken	xpt_path_string(local_path, path_str, sizeof(path_str));
3351253549Sken	mps_dprint(sc, MPS_INFO, "Sending read cap: path %s handle %d\n",
3352253549Sken	    path_str, target->handle);
3353237683Sken
3354253549Sken	/*
3355253549Sken	 * Issue a READ CAPACITY 16 command for the LUN.
3356253549Sken	 * The mpssas_read_cap_done function will load
3357253549Sken	 * the read cap info into the LUN struct.
3358253549Sken	 */
3359253549Sken	rcap_buf = malloc(sizeof(struct scsi_read_capacity_eedp),
3360253549Sken	    M_MPT2, M_NOWAIT | M_ZERO);
3361253549Sken	if (rcap_buf == NULL) {
3362253549Sken		mps_dprint(sc, MPS_FAULT,
3363253549Sken		    "Unable to alloc read capacity buffer for EEDP support.\n");
3364253549Sken		xpt_free_path(ccb->ccb_h.path);
3365253549Sken		xpt_free_ccb(ccb);
3366253549Sken		return;
3367253549Sken	}
3368253549Sken	xpt_setup_ccb(&ccb->ccb_h, local_path, CAM_PRIORITY_XPT);
3369253549Sken	csio = &ccb->csio;
3370253549Sken	csio->ccb_h.func_code = XPT_SCSI_IO;
3371253549Sken	csio->ccb_h.flags = CAM_DIR_IN;
3372253549Sken	csio->ccb_h.retry_count = 4;
3373253549Sken	csio->ccb_h.cbfcnp = mpssas_read_cap_done;
3374253549Sken	csio->ccb_h.timeout = 60000;
3375253549Sken	csio->data_ptr = (uint8_t *)rcap_buf;
3376253549Sken	csio->dxfer_len = sizeof(struct scsi_read_capacity_eedp);
3377253549Sken	csio->sense_len = MPS_SENSE_LEN;
3378253549Sken	csio->cdb_len = sizeof(*scsi_cmd);
3379253549Sken	csio->tag_action = MSG_SIMPLE_Q_TAG;
3380237683Sken
3381253549Sken	scsi_cmd = (struct scsi_read_capacity_16 *)&csio->cdb_io.cdb_bytes;
3382253549Sken	bzero(scsi_cmd, sizeof(*scsi_cmd));
3383253549Sken	scsi_cmd->opcode = 0x9E;
3384253549Sken	scsi_cmd->service_action = SRC16_SERVICE_ACTION;
3385253549Sken	((uint8_t *)scsi_cmd)[13] = sizeof(struct scsi_read_capacity_eedp);
3386230592Sken
3387253549Sken	ccb->ccb_h.ppriv_ptr1 = sassc;
3388253549Sken	xpt_action(ccb);
3389230592Sken}
3390230592Sken
3391230592Skenstatic void
3392230592Skenmpssas_read_cap_done(struct cam_periph *periph, union ccb *done_ccb)
3393230592Sken{
3394230592Sken	struct mpssas_softc *sassc;
3395230592Sken	struct mpssas_target *target;
3396230592Sken	struct mpssas_lun *lun;
3397230592Sken	struct scsi_read_capacity_eedp *rcap_buf;
3398230592Sken
3399230592Sken	if (done_ccb == NULL)
3400230592Sken		return;
3401231240Sken
3402231240Sken	/* Driver need to release devq, it Scsi command is
3403231240Sken	 * generated by driver internally.
3404231240Sken	 * Currently there is a single place where driver
3405231240Sken	 * calls scsi command internally. In future if driver
3406231240Sken	 * calls more scsi command internally, it needs to release
3407231240Sken	 * devq internally, since those command will not go back to
3408231240Sken	 * cam_periph.
3409231240Sken	 */
3410231240Sken	if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) ) {
3411231240Sken        	done_ccb->ccb_h.status &= ~CAM_DEV_QFRZN;
3412231240Sken		xpt_release_devq(done_ccb->ccb_h.path,
3413231240Sken			       	/*count*/ 1, /*run_queue*/TRUE);
3414231240Sken	}
3415230592Sken
3416230592Sken	rcap_buf = (struct scsi_read_capacity_eedp *)done_ccb->csio.data_ptr;
3417230592Sken
3418230592Sken	/*
3419230592Sken	 * Get the LUN ID for the path and look it up in the LUN list for the
3420230592Sken	 * target.
3421230592Sken	 */
3422230592Sken	sassc = (struct mpssas_softc *)done_ccb->ccb_h.ppriv_ptr1;
3423230592Sken	target = &sassc->targets[done_ccb->ccb_h.target_id];
3424230592Sken	SLIST_FOREACH(lun, &target->luns, lun_link) {
3425230592Sken		if (lun->lun_id != done_ccb->ccb_h.target_lun)
3426230592Sken			continue;
3427230592Sken
3428230592Sken		/*
3429230592Sken		 * Got the LUN in the target's LUN list.  Fill it in
3430230592Sken		 * with EEDP info.  If the READ CAP 16 command had some
3431230592Sken		 * SCSI error (common if command is not supported), mark
3432230592Sken		 * the lun as not supporting EEDP and set the block size
3433230592Sken		 * to 0.
3434230592Sken		 */
3435230592Sken		if (((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)
3436230592Sken		 || (done_ccb->csio.scsi_status != SCSI_STATUS_OK)) {
3437230592Sken			lun->eedp_formatted = FALSE;
3438230592Sken			lun->eedp_block_size = 0;
3439230592Sken			break;
3440230592Sken		}
3441230592Sken
3442230592Sken		if (rcap_buf->protect & 0x01) {
3443253550Sken			mps_dprint(sassc->sc, MPS_INFO, "LUN %d for "
3444253550Sken 			    "target ID %d is formatted for EEDP "
3445253550Sken 			    "support.\n", done_ccb->ccb_h.target_lun,
3446253550Sken 			    done_ccb->ccb_h.target_id);
3447230592Sken			lun->eedp_formatted = TRUE;
3448230592Sken			lun->eedp_block_size = scsi_4btoul(rcap_buf->length);
3449230592Sken		}
3450230592Sken		break;
3451230592Sken	}
3452230592Sken
3453230592Sken	// Finished with this CCB and path.
3454230592Sken	free(rcap_buf, M_MPT2);
3455230592Sken	xpt_free_path(done_ccb->ccb_h.path);
3456230592Sken	xpt_free_ccb(done_ccb);
3457230592Sken}
3458253549Sken#endif /* (__FreeBSD_version < 901503) || \
3459253549Sken          ((__FreeBSD_version >= 1000000) && (__FreeBSD_version < 1000006)) */
3460230592Sken
3461230592Skenint
3462230592Skenmpssas_startup(struct mps_softc *sc)
3463230592Sken{
3464230592Sken	struct mpssas_softc *sassc;
3465230592Sken
3466230592Sken	/*
3467230592Sken	 * Send the port enable message and set the wait_for_port_enable flag.
3468230592Sken	 * This flag helps to keep the simq frozen until all discovery events
3469230592Sken	 * are processed.
3470230592Sken	 */
3471230592Sken	sassc = sc->sassc;
3472230592Sken	mpssas_startup_increment(sassc);
3473230592Sken	sc->wait_for_port_enable = 1;
3474230592Sken	mpssas_send_portenable(sc);
3475230592Sken	return (0);
3476230592Sken}
3477230592Sken
3478230592Skenstatic int
3479230592Skenmpssas_send_portenable(struct mps_softc *sc)
3480230592Sken{
3481230592Sken	MPI2_PORT_ENABLE_REQUEST *request;
3482230592Sken	struct mps_command *cm;
3483230592Sken
3484253460Sscottl	MPS_FUNCTRACE(sc);
3485230592Sken
3486230592Sken	if ((cm = mps_alloc_command(sc)) == NULL)
3487230592Sken		return (EBUSY);
3488230592Sken	request = (MPI2_PORT_ENABLE_REQUEST *)cm->cm_req;
3489230592Sken	request->Function = MPI2_FUNCTION_PORT_ENABLE;
3490230592Sken	request->MsgFlags = 0;
3491230592Sken	request->VP_ID = 0;
3492230592Sken	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
3493230592Sken	cm->cm_complete = mpssas_portenable_complete;
3494230592Sken	cm->cm_data = NULL;
3495230592Sken	cm->cm_sge = NULL;
3496230592Sken
3497230592Sken	mps_map_command(sc, cm);
3498253460Sscottl	mps_dprint(sc, MPS_XINFO,
3499230592Sken	    "mps_send_portenable finished cm %p req %p complete %p\n",
3500230592Sken	    cm, cm->cm_req, cm->cm_complete);
3501230592Sken	return (0);
3502230592Sken}
3503230592Sken
3504230592Skenstatic void
3505230592Skenmpssas_portenable_complete(struct mps_softc *sc, struct mps_command *cm)
3506230592Sken{
3507230592Sken	MPI2_PORT_ENABLE_REPLY *reply;
3508230592Sken	struct mpssas_softc *sassc;
3509230592Sken
3510253460Sscottl	MPS_FUNCTRACE(sc);
3511230592Sken	sassc = sc->sassc;
3512230592Sken
3513230592Sken	/*
3514230592Sken	 * Currently there should be no way we can hit this case.  It only
3515230592Sken	 * happens when we have a failure to allocate chain frames, and
3516230592Sken	 * port enable commands don't have S/G lists.
3517230592Sken	 */
3518230592Sken	if ((cm->cm_flags & MPS_CM_FLAGS_ERROR_MASK) != 0) {
3519253460Sscottl		mps_dprint(sc, MPS_ERROR, "%s: cm_flags = %#x for port enable! "
3520230592Sken			   "This should not happen!\n", __func__, cm->cm_flags);
3521230592Sken	}
3522230592Sken
3523230592Sken	reply = (MPI2_PORT_ENABLE_REPLY *)cm->cm_reply;
3524230592Sken	if (reply == NULL)
3525230592Sken		mps_dprint(sc, MPS_FAULT, "Portenable NULL reply\n");
3526237683Sken	else if (le16toh(reply->IOCStatus & MPI2_IOCSTATUS_MASK) !=
3527230592Sken	    MPI2_IOCSTATUS_SUCCESS)
3528230592Sken		mps_dprint(sc, MPS_FAULT, "Portenable failed\n");
3529230592Sken
3530230592Sken	mps_free_command(sc, cm);
3531230592Sken	if (sc->mps_ich.ich_arg != NULL) {
3532253460Sscottl		mps_dprint(sc, MPS_XINFO, "disestablish config intrhook\n");
3533230592Sken		config_intrhook_disestablish(&sc->mps_ich);
3534230592Sken		sc->mps_ich.ich_arg = NULL;
3535230592Sken	}
3536230592Sken
3537230592Sken	/*
3538230592Sken	 * Get WarpDrive info after discovery is complete but before the scan
3539230592Sken	 * starts.  At this point, all devices are ready to be exposed to the
3540230592Sken	 * OS.  If devices should be hidden instead, take them out of the
3541230592Sken	 * 'targets' array before the scan.  The devinfo for a disk will have
3542230592Sken	 * some info and a volume's will be 0.  Use that to remove disks.
3543230592Sken	 */
3544230592Sken	mps_wd_config_pages(sc);
3545230592Sken
3546230592Sken	/*
3547230592Sken	 * Done waiting for port enable to complete.  Decrement the refcount.
3548230592Sken	 * If refcount is 0, discovery is complete and a rescan of the bus can
3549230592Sken	 * take place.  Since the simq was explicitly frozen before port
3550230592Sken	 * enable, it must be explicitly released here to keep the
3551230592Sken	 * freeze/release count in sync.
3552230592Sken	 */
3553230592Sken	sc->wait_for_port_enable = 0;
3554230592Sken	sc->port_enable_complete = 1;
3555237683Sken	wakeup(&sc->port_enable_complete);
3556230592Sken	mpssas_startup_decrement(sassc);
3557230592Sken	xpt_release_simq(sassc->sim, 1);
3558230592Sken}
3559230592Sken
3560254116Sscottlint
3561254116Sscottlmpssas_check_id(struct mpssas_softc *sassc, int id)
3562254116Sscottl{
3563254116Sscottl	struct mps_softc *sc = sassc->sc;
3564254116Sscottl	char *ids;
3565254116Sscottl	char *name;
3566254116Sscottl
3567254116Sscottl	ids = &sc->exclude_ids[0];
3568254116Sscottl	while((name = strsep(&ids, ",")) != NULL) {
3569254116Sscottl		if (name[0] == '\0')
3570254116Sscottl			continue;
3571254116Sscottl		if (strtol(name, NULL, 0) == (long)id)
3572254116Sscottl			return (1);
3573254116Sscottl	}
3574254116Sscottl
3575254116Sscottl	return (0);
3576254116Sscottl}
3577