1265555Sambrisko/*
2284267Skadesai * Copyright (c) 2015, AVAGO Tech. All rights reserved. Author: Marian Choy
3275976Ssmh * Copyright (c) 2014, LSI Corp. All rights reserved. Author: Marian Choy
4284267Skadesai * Support: freebsdraid@avagotech.com
5265555Sambrisko *
6265555Sambrisko * Redistribution and use in source and binary forms, with or without
7275976Ssmh * modification, are permitted provided that the following conditions are
8275976Ssmh * met:
9265555Sambrisko *
10275976Ssmh * 1. Redistributions of source code must retain the above copyright notice,
11275976Ssmh * this list of conditions and the following disclaimer. 2. Redistributions
12275976Ssmh * in binary form must reproduce the above copyright notice, this list of
13275976Ssmh * conditions and the following disclaimer in the documentation and/or other
14275976Ssmh * materials provided with the distribution. 3. Neither the name of the
15275976Ssmh * <ORGANIZATION> nor the names of its contributors may be used to endorse or
16275976Ssmh * promote products derived from this software without specific prior written
17275976Ssmh * permission.
18265555Sambrisko *
19275976Ssmh * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20275976Ssmh * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21275976Ssmh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22275976Ssmh * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23275976Ssmh * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24275976Ssmh * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25275976Ssmh * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26275976Ssmh * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27275976Ssmh * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28275976Ssmh * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29265555Sambrisko * POSSIBILITY OF SUCH DAMAGE.
30265555Sambrisko *
31275976Ssmh * The views and conclusions contained in the software and documentation are
32275976Ssmh * those of the authors and should not be interpreted as representing
33265555Sambrisko * official policies,either expressed or implied, of the FreeBSD Project.
34265555Sambrisko *
35284267Skadesai * Send feedback to: <megaraidfbsd@avagotech.com> Mail to: AVAGO TECHNOLOGIES 1621
36275976Ssmh * Barber Lane, Milpitas, CA 95035 ATTN: MegaRaid FreeBSD
37265555Sambrisko *
38265555Sambrisko */
39265555Sambrisko
40265555Sambrisko#include <sys/cdefs.h>
41265555Sambrisko__FBSDID("$FreeBSD: releng/10.3/sys/dev/mrsas/mrsas.c 284267 2015-06-11 14:11:41Z kadesai $");
42265555Sambrisko
43265555Sambrisko#include <dev/mrsas/mrsas.h>
44265555Sambrisko#include <dev/mrsas/mrsas_ioctl.h>
45265555Sambrisko
46265555Sambrisko#include <cam/cam.h>
47265555Sambrisko#include <cam/cam_ccb.h>
48265555Sambrisko
49265555Sambrisko#include <sys/sysctl.h>
50265555Sambrisko#include <sys/types.h>
51265555Sambrisko#include <sys/kthread.h>
52265555Sambrisko#include <sys/taskqueue.h>
53275976Ssmh#include <sys/smp.h>
54265555Sambrisko
55265555Sambrisko
56275976Ssmh/*
57275976Ssmh * Function prototypes
58265555Sambrisko */
59275976Ssmhstatic d_open_t mrsas_open;
60275976Ssmhstatic d_close_t mrsas_close;
61275976Ssmhstatic d_read_t mrsas_read;
62275976Ssmhstatic d_write_t mrsas_write;
63275976Ssmhstatic d_ioctl_t mrsas_ioctl;
64275976Ssmhstatic d_poll_t mrsas_poll;
65265555Sambrisko
66275976Ssmhstatic struct mrsas_mgmt_info mrsas_mgmt_info;
67265555Sambriskostatic struct mrsas_ident *mrsas_find_ident(device_t);
68275976Ssmhstatic int mrsas_setup_msix(struct mrsas_softc *sc);
69275976Ssmhstatic int mrsas_allocate_msix(struct mrsas_softc *sc);
70265555Sambriskostatic void mrsas_shutdown_ctlr(struct mrsas_softc *sc, u_int32_t opcode);
71265555Sambriskostatic void mrsas_flush_cache(struct mrsas_softc *sc);
72265555Sambriskostatic void mrsas_reset_reply_desc(struct mrsas_softc *sc);
73265555Sambriskostatic void mrsas_ocr_thread(void *arg);
74265555Sambriskostatic int mrsas_get_map_info(struct mrsas_softc *sc);
75265555Sambriskostatic int mrsas_get_ld_map_info(struct mrsas_softc *sc);
76265555Sambriskostatic int mrsas_sync_map_info(struct mrsas_softc *sc);
77265555Sambriskostatic int mrsas_get_pd_list(struct mrsas_softc *sc);
78265555Sambriskostatic int mrsas_get_ld_list(struct mrsas_softc *sc);
79265555Sambriskostatic int mrsas_setup_irq(struct mrsas_softc *sc);
80265555Sambriskostatic int mrsas_alloc_mem(struct mrsas_softc *sc);
81265555Sambriskostatic int mrsas_init_fw(struct mrsas_softc *sc);
82265555Sambriskostatic int mrsas_setup_raidmap(struct mrsas_softc *sc);
83275976Ssmhstatic int mrsas_complete_cmd(struct mrsas_softc *sc, u_int32_t MSIxIndex);
84265555Sambriskostatic int mrsas_clear_intr(struct mrsas_softc *sc);
85284267Skadesaistatic int mrsas_get_ctrl_info(struct mrsas_softc *sc);
86284267Skadesaistatic void mrsas_update_ext_vd_details(struct mrsas_softc *sc);
87284267Skadesaistatic int
88275976Ssmhmrsas_issue_blocked_abort_cmd(struct mrsas_softc *sc,
89275976Ssmh    struct mrsas_mfi_cmd *cmd_to_abort);
90284267Skadesaistatic struct mrsas_softc *
91284267Skadesaimrsas_get_softc_instance(struct cdev *dev,
92284267Skadesai    u_long cmd, caddr_t arg);
93265555Sambriskou_int32_t mrsas_read_reg(struct mrsas_softc *sc, int offset);
94284267Skadesaiu_int8_t
95275976Ssmhmrsas_build_mptmfi_passthru(struct mrsas_softc *sc,
96275976Ssmh    struct mrsas_mfi_cmd *mfi_cmd);
97284267Skadesaivoid	mrsas_complete_outstanding_ioctls(struct mrsas_softc *sc);
98275976Ssmhint	mrsas_transition_to_ready(struct mrsas_softc *sc, int ocr);
99275976Ssmhint	mrsas_init_adapter(struct mrsas_softc *sc);
100275976Ssmhint	mrsas_alloc_mpt_cmds(struct mrsas_softc *sc);
101275976Ssmhint	mrsas_alloc_ioc_cmd(struct mrsas_softc *sc);
102275976Ssmhint	mrsas_alloc_ctlr_info_cmd(struct mrsas_softc *sc);
103275976Ssmhint	mrsas_ioc_init(struct mrsas_softc *sc);
104275976Ssmhint	mrsas_bus_scan(struct mrsas_softc *sc);
105275976Ssmhint	mrsas_issue_dcmd(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd);
106275976Ssmhint	mrsas_issue_polled(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd);
107275976Ssmhint	mrsas_reset_ctrl(struct mrsas_softc *sc);
108275976Ssmhint	mrsas_wait_for_outstanding(struct mrsas_softc *sc);
109284267Skadesaiint
110275976Ssmhmrsas_issue_blocked_cmd(struct mrsas_softc *sc,
111275976Ssmh    struct mrsas_mfi_cmd *cmd);
112284267Skadesaiint
113275976Ssmhmrsas_alloc_tmp_dcmd(struct mrsas_softc *sc, struct mrsas_tmp_dcmd *tcmd,
114275976Ssmh    int size);
115275976Ssmhvoid	mrsas_release_mfi_cmd(struct mrsas_mfi_cmd *cmd);
116275976Ssmhvoid	mrsas_wakeup(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd);
117275976Ssmhvoid	mrsas_complete_aen(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd);
118275976Ssmhvoid	mrsas_complete_abort(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd);
119275976Ssmhvoid	mrsas_disable_intr(struct mrsas_softc *sc);
120275976Ssmhvoid	mrsas_enable_intr(struct mrsas_softc *sc);
121275976Ssmhvoid	mrsas_free_ioc_cmd(struct mrsas_softc *sc);
122275976Ssmhvoid	mrsas_free_mem(struct mrsas_softc *sc);
123275976Ssmhvoid	mrsas_free_tmp_dcmd(struct mrsas_tmp_dcmd *tmp);
124275976Ssmhvoid	mrsas_isr(void *arg);
125275976Ssmhvoid	mrsas_teardown_intr(struct mrsas_softc *sc);
126275976Ssmhvoid	mrsas_addr_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error);
127275976Ssmhvoid	mrsas_kill_hba(struct mrsas_softc *sc);
128275976Ssmhvoid	mrsas_aen_handler(struct mrsas_softc *sc);
129284267Skadesaivoid
130275976Ssmhmrsas_write_reg(struct mrsas_softc *sc, int offset,
131275976Ssmh    u_int32_t value);
132284267Skadesaivoid
133275976Ssmhmrsas_fire_cmd(struct mrsas_softc *sc, u_int32_t req_desc_lo,
134275976Ssmh    u_int32_t req_desc_hi);
135275976Ssmhvoid	mrsas_free_ctlr_info_cmd(struct mrsas_softc *sc);
136284267Skadesaivoid
137275976Ssmhmrsas_complete_mptmfi_passthru(struct mrsas_softc *sc,
138275976Ssmh    struct mrsas_mfi_cmd *cmd, u_int8_t status);
139284267Skadesaivoid
140275976Ssmhmrsas_map_mpt_cmd_status(struct mrsas_mpt_cmd *cmd, u_int8_t status,
141275976Ssmh    u_int8_t extStatus);
142275976Ssmhstruct mrsas_mfi_cmd *mrsas_get_mfi_cmd(struct mrsas_softc *sc);
143265555Sambrisko
144275976SsmhMRSAS_REQUEST_DESCRIPTOR_UNION *mrsas_build_mpt_cmd
145275976Ssmh        (struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd);
146275976Ssmh
147265555Sambriskoextern int mrsas_cam_attach(struct mrsas_softc *sc);
148265555Sambriskoextern void mrsas_cam_detach(struct mrsas_softc *sc);
149265555Sambriskoextern void mrsas_cmd_done(struct mrsas_softc *sc, struct mrsas_mpt_cmd *cmd);
150265555Sambriskoextern void mrsas_free_frame(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd);
151265555Sambriskoextern int mrsas_alloc_mfi_cmds(struct mrsas_softc *sc);
152275976Ssmhextern void mrsas_release_mpt_cmd(struct mrsas_mpt_cmd *cmd);
153265555Sambriskoextern struct mrsas_mpt_cmd *mrsas_get_mpt_cmd(struct mrsas_softc *sc);
154275976Ssmhextern int mrsas_passthru(struct mrsas_softc *sc, void *arg, u_long ioctlCmd);
155265555Sambriskoextern uint8_t MR_ValidateMapInfo(struct mrsas_softc *sc);
156275976Ssmhextern u_int16_t MR_GetLDTgtId(u_int32_t ld, MR_DRV_RAID_MAP_ALL * map);
157275976Ssmhextern MR_LD_RAID *MR_LdRaidGet(u_int32_t ld, MR_DRV_RAID_MAP_ALL * map);
158265555Sambriskoextern void mrsas_xpt_freeze(struct mrsas_softc *sc);
159265555Sambriskoextern void mrsas_xpt_release(struct mrsas_softc *sc);
160275976Ssmhextern MRSAS_REQUEST_DESCRIPTOR_UNION *
161275976Ssmhmrsas_get_request_desc(struct mrsas_softc *sc,
162275976Ssmh    u_int16_t index);
163265555Sambriskoextern int mrsas_bus_scan_sim(struct mrsas_softc *sc, struct cam_sim *sim);
164265555Sambriskostatic int mrsas_alloc_evt_log_info_cmd(struct mrsas_softc *sc);
165265555Sambriskostatic void mrsas_free_evt_log_info_cmd(struct mrsas_softc *sc);
166275976Ssmh
167265555SambriskoSYSCTL_NODE(_hw, OID_AUTO, mrsas, CTLFLAG_RD, 0, "MRSAS Driver Parameters");
168265555Sambrisko
169275976Ssmh/*
170265555Sambrisko * PCI device struct and table
171265555Sambrisko *
172265555Sambrisko */
173265555Sambriskotypedef struct mrsas_ident {
174275976Ssmh	uint16_t vendor;
175275976Ssmh	uint16_t device;
176275976Ssmh	uint16_t subvendor;
177275976Ssmh	uint16_t subdevice;
178275976Ssmh	const char *desc;
179275976Ssmh}	MRSAS_CTLR_ID;
180265555Sambrisko
181265555SambriskoMRSAS_CTLR_ID device_table[] = {
182284267Skadesai	{0x1000, MRSAS_TBOLT, 0xffff, 0xffff, "AVAGO Thunderbolt SAS Controller"},
183284267Skadesai	{0x1000, MRSAS_INVADER, 0xffff, 0xffff, "AVAGO Invader SAS Controller"},
184284267Skadesai	{0x1000, MRSAS_FURY, 0xffff, 0xffff, "AVAGO Fury SAS Controller"},
185275976Ssmh	{0, 0, 0, 0, NULL}
186265555Sambrisko};
187265555Sambrisko
188275976Ssmh/*
189275976Ssmh * Character device entry points
190265555Sambrisko *
191265555Sambrisko */
192265555Sambriskostatic struct cdevsw mrsas_cdevsw = {
193275976Ssmh	.d_version = D_VERSION,
194275976Ssmh	.d_open = mrsas_open,
195275976Ssmh	.d_close = mrsas_close,
196275976Ssmh	.d_read = mrsas_read,
197275976Ssmh	.d_write = mrsas_write,
198275976Ssmh	.d_ioctl = mrsas_ioctl,
199275976Ssmh	.d_poll = mrsas_poll,
200275976Ssmh	.d_name = "mrsas",
201265555Sambrisko};
202265555Sambrisko
203265555SambriskoMALLOC_DEFINE(M_MRSAS, "mrsasbuf", "Buffers for the MRSAS driver");
204265555Sambrisko
205275976Ssmh/*
206275976Ssmh * In the cdevsw routines, we find our softc by using the si_drv1 member of
207275976Ssmh * struct cdev.  We set this variable to point to our softc in our attach
208275976Ssmh * routine when we create the /dev entry.
209265555Sambrisko */
210265555Sambriskoint
211265555Sambriskomrsas_open(struct cdev *dev, int oflags, int devtype, d_thread_t *td)
212265555Sambrisko{
213275976Ssmh	struct mrsas_softc *sc;
214265555Sambrisko
215275976Ssmh	sc = dev->si_drv1;
216275976Ssmh	return (0);
217265555Sambrisko}
218265555Sambrisko
219265555Sambriskoint
220265555Sambriskomrsas_close(struct cdev *dev, int fflag, int devtype, d_thread_t *td)
221265555Sambrisko{
222275976Ssmh	struct mrsas_softc *sc;
223265555Sambrisko
224275976Ssmh	sc = dev->si_drv1;
225275976Ssmh	return (0);
226265555Sambrisko}
227265555Sambrisko
228265555Sambriskoint
229265555Sambriskomrsas_read(struct cdev *dev, struct uio *uio, int ioflag)
230265555Sambrisko{
231275976Ssmh	struct mrsas_softc *sc;
232265555Sambrisko
233275976Ssmh	sc = dev->si_drv1;
234275976Ssmh	return (0);
235265555Sambrisko}
236265555Sambriskoint
237265555Sambriskomrsas_write(struct cdev *dev, struct uio *uio, int ioflag)
238265555Sambrisko{
239275976Ssmh	struct mrsas_softc *sc;
240265555Sambrisko
241275976Ssmh	sc = dev->si_drv1;
242275976Ssmh	return (0);
243265555Sambrisko}
244265555Sambrisko
245275976Ssmh/*
246275976Ssmh * Register Read/Write Functions
247265555Sambrisko *
248265555Sambrisko */
249265555Sambriskovoid
250265555Sambriskomrsas_write_reg(struct mrsas_softc *sc, int offset,
251275976Ssmh    u_int32_t value)
252265555Sambrisko{
253275976Ssmh	bus_space_tag_t bus_tag = sc->bus_tag;
254275976Ssmh	bus_space_handle_t bus_handle = sc->bus_handle;
255265555Sambrisko
256275976Ssmh	bus_space_write_4(bus_tag, bus_handle, offset, value);
257265555Sambrisko}
258265555Sambrisko
259265555Sambriskou_int32_t
260265555Sambriskomrsas_read_reg(struct mrsas_softc *sc, int offset)
261265555Sambrisko{
262275976Ssmh	bus_space_tag_t bus_tag = sc->bus_tag;
263275976Ssmh	bus_space_handle_t bus_handle = sc->bus_handle;
264265555Sambrisko
265275976Ssmh	return ((u_int32_t)bus_space_read_4(bus_tag, bus_handle, offset));
266265555Sambrisko}
267265555Sambrisko
268265555Sambrisko
269275976Ssmh/*
270275976Ssmh * Interrupt Disable/Enable/Clear Functions
271265555Sambrisko *
272265555Sambrisko */
273275976Ssmhvoid
274275976Ssmhmrsas_disable_intr(struct mrsas_softc *sc)
275265555Sambrisko{
276275976Ssmh	u_int32_t mask = 0xFFFFFFFF;
277275976Ssmh	u_int32_t status;
278265555Sambrisko
279284267Skadesai	sc->mask_interrupts = 1;
280275976Ssmh	mrsas_write_reg(sc, offsetof(mrsas_reg_set, outbound_intr_mask), mask);
281275976Ssmh	/* Dummy read to force pci flush */
282275976Ssmh	status = mrsas_read_reg(sc, offsetof(mrsas_reg_set, outbound_intr_mask));
283265555Sambrisko}
284265555Sambrisko
285275976Ssmhvoid
286275976Ssmhmrsas_enable_intr(struct mrsas_softc *sc)
287265555Sambrisko{
288275976Ssmh	u_int32_t mask = MFI_FUSION_ENABLE_INTERRUPT_MASK;
289275976Ssmh	u_int32_t status;
290265555Sambrisko
291284267Skadesai	sc->mask_interrupts = 0;
292275976Ssmh	mrsas_write_reg(sc, offsetof(mrsas_reg_set, outbound_intr_status), ~0);
293275976Ssmh	status = mrsas_read_reg(sc, offsetof(mrsas_reg_set, outbound_intr_status));
294265555Sambrisko
295275976Ssmh	mrsas_write_reg(sc, offsetof(mrsas_reg_set, outbound_intr_mask), ~mask);
296275976Ssmh	status = mrsas_read_reg(sc, offsetof(mrsas_reg_set, outbound_intr_mask));
297265555Sambrisko}
298265555Sambrisko
299275976Ssmhstatic int
300275976Ssmhmrsas_clear_intr(struct mrsas_softc *sc)
301265555Sambrisko{
302275976Ssmh	u_int32_t status, fw_status, fw_state;
303265555Sambrisko
304275976Ssmh	/* Read received interrupt */
305275976Ssmh	status = mrsas_read_reg(sc, offsetof(mrsas_reg_set, outbound_intr_status));
306265555Sambrisko
307275976Ssmh	/*
308275976Ssmh	 * If FW state change interrupt is received, write to it again to
309275976Ssmh	 * clear
310275976Ssmh	 */
311275976Ssmh	if (status & MRSAS_FW_STATE_CHNG_INTERRUPT) {
312275976Ssmh		fw_status = mrsas_read_reg(sc, offsetof(mrsas_reg_set,
313275976Ssmh		    outbound_scratch_pad));
314275976Ssmh		fw_state = fw_status & MFI_STATE_MASK;
315275976Ssmh		if (fw_state == MFI_STATE_FAULT) {
316275976Ssmh			device_printf(sc->mrsas_dev, "FW is in FAULT state!\n");
317275976Ssmh			if (sc->ocr_thread_active)
318275976Ssmh				wakeup(&sc->ocr_chan);
319275976Ssmh		}
320275976Ssmh		mrsas_write_reg(sc, offsetof(mrsas_reg_set, outbound_intr_status), status);
321275976Ssmh		mrsas_read_reg(sc, offsetof(mrsas_reg_set, outbound_intr_status));
322275976Ssmh		return (1);
323275976Ssmh	}
324275976Ssmh	/* Not our interrupt, so just return */
325275976Ssmh	if (!(status & MFI_FUSION_ENABLE_INTERRUPT_MASK))
326275976Ssmh		return (0);
327265555Sambrisko
328275976Ssmh	/* We got a reply interrupt */
329275976Ssmh	return (1);
330265555Sambrisko}
331265555Sambrisko
332275976Ssmh/*
333275976Ssmh * PCI Support Functions
334265555Sambrisko *
335265555Sambrisko */
336275976Ssmhstatic struct mrsas_ident *
337275976Ssmhmrsas_find_ident(device_t dev)
338265555Sambrisko{
339275976Ssmh	struct mrsas_ident *pci_device;
340265555Sambrisko
341275976Ssmh	for (pci_device = device_table; pci_device->vendor != 0; pci_device++) {
342275976Ssmh		if ((pci_device->vendor == pci_get_vendor(dev)) &&
343275976Ssmh		    (pci_device->device == pci_get_device(dev)) &&
344275976Ssmh		    ((pci_device->subvendor == pci_get_subvendor(dev)) ||
345275976Ssmh		    (pci_device->subvendor == 0xffff)) &&
346275976Ssmh		    ((pci_device->subdevice == pci_get_subdevice(dev)) ||
347275976Ssmh		    (pci_device->subdevice == 0xffff)))
348275976Ssmh			return (pci_device);
349275976Ssmh	}
350275976Ssmh	return (NULL);
351265555Sambrisko}
352265555Sambrisko
353275976Ssmhstatic int
354275976Ssmhmrsas_probe(device_t dev)
355265555Sambrisko{
356275976Ssmh	static u_int8_t first_ctrl = 1;
357275976Ssmh	struct mrsas_ident *id;
358265555Sambrisko
359275976Ssmh	if ((id = mrsas_find_ident(dev)) != NULL) {
360275976Ssmh		if (first_ctrl) {
361284267Skadesai			printf("AVAGO MegaRAID SAS FreeBSD mrsas driver version: %s\n",
362275976Ssmh			    MRSAS_VERSION);
363275976Ssmh			first_ctrl = 0;
364275976Ssmh		}
365275976Ssmh		device_set_desc(dev, id->desc);
366275976Ssmh		/* between BUS_PROBE_DEFAULT and BUS_PROBE_LOW_PRIORITY */
367275976Ssmh		return (-30);
368275976Ssmh	}
369275976Ssmh	return (ENXIO);
370265555Sambrisko}
371265555Sambrisko
372275976Ssmh/*
373275976Ssmh * mrsas_setup_sysctl:	setup sysctl values for mrsas
374275976Ssmh * input:				Adapter instance soft state
375265555Sambrisko *
376265555Sambrisko * Setup sysctl entries for mrsas driver.
377265555Sambrisko */
378265555Sambriskostatic void
379265555Sambriskomrsas_setup_sysctl(struct mrsas_softc *sc)
380265555Sambrisko{
381275976Ssmh	struct sysctl_ctx_list *sysctl_ctx = NULL;
382275976Ssmh	struct sysctl_oid *sysctl_tree = NULL;
383275976Ssmh	char tmpstr[80], tmpstr2[80];
384265555Sambrisko
385275976Ssmh	/*
386275976Ssmh	 * Setup the sysctl variable so the user can change the debug level
387275976Ssmh	 * on the fly.
388275976Ssmh	 */
389275976Ssmh	snprintf(tmpstr, sizeof(tmpstr), "MRSAS controller %d",
390275976Ssmh	    device_get_unit(sc->mrsas_dev));
391275976Ssmh	snprintf(tmpstr2, sizeof(tmpstr2), "%d", device_get_unit(sc->mrsas_dev));
392265555Sambrisko
393275976Ssmh	sysctl_ctx = device_get_sysctl_ctx(sc->mrsas_dev);
394275976Ssmh	if (sysctl_ctx != NULL)
395275976Ssmh		sysctl_tree = device_get_sysctl_tree(sc->mrsas_dev);
396265555Sambrisko
397275976Ssmh	if (sysctl_tree == NULL) {
398275976Ssmh		sysctl_ctx_init(&sc->sysctl_ctx);
399275976Ssmh		sc->sysctl_tree = SYSCTL_ADD_NODE(&sc->sysctl_ctx,
400275976Ssmh		    SYSCTL_STATIC_CHILDREN(_hw_mrsas), OID_AUTO, tmpstr2,
401275976Ssmh		    CTLFLAG_RD, 0, tmpstr);
402275976Ssmh		if (sc->sysctl_tree == NULL)
403275976Ssmh			return;
404275976Ssmh		sysctl_ctx = &sc->sysctl_ctx;
405275976Ssmh		sysctl_tree = sc->sysctl_tree;
406275976Ssmh	}
407275976Ssmh	SYSCTL_ADD_UINT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
408275976Ssmh	    OID_AUTO, "disable_ocr", CTLFLAG_RW, &sc->disableOnlineCtrlReset, 0,
409275976Ssmh	    "Disable the use of OCR");
410265555Sambrisko
411275976Ssmh	SYSCTL_ADD_STRING(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
412275976Ssmh	    OID_AUTO, "driver_version", CTLFLAG_RD, MRSAS_VERSION,
413275976Ssmh	    strlen(MRSAS_VERSION), "driver version");
414265555Sambrisko
415275976Ssmh	SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
416275976Ssmh	    OID_AUTO, "reset_count", CTLFLAG_RD,
417275976Ssmh	    &sc->reset_count, 0, "number of ocr from start of the day");
418265555Sambrisko
419275976Ssmh	SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
420275976Ssmh	    OID_AUTO, "fw_outstanding", CTLFLAG_RD,
421275976Ssmh	    &sc->fw_outstanding.val_rdonly, 0, "FW outstanding commands");
422265555Sambrisko
423265555Sambrisko	SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
424275976Ssmh	    OID_AUTO, "io_cmds_highwater", CTLFLAG_RD,
425275976Ssmh	    &sc->io_cmds_highwater, 0, "Max FW outstanding commands");
426265555Sambrisko
427275976Ssmh	SYSCTL_ADD_UINT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
428275976Ssmh	    OID_AUTO, "mrsas_debug", CTLFLAG_RW, &sc->mrsas_debug, 0,
429275976Ssmh	    "Driver debug level");
430265555Sambrisko
431275976Ssmh	SYSCTL_ADD_UINT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
432275976Ssmh	    OID_AUTO, "mrsas_io_timeout", CTLFLAG_RW, &sc->mrsas_io_timeout,
433275976Ssmh	    0, "Driver IO timeout value in mili-second.");
434265555Sambrisko
435275976Ssmh	SYSCTL_ADD_UINT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
436275976Ssmh	    OID_AUTO, "mrsas_fw_fault_check_delay", CTLFLAG_RW,
437275976Ssmh	    &sc->mrsas_fw_fault_check_delay,
438275976Ssmh	    0, "FW fault check thread delay in seconds. <default is 1 sec>");
439265555Sambrisko
440275976Ssmh	SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
441275976Ssmh	    OID_AUTO, "reset_in_progress", CTLFLAG_RD,
442275976Ssmh	    &sc->reset_in_progress, 0, "ocr in progress status");
443265555Sambrisko
444265555Sambrisko}
445265555Sambrisko
446275976Ssmh/*
447275976Ssmh * mrsas_get_tunables:	get tunable parameters.
448275976Ssmh * input:				Adapter instance soft state
449265555Sambrisko *
450265555Sambrisko * Get tunable parameters. This will help to debug driver at boot time.
451265555Sambrisko */
452265555Sambriskostatic void
453265555Sambriskomrsas_get_tunables(struct mrsas_softc *sc)
454265555Sambrisko{
455275976Ssmh	char tmpstr[80];
456265555Sambrisko
457275976Ssmh	/* XXX default to some debugging for now */
458275976Ssmh	sc->mrsas_debug = MRSAS_FAULT;
459275976Ssmh	sc->mrsas_io_timeout = MRSAS_IO_TIMEOUT;
460275976Ssmh	sc->mrsas_fw_fault_check_delay = 1;
461275976Ssmh	sc->reset_count = 0;
462275976Ssmh	sc->reset_in_progress = 0;
463265555Sambrisko
464275976Ssmh	/*
465275976Ssmh	 * Grab the global variables.
466275976Ssmh	 */
467275976Ssmh	TUNABLE_INT_FETCH("hw.mrsas.debug_level", &sc->mrsas_debug);
468265555Sambrisko
469284267Skadesai	/*
470284267Skadesai	 * Grab the global variables.
471284267Skadesai	 */
472284267Skadesai	TUNABLE_INT_FETCH("hw.mrsas.lb_pending_cmds", &sc->lb_pending_cmds);
473284267Skadesai
474275976Ssmh	/* Grab the unit-instance variables */
475275976Ssmh	snprintf(tmpstr, sizeof(tmpstr), "dev.mrsas.%d.debug_level",
476275976Ssmh	    device_get_unit(sc->mrsas_dev));
477275976Ssmh	TUNABLE_INT_FETCH(tmpstr, &sc->mrsas_debug);
478265555Sambrisko}
479265555Sambrisko
480275976Ssmh/*
481275976Ssmh * mrsas_alloc_evt_log_info cmd: Allocates memory to get event log information.
482275976Ssmh * Used to get sequence number at driver load time.
483275976Ssmh * input:		Adapter soft state
484265555Sambrisko *
485265555Sambrisko * Allocates DMAable memory for the event log info internal command.
486265555Sambrisko */
487275976Ssmhint
488275976Ssmhmrsas_alloc_evt_log_info_cmd(struct mrsas_softc *sc)
489265555Sambrisko{
490275976Ssmh	int el_info_size;
491265555Sambrisko
492275976Ssmh	/* Allocate get event log info command */
493275976Ssmh	el_info_size = sizeof(struct mrsas_evt_log_info);
494275976Ssmh	if (bus_dma_tag_create(sc->mrsas_parent_tag,
495275976Ssmh	    1, 0,
496275976Ssmh	    BUS_SPACE_MAXADDR_32BIT,
497275976Ssmh	    BUS_SPACE_MAXADDR,
498275976Ssmh	    NULL, NULL,
499275976Ssmh	    el_info_size,
500275976Ssmh	    1,
501275976Ssmh	    el_info_size,
502275976Ssmh	    BUS_DMA_ALLOCNOW,
503275976Ssmh	    NULL, NULL,
504275976Ssmh	    &sc->el_info_tag)) {
505275976Ssmh		device_printf(sc->mrsas_dev, "Cannot allocate event log info tag\n");
506275976Ssmh		return (ENOMEM);
507275976Ssmh	}
508275976Ssmh	if (bus_dmamem_alloc(sc->el_info_tag, (void **)&sc->el_info_mem,
509275976Ssmh	    BUS_DMA_NOWAIT, &sc->el_info_dmamap)) {
510275976Ssmh		device_printf(sc->mrsas_dev, "Cannot allocate event log info cmd mem\n");
511275976Ssmh		return (ENOMEM);
512275976Ssmh	}
513275976Ssmh	if (bus_dmamap_load(sc->el_info_tag, sc->el_info_dmamap,
514275976Ssmh	    sc->el_info_mem, el_info_size, mrsas_addr_cb,
515275976Ssmh	    &sc->el_info_phys_addr, BUS_DMA_NOWAIT)) {
516275976Ssmh		device_printf(sc->mrsas_dev, "Cannot load event log info cmd mem\n");
517275976Ssmh		return (ENOMEM);
518275976Ssmh	}
519275976Ssmh	memset(sc->el_info_mem, 0, el_info_size);
520275976Ssmh	return (0);
521265555Sambrisko}
522265555Sambrisko
523275976Ssmh/*
524275976Ssmh * mrsas_free_evt_info_cmd:	Free memory for Event log info command
525275976Ssmh * input:					Adapter soft state
526265555Sambrisko *
527265555Sambrisko * Deallocates memory for the event log info internal command.
528265555Sambrisko */
529275976Ssmhvoid
530275976Ssmhmrsas_free_evt_log_info_cmd(struct mrsas_softc *sc)
531265555Sambrisko{
532275976Ssmh	if (sc->el_info_phys_addr)
533275976Ssmh		bus_dmamap_unload(sc->el_info_tag, sc->el_info_dmamap);
534275976Ssmh	if (sc->el_info_mem != NULL)
535275976Ssmh		bus_dmamem_free(sc->el_info_tag, sc->el_info_mem, sc->el_info_dmamap);
536275976Ssmh	if (sc->el_info_tag != NULL)
537275976Ssmh		bus_dma_tag_destroy(sc->el_info_tag);
538265555Sambrisko}
539265555Sambrisko
540275976Ssmh/*
541265555Sambrisko *  mrsas_get_seq_num:	Get latest event sequence number
542265555Sambrisko *  @sc:				Adapter soft state
543265555Sambrisko *  @eli:				Firmware event log sequence number information.
544275976Ssmh *
545275976Ssmh * Firmware maintains a log of all events in a non-volatile area.
546275976Ssmh * Driver get the sequence number using DCMD
547275976Ssmh * "MR_DCMD_CTRL_EVENT_GET_INFO" at driver load time.
548265555Sambrisko */
549265555Sambrisko
550265555Sambriskostatic int
551265555Sambriskomrsas_get_seq_num(struct mrsas_softc *sc,
552275976Ssmh    struct mrsas_evt_log_info *eli)
553265555Sambrisko{
554265555Sambrisko	struct mrsas_mfi_cmd *cmd;
555265555Sambrisko	struct mrsas_dcmd_frame *dcmd;
556265555Sambrisko
557275976Ssmh	cmd = mrsas_get_mfi_cmd(sc);
558265555Sambrisko
559265555Sambrisko	if (!cmd) {
560265555Sambrisko		device_printf(sc->mrsas_dev, "Failed to get a free cmd\n");
561265555Sambrisko		return -ENOMEM;
562265555Sambrisko	}
563265555Sambrisko	dcmd = &cmd->frame->dcmd;
564265555Sambrisko
565265555Sambrisko	if (mrsas_alloc_evt_log_info_cmd(sc) != SUCCESS) {
566265555Sambrisko		device_printf(sc->mrsas_dev, "Cannot allocate evt log info cmd\n");
567265555Sambrisko		mrsas_release_mfi_cmd(cmd);
568265555Sambrisko		return -ENOMEM;
569265555Sambrisko	}
570265555Sambrisko	memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
571265555Sambrisko
572265555Sambrisko	dcmd->cmd = MFI_CMD_DCMD;
573265555Sambrisko	dcmd->cmd_status = 0x0;
574265555Sambrisko	dcmd->sge_count = 1;
575265555Sambrisko	dcmd->flags = MFI_FRAME_DIR_READ;
576265555Sambrisko	dcmd->timeout = 0;
577265555Sambrisko	dcmd->pad_0 = 0;
578265555Sambrisko	dcmd->data_xfer_len = sizeof(struct mrsas_evt_log_info);
579265555Sambrisko	dcmd->opcode = MR_DCMD_CTRL_EVENT_GET_INFO;
580265555Sambrisko	dcmd->sgl.sge32[0].phys_addr = sc->el_info_phys_addr;
581265555Sambrisko	dcmd->sgl.sge32[0].length = sizeof(struct mrsas_evt_log_info);
582265555Sambrisko
583265555Sambrisko	mrsas_issue_blocked_cmd(sc, cmd);
584265555Sambrisko
585265555Sambrisko	/*
586275976Ssmh	 * Copy the data back into callers buffer
587275976Ssmh	 */
588265555Sambrisko	memcpy(eli, sc->el_info_mem, sizeof(struct mrsas_evt_log_info));
589265555Sambrisko	mrsas_free_evt_log_info_cmd(sc);
590265555Sambrisko	mrsas_release_mfi_cmd(cmd);
591265555Sambrisko
592265555Sambrisko	return 0;
593265555Sambrisko}
594265555Sambrisko
595265555Sambrisko
596275976Ssmh/*
597265555Sambrisko *  mrsas_register_aen:		Register for asynchronous event notification
598275976Ssmh *  @sc:			Adapter soft state
599275976Ssmh *  @seq_num:			Starting sequence number
600275976Ssmh *  @class_locale:		Class of the event
601275976Ssmh *
602275976Ssmh *  This function subscribes for events beyond the @seq_num
603275976Ssmh *  and type @class_locale.
604275976Ssmh *
605275976Ssmh */
606265555Sambriskostatic int
607265555Sambriskomrsas_register_aen(struct mrsas_softc *sc, u_int32_t seq_num,
608275976Ssmh    u_int32_t class_locale_word)
609265555Sambrisko{
610265555Sambrisko	int ret_val;
611265555Sambrisko	struct mrsas_mfi_cmd *cmd;
612265555Sambrisko	struct mrsas_dcmd_frame *dcmd;
613265555Sambrisko	union mrsas_evt_class_locale curr_aen;
614265555Sambrisko	union mrsas_evt_class_locale prev_aen;
615265555Sambrisko
616275976Ssmh	/*
617275976Ssmh	 * If there an AEN pending already (aen_cmd), check if the
618275976Ssmh	 * class_locale of that pending AEN is inclusive of the new AEN
619275976Ssmh	 * request we currently have. If it is, then we don't have to do
620275976Ssmh	 * anything. In other words, whichever events the current AEN request
621275976Ssmh	 * is subscribing to, have already been subscribed to. If the old_cmd
622275976Ssmh	 * is _not_ inclusive, then we have to abort that command, form a
623275976Ssmh	 * class_locale that is superset of both old and current and re-issue
624275976Ssmh	 * to the FW
625275976Ssmh	 */
626265555Sambrisko
627265555Sambrisko	curr_aen.word = class_locale_word;
628265555Sambrisko
629265555Sambrisko	if (sc->aen_cmd) {
630265555Sambrisko
631265555Sambrisko		prev_aen.word = sc->aen_cmd->frame->dcmd.mbox.w[1];
632265555Sambrisko
633275976Ssmh		/*
634275976Ssmh		 * A class whose enum value is smaller is inclusive of all
635275976Ssmh		 * higher values. If a PROGRESS (= -1) was previously
636275976Ssmh		 * registered, then a new registration requests for higher
637275976Ssmh		 * classes need not be sent to FW. They are automatically
638275976Ssmh		 * included. Locale numbers don't have such hierarchy. They
639275976Ssmh		 * are bitmap values
640275976Ssmh		 */
641265555Sambrisko		if ((prev_aen.members.class <= curr_aen.members.class) &&
642275976Ssmh		    !((prev_aen.members.locale & curr_aen.members.locale) ^
643275976Ssmh		    curr_aen.members.locale)) {
644265555Sambrisko			/*
645275976Ssmh			 * Previously issued event registration includes
646275976Ssmh			 * current request. Nothing to do.
647275976Ssmh			 */
648265555Sambrisko			return 0;
649265555Sambrisko		} else {
650265555Sambrisko			curr_aen.members.locale |= prev_aen.members.locale;
651265555Sambrisko
652265555Sambrisko			if (prev_aen.members.class < curr_aen.members.class)
653265555Sambrisko				curr_aen.members.class = prev_aen.members.class;
654265555Sambrisko
655265555Sambrisko			sc->aen_cmd->abort_aen = 1;
656265555Sambrisko			ret_val = mrsas_issue_blocked_abort_cmd(sc,
657275976Ssmh			    sc->aen_cmd);
658265555Sambrisko
659265555Sambrisko			if (ret_val) {
660265555Sambrisko				printf("mrsas: Failed to abort "
661275976Ssmh				    "previous AEN command\n");
662265555Sambrisko				return ret_val;
663265555Sambrisko			}
664265555Sambrisko		}
665265555Sambrisko	}
666275976Ssmh	cmd = mrsas_get_mfi_cmd(sc);
667265555Sambrisko
668265555Sambrisko	if (!cmd)
669265555Sambrisko		return -ENOMEM;
670265555Sambrisko
671265555Sambrisko	dcmd = &cmd->frame->dcmd;
672265555Sambrisko
673265555Sambrisko	memset(sc->evt_detail_mem, 0, sizeof(struct mrsas_evt_detail));
674265555Sambrisko
675275976Ssmh	/*
676275976Ssmh	 * Prepare DCMD for aen registration
677275976Ssmh	 */
678265555Sambrisko	memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
679265555Sambrisko
680265555Sambrisko	dcmd->cmd = MFI_CMD_DCMD;
681265555Sambrisko	dcmd->cmd_status = 0x0;
682265555Sambrisko	dcmd->sge_count = 1;
683265555Sambrisko	dcmd->flags = MFI_FRAME_DIR_READ;
684265555Sambrisko	dcmd->timeout = 0;
685265555Sambrisko	dcmd->pad_0 = 0;
686265555Sambrisko	dcmd->data_xfer_len = sizeof(struct mrsas_evt_detail);
687265555Sambrisko	dcmd->opcode = MR_DCMD_CTRL_EVENT_WAIT;
688265555Sambrisko	dcmd->mbox.w[0] = seq_num;
689275976Ssmh	sc->last_seq_num = seq_num;
690265555Sambrisko	dcmd->mbox.w[1] = curr_aen.word;
691275976Ssmh	dcmd->sgl.sge32[0].phys_addr = (u_int32_t)sc->evt_detail_phys_addr;
692265555Sambrisko	dcmd->sgl.sge32[0].length = sizeof(struct mrsas_evt_detail);
693265555Sambrisko
694265555Sambrisko	if (sc->aen_cmd != NULL) {
695265555Sambrisko		mrsas_release_mfi_cmd(cmd);
696265555Sambrisko		return 0;
697265555Sambrisko	}
698265555Sambrisko	/*
699275976Ssmh	 * Store reference to the cmd used to register for AEN. When an
700275976Ssmh	 * application wants us to register for AEN, we have to abort this
701275976Ssmh	 * cmd and re-register with a new EVENT LOCALE supplied by that app
702275976Ssmh	 */
703265555Sambrisko	sc->aen_cmd = cmd;
704265555Sambrisko
705265555Sambrisko	/*
706275976Ssmh	 * Issue the aen registration frame
707275976Ssmh	 */
708275976Ssmh	if (mrsas_issue_dcmd(sc, cmd)) {
709275976Ssmh		device_printf(sc->mrsas_dev, "Cannot issue AEN DCMD command.\n");
710275976Ssmh		return (1);
711275976Ssmh	}
712265555Sambrisko	return 0;
713265555Sambrisko}
714275976Ssmh
715275976Ssmh/*
716275976Ssmh * mrsas_start_aen:	Subscribes to AEN during driver load time
717275976Ssmh * @instance:		Adapter soft state
718265555Sambrisko */
719275976Ssmhstatic int
720275976Ssmhmrsas_start_aen(struct mrsas_softc *sc)
721265555Sambrisko{
722265555Sambrisko	struct mrsas_evt_log_info eli;
723265555Sambrisko	union mrsas_evt_class_locale class_locale;
724265555Sambrisko
725265555Sambrisko
726275976Ssmh	/* Get the latest sequence number from FW */
727275976Ssmh
728265555Sambrisko	memset(&eli, 0, sizeof(eli));
729265555Sambrisko
730265555Sambrisko	if (mrsas_get_seq_num(sc, &eli))
731265555Sambrisko		return -1;
732265555Sambrisko
733275976Ssmh	/* Register AEN with FW for latest sequence number plus 1 */
734265555Sambrisko	class_locale.members.reserved = 0;
735265555Sambrisko	class_locale.members.locale = MR_EVT_LOCALE_ALL;
736265555Sambrisko	class_locale.members.class = MR_EVT_CLASS_DEBUG;
737265555Sambrisko
738265555Sambrisko	return mrsas_register_aen(sc, eli.newest_seq_num + 1,
739275976Ssmh	    class_locale.word);
740275976Ssmh
741265555Sambrisko}
742265555Sambrisko
743275976Ssmh/*
744275976Ssmh * mrsas_setup_msix:	Allocate MSI-x vectors
745275976Ssmh * @sc:					adapter soft state
746265555Sambrisko */
747275976Ssmhstatic int
748275976Ssmhmrsas_setup_msix(struct mrsas_softc *sc)
749265555Sambrisko{
750275976Ssmh	int i;
751265555Sambrisko
752275976Ssmh	for (i = 0; i < sc->msix_vectors; i++) {
753275976Ssmh		sc->irq_context[i].sc = sc;
754275976Ssmh		sc->irq_context[i].MSIxIndex = i;
755275976Ssmh		sc->irq_id[i] = i + 1;
756275976Ssmh		sc->mrsas_irq[i] = bus_alloc_resource_any
757275976Ssmh		    (sc->mrsas_dev, SYS_RES_IRQ, &sc->irq_id[i]
758275976Ssmh		    ,RF_ACTIVE);
759275976Ssmh		if (sc->mrsas_irq[i] == NULL) {
760275976Ssmh			device_printf(sc->mrsas_dev, "Can't allocate MSI-x\n");
761275976Ssmh			goto irq_alloc_failed;
762275976Ssmh		}
763275976Ssmh		if (bus_setup_intr(sc->mrsas_dev,
764275976Ssmh		    sc->mrsas_irq[i],
765275976Ssmh		    INTR_MPSAFE | INTR_TYPE_CAM,
766275976Ssmh		    NULL, mrsas_isr, &sc->irq_context[i],
767275976Ssmh		    &sc->intr_handle[i])) {
768275976Ssmh			device_printf(sc->mrsas_dev,
769275976Ssmh			    "Cannot set up MSI-x interrupt handler\n");
770275976Ssmh			goto irq_alloc_failed;
771275976Ssmh		}
772275976Ssmh	}
773275976Ssmh	return SUCCESS;
774265555Sambrisko
775275976Ssmhirq_alloc_failed:
776275976Ssmh	mrsas_teardown_intr(sc);
777275976Ssmh	return (FAIL);
778275976Ssmh}
779265555Sambrisko
780275976Ssmh/*
781275976Ssmh * mrsas_allocate_msix:		Setup MSI-x vectors
782275976Ssmh * @sc:						adapter soft state
783275976Ssmh */
784275976Ssmhstatic int
785275976Ssmhmrsas_allocate_msix(struct mrsas_softc *sc)
786275976Ssmh{
787275976Ssmh	if (pci_alloc_msix(sc->mrsas_dev, &sc->msix_vectors) == 0) {
788275976Ssmh		device_printf(sc->mrsas_dev, "Using MSI-X with %d number"
789275976Ssmh		    " of vectors\n", sc->msix_vectors);
790275976Ssmh	} else {
791275976Ssmh		device_printf(sc->mrsas_dev, "MSI-x setup failed\n");
792275976Ssmh		goto irq_alloc_failed;
793275976Ssmh	}
794275976Ssmh	return SUCCESS;
795265555Sambrisko
796275976Ssmhirq_alloc_failed:
797275976Ssmh	mrsas_teardown_intr(sc);
798275976Ssmh	return (FAIL);
799275976Ssmh}
800265555Sambrisko
801275976Ssmh/*
802275976Ssmh * mrsas_attach:	PCI entry point
803275976Ssmh * input:			pointer to device struct
804275976Ssmh *
805275976Ssmh * Performs setup of PCI and registers, initializes mutexes and linked lists,
806275976Ssmh * registers interrupts and CAM, and initializes   the adapter/controller to
807275976Ssmh * its proper state.
808275976Ssmh */
809275976Ssmhstatic int
810275976Ssmhmrsas_attach(device_t dev)
811275976Ssmh{
812275976Ssmh	struct mrsas_softc *sc = device_get_softc(dev);
813275976Ssmh	uint32_t cmd, bar, error;
814265555Sambrisko
815275976Ssmh	/* Look up our softc and initialize its fields. */
816275976Ssmh	sc->mrsas_dev = dev;
817275976Ssmh	sc->device_id = pci_get_device(dev);
818265555Sambrisko
819275976Ssmh	mrsas_get_tunables(sc);
820265555Sambrisko
821275976Ssmh	/*
822275976Ssmh	 * Set up PCI and registers
823275976Ssmh	 */
824275976Ssmh	cmd = pci_read_config(dev, PCIR_COMMAND, 2);
825275976Ssmh	if ((cmd & PCIM_CMD_PORTEN) == 0) {
826275976Ssmh		return (ENXIO);
827275976Ssmh	}
828275976Ssmh	/* Force the busmaster enable bit on. */
829275976Ssmh	cmd |= PCIM_CMD_BUSMASTEREN;
830275976Ssmh	pci_write_config(dev, PCIR_COMMAND, cmd, 2);
831265555Sambrisko
832275976Ssmh	bar = pci_read_config(dev, MRSAS_PCI_BAR1, 4);
833275976Ssmh
834275976Ssmh	sc->reg_res_id = MRSAS_PCI_BAR1;/* BAR1 offset */
835275976Ssmh	if ((sc->reg_res = bus_alloc_resource(dev, SYS_RES_MEMORY,
836275976Ssmh	    &(sc->reg_res_id), 0, ~0, 1, RF_ACTIVE))
837275976Ssmh	    == NULL) {
838275976Ssmh		device_printf(dev, "Cannot allocate PCI registers\n");
839275976Ssmh		goto attach_fail;
840275976Ssmh	}
841275976Ssmh	sc->bus_tag = rman_get_bustag(sc->reg_res);
842275976Ssmh	sc->bus_handle = rman_get_bushandle(sc->reg_res);
843275976Ssmh
844275976Ssmh	/* Intialize mutexes */
845275976Ssmh	mtx_init(&sc->sim_lock, "mrsas_sim_lock", NULL, MTX_DEF);
846275976Ssmh	mtx_init(&sc->pci_lock, "mrsas_pci_lock", NULL, MTX_DEF);
847275976Ssmh	mtx_init(&sc->io_lock, "mrsas_io_lock", NULL, MTX_DEF);
848275976Ssmh	mtx_init(&sc->aen_lock, "mrsas_aen_lock", NULL, MTX_DEF);
849275976Ssmh	mtx_init(&sc->ioctl_lock, "mrsas_ioctl_lock", NULL, MTX_SPIN);
850275976Ssmh	mtx_init(&sc->mpt_cmd_pool_lock, "mrsas_mpt_cmd_pool_lock", NULL, MTX_DEF);
851275976Ssmh	mtx_init(&sc->mfi_cmd_pool_lock, "mrsas_mfi_cmd_pool_lock", NULL, MTX_DEF);
852275976Ssmh	mtx_init(&sc->raidmap_lock, "mrsas_raidmap_lock", NULL, MTX_DEF);
853275976Ssmh
854275976Ssmh	/*
855275976Ssmh	 * Intialize a counting Semaphore to take care no. of concurrent
856275976Ssmh	 * IOCTLs
857275976Ssmh	 */
858275976Ssmh	sema_init(&sc->ioctl_count_sema, MRSAS_MAX_MFI_CMDS - 5, IOCTL_SEMA_DESCRIPTION);
859275976Ssmh
860275976Ssmh	/* Intialize linked list */
861275976Ssmh	TAILQ_INIT(&sc->mrsas_mpt_cmd_list_head);
862275976Ssmh	TAILQ_INIT(&sc->mrsas_mfi_cmd_list_head);
863275976Ssmh
864275976Ssmh	mrsas_atomic_set(&sc->fw_outstanding, 0);
865275976Ssmh
866265555Sambrisko	sc->io_cmds_highwater = 0;
867265555Sambrisko
868275976Ssmh	/* Create a /dev entry for this device. */
869275976Ssmh	sc->mrsas_cdev = make_dev(&mrsas_cdevsw, device_get_unit(dev), UID_ROOT,
870275976Ssmh	    GID_OPERATOR, (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP), "mrsas%u",
871275976Ssmh	    device_get_unit(dev));
872275976Ssmh	if (device_get_unit(dev) == 0)
873275976Ssmh		make_dev_alias(sc->mrsas_cdev, "megaraid_sas_ioctl_node");
874275976Ssmh	if (sc->mrsas_cdev)
875275976Ssmh		sc->mrsas_cdev->si_drv1 = sc;
876265555Sambrisko
877275976Ssmh	sc->adprecovery = MRSAS_HBA_OPERATIONAL;
878265555Sambrisko	sc->UnevenSpanSupport = 0;
879265555Sambrisko
880275976Ssmh	sc->msix_enable = 0;
881265555Sambrisko
882275976Ssmh	/* Initialize Firmware */
883275976Ssmh	if (mrsas_init_fw(sc) != SUCCESS) {
884275976Ssmh		goto attach_fail_fw;
885275976Ssmh	}
886275976Ssmh	/* Register SCSI mid-layer */
887275976Ssmh	if ((mrsas_cam_attach(sc) != SUCCESS)) {
888275976Ssmh		goto attach_fail_cam;
889275976Ssmh	}
890275976Ssmh	/* Register IRQs */
891275976Ssmh	if (mrsas_setup_irq(sc) != SUCCESS) {
892275976Ssmh		goto attach_fail_irq;
893275976Ssmh	}
894275976Ssmh	/* Enable Interrupts */
895275976Ssmh	mrsas_enable_intr(sc);
896265555Sambrisko
897275976Ssmh	error = mrsas_kproc_create(mrsas_ocr_thread, sc,
898275976Ssmh	    &sc->ocr_thread, 0, 0, "mrsas_ocr%d",
899275976Ssmh	    device_get_unit(sc->mrsas_dev));
900275976Ssmh	if (error) {
901275976Ssmh		printf("Error %d starting rescan thread\n", error);
902275976Ssmh		goto attach_fail_irq;
903275976Ssmh	}
904275976Ssmh	mrsas_setup_sysctl(sc);
905265555Sambrisko
906275976Ssmh	/* Initiate AEN (Asynchronous Event Notification) */
907265555Sambrisko
908265555Sambrisko	if (mrsas_start_aen(sc)) {
909265555Sambrisko		printf("Error: start aen failed\n");
910265555Sambrisko		goto fail_start_aen;
911265555Sambrisko	}
912275976Ssmh	/*
913275976Ssmh	 * Add this controller to mrsas_mgmt_info structure so that it can be
914275976Ssmh	 * exported to management applications
915275976Ssmh	 */
916275976Ssmh	if (device_get_unit(dev) == 0)
917275976Ssmh		memset(&mrsas_mgmt_info, 0, sizeof(mrsas_mgmt_info));
918265555Sambrisko
919275976Ssmh	mrsas_mgmt_info.count++;
920275976Ssmh	mrsas_mgmt_info.sc_ptr[mrsas_mgmt_info.max_index] = sc;
921275976Ssmh	mrsas_mgmt_info.max_index++;
922265555Sambrisko
923275976Ssmh	return (0);
924275976Ssmh
925265555Sambriskofail_start_aen:
926265555Sambriskoattach_fail_irq:
927275976Ssmh	mrsas_teardown_intr(sc);
928265555Sambriskoattach_fail_cam:
929275976Ssmh	mrsas_cam_detach(sc);
930265555Sambriskoattach_fail_fw:
931275976Ssmh	/* if MSIX vector is allocated and FW Init FAILED then release MSIX */
932275976Ssmh	if (sc->msix_enable == 1)
933275976Ssmh		pci_release_msi(sc->mrsas_dev);
934275976Ssmh	mrsas_free_mem(sc);
935275976Ssmh	mtx_destroy(&sc->sim_lock);
936275976Ssmh	mtx_destroy(&sc->aen_lock);
937275976Ssmh	mtx_destroy(&sc->pci_lock);
938275976Ssmh	mtx_destroy(&sc->io_lock);
939275976Ssmh	mtx_destroy(&sc->ioctl_lock);
940275976Ssmh	mtx_destroy(&sc->mpt_cmd_pool_lock);
941275976Ssmh	mtx_destroy(&sc->mfi_cmd_pool_lock);
942275976Ssmh	mtx_destroy(&sc->raidmap_lock);
943275976Ssmh	/* Destroy the counting semaphore created for Ioctl */
944275976Ssmh	sema_destroy(&sc->ioctl_count_sema);
945265555Sambriskoattach_fail:
946275976Ssmh	destroy_dev(sc->mrsas_cdev);
947275976Ssmh	if (sc->reg_res) {
948275976Ssmh		bus_release_resource(sc->mrsas_dev, SYS_RES_MEMORY,
949275976Ssmh		    sc->reg_res_id, sc->reg_res);
950275976Ssmh	}
951275976Ssmh	return (ENXIO);
952265555Sambrisko}
953265555Sambrisko
954275976Ssmh/*
955275976Ssmh * mrsas_detach:	De-allocates and teardown resources
956275976Ssmh * input:			pointer to device struct
957275976Ssmh *
958275976Ssmh * This function is the entry point for device disconnect and detach.
959275976Ssmh * It performs memory de-allocations, shutdown of the controller and various
960265555Sambrisko * teardown and destroy resource functions.
961265555Sambrisko */
962275976Ssmhstatic int
963275976Ssmhmrsas_detach(device_t dev)
964265555Sambrisko{
965275976Ssmh	struct mrsas_softc *sc;
966275976Ssmh	int i = 0;
967265555Sambrisko
968275976Ssmh	sc = device_get_softc(dev);
969275976Ssmh	sc->remove_in_progress = 1;
970275976Ssmh
971275976Ssmh	/* Destroy the character device so no other IOCTL will be handled */
972275976Ssmh	destroy_dev(sc->mrsas_cdev);
973275976Ssmh
974275976Ssmh	/*
975275976Ssmh	 * Take the instance off the instance array. Note that we will not
976275976Ssmh	 * decrement the max_index. We let this array be sparse array
977275976Ssmh	 */
978275976Ssmh	for (i = 0; i < mrsas_mgmt_info.max_index; i++) {
979275976Ssmh		if (mrsas_mgmt_info.sc_ptr[i] == sc) {
980275976Ssmh			mrsas_mgmt_info.count--;
981275976Ssmh			mrsas_mgmt_info.sc_ptr[i] = NULL;
982275976Ssmh			break;
983275976Ssmh		}
984275976Ssmh	}
985275976Ssmh
986275976Ssmh	if (sc->ocr_thread_active)
987275976Ssmh		wakeup(&sc->ocr_chan);
988275976Ssmh	while (sc->reset_in_progress) {
989275976Ssmh		i++;
990275976Ssmh		if (!(i % MRSAS_RESET_NOTICE_INTERVAL)) {
991275976Ssmh			mrsas_dprint(sc, MRSAS_INFO,
992275976Ssmh			    "[%2d]waiting for ocr to be finished\n", i);
993275976Ssmh		}
994275976Ssmh		pause("mr_shutdown", hz);
995275976Ssmh	}
996275976Ssmh	i = 0;
997275976Ssmh	while (sc->ocr_thread_active) {
998275976Ssmh		i++;
999275976Ssmh		if (!(i % MRSAS_RESET_NOTICE_INTERVAL)) {
1000275976Ssmh			mrsas_dprint(sc, MRSAS_INFO,
1001275976Ssmh			    "[%2d]waiting for "
1002275976Ssmh			    "mrsas_ocr thread to quit ocr %d\n", i,
1003275976Ssmh			    sc->ocr_thread_active);
1004275976Ssmh		}
1005275976Ssmh		pause("mr_shutdown", hz);
1006275976Ssmh	}
1007275976Ssmh	mrsas_flush_cache(sc);
1008275976Ssmh	mrsas_shutdown_ctlr(sc, MR_DCMD_CTRL_SHUTDOWN);
1009275976Ssmh	mrsas_disable_intr(sc);
1010275976Ssmh	mrsas_cam_detach(sc);
1011275976Ssmh	mrsas_teardown_intr(sc);
1012275976Ssmh	mrsas_free_mem(sc);
1013275976Ssmh	mtx_destroy(&sc->sim_lock);
1014275976Ssmh	mtx_destroy(&sc->aen_lock);
1015275976Ssmh	mtx_destroy(&sc->pci_lock);
1016275976Ssmh	mtx_destroy(&sc->io_lock);
1017275976Ssmh	mtx_destroy(&sc->ioctl_lock);
1018275976Ssmh	mtx_destroy(&sc->mpt_cmd_pool_lock);
1019275976Ssmh	mtx_destroy(&sc->mfi_cmd_pool_lock);
1020275976Ssmh	mtx_destroy(&sc->raidmap_lock);
1021275976Ssmh
1022275976Ssmh	/* Wait for all the semaphores to be released */
1023275976Ssmh	while (sema_value(&sc->ioctl_count_sema) != (MRSAS_MAX_MFI_CMDS - 5))
1024275976Ssmh		pause("mr_shutdown", hz);
1025275976Ssmh
1026275976Ssmh	/* Destroy the counting semaphore created for Ioctl */
1027275976Ssmh	sema_destroy(&sc->ioctl_count_sema);
1028275976Ssmh
1029275976Ssmh	if (sc->reg_res) {
1030275976Ssmh		bus_release_resource(sc->mrsas_dev,
1031275976Ssmh		    SYS_RES_MEMORY, sc->reg_res_id, sc->reg_res);
1032275976Ssmh	}
1033275976Ssmh	if (sc->sysctl_tree != NULL)
1034275976Ssmh		sysctl_ctx_free(&sc->sysctl_ctx);
1035275976Ssmh
1036275976Ssmh	return (0);
1037265555Sambrisko}
1038265555Sambrisko
1039275976Ssmh/*
1040275976Ssmh * mrsas_free_mem:		Frees allocated memory
1041275976Ssmh * input:				Adapter instance soft state
1042275976Ssmh *
1043265555Sambrisko * This function is called from mrsas_detach() to free previously allocated
1044275976Ssmh * memory.
1045265555Sambrisko */
1046275976Ssmhvoid
1047275976Ssmhmrsas_free_mem(struct mrsas_softc *sc)
1048265555Sambrisko{
1049275976Ssmh	int i;
1050275976Ssmh	u_int32_t max_cmd;
1051275976Ssmh	struct mrsas_mfi_cmd *mfi_cmd;
1052275976Ssmh	struct mrsas_mpt_cmd *mpt_cmd;
1053275976Ssmh
1054265555Sambrisko	/*
1055275976Ssmh	 * Free RAID map memory
1056275976Ssmh	 */
1057275976Ssmh	for (i = 0; i < 2; i++) {
1058275976Ssmh		if (sc->raidmap_phys_addr[i])
1059275976Ssmh			bus_dmamap_unload(sc->raidmap_tag[i], sc->raidmap_dmamap[i]);
1060275976Ssmh		if (sc->raidmap_mem[i] != NULL)
1061275976Ssmh			bus_dmamem_free(sc->raidmap_tag[i], sc->raidmap_mem[i], sc->raidmap_dmamap[i]);
1062275976Ssmh		if (sc->raidmap_tag[i] != NULL)
1063275976Ssmh			bus_dma_tag_destroy(sc->raidmap_tag[i]);
1064265555Sambrisko
1065275976Ssmh		if (sc->ld_drv_map[i] != NULL)
1066275976Ssmh			free(sc->ld_drv_map[i], M_MRSAS);
1067275976Ssmh	}
1068265555Sambrisko
1069275976Ssmh	/*
1070275976Ssmh	 * Free version buffer memroy
1071275976Ssmh	 */
1072275976Ssmh	if (sc->verbuf_phys_addr)
1073275976Ssmh		bus_dmamap_unload(sc->verbuf_tag, sc->verbuf_dmamap);
1074275976Ssmh	if (sc->verbuf_mem != NULL)
1075275976Ssmh		bus_dmamem_free(sc->verbuf_tag, sc->verbuf_mem, sc->verbuf_dmamap);
1076275976Ssmh	if (sc->verbuf_tag != NULL)
1077275976Ssmh		bus_dma_tag_destroy(sc->verbuf_tag);
1078265555Sambrisko
1079265555Sambrisko
1080275976Ssmh	/*
1081275976Ssmh	 * Free sense buffer memory
1082275976Ssmh	 */
1083275976Ssmh	if (sc->sense_phys_addr)
1084275976Ssmh		bus_dmamap_unload(sc->sense_tag, sc->sense_dmamap);
1085275976Ssmh	if (sc->sense_mem != NULL)
1086275976Ssmh		bus_dmamem_free(sc->sense_tag, sc->sense_mem, sc->sense_dmamap);
1087275976Ssmh	if (sc->sense_tag != NULL)
1088275976Ssmh		bus_dma_tag_destroy(sc->sense_tag);
1089265555Sambrisko
1090275976Ssmh	/*
1091275976Ssmh	 * Free chain frame memory
1092275976Ssmh	 */
1093275976Ssmh	if (sc->chain_frame_phys_addr)
1094275976Ssmh		bus_dmamap_unload(sc->chain_frame_tag, sc->chain_frame_dmamap);
1095275976Ssmh	if (sc->chain_frame_mem != NULL)
1096275976Ssmh		bus_dmamem_free(sc->chain_frame_tag, sc->chain_frame_mem, sc->chain_frame_dmamap);
1097275976Ssmh	if (sc->chain_frame_tag != NULL)
1098275976Ssmh		bus_dma_tag_destroy(sc->chain_frame_tag);
1099265555Sambrisko
1100275976Ssmh	/*
1101275976Ssmh	 * Free IO Request memory
1102275976Ssmh	 */
1103275976Ssmh	if (sc->io_request_phys_addr)
1104275976Ssmh		bus_dmamap_unload(sc->io_request_tag, sc->io_request_dmamap);
1105275976Ssmh	if (sc->io_request_mem != NULL)
1106275976Ssmh		bus_dmamem_free(sc->io_request_tag, sc->io_request_mem, sc->io_request_dmamap);
1107275976Ssmh	if (sc->io_request_tag != NULL)
1108275976Ssmh		bus_dma_tag_destroy(sc->io_request_tag);
1109265555Sambrisko
1110275976Ssmh	/*
1111275976Ssmh	 * Free Reply Descriptor memory
1112275976Ssmh	 */
1113275976Ssmh	if (sc->reply_desc_phys_addr)
1114275976Ssmh		bus_dmamap_unload(sc->reply_desc_tag, sc->reply_desc_dmamap);
1115275976Ssmh	if (sc->reply_desc_mem != NULL)
1116275976Ssmh		bus_dmamem_free(sc->reply_desc_tag, sc->reply_desc_mem, sc->reply_desc_dmamap);
1117275976Ssmh	if (sc->reply_desc_tag != NULL)
1118275976Ssmh		bus_dma_tag_destroy(sc->reply_desc_tag);
1119275976Ssmh
1120275976Ssmh	/*
1121275976Ssmh	 * Free event detail memory
1122275976Ssmh	 */
1123275976Ssmh	if (sc->evt_detail_phys_addr)
1124275976Ssmh		bus_dmamap_unload(sc->evt_detail_tag, sc->evt_detail_dmamap);
1125275976Ssmh	if (sc->evt_detail_mem != NULL)
1126275976Ssmh		bus_dmamem_free(sc->evt_detail_tag, sc->evt_detail_mem, sc->evt_detail_dmamap);
1127275976Ssmh	if (sc->evt_detail_tag != NULL)
1128275976Ssmh		bus_dma_tag_destroy(sc->evt_detail_tag);
1129275976Ssmh
1130275976Ssmh	/*
1131275976Ssmh	 * Free MFI frames
1132275976Ssmh	 */
1133265555Sambrisko	if (sc->mfi_cmd_list) {
1134275976Ssmh		for (i = 0; i < MRSAS_MAX_MFI_CMDS; i++) {
1135275976Ssmh			mfi_cmd = sc->mfi_cmd_list[i];
1136275976Ssmh			mrsas_free_frame(sc, mfi_cmd);
1137265555Sambrisko		}
1138275976Ssmh	}
1139275976Ssmh	if (sc->mficmd_frame_tag != NULL)
1140275976Ssmh		bus_dma_tag_destroy(sc->mficmd_frame_tag);
1141265555Sambrisko
1142275976Ssmh	/*
1143275976Ssmh	 * Free MPT internal command list
1144275976Ssmh	 */
1145275976Ssmh	max_cmd = sc->max_fw_cmds;
1146265555Sambrisko	if (sc->mpt_cmd_list) {
1147275976Ssmh		for (i = 0; i < max_cmd; i++) {
1148275976Ssmh			mpt_cmd = sc->mpt_cmd_list[i];
1149275976Ssmh			bus_dmamap_destroy(sc->data_tag, mpt_cmd->data_dmamap);
1150275976Ssmh			free(sc->mpt_cmd_list[i], M_MRSAS);
1151275976Ssmh		}
1152275976Ssmh		free(sc->mpt_cmd_list, M_MRSAS);
1153275976Ssmh		sc->mpt_cmd_list = NULL;
1154265555Sambrisko	}
1155275976Ssmh	/*
1156275976Ssmh	 * Free MFI internal command list
1157275976Ssmh	 */
1158265555Sambrisko
1159265555Sambrisko	if (sc->mfi_cmd_list) {
1160275976Ssmh		for (i = 0; i < MRSAS_MAX_MFI_CMDS; i++) {
1161275976Ssmh			free(sc->mfi_cmd_list[i], M_MRSAS);
1162275976Ssmh		}
1163275976Ssmh		free(sc->mfi_cmd_list, M_MRSAS);
1164275976Ssmh		sc->mfi_cmd_list = NULL;
1165265555Sambrisko	}
1166275976Ssmh	/*
1167275976Ssmh	 * Free request descriptor memory
1168275976Ssmh	 */
1169275976Ssmh	free(sc->req_desc, M_MRSAS);
1170275976Ssmh	sc->req_desc = NULL;
1171265555Sambrisko
1172275976Ssmh	/*
1173275976Ssmh	 * Destroy parent tag
1174275976Ssmh	 */
1175275976Ssmh	if (sc->mrsas_parent_tag != NULL)
1176275976Ssmh		bus_dma_tag_destroy(sc->mrsas_parent_tag);
1177284267Skadesai
1178284267Skadesai	/*
1179284267Skadesai	 * Free ctrl_info memory
1180284267Skadesai	 */
1181284267Skadesai	if (sc->ctrl_info != NULL)
1182284267Skadesai		free(sc->ctrl_info, M_MRSAS);
1183265555Sambrisko}
1184265555Sambrisko
1185275976Ssmh/*
1186275976Ssmh * mrsas_teardown_intr:	Teardown interrupt
1187275976Ssmh * input:				Adapter instance soft state
1188265555Sambrisko *
1189275976Ssmh * This function is called from mrsas_detach() to teardown and release bus
1190275976Ssmh * interrupt resourse.
1191265555Sambrisko */
1192275976Ssmhvoid
1193275976Ssmhmrsas_teardown_intr(struct mrsas_softc *sc)
1194265555Sambrisko{
1195275976Ssmh	int i;
1196275976Ssmh
1197275976Ssmh	if (!sc->msix_enable) {
1198275976Ssmh		if (sc->intr_handle[0])
1199275976Ssmh			bus_teardown_intr(sc->mrsas_dev, sc->mrsas_irq[0], sc->intr_handle[0]);
1200275976Ssmh		if (sc->mrsas_irq[0] != NULL)
1201275976Ssmh			bus_release_resource(sc->mrsas_dev, SYS_RES_IRQ,
1202275976Ssmh			    sc->irq_id[0], sc->mrsas_irq[0]);
1203275976Ssmh		sc->intr_handle[0] = NULL;
1204275976Ssmh	} else {
1205275976Ssmh		for (i = 0; i < sc->msix_vectors; i++) {
1206275976Ssmh			if (sc->intr_handle[i])
1207275976Ssmh				bus_teardown_intr(sc->mrsas_dev, sc->mrsas_irq[i],
1208275976Ssmh				    sc->intr_handle[i]);
1209275976Ssmh
1210275976Ssmh			if (sc->mrsas_irq[i] != NULL)
1211275976Ssmh				bus_release_resource(sc->mrsas_dev, SYS_RES_IRQ,
1212275976Ssmh				    sc->irq_id[i], sc->mrsas_irq[i]);
1213275976Ssmh
1214275976Ssmh			sc->intr_handle[i] = NULL;
1215275976Ssmh		}
1216275976Ssmh		pci_release_msi(sc->mrsas_dev);
1217275976Ssmh	}
1218275976Ssmh
1219265555Sambrisko}
1220265555Sambrisko
1221275976Ssmh/*
1222275976Ssmh * mrsas_suspend:	Suspend entry point
1223275976Ssmh * input:			Device struct pointer
1224275976Ssmh *
1225275976Ssmh * This function is the entry point for system suspend from the OS.
1226265555Sambrisko */
1227275976Ssmhstatic int
1228275976Ssmhmrsas_suspend(device_t dev)
1229265555Sambrisko{
1230275976Ssmh	struct mrsas_softc *sc;
1231265555Sambrisko
1232275976Ssmh	sc = device_get_softc(dev);
1233275976Ssmh	return (0);
1234265555Sambrisko}
1235265555Sambrisko
1236275976Ssmh/*
1237275976Ssmh * mrsas_resume:	Resume entry point
1238275976Ssmh * input:			Device struct pointer
1239275976Ssmh *
1240275976Ssmh * This function is the entry point for system resume from the OS.
1241265555Sambrisko */
1242275976Ssmhstatic int
1243275976Ssmhmrsas_resume(device_t dev)
1244265555Sambrisko{
1245275976Ssmh	struct mrsas_softc *sc;
1246265555Sambrisko
1247275976Ssmh	sc = device_get_softc(dev);
1248275976Ssmh	return (0);
1249265555Sambrisko}
1250265555Sambrisko
1251284267Skadesai/**
1252284267Skadesai * mrsas_get_softc_instance:    Find softc instance based on cmd type
1253284267Skadesai *
1254284267Skadesai * This function will return softc instance based on cmd type.
1255284267Skadesai * In some case, application fire ioctl on required management instance and
1256284267Skadesai * do not provide host_no. Use cdev->si_drv1 to get softc instance for those
1257284267Skadesai * case, else get the softc instance from host_no provided by application in
1258284267Skadesai * user data.
1259284267Skadesai */
1260284267Skadesai
1261284267Skadesaistatic struct mrsas_softc *
1262284267Skadesaimrsas_get_softc_instance(struct cdev *dev, u_long cmd, caddr_t arg)
1263284267Skadesai{
1264284267Skadesai	struct mrsas_softc *sc = NULL;
1265284267Skadesai	struct mrsas_iocpacket *user_ioc = (struct mrsas_iocpacket *)arg;
1266284267Skadesai
1267284267Skadesai	if (cmd == MRSAS_IOC_GET_PCI_INFO) {
1268284267Skadesai		sc = dev->si_drv1;
1269284267Skadesai	} else {
1270284267Skadesai		/*
1271284267Skadesai		 * get the Host number & the softc from data sent by the
1272284267Skadesai		 * Application
1273284267Skadesai		 */
1274284267Skadesai		sc = mrsas_mgmt_info.sc_ptr[user_ioc->host_no];
1275284267Skadesai		if ((user_ioc->host_no >= mrsas_mgmt_info.max_index) || (sc == NULL)) {
1276284267Skadesai			if (sc == NULL)
1277284267Skadesai				mrsas_dprint(sc, MRSAS_FAULT,
1278284267Skadesai				    "There is no Controller number %d .\n", user_ioc->host_no);
1279284267Skadesai			else
1280284267Skadesai				mrsas_dprint(sc, MRSAS_FAULT,
1281284267Skadesai				    "Invalid Controller number %d .\n", user_ioc->host_no);
1282284267Skadesai		}
1283284267Skadesai	}
1284284267Skadesai
1285284267Skadesai	return sc;
1286284267Skadesai}
1287284267Skadesai
1288275976Ssmh/*
1289275976Ssmh * mrsas_ioctl:	IOCtl commands entry point.
1290275976Ssmh *
1291275976Ssmh * This function is the entry point for IOCtls from the OS.  It calls the
1292265555Sambrisko * appropriate function for processing depending on the command received.
1293265555Sambrisko */
1294265555Sambriskostatic int
1295265555Sambriskomrsas_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td)
1296265555Sambrisko{
1297275976Ssmh	struct mrsas_softc *sc;
1298275976Ssmh	int ret = 0, i = 0;
1299284267Skadesai	MRSAS_DRV_PCI_INFORMATION *pciDrvInfo;
1300265555Sambrisko
1301284267Skadesai	sc = mrsas_get_softc_instance(dev, cmd, arg);
1302284267Skadesai	if (!sc)
1303284267Skadesai		return ENOENT;
1304265555Sambrisko
1305275976Ssmh	if (sc->remove_in_progress) {
1306275976Ssmh		mrsas_dprint(sc, MRSAS_INFO,
1307275976Ssmh		    "Driver remove or shutdown called.\n");
1308275976Ssmh		return ENOENT;
1309275976Ssmh	}
1310275976Ssmh	mtx_lock_spin(&sc->ioctl_lock);
1311275976Ssmh	if (!sc->reset_in_progress) {
1312275976Ssmh		mtx_unlock_spin(&sc->ioctl_lock);
1313275976Ssmh		goto do_ioctl;
1314275976Ssmh	}
1315275976Ssmh	mtx_unlock_spin(&sc->ioctl_lock);
1316275976Ssmh	while (sc->reset_in_progress) {
1317275976Ssmh		i++;
1318275976Ssmh		if (!(i % MRSAS_RESET_NOTICE_INTERVAL)) {
1319275976Ssmh			mrsas_dprint(sc, MRSAS_INFO,
1320275976Ssmh			    "[%2d]waiting for "
1321275976Ssmh			    "OCR to be finished %d\n", i,
1322275976Ssmh			    sc->ocr_thread_active);
1323275976Ssmh		}
1324275976Ssmh		pause("mr_ioctl", hz);
1325275976Ssmh	}
1326275976Ssmh
1327265555Sambriskodo_ioctl:
1328275976Ssmh	switch (cmd) {
1329275976Ssmh	case MRSAS_IOC_FIRMWARE_PASS_THROUGH64:
1330275976Ssmh#ifdef COMPAT_FREEBSD32
1331275976Ssmh	case MRSAS_IOC_FIRMWARE_PASS_THROUGH32:
1332275976Ssmh#endif
1333275976Ssmh		/*
1334275976Ssmh		 * Decrement the Ioctl counting Semaphore before getting an
1335275976Ssmh		 * mfi command
1336275976Ssmh		 */
1337275976Ssmh		sema_wait(&sc->ioctl_count_sema);
1338275976Ssmh
1339275976Ssmh		ret = mrsas_passthru(sc, (void *)arg, cmd);
1340275976Ssmh
1341275976Ssmh		/* Increment the Ioctl counting semaphore value */
1342275976Ssmh		sema_post(&sc->ioctl_count_sema);
1343275976Ssmh
1344275976Ssmh		break;
1345275976Ssmh	case MRSAS_IOC_SCAN_BUS:
1346275976Ssmh		ret = mrsas_bus_scan(sc);
1347275976Ssmh		break;
1348284267Skadesai
1349284267Skadesai	case MRSAS_IOC_GET_PCI_INFO:
1350284267Skadesai		pciDrvInfo = (MRSAS_DRV_PCI_INFORMATION *) arg;
1351284267Skadesai		memset(pciDrvInfo, 0, sizeof(MRSAS_DRV_PCI_INFORMATION));
1352284267Skadesai		pciDrvInfo->busNumber = pci_get_bus(sc->mrsas_dev);
1353284267Skadesai		pciDrvInfo->deviceNumber = pci_get_slot(sc->mrsas_dev);
1354284267Skadesai		pciDrvInfo->functionNumber = pci_get_function(sc->mrsas_dev);
1355284267Skadesai		pciDrvInfo->domainID = pci_get_domain(sc->mrsas_dev);
1356284267Skadesai		mrsas_dprint(sc, MRSAS_INFO, "pci bus no: %d,"
1357284267Skadesai		    "pci device no: %d, pci function no: %d,"
1358284267Skadesai		    "pci domain ID: %d\n",
1359284267Skadesai		    pciDrvInfo->busNumber, pciDrvInfo->deviceNumber,
1360284267Skadesai		    pciDrvInfo->functionNumber, pciDrvInfo->domainID);
1361284267Skadesai		ret = 0;
1362284267Skadesai		break;
1363284267Skadesai
1364275976Ssmh	default:
1365275976Ssmh		mrsas_dprint(sc, MRSAS_TRACE, "IOCTL command 0x%lx is not handled\n", cmd);
1366275976Ssmh		ret = ENOENT;
1367275976Ssmh	}
1368275976Ssmh
1369275976Ssmh	return (ret);
1370265555Sambrisko}
1371265555Sambrisko
1372275976Ssmh/*
1373275976Ssmh * mrsas_poll:	poll entry point for mrsas driver fd
1374275976Ssmh *
1375275976Ssmh * This function is the entry point for poll from the OS.  It waits for some AEN
1376275976Ssmh * events to be triggered from the controller and notifies back.
1377275976Ssmh */
1378275976Ssmhstatic int
1379275976Ssmhmrsas_poll(struct cdev *dev, int poll_events, struct thread *td)
1380275976Ssmh{
1381275976Ssmh	struct mrsas_softc *sc;
1382275976Ssmh	int revents = 0;
1383275976Ssmh
1384275976Ssmh	sc = dev->si_drv1;
1385275976Ssmh
1386275976Ssmh	if (poll_events & (POLLIN | POLLRDNORM)) {
1387275976Ssmh		if (sc->mrsas_aen_triggered) {
1388275976Ssmh			revents |= poll_events & (POLLIN | POLLRDNORM);
1389275976Ssmh		}
1390275976Ssmh	}
1391275976Ssmh	if (revents == 0) {
1392275976Ssmh		if (poll_events & (POLLIN | POLLRDNORM)) {
1393284267Skadesai			mtx_lock(&sc->aen_lock);
1394275976Ssmh			sc->mrsas_poll_waiting = 1;
1395275976Ssmh			selrecord(td, &sc->mrsas_select);
1396284267Skadesai			mtx_unlock(&sc->aen_lock);
1397275976Ssmh		}
1398275976Ssmh	}
1399275976Ssmh	return revents;
1400275976Ssmh}
1401275976Ssmh
1402275976Ssmh/*
1403275976Ssmh * mrsas_setup_irq:	Set up interrupt
1404275976Ssmh * input:			Adapter instance soft state
1405275976Ssmh *
1406265555Sambrisko * This function sets up interrupts as a bus resource, with flags indicating
1407275976Ssmh * resource permitting contemporaneous sharing and for resource to activate
1408265555Sambrisko * atomically.
1409265555Sambrisko */
1410275976Ssmhstatic int
1411275976Ssmhmrsas_setup_irq(struct mrsas_softc *sc)
1412265555Sambrisko{
1413275976Ssmh	if (sc->msix_enable && (mrsas_setup_msix(sc) == SUCCESS))
1414275976Ssmh		device_printf(sc->mrsas_dev, "MSI-x interrupts setup success\n");
1415265555Sambrisko
1416275976Ssmh	else {
1417275976Ssmh		device_printf(sc->mrsas_dev, "Fall back to legacy interrupt\n");
1418275976Ssmh		sc->irq_context[0].sc = sc;
1419275976Ssmh		sc->irq_context[0].MSIxIndex = 0;
1420275976Ssmh		sc->irq_id[0] = 0;
1421275976Ssmh		sc->mrsas_irq[0] = bus_alloc_resource_any(sc->mrsas_dev,
1422275976Ssmh		    SYS_RES_IRQ, &sc->irq_id[0], RF_SHAREABLE | RF_ACTIVE);
1423275976Ssmh		if (sc->mrsas_irq[0] == NULL) {
1424275976Ssmh			device_printf(sc->mrsas_dev, "Cannot allocate legcay"
1425275976Ssmh			    "interrupt\n");
1426275976Ssmh			return (FAIL);
1427275976Ssmh		}
1428275976Ssmh		if (bus_setup_intr(sc->mrsas_dev, sc->mrsas_irq[0],
1429275976Ssmh		    INTR_MPSAFE | INTR_TYPE_CAM, NULL, mrsas_isr,
1430275976Ssmh		    &sc->irq_context[0], &sc->intr_handle[0])) {
1431275976Ssmh			device_printf(sc->mrsas_dev, "Cannot set up legacy"
1432275976Ssmh			    "interrupt\n");
1433275976Ssmh			return (FAIL);
1434275976Ssmh		}
1435275976Ssmh	}
1436275976Ssmh	return (0);
1437265555Sambrisko}
1438265555Sambrisko
1439265555Sambrisko/*
1440275976Ssmh * mrsas_isr:	ISR entry point
1441275976Ssmh * input:		argument pointer
1442265555Sambrisko *
1443275976Ssmh * This function is the interrupt service routine entry point.  There are two
1444275976Ssmh * types of interrupts, state change interrupt and response interrupt.  If an
1445275976Ssmh * interrupt is not ours, we just return.
1446265555Sambrisko */
1447275976Ssmhvoid
1448275976Ssmhmrsas_isr(void *arg)
1449265555Sambrisko{
1450275976Ssmh	struct mrsas_irq_context *irq_context = (struct mrsas_irq_context *)arg;
1451275976Ssmh	struct mrsas_softc *sc = irq_context->sc;
1452275976Ssmh	int status = 0;
1453265555Sambrisko
1454284267Skadesai	if (sc->mask_interrupts)
1455284267Skadesai		return;
1456284267Skadesai
1457275976Ssmh	if (!sc->msix_vectors) {
1458275976Ssmh		status = mrsas_clear_intr(sc);
1459275976Ssmh		if (!status)
1460275976Ssmh			return;
1461275976Ssmh	}
1462275976Ssmh	/* If we are resetting, bail */
1463275976Ssmh	if (mrsas_test_bit(MRSAS_FUSION_IN_RESET, &sc->reset_flags)) {
1464275976Ssmh		printf(" Entered into ISR when OCR is going active. \n");
1465275976Ssmh		mrsas_clear_intr(sc);
1466275976Ssmh		return;
1467275976Ssmh	}
1468275976Ssmh	/* Process for reply request and clear response interrupt */
1469275976Ssmh	if (mrsas_complete_cmd(sc, irq_context->MSIxIndex) != SUCCESS)
1470275976Ssmh		mrsas_clear_intr(sc);
1471265555Sambrisko
1472275976Ssmh	return;
1473265555Sambrisko}
1474265555Sambrisko
1475265555Sambrisko/*
1476275976Ssmh * mrsas_complete_cmd:	Process reply request
1477275976Ssmh * input:				Adapter instance soft state
1478265555Sambrisko *
1479275976Ssmh * This function is called from mrsas_isr() to process reply request and clear
1480275976Ssmh * response interrupt. Processing of the reply request entails walking
1481275976Ssmh * through the reply descriptor array for the command request  pended from
1482275976Ssmh * Firmware.  We look at the Function field to determine the command type and
1483275976Ssmh * perform the appropriate action.  Before we return, we clear the response
1484275976Ssmh * interrupt.
1485265555Sambrisko */
1486275976Ssmhstatic int
1487275976Ssmhmrsas_complete_cmd(struct mrsas_softc *sc, u_int32_t MSIxIndex)
1488265555Sambrisko{
1489275976Ssmh	Mpi2ReplyDescriptorsUnion_t *desc;
1490275976Ssmh	MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR *reply_desc;
1491275976Ssmh	MRSAS_RAID_SCSI_IO_REQUEST *scsi_io_req;
1492275976Ssmh	struct mrsas_mpt_cmd *cmd_mpt;
1493275976Ssmh	struct mrsas_mfi_cmd *cmd_mfi;
1494284267Skadesai	u_int8_t reply_descript_type;
1495275976Ssmh	u_int16_t smid, num_completed;
1496275976Ssmh	u_int8_t status, extStatus;
1497275976Ssmh	union desc_value desc_val;
1498275976Ssmh	PLD_LOAD_BALANCE_INFO lbinfo;
1499275976Ssmh	u_int32_t device_id;
1500275976Ssmh	int threshold_reply_count = 0;
1501265555Sambrisko
1502265555Sambrisko
1503275976Ssmh	/* If we have a hardware error, not need to continue */
1504275976Ssmh	if (sc->adprecovery == MRSAS_HW_CRITICAL_ERROR)
1505275976Ssmh		return (DONE);
1506265555Sambrisko
1507275976Ssmh	desc = sc->reply_desc_mem;
1508275976Ssmh	desc += ((MSIxIndex * sc->reply_alloc_sz) / sizeof(MPI2_REPLY_DESCRIPTORS_UNION))
1509275976Ssmh	    + sc->last_reply_idx[MSIxIndex];
1510265555Sambrisko
1511275976Ssmh	reply_desc = (MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR *) desc;
1512265555Sambrisko
1513275976Ssmh	desc_val.word = desc->Words;
1514275976Ssmh	num_completed = 0;
1515265555Sambrisko
1516275976Ssmh	reply_descript_type = reply_desc->ReplyFlags & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK;
1517265555Sambrisko
1518275976Ssmh	/* Find our reply descriptor for the command and process */
1519275976Ssmh	while ((desc_val.u.low != 0xFFFFFFFF) && (desc_val.u.high != 0xFFFFFFFF)) {
1520275976Ssmh		smid = reply_desc->SMID;
1521275976Ssmh		cmd_mpt = sc->mpt_cmd_list[smid - 1];
1522275976Ssmh		scsi_io_req = (MRSAS_RAID_SCSI_IO_REQUEST *) cmd_mpt->io_request;
1523265555Sambrisko
1524275976Ssmh		status = scsi_io_req->RaidContext.status;
1525275976Ssmh		extStatus = scsi_io_req->RaidContext.exStatus;
1526265555Sambrisko
1527275976Ssmh		switch (scsi_io_req->Function) {
1528275976Ssmh		case MPI2_FUNCTION_SCSI_IO_REQUEST:	/* Fast Path IO. */
1529275976Ssmh			device_id = cmd_mpt->ccb_ptr->ccb_h.target_id;
1530275976Ssmh			lbinfo = &sc->load_balance_info[device_id];
1531275976Ssmh			if (cmd_mpt->load_balance == MRSAS_LOAD_BALANCE_FLAG) {
1532284267Skadesai				mrsas_atomic_dec(&lbinfo->scsi_pending_cmds[cmd_mpt->pd_r1_lb]);
1533275976Ssmh				cmd_mpt->load_balance &= ~MRSAS_LOAD_BALANCE_FLAG;
1534275976Ssmh			}
1535275976Ssmh			/* Fall thru and complete IO */
1536275976Ssmh		case MRSAS_MPI2_FUNCTION_LD_IO_REQUEST:
1537275976Ssmh			mrsas_map_mpt_cmd_status(cmd_mpt, status, extStatus);
1538275976Ssmh			mrsas_cmd_done(sc, cmd_mpt);
1539275976Ssmh			scsi_io_req->RaidContext.status = 0;
1540275976Ssmh			scsi_io_req->RaidContext.exStatus = 0;
1541275976Ssmh			mrsas_atomic_dec(&sc->fw_outstanding);
1542275976Ssmh			break;
1543275976Ssmh		case MRSAS_MPI2_FUNCTION_PASSTHRU_IO_REQUEST:	/* MFI command */
1544275976Ssmh			cmd_mfi = sc->mfi_cmd_list[cmd_mpt->sync_cmd_idx];
1545275976Ssmh			mrsas_complete_mptmfi_passthru(sc, cmd_mfi, status);
1546275976Ssmh			cmd_mpt->flags = 0;
1547275976Ssmh			mrsas_release_mpt_cmd(cmd_mpt);
1548275976Ssmh			break;
1549275976Ssmh		}
1550265555Sambrisko
1551275976Ssmh		sc->last_reply_idx[MSIxIndex]++;
1552275976Ssmh		if (sc->last_reply_idx[MSIxIndex] >= sc->reply_q_depth)
1553275976Ssmh			sc->last_reply_idx[MSIxIndex] = 0;
1554265555Sambrisko
1555275976Ssmh		desc->Words = ~((uint64_t)0x00);	/* set it back to all
1556275976Ssmh							 * 0xFFFFFFFFs */
1557275976Ssmh		num_completed++;
1558275976Ssmh		threshold_reply_count++;
1559265555Sambrisko
1560275976Ssmh		/* Get the next reply descriptor */
1561275976Ssmh		if (!sc->last_reply_idx[MSIxIndex]) {
1562275976Ssmh			desc = sc->reply_desc_mem;
1563275976Ssmh			desc += ((MSIxIndex * sc->reply_alloc_sz) / sizeof(MPI2_REPLY_DESCRIPTORS_UNION));
1564275976Ssmh		} else
1565275976Ssmh			desc++;
1566265555Sambrisko
1567275976Ssmh		reply_desc = (MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR *) desc;
1568275976Ssmh		desc_val.word = desc->Words;
1569265555Sambrisko
1570275976Ssmh		reply_descript_type = reply_desc->ReplyFlags & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK;
1571265555Sambrisko
1572275976Ssmh		if (reply_descript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED)
1573275976Ssmh			break;
1574265555Sambrisko
1575275976Ssmh		/*
1576275976Ssmh		 * Write to reply post index after completing threshold reply
1577275976Ssmh		 * count and still there are more replies in reply queue
1578275976Ssmh		 * pending to be completed.
1579275976Ssmh		 */
1580275976Ssmh		if (threshold_reply_count >= THRESHOLD_REPLY_COUNT) {
1581275976Ssmh			if (sc->msix_enable) {
1582275976Ssmh				if ((sc->device_id == MRSAS_INVADER) ||
1583275976Ssmh				    (sc->device_id == MRSAS_FURY))
1584275976Ssmh					mrsas_write_reg(sc, sc->msix_reg_offset[MSIxIndex / 8],
1585275976Ssmh					    ((MSIxIndex & 0x7) << 24) |
1586275976Ssmh					    sc->last_reply_idx[MSIxIndex]);
1587275976Ssmh				else
1588275976Ssmh					mrsas_write_reg(sc, sc->msix_reg_offset[0], (MSIxIndex << 24) |
1589275976Ssmh					    sc->last_reply_idx[MSIxIndex]);
1590275976Ssmh			} else
1591275976Ssmh				mrsas_write_reg(sc, offsetof(mrsas_reg_set,
1592275976Ssmh				    reply_post_host_index), sc->last_reply_idx[0]);
1593265555Sambrisko
1594275976Ssmh			threshold_reply_count = 0;
1595275976Ssmh		}
1596275976Ssmh	}
1597265555Sambrisko
1598275976Ssmh	/* No match, just return */
1599275976Ssmh	if (num_completed == 0)
1600275976Ssmh		return (DONE);
1601275976Ssmh
1602275976Ssmh	/* Clear response interrupt */
1603275976Ssmh	if (sc->msix_enable) {
1604275976Ssmh		if ((sc->device_id == MRSAS_INVADER) ||
1605275976Ssmh		    (sc->device_id == MRSAS_FURY)) {
1606275976Ssmh			mrsas_write_reg(sc, sc->msix_reg_offset[MSIxIndex / 8],
1607275976Ssmh			    ((MSIxIndex & 0x7) << 24) |
1608275976Ssmh			    sc->last_reply_idx[MSIxIndex]);
1609275976Ssmh		} else
1610275976Ssmh			mrsas_write_reg(sc, sc->msix_reg_offset[0], (MSIxIndex << 24) |
1611275976Ssmh			    sc->last_reply_idx[MSIxIndex]);
1612275976Ssmh	} else
1613275976Ssmh		mrsas_write_reg(sc, offsetof(mrsas_reg_set,
1614275976Ssmh		    reply_post_host_index), sc->last_reply_idx[0]);
1615275976Ssmh
1616275976Ssmh	return (0);
1617265555Sambrisko}
1618265555Sambrisko
1619265555Sambrisko/*
1620275976Ssmh * mrsas_map_mpt_cmd_status:	Allocate DMAable memory.
1621275976Ssmh * input:						Adapter instance soft state
1622265555Sambrisko *
1623265555Sambrisko * This function is called from mrsas_complete_cmd(), for LD IO and FastPath IO.
1624275976Ssmh * It checks the command status and maps the appropriate CAM status for the
1625275976Ssmh * CCB.
1626265555Sambrisko */
1627275976Ssmhvoid
1628275976Ssmhmrsas_map_mpt_cmd_status(struct mrsas_mpt_cmd *cmd, u_int8_t status, u_int8_t extStatus)
1629265555Sambrisko{
1630275976Ssmh	struct mrsas_softc *sc = cmd->sc;
1631275976Ssmh	u_int8_t *sense_data;
1632265555Sambrisko
1633275976Ssmh	switch (status) {
1634275976Ssmh	case MFI_STAT_OK:
1635275976Ssmh		cmd->ccb_ptr->ccb_h.status = CAM_REQ_CMP;
1636275976Ssmh		break;
1637275976Ssmh	case MFI_STAT_SCSI_IO_FAILED:
1638275976Ssmh	case MFI_STAT_SCSI_DONE_WITH_ERROR:
1639275976Ssmh		cmd->ccb_ptr->ccb_h.status = CAM_SCSI_STATUS_ERROR;
1640275976Ssmh		sense_data = (u_int8_t *)&cmd->ccb_ptr->csio.sense_data;
1641275976Ssmh		if (sense_data) {
1642275976Ssmh			/* For now just copy 18 bytes back */
1643275976Ssmh			memcpy(sense_data, cmd->sense, 18);
1644275976Ssmh			cmd->ccb_ptr->csio.sense_len = 18;
1645275976Ssmh			cmd->ccb_ptr->ccb_h.status |= CAM_AUTOSNS_VALID;
1646275976Ssmh		}
1647275976Ssmh		break;
1648275976Ssmh	case MFI_STAT_LD_OFFLINE:
1649275976Ssmh	case MFI_STAT_DEVICE_NOT_FOUND:
1650275976Ssmh		if (cmd->ccb_ptr->ccb_h.target_lun)
1651275976Ssmh			cmd->ccb_ptr->ccb_h.status |= CAM_LUN_INVALID;
1652275976Ssmh		else
1653275976Ssmh			cmd->ccb_ptr->ccb_h.status |= CAM_DEV_NOT_THERE;
1654275976Ssmh		break;
1655275976Ssmh	case MFI_STAT_CONFIG_SEQ_MISMATCH:
1656275976Ssmh		cmd->ccb_ptr->ccb_h.status |= CAM_REQUEUE_REQ;
1657275976Ssmh		break;
1658275976Ssmh	default:
1659275976Ssmh		device_printf(sc->mrsas_dev, "FW cmd complete status %x\n", status);
1660275976Ssmh		cmd->ccb_ptr->ccb_h.status = CAM_REQ_CMP_ERR;
1661275976Ssmh		cmd->ccb_ptr->csio.scsi_status = status;
1662275976Ssmh	}
1663275976Ssmh	return;
1664265555Sambrisko}
1665265555Sambrisko
1666265555Sambrisko/*
1667275976Ssmh * mrsas_alloc_mem:	Allocate DMAable memory
1668275976Ssmh * input:			Adapter instance soft state
1669265555Sambrisko *
1670275976Ssmh * This function creates the parent DMA tag and allocates DMAable memory. DMA
1671275976Ssmh * tag describes constraints of DMA mapping. Memory allocated is mapped into
1672275976Ssmh * Kernel virtual address. Callback argument is physical memory address.
1673265555Sambrisko */
1674275976Ssmhstatic int
1675275976Ssmhmrsas_alloc_mem(struct mrsas_softc *sc)
1676265555Sambrisko{
1677284267Skadesai	u_int32_t verbuf_size, io_req_size, reply_desc_size, sense_size,
1678284267Skadesai	          chain_frame_size, evt_detail_size, count;
1679265555Sambrisko
1680275976Ssmh	/*
1681275976Ssmh	 * Allocate parent DMA tag
1682275976Ssmh	 */
1683275976Ssmh	if (bus_dma_tag_create(NULL,	/* parent */
1684275976Ssmh	    1,				/* alignment */
1685275976Ssmh	    0,				/* boundary */
1686275976Ssmh	    BUS_SPACE_MAXADDR,		/* lowaddr */
1687275976Ssmh	    BUS_SPACE_MAXADDR,		/* highaddr */
1688275976Ssmh	    NULL, NULL,			/* filter, filterarg */
1689275976Ssmh	    MRSAS_MAX_IO_SIZE,		/* maxsize */
1690275976Ssmh	    MRSAS_MAX_SGL,		/* nsegments */
1691275976Ssmh	    MRSAS_MAX_IO_SIZE,		/* maxsegsize */
1692275976Ssmh	    0,				/* flags */
1693275976Ssmh	    NULL, NULL,			/* lockfunc, lockarg */
1694275976Ssmh	    &sc->mrsas_parent_tag	/* tag */
1695275976Ssmh	    )) {
1696275976Ssmh		device_printf(sc->mrsas_dev, "Cannot allocate parent DMA tag\n");
1697275976Ssmh		return (ENOMEM);
1698275976Ssmh	}
1699275976Ssmh	/*
1700275976Ssmh	 * Allocate for version buffer
1701275976Ssmh	 */
1702275976Ssmh	verbuf_size = MRSAS_MAX_NAME_LENGTH * (sizeof(bus_addr_t));
1703275976Ssmh	if (bus_dma_tag_create(sc->mrsas_parent_tag,
1704275976Ssmh	    1, 0,
1705275976Ssmh	    BUS_SPACE_MAXADDR_32BIT,
1706275976Ssmh	    BUS_SPACE_MAXADDR,
1707275976Ssmh	    NULL, NULL,
1708275976Ssmh	    verbuf_size,
1709275976Ssmh	    1,
1710275976Ssmh	    verbuf_size,
1711275976Ssmh	    BUS_DMA_ALLOCNOW,
1712275976Ssmh	    NULL, NULL,
1713275976Ssmh	    &sc->verbuf_tag)) {
1714275976Ssmh		device_printf(sc->mrsas_dev, "Cannot allocate verbuf DMA tag\n");
1715275976Ssmh		return (ENOMEM);
1716275976Ssmh	}
1717275976Ssmh	if (bus_dmamem_alloc(sc->verbuf_tag, (void **)&sc->verbuf_mem,
1718275976Ssmh	    BUS_DMA_NOWAIT, &sc->verbuf_dmamap)) {
1719275976Ssmh		device_printf(sc->mrsas_dev, "Cannot allocate verbuf memory\n");
1720275976Ssmh		return (ENOMEM);
1721275976Ssmh	}
1722275976Ssmh	bzero(sc->verbuf_mem, verbuf_size);
1723275976Ssmh	if (bus_dmamap_load(sc->verbuf_tag, sc->verbuf_dmamap, sc->verbuf_mem,
1724275976Ssmh	    verbuf_size, mrsas_addr_cb, &sc->verbuf_phys_addr,
1725275976Ssmh	    BUS_DMA_NOWAIT)) {
1726275976Ssmh		device_printf(sc->mrsas_dev, "Cannot load verbuf DMA map\n");
1727275976Ssmh		return (ENOMEM);
1728275976Ssmh	}
1729275976Ssmh	/*
1730275976Ssmh	 * Allocate IO Request Frames
1731275976Ssmh	 */
1732275976Ssmh	io_req_size = sc->io_frames_alloc_sz;
1733275976Ssmh	if (bus_dma_tag_create(sc->mrsas_parent_tag,
1734275976Ssmh	    16, 0,
1735275976Ssmh	    BUS_SPACE_MAXADDR_32BIT,
1736275976Ssmh	    BUS_SPACE_MAXADDR,
1737275976Ssmh	    NULL, NULL,
1738275976Ssmh	    io_req_size,
1739275976Ssmh	    1,
1740275976Ssmh	    io_req_size,
1741275976Ssmh	    BUS_DMA_ALLOCNOW,
1742275976Ssmh	    NULL, NULL,
1743275976Ssmh	    &sc->io_request_tag)) {
1744275976Ssmh		device_printf(sc->mrsas_dev, "Cannot create IO request tag\n");
1745275976Ssmh		return (ENOMEM);
1746275976Ssmh	}
1747275976Ssmh	if (bus_dmamem_alloc(sc->io_request_tag, (void **)&sc->io_request_mem,
1748275976Ssmh	    BUS_DMA_NOWAIT, &sc->io_request_dmamap)) {
1749275976Ssmh		device_printf(sc->mrsas_dev, "Cannot alloc IO request memory\n");
1750275976Ssmh		return (ENOMEM);
1751275976Ssmh	}
1752275976Ssmh	bzero(sc->io_request_mem, io_req_size);
1753275976Ssmh	if (bus_dmamap_load(sc->io_request_tag, sc->io_request_dmamap,
1754275976Ssmh	    sc->io_request_mem, io_req_size, mrsas_addr_cb,
1755275976Ssmh	    &sc->io_request_phys_addr, BUS_DMA_NOWAIT)) {
1756275976Ssmh		device_printf(sc->mrsas_dev, "Cannot load IO request memory\n");
1757275976Ssmh		return (ENOMEM);
1758275976Ssmh	}
1759275976Ssmh	/*
1760275976Ssmh	 * Allocate Chain Frames
1761275976Ssmh	 */
1762275976Ssmh	chain_frame_size = sc->chain_frames_alloc_sz;
1763275976Ssmh	if (bus_dma_tag_create(sc->mrsas_parent_tag,
1764275976Ssmh	    4, 0,
1765275976Ssmh	    BUS_SPACE_MAXADDR_32BIT,
1766275976Ssmh	    BUS_SPACE_MAXADDR,
1767275976Ssmh	    NULL, NULL,
1768275976Ssmh	    chain_frame_size,
1769275976Ssmh	    1,
1770275976Ssmh	    chain_frame_size,
1771275976Ssmh	    BUS_DMA_ALLOCNOW,
1772275976Ssmh	    NULL, NULL,
1773275976Ssmh	    &sc->chain_frame_tag)) {
1774275976Ssmh		device_printf(sc->mrsas_dev, "Cannot create chain frame tag\n");
1775275976Ssmh		return (ENOMEM);
1776275976Ssmh	}
1777275976Ssmh	if (bus_dmamem_alloc(sc->chain_frame_tag, (void **)&sc->chain_frame_mem,
1778275976Ssmh	    BUS_DMA_NOWAIT, &sc->chain_frame_dmamap)) {
1779275976Ssmh		device_printf(sc->mrsas_dev, "Cannot alloc chain frame memory\n");
1780275976Ssmh		return (ENOMEM);
1781275976Ssmh	}
1782275976Ssmh	bzero(sc->chain_frame_mem, chain_frame_size);
1783275976Ssmh	if (bus_dmamap_load(sc->chain_frame_tag, sc->chain_frame_dmamap,
1784275976Ssmh	    sc->chain_frame_mem, chain_frame_size, mrsas_addr_cb,
1785275976Ssmh	    &sc->chain_frame_phys_addr, BUS_DMA_NOWAIT)) {
1786275976Ssmh		device_printf(sc->mrsas_dev, "Cannot load chain frame memory\n");
1787275976Ssmh		return (ENOMEM);
1788275976Ssmh	}
1789275976Ssmh	count = sc->msix_vectors > 0 ? sc->msix_vectors : 1;
1790275976Ssmh	/*
1791275976Ssmh	 * Allocate Reply Descriptor Array
1792275976Ssmh	 */
1793275976Ssmh	reply_desc_size = sc->reply_alloc_sz * count;
1794275976Ssmh	if (bus_dma_tag_create(sc->mrsas_parent_tag,
1795275976Ssmh	    16, 0,
1796275976Ssmh	    BUS_SPACE_MAXADDR_32BIT,
1797275976Ssmh	    BUS_SPACE_MAXADDR,
1798275976Ssmh	    NULL, NULL,
1799275976Ssmh	    reply_desc_size,
1800275976Ssmh	    1,
1801275976Ssmh	    reply_desc_size,
1802275976Ssmh	    BUS_DMA_ALLOCNOW,
1803275976Ssmh	    NULL, NULL,
1804275976Ssmh	    &sc->reply_desc_tag)) {
1805275976Ssmh		device_printf(sc->mrsas_dev, "Cannot create reply descriptor tag\n");
1806275976Ssmh		return (ENOMEM);
1807275976Ssmh	}
1808275976Ssmh	if (bus_dmamem_alloc(sc->reply_desc_tag, (void **)&sc->reply_desc_mem,
1809275976Ssmh	    BUS_DMA_NOWAIT, &sc->reply_desc_dmamap)) {
1810275976Ssmh		device_printf(sc->mrsas_dev, "Cannot alloc reply descriptor memory\n");
1811275976Ssmh		return (ENOMEM);
1812275976Ssmh	}
1813275976Ssmh	if (bus_dmamap_load(sc->reply_desc_tag, sc->reply_desc_dmamap,
1814275976Ssmh	    sc->reply_desc_mem, reply_desc_size, mrsas_addr_cb,
1815275976Ssmh	    &sc->reply_desc_phys_addr, BUS_DMA_NOWAIT)) {
1816275976Ssmh		device_printf(sc->mrsas_dev, "Cannot load reply descriptor memory\n");
1817275976Ssmh		return (ENOMEM);
1818275976Ssmh	}
1819275976Ssmh	/*
1820275976Ssmh	 * Allocate Sense Buffer Array.  Keep in lower 4GB
1821275976Ssmh	 */
1822275976Ssmh	sense_size = sc->max_fw_cmds * MRSAS_SENSE_LEN;
1823275976Ssmh	if (bus_dma_tag_create(sc->mrsas_parent_tag,
1824275976Ssmh	    64, 0,
1825275976Ssmh	    BUS_SPACE_MAXADDR_32BIT,
1826275976Ssmh	    BUS_SPACE_MAXADDR,
1827275976Ssmh	    NULL, NULL,
1828275976Ssmh	    sense_size,
1829275976Ssmh	    1,
1830275976Ssmh	    sense_size,
1831275976Ssmh	    BUS_DMA_ALLOCNOW,
1832275976Ssmh	    NULL, NULL,
1833275976Ssmh	    &sc->sense_tag)) {
1834275976Ssmh		device_printf(sc->mrsas_dev, "Cannot allocate sense buf tag\n");
1835275976Ssmh		return (ENOMEM);
1836275976Ssmh	}
1837275976Ssmh	if (bus_dmamem_alloc(sc->sense_tag, (void **)&sc->sense_mem,
1838275976Ssmh	    BUS_DMA_NOWAIT, &sc->sense_dmamap)) {
1839275976Ssmh		device_printf(sc->mrsas_dev, "Cannot allocate sense buf memory\n");
1840275976Ssmh		return (ENOMEM);
1841275976Ssmh	}
1842275976Ssmh	if (bus_dmamap_load(sc->sense_tag, sc->sense_dmamap,
1843275976Ssmh	    sc->sense_mem, sense_size, mrsas_addr_cb, &sc->sense_phys_addr,
1844275976Ssmh	    BUS_DMA_NOWAIT)) {
1845275976Ssmh		device_printf(sc->mrsas_dev, "Cannot load sense buf memory\n");
1846275976Ssmh		return (ENOMEM);
1847275976Ssmh	}
1848275976Ssmh	/*
1849275976Ssmh	 * Allocate for Event detail structure
1850275976Ssmh	 */
1851275976Ssmh	evt_detail_size = sizeof(struct mrsas_evt_detail);
1852275976Ssmh	if (bus_dma_tag_create(sc->mrsas_parent_tag,
1853275976Ssmh	    1, 0,
1854275976Ssmh	    BUS_SPACE_MAXADDR_32BIT,
1855275976Ssmh	    BUS_SPACE_MAXADDR,
1856275976Ssmh	    NULL, NULL,
1857275976Ssmh	    evt_detail_size,
1858275976Ssmh	    1,
1859275976Ssmh	    evt_detail_size,
1860275976Ssmh	    BUS_DMA_ALLOCNOW,
1861275976Ssmh	    NULL, NULL,
1862275976Ssmh	    &sc->evt_detail_tag)) {
1863275976Ssmh		device_printf(sc->mrsas_dev, "Cannot create Event detail tag\n");
1864275976Ssmh		return (ENOMEM);
1865275976Ssmh	}
1866275976Ssmh	if (bus_dmamem_alloc(sc->evt_detail_tag, (void **)&sc->evt_detail_mem,
1867275976Ssmh	    BUS_DMA_NOWAIT, &sc->evt_detail_dmamap)) {
1868275976Ssmh		device_printf(sc->mrsas_dev, "Cannot alloc Event detail buffer memory\n");
1869275976Ssmh		return (ENOMEM);
1870275976Ssmh	}
1871275976Ssmh	bzero(sc->evt_detail_mem, evt_detail_size);
1872275976Ssmh	if (bus_dmamap_load(sc->evt_detail_tag, sc->evt_detail_dmamap,
1873275976Ssmh	    sc->evt_detail_mem, evt_detail_size, mrsas_addr_cb,
1874275976Ssmh	    &sc->evt_detail_phys_addr, BUS_DMA_NOWAIT)) {
1875275976Ssmh		device_printf(sc->mrsas_dev, "Cannot load Event detail buffer memory\n");
1876275976Ssmh		return (ENOMEM);
1877275976Ssmh	}
1878275976Ssmh	/*
1879275976Ssmh	 * Create a dma tag for data buffers; size will be the maximum
1880275976Ssmh	 * possible I/O size (280kB).
1881275976Ssmh	 */
1882275976Ssmh	if (bus_dma_tag_create(sc->mrsas_parent_tag,
1883275976Ssmh	    1,
1884275976Ssmh	    0,
1885275976Ssmh	    BUS_SPACE_MAXADDR,
1886275976Ssmh	    BUS_SPACE_MAXADDR,
1887275976Ssmh	    NULL, NULL,
1888275976Ssmh	    MRSAS_MAX_IO_SIZE,
1889275976Ssmh	    MRSAS_MAX_SGL,
1890275976Ssmh	    MRSAS_MAX_IO_SIZE,
1891275976Ssmh	    BUS_DMA_ALLOCNOW,
1892275976Ssmh	    busdma_lock_mutex,
1893275976Ssmh	    &sc->io_lock,
1894275976Ssmh	    &sc->data_tag)) {
1895275976Ssmh		device_printf(sc->mrsas_dev, "Cannot create data dma tag\n");
1896275976Ssmh		return (ENOMEM);
1897275976Ssmh	}
1898275976Ssmh	return (0);
1899265555Sambrisko}
1900265555Sambrisko
1901265555Sambrisko/*
1902275976Ssmh * mrsas_addr_cb:	Callback function of bus_dmamap_load()
1903275976Ssmh * input:			callback argument, machine dependent type
1904275976Ssmh * 					that describes DMA segments, number of segments, error code
1905265555Sambrisko *
1906275976Ssmh * This function is for the driver to receive mapping information resultant of
1907275976Ssmh * the bus_dmamap_load(). The information is actually not being used, but the
1908275976Ssmh * address is saved anyway.
1909265555Sambrisko */
1910265555Sambriskovoid
1911265555Sambriskomrsas_addr_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
1912265555Sambrisko{
1913275976Ssmh	bus_addr_t *addr;
1914275976Ssmh
1915275976Ssmh	addr = arg;
1916275976Ssmh	*addr = segs[0].ds_addr;
1917265555Sambrisko}
1918265555Sambrisko
1919265555Sambrisko/*
1920275976Ssmh * mrsas_setup_raidmap:	Set up RAID map.
1921275976Ssmh * input:				Adapter instance soft state
1922265555Sambrisko *
1923265555Sambrisko * Allocate DMA memory for the RAID maps and perform setup.
1924265555Sambrisko */
1925275976Ssmhstatic int
1926275976Ssmhmrsas_setup_raidmap(struct mrsas_softc *sc)
1927275976Ssmh{
1928275976Ssmh	int i;
1929265555Sambrisko
1930275976Ssmh	for (i = 0; i < 2; i++) {
1931275976Ssmh		sc->ld_drv_map[i] =
1932275976Ssmh		    (void *)malloc(sc->drv_map_sz, M_MRSAS, M_NOWAIT);
1933275976Ssmh		/* Do Error handling */
1934275976Ssmh		if (!sc->ld_drv_map[i]) {
1935275976Ssmh			device_printf(sc->mrsas_dev, "Could not allocate memory for local map");
1936275976Ssmh
1937275976Ssmh			if (i == 1)
1938275976Ssmh				free(sc->ld_drv_map[0], M_MRSAS);
1939275976Ssmh			/* ABORT driver initialization */
1940275976Ssmh			goto ABORT;
1941275976Ssmh		}
1942275976Ssmh	}
1943275976Ssmh
1944275976Ssmh	for (int i = 0; i < 2; i++) {
1945275976Ssmh		if (bus_dma_tag_create(sc->mrsas_parent_tag,
1946275976Ssmh		    4, 0,
1947275976Ssmh		    BUS_SPACE_MAXADDR_32BIT,
1948275976Ssmh		    BUS_SPACE_MAXADDR,
1949275976Ssmh		    NULL, NULL,
1950275976Ssmh		    sc->max_map_sz,
1951275976Ssmh		    1,
1952275976Ssmh		    sc->max_map_sz,
1953275976Ssmh		    BUS_DMA_ALLOCNOW,
1954275976Ssmh		    NULL, NULL,
1955275976Ssmh		    &sc->raidmap_tag[i])) {
1956275976Ssmh			device_printf(sc->mrsas_dev,
1957275976Ssmh			    "Cannot allocate raid map tag.\n");
1958275976Ssmh			return (ENOMEM);
1959275976Ssmh		}
1960275976Ssmh		if (bus_dmamem_alloc(sc->raidmap_tag[i],
1961275976Ssmh		    (void **)&sc->raidmap_mem[i],
1962275976Ssmh		    BUS_DMA_NOWAIT, &sc->raidmap_dmamap[i])) {
1963275976Ssmh			device_printf(sc->mrsas_dev,
1964275976Ssmh			    "Cannot allocate raidmap memory.\n");
1965275976Ssmh			return (ENOMEM);
1966275976Ssmh		}
1967275976Ssmh		bzero(sc->raidmap_mem[i], sc->max_map_sz);
1968275976Ssmh
1969275976Ssmh		if (bus_dmamap_load(sc->raidmap_tag[i], sc->raidmap_dmamap[i],
1970275976Ssmh		    sc->raidmap_mem[i], sc->max_map_sz,
1971275976Ssmh		    mrsas_addr_cb, &sc->raidmap_phys_addr[i],
1972275976Ssmh		    BUS_DMA_NOWAIT)) {
1973275976Ssmh			device_printf(sc->mrsas_dev, "Cannot load raidmap memory.\n");
1974275976Ssmh			return (ENOMEM);
1975275976Ssmh		}
1976275976Ssmh		if (!sc->raidmap_mem[i]) {
1977275976Ssmh			device_printf(sc->mrsas_dev,
1978275976Ssmh			    "Cannot allocate memory for raid map.\n");
1979275976Ssmh			return (ENOMEM);
1980275976Ssmh		}
1981275976Ssmh	}
1982275976Ssmh
1983275976Ssmh	if (!mrsas_get_map_info(sc))
1984275976Ssmh		mrsas_sync_map_info(sc);
1985275976Ssmh
1986275976Ssmh	return (0);
1987275976Ssmh
1988275976SsmhABORT:
1989275976Ssmh	return (1);
1990265555Sambrisko}
1991265555Sambrisko
1992275976Ssmh/*
1993275976Ssmh * mrsas_init_fw:	Initialize Firmware
1994275976Ssmh * input:			Adapter soft state
1995265555Sambrisko *
1996275976Ssmh * Calls transition_to_ready() to make sure Firmware is in operational state and
1997275976Ssmh * calls mrsas_init_adapter() to send IOC_INIT command to Firmware.  It
1998275976Ssmh * issues internal commands to get the controller info after the IOC_INIT
1999275976Ssmh * command response is received by Firmware.  Note:  code relating to
2000275976Ssmh * get_pdlist, get_ld_list and max_sectors are currently not being used, it
2001275976Ssmh * is left here as placeholder.
2002265555Sambrisko */
2003284267Skadesaistatic int
2004275976Ssmhmrsas_init_fw(struct mrsas_softc *sc)
2005265555Sambrisko{
2006265555Sambrisko
2007275976Ssmh	int ret, loop, ocr = 0;
2008275976Ssmh	u_int32_t max_sectors_1;
2009275976Ssmh	u_int32_t max_sectors_2;
2010275976Ssmh	u_int32_t tmp_sectors;
2011275976Ssmh	u_int32_t scratch_pad_2;
2012275976Ssmh	int msix_enable = 0;
2013275976Ssmh	int fw_msix_count = 0;
2014265555Sambrisko
2015275976Ssmh	/* Make sure Firmware is ready */
2016275976Ssmh	ret = mrsas_transition_to_ready(sc, ocr);
2017275976Ssmh	if (ret != SUCCESS) {
2018275976Ssmh		return (ret);
2019265555Sambrisko	}
2020275976Ssmh	/* MSI-x index 0- reply post host index register */
2021275976Ssmh	sc->msix_reg_offset[0] = MPI2_REPLY_POST_HOST_INDEX_OFFSET;
2022275976Ssmh	/* Check if MSI-X is supported while in ready state */
2023275976Ssmh	msix_enable = (mrsas_read_reg(sc, offsetof(mrsas_reg_set, outbound_scratch_pad)) & 0x4000000) >> 0x1a;
2024265555Sambrisko
2025275976Ssmh	if (msix_enable) {
2026275976Ssmh		scratch_pad_2 = mrsas_read_reg(sc, offsetof(mrsas_reg_set,
2027275976Ssmh		    outbound_scratch_pad_2));
2028265555Sambrisko
2029275976Ssmh		/* Check max MSI-X vectors */
2030275976Ssmh		if (sc->device_id == MRSAS_TBOLT) {
2031275976Ssmh			sc->msix_vectors = (scratch_pad_2
2032275976Ssmh			    & MR_MAX_REPLY_QUEUES_OFFSET) + 1;
2033275976Ssmh			fw_msix_count = sc->msix_vectors;
2034275976Ssmh		} else {
2035275976Ssmh			/* Invader/Fury supports 96 MSI-X vectors */
2036275976Ssmh			sc->msix_vectors = ((scratch_pad_2
2037275976Ssmh			    & MR_MAX_REPLY_QUEUES_EXT_OFFSET)
2038275976Ssmh			    >> MR_MAX_REPLY_QUEUES_EXT_OFFSET_SHIFT) + 1;
2039275976Ssmh			fw_msix_count = sc->msix_vectors;
2040275976Ssmh
2041275976Ssmh			for (loop = 1; loop < MR_MAX_MSIX_REG_ARRAY;
2042275976Ssmh			    loop++) {
2043275976Ssmh				sc->msix_reg_offset[loop] =
2044275976Ssmh				    MPI2_SUP_REPLY_POST_HOST_INDEX_OFFSET +
2045275976Ssmh				    (loop * 0x10);
2046275976Ssmh			}
2047275976Ssmh		}
2048275976Ssmh
2049275976Ssmh		/* Don't bother allocating more MSI-X vectors than cpus */
2050275976Ssmh		sc->msix_vectors = min(sc->msix_vectors,
2051275976Ssmh		    mp_ncpus);
2052275976Ssmh
2053275976Ssmh		/* Allocate MSI-x vectors */
2054275976Ssmh		if (mrsas_allocate_msix(sc) == SUCCESS)
2055275976Ssmh			sc->msix_enable = 1;
2056275976Ssmh		else
2057275976Ssmh			sc->msix_enable = 0;
2058275976Ssmh
2059275976Ssmh		device_printf(sc->mrsas_dev, "FW supports <%d> MSIX vector,"
2060275976Ssmh		    "Online CPU %d Current MSIX <%d>\n",
2061275976Ssmh		    fw_msix_count, mp_ncpus, sc->msix_vectors);
2062265555Sambrisko	}
2063275976Ssmh	if (mrsas_init_adapter(sc) != SUCCESS) {
2064275976Ssmh		device_printf(sc->mrsas_dev, "Adapter initialize Fail.\n");
2065275976Ssmh		return (1);
2066275976Ssmh	}
2067275976Ssmh	/* Allocate internal commands for pass-thru */
2068275976Ssmh	if (mrsas_alloc_mfi_cmds(sc) != SUCCESS) {
2069275976Ssmh		device_printf(sc->mrsas_dev, "Allocate MFI cmd failed.\n");
2070275976Ssmh		return (1);
2071275976Ssmh	}
2072284267Skadesai	sc->ctrl_info = malloc(sizeof(struct mrsas_ctrl_info), M_MRSAS, M_NOWAIT);
2073284267Skadesai	if (!sc->ctrl_info) {
2074284267Skadesai		device_printf(sc->mrsas_dev, "Malloc for ctrl_info failed.\n");
2075284267Skadesai		return (1);
2076284267Skadesai	}
2077275976Ssmh	/*
2078275976Ssmh	 * Get the controller info from FW, so that the MAX VD support
2079275976Ssmh	 * availability can be decided.
2080275976Ssmh	 */
2081284267Skadesai	if (mrsas_get_ctrl_info(sc)) {
2082275976Ssmh		device_printf(sc->mrsas_dev, "Unable to get FW ctrl_info.\n");
2083284267Skadesai		return (1);
2084275976Ssmh	}
2085284267Skadesai	sc->secure_jbod_support =
2086284267Skadesai	    (u_int8_t)sc->ctrl_info->adapterOperations3.supportSecurityonJBOD;
2087265555Sambrisko
2088284267Skadesai	if (sc->secure_jbod_support)
2089284267Skadesai		device_printf(sc->mrsas_dev, "FW supports SED \n");
2090284267Skadesai
2091275976Ssmh	if (mrsas_setup_raidmap(sc) != SUCCESS) {
2092275976Ssmh		device_printf(sc->mrsas_dev, "Set up RAID map failed.\n");
2093275976Ssmh		return (1);
2094275976Ssmh	}
2095275976Ssmh	/* For pass-thru, get PD/LD list and controller info */
2096275976Ssmh	memset(sc->pd_list, 0,
2097275976Ssmh	    MRSAS_MAX_PD * sizeof(struct mrsas_pd_list));
2098275976Ssmh	mrsas_get_pd_list(sc);
2099265555Sambrisko
2100275976Ssmh	memset(sc->ld_ids, 0xff, MRSAS_MAX_LD_IDS);
2101275976Ssmh	mrsas_get_ld_list(sc);
2102265555Sambrisko
2103275976Ssmh	/*
2104275976Ssmh	 * Compute the max allowed sectors per IO: The controller info has
2105275976Ssmh	 * two limits on max sectors. Driver should use the minimum of these
2106275976Ssmh	 * two.
2107275976Ssmh	 *
2108275976Ssmh	 * 1 << stripe_sz_ops.min = max sectors per strip
2109275976Ssmh	 *
2110275976Ssmh	 * Note that older firmwares ( < FW ver 30) didn't report information to
2111275976Ssmh	 * calculate max_sectors_1. So the number ended up as zero always.
2112275976Ssmh	 */
2113275976Ssmh	tmp_sectors = 0;
2114284267Skadesai	max_sectors_1 = (1 << sc->ctrl_info->stripe_sz_ops.min) *
2115284267Skadesai	    sc->ctrl_info->max_strips_per_io;
2116284267Skadesai	max_sectors_2 = sc->ctrl_info->max_request_size;
2117275976Ssmh	tmp_sectors = min(max_sectors_1, max_sectors_2);
2118275976Ssmh	sc->max_sectors_per_req = sc->max_num_sge * MRSAS_PAGE_SIZE / 512;
2119265555Sambrisko
2120275976Ssmh	if (tmp_sectors && (sc->max_sectors_per_req > tmp_sectors))
2121275976Ssmh		sc->max_sectors_per_req = tmp_sectors;
2122265555Sambrisko
2123275976Ssmh	sc->disableOnlineCtrlReset =
2124284267Skadesai	    sc->ctrl_info->properties.OnOffProperties.disableOnlineCtrlReset;
2125275976Ssmh	sc->UnevenSpanSupport =
2126284267Skadesai	    sc->ctrl_info->adapterOperations2.supportUnevenSpans;
2127275976Ssmh	if (sc->UnevenSpanSupport) {
2128275976Ssmh		device_printf(sc->mrsas_dev, "FW supports: UnevenSpanSupport=%x\n\n",
2129275976Ssmh		    sc->UnevenSpanSupport);
2130265555Sambrisko
2131275976Ssmh		if (MR_ValidateMapInfo(sc))
2132275976Ssmh			sc->fast_path_io = 1;
2133275976Ssmh		else
2134275976Ssmh			sc->fast_path_io = 0;
2135275976Ssmh	}
2136275976Ssmh	return (0);
2137265555Sambrisko}
2138265555Sambrisko
2139275976Ssmh/*
2140275976Ssmh * mrsas_init_adapter:	Initializes the adapter/controller
2141275976Ssmh * input:				Adapter soft state
2142265555Sambrisko *
2143275976Ssmh * Prepares for the issuing of the IOC Init cmd to FW for initializing the
2144275976Ssmh * ROC/controller.  The FW register is read to determined the number of
2145265555Sambrisko * commands that is supported.  All memory allocations for IO is based on
2146275976Ssmh * max_cmd.  Appropriate calculations are performed in this function.
2147265555Sambrisko */
2148275976Ssmhint
2149275976Ssmhmrsas_init_adapter(struct mrsas_softc *sc)
2150265555Sambrisko{
2151275976Ssmh	uint32_t status;
2152275976Ssmh	u_int32_t max_cmd;
2153275976Ssmh	int ret;
2154275976Ssmh	int i = 0;
2155265555Sambrisko
2156275976Ssmh	/* Read FW status register */
2157275976Ssmh	status = mrsas_read_reg(sc, offsetof(mrsas_reg_set, outbound_scratch_pad));
2158265555Sambrisko
2159275976Ssmh	/* Get operational params from status register */
2160275976Ssmh	sc->max_fw_cmds = status & MRSAS_FWSTATE_MAXCMD_MASK;
2161265555Sambrisko
2162275976Ssmh	/* Decrement the max supported by 1, to correlate with FW */
2163275976Ssmh	sc->max_fw_cmds = sc->max_fw_cmds - 1;
2164275976Ssmh	max_cmd = sc->max_fw_cmds;
2165265555Sambrisko
2166275976Ssmh	/* Determine allocation size of command frames */
2167284267Skadesai	sc->reply_q_depth = ((max_cmd + 1 + 15) / 16 * 16) * 2;
2168275976Ssmh	sc->request_alloc_sz = sizeof(MRSAS_REQUEST_DESCRIPTOR_UNION) * max_cmd;
2169275976Ssmh	sc->reply_alloc_sz = sizeof(MPI2_REPLY_DESCRIPTORS_UNION) * (sc->reply_q_depth);
2170275976Ssmh	sc->io_frames_alloc_sz = MRSAS_MPI2_RAID_DEFAULT_IO_FRAME_SIZE + (MRSAS_MPI2_RAID_DEFAULT_IO_FRAME_SIZE * (max_cmd + 1));
2171275976Ssmh	sc->chain_frames_alloc_sz = 1024 * max_cmd;
2172275976Ssmh	sc->max_sge_in_main_msg = (MRSAS_MPI2_RAID_DEFAULT_IO_FRAME_SIZE -
2173275976Ssmh	    offsetof(MRSAS_RAID_SCSI_IO_REQUEST, SGL)) / 16;
2174265555Sambrisko
2175275976Ssmh	sc->max_sge_in_chain = MRSAS_MAX_SZ_CHAIN_FRAME / sizeof(MPI2_SGE_IO_UNION);
2176275976Ssmh	sc->max_num_sge = sc->max_sge_in_main_msg + sc->max_sge_in_chain - 2;
2177265555Sambrisko
2178275976Ssmh	/* Used for pass thru MFI frame (DCMD) */
2179275976Ssmh	sc->chain_offset_mfi_pthru = offsetof(MRSAS_RAID_SCSI_IO_REQUEST, SGL) / 16;
2180265555Sambrisko
2181275976Ssmh	sc->chain_offset_io_request = (MRSAS_MPI2_RAID_DEFAULT_IO_FRAME_SIZE -
2182275976Ssmh	    sizeof(MPI2_SGE_IO_UNION)) / 16;
2183265555Sambrisko
2184275976Ssmh	int count = sc->msix_vectors > 0 ? sc->msix_vectors : 1;
2185265555Sambrisko
2186275976Ssmh	for (i = 0; i < count; i++)
2187275976Ssmh		sc->last_reply_idx[i] = 0;
2188265555Sambrisko
2189275976Ssmh	ret = mrsas_alloc_mem(sc);
2190275976Ssmh	if (ret != SUCCESS)
2191275976Ssmh		return (ret);
2192265555Sambrisko
2193275976Ssmh	ret = mrsas_alloc_mpt_cmds(sc);
2194275976Ssmh	if (ret != SUCCESS)
2195275976Ssmh		return (ret);
2196275976Ssmh
2197275976Ssmh	ret = mrsas_ioc_init(sc);
2198275976Ssmh	if (ret != SUCCESS)
2199275976Ssmh		return (ret);
2200275976Ssmh
2201275976Ssmh	return (0);
2202265555Sambrisko}
2203265555Sambrisko
2204275976Ssmh/*
2205275976Ssmh * mrsas_alloc_ioc_cmd:	Allocates memory for IOC Init command
2206275976Ssmh * input:				Adapter soft state
2207265555Sambrisko *
2208265555Sambrisko * Allocates for the IOC Init cmd to FW to initialize the ROC/controller.
2209265555Sambrisko */
2210275976Ssmhint
2211275976Ssmhmrsas_alloc_ioc_cmd(struct mrsas_softc *sc)
2212265555Sambrisko{
2213275976Ssmh	int ioc_init_size;
2214265555Sambrisko
2215275976Ssmh	/* Allocate IOC INIT command */
2216275976Ssmh	ioc_init_size = 1024 + sizeof(MPI2_IOC_INIT_REQUEST);
2217275976Ssmh	if (bus_dma_tag_create(sc->mrsas_parent_tag,
2218275976Ssmh	    1, 0,
2219275976Ssmh	    BUS_SPACE_MAXADDR_32BIT,
2220275976Ssmh	    BUS_SPACE_MAXADDR,
2221275976Ssmh	    NULL, NULL,
2222275976Ssmh	    ioc_init_size,
2223275976Ssmh	    1,
2224275976Ssmh	    ioc_init_size,
2225275976Ssmh	    BUS_DMA_ALLOCNOW,
2226275976Ssmh	    NULL, NULL,
2227275976Ssmh	    &sc->ioc_init_tag)) {
2228275976Ssmh		device_printf(sc->mrsas_dev, "Cannot allocate ioc init tag\n");
2229275976Ssmh		return (ENOMEM);
2230275976Ssmh	}
2231275976Ssmh	if (bus_dmamem_alloc(sc->ioc_init_tag, (void **)&sc->ioc_init_mem,
2232275976Ssmh	    BUS_DMA_NOWAIT, &sc->ioc_init_dmamap)) {
2233275976Ssmh		device_printf(sc->mrsas_dev, "Cannot allocate ioc init cmd mem\n");
2234275976Ssmh		return (ENOMEM);
2235275976Ssmh	}
2236275976Ssmh	bzero(sc->ioc_init_mem, ioc_init_size);
2237275976Ssmh	if (bus_dmamap_load(sc->ioc_init_tag, sc->ioc_init_dmamap,
2238275976Ssmh	    sc->ioc_init_mem, ioc_init_size, mrsas_addr_cb,
2239275976Ssmh	    &sc->ioc_init_phys_mem, BUS_DMA_NOWAIT)) {
2240275976Ssmh		device_printf(sc->mrsas_dev, "Cannot load ioc init cmd mem\n");
2241275976Ssmh		return (ENOMEM);
2242275976Ssmh	}
2243275976Ssmh	return (0);
2244265555Sambrisko}
2245265555Sambrisko
2246275976Ssmh/*
2247275976Ssmh * mrsas_free_ioc_cmd:	Allocates memory for IOC Init command
2248275976Ssmh * input:				Adapter soft state
2249265555Sambrisko *
2250265555Sambrisko * Deallocates memory of the IOC Init cmd.
2251265555Sambrisko */
2252275976Ssmhvoid
2253275976Ssmhmrsas_free_ioc_cmd(struct mrsas_softc *sc)
2254265555Sambrisko{
2255275976Ssmh	if (sc->ioc_init_phys_mem)
2256275976Ssmh		bus_dmamap_unload(sc->ioc_init_tag, sc->ioc_init_dmamap);
2257275976Ssmh	if (sc->ioc_init_mem != NULL)
2258275976Ssmh		bus_dmamem_free(sc->ioc_init_tag, sc->ioc_init_mem, sc->ioc_init_dmamap);
2259275976Ssmh	if (sc->ioc_init_tag != NULL)
2260275976Ssmh		bus_dma_tag_destroy(sc->ioc_init_tag);
2261265555Sambrisko}
2262265555Sambrisko
2263275976Ssmh/*
2264275976Ssmh * mrsas_ioc_init:	Sends IOC Init command to FW
2265275976Ssmh * input:			Adapter soft state
2266265555Sambrisko *
2267265555Sambrisko * Issues the IOC Init cmd to FW to initialize the ROC/controller.
2268265555Sambrisko */
2269275976Ssmhint
2270275976Ssmhmrsas_ioc_init(struct mrsas_softc *sc)
2271265555Sambrisko{
2272275976Ssmh	struct mrsas_init_frame *init_frame;
2273275976Ssmh	pMpi2IOCInitRequest_t IOCInitMsg;
2274275976Ssmh	MRSAS_REQUEST_DESCRIPTOR_UNION req_desc;
2275275976Ssmh	u_int8_t max_wait = MRSAS_IOC_INIT_WAIT_TIME;
2276275976Ssmh	bus_addr_t phys_addr;
2277275976Ssmh	int i, retcode = 0;
2278265555Sambrisko
2279275976Ssmh	/* Allocate memory for the IOC INIT command */
2280275976Ssmh	if (mrsas_alloc_ioc_cmd(sc)) {
2281275976Ssmh		device_printf(sc->mrsas_dev, "Cannot allocate IOC command.\n");
2282275976Ssmh		return (1);
2283275976Ssmh	}
2284275976Ssmh	IOCInitMsg = (pMpi2IOCInitRequest_t)(((char *)sc->ioc_init_mem) + 1024);
2285275976Ssmh	IOCInitMsg->Function = MPI2_FUNCTION_IOC_INIT;
2286275976Ssmh	IOCInitMsg->WhoInit = MPI2_WHOINIT_HOST_DRIVER;
2287275976Ssmh	IOCInitMsg->MsgVersion = MPI2_VERSION;
2288275976Ssmh	IOCInitMsg->HeaderVersion = MPI2_HEADER_VERSION;
2289275976Ssmh	IOCInitMsg->SystemRequestFrameSize = MRSAS_MPI2_RAID_DEFAULT_IO_FRAME_SIZE / 4;
2290275976Ssmh	IOCInitMsg->ReplyDescriptorPostQueueDepth = sc->reply_q_depth;
2291275976Ssmh	IOCInitMsg->ReplyDescriptorPostQueueAddress = sc->reply_desc_phys_addr;
2292275976Ssmh	IOCInitMsg->SystemRequestFrameBaseAddress = sc->io_request_phys_addr;
2293275976Ssmh	IOCInitMsg->HostMSIxVectors = (sc->msix_vectors > 0 ? sc->msix_vectors : 0);
2294265555Sambrisko
2295275976Ssmh	init_frame = (struct mrsas_init_frame *)sc->ioc_init_mem;
2296275976Ssmh	init_frame->cmd = MFI_CMD_INIT;
2297275976Ssmh	init_frame->cmd_status = 0xFF;
2298275976Ssmh	init_frame->flags |= MFI_FRAME_DONT_POST_IN_REPLY_QUEUE;
2299265555Sambrisko
2300275976Ssmh	/* driver support Extended MSIX */
2301275976Ssmh	if ((sc->device_id == MRSAS_INVADER) ||
2302275976Ssmh	    (sc->device_id == MRSAS_FURY)) {
2303275976Ssmh		init_frame->driver_operations.
2304275976Ssmh		    mfi_capabilities.support_additional_msix = 1;
2305275976Ssmh	}
2306275976Ssmh	if (sc->verbuf_mem) {
2307275976Ssmh		snprintf((char *)sc->verbuf_mem, strlen(MRSAS_VERSION) + 2, "%s\n",
2308275976Ssmh		    MRSAS_VERSION);
2309275976Ssmh		init_frame->driver_ver_lo = (bus_addr_t)sc->verbuf_phys_addr;
2310275976Ssmh		init_frame->driver_ver_hi = 0;
2311275976Ssmh	}
2312284267Skadesai	init_frame->driver_operations.mfi_capabilities.support_ndrive_r1_lb = 1;
2313275976Ssmh	init_frame->driver_operations.mfi_capabilities.support_max_255lds = 1;
2314284267Skadesai	init_frame->driver_operations.mfi_capabilities.security_protocol_cmds_fw = 1;
2315275976Ssmh	phys_addr = (bus_addr_t)sc->ioc_init_phys_mem + 1024;
2316275976Ssmh	init_frame->queue_info_new_phys_addr_lo = phys_addr;
2317275976Ssmh	init_frame->data_xfer_len = sizeof(Mpi2IOCInitRequest_t);
2318265555Sambrisko
2319275976Ssmh	req_desc.addr.Words = (bus_addr_t)sc->ioc_init_phys_mem;
2320275976Ssmh	req_desc.MFAIo.RequestFlags =
2321275976Ssmh	    (MRSAS_REQ_DESCRIPT_FLAGS_MFA << MRSAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
2322265555Sambrisko
2323275976Ssmh	mrsas_disable_intr(sc);
2324275976Ssmh	mrsas_dprint(sc, MRSAS_OCR, "Issuing IOC INIT command to FW.\n");
2325275976Ssmh	mrsas_fire_cmd(sc, req_desc.addr.u.low, req_desc.addr.u.high);
2326265555Sambrisko
2327275976Ssmh	/*
2328275976Ssmh	 * Poll response timer to wait for Firmware response.  While this
2329275976Ssmh	 * timer with the DELAY call could block CPU, the time interval for
2330275976Ssmh	 * this is only 1 millisecond.
2331275976Ssmh	 */
2332275976Ssmh	if (init_frame->cmd_status == 0xFF) {
2333275976Ssmh		for (i = 0; i < (max_wait * 1000); i++) {
2334275976Ssmh			if (init_frame->cmd_status == 0xFF)
2335275976Ssmh				DELAY(1000);
2336275976Ssmh			else
2337275976Ssmh				break;
2338275976Ssmh		}
2339275976Ssmh	}
2340275976Ssmh	if (init_frame->cmd_status == 0)
2341275976Ssmh		mrsas_dprint(sc, MRSAS_OCR,
2342275976Ssmh		    "IOC INIT response received from FW.\n");
2343275976Ssmh	else {
2344275976Ssmh		if (init_frame->cmd_status == 0xFF)
2345275976Ssmh			device_printf(sc->mrsas_dev, "IOC Init timed out after %d seconds.\n", max_wait);
2346275976Ssmh		else
2347275976Ssmh			device_printf(sc->mrsas_dev, "IOC Init failed, status = 0x%x\n", init_frame->cmd_status);
2348275976Ssmh		retcode = 1;
2349275976Ssmh	}
2350265555Sambrisko
2351275976Ssmh	mrsas_free_ioc_cmd(sc);
2352275976Ssmh	return (retcode);
2353265555Sambrisko}
2354265555Sambrisko
2355275976Ssmh/*
2356275976Ssmh * mrsas_alloc_mpt_cmds:	Allocates the command packets
2357275976Ssmh * input:					Adapter instance soft state
2358265555Sambrisko *
2359265555Sambrisko * This function allocates the internal commands for IOs. Each command that is
2360275976Ssmh * issued to FW is wrapped in a local data structure called mrsas_mpt_cmd. An
2361275976Ssmh * array is allocated with mrsas_mpt_cmd context.  The free commands are
2362265555Sambrisko * maintained in a linked list (cmd pool). SMID value range is from 1 to
2363265555Sambrisko * max_fw_cmds.
2364265555Sambrisko */
2365275976Ssmhint
2366275976Ssmhmrsas_alloc_mpt_cmds(struct mrsas_softc *sc)
2367265555Sambrisko{
2368275976Ssmh	int i, j;
2369275976Ssmh	u_int32_t max_cmd, count;
2370275976Ssmh	struct mrsas_mpt_cmd *cmd;
2371275976Ssmh	pMpi2ReplyDescriptorsUnion_t reply_desc;
2372275976Ssmh	u_int32_t offset, chain_offset, sense_offset;
2373275976Ssmh	bus_addr_t io_req_base_phys, chain_frame_base_phys, sense_base_phys;
2374275976Ssmh	u_int8_t *io_req_base, *chain_frame_base, *sense_base;
2375265555Sambrisko
2376275976Ssmh	max_cmd = sc->max_fw_cmds;
2377265555Sambrisko
2378275976Ssmh	sc->req_desc = malloc(sc->request_alloc_sz, M_MRSAS, M_NOWAIT);
2379275976Ssmh	if (!sc->req_desc) {
2380275976Ssmh		device_printf(sc->mrsas_dev, "Out of memory, cannot alloc req desc\n");
2381275976Ssmh		return (ENOMEM);
2382275976Ssmh	}
2383275976Ssmh	memset(sc->req_desc, 0, sc->request_alloc_sz);
2384265555Sambrisko
2385275976Ssmh	/*
2386275976Ssmh	 * sc->mpt_cmd_list is an array of struct mrsas_mpt_cmd pointers.
2387275976Ssmh	 * Allocate the dynamic array first and then allocate individual
2388275976Ssmh	 * commands.
2389275976Ssmh	 */
2390275976Ssmh	sc->mpt_cmd_list = malloc(sizeof(struct mrsas_mpt_cmd *) * max_cmd, M_MRSAS, M_NOWAIT);
2391275976Ssmh	if (!sc->mpt_cmd_list) {
2392275976Ssmh		device_printf(sc->mrsas_dev, "Cannot alloc memory for mpt_cmd_list.\n");
2393275976Ssmh		return (ENOMEM);
2394275976Ssmh	}
2395275976Ssmh	memset(sc->mpt_cmd_list, 0, sizeof(struct mrsas_mpt_cmd *) * max_cmd);
2396275976Ssmh	for (i = 0; i < max_cmd; i++) {
2397275976Ssmh		sc->mpt_cmd_list[i] = malloc(sizeof(struct mrsas_mpt_cmd),
2398275976Ssmh		    M_MRSAS, M_NOWAIT);
2399275976Ssmh		if (!sc->mpt_cmd_list[i]) {
2400275976Ssmh			for (j = 0; j < i; j++)
2401275976Ssmh				free(sc->mpt_cmd_list[j], M_MRSAS);
2402275976Ssmh			free(sc->mpt_cmd_list, M_MRSAS);
2403275976Ssmh			sc->mpt_cmd_list = NULL;
2404275976Ssmh			return (ENOMEM);
2405275976Ssmh		}
2406275976Ssmh	}
2407265555Sambrisko
2408275976Ssmh	io_req_base = (u_int8_t *)sc->io_request_mem + MRSAS_MPI2_RAID_DEFAULT_IO_FRAME_SIZE;
2409275976Ssmh	io_req_base_phys = (bus_addr_t)sc->io_request_phys_addr + MRSAS_MPI2_RAID_DEFAULT_IO_FRAME_SIZE;
2410275976Ssmh	chain_frame_base = (u_int8_t *)sc->chain_frame_mem;
2411275976Ssmh	chain_frame_base_phys = (bus_addr_t)sc->chain_frame_phys_addr;
2412275976Ssmh	sense_base = (u_int8_t *)sc->sense_mem;
2413275976Ssmh	sense_base_phys = (bus_addr_t)sc->sense_phys_addr;
2414275976Ssmh	for (i = 0; i < max_cmd; i++) {
2415275976Ssmh		cmd = sc->mpt_cmd_list[i];
2416275976Ssmh		offset = MRSAS_MPI2_RAID_DEFAULT_IO_FRAME_SIZE * i;
2417275976Ssmh		chain_offset = 1024 * i;
2418275976Ssmh		sense_offset = MRSAS_SENSE_LEN * i;
2419275976Ssmh		memset(cmd, 0, sizeof(struct mrsas_mpt_cmd));
2420275976Ssmh		cmd->index = i + 1;
2421275976Ssmh		cmd->ccb_ptr = NULL;
2422275976Ssmh		callout_init(&cmd->cm_callout, 0);
2423275976Ssmh		cmd->sync_cmd_idx = (u_int32_t)MRSAS_ULONG_MAX;
2424275976Ssmh		cmd->sc = sc;
2425275976Ssmh		cmd->io_request = (MRSAS_RAID_SCSI_IO_REQUEST *) (io_req_base + offset);
2426275976Ssmh		memset(cmd->io_request, 0, sizeof(MRSAS_RAID_SCSI_IO_REQUEST));
2427275976Ssmh		cmd->io_request_phys_addr = io_req_base_phys + offset;
2428275976Ssmh		cmd->chain_frame = (MPI2_SGE_IO_UNION *) (chain_frame_base + chain_offset);
2429275976Ssmh		cmd->chain_frame_phys_addr = chain_frame_base_phys + chain_offset;
2430275976Ssmh		cmd->sense = sense_base + sense_offset;
2431275976Ssmh		cmd->sense_phys_addr = sense_base_phys + sense_offset;
2432275976Ssmh		if (bus_dmamap_create(sc->data_tag, 0, &cmd->data_dmamap)) {
2433275976Ssmh			return (FAIL);
2434275976Ssmh		}
2435275976Ssmh		TAILQ_INSERT_TAIL(&(sc->mrsas_mpt_cmd_list_head), cmd, next);
2436275976Ssmh	}
2437275976Ssmh
2438275976Ssmh	/* Initialize reply descriptor array to 0xFFFFFFFF */
2439275976Ssmh	reply_desc = sc->reply_desc_mem;
2440275976Ssmh	count = sc->msix_vectors > 0 ? sc->msix_vectors : 1;
2441275976Ssmh	for (i = 0; i < sc->reply_q_depth * count; i++, reply_desc++) {
2442275976Ssmh		reply_desc->Words = MRSAS_ULONG_MAX;
2443275976Ssmh	}
2444275976Ssmh	return (0);
2445265555Sambrisko}
2446265555Sambrisko
2447275976Ssmh/*
2448275976Ssmh * mrsas_fire_cmd:	Sends command to FW
2449275976Ssmh * input:			Adapter softstate
2450275976Ssmh * 					request descriptor address low
2451275976Ssmh * 					request descriptor address high
2452265555Sambrisko *
2453275976Ssmh * This functions fires the command to Firmware by writing to the
2454265555Sambrisko * inbound_low_queue_port and inbound_high_queue_port.
2455265555Sambrisko */
2456284267Skadesaivoid
2457275976Ssmhmrsas_fire_cmd(struct mrsas_softc *sc, u_int32_t req_desc_lo,
2458275976Ssmh    u_int32_t req_desc_hi)
2459275976Ssmh{
2460275976Ssmh	mtx_lock(&sc->pci_lock);
2461275976Ssmh	mrsas_write_reg(sc, offsetof(mrsas_reg_set, inbound_low_queue_port),
2462275976Ssmh	    req_desc_lo);
2463275976Ssmh	mrsas_write_reg(sc, offsetof(mrsas_reg_set, inbound_high_queue_port),
2464275976Ssmh	    req_desc_hi);
2465275976Ssmh	mtx_unlock(&sc->pci_lock);
2466265555Sambrisko}
2467265555Sambrisko
2468275976Ssmh/*
2469275976Ssmh * mrsas_transition_to_ready:  Move FW to Ready state input:
2470275976Ssmh * Adapter instance soft state
2471265555Sambrisko *
2472275976Ssmh * During the initialization, FW passes can potentially be in any one of several
2473275976Ssmh * possible states. If the FW in operational, waiting-for-handshake states,
2474275976Ssmh * driver must take steps to bring it to ready state. Otherwise, it has to
2475275976Ssmh * wait for the ready state.
2476265555Sambrisko */
2477275976Ssmhint
2478275976Ssmhmrsas_transition_to_ready(struct mrsas_softc *sc, int ocr)
2479265555Sambrisko{
2480275976Ssmh	int i;
2481275976Ssmh	u_int8_t max_wait;
2482275976Ssmh	u_int32_t val, fw_state;
2483275976Ssmh	u_int32_t cur_state;
2484275976Ssmh	u_int32_t abs_state, curr_abs_state;
2485265555Sambrisko
2486275976Ssmh	val = mrsas_read_reg(sc, offsetof(mrsas_reg_set, outbound_scratch_pad));
2487275976Ssmh	fw_state = val & MFI_STATE_MASK;
2488275976Ssmh	max_wait = MRSAS_RESET_WAIT_TIME;
2489265555Sambrisko
2490275976Ssmh	if (fw_state != MFI_STATE_READY)
2491275976Ssmh		device_printf(sc->mrsas_dev, "Waiting for FW to come to ready state\n");
2492265555Sambrisko
2493275976Ssmh	while (fw_state != MFI_STATE_READY) {
2494275976Ssmh		abs_state = mrsas_read_reg(sc, offsetof(mrsas_reg_set, outbound_scratch_pad));
2495275976Ssmh		switch (fw_state) {
2496275976Ssmh		case MFI_STATE_FAULT:
2497275976Ssmh			device_printf(sc->mrsas_dev, "FW is in FAULT state!!\n");
2498275976Ssmh			if (ocr) {
2499275976Ssmh				cur_state = MFI_STATE_FAULT;
2500275976Ssmh				break;
2501275976Ssmh			} else
2502275976Ssmh				return -ENODEV;
2503275976Ssmh		case MFI_STATE_WAIT_HANDSHAKE:
2504275976Ssmh			/* Set the CLR bit in inbound doorbell */
2505275976Ssmh			mrsas_write_reg(sc, offsetof(mrsas_reg_set, doorbell),
2506275976Ssmh			    MFI_INIT_CLEAR_HANDSHAKE | MFI_INIT_HOTPLUG);
2507275976Ssmh			cur_state = MFI_STATE_WAIT_HANDSHAKE;
2508275976Ssmh			break;
2509275976Ssmh		case MFI_STATE_BOOT_MESSAGE_PENDING:
2510275976Ssmh			mrsas_write_reg(sc, offsetof(mrsas_reg_set, doorbell),
2511275976Ssmh			    MFI_INIT_HOTPLUG);
2512275976Ssmh			cur_state = MFI_STATE_BOOT_MESSAGE_PENDING;
2513275976Ssmh			break;
2514275976Ssmh		case MFI_STATE_OPERATIONAL:
2515275976Ssmh			/*
2516275976Ssmh			 * Bring it to READY state; assuming max wait 10
2517275976Ssmh			 * secs
2518275976Ssmh			 */
2519275976Ssmh			mrsas_disable_intr(sc);
2520275976Ssmh			mrsas_write_reg(sc, offsetof(mrsas_reg_set, doorbell), MFI_RESET_FLAGS);
2521275976Ssmh			for (i = 0; i < max_wait * 1000; i++) {
2522275976Ssmh				if (mrsas_read_reg(sc, offsetof(mrsas_reg_set, doorbell)) & 1)
2523275976Ssmh					DELAY(1000);
2524275976Ssmh				else
2525275976Ssmh					break;
2526275976Ssmh			}
2527275976Ssmh			cur_state = MFI_STATE_OPERATIONAL;
2528275976Ssmh			break;
2529275976Ssmh		case MFI_STATE_UNDEFINED:
2530275976Ssmh			/*
2531275976Ssmh			 * This state should not last for more than 2
2532275976Ssmh			 * seconds
2533275976Ssmh			 */
2534275976Ssmh			cur_state = MFI_STATE_UNDEFINED;
2535275976Ssmh			break;
2536275976Ssmh		case MFI_STATE_BB_INIT:
2537275976Ssmh			cur_state = MFI_STATE_BB_INIT;
2538275976Ssmh			break;
2539275976Ssmh		case MFI_STATE_FW_INIT:
2540275976Ssmh			cur_state = MFI_STATE_FW_INIT;
2541275976Ssmh			break;
2542275976Ssmh		case MFI_STATE_FW_INIT_2:
2543275976Ssmh			cur_state = MFI_STATE_FW_INIT_2;
2544275976Ssmh			break;
2545275976Ssmh		case MFI_STATE_DEVICE_SCAN:
2546275976Ssmh			cur_state = MFI_STATE_DEVICE_SCAN;
2547275976Ssmh			break;
2548275976Ssmh		case MFI_STATE_FLUSH_CACHE:
2549275976Ssmh			cur_state = MFI_STATE_FLUSH_CACHE;
2550275976Ssmh			break;
2551275976Ssmh		default:
2552275976Ssmh			device_printf(sc->mrsas_dev, "Unknown state 0x%x\n", fw_state);
2553265555Sambrisko			return -ENODEV;
2554275976Ssmh		}
2555265555Sambrisko
2556275976Ssmh		/*
2557275976Ssmh		 * The cur_state should not last for more than max_wait secs
2558275976Ssmh		 */
2559275976Ssmh		for (i = 0; i < (max_wait * 1000); i++) {
2560275976Ssmh			fw_state = (mrsas_read_reg(sc, offsetof(mrsas_reg_set,
2561275976Ssmh			    outbound_scratch_pad)) & MFI_STATE_MASK);
2562275976Ssmh			curr_abs_state = mrsas_read_reg(sc, offsetof(mrsas_reg_set,
2563275976Ssmh			    outbound_scratch_pad));
2564275976Ssmh			if (abs_state == curr_abs_state)
2565275976Ssmh				DELAY(1000);
2566275976Ssmh			else
2567275976Ssmh				break;
2568275976Ssmh		}
2569265555Sambrisko
2570275976Ssmh		/*
2571275976Ssmh		 * Return error if fw_state hasn't changed after max_wait
2572275976Ssmh		 */
2573275976Ssmh		if (curr_abs_state == abs_state) {
2574275976Ssmh			device_printf(sc->mrsas_dev, "FW state [%d] hasn't changed "
2575275976Ssmh			    "in %d secs\n", fw_state, max_wait);
2576275976Ssmh			return -ENODEV;
2577275976Ssmh		}
2578265555Sambrisko	}
2579275976Ssmh	mrsas_dprint(sc, MRSAS_OCR, "FW now in Ready state\n");
2580275976Ssmh	return 0;
2581265555Sambrisko}
2582265555Sambrisko
2583275976Ssmh/*
2584275976Ssmh * mrsas_get_mfi_cmd:	Get a cmd from free command pool
2585275976Ssmh * input:				Adapter soft state
2586265555Sambrisko *
2587265555Sambrisko * This function removes an MFI command from the command list.
2588265555Sambrisko */
2589275976Ssmhstruct mrsas_mfi_cmd *
2590275976Ssmhmrsas_get_mfi_cmd(struct mrsas_softc *sc)
2591265555Sambrisko{
2592275976Ssmh	struct mrsas_mfi_cmd *cmd = NULL;
2593275976Ssmh
2594275976Ssmh	mtx_lock(&sc->mfi_cmd_pool_lock);
2595275976Ssmh	if (!TAILQ_EMPTY(&sc->mrsas_mfi_cmd_list_head)) {
2596275976Ssmh		cmd = TAILQ_FIRST(&sc->mrsas_mfi_cmd_list_head);
2597275976Ssmh		TAILQ_REMOVE(&sc->mrsas_mfi_cmd_list_head, cmd, next);
2598275976Ssmh	}
2599275976Ssmh	mtx_unlock(&sc->mfi_cmd_pool_lock);
2600275976Ssmh
2601275976Ssmh	return cmd;
2602265555Sambrisko}
2603265555Sambrisko
2604275976Ssmh/*
2605275976Ssmh * mrsas_ocr_thread:	Thread to handle OCR/Kill Adapter.
2606275976Ssmh * input:				Adapter Context.
2607265555Sambrisko *
2608275976Ssmh * This function will check FW status register and flag do_timeout_reset flag.
2609275976Ssmh * It will do OCR/Kill adapter if FW is in fault state or IO timed out has
2610275976Ssmh * trigger reset.
2611265555Sambrisko */
2612265555Sambriskostatic void
2613265555Sambriskomrsas_ocr_thread(void *arg)
2614265555Sambrisko{
2615275976Ssmh	struct mrsas_softc *sc;
2616275976Ssmh	u_int32_t fw_status, fw_state;
2617265555Sambrisko
2618275976Ssmh	sc = (struct mrsas_softc *)arg;
2619275976Ssmh
2620275976Ssmh	mrsas_dprint(sc, MRSAS_TRACE, "%s\n", __func__);
2621275976Ssmh
2622275976Ssmh	sc->ocr_thread_active = 1;
2623275976Ssmh	mtx_lock(&sc->sim_lock);
2624275976Ssmh	for (;;) {
2625275976Ssmh		/* Sleep for 1 second and check the queue status */
2626275976Ssmh		msleep(&sc->ocr_chan, &sc->sim_lock, PRIBIO,
2627275976Ssmh		    "mrsas_ocr", sc->mrsas_fw_fault_check_delay * hz);
2628275976Ssmh		if (sc->remove_in_progress) {
2629275976Ssmh			mrsas_dprint(sc, MRSAS_OCR,
2630275976Ssmh			    "Exit due to shutdown from %s\n", __func__);
2631275976Ssmh			break;
2632275976Ssmh		}
2633275976Ssmh		fw_status = mrsas_read_reg(sc,
2634275976Ssmh		    offsetof(mrsas_reg_set, outbound_scratch_pad));
2635275976Ssmh		fw_state = fw_status & MFI_STATE_MASK;
2636275976Ssmh		if (fw_state == MFI_STATE_FAULT || sc->do_timedout_reset) {
2637275976Ssmh			device_printf(sc->mrsas_dev, "OCR started due to %s!\n",
2638275976Ssmh			    sc->do_timedout_reset ? "IO Timeout" :
2639275976Ssmh			    "FW fault detected");
2640275976Ssmh			mtx_lock_spin(&sc->ioctl_lock);
2641275976Ssmh			sc->reset_in_progress = 1;
2642275976Ssmh			sc->reset_count++;
2643275976Ssmh			mtx_unlock_spin(&sc->ioctl_lock);
2644275976Ssmh			mrsas_xpt_freeze(sc);
2645275976Ssmh			mrsas_reset_ctrl(sc);
2646275976Ssmh			mrsas_xpt_release(sc);
2647275976Ssmh			sc->reset_in_progress = 0;
2648275976Ssmh			sc->do_timedout_reset = 0;
2649275976Ssmh		}
2650275976Ssmh	}
2651275976Ssmh	mtx_unlock(&sc->sim_lock);
2652275976Ssmh	sc->ocr_thread_active = 0;
2653275976Ssmh	mrsas_kproc_exit(0);
2654265555Sambrisko}
2655265555Sambrisko
2656275976Ssmh/*
2657275976Ssmh * mrsas_reset_reply_desc:	Reset Reply descriptor as part of OCR.
2658275976Ssmh * input:					Adapter Context.
2659265555Sambrisko *
2660275976Ssmh * This function will clear reply descriptor so that post OCR driver and FW will
2661275976Ssmh * lost old history.
2662265555Sambrisko */
2663275976Ssmhvoid
2664275976Ssmhmrsas_reset_reply_desc(struct mrsas_softc *sc)
2665265555Sambrisko{
2666275976Ssmh	int i, count;
2667275976Ssmh	pMpi2ReplyDescriptorsUnion_t reply_desc;
2668265555Sambrisko
2669275976Ssmh	count = sc->msix_vectors > 0 ? sc->msix_vectors : 1;
2670275976Ssmh	for (i = 0; i < count; i++)
2671275976Ssmh		sc->last_reply_idx[i] = 0;
2672275976Ssmh
2673275976Ssmh	reply_desc = sc->reply_desc_mem;
2674275976Ssmh	for (i = 0; i < sc->reply_q_depth; i++, reply_desc++) {
2675275976Ssmh		reply_desc->Words = MRSAS_ULONG_MAX;
2676275976Ssmh	}
2677265555Sambrisko}
2678265555Sambrisko
2679275976Ssmh/*
2680275976Ssmh * mrsas_reset_ctrl:	Core function to OCR/Kill adapter.
2681275976Ssmh * input:				Adapter Context.
2682265555Sambrisko *
2683275976Ssmh * This function will run from thread context so that it can sleep. 1. Do not
2684275976Ssmh * handle OCR if FW is in HW critical error. 2. Wait for outstanding command
2685275976Ssmh * to complete for 180 seconds. 3. If #2 does not find any outstanding
2686275976Ssmh * command Controller is in working state, so skip OCR. Otherwise, do
2687275976Ssmh * OCR/kill Adapter based on flag disableOnlineCtrlReset. 4. Start of the
2688275976Ssmh * OCR, return all SCSI command back to CAM layer which has ccb_ptr. 5. Post
2689275976Ssmh * OCR, Re-fire Managment command and move Controller to Operation state.
2690265555Sambrisko */
2691275976Ssmhint
2692275976Ssmhmrsas_reset_ctrl(struct mrsas_softc *sc)
2693265555Sambrisko{
2694275976Ssmh	int retval = SUCCESS, i, j, retry = 0;
2695275976Ssmh	u_int32_t host_diag, abs_state, status_reg, reset_adapter;
2696275976Ssmh	union ccb *ccb;
2697275976Ssmh	struct mrsas_mfi_cmd *mfi_cmd;
2698275976Ssmh	struct mrsas_mpt_cmd *mpt_cmd;
2699275976Ssmh	MRSAS_REQUEST_DESCRIPTOR_UNION *req_desc;
2700265555Sambrisko
2701275976Ssmh	if (sc->adprecovery == MRSAS_HW_CRITICAL_ERROR) {
2702275976Ssmh		device_printf(sc->mrsas_dev,
2703275976Ssmh		    "mrsas: Hardware critical error, returning FAIL.\n");
2704275976Ssmh		return FAIL;
2705275976Ssmh	}
2706275976Ssmh	mrsas_set_bit(MRSAS_FUSION_IN_RESET, &sc->reset_flags);
2707275976Ssmh	sc->adprecovery = MRSAS_ADPRESET_SM_INFAULT;
2708275976Ssmh	mrsas_disable_intr(sc);
2709275976Ssmh	DELAY(1000 * 1000);
2710265555Sambrisko
2711275976Ssmh	/* First try waiting for commands to complete */
2712275976Ssmh	if (mrsas_wait_for_outstanding(sc)) {
2713275976Ssmh		mrsas_dprint(sc, MRSAS_OCR,
2714275976Ssmh		    "resetting adapter from %s.\n",
2715275976Ssmh		    __func__);
2716275976Ssmh		/* Now return commands back to the CAM layer */
2717275976Ssmh		for (i = 0; i < sc->max_fw_cmds; i++) {
2718275976Ssmh			mpt_cmd = sc->mpt_cmd_list[i];
2719275976Ssmh			if (mpt_cmd->ccb_ptr) {
2720275976Ssmh				ccb = (union ccb *)(mpt_cmd->ccb_ptr);
2721275976Ssmh				ccb->ccb_h.status = CAM_SCSI_BUS_RESET;
2722275976Ssmh				mrsas_cmd_done(sc, mpt_cmd);
2723275976Ssmh				mrsas_atomic_dec(&sc->fw_outstanding);
2724275976Ssmh			}
2725275976Ssmh		}
2726265555Sambrisko
2727275976Ssmh		status_reg = mrsas_read_reg(sc, offsetof(mrsas_reg_set,
2728275976Ssmh		    outbound_scratch_pad));
2729275976Ssmh		abs_state = status_reg & MFI_STATE_MASK;
2730275976Ssmh		reset_adapter = status_reg & MFI_RESET_ADAPTER;
2731275976Ssmh		if (sc->disableOnlineCtrlReset ||
2732275976Ssmh		    (abs_state == MFI_STATE_FAULT && !reset_adapter)) {
2733275976Ssmh			/* Reset not supported, kill adapter */
2734275976Ssmh			mrsas_dprint(sc, MRSAS_OCR, "Reset not supported, killing adapter.\n");
2735275976Ssmh			mrsas_kill_hba(sc);
2736275976Ssmh			retval = FAIL;
2737275976Ssmh			goto out;
2738275976Ssmh		}
2739275976Ssmh		/* Now try to reset the chip */
2740275976Ssmh		for (i = 0; i < MRSAS_FUSION_MAX_RESET_TRIES; i++) {
2741275976Ssmh			mrsas_write_reg(sc, offsetof(mrsas_reg_set, fusion_seq_offset),
2742275976Ssmh			    MPI2_WRSEQ_FLUSH_KEY_VALUE);
2743275976Ssmh			mrsas_write_reg(sc, offsetof(mrsas_reg_set, fusion_seq_offset),
2744275976Ssmh			    MPI2_WRSEQ_1ST_KEY_VALUE);
2745275976Ssmh			mrsas_write_reg(sc, offsetof(mrsas_reg_set, fusion_seq_offset),
2746275976Ssmh			    MPI2_WRSEQ_2ND_KEY_VALUE);
2747275976Ssmh			mrsas_write_reg(sc, offsetof(mrsas_reg_set, fusion_seq_offset),
2748275976Ssmh			    MPI2_WRSEQ_3RD_KEY_VALUE);
2749275976Ssmh			mrsas_write_reg(sc, offsetof(mrsas_reg_set, fusion_seq_offset),
2750275976Ssmh			    MPI2_WRSEQ_4TH_KEY_VALUE);
2751275976Ssmh			mrsas_write_reg(sc, offsetof(mrsas_reg_set, fusion_seq_offset),
2752275976Ssmh			    MPI2_WRSEQ_5TH_KEY_VALUE);
2753275976Ssmh			mrsas_write_reg(sc, offsetof(mrsas_reg_set, fusion_seq_offset),
2754275976Ssmh			    MPI2_WRSEQ_6TH_KEY_VALUE);
2755265555Sambrisko
2756275976Ssmh			/* Check that the diag write enable (DRWE) bit is on */
2757275976Ssmh			host_diag = mrsas_read_reg(sc, offsetof(mrsas_reg_set,
2758275976Ssmh			    fusion_host_diag));
2759275976Ssmh			retry = 0;
2760275976Ssmh			while (!(host_diag & HOST_DIAG_WRITE_ENABLE)) {
2761275976Ssmh				DELAY(100 * 1000);
2762275976Ssmh				host_diag = mrsas_read_reg(sc, offsetof(mrsas_reg_set,
2763275976Ssmh				    fusion_host_diag));
2764275976Ssmh				if (retry++ == 100) {
2765275976Ssmh					mrsas_dprint(sc, MRSAS_OCR,
2766275976Ssmh					    "Host diag unlock failed!\n");
2767275976Ssmh					break;
2768275976Ssmh				}
2769275976Ssmh			}
2770275976Ssmh			if (!(host_diag & HOST_DIAG_WRITE_ENABLE))
2771275976Ssmh				continue;
2772265555Sambrisko
2773275976Ssmh			/* Send chip reset command */
2774275976Ssmh			mrsas_write_reg(sc, offsetof(mrsas_reg_set, fusion_host_diag),
2775275976Ssmh			    host_diag | HOST_DIAG_RESET_ADAPTER);
2776275976Ssmh			DELAY(3000 * 1000);
2777265555Sambrisko
2778275976Ssmh			/* Make sure reset adapter bit is cleared */
2779275976Ssmh			host_diag = mrsas_read_reg(sc, offsetof(mrsas_reg_set,
2780275976Ssmh			    fusion_host_diag));
2781275976Ssmh			retry = 0;
2782275976Ssmh			while (host_diag & HOST_DIAG_RESET_ADAPTER) {
2783275976Ssmh				DELAY(100 * 1000);
2784275976Ssmh				host_diag = mrsas_read_reg(sc, offsetof(mrsas_reg_set,
2785275976Ssmh				    fusion_host_diag));
2786275976Ssmh				if (retry++ == 1000) {
2787275976Ssmh					mrsas_dprint(sc, MRSAS_OCR,
2788275976Ssmh					    "Diag reset adapter never cleared!\n");
2789275976Ssmh					break;
2790275976Ssmh				}
2791275976Ssmh			}
2792275976Ssmh			if (host_diag & HOST_DIAG_RESET_ADAPTER)
2793275976Ssmh				continue;
2794265555Sambrisko
2795275976Ssmh			abs_state = mrsas_read_reg(sc, offsetof(mrsas_reg_set,
2796275976Ssmh			    outbound_scratch_pad)) & MFI_STATE_MASK;
2797275976Ssmh			retry = 0;
2798265555Sambrisko
2799275976Ssmh			while ((abs_state <= MFI_STATE_FW_INIT) && (retry++ < 1000)) {
2800275976Ssmh				DELAY(100 * 1000);
2801275976Ssmh				abs_state = mrsas_read_reg(sc, offsetof(mrsas_reg_set,
2802275976Ssmh				    outbound_scratch_pad)) & MFI_STATE_MASK;
2803275976Ssmh			}
2804275976Ssmh			if (abs_state <= MFI_STATE_FW_INIT) {
2805275976Ssmh				mrsas_dprint(sc, MRSAS_OCR, "firmware state < MFI_STATE_FW_INIT,"
2806275976Ssmh				    " state = 0x%x\n", abs_state);
2807275976Ssmh				continue;
2808275976Ssmh			}
2809275976Ssmh			/* Wait for FW to become ready */
2810275976Ssmh			if (mrsas_transition_to_ready(sc, 1)) {
2811275976Ssmh				mrsas_dprint(sc, MRSAS_OCR,
2812275976Ssmh				    "mrsas: Failed to transition controller to ready.\n");
2813275976Ssmh				continue;
2814275976Ssmh			}
2815275976Ssmh			mrsas_reset_reply_desc(sc);
2816275976Ssmh			if (mrsas_ioc_init(sc)) {
2817275976Ssmh				mrsas_dprint(sc, MRSAS_OCR, "mrsas_ioc_init() failed!\n");
2818275976Ssmh				continue;
2819275976Ssmh			}
2820275976Ssmh			/* Re-fire management commands */
2821275976Ssmh			for (j = 0; j < sc->max_fw_cmds; j++) {
2822275976Ssmh				mpt_cmd = sc->mpt_cmd_list[j];
2823275976Ssmh				if (mpt_cmd->sync_cmd_idx != (u_int32_t)MRSAS_ULONG_MAX) {
2824275976Ssmh					mfi_cmd = sc->mfi_cmd_list[mpt_cmd->sync_cmd_idx];
2825275976Ssmh					if (mfi_cmd->frame->dcmd.opcode ==
2826275976Ssmh					    MR_DCMD_LD_MAP_GET_INFO) {
2827275976Ssmh						mrsas_release_mfi_cmd(mfi_cmd);
2828275976Ssmh						mrsas_release_mpt_cmd(mpt_cmd);
2829275976Ssmh					} else {
2830275976Ssmh						req_desc = mrsas_get_request_desc(sc,
2831275976Ssmh						    mfi_cmd->cmd_id.context.smid - 1);
2832275976Ssmh						mrsas_dprint(sc, MRSAS_OCR,
2833275976Ssmh						    "Re-fire command DCMD opcode 0x%x index %d\n ",
2834275976Ssmh						    mfi_cmd->frame->dcmd.opcode, j);
2835275976Ssmh						if (!req_desc)
2836275976Ssmh							device_printf(sc->mrsas_dev,
2837275976Ssmh							    "Cannot build MPT cmd.\n");
2838275976Ssmh						else
2839275976Ssmh							mrsas_fire_cmd(sc, req_desc->addr.u.low,
2840275976Ssmh							    req_desc->addr.u.high);
2841275976Ssmh					}
2842275976Ssmh				}
2843275976Ssmh			}
2844265555Sambrisko
2845275976Ssmh			/* Reset load balance info */
2846275976Ssmh			memset(sc->load_balance_info, 0,
2847275976Ssmh			    sizeof(LD_LOAD_BALANCE_INFO) * MAX_LOGICAL_DRIVES_EXT);
2848265555Sambrisko
2849284267Skadesai			if (mrsas_get_ctrl_info(sc)) {
2850284267Skadesai				mrsas_kill_hba(sc);
2851284267Skadesai				retval = FAIL;
2852284267Skadesai				goto out;
2853284267Skadesai			}
2854275976Ssmh			if (!mrsas_get_map_info(sc))
2855275976Ssmh				mrsas_sync_map_info(sc);
2856265555Sambrisko
2857284267Skadesai			mrsas_clear_bit(MRSAS_FUSION_IN_RESET, &sc->reset_flags);
2858284267Skadesai			mrsas_enable_intr(sc);
2859284267Skadesai			sc->adprecovery = MRSAS_HBA_OPERATIONAL;
2860284267Skadesai
2861275976Ssmh			/* Adapter reset completed successfully */
2862275976Ssmh			device_printf(sc->mrsas_dev, "Reset successful\n");
2863275976Ssmh			retval = SUCCESS;
2864275976Ssmh			goto out;
2865275976Ssmh		}
2866275976Ssmh		/* Reset failed, kill the adapter */
2867275976Ssmh		device_printf(sc->mrsas_dev, "Reset failed, killing adapter.\n");
2868275976Ssmh		mrsas_kill_hba(sc);
2869275976Ssmh		retval = FAIL;
2870275976Ssmh	} else {
2871275976Ssmh		mrsas_clear_bit(MRSAS_FUSION_IN_RESET, &sc->reset_flags);
2872275976Ssmh		mrsas_enable_intr(sc);
2873275976Ssmh		sc->adprecovery = MRSAS_HBA_OPERATIONAL;
2874275976Ssmh	}
2875265555Sambriskoout:
2876275976Ssmh	mrsas_clear_bit(MRSAS_FUSION_IN_RESET, &sc->reset_flags);
2877275976Ssmh	mrsas_dprint(sc, MRSAS_OCR,
2878275976Ssmh	    "Reset Exit with %d.\n", retval);
2879275976Ssmh	return retval;
2880265555Sambrisko}
2881265555Sambrisko
2882275976Ssmh/*
2883275976Ssmh * mrsas_kill_hba:	Kill HBA when OCR is not supported
2884275976Ssmh * input:			Adapter Context.
2885265555Sambrisko *
2886265555Sambrisko * This function will kill HBA when OCR is not supported.
2887265555Sambrisko */
2888275976Ssmhvoid
2889275976Ssmhmrsas_kill_hba(struct mrsas_softc *sc)
2890265555Sambrisko{
2891284267Skadesai	sc->adprecovery = MRSAS_HW_CRITICAL_ERROR;
2892284267Skadesai	pause("mrsas_kill_hba", 1000);
2893275976Ssmh	mrsas_dprint(sc, MRSAS_OCR, "%s\n", __func__);
2894275976Ssmh	mrsas_write_reg(sc, offsetof(mrsas_reg_set, doorbell),
2895275976Ssmh	    MFI_STOP_ADP);
2896275976Ssmh	/* Flush */
2897275976Ssmh	mrsas_read_reg(sc, offsetof(mrsas_reg_set, doorbell));
2898284267Skadesai	mrsas_complete_outstanding_ioctls(sc);
2899265555Sambrisko}
2900265555Sambrisko
2901284267Skadesai/**
2902284267Skadesai * mrsas_complete_outstanding_ioctls	Complete pending IOCTLS after kill_hba
2903284267Skadesai * input:			Controller softc
2904284267Skadesai *
2905284267Skadesai * Returns void
2906284267Skadesai */
2907284267Skadesaivoid
2908284267Skadesaimrsas_complete_outstanding_ioctls(struct mrsas_softc *sc)
2909284267Skadesai{
2910284267Skadesai	int i;
2911284267Skadesai	struct mrsas_mpt_cmd *cmd_mpt;
2912284267Skadesai	struct mrsas_mfi_cmd *cmd_mfi;
2913284267Skadesai	u_int32_t count, MSIxIndex;
2914284267Skadesai
2915284267Skadesai	count = sc->msix_vectors > 0 ? sc->msix_vectors : 1;
2916284267Skadesai	for (i = 0; i < sc->max_fw_cmds; i++) {
2917284267Skadesai		cmd_mpt = sc->mpt_cmd_list[i];
2918284267Skadesai
2919284267Skadesai		if (cmd_mpt->sync_cmd_idx != (u_int32_t)MRSAS_ULONG_MAX) {
2920284267Skadesai			cmd_mfi = sc->mfi_cmd_list[cmd_mpt->sync_cmd_idx];
2921284267Skadesai			if (cmd_mfi->sync_cmd && cmd_mfi->frame->hdr.cmd != MFI_CMD_ABORT) {
2922284267Skadesai				for (MSIxIndex = 0; MSIxIndex < count; MSIxIndex++)
2923284267Skadesai					mrsas_complete_mptmfi_passthru(sc, cmd_mfi,
2924284267Skadesai					    cmd_mpt->io_request->RaidContext.status);
2925284267Skadesai			}
2926284267Skadesai		}
2927284267Skadesai	}
2928284267Skadesai}
2929284267Skadesai
2930275976Ssmh/*
2931275976Ssmh * mrsas_wait_for_outstanding:	Wait for outstanding commands
2932275976Ssmh * input:						Adapter Context.
2933265555Sambrisko *
2934275976Ssmh * This function will wait for 180 seconds for outstanding commands to be
2935275976Ssmh * completed.
2936265555Sambrisko */
2937275976Ssmhint
2938275976Ssmhmrsas_wait_for_outstanding(struct mrsas_softc *sc)
2939265555Sambrisko{
2940275976Ssmh	int i, outstanding, retval = 0;
2941275976Ssmh	u_int32_t fw_state, count, MSIxIndex;
2942265555Sambrisko
2943265555Sambrisko
2944275976Ssmh	for (i = 0; i < MRSAS_RESET_WAIT_TIME; i++) {
2945275976Ssmh		if (sc->remove_in_progress) {
2946275976Ssmh			mrsas_dprint(sc, MRSAS_OCR,
2947275976Ssmh			    "Driver remove or shutdown called.\n");
2948275976Ssmh			retval = 1;
2949275976Ssmh			goto out;
2950275976Ssmh		}
2951275976Ssmh		/* Check if firmware is in fault state */
2952275976Ssmh		fw_state = mrsas_read_reg(sc, offsetof(mrsas_reg_set,
2953275976Ssmh		    outbound_scratch_pad)) & MFI_STATE_MASK;
2954275976Ssmh		if (fw_state == MFI_STATE_FAULT) {
2955275976Ssmh			mrsas_dprint(sc, MRSAS_OCR,
2956275976Ssmh			    "Found FW in FAULT state, will reset adapter.\n");
2957275976Ssmh			retval = 1;
2958275976Ssmh			goto out;
2959275976Ssmh		}
2960275976Ssmh		outstanding = mrsas_atomic_read(&sc->fw_outstanding);
2961275976Ssmh		if (!outstanding)
2962275976Ssmh			goto out;
2963265555Sambrisko
2964275976Ssmh		if (!(i % MRSAS_RESET_NOTICE_INTERVAL)) {
2965275976Ssmh			mrsas_dprint(sc, MRSAS_OCR, "[%2d]waiting for %d "
2966275976Ssmh			    "commands to complete\n", i, outstanding);
2967275976Ssmh			count = sc->msix_vectors > 0 ? sc->msix_vectors : 1;
2968275976Ssmh			for (MSIxIndex = 0; MSIxIndex < count; MSIxIndex++)
2969275976Ssmh				mrsas_complete_cmd(sc, MSIxIndex);
2970275976Ssmh		}
2971275976Ssmh		DELAY(1000 * 1000);
2972275976Ssmh	}
2973275976Ssmh
2974275976Ssmh	if (mrsas_atomic_read(&sc->fw_outstanding)) {
2975275976Ssmh		mrsas_dprint(sc, MRSAS_OCR,
2976275976Ssmh		    " pending commands remain after waiting,"
2977275976Ssmh		    " will reset adapter.\n");
2978275976Ssmh		retval = 1;
2979275976Ssmh	}
2980265555Sambriskoout:
2981275976Ssmh	return retval;
2982265555Sambrisko}
2983265555Sambrisko
2984275976Ssmh/*
2985275976Ssmh * mrsas_release_mfi_cmd:	Return a cmd to free command pool
2986275976Ssmh * input:					Command packet for return to free cmd pool
2987265555Sambrisko *
2988265555Sambrisko * This function returns the MFI command to the command list.
2989265555Sambrisko */
2990275976Ssmhvoid
2991275976Ssmhmrsas_release_mfi_cmd(struct mrsas_mfi_cmd *cmd)
2992265555Sambrisko{
2993275976Ssmh	struct mrsas_softc *sc = cmd->sc;
2994265555Sambrisko
2995275976Ssmh	mtx_lock(&sc->mfi_cmd_pool_lock);
2996275976Ssmh	cmd->ccb_ptr = NULL;
2997265555Sambrisko	cmd->cmd_id.frame_count = 0;
2998275976Ssmh	TAILQ_INSERT_TAIL(&(sc->mrsas_mfi_cmd_list_head), cmd, next);
2999275976Ssmh	mtx_unlock(&sc->mfi_cmd_pool_lock);
3000265555Sambrisko
3001275976Ssmh	return;
3002265555Sambrisko}
3003265555Sambrisko
3004275976Ssmh/*
3005275976Ssmh * mrsas_get_controller_info:	Returns FW's controller structure
3006275976Ssmh * input:						Adapter soft state
3007275976Ssmh * 								Controller information structure
3008265555Sambrisko *
3009275976Ssmh * Issues an internal command (DCMD) to get the FW's controller structure. This
3010275976Ssmh * information is mainly used to find out the maximum IO transfer per command
3011275976Ssmh * supported by the FW.
3012265555Sambrisko */
3013275976Ssmhstatic int
3014284267Skadesaimrsas_get_ctrl_info(struct mrsas_softc *sc)
3015265555Sambrisko{
3016275976Ssmh	int retcode = 0;
3017275976Ssmh	struct mrsas_mfi_cmd *cmd;
3018275976Ssmh	struct mrsas_dcmd_frame *dcmd;
3019265555Sambrisko
3020275976Ssmh	cmd = mrsas_get_mfi_cmd(sc);
3021265555Sambrisko
3022275976Ssmh	if (!cmd) {
3023275976Ssmh		device_printf(sc->mrsas_dev, "Failed to get a free cmd\n");
3024275976Ssmh		return -ENOMEM;
3025275976Ssmh	}
3026275976Ssmh	dcmd = &cmd->frame->dcmd;
3027265555Sambrisko
3028275976Ssmh	if (mrsas_alloc_ctlr_info_cmd(sc) != SUCCESS) {
3029275976Ssmh		device_printf(sc->mrsas_dev, "Cannot allocate get ctlr info cmd\n");
3030275976Ssmh		mrsas_release_mfi_cmd(cmd);
3031275976Ssmh		return -ENOMEM;
3032275976Ssmh	}
3033275976Ssmh	memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
3034265555Sambrisko
3035275976Ssmh	dcmd->cmd = MFI_CMD_DCMD;
3036275976Ssmh	dcmd->cmd_status = 0xFF;
3037275976Ssmh	dcmd->sge_count = 1;
3038275976Ssmh	dcmd->flags = MFI_FRAME_DIR_READ;
3039275976Ssmh	dcmd->timeout = 0;
3040275976Ssmh	dcmd->pad_0 = 0;
3041275976Ssmh	dcmd->data_xfer_len = sizeof(struct mrsas_ctrl_info);
3042275976Ssmh	dcmd->opcode = MR_DCMD_CTRL_GET_INFO;
3043275976Ssmh	dcmd->sgl.sge32[0].phys_addr = sc->ctlr_info_phys_addr;
3044275976Ssmh	dcmd->sgl.sge32[0].length = sizeof(struct mrsas_ctrl_info);
3045265555Sambrisko
3046275976Ssmh	if (!mrsas_issue_polled(sc, cmd))
3047284267Skadesai		memcpy(sc->ctrl_info, sc->ctlr_info_mem, sizeof(struct mrsas_ctrl_info));
3048275976Ssmh	else
3049275976Ssmh		retcode = 1;
3050265555Sambrisko
3051284267Skadesai	mrsas_update_ext_vd_details(sc);
3052284267Skadesai
3053275976Ssmh	mrsas_free_ctlr_info_cmd(sc);
3054275976Ssmh	mrsas_release_mfi_cmd(cmd);
3055275976Ssmh	return (retcode);
3056265555Sambrisko}
3057265555Sambrisko
3058275976Ssmh/*
3059284267Skadesai * mrsas_update_ext_vd_details : Update details w.r.t Extended VD
3060284267Skadesai * input:
3061284267Skadesai *	sc - Controller's softc
3062284267Skadesai*/
3063284267Skadesaistatic void
3064284267Skadesaimrsas_update_ext_vd_details(struct mrsas_softc *sc)
3065284267Skadesai{
3066284267Skadesai	sc->max256vdSupport =
3067284267Skadesai	sc->ctrl_info->adapterOperations3.supportMaxExtLDs;
3068284267Skadesai	/* Below is additional check to address future FW enhancement */
3069284267Skadesai	if (sc->ctrl_info->max_lds > 64)
3070284267Skadesai		sc->max256vdSupport = 1;
3071284267Skadesai
3072284267Skadesai	sc->drv_supported_vd_count = MRSAS_MAX_LD_CHANNELS
3073284267Skadesai	    * MRSAS_MAX_DEV_PER_CHANNEL;
3074284267Skadesai	sc->drv_supported_pd_count = MRSAS_MAX_PD_CHANNELS
3075284267Skadesai	    * MRSAS_MAX_DEV_PER_CHANNEL;
3076284267Skadesai	if (sc->max256vdSupport) {
3077284267Skadesai		sc->fw_supported_vd_count = MAX_LOGICAL_DRIVES_EXT;
3078284267Skadesai		sc->fw_supported_pd_count = MAX_PHYSICAL_DEVICES;
3079284267Skadesai	} else {
3080284267Skadesai		sc->fw_supported_vd_count = MAX_LOGICAL_DRIVES;
3081284267Skadesai		sc->fw_supported_pd_count = MAX_PHYSICAL_DEVICES;
3082284267Skadesai	}
3083284267Skadesai
3084284267Skadesai	sc->old_map_sz = sizeof(MR_FW_RAID_MAP) +
3085284267Skadesai	    (sizeof(MR_LD_SPAN_MAP) *
3086284267Skadesai	    (sc->fw_supported_vd_count - 1));
3087284267Skadesai	sc->new_map_sz = sizeof(MR_FW_RAID_MAP_EXT);
3088284267Skadesai	sc->drv_map_sz = sizeof(MR_DRV_RAID_MAP) +
3089284267Skadesai	    (sizeof(MR_LD_SPAN_MAP) *
3090284267Skadesai	    (sc->drv_supported_vd_count - 1));
3091284267Skadesai
3092284267Skadesai	sc->max_map_sz = max(sc->old_map_sz, sc->new_map_sz);
3093284267Skadesai
3094284267Skadesai	if (sc->max256vdSupport)
3095284267Skadesai		sc->current_map_sz = sc->new_map_sz;
3096284267Skadesai	else
3097284267Skadesai		sc->current_map_sz = sc->old_map_sz;
3098284267Skadesai}
3099284267Skadesai
3100284267Skadesai/*
3101275976Ssmh * mrsas_alloc_ctlr_info_cmd:	Allocates memory for controller info command
3102275976Ssmh * input:						Adapter soft state
3103265555Sambrisko *
3104265555Sambrisko * Allocates DMAable memory for the controller info internal command.
3105265555Sambrisko */
3106275976Ssmhint
3107275976Ssmhmrsas_alloc_ctlr_info_cmd(struct mrsas_softc *sc)
3108265555Sambrisko{
3109275976Ssmh	int ctlr_info_size;
3110265555Sambrisko
3111275976Ssmh	/* Allocate get controller info command */
3112275976Ssmh	ctlr_info_size = sizeof(struct mrsas_ctrl_info);
3113275976Ssmh	if (bus_dma_tag_create(sc->mrsas_parent_tag,
3114275976Ssmh	    1, 0,
3115275976Ssmh	    BUS_SPACE_MAXADDR_32BIT,
3116275976Ssmh	    BUS_SPACE_MAXADDR,
3117275976Ssmh	    NULL, NULL,
3118275976Ssmh	    ctlr_info_size,
3119275976Ssmh	    1,
3120275976Ssmh	    ctlr_info_size,
3121275976Ssmh	    BUS_DMA_ALLOCNOW,
3122275976Ssmh	    NULL, NULL,
3123275976Ssmh	    &sc->ctlr_info_tag)) {
3124275976Ssmh		device_printf(sc->mrsas_dev, "Cannot allocate ctlr info tag\n");
3125275976Ssmh		return (ENOMEM);
3126275976Ssmh	}
3127275976Ssmh	if (bus_dmamem_alloc(sc->ctlr_info_tag, (void **)&sc->ctlr_info_mem,
3128275976Ssmh	    BUS_DMA_NOWAIT, &sc->ctlr_info_dmamap)) {
3129275976Ssmh		device_printf(sc->mrsas_dev, "Cannot allocate ctlr info cmd mem\n");
3130275976Ssmh		return (ENOMEM);
3131275976Ssmh	}
3132275976Ssmh	if (bus_dmamap_load(sc->ctlr_info_tag, sc->ctlr_info_dmamap,
3133275976Ssmh	    sc->ctlr_info_mem, ctlr_info_size, mrsas_addr_cb,
3134275976Ssmh	    &sc->ctlr_info_phys_addr, BUS_DMA_NOWAIT)) {
3135275976Ssmh		device_printf(sc->mrsas_dev, "Cannot load ctlr info cmd mem\n");
3136275976Ssmh		return (ENOMEM);
3137275976Ssmh	}
3138275976Ssmh	memset(sc->ctlr_info_mem, 0, ctlr_info_size);
3139275976Ssmh	return (0);
3140265555Sambrisko}
3141265555Sambrisko
3142275976Ssmh/*
3143275976Ssmh * mrsas_free_ctlr_info_cmd:	Free memory for controller info command
3144275976Ssmh * input:						Adapter soft state
3145265555Sambrisko *
3146265555Sambrisko * Deallocates memory of the get controller info cmd.
3147265555Sambrisko */
3148275976Ssmhvoid
3149275976Ssmhmrsas_free_ctlr_info_cmd(struct mrsas_softc *sc)
3150265555Sambrisko{
3151275976Ssmh	if (sc->ctlr_info_phys_addr)
3152275976Ssmh		bus_dmamap_unload(sc->ctlr_info_tag, sc->ctlr_info_dmamap);
3153275976Ssmh	if (sc->ctlr_info_mem != NULL)
3154275976Ssmh		bus_dmamem_free(sc->ctlr_info_tag, sc->ctlr_info_mem, sc->ctlr_info_dmamap);
3155275976Ssmh	if (sc->ctlr_info_tag != NULL)
3156275976Ssmh		bus_dma_tag_destroy(sc->ctlr_info_tag);
3157265555Sambrisko}
3158265555Sambrisko
3159275976Ssmh/*
3160275976Ssmh * mrsas_issue_polled:	Issues a polling command
3161275976Ssmh * inputs:				Adapter soft state
3162275976Ssmh * 						Command packet to be issued
3163265555Sambrisko *
3164275976Ssmh * This function is for posting of internal commands to Firmware.  MFI requires
3165275976Ssmh * the cmd_status to be set to 0xFF before posting.  The maximun wait time of
3166275976Ssmh * the poll response timer is 180 seconds.
3167265555Sambrisko */
3168275976Ssmhint
3169275976Ssmhmrsas_issue_polled(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd)
3170265555Sambrisko{
3171275976Ssmh	struct mrsas_header *frame_hdr = &cmd->frame->hdr;
3172275976Ssmh	u_int8_t max_wait = MRSAS_INTERNAL_CMD_WAIT_TIME;
3173275976Ssmh	int i, retcode = 0;
3174265555Sambrisko
3175275976Ssmh	frame_hdr->cmd_status = 0xFF;
3176275976Ssmh	frame_hdr->flags |= MFI_FRAME_DONT_POST_IN_REPLY_QUEUE;
3177265555Sambrisko
3178275976Ssmh	/* Issue the frame using inbound queue port */
3179275976Ssmh	if (mrsas_issue_dcmd(sc, cmd)) {
3180275976Ssmh		device_printf(sc->mrsas_dev, "Cannot issue DCMD internal command.\n");
3181275976Ssmh		return (1);
3182275976Ssmh	}
3183275976Ssmh	/*
3184275976Ssmh	 * Poll response timer to wait for Firmware response.  While this
3185275976Ssmh	 * timer with the DELAY call could block CPU, the time interval for
3186275976Ssmh	 * this is only 1 millisecond.
3187275976Ssmh	 */
3188275976Ssmh	if (frame_hdr->cmd_status == 0xFF) {
3189275976Ssmh		for (i = 0; i < (max_wait * 1000); i++) {
3190275976Ssmh			if (frame_hdr->cmd_status == 0xFF)
3191275976Ssmh				DELAY(1000);
3192275976Ssmh			else
3193275976Ssmh				break;
3194275976Ssmh		}
3195275976Ssmh	}
3196275976Ssmh	if (frame_hdr->cmd_status != 0) {
3197275976Ssmh		if (frame_hdr->cmd_status == 0xFF)
3198275976Ssmh			device_printf(sc->mrsas_dev, "DCMD timed out after %d seconds.\n", max_wait);
3199275976Ssmh		else
3200275976Ssmh			device_printf(sc->mrsas_dev, "DCMD failed, status = 0x%x\n", frame_hdr->cmd_status);
3201275976Ssmh		retcode = 1;
3202275976Ssmh	}
3203275976Ssmh	return (retcode);
3204265555Sambrisko}
3205265555Sambrisko
3206275976Ssmh/*
3207275976Ssmh * mrsas_issue_dcmd:	Issues a MFI Pass thru cmd
3208275976Ssmh * input:				Adapter soft state mfi cmd pointer
3209265555Sambrisko *
3210265555Sambrisko * This function is called by mrsas_issued_blocked_cmd() and
3211275976Ssmh * mrsas_issued_polled(), to build the MPT command and then fire the command
3212275976Ssmh * to Firmware.
3213265555Sambrisko */
3214265555Sambriskoint
3215265555Sambriskomrsas_issue_dcmd(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd)
3216265555Sambrisko{
3217275976Ssmh	MRSAS_REQUEST_DESCRIPTOR_UNION *req_desc;
3218265555Sambrisko
3219275976Ssmh	req_desc = mrsas_build_mpt_cmd(sc, cmd);
3220275976Ssmh	if (!req_desc) {
3221275976Ssmh		device_printf(sc->mrsas_dev, "Cannot build MPT cmd.\n");
3222275976Ssmh		return (1);
3223275976Ssmh	}
3224275976Ssmh	mrsas_fire_cmd(sc, req_desc->addr.u.low, req_desc->addr.u.high);
3225265555Sambrisko
3226275976Ssmh	return (0);
3227265555Sambrisko}
3228265555Sambrisko
3229275976Ssmh/*
3230275976Ssmh * mrsas_build_mpt_cmd:	Calls helper function to build Passthru cmd
3231275976Ssmh * input:				Adapter soft state mfi cmd to build
3232265555Sambrisko *
3233275976Ssmh * This function is called by mrsas_issue_cmd() to build the MPT-MFI passthru
3234275976Ssmh * command and prepares the MPT command to send to Firmware.
3235265555Sambrisko */
3236265555SambriskoMRSAS_REQUEST_DESCRIPTOR_UNION *
3237265555Sambriskomrsas_build_mpt_cmd(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd)
3238265555Sambrisko{
3239275976Ssmh	MRSAS_REQUEST_DESCRIPTOR_UNION *req_desc;
3240275976Ssmh	u_int16_t index;
3241265555Sambrisko
3242275976Ssmh	if (mrsas_build_mptmfi_passthru(sc, cmd)) {
3243275976Ssmh		device_printf(sc->mrsas_dev, "Cannot build MPT-MFI passthru cmd.\n");
3244275976Ssmh		return NULL;
3245275976Ssmh	}
3246275976Ssmh	index = cmd->cmd_id.context.smid;
3247265555Sambrisko
3248275976Ssmh	req_desc = mrsas_get_request_desc(sc, index - 1);
3249275976Ssmh	if (!req_desc)
3250275976Ssmh		return NULL;
3251265555Sambrisko
3252275976Ssmh	req_desc->addr.Words = 0;
3253275976Ssmh	req_desc->SCSIIO.RequestFlags = (MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO << MRSAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
3254265555Sambrisko
3255275976Ssmh	req_desc->SCSIIO.SMID = index;
3256265555Sambrisko
3257275976Ssmh	return (req_desc);
3258265555Sambrisko}
3259265555Sambrisko
3260275976Ssmh/*
3261275976Ssmh * mrsas_build_mptmfi_passthru:	Builds a MPT MFI Passthru command
3262275976Ssmh * input:						Adapter soft state mfi cmd pointer
3263265555Sambrisko *
3264275976Ssmh * The MPT command and the io_request are setup as a passthru command. The SGE
3265275976Ssmh * chain address is set to frame_phys_addr of the MFI command.
3266265555Sambrisko */
3267265555Sambriskou_int8_t
3268265555Sambriskomrsas_build_mptmfi_passthru(struct mrsas_softc *sc, struct mrsas_mfi_cmd *mfi_cmd)
3269265555Sambrisko{
3270275976Ssmh	MPI25_IEEE_SGE_CHAIN64 *mpi25_ieee_chain;
3271275976Ssmh	PTR_MRSAS_RAID_SCSI_IO_REQUEST io_req;
3272275976Ssmh	struct mrsas_mpt_cmd *mpt_cmd;
3273275976Ssmh	struct mrsas_header *frame_hdr = &mfi_cmd->frame->hdr;
3274265555Sambrisko
3275275976Ssmh	mpt_cmd = mrsas_get_mpt_cmd(sc);
3276275976Ssmh	if (!mpt_cmd)
3277275976Ssmh		return (1);
3278265555Sambrisko
3279275976Ssmh	/* Save the smid. To be used for returning the cmd */
3280275976Ssmh	mfi_cmd->cmd_id.context.smid = mpt_cmd->index;
3281265555Sambrisko
3282275976Ssmh	mpt_cmd->sync_cmd_idx = mfi_cmd->index;
3283265555Sambrisko
3284275976Ssmh	/*
3285275976Ssmh	 * For cmds where the flag is set, store the flag and check on
3286275976Ssmh	 * completion. For cmds with this flag, don't call
3287275976Ssmh	 * mrsas_complete_cmd.
3288275976Ssmh	 */
3289265555Sambrisko
3290275976Ssmh	if (frame_hdr->flags & MFI_FRAME_DONT_POST_IN_REPLY_QUEUE)
3291275976Ssmh		mpt_cmd->flags = MFI_FRAME_DONT_POST_IN_REPLY_QUEUE;
3292265555Sambrisko
3293275976Ssmh	io_req = mpt_cmd->io_request;
3294265555Sambrisko
3295275976Ssmh	if ((sc->device_id == MRSAS_INVADER) || (sc->device_id == MRSAS_FURY)) {
3296275976Ssmh		pMpi25IeeeSgeChain64_t sgl_ptr_end = (pMpi25IeeeSgeChain64_t)&io_req->SGL;
3297265555Sambrisko
3298275976Ssmh		sgl_ptr_end += sc->max_sge_in_main_msg - 1;
3299275976Ssmh		sgl_ptr_end->Flags = 0;
3300275976Ssmh	}
3301275976Ssmh	mpi25_ieee_chain = (MPI25_IEEE_SGE_CHAIN64 *) & io_req->SGL.IeeeChain;
3302265555Sambrisko
3303275976Ssmh	io_req->Function = MRSAS_MPI2_FUNCTION_PASSTHRU_IO_REQUEST;
3304275976Ssmh	io_req->SGLOffset0 = offsetof(MRSAS_RAID_SCSI_IO_REQUEST, SGL) / 4;
3305275976Ssmh	io_req->ChainOffset = sc->chain_offset_mfi_pthru;
3306265555Sambrisko
3307275976Ssmh	mpi25_ieee_chain->Address = mfi_cmd->frame_phys_addr;
3308265555Sambrisko
3309275976Ssmh	mpi25_ieee_chain->Flags = IEEE_SGE_FLAGS_CHAIN_ELEMENT |
3310275976Ssmh	    MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR;
3311265555Sambrisko
3312275976Ssmh	mpi25_ieee_chain->Length = MRSAS_MAX_SZ_CHAIN_FRAME;
3313265555Sambrisko
3314275976Ssmh	return (0);
3315265555Sambrisko}
3316265555Sambrisko
3317275976Ssmh/*
3318275976Ssmh * mrsas_issue_blocked_cmd:	Synchronous wrapper around regular FW cmds
3319275976Ssmh * input:					Adapter soft state Command to be issued
3320265555Sambrisko *
3321275976Ssmh * This function waits on an event for the command to be returned from the ISR.
3322275976Ssmh * Max wait time is MRSAS_INTERNAL_CMD_WAIT_TIME secs. Used for issuing
3323275976Ssmh * internal and ioctl commands.
3324265555Sambrisko */
3325275976Ssmhint
3326275976Ssmhmrsas_issue_blocked_cmd(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd)
3327265555Sambrisko{
3328275976Ssmh	u_int8_t max_wait = MRSAS_INTERNAL_CMD_WAIT_TIME;
3329275976Ssmh	unsigned long total_time = 0;
3330275976Ssmh	int retcode = 0;
3331265555Sambrisko
3332275976Ssmh	/* Initialize cmd_status */
3333275976Ssmh	cmd->cmd_status = ECONNREFUSED;
3334265555Sambrisko
3335275976Ssmh	/* Build MPT-MFI command for issue to FW */
3336275976Ssmh	if (mrsas_issue_dcmd(sc, cmd)) {
3337275976Ssmh		device_printf(sc->mrsas_dev, "Cannot issue DCMD internal command.\n");
3338275976Ssmh		return (1);
3339275976Ssmh	}
3340275976Ssmh	sc->chan = (void *)&cmd;
3341265555Sambrisko
3342275976Ssmh	while (1) {
3343275976Ssmh		if (cmd->cmd_status == ECONNREFUSED) {
3344275976Ssmh			tsleep((void *)&sc->chan, 0, "mrsas_sleep", hz);
3345275976Ssmh		} else
3346275976Ssmh			break;
3347275976Ssmh		total_time++;
3348275976Ssmh		if (total_time >= max_wait) {
3349275976Ssmh			device_printf(sc->mrsas_dev,
3350275976Ssmh			    "Internal command timed out after %d seconds.\n", max_wait);
3351275976Ssmh			retcode = 1;
3352275976Ssmh			break;
3353275976Ssmh		}
3354275976Ssmh	}
3355275976Ssmh	return (retcode);
3356265555Sambrisko}
3357265555Sambrisko
3358275976Ssmh/*
3359275976Ssmh * mrsas_complete_mptmfi_passthru:	Completes a command
3360275976Ssmh * input:	@sc:					Adapter soft state
3361275976Ssmh * 			@cmd:					Command to be completed
3362275976Ssmh * 			@status:				cmd completion status
3363265555Sambrisko *
3364275976Ssmh * This function is called from mrsas_complete_cmd() after an interrupt is
3365275976Ssmh * received from Firmware, and io_request->Function is
3366265555Sambrisko * MRSAS_MPI2_FUNCTION_PASSTHRU_IO_REQUEST.
3367265555Sambrisko */
3368265555Sambriskovoid
3369265555Sambriskomrsas_complete_mptmfi_passthru(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd,
3370275976Ssmh    u_int8_t status)
3371265555Sambrisko{
3372275976Ssmh	struct mrsas_header *hdr = &cmd->frame->hdr;
3373275976Ssmh	u_int8_t cmd_status = cmd->frame->hdr.cmd_status;
3374265555Sambrisko
3375275976Ssmh	/* Reset the retry counter for future re-tries */
3376275976Ssmh	cmd->retry_for_fw_reset = 0;
3377265555Sambrisko
3378275976Ssmh	if (cmd->ccb_ptr)
3379275976Ssmh		cmd->ccb_ptr = NULL;
3380265555Sambrisko
3381275976Ssmh	switch (hdr->cmd) {
3382275976Ssmh	case MFI_CMD_INVALID:
3383275976Ssmh		device_printf(sc->mrsas_dev, "MFI_CMD_INVALID command.\n");
3384275976Ssmh		break;
3385275976Ssmh	case MFI_CMD_PD_SCSI_IO:
3386275976Ssmh	case MFI_CMD_LD_SCSI_IO:
3387275976Ssmh		/*
3388275976Ssmh		 * MFI_CMD_PD_SCSI_IO and MFI_CMD_LD_SCSI_IO could have been
3389275976Ssmh		 * issued either through an IO path or an IOCTL path. If it
3390275976Ssmh		 * was via IOCTL, we will send it to internal completion.
3391275976Ssmh		 */
3392275976Ssmh		if (cmd->sync_cmd) {
3393275976Ssmh			cmd->sync_cmd = 0;
3394275976Ssmh			mrsas_wakeup(sc, cmd);
3395275976Ssmh			break;
3396275976Ssmh		}
3397275976Ssmh	case MFI_CMD_SMP:
3398275976Ssmh	case MFI_CMD_STP:
3399275976Ssmh	case MFI_CMD_DCMD:
3400275976Ssmh		/* Check for LD map update */
3401275976Ssmh		if ((cmd->frame->dcmd.opcode == MR_DCMD_LD_MAP_GET_INFO) &&
3402275976Ssmh		    (cmd->frame->dcmd.mbox.b[1] == 1)) {
3403275976Ssmh			sc->fast_path_io = 0;
3404275976Ssmh			mtx_lock(&sc->raidmap_lock);
3405275976Ssmh			if (cmd_status != 0) {
3406275976Ssmh				if (cmd_status != MFI_STAT_NOT_FOUND)
3407275976Ssmh					device_printf(sc->mrsas_dev, "map sync failed, status=%x\n", cmd_status);
3408275976Ssmh				else {
3409275976Ssmh					mrsas_release_mfi_cmd(cmd);
3410275976Ssmh					mtx_unlock(&sc->raidmap_lock);
3411275976Ssmh					break;
3412275976Ssmh				}
3413275976Ssmh			} else
3414275976Ssmh				sc->map_id++;
3415275976Ssmh			mrsas_release_mfi_cmd(cmd);
3416275976Ssmh			if (MR_ValidateMapInfo(sc))
3417275976Ssmh				sc->fast_path_io = 0;
3418275976Ssmh			else
3419275976Ssmh				sc->fast_path_io = 1;
3420275976Ssmh			mrsas_sync_map_info(sc);
3421275976Ssmh			mtx_unlock(&sc->raidmap_lock);
3422275976Ssmh			break;
3423275976Ssmh		}
3424275976Ssmh		if (cmd->frame->dcmd.opcode == MR_DCMD_CTRL_EVENT_GET_INFO ||
3425275976Ssmh		    cmd->frame->dcmd.opcode == MR_DCMD_CTRL_EVENT_GET) {
3426275976Ssmh			sc->mrsas_aen_triggered = 0;
3427275976Ssmh		}
3428275976Ssmh		/* See if got an event notification */
3429275976Ssmh		if (cmd->frame->dcmd.opcode == MR_DCMD_CTRL_EVENT_WAIT)
3430275976Ssmh			mrsas_complete_aen(sc, cmd);
3431275976Ssmh		else
3432275976Ssmh			mrsas_wakeup(sc, cmd);
3433275976Ssmh		break;
3434275976Ssmh	case MFI_CMD_ABORT:
3435275976Ssmh		/* Command issued to abort another cmd return */
3436275976Ssmh		mrsas_complete_abort(sc, cmd);
3437275976Ssmh		break;
3438275976Ssmh	default:
3439275976Ssmh		device_printf(sc->mrsas_dev, "Unknown command completed! [0x%X]\n", hdr->cmd);
3440275976Ssmh		break;
3441275976Ssmh	}
3442265555Sambrisko}
3443265555Sambrisko
3444275976Ssmh/*
3445275976Ssmh * mrsas_wakeup:	Completes an internal command
3446275976Ssmh * input:			Adapter soft state
3447275976Ssmh * 					Command to be completed
3448265555Sambrisko *
3449275976Ssmh * In mrsas_issue_blocked_cmd(), after a command is issued to Firmware, a wait
3450275976Ssmh * timer is started.  This function is called from
3451275976Ssmh * mrsas_complete_mptmfi_passthru() as it completes the command, to wake up
3452275976Ssmh * from the command wait.
3453265555Sambrisko */
3454275976Ssmhvoid
3455275976Ssmhmrsas_wakeup(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd)
3456265555Sambrisko{
3457275976Ssmh	cmd->cmd_status = cmd->frame->io.cmd_status;
3458265555Sambrisko
3459275976Ssmh	if (cmd->cmd_status == ECONNREFUSED)
3460275976Ssmh		cmd->cmd_status = 0;
3461265555Sambrisko
3462275976Ssmh	sc->chan = (void *)&cmd;
3463275976Ssmh	wakeup_one((void *)&sc->chan);
3464275976Ssmh	return;
3465265555Sambrisko}
3466265555Sambrisko
3467275976Ssmh/*
3468275976Ssmh * mrsas_shutdown_ctlr:       Instructs FW to shutdown the controller input:
3469275976Ssmh * Adapter soft state Shutdown/Hibernate
3470265555Sambrisko *
3471275976Ssmh * This function issues a DCMD internal command to Firmware to initiate shutdown
3472275976Ssmh * of the controller.
3473265555Sambrisko */
3474275976Ssmhstatic void
3475275976Ssmhmrsas_shutdown_ctlr(struct mrsas_softc *sc, u_int32_t opcode)
3476265555Sambrisko{
3477275976Ssmh	struct mrsas_mfi_cmd *cmd;
3478275976Ssmh	struct mrsas_dcmd_frame *dcmd;
3479265555Sambrisko
3480275976Ssmh	if (sc->adprecovery == MRSAS_HW_CRITICAL_ERROR)
3481275976Ssmh		return;
3482265555Sambrisko
3483275976Ssmh	cmd = mrsas_get_mfi_cmd(sc);
3484275976Ssmh	if (!cmd) {
3485275976Ssmh		device_printf(sc->mrsas_dev, "Cannot allocate for shutdown cmd.\n");
3486275976Ssmh		return;
3487275976Ssmh	}
3488275976Ssmh	if (sc->aen_cmd)
3489275976Ssmh		mrsas_issue_blocked_abort_cmd(sc, sc->aen_cmd);
3490265555Sambrisko
3491265555Sambrisko	if (sc->map_update_cmd)
3492275976Ssmh		mrsas_issue_blocked_abort_cmd(sc, sc->map_update_cmd);
3493265555Sambrisko
3494275976Ssmh	dcmd = &cmd->frame->dcmd;
3495275976Ssmh	memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
3496265555Sambrisko
3497275976Ssmh	dcmd->cmd = MFI_CMD_DCMD;
3498275976Ssmh	dcmd->cmd_status = 0x0;
3499275976Ssmh	dcmd->sge_count = 0;
3500275976Ssmh	dcmd->flags = MFI_FRAME_DIR_NONE;
3501275976Ssmh	dcmd->timeout = 0;
3502275976Ssmh	dcmd->pad_0 = 0;
3503275976Ssmh	dcmd->data_xfer_len = 0;
3504275976Ssmh	dcmd->opcode = opcode;
3505265555Sambrisko
3506275976Ssmh	device_printf(sc->mrsas_dev, "Preparing to shut down controller.\n");
3507265555Sambrisko
3508275976Ssmh	mrsas_issue_blocked_cmd(sc, cmd);
3509275976Ssmh	mrsas_release_mfi_cmd(cmd);
3510265555Sambrisko
3511275976Ssmh	return;
3512265555Sambrisko}
3513265555Sambrisko
3514275976Ssmh/*
3515275976Ssmh * mrsas_flush_cache:         Requests FW to flush all its caches input:
3516275976Ssmh * Adapter soft state
3517265555Sambrisko *
3518265555Sambrisko * This function is issues a DCMD internal command to Firmware to initiate
3519265555Sambrisko * flushing of all caches.
3520265555Sambrisko */
3521275976Ssmhstatic void
3522275976Ssmhmrsas_flush_cache(struct mrsas_softc *sc)
3523265555Sambrisko{
3524275976Ssmh	struct mrsas_mfi_cmd *cmd;
3525275976Ssmh	struct mrsas_dcmd_frame *dcmd;
3526265555Sambrisko
3527275976Ssmh	if (sc->adprecovery == MRSAS_HW_CRITICAL_ERROR)
3528275976Ssmh		return;
3529265555Sambrisko
3530275976Ssmh	cmd = mrsas_get_mfi_cmd(sc);
3531275976Ssmh	if (!cmd) {
3532275976Ssmh		device_printf(sc->mrsas_dev, "Cannot allocate for flush cache cmd.\n");
3533275976Ssmh		return;
3534275976Ssmh	}
3535275976Ssmh	dcmd = &cmd->frame->dcmd;
3536275976Ssmh	memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
3537265555Sambrisko
3538275976Ssmh	dcmd->cmd = MFI_CMD_DCMD;
3539275976Ssmh	dcmd->cmd_status = 0x0;
3540275976Ssmh	dcmd->sge_count = 0;
3541275976Ssmh	dcmd->flags = MFI_FRAME_DIR_NONE;
3542275976Ssmh	dcmd->timeout = 0;
3543275976Ssmh	dcmd->pad_0 = 0;
3544275976Ssmh	dcmd->data_xfer_len = 0;
3545275976Ssmh	dcmd->opcode = MR_DCMD_CTRL_CACHE_FLUSH;
3546275976Ssmh	dcmd->mbox.b[0] = MR_FLUSH_CTRL_CACHE | MR_FLUSH_DISK_CACHE;
3547265555Sambrisko
3548275976Ssmh	mrsas_issue_blocked_cmd(sc, cmd);
3549275976Ssmh	mrsas_release_mfi_cmd(cmd);
3550265555Sambrisko
3551275976Ssmh	return;
3552265555Sambrisko}
3553265555Sambrisko
3554275976Ssmh/*
3555275976Ssmh * mrsas_get_map_info:        Load and validate RAID map input:
3556275976Ssmh * Adapter instance soft state
3557265555Sambrisko *
3558275976Ssmh * This function calls mrsas_get_ld_map_info() and MR_ValidateMapInfo() to load
3559275976Ssmh * and validate RAID map.  It returns 0 if successful, 1 other- wise.
3560265555Sambrisko */
3561275976Ssmhstatic int
3562275976Ssmhmrsas_get_map_info(struct mrsas_softc *sc)
3563275976Ssmh{
3564275976Ssmh	uint8_t retcode = 0;
3565265555Sambrisko
3566275976Ssmh	sc->fast_path_io = 0;
3567275976Ssmh	if (!mrsas_get_ld_map_info(sc)) {
3568275976Ssmh		retcode = MR_ValidateMapInfo(sc);
3569275976Ssmh		if (retcode == 0) {
3570275976Ssmh			sc->fast_path_io = 1;
3571275976Ssmh			return 0;
3572275976Ssmh		}
3573275976Ssmh	}
3574275976Ssmh	return 1;
3575265555Sambrisko}
3576265555Sambrisko
3577275976Ssmh/*
3578275976Ssmh * mrsas_get_ld_map_info:      Get FW's ld_map structure input:
3579275976Ssmh * Adapter instance soft state
3580265555Sambrisko *
3581275976Ssmh * Issues an internal command (DCMD) to get the FW's controller PD list
3582275976Ssmh * structure.
3583265555Sambrisko */
3584275976Ssmhstatic int
3585275976Ssmhmrsas_get_ld_map_info(struct mrsas_softc *sc)
3586265555Sambrisko{
3587275976Ssmh	int retcode = 0;
3588275976Ssmh	struct mrsas_mfi_cmd *cmd;
3589275976Ssmh	struct mrsas_dcmd_frame *dcmd;
3590275976Ssmh	void *map;
3591275976Ssmh	bus_addr_t map_phys_addr = 0;
3592265555Sambrisko
3593275976Ssmh	cmd = mrsas_get_mfi_cmd(sc);
3594275976Ssmh	if (!cmd) {
3595275976Ssmh		device_printf(sc->mrsas_dev,
3596275976Ssmh		    "Cannot alloc for ld map info cmd.\n");
3597275976Ssmh		return 1;
3598275976Ssmh	}
3599275976Ssmh	dcmd = &cmd->frame->dcmd;
3600265555Sambrisko
3601275976Ssmh	map = (void *)sc->raidmap_mem[(sc->map_id & 1)];
3602275976Ssmh	map_phys_addr = sc->raidmap_phys_addr[(sc->map_id & 1)];
3603275976Ssmh	if (!map) {
3604275976Ssmh		device_printf(sc->mrsas_dev,
3605275976Ssmh		    "Failed to alloc mem for ld map info.\n");
3606275976Ssmh		mrsas_release_mfi_cmd(cmd);
3607275976Ssmh		return (ENOMEM);
3608275976Ssmh	}
3609275976Ssmh	memset(map, 0, sizeof(sc->max_map_sz));
3610275976Ssmh	memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
3611265555Sambrisko
3612275976Ssmh	dcmd->cmd = MFI_CMD_DCMD;
3613275976Ssmh	dcmd->cmd_status = 0xFF;
3614275976Ssmh	dcmd->sge_count = 1;
3615275976Ssmh	dcmd->flags = MFI_FRAME_DIR_READ;
3616275976Ssmh	dcmd->timeout = 0;
3617275976Ssmh	dcmd->pad_0 = 0;
3618275976Ssmh	dcmd->data_xfer_len = sc->current_map_sz;
3619275976Ssmh	dcmd->opcode = MR_DCMD_LD_MAP_GET_INFO;
3620275976Ssmh	dcmd->sgl.sge32[0].phys_addr = map_phys_addr;
3621275976Ssmh	dcmd->sgl.sge32[0].length = sc->current_map_sz;
3622265555Sambrisko
3623275976Ssmh	if (!mrsas_issue_polled(sc, cmd))
3624275976Ssmh		retcode = 0;
3625275976Ssmh	else {
3626275976Ssmh		device_printf(sc->mrsas_dev,
3627275976Ssmh		    "Fail to send get LD map info cmd.\n");
3628275976Ssmh		retcode = 1;
3629275976Ssmh	}
3630275976Ssmh	mrsas_release_mfi_cmd(cmd);
3631275976Ssmh
3632275976Ssmh	return (retcode);
3633265555Sambrisko}
3634265555Sambrisko
3635275976Ssmh/*
3636275976Ssmh * mrsas_sync_map_info:        Get FW's ld_map structure input:
3637275976Ssmh * Adapter instance soft state
3638265555Sambrisko *
3639275976Ssmh * Issues an internal command (DCMD) to get the FW's controller PD list
3640275976Ssmh * structure.
3641265555Sambrisko */
3642275976Ssmhstatic int
3643275976Ssmhmrsas_sync_map_info(struct mrsas_softc *sc)
3644265555Sambrisko{
3645275976Ssmh	int retcode = 0, i;
3646275976Ssmh	struct mrsas_mfi_cmd *cmd;
3647275976Ssmh	struct mrsas_dcmd_frame *dcmd;
3648275976Ssmh	uint32_t size_sync_info, num_lds;
3649275976Ssmh	MR_LD_TARGET_SYNC *target_map = NULL;
3650275976Ssmh	MR_DRV_RAID_MAP_ALL *map;
3651275976Ssmh	MR_LD_RAID *raid;
3652275976Ssmh	MR_LD_TARGET_SYNC *ld_sync;
3653275976Ssmh	bus_addr_t map_phys_addr = 0;
3654265555Sambrisko
3655275976Ssmh	cmd = mrsas_get_mfi_cmd(sc);
3656275976Ssmh	if (!cmd) {
3657275976Ssmh		device_printf(sc->mrsas_dev,
3658275976Ssmh		    "Cannot alloc for sync map info cmd\n");
3659275976Ssmh		return 1;
3660275976Ssmh	}
3661275976Ssmh	map = sc->ld_drv_map[sc->map_id & 1];
3662275976Ssmh	num_lds = map->raidMap.ldCount;
3663265555Sambrisko
3664275976Ssmh	dcmd = &cmd->frame->dcmd;
3665275976Ssmh	size_sync_info = sizeof(MR_LD_TARGET_SYNC) * num_lds;
3666275976Ssmh	memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
3667265555Sambrisko
3668275976Ssmh	target_map = (MR_LD_TARGET_SYNC *) sc->raidmap_mem[(sc->map_id - 1) & 1];
3669275976Ssmh	memset(target_map, 0, sc->max_map_sz);
3670265555Sambrisko
3671275976Ssmh	map_phys_addr = sc->raidmap_phys_addr[(sc->map_id - 1) & 1];
3672265555Sambrisko
3673275976Ssmh	ld_sync = (MR_LD_TARGET_SYNC *) target_map;
3674265555Sambrisko
3675275976Ssmh	for (i = 0; i < num_lds; i++, ld_sync++) {
3676275976Ssmh		raid = MR_LdRaidGet(i, map);
3677275976Ssmh		ld_sync->targetId = MR_GetLDTgtId(i, map);
3678275976Ssmh		ld_sync->seqNum = raid->seqNum;
3679275976Ssmh	}
3680265555Sambrisko
3681275976Ssmh	dcmd->cmd = MFI_CMD_DCMD;
3682275976Ssmh	dcmd->cmd_status = 0xFF;
3683275976Ssmh	dcmd->sge_count = 1;
3684275976Ssmh	dcmd->flags = MFI_FRAME_DIR_WRITE;
3685275976Ssmh	dcmd->timeout = 0;
3686275976Ssmh	dcmd->pad_0 = 0;
3687275976Ssmh	dcmd->data_xfer_len = sc->current_map_sz;
3688275976Ssmh	dcmd->mbox.b[0] = num_lds;
3689275976Ssmh	dcmd->mbox.b[1] = MRSAS_DCMD_MBOX_PEND_FLAG;
3690275976Ssmh	dcmd->opcode = MR_DCMD_LD_MAP_GET_INFO;
3691275976Ssmh	dcmd->sgl.sge32[0].phys_addr = map_phys_addr;
3692275976Ssmh	dcmd->sgl.sge32[0].length = sc->current_map_sz;
3693265555Sambrisko
3694275976Ssmh	sc->map_update_cmd = cmd;
3695275976Ssmh	if (mrsas_issue_dcmd(sc, cmd)) {
3696275976Ssmh		device_printf(sc->mrsas_dev,
3697275976Ssmh		    "Fail to send sync map info command.\n");
3698275976Ssmh		return (1);
3699275976Ssmh	}
3700275976Ssmh	return (retcode);
3701265555Sambrisko}
3702265555Sambrisko
3703275976Ssmh/*
3704275976Ssmh * mrsas_get_pd_list:           Returns FW's PD list structure input:
3705275976Ssmh * Adapter soft state
3706265555Sambrisko *
3707275976Ssmh * Issues an internal command (DCMD) to get the FW's controller PD list
3708275976Ssmh * structure.  This information is mainly used to find out about system
3709275976Ssmh * supported by Firmware.
3710265555Sambrisko */
3711275976Ssmhstatic int
3712275976Ssmhmrsas_get_pd_list(struct mrsas_softc *sc)
3713265555Sambrisko{
3714275976Ssmh	int retcode = 0, pd_index = 0, pd_count = 0, pd_list_size;
3715275976Ssmh	struct mrsas_mfi_cmd *cmd;
3716275976Ssmh	struct mrsas_dcmd_frame *dcmd;
3717275976Ssmh	struct MR_PD_LIST *pd_list_mem;
3718275976Ssmh	struct MR_PD_ADDRESS *pd_addr;
3719275976Ssmh	bus_addr_t pd_list_phys_addr = 0;
3720275976Ssmh	struct mrsas_tmp_dcmd *tcmd;
3721265555Sambrisko
3722275976Ssmh	cmd = mrsas_get_mfi_cmd(sc);
3723275976Ssmh	if (!cmd) {
3724275976Ssmh		device_printf(sc->mrsas_dev,
3725275976Ssmh		    "Cannot alloc for get PD list cmd\n");
3726275976Ssmh		return 1;
3727275976Ssmh	}
3728275976Ssmh	dcmd = &cmd->frame->dcmd;
3729265555Sambrisko
3730275976Ssmh	tcmd = malloc(sizeof(struct mrsas_tmp_dcmd), M_MRSAS, M_NOWAIT);
3731275976Ssmh	pd_list_size = MRSAS_MAX_PD * sizeof(struct MR_PD_LIST);
3732275976Ssmh	if (mrsas_alloc_tmp_dcmd(sc, tcmd, pd_list_size) != SUCCESS) {
3733275976Ssmh		device_printf(sc->mrsas_dev,
3734275976Ssmh		    "Cannot alloc dmamap for get PD list cmd\n");
3735275976Ssmh		mrsas_release_mfi_cmd(cmd);
3736275976Ssmh		return (ENOMEM);
3737275976Ssmh	} else {
3738275976Ssmh		pd_list_mem = tcmd->tmp_dcmd_mem;
3739275976Ssmh		pd_list_phys_addr = tcmd->tmp_dcmd_phys_addr;
3740275976Ssmh	}
3741275976Ssmh	memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
3742265555Sambrisko
3743275976Ssmh	dcmd->mbox.b[0] = MR_PD_QUERY_TYPE_EXPOSED_TO_HOST;
3744275976Ssmh	dcmd->mbox.b[1] = 0;
3745275976Ssmh	dcmd->cmd = MFI_CMD_DCMD;
3746275976Ssmh	dcmd->cmd_status = 0xFF;
3747275976Ssmh	dcmd->sge_count = 1;
3748275976Ssmh	dcmd->flags = MFI_FRAME_DIR_READ;
3749275976Ssmh	dcmd->timeout = 0;
3750275976Ssmh	dcmd->pad_0 = 0;
3751275976Ssmh	dcmd->data_xfer_len = MRSAS_MAX_PD * sizeof(struct MR_PD_LIST);
3752275976Ssmh	dcmd->opcode = MR_DCMD_PD_LIST_QUERY;
3753275976Ssmh	dcmd->sgl.sge32[0].phys_addr = pd_list_phys_addr;
3754275976Ssmh	dcmd->sgl.sge32[0].length = MRSAS_MAX_PD * sizeof(struct MR_PD_LIST);
3755265555Sambrisko
3756275976Ssmh	if (!mrsas_issue_polled(sc, cmd))
3757275976Ssmh		retcode = 0;
3758275976Ssmh	else
3759275976Ssmh		retcode = 1;
3760265555Sambrisko
3761275976Ssmh	/* Get the instance PD list */
3762275976Ssmh	pd_count = MRSAS_MAX_PD;
3763275976Ssmh	pd_addr = pd_list_mem->addr;
3764275976Ssmh	if (retcode == 0 && pd_list_mem->count < pd_count) {
3765275976Ssmh		memset(sc->local_pd_list, 0,
3766275976Ssmh		    MRSAS_MAX_PD * sizeof(struct mrsas_pd_list));
3767275976Ssmh		for (pd_index = 0; pd_index < pd_list_mem->count; pd_index++) {
3768275976Ssmh			sc->local_pd_list[pd_addr->deviceId].tid = pd_addr->deviceId;
3769275976Ssmh			sc->local_pd_list[pd_addr->deviceId].driveType =
3770275976Ssmh			    pd_addr->scsiDevType;
3771275976Ssmh			sc->local_pd_list[pd_addr->deviceId].driveState =
3772275976Ssmh			    MR_PD_STATE_SYSTEM;
3773275976Ssmh			pd_addr++;
3774275976Ssmh		}
3775275976Ssmh	}
3776275976Ssmh	/*
3777275976Ssmh	 * Use mutext/spinlock if pd_list component size increase more than
3778275976Ssmh	 * 32 bit.
3779275976Ssmh	 */
3780275976Ssmh	memcpy(sc->pd_list, sc->local_pd_list, sizeof(sc->local_pd_list));
3781275976Ssmh	mrsas_free_tmp_dcmd(tcmd);
3782275976Ssmh	mrsas_release_mfi_cmd(cmd);
3783275976Ssmh	free(tcmd, M_MRSAS);
3784275976Ssmh	return (retcode);
3785265555Sambrisko}
3786265555Sambrisko
3787275976Ssmh/*
3788275976Ssmh * mrsas_get_ld_list:           Returns FW's LD list structure input:
3789275976Ssmh * Adapter soft state
3790265555Sambrisko *
3791275976Ssmh * Issues an internal command (DCMD) to get the FW's controller PD list
3792275976Ssmh * structure.  This information is mainly used to find out about supported by
3793275976Ssmh * the FW.
3794265555Sambrisko */
3795275976Ssmhstatic int
3796275976Ssmhmrsas_get_ld_list(struct mrsas_softc *sc)
3797265555Sambrisko{
3798275976Ssmh	int ld_list_size, retcode = 0, ld_index = 0, ids = 0;
3799275976Ssmh	struct mrsas_mfi_cmd *cmd;
3800275976Ssmh	struct mrsas_dcmd_frame *dcmd;
3801275976Ssmh	struct MR_LD_LIST *ld_list_mem;
3802275976Ssmh	bus_addr_t ld_list_phys_addr = 0;
3803275976Ssmh	struct mrsas_tmp_dcmd *tcmd;
3804265555Sambrisko
3805275976Ssmh	cmd = mrsas_get_mfi_cmd(sc);
3806275976Ssmh	if (!cmd) {
3807275976Ssmh		device_printf(sc->mrsas_dev,
3808275976Ssmh		    "Cannot alloc for get LD list cmd\n");
3809275976Ssmh		return 1;
3810275976Ssmh	}
3811275976Ssmh	dcmd = &cmd->frame->dcmd;
3812265555Sambrisko
3813275976Ssmh	tcmd = malloc(sizeof(struct mrsas_tmp_dcmd), M_MRSAS, M_NOWAIT);
3814275976Ssmh	ld_list_size = sizeof(struct MR_LD_LIST);
3815275976Ssmh	if (mrsas_alloc_tmp_dcmd(sc, tcmd, ld_list_size) != SUCCESS) {
3816275976Ssmh		device_printf(sc->mrsas_dev,
3817275976Ssmh		    "Cannot alloc dmamap for get LD list cmd\n");
3818275976Ssmh		mrsas_release_mfi_cmd(cmd);
3819275976Ssmh		return (ENOMEM);
3820275976Ssmh	} else {
3821275976Ssmh		ld_list_mem = tcmd->tmp_dcmd_mem;
3822275976Ssmh		ld_list_phys_addr = tcmd->tmp_dcmd_phys_addr;
3823275976Ssmh	}
3824275976Ssmh	memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
3825265555Sambrisko
3826275976Ssmh	if (sc->max256vdSupport)
3827275976Ssmh		dcmd->mbox.b[0] = 1;
3828265555Sambrisko
3829275976Ssmh	dcmd->cmd = MFI_CMD_DCMD;
3830275976Ssmh	dcmd->cmd_status = 0xFF;
3831275976Ssmh	dcmd->sge_count = 1;
3832275976Ssmh	dcmd->flags = MFI_FRAME_DIR_READ;
3833275976Ssmh	dcmd->timeout = 0;
3834275976Ssmh	dcmd->data_xfer_len = sizeof(struct MR_LD_LIST);
3835275976Ssmh	dcmd->opcode = MR_DCMD_LD_GET_LIST;
3836275976Ssmh	dcmd->sgl.sge32[0].phys_addr = ld_list_phys_addr;
3837275976Ssmh	dcmd->sgl.sge32[0].length = sizeof(struct MR_LD_LIST);
3838275976Ssmh	dcmd->pad_0 = 0;
3839265555Sambrisko
3840275976Ssmh	if (!mrsas_issue_polled(sc, cmd))
3841275976Ssmh		retcode = 0;
3842275976Ssmh	else
3843275976Ssmh		retcode = 1;
3844265555Sambrisko
3845275976Ssmh#if VD_EXT_DEBUG
3846275976Ssmh	printf("Number of LDs %d\n", ld_list_mem->ldCount);
3847275976Ssmh#endif
3848265555Sambrisko
3849275976Ssmh	/* Get the instance LD list */
3850275976Ssmh	if ((retcode == 0) &&
3851275976Ssmh	    (ld_list_mem->ldCount <= sc->fw_supported_vd_count)) {
3852275976Ssmh		sc->CurLdCount = ld_list_mem->ldCount;
3853275976Ssmh		memset(sc->ld_ids, 0xff, MAX_LOGICAL_DRIVES_EXT);
3854275976Ssmh		for (ld_index = 0; ld_index < ld_list_mem->ldCount; ld_index++) {
3855275976Ssmh			if (ld_list_mem->ldList[ld_index].state != 0) {
3856275976Ssmh				ids = ld_list_mem->ldList[ld_index].ref.ld_context.targetId;
3857275976Ssmh				sc->ld_ids[ids] = ld_list_mem->ldList[ld_index].ref.ld_context.targetId;
3858275976Ssmh			}
3859275976Ssmh		}
3860275976Ssmh	}
3861275976Ssmh	mrsas_free_tmp_dcmd(tcmd);
3862275976Ssmh	mrsas_release_mfi_cmd(cmd);
3863275976Ssmh	free(tcmd, M_MRSAS);
3864275976Ssmh	return (retcode);
3865265555Sambrisko}
3866265555Sambrisko
3867275976Ssmh/*
3868275976Ssmh * mrsas_alloc_tmp_dcmd:       Allocates memory for temporary command input:
3869275976Ssmh * Adapter soft state Temp command Size of alloction
3870265555Sambrisko *
3871265555Sambrisko * Allocates DMAable memory for a temporary internal command. The allocated
3872275976Ssmh * memory is initialized to all zeros upon successful loading of the dma
3873265555Sambrisko * mapped memory.
3874265555Sambrisko */
3875284267Skadesaiint
3876275976Ssmhmrsas_alloc_tmp_dcmd(struct mrsas_softc *sc,
3877275976Ssmh    struct mrsas_tmp_dcmd *tcmd, int size)
3878265555Sambrisko{
3879275976Ssmh	if (bus_dma_tag_create(sc->mrsas_parent_tag,
3880275976Ssmh	    1, 0,
3881275976Ssmh	    BUS_SPACE_MAXADDR_32BIT,
3882275976Ssmh	    BUS_SPACE_MAXADDR,
3883275976Ssmh	    NULL, NULL,
3884275976Ssmh	    size,
3885275976Ssmh	    1,
3886275976Ssmh	    size,
3887275976Ssmh	    BUS_DMA_ALLOCNOW,
3888275976Ssmh	    NULL, NULL,
3889275976Ssmh	    &tcmd->tmp_dcmd_tag)) {
3890275976Ssmh		device_printf(sc->mrsas_dev, "Cannot allocate tmp dcmd tag\n");
3891275976Ssmh		return (ENOMEM);
3892275976Ssmh	}
3893275976Ssmh	if (bus_dmamem_alloc(tcmd->tmp_dcmd_tag, (void **)&tcmd->tmp_dcmd_mem,
3894275976Ssmh	    BUS_DMA_NOWAIT, &tcmd->tmp_dcmd_dmamap)) {
3895275976Ssmh		device_printf(sc->mrsas_dev, "Cannot allocate tmp dcmd mem\n");
3896275976Ssmh		return (ENOMEM);
3897275976Ssmh	}
3898275976Ssmh	if (bus_dmamap_load(tcmd->tmp_dcmd_tag, tcmd->tmp_dcmd_dmamap,
3899275976Ssmh	    tcmd->tmp_dcmd_mem, size, mrsas_addr_cb,
3900275976Ssmh	    &tcmd->tmp_dcmd_phys_addr, BUS_DMA_NOWAIT)) {
3901275976Ssmh		device_printf(sc->mrsas_dev, "Cannot load tmp dcmd mem\n");
3902275976Ssmh		return (ENOMEM);
3903275976Ssmh	}
3904275976Ssmh	memset(tcmd->tmp_dcmd_mem, 0, size);
3905275976Ssmh	return (0);
3906265555Sambrisko}
3907265555Sambrisko
3908275976Ssmh/*
3909275976Ssmh * mrsas_free_tmp_dcmd:      Free memory for temporary command input:
3910275976Ssmh * temporary dcmd pointer
3911265555Sambrisko *
3912275976Ssmh * Deallocates memory of the temporary command for use in the construction of
3913275976Ssmh * the internal DCMD.
3914265555Sambrisko */
3915275976Ssmhvoid
3916275976Ssmhmrsas_free_tmp_dcmd(struct mrsas_tmp_dcmd *tmp)
3917265555Sambrisko{
3918275976Ssmh	if (tmp->tmp_dcmd_phys_addr)
3919275976Ssmh		bus_dmamap_unload(tmp->tmp_dcmd_tag, tmp->tmp_dcmd_dmamap);
3920275976Ssmh	if (tmp->tmp_dcmd_mem != NULL)
3921275976Ssmh		bus_dmamem_free(tmp->tmp_dcmd_tag, tmp->tmp_dcmd_mem, tmp->tmp_dcmd_dmamap);
3922275976Ssmh	if (tmp->tmp_dcmd_tag != NULL)
3923275976Ssmh		bus_dma_tag_destroy(tmp->tmp_dcmd_tag);
3924265555Sambrisko}
3925265555Sambrisko
3926275976Ssmh/*
3927275976Ssmh * mrsas_issue_blocked_abort_cmd:       Aborts previously issued cmd input:
3928275976Ssmh * Adapter soft state Previously issued cmd to be aborted
3929265555Sambrisko *
3930275976Ssmh * This function is used to abort previously issued commands, such as AEN and
3931275976Ssmh * RAID map sync map commands.  The abort command is sent as a DCMD internal
3932275976Ssmh * command and subsequently the driver will wait for a return status.  The
3933275976Ssmh * max wait time is MRSAS_INTERNAL_CMD_WAIT_TIME seconds.
3934265555Sambrisko */
3935275976Ssmhstatic int
3936275976Ssmhmrsas_issue_blocked_abort_cmd(struct mrsas_softc *sc,
3937275976Ssmh    struct mrsas_mfi_cmd *cmd_to_abort)
3938265555Sambrisko{
3939275976Ssmh	struct mrsas_mfi_cmd *cmd;
3940275976Ssmh	struct mrsas_abort_frame *abort_fr;
3941275976Ssmh	u_int8_t retcode = 0;
3942275976Ssmh	unsigned long total_time = 0;
3943275976Ssmh	u_int8_t max_wait = MRSAS_INTERNAL_CMD_WAIT_TIME;
3944265555Sambrisko
3945275976Ssmh	cmd = mrsas_get_mfi_cmd(sc);
3946275976Ssmh	if (!cmd) {
3947275976Ssmh		device_printf(sc->mrsas_dev, "Cannot alloc for abort cmd\n");
3948275976Ssmh		return (1);
3949275976Ssmh	}
3950275976Ssmh	abort_fr = &cmd->frame->abort;
3951265555Sambrisko
3952275976Ssmh	/* Prepare and issue the abort frame */
3953275976Ssmh	abort_fr->cmd = MFI_CMD_ABORT;
3954275976Ssmh	abort_fr->cmd_status = 0xFF;
3955275976Ssmh	abort_fr->flags = 0;
3956275976Ssmh	abort_fr->abort_context = cmd_to_abort->index;
3957275976Ssmh	abort_fr->abort_mfi_phys_addr_lo = cmd_to_abort->frame_phys_addr;
3958275976Ssmh	abort_fr->abort_mfi_phys_addr_hi = 0;
3959265555Sambrisko
3960275976Ssmh	cmd->sync_cmd = 1;
3961275976Ssmh	cmd->cmd_status = 0xFF;
3962265555Sambrisko
3963275976Ssmh	if (mrsas_issue_dcmd(sc, cmd)) {
3964275976Ssmh		device_printf(sc->mrsas_dev, "Fail to send abort command.\n");
3965275976Ssmh		return (1);
3966275976Ssmh	}
3967275976Ssmh	/* Wait for this cmd to complete */
3968275976Ssmh	sc->chan = (void *)&cmd;
3969275976Ssmh	while (1) {
3970275976Ssmh		if (cmd->cmd_status == 0xFF) {
3971275976Ssmh			tsleep((void *)&sc->chan, 0, "mrsas_sleep", hz);
3972275976Ssmh		} else
3973275976Ssmh			break;
3974275976Ssmh		total_time++;
3975275976Ssmh		if (total_time >= max_wait) {
3976275976Ssmh			device_printf(sc->mrsas_dev, "Abort cmd timed out after %d sec.\n", max_wait);
3977275976Ssmh			retcode = 1;
3978275976Ssmh			break;
3979275976Ssmh		}
3980275976Ssmh	}
3981265555Sambrisko
3982275976Ssmh	cmd->sync_cmd = 0;
3983275976Ssmh	mrsas_release_mfi_cmd(cmd);
3984275976Ssmh	return (retcode);
3985265555Sambrisko}
3986265555Sambrisko
3987275976Ssmh/*
3988275976Ssmh * mrsas_complete_abort:      Completes aborting a command input:
3989275976Ssmh * Adapter soft state Cmd that was issued to abort another cmd
3990265555Sambrisko *
3991275976Ssmh * The mrsas_issue_blocked_abort_cmd() function waits for the command status to
3992275976Ssmh * change after sending the command.  This function is called from
3993265555Sambrisko * mrsas_complete_mptmfi_passthru() to wake up the sleep thread associated.
3994265555Sambrisko */
3995275976Ssmhvoid
3996275976Ssmhmrsas_complete_abort(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd)
3997265555Sambrisko{
3998275976Ssmh	if (cmd->sync_cmd) {
3999275976Ssmh		cmd->sync_cmd = 0;
4000275976Ssmh		cmd->cmd_status = 0;
4001275976Ssmh		sc->chan = (void *)&cmd;
4002275976Ssmh		wakeup_one((void *)&sc->chan);
4003275976Ssmh	}
4004275976Ssmh	return;
4005265555Sambrisko}
4006265555Sambrisko
4007275976Ssmh/*
4008275976Ssmh * mrsas_aen_handler:	AEN processing callback function from thread context
4009275976Ssmh * input:				Adapter soft state
4010265555Sambrisko *
4011275976Ssmh * Asynchronous event handler
4012265555Sambrisko */
4013275976Ssmhvoid
4014275976Ssmhmrsas_aen_handler(struct mrsas_softc *sc)
4015265555Sambrisko{
4016265555Sambrisko	union mrsas_evt_class_locale class_locale;
4017275976Ssmh	int doscan = 0;
4018265555Sambrisko	u_int32_t seq_num;
4019265555Sambrisko	int error;
4020265555Sambrisko
4021265555Sambrisko	if (!sc) {
4022265555Sambrisko		device_printf(sc->mrsas_dev, "invalid instance!\n");
4023265555Sambrisko		return;
4024265555Sambrisko	}
4025265555Sambrisko	if (sc->evt_detail_mem) {
4026265555Sambrisko		switch (sc->evt_detail_mem->code) {
4027275976Ssmh		case MR_EVT_PD_INSERTED:
4028275976Ssmh			mrsas_get_pd_list(sc);
4029275976Ssmh			mrsas_bus_scan_sim(sc, sc->sim_1);
4030275976Ssmh			doscan = 0;
4031275976Ssmh			break;
4032275976Ssmh		case MR_EVT_PD_REMOVED:
4033275976Ssmh			mrsas_get_pd_list(sc);
4034275976Ssmh			mrsas_bus_scan_sim(sc, sc->sim_1);
4035275976Ssmh			doscan = 0;
4036275976Ssmh			break;
4037275976Ssmh		case MR_EVT_LD_OFFLINE:
4038275976Ssmh		case MR_EVT_CFG_CLEARED:
4039275976Ssmh		case MR_EVT_LD_DELETED:
4040275976Ssmh			mrsas_bus_scan_sim(sc, sc->sim_0);
4041275976Ssmh			doscan = 0;
4042275976Ssmh			break;
4043275976Ssmh		case MR_EVT_LD_CREATED:
4044275976Ssmh			mrsas_get_ld_list(sc);
4045275976Ssmh			mrsas_bus_scan_sim(sc, sc->sim_0);
4046275976Ssmh			doscan = 0;
4047275976Ssmh			break;
4048275976Ssmh		case MR_EVT_CTRL_HOST_BUS_SCAN_REQUESTED:
4049275976Ssmh		case MR_EVT_FOREIGN_CFG_IMPORTED:
4050275976Ssmh		case MR_EVT_LD_STATE_CHANGE:
4051275976Ssmh			doscan = 1;
4052275976Ssmh			break;
4053275976Ssmh		default:
4054275976Ssmh			doscan = 0;
4055275976Ssmh			break;
4056265555Sambrisko		}
4057265555Sambrisko	} else {
4058265555Sambrisko		device_printf(sc->mrsas_dev, "invalid evt_detail\n");
4059265555Sambrisko		return;
4060265555Sambrisko	}
4061265555Sambrisko	if (doscan) {
4062265555Sambrisko		mrsas_get_pd_list(sc);
4063265555Sambrisko		mrsas_dprint(sc, MRSAS_AEN, "scanning ...sim 1\n");
4064265555Sambrisko		mrsas_bus_scan_sim(sc, sc->sim_1);
4065265555Sambrisko		mrsas_get_ld_list(sc);
4066265555Sambrisko		mrsas_dprint(sc, MRSAS_AEN, "scanning ...sim 0\n");
4067265555Sambrisko		mrsas_bus_scan_sim(sc, sc->sim_0);
4068265555Sambrisko	}
4069265555Sambrisko	seq_num = sc->evt_detail_mem->seq_num + 1;
4070265555Sambrisko
4071275976Ssmh	/* Register AEN with FW for latest sequence number plus 1 */
4072265555Sambrisko	class_locale.members.reserved = 0;
4073265555Sambrisko	class_locale.members.locale = MR_EVT_LOCALE_ALL;
4074265555Sambrisko	class_locale.members.class = MR_EVT_CLASS_DEBUG;
4075265555Sambrisko
4076275976Ssmh	if (sc->aen_cmd != NULL)
4077275976Ssmh		return;
4078275976Ssmh
4079265555Sambrisko	mtx_lock(&sc->aen_lock);
4080265555Sambrisko	error = mrsas_register_aen(sc, seq_num,
4081275976Ssmh	    class_locale.word);
4082265555Sambrisko	mtx_unlock(&sc->aen_lock);
4083265555Sambrisko
4084265555Sambrisko	if (error)
4085265555Sambrisko		device_printf(sc->mrsas_dev, "register aen failed error %x\n", error);
4086265555Sambrisko
4087265555Sambrisko}
4088265555Sambrisko
4089265555Sambrisko
4090275976Ssmh/*
4091275976Ssmh * mrsas_complete_aen:	Completes AEN command
4092275976Ssmh * input:				Adapter soft state
4093275976Ssmh * 						Cmd that was issued to abort another cmd
4094265555Sambrisko *
4095275976Ssmh * This function will be called from ISR and will continue event processing from
4096275976Ssmh * thread context by enqueuing task in ev_tq (callback function
4097275976Ssmh * "mrsas_aen_handler").
4098265555Sambrisko */
4099275976Ssmhvoid
4100275976Ssmhmrsas_complete_aen(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd)
4101265555Sambrisko{
4102265555Sambrisko	/*
4103275976Ssmh	 * Don't signal app if it is just an aborted previously registered
4104275976Ssmh	 * aen
4105275976Ssmh	 */
4106265555Sambrisko	if ((!cmd->abort_aen) && (sc->remove_in_progress == 0)) {
4107275976Ssmh		sc->mrsas_aen_triggered = 1;
4108284267Skadesai		mtx_lock(&sc->aen_lock);
4109275976Ssmh		if (sc->mrsas_poll_waiting) {
4110275976Ssmh			sc->mrsas_poll_waiting = 0;
4111275976Ssmh			selwakeup(&sc->mrsas_select);
4112275976Ssmh		}
4113284267Skadesai		mtx_unlock(&sc->aen_lock);
4114275976Ssmh	} else
4115265555Sambrisko		cmd->abort_aen = 0;
4116265555Sambrisko
4117265555Sambrisko	sc->aen_cmd = NULL;
4118265555Sambrisko	mrsas_release_mfi_cmd(cmd);
4119265555Sambrisko
4120265555Sambrisko	if (!sc->remove_in_progress)
4121265555Sambrisko		taskqueue_enqueue(sc->ev_tq, &sc->ev_task);
4122265555Sambrisko
4123265555Sambrisko	return;
4124265555Sambrisko}
4125265555Sambrisko
4126265555Sambriskostatic device_method_t mrsas_methods[] = {
4127275976Ssmh	DEVMETHOD(device_probe, mrsas_probe),
4128275976Ssmh	DEVMETHOD(device_attach, mrsas_attach),
4129275976Ssmh	DEVMETHOD(device_detach, mrsas_detach),
4130275976Ssmh	DEVMETHOD(device_suspend, mrsas_suspend),
4131275976Ssmh	DEVMETHOD(device_resume, mrsas_resume),
4132275976Ssmh	DEVMETHOD(bus_print_child, bus_generic_print_child),
4133275976Ssmh	DEVMETHOD(bus_driver_added, bus_generic_driver_added),
4134275976Ssmh	{0, 0}
4135265555Sambrisko};
4136265555Sambrisko
4137265555Sambriskostatic driver_t mrsas_driver = {
4138275976Ssmh	"mrsas",
4139275976Ssmh	mrsas_methods,
4140275976Ssmh	sizeof(struct mrsas_softc)
4141265555Sambrisko};
4142265555Sambrisko
4143275976Ssmhstatic devclass_t mrsas_devclass;
4144275976Ssmh
4145265555SambriskoDRIVER_MODULE(mrsas, pci, mrsas_driver, mrsas_devclass, 0, 0);
4146275976SsmhMODULE_DEPEND(mrsas, cam, 1, 1, 1);
4147