1265555Sambrisko/*
2265555Sambrisko * Copyright (c) 2014, LSI Corp.
3265555Sambrisko * All rights reserved.
4265555Sambrisko * Author: Marian Choy
5265555Sambrisko * Support: freebsdraid@lsi.com
6265555Sambrisko *
7265555Sambrisko * Redistribution and use in source and binary forms, with or without
8265555Sambrisko * modification, are permitted provided that the following conditions
9265555Sambrisko * are met:
10265555Sambrisko *
11265555Sambrisko * 1. Redistributions of source code must retain the above copyright
12265555Sambrisko *    notice, this list of conditions and the following disclaimer.
13265555Sambrisko * 2. Redistributions in binary form must reproduce the above copyright
14265555Sambrisko *    notice, this list of conditions and the following disclaimer in
15265555Sambrisko *    the documentation and/or other materials provided with the
16265555Sambrisko *    distribution.
17265555Sambrisko * 3. Neither the name of the <ORGANIZATION> nor the names of its
18265555Sambrisko *    contributors may be used to endorse or promote products derived
19265555Sambrisko *    from this software without specific prior written permission.
20265555Sambrisko *
21265555Sambrisko * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22265555Sambrisko * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23265555Sambrisko * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24265555Sambrisko * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25265555Sambrisko * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26265555Sambrisko * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27265555Sambrisko * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28265555Sambrisko * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29265555Sambrisko * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30265555Sambrisko * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31265555Sambrisko * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32265555Sambrisko * POSSIBILITY OF SUCH DAMAGE.
33265555Sambrisko *
34265555Sambrisko * The views and conclusions contained in the software and documentation
35265555Sambrisko * are those of the authors and should not be interpreted as representing
36265555Sambrisko * official policies,either expressed or implied, of the FreeBSD Project.
37265555Sambrisko *
38265555Sambrisko * Send feedback to: <megaraidfbsd@lsi.com>
39265555Sambrisko * Mail to: LSI Corporation, 1621 Barber Lane, Milpitas, CA 95035
40265555Sambrisko *    ATTN: MegaRaid FreeBSD
41265555Sambrisko *
42265555Sambrisko */
43265555Sambrisko
44265555Sambrisko#include <sys/cdefs.h>
45265555Sambrisko__FBSDID("$FreeBSD$");
46265555Sambrisko
47265555Sambrisko#include <dev/mrsas/mrsas.h>
48265555Sambrisko#include <dev/mrsas/mrsas_ioctl.h>
49265555Sambrisko
50265555Sambrisko#include <cam/cam.h>
51265555Sambrisko#include <cam/cam_ccb.h>
52265555Sambrisko
53265555Sambrisko#include <sys/sysctl.h>
54265555Sambrisko#include <sys/types.h>
55265555Sambrisko#include <sys/kthread.h>
56265555Sambrisko#include <sys/taskqueue.h>
57265555Sambrisko
58265555Sambrisko
59265555Sambrisko/*
60265555Sambrisko * Function prototypes
61265555Sambrisko */
62265555Sambriskostatic d_open_t     mrsas_open;
63265555Sambriskostatic d_close_t    mrsas_close;
64265555Sambriskostatic d_read_t     mrsas_read;
65265555Sambriskostatic d_write_t    mrsas_write;
66265555Sambriskostatic d_ioctl_t    mrsas_ioctl;
67265555Sambrisko
68265555Sambriskostatic struct mrsas_ident *mrsas_find_ident(device_t);
69265555Sambriskostatic void mrsas_shutdown_ctlr(struct mrsas_softc *sc, u_int32_t opcode);
70265555Sambriskostatic void mrsas_flush_cache(struct mrsas_softc *sc);
71265555Sambriskostatic void mrsas_reset_reply_desc(struct mrsas_softc *sc);
72265555Sambriskostatic void mrsas_ocr_thread(void *arg);
73265555Sambriskostatic int mrsas_get_map_info(struct mrsas_softc *sc);
74265555Sambriskostatic int mrsas_get_ld_map_info(struct mrsas_softc *sc);
75265555Sambriskostatic int mrsas_sync_map_info(struct mrsas_softc *sc);
76265555Sambriskostatic int mrsas_get_pd_list(struct mrsas_softc *sc);
77265555Sambriskostatic int mrsas_get_ld_list(struct mrsas_softc *sc);
78265555Sambriskostatic int mrsas_setup_irq(struct mrsas_softc *sc);
79265555Sambriskostatic int mrsas_alloc_mem(struct mrsas_softc *sc);
80265555Sambriskostatic int mrsas_init_fw(struct mrsas_softc *sc);
81265555Sambriskostatic int mrsas_setup_raidmap(struct mrsas_softc *sc);
82265555Sambriskostatic int mrsas_complete_cmd(struct mrsas_softc *sc);
83265555Sambriskostatic int mrsas_clear_intr(struct mrsas_softc *sc);
84265555Sambriskostatic int mrsas_get_ctrl_info(struct mrsas_softc *sc,
85265555Sambrisko                          struct mrsas_ctrl_info *ctrl_info);
86265555Sambriskostatic int mrsas_issue_blocked_abort_cmd(struct mrsas_softc *sc,
87265555Sambrisko                         struct mrsas_mfi_cmd *cmd_to_abort);
88265555Sambriskou_int32_t mrsas_read_reg(struct mrsas_softc *sc, int offset);
89265555Sambriskou_int8_t mrsas_build_mptmfi_passthru(struct mrsas_softc *sc,
90265555Sambrisko                         struct mrsas_mfi_cmd *mfi_cmd);
91265555Sambriskoint mrsas_transition_to_ready(struct mrsas_softc *sc, int ocr);
92265555Sambriskoint mrsas_init_adapter(struct mrsas_softc *sc);
93265555Sambriskoint mrsas_alloc_mpt_cmds(struct mrsas_softc *sc);
94265555Sambriskoint mrsas_alloc_ioc_cmd(struct mrsas_softc *sc);
95265555Sambriskoint mrsas_alloc_ctlr_info_cmd(struct mrsas_softc *sc);
96265555Sambriskoint mrsas_ioc_init(struct mrsas_softc *sc);
97265555Sambriskoint mrsas_bus_scan(struct mrsas_softc *sc);
98265555Sambriskoint mrsas_issue_dcmd(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd);
99265555Sambriskoint mrsas_issue_polled(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd);
100265555Sambriskoint mrsas_reset_ctrl(struct mrsas_softc *sc);
101265555Sambriskoint mrsas_wait_for_outstanding(struct mrsas_softc *sc);
102265555Sambriskoint mrsas_issue_blocked_cmd(struct mrsas_softc *sc,
103265555Sambrisko                          struct mrsas_mfi_cmd *cmd);
104265555Sambriskoint mrsas_alloc_tmp_dcmd(struct mrsas_softc *sc, struct mrsas_tmp_dcmd *tcmd,
105265555Sambrisko                          int size);
106265555Sambriskovoid mrsas_release_mfi_cmd(struct mrsas_mfi_cmd *cmd);
107265555Sambriskovoid mrsas_wakeup(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd);
108265555Sambriskovoid mrsas_complete_aen(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd);
109265555Sambriskovoid mrsas_complete_abort(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd);
110265555Sambriskovoid mrsas_disable_intr(struct mrsas_softc *sc);
111265555Sambriskovoid mrsas_enable_intr(struct mrsas_softc *sc);
112265555Sambriskovoid mrsas_free_ioc_cmd(struct mrsas_softc *sc);
113265555Sambriskovoid mrsas_free_mem(struct mrsas_softc *sc);
114265555Sambriskovoid mrsas_free_tmp_dcmd(struct mrsas_tmp_dcmd *tmp);
115265555Sambriskovoid mrsas_isr(void *arg);
116265555Sambriskovoid mrsas_teardown_intr(struct mrsas_softc *sc);
117265555Sambriskovoid mrsas_addr_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error);
118265555Sambriskovoid mrsas_kill_hba (struct mrsas_softc *sc);
119265555Sambriskovoid mrsas_aen_handler(struct mrsas_softc *sc);
120265555Sambriskovoid mrsas_write_reg(struct mrsas_softc *sc, int offset,
121265555Sambrisko                          u_int32_t value);
122265555Sambriskovoid mrsas_fire_cmd(struct mrsas_softc *sc, u_int32_t req_desc_lo,
123265555Sambrisko                          u_int32_t req_desc_hi);
124265555Sambriskovoid mrsas_free_ctlr_info_cmd(struct mrsas_softc *sc);
125265555Sambriskovoid mrsas_complete_mptmfi_passthru(struct mrsas_softc *sc,
126265555Sambrisko                          struct mrsas_mfi_cmd *cmd, u_int8_t status);
127265555Sambriskovoid mrsas_map_mpt_cmd_status(struct mrsas_mpt_cmd *cmd, u_int8_t status,
128265555Sambrisko                          u_int8_t extStatus);
129265555Sambriskostruct mrsas_mfi_cmd* mrsas_get_mfi_cmd(struct mrsas_softc *sc);
130265555SambriskoMRSAS_REQUEST_DESCRIPTOR_UNION * mrsas_build_mpt_cmd(struct mrsas_softc *sc,
131265555Sambrisko                          struct mrsas_mfi_cmd *cmd);
132265555Sambrisko
133265555Sambriskoextern int mrsas_cam_attach(struct mrsas_softc *sc);
134265555Sambriskoextern void mrsas_cam_detach(struct mrsas_softc *sc);
135265555Sambriskoextern void mrsas_cmd_done(struct mrsas_softc *sc, struct mrsas_mpt_cmd *cmd);
136265555Sambriskoextern void mrsas_free_frame(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd);
137265555Sambriskoextern int mrsas_alloc_mfi_cmds(struct mrsas_softc *sc);
138265555Sambriskoextern void mrsas_release_mpt_cmd(struct mrsas_mpt_cmd *cmd);
139265555Sambriskoextern struct mrsas_mpt_cmd *mrsas_get_mpt_cmd(struct mrsas_softc *sc);
140265555Sambriskoextern int mrsas_passthru(struct mrsas_softc *sc, void *arg);
141265555Sambriskoextern uint8_t MR_ValidateMapInfo(struct mrsas_softc *sc);
142265555Sambriskoextern u_int16_t MR_GetLDTgtId(u_int32_t ld, MR_FW_RAID_MAP_ALL *map);
143265555Sambriskoextern MR_LD_RAID *MR_LdRaidGet(u_int32_t ld, MR_FW_RAID_MAP_ALL *map);
144265555Sambriskoextern void mrsas_xpt_freeze(struct mrsas_softc *sc);
145265555Sambriskoextern void mrsas_xpt_release(struct mrsas_softc *sc);
146265555Sambriskoextern MRSAS_REQUEST_DESCRIPTOR_UNION *mrsas_get_request_desc(struct mrsas_softc *sc,
147265555Sambrisko                         u_int16_t index);
148265555Sambriskoextern int mrsas_bus_scan_sim(struct mrsas_softc *sc, struct cam_sim *sim);
149265555Sambriskostatic int mrsas_alloc_evt_log_info_cmd(struct mrsas_softc *sc);
150265555Sambriskostatic void mrsas_free_evt_log_info_cmd(struct mrsas_softc *sc);
151265555SambriskoSYSCTL_NODE(_hw, OID_AUTO, mrsas, CTLFLAG_RD, 0, "MRSAS Driver Parameters");
152265555Sambrisko
153265555Sambrisko
154265555Sambrisko/**
155265555Sambrisko * PCI device struct and table
156265555Sambrisko *
157265555Sambrisko */
158265555Sambriskotypedef struct mrsas_ident {
159265555Sambrisko    uint16_t    vendor;
160265555Sambrisko    uint16_t    device;
161265555Sambrisko    uint16_t    subvendor;
162265555Sambrisko    uint16_t    subdevice;
163265555Sambrisko    const char  *desc;
164265555Sambrisko} MRSAS_CTLR_ID;
165265555Sambrisko
166265555SambriskoMRSAS_CTLR_ID device_table[] = {
167265555Sambrisko    {0x1000, MRSAS_TBOLT, 0xffff, 0xffff, "LSI Thunderbolt SAS Controller"},
168265555Sambrisko    {0x1000, MRSAS_INVADER, 0xffff, 0xffff, "LSI Invader SAS Controller"},
169265555Sambrisko    {0x1000, MRSAS_FURY, 0xffff, 0xffff, "LSI Fury SAS Controller"},
170265555Sambrisko    {0, 0, 0, 0, NULL}
171265555Sambrisko};
172265555Sambrisko
173265555Sambrisko/**
174265555Sambrisko * Character device entry points
175265555Sambrisko *
176265555Sambrisko */
177265555Sambriskostatic struct cdevsw mrsas_cdevsw = {
178265555Sambrisko    .d_version =    D_VERSION,
179265555Sambrisko    .d_open =   mrsas_open,
180265555Sambrisko    .d_close =  mrsas_close,
181265555Sambrisko    .d_read =   mrsas_read,
182265555Sambrisko    .d_write =  mrsas_write,
183265555Sambrisko    .d_ioctl =  mrsas_ioctl,
184265555Sambrisko    .d_name =   "mrsas",
185265555Sambrisko};
186265555Sambrisko
187265555SambriskoMALLOC_DEFINE(M_MRSAS, "mrsasbuf", "Buffers for the MRSAS driver");
188265555Sambrisko
189265555Sambrisko/**
190265555Sambrisko * In the cdevsw routines, we find our softc by using the si_drv1 member
191265555Sambrisko * of struct cdev.  We set this variable to point to our softc in our
192265555Sambrisko * attach routine when we create the /dev entry.
193265555Sambrisko */
194265555Sambriskoint
195265555Sambriskomrsas_open(struct cdev *dev, int oflags, int devtype, d_thread_t *td)
196265555Sambrisko{
197265555Sambrisko    struct mrsas_softc *sc;
198265555Sambrisko
199265555Sambrisko    sc = dev->si_drv1;
200265555Sambrisko    return (0);
201265555Sambrisko}
202265555Sambrisko
203265555Sambriskoint
204265555Sambriskomrsas_close(struct cdev *dev, int fflag, int devtype, d_thread_t *td)
205265555Sambrisko{
206265555Sambrisko    struct mrsas_softc *sc;
207265555Sambrisko
208265555Sambrisko    sc = dev->si_drv1;
209265555Sambrisko    return (0);
210265555Sambrisko}
211265555Sambrisko
212265555Sambriskoint
213265555Sambriskomrsas_read(struct cdev *dev, struct uio *uio, int ioflag)
214265555Sambrisko{
215265555Sambrisko    struct mrsas_softc *sc;
216265555Sambrisko
217265555Sambrisko    sc = dev->si_drv1;
218265555Sambrisko    return (0);
219265555Sambrisko}
220265555Sambriskoint
221265555Sambriskomrsas_write(struct cdev *dev, struct uio *uio, int ioflag)
222265555Sambrisko{
223265555Sambrisko    struct mrsas_softc *sc;
224265555Sambrisko
225265555Sambrisko    sc = dev->si_drv1;
226265555Sambrisko    return (0);
227265555Sambrisko}
228265555Sambrisko
229265555Sambrisko/**
230265555Sambrisko * Register Read/Write Functions
231265555Sambrisko *
232265555Sambrisko */
233265555Sambriskovoid
234265555Sambriskomrsas_write_reg(struct mrsas_softc *sc, int offset,
235265555Sambrisko                  u_int32_t value)
236265555Sambrisko{
237265555Sambrisko    bus_space_tag_t         bus_tag = sc->bus_tag;
238265555Sambrisko    bus_space_handle_t      bus_handle = sc->bus_handle;
239265555Sambrisko
240265555Sambrisko    bus_space_write_4(bus_tag, bus_handle, offset, value);
241265555Sambrisko}
242265555Sambrisko
243265555Sambriskou_int32_t
244265555Sambriskomrsas_read_reg(struct mrsas_softc *sc, int offset)
245265555Sambrisko{
246265555Sambrisko    bus_space_tag_t bus_tag = sc->bus_tag;
247265555Sambrisko    bus_space_handle_t bus_handle = sc->bus_handle;
248265555Sambrisko
249265555Sambrisko    return((u_int32_t)bus_space_read_4(bus_tag, bus_handle, offset));
250265555Sambrisko}
251265555Sambrisko
252265555Sambrisko
253265555Sambrisko/**
254265555Sambrisko * Interrupt Disable/Enable/Clear Functions
255265555Sambrisko *
256265555Sambrisko */
257265555Sambriskovoid mrsas_disable_intr(struct mrsas_softc *sc)
258265555Sambrisko{
259265555Sambrisko    u_int32_t mask = 0xFFFFFFFF;
260265555Sambrisko    u_int32_t status;
261265555Sambrisko
262265555Sambrisko    mrsas_write_reg(sc, offsetof(mrsas_reg_set, outbound_intr_mask), mask);
263265555Sambrisko    /* Dummy read to force pci flush */
264265555Sambrisko    status = mrsas_read_reg(sc, offsetof(mrsas_reg_set, outbound_intr_mask));
265265555Sambrisko}
266265555Sambrisko
267265555Sambriskovoid mrsas_enable_intr(struct mrsas_softc *sc)
268265555Sambrisko{
269265555Sambrisko    u_int32_t mask = MFI_FUSION_ENABLE_INTERRUPT_MASK;
270265555Sambrisko    u_int32_t status;
271265555Sambrisko
272265555Sambrisko    mrsas_write_reg(sc, offsetof(mrsas_reg_set, outbound_intr_status), ~0);
273265555Sambrisko    status = mrsas_read_reg(sc, offsetof(mrsas_reg_set, outbound_intr_status));
274265555Sambrisko
275265555Sambrisko    mrsas_write_reg(sc, offsetof(mrsas_reg_set, outbound_intr_mask), ~mask);
276265555Sambrisko    status = mrsas_read_reg(sc, offsetof(mrsas_reg_set, outbound_intr_mask));
277265555Sambrisko}
278265555Sambrisko
279265555Sambriskostatic int mrsas_clear_intr(struct mrsas_softc *sc)
280265555Sambrisko{
281265555Sambrisko    u_int32_t status, fw_status, fw_state;
282265555Sambrisko
283265555Sambrisko    /* Read received interrupt */
284265555Sambrisko    status = mrsas_read_reg(sc, offsetof(mrsas_reg_set, outbound_intr_status));
285265555Sambrisko
286265555Sambrisko    /* If FW state change interrupt is received, write to it again to clear */
287265555Sambrisko    if (status & MRSAS_FW_STATE_CHNG_INTERRUPT) {
288265555Sambrisko        fw_status = mrsas_read_reg(sc, offsetof(mrsas_reg_set,
289265555Sambrisko                                   outbound_scratch_pad));
290265555Sambrisko        fw_state = fw_status & MFI_STATE_MASK;
291265555Sambrisko        if (fw_state == MFI_STATE_FAULT) {
292265555Sambrisko            device_printf(sc->mrsas_dev, "FW is in FAULT state!\n");
293265555Sambrisko            if(sc->ocr_thread_active)
294265555Sambrisko                wakeup(&sc->ocr_chan);
295265555Sambrisko        }
296265555Sambrisko        mrsas_write_reg(sc, offsetof(mrsas_reg_set, outbound_intr_status), status);
297265555Sambrisko        mrsas_read_reg(sc, offsetof(mrsas_reg_set, outbound_intr_status));
298265555Sambrisko        return(1);
299265555Sambrisko    }
300265555Sambrisko
301265555Sambrisko    /* Not our interrupt, so just return */
302265555Sambrisko    if (!(status & MFI_FUSION_ENABLE_INTERRUPT_MASK))
303265555Sambrisko        return(0);
304265555Sambrisko
305265555Sambrisko    /* We got a reply interrupt */
306265555Sambrisko    return(1);
307265555Sambrisko}
308265555Sambrisko
309265555Sambrisko/**
310265555Sambrisko * PCI Support Functions
311265555Sambrisko *
312265555Sambrisko */
313265555Sambriskostatic struct mrsas_ident * mrsas_find_ident(device_t dev)
314265555Sambrisko{
315265555Sambrisko    struct mrsas_ident *pci_device;
316265555Sambrisko
317265555Sambrisko    for (pci_device=device_table; pci_device->vendor != 0; pci_device++)
318265555Sambrisko    {
319265555Sambrisko        if ((pci_device->vendor == pci_get_vendor(dev)) &&
320265555Sambrisko            (pci_device->device == pci_get_device(dev)) &&
321265555Sambrisko            ((pci_device->subvendor == pci_get_subvendor(dev)) ||
322265555Sambrisko            (pci_device->subvendor == 0xffff)) &&
323265555Sambrisko            ((pci_device->subdevice == pci_get_subdevice(dev)) ||
324265555Sambrisko            (pci_device->subdevice == 0xffff)))
325265555Sambrisko        return (pci_device);
326265555Sambrisko    }
327265555Sambrisko    return (NULL);
328265555Sambrisko}
329265555Sambrisko
330265555Sambriskostatic int mrsas_probe(device_t dev)
331265555Sambrisko{
332265555Sambrisko    static u_int8_t first_ctrl = 1;
333265555Sambrisko    struct mrsas_ident *id;
334265555Sambrisko
335265555Sambrisko    if ((id = mrsas_find_ident(dev)) != NULL) {
336265555Sambrisko        if (first_ctrl) {
337265555Sambrisko            printf("LSI MegaRAID SAS FreeBSD mrsas driver version: %s\n", MRSAS_VERSION);
338265555Sambrisko            first_ctrl = 0;
339265555Sambrisko        }
340265555Sambrisko        device_set_desc(dev, id->desc);
341265555Sambrisko    	/* between BUS_PROBE_DEFAULT and BUS_PROBE_LOW_PRIORITY */
342265555Sambrisko    	return (-30);
343265555Sambrisko    }
344265555Sambrisko    return (ENXIO);
345265555Sambrisko}
346265555Sambrisko
347265555Sambrisko/**
348265555Sambrisko * mrsas_setup_sysctl:  setup sysctl values for mrsas
349265555Sambrisko * input:               Adapter instance soft state
350265555Sambrisko *
351265555Sambrisko * Setup sysctl entries for mrsas driver.
352265555Sambrisko */
353265555Sambriskostatic void
354265555Sambriskomrsas_setup_sysctl(struct mrsas_softc *sc)
355265555Sambrisko{
356265555Sambrisko    struct sysctl_ctx_list  *sysctl_ctx = NULL;
357265555Sambrisko    struct sysctl_oid       *sysctl_tree = NULL;
358265555Sambrisko    char tmpstr[80], tmpstr2[80];
359265555Sambrisko
360265555Sambrisko    /*
361265555Sambrisko     * Setup the sysctl variable so the user can change the debug level
362265555Sambrisko     * on the fly.
363265555Sambrisko     */
364265555Sambrisko    snprintf(tmpstr, sizeof(tmpstr), "MRSAS controller %d",
365265555Sambrisko    device_get_unit(sc->mrsas_dev));
366265555Sambrisko    snprintf(tmpstr2, sizeof(tmpstr2), "%d", device_get_unit(sc->mrsas_dev));
367265555Sambrisko
368265555Sambrisko    sysctl_ctx = device_get_sysctl_ctx(sc->mrsas_dev);
369265555Sambrisko    if (sysctl_ctx != NULL)
370265555Sambrisko        sysctl_tree = device_get_sysctl_tree(sc->mrsas_dev);
371265555Sambrisko
372265555Sambrisko    if (sysctl_tree == NULL) {
373265555Sambrisko        sysctl_ctx_init(&sc->sysctl_ctx);
374265555Sambrisko        sc->sysctl_tree = SYSCTL_ADD_NODE(&sc->sysctl_ctx,
375265555Sambrisko            SYSCTL_STATIC_CHILDREN(_hw_mrsas), OID_AUTO, tmpstr2,
376265555Sambrisko            CTLFLAG_RD, 0, tmpstr);
377265555Sambrisko        if (sc->sysctl_tree == NULL)
378265555Sambrisko             return;
379265555Sambrisko        sysctl_ctx = &sc->sysctl_ctx;
380265555Sambrisko        sysctl_tree = sc->sysctl_tree;
381265555Sambrisko    }
382265555Sambrisko    SYSCTL_ADD_UINT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
383265555Sambrisko        OID_AUTO, "disable_ocr", CTLFLAG_RW, &sc->disableOnlineCtrlReset, 0,
384265555Sambrisko        "Disable the use of OCR");
385265555Sambrisko
386265555Sambrisko    SYSCTL_ADD_STRING(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
387265555Sambrisko        OID_AUTO, "driver_version", CTLFLAG_RD, MRSAS_VERSION,
388265555Sambrisko        strlen(MRSAS_VERSION), "driver version");
389265555Sambrisko
390265555Sambrisko    SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
391265555Sambrisko        OID_AUTO, "reset_count", CTLFLAG_RD,
392265555Sambrisko        &sc->reset_count, 0, "number of ocr from start of the day");
393265555Sambrisko
394265555Sambrisko    SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
395265555Sambrisko        OID_AUTO, "fw_outstanding", CTLFLAG_RD,
396265555Sambrisko        &sc->fw_outstanding, 0, "FW outstanding commands");
397265555Sambrisko
398265555Sambrisko	SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
399265555Sambrisko        OID_AUTO, "io_cmds_highwater", CTLFLAG_RD,
400265555Sambrisko        &sc->io_cmds_highwater, 0, "Max FW outstanding commands");
401265555Sambrisko
402265555Sambrisko    SYSCTL_ADD_UINT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
403265555Sambrisko        OID_AUTO, "mrsas_debug", CTLFLAG_RW, &sc->mrsas_debug, 0,
404265555Sambrisko        "Driver debug level");
405265555Sambrisko
406265555Sambrisko    SYSCTL_ADD_UINT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
407265555Sambrisko        OID_AUTO, "mrsas_io_timeout", CTLFLAG_RW, &sc->mrsas_io_timeout,
408265555Sambrisko        0, "Driver IO timeout value in mili-second.");
409265555Sambrisko
410265555Sambrisko    SYSCTL_ADD_UINT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
411265555Sambrisko        OID_AUTO, "mrsas_fw_fault_check_delay", CTLFLAG_RW,
412265555Sambrisko        &sc->mrsas_fw_fault_check_delay,
413265555Sambrisko        0, "FW fault check thread delay in seconds. <default is 1 sec>");
414265555Sambrisko
415265555Sambrisko    SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
416265555Sambrisko        OID_AUTO, "reset_in_progress", CTLFLAG_RD,
417265555Sambrisko        &sc->reset_in_progress, 0, "ocr in progress status");
418265555Sambrisko
419265555Sambrisko}
420265555Sambrisko
421265555Sambrisko/**
422265555Sambrisko * mrsas_get_tunables:  get tunable parameters.
423265555Sambrisko * input:               Adapter instance soft state
424265555Sambrisko *
425265555Sambrisko * Get tunable parameters. This will help to debug driver at boot time.
426265555Sambrisko */
427265555Sambriskostatic void
428265555Sambriskomrsas_get_tunables(struct mrsas_softc *sc)
429265555Sambrisko{
430265555Sambrisko    char tmpstr[80];
431265555Sambrisko
432265555Sambrisko    /* XXX default to some debugging for now */
433265555Sambrisko    sc->mrsas_debug = MRSAS_FAULT;
434265555Sambrisko    sc->mrsas_io_timeout = MRSAS_IO_TIMEOUT;
435265555Sambrisko    sc->mrsas_fw_fault_check_delay = 1;
436265555Sambrisko    sc->reset_count = 0;
437265555Sambrisko    sc->reset_in_progress = 0;
438265555Sambrisko
439265555Sambrisko    /*
440265555Sambrisko     * Grab the global variables.
441265555Sambrisko     */
442265555Sambrisko    TUNABLE_INT_FETCH("hw.mrsas.debug_level", &sc->mrsas_debug);
443265555Sambrisko
444265555Sambrisko    /* Grab the unit-instance variables */
445265555Sambrisko    snprintf(tmpstr, sizeof(tmpstr), "dev.mrsas.%d.debug_level",
446265555Sambrisko        device_get_unit(sc->mrsas_dev));
447265555Sambrisko    TUNABLE_INT_FETCH(tmpstr, &sc->mrsas_debug);
448265555Sambrisko}
449265555Sambrisko
450265555Sambrisko/**
451265555Sambrisko * mrsas_alloc_evt_log_info cmd:	Allocates memory to get event log information.
452265555Sambrisko * 								  	Used to get sequence number at driver load time.
453265555Sambrisko * input:                      	  	Adapter soft state
454265555Sambrisko *
455265555Sambrisko * Allocates DMAable memory for the event log info internal command.
456265555Sambrisko */
457265555Sambriskoint mrsas_alloc_evt_log_info_cmd(struct mrsas_softc *sc)
458265555Sambrisko{
459265555Sambrisko    int el_info_size;
460265555Sambrisko
461265555Sambrisko    /* Allocate get event log info command */
462265555Sambrisko    el_info_size = sizeof(struct mrsas_evt_log_info);
463265555Sambrisko    if (bus_dma_tag_create( sc->mrsas_parent_tag,   // parent
464265555Sambrisko                            1, 0,                   // algnmnt, boundary
465265555Sambrisko                            BUS_SPACE_MAXADDR_32BIT,// lowaddr
466265555Sambrisko                            BUS_SPACE_MAXADDR,      // highaddr
467265555Sambrisko                            NULL, NULL,             // filter, filterarg
468265555Sambrisko                            el_info_size,          // maxsize
469265555Sambrisko                            1,                      // msegments
470265555Sambrisko                            el_info_size,          // maxsegsize
471265555Sambrisko                            BUS_DMA_ALLOCNOW,       // flags
472265555Sambrisko                            NULL, NULL,             // lockfunc, lockarg
473265555Sambrisko                            &sc->el_info_tag)) {
474265555Sambrisko        device_printf(sc->mrsas_dev, "Cannot allocate event log info tag\n");
475265555Sambrisko        return (ENOMEM);
476265555Sambrisko    }
477265555Sambrisko    if (bus_dmamem_alloc(sc->el_info_tag, (void **)&sc->el_info_mem,
478265555Sambrisko            BUS_DMA_NOWAIT, &sc->el_info_dmamap)) {
479265555Sambrisko        device_printf(sc->mrsas_dev, "Cannot allocate event log info cmd mem\n");
480265555Sambrisko        return (ENOMEM);
481265555Sambrisko    }
482265555Sambrisko    if (bus_dmamap_load(sc->el_info_tag, sc->el_info_dmamap,
483265555Sambrisko            sc->el_info_mem, el_info_size, mrsas_addr_cb,
484265555Sambrisko            &sc->el_info_phys_addr, BUS_DMA_NOWAIT)) {
485265555Sambrisko        device_printf(sc->mrsas_dev, "Cannot load event log info cmd mem\n");
486265555Sambrisko        return (ENOMEM);
487265555Sambrisko    }
488265555Sambrisko
489265555Sambrisko    memset(sc->el_info_mem, 0, el_info_size);
490265555Sambrisko    return (0);
491265555Sambrisko}
492265555Sambrisko
493265555Sambrisko/**
494265555Sambrisko * mrsas_free_evt_info_cmd: 	Free memory for Event log info command
495265555Sambrisko * input:                    	Adapter soft state
496265555Sambrisko *
497265555Sambrisko * Deallocates memory for the event log info internal command.
498265555Sambrisko */
499265555Sambriskovoid mrsas_free_evt_log_info_cmd(struct mrsas_softc *sc)
500265555Sambrisko{
501265555Sambrisko    if (sc->el_info_phys_addr)
502265555Sambrisko        bus_dmamap_unload(sc->el_info_tag, sc->el_info_dmamap);
503265555Sambrisko    if (sc->el_info_mem != NULL)
504265555Sambrisko        bus_dmamem_free(sc->el_info_tag, sc->el_info_mem, sc->el_info_dmamap);
505265555Sambrisko    if (sc->el_info_tag != NULL)
506265555Sambrisko        bus_dma_tag_destroy(sc->el_info_tag);
507265555Sambrisko}
508265555Sambrisko
509265555Sambrisko/**
510265555Sambrisko *  mrsas_get_seq_num:	Get latest event sequence number
511265555Sambrisko *  @sc:				Adapter soft state
512265555Sambrisko *  @eli:				Firmware event log sequence number information.
513265555Sambrisko *						Firmware maintains a log of all events in a non-volatile area.
514265555Sambrisko *						Driver get the sequence number using DCMD
515265555Sambrisko *						"MR_DCMD_CTRL_EVENT_GET_INFO" at driver load time.
516265555Sambrisko */
517265555Sambrisko
518265555Sambriskostatic int
519265555Sambriskomrsas_get_seq_num(struct mrsas_softc *sc,
520265555Sambrisko		    struct mrsas_evt_log_info *eli)
521265555Sambrisko{
522265555Sambrisko	struct mrsas_mfi_cmd *cmd;
523265555Sambrisko	struct mrsas_dcmd_frame *dcmd;
524265555Sambrisko
525265555Sambrisko	cmd =  mrsas_get_mfi_cmd(sc);
526265555Sambrisko
527265555Sambrisko	if (!cmd) {
528265555Sambrisko		device_printf(sc->mrsas_dev, "Failed to get a free cmd\n");
529265555Sambrisko		return -ENOMEM;
530265555Sambrisko	}
531265555Sambrisko
532265555Sambrisko	dcmd = &cmd->frame->dcmd;
533265555Sambrisko
534265555Sambrisko	if (mrsas_alloc_evt_log_info_cmd(sc) != SUCCESS) {
535265555Sambrisko		device_printf(sc->mrsas_dev, "Cannot allocate evt log info cmd\n");
536265555Sambrisko		mrsas_release_mfi_cmd(cmd);
537265555Sambrisko		return -ENOMEM;
538265555Sambrisko	}
539265555Sambrisko
540265555Sambrisko	memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
541265555Sambrisko
542265555Sambrisko	dcmd->cmd = MFI_CMD_DCMD;
543265555Sambrisko	dcmd->cmd_status = 0x0;
544265555Sambrisko	dcmd->sge_count = 1;
545265555Sambrisko	dcmd->flags = MFI_FRAME_DIR_READ;
546265555Sambrisko	dcmd->timeout = 0;
547265555Sambrisko	dcmd->pad_0 = 0;
548265555Sambrisko	dcmd->data_xfer_len = sizeof(struct mrsas_evt_log_info);
549265555Sambrisko	dcmd->opcode = MR_DCMD_CTRL_EVENT_GET_INFO;
550265555Sambrisko	dcmd->sgl.sge32[0].phys_addr = sc->el_info_phys_addr;
551265555Sambrisko	dcmd->sgl.sge32[0].length = sizeof(struct mrsas_evt_log_info);
552265555Sambrisko
553265555Sambrisko	mrsas_issue_blocked_cmd(sc, cmd);
554265555Sambrisko
555265555Sambrisko	/*
556265555Sambrisko 	 * Copy the data back into callers buffer
557265555Sambrisko 	 */
558265555Sambrisko	memcpy(eli, sc->el_info_mem, sizeof(struct mrsas_evt_log_info));
559265555Sambrisko	mrsas_free_evt_log_info_cmd(sc);
560265555Sambrisko	mrsas_release_mfi_cmd(cmd);
561265555Sambrisko
562265555Sambrisko	return 0;
563265555Sambrisko}
564265555Sambrisko
565265555Sambrisko
566265555Sambrisko/**
567265555Sambrisko *  mrsas_register_aen:		Register for asynchronous event notification
568265555Sambrisko *  @sc:					Adapter soft state
569265555Sambrisko *  @seq_num:				Starting sequence number
570265555Sambrisko *  @class_locale:			Class of the event
571265555Sambrisko *  						This function subscribes for events beyond the @seq_num
572265555Sambrisko *  						and type @class_locale.
573265555Sambrisko *
574265555Sambrisko * */
575265555Sambriskostatic int
576265555Sambriskomrsas_register_aen(struct mrsas_softc *sc, u_int32_t seq_num,
577265555Sambrisko		     u_int32_t class_locale_word)
578265555Sambrisko{
579265555Sambrisko	int ret_val;
580265555Sambrisko	struct mrsas_mfi_cmd *cmd;
581265555Sambrisko	struct mrsas_dcmd_frame *dcmd;
582265555Sambrisko	union mrsas_evt_class_locale curr_aen;
583265555Sambrisko	union mrsas_evt_class_locale prev_aen;
584265555Sambrisko
585265555Sambrisko/*
586265555Sambrisko *  If there an AEN pending already (aen_cmd), check if the
587265555Sambrisko *  class_locale of that pending AEN is inclusive of the new
588265555Sambrisko *  AEN request we currently have. If it is, then we don't have
589265555Sambrisko *  to do anything. In other words, whichever events the current
590265555Sambrisko *  AEN request is subscribing to, have already been subscribed
591265555Sambrisko *  to.
592265555Sambrisko *  If the old_cmd is _not_ inclusive, then we have to abort
593265555Sambrisko *  that command, form a class_locale that is superset of both
594265555Sambrisko *  old and current and re-issue to the FW
595265555Sambrisko * */
596265555Sambrisko
597265555Sambrisko	curr_aen.word = class_locale_word;
598265555Sambrisko
599265555Sambrisko	if (sc->aen_cmd) {
600265555Sambrisko
601265555Sambrisko		prev_aen.word = sc->aen_cmd->frame->dcmd.mbox.w[1];
602265555Sambrisko
603265555Sambrisko/*
604265555Sambrisko * A class whose enum value is smaller is inclusive of all
605265555Sambrisko * higher values. If a PROGRESS (= -1) was previously
606265555Sambrisko * registered, then a new registration requests for higher
607265555Sambrisko * classes need not be sent to FW. They are automatically
608265555Sambrisko * included.
609265555Sambrisko * Locale numbers don't have such hierarchy. They are bitmap values
610265555Sambrisko */
611265555Sambrisko		if ((prev_aen.members.class <= curr_aen.members.class) &&
612265555Sambrisko	    	!((prev_aen.members.locale & curr_aen.members.locale) ^
613265555Sambrisko	      	curr_aen.members.locale)) {
614265555Sambrisko			/*
615265555Sambrisko  			 * Previously issued event registration includes
616265555Sambrisko  			 * current request. Nothing to do.
617265555Sambrisko  			 */
618265555Sambrisko			return 0;
619265555Sambrisko		} else {
620265555Sambrisko			curr_aen.members.locale |= prev_aen.members.locale;
621265555Sambrisko
622265555Sambrisko			if (prev_aen.members.class < curr_aen.members.class)
623265555Sambrisko				curr_aen.members.class = prev_aen.members.class;
624265555Sambrisko
625265555Sambrisko			sc->aen_cmd->abort_aen = 1;
626265555Sambrisko			ret_val = mrsas_issue_blocked_abort_cmd(sc,
627265555Sambrisko				  sc->aen_cmd);
628265555Sambrisko
629265555Sambrisko			if (ret_val) {
630265555Sambrisko				printf("mrsas: Failed to abort "
631265555Sambrisko					   "previous AEN command\n");
632265555Sambrisko				return ret_val;
633265555Sambrisko			}
634265555Sambrisko		}
635265555Sambrisko	}
636265555Sambrisko
637265555Sambrisko	cmd =  mrsas_get_mfi_cmd(sc);
638265555Sambrisko
639265555Sambrisko	if (!cmd)
640265555Sambrisko		return -ENOMEM;
641265555Sambrisko
642265555Sambrisko	dcmd = &cmd->frame->dcmd;
643265555Sambrisko
644265555Sambrisko	memset(sc->evt_detail_mem, 0, sizeof(struct mrsas_evt_detail));
645265555Sambrisko
646265555Sambrisko/*
647265555Sambrisko * Prepare DCMD for aen registration
648265555Sambrisko */
649265555Sambrisko	memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
650265555Sambrisko
651265555Sambrisko	dcmd->cmd = MFI_CMD_DCMD;
652265555Sambrisko	dcmd->cmd_status = 0x0;
653265555Sambrisko	dcmd->sge_count = 1;
654265555Sambrisko	dcmd->flags = MFI_FRAME_DIR_READ;
655265555Sambrisko	dcmd->timeout = 0;
656265555Sambrisko	dcmd->pad_0 = 0;
657265555Sambrisko	dcmd->data_xfer_len = sizeof(struct mrsas_evt_detail);
658265555Sambrisko	dcmd->opcode = MR_DCMD_CTRL_EVENT_WAIT;
659265555Sambrisko	dcmd->mbox.w[0] = seq_num;
660265555Sambrisko    sc->last_seq_num = seq_num;
661265555Sambrisko	dcmd->mbox.w[1] = curr_aen.word;
662265555Sambrisko	dcmd->sgl.sge32[0].phys_addr = (u_int32_t) sc->evt_detail_phys_addr;
663265555Sambrisko	dcmd->sgl.sge32[0].length = sizeof(struct mrsas_evt_detail);
664265555Sambrisko
665265555Sambrisko	if (sc->aen_cmd != NULL) {
666265555Sambrisko		mrsas_release_mfi_cmd(cmd);
667265555Sambrisko		return 0;
668265555Sambrisko	}
669265555Sambrisko
670265555Sambrisko	/*
671265555Sambrisko  	 * Store reference to the cmd used to register for AEN. When an
672265555Sambrisko  	 * application wants us to register for AEN, we have to abort this
673265555Sambrisko   	 * cmd and re-register with a new EVENT LOCALE supplied by that app
674265555Sambrisko  	 */
675265555Sambrisko	sc->aen_cmd = cmd;
676265555Sambrisko
677265555Sambrisko	/*
678265555Sambrisko  	  Issue the aen registration frame
679265555Sambrisko  	*/
680265555Sambrisko  	if (mrsas_issue_dcmd(sc, cmd)){
681265555Sambrisko       	device_printf(sc->mrsas_dev, "Cannot issue AEN DCMD command.\n");
682265555Sambrisko       	return(1);
683265555Sambrisko   	}
684265555Sambrisko
685265555Sambrisko	return 0;
686265555Sambrisko}
687265555Sambrisko/**
688265555Sambrisko * mrsas_start_aen -  Subscribes to AEN during driver load time
689265555Sambrisko * @instance:           Adapter soft state
690265555Sambrisko */
691265555Sambriskostatic int mrsas_start_aen(struct mrsas_softc *sc)
692265555Sambrisko{
693265555Sambrisko	struct mrsas_evt_log_info eli;
694265555Sambrisko	union mrsas_evt_class_locale class_locale;
695265555Sambrisko
696265555Sambrisko
697265555Sambrisko	/* Get the latest sequence number from FW*/
698265555Sambrisko
699265555Sambrisko	memset(&eli, 0, sizeof(eli));
700265555Sambrisko
701265555Sambrisko	if (mrsas_get_seq_num(sc, &eli))
702265555Sambrisko		return -1;
703265555Sambrisko
704265555Sambrisko	/* Register AEN with FW for latest sequence number plus 1*/
705265555Sambrisko	class_locale.members.reserved = 0;
706265555Sambrisko	class_locale.members.locale = MR_EVT_LOCALE_ALL;
707265555Sambrisko	class_locale.members.class = MR_EVT_CLASS_DEBUG;
708265555Sambrisko
709265555Sambrisko	return mrsas_register_aen(sc, eli.newest_seq_num + 1,
710265555Sambrisko				class_locale.word);
711265555Sambrisko}
712265555Sambrisko
713265555Sambrisko/**
714265555Sambrisko * mrsas_attach:            PCI entry point
715265555Sambrisko * input:                   device struct pointer
716265555Sambrisko *
717265555Sambrisko * Performs setup of PCI and registers, initializes mutexes and
718265555Sambrisko * linked lists, registers interrupts and CAM, and initializes
719265555Sambrisko * the adapter/controller to its proper state.
720265555Sambrisko */
721265555Sambriskostatic int mrsas_attach(device_t dev)
722265555Sambrisko{
723265555Sambrisko    struct mrsas_softc *sc = device_get_softc(dev);
724265555Sambrisko    uint32_t cmd, bar, error;
725265555Sambrisko
726265555Sambrisko    /* Look up our softc and initialize its fields. */
727265555Sambrisko    sc->mrsas_dev = dev;
728265555Sambrisko    sc->device_id = pci_get_device(dev);
729265555Sambrisko
730265555Sambrisko    mrsas_get_tunables(sc);
731265555Sambrisko
732265555Sambrisko    /*
733265555Sambrisko     * Set up PCI and registers
734265555Sambrisko     */
735265555Sambrisko    cmd = pci_read_config(dev, PCIR_COMMAND, 2);
736265555Sambrisko    if ( (cmd & PCIM_CMD_PORTEN) == 0) {
737265555Sambrisko        return (ENXIO);
738265555Sambrisko    }
739265555Sambrisko    /* Force the busmaster enable bit on. */
740265555Sambrisko    cmd |= PCIM_CMD_BUSMASTEREN;
741265555Sambrisko    pci_write_config(dev, PCIR_COMMAND, cmd, 2);
742265555Sambrisko
743265555Sambrisko    //bar = pci_read_config(dev, MRSAS_PCI_BAR0, 4);
744265555Sambrisko    bar = pci_read_config(dev, MRSAS_PCI_BAR1, 4);
745265555Sambrisko
746265555Sambrisko    sc->reg_res_id = MRSAS_PCI_BAR1; /* BAR1 offset */
747265555Sambrisko    if ((sc->reg_res = bus_alloc_resource(dev, SYS_RES_MEMORY,
748265555Sambrisko                                &(sc->reg_res_id), 0, ~0, 1, RF_ACTIVE))
749265555Sambrisko                                == NULL) {
750265555Sambrisko        device_printf(dev, "Cannot allocate PCI registers\n");
751265555Sambrisko        goto attach_fail;
752265555Sambrisko    }
753265555Sambrisko    sc->bus_tag = rman_get_bustag(sc->reg_res);
754265555Sambrisko    sc->bus_handle = rman_get_bushandle(sc->reg_res);
755265555Sambrisko
756265555Sambrisko    /* Intialize mutexes */
757265555Sambrisko    mtx_init(&sc->sim_lock,  "mrsas_sim_lock", NULL, MTX_DEF);
758265555Sambrisko    mtx_init(&sc->pci_lock,  "mrsas_pci_lock", NULL, MTX_DEF);
759265555Sambrisko    mtx_init(&sc->io_lock,  "mrsas_io_lock", NULL, MTX_DEF);
760265555Sambrisko    mtx_init(&sc->aen_lock,  "mrsas_aen_lock", NULL, MTX_DEF);
761265555Sambrisko    mtx_init(&sc->ioctl_lock,  "mrsas_ioctl_lock", NULL, MTX_SPIN);
762265555Sambrisko    mtx_init(&sc->mpt_cmd_pool_lock, "mrsas_mpt_cmd_pool_lock", NULL, MTX_DEF);
763265555Sambrisko    mtx_init(&sc->mfi_cmd_pool_lock, "mrsas_mfi_cmd_pool_lock", NULL, MTX_DEF);
764265555Sambrisko    mtx_init(&sc->raidmap_lock, "mrsas_raidmap_lock", NULL, MTX_DEF);
765265555Sambrisko
766265555Sambrisko    /* Intialize linked list */
767265555Sambrisko    TAILQ_INIT(&sc->mrsas_mpt_cmd_list_head);
768265555Sambrisko    TAILQ_INIT(&sc->mrsas_mfi_cmd_list_head);
769265555Sambrisko
770265555Sambrisko    atomic_set(&sc->fw_outstanding,0);
771265555Sambrisko
772265555Sambrisko	sc->io_cmds_highwater = 0;
773265555Sambrisko
774265555Sambrisko    /* Create a /dev entry for this device. */
775265555Sambrisko    sc->mrsas_cdev = make_dev(&mrsas_cdevsw, device_get_unit(dev), UID_ROOT,
776265555Sambrisko        GID_OPERATOR, (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP), "mrsas%u",
777265555Sambrisko        device_get_unit(dev));
778265555Sambrisko    if (sc->mrsas_cdev)
779265555Sambrisko    	sc->mrsas_cdev->si_drv1 = sc;
780265555Sambrisko
781265555Sambrisko    sc->adprecovery = MRSAS_HBA_OPERATIONAL;
782265555Sambrisko	sc->UnevenSpanSupport = 0;
783265555Sambrisko
784265555Sambrisko    /* Initialize Firmware */
785265555Sambrisko    if (mrsas_init_fw(sc) != SUCCESS) {
786265555Sambrisko        goto attach_fail_fw;
787265555Sambrisko    }
788265555Sambrisko
789265555Sambrisko    /* Register SCSI mid-layer */
790265555Sambrisko    if ((mrsas_cam_attach(sc) != SUCCESS)) {
791265555Sambrisko        goto attach_fail_cam;
792265555Sambrisko    }
793265555Sambrisko
794265555Sambrisko    /* Register IRQs */
795265555Sambrisko    if (mrsas_setup_irq(sc) != SUCCESS) {
796265555Sambrisko        goto attach_fail_irq;
797265555Sambrisko    }
798265555Sambrisko
799265555Sambrisko    /* Enable Interrupts */
800265555Sambrisko    mrsas_enable_intr(sc);
801265555Sambrisko
802265555Sambrisko    error = mrsas_kproc_create(mrsas_ocr_thread, sc,
803265555Sambrisko        &sc->ocr_thread, 0, 0, "mrsas_ocr%d",
804265555Sambrisko        device_get_unit(sc->mrsas_dev));
805265555Sambrisko    if (error) {
806265555Sambrisko        printf("Error %d starting rescan thread\n", error);
807265555Sambrisko        goto attach_fail_irq;
808265555Sambrisko    }
809265555Sambrisko
810265555Sambrisko    mrsas_setup_sysctl(sc);
811265555Sambrisko
812265555Sambrisko	/* Initiate AEN (Asynchronous Event Notification)*/
813265555Sambrisko
814265555Sambrisko	if (mrsas_start_aen(sc)) {
815265555Sambrisko		printf("Error: start aen failed\n");
816265555Sambrisko		goto fail_start_aen;
817265555Sambrisko	}
818265555Sambrisko
819265555Sambrisko    return (0);
820265555Sambrisko
821265555Sambriskofail_start_aen:
822265555Sambriskoattach_fail_irq:
823265555Sambrisko    mrsas_teardown_intr(sc);
824265555Sambriskoattach_fail_cam:
825265555Sambrisko    mrsas_cam_detach(sc);
826265555Sambriskoattach_fail_fw:
827265555Sambrisko//attach_fail_raidmap:
828265555Sambrisko    mrsas_free_mem(sc);
829265555Sambrisko    mtx_destroy(&sc->sim_lock);
830265555Sambrisko    mtx_destroy(&sc->aen_lock);
831265555Sambrisko    mtx_destroy(&sc->pci_lock);
832265555Sambrisko    mtx_destroy(&sc->io_lock);
833265555Sambrisko    mtx_destroy(&sc->ioctl_lock);
834265555Sambrisko    mtx_destroy(&sc->mpt_cmd_pool_lock);
835265555Sambrisko    mtx_destroy(&sc->mfi_cmd_pool_lock);
836265555Sambrisko    mtx_destroy(&sc->raidmap_lock);
837265555Sambriskoattach_fail:
838265555Sambrisko    destroy_dev(sc->mrsas_cdev);
839265555Sambrisko    if (sc->reg_res){
840265555Sambrisko        bus_release_resource(sc->mrsas_dev, SYS_RES_MEMORY,
841265555Sambrisko                             sc->reg_res_id, sc->reg_res);
842265555Sambrisko    }
843265555Sambrisko    return (ENXIO);
844265555Sambrisko}
845265555Sambrisko
846265555Sambrisko/**
847265555Sambrisko * mrsas_detach:            De-allocates and teardown resources
848265555Sambrisko * input:                   device struct pointer
849265555Sambrisko *
850265555Sambrisko * This function is the entry point for device disconnect and detach.  It
851265555Sambrisko * performs memory de-allocations, shutdown of the controller and various
852265555Sambrisko * teardown and destroy resource functions.
853265555Sambrisko */
854265555Sambriskostatic int mrsas_detach(device_t dev)
855265555Sambrisko{
856265555Sambrisko    struct mrsas_softc *sc;
857265555Sambrisko    int i = 0;
858265555Sambrisko
859265555Sambrisko    sc = device_get_softc(dev);
860265555Sambrisko    sc->remove_in_progress = 1;
861265555Sambrisko    if(sc->ocr_thread_active)
862265555Sambrisko        wakeup(&sc->ocr_chan);
863265555Sambrisko    while(sc->reset_in_progress){
864265555Sambrisko        i++;
865265555Sambrisko        if (!(i % MRSAS_RESET_NOTICE_INTERVAL)) {
866265555Sambrisko            mrsas_dprint(sc, MRSAS_INFO,
867265555Sambrisko                "[%2d]waiting for ocr to be finished\n",i);
868265555Sambrisko        }
869265555Sambrisko        pause("mr_shutdown", hz);
870265555Sambrisko    }
871265555Sambrisko    i = 0;
872265555Sambrisko    while(sc->ocr_thread_active){
873265555Sambrisko        i++;
874265555Sambrisko        if (!(i % MRSAS_RESET_NOTICE_INTERVAL)) {
875265555Sambrisko            mrsas_dprint(sc, MRSAS_INFO,
876265555Sambrisko                "[%2d]waiting for "
877265555Sambrisko                "mrsas_ocr thread to quit ocr %d\n",i,
878265555Sambrisko                 sc->ocr_thread_active);
879265555Sambrisko        }
880265555Sambrisko        pause("mr_shutdown", hz);
881265555Sambrisko    }
882265555Sambrisko    mrsas_flush_cache(sc);
883265555Sambrisko    mrsas_shutdown_ctlr(sc, MR_DCMD_CTRL_SHUTDOWN);
884265555Sambrisko    mrsas_disable_intr(sc);
885265555Sambrisko    mrsas_cam_detach(sc);
886265555Sambrisko    mrsas_teardown_intr(sc);
887265555Sambrisko    mrsas_free_mem(sc);
888265555Sambrisko    mtx_destroy(&sc->sim_lock);
889265555Sambrisko    mtx_destroy(&sc->aen_lock);
890265555Sambrisko    mtx_destroy(&sc->pci_lock);
891265555Sambrisko    mtx_destroy(&sc->io_lock);
892265555Sambrisko    mtx_destroy(&sc->ioctl_lock);
893265555Sambrisko    mtx_destroy(&sc->mpt_cmd_pool_lock);
894265555Sambrisko    mtx_destroy(&sc->mfi_cmd_pool_lock);
895265555Sambrisko    mtx_destroy(&sc->raidmap_lock);
896265555Sambrisko    if (sc->reg_res){
897265555Sambrisko        bus_release_resource(sc->mrsas_dev,
898265555Sambrisko                 SYS_RES_MEMORY, sc->reg_res_id, sc->reg_res);
899265555Sambrisko    }
900265555Sambrisko    destroy_dev(sc->mrsas_cdev);
901265555Sambrisko    if (sc->sysctl_tree != NULL)
902265555Sambrisko        sysctl_ctx_free(&sc->sysctl_ctx);
903265555Sambrisko    return (0);
904265555Sambrisko}
905265555Sambrisko
906265555Sambrisko/**
907265555Sambrisko * mrsas_free_mem:          Frees allocated memory
908265555Sambrisko * input:                   Adapter instance soft state
909265555Sambrisko *
910265555Sambrisko * This function is called from mrsas_detach() to free previously allocated
911265555Sambrisko * memory.
912265555Sambrisko */
913265555Sambriskovoid mrsas_free_mem(struct mrsas_softc *sc)
914265555Sambrisko{
915265555Sambrisko    int i;
916265555Sambrisko    u_int32_t max_cmd;
917265555Sambrisko    struct mrsas_mfi_cmd *mfi_cmd;
918265555Sambrisko    struct mrsas_mpt_cmd *mpt_cmd;
919265555Sambrisko
920265555Sambrisko	/*
921265555Sambrisko     * Free RAID map memory
922265555Sambrisko     */
923265555Sambrisko    for (i=0; i < 2; i++)
924265555Sambrisko    {
925265555Sambrisko        if (sc->raidmap_phys_addr[i])
926265555Sambrisko            bus_dmamap_unload(sc->raidmap_tag[i], sc->raidmap_dmamap[i]);
927265555Sambrisko        if (sc->raidmap_mem[i] != NULL)
928265555Sambrisko            bus_dmamem_free(sc->raidmap_tag[i], sc->raidmap_mem[i], sc->raidmap_dmamap[i]);
929265555Sambrisko        if (sc->raidmap_tag[i] != NULL)
930265555Sambrisko            bus_dma_tag_destroy(sc->raidmap_tag[i]);
931265555Sambrisko    }
932265555Sambrisko
933265555Sambrisko    /*
934265555Sambrisko     * Free version buffer memroy
935265555Sambrisko     */
936265555Sambrisko    if (sc->verbuf_phys_addr)
937265555Sambrisko        bus_dmamap_unload(sc->verbuf_tag, sc->verbuf_dmamap);
938265555Sambrisko    if (sc->verbuf_mem != NULL)
939265555Sambrisko        bus_dmamem_free(sc->verbuf_tag, sc->verbuf_mem, sc->verbuf_dmamap);
940265555Sambrisko    if (sc->verbuf_tag != NULL)
941265555Sambrisko        bus_dma_tag_destroy(sc->verbuf_tag);
942265555Sambrisko
943265555Sambrisko
944265555Sambrisko    /*
945265555Sambrisko     * Free sense buffer memory
946265555Sambrisko     */
947265555Sambrisko    if (sc->sense_phys_addr)
948265555Sambrisko        bus_dmamap_unload(sc->sense_tag, sc->sense_dmamap);
949265555Sambrisko    if (sc->sense_mem != NULL)
950265555Sambrisko        bus_dmamem_free(sc->sense_tag, sc->sense_mem, sc->sense_dmamap);
951265555Sambrisko    if (sc->sense_tag != NULL)
952265555Sambrisko        bus_dma_tag_destroy(sc->sense_tag);
953265555Sambrisko
954265555Sambrisko    /*
955265555Sambrisko     * Free chain frame memory
956265555Sambrisko     */
957265555Sambrisko    if (sc->chain_frame_phys_addr)
958265555Sambrisko        bus_dmamap_unload(sc->chain_frame_tag, sc->chain_frame_dmamap);
959265555Sambrisko    if (sc->chain_frame_mem != NULL)
960265555Sambrisko        bus_dmamem_free(sc->chain_frame_tag, sc->chain_frame_mem, sc->chain_frame_dmamap);
961265555Sambrisko    if (sc->chain_frame_tag != NULL)
962265555Sambrisko        bus_dma_tag_destroy(sc->chain_frame_tag);
963265555Sambrisko
964265555Sambrisko    /*
965265555Sambrisko     * Free IO Request memory
966265555Sambrisko     */
967265555Sambrisko    if (sc->io_request_phys_addr)
968265555Sambrisko        bus_dmamap_unload(sc->io_request_tag, sc->io_request_dmamap);
969265555Sambrisko    if (sc->io_request_mem != NULL)
970265555Sambrisko        bus_dmamem_free(sc->io_request_tag, sc->io_request_mem, sc->io_request_dmamap);
971265555Sambrisko    if (sc->io_request_tag != NULL)
972265555Sambrisko        bus_dma_tag_destroy(sc->io_request_tag);
973265555Sambrisko
974265555Sambrisko    /*
975265555Sambrisko     * Free Reply Descriptor memory
976265555Sambrisko     */
977265555Sambrisko    if (sc->reply_desc_phys_addr)
978265555Sambrisko        bus_dmamap_unload(sc->reply_desc_tag, sc->reply_desc_dmamap);
979265555Sambrisko    if (sc->reply_desc_mem != NULL)
980265555Sambrisko        bus_dmamem_free(sc->reply_desc_tag, sc->reply_desc_mem, sc->reply_desc_dmamap);
981265555Sambrisko    if (sc->reply_desc_tag != NULL)
982265555Sambrisko        bus_dma_tag_destroy(sc->reply_desc_tag);
983265555Sambrisko
984265555Sambrisko    /*
985265555Sambrisko     * Free event detail memory
986265555Sambrisko     */
987265555Sambrisko    if (sc->evt_detail_phys_addr)
988265555Sambrisko        bus_dmamap_unload(sc->evt_detail_tag, sc->evt_detail_dmamap);
989265555Sambrisko    if (sc->evt_detail_mem != NULL)
990265555Sambrisko        bus_dmamem_free(sc->evt_detail_tag, sc->evt_detail_mem, sc->evt_detail_dmamap);
991265555Sambrisko    if (sc->evt_detail_tag != NULL)
992265555Sambrisko        bus_dma_tag_destroy(sc->evt_detail_tag);
993265555Sambrisko
994265555Sambrisko    /*
995265555Sambrisko     * Free MFI frames
996265555Sambrisko     */
997265555Sambrisko	if (sc->mfi_cmd_list) {
998265555Sambrisko    	for (i = 0; i < MRSAS_MAX_MFI_CMDS; i++) {
999265555Sambrisko        	mfi_cmd = sc->mfi_cmd_list[i];
1000265555Sambrisko        	mrsas_free_frame(sc, mfi_cmd);
1001265555Sambrisko		}
1002265555Sambrisko    }
1003265555Sambrisko    if (sc->mficmd_frame_tag != NULL)
1004265555Sambrisko        bus_dma_tag_destroy(sc->mficmd_frame_tag);
1005265555Sambrisko
1006265555Sambrisko    /*
1007265555Sambrisko     * Free MPT internal command list
1008265555Sambrisko     */
1009265555Sambrisko    max_cmd = sc->max_fw_cmds;
1010265555Sambrisko	if (sc->mpt_cmd_list) {
1011265555Sambrisko    	for (i = 0; i < max_cmd; i++) {
1012265555Sambrisko        	mpt_cmd = sc->mpt_cmd_list[i];
1013265555Sambrisko        	bus_dmamap_destroy(sc->data_tag, mpt_cmd->data_dmamap);
1014265555Sambrisko        	free(sc->mpt_cmd_list[i], M_MRSAS);
1015265555Sambrisko    	}
1016265555Sambrisko    	free(sc->mpt_cmd_list, M_MRSAS);
1017265555Sambrisko    	sc->mpt_cmd_list = NULL;
1018265555Sambrisko	}
1019265555Sambrisko
1020265555Sambrisko    /*
1021265555Sambrisko     * Free MFI internal command list
1022265555Sambrisko     */
1023265555Sambrisko
1024265555Sambrisko	if (sc->mfi_cmd_list) {
1025265555Sambrisko    	for (i = 0; i < MRSAS_MAX_MFI_CMDS; i++) {
1026265555Sambrisko        	free(sc->mfi_cmd_list[i], M_MRSAS);
1027265555Sambrisko    	}
1028265555Sambrisko    	free(sc->mfi_cmd_list, M_MRSAS);
1029265555Sambrisko    	sc->mfi_cmd_list = NULL;
1030265555Sambrisko	}
1031265555Sambrisko
1032265555Sambrisko    /*
1033265555Sambrisko     * Free request descriptor memory
1034265555Sambrisko     */
1035265555Sambrisko    free(sc->req_desc, M_MRSAS);
1036265555Sambrisko    sc->req_desc = NULL;
1037265555Sambrisko
1038265555Sambrisko    /*
1039265555Sambrisko     * Destroy parent tag
1040265555Sambrisko     */
1041265555Sambrisko    if (sc->mrsas_parent_tag != NULL)
1042265555Sambrisko        bus_dma_tag_destroy(sc->mrsas_parent_tag);
1043265555Sambrisko}
1044265555Sambrisko
1045265555Sambrisko/**
1046265555Sambrisko * mrsas_teardown_intr:        Teardown interrupt
1047265555Sambrisko * input:                      Adapter instance soft state
1048265555Sambrisko *
1049265555Sambrisko * This function is called from mrsas_detach() to teardown and release
1050265555Sambrisko * bus interrupt resourse.
1051265555Sambrisko */
1052265555Sambriskovoid mrsas_teardown_intr(struct mrsas_softc *sc)
1053265555Sambrisko{
1054265555Sambrisko    if (sc->intr_handle)
1055265555Sambrisko        bus_teardown_intr(sc->mrsas_dev, sc->mrsas_irq, sc->intr_handle);
1056265555Sambrisko    if (sc->mrsas_irq != NULL)
1057265555Sambrisko        bus_release_resource(sc->mrsas_dev, SYS_RES_IRQ, sc->irq_id, sc->mrsas_irq);
1058265555Sambrisko    sc->intr_handle = NULL;
1059265555Sambrisko}
1060265555Sambrisko
1061265555Sambrisko/**
1062265555Sambrisko * mrsas_suspend:          Suspend entry point
1063265555Sambrisko * input:                  Device struct pointer
1064265555Sambrisko *
1065265555Sambrisko * This function is the entry point for system suspend from the OS.
1066265555Sambrisko */
1067265555Sambriskostatic int mrsas_suspend(device_t dev)
1068265555Sambrisko{
1069265555Sambrisko    struct mrsas_softc *sc;
1070265555Sambrisko
1071265555Sambrisko    sc = device_get_softc(dev);
1072265555Sambrisko    return (0);
1073265555Sambrisko}
1074265555Sambrisko
1075265555Sambrisko/**
1076265555Sambrisko * mrsas_resume:           Resume entry point
1077265555Sambrisko * input:                  Device struct pointer
1078265555Sambrisko *
1079265555Sambrisko * This function is the entry point for system resume from the OS.
1080265555Sambrisko */
1081265555Sambriskostatic int mrsas_resume(device_t dev)
1082265555Sambrisko{
1083265555Sambrisko    struct mrsas_softc *sc;
1084265555Sambrisko
1085265555Sambrisko    sc = device_get_softc(dev);
1086265555Sambrisko    return (0);
1087265555Sambrisko}
1088265555Sambrisko
1089265555Sambrisko/**
1090265555Sambrisko * mrsas_ioctl:       IOCtl commands entry point.
1091265555Sambrisko *
1092265555Sambrisko * This function is the entry point for IOCtls from the OS.  It calls the
1093265555Sambrisko * appropriate function for processing depending on the command received.
1094265555Sambrisko */
1095265555Sambriskostatic int
1096265555Sambriskomrsas_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td)
1097265555Sambrisko{
1098265555Sambrisko    struct mrsas_softc *sc;
1099265555Sambrisko    int ret = 0, i = 0;
1100265555Sambrisko
1101265555Sambrisko    sc = (struct mrsas_softc *)(dev->si_drv1);
1102265555Sambrisko
1103265555Sambrisko    if (sc->remove_in_progress) {
1104265555Sambrisko        mrsas_dprint(sc, MRSAS_INFO,
1105265555Sambrisko            "Driver remove or shutdown called.\n");
1106265555Sambrisko        return ENOENT;
1107265555Sambrisko    }
1108265555Sambrisko
1109265555Sambrisko    mtx_lock_spin(&sc->ioctl_lock);
1110265555Sambrisko    if (!sc->reset_in_progress) {
1111265555Sambrisko        mtx_unlock_spin(&sc->ioctl_lock);
1112265555Sambrisko        goto do_ioctl;
1113265555Sambrisko    }
1114265555Sambrisko
1115265555Sambrisko    /* Release ioclt_lock, and wait for OCR
1116265555Sambrisko     * to be finished */
1117265555Sambrisko    mtx_unlock_spin(&sc->ioctl_lock);
1118265555Sambrisko    while(sc->reset_in_progress){
1119265555Sambrisko        i++;
1120265555Sambrisko        if (!(i % MRSAS_RESET_NOTICE_INTERVAL)) {
1121265555Sambrisko            mrsas_dprint(sc, MRSAS_INFO,
1122265555Sambrisko                "[%2d]waiting for "
1123265555Sambrisko                "OCR to be finished %d\n",i,
1124265555Sambrisko                 sc->ocr_thread_active);
1125265555Sambrisko        }
1126265555Sambrisko        pause("mr_ioctl", hz);
1127265555Sambrisko    }
1128265555Sambrisko
1129265555Sambriskodo_ioctl:
1130265555Sambrisko    switch (cmd) {
1131265555Sambrisko        case MRSAS_IOC_FIRMWARE_PASS_THROUGH:
1132265555Sambrisko            ret = mrsas_passthru(sc, (void *)arg);
1133265555Sambrisko            break;
1134265555Sambrisko        case MRSAS_IOC_SCAN_BUS:
1135265555Sambrisko            ret = mrsas_bus_scan(sc);
1136265555Sambrisko            break;
1137265555Sambrisko    }
1138265555Sambrisko
1139265555Sambrisko    return (ret);
1140265555Sambrisko}
1141265555Sambrisko
1142265555Sambrisko/**
1143265555Sambrisko * mrsas_setup_irq:   Set up interrupt.
1144265555Sambrisko * input:             Adapter instance soft state
1145265555Sambrisko *
1146265555Sambrisko * This function sets up interrupts as a bus resource, with flags indicating
1147265555Sambrisko * resource permitting contemporaneous sharing and for resource to activate
1148265555Sambrisko * atomically.
1149265555Sambrisko */
1150265555Sambriskostatic int mrsas_setup_irq(struct mrsas_softc *sc)
1151265555Sambrisko{
1152265555Sambrisko    sc->irq_id = 0;
1153265555Sambrisko    sc->mrsas_irq = bus_alloc_resource_any(sc->mrsas_dev, SYS_RES_IRQ,
1154265555Sambrisko                        &sc->irq_id, RF_SHAREABLE | RF_ACTIVE);
1155265555Sambrisko    if (sc->mrsas_irq == NULL){
1156265555Sambrisko        device_printf(sc->mrsas_dev, "Cannot allocate interrupt\n");
1157265555Sambrisko        return (FAIL);
1158265555Sambrisko    }
1159265555Sambrisko    if (bus_setup_intr(sc->mrsas_dev, sc->mrsas_irq, INTR_MPSAFE|INTR_TYPE_CAM,
1160265555Sambrisko                       NULL, mrsas_isr, sc, &sc->intr_handle)) {
1161265555Sambrisko        device_printf(sc->mrsas_dev, "Cannot set up interrupt\n");
1162265555Sambrisko        return (FAIL);
1163265555Sambrisko    }
1164265555Sambrisko
1165265555Sambrisko    return (0);
1166265555Sambrisko}
1167265555Sambrisko
1168265555Sambrisko/*
1169265555Sambrisko * mrsas_isr:        ISR entry point
1170265555Sambrisko * input:            argument pointer
1171265555Sambrisko *
1172265555Sambrisko * This function is the interrupt service routine entry point.  There
1173265555Sambrisko * are two types of interrupts, state change interrupt and response
1174265555Sambrisko * interrupt.  If an interrupt is not ours, we just return.
1175265555Sambrisko */
1176265555Sambriskovoid mrsas_isr(void *arg)
1177265555Sambrisko{
1178265555Sambrisko    struct mrsas_softc *sc = (struct mrsas_softc *)arg;
1179265555Sambrisko    int status;
1180265555Sambrisko
1181265555Sambrisko    /* Clear FW state change interrupt */
1182265555Sambrisko    status = mrsas_clear_intr(sc);
1183265555Sambrisko
1184265555Sambrisko    /* Not our interrupt */
1185265555Sambrisko    if (!status)
1186265555Sambrisko        return;
1187265555Sambrisko
1188265555Sambrisko    /* If we are resetting, bail */
1189265555Sambrisko    if (test_bit(MRSAS_FUSION_IN_RESET, &sc->reset_flags)) {
1190265555Sambrisko        printf(" Entered into ISR when OCR is going active. \n");
1191265555Sambrisko        mrsas_clear_intr(sc);
1192265555Sambrisko        return;
1193265555Sambrisko    }
1194265555Sambrisko    /* Process for reply request and clear response interrupt */
1195265555Sambrisko    if (mrsas_complete_cmd(sc) != SUCCESS)
1196265555Sambrisko        mrsas_clear_intr(sc);
1197265555Sambrisko
1198265555Sambrisko    return;
1199265555Sambrisko}
1200265555Sambrisko
1201265555Sambrisko/*
1202265555Sambrisko * mrsas_complete_cmd:        Process reply request
1203265555Sambrisko * input:                     Adapter instance soft state
1204265555Sambrisko *
1205265555Sambrisko * This function is called from mrsas_isr() to process reply request and
1206265555Sambrisko * clear response interrupt. Processing of the reply request entails
1207265555Sambrisko * walking through the reply descriptor array for the command request
1208265555Sambrisko * pended from Firmware.  We look at the Function field to determine
1209265555Sambrisko * the command type and perform the appropriate action.  Before we
1210265555Sambrisko * return, we clear the response interrupt.
1211265555Sambrisko */
1212265555Sambriskostatic int mrsas_complete_cmd(struct mrsas_softc *sc)
1213265555Sambrisko{
1214265555Sambrisko    Mpi2ReplyDescriptorsUnion_t *desc;
1215265555Sambrisko    MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR *reply_desc;
1216265555Sambrisko    MRSAS_RAID_SCSI_IO_REQUEST  *scsi_io_req;
1217265555Sambrisko    struct mrsas_mpt_cmd *cmd_mpt;
1218265555Sambrisko    struct mrsas_mfi_cmd *cmd_mfi;
1219265555Sambrisko    u_int8_t arm, reply_descript_type;
1220265555Sambrisko    u_int16_t smid, num_completed;
1221265555Sambrisko    u_int8_t status, extStatus;
1222265555Sambrisko    union desc_value desc_val;
1223265555Sambrisko    PLD_LOAD_BALANCE_INFO lbinfo;
1224265555Sambrisko    u_int32_t device_id;
1225265555Sambrisko    int threshold_reply_count = 0;
1226265555Sambrisko
1227265555Sambrisko
1228265555Sambrisko    /* If we have a hardware error, not need to continue */
1229265555Sambrisko    if (sc->adprecovery == MRSAS_HW_CRITICAL_ERROR)
1230265555Sambrisko        return (DONE);
1231265555Sambrisko
1232265555Sambrisko    desc = sc->reply_desc_mem;
1233265555Sambrisko    desc += sc->last_reply_idx;
1234265555Sambrisko
1235265555Sambrisko    reply_desc = (MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR *)desc;
1236265555Sambrisko
1237265555Sambrisko    desc_val.word = desc->Words;
1238265555Sambrisko    num_completed = 0;
1239265555Sambrisko
1240265555Sambrisko    reply_descript_type = reply_desc->ReplyFlags & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK;
1241265555Sambrisko
1242265555Sambrisko    /* Find our reply descriptor for the command and process */
1243265555Sambrisko    while((desc_val.u.low != 0xFFFFFFFF) && (desc_val.u.high != 0xFFFFFFFF))
1244265555Sambrisko    {
1245265555Sambrisko        smid = reply_desc->SMID;
1246265555Sambrisko        cmd_mpt = sc->mpt_cmd_list[smid -1];
1247265555Sambrisko        scsi_io_req = (MRSAS_RAID_SCSI_IO_REQUEST *)cmd_mpt->io_request;
1248265555Sambrisko
1249265555Sambrisko        status = scsi_io_req->RaidContext.status;
1250265555Sambrisko        extStatus = scsi_io_req->RaidContext.exStatus;
1251265555Sambrisko
1252265555Sambrisko        switch (scsi_io_req->Function)
1253265555Sambrisko        {
1254265555Sambrisko            case MPI2_FUNCTION_SCSI_IO_REQUEST :  /*Fast Path IO.*/
1255265555Sambrisko                device_id = cmd_mpt->ccb_ptr->ccb_h.target_id;
1256265555Sambrisko                lbinfo = &sc->load_balance_info[device_id];
1257265555Sambrisko                if (cmd_mpt->load_balance == MRSAS_LOAD_BALANCE_FLAG) {
1258265555Sambrisko                    arm = lbinfo->raid1DevHandle[0] == scsi_io_req->DevHandle ? 0 : 1;
1259265555Sambrisko                    atomic_dec(&lbinfo->scsi_pending_cmds[arm]);
1260265555Sambrisko                    cmd_mpt->load_balance &= ~MRSAS_LOAD_BALANCE_FLAG;
1261265555Sambrisko                }
1262265555Sambrisko                //Fall thru and complete IO
1263265555Sambrisko            case MRSAS_MPI2_FUNCTION_LD_IO_REQUEST:
1264265555Sambrisko                mrsas_map_mpt_cmd_status(cmd_mpt, status, extStatus);
1265265555Sambrisko                mrsas_cmd_done(sc, cmd_mpt);
1266265555Sambrisko                scsi_io_req->RaidContext.status = 0;
1267265555Sambrisko                scsi_io_req->RaidContext.exStatus = 0;
1268265555Sambrisko                atomic_dec(&sc->fw_outstanding);
1269265555Sambrisko                break;
1270265555Sambrisko            case MRSAS_MPI2_FUNCTION_PASSTHRU_IO_REQUEST: /*MFI command */
1271265555Sambrisko                cmd_mfi = sc->mfi_cmd_list[cmd_mpt->sync_cmd_idx];
1272265555Sambrisko                mrsas_complete_mptmfi_passthru(sc, cmd_mfi, status);
1273265555Sambrisko                cmd_mpt->flags = 0;
1274265555Sambrisko                mrsas_release_mpt_cmd(cmd_mpt);
1275265555Sambrisko                break;
1276265555Sambrisko        }
1277265555Sambrisko
1278265555Sambrisko        sc->last_reply_idx++;
1279265555Sambrisko        if (sc->last_reply_idx >= sc->reply_q_depth)
1280265555Sambrisko            sc->last_reply_idx = 0;
1281265555Sambrisko
1282265555Sambrisko        desc->Words = ~((uint64_t)0x00); /* set it back to all 0xFFFFFFFFs */
1283265555Sambrisko        num_completed++;
1284265555Sambrisko        threshold_reply_count++;
1285265555Sambrisko
1286265555Sambrisko        /* Get the next reply descriptor */
1287265555Sambrisko        if (!sc->last_reply_idx)
1288265555Sambrisko            desc = sc->reply_desc_mem;
1289265555Sambrisko        else
1290265555Sambrisko            desc++;
1291265555Sambrisko
1292265555Sambrisko        reply_desc = (MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR *)desc;
1293265555Sambrisko        desc_val.word = desc->Words;
1294265555Sambrisko
1295265555Sambrisko        reply_descript_type = reply_desc->ReplyFlags & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK;
1296265555Sambrisko
1297265555Sambrisko        if(reply_descript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED)
1298265555Sambrisko            break;
1299265555Sambrisko
1300265555Sambrisko        /*
1301265555Sambrisko         * Write to reply post index after completing threshold reply count
1302265555Sambrisko         * and still there are more replies in reply queue pending to be
1303265555Sambrisko         * completed.
1304265555Sambrisko         */
1305265555Sambrisko        if (threshold_reply_count >= THRESHOLD_REPLY_COUNT) {
1306265555Sambrisko            mrsas_write_reg(sc, offsetof(mrsas_reg_set, reply_post_host_index),
1307265555Sambrisko                            sc->last_reply_idx);
1308265555Sambrisko            threshold_reply_count = 0;
1309265555Sambrisko        }
1310265555Sambrisko    }
1311265555Sambrisko
1312265555Sambrisko    /* No match, just return */
1313265555Sambrisko    if (num_completed == 0)
1314265555Sambrisko        return (DONE);
1315265555Sambrisko
1316265555Sambrisko    /* Clear response interrupt */
1317265555Sambrisko    mrsas_write_reg(sc, offsetof(mrsas_reg_set, reply_post_host_index),sc->last_reply_idx);
1318265555Sambrisko
1319265555Sambrisko    return(0);
1320265555Sambrisko}
1321265555Sambrisko
1322265555Sambrisko/*
1323265555Sambrisko * mrsas_map_mpt_cmd_status:  Allocate DMAable memory.
1324265555Sambrisko * input:                     Adapter instance soft state
1325265555Sambrisko *
1326265555Sambrisko * This function is called from mrsas_complete_cmd(), for LD IO and FastPath IO.
1327265555Sambrisko * It checks the command status and maps the appropriate CAM status for the CCB.
1328265555Sambrisko */
1329265555Sambriskovoid mrsas_map_mpt_cmd_status(struct mrsas_mpt_cmd *cmd, u_int8_t status, u_int8_t extStatus)
1330265555Sambrisko{
1331265555Sambrisko    struct mrsas_softc *sc = cmd->sc;
1332265555Sambrisko    u_int8_t *sense_data;
1333265555Sambrisko
1334265555Sambrisko    switch (status) {
1335265555Sambrisko        case MFI_STAT_OK:
1336265555Sambrisko            cmd->ccb_ptr->ccb_h.status = CAM_REQ_CMP;
1337265555Sambrisko            break;
1338265555Sambrisko        case MFI_STAT_SCSI_IO_FAILED:
1339265555Sambrisko        case MFI_STAT_SCSI_DONE_WITH_ERROR:
1340265555Sambrisko            cmd->ccb_ptr->ccb_h.status = CAM_SCSI_STATUS_ERROR;
1341265555Sambrisko            sense_data = (u_int8_t *)&cmd->ccb_ptr->csio.sense_data;
1342265555Sambrisko            if (sense_data) {
1343265555Sambrisko                /* For now just copy 18 bytes back */
1344265555Sambrisko                memcpy(sense_data, cmd->sense, 18);
1345265555Sambrisko                cmd->ccb_ptr->csio.sense_len = 18;
1346265555Sambrisko                cmd->ccb_ptr->ccb_h.status |= CAM_AUTOSNS_VALID;
1347265555Sambrisko            }
1348265555Sambrisko            break;
1349265555Sambrisko        case MFI_STAT_LD_OFFLINE:
1350265555Sambrisko        case MFI_STAT_DEVICE_NOT_FOUND:
1351265555Sambrisko            if (cmd->ccb_ptr->ccb_h.target_lun)
1352265555Sambrisko                cmd->ccb_ptr->ccb_h.status |= CAM_LUN_INVALID;
1353265555Sambrisko            else
1354265555Sambrisko                cmd->ccb_ptr->ccb_h.status |= CAM_DEV_NOT_THERE;
1355265555Sambrisko            break;
1356265555Sambrisko        case MFI_STAT_CONFIG_SEQ_MISMATCH:
1357265555Sambrisko            /*send status to CAM layer to retry sending  command without
1358265555Sambrisko             * decrementing retry counter*/
1359265555Sambrisko            cmd->ccb_ptr->ccb_h.status |= CAM_REQUEUE_REQ;
1360265555Sambrisko            break;
1361265555Sambrisko        default:
1362265555Sambrisko            device_printf(sc->mrsas_dev, "FW cmd complete status %x\n", status);
1363265555Sambrisko            cmd->ccb_ptr->ccb_h.status = CAM_REQ_CMP_ERR;
1364265555Sambrisko            cmd->ccb_ptr->csio.scsi_status = status;
1365265555Sambrisko    }
1366265555Sambrisko    return;
1367265555Sambrisko}
1368265555Sambrisko
1369265555Sambrisko/*
1370265555Sambrisko * mrsas_alloc_mem:  Allocate DMAable memory.
1371265555Sambrisko * input:            Adapter instance soft state
1372265555Sambrisko *
1373265555Sambrisko * This function creates the parent DMA tag and allocates DMAable memory.
1374265555Sambrisko * DMA tag describes constraints of DMA mapping. Memory allocated is mapped
1375265555Sambrisko * into Kernel virtual address. Callback argument is physical memory address.
1376265555Sambrisko */
1377265555Sambriskostatic int mrsas_alloc_mem(struct mrsas_softc *sc)
1378265555Sambrisko{
1379265555Sambrisko    u_int32_t verbuf_size, io_req_size, reply_desc_size, sense_size,
1380265555Sambrisko              chain_frame_size, evt_detail_size;
1381265555Sambrisko
1382265555Sambrisko    /*
1383265555Sambrisko     * Allocate parent DMA tag
1384265555Sambrisko     */
1385265555Sambrisko    if (bus_dma_tag_create(NULL,                   /* parent */
1386265555Sambrisko                           1,         /* alignment */
1387265555Sambrisko                           0,                      /* boundary */
1388265555Sambrisko                           BUS_SPACE_MAXADDR,     /* lowaddr */
1389265555Sambrisko                           BUS_SPACE_MAXADDR,      /* highaddr */
1390265555Sambrisko                           NULL, NULL,             /* filter, filterarg */
1391265555Sambrisko                           MRSAS_MAX_IO_SIZE,/* maxsize */
1392265555Sambrisko                           MRSAS_MAX_SGL, /* nsegments */
1393265555Sambrisko                           MRSAS_MAX_IO_SIZE,/* maxsegsize */
1394265555Sambrisko                           0,                      /* flags */
1395265555Sambrisko                           NULL, NULL,             /* lockfunc, lockarg */
1396265555Sambrisko                           &sc->mrsas_parent_tag   /* tag */
1397265555Sambrisko                           )) {
1398265555Sambrisko           device_printf(sc->mrsas_dev, "Cannot allocate parent DMA tag\n");
1399265555Sambrisko           return(ENOMEM);
1400265555Sambrisko    }
1401265555Sambrisko
1402265555Sambrisko    /*
1403265555Sambrisko     * Allocate for version buffer
1404265555Sambrisko     */
1405265555Sambrisko    verbuf_size = MRSAS_MAX_NAME_LENGTH*(sizeof(bus_addr_t));
1406265555Sambrisko    if (bus_dma_tag_create(sc->mrsas_parent_tag,   // parent
1407265555Sambrisko                           1, 0,                   // algnmnt, boundary
1408265555Sambrisko                           BUS_SPACE_MAXADDR_32BIT,// lowaddr
1409265555Sambrisko                           BUS_SPACE_MAXADDR,      // highaddr
1410265555Sambrisko                           NULL, NULL,             // filter, filterarg
1411265555Sambrisko                           verbuf_size,           // maxsize
1412265555Sambrisko                           1,                      // msegments
1413265555Sambrisko                           verbuf_size,           // maxsegsize
1414265555Sambrisko                           BUS_DMA_ALLOCNOW,       // flags
1415265555Sambrisko                           NULL, NULL,             // lockfunc, lockarg
1416265555Sambrisko                           &sc->verbuf_tag)) {
1417265555Sambrisko            device_printf(sc->mrsas_dev, "Cannot allocate verbuf DMA tag\n");
1418265555Sambrisko            return (ENOMEM);
1419265555Sambrisko    }
1420265555Sambrisko    if (bus_dmamem_alloc(sc->verbuf_tag, (void **)&sc->verbuf_mem,
1421265555Sambrisko        BUS_DMA_NOWAIT, &sc->verbuf_dmamap)) {
1422265555Sambrisko            device_printf(sc->mrsas_dev, "Cannot allocate verbuf memory\n");
1423265555Sambrisko            return (ENOMEM);
1424265555Sambrisko    }
1425265555Sambrisko    bzero(sc->verbuf_mem, verbuf_size);
1426265555Sambrisko    if (bus_dmamap_load(sc->verbuf_tag, sc->verbuf_dmamap, sc->verbuf_mem,
1427265555Sambrisko        verbuf_size, mrsas_addr_cb, &sc->verbuf_phys_addr, BUS_DMA_NOWAIT)){
1428265555Sambrisko            device_printf(sc->mrsas_dev, "Cannot load verbuf DMA map\n");
1429265555Sambrisko            return(ENOMEM);
1430265555Sambrisko    }
1431265555Sambrisko
1432265555Sambrisko    /*
1433265555Sambrisko     * Allocate IO Request Frames
1434265555Sambrisko     */
1435265555Sambrisko    io_req_size = sc->io_frames_alloc_sz;
1436265555Sambrisko    if (bus_dma_tag_create( sc->mrsas_parent_tag,   // parent
1437265555Sambrisko                            16, 0,                   // algnmnt, boundary
1438265555Sambrisko                            BUS_SPACE_MAXADDR_32BIT,// lowaddr
1439265555Sambrisko                            BUS_SPACE_MAXADDR,      // highaddr
1440265555Sambrisko                            NULL, NULL,             // filter, filterarg
1441265555Sambrisko                            io_req_size,            // maxsize
1442265555Sambrisko                            1,                      // msegments
1443265555Sambrisko                            io_req_size,            // maxsegsize
1444265555Sambrisko                            BUS_DMA_ALLOCNOW,       // flags
1445265555Sambrisko                            NULL, NULL,             // lockfunc, lockarg
1446265555Sambrisko                            &sc->io_request_tag)) {
1447265555Sambrisko        device_printf(sc->mrsas_dev, "Cannot create IO request tag\n");
1448265555Sambrisko        return (ENOMEM);
1449265555Sambrisko    }
1450265555Sambrisko    if (bus_dmamem_alloc(sc->io_request_tag, (void **)&sc->io_request_mem,
1451265555Sambrisko                    BUS_DMA_NOWAIT, &sc->io_request_dmamap)) {
1452265555Sambrisko        device_printf(sc->mrsas_dev, "Cannot alloc IO request memory\n");
1453265555Sambrisko        return (ENOMEM);
1454265555Sambrisko    }
1455265555Sambrisko    bzero(sc->io_request_mem, io_req_size);
1456265555Sambrisko    if (bus_dmamap_load(sc->io_request_tag, sc->io_request_dmamap,
1457265555Sambrisko                        sc->io_request_mem, io_req_size, mrsas_addr_cb,
1458265555Sambrisko                        &sc->io_request_phys_addr, BUS_DMA_NOWAIT)) {
1459265555Sambrisko        device_printf(sc->mrsas_dev, "Cannot load IO request memory\n");
1460265555Sambrisko        return (ENOMEM);
1461265555Sambrisko    }
1462265555Sambrisko
1463265555Sambrisko    /*
1464265555Sambrisko     * Allocate Chain Frames
1465265555Sambrisko     */
1466265555Sambrisko    chain_frame_size = sc->chain_frames_alloc_sz;
1467265555Sambrisko    if (bus_dma_tag_create( sc->mrsas_parent_tag,   // parent
1468265555Sambrisko                            4, 0,                   // algnmnt, boundary
1469265555Sambrisko                            BUS_SPACE_MAXADDR_32BIT,// lowaddr
1470265555Sambrisko                            BUS_SPACE_MAXADDR,      // highaddr
1471265555Sambrisko                            NULL, NULL,             // filter, filterarg
1472265555Sambrisko                            chain_frame_size,       // maxsize
1473265555Sambrisko                            1,                      // msegments
1474265555Sambrisko                            chain_frame_size,       // maxsegsize
1475265555Sambrisko                            BUS_DMA_ALLOCNOW,       // flags
1476265555Sambrisko                            NULL, NULL,             // lockfunc, lockarg
1477265555Sambrisko                            &sc->chain_frame_tag)) {
1478265555Sambrisko        device_printf(sc->mrsas_dev, "Cannot create chain frame tag\n");
1479265555Sambrisko        return (ENOMEM);
1480265555Sambrisko    }
1481265555Sambrisko    if (bus_dmamem_alloc(sc->chain_frame_tag, (void **)&sc->chain_frame_mem,
1482265555Sambrisko                    BUS_DMA_NOWAIT, &sc->chain_frame_dmamap)) {
1483265555Sambrisko        device_printf(sc->mrsas_dev, "Cannot alloc chain frame memory\n");
1484265555Sambrisko        return (ENOMEM);
1485265555Sambrisko    }
1486265555Sambrisko    bzero(sc->chain_frame_mem, chain_frame_size);
1487265555Sambrisko    if (bus_dmamap_load(sc->chain_frame_tag, sc->chain_frame_dmamap,
1488265555Sambrisko                        sc->chain_frame_mem, chain_frame_size, mrsas_addr_cb,
1489265555Sambrisko                        &sc->chain_frame_phys_addr, BUS_DMA_NOWAIT)) {
1490265555Sambrisko        device_printf(sc->mrsas_dev, "Cannot load chain frame memory\n");
1491265555Sambrisko        return (ENOMEM);
1492265555Sambrisko    }
1493265555Sambrisko
1494265555Sambrisko    /*
1495265555Sambrisko     * Allocate Reply Descriptor Array
1496265555Sambrisko     */
1497265555Sambrisko    reply_desc_size = sc->reply_alloc_sz;
1498265555Sambrisko    if (bus_dma_tag_create( sc->mrsas_parent_tag,   // parent
1499265555Sambrisko                            16, 0,                   // algnmnt, boundary
1500265555Sambrisko                            BUS_SPACE_MAXADDR_32BIT,// lowaddr
1501265555Sambrisko                            BUS_SPACE_MAXADDR,      // highaddr
1502265555Sambrisko                            NULL, NULL,             // filter, filterarg
1503265555Sambrisko                            reply_desc_size,        // maxsize
1504265555Sambrisko                            1,                      // msegments
1505265555Sambrisko                            reply_desc_size,        // maxsegsize
1506265555Sambrisko                            BUS_DMA_ALLOCNOW,       // flags
1507265555Sambrisko                            NULL, NULL,             // lockfunc, lockarg
1508265555Sambrisko                            &sc->reply_desc_tag)) {
1509265555Sambrisko        device_printf(sc->mrsas_dev, "Cannot create reply descriptor tag\n");
1510265555Sambrisko        return (ENOMEM);
1511265555Sambrisko    }
1512265555Sambrisko    if (bus_dmamem_alloc(sc->reply_desc_tag, (void **)&sc->reply_desc_mem,
1513265555Sambrisko                    BUS_DMA_NOWAIT, &sc->reply_desc_dmamap)) {
1514265555Sambrisko        device_printf(sc->mrsas_dev, "Cannot alloc reply descriptor memory\n");
1515265555Sambrisko        return (ENOMEM);
1516265555Sambrisko    }
1517265555Sambrisko    if (bus_dmamap_load(sc->reply_desc_tag, sc->reply_desc_dmamap,
1518265555Sambrisko                        sc->reply_desc_mem, reply_desc_size, mrsas_addr_cb,
1519265555Sambrisko                        &sc->reply_desc_phys_addr, BUS_DMA_NOWAIT)) {
1520265555Sambrisko        device_printf(sc->mrsas_dev, "Cannot load reply descriptor memory\n");
1521265555Sambrisko        return (ENOMEM);
1522265555Sambrisko    }
1523265555Sambrisko
1524265555Sambrisko    /*
1525265555Sambrisko     * Allocate Sense Buffer Array.  Keep in lower 4GB
1526265555Sambrisko     */
1527265555Sambrisko    sense_size = sc->max_fw_cmds * MRSAS_SENSE_LEN;
1528265555Sambrisko    if (bus_dma_tag_create(sc->mrsas_parent_tag,    // parent
1529265555Sambrisko                            64, 0,                   // algnmnt, boundary
1530265555Sambrisko                            BUS_SPACE_MAXADDR_32BIT,// lowaddr
1531265555Sambrisko                            BUS_SPACE_MAXADDR,      // highaddr
1532265555Sambrisko                            NULL, NULL,             // filter, filterarg
1533265555Sambrisko                            sense_size,             // maxsize
1534265555Sambrisko                            1,                      // nsegments
1535265555Sambrisko                            sense_size,             // maxsegsize
1536265555Sambrisko                            BUS_DMA_ALLOCNOW,       // flags
1537265555Sambrisko                            NULL, NULL,             // lockfunc, lockarg
1538265555Sambrisko                            &sc->sense_tag)) {
1539265555Sambrisko        device_printf(sc->mrsas_dev, "Cannot allocate sense buf tag\n");
1540265555Sambrisko        return (ENOMEM);
1541265555Sambrisko    }
1542265555Sambrisko    if (bus_dmamem_alloc(sc->sense_tag, (void **)&sc->sense_mem,
1543265555Sambrisko            BUS_DMA_NOWAIT, &sc->sense_dmamap)) {
1544265555Sambrisko        device_printf(sc->mrsas_dev, "Cannot allocate sense buf memory\n");
1545265555Sambrisko        return (ENOMEM);
1546265555Sambrisko    }
1547265555Sambrisko    if (bus_dmamap_load(sc->sense_tag, sc->sense_dmamap,
1548265555Sambrisko            sc->sense_mem, sense_size, mrsas_addr_cb, &sc->sense_phys_addr,
1549265555Sambrisko            BUS_DMA_NOWAIT)){
1550265555Sambrisko        device_printf(sc->mrsas_dev, "Cannot load sense buf memory\n");
1551265555Sambrisko        return (ENOMEM);
1552265555Sambrisko    }
1553265555Sambrisko
1554265555Sambrisko    /*
1555265555Sambrisko     * Allocate for Event detail structure
1556265555Sambrisko     */
1557265555Sambrisko    evt_detail_size = sizeof(struct mrsas_evt_detail);
1558265555Sambrisko    if (bus_dma_tag_create( sc->mrsas_parent_tag,   // parent
1559265555Sambrisko                            1, 0,                   // algnmnt, boundary
1560265555Sambrisko                            BUS_SPACE_MAXADDR_32BIT,// lowaddr
1561265555Sambrisko                            BUS_SPACE_MAXADDR,      // highaddr
1562265555Sambrisko                            NULL, NULL,             // filter, filterarg
1563265555Sambrisko                            evt_detail_size,        // maxsize
1564265555Sambrisko                            1,                      // msegments
1565265555Sambrisko                            evt_detail_size,        // maxsegsize
1566265555Sambrisko                            BUS_DMA_ALLOCNOW,       // flags
1567265555Sambrisko                            NULL, NULL,             // lockfunc, lockarg
1568265555Sambrisko                            &sc->evt_detail_tag)) {
1569265555Sambrisko        device_printf(sc->mrsas_dev, "Cannot create Event detail tag\n");
1570265555Sambrisko        return (ENOMEM);
1571265555Sambrisko    }
1572265555Sambrisko    if (bus_dmamem_alloc(sc->evt_detail_tag, (void **)&sc->evt_detail_mem,
1573265555Sambrisko                    BUS_DMA_NOWAIT, &sc->evt_detail_dmamap)) {
1574265555Sambrisko        device_printf(sc->mrsas_dev, "Cannot alloc Event detail buffer memory\n");
1575265555Sambrisko        return (ENOMEM);
1576265555Sambrisko    }
1577265555Sambrisko    bzero(sc->evt_detail_mem, evt_detail_size);
1578265555Sambrisko    if (bus_dmamap_load(sc->evt_detail_tag, sc->evt_detail_dmamap,
1579265555Sambrisko                        sc->evt_detail_mem, evt_detail_size, mrsas_addr_cb,
1580265555Sambrisko                        &sc->evt_detail_phys_addr, BUS_DMA_NOWAIT)) {
1581265555Sambrisko        device_printf(sc->mrsas_dev, "Cannot load Event detail buffer memory\n");
1582265555Sambrisko        return (ENOMEM);
1583265555Sambrisko    }
1584265555Sambrisko
1585265555Sambrisko
1586265555Sambrisko   /*
1587265555Sambrisko    * Create a dma tag for data buffers; size will be the maximum
1588265555Sambrisko    * possible I/O size (280kB).
1589265555Sambrisko    */
1590265555Sambrisko    if (bus_dma_tag_create(sc->mrsas_parent_tag,   // parent
1591265555Sambrisko                           1,         // alignment
1592265555Sambrisko                           0,                      // boundary
1593265555Sambrisko                           BUS_SPACE_MAXADDR,      // lowaddr
1594265555Sambrisko                           BUS_SPACE_MAXADDR,      // highaddr
1595265555Sambrisko                           NULL, NULL,             // filter, filterarg
1596265555Sambrisko                           MRSAS_MAX_IO_SIZE,      // maxsize
1597265555Sambrisko                           MRSAS_MAX_SGL,          // nsegments
1598265555Sambrisko                           MRSAS_MAX_IO_SIZE,      // maxsegsize
1599265555Sambrisko                           BUS_DMA_ALLOCNOW,       // flags
1600265555Sambrisko                           busdma_lock_mutex,      // lockfunc
1601265555Sambrisko                           &sc->io_lock,           // lockfuncarg
1602265555Sambrisko                           &sc->data_tag)) {
1603265555Sambrisko        device_printf(sc->mrsas_dev, "Cannot create data dma tag\n");
1604265555Sambrisko        return(ENOMEM);
1605265555Sambrisko    }
1606265555Sambrisko
1607265555Sambrisko    return(0);
1608265555Sambrisko}
1609265555Sambrisko
1610265555Sambrisko/*
1611265555Sambrisko * mrsas_addr_cb:   Callback function of bus_dmamap_load()
1612265555Sambrisko * input:           callback argument,
1613265555Sambrisko *                  machine dependent type that describes DMA segments,
1614265555Sambrisko *                  number of segments,
1615265555Sambrisko *                  error code.
1616265555Sambrisko *
1617265555Sambrisko * This function is for the driver to receive mapping information resultant
1618265555Sambrisko * of the bus_dmamap_load(). The information is actually not being used,
1619265555Sambrisko * but the address is saved anyway.
1620265555Sambrisko */
1621265555Sambriskovoid
1622265555Sambriskomrsas_addr_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
1623265555Sambrisko{
1624265555Sambrisko    bus_addr_t *addr;
1625265555Sambrisko
1626265555Sambrisko    addr = arg;
1627265555Sambrisko    *addr = segs[0].ds_addr;
1628265555Sambrisko}
1629265555Sambrisko
1630265555Sambrisko/*
1631265555Sambrisko * mrsas_setup_raidmap:  Set up RAID map.
1632265555Sambrisko * input:                Adapter instance soft state
1633265555Sambrisko *
1634265555Sambrisko * Allocate DMA memory for the RAID maps and perform setup.
1635265555Sambrisko */
1636265555Sambriskostatic int mrsas_setup_raidmap(struct mrsas_softc *sc)
1637265555Sambrisko{
1638265555Sambrisko    sc->map_sz = sizeof(MR_FW_RAID_MAP) +
1639265555Sambrisko                (sizeof(MR_LD_SPAN_MAP) * (MAX_LOGICAL_DRIVES - 1));
1640265555Sambrisko
1641265555Sambrisko    for (int i=0; i < 2; i++)
1642265555Sambrisko    {
1643265555Sambrisko        if (bus_dma_tag_create(sc->mrsas_parent_tag,    // parent
1644265555Sambrisko                            4, 0,                   // algnmnt, boundary
1645265555Sambrisko                            BUS_SPACE_MAXADDR_32BIT,// lowaddr
1646265555Sambrisko                            BUS_SPACE_MAXADDR,      // highaddr
1647265555Sambrisko                            NULL, NULL,             // filter, filterarg
1648265555Sambrisko                            sc->map_sz,             // maxsize
1649265555Sambrisko                            1,                      // nsegments
1650265555Sambrisko                            sc->map_sz,             // maxsegsize
1651265555Sambrisko                            BUS_DMA_ALLOCNOW,       // flags
1652265555Sambrisko                            NULL, NULL,             // lockfunc, lockarg
1653265555Sambrisko                            &sc->raidmap_tag[i])) {
1654265555Sambrisko            device_printf(sc->mrsas_dev, "Cannot allocate raid map tag.\n");
1655265555Sambrisko            return (ENOMEM);
1656265555Sambrisko        }
1657265555Sambrisko        if (bus_dmamem_alloc(sc->raidmap_tag[i], (void **)&sc->raidmap_mem[i],
1658265555Sambrisko                BUS_DMA_NOWAIT, &sc->raidmap_dmamap[i])) {
1659265555Sambrisko            device_printf(sc->mrsas_dev, "Cannot allocate raidmap memory.\n");
1660265555Sambrisko            return (ENOMEM);
1661265555Sambrisko        }
1662265555Sambrisko        if (bus_dmamap_load(sc->raidmap_tag[i], sc->raidmap_dmamap[i],
1663265555Sambrisko                sc->raidmap_mem[i], sc->map_sz, mrsas_addr_cb, &sc->raidmap_phys_addr[i],
1664265555Sambrisko                BUS_DMA_NOWAIT)){
1665265555Sambrisko            device_printf(sc->mrsas_dev, "Cannot load raidmap memory.\n");
1666265555Sambrisko            return (ENOMEM);
1667265555Sambrisko        }
1668265555Sambrisko        if (!sc->raidmap_mem[i]) {
1669265555Sambrisko            device_printf(sc->mrsas_dev, "Cannot allocate memory for raid map.\n");
1670265555Sambrisko            return (ENOMEM);
1671265555Sambrisko        }
1672265555Sambrisko    }
1673265555Sambrisko
1674265555Sambrisko    if (!mrsas_get_map_info(sc))
1675265555Sambrisko        mrsas_sync_map_info(sc);
1676265555Sambrisko
1677265555Sambrisko    return (0);
1678265555Sambrisko}
1679265555Sambrisko
1680265555Sambrisko/**
1681265555Sambrisko * mrsas_init_fw:      Initialize Firmware
1682265555Sambrisko * input:              Adapter soft state
1683265555Sambrisko *
1684265555Sambrisko * Calls transition_to_ready() to make sure Firmware is in operational
1685265555Sambrisko * state and calls mrsas_init_adapter() to send IOC_INIT command to
1686265555Sambrisko * Firmware.  It issues internal commands to get the controller info
1687265555Sambrisko * after the IOC_INIT command response is received by Firmware.
1688265555Sambrisko * Note:  code relating to get_pdlist, get_ld_list and max_sectors
1689265555Sambrisko * are currently not being used, it is left here as placeholder.
1690265555Sambrisko */
1691265555Sambriskostatic int mrsas_init_fw(struct mrsas_softc *sc)
1692265555Sambrisko{
1693265555Sambrisko    u_int32_t max_sectors_1;
1694265555Sambrisko    u_int32_t max_sectors_2;
1695265555Sambrisko    u_int32_t tmp_sectors;
1696265555Sambrisko    struct mrsas_ctrl_info *ctrl_info;
1697265555Sambrisko
1698265555Sambrisko    int ret, ocr = 0;
1699265555Sambrisko
1700265555Sambrisko
1701265555Sambrisko    /* Make sure Firmware is ready */
1702265555Sambrisko    ret = mrsas_transition_to_ready(sc, ocr);
1703265555Sambrisko    if (ret != SUCCESS) {
1704265555Sambrisko        return(ret);
1705265555Sambrisko	}
1706265555Sambrisko
1707265555Sambrisko    /* Get operational params, sge flags, send init cmd to ctlr */
1708265555Sambrisko    if (mrsas_init_adapter(sc) != SUCCESS){
1709265555Sambrisko        device_printf(sc->mrsas_dev, "Adapter initialize Fail.\n");
1710265555Sambrisko        return(1);
1711265555Sambrisko    }
1712265555Sambrisko
1713265555Sambrisko    /* Allocate internal commands for pass-thru */
1714265555Sambrisko    if (mrsas_alloc_mfi_cmds(sc) != SUCCESS){
1715265555Sambrisko        device_printf(sc->mrsas_dev, "Allocate MFI cmd failed.\n");
1716265555Sambrisko        return(1);
1717265555Sambrisko    }
1718265555Sambrisko
1719265555Sambrisko    if (mrsas_setup_raidmap(sc) != SUCCESS) {
1720265555Sambrisko        device_printf(sc->mrsas_dev, "Set up RAID map failed.\n");
1721265555Sambrisko        return(1);
1722265555Sambrisko	}
1723265555Sambrisko
1724265555Sambrisko    /* For pass-thru, get PD/LD list and controller info */
1725265555Sambrisko    memset(sc->pd_list, 0, MRSAS_MAX_PD * sizeof(struct mrsas_pd_list));
1726265555Sambrisko    mrsas_get_pd_list(sc);
1727265555Sambrisko
1728265555Sambrisko    memset(sc->ld_ids, 0xff, MRSAS_MAX_LD);
1729265555Sambrisko    mrsas_get_ld_list(sc);
1730265555Sambrisko
1731265555Sambrisko	//memset(sc->log_to_span, 0, MRSAS_MAX_LD * sizeof(LD_SPAN_INFO));
1732265555Sambrisko
1733265555Sambrisko    ctrl_info = malloc(sizeof(struct mrsas_ctrl_info), M_MRSAS, M_NOWAIT);
1734265555Sambrisko
1735265555Sambrisko    /*
1736265555Sambrisko     * Compute the max allowed sectors per IO: The controller info has two
1737265555Sambrisko     * limits on max sectors. Driver should use the minimum of these two.
1738265555Sambrisko     *
1739265555Sambrisko     * 1 << stripe_sz_ops.min = max sectors per strip
1740265555Sambrisko     *
1741265555Sambrisko     * Note that older firmwares ( < FW ver 30) didn't report information
1742265555Sambrisko     * to calculate max_sectors_1. So the number ended up as zero always.
1743265555Sambrisko     */
1744265555Sambrisko    tmp_sectors = 0;
1745265555Sambrisko    if (ctrl_info && !mrsas_get_ctrl_info(sc, ctrl_info)) {
1746265555Sambrisko        max_sectors_1 = (1 << ctrl_info->stripe_sz_ops.min) *
1747265555Sambrisko                    ctrl_info->max_strips_per_io;
1748265555Sambrisko        max_sectors_2 = ctrl_info->max_request_size;
1749265555Sambrisko        tmp_sectors = min(max_sectors_1 , max_sectors_2);
1750265555Sambrisko        sc->disableOnlineCtrlReset =
1751265555Sambrisko            ctrl_info->properties.OnOffProperties.disableOnlineCtrlReset;
1752265555Sambrisko        sc->UnevenSpanSupport =
1753265555Sambrisko            ctrl_info->adapterOperations2.supportUnevenSpans;
1754265555Sambrisko        if(sc->UnevenSpanSupport) {
1755265555Sambrisko            device_printf(sc->mrsas_dev, "FW supports: UnevenSpanSupport=%x\n",
1756265555Sambrisko                sc->UnevenSpanSupport);
1757265555Sambrisko            if (MR_ValidateMapInfo(sc))
1758265555Sambrisko           	    sc->fast_path_io = 1;
1759265555Sambrisko            else
1760265555Sambrisko                sc->fast_path_io = 0;
1761265555Sambrisko
1762265555Sambrisko        }
1763265555Sambrisko    }
1764265555Sambrisko    sc->max_sectors_per_req = sc->max_num_sge * MRSAS_PAGE_SIZE / 512;
1765265555Sambrisko
1766265555Sambrisko    if (tmp_sectors && (sc->max_sectors_per_req > tmp_sectors))
1767265555Sambrisko        sc->max_sectors_per_req = tmp_sectors;
1768265555Sambrisko
1769265555Sambrisko    if (ctrl_info)
1770265555Sambrisko        free(ctrl_info, M_MRSAS);
1771265555Sambrisko
1772265555Sambrisko    return(0);
1773265555Sambrisko}
1774265555Sambrisko
1775265555Sambrisko/**
1776265555Sambrisko * mrsas_init_adapter:     Initializes the adapter/controller
1777265555Sambrisko * input:                  Adapter soft state
1778265555Sambrisko *
1779265555Sambrisko * Prepares for the issuing of the IOC Init cmd to FW for initializing the
1780265555Sambrisko * ROC/controller.  The FW register is read to determined the number of
1781265555Sambrisko * commands that is supported.  All memory allocations for IO is based on
1782265555Sambrisko * max_cmd.  Appropriate calculations are performed in this function.
1783265555Sambrisko */
1784265555Sambriskoint mrsas_init_adapter(struct mrsas_softc *sc)
1785265555Sambrisko{
1786265555Sambrisko    uint32_t status;
1787265555Sambrisko    u_int32_t max_cmd;
1788265555Sambrisko    int ret;
1789265555Sambrisko
1790265555Sambrisko    /* Read FW status register */
1791265555Sambrisko    status = mrsas_read_reg(sc, offsetof(mrsas_reg_set, outbound_scratch_pad));
1792265555Sambrisko
1793265555Sambrisko    /* Get operational params from status register */
1794265555Sambrisko    sc->max_fw_cmds = status & MRSAS_FWSTATE_MAXCMD_MASK;
1795265555Sambrisko
1796265555Sambrisko    /* Decrement the max supported by 1, to correlate with FW */
1797265555Sambrisko    sc->max_fw_cmds = sc->max_fw_cmds-1;
1798265555Sambrisko    max_cmd = sc->max_fw_cmds;
1799265555Sambrisko
1800265555Sambrisko    /* Determine allocation size of command frames */
1801265555Sambrisko    sc->reply_q_depth = ((max_cmd *2 +1 +15)/16*16);
1802265555Sambrisko    sc->request_alloc_sz = sizeof(MRSAS_REQUEST_DESCRIPTOR_UNION) * max_cmd;
1803265555Sambrisko    sc->reply_alloc_sz = sizeof(MPI2_REPLY_DESCRIPTORS_UNION) * (sc->reply_q_depth);
1804265555Sambrisko    sc->io_frames_alloc_sz = MRSAS_MPI2_RAID_DEFAULT_IO_FRAME_SIZE + (MRSAS_MPI2_RAID_DEFAULT_IO_FRAME_SIZE * (max_cmd + 1));
1805265555Sambrisko    sc->chain_frames_alloc_sz = 1024 * max_cmd;
1806265555Sambrisko    sc->max_sge_in_main_msg = (MRSAS_MPI2_RAID_DEFAULT_IO_FRAME_SIZE -
1807265555Sambrisko        offsetof(MRSAS_RAID_SCSI_IO_REQUEST, SGL))/16;
1808265555Sambrisko
1809265555Sambrisko    sc->max_sge_in_chain = MRSAS_MAX_SZ_CHAIN_FRAME / sizeof(MPI2_SGE_IO_UNION);
1810265555Sambrisko    sc->max_num_sge = sc->max_sge_in_main_msg + sc->max_sge_in_chain - 2;
1811265555Sambrisko
1812265555Sambrisko    /* Used for pass thru MFI frame (DCMD) */
1813265555Sambrisko    sc->chain_offset_mfi_pthru = offsetof(MRSAS_RAID_SCSI_IO_REQUEST, SGL)/16;
1814265555Sambrisko
1815265555Sambrisko    sc->chain_offset_io_request = (MRSAS_MPI2_RAID_DEFAULT_IO_FRAME_SIZE -
1816265555Sambrisko        sizeof(MPI2_SGE_IO_UNION))/16;
1817265555Sambrisko
1818265555Sambrisko    sc->last_reply_idx = 0;
1819265555Sambrisko
1820265555Sambrisko    ret = mrsas_alloc_mem(sc);
1821265555Sambrisko    if (ret != SUCCESS)
1822265555Sambrisko        return(ret);
1823265555Sambrisko
1824265555Sambrisko    ret = mrsas_alloc_mpt_cmds(sc);
1825265555Sambrisko    if (ret != SUCCESS)
1826265555Sambrisko        return(ret);
1827265555Sambrisko
1828265555Sambrisko    ret = mrsas_ioc_init(sc);
1829265555Sambrisko    if (ret != SUCCESS)
1830265555Sambrisko        return(ret);
1831265555Sambrisko
1832265555Sambrisko
1833265555Sambrisko    return(0);
1834265555Sambrisko}
1835265555Sambrisko
1836265555Sambrisko/**
1837265555Sambrisko * mrsas_alloc_ioc_cmd:   Allocates memory for IOC Init command
1838265555Sambrisko * input:                 Adapter soft state
1839265555Sambrisko *
1840265555Sambrisko * Allocates for the IOC Init cmd to FW to initialize the ROC/controller.
1841265555Sambrisko */
1842265555Sambriskoint mrsas_alloc_ioc_cmd(struct mrsas_softc *sc)
1843265555Sambrisko{
1844265555Sambrisko    int ioc_init_size;
1845265555Sambrisko
1846265555Sambrisko    /* Allocate IOC INIT command */
1847265555Sambrisko    ioc_init_size = 1024 + sizeof(MPI2_IOC_INIT_REQUEST);
1848265555Sambrisko    if (bus_dma_tag_create( sc->mrsas_parent_tag,   // parent
1849265555Sambrisko                            1, 0,                   // algnmnt, boundary
1850265555Sambrisko                            BUS_SPACE_MAXADDR_32BIT,// lowaddr
1851265555Sambrisko                            BUS_SPACE_MAXADDR,      // highaddr
1852265555Sambrisko                            NULL, NULL,             // filter, filterarg
1853265555Sambrisko                            ioc_init_size,          // maxsize
1854265555Sambrisko                            1,                      // msegments
1855265555Sambrisko                            ioc_init_size,          // maxsegsize
1856265555Sambrisko                            BUS_DMA_ALLOCNOW,       // flags
1857265555Sambrisko                            NULL, NULL,             // lockfunc, lockarg
1858265555Sambrisko                            &sc->ioc_init_tag)) {
1859265555Sambrisko        device_printf(sc->mrsas_dev, "Cannot allocate ioc init tag\n");
1860265555Sambrisko        return (ENOMEM);
1861265555Sambrisko    }
1862265555Sambrisko    if (bus_dmamem_alloc(sc->ioc_init_tag, (void **)&sc->ioc_init_mem,
1863265555Sambrisko            BUS_DMA_NOWAIT, &sc->ioc_init_dmamap)) {
1864265555Sambrisko        device_printf(sc->mrsas_dev, "Cannot allocate ioc init cmd mem\n");
1865265555Sambrisko        return (ENOMEM);
1866265555Sambrisko    }
1867265555Sambrisko    bzero(sc->ioc_init_mem, ioc_init_size);
1868265555Sambrisko    if (bus_dmamap_load(sc->ioc_init_tag, sc->ioc_init_dmamap,
1869265555Sambrisko            sc->ioc_init_mem, ioc_init_size, mrsas_addr_cb,
1870265555Sambrisko            &sc->ioc_init_phys_mem, BUS_DMA_NOWAIT)) {
1871265555Sambrisko        device_printf(sc->mrsas_dev, "Cannot load ioc init cmd mem\n");
1872265555Sambrisko        return (ENOMEM);
1873265555Sambrisko    }
1874265555Sambrisko
1875265555Sambrisko    return (0);
1876265555Sambrisko}
1877265555Sambrisko
1878265555Sambrisko/**
1879265555Sambrisko * mrsas_free_ioc_cmd:   Allocates memory for IOC Init command
1880265555Sambrisko * input:                Adapter soft state
1881265555Sambrisko *
1882265555Sambrisko * Deallocates memory of the IOC Init cmd.
1883265555Sambrisko */
1884265555Sambriskovoid mrsas_free_ioc_cmd(struct mrsas_softc *sc)
1885265555Sambrisko{
1886265555Sambrisko    if (sc->ioc_init_phys_mem)
1887265555Sambrisko        bus_dmamap_unload(sc->ioc_init_tag, sc->ioc_init_dmamap);
1888265555Sambrisko    if (sc->ioc_init_mem != NULL)
1889265555Sambrisko        bus_dmamem_free(sc->ioc_init_tag, sc->ioc_init_mem, sc->ioc_init_dmamap);
1890265555Sambrisko    if (sc->ioc_init_tag != NULL)
1891265555Sambrisko        bus_dma_tag_destroy(sc->ioc_init_tag);
1892265555Sambrisko}
1893265555Sambrisko
1894265555Sambrisko/**
1895265555Sambrisko * mrsas_ioc_init:     Sends IOC Init command to FW
1896265555Sambrisko * input:              Adapter soft state
1897265555Sambrisko *
1898265555Sambrisko * Issues the IOC Init cmd to FW to initialize the ROC/controller.
1899265555Sambrisko */
1900265555Sambriskoint mrsas_ioc_init(struct mrsas_softc *sc)
1901265555Sambrisko{
1902265555Sambrisko    struct mrsas_init_frame *init_frame;
1903265555Sambrisko    pMpi2IOCInitRequest_t   IOCInitMsg;
1904265555Sambrisko    MRSAS_REQUEST_DESCRIPTOR_UNION req_desc;
1905265555Sambrisko    u_int8_t max_wait = MRSAS_IOC_INIT_WAIT_TIME;
1906265555Sambrisko    bus_addr_t phys_addr;
1907265555Sambrisko    int i, retcode = 0;
1908265555Sambrisko
1909265555Sambrisko    /* Allocate memory for the IOC INIT command */
1910265555Sambrisko    if (mrsas_alloc_ioc_cmd(sc)) {
1911265555Sambrisko        device_printf(sc->mrsas_dev, "Cannot allocate IOC command.\n");
1912265555Sambrisko        return(1);
1913265555Sambrisko    }
1914265555Sambrisko
1915265555Sambrisko    IOCInitMsg = (pMpi2IOCInitRequest_t)(((char *)sc->ioc_init_mem) +1024);
1916265555Sambrisko    IOCInitMsg->Function = MPI2_FUNCTION_IOC_INIT;
1917265555Sambrisko    IOCInitMsg->WhoInit = MPI2_WHOINIT_HOST_DRIVER;
1918265555Sambrisko    IOCInitMsg->MsgVersion = MPI2_VERSION;
1919265555Sambrisko    IOCInitMsg->HeaderVersion = MPI2_HEADER_VERSION;
1920265555Sambrisko    IOCInitMsg->SystemRequestFrameSize = MRSAS_MPI2_RAID_DEFAULT_IO_FRAME_SIZE / 4;
1921265555Sambrisko    IOCInitMsg->ReplyDescriptorPostQueueDepth = sc->reply_q_depth;
1922265555Sambrisko    IOCInitMsg->ReplyDescriptorPostQueueAddress = sc->reply_desc_phys_addr;
1923265555Sambrisko    IOCInitMsg->SystemRequestFrameBaseAddress = sc->io_request_phys_addr;
1924265555Sambrisko
1925265555Sambrisko    init_frame = (struct mrsas_init_frame *)sc->ioc_init_mem;
1926265555Sambrisko    init_frame->cmd = MFI_CMD_INIT;
1927265555Sambrisko    init_frame->cmd_status = 0xFF;
1928265555Sambrisko    init_frame->flags |= MFI_FRAME_DONT_POST_IN_REPLY_QUEUE;
1929265555Sambrisko
1930265555Sambrisko    if (sc->verbuf_mem) {
1931265555Sambrisko        snprintf((char *)sc->verbuf_mem, strlen(MRSAS_VERSION)+2,"%s\n",
1932265555Sambrisko                MRSAS_VERSION);
1933265555Sambrisko        init_frame->driver_ver_lo = (bus_addr_t)sc->verbuf_phys_addr;
1934265555Sambrisko        init_frame->driver_ver_hi = 0;
1935265555Sambrisko    }
1936265555Sambrisko
1937265555Sambrisko    phys_addr = (bus_addr_t)sc->ioc_init_phys_mem + 1024;
1938265555Sambrisko    init_frame->queue_info_new_phys_addr_lo = phys_addr;
1939265555Sambrisko    init_frame->data_xfer_len = sizeof(Mpi2IOCInitRequest_t);
1940265555Sambrisko
1941265555Sambrisko    req_desc.addr.Words = (bus_addr_t)sc->ioc_init_phys_mem;
1942265555Sambrisko    req_desc.MFAIo.RequestFlags =
1943265555Sambrisko        (MRSAS_REQ_DESCRIPT_FLAGS_MFA << MRSAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
1944265555Sambrisko
1945265555Sambrisko    mrsas_disable_intr(sc);
1946265555Sambrisko    mrsas_dprint(sc, MRSAS_OCR, "Issuing IOC INIT command to FW.\n");
1947265555Sambrisko    //device_printf(sc->mrsas_dev, "Issuing IOC INIT command to FW.\n");del?
1948265555Sambrisko    mrsas_fire_cmd(sc, req_desc.addr.u.low, req_desc.addr.u.high);
1949265555Sambrisko
1950265555Sambrisko    /*
1951265555Sambrisko     * Poll response timer to wait for Firmware response.  While this
1952265555Sambrisko     * timer with the DELAY call could block CPU, the time interval for
1953265555Sambrisko     * this is only 1 millisecond.
1954265555Sambrisko     */
1955265555Sambrisko    if (init_frame->cmd_status == 0xFF) {
1956265555Sambrisko        for (i=0; i < (max_wait * 1000); i++){
1957265555Sambrisko            if (init_frame->cmd_status == 0xFF)
1958265555Sambrisko                DELAY(1000);
1959265555Sambrisko            else
1960265555Sambrisko                break;
1961265555Sambrisko        }
1962265555Sambrisko    }
1963265555Sambrisko
1964265555Sambrisko    if (init_frame->cmd_status == 0)
1965265555Sambrisko         mrsas_dprint(sc, MRSAS_OCR,
1966265555Sambrisko               "IOC INIT response received from FW.\n");
1967265555Sambrisko         //device_printf(sc->mrsas_dev, "IOC INIT response received from FW.\n");del?
1968265555Sambrisko    else
1969265555Sambrisko    {
1970265555Sambrisko        if (init_frame->cmd_status == 0xFF)
1971265555Sambrisko            device_printf(sc->mrsas_dev, "IOC Init timed out after %d seconds.\n", max_wait);
1972265555Sambrisko        else
1973265555Sambrisko            device_printf(sc->mrsas_dev, "IOC Init failed, status = 0x%x\n", init_frame->cmd_status);
1974265555Sambrisko        retcode = 1;
1975265555Sambrisko    }
1976265555Sambrisko
1977265555Sambrisko    mrsas_free_ioc_cmd(sc);
1978265555Sambrisko    return (retcode);
1979265555Sambrisko}
1980265555Sambrisko
1981265555Sambrisko/**
1982265555Sambrisko * mrsas_alloc_mpt_cmds:  Allocates the command packets
1983265555Sambrisko * input:                 Adapter instance soft state
1984265555Sambrisko *
1985265555Sambrisko * This function allocates the internal commands for IOs. Each command that is
1986265555Sambrisko * issued to FW is wrapped in a local data structure called mrsas_mpt_cmd.
1987265555Sambrisko * An array is allocated with mrsas_mpt_cmd context.  The free commands are
1988265555Sambrisko * maintained in a linked list (cmd pool). SMID value range is from 1 to
1989265555Sambrisko * max_fw_cmds.
1990265555Sambrisko */
1991265555Sambriskoint mrsas_alloc_mpt_cmds(struct mrsas_softc *sc)
1992265555Sambrisko{
1993265555Sambrisko    int i, j;
1994265555Sambrisko    u_int32_t max_cmd;
1995265555Sambrisko    struct mrsas_mpt_cmd *cmd;
1996265555Sambrisko    pMpi2ReplyDescriptorsUnion_t reply_desc;
1997265555Sambrisko    u_int32_t offset, chain_offset, sense_offset;
1998265555Sambrisko    bus_addr_t io_req_base_phys, chain_frame_base_phys, sense_base_phys;
1999265555Sambrisko    u_int8_t *io_req_base, *chain_frame_base, *sense_base;
2000265555Sambrisko
2001265555Sambrisko    max_cmd = sc->max_fw_cmds;
2002265555Sambrisko
2003265555Sambrisko    sc->req_desc = malloc(sc->request_alloc_sz, M_MRSAS, M_NOWAIT);
2004265555Sambrisko    if (!sc->req_desc) {
2005265555Sambrisko        device_printf(sc->mrsas_dev, "Out of memory, cannot alloc req desc\n");
2006265555Sambrisko        return(ENOMEM);
2007265555Sambrisko    }
2008265555Sambrisko    memset(sc->req_desc, 0, sc->request_alloc_sz);
2009265555Sambrisko
2010265555Sambrisko    /*
2011265555Sambrisko     * sc->mpt_cmd_list is an array of struct mrsas_mpt_cmd pointers. Allocate the
2012265555Sambrisko     * dynamic array first and then allocate individual commands.
2013265555Sambrisko     */
2014265555Sambrisko    sc->mpt_cmd_list = malloc(sizeof(struct mrsas_mpt_cmd*)*max_cmd, M_MRSAS, M_NOWAIT);
2015265555Sambrisko    if (!sc->mpt_cmd_list) {
2016265555Sambrisko        device_printf(sc->mrsas_dev, "Cannot alloc memory for mpt_cmd_list.\n");
2017265555Sambrisko        return(ENOMEM);
2018265555Sambrisko    }
2019265555Sambrisko    memset(sc->mpt_cmd_list, 0, sizeof(struct mrsas_mpt_cmd *)*max_cmd);
2020265555Sambrisko    for (i = 0; i < max_cmd; i++) {
2021265555Sambrisko        sc->mpt_cmd_list[i] = malloc(sizeof(struct mrsas_mpt_cmd),
2022265555Sambrisko                                 M_MRSAS, M_NOWAIT);
2023265555Sambrisko        if (!sc->mpt_cmd_list[i]) {
2024265555Sambrisko            for (j = 0; j < i; j++)
2025265555Sambrisko                free(sc->mpt_cmd_list[j],M_MRSAS);
2026265555Sambrisko            free(sc->mpt_cmd_list, M_MRSAS);
2027265555Sambrisko            sc->mpt_cmd_list = NULL;
2028265555Sambrisko            return(ENOMEM);
2029265555Sambrisko        }
2030265555Sambrisko    }
2031265555Sambrisko
2032265555Sambrisko    io_req_base = (u_int8_t*)sc->io_request_mem + MRSAS_MPI2_RAID_DEFAULT_IO_FRAME_SIZE;
2033265555Sambrisko    io_req_base_phys = (bus_addr_t)sc->io_request_phys_addr + MRSAS_MPI2_RAID_DEFAULT_IO_FRAME_SIZE;
2034265555Sambrisko    chain_frame_base = (u_int8_t*)sc->chain_frame_mem;
2035265555Sambrisko    chain_frame_base_phys = (bus_addr_t)sc->chain_frame_phys_addr;
2036265555Sambrisko    sense_base = (u_int8_t*)sc->sense_mem;
2037265555Sambrisko    sense_base_phys = (bus_addr_t)sc->sense_phys_addr;
2038265555Sambrisko    for (i = 0; i < max_cmd; i++) {
2039265555Sambrisko        cmd = sc->mpt_cmd_list[i];
2040265555Sambrisko        offset = MRSAS_MPI2_RAID_DEFAULT_IO_FRAME_SIZE * i;
2041265555Sambrisko	chain_offset = 1024 * i;
2042265555Sambrisko        sense_offset = MRSAS_SENSE_LEN * i;
2043265555Sambrisko        memset(cmd, 0, sizeof(struct mrsas_mpt_cmd));
2044265555Sambrisko        cmd->index = i + 1;
2045265555Sambrisko        cmd->ccb_ptr = NULL;
2046265555Sambrisko        callout_init(&cmd->cm_callout, 0);
2047265555Sambrisko        cmd->sync_cmd_idx = (u_int32_t)MRSAS_ULONG_MAX;
2048265555Sambrisko        cmd->sc = sc;
2049265555Sambrisko        cmd->io_request = (MRSAS_RAID_SCSI_IO_REQUEST *) (io_req_base + offset);
2050265555Sambrisko        memset(cmd->io_request, 0, sizeof(MRSAS_RAID_SCSI_IO_REQUEST));
2051265555Sambrisko        cmd->io_request_phys_addr = io_req_base_phys + offset;
2052265555Sambrisko	cmd->chain_frame = (MPI2_SGE_IO_UNION *) (chain_frame_base + chain_offset);
2053265555Sambrisko	cmd->chain_frame_phys_addr = chain_frame_base_phys + chain_offset;
2054265555Sambrisko        cmd->sense = sense_base + sense_offset;
2055265555Sambrisko        cmd->sense_phys_addr = sense_base_phys + sense_offset;
2056265555Sambrisko        if (bus_dmamap_create(sc->data_tag, 0, &cmd->data_dmamap)) {
2057265555Sambrisko            return(FAIL);
2058265555Sambrisko        }
2059265555Sambrisko        TAILQ_INSERT_TAIL(&(sc->mrsas_mpt_cmd_list_head), cmd, next);
2060265555Sambrisko    }
2061265555Sambrisko
2062265555Sambrisko    /* Initialize reply descriptor array to 0xFFFFFFFF */
2063265555Sambrisko    reply_desc = sc->reply_desc_mem;
2064265555Sambrisko    for (i = 0; i < sc->reply_q_depth; i++, reply_desc++) {
2065265555Sambrisko        reply_desc->Words = MRSAS_ULONG_MAX;
2066265555Sambrisko    }
2067265555Sambrisko    return(0);
2068265555Sambrisko}
2069265555Sambrisko
2070265555Sambrisko/**
2071265555Sambrisko * mrsas_fire_cmd:     Sends command to FW
2072265555Sambrisko * input:              Adapter soft state
2073265555Sambrisko *                     request descriptor address low
2074265555Sambrisko *                     request descriptor address high
2075265555Sambrisko *
2076265555Sambrisko * This functions fires the command to Firmware by writing to the
2077265555Sambrisko * inbound_low_queue_port and inbound_high_queue_port.
2078265555Sambrisko */
2079265555Sambriskovoid mrsas_fire_cmd(struct mrsas_softc *sc, u_int32_t req_desc_lo,
2080265555Sambrisko                   u_int32_t req_desc_hi)
2081265555Sambrisko{
2082265555Sambrisko    mtx_lock(&sc->pci_lock);
2083265555Sambrisko    mrsas_write_reg(sc, offsetof(mrsas_reg_set, inbound_low_queue_port),
2084265555Sambrisko                    req_desc_lo);
2085265555Sambrisko    mrsas_write_reg(sc, offsetof(mrsas_reg_set, inbound_high_queue_port),
2086265555Sambrisko                    req_desc_hi);
2087265555Sambrisko    mtx_unlock(&sc->pci_lock);
2088265555Sambrisko}
2089265555Sambrisko
2090265555Sambrisko/**
2091265555Sambrisko * mrsas_transition_to_ready:  Move FW to Ready state
2092265555Sambrisko * input:                      Adapter instance soft state
2093265555Sambrisko *
2094265555Sambrisko * During the initialization, FW passes can potentially be in any one of
2095265555Sambrisko * several possible states. If the FW in operational, waiting-for-handshake
2096265555Sambrisko * states, driver must take steps to bring it to ready state. Otherwise, it
2097265555Sambrisko * has to wait for the ready state.
2098265555Sambrisko */
2099265555Sambriskoint mrsas_transition_to_ready(struct mrsas_softc *sc, int ocr)
2100265555Sambrisko{
2101265555Sambrisko    int i;
2102265555Sambrisko    u_int8_t max_wait;
2103265555Sambrisko    u_int32_t val, fw_state;
2104265555Sambrisko    u_int32_t cur_state;
2105265555Sambrisko    u_int32_t abs_state, curr_abs_state;
2106265555Sambrisko
2107265555Sambrisko    val = mrsas_read_reg(sc, offsetof(mrsas_reg_set, outbound_scratch_pad));
2108265555Sambrisko    fw_state = val & MFI_STATE_MASK;
2109265555Sambrisko    max_wait = MRSAS_RESET_WAIT_TIME;
2110265555Sambrisko
2111265555Sambrisko    if (fw_state != MFI_STATE_READY)
2112265555Sambrisko        device_printf(sc->mrsas_dev, "Waiting for FW to come to ready state\n");
2113265555Sambrisko
2114265555Sambrisko    while (fw_state != MFI_STATE_READY) {
2115265555Sambrisko	abs_state = mrsas_read_reg(sc, offsetof(mrsas_reg_set, outbound_scratch_pad));
2116265555Sambrisko	switch (fw_state) {
2117265555Sambrisko	    case MFI_STATE_FAULT:
2118265555Sambrisko		device_printf(sc->mrsas_dev, "FW is in FAULT state!!\n");
2119265555Sambrisko		if (ocr) {
2120265555Sambrisko		    cur_state = MFI_STATE_FAULT;
2121265555Sambrisko	  	    break;
2122265555Sambrisko		}
2123265555Sambrisko        else
2124265555Sambrisko			return -ENODEV;
2125265555Sambrisko	    case MFI_STATE_WAIT_HANDSHAKE:
2126265555Sambrisko		/* Set the CLR bit in inbound doorbell */
2127265555Sambrisko                mrsas_write_reg(sc, offsetof(mrsas_reg_set, doorbell),
2128265555Sambrisko		        MFI_INIT_CLEAR_HANDSHAKE|MFI_INIT_HOTPLUG);
2129265555Sambrisko		cur_state = MFI_STATE_WAIT_HANDSHAKE;
2130265555Sambrisko		break;
2131265555Sambrisko	    case MFI_STATE_BOOT_MESSAGE_PENDING:
2132265555Sambrisko                mrsas_write_reg(sc, offsetof(mrsas_reg_set, doorbell),
2133265555Sambrisko		        MFI_INIT_HOTPLUG);
2134265555Sambrisko		cur_state = MFI_STATE_BOOT_MESSAGE_PENDING;
2135265555Sambrisko		break;
2136265555Sambrisko	    case MFI_STATE_OPERATIONAL:
2137265555Sambrisko		/* Bring it to READY state; assuming max wait 10 secs */
2138265555Sambrisko		mrsas_disable_intr(sc);
2139265555Sambrisko                mrsas_write_reg(sc, offsetof(mrsas_reg_set, doorbell), MFI_RESET_FLAGS);
2140265555Sambrisko                for (i=0; i < max_wait * 1000; i++) {
2141265555Sambrisko	            if (mrsas_read_reg(sc, offsetof(mrsas_reg_set, doorbell)) & 1)
2142265555Sambrisko                        DELAY(1000);
2143265555Sambrisko		    else
2144265555Sambrisko		        break;
2145265555Sambrisko                }
2146265555Sambrisko		cur_state = MFI_STATE_OPERATIONAL;
2147265555Sambrisko	        break;
2148265555Sambrisko	    case MFI_STATE_UNDEFINED:
2149265555Sambrisko	        /* This state should not last for more than 2 seconds */
2150265555Sambrisko	        cur_state = MFI_STATE_UNDEFINED;
2151265555Sambrisko	        break;
2152265555Sambrisko	    case MFI_STATE_BB_INIT:
2153265555Sambrisko		cur_state = MFI_STATE_BB_INIT;
2154265555Sambrisko		break;
2155265555Sambrisko	    case MFI_STATE_FW_INIT:
2156265555Sambrisko		cur_state = MFI_STATE_FW_INIT;
2157265555Sambrisko		break;
2158265555Sambrisko	    case MFI_STATE_FW_INIT_2:
2159265555Sambrisko		cur_state = MFI_STATE_FW_INIT_2;
2160265555Sambrisko		break;
2161265555Sambrisko	    case MFI_STATE_DEVICE_SCAN:
2162265555Sambrisko		cur_state = MFI_STATE_DEVICE_SCAN;
2163265555Sambrisko		break;
2164265555Sambrisko	    case MFI_STATE_FLUSH_CACHE:
2165265555Sambrisko		cur_state = MFI_STATE_FLUSH_CACHE;
2166265555Sambrisko		break;
2167265555Sambrisko	    default:
2168265555Sambrisko		device_printf(sc->mrsas_dev, "Unknown state 0x%x\n", fw_state);
2169265555Sambrisko		return -ENODEV;
2170265555Sambrisko	}
2171265555Sambrisko
2172265555Sambrisko	/*
2173265555Sambrisko	 * The cur_state should not last for more than max_wait secs
2174265555Sambrisko	 */
2175265555Sambrisko	for (i = 0; i < (max_wait * 1000); i++) {
2176265555Sambrisko            fw_state = (mrsas_read_reg(sc, offsetof(mrsas_reg_set,
2177265555Sambrisko                    outbound_scratch_pad))& MFI_STATE_MASK);
2178265555Sambrisko	    curr_abs_state = mrsas_read_reg(sc, offsetof(mrsas_reg_set,
2179265555Sambrisko                    outbound_scratch_pad));
2180265555Sambrisko            if (abs_state == curr_abs_state)
2181265555Sambrisko                DELAY(1000);
2182265555Sambrisko	    else
2183265555Sambrisko		break;
2184265555Sambrisko	}
2185265555Sambrisko
2186265555Sambrisko	/*
2187265555Sambrisko	 * Return error if fw_state hasn't changed after max_wait
2188265555Sambrisko	 */
2189265555Sambrisko	if (curr_abs_state == abs_state) {
2190265555Sambrisko            device_printf(sc->mrsas_dev, "FW state [%d] hasn't changed "
2191265555Sambrisko		       "in %d secs\n", fw_state, max_wait);
2192265555Sambrisko	    return -ENODEV;
2193265555Sambrisko	}
2194265555Sambrisko    }
2195265555Sambrisko    mrsas_dprint(sc, MRSAS_OCR, "FW now in Ready state\n");
2196265555Sambrisko    //device_printf(sc->mrsas_dev, "FW now in Ready state\n");del?
2197265555Sambrisko    return 0;
2198265555Sambrisko}
2199265555Sambrisko
2200265555Sambrisko/**
2201265555Sambrisko * mrsas_get_mfi_cmd:      Get a cmd from free command pool
2202265555Sambrisko * input:                  Adapter soft state
2203265555Sambrisko *
2204265555Sambrisko * This function removes an MFI command from the command list.
2205265555Sambrisko */
2206265555Sambriskostruct mrsas_mfi_cmd* mrsas_get_mfi_cmd(struct mrsas_softc *sc)
2207265555Sambrisko{
2208265555Sambrisko    struct mrsas_mfi_cmd *cmd = NULL;
2209265555Sambrisko
2210265555Sambrisko    mtx_lock(&sc->mfi_cmd_pool_lock);
2211265555Sambrisko    if (!TAILQ_EMPTY(&sc->mrsas_mfi_cmd_list_head)){
2212265555Sambrisko        cmd = TAILQ_FIRST(&sc->mrsas_mfi_cmd_list_head);
2213265555Sambrisko        TAILQ_REMOVE(&sc->mrsas_mfi_cmd_list_head, cmd, next);
2214265555Sambrisko    }
2215265555Sambrisko    mtx_unlock(&sc->mfi_cmd_pool_lock);
2216265555Sambrisko
2217265555Sambrisko    return cmd;
2218265555Sambrisko}
2219265555Sambrisko
2220265555Sambrisko/**
2221265555Sambrisko * mrsas_ocr_thread             Thread to handle OCR/Kill Adapter.
2222265555Sambrisko * input:               Adapter Context.
2223265555Sambrisko *
2224265555Sambrisko * This function will check FW status register and flag
2225265555Sambrisko * do_timeout_reset flag. It will do OCR/Kill adapter if
2226265555Sambrisko * FW is in fault state or IO timed out has trigger reset.
2227265555Sambrisko */
2228265555Sambriskostatic void
2229265555Sambriskomrsas_ocr_thread(void *arg)
2230265555Sambrisko{
2231265555Sambrisko    struct mrsas_softc *sc;
2232265555Sambrisko    u_int32_t  fw_status, fw_state;
2233265555Sambrisko
2234265555Sambrisko    sc = (struct mrsas_softc *)arg;
2235265555Sambrisko
2236265555Sambrisko    mrsas_dprint(sc, MRSAS_TRACE, "%s\n", __func__);
2237265555Sambrisko
2238265555Sambrisko    sc->ocr_thread_active = 1;
2239265555Sambrisko    mtx_lock(&sc->sim_lock);
2240265555Sambrisko    for (;;) {
2241265555Sambrisko        /* Sleep for 1 second and check the queue status*/
2242265555Sambrisko        msleep(&sc->ocr_chan, &sc->sim_lock, PRIBIO,
2243265555Sambrisko               "mrsas_ocr", sc->mrsas_fw_fault_check_delay * hz);
2244265555Sambrisko        if (sc->remove_in_progress) {
2245265555Sambrisko            mrsas_dprint(sc, MRSAS_OCR,
2246265555Sambrisko				"Exit due to shutdown from %s\n", __func__);
2247265555Sambrisko            break;
2248265555Sambrisko        }
2249265555Sambrisko        fw_status = mrsas_read_reg(sc,
2250265555Sambrisko				offsetof(mrsas_reg_set, outbound_scratch_pad));
2251265555Sambrisko        fw_state = fw_status & MFI_STATE_MASK;
2252265555Sambrisko        if (fw_state == MFI_STATE_FAULT || sc->do_timedout_reset) {
2253265555Sambrisko            device_printf(sc->mrsas_dev, "OCR started due to %s!\n",
2254265555Sambrisko                 sc->do_timedout_reset?"IO Timeout":
2255265555Sambrisko                 "FW fault detected");
2256265555Sambrisko            mtx_lock_spin(&sc->ioctl_lock);
2257265555Sambrisko            sc->reset_in_progress = 1;
2258265555Sambrisko            sc->reset_count++;
2259265555Sambrisko            mtx_unlock_spin(&sc->ioctl_lock);
2260265555Sambrisko            mrsas_xpt_freeze(sc);
2261265555Sambrisko            mrsas_reset_ctrl(sc);
2262265555Sambrisko            mrsas_xpt_release(sc);
2263265555Sambrisko            sc->reset_in_progress = 0;
2264265555Sambrisko            sc->do_timedout_reset = 0;
2265265555Sambrisko        }
2266265555Sambrisko    }
2267265555Sambrisko    mtx_unlock(&sc->sim_lock);
2268265555Sambrisko    sc->ocr_thread_active = 0;
2269265555Sambrisko    mrsas_kproc_exit(0);
2270265555Sambrisko}
2271265555Sambrisko
2272265555Sambrisko/**
2273265555Sambrisko * mrsas_reset_reply_desc       Reset Reply descriptor as part of OCR.
2274265555Sambrisko * input:                       Adapter Context.
2275265555Sambrisko *
2276265555Sambrisko * This function will clear reply descriptor so that post OCR
2277265555Sambrisko * driver and FW will lost old history.
2278265555Sambrisko */
2279265555Sambriskovoid  mrsas_reset_reply_desc(struct mrsas_softc *sc)
2280265555Sambrisko{
2281265555Sambrisko    int i;
2282265555Sambrisko    pMpi2ReplyDescriptorsUnion_t reply_desc;
2283265555Sambrisko
2284265555Sambrisko    sc->last_reply_idx = 0;
2285265555Sambrisko    reply_desc = sc->reply_desc_mem;
2286265555Sambrisko    for (i = 0; i < sc->reply_q_depth; i++, reply_desc++) {
2287265555Sambrisko        reply_desc->Words = MRSAS_ULONG_MAX;
2288265555Sambrisko    }
2289265555Sambrisko}
2290265555Sambrisko
2291265555Sambrisko/**
2292265555Sambrisko * mrsas_reset_ctrl     Core function to OCR/Kill adapter.
2293265555Sambrisko * input:               Adapter Context.
2294265555Sambrisko *
2295265555Sambrisko * This function will run from thread context so that it can sleep.
2296265555Sambrisko * 1. Do not handle OCR if FW is in HW critical error.
2297265555Sambrisko * 2. Wait for outstanding command to complete for 180 seconds.
2298265555Sambrisko * 3. If #2 does not find any outstanding command Controller is in working
2299265555Sambrisko * state, so skip OCR.
2300265555Sambrisko * Otherwise, do OCR/kill Adapter based on flag disableOnlineCtrlReset.
2301265555Sambrisko * 4. Start of the OCR, return all SCSI command back to CAM layer which has
2302265555Sambrisko * ccb_ptr.
2303265555Sambrisko * 5. Post OCR, Re-fire Managment command and move Controller to Operation
2304265555Sambrisko * state.
2305265555Sambrisko */
2306265555Sambriskoint mrsas_reset_ctrl(struct mrsas_softc *sc)
2307265555Sambrisko{
2308265555Sambrisko    int retval = SUCCESS, i, j, retry = 0;
2309265555Sambrisko    u_int32_t       host_diag, abs_state, status_reg, reset_adapter;
2310265555Sambrisko    union ccb   *ccb;
2311265555Sambrisko    struct mrsas_mfi_cmd *mfi_cmd;
2312265555Sambrisko    struct mrsas_mpt_cmd *mpt_cmd;
2313265555Sambrisko    MRSAS_REQUEST_DESCRIPTOR_UNION *req_desc;
2314265555Sambrisko
2315265555Sambrisko    if (sc->adprecovery == MRSAS_HW_CRITICAL_ERROR) {
2316265555Sambrisko        device_printf(sc->mrsas_dev,
2317265555Sambrisko                        "mrsas: Hardware critical error, returning FAIL.\n");
2318265555Sambrisko        return FAIL;
2319265555Sambrisko    }
2320265555Sambrisko
2321265555Sambrisko    set_bit(MRSAS_FUSION_IN_RESET, &sc->reset_flags);
2322265555Sambrisko    sc->adprecovery = MRSAS_ADPRESET_SM_INFAULT;
2323265555Sambrisko    mrsas_disable_intr(sc);
2324265555Sambrisko    DELAY(1000 * 1000);
2325265555Sambrisko
2326265555Sambrisko    /* First try waiting for commands to complete */
2327265555Sambrisko    if (mrsas_wait_for_outstanding(sc)) {
2328265555Sambrisko        mrsas_dprint(sc, MRSAS_OCR,
2329265555Sambrisko                     "resetting adapter from %s.\n",
2330265555Sambrisko                      __func__);
2331265555Sambrisko        /* Now return commands back to the CAM layer */
2332265555Sambrisko        for (i = 0 ; i < sc->max_fw_cmds; i++) {
2333265555Sambrisko            mpt_cmd = sc->mpt_cmd_list[i];
2334265555Sambrisko            if (mpt_cmd->ccb_ptr) {
2335265555Sambrisko                ccb = (union ccb *)(mpt_cmd->ccb_ptr);
2336265555Sambrisko                ccb->ccb_h.status = CAM_SCSI_BUS_RESET;
2337265555Sambrisko                mrsas_cmd_done(sc, mpt_cmd);
2338265555Sambrisko                atomic_dec(&sc->fw_outstanding);
2339265555Sambrisko            }
2340265555Sambrisko        }
2341265555Sambrisko
2342265555Sambrisko        status_reg = mrsas_read_reg(sc, offsetof(mrsas_reg_set,
2343265555Sambrisko                                                           outbound_scratch_pad));
2344265555Sambrisko        abs_state = status_reg & MFI_STATE_MASK;
2345265555Sambrisko        reset_adapter = status_reg & MFI_RESET_ADAPTER;
2346265555Sambrisko        if (sc->disableOnlineCtrlReset ||
2347265555Sambrisko                        (abs_state == MFI_STATE_FAULT && !reset_adapter)) {
2348265555Sambrisko            /* Reset not supported, kill adapter */
2349265555Sambrisko            mrsas_dprint(sc, MRSAS_OCR,"Reset not supported, killing adapter.\n");
2350265555Sambrisko            mrsas_kill_hba(sc);
2351265555Sambrisko            sc->adprecovery = MRSAS_HW_CRITICAL_ERROR;
2352265555Sambrisko            retval = FAIL;
2353265555Sambrisko             goto out;
2354265555Sambrisko        }
2355265555Sambrisko
2356265555Sambrisko        /* Now try to reset the chip */
2357265555Sambrisko        for (i = 0; i < MRSAS_FUSION_MAX_RESET_TRIES; i++) {
2358265555Sambrisko            mrsas_write_reg(sc, offsetof(mrsas_reg_set, fusion_seq_offset),
2359265555Sambrisko                MPI2_WRSEQ_FLUSH_KEY_VALUE);
2360265555Sambrisko            mrsas_write_reg(sc, offsetof(mrsas_reg_set, fusion_seq_offset),
2361265555Sambrisko                MPI2_WRSEQ_1ST_KEY_VALUE);
2362265555Sambrisko            mrsas_write_reg(sc, offsetof(mrsas_reg_set, fusion_seq_offset),
2363265555Sambrisko                MPI2_WRSEQ_2ND_KEY_VALUE);
2364265555Sambrisko            mrsas_write_reg(sc, offsetof(mrsas_reg_set, fusion_seq_offset),
2365265555Sambrisko                MPI2_WRSEQ_3RD_KEY_VALUE);
2366265555Sambrisko            mrsas_write_reg(sc, offsetof(mrsas_reg_set, fusion_seq_offset),
2367265555Sambrisko                MPI2_WRSEQ_4TH_KEY_VALUE);
2368265555Sambrisko            mrsas_write_reg(sc, offsetof(mrsas_reg_set, fusion_seq_offset),
2369265555Sambrisko                MPI2_WRSEQ_5TH_KEY_VALUE);
2370265555Sambrisko            mrsas_write_reg(sc, offsetof(mrsas_reg_set, fusion_seq_offset),
2371265555Sambrisko                MPI2_WRSEQ_6TH_KEY_VALUE);
2372265555Sambrisko
2373265555Sambrisko            /* Check that the diag write enable (DRWE) bit is on */
2374265555Sambrisko            host_diag = mrsas_read_reg(sc, offsetof(mrsas_reg_set,
2375265555Sambrisko                                                        fusion_host_diag));
2376265555Sambrisko            retry = 0;
2377265555Sambrisko            while (!(host_diag & HOST_DIAG_WRITE_ENABLE)) {
2378265555Sambrisko                DELAY(100 * 1000);
2379265555Sambrisko                host_diag = mrsas_read_reg(sc, offsetof(mrsas_reg_set,
2380265555Sambrisko                                                        fusion_host_diag));
2381265555Sambrisko                if (retry++ == 100) {
2382265555Sambrisko                    mrsas_dprint(sc, MRSAS_OCR,
2383265555Sambrisko                    "Host diag unlock failed!\n");
2384265555Sambrisko                    break;
2385265555Sambrisko                }
2386265555Sambrisko            }
2387265555Sambrisko            if (!(host_diag & HOST_DIAG_WRITE_ENABLE))
2388265555Sambrisko                continue;
2389265555Sambrisko
2390265555Sambrisko            /* Send chip reset command */
2391265555Sambrisko            mrsas_write_reg(sc, offsetof(mrsas_reg_set, fusion_host_diag),
2392265555Sambrisko               host_diag | HOST_DIAG_RESET_ADAPTER);
2393265555Sambrisko            DELAY(3000 * 1000);
2394265555Sambrisko
2395265555Sambrisko            /* Make sure reset adapter bit is cleared */
2396265555Sambrisko            host_diag = mrsas_read_reg(sc, offsetof(mrsas_reg_set,
2397265555Sambrisko                                                        fusion_host_diag));
2398265555Sambrisko            retry = 0;
2399265555Sambrisko            while (host_diag & HOST_DIAG_RESET_ADAPTER) {
2400265555Sambrisko                DELAY(100 * 1000);
2401265555Sambrisko                host_diag = mrsas_read_reg(sc, offsetof(mrsas_reg_set,
2402265555Sambrisko                                                        fusion_host_diag));
2403265555Sambrisko                if (retry++ == 1000) {
2404265555Sambrisko                    mrsas_dprint(sc, MRSAS_OCR,
2405265555Sambrisko                                        "Diag reset adapter never cleared!\n");
2406265555Sambrisko                    break;
2407265555Sambrisko                }
2408265555Sambrisko            }
2409265555Sambrisko            if (host_diag & HOST_DIAG_RESET_ADAPTER)
2410265555Sambrisko                continue;
2411265555Sambrisko
2412265555Sambrisko            abs_state = mrsas_read_reg(sc, offsetof(mrsas_reg_set,
2413265555Sambrisko                                    outbound_scratch_pad)) & MFI_STATE_MASK;
2414265555Sambrisko            retry = 0;
2415265555Sambrisko
2416265555Sambrisko            while ((abs_state <= MFI_STATE_FW_INIT) && (retry++ < 1000)) {
2417265555Sambrisko                DELAY(100 * 1000);
2418265555Sambrisko                abs_state = mrsas_read_reg(sc, offsetof(mrsas_reg_set,
2419265555Sambrisko                                     outbound_scratch_pad)) & MFI_STATE_MASK;
2420265555Sambrisko            }
2421265555Sambrisko            if (abs_state <= MFI_STATE_FW_INIT) {
2422265555Sambrisko                mrsas_dprint(sc, MRSAS_OCR, "firmware state < MFI_STATE_FW_INIT,"
2423265555Sambrisko                                " state = 0x%x\n", abs_state);
2424265555Sambrisko                continue;
2425265555Sambrisko            }
2426265555Sambrisko
2427265555Sambrisko            /* Wait for FW to become ready */
2428265555Sambrisko            if (mrsas_transition_to_ready(sc, 1)) {
2429265555Sambrisko                mrsas_dprint(sc, MRSAS_OCR,
2430265555Sambrisko                           "mrsas: Failed to transition controller to ready.\n");
2431265555Sambrisko                continue;
2432265555Sambrisko            }
2433265555Sambrisko
2434265555Sambrisko            mrsas_reset_reply_desc(sc);
2435265555Sambrisko            if (mrsas_ioc_init(sc)) {
2436265555Sambrisko                mrsas_dprint(sc, MRSAS_OCR, "mrsas_ioc_init() failed!\n");
2437265555Sambrisko                continue;
2438265555Sambrisko            }
2439265555Sambrisko
2440265555Sambrisko            clear_bit(MRSAS_FUSION_IN_RESET, &sc->reset_flags);
2441265555Sambrisko            mrsas_enable_intr(sc);
2442265555Sambrisko            sc->adprecovery = MRSAS_HBA_OPERATIONAL;
2443265555Sambrisko
2444265555Sambrisko            /* Re-fire management commands */
2445265555Sambrisko            for (j = 0 ; j < sc->max_fw_cmds; j++) {
2446265555Sambrisko                mpt_cmd = sc->mpt_cmd_list[j];
2447265555Sambrisko                if (mpt_cmd->sync_cmd_idx != (u_int32_t)MRSAS_ULONG_MAX) {
2448265555Sambrisko                    mfi_cmd = sc->mfi_cmd_list[mpt_cmd->sync_cmd_idx];
2449265555Sambrisko                    if (mfi_cmd->frame->dcmd.opcode ==
2450265555Sambrisko                                          MR_DCMD_LD_MAP_GET_INFO) {
2451265555Sambrisko                        mrsas_release_mfi_cmd(mfi_cmd);
2452265555Sambrisko                        mrsas_release_mpt_cmd(mpt_cmd);
2453265555Sambrisko                    } else  {
2454265555Sambrisko                        req_desc = mrsas_get_request_desc(sc,
2455265555Sambrisko                            mfi_cmd->cmd_id.context.smid - 1);
2456265555Sambrisko                        mrsas_dprint(sc, MRSAS_OCR,
2457265555Sambrisko                            "Re-fire command DCMD opcode 0x%x index %d\n ",
2458265555Sambrisko                             mfi_cmd->frame->dcmd.opcode, j);
2459265555Sambrisko                        if (!req_desc)
2460265555Sambrisko                            device_printf(sc->mrsas_dev,
2461265555Sambrisko                                          "Cannot build MPT cmd.\n");
2462265555Sambrisko                        else
2463265555Sambrisko                            mrsas_fire_cmd(sc, req_desc->addr.u.low,
2464265555Sambrisko                                                     req_desc->addr.u.high);
2465265555Sambrisko                    }
2466265555Sambrisko                }
2467265555Sambrisko            }
2468265555Sambrisko
2469265555Sambrisko            /* Reset load balance info */
2470265555Sambrisko            memset(sc->load_balance_info, 0,
2471265555Sambrisko                   sizeof(LD_LOAD_BALANCE_INFO) * MAX_LOGICAL_DRIVES);
2472265555Sambrisko
2473265555Sambrisko            if (!mrsas_get_map_info(sc))
2474265555Sambrisko                mrsas_sync_map_info(sc);
2475265555Sambrisko
2476265555Sambrisko            /* Adapter reset completed successfully */
2477265555Sambrisko            device_printf(sc->mrsas_dev, "Reset successful\n");
2478265555Sambrisko            retval = SUCCESS;
2479265555Sambrisko            goto out;
2480265555Sambrisko        }
2481265555Sambrisko        /* Reset failed, kill the adapter */
2482265555Sambrisko        device_printf(sc->mrsas_dev, "Reset failed, killing adapter.\n");
2483265555Sambrisko        mrsas_kill_hba(sc);
2484265555Sambrisko        retval = FAIL;
2485265555Sambrisko    } else {
2486265555Sambrisko        clear_bit(MRSAS_FUSION_IN_RESET, &sc->reset_flags);
2487265555Sambrisko        mrsas_enable_intr(sc);
2488265555Sambrisko        sc->adprecovery = MRSAS_HBA_OPERATIONAL;
2489265555Sambrisko    }
2490265555Sambriskoout:
2491265555Sambrisko    clear_bit(MRSAS_FUSION_IN_RESET, &sc->reset_flags);
2492265555Sambrisko    mrsas_dprint(sc, MRSAS_OCR,
2493265555Sambrisko            "Reset Exit with %d.\n", retval);
2494265555Sambrisko    return retval;
2495265555Sambrisko}
2496265555Sambrisko
2497265555Sambrisko/**
2498265555Sambrisko * mrsas_kill_hba       Kill HBA when OCR is not supported.
2499265555Sambrisko * input:               Adapter Context.
2500265555Sambrisko *
2501265555Sambrisko * This function will kill HBA when OCR is not supported.
2502265555Sambrisko */
2503265555Sambriskovoid mrsas_kill_hba (struct mrsas_softc *sc)
2504265555Sambrisko{
2505265555Sambrisko    mrsas_dprint(sc, MRSAS_OCR, "%s\n", __func__);
2506265555Sambrisko    mrsas_write_reg(sc, offsetof(mrsas_reg_set, doorbell),
2507265555Sambrisko                        MFI_STOP_ADP);
2508265555Sambrisko    /* Flush */
2509265555Sambrisko    mrsas_read_reg(sc, offsetof(mrsas_reg_set, doorbell));
2510265555Sambrisko}
2511265555Sambrisko
2512265555Sambrisko/**
2513265555Sambrisko * mrsas_wait_for_outstanding           Wait for outstanding commands
2514265555Sambrisko * input:                               Adapter Context.
2515265555Sambrisko *
2516265555Sambrisko * This function will wait for 180 seconds for outstanding
2517265555Sambrisko * commands to be completed.
2518265555Sambrisko */
2519265555Sambriskoint mrsas_wait_for_outstanding(struct mrsas_softc *sc)
2520265555Sambrisko{
2521265555Sambrisko    int i, outstanding, retval = 0;
2522265555Sambrisko    u_int32_t fw_state;
2523265555Sambrisko
2524265555Sambrisko    for (i = 0; i < MRSAS_RESET_WAIT_TIME; i++) {
2525265555Sambrisko        if (sc->remove_in_progress) {
2526265555Sambrisko            mrsas_dprint(sc, MRSAS_OCR,
2527265555Sambrisko                "Driver remove or shutdown called.\n");
2528265555Sambrisko            retval = 1;
2529265555Sambrisko            goto out;
2530265555Sambrisko        }
2531265555Sambrisko        /* Check if firmware is in fault state */
2532265555Sambrisko        fw_state = mrsas_read_reg(sc, offsetof(mrsas_reg_set,
2533265555Sambrisko                                  outbound_scratch_pad)) & MFI_STATE_MASK;
2534265555Sambrisko        if (fw_state == MFI_STATE_FAULT) {
2535265555Sambrisko            mrsas_dprint(sc, MRSAS_OCR,
2536265555Sambrisko                         "Found FW in FAULT state, will reset adapter.\n");
2537265555Sambrisko            retval = 1;
2538265555Sambrisko            goto out;
2539265555Sambrisko        }
2540265555Sambrisko        outstanding = atomic_read(&sc->fw_outstanding);
2541265555Sambrisko        if (!outstanding)
2542265555Sambrisko            goto out;
2543265555Sambrisko
2544265555Sambrisko        if (!(i % MRSAS_RESET_NOTICE_INTERVAL)) {
2545265555Sambrisko            mrsas_dprint(sc, MRSAS_OCR, "[%2d]waiting for %d "
2546265555Sambrisko                                "commands to complete\n",i,outstanding);
2547265555Sambrisko            mrsas_complete_cmd(sc);
2548265555Sambrisko        }
2549265555Sambrisko        DELAY(1000 * 1000);
2550265555Sambrisko    }
2551265555Sambrisko
2552265555Sambrisko    if (atomic_read(&sc->fw_outstanding)) {
2553265555Sambrisko        mrsas_dprint(sc, MRSAS_OCR,
2554265555Sambrisko                        " pending commands remain after waiting,"
2555265555Sambrisko                        " will reset adapter.\n");
2556265555Sambrisko        retval = 1;
2557265555Sambrisko    }
2558265555Sambriskoout:
2559265555Sambrisko    return retval;
2560265555Sambrisko}
2561265555Sambrisko
2562265555Sambrisko/**
2563265555Sambrisko * mrsas_release_mfi_cmd: Return a cmd to free command pool
2564265555Sambrisko * input:                 Command packet for return to free cmd pool
2565265555Sambrisko *
2566265555Sambrisko * This function returns the MFI command to the command list.
2567265555Sambrisko */
2568265555Sambriskovoid mrsas_release_mfi_cmd(struct mrsas_mfi_cmd *cmd)
2569265555Sambrisko{
2570265555Sambrisko    struct mrsas_softc *sc = cmd->sc;
2571265555Sambrisko
2572265555Sambrisko    mtx_lock(&sc->mfi_cmd_pool_lock);
2573265555Sambrisko    cmd->ccb_ptr = NULL;
2574265555Sambrisko	cmd->cmd_id.frame_count = 0;
2575265555Sambrisko    TAILQ_INSERT_TAIL(&(sc->mrsas_mfi_cmd_list_head), cmd, next);
2576265555Sambrisko    mtx_unlock(&sc->mfi_cmd_pool_lock);
2577265555Sambrisko
2578265555Sambrisko    return;
2579265555Sambrisko}
2580265555Sambrisko
2581265555Sambrisko/**
2582265555Sambrisko * mrsas_get_controller_info -        Returns FW's controller structure
2583265555Sambrisko * input:                             Adapter soft state
2584265555Sambrisko *                                    Controller information structure
2585265555Sambrisko *
2586265555Sambrisko * Issues an internal command (DCMD) to get the FW's controller structure.
2587265555Sambrisko * This information is mainly used to find out the maximum IO transfer per
2588265555Sambrisko * command supported by the FW.
2589265555Sambrisko */
2590265555Sambriskostatic int mrsas_get_ctrl_info(struct mrsas_softc *sc,
2591265555Sambrisko                      struct mrsas_ctrl_info *ctrl_info)
2592265555Sambrisko{
2593265555Sambrisko    int retcode = 0;
2594265555Sambrisko    struct mrsas_mfi_cmd *cmd;
2595265555Sambrisko    struct mrsas_dcmd_frame *dcmd;
2596265555Sambrisko
2597265555Sambrisko    cmd = mrsas_get_mfi_cmd(sc);
2598265555Sambrisko
2599265555Sambrisko    if (!cmd) {
2600265555Sambrisko        device_printf(sc->mrsas_dev, "Failed to get a free cmd\n");
2601265555Sambrisko        return -ENOMEM;
2602265555Sambrisko    }
2603265555Sambrisko    dcmd = &cmd->frame->dcmd;
2604265555Sambrisko
2605265555Sambrisko    if (mrsas_alloc_ctlr_info_cmd(sc) != SUCCESS) {
2606265555Sambrisko        device_printf(sc->mrsas_dev, "Cannot allocate get ctlr info cmd\n");
2607265555Sambrisko        mrsas_release_mfi_cmd(cmd);
2608265555Sambrisko        return -ENOMEM;
2609265555Sambrisko    }
2610265555Sambrisko    memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
2611265555Sambrisko
2612265555Sambrisko    dcmd->cmd = MFI_CMD_DCMD;
2613265555Sambrisko    dcmd->cmd_status = 0xFF;
2614265555Sambrisko    dcmd->sge_count = 1;
2615265555Sambrisko    dcmd->flags = MFI_FRAME_DIR_READ;
2616265555Sambrisko    dcmd->timeout = 0;
2617265555Sambrisko    dcmd->pad_0 = 0;
2618265555Sambrisko    dcmd->data_xfer_len = sizeof(struct mrsas_ctrl_info);
2619265555Sambrisko    dcmd->opcode = MR_DCMD_CTRL_GET_INFO;
2620265555Sambrisko    dcmd->sgl.sge32[0].phys_addr = sc->ctlr_info_phys_addr;
2621265555Sambrisko    dcmd->sgl.sge32[0].length = sizeof(struct mrsas_ctrl_info);
2622265555Sambrisko
2623265555Sambrisko    if (!mrsas_issue_polled(sc, cmd))
2624265555Sambrisko        memcpy(ctrl_info, sc->ctlr_info_mem, sizeof(struct mrsas_ctrl_info));
2625265555Sambrisko    else
2626265555Sambrisko        retcode = 1;
2627265555Sambrisko
2628265555Sambrisko    mrsas_free_ctlr_info_cmd(sc);
2629265555Sambrisko    mrsas_release_mfi_cmd(cmd);
2630265555Sambrisko    return(retcode);
2631265555Sambrisko}
2632265555Sambrisko
2633265555Sambrisko/**
2634265555Sambrisko * mrsas_alloc_ctlr_info_cmd:  Allocates memory for controller info command
2635265555Sambrisko * input:                      Adapter soft state
2636265555Sambrisko *
2637265555Sambrisko * Allocates DMAable memory for the controller info internal command.
2638265555Sambrisko */
2639265555Sambriskoint mrsas_alloc_ctlr_info_cmd(struct mrsas_softc *sc)
2640265555Sambrisko{
2641265555Sambrisko    int ctlr_info_size;
2642265555Sambrisko
2643265555Sambrisko    /* Allocate get controller info command */
2644265555Sambrisko    ctlr_info_size = sizeof(struct mrsas_ctrl_info);
2645265555Sambrisko    if (bus_dma_tag_create( sc->mrsas_parent_tag,   // parent
2646265555Sambrisko                            1, 0,                   // algnmnt, boundary
2647265555Sambrisko                            BUS_SPACE_MAXADDR_32BIT,// lowaddr
2648265555Sambrisko                            BUS_SPACE_MAXADDR,      // highaddr
2649265555Sambrisko                            NULL, NULL,             // filter, filterarg
2650265555Sambrisko                            ctlr_info_size,          // maxsize
2651265555Sambrisko                            1,                      // msegments
2652265555Sambrisko                            ctlr_info_size,          // maxsegsize
2653265555Sambrisko                            BUS_DMA_ALLOCNOW,       // flags
2654265555Sambrisko                            NULL, NULL,             // lockfunc, lockarg
2655265555Sambrisko                            &sc->ctlr_info_tag)) {
2656265555Sambrisko        device_printf(sc->mrsas_dev, "Cannot allocate ctlr info tag\n");
2657265555Sambrisko        return (ENOMEM);
2658265555Sambrisko    }
2659265555Sambrisko    if (bus_dmamem_alloc(sc->ctlr_info_tag, (void **)&sc->ctlr_info_mem,
2660265555Sambrisko            BUS_DMA_NOWAIT, &sc->ctlr_info_dmamap)) {
2661265555Sambrisko        device_printf(sc->mrsas_dev, "Cannot allocate ctlr info cmd mem\n");
2662265555Sambrisko        return (ENOMEM);
2663265555Sambrisko    }
2664265555Sambrisko    if (bus_dmamap_load(sc->ctlr_info_tag, sc->ctlr_info_dmamap,
2665265555Sambrisko            sc->ctlr_info_mem, ctlr_info_size, mrsas_addr_cb,
2666265555Sambrisko            &sc->ctlr_info_phys_addr, BUS_DMA_NOWAIT)) {
2667265555Sambrisko        device_printf(sc->mrsas_dev, "Cannot load ctlr info cmd mem\n");
2668265555Sambrisko        return (ENOMEM);
2669265555Sambrisko    }
2670265555Sambrisko
2671265555Sambrisko    memset(sc->ctlr_info_mem, 0, ctlr_info_size);
2672265555Sambrisko    return (0);
2673265555Sambrisko}
2674265555Sambrisko
2675265555Sambrisko/**
2676265555Sambrisko * mrsas_free_ctlr_info_cmd: Free memory for controller info command
2677265555Sambrisko * input:                    Adapter soft state
2678265555Sambrisko *
2679265555Sambrisko * Deallocates memory of the get controller info cmd.
2680265555Sambrisko */
2681265555Sambriskovoid mrsas_free_ctlr_info_cmd(struct mrsas_softc *sc)
2682265555Sambrisko{
2683265555Sambrisko    if (sc->ctlr_info_phys_addr)
2684265555Sambrisko        bus_dmamap_unload(sc->ctlr_info_tag, sc->ctlr_info_dmamap);
2685265555Sambrisko    if (sc->ctlr_info_mem != NULL)
2686265555Sambrisko        bus_dmamem_free(sc->ctlr_info_tag, sc->ctlr_info_mem, sc->ctlr_info_dmamap);
2687265555Sambrisko    if (sc->ctlr_info_tag != NULL)
2688265555Sambrisko        bus_dma_tag_destroy(sc->ctlr_info_tag);
2689265555Sambrisko}
2690265555Sambrisko
2691265555Sambrisko/**
2692265555Sambrisko * mrsas_issue_polled:        Issues a polling command
2693265555Sambrisko * inputs:                    Adapter soft state
2694265555Sambrisko *                            Command packet to be issued
2695265555Sambrisko *
2696265555Sambrisko * This function is for posting of internal commands to Firmware.  MFI
2697265555Sambrisko * requires the cmd_status to be set to 0xFF before posting.  The maximun
2698265555Sambrisko * wait time of the poll response timer is 180 seconds.
2699265555Sambrisko */
2700265555Sambriskoint mrsas_issue_polled(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd)
2701265555Sambrisko{
2702265555Sambrisko    struct mrsas_header *frame_hdr = &cmd->frame->hdr;
2703265555Sambrisko    u_int8_t max_wait = MRSAS_INTERNAL_CMD_WAIT_TIME;
2704265555Sambrisko    int i, retcode = 0;
2705265555Sambrisko
2706265555Sambrisko    frame_hdr->cmd_status = 0xFF;
2707265555Sambrisko    frame_hdr->flags |= MFI_FRAME_DONT_POST_IN_REPLY_QUEUE;
2708265555Sambrisko
2709265555Sambrisko    /* Issue the frame using inbound queue port */
2710265555Sambrisko    if (mrsas_issue_dcmd(sc, cmd)) {
2711265555Sambrisko        device_printf(sc->mrsas_dev, "Cannot issue DCMD internal command.\n");
2712265555Sambrisko        return(1);
2713265555Sambrisko    }
2714265555Sambrisko
2715265555Sambrisko    /*
2716265555Sambrisko     * Poll response timer to wait for Firmware response.  While this
2717265555Sambrisko     * timer with the DELAY call could block CPU, the time interval for
2718265555Sambrisko     * this is only 1 millisecond.
2719265555Sambrisko     */
2720265555Sambrisko    if (frame_hdr->cmd_status == 0xFF) {
2721265555Sambrisko        for (i=0; i < (max_wait * 1000); i++){
2722265555Sambrisko            if (frame_hdr->cmd_status == 0xFF)
2723265555Sambrisko                DELAY(1000);
2724265555Sambrisko            else
2725265555Sambrisko                break;
2726265555Sambrisko        }
2727265555Sambrisko    }
2728265555Sambrisko    if (frame_hdr->cmd_status != 0)
2729265555Sambrisko    {
2730265555Sambrisko        if (frame_hdr->cmd_status == 0xFF)
2731265555Sambrisko            device_printf(sc->mrsas_dev, "DCMD timed out after %d seconds.\n", max_wait);
2732265555Sambrisko        else
2733265555Sambrisko            device_printf(sc->mrsas_dev, "DCMD failed, status = 0x%x\n", frame_hdr->cmd_status);
2734265555Sambrisko        retcode = 1;
2735265555Sambrisko    }
2736265555Sambrisko    return(retcode);
2737265555Sambrisko}
2738265555Sambrisko
2739265555Sambrisko/**
2740265555Sambrisko * mrsas_issue_dcmd -     Issues a MFI Pass thru cmd
2741265555Sambrisko * input:                 Adapter soft state
2742265555Sambrisko *                        mfi cmd pointer
2743265555Sambrisko *
2744265555Sambrisko * This function is called by mrsas_issued_blocked_cmd() and
2745265555Sambrisko * mrsas_issued_polled(), to build the MPT command and then fire the
2746265555Sambrisko * command to Firmware.
2747265555Sambrisko */
2748265555Sambriskoint
2749265555Sambriskomrsas_issue_dcmd(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd)
2750265555Sambrisko{
2751265555Sambrisko    MRSAS_REQUEST_DESCRIPTOR_UNION *req_desc;
2752265555Sambrisko
2753265555Sambrisko    req_desc = mrsas_build_mpt_cmd(sc, cmd);
2754265555Sambrisko    if (!req_desc) {
2755265555Sambrisko        device_printf(sc->mrsas_dev, "Cannot build MPT cmd.\n");
2756265555Sambrisko        return(1);
2757265555Sambrisko    }
2758265555Sambrisko
2759265555Sambrisko    mrsas_fire_cmd(sc, req_desc->addr.u.low, req_desc->addr.u.high);
2760265555Sambrisko
2761265555Sambrisko    return(0);
2762265555Sambrisko}
2763265555Sambrisko
2764265555Sambrisko/**
2765265555Sambrisko * mrsas_build_mpt_cmd - Calls helper function to build Passthru cmd
2766265555Sambrisko * input:                Adapter soft state
2767265555Sambrisko *                       mfi cmd to build
2768265555Sambrisko *
2769265555Sambrisko * This function is called by mrsas_issue_cmd() to build the MPT-MFI
2770265555Sambrisko * passthru command and prepares the MPT command to send to Firmware.
2771265555Sambrisko */
2772265555SambriskoMRSAS_REQUEST_DESCRIPTOR_UNION *
2773265555Sambriskomrsas_build_mpt_cmd(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd)
2774265555Sambrisko{
2775265555Sambrisko    MRSAS_REQUEST_DESCRIPTOR_UNION *req_desc;
2776265555Sambrisko    u_int16_t index;
2777265555Sambrisko
2778265555Sambrisko    if (mrsas_build_mptmfi_passthru(sc, cmd)) {
2779265555Sambrisko        device_printf(sc->mrsas_dev, "Cannot build MPT-MFI passthru cmd.\n");
2780265555Sambrisko        return NULL;
2781265555Sambrisko    }
2782265555Sambrisko
2783265555Sambrisko    index = cmd->cmd_id.context.smid;
2784265555Sambrisko
2785265555Sambrisko    req_desc = mrsas_get_request_desc(sc, index-1);
2786265555Sambrisko    if(!req_desc)
2787265555Sambrisko        return NULL;
2788265555Sambrisko
2789265555Sambrisko    req_desc->addr.Words = 0;
2790265555Sambrisko    req_desc->SCSIIO.RequestFlags = (MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO << MRSAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
2791265555Sambrisko
2792265555Sambrisko    req_desc->SCSIIO.SMID = index;
2793265555Sambrisko
2794265555Sambrisko    return(req_desc);
2795265555Sambrisko}
2796265555Sambrisko
2797265555Sambrisko/**
2798265555Sambrisko * mrsas_build_mptmfi_passthru - Builds a MPT MFI Passthru command
2799265555Sambrisko * input:                        Adapter soft state
2800265555Sambrisko *                               mfi cmd pointer
2801265555Sambrisko *
2802265555Sambrisko * The MPT command and the io_request are setup as a passthru command.
2803265555Sambrisko * The SGE chain address is set to frame_phys_addr of the MFI command.
2804265555Sambrisko */
2805265555Sambriskou_int8_t
2806265555Sambriskomrsas_build_mptmfi_passthru(struct mrsas_softc *sc, struct mrsas_mfi_cmd *mfi_cmd)
2807265555Sambrisko{
2808265555Sambrisko    MPI25_IEEE_SGE_CHAIN64 *mpi25_ieee_chain;
2809265555Sambrisko    PTR_MRSAS_RAID_SCSI_IO_REQUEST io_req;
2810265555Sambrisko    struct mrsas_mpt_cmd *mpt_cmd;
2811265555Sambrisko    struct mrsas_header *frame_hdr = &mfi_cmd->frame->hdr;
2812265555Sambrisko
2813265555Sambrisko    mpt_cmd = mrsas_get_mpt_cmd(sc);
2814265555Sambrisko    if (!mpt_cmd)
2815265555Sambrisko        return(1);
2816265555Sambrisko
2817265555Sambrisko    /* Save the smid. To be used for returning the cmd */
2818265555Sambrisko    mfi_cmd->cmd_id.context.smid = mpt_cmd->index;
2819265555Sambrisko
2820265555Sambrisko    mpt_cmd->sync_cmd_idx = mfi_cmd->index;
2821265555Sambrisko
2822265555Sambrisko    /*
2823265555Sambrisko     * For cmds where the flag is set, store the flag and check
2824265555Sambrisko     * on completion. For cmds with this flag, don't call
2825265555Sambrisko     * mrsas_complete_cmd.
2826265555Sambrisko     */
2827265555Sambrisko
2828265555Sambrisko    if (frame_hdr->flags & MFI_FRAME_DONT_POST_IN_REPLY_QUEUE)
2829265555Sambrisko        mpt_cmd->flags = MFI_FRAME_DONT_POST_IN_REPLY_QUEUE;
2830265555Sambrisko
2831265555Sambrisko    io_req = mpt_cmd->io_request;
2832265555Sambrisko
2833265555Sambrisko    if ((sc->device_id == MRSAS_INVADER) || (sc->device_id == MRSAS_FURY)) {
2834265555Sambrisko		pMpi25IeeeSgeChain64_t sgl_ptr_end = (pMpi25IeeeSgeChain64_t) &io_req->SGL;
2835265555Sambrisko                sgl_ptr_end += sc->max_sge_in_main_msg - 1;
2836265555Sambrisko                sgl_ptr_end->Flags = 0;
2837265555Sambrisko    }
2838265555Sambrisko
2839265555Sambrisko    mpi25_ieee_chain = (MPI25_IEEE_SGE_CHAIN64 *)&io_req->SGL.IeeeChain;
2840265555Sambrisko
2841265555Sambrisko    io_req->Function    = MRSAS_MPI2_FUNCTION_PASSTHRU_IO_REQUEST;
2842265555Sambrisko    io_req->SGLOffset0  = offsetof(MRSAS_RAID_SCSI_IO_REQUEST, SGL) / 4;
2843265555Sambrisko    io_req->ChainOffset = sc->chain_offset_mfi_pthru;
2844265555Sambrisko
2845265555Sambrisko    mpi25_ieee_chain->Address = mfi_cmd->frame_phys_addr;
2846265555Sambrisko
2847265555Sambrisko    mpi25_ieee_chain->Flags= IEEE_SGE_FLAGS_CHAIN_ELEMENT |
2848265555Sambrisko              MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR;
2849265555Sambrisko
2850265555Sambrisko    mpi25_ieee_chain->Length = MRSAS_MAX_SZ_CHAIN_FRAME;
2851265555Sambrisko
2852265555Sambrisko    return(0);
2853265555Sambrisko}
2854265555Sambrisko
2855265555Sambrisko/**
2856265555Sambrisko * mrsas_issue_blocked_cmd - Synchronous wrapper around regular FW cmds
2857265555Sambrisko * input:                    Adapter soft state
2858265555Sambrisko *                           Command to be issued
2859265555Sambrisko *
2860265555Sambrisko * This function waits on an event for the command to be returned
2861265555Sambrisko * from the ISR. Max wait time is MRSAS_INTERNAL_CMD_WAIT_TIME secs.
2862265555Sambrisko * Used for issuing internal and ioctl commands.
2863265555Sambrisko */
2864265555Sambriskoint mrsas_issue_blocked_cmd(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd)
2865265555Sambrisko{
2866265555Sambrisko    u_int8_t max_wait = MRSAS_INTERNAL_CMD_WAIT_TIME;
2867265555Sambrisko    unsigned long total_time = 0;
2868265555Sambrisko    int retcode = 0;
2869265555Sambrisko
2870265555Sambrisko    /* Initialize cmd_status */
2871265555Sambrisko    cmd->cmd_status = ECONNREFUSED;
2872265555Sambrisko
2873265555Sambrisko    /* Build MPT-MFI command for issue to FW */
2874265555Sambrisko    if (mrsas_issue_dcmd(sc, cmd)){
2875265555Sambrisko        device_printf(sc->mrsas_dev, "Cannot issue DCMD internal command.\n");
2876265555Sambrisko        return(1);
2877265555Sambrisko    }
2878265555Sambrisko
2879265555Sambrisko    sc->chan = (void*)&cmd;
2880265555Sambrisko
2881265555Sambrisko    /* The following is for debug only... */
2882265555Sambrisko    //device_printf(sc->mrsas_dev,"DCMD issued to FW, about to sleep-wait...\n");
2883265555Sambrisko    //device_printf(sc->mrsas_dev,"sc->chan = %p\n", sc->chan);
2884265555Sambrisko
2885265555Sambrisko    while (1) {
2886265555Sambrisko       if (cmd->cmd_status == ECONNREFUSED){
2887265555Sambrisko           tsleep((void *)&sc->chan, 0, "mrsas_sleep", hz);
2888265555Sambrisko       }
2889265555Sambrisko       else
2890265555Sambrisko           break;
2891265555Sambrisko       total_time++;
2892265555Sambrisko       if (total_time >= max_wait) {
2893265555Sambrisko           device_printf(sc->mrsas_dev, "Internal command timed out after %d seconds.\n", max_wait);
2894265555Sambrisko           retcode = 1;
2895265555Sambrisko           break;
2896265555Sambrisko       }
2897265555Sambrisko    }
2898265555Sambrisko    return(retcode);
2899265555Sambrisko}
2900265555Sambrisko
2901265555Sambrisko/**
2902265555Sambrisko * mrsas_complete_mptmfi_passthru - Completes a command
2903265555Sambrisko * input:                           sc: Adapter soft state
2904265555Sambrisko *                                  cmd: Command to be completed
2905265555Sambrisko *                                  status: cmd completion status
2906265555Sambrisko *
2907265555Sambrisko * This function is called from mrsas_complete_cmd() after an interrupt
2908265555Sambrisko * is received from Firmware, and io_request->Function is
2909265555Sambrisko * MRSAS_MPI2_FUNCTION_PASSTHRU_IO_REQUEST.
2910265555Sambrisko */
2911265555Sambriskovoid
2912265555Sambriskomrsas_complete_mptmfi_passthru(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd,
2913265555Sambrisko                     u_int8_t status)
2914265555Sambrisko{
2915265555Sambrisko    struct mrsas_header *hdr = &cmd->frame->hdr;
2916265555Sambrisko    u_int8_t cmd_status = cmd->frame->hdr.cmd_status;
2917265555Sambrisko
2918265555Sambrisko    /* Reset the retry counter for future re-tries */
2919265555Sambrisko    cmd->retry_for_fw_reset = 0;
2920265555Sambrisko
2921265555Sambrisko    if (cmd->ccb_ptr)
2922265555Sambrisko        cmd->ccb_ptr = NULL;
2923265555Sambrisko
2924265555Sambrisko    switch (hdr->cmd) {
2925265555Sambrisko        case MFI_CMD_INVALID:
2926265555Sambrisko            device_printf(sc->mrsas_dev, "MFI_CMD_INVALID command.\n");
2927265555Sambrisko            break;
2928265555Sambrisko        case MFI_CMD_PD_SCSI_IO:
2929265555Sambrisko        case MFI_CMD_LD_SCSI_IO:
2930265555Sambrisko            /*
2931265555Sambrisko             * MFI_CMD_PD_SCSI_IO and MFI_CMD_LD_SCSI_IO could have been
2932265555Sambrisko             * issued either through an IO path or an IOCTL path. If it
2933265555Sambrisko             * was via IOCTL, we will send it to internal completion.
2934265555Sambrisko             */
2935265555Sambrisko            if (cmd->sync_cmd) {
2936265555Sambrisko                cmd->sync_cmd = 0;
2937265555Sambrisko                mrsas_wakeup(sc, cmd);
2938265555Sambrisko                break;
2939265555Sambrisko            }
2940265555Sambrisko        case MFI_CMD_SMP:
2941265555Sambrisko        case MFI_CMD_STP:
2942265555Sambrisko        case MFI_CMD_DCMD:
2943265555Sambrisko            /* Check for LD map update */
2944265555Sambrisko            if ((cmd->frame->dcmd.opcode == MR_DCMD_LD_MAP_GET_INFO) &&
2945265555Sambrisko                (cmd->frame->dcmd.mbox.b[1] == 1)) {
2946265555Sambrisko                sc->fast_path_io = 0;
2947265555Sambrisko		        mtx_lock(&sc->raidmap_lock);
2948265555Sambrisko                if (cmd_status != 0) {
2949265555Sambrisko                    if (cmd_status != MFI_STAT_NOT_FOUND)
2950265555Sambrisko                        device_printf(sc->mrsas_dev, "map sync failed, status=%x\n",cmd_status);
2951265555Sambrisko                    else {
2952265555Sambrisko                        mrsas_release_mfi_cmd(cmd);
2953265555Sambrisko		        mtx_unlock(&sc->raidmap_lock);
2954265555Sambrisko                        break;
2955265555Sambrisko                    }
2956265555Sambrisko                }
2957265555Sambrisko                else
2958265555Sambrisko                    sc->map_id++;
2959265555Sambrisko                mrsas_release_mfi_cmd(cmd);
2960265555Sambrisko                if (MR_ValidateMapInfo(sc))
2961265555Sambrisko                    sc->fast_path_io = 0;
2962265555Sambrisko                else
2963265555Sambrisko                    sc->fast_path_io = 1;
2964265555Sambrisko                mrsas_sync_map_info(sc);
2965265555Sambrisko                mtx_unlock(&sc->raidmap_lock);
2966265555Sambrisko                break;
2967265555Sambrisko            }
2968265555Sambrisko#if 0 //currently not supporting event handling, so commenting out
2969265555Sambrisko            if (cmd->frame->dcmd.opcode == MR_DCMD_CTRL_EVENT_GET_INFO ||
2970265555Sambrisko                    cmd->frame->dcmd.opcode == MR_DCMD_CTRL_EVENT_GET) {
2971265555Sambrisko                mrsas_poll_wait_aen = 0;
2972265555Sambrisko            }
2973265555Sambrisko#endif
2974265555Sambrisko            /* See if got an event notification */
2975265555Sambrisko            if (cmd->frame->dcmd.opcode == MR_DCMD_CTRL_EVENT_WAIT)
2976265555Sambrisko                mrsas_complete_aen(sc, cmd);
2977265555Sambrisko            else
2978265555Sambrisko                mrsas_wakeup(sc, cmd);
2979265555Sambrisko            break;
2980265555Sambrisko        case MFI_CMD_ABORT:
2981265555Sambrisko            /* Command issued to abort another cmd return */
2982265555Sambrisko            mrsas_complete_abort(sc, cmd);
2983265555Sambrisko            break;
2984265555Sambrisko        default:
2985265555Sambrisko            device_printf(sc->mrsas_dev,"Unknown command completed! [0x%X]\n", hdr->cmd);
2986265555Sambrisko            break;
2987265555Sambrisko    }
2988265555Sambrisko}
2989265555Sambrisko
2990265555Sambrisko/**
2991265555Sambrisko * mrsas_wakeup -         Completes an internal command
2992265555Sambrisko * input:                 Adapter soft state
2993265555Sambrisko *                        Command to be completed
2994265555Sambrisko *
2995265555Sambrisko * In mrsas_issue_blocked_cmd(), after a command is issued to Firmware,
2996265555Sambrisko * a wait timer is started.  This function is called from
2997265555Sambrisko * mrsas_complete_mptmfi_passthru() as it completes the command,
2998265555Sambrisko * to wake up from the command wait.
2999265555Sambrisko */
3000265555Sambriskovoid mrsas_wakeup(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd)
3001265555Sambrisko{
3002265555Sambrisko    cmd->cmd_status = cmd->frame->io.cmd_status;
3003265555Sambrisko
3004265555Sambrisko    if (cmd->cmd_status == ECONNREFUSED)
3005265555Sambrisko        cmd->cmd_status = 0;
3006265555Sambrisko
3007265555Sambrisko    /* For debug only ... */
3008265555Sambrisko    //device_printf(sc->mrsas_dev,"DCMD rec'd for wakeup, sc->chan=%p\n", sc->chan);
3009265555Sambrisko
3010265555Sambrisko    sc->chan = (void*)&cmd;
3011265555Sambrisko    wakeup_one((void *)&sc->chan);
3012265555Sambrisko    return;
3013265555Sambrisko}
3014265555Sambrisko
3015265555Sambrisko/**
3016265555Sambrisko * mrsas_shutdown_ctlr:       Instructs FW to shutdown the controller
3017265555Sambrisko * input:                     Adapter soft state
3018265555Sambrisko *                            Shutdown/Hibernate
3019265555Sambrisko *
3020265555Sambrisko * This function issues a DCMD internal command to Firmware to initiate
3021265555Sambrisko * shutdown of the controller.
3022265555Sambrisko */
3023265555Sambriskostatic void mrsas_shutdown_ctlr(struct mrsas_softc *sc, u_int32_t opcode)
3024265555Sambrisko{
3025265555Sambrisko    struct mrsas_mfi_cmd *cmd;
3026265555Sambrisko    struct mrsas_dcmd_frame *dcmd;
3027265555Sambrisko
3028265555Sambrisko    if (sc->adprecovery == MRSAS_HW_CRITICAL_ERROR)
3029265555Sambrisko        return;
3030265555Sambrisko
3031265555Sambrisko    cmd = mrsas_get_mfi_cmd(sc);
3032265555Sambrisko    if (!cmd) {
3033265555Sambrisko        device_printf(sc->mrsas_dev,"Cannot allocate for shutdown cmd.\n");
3034265555Sambrisko        return;
3035265555Sambrisko    }
3036265555Sambrisko
3037265555Sambrisko	if (sc->aen_cmd)
3038265555Sambrisko        mrsas_issue_blocked_abort_cmd(sc, sc->aen_cmd);
3039265555Sambrisko
3040265555Sambrisko	if (sc->map_update_cmd)
3041265555Sambrisko        mrsas_issue_blocked_abort_cmd(sc, sc->map_update_cmd);
3042265555Sambrisko
3043265555Sambrisko    dcmd = &cmd->frame->dcmd;
3044265555Sambrisko    memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
3045265555Sambrisko
3046265555Sambrisko    dcmd->cmd = MFI_CMD_DCMD;
3047265555Sambrisko    dcmd->cmd_status = 0x0;
3048265555Sambrisko    dcmd->sge_count = 0;
3049265555Sambrisko    dcmd->flags = MFI_FRAME_DIR_NONE;
3050265555Sambrisko    dcmd->timeout = 0;
3051265555Sambrisko    dcmd->pad_0 = 0;
3052265555Sambrisko    dcmd->data_xfer_len = 0;
3053265555Sambrisko    dcmd->opcode = opcode;
3054265555Sambrisko
3055265555Sambrisko    device_printf(sc->mrsas_dev,"Preparing to shut down controller.\n");
3056265555Sambrisko
3057265555Sambrisko    mrsas_issue_blocked_cmd(sc, cmd);
3058265555Sambrisko    mrsas_release_mfi_cmd(cmd);
3059265555Sambrisko
3060265555Sambrisko    return;
3061265555Sambrisko}
3062265555Sambrisko
3063265555Sambrisko/**
3064265555Sambrisko * mrsas_flush_cache:         Requests FW to flush all its caches
3065265555Sambrisko * input:                     Adapter soft state
3066265555Sambrisko *
3067265555Sambrisko * This function is issues a DCMD internal command to Firmware to initiate
3068265555Sambrisko * flushing of all caches.
3069265555Sambrisko */
3070265555Sambriskostatic void mrsas_flush_cache(struct mrsas_softc *sc)
3071265555Sambrisko{
3072265555Sambrisko    struct mrsas_mfi_cmd *cmd;
3073265555Sambrisko    struct mrsas_dcmd_frame *dcmd;
3074265555Sambrisko
3075265555Sambrisko    if (sc->adprecovery == MRSAS_HW_CRITICAL_ERROR)
3076265555Sambrisko        return;
3077265555Sambrisko
3078265555Sambrisko    cmd = mrsas_get_mfi_cmd(sc);
3079265555Sambrisko    if (!cmd) {
3080265555Sambrisko        device_printf(sc->mrsas_dev,"Cannot allocate for flush cache cmd.\n");
3081265555Sambrisko        return;
3082265555Sambrisko    }
3083265555Sambrisko
3084265555Sambrisko    dcmd = &cmd->frame->dcmd;
3085265555Sambrisko    memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
3086265555Sambrisko
3087265555Sambrisko    dcmd->cmd = MFI_CMD_DCMD;
3088265555Sambrisko    dcmd->cmd_status = 0x0;
3089265555Sambrisko    dcmd->sge_count = 0;
3090265555Sambrisko    dcmd->flags = MFI_FRAME_DIR_NONE;
3091265555Sambrisko    dcmd->timeout = 0;
3092265555Sambrisko    dcmd->pad_0 = 0;
3093265555Sambrisko    dcmd->data_xfer_len = 0;
3094265555Sambrisko    dcmd->opcode = MR_DCMD_CTRL_CACHE_FLUSH;
3095265555Sambrisko    dcmd->mbox.b[0] = MR_FLUSH_CTRL_CACHE | MR_FLUSH_DISK_CACHE;
3096265555Sambrisko
3097265555Sambrisko    mrsas_issue_blocked_cmd(sc, cmd);
3098265555Sambrisko    mrsas_release_mfi_cmd(cmd);
3099265555Sambrisko
3100265555Sambrisko    return;
3101265555Sambrisko}
3102265555Sambrisko
3103265555Sambrisko/**
3104265555Sambrisko * mrsas_get_map_info:        Load and validate RAID map
3105265555Sambrisko * input:                     Adapter instance soft state
3106265555Sambrisko *
3107265555Sambrisko * This function calls mrsas_get_ld_map_info() and MR_ValidateMapInfo()
3108265555Sambrisko * to load and validate RAID map.  It returns 0 if successful, 1 other-
3109265555Sambrisko * wise.
3110265555Sambrisko */
3111265555Sambriskostatic int mrsas_get_map_info(struct mrsas_softc *sc)
3112265555Sambrisko{
3113265555Sambrisko   uint8_t  retcode = 0;
3114265555Sambrisko
3115265555Sambrisko    sc->fast_path_io = 0;
3116265555Sambrisko    if (!mrsas_get_ld_map_info(sc)) {
3117265555Sambrisko        retcode = MR_ValidateMapInfo(sc);
3118265555Sambrisko        if (retcode == 0) {
3119265555Sambrisko            sc->fast_path_io = 1;
3120265555Sambrisko            return 0;
3121265555Sambrisko        }
3122265555Sambrisko    }
3123265555Sambrisko    return 1;
3124265555Sambrisko}
3125265555Sambrisko
3126265555Sambrisko/**
3127265555Sambrisko * mrsas_get_ld_map_info:      Get FW's ld_map structure
3128265555Sambrisko * input:                      Adapter instance soft state
3129265555Sambrisko *
3130265555Sambrisko * Issues an internal command (DCMD) to get the FW's controller PD
3131265555Sambrisko * list structure.
3132265555Sambrisko */
3133265555Sambriskostatic int mrsas_get_ld_map_info(struct mrsas_softc *sc)
3134265555Sambrisko{
3135265555Sambrisko    int retcode = 0;
3136265555Sambrisko    struct mrsas_mfi_cmd *cmd;
3137265555Sambrisko    struct mrsas_dcmd_frame *dcmd;
3138265555Sambrisko    MR_FW_RAID_MAP_ALL *map;
3139265555Sambrisko    bus_addr_t map_phys_addr = 0;
3140265555Sambrisko
3141265555Sambrisko    cmd = mrsas_get_mfi_cmd(sc);
3142265555Sambrisko    if (!cmd) {
3143265555Sambrisko        device_printf(sc->mrsas_dev, "Cannot alloc for ld map info cmd.\n");
3144265555Sambrisko        return 1;
3145265555Sambrisko    }
3146265555Sambrisko
3147265555Sambrisko    dcmd = &cmd->frame->dcmd;
3148265555Sambrisko
3149265555Sambrisko    map = sc->raidmap_mem[(sc->map_id & 1)];
3150265555Sambrisko    map_phys_addr = sc->raidmap_phys_addr[(sc->map_id & 1)];
3151265555Sambrisko    if (!map) {
3152265555Sambrisko        device_printf(sc->mrsas_dev, "Failed to alloc mem for ld map info.\n");
3153265555Sambrisko        mrsas_release_mfi_cmd(cmd);
3154265555Sambrisko        return (ENOMEM);
3155265555Sambrisko    }
3156265555Sambrisko    memset(map, 0, sizeof(*map));
3157265555Sambrisko    memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
3158265555Sambrisko
3159265555Sambrisko    dcmd->cmd = MFI_CMD_DCMD;
3160265555Sambrisko    dcmd->cmd_status = 0xFF;
3161265555Sambrisko    dcmd->sge_count = 1;
3162265555Sambrisko    dcmd->flags = MFI_FRAME_DIR_READ;
3163265555Sambrisko    dcmd->timeout = 0;
3164265555Sambrisko    dcmd->pad_0 = 0;
3165265555Sambrisko    dcmd->data_xfer_len = sc->map_sz;
3166265555Sambrisko    dcmd->opcode = MR_DCMD_LD_MAP_GET_INFO;
3167265555Sambrisko    dcmd->sgl.sge32[0].phys_addr = map_phys_addr;
3168265555Sambrisko    dcmd->sgl.sge32[0].length = sc->map_sz;
3169265555Sambrisko    if (!mrsas_issue_polled(sc, cmd))
3170265555Sambrisko        retcode = 0;
3171265555Sambrisko    else
3172265555Sambrisko    {
3173265555Sambrisko        device_printf(sc->mrsas_dev, "Fail to send get LD map info cmd.\n");
3174265555Sambrisko        retcode = 1;
3175265555Sambrisko    }
3176265555Sambrisko    mrsas_release_mfi_cmd(cmd);
3177265555Sambrisko    return(retcode);
3178265555Sambrisko}
3179265555Sambrisko
3180265555Sambrisko/**
3181265555Sambrisko * mrsas_sync_map_info:        Get FW's ld_map structure
3182265555Sambrisko * input:                      Adapter instance soft state
3183265555Sambrisko *
3184265555Sambrisko * Issues an internal command (DCMD) to get the FW's controller PD
3185265555Sambrisko * list structure.
3186265555Sambrisko */
3187265555Sambriskostatic int mrsas_sync_map_info(struct mrsas_softc *sc)
3188265555Sambrisko{
3189265555Sambrisko    int retcode = 0, i;
3190265555Sambrisko    struct mrsas_mfi_cmd *cmd;
3191265555Sambrisko    struct mrsas_dcmd_frame *dcmd;
3192265555Sambrisko    uint32_t size_sync_info, num_lds;
3193265555Sambrisko    MR_LD_TARGET_SYNC *target_map = NULL;
3194265555Sambrisko    MR_FW_RAID_MAP_ALL *map;
3195265555Sambrisko    MR_LD_RAID  *raid;
3196265555Sambrisko    MR_LD_TARGET_SYNC *ld_sync;
3197265555Sambrisko    bus_addr_t map_phys_addr = 0;
3198265555Sambrisko
3199265555Sambrisko    cmd = mrsas_get_mfi_cmd(sc);
3200265555Sambrisko    if (!cmd) {
3201265555Sambrisko        device_printf(sc->mrsas_dev, "Cannot alloc for sync map info cmd\n");
3202265555Sambrisko        return 1;
3203265555Sambrisko    }
3204265555Sambrisko
3205265555Sambrisko    map = sc->raidmap_mem[sc->map_id & 1];
3206265555Sambrisko    num_lds = map->raidMap.ldCount;
3207265555Sambrisko
3208265555Sambrisko    dcmd = &cmd->frame->dcmd;
3209265555Sambrisko    size_sync_info = sizeof(MR_LD_TARGET_SYNC) * num_lds;
3210265555Sambrisko    memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
3211265555Sambrisko
3212265555Sambrisko    target_map = (MR_LD_TARGET_SYNC *)sc->raidmap_mem[(sc->map_id - 1) & 1];
3213265555Sambrisko    memset(target_map, 0, sizeof(MR_FW_RAID_MAP_ALL));
3214265555Sambrisko
3215265555Sambrisko    map_phys_addr = sc->raidmap_phys_addr[(sc->map_id - 1) & 1];
3216265555Sambrisko
3217265555Sambrisko    ld_sync = (MR_LD_TARGET_SYNC *)target_map;
3218265555Sambrisko
3219265555Sambrisko    for (i = 0; i < num_lds; i++, ld_sync++) {
3220265555Sambrisko        raid = MR_LdRaidGet(i, map);
3221265555Sambrisko        ld_sync->targetId = MR_GetLDTgtId(i, map);
3222265555Sambrisko        ld_sync->seqNum = raid->seqNum;
3223265555Sambrisko    }
3224265555Sambrisko
3225265555Sambrisko    dcmd->cmd = MFI_CMD_DCMD;
3226265555Sambrisko    dcmd->cmd_status = 0xFF;
3227265555Sambrisko    dcmd->sge_count = 1;
3228265555Sambrisko    dcmd->flags = MFI_FRAME_DIR_WRITE;
3229265555Sambrisko    dcmd->timeout = 0;
3230265555Sambrisko    dcmd->pad_0 = 0;
3231265555Sambrisko    dcmd->data_xfer_len = sc->map_sz;
3232265555Sambrisko    dcmd->mbox.b[0] = num_lds;
3233265555Sambrisko    dcmd->mbox.b[1] = MRSAS_DCMD_MBOX_PEND_FLAG;
3234265555Sambrisko    dcmd->opcode = MR_DCMD_LD_MAP_GET_INFO;
3235265555Sambrisko    dcmd->sgl.sge32[0].phys_addr = map_phys_addr;
3236265555Sambrisko    dcmd->sgl.sge32[0].length = sc->map_sz;
3237265555Sambrisko
3238265555Sambrisko    sc->map_update_cmd = cmd;
3239265555Sambrisko    if (mrsas_issue_dcmd(sc, cmd)) {
3240265555Sambrisko        device_printf(sc->mrsas_dev, "Fail to send sync map info command.\n");
3241265555Sambrisko        return(1);
3242265555Sambrisko    }
3243265555Sambrisko    return(retcode);
3244265555Sambrisko}
3245265555Sambrisko
3246265555Sambrisko/**
3247265555Sambrisko * mrsas_get_pd_list:           Returns FW's PD list structure
3248265555Sambrisko * input:                       Adapter soft state
3249265555Sambrisko *
3250265555Sambrisko * Issues an internal command (DCMD) to get the FW's controller PD
3251265555Sambrisko * list structure.  This information is mainly used to find out about
3252265555Sambrisko * system supported by Firmware.
3253265555Sambrisko */
3254265555Sambriskostatic int mrsas_get_pd_list(struct mrsas_softc *sc)
3255265555Sambrisko{
3256265555Sambrisko    int retcode = 0, pd_index = 0, pd_count=0, pd_list_size;
3257265555Sambrisko    struct mrsas_mfi_cmd *cmd;
3258265555Sambrisko    struct mrsas_dcmd_frame *dcmd;
3259265555Sambrisko    struct MR_PD_LIST *pd_list_mem;
3260265555Sambrisko    struct MR_PD_ADDRESS *pd_addr;
3261265555Sambrisko    bus_addr_t pd_list_phys_addr = 0;
3262265555Sambrisko    struct mrsas_tmp_dcmd *tcmd;
3263265555Sambrisko
3264265555Sambrisko    cmd = mrsas_get_mfi_cmd(sc);
3265265555Sambrisko    if (!cmd) {
3266265555Sambrisko        device_printf(sc->mrsas_dev, "Cannot alloc for get PD list cmd\n");
3267265555Sambrisko        return 1;
3268265555Sambrisko    }
3269265555Sambrisko
3270265555Sambrisko    dcmd = &cmd->frame->dcmd;
3271265555Sambrisko
3272265555Sambrisko    tcmd = malloc(sizeof(struct mrsas_tmp_dcmd), M_MRSAS, M_NOWAIT);
3273265555Sambrisko    pd_list_size = MRSAS_MAX_PD * sizeof(struct MR_PD_LIST);
3274265555Sambrisko    if (mrsas_alloc_tmp_dcmd(sc, tcmd, pd_list_size) != SUCCESS) {
3275265555Sambrisko        device_printf(sc->mrsas_dev, "Cannot alloc dmamap for get PD list cmd\n");
3276265555Sambrisko        mrsas_release_mfi_cmd(cmd);
3277265555Sambrisko        return(ENOMEM);
3278265555Sambrisko    }
3279265555Sambrisko    else {
3280265555Sambrisko        pd_list_mem = tcmd->tmp_dcmd_mem;
3281265555Sambrisko        pd_list_phys_addr = tcmd->tmp_dcmd_phys_addr;
3282265555Sambrisko    }
3283265555Sambrisko    memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
3284265555Sambrisko
3285265555Sambrisko    dcmd->mbox.b[0] = MR_PD_QUERY_TYPE_EXPOSED_TO_HOST;
3286265555Sambrisko    dcmd->mbox.b[1] = 0;
3287265555Sambrisko    dcmd->cmd = MFI_CMD_DCMD;
3288265555Sambrisko    dcmd->cmd_status = 0xFF;
3289265555Sambrisko    dcmd->sge_count = 1;
3290265555Sambrisko    dcmd->flags = MFI_FRAME_DIR_READ;
3291265555Sambrisko    dcmd->timeout = 0;
3292265555Sambrisko    dcmd->pad_0 = 0;
3293265555Sambrisko    dcmd->data_xfer_len = MRSAS_MAX_PD * sizeof(struct MR_PD_LIST);
3294265555Sambrisko    dcmd->opcode = MR_DCMD_PD_LIST_QUERY;
3295265555Sambrisko    dcmd->sgl.sge32[0].phys_addr = pd_list_phys_addr;
3296265555Sambrisko    dcmd->sgl.sge32[0].length = MRSAS_MAX_PD * sizeof(struct MR_PD_LIST);
3297265555Sambrisko
3298265555Sambrisko    if (!mrsas_issue_polled(sc, cmd))
3299265555Sambrisko        retcode = 0;
3300265555Sambrisko    else
3301265555Sambrisko        retcode = 1;
3302265555Sambrisko
3303265555Sambrisko    /* Get the instance PD list */
3304265555Sambrisko    pd_count = MRSAS_MAX_PD;
3305265555Sambrisko    pd_addr = pd_list_mem->addr;
3306265555Sambrisko    if (retcode == 0 && pd_list_mem->count < pd_count) {
3307265555Sambrisko        memset(sc->local_pd_list, 0, MRSAS_MAX_PD * sizeof(struct mrsas_pd_list));
3308265555Sambrisko        for (pd_index = 0; pd_index < pd_list_mem->count; pd_index++) {
3309265555Sambrisko            sc->local_pd_list[pd_addr->deviceId].tid = pd_addr->deviceId;
3310265555Sambrisko            sc->local_pd_list[pd_addr->deviceId].driveType = pd_addr->scsiDevType;
3311265555Sambrisko            sc->local_pd_list[pd_addr->deviceId].driveState = MR_PD_STATE_SYSTEM;
3312265555Sambrisko            pd_addr++;
3313265555Sambrisko        }
3314265555Sambrisko    }
3315265555Sambrisko
3316265555Sambrisko    /* Use mutext/spinlock if pd_list component size increase more than 32 bit. */
3317265555Sambrisko    memcpy(sc->pd_list, sc->local_pd_list, sizeof(sc->local_pd_list));
3318265555Sambrisko    mrsas_free_tmp_dcmd(tcmd);
3319265555Sambrisko    mrsas_release_mfi_cmd(cmd);
3320265555Sambrisko    free(tcmd, M_MRSAS);
3321265555Sambrisko    return(retcode);
3322265555Sambrisko}
3323265555Sambrisko
3324265555Sambrisko/**
3325265555Sambrisko * mrsas_get_ld_list:           Returns FW's LD list structure
3326265555Sambrisko * input:                       Adapter soft state
3327265555Sambrisko *
3328265555Sambrisko * Issues an internal command (DCMD) to get the FW's controller PD
3329265555Sambrisko * list structure.  This information is mainly used to find out about
3330265555Sambrisko * supported by the FW.
3331265555Sambrisko */
3332265555Sambriskostatic int mrsas_get_ld_list(struct mrsas_softc *sc)
3333265555Sambrisko{
3334265555Sambrisko    int ld_list_size, retcode = 0, ld_index = 0, ids = 0;
3335265555Sambrisko    struct mrsas_mfi_cmd *cmd;
3336265555Sambrisko    struct mrsas_dcmd_frame *dcmd;
3337265555Sambrisko    struct MR_LD_LIST *ld_list_mem;
3338265555Sambrisko    bus_addr_t ld_list_phys_addr = 0;
3339265555Sambrisko    struct mrsas_tmp_dcmd *tcmd;
3340265555Sambrisko
3341265555Sambrisko    cmd = mrsas_get_mfi_cmd(sc);
3342265555Sambrisko    if (!cmd) {
3343265555Sambrisko        device_printf(sc->mrsas_dev, "Cannot alloc for get LD list cmd\n");
3344265555Sambrisko        return 1;
3345265555Sambrisko    }
3346265555Sambrisko
3347265555Sambrisko    dcmd = &cmd->frame->dcmd;
3348265555Sambrisko
3349265555Sambrisko    tcmd = malloc(sizeof(struct mrsas_tmp_dcmd), M_MRSAS, M_NOWAIT);
3350265555Sambrisko    ld_list_size = sizeof(struct MR_LD_LIST);
3351265555Sambrisko    if (mrsas_alloc_tmp_dcmd(sc, tcmd, ld_list_size) != SUCCESS) {
3352265555Sambrisko        device_printf(sc->mrsas_dev, "Cannot alloc dmamap for get LD list cmd\n");
3353265555Sambrisko        mrsas_release_mfi_cmd(cmd);
3354265555Sambrisko        return(ENOMEM);
3355265555Sambrisko    }
3356265555Sambrisko    else {
3357265555Sambrisko        ld_list_mem = tcmd->tmp_dcmd_mem;
3358265555Sambrisko        ld_list_phys_addr = tcmd->tmp_dcmd_phys_addr;
3359265555Sambrisko    }
3360265555Sambrisko    memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
3361265555Sambrisko
3362265555Sambrisko    dcmd->cmd = MFI_CMD_DCMD;
3363265555Sambrisko    dcmd->cmd_status = 0xFF;
3364265555Sambrisko    dcmd->sge_count = 1;
3365265555Sambrisko    dcmd->flags = MFI_FRAME_DIR_READ;
3366265555Sambrisko    dcmd->timeout = 0;
3367265555Sambrisko    dcmd->data_xfer_len = sizeof(struct MR_LD_LIST);
3368265555Sambrisko    dcmd->opcode = MR_DCMD_LD_GET_LIST;
3369265555Sambrisko    dcmd->sgl.sge32[0].phys_addr = ld_list_phys_addr;
3370265555Sambrisko    dcmd->sgl.sge32[0].length = sizeof(struct MR_LD_LIST);
3371265555Sambrisko    dcmd->pad_0  = 0;
3372265555Sambrisko
3373265555Sambrisko    if (!mrsas_issue_polled(sc, cmd))
3374265555Sambrisko        retcode = 0;
3375265555Sambrisko    else
3376265555Sambrisko        retcode = 1;
3377265555Sambrisko
3378265555Sambrisko     /* Get the instance LD list */
3379265555Sambrisko     if ((retcode == 0) && (ld_list_mem->ldCount <= (MAX_LOGICAL_DRIVES))){
3380265555Sambrisko        sc->CurLdCount = ld_list_mem->ldCount;
3381265555Sambrisko        memset(sc->ld_ids, 0xff, MRSAS_MAX_LD);
3382265555Sambrisko        for (ld_index = 0; ld_index < ld_list_mem->ldCount; ld_index++) {
3383265555Sambrisko            if (ld_list_mem->ldList[ld_index].state != 0) {
3384265555Sambrisko                ids = ld_list_mem->ldList[ld_index].ref.ld_context.targetId;
3385265555Sambrisko                sc->ld_ids[ids] = ld_list_mem->ldList[ld_index].ref.ld_context.targetId;
3386265555Sambrisko            }
3387265555Sambrisko        }
3388265555Sambrisko    }
3389265555Sambrisko
3390265555Sambrisko    mrsas_free_tmp_dcmd(tcmd);
3391265555Sambrisko    mrsas_release_mfi_cmd(cmd);
3392265555Sambrisko    free(tcmd, M_MRSAS);
3393265555Sambrisko    return(retcode);
3394265555Sambrisko}
3395265555Sambrisko
3396265555Sambrisko/**
3397265555Sambrisko * mrsas_alloc_tmp_dcmd:       Allocates memory for temporary command
3398265555Sambrisko * input:                      Adapter soft state
3399265555Sambrisko *                             Temp command
3400265555Sambrisko *                             Size of alloction
3401265555Sambrisko *
3402265555Sambrisko * Allocates DMAable memory for a temporary internal command. The allocated
3403265555Sambrisko * memory is initialized to all zeros upon successful loading of the dma
3404265555Sambrisko * mapped memory.
3405265555Sambrisko */
3406265555Sambriskoint mrsas_alloc_tmp_dcmd(struct mrsas_softc *sc, struct mrsas_tmp_dcmd *tcmd,
3407265555Sambrisko          int size)
3408265555Sambrisko{
3409265555Sambrisko    if (bus_dma_tag_create( sc->mrsas_parent_tag,   // parent
3410265555Sambrisko                            1, 0,                   // algnmnt, boundary
3411265555Sambrisko                            BUS_SPACE_MAXADDR_32BIT,// lowaddr
3412265555Sambrisko                            BUS_SPACE_MAXADDR,      // highaddr
3413265555Sambrisko                            NULL, NULL,             // filter, filterarg
3414265555Sambrisko                            size,                   // maxsize
3415265555Sambrisko                            1,                      // msegments
3416265555Sambrisko                            size,                   // maxsegsize
3417265555Sambrisko                            BUS_DMA_ALLOCNOW,       // flags
3418265555Sambrisko                            NULL, NULL,             // lockfunc, lockarg
3419265555Sambrisko                            &tcmd->tmp_dcmd_tag)) {
3420265555Sambrisko        device_printf(sc->mrsas_dev, "Cannot allocate tmp dcmd tag\n");
3421265555Sambrisko        return (ENOMEM);
3422265555Sambrisko    }
3423265555Sambrisko    if (bus_dmamem_alloc(tcmd->tmp_dcmd_tag, (void **)&tcmd->tmp_dcmd_mem,
3424265555Sambrisko            BUS_DMA_NOWAIT, &tcmd->tmp_dcmd_dmamap)) {
3425265555Sambrisko        device_printf(sc->mrsas_dev, "Cannot allocate tmp dcmd mem\n");
3426265555Sambrisko        return (ENOMEM);
3427265555Sambrisko    }
3428265555Sambrisko    if (bus_dmamap_load(tcmd->tmp_dcmd_tag, tcmd->tmp_dcmd_dmamap,
3429265555Sambrisko            tcmd->tmp_dcmd_mem, size, mrsas_addr_cb,
3430265555Sambrisko            &tcmd->tmp_dcmd_phys_addr, BUS_DMA_NOWAIT)) {
3431265555Sambrisko        device_printf(sc->mrsas_dev, "Cannot load tmp dcmd mem\n");
3432265555Sambrisko        return (ENOMEM);
3433265555Sambrisko    }
3434265555Sambrisko
3435265555Sambrisko    memset(tcmd->tmp_dcmd_mem, 0, size);
3436265555Sambrisko    return (0);
3437265555Sambrisko}
3438265555Sambrisko
3439265555Sambrisko/**
3440265555Sambrisko * mrsas_free_tmp_dcmd:      Free memory for temporary command
3441265555Sambrisko * input:                    temporary dcmd pointer
3442265555Sambrisko *
3443265555Sambrisko * Deallocates memory of the temporary command for use in the construction
3444265555Sambrisko * of the internal DCMD.
3445265555Sambrisko */
3446265555Sambriskovoid mrsas_free_tmp_dcmd(struct mrsas_tmp_dcmd *tmp)
3447265555Sambrisko{
3448265555Sambrisko    if (tmp->tmp_dcmd_phys_addr)
3449265555Sambrisko        bus_dmamap_unload(tmp->tmp_dcmd_tag, tmp->tmp_dcmd_dmamap);
3450265555Sambrisko    if (tmp->tmp_dcmd_mem != NULL)
3451265555Sambrisko        bus_dmamem_free(tmp->tmp_dcmd_tag, tmp->tmp_dcmd_mem, tmp->tmp_dcmd_dmamap);
3452265555Sambrisko    if (tmp->tmp_dcmd_tag != NULL)
3453265555Sambrisko        bus_dma_tag_destroy(tmp->tmp_dcmd_tag);
3454265555Sambrisko}
3455265555Sambrisko
3456265555Sambrisko/**
3457265555Sambrisko * mrsas_issue_blocked_abort_cmd:       Aborts previously issued cmd
3458265555Sambrisko * input:                               Adapter soft state
3459265555Sambrisko *                                      Previously issued cmd to be aborted
3460265555Sambrisko *
3461265555Sambrisko * This function is used to abort previously issued commands, such as AEN and
3462265555Sambrisko * RAID map sync map commands.  The abort command is sent as a DCMD internal
3463265555Sambrisko * command and subsequently the driver will wait for a return status.  The
3464265555Sambrisko * max wait time is MRSAS_INTERNAL_CMD_WAIT_TIME seconds.
3465265555Sambrisko */
3466265555Sambriskostatic int mrsas_issue_blocked_abort_cmd(struct mrsas_softc *sc,
3467265555Sambrisko                                         struct mrsas_mfi_cmd *cmd_to_abort)
3468265555Sambrisko{
3469265555Sambrisko    struct mrsas_mfi_cmd *cmd;
3470265555Sambrisko    struct mrsas_abort_frame *abort_fr;
3471265555Sambrisko    u_int8_t retcode = 0;
3472265555Sambrisko    unsigned long total_time = 0;
3473265555Sambrisko    u_int8_t max_wait = MRSAS_INTERNAL_CMD_WAIT_TIME;
3474265555Sambrisko
3475265555Sambrisko    cmd = mrsas_get_mfi_cmd(sc);
3476265555Sambrisko    if (!cmd) {
3477265555Sambrisko        device_printf(sc->mrsas_dev, "Cannot alloc for abort cmd\n");
3478265555Sambrisko        return(1);
3479265555Sambrisko    }
3480265555Sambrisko
3481265555Sambrisko    abort_fr = &cmd->frame->abort;
3482265555Sambrisko
3483265555Sambrisko    /* Prepare and issue the abort frame */
3484265555Sambrisko    abort_fr->cmd = MFI_CMD_ABORT;
3485265555Sambrisko    abort_fr->cmd_status = 0xFF;
3486265555Sambrisko    abort_fr->flags = 0;
3487265555Sambrisko    abort_fr->abort_context = cmd_to_abort->index;
3488265555Sambrisko    abort_fr->abort_mfi_phys_addr_lo = cmd_to_abort->frame_phys_addr;
3489265555Sambrisko    abort_fr->abort_mfi_phys_addr_hi = 0;
3490265555Sambrisko
3491265555Sambrisko    cmd->sync_cmd = 1;
3492265555Sambrisko    cmd->cmd_status = 0xFF;
3493265555Sambrisko
3494265555Sambrisko    if (mrsas_issue_dcmd(sc, cmd)) {
3495265555Sambrisko        device_printf(sc->mrsas_dev, "Fail to send abort command.\n");
3496265555Sambrisko        return(1);
3497265555Sambrisko    }
3498265555Sambrisko
3499265555Sambrisko    /* Wait for this cmd to complete */
3500265555Sambrisko    sc->chan = (void*)&cmd;
3501265555Sambrisko    while (1) {
3502265555Sambrisko       if (cmd->cmd_status == 0xFF){
3503265555Sambrisko           tsleep((void *)&sc->chan, 0, "mrsas_sleep", hz);
3504265555Sambrisko       }
3505265555Sambrisko       else
3506265555Sambrisko           break;
3507265555Sambrisko       total_time++;
3508265555Sambrisko       if (total_time >= max_wait) {
3509265555Sambrisko           device_printf(sc->mrsas_dev, "Abort cmd timed out after %d sec.\n", max_wait);
3510265555Sambrisko           retcode = 1;
3511265555Sambrisko           break;
3512265555Sambrisko       }
3513265555Sambrisko    }
3514265555Sambrisko
3515265555Sambrisko    cmd->sync_cmd = 0;
3516265555Sambrisko    mrsas_release_mfi_cmd(cmd);
3517265555Sambrisko    return(retcode);
3518265555Sambrisko}
3519265555Sambrisko
3520265555Sambrisko/**
3521265555Sambrisko * mrsas_complete_abort:      Completes aborting a command
3522265555Sambrisko * input:                     Adapter soft state
3523265555Sambrisko *                            Cmd that was issued to abort another cmd
3524265555Sambrisko *
3525265555Sambrisko * The mrsas_issue_blocked_abort_cmd() function waits for the command status
3526265555Sambrisko * to change after sending the command.  This function is called from
3527265555Sambrisko * mrsas_complete_mptmfi_passthru() to wake up the sleep thread associated.
3528265555Sambrisko */
3529265555Sambriskovoid mrsas_complete_abort(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd)
3530265555Sambrisko{
3531265555Sambrisko    if (cmd->sync_cmd) {
3532265555Sambrisko        cmd->sync_cmd = 0;
3533265555Sambrisko        cmd->cmd_status = 0;
3534265555Sambrisko        sc->chan = (void*)&cmd;
3535265555Sambrisko        wakeup_one((void *)&sc->chan);
3536265555Sambrisko    }
3537265555Sambrisko    return;
3538265555Sambrisko}
3539265555Sambrisko
3540265555Sambrisko/**
3541265555Sambrisko * mrsas_aen_handler:		Callback function for AEN processing from thread context.
3542265555Sambrisko * input:					Adapter soft state
3543265555Sambrisko *
3544265555Sambrisko */
3545265555Sambriskovoid mrsas_aen_handler(struct mrsas_softc *sc)
3546265555Sambrisko{
3547265555Sambrisko	union mrsas_evt_class_locale class_locale;
3548265555Sambrisko	int     doscan = 0;
3549265555Sambrisko	u_int32_t seq_num;
3550265555Sambrisko	int error;
3551265555Sambrisko
3552265555Sambrisko	if (!sc) {
3553265555Sambrisko		device_printf(sc->mrsas_dev, "invalid instance!\n");
3554265555Sambrisko		return;
3555265555Sambrisko	}
3556265555Sambrisko
3557265555Sambrisko	if (sc->evt_detail_mem) {
3558265555Sambrisko		switch (sc->evt_detail_mem->code) {
3559265555Sambrisko			case MR_EVT_PD_INSERTED:
3560265555Sambrisko				mrsas_get_pd_list(sc);
3561265555Sambrisko				mrsas_bus_scan_sim(sc, sc->sim_1);
3562265555Sambrisko				doscan = 0;
3563265555Sambrisko				break;
3564265555Sambrisko			case MR_EVT_PD_REMOVED:
3565265555Sambrisko				mrsas_get_pd_list(sc);
3566265555Sambrisko				mrsas_bus_scan_sim(sc, sc->sim_1);
3567265555Sambrisko				doscan = 0;
3568265555Sambrisko				break;
3569265555Sambrisko			case MR_EVT_LD_OFFLINE:
3570265555Sambrisko			case MR_EVT_CFG_CLEARED:
3571265555Sambrisko			case MR_EVT_LD_DELETED:
3572265555Sambrisko				mrsas_bus_scan_sim(sc, sc->sim_0);
3573265555Sambrisko				doscan = 0;
3574265555Sambrisko				break;
3575265555Sambrisko			case MR_EVT_LD_CREATED:
3576265555Sambrisko				mrsas_get_ld_list(sc);
3577265555Sambrisko				mrsas_bus_scan_sim(sc, sc->sim_0);
3578265555Sambrisko				doscan = 0;
3579265555Sambrisko				break;
3580265555Sambrisko			case MR_EVT_CTRL_HOST_BUS_SCAN_REQUESTED:
3581265555Sambrisko			case MR_EVT_FOREIGN_CFG_IMPORTED:
3582265555Sambrisko			case MR_EVT_LD_STATE_CHANGE:
3583265555Sambrisko				doscan = 1;
3584265555Sambrisko				break;
3585265555Sambrisko			default:
3586265555Sambrisko				doscan = 0;
3587265555Sambrisko				break;
3588265555Sambrisko		}
3589265555Sambrisko	} else {
3590265555Sambrisko		device_printf(sc->mrsas_dev, "invalid evt_detail\n");
3591265555Sambrisko		return;
3592265555Sambrisko	}
3593265555Sambrisko	if (doscan) {
3594265555Sambrisko		mrsas_get_pd_list(sc);
3595265555Sambrisko		mrsas_dprint(sc, MRSAS_AEN, "scanning ...sim 1\n");
3596265555Sambrisko		mrsas_bus_scan_sim(sc, sc->sim_1);
3597265555Sambrisko		mrsas_get_ld_list(sc);
3598265555Sambrisko		mrsas_dprint(sc, MRSAS_AEN, "scanning ...sim 0\n");
3599265555Sambrisko		mrsas_bus_scan_sim(sc, sc->sim_0);
3600265555Sambrisko	}
3601265555Sambrisko
3602265555Sambrisko	seq_num = sc->evt_detail_mem->seq_num + 1;
3603265555Sambrisko
3604265555Sambrisko	// Register AEN with FW for latest sequence number plus 1
3605265555Sambrisko	class_locale.members.reserved = 0;
3606265555Sambrisko	class_locale.members.locale = MR_EVT_LOCALE_ALL;
3607265555Sambrisko	class_locale.members.class = MR_EVT_CLASS_DEBUG;
3608265555Sambrisko
3609265555Sambrisko	if (sc->aen_cmd != NULL )
3610265555Sambrisko		return ;
3611265555Sambrisko
3612265555Sambrisko	mtx_lock(&sc->aen_lock);
3613265555Sambrisko	error = mrsas_register_aen(sc, seq_num,
3614265555Sambrisko					class_locale.word);
3615265555Sambrisko	mtx_unlock(&sc->aen_lock);
3616265555Sambrisko
3617265555Sambrisko	if (error)
3618265555Sambrisko		device_printf(sc->mrsas_dev, "register aen failed error %x\n", error);
3619265555Sambrisko
3620265555Sambrisko}
3621265555Sambrisko
3622265555Sambrisko
3623265555Sambrisko/**
3624265555Sambrisko * mrsas_complete_aen:        	Completes AEN command
3625265555Sambrisko * input:                     	Adapter soft state
3626265555Sambrisko *                            	Cmd that was issued to abort another cmd
3627265555Sambrisko *
3628265555Sambrisko * 								This function will be called from ISR and will continue
3629265555Sambrisko * 								event processing from thread context by enqueuing task
3630265555Sambrisko * 								in ev_tq (callback function "mrsas_aen_handler").
3631265555Sambrisko */
3632265555Sambriskovoid mrsas_complete_aen(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd)
3633265555Sambrisko{
3634265555Sambrisko	/*
3635265555Sambrisko	* Don't signal app if it is just an aborted previously registered aen
3636265555Sambrisko	*/
3637265555Sambrisko	if ((!cmd->abort_aen) && (sc->remove_in_progress == 0)) {
3638265555Sambrisko		/* TO DO (?) */
3639265555Sambrisko	}
3640265555Sambrisko	else
3641265555Sambrisko		cmd->abort_aen = 0;
3642265555Sambrisko
3643265555Sambrisko	sc->aen_cmd = NULL;
3644265555Sambrisko	mrsas_release_mfi_cmd(cmd);
3645265555Sambrisko
3646265555Sambrisko	if (!sc->remove_in_progress)
3647265555Sambrisko		taskqueue_enqueue(sc->ev_tq, &sc->ev_task);
3648265555Sambrisko
3649265555Sambrisko	return;
3650265555Sambrisko}
3651265555Sambrisko
3652265555Sambriskostatic device_method_t mrsas_methods[] = {
3653265555Sambrisko    DEVMETHOD(device_probe,     mrsas_probe),
3654265555Sambrisko    DEVMETHOD(device_attach,    mrsas_attach),
3655265555Sambrisko    DEVMETHOD(device_detach,    mrsas_detach),
3656265555Sambrisko    DEVMETHOD(device_suspend,   mrsas_suspend),
3657265555Sambrisko    DEVMETHOD(device_resume,    mrsas_resume),
3658265555Sambrisko    DEVMETHOD(bus_print_child,  bus_generic_print_child),
3659265555Sambrisko    DEVMETHOD(bus_driver_added, bus_generic_driver_added),
3660265555Sambrisko    { 0, 0 }
3661265555Sambrisko};
3662265555Sambrisko
3663265555Sambriskostatic driver_t mrsas_driver = {
3664265555Sambrisko    "mrsas",
3665265555Sambrisko    mrsas_methods,
3666265555Sambrisko    sizeof(struct mrsas_softc)
3667265555Sambrisko};
3668265555Sambrisko
3669265555Sambriskostatic devclass_t       mrsas_devclass;
3670265555SambriskoDRIVER_MODULE(mrsas, pci, mrsas_driver, mrsas_devclass, 0, 0);
3671265555SambriskoMODULE_DEPEND(mrsas, cam, 1,1,1);
3672265555Sambrisko
3673