17282444bSPedro F. Giffuni /*-
27282444bSPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause
37282444bSPedro F. Giffuni *
4db1fda10SXin LI * Copyright (c) 2010, LSI Corp.
5db1fda10SXin LI * All rights reserved.
6db1fda10SXin LI * Author : Manjunath Ranganathaiah
7db1fda10SXin LI * Support: freebsdraid@lsi.com
8db1fda10SXin LI *
9db1fda10SXin LI * Redistribution and use in source and binary forms, with or without
10db1fda10SXin LI * modification, are permitted provided that the following conditions
11db1fda10SXin LI * are met:
12db1fda10SXin LI *
13db1fda10SXin LI * 1. Redistributions of source code must retain the above copyright
14db1fda10SXin LI * notice, this list of conditions and the following disclaimer.
15db1fda10SXin LI * 2. Redistributions in binary form must reproduce the above copyright
16db1fda10SXin LI * notice, this list of conditions and the following disclaimer in
17db1fda10SXin LI * the documentation and/or other materials provided with the
18db1fda10SXin LI * distribution.
19db1fda10SXin LI * 3. Neither the name of the <ORGANIZATION> nor the names of its
20db1fda10SXin LI * contributors may be used to endorse or promote products derived
21db1fda10SXin LI * from this software without specific prior written permission.
22db1fda10SXin LI *
23db1fda10SXin LI * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24db1fda10SXin LI * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25db1fda10SXin LI * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26db1fda10SXin LI * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27db1fda10SXin LI * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28db1fda10SXin LI * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29db1fda10SXin LI * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30db1fda10SXin LI * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31db1fda10SXin LI * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32db1fda10SXin LI * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33db1fda10SXin LI * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34db1fda10SXin LI * POSSIBILITY OF SUCH DAMAGE.
35db1fda10SXin LI */
36db1fda10SXin LI
374b7ec270SMarius Strobl #include <sys/cdefs.h>
38db1fda10SXin LI #include <dev/tws/tws.h>
39db1fda10SXin LI #include <dev/tws/tws_services.h>
40db1fda10SXin LI #include <dev/tws/tws_hdm.h>
41db1fda10SXin LI
42db1fda10SXin LI #include <cam/cam.h>
43db1fda10SXin LI #include <cam/cam_ccb.h>
44cca5be24SEdward Tomasz Napierala #include <cam/cam_xpt.h>
45db1fda10SXin LI
46db1fda10SXin LI MALLOC_DEFINE(M_TWS, "twsbuf", "buffers used by tws driver");
47db1fda10SXin LI int tws_queue_depth = TWS_MAX_REQS;
48db1fda10SXin LI int tws_enable_msi = 0;
49db1fda10SXin LI int tws_enable_msix = 0;
50db1fda10SXin LI
51db1fda10SXin LI /* externs */
52db1fda10SXin LI extern int tws_cam_attach(struct tws_softc *sc);
53db1fda10SXin LI extern void tws_cam_detach(struct tws_softc *sc);
54db1fda10SXin LI extern int tws_init_ctlr(struct tws_softc *sc);
55db1fda10SXin LI extern boolean tws_ctlr_ready(struct tws_softc *sc);
56db1fda10SXin LI extern void tws_turn_off_interrupts(struct tws_softc *sc);
57db1fda10SXin LI extern void tws_q_insert_tail(struct tws_softc *sc, struct tws_request *req,
58db1fda10SXin LI u_int8_t q_type );
59db1fda10SXin LI extern struct tws_request *tws_q_remove_request(struct tws_softc *sc,
60db1fda10SXin LI struct tws_request *req, u_int8_t q_type );
61db1fda10SXin LI extern struct tws_request *tws_q_remove_head(struct tws_softc *sc,
62db1fda10SXin LI u_int8_t q_type );
63db1fda10SXin LI extern boolean tws_get_response(struct tws_softc *sc, u_int16_t *req_id);
64db1fda10SXin LI extern boolean tws_ctlr_reset(struct tws_softc *sc);
65db1fda10SXin LI extern void tws_intr(void *arg);
66db1fda10SXin LI extern int tws_use_32bit_sgls;
67db1fda10SXin LI
68db1fda10SXin LI struct tws_request *tws_get_request(struct tws_softc *sc, u_int16_t type);
69db1fda10SXin LI int tws_init_connect(struct tws_softc *sc, u_int16_t mc);
70db1fda10SXin LI void tws_send_event(struct tws_softc *sc, u_int8_t event);
71db1fda10SXin LI uint8_t tws_get_state(struct tws_softc *sc);
72db1fda10SXin LI void tws_release_request(struct tws_request *req);
73db1fda10SXin LI
74db1fda10SXin LI /* Function prototypes */
75db1fda10SXin LI static d_open_t tws_open;
76db1fda10SXin LI static d_close_t tws_close;
77db1fda10SXin LI static d_read_t tws_read;
78db1fda10SXin LI static d_write_t tws_write;
79db1fda10SXin LI extern d_ioctl_t tws_ioctl;
80db1fda10SXin LI
81db1fda10SXin LI static int tws_init(struct tws_softc *sc);
82db1fda10SXin LI static void tws_dmamap_cmds_load_cbfn(void *arg, bus_dma_segment_t *segs,
83db1fda10SXin LI int nseg, int error);
84db1fda10SXin LI
85db1fda10SXin LI static int tws_init_reqs(struct tws_softc *sc, u_int32_t dma_mem_size);
86db1fda10SXin LI static int tws_init_aen_q(struct tws_softc *sc);
87db1fda10SXin LI static int tws_init_trace_q(struct tws_softc *sc);
88db1fda10SXin LI static int tws_setup_irq(struct tws_softc *sc);
89db1fda10SXin LI int tws_setup_intr(struct tws_softc *sc, int irqs);
90db1fda10SXin LI int tws_teardown_intr(struct tws_softc *sc);
91db1fda10SXin LI
92db1fda10SXin LI /* Character device entry points */
93db1fda10SXin LI
94db1fda10SXin LI static struct cdevsw tws_cdevsw = {
95db1fda10SXin LI .d_version = D_VERSION,
96db1fda10SXin LI .d_open = tws_open,
97db1fda10SXin LI .d_close = tws_close,
98db1fda10SXin LI .d_read = tws_read,
99db1fda10SXin LI .d_write = tws_write,
100db1fda10SXin LI .d_ioctl = tws_ioctl,
101db1fda10SXin LI .d_name = "tws",
102db1fda10SXin LI };
103db1fda10SXin LI
104db1fda10SXin LI /*
105db1fda10SXin LI * In the cdevsw routines, we find our softc by using the si_drv1 member
106db1fda10SXin LI * of struct cdev. We set this variable to point to our softc in our
107db1fda10SXin LI * attach routine when we create the /dev entry.
108db1fda10SXin LI */
109db1fda10SXin LI
110db1fda10SXin LI int
tws_open(struct cdev * dev,int oflags,int devtype,struct thread * td)111f045564dSJohn Baldwin tws_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
112db1fda10SXin LI {
113db1fda10SXin LI struct tws_softc *sc = dev->si_drv1;
114db1fda10SXin LI
115db1fda10SXin LI if ( sc )
116db1fda10SXin LI TWS_TRACE_DEBUG(sc, "entry", dev, oflags);
117db1fda10SXin LI return (0);
118db1fda10SXin LI }
119db1fda10SXin LI
120db1fda10SXin LI int
tws_close(struct cdev * dev,int fflag,int devtype,struct thread * td)121f045564dSJohn Baldwin tws_close(struct cdev *dev, int fflag, int devtype, struct thread *td)
122db1fda10SXin LI {
123db1fda10SXin LI struct tws_softc *sc = dev->si_drv1;
124db1fda10SXin LI
125db1fda10SXin LI if ( sc )
126db1fda10SXin LI TWS_TRACE_DEBUG(sc, "entry", dev, fflag);
127db1fda10SXin LI return (0);
128db1fda10SXin LI }
129db1fda10SXin LI
130db1fda10SXin LI int
tws_read(struct cdev * dev,struct uio * uio,int ioflag)131db1fda10SXin LI tws_read(struct cdev *dev, struct uio *uio, int ioflag)
132db1fda10SXin LI {
133db1fda10SXin LI struct tws_softc *sc = dev->si_drv1;
134db1fda10SXin LI
135db1fda10SXin LI if ( sc )
136db1fda10SXin LI TWS_TRACE_DEBUG(sc, "entry", dev, ioflag);
137db1fda10SXin LI return (0);
138db1fda10SXin LI }
139db1fda10SXin LI
140db1fda10SXin LI int
tws_write(struct cdev * dev,struct uio * uio,int ioflag)141db1fda10SXin LI tws_write(struct cdev *dev, struct uio *uio, int ioflag)
142db1fda10SXin LI {
143db1fda10SXin LI struct tws_softc *sc = dev->si_drv1;
144db1fda10SXin LI
145db1fda10SXin LI if ( sc )
146db1fda10SXin LI TWS_TRACE_DEBUG(sc, "entry", dev, ioflag);
147db1fda10SXin LI return (0);
148db1fda10SXin LI }
149db1fda10SXin LI
150db1fda10SXin LI /* PCI Support Functions */
151db1fda10SXin LI
152db1fda10SXin LI /*
153db1fda10SXin LI * Compare the device ID of this device against the IDs that this driver
154db1fda10SXin LI * supports. If there is a match, set the description and return success.
155db1fda10SXin LI */
156db1fda10SXin LI static int
tws_probe(device_t dev)157db1fda10SXin LI tws_probe(device_t dev)
158db1fda10SXin LI {
159db1fda10SXin LI static u_int8_t first_ctlr = 1;
160db1fda10SXin LI
161db1fda10SXin LI if ((pci_get_vendor(dev) == TWS_VENDOR_ID) &&
162db1fda10SXin LI (pci_get_device(dev) == TWS_DEVICE_ID)) {
163db1fda10SXin LI device_set_desc(dev, "LSI 3ware SAS/SATA Storage Controller");
164db1fda10SXin LI if (first_ctlr) {
165db1fda10SXin LI printf("LSI 3ware device driver for SAS/SATA storage "
166db1fda10SXin LI "controllers, version: %s\n", TWS_DRIVER_VERSION_STRING);
167db1fda10SXin LI first_ctlr = 0;
168db1fda10SXin LI }
169db1fda10SXin LI
17047833734SXin LI return(BUS_PROBE_DEFAULT);
171db1fda10SXin LI }
172db1fda10SXin LI return (ENXIO);
173db1fda10SXin LI }
174db1fda10SXin LI
175db1fda10SXin LI /* Attach function is only called if the probe is successful. */
176db1fda10SXin LI
177db1fda10SXin LI static int
tws_attach(device_t dev)178db1fda10SXin LI tws_attach(device_t dev)
179db1fda10SXin LI {
180db1fda10SXin LI struct tws_softc *sc = device_get_softc(dev);
181c68534f1SScott Long u_int32_t bar;
182db1fda10SXin LI int error=0,i;
183db1fda10SXin LI
184db1fda10SXin LI /* no tracing yet */
185db1fda10SXin LI /* Look up our softc and initialize its fields. */
186db1fda10SXin LI sc->tws_dev = dev;
187db1fda10SXin LI sc->device_id = pci_get_device(dev);
188db1fda10SXin LI sc->subvendor_id = pci_get_subvendor(dev);
189db1fda10SXin LI sc->subdevice_id = pci_get_subdevice(dev);
190db1fda10SXin LI
191db1fda10SXin LI /* Intialize mutexes */
192db1fda10SXin LI mtx_init( &sc->q_lock, "tws_q_lock", NULL, MTX_DEF);
193db1fda10SXin LI mtx_init( &sc->sim_lock, "tws_sim_lock", NULL, MTX_DEF);
194db1fda10SXin LI mtx_init( &sc->gen_lock, "tws_gen_lock", NULL, MTX_DEF);
19595161fc3SJim Harris mtx_init( &sc->io_lock, "tws_io_lock", NULL, MTX_DEF | MTX_RECURSE);
196fd90e2edSJung-uk Kim callout_init(&sc->stats_timer, 1);
197db1fda10SXin LI
198db1fda10SXin LI if ( tws_init_trace_q(sc) == FAILURE )
199db1fda10SXin LI printf("trace init failure\n");
200db1fda10SXin LI /* send init event */
201db1fda10SXin LI mtx_lock(&sc->gen_lock);
202db1fda10SXin LI tws_send_event(sc, TWS_INIT_START);
203db1fda10SXin LI mtx_unlock(&sc->gen_lock);
204db1fda10SXin LI
205db1fda10SXin LI #if _BYTE_ORDER == _BIG_ENDIAN
206db1fda10SXin LI TWS_TRACE(sc, "BIG endian", 0, 0);
207db1fda10SXin LI #endif
208db1fda10SXin LI /* sysctl context setup */
209db1fda10SXin LI sysctl_ctx_init(&sc->tws_clist);
210db1fda10SXin LI sc->tws_oidp = SYSCTL_ADD_NODE(&sc->tws_clist,
211db1fda10SXin LI SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO,
2127029da5cSPawel Biernacki device_get_nameunit(dev), CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
213db1fda10SXin LI if ( sc->tws_oidp == NULL ) {
214db1fda10SXin LI tws_log(sc, SYSCTL_TREE_NODE_ADD);
215db1fda10SXin LI goto attach_fail_1;
216db1fda10SXin LI }
217db1fda10SXin LI SYSCTL_ADD_STRING(&sc->tws_clist, SYSCTL_CHILDREN(sc->tws_oidp),
218db1fda10SXin LI OID_AUTO, "driver_version", CTLFLAG_RD,
219db1fda10SXin LI TWS_DRIVER_VERSION_STRING, 0, "TWS driver version");
220db1fda10SXin LI
221c68534f1SScott Long pci_enable_busmaster(dev);
222db1fda10SXin LI
223db1fda10SXin LI bar = pci_read_config(dev, TWS_PCI_BAR0, 4);
224db1fda10SXin LI TWS_TRACE_DEBUG(sc, "bar0 ", bar, 0);
225db1fda10SXin LI bar = pci_read_config(dev, TWS_PCI_BAR1, 4);
226db1fda10SXin LI bar = bar & ~TWS_BIT2;
227db1fda10SXin LI TWS_TRACE_DEBUG(sc, "bar1 ", bar, 0);
228db1fda10SXin LI
229db1fda10SXin LI /* MFA base address is BAR2 register used for
230db1fda10SXin LI * push mode. Firmware will evatualy move to
231db1fda10SXin LI * pull mode during witch this needs to change
232db1fda10SXin LI */
233db1fda10SXin LI #ifndef TWS_PULL_MODE_ENABLE
234db1fda10SXin LI sc->mfa_base = (u_int64_t)pci_read_config(dev, TWS_PCI_BAR2, 4);
235db1fda10SXin LI sc->mfa_base = sc->mfa_base & ~TWS_BIT2;
236db1fda10SXin LI TWS_TRACE_DEBUG(sc, "bar2 ", sc->mfa_base, 0);
237db1fda10SXin LI #endif
238db1fda10SXin LI
239db1fda10SXin LI /* allocate MMIO register space */
240db1fda10SXin LI sc->reg_res_id = TWS_PCI_BAR1; /* BAR1 offset */
24143cd6160SJustin Hibbits if ((sc->reg_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
24243cd6160SJustin Hibbits &(sc->reg_res_id), RF_ACTIVE))
243db1fda10SXin LI == NULL) {
244db1fda10SXin LI tws_log(sc, ALLOC_MEMORY_RES);
245db1fda10SXin LI goto attach_fail_1;
246db1fda10SXin LI }
247db1fda10SXin LI sc->bus_tag = rman_get_bustag(sc->reg_res);
248db1fda10SXin LI sc->bus_handle = rman_get_bushandle(sc->reg_res);
249db1fda10SXin LI
250db1fda10SXin LI #ifndef TWS_PULL_MODE_ENABLE
251db1fda10SXin LI /* Allocate bus space for inbound mfa */
252db1fda10SXin LI sc->mfa_res_id = TWS_PCI_BAR2; /* BAR2 offset */
253eff83876SJustin Hibbits if ((sc->mfa_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
254eff83876SJustin Hibbits &(sc->mfa_res_id), RF_ACTIVE))
255db1fda10SXin LI == NULL) {
256db1fda10SXin LI tws_log(sc, ALLOC_MEMORY_RES);
257db1fda10SXin LI goto attach_fail_2;
258db1fda10SXin LI }
259db1fda10SXin LI sc->bus_mfa_tag = rman_get_bustag(sc->mfa_res);
260db1fda10SXin LI sc->bus_mfa_handle = rman_get_bushandle(sc->mfa_res);
261db1fda10SXin LI #endif
262db1fda10SXin LI
263db1fda10SXin LI /* Allocate and register our interrupt. */
264db1fda10SXin LI sc->intr_type = TWS_INTx; /* default */
265db1fda10SXin LI
266db1fda10SXin LI if ( tws_enable_msi )
267db1fda10SXin LI sc->intr_type = TWS_MSI;
268db1fda10SXin LI if ( tws_setup_irq(sc) == FAILURE ) {
269db1fda10SXin LI tws_log(sc, ALLOC_MEMORY_RES);
270db1fda10SXin LI goto attach_fail_3;
271db1fda10SXin LI }
272db1fda10SXin LI
273db1fda10SXin LI /*
274db1fda10SXin LI * Create a /dev entry for this device. The kernel will assign us
275db1fda10SXin LI * a major number automatically. We use the unit number of this
276db1fda10SXin LI * device as the minor number and name the character device
277db1fda10SXin LI * "tws<unit>".
278db1fda10SXin LI */
279db1fda10SXin LI sc->tws_cdev = make_dev(&tws_cdevsw, device_get_unit(dev),
280db1fda10SXin LI UID_ROOT, GID_OPERATOR, S_IRUSR | S_IWUSR, "tws%u",
281db1fda10SXin LI device_get_unit(dev));
282db1fda10SXin LI sc->tws_cdev->si_drv1 = sc;
283db1fda10SXin LI
284db1fda10SXin LI if ( tws_init(sc) == FAILURE ) {
285db1fda10SXin LI tws_log(sc, TWS_INIT_FAILURE);
286db1fda10SXin LI goto attach_fail_4;
287db1fda10SXin LI }
288db1fda10SXin LI if ( tws_init_ctlr(sc) == FAILURE ) {
289db1fda10SXin LI tws_log(sc, TWS_CTLR_INIT_FAILURE);
290db1fda10SXin LI goto attach_fail_4;
291db1fda10SXin LI }
292db1fda10SXin LI if ((error = tws_cam_attach(sc))) {
293db1fda10SXin LI tws_log(sc, TWS_CAM_ATTACH);
294db1fda10SXin LI goto attach_fail_4;
295db1fda10SXin LI }
296db1fda10SXin LI /* send init complete event */
297db1fda10SXin LI mtx_lock(&sc->gen_lock);
298db1fda10SXin LI tws_send_event(sc, TWS_INIT_COMPLETE);
299db1fda10SXin LI mtx_unlock(&sc->gen_lock);
300db1fda10SXin LI
301db1fda10SXin LI TWS_TRACE_DEBUG(sc, "attached successfully", 0, sc->device_id);
302db1fda10SXin LI return(0);
303db1fda10SXin LI
304db1fda10SXin LI attach_fail_4:
305db1fda10SXin LI tws_teardown_intr(sc);
306db1fda10SXin LI destroy_dev(sc->tws_cdev);
30730a13db0SJohn Baldwin if (sc->dma_mem_phys)
30830a13db0SJohn Baldwin bus_dmamap_unload(sc->cmd_tag, sc->cmd_map);
30930a13db0SJohn Baldwin if (sc->dma_mem)
31030a13db0SJohn Baldwin bus_dmamem_free(sc->cmd_tag, sc->dma_mem, sc->cmd_map);
31130a13db0SJohn Baldwin if (sc->cmd_tag)
31230a13db0SJohn Baldwin bus_dma_tag_destroy(sc->cmd_tag);
313db1fda10SXin LI attach_fail_3:
314db1fda10SXin LI for(i=0;i<sc->irqs;i++) {
315db1fda10SXin LI if ( sc->irq_res[i] ){
316db1fda10SXin LI if (bus_release_resource(sc->tws_dev,
317db1fda10SXin LI SYS_RES_IRQ, sc->irq_res_id[i], sc->irq_res[i]))
318db1fda10SXin LI TWS_TRACE(sc, "bus irq res", 0, 0);
319db1fda10SXin LI }
320db1fda10SXin LI }
321db1fda10SXin LI #ifndef TWS_PULL_MODE_ENABLE
322db1fda10SXin LI attach_fail_2:
323db1fda10SXin LI #endif
324db1fda10SXin LI if ( sc->mfa_res ){
325db1fda10SXin LI if (bus_release_resource(sc->tws_dev,
326db1fda10SXin LI SYS_RES_MEMORY, sc->mfa_res_id, sc->mfa_res))
327db1fda10SXin LI TWS_TRACE(sc, "bus release ", 0, sc->mfa_res_id);
328db1fda10SXin LI }
329db1fda10SXin LI if ( sc->reg_res ){
330db1fda10SXin LI if (bus_release_resource(sc->tws_dev,
331db1fda10SXin LI SYS_RES_MEMORY, sc->reg_res_id, sc->reg_res))
332db1fda10SXin LI TWS_TRACE(sc, "bus release2 ", 0, sc->reg_res_id);
333db1fda10SXin LI }
334db1fda10SXin LI attach_fail_1:
335db1fda10SXin LI mtx_destroy(&sc->q_lock);
336db1fda10SXin LI mtx_destroy(&sc->sim_lock);
337db1fda10SXin LI mtx_destroy(&sc->gen_lock);
338db1fda10SXin LI mtx_destroy(&sc->io_lock);
339db1fda10SXin LI sysctl_ctx_free(&sc->tws_clist);
340db1fda10SXin LI return (ENXIO);
341db1fda10SXin LI }
342db1fda10SXin LI
343db1fda10SXin LI /* Detach device. */
344db1fda10SXin LI
345db1fda10SXin LI static int
tws_detach(device_t dev)346db1fda10SXin LI tws_detach(device_t dev)
347db1fda10SXin LI {
348db1fda10SXin LI struct tws_softc *sc = device_get_softc(dev);
349db1fda10SXin LI int i;
350174d86a0SRobert Wing u_int32_t reg __tws_debug;
351db1fda10SXin LI
352db1fda10SXin LI TWS_TRACE_DEBUG(sc, "entry", 0, 0);
353db1fda10SXin LI
354db1fda10SXin LI mtx_lock(&sc->gen_lock);
355db1fda10SXin LI tws_send_event(sc, TWS_UNINIT_START);
356db1fda10SXin LI mtx_unlock(&sc->gen_lock);
357db1fda10SXin LI
358db1fda10SXin LI /* needs to disable interrupt before detaching from cam */
359db1fda10SXin LI tws_turn_off_interrupts(sc);
360db1fda10SXin LI /* clear door bell */
361db1fda10SXin LI tws_write_reg(sc, TWS_I2O0_HOBDBC, ~0, 4);
362db1fda10SXin LI reg = tws_read_reg(sc, TWS_I2O0_HIMASK, 4);
363db1fda10SXin LI TWS_TRACE_DEBUG(sc, "turn-off-intr", reg, 0);
364db1fda10SXin LI sc->obfl_q_overrun = false;
365db1fda10SXin LI tws_init_connect(sc, 1);
366db1fda10SXin LI
367db1fda10SXin LI /* Teardown the state in our softc created in our attach routine. */
368db1fda10SXin LI /* Disconnect the interrupt handler. */
369db1fda10SXin LI tws_teardown_intr(sc);
370db1fda10SXin LI
371db1fda10SXin LI /* Release irq resource */
372db1fda10SXin LI for(i=0;i<sc->irqs;i++) {
373db1fda10SXin LI if ( sc->irq_res[i] ){
374db1fda10SXin LI if (bus_release_resource(sc->tws_dev,
375db1fda10SXin LI SYS_RES_IRQ, sc->irq_res_id[i], sc->irq_res[i]))
376db1fda10SXin LI TWS_TRACE(sc, "bus release irq resource",
377db1fda10SXin LI i, sc->irq_res_id[i]);
378db1fda10SXin LI }
379db1fda10SXin LI }
380db1fda10SXin LI if ( sc->intr_type == TWS_MSI ) {
381db1fda10SXin LI pci_release_msi(sc->tws_dev);
382db1fda10SXin LI }
383db1fda10SXin LI
384db1fda10SXin LI tws_cam_detach(sc);
385db1fda10SXin LI
38630a13db0SJohn Baldwin if (sc->dma_mem_phys)
38730a13db0SJohn Baldwin bus_dmamap_unload(sc->cmd_tag, sc->cmd_map);
38830a13db0SJohn Baldwin if (sc->dma_mem)
38930a13db0SJohn Baldwin bus_dmamem_free(sc->cmd_tag, sc->dma_mem, sc->cmd_map);
39030a13db0SJohn Baldwin if (sc->cmd_tag)
39130a13db0SJohn Baldwin bus_dma_tag_destroy(sc->cmd_tag);
39230a13db0SJohn Baldwin
393db1fda10SXin LI /* Release memory resource */
394db1fda10SXin LI if ( sc->mfa_res ){
395db1fda10SXin LI if (bus_release_resource(sc->tws_dev,
396db1fda10SXin LI SYS_RES_MEMORY, sc->mfa_res_id, sc->mfa_res))
397db1fda10SXin LI TWS_TRACE(sc, "bus release mem resource", 0, sc->mfa_res_id);
398db1fda10SXin LI }
399db1fda10SXin LI if ( sc->reg_res ){
400db1fda10SXin LI if (bus_release_resource(sc->tws_dev,
401db1fda10SXin LI SYS_RES_MEMORY, sc->reg_res_id, sc->reg_res))
402db1fda10SXin LI TWS_TRACE(sc, "bus release mem resource", 0, sc->reg_res_id);
403db1fda10SXin LI }
404db1fda10SXin LI
405166a4e47SJohn Baldwin for ( i=0; i< tws_queue_depth; i++) {
406166a4e47SJohn Baldwin if (sc->reqs[i].dma_map)
407166a4e47SJohn Baldwin bus_dmamap_destroy(sc->data_tag, sc->reqs[i].dma_map);
408166a4e47SJohn Baldwin callout_drain(&sc->reqs[i].timeout);
409166a4e47SJohn Baldwin }
410166a4e47SJohn Baldwin
411166a4e47SJohn Baldwin callout_drain(&sc->stats_timer);
412db1fda10SXin LI free(sc->reqs, M_TWS);
413db1fda10SXin LI free(sc->sense_bufs, M_TWS);
414cca5be24SEdward Tomasz Napierala xpt_free_ccb(sc->scan_ccb);
415c5f33959SXin LI if (sc->ioctl_data_mem)
416c5f33959SXin LI bus_dmamem_free(sc->data_tag, sc->ioctl_data_mem, sc->ioctl_data_map);
417166a4e47SJohn Baldwin if (sc->data_tag)
418166a4e47SJohn Baldwin bus_dma_tag_destroy(sc->data_tag);
419db1fda10SXin LI free(sc->aen_q.q, M_TWS);
420db1fda10SXin LI free(sc->trace_q.q, M_TWS);
421db1fda10SXin LI mtx_destroy(&sc->q_lock);
422db1fda10SXin LI mtx_destroy(&sc->sim_lock);
423db1fda10SXin LI mtx_destroy(&sc->gen_lock);
424db1fda10SXin LI mtx_destroy(&sc->io_lock);
425db1fda10SXin LI destroy_dev(sc->tws_cdev);
426db1fda10SXin LI sysctl_ctx_free(&sc->tws_clist);
427db1fda10SXin LI return (0);
428db1fda10SXin LI }
429db1fda10SXin LI
430db1fda10SXin LI int
tws_setup_intr(struct tws_softc * sc,int irqs)431db1fda10SXin LI tws_setup_intr(struct tws_softc *sc, int irqs)
432db1fda10SXin LI {
433db1fda10SXin LI int i, error;
434db1fda10SXin LI
435db1fda10SXin LI for(i=0;i<irqs;i++) {
436db1fda10SXin LI if (!(sc->intr_handle[i])) {
437db1fda10SXin LI if ((error = bus_setup_intr(sc->tws_dev, sc->irq_res[i],
438db1fda10SXin LI INTR_TYPE_CAM | INTR_MPSAFE,
439db1fda10SXin LI NULL,
440db1fda10SXin LI tws_intr, sc, &sc->intr_handle[i]))) {
441db1fda10SXin LI tws_log(sc, SETUP_INTR_RES);
442db1fda10SXin LI return(FAILURE);
443db1fda10SXin LI }
444db1fda10SXin LI }
445db1fda10SXin LI }
446db1fda10SXin LI return(SUCCESS);
447db1fda10SXin LI
448db1fda10SXin LI }
449db1fda10SXin LI
450db1fda10SXin LI int
tws_teardown_intr(struct tws_softc * sc)451db1fda10SXin LI tws_teardown_intr(struct tws_softc *sc)
452db1fda10SXin LI {
453a21f086aSScott Long int i;
454db1fda10SXin LI
455db1fda10SXin LI for(i=0;i<sc->irqs;i++) {
456db1fda10SXin LI if (sc->intr_handle[i]) {
457a21f086aSScott Long bus_teardown_intr(sc->tws_dev,
458db1fda10SXin LI sc->irq_res[i], sc->intr_handle[i]);
459db1fda10SXin LI sc->intr_handle[i] = NULL;
460db1fda10SXin LI }
461db1fda10SXin LI }
462db1fda10SXin LI return(SUCCESS);
463db1fda10SXin LI }
464db1fda10SXin LI
465db1fda10SXin LI static int
tws_setup_irq(struct tws_softc * sc)466db1fda10SXin LI tws_setup_irq(struct tws_softc *sc)
467db1fda10SXin LI {
468db1fda10SXin LI int messages;
469db1fda10SXin LI
470db1fda10SXin LI switch(sc->intr_type) {
471db1fda10SXin LI case TWS_INTx :
472db1fda10SXin LI sc->irqs = 1;
473db1fda10SXin LI sc->irq_res_id[0] = 0;
474db1fda10SXin LI sc->irq_res[0] = bus_alloc_resource_any(sc->tws_dev, SYS_RES_IRQ,
475db1fda10SXin LI &sc->irq_res_id[0], RF_SHAREABLE | RF_ACTIVE);
476db1fda10SXin LI if ( ! sc->irq_res[0] )
477db1fda10SXin LI return(FAILURE);
478db1fda10SXin LI if ( tws_setup_intr(sc, sc->irqs) == FAILURE )
479db1fda10SXin LI return(FAILURE);
480db1fda10SXin LI device_printf(sc->tws_dev, "Using legacy INTx\n");
481db1fda10SXin LI break;
482db1fda10SXin LI case TWS_MSI :
483db1fda10SXin LI sc->irqs = 1;
484db1fda10SXin LI sc->irq_res_id[0] = 1;
485db1fda10SXin LI messages = 1;
486db1fda10SXin LI if (pci_alloc_msi(sc->tws_dev, &messages) != 0 ) {
487db1fda10SXin LI TWS_TRACE(sc, "pci alloc msi fail", 0, messages);
488db1fda10SXin LI return(FAILURE);
489db1fda10SXin LI }
490db1fda10SXin LI sc->irq_res[0] = bus_alloc_resource_any(sc->tws_dev, SYS_RES_IRQ,
491db1fda10SXin LI &sc->irq_res_id[0], RF_SHAREABLE | RF_ACTIVE);
492db1fda10SXin LI
493db1fda10SXin LI if ( !sc->irq_res[0] )
494db1fda10SXin LI return(FAILURE);
495db1fda10SXin LI if ( tws_setup_intr(sc, sc->irqs) == FAILURE )
496db1fda10SXin LI return(FAILURE);
497db1fda10SXin LI device_printf(sc->tws_dev, "Using MSI\n");
498db1fda10SXin LI break;
499db1fda10SXin LI }
500db1fda10SXin LI
501db1fda10SXin LI return(SUCCESS);
502db1fda10SXin LI }
503db1fda10SXin LI
504db1fda10SXin LI static int
tws_init(struct tws_softc * sc)505db1fda10SXin LI tws_init(struct tws_softc *sc)
506db1fda10SXin LI {
507db1fda10SXin LI
508db1fda10SXin LI u_int32_t max_sg_elements;
509db1fda10SXin LI u_int32_t dma_mem_size;
510db1fda10SXin LI u_int32_t reg;
511db1fda10SXin LI
512db1fda10SXin LI sc->seq_id = 0;
513db1fda10SXin LI if ( tws_queue_depth > TWS_MAX_REQS )
514db1fda10SXin LI tws_queue_depth = TWS_MAX_REQS;
515db1fda10SXin LI if (tws_queue_depth < TWS_RESERVED_REQS+1)
516db1fda10SXin LI tws_queue_depth = TWS_RESERVED_REQS+1;
517db1fda10SXin LI sc->is64bit = (sizeof(bus_addr_t) == 8) ? true : false;
518db1fda10SXin LI max_sg_elements = (sc->is64bit && !tws_use_32bit_sgls) ?
519db1fda10SXin LI TWS_MAX_64BIT_SG_ELEMENTS :
520db1fda10SXin LI TWS_MAX_32BIT_SG_ELEMENTS;
521db1fda10SXin LI dma_mem_size = (sizeof(struct tws_command_packet) * tws_queue_depth) +
522db1fda10SXin LI (TWS_SECTOR_SIZE) ;
523b6f97155SScott Long if ( bus_dma_tag_create(bus_get_dma_tag(sc->tws_dev), /* PCI parent */
524db1fda10SXin LI TWS_ALIGNMENT, /* alignment */
525db1fda10SXin LI 0, /* boundary */
526db1fda10SXin LI BUS_SPACE_MAXADDR_32BIT, /* lowaddr */
527db1fda10SXin LI BUS_SPACE_MAXADDR, /* highaddr */
528db1fda10SXin LI NULL, NULL, /* filter, filterarg */
529db1fda10SXin LI BUS_SPACE_MAXSIZE, /* maxsize */
530db1fda10SXin LI max_sg_elements, /* numsegs */
531db1fda10SXin LI BUS_SPACE_MAXSIZE, /* maxsegsize */
532db1fda10SXin LI 0, /* flags */
533db1fda10SXin LI NULL, NULL, /* lockfunc, lockfuncarg */
534db1fda10SXin LI &sc->parent_tag /* tag */
535db1fda10SXin LI )) {
536db1fda10SXin LI TWS_TRACE_DEBUG(sc, "DMA parent tag Create fail", max_sg_elements,
537db1fda10SXin LI sc->is64bit);
538db1fda10SXin LI return(ENOMEM);
539db1fda10SXin LI }
540db1fda10SXin LI /* In bound message frame requires 16byte alignment.
541db1fda10SXin LI * Outbound MF's can live with 4byte alignment - for now just
542db1fda10SXin LI * use 16 for both.
543db1fda10SXin LI */
544db1fda10SXin LI if ( bus_dma_tag_create(sc->parent_tag, /* parent */
545db1fda10SXin LI TWS_IN_MF_ALIGNMENT, /* alignment */
546db1fda10SXin LI 0, /* boundary */
547db1fda10SXin LI BUS_SPACE_MAXADDR_32BIT, /* lowaddr */
548db1fda10SXin LI BUS_SPACE_MAXADDR, /* highaddr */
549db1fda10SXin LI NULL, NULL, /* filter, filterarg */
550db1fda10SXin LI dma_mem_size, /* maxsize */
551db1fda10SXin LI 1, /* numsegs */
552db1fda10SXin LI BUS_SPACE_MAXSIZE, /* maxsegsize */
553db1fda10SXin LI 0, /* flags */
554db1fda10SXin LI NULL, NULL, /* lockfunc, lockfuncarg */
555db1fda10SXin LI &sc->cmd_tag /* tag */
556db1fda10SXin LI )) {
557db1fda10SXin LI TWS_TRACE_DEBUG(sc, "DMA cmd tag Create fail", max_sg_elements, sc->is64bit);
558db1fda10SXin LI return(ENOMEM);
559db1fda10SXin LI }
560db1fda10SXin LI
561db1fda10SXin LI if (bus_dmamem_alloc(sc->cmd_tag, &sc->dma_mem,
562db1fda10SXin LI BUS_DMA_NOWAIT, &sc->cmd_map)) {
563db1fda10SXin LI TWS_TRACE_DEBUG(sc, "DMA mem alloc fail", max_sg_elements, sc->is64bit);
564db1fda10SXin LI return(ENOMEM);
565db1fda10SXin LI }
566db1fda10SXin LI
567db1fda10SXin LI /* if bus_dmamem_alloc succeeds then bus_dmamap_load will succeed */
568db1fda10SXin LI sc->dma_mem_phys=0;
569a21f086aSScott Long bus_dmamap_load(sc->cmd_tag, sc->cmd_map, sc->dma_mem,
570db1fda10SXin LI dma_mem_size, tws_dmamap_cmds_load_cbfn,
571db1fda10SXin LI &sc->dma_mem_phys, 0);
572db1fda10SXin LI
573db1fda10SXin LI /*
574db1fda10SXin LI * Create a dma tag for data buffers; size will be the maximum
575db1fda10SXin LI * possible I/O size (128kB).
576db1fda10SXin LI */
577db1fda10SXin LI if (bus_dma_tag_create(sc->parent_tag, /* parent */
578db1fda10SXin LI TWS_ALIGNMENT, /* alignment */
579db1fda10SXin LI 0, /* boundary */
580db1fda10SXin LI BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
581db1fda10SXin LI BUS_SPACE_MAXADDR, /* highaddr */
582db1fda10SXin LI NULL, NULL, /* filter, filterarg */
583db1fda10SXin LI TWS_MAX_IO_SIZE, /* maxsize */
584db1fda10SXin LI max_sg_elements, /* nsegments */
585db1fda10SXin LI TWS_MAX_IO_SIZE, /* maxsegsize */
586db1fda10SXin LI BUS_DMA_ALLOCNOW, /* flags */
587db1fda10SXin LI busdma_lock_mutex, /* lockfunc */
588db1fda10SXin LI &sc->io_lock, /* lockfuncarg */
589db1fda10SXin LI &sc->data_tag /* tag */)) {
590db1fda10SXin LI TWS_TRACE_DEBUG(sc, "DMA cmd tag Create fail", max_sg_elements, sc->is64bit);
591db1fda10SXin LI return(ENOMEM);
592db1fda10SXin LI }
593db1fda10SXin LI
594db1fda10SXin LI sc->reqs = malloc(sizeof(struct tws_request) * tws_queue_depth, M_TWS,
595db1fda10SXin LI M_WAITOK | M_ZERO);
596db1fda10SXin LI sc->sense_bufs = malloc(sizeof(struct tws_sense) * tws_queue_depth, M_TWS,
597db1fda10SXin LI M_WAITOK | M_ZERO);
598cca5be24SEdward Tomasz Napierala sc->scan_ccb = xpt_alloc_ccb();
599c5f33959SXin LI if (bus_dmamem_alloc(sc->data_tag, (void **)&sc->ioctl_data_mem,
600c5f33959SXin LI (BUS_DMA_NOWAIT | BUS_DMA_ZERO), &sc->ioctl_data_map)) {
601c5f33959SXin LI device_printf(sc->tws_dev, "Cannot allocate ioctl data mem\n");
602c5f33959SXin LI return(ENOMEM);
603c5f33959SXin LI }
604db1fda10SXin LI
605db1fda10SXin LI if ( !tws_ctlr_ready(sc) )
606db1fda10SXin LI if( !tws_ctlr_reset(sc) )
607db1fda10SXin LI return(FAILURE);
608db1fda10SXin LI
609db1fda10SXin LI bzero(&sc->stats, sizeof(struct tws_stats));
610db1fda10SXin LI tws_init_qs(sc);
611db1fda10SXin LI tws_turn_off_interrupts(sc);
612db1fda10SXin LI
613db1fda10SXin LI /*
614db1fda10SXin LI * enable pull mode by setting bit1 .
615db1fda10SXin LI * setting bit0 to 1 will enable interrupt coalesing
616db1fda10SXin LI * will revisit.
617db1fda10SXin LI */
618db1fda10SXin LI
619db1fda10SXin LI #ifdef TWS_PULL_MODE_ENABLE
620db1fda10SXin LI
621db1fda10SXin LI reg = tws_read_reg(sc, TWS_I2O0_CTL, 4);
622db1fda10SXin LI TWS_TRACE_DEBUG(sc, "i20 ctl", reg, TWS_I2O0_CTL);
623db1fda10SXin LI tws_write_reg(sc, TWS_I2O0_CTL, reg | TWS_BIT1, 4);
624db1fda10SXin LI
625db1fda10SXin LI #endif
626db1fda10SXin LI
627db1fda10SXin LI TWS_TRACE_DEBUG(sc, "dma_mem_phys", sc->dma_mem_phys, TWS_I2O0_CTL);
628db1fda10SXin LI if ( tws_init_reqs(sc, dma_mem_size) == FAILURE )
629db1fda10SXin LI return(FAILURE);
630db1fda10SXin LI if ( tws_init_aen_q(sc) == FAILURE )
631db1fda10SXin LI return(FAILURE);
632db1fda10SXin LI
633db1fda10SXin LI return(SUCCESS);
634db1fda10SXin LI
635db1fda10SXin LI }
636db1fda10SXin LI
637db1fda10SXin LI static int
tws_init_aen_q(struct tws_softc * sc)638db1fda10SXin LI tws_init_aen_q(struct tws_softc *sc)
639db1fda10SXin LI {
640db1fda10SXin LI sc->aen_q.head=0;
641db1fda10SXin LI sc->aen_q.tail=0;
642db1fda10SXin LI sc->aen_q.depth=256;
643db1fda10SXin LI sc->aen_q.overflow=0;
644db1fda10SXin LI sc->aen_q.q = malloc(sizeof(struct tws_event_packet)*sc->aen_q.depth,
645db1fda10SXin LI M_TWS, M_WAITOK | M_ZERO);
646db1fda10SXin LI return(SUCCESS);
647db1fda10SXin LI }
648db1fda10SXin LI
649db1fda10SXin LI static int
tws_init_trace_q(struct tws_softc * sc)650db1fda10SXin LI tws_init_trace_q(struct tws_softc *sc)
651db1fda10SXin LI {
652db1fda10SXin LI sc->trace_q.head=0;
653db1fda10SXin LI sc->trace_q.tail=0;
654db1fda10SXin LI sc->trace_q.depth=256;
655db1fda10SXin LI sc->trace_q.overflow=0;
656db1fda10SXin LI sc->trace_q.q = malloc(sizeof(struct tws_trace_rec)*sc->trace_q.depth,
657db1fda10SXin LI M_TWS, M_WAITOK | M_ZERO);
658db1fda10SXin LI return(SUCCESS);
659db1fda10SXin LI }
660db1fda10SXin LI
661db1fda10SXin LI static int
tws_init_reqs(struct tws_softc * sc,u_int32_t dma_mem_size)662db1fda10SXin LI tws_init_reqs(struct tws_softc *sc, u_int32_t dma_mem_size)
663db1fda10SXin LI {
664db1fda10SXin LI
665db1fda10SXin LI struct tws_command_packet *cmd_buf;
666db1fda10SXin LI cmd_buf = (struct tws_command_packet *)sc->dma_mem;
667db1fda10SXin LI int i;
668db1fda10SXin LI
669db1fda10SXin LI bzero(cmd_buf, dma_mem_size);
670db1fda10SXin LI TWS_TRACE_DEBUG(sc, "phy cmd", sc->dma_mem_phys, 0);
671db1fda10SXin LI mtx_lock(&sc->q_lock);
672db1fda10SXin LI for ( i=0; i< tws_queue_depth; i++)
673db1fda10SXin LI {
674db1fda10SXin LI if (bus_dmamap_create(sc->data_tag, 0, &sc->reqs[i].dma_map)) {
675db1fda10SXin LI /* log a ENOMEM failure msg here */
6763093cb15SXin LI mtx_unlock(&sc->q_lock);
677db1fda10SXin LI return(FAILURE);
678db1fda10SXin LI }
679db1fda10SXin LI sc->reqs[i].cmd_pkt = &cmd_buf[i];
680db1fda10SXin LI
681db1fda10SXin LI sc->sense_bufs[i].hdr = &cmd_buf[i].hdr ;
682db1fda10SXin LI sc->sense_bufs[i].hdr_pkt_phy = sc->dma_mem_phys +
683db1fda10SXin LI (i * sizeof(struct tws_command_packet));
684db1fda10SXin LI
685db1fda10SXin LI sc->reqs[i].cmd_pkt_phy = sc->dma_mem_phys +
686db1fda10SXin LI sizeof(struct tws_command_header) +
687db1fda10SXin LI (i * sizeof(struct tws_command_packet));
688db1fda10SXin LI sc->reqs[i].request_id = i;
689db1fda10SXin LI sc->reqs[i].sc = sc;
690db1fda10SXin LI
691db1fda10SXin LI sc->reqs[i].cmd_pkt->hdr.header_desc.size_header = 128;
692db1fda10SXin LI
693fd90e2edSJung-uk Kim callout_init(&sc->reqs[i].timeout, 1);
694db1fda10SXin LI sc->reqs[i].state = TWS_REQ_STATE_FREE;
695db1fda10SXin LI if ( i >= TWS_RESERVED_REQS )
696db1fda10SXin LI tws_q_insert_tail(sc, &sc->reqs[i], TWS_FREE_Q);
697db1fda10SXin LI }
698db1fda10SXin LI mtx_unlock(&sc->q_lock);
699db1fda10SXin LI return(SUCCESS);
700db1fda10SXin LI }
701db1fda10SXin LI
702db1fda10SXin LI static void
tws_dmamap_cmds_load_cbfn(void * arg,bus_dma_segment_t * segs,int nseg,int error)703db1fda10SXin LI tws_dmamap_cmds_load_cbfn(void *arg, bus_dma_segment_t *segs,
704db1fda10SXin LI int nseg, int error)
705db1fda10SXin LI {
706db1fda10SXin LI
707db1fda10SXin LI /* printf("command load done \n"); */
708db1fda10SXin LI
709db1fda10SXin LI *((bus_addr_t *)arg) = segs[0].ds_addr;
710db1fda10SXin LI }
711db1fda10SXin LI
712db1fda10SXin LI void
tws_send_event(struct tws_softc * sc,u_int8_t event)713db1fda10SXin LI tws_send_event(struct tws_softc *sc, u_int8_t event)
714db1fda10SXin LI {
715db1fda10SXin LI mtx_assert(&sc->gen_lock, MA_OWNED);
716db1fda10SXin LI TWS_TRACE_DEBUG(sc, "received event ", 0, event);
717db1fda10SXin LI switch (event) {
718db1fda10SXin LI case TWS_INIT_START:
719db1fda10SXin LI sc->tws_state = TWS_INIT;
720db1fda10SXin LI break;
721db1fda10SXin LI
722db1fda10SXin LI case TWS_INIT_COMPLETE:
723db1fda10SXin LI if (sc->tws_state != TWS_INIT) {
724db1fda10SXin LI device_printf(sc->tws_dev, "invalid state transition %d => TWS_ONLINE\n", sc->tws_state);
725db1fda10SXin LI } else {
726db1fda10SXin LI sc->tws_state = TWS_ONLINE;
727db1fda10SXin LI }
728db1fda10SXin LI break;
729db1fda10SXin LI
730db1fda10SXin LI case TWS_RESET_START:
731db1fda10SXin LI /* We can transition to reset state from any state except reset*/
732db1fda10SXin LI if (sc->tws_state != TWS_RESET) {
733db1fda10SXin LI sc->tws_prev_state = sc->tws_state;
734db1fda10SXin LI sc->tws_state = TWS_RESET;
735db1fda10SXin LI }
736db1fda10SXin LI break;
737db1fda10SXin LI
738db1fda10SXin LI case TWS_RESET_COMPLETE:
739db1fda10SXin LI if (sc->tws_state != TWS_RESET) {
740db1fda10SXin LI device_printf(sc->tws_dev, "invalid state transition %d => %d (previous state)\n", sc->tws_state, sc->tws_prev_state);
741db1fda10SXin LI } else {
742db1fda10SXin LI sc->tws_state = sc->tws_prev_state;
743db1fda10SXin LI }
744db1fda10SXin LI break;
745db1fda10SXin LI
746db1fda10SXin LI case TWS_SCAN_FAILURE:
747db1fda10SXin LI if (sc->tws_state != TWS_ONLINE) {
748db1fda10SXin LI device_printf(sc->tws_dev, "invalid state transition %d => TWS_OFFLINE\n", sc->tws_state);
749db1fda10SXin LI } else {
750db1fda10SXin LI sc->tws_state = TWS_OFFLINE;
751db1fda10SXin LI }
752db1fda10SXin LI break;
753db1fda10SXin LI
754db1fda10SXin LI case TWS_UNINIT_START:
755db1fda10SXin LI if ((sc->tws_state != TWS_ONLINE) && (sc->tws_state != TWS_OFFLINE)) {
756db1fda10SXin LI device_printf(sc->tws_dev, "invalid state transition %d => TWS_UNINIT\n", sc->tws_state);
757db1fda10SXin LI } else {
758db1fda10SXin LI sc->tws_state = TWS_UNINIT;
759db1fda10SXin LI }
760db1fda10SXin LI break;
761db1fda10SXin LI }
762db1fda10SXin LI
763db1fda10SXin LI }
764db1fda10SXin LI
765db1fda10SXin LI uint8_t
tws_get_state(struct tws_softc * sc)766db1fda10SXin LI tws_get_state(struct tws_softc *sc)
767db1fda10SXin LI {
768db1fda10SXin LI
769db1fda10SXin LI return((u_int8_t)sc->tws_state);
770db1fda10SXin LI
771db1fda10SXin LI }
772db1fda10SXin LI
773db1fda10SXin LI /* Called during system shutdown after sync. */
774db1fda10SXin LI
775db1fda10SXin LI static int
tws_shutdown(device_t dev)776db1fda10SXin LI tws_shutdown(device_t dev)
777db1fda10SXin LI {
778db1fda10SXin LI
779db1fda10SXin LI struct tws_softc *sc = device_get_softc(dev);
780db1fda10SXin LI
781db1fda10SXin LI TWS_TRACE_DEBUG(sc, "entry", 0, 0);
782db1fda10SXin LI
783db1fda10SXin LI tws_turn_off_interrupts(sc);
784db1fda10SXin LI tws_init_connect(sc, 1);
785db1fda10SXin LI
786db1fda10SXin LI return (0);
787db1fda10SXin LI }
788db1fda10SXin LI
789db1fda10SXin LI /*
790db1fda10SXin LI * Device suspend routine.
791db1fda10SXin LI */
792db1fda10SXin LI static int
tws_suspend(device_t dev)793db1fda10SXin LI tws_suspend(device_t dev)
794db1fda10SXin LI {
795db1fda10SXin LI struct tws_softc *sc = device_get_softc(dev);
796db1fda10SXin LI
797db1fda10SXin LI if ( sc )
798db1fda10SXin LI TWS_TRACE_DEBUG(sc, "entry", 0, 0);
799db1fda10SXin LI return (0);
800db1fda10SXin LI }
801db1fda10SXin LI
802db1fda10SXin LI /*
803db1fda10SXin LI * Device resume routine.
804db1fda10SXin LI */
805db1fda10SXin LI static int
tws_resume(device_t dev)806db1fda10SXin LI tws_resume(device_t dev)
807db1fda10SXin LI {
808db1fda10SXin LI
809db1fda10SXin LI struct tws_softc *sc = device_get_softc(dev);
810db1fda10SXin LI
811db1fda10SXin LI if ( sc )
812db1fda10SXin LI TWS_TRACE_DEBUG(sc, "entry", 0, 0);
813db1fda10SXin LI return (0);
814db1fda10SXin LI }
815db1fda10SXin LI
816db1fda10SXin LI struct tws_request *
tws_get_request(struct tws_softc * sc,u_int16_t type)817db1fda10SXin LI tws_get_request(struct tws_softc *sc, u_int16_t type)
818db1fda10SXin LI {
819db1fda10SXin LI struct mtx *my_mutex = ((type == TWS_REQ_TYPE_SCSI_IO) ? &sc->q_lock : &sc->gen_lock);
820db1fda10SXin LI struct tws_request *r = NULL;
821db1fda10SXin LI
822db1fda10SXin LI mtx_lock(my_mutex);
823db1fda10SXin LI
824db1fda10SXin LI if (type == TWS_REQ_TYPE_SCSI_IO) {
825db1fda10SXin LI r = tws_q_remove_head(sc, TWS_FREE_Q);
826db1fda10SXin LI } else {
827db1fda10SXin LI if ( sc->reqs[type].state == TWS_REQ_STATE_FREE ) {
828db1fda10SXin LI r = &sc->reqs[type];
829db1fda10SXin LI }
830db1fda10SXin LI }
831db1fda10SXin LI
832db1fda10SXin LI if ( r ) {
833db1fda10SXin LI bzero(&r->cmd_pkt->cmd, sizeof(struct tws_command_apache));
834db1fda10SXin LI r->data = NULL;
835db1fda10SXin LI r->length = 0;
836db1fda10SXin LI r->type = type;
837db1fda10SXin LI r->flags = TWS_DIR_UNKNOWN;
838db1fda10SXin LI r->error_code = TWS_REQ_RET_INVALID;
839db1fda10SXin LI r->cb = NULL;
840db1fda10SXin LI r->ccb_ptr = NULL;
841166a4e47SJohn Baldwin callout_stop(&r->timeout);
842db1fda10SXin LI r->next = r->prev = NULL;
843db1fda10SXin LI
844db1fda10SXin LI r->state = ((type == TWS_REQ_TYPE_SCSI_IO) ? TWS_REQ_STATE_TRAN : TWS_REQ_STATE_BUSY);
845db1fda10SXin LI }
846db1fda10SXin LI
847db1fda10SXin LI mtx_unlock(my_mutex);
848db1fda10SXin LI
849db1fda10SXin LI return(r);
850db1fda10SXin LI }
851db1fda10SXin LI
852db1fda10SXin LI void
tws_release_request(struct tws_request * req)853db1fda10SXin LI tws_release_request(struct tws_request *req)
854db1fda10SXin LI {
855db1fda10SXin LI
856db1fda10SXin LI struct tws_softc *sc = req->sc;
857db1fda10SXin LI
858db1fda10SXin LI TWS_TRACE_DEBUG(sc, "entry", sc, 0);
859db1fda10SXin LI mtx_lock(&sc->q_lock);
860db1fda10SXin LI tws_q_insert_tail(sc, req, TWS_FREE_Q);
861db1fda10SXin LI mtx_unlock(&sc->q_lock);
862db1fda10SXin LI }
863db1fda10SXin LI
864db1fda10SXin LI static device_method_t tws_methods[] = {
865db1fda10SXin LI /* Device interface */
866db1fda10SXin LI DEVMETHOD(device_probe, tws_probe),
867db1fda10SXin LI DEVMETHOD(device_attach, tws_attach),
868db1fda10SXin LI DEVMETHOD(device_detach, tws_detach),
869db1fda10SXin LI DEVMETHOD(device_shutdown, tws_shutdown),
870db1fda10SXin LI DEVMETHOD(device_suspend, tws_suspend),
871db1fda10SXin LI DEVMETHOD(device_resume, tws_resume),
872db1fda10SXin LI
8734b7ec270SMarius Strobl DEVMETHOD_END
874db1fda10SXin LI };
875db1fda10SXin LI
876db1fda10SXin LI static driver_t tws_driver = {
877db1fda10SXin LI "tws",
878db1fda10SXin LI tws_methods,
879db1fda10SXin LI sizeof(struct tws_softc)
880db1fda10SXin LI };
881db1fda10SXin LI
882db1fda10SXin LI /* DEFINE_CLASS_0(tws, tws_driver, tws_methods, sizeof(struct tws_softc)); */
883*716debedSJohn Baldwin DRIVER_MODULE(tws, pci, tws_driver, 0, 0);
884db1fda10SXin LI MODULE_DEPEND(tws, cam, 1, 1, 1);
885db1fda10SXin LI MODULE_DEPEND(tws, pci, 1, 1, 1);
886db1fda10SXin LI
887db1fda10SXin LI TUNABLE_INT("hw.tws.queue_depth", &tws_queue_depth);
888db1fda10SXin LI TUNABLE_INT("hw.tws.enable_msi", &tws_enable_msi);
889