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